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 54 struct 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 78 int esp_pcmcia_match(device_t, cfdata_t, void *); 79 int esp_pcmcia_validate_config(struct pcmcia_config_entry *); 80 void esp_pcmcia_attach(device_t, device_t, void *); 81 void esp_pcmcia_init(struct esp_pcmcia_softc *); 82 int esp_pcmcia_detach(device_t, int); 83 int esp_pcmcia_enable(device_t, int); 84 85 CFATTACH_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 92 void esp_pcmcia_poll(void *); 93 #endif 94 uint8_t esp_pcmcia_read_reg(struct ncr53c9x_softc *, int); 95 void esp_pcmcia_write_reg(struct ncr53c9x_softc *, int, uint8_t); 96 int esp_pcmcia_dma_isintr(struct ncr53c9x_softc *); 97 void esp_pcmcia_dma_reset(struct ncr53c9x_softc *); 98 int esp_pcmcia_dma_intr(struct ncr53c9x_softc *); 99 int esp_pcmcia_dma_setup(struct ncr53c9x_softc *, uint8_t **, 100 size_t *, int, size_t *); 101 void esp_pcmcia_dma_go(struct ncr53c9x_softc *); 102 void esp_pcmcia_dma_stop(struct ncr53c9x_softc *); 103 int esp_pcmcia_dma_isactive(struct ncr53c9x_softc *); 104 105 const 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 118 const 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 }; 125 const size_t esp_pcmcia_nproducts = __arraycount(esp_pcmcia_products); 126 127 int 128 esp_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 138 int 139 esp_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 149 void 150 esp_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 184 void 185 esp_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 214 int 215 esp_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 232 int 233 esp_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 272 void 273 esp_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 */ 285 uint8_t 286 esp_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 293 void 294 esp_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 304 int 305 esp_pcmcia_dma_isintr(struct ncr53c9x_softc *sc) 306 { 307 308 return NCR_READ_REG(sc, NCR_STAT) & NCRSTAT_INT; 309 } 310 311 void 312 esp_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 320 int 321 esp_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 389 int 390 esp_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 404 void 405 esp_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 412 void 413 esp_pcmcia_dma_stop(struct ncr53c9x_softc *sc) 414 { 415 } 416 417 int 418 esp_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