Annotation of sys/dev/ic/oosiop.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: oosiop.c,v 1.5 2006/11/28 23:59:45 dlg Exp $ */
! 2: /* $NetBSD: oosiop.c,v 1.4 2003/10/29 17:45:55 tsutsui Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 2001 Shuichiro URATA. 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: /*
! 31: * NCR53C700 SCSI I/O processor (OOSIOP) driver
! 32: *
! 33: * TODO:
! 34: * - Better error handling.
! 35: * - Implement tagged queuing.
! 36: */
! 37:
! 38: #include <sys/param.h>
! 39: #include <sys/systm.h>
! 40: #include <sys/timeout.h>
! 41: #include <sys/kernel.h>
! 42: #include <sys/device.h>
! 43: #include <sys/buf.h>
! 44: #include <sys/malloc.h>
! 45: #include <sys/queue.h>
! 46:
! 47: #include <uvm/uvm_extern.h>
! 48:
! 49: #include <scsi/scsi_all.h>
! 50: #include <scsi/scsiconf.h>
! 51: #include <scsi/scsi_message.h>
! 52:
! 53: #include <machine/cpu.h>
! 54: #include <machine/bus.h>
! 55:
! 56: #include <dev/ic/oosiopreg.h>
! 57: #include <dev/ic/oosiopvar.h>
! 58:
! 59: /* 53C700 script */
! 60: #include <dev/microcode/siop/oosiop.out>
! 61:
! 62: int oosiop_alloc_cb(struct oosiop_softc *, int);
! 63:
! 64: static __inline void oosiop_relocate_io(struct oosiop_softc *, bus_addr_t);
! 65: static __inline void oosiop_relocate_tc(struct oosiop_softc *, bus_addr_t);
! 66: static __inline void oosiop_fixup_select(struct oosiop_softc *, bus_addr_t,
! 67: int);
! 68: static __inline void oosiop_fixup_jump(struct oosiop_softc *, bus_addr_t,
! 69: bus_addr_t);
! 70: static __inline void oosiop_fixup_move(struct oosiop_softc *, bus_addr_t,
! 71: bus_size_t, bus_addr_t);
! 72:
! 73: void oosiop_load_script(struct oosiop_softc *);
! 74: void oosiop_setup_sgdma(struct oosiop_softc *, struct oosiop_cb *);
! 75: void oosiop_setup_dma(struct oosiop_softc *);
! 76: void oosiop_flush_fifo(struct oosiop_softc *);
! 77: void oosiop_clear_fifo(struct oosiop_softc *);
! 78: void oosiop_phasemismatch(struct oosiop_softc *);
! 79: void oosiop_setup_syncxfer(struct oosiop_softc *);
! 80: void oosiop_set_syncparam(struct oosiop_softc *, int, int, int);
! 81: void oosiop_minphys(struct buf *);
! 82: int oosiop_scsicmd(struct scsi_xfer *);
! 83: void oosiop_done(struct oosiop_softc *, struct oosiop_cb *);
! 84: void oosiop_timeout(void *);
! 85: void oosiop_reset(struct oosiop_softc *);
! 86: void oosiop_reset_bus(struct oosiop_softc *);
! 87: void oosiop_scriptintr(struct oosiop_softc *);
! 88: void oosiop_msgin(struct oosiop_softc *, struct oosiop_cb *);
! 89: void oosiop_setup(struct oosiop_softc *, struct oosiop_cb *);
! 90: void oosiop_poll(struct oosiop_softc *, struct oosiop_cb *);
! 91: void oosiop_processintr(struct oosiop_softc *, u_int8_t);
! 92:
! 93: /* Trap interrupt code for unexpected data I/O */
! 94: #define DATAIN_TRAP 0xdead0001
! 95: #define DATAOUT_TRAP 0xdead0002
! 96:
! 97: /* Possible TP and SCF conbination */
! 98: static const struct {
! 99: u_int8_t tp;
! 100: u_int8_t scf;
! 101: } synctbl[] = {
! 102: {0, 1}, /* SCLK / 4.0 */
! 103: {1, 1}, /* SCLK / 5.0 */
! 104: {2, 1}, /* SCLK / 6.0 */
! 105: {3, 1}, /* SCLK / 7.0 */
! 106: {1, 2}, /* SCLK / 7.5 */
! 107: {4, 1}, /* SCLK / 8.0 */
! 108: {5, 1}, /* SCLK / 9.0 */
! 109: {6, 1}, /* SCLK / 10.0 */
! 110: {3, 2}, /* SCLK / 10.5 */
! 111: {7, 1}, /* SCLK / 11.0 */
! 112: {4, 2}, /* SCLK / 12.0 */
! 113: {5, 2}, /* SCLK / 13.5 */
! 114: {3, 3}, /* SCLK / 14.0 */
! 115: {6, 2}, /* SCLK / 15.0 */
! 116: {4, 3}, /* SCLK / 16.0 */
! 117: {7, 2}, /* SCLK / 16.5 */
! 118: {5, 3}, /* SCLK / 18.0 */
! 119: {6, 3}, /* SCLK / 20.0 */
! 120: {7, 3} /* SCLK / 22.0 */
! 121: };
! 122: #define NSYNCTBL (sizeof(synctbl) / sizeof(synctbl[0]))
! 123:
! 124: #define oosiop_period(sc, tp, scf) \
! 125: (((1000000000 / (sc)->sc_freq) * (tp) * (scf)) / 40)
! 126:
! 127: struct cfdriver oosiop_cd = {
! 128: NULL, "oosiop", DV_DULL
! 129: };
! 130:
! 131: struct scsi_adapter oosiop_adapter = {
! 132: oosiop_scsicmd,
! 133: oosiop_minphys,
! 134: NULL,
! 135: NULL
! 136: };
! 137:
! 138: struct scsi_device oosiop_dev = {
! 139: NULL,
! 140: NULL,
! 141: NULL,
! 142: NULL
! 143: };
! 144:
! 145: void
! 146: oosiop_attach(struct oosiop_softc *sc)
! 147: {
! 148: struct scsibus_attach_args saa;
! 149: bus_size_t scrsize;
! 150: bus_dma_segment_t seg;
! 151: struct oosiop_cb *cb;
! 152: int err, i, nseg;
! 153:
! 154: /*
! 155: * Allocate DMA-safe memory for the script and map it.
! 156: */
! 157: scrsize = round_page(sizeof(oosiop_script));
! 158: err = bus_dmamem_alloc(sc->sc_dmat, scrsize, PAGE_SIZE, 0, &seg, 1,
! 159: &nseg, BUS_DMA_NOWAIT);
! 160: if (err) {
! 161: printf(": failed to allocate script memory, err=%d\n", err);
! 162: return;
! 163: }
! 164: err = bus_dmamem_map(sc->sc_dmat, &seg, nseg, scrsize,
! 165: (caddr_t *)&sc->sc_scr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
! 166: if (err) {
! 167: printf(": failed to map script memory, err=%d\n", err);
! 168: return;
! 169: }
! 170: err = bus_dmamap_create(sc->sc_dmat, scrsize, 1, scrsize, 0,
! 171: BUS_DMA_NOWAIT, &sc->sc_scrdma);
! 172: if (err) {
! 173: printf(": failed to create script map, err=%d\n", err);
! 174: return;
! 175: }
! 176: err = bus_dmamap_load_raw(sc->sc_dmat, sc->sc_scrdma,
! 177: &seg, nseg, scrsize, BUS_DMA_NOWAIT | BUS_DMA_WRITE);
! 178: if (err) {
! 179: printf(": failed to load script map, err=%d\n", err);
! 180: return;
! 181: }
! 182: bzero(sc->sc_scr, scrsize);
! 183: sc->sc_scrbase = sc->sc_scrdma->dm_segs[0].ds_addr;
! 184:
! 185: /* Initialize command block array */
! 186: TAILQ_INIT(&sc->sc_free_cb);
! 187: TAILQ_INIT(&sc->sc_cbq);
! 188: if (oosiop_alloc_cb(sc, OOSIOP_NCB) != 0)
! 189: return;
! 190:
! 191: /* Use first cb to reselection msgin buffer */
! 192: cb = TAILQ_FIRST(&sc->sc_free_cb);
! 193: sc->sc_reselbuf = cb->xferdma->dm_segs[0].ds_addr +
! 194: offsetof(struct oosiop_xfer, msgin[0]);
! 195:
! 196: for (i = 0; i < OOSIOP_NTGT; i++) {
! 197: sc->sc_tgt[i].nexus = NULL;
! 198: sc->sc_tgt[i].flags = 0;
! 199: }
! 200:
! 201: /* Setup asynchronous clock divisor parameters */
! 202: if (sc->sc_freq <= 25000000) {
! 203: sc->sc_ccf = 10;
! 204: sc->sc_dcntl = OOSIOP_DCNTL_CF_1;
! 205: } else if (sc->sc_freq <= 37500000) {
! 206: sc->sc_ccf = 15;
! 207: sc->sc_dcntl = OOSIOP_DCNTL_CF_1_5;
! 208: } else if (sc->sc_freq <= 50000000) {
! 209: sc->sc_ccf = 20;
! 210: sc->sc_dcntl = OOSIOP_DCNTL_CF_2;
! 211: } else {
! 212: sc->sc_ccf = 30;
! 213: sc->sc_dcntl = OOSIOP_DCNTL_CF_3;
! 214: }
! 215:
! 216: if (sc->sc_chip == OOSIOP_700)
! 217: sc->sc_minperiod = oosiop_period(sc, 4, sc->sc_ccf);
! 218: else
! 219: sc->sc_minperiod = oosiop_period(sc, 4, 10);
! 220:
! 221: if (sc->sc_minperiod < 25)
! 222: sc->sc_minperiod = 25; /* limit to 10MB/s */
! 223:
! 224: printf(": NCR53C700%s rev %d, %dMHz, SCSI ID %d\n",
! 225: sc->sc_chip == OOSIOP_700_66 ? "-66" : "",
! 226: oosiop_read_1(sc, OOSIOP_CTEST7) >> 4,
! 227: sc->sc_freq / 1000000, sc->sc_id);
! 228: /*
! 229: * Reset all
! 230: */
! 231: oosiop_reset(sc);
! 232: oosiop_reset_bus(sc);
! 233:
! 234: /*
! 235: * Start SCRIPTS processor
! 236: */
! 237: oosiop_load_script(sc);
! 238: sc->sc_active = 0;
! 239: oosiop_write_4(sc, OOSIOP_DSP, sc->sc_scrbase + Ent_wait_reselect);
! 240:
! 241: /*
! 242: * Fill in the sc_link.
! 243: */
! 244: sc->sc_link.adapter = &oosiop_adapter;
! 245: sc->sc_link.adapter_softc = sc;
! 246: sc->sc_link.device = &oosiop_dev;
! 247: sc->sc_link.openings = 1; /* XXX */
! 248: sc->sc_link.adapter_buswidth = OOSIOP_NTGT;
! 249: sc->sc_link.adapter_target = sc->sc_id;
! 250: sc->sc_link.quirks = ADEV_NODOORLOCK;
! 251:
! 252: bzero(&saa, sizeof(saa));
! 253: saa.saa_sc_link = &sc->sc_link;
! 254:
! 255: /*
! 256: * Now try to attach all the sub devices.
! 257: */
! 258: config_found(&sc->sc_dev, &saa, scsiprint);
! 259: }
! 260:
! 261: int
! 262: oosiop_alloc_cb(struct oosiop_softc *sc, int ncb)
! 263: {
! 264: struct oosiop_cb *cb;
! 265: struct oosiop_xfer *xfer;
! 266: bus_size_t xfersize;
! 267: bus_dma_segment_t seg;
! 268: int i, s, err, nseg;
! 269:
! 270: /*
! 271: * Allocate oosiop_cb.
! 272: */
! 273: cb = malloc(sizeof(struct oosiop_cb) * ncb, M_DEVBUF, M_NOWAIT);
! 274: if (cb == NULL) {
! 275: printf(": failed to allocate cb memory\n");
! 276: return (ENOMEM);
! 277: }
! 278: bzero(cb, sizeof(struct oosiop_cb) * ncb);
! 279:
! 280: /*
! 281: * Allocate DMA-safe memory for the oosiop_xfer and map it.
! 282: */
! 283: xfersize = sizeof(struct oosiop_xfer) * ncb;
! 284: err = bus_dmamem_alloc(sc->sc_dmat, xfersize, PAGE_SIZE, 0, &seg, 1,
! 285: &nseg, BUS_DMA_NOWAIT);
! 286: if (err) {
! 287: printf(": failed to allocate xfer block memory, err=%d\n", err);
! 288: return (err);
! 289: }
! 290: err = bus_dmamem_map(sc->sc_dmat, &seg, nseg, xfersize,
! 291: (caddr_t *)(void *)&xfer, BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
! 292: if (err) {
! 293: printf(": failed to map xfer block memory, err=%d\n", err);
! 294: return (err);
! 295: }
! 296:
! 297: /* Initialize each command block */
! 298: for (i = 0; i < ncb; i++) {
! 299: err = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, PAGE_SIZE,
! 300: 0, BUS_DMA_NOWAIT, &cb->cmddma);
! 301: if (err) {
! 302: printf(": failed to create cmddma map, err=%d\n", err);
! 303: return (err);
! 304: }
! 305:
! 306: err = bus_dmamap_create(sc->sc_dmat, OOSIOP_MAX_XFER,
! 307: OOSIOP_NSG, OOSIOP_DBC_MAX, 0, BUS_DMA_NOWAIT,
! 308: &cb->datadma);
! 309: if (err) {
! 310: printf(": failed to create datadma map, err=%d\n", err);
! 311: return (err);
! 312: }
! 313:
! 314: err = bus_dmamap_create(sc->sc_dmat,
! 315: sizeof(struct oosiop_xfer), 1, sizeof(struct oosiop_xfer),
! 316: 0, BUS_DMA_NOWAIT, &cb->xferdma);
! 317: if (err) {
! 318: printf(": failed to create xfer block map, err=%d\n",
! 319: err);
! 320: return (err);
! 321: }
! 322: err = bus_dmamap_load(sc->sc_dmat, cb->xferdma, xfer,
! 323: sizeof(struct oosiop_xfer), NULL, BUS_DMA_NOWAIT);
! 324: if (err) {
! 325: printf(": failed to load xfer block, err=%d\n", err);
! 326: return (err);
! 327: }
! 328:
! 329: cb->xfer = xfer;
! 330:
! 331: s = splbio();
! 332: TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain);
! 333: splx(s);
! 334:
! 335: cb++;
! 336: xfer++;
! 337: }
! 338:
! 339: return (0);
! 340: }
! 341:
! 342: static __inline void
! 343: oosiop_relocate_io(struct oosiop_softc *sc, bus_addr_t addr)
! 344: {
! 345: u_int32_t dcmd;
! 346: int32_t dsps;
! 347:
! 348: dcmd = letoh32(sc->sc_scr[addr / 4 + 0]);
! 349: dsps = letoh32(sc->sc_scr[addr / 4 + 1]);
! 350:
! 351: /* convert relative to absolute */
! 352: if (dcmd & 0x04000000) {
! 353: dcmd &= ~0x04000000;
! 354: #if 0
! 355: /*
! 356: * sign extension isn't needed here because
! 357: * ncr53cxxx.c generates 32 bit dsps.
! 358: */
! 359: dsps <<= 8;
! 360: dsps >>= 8;
! 361: #endif
! 362: sc->sc_scr[addr / 4 + 0] = htole32(dcmd);
! 363: dsps += addr + 8;
! 364: }
! 365:
! 366: sc->sc_scr[addr / 4 + 1] = htole32(dsps + sc->sc_scrbase);
! 367: }
! 368:
! 369: static __inline void
! 370: oosiop_relocate_tc(struct oosiop_softc *sc, bus_addr_t addr)
! 371: {
! 372: u_int32_t dcmd;
! 373: int32_t dsps;
! 374:
! 375: dcmd = letoh32(sc->sc_scr[addr / 4 + 0]);
! 376: dsps = letoh32(sc->sc_scr[addr / 4 + 1]);
! 377:
! 378: /* convert relative to absolute */
! 379: if (dcmd & 0x00800000) {
! 380: dcmd &= ~0x00800000;
! 381: sc->sc_scr[addr / 4] = htole32(dcmd);
! 382: #if 0
! 383: /*
! 384: * sign extension isn't needed here because
! 385: * ncr53cxxx.c generates 32 bit dsps.
! 386: */
! 387: dsps <<= 8;
! 388: dsps >>= 8;
! 389: #endif
! 390: dsps += addr + 8;
! 391: }
! 392:
! 393: sc->sc_scr[addr / 4 + 1] = htole32(dsps + sc->sc_scrbase);
! 394: }
! 395:
! 396: static __inline void
! 397: oosiop_fixup_select(struct oosiop_softc *sc, bus_addr_t addr, int id)
! 398: {
! 399: u_int32_t dcmd;
! 400:
! 401: dcmd = letoh32(sc->sc_scr[addr / 4]);
! 402: dcmd &= 0xff00ffff;
! 403: dcmd |= 0x00010000 << id;
! 404: sc->sc_scr[addr / 4] = htole32(dcmd);
! 405: }
! 406:
! 407: static __inline void
! 408: oosiop_fixup_jump(struct oosiop_softc *sc, bus_addr_t addr, bus_addr_t dst)
! 409: {
! 410:
! 411: sc->sc_scr[addr / 4 + 1] = htole32(dst);
! 412: }
! 413:
! 414: static __inline void
! 415: oosiop_fixup_move(struct oosiop_softc *sc, bus_addr_t addr, bus_size_t dbc,
! 416: bus_addr_t dsps)
! 417: {
! 418: u_int32_t dcmd;
! 419:
! 420: dcmd = letoh32(sc->sc_scr[addr / 4]);
! 421: dcmd &= 0xff000000;
! 422: dcmd |= dbc & 0x00ffffff;
! 423: sc->sc_scr[addr / 4 + 0] = htole32(dcmd);
! 424: sc->sc_scr[addr / 4 + 1] = htole32(dsps);
! 425: }
! 426:
! 427: void
! 428: oosiop_load_script(struct oosiop_softc *sc)
! 429: {
! 430: int i;
! 431:
! 432: /* load script */
! 433: for (i = 0; i < sizeof(oosiop_script) / sizeof(oosiop_script[0]); i++)
! 434: sc->sc_scr[i] = htole32(oosiop_script[i]);
! 435:
! 436: /* relocate script */
! 437: for (i = 0; i < (sizeof(oosiop_script) / 8); i++) {
! 438: switch (oosiop_script[i * 2] >> 27) {
! 439: case 0x08: /* select */
! 440: case 0x0a: /* wait reselect */
! 441: oosiop_relocate_io(sc, i * 8);
! 442: break;
! 443: case 0x10: /* jump */
! 444: case 0x11: /* call */
! 445: oosiop_relocate_tc(sc, i * 8);
! 446: break;
! 447: }
! 448: }
! 449:
! 450: oosiop_fixup_move(sc, Ent_p_resel_msgin_move, 1, sc->sc_reselbuf);
! 451: OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE);
! 452: }
! 453:
! 454: void
! 455: oosiop_setup_sgdma(struct oosiop_softc *sc, struct oosiop_cb *cb)
! 456: {
! 457: struct oosiop_xfer *xfer = cb->xfer;
! 458: struct scsi_xfer *xs = cb->xs;
! 459: int i, n, off;
! 460:
! 461: OOSIOP_XFERSCR_SYNC(sc, cb,
! 462: BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
! 463:
! 464: off = cb->curdp;
! 465:
! 466: if (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
! 467: /* Find start segment */
! 468: for (i = 0; i < cb->datadma->dm_nsegs; i++) {
! 469: if (off < cb->datadma->dm_segs[i].ds_len)
! 470: break;
! 471: off -= cb->datadma->dm_segs[i].ds_len;
! 472: }
! 473:
! 474: /* build MOVE block */
! 475: if (xs->flags & SCSI_DATA_IN) {
! 476: n = 0;
! 477: while (i < cb->datadma->dm_nsegs) {
! 478: xfer->datain_scr[n * 2 + 0] =
! 479: htole32(0x09000000 |
! 480: (cb->datadma->dm_segs[i].ds_len - off));
! 481: xfer->datain_scr[n * 2 + 1] =
! 482: htole32(cb->datadma->dm_segs[i].ds_addr +
! 483: off);
! 484: n++;
! 485: i++;
! 486: off = 0;
! 487: }
! 488: xfer->datain_scr[n * 2 + 0] = htole32(0x80080000);
! 489: xfer->datain_scr[n * 2 + 1] =
! 490: htole32(sc->sc_scrbase + Ent_phasedispatch);
! 491: }
! 492: if (xs->flags & SCSI_DATA_OUT) {
! 493: n = 0;
! 494: while (i < cb->datadma->dm_nsegs) {
! 495: xfer->dataout_scr[n * 2 + 0] =
! 496: htole32(0x08000000 |
! 497: (cb->datadma->dm_segs[i].ds_len - off));
! 498: xfer->dataout_scr[n * 2 + 1] =
! 499: htole32(cb->datadma->dm_segs[i].ds_addr +
! 500: off);
! 501: n++;
! 502: i++;
! 503: off = 0;
! 504: }
! 505: xfer->dataout_scr[n * 2 + 0] = htole32(0x80080000);
! 506: xfer->dataout_scr[n * 2 + 1] =
! 507: htole32(sc->sc_scrbase + Ent_phasedispatch);
! 508: }
! 509: }
! 510: if ((xs->flags & SCSI_DATA_IN) == 0) {
! 511: xfer->datain_scr[0] = htole32(0x98080000);
! 512: xfer->datain_scr[1] = htole32(DATAIN_TRAP);
! 513: }
! 514: if ((xs->flags & SCSI_DATA_OUT) == 0) {
! 515: xfer->dataout_scr[0] = htole32(0x98080000);
! 516: xfer->dataout_scr[1] = htole32(DATAOUT_TRAP);
! 517: }
! 518: OOSIOP_XFERSCR_SYNC(sc, cb,
! 519: BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
! 520: }
! 521:
! 522: /*
! 523: * Setup DMA pointer into script.
! 524: */
! 525: void
! 526: oosiop_setup_dma(struct oosiop_softc *sc)
! 527: {
! 528: struct oosiop_cb *cb;
! 529: bus_addr_t xferbase;
! 530:
! 531: cb = sc->sc_curcb;
! 532: xferbase = cb->xferdma->dm_segs[0].ds_addr;
! 533:
! 534: OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE);
! 535:
! 536: oosiop_fixup_select(sc, Ent_p_select, cb->id);
! 537: oosiop_fixup_jump(sc, Ent_p_datain_jump, xferbase +
! 538: offsetof(struct oosiop_xfer, datain_scr[0]));
! 539: oosiop_fixup_jump(sc, Ent_p_dataout_jump, xferbase +
! 540: offsetof(struct oosiop_xfer, dataout_scr[0]));
! 541: oosiop_fixup_move(sc, Ent_p_msgin_move, 1, xferbase +
! 542: offsetof(struct oosiop_xfer, msgin[0]));
! 543: oosiop_fixup_move(sc, Ent_p_extmsglen_move, 1, xferbase +
! 544: offsetof(struct oosiop_xfer, msgin[1]));
! 545: oosiop_fixup_move(sc, Ent_p_msgout_move, cb->msgoutlen, xferbase +
! 546: offsetof(struct oosiop_xfer, msgout[0]));
! 547: oosiop_fixup_move(sc, Ent_p_status_move, 1, xferbase +
! 548: offsetof(struct oosiop_xfer, status));
! 549: oosiop_fixup_move(sc, Ent_p_cmdout_move, cb->cmdlen,
! 550: cb->cmddma->dm_segs[0].ds_addr);
! 551:
! 552: OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE);
! 553: }
! 554:
! 555: void
! 556: oosiop_flush_fifo(struct oosiop_softc *sc)
! 557: {
! 558:
! 559: oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) |
! 560: OOSIOP_DFIFO_FLF);
! 561: while ((oosiop_read_1(sc, OOSIOP_CTEST1) & OOSIOP_CTEST1_FMT) !=
! 562: OOSIOP_CTEST1_FMT)
! 563: ;
! 564: oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) &
! 565: ~OOSIOP_DFIFO_FLF);
! 566: }
! 567:
! 568: void
! 569: oosiop_clear_fifo(struct oosiop_softc *sc)
! 570: {
! 571:
! 572: oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) |
! 573: OOSIOP_DFIFO_CLF);
! 574: while ((oosiop_read_1(sc, OOSIOP_CTEST1) & OOSIOP_CTEST1_FMT) !=
! 575: OOSIOP_CTEST1_FMT)
! 576: ;
! 577: oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) &
! 578: ~OOSIOP_DFIFO_CLF);
! 579: }
! 580:
! 581: void
! 582: oosiop_phasemismatch(struct oosiop_softc *sc)
! 583: {
! 584: struct oosiop_cb *cb;
! 585: u_int32_t dsp, dbc, n, i, len;
! 586: u_int8_t dfifo, sstat1;
! 587:
! 588: cb = sc->sc_curcb;
! 589: if (cb == NULL)
! 590: return;
! 591:
! 592: dsp = oosiop_read_4(sc, OOSIOP_DSP);
! 593: dbc = oosiop_read_4(sc, OOSIOP_DBC) & OOSIOP_DBC_MAX;
! 594: len = 0;
! 595:
! 596: n = dsp - cb->xferdma->dm_segs[0].ds_addr - 8;
! 597: if (n >= offsetof(struct oosiop_xfer, datain_scr[0]) &&
! 598: n < offsetof(struct oosiop_xfer, datain_scr[OOSIOP_NSG * 2])) {
! 599: n -= offsetof(struct oosiop_xfer, datain_scr[0]);
! 600: n >>= 3;
! 601: OOSIOP_DINSCR_SYNC(sc, cb,
! 602: BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
! 603: for (i = 0; i <= n; i++)
! 604: len += letoh32(cb->xfer->datain_scr[i * 2]) &
! 605: 0x00ffffff;
! 606: OOSIOP_DINSCR_SYNC(sc, cb,
! 607: BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
! 608: /* All data in the chip are already flushed */
! 609: } else if (n >= offsetof(struct oosiop_xfer, dataout_scr[0]) &&
! 610: n < offsetof(struct oosiop_xfer, dataout_scr[OOSIOP_NSG * 2])) {
! 611: n -= offsetof(struct oosiop_xfer, dataout_scr[0]);
! 612: n >>= 3;
! 613: OOSIOP_DOUTSCR_SYNC(sc, cb,
! 614: BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
! 615: for (i = 0; i <= n; i++)
! 616: len += letoh32(cb->xfer->dataout_scr[i * 2]) &
! 617: 0x00ffffff;
! 618: OOSIOP_DOUTSCR_SYNC(sc, cb,
! 619: BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
! 620:
! 621: dfifo = oosiop_read_1(sc, OOSIOP_DFIFO);
! 622: dbc += ((dfifo & OOSIOP_DFIFO_BO) - (dbc & OOSIOP_DFIFO_BO)) &
! 623: OOSIOP_DFIFO_BO;
! 624:
! 625: sstat1 = oosiop_read_1(sc, OOSIOP_SSTAT1);
! 626: if (sstat1 & OOSIOP_SSTAT1_OLF)
! 627: dbc++;
! 628: if ((sc->sc_tgt[cb->id].sxfer != 0) &&
! 629: (sstat1 & OOSIOP_SSTAT1_ORF) != 0)
! 630: dbc++;
! 631:
! 632: oosiop_clear_fifo(sc);
! 633: } else {
! 634: printf("%s: phase mismatch addr=%08x\n", sc->sc_dev.dv_xname,
! 635: oosiop_read_4(sc, OOSIOP_DSP) - 8);
! 636: oosiop_clear_fifo(sc);
! 637: return;
! 638: }
! 639:
! 640: len -= dbc;
! 641: if (len) {
! 642: cb->curdp += len;
! 643: oosiop_setup_sgdma(sc, cb);
! 644: }
! 645: }
! 646:
! 647: void
! 648: oosiop_setup_syncxfer(struct oosiop_softc *sc)
! 649: {
! 650: int id;
! 651:
! 652: id = sc->sc_curcb->id;
! 653: if (sc->sc_chip != OOSIOP_700)
! 654: oosiop_write_1(sc, OOSIOP_SBCL, sc->sc_tgt[id].scf);
! 655:
! 656: oosiop_write_1(sc, OOSIOP_SXFER, sc->sc_tgt[id].sxfer);
! 657: }
! 658:
! 659: void
! 660: oosiop_set_syncparam(struct oosiop_softc *sc, int id, int period, int offset)
! 661: {
! 662: int i, p;
! 663:
! 664: printf("%s: target %d now using 8 bit ", sc->sc_dev.dv_xname, id);
! 665:
! 666: if (offset == 0) {
! 667: /* Asynchronous */
! 668: sc->sc_tgt[id].scf = 0;
! 669: sc->sc_tgt[id].sxfer = 0;
! 670: printf("asynchronous");
! 671: } else {
! 672: /* Synchronous */
! 673: if (sc->sc_chip == OOSIOP_700) {
! 674: for (i = 4; i < 12; i++) {
! 675: p = oosiop_period(sc, i, sc->sc_ccf);
! 676: if (p >= period)
! 677: break;
! 678: }
! 679: if (i == 12) {
! 680: printf("%s: target %d period too large\n",
! 681: sc->sc_dev.dv_xname, id);
! 682: i = 11; /* XXX */
! 683: }
! 684: sc->sc_tgt[id].scf = 0;
! 685: sc->sc_tgt[id].sxfer = ((i - 4) << 4) | offset;
! 686: } else {
! 687: for (i = 0; i < NSYNCTBL; i++) {
! 688: p = oosiop_period(sc, synctbl[i].tp + 4,
! 689: (synctbl[i].scf + 1) * 5);
! 690: if (p >= period)
! 691: break;
! 692: }
! 693: if (i == NSYNCTBL) {
! 694: printf("%s: target %d period too large\n",
! 695: sc->sc_dev.dv_xname, id);
! 696: i = NSYNCTBL - 1; /* XXX */
! 697: }
! 698: sc->sc_tgt[id].scf = synctbl[i].scf;
! 699: sc->sc_tgt[id].sxfer = (synctbl[i].tp << 4) | offset;
! 700: }
! 701: /* XXX print actual ns period... */
! 702: printf(" synchronous");
! 703: }
! 704: printf(" xfers\n");
! 705: }
! 706:
! 707: void
! 708: oosiop_minphys(struct buf *bp)
! 709: {
! 710:
! 711: if (bp->b_bcount > OOSIOP_MAX_XFER)
! 712: bp->b_bcount = OOSIOP_MAX_XFER;
! 713: minphys(bp);
! 714: }
! 715:
! 716: int
! 717: oosiop_scsicmd(struct scsi_xfer *xs)
! 718: {
! 719: struct oosiop_softc *sc;
! 720: struct oosiop_cb *cb;
! 721: struct oosiop_xfer *xfer;
! 722: int s, err;
! 723:
! 724: sc = (struct oosiop_softc *)xs->sc_link->adapter_softc;
! 725:
! 726: s = splbio();
! 727: cb = TAILQ_FIRST(&sc->sc_free_cb);
! 728: TAILQ_REMOVE(&sc->sc_free_cb, cb, chain);
! 729: splx(s);
! 730:
! 731: cb->xs = xs;
! 732: cb->xsflags = xs->flags;
! 733: cb->cmdlen = xs->cmdlen;
! 734: cb->datalen = 0;
! 735: cb->flags = 0;
! 736: cb->id = xs->sc_link->target;
! 737: cb->lun = xs->sc_link->lun;
! 738: xfer = cb->xfer;
! 739:
! 740: /* Setup SCSI command buffer DMA */
! 741: err = bus_dmamap_load(sc->sc_dmat, cb->cmddma, xs->cmd,
! 742: xs->cmdlen, NULL, ((xs->flags & SCSI_NOSLEEP) ?
! 743: BUS_DMA_NOWAIT : BUS_DMA_WAITOK) |
! 744: BUS_DMA_STREAMING | BUS_DMA_WRITE);
! 745: if (err) {
! 746: printf("%s: unable to load cmd DMA map: %d",
! 747: sc->sc_dev.dv_xname, err);
! 748: xs->error = XS_DRIVER_STUFFUP;
! 749: scsi_done(xs);
! 750: TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain);
! 751: return (COMPLETE);
! 752: }
! 753: bus_dmamap_sync(sc->sc_dmat, cb->cmddma, 0, xs->cmdlen,
! 754: BUS_DMASYNC_PREWRITE);
! 755:
! 756: /* Setup data buffer DMA */
! 757: if (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
! 758: cb->datalen = xs->datalen;
! 759: err = bus_dmamap_load(sc->sc_dmat, cb->datadma,
! 760: xs->data, xs->datalen, NULL,
! 761: ((xs->flags & SCSI_NOSLEEP) ?
! 762: BUS_DMA_NOWAIT : BUS_DMA_WAITOK) |
! 763: BUS_DMA_STREAMING |
! 764: ((xs->flags & SCSI_DATA_IN) ? BUS_DMA_READ :
! 765: BUS_DMA_WRITE));
! 766: if (err) {
! 767: printf("%s: unable to load data DMA map: %d",
! 768: sc->sc_dev.dv_xname, err);
! 769: xs->error = XS_DRIVER_STUFFUP;
! 770: bus_dmamap_unload(sc->sc_dmat, cb->cmddma);
! 771: scsi_done(xs);
! 772: TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain);
! 773: return (COMPLETE);
! 774: }
! 775: bus_dmamap_sync(sc->sc_dmat, cb->datadma,
! 776: 0, xs->datalen,
! 777: BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
! 778: }
! 779:
! 780: xfer->status = SCSI_OOSIOP_NOSTATUS;
! 781:
! 782: oosiop_setup(sc, cb);
! 783:
! 784: s = splbio();
! 785:
! 786: /*
! 787: * Always initialize timeout so it does not contain trash
! 788: * that could confuse timeout_del().
! 789: */
! 790: timeout_set(&xs->stimeout, oosiop_timeout, cb);
! 791:
! 792: TAILQ_INSERT_TAIL(&sc->sc_cbq, cb, chain);
! 793:
! 794: if (!sc->sc_active) {
! 795: /* Abort script to start selection */
! 796: oosiop_write_1(sc, OOSIOP_ISTAT, OOSIOP_ISTAT_ABRT);
! 797: }
! 798: if (xs->flags & SCSI_POLL)
! 799: oosiop_poll(sc, cb);
! 800: else {
! 801: /* start expire timer */
! 802: timeout_add(&xs->stimeout, (xs->timeout / 1000) * hz);
! 803: }
! 804:
! 805: splx(s);
! 806:
! 807: if ((xs->flags & ITSDONE) == 0)
! 808: return (SUCCESSFULLY_QUEUED);
! 809: else
! 810: return (COMPLETE);
! 811: }
! 812:
! 813: void
! 814: oosiop_poll(struct oosiop_softc *sc, struct oosiop_cb *cb)
! 815: {
! 816: struct scsi_xfer *xs = cb->xs;
! 817: int i, s, to;
! 818: u_int8_t istat;
! 819:
! 820: s = splbio();
! 821: to = xs->timeout / 1000;
! 822: for (;;) {
! 823: i = 1000;
! 824: while (((istat = oosiop_read_1(sc, OOSIOP_ISTAT)) &
! 825: (OOSIOP_ISTAT_SIP | OOSIOP_ISTAT_DIP)) == 0) {
! 826: if (i <= 0) {
! 827: i = 1000;
! 828: to--;
! 829: if (to <= 0) {
! 830: oosiop_reset(sc);
! 831: splx(s);
! 832: return;
! 833: }
! 834: }
! 835: delay(1000);
! 836: i--;
! 837: }
! 838: oosiop_processintr(sc, istat);
! 839:
! 840: if (xs->flags & ITSDONE)
! 841: break;
! 842: }
! 843:
! 844: splx(s);
! 845: }
! 846:
! 847: void
! 848: oosiop_setup(struct oosiop_softc *sc, struct oosiop_cb *cb)
! 849: {
! 850: struct oosiop_xfer *xfer = cb->xfer;
! 851:
! 852: cb->curdp = 0;
! 853: cb->savedp = 0;
! 854:
! 855: oosiop_setup_sgdma(sc, cb);
! 856:
! 857: /* Setup msgout buffer */
! 858: OOSIOP_XFERMSG_SYNC(sc, cb,
! 859: BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
! 860: xfer->msgout[0] = MSG_IDENTIFY(cb->lun,
! 861: (cb->xs->cmd->opcode != REQUEST_SENSE));
! 862: cb->msgoutlen = 1;
! 863:
! 864: if (sc->sc_tgt[cb->id].flags & TGTF_SYNCNEG) {
! 865: /* Send SDTR */
! 866: xfer->msgout[1] = MSG_EXTENDED;
! 867: xfer->msgout[2] = MSG_EXT_SDTR_LEN;
! 868: xfer->msgout[3] = MSG_EXT_SDTR;
! 869: xfer->msgout[4] = sc->sc_minperiod;
! 870: xfer->msgout[5] = OOSIOP_MAX_OFFSET;
! 871: cb->msgoutlen = 6;
! 872: sc->sc_tgt[cb->id].flags &= ~TGTF_SYNCNEG;
! 873: sc->sc_tgt[cb->id].flags |= TGTF_WAITSDTR;
! 874: }
! 875:
! 876: OOSIOP_XFERMSG_SYNC(sc, cb,
! 877: BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
! 878: }
! 879:
! 880: void
! 881: oosiop_done(struct oosiop_softc *sc, struct oosiop_cb *cb)
! 882: {
! 883: struct scsi_xfer *xs;
! 884: struct scsi_link *periph;
! 885: int autosense;
! 886:
! 887: xs = cb->xs;
! 888: periph = xs->sc_link;
! 889:
! 890: /*
! 891: * Record if this is the completion of an auto sense
! 892: * scsi command, and then reset the flag so we don't loop
! 893: * when such a command fails or times out.
! 894: */
! 895: autosense = cb->flags & CBF_AUTOSENSE;
! 896: cb->flags &= ~CBF_AUTOSENSE;
! 897:
! 898: bus_dmamap_sync(sc->sc_dmat, cb->cmddma, 0, cb->cmdlen,
! 899: BUS_DMASYNC_POSTWRITE);
! 900: bus_dmamap_unload(sc->sc_dmat, cb->cmddma);
! 901:
! 902: if (cb->xsflags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
! 903: bus_dmamap_sync(sc->sc_dmat, cb->datadma, 0, cb->datalen,
! 904: (cb->xsflags & SCSI_DATA_IN) ?
! 905: BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
! 906: bus_dmamap_unload(sc->sc_dmat, cb->datadma);
! 907: }
! 908:
! 909: timeout_del(&xs->stimeout);
! 910:
! 911: xs->status = cb->xfer->status;
! 912:
! 913: if (cb->flags & CBF_SELTOUT)
! 914: xs->error = XS_SELTIMEOUT;
! 915: else if (cb->flags & CBF_TIMEOUT)
! 916: xs->error = XS_TIMEOUT;
! 917: else switch (xs->status) {
! 918: case SCSI_OK:
! 919: if (autosense == 0)
! 920: xs->error = XS_NOERROR;
! 921: else
! 922: xs->error = XS_SENSE;
! 923: break;
! 924:
! 925: case SCSI_BUSY:
! 926: xs->error = XS_BUSY;
! 927: break;
! 928: case SCSI_CHECK:
! 929: #ifdef notyet
! 930: if (autosense == 0)
! 931: cb->flags |= CBF_AUTOSENSE;
! 932: else
! 933: #endif
! 934: xs->error = XS_DRIVER_STUFFUP;
! 935: break;
! 936: case SCSI_OOSIOP_NOSTATUS:
! 937: /* the status byte was not updated, cmd was aborted. */
! 938: xs->error = XS_SELTIMEOUT;
! 939: break;
! 940:
! 941: default:
! 942: xs->error = XS_RESET;
! 943: break;
! 944: }
! 945:
! 946: if ((cb->flags & CBF_AUTOSENSE) == 0) {
! 947: /* Put it on the free list. */
! 948: FREE:
! 949: xs->resid = 0;
! 950: xs->flags |= ITSDONE;
! 951: scsi_done(xs);
! 952: TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain);
! 953:
! 954: if (cb == sc->sc_curcb)
! 955: sc->sc_curcb = NULL;
! 956: if (cb == sc->sc_lastcb)
! 957: sc->sc_lastcb = NULL;
! 958: sc->sc_tgt[cb->id].nexus = NULL;
! 959: } else {
! 960: /* Set up REQUEST_SENSE command */
! 961: struct scsi_sense *cmd = (struct scsi_sense *)xs->cmd;
! 962: int err;
! 963:
! 964: bzero(cmd, sizeof(*cmd));
! 965: cmd->opcode = REQUEST_SENSE;
! 966: cmd->byte2 = xs->sc_link->lun << 5;
! 967: cb->cmdlen = cmd->length = sizeof(xs->sense);
! 968:
! 969: cb->xsflags &= SCSI_POLL | SCSI_NOSLEEP;
! 970: cb->xsflags |= SCSI_DATA_IN;
! 971: cb->datalen = sizeof xs->sense;
! 972:
! 973: /* Setup SCSI command buffer DMA */
! 974: err = bus_dmamap_load(sc->sc_dmat, cb->cmddma, cmd,
! 975: cb->cmdlen, NULL,
! 976: BUS_DMA_NOWAIT | BUS_DMA_STREAMING | BUS_DMA_WRITE);
! 977: if (err) {
! 978: printf("%s: unable to load REQUEST_SENSE cmd DMA map: %d",
! 979: sc->sc_dev.dv_xname, err);
! 980: xs->error = XS_DRIVER_STUFFUP;
! 981: goto FREE;
! 982: }
! 983: bus_dmamap_sync(sc->sc_dmat, cb->cmddma, 0, cb->cmdlen,
! 984: BUS_DMASYNC_PREWRITE);
! 985:
! 986: /* Setup data buffer DMA */
! 987: err = bus_dmamap_load(sc->sc_dmat, cb->datadma,
! 988: &xs->sense, sizeof(xs->sense), NULL,
! 989: BUS_DMA_NOWAIT | BUS_DMA_STREAMING | BUS_DMA_READ);
! 990: if (err) {
! 991: printf("%s: unable to load REQUEST_SENSE data DMA map: %d",
! 992: sc->sc_dev.dv_xname, err);
! 993: xs->error = XS_DRIVER_STUFFUP;
! 994: bus_dmamap_unload(sc->sc_dmat, cb->cmddma);
! 995: goto FREE;
! 996: }
! 997: bus_dmamap_sync(sc->sc_dmat, cb->datadma,
! 998: 0, sizeof(xs->sense), BUS_DMASYNC_PREREAD);
! 999:
! 1000: oosiop_setup(sc, cb);
! 1001:
! 1002: TAILQ_INSERT_HEAD(&sc->sc_cbq, cb, chain);
! 1003: if ((cb->xs->flags & SCSI_POLL) == 0) {
! 1004: /* start expire timer */
! 1005: timeout_add(&xs->stimeout, (xs->timeout / 1000) * hz);
! 1006: }
! 1007: }
! 1008: }
! 1009:
! 1010: void
! 1011: oosiop_timeout(void *arg)
! 1012: {
! 1013: struct oosiop_cb *cb = arg;
! 1014: struct scsi_xfer *xs = cb->xs;
! 1015: struct oosiop_softc *sc = xs->sc_link->adapter_softc;
! 1016: int s;
! 1017:
! 1018: sc_print_addr(xs->sc_link);
! 1019: printf("command 0x%02x timeout on xs %p\n", xs->cmd->opcode, xs);
! 1020:
! 1021: s = splbio();
! 1022:
! 1023: oosiop_reset_bus(sc);
! 1024:
! 1025: cb->flags |= CBF_TIMEOUT;
! 1026: oosiop_done(sc, cb);
! 1027:
! 1028: splx(s);
! 1029: }
! 1030:
! 1031: void
! 1032: oosiop_reset(struct oosiop_softc *sc)
! 1033: {
! 1034: int i, s;
! 1035:
! 1036: s = splbio();
! 1037:
! 1038: /* Stop SCRIPTS processor */
! 1039: oosiop_write_1(sc, OOSIOP_ISTAT, OOSIOP_ISTAT_ABRT);
! 1040: delay(100);
! 1041: oosiop_write_1(sc, OOSIOP_ISTAT, 0);
! 1042:
! 1043: /* Reset the chip */
! 1044: oosiop_write_1(sc, OOSIOP_DCNTL, sc->sc_dcntl | OOSIOP_DCNTL_RST);
! 1045: delay(100);
! 1046: oosiop_write_1(sc, OOSIOP_DCNTL, sc->sc_dcntl);
! 1047: delay(10000);
! 1048:
! 1049: /* Set up various chip parameters */
! 1050: oosiop_write_1(sc, OOSIOP_SCNTL0, OOSIOP_ARB_FULL | OOSIOP_SCNTL0_EPG);
! 1051: oosiop_write_1(sc, OOSIOP_SCNTL1, OOSIOP_SCNTL1_ESR);
! 1052: oosiop_write_1(sc, OOSIOP_DCNTL, sc->sc_dcntl);
! 1053: oosiop_write_1(sc, OOSIOP_DMODE, OOSIOP_DMODE_BL_8);
! 1054: oosiop_write_1(sc, OOSIOP_SCID, OOSIOP_SCID_VALUE(sc->sc_id));
! 1055: oosiop_write_1(sc, OOSIOP_DWT, 0xff); /* Enable DMA timeout */
! 1056: oosiop_write_1(sc, OOSIOP_CTEST7, 0);
! 1057: oosiop_write_1(sc, OOSIOP_SXFER, 0);
! 1058:
! 1059: /* Clear all interrupts */
! 1060: (void)oosiop_read_1(sc, OOSIOP_SSTAT0);
! 1061: (void)oosiop_read_1(sc, OOSIOP_SSTAT1);
! 1062: (void)oosiop_read_1(sc, OOSIOP_DSTAT);
! 1063:
! 1064: /* Enable interrupts */
! 1065: oosiop_write_1(sc, OOSIOP_SIEN,
! 1066: OOSIOP_SIEN_M_A | OOSIOP_SIEN_STO | OOSIOP_SIEN_SGE |
! 1067: OOSIOP_SIEN_UDC | OOSIOP_SIEN_RST | OOSIOP_SIEN_PAR);
! 1068: oosiop_write_1(sc, OOSIOP_DIEN,
! 1069: OOSIOP_DIEN_ABRT | OOSIOP_DIEN_SSI | OOSIOP_DIEN_SIR |
! 1070: OOSIOP_DIEN_WTD | OOSIOP_DIEN_IID);
! 1071:
! 1072: /* Set target state to asynchronous */
! 1073: for (i = 0; i < OOSIOP_NTGT; i++) {
! 1074: sc->sc_tgt[i].flags = 0;
! 1075: sc->sc_tgt[i].scf = 0;
! 1076: sc->sc_tgt[i].sxfer = 0;
! 1077: }
! 1078:
! 1079: splx(s);
! 1080: }
! 1081:
! 1082: void
! 1083: oosiop_reset_bus(struct oosiop_softc *sc)
! 1084: {
! 1085: int s, i;
! 1086:
! 1087: s = splbio();
! 1088:
! 1089: /* Assert SCSI RST */
! 1090: oosiop_write_1(sc, OOSIOP_SCNTL1, OOSIOP_SCNTL1_RST);
! 1091: delay(25); /* Reset hold time (25us) */
! 1092: oosiop_write_1(sc, OOSIOP_SCNTL1, 0);
! 1093:
! 1094: /* Remove all nexuses */
! 1095: for (i = 0; i < OOSIOP_NTGT; i++) {
! 1096: if (sc->sc_tgt[i].nexus) {
! 1097: sc->sc_tgt[i].nexus->xfer->status =
! 1098: SCSI_OOSIOP_NOSTATUS; /* XXX */
! 1099: oosiop_done(sc, sc->sc_tgt[i].nexus);
! 1100: }
! 1101: }
! 1102:
! 1103: sc->sc_curcb = NULL;
! 1104:
! 1105: delay(250000); /* Reset to selection (250ms) */
! 1106:
! 1107: splx(s);
! 1108: }
! 1109:
! 1110: /*
! 1111: * interrupt handler
! 1112: */
! 1113: int
! 1114: oosiop_intr(struct oosiop_softc *sc)
! 1115: {
! 1116: u_int8_t istat;
! 1117:
! 1118: istat = oosiop_read_1(sc, OOSIOP_ISTAT);
! 1119:
! 1120: if ((istat & (OOSIOP_ISTAT_SIP | OOSIOP_ISTAT_DIP)) == 0)
! 1121: return (0);
! 1122:
! 1123: oosiop_processintr(sc, istat);
! 1124: return (1);
! 1125: }
! 1126:
! 1127: void
! 1128: oosiop_processintr(struct oosiop_softc *sc, u_int8_t istat)
! 1129: {
! 1130: struct oosiop_cb *cb;
! 1131: u_int32_t dcmd;
! 1132: u_int8_t dstat, sstat0;
! 1133:
! 1134: sc->sc_nextdsp = Ent_wait_reselect;
! 1135:
! 1136: /* DMA interrupts */
! 1137: if (istat & OOSIOP_ISTAT_DIP) {
! 1138: oosiop_write_1(sc, OOSIOP_ISTAT, 0);
! 1139:
! 1140: dstat = oosiop_read_1(sc, OOSIOP_DSTAT);
! 1141:
! 1142: if (dstat & OOSIOP_DSTAT_ABRT) {
! 1143: sc->sc_nextdsp = oosiop_read_4(sc, OOSIOP_DSP) -
! 1144: sc->sc_scrbase - 8;
! 1145:
! 1146: if (sc->sc_nextdsp == Ent_p_resel_msgin_move &&
! 1147: (oosiop_read_1(sc, OOSIOP_SBCL) & OOSIOP_ACK)) {
! 1148: if ((dstat & OOSIOP_DSTAT_DFE) == 0)
! 1149: oosiop_flush_fifo(sc);
! 1150: sc->sc_nextdsp += 8;
! 1151: }
! 1152: }
! 1153:
! 1154: if (dstat & OOSIOP_DSTAT_SSI) {
! 1155: sc->sc_nextdsp = oosiop_read_4(sc, OOSIOP_DSP) -
! 1156: sc->sc_scrbase;
! 1157: printf("%s: single step %08x\n", sc->sc_dev.dv_xname,
! 1158: sc->sc_nextdsp);
! 1159: }
! 1160:
! 1161: if (dstat & OOSIOP_DSTAT_SIR) {
! 1162: if ((dstat & OOSIOP_DSTAT_DFE) == 0)
! 1163: oosiop_flush_fifo(sc);
! 1164: oosiop_scriptintr(sc);
! 1165: }
! 1166:
! 1167: if (dstat & OOSIOP_DSTAT_WTD) {
! 1168: printf("%s: DMA time out\n", sc->sc_dev.dv_xname);
! 1169: oosiop_reset(sc);
! 1170: }
! 1171:
! 1172: if (dstat & OOSIOP_DSTAT_IID) {
! 1173: dcmd = oosiop_read_4(sc, OOSIOP_DBC);
! 1174: if ((dcmd & 0xf8000000) == 0x48000000) {
! 1175: printf("%s: REQ asserted on WAIT DISCONNECT\n",
! 1176: sc->sc_dev.dv_xname);
! 1177: sc->sc_nextdsp = Ent_phasedispatch; /* XXX */
! 1178: } else {
! 1179: printf("%s: invalid SCRIPTS instruction "
! 1180: "addr=%08x dcmd=%08x dsps=%08x\n",
! 1181: sc->sc_dev.dv_xname,
! 1182: oosiop_read_4(sc, OOSIOP_DSP) - 8, dcmd,
! 1183: oosiop_read_4(sc, OOSIOP_DSPS));
! 1184: oosiop_reset(sc);
! 1185: OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE);
! 1186: oosiop_load_script(sc);
! 1187: }
! 1188: }
! 1189:
! 1190: if ((dstat & OOSIOP_DSTAT_DFE) == 0)
! 1191: oosiop_clear_fifo(sc);
! 1192: }
! 1193:
! 1194: /* SCSI interrupts */
! 1195: if (istat & OOSIOP_ISTAT_SIP) {
! 1196: if (istat & OOSIOP_ISTAT_DIP)
! 1197: delay(1);
! 1198: sstat0 = oosiop_read_1(sc, OOSIOP_SSTAT0);
! 1199:
! 1200: if (sstat0 & OOSIOP_SSTAT0_M_A) {
! 1201: /* SCSI phase mismatch during MOVE operation */
! 1202: oosiop_phasemismatch(sc);
! 1203: sc->sc_nextdsp = Ent_phasedispatch;
! 1204: }
! 1205:
! 1206: if (sstat0 & OOSIOP_SSTAT0_STO) {
! 1207: if (sc->sc_curcb) {
! 1208: sc->sc_curcb->flags |= CBF_SELTOUT;
! 1209: oosiop_done(sc, sc->sc_curcb);
! 1210: }
! 1211: }
! 1212:
! 1213: if (sstat0 & OOSIOP_SSTAT0_SGE) {
! 1214: printf("%s: SCSI gross error\n", sc->sc_dev.dv_xname);
! 1215: oosiop_reset(sc);
! 1216: }
! 1217:
! 1218: if (sstat0 & OOSIOP_SSTAT0_UDC) {
! 1219: /* XXX */
! 1220: if (sc->sc_curcb) {
! 1221: printf("%s: unexpected disconnect\n",
! 1222: sc->sc_dev.dv_xname);
! 1223: oosiop_done(sc, sc->sc_curcb);
! 1224: }
! 1225: }
! 1226:
! 1227: if (sstat0 & OOSIOP_SSTAT0_RST)
! 1228: oosiop_reset(sc);
! 1229:
! 1230: if (sstat0 & OOSIOP_SSTAT0_PAR)
! 1231: printf("%s: parity error\n", sc->sc_dev.dv_xname);
! 1232: }
! 1233:
! 1234: /* Start next command if available */
! 1235: if (sc->sc_nextdsp == Ent_wait_reselect && TAILQ_FIRST(&sc->sc_cbq)) {
! 1236: cb = sc->sc_curcb = TAILQ_FIRST(&sc->sc_cbq);
! 1237: TAILQ_REMOVE(&sc->sc_cbq, cb, chain);
! 1238: sc->sc_tgt[cb->id].nexus = cb;
! 1239:
! 1240: oosiop_setup_dma(sc);
! 1241: oosiop_setup_syncxfer(sc);
! 1242: sc->sc_lastcb = cb;
! 1243: sc->sc_nextdsp = Ent_start_select;
! 1244:
! 1245: /* Schedule timeout */
! 1246: if ((cb->xs->flags & SCSI_POLL) == 0) {
! 1247: /* start expire timer */
! 1248: timeout_add(&cb->xs->stimeout,
! 1249: (cb->xs->timeout / 1000) * hz);
! 1250: }
! 1251: }
! 1252:
! 1253: sc->sc_active = (sc->sc_nextdsp != Ent_wait_reselect);
! 1254:
! 1255: /* Restart script */
! 1256: oosiop_write_4(sc, OOSIOP_DSP, sc->sc_nextdsp + sc->sc_scrbase);
! 1257: }
! 1258:
! 1259: void
! 1260: oosiop_scriptintr(struct oosiop_softc *sc)
! 1261: {
! 1262: struct oosiop_cb *cb;
! 1263: u_int32_t icode;
! 1264: u_int32_t dsp;
! 1265: int i;
! 1266: u_int8_t sfbr, resid, resmsg;
! 1267:
! 1268: cb = sc->sc_curcb;
! 1269: icode = oosiop_read_4(sc, OOSIOP_DSPS);
! 1270:
! 1271: switch (icode) {
! 1272: case A_int_done:
! 1273: if (cb)
! 1274: oosiop_done(sc, cb);
! 1275: break;
! 1276:
! 1277: case A_int_msgin:
! 1278: if (cb)
! 1279: oosiop_msgin(sc, cb);
! 1280: break;
! 1281:
! 1282: case A_int_extmsg:
! 1283: /* extended message in DMA setup request */
! 1284: sfbr = oosiop_read_1(sc, OOSIOP_SFBR);
! 1285: OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE);
! 1286: oosiop_fixup_move(sc, Ent_p_extmsgin_move, sfbr,
! 1287: cb->xferdma->dm_segs[0].ds_addr +
! 1288: offsetof(struct oosiop_xfer, msgin[2]));
! 1289: OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE);
! 1290: sc->sc_nextdsp = Ent_rcv_extmsg;
! 1291: break;
! 1292:
! 1293: case A_int_resel:
! 1294: /* reselected */
! 1295: resid = oosiop_read_1(sc, OOSIOP_SFBR);
! 1296: for (i = 0; i < OOSIOP_NTGT; i++)
! 1297: if (resid & (1 << i))
! 1298: break;
! 1299: if (i == OOSIOP_NTGT) {
! 1300: printf("%s: missing reselection target id\n",
! 1301: sc->sc_dev.dv_xname);
! 1302: break;
! 1303: }
! 1304: sc->sc_resid = i;
! 1305: sc->sc_nextdsp = Ent_wait_resel_identify;
! 1306:
! 1307: if (cb) {
! 1308: /* Current command was lost arbitration */
! 1309: sc->sc_tgt[cb->id].nexus = NULL;
! 1310: TAILQ_INSERT_HEAD(&sc->sc_cbq, cb, chain);
! 1311: sc->sc_curcb = NULL;
! 1312: }
! 1313:
! 1314: break;
! 1315:
! 1316: case A_int_res_id:
! 1317: cb = sc->sc_tgt[sc->sc_resid].nexus;
! 1318: resmsg = oosiop_read_1(sc, OOSIOP_SFBR);
! 1319: if (MSG_ISIDENTIFY(resmsg) && cb &&
! 1320: (resmsg & MSG_IDENTIFY_LUNMASK) == cb->lun) {
! 1321: sc->sc_curcb = cb;
! 1322: if (cb != sc->sc_lastcb) {
! 1323: oosiop_setup_dma(sc);
! 1324: oosiop_setup_syncxfer(sc);
! 1325: sc->sc_lastcb = cb;
! 1326: }
! 1327: if (cb->curdp != cb->savedp) {
! 1328: cb->curdp = cb->savedp;
! 1329: oosiop_setup_sgdma(sc, cb);
! 1330: }
! 1331: sc->sc_nextdsp = Ent_ack_msgin;
! 1332: } else {
! 1333: /* Reselection from invalid target */
! 1334: oosiop_reset_bus(sc);
! 1335: }
! 1336: break;
! 1337:
! 1338: case A_int_resfail:
! 1339: /* reselect failed */
! 1340: break;
! 1341:
! 1342: case A_int_disc:
! 1343: /* disconnected */
! 1344: sc->sc_curcb = NULL;
! 1345: break;
! 1346:
! 1347: case A_int_err:
! 1348: /* generic error */
! 1349: dsp = oosiop_read_4(sc, OOSIOP_DSP);
! 1350: printf("%s: script error at 0x%08x\n", sc->sc_dev.dv_xname,
! 1351: dsp - 8);
! 1352: sc->sc_curcb = NULL;
! 1353: break;
! 1354:
! 1355: case DATAIN_TRAP:
! 1356: printf("%s: unexpected datain\n", sc->sc_dev.dv_xname);
! 1357: /* XXX: need to reset? */
! 1358: break;
! 1359:
! 1360: case DATAOUT_TRAP:
! 1361: printf("%s: unexpected dataout\n", sc->sc_dev.dv_xname);
! 1362: /* XXX: need to reset? */
! 1363: break;
! 1364:
! 1365: default:
! 1366: printf("%s: unknown intr code %08x\n", sc->sc_dev.dv_xname,
! 1367: icode);
! 1368: break;
! 1369: }
! 1370: }
! 1371:
! 1372: void
! 1373: oosiop_msgin(struct oosiop_softc *sc, struct oosiop_cb *cb)
! 1374: {
! 1375: struct oosiop_xfer *xfer;
! 1376: int msgout;
! 1377:
! 1378: xfer = cb->xfer;
! 1379: sc->sc_nextdsp = Ent_ack_msgin;
! 1380: msgout = 0;
! 1381:
! 1382: OOSIOP_XFERMSG_SYNC(sc, cb,
! 1383: BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
! 1384:
! 1385: switch (xfer->msgin[0]) {
! 1386: case MSG_EXTENDED:
! 1387: switch (xfer->msgin[2]) {
! 1388: case MSG_EXT_SDTR:
! 1389: if (sc->sc_tgt[cb->id].flags & TGTF_WAITSDTR) {
! 1390: /* Host initiated SDTR */
! 1391: sc->sc_tgt[cb->id].flags &= ~TGTF_WAITSDTR;
! 1392: } else {
! 1393: /* Target initiated SDTR */
! 1394: if (xfer->msgin[3] < sc->sc_minperiod)
! 1395: xfer->msgin[3] = sc->sc_minperiod;
! 1396: if (xfer->msgin[4] > OOSIOP_MAX_OFFSET)
! 1397: xfer->msgin[4] = OOSIOP_MAX_OFFSET;
! 1398: xfer->msgout[0] = MSG_EXTENDED;
! 1399: xfer->msgout[1] = MSG_EXT_SDTR_LEN;
! 1400: xfer->msgout[2] = MSG_EXT_SDTR;
! 1401: xfer->msgout[3] = xfer->msgin[3];
! 1402: xfer->msgout[4] = xfer->msgin[4];
! 1403: cb->msgoutlen = 5;
! 1404: msgout = 1;
! 1405: }
! 1406: oosiop_set_syncparam(sc, cb->id, (int)xfer->msgin[3],
! 1407: (int)xfer->msgin[4]);
! 1408: oosiop_setup_syncxfer(sc);
! 1409: break;
! 1410:
! 1411: default:
! 1412: /* Reject message */
! 1413: xfer->msgout[0] = MSG_MESSAGE_REJECT;
! 1414: cb->msgoutlen = 1;
! 1415: msgout = 1;
! 1416: break;
! 1417: }
! 1418: break;
! 1419:
! 1420: case MSG_SAVEDATAPOINTER:
! 1421: cb->savedp = cb->curdp;
! 1422: break;
! 1423:
! 1424: case MSG_RESTOREPOINTERS:
! 1425: if (cb->curdp != cb->savedp) {
! 1426: cb->curdp = cb->savedp;
! 1427: oosiop_setup_sgdma(sc, cb);
! 1428: }
! 1429: break;
! 1430:
! 1431: case MSG_MESSAGE_REJECT:
! 1432: if (sc->sc_tgt[cb->id].flags & TGTF_WAITSDTR) {
! 1433: /* SDTR rejected */
! 1434: sc->sc_tgt[cb->id].flags &= ~TGTF_WAITSDTR;
! 1435: oosiop_set_syncparam(sc, cb->id, 0, 0);
! 1436: oosiop_setup_syncxfer(sc);
! 1437: }
! 1438: break;
! 1439:
! 1440: default:
! 1441: /* Reject message */
! 1442: xfer->msgout[0] = MSG_MESSAGE_REJECT;
! 1443: cb->msgoutlen = 1;
! 1444: msgout = 1;
! 1445: }
! 1446:
! 1447: OOSIOP_XFERMSG_SYNC(sc, cb,
! 1448: BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
! 1449:
! 1450: if (msgout) {
! 1451: OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE);
! 1452: oosiop_fixup_move(sc, Ent_p_msgout_move, cb->msgoutlen,
! 1453: cb->xferdma->dm_segs[0].ds_addr +
! 1454: offsetof(struct oosiop_xfer, msgout[0]));
! 1455: OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE);
! 1456: sc->sc_nextdsp = Ent_sendmsg;
! 1457: }
! 1458: }
CVSweb