1 /* $NetBSD: sec.c,v 1.3 2006/10/02 22:10:55 bjh21 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.3 2006/10/02 22:10:55 bjh21 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 <machine/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 boolean_t sc_dmaactive; 81 caddr_t sc_dmaaddr; 82 int sc_dmaoff; 83 size_t sc_dmalen; 84 boolean_t 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(struct device *, struct cfdata *, void *); 95 static void sec_attach(struct device *, struct device *, void *); 96 97 /* callbacks from MI WD33C93 driver */ 98 static int sec_dmasetup(struct wd33c93_softc *, caddr_t *, size_t *, int, 99 size_t *); 100 static int sec_dmago(struct wd33c93_softc *); 101 static void sec_dmastop(struct wd33c93_softc *); 102 static void sec_reset(struct wd33c93_softc *); 103 104 static int sec_intr(void *); 105 static int sec_dmatc(struct sec_softc *sc); 106 107 void sec_dumpdma(void *arg); 108 109 CFATTACH_DECL(sec, sizeof(struct sec_softc), 110 sec_match, sec_attach, NULL, NULL); 111 112 static inline void 113 sec_setpage(struct sec_softc *sc, int page) 114 { 115 116 sc->sc_mpr = (sc->sc_mpr & ~SEC_MPR_PAGE) | page; 117 bus_space_write_1(sc->sc_pod_t, sc->sc_pod_h, SEC_MPR, sc->sc_mpr); 118 } 119 120 static inline void 121 sec_cli(struct sec_softc *sc) 122 { 123 124 bus_space_write_1(sc->sc_pod_t, sc->sc_pod_h, SEC_CLRINT, 0); 125 } 126 127 static inline void 128 dmac_write(struct sec_softc *sc, int reg, uint8_t val) 129 { 130 131 bus_space_write_1(sc->sc_mod_t, sc->sc_mod_h, 132 SEC_DMAC + DMAC(reg), val); 133 } 134 135 static inline uint8_t 136 dmac_read(struct sec_softc *sc, int reg) 137 { 138 139 return bus_space_read_1(sc->sc_mod_t, sc->sc_mod_h, 140 SEC_DMAC + DMAC(reg)); 141 } 142 143 static int 144 sec_match(struct device *parent, struct cfdata *cf, void *aux) 145 { 146 struct podulebus_attach_args *pa = aux; 147 148 /* Standard ROM, skipping the MCS card that used the same ID. */ 149 if (pa->pa_product == PODULE_ACORN_SCSI && 150 strncmp(pa->pa_descr, "MCS", 3) != 0) 151 return 1; 152 153 /* PowerROM */ 154 if (pa->pa_product == PODULE_ALSYSTEMS_SCSI && 155 podulebus_initloader(pa) == 0 && 156 podloader_callloader(pa, 0, 0) == PRID_ACORN_SCSI1) 157 return 1; 158 159 return 0; 160 } 161 162 static void 163 sec_attach(struct device *parent, struct device *self, void *aux) 164 { 165 struct podulebus_attach_args *pa = aux; 166 struct sec_softc *sc = device_private(self); 167 int i; 168 169 /* Set up bus spaces */ 170 sc->sc_pod_t = pa->pa_fast_t; 171 bus_space_map(pa->pa_fast_t, pa->pa_fast_base, 0x1000, 0, 172 &sc->sc_pod_h); 173 sc->sc_mod_t = pa->pa_mod_t; 174 bus_space_map(pa->pa_mod_t, pa->pa_mod_base, 0x1000, 0, 175 &sc->sc_mod_h); 176 177 sc->sc_sbic.sc_regt = sc->sc_mod_t; 178 bus_space_subregion(sc->sc_mod_t, sc->sc_mod_h, SEC_SBIC, 179 0x1000 - SEC_SBIC, &sc->sc_sbic.sc_regh); 180 181 sc->sc_sbic.sc_id = 7; 182 sc->sc_sbic.sc_clkfreq = SEC_CLKFREQ; 183 sc->sc_sbic.sc_dmamode = SBIC_CTL_BURST_DMA; 184 185 sc->sc_sbic.sc_adapter.adapt_request = wd33c93_scsi_request; 186 sc->sc_sbic.sc_adapter.adapt_minphys = minphys; 187 188 sc->sc_sbic.sc_dmasetup = sec_dmasetup; 189 sc->sc_sbic.sc_dmago = sec_dmago; 190 sc->sc_sbic.sc_dmastop = sec_dmastop; 191 sc->sc_sbic.sc_reset = sec_reset; 192 193 sc->sc_mpr = 0; 194 bus_space_write_1(sc->sc_pod_t, sc->sc_pod_h, SEC_MPR, sc->sc_mpr); 195 196 for (i = 0; i < SEC_NPAGES; i++) { 197 sec_setpage(sc, i); 198 bus_space_set_region_2(sc->sc_mod_t, sc->sc_mod_h, 199 SEC_SRAM, 0, SEC_PAGESIZE / 2); 200 } 201 202 wd33c93_attach(&sc->sc_sbic); 203 204 evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, NULL, 205 self->dv_xname, "intr"); 206 sc->sc_ih = podulebus_irq_establish(pa->pa_ih, IPL_BIO, sec_intr, 207 sc, &sc->sc_intrcnt); 208 sec_cli(sc); 209 sc->sc_mpr |= SEC_MPR_IE; 210 bus_space_write_1(sc->sc_pod_t, sc->sc_pod_h, SEC_MPR, sc->sc_mpr); 211 } 212 213 static void 214 sec_copyin(struct sec_softc *sc, void *dest, int src, size_t size) 215 { 216 uint16_t tmp, *wptr; 217 int cnt, extra_byte; 218 219 KASSERT(src >= 0); 220 KASSERT(src + size <= SEC_MEMSIZE); 221 if (src % 2 != 0) { 222 /* 223 * There's a stray byte at the start. Read the word 224 * containing it. 225 */ 226 sec_setpage(sc, src / SEC_PAGESIZE); 227 tmp = bus_space_read_2(sc->sc_mod_t, sc->sc_mod_h, 228 SEC_SRAM + (src % SEC_PAGESIZE / 2)); 229 *(uint8_t *)dest = tmp >> 8; 230 dest = ((uint8_t *)dest) + 1; 231 src++; size--; 232 } 233 KASSERT(src % 2 == 0); 234 KASSERT(ALIGNED_POINTER(dest, uint16_t)); 235 wptr = dest; 236 extra_byte = size % 2; 237 size -= extra_byte; 238 while (size > 0) { 239 cnt = SEC_PAGESIZE - src % SEC_PAGESIZE; 240 if (cnt > size) 241 cnt = size; 242 sec_setpage(sc, src / SEC_PAGESIZE); 243 /* bus ops are in words */ 244 bus_space_read_region_2(sc->sc_mod_t, sc->sc_mod_h, 245 SEC_SRAM + src % SEC_PAGESIZE / 2, wptr, cnt / 2); 246 src += cnt; 247 wptr += cnt / 2; 248 size -= cnt; 249 } 250 if (extra_byte) { 251 sec_setpage(sc, src / SEC_PAGESIZE); 252 *(u_int8_t *)wptr = 253 bus_space_read_2(sc->sc_mod_t, sc->sc_mod_h, 254 SEC_SRAM + src % SEC_PAGESIZE / 2) & 0xff; 255 } 256 } 257 258 static void 259 sec_copyout(struct sec_softc *sc, const void *src, int dest, size_t size) 260 { 261 int cnt, extra_byte; 262 const uint16_t *wptr; 263 uint16_t tmp; 264 265 KASSERT(dest >= 0); 266 KASSERT(dest + size <= SEC_MEMSIZE); 267 if (dest % 2 != 0) { 268 /* 269 * There's a stray byte at the start. Read the word 270 * containing it. 271 */ 272 sec_setpage(sc, dest / SEC_PAGESIZE); 273 tmp = bus_space_read_2(sc->sc_mod_t, sc->sc_mod_h, 274 SEC_SRAM + (dest % SEC_PAGESIZE / 2)); 275 tmp &= 0xff; 276 tmp |= *(uint8_t const *)src << 8; 277 bus_space_write_2(sc->sc_mod_t, sc->sc_mod_h, 278 SEC_SRAM + (dest % SEC_PAGESIZE / 2), tmp); 279 src = ((uint8_t const *)src) + 1; 280 dest++; size--; 281 } 282 KASSERT(dest % 2 == 0); 283 KASSERT(ALIGNED_POINTER(src, uint16_t)); 284 wptr = src; 285 extra_byte = size % 2; 286 size -= extra_byte; 287 while (size > 0) { 288 cnt = SEC_PAGESIZE - dest % SEC_PAGESIZE; 289 if (cnt > size) 290 cnt = size; 291 sec_setpage(sc, dest / SEC_PAGESIZE); 292 /* bus ops are in words */ 293 bus_space_write_region_2(sc->sc_mod_t, sc->sc_mod_h, 294 dest % SEC_PAGESIZE / 2, wptr, cnt / 2); 295 wptr += cnt / 2; 296 dest += cnt; 297 size -= cnt; 298 } 299 if (extra_byte) { 300 /* 301 * There's a stray byte at the end. Read the word 302 * containing it. 303 */ 304 sec_setpage(sc, dest / SEC_PAGESIZE); 305 tmp = bus_space_read_2(sc->sc_mod_t, sc->sc_mod_h, 306 SEC_SRAM + (dest % SEC_PAGESIZE / 2)); 307 tmp &= 0xff00; 308 tmp |= *(uint8_t const *)wptr; 309 bus_space_write_2(sc->sc_mod_t, sc->sc_mod_h, 310 SEC_SRAM + (dest % SEC_PAGESIZE / 2), tmp); 311 } 312 } 313 314 static void 315 sec_dmablk(struct sec_softc *sc, int blk) 316 { 317 int off; 318 size_t len; 319 320 KASSERT(blk >= 0); 321 KASSERT(blk * SEC_DMABLK < sc->sc_dmalen); 322 off = (blk % SEC_NBLKS) * SEC_DMABLK + sc->sc_dmaoff; 323 len = MIN(SEC_DMABLK, sc->sc_dmalen - (blk * SEC_DMABLK)); 324 dmac_write(sc, NEC71071_ADDRLO, off & 0xff); 325 dmac_write(sc, NEC71071_ADDRMID, off >> 8); 326 dmac_write(sc, NEC71071_ADDRHI, 0); 327 /* 328 * "Note: The number of DMA transfer cycles is actually the 329 * value of the current count register + 1. Therefore, when 330 * programming the count register, specify the number of DMA 331 * transfers minus one." -- uPD71071 datasheet 332 */ 333 dmac_write(sc, NEC71071_COUNTLO, (len - 1) & 0xff); 334 dmac_write(sc, NEC71071_COUNTHI, (len - 1) >> 8); 335 } 336 337 static void 338 sec_copyoutblk(struct sec_softc *sc, int blk) 339 { 340 int off; 341 size_t len; 342 343 KASSERT(blk >= 0); 344 KASSERT(blk * SEC_DMABLK < sc->sc_dmalen); 345 KASSERT(!sc->sc_dmain); 346 off = (blk % SEC_NBLKS) * SEC_DMABLK + sc->sc_dmaoff; 347 len = MIN(SEC_DMABLK, sc->sc_dmalen - (blk * SEC_DMABLK)); 348 sec_copyout(sc, sc->sc_dmaaddr + (blk * SEC_DMABLK), off, len); 349 } 350 351 static void 352 sec_copyinblk(struct sec_softc *sc, int blk) 353 { 354 int off; 355 size_t len; 356 357 KASSERT(blk >= 0); 358 KASSERT(blk * SEC_DMABLK < sc->sc_dmalen); 359 KASSERT(sc->sc_dmain); 360 off = (blk % SEC_NBLKS) * SEC_DMABLK + sc->sc_dmaoff; 361 len = MIN(SEC_DMABLK, sc->sc_dmalen - (blk * SEC_DMABLK)); 362 sec_copyin(sc, sc->sc_dmaaddr + (blk * SEC_DMABLK), off, len); 363 } 364 365 static int 366 sec_dmasetup(struct wd33c93_softc *sc_sbic, caddr_t *addr, size_t *len, 367 int datain, size_t *dmasize) 368 { 369 struct sec_softc *sc = (struct sec_softc *)sc_sbic; 370 uint8_t mode; 371 372 sc->sc_dmaaddr = *addr; 373 sc->sc_dmaoff = ALIGNED_POINTER(*addr, uint16_t) ? 0 : 1; 374 sc->sc_dmalen = *len; 375 sc->sc_dmain = datain; 376 sc->sc_dmablk = 0; 377 mode = SEC_DMAMODE | (datain ? MODE_TDIR_IOTM : MODE_TDIR_MTIO); 378 /* Program first block into DMAC and queue up second. */ 379 dmac_write(sc, NEC71071_CHANNEL, 0); 380 if (!sc->sc_dmain) 381 sec_copyoutblk(sc, 0); 382 sec_dmablk(sc, 0); 383 /* Mode control register */ 384 dmac_write(sc, NEC71071_MODE, mode); 385 return sc->sc_dmalen; 386 } 387 388 static int 389 sec_dmago(struct wd33c93_softc *sc_sbic) 390 { 391 struct sec_softc *sc = (struct sec_softc *)sc_sbic; 392 393 dmac_write(sc, NEC71071_MASK, 0xe); 394 sc->sc_dmaactive = TRUE; 395 if (!sc->sc_dmain && sc->sc_dmalen > SEC_DMABLK) 396 sec_copyoutblk(sc, 1); 397 return sc->sc_dmalen; 398 } 399 400 static void 401 sec_dmastop(struct wd33c93_softc *sc_sbic) 402 { 403 struct sec_softc *sc = (struct sec_softc *)sc_sbic; 404 405 dmac_write(sc, NEC71071_MASK, 0xf); 406 if (sc->sc_dmaactive && sc->sc_dmain) 407 sec_copyinblk(sc, sc->sc_dmablk); 408 sc->sc_dmaactive = FALSE; 409 } 410 411 /* 412 * Reset the SCSI bus, and incidentally the SBIC and DMAC. 413 */ 414 static void 415 sec_reset(struct wd33c93_softc *sc_sbic) 416 { 417 struct sec_softc *sc = (struct sec_softc *)sc_sbic; 418 uint8_t asr, csr; 419 420 bus_space_write_1(sc->sc_pod_t, sc->sc_pod_h, SEC_MPR, 421 sc->sc_mpr | SEC_MPR_UR); 422 DELAY(7); 423 bus_space_write_1(sc->sc_pod_t, sc->sc_pod_h, SEC_MPR, sc->sc_mpr); 424 /* Wait for and clear the reset-complete interrupt */ 425 do 426 GET_SBIC_asr(sc_sbic, asr); 427 while (!(asr & SBIC_ASR_INT)); 428 GET_SBIC_csr(sc_sbic, csr); 429 dmac_write(sc, NEC71071_DCTRL1, DCTRL1_CMP | DCTRL1_RQL); 430 dmac_write(sc, NEC71071_DCTRL2, 0); 431 sec_cli(sc); 432 } 433 434 static int 435 sec_intr(void *arg) 436 { 437 struct sec_softc *sc = arg; 438 u_int8_t isr; 439 440 isr = bus_space_read_1(sc->sc_pod_t, sc->sc_pod_h, SEC_ISR); 441 if (!(isr & SEC_ISR_IRQ)) 442 return 0; 443 if (isr & SEC_ISR_DMAC) 444 sec_dmatc(sc); 445 if (isr & SEC_ISR_SBIC) 446 wd33c93_intr(&sc->sc_sbic); 447 return 1; 448 } 449 450 static int 451 sec_dmatc(struct sec_softc *sc) 452 { 453 454 sec_cli(sc); 455 /* DMAC finished block n-1 and is now working on block n */ 456 sc->sc_dmablk++; 457 if (sc->sc_dmalen > sc->sc_dmablk * SEC_DMABLK) { 458 dmac_write(sc, NEC71071_CHANNEL, 0); 459 sec_dmablk(sc, sc->sc_dmablk); 460 dmac_write(sc, NEC71071_MASK, 0xe); 461 if (!sc->sc_dmain && 462 sc->sc_dmalen > (sc->sc_dmablk + 1) * SEC_DMABLK) 463 sec_copyoutblk(sc, sc->sc_dmablk + 1); 464 } else { 465 /* All blocks fully processed. */ 466 sc->sc_dmaactive = FALSE; 467 } 468 if (sc->sc_dmain) 469 sec_copyinblk(sc, sc->sc_dmablk - 1); 470 return 1; 471 } 472 473 #ifdef DDB 474 void 475 sec_dumpdma(void *arg) 476 { 477 struct sec_softc *sc = arg; 478 479 dmac_write(sc, NEC71071_CHANNEL, 0); 480 printf("%s: DMA state: cur count %02x%02x cur addr %02x%02x%02x ", 481 sc->sc_sbic.sc_dev.dv_xname, 482 dmac_read(sc, NEC71071_COUNTHI), dmac_read(sc, NEC71071_COUNTLO), 483 dmac_read(sc, NEC71071_ADDRHI), dmac_read(sc, NEC71071_ADDRMID), 484 dmac_read(sc, NEC71071_ADDRLO)); 485 dmac_write(sc, NEC71071_CHANNEL, 0 | CHANNEL_WBASE); 486 printf("base count %02x%02x base addr %02x%02x%02x\n", 487 dmac_read(sc, NEC71071_COUNTHI), dmac_read(sc, NEC71071_COUNTLO), 488 dmac_read(sc, NEC71071_ADDRHI), dmac_read(sc, NEC71071_ADDRMID), 489 dmac_read(sc, NEC71071_ADDRLO)); 490 printf("%s: DMA state: dctrl %1x%02x mode %02x status %02x req %02x " 491 "mask %02x\n", 492 sc->sc_sbic.sc_dev.dv_xname, dmac_read(sc, NEC71071_DCTRL2), 493 dmac_read(sc, NEC71071_DCTRL1), dmac_read(sc, NEC71071_MODE), 494 dmac_read(sc, NEC71071_STATUS), dmac_read(sc, NEC71071_REQUEST), 495 dmac_read(sc, NEC71071_MASK)); 496 printf("%s: soft DMA state: %zd@%p%s%d\n", sc->sc_sbic.sc_dev.dv_xname, 497 sc->sc_dmalen, sc->sc_dmaaddr, sc->sc_dmain ? "<-" : "->", 498 sc->sc_dmaoff); 499 } 500 501 void sec_dumpall(void); /* Call from DDB */ 502 503 extern struct cfdriver sec_cd; 504 505 void sec_dumpall(void) 506 { 507 int i; 508 509 for (i = 0; i < sec_cd.cd_ndevs; ++i) 510 if (sec_cd.cd_devs[i]) 511 sec_dumpdma(sec_cd.cd_devs[i]); 512 } 513 #endif 514