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"));

Reply via email to