Home | History | Annotate | Line # | Download | only in pcmcia
esp_pcmcia.c revision 1.7
      1 /*	$NetBSD: esp_pcmcia.c,v 1.7 2000/06/05 15:19:44 tsutsui Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2000 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Charles M. Hannum.
      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, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *        This product includes software developed by the NetBSD
     21  *        Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 #include <sys/param.h>
     40 #include <sys/systm.h>
     41 #include <sys/device.h>
     42 #include <sys/buf.h>
     43 
     44 #include <machine/bus.h>
     45 #include <machine/intr.h>
     46 
     47 #include <dev/scsipi/scsi_all.h>
     48 #include <dev/scsipi/scsipi_all.h>
     49 #include <dev/scsipi/scsiconf.h>
     50 
     51 #include <dev/pcmcia/pcmciareg.h>
     52 #include <dev/pcmcia/pcmciavar.h>
     53 #include <dev/pcmcia/pcmciadevs.h>
     54 
     55 #include <dev/ic/ncr53c9xreg.h>
     56 #include <dev/ic/ncr53c9xvar.h>
     57 
     58 struct esp_pcmcia_softc {
     59 	struct ncr53c9x_softc	sc_ncr53c9x;	/* glue to MI code */
     60 
     61 	int		sc_active;		/* Pseudo-DMA state vars */
     62 	int		sc_tc;
     63 	int		sc_datain;
     64 	size_t		sc_dmasize;
     65 	size_t		sc_dmatrans;
     66 	char		**sc_dmaaddr;
     67 	size_t		*sc_pdmalen;
     68 
     69 	/* PCMCIA-specific goo. */
     70 	struct pcmcia_io_handle sc_pcioh;	/* PCMCIA i/o space info */
     71 	int sc_io_window;			/* our i/o window */
     72 	struct pcmcia_function *sc_pf;		/* our PCMCIA function */
     73 	void *sc_ih;				/* interrupt handler */
     74 #ifdef ESP_PCMCIA_POLL
     75 	struct callout sc_poll_ch;
     76 #endif
     77 	int sc_flags;
     78 #define	ESP_PCMCIA_ATTACHED	1		/* attach completed */
     79 #define ESP_PCMCIA_ATTACHING	2		/* attach in progress */
     80 };
     81 
     82 int	esp_pcmcia_match __P((struct device *, struct cfdata *, void *));
     83 void	esp_pcmcia_attach __P((struct device *, struct device *, void *));
     84 void	esp_pcmcia_init __P((struct esp_pcmcia_softc *));
     85 int	esp_pcmcia_detach __P((struct device *, int));
     86 int	esp_pcmcia_enable __P((void *, int));
     87 
     88 static struct scsipi_adapter esp_pci_adapter = {
     89 	0,			/* adapter refcnt */
     90 	ncr53c9x_scsi_cmd,	/* cmd */
     91 	minphys,		/* minphys */
     92 	NULL,			/* ioctl */
     93 	esp_pcmcia_enable,	/* enable */
     94 	NULL,			/* getgeom */
     95 };
     96 
     97 struct cfattach esp_pcmcia_ca = {
     98 	sizeof(struct esp_pcmcia_softc), esp_pcmcia_match, esp_pcmcia_attach,
     99 	esp_pcmcia_detach
    100 };
    101 
    102 /*
    103  * Functions and the switch for the MI code.
    104  */
    105 #ifdef ESP_PCMCIA_POLL
    106 void	esp_pcmcia_poll __P((void *));
    107 #endif
    108 u_char	esp_pcmcia_read_reg __P((struct ncr53c9x_softc *, int));
    109 void	esp_pcmcia_write_reg __P((struct ncr53c9x_softc *, int, u_char));
    110 int	esp_pcmcia_dma_isintr __P((struct ncr53c9x_softc *));
    111 void	esp_pcmcia_dma_reset __P((struct ncr53c9x_softc *));
    112 int	esp_pcmcia_dma_intr __P((struct ncr53c9x_softc *));
    113 int	esp_pcmcia_dma_setup __P((struct ncr53c9x_softc *, caddr_t *,
    114 	    size_t *, int, size_t *));
    115 void	esp_pcmcia_dma_go __P((struct ncr53c9x_softc *));
    116 void	esp_pcmcia_dma_stop __P((struct ncr53c9x_softc *));
    117 int	esp_pcmcia_dma_isactive __P((struct ncr53c9x_softc *));
    118 
    119 struct ncr53c9x_glue esp_pcmcia_glue = {
    120 	esp_pcmcia_read_reg,
    121 	esp_pcmcia_write_reg,
    122 	esp_pcmcia_dma_isintr,
    123 	esp_pcmcia_dma_reset,
    124 	esp_pcmcia_dma_intr,
    125 	esp_pcmcia_dma_setup,
    126 	esp_pcmcia_dma_go,
    127 	esp_pcmcia_dma_stop,
    128 	esp_pcmcia_dma_isactive,
    129 	NULL,			/* gl_clear_latched_intr */
    130 };
    131 
    132 const struct pcmcia_product esp_pcmcia_products[] = {
    133 	{ PCMCIA_STR_PANASONIC_KXLC002,		PCMCIA_VENDOR_PANASONIC,
    134 	  PCMCIA_PRODUCT_PANASONIC_KXLC002,	0 },
    135 
    136 	{ NULL }
    137 };
    138 
    139 int
    140 esp_pcmcia_match(parent, match, aux)
    141 	struct device *parent;
    142 	struct cfdata *match;
    143 	void *aux;
    144 {
    145 	struct pcmcia_attach_args *pa = aux;
    146 
    147 	if (pcmcia_product_lookup(pa, esp_pcmcia_products,
    148 	    sizeof esp_pcmcia_products[0], NULL) != NULL)
    149 		return (1);
    150 	return (0);
    151 }
    152 
    153 void
    154 esp_pcmcia_attach(parent, self, aux)
    155 	struct device *parent, *self;
    156 	void *aux;
    157 {
    158 	struct esp_pcmcia_softc *esc = (void *)self;
    159 	struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x;
    160 	struct pcmcia_attach_args *pa = aux;
    161 	struct pcmcia_config_entry *cfe;
    162 	struct pcmcia_function *pf = pa->pf;
    163 	const struct pcmcia_product *pp;
    164 
    165 	esc->sc_pf = pf;
    166 
    167 	for (cfe = SIMPLEQ_FIRST(&pf->cfe_head); cfe != NULL;
    168 	    cfe = SIMPLEQ_NEXT(cfe, cfe_list)) {
    169 		if (cfe->num_memspace != 0 ||
    170 		    cfe->num_iospace != 1)
    171 			continue;
    172 
    173 		if (pcmcia_io_alloc(pa->pf, cfe->iospace[0].start,
    174 		    cfe->iospace[0].length, 0, &esc->sc_pcioh) == 0)
    175 			break;
    176 	}
    177 
    178 	if (cfe == 0) {
    179 		printf(": can't alloc i/o space\n");
    180 		goto no_config_entry;
    181 	}
    182 
    183 	/* Enable the card. */
    184 	pcmcia_function_init(pf, cfe);
    185 	if (pcmcia_function_enable(pf)) {
    186 		printf(": function enable failed\n");
    187 		goto enable_failed;
    188 	}
    189 
    190 	/* Map in the I/O space */
    191 	if (pcmcia_io_map(pa->pf, PCMCIA_WIDTH_AUTO, 0, esc->sc_pcioh.size,
    192 	    &esc->sc_pcioh, &esc->sc_io_window)) {
    193 		printf(": can't map i/o space\n");
    194 		goto iomap_failed;
    195 	}
    196 
    197 	pp = pcmcia_product_lookup(pa, esp_pcmcia_products,
    198 	    sizeof esp_pcmcia_products[0], NULL);
    199 	if (pp == NULL) {
    200 		printf("\n");
    201 		panic("esp_pcmcia_attach: impossible");
    202 	}
    203 
    204 	printf(": %s\n", pp->pp_name);
    205 
    206 	esp_pcmcia_init(esc);
    207 
    208 	/*
    209 	 *  Initialize nca board itself.
    210 	 */
    211 	esc->sc_flags |= ESP_PCMCIA_ATTACHING;
    212 	ncr53c9x_attach(sc, &esp_pci_adapter, NULL);
    213 	esc->sc_flags &= ~ESP_PCMCIA_ATTACHING;
    214 	esc->sc_flags |= ESP_PCMCIA_ATTACHED;
    215 	return;
    216 
    217 iomap_failed:
    218 	/* Disable the device. */
    219 	pcmcia_function_disable(esc->sc_pf);
    220 
    221 enable_failed:
    222 	/* Unmap our I/O space. */
    223 	pcmcia_io_free(esc->sc_pf, &esc->sc_pcioh);
    224 
    225 no_config_entry:
    226 	return;
    227 }
    228 
    229 void
    230 esp_pcmcia_init(esc)
    231 	struct esp_pcmcia_softc *esc;
    232 {
    233 	struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x;
    234 	bus_space_tag_t iot = esc->sc_pcioh.iot;
    235 	bus_space_handle_t ioh = esc->sc_pcioh.ioh;
    236 
    237 	/* id 7, clock 40M, parity ON, sync OFF, fast ON, slow ON */
    238 
    239 	sc->sc_glue = &esp_pcmcia_glue;
    240 
    241 #ifdef ESP_PCMCIA_POLL
    242 	callout_init(&esc->sc_poll_ch);
    243 #endif
    244 
    245 	sc->sc_rev = NCR_VARIANT_ESP406;
    246 	sc->sc_id = 7;
    247 	sc->sc_freq = 40;
    248 	/* try -PARENB -SLOW */
    249 	sc->sc_cfg1 = sc->sc_id | NCRCFG1_PARENB | NCRCFG1_SLOW;
    250 	/* try +FE */
    251 	sc->sc_cfg2 = NCRCFG2_SCSI2;
    252 	/* try -IDM -FSCSI -FCLK */
    253 	sc->sc_cfg3 = NCRESPCFG3_CDB | NCRESPCFG3_FCLK | NCRESPCFG3_IDM |
    254 	    NCRESPCFG3_FSCSI;
    255 	sc->sc_cfg4 = NCRCFG4_ACTNEG;
    256 	/* try +INTP */
    257 	sc->sc_cfg5 = NCRCFG5_CRS1 | NCRCFG5_AADDR | NCRCFG5_PTRINC;
    258 	sc->sc_minsync = 0;
    259 	sc->sc_maxxfer = 64 * 1024;
    260 
    261 	bus_space_write_1(iot, ioh, NCR_CFG5, sc->sc_cfg5);
    262 
    263 	bus_space_write_1(iot, ioh, NCR_PIOI, 0);
    264 	bus_space_write_1(iot, ioh, NCR_PSTAT, 0);
    265 	bus_space_write_1(iot, ioh, 0x09, 0x24);
    266 
    267 	bus_space_write_1(iot, ioh, NCR_CFG4, sc->sc_cfg4);
    268 }
    269 
    270 int
    271 esp_pcmcia_detach(self, flags)
    272 	struct device *self;
    273 	int flags;
    274 {
    275 	struct esp_pcmcia_softc *esc = (void *)self;
    276 	int error;
    277 
    278 	if ((esc->sc_flags & ESP_PCMCIA_ATTACHED) == 0) {
    279 		/* Nothing to detach. */
    280 		return (0);
    281 	}
    282 
    283 	error = ncr53c9x_detach(&esc->sc_ncr53c9x, flags);
    284 	if (error)
    285 		return (error);
    286 
    287 	/* Unmap our i/o window and i/o space. */
    288 	pcmcia_io_unmap(esc->sc_pf, esc->sc_io_window);
    289 	pcmcia_io_free(esc->sc_pf, &esc->sc_pcioh);
    290 
    291 	return (0);
    292 }
    293 
    294 int
    295 esp_pcmcia_enable(arg, onoff)
    296 	void *arg;
    297 	int onoff;
    298 {
    299 	struct esp_pcmcia_softc *esc = arg;
    300 
    301 	if (onoff) {
    302 #ifdef ESP_PCMCIA_POLL
    303 		callout_reset(&esc->sc_poll_ch, 1, esp_pcmcia_poll, esc);
    304 #else
    305 		/* Establish the interrupt handler. */
    306 		esc->sc_ih = pcmcia_intr_establish(esc->sc_pf, IPL_BIO,
    307 		    ncr53c9x_intr, &esc->sc_ncr53c9x);
    308 		if (esc->sc_ih == NULL) {
    309 			printf("%s: couldn't establish interrupt handler\n",
    310 			    esc->sc_ncr53c9x.sc_dev.dv_xname);
    311 			return (EIO);
    312 		}
    313 #endif
    314 
    315 		/*
    316 		 * If attach is in progress, we know that card power is
    317 		 * enabled and chip will be initialized later.
    318 		 * Otherwise, enable and reset now.
    319 		 */
    320 		if ((esc->sc_flags & ESP_PCMCIA_ATTACHING) == 0) {
    321 			if (pcmcia_function_enable(esc->sc_pf)) {
    322 				printf("%s: couldn't enable PCMCIA function\n",
    323 				    esc->sc_ncr53c9x.sc_dev.dv_xname);
    324 				pcmcia_intr_disestablish(esc->sc_pf,
    325 				    esc->sc_ih);
    326 				return (EIO);
    327 			}
    328 
    329 			/* Initialize only chip.  */
    330 			ncr53c9x_init(&esc->sc_ncr53c9x, 0);
    331 		}
    332 	} else {
    333 		pcmcia_function_disable(esc->sc_pf);
    334 #ifdef ESP_PCMCIA_POLL
    335 		callout_stop(&esc->sc_poll_ch);
    336 #else
    337 		pcmcia_intr_disestablish(esc->sc_pf, esc->sc_ih);
    338 #endif
    339 	}
    340 
    341 	return (0);
    342 }
    343 
    344 #ifdef ESP_PCMCIA_POLL
    345 void
    346 esp_pcmcia_poll(arg)
    347 	void *arg;
    348 {
    349 	struct esp_pcmcia_softc *esc = arg;
    350 
    351 	(void) ncr53c9x_intr(&esc->sc_ncr53c9x);
    352 	callout_reset(&esc->sc_poll_ch, 1, esp_pcmcia_poll, esc);
    353 }
    354 #endif
    355 
    356 /*
    357  * Glue functions.
    358  */
    359 u_char
    360 esp_pcmcia_read_reg(sc, reg)
    361 	struct ncr53c9x_softc *sc;
    362 	int reg;
    363 {
    364 	struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc;
    365 	u_char v;
    366 
    367 	v = bus_space_read_1(esc->sc_pcioh.iot, esc->sc_pcioh.ioh, reg);
    368 	return v;
    369 }
    370 
    371 void
    372 esp_pcmcia_write_reg(sc, reg, val)
    373 	struct ncr53c9x_softc *sc;
    374 	int reg;
    375 	u_char val;
    376 {
    377 	struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc;
    378 	u_char v = val;
    379 
    380 	if (reg == NCR_CMD && v == (NCRCMD_TRANS|NCRCMD_DMA))
    381 		v = NCRCMD_TRANS;
    382 	bus_space_write_1(esc->sc_pcioh.iot, esc->sc_pcioh.ioh, reg, v);
    383 }
    384 
    385 int
    386 esp_pcmcia_dma_isintr(sc)
    387 	struct ncr53c9x_softc *sc;
    388 {
    389 
    390 	return NCR_READ_REG(sc, NCR_STAT) & NCRSTAT_INT;
    391 }
    392 
    393 void
    394 esp_pcmcia_dma_reset(sc)
    395 	struct ncr53c9x_softc *sc;
    396 {
    397 	struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc;
    398 
    399 	esc->sc_active = 0;
    400 	esc->sc_tc = 0;
    401 }
    402 
    403 int
    404 esp_pcmcia_dma_intr(sc)
    405 	struct ncr53c9x_softc *sc;
    406 {
    407 	struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc;
    408 	u_char	*p;
    409 	u_int	espphase, espstat, espintr;
    410 	int	cnt;
    411 
    412 	if (esc->sc_active == 0) {
    413 		printf("%s: dma_intr--inactive DMA\n", sc->sc_dev.dv_xname);
    414 		return -1;
    415 	}
    416 
    417 	if ((sc->sc_espintr & NCRINTR_BS) == 0) {
    418 		esc->sc_active = 0;
    419 		return 0;
    420 	}
    421 
    422 	cnt = *esc->sc_pdmalen;
    423 	if (*esc->sc_pdmalen == 0) {
    424 		printf("%s: data interrupt, but no count left\n",
    425 		    sc->sc_dev.dv_xname);
    426 	}
    427 
    428 	p = *esc->sc_dmaaddr;
    429 	espphase = sc->sc_phase;
    430 	espstat = (u_int) sc->sc_espstat;
    431 	espintr = (u_int) sc->sc_espintr;
    432 	do {
    433 		if (esc->sc_datain) {
    434 			*p++ = NCR_READ_REG(sc, NCR_FIFO);
    435 			cnt--;
    436 			if (espphase == DATA_IN_PHASE)
    437 				NCR_WRITE_REG(sc, NCR_CMD, NCRCMD_TRANS);
    438 			else
    439 				esc->sc_active = 0;
    440 	 	} else {
    441 			if (espphase == DATA_OUT_PHASE ||
    442 			    espphase == MESSAGE_OUT_PHASE) {
    443 				NCR_WRITE_REG(sc, NCR_FIFO, *p++);
    444 				cnt--;
    445 				NCR_WRITE_REG(sc, NCR_CMD, NCRCMD_TRANS);
    446 			} else
    447 				esc->sc_active = 0;
    448 		}
    449 
    450 		if (esc->sc_active) {
    451 			while (!(NCR_READ_REG(sc, NCR_STAT) & NCRSTAT_INT));
    452 			espstat = NCR_READ_REG(sc, NCR_STAT);
    453 			espintr = NCR_READ_REG(sc, NCR_INTR);
    454 			espphase = (espintr & NCRINTR_DIS)
    455 				    ? /* Disconnected */ BUSFREE_PHASE
    456 				    : espstat & PHASE_MASK;
    457 		}
    458 	} while (esc->sc_active && espintr);
    459 	sc->sc_phase = espphase;
    460 	sc->sc_espstat = (u_char) espstat;
    461 	sc->sc_espintr = (u_char) espintr;
    462 	*esc->sc_dmaaddr = p;
    463 	*esc->sc_pdmalen = cnt;
    464 
    465 	if (*esc->sc_pdmalen == 0)
    466 		esc->sc_tc = NCRSTAT_TC;
    467 	sc->sc_espstat |= esc->sc_tc;
    468 	return 0;
    469 }
    470 
    471 int
    472 esp_pcmcia_dma_setup(sc, addr, len, datain, dmasize)
    473 	struct ncr53c9x_softc *sc;
    474 	caddr_t *addr;
    475 	size_t *len;
    476 	int datain;
    477 	size_t *dmasize;
    478 {
    479 	struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc;
    480 
    481 	esc->sc_dmaaddr = addr;
    482 	esc->sc_pdmalen = len;
    483 	esc->sc_datain = datain;
    484 	esc->sc_dmasize = *dmasize;
    485 	esc->sc_tc = 0;
    486 
    487 	return 0;
    488 }
    489 
    490 void
    491 esp_pcmcia_dma_go(sc)
    492 	struct ncr53c9x_softc *sc;
    493 {
    494 	struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc;
    495 
    496 	esc->sc_active = 1;
    497 }
    498 
    499 void
    500 esp_pcmcia_dma_stop(sc)
    501 	struct ncr53c9x_softc *sc;
    502 {
    503 }
    504 
    505 int
    506 esp_pcmcia_dma_isactive(sc)
    507 	struct ncr53c9x_softc *sc;
    508 {
    509 	struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc;
    510 
    511 	return (esc->sc_active);
    512 }
    513