summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 84e4bb1..1c3f077 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},
@@ -4449,7 +4449,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;
@@ -4611,6 +4611,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);
@@ -6221,6 +6225,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;
/*
@@ -7047,8 +7059,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
@@ -7065,8 +7082,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
@@ -11315,6 +11337,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 fa577f2..9e56160 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