[stgt] RFC [PATCH] Implement PERSISTENT RESERVE IN/OUT

Mark Harvey markh794 at gmail.com
Wed Aug 20 07:01:44 CEST 2008


Apologies for sending as an attachment... gmail and all.

This is an initial attempt to implement PERSISTENT RESERVE IN and
PERSISTENT RESERVE OUT.

Currently only READ KEY service action will actually return anything.
It returns a hard-coded 'ABC1234'.

This post is a request for comment before I get too far into coding effort.

# lsscsi -g
[3:0:0:0]    disk    USB-HS   HTS726060M9AT00  0.01  /dev/sda  /dev/sg0
[7:0:0:0]    storage IET      Controller       0001  -         /dev/sg1
[7:0:0:1]    disk    QUANTUM  HD100            0010  /dev/sdb  /dev/sg2
[7:0:0:2]    tape    QUANTUM  DLT6000          0010  /dev/st0  /dev/sg3
[7:0:0:3]    tape    QUANTUM  DLT6000          0010  /dev/st1  /dev/sg4
[7:0:0:4]    tape    QUANTUM  DLT6000          0010  /dev/st2  /dev/sg5
[7:0:0:5]    mediumx STK      L700             0010  -         /dev/sg6

# sg_persist -i /dev/sg3
>> No service action given; assume Persistent Reservations In command
>> with Read Keys service action
  QUANTUM  DLT6000  0010
  Peripheral device type: tape
  PR generation=0x0, 4 registered reservation keys follow:
    0x4142433132333400
    0x0
    0x0
    0x0


I'll include in-line for viewing pleasure :)

[PATCH 1/2]
>From 11ad9ee209708f51bd2884598d309b1e7079cdce Mon Sep 17 00:00:00 2001
From: Mark Harvey <markh794 at gmail.com>
Date: Wed, 20 Aug 2008 14:42:27 +1000
Subject: RFC - Implement PERSISTENT RESERVE IN/OUT

Implement service action 'READ KEY' which returns
a hard-coded string 'ABC1234'

Signed-off-by: Mark Harvey <markh794 at gmail.com>
---
 usr/scsi.h |    5 ++
 usr/spc.c  |  231 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 usr/spc.h  |    2 +
 usr/tgtd.h |   13 ++++
 4 files changed, 251 insertions(+), 0 deletions(-)

diff --git a/usr/scsi.h b/usr/scsi.h
index 84fadff..a9481a1 100644
--- a/usr/scsi.h
+++ b/usr/scsi.h
@@ -208,6 +208,11 @@
 #define ASC_POSITION_PAST_BOM			0x3b0c
 #define ASC_MEDIUM_REMOVAL_PREVENTED		0x5302
 #define ASC_BAD_MICROCODE_DETECTED		0x8283
+#define ASC_INSUFFICENT_RESERVE_RESOURCE	0x5502
+#define ASC_INSUFFICENT_RESOURCE		0x5503
+#define ASC_INSUFFICENT_REGISTRAT_RESOURCE	0x5504
+#define ASC_INSUFFICENT_AC_RESOURCE		0x5505
+#define ASC_AUX_MEMORY_OUT_OF_SPACE		0x5506

 /* Key 6: Unit Attention */
 #define ASC_NOT_READY_TO_TRANSITION		0x2800
diff --git a/usr/spc.c b/usr/spc.c
index bd2c975..cc088bf 100644
--- a/usr/spc.c
+++ b/usr/spc.c
@@ -880,6 +880,237 @@ void dump_cdb(struct scsi_cmd *cmd)
 	}
 }

+/**
+ * SCSI Persistent Reservation
+ *
+ * Reference: spc4r16 Ch 5.7
+ *
+ * Interesting points:
+ *  - Persistent reservations are not reset by hard reset, lu reset ot I_T loss
+ *  - Optionally, may be retained when power to target is lost
+ */
+
+/**
+ * PERSISTENT RESERVE IN - 5Eh
+ * Ref: 6.13
+ *
+ */
+#define PR_IN_READ_KEYS 0
+#define PR_IN_READ_RESERVATION 1
+#define PR_IN_REPORT_CAPABILITIES 2
+#define PR_IN_READ_FULL_STATUS 3
+static int spc_pr_read_keys(int host_no, struct scsi_cmd *cmd)
+{
+	uint8_t *buf;
+	int len;
+	int cdb_alloc_len;
+	struct scsi_pr *pr;
+
+	cdb_alloc_len = ((cmd->scb[7] & 0xff) << 8) | (cmd->scb[8] & 0xff);
+
+	dprintf("**** Called ****\n");
+	pr = &cmd->dev->pr;
+
+	buf = scsi_get_in_buffer(cmd);
+	len = sizeof(cmd->dev->pr.pr_key);
+	memset(buf, 0, len + 8);
+
+	dprintf("Buf: %p, len: %d, cdb_alloc_len: %d\n",
+			 buf, len, cdb_alloc_len);
+
+	buf[0] = (pr->PRgeneration >> 24) & 0xff;
+	buf[1] = (pr->PRgeneration >> 16) & 0xff;
+	buf[2] = (pr->PRgeneration >>  8) & 0xff;
+	buf[3] = pr->PRgeneration & 0xff;
+	buf[4] = (len >> 24) & 0xff;
+	buf[5] = (len >> 16) & 0xff;
+	buf[6] = (len >>  8) & 0xff;
+	buf[7] = len & 0xff;
+
+	strcpy(buf + 8, "ABC1234");
+	memcpy(scsi_get_in_buffer(cmd), buf, min(cdb_alloc_len, len + 8));
+
+	scsi_set_in_resid_by_actual(cmd, len + 8);
+
+	return SAM_STAT_GOOD;
+}
+
+static int spc_pr_read_reservation(int host_no, struct scsi_cmd *cmd)
+{
+	dprintf("**** Called ****\n");
+	sense_data_build(cmd, ILLEGAL_REQUEST, ASC_INVALID_OP_CODE);
+	return SAM_STAT_CHECK_CONDITION;
+}
+
+static int spc_pr_report_capabilities(int host_no, struct scsi_cmd *cmd)
+{
+	dprintf("**** Called ****\n");
+	sense_data_build(cmd, ILLEGAL_REQUEST, ASC_INVALID_OP_CODE);
+	return SAM_STAT_CHECK_CONDITION;
+}
+
+static int spc_pr_read_full_status(int host_no, struct scsi_cmd *cmd)
+{
+	dprintf("**** Called ****\n");
+	sense_data_build(cmd, ILLEGAL_REQUEST, ASC_INVALID_OP_CODE);
+	return SAM_STAT_CHECK_CONDITION;
+}
+
+struct service_action pr_in_service_actions[] = {
+	{PR_IN_READ_KEYS, spc_pr_read_keys},
+	{PR_IN_READ_RESERVATION, spc_pr_read_reservation},
+	{PR_IN_REPORT_CAPABILITIES, spc_pr_report_capabilities},
+	{PR_IN_READ_FULL_STATUS, spc_pr_read_full_status},
+	{0, NULL}
+};
+
+int persistent_reserve_in(int host_no, struct scsi_cmd *cmd)
+{
+	uint8_t action;
+	struct service_action *service_action;
+
+	action = cmd->scb[1] & 0x1f;
+	service_action = find_service_action(pr_in_service_actions, action);
+
+	if (!service_action) {
+		scsi_set_in_resid_by_actual(cmd, 0);
+		sense_data_build(cmd, ILLEGAL_REQUEST,
+				ASC_INVALID_FIELD_IN_CDB);
+		return SAM_STAT_CHECK_CONDITION;
+	}
+
+	return service_action->cmd_perform(host_no, cmd);
+}
+
+/**
+ * PERSISTENT RESERVE OUT - 5Fh
+ * Ref: 6.14
+ */
+#define PR_OUT_REGISTER 0
+#define PR_OUT_RESERVE 1
+#define PR_OUT_RELEASE 2
+#define PR_OUT_CLEAR 3
+#define PR_OUT_PREEMPT 4
+#define PR_OUT_PREEMPT_ABORT 5
+#define PR_OUT_REGISTER_IGNORE 6
+#define PR_OUT_REGISTER_MOVE 7
+
+static int spc_pr_register(int host_no, struct scsi_cmd *cmd)
+{
+	struct scsi_pr *pr;
+
+	dprintf("**** Called ****\n");
+	pr = &cmd->dev->pr;
+	pr->PRgeneration += 1;
+
+	sense_data_build(cmd, ILLEGAL_REQUEST, ASC_INVALID_OP_CODE);
+	return SAM_STAT_CHECK_CONDITION;
+}
+
+static int spc_pr_reserve(int host_no, struct scsi_cmd *cmd)
+{
+	dprintf("**** Called ****\n");
+	sense_data_build(cmd, ILLEGAL_REQUEST, ASC_INVALID_OP_CODE);
+	return SAM_STAT_CHECK_CONDITION;
+}
+
+static int spc_pr_release(int host_no, struct scsi_cmd *cmd)
+{
+	dprintf("**** Called ****\n");
+	sense_data_build(cmd, ILLEGAL_REQUEST, ASC_INVALID_OP_CODE);
+	return SAM_STAT_CHECK_CONDITION;
+}
+
+static int spc_pr_clear(int host_no, struct scsi_cmd *cmd)
+{
+	struct scsi_pr *pr;
+
+	dprintf("**** Called ****\n");
+	pr = &cmd->dev->pr;
+	pr->PRgeneration += 1;
+
+	sense_data_build(cmd, ILLEGAL_REQUEST, ASC_INVALID_OP_CODE);
+	return SAM_STAT_CHECK_CONDITION;
+}
+
+static int spc_pr_preempt(int host_no, struct scsi_cmd *cmd)
+{
+	struct scsi_pr *pr;
+
+	dprintf("**** Called ****\n");
+	pr = &cmd->dev->pr;
+	pr->PRgeneration += 1;
+
+	sense_data_build(cmd, ILLEGAL_REQUEST, ASC_INVALID_OP_CODE);
+	return SAM_STAT_CHECK_CONDITION;
+}
+
+static int spc_pr_preempt_abort(int host_no, struct scsi_cmd *cmd)
+{
+	struct scsi_pr *pr;
+
+	dprintf("**** Called ****\n");
+	pr = &cmd->dev->pr;
+	pr->PRgeneration += 1;
+
+	sense_data_build(cmd, ILLEGAL_REQUEST, ASC_INVALID_OP_CODE);
+	return SAM_STAT_CHECK_CONDITION;
+}
+
+static int spc_pr_register_ignore(int host_no, struct scsi_cmd *cmd)
+{
+	struct scsi_pr *pr;
+
+	dprintf("**** Called ****\n");
+	pr = &cmd->dev->pr;
+	pr->PRgeneration += 1;
+
+	sense_data_build(cmd, ILLEGAL_REQUEST, ASC_INVALID_OP_CODE);
+	return SAM_STAT_CHECK_CONDITION;
+}
+
+static int spc_pr_register_move(int host_no, struct scsi_cmd *cmd)
+{
+	struct scsi_pr *pr;
+
+	dprintf("**** Called ****\n");
+	pr = &cmd->dev->pr;
+	pr->PRgeneration += 1;
+
+	sense_data_build(cmd, ILLEGAL_REQUEST, ASC_INVALID_OP_CODE);
+	return SAM_STAT_CHECK_CONDITION;
+}
+
+struct service_action pr_out_service_actions[] = {
+	{PR_OUT_REGISTER, spc_pr_register},
+	{PR_OUT_RESERVE, spc_pr_reserve},
+	{PR_OUT_RELEASE, spc_pr_release},
+	{PR_OUT_CLEAR, spc_pr_clear},
+	{PR_OUT_PREEMPT, spc_pr_preempt},
+	{PR_OUT_PREEMPT_ABORT, spc_pr_preempt_abort},
+	{PR_OUT_REGISTER_IGNORE, spc_pr_register_ignore},
+	{PR_OUT_REGISTER_MOVE, spc_pr_register_move},
+	{0, NULL}
+};
+
+int persistent_reserve_out(int host_no, struct scsi_cmd *cmd)
+{
+	uint8_t action;
+	struct service_action *service_action;
+
+	action = cmd->scb[1] & 0x1f;
+	service_action = find_service_action(pr_out_service_actions, action);
+
+	if (!service_action) {
+		scsi_set_in_resid_by_actual(cmd, 0);
+		sense_data_build(cmd, ILLEGAL_REQUEST,
+				ASC_INVALID_FIELD_IN_CDB);
+		return SAM_STAT_CHECK_CONDITION;
+	}
+
+	return service_action->cmd_perform(host_no, cmd);
+}
+
 int spc_illegal_op(int host_no, struct scsi_cmd *cmd)
 {
 	dump_cdb(cmd);
diff --git a/usr/spc.h b/usr/spc.h
index 8fe3e3c..bdc3c1f 100644
--- a/usr/spc.h
+++ b/usr/spc.h
@@ -9,6 +9,8 @@ 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 persistent_reserve_in(int host_no, struct scsi_cmd *cmd);
+extern int persistent_reserve_out(int host_no, struct scsi_cmd *cmd);
 extern int spc_lu_init(struct scsi_lu *lu);

 typedef int (match_fn_t)(struct scsi_lu *lu, char *params);
diff --git a/usr/tgtd.h b/usr/tgtd.h
index 4febcd3..d2c7135 100644
--- a/usr/tgtd.h
+++ b/usr/tgtd.h
@@ -19,6 +19,11 @@

 #define VENDOR_ID	"IET"

+/* 8 byte reservation key size */
+#define PR_KEY_SZ 8
+/* Number of PR keys we can store at any one time */
+#define PR_RESERVATION_SZ 4
+
 #define _TAB1 "    "
 #define _TAB2 _TAB1 _TAB1
 #define _TAB3 _TAB1 _TAB1 _TAB1
@@ -126,6 +131,12 @@ struct mode_pg {
 	uint8_t mode_data[0];	/* Rest of mode page info */
 };

+struct scsi_pr {
+	/* Persistent Reservation Generation */
+	uint32_t PRgeneration;
+	uint8_t pr_key[PR_RESERVATION_SZ][PR_KEY_SZ];
+};
+
 struct scsi_lu {
 	int fd;
 	uint64_t addr; /* persistent mapped address */
@@ -150,6 +161,8 @@ struct scsi_lu {
 	uint8_t	mode_block_descriptor[BLOCK_DESCRIPTOR_LEN];
 	struct mode_pg *mode_pgs[0x3f];

+	struct scsi_pr pr;
+
 	struct lu_phy_attr attrs;

 	/* A pointer for each modules private use.
-- 
1.5.6

[PATCH 2/2]
>From 68c454d2d7f1b64f9dbce9410e5c2c8500d6ceb3 Mon Sep 17 00:00:00 2001
From: Mark Harvey <markh794 at gmail.com>
Date: Wed, 20 Aug 2008 14:45:30 +1000
Subject: Add persistent reserve in/out to ssc module

Signed-off-by: Mark Harvey <markh794 at gmail.com>
---
 usr/ssc.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/usr/ssc.c b/usr/ssc.c
index 2630a6a..6dbdc0b 100644
--- a/usr/ssc.c
+++ b/usr/ssc.c
@@ -251,8 +251,8 @@ static struct device_type_template ssc_template = {
 		{spc_illegal_op,},
 		{spc_illegal_op,},
 		{spc_illegal_op,},
-		{spc_illegal_op,},
-		{spc_illegal_op,},
+		{persistent_reserve_in,},
+		{persistent_reserve_out,},

 		[0x60 ... 0x7f] = {spc_illegal_op,},

-- 
1.5.6
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-RFC-Implement-PERSISTENT-RESERVE-IN-OUT.patch
Type: application/octet-stream
Size: 8816 bytes
Desc: not available
URL: <http://lists.wpkg.org/pipermail/stgt/attachments/20080820/50a54c25/attachment.obj>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0002-Add-persistent-reserve-in-out-to-ssc-module.patch
Type: application/octet-stream
Size: 720 bytes
Desc: not available
URL: <http://lists.wpkg.org/pipermail/stgt/attachments/20080820/50a54c25/attachment-0001.obj>


More information about the stgt mailing list