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