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