diff options
-rw-r--r-- | drivers/scsi/qla2xxx/Makefile | 2 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_attr.c | 702 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_bsg.c | 1040 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_bsg.h | 135 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_def.h | 125 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_gbl.h | 8 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_mbx.c | 49 |
7 files changed, 1230 insertions, 831 deletions
diff --git a/drivers/scsi/qla2xxx/Makefile b/drivers/scsi/qla2xxx/Makefile index c51fd1f8663..1014db6f992 100644 --- a/drivers/scsi/qla2xxx/Makefile +++ b/drivers/scsi/qla2xxx/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | qla2xxx-y := qla_os.o qla_init.o qla_mbx.o qla_iocb.o qla_isr.o qla_gs.o \ | 1 | qla2xxx-y := qla_os.o qla_init.o qla_mbx.o qla_iocb.o qla_isr.o qla_gs.o \ |
2 | qla_dbg.o qla_sup.o qla_attr.o qla_mid.o qla_dfs.o | 2 | qla_dbg.o qla_sup.o qla_attr.o qla_mid.o qla_dfs.o qla_bsg.o |
3 | 3 | ||
4 | obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx.o | 4 | obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx.o |
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 1c7ef55966f..90bf7ad42f6 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c | |||
@@ -12,9 +12,7 @@ | |||
12 | #include <linux/delay.h> | 12 | #include <linux/delay.h> |
13 | 13 | ||
14 | static int qla24xx_vport_disable(struct fc_vport *, bool); | 14 | static int qla24xx_vport_disable(struct fc_vport *, bool); |
15 | static int qla84xx_reset(scsi_qla_host_t *, struct msg_echo_lb *, struct fc_bsg_job *); | 15 | |
16 | int qla84xx_reset_chip(scsi_qla_host_t *, uint16_t, uint16_t *); | ||
17 | static int qla84xx_mgmt_cmd(scsi_qla_host_t *, struct msg_echo_lb *, struct fc_bsg_job *); | ||
18 | /* SYSFS attributes --------------------------------------------------------- */ | 16 | /* SYSFS attributes --------------------------------------------------------- */ |
19 | 17 | ||
20 | static ssize_t | 18 | static ssize_t |
@@ -1825,582 +1823,6 @@ qla24xx_vport_disable(struct fc_vport *fc_vport, bool disable) | |||
1825 | return 0; | 1823 | return 0; |
1826 | } | 1824 | } |
1827 | 1825 | ||
1828 | /* BSG support for ELS/CT pass through */ | ||
1829 | inline srb_t * | ||
1830 | qla2x00_get_ctx_bsg_sp(scsi_qla_host_t *vha, fc_port_t *fcport, size_t size) | ||
1831 | { | ||
1832 | srb_t *sp; | ||
1833 | struct qla_hw_data *ha = vha->hw; | ||
1834 | struct srb_bsg_ctx *ctx; | ||
1835 | |||
1836 | sp = mempool_alloc(ha->srb_mempool, GFP_KERNEL); | ||
1837 | if (!sp) | ||
1838 | goto done; | ||
1839 | ctx = kzalloc(size, GFP_KERNEL); | ||
1840 | if (!ctx) { | ||
1841 | mempool_free(sp, ha->srb_mempool); | ||
1842 | goto done; | ||
1843 | } | ||
1844 | |||
1845 | memset(sp, 0, sizeof(*sp)); | ||
1846 | sp->fcport = fcport; | ||
1847 | sp->ctx = ctx; | ||
1848 | done: | ||
1849 | return sp; | ||
1850 | } | ||
1851 | |||
1852 | static int | ||
1853 | qla2x00_process_els(struct fc_bsg_job *bsg_job) | ||
1854 | { | ||
1855 | struct fc_rport *rport; | ||
1856 | fc_port_t *fcport; | ||
1857 | struct Scsi_Host *host; | ||
1858 | scsi_qla_host_t *vha; | ||
1859 | struct qla_hw_data *ha; | ||
1860 | srb_t *sp; | ||
1861 | const char *type; | ||
1862 | int req_sg_cnt, rsp_sg_cnt; | ||
1863 | int rval = (DRIVER_ERROR << 16); | ||
1864 | uint16_t nextlid = 0; | ||
1865 | struct srb_bsg *els; | ||
1866 | |||
1867 | /* Multiple SG's are not supported for ELS requests */ | ||
1868 | if (bsg_job->request_payload.sg_cnt > 1 || | ||
1869 | bsg_job->reply_payload.sg_cnt > 1) { | ||
1870 | DEBUG2(printk(KERN_INFO | ||
1871 | "multiple SG's are not supported for ELS requests" | ||
1872 | " [request_sg_cnt: %x reply_sg_cnt: %x]\n", | ||
1873 | bsg_job->request_payload.sg_cnt, | ||
1874 | bsg_job->reply_payload.sg_cnt)); | ||
1875 | rval = -EPERM; | ||
1876 | goto done; | ||
1877 | } | ||
1878 | |||
1879 | /* ELS request for rport */ | ||
1880 | if (bsg_job->request->msgcode == FC_BSG_RPT_ELS) { | ||
1881 | rport = bsg_job->rport; | ||
1882 | fcport = *(fc_port_t **) rport->dd_data; | ||
1883 | host = rport_to_shost(rport); | ||
1884 | vha = shost_priv(host); | ||
1885 | ha = vha->hw; | ||
1886 | type = "FC_BSG_RPT_ELS"; | ||
1887 | |||
1888 | /* make sure the rport is logged in, | ||
1889 | * if not perform fabric login | ||
1890 | */ | ||
1891 | if (qla2x00_fabric_login(vha, fcport, &nextlid)) { | ||
1892 | DEBUG2(qla_printk(KERN_WARNING, ha, | ||
1893 | "failed to login port %06X for ELS passthru\n", | ||
1894 | fcport->d_id.b24)); | ||
1895 | rval = -EIO; | ||
1896 | goto done; | ||
1897 | } | ||
1898 | } else { | ||
1899 | host = bsg_job->shost; | ||
1900 | vha = shost_priv(host); | ||
1901 | ha = vha->hw; | ||
1902 | type = "FC_BSG_HST_ELS_NOLOGIN"; | ||
1903 | |||
1904 | /* Allocate a dummy fcport structure, since functions | ||
1905 | * preparing the IOCB and mailbox command retrieves port | ||
1906 | * specific information from fcport structure. For Host based | ||
1907 | * ELS commands there will be no fcport structure allocated | ||
1908 | */ | ||
1909 | fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL); | ||
1910 | if (!fcport) { | ||
1911 | rval = -ENOMEM; | ||
1912 | goto done; | ||
1913 | } | ||
1914 | |||
1915 | /* Initialize all required fields of fcport */ | ||
1916 | fcport->vha = vha; | ||
1917 | fcport->vp_idx = vha->vp_idx; | ||
1918 | fcport->d_id.b.al_pa = | ||
1919 | bsg_job->request->rqst_data.h_els.port_id[0]; | ||
1920 | fcport->d_id.b.area = | ||
1921 | bsg_job->request->rqst_data.h_els.port_id[1]; | ||
1922 | fcport->d_id.b.domain = | ||
1923 | bsg_job->request->rqst_data.h_els.port_id[2]; | ||
1924 | fcport->loop_id = | ||
1925 | (fcport->d_id.b.al_pa == 0xFD) ? | ||
1926 | NPH_FABRIC_CONTROLLER : NPH_F_PORT; | ||
1927 | } | ||
1928 | |||
1929 | if (!vha->flags.online) { | ||
1930 | DEBUG2(qla_printk(KERN_WARNING, ha, | ||
1931 | "host not online\n")); | ||
1932 | rval = -EIO; | ||
1933 | goto done; | ||
1934 | } | ||
1935 | |||
1936 | req_sg_cnt = | ||
1937 | dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, | ||
1938 | bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); | ||
1939 | if (!req_sg_cnt) { | ||
1940 | rval = -ENOMEM; | ||
1941 | goto done_free_fcport; | ||
1942 | } | ||
1943 | rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, | ||
1944 | bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); | ||
1945 | if (!rsp_sg_cnt) { | ||
1946 | rval = -ENOMEM; | ||
1947 | goto done_free_fcport; | ||
1948 | } | ||
1949 | |||
1950 | if ((req_sg_cnt != bsg_job->request_payload.sg_cnt) || | ||
1951 | (rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) | ||
1952 | { | ||
1953 | DEBUG2(printk(KERN_INFO | ||
1954 | "dma mapping resulted in different sg counts \ | ||
1955 | [request_sg_cnt: %x dma_request_sg_cnt: %x\ | ||
1956 | reply_sg_cnt: %x dma_reply_sg_cnt: %x]\n", | ||
1957 | bsg_job->request_payload.sg_cnt, req_sg_cnt, | ||
1958 | bsg_job->reply_payload.sg_cnt, rsp_sg_cnt)); | ||
1959 | rval = -EAGAIN; | ||
1960 | goto done_unmap_sg; | ||
1961 | } | ||
1962 | |||
1963 | /* Alloc SRB structure */ | ||
1964 | sp = qla2x00_get_ctx_bsg_sp(vha, fcport, sizeof(struct srb_bsg)); | ||
1965 | if (!sp) { | ||
1966 | rval = -ENOMEM; | ||
1967 | goto done_unmap_sg; | ||
1968 | } | ||
1969 | |||
1970 | els = sp->ctx; | ||
1971 | els->ctx.type = | ||
1972 | (bsg_job->request->msgcode == FC_BSG_RPT_ELS ? | ||
1973 | SRB_ELS_CMD_RPT : SRB_ELS_CMD_HST); | ||
1974 | els->bsg_job = bsg_job; | ||
1975 | |||
1976 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
1977 | "scsi(%ld:%x): bsg rqst type: %s els type: %x - loop-id=%x " | ||
1978 | "portid=%02x%02x%02x.\n", vha->host_no, sp->handle, type, | ||
1979 | bsg_job->request->rqst_data.h_els.command_code, | ||
1980 | fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area, | ||
1981 | fcport->d_id.b.al_pa)); | ||
1982 | |||
1983 | rval = qla2x00_start_sp(sp); | ||
1984 | if (rval != QLA_SUCCESS) { | ||
1985 | kfree(sp->ctx); | ||
1986 | mempool_free(sp, ha->srb_mempool); | ||
1987 | rval = -EIO; | ||
1988 | goto done_unmap_sg; | ||
1989 | } | ||
1990 | return rval; | ||
1991 | |||
1992 | done_unmap_sg: | ||
1993 | dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, | ||
1994 | bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); | ||
1995 | dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, | ||
1996 | bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); | ||
1997 | goto done_free_fcport; | ||
1998 | |||
1999 | done_free_fcport: | ||
2000 | if (bsg_job->request->msgcode == FC_BSG_HST_ELS_NOLOGIN) | ||
2001 | kfree(fcport); | ||
2002 | done: | ||
2003 | return rval; | ||
2004 | } | ||
2005 | |||
2006 | static int | ||
2007 | qla2x00_process_ct(struct fc_bsg_job *bsg_job) | ||
2008 | { | ||
2009 | srb_t *sp; | ||
2010 | struct Scsi_Host *host = bsg_job->shost; | ||
2011 | scsi_qla_host_t *vha = shost_priv(host); | ||
2012 | struct qla_hw_data *ha = vha->hw; | ||
2013 | int rval = (DRIVER_ERROR << 16); | ||
2014 | int req_sg_cnt, rsp_sg_cnt; | ||
2015 | uint16_t loop_id; | ||
2016 | struct fc_port *fcport; | ||
2017 | char *type = "FC_BSG_HST_CT"; | ||
2018 | struct srb_bsg *ct; | ||
2019 | |||
2020 | /* pass through is supported only for ISP 4Gb or higher */ | ||
2021 | if (!IS_FWI2_CAPABLE(ha)) { | ||
2022 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
2023 | "scsi(%ld):Firmware is not capable to support FC " | ||
2024 | "CT pass thru\n", vha->host_no)); | ||
2025 | rval = -EPERM; | ||
2026 | goto done; | ||
2027 | } | ||
2028 | |||
2029 | req_sg_cnt = | ||
2030 | dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, | ||
2031 | bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); | ||
2032 | if (!req_sg_cnt) { | ||
2033 | rval = -ENOMEM; | ||
2034 | goto done; | ||
2035 | } | ||
2036 | |||
2037 | rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, | ||
2038 | bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); | ||
2039 | if (!rsp_sg_cnt) { | ||
2040 | rval = -ENOMEM; | ||
2041 | goto done; | ||
2042 | } | ||
2043 | |||
2044 | if ((req_sg_cnt != bsg_job->request_payload.sg_cnt) || | ||
2045 | (rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) | ||
2046 | { | ||
2047 | DEBUG2(qla_printk(KERN_WARNING, ha, | ||
2048 | "dma mapping resulted in different sg counts \ | ||
2049 | [request_sg_cnt: %x dma_request_sg_cnt: %x\ | ||
2050 | reply_sg_cnt: %x dma_reply_sg_cnt: %x]\n", | ||
2051 | bsg_job->request_payload.sg_cnt, req_sg_cnt, | ||
2052 | bsg_job->reply_payload.sg_cnt, rsp_sg_cnt)); | ||
2053 | rval = -EAGAIN; | ||
2054 | goto done_unmap_sg; | ||
2055 | } | ||
2056 | |||
2057 | if (!vha->flags.online) { | ||
2058 | DEBUG2(qla_printk(KERN_WARNING, ha, | ||
2059 | "host not online\n")); | ||
2060 | rval = -EIO; | ||
2061 | goto done_unmap_sg; | ||
2062 | } | ||
2063 | |||
2064 | loop_id = | ||
2065 | (bsg_job->request->rqst_data.h_ct.preamble_word1 & 0xFF000000) | ||
2066 | >> 24; | ||
2067 | switch (loop_id) { | ||
2068 | case 0xFC: | ||
2069 | loop_id = cpu_to_le16(NPH_SNS); | ||
2070 | break; | ||
2071 | case 0xFA: | ||
2072 | loop_id = vha->mgmt_svr_loop_id; | ||
2073 | break; | ||
2074 | default: | ||
2075 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
2076 | "Unknown loop id: %x\n", loop_id)); | ||
2077 | rval = -EINVAL; | ||
2078 | goto done_unmap_sg; | ||
2079 | } | ||
2080 | |||
2081 | /* Allocate a dummy fcport structure, since functions preparing the | ||
2082 | * IOCB and mailbox command retrieves port specific information | ||
2083 | * from fcport structure. For Host based ELS commands there will be | ||
2084 | * no fcport structure allocated | ||
2085 | */ | ||
2086 | fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL); | ||
2087 | if (!fcport) | ||
2088 | { | ||
2089 | rval = -ENOMEM; | ||
2090 | goto done_unmap_sg; | ||
2091 | } | ||
2092 | |||
2093 | /* Initialize all required fields of fcport */ | ||
2094 | fcport->vha = vha; | ||
2095 | fcport->vp_idx = vha->vp_idx; | ||
2096 | fcport->d_id.b.al_pa = bsg_job->request->rqst_data.h_ct.port_id[0]; | ||
2097 | fcport->d_id.b.area = bsg_job->request->rqst_data.h_ct.port_id[1]; | ||
2098 | fcport->d_id.b.domain = bsg_job->request->rqst_data.h_ct.port_id[2]; | ||
2099 | fcport->loop_id = loop_id; | ||
2100 | |||
2101 | /* Alloc SRB structure */ | ||
2102 | sp = qla2x00_get_ctx_bsg_sp(vha, fcport, sizeof(struct srb_bsg)); | ||
2103 | if (!sp) { | ||
2104 | rval = -ENOMEM; | ||
2105 | goto done_free_fcport; | ||
2106 | } | ||
2107 | |||
2108 | ct = sp->ctx; | ||
2109 | ct->ctx.type = SRB_CT_CMD; | ||
2110 | ct->bsg_job = bsg_job; | ||
2111 | |||
2112 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
2113 | "scsi(%ld:%x): bsg rqst type: %s els type: %x - loop-id=%x " | ||
2114 | "portid=%02x%02x%02x.\n", vha->host_no, sp->handle, type, | ||
2115 | (bsg_job->request->rqst_data.h_ct.preamble_word2 >> 16), | ||
2116 | fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area, | ||
2117 | fcport->d_id.b.al_pa)); | ||
2118 | |||
2119 | rval = qla2x00_start_sp(sp); | ||
2120 | if (rval != QLA_SUCCESS) { | ||
2121 | kfree(sp->ctx); | ||
2122 | mempool_free(sp, ha->srb_mempool); | ||
2123 | rval = -EIO; | ||
2124 | goto done_free_fcport; | ||
2125 | } | ||
2126 | return rval; | ||
2127 | |||
2128 | done_free_fcport: | ||
2129 | kfree(fcport); | ||
2130 | done_unmap_sg: | ||
2131 | dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, | ||
2132 | bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); | ||
2133 | dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, | ||
2134 | bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); | ||
2135 | done: | ||
2136 | return rval; | ||
2137 | } | ||
2138 | |||
2139 | static int | ||
2140 | qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job) | ||
2141 | { | ||
2142 | struct Scsi_Host *host = bsg_job->shost; | ||
2143 | scsi_qla_host_t *vha = shost_priv(host); | ||
2144 | struct qla_hw_data *ha = vha->hw; | ||
2145 | int rval; | ||
2146 | uint8_t command_sent; | ||
2147 | uint32_t vendor_cmd; | ||
2148 | char *type; | ||
2149 | struct msg_echo_lb elreq; | ||
2150 | uint16_t response[MAILBOX_REGISTER_COUNT]; | ||
2151 | uint8_t* fw_sts_ptr; | ||
2152 | uint8_t *req_data; | ||
2153 | dma_addr_t req_data_dma; | ||
2154 | uint32_t req_data_len; | ||
2155 | uint8_t *rsp_data; | ||
2156 | dma_addr_t rsp_data_dma; | ||
2157 | uint32_t rsp_data_len; | ||
2158 | |||
2159 | if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) || | ||
2160 | test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) || | ||
2161 | test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) { | ||
2162 | rval = -EBUSY; | ||
2163 | goto done; | ||
2164 | } | ||
2165 | |||
2166 | if (!vha->flags.online) { | ||
2167 | DEBUG2(qla_printk(KERN_WARNING, ha, | ||
2168 | "host not online\n")); | ||
2169 | rval = -EIO; | ||
2170 | goto done; | ||
2171 | } | ||
2172 | |||
2173 | elreq.req_sg_cnt = | ||
2174 | dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, | ||
2175 | bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); | ||
2176 | if (!elreq.req_sg_cnt) { | ||
2177 | rval = -ENOMEM; | ||
2178 | goto done; | ||
2179 | } | ||
2180 | elreq.rsp_sg_cnt = | ||
2181 | dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, | ||
2182 | bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); | ||
2183 | if (!elreq.rsp_sg_cnt) { | ||
2184 | rval = -ENOMEM; | ||
2185 | goto done; | ||
2186 | } | ||
2187 | |||
2188 | if ((elreq.req_sg_cnt != bsg_job->request_payload.sg_cnt) || | ||
2189 | (elreq.rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) | ||
2190 | { | ||
2191 | DEBUG2(printk(KERN_INFO | ||
2192 | "dma mapping resulted in different sg counts \ | ||
2193 | [request_sg_cnt: %x dma_request_sg_cnt: %x\ | ||
2194 | reply_sg_cnt: %x dma_reply_sg_cnt: %x]\n", | ||
2195 | bsg_job->request_payload.sg_cnt, elreq.req_sg_cnt, | ||
2196 | bsg_job->reply_payload.sg_cnt, elreq.rsp_sg_cnt)); | ||
2197 | rval = -EAGAIN; | ||
2198 | goto done_unmap_sg; | ||
2199 | } | ||
2200 | req_data_len = rsp_data_len = bsg_job->request_payload.payload_len; | ||
2201 | req_data = dma_alloc_coherent(&ha->pdev->dev, req_data_len, | ||
2202 | &req_data_dma, GFP_KERNEL); | ||
2203 | |||
2204 | rsp_data = dma_alloc_coherent(&ha->pdev->dev, rsp_data_len, | ||
2205 | &rsp_data_dma, GFP_KERNEL); | ||
2206 | |||
2207 | /* Copy the request buffer in req_data now */ | ||
2208 | sg_copy_to_buffer(bsg_job->request_payload.sg_list, | ||
2209 | bsg_job->request_payload.sg_cnt, req_data, | ||
2210 | req_data_len); | ||
2211 | |||
2212 | elreq.send_dma = req_data_dma; | ||
2213 | elreq.rcv_dma = rsp_data_dma; | ||
2214 | elreq.transfer_size = req_data_len; | ||
2215 | |||
2216 | /* Vendor cmd : loopback or ECHO diagnostic | ||
2217 | * Options: | ||
2218 | * Loopback : Either internal or external loopback | ||
2219 | * ECHO: ECHO ELS or Vendor specific FC4 link data | ||
2220 | */ | ||
2221 | vendor_cmd = bsg_job->request->rqst_data.h_vendor.vendor_cmd[0]; | ||
2222 | elreq.options = | ||
2223 | *(((uint32_t *)bsg_job->request->rqst_data.h_vendor.vendor_cmd) | ||
2224 | + 1); | ||
2225 | |||
2226 | switch (bsg_job->request->rqst_data.h_vendor.vendor_cmd[0]) { | ||
2227 | case QL_VND_LOOPBACK: | ||
2228 | if (ha->current_topology != ISP_CFG_F) { | ||
2229 | type = "FC_BSG_HST_VENDOR_LOOPBACK"; | ||
2230 | |||
2231 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
2232 | "scsi(%ld) bsg rqst type: %s vendor rqst type: %x options: %x.\n", | ||
2233 | vha->host_no, type, vendor_cmd, elreq.options)); | ||
2234 | |||
2235 | command_sent = INT_DEF_LB_LOOPBACK_CMD; | ||
2236 | rval = qla2x00_loopback_test(vha, &elreq, response); | ||
2237 | if (IS_QLA81XX(ha)) { | ||
2238 | if (response[0] == MBS_COMMAND_ERROR && response[1] == MBS_LB_RESET) { | ||
2239 | DEBUG2(printk(KERN_ERR "%s(%ld): ABORTing " | ||
2240 | "ISP\n", __func__, vha->host_no)); | ||
2241 | set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); | ||
2242 | qla2xxx_wake_dpc(vha); | ||
2243 | } | ||
2244 | } | ||
2245 | } else { | ||
2246 | type = "FC_BSG_HST_VENDOR_ECHO_DIAG"; | ||
2247 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
2248 | "scsi(%ld) bsg rqst type: %s vendor rqst type: %x options: %x.\n", | ||
2249 | vha->host_no, type, vendor_cmd, elreq.options)); | ||
2250 | |||
2251 | command_sent = INT_DEF_LB_ECHO_CMD; | ||
2252 | rval = qla2x00_echo_test(vha, &elreq, response); | ||
2253 | } | ||
2254 | break; | ||
2255 | case QLA84_RESET: | ||
2256 | if (!IS_QLA84XX(vha->hw)) { | ||
2257 | rval = -EINVAL; | ||
2258 | DEBUG16(printk( | ||
2259 | "%s(%ld): 8xxx exiting.\n", | ||
2260 | __func__, vha->host_no)); | ||
2261 | return rval; | ||
2262 | } | ||
2263 | rval = qla84xx_reset(vha, &elreq, bsg_job); | ||
2264 | break; | ||
2265 | case QLA84_MGMT_CMD: | ||
2266 | if (!IS_QLA84XX(vha->hw)) { | ||
2267 | rval = -EINVAL; | ||
2268 | DEBUG16(printk( | ||
2269 | "%s(%ld): 8xxx exiting.\n", | ||
2270 | __func__, vha->host_no)); | ||
2271 | return rval; | ||
2272 | } | ||
2273 | rval = qla84xx_mgmt_cmd(vha, &elreq, bsg_job); | ||
2274 | break; | ||
2275 | default: | ||
2276 | rval = -ENOSYS; | ||
2277 | } | ||
2278 | |||
2279 | if (rval != QLA_SUCCESS) { | ||
2280 | DEBUG2(qla_printk(KERN_WARNING, ha, | ||
2281 | "scsi(%ld) Vendor request %s failed\n", vha->host_no, type)); | ||
2282 | rval = 0; | ||
2283 | bsg_job->reply->result = (DID_ERROR << 16); | ||
2284 | bsg_job->reply->reply_payload_rcv_len = 0; | ||
2285 | fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply); | ||
2286 | memcpy( fw_sts_ptr, response, sizeof(response)); | ||
2287 | fw_sts_ptr += sizeof(response); | ||
2288 | *fw_sts_ptr = command_sent; | ||
2289 | } else { | ||
2290 | DEBUG2(qla_printk(KERN_WARNING, ha, | ||
2291 | "scsi(%ld) Vendor request %s completed\n", vha->host_no, type)); | ||
2292 | rval = bsg_job->reply->result = 0; | ||
2293 | bsg_job->reply_len = sizeof(struct fc_bsg_reply) + sizeof(response) + sizeof(uint8_t); | ||
2294 | bsg_job->reply->reply_payload_rcv_len = bsg_job->reply_payload.payload_len; | ||
2295 | fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply); | ||
2296 | memcpy(fw_sts_ptr, response, sizeof(response)); | ||
2297 | fw_sts_ptr += sizeof(response); | ||
2298 | *fw_sts_ptr = command_sent; | ||
2299 | sg_copy_from_buffer(bsg_job->reply_payload.sg_list, | ||
2300 | bsg_job->reply_payload.sg_cnt, rsp_data, | ||
2301 | rsp_data_len); | ||
2302 | } | ||
2303 | bsg_job->job_done(bsg_job); | ||
2304 | |||
2305 | done_unmap_sg: | ||
2306 | |||
2307 | if(req_data) | ||
2308 | dma_free_coherent(&ha->pdev->dev, req_data_len, | ||
2309 | req_data, req_data_dma); | ||
2310 | dma_unmap_sg(&ha->pdev->dev, | ||
2311 | bsg_job->request_payload.sg_list, | ||
2312 | bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); | ||
2313 | dma_unmap_sg(&ha->pdev->dev, | ||
2314 | bsg_job->reply_payload.sg_list, | ||
2315 | bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); | ||
2316 | |||
2317 | done: | ||
2318 | return rval; | ||
2319 | } | ||
2320 | |||
2321 | static int | ||
2322 | qla24xx_bsg_request(struct fc_bsg_job *bsg_job) | ||
2323 | { | ||
2324 | int ret = -EINVAL; | ||
2325 | |||
2326 | switch (bsg_job->request->msgcode) { | ||
2327 | case FC_BSG_RPT_ELS: | ||
2328 | case FC_BSG_HST_ELS_NOLOGIN: | ||
2329 | ret = qla2x00_process_els(bsg_job); | ||
2330 | break; | ||
2331 | case FC_BSG_HST_CT: | ||
2332 | ret = qla2x00_process_ct(bsg_job); | ||
2333 | break; | ||
2334 | case FC_BSG_HST_VENDOR: | ||
2335 | ret = qla2x00_process_vendor_specific(bsg_job); | ||
2336 | break; | ||
2337 | case FC_BSG_HST_ADD_RPORT: | ||
2338 | case FC_BSG_HST_DEL_RPORT: | ||
2339 | case FC_BSG_RPT_CT: | ||
2340 | default: | ||
2341 | DEBUG2(printk("qla2xxx: unsupported BSG request\n")); | ||
2342 | break; | ||
2343 | } | ||
2344 | return ret; | ||
2345 | } | ||
2346 | |||
2347 | static int | ||
2348 | qla24xx_bsg_timeout(struct fc_bsg_job *bsg_job) | ||
2349 | { | ||
2350 | scsi_qla_host_t *vha = shost_priv(bsg_job->shost); | ||
2351 | struct qla_hw_data *ha = vha->hw; | ||
2352 | srb_t *sp; | ||
2353 | int cnt, que; | ||
2354 | unsigned long flags; | ||
2355 | struct req_que *req; | ||
2356 | struct srb_bsg *sp_bsg; | ||
2357 | |||
2358 | /* find the bsg job from the active list of commands */ | ||
2359 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
2360 | for (que = 0; que < ha->max_req_queues; que++) { | ||
2361 | req = ha->req_q_map[que]; | ||
2362 | if (!req) | ||
2363 | continue; | ||
2364 | |||
2365 | for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++ ) { | ||
2366 | sp = req->outstanding_cmds[cnt]; | ||
2367 | |||
2368 | if (sp) { | ||
2369 | sp_bsg = (struct srb_bsg*)sp->ctx; | ||
2370 | |||
2371 | if (((sp_bsg->ctx.type == SRB_CT_CMD) || | ||
2372 | (sp_bsg->ctx.type == SRB_ELS_CMD_RPT) | ||
2373 | || ( sp_bsg->ctx.type == SRB_ELS_CMD_HST)) && | ||
2374 | (sp_bsg->bsg_job == bsg_job)) { | ||
2375 | if (ha->isp_ops->abort_command(sp)) { | ||
2376 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
2377 | "scsi(%ld): mbx abort_command failed\n", vha->host_no)); | ||
2378 | bsg_job->req->errors = bsg_job->reply->result = -EIO; | ||
2379 | } else { | ||
2380 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
2381 | "scsi(%ld): mbx abort_command success\n", vha->host_no)); | ||
2382 | bsg_job->req->errors = bsg_job->reply->result = 0; | ||
2383 | } | ||
2384 | goto done; | ||
2385 | } | ||
2386 | } | ||
2387 | } | ||
2388 | } | ||
2389 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
2390 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
2391 | "scsi(%ld) SRB not found to abort\n", vha->host_no)); | ||
2392 | bsg_job->req->errors = bsg_job->reply->result = -ENXIO; | ||
2393 | return 0; | ||
2394 | |||
2395 | done: | ||
2396 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
2397 | if (bsg_job->request->msgcode == FC_BSG_HST_CT) | ||
2398 | kfree(sp->fcport); | ||
2399 | kfree(sp->ctx); | ||
2400 | mempool_free(sp, ha->srb_mempool); | ||
2401 | return 0; | ||
2402 | } | ||
2403 | |||
2404 | struct fc_function_template qla2xxx_transport_functions = { | 1826 | struct fc_function_template qla2xxx_transport_functions = { |
2405 | 1827 | ||
2406 | .show_host_node_name = 1, | 1828 | .show_host_node_name = 1, |
@@ -2516,125 +1938,3 @@ qla2x00_init_host_attr(scsi_qla_host_t *vha) | |||
2516 | speed = FC_PORTSPEED_1GBIT; | 1938 | speed = FC_PORTSPEED_1GBIT; |
2517 | fc_host_supported_speeds(vha->host) = speed; | 1939 | fc_host_supported_speeds(vha->host) = speed; |
2518 | } | 1940 | } |
2519 | static int | ||
2520 | qla84xx_reset(scsi_qla_host_t *ha, struct msg_echo_lb *mreq, struct fc_bsg_job *bsg_job) | ||
2521 | { | ||
2522 | int ret = 0; | ||
2523 | int cmd; | ||
2524 | uint16_t cmd_status; | ||
2525 | |||
2526 | DEBUG16(printk("%s(%ld): entered.\n", __func__, ha->host_no)); | ||
2527 | |||
2528 | cmd = (*((bsg_job->request->rqst_data.h_vendor.vendor_cmd) + 2)) | ||
2529 | == A84_RESET_FLAG_ENABLE_DIAG_FW ? | ||
2530 | A84_ISSUE_RESET_DIAG_FW : A84_ISSUE_RESET_OP_FW; | ||
2531 | ret = qla84xx_reset_chip(ha, cmd == A84_ISSUE_RESET_DIAG_FW, | ||
2532 | &cmd_status); | ||
2533 | return ret; | ||
2534 | } | ||
2535 | |||
2536 | static int | ||
2537 | qla84xx_mgmt_cmd(scsi_qla_host_t *ha, struct msg_echo_lb *mreq, struct fc_bsg_job *bsg_job) | ||
2538 | { | ||
2539 | struct access_chip_84xx *mn; | ||
2540 | dma_addr_t mn_dma, mgmt_dma; | ||
2541 | void *mgmt_b = NULL; | ||
2542 | int ret = 0; | ||
2543 | int rsp_hdr_len, len = 0; | ||
2544 | struct qla84_msg_mgmt *ql84_mgmt; | ||
2545 | |||
2546 | ql84_mgmt = (struct qla84_msg_mgmt *) vmalloc(sizeof(struct qla84_msg_mgmt)); | ||
2547 | ql84_mgmt->cmd = | ||
2548 | *((uint16_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 2)); | ||
2549 | ql84_mgmt->mgmtp.u.mem.start_addr = | ||
2550 | *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 3)); | ||
2551 | ql84_mgmt->len = | ||
2552 | *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 4)); | ||
2553 | ql84_mgmt->mgmtp.u.config.id = | ||
2554 | *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 5)); | ||
2555 | ql84_mgmt->mgmtp.u.config.param0 = | ||
2556 | *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 6)); | ||
2557 | ql84_mgmt->mgmtp.u.config.param1 = | ||
2558 | *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 7)); | ||
2559 | ql84_mgmt->mgmtp.u.info.type = | ||
2560 | *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 8)); | ||
2561 | ql84_mgmt->mgmtp.u.info.context = | ||
2562 | *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 9)); | ||
2563 | |||
2564 | rsp_hdr_len = bsg_job->request_payload.payload_len; | ||
2565 | |||
2566 | mn = dma_pool_alloc(ha->hw->s_dma_pool, GFP_KERNEL, &mn_dma); | ||
2567 | if (mn == NULL) { | ||
2568 | DEBUG2(printk(KERN_ERR "%s: dma alloc for fw buffer " | ||
2569 | "failed%lu\n", __func__, ha->host_no)); | ||
2570 | return -ENOMEM; | ||
2571 | } | ||
2572 | |||
2573 | memset(mn, 0, sizeof (struct access_chip_84xx)); | ||
2574 | |||
2575 | mn->entry_type = ACCESS_CHIP_IOCB_TYPE; | ||
2576 | mn->entry_count = 1; | ||
2577 | |||
2578 | switch (ql84_mgmt->cmd) { | ||
2579 | case QLA84_MGMT_READ_MEM: | ||
2580 | mn->options = cpu_to_le16(ACO_DUMP_MEMORY); | ||
2581 | mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.mem.start_addr); | ||
2582 | break; | ||
2583 | case QLA84_MGMT_WRITE_MEM: | ||
2584 | mn->options = cpu_to_le16(ACO_LOAD_MEMORY); | ||
2585 | mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.mem.start_addr); | ||
2586 | break; | ||
2587 | case QLA84_MGMT_CHNG_CONFIG: | ||
2588 | mn->options = cpu_to_le16(ACO_CHANGE_CONFIG_PARAM); | ||
2589 | mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.config.id); | ||
2590 | mn->parameter2 = cpu_to_le32(ql84_mgmt->mgmtp.u.config.param0); | ||
2591 | mn->parameter3 = cpu_to_le32(ql84_mgmt->mgmtp.u.config.param1); | ||
2592 | break; | ||
2593 | case QLA84_MGMT_GET_INFO: | ||
2594 | mn->options = cpu_to_le16(ACO_REQUEST_INFO); | ||
2595 | mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.info.type); | ||
2596 | mn->parameter2 = cpu_to_le32(ql84_mgmt->mgmtp.u.info.context); | ||
2597 | break; | ||
2598 | default: | ||
2599 | ret = -EIO; | ||
2600 | goto exit_mgmt0; | ||
2601 | } | ||
2602 | |||
2603 | if ((len == ql84_mgmt->len) && | ||
2604 | ql84_mgmt->cmd != QLA84_MGMT_CHNG_CONFIG) { | ||
2605 | mgmt_b = dma_alloc_coherent(&ha->hw->pdev->dev, len, | ||
2606 | &mgmt_dma, GFP_KERNEL); | ||
2607 | if (mgmt_b == NULL) { | ||
2608 | DEBUG2(printk(KERN_ERR "%s: dma alloc mgmt_b " | ||
2609 | "failed%lu\n", __func__, ha->host_no)); | ||
2610 | ret = -ENOMEM; | ||
2611 | goto exit_mgmt0; | ||
2612 | } | ||
2613 | mn->total_byte_cnt = cpu_to_le32(ql84_mgmt->len); | ||
2614 | mn->dseg_count = cpu_to_le16(1); | ||
2615 | mn->dseg_address[0] = cpu_to_le32(LSD(mgmt_dma)); | ||
2616 | mn->dseg_address[1] = cpu_to_le32(MSD(mgmt_dma)); | ||
2617 | mn->dseg_length = cpu_to_le32(len); | ||
2618 | |||
2619 | if (ql84_mgmt->cmd == QLA84_MGMT_WRITE_MEM) { | ||
2620 | memcpy(mgmt_b, ql84_mgmt->payload, len); | ||
2621 | } | ||
2622 | } | ||
2623 | |||
2624 | ret = qla2x00_issue_iocb(ha, mn, mn_dma, 0); | ||
2625 | if ((ret != QLA_SUCCESS) || (ql84_mgmt->cmd == QLA84_MGMT_WRITE_MEM) | ||
2626 | || (ql84_mgmt->cmd == QLA84_MGMT_CHNG_CONFIG)) { | ||
2627 | if (ret != QLA_SUCCESS) | ||
2628 | DEBUG2(printk(KERN_ERR "%s(%lu): failed\n", | ||
2629 | __func__, ha->host_no)); | ||
2630 | } else if ((ql84_mgmt->cmd == QLA84_MGMT_READ_MEM) || | ||
2631 | (ql84_mgmt->cmd == QLA84_MGMT_GET_INFO)) { | ||
2632 | } | ||
2633 | |||
2634 | if (mgmt_b) | ||
2635 | dma_free_coherent(&ha->hw->pdev->dev, len, mgmt_b, mgmt_dma); | ||
2636 | |||
2637 | exit_mgmt0: | ||
2638 | dma_pool_free(ha->hw->s_dma_pool, mn, mn_dma); | ||
2639 | return ret; | ||
2640 | } | ||
diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c new file mode 100644 index 00000000000..c20292fde72 --- /dev/null +++ b/drivers/scsi/qla2xxx/qla_bsg.c | |||
@@ -0,0 +1,1040 @@ | |||
1 | /* | ||
2 | * QLogic Fibre Channel HBA Driver | ||
3 | * Copyright (c) 2003-2008 QLogic Corporation | ||
4 | * | ||
5 | * See LICENSE.qla2xxx for copyright and licensing details. | ||
6 | */ | ||
7 | #include "qla_def.h" | ||
8 | |||
9 | #include <linux/kthread.h> | ||
10 | #include <linux/vmalloc.h> | ||
11 | #include <linux/delay.h> | ||
12 | |||
13 | /* BSG support for ELS/CT pass through */ | ||
14 | inline srb_t * | ||
15 | qla2x00_get_ctx_bsg_sp(scsi_qla_host_t *vha, fc_port_t *fcport, size_t size) | ||
16 | { | ||
17 | srb_t *sp; | ||
18 | struct qla_hw_data *ha = vha->hw; | ||
19 | struct srb_bsg_ctx *ctx; | ||
20 | |||
21 | sp = mempool_alloc(ha->srb_mempool, GFP_KERNEL); | ||
22 | if (!sp) | ||
23 | goto done; | ||
24 | ctx = kzalloc(size, GFP_KERNEL); | ||
25 | if (!ctx) { | ||
26 | mempool_free(sp, ha->srb_mempool); | ||
27 | sp = NULL; | ||
28 | goto done; | ||
29 | } | ||
30 | |||
31 | memset(sp, 0, sizeof(*sp)); | ||
32 | sp->fcport = fcport; | ||
33 | sp->ctx = ctx; | ||
34 | done: | ||
35 | return sp; | ||
36 | } | ||
37 | |||
38 | static int | ||
39 | qla2x00_process_els(struct fc_bsg_job *bsg_job) | ||
40 | { | ||
41 | struct fc_rport *rport; | ||
42 | fc_port_t *fcport; | ||
43 | struct Scsi_Host *host; | ||
44 | scsi_qla_host_t *vha; | ||
45 | struct qla_hw_data *ha; | ||
46 | srb_t *sp; | ||
47 | const char *type; | ||
48 | int req_sg_cnt, rsp_sg_cnt; | ||
49 | int rval = (DRIVER_ERROR << 16); | ||
50 | uint16_t nextlid = 0; | ||
51 | struct srb_bsg *els; | ||
52 | |||
53 | /* Multiple SG's are not supported for ELS requests */ | ||
54 | if (bsg_job->request_payload.sg_cnt > 1 || | ||
55 | bsg_job->reply_payload.sg_cnt > 1) { | ||
56 | DEBUG2(printk(KERN_INFO | ||
57 | "multiple SG's are not supported for ELS requests" | ||
58 | " [request_sg_cnt: %x reply_sg_cnt: %x]\n", | ||
59 | bsg_job->request_payload.sg_cnt, | ||
60 | bsg_job->reply_payload.sg_cnt)); | ||
61 | rval = -EPERM; | ||
62 | goto done; | ||
63 | } | ||
64 | |||
65 | /* ELS request for rport */ | ||
66 | if (bsg_job->request->msgcode == FC_BSG_RPT_ELS) { | ||
67 | rport = bsg_job->rport; | ||
68 | fcport = *(fc_port_t **) rport->dd_data; | ||
69 | host = rport_to_shost(rport); | ||
70 | vha = shost_priv(host); | ||
71 | ha = vha->hw; | ||
72 | type = "FC_BSG_RPT_ELS"; | ||
73 | |||
74 | /* make sure the rport is logged in, | ||
75 | * if not perform fabric login | ||
76 | */ | ||
77 | if (qla2x00_fabric_login(vha, fcport, &nextlid)) { | ||
78 | DEBUG2(qla_printk(KERN_WARNING, ha, | ||
79 | "failed to login port %06X for ELS passthru\n", | ||
80 | fcport->d_id.b24)); | ||
81 | rval = -EIO; | ||
82 | goto done; | ||
83 | } | ||
84 | } else { | ||
85 | host = bsg_job->shost; | ||
86 | vha = shost_priv(host); | ||
87 | ha = vha->hw; | ||
88 | type = "FC_BSG_HST_ELS_NOLOGIN"; | ||
89 | |||
90 | /* Allocate a dummy fcport structure, since functions | ||
91 | * preparing the IOCB and mailbox command retrieves port | ||
92 | * specific information from fcport structure. For Host based | ||
93 | * ELS commands there will be no fcport structure allocated | ||
94 | */ | ||
95 | fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL); | ||
96 | if (!fcport) { | ||
97 | rval = -ENOMEM; | ||
98 | goto done; | ||
99 | } | ||
100 | |||
101 | /* Initialize all required fields of fcport */ | ||
102 | fcport->vha = vha; | ||
103 | fcport->vp_idx = vha->vp_idx; | ||
104 | fcport->d_id.b.al_pa = | ||
105 | bsg_job->request->rqst_data.h_els.port_id[0]; | ||
106 | fcport->d_id.b.area = | ||
107 | bsg_job->request->rqst_data.h_els.port_id[1]; | ||
108 | fcport->d_id.b.domain = | ||
109 | bsg_job->request->rqst_data.h_els.port_id[2]; | ||
110 | fcport->loop_id = | ||
111 | (fcport->d_id.b.al_pa == 0xFD) ? | ||
112 | NPH_FABRIC_CONTROLLER : NPH_F_PORT; | ||
113 | } | ||
114 | |||
115 | if (!vha->flags.online) { | ||
116 | DEBUG2(qla_printk(KERN_WARNING, ha, | ||
117 | "host not online\n")); | ||
118 | rval = -EIO; | ||
119 | goto done; | ||
120 | } | ||
121 | |||
122 | req_sg_cnt = | ||
123 | dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, | ||
124 | bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); | ||
125 | if (!req_sg_cnt) { | ||
126 | rval = -ENOMEM; | ||
127 | goto done_free_fcport; | ||
128 | } | ||
129 | rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, | ||
130 | bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); | ||
131 | if (!rsp_sg_cnt) { | ||
132 | rval = -ENOMEM; | ||
133 | goto done_free_fcport; | ||
134 | } | ||
135 | |||
136 | if ((req_sg_cnt != bsg_job->request_payload.sg_cnt) || | ||
137 | (rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) | ||
138 | { | ||
139 | DEBUG2(printk(KERN_INFO | ||
140 | "dma mapping resulted in different sg counts \ | ||
141 | [request_sg_cnt: %x dma_request_sg_cnt: %x\ | ||
142 | reply_sg_cnt: %x dma_reply_sg_cnt: %x]\n", | ||
143 | bsg_job->request_payload.sg_cnt, req_sg_cnt, | ||
144 | bsg_job->reply_payload.sg_cnt, rsp_sg_cnt)); | ||
145 | rval = -EAGAIN; | ||
146 | goto done_unmap_sg; | ||
147 | } | ||
148 | |||
149 | /* Alloc SRB structure */ | ||
150 | sp = qla2x00_get_ctx_bsg_sp(vha, fcport, sizeof(struct srb_bsg)); | ||
151 | if (!sp) { | ||
152 | rval = -ENOMEM; | ||
153 | goto done_unmap_sg; | ||
154 | } | ||
155 | |||
156 | els = sp->ctx; | ||
157 | els->ctx.type = | ||
158 | (bsg_job->request->msgcode == FC_BSG_RPT_ELS ? | ||
159 | SRB_ELS_CMD_RPT : SRB_ELS_CMD_HST); | ||
160 | els->bsg_job = bsg_job; | ||
161 | |||
162 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
163 | "scsi(%ld:%x): bsg rqst type: %s els type: %x - loop-id=%x " | ||
164 | "portid=%02x%02x%02x.\n", vha->host_no, sp->handle, type, | ||
165 | bsg_job->request->rqst_data.h_els.command_code, | ||
166 | fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area, | ||
167 | fcport->d_id.b.al_pa)); | ||
168 | |||
169 | rval = qla2x00_start_sp(sp); | ||
170 | if (rval != QLA_SUCCESS) { | ||
171 | kfree(sp->ctx); | ||
172 | mempool_free(sp, ha->srb_mempool); | ||
173 | rval = -EIO; | ||
174 | goto done_unmap_sg; | ||
175 | } | ||
176 | return rval; | ||
177 | |||
178 | done_unmap_sg: | ||
179 | dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, | ||
180 | bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); | ||
181 | dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, | ||
182 | bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); | ||
183 | goto done_free_fcport; | ||
184 | |||
185 | done_free_fcport: | ||
186 | if (bsg_job->request->msgcode == FC_BSG_HST_ELS_NOLOGIN) | ||
187 | kfree(fcport); | ||
188 | done: | ||
189 | return rval; | ||
190 | } | ||
191 | |||
192 | static int | ||
193 | qla2x00_process_ct(struct fc_bsg_job *bsg_job) | ||
194 | { | ||
195 | srb_t *sp; | ||
196 | struct Scsi_Host *host = bsg_job->shost; | ||
197 | scsi_qla_host_t *vha = shost_priv(host); | ||
198 | struct qla_hw_data *ha = vha->hw; | ||
199 | int rval = (DRIVER_ERROR << 16); | ||
200 | int req_sg_cnt, rsp_sg_cnt; | ||
201 | uint16_t loop_id; | ||
202 | struct fc_port *fcport; | ||
203 | char *type = "FC_BSG_HST_CT"; | ||
204 | struct srb_bsg *ct; | ||
205 | |||
206 | /* pass through is supported only for ISP 4Gb or higher */ | ||
207 | if (!IS_FWI2_CAPABLE(ha)) { | ||
208 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
209 | "scsi(%ld):Firmware is not capable to support FC " | ||
210 | "CT pass thru\n", vha->host_no)); | ||
211 | rval = -EPERM; | ||
212 | goto done; | ||
213 | } | ||
214 | |||
215 | req_sg_cnt = | ||
216 | dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, | ||
217 | bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); | ||
218 | if (!req_sg_cnt) { | ||
219 | rval = -ENOMEM; | ||
220 | goto done; | ||
221 | } | ||
222 | |||
223 | rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, | ||
224 | bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); | ||
225 | if (!rsp_sg_cnt) { | ||
226 | rval = -ENOMEM; | ||
227 | goto done; | ||
228 | } | ||
229 | |||
230 | if ((req_sg_cnt != bsg_job->request_payload.sg_cnt) || | ||
231 | (rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) | ||
232 | { | ||
233 | DEBUG2(qla_printk(KERN_WARNING, ha, | ||
234 | "[request_sg_cnt: %x dma_request_sg_cnt: %x\ | ||
235 | reply_sg_cnt: %x dma_reply_sg_cnt: %x]\n", | ||
236 | bsg_job->request_payload.sg_cnt, req_sg_cnt, | ||
237 | bsg_job->reply_payload.sg_cnt, rsp_sg_cnt)); | ||
238 | rval = -EAGAIN; | ||
239 | goto done_unmap_sg; | ||
240 | } | ||
241 | |||
242 | if (!vha->flags.online) { | ||
243 | DEBUG2(qla_printk(KERN_WARNING, ha, | ||
244 | "host not online\n")); | ||
245 | rval = -EIO; | ||
246 | goto done_unmap_sg; | ||
247 | } | ||
248 | |||
249 | loop_id = | ||
250 | (bsg_job->request->rqst_data.h_ct.preamble_word1 & 0xFF000000) | ||
251 | >> 24; | ||
252 | switch (loop_id) { | ||
253 | case 0xFC: | ||
254 | loop_id = cpu_to_le16(NPH_SNS); | ||
255 | break; | ||
256 | case 0xFA: | ||
257 | loop_id = vha->mgmt_svr_loop_id; | ||
258 | break; | ||
259 | default: | ||
260 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
261 | "Unknown loop id: %x\n", loop_id)); | ||
262 | rval = -EINVAL; | ||
263 | goto done_unmap_sg; | ||
264 | } | ||
265 | |||
266 | /* Allocate a dummy fcport structure, since functions preparing the | ||
267 | * IOCB and mailbox command retrieves port specific information | ||
268 | * from fcport structure. For Host based ELS commands there will be | ||
269 | * no fcport structure allocated | ||
270 | */ | ||
271 | fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL); | ||
272 | if (!fcport) | ||
273 | { | ||
274 | rval = -ENOMEM; | ||
275 | goto done_unmap_sg; | ||
276 | } | ||
277 | |||
278 | /* Initialize all required fields of fcport */ | ||
279 | fcport->vha = vha; | ||
280 | fcport->vp_idx = vha->vp_idx; | ||
281 | fcport->d_id.b.al_pa = bsg_job->request->rqst_data.h_ct.port_id[0]; | ||
282 | fcport->d_id.b.area = bsg_job->request->rqst_data.h_ct.port_id[1]; | ||
283 | fcport->d_id.b.domain = bsg_job->request->rqst_data.h_ct.port_id[2]; | ||
284 | fcport->loop_id = loop_id; | ||
285 | |||
286 | /* Alloc SRB structure */ | ||
287 | sp = qla2x00_get_ctx_bsg_sp(vha, fcport, sizeof(struct srb_bsg)); | ||
288 | if (!sp) { | ||
289 | rval = -ENOMEM; | ||
290 | goto done_free_fcport; | ||
291 | } | ||
292 | |||
293 | ct = sp->ctx; | ||
294 | ct->ctx.type = SRB_CT_CMD; | ||
295 | ct->bsg_job = bsg_job; | ||
296 | |||
297 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
298 | "scsi(%ld:%x): bsg rqst type: %s els type: %x - loop-id=%x " | ||
299 | "portid=%02x%02x%02x.\n", vha->host_no, sp->handle, type, | ||
300 | (bsg_job->request->rqst_data.h_ct.preamble_word2 >> 16), | ||
301 | fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area, | ||
302 | fcport->d_id.b.al_pa)); | ||
303 | |||
304 | rval = qla2x00_start_sp(sp); | ||
305 | if (rval != QLA_SUCCESS) { | ||
306 | kfree(sp->ctx); | ||
307 | mempool_free(sp, ha->srb_mempool); | ||
308 | rval = -EIO; | ||
309 | goto done_free_fcport; | ||
310 | } | ||
311 | return rval; | ||
312 | |||
313 | done_free_fcport: | ||
314 | kfree(fcport); | ||
315 | done_unmap_sg: | ||
316 | dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, | ||
317 | bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); | ||
318 | dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, | ||
319 | bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); | ||
320 | done: | ||
321 | return rval; | ||
322 | } | ||
323 | |||
324 | static int | ||
325 | qla2x00_process_loopback(struct fc_bsg_job *bsg_job) | ||
326 | { | ||
327 | struct Scsi_Host *host = bsg_job->shost; | ||
328 | scsi_qla_host_t *vha = shost_priv(host); | ||
329 | struct qla_hw_data *ha = vha->hw; | ||
330 | int rval; | ||
331 | uint8_t command_sent; | ||
332 | char *type; | ||
333 | struct msg_echo_lb elreq; | ||
334 | uint16_t response[MAILBOX_REGISTER_COUNT]; | ||
335 | uint8_t* fw_sts_ptr; | ||
336 | uint8_t *req_data = NULL; | ||
337 | dma_addr_t req_data_dma; | ||
338 | uint32_t req_data_len; | ||
339 | uint8_t *rsp_data = NULL; | ||
340 | dma_addr_t rsp_data_dma; | ||
341 | uint32_t rsp_data_len; | ||
342 | |||
343 | if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) || | ||
344 | test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) || | ||
345 | test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) | ||
346 | return -EBUSY; | ||
347 | |||
348 | if (!vha->flags.online) { | ||
349 | DEBUG2(qla_printk(KERN_WARNING, ha, "host not online\n")); | ||
350 | return -EIO; | ||
351 | } | ||
352 | |||
353 | elreq.req_sg_cnt = dma_map_sg(&ha->pdev->dev, | ||
354 | bsg_job->request_payload.sg_list, bsg_job->request_payload.sg_cnt, | ||
355 | DMA_TO_DEVICE); | ||
356 | |||
357 | if (!elreq.req_sg_cnt) | ||
358 | return -ENOMEM; | ||
359 | |||
360 | elreq.rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, | ||
361 | bsg_job->reply_payload.sg_list, bsg_job->reply_payload.sg_cnt, | ||
362 | DMA_FROM_DEVICE); | ||
363 | |||
364 | if (!elreq.rsp_sg_cnt) { | ||
365 | rval = -ENOMEM; | ||
366 | goto done_unmap_req_sg; | ||
367 | } | ||
368 | |||
369 | if ((elreq.req_sg_cnt != bsg_job->request_payload.sg_cnt) || | ||
370 | (elreq.rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) { | ||
371 | DEBUG2(printk(KERN_INFO | ||
372 | "dma mapping resulted in different sg counts " | ||
373 | "[request_sg_cnt: %x dma_request_sg_cnt: %x " | ||
374 | "reply_sg_cnt: %x dma_reply_sg_cnt: %x]\n", | ||
375 | bsg_job->request_payload.sg_cnt, elreq.req_sg_cnt, | ||
376 | bsg_job->reply_payload.sg_cnt, elreq.rsp_sg_cnt)); | ||
377 | rval = -EAGAIN; | ||
378 | goto done_unmap_sg; | ||
379 | } | ||
380 | req_data_len = rsp_data_len = bsg_job->request_payload.payload_len; | ||
381 | req_data = dma_alloc_coherent(&ha->pdev->dev, req_data_len, | ||
382 | &req_data_dma, GFP_KERNEL); | ||
383 | if (!req_data) { | ||
384 | DEBUG2(printk(KERN_ERR "%s: dma alloc for req_data " | ||
385 | "failed for host=%lu\n", __func__, vha->host_no)); | ||
386 | rval = -ENOMEM; | ||
387 | goto done_unmap_sg; | ||
388 | } | ||
389 | |||
390 | rsp_data = dma_alloc_coherent(&ha->pdev->dev, rsp_data_len, | ||
391 | &rsp_data_dma, GFP_KERNEL); | ||
392 | if (!rsp_data) { | ||
393 | DEBUG2(printk(KERN_ERR "%s: dma alloc for rsp_data " | ||
394 | "failed for host=%lu\n", __func__, vha->host_no)); | ||
395 | rval = -ENOMEM; | ||
396 | goto done_free_dma_req; | ||
397 | } | ||
398 | |||
399 | /* Copy the request buffer in req_data now */ | ||
400 | sg_copy_to_buffer(bsg_job->request_payload.sg_list, | ||
401 | bsg_job->request_payload.sg_cnt, req_data, req_data_len); | ||
402 | |||
403 | elreq.send_dma = req_data_dma; | ||
404 | elreq.rcv_dma = rsp_data_dma; | ||
405 | elreq.transfer_size = req_data_len; | ||
406 | |||
407 | elreq.options = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1]; | ||
408 | |||
409 | if (ha->current_topology != ISP_CFG_F) { | ||
410 | type = "FC_BSG_HST_VENDOR_LOOPBACK"; | ||
411 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
412 | "scsi(%ld) bsg rqst type: %s\n", | ||
413 | vha->host_no, type)); | ||
414 | |||
415 | command_sent = INT_DEF_LB_LOOPBACK_CMD; | ||
416 | rval = qla2x00_loopback_test(vha, &elreq, response); | ||
417 | if (IS_QLA81XX(ha)) { | ||
418 | if (response[0] == MBS_COMMAND_ERROR && | ||
419 | response[1] == MBS_LB_RESET) { | ||
420 | DEBUG2(printk(KERN_ERR "%s(%ld): ABORTing " | ||
421 | "ISP\n", __func__, vha->host_no)); | ||
422 | set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); | ||
423 | qla2xxx_wake_dpc(vha); | ||
424 | } | ||
425 | } | ||
426 | } else { | ||
427 | type = "FC_BSG_HST_VENDOR_ECHO_DIAG"; | ||
428 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
429 | "scsi(%ld) bsg rqst type: %s\n" ,vha->host_no, type)); | ||
430 | command_sent = INT_DEF_LB_ECHO_CMD; | ||
431 | rval = qla2x00_echo_test(vha, &elreq, response); | ||
432 | } | ||
433 | |||
434 | if (rval) { | ||
435 | DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor " | ||
436 | "request %s failed\n", vha->host_no, type)); | ||
437 | |||
438 | fw_sts_ptr = ((uint8_t *)bsg_job->req->sense) + | ||
439 | sizeof(struct fc_bsg_reply); | ||
440 | |||
441 | memcpy(fw_sts_ptr, response, sizeof(response)); | ||
442 | fw_sts_ptr += sizeof(response); | ||
443 | *fw_sts_ptr = command_sent; | ||
444 | rval = 0; | ||
445 | bsg_job->reply->reply_payload_rcv_len = 0; | ||
446 | bsg_job->reply->result = (DID_ERROR << 16); | ||
447 | } else { | ||
448 | DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor " | ||
449 | "request %s completed\n", vha->host_no, type)); | ||
450 | |||
451 | bsg_job->reply_len = sizeof(struct fc_bsg_reply) + | ||
452 | sizeof(response) + sizeof(uint8_t); | ||
453 | bsg_job->reply->reply_payload_rcv_len = | ||
454 | bsg_job->reply_payload.payload_len; | ||
455 | fw_sts_ptr = ((uint8_t *)bsg_job->req->sense) + | ||
456 | sizeof(struct fc_bsg_reply); | ||
457 | memcpy(fw_sts_ptr, response, sizeof(response)); | ||
458 | fw_sts_ptr += sizeof(response); | ||
459 | *fw_sts_ptr = command_sent; | ||
460 | bsg_job->reply->result = DID_OK; | ||
461 | sg_copy_from_buffer(bsg_job->reply_payload.sg_list, | ||
462 | bsg_job->reply_payload.sg_cnt, rsp_data, | ||
463 | rsp_data_len); | ||
464 | } | ||
465 | bsg_job->job_done(bsg_job); | ||
466 | |||
467 | dma_free_coherent(&ha->pdev->dev, rsp_data_len, | ||
468 | rsp_data, rsp_data_dma); | ||
469 | done_free_dma_req: | ||
470 | dma_free_coherent(&ha->pdev->dev, req_data_len, | ||
471 | req_data, req_data_dma); | ||
472 | done_unmap_sg: | ||
473 | dma_unmap_sg(&ha->pdev->dev, | ||
474 | bsg_job->reply_payload.sg_list, | ||
475 | bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); | ||
476 | done_unmap_req_sg: | ||
477 | dma_unmap_sg(&ha->pdev->dev, | ||
478 | bsg_job->request_payload.sg_list, | ||
479 | bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); | ||
480 | return rval; | ||
481 | } | ||
482 | |||
483 | static int | ||
484 | qla84xx_reset(struct fc_bsg_job *bsg_job) | ||
485 | { | ||
486 | struct Scsi_Host *host = bsg_job->shost; | ||
487 | scsi_qla_host_t *vha = shost_priv(host); | ||
488 | struct qla_hw_data *ha = vha->hw; | ||
489 | int rval = 0; | ||
490 | uint32_t flag; | ||
491 | |||
492 | if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) || | ||
493 | test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) || | ||
494 | test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) | ||
495 | return -EBUSY; | ||
496 | |||
497 | if (!IS_QLA84XX(ha)) { | ||
498 | DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld): Not 84xx, " | ||
499 | "exiting.\n", vha->host_no)); | ||
500 | return -EINVAL; | ||
501 | } | ||
502 | |||
503 | flag = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1]; | ||
504 | |||
505 | rval = qla84xx_reset_chip(vha, flag == A84_ISSUE_RESET_DIAG_FW); | ||
506 | |||
507 | if (rval) { | ||
508 | DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor " | ||
509 | "request 84xx reset failed\n", vha->host_no)); | ||
510 | rval = bsg_job->reply->reply_payload_rcv_len = 0; | ||
511 | bsg_job->reply->result = (DID_ERROR << 16); | ||
512 | |||
513 | } else { | ||
514 | DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor " | ||
515 | "request 84xx reset completed\n", vha->host_no)); | ||
516 | bsg_job->reply->result = DID_OK; | ||
517 | } | ||
518 | |||
519 | bsg_job->job_done(bsg_job); | ||
520 | return rval; | ||
521 | } | ||
522 | |||
523 | static int | ||
524 | qla84xx_updatefw(struct fc_bsg_job *bsg_job) | ||
525 | { | ||
526 | struct Scsi_Host *host = bsg_job->shost; | ||
527 | scsi_qla_host_t *vha = shost_priv(host); | ||
528 | struct qla_hw_data *ha = vha->hw; | ||
529 | struct verify_chip_entry_84xx *mn = NULL; | ||
530 | dma_addr_t mn_dma, fw_dma; | ||
531 | void *fw_buf = NULL; | ||
532 | int rval = 0; | ||
533 | uint32_t sg_cnt; | ||
534 | uint32_t data_len; | ||
535 | uint16_t options; | ||
536 | uint32_t flag; | ||
537 | uint32_t fw_ver; | ||
538 | |||
539 | if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) || | ||
540 | test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) || | ||
541 | test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) | ||
542 | return -EBUSY; | ||
543 | |||
544 | if (!IS_QLA84XX(ha)) { | ||
545 | DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld): Not 84xx, " | ||
546 | "exiting.\n", vha->host_no)); | ||
547 | return -EINVAL; | ||
548 | } | ||
549 | |||
550 | sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, | ||
551 | bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); | ||
552 | if (!sg_cnt) | ||
553 | return -ENOMEM; | ||
554 | |||
555 | if (sg_cnt != bsg_job->request_payload.sg_cnt) { | ||
556 | DEBUG2(printk(KERN_INFO | ||
557 | "dma mapping resulted in different sg counts " | ||
558 | "request_sg_cnt: %x dma_request_sg_cnt: %x ", | ||
559 | bsg_job->request_payload.sg_cnt, sg_cnt)); | ||
560 | rval = -EAGAIN; | ||
561 | goto done_unmap_sg; | ||
562 | } | ||
563 | |||
564 | data_len = bsg_job->request_payload.payload_len; | ||
565 | fw_buf = dma_alloc_coherent(&ha->pdev->dev, data_len, | ||
566 | &fw_dma, GFP_KERNEL); | ||
567 | if (!fw_buf) { | ||
568 | DEBUG2(printk(KERN_ERR "%s: dma alloc for fw_buf " | ||
569 | "failed for host=%lu\n", __func__, vha->host_no)); | ||
570 | rval = -ENOMEM; | ||
571 | goto done_unmap_sg; | ||
572 | } | ||
573 | |||
574 | sg_copy_to_buffer(bsg_job->request_payload.sg_list, | ||
575 | bsg_job->request_payload.sg_cnt, fw_buf, data_len); | ||
576 | |||
577 | mn = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &mn_dma); | ||
578 | if (!mn) { | ||
579 | DEBUG2(printk(KERN_ERR "%s: dma alloc for fw buffer " | ||
580 | "failed for host=%lu\n", __func__, vha->host_no)); | ||
581 | rval = -ENOMEM; | ||
582 | goto done_free_fw_buf; | ||
583 | } | ||
584 | |||
585 | flag = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1]; | ||
586 | fw_ver = le32_to_cpu(*((uint32_t *)((uint32_t *)fw_buf + 2))); | ||
587 | |||
588 | memset(mn, 0, sizeof(struct access_chip_84xx)); | ||
589 | mn->entry_type = VERIFY_CHIP_IOCB_TYPE; | ||
590 | mn->entry_count = 1; | ||
591 | |||
592 | options = VCO_FORCE_UPDATE | VCO_END_OF_DATA; | ||
593 | if (flag == A84_ISSUE_UPDATE_DIAGFW_CMD) | ||
594 | options |= VCO_DIAG_FW; | ||
595 | |||
596 | mn->options = cpu_to_le16(options); | ||
597 | mn->fw_ver = cpu_to_le32(fw_ver); | ||
598 | mn->fw_size = cpu_to_le32(data_len); | ||
599 | mn->fw_seq_size = cpu_to_le32(data_len); | ||
600 | mn->dseg_address[0] = cpu_to_le32(LSD(fw_dma)); | ||
601 | mn->dseg_address[1] = cpu_to_le32(MSD(fw_dma)); | ||
602 | mn->dseg_length = cpu_to_le32(data_len); | ||
603 | mn->data_seg_cnt = cpu_to_le16(1); | ||
604 | |||
605 | rval = qla2x00_issue_iocb_timeout(vha, mn, mn_dma, 0, 120); | ||
606 | |||
607 | if (rval) { | ||
608 | DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor " | ||
609 | "request 84xx updatefw failed\n", vha->host_no)); | ||
610 | |||
611 | rval = bsg_job->reply->reply_payload_rcv_len = 0; | ||
612 | bsg_job->reply->result = (DID_ERROR << 16); | ||
613 | |||
614 | } else { | ||
615 | DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor " | ||
616 | "request 84xx updatefw completed\n", vha->host_no)); | ||
617 | |||
618 | bsg_job->reply_len = sizeof(struct fc_bsg_reply); | ||
619 | bsg_job->reply->result = DID_OK; | ||
620 | } | ||
621 | |||
622 | bsg_job->job_done(bsg_job); | ||
623 | dma_pool_free(ha->s_dma_pool, mn, mn_dma); | ||
624 | |||
625 | done_free_fw_buf: | ||
626 | dma_free_coherent(&ha->pdev->dev, data_len, fw_buf, fw_dma); | ||
627 | |||
628 | done_unmap_sg: | ||
629 | dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, | ||
630 | bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); | ||
631 | |||
632 | return rval; | ||
633 | } | ||
634 | |||
635 | static int | ||
636 | qla84xx_mgmt_cmd(struct fc_bsg_job *bsg_job) | ||
637 | { | ||
638 | struct Scsi_Host *host = bsg_job->shost; | ||
639 | scsi_qla_host_t *vha = shost_priv(host); | ||
640 | struct qla_hw_data *ha = vha->hw; | ||
641 | struct access_chip_84xx *mn = NULL; | ||
642 | dma_addr_t mn_dma, mgmt_dma; | ||
643 | void *mgmt_b = NULL; | ||
644 | int rval = 0; | ||
645 | struct qla_bsg_a84_mgmt *ql84_mgmt; | ||
646 | uint32_t sg_cnt; | ||
647 | uint32_t data_len; | ||
648 | uint32_t dma_direction = DMA_NONE; | ||
649 | |||
650 | if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) || | ||
651 | test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) || | ||
652 | test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) | ||
653 | return -EBUSY; | ||
654 | |||
655 | if (!IS_QLA84XX(ha)) { | ||
656 | DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld): Not 84xx, " | ||
657 | "exiting.\n", vha->host_no)); | ||
658 | return -EINVAL; | ||
659 | } | ||
660 | |||
661 | ql84_mgmt = (struct qla_bsg_a84_mgmt *)((char *)bsg_job->request + | ||
662 | sizeof(struct fc_bsg_request)); | ||
663 | if (!ql84_mgmt) { | ||
664 | DEBUG2(printk("%s(%ld): mgmt header not provided, exiting.\n", | ||
665 | __func__, vha->host_no)); | ||
666 | return -EINVAL; | ||
667 | } | ||
668 | |||
669 | mn = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &mn_dma); | ||
670 | if (!mn) { | ||
671 | DEBUG2(printk(KERN_ERR "%s: dma alloc for fw buffer " | ||
672 | "failed for host=%lu\n", __func__, vha->host_no)); | ||
673 | return -ENOMEM; | ||
674 | } | ||
675 | |||
676 | memset(mn, 0, sizeof(struct access_chip_84xx)); | ||
677 | mn->entry_type = ACCESS_CHIP_IOCB_TYPE; | ||
678 | mn->entry_count = 1; | ||
679 | |||
680 | switch (ql84_mgmt->mgmt.cmd) { | ||
681 | case QLA84_MGMT_READ_MEM: | ||
682 | case QLA84_MGMT_GET_INFO: | ||
683 | sg_cnt = dma_map_sg(&ha->pdev->dev, | ||
684 | bsg_job->reply_payload.sg_list, | ||
685 | bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); | ||
686 | if (!sg_cnt) { | ||
687 | rval = -ENOMEM; | ||
688 | goto exit_mgmt; | ||
689 | } | ||
690 | |||
691 | dma_direction = DMA_FROM_DEVICE; | ||
692 | |||
693 | if (sg_cnt != bsg_job->reply_payload.sg_cnt) { | ||
694 | DEBUG2(printk(KERN_INFO | ||
695 | "dma mapping resulted in different sg counts " | ||
696 | "reply_sg_cnt: %x dma_reply_sg_cnt: %x\n", | ||
697 | bsg_job->reply_payload.sg_cnt, sg_cnt)); | ||
698 | rval = -EAGAIN; | ||
699 | goto done_unmap_sg; | ||
700 | } | ||
701 | |||
702 | data_len = bsg_job->reply_payload.payload_len; | ||
703 | |||
704 | mgmt_b = dma_alloc_coherent(&ha->pdev->dev, data_len, | ||
705 | &mgmt_dma, GFP_KERNEL); | ||
706 | if (!mgmt_b) { | ||
707 | DEBUG2(printk(KERN_ERR "%s: dma alloc for mgmt_b " | ||
708 | "failed for host=%lu\n", | ||
709 | __func__, vha->host_no)); | ||
710 | rval = -ENOMEM; | ||
711 | goto done_unmap_sg; | ||
712 | } | ||
713 | |||
714 | if (ql84_mgmt->mgmt.cmd == QLA84_MGMT_READ_MEM) { | ||
715 | mn->options = cpu_to_le16(ACO_DUMP_MEMORY); | ||
716 | mn->parameter1 = | ||
717 | cpu_to_le32( | ||
718 | ql84_mgmt->mgmt.mgmtp.u.mem.start_addr); | ||
719 | |||
720 | } else if (ql84_mgmt->mgmt.cmd == QLA84_MGMT_GET_INFO) { | ||
721 | mn->options = cpu_to_le16(ACO_REQUEST_INFO); | ||
722 | mn->parameter1 = | ||
723 | cpu_to_le32(ql84_mgmt->mgmt.mgmtp.u.info.type); | ||
724 | |||
725 | mn->parameter2 = | ||
726 | cpu_to_le32( | ||
727 | ql84_mgmt->mgmt.mgmtp.u.info.context); | ||
728 | } | ||
729 | break; | ||
730 | |||
731 | case QLA84_MGMT_WRITE_MEM: | ||
732 | sg_cnt = dma_map_sg(&ha->pdev->dev, | ||
733 | bsg_job->request_payload.sg_list, | ||
734 | bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); | ||
735 | |||
736 | if (!sg_cnt) { | ||
737 | rval = -ENOMEM; | ||
738 | goto exit_mgmt; | ||
739 | } | ||
740 | |||
741 | dma_direction = DMA_TO_DEVICE; | ||
742 | |||
743 | if (sg_cnt != bsg_job->request_payload.sg_cnt) { | ||
744 | DEBUG2(printk(KERN_INFO | ||
745 | "dma mapping resulted in different sg counts " | ||
746 | "request_sg_cnt: %x dma_request_sg_cnt: %x ", | ||
747 | bsg_job->request_payload.sg_cnt, sg_cnt)); | ||
748 | rval = -EAGAIN; | ||
749 | goto done_unmap_sg; | ||
750 | } | ||
751 | |||
752 | data_len = bsg_job->request_payload.payload_len; | ||
753 | mgmt_b = dma_alloc_coherent(&ha->pdev->dev, data_len, | ||
754 | &mgmt_dma, GFP_KERNEL); | ||
755 | if (!mgmt_b) { | ||
756 | DEBUG2(printk(KERN_ERR "%s: dma alloc for mgmt_b " | ||
757 | "failed for host=%lu\n", | ||
758 | __func__, vha->host_no)); | ||
759 | rval = -ENOMEM; | ||
760 | goto done_unmap_sg; | ||
761 | } | ||
762 | |||
763 | sg_copy_to_buffer(bsg_job->request_payload.sg_list, | ||
764 | bsg_job->request_payload.sg_cnt, mgmt_b, data_len); | ||
765 | |||
766 | mn->options = cpu_to_le16(ACO_LOAD_MEMORY); | ||
767 | mn->parameter1 = | ||
768 | cpu_to_le32(ql84_mgmt->mgmt.mgmtp.u.mem.start_addr); | ||
769 | break; | ||
770 | |||
771 | case QLA84_MGMT_CHNG_CONFIG: | ||
772 | mn->options = cpu_to_le16(ACO_CHANGE_CONFIG_PARAM); | ||
773 | mn->parameter1 = | ||
774 | cpu_to_le32(ql84_mgmt->mgmt.mgmtp.u.config.id); | ||
775 | |||
776 | mn->parameter2 = | ||
777 | cpu_to_le32(ql84_mgmt->mgmt.mgmtp.u.config.param0); | ||
778 | |||
779 | mn->parameter3 = | ||
780 | cpu_to_le32(ql84_mgmt->mgmt.mgmtp.u.config.param1); | ||
781 | break; | ||
782 | |||
783 | default: | ||
784 | rval = -EIO; | ||
785 | goto exit_mgmt; | ||
786 | } | ||
787 | |||
788 | if (ql84_mgmt->mgmt.cmd != QLA84_MGMT_CHNG_CONFIG) { | ||
789 | mn->total_byte_cnt = cpu_to_le32(ql84_mgmt->mgmt.len); | ||
790 | mn->dseg_count = cpu_to_le16(1); | ||
791 | mn->dseg_address[0] = cpu_to_le32(LSD(mgmt_dma)); | ||
792 | mn->dseg_address[1] = cpu_to_le32(MSD(mgmt_dma)); | ||
793 | mn->dseg_length = cpu_to_le32(ql84_mgmt->mgmt.len); | ||
794 | } | ||
795 | |||
796 | rval = qla2x00_issue_iocb(vha, mn, mn_dma, 0); | ||
797 | |||
798 | if (rval) { | ||
799 | DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor " | ||
800 | "request 84xx mgmt failed\n", vha->host_no)); | ||
801 | |||
802 | rval = bsg_job->reply->reply_payload_rcv_len = 0; | ||
803 | bsg_job->reply->result = (DID_ERROR << 16); | ||
804 | |||
805 | } else { | ||
806 | DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor " | ||
807 | "request 84xx mgmt completed\n", vha->host_no)); | ||
808 | |||
809 | bsg_job->reply_len = sizeof(struct fc_bsg_reply); | ||
810 | bsg_job->reply->result = DID_OK; | ||
811 | |||
812 | if ((ql84_mgmt->mgmt.cmd == QLA84_MGMT_READ_MEM) || | ||
813 | (ql84_mgmt->mgmt.cmd == QLA84_MGMT_GET_INFO)) { | ||
814 | bsg_job->reply->reply_payload_rcv_len = | ||
815 | bsg_job->reply_payload.payload_len; | ||
816 | |||
817 | sg_copy_from_buffer(bsg_job->reply_payload.sg_list, | ||
818 | bsg_job->reply_payload.sg_cnt, mgmt_b, data_len); | ||
819 | } | ||
820 | } | ||
821 | |||
822 | bsg_job->job_done(bsg_job); | ||
823 | dma_free_coherent(&ha->pdev->dev, data_len, mgmt_b, mgmt_dma); | ||
824 | |||
825 | done_unmap_sg: | ||
826 | if (dma_direction == DMA_TO_DEVICE) | ||
827 | dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, | ||
828 | bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); | ||
829 | else if (dma_direction == DMA_FROM_DEVICE) | ||
830 | dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, | ||
831 | bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); | ||
832 | |||
833 | exit_mgmt: | ||
834 | dma_pool_free(ha->s_dma_pool, mn, mn_dma); | ||
835 | |||
836 | return rval; | ||
837 | } | ||
838 | |||
839 | static int | ||
840 | qla24xx_iidma(struct fc_bsg_job *bsg_job) | ||
841 | { | ||
842 | struct Scsi_Host *host = bsg_job->shost; | ||
843 | scsi_qla_host_t *vha = shost_priv(host); | ||
844 | struct qla_hw_data *ha = vha->hw; | ||
845 | int rval = 0; | ||
846 | struct qla_port_param *port_param = NULL; | ||
847 | fc_port_t *fcport = NULL; | ||
848 | uint16_t mb[MAILBOX_REGISTER_COUNT]; | ||
849 | uint8_t *rsp_ptr = NULL; | ||
850 | |||
851 | bsg_job->reply->reply_payload_rcv_len = 0; | ||
852 | |||
853 | if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) || | ||
854 | test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) || | ||
855 | test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) | ||
856 | return -EBUSY; | ||
857 | |||
858 | if (!IS_IIDMA_CAPABLE(vha->hw)) { | ||
859 | DEBUG2(qla_printk(KERN_WARNING, ha, "%s(%lu): iiDMA not " | ||
860 | "supported\n", __func__, vha->host_no)); | ||
861 | return -EINVAL; | ||
862 | } | ||
863 | |||
864 | port_param = (struct qla_port_param *)((char *)bsg_job->request + | ||
865 | sizeof(struct fc_bsg_request)); | ||
866 | if (!port_param) { | ||
867 | DEBUG2(printk("%s(%ld): port_param header not provided, " | ||
868 | "exiting.\n", __func__, vha->host_no)); | ||
869 | return -EINVAL; | ||
870 | } | ||
871 | |||
872 | if (port_param->fc_scsi_addr.dest_type != EXT_DEF_TYPE_WWPN) { | ||
873 | DEBUG2(printk(KERN_ERR "%s(%ld): Invalid destination type\n", | ||
874 | __func__, vha->host_no)); | ||
875 | return -EINVAL; | ||
876 | } | ||
877 | |||
878 | list_for_each_entry(fcport, &vha->vp_fcports, list) { | ||
879 | if (fcport->port_type != FCT_TARGET) | ||
880 | continue; | ||
881 | |||
882 | if (memcmp(port_param->fc_scsi_addr.dest_addr.wwpn, | ||
883 | fcport->port_name, sizeof(fcport->port_name))) | ||
884 | continue; | ||
885 | break; | ||
886 | } | ||
887 | |||
888 | if (!fcport) { | ||
889 | DEBUG2(printk(KERN_ERR "%s(%ld): Failed to find port\n", | ||
890 | __func__, vha->host_no)); | ||
891 | return -EINVAL; | ||
892 | } | ||
893 | |||
894 | if (port_param->mode) | ||
895 | rval = qla2x00_set_idma_speed(vha, fcport->loop_id, | ||
896 | port_param->speed, mb); | ||
897 | else | ||
898 | rval = qla2x00_get_idma_speed(vha, fcport->loop_id, | ||
899 | &port_param->speed, mb); | ||
900 | |||
901 | if (rval) { | ||
902 | DEBUG16(printk(KERN_ERR "scsi(%ld): iIDMA cmd failed for " | ||
903 | "%02x%02x%02x%02x%02x%02x%02x%02x -- %04x %x %04x %04x.\n", | ||
904 | vha->host_no, fcport->port_name[0], | ||
905 | fcport->port_name[1], | ||
906 | fcport->port_name[2], fcport->port_name[3], | ||
907 | fcport->port_name[4], fcport->port_name[5], | ||
908 | fcport->port_name[6], fcport->port_name[7], rval, | ||
909 | fcport->fp_speed, mb[0], mb[1])); | ||
910 | rval = 0; | ||
911 | bsg_job->reply->result = (DID_ERROR << 16); | ||
912 | |||
913 | } else { | ||
914 | if (!port_param->mode) { | ||
915 | bsg_job->reply_len = sizeof(struct fc_bsg_reply) + | ||
916 | sizeof(struct qla_port_param); | ||
917 | |||
918 | rsp_ptr = ((uint8_t *)bsg_job->reply) + | ||
919 | sizeof(struct fc_bsg_reply); | ||
920 | |||
921 | memcpy(rsp_ptr, port_param, | ||
922 | sizeof(struct qla_port_param)); | ||
923 | } | ||
924 | |||
925 | bsg_job->reply->result = DID_OK; | ||
926 | } | ||
927 | |||
928 | bsg_job->job_done(bsg_job); | ||
929 | return rval; | ||
930 | } | ||
931 | |||
932 | static int | ||
933 | qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job) | ||
934 | { | ||
935 | switch (bsg_job->request->rqst_data.h_vendor.vendor_cmd[0]) { | ||
936 | case QL_VND_LOOPBACK: | ||
937 | return qla2x00_process_loopback(bsg_job); | ||
938 | |||
939 | case QL_VND_A84_RESET: | ||
940 | return qla84xx_reset(bsg_job); | ||
941 | |||
942 | case QL_VND_A84_UPDATE_FW: | ||
943 | return qla84xx_updatefw(bsg_job); | ||
944 | |||
945 | case QL_VND_A84_MGMT_CMD: | ||
946 | return qla84xx_mgmt_cmd(bsg_job); | ||
947 | |||
948 | case QL_VND_IIDMA: | ||
949 | return qla24xx_iidma(bsg_job); | ||
950 | |||
951 | default: | ||
952 | bsg_job->reply->result = (DID_ERROR << 16); | ||
953 | bsg_job->job_done(bsg_job); | ||
954 | return -ENOSYS; | ||
955 | } | ||
956 | } | ||
957 | |||
958 | int | ||
959 | qla24xx_bsg_request(struct fc_bsg_job *bsg_job) | ||
960 | { | ||
961 | int ret = -EINVAL; | ||
962 | |||
963 | switch (bsg_job->request->msgcode) { | ||
964 | case FC_BSG_RPT_ELS: | ||
965 | case FC_BSG_HST_ELS_NOLOGIN: | ||
966 | ret = qla2x00_process_els(bsg_job); | ||
967 | break; | ||
968 | case FC_BSG_HST_CT: | ||
969 | ret = qla2x00_process_ct(bsg_job); | ||
970 | break; | ||
971 | case FC_BSG_HST_VENDOR: | ||
972 | ret = qla2x00_process_vendor_specific(bsg_job); | ||
973 | break; | ||
974 | case FC_BSG_HST_ADD_RPORT: | ||
975 | case FC_BSG_HST_DEL_RPORT: | ||
976 | case FC_BSG_RPT_CT: | ||
977 | default: | ||
978 | DEBUG2(printk("qla2xxx: unsupported BSG request\n")); | ||
979 | break; | ||
980 | } | ||
981 | return ret; | ||
982 | } | ||
983 | |||
984 | int | ||
985 | qla24xx_bsg_timeout(struct fc_bsg_job *bsg_job) | ||
986 | { | ||
987 | scsi_qla_host_t *vha = shost_priv(bsg_job->shost); | ||
988 | struct qla_hw_data *ha = vha->hw; | ||
989 | srb_t *sp; | ||
990 | int cnt, que; | ||
991 | unsigned long flags; | ||
992 | struct req_que *req; | ||
993 | struct srb_bsg *sp_bsg; | ||
994 | |||
995 | /* find the bsg job from the active list of commands */ | ||
996 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
997 | for (que = 0; que < ha->max_req_queues; que++) { | ||
998 | req = ha->req_q_map[que]; | ||
999 | if (!req) | ||
1000 | continue; | ||
1001 | |||
1002 | for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++ ) { | ||
1003 | sp = req->outstanding_cmds[cnt]; | ||
1004 | |||
1005 | if (sp) { | ||
1006 | sp_bsg = (struct srb_bsg*)sp->ctx; | ||
1007 | |||
1008 | if (((sp_bsg->ctx.type == SRB_CT_CMD) || | ||
1009 | (sp_bsg->ctx.type == SRB_ELS_CMD_HST)) | ||
1010 | && (sp_bsg->bsg_job == bsg_job)) { | ||
1011 | if (ha->isp_ops->abort_command(sp)) { | ||
1012 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
1013 | "scsi(%ld): mbx abort_command failed\n", vha->host_no)); | ||
1014 | bsg_job->req->errors = | ||
1015 | bsg_job->reply->result = -EIO; | ||
1016 | } else { | ||
1017 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
1018 | "scsi(%ld): mbx abort_command success\n", vha->host_no)); | ||
1019 | bsg_job->req->errors = | ||
1020 | bsg_job->reply->result = 0; | ||
1021 | } | ||
1022 | goto done; | ||
1023 | } | ||
1024 | } | ||
1025 | } | ||
1026 | } | ||
1027 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
1028 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
1029 | "scsi(%ld) SRB not found to abort\n", vha->host_no)); | ||
1030 | bsg_job->req->errors = bsg_job->reply->result = -ENXIO; | ||
1031 | return 0; | ||
1032 | |||
1033 | done: | ||
1034 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
1035 | if (bsg_job->request->msgcode == FC_BSG_HST_CT) | ||
1036 | kfree(sp->fcport); | ||
1037 | kfree(sp->ctx); | ||
1038 | mempool_free(sp, ha->srb_mempool); | ||
1039 | return 0; | ||
1040 | } | ||
diff --git a/drivers/scsi/qla2xxx/qla_bsg.h b/drivers/scsi/qla2xxx/qla_bsg.h new file mode 100644 index 00000000000..76ed92dd2ef --- /dev/null +++ b/drivers/scsi/qla2xxx/qla_bsg.h | |||
@@ -0,0 +1,135 @@ | |||
1 | /* | ||
2 | * QLogic Fibre Channel HBA Driver | ||
3 | * Copyright (c) 2003-2008 QLogic Corporation | ||
4 | * | ||
5 | * See LICENSE.qla2xxx for copyright and licensing details. | ||
6 | */ | ||
7 | #ifndef __QLA_BSG_H | ||
8 | #define __QLA_BSG_H | ||
9 | |||
10 | /* BSG Vendor specific commands */ | ||
11 | #define QL_VND_LOOPBACK 0x01 | ||
12 | #define QL_VND_A84_RESET 0x02 | ||
13 | #define QL_VND_A84_UPDATE_FW 0x03 | ||
14 | #define QL_VND_A84_MGMT_CMD 0x04 | ||
15 | #define QL_VND_IIDMA 0x05 | ||
16 | #define QL_VND_FCP_PRIO_CFG_CMD 0x06 | ||
17 | |||
18 | /* BSG definations for interpreting CommandSent field */ | ||
19 | #define INT_DEF_LB_LOOPBACK_CMD 0 | ||
20 | #define INT_DEF_LB_ECHO_CMD 1 | ||
21 | |||
22 | /* BSG Vendor specific definations */ | ||
23 | #define A84_ISSUE_WRITE_TYPE_CMD 0 | ||
24 | #define A84_ISSUE_READ_TYPE_CMD 1 | ||
25 | #define A84_CLEANUP_CMD 2 | ||
26 | #define A84_ISSUE_RESET_OP_FW 3 | ||
27 | #define A84_ISSUE_RESET_DIAG_FW 4 | ||
28 | #define A84_ISSUE_UPDATE_OPFW_CMD 5 | ||
29 | #define A84_ISSUE_UPDATE_DIAGFW_CMD 6 | ||
30 | |||
31 | struct qla84_mgmt_param { | ||
32 | union { | ||
33 | struct { | ||
34 | uint32_t start_addr; | ||
35 | } mem; /* for QLA84_MGMT_READ/WRITE_MEM */ | ||
36 | struct { | ||
37 | uint32_t id; | ||
38 | #define QLA84_MGMT_CONFIG_ID_UIF 1 | ||
39 | #define QLA84_MGMT_CONFIG_ID_FCOE_COS 2 | ||
40 | #define QLA84_MGMT_CONFIG_ID_PAUSE 3 | ||
41 | #define QLA84_MGMT_CONFIG_ID_TIMEOUTS 4 | ||
42 | |||
43 | uint32_t param0; | ||
44 | uint32_t param1; | ||
45 | } config; /* for QLA84_MGMT_CHNG_CONFIG */ | ||
46 | |||
47 | struct { | ||
48 | uint32_t type; | ||
49 | #define QLA84_MGMT_INFO_CONFIG_LOG_DATA 1 /* Get Config Log Data */ | ||
50 | #define QLA84_MGMT_INFO_LOG_DATA 2 /* Get Log Data */ | ||
51 | #define QLA84_MGMT_INFO_PORT_STAT 3 /* Get Port Statistics */ | ||
52 | #define QLA84_MGMT_INFO_LIF_STAT 4 /* Get LIF Statistics */ | ||
53 | #define QLA84_MGMT_INFO_ASIC_STAT 5 /* Get ASIC Statistics */ | ||
54 | #define QLA84_MGMT_INFO_CONFIG_PARAMS 6 /* Get Config Parameters */ | ||
55 | #define QLA84_MGMT_INFO_PANIC_LOG 7 /* Get Panic Log */ | ||
56 | |||
57 | uint32_t context; | ||
58 | /* | ||
59 | * context definitions for QLA84_MGMT_INFO_CONFIG_LOG_DATA | ||
60 | */ | ||
61 | #define IC_LOG_DATA_LOG_ID_DEBUG_LOG 0 | ||
62 | #define IC_LOG_DATA_LOG_ID_LEARN_LOG 1 | ||
63 | #define IC_LOG_DATA_LOG_ID_FC_ACL_INGRESS_LOG 2 | ||
64 | #define IC_LOG_DATA_LOG_ID_FC_ACL_EGRESS_LOG 3 | ||
65 | #define IC_LOG_DATA_LOG_ID_ETHERNET_ACL_INGRESS_LOG 4 | ||
66 | #define IC_LOG_DATA_LOG_ID_ETHERNET_ACL_EGRESS_LOG 5 | ||
67 | #define IC_LOG_DATA_LOG_ID_MESSAGE_TRANSMIT_LOG 6 | ||
68 | #define IC_LOG_DATA_LOG_ID_MESSAGE_RECEIVE_LOG 7 | ||
69 | #define IC_LOG_DATA_LOG_ID_LINK_EVENT_LOG 8 | ||
70 | #define IC_LOG_DATA_LOG_ID_DCX_LOG 9 | ||
71 | |||
72 | /* | ||
73 | * context definitions for QLA84_MGMT_INFO_PORT_STAT | ||
74 | */ | ||
75 | #define IC_PORT_STATISTICS_PORT_NUMBER_ETHERNET_PORT0 0 | ||
76 | #define IC_PORT_STATISTICS_PORT_NUMBER_ETHERNET_PORT1 1 | ||
77 | #define IC_PORT_STATISTICS_PORT_NUMBER_NSL_PORT0 2 | ||
78 | #define IC_PORT_STATISTICS_PORT_NUMBER_NSL_PORT1 3 | ||
79 | #define IC_PORT_STATISTICS_PORT_NUMBER_FC_PORT0 4 | ||
80 | #define IC_PORT_STATISTICS_PORT_NUMBER_FC_PORT1 5 | ||
81 | |||
82 | |||
83 | /* | ||
84 | * context definitions for QLA84_MGMT_INFO_LIF_STAT | ||
85 | */ | ||
86 | #define IC_LIF_STATISTICS_LIF_NUMBER_ETHERNET_PORT0 0 | ||
87 | #define IC_LIF_STATISTICS_LIF_NUMBER_ETHERNET_PORT1 1 | ||
88 | #define IC_LIF_STATISTICS_LIF_NUMBER_FC_PORT0 2 | ||
89 | #define IC_LIF_STATISTICS_LIF_NUMBER_FC_PORT1 3 | ||
90 | #define IC_LIF_STATISTICS_LIF_NUMBER_CPU 6 | ||
91 | |||
92 | } info; /* for QLA84_MGMT_GET_INFO */ | ||
93 | } u; | ||
94 | }; | ||
95 | |||
96 | struct qla84_msg_mgmt { | ||
97 | uint16_t cmd; | ||
98 | #define QLA84_MGMT_READ_MEM 0x00 | ||
99 | #define QLA84_MGMT_WRITE_MEM 0x01 | ||
100 | #define QLA84_MGMT_CHNG_CONFIG 0x02 | ||
101 | #define QLA84_MGMT_GET_INFO 0x03 | ||
102 | uint16_t rsrvd; | ||
103 | struct qla84_mgmt_param mgmtp;/* parameters for cmd */ | ||
104 | uint32_t len; /* bytes in payload following this struct */ | ||
105 | uint8_t payload[0]; /* payload for cmd */ | ||
106 | }; | ||
107 | |||
108 | struct qla_bsg_a84_mgmt { | ||
109 | struct qla84_msg_mgmt mgmt; | ||
110 | } __attribute__ ((packed)); | ||
111 | |||
112 | struct qla_scsi_addr { | ||
113 | uint16_t bus; | ||
114 | uint16_t target; | ||
115 | } __attribute__ ((packed)); | ||
116 | |||
117 | struct qla_ext_dest_addr { | ||
118 | union { | ||
119 | uint8_t wwnn[8]; | ||
120 | uint8_t wwpn[8]; | ||
121 | uint8_t id[4]; | ||
122 | struct qla_scsi_addr scsi_addr; | ||
123 | } dest_addr; | ||
124 | uint16_t dest_type; | ||
125 | #define EXT_DEF_TYPE_WWPN 2 | ||
126 | uint16_t lun; | ||
127 | uint16_t padding[2]; | ||
128 | } __attribute__ ((packed)); | ||
129 | |||
130 | struct qla_port_param { | ||
131 | struct qla_ext_dest_addr fc_scsi_addr; | ||
132 | uint16_t mode; | ||
133 | uint16_t speed; | ||
134 | } __attribute__ ((packed)); | ||
135 | #endif | ||
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index afa95614aaf..608397bf7e0 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <scsi/scsi_transport_fc.h> | 33 | #include <scsi/scsi_transport_fc.h> |
34 | #include <scsi/scsi_bsg_fc.h> | 34 | #include <scsi/scsi_bsg_fc.h> |
35 | 35 | ||
36 | #include "qla_bsg.h" | ||
36 | #define QLA2XXX_DRIVER_NAME "qla2xxx" | 37 | #define QLA2XXX_DRIVER_NAME "qla2xxx" |
37 | 38 | ||
38 | /* | 39 | /* |
@@ -2797,128 +2798,4 @@ typedef struct scsi_qla_host { | |||
2797 | #include "qla_inline.h" | 2798 | #include "qla_inline.h" |
2798 | 2799 | ||
2799 | #define CMD_SP(Cmnd) ((Cmnd)->SCp.ptr) | 2800 | #define CMD_SP(Cmnd) ((Cmnd)->SCp.ptr) |
2800 | |||
2801 | /* | ||
2802 | * BSG Vendor specific commands | ||
2803 | */ | ||
2804 | |||
2805 | #define QL_VND_LOOPBACK 0x01 | ||
2806 | #define QLA84_RESET 0x02 | ||
2807 | #define QLA84_UPDATE_FW 0x03 | ||
2808 | #define QLA84_MGMT_CMD 0x04 | ||
2809 | |||
2810 | /* BSG definations for interpreting CommandSent field */ | ||
2811 | #define INT_DEF_LB_LOOPBACK_CMD 0 | ||
2812 | #define INT_DEF_LB_ECHO_CMD 1 | ||
2813 | |||
2814 | /* BSG Vendor specific definations */ | ||
2815 | typedef struct _A84_RESET { | ||
2816 | uint16_t Flags; | ||
2817 | uint16_t Reserved; | ||
2818 | #define A84_RESET_FLAG_ENABLE_DIAG_FW 1 | ||
2819 | } __attribute__((packed)) A84_RESET, *PA84_RESET; | ||
2820 | |||
2821 | #define A84_ISSUE_WRITE_TYPE_CMD 0 | ||
2822 | #define A84_ISSUE_READ_TYPE_CMD 1 | ||
2823 | #define A84_CLEANUP_CMD 2 | ||
2824 | #define A84_ISSUE_RESET_OP_FW 3 | ||
2825 | #define A84_ISSUE_RESET_DIAG_FW 4 | ||
2826 | #define A84_ISSUE_UPDATE_OPFW_CMD 5 | ||
2827 | #define A84_ISSUE_UPDATE_DIAGFW_CMD 6 | ||
2828 | |||
2829 | struct qla84_mgmt_param { | ||
2830 | union { | ||
2831 | struct { | ||
2832 | uint32_t start_addr; | ||
2833 | } mem; /* for QLA84_MGMT_READ/WRITE_MEM */ | ||
2834 | struct { | ||
2835 | uint32_t id; | ||
2836 | #define QLA84_MGMT_CONFIG_ID_UIF 1 | ||
2837 | #define QLA84_MGMT_CONFIG_ID_FCOE_COS 2 | ||
2838 | #define QLA84_MGMT_CONFIG_ID_PAUSE 3 | ||
2839 | #define QLA84_MGMT_CONFIG_ID_TIMEOUTS 4 | ||
2840 | |||
2841 | uint32_t param0; | ||
2842 | uint32_t param1; | ||
2843 | } config; /* for QLA84_MGMT_CHNG_CONFIG */ | ||
2844 | |||
2845 | struct { | ||
2846 | uint32_t type; | ||
2847 | #define QLA84_MGMT_INFO_CONFIG_LOG_DATA 1 /* Get Config Log Data */ | ||
2848 | #define QLA84_MGMT_INFO_LOG_DATA 2 /* Get Log Data */ | ||
2849 | #define QLA84_MGMT_INFO_PORT_STAT 3 /* Get Port Statistics */ | ||
2850 | #define QLA84_MGMT_INFO_LIF_STAT 4 /* Get LIF Statistics */ | ||
2851 | #define QLA84_MGMT_INFO_ASIC_STAT 5 /* Get ASIC Statistics */ | ||
2852 | #define QLA84_MGMT_INFO_CONFIG_PARAMS 6 /* Get Config Parameters */ | ||
2853 | #define QLA84_MGMT_INFO_PANIC_LOG 7 /* Get Panic Log */ | ||
2854 | |||
2855 | uint32_t context; | ||
2856 | /* | ||
2857 | * context definitions for QLA84_MGMT_INFO_CONFIG_LOG_DATA | ||
2858 | */ | ||
2859 | #define IC_LOG_DATA_LOG_ID_DEBUG_LOG 0 | ||
2860 | #define IC_LOG_DATA_LOG_ID_LEARN_LOG 1 | ||
2861 | #define IC_LOG_DATA_LOG_ID_FC_ACL_INGRESS_LOG 2 | ||
2862 | #define IC_LOG_DATA_LOG_ID_FC_ACL_EGRESS_LOG 3 | ||
2863 | #define IC_LOG_DATA_LOG_ID_ETHERNET_ACL_INGRESS_LOG 4 | ||
2864 | #define IC_LOG_DATA_LOG_ID_ETHERNET_ACL_EGRESS_LOG 5 | ||
2865 | #define IC_LOG_DATA_LOG_ID_MESSAGE_TRANSMIT_LOG 6 | ||
2866 | #define IC_LOG_DATA_LOG_ID_MESSAGE_RECEIVE_LOG 7 | ||
2867 | #define IC_LOG_DATA_LOG_ID_LINK_EVENT_LOG 8 | ||
2868 | #define IC_LOG_DATA_LOG_ID_DCX_LOG 9 | ||
2869 | |||
2870 | /* | ||
2871 | * context definitions for QLA84_MGMT_INFO_PORT_STAT | ||
2872 | */ | ||
2873 | #define IC_PORT_STATISTICS_PORT_NUMBER_ETHERNET_PORT0 0 | ||
2874 | #define IC_PORT_STATISTICS_PORT_NUMBER_ETHERNET_PORT1 1 | ||
2875 | #define IC_PORT_STATISTICS_PORT_NUMBER_NSL_PORT0 2 | ||
2876 | #define IC_PORT_STATISTICS_PORT_NUMBER_NSL_PORT1 3 | ||
2877 | #define IC_PORT_STATISTICS_PORT_NUMBER_FC_PORT0 4 | ||
2878 | #define IC_PORT_STATISTICS_PORT_NUMBER_FC_PORT1 5 | ||
2879 | |||
2880 | |||
2881 | /* | ||
2882 | * context definitions for QLA84_MGMT_INFO_LIF_STAT | ||
2883 | */ | ||
2884 | #define IC_LIF_STATISTICS_LIF_NUMBER_ETHERNET_PORT0 0 | ||
2885 | #define IC_LIF_STATISTICS_LIF_NUMBER_ETHERNET_PORT1 1 | ||
2886 | #define IC_LIF_STATISTICS_LIF_NUMBER_FC_PORT0 2 | ||
2887 | #define IC_LIF_STATISTICS_LIF_NUMBER_FC_PORT1 3 | ||
2888 | #define IC_LIF_STATISTICS_LIF_NUMBER_CPU 6 | ||
2889 | |||
2890 | } info; /* for QLA84_MGMT_GET_INFO */ | ||
2891 | } u; | ||
2892 | }; | ||
2893 | |||
2894 | struct qla84_msg_mgmt { | ||
2895 | uint16_t cmd; | ||
2896 | #define QLA84_MGMT_READ_MEM 0x00 | ||
2897 | #define QLA84_MGMT_WRITE_MEM 0x01 | ||
2898 | #define QLA84_MGMT_CHNG_CONFIG 0x02 | ||
2899 | #define QLA84_MGMT_GET_INFO 0x03 | ||
2900 | uint16_t rsrvd; | ||
2901 | struct qla84_mgmt_param mgmtp;/* parameters for cmd */ | ||
2902 | uint32_t len; /* bytes in payload following this struct */ | ||
2903 | uint8_t payload[0]; /* payload for cmd */ | ||
2904 | }; | ||
2905 | |||
2906 | struct msg_update_fw { | ||
2907 | /* | ||
2908 | * diag_fw = 0 operational fw | ||
2909 | * otherwise diagnostic fw | ||
2910 | * offset, len, fw_len are present to overcome the current limitation | ||
2911 | * of 128Kb xfer size. The fw is sent in smaller chunks. Each chunk | ||
2912 | * specifies the byte "offset" where it fits in the fw buffer. The | ||
2913 | * number of bytes in each chunk is specified in "len". "fw_len" | ||
2914 | * is the total size of fw. The first chunk should start at offset = 0. | ||
2915 | * When offset+len == fw_len, the fw is written to the HBA. | ||
2916 | */ | ||
2917 | uint32_t diag_fw; | ||
2918 | uint32_t offset;/* start offset */ | ||
2919 | uint32_t len; /* num bytes in cur xfer */ | ||
2920 | uint32_t fw_len; /* size of fw in bytes */ | ||
2921 | uint8_t fw_bytes[0]; | ||
2922 | }; | ||
2923 | |||
2924 | #endif | 2801 | #endif |
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 3a89bc514e2..c1f1736dcda 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h | |||
@@ -459,4 +459,12 @@ extern void qla25xx_wrt_req_reg(struct qla_hw_data *, uint16_t, uint16_t); | |||
459 | extern void qla25xx_wrt_rsp_reg(struct qla_hw_data *, uint16_t, uint16_t); | 459 | extern void qla25xx_wrt_rsp_reg(struct qla_hw_data *, uint16_t, uint16_t); |
460 | extern void qla24xx_wrt_rsp_reg(struct qla_hw_data *, uint16_t, uint16_t); | 460 | extern void qla24xx_wrt_rsp_reg(struct qla_hw_data *, uint16_t, uint16_t); |
461 | 461 | ||
462 | /* BSG related functions */ | ||
463 | extern int qla24xx_bsg_request(struct fc_bsg_job *); | ||
464 | extern int qla24xx_bsg_timeout(struct fc_bsg_job *); | ||
465 | extern int qla84xx_reset_chip(scsi_qla_host_t *, uint16_t); | ||
466 | extern int qla2x00_issue_iocb_timeout(scsi_qla_host_t *, void *, | ||
467 | dma_addr_t, size_t, uint32_t); | ||
468 | extern int qla2x00_get_idma_speed(scsi_qla_host_t *, uint16_t, | ||
469 | uint16_t *, uint16_t *); | ||
462 | #endif /* _QLA_GBL_H */ | 470 | #endif /* _QLA_GBL_H */ |
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 42eb7ffd594..7f3bc45d2e2 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c | |||
@@ -711,7 +711,7 @@ qla2x00_verify_checksum(scsi_qla_host_t *vha, uint32_t risc_addr) | |||
711 | * Context: | 711 | * Context: |
712 | * Kernel context. | 712 | * Kernel context. |
713 | */ | 713 | */ |
714 | static int | 714 | int |
715 | qla2x00_issue_iocb_timeout(scsi_qla_host_t *vha, void *buffer, | 715 | qla2x00_issue_iocb_timeout(scsi_qla_host_t *vha, void *buffer, |
716 | dma_addr_t phys_addr, size_t size, uint32_t tov) | 716 | dma_addr_t phys_addr, size_t size, uint32_t tov) |
717 | { | 717 | { |
@@ -2740,6 +2740,48 @@ qla2x00_read_sfp(scsi_qla_host_t *vha, dma_addr_t sfp_dma, uint16_t addr, | |||
2740 | } | 2740 | } |
2741 | 2741 | ||
2742 | int | 2742 | int |
2743 | qla2x00_get_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id, | ||
2744 | uint16_t *port_speed, uint16_t *mb) | ||
2745 | { | ||
2746 | int rval; | ||
2747 | mbx_cmd_t mc; | ||
2748 | mbx_cmd_t *mcp = &mc; | ||
2749 | |||
2750 | if (!IS_IIDMA_CAPABLE(vha->hw)) | ||
2751 | return QLA_FUNCTION_FAILED; | ||
2752 | |||
2753 | DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no)); | ||
2754 | |||
2755 | mcp->mb[0] = MBC_PORT_PARAMS; | ||
2756 | mcp->mb[1] = loop_id; | ||
2757 | mcp->mb[2] = mcp->mb[3] = 0; | ||
2758 | mcp->mb[9] = vha->vp_idx; | ||
2759 | mcp->out_mb = MBX_9|MBX_3|MBX_2|MBX_1|MBX_0; | ||
2760 | mcp->in_mb = MBX_3|MBX_1|MBX_0; | ||
2761 | mcp->tov = MBX_TOV_SECONDS; | ||
2762 | mcp->flags = 0; | ||
2763 | rval = qla2x00_mailbox_command(vha, mcp); | ||
2764 | |||
2765 | /* Return mailbox statuses. */ | ||
2766 | if (mb != NULL) { | ||
2767 | mb[0] = mcp->mb[0]; | ||
2768 | mb[1] = mcp->mb[1]; | ||
2769 | mb[3] = mcp->mb[3]; | ||
2770 | } | ||
2771 | |||
2772 | if (rval != QLA_SUCCESS) { | ||
2773 | DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__, | ||
2774 | vha->host_no, rval)); | ||
2775 | } else { | ||
2776 | DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no)); | ||
2777 | if (port_speed) | ||
2778 | *port_speed = mcp->mb[3]; | ||
2779 | } | ||
2780 | |||
2781 | return rval; | ||
2782 | } | ||
2783 | |||
2784 | int | ||
2743 | qla2x00_set_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id, | 2785 | qla2x00_set_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id, |
2744 | uint16_t port_speed, uint16_t *mb) | 2786 | uint16_t port_speed, uint16_t *mb) |
2745 | { | 2787 | { |
@@ -3764,8 +3806,7 @@ qla2x00_echo_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq, uint16_t *mres | |||
3764 | return rval; | 3806 | return rval; |
3765 | } | 3807 | } |
3766 | int | 3808 | int |
3767 | qla84xx_reset_chip(scsi_qla_host_t *ha, uint16_t enable_diagnostic, | 3809 | qla84xx_reset_chip(scsi_qla_host_t *ha, uint16_t enable_diagnostic) |
3768 | uint16_t *cmd_status) | ||
3769 | { | 3810 | { |
3770 | int rval; | 3811 | int rval; |
3771 | mbx_cmd_t mc; | 3812 | mbx_cmd_t mc; |
@@ -3782,8 +3823,6 @@ qla84xx_reset_chip(scsi_qla_host_t *ha, uint16_t enable_diagnostic, | |||
3782 | mcp->flags = MBX_DMA_OUT|MBX_DMA_IN|IOCTL_CMD; | 3823 | mcp->flags = MBX_DMA_OUT|MBX_DMA_IN|IOCTL_CMD; |
3783 | rval = qla2x00_mailbox_command(ha, mcp); | 3824 | rval = qla2x00_mailbox_command(ha, mcp); |
3784 | 3825 | ||
3785 | /* Return mailbox statuses. */ | ||
3786 | *cmd_status = mcp->mb[0]; | ||
3787 | if (rval != QLA_SUCCESS) | 3826 | if (rval != QLA_SUCCESS) |
3788 | DEBUG16(printk("%s(%ld): failed=%x.\n", __func__, ha->host_no, | 3827 | DEBUG16(printk("%s(%ld): failed=%x.\n", __func__, ha->host_no, |
3789 | rval)); | 3828 | rval)); |