xref: /illumos-gate/usr/src/uts/common/io/fibre-channel/fca/emlxs/emlxs_pkt.c (revision b6805bf78d2bbbeeaea8909a05623587b42d58b3)
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 2010 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 {
36 	ddi_dma_cookie_t pkt_cmd_cookie;
37 	ddi_dma_cookie_t pkt_resp_cookie;
38 	ddi_dma_cookie_t pkt_data_cookie;
39 
40 } emlxs_pkt_cookie_t;
41 #endif /* >= EMLXS_MODREV3 */
42 
43 
44 /* ARGSUSED */
45 static void
46 emlxs_pkt_thread(emlxs_hba_t *hba, void *arg1, void *arg2)
47 {
48 	emlxs_port_t *port;
49 	fc_packet_t *pkt = (fc_packet_t *)arg1;
50 	int32_t rval;
51 	emlxs_buf_t *sbp;
52 
53 	sbp = PKT2PRIV(pkt);
54 	port = sbp->port;
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", rval,
62 		    pkt);
63 
64 		if (pkt->pkt_comp) {
65 			emlxs_set_pkt_state(sbp, IOSTAT_LOCAL_REJECT, 0, 1);
66 
67 			((CHANNEL *)sbp->channel)->ulpCmplCmd++;
68 			(*pkt->pkt_comp) (pkt);
69 		} else {
70 			emlxs_pkt_free(pkt);
71 		}
72 	}
73 
74 	return;
75 
76 } /* emlxs_pkt_thread() */
77 
78 
79 extern int32_t
80 emlxs_pkt_send(fc_packet_t *pkt, uint32_t now)
81 {
82 	emlxs_port_t *port = (emlxs_port_t *)pkt->pkt_ulp_private;
83 	emlxs_hba_t *hba = HBA;
84 	int32_t rval;
85 
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);
91 
92 		rval = FC_SUCCESS;
93 	}
94 
95 	return (rval);
96 
97 } /* emlxs_pkt_send() */
98 
99 
100 extern void
101 emlxs_pkt_free(fc_packet_t *pkt)
102 {
103 	emlxs_port_t *port = (emlxs_port_t *)pkt->pkt_ulp_private;
104 
105 	(void) emlxs_fca_pkt_uninit((opaque_t)port, pkt);
106 
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);
111 	}
112 
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);
117 	}
118 
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);
123 	}
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 */
130 
131 	return;
132 
133 } /* emlxs_pkt_free() */
134 
135 
136 /* Default pkt callback routine */
137 extern void
138 emlxs_pkt_callback(fc_packet_t *pkt)
139 {
140 	emlxs_pkt_free(pkt);
141 
142 	return;
143 
144 } /* emlxs_pkt_callback() */
145 
146 
147 
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)
151 {
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;
158 
159 #if (EMLXS_MODREV >= EMLXS_MODREV3)
160 	emlxs_pkt_cookie_t *pkt_cookie;
161 
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;
167 
168 	pkt_size = sizeof (fc_packet_t) + sizeof (emlxs_buf_t);
169 #endif /* >= EMLXS_MODREV3 */
170 
171 
172 	/* Allocate some space */
173 	if (!(pkt = (fc_packet_t *)kmem_alloc(pkt_size, sleep))) {
174 		return (NULL);
175 	}
176 
177 	bzero(pkt, pkt_size);
178 
179 	cb = (sleep == KM_SLEEP) ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT;
180 
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;
189 
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 */
198 
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;
207 		}
208 
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);
214 
215 			cmdlen = 0;
216 			rsplen = 0;
217 			datalen = 0;
218 			goto failed;
219 		}
220 
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);
224 
225 			cmdlen = 0;
226 			rsplen = 0;
227 			datalen = 0;
228 			goto failed;
229 		}
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 */
242 		{
243 			(void) ddi_dma_mem_free(&pkt->pkt_cmd_acc);
244 			(void) ddi_dma_free_handle(&pkt->pkt_cmd_dma);
245 
246 			cmdlen = 0;
247 			rsplen = 0;
248 			datalen = 0;
249 			goto failed;
250 		}
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 */
256 		{
257 			rsplen = 0;
258 			datalen = 0;
259 			goto failed;
260 		}
261 
262 		bzero(pkt->pkt_cmd, cmdlen);
263 
264 	}
265 
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;
273 
274 		}
275 
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);
281 
282 			rsplen = 0;
283 			datalen = 0;
284 			goto failed;
285 		}
286 
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);
290 
291 			rsplen = 0;
292 			datalen = 0;
293 			goto failed;
294 		}
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 */
307 		{
308 			(void) ddi_dma_mem_free(&pkt->pkt_resp_acc);
309 			(void) ddi_dma_free_handle(&pkt->pkt_resp_dma);
310 
311 			rsplen = 0;
312 			datalen = 0;
313 			goto failed;
314 		}
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 */
320 		{
321 			datalen = 0;
322 			goto failed;
323 		}
324 
325 		bzero(pkt->pkt_resp, rsplen);
326 
327 	}
328 
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;
336 		}
337 
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);
343 
344 			datalen = 0;
345 			goto failed;
346 		}
347 
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);
351 
352 			datalen = 0;
353 			goto failed;
354 		}
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 */
368 		{
369 			(void) ddi_dma_mem_free(&pkt->pkt_data_acc);
370 			(void) ddi_dma_free_handle(&pkt->pkt_data_dma);
371 
372 			datalen = 0;
373 			goto failed;
374 		}
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 */
380 		{
381 			goto failed;
382 		}
383 
384 		bzero(pkt->pkt_data, datalen);
385 	}
386 
387 	sbp = PKT2PRIV(pkt);
388 	bzero((void *)sbp, sizeof (emlxs_buf_t));
389 
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;
395 
396 	return (pkt);
397 
398 failed:
399 
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);
404 	}
405 
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);
410 	}
411 
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);
416 	}
417 
418 	if (pkt) {
419 		kmem_free(pkt, pkt_size);
420 	}
421 
422 	return (NULL);
423 
424 } /* emlxs_pkt_alloc() */
425