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 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.
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 2009 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 _emlxs_pkt_cookie_t
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 static void
44 emlxs_pkt_thread(void *arg)
45 {
46 	emlxs_port_t *port;
47 	fc_packet_t *pkt = (fc_packet_t *)arg;
48 	int32_t rval;
49 	emlxs_buf_t *sbp;
50 
51 	sbp = PKT2PRIV(pkt);
52 	port = sbp->port;
53 
54 	/* Send the pkt now */
55 	rval = emlxs_pkt_send(pkt, 1);
56 
57 	if (rval != FC_SUCCESS) {
58 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_trans_msg,
59 		    "Deferred emlxs_pkt_send failed: status=%x pkt=%p", rval,
60 		    pkt);
61 
62 		if (pkt->pkt_comp) {
63 			emlxs_set_pkt_state(sbp, IOSTAT_LOCAL_REJECT, 0, 1);
64 
65 			(*pkt->pkt_comp) (pkt);
66 		} else {
67 			emlxs_pkt_free(pkt);
68 		}
69 	}
70 
71 	return;
72 
73 }  /* emlxs_pkt_thread() */
74 
75 
76 extern int32_t
77 emlxs_pkt_send(fc_packet_t *pkt, uint32_t now)
78 {
79 	int32_t rval;
80 
81 	if (now) {
82 		rval = emlxs_transport((opaque_t)pkt->pkt_ulp_private, pkt);
83 	} else {
84 		/* Spawn a thread to send the pkt */
85 		thread_create(NULL, 0, emlxs_pkt_thread, (char *)pkt, 0, &p0,
86 		    TS_RUN, v.v_maxsyspri - 2);
87 
88 		rval = FC_SUCCESS;
89 	}
90 
91 	return (rval);
92 
93 }  /* emlxs_pkt_send() */
94 
95 
96 extern void
97 emlxs_pkt_free(fc_packet_t *pkt)
98 {
99 	emlxs_port_t *port = (emlxs_port_t *)pkt->pkt_ulp_private;
100 
101 	(void) emlxs_pkt_uninit((opaque_t)port, pkt);
102 
103 	if (pkt->pkt_datalen) {
104 		(void) ddi_dma_unbind_handle(pkt->pkt_data_dma);
105 		(void) ddi_dma_mem_free(&pkt->pkt_data_acc);
106 		(void) ddi_dma_free_handle(&pkt->pkt_data_dma);
107 	}
108 
109 	if (pkt->pkt_rsplen) {
110 		(void) ddi_dma_unbind_handle(pkt->pkt_resp_dma);
111 		(void) ddi_dma_mem_free(&pkt->pkt_resp_acc);
112 		(void) ddi_dma_free_handle(&pkt->pkt_resp_dma);
113 	}
114 
115 	if (pkt->pkt_cmdlen) {
116 		(void) ddi_dma_unbind_handle(pkt->pkt_cmd_dma);
117 		(void) ddi_dma_mem_free(&pkt->pkt_cmd_acc);
118 		(void) ddi_dma_free_handle(&pkt->pkt_cmd_dma);
119 	}
120 #if (EMLXS_MODREV >= EMLXS_MODREV3)
121 	kmem_free(pkt, (sizeof (fc_packet_t) + sizeof (emlxs_buf_t) +
122 	    sizeof (emlxs_pkt_cookie_t)));
123 #else
124 	kmem_free(pkt, (sizeof (fc_packet_t) + sizeof (emlxs_buf_t)));
125 #endif /* >= EMLXS_MODREV3 */
126 
127 	return;
128 
129 }  /* emlxs_pkt_free() */
130 
131 
132 /* Default pkt callback routine */
133 extern void
134 emlxs_pkt_callback(fc_packet_t *pkt)
135 {
136 	emlxs_pkt_free(pkt);
137 
138 	return;
139 
140 }  /* emlxs_pkt_callback() */
141 
142 
143 
144 extern fc_packet_t *
145 emlxs_pkt_alloc(emlxs_port_t *port, uint32_t cmdlen, uint32_t rsplen,
146     uint32_t datalen, int32_t sleep)
147 {
148 	emlxs_hba_t *hba = HBA;
149 	fc_packet_t *pkt;
150 	int32_t(*cb) (caddr_t);
151 	unsigned long real_len;
152 	uint32_t pkt_size;
153 	emlxs_buf_t *sbp;
154 
155 #if (EMLXS_MODREV >= EMLXS_MODREV3)
156 	emlxs_pkt_cookie_t *pkt_cookie;
157 
158 	pkt_size =
159 	    sizeof (fc_packet_t) + sizeof (emlxs_buf_t) +
160 	    sizeof (emlxs_pkt_cookie_t);
161 #else
162 	uint32_t num_cookie;
163 
164 	pkt_size = sizeof (fc_packet_t) + sizeof (emlxs_buf_t);
165 #endif /* >= EMLXS_MODREV3 */
166 
167 
168 	/* Allocate some space */
169 	if (!(pkt = (fc_packet_t *)kmem_alloc(pkt_size, sleep))) {
170 		return (NULL);
171 	}
172 
173 	bzero(pkt, pkt_size);
174 
175 	cb = (sleep == KM_SLEEP) ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT;
176 
177 	pkt->pkt_ulp_private = (opaque_t)port;
178 	pkt->pkt_fca_private =
179 	    (opaque_t)((uintptr_t)pkt + sizeof (fc_packet_t));
180 	pkt->pkt_comp = emlxs_pkt_callback;
181 	pkt->pkt_tran_flags = (FC_TRAN_CLASS3 | FC_TRAN_INTR);
182 	pkt->pkt_cmdlen = cmdlen;
183 	pkt->pkt_rsplen = rsplen;
184 	pkt->pkt_datalen = datalen;
185 
186 #if (EMLXS_MODREV >= EMLXS_MODREV3)
187 	pkt_cookie =
188 	    (emlxs_pkt_cookie_t *)((uintptr_t)pkt + sizeof (fc_packet_t) +
189 	    sizeof (emlxs_buf_t));
190 	pkt->pkt_cmd_cookie = &pkt_cookie->pkt_cmd_cookie;
191 	pkt->pkt_resp_cookie = &pkt_cookie->pkt_resp_cookie;
192 	pkt->pkt_data_cookie = &pkt_cookie->pkt_data_cookie;
193 #endif /* >= EMLXS_MODREV3 */
194 
195 	if (cmdlen) {
196 		/* Allocate the cmd buf */
197 		if (ddi_dma_alloc_handle(hba->dip, &emlxs_dma_attr_1sg, cb,
198 		    NULL, &pkt->pkt_cmd_dma) != DDI_SUCCESS) {
199 			cmdlen = 0;
200 			rsplen = 0;
201 			datalen = 0;
202 			goto failed;
203 		}
204 
205 		if (ddi_dma_mem_alloc(pkt->pkt_cmd_dma, cmdlen,
206 		    &emlxs_data_acc_attr, DDI_DMA_CONSISTENT, cb, NULL,
207 		    (caddr_t *)&pkt->pkt_cmd, &real_len,
208 		    &pkt->pkt_cmd_acc) != DDI_SUCCESS) {
209 			(void) ddi_dma_free_handle(&pkt->pkt_cmd_dma);
210 
211 			cmdlen = 0;
212 			rsplen = 0;
213 			datalen = 0;
214 			goto failed;
215 		}
216 
217 		if (real_len < cmdlen) {
218 			(void) ddi_dma_mem_free(&pkt->pkt_cmd_acc);
219 			(void) ddi_dma_free_handle(&pkt->pkt_cmd_dma);
220 
221 			cmdlen = 0;
222 			rsplen = 0;
223 			datalen = 0;
224 			goto failed;
225 		}
226 #if (EMLXS_MODREV >= EMLXS_MODREV3)
227 		if (ddi_dma_addr_bind_handle(pkt->pkt_cmd_dma, NULL,
228 		    pkt->pkt_cmd, real_len,
229 		    DDI_DMA_WRITE | DDI_DMA_CONSISTENT, cb, NULL,
230 		    pkt->pkt_cmd_cookie,
231 		    &pkt->pkt_cmd_cookie_cnt) != DDI_DMA_MAPPED)
232 #else
233 		if (ddi_dma_addr_bind_handle(pkt->pkt_cmd_dma, NULL,
234 		    pkt->pkt_cmd, real_len,
235 		    DDI_DMA_WRITE | DDI_DMA_CONSISTENT, cb, NULL,
236 		    &pkt->pkt_cmd_cookie, &num_cookie) != DDI_DMA_MAPPED)
237 #endif /* >= EMLXS_MODREV3 */
238 		{
239 			(void) ddi_dma_mem_free(&pkt->pkt_cmd_acc);
240 			(void) ddi_dma_free_handle(&pkt->pkt_cmd_dma);
241 
242 			cmdlen = 0;
243 			rsplen = 0;
244 			datalen = 0;
245 			goto failed;
246 		}
247 #if (EMLXS_MODREV >= EMLXS_MODREV3)
248 		if (pkt->pkt_cmd_cookie_cnt != 1)
249 #else
250 		if (num_cookie != 1)
251 #endif /* >= EMLXS_MODREV3 */
252 		{
253 			rsplen = 0;
254 			datalen = 0;
255 			goto failed;
256 		}
257 
258 		bzero(pkt->pkt_cmd, cmdlen);
259 
260 	}
261 
262 	if (rsplen) {
263 		/* Allocate the rsp buf */
264 		if (ddi_dma_alloc_handle(hba->dip, &emlxs_dma_attr_1sg, cb,
265 		    NULL, &pkt->pkt_resp_dma) != DDI_SUCCESS) {
266 			rsplen = 0;
267 			datalen = 0;
268 			goto failed;
269 
270 		}
271 
272 		if (ddi_dma_mem_alloc(pkt->pkt_resp_dma, rsplen,
273 		    &emlxs_data_acc_attr, DDI_DMA_CONSISTENT, cb, NULL,
274 		    (caddr_t *)&pkt->pkt_resp, &real_len,
275 		    &pkt->pkt_resp_acc) != DDI_SUCCESS) {
276 			(void) ddi_dma_free_handle(&pkt->pkt_resp_dma);
277 
278 			rsplen = 0;
279 			datalen = 0;
280 			goto failed;
281 		}
282 
283 		if (real_len < rsplen) {
284 			(void) ddi_dma_mem_free(&pkt->pkt_resp_acc);
285 			(void) ddi_dma_free_handle(&pkt->pkt_resp_dma);
286 
287 			rsplen = 0;
288 			datalen = 0;
289 			goto failed;
290 		}
291 #if (EMLXS_MODREV >= EMLXS_MODREV3)
292 		if (ddi_dma_addr_bind_handle(pkt->pkt_resp_dma, NULL,
293 		    pkt->pkt_resp, real_len,
294 		    DDI_DMA_READ | DDI_DMA_CONSISTENT, cb, NULL,
295 		    pkt->pkt_resp_cookie,
296 		    &pkt->pkt_resp_cookie_cnt) != DDI_DMA_MAPPED)
297 #else
298 		if (ddi_dma_addr_bind_handle(pkt->pkt_resp_dma, NULL,
299 		    pkt->pkt_resp, real_len,
300 		    DDI_DMA_READ | DDI_DMA_CONSISTENT, cb, NULL,
301 		    &pkt->pkt_resp_cookie, &num_cookie) != DDI_DMA_MAPPED)
302 #endif /* >= EMLXS_MODREV3 */
303 		{
304 			(void) ddi_dma_mem_free(&pkt->pkt_resp_acc);
305 			(void) ddi_dma_free_handle(&pkt->pkt_resp_dma);
306 
307 			rsplen = 0;
308 			datalen = 0;
309 			goto failed;
310 		}
311 #if (EMLXS_MODREV >= EMLXS_MODREV3)
312 		if (pkt->pkt_resp_cookie_cnt != 1)
313 #else
314 		if (num_cookie != 1)
315 #endif /* >= EMLXS_MODREV3 */
316 		{
317 			datalen = 0;
318 			goto failed;
319 		}
320 
321 		bzero(pkt->pkt_resp, rsplen);
322 
323 	}
324 
325 	/* Allocate the data buf */
326 	if (datalen) {
327 		/* Allocate the rsp buf */
328 		if (ddi_dma_alloc_handle(hba->dip, &emlxs_dma_attr_1sg, cb,
329 		    NULL, &pkt->pkt_data_dma) != DDI_SUCCESS) {
330 			datalen = 0;
331 			goto failed;
332 		}
333 
334 		if (ddi_dma_mem_alloc(pkt->pkt_data_dma, datalen,
335 		    &emlxs_data_acc_attr, DDI_DMA_CONSISTENT, cb, NULL,
336 		    (caddr_t *)&pkt->pkt_data, &real_len,
337 		    &pkt->pkt_data_acc) != DDI_SUCCESS) {
338 			(void) ddi_dma_free_handle(&pkt->pkt_data_dma);
339 
340 			datalen = 0;
341 			goto failed;
342 		}
343 
344 		if (real_len < datalen) {
345 			(void) ddi_dma_mem_free(&pkt->pkt_data_acc);
346 			(void) ddi_dma_free_handle(&pkt->pkt_data_dma);
347 
348 			datalen = 0;
349 			goto failed;
350 		}
351 #if (EMLXS_MODREV >= EMLXS_MODREV3)
352 		if (ddi_dma_addr_bind_handle(pkt->pkt_data_dma, NULL,
353 		    pkt->pkt_data, real_len,
354 		    DDI_DMA_READ | DDI_DMA_WRITE | DDI_DMA_CONSISTENT, cb,
355 		    NULL, pkt->pkt_data_cookie,
356 		    &pkt->pkt_data_cookie_cnt) != DDI_DMA_MAPPED)
357 #else
358 		if (ddi_dma_addr_bind_handle(pkt->pkt_data_dma, NULL,
359 		    pkt->pkt_data, real_len,
360 		    DDI_DMA_READ | DDI_DMA_WRITE | DDI_DMA_CONSISTENT, cb,
361 		    NULL, &pkt->pkt_data_cookie,
362 		    &num_cookie) != DDI_DMA_MAPPED)
363 #endif /* >= EMLXS_MODREV3 */
364 		{
365 			(void) ddi_dma_mem_free(&pkt->pkt_data_acc);
366 			(void) ddi_dma_free_handle(&pkt->pkt_data_dma);
367 
368 			datalen = 0;
369 			goto failed;
370 		}
371 #if (EMLXS_MODREV >= EMLXS_MODREV3)
372 		if (pkt->pkt_data_cookie_cnt != 1)
373 #else
374 		if (num_cookie != 1)
375 #endif /* >= EMLXS_MODREV3 */
376 		{
377 			goto failed;
378 		}
379 
380 		bzero(pkt->pkt_data, datalen);
381 	}
382 
383 	sbp = PKT2PRIV(pkt);
384 	bzero((void *)sbp, sizeof (emlxs_buf_t));
385 
386 	mutex_init(&sbp->mtx, NULL, MUTEX_DRIVER, (void *)hba->intr_arg);
387 	sbp->pkt_flags = PACKET_VALID | PACKET_RETURNED | PACKET_ALLOCATED;
388 	sbp->port = port;
389 	sbp->pkt = pkt;
390 	sbp->iocbq.sbp = sbp;
391 
392 	return (pkt);
393 
394 failed:
395 
396 	if (datalen) {
397 		(void) ddi_dma_unbind_handle(pkt->pkt_data_dma);
398 		(void) ddi_dma_mem_free(&pkt->pkt_data_acc);
399 		(void) ddi_dma_free_handle(&pkt->pkt_data_dma);
400 	}
401 
402 	if (rsplen) {
403 		(void) ddi_dma_unbind_handle(pkt->pkt_resp_dma);
404 		(void) ddi_dma_mem_free(&pkt->pkt_resp_acc);
405 		(void) ddi_dma_free_handle(&pkt->pkt_resp_dma);
406 	}
407 
408 	if (cmdlen) {
409 		(void) ddi_dma_unbind_handle(pkt->pkt_cmd_dma);
410 		(void) ddi_dma_mem_free(&pkt->pkt_cmd_acc);
411 		(void) ddi_dma_free_handle(&pkt->pkt_cmd_dma);
412 	}
413 
414 	if (pkt) {
415 		kmem_free(pkt, pkt_size);
416 	}
417 
418 	return (NULL);
419 
420 }  /* emlxs_pkt_alloc() */
421