From 0463afc282264d54b84c98af7da6d0e2355216eb Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Tue, 9 Nov 2010 21:01:21 +0000 Subject: [PATCH] Patch from Bart Van Assche 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 --- scst/include/scst.h | 56 ++++++++++++++++++++++- scst/include/scst_const.h | 11 +++++ scst/src/dev_handlers/scst_vdisk.c | 40 +++++++++++++---- scst/src/scst_lib.c | 72 +++++++----------------------- scst/src/scst_priv.h | 6 +-- scst/src/scst_proc.c | 14 ++++-- scst/src/scst_sysfs.c | 10 ++++- scst/src/scst_targ.c | 24 ++++------ 8 files changed, 144 insertions(+), 89 deletions(-) diff --git a/scst/include/scst.h b/scst/include/scst.h index 6ede5fd3f..8858baeb3 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -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; }; /* diff --git a/scst/include/scst_const.h b/scst/include/scst_const.h index b5918b6f3..25d079645 100644 --- a/scst/include/scst_const.h +++ b/scst/include/scst_const.h @@ -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 *************************************************************/ diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index 5d9cd10f0..2993a8b84 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -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; } diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index a39ef2019..d66f3a6fc 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -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); diff --git a/scst/src/scst_priv.h b/scst/src/scst_priv.h index f3c15cbea..f6f9cea8f 100644 --- a/scst/src/scst_priv.h +++ b/scst/src/scst_priv.h @@ -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); diff --git a/scst/src/scst_proc.c b/scst/src/scst_proc.c index 3a418e86e..064ec1f89 100644 --- a/scst/src/scst_proc.c +++ b/scst/src/scst_proc.c @@ -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; diff --git a/scst/src/scst_sysfs.c b/scst/src/scst_sysfs.c index f0fbb5fa5..ea925391b 100644 --- a/scst/src/scst_sysfs.c +++ b/scst/src/scst_sysfs.c @@ -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; diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index 4fd825c64..c183eb7ce 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -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,