mirror of
https://github.com/SCST-project/scst.git
synced 2026-08-19 13:46:25 +00:00
Patch from Bart Van Assche <bvanassche@acm.org> with some changes implementing additional hooks to allow target drivers to override INQUIRY responses and support for LUNs addressing method.
git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@2649 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
+55
-1
@@ -640,6 +640,18 @@ struct scst_tgt_template {
|
||||
unsigned enabled_attr_not_needed:1;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* True if SCST should report that it supports ACA although it does
|
||||
* not yet support ACA. Necessary for the IBM virtual SCSI target
|
||||
* driver.
|
||||
*/
|
||||
unsigned fake_aca:1;
|
||||
|
||||
/*
|
||||
* Preferred SCSI LUN addressing method.
|
||||
*/
|
||||
enum scst_lun_addr_method preferred_addr_method;
|
||||
|
||||
/*
|
||||
* The maximum time in seconds cmd can stay inside the target
|
||||
* hardware, i.e. after rdy_to_xfer() and xmit_response(), before
|
||||
@@ -1036,6 +1048,48 @@ struct scst_tgt_template {
|
||||
/* Device number in /proc */
|
||||
int proc_dev_num;
|
||||
#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.
|
||||
*
|
||||
* Note: SCST can be configured such that a device can be accessed
|
||||
* from several different transports at the same time. It is important
|
||||
* that all clients see the same USN for proper operation. Overriding
|
||||
* the serial number can lead to subtle misbehavior.
|
||||
*/
|
||||
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);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -2441,7 +2495,7 @@ struct scst_acg {
|
||||
struct kobject *luns_kobj;
|
||||
struct kobject *initiators_kobj;
|
||||
|
||||
unsigned int addr_method;
|
||||
enum scst_lun_addr_method addr_method;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -134,6 +134,17 @@
|
||||
#define SCST_MGMT_STATUS_REJECTED -255
|
||||
#define SCST_MGMT_STATUS_FAILED -129
|
||||
|
||||
/*************************************************************
|
||||
** SCSI LUN addressing methods. See also SAM-2 and the
|
||||
** section about eight byte LUNs.
|
||||
*************************************************************/
|
||||
enum scst_lun_addr_method {
|
||||
SCST_LUN_ADDR_METHOD_PERIPHERAL = 0,
|
||||
SCST_LUN_ADDR_METHOD_FLAT = 1,
|
||||
SCST_LUN_ADDR_METHOD_LUN = 2,
|
||||
SCST_LUN_ADDR_METHOD_EXTENDED_LUN = 3,
|
||||
};
|
||||
|
||||
/*************************************************************
|
||||
** SCSI task attribute queue types
|
||||
*************************************************************/
|
||||
|
||||
@@ -1489,10 +1489,15 @@ static void vdisk_exec_inquiry(struct scst_cmd *cmd)
|
||||
resp_len = buf[3] + 4;
|
||||
} else if (0x80 == cmd->cdb[2]) {
|
||||
/* unit serial number */
|
||||
int usn_len = strlen(virt_dev->usn);
|
||||
buf[1] = 0x80;
|
||||
buf[3] = usn_len;
|
||||
strncpy(&buf[4], virt_dev->usn, usn_len);
|
||||
if (cmd->tgtt->get_serial) {
|
||||
buf[3] = cmd->tgtt->get_serial(cmd->tgt_dev,
|
||||
&buf[4], INQ_BUF_SZ - 4);
|
||||
} else {
|
||||
int usn_len = strlen(virt_dev->usn);
|
||||
buf[3] = usn_len;
|
||||
strncpy(&buf[4], virt_dev->usn, usn_len);
|
||||
}
|
||||
resp_len = buf[3] + 4;
|
||||
} else if (0x83 == cmd->cdb[2]) {
|
||||
/* device identification */
|
||||
@@ -1502,7 +1507,9 @@ static void vdisk_exec_inquiry(struct scst_cmd *cmd)
|
||||
/* T10 vendor identifier field format (faked) */
|
||||
buf[num + 0] = 0x2; /* ASCII */
|
||||
buf[num + 1] = 0x1; /* Vendor ID */
|
||||
if (virt_dev->blockio)
|
||||
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);
|
||||
@@ -1633,7 +1640,9 @@ static void vdisk_exec_inquiry(struct scst_cmd *cmd)
|
||||
* 8 byte ASCII Vendor Identification of the target
|
||||
* - left aligned.
|
||||
*/
|
||||
if (virt_dev->blockio)
|
||||
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);
|
||||
@@ -1643,14 +1652,21 @@ static void vdisk_exec_inquiry(struct scst_cmd *cmd)
|
||||
* aligned.
|
||||
*/
|
||||
memset(&buf[16], ' ', 16);
|
||||
len = min(strlen(virt_dev->name), (size_t)16);
|
||||
memcpy(&buf[16], virt_dev->name, len);
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 4 byte ASCII Product Revision Level of the target - left
|
||||
* aligned.
|
||||
*/
|
||||
memcpy(&buf[32], SCST_FIO_REV, 4);
|
||||
if (cmd->tgtt->revision)
|
||||
memcpy(&buf[32], cmd->tgtt->revision, 4);
|
||||
else
|
||||
memcpy(&buf[32], SCST_FIO_REV, 4);
|
||||
|
||||
/** Version descriptors **/
|
||||
|
||||
@@ -1690,6 +1706,14 @@ static void vdisk_exec_inquiry(struct scst_cmd *cmd)
|
||||
num += 2;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
buf[4] += num;
|
||||
resp_len = buf[4] + 5;
|
||||
}
|
||||
|
||||
+16
-56
@@ -2816,14 +2816,17 @@ struct scst_acg *scst_alloc_add_acg(struct scst_tgt *tgt,
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
acg->addr_method = SCST_LUN_ADDR_METHOD_PERIPHERAL;
|
||||
|
||||
#ifdef CONFIG_SCST_PROC
|
||||
acg->addr_method = tgt && tgt->tgtt ? tgt->tgtt->preferred_addr_method
|
||||
: SCST_LUN_ADDR_METHOD_PERIPHERAL;
|
||||
|
||||
TRACE_DBG("Adding acg %s to scst_acg_list", acg_name);
|
||||
list_add_tail(&acg->acg_list_entry, &scst_acg_list);
|
||||
|
||||
scst_check_reassign_sessions();
|
||||
#else
|
||||
acg->addr_method = tgt->tgtt->preferred_addr_method;
|
||||
|
||||
if (tgt_acg) {
|
||||
int rc;
|
||||
|
||||
@@ -5216,27 +5219,17 @@ out:
|
||||
EXPORT_SYMBOL_GPL(scst_get_cdb_info);
|
||||
|
||||
/* Packs SCST LUN back to SCSI form */
|
||||
__be64 scst_pack_lun(const uint64_t lun, unsigned int addr_method)
|
||||
__be64 scst_pack_lun(const uint64_t lun, enum scst_lun_addr_method addr_method)
|
||||
{
|
||||
uint64_t res;
|
||||
uint16_t *p = (uint16_t *)&res;
|
||||
uint64_t res = 0;
|
||||
|
||||
res = lun;
|
||||
|
||||
if ((addr_method == SCST_LUN_ADDR_METHOD_FLAT) && (lun != 0)) {
|
||||
/*
|
||||
* Flat space: luns other than 0 should use flat space
|
||||
* addressing method.
|
||||
*/
|
||||
*p = 0x7fff & *p;
|
||||
*p = 0x4000 | *p;
|
||||
if (lun) {
|
||||
res = (addr_method << 14) | (lun & 0x3fff);
|
||||
res = res << 48;
|
||||
}
|
||||
/* Default is to use peripheral device addressing mode */
|
||||
|
||||
*p = (__force u16)cpu_to_be16(*p);
|
||||
|
||||
TRACE_EXIT_HRES((unsigned long)res);
|
||||
return (__force __be64)res;
|
||||
TRACE_EXIT_HRES(res >> 48);
|
||||
return cpu_to_be64(res);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -5282,46 +5275,13 @@ uint64_t scst_unpack_lun(const uint8_t *lun, int len)
|
||||
|
||||
address_method = (*lun) >> 6; /* high 2 bits of byte 0 */
|
||||
switch (address_method) {
|
||||
case 0: /* peripheral device addressing method */
|
||||
#if 0
|
||||
if (*lun) {
|
||||
PRINT_ERROR("Illegal BUS INDENTIFIER in LUN "
|
||||
"peripheral device addressing method 0x%02x, "
|
||||
"expected 0", *lun);
|
||||
break;
|
||||
}
|
||||
res = *(lun + 1);
|
||||
break;
|
||||
#else
|
||||
/*
|
||||
* Looks like it's legal to use it as flat space addressing
|
||||
* method as well
|
||||
*/
|
||||
|
||||
/* go through */
|
||||
#endif
|
||||
|
||||
case 1: /* flat space addressing method */
|
||||
case SCST_LUN_ADDR_METHOD_PERIPHERAL:
|
||||
case SCST_LUN_ADDR_METHOD_FLAT:
|
||||
case SCST_LUN_ADDR_METHOD_LUN:
|
||||
res = *(lun + 1) | (((*lun) & 0x3f) << 8);
|
||||
break;
|
||||
|
||||
case 2: /* logical unit addressing method */
|
||||
if (*lun & 0x3f) {
|
||||
PRINT_ERROR("Illegal BUS NUMBER in LUN logical unit "
|
||||
"addressing method 0x%02x, expected 0",
|
||||
*lun & 0x3f);
|
||||
break;
|
||||
}
|
||||
if (*(lun + 1) & 0xe0) {
|
||||
PRINT_ERROR("Illegal TARGET in LUN logical unit "
|
||||
"addressing method 0x%02x, expected 0",
|
||||
(*(lun + 1) & 0xf8) >> 5);
|
||||
break;
|
||||
}
|
||||
res = *(lun + 1) & 0x1f;
|
||||
break;
|
||||
|
||||
case 3: /* extended logical unit addressing method */
|
||||
case SCST_LUN_ADDR_METHOD_EXTENDED_LUN:
|
||||
default:
|
||||
PRINT_ERROR("Unimplemented LUN addressing method %u",
|
||||
address_method);
|
||||
|
||||
@@ -117,10 +117,6 @@ extern unsigned long scst_trace_flag;
|
||||
|
||||
#define SCST_TGT_RETRY_TIMEOUT (3/2*HZ)
|
||||
|
||||
/* Definitions of symbolic constants for LUN addressing method */
|
||||
#define SCST_LUN_ADDR_METHOD_PERIPHERAL 0
|
||||
#define SCST_LUN_ADDR_METHOD_FLAT 1
|
||||
|
||||
/* Activities suspending timeout */
|
||||
#define SCST_SUSPENDING_TIMEOUT (90 * HZ)
|
||||
|
||||
@@ -400,7 +396,7 @@ int scst_alloc_space(struct scst_cmd *cmd);
|
||||
int scst_lib_init(void);
|
||||
void scst_lib_exit(void);
|
||||
|
||||
__be64 scst_pack_lun(const uint64_t lun, unsigned int addr_method);
|
||||
__be64 scst_pack_lun(const uint64_t lun, enum scst_lun_addr_method addr_method);
|
||||
uint64_t scst_unpack_lun(const uint8_t *lun, int len);
|
||||
|
||||
struct scst_mgmt_cmd *scst_alloc_mgmt_cmd(gfp_t gfp_mask);
|
||||
|
||||
+11
-3
@@ -137,6 +137,7 @@ static char *scst_proc_help_string =
|
||||
" echo \"assign H:C:I:L HANDLER_NAME\" >/proc/scsi_tgt/scsi_tgt\n"
|
||||
"\n"
|
||||
" echo \"add_group GROUP_NAME [FLAT]\" >/proc/scsi_tgt/scsi_tgt\n"
|
||||
" echo \"add_group GROUP_NAME [LUN]\" >/proc/scsi_tgt/scsi_tgt\n"
|
||||
" echo \"del_group GROUP_NAME\" >/proc/scsi_tgt/scsi_tgt\n"
|
||||
" echo \"rename_group OLD_NAME NEW_NAME\" >/proc/scsi_tgt/scsi_tgt\n"
|
||||
"\n"
|
||||
@@ -1628,6 +1629,7 @@ static ssize_t scst_proc_scsi_tgt_gen_write(struct file *file,
|
||||
|
||||
/*
|
||||
* Usage: echo "add_group GROUP_NAME [FLAT]" >/proc/scsi_tgt/scsi_tgt
|
||||
* or echo "add_group GROUP_NAME [LUN]" >/proc/scsi_tgt/scsi_tgt
|
||||
* or echo "del_group GROUP_NAME" >/proc/scsi_tgt/scsi_tgt
|
||||
* or echo "rename_group OLD_NAME NEW_NAME" >/proc/scsi_tgt/scsi_tgt"
|
||||
* or echo "assign H:C:I:L HANDLER_NAME" >/proc/scsi_tgt/scsi_tgt
|
||||
@@ -1697,13 +1699,16 @@ static ssize_t scst_proc_scsi_tgt_gen_write(struct file *file,
|
||||
goto out_up_free;
|
||||
}
|
||||
}
|
||||
if (strcasecmp(pp, "FLAT") != 0) {
|
||||
if (strcasecmp(pp, "FLAT") == 0)
|
||||
addr_method = SCST_LUN_ADDR_METHOD_FLAT;
|
||||
else if (strcasecmp(pp, "LUN") == 0)
|
||||
addr_method = SCST_LUN_ADDR_METHOD_LUN;
|
||||
else {
|
||||
PRINT_ERROR("Unexpected "
|
||||
"argument %s", pp);
|
||||
res = -EINVAL;
|
||||
goto out_up_free;
|
||||
} else
|
||||
addr_method = SCST_LUN_ADDR_METHOD_FLAT;
|
||||
}
|
||||
break;
|
||||
case SCST_PROC_ACTION_DEL_GROUP:
|
||||
PRINT_ERROR("%s", "Too many "
|
||||
@@ -2497,6 +2502,9 @@ static int scst_groups_addr_method_show(struct seq_file *seq, void *v)
|
||||
case SCST_LUN_ADDR_METHOD_PERIPHERAL:
|
||||
seq_printf(seq, "%s\n", "PERIPHERAL");
|
||||
break;
|
||||
case SCST_LUN_ADDR_METHOD_LUN:
|
||||
seq_printf(seq, "%s\n", "LUN");
|
||||
break;
|
||||
default:
|
||||
seq_printf(seq, "%s\n", "UNKNOWN");
|
||||
break;
|
||||
|
||||
@@ -2965,16 +2965,22 @@ static ssize_t __scst_acg_addr_method_show(struct scst_acg *acg, char *buf)
|
||||
|
||||
switch (acg->addr_method) {
|
||||
case SCST_LUN_ADDR_METHOD_FLAT:
|
||||
res = sprintf(buf, "FLAT\n%s\n", SCST_SYSFS_KEY_MARK);
|
||||
res = sprintf(buf, "FLAT\n");
|
||||
break;
|
||||
case SCST_LUN_ADDR_METHOD_PERIPHERAL:
|
||||
res = sprintf(buf, "PERIPHERAL\n");
|
||||
break;
|
||||
case SCST_LUN_ADDR_METHOD_LUN:
|
||||
res = sprintf(buf, "LUN\n");
|
||||
break;
|
||||
default:
|
||||
res = sprintf(buf, "UNKNOWN\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (acg->addr_method != acg->tgt->tgtt->preferred_addr_method)
|
||||
res += sprintf(&buf[res], "%s\n", SCST_SYSFS_KEY_MARK);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -2987,6 +2993,8 @@ static ssize_t __scst_acg_addr_method_store(struct scst_acg *acg,
|
||||
acg->addr_method = SCST_LUN_ADDR_METHOD_FLAT;
|
||||
else if (strncasecmp(buf, "PERIPHERAL", min_t(int, 10, count)) == 0)
|
||||
acg->addr_method = SCST_LUN_ADDR_METHOD_PERIPHERAL;
|
||||
else if (strncasecmp(buf, "LUN", min_t(int, 3, count)) == 0)
|
||||
acg->addr_method = SCST_LUN_ADDR_METHOD_LUN;
|
||||
else {
|
||||
PRINT_ERROR("Unknown address method %s", buf);
|
||||
res = -EINVAL;
|
||||
|
||||
+9
-15
@@ -1644,15 +1644,9 @@ static int scst_report_luns_local(struct scst_cmd *cmd)
|
||||
buffer_size);
|
||||
goto out_put_hw_err;
|
||||
}
|
||||
if ((cmd->sess->acg->addr_method == SCST_LUN_ADDR_METHOD_FLAT) &&
|
||||
(tgt_dev->lun != 0)) {
|
||||
buffer[offs] = (tgt_dev->lun >> 8) & 0x3f;
|
||||
buffer[offs] = buffer[offs] | 0x40;
|
||||
buffer[offs+1] = tgt_dev->lun & 0xff;
|
||||
} else {
|
||||
buffer[offs] = (tgt_dev->lun >> 8) & 0xff;
|
||||
buffer[offs+1] = tgt_dev->lun & 0xff;
|
||||
}
|
||||
*(__force __be64 *)&buffer[offs]
|
||||
= scst_pack_lun(tgt_dev->lun,
|
||||
cmd->sess->acg->addr_method);
|
||||
offs += 8;
|
||||
}
|
||||
inc_dev_cnt:
|
||||
@@ -2987,18 +2981,18 @@ static int scst_pre_dev_done(struct scst_cmd *cmd)
|
||||
|
||||
/* ToDo: all pages ?? */
|
||||
buflen = scst_get_buf_first(cmd, &buffer);
|
||||
if (buflen > SCST_INQ_BYTE3) {
|
||||
if (buflen > SCST_INQ_BYTE3 && !cmd->tgtt->fake_aca) {
|
||||
#ifdef CONFIG_SCST_EXTRACHECKS
|
||||
if (buffer[SCST_INQ_BYTE3] & SCST_INQ_NORMACA_BIT) {
|
||||
PRINT_INFO("NormACA set for device: "
|
||||
"lun=%lld, type 0x%02x. Clear it, "
|
||||
"since it's unsupported.",
|
||||
(long long unsigned int)cmd->lun,
|
||||
buffer[0]);
|
||||
"lun=%lld, type 0x%02x. Clear it, "
|
||||
"since it's unsupported.",
|
||||
(long long unsigned int)cmd->lun,
|
||||
buffer[0]);
|
||||
}
|
||||
#endif
|
||||
buffer[SCST_INQ_BYTE3] &= ~SCST_INQ_NORMACA_BIT;
|
||||
} else if (buflen != 0) {
|
||||
} else if (buflen <= SCST_INQ_BYTE3 && buflen != 0) {
|
||||
PRINT_ERROR("%s", "Unable to get INQUIRY "
|
||||
"buffer");
|
||||
scst_set_cmd_error(cmd,
|
||||
|
||||
Reference in New Issue
Block a user