Merge branch 'usb-3.3-rc4' into usb-next

This is to pull in the xhci changes and the other fixes and device id
updates that were done in Linus's tree.

Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Greg Kroah-Hartman 2012-02-23 08:20:44 -08:00
commit c69263c66e
56 changed files with 1051 additions and 352 deletions

View File

@ -182,3 +182,14 @@ Description:
USB2 hardware LPM is enabled for the device. Developer can USB2 hardware LPM is enabled for the device. Developer can
write y/Y/1 or n/N/0 to the file to enable/disable the write y/Y/1 or n/N/0 to the file to enable/disable the
feature. feature.
What: /sys/bus/usb/devices/.../removable
Date: February 2012
Contact: Matthew Garrett <mjg@redhat.com>
Description:
Some information about whether a given USB device is
physically fixed to the platform can be inferred from a
combination of hub decriptor bits and platform-specific data
such as ACPI. This file will read either "removable" or
"fixed" if the information is available, and "unknown"
otherwise.

View File

@ -1295,6 +1295,7 @@ EXPORT_SYMBOL(int_to_scsilun);
* LUNs even if it's older than SCSI-3. * LUNs even if it's older than SCSI-3.
* If BLIST_NOREPORTLUN is set, return 1 always. * If BLIST_NOREPORTLUN is set, return 1 always.
* If BLIST_NOLUN is set, return 0 always. * If BLIST_NOLUN is set, return 0 always.
* If starget->no_report_luns is set, return 1 always.
* *
* Return: * Return:
* 0: scan completed (or no memory, so further scanning is futile) * 0: scan completed (or no memory, so further scanning is futile)
@ -1321,6 +1322,7 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags,
* Only support SCSI-3 and up devices if BLIST_NOREPORTLUN is not set. * Only support SCSI-3 and up devices if BLIST_NOREPORTLUN is not set.
* Also allow SCSI-2 if BLIST_REPORTLUN2 is set and host adapter does * Also allow SCSI-2 if BLIST_REPORTLUN2 is set and host adapter does
* support more than 8 LUNs. * support more than 8 LUNs.
* Don't attempt if the target doesn't support REPORT LUNS.
*/ */
if (bflags & BLIST_NOREPORTLUN) if (bflags & BLIST_NOREPORTLUN)
return 1; return 1;
@ -1332,6 +1334,8 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags,
return 1; return 1;
if (bflags & BLIST_NOLUN) if (bflags & BLIST_NOLUN)
return 0; return 0;
if (starget->no_report_luns)
return 1;
if (!(sdev = scsi_device_lookup_by_target(starget, 0))) { if (!(sdev = scsi_device_lookup_by_target(starget, 0))) {
sdev = scsi_alloc_sdev(starget, 0, NULL); sdev = scsi_alloc_sdev(starget, 0, NULL);

View File

@ -2349,7 +2349,7 @@ static int sd_try_extended_inquiry(struct scsi_device *sdp)
* some USB ones crash on receiving them, and the pages * some USB ones crash on receiving them, and the pages
* we currently ask for are for SPC-3 and beyond * we currently ask for are for SPC-3 and beyond
*/ */
if (sdp->scsi_level > SCSI_SPC_2) if (sdp->scsi_level > SCSI_SPC_2 && !sdp->skip_vpd_pages)
return 1; return 1;
return 0; return 0;
} }

View File

@ -76,6 +76,7 @@ config USB_ARCH_HAS_EHCI
default y if MICROBLAZE default y if MICROBLAZE
default y if SPARC_LEON default y if SPARC_LEON
default y if ARCH_MMP default y if ARCH_MMP
default y if MACH_LOONGSON1
default PCI default PCI
# some non-PCI HCDs implement xHCI # some non-PCI HCDs implement xHCI

View File

@ -31,6 +31,8 @@
#define DRIVER_AUTHOR "Oliver Neukum" #define DRIVER_AUTHOR "Oliver Neukum"
#define DRIVER_DESC "USB Abstract Control Model driver for USB WCM Device Management" #define DRIVER_DESC "USB Abstract Control Model driver for USB WCM Device Management"
#define HUAWEI_VENDOR_ID 0x12D1
static const struct usb_device_id wdm_ids[] = { static const struct usb_device_id wdm_ids[] = {
{ {
.match_flags = USB_DEVICE_ID_MATCH_INT_CLASS | .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS |
@ -38,6 +40,20 @@ static const struct usb_device_id wdm_ids[] = {
.bInterfaceClass = USB_CLASS_COMM, .bInterfaceClass = USB_CLASS_COMM,
.bInterfaceSubClass = USB_CDC_SUBCLASS_DMM .bInterfaceSubClass = USB_CDC_SUBCLASS_DMM
}, },
{
/*
* Huawei E392, E398 and possibly other Qualcomm based modems
* embed the Qualcomm QMI protocol inside CDC on CDC ECM like
* control interfaces. Userspace access to this is required
* to configure the accompanying data interface
*/
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = HUAWEI_VENDOR_ID,
.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 9, /* NOTE: CDC ECM control interface! */
},
{ } { }
}; };
@ -54,6 +70,7 @@ MODULE_DEVICE_TABLE (usb, wdm_ids);
#define WDM_POLL_RUNNING 6 #define WDM_POLL_RUNNING 6
#define WDM_RESPONDING 7 #define WDM_RESPONDING 7
#define WDM_SUSPENDING 8 #define WDM_SUSPENDING 8
#define WDM_RESETTING 9
#define WDM_MAX 16 #define WDM_MAX 16
@ -82,7 +99,6 @@ struct wdm_device {
u16 bufsize; u16 bufsize;
u16 wMaxCommand; u16 wMaxCommand;
u16 wMaxPacketSize; u16 wMaxPacketSize;
u16 bMaxPacketSize0;
__le16 inum; __le16 inum;
int reslength; int reslength;
int length; int length;
@ -162,11 +178,9 @@ static void wdm_int_callback(struct urb *urb)
int rv = 0; int rv = 0;
int status = urb->status; int status = urb->status;
struct wdm_device *desc; struct wdm_device *desc;
struct usb_ctrlrequest *req;
struct usb_cdc_notification *dr; struct usb_cdc_notification *dr;
desc = urb->context; desc = urb->context;
req = desc->irq;
dr = (struct usb_cdc_notification *)desc->sbuf; dr = (struct usb_cdc_notification *)desc->sbuf;
if (status) { if (status) {
@ -213,24 +227,6 @@ static void wdm_int_callback(struct urb *urb)
goto exit; goto exit;
} }
req->bRequestType = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE);
req->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE;
req->wValue = 0;
req->wIndex = desc->inum;
req->wLength = cpu_to_le16(desc->wMaxCommand);
usb_fill_control_urb(
desc->response,
interface_to_usbdev(desc->intf),
/* using common endpoint 0 */
usb_rcvctrlpipe(interface_to_usbdev(desc->intf), 0),
(unsigned char *)req,
desc->inbuf,
desc->wMaxCommand,
wdm_in_callback,
desc
);
desc->response->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
spin_lock(&desc->iuspin); spin_lock(&desc->iuspin);
clear_bit(WDM_READ, &desc->flags); clear_bit(WDM_READ, &desc->flags);
set_bit(WDM_RESPONDING, &desc->flags); set_bit(WDM_RESPONDING, &desc->flags);
@ -279,14 +275,8 @@ static void free_urbs(struct wdm_device *desc)
static void cleanup(struct wdm_device *desc) static void cleanup(struct wdm_device *desc)
{ {
usb_free_coherent(interface_to_usbdev(desc->intf), kfree(desc->sbuf);
desc->wMaxPacketSize, kfree(desc->inbuf);
desc->sbuf,
desc->validity->transfer_dma);
usb_free_coherent(interface_to_usbdev(desc->intf),
desc->bMaxPacketSize0,
desc->inbuf,
desc->response->transfer_dma);
kfree(desc->orq); kfree(desc->orq);
kfree(desc->irq); kfree(desc->irq);
kfree(desc->ubuf); kfree(desc->ubuf);
@ -351,6 +341,10 @@ static ssize_t wdm_write
else else
if (test_bit(WDM_IN_USE, &desc->flags)) if (test_bit(WDM_IN_USE, &desc->flags))
r = -EAGAIN; r = -EAGAIN;
if (test_bit(WDM_RESETTING, &desc->flags))
r = -EIO;
if (r < 0) { if (r < 0) {
kfree(buf); kfree(buf);
goto out; goto out;
@ -430,6 +424,10 @@ retry:
rv = -ENODEV; rv = -ENODEV;
goto err; goto err;
} }
if (test_bit(WDM_RESETTING, &desc->flags)) {
rv = -EIO;
goto err;
}
usb_mark_last_busy(interface_to_usbdev(desc->intf)); usb_mark_last_busy(interface_to_usbdev(desc->intf));
if (rv < 0) { if (rv < 0) {
rv = -ERESTARTSYS; rv = -ERESTARTSYS;
@ -631,7 +629,6 @@ static void wdm_rxwork(struct work_struct *work)
static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id) static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id)
{ {
int rv = -EINVAL; int rv = -EINVAL;
struct usb_device *udev = interface_to_usbdev(intf);
struct wdm_device *desc; struct wdm_device *desc;
struct usb_host_interface *iface; struct usb_host_interface *iface;
struct usb_endpoint_descriptor *ep; struct usb_endpoint_descriptor *ep;
@ -692,7 +689,6 @@ next_desc:
goto err; goto err;
desc->wMaxPacketSize = usb_endpoint_maxp(ep); desc->wMaxPacketSize = usb_endpoint_maxp(ep);
desc->bMaxPacketSize0 = udev->descriptor.bMaxPacketSize0;
desc->orq = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); desc->orq = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
if (!desc->orq) if (!desc->orq)
@ -717,19 +713,13 @@ next_desc:
if (!desc->ubuf) if (!desc->ubuf)
goto err; goto err;
desc->sbuf = usb_alloc_coherent(interface_to_usbdev(intf), desc->sbuf = kmalloc(desc->wMaxPacketSize, GFP_KERNEL);
desc->wMaxPacketSize,
GFP_KERNEL,
&desc->validity->transfer_dma);
if (!desc->sbuf) if (!desc->sbuf)
goto err; goto err;
desc->inbuf = usb_alloc_coherent(interface_to_usbdev(intf), desc->inbuf = kmalloc(desc->wMaxCommand, GFP_KERNEL);
desc->wMaxCommand,
GFP_KERNEL,
&desc->response->transfer_dma);
if (!desc->inbuf) if (!desc->inbuf)
goto err2; goto err;
usb_fill_int_urb( usb_fill_int_urb(
desc->validity, desc->validity,
@ -741,30 +731,39 @@ next_desc:
desc, desc,
ep->bInterval ep->bInterval
); );
desc->validity->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
desc->irq->bRequestType = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE);
desc->irq->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE;
desc->irq->wValue = 0;
desc->irq->wIndex = desc->inum;
desc->irq->wLength = cpu_to_le16(desc->wMaxCommand);
usb_fill_control_urb(
desc->response,
interface_to_usbdev(intf),
/* using common endpoint 0 */
usb_rcvctrlpipe(interface_to_usbdev(desc->intf), 0),
(unsigned char *)desc->irq,
desc->inbuf,
desc->wMaxCommand,
wdm_in_callback,
desc
);
usb_set_intfdata(intf, desc); usb_set_intfdata(intf, desc);
rv = usb_register_dev(intf, &wdm_class); rv = usb_register_dev(intf, &wdm_class);
if (rv < 0) if (rv < 0)
goto err3; goto err2;
else else
dev_info(&intf->dev, "cdc-wdm%d: USB WDM device\n", dev_info(&intf->dev, "%s: USB WDM device\n", dev_name(intf->usb_dev));
intf->minor - WDM_MINOR_BASE);
out: out:
return rv; return rv;
err3:
usb_set_intfdata(intf, NULL);
usb_free_coherent(interface_to_usbdev(desc->intf),
desc->bMaxPacketSize0,
desc->inbuf,
desc->response->transfer_dma);
err2: err2:
usb_free_coherent(interface_to_usbdev(desc->intf), usb_set_intfdata(intf, NULL);
desc->wMaxPacketSize,
desc->sbuf,
desc->validity->transfer_dma);
err: err:
free_urbs(desc); free_urbs(desc);
kfree(desc->inbuf);
kfree(desc->sbuf);
kfree(desc->ubuf); kfree(desc->ubuf);
kfree(desc->orq); kfree(desc->orq);
kfree(desc->irq); kfree(desc->irq);
@ -869,10 +868,6 @@ static int wdm_pre_reset(struct usb_interface *intf)
{ {
struct wdm_device *desc = usb_get_intfdata(intf); struct wdm_device *desc = usb_get_intfdata(intf);
mutex_lock(&desc->rlock);
mutex_lock(&desc->wlock);
kill_urbs(desc);
/* /*
* we notify everybody using poll of * we notify everybody using poll of
* an exceptional situation * an exceptional situation
@ -880,9 +875,16 @@ static int wdm_pre_reset(struct usb_interface *intf)
* message from the device is lost * message from the device is lost
*/ */
spin_lock_irq(&desc->iuspin); spin_lock_irq(&desc->iuspin);
set_bit(WDM_RESETTING, &desc->flags); /* inform read/write */
set_bit(WDM_READ, &desc->flags); /* unblock read */
clear_bit(WDM_IN_USE, &desc->flags); /* unblock write */
desc->rerr = -EINTR; desc->rerr = -EINTR;
spin_unlock_irq(&desc->iuspin); spin_unlock_irq(&desc->iuspin);
wake_up_all(&desc->wait); wake_up_all(&desc->wait);
mutex_lock(&desc->rlock);
mutex_lock(&desc->wlock);
kill_urbs(desc);
cancel_work_sync(&desc->rxwork);
return 0; return 0;
} }
@ -891,6 +893,7 @@ static int wdm_post_reset(struct usb_interface *intf)
struct wdm_device *desc = usb_get_intfdata(intf); struct wdm_device *desc = usb_get_intfdata(intf);
int rv; int rv;
clear_bit(WDM_RESETTING, &desc->flags);
rv = recover_from_urb_loss(desc); rv = recover_from_urb_loss(desc);
mutex_unlock(&desc->wlock); mutex_unlock(&desc->wlock);
mutex_unlock(&desc->rlock); mutex_unlock(&desc->rlock);

View File

@ -958,13 +958,8 @@ void usb_rebind_intf(struct usb_interface *intf)
int rc; int rc;
/* Delayed unbind of an existing driver */ /* Delayed unbind of an existing driver */
if (intf->dev.driver) { if (intf->dev.driver)
struct usb_driver *driver = usb_forced_unbind_intf(intf);
to_usb_driver(intf->dev.driver);
dev_dbg(&intf->dev, "forced unbind\n");
usb_driver_release_interface(driver, intf);
}
/* Try to rebind the interface */ /* Try to rebind the interface */
if (!intf->dev.power.is_prepared) { if (!intf->dev.power.is_prepared) {
@ -977,15 +972,13 @@ void usb_rebind_intf(struct usb_interface *intf)
#ifdef CONFIG_PM #ifdef CONFIG_PM
#define DO_UNBIND 0 /* Unbind drivers for @udev's interfaces that don't support suspend/resume
#define DO_REBIND 1 * There is no check for reset_resume here because it can be determined
* only during resume whether reset_resume is needed.
/* Unbind drivers for @udev's interfaces that don't support suspend/resume,
* or rebind interfaces that have been unbound, according to @action.
* *
* The caller must hold @udev's device lock. * The caller must hold @udev's device lock.
*/ */
static void do_unbind_rebind(struct usb_device *udev, int action) static void unbind_no_pm_drivers_interfaces(struct usb_device *udev)
{ {
struct usb_host_config *config; struct usb_host_config *config;
int i; int i;
@ -996,23 +989,53 @@ static void do_unbind_rebind(struct usb_device *udev, int action)
if (config) { if (config) {
for (i = 0; i < config->desc.bNumInterfaces; ++i) { for (i = 0; i < config->desc.bNumInterfaces; ++i) {
intf = config->interface[i]; intf = config->interface[i];
switch (action) {
case DO_UNBIND: if (intf->dev.driver) {
if (intf->dev.driver) { drv = to_usb_driver(intf->dev.driver);
drv = to_usb_driver(intf->dev.driver); if (!drv->suspend || !drv->resume)
if (!drv->suspend || !drv->resume) usb_forced_unbind_intf(intf);
usb_forced_unbind_intf(intf);
}
break;
case DO_REBIND:
if (intf->needs_binding)
usb_rebind_intf(intf);
break;
} }
} }
} }
} }
/* Unbind drivers for @udev's interfaces that failed to support reset-resume.
* These interfaces have the needs_binding flag set by usb_resume_interface().
*
* The caller must hold @udev's device lock.
*/
static void unbind_no_reset_resume_drivers_interfaces(struct usb_device *udev)
{
struct usb_host_config *config;
int i;
struct usb_interface *intf;
config = udev->actconfig;
if (config) {
for (i = 0; i < config->desc.bNumInterfaces; ++i) {
intf = config->interface[i];
if (intf->dev.driver && intf->needs_binding)
usb_forced_unbind_intf(intf);
}
}
}
static void do_rebind_interfaces(struct usb_device *udev)
{
struct usb_host_config *config;
int i;
struct usb_interface *intf;
config = udev->actconfig;
if (config) {
for (i = 0; i < config->desc.bNumInterfaces; ++i) {
intf = config->interface[i];
if (intf->needs_binding)
usb_rebind_intf(intf);
}
}
}
static int usb_suspend_device(struct usb_device *udev, pm_message_t msg) static int usb_suspend_device(struct usb_device *udev, pm_message_t msg)
{ {
struct usb_device_driver *udriver; struct usb_device_driver *udriver;
@ -1302,35 +1325,48 @@ int usb_suspend(struct device *dev, pm_message_t msg)
{ {
struct usb_device *udev = to_usb_device(dev); struct usb_device *udev = to_usb_device(dev);
do_unbind_rebind(udev, DO_UNBIND); unbind_no_pm_drivers_interfaces(udev);
/* From now on we are sure all drivers support suspend/resume
* but not necessarily reset_resume()
* so we may still need to unbind and rebind upon resume
*/
choose_wakeup(udev, msg); choose_wakeup(udev, msg);
return usb_suspend_both(udev, msg); return usb_suspend_both(udev, msg);
} }
/* The device lock is held by the PM core */
int usb_resume_complete(struct device *dev)
{
struct usb_device *udev = to_usb_device(dev);
/* For PM complete calls, all we do is rebind interfaces
* whose needs_binding flag is set
*/
if (udev->state != USB_STATE_NOTATTACHED)
do_rebind_interfaces(udev);
return 0;
}
/* The device lock is held by the PM core */ /* The device lock is held by the PM core */
int usb_resume(struct device *dev, pm_message_t msg) int usb_resume(struct device *dev, pm_message_t msg)
{ {
struct usb_device *udev = to_usb_device(dev); struct usb_device *udev = to_usb_device(dev);
int status; int status;
/* For PM complete calls, all we do is rebind interfaces */ /* For all calls, take the device back to full power and
if (msg.event == PM_EVENT_ON) {
if (udev->state != USB_STATE_NOTATTACHED)
do_unbind_rebind(udev, DO_REBIND);
status = 0;
/* For all other calls, take the device back to full power and
* tell the PM core in case it was autosuspended previously. * tell the PM core in case it was autosuspended previously.
* Unbind the interfaces that will need rebinding later. * Unbind the interfaces that will need rebinding later,
* because they fail to support reset_resume.
* (This can't be done in usb_resume_interface()
* above because it doesn't own the right set of locks.)
*/ */
} else { status = usb_resume_both(udev, msg);
status = usb_resume_both(udev, msg); if (status == 0) {
if (status == 0) { pm_runtime_disable(dev);
pm_runtime_disable(dev); pm_runtime_set_active(dev);
pm_runtime_set_active(dev); pm_runtime_enable(dev);
pm_runtime_enable(dev); unbind_no_reset_resume_drivers_interfaces(udev);
do_unbind_rebind(udev, DO_REBIND);
}
} }
/* Avoid PM error messages for devices disconnected while suspended /* Avoid PM error messages for devices disconnected while suspended

View File

@ -62,6 +62,8 @@ struct usb_hub {
resumed */ resumed */
unsigned long removed_bits[1]; /* ports with a "removed" unsigned long removed_bits[1]; /* ports with a "removed"
device present */ device present */
unsigned long wakeup_bits[1]; /* ports that have signaled
remote wakeup */
#if USB_MAXCHILDREN > 31 /* 8*sizeof(unsigned long) - 1 */ #if USB_MAXCHILDREN > 31 /* 8*sizeof(unsigned long) - 1 */
#error event_bits[] is too short! #error event_bits[] is too short!
#endif #endif
@ -411,6 +413,29 @@ void usb_kick_khubd(struct usb_device *hdev)
kick_khubd(hub); kick_khubd(hub);
} }
/*
* Let the USB core know that a USB 3.0 device has sent a Function Wake Device
* Notification, which indicates it had initiated remote wakeup.
*
* USB 3.0 hubs do not report the port link state change from U3 to U0 when the
* device initiates resume, so the USB core will not receive notice of the
* resume through the normal hub interrupt URB.
*/
void usb_wakeup_notification(struct usb_device *hdev,
unsigned int portnum)
{
struct usb_hub *hub;
if (!hdev)
return;
hub = hdev_to_hub(hdev);
if (hub) {
set_bit(portnum, hub->wakeup_bits);
kick_khubd(hub);
}
}
EXPORT_SYMBOL_GPL(usb_wakeup_notification);
/* completion function, fires on port status changes and various faults */ /* completion function, fires on port status changes and various faults */
static void hub_irq(struct urb *urb) static void hub_irq(struct urb *urb)
@ -823,12 +848,6 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
clear_port_feature(hub->hdev, port1, clear_port_feature(hub->hdev, port1,
USB_PORT_FEAT_C_ENABLE); USB_PORT_FEAT_C_ENABLE);
} }
if (portchange & USB_PORT_STAT_C_LINK_STATE) {
need_debounce_delay = true;
clear_port_feature(hub->hdev, port1,
USB_PORT_FEAT_C_PORT_LINK_STATE);
}
if ((portchange & USB_PORT_STAT_C_BH_RESET) && if ((portchange & USB_PORT_STAT_C_BH_RESET) &&
hub_is_superspeed(hub->hdev)) { hub_is_superspeed(hub->hdev)) {
need_debounce_delay = true; need_debounce_delay = true;
@ -850,12 +869,19 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
set_bit(port1, hub->change_bits); set_bit(port1, hub->change_bits);
} else if (portstatus & USB_PORT_STAT_ENABLE) { } else if (portstatus & USB_PORT_STAT_ENABLE) {
bool port_resumed = (portstatus &
USB_PORT_STAT_LINK_STATE) ==
USB_SS_PORT_LS_U0;
/* The power session apparently survived the resume. /* The power session apparently survived the resume.
* If there was an overcurrent or suspend change * If there was an overcurrent or suspend change
* (i.e., remote wakeup request), have khubd * (i.e., remote wakeup request), have khubd
* take care of it. * take care of it. Look at the port link state
* for USB 3.0 hubs, since they don't have a suspend
* change bit, and they don't set the port link change
* bit on device-initiated resume.
*/ */
if (portchange) if (portchange || (hub_is_superspeed(hub->hdev) &&
port_resumed))
set_bit(port1, hub->change_bits); set_bit(port1, hub->change_bits);
} else if (udev->persist_enabled) { } else if (udev->persist_enabled) {
@ -1293,14 +1319,8 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
desc = intf->cur_altsetting; desc = intf->cur_altsetting;
hdev = interface_to_usbdev(intf); hdev = interface_to_usbdev(intf);
/* Hubs have proper suspend/resume support. USB 3.0 device suspend is /* Hubs have proper suspend/resume support. */
* different from USB 2.0/1.1 device suspend, and unfortunately we usb_enable_autosuspend(hdev);
* don't support it yet. So leave autosuspend disabled for USB 3.0
* external hubs for now. Enable autosuspend for USB 3.0 roothubs,
* since that isn't a "real" hub.
*/
if (!hub_is_superspeed(hdev) || !hdev->parent)
usb_enable_autosuspend(hdev);
if (hdev->level == MAX_TOPO_LEVEL) { if (hdev->level == MAX_TOPO_LEVEL) {
dev_err(&intf->dev, dev_err(&intf->dev,
@ -1842,6 +1862,37 @@ fail:
return err; return err;
} }
static void set_usb_port_removable(struct usb_device *udev)
{
struct usb_device *hdev = udev->parent;
struct usb_hub *hub;
u8 port = udev->portnum;
u16 wHubCharacteristics;
bool removable = true;
if (!hdev)
return;
hub = hdev_to_hub(udev->parent);
wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
if (!(wHubCharacteristics & HUB_CHAR_COMPOUND))
return;
if (hub_is_superspeed(hdev)) {
if (hub->descriptor->u.ss.DeviceRemovable & (1 << port))
removable = false;
} else {
if (hub->descriptor->u.hs.DeviceRemovable[port / 8] & (1 << (port % 8)))
removable = false;
}
if (removable)
udev->removable = USB_DEVICE_REMOVABLE;
else
udev->removable = USB_DEVICE_FIXED;
}
/** /**
* usb_new_device - perform initial device setup (usbcore-internal) * usb_new_device - perform initial device setup (usbcore-internal)
@ -1900,6 +1951,15 @@ int usb_new_device(struct usb_device *udev)
announce_device(udev); announce_device(udev);
device_enable_async_suspend(&udev->dev); device_enable_async_suspend(&udev->dev);
/*
* check whether the hub marks this port as non-removable. Do it
* now so that platform-specific data can override it in
* device_add()
*/
if (udev->parent)
set_usb_port_removable(udev);
/* Register the device. The device driver is responsible /* Register the device. The device driver is responsible
* for configuring the device and invoking the add-device * for configuring the device and invoking the add-device
* notifier chain (used by usbfs and possibly others). * notifier chain (used by usbfs and possibly others).
@ -2385,11 +2445,27 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
* we don't explicitly enable it here. * we don't explicitly enable it here.
*/ */
if (udev->do_remote_wakeup) { if (udev->do_remote_wakeup) {
status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), if (!hub_is_superspeed(hub->hdev)) {
USB_REQ_SET_FEATURE, USB_RECIP_DEVICE, status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
USB_DEVICE_REMOTE_WAKEUP, 0, USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,
NULL, 0, USB_DEVICE_REMOTE_WAKEUP, 0,
USB_CTRL_SET_TIMEOUT); NULL, 0,
USB_CTRL_SET_TIMEOUT);
} else {
/* Assume there's only one function on the USB 3.0
* device and enable remote wake for the first
* interface. FIXME if the interface association
* descriptor shows there's more than one function.
*/
status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
USB_REQ_SET_FEATURE,
USB_RECIP_INTERFACE,
USB_INTRF_FUNC_SUSPEND,
USB_INTRF_FUNC_SUSPEND_RW |
USB_INTRF_FUNC_SUSPEND_LP,
NULL, 0,
USB_CTRL_SET_TIMEOUT);
}
if (status) { if (status) {
dev_dbg(&udev->dev, "won't remote wakeup, status %d\n", dev_dbg(&udev->dev, "won't remote wakeup, status %d\n",
status); status);
@ -2679,6 +2755,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
struct usb_hub *hub = usb_get_intfdata (intf); struct usb_hub *hub = usb_get_intfdata (intf);
struct usb_device *hdev = hub->hdev; struct usb_device *hdev = hub->hdev;
unsigned port1; unsigned port1;
int status;
/* Warn if children aren't already suspended */ /* Warn if children aren't already suspended */
for (port1 = 1; port1 <= hdev->maxchild; port1++) { for (port1 = 1; port1 <= hdev->maxchild; port1++) {
@ -2691,6 +2768,17 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
return -EBUSY; return -EBUSY;
} }
} }
if (hub_is_superspeed(hdev) && hdev->do_remote_wakeup) {
/* Enable hub to send remote wakeup for all ports. */
for (port1 = 1; port1 <= hdev->maxchild; port1++) {
status = set_port_feature(hdev,
port1 |
USB_PORT_FEAT_REMOTE_WAKE_CONNECT |
USB_PORT_FEAT_REMOTE_WAKE_DISCONNECT |
USB_PORT_FEAT_REMOTE_WAKE_OVER_CURRENT,
USB_PORT_FEAT_REMOTE_WAKE_MASK);
}
}
dev_dbg(&intf->dev, "%s\n", __func__); dev_dbg(&intf->dev, "%s\n", __func__);
@ -3424,6 +3512,46 @@ done:
hcd->driver->relinquish_port(hcd, port1); hcd->driver->relinquish_port(hcd, port1);
} }
/* Returns 1 if there was a remote wakeup and a connect status change. */
static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port,
u16 portstatus, u16 portchange)
{
struct usb_device *hdev;
struct usb_device *udev;
int connect_change = 0;
int ret;
hdev = hub->hdev;
udev = hdev->children[port-1];
if (!hub_is_superspeed(hdev)) {
if (!(portchange & USB_PORT_STAT_C_SUSPEND))
return 0;
clear_port_feature(hdev, port, USB_PORT_FEAT_C_SUSPEND);
} else {
if (!udev || udev->state != USB_STATE_SUSPENDED ||
(portstatus & USB_PORT_STAT_LINK_STATE) !=
USB_SS_PORT_LS_U0)
return 0;
}
if (udev) {
/* TRSMRCY = 10 msec */
msleep(10);
usb_lock_device(udev);
ret = usb_remote_wakeup(udev);
usb_unlock_device(udev);
if (ret < 0)
connect_change = 1;
} else {
ret = -ENODEV;
hub_port_disable(hub, port, 1);
}
dev_dbg(hub->intfdev, "resume on port %d, status %d\n",
port, ret);
return connect_change;
}
static void hub_events(void) static void hub_events(void)
{ {
struct list_head *tmp; struct list_head *tmp;
@ -3436,7 +3564,7 @@ static void hub_events(void)
u16 portstatus; u16 portstatus;
u16 portchange; u16 portchange;
int i, ret; int i, ret;
int connect_change; int connect_change, wakeup_change;
/* /*
* We restart the list every time to avoid a deadlock with * We restart the list every time to avoid a deadlock with
@ -3515,8 +3643,9 @@ static void hub_events(void)
if (test_bit(i, hub->busy_bits)) if (test_bit(i, hub->busy_bits))
continue; continue;
connect_change = test_bit(i, hub->change_bits); connect_change = test_bit(i, hub->change_bits);
wakeup_change = test_and_clear_bit(i, hub->wakeup_bits);
if (!test_and_clear_bit(i, hub->event_bits) && if (!test_and_clear_bit(i, hub->event_bits) &&
!connect_change) !connect_change && !wakeup_change)
continue; continue;
ret = hub_port_status(hub, i, ret = hub_port_status(hub, i,
@ -3557,31 +3686,10 @@ static void hub_events(void)
} }
} }
if (portchange & USB_PORT_STAT_C_SUSPEND) { if (hub_handle_remote_wakeup(hub, i,
struct usb_device *udev; portstatus, portchange))
connect_change = 1;
clear_port_feature(hdev, i,
USB_PORT_FEAT_C_SUSPEND);
udev = hdev->children[i-1];
if (udev) {
/* TRSMRCY = 10 msec */
msleep(10);
usb_lock_device(udev);
ret = usb_remote_wakeup(hdev->
children[i-1]);
usb_unlock_device(udev);
if (ret < 0)
connect_change = 1;
} else {
ret = -ENODEV;
hub_port_disable(hub, i, 1);
}
dev_dbg (hub_dev,
"resume on port %d, status %d\n",
i, ret);
}
if (portchange & USB_PORT_STAT_C_OVERCURRENT) { if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
u16 status = 0; u16 status = 0;
u16 unused; u16 unused;

View File

@ -230,6 +230,28 @@ show_urbnum(struct device *dev, struct device_attribute *attr, char *buf)
} }
static DEVICE_ATTR(urbnum, S_IRUGO, show_urbnum, NULL); static DEVICE_ATTR(urbnum, S_IRUGO, show_urbnum, NULL);
static ssize_t
show_removable(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_device *udev;
char *state;
udev = to_usb_device(dev);
switch (udev->removable) {
case USB_DEVICE_REMOVABLE:
state = "removable";
break;
case USB_DEVICE_FIXED:
state = "fixed";
break;
default:
state = "unknown";
}
return sprintf(buf, "%s\n", state);
}
static DEVICE_ATTR(removable, S_IRUGO, show_removable, NULL);
#ifdef CONFIG_PM #ifdef CONFIG_PM
@ -626,6 +648,7 @@ static struct attribute *dev_attrs[] = {
&dev_attr_avoid_reset_quirk.attr, &dev_attr_avoid_reset_quirk.attr,
&dev_attr_authorized.attr, &dev_attr_authorized.attr,
&dev_attr_remove.attr, &dev_attr_remove.attr,
&dev_attr_removable.attr,
NULL, NULL,
}; };
static struct attribute_group dev_attr_grp = { static struct attribute_group dev_attr_grp = {

View File

@ -403,20 +403,17 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
* cause problems in HCDs if they get it wrong. * cause problems in HCDs if they get it wrong.
*/ */
{ {
unsigned int orig_flags = urb->transfer_flags;
unsigned int allowed; unsigned int allowed;
static int pipetypes[4] = { static int pipetypes[4] = {
PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT
}; };
/* Check that the pipe's type matches the endpoint's type */ /* Check that the pipe's type matches the endpoint's type */
if (usb_pipetype(urb->pipe) != pipetypes[xfertype]) { if (usb_pipetype(urb->pipe) != pipetypes[xfertype])
dev_err(&dev->dev, "BOGUS urb xfer, pipe %x != type %x\n", dev_WARN(&dev->dev, "BOGUS urb xfer, pipe %x != type %x\n",
usb_pipetype(urb->pipe), pipetypes[xfertype]); usb_pipetype(urb->pipe), pipetypes[xfertype]);
return -EPIPE; /* The most suitable error code :-) */
}
/* enforce simple/standard policy */ /* Check against a simple/standard policy */
allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT | URB_DIR_MASK | allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT | URB_DIR_MASK |
URB_FREE_BUFFER); URB_FREE_BUFFER);
switch (xfertype) { switch (xfertype) {
@ -435,14 +432,12 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
allowed |= URB_ISO_ASAP; allowed |= URB_ISO_ASAP;
break; break;
} }
urb->transfer_flags &= allowed; allowed &= urb->transfer_flags;
/* fail if submitter gave bogus flags */ /* warn if submitter gave bogus flags */
if (urb->transfer_flags != orig_flags) { if (allowed != urb->transfer_flags)
dev_err(&dev->dev, "BOGUS urb flags, %x --> %x\n", dev_WARN(&dev->dev, "BOGUS urb flags, %x --> %x\n",
orig_flags, urb->transfer_flags); urb->transfer_flags, allowed);
return -EINVAL;
}
} }
#endif #endif
/* /*

View File

@ -274,7 +274,7 @@ static int usb_dev_prepare(struct device *dev)
static void usb_dev_complete(struct device *dev) static void usb_dev_complete(struct device *dev)
{ {
/* Currently used only for rebinding interfaces */ /* Currently used only for rebinding interfaces */
usb_resume(dev, PMSG_ON); /* FIXME: change to PMSG_COMPLETE */ usb_resume_complete(dev);
} }
static int usb_dev_suspend(struct device *dev) static int usb_dev_suspend(struct device *dev)

View File

@ -56,6 +56,7 @@ extern void usb_major_cleanup(void);
extern int usb_suspend(struct device *dev, pm_message_t msg); extern int usb_suspend(struct device *dev, pm_message_t msg);
extern int usb_resume(struct device *dev, pm_message_t msg); extern int usb_resume(struct device *dev, pm_message_t msg);
extern int usb_resume_complete(struct device *dev);
extern int usb_port_suspend(struct usb_device *dev, pm_message_t msg); extern int usb_port_suspend(struct usb_device *dev, pm_message_t msg);
extern int usb_port_resume(struct usb_device *dev, pm_message_t msg); extern int usb_port_resume(struct usb_device *dev, pm_message_t msg);

View File

@ -323,7 +323,9 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct ehci_hcd *ehci = hcd_to_ehci(hcd);
int retval; int retval;
struct fsl_usb2_platform_data *pdata; struct fsl_usb2_platform_data *pdata;
struct device *dev;
dev = hcd->self.controller;
pdata = hcd->self.controller->platform_data; pdata = hcd->self.controller->platform_data;
ehci->big_endian_desc = pdata->big_endian_desc; ehci->big_endian_desc = pdata->big_endian_desc;
ehci->big_endian_mmio = pdata->big_endian_mmio; ehci->big_endian_mmio = pdata->big_endian_mmio;
@ -353,6 +355,16 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
ehci_reset(ehci); ehci_reset(ehci);
if (of_device_is_compatible(dev->parent->of_node,
"fsl,mpc5121-usb2-dr")) {
/*
* set SBUSCFG:AHBBRST so that control msgs don't
* fail when doing heavy PATA writes.
*/
ehci_writel(ehci, SBUSCFG_INCR8,
hcd->regs + FSL_SOC_USB_SBUSCFG);
}
retval = ehci_fsl_reinit(ehci); retval = ehci_fsl_reinit(ehci);
return retval; return retval;
} }
@ -476,6 +488,8 @@ static int ehci_fsl_mpc512x_drv_resume(struct device *dev)
ehci_writel(ehci, ISIPHYCTRL_PXE | ISIPHYCTRL_PHYE, ehci_writel(ehci, ISIPHYCTRL_PXE | ISIPHYCTRL_PHYE,
hcd->regs + FSL_SOC_USB_ISIPHYCTRL); hcd->regs + FSL_SOC_USB_ISIPHYCTRL);
ehci_writel(ehci, SBUSCFG_INCR8, hcd->regs + FSL_SOC_USB_SBUSCFG);
/* restore EHCI registers */ /* restore EHCI registers */
ehci_writel(ehci, pdata->pm_command, &ehci->regs->command); ehci_writel(ehci, pdata->pm_command, &ehci->regs->command);
ehci_writel(ehci, pdata->pm_intr_enable, &ehci->regs->intr_enable); ehci_writel(ehci, pdata->pm_intr_enable, &ehci->regs->intr_enable);

View File

@ -19,6 +19,8 @@
#define _EHCI_FSL_H #define _EHCI_FSL_H
/* offsets for the non-ehci registers in the FSL SOC USB controller */ /* offsets for the non-ehci registers in the FSL SOC USB controller */
#define FSL_SOC_USB_SBUSCFG 0x90
#define SBUSCFG_INCR8 0x02 /* INCR8, specified */
#define FSL_SOC_USB_ULPIVP 0x170 #define FSL_SOC_USB_ULPIVP 0x170
#define FSL_SOC_USB_PORTSC1 0x184 #define FSL_SOC_USB_PORTSC1 0x184
#define PORT_PTS_MSK (3<<30) #define PORT_PTS_MSK (3<<30)

View File

@ -1376,6 +1376,11 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ehci_mv_driver #define PLATFORM_DRIVER ehci_mv_driver
#endif #endif
#ifdef CONFIG_MACH_LOONGSON1
#include "ehci-ls1x.c"
#define PLATFORM_DRIVER ehci_ls1x_driver
#endif
#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \ #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
!defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \ !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \
!defined(XILINX_OF_PLATFORM_DRIVER) !defined(XILINX_OF_PLATFORM_DRIVER)

View File

@ -107,7 +107,7 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci)
ehci->owned_ports = 0; ehci->owned_ports = 0;
} }
static int ehci_port_change(struct ehci_hcd *ehci) static int __maybe_unused ehci_port_change(struct ehci_hcd *ehci)
{ {
int i = HCS_N_PORTS(ehci->hcs_params); int i = HCS_N_PORTS(ehci->hcs_params);
@ -1076,7 +1076,8 @@ error_exit:
return retval; return retval;
} }
static void ehci_relinquish_port(struct usb_hcd *hcd, int portnum) static void __maybe_unused ehci_relinquish_port(struct usb_hcd *hcd,
int portnum)
{ {
struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct ehci_hcd *ehci = hcd_to_ehci(hcd);
@ -1085,7 +1086,8 @@ static void ehci_relinquish_port(struct usb_hcd *hcd, int portnum)
set_owner(ehci, --portnum, PORT_OWNER); set_owner(ehci, --portnum, PORT_OWNER);
} }
static int ehci_port_handed_over(struct usb_hcd *hcd, int portnum) static int __maybe_unused ehci_port_handed_over(struct usb_hcd *hcd,
int portnum)
{ {
struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct ehci_hcd *ehci = hcd_to_ehci(hcd);
u32 __iomem *reg; u32 __iomem *reg;

View File

@ -0,0 +1,159 @@
/*
* Bus Glue for Loongson LS1X built-in EHCI controller.
*
* Copyright (c) 2012 Zhang, Keguang <keguang.zhang@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*/
#include <linux/platform_device.h>
static int ehci_ls1x_reset(struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
int ret;
ehci->caps = hcd->regs;
ret = ehci_setup(hcd);
if (ret)
return ret;
ehci_port_power(ehci, 0);
return 0;
}
static const struct hc_driver ehci_ls1x_hc_driver = {
.description = hcd_name,
.product_desc = "LOONGSON1 EHCI",
.hcd_priv_size = sizeof(struct ehci_hcd),
/*
* generic hardware linkage
*/
.irq = ehci_irq,
.flags = HCD_MEMORY | HCD_USB2,
/*
* basic lifecycle operations
*/
.reset = ehci_ls1x_reset,
.start = ehci_run,
.stop = ehci_stop,
.shutdown = ehci_shutdown,
/*
* managing i/o requests and associated device resources
*/
.urb_enqueue = ehci_urb_enqueue,
.urb_dequeue = ehci_urb_dequeue,
.endpoint_disable = ehci_endpoint_disable,
.endpoint_reset = ehci_endpoint_reset,
/*
* scheduling support
*/
.get_frame_number = ehci_get_frame,
/*
* root hub support
*/
.hub_status_data = ehci_hub_status_data,
.hub_control = ehci_hub_control,
.relinquish_port = ehci_relinquish_port,
.port_handed_over = ehci_port_handed_over,
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
};
static int ehci_hcd_ls1x_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd;
struct resource *res;
int irq;
int ret;
pr_debug("initializing loongson1 ehci USB Controller\n");
if (usb_disabled())
return -ENODEV;
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
dev_err(&pdev->dev,
"Found HC with no IRQ. Check %s setup!\n",
dev_name(&pdev->dev));
return -ENODEV;
}
irq = res->start;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev,
"Found HC with no register addr. Check %s setup!\n",
dev_name(&pdev->dev));
return -ENODEV;
}
hcd = usb_create_hcd(&ehci_ls1x_hc_driver, &pdev->dev,
dev_name(&pdev->dev));
if (!hcd)
return -ENOMEM;
hcd->rsrc_start = res->start;
hcd->rsrc_len = resource_size(res);
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
dev_dbg(&pdev->dev, "controller already in use\n");
ret = -EBUSY;
goto err_put_hcd;
}
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
if (hcd->regs == NULL) {
dev_dbg(&pdev->dev, "error mapping memory\n");
ret = -EFAULT;
goto err_release_region;
}
ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
if (ret)
goto err_iounmap;
return ret;
err_iounmap:
iounmap(hcd->regs);
err_release_region:
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
err_put_hcd:
usb_put_hcd(hcd);
return ret;
}
static int ehci_hcd_ls1x_remove(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
usb_remove_hcd(hcd);
iounmap(hcd->regs);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
return 0;
}
static struct platform_driver ehci_ls1x_driver = {
.probe = ehci_hcd_ls1x_probe,
.remove = ehci_hcd_ls1x_remove,
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "ls1x-ehci",
.owner = THIS_MODULE,
},
};
MODULE_ALIAS(PLATFORM_MODULE_PREFIX "ls1x-ehci");

View File

@ -239,7 +239,7 @@ static int debug_status_show(struct seq_file *s, void *v)
"ETDs allocated: %d/%d (max=%d)\n" "ETDs allocated: %d/%d (max=%d)\n"
"ETDs in use sw: %d\n" "ETDs in use sw: %d\n"
"ETDs in use hw: %d\n" "ETDs in use hw: %d\n"
"DMEM alocated: %d/%d (max=%d)\n" "DMEM allocated: %d/%d (max=%d)\n"
"DMEM blocks: %d\n" "DMEM blocks: %d\n"
"Queued waiting for ETD: %d\n" "Queued waiting for ETD: %d\n"
"Queued waiting for DMEM: %d\n", "Queued waiting for DMEM: %d\n",

View File

@ -565,6 +565,9 @@ static int uhci_start(struct usb_hcd *hcd)
struct dentry __maybe_unused *dentry; struct dentry __maybe_unused *dentry;
hcd->uses_new_polling = 1; hcd->uses_new_polling = 1;
/* Accept arbitrarily long scatter-gather lists */
if (!(hcd->driver->flags & HCD_LOCAL_MEM))
hcd->self.sg_tablesize = ~0;
spin_lock_init(&uhci->lock); spin_lock_init(&uhci->lock);
setup_timer(&uhci->fsbr_timer, uhci_fsbr_timeout, setup_timer(&uhci->fsbr_timer, uhci_fsbr_timeout,

View File

@ -422,6 +422,32 @@ void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array,
xhci_writel(xhci, temp, port_array[port_id]); xhci_writel(xhci, temp, port_array[port_id]);
} }
void xhci_set_remote_wake_mask(struct xhci_hcd *xhci,
__le32 __iomem **port_array, int port_id, u16 wake_mask)
{
u32 temp;
temp = xhci_readl(xhci, port_array[port_id]);
temp = xhci_port_state_to_neutral(temp);
if (wake_mask & USB_PORT_FEAT_REMOTE_WAKE_CONNECT)
temp |= PORT_WKCONN_E;
else
temp &= ~PORT_WKCONN_E;
if (wake_mask & USB_PORT_FEAT_REMOTE_WAKE_DISCONNECT)
temp |= PORT_WKDISC_E;
else
temp &= ~PORT_WKDISC_E;
if (wake_mask & USB_PORT_FEAT_REMOTE_WAKE_OVER_CURRENT)
temp |= PORT_WKOC_E;
else
temp &= ~PORT_WKOC_E;
xhci_writel(xhci, temp, port_array[port_id]);
}
/* Test and clear port RWC bit */ /* Test and clear port RWC bit */
void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array, void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,
int port_id, u32 port_bit) int port_id, u32 port_bit)
@ -448,6 +474,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
int slot_id; int slot_id;
struct xhci_bus_state *bus_state; struct xhci_bus_state *bus_state;
u16 link_state = 0; u16 link_state = 0;
u16 wake_mask = 0;
max_ports = xhci_get_ports(hcd, &port_array); max_ports = xhci_get_ports(hcd, &port_array);
bus_state = &xhci->bus_state[hcd_index(hcd)]; bus_state = &xhci->bus_state[hcd_index(hcd)];
@ -593,6 +620,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
case SetPortFeature: case SetPortFeature:
if (wValue == USB_PORT_FEAT_LINK_STATE) if (wValue == USB_PORT_FEAT_LINK_STATE)
link_state = (wIndex & 0xff00) >> 3; link_state = (wIndex & 0xff00) >> 3;
if (wValue == USB_PORT_FEAT_REMOTE_WAKE_MASK)
wake_mask = wIndex & 0xff00;
wIndex &= 0xff; wIndex &= 0xff;
if (!wIndex || wIndex > max_ports) if (!wIndex || wIndex > max_ports)
goto error; goto error;
@ -703,6 +732,14 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
temp = xhci_readl(xhci, port_array[wIndex]); temp = xhci_readl(xhci, port_array[wIndex]);
xhci_dbg(xhci, "set port reset, actual port %d status = 0x%x\n", wIndex, temp); xhci_dbg(xhci, "set port reset, actual port %d status = 0x%x\n", wIndex, temp);
break; break;
case USB_PORT_FEAT_REMOTE_WAKE_MASK:
xhci_set_remote_wake_mask(xhci, port_array,
wIndex, wake_mask);
temp = xhci_readl(xhci, port_array[wIndex]);
xhci_dbg(xhci, "set port remote wake mask, "
"actual port %d status = 0x%x\n",
wIndex, temp);
break;
case USB_PORT_FEAT_BH_PORT_RESET: case USB_PORT_FEAT_BH_PORT_RESET:
temp |= PORT_WR; temp |= PORT_WR;
xhci_writel(xhci, temp, port_array[wIndex]); xhci_writel(xhci, temp, port_array[wIndex]);
@ -883,6 +920,10 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
t2 |= PORT_LINK_STROBE | XDEV_U3; t2 |= PORT_LINK_STROBE | XDEV_U3;
set_bit(port_index, &bus_state->bus_suspended); set_bit(port_index, &bus_state->bus_suspended);
} }
/* USB core sets remote wake mask for USB 3.0 hubs,
* including the USB 3.0 roothub, but only if CONFIG_USB_SUSPEND
* is enabled, so also enable remote wake here.
*/
if (hcd->self.root_hub->do_remote_wakeup) { if (hcd->self.root_hub->do_remote_wakeup) {
if (t1 & PORT_CONNECT) { if (t1 & PORT_CONNECT) {
t2 |= PORT_WKOC_E | PORT_WKDISC_E; t2 |= PORT_WKOC_E | PORT_WKDISC_E;

View File

@ -2157,7 +2157,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
unsigned int val, val2; unsigned int val, val2;
u64 val_64; u64 val_64;
struct xhci_segment *seg; struct xhci_segment *seg;
u32 page_size; u32 page_size, temp;
int i; int i;
page_size = xhci_readl(xhci, &xhci->op_regs->page_size); page_size = xhci_readl(xhci, &xhci->op_regs->page_size);
@ -2340,6 +2340,15 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
INIT_LIST_HEAD(&xhci->lpm_failed_devs); INIT_LIST_HEAD(&xhci->lpm_failed_devs);
/* Enable USB 3.0 device notifications for function remote wake, which
* is necessary for allowing USB 3.0 devices to do remote wakeup from
* U3 (device suspend).
*/
temp = xhci_readl(xhci, &xhci->op_regs->dev_notification);
temp &= ~DEV_NOTE_MASK;
temp |= DEV_NOTE_FWAKE;
xhci_writel(xhci, temp, &xhci->op_regs->dev_notification);
return 0; return 0;
fail: fail:

View File

@ -1237,6 +1237,26 @@ static unsigned int find_faked_portnum_from_hw_portnum(struct usb_hcd *hcd,
return num_similar_speed_ports; return num_similar_speed_ports;
} }
static void handle_device_notification(struct xhci_hcd *xhci,
union xhci_trb *event)
{
u32 slot_id;
struct usb_device *udev;
slot_id = TRB_TO_SLOT_ID(event->generic.field[3]);
if (!xhci->devs[slot_id]) {
xhci_warn(xhci, "Device Notification event for "
"unused slot %u\n", slot_id);
return;
}
xhci_dbg(xhci, "Device Wake Notification event for slot ID %u\n",
slot_id);
udev = xhci->devs[slot_id]->udev;
if (udev && udev->parent)
usb_wakeup_notification(udev->parent, udev->portnum);
}
static void handle_port_status(struct xhci_hcd *xhci, static void handle_port_status(struct xhci_hcd *xhci,
union xhci_trb *event) union xhci_trb *event)
{ {
@ -1321,20 +1341,21 @@ static void handle_port_status(struct xhci_hcd *xhci,
} }
if (DEV_SUPERSPEED(temp)) { if (DEV_SUPERSPEED(temp)) {
xhci_dbg(xhci, "resume SS port %d\n", port_id); xhci_dbg(xhci, "remote wake SS port %d\n", port_id);
/* Set a flag to say the port signaled remote wakeup,
* so we can tell the difference between the end of
* device and host initiated resume.
*/
bus_state->port_remote_wakeup |= 1 << faked_port_index;
xhci_test_and_clear_bit(xhci, port_array,
faked_port_index, PORT_PLC);
xhci_set_link_state(xhci, port_array, faked_port_index, xhci_set_link_state(xhci, port_array, faked_port_index,
XDEV_U0); XDEV_U0);
slot_id = xhci_find_slot_id_by_port(hcd, xhci, /* Need to wait until the next link state change
faked_port_index + 1); * indicates the device is actually in U0.
if (!slot_id) { */
xhci_dbg(xhci, "slot_id is zero\n"); bogus_port_status = true;
goto cleanup; goto cleanup;
}
xhci_ring_device(xhci, slot_id);
xhci_dbg(xhci, "resume SS port %d finished\n", port_id);
/* Clear PORT_PLC */
xhci_test_and_clear_bit(xhci, port_array,
faked_port_index, PORT_PLC);
} else { } else {
xhci_dbg(xhci, "resume HS port %d\n", port_id); xhci_dbg(xhci, "resume HS port %d\n", port_id);
bus_state->resume_done[faked_port_index] = jiffies + bus_state->resume_done[faked_port_index] = jiffies +
@ -1345,6 +1366,32 @@ static void handle_port_status(struct xhci_hcd *xhci,
} }
} }
if ((temp & PORT_PLC) && (temp & PORT_PLS_MASK) == XDEV_U0 &&
DEV_SUPERSPEED(temp)) {
xhci_dbg(xhci, "resume SS port %d finished\n", port_id);
/* We've just brought the device into U0 through either the
* Resume state after a device remote wakeup, or through the
* U3Exit state after a host-initiated resume. If it's a device
* initiated remote wake, don't pass up the link state change,
* so the roothub behavior is consistent with external
* USB 3.0 hub behavior.
*/
slot_id = xhci_find_slot_id_by_port(hcd, xhci,
faked_port_index + 1);
if (slot_id && xhci->devs[slot_id])
xhci_ring_device(xhci, slot_id);
if (bus_state->port_remote_wakeup && (1 << faked_port_index)) {
bus_state->port_remote_wakeup &=
~(1 << faked_port_index);
xhci_test_and_clear_bit(xhci, port_array,
faked_port_index, PORT_PLC);
usb_wakeup_notification(hcd->self.root_hub,
faked_port_index + 1);
bogus_port_status = true;
goto cleanup;
}
}
if (hcd->speed != HCD_USB3) if (hcd->speed != HCD_USB3)
xhci_test_and_clear_bit(xhci, port_array, faked_port_index, xhci_test_and_clear_bit(xhci, port_array, faked_port_index,
PORT_PLC); PORT_PLC);
@ -2277,6 +2324,9 @@ static int xhci_handle_event(struct xhci_hcd *xhci)
else else
update_ptrs = 0; update_ptrs = 0;
break; break;
case TRB_TYPE(TRB_DEV_NOTE):
handle_device_notification(xhci, event);
break;
default: default:
if ((le32_to_cpu(event->event_cmd.flags) & TRB_TYPE_BITMASK) >= if ((le32_to_cpu(event->event_cmd.flags) & TRB_TYPE_BITMASK) >=
TRB_TYPE(48)) TRB_TYPE(48))

View File

@ -1344,6 +1344,7 @@ struct xhci_bus_state {
/* ports suspend status arrays - max 31 ports for USB2, 15 for USB3 */ /* ports suspend status arrays - max 31 ports for USB2, 15 for USB3 */
u32 port_c_suspend; u32 port_c_suspend;
u32 suspended_ports; u32 suspended_ports;
u32 port_remote_wakeup;
unsigned long resume_done[USB_MAXCHILDREN]; unsigned long resume_done[USB_MAXCHILDREN];
}; };

View File

@ -286,7 +286,7 @@ static int cp210x_get_config(struct usb_serial_port *port, u8 request,
if (result != size) { if (result != size) {
dbg("%s - Unable to send config request, " dbg("%s - Unable to send config request, "
"request=0x%x size=%d result=%d\n", "request=0x%x size=%d result=%d",
__func__, request, size, result); __func__, request, size, result);
if (result > 0) if (result > 0)
result = -EPROTO; result = -EPROTO;
@ -340,7 +340,7 @@ static int cp210x_set_config(struct usb_serial_port *port, u8 request,
if ((size > 2 && result != size) || result < 0) { if ((size > 2 && result != size) || result < 0) {
dbg("%s - Unable to send request, " dbg("%s - Unable to send request, "
"request=0x%x size=%d result=%d\n", "request=0x%x size=%d result=%d",
__func__, request, size, result); __func__, request, size, result);
if (result > 0) if (result > 0)
result = -EPROTO; result = -EPROTO;
@ -683,13 +683,13 @@ static void cp210x_set_termios(struct tty_struct *tty,
default: default:
dbg("cp210x driver does not " dbg("cp210x driver does not "
"support the number of bits requested," "support the number of bits requested,"
" using 8 bit mode\n"); " using 8 bit mode");
bits |= BITS_DATA_8; bits |= BITS_DATA_8;
break; break;
} }
if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2)) if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2))
dbg("Number of data bits requested " dbg("Number of data bits requested "
"not supported by device\n"); "not supported by device");
} }
if ((cflag & (PARENB|PARODD|CMSPAR)) != if ((cflag & (PARENB|PARODD|CMSPAR)) !=
@ -716,8 +716,7 @@ static void cp210x_set_termios(struct tty_struct *tty,
} }
} }
if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2)) if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2))
dbg("Parity mode not supported " dbg("Parity mode not supported by device");
"by device\n");
} }
if ((cflag & CSTOPB) != (old_cflag & CSTOPB)) { if ((cflag & CSTOPB) != (old_cflag & CSTOPB)) {
@ -732,7 +731,7 @@ static void cp210x_set_termios(struct tty_struct *tty,
} }
if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2)) if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2))
dbg("Number of stop bits requested " dbg("Number of stop bits requested "
"not supported by device\n"); "not supported by device");
} }
if ((cflag & CRTSCTS) != (old_cflag & CRTSCTS)) { if ((cflag & CRTSCTS) != (old_cflag & CRTSCTS)) {

View File

@ -800,7 +800,7 @@ send:
cypress_write_int_callback, port, priv->write_urb_interval); cypress_write_int_callback, port, priv->write_urb_interval);
result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC); result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC);
if (result) { if (result) {
dev_err(&port->dev, dev_err_console(port,
"%s - failed submitting write urb, error %d\n", "%s - failed submitting write urb, error %d\n",
__func__, result); __func__, result);
priv->write_urb_in_use = 0; priv->write_urb_in_use = 0;

View File

@ -995,7 +995,7 @@ static int digi_write(struct tty_struct *tty, struct usb_serial_port *port,
/* return length of new data written, or error */ /* return length of new data written, or error */
spin_unlock_irqrestore(&priv->dp_port_lock, flags); spin_unlock_irqrestore(&priv->dp_port_lock, flags);
if (ret < 0) if (ret < 0)
dev_err(&port->dev, dev_err_console(port,
"%s: usb_submit_urb failed, ret=%d, port=%d\n", "%s: usb_submit_urb failed, ret=%d, port=%d\n",
__func__, ret, priv->dp_port_num); __func__, ret, priv->dp_port_num);
dbg("digi_write: returning %d", ret); dbg("digi_write: returning %d", ret);
@ -1065,7 +1065,7 @@ static void digi_write_bulk_callback(struct urb *urb)
spin_unlock(&priv->dp_port_lock); spin_unlock(&priv->dp_port_lock);
if (ret && ret != -EPERM) if (ret && ret != -EPERM)
dev_err(&port->dev, dev_err_console(port,
"%s: usb_submit_urb failed, ret=%d, port=%d\n", "%s: usb_submit_urb failed, ret=%d, port=%d\n",
__func__, ret, priv->dp_port_num); __func__, ret, priv->dp_port_num);
} }

View File

@ -217,7 +217,7 @@ retry:
clear_bit(i, &port->write_urbs_free); clear_bit(i, &port->write_urbs_free);
result = usb_submit_urb(urb, GFP_ATOMIC); result = usb_submit_urb(urb, GFP_ATOMIC);
if (result) { if (result) {
dev_err(&port->dev, "%s - error submitting urb: %d\n", dev_err_console(port, "%s - error submitting urb: %d\n",
__func__, result); __func__, result);
set_bit(i, &port->write_urbs_free); set_bit(i, &port->write_urbs_free);
spin_lock_irqsave(&port->lock, flags); spin_lock_irqsave(&port->lock, flags);

View File

@ -1286,7 +1286,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial,
count = fifo->count; count = fifo->count;
buffer = kmalloc(count+2, GFP_ATOMIC); buffer = kmalloc(count+2, GFP_ATOMIC);
if (buffer == NULL) { if (buffer == NULL) {
dev_err(&edge_port->port->dev, dev_err_console(edge_port->port,
"%s - no more kernel memory...\n", __func__); "%s - no more kernel memory...\n", __func__);
edge_port->write_in_progress = false; edge_port->write_in_progress = false;
goto exit_send; goto exit_send;
@ -1331,7 +1331,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial,
status = usb_submit_urb(urb, GFP_ATOMIC); status = usb_submit_urb(urb, GFP_ATOMIC);
if (status) { if (status) {
/* something went wrong */ /* something went wrong */
dev_err(&edge_port->port->dev, dev_err_console(edge_port->port,
"%s - usb_submit_urb(write bulk) failed, status = %d, data lost\n", "%s - usb_submit_urb(write bulk) failed, status = %d, data lost\n",
__func__, status); __func__, status);
edge_port->write_in_progress = false; edge_port->write_in_progress = false;

View File

@ -1817,7 +1817,7 @@ static void edge_bulk_out_callback(struct urb *urb)
__func__, status); __func__, status);
return; return;
default: default:
dev_err(&urb->dev->dev, "%s - nonzero write bulk status " dev_err_console(port, "%s - nonzero write bulk status "
"received: %d\n", __func__, status); "received: %d\n", __func__, status);
} }
@ -2111,7 +2111,7 @@ static void edge_send(struct tty_struct *tty)
/* send the data out the bulk port */ /* send the data out the bulk port */
result = usb_submit_urb(port->write_urb, GFP_ATOMIC); result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (result) { if (result) {
dev_err(&port->dev, dev_err_console(port,
"%s - failed submitting write urb, error %d\n", "%s - failed submitting write urb, error %d\n",
__func__, result); __func__, result);
edge_port->ep_write_urb_in_use = 0; edge_port->ep_write_urb_in_use = 0;

View File

@ -1294,7 +1294,7 @@ static int mos7720_write(struct tty_struct *tty, struct usb_serial_port *port,
urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE, urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,
GFP_KERNEL); GFP_KERNEL);
if (urb->transfer_buffer == NULL) { if (urb->transfer_buffer == NULL) {
dev_err(&port->dev, "%s no more kernel memory...\n", dev_err_console(port, "%s no more kernel memory...\n",
__func__); __func__);
goto exit; goto exit;
} }
@ -1315,7 +1315,7 @@ static int mos7720_write(struct tty_struct *tty, struct usb_serial_port *port,
/* send it down the pipe */ /* send it down the pipe */
status = usb_submit_urb(urb, GFP_ATOMIC); status = usb_submit_urb(urb, GFP_ATOMIC);
if (status) { if (status) {
dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed " dev_err_console(port, "%s - usb_submit_urb(write bulk) failed "
"with status = %d\n", __func__, status); "with status = %d\n", __func__, status);
bytes_sent = status; bytes_sent = status;
goto exit; goto exit;

View File

@ -1509,7 +1509,7 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port,
kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL); kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
if (urb->transfer_buffer == NULL) { if (urb->transfer_buffer == NULL) {
dev_err(&port->dev, "%s no more kernel memory...\n", dev_err_console(port, "%s no more kernel memory...\n",
__func__); __func__);
goto exit; goto exit;
} }
@ -1535,7 +1535,7 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port,
if (status) { if (status) {
mos7840_port->busy[i] = 0; mos7840_port->busy[i] = 0;
dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed " dev_err_console(port, "%s - usb_submit_urb(write bulk) failed "
"with status = %d\n", __func__, status); "with status = %d\n", __func__, status);
bytes_sent = status; bytes_sent = status;
goto exit; goto exit;

View File

@ -254,7 +254,7 @@ static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port,
result = usb_submit_urb(wport->write_urb, GFP_ATOMIC); result = usb_submit_urb(wport->write_urb, GFP_ATOMIC);
if (result) { if (result) {
set_bit(0, &wport->write_urbs_free); set_bit(0, &wport->write_urbs_free);
dev_err(&port->dev, dev_err_console(port,
"%s - failed submitting write urb, error %d\n", "%s - failed submitting write urb, error %d\n",
__func__, result); __func__, result);
} else } else

View File

@ -302,7 +302,7 @@ static void send_data(struct work_struct *work)
if (count != 0) { if (count != 0) {
allow = kmalloc(1, GFP_KERNEL); allow = kmalloc(1, GFP_KERNEL);
if (!allow) { if (!allow) {
dev_err(&port->dev, "%s(): kmalloc failed\n", dev_err_console(port, "%s(): kmalloc failed\n",
__func__); __func__);
return; return;
} }
@ -334,7 +334,7 @@ static void send_data(struct work_struct *work)
port->write_urb->transfer_buffer_length = count; port->write_urb->transfer_buffer_length = count;
result = usb_submit_urb(port->write_urb, GFP_NOIO); result = usb_submit_urb(port->write_urb, GFP_NOIO);
if (result != 0) { if (result != 0) {
dev_err(&port->dev, "%s(): usb_submit_urb() failed" dev_err_console(port, "%s(): usb_submit_urb() failed"
" with error %d\n", __func__, result); " with error %d\n", __func__, result);
priv->flags.write_urb_in_use = 0; priv->flags.write_urb_in_use = 0;
} }
@ -938,7 +938,7 @@ static void oti6858_write_bulk_callback(struct urb *urb)
port->write_urb->transfer_buffer_length = 1; port->write_urb->transfer_buffer_length = 1;
result = usb_submit_urb(port->write_urb, GFP_ATOMIC); result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (result) { if (result) {
dev_err(&port->dev, "%s(): usb_submit_urb() failed," dev_err_console(port, "%s(): usb_submit_urb() failed,"
" error %d\n", __func__, result); " error %d\n", __func__, result);
} else { } else {
return; return;

View File

@ -1250,7 +1250,6 @@ static void ti_bulk_out_callback(struct urb *urb)
{ {
struct ti_port *tport = urb->context; struct ti_port *tport = urb->context;
struct usb_serial_port *port = tport->tp_port; struct usb_serial_port *port = tport->tp_port;
struct device *dev = &urb->dev->dev;
int status = urb->status; int status = urb->status;
dbg("%s - port %d", __func__, port->number); dbg("%s - port %d", __func__, port->number);
@ -1268,7 +1267,7 @@ static void ti_bulk_out_callback(struct urb *urb)
wake_up_interruptible(&tport->tp_write_wait); wake_up_interruptible(&tport->tp_write_wait);
return; return;
default: default:
dev_err(dev, "%s - nonzero urb status, %d\n", dev_err_console(port, "%s - nonzero urb status, %d\n",
__func__, status); __func__, status);
tport->tp_tdev->td_urb_error = 1; tport->tp_tdev->td_urb_error = 1;
wake_up_interruptible(&tport->tp_write_wait); wake_up_interruptible(&tport->tp_write_wait);
@ -1337,7 +1336,7 @@ static void ti_send(struct ti_port *tport)
result = usb_submit_urb(port->write_urb, GFP_ATOMIC); result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (result) { if (result) {
dev_err(&port->dev, "%s - submit write urb failed, %d\n", dev_err_console(port, "%s - submit write urb failed, %d\n",
__func__, result); __func__, result);
tport->tp_write_urb_in_use = 0; tport->tp_write_urb_in_use = 0;
/* TODO: reschedule ti_send */ /* TODO: reschedule ti_send */

View File

@ -740,7 +740,7 @@ static int whiteheat_write(struct tty_struct *tty,
urb->transfer_buffer_length = bytes; urb->transfer_buffer_length = bytes;
result = usb_submit_urb(urb, GFP_ATOMIC); result = usb_submit_urb(urb, GFP_ATOMIC);
if (result) { if (result) {
dev_err(&port->dev, dev_err_console(port,
"%s - failed submitting write urb, error %d\n", "%s - failed submitting write urb, error %d\n",
__func__, result); __func__, result);
sent = result; sent = result;

View File

@ -1276,6 +1276,7 @@ static struct usb_driver alauda_driver = {
.post_reset = usb_stor_post_reset, .post_reset = usb_stor_post_reset,
.id_table = alauda_usb_ids, .id_table = alauda_usb_ids,
.soft_unbind = 1, .soft_unbind = 1,
.no_dynamic_id = 1,
}; };
module_usb_driver(alauda_driver); module_usb_driver(alauda_driver);

View File

@ -272,6 +272,7 @@ static struct usb_driver cypress_driver = {
.post_reset = usb_stor_post_reset, .post_reset = usb_stor_post_reset,
.id_table = cypress_usb_ids, .id_table = cypress_usb_ids,
.soft_unbind = 1, .soft_unbind = 1,
.no_dynamic_id = 1,
}; };
module_usb_driver(cypress_driver); module_usb_driver(cypress_driver);

View File

@ -751,6 +751,7 @@ static struct usb_driver datafab_driver = {
.post_reset = usb_stor_post_reset, .post_reset = usb_stor_post_reset,
.id_table = datafab_usb_ids, .id_table = datafab_usb_ids,
.soft_unbind = 1, .soft_unbind = 1,
.no_dynamic_id = 1,
}; };
module_usb_driver(datafab_driver); module_usb_driver(datafab_driver);

View File

@ -2407,6 +2407,7 @@ static struct usb_driver ene_ub6250_driver = {
.post_reset = usb_stor_post_reset, .post_reset = usb_stor_post_reset,
.id_table = ene_ub6250_usb_ids, .id_table = ene_ub6250_usb_ids,
.soft_unbind = 1, .soft_unbind = 1,
.no_dynamic_id = 1,
}; };
module_usb_driver(ene_ub6250_driver); module_usb_driver(ene_ub6250_driver);

View File

@ -553,6 +553,7 @@ static struct usb_driver freecom_driver = {
.post_reset = usb_stor_post_reset, .post_reset = usb_stor_post_reset,
.id_table = freecom_usb_ids, .id_table = freecom_usb_ids,
.soft_unbind = 1, .soft_unbind = 1,
.no_dynamic_id = 1,
}; };
module_usb_driver(freecom_driver); module_usb_driver(freecom_driver);

View File

@ -1566,6 +1566,7 @@ static struct usb_driver isd200_driver = {
.post_reset = usb_stor_post_reset, .post_reset = usb_stor_post_reset,
.id_table = isd200_usb_ids, .id_table = isd200_usb_ids,
.soft_unbind = 1, .soft_unbind = 1,
.no_dynamic_id = 1,
}; };
module_usb_driver(isd200_driver); module_usb_driver(isd200_driver);

View File

@ -677,6 +677,7 @@ static struct usb_driver jumpshot_driver = {
.post_reset = usb_stor_post_reset, .post_reset = usb_stor_post_reset,
.id_table = jumpshot_usb_ids, .id_table = jumpshot_usb_ids,
.soft_unbind = 1, .soft_unbind = 1,
.no_dynamic_id = 1,
}; };
module_usb_driver(jumpshot_driver); module_usb_driver(jumpshot_driver);

View File

@ -230,6 +230,7 @@ static struct usb_driver karma_driver = {
.post_reset = usb_stor_post_reset, .post_reset = usb_stor_post_reset,
.id_table = karma_usb_ids, .id_table = karma_usb_ids,
.soft_unbind = 1, .soft_unbind = 1,
.no_dynamic_id = 1,
}; };
module_usb_driver(karma_driver); module_usb_driver(karma_driver);

View File

@ -312,6 +312,7 @@ static struct usb_driver onetouch_driver = {
.post_reset = usb_stor_post_reset, .post_reset = usb_stor_post_reset,
.id_table = onetouch_usb_ids, .id_table = onetouch_usb_ids,
.soft_unbind = 1, .soft_unbind = 1,
.no_dynamic_id = 1,
}; };
module_usb_driver(onetouch_driver); module_usb_driver(onetouch_driver);

View File

@ -1100,6 +1100,7 @@ static struct usb_driver realtek_cr_driver = {
.id_table = realtek_cr_ids, .id_table = realtek_cr_ids,
.soft_unbind = 1, .soft_unbind = 1,
.supports_autosuspend = 1, .supports_autosuspend = 1,
.no_dynamic_id = 1,
}; };
module_usb_driver(realtek_cr_driver); module_usb_driver(realtek_cr_driver);

View File

@ -78,8 +78,6 @@ static const char* host_info(struct Scsi_Host *host)
static int slave_alloc (struct scsi_device *sdev) static int slave_alloc (struct scsi_device *sdev)
{ {
struct us_data *us = host_to_us(sdev->host);
/* /*
* Set the INQUIRY transfer length to 36. We don't use any of * Set the INQUIRY transfer length to 36. We don't use any of
* the extra data and many devices choke if asked for more or * the extra data and many devices choke if asked for more or
@ -104,18 +102,6 @@ static int slave_alloc (struct scsi_device *sdev)
*/ */
blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1)); blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1));
/*
* The UFI spec treates the Peripheral Qualifier bits in an
* INQUIRY result as reserved and requires devices to set them
* to 0. However the SCSI spec requires these bits to be set
* to 3 to indicate when a LUN is not present.
*
* Let the scanning code know if this target merely sets
* Peripheral Device Type to 0x1f to indicate no LUN.
*/
if (us->subclass == USB_SC_UFI)
sdev->sdev_target->pdt_1f_for_no_lun = 1;
return 0; return 0;
} }
@ -197,6 +183,9 @@ static int slave_configure(struct scsi_device *sdev)
* page x08, so we will skip it. */ * page x08, so we will skip it. */
sdev->skip_ms_page_8 = 1; sdev->skip_ms_page_8 = 1;
/* Some devices don't handle VPD pages correctly */
sdev->skip_vpd_pages = 1;
/* Some disks return the total number of blocks in response /* Some disks return the total number of blocks in response
* to READ CAPACITY rather than the highest block number. * to READ CAPACITY rather than the highest block number.
* If this device makes that mistake, tell the sd driver. */ * If this device makes that mistake, tell the sd driver. */
@ -217,16 +206,6 @@ static int slave_configure(struct scsi_device *sdev)
if (sdev->scsi_level > SCSI_SPC_2) if (sdev->scsi_level > SCSI_SPC_2)
us->fflags |= US_FL_SANE_SENSE; us->fflags |= US_FL_SANE_SENSE;
/* Some devices report a SCSI revision level above 2 but are
* unable to handle the REPORT LUNS command (for which
* support is mandatory at level 3). Since we already have
* a Get-Max-LUN request, we won't lose much by setting the
* revision level down to 2. The only devices that would be
* affected are those with sparse LUNs. */
if (sdev->scsi_level > SCSI_2)
sdev->sdev_target->scsi_level =
sdev->scsi_level = SCSI_2;
/* USB-IDE bridges tend to report SK = 0x04 (Non-recoverable /* USB-IDE bridges tend to report SK = 0x04 (Non-recoverable
* Hardware Error) when any low-level error occurs, * Hardware Error) when any low-level error occurs,
* recoverable or not. Setting this flag tells the SCSI * recoverable or not. Setting this flag tells the SCSI
@ -283,6 +262,33 @@ static int slave_configure(struct scsi_device *sdev)
return 0; return 0;
} }
static int target_alloc(struct scsi_target *starget)
{
struct us_data *us = host_to_us(dev_to_shost(starget->dev.parent));
/*
* Some USB drives don't support REPORT LUNS, even though they
* report a SCSI revision level above 2. Tell the SCSI layer
* not to issue that command; it will perform a normal sequential
* scan instead.
*/
starget->no_report_luns = 1;
/*
* The UFI spec treats the Peripheral Qualifier bits in an
* INQUIRY result as reserved and requires devices to set them
* to 0. However the SCSI spec requires these bits to be set
* to 3 to indicate when a LUN is not present.
*
* Let the scanning code know if this target merely sets
* Peripheral Device Type to 0x1f to indicate no LUN.
*/
if (us->subclass == USB_SC_UFI)
starget->pdt_1f_for_no_lun = 1;
return 0;
}
/* queue a command */ /* queue a command */
/* This is always called with scsi_lock(host) held */ /* This is always called with scsi_lock(host) held */
static int queuecommand_lck(struct scsi_cmnd *srb, static int queuecommand_lck(struct scsi_cmnd *srb,
@ -546,6 +552,7 @@ struct scsi_host_template usb_stor_host_template = {
.slave_alloc = slave_alloc, .slave_alloc = slave_alloc,
.slave_configure = slave_configure, .slave_configure = slave_configure,
.target_alloc = target_alloc,
/* lots of sg segments can be handled */ /* lots of sg segments can be handled */
.sg_tablesize = SCSI_MAX_SG_CHAIN_SEGMENTS, .sg_tablesize = SCSI_MAX_SG_CHAIN_SEGMENTS,

View File

@ -1787,6 +1787,7 @@ static struct usb_driver sddr09_driver = {
.post_reset = usb_stor_post_reset, .post_reset = usb_stor_post_reset,
.id_table = sddr09_usb_ids, .id_table = sddr09_usb_ids,
.soft_unbind = 1, .soft_unbind = 1,
.no_dynamic_id = 1,
}; };
module_usb_driver(sddr09_driver); module_usb_driver(sddr09_driver);

View File

@ -1006,6 +1006,7 @@ static struct usb_driver sddr55_driver = {
.post_reset = usb_stor_post_reset, .post_reset = usb_stor_post_reset,
.id_table = sddr55_usb_ids, .id_table = sddr55_usb_ids,
.soft_unbind = 1, .soft_unbind = 1,
.no_dynamic_id = 1,
}; };
module_usb_driver(sddr55_driver); module_usb_driver(sddr55_driver);

View File

@ -1863,6 +1863,7 @@ static struct usb_driver usbat_driver = {
.post_reset = usb_stor_post_reset, .post_reset = usb_stor_post_reset,
.id_table = usbat_usb_ids, .id_table = usbat_usb_ids,
.soft_unbind = 1, .soft_unbind = 1,
.no_dynamic_id = 1,
}; };
module_usb_driver(usbat_driver); module_usb_driver(usbat_driver);

View File

@ -13,7 +13,9 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/usb/hcd.h>
#include <linux/usb/storage.h> #include <linux/usb/storage.h>
#include <linux/usb/uas.h>
#include <scsi/scsi.h> #include <scsi/scsi.h>
#include <scsi/scsi_dbg.h> #include <scsi/scsi_dbg.h>
@ -22,49 +24,6 @@
#include <scsi/scsi_host.h> #include <scsi/scsi_host.h>
#include <scsi/scsi_tcq.h> #include <scsi/scsi_tcq.h>
/* Common header for all IUs */
struct iu {
__u8 iu_id;
__u8 rsvd1;
__be16 tag;
};
enum {
IU_ID_COMMAND = 0x01,
IU_ID_STATUS = 0x03,
IU_ID_RESPONSE = 0x04,
IU_ID_TASK_MGMT = 0x05,
IU_ID_READ_READY = 0x06,
IU_ID_WRITE_READY = 0x07,
};
struct command_iu {
__u8 iu_id;
__u8 rsvd1;
__be16 tag;
__u8 prio_attr;
__u8 rsvd5;
__u8 len;
__u8 rsvd7;
struct scsi_lun lun;
__u8 cdb[16]; /* XXX: Overflow-checking tools may misunderstand */
};
/*
* Also used for the Read Ready and Write Ready IUs since they have the
* same first four bytes
*/
struct sense_iu {
__u8 iu_id;
__u8 rsvd1;
__be16 tag;
__be16 status_qual;
__u8 status;
__u8 rsvd7[7];
__be16 len;
__u8 sense[SCSI_SENSE_BUFFERSIZE];
};
/* /*
* The r00-r01c specs define this version of the SENSE IU data structure. * The r00-r01c specs define this version of the SENSE IU data structure.
* It's still in use by several different firmware releases. * It's still in use by several different firmware releases.
@ -79,18 +38,6 @@ struct sense_iu_old {
__u8 sense[SCSI_SENSE_BUFFERSIZE]; __u8 sense[SCSI_SENSE_BUFFERSIZE];
}; };
enum {
CMD_PIPE_ID = 1,
STATUS_PIPE_ID = 2,
DATA_IN_PIPE_ID = 3,
DATA_OUT_PIPE_ID = 4,
UAS_SIMPLE_TAG = 0,
UAS_HEAD_TAG = 1,
UAS_ORDERED_TAG = 2,
UAS_ACA = 4,
};
struct uas_dev_info { struct uas_dev_info {
struct usb_interface *intf; struct usb_interface *intf;
struct usb_device *udev; struct usb_device *udev;
@ -98,6 +45,8 @@ struct uas_dev_info {
unsigned cmd_pipe, status_pipe, data_in_pipe, data_out_pipe; unsigned cmd_pipe, status_pipe, data_in_pipe, data_out_pipe;
unsigned use_streams:1; unsigned use_streams:1;
unsigned uas_sense_old:1; unsigned uas_sense_old:1;
struct scsi_cmnd *cmnd;
struct urb *status_urb; /* used only if stream support is available */
}; };
enum { enum {
@ -109,6 +58,9 @@ enum {
SUBMIT_DATA_OUT_URB = (1 << 5), SUBMIT_DATA_OUT_URB = (1 << 5),
ALLOC_CMD_URB = (1 << 6), ALLOC_CMD_URB = (1 << 6),
SUBMIT_CMD_URB = (1 << 7), SUBMIT_CMD_URB = (1 << 7),
COMPLETED_DATA_IN = (1 << 8),
COMPLETED_DATA_OUT = (1 << 9),
DATA_COMPLETES_CMD = (1 << 10),
}; };
/* Overrides scsi_pointer */ /* Overrides scsi_pointer */
@ -116,6 +68,7 @@ struct uas_cmd_info {
unsigned int state; unsigned int state;
unsigned int stream; unsigned int stream;
struct urb *cmd_urb; struct urb *cmd_urb;
/* status_urb is used only if stream support isn't available */
struct urb *status_urb; struct urb *status_urb;
struct urb *data_in_urb; struct urb *data_in_urb;
struct urb *data_out_urb; struct urb *data_out_urb;
@ -125,33 +78,43 @@ struct uas_cmd_info {
/* I hate forward declarations, but I actually have a loop */ /* I hate forward declarations, but I actually have a loop */
static int uas_submit_urbs(struct scsi_cmnd *cmnd, static int uas_submit_urbs(struct scsi_cmnd *cmnd,
struct uas_dev_info *devinfo, gfp_t gfp); struct uas_dev_info *devinfo, gfp_t gfp);
static void uas_do_work(struct work_struct *work);
static DECLARE_WORK(uas_work, uas_do_work);
static DEFINE_SPINLOCK(uas_work_lock); static DEFINE_SPINLOCK(uas_work_lock);
static LIST_HEAD(uas_work_list); static LIST_HEAD(uas_work_list);
static void uas_do_work(struct work_struct *work) static void uas_do_work(struct work_struct *work)
{ {
struct uas_cmd_info *cmdinfo; struct uas_cmd_info *cmdinfo;
struct uas_cmd_info *temp;
struct list_head list; struct list_head list;
int err;
spin_lock_irq(&uas_work_lock); spin_lock_irq(&uas_work_lock);
list_replace_init(&uas_work_list, &list); list_replace_init(&uas_work_list, &list);
spin_unlock_irq(&uas_work_lock); spin_unlock_irq(&uas_work_lock);
list_for_each_entry(cmdinfo, &list, list) { list_for_each_entry_safe(cmdinfo, temp, &list, list) {
struct scsi_pointer *scp = (void *)cmdinfo; struct scsi_pointer *scp = (void *)cmdinfo;
struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd *cmnd = container_of(scp,
struct scsi_cmnd, SCp); struct scsi_cmnd, SCp);
uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_NOIO); err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_NOIO);
if (err) {
list_del(&cmdinfo->list);
spin_lock_irq(&uas_work_lock);
list_add_tail(&cmdinfo->list, &uas_work_list);
spin_unlock_irq(&uas_work_lock);
schedule_work(&uas_work);
}
} }
} }
static DECLARE_WORK(uas_work, uas_do_work);
static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd) static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd)
{ {
struct sense_iu *sense_iu = urb->transfer_buffer; struct sense_iu *sense_iu = urb->transfer_buffer;
struct scsi_device *sdev = cmnd->device; struct scsi_device *sdev = cmnd->device;
struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
if (urb->actual_length > 16) { if (urb->actual_length > 16) {
unsigned len = be16_to_cpup(&sense_iu->len); unsigned len = be16_to_cpup(&sense_iu->len);
@ -169,16 +132,15 @@ static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd)
} }
cmnd->result = sense_iu->status; cmnd->result = sense_iu->status;
if (sdev->current_cmnd) if (!(cmdinfo->state & DATA_COMPLETES_CMD))
sdev->current_cmnd = NULL; cmnd->scsi_done(cmnd);
cmnd->scsi_done(cmnd);
usb_free_urb(urb);
} }
static void uas_sense_old(struct urb *urb, struct scsi_cmnd *cmnd) static void uas_sense_old(struct urb *urb, struct scsi_cmnd *cmnd)
{ {
struct sense_iu_old *sense_iu = urb->transfer_buffer; struct sense_iu_old *sense_iu = urb->transfer_buffer;
struct scsi_device *sdev = cmnd->device; struct scsi_device *sdev = cmnd->device;
struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
if (urb->actual_length > 8) { if (urb->actual_length > 8) {
unsigned len = be16_to_cpup(&sense_iu->len) - 2; unsigned len = be16_to_cpup(&sense_iu->len) - 2;
@ -196,10 +158,8 @@ static void uas_sense_old(struct urb *urb, struct scsi_cmnd *cmnd)
} }
cmnd->result = sense_iu->status; cmnd->result = sense_iu->status;
if (sdev->current_cmnd) if (!(cmdinfo->state & DATA_COMPLETES_CMD))
sdev->current_cmnd = NULL; cmnd->scsi_done(cmnd);
cmnd->scsi_done(cmnd);
usb_free_urb(urb);
} }
static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd, static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd,
@ -208,7 +168,7 @@ static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd,
struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
int err; int err;
cmdinfo->state = direction | SUBMIT_STATUS_URB; cmdinfo->state = direction;
err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC); err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC);
if (err) { if (err) {
spin_lock(&uas_work_lock); spin_lock(&uas_work_lock);
@ -221,27 +181,61 @@ static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd,
static void uas_stat_cmplt(struct urb *urb) static void uas_stat_cmplt(struct urb *urb)
{ {
struct iu *iu = urb->transfer_buffer; struct iu *iu = urb->transfer_buffer;
struct scsi_device *sdev = urb->context; struct Scsi_Host *shost = urb->context;
struct uas_dev_info *devinfo = sdev->hostdata; struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
struct scsi_cmnd *cmnd; struct scsi_cmnd *cmnd;
struct uas_cmd_info *cmdinfo;
u16 tag; u16 tag;
int ret;
if (urb->status) { if (urb->status) {
dev_err(&urb->dev->dev, "URB BAD STATUS %d\n", urb->status); dev_err(&urb->dev->dev, "URB BAD STATUS %d\n", urb->status);
usb_free_urb(urb); if (devinfo->use_streams)
usb_free_urb(urb);
return; return;
} }
tag = be16_to_cpup(&iu->tag) - 1; tag = be16_to_cpup(&iu->tag) - 1;
if (sdev->current_cmnd) if (tag == 0)
cmnd = sdev->current_cmnd; cmnd = devinfo->cmnd;
else else
cmnd = scsi_find_tag(sdev, tag); cmnd = scsi_host_find_tag(shost, tag - 1);
if (!cmnd) if (!cmnd) {
if (devinfo->use_streams) {
usb_free_urb(urb);
return;
}
ret = usb_submit_urb(urb, GFP_ATOMIC);
if (ret)
dev_err(&urb->dev->dev, "failed submit status urb\n");
return; return;
}
cmdinfo = (void *)&cmnd->SCp;
switch (iu->iu_id) { switch (iu->iu_id) {
case IU_ID_STATUS: case IU_ID_STATUS:
if (devinfo->cmnd == cmnd)
devinfo->cmnd = NULL;
if (!(cmdinfo->state & COMPLETED_DATA_IN) &&
cmdinfo->data_in_urb) {
if (devinfo->use_streams) {
cmdinfo->state |= DATA_COMPLETES_CMD;
usb_unlink_urb(cmdinfo->data_in_urb);
} else {
usb_free_urb(cmdinfo->data_in_urb);
}
}
if (!(cmdinfo->state & COMPLETED_DATA_OUT) &&
cmdinfo->data_out_urb) {
if (devinfo->use_streams) {
cmdinfo->state |= DATA_COMPLETES_CMD;
usb_unlink_urb(cmdinfo->data_in_urb);
} else {
usb_free_urb(cmdinfo->data_out_urb);
}
}
if (urb->actual_length < 16) if (urb->actual_length < 16)
devinfo->uas_sense_old = 1; devinfo->uas_sense_old = 1;
if (devinfo->uas_sense_old) if (devinfo->uas_sense_old)
@ -259,29 +253,70 @@ static void uas_stat_cmplt(struct urb *urb)
scmd_printk(KERN_ERR, cmnd, scmd_printk(KERN_ERR, cmnd,
"Bogus IU (%d) received on status pipe\n", iu->iu_id); "Bogus IU (%d) received on status pipe\n", iu->iu_id);
} }
if (devinfo->use_streams) {
usb_free_urb(urb);
return;
}
ret = usb_submit_urb(urb, GFP_ATOMIC);
if (ret)
dev_err(&urb->dev->dev, "failed submit status urb\n");
} }
static void uas_data_cmplt(struct urb *urb) static void uas_data_out_cmplt(struct urb *urb)
{ {
struct scsi_data_buffer *sdb = urb->context; struct scsi_cmnd *cmnd = urb->context;
struct scsi_data_buffer *sdb = scsi_out(cmnd);
struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
cmdinfo->state |= COMPLETED_DATA_OUT;
sdb->resid = sdb->length - urb->actual_length; sdb->resid = sdb->length - urb->actual_length;
usb_free_urb(urb); usb_free_urb(urb);
if (cmdinfo->state & DATA_COMPLETES_CMD)
cmnd->scsi_done(cmnd);
}
static void uas_data_in_cmplt(struct urb *urb)
{
struct scsi_cmnd *cmnd = urb->context;
struct scsi_data_buffer *sdb = scsi_in(cmnd);
struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
cmdinfo->state |= COMPLETED_DATA_IN;
sdb->resid = sdb->length - urb->actual_length;
usb_free_urb(urb);
if (cmdinfo->state & DATA_COMPLETES_CMD)
cmnd->scsi_done(cmnd);
} }
static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp, static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp,
unsigned int pipe, u16 stream_id, unsigned int pipe, struct scsi_cmnd *cmnd,
struct scsi_data_buffer *sdb, enum dma_data_direction dir)
enum dma_data_direction dir)
{ {
struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
struct usb_device *udev = devinfo->udev; struct usb_device *udev = devinfo->udev;
struct urb *urb = usb_alloc_urb(0, gfp); struct urb *urb = usb_alloc_urb(0, gfp);
struct scsi_data_buffer *sdb;
usb_complete_t complete_fn;
u16 stream_id = cmdinfo->stream;
if (!urb) if (!urb)
goto out; goto out;
usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length, uas_data_cmplt, if (dir == DMA_FROM_DEVICE) {
sdb); sdb = scsi_in(cmnd);
if (devinfo->use_streams) complete_fn = uas_data_in_cmplt;
urb->stream_id = stream_id; } else {
sdb = scsi_out(cmnd);
complete_fn = uas_data_out_cmplt;
}
usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length,
complete_fn, cmnd);
urb->stream_id = stream_id;
urb->num_sgs = udev->bus->sg_tablesize ? sdb->table.nents : 0; urb->num_sgs = udev->bus->sg_tablesize ? sdb->table.nents : 0;
urb->sg = sdb->table.sgl; urb->sg = sdb->table.sgl;
out: out:
@ -289,7 +324,7 @@ static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp,
} }
static struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp, static struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp,
struct scsi_cmnd *cmnd, u16 stream_id) struct Scsi_Host *shost, u16 stream_id)
{ {
struct usb_device *udev = devinfo->udev; struct usb_device *udev = devinfo->udev;
struct urb *urb = usb_alloc_urb(0, gfp); struct urb *urb = usb_alloc_urb(0, gfp);
@ -303,7 +338,7 @@ static struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp,
goto free; goto free;
usb_fill_bulk_urb(urb, udev, devinfo->status_pipe, iu, sizeof(*iu), usb_fill_bulk_urb(urb, udev, devinfo->status_pipe, iu, sizeof(*iu),
uas_stat_cmplt, cmnd->device); uas_stat_cmplt, shost);
urb->stream_id = stream_id; urb->stream_id = stream_id;
urb->transfer_flags |= URB_FREE_BUFFER; urb->transfer_flags |= URB_FREE_BUFFER;
out: out:
@ -334,7 +369,10 @@ static struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp,
goto free; goto free;
iu->iu_id = IU_ID_COMMAND; iu->iu_id = IU_ID_COMMAND;
iu->tag = cpu_to_be16(stream_id); if (blk_rq_tagged(cmnd->request))
iu->tag = cpu_to_be16(cmnd->request->tag + 2);
else
iu->tag = cpu_to_be16(1);
iu->prio_attr = UAS_SIMPLE_TAG; iu->prio_attr = UAS_SIMPLE_TAG;
iu->len = len; iu->len = len;
int_to_scsilun(sdev->lun, &iu->lun); int_to_scsilun(sdev->lun, &iu->lun);
@ -362,8 +400,8 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
if (cmdinfo->state & ALLOC_STATUS_URB) { if (cmdinfo->state & ALLOC_STATUS_URB) {
cmdinfo->status_urb = uas_alloc_sense_urb(devinfo, gfp, cmnd, cmdinfo->status_urb = uas_alloc_sense_urb(devinfo, gfp,
cmdinfo->stream); cmnd->device->host, cmdinfo->stream);
if (!cmdinfo->status_urb) if (!cmdinfo->status_urb)
return SCSI_MLQUEUE_DEVICE_BUSY; return SCSI_MLQUEUE_DEVICE_BUSY;
cmdinfo->state &= ~ALLOC_STATUS_URB; cmdinfo->state &= ~ALLOC_STATUS_URB;
@ -380,8 +418,8 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
if (cmdinfo->state & ALLOC_DATA_IN_URB) { if (cmdinfo->state & ALLOC_DATA_IN_URB) {
cmdinfo->data_in_urb = uas_alloc_data_urb(devinfo, gfp, cmdinfo->data_in_urb = uas_alloc_data_urb(devinfo, gfp,
devinfo->data_in_pipe, cmdinfo->stream, devinfo->data_in_pipe, cmnd,
scsi_in(cmnd), DMA_FROM_DEVICE); DMA_FROM_DEVICE);
if (!cmdinfo->data_in_urb) if (!cmdinfo->data_in_urb)
return SCSI_MLQUEUE_DEVICE_BUSY; return SCSI_MLQUEUE_DEVICE_BUSY;
cmdinfo->state &= ~ALLOC_DATA_IN_URB; cmdinfo->state &= ~ALLOC_DATA_IN_URB;
@ -398,8 +436,8 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
if (cmdinfo->state & ALLOC_DATA_OUT_URB) { if (cmdinfo->state & ALLOC_DATA_OUT_URB) {
cmdinfo->data_out_urb = uas_alloc_data_urb(devinfo, gfp, cmdinfo->data_out_urb = uas_alloc_data_urb(devinfo, gfp,
devinfo->data_out_pipe, cmdinfo->stream, devinfo->data_out_pipe, cmnd,
scsi_out(cmnd), DMA_TO_DEVICE); DMA_TO_DEVICE);
if (!cmdinfo->data_out_urb) if (!cmdinfo->data_out_urb)
return SCSI_MLQUEUE_DEVICE_BUSY; return SCSI_MLQUEUE_DEVICE_BUSY;
cmdinfo->state &= ~ALLOC_DATA_OUT_URB; cmdinfo->state &= ~ALLOC_DATA_OUT_URB;
@ -444,13 +482,13 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
BUILD_BUG_ON(sizeof(struct uas_cmd_info) > sizeof(struct scsi_pointer)); BUILD_BUG_ON(sizeof(struct uas_cmd_info) > sizeof(struct scsi_pointer));
if (!cmdinfo->status_urb && sdev->current_cmnd) if (devinfo->cmnd)
return SCSI_MLQUEUE_DEVICE_BUSY; return SCSI_MLQUEUE_DEVICE_BUSY;
if (blk_rq_tagged(cmnd->request)) { if (blk_rq_tagged(cmnd->request)) {
cmdinfo->stream = cmnd->request->tag + 1; cmdinfo->stream = cmnd->request->tag + 2;
} else { } else {
sdev->current_cmnd = cmnd; devinfo->cmnd = cmnd;
cmdinfo->stream = 1; cmdinfo->stream = 1;
} }
@ -472,7 +510,8 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
} }
if (!devinfo->use_streams) { if (!devinfo->use_streams) {
cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB); cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB |
ALLOC_STATUS_URB | SUBMIT_STATUS_URB);
cmdinfo->stream = 0; cmdinfo->stream = 0;
} }
@ -551,7 +590,7 @@ static int uas_slave_configure(struct scsi_device *sdev)
{ {
struct uas_dev_info *devinfo = sdev->hostdata; struct uas_dev_info *devinfo = sdev->hostdata;
scsi_set_tag_type(sdev, MSG_ORDERED_TAG); scsi_set_tag_type(sdev, MSG_ORDERED_TAG);
scsi_activate_tcq(sdev, devinfo->qdepth - 1); scsi_activate_tcq(sdev, devinfo->qdepth - 2);
return 0; return 0;
} }
@ -589,22 +628,34 @@ static int uas_is_interface(struct usb_host_interface *intf)
intf->desc.bInterfaceProtocol == USB_PR_UAS); intf->desc.bInterfaceProtocol == USB_PR_UAS);
} }
static int uas_isnt_supported(struct usb_device *udev)
{
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
dev_warn(&udev->dev, "The driver for the USB controller %s does not "
"support scatter-gather which is\n",
hcd->driver->description);
dev_warn(&udev->dev, "required by the UAS driver. Please try an"
"alternative USB controller if you wish to use UAS.\n");
return -ENODEV;
}
static int uas_switch_interface(struct usb_device *udev, static int uas_switch_interface(struct usb_device *udev,
struct usb_interface *intf) struct usb_interface *intf)
{ {
int i; int i;
int sg_supported = udev->bus->sg_tablesize != 0;
if (uas_is_interface(intf->cur_altsetting))
return 0;
for (i = 0; i < intf->num_altsetting; i++) { for (i = 0; i < intf->num_altsetting; i++) {
struct usb_host_interface *alt = &intf->altsetting[i]; struct usb_host_interface *alt = &intf->altsetting[i];
if (alt == intf->cur_altsetting)
continue; if (uas_is_interface(alt)) {
if (uas_is_interface(alt)) if (!sg_supported)
return uas_isnt_supported(udev);
return usb_set_interface(udev, return usb_set_interface(udev,
alt->desc.bInterfaceNumber, alt->desc.bInterfaceNumber,
alt->desc.bAlternateSetting); alt->desc.bAlternateSetting);
}
} }
return -ENODEV; return -ENODEV;
@ -619,6 +670,7 @@ static void uas_configure_endpoints(struct uas_dev_info *devinfo)
unsigned i, n_endpoints = intf->cur_altsetting->desc.bNumEndpoints; unsigned i, n_endpoints = intf->cur_altsetting->desc.bNumEndpoints;
devinfo->uas_sense_old = 0; devinfo->uas_sense_old = 0;
devinfo->cmnd = NULL;
for (i = 0; i < n_endpoints; i++) { for (i = 0; i < n_endpoints; i++) {
unsigned char *extra = endpoint[i].extra; unsigned char *extra = endpoint[i].extra;
@ -670,6 +722,40 @@ static void uas_configure_endpoints(struct uas_dev_info *devinfo)
} }
} }
static int uas_alloc_status_urb(struct uas_dev_info *devinfo,
struct Scsi_Host *shost)
{
if (devinfo->use_streams) {
devinfo->status_urb = NULL;
return 0;
}
devinfo->status_urb = uas_alloc_sense_urb(devinfo, GFP_KERNEL,
shost, 0);
if (!devinfo->status_urb)
goto err_s_urb;
if (usb_submit_urb(devinfo->status_urb, GFP_KERNEL))
goto err_submit_urb;
return 0;
err_submit_urb:
usb_free_urb(devinfo->status_urb);
err_s_urb:
return -ENOMEM;
}
static void uas_free_streams(struct uas_dev_info *devinfo)
{
struct usb_device *udev = devinfo->udev;
struct usb_host_endpoint *eps[3];
eps[0] = usb_pipe_endpoint(udev, devinfo->status_pipe);
eps[1] = usb_pipe_endpoint(udev, devinfo->data_in_pipe);
eps[2] = usb_pipe_endpoint(udev, devinfo->data_out_pipe);
usb_free_streams(devinfo->intf, eps, 3, GFP_KERNEL);
}
/* /*
* XXX: What I'd like to do here is register a SCSI host for each USB host in * XXX: What I'd like to do here is register a SCSI host for each USB host in
* the system. Follow usb-storage's design of registering a SCSI host for * the system. Follow usb-storage's design of registering a SCSI host for
@ -699,18 +785,33 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
shost->max_id = 1; shost->max_id = 1;
shost->sg_tablesize = udev->bus->sg_tablesize; shost->sg_tablesize = udev->bus->sg_tablesize;
result = scsi_add_host(shost, &intf->dev);
if (result)
goto free;
shost->hostdata[0] = (unsigned long)devinfo;
devinfo->intf = intf; devinfo->intf = intf;
devinfo->udev = udev; devinfo->udev = udev;
uas_configure_endpoints(devinfo); uas_configure_endpoints(devinfo);
result = scsi_init_shared_tag_map(shost, devinfo->qdepth - 2);
if (result)
goto free;
result = scsi_add_host(shost, &intf->dev);
if (result)
goto deconfig_eps;
shost->hostdata[0] = (unsigned long)devinfo;
result = uas_alloc_status_urb(devinfo, shost);
if (result)
goto err_alloc_status;
scsi_scan_host(shost); scsi_scan_host(shost);
usb_set_intfdata(intf, shost); usb_set_intfdata(intf, shost);
return result; return result;
err_alloc_status:
scsi_remove_host(shost);
shost = NULL;
deconfig_eps:
uas_free_streams(devinfo);
free: free:
kfree(devinfo); kfree(devinfo);
if (shost) if (shost)
@ -732,18 +833,13 @@ static int uas_post_reset(struct usb_interface *intf)
static void uas_disconnect(struct usb_interface *intf) static void uas_disconnect(struct usb_interface *intf)
{ {
struct usb_device *udev = interface_to_usbdev(intf);
struct usb_host_endpoint *eps[3];
struct Scsi_Host *shost = usb_get_intfdata(intf); struct Scsi_Host *shost = usb_get_intfdata(intf);
struct uas_dev_info *devinfo = (void *)shost->hostdata[0]; struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
scsi_remove_host(shost); scsi_remove_host(shost);
usb_kill_urb(devinfo->status_urb);
eps[0] = usb_pipe_endpoint(udev, devinfo->status_pipe); usb_free_urb(devinfo->status_urb);
eps[1] = usb_pipe_endpoint(udev, devinfo->data_in_pipe); uas_free_streams(devinfo);
eps[2] = usb_pipe_endpoint(udev, devinfo->data_out_pipe);
usb_free_streams(intf, eps, 3, GFP_KERNEL);
kfree(devinfo); kfree(devinfo);
} }

View File

@ -125,6 +125,9 @@ static struct us_unusual_dev us_unusual_dev_list[] = {
{ } /* Terminating entry */ { } /* Terminating entry */
}; };
static struct us_unusual_dev for_dynamic_ids =
USUAL_DEV(USB_SC_SCSI, USB_PR_BULK, 0);
#undef UNUSUAL_DEV #undef UNUSUAL_DEV
#undef COMPLIANT_DEV #undef COMPLIANT_DEV
#undef USUAL_DEV #undef USUAL_DEV
@ -999,8 +1002,10 @@ EXPORT_SYMBOL_GPL(usb_stor_disconnect);
static int storage_probe(struct usb_interface *intf, static int storage_probe(struct usb_interface *intf,
const struct usb_device_id *id) const struct usb_device_id *id)
{ {
struct us_unusual_dev *unusual_dev;
struct us_data *us; struct us_data *us;
int result; int result;
int size;
/* /*
* If libusual is configured, let it decide whether a standard * If libusual is configured, let it decide whether a standard
@ -1019,8 +1024,19 @@ static int storage_probe(struct usb_interface *intf,
* table, so we use the index of the id entry to find the * table, so we use the index of the id entry to find the
* corresponding unusual_devs entry. * corresponding unusual_devs entry.
*/ */
result = usb_stor_probe1(&us, intf, id,
(id - usb_storage_usb_ids) + us_unusual_dev_list); size = ARRAY_SIZE(us_unusual_dev_list);
if (id >= usb_storage_usb_ids && id < usb_storage_usb_ids + size) {
unusual_dev = (id - usb_storage_usb_ids) + us_unusual_dev_list;
} else {
unusual_dev = &for_dynamic_ids;
US_DEBUGP("%s %s 0x%04x 0x%04x\n", "Use Bulk-Only transport",
"with the Transparent SCSI protocol for dynamic id:",
id->idVendor, id->idProduct);
}
result = usb_stor_probe1(&us, intf, id, unusual_dev);
if (result) if (result)
return result; return result;
@ -1046,7 +1062,6 @@ static struct usb_driver usb_storage_driver = {
.id_table = usb_storage_usb_ids, .id_table = usb_storage_usb_ids,
.supports_autosuspend = 1, .supports_autosuspend = 1,
.soft_unbind = 1, .soft_unbind = 1,
.no_dynamic_id = 1,
}; };
static int __init usb_stor_init(void) static int __init usb_stor_init(void)

View File

@ -376,6 +376,12 @@ struct usb_bus {
struct usb_tt; struct usb_tt;
enum usb_device_removable {
USB_DEVICE_REMOVABLE_UNKNOWN = 0,
USB_DEVICE_REMOVABLE,
USB_DEVICE_FIXED,
};
/** /**
* struct usb_device - kernel's representation of a USB device * struct usb_device - kernel's representation of a USB device
* @devnum: device number; address on a USB bus * @devnum: device number; address on a USB bus
@ -432,6 +438,7 @@ struct usb_tt;
* @wusb_dev: if this is a Wireless USB device, link to the WUSB * @wusb_dev: if this is a Wireless USB device, link to the WUSB
* specific data for the device. * specific data for the device.
* @slot_id: Slot ID assigned by xHCI * @slot_id: Slot ID assigned by xHCI
* @removable: Device can be physically removed from this port
* *
* Notes: * Notes:
* Usbcore drivers should not set usbdev->state directly. Instead use * Usbcore drivers should not set usbdev->state directly. Instead use
@ -509,6 +516,7 @@ struct usb_device {
#endif #endif
struct wusb_dev *wusb_dev; struct wusb_dev *wusb_dev;
int slot_id; int slot_id;
enum usb_device_removable removable;
}; };
#define to_usb_device(d) container_of(d, struct usb_device, dev) #define to_usb_device(d) container_of(d, struct usb_device, dev)

View File

@ -76,6 +76,11 @@
#define USB_PORT_FEAT_C_BH_PORT_RESET 29 #define USB_PORT_FEAT_C_BH_PORT_RESET 29
#define USB_PORT_FEAT_FORCE_LINKPM_ACCEPT 30 #define USB_PORT_FEAT_FORCE_LINKPM_ACCEPT 30
/* USB 3.0 hub remote wake mask bits, see table 10-14 */
#define USB_PORT_FEAT_REMOTE_WAKE_CONNECT (1 << 8)
#define USB_PORT_FEAT_REMOTE_WAKE_DISCONNECT (1 << 9)
#define USB_PORT_FEAT_REMOTE_WAKE_OVER_CURRENT (1 << 10)
/* /*
* Hub Status and Hub Change results * Hub Status and Hub Change results
* See USB 2.0 spec Table 11-19 and Table 11-20 * See USB 2.0 spec Table 11-19 and Table 11-20

View File

@ -412,6 +412,8 @@ extern irqreturn_t usb_hcd_irq(int irq, void *__hcd);
extern void usb_hc_died(struct usb_hcd *hcd); extern void usb_hc_died(struct usb_hcd *hcd);
extern void usb_hcd_poll_rh_status(struct usb_hcd *hcd); extern void usb_hcd_poll_rh_status(struct usb_hcd *hcd);
extern void usb_wakeup_notification(struct usb_device *hdev,
unsigned int portnum);
/* The D0/D1 toggle bits ... USE WITH CAUTION (they're almost hcd-internal) */ /* The D0/D1 toggle bits ... USE WITH CAUTION (they're almost hcd-internal) */
#define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> (ep)) & 1) #define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> (ep)) & 1)

View File

@ -389,5 +389,20 @@ do { \
printk(KERN_DEBUG "%s: " format "\n", __FILE__, ##arg); \ printk(KERN_DEBUG "%s: " format "\n", __FILE__, ##arg); \
} while (0) } while (0)
/*
* Macro for reporting errors in write path to avoid inifinite loop
* when port is used as a console.
*/
#define dev_err_console(usport, fmt, ...) \
do { \
static bool __print_once; \
struct usb_serial_port *__port = (usport); \
\
if (!__port->port.console || !__print_once) { \
__print_once = true; \
dev_err(&__port->dev, fmt, ##__VA_ARGS__); \
} \
} while (0)
#endif /* __LINUX_USB_SERIAL_H */ #endif /* __LINUX_USB_SERIAL_H */

69
include/linux/usb/uas.h Normal file
View File

@ -0,0 +1,69 @@
#ifndef __USB_UAS_H__
#define __USB_UAS_H__
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
/* Common header for all IUs */
struct iu {
__u8 iu_id;
__u8 rsvd1;
__be16 tag;
};
enum {
IU_ID_COMMAND = 0x01,
IU_ID_STATUS = 0x03,
IU_ID_RESPONSE = 0x04,
IU_ID_TASK_MGMT = 0x05,
IU_ID_READ_READY = 0x06,
IU_ID_WRITE_READY = 0x07,
};
struct command_iu {
__u8 iu_id;
__u8 rsvd1;
__be16 tag;
__u8 prio_attr;
__u8 rsvd5;
__u8 len;
__u8 rsvd7;
struct scsi_lun lun;
__u8 cdb[16]; /* XXX: Overflow-checking tools may misunderstand */
};
/*
* Also used for the Read Ready and Write Ready IUs since they have the
* same first four bytes
*/
struct sense_iu {
__u8 iu_id;
__u8 rsvd1;
__be16 tag;
__be16 status_qual;
__u8 status;
__u8 rsvd7[7];
__be16 len;
__u8 sense[SCSI_SENSE_BUFFERSIZE];
};
struct usb_pipe_usage_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bPipeID;
__u8 Reserved;
} __attribute__((__packed__));
enum {
CMD_PIPE_ID = 1,
STATUS_PIPE_ID = 2,
DATA_IN_PIPE_ID = 3,
DATA_OUT_PIPE_ID = 4,
UAS_SIMPLE_TAG = 0,
UAS_HEAD_TAG = 1,
UAS_ORDERED_TAG = 2,
UAS_ACA = 4,
};
#endif

View File

@ -136,6 +136,7 @@ struct scsi_device {
unsigned use_10_for_ms:1; /* first try 10-byte mode sense/select */ unsigned use_10_for_ms:1; /* first try 10-byte mode sense/select */
unsigned skip_ms_page_8:1; /* do not use MODE SENSE page 0x08 */ unsigned skip_ms_page_8:1; /* do not use MODE SENSE page 0x08 */
unsigned skip_ms_page_3f:1; /* do not use MODE SENSE page 0x3f */ unsigned skip_ms_page_3f:1; /* do not use MODE SENSE page 0x3f */
unsigned skip_vpd_pages:1; /* do not read VPD pages */
unsigned use_192_bytes_for_3f:1; /* ask for 192 bytes from page 0x3f */ unsigned use_192_bytes_for_3f:1; /* ask for 192 bytes from page 0x3f */
unsigned no_start_on_add:1; /* do not issue start on add */ unsigned no_start_on_add:1; /* do not issue start on add */
unsigned allow_restart:1; /* issue START_UNIT in error handler */ unsigned allow_restart:1; /* issue START_UNIT in error handler */
@ -246,8 +247,10 @@ struct scsi_target {
unsigned int single_lun:1; /* Indicates we should only unsigned int single_lun:1; /* Indicates we should only
* allow I/O to one of the luns * allow I/O to one of the luns
* for the device at a time. */ * for the device at a time. */
unsigned int pdt_1f_for_no_lun; /* PDT = 0x1f */ unsigned int pdt_1f_for_no_lun:1; /* PDT = 0x1f
/* means no lun present */ * means no lun present. */
unsigned int no_report_luns:1; /* Don't use
* REPORT LUNS for scanning. */
/* commands actually active on LLD. protected by host lock. */ /* commands actually active on LLD. protected by host lock. */
unsigned int target_busy; unsigned int target_busy;
/* /*