From: Ronnie Sahlberg <ronniesahlberg at gmail.com> Added a device parameter that allows a logical unit to be set to readonly. For DISK devices, this is communicated back to the initiator by setting the WP bit in the device specific byte in the mode sense header. It will also fail any WRITE6/10/12/16 calls with a DATA_PROTECT/ASC_WRITE_PROTECT Signed-off-by: Ronnie Sahlberg <ronniesahlberg at gmail.com> Signed-off-by: Mike Anderson <andmike at linux.vnet.ibm.com> --- doc/tgtadm.8.xml | 16 ++++++++++++++++ usr/sbc.c | 44 ++++++++++++++++++++++++++++++++++++++++++-- usr/spc.c | 8 +++++++- usr/target.c | 2 ++ usr/tgtd.h | 1 + 5 files changed, 68 insertions(+), 3 deletions(-) diff --git a/doc/tgtadm.8.xml b/doc/tgtadm.8.xml index 1191597..92218b7 100644 --- a/doc/tgtadm.8.xml +++ b/doc/tgtadm.8.xml @@ -288,6 +288,22 @@ 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 </screen> + <varlistentry><term><option>readonly=<0|1></option></term> + <listitem> + <para> + This sets the read-only flag of a LUN. A read-only LUN will + refuse any attempts to write data to it. + </para> + <para> + This parameter only applies to DISK devices. + </para> + </listitem> + </varlistentry> + + <screen format="linespecific"> +tgtadm --lld iscsi --mode logicalunit --op update --tid 1 --lun 1 \ + --params readonly=1 + </screen> </variablelist> </refsect1> diff --git a/usr/sbc.c b/usr/sbc.c index b8e6887..3ca2aae 100644 --- a/usr/sbc.c +++ b/usr/sbc.c @@ -72,16 +72,55 @@ static int sbc_mode_select(int host_no, struct scsi_cmd *cmd) return spc_mode_select(host_no, cmd, sbc_mode_page_update); } +static int sbc_mode_sense(int host_no, struct scsi_cmd *cmd) +{ + int ret; + + ret = spc_mode_sense(host_no, cmd); + + /* + * If this is a read-only lun, we must modify the data and set the + * write protect bit + */ + if (cmd->dev->attrs.readonly && ret == SAM_STAT_GOOD) { + uint8_t *data, mode6; + + mode6 = (cmd->scb[0] == 0x1a); + data = scsi_get_in_buffer(cmd); + + if (mode6) + data[2] |= 0x80; + else + data[3] |= 0x80; + } + + return ret; +} + static int sbc_rw(int host_no, struct scsi_cmd *cmd) { int ret; unsigned char key = ILLEGAL_REQUEST; uint16_t asc = ASC_LUN_NOT_SUPPORTED; + struct scsi_lu *lu = cmd->dev; ret = device_reserved(cmd); if (ret) return SAM_STAT_RESERVATION_CONFLICT; + if (lu->attrs.readonly) { + switch (cmd->scb[0]) { + case WRITE_6: + case WRITE_10: + case WRITE_12: + case WRITE_16: + key = DATA_PROTECT; + asc = ASC_WRITE_PROTECT; + goto sense; + break; + } + } + cmd->scsi_cmd_done = target_cmd_io_done; cmd->offset = (scsi_rw_offset(cmd->scb) << BLK_SHIFT); @@ -94,6 +133,7 @@ static int sbc_rw(int host_no, struct scsi_cmd *cmd) return SAM_STAT_GOOD; } +sense: cmd->offset = 0; scsi_set_in_resid_by_actual(cmd, 0); scsi_set_out_resid_by_actual(cmd, 0); @@ -301,7 +341,7 @@ static struct device_type_template sbc_template = { {spc_illegal_op,}, {spc_illegal_op,}, - {spc_mode_sense, NULL, PR_WE_FA|PR_EA_FA|PR_WE_FN|PR_EA_FN}, + {sbc_mode_sense, NULL, PR_WE_FA|PR_EA_FA|PR_WE_FN|PR_EA_FN}, {spc_start_stop, NULL, PR_SPECIAL}, {spc_illegal_op,}, {spc_illegal_op,}, @@ -360,7 +400,7 @@ static struct device_type_template sbc_template = { {spc_illegal_op,}, {spc_illegal_op,}, - {spc_mode_sense, NULL, PR_WE_FA|PR_EA_FA|PR_WE_FN|PR_EA_FN}, + {sbc_mode_sense, NULL, PR_WE_FA|PR_EA_FA|PR_WE_FN|PR_EA_FN}, {spc_illegal_op,}, {spc_illegal_op,}, {spc_illegal_op,}, diff --git a/usr/spc.c b/usr/spc.c index 8257b96..11712de 100644 --- a/usr/spc.c +++ b/usr/spc.c @@ -1578,7 +1578,7 @@ enum { Opt_scsi_id, Opt_scsi_sn, Opt_vendor_id, Opt_product_id, Opt_product_rev, Opt_sense_format, - Opt_removable, Opt_online, + Opt_removable, Opt_readonly, Opt_online, Opt_mode_page, Opt_path, Opt_bsoflags, @@ -1593,6 +1593,7 @@ static match_table_t tokens = { {Opt_product_rev, "product_rev=%s"}, {Opt_sense_format, "sense_format=%s"}, {Opt_removable, "removable=%s"}, + {Opt_readonly, "readonly=%s"}, {Opt_online, "online=%s"}, {Opt_mode_page, "mode_page=%s"}, {Opt_path, "path=%s"}, @@ -1664,6 +1665,10 @@ int lu_config(struct scsi_lu *lu, char *params, match_fn_t *fn) match_strncpy(buf, &args[0], sizeof(buf)); attrs->removable = atoi(buf); break; + case Opt_readonly: + match_strncpy(buf, &args[0], sizeof(buf)); + attrs->readonly = atoi(buf); + break; case Opt_online: match_strncpy(buf, &args[0], sizeof(buf)); if (atoi(buf)) @@ -1722,6 +1727,7 @@ int spc_lu_init(struct scsi_lu *lu) lu_vpd[pg]->vpd_update(lu, lu->attrs.scsi_id); lu->attrs.removable = 0; + lu->attrs.readonly = 0; lu->attrs.sense_format = 0; lu->dev_type_template.lu_offline(lu); diff --git a/usr/target.c b/usr/target.c index 8d6a889..49c241d 100644 --- a/usr/target.c +++ b/usr/target.c @@ -1722,6 +1722,7 @@ int tgt_target_show_all(char *buf, int rest) _TAB3 "Size: %s\n" _TAB3 "Online: %s\n" _TAB3 "Removable media: %s\n" + _TAB3 "Readonly: %s\n" _TAB3 "Backing store type: %s\n" _TAB3 "Backing store path: %s\n" _TAB3 "Backing store flags: %s\n", @@ -1732,6 +1733,7 @@ int tgt_target_show_all(char *buf, int rest) print_disksize(lu->size), lu->attrs.online ? "Yes" : "No", lu->attrs.removable ? "Yes" : "No", + lu->attrs.readonly ? "Yes" : "No", lu->bst ? (lu->bst->bs_name ? : "Unknown") : "None", diff --git a/usr/tgtd.h b/usr/tgtd.h index 09c722d..1af6c08 100644 --- a/usr/tgtd.h +++ b/usr/tgtd.h @@ -63,6 +63,7 @@ struct lu_phy_attr { unsigned char device_type; /* Peripheral device type */ char qualifier; /* Peripheral Qualifier */ char removable; /* Removable media */ + char readonly; /* Read-Only media */ char online; /* Logical Unit online */ char sense_format; /* Descrptor format sense data supported */ -- 1.6.6.1 -- To unsubscribe from this list: send the line "unsubscribe stgt" in the body of a message to majordomo at vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html |