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