[Stgt-devel] [Patch 1/1] Add support for extra VPD pages within INQUIRY op code

Mark Harvey markh794
Fri Aug 24 10:15:52 CEST 2007


As always, feedback welcome.


Unfortunately I had to change the lu_init() interface so I could more 
easily include the TID in the SCSI VPD page 80h and 83h

Hence the number of files touched with this patch.

As indicated in the patch, I am unsure from the osd2r01.pdf 
documentation of what data should be included within VPD pages B0h and 
B1h for the OSD module.

Regards
Mark


>From e752630bf3c33b9f4a0c22d4cc7af28b141c926b Mon Sep 17 00:00:00 2001
From: Mark Harvey <markh794 at gmail.com>
Date: Fri, 24 Aug 2007 18:04:24 +1000
Subject: Add support for VPD pages 0x80 - 0xff

Ability to add VPD pages between 80h and FFh per SCSI device type.

An array of 128 vpd structures added to ly_phy_attr struct.

Use alloc_vpd(data size) to pre-alloc data for custom VPD page.
- This data is appended to the 4 byte VPD header at runtime
  i.e. When an INQUIRY for the VPD page is received.

- A custom vpd_update(struct scsi_lu *lu, void *) is used to
  set/change data pre-allocated by alloc_vpd()

- All modules except use default page 80h & 83h defined in spc.c
  The osd module has two extra for VPD pages B0h and B1h
  - Note: garbage values are set and should be reviewed/updated
          by somebody who knows what should be set here.

Signed-off-by: Mark Harvey <markh794 at gmail.com>
---
 scripts/tgt-core-test |   11 +++
 usr/mmc.c             |    4 +-
 usr/osd.c             |   42 +++++++++-
 usr/sbc.c             |    4 +-
 usr/scc.c             |    4 +-
 usr/smc.c             |    4 +-
 usr/spc.c             |  220 ++++++++++++++++++++++++++++++++++++++-----------
 usr/spc.h             |    3 +-
 usr/target.c          |    9 +--
 usr/tgtd.h            |   16 +++-
 10 files changed, 245 insertions(+), 72 deletions(-)

diff --git a/scripts/tgt-core-test b/scripts/tgt-core-test
index 8c58972..cf92303 100755
--- a/scripts/tgt-core-test
+++ b/scripts/tgt-core-test
@@ -184,6 +184,17 @@ tgtadm --lld iscsi --mode logicalunit --op update --tid $TID --lun $LUN \
 	--params dump=1
 
 
+# Create OSD LUN
+LUN=6
+tgtadm --lld iscsi --mode logicalunit --op new --tid $TID --lun $LUN -b $HOME/hd_block --device-type=osd
+
+tgtadm --lld iscsi --mode logicalunit --op update --tid $TID --lun $LUN \
+	--params scsi_sn=FRED06,scsi_id=FredOSD
+
+tgtadm --lld iscsi --mode logicalunit --op update --tid $TID --lun $LUN \
+	--params vendor_id=OSD,product_id=OSD00,product_rev=0010,removable=1,sense_format=1
+
+
 # Allow ALL initiators to connect to this target
 tgtadm --lld iscsi --mode target --op bind --tid $TID -I ALL
 
diff --git a/usr/mmc.c b/usr/mmc.c
index 7f70943..fffb2b7 100644
--- a/usr/mmc.c
+++ b/usr/mmc.c
@@ -132,9 +132,9 @@ static int mmc_mode_sense(int host_no, struct scsi_cmd *cmd)
 	return spc_mode_sense(host_no, cmd);
 }
 
-static int mmc_lu_init(struct scsi_lu *lu)
+static int mmc_lu_init(struct scsi_lu *lu, int tid)
 {
-	if (spc_lu_init(lu))
+	if (spc_lu_init(lu, tid))
 		return TGTADM_NOMEM;
 
 	strncpy(lu->attrs.product_id, "VIRTUAL-CDROM", sizeof(lu->attrs.product_id));
diff --git a/usr/osd.c b/usr/osd.c
index 189fba4..80ae9c5 100644
--- a/usr/osd.c
+++ b/usr/osd.c
@@ -51,13 +51,35 @@ static int osd_varlen_cdb(int host_no, struct scsi_cmd *cmd)
 	return cmd->dev->bst->bs_cmd_submit(cmd);
 }
 
+static void update_vpd_b0(struct scsi_lu *lu, void *p)
+{
+	int pg = 0xb0 & 0x7f;
+	struct vpd *vpd_pg = lu->attrs.vpd[pg];
+
+	memcpy(vpd_pg->data, p, vpd_pg->size);
+}
+
+static void update_vpd_b1(struct scsi_lu *lu, void *p)
+{
+	int pg = 0xb1 & 0x7f;
+	struct vpd *vpd_pg = lu->attrs.vpd[pg];
+
+	memcpy(vpd_pg->data, p, vpd_pg->size);
+}
+
 /*
- * XXX: missing support for b0 and b1, in page 0 and in inquiry code.
- * Figure out how to make spc_inquiry handle extra mode pages.
+ * FIXME: I've made up the value for these params. Somebody who knows what
+ * should be in these + size of pages need to put sane vaues for pg B0 & B1
+ * markh794 at gmail.com
  */
-static int osd_lu_init(struct scsi_lu *lu)
+#define OSD_INFORMATION_LEN 12
+#define OSD_SECURITY_TOKEN_LEN 12
+static int osd_lu_init(struct scsi_lu *lu, int tid)
 {
-	if (spc_lu_init(lu))
+	int pg;
+	struct vpd **lu_vpd = lu->attrs.vpd;
+
+	if (spc_lu_init(lu, tid))
 		return TGTADM_NOMEM;
 
 	strncpy(lu->attrs.product_id, "OSD", sizeof(lu->attrs.product_id));
@@ -66,6 +88,18 @@ static int osd_lu_init(struct scsi_lu *lu)
 	lu->attrs.version_desc[1] = 0x0960; /* iSCSI */
 	lu->attrs.version_desc[2] = 0x0300; /* SPC-3 */
 
+	/* VPD page 0xB0 */
+	pg = 0xb0 & 0x7f;
+	lu_vpd[pg] = alloc_vpd(OSD_INFORMATION_LEN);
+	lu_vpd[pg]->vpd_update = update_vpd_b0;
+	lu_vpd[pg]->vpd_update(lu, "Information");
+
+	/* VPD page 0xB1 */
+	pg = 0xb1 & 0x7f;
+	lu_vpd[pg] = alloc_vpd(OSD_SECURITY_TOKEN_LEN);
+	lu_vpd[pg]->vpd_update = update_vpd_b1;
+	lu_vpd[pg]->vpd_update(lu, "Security");
+
 	return 0;
 }
 
diff --git a/usr/sbc.c b/usr/sbc.c
index 33485e6..7d488fb 100644
--- a/usr/sbc.c
+++ b/usr/sbc.c
@@ -170,12 +170,12 @@ sense:
 	return SAM_STAT_CHECK_CONDITION;
 }
 
-static int sbc_lu_init(struct scsi_lu *lu)
+static int sbc_lu_init(struct scsi_lu *lu, int tid)
 {
 	uint64_t size;
 	uint8_t *data;
 
-	if (spc_lu_init(lu))
+	if (spc_lu_init(lu, tid))
 		return TGTADM_NOMEM;
 
 	strncpy(lu->attrs.product_id, "VIRTUAL-DISK", sizeof(lu->attrs.product_id));
diff --git a/usr/scc.c b/usr/scc.c
index 0a154a5..c52d4f1 100644
--- a/usr/scc.c
+++ b/usr/scc.c
@@ -36,9 +36,9 @@
 #include "tgtadm_error.h"
 #include "spc.h"
 
-static int scc_lu_init(struct scsi_lu *lu)
+static int scc_lu_init(struct scsi_lu *lu, int tid)
 {
-	if (spc_lu_init(lu))
+	if (spc_lu_init(lu, tid))
 		return TGTADM_NOMEM;
 
 	strncpy(lu->attrs.product_id, "Controller",
diff --git a/usr/smc.c b/usr/smc.c
index 4f0ee4b..318cb4f 100644
--- a/usr/smc.c
+++ b/usr/smc.c
@@ -435,7 +435,7 @@ sense:
 	return SAM_STAT_CHECK_CONDITION;
 }
 
-static int smc_lu_init(struct scsi_lu *lu)
+static int smc_lu_init(struct scsi_lu *lu, int tid)
 {
 	struct smc_info *smc;
 
@@ -445,7 +445,7 @@ static int smc_lu_init(struct scsi_lu *lu)
 	else
 		return -ENOMEM;
 
-	spc_lu_init(lu);
+	spc_lu_init(lu, tid);
 
 	strncpy(lu->attrs.product_id, "VIRTUAL-CHANGER",
 						sizeof(lu->attrs.product_id));
diff --git a/usr/spc.c b/usr/spc.c
index b56c0b3..08a4bc5 100644
--- a/usr/spc.c
+++ b/usr/spc.c
@@ -20,6 +20,7 @@
  * 02110-1301 USA
  */
 #include <errno.h>
+#include <inttypes.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -38,6 +39,96 @@
 #define PRODUCT_REV	"0"
 #define BLK_SHIFT	9
 
+/** Protocol Identifier Values
+ * 0 Fibre Channel (FCP-2)
+ * 1 Parallel SCSI (SPI-5)
+ * 2 SSA (SSA-S3P)
+ * 3 IEEE 1394 (SBP-3)
+ * 4 SCSI Remote Direct Memory Access (SRP)
+ * 5 iSCSI
+ * 6 SAS Serial SCSI Protocol (SAS)
+ * 7 Automation/Drive Interface (ADT)
+ * 8 AT Attachment Interface (ATA/ATAPI-7)
+ */
+#define PIV_FCP 0
+#define PIV_SPI 1
+#define PIV_S3P 2
+#define PIV_SBP 3
+#define PIV_SRP 4
+#define PIV_ISCSI 5
+#define PIV_SAS 6
+#define PIV_ADT 7
+#define PIV_ATA 8
+
+#define PIV_VALID 0x80
+
+/** Code Set
+ *  1 - Designator fild contains binary values
+ *  2 - Designator field contains ASCII printable chars
+ *  3 - Designaotor field contains UTF-8
+ */
+#define INQ_CODE_BIN 1
+#define INQ_CODE_ASCII 2
+#define INQ_CODE_UTF8 3
+
+/** Association field
+ * 00b - Associated with Logical Unit
+ * 01b - Associated with target port
+ * 10b - Associated with SCSI Target device
+ * 11b - Reserved
+ */
+#define ASS_LU	0
+#define ASS_TGT_PORT 0x10
+#define ASS_TGT_DEV 0x20
+
+/** Designator type - SPC-4 Reference
+ * 0 - Vendor specific - 7.6.3.3
+ * 1 - T10 vendor ID - 7.6.3.4
+ * 2 - EUI-64 - 7.6.3.5
+ * 3 - NAA - 7.6.3.6
+ * 4 - Relative Target port identifier - 7.6.3.7
+ * 5 - Target Port group - 7.6.3.8
+ * 6 - Logical Unit group - 7.6.3.9
+ * 7 - MD5 logical unit identifier - 7.6.3.10
+ * 8 - SCSI name string - 7.6.3.11
+ */
+#define DESG_VENDOR 0
+#define DESG_T10 1
+#define DESG_EUI64 2
+#define DESG_NAA 3
+#define DESG_REL_TGT_PORT 4
+#define DESG_TGT_PORT_GRP 5
+#define DESG_LU_GRP 6
+#define DESG_MD5 7
+#define DESG_SCSI 8
+
+static int valid_vpd(struct vpd **vpd, uint8_t page)
+{
+	if (vpd[page & 0x7f])
+		return 1;
+	return 0;
+}
+
+void update_vpd_80(struct scsi_lu *lu, void *sn)
+{
+	struct vpd *vpd_pg = lu->attrs.vpd[0];
+	char *data = (char *)vpd_pg->data;
+
+	snprintf(data, SCSI_SN_LEN, "%-8s", (char *)sn);
+}
+
+void update_vpd_83(struct scsi_lu *lu, void *id)
+{
+	struct vpd *vpd_pg = lu->attrs.vpd[3];
+	uint8_t	*data = vpd_pg->data;
+
+	data[0] = (PIV_ISCSI << 4) | INQ_CODE_ASCII;
+	data[1] = PIV_VALID | ASS_TGT_PORT | DESG_VENDOR;
+	data[3] = SCSI_ID_LEN;
+
+	strncpy((char *)data + 4, id, SCSI_ID_LEN);
+}
+
 int spc_inquiry(int host_no, struct scsi_cmd *cmd)
 {
 	int len = 0, ret = SAM_STAT_CHECK_CONDITION;
@@ -47,6 +138,8 @@ int spc_inquiry(int host_no, struct scsi_cmd *cmd)
 	uint16_t asc = ASC_INVALID_FIELD_IN_CDB;
 	uint8_t devtype = 0;
 	struct lu_phy_attr *attrs;
+	struct vpd **vpd;
+	struct vpd *vpd_pg;
 
 	if (((scb[1] & 0x3) == 0x3) || (!(scb[1] & 0x3) && scb[2]))
 		goto sense;
@@ -97,44 +190,37 @@ int spc_inquiry(int host_no, struct scsi_cmd *cmd)
 		ret = SAM_STAT_GOOD;
 	} else if (scb[1] & 0x1) {
 		/* EVPD bit set */
+		vpd = attrs->vpd;
 		if (scb[2] == 0x0) {
+			int i, j, tmp;
+
+			i = 5;
+			tmp = 1;
 			data[0] = devtype;
-			data[1] = 0x0;
-			data[3] = 3;
+			data[1] = 0;
+			data[2] = 0;
+			for (j = 0; j < 0x80; j++) {
+				if (vpd[j]) {
+					data[i] = j | 0x80;
+					tmp++;
+					i++;
+				}
+			}
+			data[3] = tmp;
 			data[4] = 0x0;
-			data[5] = 0x80;
-			data[6] = 0x83;
-			len = 7;
-			ret = SAM_STAT_GOOD;
-		} else if (scb[2] == 0x80) {
-			int tmp = SCSI_SN_LEN;
-
-			data[1] = 0x80;
-			data[3] = SCSI_SN_LEN;
-			memset(data + 4, 0x20, 4);
-			len = 4 + SCSI_SN_LEN;
+			len = tmp + 4;
 			ret = SAM_STAT_GOOD;
+		} else if (valid_vpd(vpd, scb[2])) {
+			int tmp;
+			vpd_pg = vpd[scb[2] & 0x7f];
+			tmp = vpd_pg->size;
 
-			if (strlen(attrs->scsi_sn)) {
-				uint8_t *p;
-				char *q;
-
-				p = data + 4 + tmp - 1;
-				q = attrs->scsi_sn + SCSI_SN_LEN - 1;
-				for (; tmp > 0; tmp--, q)
-					*(p--) = *(q--);
-			}
-		} else if (scb[2] == 0x83) {
-			int tmp = SCSI_ID_LEN;
-
-			data[1] = 0x83;
-			data[3] = tmp + 4;
-			data[4] = 0x1;
-			data[5] = 0x1;
-			data[7] = tmp;
-			strncpy((char *) data + 8, attrs->scsi_id, SCSI_ID_LEN);
-
-			len = tmp + 8;
+			data[0] = devtype;
+			data[1] = scb[2];
+			data[2] = (tmp >> 8);
+			data[3] = tmp & 0xff;
+			memcpy(&data[4], vpd_pg->data, tmp);
+			len = tmp + 4;
 			ret = SAM_STAT_GOOD;
 		}
 	}
@@ -358,6 +444,19 @@ int spc_request_sense(int host_no, struct scsi_cmd *cmd)
 	return SAM_STAT_GOOD;
 }
 
+struct vpd *alloc_vpd(uint16_t size)
+{
+	struct vpd *vpd;
+
+	vpd = zalloc(sizeof(struct vpd) + size);
+	if (!vpd)
+		return NULL;
+
+	vpd->size = size;
+
+	return vpd;
+}
+
 static struct mode_pg *alloc_mode_pg(uint8_t pcode, uint8_t subpcode,
 				     uint16_t size)
 {
@@ -500,6 +599,11 @@ int lu_config(struct scsi_lu *lu, char *params, match_fn_t *fn)
 	int err = TGTADM_SUCCESS;
 	char *p;
 	char buf[256];
+	struct lu_phy_attr *attrs;
+	struct vpd **vpd;
+
+	attrs = &lu->attrs;
+	vpd = attrs->vpd;
 
 	if (!strncmp("targetOps", params, 9))
 		params = params + 10;
@@ -512,36 +616,38 @@ int lu_config(struct scsi_lu *lu, char *params, match_fn_t *fn)
 		token = match_token(p, tokens, args);
 		switch (token) {
 		case Opt_scsi_id:
-			match_strncpy(lu->attrs.scsi_id, &args[0],
-				      sizeof(lu->attrs.scsi_id));
+			match_strncpy(attrs->scsi_id, &args[0],
+				      sizeof(attrs->scsi_id));
+			vpd[3]->vpd_update(lu, attrs->scsi_id);
 			break;
 		case Opt_scsi_sn:
-			match_strncpy(lu->attrs.scsi_sn, &args[0],
-				      sizeof(lu->attrs.scsi_sn));
+			match_strncpy(attrs->scsi_sn, &args[0],
+				      sizeof(attrs->scsi_sn));
+			vpd[0]->vpd_update(lu, attrs->scsi_sn);
 			break;
 		case Opt_vendor_id:
-			match_strncpy(lu->attrs.vendor_id, &args[0],
-				      sizeof(lu->attrs.vendor_id));
+			match_strncpy(attrs->vendor_id, &args[0],
+				      sizeof(attrs->vendor_id));
 			break;
 		case Opt_product_id:
-			match_strncpy(lu->attrs.product_id, &args[0],
-				      sizeof(lu->attrs.product_id));
+			match_strncpy(attrs->product_id, &args[0],
+				      sizeof(attrs->product_id));
 			break;
 		case Opt_product_rev:
-			match_strncpy(lu->attrs.product_rev, &args[0],
-				      sizeof(lu->attrs.product_rev));
+			match_strncpy(attrs->product_rev, &args[0],
+				      sizeof(attrs->product_rev));
 			break;
 		case Opt_sense_format:
 			match_strncpy(buf, &args[0], sizeof(buf));
-			lu->attrs.sense_format = atoi(buf);
+			attrs->sense_format = atoi(buf);
 			break;
 		case Opt_removable:
 			match_strncpy(buf, &args[0], sizeof(buf));
-			lu->attrs.removable = atoi(buf);
+			attrs->removable = atoi(buf);
 			break;
 		case Opt_online:
 			match_strncpy(buf, &args[0], sizeof(buf));
-			lu->attrs.online = atoi(buf);
+			attrs->online = atoi(buf);
 			break;
 		case Opt_mode_page:
 			match_strncpy(buf, &args[0], sizeof(buf));
@@ -559,12 +665,32 @@ int spc_lu_config(struct scsi_lu *lu, char *params)
 	return lu_config(lu, params, NULL);
 }
 
-int spc_lu_init(struct scsi_lu *lu)
+int spc_lu_init(struct scsi_lu *lu, int tid)
 {
+	struct vpd **lu_vpd = lu->attrs.vpd;
+
+	lu->attrs.device_type = lu->dev_type_template.type;
+	lu->attrs.qualifier = 0x0;
+
 	snprintf(lu->attrs.vendor_id, sizeof(lu->attrs.vendor_id),
 		 "%-16s", VENDOR_ID);
 	snprintf(lu->attrs.product_rev, sizeof(lu->attrs.product_rev),
 		 "%s", "0001");
+	snprintf(lu->attrs.scsi_id, sizeof(lu->attrs.scsi_id),
+		 "deadbeaf%d:%" PRIu64, tid, lu->lun);
+	snprintf(lu->attrs.scsi_sn, sizeof(lu->attrs.scsi_sn),
+		 "beaf%d%" PRIu64, tid, lu->lun);
+
+	/* VPD page 0x80 */
+	lu_vpd[0] = alloc_vpd(SCSI_SN_LEN);
+	lu_vpd[0]->vpd_update = update_vpd_80;
+	update_vpd_80(lu, lu->attrs.scsi_sn);
+
+	/* VPD page 0x83 */
+	lu_vpd[3] = alloc_vpd(SCSI_ID_LEN + 4); /* + Designator descriptor len*/
+	lu_vpd[3]->vpd_update = update_vpd_83;
+	update_vpd_83(lu, lu->attrs.scsi_id);
+
 	lu->attrs.removable = 0;
 	lu->attrs.sense_format = 0;
 	lu->attrs.online = 0;
diff --git a/usr/spc.h b/usr/spc.h
index 1cc8623..315b49e 100644
--- a/usr/spc.h
+++ b/usr/spc.h
@@ -7,7 +7,7 @@ extern int spc_start_stop(int host_no, struct scsi_cmd *cmd);
 extern int spc_test_unit(int host_no, struct scsi_cmd *cmd);
 extern int spc_request_sense(int host_no, struct scsi_cmd *cmd);
 extern int spc_illegal_op(int host_no, struct scsi_cmd *cmd);
-extern int spc_lu_init(struct scsi_lu *lu);
+extern int spc_lu_init(struct scsi_lu *lu, int tid);
 
 typedef int (match_fn_t)(struct scsi_lu *lu, char *params);
 extern int lu_config(struct scsi_lu *lu, char *params, match_fn_t *);
@@ -15,5 +15,6 @@ extern int spc_lu_config(struct scsi_lu *lu, char *params);
 extern void dump_cdb(struct scsi_cmd *cmd);
 extern int spc_mode_sense(int host_no, struct scsi_cmd *cmd);
 extern int add_mode_page(struct scsi_lu *lu, char *params);
+extern struct vpd *alloc_vpd(uint16_t size);
 
 #endif
diff --git a/usr/target.c b/usr/target.c
index 2474d05..b966579 100644
--- a/usr/target.c
+++ b/usr/target.c
@@ -266,7 +266,7 @@ int tgt_device_create(int tid, int dev_type, uint64_t lun, char *args, int backi
 	tgt_cmd_queue_init(&lu->cmd_queue);
 
  	if (lu->dev_type_template.lu_init) {
- 		ret = lu->dev_type_template.lu_init(lu);
+		ret = lu->dev_type_template.lu_init(lu, tid);
 		if (ret)
 			goto free_lu;
 	}
@@ -285,13 +285,6 @@ int tgt_device_create(int tid, int dev_type, uint64_t lun, char *args, int backi
 			goto free_lu;
 	}
 
-	lu->attrs.device_type = lu->dev_type_template.type;
-	lu->attrs.qualifier = 0x0;
-	snprintf(lu->attrs.scsi_id, sizeof(lu->attrs.scsi_id),
-		 "deadbeaf%d:%" PRIu64, tid, lun);
-	snprintf(lu->attrs.scsi_sn, sizeof(lu->attrs.scsi_sn),
-		 "beaf%d%" PRIu64, tid, lun);
-
 	if (tgt_drivers[target->lid]->lu_create)
 		tgt_drivers[target->lid]->lu_create(lu);
 
diff --git a/usr/tgtd.h b/usr/tgtd.h
index c39b9c2..6fc38c4 100644
--- a/usr/tgtd.h
+++ b/usr/tgtd.h
@@ -36,6 +36,15 @@ struct tgt_cmd_queue {
 	struct list_head queue;
 };
 
+struct scsi_lu;
+struct scsi_cmd;
+
+struct vpd {
+	uint16_t size;
+	void (*vpd_update)(struct scsi_lu *lu, void *data);
+	uint8_t data[0];
+};
+
 struct lu_phy_attr {
 	char scsi_id[SCSI_ID_LEN + 1];
 	char scsi_sn[SCSI_SN_LEN + 1];
@@ -52,10 +61,9 @@ struct lu_phy_attr {
 	char online;		/* Logical Unit online */
 	char reset;		/* Power-on or reset has occured */
 	char sense_format;	/* Descrptor format sense data supported */
-};
 
-struct scsi_lu;
-struct scsi_cmd;
+	struct vpd *vpd[0x80];	/* VPD pages 0x80 -> 0xff masked with 0x80*/
+};
 
 struct device_type_operations {
 	int (*cmd_perform)(int host_no, struct scsi_cmd *cmd);
@@ -64,7 +72,7 @@ struct device_type_operations {
 struct device_type_template {
 	unsigned char type;
 
-	int (*lu_init)(struct scsi_lu *lu);
+	int (*lu_init)(struct scsi_lu *lu, int tid);
 	void (*lu_exit)(struct scsi_lu *lu);
 	int (*lu_config)(struct scsi_lu *lu, char *args);
 
-- 
1.5.2.3







More information about the stgt mailing list