diff options
-rw-r--r-- | drivers/scsi/isci/events.c | 30 | ||||
-rw-r--r-- | drivers/scsi/isci/host.c | 2 | ||||
-rw-r--r-- | drivers/scsi/isci/host.h | 13 | ||||
-rw-r--r-- | drivers/scsi/isci/remote_device.c | 98 | ||||
-rw-r--r-- | drivers/scsi/isci/remote_device.h | 11 |
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 | */ |
537 | void isci_event_remote_device_stop_complete( | 537 | void 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 | ||
215 | static 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 | |||
220 | static 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 | */ |
286 | void isci_remote_device_ready(struct isci_remote_device *isci_device) | 290 | void 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 | */ |
388 | enum sci_status isci_remote_device_stop( | 380 | enum 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 | */ |
431 | void isci_remote_device_gone( | 416 | void 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 | ||
62 | struct isci_remote_device { | 62 | struct 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 | ||
105 | enum sci_status isci_remote_device_stop( | 107 | enum sci_status isci_remote_device_stop(struct isci_host *ihost, |
106 | struct isci_remote_device *isci_device); | 108 | struct isci_remote_device *idev); |
107 | |||
108 | void isci_remote_device_nuke_requests( | 109 | void isci_remote_device_nuke_requests( |
109 | struct isci_remote_device *isci_device); | 110 | struct isci_remote_device *isci_device); |
110 | 111 | ||