Commit ac01ad71 authored by Matthew Dharm's avatar Matthew Dharm Committed by Greg Kroah-Hartman

[PATCH] USB: usb-storage: usb_stor_control_msg() and stuff

This patch replaces usb_control_msg() with usb_stor_control_msg() everywhere,
which allows better abort/disconnect processing.

Some comments are fixed-up.

The GetMaxLUN function is moved later so URBs are initialized (now that it
uses the new control_msg() ).

There is also some locking cleanup during reset.
parent 08c85f44
...@@ -399,7 +399,7 @@ freecom_init (struct us_data *us) ...@@ -399,7 +399,7 @@ freecom_init (struct us_data *us)
} }
} }
result = usb_control_msg(us->pusb_dev, us->recv_ctrl_pipe, result = usb_stor_control_msg(us, us->recv_ctrl_pipe,
0x4c, 0xc0, 0x4346, 0x0, buffer, 0x20, 3*HZ); 0x4c, 0xc0, 0x4346, 0x0, buffer, 0x20, 3*HZ);
buffer[32] = '\0'; buffer[32] = '\0';
US_DEBUGP("String returned from FC init is: %s\n", buffer); US_DEBUGP("String returned from FC init is: %s\n", buffer);
...@@ -411,7 +411,7 @@ freecom_init (struct us_data *us) ...@@ -411,7 +411,7 @@ freecom_init (struct us_data *us)
*/ */
/* send reset */ /* send reset */
result = usb_control_msg(us->pusb_dev, us->send_ctrl_pipe, result = usb_stor_control_msg(us, us->send_ctrl_pipe,
0x4d, 0x40, 0x24d8, 0x0, NULL, 0x0, 3*HZ); 0x4d, 0x40, 0x24d8, 0x0, NULL, 0x0, 3*HZ);
US_DEBUGP("result from activate reset is %d\n", result); US_DEBUGP("result from activate reset is %d\n", result);
...@@ -419,7 +419,7 @@ freecom_init (struct us_data *us) ...@@ -419,7 +419,7 @@ freecom_init (struct us_data *us)
mdelay(250); mdelay(250);
/* clear reset */ /* clear reset */
result = usb_control_msg(us->pusb_dev, us->send_ctrl_pipe, result = usb_stor_control_msg(us, us->send_ctrl_pipe,
0x4d, 0x40, 0x24f8, 0x0, NULL, 0x0, 3*HZ); 0x4d, 0x40, 0x24f8, 0x0, NULL, 0x0, 3*HZ);
US_DEBUGP("result from clear reset is %d\n", result); US_DEBUGP("result from clear reset is %d\n", result);
......
...@@ -50,7 +50,7 @@ int usb_stor_euscsi_init(struct us_data *us) ...@@ -50,7 +50,7 @@ int usb_stor_euscsi_init(struct us_data *us)
int result; int result;
US_DEBUGP("Attempting to init eUSCSI bridge...\n"); US_DEBUGP("Attempting to init eUSCSI bridge...\n");
result = usb_control_msg(us->pusb_dev, us->send_ctrl_pipe, result = usb_stor_control_msg(us, us->send_ctrl_pipe,
0x0C, USB_RECIP_INTERFACE | USB_TYPE_VENDOR, 0x0C, USB_RECIP_INTERFACE | USB_TYPE_VENDOR,
0x01, 0x0, &data, 0x1, 5*HZ); 0x01, 0x0, &data, 0x1, 5*HZ);
US_DEBUGP("-- result is %d\n", result); US_DEBUGP("-- result is %d\n", result);
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include <linux/config.h> #include <linux/config.h>
#include "usb.h" #include "usb.h"
#include "transport.h"
/* This places the Shuttle/SCM USB<->SCSI bridge devices in multi-target /* This places the Shuttle/SCM USB<->SCSI bridge devices in multi-target
* mode */ * mode */
......
...@@ -219,7 +219,7 @@ static int usb_storage_device_reset( Scsi_Cmnd *srb ) ...@@ -219,7 +219,7 @@ static int usb_storage_device_reset( Scsi_Cmnd *srb )
int state = atomic_read(&us->sm_state); int state = atomic_read(&us->sm_state);
int result; int result;
US_DEBUGP("device_reset() called\n" ); US_DEBUGP("%s called\n", __FUNCTION__);
if (state != US_STATE_IDLE) { if (state != US_STATE_IDLE) {
printk(KERN_ERR USB_STORAGE "Error in %s: " printk(KERN_ERR USB_STORAGE "Error in %s: "
"invalid state %d\n", __FUNCTION__, state); "invalid state %d\n", __FUNCTION__, state);
...@@ -245,39 +245,49 @@ static int usb_storage_device_reset( Scsi_Cmnd *srb ) ...@@ -245,39 +245,49 @@ static int usb_storage_device_reset( Scsi_Cmnd *srb )
return result; return result;
} }
/* This resets the device port */ /* This resets the device's USB port. */
/* It refuses to work if there's more than one interface in /* It refuses to work if there's more than one interface in
this device, so that other users are not affected. */ * the device, so that other users are not affected. */
/* This is always called with scsi_lock(srb->host) held */ /* This is always called with scsi_lock(srb->host) held */
static int usb_storage_bus_reset( Scsi_Cmnd *srb ) static int usb_storage_bus_reset( Scsi_Cmnd *srb )
{ {
struct us_data *us; struct us_data *us = (struct us_data *)srb->device->host->hostdata[0];
int state = atomic_read(&us->sm_state);
int result; int result;
/* we use the usb_reset_device() function to handle this for us */ US_DEBUGP("%s called\n", __FUNCTION__);
US_DEBUGP("bus_reset() called\n"); if (state != US_STATE_IDLE) {
printk(KERN_ERR USB_STORAGE "Error in %s: "
"invalid state %d\n", __FUNCTION__, state);
return FAILED;
}
/* set the state and release the lock */
atomic_set(&us->sm_state, US_STATE_RESETTING);
scsi_unlock(srb->device->host); scsi_unlock(srb->device->host);
us = (struct us_data *)srb->device->host->hostdata[0];
/* The USB subsystem doesn't handle synchronisation between /* The USB subsystem doesn't handle synchronisation between
a device's several drivers. Therefore we reset only devices a device's several drivers. Therefore we reset only devices
with one interface which we of course own. with just one interface, which we of course own.
*/ */
//FIXME: needs locking against config changes //FIXME: needs locking against config changes
if ( us->pusb_dev->actconfig->desc.bNumInterfaces == 1) { if (us->pusb_dev->actconfig->desc.bNumInterfaces == 1) {
/* attempt to reset the port */
/* lock the device and attempt to reset the port */
down(&(us->dev_semaphore));
result = usb_reset_device(us->pusb_dev); result = usb_reset_device(us->pusb_dev);
up(&(us->dev_semaphore));
US_DEBUGP("usb_reset_device returns %d\n", result); US_DEBUGP("usb_reset_device returns %d\n", result);
} else { } else {
result = -EBUSY; result = -EBUSY;
US_DEBUGP("cannot reset a multiinterface device. failing to reset.\n"); US_DEBUGP("Refusing to reset a multi-interface device\n");
} }
US_DEBUGP("bus_reset() complete\n"); /* lock access to the state and clear it */
scsi_lock(srb->device->host); scsi_lock(srb->device->host);
atomic_set(&us->sm_state, US_STATE_IDLE);
return result < 0 ? FAILED : SUCCESS; return result < 0 ? FAILED : SUCCESS;
} }
......
...@@ -875,11 +875,8 @@ int usb_stor_Bulk_max_lun(struct us_data *us) ...@@ -875,11 +875,8 @@ int usb_stor_Bulk_max_lun(struct us_data *us)
unsigned char data; unsigned char data;
int result; int result;
/* Issue the command -- use usb_control_msg() because this is /* issue the command */
* not a scsi queued-command. Also note that at this point the result = usb_stor_control_msg(us, us->recv_ctrl_pipe,
* cached pipe values have not yet been stored. */
result = usb_control_msg(us->pusb_dev,
usb_rcvctrlpipe(us->pusb_dev, 0),
US_BULK_GET_MAX_LUN, US_BULK_GET_MAX_LUN,
USB_DIR_IN | USB_TYPE_CLASS | USB_DIR_IN | USB_TYPE_CLASS |
USB_RECIP_INTERFACE, USB_RECIP_INTERFACE,
...@@ -1027,10 +1024,12 @@ static int usb_stor_reset_common(struct us_data *us, ...@@ -1027,10 +1024,12 @@ static int usb_stor_reset_common(struct us_data *us,
return FAILED; return FAILED;
} }
/* long wait for reset */ /* long wait for reset, so unlock to allow disconnects */
up(&us->dev_semaphore);
set_current_state(TASK_UNINTERRUPTIBLE); set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ*6); schedule_timeout(HZ*6);
set_current_state(TASK_RUNNING); set_current_state(TASK_RUNNING);
down(&us->dev_semaphore);
US_DEBUGP("Soft reset: clearing bulk-in endpoint halt\n"); US_DEBUGP("Soft reset: clearing bulk-in endpoint halt\n");
result = usb_stor_clear_halt(us, us->recv_bulk_pipe); result = usb_stor_clear_halt(us, us->recv_bulk_pipe);
......
...@@ -412,9 +412,11 @@ static int usb_stor_control_thread(void * __us) ...@@ -412,9 +412,11 @@ static int usb_stor_control_thread(void * __us)
US_DEBUGP("scsi command aborted\n"); US_DEBUGP("scsi command aborted\n");
} }
/* in case an abort request was received after the command /* If an abort request was received we need to signal that
* completed, we must use a separate test to see whether * the abort has finished. The proper test for this is
* we need to signal that the abort has finished */ * sm_state == US_STATE_ABORTING, not srb->result == DID_ABORT,
* because an abort request might be received after all the
* USB processing was complete. */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) if (atomic_read(&us->sm_state) == US_STATE_ABORTING)
complete(&(us->notify)); complete(&(us->notify));
...@@ -715,7 +717,6 @@ static int storage_probe(struct usb_interface *intf, ...@@ -715,7 +717,6 @@ static int storage_probe(struct usb_interface *intf,
us->transport_name = "Bulk"; us->transport_name = "Bulk";
us->transport = usb_stor_Bulk_transport; us->transport = usb_stor_Bulk_transport;
us->transport_reset = usb_stor_Bulk_reset; us->transport_reset = usb_stor_Bulk_reset;
us->max_lun = usb_stor_Bulk_max_lun(us);
break; break;
#ifdef CONFIG_USB_STORAGE_HP8200e #ifdef CONFIG_USB_STORAGE_HP8200e
...@@ -842,6 +843,10 @@ static int storage_probe(struct usb_interface *intf, ...@@ -842,6 +843,10 @@ static int storage_probe(struct usb_interface *intf,
if (usb_stor_allocate_urbs(us)) if (usb_stor_allocate_urbs(us))
goto BadDevice; goto BadDevice;
/* For bulk-only devices, determine the max LUN value */
if (us->protocol == US_PR_BULK)
us->max_lun = usb_stor_Bulk_max_lun(us);
/* /*
* Since this is a new device, we need to generate a scsi * Since this is a new device, we need to generate a scsi
* host definition, and register with the higher SCSI layers * host definition, and register with the higher SCSI layers
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment