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