aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/isci/remote_device.c
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2011-03-03 20:59:32 -0500
committerDan Williams <dan.j.williams@intel.com>2011-07-03 06:55:29 -0400
commitd9c37390c4f02153188a64a7a89fa6798dc3ffc2 (patch)
tree508f28b5b88348b2d989f479442cbd6813bd2b42 /drivers/scsi/isci/remote_device.c
parent6ad31fec306d532031b2f778f8656385df1b9d8f (diff)
isci: preallocate remote devices
Until we synchronize against device removal this limits the damage of use after free bugs to the driver's own objects. Unless we implement reference counting we need to ensure at least a subset of a remote device is valid at all times. We follow the lead of other libsas drivers that also preallocate devices. This also enforces maximum remote device accounting at the lldd layer, but the core may still run out of RNC's before we hit this limit. Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/scsi/isci/remote_device.c')
-rw-r--r--drivers/scsi/isci/remote_device.c73
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 */
74static void isci_remote_device_deconstruct( 74static 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 */
261static struct isci_remote_device * 256static struct isci_remote_device *
262isci_remote_device_alloc(struct isci_host *isci_host, struct isci_port *port) 257isci_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;