Hi Matt, I've just added both sets of patches to CVS. regards,
Stephen. [antonia] ~/unix/linux-usb/storage > patch -p4 <~/temp patching file scsiglue.c Hunk #1 succeeded at 4 with fuzz 1. patching file transport.c patching file usb.c patching file usb.h Hunk #1 succeeded at 4 with fuzz 1. [antonia] ~/unix/linux-usb/storage > patch -p4 < ~/temp patching file debug.h On Sat, 25 May 2002, Matthew Dharm wrote: > So, my first BK patch. Once you figure out these tools, it's really not > that bad... but the problem is the initial learning curve and the high > shoot-yourself-in-the-foot potential. > > Greg, this won't compile without the next changeset (which I'm about to > send). I figured that sending this via e-mail was going to be better than > attempting a 'bk push' (will that even work)? This is based on a clone of > your usb-2.5 tree... and I'm not even sure that's the right starting point. > > What will happen if I try to 'bk push' this back to linuxusb.bitmover.net? > Will it even let me do that? I don't want to try it without some feedback > telling me it's okay, as I don't want to risk messing up a remote > repository -- I've already had to wipe and start over with my local > repositories a few times.... > > This material is _not_ in the CVS repository. It would be nice if someone > would update CVS apropriately. > > Matt > > # This is a BitKeeper generated patch for the following project: > # Project Name: greg k-h's linux 2.5 USB kernel tree > # This patch format is intended for GNU patch command version 2.5 or higher. > # This patch includes the following deltas: > # ChangeSet 1.561 -> 1.562 > # drivers/usb/storage/scsiglue.c 1.11 -> 1.12 > # drivers/usb/storage/transport.c 1.17 -> 1.18 > # drivers/usb/storage/usb.h 1.5 -> 1.6 > # drivers/usb/storage/usb.c 1.16 -> 1.17 > # > # The following is the BitKeeper ChangeSet Log > # -------------------------------------------- > # 02/05/25 [EMAIL PROTECTED] 1.562 > # Cleanup of abort mechanism. This version should be much more crash resistant >(dare I say crash-proof?) > # -------------------------------------------- > # > diff -Nru a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c > --- a/drivers/usb/storage/scsiglue.c Sat May 25 17:30:49 2002 > +++ b/drivers/usb/storage/scsiglue.c Sat May 25 17:30:49 2002 > @@ -4,7 +4,7 @@ > * $Id: scsiglue.c,v 1.26 2002/04/22 03:39:43 mdharm Exp $ > * > * Current development and maintenance by: > - * (c) 1999, 2000 Matthew Dharm ([EMAIL PROTECTED]) > + * (c) 1999-2002 Matthew Dharm ([EMAIL PROTECTED]) > * > * Developed with the assistance of: > * (c) 2000 David L. Brown, Jr. ([EMAIL PROTECTED]) > @@ -56,9 +56,6 @@ > */ > > #define US_ACT_COMMAND 1 > -#define US_ACT_DEVICE_RESET 2 > -#define US_ACT_BUS_RESET 3 > -#define US_ACT_HOST_RESET 4 > #define US_ACT_EXIT 5 > > /*********************************************************************** > diff -Nru a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c > --- a/drivers/usb/storage/transport.c Sat May 25 17:30:49 2002 > +++ b/drivers/usb/storage/transport.c Sat May 25 17:30:49 2002 > @@ -351,6 +351,29 @@ > * Data transfer routines > ***********************************************************************/ > > +/* > + * This is subtle, so pay attention: > + * --------------------------------- > + * We're very concered about races with a command abort. Hanging this code is > + * a sure fire way to hang the kernel. > + * > + * The abort function first sets the machine state, then tries to acquire the > + * lock on the current_urb to abort it. > + * > + * Once a function grabs the current_urb_sem, then it -MUST- test the state to > + * see if we just got aborted before the lock was grabbed. If so, it's > + * essential to release the lock and return. > + * > + * The idea is that, once the current_urb_sem is held, the state can't really > + * change anymore without also engaging the usb_unlink_urb() call _after_ the > + * URB is actually submitted. > + * > + * So, we've guaranteed that (after the sm_state test), if we do submit the > + * URB it will get aborted when we release the current_urb_sem. And we've > + * also guaranteed that if the abort code was called before we held the > + * current_urb_sem, we can safely get out before the URB is submitted. > + */ > + > /* This is the completion handler which will wake us up when an URB > * completes. > */ > @@ -363,6 +386,9 @@ > > /* This is the common part of the URB message submission code > * This function expects the current_urb_sem to be held upon entry. > + * > + * All URBs from the usb-storage driver _must_ pass through this function > + * (or something like it) for the abort mechanisms to work properly. > */ > static int usb_stor_msg_common(struct us_data *us) > { > @@ -385,16 +411,6 @@ > return status; > } > > - /* has the current command been aborted? */ > - if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { > - > - /* avoid a race with usb_stor_abort_transport(): > - * if the abort took place before we submitted > - * the URB, we must cancel it ourselves */ > - if (us->current_urb->status == -EINPROGRESS) > - usb_unlink_urb(us->current_urb); > - } > - > /* wait for the completion of the URB */ > up(&(us->current_urb_sem)); > wait_for_completion(&urb_done); > @@ -428,6 +444,12 @@ > /* lock the URB */ > down(&(us->current_urb_sem)); > > + /* has the current command been aborted? */ > + if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { > + up(&(us->current_urb_sem)); > + return 0; > + } > + > /* fill the URB */ > FILL_CONTROL_URB(us->current_urb, us->pusb_dev, pipe, > (unsigned char*) &dr, data, size, > @@ -456,6 +478,12 @@ > /* lock the URB */ > down(&(us->current_urb_sem)); > > + /* has the current command been aborted? */ > + if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { > + up(&(us->current_urb_sem)); > + return 0; > + } > + > /* fill the URB */ > FILL_BULK_URB(us->current_urb, us->pusb_dev, pipe, data, len, > usb_stor_blocking_completion, NULL); > @@ -823,24 +851,31 @@ > > /* If the current state is wrong or if there's > * no srb, then there's nothing to do */ > - if ( !(state == US_STATE_RUNNING || state == US_STATE_RESETTING) > - || !us->srb) { > - US_DEBUGP("-- invalid current state\n"); > - return; > - } > + ASSERT((state == US_STATE_RUNNING || state == US_STATE_RESETTING)); > + ASSERT(us->srb); > + > + /* set state to abort */ > atomic_set(&us->sm_state, US_STATE_ABORTING); > > /* If the state machine is blocked waiting for an URB or an IRQ, > - * let's wake it up */ > + * let's wake it up */ > > - /* if we have an URB pending, cancel it */ > + /* If we have an URB pending, cancel it. Note that we guarantee with > + * the current_urb_sem that either (a) an URB has just been submitted, > + * or (b) the URB will never get submitted. But, because of the use > + * of us->sm_state and current_urb_sem, we can't get an URB sumbitted > + * _after_ we set the state to US_STATE_ABORTING and this section of > + * code runs. Thus we avoid deadlocks. > + */ > + down(&(us->current_urb_sem)); > if (us->current_urb->status == -EINPROGRESS) { > US_DEBUGP("-- cancelling URB\n"); > usb_unlink_urb(us->current_urb); > } > + up(&(us->current_urb_sem)); > > - /* if we are waiting for an IRQ, simulate it */ > - else if (test_bit(IP_WANTED, &us->bitflags)) { > + /* If we are waiting for an IRQ, simulate it */ > + if (test_bit(IP_WANTED, &us->bitflags)) { > US_DEBUGP("-- simulating missing IRQ\n"); > usb_stor_CBI_irq(us->irq_urb); > } > diff -Nru a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c > --- a/drivers/usb/storage/usb.c Sat May 25 17:30:49 2002 > +++ b/drivers/usb/storage/usb.c Sat May 25 17:30:49 2002 > @@ -102,9 +102,6 @@ > */ > > #define US_ACT_COMMAND 1 > -#define US_ACT_DEVICE_RESET 2 > -#define US_ACT_BUS_RESET 3 > -#define US_ACT_HOST_RESET 4 > #define US_ACT_EXIT 5 > > /* The list of structures and the protective lock for them */ > @@ -341,10 +338,12 @@ > for(;;) { > struct Scsi_Host *host; > US_DEBUGP("*** thread sleeping.\n"); > + atomic_set(&us->sm_state, US_STATE_IDLE); > if(down_interruptible(&us->sema)) > break; > > US_DEBUGP("*** thread awakened.\n"); > + atomic_set(&us->sm_state, US_STATE_RUNNING); > > /* lock access to the queue element */ > spin_lock_irq(&us->queue_exclusion); > @@ -358,145 +357,131 @@ > /* release the queue lock as fast as possible */ > spin_unlock_irq(&us->queue_exclusion); > > - switch (action) { > - case US_ACT_COMMAND: > - /* reject the command if the direction indicator > - * is UNKNOWN > - */ > - if (us->srb->sc_data_direction == SCSI_DATA_UNKNOWN) { > - US_DEBUGP("UNKNOWN data direction\n"); > - us->srb->result = DID_ERROR << 16; > - scsi_lock(host); > - us->srb->scsi_done(us->srb); > - us->srb = NULL; > - scsi_unlock(host); > - break; > - } > + /* exit if we get a signal to exit */ > + if (action == US_ACT_EXIT) { > + US_DEBUGP("-- US_ACT_EXIT command received\n"); > + break; > + } > > - /* reject if target != 0 or if LUN is higher than > - * the maximum known LUN > - */ > - if (us->srb->target && > - !(us->flags & US_FL_SCM_MULT_TARG)) { > - US_DEBUGP("Bad target number (%d/%d)\n", > - us->srb->target, us->srb->lun); > - us->srb->result = DID_BAD_TARGET << 16; > - > - scsi_lock(host); > - us->srb->scsi_done(us->srb); > - us->srb = NULL; > - scsi_unlock(host); > - break; > - } > + ASSERT (action == US_ACT_COMMAND); > > - if (us->srb->lun > us->max_lun) { > - US_DEBUGP("Bad LUN (%d/%d)\n", > - us->srb->target, us->srb->lun); > - us->srb->result = DID_BAD_TARGET << 16; > - > - scsi_lock(host); > - us->srb->scsi_done(us->srb); > - us->srb = NULL; > - scsi_unlock(host); > - break; > - } > - > - /* handle those devices which can't do a START_STOP */ > - if ((us->srb->cmnd[0] == START_STOP) && > - (us->flags & US_FL_START_STOP)) { > - US_DEBUGP("Skipping START_STOP command\n"); > - us->srb->result = GOOD << 1; > + /* reject the command if the direction indicator > + * is UNKNOWN > + */ > + if (us->srb->sc_data_direction == SCSI_DATA_UNKNOWN) { > + US_DEBUGP("UNKNOWN data direction\n"); > + us->srb->result = DID_ERROR << 16; > + scsi_lock(host); > + us->srb->scsi_done(us->srb); > + us->srb = NULL; > + scsi_unlock(host); > + continue; > + } > > - scsi_lock(host); > - us->srb->scsi_done(us->srb); > - us->srb = NULL; > - scsi_unlock(host); > - break; > - } > + /* reject if target != 0 or if LUN is higher than > + * the maximum known LUN > + */ > + if (us->srb->target && > + !(us->flags & US_FL_SCM_MULT_TARG)) { > + US_DEBUGP("Bad target number (%d/%d)\n", > + us->srb->target, us->srb->lun); > + us->srb->result = DID_BAD_TARGET << 16; > + > + scsi_lock(host); > + us->srb->scsi_done(us->srb); > + us->srb = NULL; > + scsi_unlock(host); > + continue; > + } > + > + if (us->srb->lun > us->max_lun) { > + US_DEBUGP("Bad LUN (%d/%d)\n", > + us->srb->target, us->srb->lun); > + us->srb->result = DID_BAD_TARGET << 16; > + > + scsi_lock(host); > + us->srb->scsi_done(us->srb); > + us->srb = NULL; > + scsi_unlock(host); > + continue; > + } > + > + /* handle those devices which can't do a START_STOP */ > + if ((us->srb->cmnd[0] == START_STOP) && > + (us->flags & US_FL_START_STOP)) { > + US_DEBUGP("Skipping START_STOP command\n"); > + us->srb->result = GOOD << 1; > + > + scsi_lock(host); > + us->srb->scsi_done(us->srb); > + us->srb = NULL; > + scsi_unlock(host); > + continue; > + } > > - /* lock the device pointers */ > - down(&(us->dev_semaphore)); > + /* lock the device pointers */ > + down(&(us->dev_semaphore)); > > - /* our device has gone - pretend not ready */ > - if (atomic_read(&us->sm_state) == US_STATE_DETACHED) { > - US_DEBUGP("Request is for removed device\n"); > - /* For REQUEST_SENSE, it's the data. But > - * for anything else, it should look like > - * we auto-sensed for it. > - */ > - if (us->srb->cmnd[0] == REQUEST_SENSE) { > - memcpy(us->srb->request_buffer, > - usb_stor_sense_notready, > - sizeof(usb_stor_sense_notready)); > - us->srb->result = GOOD << 1; > - } else if(us->srb->cmnd[0] == INQUIRY) { > - unsigned char data_ptr[36] = { > - 0x20, 0x80, 0x02, 0x02, > - 0x1F, 0x00, 0x00, 0x00}; > - US_DEBUGP("Faking INQUIRY command for >disconnected device\n"); > - fill_inquiry_response(us, data_ptr, 36); > - us->srb->result = GOOD << 1; > - } else { > - memcpy(us->srb->sense_buffer, > - usb_stor_sense_notready, > - sizeof(usb_stor_sense_notready)); > - us->srb->result = CHECK_CONDITION << 1; > - } > - } else { /* atomic_read(&us->sm_state) == STATE_DETACHED */ > - > - /* Handle those devices which need us to fake > - * their inquiry data */ > - if ((us->srb->cmnd[0] == INQUIRY) && > - (us->flags & US_FL_FIX_INQUIRY)) { > - unsigned char data_ptr[36] = { > - 0x00, 0x80, 0x02, 0x02, > - 0x1F, 0x00, 0x00, 0x00}; > - > - US_DEBUGP("Faking INQUIRY command\n"); > - fill_inquiry_response(us, data_ptr, 36); > - us->srb->result = GOOD << 1; > - } else { > - /* we've got a command, let's do it! */ > - US_DEBUG(usb_stor_show_command(us->srb)); > - atomic_set(&us->sm_state, US_STATE_RUNNING); > - us->proto_handler(us->srb, us); > - atomic_set(&us->sm_state, US_STATE_IDLE); > - } > + /* our device has gone - pretend not ready */ > + if (atomic_read(&us->device_state) == US_STATE_DETACHED) { > + US_DEBUGP("Request is for removed device\n"); > + /* For REQUEST_SENSE, it's the data. But > + * for anything else, it should look like > + * we auto-sensed for it. > + */ > + if (us->srb->cmnd[0] == REQUEST_SENSE) { > + memcpy(us->srb->request_buffer, > + usb_stor_sense_notready, > + sizeof(usb_stor_sense_notready)); > + us->srb->result = GOOD << 1; > + } else if(us->srb->cmnd[0] == INQUIRY) { > + unsigned char data_ptr[36] = { > + 0x20, 0x80, 0x02, 0x02, > + 0x1F, 0x00, 0x00, 0x00}; > + US_DEBUGP("Faking INQUIRY command for disconnected >device\n"); > + fill_inquiry_response(us, data_ptr, 36); > + us->srb->result = GOOD << 1; > + } else { > + memcpy(us->srb->sense_buffer, > + usb_stor_sense_notready, > + sizeof(usb_stor_sense_notready)); > + us->srb->result = CHECK_CONDITION << 1; > } > + } else { /* atomic_read(&us->device_state) == STATE_DETACHED */ > > - /* unlock the device pointers */ > - up(&(us->dev_semaphore)); > + /* Handle those devices which need us to fake > + * their inquiry data */ > + if ((us->srb->cmnd[0] == INQUIRY) && > + (us->flags & US_FL_FIX_INQUIRY)) { > + unsigned char data_ptr[36] = { > + 0x00, 0x80, 0x02, 0x02, > + 0x1F, 0x00, 0x00, 0x00}; > > - /* indicate that the command is done */ > - if (us->srb->result != DID_ABORT << 16) { > - US_DEBUGP("scsi cmd done, result=0x%x\n", > - us->srb->result); > - scsi_lock(host); > - us->srb->scsi_done(us->srb); > - us->srb = NULL; > - scsi_unlock(host); > + US_DEBUGP("Faking INQUIRY command\n"); > + fill_inquiry_response(us, data_ptr, 36); > + us->srb->result = GOOD << 1; > } else { > - US_DEBUGP("scsi command aborted\n"); > - us->srb = NULL; > - complete(&(us->notify)); > + /* we've got a command, let's do it! */ > + US_DEBUG(usb_stor_show_command(us->srb)); > + us->proto_handler(us->srb, us); > } > - break; > - > - case US_ACT_DEVICE_RESET: > - break; > - > - case US_ACT_BUS_RESET: > - break; > - > - case US_ACT_HOST_RESET: > - break; > + } > > - } /* end switch on action */ > + /* unlock the device pointers */ > + up(&(us->dev_semaphore)); > > - /* exit if we get a signal to exit */ > - if (action == US_ACT_EXIT) { > - US_DEBUGP("-- US_ACT_EXIT command received\n"); > - break; > + /* indicate that the command is done */ > + if (us->srb->result != DID_ABORT << 16) { > + US_DEBUGP("scsi cmd done, result=0x%x\n", > + us->srb->result); > + scsi_lock(host); > + us->srb->scsi_done(us->srb); > + us->srb = NULL; > + scsi_unlock(host); > + } else { > + US_DEBUGP("scsi command aborted\n"); > + us->srb = NULL; > + complete(&(us->notify)); > } > } /* for (;;) */ > > @@ -722,7 +707,7 @@ > /* establish the connection to the new device upon reconnect */ > ss->ifnum = ifnum; > ss->pusb_dev = dev; > - atomic_set(&ss->sm_state, US_STATE_IDLE); > + atomic_set(&ss->device_state, US_STATE_ATTACHED); > > /* copy over the endpoint data */ > if (ep_in) > @@ -1013,6 +998,7 @@ > > /* start up our control thread */ > atomic_set(&ss->sm_state, US_STATE_IDLE); > + atomic_set(&ss->device_state, US_STATE_ATTACHED); > ss->pid = kernel_thread(usb_stor_control_thread, ss, > CLONE_VM); > if (ss->pid < 0) { > diff -Nru a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h > --- a/drivers/usb/storage/usb.h Sat May 25 17:30:49 2002 > +++ b/drivers/usb/storage/usb.h Sat May 25 17:30:49 2002 > @@ -4,7 +4,7 @@ > * $Id: usb.h,v 1.21 2002/04/21 02:57:59 mdharm Exp $ > * > * Current development and maintenance by: > - * (c) 1999, 2000 Matthew Dharm ([EMAIL PROTECTED]) > + * (c) 1999-2002 Matthew Dharm ([EMAIL PROTECTED]) > * > * Initial work by: > * (c) 1999 Michael Gee ([EMAIL PROTECTED]) > @@ -102,11 +102,15 @@ > #define US_FL_SCM_MULT_TARG 0x00000020 /* supports multiple targets */ > #define US_FL_FIX_INQUIRY 0x00000040 /* INQUIRY response needs fixing */ > > -#define US_STATE_DETACHED 1 /* State machine states */ > -#define US_STATE_IDLE 2 > -#define US_STATE_RUNNING 3 > -#define US_STATE_RESETTING 4 > -#define US_STATE_ABORTING 5 > +/* device attached/detached states */ > +#define US_STATE_DETACHED 1 > +#define US_STATE_ATTACHED 2 > + > +/* processing state machine states */ > +#define US_STATE_IDLE 1 > +#define US_STATE_RUNNING 2 > +#define US_STATE_RESETTING 3 > +#define US_STATE_ABORTING 4 > > #define USB_STOR_STRING_LEN 32 > > @@ -119,8 +123,13 @@ > 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: > + * (o) you must hold dev_semaphore to change pusb_dev > + * (o) device_state should change whenever pusb_dev does > + */ > struct semaphore dev_semaphore; /* protect pusb_dev */ > + atomic_t device_state; /* attached or detached */ > struct usb_device *pusb_dev; /* this usb_device */ > > unsigned int flags; /* from filter initially */ > > -- /------------------------------------+-------------------------\ |Stephen J. Gowdy | SLAC, MailStop 34, | |http://www.slac.stanford.edu/~gowdy/ | 2575 Sand Hill Road, | |http://calendar.yahoo.com/gowdy | Menlo Park CA 94025, USA | |EMail: [EMAIL PROTECTED] | Tel: +1 650 926 3144 | \------------------------------------+-------------------------/ _______________________________________________________________ Don't miss the 2002 Sprint PCS Application Developer's Conference August 25-28 in Las Vegas -- http://devcon.sprintpcs.com/adp/index.cfm _______________________________________________ [EMAIL PROTECTED] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel