diff options
Diffstat (limited to 'drivers/scsi/scsi_transport_fc.c')
-rw-r--r-- | drivers/scsi/scsi_transport_fc.c | 72 |
1 files changed, 42 insertions, 30 deletions
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 6b165a3ec6de..3a821afee9bc 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -446,13 +446,6 @@ static int fc_host_setup(struct transport_container *tc, struct device *dev, return -ENOMEM; fc_host->dev_loss_tmo = fc_dev_loss_tmo; - fc_host->devloss_work_q = alloc_workqueue("fc_dl_%d", 0, 0, - shost->host_no); - if (!fc_host->devloss_work_q) { - destroy_workqueue(fc_host->work_q); - fc_host->work_q = NULL; - return -ENOMEM; - } fc_bsg_hostadd(shost, fc_host); /* ignore any bsg add error - we just can't do sgio */ @@ -2814,6 +2807,7 @@ fc_flush_work(struct Scsi_Host *shost) /** * fc_queue_devloss_work - Schedule work for the fc_host devloss workqueue. * @shost: Pointer to Scsi_Host bound to fc_host. + * @rport: rport associated with the devloss work * @work: Work to queue for execution. * @delay: jiffies to delay the work queuing * @@ -2821,10 +2815,10 @@ fc_flush_work(struct Scsi_Host *shost) * 1 on success / 0 already queued / < 0 for error */ static int -fc_queue_devloss_work(struct Scsi_Host *shost, struct delayed_work *work, - unsigned long delay) +fc_queue_devloss_work(struct Scsi_Host *shost, struct fc_rport *rport, + struct delayed_work *work, unsigned long delay) { - if (unlikely(!fc_host_devloss_work_q(shost))) { + if (unlikely(!rport->devloss_work_q)) { printk(KERN_ERR "ERROR: FC host '%s' attempted to queue work, " "when no workqueue created.\n", shost->hostt->name); @@ -2833,17 +2827,18 @@ fc_queue_devloss_work(struct Scsi_Host *shost, struct delayed_work *work, return -EINVAL; } - return queue_delayed_work(fc_host_devloss_work_q(shost), work, delay); + return queue_delayed_work(rport->devloss_work_q, work, delay); } /** * fc_flush_devloss - Flush a fc_host's devloss workqueue. * @shost: Pointer to Scsi_Host bound to fc_host. + * @rport: rport associated with the devloss work */ static void -fc_flush_devloss(struct Scsi_Host *shost) +fc_flush_devloss(struct Scsi_Host *shost, struct fc_rport *rport) { - if (!fc_host_devloss_work_q(shost)) { + if (unlikely(!rport->devloss_work_q)) { printk(KERN_ERR "ERROR: FC host '%s' attempted to flush work, " "when no workqueue created.\n", shost->hostt->name); @@ -2851,7 +2846,7 @@ fc_flush_devloss(struct Scsi_Host *shost) return; } - flush_workqueue(fc_host_devloss_work_q(shost)); + flush_workqueue(rport->devloss_work_q); } @@ -2913,13 +2908,6 @@ fc_remove_host(struct Scsi_Host *shost) fc_host->work_q = NULL; destroy_workqueue(work_q); } - - /* flush all devloss work items, then kill it */ - if (fc_host->devloss_work_q) { - work_q = fc_host->devloss_work_q; - fc_host->devloss_work_q = NULL; - destroy_workqueue(work_q); - } } EXPORT_SYMBOL(fc_remove_host); @@ -2967,6 +2955,7 @@ fc_rport_final_delete(struct work_struct *work) struct device *dev = &rport->dev; struct Scsi_Host *shost = rport_to_shost(rport); struct fc_internal *i = to_fc_internal(shost->transportt); + struct workqueue_struct *work_q; unsigned long flags; int do_callback = 0; @@ -2988,9 +2977,9 @@ fc_rport_final_delete(struct work_struct *work) if (rport->flags & FC_RPORT_DEVLOSS_PENDING) { spin_unlock_irqrestore(shost->host_lock, flags); if (!cancel_delayed_work(&rport->fail_io_work)) - fc_flush_devloss(shost); + fc_flush_devloss(shost, rport); if (!cancel_delayed_work(&rport->dev_loss_work)) - fc_flush_devloss(shost); + fc_flush_devloss(shost, rport); cancel_work_sync(&rport->scan_work); spin_lock_irqsave(shost->host_lock, flags); rport->flags &= ~FC_RPORT_DEVLOSS_PENDING; @@ -3021,6 +3010,12 @@ fc_rport_final_delete(struct work_struct *work) fc_bsg_remove(rport->rqst_q); + if (rport->devloss_work_q) { + work_q = rport->devloss_work_q; + rport->devloss_work_q = NULL; + destroy_workqueue(work_q); + } + transport_remove_device(dev); device_del(dev); transport_destroy_device(dev); @@ -3093,6 +3088,22 @@ fc_remote_port_create(struct Scsi_Host *shost, int channel, spin_unlock_irqrestore(shost->host_lock, flags); + rport->devloss_work_q = alloc_workqueue("fc_dl_%d_%d", 0, 0, + shost->host_no, rport->number); + if (!rport->devloss_work_q) { + printk(KERN_ERR "FC Remote Port alloc_workqueue failed\n"); +/* + * Note that we have not yet called device_initialize() / get_device() + * Cannot reclaim incremented rport->number because we released host_lock + */ + spin_lock_irqsave(shost->host_lock, flags); + list_del(&rport->peers); + scsi_host_put(shost); /* for fc_host->rport list */ + spin_unlock_irqrestore(shost->host_lock, flags); + kfree(rport); + return NULL; + } + dev = &rport->dev; device_initialize(dev); /* takes self reference */ dev->parent = get_device(&shost->shost_gendev); /* parent reference */ @@ -3255,9 +3266,9 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel, * be checked and will NOOP the function. */ if (!cancel_delayed_work(&rport->fail_io_work)) - fc_flush_devloss(shost); + fc_flush_devloss(shost, rport); if (!cancel_delayed_work(&rport->dev_loss_work)) - fc_flush_devloss(shost); + fc_flush_devloss(shost, rport); spin_lock_irqsave(shost->host_lock, flags); @@ -3451,11 +3462,12 @@ fc_remote_port_delete(struct fc_rport *rport) /* see if we need to kill io faster than waiting for device loss */ if ((rport->fast_io_fail_tmo != -1) && (rport->fast_io_fail_tmo < timeout)) - fc_queue_devloss_work(shost, &rport->fail_io_work, - rport->fast_io_fail_tmo * HZ); + fc_queue_devloss_work(shost, rport, &rport->fail_io_work, + rport->fast_io_fail_tmo * HZ); /* cap the length the devices can be blocked until they are deleted */ - fc_queue_devloss_work(shost, &rport->dev_loss_work, timeout * HZ); + fc_queue_devloss_work(shost, rport, &rport->dev_loss_work, + timeout * HZ); } EXPORT_SYMBOL(fc_remote_port_delete); @@ -3514,9 +3526,9 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles) * transaction. */ if (!cancel_delayed_work(&rport->fail_io_work)) - fc_flush_devloss(shost); + fc_flush_devloss(shost, rport); if (!cancel_delayed_work(&rport->dev_loss_work)) - fc_flush_devloss(shost); + fc_flush_devloss(shost, rport); spin_lock_irqsave(shost->host_lock, flags); rport->flags &= ~(FC_RPORT_FAST_FAIL_TIMEDOUT | |