target: Add/check max_write_same_len device attribute + update block limits VPD
authorNicholas Bellinger <nab@linux-iscsi.org>
Thu, 15 Nov 2012 19:02:49 +0000 (11:02 -0800)
committerNicholas Bellinger <nab@linux-iscsi.org>
Thu, 15 Nov 2012 20:27:21 +0000 (12:27 -0800)
This patch adds a new max_write_same_len device attribute for use with
WRITE_SAME w/ UNMAP=0 backend emulation.  This can be useful for
lowering the default backend value (IBLOCK uses 0xFFFF).

Also, update block limits VPD emulation code in spc_emulate_evpd_b0() to
report MAXIMUM WRITE SAME LENGTH, and enforce max_write_same_len during
sbc_parse() -> sbc_setup_write_same() CDB sanity checking for all emulated
WRITE_SAME w/ UNMAP=0 cases.

(Robert: Move max_write_same_len check in sbc_setup_write_same() to
         check both WRITE_SAME w/ UNMAP=1 and w/ UNMAP=0 cases)

Cc: Christoph Hellwig <hch@lst.de>
Cc: Martin K. Petersen <martin.petersen@oracle.com>
Cc: Robert Elliott <Elliott@hp.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
drivers/target/target_core_configfs.c
drivers/target/target_core_device.c
drivers/target/target_core_internal.h
drivers/target/target_core_sbc.c
drivers/target/target_core_spc.c
include/target/target_core_base.h

index 7b473b6..2b14164 100644 (file)
@@ -676,6 +676,9 @@ 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);
 
+DEF_DEV_ATTRIB(max_write_same_len);
+SE_DEV_ATTR(max_write_same_len, 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[] = {
@@ -701,6 +704,7 @@ static struct configfs_attribute *target_core_dev_attrib_attrs[] = {
        &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,
+       &target_core_dev_attrib_max_write_same_len.attr,
        NULL,
 };
 
index 599374e..54439bc 100644 (file)
@@ -706,6 +706,16 @@ int se_dev_set_unmap_granularity_alignment(
        return 0;
 }
 
+int se_dev_set_max_write_same_len(
+       struct se_device *dev,
+       u32 max_write_same_len)
+{
+       dev->dev_attrib.max_write_same_len = max_write_same_len;
+       pr_debug("dev[%p]: Set max_write_same_len: %u\n",
+                       dev, dev->dev_attrib.max_write_same_len);
+       return 0;
+}
+
 int se_dev_set_emulate_dpo(struct se_device *dev, int flag)
 {
        if (flag != 0 && flag != 1) {
@@ -1393,6 +1403,7 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)
        dev->dev_attrib.unmap_granularity = DA_UNMAP_GRANULARITY_DEFAULT;
        dev->dev_attrib.unmap_granularity_alignment =
                                DA_UNMAP_GRANULARITY_ALIGNMENT_DEFAULT;
+       dev->dev_attrib.max_write_same_len = DA_MAX_WRITE_SAME_LEN;
        dev->dev_attrib.fabric_max_sectors = DA_FABRIC_MAX_SECTORS;
        dev->dev_attrib.optimal_sectors = DA_FABRIC_MAX_SECTORS;
 
index bc9c522..93e9c1f 100644 (file)
@@ -24,6 +24,7 @@ int   se_dev_set_max_unmap_lba_count(struct se_device *, u32);
 int    se_dev_set_max_unmap_block_desc_count(struct se_device *, u32);
 int    se_dev_set_unmap_granularity(struct se_device *, u32);
 int    se_dev_set_unmap_granularity_alignment(struct se_device *, u32);
+int    se_dev_set_max_write_same_len(struct se_device *, u32);
 int    se_dev_set_emulate_dpo(struct se_device *, int);
 int    se_dev_set_emulate_fua_write(struct se_device *, int);
 int    se_dev_set_emulate_fua_read(struct se_device *, int);
index a5a8f46..45e11d0 100644 (file)
@@ -238,12 +238,19 @@ static inline unsigned long long transport_lba_64_ext(unsigned char *cdb)
 static sense_reason_t
 sbc_setup_write_same(struct se_cmd *cmd, unsigned char *flags, struct sbc_ops *ops)
 {
+       unsigned int sectors = spc_get_write_same_sectors(cmd);
+
        if ((flags[0] & 0x04) || (flags[0] & 0x02)) {
                pr_err("WRITE_SAME PBDATA and LBDATA"
                        " bits not supported for Block Discard"
                        " Emulation\n");
                return TCM_UNSUPPORTED_SCSI_OPCODE;
        }
+       if (sectors > cmd->se_dev->dev_attrib.max_write_same_len) {
+               pr_warn("WRITE_SAME sectors: %u exceeds max_write_same_len: %u\n",
+                       sectors, cmd->se_dev->dev_attrib.max_write_same_len);
+               return TCM_INVALID_CDB_FIELD;
+       }
        /*
         * Special case for WRITE_SAME w/ UNMAP=1 that ends up getting
         * translated into block discard requests within backend code.
index 4b3c183..cf1b8bb 100644 (file)
@@ -465,7 +465,7 @@ spc_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf)
         * Exit now if we don't support TP.
         */
        if (!have_tp)
-               return 0;
+               goto max_write_same;
 
        /*
         * Set MAXIMUM UNMAP LBA COUNT
@@ -491,6 +491,12 @@ spc_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf)
        if (dev->dev_attrib.unmap_granularity_alignment != 0)
                buf[32] |= 0x80; /* Set the UGAVALID bit */
 
+       /*
+        * MAXIMUM WRITE SAME LENGTH
+        */
+max_write_same:
+       put_unaligned_be64(dev->dev_attrib.max_write_same_len, &buf[36]);
+
        return 0;
 }
 
index 5350f6e..645d90a 100644 (file)
@@ -71,6 +71,8 @@
 #define DA_UNMAP_GRANULARITY_DEFAULT           0
 /* Default unmap_granularity_alignment */
 #define DA_UNMAP_GRANULARITY_ALIGNMENT_DEFAULT 0
+/* Default max_write_same_len, disabled by default */
+#define DA_MAX_WRITE_SAME_LEN                  0
 /* Default max transfer length */
 #define DA_FABRIC_MAX_SECTORS                  8192
 /* Emulation for Direct Page Out */
@@ -609,6 +611,7 @@ struct se_dev_attrib {
        u32             max_unmap_block_desc_count;
        u32             unmap_granularity;
        u32             unmap_granularity_alignment;
+       u32             max_write_same_len;
        struct se_device *da_dev;
        struct config_group da_group;
 };