esp_pcmcia.c revision 1.5 1 /* $NetBSD: esp_pcmcia.c,v 1.5 2000/03/23 07:01:42 thorpej 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 struct cfattach esp_pcmcia_ca = {
89 sizeof(struct esp_pcmcia_softc), esp_pcmcia_match, esp_pcmcia_attach,
90 esp_pcmcia_detach
91 };
92
93 struct scsipi_device esp_pcmcia_dev = {
94 NULL, /* Use default error handler */
95 NULL, /* have a queue, served by this */
96 NULL, /* have no async handler */
97 NULL, /* Use default 'done' routine */
98 };
99
100 /*
101 * Functions and the switch for the MI code.
102 */
103 #ifdef ESP_PCMCIA_POLL
104 void esp_pcmcia_poll __P((void *));
105 #endif
106 u_char esp_pcmcia_read_reg __P((struct ncr53c9x_softc *, int));
107 void esp_pcmcia_write_reg __P((struct ncr53c9x_softc *, int, u_char));
108 int esp_pcmcia_dma_isintr __P((struct ncr53c9x_softc *));
109 void esp_pcmcia_dma_reset __P((struct ncr53c9x_softc *));
110 int esp_pcmcia_dma_intr __P((struct ncr53c9x_softc *));
111 int esp_pcmcia_dma_setup __P((struct ncr53c9x_softc *, caddr_t *,
112 size_t *, int, size_t *));
113 void esp_pcmcia_dma_go __P((struct ncr53c9x_softc *));
114 void esp_pcmcia_dma_stop __P((struct ncr53c9x_softc *));
115 int esp_pcmcia_dma_isactive __P((struct ncr53c9x_softc *));
116
117 struct ncr53c9x_glue esp_pcmcia_glue = {
118 esp_pcmcia_read_reg,
119 esp_pcmcia_write_reg,
120 esp_pcmcia_dma_isintr,
121 esp_pcmcia_dma_reset,
122 esp_pcmcia_dma_intr,
123 esp_pcmcia_dma_setup,
124 esp_pcmcia_dma_go,
125 esp_pcmcia_dma_stop,
126 esp_pcmcia_dma_isactive,
127 NULL, /* gl_clear_latched_intr */
128 };
129
130 const struct pcmcia_product esp_pcmcia_products[] = {
131 { PCMCIA_STR_PANASONIC_KXLC002, PCMCIA_VENDOR_PANASONIC,
132 PCMCIA_PRODUCT_PANASONIC_KXLC002, 0 },
133
134 { NULL }
135 };
136
137 int
138 esp_pcmcia_match(parent, match, aux)
139 struct device *parent;
140 struct cfdata *match;
141 void *aux;
142 {
143 struct pcmcia_attach_args *pa = aux;
144
145 if (pcmcia_product_lookup(pa, esp_pcmcia_products,
146 sizeof esp_pcmcia_products[0], NULL) != NULL)
147 return (1);
148 return (0);
149 }
150
151 void
152 esp_pcmcia_attach(parent, self, aux)
153 struct device *parent, *self;
154 void *aux;
155 {
156 struct esp_pcmcia_softc *esc = (void *)self;
157 struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x;
158 struct pcmcia_attach_args *pa = aux;
159 struct pcmcia_config_entry *cfe;
160 struct pcmcia_function *pf = pa->pf;
161 const struct pcmcia_product *pp;
162
163 esc->sc_pf = pf;
164
165 for (cfe = SIMPLEQ_FIRST(&pf->cfe_head); cfe != NULL;
166 cfe = SIMPLEQ_NEXT(cfe, cfe_list)) {
167 if (cfe->num_memspace != 0 ||
168 cfe->num_iospace != 1)
169 continue;
170
171 if (pcmcia_io_alloc(pa->pf, cfe->iospace[0].start,
172 cfe->iospace[0].length, 0, &esc->sc_pcioh) == 0)
173 break;
174 }
175
176 if (cfe == 0) {
177 printf(": can't alloc i/o space\n");
178 goto no_config_entry;
179 }
180
181 /* Enable the card. */
182 pcmcia_function_init(pf, cfe);
183 if (pcmcia_function_enable(pf)) {
184 printf(": function enable failed\n");
185 goto enable_failed;
186 }
187
188 /* Map in the I/O space */
189 if (pcmcia_io_map(pa->pf, PCMCIA_WIDTH_AUTO, 0, esc->sc_pcioh.size,
190 &esc->sc_pcioh, &esc->sc_io_window)) {
191 printf(": can't map i/o space\n");
192 goto iomap_failed;
193 }
194
195 pp = pcmcia_product_lookup(pa, esp_pcmcia_products,
196 sizeof esp_pcmcia_products[0], NULL);
197 if (pp == NULL) {
198 printf("\n");
199 panic("esp_pcmcia_attach: impossible");
200 }
201
202 printf(": %s\n", pp->pp_name);
203
204 esp_pcmcia_init(esc);
205
206 sc->sc_adapter.scsipi_enable = esp_pcmcia_enable;
207 sc->sc_adapter.scsipi_cmd = ncr53c9x_scsi_cmd;
208 sc->sc_adapter.scsipi_minphys = minphys;
209
210 /*
211 * Initialize nca board itself.
212 */
213 esc->sc_flags |= ESP_PCMCIA_ATTACHING;
214 ncr53c9x_attach(sc, &esp_pcmcia_dev);
215 esc->sc_flags &= ~ESP_PCMCIA_ATTACHING;
216 esc->sc_flags |= ESP_PCMCIA_ATTACHED;
217 return;
218
219 iomap_failed:
220 /* Disable the device. */
221 pcmcia_function_disable(esc->sc_pf);
222
223 enable_failed:
224 /* Unmap our I/O space. */
225 pcmcia_io_free(esc->sc_pf, &esc->sc_pcioh);
226
227 no_config_entry:
228 return;
229 }
230
231 void
232 esp_pcmcia_init(esc)
233 struct esp_pcmcia_softc *esc;
234 {
235 struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x;
236 bus_space_tag_t iot = esc->sc_pcioh.iot;
237 bus_space_handle_t ioh = esc->sc_pcioh.ioh;
238
239 /* id 7, clock 40M, parity ON, sync OFF, fast ON, slow ON */
240
241 sc->sc_glue = &esp_pcmcia_glue;
242
243 #ifdef ESP_PCMCIA_POLL
244 callout_init(&esc->sc_poll_ch);
245 #endif
246
247 sc->sc_rev = NCR_VARIANT_ESP406;
248 sc->sc_id = 7;
249 sc->sc_freq = 40;
250 /* try -PARENB -SLOW */
251 sc->sc_cfg1 = sc->sc_id | NCRCFG1_PARENB | NCRCFG1_SLOW;
252 /* try +FE */
253 sc->sc_cfg2 = NCRCFG2_SCSI2;
254 /* try -IDM -FSCSI -FCLK */
255 sc->sc_cfg3 = NCRESPCFG3_CDB | NCRESPCFG3_FCLK | NCRESPCFG3_IDM |
256 NCRESPCFG3_FSCSI;
257 sc->sc_cfg4 = NCRCFG4_ACTNEG;
258 /* try +INTP */
259 sc->sc_cfg5 = NCRCFG5_CRS1 | NCRCFG5_AADDR | NCRCFG5_PTRINC;
260 sc->sc_minsync = 0;
261 sc->sc_maxxfer = 64 * 1024;
262
263 bus_space_write_1(iot, ioh, NCR_CFG5, sc->sc_cfg5);
264
265 bus_space_write_1(iot, ioh, NCR_PIOI, 0);
266 bus_space_write_1(iot, ioh, NCR_PSTAT, 0);
267 bus_space_write_1(iot, ioh, 0x09, 0x24);
268
269 bus_space_write_1(iot, ioh, NCR_CFG4, sc->sc_cfg4);
270 }
271
272 int
273 esp_pcmcia_detach(self, flags)
274 struct device *self;
275 int flags;
276 {
277 struct esp_pcmcia_softc *esc = (void *)self;
278 int error;
279
280 if ((esc->sc_flags & ESP_PCMCIA_ATTACHED) == 0) {
281 /* Nothing to detach. */
282 return (0);
283 }
284
285 error = ncr53c9x_detach(&esc->sc_ncr53c9x, flags);
286 if (error)
287 return (error);
288
289 /* Unmap our i/o window and i/o space. */
290 pcmcia_io_unmap(esc->sc_pf, esc->sc_io_window);
291 pcmcia_io_free(esc->sc_pf, &esc->sc_pcioh);
292
293 return (0);
294 }
295
296 int
297 esp_pcmcia_enable(arg, onoff)
298 void *arg;
299 int onoff;
300 {
301 struct esp_pcmcia_softc *esc = arg;
302
303 if (onoff) {
304 #ifdef ESP_PCMCIA_POLL
305 callout_reset(&esc->sc_poll_ch, 1, esp_pcmcia_poll, esc);
306 #else
307 /* Establish the interrupt handler. */
308 esc->sc_ih = pcmcia_intr_establish(esc->sc_pf, IPL_BIO,
309 ncr53c9x_intr, &esc->sc_ncr53c9x);
310 if (esc->sc_ih == NULL) {
311 printf("%s: couldn't establish interrupt handler\n",
312 esc->sc_ncr53c9x.sc_dev.dv_xname);
313 return (EIO);
314 }
315 #endif
316
317 /*
318 * If attach is in progress, we know that card power is
319 * enabled and chip will be initialized later.
320 * Otherwise, enable and reset now.
321 */
322 if ((esc->sc_flags & ESP_PCMCIA_ATTACHING) == 0) {
323 if (pcmcia_function_enable(esc->sc_pf)) {
324 printf("%s: couldn't enable PCMCIA function\n",
325 esc->sc_ncr53c9x.sc_dev.dv_xname);
326 pcmcia_intr_disestablish(esc->sc_pf,
327 esc->sc_ih);
328 return (EIO);
329 }
330
331 /* Initialize only chip. */
332 ncr53c9x_init(&esc->sc_ncr53c9x, 0);
333 }
334 } else {
335 pcmcia_function_disable(esc->sc_pf);
336 #ifdef ESP_PCMCIA_POLL
337 callout_stop(&esc->sc_poll_ch);
338 #else
339 pcmcia_intr_disestablish(esc->sc_pf, esc->sc_ih);
340 #endif
341 }
342
343 return (0);
344 }
345
346 #ifdef ESP_PCMCIA_POLL
347 void
348 esp_pcmcia_poll(arg)
349 void *arg;
350 {
351 struct esp_pcmcia_softc *esc = arg;
352
353 (void) ncr53c9x_intr(&esc->sc_ncr53c9x);
354 callout_reset(&esc->sc_poll_ch, 1, esp_pcmcia_poll, esc);
355 }
356 #endif
357
358 /*
359 * Glue functions.
360 */
361 u_char
362 esp_pcmcia_read_reg(sc, reg)
363 struct ncr53c9x_softc *sc;
364 int reg;
365 {
366 struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc;
367 u_char v;
368
369 v = bus_space_read_1(esc->sc_pcioh.iot, esc->sc_pcioh.ioh, reg);
370 return v;
371 }
372
373 void
374 esp_pcmcia_write_reg(sc, reg, val)
375 struct ncr53c9x_softc *sc;
376 int reg;
377 u_char val;
378 {
379 struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc;
380 u_char v = val;
381
382 if (reg == NCR_CMD && v == (NCRCMD_TRANS|NCRCMD_DMA))
383 v = NCRCMD_TRANS;
384 bus_space_write_1(esc->sc_pcioh.iot, esc->sc_pcioh.ioh, reg, v);
385 }
386
387 int
388 esp_pcmcia_dma_isintr(sc)
389 struct ncr53c9x_softc *sc;
390 {
391
392 return NCR_READ_REG(sc, NCR_STAT) & NCRSTAT_INT;
393 }
394
395 void
396 esp_pcmcia_dma_reset(sc)
397 struct ncr53c9x_softc *sc;
398 {
399 struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc;
400
401 esc->sc_active = 0;
402 esc->sc_tc = 0;
403 }
404
405 int
406 esp_pcmcia_dma_intr(sc)
407 struct ncr53c9x_softc *sc;
408 {
409 struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc;
410 u_char *p;
411 u_int espphase, espstat, espintr;
412 int cnt;
413
414 if (esc->sc_active == 0) {
415 printf("%s: dma_intr--inactive DMA\n", sc->sc_dev.dv_xname);
416 return -1;
417 }
418
419 if ((sc->sc_espintr & NCRINTR_BS) == 0) {
420 esc->sc_active = 0;
421 return 0;
422 }
423
424 cnt = *esc->sc_pdmalen;
425 if (*esc->sc_pdmalen == 0) {
426 printf("%s: data interrupt, but no count left\n",
427 sc->sc_dev.dv_xname);
428 }
429
430 p = *esc->sc_dmaaddr;
431 espphase = sc->sc_phase;
432 espstat = (u_int) sc->sc_espstat;
433 espintr = (u_int) sc->sc_espintr;
434 do {
435 if (esc->sc_datain) {
436 *p++ = NCR_READ_REG(sc, NCR_FIFO);
437 cnt--;
438 if (espphase == DATA_IN_PHASE)
439 NCR_WRITE_REG(sc, NCR_CMD, NCRCMD_TRANS);
440 else
441 esc->sc_active = 0;
442 } else {
443 if (espphase == DATA_OUT_PHASE ||
444 espphase == MESSAGE_OUT_PHASE) {
445 NCR_WRITE_REG(sc, NCR_FIFO, *p++);
446 cnt--;
447 NCR_WRITE_REG(sc, NCR_CMD, NCRCMD_TRANS);
448 } else
449 esc->sc_active = 0;
450 }
451
452 if (esc->sc_active) {
453 while (!(NCR_READ_REG(sc, NCR_STAT) & NCRSTAT_INT));
454 espstat = NCR_READ_REG(sc, NCR_STAT);
455 espintr = NCR_READ_REG(sc, NCR_INTR);
456 espphase = (espintr & NCRINTR_DIS)
457 ? /* Disconnected */ BUSFREE_PHASE
458 : espstat & PHASE_MASK;
459 }
460 } while (esc->sc_active && espintr);
461 sc->sc_phase = espphase;
462 sc->sc_espstat = (u_char) espstat;
463 sc->sc_espintr = (u_char) espintr;
464 *esc->sc_dmaaddr = p;
465 *esc->sc_pdmalen = cnt;
466
467 if (*esc->sc_pdmalen == 0)
468 esc->sc_tc = NCRSTAT_TC;
469 sc->sc_espstat |= esc->sc_tc;
470 return 0;
471 }
472
473 int
474 esp_pcmcia_dma_setup(sc, addr, len, datain, dmasize)
475 struct ncr53c9x_softc *sc;
476 caddr_t *addr;
477 size_t *len;
478 int datain;
479 size_t *dmasize;
480 {
481 struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc;
482
483 esc->sc_dmaaddr = addr;
484 esc->sc_pdmalen = len;
485 esc->sc_datain = datain;
486 esc->sc_dmasize = *dmasize;
487 esc->sc_tc = 0;
488
489 return 0;
490 }
491
492 void
493 esp_pcmcia_dma_go(sc)
494 struct ncr53c9x_softc *sc;
495 {
496 struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc;
497
498 esc->sc_active = 1;
499 }
500
501 void
502 esp_pcmcia_dma_stop(sc)
503 struct ncr53c9x_softc *sc;
504 {
505 }
506
507 int
508 esp_pcmcia_dma_isactive(sc)
509 struct ncr53c9x_softc *sc;
510 {
511 struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc;
512
513 return (esc->sc_active);
514 }
515