aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/qla2xxx/qla_attr.c
diff options
context:
space:
mode:
authorGiridhar Malavali <giridhar.malavali@qlogic.com>2010-01-12 16:02:47 -0500
committerJames Bottomley <James.Bottomley@suse.de>2010-01-18 17:51:05 -0500
commit9a069e196767d7b87184fd8d8211d22bb5b9c0b8 (patch)
tree44bc0f206793a2e9bcf280ea168e468bd62c15bb /drivers/scsi/qla2xxx/qla_attr.c
parent90a86fc05ffefe48581c88106d0b9cc37f6e060c (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.c746
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
13static int qla24xx_vport_disable(struct fc_vport *, bool); 13static int qla24xx_vport_disable(struct fc_vport *, bool);
14 14static int qla84xx_reset(scsi_qla_host_t *, struct msg_echo_lb *, struct fc_bsg_job *);
15int qla84xx_reset_chip(scsi_qla_host_t *, uint16_t, uint16_t *);
16static int qla84xx_mgmt_cmd(scsi_qla_host_t *, struct msg_echo_lb *, struct fc_bsg_job *);
15/* SYSFS attributes --------------------------------------------------------- */ 17/* SYSFS attributes --------------------------------------------------------- */
16 18
17static ssize_t 19static ssize_t
@@ -1168,6 +1170,28 @@ qla2x00_total_isp_aborts_show(struct device *dev,
1168} 1170}
1169 1171
1170static ssize_t 1172static ssize_t
1173qla24xx_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
1194static ssize_t
1171qla2x00_mpi_version_show(struct device *dev, struct device_attribute *attr, 1195qla2x00_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);
1282static DEVICE_ATTR(optrom_fw_version, S_IRUGO, qla2x00_optrom_fw_version_show, 1306static DEVICE_ATTR(optrom_fw_version, S_IRUGO, qla2x00_optrom_fw_version_show,
1283 NULL); 1307 NULL);
1308static DEVICE_ATTR(84xx_fw_version, S_IRUGO, qla24xx_84xx_fw_version_show,
1309 NULL);
1284static DEVICE_ATTR(total_isp_aborts, S_IRUGO, qla2x00_total_isp_aborts_show, 1310static DEVICE_ATTR(total_isp_aborts, S_IRUGO, qla2x00_total_isp_aborts_show,
1285 NULL); 1311 NULL);
1286static DEVICE_ATTR(mpi_version, S_IRUGO, qla2x00_mpi_version_show, NULL); 1312static 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 */
1826inline srb_t *
1827qla2x00_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;
1845done:
1846 return sp;
1847}
1848
1849static int
1850qla2x00_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
1997done_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
2004done_free_fcport:
2005 if (bsg_job->request->msgcode == FC_BSG_HST_ELS_NOLOGIN)
2006 kfree(fcport);
2007done:
2008 return rval;
2009}
2010
2011static int
2012qla2x00_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
2126done_free_fcport:
2127 kfree(fcport);
2128done_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);
2133done:
2134 return rval;
2135}
2136
2137static int
2138qla2x00_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
2307done_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
2319done:
2320 return rval;
2321}
2322
2323static int
2324qla24xx_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
2349static int
2350qla24xx_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
1798struct fc_function_template qla2xxx_transport_functions = { 2416struct 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
1843struct fc_function_template qla2xxx_transport_vport_functions = { 2463struct 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
1883void 2505void
@@ -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}
2531static int
2532qla84xx_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
2548static int
2549qla84xx_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
2649exit_mgmt0:
2650 dma_pool_free(ha->hw->s_dma_pool, mn, mn_dma);
2651 return ret;
2652}