diff options
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_attr.c')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_attr.c | 732 |
1 files changed, 729 insertions, 3 deletions
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 3a9f5b288aee..90d1e062ec4f 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c | |||
@@ -11,7 +11,9 @@ | |||
11 | #include <linux/delay.h> | 11 | #include <linux/delay.h> |
12 | 12 | ||
13 | static int qla24xx_vport_disable(struct fc_vport *, bool); | 13 | static int qla24xx_vport_disable(struct fc_vport *, bool); |
14 | 14 | static int qla84xx_reset(scsi_qla_host_t *, struct msg_echo_lb *, struct fc_bsg_job *); | |
15 | int qla84xx_reset_chip(scsi_qla_host_t *, uint16_t, uint16_t *); | ||
16 | static int qla84xx_mgmt_cmd(scsi_qla_host_t *, struct msg_echo_lb *, struct fc_bsg_job *); | ||
15 | /* SYSFS attributes --------------------------------------------------------- */ | 17 | /* SYSFS attributes --------------------------------------------------------- */ |
16 | 18 | ||
17 | static ssize_t | 19 | static ssize_t |
@@ -1168,6 +1170,28 @@ qla2x00_total_isp_aborts_show(struct device *dev, | |||
1168 | } | 1170 | } |
1169 | 1171 | ||
1170 | static ssize_t | 1172 | static ssize_t |
1173 | qla24xx_84xx_fw_version_show(struct device *dev, | ||
1174 | struct device_attribute *attr, char *buf) | ||
1175 | { | ||
1176 | int rval = QLA_SUCCESS; | ||
1177 | uint16_t status[2] = {0, 0}; | ||
1178 | scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); | ||
1179 | struct qla_hw_data *ha = vha->hw; | ||
1180 | |||
1181 | if (IS_QLA84XX(ha) && ha->cs84xx) { | ||
1182 | if (ha->cs84xx->op_fw_version == 0) { | ||
1183 | rval = qla84xx_verify_chip(vha, status); | ||
1184 | } | ||
1185 | |||
1186 | if ((rval == QLA_SUCCESS) && (status[0] == 0)) | ||
1187 | return snprintf(buf, PAGE_SIZE, "%u\n", | ||
1188 | (uint32_t)ha->cs84xx->op_fw_version); | ||
1189 | } | ||
1190 | |||
1191 | return snprintf(buf, PAGE_SIZE, "\n"); | ||
1192 | } | ||
1193 | |||
1194 | static ssize_t | ||
1171 | qla2x00_mpi_version_show(struct device *dev, struct device_attribute *attr, | 1195 | qla2x00_mpi_version_show(struct device *dev, struct device_attribute *attr, |
1172 | char *buf) | 1196 | char *buf) |
1173 | { | 1197 | { |
@@ -1281,6 +1305,8 @@ static DEVICE_ATTR(optrom_fcode_version, S_IRUGO, | |||
1281 | qla2x00_optrom_fcode_version_show, NULL); | 1305 | qla2x00_optrom_fcode_version_show, NULL); |
1282 | static DEVICE_ATTR(optrom_fw_version, S_IRUGO, qla2x00_optrom_fw_version_show, | 1306 | static DEVICE_ATTR(optrom_fw_version, S_IRUGO, qla2x00_optrom_fw_version_show, |
1283 | NULL); | 1307 | NULL); |
1308 | static DEVICE_ATTR(84xx_fw_version, S_IRUGO, qla24xx_84xx_fw_version_show, | ||
1309 | NULL); | ||
1284 | static DEVICE_ATTR(total_isp_aborts, S_IRUGO, qla2x00_total_isp_aborts_show, | 1310 | static DEVICE_ATTR(total_isp_aborts, S_IRUGO, qla2x00_total_isp_aborts_show, |
1285 | NULL); | 1311 | NULL); |
1286 | static DEVICE_ATTR(mpi_version, S_IRUGO, qla2x00_mpi_version_show, NULL); | 1312 | static DEVICE_ATTR(mpi_version, S_IRUGO, qla2x00_mpi_version_show, NULL); |
@@ -1310,6 +1336,7 @@ struct device_attribute *qla2x00_host_attrs[] = { | |||
1310 | &dev_attr_optrom_efi_version, | 1336 | &dev_attr_optrom_efi_version, |
1311 | &dev_attr_optrom_fcode_version, | 1337 | &dev_attr_optrom_fcode_version, |
1312 | &dev_attr_optrom_fw_version, | 1338 | &dev_attr_optrom_fw_version, |
1339 | &dev_attr_84xx_fw_version, | ||
1313 | &dev_attr_total_isp_aborts, | 1340 | &dev_attr_total_isp_aborts, |
1314 | &dev_attr_mpi_version, | 1341 | &dev_attr_mpi_version, |
1315 | &dev_attr_phy_version, | 1342 | &dev_attr_phy_version, |
@@ -1504,8 +1531,6 @@ qla2x00_terminate_rport_io(struct fc_rport *rport) | |||
1504 | fcport->vha->hw->isp_ops->fabric_logout(fcport->vha, | 1531 | fcport->vha->hw->isp_ops->fabric_logout(fcport->vha, |
1505 | fcport->loop_id, fcport->d_id.b.domain, | 1532 | fcport->loop_id, fcport->d_id.b.domain, |
1506 | fcport->d_id.b.area, fcport->d_id.b.al_pa); | 1533 | fcport->d_id.b.area, fcport->d_id.b.al_pa); |
1507 | |||
1508 | qla2x00_abort_fcport_cmds(fcport); | ||
1509 | } | 1534 | } |
1510 | 1535 | ||
1511 | static int | 1536 | static int |
@@ -1795,6 +1820,581 @@ qla24xx_vport_disable(struct fc_vport *fc_vport, bool disable) | |||
1795 | return 0; | 1820 | return 0; |
1796 | } | 1821 | } |
1797 | 1822 | ||
1823 | /* BSG support for ELS/CT pass through */ | ||
1824 | inline srb_t * | ||
1825 | qla2x00_get_ctx_bsg_sp(scsi_qla_host_t *vha, fc_port_t *fcport, size_t size) | ||
1826 | { | ||
1827 | srb_t *sp; | ||
1828 | struct qla_hw_data *ha = vha->hw; | ||
1829 | struct srb_bsg_ctx *ctx; | ||
1830 | |||
1831 | sp = mempool_alloc(ha->srb_mempool, GFP_KERNEL); | ||
1832 | if (!sp) | ||
1833 | goto done; | ||
1834 | ctx = kzalloc(size, GFP_KERNEL); | ||
1835 | if (!ctx) { | ||
1836 | mempool_free(sp, ha->srb_mempool); | ||
1837 | goto done; | ||
1838 | } | ||
1839 | |||
1840 | memset(sp, 0, sizeof(*sp)); | ||
1841 | sp->fcport = fcport; | ||
1842 | sp->ctx = ctx; | ||
1843 | done: | ||
1844 | return sp; | ||
1845 | } | ||
1846 | |||
1847 | static int | ||
1848 | qla2x00_process_els(struct fc_bsg_job *bsg_job) | ||
1849 | { | ||
1850 | struct fc_rport *rport; | ||
1851 | fc_port_t *fcport; | ||
1852 | struct Scsi_Host *host; | ||
1853 | scsi_qla_host_t *vha; | ||
1854 | struct qla_hw_data *ha; | ||
1855 | srb_t *sp; | ||
1856 | const char *type; | ||
1857 | int req_sg_cnt, rsp_sg_cnt; | ||
1858 | int rval = (DRIVER_ERROR << 16); | ||
1859 | uint16_t nextlid = 0; | ||
1860 | struct srb_bsg *els; | ||
1861 | |||
1862 | /* Multiple SG's are not supported for ELS requests */ | ||
1863 | if (bsg_job->request_payload.sg_cnt > 1 || | ||
1864 | bsg_job->reply_payload.sg_cnt > 1) { | ||
1865 | DEBUG2(printk(KERN_INFO | ||
1866 | "multiple SG's are not supported for ELS requests" | ||
1867 | " [request_sg_cnt: %x reply_sg_cnt: %x]\n", | ||
1868 | bsg_job->request_payload.sg_cnt, | ||
1869 | bsg_job->reply_payload.sg_cnt)); | ||
1870 | rval = -EPERM; | ||
1871 | goto done; | ||
1872 | } | ||
1873 | |||
1874 | /* ELS request for rport */ | ||
1875 | if (bsg_job->request->msgcode == FC_BSG_RPT_ELS) { | ||
1876 | rport = bsg_job->rport; | ||
1877 | fcport = *(fc_port_t **) rport->dd_data; | ||
1878 | host = rport_to_shost(rport); | ||
1879 | vha = shost_priv(host); | ||
1880 | ha = vha->hw; | ||
1881 | type = "FC_BSG_RPT_ELS"; | ||
1882 | |||
1883 | /* make sure the rport is logged in, | ||
1884 | * if not perform fabric login | ||
1885 | */ | ||
1886 | if (qla2x00_fabric_login(vha, fcport, &nextlid)) { | ||
1887 | DEBUG2(qla_printk(KERN_WARNING, ha, | ||
1888 | "failed to login port %06X for ELS passthru\n", | ||
1889 | fcport->d_id.b24)); | ||
1890 | rval = -EIO; | ||
1891 | goto done; | ||
1892 | } | ||
1893 | } else { | ||
1894 | host = bsg_job->shost; | ||
1895 | vha = shost_priv(host); | ||
1896 | ha = vha->hw; | ||
1897 | type = "FC_BSG_HST_ELS_NOLOGIN"; | ||
1898 | |||
1899 | /* Allocate a dummy fcport structure, since functions | ||
1900 | * preparing the IOCB and mailbox command retrieves port | ||
1901 | * specific information from fcport structure. For Host based | ||
1902 | * ELS commands there will be no fcport structure allocated | ||
1903 | */ | ||
1904 | fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL); | ||
1905 | if (!fcport) { | ||
1906 | rval = -ENOMEM; | ||
1907 | goto done; | ||
1908 | } | ||
1909 | |||
1910 | /* Initialize all required fields of fcport */ | ||
1911 | fcport->vha = vha; | ||
1912 | fcport->vp_idx = vha->vp_idx; | ||
1913 | fcport->d_id.b.al_pa = | ||
1914 | bsg_job->request->rqst_data.h_els.port_id[0]; | ||
1915 | fcport->d_id.b.area = | ||
1916 | bsg_job->request->rqst_data.h_els.port_id[1]; | ||
1917 | fcport->d_id.b.domain = | ||
1918 | bsg_job->request->rqst_data.h_els.port_id[2]; | ||
1919 | fcport->loop_id = | ||
1920 | (fcport->d_id.b.al_pa == 0xFD) ? | ||
1921 | NPH_FABRIC_CONTROLLER : NPH_F_PORT; | ||
1922 | } | ||
1923 | |||
1924 | if (!vha->flags.online) { | ||
1925 | DEBUG2(qla_printk(KERN_WARNING, ha, | ||
1926 | "host not online\n")); | ||
1927 | rval = -EIO; | ||
1928 | goto done; | ||
1929 | } | ||
1930 | |||
1931 | req_sg_cnt = | ||
1932 | dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, | ||
1933 | bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); | ||
1934 | if (!req_sg_cnt) { | ||
1935 | rval = -ENOMEM; | ||
1936 | goto done_free_fcport; | ||
1937 | } | ||
1938 | rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, | ||
1939 | bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); | ||
1940 | if (!rsp_sg_cnt) { | ||
1941 | rval = -ENOMEM; | ||
1942 | goto done_free_fcport; | ||
1943 | } | ||
1944 | |||
1945 | if ((req_sg_cnt != bsg_job->request_payload.sg_cnt) || | ||
1946 | (rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) | ||
1947 | { | ||
1948 | DEBUG2(printk(KERN_INFO | ||
1949 | "dma mapping resulted in different sg counts \ | ||
1950 | [request_sg_cnt: %x dma_request_sg_cnt: %x\ | ||
1951 | reply_sg_cnt: %x dma_reply_sg_cnt: %x]\n", | ||
1952 | bsg_job->request_payload.sg_cnt, req_sg_cnt, | ||
1953 | bsg_job->reply_payload.sg_cnt, rsp_sg_cnt)); | ||
1954 | rval = -EAGAIN; | ||
1955 | goto done_unmap_sg; | ||
1956 | } | ||
1957 | |||
1958 | /* Alloc SRB structure */ | ||
1959 | sp = qla2x00_get_ctx_bsg_sp(vha, fcport, sizeof(struct srb_bsg)); | ||
1960 | if (!sp) { | ||
1961 | rval = -ENOMEM; | ||
1962 | goto done_unmap_sg; | ||
1963 | } | ||
1964 | |||
1965 | els = sp->ctx; | ||
1966 | els->ctx.type = | ||
1967 | (bsg_job->request->msgcode == FC_BSG_RPT_ELS ? | ||
1968 | SRB_ELS_CMD_RPT : SRB_ELS_CMD_HST); | ||
1969 | els->bsg_job = bsg_job; | ||
1970 | |||
1971 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
1972 | "scsi(%ld:%x): bsg rqst type: %s els type: %x - loop-id=%x " | ||
1973 | "portid=%02x%02x%02x.\n", vha->host_no, sp->handle, type, | ||
1974 | bsg_job->request->rqst_data.h_els.command_code, | ||
1975 | fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area, | ||
1976 | fcport->d_id.b.al_pa)); | ||
1977 | |||
1978 | rval = qla2x00_start_sp(sp); | ||
1979 | if (rval != QLA_SUCCESS) { | ||
1980 | kfree(sp->ctx); | ||
1981 | mempool_free(sp, ha->srb_mempool); | ||
1982 | rval = -EIO; | ||
1983 | goto done_unmap_sg; | ||
1984 | } | ||
1985 | return rval; | ||
1986 | |||
1987 | done_unmap_sg: | ||
1988 | dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, | ||
1989 | bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); | ||
1990 | dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, | ||
1991 | bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); | ||
1992 | goto done_free_fcport; | ||
1993 | |||
1994 | done_free_fcport: | ||
1995 | if (bsg_job->request->msgcode == FC_BSG_HST_ELS_NOLOGIN) | ||
1996 | kfree(fcport); | ||
1997 | done: | ||
1998 | return rval; | ||
1999 | } | ||
2000 | |||
2001 | static int | ||
2002 | qla2x00_process_ct(struct fc_bsg_job *bsg_job) | ||
2003 | { | ||
2004 | srb_t *sp; | ||
2005 | struct Scsi_Host *host = bsg_job->shost; | ||
2006 | scsi_qla_host_t *vha = shost_priv(host); | ||
2007 | struct qla_hw_data *ha = vha->hw; | ||
2008 | int rval = (DRIVER_ERROR << 16); | ||
2009 | int req_sg_cnt, rsp_sg_cnt; | ||
2010 | uint16_t loop_id; | ||
2011 | struct fc_port *fcport; | ||
2012 | char *type = "FC_BSG_HST_CT"; | ||
2013 | struct srb_bsg *ct; | ||
2014 | |||
2015 | /* pass through is supported only for ISP 4Gb or higher */ | ||
2016 | if (!IS_FWI2_CAPABLE(ha)) { | ||
2017 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
2018 | "scsi(%ld):Firmware is not capable to support FC " | ||
2019 | "CT pass thru\n", vha->host_no)); | ||
2020 | rval = -EPERM; | ||
2021 | goto done; | ||
2022 | } | ||
2023 | |||
2024 | req_sg_cnt = | ||
2025 | dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, | ||
2026 | bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); | ||
2027 | if (!req_sg_cnt) { | ||
2028 | rval = -ENOMEM; | ||
2029 | goto done; | ||
2030 | } | ||
2031 | |||
2032 | rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, | ||
2033 | bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); | ||
2034 | if (!rsp_sg_cnt) { | ||
2035 | rval = -ENOMEM; | ||
2036 | goto done; | ||
2037 | } | ||
2038 | |||
2039 | if ((req_sg_cnt != bsg_job->request_payload.sg_cnt) || | ||
2040 | (rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) | ||
2041 | { | ||
2042 | DEBUG2(qla_printk(KERN_WARNING, ha, | ||
2043 | "dma mapping resulted in different sg counts \ | ||
2044 | [request_sg_cnt: %x dma_request_sg_cnt: %x\ | ||
2045 | reply_sg_cnt: %x dma_reply_sg_cnt: %x]\n", | ||
2046 | bsg_job->request_payload.sg_cnt, req_sg_cnt, | ||
2047 | bsg_job->reply_payload.sg_cnt, rsp_sg_cnt)); | ||
2048 | rval = -EAGAIN; | ||
2049 | goto done_unmap_sg; | ||
2050 | } | ||
2051 | |||
2052 | if (!vha->flags.online) { | ||
2053 | DEBUG2(qla_printk(KERN_WARNING, ha, | ||
2054 | "host not online\n")); | ||
2055 | rval = -EIO; | ||
2056 | goto done_unmap_sg; | ||
2057 | } | ||
2058 | |||
2059 | loop_id = | ||
2060 | (bsg_job->request->rqst_data.h_ct.preamble_word1 & 0xFF000000) | ||
2061 | >> 24; | ||
2062 | switch (loop_id) { | ||
2063 | case 0xFC: | ||
2064 | loop_id = cpu_to_le16(NPH_SNS); | ||
2065 | break; | ||
2066 | case 0xFA: | ||
2067 | loop_id = vha->mgmt_svr_loop_id; | ||
2068 | break; | ||
2069 | default: | ||
2070 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
2071 | "Unknown loop id: %x\n", loop_id)); | ||
2072 | rval = -EINVAL; | ||
2073 | goto done_unmap_sg; | ||
2074 | } | ||
2075 | |||
2076 | /* Allocate a dummy fcport structure, since functions preparing the | ||
2077 | * IOCB and mailbox command retrieves port specific information | ||
2078 | * from fcport structure. For Host based ELS commands there will be | ||
2079 | * no fcport structure allocated | ||
2080 | */ | ||
2081 | fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL); | ||
2082 | if (!fcport) | ||
2083 | { | ||
2084 | rval = -ENOMEM; | ||
2085 | goto done_unmap_sg; | ||
2086 | } | ||
2087 | |||
2088 | /* Initialize all required fields of fcport */ | ||
2089 | fcport->vha = vha; | ||
2090 | fcport->vp_idx = vha->vp_idx; | ||
2091 | fcport->d_id.b.al_pa = bsg_job->request->rqst_data.h_ct.port_id[0]; | ||
2092 | fcport->d_id.b.area = bsg_job->request->rqst_data.h_ct.port_id[1]; | ||
2093 | fcport->d_id.b.domain = bsg_job->request->rqst_data.h_ct.port_id[2]; | ||
2094 | fcport->loop_id = loop_id; | ||
2095 | |||
2096 | /* Alloc SRB structure */ | ||
2097 | sp = qla2x00_get_ctx_bsg_sp(vha, fcport, sizeof(struct srb_bsg)); | ||
2098 | if (!sp) { | ||
2099 | rval = -ENOMEM; | ||
2100 | goto done_free_fcport; | ||
2101 | } | ||
2102 | |||
2103 | ct = sp->ctx; | ||
2104 | ct->ctx.type = SRB_CT_CMD; | ||
2105 | ct->bsg_job = bsg_job; | ||
2106 | |||
2107 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
2108 | "scsi(%ld:%x): bsg rqst type: %s els type: %x - loop-id=%x " | ||
2109 | "portid=%02x%02x%02x.\n", vha->host_no, sp->handle, type, | ||
2110 | (bsg_job->request->rqst_data.h_ct.preamble_word2 >> 16), | ||
2111 | fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area, | ||
2112 | fcport->d_id.b.al_pa)); | ||
2113 | |||
2114 | rval = qla2x00_start_sp(sp); | ||
2115 | if (rval != QLA_SUCCESS) { | ||
2116 | kfree(sp->ctx); | ||
2117 | mempool_free(sp, ha->srb_mempool); | ||
2118 | rval = -EIO; | ||
2119 | goto done_free_fcport; | ||
2120 | } | ||
2121 | return rval; | ||
2122 | |||
2123 | done_free_fcport: | ||
2124 | kfree(fcport); | ||
2125 | done_unmap_sg: | ||
2126 | dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, | ||
2127 | bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); | ||
2128 | dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, | ||
2129 | bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); | ||
2130 | done: | ||
2131 | return rval; | ||
2132 | } | ||
2133 | |||
2134 | static int | ||
2135 | qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job) | ||
2136 | { | ||
2137 | struct Scsi_Host *host = bsg_job->shost; | ||
2138 | scsi_qla_host_t *vha = shost_priv(host); | ||
2139 | struct qla_hw_data *ha = vha->hw; | ||
2140 | int rval; | ||
2141 | uint8_t command_sent; | ||
2142 | uint32_t vendor_cmd; | ||
2143 | char *type; | ||
2144 | struct msg_echo_lb elreq; | ||
2145 | uint16_t response[MAILBOX_REGISTER_COUNT]; | ||
2146 | uint8_t* fw_sts_ptr; | ||
2147 | uint8_t *req_data; | ||
2148 | dma_addr_t req_data_dma; | ||
2149 | uint32_t req_data_len; | ||
2150 | uint8_t *rsp_data; | ||
2151 | dma_addr_t rsp_data_dma; | ||
2152 | uint32_t rsp_data_len; | ||
2153 | |||
2154 | if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) || | ||
2155 | test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) || | ||
2156 | test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) { | ||
2157 | rval = -EBUSY; | ||
2158 | goto done; | ||
2159 | } | ||
2160 | |||
2161 | if (!vha->flags.online) { | ||
2162 | DEBUG2(qla_printk(KERN_WARNING, ha, | ||
2163 | "host not online\n")); | ||
2164 | rval = -EIO; | ||
2165 | goto done; | ||
2166 | } | ||
2167 | |||
2168 | elreq.req_sg_cnt = | ||
2169 | dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, | ||
2170 | bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); | ||
2171 | if (!elreq.req_sg_cnt) { | ||
2172 | rval = -ENOMEM; | ||
2173 | goto done; | ||
2174 | } | ||
2175 | elreq.rsp_sg_cnt = | ||
2176 | dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, | ||
2177 | bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); | ||
2178 | if (!elreq.rsp_sg_cnt) { | ||
2179 | rval = -ENOMEM; | ||
2180 | goto done; | ||
2181 | } | ||
2182 | |||
2183 | if ((elreq.req_sg_cnt != bsg_job->request_payload.sg_cnt) || | ||
2184 | (elreq.rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) | ||
2185 | { | ||
2186 | DEBUG2(printk(KERN_INFO | ||
2187 | "dma mapping resulted in different sg counts \ | ||
2188 | [request_sg_cnt: %x dma_request_sg_cnt: %x\ | ||
2189 | reply_sg_cnt: %x dma_reply_sg_cnt: %x]\n", | ||
2190 | bsg_job->request_payload.sg_cnt, elreq.req_sg_cnt, | ||
2191 | bsg_job->reply_payload.sg_cnt, elreq.rsp_sg_cnt)); | ||
2192 | rval = -EAGAIN; | ||
2193 | goto done_unmap_sg; | ||
2194 | } | ||
2195 | req_data_len = rsp_data_len = bsg_job->request_payload.payload_len; | ||
2196 | req_data = dma_alloc_coherent(&ha->pdev->dev, req_data_len, | ||
2197 | &req_data_dma, GFP_KERNEL); | ||
2198 | |||
2199 | rsp_data = dma_alloc_coherent(&ha->pdev->dev, rsp_data_len, | ||
2200 | &rsp_data_dma, GFP_KERNEL); | ||
2201 | |||
2202 | /* Copy the request buffer in req_data now */ | ||
2203 | sg_copy_to_buffer(bsg_job->request_payload.sg_list, | ||
2204 | bsg_job->request_payload.sg_cnt, req_data, | ||
2205 | req_data_len); | ||
2206 | |||
2207 | elreq.send_dma = req_data_dma; | ||
2208 | elreq.rcv_dma = rsp_data_dma; | ||
2209 | elreq.transfer_size = req_data_len; | ||
2210 | |||
2211 | /* Vendor cmd : loopback or ECHO diagnostic | ||
2212 | * Options: | ||
2213 | * Loopback : Either internal or external loopback | ||
2214 | * ECHO: ECHO ELS or Vendor specific FC4 link data | ||
2215 | */ | ||
2216 | vendor_cmd = bsg_job->request->rqst_data.h_vendor.vendor_cmd[0]; | ||
2217 | elreq.options = | ||
2218 | *(((uint32_t *)bsg_job->request->rqst_data.h_vendor.vendor_cmd) | ||
2219 | + 1); | ||
2220 | |||
2221 | switch (bsg_job->request->rqst_data.h_vendor.vendor_cmd[0]) { | ||
2222 | case QL_VND_LOOPBACK: | ||
2223 | if (ha->current_topology != ISP_CFG_F) { | ||
2224 | type = "FC_BSG_HST_VENDOR_LOOPBACK"; | ||
2225 | |||
2226 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
2227 | "scsi(%ld) bsg rqst type: %s vendor rqst type: %x options: %x.\n", | ||
2228 | vha->host_no, type, vendor_cmd, elreq.options)); | ||
2229 | |||
2230 | command_sent = INT_DEF_LB_LOOPBACK_CMD; | ||
2231 | rval = qla2x00_loopback_test(vha, &elreq, response); | ||
2232 | if (IS_QLA81XX(ha)) { | ||
2233 | if (response[0] == MBS_COMMAND_ERROR && response[1] == MBS_LB_RESET) { | ||
2234 | DEBUG2(printk(KERN_ERR "%s(%ld): ABORTing " | ||
2235 | "ISP\n", __func__, vha->host_no)); | ||
2236 | set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); | ||
2237 | qla2xxx_wake_dpc(vha); | ||
2238 | } | ||
2239 | } | ||
2240 | } else { | ||
2241 | type = "FC_BSG_HST_VENDOR_ECHO_DIAG"; | ||
2242 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
2243 | "scsi(%ld) bsg rqst type: %s vendor rqst type: %x options: %x.\n", | ||
2244 | vha->host_no, type, vendor_cmd, elreq.options)); | ||
2245 | |||
2246 | command_sent = INT_DEF_LB_ECHO_CMD; | ||
2247 | rval = qla2x00_echo_test(vha, &elreq, response); | ||
2248 | } | ||
2249 | break; | ||
2250 | case QLA84_RESET: | ||
2251 | if (!IS_QLA84XX(vha->hw)) { | ||
2252 | rval = -EINVAL; | ||
2253 | DEBUG16(printk( | ||
2254 | "%s(%ld): 8xxx exiting.\n", | ||
2255 | __func__, vha->host_no)); | ||
2256 | return rval; | ||
2257 | } | ||
2258 | rval = qla84xx_reset(vha, &elreq, bsg_job); | ||
2259 | break; | ||
2260 | case QLA84_MGMT_CMD: | ||
2261 | if (!IS_QLA84XX(vha->hw)) { | ||
2262 | rval = -EINVAL; | ||
2263 | DEBUG16(printk( | ||
2264 | "%s(%ld): 8xxx exiting.\n", | ||
2265 | __func__, vha->host_no)); | ||
2266 | return rval; | ||
2267 | } | ||
2268 | rval = qla84xx_mgmt_cmd(vha, &elreq, bsg_job); | ||
2269 | break; | ||
2270 | default: | ||
2271 | rval = -ENOSYS; | ||
2272 | } | ||
2273 | |||
2274 | if (rval != QLA_SUCCESS) { | ||
2275 | DEBUG2(qla_printk(KERN_WARNING, ha, | ||
2276 | "scsi(%ld) Vendor request %s failed\n", vha->host_no, type)); | ||
2277 | rval = 0; | ||
2278 | bsg_job->reply->result = (DID_ERROR << 16); | ||
2279 | bsg_job->reply->reply_payload_rcv_len = 0; | ||
2280 | fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply); | ||
2281 | memcpy( fw_sts_ptr, response, sizeof(response)); | ||
2282 | fw_sts_ptr += sizeof(response); | ||
2283 | *fw_sts_ptr = command_sent; | ||
2284 | } else { | ||
2285 | DEBUG2(qla_printk(KERN_WARNING, ha, | ||
2286 | "scsi(%ld) Vendor request %s completed\n", vha->host_no, type)); | ||
2287 | rval = bsg_job->reply->result = 0; | ||
2288 | bsg_job->reply_len = sizeof(struct fc_bsg_reply) + sizeof(response) + sizeof(uint8_t); | ||
2289 | bsg_job->reply->reply_payload_rcv_len = bsg_job->reply_payload.payload_len; | ||
2290 | fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply); | ||
2291 | memcpy(fw_sts_ptr, response, sizeof(response)); | ||
2292 | fw_sts_ptr += sizeof(response); | ||
2293 | *fw_sts_ptr = command_sent; | ||
2294 | sg_copy_from_buffer(bsg_job->reply_payload.sg_list, | ||
2295 | bsg_job->reply_payload.sg_cnt, rsp_data, | ||
2296 | rsp_data_len); | ||
2297 | } | ||
2298 | bsg_job->job_done(bsg_job); | ||
2299 | |||
2300 | done_unmap_sg: | ||
2301 | |||
2302 | if(req_data) | ||
2303 | dma_free_coherent(&ha->pdev->dev, req_data_len, | ||
2304 | req_data, req_data_dma); | ||
2305 | dma_unmap_sg(&ha->pdev->dev, | ||
2306 | bsg_job->request_payload.sg_list, | ||
2307 | bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); | ||
2308 | dma_unmap_sg(&ha->pdev->dev, | ||
2309 | bsg_job->reply_payload.sg_list, | ||
2310 | bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); | ||
2311 | |||
2312 | done: | ||
2313 | return rval; | ||
2314 | } | ||
2315 | |||
2316 | static int | ||
2317 | qla24xx_bsg_request(struct fc_bsg_job *bsg_job) | ||
2318 | { | ||
2319 | int ret = -EINVAL; | ||
2320 | |||
2321 | switch (bsg_job->request->msgcode) { | ||
2322 | case FC_BSG_RPT_ELS: | ||
2323 | case FC_BSG_HST_ELS_NOLOGIN: | ||
2324 | ret = qla2x00_process_els(bsg_job); | ||
2325 | break; | ||
2326 | case FC_BSG_HST_CT: | ||
2327 | ret = qla2x00_process_ct(bsg_job); | ||
2328 | break; | ||
2329 | case FC_BSG_HST_VENDOR: | ||
2330 | ret = qla2x00_process_vendor_specific(bsg_job); | ||
2331 | break; | ||
2332 | case FC_BSG_HST_ADD_RPORT: | ||
2333 | case FC_BSG_HST_DEL_RPORT: | ||
2334 | case FC_BSG_RPT_CT: | ||
2335 | default: | ||
2336 | DEBUG2(printk("qla2xxx: unsupported BSG request\n")); | ||
2337 | break; | ||
2338 | } | ||
2339 | return ret; | ||
2340 | } | ||
2341 | |||
2342 | static int | ||
2343 | qla24xx_bsg_timeout(struct fc_bsg_job *bsg_job) | ||
2344 | { | ||
2345 | scsi_qla_host_t *vha = shost_priv(bsg_job->shost); | ||
2346 | struct qla_hw_data *ha = vha->hw; | ||
2347 | srb_t *sp; | ||
2348 | int cnt, que; | ||
2349 | unsigned long flags; | ||
2350 | struct req_que *req; | ||
2351 | struct srb_bsg *sp_bsg; | ||
2352 | |||
2353 | /* find the bsg job from the active list of commands */ | ||
2354 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
2355 | for (que = 0; que < ha->max_req_queues; que++) { | ||
2356 | req = ha->req_q_map[que]; | ||
2357 | if (!req) | ||
2358 | continue; | ||
2359 | |||
2360 | for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++ ) { | ||
2361 | sp = req->outstanding_cmds[cnt]; | ||
2362 | |||
2363 | if (sp) { | ||
2364 | sp_bsg = (struct srb_bsg*)sp->ctx; | ||
2365 | |||
2366 | if (((sp_bsg->ctx.type == SRB_CT_CMD) || | ||
2367 | (sp_bsg->ctx.type == SRB_ELS_CMD_RPT) | ||
2368 | || ( sp_bsg->ctx.type == SRB_ELS_CMD_HST)) && | ||
2369 | (sp_bsg->bsg_job == bsg_job)) { | ||
2370 | if (ha->isp_ops->abort_command(sp)) { | ||
2371 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
2372 | "scsi(%ld): mbx abort_command failed\n", vha->host_no)); | ||
2373 | bsg_job->req->errors = bsg_job->reply->result = -EIO; | ||
2374 | } else { | ||
2375 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
2376 | "scsi(%ld): mbx abort_command success\n", vha->host_no)); | ||
2377 | bsg_job->req->errors = bsg_job->reply->result = 0; | ||
2378 | } | ||
2379 | goto done; | ||
2380 | } | ||
2381 | } | ||
2382 | } | ||
2383 | } | ||
2384 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
2385 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
2386 | "scsi(%ld) SRB not found to abort\n", vha->host_no)); | ||
2387 | bsg_job->req->errors = bsg_job->reply->result = -ENXIO; | ||
2388 | return 0; | ||
2389 | |||
2390 | done: | ||
2391 | if (bsg_job->request->msgcode == FC_BSG_HST_CT) | ||
2392 | kfree(sp->fcport); | ||
2393 | kfree(sp->ctx); | ||
2394 | mempool_free(sp, ha->srb_mempool); | ||
2395 | return 0; | ||
2396 | } | ||
2397 | |||
1798 | struct fc_function_template qla2xxx_transport_functions = { | 2398 | struct fc_function_template qla2xxx_transport_functions = { |
1799 | 2399 | ||
1800 | .show_host_node_name = 1, | 2400 | .show_host_node_name = 1, |
@@ -1838,6 +2438,8 @@ struct fc_function_template qla2xxx_transport_functions = { | |||
1838 | .vport_create = qla24xx_vport_create, | 2438 | .vport_create = qla24xx_vport_create, |
1839 | .vport_disable = qla24xx_vport_disable, | 2439 | .vport_disable = qla24xx_vport_disable, |
1840 | .vport_delete = qla24xx_vport_delete, | 2440 | .vport_delete = qla24xx_vport_delete, |
2441 | .bsg_request = qla24xx_bsg_request, | ||
2442 | .bsg_timeout = qla24xx_bsg_timeout, | ||
1841 | }; | 2443 | }; |
1842 | 2444 | ||
1843 | struct fc_function_template qla2xxx_transport_vport_functions = { | 2445 | struct fc_function_template qla2xxx_transport_vport_functions = { |
@@ -1878,6 +2480,8 @@ struct fc_function_template qla2xxx_transport_vport_functions = { | |||
1878 | .dev_loss_tmo_callbk = qla2x00_dev_loss_tmo_callbk, | 2480 | .dev_loss_tmo_callbk = qla2x00_dev_loss_tmo_callbk, |
1879 | .terminate_rport_io = qla2x00_terminate_rport_io, | 2481 | .terminate_rport_io = qla2x00_terminate_rport_io, |
1880 | .get_fc_host_stats = qla2x00_get_fc_host_stats, | 2482 | .get_fc_host_stats = qla2x00_get_fc_host_stats, |
2483 | .bsg_request = qla24xx_bsg_request, | ||
2484 | .bsg_timeout = qla24xx_bsg_timeout, | ||
1881 | }; | 2485 | }; |
1882 | 2486 | ||
1883 | void | 2487 | void |
@@ -1906,3 +2510,125 @@ qla2x00_init_host_attr(scsi_qla_host_t *vha) | |||
1906 | speed = FC_PORTSPEED_1GBIT; | 2510 | speed = FC_PORTSPEED_1GBIT; |
1907 | fc_host_supported_speeds(vha->host) = speed; | 2511 | fc_host_supported_speeds(vha->host) = speed; |
1908 | } | 2512 | } |
2513 | static int | ||
2514 | qla84xx_reset(scsi_qla_host_t *ha, struct msg_echo_lb *mreq, struct fc_bsg_job *bsg_job) | ||
2515 | { | ||
2516 | int ret = 0; | ||
2517 | int cmd; | ||
2518 | uint16_t cmd_status; | ||
2519 | |||
2520 | DEBUG16(printk("%s(%ld): entered.\n", __func__, ha->host_no)); | ||
2521 | |||
2522 | cmd = (*((bsg_job->request->rqst_data.h_vendor.vendor_cmd) + 2)) | ||
2523 | == A84_RESET_FLAG_ENABLE_DIAG_FW ? | ||
2524 | A84_ISSUE_RESET_DIAG_FW : A84_ISSUE_RESET_OP_FW; | ||
2525 | ret = qla84xx_reset_chip(ha, cmd == A84_ISSUE_RESET_DIAG_FW, | ||
2526 | &cmd_status); | ||
2527 | return ret; | ||
2528 | } | ||
2529 | |||
2530 | static int | ||
2531 | qla84xx_mgmt_cmd(scsi_qla_host_t *ha, struct msg_echo_lb *mreq, struct fc_bsg_job *bsg_job) | ||
2532 | { | ||
2533 | struct access_chip_84xx *mn; | ||
2534 | dma_addr_t mn_dma, mgmt_dma; | ||
2535 | void *mgmt_b = NULL; | ||
2536 | int ret = 0; | ||
2537 | int rsp_hdr_len, len = 0; | ||
2538 | struct qla84_msg_mgmt *ql84_mgmt; | ||
2539 | |||
2540 | ql84_mgmt = (struct qla84_msg_mgmt *) vmalloc(sizeof(struct qla84_msg_mgmt)); | ||
2541 | ql84_mgmt->cmd = | ||
2542 | *((uint16_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 2)); | ||
2543 | ql84_mgmt->mgmtp.u.mem.start_addr = | ||
2544 | *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 3)); | ||
2545 | ql84_mgmt->len = | ||
2546 | *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 4)); | ||
2547 | ql84_mgmt->mgmtp.u.config.id = | ||
2548 | *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 5)); | ||
2549 | ql84_mgmt->mgmtp.u.config.param0 = | ||
2550 | *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 6)); | ||
2551 | ql84_mgmt->mgmtp.u.config.param1 = | ||
2552 | *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 7)); | ||
2553 | ql84_mgmt->mgmtp.u.info.type = | ||
2554 | *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 8)); | ||
2555 | ql84_mgmt->mgmtp.u.info.context = | ||
2556 | *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 9)); | ||
2557 | |||
2558 | rsp_hdr_len = bsg_job->request_payload.payload_len; | ||
2559 | |||
2560 | mn = dma_pool_alloc(ha->hw->s_dma_pool, GFP_KERNEL, &mn_dma); | ||
2561 | if (mn == NULL) { | ||
2562 | DEBUG2(printk(KERN_ERR "%s: dma alloc for fw buffer " | ||
2563 | "failed%lu\n", __func__, ha->host_no)); | ||
2564 | return -ENOMEM; | ||
2565 | } | ||
2566 | |||
2567 | memset(mn, 0, sizeof (struct access_chip_84xx)); | ||
2568 | |||
2569 | mn->entry_type = ACCESS_CHIP_IOCB_TYPE; | ||
2570 | mn->entry_count = 1; | ||
2571 | |||
2572 | switch (ql84_mgmt->cmd) { | ||
2573 | case QLA84_MGMT_READ_MEM: | ||
2574 | mn->options = cpu_to_le16(ACO_DUMP_MEMORY); | ||
2575 | mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.mem.start_addr); | ||
2576 | break; | ||
2577 | case QLA84_MGMT_WRITE_MEM: | ||
2578 | mn->options = cpu_to_le16(ACO_LOAD_MEMORY); | ||
2579 | mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.mem.start_addr); | ||
2580 | break; | ||
2581 | case QLA84_MGMT_CHNG_CONFIG: | ||
2582 | mn->options = cpu_to_le16(ACO_CHANGE_CONFIG_PARAM); | ||
2583 | mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.config.id); | ||
2584 | mn->parameter2 = cpu_to_le32(ql84_mgmt->mgmtp.u.config.param0); | ||
2585 | mn->parameter3 = cpu_to_le32(ql84_mgmt->mgmtp.u.config.param1); | ||
2586 | break; | ||
2587 | case QLA84_MGMT_GET_INFO: | ||
2588 | mn->options = cpu_to_le16(ACO_REQUEST_INFO); | ||
2589 | mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.info.type); | ||
2590 | mn->parameter2 = cpu_to_le32(ql84_mgmt->mgmtp.u.info.context); | ||
2591 | break; | ||
2592 | default: | ||
2593 | ret = -EIO; | ||
2594 | goto exit_mgmt0; | ||
2595 | } | ||
2596 | |||
2597 | if ((len == ql84_mgmt->len) && | ||
2598 | ql84_mgmt->cmd != QLA84_MGMT_CHNG_CONFIG) { | ||
2599 | mgmt_b = dma_alloc_coherent(&ha->hw->pdev->dev, len, | ||
2600 | &mgmt_dma, GFP_KERNEL); | ||
2601 | if (mgmt_b == NULL) { | ||
2602 | DEBUG2(printk(KERN_ERR "%s: dma alloc mgmt_b " | ||
2603 | "failed%lu\n", __func__, ha->host_no)); | ||
2604 | ret = -ENOMEM; | ||
2605 | goto exit_mgmt0; | ||
2606 | } | ||
2607 | mn->total_byte_cnt = cpu_to_le32(ql84_mgmt->len); | ||
2608 | mn->dseg_count = cpu_to_le16(1); | ||
2609 | mn->dseg_address[0] = cpu_to_le32(LSD(mgmt_dma)); | ||
2610 | mn->dseg_address[1] = cpu_to_le32(MSD(mgmt_dma)); | ||
2611 | mn->dseg_length = cpu_to_le32(len); | ||
2612 | |||
2613 | if (ql84_mgmt->cmd == QLA84_MGMT_WRITE_MEM) { | ||
2614 | memcpy(mgmt_b, ql84_mgmt->payload, len); | ||
2615 | } | ||
2616 | } | ||
2617 | |||
2618 | ret = qla2x00_issue_iocb(ha, mn, mn_dma, 0); | ||
2619 | if ((ret != QLA_SUCCESS) || (ql84_mgmt->cmd == QLA84_MGMT_WRITE_MEM) | ||
2620 | || (ql84_mgmt->cmd == QLA84_MGMT_CHNG_CONFIG)) { | ||
2621 | if (ret != QLA_SUCCESS) | ||
2622 | DEBUG2(printk(KERN_ERR "%s(%lu): failed\n", | ||
2623 | __func__, ha->host_no)); | ||
2624 | } else if ((ql84_mgmt->cmd == QLA84_MGMT_READ_MEM) || | ||
2625 | (ql84_mgmt->cmd == QLA84_MGMT_GET_INFO)) { | ||
2626 | } | ||
2627 | |||
2628 | if (mgmt_b) | ||
2629 | dma_free_coherent(&ha->hw->pdev->dev, len, mgmt_b, mgmt_dma); | ||
2630 | |||
2631 | exit_mgmt0: | ||
2632 | dma_pool_free(ha->hw->s_dma_pool, mn, mn_dma); | ||
2633 | return ret; | ||
2634 | } | ||