xref: /openbmc/linux/drivers/scsi/qla4xxx/ql4_bsg.c (revision a355943c)
1 /*
2  * QLogic iSCSI HBA Driver
3  * Copyright (c) 2011 QLogic Corporation
4  *
5  * See LICENSE.qla4xxx for copyright and licensing details.
6  */
7 
8 #include "ql4_def.h"
9 #include "ql4_glbl.h"
10 #include "ql4_bsg.h"
11 
12 static int
13 qla4xxx_read_flash(struct bsg_job *bsg_job)
14 {
15 	struct Scsi_Host *host = iscsi_job_to_shost(bsg_job);
16 	struct scsi_qla_host *ha = to_qla_host(host);
17 	struct iscsi_bsg_reply *bsg_reply = bsg_job->reply;
18 	struct iscsi_bsg_request *bsg_req = bsg_job->request;
19 	uint32_t sg_cnt;
20 	uint32_t offset = 0;
21 	uint32_t length = 0;
22 	dma_addr_t flash_dma;
23 	uint8_t *flash = NULL;
24 	int rval = 0;
25 
26 	bsg_reply->reply_payload_rcv_len = 0;
27 
28 	if (unlikely(pci_channel_offline(ha->pdev)))
29 		return -EINVAL;
30 
31 	if (ha->flash_state != QLFLASH_WAITING)
32 		return -EBUSY;
33 
34 	/* TODO: Add check for adapter online, reset active?? */
35 	sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
36 			    bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
37 
38 	if (!sg_cnt)
39 		return -ENOMEM;
40 
41 	if (sg_cnt != bsg_job->reply_payload.sg_cnt) {
42 		ql4_printk(KERN_ERR, ha, "dma mapping resulted in different"
43 			   " sg counts, sg_cnt: %x dma_sg_cnt: %x\n",
44 			   bsg_job->reply_payload.sg_cnt, sg_cnt);
45 		rval = -EAGAIN;
46 		goto unmap_sg;
47 	}
48 
49 	offset = bsg_req->rqst_data.h_vendor.vendor_cmd[1];
50 	length = bsg_job->reply_payload.payload_len;
51 
52 	flash = dma_alloc_coherent(&ha->pdev->dev, length, &flash_dma,
53 				   GFP_KERNEL);
54 	if (!flash) {
55 		ql4_printk(KERN_ERR, ha, "%s: dma alloc failed for flash "
56 			   "data\n", __func__);
57 		rval = -ENOMEM;
58 		goto unmap_sg;
59 	}
60 
61 	ha->flash_state = QLFLASH_READING;
62 	if (qla4xxx_get_flash(ha, flash_dma, offset, length))
63 		bsg_reply->result = (DID_ERROR << 16);
64 	else {
65 		sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
66 				    bsg_job->reply_payload.sg_cnt,
67 				    flash, length);
68 
69 		bsg_reply->result = DID_OK;
70 		bsg_reply->reply_payload_rcv_len = length;
71 	}
72 
73 	if (flash)
74 		dma_free_coherent(&ha->pdev->dev, length, flash, flash_dma);
75 
76 	ha->flash_state = QLFLASH_WAITING;
77 unmap_sg:
78 	dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
79 		     bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
80 	if (!rval)
81 		bsg_job_done(bsg_job, bsg_reply->result,
82 			     bsg_reply->reply_payload_rcv_len);
83 	return rval;
84 }
85 
86 static int
87 qla4xxx_update_flash(struct bsg_job *bsg_job)
88 {
89 	struct Scsi_Host *host = iscsi_job_to_shost(bsg_job);
90 	struct scsi_qla_host *ha = to_qla_host(host);
91 	struct iscsi_bsg_reply *bsg_reply = bsg_job->reply;
92 	struct iscsi_bsg_request *bsg_req = bsg_job->request;
93 	uint32_t sg_cnt;
94 	uint32_t length = 0;
95 	uint32_t offset = 0;
96 	uint32_t options = 0;
97 	dma_addr_t flash_dma;
98 	uint8_t *flash = NULL;
99 	int rval = 0;
100 
101 	bsg_reply->reply_payload_rcv_len = 0;
102 
103 	if (unlikely(pci_channel_offline(ha->pdev)))
104 		return -EINVAL;
105 
106 	if (ha->flash_state != QLFLASH_WAITING)
107 		return -EBUSY;
108 
109 	sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
110 			    bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
111 
112 	if (!sg_cnt)
113 		return -ENOMEM;
114 
115 	if (sg_cnt != bsg_job->request_payload.sg_cnt) {
116 		ql4_printk(KERN_ERR, ha, "dma mapping resulted in different "
117 			   "sg counts request_sg_cnt: %x dma_request_sg_cnt: "
118 			   "%x\n", bsg_job->request_payload.sg_cnt, sg_cnt);
119 		rval = -EAGAIN;
120 		goto unmap_sg;
121 	}
122 
123 	length = bsg_job->request_payload.payload_len;
124 	offset = bsg_req->rqst_data.h_vendor.vendor_cmd[1];
125 	options = bsg_req->rqst_data.h_vendor.vendor_cmd[2];
126 
127 	flash = dma_alloc_coherent(&ha->pdev->dev, length, &flash_dma,
128 				   GFP_KERNEL);
129 	if (!flash) {
130 		ql4_printk(KERN_ERR, ha, "%s: dma alloc failed for flash "
131 			   "data\n", __func__);
132 		rval = -ENOMEM;
133 		goto unmap_sg;
134 	}
135 
136 	ha->flash_state = QLFLASH_WRITING;
137 	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
138 			  bsg_job->request_payload.sg_cnt, flash, length);
139 
140 	if (qla4xxx_set_flash(ha, flash_dma, offset, length, options))
141 		bsg_reply->result = (DID_ERROR << 16);
142 	else {
143 		bsg_reply->result = DID_OK;
144 		bsg_reply->reply_payload_rcv_len = length;
145 	}
146 
147 	if (flash)
148 		dma_free_coherent(&ha->pdev->dev, length, flash, flash_dma);
149 	ha->flash_state = QLFLASH_WAITING;
150 unmap_sg:
151 	dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
152 		     bsg_job->reply_payload.sg_cnt, DMA_TO_DEVICE);
153 
154 	if (!rval)
155 		bsg_job_done(bsg_job, bsg_reply->result,
156 			     bsg_reply->reply_payload_rcv_len);
157 	return rval;
158 }
159 
160 /**
161  * qla4xxx_process_vendor_specific - handle vendor specific bsg request
162  * @job: iscsi_bsg_job to handle
163  **/
164 int qla4xxx_process_vendor_specific(struct bsg_job *bsg_job)
165 {
166 	struct iscsi_bsg_reply *bsg_reply = bsg_job->reply;
167 	struct iscsi_bsg_request *bsg_req = bsg_job->request;
168 	struct Scsi_Host *host = iscsi_job_to_shost(bsg_job);
169 	struct scsi_qla_host *ha = to_qla_host(host);
170 
171 	switch (bsg_req->rqst_data.h_vendor.vendor_cmd[0]) {
172 	case QLISCSI_VND_READ_FLASH:
173 		return qla4xxx_read_flash(bsg_job);
174 
175 	case QLISCSI_VND_UPDATE_FLASH:
176 		return qla4xxx_update_flash(bsg_job);
177 
178 	default:
179 		ql4_printk(KERN_ERR, ha, "%s: invalid BSG vendor command: "
180 			   "0x%x\n", __func__, bsg_req->msgcode);
181 		bsg_reply->result = (DID_ERROR << 16);
182 		bsg_reply->reply_payload_rcv_len = 0;
183 		bsg_job_done(bsg_job, bsg_reply->result,
184 			     bsg_reply->reply_payload_rcv_len);
185 		return -ENOSYS;
186 	}
187 }
188 
189 /**
190  * qla4xxx_bsg_request - handle bsg request from ISCSI transport
191  * @job: iscsi_bsg_job to handle
192  */
193 int qla4xxx_bsg_request(struct bsg_job *bsg_job)
194 {
195 	struct iscsi_bsg_request *bsg_req = bsg_job->request;
196 	struct Scsi_Host *host = iscsi_job_to_shost(bsg_job);
197 	struct scsi_qla_host *ha = to_qla_host(host);
198 
199 	switch (bsg_req->msgcode) {
200 	case ISCSI_BSG_HST_VENDOR:
201 		return qla4xxx_process_vendor_specific(bsg_job);
202 
203 	default:
204 		ql4_printk(KERN_ERR, ha, "%s: invalid BSG command: 0x%x\n",
205 			   __func__, bsg_req->msgcode);
206 	}
207 
208 	return -ENOSYS;
209 }
210