xref: /openbmc/linux/drivers/scsi/qla4xxx/ql4_bsg.c (revision 6085491c)
1a355943cSVikas Chaudhary /*
2a355943cSVikas Chaudhary  * QLogic iSCSI HBA Driver
3a355943cSVikas Chaudhary  * Copyright (c) 2011 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 
449a355943cSVikas Chaudhary /**
450a355943cSVikas Chaudhary  * qla4xxx_process_vendor_specific - handle vendor specific bsg request
451a355943cSVikas Chaudhary  * @job: iscsi_bsg_job to handle
452a355943cSVikas Chaudhary  **/
453a355943cSVikas Chaudhary int qla4xxx_process_vendor_specific(struct bsg_job *bsg_job)
454a355943cSVikas Chaudhary {
455a355943cSVikas Chaudhary 	struct iscsi_bsg_reply *bsg_reply = bsg_job->reply;
456a355943cSVikas Chaudhary 	struct iscsi_bsg_request *bsg_req = bsg_job->request;
457a355943cSVikas Chaudhary 	struct Scsi_Host *host = iscsi_job_to_shost(bsg_job);
458a355943cSVikas Chaudhary 	struct scsi_qla_host *ha = to_qla_host(host);
459a355943cSVikas Chaudhary 
460a355943cSVikas Chaudhary 	switch (bsg_req->rqst_data.h_vendor.vendor_cmd[0]) {
461a355943cSVikas Chaudhary 	case QLISCSI_VND_READ_FLASH:
462a355943cSVikas Chaudhary 		return qla4xxx_read_flash(bsg_job);
463a355943cSVikas Chaudhary 
464a355943cSVikas Chaudhary 	case QLISCSI_VND_UPDATE_FLASH:
465a355943cSVikas Chaudhary 		return qla4xxx_update_flash(bsg_job);
466a355943cSVikas Chaudhary 
4678b0402e1SHarish Zunjarrao 	case QLISCSI_VND_GET_ACB_STATE:
4688b0402e1SHarish Zunjarrao 		return qla4xxx_get_acb_state(bsg_job);
4698b0402e1SHarish Zunjarrao 
4707c07d139SHarish Zunjarrao 	case QLISCSI_VND_READ_NVRAM:
4717c07d139SHarish Zunjarrao 		return qla4xxx_read_nvram(bsg_job);
4727c07d139SHarish Zunjarrao 
4737c07d139SHarish Zunjarrao 	case QLISCSI_VND_UPDATE_NVRAM:
4747c07d139SHarish Zunjarrao 		return qla4xxx_update_nvram(bsg_job);
4757c07d139SHarish Zunjarrao 
4765232f801SHarish Zunjarrao 	case QLISCSI_VND_RESTORE_DEFAULTS:
4775232f801SHarish Zunjarrao 		return qla4xxx_restore_defaults(bsg_job);
4785232f801SHarish Zunjarrao 
4796085491cSHarish Zunjarrao 	case QLISCSI_VND_GET_ACB:
4806085491cSHarish Zunjarrao 		return qla4xxx_bsg_get_acb(bsg_job);
4816085491cSHarish Zunjarrao 
482a355943cSVikas Chaudhary 	default:
483a355943cSVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: invalid BSG vendor command: "
484a355943cSVikas Chaudhary 			   "0x%x\n", __func__, bsg_req->msgcode);
485a355943cSVikas Chaudhary 		bsg_reply->result = (DID_ERROR << 16);
486a355943cSVikas Chaudhary 		bsg_reply->reply_payload_rcv_len = 0;
487a355943cSVikas Chaudhary 		bsg_job_done(bsg_job, bsg_reply->result,
488a355943cSVikas Chaudhary 			     bsg_reply->reply_payload_rcv_len);
489a355943cSVikas Chaudhary 		return -ENOSYS;
490a355943cSVikas Chaudhary 	}
491a355943cSVikas Chaudhary }
492a355943cSVikas Chaudhary 
493a355943cSVikas Chaudhary /**
494a355943cSVikas Chaudhary  * qla4xxx_bsg_request - handle bsg request from ISCSI transport
495a355943cSVikas Chaudhary  * @job: iscsi_bsg_job to handle
496a355943cSVikas Chaudhary  */
497a355943cSVikas Chaudhary int qla4xxx_bsg_request(struct bsg_job *bsg_job)
498a355943cSVikas Chaudhary {
499a355943cSVikas Chaudhary 	struct iscsi_bsg_request *bsg_req = bsg_job->request;
500a355943cSVikas Chaudhary 	struct Scsi_Host *host = iscsi_job_to_shost(bsg_job);
501a355943cSVikas Chaudhary 	struct scsi_qla_host *ha = to_qla_host(host);
502a355943cSVikas Chaudhary 
503a355943cSVikas Chaudhary 	switch (bsg_req->msgcode) {
504a355943cSVikas Chaudhary 	case ISCSI_BSG_HST_VENDOR:
505a355943cSVikas Chaudhary 		return qla4xxx_process_vendor_specific(bsg_job);
506a355943cSVikas Chaudhary 
507a355943cSVikas Chaudhary 	default:
508a355943cSVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: invalid BSG command: 0x%x\n",
509a355943cSVikas Chaudhary 			   __func__, bsg_req->msgcode);
510a355943cSVikas Chaudhary 	}
511a355943cSVikas Chaudhary 
512a355943cSVikas Chaudhary 	return -ENOSYS;
513a355943cSVikas Chaudhary }
514