On Mon, Mar 1, 2010 at 10:26 AM, Tomasz Chmielewski <tch@xxxxxxxx> wrote: ... > Not sure if tgtd allows a target to be truly read only? It does not. > > So that when the kernel detects a drive, it reports: > > sd 1:0:0:0: [sdx] Write Protect is on Please see attached hack for discussion. It is not tested but should/might work. While it probably needs a bit of work, this might be one approach to add a global read-only attribute for a LUN. Use update an existing lun and use --params readonly=1 to activate. Or should a readonly attribute be set initiator by initiator as part of the ACL instead? regards ronnie sahlberg
diff --git a/usr/sbc.c b/usr/sbc.c index a048d53..be8a0e1 100644 --- a/usr/sbc.c +++ b/usr/sbc.c @@ -77,11 +77,29 @@ 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_VERIFY: + case SYNCHRONIZE_CACHE: + case WRITE_12: + case WRITE_VERIFY_12: + case WRITE_16: + case WRITE_VERIFY_16: + case SYNCHRONIZE_CACHE_16: + key = DATA_PROTECT; + asc = ASC_WRITE_PROTECT; + goto check_condition; + break; + } + } cmd->scsi_cmd_done = target_cmd_io_done; cmd->offset = (scsi_rw_offset(cmd->scb) << BLK_SHIFT); @@ -94,6 +112,7 @@ static int sbc_rw(int host_no, struct scsi_cmd *cmd) return SAM_STAT_GOOD; } +check_condition: cmd->offset = 0; scsi_set_in_resid_by_actual(cmd, 0); scsi_set_out_resid_by_actual(cmd, 0); diff --git a/usr/spc.c b/usr/spc.c index 14a3ee1..00d5189 100644 --- a/usr/spc.c +++ b/usr/spc.c @@ -455,6 +455,22 @@ int set_mode_page_changeable_mask(struct scsi_lu *lu, uint8_t pcode, return 1; } +static int set_mode_page_control_readonly(struct scsi_lu *lu, uint8_t readonly) +{ + struct mode_pg *pg = lu->mode_pgs[0x0a]; + + if (pg) { + if (readonly) { + pg->mode_data[2] |= 0x08; + } else { + pg->mode_data[2] &= 0xf7; + } + + return 0; + } + return 1; +} + /** * build_mode_page - static routine used by spc_mode_sense() * @data: destination pointer @@ -482,7 +498,7 @@ static int build_mode_page(uint8_t *data, struct mode_pg *pg, p = &data[2]; len += 2; if (*alloc_len >= pg->pcode_size) { - if (pc == 1) + if (pc == 1) mode_data = pg->mode_data + pg->pcode_size; else mode_data = pg->mode_data; @@ -1578,7 +1594,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_err, @@ -1592,6 +1608,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"}, @@ -1661,6 +1678,11 @@ 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); + set_mode_page_control_readonly(lu, attrs->readonly); + break; case Opt_online: match_strncpy(buf, &args[0], sizeof(buf)); if (atoi(buf)) @@ -1719,6 +1741,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/tgtd.h b/usr/tgtd.h index 3323a9b..1e87a64 100644 --- a/usr/tgtd.h +++ b/usr/tgtd.h @@ -63,6 +63,7 @@ struct lu_phy_attr { 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 */