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 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <sys/scsi/scsi.h>
28 #include <sys/vtrace.h>
29 
30 
31 #define	A_TO_TRAN(ap)	((ap)->a_hba_tran)
32 #define	P_TO_TRAN(pkt)	((pkt)->pkt_address.a_hba_tran)
33 #define	P_TO_ADDR(pkt)	(&((pkt)->pkt_address))
34 
35 /*
36  * Callback id
37  */
38 uintptr_t scsi_callback_id = 0;
39 
40 extern ddi_dma_attr_t scsi_alloc_attr;
41 
42 struct buf *
43 scsi_alloc_consistent_buf(struct scsi_address *ap,
44     struct buf *in_bp, size_t datalen, uint_t bflags,
45     int (*callback)(caddr_t), caddr_t callback_arg)
46 {
47 	dev_info_t	*pdip;
48 	struct		buf *bp;
49 	int		kmflag;
50 	size_t		rlen;
51 
52 	TRACE_0(TR_FAC_SCSI_RES, TR_SCSI_ALLOC_CONSISTENT_BUF_START,
53 	    "scsi_alloc_consistent_buf_start");
54 
55 	if (!in_bp) {
56 		kmflag = (callback == SLEEP_FUNC) ? KM_SLEEP : KM_NOSLEEP;
57 		if ((bp = getrbuf(kmflag)) == NULL) {
58 			goto no_resource;
59 		}
60 	} else {
61 		bp = in_bp;
62 
63 		/* we are establishing a new buffer memory association */
64 		bp->b_flags &= ~(B_PAGEIO | B_PHYS | B_REMAPPED | B_SHADOW);
65 		bp->b_proc = NULL;
66 		bp->b_pages = NULL;
67 		bp->b_shadow = NULL;
68 	}
69 
70 	/* limit bits that can be set by bflags argument */
71 	ASSERT(!(bflags & ~(B_READ | B_WRITE)));
72 	bflags &= (B_READ | B_WRITE);
73 	bp->b_un.b_addr = 0;
74 
75 	if (datalen) {
76 		pdip = (A_TO_TRAN(ap))->tran_hba_dip;
77 
78 		/*
79 		 * use i_ddi_mem_alloc() for now until we have an interface to
80 		 * allocate memory for DMA which doesn't require a DMA handle.
81 		 * ddi_iopb_alloc() is obsolete and we want more flexibility in
82 		 * controlling the DMA address constraints.
83 		 */
84 		while (i_ddi_mem_alloc(pdip, &scsi_alloc_attr, datalen,
85 		    ((callback == SLEEP_FUNC) ? 1 : 0), 0, NULL,
86 		    &bp->b_un.b_addr, &rlen, NULL) != DDI_SUCCESS) {
87 			if (callback == SLEEP_FUNC) {
88 				delay(drv_usectohz(10000));
89 			} else {
90 				if (!in_bp)
91 					freerbuf(bp);
92 				goto no_resource;
93 			}
94 		}
95 		bp->b_flags |= bflags;
96 	}
97 	bp->b_bcount = datalen;
98 	bp->b_resid = 0;
99 
100 	TRACE_0(TR_FAC_SCSI_RES, TR_SCSI_ALLOC_CONSISTENT_BUF_END,
101 	    "scsi_alloc_consistent_buf_end");
102 	return (bp);
103 
104 no_resource:
105 
106 	if (callback != NULL_FUNC && callback != SLEEP_FUNC) {
107 		ddi_set_callback(callback, callback_arg,
108 		    &scsi_callback_id);
109 	}
110 	TRACE_0(TR_FAC_SCSI_RES,
111 	    TR_SCSI_ALLOC_CONSISTENT_BUF_RETURN1_END,
112 	    "scsi_alloc_consistent_buf_end (return1)");
113 	return (NULL);
114 }
115 
116 void
117 scsi_free_consistent_buf(struct buf *bp)
118 {
119 	TRACE_0(TR_FAC_SCSI_RES, TR_SCSI_FREE_CONSISTENT_BUF_START,
120 	    "scsi_free_consistent_buf_start");
121 	if (!bp)
122 		return;
123 	if (bp->b_un.b_addr)
124 		i_ddi_mem_free((caddr_t)bp->b_un.b_addr, NULL);
125 	freerbuf(bp);
126 	if (scsi_callback_id != 0) {
127 		ddi_run_callback(&scsi_callback_id);
128 	}
129 	TRACE_0(TR_FAC_SCSI_RES, TR_SCSI_FREE_CONSISTENT_BUF_END,
130 	    "scsi_free_consistent_buf_end");
131 }
132 
133 void
134 scsi_dmafree_attr(struct scsi_pkt *pktp)
135 {
136 	struct scsi_pkt_cache_wrapper *pktw =
137 	    (struct scsi_pkt_cache_wrapper *)pktp;
138 
139 	if (pktw->pcw_flags & PCW_BOUND) {
140 		if (ddi_dma_unbind_handle(pktp->pkt_handle) !=
141 		    DDI_SUCCESS)
142 			cmn_err(CE_WARN, "scsi_dmafree_attr: "
143 			    "unbind handle failed");
144 		pktw->pcw_flags &= ~PCW_BOUND;
145 	}
146 	pktp->pkt_numcookies = 0;
147 	pktw->pcw_totalwin = 0;
148 }
149 
150 struct buf *
151 scsi_pkt2bp(struct scsi_pkt *pkt)
152 {
153 	return (((struct scsi_pkt_cache_wrapper *)pkt)->pcw_bp);
154 }
155 
156 int
157 scsi_dma_buf_bind_attr(struct scsi_pkt_cache_wrapper *pktw,
158 			struct buf	*bp,
159 			int		 dma_flags,
160 			int		(*callback)(),
161 			caddr_t		 arg)
162 {
163 	struct scsi_pkt *pktp = &(pktw->pcw_pkt);
164 	int	 status;
165 
166 	/*
167 	 * First time, need to establish the handle.
168 	 */
169 
170 	ASSERT(pktp->pkt_numcookies == 0);
171 	ASSERT(pktw->pcw_totalwin == 0);
172 
173 	status = ddi_dma_buf_bind_handle(pktp->pkt_handle, bp, dma_flags,
174 	    callback, arg, &pktw->pcw_cookie,
175 	    &pktp->pkt_numcookies);
176 
177 	switch (status) {
178 	case DDI_DMA_MAPPED:
179 		pktw->pcw_totalwin = 1;
180 		break;
181 
182 	case DDI_DMA_PARTIAL_MAP:
183 		/* enable first call to ddi_dma_getwin */
184 		if (ddi_dma_numwin(pktp->pkt_handle,
185 		    &pktw->pcw_totalwin) != DDI_SUCCESS) {
186 			bp->b_error = 0;
187 			return (0);
188 		}
189 		break;
190 
191 	case DDI_DMA_NORESOURCES:
192 		bp->b_error = 0;
193 		return (0);
194 
195 	case DDI_DMA_TOOBIG:
196 		bioerror(bp, EINVAL);
197 		return (0);
198 
199 	case DDI_DMA_NOMAPPING:
200 	case DDI_DMA_INUSE:
201 	default:
202 		bioerror(bp, EFAULT);
203 		return (0);
204 	}
205 
206 	/* initialize the loop controls for scsi_dmaget_attr() */
207 	pktw->pcw_curwin = 0;
208 	pktw->pcw_total_xfer = 0;
209 	pktp->pkt_dma_flags = dma_flags;
210 	return (1);
211 }
212 
213 #if defined(_DMA_USES_PHYSADDR)
214 int
215 scsi_dmaget_attr(struct scsi_pkt_cache_wrapper *pktw)
216 {
217 	struct scsi_pkt *pktp = &(pktw->pcw_pkt);
218 
219 	int		status;
220 	int		num_segs = 0;
221 	ddi_dma_impl_t	*hp = (ddi_dma_impl_t *)pktp->pkt_handle;
222 	ddi_dma_cookie_t *cp;
223 
224 	if (pktw->pcw_curwin != 0) {
225 		ddi_dma_cookie_t	cookie;
226 
227 		/*
228 		 * start the next window, and get its first cookie
229 		 */
230 		status = ddi_dma_getwin(pktp->pkt_handle,
231 		    pktw->pcw_curwin, &pktp->pkt_dma_offset,
232 		    &pktp->pkt_dma_len, &cookie,
233 		    &pktp->pkt_numcookies);
234 		if (status != DDI_SUCCESS)
235 			return (0);
236 	}
237 
238 	/*
239 	 * start the Scatter/Gather loop
240 	 */
241 	cp = hp->dmai_cookie - 1;
242 	pktp->pkt_dma_len = 0;
243 	for (;;) {
244 
245 		/* take care of the loop-bookkeeping */
246 		pktp->pkt_dma_len += cp->dmac_size;
247 		num_segs++;
248 		/*
249 		 * if this was the last cookie in the current window
250 		 * set the loop controls start the next window and
251 		 * exit so the HBA can do this partial transfer
252 		 */
253 		if (num_segs >= pktp->pkt_numcookies) {
254 			pktw->pcw_curwin++;
255 			break;
256 		}
257 
258 		cp++;
259 	}
260 	pktw->pcw_total_xfer += pktp->pkt_dma_len;
261 	pktp->pkt_cookies = hp->dmai_cookie - 1;
262 	hp->dmai_cookie = cp;
263 
264 	return (1);
265 }
266 #endif
267 
268 void scsi_free_cache_pkt(struct scsi_address *, struct scsi_pkt *);
269 
270 struct scsi_pkt *
271 scsi_init_cache_pkt(struct scsi_address *ap, struct scsi_pkt *in_pktp,
272     struct buf *bp, int cmdlen, int statuslen, int pplen,
273     int flags, int (*callback)(caddr_t), caddr_t callback_arg)
274 {
275 	struct scsi_pkt_cache_wrapper *pktw;
276 	scsi_hba_tran_t *tranp = ap->a_hba_tran;
277 	int		(*func)(caddr_t);
278 
279 	func = (callback == SLEEP_FUNC) ? SLEEP_FUNC : NULL_FUNC;
280 
281 	if (in_pktp == NULL) {
282 		int kf;
283 
284 		if (callback == SLEEP_FUNC)
285 			kf = KM_SLEEP;
286 		else
287 			kf = KM_NOSLEEP;
288 		/*
289 		 * By using kmem_cache_alloc(), the layout of the
290 		 * scsi_pkt, scsi_pkt_cache_wrapper, hba private data,
291 		 * cdb, tgt driver private data, and status block is
292 		 * as below.
293 		 *
294 		 * This is a piece of contiguous memory starting from
295 		 * the first structure field scsi_pkt in the struct
296 		 * scsi_pkt_cache_wrapper, followed by the hba private
297 		 * data, pkt_cdbp, the tgt driver private data and
298 		 * pkt_scbp.
299 		 *
300 		 * |----------------------------|--------------------->
301 		 * |	struct scsi_pkt		|	struct
302 		 * |	......			|scsi_pkt_cache_wrapper
303 		 * |	pcw_flags		|
304 		 * |----------------------------|<---------------------
305 		 * |	hba private data	|tranp->tran_hba_len
306 		 * |----------------------------|
307 		 * |	pkt_cdbp		|DEFAULT_CDBLEN
308 		 * |----------------------------|
309 		 * |	tgt private data	|DEFAULT_PRIVLEN
310 		 * |----------------------------|
311 		 * |	pkt_scbp		|DEFAULT_SCBLEN
312 		 * |----------------------------|
313 		 *
314 		 * If the actual data length of the cdb, or the tgt
315 		 * driver private data, or the status block is bigger
316 		 * than the default data length, kmem_alloc() will be
317 		 * called to get extra space.
318 		 */
319 		pktw = kmem_cache_alloc(tranp->tran_pkt_cache_ptr,
320 		    kf);
321 		if (pktw == NULL)
322 			goto fail1;
323 
324 		pktw->pcw_flags = 0;
325 		in_pktp = &(pktw->pcw_pkt);
326 		in_pktp->pkt_address = *ap;
327 
328 		/*
329 		 * target drivers should initialize pkt_comp and
330 		 * pkt_time, but sometimes they don't so initialize
331 		 * them here to be safe.
332 		 */
333 		in_pktp->pkt_flags = 0;
334 		in_pktp->pkt_time = 0;
335 		in_pktp->pkt_resid = 0;
336 		in_pktp->pkt_state = 0;
337 		in_pktp->pkt_statistics = 0;
338 		in_pktp->pkt_reason = 0;
339 		in_pktp->pkt_dma_offset = 0;
340 		in_pktp->pkt_dma_len = 0;
341 		in_pktp->pkt_dma_flags = 0;
342 		in_pktp->pkt_path_instance = 0;
343 		ASSERT(in_pktp->pkt_numcookies == 0);
344 		pktw->pcw_curwin = 0;
345 		pktw->pcw_totalwin = 0;
346 		pktw->pcw_total_xfer = 0;
347 
348 		in_pktp->pkt_cdblen = cmdlen;
349 		if ((tranp->tran_hba_flags & SCSI_HBA_TRAN_CDB) &&
350 		    (cmdlen > DEFAULT_CDBLEN)) {
351 			pktw->pcw_flags |= PCW_NEED_EXT_CDB;
352 			in_pktp->pkt_cdbp = kmem_alloc(cmdlen, kf);
353 			if (in_pktp->pkt_cdbp == NULL)
354 				goto fail2;
355 		}
356 		in_pktp->pkt_tgtlen = pplen;
357 		if (pplen > DEFAULT_PRIVLEN) {
358 			pktw->pcw_flags |= PCW_NEED_EXT_TGT;
359 			in_pktp->pkt_private = kmem_alloc(pplen, kf);
360 			if (in_pktp->pkt_private == NULL)
361 				goto fail3;
362 		}
363 		in_pktp->pkt_scblen = statuslen;
364 		if ((tranp->tran_hba_flags & SCSI_HBA_TRAN_SCB) &&
365 		    (statuslen > DEFAULT_SCBLEN)) {
366 			pktw->pcw_flags |= PCW_NEED_EXT_SCB;
367 			in_pktp->pkt_scbp = kmem_alloc(statuslen, kf);
368 			if (in_pktp->pkt_scbp == NULL)
369 				goto fail4;
370 		}
371 		if ((*tranp->tran_setup_pkt) (in_pktp,
372 		    func, NULL) == -1) {
373 				goto fail5;
374 		}
375 		if (cmdlen)
376 			bzero((void *)in_pktp->pkt_cdbp, cmdlen);
377 		if (pplen)
378 			bzero((void *)in_pktp->pkt_private, pplen);
379 		if (statuslen)
380 			bzero((void *)in_pktp->pkt_scbp, statuslen);
381 	} else
382 		pktw = (struct scsi_pkt_cache_wrapper *)in_pktp;
383 
384 	if (bp && bp->b_bcount) {
385 
386 		int dma_flags = 0;
387 
388 		/*
389 		 * we need to transfer data, so we alloc dma resources
390 		 * for this packet
391 		 */
392 		/*CONSTCOND*/
393 		ASSERT(SLEEP_FUNC == DDI_DMA_SLEEP);
394 		/*CONSTCOND*/
395 		ASSERT(NULL_FUNC == DDI_DMA_DONTWAIT);
396 
397 #if defined(_DMA_USES_PHYSADDR)
398 		/*
399 		 * with an IOMMU we map everything, so we don't
400 		 * need to bother with this
401 		 */
402 		if (tranp->tran_dma_attr.dma_attr_granular !=
403 		    pktw->pcw_granular) {
404 
405 			ddi_dma_free_handle(&in_pktp->pkt_handle);
406 			if (ddi_dma_alloc_handle(tranp->tran_hba_dip,
407 			    &tranp->tran_dma_attr,
408 			    func, NULL,
409 			    &in_pktp->pkt_handle) != DDI_SUCCESS) {
410 
411 				in_pktp->pkt_handle = NULL;
412 				return (NULL);
413 			}
414 			pktw->pcw_granular =
415 			    tranp->tran_dma_attr.dma_attr_granular;
416 		}
417 #endif
418 
419 		if (in_pktp->pkt_numcookies == 0) {
420 			pktw->pcw_bp = bp;
421 			/*
422 			 * set dma flags; the "read" case must be first
423 			 * since B_WRITE isn't always be set for writes.
424 			 */
425 			if (bp->b_flags & B_READ) {
426 				dma_flags |= DDI_DMA_READ;
427 			} else {
428 				dma_flags |= DDI_DMA_WRITE;
429 			}
430 			if (flags & PKT_CONSISTENT)
431 				dma_flags |= DDI_DMA_CONSISTENT;
432 			if (flags & PKT_DMA_PARTIAL)
433 				dma_flags |= DDI_DMA_PARTIAL;
434 
435 #if defined(__sparc)
436 			/*
437 			 * workaround for byte hole issue on psycho and
438 			 * schizo pre 2.1
439 			 */
440 			if ((bp->b_flags & B_READ) && ((bp->b_flags &
441 			    (B_PAGEIO|B_REMAPPED)) != B_PAGEIO) &&
442 			    (((uintptr_t)bp->b_un.b_addr & 0x7) ||
443 			    ((uintptr_t)bp->b_bcount & 0x7))) {
444 				dma_flags |= DDI_DMA_CONSISTENT;
445 			}
446 #endif
447 			if (!scsi_dma_buf_bind_attr(pktw, bp,
448 			    dma_flags, callback, callback_arg)) {
449 				return (NULL);
450 			} else {
451 				pktw->pcw_flags |= PCW_BOUND;
452 			}
453 		}
454 
455 #if defined(_DMA_USES_PHYSADDR)
456 		if (!scsi_dmaget_attr(pktw)) {
457 			scsi_dmafree_attr(in_pktp);
458 			goto fail5;
459 		}
460 #else
461 		in_pktp->pkt_cookies = &pktw->pcw_cookie;
462 		in_pktp->pkt_dma_len = pktw->pcw_cookie.dmac_size;
463 		pktw->pcw_total_xfer += in_pktp->pkt_dma_len;
464 #endif
465 		ASSERT(in_pktp->pkt_numcookies <=
466 		    tranp->tran_dma_attr.dma_attr_sgllen);
467 		ASSERT(pktw->pcw_total_xfer <= bp->b_bcount);
468 		in_pktp->pkt_resid = bp->b_bcount -
469 		    pktw->pcw_total_xfer;
470 
471 		ASSERT((in_pktp->pkt_resid % pktw->pcw_granular) ==
472 		    0);
473 	} else {
474 		/* !bp or no b_bcount */
475 		in_pktp->pkt_resid = 0;
476 	}
477 	return (in_pktp);
478 
479 fail5:
480 	if (pktw->pcw_flags & PCW_NEED_EXT_SCB) {
481 		kmem_free(in_pktp->pkt_scbp, statuslen);
482 		in_pktp->pkt_scbp = (opaque_t)((char *)in_pktp +
483 		    tranp->tran_hba_len + DEFAULT_PRIVLEN +
484 		    sizeof (struct scsi_pkt_cache_wrapper));
485 		if ((A_TO_TRAN(ap))->tran_hba_flags & SCSI_HBA_TRAN_CDB)
486 			in_pktp->pkt_scbp = (opaque_t)((in_pktp->pkt_scbp) +
487 			    DEFAULT_CDBLEN);
488 		in_pktp->pkt_scblen = 0;
489 	}
490 fail4:
491 	if (pktw->pcw_flags & PCW_NEED_EXT_TGT) {
492 		kmem_free(in_pktp->pkt_private, pplen);
493 		in_pktp->pkt_tgtlen = 0;
494 		in_pktp->pkt_private = NULL;
495 	}
496 fail3:
497 	if (pktw->pcw_flags & PCW_NEED_EXT_CDB) {
498 		kmem_free(in_pktp->pkt_cdbp, cmdlen);
499 		in_pktp->pkt_cdbp = (opaque_t)((char *)in_pktp +
500 		    tranp->tran_hba_len +
501 		    sizeof (struct scsi_pkt_cache_wrapper));
502 		in_pktp->pkt_cdblen = 0;
503 	}
504 	pktw->pcw_flags &=
505 	    ~(PCW_NEED_EXT_CDB|PCW_NEED_EXT_TGT|PCW_NEED_EXT_SCB);
506 fail2:
507 	kmem_cache_free(tranp->tran_pkt_cache_ptr, pktw);
508 fail1:
509 	if (callback != NULL_FUNC && callback != SLEEP_FUNC) {
510 		ddi_set_callback(callback, callback_arg,
511 		    &scsi_callback_id);
512 	}
513 
514 	return (NULL);
515 }
516 
517 void
518 scsi_free_cache_pkt(struct scsi_address *ap, struct scsi_pkt *pktp)
519 {
520 	struct scsi_pkt_cache_wrapper *pktw;
521 
522 	(*A_TO_TRAN(ap)->tran_teardown_pkt)(pktp);
523 	pktw = (struct scsi_pkt_cache_wrapper *)pktp;
524 	if (pktw->pcw_flags & PCW_BOUND)
525 		scsi_dmafree_attr(pktp);
526 
527 	/*
528 	 * if we allocated memory for anything that wouldn't fit, free
529 	 * the memory and restore the pointers
530 	 */
531 	if (pktw->pcw_flags & PCW_NEED_EXT_SCB) {
532 		kmem_free(pktp->pkt_scbp, pktp->pkt_scblen);
533 		pktp->pkt_scbp = (opaque_t)((char *)pktp +
534 		    (A_TO_TRAN(ap))->tran_hba_len +
535 		    DEFAULT_PRIVLEN + sizeof (struct scsi_pkt_cache_wrapper));
536 		if ((A_TO_TRAN(ap))->tran_hba_flags & SCSI_HBA_TRAN_CDB)
537 			pktp->pkt_scbp = (opaque_t)((pktp->pkt_scbp) +
538 			    DEFAULT_CDBLEN);
539 		pktp->pkt_scblen = 0;
540 	}
541 	if (pktw->pcw_flags & PCW_NEED_EXT_TGT) {
542 		kmem_free(pktp->pkt_private, pktp->pkt_tgtlen);
543 		pktp->pkt_tgtlen = 0;
544 		pktp->pkt_private = NULL;
545 	}
546 	if (pktw->pcw_flags & PCW_NEED_EXT_CDB) {
547 		kmem_free(pktp->pkt_cdbp, pktp->pkt_cdblen);
548 		pktp->pkt_cdbp = (opaque_t)((char *)pktp +
549 		    (A_TO_TRAN(ap))->tran_hba_len +
550 		    sizeof (struct scsi_pkt_cache_wrapper));
551 		pktp->pkt_cdblen = 0;
552 	}
553 	pktw->pcw_flags &=
554 	    ~(PCW_NEED_EXT_CDB|PCW_NEED_EXT_TGT|PCW_NEED_EXT_SCB);
555 	kmem_cache_free(A_TO_TRAN(ap)->tran_pkt_cache_ptr, pktw);
556 
557 	if (scsi_callback_id != 0) {
558 		ddi_run_callback(&scsi_callback_id);
559 	}
560 
561 }
562 
563 
564 struct scsi_pkt *
565 scsi_init_pkt(struct scsi_address *ap, struct scsi_pkt *in_pktp,
566     struct buf *bp, int cmdlen, int statuslen, int pplen,
567     int flags, int (*callback)(caddr_t), caddr_t callback_arg)
568 {
569 	struct scsi_pkt *pktp;
570 	scsi_hba_tran_t *tranp = ap->a_hba_tran;
571 	int		(*func)(caddr_t);
572 
573 	TRACE_5(TR_FAC_SCSI_RES, TR_SCSI_INIT_PKT_START,
574 "scsi_init_pkt_start: addr %p in_pktp %p cmdlen %d statuslen %d pplen %d",
575 	    ap, in_pktp, cmdlen, statuslen, pplen);
576 
577 #if defined(__i386) || defined(__amd64)
578 	if (flags & PKT_CONSISTENT_OLD) {
579 		flags &= ~PKT_CONSISTENT_OLD;
580 		flags |= PKT_CONSISTENT;
581 	}
582 #endif
583 
584 	func = (callback == SLEEP_FUNC) ? SLEEP_FUNC : NULL_FUNC;
585 
586 	pktp = (*tranp->tran_init_pkt) (ap, in_pktp, bp, cmdlen,
587 	    statuslen, pplen, flags, func, NULL);
588 	if (pktp == NULL) {
589 		if (callback != NULL_FUNC && callback != SLEEP_FUNC) {
590 			ddi_set_callback(callback, callback_arg,
591 			    &scsi_callback_id);
592 		}
593 	}
594 
595 	TRACE_1(TR_FAC_SCSI_RES, TR_SCSI_INIT_PKT_END,
596 	    "scsi_init_pkt_end: pktp %p", pktp);
597 	return (pktp);
598 }
599 
600 void
601 scsi_destroy_pkt(struct scsi_pkt *pkt)
602 {
603 	struct scsi_address	*ap = P_TO_ADDR(pkt);
604 
605 	TRACE_1(TR_FAC_SCSI_RES, TR_SCSI_DESTROY_PKT_START,
606 	    "scsi_destroy_pkt_start: pkt %p", pkt);
607 
608 	(*A_TO_TRAN(ap)->tran_destroy_pkt)(ap, pkt);
609 
610 	if (scsi_callback_id != 0) {
611 		ddi_run_callback(&scsi_callback_id);
612 	}
613 
614 	TRACE_0(TR_FAC_SCSI_RES, TR_SCSI_DESTROY_PKT_END,
615 	    "scsi_destroy_pkt_end");
616 }
617 
618 
619 /*
620  *	Generic Resource Allocation Routines
621  */
622 
623 struct scsi_pkt *
624 scsi_resalloc(struct scsi_address *ap, int cmdlen, int statuslen,
625     opaque_t dmatoken, int (*callback)())
626 {
627 	register struct	scsi_pkt *pkt;
628 	register scsi_hba_tran_t *tranp = ap->a_hba_tran;
629 	register int			(*func)(caddr_t);
630 
631 	func = (callback == SLEEP_FUNC) ? SLEEP_FUNC : NULL_FUNC;
632 
633 	pkt = (*tranp->tran_init_pkt) (ap, NULL, (struct buf *)dmatoken,
634 	    cmdlen, statuslen, 0, 0, func, NULL);
635 	if (pkt == NULL) {
636 		if (callback != NULL_FUNC && callback != SLEEP_FUNC) {
637 			ddi_set_callback(callback, NULL, &scsi_callback_id);
638 		}
639 	}
640 
641 	return (pkt);
642 }
643 
644 struct scsi_pkt *
645 scsi_pktalloc(struct scsi_address *ap, int cmdlen, int statuslen,
646     int (*callback)())
647 {
648 	struct scsi_pkt		*pkt;
649 	struct scsi_hba_tran	*tran = ap->a_hba_tran;
650 	register int			(*func)(caddr_t);
651 
652 	func = (callback == SLEEP_FUNC) ? SLEEP_FUNC : NULL_FUNC;
653 
654 	pkt = (*tran->tran_init_pkt) (ap, NULL, NULL, cmdlen,
655 	    statuslen, 0, 0, func, NULL);
656 	if (pkt == NULL) {
657 		if (callback != NULL_FUNC && callback != SLEEP_FUNC) {
658 			ddi_set_callback(callback, NULL, &scsi_callback_id);
659 		}
660 	}
661 
662 	return (pkt);
663 }
664 
665 struct scsi_pkt *
666 scsi_dmaget(struct scsi_pkt *pkt, opaque_t dmatoken, int (*callback)())
667 {
668 	struct scsi_pkt		*new_pkt;
669 	register int		(*func)(caddr_t);
670 
671 	func = (callback == SLEEP_FUNC) ? SLEEP_FUNC : NULL_FUNC;
672 
673 	new_pkt = (*P_TO_TRAN(pkt)->tran_init_pkt) (&pkt->pkt_address,
674 	    pkt, (struct buf *)dmatoken,
675 	    0, 0, 0, 0, func, NULL);
676 	ASSERT(new_pkt == pkt || new_pkt == NULL);
677 	if (new_pkt == NULL) {
678 		if (callback != NULL_FUNC && callback != SLEEP_FUNC) {
679 			ddi_set_callback(callback, NULL, &scsi_callback_id);
680 		}
681 	}
682 
683 	return (new_pkt);
684 }
685 
686 
687 /*
688  *	Generic Resource Deallocation Routines
689  */
690 
691 void
692 scsi_dmafree(struct scsi_pkt *pkt)
693 {
694 	register struct scsi_address	*ap = P_TO_ADDR(pkt);
695 
696 	(*A_TO_TRAN(ap)->tran_dmafree)(ap, pkt);
697 
698 	if (scsi_callback_id != 0) {
699 		ddi_run_callback(&scsi_callback_id);
700 	}
701 }
702 
703 /*ARGSUSED*/
704 void
705 scsi_cache_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt)
706 {
707 	ASSERT(pkt->pkt_numcookies == 0 ||
708 	    ((struct scsi_pkt_cache_wrapper *)pkt)->pcw_flags & PCW_BOUND);
709 	ASSERT(pkt->pkt_handle != NULL);
710 	scsi_dmafree_attr(pkt);
711 
712 	if (scsi_callback_id != 0) {
713 		ddi_run_callback(&scsi_callback_id);
714 	}
715 }
716 
717 void
718 scsi_sync_pkt(struct scsi_pkt *pkt)
719 {
720 	register struct scsi_address	*ap = P_TO_ADDR(pkt);
721 
722 	if (pkt->pkt_state & STATE_XFERRED_DATA)
723 		(*A_TO_TRAN(ap)->tran_sync_pkt)(ap, pkt);
724 }
725 
726 /*ARGSUSED*/
727 void
728 scsi_sync_cache_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
729 {
730 	if (pkt->pkt_handle &&
731 	    (pkt->pkt_dma_flags & (DDI_DMA_WRITE | DDI_DMA_READ))) {
732 		(void) ddi_dma_sync(pkt->pkt_handle,
733 		    pkt->pkt_dma_offset, pkt->pkt_dma_len,
734 		    (pkt->pkt_dma_flags & DDI_DMA_WRITE) ?
735 		    DDI_DMA_SYNC_FORDEV : DDI_DMA_SYNC_FORCPU);
736 	}
737 }
738 
739 void
740 scsi_resfree(struct scsi_pkt *pkt)
741 {
742 	register struct scsi_address	*ap = P_TO_ADDR(pkt);
743 	(*A_TO_TRAN(ap)->tran_destroy_pkt)(ap, pkt);
744 
745 	if (scsi_callback_id != 0) {
746 		ddi_run_callback(&scsi_callback_id);
747 	}
748 }
749