Subject: "wanted 10 got 6"
To: None <port-sun3@NetBSD.ORG>
From: Jason Thorpe <thorpej@sj.xenotropic.com>
List: port-sun3
Date: 12/07/1995 00:43:22
Folks...
After the discussion there re. ancient drives rejecting commands
generated by the MI scsi code, I took a whack at fixing it, and the
patches below have eliminated the "wanted 10 got 6"-type short command
transfers for me. I was able to do 7 concurrent reads and 7 concurrent
writes across 2 ESDI disks behind a single MD21. This used to drop into
the debugger almost immediately, but managed to get through the whole
thing :-)
Here's what changed. Added code to sdstart() to build a 6-byte read or
write command if the transfer params will fit in it. Otherwise, a
10-byte command is used. To augment this, added a flag to sd_softc flags
that gets set if ((inqbuf.version & SID_ANSII) == 0), which includes the
MD21. Implemented sdminphys() which checks for this flag, and shortens
the transfer such that it will fit in a 6-byte cdb.
Since the cd driver uses basically an identical *start() routine, I added
the goo for 6- or 10-byte transfers there, but didn't implement the
minphys stuff, because I think we'll be hard-pressed to find any
"ancient" cdrom drives :-)
Attached are the patches below. Folks who are having trouble with
rejected commands, please try these out. They work for me on my 3/60 and
my 4/260 (which is also running dej's 5380 driver). If there are no
objections, I'll check these in to the tree.
Ciao.
------------------------------------------------------------------------------
Jason R. Thorpe thorpej@Xenotropic.COM
Just me and my collection of obsolete computer gear(s).
-----snip-----
Index: cd.c
===================================================================
RCS file: /usr/og/devsrc/netbsd/src/sys/scsi/cd.c,v
retrieving revision 1.1.1.5
diff -c -r1.1.1.5 cd.c
*** cd.c 1995/11/17 05:39:38 1.1.1.5
--- cd.c 1995/12/07 07:08:15
***************
*** 450,457 ****
register struct scsi_link *sc_link = cd->sc_link;
struct buf *bp = 0;
struct buf *dp;
! struct scsi_rw_big cmd;
! int blkno, nblks;
struct partition *p;
SC_DEBUG(sc_link, SDEV_DB2, ("cdstart "));
--- 450,459 ----
register struct scsi_link *sc_link = cd->sc_link;
struct buf *bp = 0;
struct buf *dp;
! 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, ("cdstart "));
***************
*** 505,527 ****
nblks = howmany(bp->b_bcount, cd->sc_dk.dk_label.d_secsize);
/*
! * Fill out the scsi command
*/
! 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;
/*
* 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,
CDRETRIES, 30000, bp, SCSI_NOSLEEP |
((bp->b_flags & B_READ) ? SCSI_DATA_IN : SCSI_DATA_OUT)))
printf("%s: not queued", cd->sc_dev.dv_xname);
--- 507,552 ----
nblks = howmany(bp->b_bcount, cd->sc_dk.dk_label.d_secsize);
/*
! * Fill out the scsi command. If the transfer will
! * fit in a "small" cdb, use it.
*/
! 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, cmdp, cmdlen,
! (u_char *) bp->b_data, bp->b_bcount,
CDRETRIES, 30000, bp, SCSI_NOSLEEP |
((bp->b_flags & B_READ) ? SCSI_DATA_IN : SCSI_DATA_OUT)))
printf("%s: not queued", cd->sc_dev.dv_xname);
Index: sd.c
===================================================================
RCS file: /usr/og/devsrc/netbsd/src/sys/scsi/sd.c,v
retrieving revision 1.1.1.4
diff -c -r1.1.1.4 sd.c
*** sd.c 1995/10/16 07:41:51 1.1.1.4
--- sd.c 1995/12/07 06:50:59
***************
*** 84,89 ****
--- 84,90 ----
#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,111 ****
--- 107,113 ----
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,172 ****
--- 169,180 ----
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,473 ****
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 partition *p;
SC_DEBUG(sc_link, SDEV_DB2, ("sdstart "));
--- 474,483 ----
register struct scsi_link *sc_link = sd->sc_link;
struct buf *bp = 0;
struct buf *dp;
! 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,549 ****
nblks = howmany(bp->b_bcount, sd->sc_dk.dk_label.d_secsize);
/*
! * Fill out the scsi command
*/
! 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;
/*
* 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,
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);
}
}
int
sdread(dev, uio)
dev_t dev;
--- 531,603 ----
nblks = howmany(bp->b_bcount, sd->sc_dk.dk_label.d_secsize);
/*
! * Fill out the scsi command. If the transfer will
! * fit in a "small" cdb, use it.
*/
! 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, 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.
+ */
+ 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;
***************
*** 551,558 ****
{
struct sd_softc *sd = sdcd.cd_devs[SDUNIT(dev)];
! return (physio(sdstrategy, NULL, dev, B_READ,
! sd->sc_link->adapter->scsi_minphys, uio));
}
int
--- 605,611 ----
{
struct sd_softc *sd = sdcd.cd_devs[SDUNIT(dev)];
! return (physio(sdstrategy, NULL, dev, B_READ, sdminphys, uio));
}
int
***************
*** 562,569 ****
{
struct sd_softc *sd = sdcd.cd_devs[SDUNIT(dev)];
! return (physio(sdstrategy, NULL, dev, B_WRITE,
! sd->sc_link->adapter->scsi_minphys, uio));
}
/*
--- 615,621 ----
{
struct sd_softc *sd = sdcd.cd_devs[SDUNIT(dev)];
! return (physio(sdstrategy, NULL, dev, B_WRITE, sdminphys, uio));
}
/*