[PATCH] Implement Prevent/AllowMediumRemoval for MMC devices

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

 



List, Tomo,

Please find attach an experimental patch to add
Prevent/AllowMediumRemoval emulation for MMC style devices.

For MMC style devices we use the "Offline" attribute to represent "no
media loaded".
If an initiator has set the "Prevent" bit via the
Prevent/AllowMediumRemoval CDB we will not allow
tgtadm to change the device to offline, instead it will fail with a
new error code.

Similarly, if an initiator sends a Start/StopUnit CDB requesting the
media to be ejected.
If the Prevent bit is set we will fail this with a check-condition.



Comments?

regards
ronnie sahlberg
From c3547d370e4f7258db1ffe6c5c1cc233923d6dac Mon Sep 17 00:00:00 2001
From: Ronnie Sahlberg <ronniesahlberg@xxxxxxxxx>
Date: Fri, 20 Jan 2012 08:48:55 +1100
Subject: [PATCH] Implement PREVENT/ALLOW MEDIUM REMOVAL for MMC

Add a new attribute for a lun to describe the prevent state.
A device that has the Prevent bit set can not be made offline
(offline == no media in drive   for MMC emulation)

Also update Start/Stop Unit to not allow "eject" of media when
Prevent is set.

Signed-off-by: Ronnie Sahlberg <ronniesahlberg@xxxxxxxxx>
---
 doc/tgtadm.8.xml   |   47 +++++++++++++++++++++++++++++++++++++++++++++++
 usr/mmc.c          |    5 ++++-
 usr/sbc.c          |    2 +-
 usr/spc.c          |   39 ++++++++++++++++++++++++++++++++-------
 usr/target.c       |   15 +++++++++++++--
 usr/tgtadm.c       |    4 +++-
 usr/tgtadm_error.h |    2 ++
 usr/tgtd.h         |    5 +++++
 8 files changed, 107 insertions(+), 12 deletions(-)

diff --git a/doc/tgtadm.8.xml b/doc/tgtadm.8.xml
index a2dd394..6eec214 100644
--- a/doc/tgtadm.8.xml
+++ b/doc/tgtadm.8.xml
@@ -671,6 +671,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 error.
+    </para>
+    <para>
+      Devices can not be set to Offline mode while there are "PREVENT ALLOW MEDIUM REMOVAL"
+      locks on the device.
+    </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 MMC (CD/DVD) 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..5545743 100644
--- a/usr/mmc.c
+++ b/usr/mmc.c
@@ -2296,6 +2296,9 @@ static int mmc_lu_online(struct scsi_lu *lu)
 
 static int mmc_lu_offline(struct scsi_lu *lu)
 {
+	if (lu->attrs.prevent & PREVENT_REMOVAL)
+		return TGTADM_PREVENT_REMOVAL;
+
 	lu->attrs.online = 0;
 	return 0;
 }
@@ -2342,7 +2345,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 9666801..ee4b538 100644
--- a/usr/sbc.c
+++ b/usr/sbc.c
@@ -380,7 +380,7 @@ static struct device_type_template sbc_template = {
 		{spc_start_stop, NULL, PR_SPECIAL},
 		{spc_illegal_op,},
 		{spc_illegal_op,},
-		{spc_illegal_op,},
+		{spc_prevent_allow_media_removal,},
 		{spc_illegal_op,},
 
 		/* 0x20 */
diff --git a/usr/spc.c b/usr/spc.c
index eba4857..86eef1a 100644
--- a/usr/spc.c
+++ b/usr/spc.c
@@ -309,12 +309,32 @@ 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
+		&& (cmd->dev->attrs.prevent & PREVENT_REMOVAL)) {
+		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;
+	}
+
+	return SAM_STAT_GOOD;
 }
 
 int spc_test_unit(int host_no, struct scsi_cmd *cmd)
@@ -335,12 +355,14 @@ 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;
 
 	if (device_reserved(cmd))
 		return SAM_STAT_RESERVATION_CONFLICT;
-	else
-		return SAM_STAT_GOOD;
+
+	cmd->dev->attrs.prevent = scb[4] & PREVENT_MASK;
+
+	return SAM_STAT_GOOD;
 }
 
 int spc_mode_select(int host_no, struct scsi_cmd *cmd,
@@ -1649,6 +1671,9 @@ int spc_lu_online(struct scsi_lu *lu)
 
 int spc_lu_offline(struct scsi_lu *lu)
 {
+	if (lu->attrs.prevent & PREVENT_REMOVAL)
+		return TGTADM_PREVENT_REMOVAL;
+
 	lu->attrs.online = 0;
 	return 0;
 }
@@ -1728,9 +1753,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 dd4b358..4411a01 100644
--- a/usr/target.c
+++ b/usr/target.c
@@ -375,10 +375,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 +760,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 +1806,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 +1819,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->attrs.prevent & PREVENT_REMOVAL ?
+					"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 7dca0f8..d0147d9 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..8a0e511 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];
@@ -64,6 +68,7 @@ struct lu_phy_attr {
 	unsigned char device_type; /* Peripheral device type */
 	char qualifier;		/* Peripheral Qualifier */
 	char removable;		/* Removable media */
+	char prevent;		/* Prevent/Allow removal */
 	char readonly;          /* Read-Only media */
 	char online;		/* Logical Unit online */
 	char sense_format;	/* Descrptor format sense data supported */
-- 
1.7.3.1

Attachment: 0001-Implement-PREVENT-ALLOW-MEDIUM-REMOVAL-for-MMC.patch.gz
Description: GNU Zip compressed data


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

  Powered by Linux