1 /* $NetBSD: sec.c,v 1.14 2009/02/12 06:24:45 rumble Exp $ */ 2 3 /*- 4 * Copyright (c) 2000, 2001, 2006 Ben Harris 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 /* 30 * sec.c -- driver for Acorn SCSI expansion cards (AKA30, AKA31, AKA32) 31 * 32 * These cards are documented in: 33 * Acorn Archimedes 500 series / Acorn R200 series Technical Reference Manual 34 * Published by Acorn Computers Limited 35 * ISBN 1 85250 086 7 36 * Part number 0486,052 37 * Issue 1, November 1990 38 */ 39 40 #include <sys/cdefs.h> 41 __KERNEL_RCSID(0, "$NetBSD: sec.c,v 1.14 2009/02/12 06:24:45 rumble Exp $"); 42 43 #include <sys/param.h> 44 45 #include <sys/buf.h> 46 #include <sys/device.h> 47 #include <sys/malloc.h> 48 #include <sys/reboot.h> /* For bootverbose */ 49 #include <sys/syslog.h> 50 #include <sys/systm.h> 51 52 #include <dev/scsipi/scsi_all.h> 53 #include <dev/scsipi/scsipi_all.h> 54 #include <dev/scsipi/scsiconf.h> 55 56 #include <sys/bus.h> 57 58 #include <dev/ic/wd33c93reg.h> 59 #include <dev/ic/wd33c93var.h> 60 #include <dev/ic/nec71071reg.h> 61 62 #include <dev/podulebus/podulebus.h> 63 #include <dev/podulebus/podules.h> 64 #include <dev/podulebus/powerromreg.h> 65 #include <dev/podulebus/secreg.h> 66 67 #include "opt_ddb.h" 68 69 struct sec_softc { 70 struct wd33c93_softc sc_sbic; 71 bus_space_tag_t sc_pod_t; 72 bus_space_handle_t sc_pod_h; 73 bus_space_tag_t sc_mod_t; 74 bus_space_handle_t sc_mod_h; 75 void *sc_ih; 76 struct evcnt sc_intrcnt; 77 uint8_t sc_mpr; 78 79 /* Details of the current DMA transfer */ 80 bool sc_dmaactive; 81 void * sc_dmaaddr; 82 int sc_dmaoff; 83 size_t sc_dmalen; 84 bool sc_dmain; 85 /* Details of the current block within the above transfer */ 86 size_t sc_dmablk; 87 }; 88 89 #define SEC_DMABLK 16384 90 #define SEC_NBLKS 3 91 #define SEC_DMAMODE MODE_TMODE_DMD 92 93 /* autoconfiguration glue */ 94 static int sec_match(device_t, cfdata_t, void *); 95 static void sec_attach(device_t, device_t, void *); 96 97 /* shutdown hook */ 98 static void sec_shutdown(void *); 99 100 /* callbacks from MI WD33C93 driver */ 101 static int sec_dmasetup(struct wd33c93_softc *, void **, size_t *, int, 102 size_t *); 103 static int sec_dmago(struct wd33c93_softc *); 104 static void sec_dmastop(struct wd33c93_softc *); 105 static void sec_reset(struct wd33c93_softc *); 106 107 static int sec_intr(void *); 108 static int sec_dmatc(struct sec_softc *sc); 109 110 void sec_dumpdma(void *arg); 111 112 CFATTACH_DECL_NEW(sec, sizeof(struct sec_softc), 113 sec_match, sec_attach, NULL, NULL); 114 115 static inline void 116 sec_setpage(struct sec_softc *sc, int page) 117 { 118 119 sc->sc_mpr = (sc->sc_mpr & ~SEC_MPR_PAGE) | page; 120 bus_space_write_1(sc->sc_pod_t, sc->sc_pod_h, SEC_MPR, sc->sc_mpr); 121 } 122 123 static inline void 124 sec_cli(struct sec_softc *sc) 125 { 126 127 bus_space_write_1(sc->sc_pod_t, sc->sc_pod_h, SEC_CLRINT, 0); 128 } 129 130 static inline void 131 dmac_write(struct sec_softc *sc, int reg, uint8_t val) 132 { 133 134 bus_space_write_1(sc->sc_mod_t, sc->sc_mod_h, 135 SEC_DMAC + DMAC(reg), val); 136 } 137 138 static inline uint8_t 139 dmac_read(struct sec_softc *sc, int reg) 140 { 141 142 return bus_space_read_1(sc->sc_mod_t, sc->sc_mod_h, 143 SEC_DMAC + DMAC(reg)); 144 } 145 146 static int 147 sec_match(device_t parent, cfdata_t cf, void *aux) 148 { 149 struct podulebus_attach_args *pa = aux; 150 151 /* Standard ROM, skipping the MCS card that used the same ID. */ 152 if (pa->pa_product == PODULE_ACORN_SCSI && 153 strncmp(pa->pa_descr, "MCS", 3) != 0) 154 return 1; 155 156 /* PowerROM */ 157 if (pa->pa_product == PODULE_ALSYSTEMS_SCSI && 158 podulebus_initloader(pa) == 0 && 159 podloader_callloader(pa, 0, 0) == PRID_ACORN_SCSI1) 160 return 1; 161 162 return 0; 163 } 164 165 static void 166 sec_attach(device_t parent, device_t self, void *aux) 167 { 168 struct podulebus_attach_args *pa = aux; 169 struct sec_softc *sc = device_private(self); 170 int i; 171 172 sc->sc_sbic.sc_dev = self; 173 /* Set up bus spaces */ 174 sc->sc_pod_t = pa->pa_fast_t; 175 bus_space_map(pa->pa_fast_t, pa->pa_fast_base, 0x1000, 0, 176 &sc->sc_pod_h); 177 sc->sc_mod_t = pa->pa_mod_t; 178 bus_space_map(pa->pa_mod_t, pa->pa_mod_base, 0x1000, 0, 179 &sc->sc_mod_h); 180 181 sc->sc_sbic.sc_regt = sc->sc_mod_t; 182 bus_space_subregion(sc->sc_mod_t, sc->sc_mod_h, SEC_SBIC + 0, 1, 183 &sc->sc_sbic.sc_asr_regh); 184 bus_space_subregion(sc->sc_mod_t, sc->sc_mod_h, SEC_SBIC + 1, 1, 185 &sc->sc_sbic.sc_data_regh); 186 187 sc->sc_sbic.sc_id = 7; 188 sc->sc_sbic.sc_clkfreq = SEC_CLKFREQ; 189 sc->sc_sbic.sc_dmamode = SBIC_CTL_BURST_DMA; 190 191 sc->sc_sbic.sc_adapter.adapt_request = wd33c93_scsi_request; 192 sc->sc_sbic.sc_adapter.adapt_minphys = minphys; 193 194 sc->sc_sbic.sc_dmasetup = sec_dmasetup; 195 sc->sc_sbic.sc_dmago = sec_dmago; 196 sc->sc_sbic.sc_dmastop = sec_dmastop; 197 sc->sc_sbic.sc_reset = sec_reset; 198 199 sc->sc_mpr = 0; 200 bus_space_write_1(sc->sc_pod_t, sc->sc_pod_h, SEC_MPR, sc->sc_mpr); 201 202 for (i = 0; i < SEC_NPAGES; i++) { 203 sec_setpage(sc, i); 204 bus_space_set_region_2(sc->sc_mod_t, sc->sc_mod_h, 205 SEC_SRAM, 0, SEC_PAGESIZE / 2); 206 } 207 208 wd33c93_attach(&sc->sc_sbic); 209 210 evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, NULL, 211 device_xname(self), "intr"); 212 sc->sc_ih = podulebus_irq_establish(pa->pa_ih, IPL_BIO, sec_intr, 213 sc, &sc->sc_intrcnt); 214 sec_cli(sc); 215 sc->sc_mpr |= SEC_MPR_IE; 216 bus_space_write_1(sc->sc_pod_t, sc->sc_pod_h, SEC_MPR, sc->sc_mpr); 217 shutdownhook_establish(sec_shutdown, sc); 218 } 219 220 /* 221 * Before reboot, reset the page register to 0 so that RISC OS can see 222 * the podule ROM. 223 */ 224 static void 225 sec_shutdown(void *cookie) 226 { 227 struct sec_softc *sc = cookie; 228 229 sec_setpage(sc, 0); 230 } 231 232 static void 233 sec_copyin(struct sec_softc *sc, void *dest, int src, size_t size) 234 { 235 uint16_t tmp, *wptr; 236 int cnt, extra_byte; 237 238 KASSERT(src >= 0); 239 KASSERT(src + size <= SEC_MEMSIZE); 240 if (src % 2 != 0) { 241 /* 242 * There's a stray byte at the start. Read the word 243 * containing it. 244 */ 245 sec_setpage(sc, src / SEC_PAGESIZE); 246 tmp = bus_space_read_2(sc->sc_mod_t, sc->sc_mod_h, 247 SEC_SRAM + (src % SEC_PAGESIZE / 2)); 248 *(uint8_t *)dest = tmp >> 8; 249 dest = ((uint8_t *)dest) + 1; 250 src++; size--; 251 } 252 KASSERT(src % 2 == 0); 253 KASSERT(ALIGNED_POINTER(dest, uint16_t)); 254 wptr = dest; 255 extra_byte = size % 2; 256 size -= extra_byte; 257 while (size > 0) { 258 cnt = SEC_PAGESIZE - src % SEC_PAGESIZE; 259 if (cnt > size) 260 cnt = size; 261 sec_setpage(sc, src / SEC_PAGESIZE); 262 /* bus ops are in words */ 263 bus_space_read_region_2(sc->sc_mod_t, sc->sc_mod_h, 264 SEC_SRAM + src % SEC_PAGESIZE / 2, wptr, cnt / 2); 265 src += cnt; 266 wptr += cnt / 2; 267 size -= cnt; 268 } 269 if (extra_byte) { 270 sec_setpage(sc, src / SEC_PAGESIZE); 271 *(u_int8_t *)wptr = 272 bus_space_read_2(sc->sc_mod_t, sc->sc_mod_h, 273 SEC_SRAM + src % SEC_PAGESIZE / 2) & 0xff; 274 } 275 } 276 277 static void 278 sec_copyout(struct sec_softc *sc, const void *src, int dest, size_t size) 279 { 280 int cnt, extra_byte; 281 const uint16_t *wptr; 282 uint16_t tmp; 283 284 KASSERT(dest >= 0); 285 KASSERT(dest + size <= SEC_MEMSIZE); 286 if (dest % 2 != 0) { 287 /* 288 * There's a stray byte at the start. Read the word 289 * containing it. 290 */ 291 sec_setpage(sc, dest / SEC_PAGESIZE); 292 tmp = bus_space_read_2(sc->sc_mod_t, sc->sc_mod_h, 293 SEC_SRAM + (dest % SEC_PAGESIZE / 2)); 294 tmp &= 0xff; 295 tmp |= *(uint8_t const *)src << 8; 296 bus_space_write_2(sc->sc_mod_t, sc->sc_mod_h, 297 SEC_SRAM + (dest % SEC_PAGESIZE / 2), tmp); 298 src = ((uint8_t const *)src) + 1; 299 dest++; size--; 300 } 301 KASSERT(dest % 2 == 0); 302 KASSERT(ALIGNED_POINTER(src, uint16_t)); 303 wptr = src; 304 extra_byte = size % 2; 305 size -= extra_byte; 306 while (size > 0) { 307 cnt = SEC_PAGESIZE - dest % SEC_PAGESIZE; 308 if (cnt > size) 309 cnt = size; 310 sec_setpage(sc, dest / SEC_PAGESIZE); 311 /* bus ops are in words */ 312 bus_space_write_region_2(sc->sc_mod_t, sc->sc_mod_h, 313 dest % SEC_PAGESIZE / 2, wptr, cnt / 2); 314 wptr += cnt / 2; 315 dest += cnt; 316 size -= cnt; 317 } 318 if (extra_byte) { 319 /* 320 * There's a stray byte at the end. Read the word 321 * containing it. 322 */ 323 sec_setpage(sc, dest / SEC_PAGESIZE); 324 tmp = bus_space_read_2(sc->sc_mod_t, sc->sc_mod_h, 325 SEC_SRAM + (dest % SEC_PAGESIZE / 2)); 326 tmp &= 0xff00; 327 tmp |= *(uint8_t const *)wptr; 328 bus_space_write_2(sc->sc_mod_t, sc->sc_mod_h, 329 SEC_SRAM + (dest % SEC_PAGESIZE / 2), tmp); 330 } 331 } 332 333 static void 334 sec_dmablk(struct sec_softc *sc, int blk) 335 { 336 int off; 337 size_t len; 338 339 KASSERT(blk >= 0); 340 KASSERT(blk * SEC_DMABLK < sc->sc_dmalen); 341 off = (blk % SEC_NBLKS) * SEC_DMABLK + sc->sc_dmaoff; 342 len = MIN(SEC_DMABLK, sc->sc_dmalen - (blk * SEC_DMABLK)); 343 dmac_write(sc, NEC71071_ADDRLO, off & 0xff); 344 dmac_write(sc, NEC71071_ADDRMID, off >> 8); 345 dmac_write(sc, NEC71071_ADDRHI, 0); 346 /* 347 * "Note: The number of DMA transfer cycles is actually the 348 * value of the current count register + 1. Therefore, when 349 * programming the count register, specify the number of DMA 350 * transfers minus one." -- uPD71071 datasheet 351 */ 352 dmac_write(sc, NEC71071_COUNTLO, (len - 1) & 0xff); 353 dmac_write(sc, NEC71071_COUNTHI, (len - 1) >> 8); 354 } 355 356 static void 357 sec_copyoutblk(struct sec_softc *sc, int blk) 358 { 359 int off; 360 size_t len; 361 362 KASSERT(blk >= 0); 363 KASSERT(blk * SEC_DMABLK < sc->sc_dmalen); 364 KASSERT(!sc->sc_dmain); 365 off = (blk % SEC_NBLKS) * SEC_DMABLK + sc->sc_dmaoff; 366 len = MIN(SEC_DMABLK, sc->sc_dmalen - (blk * SEC_DMABLK)); 367 sec_copyout(sc, (char*)sc->sc_dmaaddr + (blk * SEC_DMABLK), off, len); 368 } 369 370 static void 371 sec_copyinblk(struct sec_softc *sc, int blk) 372 { 373 int off; 374 size_t len; 375 376 KASSERT(blk >= 0); 377 KASSERT(blk * SEC_DMABLK < sc->sc_dmalen); 378 KASSERT(sc->sc_dmain); 379 off = (blk % SEC_NBLKS) * SEC_DMABLK + sc->sc_dmaoff; 380 len = MIN(SEC_DMABLK, sc->sc_dmalen - (blk * SEC_DMABLK)); 381 sec_copyin(sc, (char*)sc->sc_dmaaddr + (blk * SEC_DMABLK), off, len); 382 } 383 384 static int 385 sec_dmasetup(struct wd33c93_softc *sc_sbic, void **addr, size_t *len, 386 int datain, size_t *dmasize) 387 { 388 struct sec_softc *sc = (struct sec_softc *)sc_sbic; 389 uint8_t mode; 390 391 sc->sc_dmaaddr = *addr; 392 sc->sc_dmaoff = ALIGNED_POINTER(*addr, uint16_t) ? 0 : 1; 393 sc->sc_dmalen = *len; 394 sc->sc_dmain = datain; 395 sc->sc_dmablk = 0; 396 mode = SEC_DMAMODE | (datain ? MODE_TDIR_IOTM : MODE_TDIR_MTIO); 397 /* Program first block into DMAC and queue up second. */ 398 dmac_write(sc, NEC71071_CHANNEL, 0); 399 if (!sc->sc_dmain) 400 sec_copyoutblk(sc, 0); 401 sec_dmablk(sc, 0); 402 /* Mode control register */ 403 dmac_write(sc, NEC71071_MODE, mode); 404 return sc->sc_dmalen; 405 } 406 407 static int 408 sec_dmago(struct wd33c93_softc *sc_sbic) 409 { 410 struct sec_softc *sc = (struct sec_softc *)sc_sbic; 411 412 dmac_write(sc, NEC71071_MASK, 0xe); 413 sc->sc_dmaactive = true; 414 if (!sc->sc_dmain && sc->sc_dmalen > SEC_DMABLK) 415 sec_copyoutblk(sc, 1); 416 return sc->sc_dmalen; 417 } 418 419 static void 420 sec_dmastop(struct wd33c93_softc *sc_sbic) 421 { 422 struct sec_softc *sc = (struct sec_softc *)sc_sbic; 423 424 dmac_write(sc, NEC71071_MASK, 0xf); 425 if (sc->sc_dmaactive && sc->sc_dmain) 426 sec_copyinblk(sc, sc->sc_dmablk); 427 sc->sc_dmaactive = false; 428 } 429 430 /* 431 * Reset the SCSI bus, and incidentally the SBIC and DMAC. 432 */ 433 static void 434 sec_reset(struct wd33c93_softc *sc_sbic) 435 { 436 struct sec_softc *sc = (struct sec_softc *)sc_sbic; 437 uint8_t asr, csr; 438 439 bus_space_write_1(sc->sc_pod_t, sc->sc_pod_h, SEC_MPR, 440 sc->sc_mpr | SEC_MPR_UR); 441 DELAY(7); 442 bus_space_write_1(sc->sc_pod_t, sc->sc_pod_h, SEC_MPR, sc->sc_mpr); 443 /* Wait for and clear the reset-complete interrupt */ 444 do 445 GET_SBIC_asr(sc_sbic, asr); 446 while (!(asr & SBIC_ASR_INT)); 447 GET_SBIC_csr(sc_sbic, csr); 448 dmac_write(sc, NEC71071_DCTRL1, DCTRL1_CMP | DCTRL1_RQL); 449 dmac_write(sc, NEC71071_DCTRL2, 0); 450 sec_cli(sc); 451 } 452 453 static int 454 sec_intr(void *arg) 455 { 456 struct sec_softc *sc = arg; 457 u_int8_t isr; 458 459 isr = bus_space_read_1(sc->sc_pod_t, sc->sc_pod_h, SEC_ISR); 460 if (!(isr & SEC_ISR_IRQ)) 461 return 0; 462 if (isr & SEC_ISR_DMAC) 463 sec_dmatc(sc); 464 if (isr & SEC_ISR_SBIC) 465 wd33c93_intr(&sc->sc_sbic); 466 return 1; 467 } 468 469 static int 470 sec_dmatc(struct sec_softc *sc) 471 { 472 473 sec_cli(sc); 474 /* DMAC finished block n-1 and is now working on block n */ 475 sc->sc_dmablk++; 476 if (sc->sc_dmalen > sc->sc_dmablk * SEC_DMABLK) { 477 dmac_write(sc, NEC71071_CHANNEL, 0); 478 sec_dmablk(sc, sc->sc_dmablk); 479 dmac_write(sc, NEC71071_MASK, 0xe); 480 if (!sc->sc_dmain && 481 sc->sc_dmalen > (sc->sc_dmablk + 1) * SEC_DMABLK) 482 sec_copyoutblk(sc, sc->sc_dmablk + 1); 483 } else { 484 /* All blocks fully processed. */ 485 sc->sc_dmaactive = false; 486 } 487 if (sc->sc_dmain) 488 sec_copyinblk(sc, sc->sc_dmablk - 1); 489 return 1; 490 } 491 492 #ifdef DDB 493 void 494 sec_dumpdma(void *arg) 495 { 496 struct sec_softc *sc = arg; 497 498 dmac_write(sc, NEC71071_CHANNEL, 0); 499 printf("%s: DMA state: cur count %02x%02x cur addr %02x%02x%02x ", 500 device_xname(sc->sc_sbic.sc_dev), 501 dmac_read(sc, NEC71071_COUNTHI), dmac_read(sc, NEC71071_COUNTLO), 502 dmac_read(sc, NEC71071_ADDRHI), dmac_read(sc, NEC71071_ADDRMID), 503 dmac_read(sc, NEC71071_ADDRLO)); 504 dmac_write(sc, NEC71071_CHANNEL, 0 | CHANNEL_WBASE); 505 printf("base count %02x%02x base addr %02x%02x%02x\n", 506 dmac_read(sc, NEC71071_COUNTHI), dmac_read(sc, NEC71071_COUNTLO), 507 dmac_read(sc, NEC71071_ADDRHI), dmac_read(sc, NEC71071_ADDRMID), 508 dmac_read(sc, NEC71071_ADDRLO)); 509 printf("%s: DMA state: dctrl %1x%02x mode %02x status %02x req %02x " 510 "mask %02x\n", 511 device_xname(sc->sc_sbic.sc_dev), dmac_read(sc, NEC71071_DCTRL2), 512 dmac_read(sc, NEC71071_DCTRL1), dmac_read(sc, NEC71071_MODE), 513 dmac_read(sc, NEC71071_STATUS), dmac_read(sc, NEC71071_REQUEST), 514 dmac_read(sc, NEC71071_MASK)); 515 printf("%s: soft DMA state: %zd@%p%s%d\n", 516 device_xname(sc->sc_sbic.sc_dev), 517 sc->sc_dmalen, sc->sc_dmaaddr, sc->sc_dmain ? "<-" : "->", 518 sc->sc_dmaoff); 519 } 520 521 void sec_dumpall(void); /* Call from DDB */ 522 523 extern struct cfdriver sec_cd; 524 525 void sec_dumpall(void) 526 { 527 int i; 528 struct sec_softc *sc; 529 530 for (i = 0; i < sec_cd.cd_ndevs; ++i) { 531 sc = device_lookup_private(&sec_cd, i); 532 if (sc != NULL) 533 sec_dumpdma(sc); 534 } 535 } 536 #endif 537