[stgt] [PATCH] MODE_SENSE: add support for mode subpages

Ronnie Sahlberg ronniesahlberg at gmail.com
Sun Jul 29 08:22:41 CEST 2012


Add support for mode subpages.
Change the modepages from an array of pointers to a linked list
so that we can store an arbitrary number od mode pages with the same
page code (but different subpage codes)

Add a simple modepage with a subpage code 0x0a/0x01 which is the
ControlExtensions subpage.
Have TCMOS set to 1 in this subpage.
This value has the following meaning (SPC):
        A timestamp changeable by methods outside this standard (TCMOS)
        bit set to one specifies that the timestamp may
        be initialized by methods outside the scope of this standard.

Which sounds appropriate since root or ntpd can change the
local time on linux without first asking TGTD and SPC for permission first

Signed-off-by: Ronnie Sahlberg <ronniesahlberg at gmail.com>
---
 usr/bs_rdwr.c |   12 +++++++-
 usr/mmc.c     |    4 ++-
 usr/sbc.c     |   15 +++++++++--
 usr/smc.c     |    8 ++++--
 usr/spc.c     |   75 +++++++++++++++++++++++++++++++++++++-------------------
 usr/spc.h     |    4 ++-
 usr/ssc.c     |    4 ++-
 usr/target.c  |    1 +
 usr/tgtd.h    |    3 +-
 9 files changed, 88 insertions(+), 38 deletions(-)

diff --git a/usr/bs_rdwr.c b/usr/bs_rdwr.c
index 981ab65..a79dd02 100644
--- a/usr/bs_rdwr.c
+++ b/usr/bs_rdwr.c
@@ -38,6 +38,7 @@
 #include "util.h"
 #include "tgtd.h"
 #include "scsi.h"
+#include "spc.h"
 #include "bs_thread.h"
 
 static void set_medium_error(int *result, uint8_t *key, uint16_t *asc)
@@ -156,12 +157,19 @@ write:
 		ret = pwrite64(fd, scsi_get_out_buffer(cmd), length,
 			       offset);
 		if (ret == length) {
+			struct mode_pg *pg;
+
 			/*
 			 * it would be better not to access to pg
 			 * directy.
 			 */
-			struct mode_pg *pg = cmd->dev->mode_pgs[0x8];
-
+			pg = find_mode_page(cmd->dev, 0x08, 0);
+			if (pg == NULL) {
+				result = SAM_STAT_CHECK_CONDITION;
+				key = ILLEGAL_REQUEST;
+				asc = ASC_INVALID_FIELD_IN_CDB;
+				break;
+			}
 			if (((cmd->scb[0] != WRITE_6) && (cmd->scb[1] & 0x8)) ||
 			    !(pg->mode_data[0] & 0x04))
 				bs_sync_sync_range(cmd, length, &result, &key,
diff --git a/usr/mmc.c b/usr/mmc.c
index 4d81426..768fe91 100644
--- a/usr/mmc.c
+++ b/usr/mmc.c
@@ -2243,7 +2243,9 @@ static tgtadm_err mmc_lu_init(struct scsi_lu *lu)
 	/* Caching Page */
 	add_mode_page(lu, "8:0:10:0:0:0:0:0:0:0:0:0:0");
 	/* Control page */
-	add_mode_page(lu, "10:0:10:2:0:0:0:0:0:0:0:2:0");
+	add_mode_page(lu, "0x0a:0:10:2:0:0:0:0:0:0:0:2:0");
+	/* Control Extensions mode page:  TCMOS:1 */
+	add_mode_page(lu, "0x0a:1:0x1c:0x04:0x00:0x00");
 	/* Power Condition */
 	add_mode_page(lu, "0x1a:0:10:8:0:0:0:0:0:0:0:0:0");
 	/* Informational Exceptions Control page */
diff --git a/usr/sbc.c b/usr/sbc.c
index 7a643e1..0f99f18 100644
--- a/usr/sbc.c
+++ b/usr/sbc.c
@@ -69,9 +69,14 @@ static off_t find_next_hole(struct scsi_lu *dev, off_t offset)
 static int sbc_mode_page_update(struct scsi_cmd *cmd, uint8_t *data, int *changed)
 {
 	uint8_t pcode = data[0] & 0x3f;
-	struct mode_pg *pg = cmd->dev->mode_pgs[pcode];
+	uint8_t subpcode = data[1];
+	struct mode_pg *pg;
 	uint8_t old;
 
+	pg = find_mode_page(cmd->dev, pcode, subpcode);
+	if (pg == NULL)
+		return 1;
+
 	eprintf("%x %x\n", pg->mode_data[0], data[2]);
 
 	if (pcode == 0x08) {
@@ -688,11 +693,15 @@ static tgtadm_err sbc_lu_init(struct scsi_lu *lu)
 		memset(mask, 0, sizeof(mask));
 		mask[0] = 0x4;
 
-		set_mode_page_changeable_mask(lu, 8, mask);
+		set_mode_page_changeable_mask(lu, 8, 0, mask);
 	}
 
 	/* Control page */
-	add_mode_page(lu, "10:0:10:2:0x10:0:0:0:0:0:0:2:0");
+	add_mode_page(lu, "0x0a:0:10:2:0x10:0:0:0:0:0:0:2:0");
+
+	/* Control Extensions mode page:  TCMOS:1 */
+	add_mode_page(lu, "0x0a:1:0x1c:0x04:0x00:0x00");
+
 	/* Informational Exceptions Control page */
 	add_mode_page(lu, "0x1c:0:10:8:0:0:0:0:0:0:0:0:0");
 
diff --git a/usr/smc.c b/usr/smc.c
index bbfbfcd..910b532 100644
--- a/usr/smc.c
+++ b/usr/smc.c
@@ -514,7 +514,9 @@ static tgtadm_err smc_lu_init(struct scsi_lu *lu)
 	/* Vendor uniq - However most apps seem to call for mode page 0*/
 	add_mode_page(lu, "0:0:0");
 	/* Control page */
-	add_mode_page(lu, "10:0:10:2:0:0:0:0:0:0:0:2:0");
+	add_mode_page(lu, "0x0a:0:10:2:0:0:0:0:0:0:0:2:0");
+	/* Control Extensions mode page:  TCMOS:1 */
+	add_mode_page(lu, "0x0a:1:0x1c:0x04:0x00:0x00");
 	/* Power Condition */
 	add_mode_page(lu, "0x1a:0:10:8:0:0:0:0:0:0:0:0:0");
 	/* Informational Exceptions Control page */
@@ -625,7 +627,7 @@ static tgtadm_err add_slt(struct scsi_lu *lu, struct tmp_param *tmp)
 	int qnty_save;
 	int i;
 
-	pg = lu->mode_pgs[0x1d];
+	pg = find_mode_page(lu, 0x1d, 0);
 	if (!pg) {
 		dprintf("Failed to find Element Address Assignment mode pg\n");
 		return TGTADM_UNKNOWN_ERR;
@@ -692,7 +694,7 @@ static tgtadm_err config_slot(struct scsi_lu *lu, struct tmp_param *tmp)
 	switch(tmp->element_type) {
 	case ELEMENT_MEDIUM_TRANSPORT:
 		/* If medium has more than one side, set the 'rotate' bit */
-		m = lu->mode_pgs[0x1e];
+		m = find_mode_page(lu, 0x1e, 0);
 		if (m) {
 			m->mode_data[0] = (tmp->sides > 1) ? 1 : 0;
 			adm_err = TGTADM_SUCCESS;
diff --git a/usr/spc.c b/usr/spc.c
index c3b4052..10d799e 100644
--- a/usr/spc.c
+++ b/usr/spc.c
@@ -480,7 +480,7 @@ int spc_mode_select(int host_no, struct scsi_cmd *cmd,
 
 		pcode = data[offset] & 0x3f;
 
-		pg = cmd->dev->mode_pgs[pcode];
+		pg = find_mode_page(cmd->dev, pcode, 0);
 		if (!pg)
 			goto sense;
 
@@ -525,10 +525,22 @@ sense:
 	return SAM_STAT_CHECK_CONDITION;
 }
 
+struct mode_pg *find_mode_page(struct scsi_lu *lu, uint8_t pcode,
+			       uint8_t subpcode)
+{
+	struct mode_pg *pg;
+
+	list_for_each_entry(pg, &lu->mode_pages, mode_pg_siblings) {
+		if (pg->pcode == pcode && pg->subpcode == subpcode)
+			return pg;
+	}
+	return NULL;
+}
+
 int set_mode_page_changeable_mask(struct scsi_lu *lu, uint8_t pcode,
-				  uint8_t *mask)
+				  uint8_t subpcode, uint8_t *mask)
 {
-	struct mode_pg *pg = lu->mode_pgs[pcode];
+	struct mode_pg *pg = find_mode_page(lu, pcode, subpcode);
 
 	if (pg) {
 		memcpy(pg->mode_data + pg->pcode_size, mask, pg->pcode_size);
@@ -551,18 +563,26 @@ static int build_mode_page(uint8_t *data, struct mode_pg *pg,
 			   uint8_t pc, uint16_t *alloc_len)
 {
 	uint8_t *p;
-	int len;
+	int len, hdr_size = 2;
 	uint8_t *mode_data;
 
 	len = pg->pcode_size;
 	if (*alloc_len >= 2) {
-		data[0] = pg->pcode;
-		data[1] = len;
+		if (!pg->subpcode) {
+			data[0] = pg->pcode;
+			data[1] = len;
+		} else {
+			data[0] = pg->pcode | 0x40;
+			data[1] = pg->subpcode;
+			data[2] = len >> 8;
+			data[3] = len & 0xff;
+			hdr_size = 4;
+		}
 	}
-	*alloc_len -= min_t(uint16_t, *alloc_len, 2);
+	*alloc_len -= min_t(uint16_t, *alloc_len, hdr_size);
 
-	p = &data[2];
-	len += 2;
+	p = &data[hdr_size];
+	len += hdr_size;
 	if (*alloc_len >= pg->pcode_size) {
 		if (pc == 1)
 			mode_data = pg->mode_data + pg->pcode_size;
@@ -599,10 +619,6 @@ int spc_mode_sense(int host_no, struct scsi_cmd *cmd)
 	pctrl = (scb[2] & 0xc0) >> 6;
 	subpcode = scb[3];
 
-	/* Currently not implemented */
-	if (subpcode)
-		goto sense;
-
 	if (pctrl == 3) {
 		asc = ASC_SAVING_PARMS_UNSUP;
 		goto sense;
@@ -633,15 +649,14 @@ int spc_mode_sense(int host_no, struct scsi_cmd *cmd)
 	}
 
 	if (pcode == 0x3f) {
-		int i;
-		for (i = 0; i < ARRAY_SIZE(cmd->dev->mode_pgs); i++) {
-			pg = cmd->dev->mode_pgs[i];
-			if (pg)
-				len += build_mode_page(data + len, pg, pctrl,
-						       &alloc_len);
+		list_for_each_entry(pg,
+				    &cmd->dev->mode_pages,
+				    mode_pg_siblings) {
+			len += build_mode_page(data + len, pg, pctrl,
+					       &alloc_len);
 		}
 	} else {
-		pg = cmd->dev->mode_pgs[pcode];
+		pg = find_mode_page(cmd->dev, pcode, subpcode);
 		if (!pg)
 			goto sense;
 		len += build_mode_page(data + len, pg, pctrl, &alloc_len);
@@ -1595,8 +1610,11 @@ tgtadm_err add_mode_page(struct scsi_lu *lu, char *p)
 		case 2:
 			size = strtol(p, NULL, 0);
 
-			if (lu->mode_pgs[pcode])
-				free(lu->mode_pgs[pcode]);
+			pg = find_mode_page(lu, pcode, subpcode);
+			if (pg) {
+				list_del(&pg->mode_pg_siblings);
+				free(pg);
+			}
 
 			pg = alloc_mode_pg(pcode, subpcode, size);
 			if (!pg) {
@@ -1604,7 +1622,7 @@ tgtadm_err add_mode_page(struct scsi_lu *lu, char *p)
 				goto exit;
 			}
 
-			lu->mode_pgs[pcode] = pg;
+			list_add_tail(&pg->mode_pg_siblings, &lu->mode_pages);
 			data = pg->mode_data;
 			break;
 		default:
@@ -1898,7 +1916,12 @@ void spc_lu_exit(struct scsi_lu *lu)
 		if (lu_vpd[i])
 			free(lu_vpd[i]);
 
-	for (i = 0; i < ARRAY_SIZE(lu->mode_pgs); i++)
-		if (lu->mode_pgs[i])
-			free(lu->mode_pgs[i]);
+	while (!list_empty(&lu->mode_pages)) {
+		struct mode_pg *pg;
+		pg = list_first_entry(&lu->mode_pages,
+				       struct mode_pg,
+				       mode_pg_siblings);
+		list_del(&pg->mode_pg_siblings);
+		free(pg);
+	}
 }
diff --git a/usr/spc.h b/usr/spc.h
index 5b88542..0c537e1 100644
--- a/usr/spc.h
+++ b/usr/spc.h
@@ -23,7 +23,9 @@ extern void dump_cdb(struct scsi_cmd *cmd);
 extern int spc_mode_sense(int host_no, struct scsi_cmd *cmd);
 extern tgtadm_err add_mode_page(struct scsi_lu *lu, char *params);
 extern int set_mode_page_changeable_mask(struct scsi_lu *lu, uint8_t pcode,
-					 uint8_t *mask);
+					 uint8_t subpcode, uint8_t *mask);
+extern struct mode_pg *find_mode_page(struct scsi_lu *lu,
+				      uint8_t pcode, uint8_t subpcode);
 extern int spc_mode_select(int host_no, struct scsi_cmd *cmd,
 			   int (*update)(struct scsi_cmd *, uint8_t *, int *));
 extern struct vpd *alloc_vpd(uint16_t size);
diff --git a/usr/ssc.c b/usr/ssc.c
index 59d2e15..60c6926 100644
--- a/usr/ssc.c
+++ b/usr/ssc.c
@@ -193,7 +193,9 @@ static tgtadm_err ssc_lu_init(struct scsi_lu *lu)
 	/* Disconnect page - Mandatory - SPC-4 */
 	add_mode_page(lu, "2:0:14:0x80:0x80:0:0xa:0:0:0:0:0:0:0:0:0:0");
 	/* Control page - Mandatory - SPC-4 */
-	add_mode_page(lu, "10:0:10:2:0:0:0:0:0:0:0:2:0");
+	add_mode_page(lu, "0x0a:0:10:2:0:0:0:0:0:0:0:2:0");
+	/* Control Extensions mode page:  TCMOS:1 */
+	add_mode_page(lu, "0x0a:1:0x1c:0x04:0x00:0x00");
 	/* Data Compression - Mandatory - SSC3 8.3.2 */
 	add_mode_page(lu, "15:0:14:0:0:0:0:0:0:0:0:0:0:0:0:0:0");
 	/* Device Configuration - Mandatory - SSC3 8.3.3 */
diff --git a/usr/target.c b/usr/target.c
index e94c3ed..05d8c59 100644
--- a/usr/target.c
+++ b/usr/target.c
@@ -579,6 +579,7 @@ tgtadm_err tgt_device_create(int tid, int dev_type, uint64_t lun, char *params,
 	tgt_cmd_queue_init(&lu->cmd_queue);
 	INIT_LIST_HEAD(&lu->registration_list);
 	INIT_LIST_HEAD(&lu->lu_itl_info_list);
+	INIT_LIST_HEAD(&lu->mode_pages);
 	lu->prgeneration = 0;
 	lu->pr_holder = NULL;
 
diff --git a/usr/tgtd.h b/usr/tgtd.h
index 8bee2e3..07cd971 100644
--- a/usr/tgtd.h
+++ b/usr/tgtd.h
@@ -168,6 +168,7 @@ struct backingstore_template {
 };
 
 struct mode_pg {
+	struct list_head mode_pg_siblings;
 	uint8_t pcode;		/* Page code */
 	uint8_t subpcode;	/* Sub page code */
 	int16_t pcode_size;	/* Size of page code data. */
@@ -210,7 +211,7 @@ struct scsi_lu {
 	struct target *tgt;
 
 	uint8_t	mode_block_descriptor[BLOCK_DESCRIPTOR_LEN];
-	struct mode_pg *mode_pgs[0x3f];
+	struct list_head mode_pages;
 
 	struct lu_phy_attr attrs;
 
-- 
1.7.3.1

--
To unsubscribe from this list: send the line "unsubscribe stgt" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html



More information about the stgt mailing list