aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/pm8001
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2011-01-24 08:57:29 -0500
committerJames Bottomley <James.Bottomley@suse.de>2011-02-12 11:31:03 -0500
commit429305e4650c5d3395c21ca183455a3f3e3568af (patch)
tree22f80762c0a2d3dcca39bde7aec19e5401a3d292 /drivers/scsi/pm8001
parenta684b8da35a429a246ec2a91e2742bdff5209709 (diff)
[SCSI] pm8001: simplify workqueue usage
pm8001 manages its own list of pending works and cancel them on device free. It is unnecessarily complex and has a race condition - the works are canceled but not synced, so the work could still be running during and after the data structures are freed. This patch simplifies workqueue usage. * A driver specific workqueue pm8001_wq is created to serve these work items. * To avoid confusion, the "queue" suffixes are dropped from work items and functions. * Delayed queueing was never used. pm8001_work now uses work_struct instead. * The driver no longer keeps track of pending works. All pm8001_works are queued to pm8001_wq and the workqueue is flushed as necessary. flush_scheduled_work() usage is removed during conversion. Signed-off-by: Tejun Heo <tj@kernel.org> Acked-by: Jack Wang <jack_wang@usish.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/pm8001')
-rw-r--r--drivers/scsi/pm8001/pm8001_hwi.c37
-rw-r--r--drivers/scsi/pm8001/pm8001_init.c27
-rw-r--r--drivers/scsi/pm8001/pm8001_sas.h10
3 files changed, 41 insertions, 33 deletions
diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c
index d8db0137c0c7..18b6c55cd08c 100644
--- a/drivers/scsi/pm8001/pm8001_hwi.c
+++ b/drivers/scsi/pm8001/pm8001_hwi.c
@@ -1382,53 +1382,50 @@ static u32 mpi_msg_consume(struct pm8001_hba_info *pm8001_ha,
1382 return MPI_IO_STATUS_BUSY; 1382 return MPI_IO_STATUS_BUSY;
1383} 1383}
1384 1384
1385static void pm8001_work_queue(struct work_struct *work) 1385static void pm8001_work_fn(struct work_struct *work)
1386{ 1386{
1387 struct delayed_work *dw = container_of(work, struct delayed_work, work); 1387 struct pm8001_work *pw = container_of(work, struct pm8001_work, work);
1388 struct pm8001_wq *wq = container_of(dw, struct pm8001_wq, work_q);
1389 struct pm8001_device *pm8001_dev; 1388 struct pm8001_device *pm8001_dev;
1390 struct domain_device *dev; 1389 struct domain_device *dev;
1391 1390
1392 switch (wq->handler) { 1391 switch (pw->handler) {
1393 case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS: 1392 case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS:
1394 pm8001_dev = wq->data; 1393 pm8001_dev = pw->data;
1395 dev = pm8001_dev->sas_device; 1394 dev = pm8001_dev->sas_device;
1396 pm8001_I_T_nexus_reset(dev); 1395 pm8001_I_T_nexus_reset(dev);
1397 break; 1396 break;
1398 case IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY: 1397 case IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY:
1399 pm8001_dev = wq->data; 1398 pm8001_dev = pw->data;
1400 dev = pm8001_dev->sas_device; 1399 dev = pm8001_dev->sas_device;
1401 pm8001_I_T_nexus_reset(dev); 1400 pm8001_I_T_nexus_reset(dev);
1402 break; 1401 break;
1403 case IO_DS_IN_ERROR: 1402 case IO_DS_IN_ERROR:
1404 pm8001_dev = wq->data; 1403 pm8001_dev = pw->data;
1405 dev = pm8001_dev->sas_device; 1404 dev = pm8001_dev->sas_device;
1406 pm8001_I_T_nexus_reset(dev); 1405 pm8001_I_T_nexus_reset(dev);
1407 break; 1406 break;
1408 case IO_DS_NON_OPERATIONAL: 1407 case IO_DS_NON_OPERATIONAL:
1409 pm8001_dev = wq->data; 1408 pm8001_dev = pw->data;
1410 dev = pm8001_dev->sas_device; 1409 dev = pm8001_dev->sas_device;
1411 pm8001_I_T_nexus_reset(dev); 1410 pm8001_I_T_nexus_reset(dev);
1412 break; 1411 break;
1413 } 1412 }
1414 list_del(&wq->entry); 1413 kfree(pw);
1415 kfree(wq);
1416} 1414}
1417 1415
1418static int pm8001_handle_event(struct pm8001_hba_info *pm8001_ha, void *data, 1416static int pm8001_handle_event(struct pm8001_hba_info *pm8001_ha, void *data,
1419 int handler) 1417 int handler)
1420{ 1418{
1421 struct pm8001_wq *wq; 1419 struct pm8001_work *pw;
1422 int ret = 0; 1420 int ret = 0;
1423 1421
1424 wq = kmalloc(sizeof(struct pm8001_wq), GFP_ATOMIC); 1422 pw = kmalloc(sizeof(struct pm8001_work), GFP_ATOMIC);
1425 if (wq) { 1423 if (pw) {
1426 wq->pm8001_ha = pm8001_ha; 1424 pw->pm8001_ha = pm8001_ha;
1427 wq->data = data; 1425 pw->data = data;
1428 wq->handler = handler; 1426 pw->handler = handler;
1429 INIT_DELAYED_WORK(&wq->work_q, pm8001_work_queue); 1427 INIT_WORK(&pw->work, pm8001_work_fn);
1430 list_add_tail(&wq->entry, &pm8001_ha->wq_list); 1428 queue_work(pm8001_wq, &pw->work);
1431 schedule_delayed_work(&wq->work_q, 0);
1432 } else 1429 } else
1433 ret = -ENOMEM; 1430 ret = -ENOMEM;
1434 1431
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
index b95285f3383f..002360da01e3 100644
--- a/drivers/scsi/pm8001/pm8001_init.c
+++ b/drivers/scsi/pm8001/pm8001_init.c
@@ -51,6 +51,8 @@ static int pm8001_id;
51 51
52LIST_HEAD(hba_list); 52LIST_HEAD(hba_list);
53 53
54struct workqueue_struct *pm8001_wq;
55
54/** 56/**
55 * The main structure which LLDD must register for scsi core. 57 * The main structure which LLDD must register for scsi core.
56 */ 58 */
@@ -134,7 +136,6 @@ static void __devinit pm8001_phy_init(struct pm8001_hba_info *pm8001_ha,
134static void pm8001_free(struct pm8001_hba_info *pm8001_ha) 136static void pm8001_free(struct pm8001_hba_info *pm8001_ha)
135{ 137{
136 int i; 138 int i;
137 struct pm8001_wq *wq;
138 139
139 if (!pm8001_ha) 140 if (!pm8001_ha)
140 return; 141 return;
@@ -150,8 +151,7 @@ static void pm8001_free(struct pm8001_hba_info *pm8001_ha)
150 PM8001_CHIP_DISP->chip_iounmap(pm8001_ha); 151 PM8001_CHIP_DISP->chip_iounmap(pm8001_ha);
151 if (pm8001_ha->shost) 152 if (pm8001_ha->shost)
152 scsi_host_put(pm8001_ha->shost); 153 scsi_host_put(pm8001_ha->shost);
153 list_for_each_entry(wq, &pm8001_ha->wq_list, entry) 154 flush_workqueue(pm8001_wq);
154 cancel_delayed_work(&wq->work_q);
155 kfree(pm8001_ha->tags); 155 kfree(pm8001_ha->tags);
156 kfree(pm8001_ha); 156 kfree(pm8001_ha);
157} 157}
@@ -381,7 +381,6 @@ pm8001_pci_alloc(struct pci_dev *pdev, u32 chip_id, struct Scsi_Host *shost)
381 pm8001_ha->sas = sha; 381 pm8001_ha->sas = sha;
382 pm8001_ha->shost = shost; 382 pm8001_ha->shost = shost;
383 pm8001_ha->id = pm8001_id++; 383 pm8001_ha->id = pm8001_id++;
384 INIT_LIST_HEAD(&pm8001_ha->wq_list);
385 pm8001_ha->logging_level = 0x01; 384 pm8001_ha->logging_level = 0x01;
386 sprintf(pm8001_ha->name, "%s%d", DRV_NAME, pm8001_ha->id); 385 sprintf(pm8001_ha->name, "%s%d", DRV_NAME, pm8001_ha->id);
387#ifdef PM8001_USE_TASKLET 386#ifdef PM8001_USE_TASKLET
@@ -758,7 +757,7 @@ static int pm8001_pci_suspend(struct pci_dev *pdev, pm_message_t state)
758 int i , pos; 757 int i , pos;
759 u32 device_state; 758 u32 device_state;
760 pm8001_ha = sha->lldd_ha; 759 pm8001_ha = sha->lldd_ha;
761 flush_scheduled_work(); 760 flush_workqueue(pm8001_wq);
762 scsi_block_requests(pm8001_ha->shost); 761 scsi_block_requests(pm8001_ha->shost);
763 pos = pci_find_capability(pdev, PCI_CAP_ID_PM); 762 pos = pci_find_capability(pdev, PCI_CAP_ID_PM);
764 if (pos == 0) { 763 if (pos == 0) {
@@ -870,17 +869,26 @@ static struct pci_driver pm8001_pci_driver = {
870 */ 869 */
871static int __init pm8001_init(void) 870static int __init pm8001_init(void)
872{ 871{
873 int rc; 872 int rc = -ENOMEM;
873
874 pm8001_wq = alloc_workqueue("pm8001", 0, 0);
875 if (!pm8001_wq)
876 goto err;
877
874 pm8001_id = 0; 878 pm8001_id = 0;
875 pm8001_stt = sas_domain_attach_transport(&pm8001_transport_ops); 879 pm8001_stt = sas_domain_attach_transport(&pm8001_transport_ops);
876 if (!pm8001_stt) 880 if (!pm8001_stt)
877 return -ENOMEM; 881 goto err_wq;
878 rc = pci_register_driver(&pm8001_pci_driver); 882 rc = pci_register_driver(&pm8001_pci_driver);
879 if (rc) 883 if (rc)
880 goto err_out; 884 goto err_tp;
881 return 0; 885 return 0;
882err_out: 886
887err_tp:
883 sas_release_transport(pm8001_stt); 888 sas_release_transport(pm8001_stt);
889err_wq:
890 destroy_workqueue(pm8001_wq);
891err:
884 return rc; 892 return rc;
885} 893}
886 894
@@ -888,6 +896,7 @@ static void __exit pm8001_exit(void)
888{ 896{
889 pci_unregister_driver(&pm8001_pci_driver); 897 pci_unregister_driver(&pm8001_pci_driver);
890 sas_release_transport(pm8001_stt); 898 sas_release_transport(pm8001_stt);
899 destroy_workqueue(pm8001_wq);
891} 900}
892 901
893module_init(pm8001_init); 902module_init(pm8001_init);
diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h
index 7f064f9ca828..bdb6b27dedd6 100644
--- a/drivers/scsi/pm8001/pm8001_sas.h
+++ b/drivers/scsi/pm8001/pm8001_sas.h
@@ -50,6 +50,7 @@
50#include <linux/dma-mapping.h> 50#include <linux/dma-mapping.h>
51#include <linux/pci.h> 51#include <linux/pci.h>
52#include <linux/interrupt.h> 52#include <linux/interrupt.h>
53#include <linux/workqueue.h>
53#include <scsi/libsas.h> 54#include <scsi/libsas.h>
54#include <scsi/scsi_tcq.h> 55#include <scsi/scsi_tcq.h>
55#include <scsi/sas_ata.h> 56#include <scsi/sas_ata.h>
@@ -379,18 +380,16 @@ struct pm8001_hba_info {
379#ifdef PM8001_USE_TASKLET 380#ifdef PM8001_USE_TASKLET
380 struct tasklet_struct tasklet; 381 struct tasklet_struct tasklet;
381#endif 382#endif
382 struct list_head wq_list;
383 u32 logging_level; 383 u32 logging_level;
384 u32 fw_status; 384 u32 fw_status;
385 const struct firmware *fw_image; 385 const struct firmware *fw_image;
386}; 386};
387 387
388struct pm8001_wq { 388struct pm8001_work {
389 struct delayed_work work_q; 389 struct work_struct work;
390 struct pm8001_hba_info *pm8001_ha; 390 struct pm8001_hba_info *pm8001_ha;
391 void *data; 391 void *data;
392 int handler; 392 int handler;
393 struct list_head entry;
394}; 393};
395 394
396struct pm8001_fw_image_header { 395struct pm8001_fw_image_header {
@@ -460,6 +459,9 @@ struct fw_control_ex {
460 void *param3; 459 void *param3;
461}; 460};
462 461
462/* pm8001 workqueue */
463extern struct workqueue_struct *pm8001_wq;
464
463/******************** function prototype *********************/ 465/******************** function prototype *********************/
464int pm8001_tag_alloc(struct pm8001_hba_info *pm8001_ha, u32 *tag_out); 466int pm8001_tag_alloc(struct pm8001_hba_info *pm8001_ha, u32 *tag_out);
465void pm8001_tag_init(struct pm8001_hba_info *pm8001_ha); 467void pm8001_tag_init(struct pm8001_hba_info *pm8001_ha);