USB. Need I say more? :-) I now have a USB device in hand which has a 'READONLY' physical switch on the top. If set to READONLY, this device spews error messages when writes are attempted. And the device freaks out so that ALL subsequent i/o's fail.
I saw this: http://lists.wpkg.org/pipermail/stgt/2010-March/003569.html and hacked together the diff below to record the WRITE PROTECT info that dev_spec provides. I unified the sd and st cases to use the same flag. The USB device is now silent. This is still a bit of a puzzle since I expect the 'dd if=/dev/zero of=/dev/sd2c count=1' command to fail with an error. But it simply reports that all is well. Respecting the WRITE PROTECT bit seems like a good idea Thoughts? Anybody with 'real' SCSI specs to check up on when dev_spec started supplying this info? .... 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 5 Dec 2010 01:18:25 -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 5 Dec 2010 01:18:25 -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 5 Dec 2010 01:18:26 -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 5 Dec 2010 01:18:26 -0000 @@ -539,6 +539,11 @@ sdstrategy(struct buf *bp) bp->b_error = ENXIO; goto bad; } + if (!ISSET(bp->b_flags, B_READ) && ISSET(sc->sc_link->flags, + SDEV_READONLY)) { + bp->b_error = EIO; + goto bad; + } SC_DEBUG(sc->sc_link, SDEV_DB2, ("sdstrategy: %ld bytes @ blk %d\n", bp->b_bcount, bp->b_blkno)); @@ -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 5 Dec 2010 01:18:26 -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)) @@ -836,6 +832,12 @@ ststrategy(struct buf *bp) bp->b_error = ENXIO; goto bad; } + if (!ISSET(bp->b_flags, B_READ) && ISSET(sc_link->flags, + SDEV_READONLY)) { + bp->b_error = EIO; + 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"));
