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