diff options
-rw-r--r-- | drivers/scsi/isci/host.c | 21 | ||||
-rw-r--r-- | drivers/scsi/isci/host.h | 17 | ||||
-rw-r--r-- | drivers/scsi/isci/init.c | 27 | ||||
-rw-r--r-- | drivers/scsi/isci/isci.h | 1 | ||||
-rw-r--r-- | drivers/scsi/isci/remote_device.c | 73 | ||||
-rw-r--r-- | drivers/scsi/isci/remote_device.h | 2 |
6 files changed, 68 insertions, 73 deletions
diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c index 8d255666a657..ae5d46022073 100644 --- a/drivers/scsi/isci/host.c +++ b/drivers/scsi/isci/host.c | |||
@@ -378,8 +378,7 @@ static void __iomem *smu_base(struct isci_host *isci_host) | |||
378 | 378 | ||
379 | int isci_host_init(struct isci_host *isci_host) | 379 | int isci_host_init(struct isci_host *isci_host) |
380 | { | 380 | { |
381 | int err = 0; | 381 | int err = 0, i; |
382 | int index = 0; | ||
383 | enum sci_status status; | 382 | enum sci_status status; |
384 | struct scic_sds_controller *controller; | 383 | struct scic_sds_controller *controller; |
385 | union scic_oem_parameters scic_oem_params; | 384 | union scic_oem_parameters scic_oem_params; |
@@ -509,13 +508,19 @@ int isci_host_init(struct isci_host *isci_host) | |||
509 | if (!isci_host->dma_pool) | 508 | if (!isci_host->dma_pool) |
510 | return -ENOMEM; | 509 | return -ENOMEM; |
511 | 510 | ||
512 | for (index = 0; index < SCI_MAX_PORTS; index++) | 511 | for (i = 0; i < SCI_MAX_PORTS; i++) |
513 | isci_port_init(&isci_host->isci_ports[index], | 512 | isci_port_init(&isci_host->isci_ports[i], isci_host, i); |
514 | isci_host, | ||
515 | index); | ||
516 | 513 | ||
517 | for (index = 0; index < SCI_MAX_PHYS; index++) | 514 | for (i = 0; i < SCI_MAX_PHYS; i++) |
518 | isci_phy_init(&isci_host->phys[index], isci_host, index); | 515 | isci_phy_init(&isci_host->phys[i], isci_host, i); |
516 | |||
517 | for (i = 0; i < SCI_MAX_REMOTE_DEVICES; i++) { | ||
518 | struct isci_remote_device *idev = idev_by_id(isci_host, i); | ||
519 | |||
520 | INIT_LIST_HEAD(&idev->reqs_in_process); | ||
521 | INIT_LIST_HEAD(&idev->node); | ||
522 | spin_lock_init(&idev->state_lock); | ||
523 | } | ||
519 | 524 | ||
520 | return 0; | 525 | return 0; |
521 | } | 526 | } |
diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h index 6a6304c06976..3c69f1ffb1c3 100644 --- a/drivers/scsi/isci/host.h +++ b/drivers/scsi/isci/host.h | |||
@@ -61,6 +61,7 @@ | |||
61 | /*#include "task.h"*/ | 61 | /*#include "task.h"*/ |
62 | #include "timers.h" | 62 | #include "timers.h" |
63 | #include "remote_device.h" | 63 | #include "remote_device.h" |
64 | #include "scic_remote_device.h" | ||
64 | 65 | ||
65 | #define DRV_NAME "isci" | 66 | #define DRV_NAME "isci" |
66 | #define SCI_PCI_BAR_COUNT 2 | 67 | #define SCI_PCI_BAR_COUNT 2 |
@@ -117,8 +118,18 @@ struct isci_host { | |||
117 | struct list_head requests_to_complete; | 118 | struct list_head requests_to_complete; |
118 | struct list_head requests_to_abort; | 119 | struct list_head requests_to_abort; |
119 | spinlock_t scic_lock; | 120 | spinlock_t scic_lock; |
121 | |||
122 | /* careful only access this via idev_by_id */ | ||
123 | struct isci_remote_device devices[0]; | ||
120 | }; | 124 | }; |
121 | 125 | ||
126 | static inline struct isci_remote_device *idev_by_id(struct isci_host *ihost, int i) | ||
127 | { | ||
128 | void *p = ihost->devices; | ||
129 | |||
130 | return p + i * (sizeof(struct isci_remote_device) + | ||
131 | scic_remote_device_get_object_size()); | ||
132 | } | ||
122 | 133 | ||
123 | /** | 134 | /** |
124 | * struct isci_pci_info - This class represents the pci function containing the | 135 | * struct isci_pci_info - This class represents the pci function containing the |
@@ -219,11 +230,7 @@ static inline void wait_for_device_start(struct isci_host *ihost, struct isci_re | |||
219 | 230 | ||
220 | static inline void wait_for_device_stop(struct isci_host *ihost, struct isci_remote_device *idev) | 231 | static inline void wait_for_device_stop(struct isci_host *ihost, struct isci_remote_device *idev) |
221 | { | 232 | { |
222 | /* todo switch to: | 233 | wait_event(ihost->eventq, !test_bit(IDEV_STOP_PENDING, &idev->flags)); |
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 | } | 234 | } |
228 | 235 | ||
229 | /** | 236 | /** |
diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c index f1b8a51dd49f..2838beff43b8 100644 --- a/drivers/scsi/isci/init.c +++ b/drivers/scsi/isci/init.c | |||
@@ -64,7 +64,6 @@ | |||
64 | #include "sci_environment.h" | 64 | #include "sci_environment.h" |
65 | 65 | ||
66 | static struct scsi_transport_template *isci_transport_template; | 66 | static struct scsi_transport_template *isci_transport_template; |
67 | struct kmem_cache *isci_kmem_cache; | ||
68 | 67 | ||
69 | static DEFINE_PCI_DEVICE_TABLE(isci_id_table) = { | 68 | static DEFINE_PCI_DEVICE_TABLE(isci_id_table) = { |
70 | { PCI_VDEVICE(INTEL, 0x1D61),}, | 69 | { PCI_VDEVICE(INTEL, 0x1D61),}, |
@@ -443,7 +442,10 @@ static struct isci_host *isci_host_alloc(struct pci_dev *pdev, int id) | |||
443 | struct Scsi_Host *shost; | 442 | struct Scsi_Host *shost; |
444 | int err; | 443 | int err; |
445 | 444 | ||
446 | isci_host = devm_kzalloc(&pdev->dev, sizeof(*isci_host), GFP_KERNEL); | 445 | isci_host = devm_kzalloc(&pdev->dev, sizeof(*isci_host) + |
446 | SCI_MAX_REMOTE_DEVICES * | ||
447 | (sizeof(struct isci_remote_device) + | ||
448 | scic_remote_device_get_object_size()), GFP_KERNEL); | ||
447 | if (!isci_host) | 449 | if (!isci_host) |
448 | return NULL; | 450 | return NULL; |
449 | 451 | ||
@@ -656,31 +658,17 @@ static void __devexit isci_pci_remove(struct pci_dev *pdev) | |||
656 | 658 | ||
657 | static __init int isci_init(void) | 659 | static __init int isci_init(void) |
658 | { | 660 | { |
659 | int err = -ENOMEM; | 661 | int err; |
660 | 662 | ||
661 | pr_info("%s: Intel(R) C600 SAS Controller Driver\n", DRV_NAME); | 663 | pr_info("%s: Intel(R) C600 SAS Controller Driver\n", DRV_NAME); |
662 | 664 | ||
663 | isci_kmem_cache = kmem_cache_create(DRV_NAME, | ||
664 | sizeof(struct isci_remote_device) + | ||
665 | scic_remote_device_get_object_size(), | ||
666 | 0, 0, NULL); | ||
667 | if (!isci_kmem_cache) | ||
668 | return err; | ||
669 | |||
670 | isci_transport_template = sas_domain_attach_transport(&isci_transport_ops); | 665 | isci_transport_template = sas_domain_attach_transport(&isci_transport_ops); |
671 | if (!isci_transport_template) | 666 | if (!isci_transport_template) |
672 | goto err_kmem; | 667 | return -ENOMEM; |
673 | 668 | ||
674 | err = pci_register_driver(&isci_pci_driver); | 669 | err = pci_register_driver(&isci_pci_driver); |
675 | if (err) | 670 | if (err) |
676 | goto err_sas; | 671 | sas_release_transport(isci_transport_template); |
677 | |||
678 | return 0; | ||
679 | |||
680 | err_sas: | ||
681 | sas_release_transport(isci_transport_template); | ||
682 | err_kmem: | ||
683 | kmem_cache_destroy(isci_kmem_cache); | ||
684 | 672 | ||
685 | return err; | 673 | return err; |
686 | } | 674 | } |
@@ -689,7 +677,6 @@ static __exit void isci_exit(void) | |||
689 | { | 677 | { |
690 | pci_unregister_driver(&isci_pci_driver); | 678 | pci_unregister_driver(&isci_pci_driver); |
691 | sas_release_transport(isci_transport_template); | 679 | sas_release_transport(isci_transport_template); |
692 | kmem_cache_destroy(isci_kmem_cache); | ||
693 | } | 680 | } |
694 | 681 | ||
695 | MODULE_LICENSE("Dual BSD/GPL"); | 682 | MODULE_LICENSE("Dual BSD/GPL"); |
diff --git a/drivers/scsi/isci/isci.h b/drivers/scsi/isci/isci.h index 9b9aa50954ce..24c67b039d4a 100644 --- a/drivers/scsi/isci/isci.h +++ b/drivers/scsi/isci/isci.h | |||
@@ -89,7 +89,6 @@ | |||
89 | #include "task.h" | 89 | #include "task.h" |
90 | #include "sata.h" | 90 | #include "sata.h" |
91 | 91 | ||
92 | extern struct kmem_cache *isci_kmem_cache; | ||
93 | extern struct isci_firmware *isci_firmware; | 92 | extern struct isci_firmware *isci_firmware; |
94 | 93 | ||
95 | #define ISCI_FW_NAME "isci/isci_firmware.bin" | 94 | #define ISCI_FW_NAME "isci/isci_firmware.bin" |
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; |
diff --git a/drivers/scsi/isci/remote_device.h b/drivers/scsi/isci/remote_device.h index 3c22137c9f65..f45a5f064fce 100644 --- a/drivers/scsi/isci/remote_device.h +++ b/drivers/scsi/isci/remote_device.h | |||
@@ -63,8 +63,8 @@ struct isci_remote_device { | |||
63 | enum isci_status status; | 63 | enum isci_status status; |
64 | #define IDEV_START_PENDING 0 | 64 | #define IDEV_START_PENDING 0 |
65 | #define IDEV_STOP_PENDING 1 | 65 | #define IDEV_STOP_PENDING 1 |
66 | #define IDEV_ALLOCATED 2 | ||
66 | unsigned long flags; | 67 | unsigned long flags; |
67 | struct completion *cmp; | ||
68 | struct isci_port *isci_port; | 68 | struct isci_port *isci_port; |
69 | struct domain_device *domain_dev; | 69 | struct domain_device *domain_dev; |
70 | struct list_head node; | 70 | struct list_head node; |