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

[PATCH] usb-storage: move to SCSI hotplugging

The attached patch is my first implementation of SCSI hotplugging.

It's only been tested that it compiles, as I can't get the current
linux-2.5 tree from linuxusb to boot.  It dies _very_ early.  Greg, I'm not
sure if you'll want to apply this.  Linus seemed to want this very much,
and it is 2.5.x... I say go for it, but I can understand if you have
reservations.

I would definately like to see this tested by anyone who can get a kernel
to boot.

This patch is quite large.  Lots of things had to be changed.  Among them:

(o) The proc interface now uses the host number to look up the SCSI host
    structure, and then finds the usb-storage structure from that.
(o) The SCSI interface has been changed.  The code flow is now much
    clearer, as more work is done from the USB probe/detach functions than
    from auxillary functions.
(o) Names have been changed for newer conventions
(o) GUIDs have been removed
(o) The linked-list of devices has been removed, and it's associated
    semaphore
(o) All code dealing with re-attaching a device to it's old association has
    been removed
(o) Some spaces changed to tabs
(o) usb-storage now takes one directory under /proc/scsi instead of
    one per virtual-HBA
(o) All control threads now have the same name.  This could be changed back
    to the old behavior, if enough people want it.

Known problems:
(o) Testing, testing, testing
(o) More dead code needs to be cut
(o) It's a unclear how a LLD is supposed to cut off the flow of
    commands, so that the unregister() call always succeeds.  SCSI folks
    need to work on this.
(o) Probing needs to be broken down into smaller functions, probably.
parent 6a4f58ed
...@@ -50,23 +50,25 @@ ...@@ -50,23 +50,25 @@
#include "transport.h" #include "transport.h"
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/module.h>
/*********************************************************************** /***********************************************************************
* Host functions * Host functions
***********************************************************************/ ***********************************************************************/
static const char* host_info(struct Scsi_Host *host) static const char* usb_storage_info(struct Scsi_Host *host)
{ {
return "SCSI emulation for USB Mass Storage devices"; return "SCSI emulation for USB Mass Storage devices";
} }
#if 0
/* detect a virtual adapter (always works) /* detect a virtual adapter (always works)
* Synchronization: 2.4: with the io_request_lock * Synchronization: 2.4: with the io_request_lock
* 2.5: no locks. * 2.5: no locks.
* fortunately we don't care. * fortunately we don't care.
* */ * */
static int detect(struct SHT *sht) static int usb_storage_detect(struct SHT *sht)
{ {
struct us_data *us; struct us_data *us;
char local_name[32]; char local_name[32];
...@@ -109,7 +111,7 @@ static int detect(struct SHT *sht) ...@@ -109,7 +111,7 @@ static int detect(struct SHT *sht)
* the driver and we're doing each virtual host in turn, not in parallel * the driver and we're doing each virtual host in turn, not in parallel
* Synchronization: BKL, no spinlock. * Synchronization: BKL, no spinlock.
*/ */
static int release(struct Scsi_Host *psh) static int usb_storage_release(struct Scsi_Host *psh)
{ {
struct us_data *us = (struct us_data *)psh->hostdata[0]; struct us_data *us = (struct us_data *)psh->hostdata[0];
...@@ -132,18 +134,11 @@ static int release(struct Scsi_Host *psh) ...@@ -132,18 +134,11 @@ static int release(struct Scsi_Host *psh)
/* we always have a successful release */ /* we always have a successful release */
return 0; return 0;
} }
#endif
/* run command */
static int command( Scsi_Cmnd *srb )
{
US_DEBUGP("Bad use of us_command\n");
return DID_BAD_TARGET << 16;
}
/* queue a command */ /* queue a command */
/* This is always called with scsi_lock(srb->host) held */ /* This is always called with scsi_lock(srb->host) held */
static int queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *)) static int usb_storage_queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *))
{ {
struct us_data *us = (struct us_data *)srb->host->hostdata[0]; struct us_data *us = (struct us_data *)srb->host->hostdata[0];
...@@ -168,7 +163,7 @@ static int queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *)) ...@@ -168,7 +163,7 @@ static int queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *))
/* Command abort */ /* Command abort */
/* This is always called with scsi_lock(srb->host) held */ /* This is always called with scsi_lock(srb->host) held */
static int command_abort( Scsi_Cmnd *srb ) static int usb_storage_command_abort( Scsi_Cmnd *srb )
{ {
struct us_data *us = (struct us_data *)srb->host->hostdata[0]; struct us_data *us = (struct us_data *)srb->host->hostdata[0];
...@@ -187,7 +182,7 @@ static int command_abort( Scsi_Cmnd *srb ) ...@@ -187,7 +182,7 @@ static int command_abort( Scsi_Cmnd *srb )
/* This invokes the transport reset mechanism to reset the state of the /* This invokes the transport reset mechanism to reset the state of the
* device */ * device */
/* This is always called with scsi_lock(srb->host) held */ /* This is always called with scsi_lock(srb->host) held */
static int device_reset( Scsi_Cmnd *srb ) static int usb_storage_device_reset( Scsi_Cmnd *srb )
{ {
struct us_data *us = (struct us_data *)srb->host->hostdata[0]; struct us_data *us = (struct us_data *)srb->host->hostdata[0];
int result; int result;
...@@ -219,7 +214,7 @@ static int device_reset( Scsi_Cmnd *srb ) ...@@ -219,7 +214,7 @@ static int device_reset( Scsi_Cmnd *srb )
* disconnect/reconnect for all drivers which have claimed * disconnect/reconnect for all drivers which have claimed
* interfaces, including ourself. */ * interfaces, including ourself. */
/* This is always called with scsi_lock(srb->host) held */ /* This is always called with scsi_lock(srb->host) held */
static int bus_reset( Scsi_Cmnd *srb ) static int usb_storage_bus_reset( Scsi_Cmnd *srb )
{ {
struct us_data *us = (struct us_data *)srb->host->hostdata[0]; struct us_data *us = (struct us_data *)srb->host->hostdata[0];
int i; int i;
...@@ -274,14 +269,6 @@ static int bus_reset( Scsi_Cmnd *srb ) ...@@ -274,14 +269,6 @@ static int bus_reset( Scsi_Cmnd *srb )
return SUCCESS; return SUCCESS;
} }
/* FIXME: This doesn't do anything right now */
static int host_reset( Scsi_Cmnd *srb )
{
printk(KERN_CRIT "usb-storage: host_reset() requested but not implemented\n" );
bus_reset(srb);
return FAILED;
}
/*********************************************************************** /***********************************************************************
* /proc/scsi/ functions * /proc/scsi/ functions
***********************************************************************/ ***********************************************************************/
...@@ -291,29 +278,24 @@ static int host_reset( Scsi_Cmnd *srb ) ...@@ -291,29 +278,24 @@ static int host_reset( Scsi_Cmnd *srb )
#define SPRINTF(args...) \ #define SPRINTF(args...) \
do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0) do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0)
static int proc_info (char *buffer, char **start, off_t offset, int length, static int usb_storage_proc_info (char *buffer, char **start, off_t offset,
int hostno, int inout) int length, int hostno, int inout)
{ {
struct us_data *us; struct us_data *us;
char *pos = buffer; char *pos = buffer;
struct Scsi_Host *hostptr;
/* if someone is sending us data, just throw it away */ /* if someone is sending us data, just throw it away */
if (inout) if (inout)
return length; return length;
/* lock the data structures */ /* find our data from the given hostno */
down(&us_list_semaphore); hostptr = scsi_host_hn_get(hostno);
if (!hostptr) { /* if we couldn't find it, we return an error */
/* find our data from hostno */ return -ESRCH;
us = us_list;
while (us) {
if (us->host_no == hostno)
break;
us = us->next;
} }
us = (struct us_data*)hostptr->hostdata[0];
/* release our lock on the data structures */ scsi_host_put(hostptr);
up(&us_list_semaphore);
/* if we couldn't find it, we return an error */ /* if we couldn't find it, we return an error */
if (!us) { if (!us) {
...@@ -332,8 +314,7 @@ static int proc_info (char *buffer, char **start, off_t offset, int length, ...@@ -332,8 +314,7 @@ static int proc_info (char *buffer, char **start, off_t offset, int length,
SPRINTF(" Protocol: %s\n", us->protocol_name); SPRINTF(" Protocol: %s\n", us->protocol_name);
SPRINTF(" Transport: %s\n", us->transport_name); SPRINTF(" Transport: %s\n", us->transport_name);
/* show the GUID of the device */ /* show attached status of the device */
SPRINTF(" GUID: " GUID_FORMAT "\n", GUID_ARGS(us->guid));
SPRINTF(" Attached: %s\n", (us->flags & US_FL_DEV_ATTACHED ? SPRINTF(" Attached: %s\n", (us->flags & US_FL_DEV_ATTACHED ?
"Yes" : "No")); "Yes" : "No"));
...@@ -351,33 +332,69 @@ static int proc_info (char *buffer, char **start, off_t offset, int length, ...@@ -351,33 +332,69 @@ static int proc_info (char *buffer, char **start, off_t offset, int length,
} }
/* /*
* this defines our 'host' * this defines our host template, with which we'll allocate hosts
*/ */
Scsi_Host_Template usb_stor_host_template = { struct SHT usb_stor_host_template = {
.name = "usb-storage", /* basic userland interface stuff */
.proc_info = proc_info, .name = "usb-storage",
.info = host_info, .proc_name = "usb-storage",
.proc_info = usb_storage_proc_info,
.detect = detect, .proc_dir = NULL,
.release = release, .info = usb_storage_info,
.command = command, .ioctl = NULL,
.queuecommand = queuecommand,
/* old-style detect and release */
.eh_abort_handler = command_abort, .detect = NULL,
.eh_device_reset_handler =device_reset, .release = NULL,
.eh_bus_reset_handler = bus_reset,
.eh_host_reset_handler =host_reset, /* command interface -- queued only */
.command = NULL,
.can_queue = 1, .queuecommand = usb_storage_queuecommand,
.this_id = -1,
/* error and abort handlers */
.sg_tablesize = SG_ALL, .eh_abort_handler = usb_storage_command_abort,
.cmd_per_lun = 1, .eh_device_reset_handler = usb_storage_device_reset,
.present = 0, .eh_bus_reset_handler = usb_storage_bus_reset,
.unchecked_isa_dma = FALSE, .eh_host_reset_handler = NULL,
.use_clustering = TRUE, .eh_strategy_handler = NULL,
.emulated = TRUE
/* queue commands only, only one command per LUN */
.can_queue = 1,
.cmd_per_lun = 1,
/* unknown initiator id */
.this_id = -1,
/* no limit on commands */
.max_sectors = 0,
/* pre- and post- device scan functions */
.slave_alloc = NULL,
.slave_configure = NULL,
.slave_destroy = NULL,
/* lots of sg segments can be handled */
.sg_tablesize = SG_ALL,
/* use 32-bit address space for DMA */
.unchecked_isa_dma = FALSE,
.highmem_io = FALSE,
/* merge commands... this seems to help performance, but
* periodically someone should test to see which setting is more
* optimal.
*/
.use_clustering = TRUE,
/* emulated HBA */
.emulated = TRUE,
/* sorry, no BIOS to help us */
.bios_param = NULL,
/* module management */
.module = THIS_MODULE
}; };
/* For a device that is "Not Ready" */ /* For a device that is "Not Ready" */
......
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
extern unsigned char usb_stor_sense_notready[18]; extern unsigned char usb_stor_sense_notready[18];
extern unsigned char usb_stor_sense_invalidCDB[18]; extern unsigned char usb_stor_sense_invalidCDB[18];
extern Scsi_Host_Template usb_stor_host_template; extern struct SHT usb_stor_host_template;
extern int usb_stor_scsiSense10to6(Scsi_Cmnd*); extern int usb_stor_scsiSense10to6(Scsi_Cmnd*);
extern int usb_stor_scsiSense6to10(Scsi_Cmnd*); extern int usb_stor_scsiSense6to10(Scsi_Cmnd*);
......
This diff is collapsed.
...@@ -52,33 +52,6 @@ ...@@ -52,33 +52,6 @@
#include "scsi.h" #include "scsi.h"
#include "hosts.h" #include "hosts.h"
/*
* GUID definitions
*/
#define GUID(x) __u32 x[3]
#define GUID_EQUAL(x, y) (x[0] == y[0] && x[1] == y[1] && x[2] == y[2])
#define GUID_CLEAR(x) x[0] = x[1] = x[2] = 0;
#define GUID_NONE(x) (!x[0] && !x[1] && !x[2])
#define GUID_FORMAT "%08x%08x%08x"
#define GUID_ARGS(x) x[0], x[1], x[2]
static inline void make_guid( __u32 *pg, __u16 vendor, __u16 product, char *serial)
{
pg[0] = (vendor << 16) | product;
pg[1] = pg[2] = 0;
while (*serial) {
pg[1] <<= 4;
pg[1] |= pg[2] >> 28;
pg[2] <<= 4;
if (*serial >= 'a')
*serial -= 'a' - 'A';
pg[2] |= (*serial <= '9' && *serial >= '0') ? *serial - '0'
: *serial - 'A' + 10;
serial++;
}
}
struct us_data; struct us_data;
/* /*
...@@ -124,8 +97,6 @@ typedef void (*extra_data_destructor)(void *); /* extra data destructor */ ...@@ -124,8 +97,6 @@ typedef void (*extra_data_destructor)(void *); /* extra data destructor */
/* we allocate one of these for every device that we remember */ /* we allocate one of these for every device that we remember */
struct us_data { struct us_data {
struct us_data *next; /* next device */
/* The device we're working with /* The device we're working with
* It's important to note: * It's important to note:
* (o) you must hold dev_semaphore to change pusb_dev * (o) you must hold dev_semaphore to change pusb_dev
...@@ -163,11 +134,7 @@ struct us_data { ...@@ -163,11 +134,7 @@ struct us_data {
proto_cmnd proto_handler; /* protocol handler */ proto_cmnd proto_handler; /* protocol handler */
/* SCSI interfaces */ /* SCSI interfaces */
GUID(guid); /* unique dev id */
struct Scsi_Host *host; /* our dummy host data */ struct Scsi_Host *host; /* our dummy host data */
Scsi_Host_Template htmplt; /* own host template */
int host_number; /* to find us */
int host_no; /* allocated by scsi */
Scsi_Cmnd *srb; /* current srb */ Scsi_Cmnd *srb; /* current srb */
/* thread information */ /* thread information */
...@@ -192,10 +159,6 @@ struct us_data { ...@@ -192,10 +159,6 @@ struct us_data {
extra_data_destructor extra_destructor;/* extra data destructor */ extra_data_destructor extra_destructor;/* extra data destructor */
}; };
/* The list of structures and the protective lock for them */
extern struct us_data *us_list;
extern struct semaphore us_list_semaphore;
/* The structure which defines our driver */ /* The structure which defines our driver */
extern struct usb_driver usb_storage_driver; extern struct usb_driver usb_storage_driver;
......
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