diff options
Diffstat (limited to 'drivers/scsi/bfa/bfa_uf.c')
-rw-r--r-- | drivers/scsi/bfa/bfa_uf.c | 345 |
1 files changed, 345 insertions, 0 deletions
diff --git a/drivers/scsi/bfa/bfa_uf.c b/drivers/scsi/bfa/bfa_uf.c new file mode 100644 index 000000000000..ff5f9deb1b22 --- /dev/null +++ b/drivers/scsi/bfa/bfa_uf.c | |||
@@ -0,0 +1,345 @@ | |||
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 | /** | ||
19 | * bfa_uf.c BFA unsolicited frame receive implementation | ||
20 | */ | ||
21 | |||
22 | #include <bfa.h> | ||
23 | #include <bfa_svc.h> | ||
24 | #include <bfi/bfi_uf.h> | ||
25 | #include <cs/bfa_debug.h> | ||
26 | |||
27 | BFA_TRC_FILE(HAL, UF); | ||
28 | BFA_MODULE(uf); | ||
29 | |||
30 | /* | ||
31 | ***************************************************************************** | ||
32 | * Internal functions | ||
33 | ***************************************************************************** | ||
34 | */ | ||
35 | static void | ||
36 | __bfa_cb_uf_recv(void *cbarg, bfa_boolean_t complete) | ||
37 | { | ||
38 | struct bfa_uf_s *uf = cbarg; | ||
39 | struct bfa_uf_mod_s *ufm = BFA_UF_MOD(uf->bfa); | ||
40 | |||
41 | if (complete) | ||
42 | ufm->ufrecv(ufm->cbarg, uf); | ||
43 | } | ||
44 | |||
45 | static void | ||
46 | claim_uf_pbs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi) | ||
47 | { | ||
48 | u32 uf_pb_tot_sz; | ||
49 | |||
50 | ufm->uf_pbs_kva = (struct bfa_uf_buf_s *) bfa_meminfo_dma_virt(mi); | ||
51 | ufm->uf_pbs_pa = bfa_meminfo_dma_phys(mi); | ||
52 | uf_pb_tot_sz = BFA_ROUNDUP((sizeof(struct bfa_uf_buf_s) * ufm->num_ufs), | ||
53 | BFA_DMA_ALIGN_SZ); | ||
54 | |||
55 | bfa_meminfo_dma_virt(mi) += uf_pb_tot_sz; | ||
56 | bfa_meminfo_dma_phys(mi) += uf_pb_tot_sz; | ||
57 | |||
58 | bfa_os_memset((void *)ufm->uf_pbs_kva, 0, uf_pb_tot_sz); | ||
59 | } | ||
60 | |||
61 | static void | ||
62 | claim_uf_post_msgs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi) | ||
63 | { | ||
64 | struct bfi_uf_buf_post_s *uf_bp_msg; | ||
65 | struct bfi_sge_s *sge; | ||
66 | union bfi_addr_u sga_zero = { {0} }; | ||
67 | u16 i; | ||
68 | u16 buf_len; | ||
69 | |||
70 | ufm->uf_buf_posts = (struct bfi_uf_buf_post_s *) bfa_meminfo_kva(mi); | ||
71 | uf_bp_msg = ufm->uf_buf_posts; | ||
72 | |||
73 | for (i = 0, uf_bp_msg = ufm->uf_buf_posts; i < ufm->num_ufs; | ||
74 | i++, uf_bp_msg++) { | ||
75 | bfa_os_memset(uf_bp_msg, 0, sizeof(struct bfi_uf_buf_post_s)); | ||
76 | |||
77 | uf_bp_msg->buf_tag = i; | ||
78 | buf_len = sizeof(struct bfa_uf_buf_s); | ||
79 | uf_bp_msg->buf_len = bfa_os_htons(buf_len); | ||
80 | bfi_h2i_set(uf_bp_msg->mh, BFI_MC_UF, BFI_UF_H2I_BUF_POST, | ||
81 | bfa_lpuid(ufm->bfa)); | ||
82 | |||
83 | sge = uf_bp_msg->sge; | ||
84 | sge[0].sg_len = buf_len; | ||
85 | sge[0].flags = BFI_SGE_DATA_LAST; | ||
86 | bfa_dma_addr_set(sge[0].sga, ufm_pbs_pa(ufm, i)); | ||
87 | bfa_sge_to_be(sge); | ||
88 | |||
89 | sge[1].sg_len = buf_len; | ||
90 | sge[1].flags = BFI_SGE_PGDLEN; | ||
91 | sge[1].sga = sga_zero; | ||
92 | bfa_sge_to_be(&sge[1]); | ||
93 | } | ||
94 | |||
95 | /** | ||
96 | * advance pointer beyond consumed memory | ||
97 | */ | ||
98 | bfa_meminfo_kva(mi) = (u8 *) uf_bp_msg; | ||
99 | } | ||
100 | |||
101 | static void | ||
102 | claim_ufs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi) | ||
103 | { | ||
104 | u16 i; | ||
105 | struct bfa_uf_s *uf; | ||
106 | |||
107 | /* | ||
108 | * Claim block of memory for UF list | ||
109 | */ | ||
110 | ufm->uf_list = (struct bfa_uf_s *) bfa_meminfo_kva(mi); | ||
111 | |||
112 | /* | ||
113 | * Initialize UFs and queue it in UF free queue | ||
114 | */ | ||
115 | for (i = 0, uf = ufm->uf_list; i < ufm->num_ufs; i++, uf++) { | ||
116 | bfa_os_memset(uf, 0, sizeof(struct bfa_uf_s)); | ||
117 | uf->bfa = ufm->bfa; | ||
118 | uf->uf_tag = i; | ||
119 | uf->pb_len = sizeof(struct bfa_uf_buf_s); | ||
120 | uf->buf_kva = (void *)&ufm->uf_pbs_kva[i]; | ||
121 | uf->buf_pa = ufm_pbs_pa(ufm, i); | ||
122 | list_add_tail(&uf->qe, &ufm->uf_free_q); | ||
123 | } | ||
124 | |||
125 | /** | ||
126 | * advance memory pointer | ||
127 | */ | ||
128 | bfa_meminfo_kva(mi) = (u8 *) uf; | ||
129 | } | ||
130 | |||
131 | static void | ||
132 | uf_mem_claim(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi) | ||
133 | { | ||
134 | claim_uf_pbs(ufm, mi); | ||
135 | claim_ufs(ufm, mi); | ||
136 | claim_uf_post_msgs(ufm, mi); | ||
137 | } | ||
138 | |||
139 | static void | ||
140 | bfa_uf_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, u32 *dm_len) | ||
141 | { | ||
142 | u32 num_ufs = cfg->fwcfg.num_uf_bufs; | ||
143 | |||
144 | /* | ||
145 | * dma-able memory for UF posted bufs | ||
146 | */ | ||
147 | *dm_len += BFA_ROUNDUP((sizeof(struct bfa_uf_buf_s) * num_ufs), | ||
148 | BFA_DMA_ALIGN_SZ); | ||
149 | |||
150 | /* | ||
151 | * kernel Virtual memory for UFs and UF buf post msg copies | ||
152 | */ | ||
153 | *ndm_len += sizeof(struct bfa_uf_s) * num_ufs; | ||
154 | *ndm_len += sizeof(struct bfi_uf_buf_post_s) * num_ufs; | ||
155 | } | ||
156 | |||
157 | static void | ||
158 | bfa_uf_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, | ||
159 | struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) | ||
160 | { | ||
161 | struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa); | ||
162 | |||
163 | bfa_os_memset(ufm, 0, sizeof(struct bfa_uf_mod_s)); | ||
164 | ufm->bfa = bfa; | ||
165 | ufm->num_ufs = cfg->fwcfg.num_uf_bufs; | ||
166 | INIT_LIST_HEAD(&ufm->uf_free_q); | ||
167 | INIT_LIST_HEAD(&ufm->uf_posted_q); | ||
168 | |||
169 | uf_mem_claim(ufm, meminfo); | ||
170 | } | ||
171 | |||
172 | static void | ||
173 | bfa_uf_initdone(struct bfa_s *bfa) | ||
174 | { | ||
175 | } | ||
176 | |||
177 | static void | ||
178 | bfa_uf_detach(struct bfa_s *bfa) | ||
179 | { | ||
180 | } | ||
181 | |||
182 | static struct bfa_uf_s * | ||
183 | bfa_uf_get(struct bfa_uf_mod_s *uf_mod) | ||
184 | { | ||
185 | struct bfa_uf_s *uf; | ||
186 | |||
187 | bfa_q_deq(&uf_mod->uf_free_q, &uf); | ||
188 | return (uf); | ||
189 | } | ||
190 | |||
191 | static void | ||
192 | bfa_uf_put(struct bfa_uf_mod_s *uf_mod, struct bfa_uf_s *uf) | ||
193 | { | ||
194 | list_add_tail(&uf->qe, &uf_mod->uf_free_q); | ||
195 | } | ||
196 | |||
197 | static bfa_status_t | ||
198 | bfa_uf_post(struct bfa_uf_mod_s *ufm, struct bfa_uf_s *uf) | ||
199 | { | ||
200 | struct bfi_uf_buf_post_s *uf_post_msg; | ||
201 | |||
202 | uf_post_msg = bfa_reqq_next(ufm->bfa, BFA_REQQ_FCXP); | ||
203 | if (!uf_post_msg) | ||
204 | return BFA_STATUS_FAILED; | ||
205 | |||
206 | bfa_os_memcpy(uf_post_msg, &ufm->uf_buf_posts[uf->uf_tag], | ||
207 | sizeof(struct bfi_uf_buf_post_s)); | ||
208 | bfa_reqq_produce(ufm->bfa, BFA_REQQ_FCXP); | ||
209 | |||
210 | bfa_trc(ufm->bfa, uf->uf_tag); | ||
211 | |||
212 | list_add_tail(&uf->qe, &ufm->uf_posted_q); | ||
213 | return BFA_STATUS_OK; | ||
214 | } | ||
215 | |||
216 | static void | ||
217 | bfa_uf_post_all(struct bfa_uf_mod_s *uf_mod) | ||
218 | { | ||
219 | struct bfa_uf_s *uf; | ||
220 | |||
221 | while ((uf = bfa_uf_get(uf_mod)) != NULL) { | ||
222 | if (bfa_uf_post(uf_mod, uf) != BFA_STATUS_OK) | ||
223 | break; | ||
224 | } | ||
225 | } | ||
226 | |||
227 | static void | ||
228 | uf_recv(struct bfa_s *bfa, struct bfi_uf_frm_rcvd_s *m) | ||
229 | { | ||
230 | struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa); | ||
231 | u16 uf_tag = m->buf_tag; | ||
232 | struct bfa_uf_buf_s *uf_buf = &ufm->uf_pbs_kva[uf_tag]; | ||
233 | struct bfa_uf_s *uf = &ufm->uf_list[uf_tag]; | ||
234 | u8 *buf = &uf_buf->d[0]; | ||
235 | struct fchs_s *fchs; | ||
236 | |||
237 | m->frm_len = bfa_os_ntohs(m->frm_len); | ||
238 | m->xfr_len = bfa_os_ntohs(m->xfr_len); | ||
239 | |||
240 | fchs = (struct fchs_s *) uf_buf; | ||
241 | |||
242 | list_del(&uf->qe); /* dequeue from posted queue */ | ||
243 | |||
244 | uf->data_ptr = buf; | ||
245 | uf->data_len = m->xfr_len; | ||
246 | |||
247 | bfa_assert(uf->data_len >= sizeof(struct fchs_s)); | ||
248 | |||
249 | if (uf->data_len == sizeof(struct fchs_s)) { | ||
250 | bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_UF, BFA_PL_EID_RX, | ||
251 | uf->data_len, (struct fchs_s *) buf); | ||
252 | } else { | ||
253 | u32 pld_w0 = *((u32 *) (buf + sizeof(struct fchs_s))); | ||
254 | bfa_plog_fchdr_and_pl(bfa->plog, BFA_PL_MID_HAL_UF, | ||
255 | BFA_PL_EID_RX, uf->data_len, | ||
256 | (struct fchs_s *) buf, pld_w0); | ||
257 | } | ||
258 | |||
259 | bfa_cb_queue(bfa, &uf->hcb_qe, __bfa_cb_uf_recv, uf); | ||
260 | } | ||
261 | |||
262 | static void | ||
263 | bfa_uf_stop(struct bfa_s *bfa) | ||
264 | { | ||
265 | } | ||
266 | |||
267 | static void | ||
268 | bfa_uf_iocdisable(struct bfa_s *bfa) | ||
269 | { | ||
270 | struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa); | ||
271 | struct bfa_uf_s *uf; | ||
272 | struct list_head *qe, *qen; | ||
273 | |||
274 | list_for_each_safe(qe, qen, &ufm->uf_posted_q) { | ||
275 | uf = (struct bfa_uf_s *) qe; | ||
276 | list_del(&uf->qe); | ||
277 | bfa_uf_put(ufm, uf); | ||
278 | } | ||
279 | } | ||
280 | |||
281 | static void | ||
282 | bfa_uf_start(struct bfa_s *bfa) | ||
283 | { | ||
284 | bfa_uf_post_all(BFA_UF_MOD(bfa)); | ||
285 | } | ||
286 | |||
287 | |||
288 | |||
289 | /** | ||
290 | * bfa_uf_api | ||
291 | */ | ||
292 | |||
293 | /** | ||
294 | * Register handler for all unsolicted recieve frames. | ||
295 | * | ||
296 | * @param[in] bfa BFA instance | ||
297 | * @param[in] ufrecv receive handler function | ||
298 | * @param[in] cbarg receive handler arg | ||
299 | */ | ||
300 | void | ||
301 | bfa_uf_recv_register(struct bfa_s *bfa, bfa_cb_uf_recv_t ufrecv, void *cbarg) | ||
302 | { | ||
303 | struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa); | ||
304 | |||
305 | ufm->ufrecv = ufrecv; | ||
306 | ufm->cbarg = cbarg; | ||
307 | } | ||
308 | |||
309 | /** | ||
310 | * Free an unsolicited frame back to BFA. | ||
311 | * | ||
312 | * @param[in] uf unsolicited frame to be freed | ||
313 | * | ||
314 | * @return None | ||
315 | */ | ||
316 | void | ||
317 | bfa_uf_free(struct bfa_uf_s *uf) | ||
318 | { | ||
319 | bfa_uf_put(BFA_UF_MOD(uf->bfa), uf); | ||
320 | bfa_uf_post_all(BFA_UF_MOD(uf->bfa)); | ||
321 | } | ||
322 | |||
323 | |||
324 | |||
325 | /** | ||
326 | * uf_pub BFA uf module public functions | ||
327 | */ | ||
328 | |||
329 | void | ||
330 | bfa_uf_isr(struct bfa_s *bfa, struct bfi_msg_s *msg) | ||
331 | { | ||
332 | bfa_trc(bfa, msg->mhdr.msg_id); | ||
333 | |||
334 | switch (msg->mhdr.msg_id) { | ||
335 | case BFI_UF_I2H_FRM_RCVD: | ||
336 | uf_recv(bfa, (struct bfi_uf_frm_rcvd_s *) msg); | ||
337 | break; | ||
338 | |||
339 | default: | ||
340 | bfa_trc(bfa, msg->mhdr.msg_id); | ||
341 | bfa_assert(0); | ||
342 | } | ||
343 | } | ||
344 | |||
345 | |||