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
58struct 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
82int	esp_pcmcia_match __P((struct device *, struct cfdata *, void *));
83void	esp_pcmcia_attach __P((struct device *, struct device *, void *));
84void	esp_pcmcia_init __P((struct esp_pcmcia_softc *));
85int	esp_pcmcia_detach __P((struct device *, int));
86int	esp_pcmcia_enable __P((void *, int));
87
88static 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
97struct 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
106void	esp_pcmcia_poll __P((void *));
107#endif
108u_char	esp_pcmcia_read_reg __P((struct ncr53c9x_softc *, int));
109void	esp_pcmcia_write_reg __P((struct ncr53c9x_softc *, int, u_char));
110int	esp_pcmcia_dma_isintr __P((struct ncr53c9x_softc *));
111void	esp_pcmcia_dma_reset __P((struct ncr53c9x_softc *));
112int	esp_pcmcia_dma_intr __P((struct ncr53c9x_softc *));
113int	esp_pcmcia_dma_setup __P((struct ncr53c9x_softc *, caddr_t *,
114	    size_t *, int, size_t *));
115void	esp_pcmcia_dma_go __P((struct ncr53c9x_softc *));
116void	esp_pcmcia_dma_stop __P((struct ncr53c9x_softc *));
117int	esp_pcmcia_dma_isactive __P((struct ncr53c9x_softc *));
118
119struct 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
132const 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
139int
140esp_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
153void
154esp_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
217iomap_failed:
218	/* Disable the device. */
219	pcmcia_function_disable(esc->sc_pf);
220
221enable_failed:
222	/* Unmap our I/O space. */
223	pcmcia_io_free(esc->sc_pf, &esc->sc_pcioh);
224
225no_config_entry:
226	return;
227}
228
229void
230esp_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
270int
271esp_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
294int
295esp_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
345void
346esp_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 */
359u_char
360esp_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
371void
372esp_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
385int
386esp_pcmcia_dma_isintr(sc)
387	struct ncr53c9x_softc *sc;
388{
389
390	return NCR_READ_REG(sc, NCR_STAT) & NCRSTAT_INT;
391}
392
393void
394esp_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
403int
404esp_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
471int
472esp_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
490void
491esp_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
499void
500esp_pcmcia_dma_stop(sc)
501	struct ncr53c9x_softc *sc;
502{
503}
504
505int
506esp_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