USB 3.0 Fails To Attach Western Digital My Book 3.0

Hans Petter Selasky hselasky at c2i.net
Sat Nov 6 09:30:34 UTC 2010


Hi,

Can you revert the last patch I sent an apply the attached one?

Then repeat the testing like last time.

--HPS

> 
> I captured several debug outputs here:
> http://appliedtechnicalknowledge.com/freebsd/usb3-patch-214808/ .  Maybe
> something in these can help.
-------------- next part --------------
=== usb_hub.c
==================================================================
--- usb_hub.c	(revision 214808)
+++ usb_hub.c	(local)
@@ -126,9 +126,10 @@
 
 static usb_callback_t uhub_intr_callback;
 
-static void usb_dev_resume_peer(struct usb_device *udev);
-static void usb_dev_suspend_peer(struct usb_device *udev);
-static uint8_t usb_peer_should_wakeup(struct usb_device *udev);
+static void usb_dev_resume_peer(struct usb_device *);
+static void usb_dev_suspend_peer(struct usb_device *);
+static uint8_t usb_peer_should_wakeup(struct usb_device *);
+static uint8_t usb_device_20_compatible(struct usb_device *);
 
 static const struct usb_config uhub_config[UHUB_N_TRANSFER] = {
 
@@ -394,13 +395,29 @@
 		usb_pause_mtx(NULL, 
 		    USB_MS_TO_TICKS(USB_PORT_POWERUP_DELAY));
 
-		/* reset port, which implies enabling it */
+		if (usb_device_20_compatible(udev)) {
+			/* reset port, which implies enabling it */
+			err = usbd_req_reset_port(udev, NULL, portno);
+		} else {
+			switch (UPS_PORT_LINK_STATE_GET(sc->sc_st.port_status)) {
+			case UPS_PORT_LS_U0:
+			case UPS_PORT_LS_U1:
+			case UPS_PORT_LS_U2:
+			case UPS_PORT_LS_U3:
+				/* no reset needed, link is already UP */
+				break;
+			case UPS_PORT_LS_SS_INA:
+				/* try to recover link using a warm reset */
+				goto error;
+			default:
+				/* reset port, which implies enabling it */
+				err = usbd_req_reset_port(udev, NULL, portno);
+				break;
+			}
+		}
 
-		err = usbd_req_reset_port(udev, NULL, portno);
-
 		if (err) {
-			DPRINTFN(0, "port %d reset "
-			    "failed, error=%s\n",
+			DPRINTFN(0, "port %d reset failed, error=%s\n",
 			    portno, usbd_errstr(err));
 			goto error;
 		}
@@ -517,17 +534,43 @@
 		usb_free_device(child, 0);
 		child = NULL;
 	}
-	if (err == 0) {
+	if (err) {
+		DPRINTFN(0, "device problem (%s), "
+		    "port %u\n", usbd_errstr(err), portno);
+		goto error_ret;
+	}
+	if (usb_device_20_compatible(udev)) {
+		/* disable the port, if enabled */
 		if (sc->sc_st.port_status & UPS_PORT_ENABLED) {
 			err = usbd_req_clear_port_feature(
-			    sc->sc_udev, NULL,
-			    portno, UHF_PORT_ENABLE);
+			    udev, NULL, portno, UHF_PORT_ENABLE);
 		}
+	} else {
+		/* get fresh status again */
+		err = uhub_read_port_status(sc, portno);
+		if (err)
+			goto error_ret;
+
+		switch (UPS_PORT_LINK_STATE_GET(sc->sc_st.port_status)) {
+		case UPS_PORT_LS_SS_INA:
+			/* Try a warm port reset to recover the port. */
+			err = usbd_req_warm_reset_port(udev, NULL, portno);
+			if (err) {
+				DPRINTF("warm port reset failed.\n");
+				goto error_ret;
+			}
+			break;
+		default:
+			/* disable the port, if enabled */
+			if (sc->sc_st.port_status & UPS_PORT_ENABLED) {
+				err = usbd_req_clear_port_feature(
+				  udev, NULL, portno, UHF_PORT_ENABLE);
+			}
+			break;
+		}
 	}
-	if (err) {
-		DPRINTFN(0, "device problem (%s), "
-		    "disabling port %d\n", usbd_errstr(err), portno);
-	}
+
+error_ret:
 	return (err);
 }
 


More information about the freebsd-usb mailing list