scst_vdisk: Make vendor, product ID and related fields configurable via sysfs

Signed-off-by: Bart Van Assche <bvanassche@acm.org>



git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@5316 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2014-02-26 02:49:38 +00:00
parent d59230f2fd
commit 312c7d85d6
6 changed files with 459 additions and 90 deletions
+11
View File
@@ -32,6 +32,17 @@ more information):
2:0:0:0 ram000 ram001 ram002 ram003 ram004 ram005 ram006 ram007
ram008 ram009 ram010 ram011 ram012 ram013 ram014 ram015
Next, set the vendor ID, product ID etc. fields via sysfs. These fields
must be set to the following values to allow AIX initiators to recognize
SCST devices:
* The Vendor ID (t10_vend_id) must be set to "IBM".
* The Product ID (prod_id) must be set either to "VDASD blkdev" for SCSI disks
or "VOPTA blkdev" for a SCSI CD-ROM.
* The Product Revision Level (prod_rev_lvl) must be set to "0001".
* The Vendor Specific Information in the INQUIRY response (inq_vend_specific)
must be set to the serial number. The serial number is available in the
"usn" sysfs attribute.
After this step a LUN has to be assigned to each exported SCSI device. Some
non-Linux initiator operating systems only accept LUN numbes that are
multiples of 256 and require that the LUN addressing method is used.
-26
View File
@@ -1069,28 +1069,6 @@ static void handle_crq(struct work_struct *work)
}
}
static void ibmvstgt_get_product_id(const struct scst_tgt_dev *tgt_dev,
char *buf, const int size)
{
WARN_ON(size != 16);
/*
* AIX uses hardcoded device names. The AIX SCSI initiator even won't
* work unless we use the names VDASD and VOPTA.
*/
switch (tgt_dev->dev->type) {
case TYPE_DISK:
memcpy(buf, "VDASD blkdev ", 16);
break;
case TYPE_ROM:
memcpy(buf, "VOPTA blkdev ", 16);
break;
default:
snprintf(buf, size, "(devtype %d) ", tgt_dev->dev->type);
break;
}
}
/*
* Extract target, bus and LUN information from a 64-bit LUN in CPU-order.
*/
@@ -1236,12 +1214,8 @@ static struct scst_tgt_template ibmvstgt_template = {
#else
.sg_tablesize = SCSI_MAX_SG_SEGMENTS,
#endif
.vendor = "IBM ",
.revision = "0001",
.fake_aca = true,
.get_product_id = ibmvstgt_get_product_id,
.get_serial = ibmvstgt_get_serial,
.get_vend_specific = ibmvstgt_get_serial,
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
.default_trace_flags = DEFAULT_IBMVSTGT_TRACE_FLAGS,
+18
View File
@@ -953,8 +953,18 @@ Each vdisk_fileio's device has the following attributes in
- o_direct - contains O_DIRECT status of this virtual device.
- inq_vend_specific - Vendor specific data that will be reported via
either bytes 36..55 or bytes 96..256 of the INQUIRY response, depending
on whether this field is <= 20 or > 20 bytes long.
- nv_cache - contains NV_CACHE status of this virtual device.
- prod_id - PRODUCT IDENTIFICATION as reported via the INQUIRY response.
The default value for this field is the SCST device name.
- prod_rev_lvl - PRODUCT REVISION LEVEL as reported via the INQUIRY
response. The default value for this field is " 300".
- thin_provisioned - contains thin provisioning status of this virtual
device.
@@ -975,6 +985,10 @@ Each vdisk_fileio's device has the following attributes in
that these first eight characters are unique or VMware will consider
these devices as identical.
- t10_vend_id - Contents of the T10 VENDOR IDENTIFICATION field of the
INQUIRY response. The default value for this field is "SCST_BIO" for
vdisk_block devices and "SCST_FIO" for vdisk_fileio devices.
- usn - contains the virtual device's serial number of INQUIRY data. It
is created at the device creation time based on the device name and
scst_vdisk_ID scst_vdisk.ko module parameter for procfs (see below)
@@ -986,6 +1000,10 @@ Each vdisk_fileio's device has the following attributes in
rescan size of the backend file. It is useful if you changed it, for
instance, if you resized it.
- vend_specific_id - Vendor specific ID as reported via the Device
Identification VPD page (83h). The default value for this attribute
is the value of the t10_dev_id attribute.
For example:
/sys/kernel/scst_tgt/devices/disk1
+18
View File
@@ -811,8 +811,18 @@ Each vdisk_fileio's device has the following attributes in
- o_direct - contains O_DIRECT status of this virtual device.
- inq_vend_specific - Vendor specific data that will be reported via
either bytes 36..55 or bytes 96..256 of the INQUIRY response, depending
on whether this field is <= 20 or > 20 bytes long.
- nv_cache - contains NV_CACHE status of this virtual device.
- prod_id - PRODUCT IDENTIFICATION as reported via the INQUIRY response.
The default value for this field is the SCST device name.
- prod_rev_lvl - PRODUCT REVISION LEVEL as reported via the INQUIRY
response. The default value for this field is " 300".
- thin_provisioned - contains thin provisioning status of this virtual
device.
@@ -828,6 +838,10 @@ Each vdisk_fileio's device has the following attributes in
created device at creation time based on the device name and
scst_vdisk_ID scst_vdisk.ko module parameter (see below).
- t10_vend_id - Contents of the T10 VENDOR IDENTIFICATION field of the
INQUIRY response. The default value for this field is "SCST_BIO" for
vdisk_block devices and "SCST_FIO" for vdisk_fileio devices.
- usn - contains the virtual device's serial number of INQUIRY data. It
is created at the device creation time based on the device name and
scst_vdisk_ID scst_vdisk.ko module parameter (see below).
@@ -838,6 +852,10 @@ Each vdisk_fileio's device has the following attributes in
rescan size of the backend file. It is useful if you changed it, for
instance, if you resized it.
- vend_specific_id - Vendor specific ID as reported via the Device
Identification VPD page (83h). The default value for this attribute
is the value of the t10_dev_id attribute.
For example:
/sys/kernel/scst_tgt/devices/disk1
-30
View File
@@ -1156,29 +1156,6 @@ struct scst_tgt_template {
struct completion *tgtt_kobj_release_cmpl;
#endif
/*
* Optional vendor to be reported via the SCSI inquiry data. If NULL,
* an SCST device handler specific default value will be used, e.g.
* "SCST_FIO" for scst_vdisk file I/O.
*/
const char *vendor;
/*
* Optional method that sets the product ID in [buf, buf+size) based
* on the device type (byte 0 of the SCSI inquiry data, which contains
* the peripheral qualifier in the highest three bits and the
* peripheral device type in the lower five bits).
*/
void (*get_product_id)(const struct scst_tgt_dev *tgt_dev,
char *buf, int size);
/*
* Optional revision to be reported in the SCSI inquiry response. If
* NULL, an SCST device handler specific default value will be used,
* e.g. " 210" for scst_vdisk file I/O.
*/
const char *revision;
/*
* Optional method that writes the serial number of a target device in
* [buf, buf+size) and returns the number of bytes written.
@@ -1192,13 +1169,6 @@ struct scst_tgt_template {
*/
int (*get_serial)(const struct scst_tgt_dev *tgt_dev, char *buf,
int size);
/*
* Optional method that writes the SCSI inquiry vendor-specific data in
* [buf, buf+size) and returns the number of bytes written.
*/
int (*get_vend_specific)(const struct scst_tgt_dev *tgt_dev, char *buf,
int size);
};
/*
+412 -34
View File
@@ -82,6 +82,7 @@ static struct scst_trace_log vdisk_local_trace_tbl[] = {
#define SCST_FIO_REV " 300"
#define MAX_USN_LEN (20+1) /* For '\0' */
#define MAX_INQ_VEND_SPECIFIC_LEN (INQ_BUF_SZ - 96)
#define INQ_BUF_SZ 256
#define EVPD 0x01
@@ -175,11 +176,22 @@ struct scst_vdisk_dev {
scst_mutex and suspended activities */
uint16_t command_set_version;
/* All 4 protected by vdisk_serial_rwlock */
/* All 14 protected by vdisk_serial_rwlock */
unsigned int t10_vend_id_set:1; /* true if t10_vend_id manually set */
/* true if vend_specific_id manually set */
unsigned int vend_specific_id_set:1;
unsigned int prod_id_set:1; /* true if prod_id manually set */
unsigned int prod_rev_lvl_set:1; /* true if prod_rev_lvl manually set */
unsigned int t10_dev_id_set:1; /* true if t10_dev_id manually set */
unsigned int usn_set:1; /* true if usn manually set */
char t10_vend_id[8 + 1];
char vend_specific_id[32 + 1];
char prod_id[16 + 1];
char prod_rev_lvl[4 + 1];
char t10_dev_id[16+8+2]; /* T10 device ID */
char usn[MAX_USN_LEN];
uint8_t inq_vend_specific[MAX_INQ_VEND_SPECIFIC_LEN];
int inq_vend_specific_len;
struct scst_device *dev;
struct list_head vdev_list_entry;
@@ -319,6 +331,22 @@ static ssize_t vdev_sysfs_filename_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf);
static ssize_t vdisk_sysfs_resync_size_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count);
static ssize_t vdev_sysfs_t10_vend_id_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count);
static ssize_t vdev_sysfs_t10_vend_id_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf);
static ssize_t vdev_sysfs_vend_specific_id_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count);
static ssize_t vdev_sysfs_vend_specific_id_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf);
static ssize_t vdev_sysfs_prod_id_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count);
static ssize_t vdev_sysfs_prod_id_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf);
static ssize_t vdev_sysfs_prod_rev_lvl_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count);
static ssize_t vdev_sysfs_prod_rev_lvl_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf);
static ssize_t vdev_sysfs_t10_dev_id_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count);
static ssize_t vdev_sysfs_t10_dev_id_show(struct kobject *kobj,
@@ -327,6 +355,10 @@ static ssize_t vdev_sysfs_usn_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count);
static ssize_t vdev_sysfs_usn_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf);
static ssize_t vdev_sysfs_inq_vend_specific_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count);
static ssize_t vdev_sysfs_inq_vend_specific_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf);
static ssize_t vdev_zero_copy_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf);
@@ -357,11 +389,28 @@ static struct kobj_attribute vdisk_filename_attr =
__ATTR(filename, S_IRUGO, vdev_sysfs_filename_show, NULL);
static struct kobj_attribute vdisk_resync_size_attr =
__ATTR(resync_size, S_IWUSR, NULL, vdisk_sysfs_resync_size_store);
static struct kobj_attribute vdev_t10_vend_id_attr =
__ATTR(t10_vend_id, S_IWUSR|S_IRUGO, vdev_sysfs_t10_vend_id_show,
vdev_sysfs_t10_vend_id_store);
static struct kobj_attribute vdev_vend_specific_id_attr =
__ATTR(vend_specific_id, S_IWUSR|S_IRUGO,
vdev_sysfs_vend_specific_id_show,
vdev_sysfs_vend_specific_id_store);
static struct kobj_attribute vdev_prod_id_attr =
__ATTR(prod_id, S_IWUSR|S_IRUGO, vdev_sysfs_prod_id_show,
vdev_sysfs_prod_id_store);
static struct kobj_attribute vdev_prod_rev_lvl_attr =
__ATTR(prod_rev_lvl, S_IWUSR|S_IRUGO, vdev_sysfs_prod_rev_lvl_show,
vdev_sysfs_prod_rev_lvl_store);
static struct kobj_attribute vdev_t10_dev_id_attr =
__ATTR(t10_dev_id, S_IWUSR|S_IRUGO, vdev_sysfs_t10_dev_id_show,
vdev_sysfs_t10_dev_id_store);
static struct kobj_attribute vdev_usn_attr =
__ATTR(usn, S_IWUSR|S_IRUGO, vdev_sysfs_usn_show, vdev_sysfs_usn_store);
static struct kobj_attribute vdev_inq_vend_specific_attr =
__ATTR(inq_vend_specific, S_IWUSR|S_IRUGO,
vdev_sysfs_inq_vend_specific_show,
vdev_sysfs_inq_vend_specific_store);
static struct kobj_attribute vdev_zero_copy_attr =
__ATTR(zero_copy, S_IRUGO, vdev_zero_copy_show, NULL);
@@ -381,8 +430,13 @@ static const struct attribute *vdisk_fileio_attrs[] = {
&vdisk_removable_attr.attr,
&vdisk_filename_attr.attr,
&vdisk_resync_size_attr.attr,
&vdev_t10_vend_id_attr.attr,
&vdev_vend_specific_id_attr.attr,
&vdev_prod_id_attr.attr,
&vdev_prod_rev_lvl_attr.attr,
&vdev_t10_dev_id_attr.attr,
&vdev_usn_attr.attr,
&vdev_inq_vend_specific_attr.attr,
&vdev_zero_copy_attr.attr,
NULL,
};
@@ -397,8 +451,13 @@ static const struct attribute *vdisk_blockio_attrs[] = {
&vdisk_rotational_attr.attr,
&vdisk_filename_attr.attr,
&vdisk_resync_size_attr.attr,
&vdev_t10_vend_id_attr.attr,
&vdev_vend_specific_id_attr.attr,
&vdev_prod_id_attr.attr,
&vdev_prod_rev_lvl_attr.attr,
&vdev_t10_dev_id_attr.attr,
&vdev_usn_attr.attr,
&vdev_inq_vend_specific_attr.attr,
&vdisk_tp_attr.attr,
NULL,
};
@@ -409,8 +468,13 @@ static const struct attribute *vdisk_nullio_attrs[] = {
&vdisk_rd_only_attr.attr,
&vdev_dummy_attr.attr,
&vdisk_removable_attr.attr,
&vdev_t10_vend_id_attr.attr,
&vdev_vend_specific_id_attr.attr,
&vdev_prod_id_attr.attr,
&vdev_prod_rev_lvl_attr.attr,
&vdev_t10_dev_id_attr.attr,
&vdev_usn_attr.attr,
&vdev_inq_vend_specific_attr.attr,
&vdisk_rotational_attr.attr,
NULL,
};
@@ -418,8 +482,13 @@ static const struct attribute *vdisk_nullio_attrs[] = {
static const struct attribute *vcdrom_attrs[] = {
&vdev_size_attr.attr,
&vcdrom_filename_attr.attr,
&vdev_t10_vend_id_attr.attr,
&vdev_vend_specific_id_attr.attr,
&vdev_prod_id_attr.attr,
&vdev_prod_rev_lvl_attr.attr,
&vdev_t10_dev_id_attr.attr,
&vdev_usn_attr.attr,
&vdev_inq_vend_specific_attr.attr,
NULL,
};
@@ -428,7 +497,10 @@ static const struct attribute *vcdrom_attrs[] = {
/* Protects vdisks addition/deletion and related activities, like search */
static DEFINE_MUTEX(scst_vdisk_mutex);
/* Protects devices t10_dev_id and usn */
/*
* Protects the device attributes t10_vend_id, vend_specific_id, prod_id,
* prod_rev_lvl, t10_dev_id, usn and inq_vend_specific.
*/
static DEFINE_RWLOCK(vdisk_serial_rwlock);
/* Protected by scst_vdisk_mutex */
@@ -2235,6 +2307,28 @@ out:
return;
}
/*
* Copy a zero-terminated string into a fixed-size byte array and fill the
* trailing bytes with @fill_byte.
*/
static void scst_copy_and_fill_b(char *dst, const char *src, int len,
uint8_t fill_byte)
{
int cpy_len = min_t(int, strlen(src), len);
memcpy(dst, src, cpy_len);
memset(dst + cpy_len, fill_byte, len - cpy_len);
}
/*
* Copy a zero-terminated string into a fixed-size char array and fill the
* trailing characters with spaces.
*/
static void scst_copy_and_fill(char *dst, const char *src, int len)
{
scst_copy_and_fill_b(dst, src, len, ' ');
}
static enum compl_status_e vdisk_exec_write_same(struct vdisk_cmd_params *p)
{
struct scst_cmd *cmd = p->cmd;
@@ -2445,16 +2539,10 @@ static enum compl_status_e vdisk_exec_inquiry(struct vdisk_cmd_params *p)
/* T10 vendor identifier field format (faked) */
buf[num + 0] = 0x2; /* ASCII */
buf[num + 1] = 0x1; /* Vendor ID */
if (cmd->tgtt->vendor)
memcpy(&buf[num + 4], cmd->tgtt->vendor, 8);
else if (virt_dev->blockio)
memcpy(&buf[num + 4], SCST_BIO_VENDOR, 8);
else
memcpy(&buf[num + 4], SCST_FIO_VENDOR, 8);
read_lock(&vdisk_serial_rwlock);
i = strlen(virt_dev->t10_dev_id);
memcpy(&buf[num + 12], virt_dev->t10_dev_id, i);
scst_copy_and_fill(&buf[num + 4], virt_dev->t10_vend_id, 8);
i = strlen(virt_dev->vend_specific_id);
memcpy(&buf[num + 12], virt_dev->vend_specific_id, i);
read_unlock(&vdisk_serial_rwlock);
buf[num + 3] = 8 + i;
@@ -2608,7 +2696,7 @@ static enum compl_status_e vdisk_exec_inquiry(struct vdisk_cmd_params *p)
goto out_put;
}
} else {
int len, num;
int num;
if (cmd->cdb[2] != 0) {
TRACE_DBG("INQUIRY: Unsupported page %x", cmd->cdb[2]);
@@ -2628,37 +2716,30 @@ static enum compl_status_e vdisk_exec_inquiry(struct vdisk_cmd_params *p)
buf[6] = 0x10; /* MultiP 1 */
buf[7] = 2; /* CMDQUE 1, BQue 0 => commands queuing supported */
read_lock(&vdisk_serial_rwlock);
/*
* 8 byte ASCII Vendor Identification of the target
* - left aligned.
*/
if (cmd->tgtt->vendor)
memcpy(&buf[8], cmd->tgtt->vendor, 8);
else if (virt_dev->blockio)
memcpy(&buf[8], SCST_BIO_VENDOR, 8);
else
memcpy(&buf[8], SCST_FIO_VENDOR, 8);
scst_copy_and_fill(&buf[8], virt_dev->t10_vend_id, 8);
/*
* 16 byte ASCII Product Identification of the target - left
* aligned.
*/
memset(&buf[16], ' ', 16);
if (cmd->tgtt->get_product_id)
cmd->tgtt->get_product_id(cmd->tgt_dev, &buf[16], 16);
else {
len = min_t(size_t, strlen(virt_dev->name), 16);
memcpy(&buf[16], virt_dev->name, len);
}
scst_copy_and_fill(&buf[16], virt_dev->prod_id, 16);
/*
* 4 byte ASCII Product Revision Level of the target - left
* aligned.
*/
if (cmd->tgtt->revision)
memcpy(&buf[32], cmd->tgtt->revision, 4);
else
memcpy(&buf[32], SCST_FIO_REV, 4);
scst_copy_and_fill(&buf[32], virt_dev->prod_rev_lvl, 4);
/* Vendor specific information. */
if (virt_dev->inq_vend_specific_len <= 20)
memcpy(&buf[36], virt_dev->inq_vend_specific,
virt_dev->inq_vend_specific_len);
/** Version descriptors **/
@@ -2699,13 +2780,14 @@ static enum compl_status_e vdisk_exec_inquiry(struct vdisk_cmd_params *p)
}
/* Vendor specific information. */
if (cmd->tgtt->get_vend_specific) {
/* Skip to byte 96. */
num = 96 - 58;
num += cmd->tgtt->get_vend_specific(cmd->tgt_dev,
&buf[96], INQ_BUF_SZ - 96);
if (virt_dev->inq_vend_specific_len > 20) {
memcpy(&buf[96], virt_dev->inq_vend_specific,
virt_dev->inq_vend_specific_len);
num = 96 - 58 + virt_dev->inq_vend_specific_len;
}
read_unlock(&vdisk_serial_rwlock);
buf[4] += num;
resp_len = buf[4] + 5;
}
@@ -4640,6 +4722,20 @@ static int vdev_create(struct scst_dev_type *devt,
"%llx-%s", dev_id_num, virt_dev->name);
TRACE_DBG("t10_dev_id %s", virt_dev->t10_dev_id);
sprintf(virt_dev->t10_vend_id, "%.*s",
(int)(sizeof(virt_dev->t10_vend_id) - 1),
virt_dev->blockio ? SCST_BIO_VENDOR : SCST_FIO_VENDOR);
sprintf(virt_dev->vend_specific_id, "%.*s",
(int)(sizeof(virt_dev->vend_specific_id) - 1),
virt_dev->t10_dev_id);
sprintf(virt_dev->prod_id, "%.*s", (int)(sizeof(virt_dev->prod_id) - 1),
virt_dev->name);
sprintf(virt_dev->prod_rev_lvl, "%.*s",
(int)(sizeof(virt_dev->prod_rev_lvl) - 1), SCST_FIO_REV);
scnprintf(virt_dev->usn, sizeof(virt_dev->usn), "%llx", dev_id_num);
TRACE_DBG("usn %s", virt_dev->usn);
@@ -5739,6 +5835,239 @@ out:
return res;
}
static ssize_t vdev_sysfs_t10_vend_id_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t count)
{
struct scst_device *dev;
struct scst_vdisk_dev *virt_dev;
char *p;
int res, len;
TRACE_ENTRY();
dev = container_of(kobj, struct scst_device, dev_kobj);
virt_dev = dev->dh_priv;
p = memchr(buf, '\n', count);
len = p ? p - buf : count;
if (len >= sizeof(virt_dev->t10_vend_id)) {
PRINT_ERROR("T10 vendor id is too long (max %zd characters)",
sizeof(virt_dev->t10_vend_id));
res = -EINVAL;
goto out;
}
write_lock(&vdisk_serial_rwlock);
sprintf(virt_dev->t10_vend_id, "%.*s", len, buf);
virt_dev->t10_vend_id_set = 1;
write_unlock(&vdisk_serial_rwlock);
res = count;
out:
TRACE_EXIT_RES(res);
return res;
}
static ssize_t vdev_sysfs_t10_vend_id_show(struct kobject *kobj,
struct kobj_attribute *attr,
char *buf)
{
int pos;
struct scst_device *dev;
struct scst_vdisk_dev *virt_dev;
TRACE_ENTRY();
dev = container_of(kobj, struct scst_device, dev_kobj);
virt_dev = dev->dh_priv;
read_lock(&vdisk_serial_rwlock);
pos = sprintf(buf, "%s\n%s", virt_dev->t10_vend_id,
virt_dev->t10_vend_id_set ? SCST_SYSFS_KEY_MARK "\n" :
"");
read_unlock(&vdisk_serial_rwlock);
TRACE_EXIT_RES(pos);
return pos;
}
static ssize_t vdev_sysfs_vend_specific_id_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t count)
{
struct scst_device *dev;
struct scst_vdisk_dev *virt_dev;
char *p;
int res, len;
TRACE_ENTRY();
dev = container_of(kobj, struct scst_device, dev_kobj);
virt_dev = dev->dh_priv;
p = memchr(buf, '\n', count);
len = p ? p - buf : count;
if (len >= sizeof(virt_dev->vend_specific_id)) {
PRINT_ERROR("Vendor specific id is too long (max %zd"
" characters)",
sizeof(virt_dev->vend_specific_id) - 1);
res = -EINVAL;
goto out;
}
write_lock(&vdisk_serial_rwlock);
sprintf(virt_dev->vend_specific_id, "%.*s", len, buf);
virt_dev->vend_specific_id_set = 1;
write_unlock(&vdisk_serial_rwlock);
res = count;
out:
TRACE_EXIT_RES(res);
return res;
}
static ssize_t vdev_sysfs_vend_specific_id_show(struct kobject *kobj,
struct kobj_attribute *attr,
char *buf)
{
int pos;
struct scst_device *dev;
struct scst_vdisk_dev *virt_dev;
TRACE_ENTRY();
dev = container_of(kobj, struct scst_device, dev_kobj);
virt_dev = dev->dh_priv;
read_lock(&vdisk_serial_rwlock);
pos = sprintf(buf, "%s\n%s", virt_dev->vend_specific_id,
virt_dev->vend_specific_id_set ?
SCST_SYSFS_KEY_MARK "\n" : "");
read_unlock(&vdisk_serial_rwlock);
TRACE_EXIT_RES(pos);
return pos;
}
static ssize_t vdev_sysfs_prod_id_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t count)
{
struct scst_device *dev;
struct scst_vdisk_dev *virt_dev;
char *p;
int res, len;
TRACE_ENTRY();
dev = container_of(kobj, struct scst_device, dev_kobj);
virt_dev = dev->dh_priv;
p = memchr(buf, '\n', count);
len = p ? p - buf : count;
if (len >= sizeof(virt_dev->prod_id)) {
PRINT_ERROR("Product id is too long (max %zd characters)",
sizeof(virt_dev->prod_id));
res = -EINVAL;
goto out;
}
write_lock(&vdisk_serial_rwlock);
sprintf(virt_dev->prod_id, "%.*s", len, buf);
virt_dev->prod_id_set = 1;
write_unlock(&vdisk_serial_rwlock);
res = count;
out:
TRACE_EXIT_RES(res);
return res;
}
static ssize_t vdev_sysfs_prod_id_show(struct kobject *kobj,
struct kobj_attribute *attr,
char *buf)
{
int pos;
struct scst_device *dev;
struct scst_vdisk_dev *virt_dev;
TRACE_ENTRY();
dev = container_of(kobj, struct scst_device, dev_kobj);
virt_dev = dev->dh_priv;
read_lock(&vdisk_serial_rwlock);
pos = sprintf(buf, "%s\n%s", virt_dev->prod_id,
virt_dev->prod_id_set ? SCST_SYSFS_KEY_MARK "\n" : "");
read_unlock(&vdisk_serial_rwlock);
TRACE_EXIT_RES(pos);
return pos;
}
static ssize_t vdev_sysfs_prod_rev_lvl_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t count)
{
struct scst_device *dev;
struct scst_vdisk_dev *virt_dev;
char *p;
int res, len;
TRACE_ENTRY();
dev = container_of(kobj, struct scst_device, dev_kobj);
virt_dev = dev->dh_priv;
p = memchr(buf, '\n', count);
len = p ? p - buf : count;
if (len >= sizeof(virt_dev->prod_rev_lvl)) {
PRINT_ERROR("Product revision level is too long (max %zd"
" characters)",
sizeof(virt_dev->prod_rev_lvl));
res = -EINVAL;
goto out;
}
write_lock(&vdisk_serial_rwlock);
sprintf(virt_dev->prod_rev_lvl, "%.*s", len, buf);
virt_dev->prod_rev_lvl_set = 1;
write_unlock(&vdisk_serial_rwlock);
res = count;
out:
TRACE_EXIT_RES(res);
return res;
}
static ssize_t vdev_sysfs_prod_rev_lvl_show(struct kobject *kobj,
struct kobj_attribute *attr,
char *buf)
{
int pos;
struct scst_device *dev;
struct scst_vdisk_dev *virt_dev;
TRACE_ENTRY();
dev = container_of(kobj, struct scst_device, dev_kobj);
virt_dev = dev->dh_priv;
read_lock(&vdisk_serial_rwlock);
pos = sprintf(buf, "%s\n%s", virt_dev->prod_rev_lvl,
virt_dev->prod_rev_lvl_set ? SCST_SYSFS_KEY_MARK "\n" :
"");
read_unlock(&vdisk_serial_rwlock);
TRACE_EXIT_RES(pos);
return pos;
}
static ssize_t vdev_sysfs_t10_dev_id_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count)
{
@@ -5879,6 +6208,55 @@ static ssize_t vdev_sysfs_usn_show(struct kobject *kobj,
return pos;
}
static ssize_t vdev_sysfs_inq_vend_specific_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t count)
{
struct scst_device *dev;
struct scst_vdisk_dev *virt_dev;
char *p;
int res = -EINVAL, len;
dev = container_of(kobj, struct scst_device, dev_kobj);
virt_dev = dev->dh_priv;
p = memchr(buf, '\n', count);
len = p ? p - buf : count;
if (len > MAX_INQ_VEND_SPECIFIC_LEN)
goto out;
write_lock(&vdisk_serial_rwlock);
memcpy(virt_dev->inq_vend_specific, buf, len);
virt_dev->inq_vend_specific_len = len;
write_unlock(&vdisk_serial_rwlock);
res = count;
out:
return res;
}
static ssize_t vdev_sysfs_inq_vend_specific_show(struct kobject *kobj,
struct kobj_attribute *attr,
char *buf)
{
int pos;
struct scst_device *dev;
struct scst_vdisk_dev *virt_dev;
dev = container_of(kobj, struct scst_device, dev_kobj);
virt_dev = dev->dh_priv;
read_lock(&vdisk_serial_rwlock);
pos = snprintf(buf, PAGE_SIZE, "%.*s\n%s",
virt_dev->inq_vend_specific_len,
virt_dev->inq_vend_specific,
virt_dev->inq_vend_specific_len ?
SCST_SYSFS_KEY_MARK "\n" : "");
read_unlock(&vdisk_serial_rwlock);
return pos;
}
static ssize_t vdev_zero_copy_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{