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