Home | History | Annotate | Line # | Download | only in obio
esp.c revision 1.7
      1 /*	$NetBSD: esp.c,v 1.7 1997/02/27 14:06:25 briggs Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1996 Charles M. Hannum.  All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  * 3. All advertising materials mentioning features or use of this software
     15  *    must display the following acknowledgement:
     16  *	This product includes software developed by Charles M. Hannum.
     17  * 4. The name of the author may not be used to endorse or promote products
     18  *    derived from this software without specific prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 /*
     33  * Copyright (c) 1994 Peter Galbavy
     34  * Copyright (c) 1995 Paul Kranenburg
     35  * All rights reserved.
     36  *
     37  * Redistribution and use in source and binary forms, with or without
     38  * modification, are permitted provided that the following conditions
     39  * are met:
     40  * 1. Redistributions of source code must retain the above copyright
     41  *    notice, this list of conditions and the following disclaimer.
     42  * 2. Redistributions in binary form must reproduce the above copyright
     43  *    notice, this list of conditions and the following disclaimer in the
     44  *    documentation and/or other materials provided with the distribution.
     45  * 3. All advertising materials mentioning features or use of this software
     46  *    must display the following acknowledgement:
     47  *	This product includes software developed by Peter Galbavy
     48  * 4. The name of the author may not be used to endorse or promote products
     49  *    derived from this software without specific prior written permission.
     50  *
     51  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     52  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     53  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     54  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
     55  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     56  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     57  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     58  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     59  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
     60  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     61  * POSSIBILITY OF SUCH DAMAGE.
     62  */
     63 
     64 /*
     65  * Based on aic6360 by Jarle Greipsland
     66  *
     67  * Acknowledgements: Many of the algorithms used in this driver are
     68  * inspired by the work of Julian Elischer (julian (at) tfs.com) and
     69  * Charles Hannum (mycroft (at) duality.gnu.ai.mit.edu).  Thanks a million!
     70  */
     71 
     72 #include <sys/types.h>
     73 #include <sys/param.h>
     74 #include <sys/systm.h>
     75 #include <sys/kernel.h>
     76 #include <sys/errno.h>
     77 #include <sys/ioctl.h>
     78 #include <sys/device.h>
     79 #include <sys/buf.h>
     80 #include <sys/proc.h>
     81 #include <sys/user.h>
     82 #include <sys/queue.h>
     83 
     84 #include <scsi/scsi_all.h>
     85 #include <scsi/scsiconf.h>
     86 #include <scsi/scsi_message.h>
     87 
     88 #include <machine/cpu.h>
     89 #include <machine/param.h>
     90 
     91 #include <dev/ic/ncr53c9xreg.h>
     92 #include <dev/ic/ncr53c9xvar.h>
     93 
     94 #include <machine/viareg.h>
     95 
     96 #include <mac68k/dev/espvar.h>
     97 
     98 void	espattach	__P((struct device *, struct device *, void *));
     99 int	espmatch	__P((struct device *, void *, void *));
    100 
    101 /* Linkup to the rest of the kernel */
    102 struct cfattach esp_ca = {
    103 	sizeof(struct esp_softc), espmatch, espattach
    104 };
    105 
    106 struct cfdriver esp_cd = {
    107 	NULL, "esp", DV_DULL
    108 };
    109 
    110 struct scsi_adapter esp_switch = {
    111 	ncr53c9x_scsi_cmd,
    112 	minphys,		/* no max at this level; handled by DMA code */
    113 	NULL,
    114 	NULL,
    115 };
    116 
    117 struct scsi_device esp_dev = {
    118 	NULL,			/* Use default error handler */
    119 	NULL,			/* have a queue, served by this */
    120 	NULL,			/* have no async handler */
    121 	NULL,			/* Use default 'done' routine */
    122 };
    123 
    124 /*
    125  * Functions and the switch for the MI code.
    126  */
    127 u_char	esp_read_reg __P((struct ncr53c9x_softc *, int));
    128 void	esp_write_reg __P((struct ncr53c9x_softc *, int, u_char));
    129 int	esp_dma_isintr __P((struct ncr53c9x_softc *));
    130 void	esp_dma_reset __P((struct ncr53c9x_softc *));
    131 int	esp_dma_intr __P((struct ncr53c9x_softc *));
    132 int	esp_dma_setup __P((struct ncr53c9x_softc *, caddr_t *,
    133 	    size_t *, int, size_t *));
    134 void	esp_dma_go __P((struct ncr53c9x_softc *));
    135 void	esp_dma_stop __P((struct ncr53c9x_softc *));
    136 int	esp_dma_isactive __P((struct ncr53c9x_softc *));
    137 
    138 struct ncr53c9x_glue esp_glue = {
    139 	esp_read_reg,
    140 	esp_write_reg,
    141 	esp_dma_isintr,
    142 	esp_dma_reset,
    143 	esp_dma_intr,
    144 	esp_dma_setup,
    145 	esp_dma_go,
    146 	esp_dma_stop,
    147 	esp_dma_isactive,
    148 	NULL,			/* gl_clear_latched_intr */
    149 };
    150 
    151 int
    152 espmatch(parent, vcf, aux)
    153 	struct device *parent;
    154 	struct cfdata *cf;
    155 	void *aux;
    156 {
    157 	if ((cf->cf_unit == 0) && mac68k_machine.scsi96)
    158 		return (1);
    159 	if ((cf->cf_unit == 1) && mac68k_machine.scsi96_2)
    160 		return (1);
    161 	return (0);
    162 }
    163 
    164 /*
    165  * Attach this instance, and then all the sub-devices
    166  */
    167 void
    168 espattach(parent, self, aux)
    169 	struct device *parent, *self;
    170 	void *aux;
    171 {
    172 	extern vm_offset_t	SCSIBase;
    173 	struct esp_softc *esc = (void *)self;
    174 	struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x;
    175 
    176 	/*
    177 	 * Set up the glue for MI code early; we use some of it here.
    178 	 */
    179 	sc->sc_glue = &esp_glue;
    180 
    181 	/*
    182 	 * Save the regs
    183 	 */
    184 	if (sc->sc_dev.dv_unit == 0) {
    185 		unsigned long	reg_offset;
    186 
    187 		esc->sc_reg = (volatile u_char *) SCSIBase;
    188 		mac68k_register_scsi_irq(
    189 				(void (*)(void *)) ncr53c9x_intr, esc);
    190 		esc->irq_mask = V2IF_SCSIIRQ;
    191 		reg_offset = SCSIBase - IOBase;
    192 		if (reg_offset == 0x10000) {
    193 			sc->sc_freq = 16500000;
    194 		} else {
    195 			sc->sc_freq = 25000000;
    196 		}
    197 	} else {
    198 		esc->sc_reg = (volatile u_char *) SCSIBase + 0x402;
    199 		mac68k_register_scsi_b_irq(
    200 				(void (*)(void *)) ncr53c9x_intr, sc);
    201 		esc->irq_mask = V2IF_SCSIDRQ; /* V2IF_T1? */
    202 		sc->sc_freq = 25000000;
    203 	}
    204 
    205 	printf(": address %p", esc->sc_reg);
    206 
    207 	sc->sc_id = 7;
    208 
    209 	/* gimme Mhz */
    210 	sc->sc_freq /= 1000000;
    211 
    212 	/*
    213 	 * It is necessary to try to load the 2nd config register here,
    214 	 * to find out what rev the esp chip is, else the esp_reset
    215 	 * will not set up the defaults correctly.
    216 	 */
    217 	sc->sc_cfg1 = sc->sc_id | NCRCFG1_PARENB;
    218 	sc->sc_cfg2 = NCRCFG2_SCSI2;
    219 	sc->sc_cfg3 = 0;
    220 	sc->sc_rev = NCR_VARIANT_NCR53C96;
    221 
    222 	/*
    223 	 * This is the value used to start sync negotiations
    224 	 * Note that the NCR register "SYNCTP" is programmed
    225 	 * in "clocks per byte", and has a minimum value of 4.
    226 	 * The SCSI period used in negotiation is one-fourth
    227 	 * of the time (in nanoseconds) needed to transfer one byte.
    228 	 * Since the chip's clock is given in MHz, we have the following
    229 	 * formula: 4 * period = (1000 / freq) * 4
    230 	 */
    231 	sc->sc_minsync = 1000 / sc->sc_freq;
    232 
    233 	sc->sc_minsync = 0;	/* No synchronous xfers w/o DMA */
    234 	/* Really no limit, but since we want to fit into the TCR... */
    235 	sc->sc_maxxfer = 64 * 1024;
    236 
    237 	/*
    238 	 * Now try to attach all the sub-devices
    239 	 */
    240 	ncr53c9x_attach(sc, &esp_switch, &esp_dev);
    241 
    242 	/*
    243 	 * Configure interrupts.
    244 	 */
    245 	via2_reg(vPCR) = 0x22;
    246 	via2_reg(vIFR) = esc->irq_mask;
    247 	via2_reg(vIER) = 0x80 | esc->irq_mask;
    248 }
    249 
    250 /*
    251  * Glue functions.
    252  */
    253 
    254 u_char
    255 esp_read_reg(sc, reg)
    256 	struct ncr53c9x_softc *sc;
    257 	int reg;
    258 {
    259 	struct esp_softc *esc = (struct esp_softc *)sc;
    260 
    261 	return esc->sc_reg[reg * 16];
    262 }
    263 
    264 void
    265 esp_write_reg(sc, reg, val)
    266 	struct ncr53c9x_softc *sc;
    267 	int reg;
    268 	u_char val;
    269 {
    270 	struct esp_softc *esc = (struct esp_softc *)sc;
    271 	u_char v = val;
    272 
    273 	if (reg == NCR_CMD && v == (NCRCMD_TRANS|NCRCMD_DMA)) {
    274 		v = NCRCMD_TRANS;
    275 	}
    276 	esc->sc_reg[reg * 16] = v;
    277 }
    278 
    279 int
    280 esp_dma_isintr(sc)
    281 	struct ncr53c9x_softc *sc;
    282 {
    283 	struct esp_softc *esc = (struct esp_softc *)sc;
    284 
    285 	return esc->sc_reg[NCR_STAT * 16] & 0x80;
    286 }
    287 
    288 void
    289 esp_dma_reset(sc)
    290 	struct ncr53c9x_softc *sc;
    291 {
    292 	struct esp_softc *esc = (struct esp_softc *)sc;
    293 
    294 	esc->sc_active = 0;
    295 	esc->sc_tc = 0;
    296 }
    297 
    298 int
    299 esp_dma_intr(sc)
    300 	struct ncr53c9x_softc *sc;
    301 {
    302 	register struct esp_softc *esc = (struct esp_softc *)sc;
    303 	register u_char	*p;
    304 	volatile u_char *cmdreg, *intrreg, *statreg, *fiforeg;
    305 	register u_int	espphase, espstat, espintr;
    306 	register int	cnt;
    307 
    308 	if (esc->sc_active == 0) {
    309 		printf("dma_intr--inactive DMA\n");
    310 		return -1;
    311 	}
    312 
    313 	if ((sc->sc_espintr & NCRINTR_BS) == 0) {
    314 		esc->sc_active = 0;
    315 		return 0;
    316 	}
    317 
    318 	cnt = *esc->sc_pdmalen;
    319 	if (*esc->sc_pdmalen == 0) {
    320 		printf("data interrupt, but no count left.");
    321 	}
    322 
    323 	p = *esc->sc_dmaaddr;
    324 	espphase = sc->sc_phase;
    325 	espstat = (u_int) sc->sc_espstat;
    326 	espintr = (u_int) sc->sc_espintr;
    327 	cmdreg = esc->sc_reg + NCR_CMD * 16;
    328 	fiforeg = esc->sc_reg + NCR_FIFO * 16;
    329 	statreg = esc->sc_reg + NCR_STAT * 16;
    330 	intrreg = esc->sc_reg + NCR_INTR * 16;
    331 	do {
    332 		if (esc->sc_datain) {
    333 			*p++ = *fiforeg;
    334 			cnt--;
    335 			if (espphase == DATA_IN_PHASE) {
    336 				*cmdreg = NCRCMD_TRANS;
    337 			} else {
    338 				esc->sc_active = 0;
    339 			}
    340 	 	} else {
    341 			if (   (espphase == DATA_OUT_PHASE)
    342 			    || (espphase == MESSAGE_OUT_PHASE)) {
    343 				*fiforeg = *p++;
    344 				cnt--;
    345 				*cmdreg = NCRCMD_TRANS;
    346 			} else {
    347 				esc->sc_active = 0;
    348 			}
    349 		}
    350 
    351 		if (esc->sc_active) {
    352 			while (!(*statreg & 0x80));
    353 			espstat = *statreg;
    354 			espintr = *intrreg;
    355 			espphase = (espintr & NCRINTR_DIS)
    356 				    ? /* Disconnected */ BUSFREE_PHASE
    357 				    : espstat & PHASE_MASK;
    358 		}
    359 	} while (esc->sc_active && (espintr & NCRINTR_BS));
    360 	sc->sc_phase = espphase;
    361 	sc->sc_espstat = (u_char) espstat;
    362 	sc->sc_espintr = (u_char) espintr;
    363 	*esc->sc_dmaaddr = p;
    364 	*esc->sc_pdmalen = cnt;
    365 
    366 	if (*esc->sc_pdmalen == 0) {
    367 		esc->sc_tc = NCRSTAT_TC;
    368 	}
    369 	sc->sc_espstat |= esc->sc_tc;
    370 	return 0;
    371 }
    372 
    373 int
    374 esp_dma_setup(sc, addr, len, datain, dmasize)
    375 	struct ncr53c9x_softc *sc;
    376 	caddr_t *addr;
    377 	size_t *len;
    378 	int datain;
    379 	size_t *dmasize;
    380 {
    381 	struct esp_softc *esc = (struct esp_softc *)sc;
    382 
    383 	esc->sc_dmaaddr = addr;
    384 	esc->sc_pdmalen = len;
    385 	esc->sc_datain = datain;
    386 	esc->sc_dmasize = *dmasize;
    387 	esc->sc_tc = 0;
    388 
    389 	return 0;
    390 }
    391 
    392 void
    393 esp_dma_go(sc)
    394 	struct ncr53c9x_softc *sc;
    395 {
    396 	struct esp_softc *esc = (struct esp_softc *)sc;
    397 
    398 	if (esc->sc_datain == 0) {
    399 		esc->sc_reg[NCR_FIFO * 16] = **esc->sc_dmaaddr;
    400 		(*esc->sc_pdmalen)--;
    401 		(*esc->sc_dmaaddr)++;
    402 	}
    403 	esc->sc_active = 1;
    404 }
    405 
    406 void
    407 esp_dma_stop(sc)
    408 	struct ncr53c9x_softc *sc;
    409 {
    410 }
    411 
    412 int
    413 esp_dma_isactive(sc)
    414 	struct ncr53c9x_softc *sc;
    415 {
    416 	struct esp_softc *esc = (struct esp_softc *)sc;
    417 
    418 	return esc->sc_active;
    419 }
    420