aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/qla4xxx/ql4_bsg.c
diff options
context:
space:
mode:
authorVikas Chaudhary <vikas.chaudhary@qlogic.com>2011-07-25 14:48:51 -0400
committerJames Bottomley <JBottomley@Parallels.com>2011-08-27 10:36:22 -0400
commita355943ca847ca3a264d468e408217562234d019 (patch)
tree28aa660563b27a86427112137de818913d96a724 /drivers/scsi/qla4xxx/ql4_bsg.c
parent90eeb01a038e5fec0efdea4df008f3c18f67b82c (diff)
[SCSI] qla4xxx: add bsg support
This patch adds bsg support to qla4xxx. Signed-off-by: Vikas Chaudhary <vikas.chaudhary@qlogic.com> Signed-off-by: Harish Zunjarrao <harish.zunjarrao@qlogic.com> Signed-off-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.c209
1 files changed, 209 insertions, 0 deletions
diff --git a/drivers/scsi/qla4xxx/ql4_bsg.c b/drivers/scsi/qla4xxx/ql4_bsg.c
new file mode 100644
index 000000000000..daa2b0f8e309
--- /dev/null
+++ b/drivers/scsi/qla4xxx/ql4_bsg.c
@@ -0,0 +1,209 @@
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
12static int
13qla4xxx_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;
77unmap_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
86static int
87qla4xxx_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;
150unmap_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 **/
164int 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 */
193int 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}