Subject: kern/11713: Removing USB (OHCI) card does not detach devices, but hangs CardBus kernel thread
To: None <gnats-bugs@gnats.netbsd.org>
From: ITOH Yasufumi <itohy@netbsd.org>
List: netbsd-bugs
Date: 12/12/2000 17:31:15
>Number:         11713
>Category:       kern
>Synopsis:       Removing USB (OHCI) card does not detach devices, but hangs CardBus kernel thread
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Tue Dec 12 17:31:00 PST 2000
>Closed-Date:
>Last-Modified:
>Originator:     ITOH Yasufumi
>Release:        1.5L (Dec. 8, 2000)
>Organization:
>Environment:
System: NetBSD pino.my.domain 1.5L NetBSD 1.5L (PINO) #247: Sun Dec 10 14:13:46 JST 2000 itohy@pino.my.domain:/w/src/sys/arch/i386/compile/PINO i386
Architecture: i386
Machine: i386

machine: Toshiba Libretto 100
kernel dmesg:
	:
cbb0 at pci0 dev 19 function 0: Toshiba ToPIC95B CardBus-PCI Bridge (rev. 0x07)
cbb1 at pci0 dev 19 function 1: Toshiba ToPIC95B CardBus-PCI Bridge (rev. 0x07)
cbb0: interrupting at irq 11
cbb0: cacheline 0x0 lattimer 0x0
cbb0: bhlc 0x820000 lscp 0x141400
cardslot0 at cbb0 slot 0 flags 0
cardbus0 at cardslot0: bus 20 device 0 cacheline 0x0, lattimer 0x0
pcmcia0 at cardslot0
cbb1: interrupting at irq 11
cbb1: cacheline 0x0 lattimer 0x0
cbb1: bhlc 0x820000 lscp 0x151500
cardslot1 at cbb1 slot 1 flags 0
cardbus1 at cardslot1: bus 21 device 0 cacheline 0x0, lattimer 0x0
pcmcia1 at cardslot1
	:

>Description:
	Removing CardBus-USB interface (OHCI) doesn't detach the devices
	properly.  The root device "usb?" and the OHCI itself "ohci?"
	will not be detached.

	The kernel thread for the CardBus slot will hang since then,
	and the slot cannot be used any more.

>How-To-Repeat:
	Here's an OHCI USB card (and a USB mouse).
	Insert it into the CardBus slot #1.

	    ohci0 at cardbus1 dev 0 function 0: Opti RM861HA (rev. 0x10)
	    ohci0: interrupting at 11
	    ohci0: OHCI version 1.0, legacy support
	    usb0 at ohci0: USB revision 1.0
	    uhub0 at usb0
	    uhub0: Opti OHCI root hub, class 9/0, rev 1.00/1.00, addr 1
	    uhub0: 2 ports with 2 removable, self powered
	    ums0 at uhub0 port 1 configuration 1 interface 0
	    ums0: vendor 0x05e3 USB Mouse, rev 1.00/1.01, addr 2, iclass 3/1
	    ums0: 3 buttons and Z dir.
	    wsmouse1 at ums0 mux 0

	Then remove the card.

	    uhub0: at usb0 (addr 1) disconnected
	    ums0: at uhub0 port 1 (addr 2) disconnected
	    wsmouse1 detached
	    ums0 detached
	    uhub0 detached

	Note that the "usb0" and "ohci0" devices are not detached properly.
	The slot #1 will not work any more since the cardslot kernel thread
	is waiting an USB event forever at "usbsyn" channel.

	  % ps l3
	  UID PID PPID CPU PRI NI VSZ   RSS WCHAN  STAT TT   TIME COMMAND
	    0   3    0   2  10  0   0 12384 usbsyn DL   ?? 0:05.75 (cardslot1)

>Fix:
	Here's a workaround (I'm not sure this is correct).
	Do not register events after the root hub is detached.

	This change makes devices detached properly.

	    uhub0: at usb0 (addr 1) disconnected
	    ums0: at uhub0 port 1 (addr 2) disconnected
	    wsmouse1 detached
	    ums0 detached
	    uhub0 detached
	    usb0 detached
	    ohci0 detached

diff -uF^[a-zA-Z_][a-z 	A-Z0-9_]*([^;]*$ sys/dev/usb/usb_subr.c.orig sys/dev/usb/usb_subr.c
--- sys/dev/usb/usb_subr.c.orig	Fri Oct 27 16:59:17 2000
+++ sys/dev/usb/usb_subr.c	Sun Dec 10 10:24:44 2000
@@ -1250,6 +1250,9 @@ usb_disconnect_port(struct usbd_port *up
 	usbd_device_handle dev = up->device;
 	char *hubname = USBDEVPTRNAME(parent);
 	int i;
+#if 1
+	int is_root_hub;
+#endif
 
 	DPRINTFN(3,("uhub_disconnect: up=%p dev=%p port=%d\n", 
 		    up, dev, up->portno));
@@ -1260,6 +1263,9 @@ usb_disconnect_port(struct usbd_port *up
 		return;
 	}
 #endif
+#if 1
+	is_root_hub = (dev == dev->bus->root_hub);
+#endif
 
 	if (dev->subdevs != NULL) {
 		DPRINTFN(3,("usb_disconnect_port: disconnect subdevs\n"));
@@ -1279,6 +1285,9 @@ usb_disconnect_port(struct usbd_port *up
 		}
 	}
 
+#if 1
+	if  (!is_root_hub)
+#endif
 	usbd_add_dev_event(USB_EVENT_DEVICE_DETACH, dev);
 	dev->bus->devices[dev->address] = NULL;
 	up->device = NULL;
>Release-Note:
>Audit-Trail:
>Unformatted: