diff -Nru linux-2.6.32/drivers/scsi/hosts.c linux-2.6.32.new/drivers/scsi/hosts.c --- linux-2.6.32/drivers/scsi/hosts.c 2013-09-09 14:12:10.509339217 -0500 +++ linux-2.6.32.new/drivers/scsi/hosts.c 2013-09-09 14:01:38.220104267 -0500 @@ -276,6 +276,7 @@ struct Scsi_Host *shost = dev_to_shost(dev); struct device *parent = dev->parent; struct request_queue *q; + void *queuedata; //JRich - added by patch b485462 scsi_proc_hostdir_rm(shost->hostt); @@ -285,9 +286,13 @@ destroy_workqueue(shost->work_q); q = shost->uspace_req_q; if (q) { - kfree(q->queuedata); - q->queuedata = NULL; - scsi_free_queue(q); + //kfree(q->queuedata); //JRich - removed by patch b485462 + //q->queuedata = NULL; //JRich - removed by patch b485462 + queuedata = q->queuedata; //JRich - added by patch b485462 + //scsi_free_queue(q); //JRich - implicit remove by patch b485462 + blk_cleanup_queue(q); //JRich - implicit add by patch b485462 + kfree(q->queuedata); //JRich - added by patch b485462 + //q->queuedata = NULL; //JRich - removed by patch b485462 } scsi_destroy_command_freelist(shost); diff -Nru linux-2.6.32/drivers/scsi/scsi_lib.c linux-2.6.32.new/drivers/scsi/scsi_lib.c --- linux-2.6.32/drivers/scsi/scsi_lib.c 2013-09-09 14:12:10.512339260 -0500 +++ linux-2.6.32.new/drivers/scsi/scsi_lib.c 2013-09-09 14:01:36.568080135 -0500 @@ -67,7 +67,7 @@ struct kmem_cache *scsi_sdb_cache; -static void scsi_run_queue(struct request_queue *q); +//static void scsi_run_queue(struct request_queue *q); //JRich - Removed by 9937a5e2f /* * Function: scsi_unprep_request() @@ -103,7 +103,7 @@ * for a requeue after completion, which should only occur in this * file. */ -static int __scsi_queue_insert(struct scsi_cmnd *cmd, int reason, int unbusy) +static void __scsi_queue_insert(struct scsi_cmnd *cmd, int reason, int unbusy) //JRich changed to void by patch b485462 { struct Scsi_Host *host = cmd->device->host; struct scsi_device *device = cmd->device; @@ -148,22 +148,18 @@ /* * Requeue this command. It will go before all other commands - * that are already in the queue. - * - * NOTE: there is magic here about the way the queue is plugged if - * we have no outstanding commands. - * - * Although we *don't* plug the queue, we call the request - * function. The SCSI request function detects the blocked condition - * and plugs the queue appropriately. + * that are already in the queue. Schedule requeue work under + * lock such that the kblockd_schedule_work() call happens //JRich - comments modified by patch b485462 + * before blk_cleanup_queue() finishes. */ spin_lock_irqsave(q->queue_lock, flags); blk_requeue_request(q, cmd->request); - spin_unlock_irqrestore(q->queue_lock, flags); - - scsi_run_queue(q); + //spin_unlock_irqrestore(q->queue_lock, flags); //JRich - removed by patch b485462 + //scsi_run_queue(q); //JRich - implicit remove by patch b485462 - (removed by 9937a5e2f) + kblockd_schedule_work(q, &device->requeue_work); //JRich - implicit add by patch b485462 - (ADDED by 9937a5e2f) + spin_unlock_irqrestore(q->queue_lock, flags); //JRich - added by patch b485462 - return 0; + //return 0; //JRich - removed by patch b485462 } /* @@ -185,9 +181,9 @@ * Notes: This could be called either from an interrupt context or a * normal process context. */ -int scsi_queue_insert(struct scsi_cmnd *cmd, int reason) +void scsi_queue_insert(struct scsi_cmnd *cmd, int reason) //JRich - void by patch b485462 { - return __scsi_queue_insert(cmd, reason, 1); + __scsi_queue_insert(cmd, reason, 1); //JRich - void by patch b485462 } /** * scsi_execute - insert request and wait for the result @@ -443,18 +439,16 @@ } spin_unlock(shost->host_lock); - spin_lock(sdev->request_queue->queue_lock); - flagset = test_bit(QUEUE_FLAG_REENTER, &q->queue_flags) && - !test_bit(QUEUE_FLAG_REENTER, - &sdev->request_queue->queue_flags); - if (flagset) - queue_flag_set(QUEUE_FLAG_REENTER, sdev->request_queue); + //flagset = test_bit(QUEUE_FLAG_REENTER, &q->queue_flags) && + // !test_bit(QUEUE_FLAG_REENTER, + // &sdev->request_queue->queue_flags); //JRich - Implicit remove by patch 9937a5e2f + //if (flagset) + //queue_flag_set(QUEUE_FLAG_REENTER, sdev->request_queue); //JRich - Implicit remove by patch 9937a5e2f __blk_run_queue(sdev->request_queue); - if (flagset) - queue_flag_clear(QUEUE_FLAG_REENTER, sdev->request_queue); + //if (flagset) + //queue_flag_clear(QUEUE_FLAG_REENTER, sdev->request_queue);//JRich - Implicit remove by patch 9937a5e2f spin_unlock(sdev->request_queue->queue_lock); - spin_lock(shost->host_lock); } /* put any unprocessed entries back */ @@ -464,6 +458,16 @@ blk_run_queue(q); } +void scsi_requeue_run_queue(struct work_struct *work) //JRich - Added entire function patch 9937a5e2f +{ + struct scsi_device *sdev; + struct request_queue *q; + + sdev = container_of(work, struct scsi_device, requeue_work); + q = sdev->request_queue; + scsi_run_queue(q); +} + /* * Function: scsi_requeue_command() * @@ -484,7 +488,7 @@ */ static void scsi_requeue_command(struct request_queue *q, struct scsi_cmnd *cmd) { - struct scsi_device *sdev = cmd->device; + struct scsi_device *sdev = cmd->device; //JRich - no change needed though patch b485462 shows it was removed at some point struct request *req = cmd->request; unsigned long flags; @@ -494,7 +498,7 @@ * may happen because scsi_unprep_request() puts the command which * releases its reference on the device. */ - get_device(&sdev->sdev_gendev); + get_device(&sdev->sdev_gendev); //JRich - no change needed though patch b485462 shows it was removed at some point spin_lock_irqsave(q->queue_lock, flags); scsi_unprep_request(req); @@ -503,7 +507,7 @@ scsi_run_queue(q); - put_device(&sdev->sdev_gendev); + put_device(&sdev->sdev_gendev); //JRich - no change needed though patch b485462 shows it was removed at some point } void scsi_next_command(struct scsi_cmnd *cmd) diff -Nru linux-2.6.32/drivers/scsi/scsi_priv.h linux-2.6.32.new/drivers/scsi/scsi_priv.h --- linux-2.6.32/drivers/scsi/scsi_priv.h 2013-09-09 14:12:10.512339260 -0500 +++ linux-2.6.32.new/drivers/scsi/scsi_priv.h 2013-09-09 14:01:36.228075167 -0500 @@ -77,7 +77,7 @@ /* scsi_lib.c */ extern int scsi_maybe_unblock_host(struct scsi_device *sdev); extern void scsi_device_unbusy(struct scsi_device *sdev); -extern int scsi_queue_insert(struct scsi_cmnd *cmd, int reason); +extern void scsi_queue_insert(struct scsi_cmnd *cmd, int reason); //JRich changed to void by patch b485462 extern void scsi_next_command(struct scsi_cmnd *cmd); extern void scsi_io_completion(struct scsi_cmnd *, unsigned int); extern void scsi_run_host_queues(struct Scsi_Host *shost); diff -Nru linux-2.6.32/drivers/scsi/scsi_scan.c linux-2.6.32.new/drivers/scsi/scsi_scan.c --- linux-2.6.32/drivers/scsi/scsi_scan.c 2013-09-09 14:12:10.512339260 -0500 +++ linux-2.6.32.new/drivers/scsi/scsi_scan.c 2013-09-09 14:01:38.417107145 -0500 @@ -241,6 +241,7 @@ int display_failure_msg = 1, ret; struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); extern void scsi_evt_thread(struct work_struct *work); + extern void scsi_requeue_run_queue(struct work_struct *work); //JRich - Added by patch 9937a5e2f sdev = kzalloc(sizeof(*sdev) + shost->transportt->device_size, GFP_ATOMIC); @@ -262,6 +263,7 @@ INIT_LIST_HEAD(&sdev->event_list); spin_lock_init(&sdev->list_lock); INIT_WORK(&sdev->event_work, scsi_evt_thread); + INIT_WORK(&sdev->requeue_work, scsi_requeue_run_queue); //JRich - Added by patch 9937a5e2f sdev->sdev_gendev.parent = get_device(&starget->dev); sdev->sdev_target = starget; diff -Nru linux-2.6.32/drivers/scsi/scsi_sysfs.c linux-2.6.32.new/drivers/scsi/scsi_sysfs.c --- linux-2.6.32/drivers/scsi/scsi_sysfs.c 2013-09-09 14:12:10.512339260 -0500 +++ linux-2.6.32.new/drivers/scsi/scsi_sysfs.c 2013-09-09 14:01:38.249104690 -0500 @@ -912,16 +912,24 @@ device_del(dev); } else put_device(&sdev->sdev_dev); + /* + * Stop accepting new requests and wait until all queuecommand() and + * scsi_run_queue() invocations have finished before tearing down the + * device. + */ scsi_device_set_state(sdev, SDEV_DEL); + + blk_cleanup_queue(sdev->request_queue); //JRich - added by patch b485462 + cancel_work_sync(&sdev->requeue_work); //JRich - added by patch b485462 if (sdev->host->hostt->slave_destroy) sdev->host->hostt->slave_destroy(sdev); transport_destroy_device(dev); /* cause the request function to reject all I/O requests */ - sdev->request_queue->queuedata = NULL; + //sdev->request_queue->queuedata = NULL; //JRich - implicit remove by patch b485462 /* Freeing the queue signals to block that we're done */ - scsi_free_queue(sdev->request_queue); + //scsi_free_queue(sdev->request_queue); //JRich - implicit remove by patch b485462 put_device(dev); } diff -Nru linux-2.6.32/include/scsi/scsi_device.h linux-2.6.32.new/include/scsi/scsi_device.h --- linux-2.6.32/include/scsi/scsi_device.h 2013-09-09 14:12:10.542339698 -0500 +++ linux-2.6.32.new/include/scsi/scsi_device.h 2013-09-09 14:00:14.554882022 -0500 @@ -164,6 +164,7 @@ sdev_dev; struct execute_work ew; /* used to get process context on put */ + struct work_struct requeue_work; //JRich - Added by Patch 9937a5e2f struct scsi_dh_data *scsi_dh_data; enum scsi_device_state sdev_state;