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