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));
  }
  
  /*