1 /* $NetBSD: esp_mca.c,v 1.20 2009/01/20 20:49:51 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2001 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jaromir Dolecek <jdolecek@NetBSD.org>. 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 /* 33 * Driver for NCR 53c90, MCA version, with 86c01 DMA controller chip. 34 * 35 * Some of the information used to write this driver was taken 36 * from Tymm Twillman <tymm@computer.org>'s Linux MCA NC53c90 driver, 37 * in drivers/scsi/mca_53c9x.c 38 */ 39 40 #include <sys/cdefs.h> 41 __KERNEL_RCSID(0, "$NetBSD: esp_mca.c,v 1.20 2009/01/20 20:49:51 christos Exp $"); 42 43 #include <sys/types.h> 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/kernel.h> 47 #include <sys/errno.h> 48 #include <sys/ioctl.h> 49 #include <sys/device.h> 50 #include <sys/buf.h> 51 #include <sys/proc.h> 52 #include <sys/user.h> 53 #include <sys/queue.h> 54 55 #include <dev/scsipi/scsi_all.h> 56 #include <dev/scsipi/scsipi_all.h> 57 #include <dev/scsipi/scsiconf.h> 58 #include <dev/scsipi/scsi_message.h> 59 60 #include <sys/bus.h> 61 #include <sys/cpu.h> 62 63 #include <dev/ic/ncr53c9xreg.h> 64 #include <dev/ic/ncr53c9xvar.h> 65 66 #include <dev/mca/espvar.h> 67 #include <dev/mca/espreg.h> 68 69 #include <dev/mca/mcavar.h> 70 #include <dev/mca/mcareg.h> 71 #include <dev/mca/mcadevs.h> 72 73 #if 0 74 #if defined(DEBUG) && !defined(NCR53C9X_DEBUG) 75 #define NCR53C9X_DEBUG 76 #endif 77 #endif 78 79 #ifdef NCR53C9X_DEBUG 80 static int esp_mca_debug = 0; 81 #define DPRINTF(x) if (esp_mca_debug) printf x; 82 #else 83 #define DPRINTF(x) 84 #endif 85 86 #define ESP_MCA_IOSIZE 0x20 87 #define ESP_REG_OFFSET 0x10 88 89 static int esp_mca_match(device_t, cfdata_t, void *); 90 static void esp_mca_attach(device_t, device_t, void *); 91 92 CFATTACH_DECL_NEW(esp_mca, sizeof(struct esp_softc), 93 esp_mca_match, esp_mca_attach, NULL, NULL); 94 95 /* 96 * Functions and the switch for the MI code. 97 */ 98 static uint8_t esp_read_reg(struct ncr53c9x_softc *, int); 99 static void esp_write_reg(struct ncr53c9x_softc *, int, uint8_t); 100 static int esp_dma_isintr(struct ncr53c9x_softc *); 101 static void esp_dma_reset(struct ncr53c9x_softc *); 102 static int esp_dma_intr(struct ncr53c9x_softc *); 103 static int esp_dma_setup(struct ncr53c9x_softc *, uint8_t **, 104 size_t *, int, size_t *); 105 static void esp_dma_go(struct ncr53c9x_softc *); 106 static void esp_dma_stop(struct ncr53c9x_softc *); 107 static int esp_dma_isactive(struct ncr53c9x_softc *); 108 109 static struct ncr53c9x_glue esp_glue = { 110 esp_read_reg, 111 esp_write_reg, 112 esp_dma_isintr, 113 esp_dma_reset, 114 esp_dma_intr, 115 esp_dma_setup, 116 esp_dma_go, 117 esp_dma_stop, 118 esp_dma_isactive, 119 NULL, /* gl_clear_latched_intr */ 120 }; 121 122 static int 123 esp_mca_match(device_t parent, cfdata_t cf, void *aux) 124 { 125 struct mca_attach_args *ma = aux; 126 127 switch (ma->ma_id) { 128 case MCA_PRODUCT_NCR53C90: 129 return 1; 130 } 131 132 return 0; 133 } 134 135 static void 136 esp_mca_attach(device_t parent, device_t self, void *aux) 137 { 138 struct esp_softc *esc = device_private(self); 139 struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x; 140 struct mca_attach_args *ma = aux; 141 uint16_t iobase; 142 int scsi_id, irq, drq, error; 143 bus_space_handle_t ioh; 144 int pos2, pos3, pos5; 145 146 static const uint16_t ncrmca_iobase[] = { 147 0, 0x240, 0x340, 0x400, 0x420, 0x3240, 0x8240, 0xa240 148 }; 149 150 sc->sc_dev = self; 151 152 /* 153 * NCR SCSI Adapter (ADF 7f4f) 154 * 155 * POS register 2: (adf pos0) 156 * 157 * 7 6 5 4 3 2 1 0 158 * \_/ \___/ \__ enable: 0=adapter disabled, 1=adapter enabled 159 * | \____ I/O base (32B): 001=0x240 010=0x340 011=0x400 160 * | 100=0x420 101=0x3240 110=0x8240 111=0xa240 161 * \__________ IRQ: 00=3 01=5 10=7 11=9 162 * 163 * POS register 3: (adf pos1) 164 * 165 * 7 6 5 4 3 2 1 0 166 * 1 1 1 | \_____/ 167 * | \__ DMA level 168 * \_________ Fairness: 1=enabled 0=disabled 169 * 170 * POS register 5: (adf pos3) 171 * 172 * 7 6 5 4 3 2 1 0 173 * 1 | \___/ 174 * | \__ Static Ram: 0xC8000-0xC87FF + XX*0x4000 175 * \___________ Host Adapter ID: 1=7 0=6 176 */ 177 178 pos2 = mca_conf_read(ma->ma_mc, ma->ma_slot, 2); 179 pos3 = mca_conf_read(ma->ma_mc, ma->ma_slot, 3); 180 pos5 = mca_conf_read(ma->ma_mc, ma->ma_slot, 5); 181 182 iobase = ncrmca_iobase[(pos2 & 0x0e) >> 1]; 183 irq = 3 + 2 * ((pos2 & 0x30) >> 4); 184 drq = (pos3 & 0x0f); 185 scsi_id = 6 + ((pos5 & 0x20) ? 1 : 0); 186 187 aprint_normal(" slot %d irq %d drq %d: NCR SCSI Adapter\n", 188 ma->ma_slot + 1, irq, drq); 189 190 /* Map the 86C01 registers */ 191 if (bus_space_map(ma->ma_iot, iobase, ESP_MCA_IOSIZE, 0, &ioh)) { 192 aprint_error_dev(sc->sc_dev, "can't map i/o space\n"); 193 return; 194 } 195 196 esc->sc_iot = ma->ma_iot; 197 esc->sc_ioh = ioh; 198 199 /* Submap the 'esp' registers */ 200 if (bus_space_subregion(ma->ma_iot, ioh, ESP_REG_OFFSET, 201 ESP_MCA_IOSIZE-ESP_REG_OFFSET, &esc->sc_esp_ioh)) { 202 aprint_error_dev(sc->sc_dev, "can't subregion i/o space\n"); 203 return; 204 } 205 206 /* Setup DMA map */ 207 esc->sc_dmat = ma->ma_dmat; 208 if ((error = mca_dmamap_create(esc->sc_dmat, MAXPHYS, 209 BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW | MCABUS_DMA_IOPORT, 210 &esc->sc_xfer, drq)) != 0){ 211 aprint_error_dev(sc->sc_dev, 212 "couldn't create DMA map - error %d\n", error); 213 return; 214 } 215 216 /* MI code glue */ 217 sc->sc_id = scsi_id; 218 sc->sc_freq = 25; /* MHz */ 219 220 sc->sc_glue = &esp_glue; 221 222 sc->sc_cfg1 = sc->sc_id | NCRCFG1_PARENB; //| NCRCFG1_SLOW; 223 /* No point setting sc_cfg[2345], they won't be used */ 224 225 sc->sc_rev = NCR_VARIANT_NCR53C90_86C01; 226 sc->sc_minsync = 0; 227 228 /* max 64KB DMA */ 229 sc->sc_maxxfer = 64 * 1024; 230 231 /* Establish interrupt */ 232 esc->sc_ih = mca_intr_establish(ma->ma_mc, irq, IPL_BIO, ncr53c9x_intr, 233 esc); 234 if (esc->sc_ih == NULL) { 235 aprint_error_dev(sc->sc_dev, "couldn't establish interrupt\n"); 236 return; 237 } 238 239 /* 240 * Massage the 86C01 chip - setup MCA DMA controller for DMA via 241 * the 86C01 register, and enable 86C01 interrupts. 242 */ 243 mca_dma_set_ioport(drq, iobase + N86C01_PIO); 244 245 bus_space_write_1(esc->sc_iot, esc->sc_ioh, N86C01_MODE_ENABLE, 246 bus_space_read_1(esc->sc_iot, esc->sc_ioh, N86C01_MODE_ENABLE) | 247 N86C01_INTR_ENABLE); 248 249 /* 250 * Now try to attach all the sub-devices 251 */ 252 sc->sc_adapter.adapt_minphys = minphys; 253 sc->sc_adapter.adapt_request = ncr53c9x_scsipi_request; 254 255 /* Do the common parts of attachment. */ 256 printf("%s", device_xname(self)); 257 ncr53c9x_attach(sc); 258 } 259 260 /* 261 * Glue functions. 262 */ 263 264 static uint8_t 265 esp_read_reg(struct ncr53c9x_softc *sc, int reg) 266 { 267 struct esp_softc *esc = (struct esp_softc *)sc; 268 269 return bus_space_read_1(esc->sc_iot, esc->sc_esp_ioh, reg); 270 } 271 272 static void 273 esp_write_reg(struct ncr53c9x_softc *sc, int reg, uint8_t val) 274 { 275 struct esp_softc *esc = (struct esp_softc *)sc; 276 277 bus_space_write_1(esc->sc_iot, esc->sc_esp_ioh, reg, val); 278 } 279 280 static int 281 esp_dma_isintr(struct ncr53c9x_softc *sc) 282 { 283 struct esp_softc *esc = (struct esp_softc *)sc; 284 285 DPRINTF(("[esp_dma_isintr] ")); 286 return bus_space_read_1(esc->sc_iot, esc->sc_ioh, N86C01_STATUS) & 287 N86C01_IRQ_PEND; 288 } 289 290 static void 291 esp_dma_reset(struct ncr53c9x_softc *sc) 292 { 293 struct esp_softc *esc = (struct esp_softc *)sc; 294 295 DPRINTF(("[esp_dma_reset] ")); 296 297 if (esc->sc_flags & ESP_XFER_LOADED) { 298 bus_dmamap_unload(esc->sc_dmat, esc->sc_xfer); 299 esc->sc_flags &= ~ESP_XFER_LOADED; 300 } 301 302 if (esc->sc_flags & ESP_XFER_ACTIVE) { 303 esc->sc_flags &= ~ESP_XFER_ACTIVE; 304 mca_disk_unbusy(); 305 } 306 } 307 308 static int 309 esp_dma_intr(struct ncr53c9x_softc *sc) 310 { 311 struct esp_softc *esc = (struct esp_softc *)sc; 312 313 DPRINTF(("[esp_dma_intr] ")); 314 315 if ((esc->sc_flags & ESP_XFER_ACTIVE) == 0) { 316 printf("%s: dma_intr--inactive DMA\n", 317 device_xname(sc->sc_dev)); 318 return -1; 319 } 320 321 if ((sc->sc_espintr & NCRINTR_BS) == 0) { 322 esc->sc_flags &= ~ESP_XFER_ACTIVE; 323 mca_disk_unbusy(); 324 return 0; 325 } 326 327 sc->sc_espstat |= NCRSTAT_TC; /* XXX */ 328 329 if ((sc->sc_espstat & NCRSTAT_TC) == 0) { 330 printf("%s: DMA not complete?\n", device_xname(sc->sc_dev)); 331 return 1; 332 } 333 334 bus_dmamap_sync(esc->sc_dmat, esc->sc_xfer, 0, *esc->sc_xfer_len, 335 (esc->sc_flags & ESP_XFER_READ) ? 336 BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); 337 338 bus_dmamap_unload(esc->sc_dmat, esc->sc_xfer); 339 esc->sc_flags &= ~ESP_XFER_LOADED; 340 341 *esc->sc_xfer_addr += *esc->sc_xfer_len; 342 *esc->sc_xfer_len = 0; 343 344 esc->sc_flags &= ~ESP_XFER_ACTIVE; 345 mca_disk_unbusy(); 346 347 return 0; 348 } 349 350 /* 351 * Setup DMA transfer. 352 */ 353 static int 354 esp_dma_setup(struct ncr53c9x_softc *sc, uint8_t **addr, size_t *len, 355 int datain, size_t *dmasize) 356 { 357 struct esp_softc *esc = (struct esp_softc *)sc; 358 int error; 359 int fl; 360 361 DPRINTF(("[esp_dma_setup] ")); 362 363 if (esc->sc_flags & ESP_XFER_LOADED) { 364 printf("%s: %s: unloading leaked xfer\n", 365 device_xname(sc->sc_dev), __func__); 366 bus_dmamap_unload(esc->sc_dmat, esc->sc_xfer); 367 esc->sc_flags &= ~ESP_XFER_LOADED; 368 } 369 370 /* Load the buffer for DMA transfer. */ 371 fl = (datain) ? BUS_DMA_READ : BUS_DMA_WRITE; 372 373 if ((error = bus_dmamap_load(esc->sc_dmat, esc->sc_xfer, *addr, 374 *len, NULL, BUS_DMA_STREAMING|fl))) { 375 printf("%s: %s: unable to load DMA buffer - error %d\n", 376 device_xname(sc->sc_dev), __func__, error); 377 return error; 378 } 379 380 bus_dmamap_sync(esc->sc_dmat, esc->sc_xfer, 0, *len, 381 (datain) ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); 382 383 esc->sc_flags |= ESP_XFER_LOADED | (datain ? ESP_XFER_READ : 0); 384 esc->sc_xfer_addr = addr; 385 esc->sc_xfer_len = len; 386 387 return 0; 388 } 389 390 static void 391 esp_dma_go(struct ncr53c9x_softc *sc) 392 { 393 struct esp_softc *esc = (struct esp_softc *)sc; 394 DPRINTF(("[esp_dma_go] ")); 395 396 esc->sc_flags |= ESP_XFER_ACTIVE; 397 mca_disk_busy(); 398 } 399 400 static void 401 esp_dma_stop(struct ncr53c9x_softc *sc) 402 { 403 404 DPRINTF(("[esp_dma_stop] ")); 405 406 panic("%s: stop not yet implemented", device_xname(sc->sc_dev)); 407 } 408 409 static int 410 esp_dma_isactive(struct ncr53c9x_softc *sc) 411 { 412 struct esp_softc *esc = (struct esp_softc *)sc; 413 DPRINTF(("[esp_dma_isactive] ")); 414 415 return esc->sc_flags & ESP_XFER_ACTIVE; 416 } 417