From cc6cca3f1e5c3cec97d68e6b2d95d678f1bc0eb2 Mon Sep 17 00:00:00 2001 From: mav Date: Mon, 20 Oct 2014 07:34:37 +0000 Subject: MFC r272748: Implement software (mode page) and hardware (config) write protection. --- sys/cam/ctl/ctl.c | 48 +++++++++++++++++++++++++++++++++++++++++++---- sys/cam/ctl/ctl_private.h | 3 ++- usr.sbin/ctladm/ctladm.8 | 5 ++++- 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 -- cgit v1.1