esp_pcmcia.c revision 1.39
1/* $NetBSD: esp_pcmcia.c,v 1.39 2016/07/07 06:55:42 msaitoh Exp $ */ 2 3/*- 4 * Copyright (c) 2000, 2004 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 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include <sys/cdefs.h> 33__KERNEL_RCSID(0, "$NetBSD: esp_pcmcia.c,v 1.39 2016/07/07 06:55:42 msaitoh Exp $"); 34 35#include <sys/param.h> 36#include <sys/systm.h> 37#include <sys/device.h> 38#include <sys/buf.h> 39 40#include <sys/bus.h> 41#include <sys/intr.h> 42 43#include <dev/scsipi/scsi_all.h> 44#include <dev/scsipi/scsipi_all.h> 45#include <dev/scsipi/scsiconf.h> 46 47#include <dev/pcmcia/pcmciareg.h> 48#include <dev/pcmcia/pcmciavar.h> 49#include <dev/pcmcia/pcmciadevs.h> 50 51#include <dev/ic/ncr53c9xreg.h> 52#include <dev/ic/ncr53c9xvar.h> 53 54struct esp_pcmcia_softc { 55 struct ncr53c9x_softc sc_ncr53c9x; /* glue to MI code */ 56 57 int sc_active; /* Pseudo-DMA state vars */ 58 int sc_tc; 59 int sc_datain; 60 size_t sc_dmasize; 61 size_t sc_dmatrans; 62 uint8_t **sc_dmaaddr; 63 size_t *sc_pdmalen; 64 65 /* PCMCIA-specific goo. */ 66 struct pcmcia_function *sc_pf; /* our PCMCIA function */ 67 void *sc_ih; /* interrupt handler */ 68#ifdef ESP_PCMCIA_POLL 69 struct callout sc_poll_ch; 70#endif 71 bus_space_tag_t sc_iot; 72 bus_space_handle_t sc_ioh; 73 74 int sc_state; 75#define ESP_PCMCIA_ATTACHED 3 76}; 77 78int esp_pcmcia_match(device_t, cfdata_t, void *); 79int esp_pcmcia_validate_config(struct pcmcia_config_entry *); 80void esp_pcmcia_attach(device_t, device_t, void *); 81void esp_pcmcia_init(struct esp_pcmcia_softc *); 82int esp_pcmcia_detach(device_t, int); 83int esp_pcmcia_enable(device_t, int); 84 85CFATTACH_DECL_NEW(esp_pcmcia, sizeof(struct esp_pcmcia_softc), 86 esp_pcmcia_match, esp_pcmcia_attach, esp_pcmcia_detach, NULL); 87 88/* 89 * Functions and the switch for the MI code. 90 */ 91#ifdef ESP_PCMCIA_POLL 92void esp_pcmcia_poll(void *); 93#endif 94uint8_t esp_pcmcia_read_reg(struct ncr53c9x_softc *, int); 95void esp_pcmcia_write_reg(struct ncr53c9x_softc *, int, uint8_t); 96int esp_pcmcia_dma_isintr(struct ncr53c9x_softc *); 97void esp_pcmcia_dma_reset(struct ncr53c9x_softc *); 98int esp_pcmcia_dma_intr(struct ncr53c9x_softc *); 99int esp_pcmcia_dma_setup(struct ncr53c9x_softc *, uint8_t **, 100 size_t *, int, size_t *); 101void esp_pcmcia_dma_go(struct ncr53c9x_softc *); 102void esp_pcmcia_dma_stop(struct ncr53c9x_softc *); 103int esp_pcmcia_dma_isactive(struct ncr53c9x_softc *); 104 105const struct ncr53c9x_glue esp_pcmcia_glue = { 106 esp_pcmcia_read_reg, 107 esp_pcmcia_write_reg, 108 esp_pcmcia_dma_isintr, 109 esp_pcmcia_dma_reset, 110 esp_pcmcia_dma_intr, 111 esp_pcmcia_dma_setup, 112 esp_pcmcia_dma_go, 113 esp_pcmcia_dma_stop, 114 esp_pcmcia_dma_isactive, 115 NULL, /* gl_clear_latched_intr */ 116}; 117 118const struct pcmcia_product esp_pcmcia_products[] = { 119 { PCMCIA_VENDOR_PANASONIC, PCMCIA_PRODUCT_PANASONIC_KXLC002, 120 PCMCIA_CIS_PANASONIC_KXLC002 }, 121 122 { PCMCIA_VENDOR_RATOC, PCMCIA_PRODUCT_RATOC_REX_9530, 123 PCMCIA_CIS_RATOC_REX_9530 }, 124}; 125const size_t esp_pcmcia_nproducts = __arraycount(esp_pcmcia_products); 126 127int 128esp_pcmcia_match(device_t parent, cfdata_t cf, void *aux) 129{ 130 struct pcmcia_attach_args *pa = aux; 131 132 if (pcmcia_product_lookup(pa, esp_pcmcia_products, esp_pcmcia_nproducts, 133 sizeof(esp_pcmcia_products[0]), NULL)) 134 return 1; 135 return 0; 136} 137 138int 139esp_pcmcia_validate_config(struct pcmcia_config_entry *cfe) 140{ 141 142 if (cfe->iftype != PCMCIA_IFTYPE_IO || 143 cfe->num_memspace != 0 || 144 cfe->num_iospace != 1) 145 return EINVAL; 146 return 0; 147} 148 149void 150esp_pcmcia_attach(device_t parent, device_t self, void *aux) 151{ 152 struct esp_pcmcia_softc *esc = device_private(self); 153 struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x; 154 struct pcmcia_attach_args *pa = aux; 155 struct pcmcia_config_entry *cfe; 156 struct pcmcia_function *pf = pa->pf; 157 int error; 158 159 sc->sc_dev = self; 160 161 esc->sc_pf = pf; 162 163 error = pcmcia_function_configure(pf, esp_pcmcia_validate_config); 164 if (error) { 165 aprint_error_dev(self, "configure failed, error=%d\n", error); 166 return; 167 } 168 169 cfe = pf->cfe; 170 esc->sc_iot = cfe->iospace[0].handle.iot; 171 esc->sc_ioh = cfe->iospace[0].handle.ioh; 172 esp_pcmcia_init(esc); 173 174 aprint_normal("%s", device_xname(self)); 175 176 sc->sc_adapter.adapt_minphys = minphys; 177 sc->sc_adapter.adapt_request = ncr53c9x_scsipi_request; 178 sc->sc_adapter.adapt_enable = esp_pcmcia_enable; 179 180 ncr53c9x_attach(sc); 181 esc->sc_state = ESP_PCMCIA_ATTACHED; 182} 183 184void 185esp_pcmcia_init(struct esp_pcmcia_softc *esc) 186{ 187 struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x; 188 189 /* id 7, clock 40M, parity ON, sync OFF, fast ON, slow ON */ 190 191 sc->sc_glue = &esp_pcmcia_glue; 192 193#ifdef ESP_PCMCIA_POLL 194 callout_init(&esc->sc_poll_ch, 0); 195#endif 196 197 sc->sc_rev = NCR_VARIANT_ESP406; 198 sc->sc_id = 7; 199 sc->sc_freq = 40; 200 /* try -PARENB -SLOW */ 201 sc->sc_cfg1 = sc->sc_id | NCRCFG1_PARENB | NCRCFG1_SLOW; 202 /* try +FE */ 203 sc->sc_cfg2 = NCRCFG2_SCSI2; 204 /* try -IDM -FSCSI -FCLK */ 205 sc->sc_cfg3 = NCRESPCFG3_CDB | NCRESPCFG3_FCLK | NCRESPCFG3_IDM | 206 NCRESPCFG3_FSCSI; 207 sc->sc_cfg4 = NCRCFG4_ACTNEG; 208 /* try +INTP */ 209 sc->sc_cfg5 = NCRCFG5_CRS1 | NCRCFG5_AADDR | NCRCFG5_PTRINC; 210 sc->sc_minsync = 0; 211 sc->sc_maxxfer = 64 * 1024; 212} 213 214int 215esp_pcmcia_detach(device_t self, int flags) 216{ 217 struct esp_pcmcia_softc *sc = device_private(self); 218 int error; 219 220 if (sc->sc_state != ESP_PCMCIA_ATTACHED) 221 return 0; 222 223 error = ncr53c9x_detach(&sc->sc_ncr53c9x, flags); 224 if (error) 225 return error; 226 227 pcmcia_function_unconfigure(sc->sc_pf); 228 229 return 0; 230} 231 232int 233esp_pcmcia_enable(device_t self, int onoff) 234{ 235 struct esp_pcmcia_softc *sc = device_private(self); 236 int error; 237 238 if (onoff) { 239#ifdef ESP_PCMCIA_POLL 240 callout_reset(&sc->sc_poll_ch, 1, esp_pcmcia_poll, sc); 241#else 242 /* Establish the interrupt handler. */ 243 sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_BIO, 244 ncr53c9x_intr, &sc->sc_ncr53c9x); 245 if (!sc->sc_ih) 246 return EIO; 247#endif 248 249 error = pcmcia_function_enable(sc->sc_pf); 250 if (error) { 251 pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih); 252 sc->sc_ih = 0; 253 return error; 254 } 255 256 /* Initialize only chip. */ 257 ncr53c9x_init(&sc->sc_ncr53c9x, 0); 258 } else { 259 pcmcia_function_disable(sc->sc_pf); 260#ifdef ESP_PCMCIA_POLL 261 callout_stop(&sc->sc_poll_ch); 262#else 263 pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih); 264 sc->sc_ih = 0; 265#endif 266 } 267 268 return 0; 269} 270 271#ifdef ESP_PCMCIA_POLL 272void 273esp_pcmcia_poll(void *arg) 274{ 275 struct esp_pcmcia_softc *esc = arg; 276 277 (void)ncr53c9x_intr(&esc->sc_ncr53c9x); 278 callout_reset(&esc->sc_poll_ch, 1, esp_pcmcia_poll, esc); 279} 280#endif 281 282/* 283 * Glue functions. 284 */ 285uint8_t 286esp_pcmcia_read_reg(struct ncr53c9x_softc *sc, int reg) 287{ 288 struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc; 289 290 return bus_space_read_1(esc->sc_iot, esc->sc_ioh, reg); 291} 292 293void 294esp_pcmcia_write_reg(struct ncr53c9x_softc *sc, int reg, uint8_t val) 295{ 296 struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc; 297 uint8_t v = val; 298 299 if (reg == NCR_CMD && v == (NCRCMD_TRANS|NCRCMD_DMA)) 300 v = NCRCMD_TRANS; 301 bus_space_write_1(esc->sc_iot, esc->sc_ioh, reg, v); 302} 303 304int 305esp_pcmcia_dma_isintr(struct ncr53c9x_softc *sc) 306{ 307 308 return NCR_READ_REG(sc, NCR_STAT) & NCRSTAT_INT; 309} 310 311void 312esp_pcmcia_dma_reset(struct ncr53c9x_softc *sc) 313{ 314 struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc; 315 316 esc->sc_active = 0; 317 esc->sc_tc = 0; 318} 319 320int 321esp_pcmcia_dma_intr(struct ncr53c9x_softc *sc) 322{ 323 struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc; 324 uint8_t *p; 325 u_int espphase, espstat, espintr; 326 int cnt; 327 328 if (esc->sc_active == 0) { 329 printf("%s: dma_intr--inactive DMA\n", 330 device_xname(sc->sc_dev)); 331 return -1; 332 } 333 334 if ((sc->sc_espintr & NCRINTR_BS) == 0) { 335 esc->sc_active = 0; 336 return 0; 337 } 338 339 cnt = *esc->sc_pdmalen; 340 if (*esc->sc_pdmalen == 0) { 341 printf("%s: data interrupt, but no count left\n", 342 device_xname(sc->sc_dev)); 343 } 344 345 p = *esc->sc_dmaaddr; 346 espphase = sc->sc_phase; 347 espstat = (u_int)sc->sc_espstat; 348 espintr = (u_int)sc->sc_espintr; 349 do { 350 if (esc->sc_datain) { 351 *p++ = NCR_READ_REG(sc, NCR_FIFO); 352 cnt--; 353 if (espphase == DATA_IN_PHASE) 354 NCR_WRITE_REG(sc, NCR_CMD, NCRCMD_TRANS); 355 else 356 esc->sc_active = 0; 357 } else { 358 if (espphase == DATA_OUT_PHASE || 359 espphase == MESSAGE_OUT_PHASE) { 360 NCR_WRITE_REG(sc, NCR_FIFO, *p++); 361 cnt--; 362 NCR_WRITE_REG(sc, NCR_CMD, NCRCMD_TRANS); 363 } else 364 esc->sc_active = 0; 365 } 366 367 if (esc->sc_active) { 368 while ((NCR_READ_REG(sc, NCR_STAT) & NCRSTAT_INT) == 0) 369 ; 370 espstat = NCR_READ_REG(sc, NCR_STAT); 371 espintr = NCR_READ_REG(sc, NCR_INTR); 372 espphase = (espintr & NCRINTR_DIS) 373 ? /* Disconnected */ BUSFREE_PHASE 374 : espstat & PHASE_MASK; 375 } 376 } while (esc->sc_active && espintr); 377 sc->sc_phase = espphase; 378 sc->sc_espstat = (uint8_t)espstat; 379 sc->sc_espintr = (uint8_t)espintr; 380 *esc->sc_dmaaddr = p; 381 *esc->sc_pdmalen = cnt; 382 383 if (*esc->sc_pdmalen == 0) 384 esc->sc_tc = NCRSTAT_TC; 385 sc->sc_espstat |= esc->sc_tc; 386 return 0; 387} 388 389int 390esp_pcmcia_dma_setup(struct ncr53c9x_softc *sc, uint8_t **addr, size_t *len, 391 int datain, size_t *dmasize) 392{ 393 struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc; 394 395 esc->sc_dmaaddr = addr; 396 esc->sc_pdmalen = len; 397 esc->sc_datain = datain; 398 esc->sc_dmasize = *dmasize; 399 esc->sc_tc = 0; 400 401 return 0; 402} 403 404void 405esp_pcmcia_dma_go(struct ncr53c9x_softc *sc) 406{ 407 struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc; 408 409 esc->sc_active = 1; 410} 411 412void 413esp_pcmcia_dma_stop(struct ncr53c9x_softc *sc) 414{ 415} 416 417int 418esp_pcmcia_dma_isactive(struct ncr53c9x_softc *sc) 419{ 420 struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc; 421 422 return esc->sc_active; 423} 424