aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/target/tcm_fc/tcm_fc.h5
-rw-r--r--drivers/target/tcm_fc/tfc_cmd.c1
-rw-r--r--drivers/target/tcm_fc/tfc_io.c121
3 files changed, 78 insertions, 49 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);
187 187
188ssize_t ft_format_wwn(char *, size_t, u64); 188ssize_t ft_format_wwn(char *, size_t, u64);
189 189
190/*
191 * Underlying HW specific helper function
192 */
193void ft_invl_hw_context(struct ft_cmd *);
194
190#endif /* __TCM_FC_H__ */ 195#endif /* __TCM_FC_H__ */
diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c
index a9e9a31da11d..03977e8996d8 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)
320 default: 320 default:
321 pr_debug("%s: unhandled frame r_ctl %x\n", 321 pr_debug("%s: unhandled frame r_ctl %x\n",
322 __func__, fh->fh_r_ctl); 322 __func__, fh->fh_r_ctl);
323 ft_invl_hw_context(cmd);
323 fc_frame_free(fp); 324 fc_frame_free(fp);
324 transport_generic_free_cmd(&cmd->se_cmd, 0, 0); 325 transport_generic_free_cmd(&cmd->se_cmd, 0, 0);
325 break; 326 break;
diff --git a/drivers/target/tcm_fc/tfc_io.c b/drivers/target/tcm_fc/tfc_io.c
index 11e6483fc127..06943eeb3c84 100644
--- a/drivers/target/tcm_fc/tfc_io.c
+++ b/drivers/target/tcm_fc/tfc_io.c
@@ -214,62 +214,49 @@ void ft_recv_write_data(struct ft_cmd *cmd, struct fc_frame *fp)
214 if (!(ntoh24(fh->fh_f_ctl) & FC_FC_REL_OFF)) 214 if (!(ntoh24(fh->fh_f_ctl) & FC_FC_REL_OFF))
215 goto drop; 215 goto drop;
216 216
217 f_ctl = ntoh24(fh->fh_f_ctl);
218 ep = fc_seq_exch(seq);
219 lport = ep->lp;
220 if (cmd->was_ddp_setup) {
221 BUG_ON(!ep);
222 BUG_ON(!lport);
223 }
224
217 /* 225 /*
218 * Doesn't expect even single byte of payload. Payload 226 * Doesn't expect payload if DDP is setup. Payload
219 * is expected to be copied directly to user buffers 227 * is expected to be copied directly to user buffers
220 * due to DDP (Large Rx offload) feature, hence 228 * due to DDP (Large Rx offload),
221 * BUG_ON if BUF is non-NULL
222 */ 229 */
223 buf = fc_frame_payload_get(fp, 1); 230 buf = fc_frame_payload_get(fp, 1);
224 if (cmd->was_ddp_setup && buf) { 231 if (buf)
225 pr_debug("%s: When DDP was setup, not expected to" 232 pr_err("%s: xid 0x%x, f_ctl 0x%x, cmd->sg %p, "
226 "receive frame with payload, Payload shall be" 233 "cmd->sg_cnt 0x%x. DDP was setup"
227 "copied directly to buffer instead of coming " 234 " hence not expected to receive frame with "
228 "via. legacy receive queues\n", __func__); 235 "payload, Frame will be dropped if "
229 BUG_ON(buf); 236 "'Sequence Initiative' bit in f_ctl is "
230 } 237 "not set\n", __func__, ep->xid, f_ctl,
238 cmd->sg, cmd->sg_cnt);
239 /*
240 * Invalidate HW DDP context if it was setup for respective
241 * command. Invalidation of HW DDP context is requited in both
242 * situation (success and error).
243 */
244 ft_invl_hw_context(cmd);
231 245
232 /* 246 /*
233 * If ft_cmd indicated 'ddp_setup', in that case only the last frame 247 * If "Sequence Initiative (TSI)" bit set in f_ctl, means last
234 * should come with 'TSI bit being set'. If 'TSI bit is not set and if 248 * write data frame is received successfully where payload is
235 * data frame appears here, means error condition. In both the cases 249 * posted directly to user buffer and only the last frame's
236 * release the DDP context (ddp_put) and in error case, as well 250 * header is posted in receive queue.
237 * initiate error recovery mechanism. 251 *
252 * If "Sequence Initiative (TSI)" bit is not set, means error
253 * condition w.r.t. DDP, hence drop the packet and let explict
254 * ABORTS from other end of exchange timer trigger the recovery.
238 */ 255 */
239 ep = fc_seq_exch(seq); 256 if (f_ctl & FC_FC_SEQ_INIT)
240 if (cmd->was_ddp_setup) { 257 goto last_frame;
241 BUG_ON(!ep); 258 else
242 lport = ep->lp; 259 goto drop;
243 BUG_ON(!lport);
244 }
245 if (cmd->was_ddp_setup && ep->xid != FC_XID_UNKNOWN) {
246 f_ctl = ntoh24(fh->fh_f_ctl);
247 /*
248 * If TSI bit set in f_ctl, means last write data frame is
249 * received successfully where payload is posted directly
250 * to user buffer and only the last frame's header is posted
251 * in legacy receive queue
252 */
253 if (f_ctl & FC_FC_SEQ_INIT) { /* TSI bit set in FC frame */
254 cmd->write_data_len = lport->tt.ddp_done(lport,
255 ep->xid);
256 goto last_frame;
257 } else {
258 /*
259 * Updating the write_data_len may be meaningless at
260 * this point, but just in case if required in future
261 * for debugging or any other purpose
262 */
263 pr_err("%s: Received frame with TSI bit not"
264 " being SET, dropping the frame, "
265 "cmd->sg <%p>, cmd->sg_cnt <0x%x>\n",
266 __func__, cmd->sg, cmd->sg_cnt);
267 cmd->write_data_len = lport->tt.ddp_done(lport,
268 ep->xid);
269 lport->tt.seq_exch_abort(cmd->seq, 0);
270 goto drop;
271 }
272 }
273 260
274 rel_off = ntohl(fh->fh_parm_offset); 261 rel_off = ntohl(fh->fh_parm_offset);
275 frame_len = fr_len(fp); 262 frame_len = fr_len(fp);
@@ -332,3 +319,39 @@ last_frame:
332drop: 319drop:
333 fc_frame_free(fp); 320 fc_frame_free(fp);
334} 321}
322
323/*
324 * Handle and cleanup any HW specific resources if
325 * received ABORTS, errors, timeouts.
326 */
327void ft_invl_hw_context(struct ft_cmd *cmd)
328{
329 struct fc_seq *seq = cmd->seq;
330 struct fc_exch *ep = NULL;
331 struct fc_lport *lport = NULL;
332
333 BUG_ON(!cmd);
334
335 /* Cleanup the DDP context in HW if DDP was setup */
336 if (cmd->was_ddp_setup && seq) {
337 ep = fc_seq_exch(seq);
338 if (ep) {
339 lport = ep->lp;
340 if (lport && (ep->xid <= lport->lro_xid))
341 /*
342 * "ddp_done" trigger invalidation of HW
343 * specific DDP context
344 */
345 cmd->write_data_len = lport->tt.ddp_done(lport,
346 ep->xid);
347
348 /*
349 * Resetting same variable to indicate HW's
350 * DDP context has been invalidated to avoid
351 * re_invalidation of same context (context is
352 * identified using ep->xid)
353 */
354 cmd->was_ddp_setup = 0;
355 }
356 }
357}