aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/target/tcm_fc/tfc_io.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-08-03 21:12:09 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-08-03 21:12:09 -0400
commita9e4e6e14c322e08d1c615afc8f504fb415f9613 (patch)
tree7c842bbfdc322b5ff99644e8b1bc7b415669233e /drivers/target/tcm_fc/tfc_io.c
parent27665ffa22b9b83bab226bf12c61424f7f1f8995 (diff)
parentdcd998ccdbf74a7d8fe0f0a44e85da1ed5975946 (diff)
Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending
* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending: tcm_fc: Handle DDP/SW fc_frame_payload_get failures in ft_recv_write_data target: Fix bug for transport_generic_wait_for_tasks with direct operation target: iscsi_target depends on NET target: Fix WRITE_SAME_16 lba assignment breakage MAINTAINERS: Add target-devel list for drivers/target/ iscsi-target: Fix CONFIG_SMP=n and CONFIG_MODULES=n build failure iscsi-target: Fix snprintf usage with MAX_PORTAL_LEN iscsi-target: Fix uninitialized usage of cmd->pad_bytes iscsi-target: strlen() doesn't count the terminator iscsi-target: Fix NULL dereference on allocation failure
Diffstat (limited to 'drivers/target/tcm_fc/tfc_io.c')
-rw-r--r--drivers/target/tcm_fc/tfc_io.c121
1 files changed, 72 insertions, 49 deletions
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)
213 if (!(ntoh24(fh->fh_f_ctl) & FC_FC_REL_OFF)) 213 if (!(ntoh24(fh->fh_f_ctl) & FC_FC_REL_OFF))
214 goto drop; 214 goto drop;
215 215
216 f_ctl = ntoh24(fh->fh_f_ctl);
217 ep = fc_seq_exch(seq);
218 lport = ep->lp;
219 if (cmd->was_ddp_setup) {
220 BUG_ON(!ep);
221 BUG_ON(!lport);
222 }
223
216 /* 224 /*
217 * Doesn't expect even single byte of payload. Payload 225 * Doesn't expect payload if DDP is setup. Payload
218 * is expected to be copied directly to user buffers 226 * is expected to be copied directly to user buffers
219 * due to DDP (Large Rx offload) feature, hence 227 * due to DDP (Large Rx offload),
220 * BUG_ON if BUF is non-NULL
221 */ 228 */
222 buf = fc_frame_payload_get(fp, 1); 229 buf = fc_frame_payload_get(fp, 1);
223 if (cmd->was_ddp_setup && buf) { 230 if (buf)
224 pr_debug("%s: When DDP was setup, not expected to" 231 pr_err("%s: xid 0x%x, f_ctl 0x%x, cmd->sg %p, "
225 "receive frame with payload, Payload shall be" 232 "cmd->sg_cnt 0x%x. DDP was setup"
226 "copied directly to buffer instead of coming " 233 " hence not expected to receive frame with "
227 "via. legacy receive queues\n", __func__); 234 "payload, Frame will be dropped if "
228 BUG_ON(buf); 235 "'Sequence Initiative' bit in f_ctl is "
229 } 236 "not set\n", __func__, ep->xid, f_ctl,
237 cmd->sg, cmd->sg_cnt);
238 /*
239 * Invalidate HW DDP context if it was setup for respective
240 * command. Invalidation of HW DDP context is requited in both
241 * situation (success and error).
242 */
243 ft_invl_hw_context(cmd);
230 244
231 /* 245 /*
232 * If ft_cmd indicated 'ddp_setup', in that case only the last frame 246 * If "Sequence Initiative (TSI)" bit set in f_ctl, means last
233 * should come with 'TSI bit being set'. If 'TSI bit is not set and if 247 * write data frame is received successfully where payload is
234 * data frame appears here, means error condition. In both the cases 248 * posted directly to user buffer and only the last frame's
235 * release the DDP context (ddp_put) and in error case, as well 249 * header is posted in receive queue.
236 * initiate error recovery mechanism. 250 *
251 * If "Sequence Initiative (TSI)" bit is not set, means error
252 * condition w.r.t. DDP, hence drop the packet and let explict
253 * ABORTS from other end of exchange timer trigger the recovery.
237 */ 254 */
238 ep = fc_seq_exch(seq); 255 if (f_ctl & FC_FC_SEQ_INIT)
239 if (cmd->was_ddp_setup) { 256 goto last_frame;
240 BUG_ON(!ep); 257 else
241 lport = ep->lp; 258 goto drop;
242 BUG_ON(!lport);
243 }
244 if (cmd->was_ddp_setup && ep->xid != FC_XID_UNKNOWN) {
245 f_ctl = ntoh24(fh->fh_f_ctl);
246 /*
247 * If TSI bit set in f_ctl, means last write data frame is
248 * received successfully where payload is posted directly
249 * to user buffer and only the last frame's header is posted
250 * in legacy receive queue
251 */
252 if (f_ctl & FC_FC_SEQ_INIT) { /* TSI bit set in FC frame */
253 cmd->write_data_len = lport->tt.ddp_done(lport,
254 ep->xid);
255 goto last_frame;
256 } else {
257 /*
258 * Updating the write_data_len may be meaningless at
259 * this point, but just in case if required in future
260 * for debugging or any other purpose
261 */
262 pr_err("%s: Received frame with TSI bit not"
263 " being SET, dropping the frame, "
264 "cmd->sg <%p>, cmd->sg_cnt <0x%x>\n",
265 __func__, cmd->sg, cmd->sg_cnt);
266 cmd->write_data_len = lport->tt.ddp_done(lport,
267 ep->xid);
268 lport->tt.seq_exch_abort(cmd->seq, 0);
269 goto drop;
270 }
271 }
272 259
273 rel_off = ntohl(fh->fh_parm_offset); 260 rel_off = ntohl(fh->fh_parm_offset);
274 frame_len = fr_len(fp); 261 frame_len = fr_len(fp);
@@ -331,3 +318,39 @@ last_frame:
331drop: 318drop:
332 fc_frame_free(fp); 319 fc_frame_free(fp);
333} 320}
321
322/*
323 * Handle and cleanup any HW specific resources if
324 * received ABORTS, errors, timeouts.
325 */
326void ft_invl_hw_context(struct ft_cmd *cmd)
327{
328 struct fc_seq *seq = cmd->seq;
329 struct fc_exch *ep = NULL;
330 struct fc_lport *lport = NULL;
331
332 BUG_ON(!cmd);
333
334 /* Cleanup the DDP context in HW if DDP was setup */
335 if (cmd->was_ddp_setup && seq) {
336 ep = fc_seq_exch(seq);
337 if (ep) {
338 lport = ep->lp;
339 if (lport && (ep->xid <= lport->lro_xid))
340 /*
341 * "ddp_done" trigger invalidation of HW
342 * specific DDP context
343 */
344 cmd->write_data_len = lport->tt.ddp_done(lport,
345 ep->xid);
346
347 /*
348 * Resetting same variable to indicate HW's
349 * DDP context has been invalidated to avoid
350 * re_invalidation of same context (context is
351 * identified using ep->xid)
352 */
353 cmd->was_ddp_setup = 0;
354 }
355 }
356}