aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian King <brking@linux.vnet.ibm.com>2010-06-17 14:56:00 -0400
committerJames Bottomley <James.Bottomley@suse.de>2010-07-27 13:03:46 -0400
commit0f33ece5bc3d5a9567b65cfbc736e8f206ecfc7b (patch)
tree4b271d2c1373e1882ecffa8f4baf247a9f578c15
parent06395193b20124663b83b2894da827aec7e9d920 (diff)
[SCSI] ibmvscsi: Fix softlockup on resume
This fixes a softlockup seen on resume. During resume, the CRQ must be reenabled. However, the H_ENABLE_CRQ hcall used to do this may return H_BUSY or H_LONG_BUSY. When this happens, the caller is expected to retry later. This patch changes a simple loop, which was causing the softlockup, to a loop at task level which sleeps between retries rather than simply spinning. Signed-off-by: Brian King <brking@linux.vnet.ibm.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c117
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.h4
-rw-r--r--drivers/scsi/ibmvscsi/rpa_vscsi.c16
3 files changed, 106 insertions, 31 deletions
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index aad35cc41e49..e50fad96329c 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -73,6 +73,7 @@
73#include <linux/slab.h> 73#include <linux/slab.h>
74#include <linux/of.h> 74#include <linux/of.h>
75#include <linux/pm.h> 75#include <linux/pm.h>
76#include <linux/kthread.h>
76#include <asm/firmware.h> 77#include <asm/firmware.h>
77#include <asm/vio.h> 78#include <asm/vio.h>
78#include <scsi/scsi.h> 79#include <scsi/scsi.h>
@@ -504,14 +505,8 @@ static void ibmvscsi_reset_host(struct ibmvscsi_host_data *hostdata)
504 atomic_set(&hostdata->request_limit, 0); 505 atomic_set(&hostdata->request_limit, 0);
505 506
506 purge_requests(hostdata, DID_ERROR); 507 purge_requests(hostdata, DID_ERROR);
507 if ((ibmvscsi_ops->reset_crq_queue(&hostdata->queue, hostdata)) || 508 hostdata->reset_crq = 1;
508 (ibmvscsi_ops->send_crq(hostdata, 0xC001000000000000LL, 0)) || 509 wake_up(&hostdata->work_wait_q);
509 (vio_enable_interrupts(to_vio_dev(hostdata->dev)))) {
510 atomic_set(&hostdata->request_limit, -1);
511 dev_err(hostdata->dev, "error after reset\n");
512 }
513
514 scsi_unblock_requests(hostdata->host);
515} 510}
516 511
517/** 512/**
@@ -1462,30 +1457,14 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
1462 /* We need to re-setup the interpartition connection */ 1457 /* We need to re-setup the interpartition connection */
1463 dev_info(hostdata->dev, "Re-enabling adapter!\n"); 1458 dev_info(hostdata->dev, "Re-enabling adapter!\n");
1464 hostdata->client_migrated = 1; 1459 hostdata->client_migrated = 1;
1460 hostdata->reenable_crq = 1;
1465 purge_requests(hostdata, DID_REQUEUE); 1461 purge_requests(hostdata, DID_REQUEUE);
1466 if ((ibmvscsi_ops->reenable_crq_queue(&hostdata->queue, 1462 wake_up(&hostdata->work_wait_q);
1467 hostdata)) ||
1468 (ibmvscsi_ops->send_crq(hostdata,
1469 0xC001000000000000LL, 0))) {
1470 atomic_set(&hostdata->request_limit,
1471 -1);
1472 dev_err(hostdata->dev, "error after enable\n");
1473 }
1474 } else { 1463 } else {
1475 dev_err(hostdata->dev, "Virtual adapter failed rc %d!\n", 1464 dev_err(hostdata->dev, "Virtual adapter failed rc %d!\n",
1476 crq->format); 1465 crq->format);
1477 1466 ibmvscsi_reset_host(hostdata);
1478 purge_requests(hostdata, DID_ERROR);
1479 if ((ibmvscsi_ops->reset_crq_queue(&hostdata->queue,
1480 hostdata)) ||
1481 (ibmvscsi_ops->send_crq(hostdata,
1482 0xC001000000000000LL, 0))) {
1483 atomic_set(&hostdata->request_limit,
1484 -1);
1485 dev_err(hostdata->dev, "error after reset\n");
1486 }
1487 } 1467 }
1488 scsi_unblock_requests(hostdata->host);
1489 return; 1468 return;
1490 case 0x80: /* real payload */ 1469 case 0x80: /* real payload */
1491 break; 1470 break;
@@ -1850,6 +1829,75 @@ static unsigned long ibmvscsi_get_desired_dma(struct vio_dev *vdev)
1850 return desired_io; 1829 return desired_io;
1851} 1830}
1852 1831
1832static void ibmvscsi_do_work(struct ibmvscsi_host_data *hostdata)
1833{
1834 int rc;
1835 char *action = "reset";
1836
1837 if (hostdata->reset_crq) {
1838 smp_rmb();
1839 hostdata->reset_crq = 0;
1840
1841 rc = ibmvscsi_ops->reset_crq_queue(&hostdata->queue, hostdata);
1842 if (!rc)
1843 rc = ibmvscsi_ops->send_crq(hostdata, 0xC001000000000000LL, 0);
1844 if (!rc)
1845 rc = vio_enable_interrupts(to_vio_dev(hostdata->dev));
1846 } else if (hostdata->reenable_crq) {
1847 smp_rmb();
1848 action = "enable";
1849 rc = ibmvscsi_ops->reenable_crq_queue(&hostdata->queue, hostdata);
1850 hostdata->reenable_crq = 0;
1851 if (!rc)
1852 rc = ibmvscsi_ops->send_crq(hostdata, 0xC001000000000000LL, 0);
1853 } else
1854 return;
1855
1856 if (rc) {
1857 atomic_set(&hostdata->request_limit, -1);
1858 dev_err(hostdata->dev, "error after %s\n", action);
1859 }
1860
1861 scsi_unblock_requests(hostdata->host);
1862}
1863
1864static int ibmvscsi_work_to_do(struct ibmvscsi_host_data *hostdata)
1865{
1866 if (kthread_should_stop())
1867 return 1;
1868 else if (hostdata->reset_crq) {
1869 smp_rmb();
1870 return 1;
1871 } else if (hostdata->reenable_crq) {
1872 smp_rmb();
1873 return 1;
1874 }
1875
1876 return 0;
1877}
1878
1879static int ibmvscsi_work(void *data)
1880{
1881 struct ibmvscsi_host_data *hostdata = data;
1882 int rc;
1883
1884 set_user_nice(current, -20);
1885
1886 while (1) {
1887 rc = wait_event_interruptible(hostdata->work_wait_q,
1888 ibmvscsi_work_to_do(hostdata));
1889
1890 BUG_ON(rc);
1891
1892 if (kthread_should_stop())
1893 break;
1894
1895 ibmvscsi_do_work(hostdata);
1896 }
1897
1898 return 0;
1899}
1900
1853/** 1901/**
1854 * Called by bus code for each adapter 1902 * Called by bus code for each adapter
1855 */ 1903 */
@@ -1875,6 +1923,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
1875 hostdata = shost_priv(host); 1923 hostdata = shost_priv(host);
1876 memset(hostdata, 0x00, sizeof(*hostdata)); 1924 memset(hostdata, 0x00, sizeof(*hostdata));
1877 INIT_LIST_HEAD(&hostdata->sent); 1925 INIT_LIST_HEAD(&hostdata->sent);
1926 init_waitqueue_head(&hostdata->work_wait_q);
1878 hostdata->host = host; 1927 hostdata->host = host;
1879 hostdata->dev = dev; 1928 hostdata->dev = dev;
1880 atomic_set(&hostdata->request_limit, -1); 1929 atomic_set(&hostdata->request_limit, -1);
@@ -1885,10 +1934,19 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
1885 goto persist_bufs_failed; 1934 goto persist_bufs_failed;
1886 } 1935 }
1887 1936
1937 hostdata->work_thread = kthread_run(ibmvscsi_work, hostdata, "%s_%d",
1938 "ibmvscsi", host->host_no);
1939
1940 if (IS_ERR(hostdata->work_thread)) {
1941 dev_err(&vdev->dev, "couldn't initialize kthread. rc=%ld\n",
1942 PTR_ERR(hostdata->work_thread));
1943 goto init_crq_failed;
1944 }
1945
1888 rc = ibmvscsi_ops->init_crq_queue(&hostdata->queue, hostdata, max_events); 1946 rc = ibmvscsi_ops->init_crq_queue(&hostdata->queue, hostdata, max_events);
1889 if (rc != 0 && rc != H_RESOURCE) { 1947 if (rc != 0 && rc != H_RESOURCE) {
1890 dev_err(&vdev->dev, "couldn't initialize crq. rc=%d\n", rc); 1948 dev_err(&vdev->dev, "couldn't initialize crq. rc=%d\n", rc);
1891 goto init_crq_failed; 1949 goto kill_kthread;
1892 } 1950 }
1893 if (initialize_event_pool(&hostdata->pool, max_events, hostdata) != 0) { 1951 if (initialize_event_pool(&hostdata->pool, max_events, hostdata) != 0) {
1894 dev_err(&vdev->dev, "couldn't initialize event pool\n"); 1952 dev_err(&vdev->dev, "couldn't initialize event pool\n");
@@ -1944,6 +2002,8 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
1944 release_event_pool(&hostdata->pool, hostdata); 2002 release_event_pool(&hostdata->pool, hostdata);
1945 init_pool_failed: 2003 init_pool_failed:
1946 ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata, max_events); 2004 ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata, max_events);
2005 kill_kthread:
2006 kthread_stop(hostdata->work_thread);
1947 init_crq_failed: 2007 init_crq_failed:
1948 unmap_persist_bufs(hostdata); 2008 unmap_persist_bufs(hostdata);
1949 persist_bufs_failed: 2009 persist_bufs_failed:
@@ -1960,6 +2020,7 @@ static int ibmvscsi_remove(struct vio_dev *vdev)
1960 ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata, 2020 ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata,
1961 max_events); 2021 max_events);
1962 2022
2023 kthread_stop(hostdata->work_thread);
1963 srp_remove_host(hostdata->host); 2024 srp_remove_host(hostdata->host);
1964 scsi_remove_host(hostdata->host); 2025 scsi_remove_host(hostdata->host);
1965 scsi_host_put(hostdata->host); 2026 scsi_host_put(hostdata->host);
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h
index 9cb7c6a773e1..02197a2b22b9 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.h
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.h
@@ -91,12 +91,16 @@ struct event_pool {
91struct ibmvscsi_host_data { 91struct ibmvscsi_host_data {
92 atomic_t request_limit; 92 atomic_t request_limit;
93 int client_migrated; 93 int client_migrated;
94 int reset_crq;
95 int reenable_crq;
94 struct device *dev; 96 struct device *dev;
95 struct event_pool pool; 97 struct event_pool pool;
96 struct crq_queue queue; 98 struct crq_queue queue;
97 struct tasklet_struct srp_task; 99 struct tasklet_struct srp_task;
98 struct list_head sent; 100 struct list_head sent;
99 struct Scsi_Host *host; 101 struct Scsi_Host *host;
102 struct task_struct *work_thread;
103 wait_queue_head_t work_wait_q;
100 struct mad_adapter_info_data madapter_info; 104 struct mad_adapter_info_data madapter_info;
101 struct capabilities caps; 105 struct capabilities caps;
102 dma_addr_t caps_addr; 106 dma_addr_t caps_addr;
diff --git a/drivers/scsi/ibmvscsi/rpa_vscsi.c b/drivers/scsi/ibmvscsi/rpa_vscsi.c
index 989b9a8ba72d..f48ae0190d95 100644
--- a/drivers/scsi/ibmvscsi/rpa_vscsi.c
+++ b/drivers/scsi/ibmvscsi/rpa_vscsi.c
@@ -31,6 +31,7 @@
31#include <asm/prom.h> 31#include <asm/prom.h>
32#include <asm/iommu.h> 32#include <asm/iommu.h>
33#include <asm/hvcall.h> 33#include <asm/hvcall.h>
34#include <linux/delay.h>
34#include <linux/dma-mapping.h> 35#include <linux/dma-mapping.h>
35#include <linux/gfp.h> 36#include <linux/gfp.h>
36#include <linux/interrupt.h> 37#include <linux/interrupt.h>
@@ -71,11 +72,13 @@ static void rpavscsi_release_crq_queue(struct crq_queue *queue,
71 struct ibmvscsi_host_data *hostdata, 72 struct ibmvscsi_host_data *hostdata,
72 int max_requests) 73 int max_requests)
73{ 74{
74 long rc; 75 long rc = 0;
75 struct vio_dev *vdev = to_vio_dev(hostdata->dev); 76 struct vio_dev *vdev = to_vio_dev(hostdata->dev);
76 free_irq(vdev->irq, (void *)hostdata); 77 free_irq(vdev->irq, (void *)hostdata);
77 tasklet_kill(&hostdata->srp_task); 78 tasklet_kill(&hostdata->srp_task);
78 do { 79 do {
80 if (rc)
81 msleep(100);
79 rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); 82 rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
80 } while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc))); 83 } while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
81 dma_unmap_single(hostdata->dev, 84 dma_unmap_single(hostdata->dev,
@@ -200,11 +203,13 @@ static void set_adapter_info(struct ibmvscsi_host_data *hostdata)
200static int rpavscsi_reset_crq_queue(struct crq_queue *queue, 203static int rpavscsi_reset_crq_queue(struct crq_queue *queue,
201 struct ibmvscsi_host_data *hostdata) 204 struct ibmvscsi_host_data *hostdata)
202{ 205{
203 int rc; 206 int rc = 0;
204 struct vio_dev *vdev = to_vio_dev(hostdata->dev); 207 struct vio_dev *vdev = to_vio_dev(hostdata->dev);
205 208
206 /* Close the CRQ */ 209 /* Close the CRQ */
207 do { 210 do {
211 if (rc)
212 msleep(100);
208 rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); 213 rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
209 } while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc))); 214 } while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
210 215
@@ -301,7 +306,10 @@ static int rpavscsi_init_crq_queue(struct crq_queue *queue,
301 306
302 req_irq_failed: 307 req_irq_failed:
303 tasklet_kill(&hostdata->srp_task); 308 tasklet_kill(&hostdata->srp_task);
309 rc = 0;
304 do { 310 do {
311 if (rc)
312 msleep(100);
305 rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); 313 rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
306 } while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc))); 314 } while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
307 reg_crq_failed: 315 reg_crq_failed:
@@ -323,11 +331,13 @@ static int rpavscsi_init_crq_queue(struct crq_queue *queue,
323static int rpavscsi_reenable_crq_queue(struct crq_queue *queue, 331static int rpavscsi_reenable_crq_queue(struct crq_queue *queue,
324 struct ibmvscsi_host_data *hostdata) 332 struct ibmvscsi_host_data *hostdata)
325{ 333{
326 int rc; 334 int rc = 0;
327 struct vio_dev *vdev = to_vio_dev(hostdata->dev); 335 struct vio_dev *vdev = to_vio_dev(hostdata->dev);
328 336
329 /* Re-enable the CRQ */ 337 /* Re-enable the CRQ */
330 do { 338 do {
339 if (rc)
340 msleep(100);
331 rc = plpar_hcall_norets(H_ENABLE_CRQ, vdev->unit_address); 341 rc = plpar_hcall_norets(H_ENABLE_CRQ, vdev->unit_address);
332 } while ((rc == H_IN_PROGRESS) || (rc == H_BUSY) || (H_IS_LONG_BUSY(rc))); 342 } while ((rc == H_IN_PROGRESS) || (rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
333 343