Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1fd032ee authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Nicholas Bellinger
Browse files

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
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -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 \

drivers/target/target_core_cdb.c

deleted100644 → 0
+0 −1130

File deleted.

Preview size limit exceeded, changes collapsed.

+1 −11
Original line number Diff line number Diff line
@@ -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 *);
+24 −441
Original line number Diff line number Diff line
@@ -1022,470 +1022,53 @@ fail:
	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;

	/*
	 * 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 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];
	unsigned char *cdb = cmd->t_task_cdb;
	unsigned int dummy_size;
	int ret;

	return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32;
	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;
	}

	/*
 * For VARIABLE_LENGTH_CDB w/ 32 byte extended CDBs
	 * 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.
	 */
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;
		}
	}

	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)
{
+220 −19
Original line number Diff line number Diff line
@@ -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 @@ out:
	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:
Loading