diff options
Diffstat (limited to 'drivers/scsi/ibmvscsi/ibmvfc.c')
-rw-r--r-- | drivers/scsi/ibmvscsi/ibmvfc.c | 293 |
1 files changed, 196 insertions, 97 deletions
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index 7650707a40de..44f202f33101 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c | |||
@@ -121,6 +121,7 @@ static const struct { | |||
121 | { IBMVFC_VIOS_FAILURE, IBMVFC_TRANS_CANCELLED, DID_ABORT, 0, 1, "transaction cancelled" }, | 121 | { IBMVFC_VIOS_FAILURE, IBMVFC_TRANS_CANCELLED, DID_ABORT, 0, 1, "transaction cancelled" }, |
122 | { IBMVFC_VIOS_FAILURE, IBMVFC_TRANS_CANCELLED_IMPLICIT, DID_ABORT, 0, 1, "transaction cancelled implicit" }, | 122 | { IBMVFC_VIOS_FAILURE, IBMVFC_TRANS_CANCELLED_IMPLICIT, DID_ABORT, 0, 1, "transaction cancelled implicit" }, |
123 | { IBMVFC_VIOS_FAILURE, IBMVFC_INSUFFICIENT_RESOURCE, DID_REQUEUE, 1, 1, "insufficient resources" }, | 123 | { IBMVFC_VIOS_FAILURE, IBMVFC_INSUFFICIENT_RESOURCE, DID_REQUEUE, 1, 1, "insufficient resources" }, |
124 | { IBMVFC_VIOS_FAILURE, IBMVFC_PLOGI_REQUIRED, DID_ERROR, 0, 1, "port login required" }, | ||
124 | { IBMVFC_VIOS_FAILURE, IBMVFC_COMMAND_FAILED, DID_ERROR, 1, 1, "command failed" }, | 125 | { IBMVFC_VIOS_FAILURE, IBMVFC_COMMAND_FAILED, DID_ERROR, 1, 1, "command failed" }, |
125 | 126 | ||
126 | { IBMVFC_FC_FAILURE, IBMVFC_INVALID_ELS_CMD_CODE, DID_ERROR, 0, 1, "invalid ELS command code" }, | 127 | { IBMVFC_FC_FAILURE, IBMVFC_INVALID_ELS_CMD_CODE, DID_ERROR, 0, 1, "invalid ELS command code" }, |
@@ -278,13 +279,6 @@ static int ibmvfc_get_err_result(struct ibmvfc_cmd *vfc_cmd) | |||
278 | rsp->data.info.rsp_code)) | 279 | rsp->data.info.rsp_code)) |
279 | return DID_ERROR << 16; | 280 | return DID_ERROR << 16; |
280 | 281 | ||
281 | if (!vfc_cmd->status) { | ||
282 | if (rsp->flags & FCP_RESID_OVER) | ||
283 | return rsp->scsi_status | (DID_ERROR << 16); | ||
284 | else | ||
285 | return rsp->scsi_status | (DID_OK << 16); | ||
286 | } | ||
287 | |||
288 | err = ibmvfc_get_err_index(vfc_cmd->status, vfc_cmd->error); | 282 | err = ibmvfc_get_err_index(vfc_cmd->status, vfc_cmd->error); |
289 | if (err >= 0) | 283 | if (err >= 0) |
290 | return rsp->scsi_status | (cmd_status[err].result << 16); | 284 | return rsp->scsi_status | (cmd_status[err].result << 16); |
@@ -503,6 +497,7 @@ static void ibmvfc_set_host_action(struct ibmvfc_host *vhost, | |||
503 | case IBMVFC_HOST_ACTION_INIT: | 497 | case IBMVFC_HOST_ACTION_INIT: |
504 | case IBMVFC_HOST_ACTION_TGT_DEL: | 498 | case IBMVFC_HOST_ACTION_TGT_DEL: |
505 | case IBMVFC_HOST_ACTION_QUERY_TGTS: | 499 | case IBMVFC_HOST_ACTION_QUERY_TGTS: |
500 | case IBMVFC_HOST_ACTION_TGT_DEL_FAILED: | ||
506 | case IBMVFC_HOST_ACTION_TGT_ADD: | 501 | case IBMVFC_HOST_ACTION_TGT_ADD: |
507 | case IBMVFC_HOST_ACTION_NONE: | 502 | case IBMVFC_HOST_ACTION_NONE: |
508 | default: | 503 | default: |
@@ -566,7 +561,7 @@ static void ibmvfc_init_host(struct ibmvfc_host *vhost, int relogin) | |||
566 | struct ibmvfc_target *tgt; | 561 | struct ibmvfc_target *tgt; |
567 | 562 | ||
568 | if (vhost->action == IBMVFC_HOST_ACTION_INIT_WAIT) { | 563 | if (vhost->action == IBMVFC_HOST_ACTION_INIT_WAIT) { |
569 | if (++vhost->init_retries > IBMVFC_MAX_INIT_RETRIES) { | 564 | if (++vhost->init_retries > IBMVFC_MAX_HOST_INIT_RETRIES) { |
570 | dev_err(vhost->dev, | 565 | dev_err(vhost->dev, |
571 | "Host initialization retries exceeded. Taking adapter offline\n"); | 566 | "Host initialization retries exceeded. Taking adapter offline\n"); |
572 | ibmvfc_link_down(vhost, IBMVFC_HOST_OFFLINE); | 567 | ibmvfc_link_down(vhost, IBMVFC_HOST_OFFLINE); |
@@ -765,6 +760,9 @@ static void ibmvfc_scsi_eh_done(struct ibmvfc_event *evt) | |||
765 | cmnd->scsi_done(cmnd); | 760 | cmnd->scsi_done(cmnd); |
766 | } | 761 | } |
767 | 762 | ||
763 | if (evt->eh_comp) | ||
764 | complete(evt->eh_comp); | ||
765 | |||
768 | ibmvfc_free_event(evt); | 766 | ibmvfc_free_event(evt); |
769 | } | 767 | } |
770 | 768 | ||
@@ -847,11 +845,12 @@ static void ibmvfc_reset_host(struct ibmvfc_host *vhost) | |||
847 | static void ibmvfc_retry_host_init(struct ibmvfc_host *vhost) | 845 | static void ibmvfc_retry_host_init(struct ibmvfc_host *vhost) |
848 | { | 846 | { |
849 | if (vhost->action == IBMVFC_HOST_ACTION_INIT_WAIT) { | 847 | if (vhost->action == IBMVFC_HOST_ACTION_INIT_WAIT) { |
850 | if (++vhost->init_retries > IBMVFC_MAX_INIT_RETRIES) { | 848 | vhost->delay_init = 1; |
849 | if (++vhost->init_retries > IBMVFC_MAX_HOST_INIT_RETRIES) { | ||
851 | dev_err(vhost->dev, | 850 | dev_err(vhost->dev, |
852 | "Host initialization retries exceeded. Taking adapter offline\n"); | 851 | "Host initialization retries exceeded. Taking adapter offline\n"); |
853 | ibmvfc_link_down(vhost, IBMVFC_HOST_OFFLINE); | 852 | ibmvfc_link_down(vhost, IBMVFC_HOST_OFFLINE); |
854 | } else if (vhost->init_retries == IBMVFC_MAX_INIT_RETRIES) | 853 | } else if (vhost->init_retries == IBMVFC_MAX_HOST_INIT_RETRIES) |
855 | __ibmvfc_reset_host(vhost); | 854 | __ibmvfc_reset_host(vhost); |
856 | else | 855 | else |
857 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT); | 856 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT); |
@@ -1252,6 +1251,7 @@ static void ibmvfc_init_event(struct ibmvfc_event *evt, | |||
1252 | evt->sync_iu = NULL; | 1251 | evt->sync_iu = NULL; |
1253 | evt->crq.format = format; | 1252 | evt->crq.format = format; |
1254 | evt->done = done; | 1253 | evt->done = done; |
1254 | evt->eh_comp = NULL; | ||
1255 | } | 1255 | } |
1256 | 1256 | ||
1257 | /** | 1257 | /** |
@@ -1381,6 +1381,8 @@ static int ibmvfc_send_event(struct ibmvfc_event *evt, | |||
1381 | add_timer(&evt->timer); | 1381 | add_timer(&evt->timer); |
1382 | } | 1382 | } |
1383 | 1383 | ||
1384 | mb(); | ||
1385 | |||
1384 | if ((rc = ibmvfc_send_crq(vhost, crq_as_u64[0], crq_as_u64[1]))) { | 1386 | if ((rc = ibmvfc_send_crq(vhost, crq_as_u64[0], crq_as_u64[1]))) { |
1385 | list_del(&evt->queue); | 1387 | list_del(&evt->queue); |
1386 | del_timer(&evt->timer); | 1388 | del_timer(&evt->timer); |
@@ -1477,6 +1479,11 @@ static void ibmvfc_scsi_done(struct ibmvfc_event *evt) | |||
1477 | sense_len = SCSI_SENSE_BUFFERSIZE - rsp_len; | 1479 | sense_len = SCSI_SENSE_BUFFERSIZE - rsp_len; |
1478 | if ((rsp->flags & FCP_SNS_LEN_VALID) && rsp->fcp_sense_len && rsp_len <= 8) | 1480 | if ((rsp->flags & FCP_SNS_LEN_VALID) && rsp->fcp_sense_len && rsp_len <= 8) |
1479 | memcpy(cmnd->sense_buffer, rsp->data.sense + rsp_len, sense_len); | 1481 | memcpy(cmnd->sense_buffer, rsp->data.sense + rsp_len, sense_len); |
1482 | if ((vfc_cmd->status & IBMVFC_VIOS_FAILURE) && (vfc_cmd->error == IBMVFC_PLOGI_REQUIRED)) | ||
1483 | ibmvfc_reinit_host(evt->vhost); | ||
1484 | |||
1485 | if (!cmnd->result && (!scsi_get_resid(cmnd) || (rsp->flags & FCP_RESID_OVER))) | ||
1486 | cmnd->result = (DID_ERROR << 16); | ||
1480 | 1487 | ||
1481 | ibmvfc_log_error(evt); | 1488 | ibmvfc_log_error(evt); |
1482 | } | 1489 | } |
@@ -1489,6 +1496,9 @@ static void ibmvfc_scsi_done(struct ibmvfc_event *evt) | |||
1489 | cmnd->scsi_done(cmnd); | 1496 | cmnd->scsi_done(cmnd); |
1490 | } | 1497 | } |
1491 | 1498 | ||
1499 | if (evt->eh_comp) | ||
1500 | complete(evt->eh_comp); | ||
1501 | |||
1492 | ibmvfc_free_event(evt); | 1502 | ibmvfc_free_event(evt); |
1493 | } | 1503 | } |
1494 | 1504 | ||
@@ -1627,7 +1637,7 @@ static int ibmvfc_reset_device(struct scsi_device *sdev, int type, char *desc) | |||
1627 | struct ibmvfc_host *vhost = shost_priv(sdev->host); | 1637 | struct ibmvfc_host *vhost = shost_priv(sdev->host); |
1628 | struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); | 1638 | struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); |
1629 | struct ibmvfc_cmd *tmf; | 1639 | struct ibmvfc_cmd *tmf; |
1630 | struct ibmvfc_event *evt; | 1640 | struct ibmvfc_event *evt = NULL; |
1631 | union ibmvfc_iu rsp_iu; | 1641 | union ibmvfc_iu rsp_iu; |
1632 | struct ibmvfc_fcp_rsp *fc_rsp = &rsp_iu.cmd.rsp; | 1642 | struct ibmvfc_fcp_rsp *fc_rsp = &rsp_iu.cmd.rsp; |
1633 | int rsp_rc = -EBUSY; | 1643 | int rsp_rc = -EBUSY; |
@@ -1789,7 +1799,8 @@ static int ibmvfc_abort_task_set(struct scsi_device *sdev) | |||
1789 | static int ibmvfc_cancel_all(struct scsi_device *sdev, int type) | 1799 | static int ibmvfc_cancel_all(struct scsi_device *sdev, int type) |
1790 | { | 1800 | { |
1791 | struct ibmvfc_host *vhost = shost_priv(sdev->host); | 1801 | struct ibmvfc_host *vhost = shost_priv(sdev->host); |
1792 | struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); | 1802 | struct scsi_target *starget = scsi_target(sdev); |
1803 | struct fc_rport *rport = starget_to_rport(starget); | ||
1793 | struct ibmvfc_tmf *tmf; | 1804 | struct ibmvfc_tmf *tmf; |
1794 | struct ibmvfc_event *evt, *found_evt; | 1805 | struct ibmvfc_event *evt, *found_evt; |
1795 | union ibmvfc_iu rsp; | 1806 | union ibmvfc_iu rsp; |
@@ -1827,7 +1838,7 @@ static int ibmvfc_cancel_all(struct scsi_device *sdev, int type) | |||
1827 | int_to_scsilun(sdev->lun, &tmf->lun); | 1838 | int_to_scsilun(sdev->lun, &tmf->lun); |
1828 | tmf->flags = (type | IBMVFC_TMF_LUA_VALID); | 1839 | tmf->flags = (type | IBMVFC_TMF_LUA_VALID); |
1829 | tmf->cancel_key = (unsigned long)sdev->hostdata; | 1840 | tmf->cancel_key = (unsigned long)sdev->hostdata; |
1830 | tmf->my_cancel_key = (IBMVFC_TMF_CANCEL_KEY | (unsigned long)sdev->hostdata); | 1841 | tmf->my_cancel_key = (unsigned long)starget->hostdata; |
1831 | 1842 | ||
1832 | evt->sync_iu = &rsp; | 1843 | evt->sync_iu = &rsp; |
1833 | init_completion(&evt->comp); | 1844 | init_completion(&evt->comp); |
@@ -1859,6 +1870,91 @@ static int ibmvfc_cancel_all(struct scsi_device *sdev, int type) | |||
1859 | } | 1870 | } |
1860 | 1871 | ||
1861 | /** | 1872 | /** |
1873 | * ibmvfc_match_target - Match function for specified target | ||
1874 | * @evt: ibmvfc event struct | ||
1875 | * @device: device to match (starget) | ||
1876 | * | ||
1877 | * Returns: | ||
1878 | * 1 if event matches starget / 0 if event does not match starget | ||
1879 | **/ | ||
1880 | static int ibmvfc_match_target(struct ibmvfc_event *evt, void *device) | ||
1881 | { | ||
1882 | if (evt->cmnd && scsi_target(evt->cmnd->device) == device) | ||
1883 | return 1; | ||
1884 | return 0; | ||
1885 | } | ||
1886 | |||
1887 | /** | ||
1888 | * ibmvfc_match_lun - Match function for specified LUN | ||
1889 | * @evt: ibmvfc event struct | ||
1890 | * @device: device to match (sdev) | ||
1891 | * | ||
1892 | * Returns: | ||
1893 | * 1 if event matches sdev / 0 if event does not match sdev | ||
1894 | **/ | ||
1895 | static int ibmvfc_match_lun(struct ibmvfc_event *evt, void *device) | ||
1896 | { | ||
1897 | if (evt->cmnd && evt->cmnd->device == device) | ||
1898 | return 1; | ||
1899 | return 0; | ||
1900 | } | ||
1901 | |||
1902 | /** | ||
1903 | * ibmvfc_wait_for_ops - Wait for ops to complete | ||
1904 | * @vhost: ibmvfc host struct | ||
1905 | * @device: device to match (starget or sdev) | ||
1906 | * @match: match function | ||
1907 | * | ||
1908 | * Returns: | ||
1909 | * SUCCESS / FAILED | ||
1910 | **/ | ||
1911 | static int ibmvfc_wait_for_ops(struct ibmvfc_host *vhost, void *device, | ||
1912 | int (*match) (struct ibmvfc_event *, void *)) | ||
1913 | { | ||
1914 | struct ibmvfc_event *evt; | ||
1915 | DECLARE_COMPLETION_ONSTACK(comp); | ||
1916 | int wait; | ||
1917 | unsigned long flags; | ||
1918 | signed long timeout = init_timeout * HZ; | ||
1919 | |||
1920 | ENTER; | ||
1921 | do { | ||
1922 | wait = 0; | ||
1923 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
1924 | list_for_each_entry(evt, &vhost->sent, queue) { | ||
1925 | if (match(evt, device)) { | ||
1926 | evt->eh_comp = ∁ | ||
1927 | wait++; | ||
1928 | } | ||
1929 | } | ||
1930 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
1931 | |||
1932 | if (wait) { | ||
1933 | timeout = wait_for_completion_timeout(&comp, timeout); | ||
1934 | |||
1935 | if (!timeout) { | ||
1936 | wait = 0; | ||
1937 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
1938 | list_for_each_entry(evt, &vhost->sent, queue) { | ||
1939 | if (match(evt, device)) { | ||
1940 | evt->eh_comp = NULL; | ||
1941 | wait++; | ||
1942 | } | ||
1943 | } | ||
1944 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
1945 | if (wait) | ||
1946 | dev_err(vhost->dev, "Timed out waiting for aborted commands\n"); | ||
1947 | LEAVE; | ||
1948 | return wait ? FAILED : SUCCESS; | ||
1949 | } | ||
1950 | } | ||
1951 | } while (wait); | ||
1952 | |||
1953 | LEAVE; | ||
1954 | return SUCCESS; | ||
1955 | } | ||
1956 | |||
1957 | /** | ||
1862 | * ibmvfc_eh_abort_handler - Abort a command | 1958 | * ibmvfc_eh_abort_handler - Abort a command |
1863 | * @cmd: scsi command to abort | 1959 | * @cmd: scsi command to abort |
1864 | * | 1960 | * |
@@ -1867,29 +1963,21 @@ static int ibmvfc_cancel_all(struct scsi_device *sdev, int type) | |||
1867 | **/ | 1963 | **/ |
1868 | static int ibmvfc_eh_abort_handler(struct scsi_cmnd *cmd) | 1964 | static int ibmvfc_eh_abort_handler(struct scsi_cmnd *cmd) |
1869 | { | 1965 | { |
1870 | struct ibmvfc_host *vhost = shost_priv(cmd->device->host); | 1966 | struct scsi_device *sdev = cmd->device; |
1871 | struct ibmvfc_event *evt, *pos; | 1967 | struct ibmvfc_host *vhost = shost_priv(sdev->host); |
1872 | int cancel_rc, abort_rc; | 1968 | int cancel_rc, abort_rc; |
1873 | unsigned long flags; | 1969 | int rc = FAILED; |
1874 | 1970 | ||
1875 | ENTER; | 1971 | ENTER; |
1876 | ibmvfc_wait_while_resetting(vhost); | 1972 | ibmvfc_wait_while_resetting(vhost); |
1877 | cancel_rc = ibmvfc_cancel_all(cmd->device, IBMVFC_TMF_ABORT_TASK_SET); | 1973 | cancel_rc = ibmvfc_cancel_all(sdev, IBMVFC_TMF_ABORT_TASK_SET); |
1878 | abort_rc = ibmvfc_abort_task_set(cmd->device); | 1974 | abort_rc = ibmvfc_abort_task_set(sdev); |
1879 | 1975 | ||
1880 | if (!cancel_rc && !abort_rc) { | 1976 | if (!cancel_rc && !abort_rc) |
1881 | spin_lock_irqsave(vhost->host->host_lock, flags); | 1977 | rc = ibmvfc_wait_for_ops(vhost, sdev, ibmvfc_match_lun); |
1882 | list_for_each_entry_safe(evt, pos, &vhost->sent, queue) { | ||
1883 | if (evt->cmnd && evt->cmnd->device == cmd->device) | ||
1884 | ibmvfc_fail_request(evt, DID_ABORT); | ||
1885 | } | ||
1886 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
1887 | LEAVE; | ||
1888 | return SUCCESS; | ||
1889 | } | ||
1890 | 1978 | ||
1891 | LEAVE; | 1979 | LEAVE; |
1892 | return FAILED; | 1980 | return rc; |
1893 | } | 1981 | } |
1894 | 1982 | ||
1895 | /** | 1983 | /** |
@@ -1901,29 +1989,21 @@ static int ibmvfc_eh_abort_handler(struct scsi_cmnd *cmd) | |||
1901 | **/ | 1989 | **/ |
1902 | static int ibmvfc_eh_device_reset_handler(struct scsi_cmnd *cmd) | 1990 | static int ibmvfc_eh_device_reset_handler(struct scsi_cmnd *cmd) |
1903 | { | 1991 | { |
1904 | struct ibmvfc_host *vhost = shost_priv(cmd->device->host); | 1992 | struct scsi_device *sdev = cmd->device; |
1905 | struct ibmvfc_event *evt, *pos; | 1993 | struct ibmvfc_host *vhost = shost_priv(sdev->host); |
1906 | int cancel_rc, reset_rc; | 1994 | int cancel_rc, reset_rc; |
1907 | unsigned long flags; | 1995 | int rc = FAILED; |
1908 | 1996 | ||
1909 | ENTER; | 1997 | ENTER; |
1910 | ibmvfc_wait_while_resetting(vhost); | 1998 | ibmvfc_wait_while_resetting(vhost); |
1911 | cancel_rc = ibmvfc_cancel_all(cmd->device, IBMVFC_TMF_LUN_RESET); | 1999 | cancel_rc = ibmvfc_cancel_all(sdev, IBMVFC_TMF_LUN_RESET); |
1912 | reset_rc = ibmvfc_reset_device(cmd->device, IBMVFC_LUN_RESET, "LUN"); | 2000 | reset_rc = ibmvfc_reset_device(sdev, IBMVFC_LUN_RESET, "LUN"); |
1913 | 2001 | ||
1914 | if (!cancel_rc && !reset_rc) { | 2002 | if (!cancel_rc && !reset_rc) |
1915 | spin_lock_irqsave(vhost->host->host_lock, flags); | 2003 | rc = ibmvfc_wait_for_ops(vhost, sdev, ibmvfc_match_lun); |
1916 | list_for_each_entry_safe(evt, pos, &vhost->sent, queue) { | ||
1917 | if (evt->cmnd && evt->cmnd->device == cmd->device) | ||
1918 | ibmvfc_fail_request(evt, DID_ABORT); | ||
1919 | } | ||
1920 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
1921 | LEAVE; | ||
1922 | return SUCCESS; | ||
1923 | } | ||
1924 | 2004 | ||
1925 | LEAVE; | 2005 | LEAVE; |
1926 | return FAILED; | 2006 | return rc; |
1927 | } | 2007 | } |
1928 | 2008 | ||
1929 | /** | 2009 | /** |
@@ -1959,31 +2039,23 @@ static void ibmvfc_dev_abort_all(struct scsi_device *sdev, void *data) | |||
1959 | **/ | 2039 | **/ |
1960 | static int ibmvfc_eh_target_reset_handler(struct scsi_cmnd *cmd) | 2040 | static int ibmvfc_eh_target_reset_handler(struct scsi_cmnd *cmd) |
1961 | { | 2041 | { |
1962 | struct ibmvfc_host *vhost = shost_priv(cmd->device->host); | 2042 | struct scsi_device *sdev = cmd->device; |
1963 | struct scsi_target *starget = scsi_target(cmd->device); | 2043 | struct ibmvfc_host *vhost = shost_priv(sdev->host); |
1964 | struct ibmvfc_event *evt, *pos; | 2044 | struct scsi_target *starget = scsi_target(sdev); |
1965 | int reset_rc; | 2045 | int reset_rc; |
2046 | int rc = FAILED; | ||
1966 | unsigned long cancel_rc = 0; | 2047 | unsigned long cancel_rc = 0; |
1967 | unsigned long flags; | ||
1968 | 2048 | ||
1969 | ENTER; | 2049 | ENTER; |
1970 | ibmvfc_wait_while_resetting(vhost); | 2050 | ibmvfc_wait_while_resetting(vhost); |
1971 | starget_for_each_device(starget, &cancel_rc, ibmvfc_dev_cancel_all); | 2051 | starget_for_each_device(starget, &cancel_rc, ibmvfc_dev_cancel_all); |
1972 | reset_rc = ibmvfc_reset_device(cmd->device, IBMVFC_TARGET_RESET, "target"); | 2052 | reset_rc = ibmvfc_reset_device(sdev, IBMVFC_TARGET_RESET, "target"); |
1973 | 2053 | ||
1974 | if (!cancel_rc && !reset_rc) { | 2054 | if (!cancel_rc && !reset_rc) |
1975 | spin_lock_irqsave(vhost->host->host_lock, flags); | 2055 | rc = ibmvfc_wait_for_ops(vhost, starget, ibmvfc_match_target); |
1976 | list_for_each_entry_safe(evt, pos, &vhost->sent, queue) { | ||
1977 | if (evt->cmnd && scsi_target(evt->cmnd->device) == starget) | ||
1978 | ibmvfc_fail_request(evt, DID_ABORT); | ||
1979 | } | ||
1980 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
1981 | LEAVE; | ||
1982 | return SUCCESS; | ||
1983 | } | ||
1984 | 2056 | ||
1985 | LEAVE; | 2057 | LEAVE; |
1986 | return FAILED; | 2058 | return rc; |
1987 | } | 2059 | } |
1988 | 2060 | ||
1989 | /** | 2061 | /** |
@@ -2013,23 +2085,18 @@ static void ibmvfc_terminate_rport_io(struct fc_rport *rport) | |||
2013 | struct scsi_target *starget = to_scsi_target(&rport->dev); | 2085 | struct scsi_target *starget = to_scsi_target(&rport->dev); |
2014 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); | 2086 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); |
2015 | struct ibmvfc_host *vhost = shost_priv(shost); | 2087 | struct ibmvfc_host *vhost = shost_priv(shost); |
2016 | struct ibmvfc_event *evt, *pos; | ||
2017 | unsigned long cancel_rc = 0; | 2088 | unsigned long cancel_rc = 0; |
2018 | unsigned long abort_rc = 0; | 2089 | unsigned long abort_rc = 0; |
2019 | unsigned long flags; | 2090 | int rc = FAILED; |
2020 | 2091 | ||
2021 | ENTER; | 2092 | ENTER; |
2022 | starget_for_each_device(starget, &cancel_rc, ibmvfc_dev_cancel_all); | 2093 | starget_for_each_device(starget, &cancel_rc, ibmvfc_dev_cancel_all); |
2023 | starget_for_each_device(starget, &abort_rc, ibmvfc_dev_abort_all); | 2094 | starget_for_each_device(starget, &abort_rc, ibmvfc_dev_abort_all); |
2024 | 2095 | ||
2025 | if (!cancel_rc && !abort_rc) { | 2096 | if (!cancel_rc && !abort_rc) |
2026 | spin_lock_irqsave(shost->host_lock, flags); | 2097 | rc = ibmvfc_wait_for_ops(vhost, starget, ibmvfc_match_target); |
2027 | list_for_each_entry_safe(evt, pos, &vhost->sent, queue) { | 2098 | |
2028 | if (evt->cmnd && scsi_target(evt->cmnd->device) == starget) | 2099 | if (rc == FAILED) |
2029 | ibmvfc_fail_request(evt, DID_ABORT); | ||
2030 | } | ||
2031 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
2032 | } else | ||
2033 | ibmvfc_issue_fc_host_lip(shost); | 2100 | ibmvfc_issue_fc_host_lip(shost); |
2034 | LEAVE; | 2101 | LEAVE; |
2035 | } | 2102 | } |
@@ -2089,15 +2156,17 @@ static void ibmvfc_handle_async(struct ibmvfc_async_crq *crq, | |||
2089 | case IBMVFC_AE_LINK_UP: | 2156 | case IBMVFC_AE_LINK_UP: |
2090 | case IBMVFC_AE_RESUME: | 2157 | case IBMVFC_AE_RESUME: |
2091 | vhost->events_to_log |= IBMVFC_AE_LINKUP; | 2158 | vhost->events_to_log |= IBMVFC_AE_LINKUP; |
2092 | ibmvfc_init_host(vhost, 1); | 2159 | vhost->delay_init = 1; |
2160 | __ibmvfc_reset_host(vhost); | ||
2093 | break; | 2161 | break; |
2094 | case IBMVFC_AE_SCN_FABRIC: | 2162 | case IBMVFC_AE_SCN_FABRIC: |
2163 | case IBMVFC_AE_SCN_DOMAIN: | ||
2095 | vhost->events_to_log |= IBMVFC_AE_RSCN; | 2164 | vhost->events_to_log |= IBMVFC_AE_RSCN; |
2096 | ibmvfc_init_host(vhost, 1); | 2165 | vhost->delay_init = 1; |
2166 | __ibmvfc_reset_host(vhost); | ||
2097 | break; | 2167 | break; |
2098 | case IBMVFC_AE_SCN_NPORT: | 2168 | case IBMVFC_AE_SCN_NPORT: |
2099 | case IBMVFC_AE_SCN_GROUP: | 2169 | case IBMVFC_AE_SCN_GROUP: |
2100 | case IBMVFC_AE_SCN_DOMAIN: | ||
2101 | vhost->events_to_log |= IBMVFC_AE_RSCN; | 2170 | vhost->events_to_log |= IBMVFC_AE_RSCN; |
2102 | case IBMVFC_AE_ELS_LOGO: | 2171 | case IBMVFC_AE_ELS_LOGO: |
2103 | case IBMVFC_AE_ELS_PRLO: | 2172 | case IBMVFC_AE_ELS_PRLO: |
@@ -2263,6 +2332,28 @@ static int ibmvfc_slave_alloc(struct scsi_device *sdev) | |||
2263 | } | 2332 | } |
2264 | 2333 | ||
2265 | /** | 2334 | /** |
2335 | * ibmvfc_target_alloc - Setup the target's task set value | ||
2336 | * @starget: struct scsi_target | ||
2337 | * | ||
2338 | * Set the target's task set value so that error handling works as | ||
2339 | * expected. | ||
2340 | * | ||
2341 | * Returns: | ||
2342 | * 0 on success / -ENXIO if device does not exist | ||
2343 | **/ | ||
2344 | static int ibmvfc_target_alloc(struct scsi_target *starget) | ||
2345 | { | ||
2346 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); | ||
2347 | struct ibmvfc_host *vhost = shost_priv(shost); | ||
2348 | unsigned long flags = 0; | ||
2349 | |||
2350 | spin_lock_irqsave(shost->host_lock, flags); | ||
2351 | starget->hostdata = (void *)(unsigned long)vhost->task_set++; | ||
2352 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
2353 | return 0; | ||
2354 | } | ||
2355 | |||
2356 | /** | ||
2266 | * ibmvfc_slave_configure - Configure the device | 2357 | * ibmvfc_slave_configure - Configure the device |
2267 | * @sdev: struct scsi_device device to configure | 2358 | * @sdev: struct scsi_device device to configure |
2268 | * | 2359 | * |
@@ -2541,6 +2632,7 @@ static struct scsi_host_template driver_template = { | |||
2541 | .eh_host_reset_handler = ibmvfc_eh_host_reset_handler, | 2632 | .eh_host_reset_handler = ibmvfc_eh_host_reset_handler, |
2542 | .slave_alloc = ibmvfc_slave_alloc, | 2633 | .slave_alloc = ibmvfc_slave_alloc, |
2543 | .slave_configure = ibmvfc_slave_configure, | 2634 | .slave_configure = ibmvfc_slave_configure, |
2635 | .target_alloc = ibmvfc_target_alloc, | ||
2544 | .scan_finished = ibmvfc_scan_finished, | 2636 | .scan_finished = ibmvfc_scan_finished, |
2545 | .change_queue_depth = ibmvfc_change_queue_depth, | 2637 | .change_queue_depth = ibmvfc_change_queue_depth, |
2546 | .change_queue_type = ibmvfc_change_queue_type, | 2638 | .change_queue_type = ibmvfc_change_queue_type, |
@@ -2637,7 +2729,7 @@ static irqreturn_t ibmvfc_interrupt(int irq, void *dev_instance) | |||
2637 | } else if ((async = ibmvfc_next_async_crq(vhost)) != NULL) { | 2729 | } else if ((async = ibmvfc_next_async_crq(vhost)) != NULL) { |
2638 | vio_disable_interrupts(vdev); | 2730 | vio_disable_interrupts(vdev); |
2639 | ibmvfc_handle_async(async, vhost); | 2731 | ibmvfc_handle_async(async, vhost); |
2640 | crq->valid = 0; | 2732 | async->valid = 0; |
2641 | } else | 2733 | } else |
2642 | done = 1; | 2734 | done = 1; |
2643 | } | 2735 | } |
@@ -2669,7 +2761,7 @@ static void ibmvfc_init_tgt(struct ibmvfc_target *tgt, | |||
2669 | static void ibmvfc_retry_tgt_init(struct ibmvfc_target *tgt, | 2761 | static void ibmvfc_retry_tgt_init(struct ibmvfc_target *tgt, |
2670 | void (*job_step) (struct ibmvfc_target *)) | 2762 | void (*job_step) (struct ibmvfc_target *)) |
2671 | { | 2763 | { |
2672 | if (++tgt->init_retries > IBMVFC_MAX_INIT_RETRIES) { | 2764 | if (++tgt->init_retries > IBMVFC_MAX_TGT_INIT_RETRIES) { |
2673 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); | 2765 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); |
2674 | wake_up(&tgt->vhost->work_wait_q); | 2766 | wake_up(&tgt->vhost->work_wait_q); |
2675 | } else | 2767 | } else |
@@ -2708,6 +2800,8 @@ static void ibmvfc_tgt_prli_done(struct ibmvfc_event *evt) | |||
2708 | rsp->status, rsp->error, status); | 2800 | rsp->status, rsp->error, status); |
2709 | if (ibmvfc_retry_cmd(rsp->status, rsp->error)) | 2801 | if (ibmvfc_retry_cmd(rsp->status, rsp->error)) |
2710 | ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli); | 2802 | ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli); |
2803 | else | ||
2804 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); | ||
2711 | break; | 2805 | break; |
2712 | }; | 2806 | }; |
2713 | 2807 | ||
@@ -2802,6 +2896,8 @@ static void ibmvfc_tgt_plogi_done(struct ibmvfc_event *evt) | |||
2802 | 2896 | ||
2803 | if (ibmvfc_retry_cmd(rsp->status, rsp->error)) | 2897 | if (ibmvfc_retry_cmd(rsp->status, rsp->error)) |
2804 | ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_plogi); | 2898 | ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_plogi); |
2899 | else | ||
2900 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); | ||
2805 | break; | 2901 | break; |
2806 | }; | 2902 | }; |
2807 | 2903 | ||
@@ -3093,6 +3189,8 @@ static void ibmvfc_tgt_query_target_done(struct ibmvfc_event *evt) | |||
3093 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); | 3189 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); |
3094 | else if (ibmvfc_retry_cmd(rsp->status, rsp->error)) | 3190 | else if (ibmvfc_retry_cmd(rsp->status, rsp->error)) |
3095 | ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_query_target); | 3191 | ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_query_target); |
3192 | else | ||
3193 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); | ||
3096 | break; | 3194 | break; |
3097 | }; | 3195 | }; |
3098 | 3196 | ||
@@ -3423,6 +3521,7 @@ static int __ibmvfc_work_to_do(struct ibmvfc_host *vhost) | |||
3423 | case IBMVFC_HOST_ACTION_ALLOC_TGTS: | 3521 | case IBMVFC_HOST_ACTION_ALLOC_TGTS: |
3424 | case IBMVFC_HOST_ACTION_TGT_ADD: | 3522 | case IBMVFC_HOST_ACTION_TGT_ADD: |
3425 | case IBMVFC_HOST_ACTION_TGT_DEL: | 3523 | case IBMVFC_HOST_ACTION_TGT_DEL: |
3524 | case IBMVFC_HOST_ACTION_TGT_DEL_FAILED: | ||
3426 | case IBMVFC_HOST_ACTION_QUERY: | 3525 | case IBMVFC_HOST_ACTION_QUERY: |
3427 | default: | 3526 | default: |
3428 | break; | 3527 | break; |
@@ -3519,7 +3618,13 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost) | |||
3519 | break; | 3618 | break; |
3520 | case IBMVFC_HOST_ACTION_INIT: | 3619 | case IBMVFC_HOST_ACTION_INIT: |
3521 | BUG_ON(vhost->state != IBMVFC_INITIALIZING); | 3620 | BUG_ON(vhost->state != IBMVFC_INITIALIZING); |
3522 | vhost->job_step(vhost); | 3621 | if (vhost->delay_init) { |
3622 | vhost->delay_init = 0; | ||
3623 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
3624 | ssleep(15); | ||
3625 | return; | ||
3626 | } else | ||
3627 | vhost->job_step(vhost); | ||
3523 | break; | 3628 | break; |
3524 | case IBMVFC_HOST_ACTION_QUERY: | 3629 | case IBMVFC_HOST_ACTION_QUERY: |
3525 | list_for_each_entry(tgt, &vhost->targets, queue) | 3630 | list_for_each_entry(tgt, &vhost->targets, queue) |
@@ -3538,6 +3643,7 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost) | |||
3538 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_DEL); | 3643 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_DEL); |
3539 | break; | 3644 | break; |
3540 | case IBMVFC_HOST_ACTION_TGT_DEL: | 3645 | case IBMVFC_HOST_ACTION_TGT_DEL: |
3646 | case IBMVFC_HOST_ACTION_TGT_DEL_FAILED: | ||
3541 | list_for_each_entry(tgt, &vhost->targets, queue) { | 3647 | list_for_each_entry(tgt, &vhost->targets, queue) { |
3542 | if (tgt->action == IBMVFC_TGT_ACTION_DEL_RPORT) { | 3648 | if (tgt->action == IBMVFC_TGT_ACTION_DEL_RPORT) { |
3543 | tgt_dbg(tgt, "Deleting rport\n"); | 3649 | tgt_dbg(tgt, "Deleting rport\n"); |
@@ -3553,8 +3659,17 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost) | |||
3553 | } | 3659 | } |
3554 | 3660 | ||
3555 | if (vhost->state == IBMVFC_INITIALIZING) { | 3661 | if (vhost->state == IBMVFC_INITIALIZING) { |
3556 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT); | 3662 | if (vhost->action == IBMVFC_HOST_ACTION_TGT_DEL_FAILED) { |
3557 | vhost->job_step = ibmvfc_discover_targets; | 3663 | ibmvfc_set_host_state(vhost, IBMVFC_ACTIVE); |
3664 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_ADD); | ||
3665 | vhost->init_retries = 0; | ||
3666 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
3667 | scsi_unblock_requests(vhost->host); | ||
3668 | return; | ||
3669 | } else { | ||
3670 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT); | ||
3671 | vhost->job_step = ibmvfc_discover_targets; | ||
3672 | } | ||
3558 | } else { | 3673 | } else { |
3559 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE); | 3674 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE); |
3560 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | 3675 | spin_unlock_irqrestore(vhost->host->host_lock, flags); |
@@ -3577,14 +3692,8 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost) | |||
3577 | } | 3692 | } |
3578 | } | 3693 | } |
3579 | 3694 | ||
3580 | if (!ibmvfc_dev_init_to_do(vhost)) { | 3695 | if (!ibmvfc_dev_init_to_do(vhost)) |
3581 | ibmvfc_set_host_state(vhost, IBMVFC_ACTIVE); | 3696 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_DEL_FAILED); |
3582 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_ADD); | ||
3583 | vhost->init_retries = 0; | ||
3584 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
3585 | scsi_unblock_requests(vhost->host); | ||
3586 | return; | ||
3587 | } | ||
3588 | break; | 3697 | break; |
3589 | case IBMVFC_HOST_ACTION_TGT_ADD: | 3698 | case IBMVFC_HOST_ACTION_TGT_ADD: |
3590 | list_for_each_entry(tgt, &vhost->targets, queue) { | 3699 | list_for_each_entry(tgt, &vhost->targets, queue) { |
@@ -3592,16 +3701,6 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost) | |||
3592 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | 3701 | spin_unlock_irqrestore(vhost->host->host_lock, flags); |
3593 | ibmvfc_tgt_add_rport(tgt); | 3702 | ibmvfc_tgt_add_rport(tgt); |
3594 | return; | 3703 | return; |
3595 | } else if (tgt->action == IBMVFC_TGT_ACTION_DEL_RPORT) { | ||
3596 | tgt_dbg(tgt, "Deleting rport\n"); | ||
3597 | rport = tgt->rport; | ||
3598 | tgt->rport = NULL; | ||
3599 | list_del(&tgt->queue); | ||
3600 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
3601 | if (rport) | ||
3602 | fc_remote_port_delete(rport); | ||
3603 | kref_put(&tgt->kref, ibmvfc_release_tgt); | ||
3604 | return; | ||
3605 | } | 3704 | } |
3606 | } | 3705 | } |
3607 | 3706 | ||