diff options
author | Christoph Hellwig <hch@infradead.org> | 2012-05-20 11:59:14 -0400 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2012-07-16 17:25:56 -0700 |
commit | d6e0175cf3f9737a760482d185bb73566bcc9331 (patch) | |
tree | 99ca8361ebc8c4e83f8335193963faa3f30007b5 /drivers/target/target_core_transport.c | |
parent | 88455ec4be02c395820b1ff57656b0844ec03ac3 (diff) | |
download | blackbird-op-linux-d6e0175cf3f9737a760482d185bb73566bcc9331.tar.gz blackbird-op-linux-d6e0175cf3f9737a760482d185bb73566bcc9331.zip |
target: add a parse_cdb method to the backend drivers
Instead of trying to handle all SCSI command sets in one function
(transport_generic_cmd_sequencer) call out to the backend driver to perform
this functionality. For pSCSI a copy of the existing code is used, but for
all virtual backends we can use a new parse_sbc_cdb helper is used to
provide a simple SBC emulation.
For now this setups means a fair amount of duplication between pSCSI and the
SBC library, but patches later in this series will sort out that problem.
(nab: Fix up build failure in target_core_pscsi.c)
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers/target/target_core_transport.c')
-rw-r--r-- | drivers/target/target_core_transport.c | 736 |
1 files changed, 7 insertions, 729 deletions
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index a8a3d1544e65..0adabd37cbb1 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1343,8 +1343,6 @@ static inline void transport_generic_prepare_cdb( } } -static int transport_generic_cmd_sequencer(struct se_cmd *, unsigned char *); - static int target_cmd_size_check(struct se_cmd *cmd, unsigned int size) { struct se_device *dev = cmd->se_dev; @@ -1471,6 +1469,7 @@ int target_setup_cmd_from_cdb( u32 pr_reg_type = 0; u8 alua_ascq = 0; unsigned long flags; + unsigned int size; int ret; transport_generic_prepare_cdb(cdb); @@ -1562,13 +1561,11 @@ int target_setup_cmd_from_cdb( */ } - /* - * Setup the received CDB based on SCSI defined opcodes and - * perform unit attention, persistent reservations and ALUA - * checks for virtual device backends. The cmd->t_task_cdb - * pointer is expected to be setup before we reach this point. - */ - ret = transport_generic_cmd_sequencer(cmd, cdb); + ret = cmd->se_dev->transport->parse_cdb(cmd, &size); + if (ret < 0) + return ret; + + ret = target_cmd_size_check(cmd, size); if (ret < 0) return ret; @@ -1694,10 +1691,7 @@ void target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, target_put_sess_cmd(se_sess, se_cmd); return; } - /* - * Sanitize CDBs via transport_generic_cmd_sequencer() and - * allocate the necessary tasks to complete the received CDB+data - */ + rc = target_setup_cmd_from_cdb(se_cmd, cdb); if (rc != 0) { transport_generic_request_failure(se_cmd); @@ -1966,39 +1960,6 @@ queue_full: } EXPORT_SYMBOL(transport_generic_request_failure); -static inline u32 transport_lba_21(unsigned char *cdb) -{ - return ((cdb[1] & 0x1f) << 16) | (cdb[2] << 8) | cdb[3]; -} - -static inline u32 transport_lba_32(unsigned char *cdb) -{ - return (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; -} - -static inline unsigned long long transport_lba_64(unsigned char *cdb) -{ - unsigned int __v1, __v2; - - __v1 = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - __v2 = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; - - return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32; -} - -/* - * For VARIABLE_LENGTH_CDB w/ 32 byte extended CDBs - */ -static inline unsigned long long transport_lba_64_ext(unsigned char *cdb) -{ - unsigned int __v1, __v2; - - __v1 = (cdb[12] << 24) | (cdb[13] << 16) | (cdb[14] << 8) | cdb[15]; - __v2 = (cdb[16] << 24) | (cdb[17] << 16) | (cdb[18] << 8) | cdb[19]; - - return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32; -} - /* * Called from Fabric Module context from transport_execute_tasks() * @@ -2147,217 +2108,6 @@ check_depth: return 0; } -static inline u32 transport_get_sectors_6( - unsigned char *cdb, - struct se_cmd *cmd, - int *ret) -{ - struct se_device *dev = cmd->se_dev; - - /* - * Assume TYPE_DISK for non struct se_device objects. - * Use 8-bit sector value. - */ - if (!dev) - goto type_disk; - - /* - * Use 24-bit allocation length for TYPE_TAPE. - */ - if (dev->transport->get_device_type(dev) == TYPE_TAPE) - return (u32)(cdb[2] << 16) + (cdb[3] << 8) + cdb[4]; - - /* - * Everything else assume TYPE_DISK Sector CDB location. - * Use 8-bit sector value. SBC-3 says: - * - * A TRANSFER LENGTH field set to zero specifies that 256 - * logical blocks shall be written. Any other value - * specifies the number of logical blocks that shall be - * written. - */ -type_disk: - return cdb[4] ? : 256; -} - -static inline u32 transport_get_sectors_10( - unsigned char *cdb, - struct se_cmd *cmd, - int *ret) -{ - struct se_device *dev = cmd->se_dev; - - /* - * Assume TYPE_DISK for non struct se_device objects. - * Use 16-bit sector value. - */ - if (!dev) - goto type_disk; - - /* - * XXX_10 is not defined in SSC, throw an exception - */ - if (dev->transport->get_device_type(dev) == TYPE_TAPE) { - *ret = -EINVAL; - return 0; - } - - /* - * Everything else assume TYPE_DISK Sector CDB location. - * Use 16-bit sector value. - */ -type_disk: - return (u32)(cdb[7] << 8) + cdb[8]; -} - -static inline u32 transport_get_sectors_12( - unsigned char *cdb, - struct se_cmd *cmd, - int *ret) -{ - struct se_device *dev = cmd->se_dev; - - /* - * Assume TYPE_DISK for non struct se_device objects. - * Use 32-bit sector value. - */ - if (!dev) - goto type_disk; - - /* - * XXX_12 is not defined in SSC, throw an exception - */ - if (dev->transport->get_device_type(dev) == TYPE_TAPE) { - *ret = -EINVAL; - return 0; - } - - /* - * Everything else assume TYPE_DISK Sector CDB location. - * Use 32-bit sector value. - */ -type_disk: - return (u32)(cdb[6] << 24) + (cdb[7] << 16) + (cdb[8] << 8) + cdb[9]; -} - -static inline u32 transport_get_sectors_16( - unsigned char *cdb, - struct se_cmd *cmd, - int *ret) -{ - struct se_device *dev = cmd->se_dev; - - /* - * Assume TYPE_DISK for non struct se_device objects. - * Use 32-bit sector value. - */ - if (!dev) - goto type_disk; - - /* - * Use 24-bit allocation length for TYPE_TAPE. - */ - if (dev->transport->get_device_type(dev) == TYPE_TAPE) - return (u32)(cdb[12] << 16) + (cdb[13] << 8) + cdb[14]; - -type_disk: - return (u32)(cdb[10] << 24) + (cdb[11] << 16) + - (cdb[12] << 8) + cdb[13]; -} - -/* - * Used for VARIABLE_LENGTH_CDB WRITE_32 and READ_32 variants - */ -static inline u32 transport_get_sectors_32( - unsigned char *cdb, - struct se_cmd *cmd, - int *ret) -{ - /* - * Assume TYPE_DISK for non struct se_device objects. - * Use 32-bit sector value. - */ - return (u32)(cdb[28] << 24) + (cdb[29] << 16) + - (cdb[30] << 8) + cdb[31]; - -} - -static inline u32 transport_get_size( - u32 sectors, - unsigned char *cdb, - struct se_cmd *cmd) -{ - struct se_device *dev = cmd->se_dev; - - if (dev->transport->get_device_type(dev) == TYPE_TAPE) { - if (cdb[1] & 1) { /* sectors */ - return dev->se_sub_dev->se_dev_attrib.block_size * sectors; - } else /* bytes */ - return sectors; - } - - pr_debug("Returning block_size: %u, sectors: %u == %u for" - " %s object\n", dev->se_sub_dev->se_dev_attrib.block_size, - sectors, dev->se_sub_dev->se_dev_attrib.block_size * sectors, - dev->transport->name); - - return dev->se_sub_dev->se_dev_attrib.block_size * sectors; -} - -static void transport_xor_callback(struct se_cmd *cmd) -{ - unsigned char *buf, *addr; - struct scatterlist *sg; - unsigned int offset; - int i; - int count; - /* - * From sbc3r22.pdf section 5.48 XDWRITEREAD (10) command - * - * 1) read the specified logical block(s); - * 2) transfer logical blocks from the data-out buffer; - * 3) XOR the logical blocks transferred from the data-out buffer with - * the logical blocks read, storing the resulting XOR data in a buffer; - * 4) if the DISABLE WRITE bit is set to zero, then write the logical - * blocks transferred from the data-out buffer; and - * 5) transfer the resulting XOR data to the data-in buffer. - */ - buf = kmalloc(cmd->data_length, GFP_KERNEL); - if (!buf) { - pr_err("Unable to allocate xor_callback buf\n"); - return; - } - /* - * Copy the scatterlist WRITE buffer located at cmd->t_data_sg - * into the locally allocated *buf - */ - sg_copy_to_buffer(cmd->t_data_sg, - cmd->t_data_nents, - buf, - cmd->data_length); - - /* - * Now perform the XOR against the BIDI read memory located at - * cmd->t_mem_bidi_list - */ - - offset = 0; - for_each_sg(cmd->t_bidi_data_sg, sg, cmd->t_bidi_data_nents, count) { - addr = kmap_atomic(sg_page(sg)); - if (!addr) - goto out; - - for (i = 0; i < sg->length; i++) - *(addr + sg->offset + i) ^= *(buf + offset + i); - - offset += sg->length; - kunmap_atomic(addr); - } - -out: - kfree(buf); -} - /* * Used to obtain Sense Data from underlying Linux/SCSI struct scsi_cmnd */ @@ -2439,478 +2189,6 @@ static int transport_cmd_get_valid_sectors(struct se_cmd *cmd) return 0; } -static int target_check_write_same_discard(unsigned char *flags, struct se_device *dev) -{ - /* - * Determine if the received WRITE_SAME is used to for direct - * passthrough into Linux/SCSI with struct request via TCM/pSCSI - * or we are signaling the use of internal WRITE_SAME + UNMAP=1 - * emulation for -> Linux/BLOCK disbard with TCM/IBLOCK code. - */ - int passthrough = (dev->transport->transport_type == - TRANSPORT_PLUGIN_PHBA_PDEV); - - if (!passthrough) { - if ((flags[0] & 0x04) || (flags[0] & 0x02)) { - pr_err("WRITE_SAME PBDATA and LBDATA" - " bits not supported for Block Discard" - " Emulation\n"); - return -ENOSYS; - } - /* - * Currently for the emulated case we only accept - * tpws with the UNMAP=1 bit set. - */ - if (!(flags[0] & 0x08)) { - pr_err("WRITE_SAME w/o UNMAP bit not" - " supported for Block Discard Emulation\n"); - return -ENOSYS; - } - } - - return 0; -} - -static int transport_generic_cmd_sequencer( - struct se_cmd *cmd, - unsigned char *cdb) -{ - struct se_device *dev = cmd->se_dev; - struct se_subsystem_dev *su_dev = dev->se_sub_dev; - int sector_ret = 0, passthrough; - u32 sectors = 0, size = 0; - u16 service_action; - int ret; - - /* - * If we operate in passthrough mode we skip most CDB emulation and - * instead hand the commands down to the physical SCSI device. - */ - passthrough = - (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV); - - switch (cdb[0]) { - case READ_6: - sectors = transport_get_sectors_6(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - size = transport_get_size(sectors, cdb, cmd); - cmd->t_task_lba = transport_lba_21(cdb); - cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - break; - case READ_10: - sectors = transport_get_sectors_10(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - size = transport_get_size(sectors, cdb, cmd); - cmd->t_task_lba = transport_lba_32(cdb); - cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - break; - case READ_12: - sectors = transport_get_sectors_12(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - size = transport_get_size(sectors, cdb, cmd); - cmd->t_task_lba = transport_lba_32(cdb); - cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - break; - case READ_16: - sectors = transport_get_sectors_16(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - size = transport_get_size(sectors, cdb, cmd); - cmd->t_task_lba = transport_lba_64(cdb); - cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - break; - case WRITE_6: - sectors = transport_get_sectors_6(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - size = transport_get_size(sectors, cdb, cmd); - cmd->t_task_lba = transport_lba_21(cdb); - cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - break; - case WRITE_10: - case WRITE_VERIFY: - sectors = transport_get_sectors_10(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - size = transport_get_size(sectors, cdb, cmd); - cmd->t_task_lba = transport_lba_32(cdb); - if (cdb[1] & 0x8) - cmd->se_cmd_flags |= SCF_FUA; - cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - break; - case WRITE_12: - sectors = transport_get_sectors_12(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - size = transport_get_size(sectors, cdb, cmd); - cmd->t_task_lba = transport_lba_32(cdb); - if (cdb[1] & 0x8) - cmd->se_cmd_flags |= SCF_FUA; - cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - break; - case WRITE_16: - sectors = transport_get_sectors_16(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - size = transport_get_size(sectors, cdb, cmd); - cmd->t_task_lba = transport_lba_64(cdb); - if (cdb[1] & 0x8) - cmd->se_cmd_flags |= SCF_FUA; - cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - break; - case XDWRITEREAD_10: - if ((cmd->data_direction != DMA_TO_DEVICE) || - !(cmd->se_cmd_flags & SCF_BIDI)) - goto out_invalid_cdb_field; - sectors = transport_get_sectors_10(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - size = transport_get_size(sectors, cdb, cmd); - cmd->t_task_lba = transport_lba_32(cdb); - cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - - /* - * Do now allow BIDI commands for passthrough mode. - */ - if (passthrough) - goto out_unsupported_cdb; - - /* - * Setup BIDI XOR callback to be run after I/O completion. - */ - cmd->transport_complete_callback = &transport_xor_callback; - if (cdb[1] & 0x8) - cmd->se_cmd_flags |= SCF_FUA; - break; - case VARIABLE_LENGTH_CMD: - service_action = get_unaligned_be16(&cdb[8]); - switch (service_action) { - case XDWRITEREAD_32: - sectors = transport_get_sectors_32(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - size = transport_get_size(sectors, cdb, cmd); - /* - * Use WRITE_32 and READ_32 opcodes for the emulated - * XDWRITE_READ_32 logic. - */ - cmd->t_task_lba = transport_lba_64_ext(cdb); - cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - - /* - * Do now allow BIDI commands for passthrough mode. - */ - if (passthrough) - goto out_unsupported_cdb; - - /* - * Setup BIDI XOR callback to be run during after I/O - * completion. - */ - cmd->transport_complete_callback = &transport_xor_callback; - if (cdb[1] & 0x8) - cmd->se_cmd_flags |= SCF_FUA; - break; - case WRITE_SAME_32: - sectors = transport_get_sectors_32(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - - if (sectors) - size = transport_get_size(1, cdb, cmd); - else { - pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not" - " supported\n"); - goto out_invalid_cdb_field; - } - - cmd->t_task_lba = get_unaligned_be64(&cdb[12]); - - if (target_check_write_same_discard(&cdb[10], dev) < 0) - goto out_unsupported_cdb; - if (!passthrough) - cmd->execute_cmd = target_emulate_write_same; - break; - default: - pr_err("VARIABLE_LENGTH_CMD service action" - " 0x%04x not supported\n", service_action); - goto out_unsupported_cdb; - } - break; - case MAINTENANCE_IN: - if (dev->transport->get_device_type(dev) != TYPE_ROM) { - /* MAINTENANCE_IN from SCC-2 */ - /* - * Check for emulated MI_REPORT_TARGET_PGS. - */ - if ((cdb[1] & 0x1f) == MI_REPORT_TARGET_PGS && - su_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) { - cmd->execute_cmd = - target_emulate_report_target_port_groups; - } - size = (cdb[6] << 24) | (cdb[7] << 16) | - (cdb[8] << 8) | cdb[9]; - } else { - /* GPCMD_SEND_KEY from multi media commands */ - size = (cdb[8] << 8) + cdb[9]; - } - break; - case GPCMD_READ_BUFFER_CAPACITY: - case GPCMD_SEND_OPC: - size = (cdb[7] << 8) + cdb[8]; - break; - case READ_BLOCK_LIMITS: - size = READ_BLOCK_LEN; - break; - case GPCMD_GET_CONFIGURATION: - case GPCMD_READ_FORMAT_CAPACITIES: - case GPCMD_READ_DISC_INFO: - case GPCMD_READ_TRACK_RZONE_INFO: - size = (cdb[7] << 8) + cdb[8]; - break; - case GPCMD_MECHANISM_STATUS: - case GPCMD_READ_DVD_STRUCTURE: - size = (cdb[8] << 8) + cdb[9]; - break; - case READ_POSITION: - size = READ_POSITION_LEN; - break; - case MAINTENANCE_OUT: - if (dev->transport->get_device_type(dev) != TYPE_ROM) { - /* MAINTENANCE_OUT from SCC-2 - * - * Check for emulated MO_SET_TARGET_PGS. - */ - if (cdb[1] == MO_SET_TARGET_PGS && - su_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) { - cmd->execute_cmd = - target_emulate_set_target_port_groups; - } - - size = (cdb[6] << 24) | (cdb[7] << 16) | - (cdb[8] << 8) | cdb[9]; - } else { - /* GPCMD_REPORT_KEY from multi media commands */ - size = (cdb[8] << 8) + cdb[9]; - } - break; - case READ_BUFFER: - size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8]; - break; - case READ_CAPACITY: - size = READ_CAP_LEN; - if (!passthrough) - cmd->execute_cmd = target_emulate_readcapacity; - break; - case READ_MEDIA_SERIAL_NUMBER: - case SERVICE_ACTION_IN: - switch (cmd->t_task_cdb[1] & 0x1f) { - case SAI_READ_CAPACITY_16: - if (!passthrough) - cmd->execute_cmd = - target_emulate_readcapacity_16; - break; - default: - if (passthrough) - break; - - pr_err("Unsupported SA: 0x%02x\n", - cmd->t_task_cdb[1] & 0x1f); - goto out_invalid_cdb_field; - } - /*FALLTHROUGH*/ - case ACCESS_CONTROL_IN: - case ACCESS_CONTROL_OUT: - size = (cdb[10] << 24) | (cdb[11] << 16) | - (cdb[12] << 8) | cdb[13]; - break; -/* #warning FIXME: Figure out correct GPCMD_READ_CD blocksize. */ -#if 0 - case GPCMD_READ_CD: - sectors = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8]; - size = (2336 * sectors); - break; -#endif - case READ_TOC: - size = cdb[8]; - break; - case READ_ELEMENT_STATUS: - size = 65536 * cdb[7] + 256 * cdb[8] + cdb[9]; - break; - case SYNCHRONIZE_CACHE: - case SYNCHRONIZE_CACHE_16: - /* - * Extract LBA and range to be flushed for emulated SYNCHRONIZE_CACHE - */ - if (cdb[0] == SYNCHRONIZE_CACHE) { - sectors = transport_get_sectors_10(cdb, cmd, §or_ret); - cmd->t_task_lba = transport_lba_32(cdb); - } else { - sectors = transport_get_sectors_16(cdb, cmd, §or_ret); - cmd->t_task_lba = transport_lba_64(cdb); - } - if (sector_ret) - goto out_unsupported_cdb; - - size = transport_get_size(sectors, cdb, cmd); - - if (passthrough) - break; - - /* - * Check to ensure that LBA + Range does not exceed past end of - * device for IBLOCK and FILEIO ->do_sync_cache() backend calls - */ - if ((cmd->t_task_lba != 0) || (sectors != 0)) { - if (transport_cmd_get_valid_sectors(cmd) < 0) - goto out_invalid_cdb_field; - } - cmd->execute_cmd = target_emulate_synchronize_cache; - break; - case UNMAP: - size = get_unaligned_be16(&cdb[7]); - if (!passthrough) - cmd->execute_cmd = target_emulate_unmap; - break; - case WRITE_SAME_16: - sectors = transport_get_sectors_16(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - - if (sectors) - size = transport_get_size(1, cdb, cmd); - else { - pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n"); - goto out_invalid_cdb_field; - } - - cmd->t_task_lba = get_unaligned_be64(&cdb[2]); - - if (target_check_write_same_discard(&cdb[1], dev) < 0) - goto out_unsupported_cdb; - if (!passthrough) - cmd->execute_cmd = target_emulate_write_same; - break; - case WRITE_SAME: - sectors = transport_get_sectors_10(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - - if (sectors) - size = transport_get_size(1, cdb, cmd); - else { - pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n"); - goto out_invalid_cdb_field; - } - - cmd->t_task_lba = get_unaligned_be32(&cdb[2]); - /* - * Follow sbcr26 with WRITE_SAME (10) and check for the existence - * of byte 1 bit 3 UNMAP instead of original reserved field - */ - if (target_check_write_same_discard(&cdb[1], dev) < 0) - goto out_unsupported_cdb; - if (!passthrough) - cmd->execute_cmd = target_emulate_write_same; - break; - case ALLOW_MEDIUM_REMOVAL: - case ERASE: - case REZERO_UNIT: - case SEEK_10: - case SPACE: - case START_STOP: - case VERIFY: - case WRITE_FILEMARKS: - if (!passthrough) - cmd->execute_cmd = target_emulate_noop; - break; - case GPCMD_CLOSE_TRACK: - case INITIALIZE_ELEMENT_STATUS: - case GPCMD_LOAD_UNLOAD: - case GPCMD_SET_SPEED: - case MOVE_MEDIUM: - break; - case GET_EVENT_STATUS_NOTIFICATION: - size = (cdb[7] << 8) | cdb[8]; - break; - case ATA_16: - /* Only support ATA passthrough to pSCSI backends.. */ - if (!passthrough) - goto out_unsupported_cdb; - - /* T_LENGTH */ - switch (cdb[2] & 0x3) { - case 0x0: - sectors = 0; - break; - case 0x1: - sectors = (((cdb[1] & 0x1) ? cdb[3] : 0) << 8) | cdb[4]; - break; - case 0x2: - sectors = (((cdb[1] & 0x1) ? cdb[5] : 0) << 8) | cdb[6]; - break; - case 0x3: - pr_err("T_LENGTH=0x3 not supported for ATA_16\n"); - goto out_invalid_cdb_field; - } - - /* BYTE_BLOCK */ - if (cdb[2] & 0x4) { - /* BLOCK T_TYPE: 512 or sector */ - size = sectors * ((cdb[2] & 0x10) ? - dev->se_sub_dev->se_dev_attrib.block_size : 512); - } else { - /* BYTE */ - size = sectors; - } - break; - default: - ret = spc_parse_cdb(cmd, &size, passthrough); - if (ret) - return ret; - } - - ret = target_cmd_size_check(cmd, size); - if (ret) - return ret; - - if (cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) { - if (sectors > su_dev->se_dev_attrib.fabric_max_sectors) { - printk_ratelimited(KERN_ERR "SCSI OP %02xh with too" - " big sectors %u exceeds fabric_max_sectors:" - " %u\n", cdb[0], sectors, - su_dev->se_dev_attrib.fabric_max_sectors); - goto out_invalid_cdb_field; - } - if (sectors > su_dev->se_dev_attrib.hw_max_sectors) { - printk_ratelimited(KERN_ERR "SCSI OP %02xh with too" - " big sectors %u exceeds backend hw_max_sectors:" - " %u\n", cdb[0], sectors, - su_dev->se_dev_attrib.hw_max_sectors); - goto out_invalid_cdb_field; - } - } - - /* reject any command that we don't have a handler for */ - if (!(passthrough || cmd->execute_cmd || - (cmd->se_cmd_flags & SCF_SCSI_DATA_CDB))) - goto out_unsupported_cdb; - - return 0; - -out_unsupported_cdb: - cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; - cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; - return -EINVAL; -out_invalid_cdb_field: - cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; - cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; - return -EINVAL; -} - /* * Called from I/O completion to determine which dormant/delayed * and ordered cmds need to have their tasks added to the execution queue. |