Skip to contentSkip to conversation

tcm: Add Thin Provisioning / UNMAP emulation and Block Limits VPD page

PATCH In review Nicholas A. Bellinger 2 participants 3 messages Sep 27, 2010 – Sep 29, 2010

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

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

From: Nicholas Bellinger <[email protected]>

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.

---
 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(-)
drivers/target/target_core_configfs.c +24 -0
index f66ac33..208db8e 100644
@@ -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,
 };
 
drivers/target/target_core_device.c +90 -0

123 lines not on this page · raw message

drivers/target/target_core_transport.c +152 -0

182 lines not on this page · raw message

include/target/target_core_base.h +8 -1
index b6f3b75..69c61bb 100644
@@ -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;
include/target/target_core_device.h +6 -0
index eb825c3..01358a3 100644
@@ -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);
include/target/target_core_transport.h +11 -0
index 20702d7..47af81b 100644
@@ -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 *);
Signature · 1 line
1.5.6.5
#1 lore raw
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

"nab" == Nicholas A Bellinger <[email protected]> writes:

nab> This patch also adds the Block Limits VPD (0xb0) page

You should add the Thin Provisioning VPD page as well and set TPU and/or TPWS.

Signature · 1 line
Martin K. Petersen	Oracle Linux Engineering
#2 lore raw
Quoted 7 lines · Martin K. Petersen
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

"nab" == Nicholas A Bellinger <[email protected]> writes:

nab> This patch also adds the Block Limits VPD (0xb0) page

You should add the Thin Provisioning VPD page as well and set TPU and/or TPWS.

Greetings mkp,

So I was looking at adding this VPD page orginally to set TPU=1 w/ DP=0 (because I don't believe there is currently way to get build the PROVISIONING GROUP DESCRIPTORs from Block Discard knowledge), but I ended getting a bit confused by the THRESHOLD EXPONENT, and what value this should returned for the TCM/IBLOCK and TCM/FILEIO backstores when blk_queue_discard()==1 is enabled.

Since this is currently not implemented in scsi_debug.c or used in any way by sd.c AFAICT, do you have any additional information on how this should be determined together with the UNMAP -> blk_issue_discard() emulation bits..?

Thanks!

--nab