[Stgt-devel] [Patch 1/2] Add MODE SENSE (6) & MODE SENSE (10) support
FUJITA Tomonori
fujita.tomonori
Thu Jul 5 14:59:17 CEST 2007
Thanks a lot and sorry for the delay.
From: Mark Harvey <markh794 at gmail.com>
Subject: [Stgt-devel] [Patch 1/2] Add MODE SENSE (6) & MODE SENSE (10) support
Date: Sat, 30 Jun 2007 17:47:10 +1000
> >From 4afa975c190c87fab099f52bcd95cafa608fcf96 Mon Sep 17 00:00:00 2001
> From: Mark Harvey <markh794 at gmail.com>
> Date: Sat, 30 Jun 2007 16:56:19 +1000
> Subject: Initial commit of Dynamic MODE SENSE support
>
> Add support for:
> - MODE SENSE (6)
> - MODE SENSE (10)
>
> Add ability to add mode pages 'on the fly'. i.e. At setup time.
>
> Configuration/creation of mode pages via the 'tgtadm --params mode_page'
>
> Page data information is seperated by ':'
> e.g.
> --params mode_page=10:1:11:2:0:0:0:0:0:0:0:2:0:0
> Where '10' is mode page 10
> '1' is the subpage
> '11' is the length of the page data (11 bytes of information follow)
I keep this format but is the length necessary?
> SBC & MMC devices set up some default pages at lu creation time.
>
> The example script 'scripts/tgt-core-test' contains an executable example.
>
> The 'doc/README.lu_configuration' updated for mode page informaiton.
>
> Signed-off-by: Mark Harvey <markh794 at gmail.com>
I simplified the code slightly. I'll apply this if it works for you.
diff --git a/doc/README.lu_configuration b/doc/README.lu_configuration
index 1244bc0..d63668a 100644
--- a/doc/README.lu_configuration
+++ b/doc/README.lu_configuration
@@ -65,5 +65,25 @@ standard INQUIRY:
As can be seen from above 'sg_inq' output, the RMB (removable) bit is set to 1.
The Unit serial number page updated with 'FRED00'
+Mode Page Creation
+------------------
+Create mode page '2', subpage 0 and 14 bytes of data.
+tgtadm --mode logicalunit --op update --tid 1 --lun 2 \
+ --params mode_page=2:0:14:0x80:0x80:0:0xa:0:0:0:0:0:0:0:0:0:0
+
+Create mode page '3', subpage 0 and 22 bytes of data.
+tgtadm --lld iscsi --mode logicalunit --op update --tid 1 --lun 2 \
+ --params mode_page=3:0:22:0:0:0:0:0:0:0:0:1:0:2:0:0:0:0:0:0:0:0:13:0:0
+
+Create mode page '10', subpage 0 and 10 bytes of data.
+tgtadm --lld iscsi --mode logicalunit --op update --tid 1 --lun 2 \
+ --params mode_page=10:0:10:2:0:0:0:0:0:0:0:2:0
+
+Create mode page '0x1c', subpage 0 and 10 bytes of data.
+tgtadm --lld iscsi --mode logicalunit --op update --tid 1 --lun 2 \
+ --params mode_page=0x1c:0:10:8:0:0:0:0:0:0:0:0:0
+
+
+
Please refer to scripts/tgt-core-test for a working example.
diff --git a/scripts/tgt-core-test b/scripts/tgt-core-test
index a90fc9d..a31be1b 100755
--- a/scripts/tgt-core-test
+++ b/scripts/tgt-core-test
@@ -3,6 +3,7 @@ #!/bin/bash
# Parent directory for data files..
HOME=/d/01
+# Start tgtd if not running..
P=`ps -ef|grep -v grep|grep tgtd|wc -l`
if [ "X"$P == "X0" ]; then
tgtd -d 1
@@ -35,7 +36,7 @@ TID=1
# Create Target ID 1..
tgtadm --lld iscsi --mode target --op new --tid $TID \
- -T iqn.2007-03:marks-vtl_sbc:`hostname`
+ -T iqn.2007-03:marks-vtl_tgt:`hostname`
sleep 1
# Create first LUN - Disk
@@ -48,23 +49,58 @@ tgtadm --lld iscsi --mode logicalunit --
tgtadm --lld iscsi --mode logicalunit --op update --tid $TID --lun $LUN \
--params vendor_id=QUANTUM,product_id=HD100,product_rev=0010,removable=1,sense_format=0
-# Create 2nd LUN - CD/ROM
-LUN=2
-tgtadm --lld iscsi --mode logicalunit --op new --tid $TID --lun $LUN -b $HOME/cd_block0 --device-type=cd
+#### Set up mode pages ####
+# First try a couple of attempts with incorrect data..
+# i.e. Expect the first two to fail!
+# - Length too long & Incorrect value (300) as one if the params...
tgtadm --lld iscsi --mode logicalunit --op update --tid $TID --lun $LUN \
- --params vendor_id=VirtualCD,product_id=CD101,product_rev=0010,scsi_sn=XYZZY11,removable=1
-
-# Create 3rd LUN - CD/ROM
-LUN=3
-tgtadm --lld iscsi --mode logicalunit --op new --tid $TID --lun $LUN -b $HOME/cd_block1 --device-type=cd
+ --params mode_page=2:0:14:0x80:0x80:0:0xa:0:300:0:0:0:0:0:0:0:0:3
+# - Length too short...
tgtadm --lld iscsi --mode logicalunit --op update --tid $TID --lun $LUN \
- --params vendor_id=VirtualCD,product_id=CD101,product_rev=0010,scsi_sn=XYZZY12,removable=1
+ --params mode_page=2:0:14:0x80:0x80:0:0xa:0:0:0:0:0:0:0:0:0
+#
+# From here on - should work OK..
+#
-# Create 4th LUN - CD/ROM
-LUN=4
-tgtadm --lld iscsi --mode logicalunit --op new --tid $TID --lun $LUN -b $HOME/cd_block1 --device-type=cd
+# Vendor Uniq - Mode page 0..
+tgtadm --lld iscsi --mode logicalunit --op update --tid $TID --lun $LUN \
+ --params mode_page=0:0:0
+# Disconnect page
+tgtadm --lld iscsi --mode logicalunit --op update --tid $TID --lun $LUN \
+ --params mode_page=2:0:14:0x80:0x80:0:0xa:0:0:0:0:0:0:0:0:0:0
+# Format mode page
+tgtadm --lld iscsi --mode logicalunit --op update --tid $TID --lun $LUN \
+ --params mode_page=3:0:22:0:0:0:0:0:0:0:0:1:0:2:0:0:0:0:0:0:0:0:13:0:0
+# Geo mode page
+tgtadm --lld iscsi --mode logicalunit --op update --tid $TID --lun $LUN \
+ --params mode_page=4:0:22:0:0:0:0x40:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0x3a:0x98:0:0
+# Caching Page
+tgtadm --lld iscsi --mode logicalunit --op update --tid $TID --lun $LUN \
+ --params mode_page=8:0:18:0x14:0:0xff:0xff:0:0:0xff:0xff:0xff:0xff:0x80:0x14:0:0:0:0:0:0
+# ctrl mode page
+tgtadm --lld iscsi --mode logicalunit --op update --tid $TID --lun $LUN \
+ --params mode_page=10:0:10:2:0:0:0:0:0:0:0:2:0
+# Informational Exceptions Control Mode Page
tgtadm --lld iscsi --mode logicalunit --op update --tid $TID --lun $LUN \
- --params vendor_id=VirtualCD,product_id=CD101,product_rev=0010,scsi_sn=XYZZY13,removable=1
+ --params mode_page=0x1c:0:10:8:0:0:0:0:0:0:0:0:0
+
+
+
+for LUN in 2 3 4; do
+ # Create LUN - CD/ROM
+ tgtadm --lld iscsi --mode logicalunit --op new --tid $TID --lun $LUN -b $HOME/cd_block0 --device-type=cd
+ tgtadm --lld iscsi --mode logicalunit --op update --tid $TID --lun $LUN \
+ --params vendor_id=VirtualCD,product_id=CD101,product_rev=0010,scsi_sn=XYZZY1$LUN,removable=1
+ # Vendor Uniq - Mode page 0..
+ tgtadm --lld iscsi --mode logicalunit --op update --tid $TID --lun $LUN \
+ --params mode_page=0:0:0
+ # ctrl mode page
+ tgtadm --lld iscsi --mode logicalunit --op update --tid $TID --lun $LUN \
+ --params mode_page=10:0:10:2:0:0:0:0:0:0:0:2:0
+ # Informational Exceptions Control Mode Page
+ tgtadm --lld iscsi --mode logicalunit --op update --tid $TID --lun $LUN \
+ --params mode_page=0x1c:0:10:8:0:0:0:0:0:0:0:0:0
+done
# 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 9f8559f..0390bdb 100644
--- a/usr/mmc.c
+++ b/usr/mmc.c
@@ -41,6 +41,7 @@ #include "target.h"
#include "driver.h"
#include "scsi.h"
#include "spc.h"
+#include "tgtadm_error.h"
#define MMC_BLK_SHIFT 11
@@ -121,10 +122,19 @@ static int mmc_read_capacity(int host_no
return SAM_STAT_GOOD;
}
+static int mmc_mode_sense(int host_no, struct scsi_cmd *cmd)
+{
+ uint8_t *scb = cmd->scb;
+
+ /* MMC devices always return descriptor block */
+ scb[1] |= 8;
+ return spc_mode_sense(host_no, cmd);
+}
+
static int mmc_lu_init(struct scsi_lu *lu)
{
if (spc_lu_init(lu))
- return -ENOMEM;
+ return TGTADM_NOMEM;
strncpy(lu->attrs.product_id, "VIRTUAL-CDROM", sizeof(lu->attrs.product_id));
lu->attrs.sense_format = 0;
@@ -132,6 +142,33 @@ static int mmc_lu_init(struct scsi_lu *l
lu->attrs.version_desc[1] = 0x0960; /* iSCSI */
lu->attrs.version_desc[2] = 0x0300; /* SPC-3 */
+ /*
+ * Set up default mode pages
+ * Ref: mmc6r00.pdf 7.2.2 (Table 649)
+ */
+
+ /* Vendor uniq - However most apps seem to call for mode page 0*/
+ add_mode_page(lu, "0:0:0");
+ /* Read/Write Error Recovery */
+ add_mode_page(lu, "1:0:10:0:8:0:0:0:0:8:0:0:0");
+ /* MRW */
+ add_mode_page(lu, "3:0:6:0:0:0:0:0:0");
+ /* Write Parameter
+ * Somebody who knows more about this mode page should be setting
+ * defaults.
+ add_mode_page(lu, "5:0:0");
+ */
+ /* 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");
+ /* Power Condition */
+ add_mode_page(lu, "0x1a:0:10:8:0:0:0:0:0:0:0:0:0");
+ /* Informational Exceptions Control page */
+ add_mode_page(lu, "0x1c:0:10:8:0:0:0:0:0:0:0:0:0");
+ /* Timeout & Protect */
+ add_mode_page(lu, "0x1d:0:10:0:0:7:0:0:2:0:2:0:20");
+
return 0;
}
@@ -217,7 +254,26 @@ static struct device_type_template mmc_t
{spc_illegal_op,},
{spc_illegal_op,},
- [0x50 ... 0x9f] = {spc_illegal_op,},
+ /* 0x50 */
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {mmc_mode_sense,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+
+ [0x60 ... 0x9f] = {spc_illegal_op,},
/* 0xA0 */
{spc_report_luns,},
diff --git a/usr/osd.c b/usr/osd.c
index ff138aa..2bd33e6 100644
--- a/usr/osd.c
+++ b/usr/osd.c
@@ -33,6 +33,7 @@ #include "target.h"
#include "driver.h"
#include "scsi.h"
#include "spc.h"
+#include "tgtadm_error.h"
static int osd_varlen_cdb(int host_no, struct scsi_cmd *cmd)
{
@@ -52,7 +53,7 @@ static int osd_varlen_cdb(int host_no, s
static int osd_lu_init(struct scsi_lu *lu)
{
if (spc_lu_init(lu))
- return -ENOMEM;
+ return TGTADM_NOMEM;
strncpy(lu->attrs.product_id, "OSD", sizeof(lu->attrs.product_id));
lu->attrs.sense_format = 1;
diff --git a/usr/sbc.c b/usr/sbc.c
index 51c48da..d285207 100644
--- a/usr/sbc.c
+++ b/usr/sbc.c
@@ -38,6 +38,7 @@ #include "target.h"
#include "driver.h"
#include "scsi.h"
#include "spc.h"
+#include "tgtadm_error.h"
#define BLK_SHIFT 9
@@ -168,154 +169,43 @@ sense:
return SAM_STAT_CHECK_CONDITION;
}
-static int insert_disconnect_pg(uint8_t *ptr)
-{
- unsigned char disconnect_pg[] = {0x02, 0x0e, 0x80, 0x80, 0x00, 0x0a, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-
- memcpy(ptr, disconnect_pg, sizeof(disconnect_pg));
- return sizeof(disconnect_pg);
-}
-
-static int insert_caching_pg(uint8_t *ptr)
-{
- unsigned char caching_pg[] = {0x08, 0x12, 0x14, 0x00, 0xff, 0xff, 0x00, 0x00,
- 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00};
-
- memcpy(ptr, caching_pg, sizeof(caching_pg));
- return sizeof(caching_pg);
-}
-
-static int insert_ctrl_m_pg(uint8_t *ptr)
-{
- unsigned char ctrl_m_pg[] = {0x0a, 0x0a, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x02, 0x4b};
-
- memcpy(ptr, ctrl_m_pg, sizeof(ctrl_m_pg));
- return sizeof(ctrl_m_pg);
-}
-
-static int insert_iec_m_pg(uint8_t *ptr)
-{
- unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00};
-
- memcpy(ptr, iec_m_pg, sizeof(iec_m_pg));
- return sizeof(iec_m_pg);
-}
-
-static int insert_format_m_pg(uint8_t *ptr)
-{
- unsigned char format_m_pg[] = {0x03, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00};
- memcpy(ptr, format_m_pg, sizeof(format_m_pg));
- return sizeof(format_m_pg);
-}
-
-static int insert_geo_m_pg(uint8_t *ptr, uint64_t sec)
-{
- unsigned char geo_m_pg[] = {0x04, 0x16, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3a, 0x98, 0x00, 0x00};
- uint32_t ncyl, *p;
-
- /* assume 0xff heads, 15krpm. */
- memcpy(ptr, geo_m_pg, sizeof(geo_m_pg));
- ncyl = sec >> 14; /* 256 * 64 */
- p = (uint32_t *)(ptr + 1);
- *p = *p | __cpu_to_be32(ncyl);
- return sizeof(geo_m_pg);
-}
-
-static int sbc_mode_sense(int host_no, struct scsi_cmd *cmd)
+static int sbc_lu_init(struct scsi_lu *lu)
{
- int ret = SAM_STAT_GOOD, len;
- uint8_t pcode = cmd->scb[2] & 0x3f;
uint64_t size;
- uint8_t *data = NULL;
- unsigned char key = ILLEGAL_REQUEST;
- uint16_t asc = ASC_LUN_NOT_SUPPORTED;
+ uint8_t *data;
- if (device_reserved(cmd))
- return SAM_STAT_RESERVATION_CONFLICT;
-
- data = valloc(pagesize);
- if (!data) {
- key = HARDWARE_ERROR;
- asc = ASC_INTERNAL_TGT_FAILURE;
- goto sense;
- }
- memset(data, 0, pagesize);
-
- len = 4;
- size = cmd->dev->size >> BLK_SHIFT;
-
- if ((cmd->scb[1] & 0x8))
- data[3] = 0;
- else {
- data[3] = 8;
- len += 8;
- *(uint32_t *)(data + 4) = (size >> 32) ?
- __cpu_to_be32(0xffffffff) : __cpu_to_be32(size);
- *(uint32_t *)(data + 8) = __cpu_to_be32(1 << BLK_SHIFT);
- }
-
- switch (pcode) {
- case 0x0:
- break;
- case 0x2:
- len += insert_disconnect_pg(data + len);
- break;
- case 0x3:
- len += insert_format_m_pg(data + len);
- break;
- case 0x4:
- len += insert_geo_m_pg(data + len, size);
- break;
- case 0x8:
- len += insert_caching_pg(data + len);
- break;
- case 0xa:
- len += insert_ctrl_m_pg(data + len);
- break;
- case 0x1c:
- len += insert_iec_m_pg(data + len);
- break;
- case 0x3f:
- len += insert_disconnect_pg(data + len);
- len += insert_format_m_pg(data + len);
- len += insert_geo_m_pg(data + len, size);
- len += insert_caching_pg(data + len);
- len += insert_ctrl_m_pg(data + len);
- len += insert_iec_m_pg(data + len);
- break;
- default:
- asc = ASC_INVALID_FIELD_IN_CDB;
- goto sense;
- }
-
- data[0] = len - 1;
- cmd->len = len;
- cmd->uaddr = (unsigned long) data;
- return ret;
-sense:
- cmd->len = 0;
- sense_data_build(cmd, key, asc);
- return SAM_STAT_CHECK_CONDITION;
-}
-
-static int sbc_lu_init(struct scsi_lu *lu)
-{
if (spc_lu_init(lu))
- return -ENOMEM;
+ return TGTADM_NOMEM;
strncpy(lu->attrs.product_id, "VIRTUAL-DISK", sizeof(lu->attrs.product_id));
lu->attrs.version_desc[0] = 0x04C0; /* SBC-3 no version claimed */
lu->attrs.version_desc[1] = 0x0960; /* iSCSI */
lu->attrs.version_desc[2] = 0x0300; /* SPC-3 */
+ data = lu->mode_block_descriptor;
+ size = lu->size >> BLK_SHIFT;
+
+ *(uint32_t *)(data) = (size >> 32) ?
+ __cpu_to_be32(0xffffffff) : __cpu_to_be32(size);
+ *(uint32_t *)(data + 4) = __cpu_to_be32(1 << BLK_SHIFT);
+
+ /* Vendor uniq - However most apps seem to call for mode page 0*/
+ add_mode_page(lu, "0:0:0");
+ /* Disconnect page */
+ add_mode_page(lu, "2:0:14:0x80:0x80:0:0xa:0:0:0:0:0:0:0:0:0:0");
+ /* Format page */
+ add_mode_page(lu, "3:0:22:0:0:0:0:0:0:0:0:1:0:2:0:0:0:0:0:0:0:0:13:0:0");
+ /* GEO page */
+ add_mode_page(lu, "4:0:22:0:0:0:0x40:0:0:0:0:0:"
+ "0:0:0:0:0:0:0:0:0:0x3a:0x98:0:0");
+ /* Caching Page */
+ add_mode_page(lu, "8:0:18:0x14:0:0xff:0xff:0:0:"
+ "0xff:0xff:0xff:0xff:0x80:0x14: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");
+ /* Informational Exceptions Control page */
+ add_mode_page(lu, "0x1c:0:10:8:0:0:0:0:0:0:0:0:0");
+
return 0;
}
@@ -354,7 +244,7 @@ static struct device_type_template sbc_t
{spc_illegal_op,},
{spc_illegal_op,},
- {sbc_mode_sense,},
+ {spc_mode_sense,},
{spc_start_stop,},
{spc_illegal_op,},
{spc_illegal_op,},
@@ -399,7 +289,28 @@ static struct device_type_template sbc_t
{spc_illegal_op,},
{spc_illegal_op,},
- [0x40 ... 0x7f] = {spc_illegal_op,},
+ [0x40 ... 0x4f] = {spc_illegal_op,},
+
+ /* 0x50 */
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_mode_sense,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+
+ [0x60 ... 0x7f] = {spc_illegal_op,},
/* 0x80 */
{spc_illegal_op,},
diff --git a/usr/scc.c b/usr/scc.c
index 3b26a57..0a154a5 100644
--- a/usr/scc.c
+++ b/usr/scc.c
@@ -33,12 +33,13 @@ #include "tgtd.h"
#include "target.h"
#include "driver.h"
#include "scsi.h"
+#include "tgtadm_error.h"
#include "spc.h"
static int scc_lu_init(struct scsi_lu *lu)
{
if (spc_lu_init(lu))
- return -ENOMEM;
+ return TGTADM_NOMEM;
strncpy(lu->attrs.product_id, "Controller",
sizeof(lu->attrs.product_id));
diff --git a/usr/spc.c b/usr/spc.c
index 1997329..7711078 100644
--- a/usr/spc.c
+++ b/usr/spc.c
@@ -230,6 +230,112 @@ int spc_test_unit(int host_no, struct sc
return SAM_STAT_GOOD;
}
+/*
+ * Copy mode page data from list into SCSI data so it can be returned
+ * to the initiator
+ *
+ * *data -> target address (destination)
+ * pg -> Pointer to mode page information (source)
+ *
+ * Returns number of bytes copied.
+ */
+static int build_mode_page(uint8_t *data, struct mode_pg *pg)
+{
+ uint8_t *p;
+ int len;
+
+ data[0] = pg->pcode;
+ len = pg->pcode_size;
+ data[1] = len;
+ p = &data[2];
+ len += 2;
+ memcpy(p, pg->mode_data, pg->pcode_size);
+
+ return len;
+}
+
+int spc_mode_sense(int host_no, struct scsi_cmd *cmd)
+{
+ int len = 0;
+ uint8_t *data, *scb, mode6, dbd, pcode, subpcode;
+ uint16_t alloc_len;
+ unsigned char key = ILLEGAL_REQUEST;
+ uint16_t asc = ASC_INVALID_FIELD_IN_CDB;
+ struct mode_pg *pg;
+
+ /*
+ * Reference : SPC4r11
+ * 6.11 - MODE SENSE(6)
+ * 6.12 - MODE SENSE(10)
+ */
+
+ scb = cmd->scb;
+ mode6 = (scb[0] == 0x1a);
+ dbd = scb[1] & 0x8; /* Disable Block Descriptors */
+ pcode = scb[2] & 0x3f;
+ subpcode = scb[3];
+
+ /* Currently not implemented */
+ if (subpcode)
+ goto sense;
+
+ data = valloc(pagesize);
+ if (!data) {
+ key = HARDWARE_ERROR;
+ asc = ASC_INTERNAL_TGT_FAILURE;
+ goto sense;
+ }
+ memset(data, 0, pagesize);
+
+ if (mode6) {
+ alloc_len = scb[4];
+ len = 4;
+ } else {
+ alloc_len = (scb[7] << 8) + scb[8];
+ len = 8;
+ }
+
+ if (alloc_len > pagesize)
+ goto sense;
+
+ if (!dbd) {
+ memcpy(data + len, cmd->dev->mode_block_descriptor,
+ BLOCK_DESCRIPTOR_LEN);
+ len += 8;
+ }
+
+ 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);
+ }
+ } else {
+ pg = cmd->dev->mode_pgs[pcode];
+ if (!pg)
+ goto sense;
+ len += build_mode_page(data + len, pg);
+ }
+
+ if (mode6) {
+ data[0] = len - 1;
+ data[3] = dbd ? 0 : BLOCK_DESCRIPTOR_LEN;
+ } else {
+ *(uint16_t *)(data) = __cpu_to_be16(len - 3);
+ data[7] = dbd ? 0 : BLOCK_DESCRIPTOR_LEN;
+ }
+
+ cmd->len = len;
+ cmd->uaddr = (unsigned long)data;
+ return SAM_STAT_GOOD;
+
+sense:
+ cmd->len = 0;
+ sense_data_build(cmd, key, asc);
+ return SAM_STAT_CHECK_CONDITION;
+}
+
int spc_request_sense(int host_no, struct scsi_cmd *cmd)
{
cmd->len = 0;
@@ -237,6 +343,81 @@ int spc_request_sense(int host_no, struc
return SAM_STAT_GOOD;
}
+static struct mode_pg *alloc_mode_pg(uint8_t pcode, uint8_t subpcode,
+ uint16_t size)
+{
+ struct mode_pg *pg;
+
+ pg = zalloc(sizeof(*pg) + size);
+ if (!pg)
+ return NULL;
+
+ pg->pcode = pcode;
+ pg->subpcode = subpcode;
+ pg->pcode_size = size;
+
+ return pg;
+}
+
+int add_mode_page(struct scsi_lu *lu, char *p)
+{
+ int i, tmp, ret = TGTADM_SUCCESS;
+ uint8_t pcode, subpcode, *data;
+ uint16_t size;
+ struct mode_pg *pg;
+
+ pcode = subpcode = i = size = 0;
+ data = NULL;
+
+ for (i = 0; p; i++) {
+ switch (i) {
+ case 0:
+ pcode = strtol(p, NULL, 0);
+ break;
+ case 1:
+ subpcode = strtol(p, NULL, 0);
+ break;
+ case 2:
+ size = strtol(p, NULL, 0);
+
+ if (lu->mode_pgs[pcode])
+ free(lu->mode_pgs[pcode]);
+
+ pg = alloc_mode_pg(pcode, subpcode, size);
+ if (!pg) {
+ ret = TGTADM_NOMEM;
+ goto exit;
+ }
+
+ lu->mode_pgs[pcode] = pg;
+ data = pg->mode_data;
+ break;
+ default:
+ if (i < (size + 3)) {
+ tmp = strtol(p, NULL, 0);
+ if (tmp > UINT8_MAX)
+ eprintf("Incorrect value %d "
+ "Mode page %d (0x%02x), index: %d\n",
+ tmp, pcode, subpcode, i - 3);
+ data[i - 3] = (uint8_t)tmp;
+ }
+ break;
+ }
+
+ p = strchr(p, ':');
+ if (p)
+ p++;
+ }
+
+ if (i != size + 3) {
+ ret = TGTADM_INVALID_REQUEST;
+ eprintf("Mode Page %d (0x%02x): param_count %d != "
+ "MODE PAGE size : %d\n", pcode, subpcode, i, size + 3);
+ }
+exit:
+ return ret;
+}
+
void dump_cdb(struct scsi_cmd *cmd)
{
uint8_t *cdb = cmd->scb;
@@ -282,6 +463,7 @@ enum {
Opt_vendor_id, Opt_product_id,
Opt_product_rev, Opt_sense_format,
Opt_removable, Opt_online,
+ Opt_mode_page,
Opt_err,
};
@@ -294,13 +476,14 @@ static match_table_t tokens = {
{Opt_sense_format, "sense_format=%s"},
{Opt_removable, "removable=%s"},
{Opt_online, "online=%s"},
+ {Opt_mode_page, "mode_page=%s"},
{Opt_err, NULL},
};
int spc_lu_config(struct scsi_lu *lu, char *params) {
int err = 0;
char *p;
- char buf[20];
+ char buf[256];
if (!strncmp("targetOps", params, 9))
params = params + 10;
@@ -344,6 +527,10 @@ int spc_lu_config(struct scsi_lu *lu, ch
match_strncpy(buf, &args[0], sizeof(buf));
lu->attrs.online = atoi(buf);
break;
+ case Opt_mode_page:
+ match_strncpy(buf, &args[0], sizeof(buf));
+ err = add_mode_page(lu, buf);
+ break;
default:
err = TGTADM_INVALID_REQUEST;
}
@@ -351,6 +538,11 @@ int spc_lu_config(struct scsi_lu *lu, ch
return err;
}
+/*
+ * Set initial power-on defaults for lu
+ *
+ * Currently always return '0'
+ */
int spc_lu_init(struct scsi_lu *lu)
{
strncpy(lu->attrs.vendor_id, VENDOR_ID, sizeof(lu->attrs.vendor_id));
diff --git a/usr/spc.h b/usr/spc.h
index 1036b70..4b99268 100644
--- a/usr/spc.h
+++ b/usr/spc.h
@@ -10,5 +10,7 @@ extern int spc_illegal_op(int host_no, s
extern int spc_lu_init(struct scsi_lu *lu);
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);
#endif
diff --git a/usr/tgtd.h b/usr/tgtd.h
index 8e66d60..1c1e3e2 100644
--- a/usr/tgtd.h
+++ b/usr/tgtd.h
@@ -5,6 +5,7 @@ #include "log.h"
#define SCSI_ID_LEN 24
#define SCSI_SN_LEN 8
+#define BLOCK_DESCRIPTOR_LEN 8
#define VERSION_DESCRIPTOR_LEN 8
#define VENDOR_ID "IET"
@@ -75,6 +76,13 @@ struct backingstore_template {
int (*bs_cmd_done) (struct scsi_cmd *cmd);
};
+struct mode_pg {
+ uint8_t pcode; /* Page code */
+ uint8_t subpcode; /* Sub page code */
+ int16_t pcode_size; /* Size of page code data. */
+ uint8_t mode_data[0]; /* Rest of mode page info */
+};
+
struct scsi_lu {
int fd;
uint64_t addr; /* persistent mapped address */
@@ -96,6 +104,9 @@ struct scsi_lu {
struct backingstore_template *bst;
+ uint8_t mode_block_descriptor[BLOCK_DESCRIPTOR_LEN];
+ struct mode_pg *mode_pgs[0x3f];
+
/* TODO: needs a structure for lots of device parameters */
struct lu_phy_attr attrs;
};
More information about the stgt
mailing list