aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/ibmvscsi/ibmvscsi.c
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 /drivers/scsi/ibmvscsi/ibmvscsi.c
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>
Diffstat (limited to 'drivers/scsi/ibmvscsi/ibmvscsi.c')
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c117
1 files changed, 89 insertions, 28 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);