提交 1fd032ee 编写于 作者: C Christoph Hellwig 提交者: Nicholas Bellinger

target: move code for CDB emulation

Move the existing code in target_core_cdb.c into the files for the command
sets that the emulations implement.

(roland + nab: Squash patch: Fix range calculation in WRITE SAME emulation
 when num blocks == 0s)
Signed-off-by: NChristoph Hellwig <hch@lst.de>
Signed-off-by: NNicholas Bellinger <nab@linux-iscsi.org>
上级 d6e0175c
......@@ -9,7 +9,6 @@ target_core_mod-y := target_core_configfs.o \
target_core_tmr.o \
target_core_tpg.o \
target_core_transport.o \
target_core_cdb.o \
target_core_sbc.o \
target_core_spc.o \
target_core_ua.o \
......
此差异已折叠。
......@@ -4,17 +4,6 @@
/* target_core_alua.c */
extern struct t10_alua_lu_gp *default_lu_gp;
/* target_core_cdb.c */
int target_emulate_inquiry(struct se_cmd *cmd);
int target_emulate_readcapacity(struct se_cmd *cmd);
int target_emulate_readcapacity_16(struct se_cmd *cmd);
int target_emulate_modesense(struct se_cmd *cmd);
int target_emulate_request_sense(struct se_cmd *cmd);
int target_emulate_unmap(struct se_cmd *cmd);
int target_emulate_write_same(struct se_cmd *cmd);
int target_emulate_synchronize_cache(struct se_cmd *cmd);
int target_emulate_noop(struct se_cmd *cmd);
/* target_core_device.c */
struct se_dev_entry *core_get_se_deve_from_rtpi(struct se_node_acl *, u16);
int core_free_device_list_for_node(struct se_node_acl *,
......@@ -116,6 +105,7 @@ int transport_dump_vpd_ident(struct t10_vpd *, unsigned char *, int);
bool target_stop_cmd(struct se_cmd *cmd, unsigned long *flags);
int transport_clear_lun_from_sessions(struct se_lun *);
void transport_send_task_abort(struct se_cmd *);
int target_cmd_size_check(struct se_cmd *cmd, unsigned int size);
/* target_core_stat.c */
void target_stat_setup_dev_default_groups(struct se_subsystem_dev *);
......
......@@ -1022,470 +1022,53 @@ static int pscsi_map_sg(struct se_cmd *cmd, struct scatterlist *sgl,
return -ENOMEM;
}
static inline u32 pscsi_get_sectors_6(
unsigned char *cdb,
struct se_cmd *cmd,
int *ret)
static int pscsi_parse_cdb(struct se_cmd *cmd)
{
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 pscsi_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 pscsi_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;
unsigned char *cdb = cmd->t_task_cdb;
unsigned int dummy_size;
int ret;
/*
* XXX_12 is not defined in SSC, throw an exception
*/
if (dev->transport->get_device_type(dev) == TYPE_TAPE) {
*ret = -EINVAL;
return 0;
if (cmd->se_cmd_flags & SCF_BIDI) {
cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE;
return -EINVAL;
}
/*
* Everything else assume TYPE_DISK Sector CDB location.
* Use 32-bit sector value.
* For REPORT LUNS we always need to emulate the respone, and for everything
* related to persistent reservations and ALUA we might optionally use our
* handlers before passing on the command to the physical hardware.
*/
type_disk:
return (u32)(cdb[6] << 24) + (cdb[7] << 16) + (cdb[8] << 8) + cdb[9];
}
static inline u32 pscsi_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 pscsi_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 pscsi_get_lba_21(unsigned char *cdb)
{
return ((cdb[1] & 0x1f) << 16) | (cdb[2] << 8) | cdb[3];
}
static inline u32 pscsi_get_lba_32(unsigned char *cdb)
{
return (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5];
}
static inline unsigned long long pscsi_get_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 pscsi_get_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;
}
static inline u32 pscsi_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 int pscsi_parse_cdb(struct se_cmd *cmd, unsigned int *size)
{
struct se_device *dev = cmd->se_dev;
struct se_subsystem_dev *su_dev = dev->se_sub_dev;
unsigned char *cdb = cmd->t_task_cdb;
int sector_ret = 0;
u32 sectors = 0;
u16 service_action;
int ret;
if (cmd->se_cmd_flags & SCF_BIDI)
goto out_unsupported_cdb;
switch (cdb[0]) {
case READ_6:
sectors = pscsi_get_sectors_6(cdb, cmd, &sector_ret);
if (sector_ret)
goto out_unsupported_cdb;
*size = pscsi_get_size(sectors, cdb, cmd);
cmd->t_task_lba = pscsi_get_lba_21(cdb);
cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
case REPORT_LUNS:
case PERSISTENT_RESERVE_IN:
case PERSISTENT_RESERVE_OUT:
case RELEASE:
case RELEASE_10:
case RESERVE:
case RESERVE_10:
ret = spc_parse_cdb(cmd, &dummy_size);
if (ret)
return ret;
break;
case READ_6:
case READ_10:
sectors = pscsi_get_sectors_10(cdb, cmd, &sector_ret);
if (sector_ret)
goto out_unsupported_cdb;
*size = pscsi_get_size(sectors, cdb, cmd);
cmd->t_task_lba = pscsi_get_lba_32(cdb);
cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
break;
case READ_12:
sectors = pscsi_get_sectors_12(cdb, cmd, &sector_ret);
if (sector_ret)
goto out_unsupported_cdb;
*size = pscsi_get_size(sectors, cdb, cmd);
cmd->t_task_lba = pscsi_get_lba_32(cdb);
cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
break;
case READ_16:
sectors = pscsi_get_sectors_16(cdb, cmd, &sector_ret);
if (sector_ret)
goto out_unsupported_cdb;
*size = pscsi_get_size(sectors, cdb, cmd);
cmd->t_task_lba = pscsi_get_lba_64(cdb);
cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
break;
case WRITE_6:
sectors = pscsi_get_sectors_6(cdb, cmd, &sector_ret);
if (sector_ret)
goto out_unsupported_cdb;
*size = pscsi_get_size(sectors, cdb, cmd);
cmd->t_task_lba = pscsi_get_lba_21(cdb);
cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
break;
case WRITE_10:
case WRITE_VERIFY:
sectors = pscsi_get_sectors_10(cdb, cmd, &sector_ret);
if (sector_ret)
goto out_unsupported_cdb;
*size = pscsi_get_size(sectors, cdb, cmd);
cmd->t_task_lba = pscsi_get_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 = pscsi_get_sectors_12(cdb, cmd, &sector_ret);
if (sector_ret)
goto out_unsupported_cdb;
*size = pscsi_get_size(sectors, cdb, cmd);
cmd->t_task_lba = pscsi_get_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 = pscsi_get_sectors_16(cdb, cmd, &sector_ret);
if (sector_ret)
goto out_unsupported_cdb;
*size = pscsi_get_size(sectors, cdb, cmd);
cmd->t_task_lba = pscsi_get_lba_64(cdb);
if (cdb[1] & 0x8)
cmd->se_cmd_flags |= SCF_FUA;
case WRITE_VERIFY:
cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
break;
case VARIABLE_LENGTH_CMD:
service_action = get_unaligned_be16(&cdb[8]);
switch (service_action) {
case WRITE_SAME_32:
sectors = pscsi_get_sectors_32(cdb, cmd, &sector_ret);
if (sector_ret)
goto out_unsupported_cdb;
if (!sectors) {
pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not"
" supported\n");
goto out_invalid_cdb_field;
}
*size = pscsi_get_size(1, cdb, cmd);
cmd->t_task_lba = get_unaligned_be64(&cdb[12]);
break;
default:
pr_err("VARIABLE_LENGTH_CMD service action"
" 0x%04x not supported\n", service_action);
goto out_unsupported_cdb;
}
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 READ_BUFFER:
*size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8];
break;
case READ_CAPACITY:
*size = READ_CAP_LEN;
break;
case READ_MEDIA_SERIAL_NUMBER:
case SERVICE_ACTION_IN:
case ACCESS_CONTROL_IN:
case ACCESS_CONTROL_OUT:
*size = (cdb[10] << 24) | (cdb[11] << 16) |
(cdb[12] << 8) | cdb[13];
break;
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 = pscsi_get_sectors_10(cdb, cmd, &sector_ret);
cmd->t_task_lba = pscsi_get_lba_32(cdb);
} else {
sectors = pscsi_get_sectors_16(cdb, cmd, &sector_ret);
cmd->t_task_lba = pscsi_get_lba_64(cdb);
}
if (sector_ret)
goto out_unsupported_cdb;
*size = pscsi_get_size(sectors, cdb, cmd);
break;
case UNMAP:
*size = get_unaligned_be16(&cdb[7]);
break;
case WRITE_SAME_16:
sectors = pscsi_get_sectors_16(cdb, cmd, &sector_ret);
if (sector_ret)
goto out_unsupported_cdb;
if (!sectors) {
pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n");
goto out_invalid_cdb_field;
}
*size = pscsi_get_size(1, cdb, cmd);
cmd->t_task_lba = get_unaligned_be64(&cdb[2]);
break;
case WRITE_SAME:
sectors = pscsi_get_sectors_10(cdb, cmd, &sector_ret);
if (sector_ret)
goto out_unsupported_cdb;
if (!sectors) {
pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n");
goto out_invalid_cdb_field;
}
*size = pscsi_get_size(1, cdb, cmd);
cmd->t_task_lba = get_unaligned_be32(&cdb[2]);
break;
case ALLOW_MEDIUM_REMOVAL:
case ERASE:
case REZERO_UNIT:
case SEEK_10:
case SPACE:
case START_STOP:
case VERIFY:
case WRITE_FILEMARKS:
case GPCMD_CLOSE_TRACK:
case INITIALIZE_ELEMENT_STATUS:
case GPCMD_LOAD_UNLOAD:
case GPCMD_SET_SPEED:
case MOVE_MEDIUM:
*size = 0;
break;
case GET_EVENT_STATUS_NOTIFICATION:
*size = (cdb[7] << 8) | cdb[8];
break;
case ATA_16:
switch (cdb[2] & 0x3) { /* T_LENGTH */
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, true);
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;
}
break;
}
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;
}
static int pscsi_execute_cmd(struct se_cmd *cmd, struct scatterlist *sgl,
u32 sgl_nents, enum dma_data_direction data_direction)
{
......
......@@ -37,6 +37,192 @@
#include "target_core_ua.h"
static int sbc_emulate_readcapacity(struct se_cmd *cmd)
{
struct se_device *dev = cmd->se_dev;
unsigned char *buf;
unsigned long long blocks_long = dev->transport->get_blocks(dev);
u32 blocks;
if (blocks_long >= 0x00000000ffffffff)
blocks = 0xffffffff;
else
blocks = (u32)blocks_long;
buf = transport_kmap_data_sg(cmd);
buf[0] = (blocks >> 24) & 0xff;
buf[1] = (blocks >> 16) & 0xff;
buf[2] = (blocks >> 8) & 0xff;
buf[3] = blocks & 0xff;
buf[4] = (dev->se_sub_dev->se_dev_attrib.block_size >> 24) & 0xff;
buf[5] = (dev->se_sub_dev->se_dev_attrib.block_size >> 16) & 0xff;
buf[6] = (dev->se_sub_dev->se_dev_attrib.block_size >> 8) & 0xff;
buf[7] = dev->se_sub_dev->se_dev_attrib.block_size & 0xff;
transport_kunmap_data_sg(cmd);
target_complete_cmd(cmd, GOOD);
return 0;
}
static int sbc_emulate_readcapacity_16(struct se_cmd *cmd)
{
struct se_device *dev = cmd->se_dev;
unsigned char *buf;
unsigned long long blocks = dev->transport->get_blocks(dev);
buf = transport_kmap_data_sg(cmd);
buf[0] = (blocks >> 56) & 0xff;
buf[1] = (blocks >> 48) & 0xff;
buf[2] = (blocks >> 40) & 0xff;
buf[3] = (blocks >> 32) & 0xff;
buf[4] = (blocks >> 24) & 0xff;
buf[5] = (blocks >> 16) & 0xff;
buf[6] = (blocks >> 8) & 0xff;
buf[7] = blocks & 0xff;
buf[8] = (dev->se_sub_dev->se_dev_attrib.block_size >> 24) & 0xff;
buf[9] = (dev->se_sub_dev->se_dev_attrib.block_size >> 16) & 0xff;
buf[10] = (dev->se_sub_dev->se_dev_attrib.block_size >> 8) & 0xff;
buf[11] = dev->se_sub_dev->se_dev_attrib.block_size & 0xff;
/*
* Set Thin Provisioning Enable bit following sbc3r22 in section
* READ CAPACITY (16) byte 14 if emulate_tpu or emulate_tpws is enabled.
*/
if (dev->se_sub_dev->se_dev_attrib.emulate_tpu || dev->se_sub_dev->se_dev_attrib.emulate_tpws)
buf[14] = 0x80;
transport_kunmap_data_sg(cmd);
target_complete_cmd(cmd, GOOD);
return 0;
}
/*
* Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support.
* Note this is not used for TCM/pSCSI passthrough
*/
static int sbc_emulate_unmap(struct se_cmd *cmd)
{
struct se_device *dev = cmd->se_dev;
unsigned char *buf, *ptr = NULL;
unsigned char *cdb = &cmd->t_task_cdb[0];
sector_t lba;
unsigned int size = cmd->data_length, range;
int ret = 0, offset;
unsigned short dl, bd_dl;
if (!dev->transport->do_discard) {
pr_err("UNMAP emulation not supported for: %s\n",
dev->transport->name);
cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE;
return -ENOSYS;
}
/* First UNMAP block descriptor starts at 8 byte offset */
offset = 8;
size -= 8;
dl = get_unaligned_be16(&cdb[0]);
bd_dl = get_unaligned_be16(&cdb[2]);
buf = transport_kmap_data_sg(cmd);
ptr = &buf[offset];
pr_debug("UNMAP: Sub: %s Using dl: %hu bd_dl: %hu size: %hu"
" ptr: %p\n", dev->transport->name, dl, bd_dl, size, ptr);
while (size) {
lba = get_unaligned_be64(&ptr[0]);
range = get_unaligned_be32(&ptr[8]);
pr_debug("UNMAP: Using lba: %llu and range: %u\n",
(unsigned long long)lba, range);
ret = dev->transport->do_discard(dev, lba, range);
if (ret < 0) {
pr_err("blkdev_issue_discard() failed: %d\n",
ret);
goto err;
}
ptr += 16;
size -= 16;
}
err:
transport_kunmap_data_sg(cmd);
if (!ret)
target_complete_cmd(cmd, GOOD);
return ret;
}
/*
* Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support.
* Note this is not used for TCM/pSCSI passthrough
*/
static int sbc_emulate_write_same(struct se_cmd *cmd)
{
struct se_device *dev = cmd->se_dev;
sector_t range;
sector_t lba = cmd->t_task_lba;
u32 num_blocks;
int ret;
if (!dev->transport->do_discard) {
pr_err("WRITE_SAME emulation not supported"
" for: %s\n", dev->transport->name);
cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE;
return -ENOSYS;
}
if (cmd->t_task_cdb[0] == WRITE_SAME)
num_blocks = get_unaligned_be16(&cmd->t_task_cdb[7]);
else if (cmd->t_task_cdb[0] == WRITE_SAME_16)
num_blocks = get_unaligned_be32(&cmd->t_task_cdb[10]);
else /* WRITE_SAME_32 via VARIABLE_LENGTH_CMD */
num_blocks = get_unaligned_be32(&cmd->t_task_cdb[28]);
/*
* Use the explicit range when non zero is supplied, otherwise calculate
* the remaining range based on ->get_blocks() - starting LBA.
*/
if (num_blocks != 0)
range = num_blocks;
else
range = (dev->transport->get_blocks(dev) - lba) + 1;
pr_debug("WRITE_SAME UNMAP: LBA: %llu Range: %llu\n",
(unsigned long long)lba, (unsigned long long)range);
ret = dev->transport->do_discard(dev, lba, range);
if (ret < 0) {
pr_debug("blkdev_issue_discard() failed for WRITE_SAME\n");
return ret;
}
target_complete_cmd(cmd, GOOD);
return 0;
}
static int sbc_emulate_synchronize_cache(struct se_cmd *cmd)
{
if (!cmd->se_dev->transport->do_sync_cache) {
pr_err("SYNCHRONIZE_CACHE emulation not supported"
" for: %s\n", cmd->se_dev->transport->name);
cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE;
return -ENOSYS;
}
cmd->se_dev->transport->do_sync_cache(cmd);
return 0;
}
static int sbc_emulate_verify(struct se_cmd *cmd)
{
target_complete_cmd(cmd, GOOD);
return 0;
}
static inline u32 sbc_get_size(struct se_cmd *cmd, u32 sectors)
{
return cmd->se_dev->se_sub_dev->se_dev_attrib.block_size * sectors;
......@@ -209,11 +395,12 @@ static void xdreadwrite_callback(struct se_cmd *cmd)
kfree(buf);
}
int sbc_parse_cdb(struct se_cmd *cmd, unsigned int *size)
int sbc_parse_cdb(struct se_cmd *cmd)
{
struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev;
struct se_device *dev = cmd->se_dev;
unsigned char *cdb = cmd->t_task_cdb;
unsigned int size;
u32 sectors = 0;
int ret;
......@@ -311,12 +498,12 @@ int sbc_parse_cdb(struct se_cmd *cmd, unsigned int *size)
goto out_invalid_cdb_field;
}
*size = sbc_get_size(cmd, 1);
size = sbc_get_size(cmd, 1);
cmd->t_task_lba = get_unaligned_be64(&cdb[12]);
if (sbc_write_same_supported(dev, &cdb[10]) < 0)
goto out_unsupported_cdb;
cmd->execute_cmd = target_emulate_write_same;
cmd->execute_cmd = sbc_emulate_write_same;
break;
default:
pr_err("VARIABLE_LENGTH_CMD service action"
......@@ -326,20 +513,20 @@ int sbc_parse_cdb(struct se_cmd *cmd, unsigned int *size)
break;
}
case READ_CAPACITY:
*size = READ_CAP_LEN;
cmd->execute_cmd = target_emulate_readcapacity;
size = READ_CAP_LEN;
cmd->execute_cmd = sbc_emulate_readcapacity;
break;
case SERVICE_ACTION_IN:
switch (cmd->t_task_cdb[1] & 0x1f) {
case SAI_READ_CAPACITY_16:
cmd->execute_cmd = target_emulate_readcapacity_16;
cmd->execute_cmd = sbc_emulate_readcapacity_16;
break;
default:
pr_err("Unsupported SA: 0x%02x\n",
cmd->t_task_cdb[1] & 0x1f);
goto out_invalid_cdb_field;
}
*size = (cdb[10] << 24) | (cdb[11] << 16) |
size = (cdb[10] << 24) | (cdb[11] << 16) |
(cdb[12] << 8) | cdb[13];
break;
case SYNCHRONIZE_CACHE:
......@@ -355,7 +542,7 @@ int sbc_parse_cdb(struct se_cmd *cmd, unsigned int *size)
cmd->t_task_lba = transport_lba_64(cdb);
}
*size = sbc_get_size(cmd, sectors);
size = sbc_get_size(cmd, sectors);
/*
* Check to ensure that LBA + Range does not exceed past end of
......@@ -365,11 +552,11 @@ int sbc_parse_cdb(struct se_cmd *cmd, unsigned int *size)
if (sbc_check_valid_sectors(cmd) < 0)
goto out_invalid_cdb_field;
}
cmd->execute_cmd = target_emulate_synchronize_cache;
cmd->execute_cmd = sbc_emulate_synchronize_cache;
break;
case UNMAP:
*size = get_unaligned_be16(&cdb[7]);
cmd->execute_cmd = target_emulate_unmap;
size = get_unaligned_be16(&cdb[7]);
cmd->execute_cmd = sbc_emulate_unmap;
break;
case WRITE_SAME_16:
sectors = transport_get_sectors_16(cdb);
......@@ -378,12 +565,12 @@ int sbc_parse_cdb(struct se_cmd *cmd, unsigned int *size)
goto out_invalid_cdb_field;
}
*size = sbc_get_size(cmd, 1);
size = sbc_get_size(cmd, 1);
cmd->t_task_lba = get_unaligned_be64(&cdb[2]);
if (sbc_write_same_supported(dev, &cdb[1]) < 0)
goto out_unsupported_cdb;
cmd->execute_cmd = target_emulate_write_same;
cmd->execute_cmd = sbc_emulate_write_same;
break;
case WRITE_SAME:
sectors = transport_get_sectors_10(cdb);
......@@ -392,7 +579,7 @@ int sbc_parse_cdb(struct se_cmd *cmd, unsigned int *size)
goto out_invalid_cdb_field;
}
*size = sbc_get_size(cmd, 1);
size = sbc_get_size(cmd, 1);
cmd->t_task_lba = get_unaligned_be32(&cdb[2]);
/*
......@@ -401,14 +588,14 @@ int sbc_parse_cdb(struct se_cmd *cmd, unsigned int *size)
*/
if (sbc_write_same_supported(dev, &cdb[1]) < 0)
goto out_unsupported_cdb;
cmd->execute_cmd = target_emulate_write_same;
cmd->execute_cmd = sbc_emulate_write_same;
break;
case VERIFY:
*size = 0;
cmd->execute_cmd = target_emulate_noop;
size = 0;
cmd->execute_cmd = sbc_emulate_verify;
break;
default:
ret = spc_parse_cdb(cmd, size, false);
ret = spc_parse_cdb(cmd, &size);
if (ret)
return ret;
}
......@@ -418,6 +605,8 @@ int sbc_parse_cdb(struct se_cmd *cmd, unsigned int *size)
goto out_unsupported_cdb;
if (cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) {
unsigned long long end_lba;
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:"
......@@ -433,9 +622,21 @@ int sbc_parse_cdb(struct se_cmd *cmd, unsigned int *size)
goto out_invalid_cdb_field;
}
*size = sbc_get_size(cmd, sectors);
end_lba = dev->transport->get_blocks(dev) + 1;
if (cmd->t_task_lba + sectors > end_lba) {
pr_err("cmd exceeds last lba %llu "
"(lba %llu, sectors %u)\n",
end_lba, cmd->t_task_lba, sectors);
goto out_invalid_cdb_field;
}
size = sbc_get_size(cmd, sectors);
}
ret = target_cmd_size_check(cmd, size);
if (ret < 0)
return ret;
return 0;
out_unsupported_cdb:
......
此差异已折叠。
......@@ -1343,7 +1343,7 @@ static inline void transport_generic_prepare_cdb(
}
}
static int target_cmd_size_check(struct se_cmd *cmd, unsigned int size)
int target_cmd_size_check(struct se_cmd *cmd, unsigned int size)
{
struct se_device *dev = cmd->se_dev;
......@@ -1469,7 +1469,6 @@ 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);
......@@ -1561,11 +1560,7 @@ int target_setup_cmd_from_cdb(
*/
}
ret = cmd->se_dev->transport->parse_cdb(cmd, &size);
if (ret < 0)
return ret;
ret = target_cmd_size_check(cmd, size);
ret = cmd->se_dev->transport->parse_cdb(cmd);
if (ret < 0)
return ret;
......@@ -2163,32 +2158,6 @@ static int transport_get_sense_data(struct se_cmd *cmd)
return -1;
}
static inline long long transport_dev_end_lba(struct se_device *dev)
{
return dev->transport->get_blocks(dev) + 1;
}
static int transport_cmd_get_valid_sectors(struct se_cmd *cmd)
{
struct se_device *dev = cmd->se_dev;
u32 sectors;
if (dev->transport->get_device_type(dev) != TYPE_DISK)
return 0;
sectors = (cmd->data_length / dev->se_sub_dev->se_dev_attrib.block_size);
if ((cmd->t_task_lba + sectors) > transport_dev_end_lba(dev)) {
pr_err("LBA: %llu Sectors: %u exceeds"
" transport_dev_end_lba(): %llu\n",
cmd->t_task_lba, sectors,
transport_dev_end_lba(dev));
return -EINVAL;
}
return 0;
}
/*
* Called from I/O completion to determine which dormant/delayed
* and ordered cmds need to have their tasks added to the execution queue.
......@@ -2632,7 +2601,6 @@ transport_generic_get_mem(struct se_cmd *cmd)
*/
int transport_generic_new_cmd(struct se_cmd *cmd)
{
struct se_device *dev = cmd->se_dev;
int ret = 0;
/*
......@@ -2666,17 +2634,6 @@ int transport_generic_new_cmd(struct se_cmd *cmd)
return 0;
}
if (cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) {
struct se_dev_attrib *attr = &dev->se_sub_dev->se_dev_attrib;
if (transport_cmd_get_valid_sectors(cmd) < 0)
return -EINVAL;
BUG_ON(cmd->data_length % attr->block_size);
BUG_ON(DIV_ROUND_UP(cmd->data_length, attr->block_size) >
attr->hw_max_sectors);
}
atomic_inc(&cmd->t_fe_count);
/*
......
......@@ -25,7 +25,7 @@ struct se_subsystem_api {
void (*free_device)(void *);
int (*transport_complete)(struct se_cmd *cmd, struct scatterlist *);
int (*parse_cdb)(struct se_cmd *cmd, unsigned int *size);
int (*parse_cdb)(struct se_cmd *cmd);
int (*execute_cmd)(struct se_cmd *, struct scatterlist *, u32,
enum dma_data_direction);
int (*do_discard)(struct se_device *, sector_t, u32);
......@@ -51,8 +51,8 @@ struct se_device *transport_add_device_to_core_hba(struct se_hba *,
void target_complete_cmd(struct se_cmd *, u8);
int sbc_parse_cdb(struct se_cmd *cmd, unsigned int *size);
int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size, bool passthrough);
int sbc_parse_cdb(struct se_cmd *cmd);
int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size);
void transport_set_vpd_proto_id(struct t10_vpd *, unsigned char *);
int transport_set_vpd_assoc(struct t10_vpd *, unsigned char *);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册