Home | History | Annotate | Line # | Download | only in sbus
isp_sbus.c revision 1.4
      1  1.3  mjacob /* $NetBSD: isp_sbus.c,v 1.4 1998/12/28 19:12:26 mjacob Exp $ */
      2  1.4  mjacob /* release_12_28_98_A */
      3  1.1     mrg /*
      4  1.1     mrg  * SBus specific probe and attach routines for Qlogic ISP SCSI adapters.
      5  1.1     mrg  *
      6  1.1     mrg  * Copyright (c) 1997 by Matthew Jacob
      7  1.1     mrg  * NASA AMES Research Center
      8  1.1     mrg  * All rights reserved.
      9  1.1     mrg  *
     10  1.1     mrg  * Redistribution and use in source and binary forms, with or without
     11  1.1     mrg  * modification, are permitted provided that the following conditions
     12  1.1     mrg  * are met:
     13  1.1     mrg  * 1. Redistributions of source code must retain the above copyright
     14  1.1     mrg  *    notice immediately at the beginning of the file, without modification,
     15  1.1     mrg  *    this list of conditions, and the following disclaimer.
     16  1.1     mrg  * 2. Redistributions in binary form must reproduce the above copyright
     17  1.1     mrg  *    notice, this list of conditions and the following disclaimer in the
     18  1.1     mrg  *    documentation and/or other materials provided with the distribution.
     19  1.1     mrg  * 3. The name of the author may not be used to endorse or promote products
     20  1.1     mrg  *    derived from this software without specific prior written permission.
     21  1.1     mrg  *
     22  1.1     mrg  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     23  1.1     mrg  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24  1.1     mrg  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25  1.1     mrg  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
     26  1.1     mrg  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27  1.1     mrg  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     28  1.1     mrg  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29  1.1     mrg  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30  1.1     mrg  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31  1.1     mrg  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32  1.1     mrg  * SUCH DAMAGE.
     33  1.1     mrg  *
     34  1.1     mrg  */
     35  1.1     mrg 
     36  1.1     mrg #include <sys/param.h>
     37  1.1     mrg #include <sys/systm.h>
     38  1.1     mrg #include <sys/device.h>
     39  1.1     mrg #include <sys/kernel.h>
     40  1.1     mrg #include <sys/malloc.h>
     41  1.1     mrg #include <sys/queue.h>
     42  1.1     mrg 
     43  1.1     mrg #include <machine/autoconf.h>
     44  1.1     mrg #include <machine/cpu.h>
     45  1.1     mrg #include <machine/param.h>
     46  1.1     mrg #include <machine/vmparam.h>
     47  1.1     mrg 
     48  1.1     mrg #include <dev/ic/isp_netbsd.h>
     49  1.1     mrg #include <dev/microcode/isp/asm_sbus.h>
     50  1.1     mrg #include <dev/sbus/sbusvar.h>
     51  1.1     mrg 
     52  1.1     mrg static u_int16_t isp_sbus_rd_reg __P((struct ispsoftc *, int));
     53  1.1     mrg static void isp_sbus_wr_reg __P((struct ispsoftc *, int, u_int16_t));
     54  1.1     mrg static int isp_sbus_mbxdma __P((struct ispsoftc *));
     55  1.1     mrg static int isp_sbus_dmasetup __P((struct ispsoftc *, struct scsipi_xfer *,
     56  1.1     mrg 	ispreq_t *, u_int8_t *, u_int8_t));
     57  1.1     mrg static void isp_sbus_dmateardown __P((struct ispsoftc *, struct scsipi_xfer *,
     58  1.1     mrg 	u_int32_t));
     59  1.1     mrg 
     60  1.1     mrg static struct ispmdvec mdvec = {
     61  1.1     mrg 	isp_sbus_rd_reg,
     62  1.1     mrg 	isp_sbus_wr_reg,
     63  1.1     mrg 	isp_sbus_mbxdma,
     64  1.1     mrg 	isp_sbus_dmasetup,
     65  1.1     mrg 	isp_sbus_dmateardown,
     66  1.1     mrg 	NULL,
     67  1.1     mrg 	NULL,
     68  1.1     mrg 	NULL,
     69  1.1     mrg 	ISP_RISC_CODE,
     70  1.1     mrg 	ISP_CODE_LENGTH,
     71  1.1     mrg 	ISP_CODE_ORG,
     72  1.1     mrg 	ISP_CODE_VERSION,
     73  1.1     mrg 	0,
     74  1.1     mrg 	0
     75  1.1     mrg };
     76  1.1     mrg 
     77  1.1     mrg struct isp_sbussoftc {
     78  1.1     mrg 	struct ispsoftc	sbus_isp;
     79  1.1     mrg 	sdparam		sbus_dev;
     80  1.1     mrg 	bus_space_tag_t	sbus_bustag;
     81  1.1     mrg 	bus_dma_tag_t	sbus_dmatag;
     82  1.1     mrg 	volatile u_char	*sbus_reg;
     83  1.1     mrg 	int		sbus_node;
     84  1.1     mrg 	int		sbus_pri;
     85  1.1     mrg 	struct ispmdvec	sbus_mdvec;
     86  1.1     mrg 	bus_dmamap_t	sbus_dmamap[MAXISPREQUEST];
     87  1.1     mrg };
     88  1.1     mrg 
     89  1.1     mrg 
     90  1.1     mrg static int isp_match __P((struct device *, struct cfdata *, void *));
     91  1.1     mrg static void isp_sbus_attach __P((struct device *, struct device *, void *));
     92  1.1     mrg struct cfattach isp_sbus_ca = {
     93  1.1     mrg 	sizeof (struct isp_sbussoftc), isp_match, isp_sbus_attach
     94  1.1     mrg };
     95  1.1     mrg 
     96  1.1     mrg static int
     97  1.1     mrg isp_match(parent, cf, aux)
     98  1.1     mrg         struct device *parent;
     99  1.1     mrg         struct cfdata *cf;
    100  1.1     mrg         void *aux;
    101  1.1     mrg {
    102  1.1     mrg 	int rv;
    103  1.1     mrg #ifdef DEBUG
    104  1.1     mrg 	static int oneshot = 1;
    105  1.1     mrg #endif
    106  1.1     mrg 	struct sbus_attach_args *sa = aux;
    107  1.1     mrg 
    108  1.1     mrg 	rv = (strcmp(cf->cf_driver->cd_name, sa->sa_name) == 0 ||
    109  1.1     mrg 		strcmp("PTI,ptisp", sa->sa_name) == 0 ||
    110  1.1     mrg 		strcmp("ptisp", sa->sa_name) == 0 ||
    111  1.1     mrg 		strcmp("SUNW,isp", sa->sa_name) == 0 ||
    112  1.1     mrg 		strcmp("QLGC,isp", sa->sa_name) == 0);
    113  1.1     mrg #ifdef DEBUG
    114  1.1     mrg 	if (rv && oneshot) {
    115  1.1     mrg 		oneshot = 0;
    116  1.1     mrg 		printf("Qlogic ISP Driver, NetBSD (sbus) Platform Version "
    117  1.1     mrg 		    "%d.%d Core Version %d.%d\n",
    118  1.1     mrg 		    ISP_PLATFORM_VERSION_MAJOR, ISP_PLATFORM_VERSION_MINOR,
    119  1.1     mrg 		    ISP_CORE_VERSION_MAJOR, ISP_CORE_VERSION_MINOR);
    120  1.1     mrg 	}
    121  1.1     mrg #endif
    122  1.1     mrg 	return (rv);
    123  1.1     mrg }
    124  1.1     mrg 
    125  1.1     mrg static void
    126  1.1     mrg isp_sbus_attach(parent, self, aux)
    127  1.1     mrg         struct device *parent, *self;
    128  1.1     mrg         void *aux;
    129  1.1     mrg {
    130  1.1     mrg 	int i, freq;
    131  1.1     mrg 	struct sbus_attach_args *sa = aux;
    132  1.1     mrg 	struct isp_sbussoftc *sbc = (struct isp_sbussoftc *) self;
    133  1.1     mrg 	struct ispsoftc *isp = &sbc->sbus_isp;
    134  1.1     mrg 	ISP_LOCKVAL_DECL;
    135  1.1     mrg 
    136  1.1     mrg 	printf(" for %s\n", sa->sa_name);
    137  1.1     mrg 
    138  1.1     mrg 	sbc->sbus_bustag = sa->sa_bustag;
    139  1.1     mrg 	sbc->sbus_dmatag = sa->sa_dmatag;
    140  1.1     mrg 	sbc->sbus_pri = sa->sa_pri;
    141  1.1     mrg 	sbc->sbus_mdvec = mdvec;
    142  1.1     mrg 
    143  1.1     mrg 	if (sa->sa_npromvaddrs != 0) {
    144  1.1     mrg 		sbc->sbus_reg = (volatile u_char *) sa->sa_promvaddrs[0];
    145  1.1     mrg 	} else {
    146  1.1     mrg 		bus_space_handle_t bh;
    147  1.1     mrg 		if (sbus_bus_map(sa->sa_bustag, sa->sa_slot,
    148  1.1     mrg 				 sa->sa_offset,
    149  1.1     mrg 				 sa->sa_size,
    150  1.1     mrg 				 0, 0, &bh) != 0) {
    151  1.1     mrg 			printf("%s: cannot map registers\n", self->dv_xname);
    152  1.1     mrg 			return;
    153  1.1     mrg 		}
    154  1.1     mrg 		sbc->sbus_reg = (volatile u_char *)bh;
    155  1.1     mrg 	}
    156  1.1     mrg 	sbc->sbus_node = sa->sa_node;
    157  1.1     mrg 
    158  1.1     mrg 	freq = getpropint(sa->sa_node, "clock-frequency", 0);
    159  1.1     mrg 	if (freq) {
    160  1.1     mrg 		/*
    161  1.1     mrg 		 * Convert from HZ to MHz, rounding up.
    162  1.1     mrg 		 */
    163  1.1     mrg 		freq = (freq + 500000)/1000000;
    164  1.1     mrg #if	0
    165  1.1     mrg 		printf("%s: %d MHz\n", self->dv_xname, freq);
    166  1.1     mrg #endif
    167  1.1     mrg 	}
    168  1.1     mrg 	sbc->sbus_mdvec.dv_clock = freq;
    169  1.1     mrg 
    170  1.1     mrg 	/*
    171  1.1     mrg 	 * Some early versions of the PTI SBus adapter
    172  1.1     mrg 	 * would fail in trying to download (via poking)
    173  1.1     mrg 	 * FW. We give up on them.
    174  1.1     mrg 	 */
    175  1.1     mrg 	if (strcmp("PTI,ptisp", sa->sa_name) == 0 ||
    176  1.1     mrg 	    strcmp("ptisp", sa->sa_name) == 0) {
    177  1.1     mrg 		sbc->sbus_mdvec.dv_fwlen = 0;
    178  1.1     mrg 	}
    179  1.1     mrg 
    180  1.1     mrg 	isp->isp_mdvec = &sbc->sbus_mdvec;
    181  1.2  mjacob 	isp->isp_bustype = ISP_BT_SBUS;
    182  1.1     mrg 	isp->isp_type = ISP_HA_SCSI_UNKNOWN;
    183  1.1     mrg 	isp->isp_param = &sbc->sbus_dev;
    184  1.1     mrg 	bzero(isp->isp_param, sizeof (sdparam));
    185  1.1     mrg 
    186  1.1     mrg 
    187  1.1     mrg 	ISP_LOCK(isp);
    188  1.1     mrg 	isp_reset(isp);
    189  1.1     mrg 	if (isp->isp_state != ISP_RESETSTATE) {
    190  1.1     mrg 		ISP_UNLOCK(isp);
    191  1.1     mrg 		return;
    192  1.1     mrg 	}
    193  1.1     mrg 	isp_init(isp);
    194  1.1     mrg 	if (isp->isp_state != ISP_INITSTATE) {
    195  1.1     mrg 		isp_uninit(isp);
    196  1.1     mrg 		ISP_UNLOCK(isp);
    197  1.1     mrg 		return;
    198  1.1     mrg 	}
    199  1.1     mrg 
    200  1.1     mrg 	for (i = 0; i < MAXISPREQUEST; i++) {
    201  1.1     mrg 
    202  1.1     mrg 		/* Allocate a DMA handle */
    203  1.1     mrg 		if (bus_dmamap_create(
    204  1.1     mrg 				sbc->sbus_dmatag,
    205  1.1     mrg 				MAXPHYS,	/* size */
    206  1.1     mrg 				1,		/* nsegments */
    207  1.1     mrg 				MAXPHYS,	/* maxsegsz */
    208  1.1     mrg 				0,		/* boundary */
    209  1.1     mrg 				BUS_DMA_NOWAIT,
    210  1.1     mrg 				&sbc->sbus_dmamap[i]) != 0) {
    211  1.1     mrg 			printf("%s: DMA map create error\n",
    212  1.1     mrg 				self->dv_xname);
    213  1.1     mrg 			return;
    214  1.1     mrg 		}
    215  1.1     mrg 	}
    216  1.1     mrg 
    217  1.1     mrg 	/* Establish interrupt channel */
    218  1.1     mrg 	bus_intr_establish(sbc->sbus_bustag,
    219  1.1     mrg 			   sbc->sbus_pri, 0,
    220  1.1     mrg 			   (int(*)__P((void*)))isp_intr, sbc);
    221  1.1     mrg 
    222  1.1     mrg 	/*
    223  1.1     mrg 	 * do generic attach.
    224  1.1     mrg 	 */
    225  1.1     mrg 	isp_attach(isp);
    226  1.1     mrg 	if (isp->isp_state != ISP_RUNSTATE) {
    227  1.1     mrg 		isp_uninit(isp);
    228  1.1     mrg 	}
    229  1.1     mrg 	ISP_UNLOCK(isp);
    230  1.1     mrg }
    231  1.1     mrg 
    232  1.1     mrg #define  SBUS_BIU_REGS_OFF		0x00
    233  1.1     mrg #define	 SBUS_MBOX_REGS_OFF		0x80
    234  1.1     mrg #define	 SBUS_SXP_REGS_OFF		0x200
    235  1.1     mrg #define	 SBUS_RISC_REGS_OFF		0x400
    236  1.1     mrg 
    237  1.1     mrg static u_int16_t
    238  1.1     mrg isp_sbus_rd_reg(isp, regoff)
    239  1.1     mrg 	struct ispsoftc *isp;
    240  1.1     mrg 	int regoff;
    241  1.1     mrg {
    242  1.1     mrg 	struct isp_sbussoftc *sbc = (struct isp_sbussoftc *) isp;
    243  1.1     mrg 
    244  1.1     mrg 	int offset;
    245  1.1     mrg 	if ((regoff & BIU_BLOCK) != 0) {
    246  1.1     mrg 		offset = SBUS_BIU_REGS_OFF;
    247  1.1     mrg 	} else if ((regoff & MBOX_BLOCK) != 0) {
    248  1.1     mrg 		offset = SBUS_MBOX_REGS_OFF;
    249  1.1     mrg 	} else if ((regoff & SXP_BLOCK) != 0) {
    250  1.1     mrg 		offset = SBUS_SXP_REGS_OFF;
    251  1.1     mrg 	} else {
    252  1.1     mrg 		offset = SBUS_RISC_REGS_OFF;
    253  1.1     mrg 	}
    254  1.1     mrg 	regoff &= 0xff;
    255  1.1     mrg 	offset += regoff;
    256  1.1     mrg 	return (*((u_int16_t *) &sbc->sbus_reg[offset]));
    257  1.1     mrg }
    258  1.1     mrg 
    259  1.1     mrg static void
    260  1.1     mrg isp_sbus_wr_reg (isp, regoff, val)
    261  1.1     mrg 	struct ispsoftc *isp;
    262  1.1     mrg 	int regoff;
    263  1.1     mrg 	u_int16_t val;
    264  1.1     mrg {
    265  1.1     mrg 	struct isp_sbussoftc *sbc = (struct isp_sbussoftc *) isp;
    266  1.1     mrg 	int offset;
    267  1.1     mrg 
    268  1.1     mrg 	if ((regoff & BIU_BLOCK) != 0) {
    269  1.1     mrg 		offset = SBUS_BIU_REGS_OFF;
    270  1.1     mrg 	} else if ((regoff & MBOX_BLOCK) != 0) {
    271  1.1     mrg 		offset = SBUS_MBOX_REGS_OFF;
    272  1.1     mrg 	} else if ((regoff & SXP_BLOCK) != 0) {
    273  1.1     mrg 		offset = SBUS_SXP_REGS_OFF;
    274  1.1     mrg 	} else {
    275  1.1     mrg 		offset = SBUS_RISC_REGS_OFF;
    276  1.1     mrg 	}
    277  1.1     mrg 	regoff &= 0xff;
    278  1.1     mrg 	offset += regoff;
    279  1.1     mrg 	*((u_int16_t *) &sbc->sbus_reg[offset]) = val;
    280  1.1     mrg }
    281  1.1     mrg 
    282  1.1     mrg static int
    283  1.1     mrg isp_sbus_mbxdma(isp)
    284  1.1     mrg 	struct ispsoftc *isp;
    285  1.1     mrg {
    286  1.1     mrg 	struct isp_sbussoftc *sbc = (struct isp_sbussoftc *) isp;
    287  1.1     mrg 	bus_dma_segment_t seg;
    288  1.1     mrg 	size_t len, rseg;
    289  1.1     mrg 
    290  1.1     mrg 	/*
    291  1.1     mrg 	 * NOTE: Since most Sun machines aren't I/O coherent,
    292  1.1     mrg 	 * map the mailboxes through kdvma space to force them
    293  1.1     mrg 	 * to be uncached.
    294  1.1     mrg 	 */
    295  1.1     mrg 
    296  1.1     mrg 	/*
    297  1.1     mrg 	 * Allocate and map the request queue.
    298  1.1     mrg 	 */
    299  1.1     mrg 	len = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN);
    300  1.1     mrg 	if (bus_dmamem_alloc(sbc->sbus_dmatag, len, NBPG, 0,
    301  1.1     mrg 			     &seg, 1, &rseg, BUS_DMA_NOWAIT) != 0)
    302  1.1     mrg 		return (1);
    303  1.1     mrg 
    304  1.1     mrg 	if (bus_dmamem_map(sbc->sbus_dmatag, &seg, rseg, len,
    305  1.1     mrg 			   (caddr_t *)&isp->isp_rquest,
    306  1.1     mrg 			   BUS_DMA_NOWAIT|BUS_DMA_COHERENT) != 0)
    307  1.1     mrg 		return (1);
    308  1.1     mrg 	isp->isp_rquest_dma = seg.ds_addr;
    309  1.1     mrg 
    310  1.1     mrg 	/*
    311  1.1     mrg 	 * Allocate and map the result queue.
    312  1.1     mrg 	 */
    313  1.1     mrg 	len = ISP_QUEUE_SIZE(RESULT_QUEUE_LEN);
    314  1.1     mrg 	if (bus_dmamem_alloc(sbc->sbus_dmatag, len, NBPG, 0,
    315  1.1     mrg 			     &seg, 1, &rseg, BUS_DMA_NOWAIT) != 0)
    316  1.1     mrg 		return (1);
    317  1.1     mrg 
    318  1.1     mrg 	if (bus_dmamem_map(sbc->sbus_dmatag, &seg, rseg, len,
    319  1.1     mrg 			   (caddr_t *)&isp->isp_result,
    320  1.1     mrg 			   BUS_DMA_NOWAIT|BUS_DMA_COHERENT) != 0)
    321  1.1     mrg 		return (1);
    322  1.1     mrg 	isp->isp_result_dma = seg.ds_addr;
    323  1.1     mrg 
    324  1.1     mrg 	return (0);
    325  1.1     mrg }
    326  1.1     mrg 
    327  1.1     mrg /*
    328  1.1     mrg  * TODO: If kdvma_mapin fails, try using multiple smaller chunks..
    329  1.1     mrg  */
    330  1.1     mrg 
    331  1.1     mrg static int
    332  1.1     mrg isp_sbus_dmasetup(isp, xs, rq, iptrp, optr)
    333  1.1     mrg 	struct ispsoftc *isp;
    334  1.1     mrg 	struct scsipi_xfer *xs;
    335  1.1     mrg 	ispreq_t *rq;
    336  1.1     mrg 	u_int8_t *iptrp;
    337  1.1     mrg 	u_int8_t optr;
    338  1.1     mrg {
    339  1.1     mrg 	struct isp_sbussoftc *sbc = (struct isp_sbussoftc *) isp;
    340  1.1     mrg 	bus_dmamap_t dmamap;
    341  1.1     mrg 	int dosleep = (xs->flags & SCSI_NOSLEEP) != 0;
    342  1.1     mrg 
    343  1.1     mrg 	if (xs->datalen == 0) {
    344  1.1     mrg 		rq->req_seg_count = 1;
    345  1.3  mjacob 		return (CMD_QUEUED);
    346  1.1     mrg 	}
    347  1.1     mrg 
    348  1.1     mrg 	if (rq->req_handle > RQUEST_QUEUE_LEN || rq->req_handle < 1) {
    349  1.1     mrg 		panic("%s: bad handle (%d) in isp_sbus_dmasetup\n",
    350  1.1     mrg 			isp->isp_name, rq->req_handle);
    351  1.1     mrg 		/* NOTREACHED */
    352  1.1     mrg 	}
    353  1.1     mrg 
    354  1.1     mrg 	dmamap = sbc->sbus_dmamap[rq->req_handle - 1];
    355  1.1     mrg 	if (dmamap->dm_nsegs != 0) {
    356  1.1     mrg 		panic("%s: dma map already allocated\n", isp->isp_name);
    357  1.1     mrg 		/* NOTREACHED */
    358  1.1     mrg 	}
    359  1.1     mrg 	if (bus_dmamap_load(sbc->sbus_dmatag, dmamap,
    360  1.1     mrg 			    xs->data, xs->datalen, NULL,
    361  1.1     mrg 			    dosleep ? BUS_DMA_WAITOK : BUS_DMA_NOWAIT) != 0) {
    362  1.1     mrg 		XS_SETERR(xs, HBA_BOTCH);
    363  1.3  mjacob 		return (CMD_COMPLETE);
    364  1.1     mrg 	}
    365  1.1     mrg 	bus_dmamap_sync(sbc->sbus_dmatag, dmamap,
    366  1.1     mrg 			dmamap->dm_segs[0].ds_addr, xs->datalen,
    367  1.1     mrg 			(xs->flags & SCSI_DATA_IN)
    368  1.1     mrg 				? BUS_DMASYNC_PREREAD
    369  1.1     mrg 				: BUS_DMASYNC_PREWRITE);
    370  1.1     mrg 
    371  1.1     mrg 	if (xs->flags & SCSI_DATA_IN) {
    372  1.1     mrg 		rq->req_flags |= REQFLAG_DATA_IN;
    373  1.1     mrg 	} else {
    374  1.1     mrg 		rq->req_flags |= REQFLAG_DATA_OUT;
    375  1.1     mrg 	}
    376  1.1     mrg 	rq->req_dataseg[0].ds_count = xs->datalen;
    377  1.1     mrg 	rq->req_dataseg[0].ds_base =  dmamap->dm_segs[0].ds_addr;
    378  1.1     mrg 	rq->req_seg_count = 1;
    379  1.3  mjacob 	return (CMD_QUEUED);
    380  1.1     mrg }
    381  1.1     mrg 
    382  1.1     mrg static void
    383  1.1     mrg isp_sbus_dmateardown(isp, xs, handle)
    384  1.1     mrg 	struct ispsoftc *isp;
    385  1.1     mrg 	struct scsipi_xfer *xs;
    386  1.1     mrg 	u_int32_t handle;
    387  1.1     mrg {
    388  1.1     mrg 	struct isp_sbussoftc *sbc = (struct isp_sbussoftc *) isp;
    389  1.1     mrg 	bus_dmamap_t dmamap;
    390  1.1     mrg 
    391  1.1     mrg 	if (handle >= RQUEST_QUEUE_LEN) {
    392  1.1     mrg 		panic("%s: bad handle (%d) in isp_sbus_dmateardown\n",
    393  1.1     mrg 			isp->isp_name, handle);
    394  1.1     mrg 		/* NOTREACHED */
    395  1.1     mrg 	}
    396  1.1     mrg 
    397  1.1     mrg 	dmamap = sbc->sbus_dmamap[handle];
    398  1.1     mrg 	if (dmamap->dm_nsegs == 0) {
    399  1.1     mrg 		panic("%s: dma map not already allocated\n", isp->isp_name);
    400  1.1     mrg 		/* NOTREACHED */
    401  1.1     mrg 	}
    402  1.1     mrg 	bus_dmamap_sync(sbc->sbus_dmatag, dmamap,
    403  1.1     mrg 			dmamap->dm_segs[0].ds_addr, xs->datalen,
    404  1.1     mrg 			(xs->flags & SCSI_DATA_IN)
    405  1.1     mrg 				? BUS_DMASYNC_POSTREAD
    406  1.1     mrg 				: BUS_DMASYNC_POSTWRITE);
    407  1.1     mrg 	bus_dmamap_unload(sbc->sbus_dmatag, dmamap);
    408  1.1     mrg }
    409