diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
commit | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch) | |
tree | a8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /drivers/target/tcm_fc/tfc_cmd.c | |
parent | 406089d01562f1e2bf9f089fd7637009ebaad589 (diff) |
Patched in Tegra support.
Diffstat (limited to 'drivers/target/tcm_fc/tfc_cmd.c')
-rw-r--r-- | drivers/target/tcm_fc/tfc_cmd.c | 239 |
1 files changed, 163 insertions, 76 deletions
diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index b406f178ff3..80fbcde00cb 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c | |||
@@ -19,6 +19,8 @@ | |||
19 | 19 | ||
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | #include <linux/moduleparam.h> | 21 | #include <linux/moduleparam.h> |
22 | #include <linux/version.h> | ||
23 | #include <generated/utsrelease.h> | ||
22 | #include <linux/utsname.h> | 24 | #include <linux/utsname.h> |
23 | #include <linux/init.h> | 25 | #include <linux/init.h> |
24 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
@@ -38,8 +40,12 @@ | |||
38 | #include <scsi/fc_encode.h> | 40 | #include <scsi/fc_encode.h> |
39 | 41 | ||
40 | #include <target/target_core_base.h> | 42 | #include <target/target_core_base.h> |
41 | #include <target/target_core_fabric.h> | 43 | #include <target/target_core_transport.h> |
44 | #include <target/target_core_fabric_ops.h> | ||
45 | #include <target/target_core_device.h> | ||
46 | #include <target/target_core_tpg.h> | ||
42 | #include <target/target_core_configfs.h> | 47 | #include <target/target_core_configfs.h> |
48 | #include <target/target_core_tmr.h> | ||
43 | #include <target/configfs_macros.h> | 49 | #include <target/configfs_macros.h> |
44 | 50 | ||
45 | #include "tcm_fc.h" | 51 | #include "tcm_fc.h" |
@@ -47,7 +53,7 @@ | |||
47 | /* | 53 | /* |
48 | * Dump cmd state for debugging. | 54 | * Dump cmd state for debugging. |
49 | */ | 55 | */ |
50 | static void _ft_dump_cmd(struct ft_cmd *cmd, const char *caller) | 56 | void ft_dump_cmd(struct ft_cmd *cmd, const char *caller) |
51 | { | 57 | { |
52 | struct fc_exch *ep; | 58 | struct fc_exch *ep; |
53 | struct fc_seq *sp; | 59 | struct fc_seq *sp; |
@@ -58,6 +64,9 @@ static void _ft_dump_cmd(struct ft_cmd *cmd, const char *caller) | |||
58 | se_cmd = &cmd->se_cmd; | 64 | se_cmd = &cmd->se_cmd; |
59 | pr_debug("%s: cmd %p sess %p seq %p se_cmd %p\n", | 65 | pr_debug("%s: cmd %p sess %p seq %p se_cmd %p\n", |
60 | caller, cmd, cmd->sess, cmd->seq, se_cmd); | 66 | caller, cmd, cmd->sess, cmd->seq, se_cmd); |
67 | pr_debug("%s: cmd %p cdb %p\n", | ||
68 | caller, cmd, cmd->cdb); | ||
69 | pr_debug("%s: cmd %p lun %d\n", caller, cmd, cmd->lun); | ||
61 | 70 | ||
62 | pr_debug("%s: cmd %p data_nents %u len %u se_cmd_flags <0x%x>\n", | 71 | pr_debug("%s: cmd %p data_nents %u len %u se_cmd_flags <0x%x>\n", |
63 | caller, cmd, se_cmd->t_data_nents, | 72 | caller, cmd, se_cmd->t_data_nents, |
@@ -77,12 +86,8 @@ static void _ft_dump_cmd(struct ft_cmd *cmd, const char *caller) | |||
77 | caller, cmd, ep->sid, ep->did, ep->oxid, ep->rxid, | 86 | caller, cmd, ep->sid, ep->did, ep->oxid, ep->rxid, |
78 | sp->id, ep->esb_stat); | 87 | sp->id, ep->esb_stat); |
79 | } | 88 | } |
80 | } | 89 | print_hex_dump(KERN_INFO, "ft_dump_cmd ", DUMP_PREFIX_NONE, |
81 | 90 | 16, 4, cmd->cdb, MAX_COMMAND_SIZE, 0); | |
82 | void ft_dump_cmd(struct ft_cmd *cmd, const char *caller) | ||
83 | { | ||
84 | if (unlikely(ft_debug_logging)) | ||
85 | _ft_dump_cmd(cmd, caller); | ||
86 | } | 91 | } |
87 | 92 | ||
88 | static void ft_free_cmd(struct ft_cmd *cmd) | 93 | static void ft_free_cmd(struct ft_cmd *cmd) |
@@ -108,10 +113,9 @@ void ft_release_cmd(struct se_cmd *se_cmd) | |||
108 | ft_free_cmd(cmd); | 113 | ft_free_cmd(cmd); |
109 | } | 114 | } |
110 | 115 | ||
111 | int ft_check_stop_free(struct se_cmd *se_cmd) | 116 | void ft_check_stop_free(struct se_cmd *se_cmd) |
112 | { | 117 | { |
113 | transport_generic_free_cmd(se_cmd, 0); | 118 | transport_generic_free_cmd(se_cmd, 0, 0); |
114 | return 1; | ||
115 | } | 119 | } |
116 | 120 | ||
117 | /* | 121 | /* |
@@ -126,8 +130,6 @@ int ft_queue_status(struct se_cmd *se_cmd) | |||
126 | struct fc_exch *ep; | 130 | struct fc_exch *ep; |
127 | size_t len; | 131 | size_t len; |
128 | 132 | ||
129 | if (cmd->aborted) | ||
130 | return 0; | ||
131 | ft_dump_cmd(cmd, __func__); | 133 | ft_dump_cmd(cmd, __func__); |
132 | ep = fc_seq_exch(cmd->seq); | 134 | ep = fc_seq_exch(cmd->seq); |
133 | lport = ep->lp; | 135 | lport = ep->lp; |
@@ -194,13 +196,11 @@ int ft_write_pending(struct se_cmd *se_cmd) | |||
194 | 196 | ||
195 | ft_dump_cmd(cmd, __func__); | 197 | ft_dump_cmd(cmd, __func__); |
196 | 198 | ||
197 | if (cmd->aborted) | ||
198 | return 0; | ||
199 | ep = fc_seq_exch(cmd->seq); | 199 | ep = fc_seq_exch(cmd->seq); |
200 | lport = ep->lp; | 200 | lport = ep->lp; |
201 | fp = fc_frame_alloc(lport, sizeof(*txrdy)); | 201 | fp = fc_frame_alloc(lport, sizeof(*txrdy)); |
202 | if (!fp) | 202 | if (!fp) |
203 | return -ENOMEM; /* Signal QUEUE_FULL */ | 203 | return PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES; |
204 | 204 | ||
205 | txrdy = fc_frame_payload_get(fp, sizeof(*txrdy)); | 205 | txrdy = fc_frame_payload_get(fp, sizeof(*txrdy)); |
206 | memset(txrdy, 0, sizeof(*txrdy)); | 206 | memset(txrdy, 0, sizeof(*txrdy)); |
@@ -220,10 +220,20 @@ int ft_write_pending(struct se_cmd *se_cmd) | |||
220 | */ | 220 | */ |
221 | if ((ep->xid <= lport->lro_xid) && | 221 | if ((ep->xid <= lport->lro_xid) && |
222 | (fh->fh_r_ctl == FC_RCTL_DD_DATA_DESC)) { | 222 | (fh->fh_r_ctl == FC_RCTL_DD_DATA_DESC)) { |
223 | if ((se_cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) && | 223 | if (se_cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) { |
224 | lport->tt.ddp_target(lport, ep->xid, | 224 | /* |
225 | se_cmd->t_data_sg, | 225 | * cmd may have been broken up into multiple |
226 | se_cmd->t_data_nents)) | 226 | * tasks. Link their sgs together so we can |
227 | * operate on them all at once. | ||
228 | */ | ||
229 | transport_do_task_sg_chain(se_cmd); | ||
230 | cmd->sg = se_cmd->t_tasks_sg_chained; | ||
231 | cmd->sg_cnt = | ||
232 | se_cmd->t_tasks_sg_chained_no; | ||
233 | } | ||
234 | if (cmd->sg && lport->tt.ddp_target(lport, ep->xid, | ||
235 | cmd->sg, | ||
236 | cmd->sg_cnt)) | ||
227 | cmd->was_ddp_setup = 1; | 237 | cmd->was_ddp_setup = 1; |
228 | } | 238 | } |
229 | } | 239 | } |
@@ -235,8 +245,6 @@ u32 ft_get_task_tag(struct se_cmd *se_cmd) | |||
235 | { | 245 | { |
236 | struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); | 246 | struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); |
237 | 247 | ||
238 | if (cmd->aborted) | ||
239 | return ~0; | ||
240 | return fc_seq_exch(cmd->seq)->rxid; | 248 | return fc_seq_exch(cmd->seq)->rxid; |
241 | } | 249 | } |
242 | 250 | ||
@@ -245,6 +253,11 @@ int ft_get_cmd_state(struct se_cmd *se_cmd) | |||
245 | return 0; | 253 | return 0; |
246 | } | 254 | } |
247 | 255 | ||
256 | int ft_is_state_remove(struct se_cmd *se_cmd) | ||
257 | { | ||
258 | return 0; /* XXX TBD */ | ||
259 | } | ||
260 | |||
248 | /* | 261 | /* |
249 | * FC sequence response handler for follow-on sequences (data) and aborts. | 262 | * FC sequence response handler for follow-on sequences (data) and aborts. |
250 | */ | 263 | */ |
@@ -253,10 +266,11 @@ static void ft_recv_seq(struct fc_seq *sp, struct fc_frame *fp, void *arg) | |||
253 | struct ft_cmd *cmd = arg; | 266 | struct ft_cmd *cmd = arg; |
254 | struct fc_frame_header *fh; | 267 | struct fc_frame_header *fh; |
255 | 268 | ||
256 | if (unlikely(IS_ERR(fp))) { | 269 | if (IS_ERR(fp)) { |
257 | /* XXX need to find cmd if queued */ | 270 | /* XXX need to find cmd if queued */ |
271 | cmd->se_cmd.t_state = TRANSPORT_REMOVE; | ||
258 | cmd->seq = NULL; | 272 | cmd->seq = NULL; |
259 | cmd->aborted = true; | 273 | transport_generic_free_cmd(&cmd->se_cmd, 0, 0); |
260 | return; | 274 | return; |
261 | } | 275 | } |
262 | 276 | ||
@@ -274,7 +288,7 @@ static void ft_recv_seq(struct fc_seq *sp, struct fc_frame *fp, void *arg) | |||
274 | __func__, fh->fh_r_ctl); | 288 | __func__, fh->fh_r_ctl); |
275 | ft_invl_hw_context(cmd); | 289 | ft_invl_hw_context(cmd); |
276 | fc_frame_free(fp); | 290 | fc_frame_free(fp); |
277 | transport_generic_free_cmd(&cmd->se_cmd, 0); | 291 | transport_generic_free_cmd(&cmd->se_cmd, 0, 0); |
278 | break; | 292 | break; |
279 | } | 293 | } |
280 | } | 294 | } |
@@ -316,12 +330,10 @@ static void ft_send_resp_status(struct fc_lport *lport, | |||
316 | 330 | ||
317 | fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_DD_CMD_STATUS, 0); | 331 | fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_DD_CMD_STATUS, 0); |
318 | sp = fr_seq(fp); | 332 | sp = fr_seq(fp); |
319 | if (sp) { | 333 | if (sp) |
320 | lport->tt.seq_send(lport, sp, fp); | 334 | lport->tt.seq_send(lport, sp, fp); |
321 | lport->tt.exch_done(sp); | 335 | else |
322 | } else { | ||
323 | lport->tt.frame_send(lport, fp); | 336 | lport->tt.frame_send(lport, fp); |
324 | } | ||
325 | } | 337 | } |
326 | 338 | ||
327 | /* | 339 | /* |
@@ -351,8 +363,9 @@ static void ft_send_resp_code_and_free(struct ft_cmd *cmd, | |||
351 | */ | 363 | */ |
352 | static void ft_send_tm(struct ft_cmd *cmd) | 364 | static void ft_send_tm(struct ft_cmd *cmd) |
353 | { | 365 | { |
366 | struct se_tmr_req *tmr; | ||
354 | struct fcp_cmnd *fcp; | 367 | struct fcp_cmnd *fcp; |
355 | int rc; | 368 | struct ft_sess *sess; |
356 | u8 tm_func; | 369 | u8 tm_func; |
357 | 370 | ||
358 | fcp = fc_frame_payload_get(cmd->req_frame, sizeof(*fcp)); | 371 | fcp = fc_frame_payload_get(cmd->req_frame, sizeof(*fcp)); |
@@ -383,12 +396,45 @@ static void ft_send_tm(struct ft_cmd *cmd) | |||
383 | return; | 396 | return; |
384 | } | 397 | } |
385 | 398 | ||
386 | /* FIXME: Add referenced task tag for ABORT_TASK */ | 399 | pr_debug("alloc tm cmd fn %d\n", tm_func); |
387 | rc = target_submit_tmr(&cmd->se_cmd, cmd->sess->se_sess, | 400 | tmr = core_tmr_alloc_req(&cmd->se_cmd, cmd, tm_func); |
388 | &cmd->ft_sense_buffer[0], scsilun_to_int(&fcp->fc_lun), | 401 | if (!tmr) { |
389 | cmd, tm_func, GFP_KERNEL, 0, 0); | 402 | pr_debug("alloc failed\n"); |
390 | if (rc < 0) | ||
391 | ft_send_resp_code_and_free(cmd, FCP_TMF_FAILED); | 403 | ft_send_resp_code_and_free(cmd, FCP_TMF_FAILED); |
404 | return; | ||
405 | } | ||
406 | cmd->se_cmd.se_tmr_req = tmr; | ||
407 | |||
408 | switch (fcp->fc_tm_flags) { | ||
409 | case FCP_TMF_LUN_RESET: | ||
410 | cmd->lun = scsilun_to_int((struct scsi_lun *)fcp->fc_lun); | ||
411 | if (transport_lookup_tmr_lun(&cmd->se_cmd, cmd->lun) < 0) { | ||
412 | /* | ||
413 | * Make sure to clean up newly allocated TMR request | ||
414 | * since "unable to handle TMR request because failed | ||
415 | * to get to LUN" | ||
416 | */ | ||
417 | pr_debug("Failed to get LUN for TMR func %d, " | ||
418 | "se_cmd %p, unpacked_lun %d\n", | ||
419 | tm_func, &cmd->se_cmd, cmd->lun); | ||
420 | ft_dump_cmd(cmd, __func__); | ||
421 | sess = cmd->sess; | ||
422 | transport_send_check_condition_and_sense(&cmd->se_cmd, | ||
423 | cmd->se_cmd.scsi_sense_reason, 0); | ||
424 | transport_generic_free_cmd(&cmd->se_cmd, 0, 0); | ||
425 | ft_sess_put(sess); | ||
426 | return; | ||
427 | } | ||
428 | break; | ||
429 | case FCP_TMF_TGT_RESET: | ||
430 | case FCP_TMF_CLR_TASK_SET: | ||
431 | case FCP_TMF_ABT_TASK_SET: | ||
432 | case FCP_TMF_CLR_ACA: | ||
433 | break; | ||
434 | default: | ||
435 | return; | ||
436 | } | ||
437 | transport_generic_handle_tmr(&cmd->se_cmd); | ||
392 | } | 438 | } |
393 | 439 | ||
394 | /* | 440 | /* |
@@ -400,8 +446,6 @@ int ft_queue_tm_resp(struct se_cmd *se_cmd) | |||
400 | struct se_tmr_req *tmr = se_cmd->se_tmr_req; | 446 | struct se_tmr_req *tmr = se_cmd->se_tmr_req; |
401 | enum fcp_resp_rsp_codes code; | 447 | enum fcp_resp_rsp_codes code; |
402 | 448 | ||
403 | if (cmd->aborted) | ||
404 | return 0; | ||
405 | switch (tmr->response) { | 449 | switch (tmr->response) { |
406 | case TMR_FUNCTION_COMPLETE: | 450 | case TMR_FUNCTION_COMPLETE: |
407 | code = FCP_TMF_CMPL; | 451 | code = FCP_TMF_CMPL; |
@@ -493,9 +537,12 @@ static void ft_send_work(struct work_struct *work) | |||
493 | { | 537 | { |
494 | struct ft_cmd *cmd = container_of(work, struct ft_cmd, work); | 538 | struct ft_cmd *cmd = container_of(work, struct ft_cmd, work); |
495 | struct fc_frame_header *fh = fc_frame_header_get(cmd->req_frame); | 539 | struct fc_frame_header *fh = fc_frame_header_get(cmd->req_frame); |
540 | struct se_cmd *se_cmd; | ||
496 | struct fcp_cmnd *fcp; | 541 | struct fcp_cmnd *fcp; |
497 | int data_dir = 0; | 542 | int data_dir = 0; |
543 | u32 data_len; | ||
498 | int task_attr; | 544 | int task_attr; |
545 | int ret; | ||
499 | 546 | ||
500 | fcp = fc_frame_payload_get(cmd->req_frame, sizeof(*fcp)); | 547 | fcp = fc_frame_payload_get(cmd->req_frame, sizeof(*fcp)); |
501 | if (!fcp) | 548 | if (!fcp) |
@@ -504,6 +551,56 @@ static void ft_send_work(struct work_struct *work) | |||
504 | if (fcp->fc_flags & FCP_CFL_LEN_MASK) | 551 | if (fcp->fc_flags & FCP_CFL_LEN_MASK) |
505 | goto err; /* not handling longer CDBs yet */ | 552 | goto err; /* not handling longer CDBs yet */ |
506 | 553 | ||
554 | if (fcp->fc_tm_flags) { | ||
555 | task_attr = FCP_PTA_SIMPLE; | ||
556 | data_dir = DMA_NONE; | ||
557 | data_len = 0; | ||
558 | } else { | ||
559 | switch (fcp->fc_flags & (FCP_CFL_RDDATA | FCP_CFL_WRDATA)) { | ||
560 | case 0: | ||
561 | data_dir = DMA_NONE; | ||
562 | break; | ||
563 | case FCP_CFL_RDDATA: | ||
564 | data_dir = DMA_FROM_DEVICE; | ||
565 | break; | ||
566 | case FCP_CFL_WRDATA: | ||
567 | data_dir = DMA_TO_DEVICE; | ||
568 | break; | ||
569 | case FCP_CFL_WRDATA | FCP_CFL_RDDATA: | ||
570 | goto err; /* TBD not supported by tcm_fc yet */ | ||
571 | } | ||
572 | /* | ||
573 | * Locate the SAM Task Attr from fc_pri_ta | ||
574 | */ | ||
575 | switch (fcp->fc_pri_ta & FCP_PTA_MASK) { | ||
576 | case FCP_PTA_HEADQ: | ||
577 | task_attr = MSG_HEAD_TAG; | ||
578 | break; | ||
579 | case FCP_PTA_ORDERED: | ||
580 | task_attr = MSG_ORDERED_TAG; | ||
581 | break; | ||
582 | case FCP_PTA_ACA: | ||
583 | task_attr = MSG_ACA_TAG; | ||
584 | break; | ||
585 | case FCP_PTA_SIMPLE: /* Fallthrough */ | ||
586 | default: | ||
587 | task_attr = MSG_SIMPLE_TAG; | ||
588 | } | ||
589 | |||
590 | |||
591 | task_attr = fcp->fc_pri_ta & FCP_PTA_MASK; | ||
592 | data_len = ntohl(fcp->fc_dl); | ||
593 | cmd->cdb = fcp->fc_cdb; | ||
594 | } | ||
595 | |||
596 | se_cmd = &cmd->se_cmd; | ||
597 | /* | ||
598 | * Initialize struct se_cmd descriptor from target_core_mod | ||
599 | * infrastructure | ||
600 | */ | ||
601 | transport_init_se_cmd(se_cmd, &ft_configfs->tf_ops, cmd->sess->se_sess, | ||
602 | data_len, data_dir, task_attr, | ||
603 | &cmd->ft_sense_buffer[0]); | ||
507 | /* | 604 | /* |
508 | * Check for FCP task management flags | 605 | * Check for FCP task management flags |
509 | */ | 606 | */ |
@@ -512,48 +609,38 @@ static void ft_send_work(struct work_struct *work) | |||
512 | return; | 609 | return; |
513 | } | 610 | } |
514 | 611 | ||
515 | switch (fcp->fc_flags & (FCP_CFL_RDDATA | FCP_CFL_WRDATA)) { | 612 | fc_seq_exch(cmd->seq)->lp->tt.seq_set_resp(cmd->seq, ft_recv_seq, cmd); |
516 | case 0: | 613 | |
517 | data_dir = DMA_NONE; | 614 | cmd->lun = scsilun_to_int((struct scsi_lun *)fcp->fc_lun); |
518 | break; | 615 | ret = transport_lookup_cmd_lun(&cmd->se_cmd, cmd->lun); |
519 | case FCP_CFL_RDDATA: | 616 | if (ret < 0) { |
520 | data_dir = DMA_FROM_DEVICE; | 617 | ft_dump_cmd(cmd, __func__); |
521 | break; | 618 | transport_send_check_condition_and_sense(&cmd->se_cmd, |
522 | case FCP_CFL_WRDATA: | 619 | cmd->se_cmd.scsi_sense_reason, 0); |
523 | data_dir = DMA_TO_DEVICE; | 620 | return; |
524 | break; | ||
525 | case FCP_CFL_WRDATA | FCP_CFL_RDDATA: | ||
526 | goto err; /* TBD not supported by tcm_fc yet */ | ||
527 | } | ||
528 | /* | ||
529 | * Locate the SAM Task Attr from fc_pri_ta | ||
530 | */ | ||
531 | switch (fcp->fc_pri_ta & FCP_PTA_MASK) { | ||
532 | case FCP_PTA_HEADQ: | ||
533 | task_attr = MSG_HEAD_TAG; | ||
534 | break; | ||
535 | case FCP_PTA_ORDERED: | ||
536 | task_attr = MSG_ORDERED_TAG; | ||
537 | break; | ||
538 | case FCP_PTA_ACA: | ||
539 | task_attr = MSG_ACA_TAG; | ||
540 | break; | ||
541 | case FCP_PTA_SIMPLE: /* Fallthrough */ | ||
542 | default: | ||
543 | task_attr = MSG_SIMPLE_TAG; | ||
544 | } | 621 | } |
545 | 622 | ||
546 | fc_seq_exch(cmd->seq)->lp->tt.seq_set_resp(cmd->seq, ft_recv_seq, cmd); | 623 | ret = transport_generic_allocate_tasks(se_cmd, cmd->cdb); |
547 | /* | 624 | |
548 | * Use a single se_cmd->cmd_kref as we expect to release se_cmd | 625 | pr_debug("r_ctl %x alloc task ret %d\n", fh->fh_r_ctl, ret); |
549 | * directly from ft_check_stop_free callback in response path. | 626 | ft_dump_cmd(cmd, __func__); |
550 | */ | ||
551 | if (target_submit_cmd(&cmd->se_cmd, cmd->sess->se_sess, fcp->fc_cdb, | ||
552 | &cmd->ft_sense_buffer[0], scsilun_to_int(&fcp->fc_lun), | ||
553 | ntohl(fcp->fc_dl), task_attr, data_dir, 0)) | ||
554 | goto err; | ||
555 | 627 | ||
556 | pr_debug("r_ctl %x alloc target_submit_cmd\n", fh->fh_r_ctl); | 628 | if (ret == -ENOMEM) { |
629 | transport_send_check_condition_and_sense(se_cmd, | ||
630 | TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0); | ||
631 | transport_generic_free_cmd(se_cmd, 0, 0); | ||
632 | return; | ||
633 | } | ||
634 | if (ret == -EINVAL) { | ||
635 | if (se_cmd->se_cmd_flags & SCF_SCSI_RESERVATION_CONFLICT) | ||
636 | ft_queue_status(se_cmd); | ||
637 | else | ||
638 | transport_send_check_condition_and_sense(se_cmd, | ||
639 | se_cmd->scsi_sense_reason, 0); | ||
640 | transport_generic_free_cmd(se_cmd, 0, 0); | ||
641 | return; | ||
642 | } | ||
643 | transport_generic_handle_cdb(se_cmd); | ||
557 | return; | 644 | return; |
558 | 645 | ||
559 | err: | 646 | err: |