xref: /openbmc/linux/drivers/scsi/qla4xxx/ql4_bsg.c (revision e3976af5)
1e3976af5SThomas 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