diff options
Diffstat (limited to 'drivers/target/tcm_fc')
-rw-r--r-- | drivers/target/tcm_fc/tcm_fc.h | 5 | ||||
-rw-r--r-- | drivers/target/tcm_fc/tfc_cmd.c | 1 | ||||
-rw-r--r-- | drivers/target/tcm_fc/tfc_conf.c | 6 | ||||
-rw-r--r-- | drivers/target/tcm_fc/tfc_io.c | 121 |
4 files changed, 80 insertions, 53 deletions
diff --git a/drivers/target/tcm_fc/tcm_fc.h b/drivers/target/tcm_fc/tcm_fc.h index f7fff7ed63c3..bd4fe21a23b8 100644 --- a/drivers/target/tcm_fc/tcm_fc.h +++ b/drivers/target/tcm_fc/tcm_fc.h @@ -187,4 +187,9 @@ void ft_dump_cmd(struct ft_cmd *, const char *caller); ssize_t ft_format_wwn(char *, size_t, u64); +/* + * Underlying HW specific helper function + */ +void ft_invl_hw_context(struct ft_cmd *); + #endif /* __TCM_FC_H__ */ diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index 09df38b4610c..5654dc22f7ae 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c @@ -320,6 +320,7 @@ static void ft_recv_seq(struct fc_seq *sp, struct fc_frame *fp, void *arg) default: pr_debug("%s: unhandled frame r_ctl %x\n", __func__, fh->fh_r_ctl); + ft_invl_hw_context(cmd); fc_frame_free(fp); transport_generic_free_cmd(&cmd->se_cmd, 0, 0); break; diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c index 8781d1e423df..b15879d43e22 100644 --- a/drivers/target/tcm_fc/tfc_conf.c +++ b/drivers/target/tcm_fc/tfc_conf.c @@ -256,7 +256,7 @@ struct ft_node_acl *ft_acl_get(struct ft_tpg *tpg, struct fc_rport_priv *rdata) struct se_portal_group *se_tpg = &tpg->se_tpg; struct se_node_acl *se_acl; - spin_lock_bh(&se_tpg->acl_node_lock); + spin_lock_irq(&se_tpg->acl_node_lock); list_for_each_entry(se_acl, &se_tpg->acl_node_list, acl_list) { acl = container_of(se_acl, struct ft_node_acl, se_node_acl); pr_debug("acl %p port_name %llx\n", @@ -270,7 +270,7 @@ struct ft_node_acl *ft_acl_get(struct ft_tpg *tpg, struct fc_rport_priv *rdata) break; } } - spin_unlock_bh(&se_tpg->acl_node_lock); + spin_unlock_irq(&se_tpg->acl_node_lock); return found; } @@ -655,9 +655,7 @@ static void __exit ft_exit(void) synchronize_rcu(); } -#ifdef MODULE MODULE_DESCRIPTION("FC TCM fabric driver " FT_VERSION); MODULE_LICENSE("GPL"); module_init(ft_init); module_exit(ft_exit); -#endif /* MODULE */ diff --git a/drivers/target/tcm_fc/tfc_io.c b/drivers/target/tcm_fc/tfc_io.c index 8e2a46ddcccb..c37f4cd96452 100644 --- a/drivers/target/tcm_fc/tfc_io.c +++ b/drivers/target/tcm_fc/tfc_io.c @@ -213,62 +213,49 @@ void ft_recv_write_data(struct ft_cmd *cmd, struct fc_frame *fp) if (!(ntoh24(fh->fh_f_ctl) & FC_FC_REL_OFF)) goto drop; + f_ctl = ntoh24(fh->fh_f_ctl); + ep = fc_seq_exch(seq); + lport = ep->lp; + if (cmd->was_ddp_setup) { + BUG_ON(!ep); + BUG_ON(!lport); + } + /* - * Doesn't expect even single byte of payload. Payload + * Doesn't expect payload if DDP is setup. Payload * is expected to be copied directly to user buffers - * due to DDP (Large Rx offload) feature, hence - * BUG_ON if BUF is non-NULL + * due to DDP (Large Rx offload), */ buf = fc_frame_payload_get(fp, 1); - if (cmd->was_ddp_setup && buf) { - pr_debug("%s: When DDP was setup, not expected to" - "receive frame with payload, Payload shall be" - "copied directly to buffer instead of coming " - "via. legacy receive queues\n", __func__); - BUG_ON(buf); - } + if (buf) + pr_err("%s: xid 0x%x, f_ctl 0x%x, cmd->sg %p, " + "cmd->sg_cnt 0x%x. DDP was setup" + " hence not expected to receive frame with " + "payload, Frame will be dropped if " + "'Sequence Initiative' bit in f_ctl is " + "not set\n", __func__, ep->xid, f_ctl, + cmd->sg, cmd->sg_cnt); + /* + * Invalidate HW DDP context if it was setup for respective + * command. Invalidation of HW DDP context is requited in both + * situation (success and error). + */ + ft_invl_hw_context(cmd); /* - * If ft_cmd indicated 'ddp_setup', in that case only the last frame - * should come with 'TSI bit being set'. If 'TSI bit is not set and if - * data frame appears here, means error condition. In both the cases - * release the DDP context (ddp_put) and in error case, as well - * initiate error recovery mechanism. + * If "Sequence Initiative (TSI)" bit set in f_ctl, means last + * write data frame is received successfully where payload is + * posted directly to user buffer and only the last frame's + * header is posted in receive queue. + * + * If "Sequence Initiative (TSI)" bit is not set, means error + * condition w.r.t. DDP, hence drop the packet and let explict + * ABORTS from other end of exchange timer trigger the recovery. */ - ep = fc_seq_exch(seq); - if (cmd->was_ddp_setup) { - BUG_ON(!ep); - lport = ep->lp; - BUG_ON(!lport); - } - if (cmd->was_ddp_setup && ep->xid != FC_XID_UNKNOWN) { - f_ctl = ntoh24(fh->fh_f_ctl); - /* - * If TSI bit set in f_ctl, means last write data frame is - * received successfully where payload is posted directly - * to user buffer and only the last frame's header is posted - * in legacy receive queue - */ - if (f_ctl & FC_FC_SEQ_INIT) { /* TSI bit set in FC frame */ - cmd->write_data_len = lport->tt.ddp_done(lport, - ep->xid); - goto last_frame; - } else { - /* - * Updating the write_data_len may be meaningless at - * this point, but just in case if required in future - * for debugging or any other purpose - */ - pr_err("%s: Received frame with TSI bit not" - " being SET, dropping the frame, " - "cmd->sg <%p>, cmd->sg_cnt <0x%x>\n", - __func__, cmd->sg, cmd->sg_cnt); - cmd->write_data_len = lport->tt.ddp_done(lport, - ep->xid); - lport->tt.seq_exch_abort(cmd->seq, 0); - goto drop; - } - } + if (f_ctl & FC_FC_SEQ_INIT) + goto last_frame; + else + goto drop; rel_off = ntohl(fh->fh_parm_offset); frame_len = fr_len(fp); @@ -331,3 +318,39 @@ last_frame: drop: fc_frame_free(fp); } + +/* + * Handle and cleanup any HW specific resources if + * received ABORTS, errors, timeouts. + */ +void ft_invl_hw_context(struct ft_cmd *cmd) +{ + struct fc_seq *seq = cmd->seq; + struct fc_exch *ep = NULL; + struct fc_lport *lport = NULL; + + BUG_ON(!cmd); + + /* Cleanup the DDP context in HW if DDP was setup */ + if (cmd->was_ddp_setup && seq) { + ep = fc_seq_exch(seq); + if (ep) { + lport = ep->lp; + if (lport && (ep->xid <= lport->lro_xid)) + /* + * "ddp_done" trigger invalidation of HW + * specific DDP context + */ + cmd->write_data_len = lport->tt.ddp_done(lport, + ep->xid); + + /* + * Resetting same variable to indicate HW's + * DDP context has been invalidated to avoid + * re_invalidation of same context (context is + * identified using ep->xid) + */ + cmd->was_ddp_setup = 0; + } + } +} |