[PATCH 1/3] tcm: Add Thin Provisioning / UNMAP emulation and Block Limits VPD page

From: Nicholas A. Bellinger
Date: Mon Sep 27 2010 - 18:51:40 EST


From: Nicholas Bellinger <nab@xxxxxxxxxxxxxxx>

This patch adds a generic Thin Provisioning enabled (TPE=1) emulation
and a new transport_generic_unmap() exported caller used by TCM/IBLOCK and
TCM/FILEIO to issue blkdev_issue_discard() for a received LBA + Range
to a struct block_device. This includes the addition of UNMAP in
transport_generic_cmd_sequencer() for both the DEV_ATTRIB(dev)->emulate_tpe=1
case for IBLOCK/FILEIO and the passthrough case for TCM/pSCSI.

Tthis patch also adds the Block Limits VPD (0xb0) page for INQUIRY EVPD=1
to report both emulate_tpe=1 and emulate_tpe=0 cases. This page returns
the these values, the ones related to TPE=1 have been added into
struct se_dev_attrib:

*) OPTIMAL TRANSFER LENGTH GRANULARITY
*) MAXIMUM TRANSFER LENGTH
*) OPTIMAL TRANSFER LENGTH
*) MAXIMUM UNMAP LBA COUNT (tpe=1)
*) MAXIMUM UNMAP BLOCK DESCRIPTOR COUNT (tpe=1)
*) OPTIMAL UNMAP GRANULARITY (tpe=1)
*) UNMAP GRANULARITY ALIGNMENT (tpe=1)

the TPE=1 releated values in Block Limits VPD also now appear along with
optimal_sectors as new configfs attributes in:

/sys/kernel/config/target/core/$HBA/$DEV/attrib/

Finally, this patch updates transport_generic_emulate_readcapacity() to
signal SA READ_CAPACITY16 and updates transport_generic_emulate_readcapacity_16()
to set TPE=1 bit when emulate_tpe=1.

Signed-off-by: Nicholas A. Bellinger <nab@xxxxxxxxxxxxxxx>
---
drivers/target/target_core_configfs.c | 24 +++++
drivers/target/target_core_device.c | 90 +++++++++++++++++++
drivers/target/target_core_transport.c | 152 ++++++++++++++++++++++++++++++++
include/target/target_core_base.h | 9 ++-
include/target/target_core_device.h | 6 ++
include/target/target_core_transport.h | 11 +++
6 files changed, 291 insertions(+), 1 deletions(-)

diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index f66ac33..208db8e 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -563,6 +563,9 @@ SE_DEV_ATTR(emulate_ua_intlck_ctrl, S_IRUGO | S_IWUSR);
DEF_DEV_ATTRIB(emulate_tas);
SE_DEV_ATTR(emulate_tas, S_IRUGO | S_IWUSR);

+DEF_DEV_ATTRIB(emulate_tpe);
+SE_DEV_ATTR(emulate_tpe, S_IRUGO | S_IWUSR);
+
DEF_DEV_ATTRIB(enforce_pr_isids);
SE_DEV_ATTR(enforce_pr_isids, S_IRUGO | S_IWUSR);

@@ -578,6 +581,9 @@ SE_DEV_ATTR_RO(hw_max_sectors);
DEF_DEV_ATTRIB(max_sectors);
SE_DEV_ATTR(max_sectors, S_IRUGO | S_IWUSR);

+DEF_DEV_ATTRIB(optimal_sectors);
+SE_DEV_ATTR(optimal_sectors, S_IRUGO | S_IWUSR);
+
DEF_DEV_ATTRIB_RO(hw_queue_depth);
SE_DEV_ATTR_RO(hw_queue_depth);

@@ -587,6 +593,18 @@ SE_DEV_ATTR(queue_depth, S_IRUGO | S_IWUSR);
DEF_DEV_ATTRIB(task_timeout);
SE_DEV_ATTR(task_timeout, S_IRUGO | S_IWUSR);

+DEF_DEV_ATTRIB(max_unmap_lba_count);
+SE_DEV_ATTR(max_unmap_lba_count, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB(max_unmap_block_desc_count);
+SE_DEV_ATTR(max_unmap_block_desc_count, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB(unmap_granularity);
+SE_DEV_ATTR(unmap_granularity, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB(unmap_granularity_alignment);
+SE_DEV_ATTR(unmap_granularity_alignment, S_IRUGO | S_IWUSR);
+
CONFIGFS_EATTR_OPS(target_core_dev_attrib, se_dev_attrib, da_group);

static struct configfs_attribute *target_core_dev_attrib_attrs[] = {
@@ -596,14 +614,20 @@ static struct configfs_attribute *target_core_dev_attrib_attrs[] = {
&target_core_dev_attrib_emulate_write_cache.attr,
&target_core_dev_attrib_emulate_ua_intlck_ctrl.attr,
&target_core_dev_attrib_emulate_tas.attr,
+ &target_core_dev_attrib_emulate_tpe.attr,
&target_core_dev_attrib_enforce_pr_isids.attr,
&target_core_dev_attrib_hw_block_size.attr,
&target_core_dev_attrib_block_size.attr,
&target_core_dev_attrib_hw_max_sectors.attr,
&target_core_dev_attrib_max_sectors.attr,
+ &target_core_dev_attrib_optimal_sectors.attr,
&target_core_dev_attrib_hw_queue_depth.attr,
&target_core_dev_attrib_queue_depth.attr,
&target_core_dev_attrib_task_timeout.attr,
+ &target_core_dev_attrib_max_unmap_lba_count.attr,
+ &target_core_dev_attrib_max_unmap_block_desc_count.attr,
+ &target_core_dev_attrib_unmap_granularity.attr,
+ &target_core_dev_attrib_unmap_granularity_alignment.attr,
NULL,
};

diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c
index 1e8be47..f8543f6 100644
--- a/drivers/target/target_core_device.c
+++ b/drivers/target/target_core_device.c
@@ -1003,9 +1003,16 @@ void se_dev_set_default_attribs(struct se_device *dev)
DEV_ATTRIB(dev)->emulate_write_cache = DA_EMULATE_WRITE_CACHE;
DEV_ATTRIB(dev)->emulate_ua_intlck_ctrl = DA_EMULATE_UA_INTLLCK_CTRL;
DEV_ATTRIB(dev)->emulate_tas = DA_EMULATE_TAS;
+ DEV_ATTRIB(dev)->emulate_tpe = DA_EMULATE_TPE;
DEV_ATTRIB(dev)->emulate_reservations = DA_EMULATE_RESERVATIONS;
DEV_ATTRIB(dev)->emulate_alua = DA_EMULATE_ALUA;
DEV_ATTRIB(dev)->enforce_pr_isids = DA_ENFORCE_PR_ISIDS;
+ DEV_ATTRIB(dev)->max_unmap_lba_count = DA_MAX_UNMAP_LBA_COUNT;
+ DEV_ATTRIB(dev)->max_unmap_block_desc_count =
+ DA_MAX_UNMAP_BLOCK_DESC_COUNT;
+ DEV_ATTRIB(dev)->unmap_granularity = DA_UNMAP_GRANULARITY_DEFAULT;
+ DEV_ATTRIB(dev)->unmap_granularity_alignment =
+ DA_UNMAP_GRANULARITY_ALIGNMENT_DEFAULT;
/*
* block_size is based on subsystem plugin dependent requirements.
*/
@@ -1017,6 +1024,11 @@ void se_dev_set_default_attribs(struct se_device *dev)
DEV_ATTRIB(dev)->hw_max_sectors = TRANSPORT(dev)->get_max_sectors(dev);
DEV_ATTRIB(dev)->max_sectors = TRANSPORT(dev)->get_max_sectors(dev);
/*
+ * Set optimal_sectors from max_sectors, which can be lowered via
+ * configfs.
+ */
+ DEV_ATTRIB(dev)->optimal_sectors = DEV_ATTRIB(dev)->max_sectors;
+ /*
* queue_depth is based on subsystem plugin dependent requirements.
*/
DEV_ATTRIB(dev)->hw_queue_depth = TRANSPORT(dev)->get_queue_depth(dev);
@@ -1051,6 +1063,46 @@ int se_dev_set_task_timeout(struct se_device *dev, u32 task_timeout)
return 0;
}

+int se_dev_set_max_unmap_lba_count(
+ struct se_device *dev,
+ u32 max_unmap_lba_count)
+{
+ DEV_ATTRIB(dev)->max_unmap_lba_count = max_unmap_lba_count;
+ printk(KERN_INFO "dev[%p]: Set max_unmap_lba_count: %u\n",
+ dev, DEV_ATTRIB(dev)->max_unmap_lba_count);
+ return 0;
+}
+
+int se_dev_set_max_unmap_block_desc_count(
+ struct se_device *dev,
+ u32 max_unmap_block_desc_count)
+{
+ DEV_ATTRIB(dev)->max_unmap_block_desc_count = max_unmap_block_desc_count;
+ printk(KERN_INFO "dev[%p]: Set max_unmap_block_desc_count: %u\n",
+ dev, DEV_ATTRIB(dev)->max_unmap_block_desc_count);
+ return 0;
+}
+
+int se_dev_set_unmap_granularity(
+ struct se_device *dev,
+ u32 unmap_granularity)
+{
+ DEV_ATTRIB(dev)->unmap_granularity = unmap_granularity;
+ printk(KERN_INFO "dev[%p]: Set unmap_granularity: %u\n",
+ dev, DEV_ATTRIB(dev)->unmap_granularity);
+ return 0;
+}
+
+int se_dev_set_unmap_granularity_alignment(
+ struct se_device *dev,
+ u32 unmap_granularity_alignment)
+{
+ DEV_ATTRIB(dev)->unmap_granularity_alignment = unmap_granularity_alignment;
+ printk(KERN_INFO "dev[%p]: Set unmap_granularity_alignment: %u\n",
+ dev, DEV_ATTRIB(dev)->unmap_granularity_alignment);
+ return 0;
+}
+
int se_dev_set_emulate_dpo(struct se_device *dev, int flag)
{
if ((flag != 0) && (flag != 1)) {
@@ -1172,6 +1224,18 @@ int se_dev_set_emulate_tas(struct se_device *dev, int flag)
return 0;
}

+int se_dev_set_emulate_tpe(struct se_device *dev, int flag)
+{
+ if ((flag != 0) && (flag != 1)) {
+ printk(KERN_ERR "Illegal value %d\n", flag);
+ return -1;
+ }
+ DEV_ATTRIB(dev)->emulate_tpe = flag;
+ printk(KERN_INFO "dev[%p]: SE Device Thin Provising Enabled bit: %d\n",
+ dev, flag);
+ return 0;
+}
+
int se_dev_set_enforce_pr_isids(struct se_device *dev, int flag)
{
if ((flag != 0) && (flag != 1)) {
@@ -1297,6 +1361,32 @@ int se_dev_set_max_sectors(struct se_device *dev, u32 max_sectors)
return 0;
}

+int se_dev_set_optimal_sectors(struct se_device *dev, u32 optimal_sectors)
+{
+ if (atomic_read(&dev->dev_export_obj.obj_access_count)) {
+ printk(KERN_ERR "dev[%p]: Unable to change SE Device"
+ " optimal_sectors while dev_export_obj: %d count exists\n",
+ dev, atomic_read(&dev->dev_export_obj.obj_access_count));
+ return -EINVAL;
+ }
+ if (TRANSPORT(dev)->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) {
+ printk(KERN_ERR "dev[%p]: Passed optimal_sectors cannot be"
+ " changed for TCM/pSCSI\n", dev);
+ return -EINVAL;
+ }
+ if (optimal_sectors > DEV_ATTRIB(dev)->max_sectors) {
+ printk(KERN_ERR "dev[%p]: Passed optimal_sectors %u cannot be"
+ " greater than max_sectors: %u\n", dev,
+ optimal_sectors, DEV_ATTRIB(dev)->max_sectors);
+ return -EINVAL;
+ }
+
+ DEV_ATTRIB(dev)->optimal_sectors = optimal_sectors;
+ printk(KERN_INFO "dev[%p]: SE Device optimal_sectors changed to %u\n",
+ dev, optimal_sectors);
+ return 0;
+}
+
int se_dev_set_block_size(struct se_device *dev, u32 block_size)
{
if (atomic_read(&dev->dev_export_obj.obj_access_count)) {
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index be235ef..0a35a5c 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -4907,6 +4907,83 @@ set_len:
buf[6] = 0x01;

break;
+ case 0xb0: /* Block Limits VPD page */
+ /*
+ * Following sbc3r22 section 6.5.3 Block Limits VPD page,
+ * when emulate_tpe=1 we will be expect a different page length
+ */
+ if (!(DEV_ATTRIB(dev)->emulate_tpe)) {
+ if (cmd->data_length < 0x10) {
+ printk(KERN_INFO "Received data_length: %u"
+ " too small for TPE=0 EVPD 0xb0\n",
+ cmd->data_length);
+ return -1;
+ }
+ buf[0] = TRANSPORT(dev)->get_device_type(dev);
+ buf[1] = 0xb0;
+ buf[3] = 0x10; /* Set hardcoded TPE=0 length */
+ /*
+ * Set OPTIMAL TRANSFER LENGTH GRANULARITY
+ */
+ put_unaligned_be16(1, &buf[6]);
+ /*
+ * Set MAXIMUM TRANSFER LENGTH
+ */
+ put_unaligned_be32(DEV_ATTRIB(dev)->max_sectors,
+ &buf[8]);
+ /*
+ * Set OPTIMAL TRANSFER LENGTH
+ */
+ put_unaligned_be32(DEV_ATTRIB(dev)->optimal_sectors,
+ &buf[12]);
+ break;
+ }
+
+ if (cmd->data_length < 0x3c) {
+ printk(KERN_INFO "Received data_length: %u"
+ " too small for TPE=1 EVPD 0xb0\n",
+ cmd->data_length);
+ return -1;
+ }
+ buf[0] = TRANSPORT(dev)->get_device_type(dev);
+ buf[1] = 0xb0;
+ buf[3] = 0x3c; /* Set hardcoded TPE=1 length */
+ /*
+ * Set OPTIMAL TRANSFER LENGTH GRANULARITY
+ * Note that this follows what scsi_debug.c reports to SCSI ML
+ */
+ put_unaligned_be16(1, &buf[6]);
+ /*
+ * Set MAXIMUM TRANSFER LENGTH
+ */
+ put_unaligned_be32(DEV_ATTRIB(dev)->max_sectors, &buf[8]);
+ /*
+ * Set OPTIMAL TRANSFER LENGTH
+ */
+ put_unaligned_be32(DEV_ATTRIB(dev)->optimal_sectors, &buf[12]);
+ /*
+ * Set MAXIMUM UNMAP LBA COUNT
+ */
+ put_unaligned_be32(DEV_ATTRIB(dev)->max_unmap_lba_count,
+ &buf[20]);
+ /*
+ * Set MAXIMUM UNMAP BLOCK DESCRIPTOR COUNT
+ */
+ put_unaligned_be32(DEV_ATTRIB(dev)->max_unmap_block_desc_count,
+ &buf[24]);
+ /*
+ * Set OPTIMAL UNMAP GRANULARITY
+ */
+ put_unaligned_be32(DEV_ATTRIB(dev)->unmap_granularity,
+ &buf[28]);
+ /*
+ * UNMAP GRANULARITY ALIGNMENT
+ */
+ put_unaligned_be32(DEV_ATTRIB(dev)->unmap_granularity_alignment,
+ &buf[32]);
+ if (DEV_ATTRIB(dev)->unmap_granularity_alignment != 0)
+ buf[32] |= 0x80; /* Set the UGAVALID bit */
+ break;
default:
printk(KERN_ERR "Unknown VPD Code: 0x%02x\n", cdb[2]);
return -1;
@@ -4931,6 +5008,11 @@ int transport_generic_emulate_readcapacity(
buf[5] = (DEV_ATTRIB(dev)->block_size >> 16) & 0xff;
buf[6] = (DEV_ATTRIB(dev)->block_size >> 8) & 0xff;
buf[7] = DEV_ATTRIB(dev)->block_size & 0xff;
+ /*
+ * Set max 32-bit blocks to signal SERVICE ACTION READ_CAPACITY_16
+ */
+ if (DEV_ATTRIB(dev)->emulate_tpe)
+ put_unaligned_be32(0xFFFFFFFF, &buf[0]);

return 0;
}
@@ -4955,6 +5037,12 @@ int transport_generic_emulate_readcapacity_16(
buf[9] = (DEV_ATTRIB(dev)->block_size >> 16) & 0xff;
buf[10] = (DEV_ATTRIB(dev)->block_size >> 8) & 0xff;
buf[11] = DEV_ATTRIB(dev)->block_size & 0xff;
+ /*
+ * Set Thin Provisioning Enable bit following sbc3r22 in section
+ * READ CAPACITY (16) byte 14.
+ */
+ if (DEV_ATTRIB(dev)->emulate_tpe)
+ buf[14] = 0x80;

return 0;
}
@@ -5351,6 +5439,47 @@ static int transport_generic_synchronize_cache(struct se_cmd *cmd)
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
+ */
+int transport_generic_unmap(struct se_cmd *cmd, struct block_device *bdev)
+{
+ struct se_device *dev = SE_DEV(cmd);
+ unsigned char *buf = T_TASK(cmd)->t_task_buf, *ptr = NULL;
+ unsigned char *cdb = &T_TASK(cmd)->t_task_cdb[0];
+ sector_t lba;
+ unsigned int size = cmd->data_length, range;
+ int barrier = 0, ret, offset = 8; /* First UNMAP block descriptor starts at 8 byte offset */
+ unsigned short dl, bd_dl;
+
+ /* Skip over UNMAP header */
+ size -= 8;
+ dl = get_unaligned_be16(&cdb[0]);
+ bd_dl = get_unaligned_be16(&cdb[2]);
+ ptr = &buf[offset];
+ printk("UNMAP: Sub: %s Using dl: %hu bd_dl: %hu size: %hu ptr: %p\n",
+ TRANSPORT(dev)->name, dl, bd_dl, size, ptr);
+
+ while (size) {
+ lba = get_unaligned_be64(&ptr[0]);
+ range = get_unaligned_be32(&ptr[8]);
+ printk("UNMAP: Using lba: %llu and range: %u\n", lba, range);
+
+ ret = blkdev_issue_discard(bdev, lba, range, GFP_KERNEL, barrier);
+ if (ret < 0) {
+ printk(KERN_ERR "blkdev_issue_discard() failed: %d\n", ret);
+ return -1;
+ }
+
+ ptr += 16;
+ size -= 16;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(transport_generic_unmap);
+
static inline void transport_dev_get_mem_buf(
struct se_device *dev,
struct se_cmd *cmd)
@@ -5946,6 +6075,29 @@ static int transport_generic_cmd_sequencer(
if (transport_get_sectors(cmd) < 0)
return TGCS_INVALID_CDB_FIELD;
break;
+ case UNMAP:
+ SET_GENERIC_TRANSPORT_FUNCTIONS(cmd);
+ cmd->transport_allocate_resources =
+ &transport_generic_allocate_buf;
+ size = get_unaligned_be16(&cdb[7]);
+ transport_dev_get_mem_buf(cmd->se_orig_obj_ptr, cmd);
+ transport_get_maps(cmd);
+ passthrough = (TRANSPORT(dev)->transport_type ==
+ TRANSPORT_PLUGIN_PHBA_PDEV);
+ printk("Got UNMAP CDB for subsystem plugin: %s, pt: %hd size: %hu\n",
+ TRANSPORT(dev)->name, passthrough, size);
+ /*
+ * Determine if the received UNMAP used to for direct passthrough
+ * into Linux/SCSI with struct request via TCM/pSCSI or we are
+ * signaling the use of internal transport_generic_unmap() emulation
+ * for UNMAP -> Linux/BLOCK disbard with TCM/IBLOCK and TCM/FILEIO
+ * subsystem plugin backstores.
+ */
+ if (!(passthrough))
+ cmd->se_cmd_flags |= SCF_EMULATE_SYNC_UNMAP;
+
+ ret = TGCS_CONTROL_NONSG_IO_CDB;
+ break;
case ALLOW_MEDIUM_REMOVAL:
case GPCMD_CLOSE_TRACK:
case ERASE:
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index b6f3b75..69c61bb 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -136,7 +136,8 @@ enum se_cmd_flags_table {
SCF_PASSTHROUGH_CONTIG_TO_SG = 0x00400000,
SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC = 0x00800000,
SCF_EMULATE_SYNC_CACHE = 0x01000000,
- SCF_EMULATE_CDB_ASYNC = 0x02000000
+ SCF_EMULATE_CDB_ASYNC = 0x02000000,
+ SCF_EMULATE_SYNC_UNMAP = 0x04000000
};

/* struct se_device->type for known subsystem plugins */
@@ -748,6 +749,7 @@ struct se_dev_attrib {
int emulate_write_cache;
int emulate_ua_intlck_ctrl;
int emulate_tas;
+ int emulate_tpe;
int emulate_reservations;
int emulate_alua;
int enforce_pr_isids;
@@ -755,9 +757,14 @@ struct se_dev_attrib {
u32 block_size;
u32 hw_max_sectors;
u32 max_sectors;
+ u32 optimal_sectors;
u32 hw_queue_depth;
u32 queue_depth;
u32 task_timeout;
+ u32 max_unmap_lba_count;
+ u32 max_unmap_block_desc_count;
+ u32 unmap_granularity;
+ u32 unmap_granularity_alignment;
struct se_subsystem_dev *da_sub_dev;
struct config_group da_group;
} ____cacheline_aligned;
diff --git a/include/target/target_core_device.h b/include/target/target_core_device.h
index eb825c3..01358a3 100644
--- a/include/target/target_core_device.h
+++ b/include/target/target_core_device.h
@@ -38,15 +38,21 @@ extern int se_dev_check_online(struct se_device *);
extern int se_dev_check_shutdown(struct se_device *);
extern void se_dev_set_default_attribs(struct se_device *);
extern int se_dev_set_task_timeout(struct se_device *, u32);
+extern int se_dev_set_max_unmap_lba_count(struct se_device *, u32);
+extern int se_dev_set_max_unmap_block_desc_count(struct se_device *, u32);
+extern int se_dev_set_unmap_granularity(struct se_device *, u32);
+extern int se_dev_set_unmap_granularity_alignment(struct se_device *, u32);
extern int se_dev_set_emulate_dpo(struct se_device *, int);
extern int se_dev_set_emulate_fua_write(struct se_device *, int);
extern int se_dev_set_emulate_fua_read(struct se_device *, int);
extern int se_dev_set_emulate_write_cache(struct se_device *, int);
extern int se_dev_set_emulate_ua_intlck_ctrl(struct se_device *, int);
extern int se_dev_set_emulate_tas(struct se_device *, int);
+extern int se_dev_set_emulate_tpe(struct se_device *, int);
extern int se_dev_set_enforce_pr_isids(struct se_device *, int);
extern int se_dev_set_queue_depth(struct se_device *, u32);
extern int se_dev_set_max_sectors(struct se_device *, u32);
+extern int se_dev_set_optimal_sectors(struct se_device *, u32);
extern int se_dev_set_block_size(struct se_device *, u32);
extern struct se_lun *core_dev_add_lun(struct se_portal_group *, struct se_hba *,
struct se_device *, u32);
diff --git a/include/target/target_core_transport.h b/include/target/target_core_transport.h
index 20702d7..47af81b 100644
--- a/include/target/target_core_transport.h
+++ b/include/target/target_core_transport.h
@@ -87,6 +87,14 @@
/* struct se_dev_attrib sanity values */
/* 10 Minutes, see transport_get_default_task_timeout() */
#define DA_TASK_TIMEOUT_MAX 600
+/* Default max_unmap_lba_count */
+#define DA_MAX_UNMAP_LBA_COUNT 0
+/* Default max_unmap_block_desc_count */
+#define DA_MAX_UNMAP_BLOCK_DESC_COUNT 0
+/* Default unmap_granularity */
+#define DA_UNMAP_GRANULARITY_DEFAULT 0
+/* Default unmap_granularity_alignment */
+#define DA_UNMAP_GRANULARITY_ALIGNMENT_DEFAULT 0
/* Emulation for Direct Page Out */
#define DA_EMULATE_DPO 0
/* Emulation for Forced Unit Access WRITEs */
@@ -99,6 +107,8 @@
#define DA_EMULATE_UA_INTLLCK_CTRL 0
/* Emulation for TASK_ABORTED status (TAS) by default */
#define DA_EMULATE_TAS 1
+/* Emulation for Thin Provisioning Enabled using block/blk-lib.c:blkdev_issue_discard() */
+#define DA_EMULATE_TPE 0
/* No Emulation for PSCSI by default */
#define DA_EMULATE_RESERVATIONS 0
/* No Emulation for PSCSI by default */
@@ -224,6 +234,7 @@ extern int transport_generic_emulate_modesense(struct se_cmd *,
extern int transport_generic_emulate_request_sense(struct se_cmd *,
unsigned char *);
extern int transport_get_sense_data(struct se_cmd *);
+extern int transport_generic_unmap(struct se_cmd *, struct block_device *);
extern struct se_cmd *transport_allocate_passthrough(unsigned char *, int, u32,
void *, u32, u32, void *);
extern void transport_passthrough_release(struct se_cmd *);
--
1.5.6.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/