diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-13 17:27:32 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-13 17:27:32 -0400 |
commit | 48ea2cedde3507941f4549b0d27ed46ed29e39ff (patch) | |
tree | 07dfc2fe520445598e5429df88b32bd470f0f055 /drivers/target/target_core_xcopy.c | |
parent | 62403005975c678ba7594a36670ae3bf0273d7c4 (diff) | |
parent | 138d351eefb727ab9e41a3dc5f112ceb4f6e59f2 (diff) |
Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending
Pull SCSI target updates from Nicholas Bellinger:
"It's been usually busy for summer, with most of the efforts centered
around TCMU developments and various target-core + fabric driver bug
fixing activities. Not particularly large in terms of LoC, but lots of
smaller patches from many different folks.
The highlights include:
- ibmvscsis logical partition manager support (Michael Cyr + Bryant
Ly)
- Convert target/iblock WRITE_SAME to blkdev_issue_zeroout (hch +
nab)
- Add support for TMR percpu LUN reference counting (nab)
- Fix a potential deadlock between EXTENDED_COPY and iscsi shutdown
(Bart)
- Fix COMPARE_AND_WRITE caw_sem leak during se_cmd quiesce (Jiang Yi)
- Fix TMCU module removal (Xiubo Li)
- Fix iser-target OOPs during login failure (Andrea Righi + Sagi)
- Breakup target-core free_device backend driver callback (mnc)
- Perform TCMU add/delete/reconfig synchronously (mnc)
- Fix TCMU multiple UIO open/close sequences (mnc)
- Fix TCMU CHECK_CONDITION sense handling (mnc)
- Fix target-core SAM_STAT_BUSY + TASK_SET_FULL handling (mnc + nab)
- Introduce TYPE_ZBC support in PSCSI (Damien Le Moal)
- Fix possible TCMU memory leak + OOPs when recalculating cmd base
size (Xiubo Li + Bryant Ly + Damien Le Moal + mnc)
- Add login_keys_workaround attribute for non RFC initiators (Robert
LeBlanc + Arun Easi + nab)"
* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending: (68 commits)
iscsi-target: Add login_keys_workaround attribute for non RFC initiators
Revert "qla2xxx: Fix incorrect tcm_qla2xxx_free_cmd use during TMR ABORT"
tcmu: clean up the code and with one small fix
tcmu: Fix possbile memory leak / OOPs when recalculating cmd base size
target: export lio pgr/alua support as device attr
target: Fix return sense reason in target_scsi3_emulate_pr_out
target: Fix cmd size for PR-OUT in passthrough_parse_cdb
tcmu: Fix dev_config_store
target: pscsi: Introduce TYPE_ZBC support
target: Use macro for WRITE_VERIFY_32 operation codes
target: fix SAM_STAT_BUSY/TASK_SET_FULL handling
target: remove transport_complete
pscsi: finish cmd processing from pscsi_req_done
tcmu: fix sense handling during completion
target: add helper to copy sense to se_cmd buffer
target: do not require a transport_complete for SCF_TRANSPORT_TASK_SENSE
target: make device_mutex and device_list static
tcmu: Fix flushing cmd entry dcache page
tcmu: fix multiple uio open/close sequences
tcmu: drop configured check in destroy
...
Diffstat (limited to 'drivers/target/target_core_xcopy.c')
-rw-r--r-- | drivers/target/target_core_xcopy.c | 184 |
1 files changed, 111 insertions, 73 deletions
diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c index cac5a20a4de0..9ee89e00cd77 100644 --- a/drivers/target/target_core_xcopy.c +++ b/drivers/target/target_core_xcopy.c | |||
@@ -40,6 +40,8 @@ | |||
40 | 40 | ||
41 | static struct workqueue_struct *xcopy_wq = NULL; | 41 | static struct workqueue_struct *xcopy_wq = NULL; |
42 | 42 | ||
43 | static sense_reason_t target_parse_xcopy_cmd(struct xcopy_op *xop); | ||
44 | |||
43 | static int target_xcopy_gen_naa_ieee(struct se_device *dev, unsigned char *buf) | 45 | static int target_xcopy_gen_naa_ieee(struct se_device *dev, unsigned char *buf) |
44 | { | 46 | { |
45 | int off = 0; | 47 | int off = 0; |
@@ -53,48 +55,60 @@ static int target_xcopy_gen_naa_ieee(struct se_device *dev, unsigned char *buf) | |||
53 | return 0; | 55 | return 0; |
54 | } | 56 | } |
55 | 57 | ||
56 | static int target_xcopy_locate_se_dev_e4(const unsigned char *dev_wwn, | 58 | struct xcopy_dev_search_info { |
57 | struct se_device **found_dev) | 59 | const unsigned char *dev_wwn; |
60 | struct se_device *found_dev; | ||
61 | }; | ||
62 | |||
63 | static int target_xcopy_locate_se_dev_e4_iter(struct se_device *se_dev, | ||
64 | void *data) | ||
58 | { | 65 | { |
59 | struct se_device *se_dev; | 66 | struct xcopy_dev_search_info *info = data; |
60 | unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN]; | 67 | unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN]; |
61 | int rc; | 68 | int rc; |
62 | 69 | ||
63 | mutex_lock(&g_device_mutex); | 70 | if (!se_dev->dev_attrib.emulate_3pc) |
64 | list_for_each_entry(se_dev, &g_device_list, g_dev_node) { | 71 | return 0; |
65 | 72 | ||
66 | if (!se_dev->dev_attrib.emulate_3pc) | 73 | memset(&tmp_dev_wwn[0], 0, XCOPY_NAA_IEEE_REGEX_LEN); |
67 | continue; | 74 | target_xcopy_gen_naa_ieee(se_dev, &tmp_dev_wwn[0]); |
68 | 75 | ||
69 | memset(&tmp_dev_wwn[0], 0, XCOPY_NAA_IEEE_REGEX_LEN); | 76 | rc = memcmp(&tmp_dev_wwn[0], info->dev_wwn, XCOPY_NAA_IEEE_REGEX_LEN); |
70 | target_xcopy_gen_naa_ieee(se_dev, &tmp_dev_wwn[0]); | 77 | if (rc != 0) |
78 | return 0; | ||
71 | 79 | ||
72 | rc = memcmp(&tmp_dev_wwn[0], dev_wwn, XCOPY_NAA_IEEE_REGEX_LEN); | 80 | info->found_dev = se_dev; |
73 | if (rc != 0) | 81 | pr_debug("XCOPY 0xe4: located se_dev: %p\n", se_dev); |
74 | continue; | ||
75 | 82 | ||
76 | *found_dev = se_dev; | 83 | rc = target_depend_item(&se_dev->dev_group.cg_item); |
77 | pr_debug("XCOPY 0xe4: located se_dev: %p\n", se_dev); | 84 | if (rc != 0) { |
85 | pr_err("configfs_depend_item attempt failed: %d for se_dev: %p\n", | ||
86 | rc, se_dev); | ||
87 | return rc; | ||
88 | } | ||
78 | 89 | ||
79 | rc = target_depend_item(&se_dev->dev_group.cg_item); | 90 | pr_debug("Called configfs_depend_item for se_dev: %p se_dev->se_dev_group: %p\n", |
80 | if (rc != 0) { | 91 | se_dev, &se_dev->dev_group); |
81 | pr_err("configfs_depend_item attempt failed:" | 92 | return 1; |
82 | " %d for se_dev: %p\n", rc, se_dev); | 93 | } |
83 | mutex_unlock(&g_device_mutex); | ||
84 | return rc; | ||
85 | } | ||
86 | 94 | ||
87 | pr_debug("Called configfs_depend_item for se_dev: %p" | 95 | static int target_xcopy_locate_se_dev_e4(const unsigned char *dev_wwn, |
88 | " se_dev->se_dev_group: %p\n", se_dev, | 96 | struct se_device **found_dev) |
89 | &se_dev->dev_group); | 97 | { |
98 | struct xcopy_dev_search_info info; | ||
99 | int ret; | ||
100 | |||
101 | memset(&info, 0, sizeof(info)); | ||
102 | info.dev_wwn = dev_wwn; | ||
90 | 103 | ||
91 | mutex_unlock(&g_device_mutex); | 104 | ret = target_for_each_device(target_xcopy_locate_se_dev_e4_iter, &info); |
105 | if (ret == 1) { | ||
106 | *found_dev = info.found_dev; | ||
92 | return 0; | 107 | return 0; |
108 | } else { | ||
109 | pr_debug_ratelimited("Unable to locate 0xe4 descriptor for EXTENDED_COPY\n"); | ||
110 | return -EINVAL; | ||
93 | } | 111 | } |
94 | mutex_unlock(&g_device_mutex); | ||
95 | |||
96 | pr_debug_ratelimited("Unable to locate 0xe4 descriptor for EXTENDED_COPY\n"); | ||
97 | return -EINVAL; | ||
98 | } | 112 | } |
99 | 113 | ||
100 | static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op *xop, | 114 | static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op *xop, |
@@ -311,9 +325,7 @@ static int target_xcopy_parse_segdesc_02(struct se_cmd *se_cmd, struct xcopy_op | |||
311 | (unsigned long long)xop->dst_lba); | 325 | (unsigned long long)xop->dst_lba); |
312 | 326 | ||
313 | if (dc != 0) { | 327 | if (dc != 0) { |
314 | xop->dbl = (desc[29] & 0xff) << 16; | 328 | xop->dbl = get_unaligned_be24(&desc[29]); |
315 | xop->dbl |= (desc[30] & 0xff) << 8; | ||
316 | xop->dbl |= desc[31] & 0xff; | ||
317 | 329 | ||
318 | pr_debug("XCOPY seg desc 0x02: DC=1 w/ dbl: %u\n", xop->dbl); | 330 | pr_debug("XCOPY seg desc 0x02: DC=1 w/ dbl: %u\n", xop->dbl); |
319 | } | 331 | } |
@@ -781,13 +793,24 @@ static int target_xcopy_write_destination( | |||
781 | static void target_xcopy_do_work(struct work_struct *work) | 793 | static void target_xcopy_do_work(struct work_struct *work) |
782 | { | 794 | { |
783 | struct xcopy_op *xop = container_of(work, struct xcopy_op, xop_work); | 795 | struct xcopy_op *xop = container_of(work, struct xcopy_op, xop_work); |
784 | struct se_device *src_dev = xop->src_dev, *dst_dev = xop->dst_dev; | ||
785 | struct se_cmd *ec_cmd = xop->xop_se_cmd; | 796 | struct se_cmd *ec_cmd = xop->xop_se_cmd; |
786 | sector_t src_lba = xop->src_lba, dst_lba = xop->dst_lba, end_lba; | 797 | struct se_device *src_dev, *dst_dev; |
798 | sector_t src_lba, dst_lba, end_lba; | ||
787 | unsigned int max_sectors; | 799 | unsigned int max_sectors; |
788 | int rc; | 800 | int rc = 0; |
789 | unsigned short nolb = xop->nolb, cur_nolb, max_nolb, copied_nolb = 0; | 801 | unsigned short nolb, cur_nolb, max_nolb, copied_nolb = 0; |
802 | |||
803 | if (target_parse_xcopy_cmd(xop) != TCM_NO_SENSE) | ||
804 | goto err_free; | ||
790 | 805 | ||
806 | if (WARN_ON_ONCE(!xop->src_dev) || WARN_ON_ONCE(!xop->dst_dev)) | ||
807 | goto err_free; | ||
808 | |||
809 | src_dev = xop->src_dev; | ||
810 | dst_dev = xop->dst_dev; | ||
811 | src_lba = xop->src_lba; | ||
812 | dst_lba = xop->dst_lba; | ||
813 | nolb = xop->nolb; | ||
791 | end_lba = src_lba + nolb; | 814 | end_lba = src_lba + nolb; |
792 | /* | 815 | /* |
793 | * Break up XCOPY I/O into hw_max_sectors sized I/O based on the | 816 | * Break up XCOPY I/O into hw_max_sectors sized I/O based on the |
@@ -855,6 +878,8 @@ static void target_xcopy_do_work(struct work_struct *work) | |||
855 | 878 | ||
856 | out: | 879 | out: |
857 | xcopy_pt_undepend_remotedev(xop); | 880 | xcopy_pt_undepend_remotedev(xop); |
881 | |||
882 | err_free: | ||
858 | kfree(xop); | 883 | kfree(xop); |
859 | /* | 884 | /* |
860 | * Don't override an error scsi status if it has already been set | 885 | * Don't override an error scsi status if it has already been set |
@@ -867,48 +892,22 @@ out: | |||
867 | target_complete_cmd(ec_cmd, ec_cmd->scsi_status); | 892 | target_complete_cmd(ec_cmd, ec_cmd->scsi_status); |
868 | } | 893 | } |
869 | 894 | ||
870 | sense_reason_t target_do_xcopy(struct se_cmd *se_cmd) | 895 | /* |
896 | * Returns TCM_NO_SENSE upon success or a sense code != TCM_NO_SENSE if parsing | ||
897 | * fails. | ||
898 | */ | ||
899 | static sense_reason_t target_parse_xcopy_cmd(struct xcopy_op *xop) | ||
871 | { | 900 | { |
872 | struct se_device *dev = se_cmd->se_dev; | 901 | struct se_cmd *se_cmd = xop->xop_se_cmd; |
873 | struct xcopy_op *xop = NULL; | ||
874 | unsigned char *p = NULL, *seg_desc; | 902 | unsigned char *p = NULL, *seg_desc; |
875 | unsigned int list_id, list_id_usage, sdll, inline_dl, sa; | 903 | unsigned int list_id, list_id_usage, sdll, inline_dl; |
876 | sense_reason_t ret = TCM_INVALID_PARAMETER_LIST; | 904 | sense_reason_t ret = TCM_INVALID_PARAMETER_LIST; |
877 | int rc; | 905 | int rc; |
878 | unsigned short tdll; | 906 | unsigned short tdll; |
879 | 907 | ||
880 | if (!dev->dev_attrib.emulate_3pc) { | ||
881 | pr_err("EXTENDED_COPY operation explicitly disabled\n"); | ||
882 | return TCM_UNSUPPORTED_SCSI_OPCODE; | ||
883 | } | ||
884 | |||
885 | sa = se_cmd->t_task_cdb[1] & 0x1f; | ||
886 | if (sa != 0x00) { | ||
887 | pr_err("EXTENDED_COPY(LID4) not supported\n"); | ||
888 | return TCM_UNSUPPORTED_SCSI_OPCODE; | ||
889 | } | ||
890 | |||
891 | if (se_cmd->data_length == 0) { | ||
892 | target_complete_cmd(se_cmd, SAM_STAT_GOOD); | ||
893 | return TCM_NO_SENSE; | ||
894 | } | ||
895 | if (se_cmd->data_length < XCOPY_HDR_LEN) { | ||
896 | pr_err("XCOPY parameter truncation: length %u < hdr_len %u\n", | ||
897 | se_cmd->data_length, XCOPY_HDR_LEN); | ||
898 | return TCM_PARAMETER_LIST_LENGTH_ERROR; | ||
899 | } | ||
900 | |||
901 | xop = kzalloc(sizeof(struct xcopy_op), GFP_KERNEL); | ||
902 | if (!xop) { | ||
903 | pr_err("Unable to allocate xcopy_op\n"); | ||
904 | return TCM_OUT_OF_RESOURCES; | ||
905 | } | ||
906 | xop->xop_se_cmd = se_cmd; | ||
907 | |||
908 | p = transport_kmap_data_sg(se_cmd); | 908 | p = transport_kmap_data_sg(se_cmd); |
909 | if (!p) { | 909 | if (!p) { |
910 | pr_err("transport_kmap_data_sg() failed in target_do_xcopy\n"); | 910 | pr_err("transport_kmap_data_sg() failed in target_do_xcopy\n"); |
911 | kfree(xop); | ||
912 | return TCM_OUT_OF_RESOURCES; | 911 | return TCM_OUT_OF_RESOURCES; |
913 | } | 912 | } |
914 | 913 | ||
@@ -977,18 +976,57 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd) | |||
977 | pr_debug("XCOPY: Processed %d target descriptors, length: %u\n", rc, | 976 | pr_debug("XCOPY: Processed %d target descriptors, length: %u\n", rc, |
978 | rc * XCOPY_TARGET_DESC_LEN); | 977 | rc * XCOPY_TARGET_DESC_LEN); |
979 | transport_kunmap_data_sg(se_cmd); | 978 | transport_kunmap_data_sg(se_cmd); |
980 | |||
981 | INIT_WORK(&xop->xop_work, target_xcopy_do_work); | ||
982 | queue_work(xcopy_wq, &xop->xop_work); | ||
983 | return TCM_NO_SENSE; | 979 | return TCM_NO_SENSE; |
984 | 980 | ||
985 | out: | 981 | out: |
986 | if (p) | 982 | if (p) |
987 | transport_kunmap_data_sg(se_cmd); | 983 | transport_kunmap_data_sg(se_cmd); |
988 | kfree(xop); | ||
989 | return ret; | 984 | return ret; |
990 | } | 985 | } |
991 | 986 | ||
987 | sense_reason_t target_do_xcopy(struct se_cmd *se_cmd) | ||
988 | { | ||
989 | struct se_device *dev = se_cmd->se_dev; | ||
990 | struct xcopy_op *xop; | ||
991 | unsigned int sa; | ||
992 | |||
993 | if (!dev->dev_attrib.emulate_3pc) { | ||
994 | pr_err("EXTENDED_COPY operation explicitly disabled\n"); | ||
995 | return TCM_UNSUPPORTED_SCSI_OPCODE; | ||
996 | } | ||
997 | |||
998 | sa = se_cmd->t_task_cdb[1] & 0x1f; | ||
999 | if (sa != 0x00) { | ||
1000 | pr_err("EXTENDED_COPY(LID4) not supported\n"); | ||
1001 | return TCM_UNSUPPORTED_SCSI_OPCODE; | ||
1002 | } | ||
1003 | |||
1004 | if (se_cmd->data_length == 0) { | ||
1005 | target_complete_cmd(se_cmd, SAM_STAT_GOOD); | ||
1006 | return TCM_NO_SENSE; | ||
1007 | } | ||
1008 | if (se_cmd->data_length < XCOPY_HDR_LEN) { | ||
1009 | pr_err("XCOPY parameter truncation: length %u < hdr_len %u\n", | ||
1010 | se_cmd->data_length, XCOPY_HDR_LEN); | ||
1011 | return TCM_PARAMETER_LIST_LENGTH_ERROR; | ||
1012 | } | ||
1013 | |||
1014 | xop = kzalloc(sizeof(struct xcopy_op), GFP_KERNEL); | ||
1015 | if (!xop) | ||
1016 | goto err; | ||
1017 | xop->xop_se_cmd = se_cmd; | ||
1018 | INIT_WORK(&xop->xop_work, target_xcopy_do_work); | ||
1019 | if (WARN_ON_ONCE(!queue_work(xcopy_wq, &xop->xop_work))) | ||
1020 | goto free; | ||
1021 | return TCM_NO_SENSE; | ||
1022 | |||
1023 | free: | ||
1024 | kfree(xop); | ||
1025 | |||
1026 | err: | ||
1027 | return TCM_OUT_OF_RESOURCES; | ||
1028 | } | ||
1029 | |||
992 | static sense_reason_t target_rcr_operating_parameters(struct se_cmd *se_cmd) | 1030 | static sense_reason_t target_rcr_operating_parameters(struct se_cmd *se_cmd) |
993 | { | 1031 | { |
994 | unsigned char *p; | 1032 | unsigned char *p; |