diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-23 19:37:58 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-23 19:37:58 -0400 |
commit | a55da8a0ddac4ebe0d7b3a1e5902cb1d286f8062 (patch) | |
tree | 9a9ae5bceedb3d7e35a656769c4c83c84d2866f5 | |
parent | e6995f22d3a0f0f56716fdd62a9cbc0c0791f824 (diff) | |
parent | 1ba0158fa66b5b2c597a748f87be1650c9960ccc (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending
Pull SCSI target fixes from Nicholas Bellinger:
"Here are the outstanding target-pending fixes for v4.9-rc2.
This includes:
- Fix v4.1.y+ reference leak regression with concurrent TMR
ABORT_TASK + session shutdown. (Vaibhav Tandon)
- Enable tcm_fc w/ SCF_USE_CPUID to avoid host exchange timeouts
(Hannes)
- target/user error sense handling fixes. (Andy + MNC + HCH)
- Fix iscsi-target NOP_OUT error path iscsi_cmd descriptor leak
(Varun)
- Two EXTENDED_COPY SCSI status fixes for ESX VAAI (Dinesh Israni +
Nixon Vincent)
- Revert a v4.8 residual overflow change, that breaks sg_inq with
small allocation lengths.
There are a number of folks stress testing the v4.1.y regression fix
in their environments, and more folks doing iser-target I/O stress
testing atop recent v4.x.y code.
There is also one v4.2.y+ RCU conversion regression related to
explicit NodeACL configfs changes, that is still being tracked down"
* git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending:
target/tcm_fc: use CPU affinity for responses
target/tcm_fc: Update debugging statements to match libfc usage
target/tcm_fc: return detailed error in ft_sess_create()
target/tcm_fc: print command pointer in debug message
target: fix potential race window in target_sess_cmd_list_waiting()
Revert "target: Fix residual overflow handling in target_complete_cmd_with_length"
target: Don't override EXTENDED_COPY xcopy_pt_cmd SCSI status code
target: Make EXTENDED_COPY 0xe4 failure return COPY TARGET DEVICE NOT REACHABLE
target: Re-add missing SCF_ACK_KREF assignment in v4.1.y
iscsi-target: fix iscsi cmd leak
iscsi-target: fix spelling mistake "Unsolicitied" -> "Unsolicited"
target/user: Fix comments to not refer to data ring
target/user: Return an error if cmd data size is too large
target/user: Use sense_reason_t in tcmu_queue_cmd_ring
-rw-r--r-- | drivers/target/iscsi/iscsi_target.c | 6 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target_login.c | 4 | ||||
-rw-r--r-- | drivers/target/target_core_transport.c | 39 | ||||
-rw-r--r-- | drivers/target/target_core_user.c | 50 | ||||
-rw-r--r-- | drivers/target/target_core_xcopy.c | 34 | ||||
-rw-r--r-- | drivers/target/tcm_fc/tfc_cmd.c | 4 | ||||
-rw-r--r-- | drivers/target/tcm_fc/tfc_sess.c | 42 | ||||
-rw-r--r-- | include/target/target_core_base.h | 1 |
8 files changed, 105 insertions, 75 deletions
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 39b928c2849d..b7d747e92c7a 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c | |||
@@ -1804,6 +1804,10 @@ int iscsit_process_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd, | |||
1804 | * Otherwise, initiator is not expecting a NOPIN is response. | 1804 | * Otherwise, initiator is not expecting a NOPIN is response. |
1805 | * Just ignore for now. | 1805 | * Just ignore for now. |
1806 | */ | 1806 | */ |
1807 | |||
1808 | if (cmd) | ||
1809 | iscsit_free_cmd(cmd, false); | ||
1810 | |||
1807 | return 0; | 1811 | return 0; |
1808 | } | 1812 | } |
1809 | EXPORT_SYMBOL(iscsit_process_nop_out); | 1813 | EXPORT_SYMBOL(iscsit_process_nop_out); |
@@ -2982,7 +2986,7 @@ iscsit_build_nopin_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn, | |||
2982 | 2986 | ||
2983 | pr_debug("Built NOPIN %s Response ITT: 0x%08x, TTT: 0x%08x," | 2987 | pr_debug("Built NOPIN %s Response ITT: 0x%08x, TTT: 0x%08x," |
2984 | " StatSN: 0x%08x, Length %u\n", (nopout_response) ? | 2988 | " StatSN: 0x%08x, Length %u\n", (nopout_response) ? |
2985 | "Solicitied" : "Unsolicitied", cmd->init_task_tag, | 2989 | "Solicited" : "Unsolicited", cmd->init_task_tag, |
2986 | cmd->targ_xfer_tag, cmd->stat_sn, cmd->buf_ptr_size); | 2990 | cmd->targ_xfer_tag, cmd->stat_sn, cmd->buf_ptr_size); |
2987 | } | 2991 | } |
2988 | EXPORT_SYMBOL(iscsit_build_nopin_rsp); | 2992 | EXPORT_SYMBOL(iscsit_build_nopin_rsp); |
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index adf419fa4291..15f79a2ca34a 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c | |||
@@ -434,7 +434,7 @@ static int iscsi_login_zero_tsih_s2( | |||
434 | 434 | ||
435 | /* | 435 | /* |
436 | * Make MaxRecvDataSegmentLength PAGE_SIZE aligned for | 436 | * Make MaxRecvDataSegmentLength PAGE_SIZE aligned for |
437 | * Immediate Data + Unsolicitied Data-OUT if necessary.. | 437 | * Immediate Data + Unsolicited Data-OUT if necessary.. |
438 | */ | 438 | */ |
439 | param = iscsi_find_param_from_key("MaxRecvDataSegmentLength", | 439 | param = iscsi_find_param_from_key("MaxRecvDataSegmentLength", |
440 | conn->param_list); | 440 | conn->param_list); |
@@ -646,7 +646,7 @@ static void iscsi_post_login_start_timers(struct iscsi_conn *conn) | |||
646 | { | 646 | { |
647 | struct iscsi_session *sess = conn->sess; | 647 | struct iscsi_session *sess = conn->sess; |
648 | /* | 648 | /* |
649 | * FIXME: Unsolicitied NopIN support for ISER | 649 | * FIXME: Unsolicited NopIN support for ISER |
650 | */ | 650 | */ |
651 | if (conn->conn_transport->transport_type == ISCSI_INFINIBAND) | 651 | if (conn->conn_transport->transport_type == ISCSI_INFINIBAND) |
652 | return; | 652 | return; |
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 6094a6beddde..7dfefd66df93 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c | |||
@@ -754,15 +754,7 @@ EXPORT_SYMBOL(target_complete_cmd); | |||
754 | 754 | ||
755 | void target_complete_cmd_with_length(struct se_cmd *cmd, u8 scsi_status, int length) | 755 | void target_complete_cmd_with_length(struct se_cmd *cmd, u8 scsi_status, int length) |
756 | { | 756 | { |
757 | if (scsi_status != SAM_STAT_GOOD) { | 757 | if (scsi_status == SAM_STAT_GOOD && length < cmd->data_length) { |
758 | return; | ||
759 | } | ||
760 | |||
761 | /* | ||
762 | * Calculate new residual count based upon length of SCSI data | ||
763 | * transferred. | ||
764 | */ | ||
765 | if (length < cmd->data_length) { | ||
766 | if (cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) { | 758 | if (cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) { |
767 | cmd->residual_count += cmd->data_length - length; | 759 | cmd->residual_count += cmd->data_length - length; |
768 | } else { | 760 | } else { |
@@ -771,12 +763,6 @@ void target_complete_cmd_with_length(struct se_cmd *cmd, u8 scsi_status, int len | |||
771 | } | 763 | } |
772 | 764 | ||
773 | cmd->data_length = length; | 765 | cmd->data_length = length; |
774 | } else if (length > cmd->data_length) { | ||
775 | cmd->se_cmd_flags |= SCF_OVERFLOW_BIT; | ||
776 | cmd->residual_count = length - cmd->data_length; | ||
777 | } else { | ||
778 | cmd->se_cmd_flags &= ~(SCF_OVERFLOW_BIT | SCF_UNDERFLOW_BIT); | ||
779 | cmd->residual_count = 0; | ||
780 | } | 766 | } |
781 | 767 | ||
782 | target_complete_cmd(cmd, scsi_status); | 768 | target_complete_cmd(cmd, scsi_status); |
@@ -1706,6 +1692,7 @@ void transport_generic_request_failure(struct se_cmd *cmd, | |||
1706 | case TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED: | 1692 | case TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED: |
1707 | case TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED: | 1693 | case TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED: |
1708 | case TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED: | 1694 | case TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED: |
1695 | case TCM_COPY_TARGET_DEVICE_NOT_REACHABLE: | ||
1709 | break; | 1696 | break; |
1710 | case TCM_OUT_OF_RESOURCES: | 1697 | case TCM_OUT_OF_RESOURCES: |
1711 | sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | 1698 | sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
@@ -2547,8 +2534,12 @@ int target_get_sess_cmd(struct se_cmd *se_cmd, bool ack_kref) | |||
2547 | * fabric acknowledgement that requires two target_put_sess_cmd() | 2534 | * fabric acknowledgement that requires two target_put_sess_cmd() |
2548 | * invocations before se_cmd descriptor release. | 2535 | * invocations before se_cmd descriptor release. |
2549 | */ | 2536 | */ |
2550 | if (ack_kref) | 2537 | if (ack_kref) { |
2551 | kref_get(&se_cmd->cmd_kref); | 2538 | if (!kref_get_unless_zero(&se_cmd->cmd_kref)) |
2539 | return -EINVAL; | ||
2540 | |||
2541 | se_cmd->se_cmd_flags |= SCF_ACK_KREF; | ||
2542 | } | ||
2552 | 2543 | ||
2553 | spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); | 2544 | spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); |
2554 | if (se_sess->sess_tearing_down) { | 2545 | if (se_sess->sess_tearing_down) { |
@@ -2627,7 +2618,7 @@ EXPORT_SYMBOL(target_put_sess_cmd); | |||
2627 | */ | 2618 | */ |
2628 | void target_sess_cmd_list_set_waiting(struct se_session *se_sess) | 2619 | void target_sess_cmd_list_set_waiting(struct se_session *se_sess) |
2629 | { | 2620 | { |
2630 | struct se_cmd *se_cmd; | 2621 | struct se_cmd *se_cmd, *tmp_cmd; |
2631 | unsigned long flags; | 2622 | unsigned long flags; |
2632 | int rc; | 2623 | int rc; |
2633 | 2624 | ||
@@ -2639,14 +2630,16 @@ void target_sess_cmd_list_set_waiting(struct se_session *se_sess) | |||
2639 | se_sess->sess_tearing_down = 1; | 2630 | se_sess->sess_tearing_down = 1; |
2640 | list_splice_init(&se_sess->sess_cmd_list, &se_sess->sess_wait_list); | 2631 | list_splice_init(&se_sess->sess_cmd_list, &se_sess->sess_wait_list); |
2641 | 2632 | ||
2642 | list_for_each_entry(se_cmd, &se_sess->sess_wait_list, se_cmd_list) { | 2633 | list_for_each_entry_safe(se_cmd, tmp_cmd, |
2634 | &se_sess->sess_wait_list, se_cmd_list) { | ||
2643 | rc = kref_get_unless_zero(&se_cmd->cmd_kref); | 2635 | rc = kref_get_unless_zero(&se_cmd->cmd_kref); |
2644 | if (rc) { | 2636 | if (rc) { |
2645 | se_cmd->cmd_wait_set = 1; | 2637 | se_cmd->cmd_wait_set = 1; |
2646 | spin_lock(&se_cmd->t_state_lock); | 2638 | spin_lock(&se_cmd->t_state_lock); |
2647 | se_cmd->transport_state |= CMD_T_FABRIC_STOP; | 2639 | se_cmd->transport_state |= CMD_T_FABRIC_STOP; |
2648 | spin_unlock(&se_cmd->t_state_lock); | 2640 | spin_unlock(&se_cmd->t_state_lock); |
2649 | } | 2641 | } else |
2642 | list_del_init(&se_cmd->se_cmd_list); | ||
2650 | } | 2643 | } |
2651 | 2644 | ||
2652 | spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); | 2645 | spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); |
@@ -2871,6 +2864,12 @@ static const struct sense_info sense_info_table[] = { | |||
2871 | .ascq = 0x03, /* LOGICAL BLOCK REFERENCE TAG CHECK FAILED */ | 2864 | .ascq = 0x03, /* LOGICAL BLOCK REFERENCE TAG CHECK FAILED */ |
2872 | .add_sector_info = true, | 2865 | .add_sector_info = true, |
2873 | }, | 2866 | }, |
2867 | [TCM_COPY_TARGET_DEVICE_NOT_REACHABLE] = { | ||
2868 | .key = COPY_ABORTED, | ||
2869 | .asc = 0x0d, | ||
2870 | .ascq = 0x02, /* COPY TARGET DEVICE NOT REACHABLE */ | ||
2871 | |||
2872 | }, | ||
2874 | [TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE] = { | 2873 | [TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE] = { |
2875 | /* | 2874 | /* |
2876 | * Returning ILLEGAL REQUEST would cause immediate IO errors on | 2875 | * Returning ILLEGAL REQUEST would cause immediate IO errors on |
diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 62bf4fe5704a..47562509b489 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c | |||
@@ -96,7 +96,7 @@ struct tcmu_dev { | |||
96 | size_t dev_size; | 96 | size_t dev_size; |
97 | u32 cmdr_size; | 97 | u32 cmdr_size; |
98 | u32 cmdr_last_cleaned; | 98 | u32 cmdr_last_cleaned; |
99 | /* Offset of data ring from start of mb */ | 99 | /* Offset of data area from start of mb */ |
100 | /* Must add data_off and mb_addr to get the address */ | 100 | /* Must add data_off and mb_addr to get the address */ |
101 | size_t data_off; | 101 | size_t data_off; |
102 | size_t data_size; | 102 | size_t data_size; |
@@ -349,7 +349,7 @@ static inline size_t spc_bitmap_free(unsigned long *bitmap) | |||
349 | 349 | ||
350 | /* | 350 | /* |
351 | * We can't queue a command until we have space available on the cmd ring *and* | 351 | * We can't queue a command until we have space available on the cmd ring *and* |
352 | * space available on the data ring. | 352 | * space available on the data area. |
353 | * | 353 | * |
354 | * Called with ring lock held. | 354 | * Called with ring lock held. |
355 | */ | 355 | */ |
@@ -389,7 +389,8 @@ static bool is_ring_space_avail(struct tcmu_dev *udev, size_t cmd_size, size_t d | |||
389 | return true; | 389 | return true; |
390 | } | 390 | } |
391 | 391 | ||
392 | static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) | 392 | static sense_reason_t |
393 | tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) | ||
393 | { | 394 | { |
394 | struct tcmu_dev *udev = tcmu_cmd->tcmu_dev; | 395 | struct tcmu_dev *udev = tcmu_cmd->tcmu_dev; |
395 | struct se_cmd *se_cmd = tcmu_cmd->se_cmd; | 396 | struct se_cmd *se_cmd = tcmu_cmd->se_cmd; |
@@ -405,7 +406,7 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) | |||
405 | DECLARE_BITMAP(old_bitmap, DATA_BLOCK_BITS); | 406 | DECLARE_BITMAP(old_bitmap, DATA_BLOCK_BITS); |
406 | 407 | ||
407 | if (test_bit(TCMU_DEV_BIT_BROKEN, &udev->flags)) | 408 | if (test_bit(TCMU_DEV_BIT_BROKEN, &udev->flags)) |
408 | return -EINVAL; | 409 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
409 | 410 | ||
410 | /* | 411 | /* |
411 | * Must be a certain minimum size for response sense info, but | 412 | * Must be a certain minimum size for response sense info, but |
@@ -432,11 +433,14 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) | |||
432 | BUG_ON(!(se_cmd->t_bidi_data_sg && se_cmd->t_bidi_data_nents)); | 433 | BUG_ON(!(se_cmd->t_bidi_data_sg && se_cmd->t_bidi_data_nents)); |
433 | data_length += se_cmd->t_bidi_data_sg->length; | 434 | data_length += se_cmd->t_bidi_data_sg->length; |
434 | } | 435 | } |
435 | if ((command_size > (udev->cmdr_size / 2)) | 436 | if ((command_size > (udev->cmdr_size / 2)) || |
436 | || data_length > udev->data_size) | 437 | data_length > udev->data_size) { |
437 | pr_warn("TCMU: Request of size %zu/%zu may be too big for %u/%zu " | 438 | pr_warn("TCMU: Request of size %zu/%zu is too big for %u/%zu " |
438 | "cmd/data ring buffers\n", command_size, data_length, | 439 | "cmd ring/data area\n", command_size, data_length, |
439 | udev->cmdr_size, udev->data_size); | 440 | udev->cmdr_size, udev->data_size); |
441 | spin_unlock_irq(&udev->cmdr_lock); | ||
442 | return TCM_INVALID_CDB_FIELD; | ||
443 | } | ||
440 | 444 | ||
441 | while (!is_ring_space_avail(udev, command_size, data_length)) { | 445 | while (!is_ring_space_avail(udev, command_size, data_length)) { |
442 | int ret; | 446 | int ret; |
@@ -450,7 +454,7 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) | |||
450 | finish_wait(&udev->wait_cmdr, &__wait); | 454 | finish_wait(&udev->wait_cmdr, &__wait); |
451 | if (!ret) { | 455 | if (!ret) { |
452 | pr_warn("tcmu: command timed out\n"); | 456 | pr_warn("tcmu: command timed out\n"); |
453 | return -ETIMEDOUT; | 457 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
454 | } | 458 | } |
455 | 459 | ||
456 | spin_lock_irq(&udev->cmdr_lock); | 460 | spin_lock_irq(&udev->cmdr_lock); |
@@ -487,9 +491,7 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) | |||
487 | 491 | ||
488 | bitmap_copy(old_bitmap, udev->data_bitmap, DATA_BLOCK_BITS); | 492 | bitmap_copy(old_bitmap, udev->data_bitmap, DATA_BLOCK_BITS); |
489 | 493 | ||
490 | /* | 494 | /* Handle allocating space from the data area */ |
491 | * Fix up iovecs, and handle if allocation in data ring wrapped. | ||
492 | */ | ||
493 | iov = &entry->req.iov[0]; | 495 | iov = &entry->req.iov[0]; |
494 | iov_cnt = 0; | 496 | iov_cnt = 0; |
495 | copy_to_data_area = (se_cmd->data_direction == DMA_TO_DEVICE | 497 | copy_to_data_area = (se_cmd->data_direction == DMA_TO_DEVICE |
@@ -526,10 +528,11 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) | |||
526 | mod_timer(&udev->timeout, | 528 | mod_timer(&udev->timeout, |
527 | round_jiffies_up(jiffies + msecs_to_jiffies(TCMU_TIME_OUT))); | 529 | round_jiffies_up(jiffies + msecs_to_jiffies(TCMU_TIME_OUT))); |
528 | 530 | ||
529 | return 0; | 531 | return TCM_NO_SENSE; |
530 | } | 532 | } |
531 | 533 | ||
532 | static int tcmu_queue_cmd(struct se_cmd *se_cmd) | 534 | static sense_reason_t |
535 | tcmu_queue_cmd(struct se_cmd *se_cmd) | ||
533 | { | 536 | { |
534 | struct se_device *se_dev = se_cmd->se_dev; | 537 | struct se_device *se_dev = se_cmd->se_dev; |
535 | struct tcmu_dev *udev = TCMU_DEV(se_dev); | 538 | struct tcmu_dev *udev = TCMU_DEV(se_dev); |
@@ -538,10 +541,10 @@ static int tcmu_queue_cmd(struct se_cmd *se_cmd) | |||
538 | 541 | ||
539 | tcmu_cmd = tcmu_alloc_cmd(se_cmd); | 542 | tcmu_cmd = tcmu_alloc_cmd(se_cmd); |
540 | if (!tcmu_cmd) | 543 | if (!tcmu_cmd) |
541 | return -ENOMEM; | 544 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
542 | 545 | ||
543 | ret = tcmu_queue_cmd_ring(tcmu_cmd); | 546 | ret = tcmu_queue_cmd_ring(tcmu_cmd); |
544 | if (ret < 0) { | 547 | if (ret != TCM_NO_SENSE) { |
545 | pr_err("TCMU: Could not queue command\n"); | 548 | pr_err("TCMU: Could not queue command\n"); |
546 | spin_lock_irq(&udev->commands_lock); | 549 | spin_lock_irq(&udev->commands_lock); |
547 | idr_remove(&udev->commands, tcmu_cmd->cmd_id); | 550 | idr_remove(&udev->commands, tcmu_cmd->cmd_id); |
@@ -561,7 +564,7 @@ static void tcmu_handle_completion(struct tcmu_cmd *cmd, struct tcmu_cmd_entry * | |||
561 | if (test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags)) { | 564 | if (test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags)) { |
562 | /* | 565 | /* |
563 | * cmd has been completed already from timeout, just reclaim | 566 | * cmd has been completed already from timeout, just reclaim |
564 | * data ring space and free cmd | 567 | * data area space and free cmd |
565 | */ | 568 | */ |
566 | free_data_area(udev, cmd); | 569 | free_data_area(udev, cmd); |
567 | 570 | ||
@@ -1129,20 +1132,9 @@ static sector_t tcmu_get_blocks(struct se_device *dev) | |||
1129 | } | 1132 | } |
1130 | 1133 | ||
1131 | static sense_reason_t | 1134 | static sense_reason_t |
1132 | tcmu_pass_op(struct se_cmd *se_cmd) | ||
1133 | { | ||
1134 | int ret = tcmu_queue_cmd(se_cmd); | ||
1135 | |||
1136 | if (ret != 0) | ||
1137 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | ||
1138 | else | ||
1139 | return TCM_NO_SENSE; | ||
1140 | } | ||
1141 | |||
1142 | static sense_reason_t | ||
1143 | tcmu_parse_cdb(struct se_cmd *cmd) | 1135 | tcmu_parse_cdb(struct se_cmd *cmd) |
1144 | { | 1136 | { |
1145 | return passthrough_parse_cdb(cmd, tcmu_pass_op); | 1137 | return passthrough_parse_cdb(cmd, tcmu_queue_cmd); |
1146 | } | 1138 | } |
1147 | 1139 | ||
1148 | static const struct target_backend_ops tcmu_ops = { | 1140 | static const struct target_backend_ops tcmu_ops = { |
diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c index 75cd85426ae3..094a1440eacb 100644 --- a/drivers/target/target_core_xcopy.c +++ b/drivers/target/target_core_xcopy.c | |||
@@ -104,7 +104,7 @@ static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op | |||
104 | } | 104 | } |
105 | mutex_unlock(&g_device_mutex); | 105 | mutex_unlock(&g_device_mutex); |
106 | 106 | ||
107 | pr_err("Unable to locate 0xe4 descriptor for EXTENDED_COPY\n"); | 107 | pr_debug_ratelimited("Unable to locate 0xe4 descriptor for EXTENDED_COPY\n"); |
108 | return -EINVAL; | 108 | return -EINVAL; |
109 | } | 109 | } |
110 | 110 | ||
@@ -185,7 +185,7 @@ static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op | |||
185 | 185 | ||
186 | static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd, | 186 | static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd, |
187 | struct xcopy_op *xop, unsigned char *p, | 187 | struct xcopy_op *xop, unsigned char *p, |
188 | unsigned short tdll) | 188 | unsigned short tdll, sense_reason_t *sense_ret) |
189 | { | 189 | { |
190 | struct se_device *local_dev = se_cmd->se_dev; | 190 | struct se_device *local_dev = se_cmd->se_dev; |
191 | unsigned char *desc = p; | 191 | unsigned char *desc = p; |
@@ -193,6 +193,8 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd, | |||
193 | unsigned short start = 0; | 193 | unsigned short start = 0; |
194 | bool src = true; | 194 | bool src = true; |
195 | 195 | ||
196 | *sense_ret = TCM_INVALID_PARAMETER_LIST; | ||
197 | |||
196 | if (offset != 0) { | 198 | if (offset != 0) { |
197 | pr_err("XCOPY target descriptor list length is not" | 199 | pr_err("XCOPY target descriptor list length is not" |
198 | " multiple of %d\n", XCOPY_TARGET_DESC_LEN); | 200 | " multiple of %d\n", XCOPY_TARGET_DESC_LEN); |
@@ -243,9 +245,16 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd, | |||
243 | rc = target_xcopy_locate_se_dev_e4(se_cmd, xop, true); | 245 | rc = target_xcopy_locate_se_dev_e4(se_cmd, xop, true); |
244 | else | 246 | else |
245 | rc = target_xcopy_locate_se_dev_e4(se_cmd, xop, false); | 247 | rc = target_xcopy_locate_se_dev_e4(se_cmd, xop, false); |
246 | 248 | /* | |
247 | if (rc < 0) | 249 | * If a matching IEEE NAA 0x83 descriptor for the requested device |
250 | * is not located on this node, return COPY_ABORTED with ASQ/ASQC | ||
251 | * 0x0d/0x02 - COPY_TARGET_DEVICE_NOT_REACHABLE to request the | ||
252 | * initiator to fall back to normal copy method. | ||
253 | */ | ||
254 | if (rc < 0) { | ||
255 | *sense_ret = TCM_COPY_TARGET_DEVICE_NOT_REACHABLE; | ||
248 | goto out; | 256 | goto out; |
257 | } | ||
249 | 258 | ||
250 | pr_debug("XCOPY TGT desc: Source dev: %p NAA IEEE WWN: 0x%16phN\n", | 259 | pr_debug("XCOPY TGT desc: Source dev: %p NAA IEEE WWN: 0x%16phN\n", |
251 | xop->src_dev, &xop->src_tid_wwn[0]); | 260 | xop->src_dev, &xop->src_tid_wwn[0]); |
@@ -653,6 +662,7 @@ static int target_xcopy_read_source( | |||
653 | rc = target_xcopy_setup_pt_cmd(xpt_cmd, xop, src_dev, &cdb[0], | 662 | rc = target_xcopy_setup_pt_cmd(xpt_cmd, xop, src_dev, &cdb[0], |
654 | remote_port, true); | 663 | remote_port, true); |
655 | if (rc < 0) { | 664 | if (rc < 0) { |
665 | ec_cmd->scsi_status = xpt_cmd->se_cmd.scsi_status; | ||
656 | transport_generic_free_cmd(se_cmd, 0); | 666 | transport_generic_free_cmd(se_cmd, 0); |
657 | return rc; | 667 | return rc; |
658 | } | 668 | } |
@@ -664,6 +674,7 @@ static int target_xcopy_read_source( | |||
664 | 674 | ||
665 | rc = target_xcopy_issue_pt_cmd(xpt_cmd); | 675 | rc = target_xcopy_issue_pt_cmd(xpt_cmd); |
666 | if (rc < 0) { | 676 | if (rc < 0) { |
677 | ec_cmd->scsi_status = xpt_cmd->se_cmd.scsi_status; | ||
667 | transport_generic_free_cmd(se_cmd, 0); | 678 | transport_generic_free_cmd(se_cmd, 0); |
668 | return rc; | 679 | return rc; |
669 | } | 680 | } |
@@ -714,6 +725,7 @@ static int target_xcopy_write_destination( | |||
714 | remote_port, false); | 725 | remote_port, false); |
715 | if (rc < 0) { | 726 | if (rc < 0) { |
716 | struct se_cmd *src_cmd = &xop->src_pt_cmd->se_cmd; | 727 | struct se_cmd *src_cmd = &xop->src_pt_cmd->se_cmd; |
728 | ec_cmd->scsi_status = xpt_cmd->se_cmd.scsi_status; | ||
717 | /* | 729 | /* |
718 | * If the failure happened before the t_mem_list hand-off in | 730 | * If the failure happened before the t_mem_list hand-off in |
719 | * target_xcopy_setup_pt_cmd(), Reset memory + clear flag so that | 731 | * target_xcopy_setup_pt_cmd(), Reset memory + clear flag so that |
@@ -729,6 +741,7 @@ static int target_xcopy_write_destination( | |||
729 | 741 | ||
730 | rc = target_xcopy_issue_pt_cmd(xpt_cmd); | 742 | rc = target_xcopy_issue_pt_cmd(xpt_cmd); |
731 | if (rc < 0) { | 743 | if (rc < 0) { |
744 | ec_cmd->scsi_status = xpt_cmd->se_cmd.scsi_status; | ||
732 | se_cmd->se_cmd_flags &= ~SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC; | 745 | se_cmd->se_cmd_flags &= ~SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC; |
733 | transport_generic_free_cmd(se_cmd, 0); | 746 | transport_generic_free_cmd(se_cmd, 0); |
734 | return rc; | 747 | return rc; |
@@ -815,9 +828,14 @@ static void target_xcopy_do_work(struct work_struct *work) | |||
815 | out: | 828 | out: |
816 | xcopy_pt_undepend_remotedev(xop); | 829 | xcopy_pt_undepend_remotedev(xop); |
817 | kfree(xop); | 830 | kfree(xop); |
818 | 831 | /* | |
819 | pr_warn("target_xcopy_do_work: Setting X-COPY CHECK_CONDITION -> sending response\n"); | 832 | * Don't override an error scsi status if it has already been set |
820 | ec_cmd->scsi_status = SAM_STAT_CHECK_CONDITION; | 833 | */ |
834 | if (ec_cmd->scsi_status == SAM_STAT_GOOD) { | ||
835 | pr_warn_ratelimited("target_xcopy_do_work: rc: %d, Setting X-COPY" | ||
836 | " CHECK_CONDITION -> sending response\n", rc); | ||
837 | ec_cmd->scsi_status = SAM_STAT_CHECK_CONDITION; | ||
838 | } | ||
821 | target_complete_cmd(ec_cmd, SAM_STAT_CHECK_CONDITION); | 839 | target_complete_cmd(ec_cmd, SAM_STAT_CHECK_CONDITION); |
822 | } | 840 | } |
823 | 841 | ||
@@ -875,7 +893,7 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd) | |||
875 | " tdll: %hu sdll: %u inline_dl: %u\n", list_id, list_id_usage, | 893 | " tdll: %hu sdll: %u inline_dl: %u\n", list_id, list_id_usage, |
876 | tdll, sdll, inline_dl); | 894 | tdll, sdll, inline_dl); |
877 | 895 | ||
878 | rc = target_xcopy_parse_target_descriptors(se_cmd, xop, &p[16], tdll); | 896 | rc = target_xcopy_parse_target_descriptors(se_cmd, xop, &p[16], tdll, &ret); |
879 | if (rc <= 0) | 897 | if (rc <= 0) |
880 | goto out; | 898 | goto out; |
881 | 899 | ||
diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index 216e18cc9133..ff5de9a96643 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c | |||
@@ -572,10 +572,10 @@ static void ft_send_work(struct work_struct *work) | |||
572 | if (target_submit_cmd(&cmd->se_cmd, cmd->sess->se_sess, fcp->fc_cdb, | 572 | if (target_submit_cmd(&cmd->se_cmd, cmd->sess->se_sess, fcp->fc_cdb, |
573 | &cmd->ft_sense_buffer[0], scsilun_to_int(&fcp->fc_lun), | 573 | &cmd->ft_sense_buffer[0], scsilun_to_int(&fcp->fc_lun), |
574 | ntohl(fcp->fc_dl), task_attr, data_dir, | 574 | ntohl(fcp->fc_dl), task_attr, data_dir, |
575 | TARGET_SCF_ACK_KREF)) | 575 | TARGET_SCF_ACK_KREF | TARGET_SCF_USE_CPUID)) |
576 | goto err; | 576 | goto err; |
577 | 577 | ||
578 | pr_debug("r_ctl %x alloc target_submit_cmd\n", fh->fh_r_ctl); | 578 | pr_debug("r_ctl %x target_submit_cmd %p\n", fh->fh_r_ctl, cmd); |
579 | return; | 579 | return; |
580 | 580 | ||
581 | err: | 581 | err: |
diff --git a/drivers/target/tcm_fc/tfc_sess.c b/drivers/target/tcm_fc/tfc_sess.c index 6ffbb603d912..fd5c3de79470 100644 --- a/drivers/target/tcm_fc/tfc_sess.c +++ b/drivers/target/tcm_fc/tfc_sess.c | |||
@@ -39,6 +39,11 @@ | |||
39 | 39 | ||
40 | #include "tcm_fc.h" | 40 | #include "tcm_fc.h" |
41 | 41 | ||
42 | #define TFC_SESS_DBG(lport, fmt, args...) \ | ||
43 | pr_debug("host%u: rport %6.6x: " fmt, \ | ||
44 | (lport)->host->host_no, \ | ||
45 | (lport)->port_id, ##args ) | ||
46 | |||
42 | static void ft_sess_delete_all(struct ft_tport *); | 47 | static void ft_sess_delete_all(struct ft_tport *); |
43 | 48 | ||
44 | /* | 49 | /* |
@@ -167,24 +172,29 @@ static struct ft_sess *ft_sess_get(struct fc_lport *lport, u32 port_id) | |||
167 | struct ft_tport *tport; | 172 | struct ft_tport *tport; |
168 | struct hlist_head *head; | 173 | struct hlist_head *head; |
169 | struct ft_sess *sess; | 174 | struct ft_sess *sess; |
175 | char *reason = "no session created"; | ||
170 | 176 | ||
171 | rcu_read_lock(); | 177 | rcu_read_lock(); |
172 | tport = rcu_dereference(lport->prov[FC_TYPE_FCP]); | 178 | tport = rcu_dereference(lport->prov[FC_TYPE_FCP]); |
173 | if (!tport) | 179 | if (!tport) { |
180 | reason = "not an FCP port"; | ||
174 | goto out; | 181 | goto out; |
182 | } | ||
175 | 183 | ||
176 | head = &tport->hash[ft_sess_hash(port_id)]; | 184 | head = &tport->hash[ft_sess_hash(port_id)]; |
177 | hlist_for_each_entry_rcu(sess, head, hash) { | 185 | hlist_for_each_entry_rcu(sess, head, hash) { |
178 | if (sess->port_id == port_id) { | 186 | if (sess->port_id == port_id) { |
179 | kref_get(&sess->kref); | 187 | kref_get(&sess->kref); |
180 | rcu_read_unlock(); | 188 | rcu_read_unlock(); |
181 | pr_debug("port_id %x found %p\n", port_id, sess); | 189 | TFC_SESS_DBG(lport, "port_id %x found %p\n", |
190 | port_id, sess); | ||
182 | return sess; | 191 | return sess; |
183 | } | 192 | } |
184 | } | 193 | } |
185 | out: | 194 | out: |
186 | rcu_read_unlock(); | 195 | rcu_read_unlock(); |
187 | pr_debug("port_id %x not found\n", port_id); | 196 | TFC_SESS_DBG(lport, "port_id %x not found, %s\n", |
197 | port_id, reason); | ||
188 | return NULL; | 198 | return NULL; |
189 | } | 199 | } |
190 | 200 | ||
@@ -195,7 +205,7 @@ static int ft_sess_alloc_cb(struct se_portal_group *se_tpg, | |||
195 | struct ft_tport *tport = sess->tport; | 205 | struct ft_tport *tport = sess->tport; |
196 | struct hlist_head *head = &tport->hash[ft_sess_hash(sess->port_id)]; | 206 | struct hlist_head *head = &tport->hash[ft_sess_hash(sess->port_id)]; |
197 | 207 | ||
198 | pr_debug("port_id %x sess %p\n", sess->port_id, sess); | 208 | TFC_SESS_DBG(tport->lport, "port_id %x sess %p\n", sess->port_id, sess); |
199 | hlist_add_head_rcu(&sess->hash, head); | 209 | hlist_add_head_rcu(&sess->hash, head); |
200 | tport->sess_count++; | 210 | tport->sess_count++; |
201 | 211 | ||
@@ -223,7 +233,7 @@ static struct ft_sess *ft_sess_create(struct ft_tport *tport, u32 port_id, | |||
223 | 233 | ||
224 | sess = kzalloc(sizeof(*sess), GFP_KERNEL); | 234 | sess = kzalloc(sizeof(*sess), GFP_KERNEL); |
225 | if (!sess) | 235 | if (!sess) |
226 | return NULL; | 236 | return ERR_PTR(-ENOMEM); |
227 | 237 | ||
228 | kref_init(&sess->kref); /* ref for table entry */ | 238 | kref_init(&sess->kref); /* ref for table entry */ |
229 | sess->tport = tport; | 239 | sess->tport = tport; |
@@ -234,8 +244,9 @@ static struct ft_sess *ft_sess_create(struct ft_tport *tport, u32 port_id, | |||
234 | TARGET_PROT_NORMAL, &initiatorname[0], | 244 | TARGET_PROT_NORMAL, &initiatorname[0], |
235 | sess, ft_sess_alloc_cb); | 245 | sess, ft_sess_alloc_cb); |
236 | if (IS_ERR(sess->se_sess)) { | 246 | if (IS_ERR(sess->se_sess)) { |
247 | int rc = PTR_ERR(sess->se_sess); | ||
237 | kfree(sess); | 248 | kfree(sess); |
238 | return NULL; | 249 | sess = ERR_PTR(rc); |
239 | } | 250 | } |
240 | return sess; | 251 | return sess; |
241 | } | 252 | } |
@@ -319,7 +330,7 @@ void ft_sess_close(struct se_session *se_sess) | |||
319 | mutex_unlock(&ft_lport_lock); | 330 | mutex_unlock(&ft_lport_lock); |
320 | return; | 331 | return; |
321 | } | 332 | } |
322 | pr_debug("port_id %x\n", port_id); | 333 | TFC_SESS_DBG(sess->tport->lport, "port_id %x close session\n", port_id); |
323 | ft_sess_unhash(sess); | 334 | ft_sess_unhash(sess); |
324 | mutex_unlock(&ft_lport_lock); | 335 | mutex_unlock(&ft_lport_lock); |
325 | ft_close_sess(sess); | 336 | ft_close_sess(sess); |
@@ -379,8 +390,13 @@ static int ft_prli_locked(struct fc_rport_priv *rdata, u32 spp_len, | |||
379 | if (!(fcp_parm & FCP_SPPF_INIT_FCN)) | 390 | if (!(fcp_parm & FCP_SPPF_INIT_FCN)) |
380 | return FC_SPP_RESP_CONF; | 391 | return FC_SPP_RESP_CONF; |
381 | sess = ft_sess_create(tport, rdata->ids.port_id, rdata); | 392 | sess = ft_sess_create(tport, rdata->ids.port_id, rdata); |
382 | if (!sess) | 393 | if (IS_ERR(sess)) { |
383 | return FC_SPP_RESP_RES; | 394 | if (PTR_ERR(sess) == -EACCES) { |
395 | spp->spp_flags &= ~FC_SPP_EST_IMG_PAIR; | ||
396 | return FC_SPP_RESP_CONF; | ||
397 | } else | ||
398 | return FC_SPP_RESP_RES; | ||
399 | } | ||
384 | if (!sess->params) | 400 | if (!sess->params) |
385 | rdata->prli_count++; | 401 | rdata->prli_count++; |
386 | sess->params = fcp_parm; | 402 | sess->params = fcp_parm; |
@@ -423,8 +439,8 @@ static int ft_prli(struct fc_rport_priv *rdata, u32 spp_len, | |||
423 | mutex_lock(&ft_lport_lock); | 439 | mutex_lock(&ft_lport_lock); |
424 | ret = ft_prli_locked(rdata, spp_len, rspp, spp); | 440 | ret = ft_prli_locked(rdata, spp_len, rspp, spp); |
425 | mutex_unlock(&ft_lport_lock); | 441 | mutex_unlock(&ft_lport_lock); |
426 | pr_debug("port_id %x flags %x ret %x\n", | 442 | TFC_SESS_DBG(rdata->local_port, "port_id %x flags %x ret %x\n", |
427 | rdata->ids.port_id, rspp ? rspp->spp_flags : 0, ret); | 443 | rdata->ids.port_id, rspp ? rspp->spp_flags : 0, ret); |
428 | return ret; | 444 | return ret; |
429 | } | 445 | } |
430 | 446 | ||
@@ -477,11 +493,11 @@ static void ft_recv(struct fc_lport *lport, struct fc_frame *fp) | |||
477 | struct ft_sess *sess; | 493 | struct ft_sess *sess; |
478 | u32 sid = fc_frame_sid(fp); | 494 | u32 sid = fc_frame_sid(fp); |
479 | 495 | ||
480 | pr_debug("sid %x\n", sid); | 496 | TFC_SESS_DBG(lport, "recv sid %x\n", sid); |
481 | 497 | ||
482 | sess = ft_sess_get(lport, sid); | 498 | sess = ft_sess_get(lport, sid); |
483 | if (!sess) { | 499 | if (!sess) { |
484 | pr_debug("sid %x sess lookup failed\n", sid); | 500 | TFC_SESS_DBG(lport, "sid %x sess lookup failed\n", sid); |
485 | /* TBD XXX - if FCP_CMND, send PRLO */ | 501 | /* TBD XXX - if FCP_CMND, send PRLO */ |
486 | fc_frame_free(fp); | 502 | fc_frame_free(fp); |
487 | return; | 503 | return; |
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index fb8e3b6febdf..c2119008990a 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h | |||
@@ -177,6 +177,7 @@ enum tcm_sense_reason_table { | |||
177 | TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED = R(0x15), | 177 | TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED = R(0x15), |
178 | TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED = R(0x16), | 178 | TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED = R(0x16), |
179 | TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED = R(0x17), | 179 | TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED = R(0x17), |
180 | TCM_COPY_TARGET_DEVICE_NOT_REACHABLE = R(0x18), | ||
180 | #undef R | 181 | #undef R |
181 | }; | 182 | }; |
182 | 183 | ||