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