1*e3976af5SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2a355943cSVikas Chaudhary /*
3a355943cSVikas Chaudhary * QLogic iSCSI HBA Driver
44a4f51e9SVikas Chaudhary * Copyright (c) 2011-2013 QLogic Corporation
5a355943cSVikas Chaudhary */
6a355943cSVikas Chaudhary
7a355943cSVikas Chaudhary #include "ql4_def.h"
8a355943cSVikas Chaudhary #include "ql4_glbl.h"
9a355943cSVikas Chaudhary #include "ql4_bsg.h"
10a355943cSVikas Chaudhary
11a355943cSVikas Chaudhary static int
qla4xxx_read_flash(struct bsg_job * bsg_job)12a355943cSVikas Chaudhary qla4xxx_read_flash(struct bsg_job *bsg_job)
13a355943cSVikas Chaudhary {
14a355943cSVikas Chaudhary struct Scsi_Host *host = iscsi_job_to_shost(bsg_job);
15a355943cSVikas Chaudhary struct scsi_qla_host *ha = to_qla_host(host);
16a355943cSVikas Chaudhary struct iscsi_bsg_reply *bsg_reply = bsg_job->reply;
17a355943cSVikas Chaudhary struct iscsi_bsg_request *bsg_req = bsg_job->request;
18a355943cSVikas Chaudhary uint32_t offset = 0;
19a355943cSVikas Chaudhary uint32_t length = 0;
20a355943cSVikas Chaudhary dma_addr_t flash_dma;
21a355943cSVikas Chaudhary uint8_t *flash = NULL;
22ef7830bbSHarish Zunjarrao int rval = -EINVAL;
23a355943cSVikas Chaudhary
24a355943cSVikas Chaudhary bsg_reply->reply_payload_rcv_len = 0;
25a355943cSVikas Chaudhary
26a355943cSVikas Chaudhary if (unlikely(pci_channel_offline(ha->pdev)))
27ef7830bbSHarish Zunjarrao goto leave;
28a355943cSVikas Chaudhary
29ef7830bbSHarish Zunjarrao if (ql4xxx_reset_active(ha)) {
30ef7830bbSHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__);
31ef7830bbSHarish Zunjarrao rval = -EBUSY;
32ef7830bbSHarish Zunjarrao goto leave;
33a355943cSVikas Chaudhary }
34a355943cSVikas Chaudhary
35ef7830bbSHarish Zunjarrao if (ha->flash_state != QLFLASH_WAITING) {
36ef7830bbSHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: another flash operation "
37ef7830bbSHarish Zunjarrao "active\n", __func__);
38ef7830bbSHarish Zunjarrao rval = -EBUSY;
39ef7830bbSHarish Zunjarrao goto leave;
40ef7830bbSHarish Zunjarrao }
41ef7830bbSHarish Zunjarrao
42ef7830bbSHarish Zunjarrao ha->flash_state = QLFLASH_READING;
43a355943cSVikas Chaudhary offset = bsg_req->rqst_data.h_vendor.vendor_cmd[1];
44a355943cSVikas Chaudhary length = bsg_job->reply_payload.payload_len;
45a355943cSVikas Chaudhary
46a355943cSVikas Chaudhary flash = dma_alloc_coherent(&ha->pdev->dev, length, &flash_dma,
47a355943cSVikas Chaudhary GFP_KERNEL);
48a355943cSVikas Chaudhary if (!flash) {
49a355943cSVikas Chaudhary ql4_printk(KERN_ERR, ha, "%s: dma alloc failed for flash "
50a355943cSVikas Chaudhary "data\n", __func__);
51a355943cSVikas Chaudhary rval = -ENOMEM;
52ef7830bbSHarish Zunjarrao goto leave;
53a355943cSVikas Chaudhary }
54a355943cSVikas Chaudhary
55ef7830bbSHarish Zunjarrao rval = qla4xxx_get_flash(ha, flash_dma, offset, length);
56ef7830bbSHarish Zunjarrao if (rval) {
57ef7830bbSHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: get flash failed\n", __func__);
58ef7830bbSHarish Zunjarrao bsg_reply->result = DID_ERROR << 16;
59ef7830bbSHarish Zunjarrao rval = -EIO;
60ef7830bbSHarish Zunjarrao } else {
61ef7830bbSHarish Zunjarrao bsg_reply->reply_payload_rcv_len =
62a355943cSVikas Chaudhary sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
63a355943cSVikas Chaudhary bsg_job->reply_payload.sg_cnt,
64a355943cSVikas Chaudhary flash, length);
65ef7830bbSHarish Zunjarrao bsg_reply->result = DID_OK << 16;
66a355943cSVikas Chaudhary }
67a355943cSVikas Chaudhary
68a355943cSVikas Chaudhary bsg_job_done(bsg_job, bsg_reply->result,
69a355943cSVikas Chaudhary bsg_reply->reply_payload_rcv_len);
70ef7830bbSHarish Zunjarrao dma_free_coherent(&ha->pdev->dev, length, flash, flash_dma);
71ef7830bbSHarish Zunjarrao leave:
72ef7830bbSHarish Zunjarrao ha->flash_state = QLFLASH_WAITING;
73a355943cSVikas Chaudhary return rval;
74a355943cSVikas Chaudhary }
75a355943cSVikas Chaudhary
76a355943cSVikas Chaudhary static int
qla4xxx_update_flash(struct bsg_job * bsg_job)77a355943cSVikas Chaudhary qla4xxx_update_flash(struct bsg_job *bsg_job)
78a355943cSVikas Chaudhary {
79a355943cSVikas Chaudhary struct Scsi_Host *host = iscsi_job_to_shost(bsg_job);
80a355943cSVikas Chaudhary struct scsi_qla_host *ha = to_qla_host(host);
81a355943cSVikas Chaudhary struct iscsi_bsg_reply *bsg_reply = bsg_job->reply;
82a355943cSVikas Chaudhary struct iscsi_bsg_request *bsg_req = bsg_job->request;
83a355943cSVikas Chaudhary uint32_t length = 0;
84a355943cSVikas Chaudhary uint32_t offset = 0;
85a355943cSVikas Chaudhary uint32_t options = 0;
86a355943cSVikas Chaudhary dma_addr_t flash_dma;
87a355943cSVikas Chaudhary uint8_t *flash = NULL;
88ef7830bbSHarish Zunjarrao int rval = -EINVAL;
89a355943cSVikas Chaudhary
90a355943cSVikas Chaudhary bsg_reply->reply_payload_rcv_len = 0;
91a355943cSVikas Chaudhary
92a355943cSVikas Chaudhary if (unlikely(pci_channel_offline(ha->pdev)))
93ef7830bbSHarish Zunjarrao goto leave;
94a355943cSVikas Chaudhary
95ef7830bbSHarish Zunjarrao if (ql4xxx_reset_active(ha)) {
96ef7830bbSHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__);
97ef7830bbSHarish Zunjarrao rval = -EBUSY;
98ef7830bbSHarish Zunjarrao goto leave;
99a355943cSVikas Chaudhary }
100a355943cSVikas Chaudhary
101ef7830bbSHarish Zunjarrao if (ha->flash_state != QLFLASH_WAITING) {
102ef7830bbSHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: another flash operation "
103ef7830bbSHarish Zunjarrao "active\n", __func__);
104ef7830bbSHarish Zunjarrao rval = -EBUSY;
105ef7830bbSHarish Zunjarrao goto leave;
106ef7830bbSHarish Zunjarrao }
107ef7830bbSHarish Zunjarrao
108ef7830bbSHarish Zunjarrao ha->flash_state = QLFLASH_WRITING;
109a355943cSVikas Chaudhary length = bsg_job->request_payload.payload_len;
110a355943cSVikas Chaudhary offset = bsg_req->rqst_data.h_vendor.vendor_cmd[1];
111a355943cSVikas Chaudhary options = bsg_req->rqst_data.h_vendor.vendor_cmd[2];
112a355943cSVikas Chaudhary
113a355943cSVikas Chaudhary flash = dma_alloc_coherent(&ha->pdev->dev, length, &flash_dma,
114a355943cSVikas Chaudhary GFP_KERNEL);
115a355943cSVikas Chaudhary if (!flash) {
116a355943cSVikas Chaudhary ql4_printk(KERN_ERR, ha, "%s: dma alloc failed for flash "
117a355943cSVikas Chaudhary "data\n", __func__);
118a355943cSVikas Chaudhary rval = -ENOMEM;
119ef7830bbSHarish Zunjarrao goto leave;
120a355943cSVikas Chaudhary }
121a355943cSVikas Chaudhary
122a355943cSVikas Chaudhary sg_copy_to_buffer(bsg_job->request_payload.sg_list,
123a355943cSVikas Chaudhary bsg_job->request_payload.sg_cnt, flash, length);
124a355943cSVikas Chaudhary
125ef7830bbSHarish Zunjarrao rval = qla4xxx_set_flash(ha, flash_dma, offset, length, options);
126ef7830bbSHarish Zunjarrao if (rval) {
127ef7830bbSHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: set flash failed\n", __func__);
128ef7830bbSHarish Zunjarrao bsg_reply->result = DID_ERROR << 16;
129ef7830bbSHarish Zunjarrao rval = -EIO;
130ef7830bbSHarish Zunjarrao } else
131ef7830bbSHarish Zunjarrao bsg_reply->result = DID_OK << 16;
132a355943cSVikas Chaudhary
133a355943cSVikas Chaudhary bsg_job_done(bsg_job, bsg_reply->result,
134a355943cSVikas Chaudhary bsg_reply->reply_payload_rcv_len);
135ef7830bbSHarish Zunjarrao dma_free_coherent(&ha->pdev->dev, length, flash, flash_dma);
136ef7830bbSHarish Zunjarrao leave:
137ef7830bbSHarish Zunjarrao ha->flash_state = QLFLASH_WAITING;
138a355943cSVikas Chaudhary return rval;
139a355943cSVikas Chaudhary }
140a355943cSVikas Chaudhary
1418b0402e1SHarish Zunjarrao static int
qla4xxx_get_acb_state(struct bsg_job * bsg_job)1428b0402e1SHarish Zunjarrao qla4xxx_get_acb_state(struct bsg_job *bsg_job)
1438b0402e1SHarish Zunjarrao {
1448b0402e1SHarish Zunjarrao struct Scsi_Host *host = iscsi_job_to_shost(bsg_job);
1458b0402e1SHarish Zunjarrao struct scsi_qla_host *ha = to_qla_host(host);
1468b0402e1SHarish Zunjarrao struct iscsi_bsg_request *bsg_req = bsg_job->request;
1478b0402e1SHarish Zunjarrao struct iscsi_bsg_reply *bsg_reply = bsg_job->reply;
1488b0402e1SHarish Zunjarrao uint32_t status[MBOX_REG_COUNT];
1498b0402e1SHarish Zunjarrao uint32_t acb_idx;
1508b0402e1SHarish Zunjarrao uint32_t ip_idx;
1518b0402e1SHarish Zunjarrao int rval = -EINVAL;
1528b0402e1SHarish Zunjarrao
1538b0402e1SHarish Zunjarrao bsg_reply->reply_payload_rcv_len = 0;
1548b0402e1SHarish Zunjarrao
1558b0402e1SHarish Zunjarrao if (unlikely(pci_channel_offline(ha->pdev)))
1568b0402e1SHarish Zunjarrao goto leave;
1578b0402e1SHarish Zunjarrao
1588b0402e1SHarish Zunjarrao /* Only 4022 and above adapters are supported */
1598b0402e1SHarish Zunjarrao if (is_qla4010(ha))
1608b0402e1SHarish Zunjarrao goto leave;
1618b0402e1SHarish Zunjarrao
1628b0402e1SHarish Zunjarrao if (ql4xxx_reset_active(ha)) {
1638b0402e1SHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__);
1648b0402e1SHarish Zunjarrao rval = -EBUSY;
1658b0402e1SHarish Zunjarrao goto leave;
1668b0402e1SHarish Zunjarrao }
1678b0402e1SHarish Zunjarrao
1688b0402e1SHarish Zunjarrao if (bsg_job->reply_payload.payload_len < sizeof(status)) {
1698b0402e1SHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: invalid payload len %d\n",
1708b0402e1SHarish Zunjarrao __func__, bsg_job->reply_payload.payload_len);
1718b0402e1SHarish Zunjarrao rval = -EINVAL;
1728b0402e1SHarish Zunjarrao goto leave;
1738b0402e1SHarish Zunjarrao }
1748b0402e1SHarish Zunjarrao
1758b0402e1SHarish Zunjarrao acb_idx = bsg_req->rqst_data.h_vendor.vendor_cmd[1];
1768b0402e1SHarish Zunjarrao ip_idx = bsg_req->rqst_data.h_vendor.vendor_cmd[2];
1778b0402e1SHarish Zunjarrao
1788b0402e1SHarish Zunjarrao rval = qla4xxx_get_ip_state(ha, acb_idx, ip_idx, status);
1798b0402e1SHarish Zunjarrao if (rval) {
1808b0402e1SHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: get ip state failed\n",
1818b0402e1SHarish Zunjarrao __func__);
1828b0402e1SHarish Zunjarrao bsg_reply->result = DID_ERROR << 16;
1838b0402e1SHarish Zunjarrao rval = -EIO;
1848b0402e1SHarish Zunjarrao } else {
1858b0402e1SHarish Zunjarrao bsg_reply->reply_payload_rcv_len =
1868b0402e1SHarish Zunjarrao sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
1878b0402e1SHarish Zunjarrao bsg_job->reply_payload.sg_cnt,
1888b0402e1SHarish Zunjarrao status, sizeof(status));
1898b0402e1SHarish Zunjarrao bsg_reply->result = DID_OK << 16;
1908b0402e1SHarish Zunjarrao }
1918b0402e1SHarish Zunjarrao
1928b0402e1SHarish Zunjarrao bsg_job_done(bsg_job, bsg_reply->result,
1938b0402e1SHarish Zunjarrao bsg_reply->reply_payload_rcv_len);
1948b0402e1SHarish Zunjarrao leave:
1958b0402e1SHarish Zunjarrao return rval;
1968b0402e1SHarish Zunjarrao }
1978b0402e1SHarish Zunjarrao
1987c07d139SHarish Zunjarrao static int
qla4xxx_read_nvram(struct bsg_job * bsg_job)1997c07d139SHarish Zunjarrao qla4xxx_read_nvram(struct bsg_job *bsg_job)
2007c07d139SHarish Zunjarrao {
2017c07d139SHarish Zunjarrao struct Scsi_Host *host = iscsi_job_to_shost(bsg_job);
2027c07d139SHarish Zunjarrao struct scsi_qla_host *ha = to_qla_host(host);
2037c07d139SHarish Zunjarrao struct iscsi_bsg_request *bsg_req = bsg_job->request;
2047c07d139SHarish Zunjarrao struct iscsi_bsg_reply *bsg_reply = bsg_job->reply;
2057c07d139SHarish Zunjarrao uint32_t offset = 0;
2067c07d139SHarish Zunjarrao uint32_t len = 0;
2077c07d139SHarish Zunjarrao uint32_t total_len = 0;
2087c07d139SHarish Zunjarrao dma_addr_t nvram_dma;
2097c07d139SHarish Zunjarrao uint8_t *nvram = NULL;
2107c07d139SHarish Zunjarrao int rval = -EINVAL;
2117c07d139SHarish Zunjarrao
2127c07d139SHarish Zunjarrao bsg_reply->reply_payload_rcv_len = 0;
2137c07d139SHarish Zunjarrao
2147c07d139SHarish Zunjarrao if (unlikely(pci_channel_offline(ha->pdev)))
2157c07d139SHarish Zunjarrao goto leave;
2167c07d139SHarish Zunjarrao
2177c07d139SHarish Zunjarrao /* Only 40xx adapters are supported */
2187c07d139SHarish Zunjarrao if (!(is_qla4010(ha) || is_qla4022(ha) || is_qla4032(ha)))
2197c07d139SHarish Zunjarrao goto leave;
2207c07d139SHarish Zunjarrao
2217c07d139SHarish Zunjarrao if (ql4xxx_reset_active(ha)) {
2227c07d139SHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__);
2237c07d139SHarish Zunjarrao rval = -EBUSY;
2247c07d139SHarish Zunjarrao goto leave;
2257c07d139SHarish Zunjarrao }
2267c07d139SHarish Zunjarrao
2277c07d139SHarish Zunjarrao offset = bsg_req->rqst_data.h_vendor.vendor_cmd[1];
2287c07d139SHarish Zunjarrao len = bsg_job->reply_payload.payload_len;
2297c07d139SHarish Zunjarrao total_len = offset + len;
2307c07d139SHarish Zunjarrao
2317c07d139SHarish Zunjarrao /* total len should not be greater than max NVRAM size */
2327c07d139SHarish Zunjarrao if ((is_qla4010(ha) && total_len > QL4010_NVRAM_SIZE) ||
2337c07d139SHarish Zunjarrao ((is_qla4022(ha) || is_qla4032(ha)) &&
2347c07d139SHarish Zunjarrao total_len > QL40X2_NVRAM_SIZE)) {
2357c07d139SHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: offset+len greater than max"
2367c07d139SHarish Zunjarrao " nvram size, offset=%d len=%d\n",
2377c07d139SHarish Zunjarrao __func__, offset, len);
2387c07d139SHarish Zunjarrao goto leave;
2397c07d139SHarish Zunjarrao }
2407c07d139SHarish Zunjarrao
2417c07d139SHarish Zunjarrao nvram = dma_alloc_coherent(&ha->pdev->dev, len, &nvram_dma,
2427c07d139SHarish Zunjarrao GFP_KERNEL);
2437c07d139SHarish Zunjarrao if (!nvram) {
2447c07d139SHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: dma alloc failed for nvram "
2457c07d139SHarish Zunjarrao "data\n", __func__);
2467c07d139SHarish Zunjarrao rval = -ENOMEM;
2477c07d139SHarish Zunjarrao goto leave;
2487c07d139SHarish Zunjarrao }
2497c07d139SHarish Zunjarrao
2507c07d139SHarish Zunjarrao rval = qla4xxx_get_nvram(ha, nvram_dma, offset, len);
2517c07d139SHarish Zunjarrao if (rval) {
2527c07d139SHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: get nvram failed\n", __func__);
2537c07d139SHarish Zunjarrao bsg_reply->result = DID_ERROR << 16;
2547c07d139SHarish Zunjarrao rval = -EIO;
2557c07d139SHarish Zunjarrao } else {
2567c07d139SHarish Zunjarrao bsg_reply->reply_payload_rcv_len =
2577c07d139SHarish Zunjarrao sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
2587c07d139SHarish Zunjarrao bsg_job->reply_payload.sg_cnt,
2597c07d139SHarish Zunjarrao nvram, len);
2607c07d139SHarish Zunjarrao bsg_reply->result = DID_OK << 16;
2617c07d139SHarish Zunjarrao }
2627c07d139SHarish Zunjarrao
2637c07d139SHarish Zunjarrao bsg_job_done(bsg_job, bsg_reply->result,
2647c07d139SHarish Zunjarrao bsg_reply->reply_payload_rcv_len);
2657c07d139SHarish Zunjarrao dma_free_coherent(&ha->pdev->dev, len, nvram, nvram_dma);
2667c07d139SHarish Zunjarrao leave:
2677c07d139SHarish Zunjarrao return rval;
2687c07d139SHarish Zunjarrao }
2697c07d139SHarish Zunjarrao
2707c07d139SHarish Zunjarrao static int
qla4xxx_update_nvram(struct bsg_job * bsg_job)2717c07d139SHarish Zunjarrao qla4xxx_update_nvram(struct bsg_job *bsg_job)
2727c07d139SHarish Zunjarrao {
2737c07d139SHarish Zunjarrao struct Scsi_Host *host = iscsi_job_to_shost(bsg_job);
2747c07d139SHarish Zunjarrao struct scsi_qla_host *ha = to_qla_host(host);
2757c07d139SHarish Zunjarrao struct iscsi_bsg_request *bsg_req = bsg_job->request;
2767c07d139SHarish Zunjarrao struct iscsi_bsg_reply *bsg_reply = bsg_job->reply;
2777c07d139SHarish Zunjarrao uint32_t offset = 0;
2787c07d139SHarish Zunjarrao uint32_t len = 0;
2797c07d139SHarish Zunjarrao uint32_t total_len = 0;
2807c07d139SHarish Zunjarrao dma_addr_t nvram_dma;
2817c07d139SHarish Zunjarrao uint8_t *nvram = NULL;
2827c07d139SHarish Zunjarrao int rval = -EINVAL;
2837c07d139SHarish Zunjarrao
2847c07d139SHarish Zunjarrao bsg_reply->reply_payload_rcv_len = 0;
2857c07d139SHarish Zunjarrao
2867c07d139SHarish Zunjarrao if (unlikely(pci_channel_offline(ha->pdev)))
2877c07d139SHarish Zunjarrao goto leave;
2887c07d139SHarish Zunjarrao
2897c07d139SHarish Zunjarrao if (!(is_qla4010(ha) || is_qla4022(ha) || is_qla4032(ha)))
2907c07d139SHarish Zunjarrao goto leave;
2917c07d139SHarish Zunjarrao
2927c07d139SHarish Zunjarrao if (ql4xxx_reset_active(ha)) {
2937c07d139SHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__);
2947c07d139SHarish Zunjarrao rval = -EBUSY;
2957c07d139SHarish Zunjarrao goto leave;
2967c07d139SHarish Zunjarrao }
2977c07d139SHarish Zunjarrao
2987c07d139SHarish Zunjarrao offset = bsg_req->rqst_data.h_vendor.vendor_cmd[1];
2997c07d139SHarish Zunjarrao len = bsg_job->request_payload.payload_len;
3007c07d139SHarish Zunjarrao total_len = offset + len;
3017c07d139SHarish Zunjarrao
3027c07d139SHarish Zunjarrao /* total len should not be greater than max NVRAM size */
3037c07d139SHarish Zunjarrao if ((is_qla4010(ha) && total_len > QL4010_NVRAM_SIZE) ||
3047c07d139SHarish Zunjarrao ((is_qla4022(ha) || is_qla4032(ha)) &&
3057c07d139SHarish Zunjarrao total_len > QL40X2_NVRAM_SIZE)) {
3067c07d139SHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: offset+len greater than max"
3077c07d139SHarish Zunjarrao " nvram size, offset=%d len=%d\n",
3087c07d139SHarish Zunjarrao __func__, offset, len);
3097c07d139SHarish Zunjarrao goto leave;
3107c07d139SHarish Zunjarrao }
3117c07d139SHarish Zunjarrao
3127c07d139SHarish Zunjarrao nvram = dma_alloc_coherent(&ha->pdev->dev, len, &nvram_dma,
3137c07d139SHarish Zunjarrao GFP_KERNEL);
3147c07d139SHarish Zunjarrao if (!nvram) {
3157c07d139SHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: dma alloc failed for flash "
3167c07d139SHarish Zunjarrao "data\n", __func__);
3177c07d139SHarish Zunjarrao rval = -ENOMEM;
3187c07d139SHarish Zunjarrao goto leave;
3197c07d139SHarish Zunjarrao }
3207c07d139SHarish Zunjarrao
3217c07d139SHarish Zunjarrao sg_copy_to_buffer(bsg_job->request_payload.sg_list,
3227c07d139SHarish Zunjarrao bsg_job->request_payload.sg_cnt, nvram, len);
3237c07d139SHarish Zunjarrao
3247c07d139SHarish Zunjarrao rval = qla4xxx_set_nvram(ha, nvram_dma, offset, len);
3257c07d139SHarish Zunjarrao if (rval) {
3267c07d139SHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: set nvram failed\n", __func__);
3277c07d139SHarish Zunjarrao bsg_reply->result = DID_ERROR << 16;
3287c07d139SHarish Zunjarrao rval = -EIO;
3297c07d139SHarish Zunjarrao } else
3307c07d139SHarish Zunjarrao bsg_reply->result = DID_OK << 16;
3317c07d139SHarish Zunjarrao
3327c07d139SHarish Zunjarrao bsg_job_done(bsg_job, bsg_reply->result,
3337c07d139SHarish Zunjarrao bsg_reply->reply_payload_rcv_len);
3347c07d139SHarish Zunjarrao dma_free_coherent(&ha->pdev->dev, len, nvram, nvram_dma);
3357c07d139SHarish Zunjarrao leave:
3367c07d139SHarish Zunjarrao return rval;
3377c07d139SHarish Zunjarrao }
3387c07d139SHarish Zunjarrao
3395232f801SHarish Zunjarrao static int
qla4xxx_restore_defaults(struct bsg_job * bsg_job)3405232f801SHarish Zunjarrao qla4xxx_restore_defaults(struct bsg_job *bsg_job)
3415232f801SHarish Zunjarrao {
3425232f801SHarish Zunjarrao struct Scsi_Host *host = iscsi_job_to_shost(bsg_job);
3435232f801SHarish Zunjarrao struct scsi_qla_host *ha = to_qla_host(host);
3445232f801SHarish Zunjarrao struct iscsi_bsg_request *bsg_req = bsg_job->request;
3455232f801SHarish Zunjarrao struct iscsi_bsg_reply *bsg_reply = bsg_job->reply;
3465232f801SHarish Zunjarrao uint32_t region = 0;
3475232f801SHarish Zunjarrao uint32_t field0 = 0;
3485232f801SHarish Zunjarrao uint32_t field1 = 0;
3495232f801SHarish Zunjarrao int rval = -EINVAL;
3505232f801SHarish Zunjarrao
3515232f801SHarish Zunjarrao bsg_reply->reply_payload_rcv_len = 0;
3525232f801SHarish Zunjarrao
3535232f801SHarish Zunjarrao if (unlikely(pci_channel_offline(ha->pdev)))
3545232f801SHarish Zunjarrao goto leave;
3555232f801SHarish Zunjarrao
3565232f801SHarish Zunjarrao if (is_qla4010(ha))
3575232f801SHarish Zunjarrao goto leave;
3585232f801SHarish Zunjarrao
3595232f801SHarish Zunjarrao if (ql4xxx_reset_active(ha)) {
3605232f801SHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__);
3615232f801SHarish Zunjarrao rval = -EBUSY;
3625232f801SHarish Zunjarrao goto leave;
3635232f801SHarish Zunjarrao }
3645232f801SHarish Zunjarrao
3655232f801SHarish Zunjarrao region = bsg_req->rqst_data.h_vendor.vendor_cmd[1];
3665232f801SHarish Zunjarrao field0 = bsg_req->rqst_data.h_vendor.vendor_cmd[2];
3675232f801SHarish Zunjarrao field1 = bsg_req->rqst_data.h_vendor.vendor_cmd[3];
3685232f801SHarish Zunjarrao
3695232f801SHarish Zunjarrao rval = qla4xxx_restore_factory_defaults(ha, region, field0, field1);
3705232f801SHarish Zunjarrao if (rval) {
3715232f801SHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: set nvram failed\n", __func__);
3725232f801SHarish Zunjarrao bsg_reply->result = DID_ERROR << 16;
3735232f801SHarish Zunjarrao rval = -EIO;
3745232f801SHarish Zunjarrao } else
3755232f801SHarish Zunjarrao bsg_reply->result = DID_OK << 16;
3765232f801SHarish Zunjarrao
3775232f801SHarish Zunjarrao bsg_job_done(bsg_job, bsg_reply->result,
3785232f801SHarish Zunjarrao bsg_reply->reply_payload_rcv_len);
3795232f801SHarish Zunjarrao leave:
3805232f801SHarish Zunjarrao return rval;
3815232f801SHarish Zunjarrao }
3825232f801SHarish Zunjarrao
3836085491cSHarish Zunjarrao static int
qla4xxx_bsg_get_acb(struct bsg_job * bsg_job)3846085491cSHarish Zunjarrao qla4xxx_bsg_get_acb(struct bsg_job *bsg_job)
3856085491cSHarish Zunjarrao {
3866085491cSHarish Zunjarrao struct Scsi_Host *host = iscsi_job_to_shost(bsg_job);
3876085491cSHarish Zunjarrao struct scsi_qla_host *ha = to_qla_host(host);
3886085491cSHarish Zunjarrao struct iscsi_bsg_request *bsg_req = bsg_job->request;
3896085491cSHarish Zunjarrao struct iscsi_bsg_reply *bsg_reply = bsg_job->reply;
3906085491cSHarish Zunjarrao uint32_t acb_type = 0;
3916085491cSHarish Zunjarrao uint32_t len = 0;
3926085491cSHarish Zunjarrao dma_addr_t acb_dma;
3936085491cSHarish Zunjarrao uint8_t *acb = NULL;
3946085491cSHarish Zunjarrao int rval = -EINVAL;
3956085491cSHarish Zunjarrao
3966085491cSHarish Zunjarrao bsg_reply->reply_payload_rcv_len = 0;
3976085491cSHarish Zunjarrao
3986085491cSHarish Zunjarrao if (unlikely(pci_channel_offline(ha->pdev)))
3996085491cSHarish Zunjarrao goto leave;
4006085491cSHarish Zunjarrao
4016085491cSHarish Zunjarrao /* Only 4022 and above adapters are supported */
4026085491cSHarish Zunjarrao if (is_qla4010(ha))
4036085491cSHarish Zunjarrao goto leave;
4046085491cSHarish Zunjarrao
4056085491cSHarish Zunjarrao if (ql4xxx_reset_active(ha)) {
4066085491cSHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__);
4076085491cSHarish Zunjarrao rval = -EBUSY;
4086085491cSHarish Zunjarrao goto leave;
4096085491cSHarish Zunjarrao }
4106085491cSHarish Zunjarrao
4116085491cSHarish Zunjarrao acb_type = bsg_req->rqst_data.h_vendor.vendor_cmd[1];
4126085491cSHarish Zunjarrao len = bsg_job->reply_payload.payload_len;
4136085491cSHarish Zunjarrao if (len < sizeof(struct addr_ctrl_blk)) {
4146085491cSHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: invalid acb len %d\n",
4156085491cSHarish Zunjarrao __func__, len);
4166085491cSHarish Zunjarrao rval = -EINVAL;
4176085491cSHarish Zunjarrao goto leave;
4186085491cSHarish Zunjarrao }
4196085491cSHarish Zunjarrao
4206085491cSHarish Zunjarrao acb = dma_alloc_coherent(&ha->pdev->dev, len, &acb_dma, GFP_KERNEL);
4216085491cSHarish Zunjarrao if (!acb) {
4226085491cSHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: dma alloc failed for acb "
4236085491cSHarish Zunjarrao "data\n", __func__);
4246085491cSHarish Zunjarrao rval = -ENOMEM;
4256085491cSHarish Zunjarrao goto leave;
4266085491cSHarish Zunjarrao }
4276085491cSHarish Zunjarrao
4286085491cSHarish Zunjarrao rval = qla4xxx_get_acb(ha, acb_dma, acb_type, len);
4296085491cSHarish Zunjarrao if (rval) {
4306085491cSHarish Zunjarrao ql4_printk(KERN_ERR, ha, "%s: get acb failed\n", __func__);
4316085491cSHarish Zunjarrao bsg_reply->result = DID_ERROR << 16;
4326085491cSHarish Zunjarrao rval = -EIO;
4336085491cSHarish Zunjarrao } else {
4346085491cSHarish Zunjarrao bsg_reply->reply_payload_rcv_len =
4356085491cSHarish Zunjarrao sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
4366085491cSHarish Zunjarrao bsg_job->reply_payload.sg_cnt,
4376085491cSHarish Zunjarrao acb, len);
4386085491cSHarish Zunjarrao bsg_reply->result = DID_OK << 16;
4396085491cSHarish Zunjarrao }
4406085491cSHarish Zunjarrao
4416085491cSHarish Zunjarrao bsg_job_done(bsg_job, bsg_reply->result,
4426085491cSHarish Zunjarrao bsg_reply->reply_payload_rcv_len);
4436085491cSHarish Zunjarrao dma_free_coherent(&ha->pdev->dev, len, acb, acb_dma);
4446085491cSHarish Zunjarrao leave:
4456085491cSHarish Zunjarrao return rval;
4466085491cSHarish Zunjarrao }
4476085491cSHarish Zunjarrao
ql4xxx_execute_diag_cmd(struct bsg_job * bsg_job)448df86f771SVikas Chaudhary static void ql4xxx_execute_diag_cmd(struct bsg_job *bsg_job)
449df86f771SVikas Chaudhary {
450df86f771SVikas Chaudhary struct Scsi_Host *host = iscsi_job_to_shost(bsg_job);
451df86f771SVikas Chaudhary struct scsi_qla_host *ha = to_qla_host(host);
452df86f771SVikas Chaudhary struct iscsi_bsg_request *bsg_req = bsg_job->request;
453df86f771SVikas Chaudhary struct iscsi_bsg_reply *bsg_reply = bsg_job->reply;
454df86f771SVikas Chaudhary uint8_t *rsp_ptr = NULL;
455df86f771SVikas Chaudhary uint32_t mbox_cmd[MBOX_REG_COUNT];
456df86f771SVikas Chaudhary uint32_t mbox_sts[MBOX_REG_COUNT];
457df86f771SVikas Chaudhary int status = QLA_ERROR;
458df86f771SVikas Chaudhary
459df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s: in\n", __func__));
460df86f771SVikas Chaudhary
461df86f771SVikas Chaudhary if (test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
462df86f771SVikas Chaudhary ql4_printk(KERN_INFO, ha, "%s: Adapter reset in progress. Invalid Request\n",
463df86f771SVikas Chaudhary __func__);
464df86f771SVikas Chaudhary bsg_reply->result = DID_ERROR << 16;
465df86f771SVikas Chaudhary goto exit_diag_mem_test;
466df86f771SVikas Chaudhary }
467df86f771SVikas Chaudhary
468df86f771SVikas Chaudhary bsg_reply->reply_payload_rcv_len = 0;
469df86f771SVikas Chaudhary memcpy(mbox_cmd, &bsg_req->rqst_data.h_vendor.vendor_cmd[1],
470df86f771SVikas Chaudhary sizeof(uint32_t) * MBOX_REG_COUNT);
471df86f771SVikas Chaudhary
472df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha,
473df86f771SVikas Chaudhary "%s: mbox_cmd: %08X %08X %08X %08X %08X %08X %08X %08X\n",
474df86f771SVikas Chaudhary __func__, mbox_cmd[0], mbox_cmd[1], mbox_cmd[2],
475df86f771SVikas Chaudhary mbox_cmd[3], mbox_cmd[4], mbox_cmd[5], mbox_cmd[6],
476df86f771SVikas Chaudhary mbox_cmd[7]));
477df86f771SVikas Chaudhary
478df86f771SVikas Chaudhary status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 8, &mbox_cmd[0],
479df86f771SVikas Chaudhary &mbox_sts[0]);
480df86f771SVikas Chaudhary
481df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha,
482df86f771SVikas Chaudhary "%s: mbox_sts: %08X %08X %08X %08X %08X %08X %08X %08X\n",
483df86f771SVikas Chaudhary __func__, mbox_sts[0], mbox_sts[1], mbox_sts[2],
484df86f771SVikas Chaudhary mbox_sts[3], mbox_sts[4], mbox_sts[5], mbox_sts[6],
485df86f771SVikas Chaudhary mbox_sts[7]));
486df86f771SVikas Chaudhary
487df86f771SVikas Chaudhary if (status == QLA_SUCCESS)
488df86f771SVikas Chaudhary bsg_reply->result = DID_OK << 16;
489df86f771SVikas Chaudhary else
490df86f771SVikas Chaudhary bsg_reply->result = DID_ERROR << 16;
491df86f771SVikas Chaudhary
492df86f771SVikas Chaudhary /* Send mbox_sts to application */
493df86f771SVikas Chaudhary bsg_job->reply_len = sizeof(struct iscsi_bsg_reply) + sizeof(mbox_sts);
494df86f771SVikas Chaudhary rsp_ptr = ((uint8_t *)bsg_reply) + sizeof(struct iscsi_bsg_reply);
495df86f771SVikas Chaudhary memcpy(rsp_ptr, mbox_sts, sizeof(mbox_sts));
496df86f771SVikas Chaudhary
497df86f771SVikas Chaudhary exit_diag_mem_test:
498df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha,
499df86f771SVikas Chaudhary "%s: bsg_reply->result = x%x, status = %s\n",
500df86f771SVikas Chaudhary __func__, bsg_reply->result, STATUS(status)));
501df86f771SVikas Chaudhary
502df86f771SVikas Chaudhary bsg_job_done(bsg_job, bsg_reply->result,
503df86f771SVikas Chaudhary bsg_reply->reply_payload_rcv_len);
504df86f771SVikas Chaudhary }
505df86f771SVikas Chaudhary
qla4_83xx_wait_for_loopback_config_comp(struct scsi_qla_host * ha,int wait_for_link)506df86f771SVikas Chaudhary static int qla4_83xx_wait_for_loopback_config_comp(struct scsi_qla_host *ha,
507df86f771SVikas Chaudhary int wait_for_link)
508df86f771SVikas Chaudhary {
509df86f771SVikas Chaudhary int status = QLA_SUCCESS;
510df86f771SVikas Chaudhary
511df86f771SVikas Chaudhary if (!wait_for_completion_timeout(&ha->idc_comp, (IDC_COMP_TOV * HZ))) {
512df86f771SVikas Chaudhary ql4_printk(KERN_INFO, ha, "%s: IDC Complete notification not received, Waiting for another %d timeout",
513df86f771SVikas Chaudhary __func__, ha->idc_extend_tmo);
514df86f771SVikas Chaudhary if (ha->idc_extend_tmo) {
515df86f771SVikas Chaudhary if (!wait_for_completion_timeout(&ha->idc_comp,
516df86f771SVikas Chaudhary (ha->idc_extend_tmo * HZ))) {
517df86f771SVikas Chaudhary ha->notify_idc_comp = 0;
518df86f771SVikas Chaudhary ha->notify_link_up_comp = 0;
51956ccb988SNilesh Javali ql4_printk(KERN_WARNING, ha, "%s: Aborting: IDC Complete notification not received",
520df86f771SVikas Chaudhary __func__);
521df86f771SVikas Chaudhary status = QLA_ERROR;
522df86f771SVikas Chaudhary goto exit_wait;
523df86f771SVikas Chaudhary } else {
524df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha,
525df86f771SVikas Chaudhary "%s: IDC Complete notification received\n",
526df86f771SVikas Chaudhary __func__));
527df86f771SVikas Chaudhary }
528df86f771SVikas Chaudhary }
529df86f771SVikas Chaudhary } else {
530df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha,
531df86f771SVikas Chaudhary "%s: IDC Complete notification received\n",
532df86f771SVikas Chaudhary __func__));
533df86f771SVikas Chaudhary }
534df86f771SVikas Chaudhary ha->notify_idc_comp = 0;
535df86f771SVikas Chaudhary
536df86f771SVikas Chaudhary if (wait_for_link) {
537df86f771SVikas Chaudhary if (!wait_for_completion_timeout(&ha->link_up_comp,
538df86f771SVikas Chaudhary (IDC_COMP_TOV * HZ))) {
539df86f771SVikas Chaudhary ha->notify_link_up_comp = 0;
54056ccb988SNilesh Javali ql4_printk(KERN_WARNING, ha, "%s: Aborting: LINK UP notification not received",
541df86f771SVikas Chaudhary __func__);
542df86f771SVikas Chaudhary status = QLA_ERROR;
543df86f771SVikas Chaudhary goto exit_wait;
544df86f771SVikas Chaudhary } else {
545df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha,
546df86f771SVikas Chaudhary "%s: LINK UP notification received\n",
547df86f771SVikas Chaudhary __func__));
548df86f771SVikas Chaudhary }
549df86f771SVikas Chaudhary ha->notify_link_up_comp = 0;
550df86f771SVikas Chaudhary }
551df86f771SVikas Chaudhary
552df86f771SVikas Chaudhary exit_wait:
553df86f771SVikas Chaudhary return status;
554df86f771SVikas Chaudhary }
555df86f771SVikas Chaudhary
qla4_83xx_pre_loopback_config(struct scsi_qla_host * ha,uint32_t * mbox_cmd)556df86f771SVikas Chaudhary static int qla4_83xx_pre_loopback_config(struct scsi_qla_host *ha,
557df86f771SVikas Chaudhary uint32_t *mbox_cmd)
558df86f771SVikas Chaudhary {
559df86f771SVikas Chaudhary uint32_t config = 0;
560df86f771SVikas Chaudhary int status = QLA_SUCCESS;
561df86f771SVikas Chaudhary
562df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s: in\n", __func__));
563df86f771SVikas Chaudhary
564df86f771SVikas Chaudhary status = qla4_83xx_get_port_config(ha, &config);
565df86f771SVikas Chaudhary if (status != QLA_SUCCESS)
566df86f771SVikas Chaudhary goto exit_pre_loopback_config;
567df86f771SVikas Chaudhary
568df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Default port config=%08X\n",
569df86f771SVikas Chaudhary __func__, config));
570df86f771SVikas Chaudhary
571df86f771SVikas Chaudhary if ((config & ENABLE_INTERNAL_LOOPBACK) ||
572df86f771SVikas Chaudhary (config & ENABLE_EXTERNAL_LOOPBACK)) {
5738c519319SMasanari Iida ql4_printk(KERN_INFO, ha, "%s: Loopback diagnostics already in progress. Invalid request\n",
574df86f771SVikas Chaudhary __func__);
575df86f771SVikas Chaudhary goto exit_pre_loopback_config;
576df86f771SVikas Chaudhary }
577df86f771SVikas Chaudhary
578df86f771SVikas Chaudhary if (mbox_cmd[1] == QL_DIAG_CMD_TEST_INT_LOOPBACK)
579df86f771SVikas Chaudhary config |= ENABLE_INTERNAL_LOOPBACK;
580df86f771SVikas Chaudhary
581df86f771SVikas Chaudhary if (mbox_cmd[1] == QL_DIAG_CMD_TEST_EXT_LOOPBACK)
582df86f771SVikas Chaudhary config |= ENABLE_EXTERNAL_LOOPBACK;
583df86f771SVikas Chaudhary
584df86f771SVikas Chaudhary config &= ~ENABLE_DCBX;
585df86f771SVikas Chaudhary
586df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s: New port config=%08X\n",
587df86f771SVikas Chaudhary __func__, config));
588df86f771SVikas Chaudhary
589df86f771SVikas Chaudhary ha->notify_idc_comp = 1;
590df86f771SVikas Chaudhary ha->notify_link_up_comp = 1;
591df86f771SVikas Chaudhary
592df86f771SVikas Chaudhary /* get the link state */
593df86f771SVikas Chaudhary qla4xxx_get_firmware_state(ha);
594df86f771SVikas Chaudhary
595df86f771SVikas Chaudhary status = qla4_83xx_set_port_config(ha, &config);
596df86f771SVikas Chaudhary if (status != QLA_SUCCESS) {
597df86f771SVikas Chaudhary ha->notify_idc_comp = 0;
598df86f771SVikas Chaudhary ha->notify_link_up_comp = 0;
599df86f771SVikas Chaudhary goto exit_pre_loopback_config;
600df86f771SVikas Chaudhary }
601df86f771SVikas Chaudhary exit_pre_loopback_config:
602df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s: status = %s\n", __func__,
603df86f771SVikas Chaudhary STATUS(status)));
604df86f771SVikas Chaudhary return status;
605df86f771SVikas Chaudhary }
606df86f771SVikas Chaudhary
qla4_83xx_post_loopback_config(struct scsi_qla_host * ha,uint32_t * mbox_cmd)607df86f771SVikas Chaudhary static int qla4_83xx_post_loopback_config(struct scsi_qla_host *ha,
608df86f771SVikas Chaudhary uint32_t *mbox_cmd)
609df86f771SVikas Chaudhary {
610df86f771SVikas Chaudhary int status = QLA_SUCCESS;
611df86f771SVikas Chaudhary uint32_t config = 0;
612df86f771SVikas Chaudhary
613df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s: in\n", __func__));
614df86f771SVikas Chaudhary
615df86f771SVikas Chaudhary status = qla4_83xx_get_port_config(ha, &config);
616df86f771SVikas Chaudhary if (status != QLA_SUCCESS)
617df86f771SVikas Chaudhary goto exit_post_loopback_config;
618df86f771SVikas Chaudhary
619df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s: port config=%08X\n", __func__,
620df86f771SVikas Chaudhary config));
621df86f771SVikas Chaudhary
622df86f771SVikas Chaudhary if (mbox_cmd[1] == QL_DIAG_CMD_TEST_INT_LOOPBACK)
623df86f771SVikas Chaudhary config &= ~ENABLE_INTERNAL_LOOPBACK;
624df86f771SVikas Chaudhary else if (mbox_cmd[1] == QL_DIAG_CMD_TEST_EXT_LOOPBACK)
625df86f771SVikas Chaudhary config &= ~ENABLE_EXTERNAL_LOOPBACK;
626df86f771SVikas Chaudhary
627df86f771SVikas Chaudhary config |= ENABLE_DCBX;
628df86f771SVikas Chaudhary
629df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha,
630df86f771SVikas Chaudhary "%s: Restore default port config=%08X\n", __func__,
631df86f771SVikas Chaudhary config));
632df86f771SVikas Chaudhary
633df86f771SVikas Chaudhary ha->notify_idc_comp = 1;
634df86f771SVikas Chaudhary if (ha->addl_fw_state & FW_ADDSTATE_LINK_UP)
635df86f771SVikas Chaudhary ha->notify_link_up_comp = 1;
636df86f771SVikas Chaudhary
637df86f771SVikas Chaudhary status = qla4_83xx_set_port_config(ha, &config);
638df86f771SVikas Chaudhary if (status != QLA_SUCCESS) {
639df86f771SVikas Chaudhary ql4_printk(KERN_INFO, ha, "%s: Scheduling adapter reset\n",
640df86f771SVikas Chaudhary __func__);
641df86f771SVikas Chaudhary set_bit(DPC_RESET_HA, &ha->dpc_flags);
642df86f771SVikas Chaudhary clear_bit(AF_LOOPBACK, &ha->flags);
643df86f771SVikas Chaudhary goto exit_post_loopback_config;
644df86f771SVikas Chaudhary }
645df86f771SVikas Chaudhary
646df86f771SVikas Chaudhary exit_post_loopback_config:
647df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s: status = %s\n", __func__,
648df86f771SVikas Chaudhary STATUS(status)));
649df86f771SVikas Chaudhary return status;
650df86f771SVikas Chaudhary }
651df86f771SVikas Chaudhary
qla4xxx_execute_diag_loopback_cmd(struct bsg_job * bsg_job)652df86f771SVikas Chaudhary static void qla4xxx_execute_diag_loopback_cmd(struct bsg_job *bsg_job)
653df86f771SVikas Chaudhary {
654df86f771SVikas Chaudhary struct Scsi_Host *host = iscsi_job_to_shost(bsg_job);
655df86f771SVikas Chaudhary struct scsi_qla_host *ha = to_qla_host(host);
656df86f771SVikas Chaudhary struct iscsi_bsg_request *bsg_req = bsg_job->request;
657df86f771SVikas Chaudhary struct iscsi_bsg_reply *bsg_reply = bsg_job->reply;
658df86f771SVikas Chaudhary uint8_t *rsp_ptr = NULL;
659df86f771SVikas Chaudhary uint32_t mbox_cmd[MBOX_REG_COUNT];
660df86f771SVikas Chaudhary uint32_t mbox_sts[MBOX_REG_COUNT];
661df86f771SVikas Chaudhary int wait_for_link = 1;
662df86f771SVikas Chaudhary int status = QLA_ERROR;
663df86f771SVikas Chaudhary
664df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s: in\n", __func__));
665df86f771SVikas Chaudhary
666df86f771SVikas Chaudhary bsg_reply->reply_payload_rcv_len = 0;
667df86f771SVikas Chaudhary
668df86f771SVikas Chaudhary if (test_bit(AF_LOOPBACK, &ha->flags)) {
669df86f771SVikas Chaudhary ql4_printk(KERN_INFO, ha, "%s: Loopback Diagnostics already in progress. Invalid Request\n",
670df86f771SVikas Chaudhary __func__);
671df86f771SVikas Chaudhary bsg_reply->result = DID_ERROR << 16;
672df86f771SVikas Chaudhary goto exit_loopback_cmd;
673df86f771SVikas Chaudhary }
674df86f771SVikas Chaudhary
675df86f771SVikas Chaudhary if (test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
676df86f771SVikas Chaudhary ql4_printk(KERN_INFO, ha, "%s: Adapter reset in progress. Invalid Request\n",
677df86f771SVikas Chaudhary __func__);
678df86f771SVikas Chaudhary bsg_reply->result = DID_ERROR << 16;
679df86f771SVikas Chaudhary goto exit_loopback_cmd;
680df86f771SVikas Chaudhary }
681df86f771SVikas Chaudhary
682df86f771SVikas Chaudhary memcpy(mbox_cmd, &bsg_req->rqst_data.h_vendor.vendor_cmd[1],
683df86f771SVikas Chaudhary sizeof(uint32_t) * MBOX_REG_COUNT);
684df86f771SVikas Chaudhary
685df86f771SVikas Chaudhary if (is_qla8032(ha) || is_qla8042(ha)) {
686df86f771SVikas Chaudhary status = qla4_83xx_pre_loopback_config(ha, mbox_cmd);
687df86f771SVikas Chaudhary if (status != QLA_SUCCESS) {
688df86f771SVikas Chaudhary bsg_reply->result = DID_ERROR << 16;
689df86f771SVikas Chaudhary goto exit_loopback_cmd;
690df86f771SVikas Chaudhary }
691df86f771SVikas Chaudhary
692df86f771SVikas Chaudhary status = qla4_83xx_wait_for_loopback_config_comp(ha,
693df86f771SVikas Chaudhary wait_for_link);
694df86f771SVikas Chaudhary if (status != QLA_SUCCESS) {
695df86f771SVikas Chaudhary bsg_reply->result = DID_TIME_OUT << 16;
696df86f771SVikas Chaudhary goto restore;
697df86f771SVikas Chaudhary }
698df86f771SVikas Chaudhary }
699df86f771SVikas Chaudhary
700df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha,
701df86f771SVikas Chaudhary "%s: mbox_cmd: %08X %08X %08X %08X %08X %08X %08X %08X\n",
702df86f771SVikas Chaudhary __func__, mbox_cmd[0], mbox_cmd[1], mbox_cmd[2],
703df86f771SVikas Chaudhary mbox_cmd[3], mbox_cmd[4], mbox_cmd[5], mbox_cmd[6],
704df86f771SVikas Chaudhary mbox_cmd[7]));
705df86f771SVikas Chaudhary
706df86f771SVikas Chaudhary status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 8, &mbox_cmd[0],
707df86f771SVikas Chaudhary &mbox_sts[0]);
708df86f771SVikas Chaudhary
709df86f771SVikas Chaudhary if (status == QLA_SUCCESS)
710df86f771SVikas Chaudhary bsg_reply->result = DID_OK << 16;
711df86f771SVikas Chaudhary else
712df86f771SVikas Chaudhary bsg_reply->result = DID_ERROR << 16;
713df86f771SVikas Chaudhary
714df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha,
715df86f771SVikas Chaudhary "%s: mbox_sts: %08X %08X %08X %08X %08X %08X %08X %08X\n",
716df86f771SVikas Chaudhary __func__, mbox_sts[0], mbox_sts[1], mbox_sts[2],
717df86f771SVikas Chaudhary mbox_sts[3], mbox_sts[4], mbox_sts[5], mbox_sts[6],
718df86f771SVikas Chaudhary mbox_sts[7]));
719df86f771SVikas Chaudhary
720df86f771SVikas Chaudhary /* Send mbox_sts to application */
721df86f771SVikas Chaudhary bsg_job->reply_len = sizeof(struct iscsi_bsg_reply) + sizeof(mbox_sts);
722df86f771SVikas Chaudhary rsp_ptr = ((uint8_t *)bsg_reply) + sizeof(struct iscsi_bsg_reply);
723df86f771SVikas Chaudhary memcpy(rsp_ptr, mbox_sts, sizeof(mbox_sts));
724df86f771SVikas Chaudhary restore:
725df86f771SVikas Chaudhary if (is_qla8032(ha) || is_qla8042(ha)) {
726df86f771SVikas Chaudhary status = qla4_83xx_post_loopback_config(ha, mbox_cmd);
727df86f771SVikas Chaudhary if (status != QLA_SUCCESS) {
728df86f771SVikas Chaudhary bsg_reply->result = DID_ERROR << 16;
729df86f771SVikas Chaudhary goto exit_loopback_cmd;
730df86f771SVikas Chaudhary }
731df86f771SVikas Chaudhary
732df86f771SVikas Chaudhary /* for pre_loopback_config() wait for LINK UP only
733df86f771SVikas Chaudhary * if PHY LINK is UP */
734df86f771SVikas Chaudhary if (!(ha->addl_fw_state & FW_ADDSTATE_LINK_UP))
735df86f771SVikas Chaudhary wait_for_link = 0;
736df86f771SVikas Chaudhary
737df86f771SVikas Chaudhary status = qla4_83xx_wait_for_loopback_config_comp(ha,
738df86f771SVikas Chaudhary wait_for_link);
739df86f771SVikas Chaudhary if (status != QLA_SUCCESS) {
740df86f771SVikas Chaudhary bsg_reply->result = DID_TIME_OUT << 16;
741df86f771SVikas Chaudhary goto exit_loopback_cmd;
742df86f771SVikas Chaudhary }
743df86f771SVikas Chaudhary }
744df86f771SVikas Chaudhary exit_loopback_cmd:
745df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha,
746df86f771SVikas Chaudhary "%s: bsg_reply->result = x%x, status = %s\n",
747df86f771SVikas Chaudhary __func__, bsg_reply->result, STATUS(status)));
748df86f771SVikas Chaudhary bsg_job_done(bsg_job, bsg_reply->result,
749df86f771SVikas Chaudhary bsg_reply->reply_payload_rcv_len);
750df86f771SVikas Chaudhary }
751df86f771SVikas Chaudhary
qla4xxx_execute_diag_test(struct bsg_job * bsg_job)752df86f771SVikas Chaudhary static int qla4xxx_execute_diag_test(struct bsg_job *bsg_job)
753df86f771SVikas Chaudhary {
754df86f771SVikas Chaudhary struct Scsi_Host *host = iscsi_job_to_shost(bsg_job);
755df86f771SVikas Chaudhary struct scsi_qla_host *ha = to_qla_host(host);
756df86f771SVikas Chaudhary struct iscsi_bsg_request *bsg_req = bsg_job->request;
757df86f771SVikas Chaudhary uint32_t diag_cmd;
758df86f771SVikas Chaudhary int rval = -EINVAL;
759df86f771SVikas Chaudhary
760df86f771SVikas Chaudhary DEBUG2(ql4_printk(KERN_INFO, ha, "%s: in\n", __func__));
761df86f771SVikas Chaudhary
762df86f771SVikas Chaudhary diag_cmd = bsg_req->rqst_data.h_vendor.vendor_cmd[1];
763df86f771SVikas Chaudhary if (diag_cmd == MBOX_CMD_DIAG_TEST) {
764df86f771SVikas Chaudhary switch (bsg_req->rqst_data.h_vendor.vendor_cmd[2]) {
765df86f771SVikas Chaudhary case QL_DIAG_CMD_TEST_DDR_SIZE:
766df86f771SVikas Chaudhary case QL_DIAG_CMD_TEST_DDR_RW:
767df86f771SVikas Chaudhary case QL_DIAG_CMD_TEST_ONCHIP_MEM_RW:
768df86f771SVikas Chaudhary case QL_DIAG_CMD_TEST_NVRAM:
769df86f771SVikas Chaudhary case QL_DIAG_CMD_TEST_FLASH_ROM:
770df86f771SVikas Chaudhary case QL_DIAG_CMD_TEST_DMA_XFER:
771df86f771SVikas Chaudhary case QL_DIAG_CMD_SELF_DDR_RW:
772df86f771SVikas Chaudhary case QL_DIAG_CMD_SELF_ONCHIP_MEM_RW:
773df86f771SVikas Chaudhary /* Execute diag test for adapter RAM/FLASH */
774df86f771SVikas Chaudhary ql4xxx_execute_diag_cmd(bsg_job);
775df86f771SVikas Chaudhary /* Always return success as we want to sent bsg_reply
776df86f771SVikas Chaudhary * to Application */
777df86f771SVikas Chaudhary rval = QLA_SUCCESS;
778df86f771SVikas Chaudhary break;
779df86f771SVikas Chaudhary
780df86f771SVikas Chaudhary case QL_DIAG_CMD_TEST_INT_LOOPBACK:
781df86f771SVikas Chaudhary case QL_DIAG_CMD_TEST_EXT_LOOPBACK:
782df86f771SVikas Chaudhary /* Execute diag test for Network */
783df86f771SVikas Chaudhary qla4xxx_execute_diag_loopback_cmd(bsg_job);
784df86f771SVikas Chaudhary /* Always return success as we want to sent bsg_reply
785df86f771SVikas Chaudhary * to Application */
786df86f771SVikas Chaudhary rval = QLA_SUCCESS;
787df86f771SVikas Chaudhary break;
788df86f771SVikas Chaudhary default:
789df86f771SVikas Chaudhary ql4_printk(KERN_ERR, ha, "%s: Invalid diag test: 0x%x\n",
790df86f771SVikas Chaudhary __func__,
791df86f771SVikas Chaudhary bsg_req->rqst_data.h_vendor.vendor_cmd[2]);
792df86f771SVikas Chaudhary }
793df86f771SVikas Chaudhary } else if ((diag_cmd == MBOX_CMD_SET_LED_CONFIG) ||
794df86f771SVikas Chaudhary (diag_cmd == MBOX_CMD_GET_LED_CONFIG)) {
795df86f771SVikas Chaudhary ql4xxx_execute_diag_cmd(bsg_job);
796df86f771SVikas Chaudhary rval = QLA_SUCCESS;
797df86f771SVikas Chaudhary } else {
798df86f771SVikas Chaudhary ql4_printk(KERN_ERR, ha, "%s: Invalid diag cmd: 0x%x\n",
799df86f771SVikas Chaudhary __func__, diag_cmd);
800df86f771SVikas Chaudhary }
801df86f771SVikas Chaudhary
802df86f771SVikas Chaudhary return rval;
803df86f771SVikas Chaudhary }
804df86f771SVikas Chaudhary
805a355943cSVikas Chaudhary /**
806a355943cSVikas Chaudhary * qla4xxx_process_vendor_specific - handle vendor specific bsg request
807d10d1df6SLee Jones * @bsg_job: iscsi_bsg_job to handle
808a355943cSVikas Chaudhary **/
qla4xxx_process_vendor_specific(struct bsg_job * bsg_job)809a355943cSVikas Chaudhary int qla4xxx_process_vendor_specific(struct bsg_job *bsg_job)
810a355943cSVikas Chaudhary {
811a355943cSVikas Chaudhary struct iscsi_bsg_reply *bsg_reply = bsg_job->reply;
812a355943cSVikas Chaudhary struct iscsi_bsg_request *bsg_req = bsg_job->request;
813a355943cSVikas Chaudhary struct Scsi_Host *host = iscsi_job_to_shost(bsg_job);
814a355943cSVikas Chaudhary struct scsi_qla_host *ha = to_qla_host(host);
815a355943cSVikas Chaudhary
816a355943cSVikas Chaudhary switch (bsg_req->rqst_data.h_vendor.vendor_cmd[0]) {
817a355943cSVikas Chaudhary case QLISCSI_VND_READ_FLASH:
818a355943cSVikas Chaudhary return qla4xxx_read_flash(bsg_job);
819a355943cSVikas Chaudhary
820a355943cSVikas Chaudhary case QLISCSI_VND_UPDATE_FLASH:
821a355943cSVikas Chaudhary return qla4xxx_update_flash(bsg_job);
822a355943cSVikas Chaudhary
8238b0402e1SHarish Zunjarrao case QLISCSI_VND_GET_ACB_STATE:
8248b0402e1SHarish Zunjarrao return qla4xxx_get_acb_state(bsg_job);
8258b0402e1SHarish Zunjarrao
8267c07d139SHarish Zunjarrao case QLISCSI_VND_READ_NVRAM:
8277c07d139SHarish Zunjarrao return qla4xxx_read_nvram(bsg_job);
8287c07d139SHarish Zunjarrao
8297c07d139SHarish Zunjarrao case QLISCSI_VND_UPDATE_NVRAM:
8307c07d139SHarish Zunjarrao return qla4xxx_update_nvram(bsg_job);
8317c07d139SHarish Zunjarrao
8325232f801SHarish Zunjarrao case QLISCSI_VND_RESTORE_DEFAULTS:
8335232f801SHarish Zunjarrao return qla4xxx_restore_defaults(bsg_job);
8345232f801SHarish Zunjarrao
8356085491cSHarish Zunjarrao case QLISCSI_VND_GET_ACB:
8366085491cSHarish Zunjarrao return qla4xxx_bsg_get_acb(bsg_job);
8376085491cSHarish Zunjarrao
838df86f771SVikas Chaudhary case QLISCSI_VND_DIAG_TEST:
839df86f771SVikas Chaudhary return qla4xxx_execute_diag_test(bsg_job);
840df86f771SVikas Chaudhary
841a355943cSVikas Chaudhary default:
842a355943cSVikas Chaudhary ql4_printk(KERN_ERR, ha, "%s: invalid BSG vendor command: "
843a355943cSVikas Chaudhary "0x%x\n", __func__, bsg_req->msgcode);
844a355943cSVikas Chaudhary bsg_reply->result = (DID_ERROR << 16);
845a355943cSVikas Chaudhary bsg_reply->reply_payload_rcv_len = 0;
846a355943cSVikas Chaudhary bsg_job_done(bsg_job, bsg_reply->result,
847a355943cSVikas Chaudhary bsg_reply->reply_payload_rcv_len);
848a355943cSVikas Chaudhary return -ENOSYS;
849a355943cSVikas Chaudhary }
850a355943cSVikas Chaudhary }
851a355943cSVikas Chaudhary
852a355943cSVikas Chaudhary /**
853a355943cSVikas Chaudhary * qla4xxx_bsg_request - handle bsg request from ISCSI transport
854d10d1df6SLee Jones * @bsg_job: iscsi_bsg_job to handle
855a355943cSVikas Chaudhary */
qla4xxx_bsg_request(struct bsg_job * bsg_job)856a355943cSVikas Chaudhary int qla4xxx_bsg_request(struct bsg_job *bsg_job)
857a355943cSVikas Chaudhary {
858a355943cSVikas Chaudhary struct iscsi_bsg_request *bsg_req = bsg_job->request;
859a355943cSVikas Chaudhary struct Scsi_Host *host = iscsi_job_to_shost(bsg_job);
860a355943cSVikas Chaudhary struct scsi_qla_host *ha = to_qla_host(host);
861a355943cSVikas Chaudhary
862a355943cSVikas Chaudhary switch (bsg_req->msgcode) {
863a355943cSVikas Chaudhary case ISCSI_BSG_HST_VENDOR:
864a355943cSVikas Chaudhary return qla4xxx_process_vendor_specific(bsg_job);
865a355943cSVikas Chaudhary
866a355943cSVikas Chaudhary default:
867a355943cSVikas Chaudhary ql4_printk(KERN_ERR, ha, "%s: invalid BSG command: 0x%x\n",
868a355943cSVikas Chaudhary __func__, bsg_req->msgcode);
869a355943cSVikas Chaudhary }
870a355943cSVikas Chaudhary
871a355943cSVikas Chaudhary return -ENOSYS;
872a355943cSVikas Chaudhary }
873