diff options
author | Jing Huang <huangj@brocade.com> | 2009-09-23 20:46:15 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2009-10-02 10:47:40 -0400 |
commit | 7725ccfda59715ecf8f99e3b520a0b84cc2ea79e (patch) | |
tree | df76910891c6b92bf23c06c84955bf600c9d7573 /drivers/scsi/bfa/bfa_port.c | |
parent | 5415907af1f5ef80c95147bacbd321b0d4236dd5 (diff) |
[SCSI] bfa: Brocade BFA FC SCSI driver
Add new driver for Brocade Hardware
Signed-off-by: Jing Huang <huangj@brocade.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/bfa/bfa_port.c')
-rw-r--r-- | drivers/scsi/bfa/bfa_port.c | 460 |
1 files changed, 460 insertions, 0 deletions
diff --git a/drivers/scsi/bfa/bfa_port.c b/drivers/scsi/bfa/bfa_port.c new file mode 100644 index 00000000000..cab19028361 --- /dev/null +++ b/drivers/scsi/bfa/bfa_port.c | |||
@@ -0,0 +1,460 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. | ||
3 | * All rights reserved | ||
4 | * www.brocade.com | ||
5 | * | ||
6 | * Linux driver for Brocade Fibre Channel Host Bus Adapter. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License (GPL) Version 2 as | ||
10 | * published by the Free Software Foundation | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | */ | ||
17 | |||
18 | #include <defs/bfa_defs_port.h> | ||
19 | #include <cs/bfa_trc.h> | ||
20 | #include <cs/bfa_log.h> | ||
21 | #include <cs/bfa_debug.h> | ||
22 | #include <port/bfa_port.h> | ||
23 | #include <bfi/bfi.h> | ||
24 | #include <bfi/bfi_port.h> | ||
25 | #include <bfa_ioc.h> | ||
26 | #include <cna/bfa_cna_trcmod.h> | ||
27 | |||
28 | BFA_TRC_FILE(CNA, PORT); | ||
29 | |||
30 | #define bfa_ioc_portid(__ioc) ((__ioc)->port_id) | ||
31 | #define bfa_lpuid(__arg) bfa_ioc_portid(&(__arg)->ioc) | ||
32 | |||
33 | static void | ||
34 | bfa_port_stats_swap(struct bfa_port_s *port, union bfa_pport_stats_u *stats) | ||
35 | { | ||
36 | u32 *dip = (u32 *) stats; | ||
37 | u32 t0, t1; | ||
38 | int i; | ||
39 | |||
40 | for (i = 0; i < sizeof(union bfa_pport_stats_u) / sizeof(u32); | ||
41 | i += 2) { | ||
42 | t0 = dip[i]; | ||
43 | t1 = dip[i + 1]; | ||
44 | #ifdef __BIGENDIAN | ||
45 | dip[i] = bfa_os_ntohl(t0); | ||
46 | dip[i + 1] = bfa_os_ntohl(t1); | ||
47 | #else | ||
48 | dip[i] = bfa_os_ntohl(t1); | ||
49 | dip[i + 1] = bfa_os_ntohl(t0); | ||
50 | #endif | ||
51 | } | ||
52 | |||
53 | /** todo | ||
54 | * QoS stats r also swapped as 64bit; that structure also | ||
55 | * has to use 64 bit counters | ||
56 | */ | ||
57 | } | ||
58 | |||
59 | /** | ||
60 | * bfa_port_enable_isr() | ||
61 | * | ||
62 | * | ||
63 | * @param[in] port - Pointer to the port module | ||
64 | * status - Return status from the f/w | ||
65 | * | ||
66 | * @return void | ||
67 | */ | ||
68 | static void | ||
69 | bfa_port_enable_isr(struct bfa_port_s *port, bfa_status_t status) | ||
70 | { | ||
71 | bfa_assert(0); | ||
72 | } | ||
73 | |||
74 | /** | ||
75 | * bfa_port_disable_isr() | ||
76 | * | ||
77 | * | ||
78 | * @param[in] port - Pointer to the port module | ||
79 | * status - Return status from the f/w | ||
80 | * | ||
81 | * @return void | ||
82 | */ | ||
83 | static void | ||
84 | bfa_port_disable_isr(struct bfa_port_s *port, bfa_status_t status) | ||
85 | { | ||
86 | bfa_assert(0); | ||
87 | } | ||
88 | |||
89 | /** | ||
90 | * bfa_port_get_stats_isr() | ||
91 | * | ||
92 | * | ||
93 | * @param[in] port - Pointer to the Port module | ||
94 | * status - Return status from the f/w | ||
95 | * | ||
96 | * @return void | ||
97 | */ | ||
98 | static void | ||
99 | bfa_port_get_stats_isr(struct bfa_port_s *port, bfa_status_t status) | ||
100 | { | ||
101 | port->stats_status = status; | ||
102 | port->stats_busy = BFA_FALSE; | ||
103 | |||
104 | if (status == BFA_STATUS_OK) { | ||
105 | memcpy(port->stats, port->stats_dma.kva, | ||
106 | sizeof(union bfa_pport_stats_u)); | ||
107 | bfa_port_stats_swap(port, port->stats); | ||
108 | } | ||
109 | |||
110 | if (port->stats_cbfn) { | ||
111 | port->stats_cbfn(port->stats_cbarg, status); | ||
112 | port->stats_cbfn = NULL; | ||
113 | } | ||
114 | } | ||
115 | |||
116 | /** | ||
117 | * bfa_port_clear_stats_isr() | ||
118 | * | ||
119 | * | ||
120 | * @param[in] port - Pointer to the Port module | ||
121 | * status - Return status from the f/w | ||
122 | * | ||
123 | * @return void | ||
124 | */ | ||
125 | static void | ||
126 | bfa_port_clear_stats_isr(struct bfa_port_s *port, bfa_status_t status) | ||
127 | { | ||
128 | port->stats_status = status; | ||
129 | port->stats_busy = BFA_FALSE; | ||
130 | |||
131 | if (port->stats_cbfn) { | ||
132 | port->stats_cbfn(port->stats_cbarg, status); | ||
133 | port->stats_cbfn = NULL; | ||
134 | } | ||
135 | } | ||
136 | |||
137 | /** | ||
138 | * bfa_port_isr() | ||
139 | * | ||
140 | * | ||
141 | * @param[in] Pointer to the Port module data structure. | ||
142 | * | ||
143 | * @return void | ||
144 | */ | ||
145 | static void | ||
146 | bfa_port_isr(void *cbarg, struct bfi_mbmsg_s *m) | ||
147 | { | ||
148 | struct bfa_port_s *port = (struct bfa_port_s *)cbarg; | ||
149 | union bfi_port_i2h_msg_u *i2hmsg; | ||
150 | |||
151 | i2hmsg = (union bfi_port_i2h_msg_u *)m; | ||
152 | bfa_trc(port, m->mh.msg_id); | ||
153 | |||
154 | switch (m->mh.msg_id) { | ||
155 | case BFI_PORT_I2H_ENABLE_RSP: | ||
156 | if (port->endis_pending == BFA_FALSE) | ||
157 | break; | ||
158 | bfa_port_enable_isr(port, i2hmsg->enable_rsp.status); | ||
159 | break; | ||
160 | |||
161 | case BFI_PORT_I2H_DISABLE_RSP: | ||
162 | if (port->endis_pending == BFA_FALSE) | ||
163 | break; | ||
164 | bfa_port_disable_isr(port, i2hmsg->disable_rsp.status); | ||
165 | break; | ||
166 | |||
167 | case BFI_PORT_I2H_GET_STATS_RSP: | ||
168 | /* | ||
169 | * Stats busy flag is still set? (may be cmd timed out) | ||
170 | */ | ||
171 | if (port->stats_busy == BFA_FALSE) | ||
172 | break; | ||
173 | bfa_port_get_stats_isr(port, i2hmsg->getstats_rsp.status); | ||
174 | break; | ||
175 | |||
176 | case BFI_PORT_I2H_CLEAR_STATS_RSP: | ||
177 | if (port->stats_busy == BFA_FALSE) | ||
178 | break; | ||
179 | bfa_port_clear_stats_isr(port, i2hmsg->clearstats_rsp.status); | ||
180 | break; | ||
181 | |||
182 | default: | ||
183 | bfa_assert(0); | ||
184 | } | ||
185 | } | ||
186 | |||
187 | /** | ||
188 | * bfa_port_meminfo() | ||
189 | * | ||
190 | * | ||
191 | * @param[in] void | ||
192 | * | ||
193 | * @return Size of DMA region | ||
194 | */ | ||
195 | u32 | ||
196 | bfa_port_meminfo(void) | ||
197 | { | ||
198 | return BFA_ROUNDUP(sizeof(union bfa_pport_stats_u), BFA_DMA_ALIGN_SZ); | ||
199 | } | ||
200 | |||
201 | /** | ||
202 | * bfa_port_mem_claim() | ||
203 | * | ||
204 | * | ||
205 | * @param[in] port Port module pointer | ||
206 | * dma_kva Kernel Virtual Address of Port DMA Memory | ||
207 | * dma_pa Physical Address of Port DMA Memory | ||
208 | * | ||
209 | * @return void | ||
210 | */ | ||
211 | void | ||
212 | bfa_port_mem_claim(struct bfa_port_s *port, u8 *dma_kva, u64 dma_pa) | ||
213 | { | ||
214 | port->stats_dma.kva = dma_kva; | ||
215 | port->stats_dma.pa = dma_pa; | ||
216 | } | ||
217 | |||
218 | /** | ||
219 | * bfa_port_enable() | ||
220 | * | ||
221 | * Send the Port enable request to the f/w | ||
222 | * | ||
223 | * @param[in] Pointer to the Port module data structure. | ||
224 | * | ||
225 | * @return Status | ||
226 | */ | ||
227 | bfa_status_t | ||
228 | bfa_port_enable(struct bfa_port_s *port, bfa_port_endis_cbfn_t cbfn, | ||
229 | void *cbarg) | ||
230 | { | ||
231 | struct bfi_port_generic_req_s *m; | ||
232 | |||
233 | /** todo Not implemented */ | ||
234 | bfa_assert(0); | ||
235 | |||
236 | if (!bfa_ioc_is_operational(port->ioc)) { | ||
237 | bfa_trc(port, BFA_STATUS_IOC_FAILURE); | ||
238 | return BFA_STATUS_IOC_FAILURE; | ||
239 | } | ||
240 | |||
241 | if (port->endis_pending) { | ||
242 | bfa_trc(port, BFA_STATUS_DEVBUSY); | ||
243 | return BFA_STATUS_DEVBUSY; | ||
244 | } | ||
245 | |||
246 | m = (struct bfi_port_generic_req_s *)port->endis_mb.msg; | ||
247 | |||
248 | port->msgtag++; | ||
249 | port->endis_cbfn = cbfn; | ||
250 | port->endis_cbarg = cbarg; | ||
251 | port->endis_pending = BFA_TRUE; | ||
252 | |||
253 | bfi_h2i_set(m->mh, BFI_MC_PORT, BFI_PORT_H2I_ENABLE_REQ, | ||
254 | bfa_ioc_portid(port->ioc)); | ||
255 | bfa_ioc_mbox_queue(port->ioc, &port->endis_mb); | ||
256 | |||
257 | return BFA_STATUS_OK; | ||
258 | } | ||
259 | |||
260 | /** | ||
261 | * bfa_port_disable() | ||
262 | * | ||
263 | * Send the Port disable request to the f/w | ||
264 | * | ||
265 | * @param[in] Pointer to the Port module data structure. | ||
266 | * | ||
267 | * @return Status | ||
268 | */ | ||
269 | bfa_status_t | ||
270 | bfa_port_disable(struct bfa_port_s *port, bfa_port_endis_cbfn_t cbfn, | ||
271 | void *cbarg) | ||
272 | { | ||
273 | struct bfi_port_generic_req_s *m; | ||
274 | |||
275 | /** todo Not implemented */ | ||
276 | bfa_assert(0); | ||
277 | |||
278 | if (!bfa_ioc_is_operational(port->ioc)) { | ||
279 | bfa_trc(port, BFA_STATUS_IOC_FAILURE); | ||
280 | return BFA_STATUS_IOC_FAILURE; | ||
281 | } | ||
282 | |||
283 | if (port->endis_pending) { | ||
284 | bfa_trc(port, BFA_STATUS_DEVBUSY); | ||
285 | return BFA_STATUS_DEVBUSY; | ||
286 | } | ||
287 | |||
288 | m = (struct bfi_port_generic_req_s *)port->endis_mb.msg; | ||
289 | |||
290 | port->msgtag++; | ||
291 | port->endis_cbfn = cbfn; | ||
292 | port->endis_cbarg = cbarg; | ||
293 | port->endis_pending = BFA_TRUE; | ||
294 | |||
295 | bfi_h2i_set(m->mh, BFI_MC_PORT, BFI_PORT_H2I_DISABLE_REQ, | ||
296 | bfa_ioc_portid(port->ioc)); | ||
297 | bfa_ioc_mbox_queue(port->ioc, &port->endis_mb); | ||
298 | |||
299 | return BFA_STATUS_OK; | ||
300 | } | ||
301 | |||
302 | /** | ||
303 | * bfa_port_get_stats() | ||
304 | * | ||
305 | * Send the request to the f/w to fetch Port statistics. | ||
306 | * | ||
307 | * @param[in] Pointer to the Port module data structure. | ||
308 | * | ||
309 | * @return Status | ||
310 | */ | ||
311 | bfa_status_t | ||
312 | bfa_port_get_stats(struct bfa_port_s *port, union bfa_pport_stats_u *stats, | ||
313 | bfa_port_stats_cbfn_t cbfn, void *cbarg) | ||
314 | { | ||
315 | struct bfi_port_get_stats_req_s *m; | ||
316 | |||
317 | if (!bfa_ioc_is_operational(port->ioc)) { | ||
318 | bfa_trc(port, BFA_STATUS_IOC_FAILURE); | ||
319 | return BFA_STATUS_IOC_FAILURE; | ||
320 | } | ||
321 | |||
322 | if (port->stats_busy) { | ||
323 | bfa_trc(port, BFA_STATUS_DEVBUSY); | ||
324 | return BFA_STATUS_DEVBUSY; | ||
325 | } | ||
326 | |||
327 | m = (struct bfi_port_get_stats_req_s *)port->stats_mb.msg; | ||
328 | |||
329 | port->stats = stats; | ||
330 | port->stats_cbfn = cbfn; | ||
331 | port->stats_cbarg = cbarg; | ||
332 | port->stats_busy = BFA_TRUE; | ||
333 | bfa_dma_be_addr_set(m->dma_addr, port->stats_dma.pa); | ||
334 | |||
335 | bfi_h2i_set(m->mh, BFI_MC_PORT, BFI_PORT_H2I_GET_STATS_REQ, | ||
336 | bfa_ioc_portid(port->ioc)); | ||
337 | bfa_ioc_mbox_queue(port->ioc, &port->stats_mb); | ||
338 | |||
339 | return BFA_STATUS_OK; | ||
340 | } | ||
341 | |||
342 | /** | ||
343 | * bfa_port_clear_stats() | ||
344 | * | ||
345 | * | ||
346 | * @param[in] Pointer to the Port module data structure. | ||
347 | * | ||
348 | * @return Status | ||
349 | */ | ||
350 | bfa_status_t | ||
351 | bfa_port_clear_stats(struct bfa_port_s *port, bfa_port_stats_cbfn_t cbfn, | ||
352 | void *cbarg) | ||
353 | { | ||
354 | struct bfi_port_generic_req_s *m; | ||
355 | |||
356 | if (!bfa_ioc_is_operational(port->ioc)) { | ||
357 | bfa_trc(port, BFA_STATUS_IOC_FAILURE); | ||
358 | return BFA_STATUS_IOC_FAILURE; | ||
359 | } | ||
360 | |||
361 | if (port->stats_busy) { | ||
362 | bfa_trc(port, BFA_STATUS_DEVBUSY); | ||
363 | return BFA_STATUS_DEVBUSY; | ||
364 | } | ||
365 | |||
366 | m = (struct bfi_port_generic_req_s *)port->stats_mb.msg; | ||
367 | |||
368 | port->stats_cbfn = cbfn; | ||
369 | port->stats_cbarg = cbarg; | ||
370 | port->stats_busy = BFA_TRUE; | ||
371 | |||
372 | bfi_h2i_set(m->mh, BFI_MC_PORT, BFI_PORT_H2I_CLEAR_STATS_REQ, | ||
373 | bfa_ioc_portid(port->ioc)); | ||
374 | bfa_ioc_mbox_queue(port->ioc, &port->stats_mb); | ||
375 | |||
376 | return BFA_STATUS_OK; | ||
377 | } | ||
378 | |||
379 | /** | ||
380 | * bfa_port_hbfail() | ||
381 | * | ||
382 | * | ||
383 | * @param[in] Pointer to the Port module data structure. | ||
384 | * | ||
385 | * @return void | ||
386 | */ | ||
387 | void | ||
388 | bfa_port_hbfail(void *arg) | ||
389 | { | ||
390 | struct bfa_port_s *port = (struct bfa_port_s *)arg; | ||
391 | |||
392 | /* | ||
393 | * Fail any pending get_stats/clear_stats requests | ||
394 | */ | ||
395 | if (port->stats_busy) { | ||
396 | if (port->stats_cbfn) | ||
397 | port->stats_cbfn(port->dev, BFA_STATUS_FAILED); | ||
398 | port->stats_cbfn = NULL; | ||
399 | port->stats_busy = BFA_FALSE; | ||
400 | } | ||
401 | |||
402 | /* | ||
403 | * Clear any enable/disable is pending | ||
404 | */ | ||
405 | if (port->endis_pending) { | ||
406 | if (port->endis_cbfn) | ||
407 | port->endis_cbfn(port->dev, BFA_STATUS_FAILED); | ||
408 | port->endis_cbfn = NULL; | ||
409 | port->endis_pending = BFA_FALSE; | ||
410 | } | ||
411 | } | ||
412 | |||
413 | /** | ||
414 | * bfa_port_attach() | ||
415 | * | ||
416 | * | ||
417 | * @param[in] port - Pointer to the Port module data structure | ||
418 | * ioc - Pointer to the ioc module data structure | ||
419 | * dev - Pointer to the device driver module data structure | ||
420 | * The device driver specific mbox ISR functions have | ||
421 | * this pointer as one of the parameters. | ||
422 | * trcmod - | ||
423 | * logmod - | ||
424 | * | ||
425 | * @return void | ||
426 | */ | ||
427 | void | ||
428 | bfa_port_attach(struct bfa_port_s *port, struct bfa_ioc_s *ioc, void *dev, | ||
429 | struct bfa_trc_mod_s *trcmod, struct bfa_log_mod_s *logmod) | ||
430 | { | ||
431 | bfa_assert(port); | ||
432 | |||
433 | port->dev = dev; | ||
434 | port->ioc = ioc; | ||
435 | port->trcmod = trcmod; | ||
436 | port->logmod = logmod; | ||
437 | |||
438 | port->stats_busy = port->endis_pending = BFA_FALSE; | ||
439 | port->stats_cbfn = port->endis_cbfn = NULL; | ||
440 | |||
441 | bfa_ioc_mbox_regisr(port->ioc, BFI_MC_PORT, bfa_port_isr, port); | ||
442 | bfa_ioc_hbfail_init(&port->hbfail, bfa_port_hbfail, port); | ||
443 | bfa_ioc_hbfail_register(port->ioc, &port->hbfail); | ||
444 | |||
445 | bfa_trc(port, 0); | ||
446 | } | ||
447 | |||
448 | /** | ||
449 | * bfa_port_detach() | ||
450 | * | ||
451 | * | ||
452 | * @param[in] port - Pointer to the Port module data structure | ||
453 | * | ||
454 | * @return void | ||
455 | */ | ||
456 | void | ||
457 | bfa_port_detach(struct bfa_port_s *port) | ||
458 | { | ||
459 | bfa_trc(port, 0); | ||
460 | } | ||