diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-09-16 16:00:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-09-16 16:00:36 -0400 |
commit | 76e77daf6529381296f14628959aac127c817b26 (patch) | |
tree | 6a92187dfcdae55de642414b8008d9381a0295eb /drivers | |
parent | 9bc67590a65a18201444c2d3d7dae3e897e700c2 (diff) | |
parent | 6abbdf38363f064c8a50150c9b709682764483b3 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending
Pull scsi target fixes from Nicholas Bellinger:
"Here is the current set of target-pending fixes headed for v3.6-final
The main parts of this series include bug-fixes from Paolo Bonzini to
address an use-after-free bug in pSCSI sense exception handling, along
with addressing some long-standing bugs wrt the handling of zero-
length SCSI CDB payloads also specific to pSCSI pass-through device
backends."
* git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending:
target: go through normal processing for zero-length REQUEST_SENSE
target: support zero allocation length in REQUEST SENSE
target: support zero-size allocation lengths in transport_kmap_data_sg
target: fail REPORT LUNS with less than 16 bytes of payload
target: report too-small parameter lists everywhere
target: go through normal processing for zero-length PSCSI commands
target: fix use-after-free with PSCSI sense data
target: simplify code around transport_get_sense_data
target: move transport_get_sense_data
target: Check idr_get_new return value in iscsi_login_zero_tsih_s1
target: Fix ->data_length re-assignment bug with SCSI overflow
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/target/iscsi/iscsi_target_login.c | 11 | ||||
-rw-r--r-- | drivers/target/target_core_alua.c | 7 | ||||
-rw-r--r-- | drivers/target/target_core_device.c | 7 | ||||
-rw-r--r-- | drivers/target/target_core_iblock.c | 17 | ||||
-rw-r--r-- | drivers/target/target_core_pr.c | 8 | ||||
-rw-r--r-- | drivers/target/target_core_pscsi.c | 29 | ||||
-rw-r--r-- | drivers/target/target_core_spc.c | 35 | ||||
-rw-r--r-- | drivers/target/target_core_transport.c | 148 |
8 files changed, 137 insertions, 125 deletions
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index 0694d9b1bce6..6aba4395e8d8 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c | |||
@@ -221,6 +221,7 @@ static int iscsi_login_zero_tsih_s1( | |||
221 | { | 221 | { |
222 | struct iscsi_session *sess = NULL; | 222 | struct iscsi_session *sess = NULL; |
223 | struct iscsi_login_req *pdu = (struct iscsi_login_req *)buf; | 223 | struct iscsi_login_req *pdu = (struct iscsi_login_req *)buf; |
224 | int ret; | ||
224 | 225 | ||
225 | sess = kzalloc(sizeof(struct iscsi_session), GFP_KERNEL); | 226 | sess = kzalloc(sizeof(struct iscsi_session), GFP_KERNEL); |
226 | if (!sess) { | 227 | if (!sess) { |
@@ -257,9 +258,17 @@ static int iscsi_login_zero_tsih_s1( | |||
257 | return -ENOMEM; | 258 | return -ENOMEM; |
258 | } | 259 | } |
259 | spin_lock(&sess_idr_lock); | 260 | spin_lock(&sess_idr_lock); |
260 | idr_get_new(&sess_idr, NULL, &sess->session_index); | 261 | ret = idr_get_new(&sess_idr, NULL, &sess->session_index); |
261 | spin_unlock(&sess_idr_lock); | 262 | spin_unlock(&sess_idr_lock); |
262 | 263 | ||
264 | if (ret < 0) { | ||
265 | pr_err("idr_get_new() for sess_idr failed\n"); | ||
266 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, | ||
267 | ISCSI_LOGIN_STATUS_NO_RESOURCES); | ||
268 | kfree(sess); | ||
269 | return -ENOMEM; | ||
270 | } | ||
271 | |||
263 | sess->creation_time = get_jiffies_64(); | 272 | sess->creation_time = get_jiffies_64(); |
264 | spin_lock_init(&sess->session_stats_lock); | 273 | spin_lock_init(&sess->session_stats_lock); |
265 | /* | 274 | /* |
diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 91799973081a..41641ba54828 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c | |||
@@ -218,6 +218,13 @@ int target_emulate_set_target_port_groups(struct se_cmd *cmd) | |||
218 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | 218 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
219 | return -EINVAL; | 219 | return -EINVAL; |
220 | } | 220 | } |
221 | if (cmd->data_length < 4) { | ||
222 | pr_warn("SET TARGET PORT GROUPS parameter list length %u too" | ||
223 | " small\n", cmd->data_length); | ||
224 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; | ||
225 | return -EINVAL; | ||
226 | } | ||
227 | |||
221 | buf = transport_kmap_data_sg(cmd); | 228 | buf = transport_kmap_data_sg(cmd); |
222 | 229 | ||
223 | /* | 230 | /* |
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index cf2c66f3c116..9fc9a6006ca0 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c | |||
@@ -669,6 +669,13 @@ int target_report_luns(struct se_cmd *se_cmd) | |||
669 | unsigned char *buf; | 669 | unsigned char *buf; |
670 | u32 lun_count = 0, offset = 8, i; | 670 | u32 lun_count = 0, offset = 8, i; |
671 | 671 | ||
672 | if (se_cmd->data_length < 16) { | ||
673 | pr_warn("REPORT LUNS allocation length %u too small\n", | ||
674 | se_cmd->data_length); | ||
675 | se_cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; | ||
676 | return -EINVAL; | ||
677 | } | ||
678 | |||
672 | buf = transport_kmap_data_sg(se_cmd); | 679 | buf = transport_kmap_data_sg(se_cmd); |
673 | if (!buf) | 680 | if (!buf) |
674 | return -ENOMEM; | 681 | return -ENOMEM; |
diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 76db75e836ed..9ba495477fd2 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c | |||
@@ -325,17 +325,30 @@ static int iblock_execute_unmap(struct se_cmd *cmd) | |||
325 | struct iblock_dev *ibd = dev->dev_ptr; | 325 | struct iblock_dev *ibd = dev->dev_ptr; |
326 | unsigned char *buf, *ptr = NULL; | 326 | unsigned char *buf, *ptr = NULL; |
327 | sector_t lba; | 327 | sector_t lba; |
328 | int size = cmd->data_length; | 328 | int size; |
329 | u32 range; | 329 | u32 range; |
330 | int ret = 0; | 330 | int ret = 0; |
331 | int dl, bd_dl; | 331 | int dl, bd_dl; |
332 | 332 | ||
333 | if (cmd->data_length < 8) { | ||
334 | pr_warn("UNMAP parameter list length %u too small\n", | ||
335 | cmd->data_length); | ||
336 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; | ||
337 | return -EINVAL; | ||
338 | } | ||
339 | |||
333 | buf = transport_kmap_data_sg(cmd); | 340 | buf = transport_kmap_data_sg(cmd); |
334 | 341 | ||
335 | dl = get_unaligned_be16(&buf[0]); | 342 | dl = get_unaligned_be16(&buf[0]); |
336 | bd_dl = get_unaligned_be16(&buf[2]); | 343 | bd_dl = get_unaligned_be16(&buf[2]); |
337 | 344 | ||
338 | size = min(size - 8, bd_dl); | 345 | size = cmd->data_length - 8; |
346 | if (bd_dl > size) | ||
347 | pr_warn("UNMAP parameter list length %u too small, ignoring bd_dl %u\n", | ||
348 | cmd->data_length, bd_dl); | ||
349 | else | ||
350 | size = bd_dl; | ||
351 | |||
339 | if (size / 16 > dev->se_sub_dev->se_dev_attrib.max_unmap_block_desc_count) { | 352 | if (size / 16 > dev->se_sub_dev->se_dev_attrib.max_unmap_block_desc_count) { |
340 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; | 353 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; |
341 | ret = -EINVAL; | 354 | ret = -EINVAL; |
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 1e946502c378..956c84c6b666 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c | |||
@@ -1540,6 +1540,14 @@ static int core_scsi3_decode_spec_i_port( | |||
1540 | tidh_new->dest_local_nexus = 1; | 1540 | tidh_new->dest_local_nexus = 1; |
1541 | list_add_tail(&tidh_new->dest_list, &tid_dest_list); | 1541 | list_add_tail(&tidh_new->dest_list, &tid_dest_list); |
1542 | 1542 | ||
1543 | if (cmd->data_length < 28) { | ||
1544 | pr_warn("SPC-PR: Received PR OUT parameter list" | ||
1545 | " length too small: %u\n", cmd->data_length); | ||
1546 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; | ||
1547 | ret = -EINVAL; | ||
1548 | goto out; | ||
1549 | } | ||
1550 | |||
1543 | buf = transport_kmap_data_sg(cmd); | 1551 | buf = transport_kmap_data_sg(cmd); |
1544 | /* | 1552 | /* |
1545 | * For a PERSISTENT RESERVE OUT specify initiator ports payload, | 1553 | * For a PERSISTENT RESERVE OUT specify initiator ports payload, |
diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 5552fa7426bc..9d7ce3daa262 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c | |||
@@ -667,7 +667,8 @@ static void pscsi_free_device(void *p) | |||
667 | kfree(pdv); | 667 | kfree(pdv); |
668 | } | 668 | } |
669 | 669 | ||
670 | static int pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg) | 670 | static void pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg, |
671 | unsigned char *sense_buffer) | ||
671 | { | 672 | { |
672 | struct pscsi_dev_virt *pdv = cmd->se_dev->dev_ptr; | 673 | struct pscsi_dev_virt *pdv = cmd->se_dev->dev_ptr; |
673 | struct scsi_device *sd = pdv->pdv_sd; | 674 | struct scsi_device *sd = pdv->pdv_sd; |
@@ -679,7 +680,7 @@ static int pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg) | |||
679 | * not been allocated because TCM is handling the emulation directly. | 680 | * not been allocated because TCM is handling the emulation directly. |
680 | */ | 681 | */ |
681 | if (!pt) | 682 | if (!pt) |
682 | return 0; | 683 | return; |
683 | 684 | ||
684 | cdb = &pt->pscsi_cdb[0]; | 685 | cdb = &pt->pscsi_cdb[0]; |
685 | result = pt->pscsi_result; | 686 | result = pt->pscsi_result; |
@@ -687,11 +688,11 @@ static int pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg) | |||
687 | * Hack to make sure that Write-Protect modepage is set if R/O mode is | 688 | * Hack to make sure that Write-Protect modepage is set if R/O mode is |
688 | * forced. | 689 | * forced. |
689 | */ | 690 | */ |
691 | if (!cmd->se_deve || !cmd->data_length) | ||
692 | goto after_mode_sense; | ||
693 | |||
690 | if (((cdb[0] == MODE_SENSE) || (cdb[0] == MODE_SENSE_10)) && | 694 | if (((cdb[0] == MODE_SENSE) || (cdb[0] == MODE_SENSE_10)) && |
691 | (status_byte(result) << 1) == SAM_STAT_GOOD) { | 695 | (status_byte(result) << 1) == SAM_STAT_GOOD) { |
692 | if (!cmd->se_deve) | ||
693 | goto after_mode_sense; | ||
694 | |||
695 | if (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY) { | 696 | if (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY) { |
696 | unsigned char *buf = transport_kmap_data_sg(cmd); | 697 | unsigned char *buf = transport_kmap_data_sg(cmd); |
697 | 698 | ||
@@ -708,7 +709,7 @@ static int pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg) | |||
708 | } | 709 | } |
709 | after_mode_sense: | 710 | after_mode_sense: |
710 | 711 | ||
711 | if (sd->type != TYPE_TAPE) | 712 | if (sd->type != TYPE_TAPE || !cmd->data_length) |
712 | goto after_mode_select; | 713 | goto after_mode_select; |
713 | 714 | ||
714 | /* | 715 | /* |
@@ -750,10 +751,10 @@ after_mode_sense: | |||
750 | } | 751 | } |
751 | after_mode_select: | 752 | after_mode_select: |
752 | 753 | ||
753 | if (status_byte(result) & CHECK_CONDITION) | 754 | if (sense_buffer && (status_byte(result) & CHECK_CONDITION)) { |
754 | return 1; | 755 | memcpy(sense_buffer, pt->pscsi_sense, TRANSPORT_SENSE_BUFFER); |
755 | 756 | cmd->se_cmd_flags |= SCF_TRANSPORT_TASK_SENSE; | |
756 | return 0; | 757 | } |
757 | } | 758 | } |
758 | 759 | ||
759 | enum { | 760 | enum { |
@@ -1184,13 +1185,6 @@ fail: | |||
1184 | return -ENOMEM; | 1185 | return -ENOMEM; |
1185 | } | 1186 | } |
1186 | 1187 | ||
1187 | static unsigned char *pscsi_get_sense_buffer(struct se_cmd *cmd) | ||
1188 | { | ||
1189 | struct pscsi_plugin_task *pt = cmd->priv; | ||
1190 | |||
1191 | return pt->pscsi_sense; | ||
1192 | } | ||
1193 | |||
1194 | /* pscsi_get_device_rev(): | 1188 | /* pscsi_get_device_rev(): |
1195 | * | 1189 | * |
1196 | * | 1190 | * |
@@ -1273,7 +1267,6 @@ static struct se_subsystem_api pscsi_template = { | |||
1273 | .check_configfs_dev_params = pscsi_check_configfs_dev_params, | 1267 | .check_configfs_dev_params = pscsi_check_configfs_dev_params, |
1274 | .set_configfs_dev_params = pscsi_set_configfs_dev_params, | 1268 | .set_configfs_dev_params = pscsi_set_configfs_dev_params, |
1275 | .show_configfs_dev_params = pscsi_show_configfs_dev_params, | 1269 | .show_configfs_dev_params = pscsi_show_configfs_dev_params, |
1276 | .get_sense_buffer = pscsi_get_sense_buffer, | ||
1277 | .get_device_rev = pscsi_get_device_rev, | 1270 | .get_device_rev = pscsi_get_device_rev, |
1278 | .get_device_type = pscsi_get_device_type, | 1271 | .get_device_type = pscsi_get_device_type, |
1279 | .get_blocks = pscsi_get_blocks, | 1272 | .get_blocks = pscsi_get_blocks, |
diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index 4c861de538c9..388a922c8f6d 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c | |||
@@ -877,9 +877,11 @@ static int spc_emulate_modesense(struct se_cmd *cmd) | |||
877 | static int spc_emulate_request_sense(struct se_cmd *cmd) | 877 | static int spc_emulate_request_sense(struct se_cmd *cmd) |
878 | { | 878 | { |
879 | unsigned char *cdb = cmd->t_task_cdb; | 879 | unsigned char *cdb = cmd->t_task_cdb; |
880 | unsigned char *buf; | 880 | unsigned char *rbuf; |
881 | u8 ua_asc = 0, ua_ascq = 0; | 881 | u8 ua_asc = 0, ua_ascq = 0; |
882 | int err = 0; | 882 | unsigned char buf[SE_SENSE_BUF]; |
883 | |||
884 | memset(buf, 0, SE_SENSE_BUF); | ||
883 | 885 | ||
884 | if (cdb[1] & 0x01) { | 886 | if (cdb[1] & 0x01) { |
885 | pr_err("REQUEST_SENSE description emulation not" | 887 | pr_err("REQUEST_SENSE description emulation not" |
@@ -888,20 +890,21 @@ static int spc_emulate_request_sense(struct se_cmd *cmd) | |||
888 | return -ENOSYS; | 890 | return -ENOSYS; |
889 | } | 891 | } |
890 | 892 | ||
891 | buf = transport_kmap_data_sg(cmd); | 893 | rbuf = transport_kmap_data_sg(cmd); |
892 | 894 | if (cmd->scsi_sense_reason != 0) { | |
893 | if (!core_scsi3_ua_clear_for_request_sense(cmd, &ua_asc, &ua_ascq)) { | 895 | /* |
896 | * Out of memory. We will fail with CHECK CONDITION, so | ||
897 | * we must not clear the unit attention condition. | ||
898 | */ | ||
899 | target_complete_cmd(cmd, CHECK_CONDITION); | ||
900 | return 0; | ||
901 | } else if (!core_scsi3_ua_clear_for_request_sense(cmd, &ua_asc, &ua_ascq)) { | ||
894 | /* | 902 | /* |
895 | * CURRENT ERROR, UNIT ATTENTION | 903 | * CURRENT ERROR, UNIT ATTENTION |
896 | */ | 904 | */ |
897 | buf[0] = 0x70; | 905 | buf[0] = 0x70; |
898 | buf[SPC_SENSE_KEY_OFFSET] = UNIT_ATTENTION; | 906 | buf[SPC_SENSE_KEY_OFFSET] = UNIT_ATTENTION; |
899 | 907 | ||
900 | if (cmd->data_length < 18) { | ||
901 | buf[7] = 0x00; | ||
902 | err = -EINVAL; | ||
903 | goto end; | ||
904 | } | ||
905 | /* | 908 | /* |
906 | * The Additional Sense Code (ASC) from the UNIT ATTENTION | 909 | * The Additional Sense Code (ASC) from the UNIT ATTENTION |
907 | */ | 910 | */ |
@@ -915,11 +918,6 @@ static int spc_emulate_request_sense(struct se_cmd *cmd) | |||
915 | buf[0] = 0x70; | 918 | buf[0] = 0x70; |
916 | buf[SPC_SENSE_KEY_OFFSET] = NO_SENSE; | 919 | buf[SPC_SENSE_KEY_OFFSET] = NO_SENSE; |
917 | 920 | ||
918 | if (cmd->data_length < 18) { | ||
919 | buf[7] = 0x00; | ||
920 | err = -EINVAL; | ||
921 | goto end; | ||
922 | } | ||
923 | /* | 921 | /* |
924 | * NO ADDITIONAL SENSE INFORMATION | 922 | * NO ADDITIONAL SENSE INFORMATION |
925 | */ | 923 | */ |
@@ -927,8 +925,11 @@ static int spc_emulate_request_sense(struct se_cmd *cmd) | |||
927 | buf[7] = 0x0A; | 925 | buf[7] = 0x0A; |
928 | } | 926 | } |
929 | 927 | ||
930 | end: | 928 | if (rbuf) { |
931 | transport_kunmap_data_sg(cmd); | 929 | memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length)); |
930 | transport_kunmap_data_sg(cmd); | ||
931 | } | ||
932 | |||
932 | target_complete_cmd(cmd, GOOD); | 933 | target_complete_cmd(cmd, GOOD); |
933 | return 0; | 934 | return 0; |
934 | } | 935 | } |
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 4de3186dc44e..269f54488397 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c | |||
@@ -567,6 +567,34 @@ static void target_complete_failure_work(struct work_struct *work) | |||
567 | transport_generic_request_failure(cmd); | 567 | transport_generic_request_failure(cmd); |
568 | } | 568 | } |
569 | 569 | ||
570 | /* | ||
571 | * Used when asking transport to copy Sense Data from the underlying | ||
572 | * Linux/SCSI struct scsi_cmnd | ||
573 | */ | ||
574 | static unsigned char *transport_get_sense_buffer(struct se_cmd *cmd) | ||
575 | { | ||
576 | unsigned char *buffer = cmd->sense_buffer; | ||
577 | struct se_device *dev = cmd->se_dev; | ||
578 | u32 offset = 0; | ||
579 | |||
580 | WARN_ON(!cmd->se_lun); | ||
581 | |||
582 | if (!dev) | ||
583 | return NULL; | ||
584 | |||
585 | if (cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) | ||
586 | return NULL; | ||
587 | |||
588 | offset = cmd->se_tfo->set_fabric_sense_len(cmd, TRANSPORT_SENSE_BUFFER); | ||
589 | |||
590 | /* Automatically padded */ | ||
591 | cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER + offset; | ||
592 | |||
593 | pr_debug("HBA_[%u]_PLUG[%s]: Requesting sense for SAM STATUS: 0x%02x\n", | ||
594 | dev->se_hba->hba_id, dev->transport->name, cmd->scsi_status); | ||
595 | return &buffer[offset]; | ||
596 | } | ||
597 | |||
570 | void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status) | 598 | void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status) |
571 | { | 599 | { |
572 | struct se_device *dev = cmd->se_dev; | 600 | struct se_device *dev = cmd->se_dev; |
@@ -580,11 +608,11 @@ void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status) | |||
580 | cmd->transport_state &= ~CMD_T_BUSY; | 608 | cmd->transport_state &= ~CMD_T_BUSY; |
581 | 609 | ||
582 | if (dev && dev->transport->transport_complete) { | 610 | if (dev && dev->transport->transport_complete) { |
583 | if (dev->transport->transport_complete(cmd, | 611 | dev->transport->transport_complete(cmd, |
584 | cmd->t_data_sg) != 0) { | 612 | cmd->t_data_sg, |
585 | cmd->se_cmd_flags |= SCF_TRANSPORT_TASK_SENSE; | 613 | transport_get_sense_buffer(cmd)); |
614 | if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) | ||
586 | success = 1; | 615 | success = 1; |
587 | } | ||
588 | } | 616 | } |
589 | 617 | ||
590 | /* | 618 | /* |
@@ -1181,15 +1209,20 @@ int target_cmd_size_check(struct se_cmd *cmd, unsigned int size) | |||
1181 | /* Returns CHECK_CONDITION + INVALID_CDB_FIELD */ | 1209 | /* Returns CHECK_CONDITION + INVALID_CDB_FIELD */ |
1182 | goto out_invalid_cdb_field; | 1210 | goto out_invalid_cdb_field; |
1183 | } | 1211 | } |
1184 | 1212 | /* | |
1213 | * For the overflow case keep the existing fabric provided | ||
1214 | * ->data_length. Otherwise for the underflow case, reset | ||
1215 | * ->data_length to the smaller SCSI expected data transfer | ||
1216 | * length. | ||
1217 | */ | ||
1185 | if (size > cmd->data_length) { | 1218 | if (size > cmd->data_length) { |
1186 | cmd->se_cmd_flags |= SCF_OVERFLOW_BIT; | 1219 | cmd->se_cmd_flags |= SCF_OVERFLOW_BIT; |
1187 | cmd->residual_count = (size - cmd->data_length); | 1220 | cmd->residual_count = (size - cmd->data_length); |
1188 | } else { | 1221 | } else { |
1189 | cmd->se_cmd_flags |= SCF_UNDERFLOW_BIT; | 1222 | cmd->se_cmd_flags |= SCF_UNDERFLOW_BIT; |
1190 | cmd->residual_count = (cmd->data_length - size); | 1223 | cmd->residual_count = (cmd->data_length - size); |
1224 | cmd->data_length = size; | ||
1191 | } | 1225 | } |
1192 | cmd->data_length = size; | ||
1193 | } | 1226 | } |
1194 | 1227 | ||
1195 | return 0; | 1228 | return 0; |
@@ -1816,61 +1849,6 @@ execute: | |||
1816 | EXPORT_SYMBOL(target_execute_cmd); | 1849 | EXPORT_SYMBOL(target_execute_cmd); |
1817 | 1850 | ||
1818 | /* | 1851 | /* |
1819 | * Used to obtain Sense Data from underlying Linux/SCSI struct scsi_cmnd | ||
1820 | */ | ||
1821 | static int transport_get_sense_data(struct se_cmd *cmd) | ||
1822 | { | ||
1823 | unsigned char *buffer = cmd->sense_buffer, *sense_buffer = NULL; | ||
1824 | struct se_device *dev = cmd->se_dev; | ||
1825 | unsigned long flags; | ||
1826 | u32 offset = 0; | ||
1827 | |||
1828 | WARN_ON(!cmd->se_lun); | ||
1829 | |||
1830 | if (!dev) | ||
1831 | return 0; | ||
1832 | |||
1833 | spin_lock_irqsave(&cmd->t_state_lock, flags); | ||
1834 | if (cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) { | ||
1835 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); | ||
1836 | return 0; | ||
1837 | } | ||
1838 | |||
1839 | if (!(cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE)) | ||
1840 | goto out; | ||
1841 | |||
1842 | if (!dev->transport->get_sense_buffer) { | ||
1843 | pr_err("dev->transport->get_sense_buffer is NULL\n"); | ||
1844 | goto out; | ||
1845 | } | ||
1846 | |||
1847 | sense_buffer = dev->transport->get_sense_buffer(cmd); | ||
1848 | if (!sense_buffer) { | ||
1849 | pr_err("ITT 0x%08x cmd %p: Unable to locate" | ||
1850 | " sense buffer for task with sense\n", | ||
1851 | cmd->se_tfo->get_task_tag(cmd), cmd); | ||
1852 | goto out; | ||
1853 | } | ||
1854 | |||
1855 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); | ||
1856 | |||
1857 | offset = cmd->se_tfo->set_fabric_sense_len(cmd, TRANSPORT_SENSE_BUFFER); | ||
1858 | |||
1859 | memcpy(&buffer[offset], sense_buffer, TRANSPORT_SENSE_BUFFER); | ||
1860 | |||
1861 | /* Automatically padded */ | ||
1862 | cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER + offset; | ||
1863 | |||
1864 | pr_debug("HBA_[%u]_PLUG[%s]: Set SAM STATUS: 0x%02x and sense\n", | ||
1865 | dev->se_hba->hba_id, dev->transport->name, cmd->scsi_status); | ||
1866 | return 0; | ||
1867 | |||
1868 | out: | ||
1869 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); | ||
1870 | return -1; | ||
1871 | } | ||
1872 | |||
1873 | /* | ||
1874 | * Process all commands up to the last received ORDERED task attribute which | 1852 | * Process all commands up to the last received ORDERED task attribute which |
1875 | * requires another blocking boundary | 1853 | * requires another blocking boundary |
1876 | */ | 1854 | */ |
@@ -1985,7 +1963,7 @@ static void transport_handle_queue_full( | |||
1985 | static void target_complete_ok_work(struct work_struct *work) | 1963 | static void target_complete_ok_work(struct work_struct *work) |
1986 | { | 1964 | { |
1987 | struct se_cmd *cmd = container_of(work, struct se_cmd, work); | 1965 | struct se_cmd *cmd = container_of(work, struct se_cmd, work); |
1988 | int reason = 0, ret; | 1966 | int ret; |
1989 | 1967 | ||
1990 | /* | 1968 | /* |
1991 | * Check if we need to move delayed/dormant tasks from cmds on the | 1969 | * Check if we need to move delayed/dormant tasks from cmds on the |
@@ -2002,23 +1980,19 @@ static void target_complete_ok_work(struct work_struct *work) | |||
2002 | schedule_work(&cmd->se_dev->qf_work_queue); | 1980 | schedule_work(&cmd->se_dev->qf_work_queue); |
2003 | 1981 | ||
2004 | /* | 1982 | /* |
2005 | * Check if we need to retrieve a sense buffer from | 1983 | * Check if we need to send a sense buffer from |
2006 | * the struct se_cmd in question. | 1984 | * the struct se_cmd in question. |
2007 | */ | 1985 | */ |
2008 | if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) { | 1986 | if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) { |
2009 | if (transport_get_sense_data(cmd) < 0) | 1987 | WARN_ON(!cmd->scsi_status); |
2010 | reason = TCM_NON_EXISTENT_LUN; | 1988 | ret = transport_send_check_condition_and_sense( |
2011 | 1989 | cmd, 0, 1); | |
2012 | if (cmd->scsi_status) { | 1990 | if (ret == -EAGAIN || ret == -ENOMEM) |
2013 | ret = transport_send_check_condition_and_sense( | 1991 | goto queue_full; |
2014 | cmd, reason, 1); | ||
2015 | if (ret == -EAGAIN || ret == -ENOMEM) | ||
2016 | goto queue_full; | ||
2017 | 1992 | ||
2018 | transport_lun_remove_cmd(cmd); | 1993 | transport_lun_remove_cmd(cmd); |
2019 | transport_cmd_check_stop_to_fabric(cmd); | 1994 | transport_cmd_check_stop_to_fabric(cmd); |
2020 | return; | 1995 | return; |
2021 | } | ||
2022 | } | 1996 | } |
2023 | /* | 1997 | /* |
2024 | * Check for a callback, used by amongst other things | 1998 | * Check for a callback, used by amongst other things |
@@ -2216,7 +2190,6 @@ void *transport_kmap_data_sg(struct se_cmd *cmd) | |||
2216 | struct page **pages; | 2190 | struct page **pages; |
2217 | int i; | 2191 | int i; |
2218 | 2192 | ||
2219 | BUG_ON(!sg); | ||
2220 | /* | 2193 | /* |
2221 | * We need to take into account a possible offset here for fabrics like | 2194 | * We need to take into account a possible offset here for fabrics like |
2222 | * tcm_loop who may be using a contig buffer from the SCSI midlayer for | 2195 | * tcm_loop who may be using a contig buffer from the SCSI midlayer for |
@@ -2224,13 +2197,17 @@ void *transport_kmap_data_sg(struct se_cmd *cmd) | |||
2224 | */ | 2197 | */ |
2225 | if (!cmd->t_data_nents) | 2198 | if (!cmd->t_data_nents) |
2226 | return NULL; | 2199 | return NULL; |
2227 | else if (cmd->t_data_nents == 1) | 2200 | |
2201 | BUG_ON(!sg); | ||
2202 | if (cmd->t_data_nents == 1) | ||
2228 | return kmap(sg_page(sg)) + sg->offset; | 2203 | return kmap(sg_page(sg)) + sg->offset; |
2229 | 2204 | ||
2230 | /* >1 page. use vmap */ | 2205 | /* >1 page. use vmap */ |
2231 | pages = kmalloc(sizeof(*pages) * cmd->t_data_nents, GFP_KERNEL); | 2206 | pages = kmalloc(sizeof(*pages) * cmd->t_data_nents, GFP_KERNEL); |
2232 | if (!pages) | 2207 | if (!pages) { |
2208 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | ||
2233 | return NULL; | 2209 | return NULL; |
2210 | } | ||
2234 | 2211 | ||
2235 | /* convert sg[] to pages[] */ | 2212 | /* convert sg[] to pages[] */ |
2236 | for_each_sg(cmd->t_data_sg, sg, cmd->t_data_nents, i) { | 2213 | for_each_sg(cmd->t_data_sg, sg, cmd->t_data_nents, i) { |
@@ -2239,8 +2216,10 @@ void *transport_kmap_data_sg(struct se_cmd *cmd) | |||
2239 | 2216 | ||
2240 | cmd->t_data_vmap = vmap(pages, cmd->t_data_nents, VM_MAP, PAGE_KERNEL); | 2217 | cmd->t_data_vmap = vmap(pages, cmd->t_data_nents, VM_MAP, PAGE_KERNEL); |
2241 | kfree(pages); | 2218 | kfree(pages); |
2242 | if (!cmd->t_data_vmap) | 2219 | if (!cmd->t_data_vmap) { |
2220 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | ||
2243 | return NULL; | 2221 | return NULL; |
2222 | } | ||
2244 | 2223 | ||
2245 | return cmd->t_data_vmap + cmd->t_data_sg[0].offset; | 2224 | return cmd->t_data_vmap + cmd->t_data_sg[0].offset; |
2246 | } | 2225 | } |
@@ -2326,19 +2305,14 @@ int transport_generic_new_cmd(struct se_cmd *cmd) | |||
2326 | * into the fabric for data transfers, go ahead and complete it right | 2305 | * into the fabric for data transfers, go ahead and complete it right |
2327 | * away. | 2306 | * away. |
2328 | */ | 2307 | */ |
2329 | if (!cmd->data_length) { | 2308 | if (!cmd->data_length && |
2309 | cmd->t_task_cdb[0] != REQUEST_SENSE && | ||
2310 | cmd->se_dev->transport->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV) { | ||
2330 | spin_lock_irq(&cmd->t_state_lock); | 2311 | spin_lock_irq(&cmd->t_state_lock); |
2331 | cmd->t_state = TRANSPORT_COMPLETE; | 2312 | cmd->t_state = TRANSPORT_COMPLETE; |
2332 | cmd->transport_state |= CMD_T_ACTIVE; | 2313 | cmd->transport_state |= CMD_T_ACTIVE; |
2333 | spin_unlock_irq(&cmd->t_state_lock); | 2314 | spin_unlock_irq(&cmd->t_state_lock); |
2334 | 2315 | ||
2335 | if (cmd->t_task_cdb[0] == REQUEST_SENSE) { | ||
2336 | u8 ua_asc = 0, ua_ascq = 0; | ||
2337 | |||
2338 | core_scsi3_ua_clear_for_request_sense(cmd, | ||
2339 | &ua_asc, &ua_ascq); | ||
2340 | } | ||
2341 | |||
2342 | INIT_WORK(&cmd->work, target_complete_ok_work); | 2316 | INIT_WORK(&cmd->work, target_complete_ok_work); |
2343 | queue_work(target_completion_wq, &cmd->work); | 2317 | queue_work(target_completion_wq, &cmd->work); |
2344 | return 0; | 2318 | return 0; |