xref: /openbmc/linux/drivers/scsi/qla4xxx/ql4_bsg.c (revision ef7830bb)
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 
142a355943cSVikas Chaudhary /**
143a355943cSVikas Chaudhary  * qla4xxx_process_vendor_specific - handle vendor specific bsg request
144a355943cSVikas Chaudhary  * @job: iscsi_bsg_job to handle
145a355943cSVikas Chaudhary  **/
146a355943cSVikas Chaudhary int qla4xxx_process_vendor_specific(struct bsg_job *bsg_job)
147a355943cSVikas Chaudhary {
148a355943cSVikas Chaudhary 	struct iscsi_bsg_reply *bsg_reply = bsg_job->reply;
149a355943cSVikas Chaudhary 	struct iscsi_bsg_request *bsg_req = bsg_job->request;
150a355943cSVikas Chaudhary 	struct Scsi_Host *host = iscsi_job_to_shost(bsg_job);
151a355943cSVikas Chaudhary 	struct scsi_qla_host *ha = to_qla_host(host);
152a355943cSVikas Chaudhary 
153a355943cSVikas Chaudhary 	switch (bsg_req->rqst_data.h_vendor.vendor_cmd[0]) {
154a355943cSVikas Chaudhary 	case QLISCSI_VND_READ_FLASH:
155a355943cSVikas Chaudhary 		return qla4xxx_read_flash(bsg_job);
156a355943cSVikas Chaudhary 
157a355943cSVikas Chaudhary 	case QLISCSI_VND_UPDATE_FLASH:
158a355943cSVikas Chaudhary 		return qla4xxx_update_flash(bsg_job);
159a355943cSVikas Chaudhary 
160a355943cSVikas Chaudhary 	default:
161a355943cSVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: invalid BSG vendor command: "
162a355943cSVikas Chaudhary 			   "0x%x\n", __func__, bsg_req->msgcode);
163a355943cSVikas Chaudhary 		bsg_reply->result = (DID_ERROR << 16);
164a355943cSVikas Chaudhary 		bsg_reply->reply_payload_rcv_len = 0;
165a355943cSVikas Chaudhary 		bsg_job_done(bsg_job, bsg_reply->result,
166a355943cSVikas Chaudhary 			     bsg_reply->reply_payload_rcv_len);
167a355943cSVikas Chaudhary 		return -ENOSYS;
168a355943cSVikas Chaudhary 	}
169a355943cSVikas Chaudhary }
170a355943cSVikas Chaudhary 
171a355943cSVikas Chaudhary /**
172a355943cSVikas Chaudhary  * qla4xxx_bsg_request - handle bsg request from ISCSI transport
173a355943cSVikas Chaudhary  * @job: iscsi_bsg_job to handle
174a355943cSVikas Chaudhary  */
175a355943cSVikas Chaudhary int qla4xxx_bsg_request(struct bsg_job *bsg_job)
176a355943cSVikas Chaudhary {
177a355943cSVikas Chaudhary 	struct iscsi_bsg_request *bsg_req = bsg_job->request;
178a355943cSVikas Chaudhary 	struct Scsi_Host *host = iscsi_job_to_shost(bsg_job);
179a355943cSVikas Chaudhary 	struct scsi_qla_host *ha = to_qla_host(host);
180a355943cSVikas Chaudhary 
181a355943cSVikas Chaudhary 	switch (bsg_req->msgcode) {
182a355943cSVikas Chaudhary 	case ISCSI_BSG_HST_VENDOR:
183a355943cSVikas Chaudhary 		return qla4xxx_process_vendor_specific(bsg_job);
184a355943cSVikas Chaudhary 
185a355943cSVikas Chaudhary 	default:
186a355943cSVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: invalid BSG command: 0x%x\n",
187a355943cSVikas Chaudhary 			   __func__, bsg_req->msgcode);
188a355943cSVikas Chaudhary 	}
189a355943cSVikas Chaudhary 
190a355943cSVikas Chaudhary 	return -ENOSYS;
191a355943cSVikas Chaudhary }
192