2005-04-17 02:20:36 +04:00
/* Driver for USB Mass Storage compliant devices
* SCSI layer glue code
*
* $ Id : scsiglue . c , v 1.26 2002 / 04 / 22 03 : 39 : 43 mdharm Exp $
*
* Current development and maintenance by :
* ( c ) 1999 - 2002 Matthew Dharm ( mdharm - usb @ one - eyed - alien . net )
*
* Developed with the assistance of :
* ( c ) 2000 David L . Brown , Jr . ( usb - storage @ davidb . org )
* ( c ) 2000 Stephen J . Gowdy ( SGowdy @ lbl . gov )
*
* Initial work by :
* ( c ) 1999 Michael Gee ( michael @ linuxspecific . com )
*
* This driver is based on the ' USB Mass Storage Class ' document . This
* describes in detail the protocol used to communicate with such
* devices . Clearly , the designers had SCSI and ATAPI commands in
* mind when they created this document . The commands are all very
* similar to commands in the SCSI - II and ATAPI specifications .
*
* It is important to note that in a number of cases this class
* exhibits class - specific exemptions from the USB specification .
* Notably the usage of NAK , STALL and ACK differs from the norm , in
* that they are used to communicate wait , failed and OK on commands .
*
* Also , for certain devices , the interrupt endpoint is used to convey
* status of a command .
*
* Please see http : //www.one-eyed-alien.net/~mdharm/linux-usb for more
* information about this driver .
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation ; either version 2 , or ( at your option ) any
* later version .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
* 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include <linux/slab.h>
# include <linux/module.h>
2006-01-11 17:55:29 +03:00
# include <linux/mutex.h>
2005-04-17 02:20:36 +04:00
# include <scsi/scsi.h>
# include <scsi/scsi_cmnd.h>
# include <scsi/scsi_devinfo.h>
# include <scsi/scsi_device.h>
# include <scsi/scsi_eh.h>
# include "usb.h"
# include "scsiglue.h"
# include "debug.h"
# include "transport.h"
# include "protocol.h"
/***********************************************************************
* Host functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static const char * host_info ( struct Scsi_Host * host )
{
return " SCSI emulation for USB Mass Storage devices " ;
}
static int slave_alloc ( struct scsi_device * sdev )
{
2006-08-21 20:00:53 +04:00
struct us_data * us = host_to_us ( sdev - > host ) ;
2005-04-17 02:20:36 +04:00
/*
* 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
* less than 36 bytes .
*/
sdev - > inquiry_len = 36 ;
2006-08-21 20:00:53 +04:00
/*
* 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 = = US_SC_UFI )
sdev - > sdev_target - > pdt_1f_for_no_lun = 1 ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int slave_configure ( struct scsi_device * sdev )
{
struct us_data * us = host_to_us ( sdev - > host ) ;
/* Scatter-gather buffers (all but the last) must have a length
* divisible by the bulk maxpacket size . Otherwise a data packet
* would end up being short , causing a premature end to the data
* transfer . Since high - speed bulk pipes have a maxpacket size
* of 512 , we ' ll use that as the scsi device queue ' s DMA alignment
* mask . Guaranteeing proper alignment of the first buffer will
* have the desired effect because , except at the beginning and
* the end , scatter - gather buffers follow page boundaries . */
blk_queue_dma_alignment ( sdev - > request_queue , ( 512 - 1 ) ) ;
/* Set the SCSI level to at least 2. We'll leave it at 3 if that's
* what is originally reported . We need this to avoid confusing
* the SCSI layer with devices that report 0 or 1 , but need 10 - byte
* commands ( ala ATAPI devices behind certain bridges , or devices
* which simply have broken INQUIRY data ) .
*
* NOTE : This means / dev / sg programs ( ala cdrecord ) will get the
* actual information . This seems to be the preference for
* programs like that .
*
* NOTE : This also means that / proc / scsi / scsi and sysfs may report
* the actual value or the modified one , depending on where the
* data comes from .
*/
if ( sdev - > scsi_level < SCSI_2 )
2005-12-22 01:28:06 +03:00
sdev - > scsi_level = sdev - > sdev_target - > scsi_level = SCSI_2 ;
2005-04-17 02:20:36 +04:00
2006-06-25 04:27:10 +04:00
/* Many devices have trouble transfering more than 32KB at a time,
* while others have trouble with more than 64 K . At this time we
* are limiting both to 32 K ( 64 sectores ) .
*/
if ( ( us - > flags & US_FL_MAX_SECTORS_64 ) & &
2005-04-17 02:20:36 +04:00
sdev - > request_queue - > max_sectors > 64 )
blk_queue_max_sectors ( sdev - > request_queue , 64 ) ;
/* We can't put these settings in slave_alloc() because that gets
* called before the device type is known . Consequently these
* settings can ' t be overridden via the scsi devinfo mechanism . */
if ( sdev - > type = = TYPE_DISK ) {
/* Disk-type devices use MODE SENSE(6) if the protocol
* ( SubClass ) is Transparent SCSI , otherwise they use
* MODE SENSE ( 10 ) . */
if ( us - > subclass ! = US_SC_SCSI )
sdev - > use_10_for_ms = 1 ;
/* Many disks only accept MODE SENSE transfer lengths of
* 192 bytes ( that ' s what Windows uses ) . */
sdev - > use_192_bytes_for_3f = 1 ;
/* Some devices don't like MODE SENSE with page=0x3f,
* which is the command used for checking if a device
* is write - protected . Now that we tell the sd driver
* to do a 192 - byte transfer with this command the
* majority of devices work fine , but a few still can ' t
* handle it . The sd driver will simply assume those
* devices are write - enabled . */
if ( us - > flags & US_FL_NO_WP_DETECT )
sdev - > skip_ms_page_3f = 1 ;
/* A number of devices have problems with MODE SENSE for
* page x08 , so we will skip it . */
sdev - > skip_ms_page_8 = 1 ;
/* Some disks return the total number of blocks in response
* to READ CAPACITY rather than the highest block number .
* If this device makes that mistake , tell the sd driver . */
if ( us - > flags & US_FL_FIX_CAPACITY )
sdev - > fix_capacity = 1 ;
2005-06-07 04:22:42 +04:00
2005-07-29 01:50:29 +04:00
/* 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 . */
2005-12-22 01:28:06 +03:00
sdev - > scsi_level = sdev - > sdev_target - > scsi_level = SCSI_2 ;
2005-07-29 01:50:29 +04:00
2005-06-07 04:22:42 +04:00
/* USB-IDE bridges tend to report SK = 0x04 (Non-recoverable
* Hardware Error ) when any low - level error occurs ,
* recoverable or not . Setting this flag tells the SCSI
* midlayer to retry such commands , which frequently will
* succeed and fix the error . The worst this can lead to
* is an occasional series of retries that will all fail . */
sdev - > retry_hwerror = 1 ;
2005-04-17 02:20:36 +04:00
} else {
/* Non-disk-type devices don't need to blacklist any pages
* or to force 192 - byte transfer lengths for MODE SENSE .
* But they do need to use MODE SENSE ( 10 ) . */
sdev - > use_10_for_ms = 1 ;
}
/* Some devices choke when they receive a PREVENT-ALLOW MEDIUM
* REMOVAL command , so suppress those commands . */
if ( us - > flags & US_FL_NOT_LOCKABLE )
sdev - > lockable = 0 ;
/* this is to satisfy the compiler, tho I don't think the
* return code is ever checked anywhere . */
return 0 ;
}
/* queue a command */
/* This is always called with scsi_lock(host) held */
static int queuecommand ( struct scsi_cmnd * srb ,
void ( * done ) ( struct scsi_cmnd * ) )
{
struct us_data * us = host_to_us ( srb - > device - > host ) ;
US_DEBUGP ( " %s called \n " , __FUNCTION__ ) ;
/* check for state-transition errors */
if ( us - > srb ! = NULL ) {
printk ( KERN_ERR USB_STORAGE " Error in %s: us->srb = %p \n " ,
__FUNCTION__ , us - > srb ) ;
return SCSI_MLQUEUE_HOST_BUSY ;
}
/* fail the command if we are disconnecting */
if ( test_bit ( US_FLIDX_DISCONNECTING , & us - > flags ) ) {
US_DEBUGP ( " Fail command during disconnect \n " ) ;
srb - > result = DID_NO_CONNECT < < 16 ;
done ( srb ) ;
return 0 ;
}
/* enqueue the command and wake up the control thread */
srb - > scsi_done = done ;
us - > srb = srb ;
up ( & ( us - > sema ) ) ;
return 0 ;
}
/***********************************************************************
* Error handling functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* Command timeout and abort */
static int command_abort ( struct scsi_cmnd * srb )
{
struct us_data * us = host_to_us ( srb - > device - > host ) ;
US_DEBUGP ( " %s called \n " , __FUNCTION__ ) ;
2005-08-26 07:03:50 +04:00
/* us->srb together with the TIMED_OUT, RESETTING, and ABORTING
* bits are protected by the host lock . */
scsi_lock ( us_to_host ( us ) ) ;
2005-04-17 02:20:36 +04:00
/* Is this command still active? */
if ( us - > srb ! = srb ) {
2005-08-26 07:03:50 +04:00
scsi_unlock ( us_to_host ( us ) ) ;
2005-04-17 02:20:36 +04:00
US_DEBUGP ( " -- nothing to abort \n " ) ;
return FAILED ;
}
/* Set the TIMED_OUT bit. Also set the ABORTING bit, but only if
* a device reset isn ' t already in progress ( to avoid interfering
2005-08-26 07:03:50 +04:00
* with the reset ) . Note that we must retain the host lock while
* calling usb_stor_stop_transport ( ) ; otherwise it might interfere
* with an auto - reset that begins as soon as we release the lock . */
2005-04-17 02:20:36 +04:00
set_bit ( US_FLIDX_TIMED_OUT , & us - > flags ) ;
if ( ! test_bit ( US_FLIDX_RESETTING , & us - > flags ) ) {
set_bit ( US_FLIDX_ABORTING , & us - > flags ) ;
usb_stor_stop_transport ( us ) ;
}
2005-08-26 07:03:50 +04:00
scsi_unlock ( us_to_host ( us ) ) ;
2005-04-17 02:20:36 +04:00
/* Wait for the aborted command to finish */
wait_for_completion ( & us - > notify ) ;
return SUCCESS ;
}
/* This invokes the transport reset mechanism to reset the state of the
* device */
static int device_reset ( struct scsi_cmnd * srb )
{
struct us_data * us = host_to_us ( srb - > device - > host ) ;
int result ;
US_DEBUGP ( " %s called \n " , __FUNCTION__ ) ;
/* lock the device pointers and do the reset */
2006-01-11 17:55:29 +03:00
mutex_lock ( & ( us - > dev_mutex ) ) ;
2005-06-07 04:21:41 +04:00
result = us - > transport_reset ( us ) ;
2006-01-11 17:55:29 +03:00
mutex_unlock ( & us - > dev_mutex ) ;
2005-04-17 02:20:36 +04:00
2005-06-07 04:21:41 +04:00
return result < 0 ? FAILED : SUCCESS ;
2005-04-17 02:20:36 +04:00
}
2005-06-07 04:21:41 +04:00
/* Simulate a SCSI bus reset by resetting the device's USB port. */
2005-04-17 02:20:36 +04:00
static int bus_reset ( struct scsi_cmnd * srb )
{
struct us_data * us = host_to_us ( srb - > device - > host ) ;
2005-06-07 04:21:41 +04:00
int result ;
2005-04-17 02:20:36 +04:00
US_DEBUGP ( " %s called \n " , __FUNCTION__ ) ;
2005-06-07 04:21:41 +04:00
result = usb_stor_port_reset ( us ) ;
2005-04-17 02:20:36 +04:00
return result < 0 ? FAILED : SUCCESS ;
}
/* Report a driver-initiated device reset to the SCSI layer.
* Calling this for a SCSI - initiated reset is unnecessary but harmless .
* The caller must own the SCSI host lock . */
void usb_stor_report_device_reset ( struct us_data * us )
{
int i ;
struct Scsi_Host * host = us_to_host ( us ) ;
scsi_report_device_reset ( host , 0 , 0 ) ;
if ( us - > flags & US_FL_SCM_MULT_TARG ) {
for ( i = 1 ; i < host - > max_id ; + + i )
scsi_report_device_reset ( host , 0 , i ) ;
}
}
2005-06-07 04:21:41 +04:00
/* Report a driver-initiated bus reset to the SCSI layer.
* Calling this for a SCSI - initiated reset is unnecessary but harmless .
* The caller must own the SCSI host lock . */
void usb_stor_report_bus_reset ( struct us_data * us )
{
scsi_report_bus_reset ( us_to_host ( us ) , 0 ) ;
}
2005-04-17 02:20:36 +04:00
/***********************************************************************
* / proc / scsi / functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* we use this macro to help us write into the buffer */
# undef SPRINTF
# define SPRINTF(args...) \
do { if ( pos < buffer + length ) pos + = sprintf ( pos , # # args ) ; } while ( 0 )
static int proc_info ( struct Scsi_Host * host , char * buffer ,
char * * start , off_t offset , int length , int inout )
{
struct us_data * us = host_to_us ( host ) ;
char * pos = buffer ;
const char * string ;
/* if someone is sending us data, just throw it away */
if ( inout )
return length ;
/* print the controller name */
SPRINTF ( " Host scsi%d: usb-storage \n " , host - > host_no ) ;
/* print product, vendor, and serial number strings */
if ( us - > pusb_dev - > manufacturer )
string = us - > pusb_dev - > manufacturer ;
else if ( us - > unusual_dev - > vendorName )
string = us - > unusual_dev - > vendorName ;
else
string = " Unknown " ;
SPRINTF ( " Vendor: %s \n " , string ) ;
if ( us - > pusb_dev - > product )
string = us - > pusb_dev - > product ;
else if ( us - > unusual_dev - > productName )
string = us - > unusual_dev - > productName ;
else
string = " Unknown " ;
SPRINTF ( " Product: %s \n " , string ) ;
if ( us - > pusb_dev - > serial )
string = us - > pusb_dev - > serial ;
else
string = " None " ;
SPRINTF ( " Serial Number: %s \n " , string ) ;
/* show the protocol and transport */
SPRINTF ( " Protocol: %s \n " , us - > protocol_name ) ;
SPRINTF ( " Transport: %s \n " , us - > transport_name ) ;
/* show the device flags */
if ( pos < buffer + length ) {
pos + = sprintf ( pos , " Quirks: " ) ;
# define US_FLAG(name, value) \
if ( us - > flags & value ) pos + = sprintf ( pos , " " # name ) ;
US_DO_ALL_FLAGS
# undef US_FLAG
* ( pos + + ) = ' \n ' ;
}
/*
* Calculate start of next buffer , and return value .
*/
* start = buffer + offset ;
if ( ( pos - buffer ) < offset )
return ( 0 ) ;
else if ( ( pos - buffer - offset ) < length )
return ( pos - buffer - offset ) ;
else
return ( length ) ;
}
/***********************************************************************
* Sysfs interface
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* Output routine for the sysfs max_sectors file */
2005-05-17 14:44:04 +04:00
static ssize_t show_max_sectors ( struct device * dev , struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
struct scsi_device * sdev = to_scsi_device ( dev ) ;
return sprintf ( buf , " %u \n " , sdev - > request_queue - > max_sectors ) ;
}
/* Input routine for the sysfs max_sectors file */
2005-05-17 14:44:04 +04:00
static ssize_t store_max_sectors ( struct device * dev , struct device_attribute * attr , const char * buf ,
2005-04-17 02:20:36 +04:00
size_t count )
{
struct scsi_device * sdev = to_scsi_device ( dev ) ;
unsigned short ms ;
if ( sscanf ( buf , " %hu " , & ms ) > 0 & & ms < = SCSI_DEFAULT_MAX_SECTORS ) {
blk_queue_max_sectors ( sdev - > request_queue , ms ) ;
return strlen ( buf ) ;
}
return - EINVAL ;
}
static DEVICE_ATTR ( max_sectors , S_IRUGO | S_IWUSR , show_max_sectors ,
store_max_sectors ) ;
static struct device_attribute * sysfs_device_attr_list [ ] = {
& dev_attr_max_sectors ,
NULL ,
} ;
/*
* this defines our host template , with which we ' ll allocate hosts
*/
struct scsi_host_template usb_stor_host_template = {
/* basic userland interface stuff */
. name = " usb-storage " ,
. proc_name = " usb-storage " ,
. proc_info = proc_info ,
. info = host_info ,
/* command interface -- queued only */
. queuecommand = queuecommand ,
/* error and abort handlers */
. eh_abort_handler = command_abort ,
. eh_device_reset_handler = device_reset ,
. eh_bus_reset_handler = bus_reset ,
/* queue commands only, only one command per LUN */
. can_queue = 1 ,
. cmd_per_lun = 1 ,
/* unknown initiator id */
. this_id = - 1 ,
. slave_alloc = slave_alloc ,
. slave_configure = slave_configure ,
/* lots of sg segments can be handled */
. sg_tablesize = SG_ALL ,
/* limit the total size of a transfer to 120 KB */
. max_sectors = 240 ,
/* merge commands... this seems to help performance, but
* periodically someone should test to see which setting is more
* optimal .
*/
. use_clustering = 1 ,
/* emulated HBA */
. emulated = 1 ,
/* we do our own delay after a device or bus reset */
. skip_settle_delay = 1 ,
/* sysfs device attributes */
. sdev_attrs = sysfs_device_attr_list ,
/* module management */
. module = THIS_MODULE
} ;
/* To Report "Illegal Request: Invalid Field in CDB */
unsigned char usb_stor_sense_invalidCDB [ 18 ] = {
[ 0 ] = 0x70 , /* current error */
[ 2 ] = ILLEGAL_REQUEST , /* Illegal Request = 0x05 */
[ 7 ] = 0x0a , /* additional length */
[ 12 ] = 0x24 /* Invalid Field in CDB */
} ;