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