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