xref: /onnv-gate/usr/src/uts/common/io/scsi/impl/scsi_resource.c (revision 10696:cd0f390dd9e2)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51106Smrj  * Common Development and Distribution License (the "License").
61106Smrj  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
211106Smrj 
220Sstevel@tonic-gate /*
238487SLi.He@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #include <sys/scsi/scsi.h>
280Sstevel@tonic-gate #include <sys/vtrace.h>
290Sstevel@tonic-gate 
300Sstevel@tonic-gate 
310Sstevel@tonic-gate #define	A_TO_TRAN(ap)	((ap)->a_hba_tran)
320Sstevel@tonic-gate #define	P_TO_TRAN(pkt)	((pkt)->pkt_address.a_hba_tran)
330Sstevel@tonic-gate #define	P_TO_ADDR(pkt)	(&((pkt)->pkt_address))
340Sstevel@tonic-gate 
350Sstevel@tonic-gate /*
360Sstevel@tonic-gate  * Callback id
370Sstevel@tonic-gate  */
380Sstevel@tonic-gate uintptr_t scsi_callback_id = 0;
390Sstevel@tonic-gate 
401106Smrj extern ddi_dma_attr_t scsi_alloc_attr;
410Sstevel@tonic-gate 
420Sstevel@tonic-gate struct buf *
scsi_alloc_consistent_buf(struct scsi_address * ap,struct buf * in_bp,size_t datalen,uint_t bflags,int (* callback)(caddr_t),caddr_t callback_arg)430Sstevel@tonic-gate scsi_alloc_consistent_buf(struct scsi_address *ap,
440Sstevel@tonic-gate     struct buf *in_bp, size_t datalen, uint_t bflags,
450Sstevel@tonic-gate     int (*callback)(caddr_t), caddr_t callback_arg)
460Sstevel@tonic-gate {
470Sstevel@tonic-gate 	dev_info_t	*pdip;
480Sstevel@tonic-gate 	struct		buf *bp;
490Sstevel@tonic-gate 	int		kmflag;
501106Smrj 	size_t		rlen;
510Sstevel@tonic-gate 
520Sstevel@tonic-gate 	TRACE_0(TR_FAC_SCSI_RES, TR_SCSI_ALLOC_CONSISTENT_BUF_START,
536383Sjw149990 	    "scsi_alloc_consistent_buf_start");
540Sstevel@tonic-gate 
550Sstevel@tonic-gate 	if (!in_bp) {
560Sstevel@tonic-gate 		kmflag = (callback == SLEEP_FUNC) ? KM_SLEEP : KM_NOSLEEP;
570Sstevel@tonic-gate 		if ((bp = getrbuf(kmflag)) == NULL) {
580Sstevel@tonic-gate 			goto no_resource;
590Sstevel@tonic-gate 		}
600Sstevel@tonic-gate 	} else {
610Sstevel@tonic-gate 		bp = in_bp;
620Sstevel@tonic-gate 
630Sstevel@tonic-gate 		/* we are establishing a new buffer memory association */
640Sstevel@tonic-gate 		bp->b_flags &= ~(B_PAGEIO | B_PHYS | B_REMAPPED | B_SHADOW);
650Sstevel@tonic-gate 		bp->b_proc = NULL;
660Sstevel@tonic-gate 		bp->b_pages = NULL;
670Sstevel@tonic-gate 		bp->b_shadow = NULL;
680Sstevel@tonic-gate 	}
690Sstevel@tonic-gate 
700Sstevel@tonic-gate 	/* limit bits that can be set by bflags argument */
710Sstevel@tonic-gate 	ASSERT(!(bflags & ~(B_READ | B_WRITE)));
720Sstevel@tonic-gate 	bflags &= (B_READ | B_WRITE);
730Sstevel@tonic-gate 	bp->b_un.b_addr = 0;
740Sstevel@tonic-gate 
750Sstevel@tonic-gate 	if (datalen) {
760Sstevel@tonic-gate 		pdip = (A_TO_TRAN(ap))->tran_hba_dip;
770Sstevel@tonic-gate 
781106Smrj 		/*
791106Smrj 		 * use i_ddi_mem_alloc() for now until we have an interface to
801106Smrj 		 * allocate memory for DMA which doesn't require a DMA handle.
811106Smrj 		 * ddi_iopb_alloc() is obsolete and we want more flexibility in
821106Smrj 		 * controlling the DMA address constraints.
831106Smrj 		 */
841106Smrj 		while (i_ddi_mem_alloc(pdip, &scsi_alloc_attr, datalen,
851106Smrj 		    ((callback == SLEEP_FUNC) ? 1 : 0), 0, NULL,
861106Smrj 		    &bp->b_un.b_addr, &rlen, NULL) != DDI_SUCCESS) {
870Sstevel@tonic-gate 			if (callback == SLEEP_FUNC) {
880Sstevel@tonic-gate 				delay(drv_usectohz(10000));
890Sstevel@tonic-gate 			} else {
900Sstevel@tonic-gate 				if (!in_bp)
910Sstevel@tonic-gate 					freerbuf(bp);
920Sstevel@tonic-gate 				goto no_resource;
930Sstevel@tonic-gate 			}
940Sstevel@tonic-gate 		}
950Sstevel@tonic-gate 		bp->b_flags |= bflags;
960Sstevel@tonic-gate 	}
970Sstevel@tonic-gate 	bp->b_bcount = datalen;
980Sstevel@tonic-gate 	bp->b_resid = 0;
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate 	TRACE_0(TR_FAC_SCSI_RES, TR_SCSI_ALLOC_CONSISTENT_BUF_END,
1016383Sjw149990 	    "scsi_alloc_consistent_buf_end");
1020Sstevel@tonic-gate 	return (bp);
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate no_resource:
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate 	if (callback != NULL_FUNC && callback != SLEEP_FUNC) {
1070Sstevel@tonic-gate 		ddi_set_callback(callback, callback_arg,
1086383Sjw149990 		    &scsi_callback_id);
1090Sstevel@tonic-gate 	}
1100Sstevel@tonic-gate 	TRACE_0(TR_FAC_SCSI_RES,
1110Sstevel@tonic-gate 	    TR_SCSI_ALLOC_CONSISTENT_BUF_RETURN1_END,
1120Sstevel@tonic-gate 	    "scsi_alloc_consistent_buf_end (return1)");
1130Sstevel@tonic-gate 	return (NULL);
1140Sstevel@tonic-gate }
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate void
scsi_free_consistent_buf(struct buf * bp)1170Sstevel@tonic-gate scsi_free_consistent_buf(struct buf *bp)
1180Sstevel@tonic-gate {
1190Sstevel@tonic-gate 	TRACE_0(TR_FAC_SCSI_RES, TR_SCSI_FREE_CONSISTENT_BUF_START,
1206383Sjw149990 	    "scsi_free_consistent_buf_start");
1210Sstevel@tonic-gate 	if (!bp)
1220Sstevel@tonic-gate 		return;
1230Sstevel@tonic-gate 	if (bp->b_un.b_addr)
1241900Seota 		i_ddi_mem_free((caddr_t)bp->b_un.b_addr, NULL);
1250Sstevel@tonic-gate 	freerbuf(bp);
1260Sstevel@tonic-gate 	if (scsi_callback_id != 0) {
1270Sstevel@tonic-gate 		ddi_run_callback(&scsi_callback_id);
1280Sstevel@tonic-gate 	}
1290Sstevel@tonic-gate 	TRACE_0(TR_FAC_SCSI_RES, TR_SCSI_FREE_CONSISTENT_BUF_END,
1306383Sjw149990 	    "scsi_free_consistent_buf_end");
1310Sstevel@tonic-gate }
1320Sstevel@tonic-gate 
1331998Staylor void
scsi_dmafree_attr(struct scsi_pkt * pktp)1341998Staylor scsi_dmafree_attr(struct scsi_pkt *pktp)
1351998Staylor {
1361998Staylor 	struct scsi_pkt_cache_wrapper *pktw =
1376383Sjw149990 	    (struct scsi_pkt_cache_wrapper *)pktp;
1381998Staylor 
1391998Staylor 	if (pktw->pcw_flags & PCW_BOUND) {
1401998Staylor 		if (ddi_dma_unbind_handle(pktp->pkt_handle) !=
1411998Staylor 		    DDI_SUCCESS)
1421998Staylor 			cmn_err(CE_WARN, "scsi_dmafree_attr: "
1431998Staylor 			    "unbind handle failed");
1441998Staylor 		pktw->pcw_flags &= ~PCW_BOUND;
1451998Staylor 	}
1461998Staylor 	pktp->pkt_numcookies = 0;
1478487SLi.He@Sun.COM 	pktw->pcw_totalwin = 0;
1481998Staylor }
1491998Staylor 
1501998Staylor struct buf *
scsi_pkt2bp(struct scsi_pkt * pkt)1511998Staylor scsi_pkt2bp(struct scsi_pkt *pkt)
1521998Staylor {
1531998Staylor 	return (((struct scsi_pkt_cache_wrapper *)pkt)->pcw_bp);
1541998Staylor }
1551998Staylor 
1561998Staylor int
scsi_dma_buf_bind_attr(struct scsi_pkt_cache_wrapper * pktw,struct buf * bp,int dma_flags,int (* callback)(),caddr_t arg)1571998Staylor scsi_dma_buf_bind_attr(struct scsi_pkt_cache_wrapper *pktw,
1581998Staylor 			struct buf	*bp,
1591998Staylor 			int		 dma_flags,
1601998Staylor 			int		(*callback)(),
1611998Staylor 			caddr_t		 arg)
1621998Staylor {
1631998Staylor 	struct scsi_pkt *pktp = &(pktw->pcw_pkt);
1641998Staylor 	int	 status;
1651998Staylor 
1661998Staylor 	/*
1671998Staylor 	 * First time, need to establish the handle.
1681998Staylor 	 */
1691998Staylor 
1701998Staylor 	ASSERT(pktp->pkt_numcookies == 0);
1711998Staylor 	ASSERT(pktw->pcw_totalwin == 0);
1721998Staylor 
1731998Staylor 	status = ddi_dma_buf_bind_handle(pktp->pkt_handle, bp, dma_flags,
1746383Sjw149990 	    callback, arg, &pktw->pcw_cookie,
1756383Sjw149990 	    &pktp->pkt_numcookies);
1761998Staylor 
1771998Staylor 	switch (status) {
1781998Staylor 	case DDI_DMA_MAPPED:
1791998Staylor 		pktw->pcw_totalwin = 1;
1801998Staylor 		break;
1811998Staylor 
1821998Staylor 	case DDI_DMA_PARTIAL_MAP:
1831998Staylor 		/* enable first call to ddi_dma_getwin */
1841998Staylor 		if (ddi_dma_numwin(pktp->pkt_handle,
1851998Staylor 		    &pktw->pcw_totalwin) != DDI_SUCCESS) {
1861998Staylor 			bp->b_error = 0;
1871998Staylor 			return (0);
1881998Staylor 		}
1891998Staylor 		break;
1901998Staylor 
1911998Staylor 	case DDI_DMA_NORESOURCES:
1921998Staylor 		bp->b_error = 0;
1931998Staylor 		return (0);
1941998Staylor 
1951998Staylor 	case DDI_DMA_TOOBIG:
1961998Staylor 		bioerror(bp, EINVAL);
1971998Staylor 		return (0);
1981998Staylor 
1991998Staylor 	case DDI_DMA_NOMAPPING:
2001998Staylor 	case DDI_DMA_INUSE:
2011998Staylor 	default:
2021998Staylor 		bioerror(bp, EFAULT);
2031998Staylor 		return (0);
2041998Staylor 	}
2051998Staylor 
2061998Staylor 	/* initialize the loop controls for scsi_dmaget_attr() */
2071998Staylor 	pktw->pcw_curwin = 0;
2081998Staylor 	pktw->pcw_total_xfer = 0;
2091998Staylor 	pktp->pkt_dma_flags = dma_flags;
2101998Staylor 	return (1);
2111998Staylor }
2121998Staylor 
2131998Staylor #if defined(_DMA_USES_PHYSADDR)
2141998Staylor int
scsi_dmaget_attr(struct scsi_pkt_cache_wrapper * pktw)2151998Staylor scsi_dmaget_attr(struct scsi_pkt_cache_wrapper *pktw)
2161998Staylor {
2171998Staylor 	struct scsi_pkt *pktp = &(pktw->pcw_pkt);
2181998Staylor 
2191998Staylor 	int		status;
2201998Staylor 	int		num_segs = 0;
2211998Staylor 	ddi_dma_impl_t	*hp = (ddi_dma_impl_t *)pktp->pkt_handle;
2221998Staylor 	ddi_dma_cookie_t *cp;
2231998Staylor 
2241998Staylor 	if (pktw->pcw_curwin != 0) {
2251998Staylor 		ddi_dma_cookie_t	cookie;
2261998Staylor 
2271998Staylor 		/*
2281998Staylor 		 * start the next window, and get its first cookie
2291998Staylor 		 */
2301998Staylor 		status = ddi_dma_getwin(pktp->pkt_handle,
2316383Sjw149990 		    pktw->pcw_curwin, &pktp->pkt_dma_offset,
2326383Sjw149990 		    &pktp->pkt_dma_len, &cookie,
2336383Sjw149990 		    &pktp->pkt_numcookies);
2341998Staylor 		if (status != DDI_SUCCESS)
2351998Staylor 			return (0);
2361998Staylor 	}
2371998Staylor 
2381998Staylor 	/*
2391998Staylor 	 * start the Scatter/Gather loop
2401998Staylor 	 */
2411998Staylor 	cp = hp->dmai_cookie - 1;
2421998Staylor 	pktp->pkt_dma_len = 0;
2431998Staylor 	for (;;) {
2441998Staylor 
2451998Staylor 		/* take care of the loop-bookkeeping */
2461998Staylor 		pktp->pkt_dma_len += cp->dmac_size;
2471998Staylor 		num_segs++;
2481998Staylor 		/*
2491998Staylor 		 * if this was the last cookie in the current window
2501998Staylor 		 * set the loop controls start the next window and
2511998Staylor 		 * exit so the HBA can do this partial transfer
2521998Staylor 		 */
2531998Staylor 		if (num_segs >= pktp->pkt_numcookies) {
2541998Staylor 			pktw->pcw_curwin++;
2551998Staylor 			break;
2561998Staylor 		}
2571998Staylor 
2581998Staylor 		cp++;
2591998Staylor 	}
2601998Staylor 	pktw->pcw_total_xfer += pktp->pkt_dma_len;
2611998Staylor 	pktp->pkt_cookies = hp->dmai_cookie - 1;
2621998Staylor 	hp->dmai_cookie = cp;
2631998Staylor 
2641998Staylor 	return (1);
2651998Staylor }
2661998Staylor #endif
2671998Staylor 
2681006Staylor void scsi_free_cache_pkt(struct scsi_address *, struct scsi_pkt *);
2691006Staylor 
2701006Staylor struct scsi_pkt *
scsi_init_cache_pkt(struct scsi_address * ap,struct scsi_pkt * in_pktp,struct buf * bp,int cmdlen,int statuslen,int pplen,int flags,int (* callback)(caddr_t),caddr_t callback_arg)2711006Staylor scsi_init_cache_pkt(struct scsi_address *ap, struct scsi_pkt *in_pktp,
2721006Staylor     struct buf *bp, int cmdlen, int statuslen, int pplen,
2731006Staylor     int flags, int (*callback)(caddr_t), caddr_t callback_arg)
2741006Staylor {
2751006Staylor 	struct scsi_pkt_cache_wrapper *pktw;
2761006Staylor 	scsi_hba_tran_t *tranp = ap->a_hba_tran;
2771006Staylor 	int		(*func)(caddr_t);
2781006Staylor 
2791006Staylor 	func = (callback == SLEEP_FUNC) ? SLEEP_FUNC : NULL_FUNC;
2801006Staylor 
2811006Staylor 	if (in_pktp == NULL) {
2821006Staylor 		int kf;
2831006Staylor 
2841006Staylor 		if (callback == SLEEP_FUNC)
2851006Staylor 			kf = KM_SLEEP;
2861006Staylor 		else
2871006Staylor 			kf = KM_NOSLEEP;
28810243SLi.He@Sun.COM 		/*
28910243SLi.He@Sun.COM 		 * By using kmem_cache_alloc(), the layout of the
29010243SLi.He@Sun.COM 		 * scsi_pkt, scsi_pkt_cache_wrapper, hba private data,
29110243SLi.He@Sun.COM 		 * cdb, tgt driver private data, and status block is
29210243SLi.He@Sun.COM 		 * as below.
29310243SLi.He@Sun.COM 		 *
29410243SLi.He@Sun.COM 		 * This is a piece of contiguous memory starting from
29510243SLi.He@Sun.COM 		 * the first structure field scsi_pkt in the struct
29610243SLi.He@Sun.COM 		 * scsi_pkt_cache_wrapper, followed by the hba private
29710243SLi.He@Sun.COM 		 * data, pkt_cdbp, the tgt driver private data and
29810243SLi.He@Sun.COM 		 * pkt_scbp.
29910243SLi.He@Sun.COM 		 *
30010243SLi.He@Sun.COM 		 * |----------------------------|--------------------->
30110243SLi.He@Sun.COM 		 * |	struct scsi_pkt		|	struct
30210243SLi.He@Sun.COM 		 * |	......			|scsi_pkt_cache_wrapper
30310243SLi.He@Sun.COM 		 * |	pcw_flags		|
30410243SLi.He@Sun.COM 		 * |----------------------------|<---------------------
30510243SLi.He@Sun.COM 		 * |	hba private data	|tranp->tran_hba_len
30610243SLi.He@Sun.COM 		 * |----------------------------|
30710243SLi.He@Sun.COM 		 * |	pkt_cdbp		|DEFAULT_CDBLEN
30810243SLi.He@Sun.COM 		 * |----------------------------|
30910243SLi.He@Sun.COM 		 * |	tgt private data	|DEFAULT_PRIVLEN
31010243SLi.He@Sun.COM 		 * |----------------------------|
31110243SLi.He@Sun.COM 		 * |	pkt_scbp		|DEFAULT_SCBLEN
31210243SLi.He@Sun.COM 		 * |----------------------------|
31310243SLi.He@Sun.COM 		 *
31410243SLi.He@Sun.COM 		 * If the actual data length of the cdb, or the tgt
31510243SLi.He@Sun.COM 		 * driver private data, or the status block is bigger
31610243SLi.He@Sun.COM 		 * than the default data length, kmem_alloc() will be
31710243SLi.He@Sun.COM 		 * called to get extra space.
31810243SLi.He@Sun.COM 		 */
3191006Staylor 		pktw = kmem_cache_alloc(tranp->tran_pkt_cache_ptr,
3206383Sjw149990 		    kf);
3211006Staylor 		if (pktw == NULL)
3221006Staylor 			goto fail1;
3231006Staylor 
3241998Staylor 		pktw->pcw_flags = 0;
3251006Staylor 		in_pktp = &(pktw->pcw_pkt);
3261998Staylor 		in_pktp->pkt_address = *ap;
327*10696SDavid.Hollister@Sun.COM 
3281006Staylor 		/*
3291351Staylor 		 * target drivers should initialize pkt_comp and
3301351Staylor 		 * pkt_time, but sometimes they don't so initialize
3311351Staylor 		 * them here to be safe.
3321006Staylor 		 */
3331351Staylor 		in_pktp->pkt_flags = 0;
3341351Staylor 		in_pktp->pkt_time = 0;
3351006Staylor 		in_pktp->pkt_resid = 0;
3361006Staylor 		in_pktp->pkt_state = 0;
3371006Staylor 		in_pktp->pkt_statistics = 0;
3381006Staylor 		in_pktp->pkt_reason = 0;
3391998Staylor 		in_pktp->pkt_dma_offset = 0;
3401998Staylor 		in_pktp->pkt_dma_len = 0;
3411998Staylor 		in_pktp->pkt_dma_flags = 0;
3426640Scth 		in_pktp->pkt_path_instance = 0;
3431998Staylor 		ASSERT(in_pktp->pkt_numcookies == 0);
3441998Staylor 		pktw->pcw_curwin = 0;
3451998Staylor 		pktw->pcw_totalwin = 0;
3461998Staylor 		pktw->pcw_total_xfer = 0;
3471006Staylor 
3481006Staylor 		in_pktp->pkt_cdblen = cmdlen;
3491006Staylor 		if ((tranp->tran_hba_flags & SCSI_HBA_TRAN_CDB) &&
3501006Staylor 		    (cmdlen > DEFAULT_CDBLEN)) {
3511998Staylor 			pktw->pcw_flags |= PCW_NEED_EXT_CDB;
3521351Staylor 			in_pktp->pkt_cdbp = kmem_alloc(cmdlen, kf);
3531006Staylor 			if (in_pktp->pkt_cdbp == NULL)
3541006Staylor 				goto fail2;
3551006Staylor 		}
3561006Staylor 		in_pktp->pkt_tgtlen = pplen;
3571006Staylor 		if (pplen > DEFAULT_PRIVLEN) {
3581998Staylor 			pktw->pcw_flags |= PCW_NEED_EXT_TGT;
3591351Staylor 			in_pktp->pkt_private = kmem_alloc(pplen, kf);
3601006Staylor 			if (in_pktp->pkt_private == NULL)
3611006Staylor 				goto fail3;
3621006Staylor 		}
3631006Staylor 		in_pktp->pkt_scblen = statuslen;
3641006Staylor 		if ((tranp->tran_hba_flags & SCSI_HBA_TRAN_SCB) &&
3651006Staylor 		    (statuslen > DEFAULT_SCBLEN)) {
3661998Staylor 			pktw->pcw_flags |= PCW_NEED_EXT_SCB;
3671351Staylor 			in_pktp->pkt_scbp = kmem_alloc(statuslen, kf);
3681006Staylor 			if (in_pktp->pkt_scbp == NULL)
3691006Staylor 				goto fail4;
3701006Staylor 		}
3711006Staylor 		if ((*tranp->tran_setup_pkt) (in_pktp,
3726383Sjw149990 		    func, NULL) == -1) {
3731006Staylor 				goto fail5;
3741006Staylor 		}
3751351Staylor 		if (cmdlen)
3761351Staylor 			bzero((void *)in_pktp->pkt_cdbp, cmdlen);
3771351Staylor 		if (pplen)
3781351Staylor 			bzero((void *)in_pktp->pkt_private, pplen);
3791351Staylor 		if (statuslen)
3801351Staylor 			bzero((void *)in_pktp->pkt_scbp, statuslen);
3811998Staylor 	} else
3821998Staylor 		pktw = (struct scsi_pkt_cache_wrapper *)in_pktp;
3831998Staylor 
3841006Staylor 	if (bp && bp->b_bcount) {
3851998Staylor 
3861998Staylor 		int dma_flags = 0;
3871998Staylor 
3881998Staylor 		/*
3891998Staylor 		 * we need to transfer data, so we alloc dma resources
3901998Staylor 		 * for this packet
3911998Staylor 		 */
3921998Staylor 		/*CONSTCOND*/
3931998Staylor 		ASSERT(SLEEP_FUNC == DDI_DMA_SLEEP);
3941998Staylor 		/*CONSTCOND*/
3951998Staylor 		ASSERT(NULL_FUNC == DDI_DMA_DONTWAIT);
3961998Staylor 
3971998Staylor #if defined(_DMA_USES_PHYSADDR)
3981998Staylor 		/*
3991998Staylor 		 * with an IOMMU we map everything, so we don't
4001998Staylor 		 * need to bother with this
4011998Staylor 		 */
4021998Staylor 		if (tranp->tran_dma_attr.dma_attr_granular !=
4036383Sjw149990 		    pktw->pcw_granular) {
4041998Staylor 
4051998Staylor 			ddi_dma_free_handle(&in_pktp->pkt_handle);
4061998Staylor 			if (ddi_dma_alloc_handle(tranp->tran_hba_dip,
4076383Sjw149990 			    &tranp->tran_dma_attr,
4086383Sjw149990 			    func, NULL,
4096383Sjw149990 			    &in_pktp->pkt_handle) != DDI_SUCCESS) {
4101998Staylor 
4111998Staylor 				in_pktp->pkt_handle = NULL;
4121998Staylor 				return (NULL);
4131998Staylor 			}
4141998Staylor 			pktw->pcw_granular =
4156383Sjw149990 			    tranp->tran_dma_attr.dma_attr_granular;
4161006Staylor 		}
4171998Staylor #endif
4181998Staylor 
4191998Staylor 		if (in_pktp->pkt_numcookies == 0) {
4201998Staylor 			pktw->pcw_bp = bp;
4211998Staylor 			/*
4221998Staylor 			 * set dma flags; the "read" case must be first
4231998Staylor 			 * since B_WRITE isn't always be set for writes.
4241998Staylor 			 */
4251998Staylor 			if (bp->b_flags & B_READ) {
4261998Staylor 				dma_flags |= DDI_DMA_READ;
4271998Staylor 			} else {
4281998Staylor 				dma_flags |= DDI_DMA_WRITE;
4291998Staylor 			}
4301998Staylor 			if (flags & PKT_CONSISTENT)
4311998Staylor 				dma_flags |= DDI_DMA_CONSISTENT;
4321998Staylor 			if (flags & PKT_DMA_PARTIAL)
4331998Staylor 				dma_flags |= DDI_DMA_PARTIAL;
4341998Staylor 
4351998Staylor #if defined(__sparc)
4361998Staylor 			/*
4371998Staylor 			 * workaround for byte hole issue on psycho and
4381998Staylor 			 * schizo pre 2.1
4391998Staylor 			 */
4401998Staylor 			if ((bp->b_flags & B_READ) && ((bp->b_flags &
4411998Staylor 			    (B_PAGEIO|B_REMAPPED)) != B_PAGEIO) &&
4421998Staylor 			    (((uintptr_t)bp->b_un.b_addr & 0x7) ||
4431998Staylor 			    ((uintptr_t)bp->b_bcount & 0x7))) {
4441998Staylor 				dma_flags |= DDI_DMA_CONSISTENT;
4451998Staylor 			}
4461998Staylor #endif
4471998Staylor 			if (!scsi_dma_buf_bind_attr(pktw, bp,
4481998Staylor 			    dma_flags, callback, callback_arg)) {
4491998Staylor 				return (NULL);
4501998Staylor 			} else {
4511998Staylor 				pktw->pcw_flags |= PCW_BOUND;
4521998Staylor 			}
4531998Staylor 		}
4541998Staylor 
4551998Staylor #if defined(_DMA_USES_PHYSADDR)
4561998Staylor 		if (!scsi_dmaget_attr(pktw)) {
4571998Staylor 			scsi_dmafree_attr(in_pktp);
4581998Staylor 			goto fail5;
4591998Staylor 		}
4601998Staylor #else
4611998Staylor 		in_pktp->pkt_cookies = &pktw->pcw_cookie;
4621998Staylor 		in_pktp->pkt_dma_len = pktw->pcw_cookie.dmac_size;
4631998Staylor 		pktw->pcw_total_xfer += in_pktp->pkt_dma_len;
4641998Staylor #endif
4651998Staylor 		ASSERT(in_pktp->pkt_numcookies <=
4666383Sjw149990 		    tranp->tran_dma_attr.dma_attr_sgllen);
4671998Staylor 		ASSERT(pktw->pcw_total_xfer <= bp->b_bcount);
4681998Staylor 		in_pktp->pkt_resid = bp->b_bcount -
4696383Sjw149990 		    pktw->pcw_total_xfer;
4701998Staylor 
4711998Staylor 		ASSERT((in_pktp->pkt_resid % pktw->pcw_granular) ==
4726383Sjw149990 		    0);
4731998Staylor 	} else {
4741998Staylor 		/* !bp or no b_bcount */
4751998Staylor 		in_pktp->pkt_resid = 0;
4761006Staylor 	}
4771006Staylor 	return (in_pktp);
4781006Staylor 
4791006Staylor fail5:
4801998Staylor 	if (pktw->pcw_flags & PCW_NEED_EXT_SCB) {
4811006Staylor 		kmem_free(in_pktp->pkt_scbp, statuslen);
4821006Staylor 		in_pktp->pkt_scbp = (opaque_t)((char *)in_pktp +
4831006Staylor 		    tranp->tran_hba_len + DEFAULT_PRIVLEN +
48410243SLi.He@Sun.COM 		    sizeof (struct scsi_pkt_cache_wrapper));
4851006Staylor 		if ((A_TO_TRAN(ap))->tran_hba_flags & SCSI_HBA_TRAN_CDB)
4861006Staylor 			in_pktp->pkt_scbp = (opaque_t)((in_pktp->pkt_scbp) +
4876383Sjw149990 			    DEFAULT_CDBLEN);
4881006Staylor 		in_pktp->pkt_scblen = 0;
4891006Staylor 	}
4901006Staylor fail4:
4911998Staylor 	if (pktw->pcw_flags & PCW_NEED_EXT_TGT) {
4921006Staylor 		kmem_free(in_pktp->pkt_private, pplen);
4931006Staylor 		in_pktp->pkt_tgtlen = 0;
4941006Staylor 		in_pktp->pkt_private = NULL;
4951006Staylor 	}
4961006Staylor fail3:
4971998Staylor 	if (pktw->pcw_flags & PCW_NEED_EXT_CDB) {
4981006Staylor 		kmem_free(in_pktp->pkt_cdbp, cmdlen);
4991006Staylor 		in_pktp->pkt_cdbp = (opaque_t)((char *)in_pktp +
5001006Staylor 		    tranp->tran_hba_len +
50110243SLi.He@Sun.COM 		    sizeof (struct scsi_pkt_cache_wrapper));
5021006Staylor 		in_pktp->pkt_cdblen = 0;
5031006Staylor 	}
5041998Staylor 	pktw->pcw_flags &=
5051998Staylor 	    ~(PCW_NEED_EXT_CDB|PCW_NEED_EXT_TGT|PCW_NEED_EXT_SCB);
5061006Staylor fail2:
5071006Staylor 	kmem_cache_free(tranp->tran_pkt_cache_ptr, pktw);
5081006Staylor fail1:
5091006Staylor 	if (callback != NULL_FUNC && callback != SLEEP_FUNC) {
5101006Staylor 		ddi_set_callback(callback, callback_arg,
5116383Sjw149990 		    &scsi_callback_id);
5121006Staylor 	}
5131006Staylor 
5141006Staylor 	return (NULL);
5151006Staylor }
5161006Staylor 
5171006Staylor void
scsi_free_cache_pkt(struct scsi_address * ap,struct scsi_pkt * pktp)5181006Staylor scsi_free_cache_pkt(struct scsi_address *ap, struct scsi_pkt *pktp)
5191006Staylor {
5201006Staylor 	struct scsi_pkt_cache_wrapper *pktw;
5211006Staylor 
5221006Staylor 	(*A_TO_TRAN(ap)->tran_teardown_pkt)(pktp);
5231006Staylor 	pktw = (struct scsi_pkt_cache_wrapper *)pktp;
5241998Staylor 	if (pktw->pcw_flags & PCW_BOUND)
5251998Staylor 		scsi_dmafree_attr(pktp);
5261006Staylor 
5271006Staylor 	/*
5281006Staylor 	 * if we allocated memory for anything that wouldn't fit, free
5291006Staylor 	 * the memory and restore the pointers
5301006Staylor 	 */
5311998Staylor 	if (pktw->pcw_flags & PCW_NEED_EXT_SCB) {
5321006Staylor 		kmem_free(pktp->pkt_scbp, pktp->pkt_scblen);
5331006Staylor 		pktp->pkt_scbp = (opaque_t)((char *)pktp +
5341006Staylor 		    (A_TO_TRAN(ap))->tran_hba_len +
5351006Staylor 		    DEFAULT_PRIVLEN + sizeof (struct scsi_pkt_cache_wrapper));
5361006Staylor 		if ((A_TO_TRAN(ap))->tran_hba_flags & SCSI_HBA_TRAN_CDB)
5371006Staylor 			pktp->pkt_scbp = (opaque_t)((pktp->pkt_scbp) +
5386383Sjw149990 			    DEFAULT_CDBLEN);
5391006Staylor 		pktp->pkt_scblen = 0;
5401006Staylor 	}
5411998Staylor 	if (pktw->pcw_flags & PCW_NEED_EXT_TGT) {
5421006Staylor 		kmem_free(pktp->pkt_private, pktp->pkt_tgtlen);
5431006Staylor 		pktp->pkt_tgtlen = 0;
5441006Staylor 		pktp->pkt_private = NULL;
5451006Staylor 	}
5461998Staylor 	if (pktw->pcw_flags & PCW_NEED_EXT_CDB) {
5471006Staylor 		kmem_free(pktp->pkt_cdbp, pktp->pkt_cdblen);
5481006Staylor 		pktp->pkt_cdbp = (opaque_t)((char *)pktp +
5491006Staylor 		    (A_TO_TRAN(ap))->tran_hba_len +
5501006Staylor 		    sizeof (struct scsi_pkt_cache_wrapper));
5511006Staylor 		pktp->pkt_cdblen = 0;
5521006Staylor 	}
5531998Staylor 	pktw->pcw_flags &=
5541998Staylor 	    ~(PCW_NEED_EXT_CDB|PCW_NEED_EXT_TGT|PCW_NEED_EXT_SCB);
5551006Staylor 	kmem_cache_free(A_TO_TRAN(ap)->tran_pkt_cache_ptr, pktw);
5561006Staylor 
5571006Staylor 	if (scsi_callback_id != 0) {
5581006Staylor 		ddi_run_callback(&scsi_callback_id);
5591006Staylor 	}
5601006Staylor 
5611006Staylor }
5621006Staylor 
5631998Staylor 
5640Sstevel@tonic-gate struct scsi_pkt *
scsi_init_pkt(struct scsi_address * ap,struct scsi_pkt * in_pktp,struct buf * bp,int cmdlen,int statuslen,int pplen,int flags,int (* callback)(caddr_t),caddr_t callback_arg)5650Sstevel@tonic-gate scsi_init_pkt(struct scsi_address *ap, struct scsi_pkt *in_pktp,
5660Sstevel@tonic-gate     struct buf *bp, int cmdlen, int statuslen, int pplen,
5670Sstevel@tonic-gate     int flags, int (*callback)(caddr_t), caddr_t callback_arg)
5680Sstevel@tonic-gate {
5690Sstevel@tonic-gate 	struct scsi_pkt *pktp;
5700Sstevel@tonic-gate 	scsi_hba_tran_t *tranp = ap->a_hba_tran;
5710Sstevel@tonic-gate 	int		(*func)(caddr_t);
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate 	TRACE_5(TR_FAC_SCSI_RES, TR_SCSI_INIT_PKT_START,
5740Sstevel@tonic-gate "scsi_init_pkt_start: addr %p in_pktp %p cmdlen %d statuslen %d pplen %d",
5750Sstevel@tonic-gate 	    ap, in_pktp, cmdlen, statuslen, pplen);
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate #if defined(__i386) || defined(__amd64)
5780Sstevel@tonic-gate 	if (flags & PKT_CONSISTENT_OLD) {
5790Sstevel@tonic-gate 		flags &= ~PKT_CONSISTENT_OLD;
5800Sstevel@tonic-gate 		flags |= PKT_CONSISTENT;
5810Sstevel@tonic-gate 	}
5820Sstevel@tonic-gate #endif
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 	func = (callback == SLEEP_FUNC) ? SLEEP_FUNC : NULL_FUNC;
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 	pktp = (*tranp->tran_init_pkt) (ap, in_pktp, bp, cmdlen,
5876383Sjw149990 	    statuslen, pplen, flags, func, NULL);
5880Sstevel@tonic-gate 	if (pktp == NULL) {
5890Sstevel@tonic-gate 		if (callback != NULL_FUNC && callback != SLEEP_FUNC) {
5900Sstevel@tonic-gate 			ddi_set_callback(callback, callback_arg,
5916383Sjw149990 			    &scsi_callback_id);
5920Sstevel@tonic-gate 		}
5930Sstevel@tonic-gate 	}
5940Sstevel@tonic-gate 
5950Sstevel@tonic-gate 	TRACE_1(TR_FAC_SCSI_RES, TR_SCSI_INIT_PKT_END,
5966383Sjw149990 	    "scsi_init_pkt_end: pktp %p", pktp);
5970Sstevel@tonic-gate 	return (pktp);
5980Sstevel@tonic-gate }
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate void
scsi_destroy_pkt(struct scsi_pkt * pkt)6010Sstevel@tonic-gate scsi_destroy_pkt(struct scsi_pkt *pkt)
6020Sstevel@tonic-gate {
6030Sstevel@tonic-gate 	struct scsi_address	*ap = P_TO_ADDR(pkt);
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate 	TRACE_1(TR_FAC_SCSI_RES, TR_SCSI_DESTROY_PKT_START,
6066383Sjw149990 	    "scsi_destroy_pkt_start: pkt %p", pkt);
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 	(*A_TO_TRAN(ap)->tran_destroy_pkt)(ap, pkt);
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate 	if (scsi_callback_id != 0) {
6110Sstevel@tonic-gate 		ddi_run_callback(&scsi_callback_id);
6120Sstevel@tonic-gate 	}
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate 	TRACE_0(TR_FAC_SCSI_RES, TR_SCSI_DESTROY_PKT_END,
6156383Sjw149990 	    "scsi_destroy_pkt_end");
6160Sstevel@tonic-gate }
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate /*
6200Sstevel@tonic-gate  *	Generic Resource Allocation Routines
6210Sstevel@tonic-gate  */
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate struct scsi_pkt *
scsi_resalloc(struct scsi_address * ap,int cmdlen,int statuslen,opaque_t dmatoken,int (* callback)())6240Sstevel@tonic-gate scsi_resalloc(struct scsi_address *ap, int cmdlen, int statuslen,
6250Sstevel@tonic-gate     opaque_t dmatoken, int (*callback)())
6260Sstevel@tonic-gate {
6270Sstevel@tonic-gate 	register struct	scsi_pkt *pkt;
6280Sstevel@tonic-gate 	register scsi_hba_tran_t *tranp = ap->a_hba_tran;
6290Sstevel@tonic-gate 	register int			(*func)(caddr_t);
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	func = (callback == SLEEP_FUNC) ? SLEEP_FUNC : NULL_FUNC;
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate 	pkt = (*tranp->tran_init_pkt) (ap, NULL, (struct buf *)dmatoken,
6346383Sjw149990 	    cmdlen, statuslen, 0, 0, func, NULL);
6350Sstevel@tonic-gate 	if (pkt == NULL) {
6360Sstevel@tonic-gate 		if (callback != NULL_FUNC && callback != SLEEP_FUNC) {
6370Sstevel@tonic-gate 			ddi_set_callback(callback, NULL, &scsi_callback_id);
6380Sstevel@tonic-gate 		}
6390Sstevel@tonic-gate 	}
6400Sstevel@tonic-gate 
6410Sstevel@tonic-gate 	return (pkt);
6420Sstevel@tonic-gate }
6430Sstevel@tonic-gate 
6440Sstevel@tonic-gate struct scsi_pkt *
scsi_pktalloc(struct scsi_address * ap,int cmdlen,int statuslen,int (* callback)())6450Sstevel@tonic-gate scsi_pktalloc(struct scsi_address *ap, int cmdlen, int statuslen,
6460Sstevel@tonic-gate     int (*callback)())
6470Sstevel@tonic-gate {
6480Sstevel@tonic-gate 	struct scsi_pkt		*pkt;
6490Sstevel@tonic-gate 	struct scsi_hba_tran	*tran = ap->a_hba_tran;
6500Sstevel@tonic-gate 	register int			(*func)(caddr_t);
6510Sstevel@tonic-gate 
6520Sstevel@tonic-gate 	func = (callback == SLEEP_FUNC) ? SLEEP_FUNC : NULL_FUNC;
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate 	pkt = (*tran->tran_init_pkt) (ap, NULL, NULL, cmdlen,
6556383Sjw149990 	    statuslen, 0, 0, func, NULL);
6560Sstevel@tonic-gate 	if (pkt == NULL) {
6570Sstevel@tonic-gate 		if (callback != NULL_FUNC && callback != SLEEP_FUNC) {
6580Sstevel@tonic-gate 			ddi_set_callback(callback, NULL, &scsi_callback_id);
6590Sstevel@tonic-gate 		}
6600Sstevel@tonic-gate 	}
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate 	return (pkt);
6630Sstevel@tonic-gate }
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate struct scsi_pkt *
scsi_dmaget(struct scsi_pkt * pkt,opaque_t dmatoken,int (* callback)())6660Sstevel@tonic-gate scsi_dmaget(struct scsi_pkt *pkt, opaque_t dmatoken, int (*callback)())
6670Sstevel@tonic-gate {
6680Sstevel@tonic-gate 	struct scsi_pkt		*new_pkt;
6690Sstevel@tonic-gate 	register int		(*func)(caddr_t);
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate 	func = (callback == SLEEP_FUNC) ? SLEEP_FUNC : NULL_FUNC;
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 	new_pkt = (*P_TO_TRAN(pkt)->tran_init_pkt) (&pkt->pkt_address,
6746383Sjw149990 	    pkt, (struct buf *)dmatoken,
6756383Sjw149990 	    0, 0, 0, 0, func, NULL);
6760Sstevel@tonic-gate 	ASSERT(new_pkt == pkt || new_pkt == NULL);
6770Sstevel@tonic-gate 	if (new_pkt == NULL) {
6780Sstevel@tonic-gate 		if (callback != NULL_FUNC && callback != SLEEP_FUNC) {
6790Sstevel@tonic-gate 			ddi_set_callback(callback, NULL, &scsi_callback_id);
6800Sstevel@tonic-gate 		}
6810Sstevel@tonic-gate 	}
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate 	return (new_pkt);
6840Sstevel@tonic-gate }
6850Sstevel@tonic-gate 
6860Sstevel@tonic-gate 
6870Sstevel@tonic-gate /*
6880Sstevel@tonic-gate  *	Generic Resource Deallocation Routines
6890Sstevel@tonic-gate  */
6900Sstevel@tonic-gate 
6910Sstevel@tonic-gate void
scsi_dmafree(struct scsi_pkt * pkt)6920Sstevel@tonic-gate scsi_dmafree(struct scsi_pkt *pkt)
6930Sstevel@tonic-gate {
6940Sstevel@tonic-gate 	register struct scsi_address	*ap = P_TO_ADDR(pkt);
6951998Staylor 
6960Sstevel@tonic-gate 	(*A_TO_TRAN(ap)->tran_dmafree)(ap, pkt);
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate 	if (scsi_callback_id != 0) {
6990Sstevel@tonic-gate 		ddi_run_callback(&scsi_callback_id);
7000Sstevel@tonic-gate 	}
7010Sstevel@tonic-gate }
7020Sstevel@tonic-gate 
7031998Staylor /*ARGSUSED*/
7041998Staylor void
scsi_cache_dmafree(struct scsi_address * ap,struct scsi_pkt * pkt)7051998Staylor scsi_cache_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt)
7061998Staylor {
7077932SLi.He@Sun.COM 	ASSERT(pkt->pkt_numcookies == 0 ||
7087932SLi.He@Sun.COM 	    ((struct scsi_pkt_cache_wrapper *)pkt)->pcw_flags & PCW_BOUND);
7091998Staylor 	ASSERT(pkt->pkt_handle != NULL);
7101998Staylor 	scsi_dmafree_attr(pkt);
7111998Staylor 
7121998Staylor 	if (scsi_callback_id != 0) {
7131998Staylor 		ddi_run_callback(&scsi_callback_id);
7141998Staylor 	}
7151998Staylor }
7161998Staylor 
7170Sstevel@tonic-gate void
scsi_sync_pkt(struct scsi_pkt * pkt)7180Sstevel@tonic-gate scsi_sync_pkt(struct scsi_pkt *pkt)
7190Sstevel@tonic-gate {
7200Sstevel@tonic-gate 	register struct scsi_address	*ap = P_TO_ADDR(pkt);
7216383Sjw149990 
7226383Sjw149990 	if (pkt->pkt_state & STATE_XFERRED_DATA)
7236383Sjw149990 		(*A_TO_TRAN(ap)->tran_sync_pkt)(ap, pkt);
7240Sstevel@tonic-gate }
7250Sstevel@tonic-gate 
7261998Staylor /*ARGSUSED*/
7271998Staylor void
scsi_sync_cache_pkt(struct scsi_address * ap,struct scsi_pkt * pkt)7281998Staylor scsi_sync_cache_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
7291998Staylor {
7306157Scth 	if (pkt->pkt_handle &&
7316157Scth 	    (pkt->pkt_dma_flags & (DDI_DMA_WRITE | DDI_DMA_READ))) {
7321998Staylor 		(void) ddi_dma_sync(pkt->pkt_handle,
7336157Scth 		    pkt->pkt_dma_offset, pkt->pkt_dma_len,
7346157Scth 		    (pkt->pkt_dma_flags & DDI_DMA_WRITE) ?
7356157Scth 		    DDI_DMA_SYNC_FORDEV : DDI_DMA_SYNC_FORCPU);
7361998Staylor 	}
7371998Staylor }
7381998Staylor 
7390Sstevel@tonic-gate void
scsi_resfree(struct scsi_pkt * pkt)7400Sstevel@tonic-gate scsi_resfree(struct scsi_pkt *pkt)
7410Sstevel@tonic-gate {
7420Sstevel@tonic-gate 	register struct scsi_address	*ap = P_TO_ADDR(pkt);
7430Sstevel@tonic-gate 	(*A_TO_TRAN(ap)->tran_destroy_pkt)(ap, pkt);
7440Sstevel@tonic-gate 
7450Sstevel@tonic-gate 	if (scsi_callback_id != 0) {
7460Sstevel@tonic-gate 		ddi_run_callback(&scsi_callback_id);
7470Sstevel@tonic-gate 	}
7480Sstevel@tonic-gate }
749