aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2011-03-04 15:10:29 -0500
committerDan Williams <dan.j.williams@intel.com>2011-07-03 06:55:29 -0400
commit6ad31fec306d532031b2f778f8656385df1b9d8f (patch)
treec23640084d82b5ff534fe837300ac64d3a92143e
parent8acaec1593526f922ff46812d99abf9aab5c8b43 (diff)
isci: replace isci_remote_device completion with event queue
Replace the device completion infrastructure with the controller wide event queue. There was a potential for the stop and ready notifications to corrupt each other, now that cannot happen. The stop pending flag cannot be used until devices are statically allocated. We temporarily need to maintain a completion to handle waiting for an object that has disappeared, but we can at least stop scribbling on freed memory. A future change will also get rid of the "stopping" state as it should not be exposed to the rest of the driver. Signed-off-by: Dan Williams <dan.j.williams@intel.com>
-rw-r--r--drivers/scsi/isci/events.c30
-rw-r--r--drivers/scsi/isci/host.c2
-rw-r--r--drivers/scsi/isci/host.h13
-rw-r--r--drivers/scsi/isci/remote_device.c98
-rw-r--r--drivers/scsi/isci/remote_device.h11
5 files changed, 69 insertions, 85 deletions
diff --git a/drivers/scsi/isci/events.c b/drivers/scsi/isci/events.c
index c5cbaedac041..9d58e458a37b 100644
--- a/drivers/scsi/isci/events.c
+++ b/drivers/scsi/isci/events.c
@@ -526,7 +526,7 @@ void isci_event_remote_device_start_complete(
526/** 526/**
527 * isci_event_remote_device_stop_complete() - This user callback method will 527 * isci_event_remote_device_stop_complete() - This user callback method will
528 * inform the user that a stop operation has completed. 528 * inform the user that a stop operation has completed.
529 * @controller: This parameter specifies the core controller associated with 529 * @scic: This parameter specifies the core controller associated with
530 * the completion callback. 530 * the completion callback.
531 * @remote_device: This parameter specifies the remote device associated with 531 * @remote_device: This parameter specifies the remote device associated with
532 * the completion callback. 532 * the completion callback.
@@ -534,28 +534,20 @@ void isci_event_remote_device_start_complete(
534 * operation. 534 * operation.
535 * 535 *
536 */ 536 */
537void isci_event_remote_device_stop_complete( 537void isci_event_remote_device_stop_complete(struct scic_sds_controller *scic,
538 struct scic_sds_controller *controller, 538 struct scic_sds_remote_device *sci_dev,
539 struct scic_sds_remote_device *remote_device, 539 enum sci_status completion_status)
540 enum sci_status completion_status)
541{ 540{
542 struct isci_host *isci_host; 541 struct isci_host *ihost;
543 struct isci_remote_device *isci_device; 542 struct isci_remote_device *idev;
544 543
545 isci_host = 544 ihost = sci_object_get_association(scic);
546 (struct isci_host *)sci_object_get_association(controller); 545 idev = sci_object_get_association(sci_dev);
547 546
548 isci_device = 547 dev_dbg(&ihost->pdev->dev,
549 (struct isci_remote_device *)sci_object_get_association( 548 "%s: idev = %p\n", __func__, idev);
550 remote_device
551 );
552
553 dev_dbg(&isci_host->pdev->dev,
554 "%s: isci_device = %p\n", __func__, isci_device);
555
556 isci_remote_device_stop_complete(
557 isci_host, isci_device, completion_status);
558 549
550 isci_remote_device_stop_complete(ihost, idev, completion_status);
559} 551}
560 552
561/** 553/**
diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c
index da0c0da4198f..8d255666a657 100644
--- a/drivers/scsi/isci/host.c
+++ b/drivers/scsi/isci/host.c
@@ -345,7 +345,7 @@ void isci_host_deinit(struct isci_host *ihost)
345 345
346 list_for_each_entry_safe(idev, d, &port->remote_dev_list, node) { 346 list_for_each_entry_safe(idev, d, &port->remote_dev_list, node) {
347 isci_remote_device_change_state(idev, isci_stopping); 347 isci_remote_device_change_state(idev, isci_stopping);
348 isci_remote_device_stop(idev); 348 isci_remote_device_stop(ihost, idev);
349 } 349 }
350 } 350 }
351 351
diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h
index 7c1f0b5cee7d..6a6304c06976 100644
--- a/drivers/scsi/isci/host.h
+++ b/drivers/scsi/isci/host.h
@@ -212,6 +212,19 @@ static inline void wait_for_stop(struct isci_host *ihost)
212 wait_event(ihost->eventq, !test_bit(IHOST_STOP_PENDING, &ihost->flags)); 212 wait_event(ihost->eventq, !test_bit(IHOST_STOP_PENDING, &ihost->flags));
213} 213}
214 214
215static inline void wait_for_device_start(struct isci_host *ihost, struct isci_remote_device *idev)
216{
217 wait_event(ihost->eventq, !test_bit(IDEV_START_PENDING, &idev->flags));
218}
219
220static inline void wait_for_device_stop(struct isci_host *ihost, struct isci_remote_device *idev)
221{
222 /* todo switch to:
223 * wait_event(ihost->eventq, !test_bit(IDEV_STOP_PENDING, &idev->flags));
224 * once devices are statically allocated
225 */
226 wait_for_completion(idev->cmp);
227}
215 228
216/** 229/**
217 * isci_host_from_sas_ha() - This accessor retrieves the isci_host object 230 * isci_host_from_sas_ha() - This accessor retrieves the isci_host object
diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c
index fc1f24449170..db2259ce003f 100644
--- a/drivers/scsi/isci/remote_device.c
+++ b/drivers/scsi/isci/remote_device.c
@@ -95,6 +95,11 @@ static void isci_remote_device_deconstruct(
95 scic_remote_device_destruct(to_sci_dev(isci_device)); 95 scic_remote_device_destruct(to_sci_dev(isci_device));
96 isci_device->domain_dev->lldd_dev = NULL; 96 isci_device->domain_dev->lldd_dev = NULL;
97 list_del(&isci_device->node); 97 list_del(&isci_device->node);
98
99 clear_bit(IDEV_STOP_PENDING, &isci_device->flags);
100 clear_bit(IDEV_START_PENDING, &isci_device->flags);
101 wake_up(&isci_host->eventq);
102 complete(isci_device->cmp);
98 kmem_cache_free(isci_kmem_cache, isci_device); 103 kmem_cache_free(isci_kmem_cache, isci_device);
99} 104}
100 105
@@ -279,30 +284,22 @@ isci_remote_device_alloc(struct isci_host *isci_host, struct isci_port *port)
279 * isci_remote_device_ready() - This function is called by the scic when the 284 * isci_remote_device_ready() - This function is called by the scic when the
280 * remote device is ready. We mark the isci device as ready and signal the 285 * remote device is ready. We mark the isci device as ready and signal the
281 * waiting proccess. 286 * waiting proccess.
282 * @isci_host: This parameter specifies the isci host object. 287 * @idev: This parameter specifies the remote device
283 * @isci_device: This parameter specifies the remote device
284 * 288 *
285 */ 289 */
286void isci_remote_device_ready(struct isci_remote_device *isci_device) 290void isci_remote_device_ready(struct isci_remote_device *idev)
287{ 291{
292 struct isci_host *ihost = idev->isci_port->isci_host;
288 unsigned long flags; 293 unsigned long flags;
289 294
290 dev_dbg(&isci_device->isci_port->isci_host->pdev->dev, 295 dev_dbg(&ihost->pdev->dev,
291 "%s: isci_device = %p\n", __func__, isci_device); 296 "%s: isci_device = %p\n", __func__, idev);
292
293 /* device ready is actually a "ready for io" state. */
294 if (isci_device->status == isci_starting ||
295 isci_device->status == isci_ready) {
296 spin_lock_irqsave(&isci_device->isci_port->remote_device_lock,
297 flags);
298 isci_remote_device_change_state(isci_device, isci_ready_for_io);
299 if (isci_device->completion)
300 complete(isci_device->completion);
301 spin_unlock_irqrestore(
302 &isci_device->isci_port->remote_device_lock,
303 flags);
304 }
305 297
298 spin_lock_irqsave(&idev->isci_port->remote_device_lock, flags);
299 isci_remote_device_change_state(idev, isci_ready_for_io);
300 if (test_and_clear_bit(IDEV_START_PENDING, &idev->flags))
301 wake_up(&ihost->eventq);
302 spin_unlock_irqrestore(&idev->isci_port->remote_device_lock, flags);
306} 303}
307 304
308/** 305/**
@@ -341,8 +338,6 @@ void isci_remote_device_stop_complete(
341 struct isci_remote_device *isci_device, 338 struct isci_remote_device *isci_device,
342 enum sci_status status) 339 enum sci_status status)
343{ 340{
344 struct completion *completion = isci_device->completion;
345
346 dev_dbg(&isci_host->pdev->dev, 341 dev_dbg(&isci_host->pdev->dev,
347 "%s: complete isci_device = %p, status = 0x%x\n", 342 "%s: complete isci_device = %p, status = 0x%x\n",
348 __func__, 343 __func__,
@@ -354,9 +349,6 @@ void isci_remote_device_stop_complete(
354 /* after stop, we can tear down resources. */ 349 /* after stop, we can tear down resources. */
355 isci_remote_device_deconstruct(isci_host, isci_device); 350 isci_remote_device_deconstruct(isci_host, isci_device);
356 351
357 /* notify interested parties. */
358 if (completion)
359 complete(completion);
360} 352}
361 353
362/** 354/**
@@ -385,40 +377,33 @@ void isci_remote_device_start_complete(
385 * 377 *
386 * The status of the scic request to stop. 378 * The status of the scic request to stop.
387 */ 379 */
388enum sci_status isci_remote_device_stop( 380enum sci_status isci_remote_device_stop(struct isci_host *ihost, struct isci_remote_device *idev)
389 struct isci_remote_device *isci_device)
390{ 381{
391 enum sci_status status; 382 enum sci_status status;
392 unsigned long flags; 383 unsigned long flags;
393
394 DECLARE_COMPLETION_ONSTACK(completion); 384 DECLARE_COMPLETION_ONSTACK(completion);
395 385
396 dev_dbg(&isci_device->isci_port->isci_host->pdev->dev, 386 dev_dbg(&ihost->pdev->dev,
397 "%s: isci_device = %p\n", __func__, isci_device); 387 "%s: isci_device = %p\n", __func__, idev);
398
399 isci_remote_device_change_state(isci_device, isci_stopping);
400
401 /* We need comfirmation that stop completed. */
402 isci_device->completion = &completion;
403 388
404 BUG_ON(isci_device->isci_port == NULL); 389 isci_remote_device_change_state(idev, isci_stopping);
405 BUG_ON(isci_device->isci_port->isci_host == NULL); 390 set_bit(IDEV_STOP_PENDING, &idev->flags);
391 idev->cmp = &completion;
406 392
407 spin_lock_irqsave(&isci_device->isci_port->isci_host->scic_lock, flags); 393 spin_lock_irqsave(&ihost->scic_lock, flags);
408 394
409 status = scic_remote_device_stop(to_sci_dev(isci_device), 50); 395 status = scic_remote_device_stop(to_sci_dev(idev), 50);
410 396
411 spin_unlock_irqrestore(&isci_device->isci_port->isci_host->scic_lock, flags); 397 spin_unlock_irqrestore(&ihost->scic_lock, flags);
412 398
413 /* Wait for the stop complete callback. */ 399 /* Wait for the stop complete callback. */
414 if (status == SCI_SUCCESS) 400 if (status == SCI_SUCCESS)
415 wait_for_completion(&completion); 401 wait_for_device_stop(ihost, idev);
416 402
417 dev_dbg(&isci_device->isci_port->isci_host->pdev->dev, 403 dev_dbg(&ihost->pdev->dev,
418 "%s: isci_device = %p - after completion wait\n", 404 "%s: idev = %p - after completion wait\n",
419 __func__, isci_device); 405 __func__, idev);
420 406
421 isci_device->completion = NULL;
422 return status; 407 return status;
423} 408}
424 409
@@ -428,18 +413,16 @@ enum sci_status isci_remote_device_stop(
428 * @domain_device: This parameter specifies the libsas domain device. 413 * @domain_device: This parameter specifies the libsas domain device.
429 * 414 *
430 */ 415 */
431void isci_remote_device_gone( 416void isci_remote_device_gone(struct domain_device *dev)
432 struct domain_device *domain_dev)
433{ 417{
434 struct isci_remote_device *isci_device = isci_dev_from_domain_dev( 418 struct isci_host *ihost = dev->port->ha->lldd_ha;
435 domain_dev); 419 struct isci_remote_device *idev = dev->lldd_dev;
436 420
437 dev_dbg(&isci_device->isci_port->isci_host->pdev->dev, 421 dev_dbg(&ihost->pdev->dev,
438 "%s: domain_device = %p, isci_device = %p, isci_port = %p\n", 422 "%s: domain_device = %p, isci_device = %p, isci_port = %p\n",
439 __func__, domain_dev, isci_device, isci_device->isci_port); 423 __func__, dev, idev, idev->isci_port);
440 424
441 if (isci_device != NULL) 425 isci_remote_device_stop(ihost, idev);
442 isci_remote_device_stop(isci_device);
443} 426}
444 427
445 428
@@ -462,7 +445,6 @@ int isci_remote_device_found(struct domain_device *domain_dev)
462 struct asd_sas_phy *sas_phy; 445 struct asd_sas_phy *sas_phy;
463 struct isci_remote_device *isci_device; 446 struct isci_remote_device *isci_device;
464 enum sci_status status; 447 enum sci_status status;
465 DECLARE_COMPLETION_ONSTACK(completion);
466 448
467 isci_host = isci_host_from_sas_ha(domain_dev->port->ha); 449 isci_host = isci_host_from_sas_ha(domain_dev->port->ha);
468 450
@@ -498,17 +480,10 @@ int isci_remote_device_found(struct domain_device *domain_dev)
498 spin_lock_irqsave(&isci_port->remote_device_lock, flags); 480 spin_lock_irqsave(&isci_port->remote_device_lock, flags);
499 list_add_tail(&isci_device->node, &isci_port->remote_dev_list); 481 list_add_tail(&isci_device->node, &isci_port->remote_dev_list);
500 482
501 /* for the device ready event. */ 483 set_bit(IDEV_START_PENDING, &isci_device->flags);
502 isci_device->completion = &completion;
503
504 status = isci_remote_device_construct(isci_port, isci_device); 484 status = isci_remote_device_construct(isci_port, isci_device);
505
506 spin_unlock_irqrestore(&isci_port->remote_device_lock, flags); 485 spin_unlock_irqrestore(&isci_port->remote_device_lock, flags);
507 486
508 /* wait for the device ready callback. */
509 wait_for_completion(isci_device->completion);
510 isci_device->completion = NULL;
511
512 dev_dbg(&isci_host->pdev->dev, 487 dev_dbg(&isci_host->pdev->dev,
513 "%s: isci_device = %p\n", 488 "%s: isci_device = %p\n",
514 __func__, isci_device); 489 __func__, isci_device);
@@ -524,6 +499,9 @@ int isci_remote_device_found(struct domain_device *domain_dev)
524 return -ENODEV; 499 return -ENODEV;
525 } 500 }
526 501
502 /* wait for the device ready callback. */
503 wait_for_device_start(isci_host, isci_device);
504
527 return 0; 505 return 0;
528} 506}
529/** 507/**
diff --git a/drivers/scsi/isci/remote_device.h b/drivers/scsi/isci/remote_device.h
index af03039c12f1..3c22137c9f65 100644
--- a/drivers/scsi/isci/remote_device.h
+++ b/drivers/scsi/isci/remote_device.h
@@ -61,12 +61,14 @@ struct scic_sds_remote_device;
61 61
62struct isci_remote_device { 62struct isci_remote_device {
63 enum isci_status status; 63 enum isci_status status;
64 #define IDEV_START_PENDING 0
65 #define IDEV_STOP_PENDING 1
66 unsigned long flags;
67 struct completion *cmp;
64 struct isci_port *isci_port; 68 struct isci_port *isci_port;
65 struct domain_device *domain_dev; 69 struct domain_device *domain_dev;
66 struct completion *completion;
67 struct list_head node; 70 struct list_head node;
68 struct list_head reqs_in_process; 71 struct list_head reqs_in_process;
69 struct work_struct stop_work;
70 spinlock_t state_lock; 72 spinlock_t state_lock;
71}; 73};
72 74
@@ -102,9 +104,8 @@ void isci_remote_device_stop_complete(
102 struct isci_remote_device *, 104 struct isci_remote_device *,
103 enum sci_status); 105 enum sci_status);
104 106
105enum sci_status isci_remote_device_stop( 107enum sci_status isci_remote_device_stop(struct isci_host *ihost,
106 struct isci_remote_device *isci_device); 108 struct isci_remote_device *idev);
107
108void isci_remote_device_nuke_requests( 109void isci_remote_device_nuke_requests(
109 struct isci_remote_device *isci_device); 110 struct isci_remote_device *isci_device);
110 111