summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2014-10-08 12:24:24 +0000
committermav <mav@FreeBSD.org>2014-10-08 12:24:24 +0000
commitc561a7a0862e17e6c7c2cd76ed43f98dc7893d33 (patch)
treeb49c5b1114ade868c6810f29fef666749c92d95a
parent301ee8d315a67626cc6b43996bc4bfc592dcc8bf (diff)
downloadFreeBSD-src-c561a7a0862e17e6c7c2cd76ed43f98dc7893d33.zip
FreeBSD-src-c561a7a0862e17e6c7c2cd76ed43f98dc7893d33.tar.gz
Implement software (mode page) and hardware (config) write protection.
-rw-r--r--sys/cam/ctl/ctl.c48
-rw-r--r--sys/cam/ctl/ctl_private.h3
-rw-r--r--usr.sbin/ctladm/ctladm.85
3 files changed, 50 insertions, 6 deletions
diff --git a/sys/cam/ctl/ctl.c b/sys/cam/ctl/ctl.c
index 28f07b0..4ed6a5a 100644
--- a/sys/cam/ctl/ctl.c
+++ b/sys/cam/ctl/ctl.c
@@ -293,7 +293,7 @@ static struct scsi_control_page control_page_changeable = {
/*page_length*/sizeof(struct scsi_control_page) - 2,
/*rlec*/SCP_DSENSE,
/*queue_flags*/SCP_QUEUE_ALG_MASK,
- /*eca_and_aen*/0,
+ /*eca_and_aen*/SCP_SWP,
/*flags4*/0,
/*aen_holdoff_period*/{0, 0},
/*busy_timeout_period*/{0, 0},
@@ -4447,7 +4447,7 @@ ctl_alloc_lun(struct ctl_softc *ctl_softc, struct ctl_lun *ctl_lun,
struct ctl_port *port;
struct scsi_vpd_id_descriptor *desc;
struct scsi_vpd_id_t10 *t10id;
- const char *eui, *naa, *scsiname, *vendor;
+ const char *eui, *naa, *scsiname, *vendor, *value;
int lun_number, i, lun_malloced;
int devidlen, idlen1, idlen2 = 0, len;
@@ -4609,6 +4609,10 @@ ctl_alloc_lun(struct ctl_softc *ctl_softc, struct ctl_lun *ctl_lun,
if (be_lun->flags & CTL_LUN_FLAG_PRIMARY)
lun->flags |= CTL_LUN_PRIMARY_SC;
+ value = ctl_get_opt(&be_lun->options, "readonly");
+ if (value != NULL && strcmp(value, "on") == 0)
+ lun->flags |= CTL_LUN_READONLY;
+
lun->ctl_softc = ctl_softc;
TAILQ_INIT(&lun->ooa_queue);
TAILQ_INIT(&lun->blocked_queue);
@@ -6219,6 +6223,14 @@ ctl_control_page_handler(struct ctl_scsiio *ctsio,
saved_cp->queue_flags |= user_cp->queue_flags & SCP_QUEUE_ALG_MASK;
set_ua = 1;
}
+ if ((current_cp->eca_and_aen & SCP_SWP) !=
+ (user_cp->eca_and_aen & SCP_SWP)) {
+ current_cp->eca_and_aen &= ~SCP_SWP;
+ current_cp->eca_and_aen |= user_cp->eca_and_aen & SCP_SWP;
+ saved_cp->eca_and_aen &= ~SCP_SWP;
+ saved_cp->eca_and_aen |= user_cp->eca_and_aen & SCP_SWP;
+ set_ua = 1;
+ }
if (set_ua != 0) {
int i;
/*
@@ -7045,8 +7057,13 @@ ctl_mode_sense(struct ctl_scsiio *ctsio)
header = (struct scsi_mode_hdr_6 *)ctsio->kern_data_ptr;
header->datalen = ctl_min(total_len - 1, 254);
- if (control_dev == 0)
+ if (control_dev == 0) {
header->dev_specific = 0x10; /* DPOFUA */
+ if ((lun->flags & CTL_LUN_READONLY) ||
+ (lun->mode_pages.control_page[CTL_PAGE_CURRENT]
+ .eca_and_aen & SCP_SWP) != 0)
+ header->dev_specific |= 0x80; /* WP */
+ }
if (dbd)
header->block_descr_len = 0;
else
@@ -7063,8 +7080,13 @@ ctl_mode_sense(struct ctl_scsiio *ctsio)
datalen = ctl_min(total_len - 2, 65533);
scsi_ulto2b(datalen, header->datalen);
- if (control_dev == 0)
+ if (control_dev == 0) {
header->dev_specific = 0x10; /* DPOFUA */
+ if ((lun->flags & CTL_LUN_READONLY) ||
+ (lun->mode_pages.control_page[CTL_PAGE_CURRENT]
+ .eca_and_aen & SCP_SWP) != 0)
+ header->dev_specific |= 0x80; /* WP */
+ }
if (dbd)
scsi_ulto2b(0, header->block_descr_len);
else
@@ -11313,6 +11335,24 @@ ctl_scsiio_lun_check(struct ctl_softc *ctl_softc, struct ctl_lun *lun,
}
#endif
+ if (entry->pattern & CTL_LUN_PAT_WRITE) {
+ if (lun->flags & CTL_LUN_READONLY) {
+ ctl_set_sense(ctsio, /*current_error*/ 1,
+ /*sense_key*/ SSD_KEY_DATA_PROTECT,
+ /*asc*/ 0x27, /*ascq*/ 0x01, SSD_ELEM_NONE);
+ retval = 1;
+ goto bailout;
+ }
+ if ((lun->mode_pages.control_page[CTL_PAGE_CURRENT]
+ .eca_and_aen & SCP_SWP) != 0) {
+ ctl_set_sense(ctsio, /*current_error*/ 1,
+ /*sense_key*/ SSD_KEY_DATA_PROTECT,
+ /*asc*/ 0x27, /*ascq*/ 0x02, SSD_ELEM_NONE);
+ retval = 1;
+ goto bailout;
+ }
+ }
+
/*
* Check for a reservation conflict. If this command isn't allowed
* even on reserved LUNs, and if this initiator isn't the one who
diff --git a/sys/cam/ctl/ctl_private.h b/sys/cam/ctl/ctl_private.h
index 43ee394..4f22250 100644
--- a/sys/cam/ctl/ctl_private.h
+++ b/sys/cam/ctl/ctl_private.h
@@ -198,7 +198,8 @@ typedef enum {
CTL_LUN_OFFLINE = 0x080,
CTL_LUN_PR_RESERVED = 0x100,
CTL_LUN_PRIMARY_SC = 0x200,
- CTL_LUN_SENSE_DESC = 0x400
+ CTL_LUN_SENSE_DESC = 0x400,
+ CTL_LUN_READONLY = 0x800
} ctl_lun_flags;
typedef enum {
diff --git a/usr.sbin/ctladm/ctladm.8 b/usr.sbin/ctladm/ctladm.8
index 1cacf64..19ee806 100644
--- a/usr.sbin/ctladm/ctladm.8
+++ b/usr.sbin/ctladm/ctladm.8
@@ -34,7 +34,7 @@
.\" $Id: //depot/users/kenm/FreeBSD-test2/usr.sbin/ctladm/ctladm.8#3 $
.\" $FreeBSD$
.\"
-.Dd September 13, 2014
+.Dd October 8, 2014
.Dt CTLADM 8
.Os
.Sh NAME
@@ -961,6 +961,9 @@ This allows to offload copying between different iSCSI targets residing
on the same host in trusted environments.
.It Va readcache
Set to "off", disables read caching for the LUN, if supported by the backend.
+.It Va readonly
+Set to "on", blocks all media write operations to the LUN, reporting it
+as write protected.
.It Va reordering
Set to "unrestricted", allows target to process commands with SIMPLE task
attribute in arbitrary order. Any data integrity exposures related to
OpenPOWER on IntegriCloud