1 /* $NetBSD: asc.c,v 1.22 2008/04/28 20:23:28 martin Exp $ */ 2 /*- 3 * Copyright (c) 2000 The NetBSD Foundation, Inc. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to The NetBSD Foundation 7 * by Wayne Knowles 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 __KERNEL_RCSID(0, "$NetBSD: asc.c,v 1.22 2008/04/28 20:23:28 martin Exp $"); 33 34 #include <sys/types.h> 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/kernel.h> 38 #include <sys/errno.h> 39 #include <sys/device.h> 40 #include <sys/buf.h> 41 #include <sys/malloc.h> 42 43 #include <uvm/uvm_extern.h> 44 45 #include <dev/scsipi/scsi_all.h> 46 #include <dev/scsipi/scsipi_all.h> 47 #include <dev/scsipi/scsiconf.h> 48 #include <dev/scsipi/scsi_message.h> 49 50 #include <machine/cpu.h> 51 #include <machine/autoconf.h> 52 #include <machine/mainboard.h> 53 #include <machine/bus.h> 54 55 #include <mipsco/obio/rambo.h> 56 57 #include <dev/ic/ncr53c9xreg.h> 58 #include <dev/ic/ncr53c9xvar.h> 59 60 struct asc_softc { 61 struct ncr53c9x_softc sc_ncr53c9x; /* glue to MI code */ 62 struct evcnt sc_intrcnt; /* Interrupt counter */ 63 bus_space_tag_t sc_bst; 64 bus_space_handle_t sc_bsh; /* NCR 53c94 registers */ 65 bus_space_handle_t dm_bsh; /* RAMBO registers */ 66 bus_dma_tag_t sc_dmat; 67 bus_dmamap_t sc_dmamap; 68 uint8_t **sc_dmaaddr; 69 size_t *sc_dmalen; 70 size_t sc_dmasize; 71 int sc_flags; 72 #define DMA_IDLE 0x0 73 #define DMA_PULLUP 0x1 74 #define DMA_ACTIVE 0x2 75 #define DMA_MAPLOADED 0x4 76 uint32_t dm_mode; 77 int dm_curseg; 78 }; 79 80 static int ascmatch(device_t, cfdata_t, void *); 81 static void ascattach(device_t, device_t, void *); 82 83 CFATTACH_DECL_NEW(asc, sizeof(struct asc_softc), 84 ascmatch, ascattach, NULL, NULL); 85 86 /* 87 * Functions and the switch for the MI code. 88 */ 89 static uint8_t asc_read_reg(struct ncr53c9x_softc *, int); 90 static void asc_write_reg(struct ncr53c9x_softc *, int, uint8_t); 91 static int asc_dma_isintr(struct ncr53c9x_softc *); 92 static void asc_dma_reset(struct ncr53c9x_softc *); 93 static int asc_dma_intr(struct ncr53c9x_softc *); 94 static int asc_dma_setup(struct ncr53c9x_softc *, uint8_t **, 95 size_t *, int, size_t *); 96 static void asc_dma_go(struct ncr53c9x_softc *); 97 static void asc_dma_stop(struct ncr53c9x_softc *); 98 static int asc_dma_isactive(struct ncr53c9x_softc *); 99 100 static struct ncr53c9x_glue asc_glue = { 101 asc_read_reg, 102 asc_write_reg, 103 asc_dma_isintr, 104 asc_dma_reset, 105 asc_dma_intr, 106 asc_dma_setup, 107 asc_dma_go, 108 asc_dma_stop, 109 asc_dma_isactive, 110 NULL, /* gl_clear_latched_intr */ 111 }; 112 113 static int asc_intr(void *); 114 115 #define MAX_SCSI_XFER (64 * 1024) 116 #define MAX_DMA_SZ MAX_SCSI_XFER 117 #define DMA_SEGS (MAX_DMA_SZ / PAGE_SIZE) 118 119 static int 120 ascmatch(device_t parent, cfdata_t cf, void *aux) 121 { 122 123 return 1; 124 } 125 126 static void 127 ascattach(device_t parent, device_t self, void *aux) 128 { 129 struct asc_softc *esc = device_private(self); 130 struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x; 131 struct confargs *ca = aux; 132 133 /* 134 * Set up glue for MI code early; we use some of it here. 135 */ 136 sc->sc_dev = self; 137 sc->sc_glue = &asc_glue; 138 139 esc->sc_bst = ca->ca_bustag; 140 esc->sc_dmat = ca->ca_dmatag; 141 142 if (bus_space_map(ca->ca_bustag, ca->ca_addr, 143 16 * 4, /* sizeof (ncr53c9xreg) */ 144 BUS_SPACE_MAP_LINEAR, 145 &esc->sc_bsh) != 0) { 146 aprint_error(": cannot map registers\n"); 147 return; 148 } 149 150 if (bus_space_map(ca->ca_bustag, RAMBO_BASE, sizeof(struct rambo_ch), 151 BUS_SPACE_MAP_LINEAR, &esc->dm_bsh) != 0) { 152 aprint_error(": cannot map DMA registers\n"); 153 return; 154 } 155 156 if (bus_dmamap_create(esc->sc_dmat, MAX_DMA_SZ, 157 DMA_SEGS, MAX_DMA_SZ, RB_BOUNDRY, BUS_DMA_WAITOK, 158 &esc->sc_dmamap) != 0) { 159 aprint_error(": failed to create dmamap\n"); 160 return; 161 } 162 163 evcnt_attach_dynamic(&esc->sc_intrcnt, EVCNT_TYPE_INTR, NULL, 164 device_xname(self), "intr"); 165 166 esc->sc_flags = DMA_IDLE; 167 asc_dma_reset(sc); 168 169 /* Other settings */ 170 sc->sc_id = 7; 171 sc->sc_freq = 24; /* 24 MHz clock */ 172 173 /* 174 * Setup for genuine NCR 53C94 SCSI Controller 175 */ 176 177 sc->sc_cfg1 = sc->sc_id | NCRCFG1_PARENB; 178 sc->sc_cfg2 = NCRCFG2_SCSI2 | NCRCFG2_FE; 179 sc->sc_cfg3 = NCRCFG3_CDB | NCRCFG3_QTE | NCRCFG3_FSCSI; 180 sc->sc_rev = NCR_VARIANT_NCR53C94; 181 182 sc->sc_minsync = (1000 / sc->sc_freq) * 5 / 4; 183 sc->sc_maxxfer = MAX_SCSI_XFER; 184 185 #ifdef OLDNCR 186 if (NCR_READ_REG(sc, NCR_CFG3) == 0) { 187 aprint_normal(" [old revision]"); 188 sc->sc_cfg2 = 0; 189 sc->sc_cfg3 = 0; 190 sc->sc_minsync = 0; 191 } 192 #endif 193 194 sc->sc_adapter.adapt_minphys = minphys; 195 sc->sc_adapter.adapt_request = ncr53c9x_scsipi_request; 196 ncr53c9x_attach(sc); 197 198 bus_intr_establish(esc->sc_bst, SYS_INTR_SCSI, 0, 0, asc_intr, esc); 199 } 200 201 /* 202 * Glue functions. 203 */ 204 205 static uint8_t 206 asc_read_reg(struct ncr53c9x_softc *sc, int reg) 207 { 208 struct asc_softc *esc = (struct asc_softc *)sc; 209 210 return bus_space_read_1(esc->sc_bst, esc->sc_bsh, reg * 4 + 3); 211 } 212 213 static void 214 asc_write_reg(struct ncr53c9x_softc *sc, int reg, uint8_t val) 215 { 216 struct asc_softc *esc = (struct asc_softc *)sc; 217 218 bus_space_write_1(esc->sc_bst, esc->sc_bsh, reg * 4 + 3, val); 219 } 220 221 static void 222 dma_status(struct ncr53c9x_softc *sc) 223 { 224 struct asc_softc *esc = (struct asc_softc *)sc; 225 int count; 226 int stat; 227 void *addr; 228 uint32_t tc; 229 230 tc = (asc_read_reg(sc, NCR_TCM) << 8) + asc_read_reg(sc, NCR_TCL); 231 count = bus_space_read_2(esc->sc_bst, esc->dm_bsh, RAMBO_BLKCNT); 232 stat = bus_space_read_4(esc->sc_bst, esc->dm_bsh, RAMBO_MODE); 233 addr = (void *)bus_space_read_4(esc->sc_bst, esc->dm_bsh, RAMBO_CADDR); 234 235 printf("rambo status: cnt=%x addr=%p stat=%08x tc=%04x " 236 "ncr_stat=0x%02x ncr_fifo=0x%02x\n", 237 count, addr, stat, tc, 238 asc_read_reg(sc, NCR_STAT), 239 asc_read_reg(sc, NCR_FFLAG)); 240 } 241 242 static inline void 243 check_fifo(struct asc_softc *esc) 244 { 245 int i = 100; 246 247 while (i && !(bus_space_read_4(esc->sc_bst, esc->dm_bsh, 248 RAMBO_MODE) & RB_FIFO_EMPTY)) { 249 DELAY(1); 250 i--; 251 } 252 253 if (i == 0) { 254 dma_status((void *)esc); 255 panic("fifo didn't flush"); 256 } 257 } 258 259 static int 260 asc_dma_isintr(struct ncr53c9x_softc *sc) 261 { 262 263 return NCR_READ_REG(sc, NCR_STAT) & NCRSTAT_INT; 264 } 265 266 static void 267 asc_dma_reset(struct ncr53c9x_softc *sc) 268 { 269 struct asc_softc *esc = (struct asc_softc *)sc; 270 271 bus_space_write_2(esc->sc_bst, esc->dm_bsh, RAMBO_BLKCNT, 0); 272 bus_space_write_4(esc->sc_bst, esc->dm_bsh, RAMBO_MODE, 273 RB_CLRFIFO|RB_CLRERROR); 274 DELAY(10); 275 bus_space_write_4(esc->sc_bst, esc->dm_bsh, RAMBO_MODE, 0); 276 277 if (esc->sc_flags & DMA_MAPLOADED) 278 bus_dmamap_unload(esc->sc_dmat, esc->sc_dmamap); 279 280 esc->sc_flags = DMA_IDLE; 281 } 282 283 /* 284 * Setup a DMA transfer 285 */ 286 287 static int 288 asc_dma_setup(struct ncr53c9x_softc *sc, uint8_t **addr, size_t *len, 289 int datain, size_t *dmasize) 290 { 291 struct asc_softc *esc = (struct asc_softc *)sc; 292 paddr_t paddr; 293 size_t count, blocks; 294 int prime, err; 295 296 #ifdef DIAGNOSTIC 297 if (esc->sc_flags & DMA_ACTIVE) { 298 dma_status(sc); 299 panic("DMA active"); 300 } 301 #endif 302 303 esc->sc_dmaaddr = addr; 304 esc->sc_dmalen = len; 305 esc->sc_dmasize = *dmasize; 306 esc->sc_flags = datain ? DMA_PULLUP : 0; 307 308 NCR_DMA(("asc_dma_setup va=%p len=%d datain=%d count=%d\n", 309 *addr, *len, datain, esc->sc_dmasize)); 310 311 if (esc->sc_dmasize == 0) 312 return 0; 313 314 /* have dmamap for the transfering addresses */ 315 if ((err = bus_dmamap_load(esc->sc_dmat, esc->sc_dmamap, 316 *esc->sc_dmaaddr, esc->sc_dmasize, NULL /* kernel address */, BUS_DMA_NOWAIT)) != 0) 317 panic("%s: bus_dmamap_load err=%d", 318 device_xname(sc->sc_dev), err); 319 320 esc->sc_flags |= DMA_MAPLOADED; 321 322 paddr = esc->sc_dmamap->dm_segs[0].ds_addr; 323 count = esc->sc_dmamap->dm_segs[0].ds_len; 324 prime = (uint32_t)paddr & 0x3f; 325 blocks = (prime + count + 63) >> 6; 326 327 esc->dm_mode = datain ? RB_DMA_WR : RB_DMA_RD; 328 329 /* Set transfer direction and disable DMA */ 330 bus_space_write_4(esc->sc_bst, esc->dm_bsh, RAMBO_MODE, esc->dm_mode); 331 332 /* Load DMA transfer address */ 333 bus_space_write_4(esc->sc_bst, esc->dm_bsh, RAMBO_LADDR, paddr & ~0x3f); 334 335 /* Load number of blocks to DMA (1 block = 64 bytes) */ 336 bus_space_write_2(esc->sc_bst, esc->dm_bsh, RAMBO_BLKCNT, blocks); 337 338 /* If non block-aligned transfer prime FIFO manually */ 339 if (prime) { 340 /* Enable DMA to prime the FIFO buffer */ 341 bus_space_write_4(esc->sc_bst, esc->dm_bsh, 342 RAMBO_MODE, esc->dm_mode | RB_DMA_ENABLE); 343 344 if (esc->sc_flags & DMA_PULLUP) { 345 /* Read from NCR 53c94 controller*/ 346 uint16_t *p; 347 348 p = (uint16_t *)((uint32_t)*esc->sc_dmaaddr & ~0x3f); 349 bus_space_write_multi_2(esc->sc_bst, esc->dm_bsh, 350 RAMBO_FIFO, p, prime>>1); 351 } else 352 /* Write to NCR 53C94 controller */ 353 while (prime > 0) { 354 (void)bus_space_read_2(esc->sc_bst, esc->dm_bsh, 355 RAMBO_FIFO); 356 prime -= 2; 357 } 358 /* Leave DMA disabled while we setup NCR controller */ 359 bus_space_write_4(esc->sc_bst, esc->dm_bsh, RAMBO_MODE, 360 esc->dm_mode); 361 } 362 363 bus_dmamap_sync(esc->sc_dmat, esc->sc_dmamap, 0, esc->sc_dmasize, 364 datain ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); 365 366 esc->dm_curseg = 0; 367 esc->dm_mode |= RB_DMA_ENABLE; 368 if (esc->sc_dmamap->dm_nsegs > 1) 369 esc->dm_mode |= RB_INT_ENABLE; /* Requires DMA chaining */ 370 371 return 0; 372 } 373 374 static void 375 asc_dma_go(struct ncr53c9x_softc *sc) 376 { 377 struct asc_softc *esc = (struct asc_softc *)sc; 378 379 /* Start DMA */ 380 bus_space_write_4(esc->sc_bst, esc->dm_bsh, RAMBO_MODE, esc->dm_mode); 381 382 esc->sc_flags |= DMA_ACTIVE; 383 } 384 385 static int 386 asc_dma_intr(struct ncr53c9x_softc *sc) 387 { 388 struct asc_softc *esc = (struct asc_softc *)sc; 389 390 size_t resid, len; 391 int trans; 392 uint32_t status; 393 u_int tcl, tcm; 394 395 #ifdef DIAGNOSTIC 396 if ((esc->sc_flags & DMA_ACTIVE) == 0) { 397 dma_status(sc); 398 panic("DMA not active"); 399 } 400 #endif 401 402 resid = 0; 403 if ((esc->sc_flags & DMA_PULLUP) == 0 && 404 (resid = (NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF)) != 0) { 405 NCR_DMA(("asc_intr: empty FIFO of %d ", resid)); 406 DELAY(10); 407 } 408 409 resid += (tcl = NCR_READ_REG(sc, NCR_TCL)) + 410 ((tcm = NCR_READ_REG(sc, NCR_TCM)) << 8); 411 412 if (esc->sc_dmasize == 0) { /* Transfer pad operation */ 413 NCR_DMA(("asc_intr: discard %d bytes\n", resid)); 414 return 0; 415 } 416 417 trans = esc->sc_dmasize - resid; 418 if (trans < 0) { /* transferred < 0 ? */ 419 printf("%s: xfer (%d) > req (%d)\n", 420 __func__, trans, esc->sc_dmasize); 421 trans = esc->sc_dmasize; 422 } 423 424 NCR_DMA(("asc_intr: tcl=%d, tcm=%d; trans=%d, resid=%d\n", 425 tcl, tcm, trans, resid)); 426 427 status = bus_space_read_4(esc->sc_bst, esc->dm_bsh, RAMBO_MODE); 428 429 if ((status & RB_FIFO_EMPTY) == 0) { /* Data left in RAMBO FIFO */ 430 if ((esc->sc_flags & DMA_PULLUP) != 0) { /* SCSI Read */ 431 paddr_t ptr; 432 uint16_t *p; 433 434 resid = status & 0x1f; 435 436 /* take the address of block to fixed up */ 437 ptr = bus_space_read_4(esc->sc_bst, esc->dm_bsh, 438 RAMBO_CADDR); 439 /* find the starting address of fractional data */ 440 p = (uint16_t *)MIPS_PHYS_TO_KSEG0(ptr + (resid << 1)); 441 442 /* duplicate trailing data to FIFO for force flush */ 443 len = RB_BLK_CNT - resid; 444 bus_space_write_multi_2(esc->sc_bst, esc->dm_bsh, 445 RAMBO_FIFO, p, len); 446 check_fifo(esc); 447 } else { /* SCSI Write */ 448 bus_space_write_4(esc->sc_bst, esc->dm_bsh, 449 RAMBO_MODE, 0); 450 bus_space_write_4(esc->sc_bst, esc->dm_bsh, 451 RAMBO_MODE, RB_CLRFIFO); 452 } 453 } 454 455 bus_space_write_2(esc->sc_bst, esc->dm_bsh, RAMBO_BLKCNT, 0); 456 457 bus_space_write_4(esc->sc_bst, esc->dm_bsh, RAMBO_MODE, 0); 458 459 bus_dmamap_sync(esc->sc_dmat, esc->sc_dmamap, 460 0, esc->sc_dmasize, 461 (esc->sc_flags & DMA_PULLUP) != 0 ? 462 BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); 463 bus_dmamap_unload(esc->sc_dmat, esc->sc_dmamap); 464 465 *esc->sc_dmaaddr += trans; 466 *esc->sc_dmalen -= trans; 467 468 esc->sc_flags = DMA_IDLE; 469 470 return 0; 471 } 472 473 474 static void 475 asc_dma_stop(struct ncr53c9x_softc *sc) 476 { 477 struct asc_softc *esc = (struct asc_softc *)sc; 478 479 bus_space_write_4(esc->sc_bst, esc->dm_bsh, RAMBO_MODE, 0); 480 if ((esc->sc_flags & DMA_MAPLOADED) != 0) 481 bus_dmamap_unload(esc->sc_dmat, esc->sc_dmamap); 482 esc->sc_flags = DMA_IDLE; 483 } 484 485 static int 486 asc_dma_isactive(struct ncr53c9x_softc *sc) 487 { 488 struct asc_softc *esc = (struct asc_softc *)sc; 489 return (esc->sc_flags & DMA_ACTIVE) != 0 ? 1 : 0; 490 } 491 492 static void 493 rambo_dma_chain(struct asc_softc *esc) 494 { 495 int seg; 496 size_t count, blocks; 497 paddr_t paddr; 498 499 seg = ++esc->dm_curseg; 500 501 #ifdef DIAGNOSTIC 502 if ((esc->sc_flags & DMA_ACTIVE) == 0 || seg > esc->sc_dmamap->dm_nsegs) 503 panic("Unexpected DMA chaining intr"); 504 505 /* Interrupt can only occur at terminal count, but double check */ 506 if (bus_space_read_2(esc->sc_bst, esc->dm_bsh, RAMBO_BLKCNT)) { 507 dma_status((void *)esc); 508 panic("rambo blkcnt != 0"); 509 } 510 #endif 511 512 paddr = esc->sc_dmamap->dm_segs[seg].ds_addr; 513 count = esc->sc_dmamap->dm_segs[seg].ds_len; 514 blocks = (count + 63) >> 6; 515 516 /* Disable DMA interrupt if last segment */ 517 if (seg + 1 > esc->sc_dmamap->dm_nsegs) { 518 bus_space_write_4(esc->sc_bst, esc->dm_bsh, 519 RAMBO_MODE, esc->dm_mode & ~RB_INT_ENABLE); 520 } 521 522 /* Load transfer address for next DMA chain */ 523 bus_space_write_4(esc->sc_bst, esc->dm_bsh, RAMBO_LADDR, paddr); 524 525 /* DMA restarts when we enter a new block count */ 526 bus_space_write_2(esc->sc_bst, esc->dm_bsh, RAMBO_BLKCNT, blocks); 527 } 528 529 static int 530 asc_intr(void *arg) 531 { 532 uint32_t dma_stat; 533 struct asc_softc *esc = arg; 534 struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x; 535 536 esc->sc_intrcnt.ev_count++; 537 538 /* Check for RAMBO DMA Interrupt */ 539 dma_stat = bus_space_read_4(esc->sc_bst, esc->dm_bsh, RAMBO_MODE); 540 if ((dma_stat & RB_INTR_PEND) != 0) { 541 rambo_dma_chain(esc); 542 } 543 /* Check for NCR 53c94 interrupt */ 544 if (NCR_READ_REG(sc, NCR_STAT) & NCRSTAT_INT) { 545 ncr53c9x_intr(sc); 546 } 547 return 0; 548 } 549