Subject: Re: USB Printing still panicking ...sometimes
To: Martin S. Weber <Ephaeton@gmx.net>
From: Lennart Augustsson <lennart@augustsson.net>
List: current-users
Date: 04/28/2005 16:42:11
This is a multi-part message in MIME format.
--------------050803080504090401000100
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit

Here's a patch (derived from FreeBSD) that I think should
fix the problem.  Could you try it?

	-- Lennart

Martin S. Weber wrote:
> Yo,
> 
> I'm still experiencing problems with printing to a USB printer as
> previously described in a reply on netbsd-users[1] (System panics
> with "concurrent" lps, printing from like xpdf, soffice etc.) which 
> I thought had disappeared. It's happening with NetBSD 3.99.3 (GENERIC.MP) 
> #0: Wed Apr 20 20:26:27 CEST 2005 (whole system built at that date).
> 
> This is on a p4 (ht - mp) based dell:
> 
> uhci0 at pci0 dev 29 function 0: Intel 82801EB/ER USB UHCI Controller (rev. 0x02)
> uhci0: interrupting at ioapic0 pin 16 (irq 11)
> usb0 at uhci0: USB revision 1.0
> uhub0 at usb0
> uhub0: Intel UHCI root hub, class 9/0, rev 1.00/1.00, addr 1
> uhub0: 2 ports with 2 removable, self powered
> uhci[1-3] follow
> usb[1-3] follow
> uhub[1-3] follow
> ehci0 + usb4 + uhub4 follow
> ulpt0 at uhub0 port 1 configuration 1 interface 0
> ulpt0: Dell Dell Laser Printer P1500, rev 1.10/1.00, addr 2, iclass 7/1
> ulpt0: using bi-directional mode
> 
> (gdb) bt
> #0  0xc0b00000 in ?? ()
> #1  0xc04a0748 in cpu_reboot ()
> #2  0xc039b783 in db_sync_cmd ()
> #3  0xc039b1ce in db_command ()
> #4  0xc039aed8 in db_command_loop ()
> #5  0xc039e2b9 in db_trap ()
> #6  0xc049d33a in kdb_trap ()
> #7  0xc04ad4da in trap ()
> #8  0xc010be63 in calltrap ()
> #9  0xc02cdde0 in uhci_abort_xfer ()
> #10 0xc02cdbf8 in uhci_device_bulk_abort ()
> #11 0xc06229f5 in usbd_ar_pipe ()
> #12 0xc06226f2 in usbd_abort_pipe ()
> #13 0xc0633ee9 in ulptclose ()
> #14 0xc04322d7 in spec_close ()
> #15 0xc0399a52 in ufsspec_close ()
> #16 0xc042b16f in VOP_CLOSE ()
> #17 0xc0429c62 in vn_close ()
> #18 0xc042a745 in vn_closefile ()
> #19 0xc03c75e7 in closef ()
> #20 0xc03c7404 in fdfree ()
> #21 0xc03cc94e in exit1 ()
> #22 0xc03cc756 in sys_exit ()
> #23 0xc04acf08 in syscall_plain ()
> 
> 
> I'm baking a DEBUG kernel (along with a netbsd.gdb) and see if I can 
> reproduce it (it's become harder to trigger AFAICT, so could take some 
> time.). I have the dump lying around if it helps someone.
> 
> Regards,
> 
> -Martin
> 
> [1] http://mail-index.netbsd.org/netbsd-users/2005/04/12/0005.html
> 


--------------050803080504090401000100
Content-Type: text/plain;
 name="race.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="race.diff"

? TODO.la
? a.out
? aaa
? apa
? axe.diff
? control.ps
? ehci
? ehci.c.la
? net
? obsd
? open
? umass.c.la
? ut
Index: ehci.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/ehci.c,v
retrieving revision 1.95
diff -c -r1.95 ehci.c
*** ehci.c	27 Apr 2005 23:39:54 -0000	1.95
--- ehci.c	28 Apr 2005 14:38:57 -0000
***************
*** 2443,2448 ****
--- 2443,2449 ----
  	u_int32_t qhstatus;
  	int s;
  	int hit;
+ 	int wake;
  
  	DPRINTF(("ehci_abort_xfer: xfer=%p pipe=%p\n", xfer, epipe));
  
***************
*** 2460,2465 ****
--- 2461,2486 ----
  		panic("ehci_abort_xfer: not in process context");
  
  	/*
+ 	 * If an abort is already in progress then just wait for it to
+ 	 * complete and return.
+ 	 */
+ 	if (xfer->hcflags & UXFER_ABORTING) {
+ 		DPRINTFN(2, ("ehci_abort_xfer: already aborting\n"));
+ #ifdef DIAGNOSTIC
+ 		if (status == USBD_TIMEOUT)
+ 			printf("ehci_abort_xfer: TIMEOUT while aborting\n");
+ #endif
+ 		/* Override the status which might be USBD_TIMEOUT. */
+ 		xfer->status = status;
+ 		DPRINTFN(2, ("ehci_abort_xfer: waiting for abort to finish\n"));
+ 		xfer->hcflags |= UXFER_ABORTWAIT;
+ 		while (xfer->hcflags & UXFER_ABORTING)
+ 			tsleep(&xfer->hcflags, PZERO, "ehciaw", 0);
+ 		return;
+ 	}
+ 	xfer->hcflags |= UXFER_ABORTING;
+ 
+ 	/*
  	 * Step 1: Make interrupt routine and hardware ignore xfer.
  	 */
  	s = splusb();
***************
*** 2521,2527 ****
--- 2542,2552 ----
  #ifdef DIAGNOSTIC
  	exfer->isdone = 1;
  #endif
+ 	wake = xfer->hcflags & UXFER_ABORTWAIT;
+ 	xfer->hcflags &= ~(UXFER_ABORTING | UXFER_ABORTWAIT);
  	usb_transfer_complete(xfer);
+ 	if (wake)
+ 		wakeup(&xfer->hcflags);
  
  	splx(s);
  #undef exfer
Index: ohci.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/ohci.c,v
retrieving revision 1.158
diff -c -r1.158 ohci.c
*** ohci.c	17 Apr 2005 14:46:49 -0000	1.158
--- ohci.c	28 Apr 2005 14:38:58 -0000
***************
*** 2146,2151 ****
--- 2146,2152 ----
  	ohci_soft_td_t *p, *n;
  	ohci_physaddr_t headp;
  	int s, hit;
+ 	int wake;
  
  	DPRINTF(("ohci_abort_xfer: xfer=%p pipe=%p sed=%p\n", xfer, opipe,sed));
  
***************
*** 2162,2167 ****
--- 2163,2188 ----
  		panic("ohci_abort_xfer: not in process context");
  
  	/*
+ 	 * If an abort is already in progress then just wait for it to
+ 	 * complete and return.
+ 	 */
+ 	if (xfer->hcflags & UXFER_ABORTING) {
+ 		DPRINTFN(2, ("ohci_abort_xfer: already aborting\n"));
+ #ifdef DIAGNOSTIC
+ 		if (status == USBD_TIMEOUT)
+ 			printf("0hci_abort_xfer: TIMEOUT while aborting\n");
+ #endif
+ 		/* Override the status which might be USBD_TIMEOUT. */
+ 		xfer->status = status;
+ 		DPRINTFN(2, ("ohci_abort_xfer: waiting for abort to finish\n"));
+ 		xfer->hcflags |= UXFER_ABORTWAIT;
+ 		while (xfer->hcflags & UXFER_ABORTING)
+ 			tsleep(&xfer->hcflags, PZERO, "ohciaw", 0);
+ 		return;
+ 	}
+ 	xfer->hcflags |= UXFER_ABORTING;
+ 
+ 	/*
  	 * Step 1: Make interrupt routine and hardware ignore xfer.
  	 */
  	s = splusb();
***************
*** 2198,2203 ****
--- 2219,2225 ----
  	p = xfer->hcpriv;
  #ifdef DIAGNOSTIC
  	if (p == NULL) {
+ 		xfer->hcflags &= ~UXFER_ABORTING; /* XXX */
  		splx(s);
  		printf("ohci_abort_xfer: hcpriv is NULL\n");
  		return;
***************
*** 2234,2240 ****
--- 2256,2266 ----
  	/*
  	 * Step 5: Execute callback.
  	 */
+ 	wake = xfer->hcflags & UXFER_ABORTWAIT;
+ 	xfer->hcflags &= ~(UXFER_ABORTING | UXFER_ABORTWAIT);
  	usb_transfer_complete(xfer);
+ 	if (wake)
+ 		wakeup(&xfer->hcflags);
  
  	splx(s);
  }
Index: uhci.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/uhci.c,v
retrieving revision 1.185
diff -c -r1.185 uhci.c
*** uhci.c	2 Mar 2005 11:37:27 -0000	1.185
--- uhci.c	28 Apr 2005 14:38:58 -0000
***************
*** 1938,1943 ****
--- 1938,1944 ----
  	uhci_softc_t *sc = (uhci_softc_t *)upipe->pipe.device->bus;
  	uhci_soft_td_t *std;
  	int s;
+ 	int wake;
  
  	DPRINTFN(1,("uhci_abort_xfer: xfer=%p, status=%d\n", xfer, status));
  
***************
*** 1954,1959 ****
--- 1955,1980 ----
  		panic("uhci_abort_xfer: not in process context");
  
  	/*
+ 	 * If an abort is already in progress then just wait for it to
+ 	 * complete and return.
+ 	 */
+ 	if (xfer->hcflags & UXFER_ABORTING) {
+ 		DPRINTFN(2, ("uhci_abort_xfer: already aborting\n"));
+ #ifdef DIAGNOSTIC
+ 		if (status == USBD_TIMEOUT)
+ 			printf("uhci_abort_xfer: TIMEOUT while aborting\n");
+ #endif
+ 		/* Override the status which might be USBD_TIMEOUT. */
+ 		xfer->status = status;
+ 		DPRINTFN(2, ("uhci_abort_xfer: waiting for abort to finish\n"));
+ 		xfer->hcflags |= UXFER_ABORTWAIT;
+ 		while (xfer->hcflags & UXFER_ABORTING)
+ 			tsleep(&xfer->hcflags, PZERO, "uhciaw", 0);
+ 		return;
+ 	}
+ 	xfer->hcflags |= UXFER_ABORTING;
+ 
+ 	/*
  	 * Step 1: Make interrupt routine and hardware ignore xfer.
  	 */
  	s = splusb();
***************
*** 1989,1995 ****
--- 2010,2020 ----
  #ifdef DIAGNOSTIC
  	ii->isdone = 1;
  #endif
+ 	wake = xfer->hcflags & UXFER_ABORTWAIT;
+ 	xfer->hcflags &= ~(UXFER_ABORTING | UXFER_ABORTWAIT);
  	usb_transfer_complete(xfer);
+ 	if (wake)
+ 		wakeup(&xfer->hcflags);
  	splx(s);
  }
  
Index: usbdivar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/usbdivar.h,v
retrieving revision 1.73
diff -c -r1.73 usbdivar.h
*** usbdivar.h	24 Jan 2005 01:30:38 -0000	1.73
--- usbdivar.h	28 Apr 2005 14:38:59 -0000
***************
*** 217,223 ****
  	struct usbd_device     *device;
  	usb_dma_t		dmabuf;
  
! 	int			rqflags;
  #define URQ_REQUEST	0x01
  #define URQ_AUTO_DMABUF	0x10
  #define URQ_DEV_DMABUF	0x20
--- 217,223 ----
  	struct usbd_device     *device;
  	usb_dma_t		dmabuf;
  
! 	u_int8_t		rqflags;
  #define URQ_REQUEST	0x01
  #define URQ_AUTO_DMABUF	0x10
  #define URQ_DEV_DMABUF	0x20
***************
*** 225,230 ****
--- 225,233 ----
  	SIMPLEQ_ENTRY(usbd_xfer) next;
  
  	void		       *hcpriv; /* private use by the HC driver */
+ 	u_int8_t		hcflags; /* private use by the HC driver */
+ #define UXFER_ABORTING	0x01	/* xfer is aborting. */
+ #define UXFER_ABORTWAIT	0x02	/* abort completion is being awaited. */
  
  	usb_callout_t		timeout_handle;
  };

--------------050803080504090401000100--