Re: [PATCH] Add support for PREVENT/ALLOWMEDIUMREMOVAL and STARTSTOPUNIT

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Tomo,

Please have a look at this patch.

It hangs a "prevent" field off the itl nexus.
As long as at least one itl nexus have "prevent" set
we will not allow startstopunit to eject the media.


regards
ronnie sahlberg


On Sat, Jan 28, 2012 at 2:34 PM, ronnie sahlberg
<ronniesahlberg@xxxxxxxxx> wrote:
> Yes  you are right.
>
> Should do it right or not at all.
> I will look into doing this tomorrow.
>
> regards
> ronnie sahlberg
>
>
> On Sat, Jan 28, 2012 at 4:04 AM, FUJITA Tomonori
> <fujita.tomonori@xxxxxxxxxxxxx> wrote:
>> On Sat, 28 Jan 2012 01:16:41 +0900
>> FUJITA Tomonori <fujita.tomonori@xxxxxxxxxxxxx> wrote:
>>
>>> On Fri, 27 Jan 2012 16:12:20 +1100
>>> ronnie sahlberg <ronniesahlberg@xxxxxxxxx> wrote:
>>>
>>> > From 17fdaf426120d6167b7f14068d7c6f4ca0322217 Mon Sep 17 00:00:00 2001
>>> > From: Ronnie Sahlberg <ronniesahlberg@xxxxxxxxx>
>>> > Date: Fri, 27 Jan 2012 16:07:00 +1100
>>> > Subject: [PATCH] Add PREVENT/ALLOW MEDIUM REMOVAL and START STOP UNIT
>>> >
>>> > Implement logic for PAMR and SSU.
>>> >
>>> > Add a new attribute .prevent to track the allow prevent removal status of a LUN.
>>> > Implement PAMR and update the LUN attribute accordingly.
>>> >
>>> > Units where PAMR is set to prevent removal of the device can not be
>>> > made offline using tgtadm. Attempts to make the unit offline
>>> > will fail with a new TGTADM error to indicate there is a PAMR lock on the device.
>>> >
>>> > SSU attempts to "eject" the media will fail with a check condition
>>> > if the media is locked by PAMR.
>>> >
>>> > If SSU successfully "ejects" the media, we automatically set the LUN to "Offline".
>>> >
>>> > Update tgt_target_show_all() to show the PreventRemoval status for the LUN in the output.
>>> >
>>> > Signed-off-by: Ronnie Sahlberg <ronniesahlberg@xxxxxxxxx>
>>> > ---
>>> >  doc/tgtadm.8.xml   |   47 +++++++++++++++++++++++++++++++++++++++++++++++
>>> >  usr/mmc.c          |   10 ++--------
>>> >  usr/sbc.c          |    2 +-
>>> >  usr/spc.c          |   43 ++++++++++++++++++++++++++++++++++++-------
>>> >  usr/target.c       |   15 +++++++++++++--
>>> >  usr/tgtadm.c       |    4 +++-
>>> >  usr/tgtadm_error.h |    2 ++
>>> >  usr/tgtd.h         |    5 +++++
>>> >  8 files changed, 109 insertions(+), 19 deletions(-)
>>>
>>> Thanks a lot! Another "TODO: implement properly" comment removal!
>>>
>>> SPC3 says:
>>>
>>> The prevention of medium removal shall begin when any application
>>> client issues a PREVENT ALLOW MEDIUM REMOVAL command with a PREVENT
>>> field of 01b or 11b (i.e., medium removal prevented). The prevention
>>> of medium removal for the logical unit shall terminate after:
>>>
>>> a) One of the following occurs for each I_T nexus that previously had
>>> medium removal prevented:
>>>    A) Receipt of a PREVENT ALLOW MEDIUM REMOVAL command with a PREVENT
>>>    field of 00b or 10b;
>>>    B) An I_T nexus loss; or
>>>
>>> With the current code, even an I_T nexus that previously had NOT
>>> medium removal prevented can terminate the prevention of medium
>>> removal? Is that against the spec, No?
>>
>> And of course, we need to terminate the prevention of medium removal
>> when the I_T nexus that previously had medium removal prevented
>> loses. So I guess that we need some data structures per nexus for this
>> feature.

Attachment: 0001-Implement-PreventAllowMeduimRemoval-and-StartStopUni.patch.gz
Description: GNU Zip compressed data

From f8aeb1f4da2a2d86a6c75fd6f3435ced39d08dec Mon Sep 17 00:00:00 2001
From: Ronnie Sahlberg <ronniesahlberg@xxxxxxxxx>
Date: Mon, 30 Jan 2012 22:58:21 +1100
Subject: [PATCH] Implement PreventAllowMeduimRemoval and StartStopUnit

This patch adds support for the two opcodes
PreventAllowMediom Removeal
and
StartStopUnit

Signed-off-by: Ronnie Sahlberg <ronniesahlberg@xxxxxxxxx>
---
 doc/tgtadm.8.xml   |   47 +++++++++++++++++++++++++++++++++++++++++++++++
 usr/mmc.c          |   10 ++--------
 usr/sbc.c          |    2 +-
 usr/spc.c          |   44 +++++++++++++++++++++++++++++++++++++-------
 usr/target.c       |   32 ++++++++++++++++++++++++++++++--
 usr/tgtadm.c       |    4 +++-
 usr/tgtadm_error.h |    2 ++
 usr/tgtd.h         |    7 +++++++
 8 files changed, 129 insertions(+), 19 deletions(-)

diff --git a/doc/tgtadm.8.xml b/doc/tgtadm.8.xml
index f0710ac..ee973ba 100644
--- a/doc/tgtadm.8.xml
+++ b/doc/tgtadm.8.xml
@@ -681,6 +681,53 @@ tgtadm --lld iscsi --op delete --mode conn --tid 1 --sid 2 --cid 0
   </refsect1>
 
 
+
+  <refsect1><title>Online/Offline Status</title>
+    <para>
+      Tgtd LUNs can be in online or offline status. LUNs that are Offline behave slightly different 
+      depending on the device type. Offline devices behave as if there is no media available and any
+      operations that access media will fail with an check-condition error.
+    </para>
+    <para>
+      Devices can not be set to Offline mode while there are "PREVENT ALLOW MEDIUM REMOVAL"
+      locks on the device. Similarly media in Online devices can not be software ejected while there are such locks on the device (the 'eject' command will fail).
+    </para>
+    <refsect2><title>Show Online/Offline status</title>
+      <para>
+	Finding the Online/Offline status of a LUN is done through the tgtd command. If "Prevent removal"
+	is "Yes" this indicates that an application holds a "prevent media removal" lock on the device.
+      </para>
+      <screen format="linespecific">
+tgtadm --lld iscsi --mode target --op show
+...
+        LUN: 2
+            Type: cd/dvd
+            SCSI ID: IET     00010002
+            SCSI SN: beaf12
+            Size: 3432 MB, Block size: 1
+            Online: Yes
+            Removable media: Yes
+            Prevent removal: Yes
+...
+      </screen>
+    </refsect2>
+    <refsect2><title>Changing a LUN to Offline</title>
+      <para>
+	A LUN is changed to Offline status using the tgtadm command.
+	When devices are set Offline these devices will behave as if there is no media
+	loaded into the drive.
+      </para>
+      <para>
+	Change a LUN to become offline. (no disk in the drive)
+      </para>
+      <screen format="linespecific">
+tgtadm --tid 1 --lun 2 --op update --mode logicalunit -P Online=No
+      </screen>
+
+    </refsect2>
+  </refsect1>
+
+
   <refsect1><title>iSNS PARAMETERS</title>
     <para>
       iSNS configuration for a target is by using the tgtadm command.
diff --git a/usr/mmc.c b/usr/mmc.c
index 3279c3d..c50c3c0 100644
--- a/usr/mmc.c
+++ b/usr/mmc.c
@@ -2294,18 +2294,12 @@ static int mmc_lu_online(struct scsi_lu *lu)
 	return 0;
 }
 
-static int mmc_lu_offline(struct scsi_lu *lu)
-{
-	lu->attrs.online = 0;
-	return 0;
-}
-
 static struct device_type_template mmc_template = {
 	.type		= TYPE_MMC,
 	.lu_init	= mmc_lu_init,
 	.lu_config	= spc_lu_config,
 	.lu_online	= mmc_lu_online,
-	.lu_offline	= mmc_lu_offline,
+	.lu_offline	= spc_lu_offline,
 	.lu_exit	= spc_lu_exit,
 	.ops		= {
 		{spc_test_unit,},
@@ -2342,7 +2336,7 @@ static struct device_type_template mmc_template = {
 		{spc_start_stop,},
 		{spc_illegal_op,},
 		{spc_illegal_op,},
-		{spc_start_stop,}, /* allow medium removal */
+		{spc_prevent_allow_media_removal,},
 		{spc_illegal_op,},
 
 		/* 0x20 */
diff --git a/usr/sbc.c b/usr/sbc.c
index b96cc7a..24aaddb 100644
--- a/usr/sbc.c
+++ b/usr/sbc.c
@@ -506,7 +506,7 @@ static struct device_type_template sbc_template = {
 		{spc_start_stop, NULL, PR_SPECIAL},
 		{spc_illegal_op,},
 		{spc_send_diagnostics,},
-		{spc_illegal_op,},
+		{spc_prevent_allow_media_removal,},
 		{spc_illegal_op,},
 
 		/* 0x20 */
diff --git a/usr/spc.c b/usr/spc.c
index 8b5ecaa..7ff7834 100644
--- a/usr/spc.c
+++ b/usr/spc.c
@@ -309,12 +309,36 @@ sense:
 
 int spc_start_stop(int host_no, struct scsi_cmd *cmd)
 {
+	uint8_t *scb = cmd->scb;
+	int start, loej;
+
 	scsi_set_in_resid_by_actual(cmd, 0);
 
 	if (device_reserved(cmd))
 		return SAM_STAT_RESERVATION_CONFLICT;
-	else
-		return SAM_STAT_GOOD;
+
+	loej  = scb[4] & 0x02;
+	start = scb[4] & 0x01;
+
+	if (loej == 1 && start == 0) {
+		if (lu_prevent_removal(cmd->dev)) {
+			if (cmd->dev->attrs.online) {
+				/*  online == media is present */
+				sense_data_build(cmd, ILLEGAL_REQUEST,
+					ASC_MEDIUM_REMOVAL_PREVENTED);
+			} else {
+				/* !online == media is not present */
+				sense_data_build(cmd, NOT_READY,
+				ASC_MEDIUM_REMOVAL_PREVENTED);
+			}
+			return SAM_STAT_CHECK_CONDITION;
+		}
+		spc_lu_offline(cmd->dev);
+	}
+	if (loej == 1 && start == 1)
+		spc_lu_online(cmd->dev);
+
+	return SAM_STAT_GOOD;
 }
 
 int spc_test_unit(int host_no, struct scsi_cmd *cmd)
@@ -335,12 +359,15 @@ int spc_test_unit(int host_no, struct scsi_cmd *cmd)
 
 int spc_prevent_allow_media_removal(int host_no, struct scsi_cmd *cmd)
 {
-	/* TODO: implement properly */
+	uint8_t *scb = cmd->scb;
+	struct it_nexus_lu_info *itn_lu_info = cmd->itn_lu_info;
 
 	if (device_reserved(cmd))
 		return SAM_STAT_RESERVATION_CONFLICT;
-	else
-		return SAM_STAT_GOOD;
+
+	itn_lu_info->prevent = scb[4] & PREVENT_MASK;
+
+	return SAM_STAT_GOOD;
 }
 
 int spc_mode_select(int host_no, struct scsi_cmd *cmd,
@@ -1665,6 +1692,9 @@ int spc_lu_online(struct scsi_lu *lu)
 
 int spc_lu_offline(struct scsi_lu *lu)
 {
+	if (lu_prevent_removal(lu))
+		return TGTADM_PREVENT_REMOVAL;
+
 	lu->attrs.online = 0;
 	return 0;
 }
@@ -1744,9 +1774,9 @@ int lu_config(struct scsi_lu *lu, char *params, match_fn_t *fn)
 		case Opt_online:
 			match_strncpy(buf, &args[0], sizeof(buf));
 			if (atoi(buf))
-				lu->dev_type_template.lu_online(lu);
+				err |= lu->dev_type_template.lu_online(lu);
 			else
-				lu->dev_type_template.lu_offline(lu);
+				err |= lu->dev_type_template.lu_offline(lu);
 			break;
 		case Opt_mode_page:
 			match_strncpy(buf, &args[0], sizeof(buf));
diff --git a/usr/target.c b/usr/target.c
index fad6801..daa115b 100644
--- a/usr/target.c
+++ b/usr/target.c
@@ -261,6 +261,23 @@ void ua_sense_add_it_nexus(uint64_t itn_id, struct scsi_lu *lu,
 	}
 }
 
+int lu_prevent_removal(struct scsi_lu *lu)
+{
+	struct it_nexus *itn;
+	struct it_nexus_lu_info *itn_lu;
+
+	list_for_each_entry(itn, &lu->tgt->it_nexus_list, nexus_siblings) {
+		list_for_each_entry(itn_lu, &itn->it_nexus_lu_info_list,
+				    lu_info_siblings) {
+			if (itn_lu->lu == lu) {
+				if (itn_lu->prevent & PREVENT_REMOVAL)
+					return 1;
+			}
+		}
+	}
+	return 0;
+}
+
 int it_nexus_create(int tid, uint64_t itn_id, int host_no, char *info)
 {
 	int ret;
@@ -375,10 +392,15 @@ int tgt_device_path_update(struct target *target, struct scsi_lu *lu, char *path
 	uint64_t size;
 
 	if (lu->path) {
+		int ret;
+
 		if (lu->attrs.online)
 			return TGTADM_INVALID_REQUEST;
 
-		lu->dev_type_template.lu_offline(lu);
+		ret = lu->dev_type_template.lu_offline(lu);
+		if (ret)
+			return ret;
+
 		lu->bst->bs_close(lu);
 		free(lu->path);
 		lu->fd = 0;
@@ -755,7 +777,10 @@ int dtd_load_unload(int tid, uint64_t lun, int load, char *file)
 
 	lu->size = 0;
 	lu->fd = 0;
-	lu->dev_type_template.lu_offline(lu);
+
+	err = lu->dev_type_template.lu_offline(lu);
+	if (err)
+		return err;
 
 	if (load) {
 		lu->path = strdup(file);
@@ -1798,6 +1823,7 @@ int tgt_target_show_all(char *buf, int rest)
 				 _TAB3 "Size: %s, Block size: %d\n"
 				 _TAB3 "Online: %s\n"
 				 _TAB3 "Removable media: %s\n"
+				 _TAB3 "Prevent removal: %s\n"
 				 _TAB3 "Readonly: %s\n"
 				 _TAB3 "Backing store type: %s\n"
 				 _TAB3 "Backing store path: %s\n"
@@ -1810,6 +1836,8 @@ int tgt_target_show_all(char *buf, int rest)
 				 1U << lu->blk_shift,
 				 lu->attrs.online ? "Yes" : "No",
 				 lu->attrs.removable ? "Yes" : "No",
+				 lu_prevent_removal(lu) ?
+					"Yes" : "No",
 				 lu->attrs.readonly ? "Yes" : "No",
 				 lu->bst ?
 					(lu->bst->bs_name ? : "Unknown") :
diff --git a/usr/tgtadm.c b/usr/tgtadm.c
index 26c82bc..ba23c3a 100644
--- a/usr/tgtadm.c
+++ b/usr/tgtadm.c
@@ -77,7 +77,9 @@ static const char * tgtadm_strerror(int err)
 		{ TGTADM_LUN_ACTIVE, "this logical unit is still active" },
 		{ TGTADM_UNSUPPORTED_OPERATION,
 		  "this operation isn't supported" },
-		{ TGTADM_UNKNOWN_PARAM, "unknown parameter" }
+		{ TGTADM_UNKNOWN_PARAM, "unknown parameter" },
+		{ TGTADM_PREVENT_REMOVAL,
+		  "this device has Prevent Removal set" }
 	};
 	int i;
 
diff --git a/usr/tgtadm_error.h b/usr/tgtadm_error.h
index 4cd8f81..3a37a69 100644
--- a/usr/tgtadm_error.h
+++ b/usr/tgtadm_error.h
@@ -26,6 +26,8 @@ enum tgtadm_errno {
 	TGTADM_LUN_ACTIVE,
 	TGTADM_UNSUPPORTED_OPERATION,
 	TGTADM_UNKNOWN_PARAM,
+
+	TGTADM_PREVENT_REMOVAL,
 };
 
 #endif
diff --git a/usr/tgtd.h b/usr/tgtd.h
index 1805f3e..b50a887 100644
--- a/usr/tgtd.h
+++ b/usr/tgtd.h
@@ -51,6 +51,10 @@ struct vpd {
 	uint8_t data[0];
 };
 
+#define PREVENT_REMOVAL			0x01
+#define PREVENT_REMOVAL_PERSISTENT	0x02
+#define PREVENT_MASK			0x03
+
 struct lu_phy_attr {
 	char scsi_id[SCSI_ID_LEN + 1];
 	char scsi_sn[SCSI_SN_LEN + 1];
@@ -85,6 +89,7 @@ struct it_nexus_lu_info {
 	struct scsi_lu *lu;
 	struct list_head lu_info_siblings;
 	struct list_head pending_ua_sense_list;
+	int prevent; /* prevent removal on this itl nexus ? */
 };
 
 struct service_action {
@@ -276,6 +281,8 @@ extern void ua_sense_add_other_it_nexus(uint64_t itn_id, struct scsi_lu *lu,
 extern void ua_sense_add_it_nexus(uint64_t itn_id, struct scsi_lu *lu,
 					uint16_t asc);
 
+extern int lu_prevent_removal(struct scsi_lu *lu);
+
 extern uint64_t scsi_get_devid(int lid, uint8_t *pdu);
 extern int scsi_cmd_perform(int host_no, struct scsi_cmd *cmd);
 extern void sense_data_build(struct scsi_cmd *cmd, uint8_t key, uint16_t asc);
-- 
1.7.3.1


[Index of Archives]     [Linux SCSI]     [Linux RAID]     [Linux Clusters]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]

  Powered by Linux