diff options
Diffstat (limited to 'drivers/scsi/isci/remote_device.c')
-rw-r--r-- | drivers/scsi/isci/remote_device.c | 73 |
1 files changed, 35 insertions, 38 deletions
diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c index db2259ce003..48556e47bb9 100644 --- a/drivers/scsi/isci/remote_device.c +++ b/drivers/scsi/isci/remote_device.c @@ -67,40 +67,35 @@ /** * isci_remote_device_deconstruct() - This function frees an isci_remote_device. - * @isci_host: This parameter specifies the isci host object. - * @isci_device: This parameter specifies the remote device to be freed. + * @ihost: This parameter specifies the isci host object. + * @idev: This parameter specifies the remote device to be freed. * */ -static void isci_remote_device_deconstruct( - struct isci_host *isci_host, - struct isci_remote_device *isci_device) +static void isci_remote_device_deconstruct(struct isci_host *ihost, struct isci_remote_device *idev) { - dev_dbg(&isci_host->pdev->dev, - "%s: isci_device = %p\n", __func__, isci_device); + dev_dbg(&ihost->pdev->dev, + "%s: isci_device = %p\n", __func__, idev); /* There should not be any outstanding io's. All paths to * here should go through isci_remote_device_nuke_requests. * If we hit this condition, we will need a way to complete * io requests in process */ - while (!list_empty(&isci_device->reqs_in_process)) { + while (!list_empty(&idev->reqs_in_process)) { - dev_err(&isci_host->pdev->dev, + dev_err(&ihost->pdev->dev, "%s: ** request list not empty! **\n", __func__); BUG(); } - /* Remove all related references to this device and free - * the cache object. - */ - scic_remote_device_destruct(to_sci_dev(isci_device)); - isci_device->domain_dev->lldd_dev = NULL; - list_del(&isci_device->node); - - clear_bit(IDEV_STOP_PENDING, &isci_device->flags); - clear_bit(IDEV_START_PENDING, &isci_device->flags); - wake_up(&isci_host->eventq); - complete(isci_device->cmp); - kmem_cache_free(isci_kmem_cache, isci_device); + scic_remote_device_destruct(to_sci_dev(idev)); + idev->domain_dev->lldd_dev = NULL; + idev->domain_dev = NULL; + idev->isci_port = NULL; + list_del_init(&idev->node); + + clear_bit(IDEV_START_PENDING, &idev->flags); + clear_bit(IDEV_STOP_PENDING, &idev->flags); + wake_up(&ihost->eventq); } @@ -259,25 +254,27 @@ void isci_remote_device_nuke_requests( * pointer to new isci_remote_device. */ static struct isci_remote_device * -isci_remote_device_alloc(struct isci_host *isci_host, struct isci_port *port) +isci_remote_device_alloc(struct isci_host *ihost, struct isci_port *iport) { - struct isci_remote_device *isci_device; + struct isci_remote_device *idev; + int i; - isci_device = kmem_cache_zalloc(isci_kmem_cache, GFP_KERNEL); + for (i = 0; i < SCI_MAX_REMOTE_DEVICES; i++) { + idev = idev_by_id(ihost, i); + if (!test_and_set_bit(IDEV_ALLOCATED, &idev->flags)) + break; + } - if (!isci_device) { - dev_warn(&isci_host->pdev->dev, "%s: failed\n", __func__); + if (i >= SCI_MAX_REMOTE_DEVICES) { + dev_warn(&ihost->pdev->dev, "%s: failed\n", __func__); return NULL; } - INIT_LIST_HEAD(&isci_device->reqs_in_process); - INIT_LIST_HEAD(&isci_device->node); - - spin_lock_init(&isci_device->state_lock); - isci_remote_device_change_state(isci_device, isci_freed); - - return isci_device; + BUG_ON(!list_empty(&idev->reqs_in_process)); + BUG_ON(!list_empty(&idev->node)); + isci_remote_device_change_state(idev, isci_freed); + return idev; } /** @@ -381,24 +378,22 @@ enum sci_status isci_remote_device_stop(struct isci_host *ihost, struct isci_rem { enum sci_status status; unsigned long flags; - DECLARE_COMPLETION_ONSTACK(completion); dev_dbg(&ihost->pdev->dev, "%s: isci_device = %p\n", __func__, idev); isci_remote_device_change_state(idev, isci_stopping); set_bit(IDEV_STOP_PENDING, &idev->flags); - idev->cmp = &completion; spin_lock_irqsave(&ihost->scic_lock, flags); - status = scic_remote_device_stop(to_sci_dev(idev), 50); - spin_unlock_irqrestore(&ihost->scic_lock, flags); /* Wait for the stop complete callback. */ - if (status == SCI_SUCCESS) + if (status == SCI_SUCCESS) { wait_for_device_stop(ihost, idev); + clear_bit(IDEV_ALLOCATED, &idev->flags); + } dev_dbg(&ihost->pdev->dev, "%s: idev = %p - after completion wait\n", @@ -469,6 +464,8 @@ int isci_remote_device_found(struct domain_device *domain_dev) return -ENODEV; isci_device = isci_remote_device_alloc(isci_host, isci_port); + if (!isci_device) + return -ENODEV; INIT_LIST_HEAD(&isci_device->node); domain_dev->lldd_dev = isci_device; |