aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/qla4xxx
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
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')
-rw-r--r--drivers/scsi/qla4xxx/Makefile2
-rw-r--r--drivers/scsi/qla4xxx/ql4_bsg.c209
-rw-r--r--drivers/scsi/qla4xxx/ql4_bsg.h14
-rw-r--r--drivers/scsi/qla4xxx/ql4_def.h8
-rw-r--r--drivers/scsi/qla4xxx/ql4_glbl.h4
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c2
6 files changed, 238 insertions, 1 deletions
diff --git a/drivers/scsi/qla4xxx/Makefile b/drivers/scsi/qla4xxx/Makefile
index 252523d7847e..5b44139ff43d 100644
--- a/drivers/scsi/qla4xxx/Makefile
+++ b/drivers/scsi/qla4xxx/Makefile
@@ -1,5 +1,5 @@
1qla4xxx-y := ql4_os.o ql4_init.o ql4_mbx.o ql4_iocb.o ql4_isr.o \ 1qla4xxx-y := ql4_os.o ql4_init.o ql4_mbx.o ql4_iocb.o ql4_isr.o \
2 ql4_nx.o ql4_nvram.o ql4_dbg.o ql4_attr.o 2 ql4_nx.o ql4_nvram.o ql4_dbg.o ql4_attr.o ql4_bsg.o
3 3
4obj-$(CONFIG_SCSI_QLA_ISCSI) += qla4xxx.o 4obj-$(CONFIG_SCSI_QLA_ISCSI) += qla4xxx.o
5 5
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}
diff --git a/drivers/scsi/qla4xxx/ql4_bsg.h b/drivers/scsi/qla4xxx/ql4_bsg.h
new file mode 100644
index 000000000000..5f6424ee6c1e
--- /dev/null
+++ b/drivers/scsi/qla4xxx/ql4_bsg.h
@@ -0,0 +1,14 @@
1/*
2 * QLogic iSCSI HBA Driver
3 * Copyright (c) 2011 QLogic Corporation
4 *
5 * See LICENSE.qla4xxx for copyright and licensing details.
6 */
7#ifndef __QL4_BSG_H
8#define __QL4_BSG_H
9
10/* BSG Vendor specific commands */
11#define QLISCSI_VND_READ_FLASH 1
12#define QLISCSI_VND_UPDATE_FLASH 2
13
14#endif
diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h
index 12db99280e04..b17f5c43bbe4 100644
--- a/drivers/scsi/qla4xxx/ql4_def.h
+++ b/drivers/scsi/qla4xxx/ql4_def.h
@@ -25,6 +25,7 @@
25#include <linux/interrupt.h> 25#include <linux/interrupt.h>
26#include <linux/mutex.h> 26#include <linux/mutex.h>
27#include <linux/aer.h> 27#include <linux/aer.h>
28#include <linux/bsg-lib.h>
28 29
29#include <net/tcp.h> 30#include <net/tcp.h>
30#include <scsi/scsi.h> 31#include <scsi/scsi.h>
@@ -33,6 +34,8 @@
33#include <scsi/scsi_cmnd.h> 34#include <scsi/scsi_cmnd.h>
34#include <scsi/scsi_transport.h> 35#include <scsi/scsi_transport.h>
35#include <scsi/scsi_transport_iscsi.h> 36#include <scsi/scsi_transport_iscsi.h>
37#include <scsi/scsi_bsg_iscsi.h>
38#include <scsi/scsi_netlink.h>
36 39
37#include "ql4_dbg.h" 40#include "ql4_dbg.h"
38#include "ql4_nx.h" 41#include "ql4_nx.h"
@@ -599,6 +602,11 @@ struct scsi_qla_host {
599 uint16_t bootload_minor; 602 uint16_t bootload_minor;
600 uint16_t bootload_patch; 603 uint16_t bootload_patch;
601 uint16_t bootload_build; 604 uint16_t bootload_build;
605
606 uint32_t flash_state;
607#define QLFLASH_WAITING 0
608#define QLFLASH_READING 1
609#define QLFLASH_WRITING 2
602}; 610};
603 611
604static inline int is_ipv4_enabled(struct scsi_qla_host *ha) 612static inline int is_ipv4_enabled(struct scsi_qla_host *ha)
diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h
index 786274c48313..77539ae00b83 100644
--- a/drivers/scsi/qla4xxx/ql4_glbl.h
+++ b/drivers/scsi/qla4xxx/ql4_glbl.h
@@ -151,6 +151,10 @@ void qla4_8xxx_need_qsnt_handler(struct scsi_qla_host *ha);
151void qla4_8xxx_clear_drv_active(struct scsi_qla_host *ha); 151void qla4_8xxx_clear_drv_active(struct scsi_qla_host *ha);
152void qla4_8xxx_set_drv_active(struct scsi_qla_host *ha); 152void qla4_8xxx_set_drv_active(struct scsi_qla_host *ha);
153 153
154/* BSG Functions */
155int qla4xxx_bsg_request(struct bsg_job *bsg_job);
156int qla4xxx_process_vendor_specific(struct bsg_job *bsg_job);
157
154extern int ql4xextended_error_logging; 158extern int ql4xextended_error_logging;
155extern int ql4xdontresethba; 159extern int ql4xdontresethba;
156extern int ql4xenablemsix; 160extern int ql4xenablemsix;
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index d5f9f60609b6..4e47bb1a85d1 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -131,6 +131,7 @@ static struct scsi_host_template qla4xxx_driver_template = {
131 131
132 .max_sectors = 0xFFFF, 132 .max_sectors = 0xFFFF,
133 .shost_attrs = qla4xxx_host_attrs, 133 .shost_attrs = qla4xxx_host_attrs,
134 .vendor_id = SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_QLOGIC,
134}; 135};
135 136
136static struct iscsi_transport qla4xxx_iscsi_transport = { 137static struct iscsi_transport qla4xxx_iscsi_transport = {
@@ -146,6 +147,7 @@ static struct iscsi_transport qla4xxx_iscsi_transport = {
146 .set_iface_param = qla4xxx_iface_set_param, 147 .set_iface_param = qla4xxx_iface_set_param,
147 .session_recovery_timedout = qla4xxx_recovery_timedout, 148 .session_recovery_timedout = qla4xxx_recovery_timedout,
148 .get_iface_param = qla4xxx_get_iface_param, 149 .get_iface_param = qla4xxx_get_iface_param,
150 .bsg_request = qla4xxx_bsg_request,
149}; 151};
150 152
151static struct scsi_transport_template *qla4xxx_scsi_transport; 153static struct scsi_transport_template *qla4xxx_scsi_transport;