diff options
Diffstat (limited to 'drivers')
-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_io.c | 121 |
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 | ||
188 | ssize_t ft_format_wwn(char *, size_t, u64); | 188 | ssize_t ft_format_wwn(char *, size_t, u64); |
189 | 189 | ||
190 | /* | ||
191 | * Underlying HW specific helper function | ||
192 | */ | ||
193 | void 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: | |||
332 | drop: | 319 | drop: |
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 | */ | ||
327 | void 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 | } | ||