diff options
author | Harish Zunjarrao <harish.zunjarrao@qlogic.com> | 2011-08-01 06:26:16 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2011-08-27 10:36:33 -0400 |
commit | 7c07d139cfec3172e813b468a8a173ad73bb5da9 (patch) | |
tree | b7c83b48845668b75d0efd4d7f4e3eb6fe8570e8 /drivers/scsi/qla4xxx/ql4_bsg.c | |
parent | 8b0402e1383cd51121f05a1d249cde0212c28c99 (diff) |
[SCSI] qla4xxx: Add read/update NVRAM support for 40xx adapters using BSG
Signed-off-by: Harish Zunjarrao <harish.zunjarrao@qlogic.com>
Signed-off-by: Vikas Chaudhary <vikas.chaudhary@qlogic.com>
Reviewed-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/qla4xxx/ql4_bsg.c')
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_bsg.c | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/drivers/scsi/qla4xxx/ql4_bsg.c b/drivers/scsi/qla4xxx/ql4_bsg.c index de4db299bfcb..c47545356f7b 100644 --- a/drivers/scsi/qla4xxx/ql4_bsg.c +++ b/drivers/scsi/qla4xxx/ql4_bsg.c | |||
@@ -196,6 +196,147 @@ leave: | |||
196 | return rval; | 196 | return rval; |
197 | } | 197 | } |
198 | 198 | ||
199 | static int | ||
200 | qla4xxx_read_nvram(struct bsg_job *bsg_job) | ||
201 | { | ||
202 | struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); | ||
203 | struct scsi_qla_host *ha = to_qla_host(host); | ||
204 | struct iscsi_bsg_request *bsg_req = bsg_job->request; | ||
205 | struct iscsi_bsg_reply *bsg_reply = bsg_job->reply; | ||
206 | uint32_t offset = 0; | ||
207 | uint32_t len = 0; | ||
208 | uint32_t total_len = 0; | ||
209 | dma_addr_t nvram_dma; | ||
210 | uint8_t *nvram = NULL; | ||
211 | int rval = -EINVAL; | ||
212 | |||
213 | bsg_reply->reply_payload_rcv_len = 0; | ||
214 | |||
215 | if (unlikely(pci_channel_offline(ha->pdev))) | ||
216 | goto leave; | ||
217 | |||
218 | /* Only 40xx adapters are supported */ | ||
219 | if (!(is_qla4010(ha) || is_qla4022(ha) || is_qla4032(ha))) | ||
220 | goto leave; | ||
221 | |||
222 | if (ql4xxx_reset_active(ha)) { | ||
223 | ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__); | ||
224 | rval = -EBUSY; | ||
225 | goto leave; | ||
226 | } | ||
227 | |||
228 | offset = bsg_req->rqst_data.h_vendor.vendor_cmd[1]; | ||
229 | len = bsg_job->reply_payload.payload_len; | ||
230 | total_len = offset + len; | ||
231 | |||
232 | /* total len should not be greater than max NVRAM size */ | ||
233 | if ((is_qla4010(ha) && total_len > QL4010_NVRAM_SIZE) || | ||
234 | ((is_qla4022(ha) || is_qla4032(ha)) && | ||
235 | total_len > QL40X2_NVRAM_SIZE)) { | ||
236 | ql4_printk(KERN_ERR, ha, "%s: offset+len greater than max" | ||
237 | " nvram size, offset=%d len=%d\n", | ||
238 | __func__, offset, len); | ||
239 | goto leave; | ||
240 | } | ||
241 | |||
242 | nvram = dma_alloc_coherent(&ha->pdev->dev, len, &nvram_dma, | ||
243 | GFP_KERNEL); | ||
244 | if (!nvram) { | ||
245 | ql4_printk(KERN_ERR, ha, "%s: dma alloc failed for nvram " | ||
246 | "data\n", __func__); | ||
247 | rval = -ENOMEM; | ||
248 | goto leave; | ||
249 | } | ||
250 | |||
251 | rval = qla4xxx_get_nvram(ha, nvram_dma, offset, len); | ||
252 | if (rval) { | ||
253 | ql4_printk(KERN_ERR, ha, "%s: get nvram failed\n", __func__); | ||
254 | bsg_reply->result = DID_ERROR << 16; | ||
255 | rval = -EIO; | ||
256 | } else { | ||
257 | bsg_reply->reply_payload_rcv_len = | ||
258 | sg_copy_from_buffer(bsg_job->reply_payload.sg_list, | ||
259 | bsg_job->reply_payload.sg_cnt, | ||
260 | nvram, len); | ||
261 | bsg_reply->result = DID_OK << 16; | ||
262 | } | ||
263 | |||
264 | bsg_job_done(bsg_job, bsg_reply->result, | ||
265 | bsg_reply->reply_payload_rcv_len); | ||
266 | dma_free_coherent(&ha->pdev->dev, len, nvram, nvram_dma); | ||
267 | leave: | ||
268 | return rval; | ||
269 | } | ||
270 | |||
271 | static int | ||
272 | qla4xxx_update_nvram(struct bsg_job *bsg_job) | ||
273 | { | ||
274 | struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); | ||
275 | struct scsi_qla_host *ha = to_qla_host(host); | ||
276 | struct iscsi_bsg_request *bsg_req = bsg_job->request; | ||
277 | struct iscsi_bsg_reply *bsg_reply = bsg_job->reply; | ||
278 | uint32_t offset = 0; | ||
279 | uint32_t len = 0; | ||
280 | uint32_t total_len = 0; | ||
281 | dma_addr_t nvram_dma; | ||
282 | uint8_t *nvram = NULL; | ||
283 | int rval = -EINVAL; | ||
284 | |||
285 | bsg_reply->reply_payload_rcv_len = 0; | ||
286 | |||
287 | if (unlikely(pci_channel_offline(ha->pdev))) | ||
288 | goto leave; | ||
289 | |||
290 | if (!(is_qla4010(ha) || is_qla4022(ha) || is_qla4032(ha))) | ||
291 | goto leave; | ||
292 | |||
293 | if (ql4xxx_reset_active(ha)) { | ||
294 | ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__); | ||
295 | rval = -EBUSY; | ||
296 | goto leave; | ||
297 | } | ||
298 | |||
299 | offset = bsg_req->rqst_data.h_vendor.vendor_cmd[1]; | ||
300 | len = bsg_job->request_payload.payload_len; | ||
301 | total_len = offset + len; | ||
302 | |||
303 | /* total len should not be greater than max NVRAM size */ | ||
304 | if ((is_qla4010(ha) && total_len > QL4010_NVRAM_SIZE) || | ||
305 | ((is_qla4022(ha) || is_qla4032(ha)) && | ||
306 | total_len > QL40X2_NVRAM_SIZE)) { | ||
307 | ql4_printk(KERN_ERR, ha, "%s: offset+len greater than max" | ||
308 | " nvram size, offset=%d len=%d\n", | ||
309 | __func__, offset, len); | ||
310 | goto leave; | ||
311 | } | ||
312 | |||
313 | nvram = dma_alloc_coherent(&ha->pdev->dev, len, &nvram_dma, | ||
314 | GFP_KERNEL); | ||
315 | if (!nvram) { | ||
316 | ql4_printk(KERN_ERR, ha, "%s: dma alloc failed for flash " | ||
317 | "data\n", __func__); | ||
318 | rval = -ENOMEM; | ||
319 | goto leave; | ||
320 | } | ||
321 | |||
322 | sg_copy_to_buffer(bsg_job->request_payload.sg_list, | ||
323 | bsg_job->request_payload.sg_cnt, nvram, len); | ||
324 | |||
325 | rval = qla4xxx_set_nvram(ha, nvram_dma, offset, len); | ||
326 | if (rval) { | ||
327 | ql4_printk(KERN_ERR, ha, "%s: set nvram failed\n", __func__); | ||
328 | bsg_reply->result = DID_ERROR << 16; | ||
329 | rval = -EIO; | ||
330 | } else | ||
331 | bsg_reply->result = DID_OK << 16; | ||
332 | |||
333 | bsg_job_done(bsg_job, bsg_reply->result, | ||
334 | bsg_reply->reply_payload_rcv_len); | ||
335 | dma_free_coherent(&ha->pdev->dev, len, nvram, nvram_dma); | ||
336 | leave: | ||
337 | return rval; | ||
338 | } | ||
339 | |||
199 | /** | 340 | /** |
200 | * qla4xxx_process_vendor_specific - handle vendor specific bsg request | 341 | * qla4xxx_process_vendor_specific - handle vendor specific bsg request |
201 | * @job: iscsi_bsg_job to handle | 342 | * @job: iscsi_bsg_job to handle |
@@ -217,6 +358,12 @@ int qla4xxx_process_vendor_specific(struct bsg_job *bsg_job) | |||
217 | case QLISCSI_VND_GET_ACB_STATE: | 358 | case QLISCSI_VND_GET_ACB_STATE: |
218 | return qla4xxx_get_acb_state(bsg_job); | 359 | return qla4xxx_get_acb_state(bsg_job); |
219 | 360 | ||
361 | case QLISCSI_VND_READ_NVRAM: | ||
362 | return qla4xxx_read_nvram(bsg_job); | ||
363 | |||
364 | case QLISCSI_VND_UPDATE_NVRAM: | ||
365 | return qla4xxx_update_nvram(bsg_job); | ||
366 | |||
220 | default: | 367 | default: |
221 | ql4_printk(KERN_ERR, ha, "%s: invalid BSG vendor command: " | 368 | ql4_printk(KERN_ERR, ha, "%s: invalid BSG vendor command: " |
222 | "0x%x\n", __func__, bsg_req->msgcode); | 369 | "0x%x\n", __func__, bsg_req->msgcode); |