1890 Updated emlxs driver from Emulex
[unleashed.git] / usr / src / uts / common / io / fibre-channel / fca / emlxs / emlxs_pkt.c
blobc23adc18d7c66dabaf8e5e65c9741e43688d82cc
1 /*
2 * CDDL HEADER START
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.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
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]
19 * CDDL HEADER END
23 * Copyright 2010 Emulex. All rights reserved.
24 * Use is subject to license terms.
28 #include <emlxs.h>
30 /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
31 EMLXS_MSG_DEF(EMLXS_PKT_C);
33 #if (EMLXS_MODREV >= EMLXS_MODREV3)
34 typedef struct _emlxs_pkt_cookie_t
36 ddi_dma_cookie_t pkt_cmd_cookie;
37 ddi_dma_cookie_t pkt_resp_cookie;
38 ddi_dma_cookie_t pkt_data_cookie;
40 } emlxs_pkt_cookie_t;
41 #endif /* >= EMLXS_MODREV3 */
44 /* ARGSUSED */
45 static void
46 emlxs_pkt_thread(emlxs_hba_t *hba, void *arg1, void *arg2)
48 emlxs_port_t *port;
49 fc_packet_t *pkt = (fc_packet_t *)arg1;
50 int32_t rval;
51 emlxs_buf_t *sbp;
53 sbp = PKT2PRIV(pkt);
54 port = sbp->port;
56 /* Send the pkt now */
57 rval = emlxs_pkt_send(pkt, 1);
59 if (rval != FC_SUCCESS) {
60 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_trans_msg,
61 "Deferred emlxs_pkt_send failed: status=%x pkt=%p", rval,
62 pkt);
64 if (pkt->pkt_comp) {
65 emlxs_set_pkt_state(sbp, IOSTAT_LOCAL_REJECT, 0, 1);
67 ((CHANNEL *)sbp->channel)->ulpCmplCmd++;
68 (*pkt->pkt_comp) (pkt);
69 } else {
70 emlxs_pkt_free(pkt);
74 return;
76 } /* emlxs_pkt_thread() */
79 extern int32_t
80 emlxs_pkt_send(fc_packet_t *pkt, uint32_t now)
82 emlxs_port_t *port = (emlxs_port_t *)pkt->pkt_ulp_private;
83 emlxs_hba_t *hba = HBA;
84 int32_t rval;
86 if (now) {
87 rval = emlxs_fca_transport((opaque_t)port, pkt);
88 } else {
89 /* Spawn a thread to send the pkt */
90 emlxs_thread_spawn(hba, emlxs_pkt_thread, (char *)pkt, NULL);
92 rval = FC_SUCCESS;
95 return (rval);
97 } /* emlxs_pkt_send() */
100 extern void
101 emlxs_pkt_free(fc_packet_t *pkt)
103 emlxs_port_t *port = (emlxs_port_t *)pkt->pkt_ulp_private;
105 (void) emlxs_fca_pkt_uninit((opaque_t)port, pkt);
107 if (pkt->pkt_datalen) {
108 (void) ddi_dma_unbind_handle(pkt->pkt_data_dma);
109 (void) ddi_dma_mem_free(&pkt->pkt_data_acc);
110 (void) ddi_dma_free_handle(&pkt->pkt_data_dma);
113 if (pkt->pkt_rsplen) {
114 (void) ddi_dma_unbind_handle(pkt->pkt_resp_dma);
115 (void) ddi_dma_mem_free(&pkt->pkt_resp_acc);
116 (void) ddi_dma_free_handle(&pkt->pkt_resp_dma);
119 if (pkt->pkt_cmdlen) {
120 (void) ddi_dma_unbind_handle(pkt->pkt_cmd_dma);
121 (void) ddi_dma_mem_free(&pkt->pkt_cmd_acc);
122 (void) ddi_dma_free_handle(&pkt->pkt_cmd_dma);
124 #if (EMLXS_MODREV >= EMLXS_MODREV3)
125 kmem_free(pkt, (sizeof (fc_packet_t) + sizeof (emlxs_buf_t) +
126 sizeof (emlxs_pkt_cookie_t)));
127 #else
128 kmem_free(pkt, (sizeof (fc_packet_t) + sizeof (emlxs_buf_t)));
129 #endif /* >= EMLXS_MODREV3 */
131 return;
133 } /* emlxs_pkt_free() */
136 /* Default pkt callback routine */
137 extern void
138 emlxs_pkt_callback(fc_packet_t *pkt)
140 emlxs_pkt_free(pkt);
142 return;
144 } /* emlxs_pkt_callback() */
148 extern fc_packet_t *
149 emlxs_pkt_alloc(emlxs_port_t *port, uint32_t cmdlen, uint32_t rsplen,
150 uint32_t datalen, int32_t sleep)
152 emlxs_hba_t *hba = HBA;
153 fc_packet_t *pkt;
154 int32_t(*cb) (caddr_t);
155 unsigned long real_len;
156 uint32_t pkt_size;
157 emlxs_buf_t *sbp;
159 #if (EMLXS_MODREV >= EMLXS_MODREV3)
160 emlxs_pkt_cookie_t *pkt_cookie;
162 pkt_size =
163 sizeof (fc_packet_t) + sizeof (emlxs_buf_t) +
164 sizeof (emlxs_pkt_cookie_t);
165 #else
166 uint32_t num_cookie;
168 pkt_size = sizeof (fc_packet_t) + sizeof (emlxs_buf_t);
169 #endif /* >= EMLXS_MODREV3 */
172 /* Allocate some space */
173 if (!(pkt = (fc_packet_t *)kmem_alloc(pkt_size, sleep))) {
174 return (NULL);
177 bzero(pkt, pkt_size);
179 cb = (sleep == KM_SLEEP) ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT;
181 pkt->pkt_ulp_private = (opaque_t)port;
182 pkt->pkt_fca_private =
183 (opaque_t)((uintptr_t)pkt + sizeof (fc_packet_t));
184 pkt->pkt_comp = emlxs_pkt_callback;
185 pkt->pkt_tran_flags = (FC_TRAN_CLASS3 | FC_TRAN_INTR);
186 pkt->pkt_cmdlen = cmdlen;
187 pkt->pkt_rsplen = rsplen;
188 pkt->pkt_datalen = datalen;
190 #if (EMLXS_MODREV >= EMLXS_MODREV3)
191 pkt_cookie =
192 (emlxs_pkt_cookie_t *)((uintptr_t)pkt + sizeof (fc_packet_t) +
193 sizeof (emlxs_buf_t));
194 pkt->pkt_cmd_cookie = &pkt_cookie->pkt_cmd_cookie;
195 pkt->pkt_resp_cookie = &pkt_cookie->pkt_resp_cookie;
196 pkt->pkt_data_cookie = &pkt_cookie->pkt_data_cookie;
197 #endif /* >= EMLXS_MODREV3 */
199 if (cmdlen) {
200 /* Allocate the cmd buf */
201 if (ddi_dma_alloc_handle(hba->dip, &hba->dma_attr_1sg, cb,
202 NULL, &pkt->pkt_cmd_dma) != DDI_SUCCESS) {
203 cmdlen = 0;
204 rsplen = 0;
205 datalen = 0;
206 goto failed;
209 if (ddi_dma_mem_alloc(pkt->pkt_cmd_dma, cmdlen,
210 &emlxs_data_acc_attr, DDI_DMA_CONSISTENT, cb, NULL,
211 (caddr_t *)&pkt->pkt_cmd, &real_len,
212 &pkt->pkt_cmd_acc) != DDI_SUCCESS) {
213 (void) ddi_dma_free_handle(&pkt->pkt_cmd_dma);
215 cmdlen = 0;
216 rsplen = 0;
217 datalen = 0;
218 goto failed;
221 if (real_len < cmdlen) {
222 (void) ddi_dma_mem_free(&pkt->pkt_cmd_acc);
223 (void) ddi_dma_free_handle(&pkt->pkt_cmd_dma);
225 cmdlen = 0;
226 rsplen = 0;
227 datalen = 0;
228 goto failed;
230 #if (EMLXS_MODREV >= EMLXS_MODREV3)
231 if (ddi_dma_addr_bind_handle(pkt->pkt_cmd_dma, NULL,
232 pkt->pkt_cmd, real_len,
233 DDI_DMA_WRITE | DDI_DMA_CONSISTENT, cb, NULL,
234 pkt->pkt_cmd_cookie,
235 &pkt->pkt_cmd_cookie_cnt) != DDI_DMA_MAPPED)
236 #else
237 if (ddi_dma_addr_bind_handle(pkt->pkt_cmd_dma, NULL,
238 pkt->pkt_cmd, real_len,
239 DDI_DMA_WRITE | DDI_DMA_CONSISTENT, cb, NULL,
240 &pkt->pkt_cmd_cookie, &num_cookie) != DDI_DMA_MAPPED)
241 #endif /* >= EMLXS_MODREV3 */
243 (void) ddi_dma_mem_free(&pkt->pkt_cmd_acc);
244 (void) ddi_dma_free_handle(&pkt->pkt_cmd_dma);
246 cmdlen = 0;
247 rsplen = 0;
248 datalen = 0;
249 goto failed;
251 #if (EMLXS_MODREV >= EMLXS_MODREV3)
252 if (pkt->pkt_cmd_cookie_cnt != 1)
253 #else
254 if (num_cookie != 1)
255 #endif /* >= EMLXS_MODREV3 */
257 rsplen = 0;
258 datalen = 0;
259 goto failed;
262 bzero(pkt->pkt_cmd, cmdlen);
266 if (rsplen) {
267 /* Allocate the rsp buf */
268 if (ddi_dma_alloc_handle(hba->dip, &hba->dma_attr_1sg, cb,
269 NULL, &pkt->pkt_resp_dma) != DDI_SUCCESS) {
270 rsplen = 0;
271 datalen = 0;
272 goto failed;
276 if (ddi_dma_mem_alloc(pkt->pkt_resp_dma, rsplen,
277 &emlxs_data_acc_attr, DDI_DMA_CONSISTENT, cb, NULL,
278 (caddr_t *)&pkt->pkt_resp, &real_len,
279 &pkt->pkt_resp_acc) != DDI_SUCCESS) {
280 (void) ddi_dma_free_handle(&pkt->pkt_resp_dma);
282 rsplen = 0;
283 datalen = 0;
284 goto failed;
287 if (real_len < rsplen) {
288 (void) ddi_dma_mem_free(&pkt->pkt_resp_acc);
289 (void) ddi_dma_free_handle(&pkt->pkt_resp_dma);
291 rsplen = 0;
292 datalen = 0;
293 goto failed;
295 #if (EMLXS_MODREV >= EMLXS_MODREV3)
296 if (ddi_dma_addr_bind_handle(pkt->pkt_resp_dma, NULL,
297 pkt->pkt_resp, real_len,
298 DDI_DMA_READ | DDI_DMA_CONSISTENT, cb, NULL,
299 pkt->pkt_resp_cookie,
300 &pkt->pkt_resp_cookie_cnt) != DDI_DMA_MAPPED)
301 #else
302 if (ddi_dma_addr_bind_handle(pkt->pkt_resp_dma, NULL,
303 pkt->pkt_resp, real_len,
304 DDI_DMA_READ | DDI_DMA_CONSISTENT, cb, NULL,
305 &pkt->pkt_resp_cookie, &num_cookie) != DDI_DMA_MAPPED)
306 #endif /* >= EMLXS_MODREV3 */
308 (void) ddi_dma_mem_free(&pkt->pkt_resp_acc);
309 (void) ddi_dma_free_handle(&pkt->pkt_resp_dma);
311 rsplen = 0;
312 datalen = 0;
313 goto failed;
315 #if (EMLXS_MODREV >= EMLXS_MODREV3)
316 if (pkt->pkt_resp_cookie_cnt != 1)
317 #else
318 if (num_cookie != 1)
319 #endif /* >= EMLXS_MODREV3 */
321 datalen = 0;
322 goto failed;
325 bzero(pkt->pkt_resp, rsplen);
329 /* Allocate the data buf */
330 if (datalen) {
331 /* Allocate the rsp buf */
332 if (ddi_dma_alloc_handle(hba->dip, &hba->dma_attr_1sg, cb,
333 NULL, &pkt->pkt_data_dma) != DDI_SUCCESS) {
334 datalen = 0;
335 goto failed;
338 if (ddi_dma_mem_alloc(pkt->pkt_data_dma, datalen,
339 &emlxs_data_acc_attr, DDI_DMA_CONSISTENT, cb, NULL,
340 (caddr_t *)&pkt->pkt_data, &real_len,
341 &pkt->pkt_data_acc) != DDI_SUCCESS) {
342 (void) ddi_dma_free_handle(&pkt->pkt_data_dma);
344 datalen = 0;
345 goto failed;
348 if (real_len < datalen) {
349 (void) ddi_dma_mem_free(&pkt->pkt_data_acc);
350 (void) ddi_dma_free_handle(&pkt->pkt_data_dma);
352 datalen = 0;
353 goto failed;
355 #if (EMLXS_MODREV >= EMLXS_MODREV3)
356 if (ddi_dma_addr_bind_handle(pkt->pkt_data_dma, NULL,
357 pkt->pkt_data, real_len,
358 DDI_DMA_READ | DDI_DMA_WRITE | DDI_DMA_CONSISTENT, cb,
359 NULL, pkt->pkt_data_cookie,
360 &pkt->pkt_data_cookie_cnt) != DDI_DMA_MAPPED)
361 #else
362 if (ddi_dma_addr_bind_handle(pkt->pkt_data_dma, NULL,
363 pkt->pkt_data, real_len,
364 DDI_DMA_READ | DDI_DMA_WRITE | DDI_DMA_CONSISTENT, cb,
365 NULL, &pkt->pkt_data_cookie,
366 &num_cookie) != DDI_DMA_MAPPED)
367 #endif /* >= EMLXS_MODREV3 */
369 (void) ddi_dma_mem_free(&pkt->pkt_data_acc);
370 (void) ddi_dma_free_handle(&pkt->pkt_data_dma);
372 datalen = 0;
373 goto failed;
375 #if (EMLXS_MODREV >= EMLXS_MODREV3)
376 if (pkt->pkt_data_cookie_cnt != 1)
377 #else
378 if (num_cookie != 1)
379 #endif /* >= EMLXS_MODREV3 */
381 goto failed;
384 bzero(pkt->pkt_data, datalen);
387 sbp = PKT2PRIV(pkt);
388 bzero((void *)sbp, sizeof (emlxs_buf_t));
390 mutex_init(&sbp->mtx, NULL, MUTEX_DRIVER, DDI_INTR_PRI(hba->intr_arg));
391 sbp->pkt_flags = PACKET_VALID | PACKET_ULP_OWNED | PACKET_ALLOCATED;
392 sbp->port = port;
393 sbp->pkt = pkt;
394 sbp->iocbq.sbp = sbp;
396 return (pkt);
398 failed:
400 if (datalen) {
401 (void) ddi_dma_unbind_handle(pkt->pkt_data_dma);
402 (void) ddi_dma_mem_free(&pkt->pkt_data_acc);
403 (void) ddi_dma_free_handle(&pkt->pkt_data_dma);
406 if (rsplen) {
407 (void) ddi_dma_unbind_handle(pkt->pkt_resp_dma);
408 (void) ddi_dma_mem_free(&pkt->pkt_resp_acc);
409 (void) ddi_dma_free_handle(&pkt->pkt_resp_dma);
412 if (cmdlen) {
413 (void) ddi_dma_unbind_handle(pkt->pkt_cmd_dma);
414 (void) ddi_dma_mem_free(&pkt->pkt_cmd_acc);
415 (void) ddi_dma_free_handle(&pkt->pkt_cmd_dma);
418 if (pkt) {
419 kmem_free(pkt, pkt_size);
422 return (NULL);
424 } /* emlxs_pkt_alloc() */