Tomo, List Please find attached a patch to implement PAMR and SSU. PAMR adds a new LUN attribute to track the removable state of a device. A device that is "revent removal" can not be made offline by tgtadm. In this case tgtadm will fail with a new errorcode. Implement SSU and implement "eject" and "load". Devices that are locked in "prevent removal" can not be "ejected" by SSU. In this case SSU will fail with a check-condition. If a device is "ejected" by SSU, we also automatically flag the device as offline. regards ronnie sahlberg
Attachment:
0001-Add-PREVENT-ALLOW-MEDIUM-REMOVAL-and-START-STOP-UNIT.patch.gz
Description: GNU Zip compressed data
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(-) diff --git a/doc/tgtadm.8.xml b/doc/tgtadm.8.xml index a2dd394..d547d58 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 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..3e75ce8 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 (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; + } + 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,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, @@ -1665,6 +1691,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; } @@ -1744,9 +1773,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