diff --git a/fcst/fcst.h b/fcst/fcst.h index 11b52fa9c..b7569542b 100644 --- a/fcst/fcst.h +++ b/fcst/fcst.h @@ -19,6 +19,7 @@ #ifndef __SCSI_FCST_H__ #define __SCSI_FCST_H__ +#include #ifdef INSIDE_KERNEL_TREE #include #else @@ -117,7 +118,11 @@ extern struct scst_tgt_template ft_scst_template; int ft_prli(struct fc_rport_priv *, u32 spp_len, const struct fc_els_spp *, struct fc_els_spp *); void ft_prlo(struct fc_rport_priv *); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) void ft_recv(struct fc_lport *, struct fc_seq *, struct fc_frame *); +#else +void ft_recv(struct fc_lport *, struct fc_frame *); +#endif /* * SCST interface. @@ -145,7 +150,7 @@ void ft_lport_del(struct fc_lport *, void *); * other internal functions. */ int ft_thread(void *); -void ft_recv_req(struct ft_sess *, struct fc_seq *, struct fc_frame *); +void ft_recv_req(struct ft_sess *, struct fc_frame *); void ft_recv_write_data(struct scst_cmd *, struct fc_frame *); int ft_send_read_data(struct scst_cmd *); struct ft_tpg *ft_lport_find_tpg(struct fc_lport *); diff --git a/fcst/ft_cmd.c b/fcst/ft_cmd.c index bde665b39..a03439613 100644 --- a/fcst/ft_cmd.c +++ b/fcst/ft_cmd.c @@ -38,7 +38,7 @@ void ft_cmd_dump(struct scst_cmd *cmd, const char *caller) { static atomic_t serial; struct ft_cmd *fcmd; - struct fc_exch *ep; + struct fc_frame_header *fh; char prefix[30]; char buf[150]; @@ -46,12 +46,12 @@ void ft_cmd_dump(struct scst_cmd *cmd, const char *caller) return; fcmd = scst_cmd_get_tgt_priv(cmd); - ep = fc_seq_exch(fcmd->seq); + fh = fc_frame_header_get(fcmd->req_frame); snprintf(prefix, sizeof(prefix), FT_MODULE ": cmd %2x", atomic_inc_return(&serial) & 0xff); printk(KERN_INFO "%s %s oid %x oxid %x resp_len %u\n", - prefix, caller, ep->oid, ep->oxid, + prefix, caller, ntoh24(fh->fh_s_id), ntohs(fh->fh_ox_id), scst_cmd_get_resp_data_len(cmd)); printk(KERN_INFO "%s scst_cmd %p wlen %u rlen %u\n", prefix, cmd, fcmd->write_data_len, fcmd->read_data_len); @@ -138,19 +138,19 @@ void ft_cmd_dump(struct scst_cmd *cmd, const char *caller) static void ft_cmd_tm_dump(struct scst_mgmt_cmd *mcmd, const char *caller) { struct ft_cmd *fcmd; - struct fc_exch *ep; + struct fc_frame_header *fh; char prefix[30]; char buf[150]; if (!(ft_debug_logging & FT_DEBUG_IO)) return; fcmd = scst_mgmt_cmd_get_tgt_priv(mcmd); - ep = fc_seq_exch(fcmd->seq); + fh = fc_frame_header_get(fcmd->req_frame); snprintf(prefix, sizeof(prefix), FT_MODULE ": mcmd"); printk(KERN_INFO "%s %s oid %x oxid %x lun %lld\n", - prefix, caller, ep->oid, ep->oxid, + prefix, caller, ntoh24(fh->fh_s_id), ntohs(fh->fh_ox_id), (unsigned long long)mcmd->lun); printk(KERN_INFO "%s state %d fn %d fin_wait %d done_wait %d comp %d\n", prefix, mcmd->state, mcmd->fn, @@ -169,7 +169,25 @@ static void ft_cmd_tm_dump(struct scst_mgmt_cmd *mcmd, const char *caller) } /* - * Free command. + * Free command and associated frame. + */ +static void ft_cmd_done(struct ft_cmd *fcmd) +{ + struct fc_frame *fp = fcmd->req_frame; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) + struct fc_lport *lport; + + lport = fr_dev(fp); + if (fr_seq(fp)) + lport->tt.seq_release(fr_seq(fp)); +#endif + + fc_frame_free(fp); + kfree(fcmd); +} + +/* + * Free command - callback from SCST. */ void ft_cmd_free(struct scst_cmd *cmd) { @@ -178,8 +196,7 @@ void ft_cmd_free(struct scst_cmd *cmd) fcmd = scst_cmd_get_tgt_priv(cmd); if (fcmd) { scst_cmd_set_tgt_priv(cmd, NULL); - fc_frame_free(fcmd->req_frame); - kfree(fcmd); + ft_cmd_done(fcmd); } } @@ -383,27 +400,35 @@ int ft_send_xfer_rdy(struct scst_cmd *cmd) * status is SAM_STAT_GOOD (zero) if code is valid. * This is used in error cases, such as allocation failures. */ -static void ft_send_resp_status(struct fc_seq *sp, u32 status, +static void ft_send_resp_status(struct fc_frame *rx_fp, u32 status, enum fcp_resp_rsp_codes code) { struct fc_frame *fp; + struct fc_frame_header *fh; size_t len; struct fcp_resp_with_ext *fcp; struct fcp_resp_rsp_info *info; struct fc_lport *lport; + struct fc_seq *sp; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) struct fc_exch *ep; +#endif - ep = fc_seq_exch(sp); - + sp = fr_seq(rx_fp); + fh = fc_frame_header_get(rx_fp); FT_IO_DBG("FCP error response: did %x oxid %x status %x code %x\n", - ep->did, ep->oxid, status, code); - lport = ep->lp; + ntoh24(fh->fh_s_id), ntohs(fh->fh_ox_id), status, code); + lport = fr_dev(rx_fp); len = sizeof(*fcp); if (status == SAM_STAT_GOOD) len += sizeof(*info); fp = fc_frame_alloc(lport, len); if (!fp) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) goto out; +#else + return; +#endif fcp = fc_frame_payload_get(fp, len); memset(fcp, 0, len); fcp->resp.fr_status = status; @@ -414,13 +439,22 @@ static void ft_send_resp_status(struct fc_seq *sp, u32 status, info->rsp_code = code; } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) sp = lport->tt.seq_start_next(sp); + ep = fc_seq_exch(sp); fc_fill_fc_hdr(fp, FC_RCTL_DD_CMD_STATUS, ep->did, ep->sid, FC_TYPE_FCP, FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ, 0); lport->tt.seq_send(lport, sp, fp); out: lport->tt.exch_done(sp); +#else + fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_DD_CMD_STATUS, 0); + if (sp) + lport->tt.seq_send(lport, sp, fp); + else + lport->tt.frame_send(lport, fp); +#endif } /* @@ -429,9 +463,8 @@ out: */ static void ft_send_resp_code(struct ft_cmd *fcmd, enum fcp_resp_rsp_codes code) { - ft_send_resp_status(fcmd->seq, SAM_STAT_GOOD, code); - fc_frame_free(fcmd->req_frame); - kfree(fcmd); + ft_send_resp_status(fcmd->req_frame, SAM_STAT_GOOD, code); + ft_cmd_done(fcmd); } void ft_cmd_tm_done(struct scst_mgmt_cmd *mcmd) @@ -516,10 +549,10 @@ static void ft_recv_tm(struct scst_session *scst_sess, * Handle an incoming FCP command frame. * Note that this may be called directly from the softirq context. */ -static void ft_recv_cmd(struct ft_sess *sess, struct fc_seq *sp, - struct fc_frame *fp) +static void ft_recv_cmd(struct ft_sess *sess, struct fc_frame *fp) { static atomic_t serial; + struct fc_seq *sp; struct scst_cmd *cmd; struct ft_cmd *fcmd; struct fcp_cmnd *fcp; @@ -528,12 +561,11 @@ static void ft_recv_cmd(struct ft_sess *sess, struct fc_seq *sp, u32 data_len; int cdb_len; - lport = fc_seq_exch(sp)->lp; + lport = sess->tport->lport; fcmd = kzalloc(sizeof(*fcmd), GFP_ATOMIC); if (!fcmd) goto busy; fcmd->serial = atomic_inc_return(&serial); /* debug only */ - fcmd->seq = sp; fcmd->max_payload = sess->max_payload; fcmd->max_lso_payload = sess->max_lso_payload; fcmd->req_frame = fp; @@ -559,13 +591,21 @@ static void ft_recv_cmd(struct ft_sess *sess, struct fc_seq *sp, cmd = scst_rx_cmd(sess->scst_sess, fcp->fc_lun, sizeof(fcp->fc_lun), fcp->fc_cdb, cdb_len, SCST_ATOMIC); - if (!cmd) { - kfree(fcmd); + if (!cmd) goto busy; - } fcmd->scst_cmd = cmd; scst_cmd_set_tgt_priv(cmd, fcmd); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) + sp = fr_seq(fp); +#else + sp = lport->tt.seq_assign(lport, fp); + if (!sp) + goto busy; +#endif + fcmd->seq = sp; + lport->tt.seq_set_resp(sp, ft_recv_seq, cmd); + switch (fcp->fc_flags & (FCP_CFL_RDDATA | FCP_CFL_WRDATA)) { case 0: default: @@ -599,7 +639,6 @@ static void ft_recv_cmd(struct ft_sess *sess, struct fc_seq *sp, break; } - lport->tt.seq_set_resp(sp, ft_recv_seq, cmd); scst_cmd_init_done(cmd, SCST_CONTEXT_THREAD); return; @@ -609,16 +648,18 @@ err: busy: FT_IO_DBG("cmd allocation failure - sending BUSY\n"); - ft_send_resp_status(sp, SAM_STAT_BUSY, 0); - fc_frame_free(fp); + ft_send_resp_status(fp, SAM_STAT_BUSY, 0); + ft_cmd_done(fcmd); } /* * Send FCP ELS-4 Reject. */ -static void ft_cmd_ls_rjt(struct fc_seq *sp, enum fc_els_rjt_reason reason, +static void ft_cmd_ls_rjt(struct fc_frame *rx_fp, enum fc_els_rjt_reason reason, enum fc_els_rjt_explan explan) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) + struct fc_seq *sp = fr_seq(rx_fp); struct fc_frame *fp; struct fc_els_ls_rjt *rjt; struct fc_lport *lport; @@ -640,14 +681,22 @@ static void ft_cmd_ls_rjt(struct fc_seq *sp, enum fc_els_rjt_reason reason, fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, FC_TYPE_FCP, FC_FC_EX_CTX | FC_FC_END_SEQ | FC_FC_LAST_SEQ, 0); lport->tt.seq_send(lport, sp, fp); +#else + struct fc_seq_els_data rjt_data; + struct fc_lport *lport; + + lport = fr_dev(rx_fp); + rjt_data.reason = reason; + rjt_data.explan = explan; + lport->tt.seq_els_rsp_send(rx_fp, ELS_LS_RJT, &rjt_data); +#endif } /* * Handle an incoming FCP ELS-4 command frame. * Note that this may be called directly from the softirq context. */ -static void ft_recv_els4(struct ft_sess *sess, struct fc_seq *sp, - struct fc_frame *fp) +static void ft_recv_els4(struct ft_sess *sess, struct fc_frame *fp) { u8 op = fc_frame_payload_op(fp); @@ -655,7 +704,7 @@ static void ft_recv_els4(struct ft_sess *sess, struct fc_seq *sp, case ELS_SRR: /* TBD */ default: FT_IO_DBG("unsupported ELS-4 op %x\n", op); - ft_cmd_ls_rjt(sp, ELS_RJT_INVAL, ELS_EXPL_NONE); + ft_cmd_ls_rjt(fp, ELS_RJT_INVAL, ELS_EXPL_NONE); fc_frame_free(fp); break; } @@ -665,22 +714,24 @@ static void ft_recv_els4(struct ft_sess *sess, struct fc_seq *sp, * Handle an incoming FCP frame. * Note that this may be called directly from the softirq context. */ -void ft_recv_req(struct ft_sess *sess, struct fc_seq *sp, struct fc_frame *fp) +void ft_recv_req(struct ft_sess *sess, struct fc_frame *fp) { struct fc_frame_header *fh = fc_frame_header_get(fp); switch (fh->fh_r_ctl) { case FC_RCTL_DD_UNSOL_CMD: - ft_recv_cmd(sess, sp, fp); + ft_recv_cmd(sess, fp); break; case FC_RCTL_ELS4_REQ: - ft_recv_els4(sess, sp, fp); + ft_recv_els4(sess, fp); break; default: printk(KERN_INFO "%s: unhandled frame r_ctl %x\n", __func__, fh->fh_r_ctl); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) + sess->tport->lport->tt.exch_done(fr_seq(fp)); +#endif fc_frame_free(fp); - sess->tport->lport->tt.exch_done(sp); break; } } diff --git a/fcst/ft_io.c b/fcst/ft_io.c index 05fa2e8db..88e95d530 100644 --- a/fcst/ft_io.c +++ b/fcst/ft_io.c @@ -218,7 +218,6 @@ int ft_send_read_data(struct scst_cmd *cmd) fr_max_payload(fp) = fcmd->max_payload; to = fc_frame_payload_get(fp, 0); fh_off = frame_off; - frame_off += frame_len; } tlen = min(mem_len, frame_len); BUG_ON(!tlen); @@ -233,20 +232,25 @@ int ft_send_read_data(struct scst_cmd *cmd) PAGE_SIZE - (mem_off & ~PAGE_MASK)); skb_fill_page_desc(fp_skb(fp), skb_shinfo(fp_skb(fp))->nr_frags, - page, mem_off, tlen); + page, offset_in_page(from + mem_off), + tlen); fr_len(fp) += tlen; fp_skb(fp)->data_len += tlen; fp_skb(fp)->truesize += PAGE_SIZE << compound_order(page); + frame_len -= tlen; + if (skb_shinfo(fp_skb(fp))->nr_frags >= FC_FRAME_SG_LEN) + frame_len = 0; } else { memcpy(to, from + mem_off, tlen); to += tlen; + frame_len -= tlen; } mem_len -= tlen; mem_off += tlen; - frame_len -= tlen; remaining -= tlen; + frame_off += tlen; if (frame_len) continue; diff --git a/fcst/ft_sess.c b/fcst/ft_sess.c index 25fab3851..70f84dbbc 100644 --- a/fcst/ft_sess.c +++ b/fcst/ft_sess.c @@ -49,15 +49,20 @@ static struct ft_tport *ft_tport_create(struct fc_lport *lport) FT_SESS_DBG("create %s\n", name); tport = rcu_dereference(lport->prov[FC_TYPE_FCP]); - if (tport) + if (tport) { + FT_SESS_DBG("tport alloc %s - already setup\n", name); return tport; + } tport = kzalloc(sizeof(*tport), GFP_KERNEL); - if (!tport) + if (!tport) { + FT_SESS_DBG("tport alloc %s failed\n", name); return NULL; + } tport->tgt = scst_register_target(&ft_scst_template, name); if (!tport->tgt) { + FT_SESS_DBG("register_target %s failed\n", name); kfree(tport); return NULL; } @@ -69,6 +74,7 @@ static struct ft_tport *ft_tport_create(struct fc_lport *lport) INIT_HLIST_HEAD(&tport->hash[i]); rcu_assign_pointer(lport->prov[FC_TYPE_FCP], tport); + FT_SESS_DBG("register_target %s succeeded\n", name); return tport; } @@ -474,7 +480,11 @@ void ft_prlo(struct fc_rport_priv *rdata) * Caller has verified that the frame is type FCP. * Note that this may be called directly from the softirq context. */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) void ft_recv(struct fc_lport *lport, struct fc_seq *sp, struct fc_frame *fp) +#else +void ft_recv(struct fc_lport *lport, struct fc_frame *fp) +#endif { struct ft_sess *sess; struct fc_frame_header *fh; @@ -488,14 +498,16 @@ void ft_recv(struct fc_lport *lport, struct fc_seq *sp, struct fc_frame *fp) sess = ft_sess_get(lport, sid); if (!sess) { FT_SESS_DBG("sid %x sess lookup failed\n", sid); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) lport->tt.exch_done(sp); +#endif /* TBD XXX - if FCP_CMND, send LOGO */ fc_frame_free(fp); return; } FT_SESS_DBG("sid %x sess lookup returned %p preempt %x\n", sid, sess, preempt_count()); - ft_recv_req(sess, sp, fp); + ft_recv_req(sess, fp); ft_sess_put(sess); } diff --git a/fcst/linux-patches/series-2.6.36 b/fcst/linux-patches/series-2.6.36 new file mode 100644 index 000000000..1db6f7715 --- /dev/null +++ b/fcst/linux-patches/series-2.6.36 @@ -0,0 +1,6 @@ +# applies to linux 2.6.36 +19-fc4-v2 +20-seq-set-resp +21-lport-hook +22-lport-notify +24-softirq