Annotation of sys/dev/ic/siop.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: siop.c,v 1.48 2007/08/05 19:05:09 kettenis Exp $ */
! 2: /* $NetBSD: siop.c,v 1.79 2005/11/18 23:10:32 bouyer Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 2000 Manuel Bouyer.
! 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. All advertising materials mentioning features or use of this software
! 16: * must display the following acknowledgement:
! 17: * This product includes software developed by Manuel Bouyer.
! 18: * 4. The name of the author may not be used to endorse or promote products
! 19: * derived from this software without specific prior written permission.
! 20: *
! 21: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 22: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 23: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 24: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 25: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 26: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 27: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 28: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 29: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 30: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 31: *
! 32: */
! 33:
! 34: /* SYM53c7/8xx PCI-SCSI I/O Processors driver */
! 35:
! 36: #include <sys/param.h>
! 37: #include <sys/systm.h>
! 38: #include <sys/device.h>
! 39: #include <sys/malloc.h>
! 40: #include <sys/buf.h>
! 41: #include <sys/kernel.h>
! 42:
! 43: #include <machine/endian.h>
! 44: #include <machine/bus.h>
! 45:
! 46: #include <dev/microcode/siop/siop.out>
! 47:
! 48: #include <scsi/scsi_all.h>
! 49: #include <scsi/scsi_message.h>
! 50: #include <scsi/scsiconf.h>
! 51:
! 52: #include <dev/ic/siopreg.h>
! 53: #include <dev/ic/siopvar_common.h>
! 54: #include <dev/ic/siopvar.h>
! 55:
! 56: #ifndef SIOP_DEBUG
! 57: #undef SIOP_DEBUG
! 58: #undef SIOP_DEBUG_DR
! 59: #undef SIOP_DEBUG_INTR
! 60: #undef SIOP_DEBUG_SCHED
! 61: #undef DUMP_SCRIPT
! 62: #else
! 63: #define SIOP_DEBUG_DR
! 64: #define SIOP_DEBUG_INTR
! 65: #define SIOP_DEBUG_SCHED
! 66: #define DUMP_SCRIPT
! 67: #endif
! 68:
! 69:
! 70: #undef SIOP_STATS
! 71:
! 72: #ifndef SIOP_DEFAULT_TARGET
! 73: #define SIOP_DEFAULT_TARGET 7
! 74: #endif
! 75:
! 76: /* number of cmd descriptors per block */
! 77: #define SIOP_NCMDPB (PAGE_SIZE / sizeof(struct siop_xfer))
! 78:
! 79: /* Number of scheduler slot (needs to match script) */
! 80: #define SIOP_NSLOTS 40
! 81:
! 82: void siop_table_sync(struct siop_cmd *, int);
! 83: void siop_script_sync(struct siop_softc *, int);
! 84: u_int32_t siop_script_read(struct siop_softc *, u_int);
! 85: void siop_script_write(struct siop_softc *, u_int, u_int32_t);
! 86: void siop_reset(struct siop_softc *);
! 87: void siop_handle_reset(struct siop_softc *);
! 88: int siop_handle_qtag_reject(struct siop_cmd *);
! 89: void siop_scsicmd_end(struct siop_cmd *);
! 90: void siop_start(struct siop_softc *);
! 91: void siop_timeout(void *);
! 92: int siop_scsicmd(struct scsi_xfer *);
! 93: #ifdef DUMP_SCRIPT
! 94: void siop_dump_script(struct siop_softc *);
! 95: #endif
! 96: void siop_morecbd(struct siop_softc *);
! 97: struct siop_lunsw *siop_get_lunsw(struct siop_softc *);
! 98: void siop_add_reselsw(struct siop_softc *, int);
! 99: void siop_update_scntl3(struct siop_softc *, struct siop_common_target *);
! 100:
! 101: struct cfdriver siop_cd = {
! 102: NULL, "siop", DV_DULL
! 103: };
! 104:
! 105: struct scsi_adapter siop_adapter = {
! 106: siop_scsicmd,
! 107: siop_minphys,
! 108: NULL,
! 109: NULL,
! 110: };
! 111:
! 112: struct scsi_device siop_dev = {
! 113: NULL,
! 114: NULL,
! 115: NULL,
! 116: NULL,
! 117: };
! 118:
! 119: #ifdef SIOP_STATS
! 120: static int siop_stat_intr = 0;
! 121: static int siop_stat_intr_shortxfer = 0;
! 122: static int siop_stat_intr_sdp = 0;
! 123: static int siop_stat_intr_saveoffset = 0;
! 124: static int siop_stat_intr_done = 0;
! 125: static int siop_stat_intr_xferdisc = 0;
! 126: static int siop_stat_intr_lunresel = 0;
! 127: static int siop_stat_intr_qfull = 0;
! 128: void siop_printstats(void);
! 129: #define INCSTAT(x) x++
! 130: #else
! 131: #define INCSTAT(x)
! 132: #endif
! 133:
! 134: void
! 135: siop_table_sync(siop_cmd, ops)
! 136: struct siop_cmd *siop_cmd;
! 137: int ops;
! 138: {
! 139: struct siop_common_softc *sc = siop_cmd->cmd_c.siop_sc;
! 140: bus_addr_t offset;
! 141:
! 142: offset = siop_cmd->cmd_c.dsa -
! 143: siop_cmd->siop_cbdp->xferdma->dm_segs[0].ds_addr;
! 144: bus_dmamap_sync(sc->sc_dmat, siop_cmd->siop_cbdp->xferdma, offset,
! 145: sizeof(struct siop_xfer), ops);
! 146: }
! 147:
! 148: void
! 149: siop_script_sync(sc, ops)
! 150: struct siop_softc *sc;
! 151: int ops;
! 152: {
! 153: if ((sc->sc_c.features & SF_CHIP_RAM) == 0)
! 154: bus_dmamap_sync(sc->sc_c.sc_dmat, sc->sc_c.sc_scriptdma, 0,
! 155: PAGE_SIZE, ops);
! 156: }
! 157:
! 158: u_int32_t
! 159: siop_script_read(sc, offset)
! 160: struct siop_softc *sc;
! 161: u_int offset;
! 162: {
! 163: if (sc->sc_c.features & SF_CHIP_RAM) {
! 164: return bus_space_read_4(sc->sc_c.sc_ramt, sc->sc_c.sc_ramh,
! 165: offset * 4);
! 166: } else {
! 167: return siop_ctoh32(&sc->sc_c, sc->sc_c.sc_script[offset]);
! 168: }
! 169: }
! 170:
! 171: void
! 172: siop_script_write(sc, offset, val)
! 173: struct siop_softc *sc;
! 174: u_int offset;
! 175: u_int32_t val;
! 176: {
! 177: if (sc->sc_c.features & SF_CHIP_RAM) {
! 178: bus_space_write_4(sc->sc_c.sc_ramt, sc->sc_c.sc_ramh,
! 179: offset * 4, val);
! 180: } else {
! 181: sc->sc_c.sc_script[offset] = siop_htoc32(&sc->sc_c, val);
! 182: }
! 183: }
! 184:
! 185: void
! 186: siop_attach(sc)
! 187: struct siop_softc *sc;
! 188: {
! 189: struct scsibus_attach_args saa;
! 190:
! 191: if (siop_common_attach(&sc->sc_c) != 0)
! 192: return;
! 193:
! 194: TAILQ_INIT(&sc->free_list);
! 195: TAILQ_INIT(&sc->ready_list);
! 196: TAILQ_INIT(&sc->urgent_list);
! 197: TAILQ_INIT(&sc->cmds);
! 198: TAILQ_INIT(&sc->lunsw_list);
! 199: sc->sc_currschedslot = 0;
! 200: sc->sc_c.sc_link.adapter = &siop_adapter;
! 201: sc->sc_c.sc_link.device = &siop_dev;
! 202: sc->sc_c.sc_link.openings = SIOP_NTAG;
! 203:
! 204: /* Start with one page worth of commands */
! 205: siop_morecbd(sc);
! 206:
! 207: #ifdef SIOP_DEBUG
! 208: printf("%s: script size = %d, PHY addr=0x%x, VIRT=%p\n",
! 209: sc->sc_c.sc_dev.dv_xname, (int)sizeof(siop_script),
! 210: (u_int32_t)sc->sc_c.sc_scriptaddr, sc->sc_c.sc_script);
! 211: #endif
! 212:
! 213: /* Do a bus reset, so that devices fall back to narrow/async */
! 214: siop_resetbus(&sc->sc_c);
! 215: /*
! 216: * siop_reset() will reset the chip, thus clearing pending interrupts
! 217: */
! 218: siop_reset(sc);
! 219: #ifdef DUMP_SCRIPT
! 220: siop_dump_script(sc);
! 221: #endif
! 222:
! 223: bzero(&saa, sizeof(saa));
! 224: saa.saa_sc_link = &sc->sc_c.sc_link;
! 225:
! 226: config_found((struct device*)sc, &saa, scsiprint);
! 227: }
! 228:
! 229: void
! 230: siop_reset(sc)
! 231: struct siop_softc *sc;
! 232: {
! 233: int i, j;
! 234: struct siop_lunsw *lunsw;
! 235:
! 236: siop_common_reset(&sc->sc_c);
! 237:
! 238: /* copy and patch the script */
! 239: if (sc->sc_c.features & SF_CHIP_RAM) {
! 240: bus_space_write_region_4(sc->sc_c.sc_ramt, sc->sc_c.sc_ramh, 0,
! 241: siop_script, sizeof(siop_script) / sizeof(siop_script[0]));
! 242: for (j = 0; j <
! 243: (sizeof(E_abs_msgin_Used) / sizeof(E_abs_msgin_Used[0]));
! 244: j++) {
! 245: bus_space_write_4(sc->sc_c.sc_ramt, sc->sc_c.sc_ramh,
! 246: E_abs_msgin_Used[j] * 4,
! 247: sc->sc_c.sc_scriptaddr + Ent_msgin_space);
! 248: }
! 249: if (sc->sc_c.features & SF_CHIP_LED0) {
! 250: bus_space_write_region_4(sc->sc_c.sc_ramt,
! 251: sc->sc_c.sc_ramh,
! 252: Ent_led_on1, siop_led_on,
! 253: sizeof(siop_led_on) / sizeof(siop_led_on[0]));
! 254: bus_space_write_region_4(sc->sc_c.sc_ramt,
! 255: sc->sc_c.sc_ramh,
! 256: Ent_led_on2, siop_led_on,
! 257: sizeof(siop_led_on) / sizeof(siop_led_on[0]));
! 258: bus_space_write_region_4(sc->sc_c.sc_ramt,
! 259: sc->sc_c.sc_ramh,
! 260: Ent_led_off, siop_led_off,
! 261: sizeof(siop_led_off) / sizeof(siop_led_off[0]));
! 262: }
! 263: } else {
! 264: for (j = 0;
! 265: j < (sizeof(siop_script) / sizeof(siop_script[0])); j++) {
! 266: sc->sc_c.sc_script[j] =
! 267: siop_htoc32(&sc->sc_c, siop_script[j]);
! 268: }
! 269: for (j = 0; j <
! 270: (sizeof(E_abs_msgin_Used) / sizeof(E_abs_msgin_Used[0]));
! 271: j++) {
! 272: sc->sc_c.sc_script[E_abs_msgin_Used[j]] =
! 273: siop_htoc32(&sc->sc_c,
! 274: sc->sc_c.sc_scriptaddr + Ent_msgin_space);
! 275: }
! 276: if (sc->sc_c.features & SF_CHIP_LED0) {
! 277: for (j = 0; j < (sizeof(siop_led_on) /
! 278: sizeof(siop_led_on[0])); j++)
! 279: sc->sc_c.sc_script[
! 280: Ent_led_on1 / sizeof(siop_led_on[0]) + j
! 281: ] = siop_htoc32(&sc->sc_c, siop_led_on[j]);
! 282: for (j = 0; j < (sizeof(siop_led_on) /
! 283: sizeof(siop_led_on[0])); j++)
! 284: sc->sc_c.sc_script[
! 285: Ent_led_on2 / sizeof(siop_led_on[0]) + j
! 286: ] = siop_htoc32(&sc->sc_c, siop_led_on[j]);
! 287: for (j = 0; j < (sizeof(siop_led_off) /
! 288: sizeof(siop_led_off[0])); j++)
! 289: sc->sc_c.sc_script[
! 290: Ent_led_off / sizeof(siop_led_off[0]) + j
! 291: ] = siop_htoc32(&sc->sc_c, siop_led_off[j]);
! 292: }
! 293: }
! 294: sc->script_free_lo = sizeof(siop_script) / sizeof(siop_script[0]);
! 295: sc->script_free_hi = sc->sc_c.ram_size / 4;
! 296: sc->sc_ntargets = 0;
! 297:
! 298: /* free used and unused lun switches */
! 299: while((lunsw = TAILQ_FIRST(&sc->lunsw_list)) != NULL) {
! 300: #ifdef SIOP_DEBUG
! 301: printf("%s: free lunsw at offset %d\n",
! 302: sc->sc_c.sc_dev.dv_xname, lunsw->lunsw_off);
! 303: #endif
! 304: TAILQ_REMOVE(&sc->lunsw_list, lunsw, next);
! 305: free(lunsw, M_DEVBUF);
! 306: }
! 307: TAILQ_INIT(&sc->lunsw_list);
! 308: /* restore reselect switch */
! 309: for (i = 0; i < sc->sc_c.sc_link.adapter_buswidth; i++) {
! 310: struct siop_target *target;
! 311: if (sc->sc_c.targets[i] == NULL)
! 312: continue;
! 313: #ifdef SIOP_DEBUG
! 314: printf("%s: restore sw for target %d\n",
! 315: sc->sc_c.sc_dev.dv_xname, i);
! 316: #endif
! 317: target = (struct siop_target *)sc->sc_c.targets[i];
! 318: free(target->lunsw, M_DEVBUF);
! 319: target->lunsw = siop_get_lunsw(sc);
! 320: if (target->lunsw == NULL) {
! 321: printf("%s: can't alloc lunsw for target %d\n",
! 322: sc->sc_c.sc_dev.dv_xname, i);
! 323: break;
! 324: }
! 325: siop_add_reselsw(sc, i);
! 326: }
! 327:
! 328: /* start script */
! 329: if ((sc->sc_c.features & SF_CHIP_RAM) == 0) {
! 330: bus_dmamap_sync(sc->sc_c.sc_dmat, sc->sc_c.sc_scriptdma, 0,
! 331: PAGE_SIZE, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
! 332: }
! 333: bus_space_write_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSP,
! 334: sc->sc_c.sc_scriptaddr + Ent_reselect);
! 335: }
! 336:
! 337: #if 0
! 338: #define CALL_SCRIPT(ent) do {\
! 339: printf ("start script DSA 0x%lx DSP 0x%lx\n", \
! 340: siop_cmd->cmd_c.dsa, \
! 341: sc->sc_c.sc_scriptaddr + ent); \
! 342: bus_space_write_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSP, sc->sc_c.sc_scriptaddr + ent); \
! 343: } while (0)
! 344: #else
! 345: #define CALL_SCRIPT(ent) do {\
! 346: bus_space_write_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSP, sc->sc_c.sc_scriptaddr + ent); \
! 347: } while (0)
! 348: #endif
! 349:
! 350: int
! 351: siop_intr(v)
! 352: void *v;
! 353: {
! 354: struct siop_softc *sc = v;
! 355: struct siop_target *siop_target;
! 356: struct siop_cmd *siop_cmd;
! 357: struct siop_lun *siop_lun;
! 358: struct scsi_xfer *xs;
! 359: int istat, sist, sstat1, dstat = 0;
! 360: u_int32_t irqcode;
! 361: int need_reset = 0;
! 362: int offset, target, lun, tag;
! 363: bus_addr_t dsa;
! 364: struct siop_cbd *cbdp;
! 365: int freetarget = 0;
! 366: int restart = 0;
! 367:
! 368: istat = bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_ISTAT);
! 369: if ((istat & (ISTAT_INTF | ISTAT_DIP | ISTAT_SIP)) == 0)
! 370: return 0;
! 371: INCSTAT(siop_stat_intr);
! 372: if (istat & ISTAT_INTF) {
! 373: printf("INTRF\n");
! 374: bus_space_write_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
! 375: SIOP_ISTAT, ISTAT_INTF);
! 376: }
! 377: if ((istat &(ISTAT_DIP | ISTAT_SIP | ISTAT_ABRT)) ==
! 378: (ISTAT_DIP | ISTAT_ABRT)) {
! 379: /* clear abort */
! 380: bus_space_write_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
! 381: SIOP_ISTAT, 0);
! 382: }
! 383: /* use DSA to find the current siop_cmd */
! 384: siop_cmd = NULL;
! 385: dsa = bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSA);
! 386: TAILQ_FOREACH(cbdp, &sc->cmds, next) {
! 387: if (dsa >= cbdp->xferdma->dm_segs[0].ds_addr &&
! 388: dsa < cbdp->xferdma->dm_segs[0].ds_addr + PAGE_SIZE) {
! 389: dsa -= cbdp->xferdma->dm_segs[0].ds_addr;
! 390: siop_cmd = &cbdp->cmds[dsa / sizeof(struct siop_xfer)];
! 391: siop_table_sync(siop_cmd,
! 392: BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
! 393: break;
! 394: }
! 395: }
! 396: if (siop_cmd) {
! 397: xs = siop_cmd->cmd_c.xs;
! 398: siop_target = (struct siop_target *)siop_cmd->cmd_c.siop_target;
! 399: target = siop_cmd->cmd_c.xs->sc_link->target;
! 400: lun = siop_cmd->cmd_c.xs->sc_link->lun;
! 401: tag = siop_cmd->cmd_c.tag;
! 402: siop_lun = siop_target->siop_lun[lun];
! 403: #ifdef DIAGNOSTIC
! 404: if (siop_cmd->cmd_c.status != CMDST_ACTIVE &&
! 405: siop_cmd->cmd_c.status != CMDST_SENSE_ACTIVE) {
! 406: printf("siop_cmd (lun %d) for DSA 0x%x "
! 407: "not active (%d)\n", lun, (u_int)dsa,
! 408: siop_cmd->cmd_c.status);
! 409: xs = NULL;
! 410: siop_target = NULL;
! 411: target = -1;
! 412: lun = -1;
! 413: tag = -1;
! 414: siop_lun = NULL;
! 415: siop_cmd = NULL;
! 416: } else if (siop_lun->siop_tag[tag].active != siop_cmd) {
! 417: printf("siop_cmd (lun %d tag %d) not in siop_lun "
! 418: "active (%p != %p)\n", lun, tag, siop_cmd,
! 419: siop_lun->siop_tag[tag].active);
! 420: }
! 421: #endif
! 422: } else {
! 423: xs = NULL;
! 424: siop_target = NULL;
! 425: target = -1;
! 426: lun = -1;
! 427: tag = -1;
! 428: siop_lun = NULL;
! 429: }
! 430: if (istat & ISTAT_DIP) {
! 431: dstat = bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
! 432: SIOP_DSTAT);
! 433: if (dstat & DSTAT_ABRT) {
! 434: /* was probably generated by a bus reset IOCTL */
! 435: if ((dstat & DSTAT_DFE) == 0)
! 436: siop_clearfifo(&sc->sc_c);
! 437: goto reset;
! 438: }
! 439: if (dstat & DSTAT_SSI) {
! 440: printf("single step dsp 0x%08x dsa 0x08%x\n",
! 441: (int)(bus_space_read_4(sc->sc_c.sc_rt,
! 442: sc->sc_c.sc_rh, SIOP_DSP) -
! 443: sc->sc_c.sc_scriptaddr),
! 444: bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
! 445: SIOP_DSA));
! 446: if ((dstat & ~(DSTAT_DFE | DSTAT_SSI)) == 0 &&
! 447: (istat & ISTAT_SIP) == 0) {
! 448: bus_space_write_1(sc->sc_c.sc_rt,
! 449: sc->sc_c.sc_rh, SIOP_DCNTL,
! 450: bus_space_read_1(sc->sc_c.sc_rt,
! 451: sc->sc_c.sc_rh, SIOP_DCNTL) | DCNTL_STD);
! 452: }
! 453: return 1;
! 454: }
! 455:
! 456: if (dstat & ~(DSTAT_SIR | DSTAT_DFE | DSTAT_SSI)) {
! 457: printf("%s: DMA IRQ:", sc->sc_c.sc_dev.dv_xname);
! 458: if (dstat & DSTAT_IID)
! 459: printf(" illegal instruction");
! 460: if (dstat & DSTAT_BF)
! 461: printf(" bus fault");
! 462: if (dstat & DSTAT_MDPE)
! 463: printf(" parity");
! 464: if (dstat & DSTAT_DFE)
! 465: printf(" DMA fifo empty");
! 466: else
! 467: siop_clearfifo(&sc->sc_c);
! 468: printf(", DSP=0x%x DSA=0x%x: ",
! 469: (int)(bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
! 470: SIOP_DSP) - sc->sc_c.sc_scriptaddr),
! 471: bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSA));
! 472: if (siop_cmd)
! 473: printf("last msg_in=0x%x status=0x%x\n",
! 474: siop_cmd->cmd_tables->msg_in[0],
! 475: siop_ctoh32(&sc->sc_c,
! 476: siop_cmd->cmd_tables->status));
! 477: else
! 478: printf("current DSA invalid\n");
! 479: need_reset = 1;
! 480: }
! 481: }
! 482: if (istat & ISTAT_SIP) {
! 483: if (istat & ISTAT_DIP)
! 484: delay(10);
! 485: /*
! 486: * Can't read sist0 & sist1 independently, or we have to
! 487: * insert delay
! 488: */
! 489: sist = bus_space_read_2(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
! 490: SIOP_SIST0);
! 491: sstat1 = bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
! 492: SIOP_SSTAT1);
! 493: #ifdef SIOP_DEBUG_INTR
! 494: printf("scsi interrupt, sist=0x%x sstat1=0x%x "
! 495: "DSA=0x%x DSP=0x%lx\n", sist, sstat1,
! 496: bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSA),
! 497: (u_long)(bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
! 498: SIOP_DSP) -
! 499: sc->sc_c.sc_scriptaddr));
! 500: #endif
! 501: if (sist & SIST0_RST) {
! 502: siop_handle_reset(sc);
! 503: siop_start(sc);
! 504: /* no table to flush here */
! 505: return 1;
! 506: }
! 507: if (sist & SIST0_SGE) {
! 508: if (siop_cmd)
! 509: sc_print_addr(xs->sc_link);
! 510: else
! 511: printf("%s:", sc->sc_c.sc_dev.dv_xname);
! 512: printf("scsi gross error\n");
! 513: goto reset;
! 514: }
! 515: if ((sist & SIST0_MA) && need_reset == 0) {
! 516: if (siop_cmd) {
! 517: int scratcha0;
! 518: /* XXX Why read DSTAT again? */
! 519: dstat = bus_space_read_1(sc->sc_c.sc_rt,
! 520: sc->sc_c.sc_rh, SIOP_DSTAT);
! 521: /*
! 522: * first restore DSA, in case we were in a S/G
! 523: * operation.
! 524: */
! 525: bus_space_write_4(sc->sc_c.sc_rt,
! 526: sc->sc_c.sc_rh,
! 527: SIOP_DSA, siop_cmd->cmd_c.dsa);
! 528: scratcha0 = bus_space_read_1(sc->sc_c.sc_rt,
! 529: sc->sc_c.sc_rh, SIOP_SCRATCHA);
! 530: switch (sstat1 & SSTAT1_PHASE_MASK) {
! 531: case SSTAT1_PHASE_STATUS:
! 532: /*
! 533: * previous phase may be aborted for any reason
! 534: * ( for example, the target has less data to
! 535: * transfer than requested). Compute resid and
! 536: * just go to status, the command should
! 537: * terminate.
! 538: */
! 539: INCSTAT(siop_stat_intr_shortxfer);
! 540: if (scratcha0 & A_flag_data)
! 541: siop_ma(&siop_cmd->cmd_c);
! 542: else if ((dstat & DSTAT_DFE) == 0)
! 543: siop_clearfifo(&sc->sc_c);
! 544: CALL_SCRIPT(Ent_status);
! 545: return 1;
! 546: case SSTAT1_PHASE_MSGIN:
! 547: /*
! 548: * target may be ready to disconnect
! 549: * Compute resid which would be used later
! 550: * if a save data pointer is needed.
! 551: */
! 552: INCSTAT(siop_stat_intr_xferdisc);
! 553: if (scratcha0 & A_flag_data)
! 554: siop_ma(&siop_cmd->cmd_c);
! 555: else if ((dstat & DSTAT_DFE) == 0)
! 556: siop_clearfifo(&sc->sc_c);
! 557: bus_space_write_1(sc->sc_c.sc_rt,
! 558: sc->sc_c.sc_rh, SIOP_SCRATCHA,
! 559: scratcha0 & ~A_flag_data);
! 560: CALL_SCRIPT(Ent_msgin);
! 561: return 1;
! 562: }
! 563: printf("%s: unexpected phase mismatch %d\n",
! 564: sc->sc_c.sc_dev.dv_xname,
! 565: sstat1 & SSTAT1_PHASE_MASK);
! 566: } else {
! 567: printf("%s: phase mismatch without command\n",
! 568: sc->sc_c.sc_dev.dv_xname);
! 569: }
! 570: need_reset = 1;
! 571: }
! 572: if (sist & SIST0_PAR) {
! 573: /* parity error, reset */
! 574: if (siop_cmd)
! 575: sc_print_addr(xs->sc_link);
! 576: else
! 577: printf("%s:", sc->sc_c.sc_dev.dv_xname);
! 578: printf("parity error\n");
! 579: goto reset;
! 580: }
! 581: if ((sist & (SIST1_STO << 8)) && need_reset == 0) {
! 582: /* selection time out, assume there's no device here */
! 583: if (siop_cmd) {
! 584: siop_cmd->cmd_c.status = CMDST_DONE;
! 585: xs->error = XS_SELTIMEOUT;
! 586: freetarget = 1;
! 587: goto end;
! 588: } else {
! 589: printf("%s: selection timeout without "
! 590: "command\n", sc->sc_c.sc_dev.dv_xname);
! 591: need_reset = 1;
! 592: }
! 593: }
! 594: if (sist & SIST0_UDC) {
! 595: /*
! 596: * unexpected disconnect. Usually the target signals
! 597: * a fatal condition this way. Attempt to get sense.
! 598: */
! 599: if (siop_cmd) {
! 600: siop_cmd->cmd_tables->status =
! 601: siop_htoc32(&sc->sc_c, SCSI_CHECK);
! 602: goto end;
! 603: }
! 604: printf("%s: unexpected disconnect without "
! 605: "command\n", sc->sc_c.sc_dev.dv_xname);
! 606: goto reset;
! 607: }
! 608: if (sist & (SIST1_SBMC << 8)) {
! 609: /* SCSI bus mode change */
! 610: if (siop_modechange(&sc->sc_c) == 0 || need_reset == 1)
! 611: goto reset;
! 612: if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) {
! 613: /*
! 614: * we have a script interrupt, it will
! 615: * restart the script.
! 616: */
! 617: goto scintr;
! 618: }
! 619: /*
! 620: * else we have to restart it ourselve, at the
! 621: * interrupted instruction.
! 622: */
! 623: bus_space_write_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
! 624: SIOP_DSP,
! 625: bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
! 626: SIOP_DSP) - 8);
! 627: return 1;
! 628: }
! 629: /* Else it's an unhandled exception (for now). */
! 630: printf("%s: unhandled scsi interrupt, sist=0x%x sstat1=0x%x "
! 631: "DSA=0x%x DSP=0x%x\n", sc->sc_c.sc_dev.dv_xname,
! 632: sist, sstat1,
! 633: bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSA),
! 634: (int)(bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
! 635: SIOP_DSP) - sc->sc_c.sc_scriptaddr));
! 636: if (siop_cmd) {
! 637: siop_cmd->cmd_c.status = CMDST_DONE;
! 638: xs->error = XS_SELTIMEOUT;
! 639: goto end;
! 640: }
! 641: need_reset = 1;
! 642: }
! 643: if (need_reset) {
! 644: reset:
! 645: /* fatal error, reset the bus */
! 646: siop_resetbus(&sc->sc_c);
! 647: /* no table to flush here */
! 648: return 1;
! 649: }
! 650:
! 651: scintr:
! 652: if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) { /* script interrupt */
! 653: irqcode = bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
! 654: SIOP_DSPS);
! 655: #ifdef SIOP_DEBUG_INTR
! 656: printf("script interrupt 0x%x\n", irqcode);
! 657: #endif
! 658: /*
! 659: * no command, or an inactive command is only valid for a
! 660: * reselect interrupt
! 661: */
! 662: if ((irqcode & 0x80) == 0) {
! 663: if (siop_cmd == NULL) {
! 664: printf(
! 665: "%s: script interrupt (0x%x) with invalid DSA !!!\n",
! 666: sc->sc_c.sc_dev.dv_xname, irqcode);
! 667: goto reset;
! 668: }
! 669: if (siop_cmd->cmd_c.status != CMDST_ACTIVE &&
! 670: siop_cmd->cmd_c.status != CMDST_SENSE_ACTIVE) {
! 671: printf("%s: command with invalid status "
! 672: "(IRQ code 0x%x current status %d) !\n",
! 673: sc->sc_c.sc_dev.dv_xname,
! 674: irqcode, siop_cmd->cmd_c.status);
! 675: xs = NULL;
! 676: }
! 677: }
! 678: switch(irqcode) {
! 679: case A_int_err:
! 680: printf("error, DSP=0x%x\n",
! 681: (int)(bus_space_read_4(sc->sc_c.sc_rt,
! 682: sc->sc_c.sc_rh, SIOP_DSP) - sc->sc_c.sc_scriptaddr));
! 683: if (xs) {
! 684: xs->error = XS_SELTIMEOUT;
! 685: goto end;
! 686: } else {
! 687: goto reset;
! 688: }
! 689: case A_int_reseltarg:
! 690: printf("%s: reselect with invalid target\n",
! 691: sc->sc_c.sc_dev.dv_xname);
! 692: goto reset;
! 693: case A_int_resellun:
! 694: INCSTAT(siop_stat_intr_lunresel);
! 695: target = bus_space_read_1(sc->sc_c.sc_rt,
! 696: sc->sc_c.sc_rh, SIOP_SCRATCHA) & 0xf;
! 697: lun = bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
! 698: SIOP_SCRATCHA + 1);
! 699: tag = bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
! 700: SIOP_SCRATCHA + 2);
! 701: siop_target =
! 702: (struct siop_target *)sc->sc_c.targets[target];
! 703: if (siop_target == NULL) {
! 704: printf("%s: reselect with invalid target %d\n",
! 705: sc->sc_c.sc_dev.dv_xname, target);
! 706: goto reset;
! 707: }
! 708: siop_lun = siop_target->siop_lun[lun];
! 709: if (siop_lun == NULL) {
! 710: printf("%s: target %d reselect with invalid "
! 711: "lun %d\n", sc->sc_c.sc_dev.dv_xname,
! 712: target, lun);
! 713: goto reset;
! 714: }
! 715: if (siop_lun->siop_tag[tag].active == NULL) {
! 716: printf("%s: target %d lun %d tag %d reselect "
! 717: "without command\n",
! 718: sc->sc_c.sc_dev.dv_xname,
! 719: target, lun, tag);
! 720: goto reset;
! 721: }
! 722: siop_cmd = siop_lun->siop_tag[tag].active;
! 723: bus_space_write_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
! 724: SIOP_DSP, siop_cmd->cmd_c.dsa +
! 725: sizeof(struct siop_common_xfer) +
! 726: Ent_ldsa_reload_dsa);
! 727: siop_table_sync(siop_cmd, BUS_DMASYNC_PREWRITE);
! 728: return 1;
! 729: case A_int_reseltag:
! 730: printf("%s: reselect with invalid tag\n",
! 731: sc->sc_c.sc_dev.dv_xname);
! 732: goto reset;
! 733: case A_int_msgin:
! 734: {
! 735: int msgin = bus_space_read_1(sc->sc_c.sc_rt,
! 736: sc->sc_c.sc_rh, SIOP_SFBR);
! 737: if (msgin == MSG_MESSAGE_REJECT) {
! 738: int msg, extmsg;
! 739: if (siop_cmd->cmd_tables->msg_out[0] & 0x80) {
! 740: /*
! 741: * message was part of a identify +
! 742: * something else. Identify shouldn't
! 743: * have been rejected.
! 744: */
! 745: msg =
! 746: siop_cmd->cmd_tables->msg_out[1];
! 747: extmsg =
! 748: siop_cmd->cmd_tables->msg_out[3];
! 749: } else {
! 750: msg = siop_cmd->cmd_tables->msg_out[0];
! 751: extmsg =
! 752: siop_cmd->cmd_tables->msg_out[2];
! 753: }
! 754: if (msg == MSG_MESSAGE_REJECT) {
! 755: /* MSG_REJECT for a MSG_REJECT !*/
! 756: if (xs)
! 757: sc_print_addr(xs->sc_link);
! 758: else
! 759: printf("%s: ",
! 760: sc->sc_c.sc_dev.dv_xname);
! 761: printf("our reject message was "
! 762: "rejected\n");
! 763: goto reset;
! 764: }
! 765: if (msg == MSG_EXTENDED &&
! 766: extmsg == MSG_EXT_WDTR) {
! 767: /* WDTR rejected, initiate sync */
! 768: if ((siop_target->target_c.flags &
! 769: TARF_SYNC) == 0) {
! 770: siop_target->target_c.status =
! 771: TARST_OK;
! 772: siop_update_xfer_mode(&sc->sc_c,
! 773: target);
! 774: /* no table to flush here */
! 775: CALL_SCRIPT(Ent_msgin_ack);
! 776: return 1;
! 777: }
! 778: siop_target->target_c.status =
! 779: TARST_SYNC_NEG;
! 780: siop_sdtr_msg(&siop_cmd->cmd_c, 0,
! 781: sc->sc_c.st_minsync,
! 782: sc->sc_c.maxoff);
! 783: siop_table_sync(siop_cmd,
! 784: BUS_DMASYNC_PREREAD |
! 785: BUS_DMASYNC_PREWRITE);
! 786: CALL_SCRIPT(Ent_send_msgout);
! 787: return 1;
! 788: } else if (msg == MSG_EXTENDED &&
! 789: extmsg == MSG_EXT_SDTR) {
! 790: /* sync rejected */
! 791: siop_target->target_c.offset = 0;
! 792: siop_target->target_c.period = 0;
! 793: siop_target->target_c.status = TARST_OK;
! 794: siop_update_xfer_mode(&sc->sc_c,
! 795: target);
! 796: /* no table to flush here */
! 797: CALL_SCRIPT(Ent_msgin_ack);
! 798: return 1;
! 799: } else if (msg == MSG_EXTENDED &&
! 800: extmsg == MSG_EXT_PPR) {
! 801: /* PPR negotiation rejected */
! 802: siop_target->target_c.offset = 0;
! 803: siop_target->target_c.period = 0;
! 804: siop_target->target_c.status = TARST_ASYNC;
! 805: siop_target->target_c.flags &= ~(TARF_DT | TARF_ISDT);
! 806: CALL_SCRIPT(Ent_msgin_ack);
! 807: return 1;
! 808: } else if (msg == MSG_SIMPLE_Q_TAG ||
! 809: msg == MSG_HEAD_OF_Q_TAG ||
! 810: msg == MSG_ORDERED_Q_TAG) {
! 811: if (siop_handle_qtag_reject(
! 812: siop_cmd) == -1)
! 813: goto reset;
! 814: CALL_SCRIPT(Ent_msgin_ack);
! 815: return 1;
! 816: }
! 817: if (xs)
! 818: sc_print_addr(xs->sc_link);
! 819: else
! 820: printf("%s: ",
! 821: sc->sc_c.sc_dev.dv_xname);
! 822: if (msg == MSG_EXTENDED) {
! 823: printf("scsi message reject, extended "
! 824: "message sent was 0x%x\n", extmsg);
! 825: } else {
! 826: printf("scsi message reject, message "
! 827: "sent was 0x%x\n", msg);
! 828: }
! 829: /* no table to flush here */
! 830: CALL_SCRIPT(Ent_msgin_ack);
! 831: return 1;
! 832: }
! 833: if (msgin == MSG_IGN_WIDE_RESIDUE) {
! 834: /* use the extmsgdata table to get the second byte */
! 835: siop_cmd->cmd_tables->t_extmsgdata.count =
! 836: siop_htoc32(&sc->sc_c, 1);
! 837: siop_table_sync(siop_cmd,
! 838: BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
! 839: CALL_SCRIPT(Ent_get_extmsgdata);
! 840: return 1;
! 841: }
! 842: if (xs)
! 843: sc_print_addr(xs->sc_link);
! 844: else
! 845: printf("%s: ", sc->sc_c.sc_dev.dv_xname);
! 846: printf("unhandled message 0x%x\n",
! 847: siop_cmd->cmd_tables->msg_in[0]);
! 848: siop_cmd->cmd_tables->msg_out[0] = MSG_MESSAGE_REJECT;
! 849: siop_cmd->cmd_tables->t_msgout.count =
! 850: siop_htoc32(&sc->sc_c, 1);
! 851: siop_table_sync(siop_cmd,
! 852: BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
! 853: CALL_SCRIPT(Ent_send_msgout);
! 854: return 1;
! 855: }
! 856: case A_int_extmsgin:
! 857: #ifdef SIOP_DEBUG_INTR
! 858: printf("extended message: msg 0x%x len %d\n",
! 859: siop_cmd->cmd_tables->msg_in[2],
! 860: siop_cmd->cmd_tables->msg_in[1]);
! 861: #endif
! 862: if (siop_cmd->cmd_tables->msg_in[1] >
! 863: sizeof(siop_cmd->cmd_tables->msg_in) - 2)
! 864: printf("%s: extended message too big (%d)\n",
! 865: sc->sc_c.sc_dev.dv_xname,
! 866: siop_cmd->cmd_tables->msg_in[1]);
! 867: siop_cmd->cmd_tables->t_extmsgdata.count =
! 868: siop_htoc32(&sc->sc_c,
! 869: siop_cmd->cmd_tables->msg_in[1] - 1);
! 870: siop_table_sync(siop_cmd,
! 871: BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
! 872: CALL_SCRIPT(Ent_get_extmsgdata);
! 873: return 1;
! 874: case A_int_extmsgdata:
! 875: #ifdef SIOP_DEBUG_INTR
! 876: {
! 877: int i;
! 878: printf("extended message: 0x%x, data:",
! 879: siop_cmd->cmd_tables->msg_in[2]);
! 880: for (i = 3; i < 2 + siop_cmd->cmd_tables->msg_in[1];
! 881: i++)
! 882: printf(" 0x%x",
! 883: siop_cmd->cmd_tables->msg_in[i]);
! 884: printf("\n");
! 885: }
! 886: #endif
! 887: if (siop_cmd->cmd_tables->msg_in[0] ==
! 888: MSG_IGN_WIDE_RESIDUE) {
! 889: /* we got the second byte of MSG_IGN_WIDE_RESIDUE */
! 890: if (siop_cmd->cmd_tables->msg_in[3] != 1)
! 891: printf("MSG_IGN_WIDE_RESIDUE: "
! 892: "bad len %d\n",
! 893: siop_cmd->cmd_tables->msg_in[3]);
! 894: switch (siop_iwr(&siop_cmd->cmd_c)) {
! 895: case SIOP_NEG_MSGOUT:
! 896: siop_table_sync(siop_cmd,
! 897: BUS_DMASYNC_PREREAD |
! 898: BUS_DMASYNC_PREWRITE);
! 899: CALL_SCRIPT(Ent_send_msgout);
! 900: return(1);
! 901: case SIOP_NEG_ACK:
! 902: CALL_SCRIPT(Ent_msgin_ack);
! 903: return(1);
! 904: default:
! 905: panic("invalid retval from "
! 906: "siop_iwr()");
! 907: }
! 908: return(1);
! 909: }
! 910: if (siop_cmd->cmd_tables->msg_in[2] == MSG_EXT_WDTR) {
! 911: switch (siop_wdtr_neg(&siop_cmd->cmd_c)) {
! 912: case SIOP_NEG_MSGOUT:
! 913: siop_update_scntl3(sc,
! 914: siop_cmd->cmd_c.siop_target);
! 915: siop_table_sync(siop_cmd,
! 916: BUS_DMASYNC_PREREAD |
! 917: BUS_DMASYNC_PREWRITE);
! 918: CALL_SCRIPT(Ent_send_msgout);
! 919: return(1);
! 920: case SIOP_NEG_ACK:
! 921: siop_update_scntl3(sc,
! 922: siop_cmd->cmd_c.siop_target);
! 923: CALL_SCRIPT(Ent_msgin_ack);
! 924: return(1);
! 925: default:
! 926: panic("invalid retval from "
! 927: "siop_wdtr_neg()");
! 928: }
! 929: return(1);
! 930: }
! 931: if (siop_cmd->cmd_tables->msg_in[2] == MSG_EXT_SDTR) {
! 932: switch (siop_sdtr_neg(&siop_cmd->cmd_c)) {
! 933: case SIOP_NEG_MSGOUT:
! 934: siop_update_scntl3(sc,
! 935: siop_cmd->cmd_c.siop_target);
! 936: siop_table_sync(siop_cmd,
! 937: BUS_DMASYNC_PREREAD |
! 938: BUS_DMASYNC_PREWRITE);
! 939: CALL_SCRIPT(Ent_send_msgout);
! 940: return(1);
! 941: case SIOP_NEG_ACK:
! 942: siop_update_scntl3(sc,
! 943: siop_cmd->cmd_c.siop_target);
! 944: CALL_SCRIPT(Ent_msgin_ack);
! 945: return(1);
! 946: default:
! 947: panic("invalid retval from "
! 948: "siop_sdtr_neg()");
! 949: }
! 950: return(1);
! 951: }
! 952: if (siop_cmd->cmd_tables->msg_in[2] == MSG_EXT_PPR) {
! 953: switch (siop_ppr_neg(&siop_cmd->cmd_c)) {
! 954: case SIOP_NEG_MSGOUT:
! 955: siop_update_scntl3(sc,
! 956: siop_cmd->cmd_c.siop_target);
! 957: siop_table_sync(siop_cmd,
! 958: BUS_DMASYNC_PREREAD |
! 959: BUS_DMASYNC_PREWRITE);
! 960: CALL_SCRIPT(Ent_send_msgout);
! 961: return(1);
! 962: case SIOP_NEG_ACK:
! 963: siop_update_scntl3(sc,
! 964: siop_cmd->cmd_c.siop_target);
! 965: CALL_SCRIPT(Ent_msgin_ack);
! 966: return(1);
! 967: default:
! 968: panic("invalid retval from "
! 969: "siop_wdtr_neg()");
! 970: }
! 971: return(1);
! 972: }
! 973: /* send a message reject */
! 974: siop_cmd->cmd_tables->msg_out[0] = MSG_MESSAGE_REJECT;
! 975: siop_cmd->cmd_tables->t_msgout.count =
! 976: siop_htoc32(&sc->sc_c, 1);
! 977: siop_table_sync(siop_cmd,
! 978: BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
! 979: CALL_SCRIPT(Ent_send_msgout);
! 980: return 1;
! 981: case A_int_disc:
! 982: INCSTAT(siop_stat_intr_sdp);
! 983: offset = bus_space_read_1(sc->sc_c.sc_rt,
! 984: sc->sc_c.sc_rh, SIOP_SCRATCHA + 1);
! 985: #ifdef SIOP_DEBUG_DR
! 986: printf("disconnect offset %d\n", offset);
! 987: #endif
! 988: siop_sdp(&siop_cmd->cmd_c, offset);
! 989: /* we start again with no offset */
! 990: siop_cmd->saved_offset = SIOP_NOOFFSET;
! 991: siop_table_sync(siop_cmd,
! 992: BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
! 993: CALL_SCRIPT(Ent_script_sched);
! 994: return 1;
! 995: case A_int_saveoffset:
! 996: INCSTAT(siop_stat_intr_saveoffset);
! 997: offset = bus_space_read_1(sc->sc_c.sc_rt,
! 998: sc->sc_c.sc_rh, SIOP_SCRATCHA + 1);
! 999: #ifdef SIOP_DEBUG_DR
! 1000: printf("saveoffset offset %d\n", offset);
! 1001: #endif
! 1002: siop_cmd->saved_offset = offset;
! 1003: CALL_SCRIPT(Ent_script_sched);
! 1004: return 1;
! 1005: case A_int_resfail:
! 1006: printf("reselect failed\n");
! 1007: /* check if we can put some command in scheduler */
! 1008: siop_start(sc);
! 1009: CALL_SCRIPT(Ent_script_sched);
! 1010: return 1;
! 1011: case A_int_done:
! 1012: if (xs == NULL) {
! 1013: printf("%s: done without command, DSA=0x%lx\n",
! 1014: sc->sc_c.sc_dev.dv_xname,
! 1015: (u_long)siop_cmd->cmd_c.dsa);
! 1016: siop_cmd->cmd_c.status = CMDST_FREE;
! 1017: siop_start(sc);
! 1018: CALL_SCRIPT(Ent_script_sched);
! 1019: return 1;
! 1020: }
! 1021: #ifdef SIOP_DEBUG_INTR
! 1022: printf("done, DSA=0x%lx target id 0x%x last msg "
! 1023: "in=0x%x status=0x%x\n", (u_long)siop_cmd->cmd_c.dsa,
! 1024: siop_ctoh32(&sc->sc_c, siop_cmd->cmd_tables->id),
! 1025: siop_cmd->cmd_tables->msg_in[0],
! 1026: siop_ctoh32(&sc->sc_c,
! 1027: siop_cmd->cmd_tables->status));
! 1028: #endif
! 1029: INCSTAT(siop_stat_intr_done);
! 1030: /* update resid. */
! 1031: offset = bus_space_read_1(sc->sc_c.sc_rt,
! 1032: sc->sc_c.sc_rh, SIOP_SCRATCHA + 1);
! 1033: /*
! 1034: * if we got a disconnect between the last data phase
! 1035: * and the status phase, offset will be 0. In this
! 1036: * case, siop_cmd->saved_offset will have the proper
! 1037: * value if it got updated by the controller
! 1038: */
! 1039: if (offset == 0 &&
! 1040: siop_cmd->saved_offset != SIOP_NOOFFSET)
! 1041: offset = siop_cmd->saved_offset;
! 1042: siop_update_resid(&siop_cmd->cmd_c, offset);
! 1043: if (siop_cmd->cmd_c.status == CMDST_SENSE_ACTIVE)
! 1044: siop_cmd->cmd_c.status = CMDST_SENSE_DONE;
! 1045: else
! 1046: siop_cmd->cmd_c.status = CMDST_DONE;
! 1047: goto end;
! 1048: default:
! 1049: printf("unknown irqcode %x\n", irqcode);
! 1050: if (xs) {
! 1051: xs->error = XS_SELTIMEOUT;
! 1052: goto end;
! 1053: }
! 1054: goto reset;
! 1055: }
! 1056: return 1;
! 1057: }
! 1058: /* We can get here if ISTAT_DIP and DSTAT_DFE are the only bits set. */
! 1059: /* But that *SHOULDN'T* happen. It does on powerpc (at least). */
! 1060: printf("%s: siop_intr() - we should not be here!\n"
! 1061: " istat = 0x%x, dstat = 0x%x, sist = 0x%x, sstat1 = 0x%x\n"
! 1062: " need_reset = %x, irqcode = %x, siop_cmd %s\n",
! 1063: sc->sc_c.sc_dev.dv_xname,
! 1064: istat, dstat, sist, sstat1, need_reset, irqcode,
! 1065: (siop_cmd == NULL) ? "== NULL" : "!= NULL");
! 1066: goto reset; /* Where we should have gone in the first place! */
! 1067: end:
! 1068: /*
! 1069: * restart the script now if command completed properly
! 1070: * Otherwise wait for siop_scsicmd_end(), we may need to cleanup the
! 1071: * queue
! 1072: */
! 1073: xs->status = siop_ctoh32(&sc->sc_c, siop_cmd->cmd_tables->status);
! 1074: if (xs->status == SCSI_OK)
! 1075: CALL_SCRIPT(Ent_script_sched);
! 1076: else
! 1077: restart = 1;
! 1078: siop_lun->siop_tag[tag].active = NULL;
! 1079: siop_scsicmd_end(siop_cmd);
! 1080: if (freetarget && siop_target->target_c.status == TARST_PROBING)
! 1081: siop_del_dev(sc, target, lun);
! 1082: siop_start(sc);
! 1083: if (restart)
! 1084: CALL_SCRIPT(Ent_script_sched);
! 1085: return 1;
! 1086: }
! 1087:
! 1088: void
! 1089: siop_scsicmd_end(siop_cmd)
! 1090: struct siop_cmd *siop_cmd;
! 1091: {
! 1092: struct scsi_xfer *xs = siop_cmd->cmd_c.xs;
! 1093: struct siop_softc *sc = (struct siop_softc *)siop_cmd->cmd_c.siop_sc;
! 1094: struct siop_lun *siop_lun =
! 1095: ((struct siop_target*)sc->sc_c.targets[xs->sc_link->target])->siop_lun[xs->sc_link->lun];
! 1096:
! 1097: /*
! 1098: * If the command is re-queued (SENSE, QUEUE_FULL) it
! 1099: * must get a new timeout, so delete existing timeout now.
! 1100: */
! 1101: timeout_del(&siop_cmd->cmd_c.xs->stimeout);
! 1102:
! 1103: switch(xs->status) {
! 1104: case SCSI_OK:
! 1105: xs->error = (siop_cmd->cmd_c.status == CMDST_DONE) ?
! 1106: XS_NOERROR : XS_SENSE;
! 1107: break;
! 1108: case SCSI_BUSY:
! 1109: xs->error = XS_BUSY;
! 1110: break;
! 1111: case SCSI_CHECK:
! 1112: if (siop_cmd->cmd_c.status == CMDST_SENSE_DONE) {
! 1113: /* request sense on a request sense ? */
! 1114: printf("%s: request sense failed\n",
! 1115: sc->sc_c.sc_dev.dv_xname);
! 1116: xs->error = XS_DRIVER_STUFFUP;
! 1117: } else {
! 1118: siop_cmd->cmd_c.status = CMDST_SENSE;
! 1119: }
! 1120: break;
! 1121: case SCSI_QUEUE_FULL:
! 1122: /*
! 1123: * Device didn't queue the command. We have to retry
! 1124: * it. We insert it into the urgent list, hoping to
! 1125: * preserve order. But unfortunately, commands already
! 1126: * in the scheduler may be accepted before this one.
! 1127: * Also remember the condition, to avoid starting new
! 1128: * commands for this device before one is done.
! 1129: */
! 1130: INCSTAT(siop_stat_intr_qfull);
! 1131: #ifdef SIOP_DEBUG
! 1132: printf("%s:%d:%d: queue full (tag %d)\n", sc->sc_c.sc_dev.dv_xname,
! 1133: xs->sc_link->target,
! 1134: xs->sc_link->lun, siop_cmd->cmd_c.tag);
! 1135: #endif
! 1136: siop_lun->lun_flags |= SIOP_LUNF_FULL;
! 1137: siop_cmd->cmd_c.status = CMDST_READY;
! 1138: siop_setuptables(&siop_cmd->cmd_c);
! 1139: siop_table_sync(siop_cmd, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
! 1140: TAILQ_INSERT_TAIL(&sc->urgent_list, siop_cmd, next);
! 1141: return;
! 1142: case SCSI_SIOP_NOCHECK:
! 1143: /*
! 1144: * don't check status, xs->error is already valid
! 1145: */
! 1146: break;
! 1147: case SCSI_SIOP_NOSTATUS:
! 1148: /*
! 1149: * the status byte was not updated, cmd was
! 1150: * aborted
! 1151: */
! 1152: xs->error = XS_SELTIMEOUT;
! 1153: break;
! 1154: default:
! 1155: xs->error = XS_DRIVER_STUFFUP;
! 1156: }
! 1157: if (siop_cmd->cmd_c.status != CMDST_SENSE_DONE &&
! 1158: xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
! 1159: bus_dmamap_sync(sc->sc_c.sc_dmat, siop_cmd->cmd_c.dmamap_data, 0,
! 1160: siop_cmd->cmd_c.dmamap_data->dm_mapsize,
! 1161: (xs->flags & SCSI_DATA_IN) ?
! 1162: BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
! 1163: bus_dmamap_unload(sc->sc_c.sc_dmat, siop_cmd->cmd_c.dmamap_data);
! 1164: }
! 1165: if (siop_cmd->cmd_c.status == CMDST_SENSE) {
! 1166: /* issue a request sense for this target */
! 1167: struct scsi_sense *cmd = (struct scsi_sense *)&siop_cmd->cmd_c.siop_tables->xscmd;
! 1168: int error;
! 1169: bzero(cmd, sizeof(*cmd));
! 1170: siop_cmd->cmd_c.siop_tables->cmd.count =
! 1171: siop_htoc32(&sc->sc_c, sizeof(struct scsi_sense));
! 1172: cmd->opcode = REQUEST_SENSE;
! 1173: cmd->byte2 = xs->sc_link->lun << 5;
! 1174: cmd->unused[0] = cmd->unused[1] = 0;
! 1175: cmd->length = sizeof(struct scsi_sense_data);
! 1176: cmd->control = 0;
! 1177: siop_cmd->cmd_c.flags &= ~CMDFL_TAG;
! 1178: error = bus_dmamap_load(sc->sc_c.sc_dmat, siop_cmd->cmd_c.dmamap_data,
! 1179: &xs->sense, sizeof(struct scsi_sense_data),
! 1180: NULL, BUS_DMA_NOWAIT);
! 1181: if (error) {
! 1182: printf("%s: unable to load data DMA map "
! 1183: "(for SENSE): %d\n",
! 1184: sc->sc_c.sc_dev.dv_xname, error);
! 1185: xs->error = XS_DRIVER_STUFFUP;
! 1186: goto out;
! 1187: }
! 1188: bus_dmamap_sync(sc->sc_c.sc_dmat, siop_cmd->cmd_c.dmamap_data,
! 1189: 0, siop_cmd->cmd_c.dmamap_data->dm_mapsize,
! 1190: BUS_DMASYNC_PREREAD);
! 1191:
! 1192: siop_setuptables(&siop_cmd->cmd_c);
! 1193: siop_table_sync(siop_cmd, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
! 1194: /* arrange for the cmd to be handled now */
! 1195: TAILQ_INSERT_HEAD(&sc->urgent_list, siop_cmd, next);
! 1196: return;
! 1197: } else if (siop_cmd->cmd_c.status == CMDST_SENSE_DONE) {
! 1198: bus_dmamap_sync(sc->sc_c.sc_dmat, siop_cmd->cmd_c.dmamap_data,
! 1199: 0, siop_cmd->cmd_c.dmamap_data->dm_mapsize,
! 1200: BUS_DMASYNC_POSTREAD);
! 1201: bus_dmamap_unload(sc->sc_c.sc_dmat, siop_cmd->cmd_c.dmamap_data);
! 1202: }
! 1203: out:
! 1204: siop_lun->lun_flags &= ~SIOP_LUNF_FULL;
! 1205: xs->flags |= ITSDONE;
! 1206: siop_cmd->cmd_c.status = CMDST_FREE;
! 1207: TAILQ_INSERT_TAIL(&sc->free_list, siop_cmd, next);
! 1208: #if 0
! 1209: if (xs->resid != 0)
! 1210: printf("resid %d datalen %d\n", xs->resid, xs->datalen);
! 1211: #endif
! 1212: scsi_done(xs);
! 1213: }
! 1214:
! 1215: /*
! 1216: * handle a rejected queue tag message: the command will run untagged,
! 1217: * has to adjust the reselect script.
! 1218: */
! 1219: int
! 1220: siop_handle_qtag_reject(siop_cmd)
! 1221: struct siop_cmd *siop_cmd;
! 1222: {
! 1223: struct siop_softc *sc = (struct siop_softc *)siop_cmd->cmd_c.siop_sc;
! 1224: int target = siop_cmd->cmd_c.xs->sc_link->target;
! 1225: int lun = siop_cmd->cmd_c.xs->sc_link->lun;
! 1226: int tag = siop_cmd->cmd_tables->msg_out[2];
! 1227: struct siop_lun *siop_lun =
! 1228: ((struct siop_target*)sc->sc_c.targets[target])->siop_lun[lun];
! 1229:
! 1230: #ifdef SIOP_DEBUG
! 1231: printf("%s:%d:%d: tag message %d (%d) rejected (status %d)\n",
! 1232: sc->sc_c.sc_dev.dv_xname, target, lun, tag, siop_cmd->cmd_c.tag,
! 1233: siop_cmd->cmd_c.status);
! 1234: #endif
! 1235:
! 1236: if (siop_lun->siop_tag[0].active != NULL) {
! 1237: printf("%s: untagged command already running for target %d "
! 1238: "lun %d (status %d)\n", sc->sc_c.sc_dev.dv_xname,
! 1239: target, lun, siop_lun->siop_tag[0].active->cmd_c.status);
! 1240: return -1;
! 1241: }
! 1242: /* clear tag slot */
! 1243: siop_lun->siop_tag[tag].active = NULL;
! 1244: /* add command to non-tagged slot */
! 1245: siop_lun->siop_tag[0].active = siop_cmd;
! 1246: siop_cmd->cmd_c.tag = 0;
! 1247: /* adjust reselect script if there is one */
! 1248: if (siop_lun->siop_tag[0].reseloff > 0) {
! 1249: siop_script_write(sc,
! 1250: siop_lun->siop_tag[0].reseloff + 1,
! 1251: siop_cmd->cmd_c.dsa + sizeof(struct siop_common_xfer) +
! 1252: Ent_ldsa_reload_dsa);
! 1253: siop_table_sync(siop_cmd, BUS_DMASYNC_PREWRITE);
! 1254: }
! 1255: return 0;
! 1256: }
! 1257:
! 1258: /*
! 1259: * handle a bus reset: reset chip, unqueue all active commands, free all
! 1260: * target struct and report lossage to upper layer.
! 1261: * As the upper layer may requeue immediately we have to first store
! 1262: * all active commands in a temporary queue.
! 1263: */
! 1264: void
! 1265: siop_handle_reset(sc)
! 1266: struct siop_softc *sc;
! 1267: {
! 1268: struct cmd_list reset_list;
! 1269: struct siop_cmd *siop_cmd, *next_siop_cmd;
! 1270: struct siop_lun *siop_lun;
! 1271: int target, lun, tag;
! 1272: /*
! 1273: * scsi bus reset. reset the chip and restart
! 1274: * the queue. Need to clean up all active commands
! 1275: */
! 1276: printf("%s: scsi bus reset\n", sc->sc_c.sc_dev.dv_xname);
! 1277: /* stop, reset and restart the chip */
! 1278: siop_reset(sc);
! 1279: TAILQ_INIT(&reset_list);
! 1280: /*
! 1281: * Process all commands: first commands being executed
! 1282: */
! 1283: for (target = 0; target < sc->sc_c.sc_link.adapter_buswidth;
! 1284: target++) {
! 1285: if (sc->sc_c.targets[target] == NULL)
! 1286: continue;
! 1287: for (lun = 0; lun < 8; lun++) {
! 1288: struct siop_target *siop_target =
! 1289: (struct siop_target *)sc->sc_c.targets[target];
! 1290: siop_lun = siop_target->siop_lun[lun];
! 1291: if (siop_lun == NULL)
! 1292: continue;
! 1293: siop_lun->lun_flags &= ~SIOP_LUNF_FULL;
! 1294: for (tag = 0; tag <
! 1295: ((sc->sc_c.targets[target]->flags & TARF_TAG) ?
! 1296: SIOP_NTAG : 1);
! 1297: tag++) {
! 1298: siop_cmd = siop_lun->siop_tag[tag].active;
! 1299: if (siop_cmd == NULL)
! 1300: continue;
! 1301: siop_lun->siop_tag[tag].active = NULL;
! 1302: TAILQ_INSERT_TAIL(&reset_list, siop_cmd, next);
! 1303: sc_print_addr(siop_cmd->cmd_c.xs->sc_link);
! 1304: printf("cmd %p (tag %d) added to reset list\n",
! 1305: siop_cmd, tag);
! 1306: }
! 1307: }
! 1308: if (sc->sc_c.targets[target]->status != TARST_PROBING) {
! 1309: sc->sc_c.targets[target]->status = TARST_ASYNC;
! 1310: sc->sc_c.targets[target]->flags &= ~TARF_ISWIDE;
! 1311: sc->sc_c.targets[target]->period =
! 1312: sc->sc_c.targets[target]->offset = 0;
! 1313: siop_update_xfer_mode(&sc->sc_c, target);
! 1314: }
! 1315: }
! 1316: /* Next commands from the urgent list */
! 1317: for (siop_cmd = TAILQ_FIRST(&sc->urgent_list); siop_cmd != NULL;
! 1318: siop_cmd = next_siop_cmd) {
! 1319: next_siop_cmd = TAILQ_NEXT(siop_cmd, next);
! 1320: TAILQ_REMOVE(&sc->urgent_list, siop_cmd, next);
! 1321: TAILQ_INSERT_TAIL(&reset_list, siop_cmd, next);
! 1322: sc_print_addr(siop_cmd->cmd_c.xs->sc_link);
! 1323: printf("cmd %p added to reset list from urgent list\n",
! 1324: siop_cmd);
! 1325: }
! 1326: /* Then commands waiting in the input list. */
! 1327: for (siop_cmd = TAILQ_FIRST(&sc->ready_list); siop_cmd != NULL;
! 1328: siop_cmd = next_siop_cmd) {
! 1329: next_siop_cmd = TAILQ_NEXT(siop_cmd, next);
! 1330: TAILQ_REMOVE(&sc->ready_list, siop_cmd, next);
! 1331: TAILQ_INSERT_TAIL(&reset_list, siop_cmd, next);
! 1332: sc_print_addr(siop_cmd->cmd_c.xs->sc_link);
! 1333: printf("cmd %p added to reset list from ready list\n",
! 1334: siop_cmd);
! 1335: }
! 1336:
! 1337: for (siop_cmd = TAILQ_FIRST(&reset_list); siop_cmd != NULL;
! 1338: siop_cmd = next_siop_cmd) {
! 1339: next_siop_cmd = TAILQ_NEXT(siop_cmd, next);
! 1340: siop_cmd->cmd_c.flags &= ~CMDFL_TAG;
! 1341: siop_cmd->cmd_c.xs->error =
! 1342: (siop_cmd->cmd_c.flags & CMDFL_TIMEOUT)
! 1343: ? XS_TIMEOUT : XS_RESET;
! 1344: siop_cmd->cmd_c.xs->status = SCSI_SIOP_NOCHECK;
! 1345: sc_print_addr(siop_cmd->cmd_c.xs->sc_link);
! 1346: printf("cmd %p (status %d) reset",
! 1347: siop_cmd, siop_cmd->cmd_c.status);
! 1348: if (siop_cmd->cmd_c.status == CMDST_SENSE ||
! 1349: siop_cmd->cmd_c.status == CMDST_SENSE_ACTIVE)
! 1350: siop_cmd->cmd_c.status = CMDST_SENSE_DONE;
! 1351: else
! 1352: siop_cmd->cmd_c.status = CMDST_DONE;
! 1353: printf(" with status %d, xs->error %d\n",
! 1354: siop_cmd->cmd_c.status, siop_cmd->cmd_c.xs->error);
! 1355: TAILQ_REMOVE(&reset_list, siop_cmd, next);
! 1356: siop_scsicmd_end(siop_cmd);
! 1357: }
! 1358: }
! 1359:
! 1360: int
! 1361: siop_scsicmd(xs)
! 1362: struct scsi_xfer *xs;
! 1363: {
! 1364: struct siop_softc *sc = (struct siop_softc *)xs->sc_link->adapter_softc;
! 1365: struct siop_cmd *siop_cmd;
! 1366: struct siop_target *siop_target;
! 1367: int s, error, i, j;
! 1368: const int target = xs->sc_link->target;
! 1369: const int lun = xs->sc_link->lun;
! 1370:
! 1371: s = splbio();
! 1372: #ifdef SIOP_DEBUG_SCHED
! 1373: printf("starting cmd for %d:%d\n", target, lun);
! 1374: #endif
! 1375: siop_cmd = TAILQ_FIRST(&sc->free_list);
! 1376: if (siop_cmd == NULL) {
! 1377: splx(s);
! 1378: return(TRY_AGAIN_LATER);
! 1379: }
! 1380: TAILQ_REMOVE(&sc->free_list, siop_cmd, next);
! 1381:
! 1382: /* Always reset xs->stimeout, lest we timeout_del() with trash */
! 1383: timeout_set(&xs->stimeout, siop_timeout, siop_cmd);
! 1384:
! 1385: #ifdef DIAGNOSTIC
! 1386: if (siop_cmd->cmd_c.status != CMDST_FREE)
! 1387: panic("siop_scsicmd: new cmd not free");
! 1388: #endif
! 1389: siop_target = (struct siop_target*)sc->sc_c.targets[target];
! 1390: if (siop_target == NULL) {
! 1391: #ifdef SIOP_DEBUG
! 1392: printf("%s: alloc siop_target for target %d\n",
! 1393: sc->sc_c.sc_dev.dv_xname, target);
! 1394: #endif
! 1395: sc->sc_c.targets[target] =
! 1396: malloc(sizeof(struct siop_target),
! 1397: M_DEVBUF, M_NOWAIT);
! 1398: if (sc->sc_c.targets[target] == NULL) {
! 1399: printf("%s: can't malloc memory for "
! 1400: "target %d\n", sc->sc_c.sc_dev.dv_xname,
! 1401: target);
! 1402: splx(s);
! 1403: return(TRY_AGAIN_LATER);
! 1404: }
! 1405: bzero(sc->sc_c.targets[target], sizeof(struct siop_target));
! 1406: siop_target =
! 1407: (struct siop_target*)sc->sc_c.targets[target];
! 1408: siop_target->target_c.status = TARST_PROBING;
! 1409: siop_target->target_c.flags = 0;
! 1410: siop_target->target_c.id =
! 1411: sc->sc_c.clock_div << 24; /* scntl3 */
! 1412: siop_target->target_c.id |= target << 16; /* id */
! 1413: /* siop_target->target_c.id |= 0x0 << 8; scxfer is 0 */
! 1414:
! 1415: /* get a lun switch script */
! 1416: siop_target->lunsw = siop_get_lunsw(sc);
! 1417: if (siop_target->lunsw == NULL) {
! 1418: printf("%s: can't alloc lunsw for target %d\n",
! 1419: sc->sc_c.sc_dev.dv_xname, target);
! 1420: splx(s);
! 1421: return(TRY_AGAIN_LATER);
! 1422: }
! 1423: for (i=0; i < 8; i++)
! 1424: siop_target->siop_lun[i] = NULL;
! 1425: siop_add_reselsw(sc, target);
! 1426: }
! 1427: if (siop_target->siop_lun[lun] == NULL) {
! 1428: siop_target->siop_lun[lun] =
! 1429: malloc(sizeof(struct siop_lun), M_DEVBUF,
! 1430: M_NOWAIT);
! 1431: if (siop_target->siop_lun[lun] == NULL) {
! 1432: printf("%s: can't alloc siop_lun for "
! 1433: "target %d lun %d\n",
! 1434: sc->sc_c.sc_dev.dv_xname, target, lun);
! 1435: splx(s);
! 1436: return(TRY_AGAIN_LATER);
! 1437: }
! 1438: bzero(siop_target->siop_lun[lun], sizeof(struct siop_lun));
! 1439: }
! 1440: siop_cmd->cmd_c.siop_target = sc->sc_c.targets[target];
! 1441: siop_cmd->cmd_c.xs = xs;
! 1442: siop_cmd->cmd_c.flags = 0;
! 1443: siop_cmd->cmd_c.status = CMDST_READY;
! 1444:
! 1445: bzero(&siop_cmd->cmd_c.siop_tables->xscmd,
! 1446: sizeof(siop_cmd->cmd_c.siop_tables->xscmd));
! 1447: bcopy(xs->cmd, &siop_cmd->cmd_c.siop_tables->xscmd, xs->cmdlen);
! 1448: siop_cmd->cmd_c.siop_tables->cmd.count =
! 1449: siop_htoc32(&sc->sc_c, xs->cmdlen);
! 1450:
! 1451: /* load the DMA maps */
! 1452: if (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
! 1453: error = bus_dmamap_load(sc->sc_c.sc_dmat,
! 1454: siop_cmd->cmd_c.dmamap_data, xs->data, xs->datalen,
! 1455: NULL, BUS_DMA_NOWAIT | BUS_DMA_STREAMING |
! 1456: ((xs->flags & SCSI_DATA_IN) ?
! 1457: BUS_DMA_READ : BUS_DMA_WRITE));
! 1458: if (error) {
! 1459: printf("%s: unable to load data DMA map: %d\n",
! 1460: sc->sc_c.sc_dev.dv_xname, error);
! 1461: splx(s);
! 1462: return(TRY_AGAIN_LATER);
! 1463: }
! 1464: bus_dmamap_sync(sc->sc_c.sc_dmat,
! 1465: siop_cmd->cmd_c.dmamap_data, 0,
! 1466: siop_cmd->cmd_c.dmamap_data->dm_mapsize,
! 1467: (xs->flags & SCSI_DATA_IN) ?
! 1468: BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
! 1469: }
! 1470:
! 1471: siop_setuptables(&siop_cmd->cmd_c);
! 1472: siop_cmd->saved_offset = SIOP_NOOFFSET;
! 1473: siop_table_sync(siop_cmd,
! 1474: BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
! 1475:
! 1476: TAILQ_INSERT_TAIL(&sc->ready_list, siop_cmd, next);
! 1477:
! 1478: /* Negotiate transfer parameters on first non-polling command. */
! 1479: if (((xs->flags & SCSI_POLL) == 0) &&
! 1480: siop_target->target_c.status == TARST_PROBING)
! 1481: siop_target->target_c.status = TARST_ASYNC;
! 1482:
! 1483: siop_start(sc);
! 1484: if ((xs->flags & SCSI_POLL) == 0) {
! 1485: splx(s);
! 1486: return (SUCCESSFULLY_QUEUED);
! 1487: }
! 1488:
! 1489: /* Poll for command completion. */
! 1490: for(i = xs->timeout; i > 0; i--) {
! 1491: siop_intr(sc);
! 1492: if ((xs->flags & ITSDONE) == 0) {
! 1493: delay(1000);
! 1494: continue;
! 1495: }
! 1496: if (xs->cmd->opcode == INQUIRY && xs->error == XS_NOERROR) {
! 1497: struct scsi_inquiry_data *inqbuf =
! 1498: (struct scsi_inquiry_data *)xs->data;
! 1499: if ((inqbuf->device & SID_QUAL) == SID_QUAL_BAD_LU)
! 1500: break;
! 1501: /*
! 1502: * Allocate cbd's to hold maximum openings worth of
! 1503: * commands. Do this now because doing it dynamically in
! 1504: * siop_startcmd may cause calls to bus_dma* functions
! 1505: * in interrupt context.
! 1506: */
! 1507: for (j = 0; j < SIOP_NTAG; j += SIOP_NCMDPB)
! 1508: siop_morecbd(sc);
! 1509:
! 1510: /*
! 1511: * Set TARF_DT here because if it is turned off during
! 1512: * PPR, it must STAY off!
! 1513: */
! 1514: if ((lun == 0) && (sc->sc_c.features & SF_BUS_ULTRA3))
! 1515: sc->sc_c.targets[target]->flags |= TARF_DT;
! 1516: /*
! 1517: * Can't do lun 0 here, because flags are not set yet.
! 1518: * But have to do other lun's here because they never go
! 1519: * through TARST_ASYNC.
! 1520: */
! 1521: if (lun > 0)
! 1522: siop_add_dev(sc, target, lun);
! 1523: }
! 1524: break;
! 1525: }
! 1526: if (i == 0) {
! 1527: siop_timeout(siop_cmd);
! 1528: while ((xs->flags & ITSDONE) == 0)
! 1529: siop_intr(sc);
! 1530: }
! 1531:
! 1532: splx(s);
! 1533: return (COMPLETE);
! 1534: }
! 1535:
! 1536: void
! 1537: siop_start(sc)
! 1538: struct siop_softc *sc;
! 1539: {
! 1540: struct siop_cmd *siop_cmd, *next_siop_cmd;
! 1541: struct siop_lun *siop_lun;
! 1542: struct siop_xfer *siop_xfer;
! 1543: u_int32_t dsa;
! 1544: int timeout;
! 1545: int target, lun, tag, slot;
! 1546: int newcmd = 0;
! 1547: int doingready = 0;
! 1548:
! 1549: /*
! 1550: * first make sure to read valid data
! 1551: */
! 1552: siop_script_sync(sc, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
! 1553:
! 1554: /*
! 1555: * The queue management here is a bit tricky: the script always looks
! 1556: * at the slot from first to last, so if we always use the first
! 1557: * free slot commands can stay at the tail of the queue ~forever.
! 1558: * The algorithm used here is to restart from the head when we know
! 1559: * that the queue is empty, and only add commands after the last one.
! 1560: * When we're at the end of the queue wait for the script to clear it.
! 1561: * The best thing to do here would be to implement a circular queue,
! 1562: * but using only 53c720 features this can be "interesting".
! 1563: * A mid-way solution could be to implement 2 queues and swap orders.
! 1564: */
! 1565: slot = sc->sc_currschedslot;
! 1566: /*
! 1567: * If the instruction is 0x80000000 (JUMP foo, IF FALSE) the slot is
! 1568: * free. As this is the last used slot, all previous slots are free,
! 1569: * we can restart from 1.
! 1570: * slot 0 is reserved for request sense commands.
! 1571: */
! 1572: if (siop_script_read(sc, (Ent_script_sched_slot0 / 4) + slot * 2) ==
! 1573: 0x80000000) {
! 1574: slot = sc->sc_currschedslot = 1;
! 1575: } else {
! 1576: slot++;
! 1577: }
! 1578: /* first handle commands from the urgent list */
! 1579: siop_cmd = TAILQ_FIRST(&sc->urgent_list);
! 1580: again:
! 1581: for (; siop_cmd != NULL; siop_cmd = next_siop_cmd) {
! 1582: next_siop_cmd = TAILQ_NEXT(siop_cmd, next);
! 1583: #ifdef DIAGNOSTIC
! 1584: if (siop_cmd->cmd_c.status != CMDST_READY &&
! 1585: siop_cmd->cmd_c.status != CMDST_SENSE)
! 1586: panic("siop: non-ready cmd in ready list");
! 1587: #endif
! 1588: target = siop_cmd->cmd_c.xs->sc_link->target;
! 1589: lun = siop_cmd->cmd_c.xs->sc_link->lun;
! 1590: siop_lun =
! 1591: ((struct siop_target*)sc->sc_c.targets[target])->siop_lun[lun];
! 1592: /* if non-tagged command active, wait */
! 1593: if (siop_lun->siop_tag[0].active != NULL)
! 1594: continue;
! 1595: /*
! 1596: * if we're in a queue full condition don't start a new
! 1597: * command, unless it's a request sense
! 1598: */
! 1599: if ((siop_lun->lun_flags & SIOP_LUNF_FULL) &&
! 1600: siop_cmd->cmd_c.status == CMDST_READY)
! 1601: continue;
! 1602: /* find a free tag if needed */
! 1603: if (siop_cmd->cmd_c.flags & CMDFL_TAG) {
! 1604: for (tag = 1; tag < SIOP_NTAG; tag++) {
! 1605: if (siop_lun->siop_tag[tag].active == NULL)
! 1606: break;
! 1607: }
! 1608: if (tag == SIOP_NTAG) /* no free tag */
! 1609: continue;
! 1610: } else {
! 1611: tag = 0;
! 1612: }
! 1613: siop_cmd->cmd_c.tag = tag;
! 1614: /*
! 1615: * find a free scheduler slot and load it. If it's a request
! 1616: * sense we need to use slot 0.
! 1617: */
! 1618: if (siop_cmd->cmd_c.status != CMDST_SENSE) {
! 1619: for (; slot < SIOP_NSLOTS; slot++) {
! 1620: /*
! 1621: * If cmd if 0x80000000 the slot is free
! 1622: */
! 1623: if (siop_script_read(sc,
! 1624: (Ent_script_sched_slot0 / 4) + slot * 2) ==
! 1625: 0x80000000)
! 1626: break;
! 1627: }
! 1628: /* no more free slots, no need to continue */
! 1629: if (slot == SIOP_NSLOTS) {
! 1630: goto end;
! 1631: }
! 1632: } else {
! 1633: slot = 0;
! 1634: if (siop_script_read(sc, Ent_script_sched_slot0 / 4)
! 1635: != 0x80000000)
! 1636: goto end;
! 1637: }
! 1638:
! 1639: #ifdef SIOP_DEBUG_SCHED
! 1640: printf("using slot %d for DSA 0x%lx\n", slot,
! 1641: (u_long)siop_cmd->cmd_c.dsa);
! 1642: #endif
! 1643: /* Ok, we can add the tag message */
! 1644: if (tag > 0) {
! 1645: #ifdef DIAGNOSTIC
! 1646: int msgcount = siop_ctoh32(&sc->sc_c,
! 1647: siop_cmd->cmd_tables->t_msgout.count);
! 1648: if (msgcount != 1)
! 1649: printf("%s:%d:%d: tag %d with msgcount %d\n",
! 1650: sc->sc_c.sc_dev.dv_xname, target, lun, tag,
! 1651: msgcount);
! 1652: #endif
! 1653: if (siop_cmd->cmd_c.xs->bp != NULL &&
! 1654: (siop_cmd->cmd_c.xs->bp->b_flags & B_ASYNC))
! 1655: siop_cmd->cmd_tables->msg_out[1] =
! 1656: MSG_SIMPLE_Q_TAG;
! 1657: else
! 1658: siop_cmd->cmd_tables->msg_out[1] =
! 1659: MSG_ORDERED_Q_TAG;
! 1660: siop_cmd->cmd_tables->msg_out[2] = tag;
! 1661: siop_cmd->cmd_tables->t_msgout.count =
! 1662: siop_htoc32(&sc->sc_c, 3);
! 1663: }
! 1664: /* note that we started a new command */
! 1665: newcmd = 1;
! 1666: /* mark command as active */
! 1667: if (siop_cmd->cmd_c.status == CMDST_READY) {
! 1668: siop_cmd->cmd_c.status = CMDST_ACTIVE;
! 1669: } else if (siop_cmd->cmd_c.status == CMDST_SENSE) {
! 1670: siop_cmd->cmd_c.status = CMDST_SENSE_ACTIVE;
! 1671: } else
! 1672: panic("siop_start: bad status");
! 1673: if (doingready)
! 1674: TAILQ_REMOVE(&sc->ready_list, siop_cmd, next);
! 1675: else
! 1676: TAILQ_REMOVE(&sc->urgent_list, siop_cmd, next);
! 1677: siop_lun->siop_tag[tag].active = siop_cmd;
! 1678: /* patch scripts with DSA addr */
! 1679: dsa = siop_cmd->cmd_c.dsa;
! 1680: /* first reselect switch, if we have an entry */
! 1681: if (siop_lun->siop_tag[tag].reseloff > 0)
! 1682: siop_script_write(sc,
! 1683: siop_lun->siop_tag[tag].reseloff + 1,
! 1684: dsa + sizeof(struct siop_common_xfer) +
! 1685: Ent_ldsa_reload_dsa);
! 1686: /* CMD script: MOVE MEMORY addr */
! 1687: siop_xfer = (struct siop_xfer*)siop_cmd->cmd_tables;
! 1688: siop_xfer->resel[E_ldsa_abs_slot_Used[0]] =
! 1689: siop_htoc32(&sc->sc_c, sc->sc_c.sc_scriptaddr +
! 1690: Ent_script_sched_slot0 + slot * 8);
! 1691: siop_table_sync(siop_cmd, BUS_DMASYNC_PREWRITE);
! 1692: /* scheduler slot: JUMP ldsa_select */
! 1693: siop_script_write(sc,
! 1694: (Ent_script_sched_slot0 / 4) + slot * 2 + 1,
! 1695: dsa + sizeof(struct siop_common_xfer) + Ent_ldsa_select);
! 1696: /* handle timeout */
! 1697: if (siop_cmd->cmd_c.status == CMDST_ACTIVE) {
! 1698: if ((siop_cmd->cmd_c.xs->flags & SCSI_POLL) == 0) {
! 1699: /* start expire timer */
! 1700: timeout = (u_int64_t) siop_cmd->cmd_c.xs->timeout *
! 1701: (u_int64_t)hz / 1000;
! 1702: if (timeout == 0)
! 1703: timeout = 1;
! 1704: timeout_add(&siop_cmd->cmd_c.xs->stimeout, timeout);
! 1705: }
! 1706: }
! 1707: /*
! 1708: * Change JUMP cmd so that this slot will be handled
! 1709: */
! 1710: siop_script_write(sc, (Ent_script_sched_slot0 / 4) + slot * 2,
! 1711: 0x80080000);
! 1712: /* if we're using the request sense slot, stop here */
! 1713: if (slot == 0)
! 1714: goto end;
! 1715: sc->sc_currschedslot = slot;
! 1716: slot++;
! 1717: }
! 1718: if (doingready == 0) {
! 1719: /* now process ready list */
! 1720: doingready = 1;
! 1721: siop_cmd = TAILQ_FIRST(&sc->ready_list);
! 1722: goto again;
! 1723: }
! 1724:
! 1725: end:
! 1726: /* if nothing changed no need to flush cache and wakeup script */
! 1727: if (newcmd == 0)
! 1728: return;
! 1729: /* make sure SCRIPT processor will read valid data */
! 1730: siop_script_sync(sc,BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
! 1731: /* Signal script it has some work to do */
! 1732: bus_space_write_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
! 1733: SIOP_ISTAT, ISTAT_SIGP);
! 1734: /* and wait for IRQ */
! 1735: return;
! 1736: }
! 1737:
! 1738: void
! 1739: siop_timeout(v)
! 1740: void *v;
! 1741: {
! 1742: struct siop_cmd *siop_cmd = v;
! 1743: struct siop_softc *sc = (struct siop_softc *)siop_cmd->cmd_c.siop_sc;
! 1744: int s;
! 1745:
! 1746: /* deactivate callout */
! 1747: timeout_del(&siop_cmd->cmd_c.xs->stimeout);
! 1748:
! 1749: sc_print_addr(siop_cmd->cmd_c.xs->sc_link);
! 1750: printf("timeout on SCSI command 0x%x\n",
! 1751: siop_cmd->cmd_c.xs->cmd->opcode);
! 1752:
! 1753: s = splbio();
! 1754: /* reset the scsi bus */
! 1755: siop_resetbus(&sc->sc_c);
! 1756: siop_cmd->cmd_c.flags |= CMDFL_TIMEOUT;
! 1757: siop_handle_reset(sc);
! 1758: splx(s);
! 1759:
! 1760: return;
! 1761: }
! 1762:
! 1763: #ifdef DUMP_SCRIPT
! 1764: void
! 1765: siop_dump_script(sc)
! 1766: struct siop_softc *sc;
! 1767: {
! 1768: int i;
! 1769: for (i = 0; i < PAGE_SIZE / 4; i += 2) {
! 1770: printf("0x%04x: 0x%08x 0x%08x", i * 4,
! 1771: siop_ctoh32(&sc->sc_c, sc->sc_c.sc_script[i]),
! 1772: siop_ctoh32(&sc->sc_c, sc->sc_c.sc_script[i+1]));
! 1773: if ((siop_ctoh32(&sc->sc_c,
! 1774: sc->sc_c.sc_script[i]) & 0xe0000000) == 0xc0000000) {
! 1775: i++;
! 1776: printf(" 0x%08x", siop_ctoh32(&sc->sc_c,
! 1777: sc->sc_c.sc_script[i+1]));
! 1778: }
! 1779: printf("\n");
! 1780: }
! 1781: }
! 1782: #endif
! 1783:
! 1784: void
! 1785: siop_morecbd(sc)
! 1786: struct siop_softc *sc;
! 1787: {
! 1788: int error, off, i, j, s;
! 1789: bus_dma_segment_t seg;
! 1790: int rseg;
! 1791: struct siop_cbd *newcbd;
! 1792: struct siop_xfer *xfer;
! 1793: bus_addr_t dsa;
! 1794: u_int32_t *scr;
! 1795:
! 1796: /* allocate a new list head */
! 1797: newcbd = malloc(sizeof(struct siop_cbd), M_DEVBUF, M_NOWAIT);
! 1798: if (newcbd == NULL) {
! 1799: printf("%s: can't allocate memory for command descriptors "
! 1800: "head\n", sc->sc_c.sc_dev.dv_xname);
! 1801: return;
! 1802: }
! 1803: bzero(newcbd, sizeof(struct siop_cbd));
! 1804:
! 1805: /* allocate cmd list */
! 1806: newcbd->cmds = malloc(sizeof(struct siop_cmd) * SIOP_NCMDPB,
! 1807: M_DEVBUF, M_NOWAIT);
! 1808: if (newcbd->cmds == NULL) {
! 1809: printf("%s: can't allocate memory for command descriptors\n",
! 1810: sc->sc_c.sc_dev.dv_xname);
! 1811: goto bad3;
! 1812: }
! 1813: bzero(newcbd->cmds, sizeof(struct siop_cmd) * SIOP_NCMDPB);
! 1814: error = bus_dmamem_alloc(sc->sc_c.sc_dmat, PAGE_SIZE, PAGE_SIZE, 0, &seg,
! 1815: 1, &rseg, BUS_DMA_NOWAIT);
! 1816: if (error) {
! 1817: printf("%s: unable to allocate cbd DMA memory, error = %d\n",
! 1818: sc->sc_c.sc_dev.dv_xname, error);
! 1819: goto bad2;
! 1820: }
! 1821: error = bus_dmamem_map(sc->sc_c.sc_dmat, &seg, rseg, PAGE_SIZE,
! 1822: (caddr_t *)&newcbd->xfers, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
! 1823: if (error) {
! 1824: printf("%s: unable to map cbd DMA memory, error = %d\n",
! 1825: sc->sc_c.sc_dev.dv_xname, error);
! 1826: goto bad2;
! 1827: }
! 1828: error = bus_dmamap_create(sc->sc_c.sc_dmat, PAGE_SIZE, 1, PAGE_SIZE, 0,
! 1829: BUS_DMA_NOWAIT, &newcbd->xferdma);
! 1830: if (error) {
! 1831: printf("%s: unable to create cbd DMA map, error = %d\n",
! 1832: sc->sc_c.sc_dev.dv_xname, error);
! 1833: goto bad1;
! 1834: }
! 1835: error = bus_dmamap_load(sc->sc_c.sc_dmat, newcbd->xferdma, newcbd->xfers,
! 1836: PAGE_SIZE, NULL, BUS_DMA_NOWAIT);
! 1837: if (error) {
! 1838: printf("%s: unable to load cbd DMA map, error = %d\n",
! 1839: sc->sc_c.sc_dev.dv_xname, error);
! 1840: goto bad0;
! 1841: }
! 1842: #ifdef SIOP_DEBUG
! 1843: printf("%s: alloc newcdb at PHY addr 0x%lx\n", sc->sc_c.sc_dev.dv_xname,
! 1844: (unsigned long)newcbd->xferdma->dm_segs[0].ds_addr);
! 1845: #endif
! 1846: for (i = 0; i < SIOP_NCMDPB; i++) {
! 1847: error = bus_dmamap_create(sc->sc_c.sc_dmat, MAXPHYS, SIOP_NSG,
! 1848: MAXPHYS, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
! 1849: &newcbd->cmds[i].cmd_c.dmamap_data);
! 1850: if (error) {
! 1851: printf("%s: unable to create data DMA map for cbd: "
! 1852: "error %d\n",
! 1853: sc->sc_c.sc_dev.dv_xname, error);
! 1854: goto bad0;
! 1855: }
! 1856: }
! 1857:
! 1858: /* Use two loops since bailing out above releases allocated memory */
! 1859: off = (sc->sc_c.features & SF_CHIP_BE) ? 3 : 0;
! 1860: for (i = 0; i < SIOP_NCMDPB; i++) {
! 1861: newcbd->cmds[i].cmd_c.siop_sc = &sc->sc_c;
! 1862: newcbd->cmds[i].siop_cbdp = newcbd;
! 1863: xfer = &newcbd->xfers[i];
! 1864: newcbd->cmds[i].cmd_tables = (struct siop_common_xfer *)xfer;
! 1865: bzero(newcbd->cmds[i].cmd_tables, sizeof(struct siop_xfer));
! 1866: dsa = newcbd->xferdma->dm_segs[0].ds_addr +
! 1867: i * sizeof(struct siop_xfer);
! 1868: newcbd->cmds[i].cmd_c.dsa = dsa;
! 1869: newcbd->cmds[i].cmd_c.status = CMDST_FREE;
! 1870: xfer->siop_tables.t_msgout.count= siop_htoc32(&sc->sc_c, 1);
! 1871: xfer->siop_tables.t_msgout.addr = siop_htoc32(&sc->sc_c, dsa);
! 1872: xfer->siop_tables.t_msgin.count= siop_htoc32(&sc->sc_c, 1);
! 1873: xfer->siop_tables.t_msgin.addr = siop_htoc32(&sc->sc_c,
! 1874: dsa + offsetof(struct siop_common_xfer, msg_in));
! 1875: xfer->siop_tables.t_extmsgin.count= siop_htoc32(&sc->sc_c, 2);
! 1876: xfer->siop_tables.t_extmsgin.addr = siop_htoc32(&sc->sc_c,
! 1877: dsa + offsetof(struct siop_common_xfer, msg_in) + 1);
! 1878: xfer->siop_tables.t_extmsgdata.addr = siop_htoc32(&sc->sc_c,
! 1879: dsa + offsetof(struct siop_common_xfer, msg_in) + 3);
! 1880: xfer->siop_tables.t_status.count= siop_htoc32(&sc->sc_c, 1);
! 1881: xfer->siop_tables.t_status.addr = siop_htoc32(&sc->sc_c,
! 1882: dsa + offsetof(struct siop_common_xfer, status) + off);
! 1883: xfer->siop_tables.cmd.count = siop_htoc32(&sc->sc_c, 0);
! 1884: xfer->siop_tables.cmd.addr = siop_htoc32(&sc->sc_c,
! 1885: dsa + offsetof(struct siop_common_xfer, xscmd));
! 1886: /* The select/reselect script */
! 1887: scr = &xfer->resel[0];
! 1888: for (j = 0; j < sizeof(load_dsa) / sizeof(load_dsa[0]); j++)
! 1889: scr[j] = siop_htoc32(&sc->sc_c, load_dsa[j]);
! 1890: /*
! 1891: * 0x78000000 is a 'move data8 to reg'. data8 is the second
! 1892: * octet, reg offset is the third.
! 1893: */
! 1894: scr[Ent_rdsa0 / 4] = siop_htoc32(&sc->sc_c,
! 1895: 0x78100000 | ((dsa & 0x000000ff) << 8));
! 1896: scr[Ent_rdsa1 / 4] = siop_htoc32(&sc->sc_c,
! 1897: 0x78110000 | ( dsa & 0x0000ff00 ));
! 1898: scr[Ent_rdsa2 / 4] = siop_htoc32(&sc->sc_c,
! 1899: 0x78120000 | ((dsa & 0x00ff0000) >> 8));
! 1900: scr[Ent_rdsa3 / 4] = siop_htoc32(&sc->sc_c,
! 1901: 0x78130000 | ((dsa & 0xff000000) >> 16));
! 1902: scr[E_ldsa_abs_reselected_Used[0]] = siop_htoc32(&sc->sc_c,
! 1903: sc->sc_c.sc_scriptaddr + Ent_reselected);
! 1904: scr[E_ldsa_abs_reselect_Used[0]] = siop_htoc32(&sc->sc_c,
! 1905: sc->sc_c.sc_scriptaddr + Ent_reselect);
! 1906: scr[E_ldsa_abs_selected_Used[0]] = siop_htoc32(&sc->sc_c,
! 1907: sc->sc_c.sc_scriptaddr + Ent_selected);
! 1908: scr[E_ldsa_abs_data_Used[0]] = siop_htoc32(&sc->sc_c,
! 1909: dsa + sizeof(struct siop_common_xfer) + Ent_ldsa_data);
! 1910: /* JUMP foo, IF FALSE - used by MOVE MEMORY to clear the slot */
! 1911: scr[Ent_ldsa_data / 4] = siop_htoc32(&sc->sc_c, 0x80000000);
! 1912: s = splbio();
! 1913: TAILQ_INSERT_TAIL(&sc->free_list, &newcbd->cmds[i], next);
! 1914: splx(s);
! 1915: #ifdef SIOP_DEBUG
! 1916: printf("tables[%d]: in=0x%x out=0x%x status=0x%x "
! 1917: "offset=0x%x\n", i,
! 1918: siop_ctoh32(&sc->sc_c,
! 1919: newcbd->cmds[i].cmd_tables->t_msgin.addr),
! 1920: siop_ctoh32(&sc->sc_c,
! 1921: newcbd->cmds[i].cmd_tables->t_msgout.addr),
! 1922: siop_ctoh32(&sc->sc_c,
! 1923: newcbd->cmds[i].cmd_tables->t_status.addr));
! 1924: #endif
! 1925: }
! 1926: s = splbio();
! 1927: TAILQ_INSERT_TAIL(&sc->cmds, newcbd, next);
! 1928: splx(s);
! 1929: return;
! 1930: bad0:
! 1931: bus_dmamap_unload(sc->sc_c.sc_dmat, newcbd->xferdma);
! 1932: bus_dmamap_destroy(sc->sc_c.sc_dmat, newcbd->xferdma);
! 1933: bad1:
! 1934: bus_dmamem_free(sc->sc_c.sc_dmat, &seg, rseg);
! 1935: bad2:
! 1936: free(newcbd->cmds, M_DEVBUF);
! 1937: bad3:
! 1938: free(newcbd, M_DEVBUF);
! 1939: return;
! 1940: }
! 1941:
! 1942: struct siop_lunsw *
! 1943: siop_get_lunsw(sc)
! 1944: struct siop_softc *sc;
! 1945: {
! 1946: struct siop_lunsw *lunsw;
! 1947: int i;
! 1948:
! 1949: if (sc->script_free_lo + (sizeof(lun_switch) / sizeof(lun_switch[0])) >=
! 1950: sc->script_free_hi)
! 1951: return NULL;
! 1952: lunsw = TAILQ_FIRST(&sc->lunsw_list);
! 1953: if (lunsw != NULL) {
! 1954: #ifdef SIOP_DEBUG
! 1955: printf("siop_get_lunsw got lunsw at offset %d\n",
! 1956: lunsw->lunsw_off);
! 1957: #endif
! 1958: TAILQ_REMOVE(&sc->lunsw_list, lunsw, next);
! 1959: return lunsw;
! 1960: }
! 1961: lunsw = malloc(sizeof(struct siop_lunsw), M_DEVBUF, M_NOWAIT);
! 1962: if (lunsw == NULL)
! 1963: return NULL;
! 1964: bzero(lunsw, sizeof(struct siop_lunsw));
! 1965: #ifdef SIOP_DEBUG
! 1966: printf("allocating lunsw at offset %d\n", sc->script_free_lo);
! 1967: #endif
! 1968: if (sc->sc_c.features & SF_CHIP_RAM) {
! 1969: bus_space_write_region_4(sc->sc_c.sc_ramt, sc->sc_c.sc_ramh,
! 1970: sc->script_free_lo * 4, lun_switch,
! 1971: sizeof(lun_switch) / sizeof(lun_switch[0]));
! 1972: bus_space_write_4(sc->sc_c.sc_ramt, sc->sc_c.sc_ramh,
! 1973: (sc->script_free_lo + E_abs_lunsw_return_Used[0]) * 4,
! 1974: sc->sc_c.sc_scriptaddr + Ent_lunsw_return);
! 1975: } else {
! 1976: for (i = 0; i < sizeof(lun_switch) / sizeof(lun_switch[0]);
! 1977: i++)
! 1978: sc->sc_c.sc_script[sc->script_free_lo + i] =
! 1979: siop_htoc32(&sc->sc_c, lun_switch[i]);
! 1980: sc->sc_c.sc_script[
! 1981: sc->script_free_lo + E_abs_lunsw_return_Used[0]] =
! 1982: siop_htoc32(&sc->sc_c,
! 1983: sc->sc_c.sc_scriptaddr + Ent_lunsw_return);
! 1984: }
! 1985: lunsw->lunsw_off = sc->script_free_lo;
! 1986: lunsw->lunsw_size = sizeof(lun_switch) / sizeof(lun_switch[0]);
! 1987: sc->script_free_lo += lunsw->lunsw_size;
! 1988: siop_script_sync(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
! 1989: return lunsw;
! 1990: }
! 1991:
! 1992: void
! 1993: siop_add_reselsw(sc, target)
! 1994: struct siop_softc *sc;
! 1995: int target;
! 1996: {
! 1997: int i,j;
! 1998: struct siop_target *siop_target;
! 1999: struct siop_lun *siop_lun;
! 2000:
! 2001: siop_target = (struct siop_target *)sc->sc_c.targets[target];
! 2002: /*
! 2003: * add an entry to resel switch
! 2004: */
! 2005: siop_script_sync(sc, BUS_DMASYNC_POSTWRITE);
! 2006: for (i = 0; i < 15; i++) {
! 2007: siop_target->reseloff = Ent_resel_targ0 / 4 + i * 2;
! 2008: if ((siop_script_read(sc, siop_target->reseloff) & 0xff)
! 2009: == 0xff) { /* it's free */
! 2010: #ifdef SIOP_DEBUG
! 2011: printf("siop: target %d slot %d offset %d\n",
! 2012: target, i, siop_target->reseloff);
! 2013: #endif
! 2014: /* JUMP abs_foo, IF target | 0x80; */
! 2015: siop_script_write(sc, siop_target->reseloff,
! 2016: 0x800c0080 | target);
! 2017: siop_script_write(sc, siop_target->reseloff + 1,
! 2018: sc->sc_c.sc_scriptaddr +
! 2019: siop_target->lunsw->lunsw_off * 4 +
! 2020: Ent_lun_switch_entry);
! 2021: break;
! 2022: }
! 2023: }
! 2024: if (i == 15) /* no free slot, shouldn't happen */
! 2025: panic("siop: resel switch full");
! 2026:
! 2027: sc->sc_ntargets++;
! 2028: for (i = 0; i < 8; i++) {
! 2029: siop_lun = siop_target->siop_lun[i];
! 2030: if (siop_lun == NULL)
! 2031: continue;
! 2032: if (siop_lun->reseloff > 0) {
! 2033: siop_lun->reseloff = 0;
! 2034: for (j = 0; j < SIOP_NTAG; j++)
! 2035: siop_lun->siop_tag[j].reseloff = 0;
! 2036: siop_add_dev(sc, target, i);
! 2037: }
! 2038: }
! 2039: siop_update_scntl3(sc, sc->sc_c.targets[target]);
! 2040: siop_script_sync(sc, BUS_DMASYNC_PREWRITE);
! 2041: }
! 2042:
! 2043: void
! 2044: siop_update_scntl3(sc, _siop_target)
! 2045: struct siop_softc *sc;
! 2046: struct siop_common_target *_siop_target;
! 2047: {
! 2048: struct siop_target *siop_target = (struct siop_target *)_siop_target;
! 2049: /* MOVE target->id >> 24 TO SCNTL3 */
! 2050: siop_script_write(sc,
! 2051: siop_target->lunsw->lunsw_off + (Ent_restore_scntl3 / 4),
! 2052: 0x78030000 | ((siop_target->target_c.id >> 16) & 0x0000ff00));
! 2053: /* MOVE target->id >> 8 TO SXFER */
! 2054: siop_script_write(sc,
! 2055: siop_target->lunsw->lunsw_off + (Ent_restore_scntl3 / 4) + 2,
! 2056: 0x78050000 | (siop_target->target_c.id & 0x0000ff00));
! 2057: siop_script_sync(sc, BUS_DMASYNC_PREWRITE);
! 2058: }
! 2059:
! 2060: void
! 2061: siop_add_dev(sc, target, lun)
! 2062: struct siop_softc *sc;
! 2063: int target;
! 2064: int lun;
! 2065: {
! 2066: struct siop_lunsw *lunsw;
! 2067: struct siop_target *siop_target =
! 2068: (struct siop_target *)sc->sc_c.targets[target];
! 2069: struct siop_lun *siop_lun = siop_target->siop_lun[lun];
! 2070: int i, ntargets;
! 2071:
! 2072: if (siop_lun->reseloff > 0)
! 2073: return;
! 2074: lunsw = siop_target->lunsw;
! 2075: if ((lunsw->lunsw_off + lunsw->lunsw_size) < sc->script_free_lo) {
! 2076: /*
! 2077: * can't extend this slot. Probably not worth trying to deal
! 2078: * with this case
! 2079: */
! 2080: #ifdef SIOP_DEBUG
! 2081: printf("%s:%d:%d: can't allocate a lun sw slot\n",
! 2082: sc->sc_c.sc_dev.dv_xname, target, lun);
! 2083: #endif
! 2084: return;
! 2085: }
! 2086: /* count how many free targets we still have to probe */
! 2087: ntargets = (sc->sc_c.sc_link.adapter_buswidth - 1) - 1 - sc->sc_ntargets;
! 2088:
! 2089: /*
! 2090: * we need 8 bytes for the lun sw additional entry, and
! 2091: * eventually sizeof(tag_switch) for the tag switch entry.
! 2092: * Keep enough free space for the free targets that could be
! 2093: * probed later.
! 2094: */
! 2095: if (sc->script_free_lo + 2 +
! 2096: (ntargets * sizeof(lun_switch) / sizeof(lun_switch[0])) >=
! 2097: ((siop_target->target_c.flags & TARF_TAG) ?
! 2098: sc->script_free_hi - (sizeof(tag_switch) / sizeof(tag_switch[0])) :
! 2099: sc->script_free_hi)) {
! 2100: /*
! 2101: * not enough space, probably not worth dealing with it.
! 2102: * We can hold 13 tagged-queuing capable devices in the 4k RAM.
! 2103: */
! 2104: #ifdef SIOP_DEBUG
! 2105: printf("%s:%d:%d: not enough memory for a lun sw slot\n",
! 2106: sc->sc_c.sc_dev.dv_xname, target, lun);
! 2107: #endif
! 2108: return;
! 2109: }
! 2110: #ifdef SIOP_DEBUG
! 2111: printf("%s:%d:%d: allocate lun sw entry\n",
! 2112: sc->sc_c.sc_dev.dv_xname, target, lun);
! 2113: #endif
! 2114: /* INT int_resellun */
! 2115: siop_script_write(sc, sc->script_free_lo, 0x98080000);
! 2116: siop_script_write(sc, sc->script_free_lo + 1, A_int_resellun);
! 2117: /* Now the slot entry: JUMP abs_foo, IF lun */
! 2118: siop_script_write(sc, sc->script_free_lo - 2,
! 2119: 0x800c0000 | lun);
! 2120: siop_script_write(sc, sc->script_free_lo - 1, 0);
! 2121: siop_lun->reseloff = sc->script_free_lo - 2;
! 2122: lunsw->lunsw_size += 2;
! 2123: sc->script_free_lo += 2;
! 2124: if (siop_target->target_c.flags & TARF_TAG) {
! 2125: /* we need a tag switch */
! 2126: sc->script_free_hi -=
! 2127: sizeof(tag_switch) / sizeof(tag_switch[0]);
! 2128: if (sc->sc_c.features & SF_CHIP_RAM) {
! 2129: bus_space_write_region_4(sc->sc_c.sc_ramt,
! 2130: sc->sc_c.sc_ramh,
! 2131: sc->script_free_hi * 4, tag_switch,
! 2132: sizeof(tag_switch) / sizeof(tag_switch[0]));
! 2133: } else {
! 2134: for(i = 0;
! 2135: i < sizeof(tag_switch) / sizeof(tag_switch[0]);
! 2136: i++) {
! 2137: sc->sc_c.sc_script[sc->script_free_hi + i] =
! 2138: siop_htoc32(&sc->sc_c, tag_switch[i]);
! 2139: }
! 2140: }
! 2141: siop_script_write(sc,
! 2142: siop_lun->reseloff + 1,
! 2143: sc->sc_c.sc_scriptaddr + sc->script_free_hi * 4 +
! 2144: Ent_tag_switch_entry);
! 2145:
! 2146: for (i = 0; i < SIOP_NTAG; i++) {
! 2147: siop_lun->siop_tag[i].reseloff =
! 2148: sc->script_free_hi + (Ent_resel_tag0 / 4) + i * 2;
! 2149: }
! 2150: } else {
! 2151: /* non-tag case; just work with the lun switch */
! 2152: siop_lun->siop_tag[0].reseloff =
! 2153: siop_target->siop_lun[lun]->reseloff;
! 2154: }
! 2155: siop_script_sync(sc, BUS_DMASYNC_PREWRITE);
! 2156: }
! 2157:
! 2158: void
! 2159: siop_del_dev(sc, target, lun)
! 2160: struct siop_softc *sc;
! 2161: int target;
! 2162: int lun;
! 2163: {
! 2164: int i;
! 2165: struct siop_target *siop_target;
! 2166: #ifdef SIOP_DEBUG
! 2167: printf("%s:%d:%d: free lun sw entry\n",
! 2168: sc->sc_c.sc_dev.dv_xname, target, lun);
! 2169: #endif
! 2170: if (sc->sc_c.targets[target] == NULL)
! 2171: return;
! 2172: siop_target = (struct siop_target *)sc->sc_c.targets[target];
! 2173: free(siop_target->siop_lun[lun], M_DEVBUF);
! 2174: siop_target->siop_lun[lun] = NULL;
! 2175: /* XXX compact sw entry too ? */
! 2176: /* check if we can free the whole target */
! 2177: for (i = 0; i < 8; i++) {
! 2178: if (siop_target->siop_lun[i] != NULL)
! 2179: return;
! 2180: }
! 2181: #ifdef SIOP_DEBUG
! 2182: printf("%s: free siop_target for target %d lun %d lunsw offset %d\n",
! 2183: sc->sc_c.sc_dev.dv_xname, target, lun,
! 2184: siop_target->lunsw->lunsw_off);
! 2185: #endif
! 2186: /*
! 2187: * nothing here, free the target struct and resel
! 2188: * switch entry
! 2189: */
! 2190: siop_script_write(sc, siop_target->reseloff, 0x800c00ff);
! 2191: siop_script_sync(sc, BUS_DMASYNC_PREWRITE);
! 2192: TAILQ_INSERT_TAIL(&sc->lunsw_list, siop_target->lunsw, next);
! 2193: free(sc->sc_c.targets[target], M_DEVBUF);
! 2194: sc->sc_c.targets[target] = NULL;
! 2195: sc->sc_ntargets--;
! 2196: }
! 2197:
! 2198: #ifdef SIOP_STATS
! 2199: void
! 2200: siop_printstats()
! 2201: {
! 2202: printf("siop_stat_intr %d\n", siop_stat_intr);
! 2203: printf("siop_stat_intr_shortxfer %d\n", siop_stat_intr_shortxfer);
! 2204: printf("siop_stat_intr_xferdisc %d\n", siop_stat_intr_xferdisc);
! 2205: printf("siop_stat_intr_sdp %d\n", siop_stat_intr_sdp);
! 2206: printf("siop_stat_intr_saveoffset %d\n", siop_stat_intr_saveoffset);
! 2207: printf("siop_stat_intr_done %d\n", siop_stat_intr_done);
! 2208: printf("siop_stat_intr_lunresel %d\n", siop_stat_intr_lunresel);
! 2209: printf("siop_stat_intr_qfull %d\n", siop_stat_intr_qfull);
! 2210: }
! 2211: #endif
CVSweb