1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at
9 * http://www.opensource.org/licenses/cddl1.txt.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2004-2011 Emulex. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include <emlxs.h>
28
29 /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
30 EMLXS_MSG_DEF(EMLXS_PKT_C);
31
32 #if (EMLXS_MODREV >= EMLXS_MODREV3)
33 typedef struct
34 {
35 ddi_dma_cookie_t pkt_cmd_cookie;
36 ddi_dma_cookie_t pkt_resp_cookie;
37 ddi_dma_cookie_t pkt_data_cookie;
38
39 } emlxs_pkt_cookie_t;
40 #endif /* >= EMLXS_MODREV3 */
41
42
43 /* ARGSUSED */
44 static void
emlxs_pkt_thread(emlxs_hba_t * hba,void * arg1,void * arg2)45 emlxs_pkt_thread(emlxs_hba_t *hba, void *arg1, void *arg2)
46 {
47 emlxs_port_t *port;
48 fc_packet_t *pkt = (fc_packet_t *)arg1;
49 int32_t rval;
50 emlxs_buf_t *sbp;
51
52 sbp = PKT2PRIV(pkt);
53 port = sbp->port;
54
55 /* Send the pkt now */
56 rval = emlxs_pkt_send(pkt, 1);
57
58 if (rval != FC_SUCCESS) {
59 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_trans_msg,
60 "Deferred pkt_send failed: status=%x pkt=%p", rval,
61 pkt);
62
63 if (pkt->pkt_comp) {
64 emlxs_set_pkt_state(sbp, IOSTAT_LOCAL_REJECT, 0, 1);
65
66 ((CHANNEL *)sbp->channel)->ulpCmplCmd++;
67 (*pkt->pkt_comp) (pkt);
68 } else {
69 emlxs_pkt_free(pkt);
70 }
71 }
72
73 return;
74
75 } /* emlxs_pkt_thread() */
76
77
78 extern int32_t
emlxs_pkt_send(fc_packet_t * pkt,uint32_t now)79 emlxs_pkt_send(fc_packet_t *pkt, uint32_t now)
80 {
81 emlxs_port_t *port = (emlxs_port_t *)pkt->pkt_ulp_private;
82 emlxs_hba_t *hba = HBA;
83 int32_t rval;
84
85 if (now) {
86 rval = emlxs_fca_transport((opaque_t)port, pkt);
87 } else {
88 /* Spawn a thread to send the pkt */
89 emlxs_thread_spawn(hba, emlxs_pkt_thread, (char *)pkt, NULL);
90
91 rval = FC_SUCCESS;
92 }
93
94 return (rval);
95
96 } /* emlxs_pkt_send() */
97
98
99 extern void
emlxs_pkt_free(fc_packet_t * pkt)100 emlxs_pkt_free(fc_packet_t *pkt)
101 {
102 emlxs_port_t *port = (emlxs_port_t *)pkt->pkt_ulp_private;
103
104 (void) emlxs_fca_pkt_uninit((opaque_t)port, pkt);
105
106 if (pkt->pkt_datalen) {
107 (void) ddi_dma_unbind_handle(pkt->pkt_data_dma);
108 (void) ddi_dma_mem_free(&pkt->pkt_data_acc);
109 (void) ddi_dma_free_handle(&pkt->pkt_data_dma);
110 }
111
112 if (pkt->pkt_rsplen) {
113 (void) ddi_dma_unbind_handle(pkt->pkt_resp_dma);
114 (void) ddi_dma_mem_free(&pkt->pkt_resp_acc);
115 (void) ddi_dma_free_handle(&pkt->pkt_resp_dma);
116 }
117
118 if (pkt->pkt_cmdlen) {
119 (void) ddi_dma_unbind_handle(pkt->pkt_cmd_dma);
120 (void) ddi_dma_mem_free(&pkt->pkt_cmd_acc);
121 (void) ddi_dma_free_handle(&pkt->pkt_cmd_dma);
122 }
123 #if (EMLXS_MODREV >= EMLXS_MODREV3)
124 kmem_free(pkt, (sizeof (fc_packet_t) + sizeof (emlxs_buf_t) +
125 sizeof (emlxs_pkt_cookie_t)));
126 #else
127 kmem_free(pkt, (sizeof (fc_packet_t) + sizeof (emlxs_buf_t)));
128 #endif /* >= EMLXS_MODREV3 */
129
130 return;
131
132 } /* emlxs_pkt_free() */
133
134
135 /* Default pkt callback routine */
136 extern void
emlxs_pkt_callback(fc_packet_t * pkt)137 emlxs_pkt_callback(fc_packet_t *pkt)
138 {
139 emlxs_pkt_free(pkt);
140
141 return;
142
143 } /* emlxs_pkt_callback() */
144
145
146
147 extern fc_packet_t *
emlxs_pkt_alloc(emlxs_port_t * port,uint32_t cmdlen,uint32_t rsplen,uint32_t datalen,int32_t sleep)148 emlxs_pkt_alloc(emlxs_port_t *port, uint32_t cmdlen, uint32_t rsplen,
149 uint32_t datalen, int32_t sleep)
150 {
151 emlxs_hba_t *hba = HBA;
152 fc_packet_t *pkt;
153 int32_t(*cb) (caddr_t);
154 unsigned long real_len;
155 uint32_t pkt_size;
156 emlxs_buf_t *sbp;
157
158 #if (EMLXS_MODREV >= EMLXS_MODREV3)
159 emlxs_pkt_cookie_t *pkt_cookie;
160
161 pkt_size =
162 sizeof (fc_packet_t) + sizeof (emlxs_buf_t) +
163 sizeof (emlxs_pkt_cookie_t);
164 #else
165 uint32_t num_cookie;
166
167 pkt_size = sizeof (fc_packet_t) + sizeof (emlxs_buf_t);
168 #endif /* >= EMLXS_MODREV3 */
169
170
171 /* Allocate some space */
172 if (!(pkt = (fc_packet_t *)kmem_alloc(pkt_size, sleep))) {
173 return (NULL);
174 }
175
176 bzero(pkt, pkt_size);
177
178 cb = (sleep == KM_SLEEP) ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT;
179
180 pkt->pkt_ulp_private = (opaque_t)port;
181 pkt->pkt_fca_private =
182 (opaque_t)((uintptr_t)pkt + sizeof (fc_packet_t));
183 pkt->pkt_comp = emlxs_pkt_callback;
184 pkt->pkt_tran_flags = (FC_TRAN_CLASS3 | FC_TRAN_INTR);
185 pkt->pkt_cmdlen = cmdlen;
186 pkt->pkt_rsplen = rsplen;
187 pkt->pkt_datalen = datalen;
188
189 #if (EMLXS_MODREV >= EMLXS_MODREV3)
190 pkt_cookie =
191 (emlxs_pkt_cookie_t *)((uintptr_t)pkt + sizeof (fc_packet_t) +
192 sizeof (emlxs_buf_t));
193 pkt->pkt_cmd_cookie = &pkt_cookie->pkt_cmd_cookie;
194 pkt->pkt_resp_cookie = &pkt_cookie->pkt_resp_cookie;
195 pkt->pkt_data_cookie = &pkt_cookie->pkt_data_cookie;
196 #endif /* >= EMLXS_MODREV3 */
197
198 if (cmdlen) {
199 /* Allocate the cmd buf */
200 if (ddi_dma_alloc_handle(hba->dip, &hba->dma_attr_1sg, cb,
201 NULL, &pkt->pkt_cmd_dma) != DDI_SUCCESS) {
202 cmdlen = 0;
203 rsplen = 0;
204 datalen = 0;
205 goto failed;
206 }
207
208 if (ddi_dma_mem_alloc(pkt->pkt_cmd_dma, cmdlen,
209 &emlxs_data_acc_attr, DDI_DMA_CONSISTENT, cb, NULL,
210 (caddr_t *)&pkt->pkt_cmd, &real_len,
211 &pkt->pkt_cmd_acc) != DDI_SUCCESS) {
212 (void) ddi_dma_free_handle(&pkt->pkt_cmd_dma);
213
214 cmdlen = 0;
215 rsplen = 0;
216 datalen = 0;
217 goto failed;
218 }
219
220 if (real_len < cmdlen) {
221 (void) ddi_dma_mem_free(&pkt->pkt_cmd_acc);
222 (void) ddi_dma_free_handle(&pkt->pkt_cmd_dma);
223
224 cmdlen = 0;
225 rsplen = 0;
226 datalen = 0;
227 goto failed;
228 }
229 #if (EMLXS_MODREV >= EMLXS_MODREV3)
230 if (ddi_dma_addr_bind_handle(pkt->pkt_cmd_dma, NULL,
231 pkt->pkt_cmd, real_len,
232 DDI_DMA_WRITE | DDI_DMA_CONSISTENT, cb, NULL,
233 pkt->pkt_cmd_cookie,
234 &pkt->pkt_cmd_cookie_cnt) != DDI_DMA_MAPPED)
235 #else
236 if (ddi_dma_addr_bind_handle(pkt->pkt_cmd_dma, NULL,
237 pkt->pkt_cmd, real_len,
238 DDI_DMA_WRITE | DDI_DMA_CONSISTENT, cb, NULL,
239 &pkt->pkt_cmd_cookie, &num_cookie) != DDI_DMA_MAPPED)
240 #endif /* >= EMLXS_MODREV3 */
241 {
242 (void) ddi_dma_mem_free(&pkt->pkt_cmd_acc);
243 (void) ddi_dma_free_handle(&pkt->pkt_cmd_dma);
244
245 cmdlen = 0;
246 rsplen = 0;
247 datalen = 0;
248 goto failed;
249 }
250 #if (EMLXS_MODREV >= EMLXS_MODREV3)
251 if (pkt->pkt_cmd_cookie_cnt != 1)
252 #else
253 if (num_cookie != 1)
254 #endif /* >= EMLXS_MODREV3 */
255 {
256 rsplen = 0;
257 datalen = 0;
258 goto failed;
259 }
260
261 bzero(pkt->pkt_cmd, cmdlen);
262
263 }
264
265 if (rsplen) {
266 /* Allocate the rsp buf */
267 if (ddi_dma_alloc_handle(hba->dip, &hba->dma_attr_1sg, cb,
268 NULL, &pkt->pkt_resp_dma) != DDI_SUCCESS) {
269 rsplen = 0;
270 datalen = 0;
271 goto failed;
272
273 }
274
275 if (ddi_dma_mem_alloc(pkt->pkt_resp_dma, rsplen,
276 &emlxs_data_acc_attr, DDI_DMA_CONSISTENT, cb, NULL,
277 (caddr_t *)&pkt->pkt_resp, &real_len,
278 &pkt->pkt_resp_acc) != DDI_SUCCESS) {
279 (void) ddi_dma_free_handle(&pkt->pkt_resp_dma);
280
281 rsplen = 0;
282 datalen = 0;
283 goto failed;
284 }
285
286 if (real_len < rsplen) {
287 (void) ddi_dma_mem_free(&pkt->pkt_resp_acc);
288 (void) ddi_dma_free_handle(&pkt->pkt_resp_dma);
289
290 rsplen = 0;
291 datalen = 0;
292 goto failed;
293 }
294 #if (EMLXS_MODREV >= EMLXS_MODREV3)
295 if (ddi_dma_addr_bind_handle(pkt->pkt_resp_dma, NULL,
296 pkt->pkt_resp, real_len,
297 DDI_DMA_READ | DDI_DMA_CONSISTENT, cb, NULL,
298 pkt->pkt_resp_cookie,
299 &pkt->pkt_resp_cookie_cnt) != DDI_DMA_MAPPED)
300 #else
301 if (ddi_dma_addr_bind_handle(pkt->pkt_resp_dma, NULL,
302 pkt->pkt_resp, real_len,
303 DDI_DMA_READ | DDI_DMA_CONSISTENT, cb, NULL,
304 &pkt->pkt_resp_cookie, &num_cookie) != DDI_DMA_MAPPED)
305 #endif /* >= EMLXS_MODREV3 */
306 {
307 (void) ddi_dma_mem_free(&pkt->pkt_resp_acc);
308 (void) ddi_dma_free_handle(&pkt->pkt_resp_dma);
309
310 rsplen = 0;
311 datalen = 0;
312 goto failed;
313 }
314 #if (EMLXS_MODREV >= EMLXS_MODREV3)
315 if (pkt->pkt_resp_cookie_cnt != 1)
316 #else
317 if (num_cookie != 1)
318 #endif /* >= EMLXS_MODREV3 */
319 {
320 datalen = 0;
321 goto failed;
322 }
323
324 bzero(pkt->pkt_resp, rsplen);
325
326 }
327
328 /* Allocate the data buf */
329 if (datalen) {
330 /* Allocate the rsp buf */
331 if (ddi_dma_alloc_handle(hba->dip, &hba->dma_attr_1sg, cb,
332 NULL, &pkt->pkt_data_dma) != DDI_SUCCESS) {
333 datalen = 0;
334 goto failed;
335 }
336
337 if (ddi_dma_mem_alloc(pkt->pkt_data_dma, datalen,
338 &emlxs_data_acc_attr, DDI_DMA_CONSISTENT, cb, NULL,
339 (caddr_t *)&pkt->pkt_data, &real_len,
340 &pkt->pkt_data_acc) != DDI_SUCCESS) {
341 (void) ddi_dma_free_handle(&pkt->pkt_data_dma);
342
343 datalen = 0;
344 goto failed;
345 }
346
347 if (real_len < datalen) {
348 (void) ddi_dma_mem_free(&pkt->pkt_data_acc);
349 (void) ddi_dma_free_handle(&pkt->pkt_data_dma);
350
351 datalen = 0;
352 goto failed;
353 }
354 #if (EMLXS_MODREV >= EMLXS_MODREV3)
355 if (ddi_dma_addr_bind_handle(pkt->pkt_data_dma, NULL,
356 pkt->pkt_data, real_len,
357 DDI_DMA_READ | DDI_DMA_WRITE | DDI_DMA_CONSISTENT, cb,
358 NULL, pkt->pkt_data_cookie,
359 &pkt->pkt_data_cookie_cnt) != DDI_DMA_MAPPED)
360 #else
361 if (ddi_dma_addr_bind_handle(pkt->pkt_data_dma, NULL,
362 pkt->pkt_data, real_len,
363 DDI_DMA_READ | DDI_DMA_WRITE | DDI_DMA_CONSISTENT, cb,
364 NULL, &pkt->pkt_data_cookie,
365 &num_cookie) != DDI_DMA_MAPPED)
366 #endif /* >= EMLXS_MODREV3 */
367 {
368 (void) ddi_dma_mem_free(&pkt->pkt_data_acc);
369 (void) ddi_dma_free_handle(&pkt->pkt_data_dma);
370
371 datalen = 0;
372 goto failed;
373 }
374 #if (EMLXS_MODREV >= EMLXS_MODREV3)
375 if (pkt->pkt_data_cookie_cnt != 1)
376 #else
377 if (num_cookie != 1)
378 #endif /* >= EMLXS_MODREV3 */
379 {
380 goto failed;
381 }
382
383 bzero(pkt->pkt_data, datalen);
384 }
385
386 sbp = PKT2PRIV(pkt);
387 bzero((void *)sbp, sizeof (emlxs_buf_t));
388
389 mutex_init(&sbp->mtx, NULL, MUTEX_DRIVER, DDI_INTR_PRI(hba->intr_arg));
390 sbp->pkt_flags = PACKET_VALID | PACKET_ULP_OWNED | PACKET_ALLOCATED;
391 sbp->port = port;
392 sbp->pkt = pkt;
393 sbp->iocbq.sbp = sbp;
394
395 return (pkt);
396
397 failed:
398
399 if (datalen) {
400 (void) ddi_dma_unbind_handle(pkt->pkt_data_dma);
401 (void) ddi_dma_mem_free(&pkt->pkt_data_acc);
402 (void) ddi_dma_free_handle(&pkt->pkt_data_dma);
403 }
404
405 if (rsplen) {
406 (void) ddi_dma_unbind_handle(pkt->pkt_resp_dma);
407 (void) ddi_dma_mem_free(&pkt->pkt_resp_acc);
408 (void) ddi_dma_free_handle(&pkt->pkt_resp_dma);
409 }
410
411 if (cmdlen) {
412 (void) ddi_dma_unbind_handle(pkt->pkt_cmd_dma);
413 (void) ddi_dma_mem_free(&pkt->pkt_cmd_acc);
414 (void) ddi_dma_free_handle(&pkt->pkt_cmd_dma);
415 }
416
417 if (pkt) {
418 kmem_free(pkt, pkt_size);
419 }
420
421 return (NULL);
422
423 } /* emlxs_pkt_alloc() */
424