Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

target: Fix error checking for UNMAP commands

SBC-3 (revision 35) says:

The PARAMETER LIST LENGTH field specifies the length in bytes of the
UNMAP parameter list that is available to be transferred from the
Data-Out Buffer. If the parameter list length is greater than zero
and less than 0008h (i.e., eight), then the device server shall
terminate the command with CHECK CONDITION status with the sense key
set to ILLEGAL REQUEST and the additional sense code set to
PARAMETER LIST LENGTH ERROR. A PARAMETER LIST LENGTH set to zero
specifies that no data shall be sent.

so our sense code for too-short descriptors was wrong, and we were
incorrectly failing commands that didn't transfer any descriptors.

While we're at it, also handle the UNMAP check:

If the ANCHOR bit is set to one, and the ANC_SUP bit in the Logical
Block Provisioning VPD page (see 6.6.4) is set to zero, then the
device server shall terminate the command with CHECK CONDITION
status with the sense key set to ILLEGAL REQUEST and the additional
sense code set to INVALID FIELD IN CDB.

(chris boot: Fix wrong cut+paste comment in transport_send_check_condition_and_sense)

Signed-off-by: Roland Dreier <roland@purestorage.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>

authored by

Roland Dreier and committed by
Nicholas Bellinger
bb992e72 33633676

+21 -1
+10 -1
drivers/target/target_core_iblock.c
··· 391 391 sense_reason_t ret = 0; 392 392 int dl, bd_dl, err; 393 393 394 + /* We never set ANC_SUP */ 395 + if (cmd->t_task_cdb[1]) 396 + return TCM_INVALID_CDB_FIELD; 397 + 398 + if (cmd->data_length == 0) { 399 + target_complete_cmd(cmd, SAM_STAT_GOOD); 400 + return 0; 401 + } 402 + 394 403 if (cmd->data_length < 8) { 395 404 pr_warn("UNMAP parameter list length %u too small\n", 396 405 cmd->data_length); 397 - return TCM_INVALID_PARAMETER_LIST; 406 + return TCM_PARAMETER_LIST_LENGTH_ERROR; 398 407 } 399 408 400 409 buf = transport_kmap_data_sg(cmd);
+10
drivers/target/target_core_transport.c
··· 1517 1517 case TCM_UNSUPPORTED_SCSI_OPCODE: 1518 1518 case TCM_INVALID_CDB_FIELD: 1519 1519 case TCM_INVALID_PARAMETER_LIST: 1520 + case TCM_PARAMETER_LIST_LENGTH_ERROR: 1520 1521 case TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE: 1521 1522 case TCM_UNKNOWN_MODE_PAGE: 1522 1523 case TCM_WRITE_PROTECTED: ··· 2677 2676 buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; 2678 2677 /* INVALID FIELD IN PARAMETER LIST */ 2679 2678 buffer[SPC_ASC_KEY_OFFSET] = 0x26; 2679 + break; 2680 + case TCM_PARAMETER_LIST_LENGTH_ERROR: 2681 + /* CURRENT ERROR */ 2682 + buffer[0] = 0x70; 2683 + buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; 2684 + /* ILLEGAL REQUEST */ 2685 + buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; 2686 + /* PARAMETER LIST LENGTH ERROR */ 2687 + buffer[SPC_ASC_KEY_OFFSET] = 0x1a; 2680 2688 break; 2681 2689 case TCM_UNEXPECTED_UNSOLICITED_DATA: 2682 2690 /* CURRENT ERROR */
+1
include/target/target_core_base.h
··· 195 195 TCM_RESERVATION_CONFLICT = R(0x10), 196 196 TCM_ADDRESS_OUT_OF_RANGE = R(0x11), 197 197 TCM_OUT_OF_RESOURCES = R(0x12), 198 + TCM_PARAMETER_LIST_LENGTH_ERROR = R(0x13), 198 199 #undef R 199 200 }; 200 201