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 db2259ce003f..48556e47bb9d 100644 --- a/drivers/scsi/isci/remote_device.c +++ b/drivers/scsi/isci/remote_device.c | |||
@@ -67,40 +67,35 @@ | |||
67 | 67 | ||
68 | /** | 68 | /** |
69 | * isci_remote_device_deconstruct() - This function frees an isci_remote_device. | 69 | * isci_remote_device_deconstruct() - This function frees an isci_remote_device. |
70 | * @isci_host: This parameter specifies the isci host object. | 70 | * @ihost: This parameter specifies the isci host object. |
71 | * @isci_device: This parameter specifies the remote device to be freed. | 71 | * @idev: This parameter specifies the remote device to be freed. |
72 | * | 72 | * |
73 | */ | 73 | */ |
74 | static void isci_remote_device_deconstruct( | 74 | static void isci_remote_device_deconstruct(struct isci_host *ihost, struct isci_remote_device *idev) |
75 | struct isci_host *isci_host, | ||
76 | struct isci_remote_device *isci_device) | ||
77 | { | 75 | { |
78 | dev_dbg(&isci_host->pdev->dev, | 76 | dev_dbg(&ihost->pdev->dev, |
79 | "%s: isci_device = %p\n", __func__, isci_device); | 77 | "%s: isci_device = %p\n", __func__, idev); |
80 | 78 | ||
81 | /* There should not be any outstanding io's. All paths to | 79 | /* There should not be any outstanding io's. All paths to |
82 | * here should go through isci_remote_device_nuke_requests. | 80 | * here should go through isci_remote_device_nuke_requests. |
83 | * If we hit this condition, we will need a way to complete | 81 | * If we hit this condition, we will need a way to complete |
84 | * io requests in process */ | 82 | * io requests in process */ |
85 | while (!list_empty(&isci_device->reqs_in_process)) { | 83 | while (!list_empty(&idev->reqs_in_process)) { |
86 | 84 | ||
87 | dev_err(&isci_host->pdev->dev, | 85 | dev_err(&ihost->pdev->dev, |
88 | "%s: ** request list not empty! **\n", __func__); | 86 | "%s: ** request list not empty! **\n", __func__); |
89 | BUG(); | 87 | BUG(); |
90 | } | 88 | } |
91 | 89 | ||
92 | /* Remove all related references to this device and free | 90 | scic_remote_device_destruct(to_sci_dev(idev)); |
93 | * the cache object. | 91 | idev->domain_dev->lldd_dev = NULL; |
94 | */ | 92 | idev->domain_dev = NULL; |
95 | scic_remote_device_destruct(to_sci_dev(isci_device)); | 93 | idev->isci_port = NULL; |
96 | isci_device->domain_dev->lldd_dev = NULL; | 94 | list_del_init(&idev->node); |
97 | list_del(&isci_device->node); | 95 | |
98 | 96 | clear_bit(IDEV_START_PENDING, &idev->flags); | |
99 | clear_bit(IDEV_STOP_PENDING, &isci_device->flags); | 97 | clear_bit(IDEV_STOP_PENDING, &idev->flags); |
100 | clear_bit(IDEV_START_PENDING, &isci_device->flags); | 98 | wake_up(&ihost->eventq); |
101 | wake_up(&isci_host->eventq); | ||
102 | complete(isci_device->cmp); | ||
103 | kmem_cache_free(isci_kmem_cache, isci_device); | ||
104 | } | 99 | } |
105 | 100 | ||
106 | 101 | ||
@@ -259,25 +254,27 @@ void isci_remote_device_nuke_requests( | |||
259 | * pointer to new isci_remote_device. | 254 | * pointer to new isci_remote_device. |
260 | */ | 255 | */ |
261 | static struct isci_remote_device * | 256 | static struct isci_remote_device * |
262 | isci_remote_device_alloc(struct isci_host *isci_host, struct isci_port *port) | 257 | isci_remote_device_alloc(struct isci_host *ihost, struct isci_port *iport) |
263 | { | 258 | { |
264 | struct isci_remote_device *isci_device; | 259 | struct isci_remote_device *idev; |
260 | int i; | ||
265 | 261 | ||
266 | isci_device = kmem_cache_zalloc(isci_kmem_cache, GFP_KERNEL); | 262 | for (i = 0; i < SCI_MAX_REMOTE_DEVICES; i++) { |
263 | idev = idev_by_id(ihost, i); | ||
264 | if (!test_and_set_bit(IDEV_ALLOCATED, &idev->flags)) | ||
265 | break; | ||
266 | } | ||
267 | 267 | ||
268 | if (!isci_device) { | 268 | if (i >= SCI_MAX_REMOTE_DEVICES) { |
269 | dev_warn(&isci_host->pdev->dev, "%s: failed\n", __func__); | 269 | dev_warn(&ihost->pdev->dev, "%s: failed\n", __func__); |
270 | return NULL; | 270 | return NULL; |
271 | } | 271 | } |
272 | 272 | ||
273 | INIT_LIST_HEAD(&isci_device->reqs_in_process); | 273 | BUG_ON(!list_empty(&idev->reqs_in_process)); |
274 | INIT_LIST_HEAD(&isci_device->node); | 274 | BUG_ON(!list_empty(&idev->node)); |
275 | 275 | isci_remote_device_change_state(idev, isci_freed); | |
276 | spin_lock_init(&isci_device->state_lock); | ||
277 | isci_remote_device_change_state(isci_device, isci_freed); | ||
278 | |||
279 | return isci_device; | ||
280 | 276 | ||
277 | return idev; | ||
281 | } | 278 | } |
282 | 279 | ||
283 | /** | 280 | /** |
@@ -381,24 +378,22 @@ enum sci_status isci_remote_device_stop(struct isci_host *ihost, struct isci_rem | |||
381 | { | 378 | { |
382 | enum sci_status status; | 379 | enum sci_status status; |
383 | unsigned long flags; | 380 | unsigned long flags; |
384 | DECLARE_COMPLETION_ONSTACK(completion); | ||
385 | 381 | ||
386 | dev_dbg(&ihost->pdev->dev, | 382 | dev_dbg(&ihost->pdev->dev, |
387 | "%s: isci_device = %p\n", __func__, idev); | 383 | "%s: isci_device = %p\n", __func__, idev); |
388 | 384 | ||
389 | isci_remote_device_change_state(idev, isci_stopping); | 385 | isci_remote_device_change_state(idev, isci_stopping); |
390 | set_bit(IDEV_STOP_PENDING, &idev->flags); | 386 | set_bit(IDEV_STOP_PENDING, &idev->flags); |
391 | idev->cmp = &completion; | ||
392 | 387 | ||
393 | spin_lock_irqsave(&ihost->scic_lock, flags); | 388 | spin_lock_irqsave(&ihost->scic_lock, flags); |
394 | |||
395 | status = scic_remote_device_stop(to_sci_dev(idev), 50); | 389 | status = scic_remote_device_stop(to_sci_dev(idev), 50); |
396 | |||
397 | spin_unlock_irqrestore(&ihost->scic_lock, flags); | 390 | spin_unlock_irqrestore(&ihost->scic_lock, flags); |
398 | 391 | ||
399 | /* Wait for the stop complete callback. */ | 392 | /* Wait for the stop complete callback. */ |
400 | if (status == SCI_SUCCESS) | 393 | if (status == SCI_SUCCESS) { |
401 | wait_for_device_stop(ihost, idev); | 394 | wait_for_device_stop(ihost, idev); |
395 | clear_bit(IDEV_ALLOCATED, &idev->flags); | ||
396 | } | ||
402 | 397 | ||
403 | dev_dbg(&ihost->pdev->dev, | 398 | dev_dbg(&ihost->pdev->dev, |
404 | "%s: idev = %p - after completion wait\n", | 399 | "%s: idev = %p - after completion wait\n", |
@@ -469,6 +464,8 @@ int isci_remote_device_found(struct domain_device *domain_dev) | |||
469 | return -ENODEV; | 464 | return -ENODEV; |
470 | 465 | ||
471 | isci_device = isci_remote_device_alloc(isci_host, isci_port); | 466 | isci_device = isci_remote_device_alloc(isci_host, isci_port); |
467 | if (!isci_device) | ||
468 | return -ENODEV; | ||
472 | 469 | ||
473 | INIT_LIST_HEAD(&isci_device->node); | 470 | INIT_LIST_HEAD(&isci_device->node); |
474 | domain_dev->lldd_dev = isci_device; | 471 | domain_dev->lldd_dev = isci_device; |