Subject: Re: sdX: not queued, error 5
To: Michael L. VanLoon -- HeadCandy.com <michaelv@mindbender.serv.net>
From: Jason Thorpe <thorpej@nas.nasa.gov>
List: tech-kern
Date: 03/11/1997 14:05:40
On Tue, 11 Mar 1997 07:26:33 -0800 
 "Michael L. VanLoon -- HeadCandy.com" <michaelv@MindBender.serv.net> wrote:

 > Is there any way to get rid of these with the ahc driver?

I fixed this in -current quite some time ago.  Attached below are
the changes I commited to -current.  They should be easy to back-port
to the 1.2 driver.

(In the Very Soon To Be Released, No Really, NetBSD 1.2 patch 1, the
-current driver has been pulled up into the branch.  But this should
do until that's released.)

Jason R. Thorpe                                       thorpej@nas.nasa.gov
NASA Ames Research Center                               Home: 408.866.1912
NAS: M/S 258-6                                          Work: 415.604.0935
Moffett Field, CA 94035                                Pager: 415.428.6939

Index: aic7xxx.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/aic7xxx.c,v
retrieving revision 1.17
retrieving revision 1.18
diff -c -r1.17 -r1.18
*** aic7xxx.c	1996/10/21 22:34:04	1.17
--- aic7xxx.c	1996/12/02 19:06:41	1.18
***************
*** 1,4 ****
! /*	$NetBSD: aic7xxx.c,v 1.17 1996/10/21 22:34:04 thorpej Exp $	*/
  
  /*
   * Generic driver for the aic7xxx based adaptec SCSI controllers
--- 1,4 ----
! /*	$NetBSD: aic7xxx.c,v 1.18 1996/12/02 19:06:41 thorpej Exp $	*/
  
  /*
   * Generic driver for the aic7xxx based adaptec SCSI controllers
***************
*** 325,330 ****
--- 325,336 ----
  static void	ahc_construct_wdtr __P((struct ahc_data *ahc, int start_byte,
  					u_int8_t bus_width));
  
+ #if defined(__NetBSD__)			/* XXX */
+ static void	ahc_xxx_enqueue __P((struct ahc_data *ahc,
+ 		    struct scsi_xfer *xs, int infront));
+ static struct scsi_xfer *ahc_xxx_dequeue __P((struct ahc_data *ahc));
+ #endif
+ 
  #if defined(__FreeBSD__)
  
  char *ahc_name(ahc)
***************
*** 619,624 ****
--- 625,637 ----
  	struct scsibus_data *scbus;
  #endif
  
+ #if defined(__NetBSD__)			/* XXX */
+ 	/*
+ 	 * Initialize the software queue.
+ 	 */
+ 	LIST_INIT(&ahc->sc_xxxq);
+ #endif
+ 
  #ifdef AHC_BROKEN_CACHE
  	if (cpu_class == CPUCLASS_386)	/* doesn't have "wbinvd" instruction */
  		ahc_broken_cache = 0;
***************
*** 1986,1991 ****
--- 1999,2017 ----
  #endif
  	ahc_free_scb(ahc, scb, xs->flags);
  	scsi_done(xs);
+ 
+ #if defined(__NetBSD__)			/* XXX */
+ 	/*
+ 	 * If there are entries in the software queue, try to
+ 	 * run the first one.  We should be more or less guaranteed
+ 	 * to succeed, since we just freed an SCB.
+ 	 *
+ 	 * NOTE: ahc_scsi_cmd() relies on our calling it with
+ 	 * the first entry in the queue.
+ 	 */
+ 	if (ahc->sc_xxxq.lh_first != NULL)
+ 		(void) ahc_scsi_cmd(ahc->sc_xxxq.lh_first);
+ #endif /* __NetBSD__ */
  }
  
  /*
***************
*** 2329,2334 ****
--- 2355,2405 ----
  #endif
  }
  
+ #if defined(__NetBSD__)			/* XXX */
+ /*
+  * Insert a scsi_xfer into the software queue.  We overload xs->free_list
+  * to to ensure we don't run into a queue resource shortage, and keep
+  * a pointer to the last entry around to make insertion O(C).
+  */
+ static void
+ ahc_xxx_enqueue(ahc, xs, infront)
+ 	struct ahc_data *ahc;
+ 	struct scsi_xfer *xs;
+ 	int infront;
+ {
+ 
+ 	if (infront || ahc->sc_xxxq.lh_first == NULL) {
+ 		if (ahc->sc_xxxq.lh_first == NULL)
+ 			ahc->sc_xxxqlast = xs;
+ 		LIST_INSERT_HEAD(&ahc->sc_xxxq, xs, free_list);
+ 		return;
+ 	}
+ 
+ 	LIST_INSERT_AFTER(ahc->sc_xxxqlast, xs, free_list);
+ 	ahc->sc_xxxqlast = xs;
+ }
+ 
+ /*
+  * Pull a scsi_xfer off the front of the software queue.  When we
+  * pull the last one off, we need to clear the pointer to the last
+  * entry.
+  */
+ static struct scsi_xfer *
+ ahc_xxx_dequeue(ahc)
+ 	struct ahc_data *ahc;
+ {
+ 	struct scsi_xfer *xs;
+ 
+ 	xs = ahc->sc_xxxq.lh_first;
+ 	LIST_REMOVE(xs, free_list);
+ 
+ 	if (ahc->sc_xxxq.lh_first == NULL)
+ 		ahc->sc_xxxqlast = NULL;
+ 
+ 	return (xs);
+ }
+ #endif
+ 
  /*
   * start a scsi operation given the command and
   * the data address, target, and lun all of which
***************
*** 2347,2352 ****
--- 2418,2426 ----
  	struct	ahc_data *ahc;
  	u_short	mask;
  	int	s;
+ #if defined(__NetBSD__)			/* XXX */
+ 	int	dontqueue = 0, fromqueue = 0;
+ #endif
  
  	ahc = (struct ahc_data *)xs->sc_link->adapter_softc;
  	mask = (0x01 << (xs->sc_link->target
***************
*** 2355,2361 ****
--- 2429,2481 ----
  #elif defined(__NetBSD__)
  			| (IS_SCSIBUS_B(ahc, xs->sc_link) ? SELBUSB : 0) ));
  #endif
+ 
  	SC_DEBUG(xs->sc_link, SDEV_DB2, ("ahc_scsi_cmd\n"));
+ 
+ #if defined(__NetBSD__)			/* XXX */
+ 	/* must protect the queue */
+ 	s = splbio();
+ 
+ 	/*
+ 	 * If we're running the queue from ahc_done(), we're called
+ 	 * with the first entry in the queue as our argument.
+ 	 * Pull it off; if we can't run the job, it will get placed
+ 	 * back at the front.
+ 	 */
+ 	if (xs == ahc->sc_xxxq.lh_first) {
+ 		xs = ahc_xxx_dequeue(ahc);
+ 		fromqueue = 1;
+ 		goto get_scb;
+ 	}
+ 
+ 	/* determine safey of software queueing */
+ 	dontqueue = xs->flags & SCSI_POLL;
+ 
+ 	/*
+ 	 * Handle situations where there's already entries in the
+ 	 * queue.
+ 	 */
+ 	if (ahc->sc_xxxq.lh_first != NULL) {
+ 		/*
+ 		 * If we can't queue, we have to abort, since
+ 		 * we have to preserve order.
+ 		 */
+ 		if (dontqueue) {
+ 			splx(s);
+ 			xs->error = XS_DRIVER_STUFFUP;
+ 			return (TRY_AGAIN_LATER);
+ 		}
+ 
+ 		/*
+ 		 * Swap with the first queue entry.
+ 		 */
+ 		ahc_xxx_enqueue(ahc, xs, 0);
+ 		xs = ahc_xxx_dequeue(ahc);
+ 		fromqueue = 1;
+ 	}
+ 
+  get_scb:
+ #endif /* __NetBSD__ */
  	/*
  	 * get an scb to use. If the transfer
  	 * is from a buf (possibly from interrupt time)
***************
*** 2371,2379 ****
--- 2491,2526 ----
  		xs->flags |= INUSE;
  	}
  	if (!(scb = ahc_get_scb(ahc, flags))) {
+ #if defined(__NetBSD__)			/* XXX */
+ 		/*
+ 		 * If we can't queue, we lose.
+ 		 */
+ 		if (dontqueue) {
+ 			splx(s);
+ 			xs->error = XS_DRIVER_STUFFUP;
+ 			return (TRY_AGAIN_LATER);
+ 		}
+ 
+ 		/*
+ 		 * If we were pulled off the queue, put ourselves
+ 		 * back in the front, otherwise tack ourselves onto
+ 		 * the end.
+ 		 */
+ 		ahc_xxx_enqueue(ahc, xs, fromqueue);
+ 
+ 		splx(s);
+ 		return (SUCCESSFULLY_QUEUED);
+ #else
  		xs->error = XS_DRIVER_STUFFUP;
  		return (TRY_AGAIN_LATER);
+ #endif /* __NetBSD__ */
  	}
+ 
+ #if defined(__NetBSD__)
+ 	/* we're done playing with the queue */
+ 	splx(s);
+ #endif
+ 
  	SC_DEBUG(xs->sc_link, SDEV_DB3, ("start scb(%p)\n", scb));
  	scb->xs = xs;
  	if (flags & SCSI_RESET) {
Index: aic7xxxvar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/aic7xxxvar.h,v
retrieving revision 1.10
retrieving revision 1.11
diff -c -r1.10 -r1.11
*** aic7xxxvar.h	1996/10/21 22:34:09	1.10
--- aic7xxxvar.h	1996/12/02 19:06:44	1.11
***************
*** 1,4 ****
! /*	$NetBSD: aic7xxxvar.h,v 1.10 1996/10/21 22:34:09 thorpej Exp $	*/
  
  /*
   * Interface to the generic driver for the aic7xxx based adaptec
--- 1,4 ----
! /*	$NetBSD: aic7xxxvar.h,v 1.11 1996/12/02 19:06:44 thorpej Exp $	*/
  
  /*
   * Interface to the generic driver for the aic7xxx based adaptec
***************
*** 213,218 ****
--- 213,220 ----
  	void	*sc_ih;
  	bus_space_tag_t sc_iot;
  	bus_space_handle_t sc_ioh;
+ 	LIST_HEAD(, scsi_xfer) sc_xxxq;	/* XXX software request queue */
+ 	struct scsi_xfer *sc_xxxqlast;	/* last entry in queue */
  #endif
  	ahc_type type;
  	ahc_flag flags;