from netbsd:
authorderaadt <deraadt@openbsd.org>
Thu, 14 Dec 1995 05:56:35 +0000 (05:56 +0000)
committerderaadt <deraadt@openbsd.org>
Thu, 14 Dec 1995 05:56:35 +0000 (05:56 +0000)
If the read or write request can fit into a 6-byte cdb, then
use a 6-byte cdb, otherwise use the 10-byte as before.
In sdattach(), make a note if the device is "ancient" (i.e.
inqbuf.version & SID_ANSII == 0).
Implement sdminphys(): if the device is "ancient", shorten the
transfer so it will fit into a 6-byte cdb.

In sdminphys(), add a comment about the semantics of the "length" field
in a 6-byte read/write cdb (namely, length == 0 really means 256), and
that we handle this conservatively by limiting the transfer to 255 blocks.
*sigh* One just never knows how a pre-scsi-1 device is going to behave.

Remove a couple of now unneeded assignments.

sys/scsi/sd.c

index 2d8ef52..474ae5d 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: sd.c,v 1.80 1995/10/10 02:53:01 mycroft Exp $  */
+/*     $NetBSD: sd.c,v 1.83 1995/12/07 21:54:24 thorpej Exp $  */
 
 /*
  * Copyright (c) 1994, 1995 Charles M. Hannum.  All rights reserved.
@@ -84,6 +84,7 @@ struct sd_softc {
 #define        SDF_WANTED      0x02
 #define        SDF_WLABEL      0x04            /* label is writable */
 #define        SDF_LABELLING   0x08            /* writing label */
+#define        SDF_ANCIENT     0x10            /* disk is ancient; for minphys */
        struct scsi_link *sc_link;      /* contains our targ, lun, etc. */
        struct disk_parms {
                u_char heads;           /* number of heads */
@@ -106,6 +107,7 @@ void sdgetdisklabel __P((struct sd_softc *));
 int sd_get_parms __P((struct sd_softc *, int));
 void sdstrategy __P((struct buf *));
 void sdstart __P((struct sd_softc *));
+void sdminphys __P((struct buf *));
 
 struct dkdriver sddkdriver = { sdstrategy };
 
@@ -167,6 +169,12 @@ sdattach(parent, self, aux)
        if (sc_link->openings > SDOUTSTANDING)
                sc_link->openings = SDOUTSTANDING;
 
+       /*
+        * Note if this device is ancient.  This is used in sdminphys().
+        */
+       if ((sa->sa_inqbuf->version & SID_ANSII) == 0)
+               sd->flags |= SDF_ANCIENT;
+
        sd->sc_dk.dk_driver = &sddkdriver;
 #if !defined(i386) || defined(NEWCONFIG)
        dk_establish(&sd->sc_dk, &sd->sc_dev);
@@ -466,8 +474,10 @@ sdstart(sd)
        register struct scsi_link *sc_link = sd->sc_link;
        struct buf *bp = 0;
        struct buf *dp;
-       struct scsi_rw_big cmd;
-       int blkno, nblks;
+       struct scsi_rw_big cmd_big;
+       struct scsi_rw cmd_small;
+       struct scsi_generic *cmdp;
+       int blkno, nblks, cmdlen;
        struct partition *p;
 
        SC_DEBUG(sc_link, SDEV_DB2, ("sdstart "));
@@ -521,38 +531,87 @@ sdstart(sd)
                nblks = howmany(bp->b_bcount, sd->sc_dk.dk_label.d_secsize);
 
                /*
-                *  Fill out the scsi command
+                *  Fill out the scsi command.  If the transfer will
+                *  fit in a "small" cdb, use it.
                 */
-               bzero(&cmd, sizeof(cmd));
-               cmd.opcode = (bp->b_flags & B_READ) ? READ_BIG : WRITE_BIG;
-               cmd.addr_3 = (blkno >> 24) & 0xff;
-               cmd.addr_2 = (blkno >> 16) & 0xff;
-               cmd.addr_1 = (blkno >> 8) & 0xff;
-               cmd.addr_0 = blkno & 0xff;
-               cmd.length2 = (nblks >> 8) & 0xff;
-               cmd.length1 = nblks & 0xff;
+               if (((blkno & 0x1fffff) == blkno) &&
+                   ((nblks & 0xff) == nblks)) {
+                       /*
+                        * We can fit in a small cdb.
+                        */
+                       bzero(&cmd_small, sizeof(cmd_small));
+                       cmd_small.opcode = (bp->b_flags & B_READ) ?
+                           READ_COMMAND : WRITE_COMMAND;
+                       cmd_small.addr_2 = (blkno >> 16) & 0x1f;
+                       cmd_small.addr_1 = (blkno >> 8) & 0xff;
+                       cmd_small.addr_0 = blkno & 0xff;
+                       cmd_small.length = nblks & 0xff;
+                       cmdlen = sizeof(cmd_small);
+                       cmdp = (struct scsi_generic *)&cmd_small;
+               } else {
+                       /*
+                        * Need a large cdb.
+                        */
+                       bzero(&cmd_big, sizeof(cmd_big));
+                       cmd_big.opcode = (bp->b_flags & B_READ) ?
+                           READ_BIG : WRITE_BIG;
+                       cmd_big.addr_3 = (blkno >> 24) & 0xff;
+                       cmd_big.addr_2 = (blkno >> 16) & 0xff;
+                       cmd_big.addr_1 = (blkno >> 8) & 0xff;
+                       cmd_big.addr_0 = blkno & 0xff;
+                       cmd_big.length2 = (nblks >> 8) & 0xff;
+                       cmd_big.length1 = nblks & 0xff;
+                       cmdlen = sizeof(cmd_big);
+                       cmdp = (struct scsi_generic *)&cmd_big;
+               }
 
                /*
                 * Call the routine that chats with the adapter.
                 * Note: we cannot sleep as we may be an interrupt
                 */
-               if (scsi_scsi_cmd(sc_link, (struct scsi_generic *)&cmd,
-                   sizeof(cmd), (u_char *)bp->b_data, bp->b_bcount,
+               if (scsi_scsi_cmd(sc_link, cmdp, cmdlen,
+                   (u_char *)bp->b_data, bp->b_bcount,
                    SDRETRIES, 10000, bp, SCSI_NOSLEEP |
                    ((bp->b_flags & B_READ) ? SCSI_DATA_IN : SCSI_DATA_OUT)))
                        printf("%s: not queued", sd->sc_dev.dv_xname);
        }
 }
 
+void
+sdminphys(bp)
+       struct buf *bp;
+{
+       struct sd_softc *sd = sdcd.cd_devs[SDUNIT(bp->b_dev)];
+       long max;
+
+       /*
+        * If the device is ancient, we want to make sure that
+        * the transfer fits into a 6-byte cdb.
+        *
+        * XXX Note that the SCSI-I spec says that 256-block transfers
+        * are allowed in a 6-byte read/write, and are specified
+        * by settng the "length" to 0.  However, we're conservative
+        * here, allowing only 255-block transfers in case an
+        * ancient device gets confused by length == 0.  A length of 0
+        * in a 10-byte read/write actually means 0 blocks.
+        */
+       if (sd->flags & SDF_ANCIENT) {
+               max = sd->sc_dk.dk_label.d_secsize * 0xff;
+
+               if (bp->b_bcount > max)
+                       bp->b_bcount = max;
+       }
+
+       (*sd->sc_link->adapter->scsi_minphys)(bp);
+}
+
 int
 sdread(dev, uio)
        dev_t dev;
        struct uio *uio;
 {
-       struct sd_softc *sd = sdcd.cd_devs[SDUNIT(dev)];
 
-       return (physio(sdstrategy, NULL, dev, B_READ,
-                      sd->sc_link->adapter->scsi_minphys, uio));
+       return (physio(sdstrategy, NULL, dev, B_READ, sdminphys, uio));
 }
 
 int
@@ -560,10 +619,8 @@ sdwrite(dev, uio)
        dev_t dev;
        struct uio *uio;
 {
-       struct sd_softc *sd = sdcd.cd_devs[SDUNIT(dev)];
 
-       return (physio(sdstrategy, NULL, dev, B_WRITE,
-                      sd->sc_link->adapter->scsi_minphys, uio));
+       return (physio(sdstrategy, NULL, dev, B_WRITE, sdminphys, uio));
 }
 
 /*