Commit 773cbaf7 authored by Nicholas Bellinger's avatar Nicholas Bellinger

target: Add/check max_write_same_len device attribute + update block limits VPD

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: default avatarNicholas Bellinger <nab@linux-iscsi.org>
parent cd063bef
...@@ -676,6 +676,9 @@ SE_DEV_ATTR(unmap_granularity, S_IRUGO | S_IWUSR); ...@@ -676,6 +676,9 @@ SE_DEV_ATTR(unmap_granularity, S_IRUGO | S_IWUSR);
DEF_DEV_ATTRIB(unmap_granularity_alignment); DEF_DEV_ATTRIB(unmap_granularity_alignment);
SE_DEV_ATTR(unmap_granularity_alignment, S_IRUGO | S_IWUSR); 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); CONFIGFS_EATTR_OPS(target_core_dev_attrib, se_dev_attrib, da_group);
static struct configfs_attribute *target_core_dev_attrib_attrs[] = { static struct configfs_attribute *target_core_dev_attrib_attrs[] = {
...@@ -701,6 +704,7 @@ 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_max_unmap_block_desc_count.attr,
&target_core_dev_attrib_unmap_granularity.attr, &target_core_dev_attrib_unmap_granularity.attr,
&target_core_dev_attrib_unmap_granularity_alignment.attr, &target_core_dev_attrib_unmap_granularity_alignment.attr,
&target_core_dev_attrib_max_write_same_len.attr,
NULL, NULL,
}; };
......
...@@ -706,6 +706,16 @@ int se_dev_set_unmap_granularity_alignment( ...@@ -706,6 +706,16 @@ int se_dev_set_unmap_granularity_alignment(
return 0; 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) int se_dev_set_emulate_dpo(struct se_device *dev, int flag)
{ {
if (flag != 0 && flag != 1) { if (flag != 0 && flag != 1) {
...@@ -1393,6 +1403,7 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name) ...@@ -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 = DA_UNMAP_GRANULARITY_DEFAULT;
dev->dev_attrib.unmap_granularity_alignment = dev->dev_attrib.unmap_granularity_alignment =
DA_UNMAP_GRANULARITY_ALIGNMENT_DEFAULT; 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.fabric_max_sectors = DA_FABRIC_MAX_SECTORS;
dev->dev_attrib.optimal_sectors = DA_FABRIC_MAX_SECTORS; dev->dev_attrib.optimal_sectors = DA_FABRIC_MAX_SECTORS;
......
...@@ -24,6 +24,7 @@ int se_dev_set_max_unmap_lba_count(struct se_device *, u32); ...@@ -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_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(struct se_device *, u32);
int se_dev_set_unmap_granularity_alignment(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_dpo(struct se_device *, int);
int se_dev_set_emulate_fua_write(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); int se_dev_set_emulate_fua_read(struct se_device *, int);
......
...@@ -238,12 +238,19 @@ static inline unsigned long long transport_lba_64_ext(unsigned char *cdb) ...@@ -238,12 +238,19 @@ static inline unsigned long long transport_lba_64_ext(unsigned char *cdb)
static sense_reason_t static sense_reason_t
sbc_setup_write_same(struct se_cmd *cmd, unsigned char *flags, struct sbc_ops *ops) 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)) { if ((flags[0] & 0x04) || (flags[0] & 0x02)) {
pr_err("WRITE_SAME PBDATA and LBDATA" pr_err("WRITE_SAME PBDATA and LBDATA"
" bits not supported for Block Discard" " bits not supported for Block Discard"
" Emulation\n"); " Emulation\n");
return TCM_UNSUPPORTED_SCSI_OPCODE; 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 * Special case for WRITE_SAME w/ UNMAP=1 that ends up getting
* translated into block discard requests within backend code. * translated into block discard requests within backend code.
......
...@@ -465,7 +465,7 @@ spc_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf) ...@@ -465,7 +465,7 @@ spc_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf)
* Exit now if we don't support TP. * Exit now if we don't support TP.
*/ */
if (!have_tp) if (!have_tp)
return 0; goto max_write_same;
/* /*
* Set MAXIMUM UNMAP LBA COUNT * Set MAXIMUM UNMAP LBA COUNT
...@@ -491,6 +491,12 @@ spc_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf) ...@@ -491,6 +491,12 @@ spc_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf)
if (dev->dev_attrib.unmap_granularity_alignment != 0) if (dev->dev_attrib.unmap_granularity_alignment != 0)
buf[32] |= 0x80; /* Set the UGAVALID bit */ 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; return 0;
} }
......
...@@ -71,6 +71,8 @@ ...@@ -71,6 +71,8 @@
#define DA_UNMAP_GRANULARITY_DEFAULT 0 #define DA_UNMAP_GRANULARITY_DEFAULT 0
/* Default unmap_granularity_alignment */ /* Default unmap_granularity_alignment */
#define DA_UNMAP_GRANULARITY_ALIGNMENT_DEFAULT 0 #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 */ /* Default max transfer length */
#define DA_FABRIC_MAX_SECTORS 8192 #define DA_FABRIC_MAX_SECTORS 8192
/* Emulation for Direct Page Out */ /* Emulation for Direct Page Out */
...@@ -609,6 +611,7 @@ struct se_dev_attrib { ...@@ -609,6 +611,7 @@ struct se_dev_attrib {
u32 max_unmap_block_desc_count; u32 max_unmap_block_desc_count;
u32 unmap_granularity; u32 unmap_granularity;
u32 unmap_granularity_alignment; u32 unmap_granularity_alignment;
u32 max_write_same_len;
struct se_device *da_dev; struct se_device *da_dev;
struct config_group da_group; struct config_group da_group;
}; };
......
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