Re: Fw: USB3: unable to enumerate, device not accepting address

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



I'm no longer the USB 3.0 driver maintainer.  Please work with Mathias
Nyman to fix this issue.

Sarah Sharp

On Fri, Oct 31, 2014 at 06:01:24PM +0300, parafin wrote:
> Hi,
> 
> it was suggested to me that since you are the author of offending
> commit I should forward this email to you. Also see this bug:
> https://bugzilla.kernel.org/show_bug.cgi?id=41752
> 
> Begin forwarded message:
> 
> Date: Thu, 30 Oct 2014 22:56:29 +0300
> From: parafin <parafin@xxxxxxxx>
> To: <linux-usb@xxxxxxxxxxxxxxx>
> Subject: USB3: unable to enumerate, device not accepting address
> 
> 
> Hi,
> 
> I have 2 very similar USB3 devices that stopped working sometime after
> kernel version 3.3 - they fail to enumerate unless I reload xhci_hcd
> driver.
> 
> These are the devices:
> http://www.agestar.com/en/Products/Docking-Station/USB3-0/974-usb30esata-to-2535-sata-hdd-docking-station.html
> http://www.agestar.com/en/Products/Docking-Station/USB3-0/980-usb30esata-to-2535-sata-hdd-docking-station.html
> Basically it's some eSATA->USB3 bridge JMicron chip (I'm guessing it's
> the same one in both devices):
> Bus 009 Device 002: ID 152d:2509 JMicron Technology Corp. / JMicron USA Technology Corp. JMS539 SuperSpeed SATA II 3.0G Bridge
> 
> This is USB controller I am testing them with:
> 01:00.0 USB controller: NEC Corporation uPD720200 USB 3.0 Host Controller (rev 03)
> I even tried upgrading firmware, with no result
> 
> It appears in system as 2 buses (lsusb -t output):
> /:  Bus 09.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/2p, 5000M
> /:  Bus 08.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/2p, 480M
> One for SuperSpeed devices, another for slower.
> 
> So here's dmesg for when it fails:
> [  195.207408] hub 8-0:1.0: unable to enumerate USB device on port 1
> [  196.016556] usb 9-1: device not accepting address 2, error -22
> [  196.520572] hub 9-0:1.0: unable to enumerate USB device on port 1
> 
> And here how it should look (when it works):
> [   61.686218] hub 8-0:1.0: unable to enumerate USB device on port 1
> [   63.620211] usb 9-1: new SuperSpeed USB device number 2 using xhci_hcd
> [   63.636918] usb 9-1: New USB device found, idVendor=152d, idProduct=2509
> [   63.636932] usb 9-1: New USB device strings: Mfr=1, Product=11, SerialNumber=3
> [   63.636942] usb 9-1: Product: Usb production
> [   63.636950] usb 9-1: Manufacturer: JMicron
> [   63.636956] usb 9-1: SerialNumber: 00A1234578EA
> [   63.638549] scsi5 : usb-storage 9-1:1.0
> [   64.926983] scsi 5:0:0:0: Direct-Access     Jmicron  Corp.            0000 PQ: 0 ANSI: 5
> [   64.927925] sd 5:0:0:0: Attached scsi generic sg6 type 0
> [   64.929912] sd 5:0:0:0: [sdg] Very big device. Trying to use READ CAPACITY(16).
> [   64.930353] sd 5:0:0:0: [sdg] 5860533168 512-byte logical blocks: (3.00 TB/2.72 TiB)
> [   64.931031] sd 5:0:0:0: [sdg] Write Protect is off
> [   64.931042] sd 5:0:0:0: [sdg] Mode Sense: 28 00 00 00
> [   64.931764] sd 5:0:0:0: [sdg] No Caching mode page present
> [   64.931772] sd 5:0:0:0: [sdg] Assuming drive cache: write through
> [   64.932486] sd 5:0:0:0: [sdg] Very big device. Trying to use READ CAPACITY(16).
> [   64.933992] sd 5:0:0:0: [sdg] No Caching mode page present
> [   64.933997] sd 5:0:0:0: [sdg] Assuming drive cache: write through
> [   64.989015]  sdg: sdg1 sdg2 sdg3 sdg4
> [   64.992112] sd 5:0:0:0: [sdg] Very big device. Trying to use READ CAPACITY(16).
> [   64.993885] sd 5:0:0:0: [sdg] No Caching mode page present
> [   64.993898] sd 5:0:0:0: [sdg] Assuming drive cache: write through
> [   64.993909] sd 5:0:0:0: [sdg] Attached SCSI disk
> First line doesn't always appear, might depend on kernel version, I'm
> not sure.
> 
> I managed to bisect this down to this commit:
> beabe20445c60322719d8f58e9eb9dd4660c1b3e
> (it's from 3.4 branch, included in 3.4.36 release, upstream commit id
> from commit message seems to be invalid, at least it's missing one
> character).
> I backported reverse of this commit to 3.17.1 (I can't run 3.4 kernel
> due to different issues) and it helps with this issue. Patch attached
> in case it is helpful, sorry though for whitespace mess, I used nano:)
> 
> I doubt that just reverting is acceptable solution for mainstream
> kernel, so I'm willing to test some other patches (on top of 3.17.1
> would be best) or provide additional information so that this issue
> could be fixed in next releases.

> --- drivers/usb/core/hub.c.orig	2014-10-30 21:44:50.000746074 +0300
> +++ drivers/usb/core/hub.c	2014-10-30 22:12:01.561256025 +0300
> @@ -2664,56 +2664,95 @@
>  	if ((portstatus & USB_PORT_STAT_RESET))
>  		return -EBUSY;
>  
> -	if (hub_port_warm_reset_required(hub, port1, portstatus))
> -		return -ENOTCONN;
> -
> -	/* Device went away? */
> -	if (!(portstatus & USB_PORT_STAT_CONNECTION))
> -		return -ENOTCONN;
> -
> -	/* bomb out completely if the connection bounced.  A USB 3.0
> -	 * connection may bounce if multiple warm resets were issued,
> -	 * but the device may have successfully re-connected. Ignore it.
> +	/* Some buggy devices require a warm reset to be issued even
> +	 * when the port appears not to be connected.
>  	 */
> -	if (!hub_is_superspeed(hub->hdev) &&
> -			(portchange & USB_PORT_STAT_C_CONNECTION))
> -		return -ENOTCONN;
> -
> -	if (!(portstatus & USB_PORT_STAT_ENABLE))
> -		return -EBUSY;
> +               if (!warm) {
> +                       /*
> +                        * Some buggy devices can cause an NEC host controller
> +                        * to transition to the "Error" state after a hot port
> +                        * reset.  This will show up as the port state in
> +                        * "Inactive", and the port may also report a
> +                        * disconnect.  Forcing a warm port reset seems to make
> +                        * the device work.
> +                        *
> +                        * See https://bugzilla.kernel.org/show_bug.cgi?id=41752
> +                        */
> +                       if (hub_port_warm_reset_required(hub, port1, portstatus)) {
> +                               int ret;
> +
> +                               if ((portchange & USB_PORT_STAT_C_CONNECTION))
> +                                       usb_clear_port_feature(hub->hdev, port1,
> +                                                       USB_PORT_FEAT_C_CONNECTION);
> +                               if (portchange & USB_PORT_STAT_C_LINK_STATE)
> +                                       usb_clear_port_feature(hub->hdev, port1,
> +                                                       USB_PORT_FEAT_C_PORT_LINK_STATE);
> +                               if (portchange & USB_PORT_STAT_C_RESET)
> +                                       usb_clear_port_feature(hub->hdev, port1,
> +                                                       USB_PORT_FEAT_C_RESET);
> +                               dev_dbg(hub->intfdev, "hot reset failed, warm reset port %d\n",
> +                                               port1);
> +                               ret = hub_port_reset(hub, port1,
> +                                               udev, HUB_BH_RESET_TIME,
> +                                               true);
> +                               if ((portchange & USB_PORT_STAT_C_CONNECTION))
> +                                       usb_clear_port_feature(hub->hdev, port1,
> +                                                       USB_PORT_FEAT_C_CONNECTION);
> +                               return ret;
> +                       }
> +                       /* Device went away? */
> +                       if (!(portstatus & USB_PORT_STAT_CONNECTION))
> +                               return -ENOTCONN;
> +
> +                       /* bomb out completely if the connection bounced */
> +                       if ((portchange & USB_PORT_STAT_C_CONNECTION))
> +                               return -ENOTCONN;
> +
> +                       if ((portstatus & USB_PORT_STAT_ENABLE)) {
> +                               if (!udev)
> +                                       return 0;
> +
> +                               if (hub_is_wusb(hub))
> +                                       udev->speed = USB_SPEED_WIRELESS;
> +                               else if (hub_is_superspeed(hub->hdev))
> +                                       udev->speed = USB_SPEED_SUPER;
> +                               else if (portstatus & USB_PORT_STAT_HIGH_SPEED)
> +                                       udev->speed = USB_SPEED_HIGH;
> +                               else if (portstatus & USB_PORT_STAT_LOW_SPEED)
> +                                       udev->speed = USB_SPEED_LOW;
> +                               else
> +                                       udev->speed = USB_SPEED_FULL;
> +				return 0;
> +                       }
> +               } else {
> +                       if (!(portstatus & USB_PORT_STAT_CONNECTION) ||
> +                                       hub_port_warm_reset_required(hub, port1,
> +                                               portstatus))
> +                               return -ENOTCONN;
>  
> -	if (!udev)
>  		return 0;
> -
> -	if (hub_is_wusb(hub))
> -		udev->speed = USB_SPEED_WIRELESS;
> -	else if (hub_is_superspeed(hub->hdev))
> -		udev->speed = USB_SPEED_SUPER;
> -	else if (portstatus & USB_PORT_STAT_HIGH_SPEED)
> -		udev->speed = USB_SPEED_HIGH;
> -	else if (portstatus & USB_PORT_STAT_LOW_SPEED)
> -		udev->speed = USB_SPEED_LOW;
> -	else
> -		udev->speed = USB_SPEED_FULL;
> -	return 0;
> +	}
> +	return -EBUSY;
>  }
>  
>  static void hub_port_finish_reset(struct usb_hub *hub, int port1,
> -			struct usb_device *udev, int *status)
> +			struct usb_device *udev, int *status, bool warm)
>  {
>  	switch (*status) {
>  	case 0:
> -		/* TRSTRCY = 10 ms; plus some extra */
> -		msleep(10 + 40);
> -		if (udev) {
> -			struct usb_hcd *hcd = bus_to_hcd(udev->bus);
> -
> -			update_devnum(udev, 0);
> -			/* The xHC may think the device is already reset,
> -			 * so ignore the status.
> -			 */
> -			if (hcd->driver->reset_device)
> -				hcd->driver->reset_device(hcd, udev);
> +               if (!warm) {
> +                       struct usb_hcd *hcd;
> +                       /* TRSTRCY = 10 ms; plus some extra */
> +                       msleep(10 + 40);
> +                       if (udev) {
> +                               update_devnum(udev, 0);
> +                               hcd = bus_to_hcd(udev->bus);
> +                               /* The xHC may think the device is already
> +                                * reset, so ignore the status.
> +                                */
> +                               if (hcd->driver->reset_device)
> +                                       hcd->driver->reset_device(hcd, udev);
> +                       }
>  		}
>  		/* FALL THROUGH */
>  	case -ENOTCONN:
> @@ -2725,10 +2764,8 @@
>  					USB_PORT_FEAT_C_BH_PORT_RESET);
>  			usb_clear_port_feature(hub->hdev, port1,
>  					USB_PORT_FEAT_C_PORT_LINK_STATE);
> -			usb_clear_port_feature(hub->hdev, port1,
> -					USB_PORT_FEAT_C_CONNECTION);
>  		}
> -		if (udev)
> +		if (!warm && udev)
>  			usb_set_device_state(udev, *status
>  					? USB_STATE_NOTATTACHED
>  					: USB_STATE_DEFAULT);
> @@ -2789,34 +2826,10 @@
>  						status);
>  		}
>  
> -		/* Check for disconnect or reset */
> +		/* return on disconnect or reset */
>  		if (status == 0 || status == -ENOTCONN || status == -ENODEV) {
> -			hub_port_finish_reset(hub, port1, udev, &status);
> -
> -			if (!hub_is_superspeed(hub->hdev))
> -				goto done;
> -
> -			/*
> -			 * If a USB 3.0 device migrates from reset to an error
> -			 * state, re-issue the warm reset.
> -			 */
> -			if (hub_port_status(hub, port1,
> -					&portstatus, &portchange) < 0)
> -				goto done;
> -
> -			if (!hub_port_warm_reset_required(hub, port1,
> -					portstatus))
> -				goto done;
> -
> -			/*
> -			 * If the port is in SS.Inactive or Compliance Mode, the
> -			 * hot or warm reset failed.  Try another warm reset.
> -			 */
> -			if (!warm) {
> -				dev_dbg(&port_dev->dev,
> -						"hot reset failed, warm reset\n");
> -				warm = true;
> -			}
> +                       hub_port_finish_reset(hub, port1, udev, &status, warm);
> +                       goto done;
>  		}
>  
>  		dev_dbg(&port_dev->dev,

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux