diff options
author | Vikas Chaudhary <vikas.chaudhary@qlogic.com> | 2011-07-25 14:48:51 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2011-08-27 10:36:22 -0400 |
commit | a355943ca847ca3a264d468e408217562234d019 (patch) | |
tree | 28aa660563b27a86427112137de818913d96a724 /drivers/scsi/qla4xxx | |
parent | 90eeb01a038e5fec0efdea4df008f3c18f67b82c (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/Makefile | 2 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_bsg.c | 209 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_bsg.h | 14 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_def.h | 8 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_glbl.h | 4 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_os.c | 2 |
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 @@ | |||
1 | qla4xxx-y := ql4_os.o ql4_init.o ql4_mbx.o ql4_iocb.o ql4_isr.o \ | 1 | qla4xxx-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 | ||
4 | obj-$(CONFIG_SCSI_QLA_ISCSI) += qla4xxx.o | 4 | obj-$(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 | |||
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 | } | ||
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 | ||
604 | static inline int is_ipv4_enabled(struct scsi_qla_host *ha) | 612 | static 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); | |||
151 | void qla4_8xxx_clear_drv_active(struct scsi_qla_host *ha); | 151 | void qla4_8xxx_clear_drv_active(struct scsi_qla_host *ha); |
152 | void qla4_8xxx_set_drv_active(struct scsi_qla_host *ha); | 152 | void qla4_8xxx_set_drv_active(struct scsi_qla_host *ha); |
153 | 153 | ||
154 | /* BSG Functions */ | ||
155 | int qla4xxx_bsg_request(struct bsg_job *bsg_job); | ||
156 | int qla4xxx_process_vendor_specific(struct bsg_job *bsg_job); | ||
157 | |||
154 | extern int ql4xextended_error_logging; | 158 | extern int ql4xextended_error_logging; |
155 | extern int ql4xdontresethba; | 159 | extern int ql4xdontresethba; |
156 | extern int ql4xenablemsix; | 160 | extern 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 | ||
136 | static struct iscsi_transport qla4xxx_iscsi_transport = { | 137 | static 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 | ||
151 | static struct scsi_transport_template *qla4xxx_scsi_transport; | 153 | static struct scsi_transport_template *qla4xxx_scsi_transport; |