Commit 1fd032ee authored by Christoph Hellwig's avatar Christoph Hellwig Committed by 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: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarNicholas Bellinger <nab@linux-iscsi.org>
parent 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 \
......
This diff is collapsed.
......@@ -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 *);
......
This diff is collapsed.
......@@ -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:
......
This diff is collapsed.
......@@ -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%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment