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