Re: Read-only sd(4) devices -- good idea?

Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]
From: Kenneth R Westerback
Date: Wednesday, December 15, 2010 - 8:24 pm

On Wed, Dec 15, 2010 at 06:20:33PM -0500, Kenneth R Westerback wrote:

As Theo pointed out, it may be less kludgy to check the open()
parameter and fail if FWRITE is attempted on read-only device.
Rather than failing each offending i/o. This also fixes the odd
behaviour I noted on dd. It now fails if the device is read only.

Works for me on the wonder device.

.... Ken

Index: scsi_all.h
===================================================================
RCS file: /cvs/src/sys/scsi/scsi_all.h,v
retrieving revision 1.51
diff -u -p -r1.51 scsi_all.h
--- scsi_all.h	2 Sep 2010 11:54:44 -0000	1.51
+++ scsi_all.h	16 Dec 2010 03:15:45 -0000
@@ -431,6 +431,9 @@ struct scsi_mode_header_big {
 	u_int8_t blk_desc_len[2];
 };
 
+/* Both disks and tapes use dev_spec to report READONLY status. */
+#define	SMH_DSP_WRITE_PROT	0x80
+
 union scsi_mode_sense_buf {
 	struct scsi_mode_header hdr;
 	struct scsi_mode_header_big hdr_big;
Index: scsi_tape.h
===================================================================
RCS file: /cvs/src/sys/scsi/scsi_tape.h,v
retrieving revision 1.7
diff -u -p -r1.7 scsi_tape.h
--- scsi_tape.h	7 Jan 1998 17:28:38 -0000	1.7
+++ scsi_tape.h	16 Dec 2010 03:15:45 -0000
@@ -173,7 +173,6 @@ struct scsi_tape_dev_conf_page {
 #define	SMH_DSP_BUFF_MODE_OFF	0x00
 #define	SMH_DSP_BUFF_MODE_ON	0x10
 #define	SMH_DSP_BUFF_MODE_MLTI	0x20
-#define	SMH_DSP_WRITE_PROT	0x80
 
 /* A special for the CIPHER ST150S(old drive) */
 struct block_desc_cipher {
Index: scsiconf.h
===================================================================
RCS file: /cvs/src/sys/scsi/scsiconf.h,v
retrieving revision 1.141
diff -u -p -r1.141 scsiconf.h
--- scsiconf.h	12 Oct 2010 00:53:32 -0000	1.141
+++ scsiconf.h	16 Dec 2010 03:15:45 -0000
@@ -367,6 +367,7 @@ struct scsi_link {
 	u_int16_t flags;		/* flags that all devices have */
 #define	SDEV_REMOVABLE	 	0x0001	/* media is removable */
 #define	SDEV_MEDIA_LOADED 	0x0002	/* device figures are still valid */
+#define	SDEV_READONLY		0x0004	/* device is read-only */
 #define	SDEV_OPEN	 	0x0008	/* at least 1 open session */
 #define	SDEV_DBX		0x00f0	/* debugging flags (scsi_debug.h) */
 #define	SDEV_EJECTING		0x0100	/* eject on device close */
Index: sd.c
===================================================================
RCS file: /cvs/src/sys/scsi/sd.c,v
retrieving revision 1.218
diff -u -p -r1.218 sd.c
--- sd.c	24 Sep 2010 01:41:34 -0000	1.218
+++ sd.c	16 Dec 2010 03:15:45 -0000
@@ -343,12 +343,17 @@ sdopen(dev_t dev, int flag, int fmt, str
 	sc = sdlookup(unit);
 	if (sc == NULL)
 		return (ENXIO);
+	sc_link = sc->sc_link;
+
 	if (sc->flags & SDF_DYING) {
 		device_unref(&sc->sc_dev);
 		return (ENXIO);
 	}
+	if (ISSET(flag, FWRITE) && ISSET(sc_link->flags, SDEV_READONLY)) {
+		device_unref(&sc->sc_dev);
+		return (EACCES);
+	}
 
-	sc_link = sc->sc_link;
 	SC_DEBUG(sc_link, SDEV_DB1,
 	    ("sdopen: dev=0x%x (unit %d (of %d), partition %d)\n", dev, unit,
 	    sd_cd.cd_ndevs, part));
@@ -1403,21 +1408,37 @@ sd_get_parms(struct sd_softc *sc, struct
 	struct page_rigid_geometry *rigid = NULL;
 	struct page_flex_geometry *flex = NULL;
 	struct page_reduced_geometry *reduced = NULL;
+	u_char *page0 = NULL;
 	u_int32_t heads = 0, sectors = 0, cyls = 0, secsize = 0, sssecsize;
-	int err = 0;
+	int err = 0, big;
 
 	dp->disksize = scsi_size(sc->sc_link, flags, &sssecsize);
 
+	buf = malloc(sizeof(*buf), M_TEMP, M_NOWAIT);
+	if (buf == NULL)
+		goto validate;
+
+	/*
+	 * Ask for page 0 (vendor specific) mode sense data to find
+	 * READONLY info. The only thing USB devices will ask for. 
+	 */
+	err = scsi_do_mode_sense(sc->sc_link, 0, buf, (void **)&page0,
+	    NULL, NULL, NULL, 1, flags | SCSI_SILENT, &big);
+	if (err == 0) {
+		if (big && buf->hdr_big.dev_spec & SMH_DSP_WRITE_PROT)
+			SET(sc->sc_link->flags, SDEV_READONLY);
+		else if (!big && buf->hdr.dev_spec & SMH_DSP_WRITE_PROT)
+			SET(sc->sc_link->flags, SDEV_READONLY);
+		else
+			CLR(sc->sc_link->flags, SDEV_READONLY);
+	}
+
 	/*
 	 * Many UMASS devices choke when asked about their geometry. Most
 	 * don't have a meaningful geometry anyway, so just fake it if
 	 * scsi_size() worked.
 	 */
 	if ((sc->sc_link->flags & SDEV_UMASS) && (dp->disksize > 0))
-		goto validate;	 /* N.B. buf will be NULL at validate. */
-
-	buf = malloc(sizeof(*buf), M_TEMP, M_NOWAIT);
-	if (buf == NULL)
 		goto validate;
 
 	switch (sc->sc_link->inqdata.device & SID_TYPE) {
Index: st.c
===================================================================
RCS file: /cvs/src/sys/scsi/st.c,v
retrieving revision 1.115
diff -u -p -r1.115 st.c
--- st.c	13 Oct 2010 02:14:52 -0000	1.115
+++ st.c	16 Dec 2010 03:15:46 -0000
@@ -262,7 +262,6 @@ struct cfdriver st_cd = {
 #define	ST_FIXEDBLOCKS	0x0008
 #define	ST_AT_FILEMARK	0x0010
 #define	ST_EIO_PENDING	0x0020	/* we couldn't report it then (had data) */
-#define	ST_READONLY	0x0080	/* st_mode_sense says write protected */
 #define	ST_FM_WRITTEN	0x0100	/*
 				 * EOF file mark written  -- used with
 				 * ~ST_WRITTEN to indicate that multiple file
@@ -276,9 +275,6 @@ struct cfdriver st_cd = {
 #define ST_WAITING	0x2000
 
 #define	ST_PER_ACTION	(ST_AT_FILEMARK | ST_EIO_PENDING | ST_BLANK_READ)
-#define	ST_PER_MOUNT	(ST_INFO_VALID | ST_BLOCK_SET | ST_WRITTEN | \
-			 ST_FIXEDBLOCKS | ST_READONLY | ST_FM_WRITTEN | \
-			 ST_2FM_AT_EOD | ST_PER_ACTION)
 
 #define stlookup(unit) (struct st_softc *)device_lookup(&st_cd, (unit))
 
@@ -457,11 +453,16 @@ stopen(dev_t dev, int flags, int fmt, st
 	st = stlookup(STUNIT(dev));
 	if (st == NULL)
 		return (ENXIO);
+	sc_link = st->sc_link;
+
 	if (st->flags & ST_DYING) {
 		error = ENXIO;
 		goto done;
 	}
-	sc_link = st->sc_link;
+	if (ISSET(flags, FWRITE) && ISSET(sc_link->flags, SDEV_READONLY)) {
+		error = EACCES;
+		goto done;
+	}
 
 	SC_DEBUG(sc_link, SDEV_DB1, ("open: dev=0x%x (unit %d (of %d))\n", dev,
 	    STUNIT(dev), st_cd.cd_ndevs));
@@ -836,6 +837,7 @@ ststrategy(struct buf *bp)
 		bp->b_error = ENXIO;
 		goto bad;
 	}
+
 	sc_link = st->sc_link;
 
 	SC_DEBUG(sc_link, SDEV_DB2, ("ststrategy: %ld bytes @ blk %d\n",
@@ -1205,7 +1207,7 @@ stioctl(dev_t dev, u_long cmd, caddr_t a
 		g->mt_density = st->density;
  		g->mt_mblksiz = st->modes.blksize;
  		g->mt_mdensity = st->modes.density;
-		if (st->flags & ST_READONLY)
+		if (st->sc_link->flags & SDEV_READONLY)
 			g->mt_dsreg |= MT_DS_RDONLY;
 		if (st->flags & ST_MOUNTED)
 			g->mt_dsreg |= MT_DS_MOUNTED;
@@ -1483,9 +1485,9 @@ st_mode_sense(struct st_softc *st, int f
 		dev_spec = data->hdr.dev_spec;
 
 	if (dev_spec & SMH_DSP_WRITE_PROT)
-		st->flags |= ST_READONLY;
+		SET(sc_link->flags, SDEV_READONLY);
 	else
-		st->flags &= ~ST_READONLY;
+		CLR(sc_link->flags, SDEV_READONLY);
 
 	st->numblks = block_count;
 	st->media_blksize = block_size;
@@ -1494,7 +1496,7 @@ st_mode_sense(struct st_softc *st, int f
 	SC_DEBUG(sc_link, SDEV_DB3,
 	    ("density code 0x%x, %d-byte blocks, write-%s, ",
 	    st->media_density, st->media_blksize,
-	    st->flags & ST_READONLY ? "protected" : "enabled"));
+	    sc_link->flags & SDEV_READONLY ? "protected" : "enabled"));
 	SC_DEBUGN(sc_link, SDEV_DB3,
 	    ("%sbuffered\n", dev_spec & SMH_DSP_BUFF_MODE ? "" : "un"));
Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]

Messages in current thread:
Read-only sd(4) devices -- good idea?, Kenneth R Westerback, (Wed Dec 15, 4:20 pm)
Re: Read-only sd(4) devices -- good idea?, Kenneth R Westerback, (Wed Dec 15, 8:24 pm)