Annotation of sys/dev/ic/ncr5380sbc.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: ncr5380sbc.c,v 1.19 2006/12/10 16:15:37 miod Exp $ */
! 2: /* $NetBSD: ncr5380sbc.c,v 1.13 1996/10/13 01:37:25 christos Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1995 David Jones, Gordon W. Ross
! 6: * Copyright (c) 1994 Jarle Greipsland
! 7: * All rights reserved.
! 8: *
! 9: * Redistribution and use in source and binary forms, with or without
! 10: * modification, are permitted provided that the following conditions
! 11: * are met:
! 12: * 1. Redistributions of source code must retain the above copyright
! 13: * notice, this list of conditions and the following disclaimer.
! 14: * 2. Redistributions in binary form must reproduce the above copyright
! 15: * notice, this list of conditions and the following disclaimer in the
! 16: * documentation and/or other materials provided with the distribution.
! 17: * 3. The name of the authors may not be used to endorse or promote products
! 18: * derived from this software without specific prior written permission.
! 19: * 4. All advertising materials mentioning features or use of this software
! 20: * must display the following acknowledgement:
! 21: * This product includes software developed by
! 22: * David Jones and Gordon Ross
! 23: *
! 24: * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
! 25: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 26: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 27: * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
! 28: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 29: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 30: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 31: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 32: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 33: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 34: */
! 35:
! 36: /*
! 37: * This is a machine-independent driver for the NCR5380
! 38: * SCSI Bus Controller (SBC), also known as the Am5380.
! 39: *
! 40: * This code should work with any memory-mapped 5380,
! 41: * and can be shared by multiple adapters that address
! 42: * the 5380 with different register offset spacings.
! 43: * (This can happen on the atari, for example.)
! 44: * For porting/design info. see: ncr5380.doc
! 45: *
! 46: * Credits, history:
! 47: *
! 48: * David Jones is the author of most of the code that now
! 49: * appears in this file, and was the architect of the
! 50: * current overall structure (MI/MD code separation, etc.)
! 51: *
! 52: * Gordon Ross integrated the message phase code, added lots of
! 53: * comments about what happens when and why (re. SCSI spec.),
! 54: * debugged some reentrance problems, and added several new
! 55: * "hooks" needed for the Sun3 "si" adapters.
! 56: *
! 57: * The message in/out code was taken nearly verbatim from
! 58: * the aic6360 driver by Jarle Greipsland.
! 59: *
! 60: * Several other NCR5380 drivers were used for reference
! 61: * while developing this driver, including work by:
! 62: * The Alice Group (mac68k port) namely:
! 63: * Allen K. Briggs, Chris P. Caputo, Michael L. Finch,
! 64: * Bradley A. Grantham, and Lawrence A. Kesteloot
! 65: * Michael L. Hitch (amiga drivers: sci.c)
! 66: * Leo Weppelman (atari driver: ncr5380.c)
! 67: * There are others too. Thanks, everyone.
! 68: */
! 69:
! 70: #include <sys/types.h>
! 71: #include <sys/param.h>
! 72: #include <sys/systm.h>
! 73: #include <sys/kernel.h>
! 74: #include <sys/errno.h>
! 75: #include <sys/device.h>
! 76: #include <sys/buf.h>
! 77: #include <sys/proc.h>
! 78: #include <sys/user.h>
! 79:
! 80: #include <scsi/scsi_all.h>
! 81: #include <scsi/scsi_debug.h>
! 82: #include <scsi/scsi_message.h>
! 83: #include <scsi/scsiconf.h>
! 84:
! 85: #ifdef DDB
! 86: #include <ddb/db_output.h>
! 87: #endif
! 88:
! 89: #include <dev/ic/ncr5380reg.h>
! 90: #include <dev/ic/ncr5380var.h>
! 91:
! 92: static void ncr5380_sched(struct ncr5380_softc *);
! 93: static void ncr5380_done(struct ncr5380_softc *);
! 94:
! 95: static int ncr5380_select(struct ncr5380_softc *, struct sci_req *);
! 96: static void ncr5380_reselect(struct ncr5380_softc *);
! 97:
! 98: static int ncr5380_msg_in(struct ncr5380_softc *);
! 99: static int ncr5380_msg_out(struct ncr5380_softc *);
! 100: static int ncr5380_data_xfer(struct ncr5380_softc *, int);
! 101: static int ncr5380_command(struct ncr5380_softc *);
! 102: static int ncr5380_status(struct ncr5380_softc *);
! 103: static void ncr5380_machine(struct ncr5380_softc *);
! 104:
! 105: void ncr5380_abort(struct ncr5380_softc *);
! 106: void ncr5380_cmd_timeout(void *);
! 107: /*
! 108: * Action flags returned by the info_transfer functions:
! 109: * (These determine what happens next.)
! 110: */
! 111: #define ACT_CONTINUE 0x00 /* No flags: expect another phase */
! 112: #define ACT_DISCONNECT 0x01 /* Target is disconnecting */
! 113: #define ACT_CMD_DONE 0x02 /* Need to call scsi_done() */
! 114: #define ACT_RESET_BUS 0x04 /* Need bus reset (cmd timeout) */
! 115: #define ACT_WAIT_DMA 0x10 /* Wait for DMA to complete */
! 116:
! 117: /*****************************************************************
! 118: * Debugging stuff
! 119: *****************************************************************/
! 120:
! 121: #ifndef DDB
! 122: /* This is used only in recoverable places. */
! 123: #define Debugger() printf("Debug: ncr5380.c:%d\n", __LINE__)
! 124: #endif
! 125:
! 126: #ifdef NCR5380_DEBUG
! 127:
! 128: #define NCR_DBG_BREAK 1
! 129: #define NCR_DBG_CMDS 2
! 130: int ncr5380_debug = NCR_DBG_BREAK|NCR_DBG_CMDS;
! 131: struct ncr5380_softc *ncr5380_debug_sc;
! 132:
! 133: #define NCR_BREAK() \
! 134: do { if (ncr5380_debug & NCR_DBG_BREAK) Debugger(); } while (0)
! 135:
! 136: static void ncr5380_show_scsi_cmd(struct scsi_xfer *);
! 137: static void ncr5380_show_sense(struct scsi_xfer *);
! 138:
! 139: #ifdef DDB
! 140: void ncr5380_trace(char *, long);
! 141: void ncr5380_clear_trace(void);
! 142: void ncr5380_show_trace(void);
! 143: void ncr5380_show_req(struct sci_req *);
! 144: void ncr5380_show_req(struct sci_req *);
! 145: void ncr5380_show_state(void);
! 146: #endif /* DDB */
! 147: #else /* NCR5380_DEBUG */
! 148:
! 149: #define NCR_BREAK() /* nada */
! 150: #define ncr5380_show_scsi_cmd(xs) /* nada */
! 151: #define ncr5380_show_sense(xs) /* nada */
! 152:
! 153: #endif /* NCR5380_DEBUG */
! 154:
! 155: static char *
! 156: phase_names[8] = {
! 157: "DATA_OUT",
! 158: "DATA_IN",
! 159: "COMMAND",
! 160: "STATUS",
! 161: "UNSPEC1",
! 162: "UNSPEC2",
! 163: "MSG_OUT",
! 164: "MSG_IN",
! 165: };
! 166:
! 167: /*****************************************************************
! 168: * Actual chip control
! 169: *****************************************************************/
! 170:
! 171: /*
! 172: * XXX: These timeouts might need to be tuned...
! 173: */
! 174:
! 175: /* This one is used when waiting for a phase change. (X100uS.) */
! 176: int ncr5380_wait_phase_timo = 1000 * 10 * 300; /* 5 min. */
! 177:
! 178: /* These are used in the following inline functions. */
! 179: int ncr5380_wait_req_timo = 1000 * 50; /* X2 = 100 mS. */
! 180: int ncr5380_wait_nrq_timo = 1000 * 25; /* X2 = 50 mS. */
! 181:
! 182: static __inline int ncr5380_wait_req(struct ncr5380_softc *);
! 183: static __inline int ncr5380_wait_not_req(struct ncr5380_softc *);
! 184: static __inline void ncr_sched_msgout(struct ncr5380_softc *, int);
! 185:
! 186: /* Return zero on success. */
! 187: static __inline int ncr5380_wait_req(sc)
! 188: struct ncr5380_softc *sc;
! 189: {
! 190: register int timo = ncr5380_wait_req_timo;
! 191: for (;;) {
! 192: if (*sc->sci_bus_csr & SCI_BUS_REQ) {
! 193: timo = 0; /* return 0 */
! 194: break;
! 195: }
! 196: if (--timo < 0)
! 197: break; /* return -1 */
! 198: delay(2);
! 199: }
! 200: return (timo);
! 201: }
! 202:
! 203: /* Return zero on success. */
! 204: static __inline int ncr5380_wait_not_req(sc)
! 205: struct ncr5380_softc *sc;
! 206: {
! 207: register int timo = ncr5380_wait_nrq_timo;
! 208: for (;;) {
! 209: if ((*sc->sci_bus_csr & SCI_BUS_REQ) == 0) {
! 210: timo = 0; /* return 0 */
! 211: break;
! 212: }
! 213: if (--timo < 0)
! 214: break; /* return -1 */
! 215: delay(2);
! 216: }
! 217: return (timo);
! 218: }
! 219:
! 220: /* Ask the target for a MSG_OUT phase. */
! 221: static __inline void
! 222: ncr_sched_msgout(sc, msg_code)
! 223: struct ncr5380_softc *sc;
! 224: int msg_code;
! 225: {
! 226: /* First time, raise ATN line. */
! 227: if (sc->sc_msgpriq == 0) {
! 228: register u_char icmd;
! 229: icmd = *sc->sci_icmd & SCI_ICMD_RMASK;
! 230: *sc->sci_icmd = icmd | SCI_ICMD_ATN;
! 231: delay(2);
! 232: }
! 233: sc->sc_msgpriq |= msg_code;
! 234: }
! 235:
! 236:
! 237: int
! 238: ncr5380_pio_out(sc, phase, count, data)
! 239: struct ncr5380_softc *sc;
! 240: int phase, count;
! 241: unsigned char *data;
! 242: {
! 243: register u_char icmd;
! 244: register int resid;
! 245: register int error;
! 246:
! 247: icmd = *(sc->sci_icmd) & SCI_ICMD_RMASK;
! 248:
! 249: icmd |= SCI_ICMD_DATA;
! 250: *sc->sci_icmd = icmd;
! 251:
! 252: resid = count;
! 253: while (resid > 0) {
! 254: if (!SCI_BUSY(sc)) {
! 255: NCR_TRACE("pio_out: lost BSY, resid=%d\n", resid);
! 256: break;
! 257: }
! 258: if (ncr5380_wait_req(sc)) {
! 259: NCR_TRACE("pio_out: no REQ, resid=%d\n", resid);
! 260: break;
! 261: }
! 262: if (SCI_BUS_PHASE(*sc->sci_bus_csr) != phase)
! 263: break;
! 264:
! 265: /* Put the data on the bus. */
! 266: if (data)
! 267: *sc->sci_odata = *data++;
! 268: else
! 269: *sc->sci_odata = 0;
! 270:
! 271: /* Tell the target it's there. */
! 272: icmd |= SCI_ICMD_ACK;
! 273: *sc->sci_icmd = icmd;
! 274:
! 275: /* Wait for target to get it. */
! 276: error = ncr5380_wait_not_req(sc);
! 277:
! 278: /* OK, it's got it (or we gave up waiting). */
! 279: icmd &= ~SCI_ICMD_ACK;
! 280: *sc->sci_icmd = icmd;
! 281:
! 282: if (error) {
! 283: NCR_TRACE("pio_out: stuck REQ, resid=%d\n", resid);
! 284: break;
! 285: }
! 286:
! 287: --resid;
! 288: }
! 289:
! 290: /* Stop driving the data bus. */
! 291: icmd &= ~SCI_ICMD_DATA;
! 292: *sc->sci_icmd = icmd;
! 293:
! 294: return (count - resid);
! 295: }
! 296:
! 297:
! 298: int
! 299: ncr5380_pio_in(sc, phase, count, data)
! 300: struct ncr5380_softc *sc;
! 301: int phase, count;
! 302: unsigned char *data;
! 303: {
! 304: register u_char icmd;
! 305: register int resid;
! 306: register int error;
! 307:
! 308: icmd = *(sc->sci_icmd) & SCI_ICMD_RMASK;
! 309:
! 310: resid = count;
! 311: while (resid > 0) {
! 312: if (!SCI_BUSY(sc)) {
! 313: NCR_TRACE("pio_in: lost BSY, resid=%d\n", resid);
! 314: break;
! 315: }
! 316: if (ncr5380_wait_req(sc)) {
! 317: NCR_TRACE("pio_in: no REQ, resid=%d\n", resid);
! 318: break;
! 319: }
! 320: /* A phase change is not valid until AFTER REQ rises! */
! 321: if (SCI_BUS_PHASE(*sc->sci_bus_csr) != phase)
! 322: break;
! 323:
! 324: /* Read the data bus. */
! 325: if (data)
! 326: *data++ = *sc->sci_data;
! 327: else
! 328: (void) *sc->sci_data;
! 329:
! 330: /* Tell target we got it. */
! 331: icmd |= SCI_ICMD_ACK;
! 332: *sc->sci_icmd = icmd;
! 333:
! 334: /* Wait for target to drop REQ... */
! 335: error = ncr5380_wait_not_req(sc);
! 336:
! 337: /* OK, we can drop ACK. */
! 338: icmd &= ~SCI_ICMD_ACK;
! 339: *sc->sci_icmd = icmd;
! 340:
! 341: if (error) {
! 342: NCR_TRACE("pio_in: stuck REQ, resid=%d\n", resid);
! 343: break;
! 344: }
! 345:
! 346: --resid;
! 347: }
! 348:
! 349: return (count - resid);
! 350: }
! 351:
! 352:
! 353: void
! 354: ncr5380_init(sc)
! 355: struct ncr5380_softc *sc;
! 356: {
! 357: int i, j;
! 358: struct sci_req *sr;
! 359:
! 360: #ifdef NCR5380_DEBUG
! 361: ncr5380_debug_sc = sc;
! 362: #endif
! 363:
! 364: for (i = 0; i < SCI_OPENINGS; i++) {
! 365: sr = &sc->sc_ring[i];
! 366: sr->sr_xs = NULL;
! 367: timeout_set(&sr->sr_timeout, ncr5380_cmd_timeout, sr);
! 368: }
! 369: for (i = 0; i < 8; i++)
! 370: for (j = 0; j < 8; j++)
! 371: sc->sc_matrix[i][j] = NULL;
! 372:
! 373: sc->sc_link.openings = 2; /* XXX - Not SCI_OPENINGS */
! 374: sc->sc_prevphase = PHASE_INVALID;
! 375: sc->sc_state = NCR_IDLE;
! 376:
! 377: *sc->sci_tcmd = PHASE_INVALID;
! 378: *sc->sci_icmd = 0;
! 379: *sc->sci_mode = 0;
! 380: *sc->sci_sel_enb = 0;
! 381: SCI_CLR_INTR(sc);
! 382:
! 383: /* XXX: Enable reselect interrupts... */
! 384: *sc->sci_sel_enb = 0x80;
! 385:
! 386: /* Another hack (Er.. hook!) for the sun3 si: */
! 387: if (sc->sc_intr_on) {
! 388: NCR_TRACE("init: intr ON\n", 0);
! 389: sc->sc_intr_on(sc);
! 390: }
! 391: }
! 392:
! 393:
! 394: void
! 395: ncr5380_reset_scsibus(sc)
! 396: struct ncr5380_softc *sc;
! 397: {
! 398:
! 399: NCR_TRACE("reset_scsibus, cur=0x%x\n",
! 400: (long) sc->sc_current);
! 401:
! 402: *sc->sci_icmd = SCI_ICMD_RST;
! 403: delay(500);
! 404: *sc->sci_icmd = 0;
! 405:
! 406: *sc->sci_mode = 0;
! 407: *sc->sci_tcmd = PHASE_INVALID;
! 408:
! 409: SCI_CLR_INTR(sc);
! 410: /* XXX - Need long delay here! */
! 411: delay(100000);
! 412:
! 413: /* XXX - Need to cancel disconnected requests. */
! 414: }
! 415:
! 416:
! 417: /*
! 418: * Interrupt handler for the SCSI Bus Controller (SBC)
! 419: * This may also called for a DMA timeout (at splbio).
! 420: */
! 421: int
! 422: ncr5380_intr(sc)
! 423: struct ncr5380_softc *sc;
! 424: {
! 425: int claimed = 0;
! 426:
! 427: /*
! 428: * Do not touch SBC regs here unless sc_current == NULL
! 429: * or it will complain about "register conflict" errors.
! 430: * Instead, just let ncr5380_machine() deal with it.
! 431: */
! 432: NCR_TRACE("intr: top, state=%d\n", sc->sc_state);
! 433:
! 434: if (sc->sc_state == NCR_IDLE) {
! 435: /*
! 436: * Might be reselect. ncr5380_reselect() will check,
! 437: * and set up the connection if so. This will verify
! 438: * that sc_current == NULL at the beginning...
! 439: */
! 440:
! 441: /* Another hack (Er.. hook!) for the sun3 si: */
! 442: if (sc->sc_intr_off) {
! 443: NCR_TRACE("intr: for reselect, intr off\n", 0);
! 444: sc->sc_intr_off(sc);
! 445: }
! 446:
! 447: ncr5380_reselect(sc);
! 448: }
! 449:
! 450: /*
! 451: * The remaining documented interrupt causes are phase mismatch and
! 452: * disconnect. In addition, the sunsi controller may produce a state
! 453: * where SCI_CSR_DONE is false, yet DMA is complete.
! 454: *
! 455: * The procedure in all these cases is to let ncr5380_machine()
! 456: * figure out what to do next.
! 457: */
! 458: if (sc->sc_state & NCR_WORKING) {
! 459: NCR_TRACE("intr: call machine, cur=0x%x\n",
! 460: (long) sc->sc_current);
! 461: /* This will usually free-up the nexus. */
! 462: ncr5380_machine(sc);
! 463: NCR_TRACE("intr: machine done, cur=0x%x\n",
! 464: (long) sc->sc_current);
! 465: claimed = 1;
! 466: }
! 467:
! 468: /* Maybe we can run some commands now... */
! 469: if (sc->sc_state == NCR_IDLE) {
! 470: NCR_TRACE("intr: call sched, cur=0x%x\n",
! 471: (long) sc->sc_current);
! 472: ncr5380_sched(sc);
! 473: NCR_TRACE("intr: sched done, cur=0x%x\n",
! 474: (long) sc->sc_current);
! 475: }
! 476:
! 477: return claimed;
! 478: }
! 479:
! 480:
! 481: /*
! 482: * Abort the current command (i.e. due to timeout)
! 483: */
! 484: void
! 485: ncr5380_abort(sc)
! 486: struct ncr5380_softc *sc;
! 487: {
! 488:
! 489: /*
! 490: * Finish it now. If DMA is in progress, we
! 491: * can not call ncr_sched_msgout() because
! 492: * that hits the SBC (avoid DMA conflict).
! 493: */
! 494:
! 495: /* Another hack (Er.. hook!) for the sun3 si: */
! 496: if (sc->sc_intr_off) {
! 497: NCR_TRACE("abort: intr off\n", 0);
! 498: sc->sc_intr_off(sc);
! 499: }
! 500:
! 501: sc->sc_state |= NCR_ABORTING;
! 502: if ((sc->sc_state & NCR_DOINGDMA) == 0) {
! 503: ncr_sched_msgout(sc, SEND_ABORT);
! 504: }
! 505: NCR_TRACE("abort: call machine, cur=0x%x\n",
! 506: (long) sc->sc_current);
! 507: ncr5380_machine(sc);
! 508: NCR_TRACE("abort: machine done, cur=0x%x\n",
! 509: (long) sc->sc_current);
! 510:
! 511: /* Another hack (Er.. hook!) for the sun3 si: */
! 512: if (sc->sc_intr_on) {
! 513: NCR_TRACE("abort: intr ON\n", 0);
! 514: sc->sc_intr_on(sc);
! 515: }
! 516: }
! 517:
! 518: /*
! 519: * Timeout handler, scheduled for each SCSI command.
! 520: */
! 521: void
! 522: ncr5380_cmd_timeout(arg)
! 523: void *arg;
! 524: {
! 525: struct sci_req *sr = arg;
! 526: struct scsi_xfer *xs;
! 527: struct scsi_link *sc_link;
! 528: struct ncr5380_softc *sc;
! 529: int s;
! 530:
! 531: s = splbio();
! 532:
! 533: /* Get all our variables... */
! 534: xs = sr->sr_xs;
! 535: if (xs == NULL) {
! 536: printf("ncr5380_cmd_timeout: no scsi_xfer\n");
! 537: goto out;
! 538: }
! 539: sc_link = xs->sc_link;
! 540: sc = sc_link->adapter_softc;
! 541:
! 542: printf("%s: cmd timeout, targ=%d, lun=%d\n",
! 543: sc->sc_dev.dv_xname,
! 544: sr->sr_target, sr->sr_lun);
! 545:
! 546: /*
! 547: * Mark the overdue job as failed, and arrange for
! 548: * ncr5380_machine to terminate it. If the victim
! 549: * is the current job, call ncr5380_machine() now.
! 550: * Otherwise arrange for ncr5380_sched() to do it.
! 551: */
! 552: sr->sr_flags |= SR_OVERDUE;
! 553: if (sc->sc_current == sr) {
! 554: NCR_TRACE("cmd_tmo: call abort, sr=0x%x\n", (long) sr);
! 555: ncr5380_abort(sc);
! 556: } else {
! 557: /*
! 558: * The driver may be idle, or busy with another job.
! 559: * Arrange for ncr5380_sched() to do the deed.
! 560: */
! 561: NCR_TRACE("cmd_tmo: clear matrix, t/l=0x%02x\n",
! 562: (sr->sr_target << 4) | sr->sr_lun);
! 563: sc->sc_matrix[sr->sr_target][sr->sr_lun] = NULL;
! 564: }
! 565:
! 566: /*
! 567: * We may have aborted the current job, or may have
! 568: * already been idle. In either case, we should now
! 569: * be idle, so try to start another job.
! 570: */
! 571: if (sc->sc_state == NCR_IDLE) {
! 572: NCR_TRACE("cmd_tmo: call sched, cur=0x%x\n",
! 573: (long) sc->sc_current);
! 574: ncr5380_sched(sc);
! 575: NCR_TRACE("cmd_tmo: sched done, cur=0x%x\n",
! 576: (long) sc->sc_current);
! 577: }
! 578:
! 579: out:
! 580: splx(s);
! 581: }
! 582:
! 583:
! 584: /*****************************************************************
! 585: * Interface to higher level
! 586: *****************************************************************/
! 587:
! 588:
! 589: /*
! 590: * Enter a new SCSI command into the "issue" queue, and
! 591: * if there is work to do, start it going.
! 592: *
! 593: * WARNING: This can be called recursively!
! 594: * (see comment in ncr5380_done)
! 595: */
! 596: int
! 597: ncr5380_scsi_cmd(xs)
! 598: struct scsi_xfer *xs;
! 599: {
! 600: struct ncr5380_softc *sc;
! 601: struct sci_req *sr;
! 602: int s, rv, i, flags;
! 603:
! 604: sc = xs->sc_link->adapter_softc;
! 605: flags = xs->flags;
! 606:
! 607: if (sc->sc_flags & NCR5380_FORCE_POLLING)
! 608: flags |= SCSI_POLL;
! 609:
! 610: if (flags & SCSI_DATA_UIO)
! 611: panic("ncr5380: scsi data uio requested");
! 612:
! 613: s = splbio();
! 614:
! 615: if (flags & SCSI_POLL) {
! 616: /* Terminate any current command. */
! 617: sr = sc->sc_current;
! 618: if (sr) {
! 619: printf("%s: polled request aborting %d/%d\n",
! 620: sc->sc_dev.dv_xname,
! 621: sr->sr_target, sr->sr_lun);
! 622: ncr5380_abort(sc);
! 623: }
! 624: if (sc->sc_state != NCR_IDLE) {
! 625: panic("ncr5380_scsi_cmd: polled request, abort failed");
! 626: }
! 627: }
! 628:
! 629: /*
! 630: * Find lowest empty slot in ring buffer.
! 631: * XXX: What about "fairness" and cmd order?
! 632: */
! 633: for (i = 0; i < SCI_OPENINGS; i++)
! 634: if (sc->sc_ring[i].sr_xs == NULL)
! 635: goto new;
! 636:
! 637: rv = TRY_AGAIN_LATER;
! 638: NCR_TRACE("scsi_cmd: no openings, rv=%d\n", rv);
! 639: goto out;
! 640:
! 641: new:
! 642: /* Create queue entry */
! 643: sr = &sc->sc_ring[i];
! 644: sr->sr_xs = xs;
! 645: sr->sr_target = xs->sc_link->target;
! 646: sr->sr_lun = xs->sc_link->lun;
! 647: sr->sr_dma_hand = NULL;
! 648: sr->sr_dataptr = xs->data;
! 649: sr->sr_datalen = xs->datalen;
! 650: sr->sr_flags = (flags & SCSI_POLL) ? SR_IMMED : 0;
! 651: sr->sr_status = -1; /* no value */
! 652: sc->sc_ncmds++;
! 653: rv = SUCCESSFULLY_QUEUED;
! 654:
! 655: NCR_TRACE("scsi_cmd: new sr=0x%x\n", (long)sr);
! 656:
! 657: if (flags & SCSI_POLL) {
! 658: /* Force this new command to be next. */
! 659: sc->sc_rr = i;
! 660: }
! 661:
! 662: /*
! 663: * If we were idle, run some commands...
! 664: */
! 665: if (sc->sc_state == NCR_IDLE) {
! 666: NCR_TRACE("scsi_cmd: call sched, cur=0x%x\n",
! 667: (long) sc->sc_current);
! 668: ncr5380_sched(sc);
! 669: NCR_TRACE("scsi_cmd: sched done, cur=0x%x\n",
! 670: (long) sc->sc_current);
! 671: }
! 672:
! 673: if (flags & SCSI_POLL) {
! 674: #ifdef DIAGNOSTIC
! 675: /* Make sure ncr5380_sched() finished it. */
! 676: if (sc->sc_state != NCR_IDLE)
! 677: panic("ncr5380_scsi_cmd: poll didn't finish");
! 678: #endif
! 679: rv = COMPLETE;
! 680: }
! 681:
! 682: out:
! 683: splx(s);
! 684: return (rv);
! 685: }
! 686:
! 687:
! 688: /*
! 689: * POST PROCESSING OF SCSI_CMD (usually current)
! 690: * Called by ncr5380_sched(), ncr5380_machine()
! 691: */
! 692: static void
! 693: ncr5380_done(sc)
! 694: struct ncr5380_softc *sc;
! 695: {
! 696: struct sci_req *sr;
! 697: struct scsi_xfer *xs;
! 698:
! 699: #ifdef DIAGNOSTIC
! 700: if (sc->sc_state == NCR_IDLE)
! 701: panic("ncr5380_done: state=idle");
! 702: if (sc->sc_current == NULL)
! 703: panic("ncr5380_done: current=0");
! 704: #endif
! 705:
! 706: sr = sc->sc_current;
! 707: xs = sr->sr_xs;
! 708:
! 709: NCR_TRACE("done: top, cur=0x%x\n", (long) sc->sc_current);
! 710:
! 711: /*
! 712: * Clean up DMA resources for this command.
! 713: */
! 714: if (sr->sr_dma_hand) {
! 715: NCR_TRACE("done: dma_free, dh=0x%x\n",
! 716: (long) sr->sr_dma_hand);
! 717: (*sc->sc_dma_free)(sc);
! 718: }
! 719: #ifdef DIAGNOSTIC
! 720: if (sr->sr_dma_hand)
! 721: panic("ncr5380_done: dma free did not");
! 722: #endif
! 723:
! 724: if (sc->sc_state & NCR_ABORTING) {
! 725: NCR_TRACE("done: aborting, error=%d\n", xs->error);
! 726: if (xs->error == XS_NOERROR)
! 727: xs->error = XS_TIMEOUT;
! 728: }
! 729:
! 730: NCR_TRACE("done: check error=%d\n", (long) xs->error);
! 731:
! 732: /* If error is already set, ignore sr_status value. */
! 733: if (xs->error != XS_NOERROR)
! 734: goto finish;
! 735:
! 736: NCR_TRACE("done: check status=%d\n", sr->sr_status);
! 737:
! 738: switch (sr->sr_status) {
! 739: case SCSI_OK: /* 0 */
! 740: if (sr->sr_flags & SR_SENSE) {
! 741: #ifdef NCR5380_DEBUG
! 742: if (ncr5380_debug & NCR_DBG_CMDS) {
! 743: ncr5380_show_sense(xs);
! 744: }
! 745: #endif
! 746: xs->error = XS_SENSE;
! 747: }
! 748: break;
! 749:
! 750: case SCSI_CHECK:
! 751: if (sr->sr_flags & SR_SENSE) {
! 752: /* Sense command also asked for sense? */
! 753: printf("ncr5380_done: sense asked for sense\n");
! 754: NCR_BREAK();
! 755: xs->error = XS_DRIVER_STUFFUP;
! 756: break;
! 757: }
! 758: sr->sr_flags |= SR_SENSE;
! 759: NCR_TRACE("done: get sense, sr=0x%x\n", (long) sr);
! 760: /*
! 761: * Leave queued, but clear sc_current so we start over
! 762: * with selection. Guaranteed to get the same request.
! 763: */
! 764: sc->sc_state = NCR_IDLE;
! 765: sc->sc_current = NULL;
! 766: sc->sc_matrix[sr->sr_target][sr->sr_lun] = NULL;
! 767: return; /* XXX */
! 768:
! 769: case SCSI_BUSY:
! 770: xs->error = XS_BUSY;
! 771: break;
! 772:
! 773: case -1:
! 774: /* This is our "impossible" initial value. */
! 775: /* fallthrough */
! 776: default:
! 777: printf("%s: target %d, bad status=%d\n",
! 778: sc->sc_dev.dv_xname, sr->sr_target, sr->sr_status);
! 779: xs->error = XS_DRIVER_STUFFUP;
! 780: break;
! 781: }
! 782:
! 783: finish:
! 784:
! 785: NCR_TRACE("done: finish, error=%d\n", xs->error);
! 786:
! 787: /*
! 788: * Dequeue the finished command, but don't clear sc_state until
! 789: * after the call to scsi_done(), because that may call back to
! 790: * ncr5380_scsi_cmd() - unwanted recursion!
! 791: *
! 792: * Keeping sc->sc_state != idle terminates the recursion.
! 793: */
! 794: #ifdef DIAGNOSTIC
! 795: if ((sc->sc_state & NCR_WORKING) == 0)
! 796: panic("ncr5380_done: bad state");
! 797: #endif
! 798:
! 799: /* Clear our pointers to the request. */
! 800: sc->sc_current = NULL;
! 801: sc->sc_matrix[sr->sr_target][sr->sr_lun] = NULL;
! 802: timeout_del(&sr->sr_timeout);
! 803:
! 804: /* Make the request free. */
! 805: sr->sr_xs = NULL;
! 806: sc->sc_ncmds--;
! 807:
! 808: /* Tell common SCSI code it is done. */
! 809: xs->flags |= ITSDONE;
! 810: scsi_done(xs);
! 811:
! 812: sc->sc_state = NCR_IDLE;
! 813: /* Now ncr5380_sched() may be called again. */
! 814: }
! 815:
! 816:
! 817: /*
! 818: * Schedule a SCSI operation. This routine should return
! 819: * only after it achieves one of the following conditions:
! 820: * Busy (sc->sc_state != NCR_IDLE)
! 821: * No more work can be started.
! 822: */
! 823: static void
! 824: ncr5380_sched(sc)
! 825: struct ncr5380_softc *sc;
! 826: {
! 827: struct sci_req *sr;
! 828: struct scsi_xfer *xs;
! 829: int target = 0, lun = 0;
! 830: int error, i;
! 831:
! 832: /* Another hack (Er.. hook!) for the sun3 si: */
! 833: if (sc->sc_intr_off) {
! 834: NCR_TRACE("sched: top, intr off\n", 0);
! 835: sc->sc_intr_off(sc);
! 836: }
! 837:
! 838: next_job:
! 839: /*
! 840: * Grab the next job from queue. Must be idle.
! 841: */
! 842: #ifdef DIAGNOSTIC
! 843: if (sc->sc_state != NCR_IDLE)
! 844: panic("ncr5380_sched: not idle");
! 845: if (sc->sc_current)
! 846: panic("ncr5380_sched: current set");
! 847: #endif
! 848:
! 849: /*
! 850: * Always start the search where we last looked.
! 851: * The REQUEST_SENSE logic depends on this to
! 852: * choose the same job as was last picked, so it
! 853: * can just clear sc_current and reschedule.
! 854: * (Avoids loss of "contingent allegiance".)
! 855: */
! 856: i = sc->sc_rr;
! 857: sr = NULL;
! 858: do {
! 859: if (sc->sc_ring[i].sr_xs) {
! 860: target = sc->sc_ring[i].sr_target;
! 861: lun = sc->sc_ring[i].sr_lun;
! 862: if (sc->sc_matrix[target][lun] == NULL) {
! 863: /*
! 864: * Do not mark the target/LUN busy yet,
! 865: * because reselect may cause some other
! 866: * job to become the current one, so we
! 867: * might not actually start this job.
! 868: * Instead, set sc_matrix later on.
! 869: */
! 870: sc->sc_rr = i;
! 871: sr = &sc->sc_ring[i];
! 872: break;
! 873: }
! 874: }
! 875: i++;
! 876: if (i == SCI_OPENINGS)
! 877: i = 0;
! 878: } while (i != sc->sc_rr);
! 879:
! 880: if (sr == NULL) {
! 881: NCR_TRACE("sched: no work, cur=0x%x\n",
! 882: (long) sc->sc_current);
! 883:
! 884: /* Another hack (Er.. hook!) for the sun3 si: */
! 885: if (sc->sc_intr_on) {
! 886: NCR_TRACE("sched: ret, intr ON\n", 0);
! 887: sc->sc_intr_on(sc);
! 888: }
! 889:
! 890: return; /* No more work to do. */
! 891: }
! 892:
! 893: NCR_TRACE("sched: select for t/l=0x%02x\n",
! 894: (sr->sr_target << 4) | sr->sr_lun);
! 895:
! 896: sc->sc_state = NCR_WORKING;
! 897: error = ncr5380_select(sc, sr);
! 898: if (sc->sc_current) {
! 899: /* Lost the race! reselected out from under us! */
! 900: /* Work with the reselected job. */
! 901: if (sr->sr_flags & SR_IMMED) {
! 902: printf("%s: reselected while polling (abort)\n",
! 903: sc->sc_dev.dv_xname);
! 904: /* Abort the reselected job. */
! 905: sc->sc_state |= NCR_ABORTING;
! 906: sc->sc_msgpriq |= SEND_ABORT;
! 907: }
! 908: sr = sc->sc_current;
! 909: xs = sr->sr_xs;
! 910: NCR_TRACE("sched: reselect, new sr=0x%x\n", (long)sr);
! 911: goto have_nexus;
! 912: }
! 913:
! 914: /* Normal selection result. Target/LUN is now busy. */
! 915: sc->sc_matrix[target][lun] = sr;
! 916: sc->sc_current = sr; /* connected */
! 917: xs = sr->sr_xs;
! 918:
! 919: /*
! 920: * Initialize pointers, etc. for this job
! 921: */
! 922: sc->sc_dataptr = sr->sr_dataptr;
! 923: sc->sc_datalen = sr->sr_datalen;
! 924: sc->sc_prevphase = PHASE_INVALID;
! 925: sc->sc_msgpriq = SEND_IDENTIFY;
! 926: sc->sc_msgoutq = 0;
! 927: sc->sc_msgout = 0;
! 928:
! 929: NCR_TRACE("sched: select rv=%d\n", error);
! 930:
! 931: switch (error) {
! 932: case XS_NOERROR:
! 933: break;
! 934:
! 935: case XS_BUSY:
! 936: /* XXX - Reset and try again. */
! 937: printf("%s: select found SCSI bus busy, resetting...\n",
! 938: sc->sc_dev.dv_xname);
! 939: ncr5380_reset_scsibus(sc);
! 940: /* fallthrough */
! 941: case XS_SELTIMEOUT:
! 942: default:
! 943: xs->error = error; /* from select */
! 944: NCR_TRACE("sched: call done, sr=0x%x\n", (long)sr);
! 945: ncr5380_done(sc);
! 946:
! 947: /* Paranoia: clear everything. */
! 948: sc->sc_dataptr = NULL;
! 949: sc->sc_datalen = 0;
! 950: sc->sc_prevphase = PHASE_INVALID;
! 951: sc->sc_msgpriq = 0;
! 952: sc->sc_msgoutq = 0;
! 953: sc->sc_msgout = 0;
! 954:
! 955: goto next_job;
! 956: }
! 957:
! 958: /*
! 959: * Selection was successful. Normally, this means
! 960: * we are starting a new command. However, this
! 961: * might be the termination of an overdue job.
! 962: */
! 963: if (sr->sr_flags & SR_OVERDUE) {
! 964: NCR_TRACE("sched: overdue, sr=0x%x\n", (long)sr);
! 965: sc->sc_state |= NCR_ABORTING;
! 966: sc->sc_msgpriq |= SEND_ABORT;
! 967: goto have_nexus;
! 968: }
! 969:
! 970: /*
! 971: * This may be the continuation of some job that
! 972: * completed with a "check condition" code.
! 973: */
! 974: if (sr->sr_flags & SR_SENSE) {
! 975: NCR_TRACE("sched: get sense, sr=0x%x\n", (long)sr);
! 976: /* Do not allocate DMA, nor set timeout. */
! 977: goto have_nexus;
! 978: }
! 979:
! 980: /*
! 981: * OK, we are starting a new command.
! 982: * Initialize and allocate resources for the new command.
! 983: * Device reset is special (only uses MSG_OUT phase).
! 984: * Normal commands start in MSG_OUT phase where we will
! 985: * send and IDENDIFY message, and then expect CMD phase.
! 986: */
! 987: #ifdef NCR5380_DEBUG
! 988: if (ncr5380_debug & NCR_DBG_CMDS) {
! 989: printf("ncr5380_sched: begin, target=%d, LUN=%d\n",
! 990: xs->sc_link->target, xs->sc_link->lun);
! 991: ncr5380_show_scsi_cmd(xs);
! 992: }
! 993: #endif
! 994: if (xs->flags & SCSI_RESET) {
! 995: NCR_TRACE("sched: cmd=reset, sr=0x%x\n", (long)sr);
! 996: /* Not an error, so do not set NCR_ABORTING */
! 997: sc->sc_msgpriq |= SEND_DEV_RESET;
! 998: goto have_nexus;
! 999: }
! 1000:
! 1001: #ifdef DIAGNOSTIC
! 1002: if ((xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) == 0) {
! 1003: if (sc->sc_dataptr) {
! 1004: printf("%s: ptr but no data in/out flags?\n",
! 1005: sc->sc_dev.dv_xname);
! 1006: NCR_BREAK();
! 1007: sc->sc_dataptr = NULL;
! 1008: }
! 1009: }
! 1010: #endif
! 1011:
! 1012: /* Allocate DMA space (maybe) */
! 1013: if (sc->sc_dataptr && sc->sc_dma_alloc &&
! 1014: (sc->sc_datalen >= sc->sc_min_dma_len))
! 1015: {
! 1016: NCR_TRACE("sched: dma_alloc, len=%d\n", sc->sc_datalen);
! 1017: (*sc->sc_dma_alloc)(sc);
! 1018: }
! 1019:
! 1020: /*
! 1021: * Initialization hook called just after select,
! 1022: * at the beginning of COMMAND phase.
! 1023: * (but AFTER the DMA allocation is done)
! 1024: *
! 1025: * The evil Sun "si" adapter (OBIO variant) needs some
! 1026: * setup done to the DMA engine BEFORE the target puts
! 1027: * the SCSI bus into any DATA phase.
! 1028: */
! 1029: if (sr->sr_dma_hand && sc->sc_dma_setup) {
! 1030: NCR_TRACE("sched: dma_setup, dh=0x%x\n",
! 1031: (long) sr->sr_dma_hand);
! 1032: sc->sc_dma_setup(sc);
! 1033: }
! 1034:
! 1035: /*
! 1036: * Schedule a timeout for the job we are starting.
! 1037: */
! 1038: if ((sr->sr_flags & SR_IMMED) == 0) {
! 1039: i = (xs->timeout * hz) / 1000;
! 1040: NCR_TRACE("sched: set timeout=%d\n", i);
! 1041: timeout_add(&sr->sr_timeout, i);
! 1042: }
! 1043:
! 1044: have_nexus:
! 1045: NCR_TRACE("sched: call machine, cur=0x%x\n",
! 1046: (long) sc->sc_current);
! 1047: ncr5380_machine(sc);
! 1048: NCR_TRACE("sched: machine done, cur=0x%x\n",
! 1049: (long) sc->sc_current);
! 1050:
! 1051: /*
! 1052: * What state did ncr5380_machine() leave us in?
! 1053: * Hopefully it sometimes completes a job...
! 1054: */
! 1055: if (sc->sc_state == NCR_IDLE)
! 1056: goto next_job;
! 1057:
! 1058: return; /* Have work in progress. */
! 1059: }
! 1060:
! 1061:
! 1062: /*
! 1063: * Reselect handler: checks for reselection, and if we are being
! 1064: * reselected, it sets up sc->sc_current.
! 1065: *
! 1066: * We are reselected when:
! 1067: * SEL is TRUE
! 1068: * IO is TRUE
! 1069: * BSY is FALSE
! 1070: */
! 1071: void
! 1072: ncr5380_reselect(sc)
! 1073: struct ncr5380_softc *sc;
! 1074: {
! 1075: struct sci_req *sr;
! 1076: int target, lun, phase, timo;
! 1077: int target_mask;
! 1078: u_char bus, data, icmd, msg;
! 1079:
! 1080: #ifdef DIAGNOSTIC
! 1081: /*
! 1082: * Note: sc_state will be "idle" when ncr5380_intr()
! 1083: * calls, or "working" when ncr5380_select() calls.
! 1084: * (So don't test that in this DIAGNOSTIC)
! 1085: */
! 1086: if (sc->sc_current)
! 1087: panic("ncr5380_reselect: current set");
! 1088: #endif
! 1089:
! 1090: /*
! 1091: * First, check the select line.
! 1092: * (That has to be set first.)
! 1093: */
! 1094: bus = *(sc->sci_bus_csr);
! 1095: if ((bus & SCI_BUS_SEL) == 0) {
! 1096: /* Not a selection or reselection. */
! 1097: return;
! 1098: }
! 1099:
! 1100: /*
! 1101: * The target will assert BSY first (for bus arbitration),
! 1102: * then raise SEL, and finally drop BSY. Only then is the
! 1103: * data bus required to have valid selection ID bits set.
! 1104: * Wait for: SEL==1, BSY==0 before reading the data bus.
! 1105: * While this theoretically can happen, we are apparently
! 1106: * never fast enough to get here before BSY drops.
! 1107: */
! 1108: timo = ncr5380_wait_nrq_timo;
! 1109: for (;;) {
! 1110: if ((bus & SCI_BUS_BSY) == 0)
! 1111: break;
! 1112: /* Probably never get here... */
! 1113: if (--timo <= 0) {
! 1114: printf("%s: reselect, BSY stuck, bus=0x%x\n",
! 1115: sc->sc_dev.dv_xname, bus);
! 1116: /* Not much we can do. Reset the bus. */
! 1117: ncr5380_reset_scsibus(sc);
! 1118: return;
! 1119: }
! 1120: delay(2);
! 1121: bus = *(sc->sci_bus_csr);
! 1122: /* If SEL went away, forget it. */
! 1123: if ((bus & SCI_BUS_SEL) == 0)
! 1124: return;
! 1125: /* Still have SEL, check BSY. */
! 1126: }
! 1127: NCR_TRACE("reselect, valid data after %d loops\n",
! 1128: ncr5380_wait_nrq_timo - timo);
! 1129:
! 1130: /*
! 1131: * Good. We have SEL=1 and BSY=0. Now wait for a
! 1132: * "bus settle delay" before we sample the data bus
! 1133: */
! 1134: delay(2);
! 1135: data = *(sc->sci_data) & 0xFF;
! 1136: /* Parity check is implicit in data validation below. */
! 1137:
! 1138: /*
! 1139: * Is this a reselect (I/O == 1) or have we been
! 1140: * selected as a target? (I/O == 0)
! 1141: */
! 1142: if ((bus & SCI_BUS_IO) == 0) {
! 1143: printf("%s: selected as target, data=0x%x\n",
! 1144: sc->sc_dev.dv_xname, data);
! 1145: /* Not much we can do. Reset the bus. */
! 1146: /* XXX: send some sort of message? */
! 1147: ncr5380_reset_scsibus(sc);
! 1148: return;
! 1149: }
! 1150:
! 1151: /*
! 1152: * OK, this is a reselection.
! 1153: */
! 1154: for (target = 0; target < 7; target++) {
! 1155: target_mask = (1 << target);
! 1156: if (data & target_mask)
! 1157: break;
! 1158: }
! 1159: if ((data & 0x7F) != target_mask) {
! 1160: /* No selecting ID? or >2 IDs on bus? */
! 1161: printf("%s: bad reselect, data=0x%x\n",
! 1162: sc->sc_dev.dv_xname, data);
! 1163: return;
! 1164: }
! 1165:
! 1166: NCR_TRACE("reselect: target=0x%x\n", target);
! 1167:
! 1168: /* Raise BSY to acknowledge target reselection. */
! 1169: *(sc->sci_icmd) = SCI_ICMD_BSY;
! 1170:
! 1171: /* Wait for target to drop SEL. */
! 1172: timo = ncr5380_wait_nrq_timo;
! 1173: for (;;) {
! 1174: bus = *(sc->sci_bus_csr);
! 1175: if ((bus & SCI_BUS_SEL) == 0)
! 1176: break; /* success */
! 1177: if (--timo <= 0) {
! 1178: printf("%s: reselect, SEL stuck, bus=0x%x\n",
! 1179: sc->sc_dev.dv_xname, bus);
! 1180: NCR_BREAK();
! 1181: /* assume connected (fail later if not) */
! 1182: break;
! 1183: }
! 1184: delay(2);
! 1185: }
! 1186:
! 1187: /* Now we drop BSY, and we are connected. */
! 1188: *(sc->sci_icmd) = 0;
! 1189: *sc->sci_sel_enb = 0;
! 1190: SCI_CLR_INTR(sc);
! 1191:
! 1192: /*
! 1193: * At this point the target should send an IDENTIFY message,
! 1194: * which will permit us to determine the reselecting LUN.
! 1195: * If not, we assume LUN 0.
! 1196: */
! 1197: lun = 0;
! 1198: /* Wait for REQ before reading bus phase. */
! 1199: if (ncr5380_wait_req(sc)) {
! 1200: printf("%s: reselect, no REQ\n",
! 1201: sc->sc_dev.dv_xname);
! 1202: /* Try to send an ABORT message. */
! 1203: goto abort;
! 1204: }
! 1205: phase = SCI_BUS_PHASE(*sc->sci_bus_csr);
! 1206: if (phase != PHASE_MSG_IN) {
! 1207: printf("%s: reselect, phase=%d\n",
! 1208: sc->sc_dev.dv_xname, phase);
! 1209: goto abort;
! 1210: }
! 1211:
! 1212: /* Ack. the change to PHASE_MSG_IN */
! 1213: *(sc->sci_tcmd) = PHASE_MSG_IN;
! 1214:
! 1215: /* Peek at the message byte without consuming it! */
! 1216: msg = *(sc->sci_data);
! 1217: if ((msg & 0x80) == 0) {
! 1218: printf("%s: reselect, not identify, msg=%d\n",
! 1219: sc->sc_dev.dv_xname, msg);
! 1220: goto abort;
! 1221: }
! 1222: lun = msg & 7;
! 1223:
! 1224: /* We now know target/LUN. Do we have the request? */
! 1225: sr = sc->sc_matrix[target][lun];
! 1226: if (sr) {
! 1227: /* We now have a nexus. */
! 1228: sc->sc_state |= NCR_WORKING;
! 1229: sc->sc_current = sr;
! 1230: NCR_TRACE("reselect: resume sr=0x%x\n", (long)sr);
! 1231:
! 1232: /* Implicit restore pointers message */
! 1233: sc->sc_dataptr = sr->sr_dataptr;
! 1234: sc->sc_datalen = sr->sr_datalen;
! 1235:
! 1236: sc->sc_prevphase = PHASE_INVALID;
! 1237: sc->sc_msgpriq = 0;
! 1238: sc->sc_msgoutq = 0;
! 1239: sc->sc_msgout = 0;
! 1240:
! 1241: /* XXX: Restore the normal mode register. */
! 1242: /* If this target's bit is set, do NOT check parity. */
! 1243: if (sc->sc_parity_disable & target_mask)
! 1244: *sc->sci_mode = (SCI_MODE_MONBSY);
! 1245: else
! 1246: *sc->sci_mode = (SCI_MODE_MONBSY | SCI_MODE_PAR_CHK);
! 1247:
! 1248: /*
! 1249: * Another hack for the Sun3 "si", which needs
! 1250: * some setup done to its DMA engine before the
! 1251: * target puts the SCSI bus into any DATA phase.
! 1252: */
! 1253: if (sr->sr_dma_hand && sc->sc_dma_setup) {
! 1254: NCR_TRACE("reselect: call DMA setup, dh=0x%x\n",
! 1255: (long) sr->sr_dma_hand);
! 1256: sc->sc_dma_setup(sc);
! 1257: }
! 1258:
! 1259: /* Now consume the IDENTIFY message. */
! 1260: ncr5380_pio_in(sc, PHASE_MSG_IN, 1, &msg);
! 1261: return;
! 1262: }
! 1263:
! 1264: printf("%s: phantom reselect: target=%d, LUN=%d\n",
! 1265: sc->sc_dev.dv_xname, target, lun);
! 1266: abort:
! 1267: /*
! 1268: * Try to send an ABORT message. This makes us
! 1269: * temporarily busy, but no current command...
! 1270: */
! 1271: sc->sc_state |= NCR_ABORTING;
! 1272:
! 1273: /* Raise ATN, delay, raise ACK... */
! 1274: icmd = SCI_ICMD_ATN;
! 1275: *sc->sci_icmd = icmd;
! 1276: delay(2);
! 1277:
! 1278: /* Now consume the IDENTIFY message. */
! 1279: ncr5380_pio_in(sc, PHASE_MSG_IN, 1, &msg);
! 1280:
! 1281: /* Finally try to send the ABORT. */
! 1282: sc->sc_prevphase = PHASE_INVALID;
! 1283: sc->sc_msgpriq = SEND_ABORT;
! 1284: ncr5380_msg_out(sc);
! 1285:
! 1286: *(sc->sci_tcmd) = PHASE_INVALID;
! 1287: *sc->sci_sel_enb = 0;
! 1288: SCI_CLR_INTR(sc);
! 1289: *sc->sci_sel_enb = 0x80;
! 1290:
! 1291: sc->sc_state &= ~NCR_ABORTING;
! 1292: }
! 1293:
! 1294:
! 1295: /*
! 1296: * Select target: xs is the transfer that we are selecting for.
! 1297: * sc->sc_current should be NULL.
! 1298: *
! 1299: * Returns:
! 1300: * sc->sc_current != NULL ==> we were reselected (race!)
! 1301: * XS_NOERROR ==> selection worked
! 1302: * XS_BUSY ==> lost arbitration
! 1303: * XS_SELTIMEOUT ==> no response to selection
! 1304: */
! 1305: static int
! 1306: ncr5380_select(sc, sr)
! 1307: struct ncr5380_softc *sc;
! 1308: struct sci_req *sr;
! 1309: {
! 1310: int timo, s, target_mask;
! 1311: u_char data, icmd;
! 1312:
! 1313: /* Check for reselect */
! 1314: ncr5380_reselect(sc);
! 1315: if (sc->sc_current) {
! 1316: NCR_TRACE("select: reselect, cur=0x%x\n",
! 1317: (long) sc->sc_current);
! 1318: return XS_BUSY; /* reselected */
! 1319: }
! 1320:
! 1321: /*
! 1322: * Set phase bits to 0, otherwise the 5380 won't drive the bus during
! 1323: * selection.
! 1324: */
! 1325: *sc->sci_tcmd = PHASE_DATA_OUT;
! 1326: *sc->sci_icmd = icmd = 0;
! 1327: *sc->sci_mode = 0;
! 1328:
! 1329: /*
! 1330: * Arbitrate for the bus. The 5380 takes care of the
! 1331: * time-critical bus interactions. We set our ID bit
! 1332: * in the output data register and set MODE_ARB. The
! 1333: * 5380 watches for the required "bus free" period.
! 1334: * If and when the "bus free" period is detected, the
! 1335: * 5380 drives BSY, drives the data bus, and sets the
! 1336: * "arbitration in progress" (AIP) bit to let us know
! 1337: * arbitration has started (and that it asserts BSY).
! 1338: * We then wait for one arbitration delay (2.2uS) and
! 1339: * check the ICMD_LST bit, which will be set if some
! 1340: * other target drives SEL during arbitration.
! 1341: *
! 1342: * There is a time-critical section during the period
! 1343: * after we enter arbitration up until we assert SEL.
! 1344: * Avoid long interrupts during this period.
! 1345: */
! 1346: s = splvm(); /* XXX: Begin time-critical section */
! 1347:
! 1348: *(sc->sci_odata) = 0x80; /* OUR_ID */
! 1349: *(sc->sci_mode) = SCI_MODE_ARB;
! 1350:
! 1351: #define WAIT_AIP_USEC 20 /* pleanty of time */
! 1352: /* Wait for the AIP bit to turn on. */
! 1353: timo = WAIT_AIP_USEC;
! 1354: for (;;) {
! 1355: if (*(sc->sci_icmd) & SCI_ICMD_AIP)
! 1356: break;
! 1357: if (timo <= 0) {
! 1358: /*
! 1359: * Did not see any "bus free" period.
! 1360: * The usual reason is a reselection,
! 1361: * so treat this as arbitration loss.
! 1362: */
! 1363: NCR_TRACE("select: bus busy, rc=%d\n", XS_BUSY);
! 1364: goto lost_arb;
! 1365: }
! 1366: timo -= 2;
! 1367: delay(2);
! 1368: }
! 1369: NCR_TRACE("select: have AIP after %d uSec.\n",
! 1370: WAIT_AIP_USEC - timo);
! 1371:
! 1372: /* Got AIP. Wait one arbitration delay (2.2 uS.) */
! 1373: delay(3);
! 1374:
! 1375: /* Check for ICMD_LST */
! 1376: if (*(sc->sci_icmd) & SCI_ICMD_LST) {
! 1377: /* Some other target asserted SEL. */
! 1378: NCR_TRACE("select: lost one, rc=%d\n", XS_BUSY);
! 1379: goto lost_arb;
! 1380: }
! 1381:
! 1382: /*
! 1383: * No other device has declared itself the winner.
! 1384: * The spec. says to check for higher IDs, but we
! 1385: * are always the highest (ID=7) so don't bother.
! 1386: * We can now declare victory by asserting SEL.
! 1387: *
! 1388: * Note that the 5380 is asserting BSY because we
! 1389: * have entered arbitration mode. We will now hold
! 1390: * BSY directly so we can turn off ARB mode.
! 1391: */
! 1392: icmd = (SCI_ICMD_BSY | SCI_ICMD_SEL);
! 1393: *sc->sci_icmd = icmd;
! 1394:
! 1395: /*
! 1396: * "The SCSI device that wins arbitration shall wait
! 1397: * at least a bus clear delay plus a bus settle delay
! 1398: * after asserting the SEL signal before changing
! 1399: * any [other] signal." (1.2uS. total)
! 1400: */
! 1401: delay(2);
! 1402:
! 1403: /*
! 1404: * Check one last time to see if we really did
! 1405: * win arbitration. This might only happen if
! 1406: * there can be a higher selection ID than ours.
! 1407: * Keep this code for reference anyway...
! 1408: */
! 1409: if (*(sc->sci_icmd) & SCI_ICMD_LST) {
! 1410: /* Some other target asserted SEL. */
! 1411: NCR_TRACE("select: lost two, rc=%d\n", XS_BUSY);
! 1412:
! 1413: lost_arb:
! 1414: *sc->sci_icmd = 0;
! 1415: *sc->sci_mode = 0;
! 1416:
! 1417: splx(s); /* XXX: End of time-critical section. */
! 1418:
! 1419: /*
! 1420: * When we lose arbitration, it usually means
! 1421: * there is a target trying to reselect us.
! 1422: */
! 1423: ncr5380_reselect(sc);
! 1424: return XS_BUSY;
! 1425: }
! 1426:
! 1427: /* Leave ARB mode Now that we drive BSY+SEL */
! 1428: *sc->sci_mode = 0;
! 1429: *sc->sci_sel_enb = 0;
! 1430:
! 1431: splx(s); /* XXX: End of time-critical section. */
! 1432:
! 1433: /*
! 1434: * Arbitration is complete. Now do selection:
! 1435: * Drive the data bus with the ID bits for both
! 1436: * the host and target. Also set ATN now, to
! 1437: * ask the target for a message out phase.
! 1438: */
! 1439: target_mask = (1 << sr->sr_target);
! 1440: data = 0x80 | target_mask;
! 1441: *(sc->sci_odata) = data;
! 1442: icmd |= (SCI_ICMD_DATA | SCI_ICMD_ATN);
! 1443: *(sc->sci_icmd) = icmd;
! 1444: delay(2); /* two deskew delays. */
! 1445:
! 1446: /* De-assert BSY (targets sample the data now). */
! 1447: icmd &= ~SCI_ICMD_BSY;
! 1448: *(sc->sci_icmd) = icmd;
! 1449: delay(3); /* Bus settle delay. */
! 1450:
! 1451: /*
! 1452: * Wait for the target to assert BSY.
! 1453: * SCSI spec. says wait for 250 mS.
! 1454: */
! 1455: for (timo = 25000;;) {
! 1456: if (*sc->sci_bus_csr & SCI_BUS_BSY)
! 1457: goto success;
! 1458: if (--timo <= 0)
! 1459: break;
! 1460: delay(10);
! 1461: }
! 1462:
! 1463: /*
! 1464: * There is no reaction from the target. Start the selection
! 1465: * timeout procedure. We release the databus but keep SEL+ATN
! 1466: * asserted. After that we wait a 'selection abort time' (200
! 1467: * usecs) and 2 deskew delays (90 ns) and check BSY again.
! 1468: * When BSY is asserted, we assume the selection succeeded,
! 1469: * otherwise we release the bus.
! 1470: */
! 1471: icmd &= ~SCI_ICMD_DATA;
! 1472: *(sc->sci_icmd) = icmd;
! 1473: delay(201);
! 1474: if ((*sc->sci_bus_csr & SCI_BUS_BSY) == 0) {
! 1475: /* Really no device on bus */
! 1476: *sc->sci_tcmd = PHASE_INVALID;
! 1477: *sc->sci_icmd = 0;
! 1478: *sc->sci_mode = 0;
! 1479: *sc->sci_sel_enb = 0;
! 1480: SCI_CLR_INTR(sc);
! 1481: *sc->sci_sel_enb = 0x80;
! 1482: NCR_TRACE("select: device down, rc=%d\n", XS_SELTIMEOUT);
! 1483: return XS_SELTIMEOUT;
! 1484: }
! 1485:
! 1486: success:
! 1487: /*
! 1488: * The target is now driving BSY, so we can stop
! 1489: * driving SEL and the data bus (keep ATN true).
! 1490: * Configure the ncr5380 to monitor BSY, parity.
! 1491: */
! 1492: icmd &= ~(SCI_ICMD_DATA | SCI_ICMD_SEL);
! 1493: *sc->sci_icmd = icmd;
! 1494:
! 1495: /* If this target's bit is set, do NOT check parity. */
! 1496: if (sc->sc_parity_disable & target_mask)
! 1497: *sc->sci_mode = (SCI_MODE_MONBSY);
! 1498: else
! 1499: *sc->sci_mode = (SCI_MODE_MONBSY | SCI_MODE_PAR_CHK);
! 1500:
! 1501: return XS_NOERROR;
! 1502: }
! 1503:
! 1504:
! 1505: /*****************************************************************
! 1506: * Functions to handle each info. transfer phase:
! 1507: *****************************************************************/
! 1508:
! 1509: /*
! 1510: * The message system:
! 1511: *
! 1512: * This is a revamped message system that now should easier accommodate
! 1513: * new messages, if necessary.
! 1514: *
! 1515: * Currently we accept these messages:
! 1516: * IDENTIFY (when reselecting)
! 1517: * COMMAND COMPLETE # (expect bus free after messages marked #)
! 1518: * NOOP
! 1519: * MESSAGE REJECT
! 1520: * SYNCHRONOUS DATA TRANSFER REQUEST
! 1521: * SAVE DATA POINTER
! 1522: * RESTORE POINTERS
! 1523: * DISCONNECT #
! 1524: *
! 1525: * We may send these messages in prioritized order:
! 1526: * BUS DEVICE RESET # if SCSI_RESET & xs->flags (or in weird sits.)
! 1527: * MESSAGE PARITY ERROR par. err. during MSGI
! 1528: * MESSAGE REJECT If we get a message we don't know how to handle
! 1529: * ABORT # send on errors
! 1530: * INITIATOR DETECTED ERROR also on errors (SCSI2) (during info xfer)
! 1531: * IDENTIFY At the start of each transfer
! 1532: * SYNCHRONOUS DATA TRANSFER REQUEST if appropriate
! 1533: * NOOP if nothing else fits the bill ...
! 1534: */
! 1535:
! 1536: #define IS1BYTEMSG(m) (((m) != 0x01 && (m) < 0x20) || (m) >= 0x80)
! 1537: #define IS2BYTEMSG(m) (((m) & 0xf0) == 0x20)
! 1538: #define ISEXTMSG(m) ((m) == 0x01)
! 1539:
! 1540: /*
! 1541: * Precondition:
! 1542: * The SCSI bus is already in the MSGI phase and there is a message byte
! 1543: * on the bus, along with an asserted REQ signal.
! 1544: *
! 1545: * Our return value determines whether our caller, ncr5380_machine()
! 1546: * will expect to see another REQ (and possibly phase change).
! 1547: */
! 1548: static int
! 1549: ncr5380_msg_in(sc)
! 1550: register struct ncr5380_softc *sc;
! 1551: {
! 1552: struct sci_req *sr = sc->sc_current;
! 1553: struct scsi_xfer *xs = sr->sr_xs;
! 1554: int n, phase;
! 1555: int act_flags;
! 1556: register u_char icmd;
! 1557:
! 1558: /* acknowledge phase change */
! 1559: *sc->sci_tcmd = PHASE_MSG_IN;
! 1560:
! 1561: act_flags = ACT_CONTINUE;
! 1562: icmd = *sc->sci_icmd & SCI_ICMD_RMASK;
! 1563:
! 1564: if (sc->sc_prevphase == PHASE_MSG_IN) {
! 1565: /* This is a continuation of the previous message. */
! 1566: n = sc->sc_imp - sc->sc_imess;
! 1567: NCR_TRACE("msg_in: continuation, n=%d\n", n);
! 1568: goto nextbyte;
! 1569: }
! 1570:
! 1571: /* This is a new MESSAGE IN phase. Clean up our state. */
! 1572: sc->sc_state &= ~NCR_DROP_MSGIN;
! 1573:
! 1574: nextmsg:
! 1575: n = 0;
! 1576: sc->sc_imp = &sc->sc_imess[n];
! 1577:
! 1578: nextbyte:
! 1579: /*
! 1580: * Read a whole message, but don't ack the last byte. If we reject the
! 1581: * message, we have to assert ATN during the message transfer phase
! 1582: * itself.
! 1583: */
! 1584: for (;;) {
! 1585: /*
! 1586: * Read a message byte.
! 1587: * First, check BSY, REQ, phase...
! 1588: */
! 1589: if (!SCI_BUSY(sc)) {
! 1590: NCR_TRACE("msg_in: lost BSY, n=%d\n", n);
! 1591: /* XXX - Assume the command completed? */
! 1592: act_flags |= (ACT_DISCONNECT | ACT_CMD_DONE);
! 1593: return (act_flags);
! 1594: }
! 1595: if (ncr5380_wait_req(sc)) {
! 1596: NCR_TRACE("msg_in: BSY but no REQ, n=%d\n", n);
! 1597: /* Just let ncr5380_machine() handle it... */
! 1598: return (act_flags);
! 1599: }
! 1600: phase = SCI_BUS_PHASE(*sc->sci_bus_csr);
! 1601: if (phase != PHASE_MSG_IN) {
! 1602: /*
! 1603: * Target left MESSAGE IN, probably because it
! 1604: * a) noticed our ATN signal, or
! 1605: * b) ran out of messages.
! 1606: */
! 1607: return (act_flags);
! 1608: }
! 1609: /* Still in MESSAGE IN phase, and REQ is asserted. */
! 1610: if (*sc->sci_csr & SCI_CSR_PERR) {
! 1611: ncr_sched_msgout(sc, SEND_PARITY_ERROR);
! 1612: sc->sc_state |= NCR_DROP_MSGIN;
! 1613: }
! 1614:
! 1615: /* Gather incoming message bytes if needed. */
! 1616: if ((sc->sc_state & NCR_DROP_MSGIN) == 0) {
! 1617: if (n >= NCR_MAX_MSG_LEN) {
! 1618: ncr_sched_msgout(sc, SEND_REJECT);
! 1619: sc->sc_state |= NCR_DROP_MSGIN;
! 1620: } else {
! 1621: *sc->sc_imp++ = *sc->sci_data;
! 1622: n++;
! 1623: /*
! 1624: * This testing is suboptimal, but most
! 1625: * messages will be of the one byte variety, so
! 1626: * it should not affect performance
! 1627: * significantly.
! 1628: */
! 1629: if (n == 1 && IS1BYTEMSG(sc->sc_imess[0]))
! 1630: goto have_msg;
! 1631: if (n == 2 && IS2BYTEMSG(sc->sc_imess[0]))
! 1632: goto have_msg;
! 1633: if (n >= 3 && ISEXTMSG(sc->sc_imess[0]) &&
! 1634: n == sc->sc_imess[1] + 2)
! 1635: goto have_msg;
! 1636: }
! 1637: }
! 1638:
! 1639: /*
! 1640: * If we reach this spot we're either:
! 1641: * a) in the middle of a multi-byte message, or
! 1642: * b) dropping bytes.
! 1643: */
! 1644:
! 1645: /* Ack the last byte read. */
! 1646: icmd |= SCI_ICMD_ACK;
! 1647: *sc->sci_icmd = icmd;
! 1648:
! 1649: if (ncr5380_wait_not_req(sc)) {
! 1650: NCR_TRACE("msg_in: drop, stuck REQ, n=%d\n", n);
! 1651: act_flags |= ACT_RESET_BUS;
! 1652: }
! 1653:
! 1654: icmd &= ~SCI_ICMD_ACK;
! 1655: *sc->sci_icmd = icmd;
! 1656:
! 1657: if (act_flags != ACT_CONTINUE)
! 1658: return (act_flags);
! 1659:
! 1660: /* back to nextbyte */
! 1661: }
! 1662:
! 1663: have_msg:
! 1664: /* We now have a complete message. Parse it. */
! 1665:
! 1666: switch (sc->sc_imess[0]) {
! 1667: case MSG_CMDCOMPLETE:
! 1668: NCR_TRACE("msg_in: CMDCOMPLETE\n", 0);
! 1669: /* Target is about to disconnect. */
! 1670: act_flags |= (ACT_DISCONNECT | ACT_CMD_DONE);
! 1671: break;
! 1672:
! 1673: case MSG_PARITY_ERROR:
! 1674: NCR_TRACE("msg_in: PARITY_ERROR\n", 0);
! 1675: /* Resend the last message. */
! 1676: ncr_sched_msgout(sc, sc->sc_msgout);
! 1677: /* Reset icmd after scheduling the REJECT cmd - jwg */
! 1678: icmd = *sc->sci_icmd & SCI_ICMD_RMASK;
! 1679: break;
! 1680:
! 1681: case MSG_MESSAGE_REJECT:
! 1682: /* The target rejects the last message we sent. */
! 1683: NCR_TRACE("msg_in: got reject for 0x%x\n", sc->sc_msgout);
! 1684: switch (sc->sc_msgout) {
! 1685: case SEND_IDENTIFY:
! 1686: /* Really old target controller? */
! 1687: /* XXX ... */
! 1688: break;
! 1689: case SEND_INIT_DET_ERR:
! 1690: goto abort;
! 1691: }
! 1692: break;
! 1693:
! 1694: case MSG_NOOP:
! 1695: NCR_TRACE("msg_in: NOOP\n", 0);
! 1696: break;
! 1697:
! 1698: case MSG_DISCONNECT:
! 1699: NCR_TRACE("msg_in: DISCONNECT\n", 0);
! 1700: /* Target is about to disconnect. */
! 1701: act_flags |= ACT_DISCONNECT;
! 1702: if ((xs->sc_link->quirks & SDEV_AUTOSAVE) == 0)
! 1703: break;
! 1704: /*FALLTHROUGH*/
! 1705:
! 1706: case MSG_SAVEDATAPOINTER:
! 1707: NCR_TRACE("msg_in: SAVE_PTRS\n", 0);
! 1708: sr->sr_dataptr = sc->sc_dataptr;
! 1709: sr->sr_datalen = sc->sc_datalen;
! 1710: break;
! 1711:
! 1712: case MSG_RESTOREPOINTERS:
! 1713: NCR_TRACE("msg_in: RESTORE_PTRS\n", 0);
! 1714: sc->sc_dataptr = sr->sr_dataptr;
! 1715: sc->sc_datalen = sr->sr_datalen;
! 1716: break;
! 1717:
! 1718: case MSG_EXTENDED:
! 1719: switch (sc->sc_imess[2]) {
! 1720: case MSG_EXT_SDTR:
! 1721: case MSG_EXT_WDTR:
! 1722: /* The ncr5380 can not do synchronous mode. */
! 1723: goto reject;
! 1724: default:
! 1725: printf("%s: unrecognized MESSAGE EXTENDED; sending REJECT\n",
! 1726: sc->sc_dev.dv_xname);
! 1727: NCR_BREAK();
! 1728: goto reject;
! 1729: }
! 1730: break;
! 1731:
! 1732: default:
! 1733: NCR_TRACE("msg_in: eh? imsg=0x%x\n", sc->sc_imess[0]);
! 1734: printf("%s: unrecognized MESSAGE; sending REJECT\n",
! 1735: sc->sc_dev.dv_xname);
! 1736: NCR_BREAK();
! 1737: /* fallthrough */
! 1738: reject:
! 1739: ncr_sched_msgout(sc, SEND_REJECT);
! 1740: /* Reset icmd after scheduling the REJECT cmd - jwg */
! 1741: icmd = *sc->sci_icmd & SCI_ICMD_RMASK;
! 1742: break;
! 1743:
! 1744: abort:
! 1745: sc->sc_state |= NCR_ABORTING;
! 1746: ncr_sched_msgout(sc, SEND_ABORT);
! 1747: break;
! 1748: }
! 1749:
! 1750: /* Ack the last byte read. */
! 1751: icmd |= SCI_ICMD_ACK;
! 1752: *sc->sci_icmd = icmd;
! 1753:
! 1754: if (ncr5380_wait_not_req(sc)) {
! 1755: NCR_TRACE("msg_in: last, stuck REQ, n=%d\n", n);
! 1756: act_flags |= ACT_RESET_BUS;
! 1757: }
! 1758:
! 1759: icmd &= ~SCI_ICMD_ACK;
! 1760: *sc->sci_icmd = icmd;
! 1761:
! 1762: /* Go get the next message, if any. */
! 1763: if (act_flags == ACT_CONTINUE)
! 1764: goto nextmsg;
! 1765:
! 1766: return (act_flags);
! 1767: }
! 1768:
! 1769:
! 1770: /*
! 1771: * The message out (and in) stuff is a bit complicated:
! 1772: * If the target requests another message (sequence) without
! 1773: * having changed phase in between it really asks for a
! 1774: * retransmit, probably due to parity error(s).
! 1775: * The following messages can be sent:
! 1776: * IDENTIFY @ These 4 stem from SCSI command activity
! 1777: * SDTR @
! 1778: * WDTR @
! 1779: * DEV_RESET @
! 1780: * REJECT if MSGI doesn't make sense
! 1781: * PARITY_ERROR if parity error while in MSGI
! 1782: * INIT_DET_ERR if parity error while not in MSGI
! 1783: * ABORT if INIT_DET_ERR rejected
! 1784: * NOOP if asked for a message and there's nothing to send
! 1785: *
! 1786: * Note that we call this one with (sc_current == NULL)
! 1787: * when sending ABORT for unwanted reselections.
! 1788: */
! 1789: static int
! 1790: ncr5380_msg_out(sc)
! 1791: register struct ncr5380_softc *sc;
! 1792: {
! 1793: struct sci_req *sr = sc->sc_current;
! 1794: int act_flags, n, phase, progress;
! 1795: register u_char icmd, msg;
! 1796:
! 1797: /* acknowledge phase change */
! 1798: *sc->sci_tcmd = PHASE_MSG_OUT;
! 1799:
! 1800: progress = 0; /* did we send any messages? */
! 1801: act_flags = ACT_CONTINUE;
! 1802:
! 1803: /*
! 1804: * Set ATN. If we're just sending a trivial 1-byte message,
! 1805: * we'll clear ATN later on anyway. Also drive the data bus.
! 1806: */
! 1807: icmd = *sc->sci_icmd & SCI_ICMD_RMASK;
! 1808: icmd |= (SCI_ICMD_ATN | SCI_ICMD_DATA);
! 1809: *sc->sci_icmd = icmd;
! 1810:
! 1811: if (sc->sc_prevphase == PHASE_MSG_OUT) {
! 1812: if (sc->sc_omp == sc->sc_omess) {
! 1813: /*
! 1814: * This is a retransmission.
! 1815: *
! 1816: * We get here if the target stayed in MESSAGE OUT
! 1817: * phase. Section 5.1.9.2 of the SCSI 2 spec indicates
! 1818: * that all of the previously transmitted messages must
! 1819: * be sent again, in the same order. Therefore, we
! 1820: * requeue all the previously transmitted messages, and
! 1821: * start again from the top. Our simple priority
! 1822: * scheme keeps the messages in the right order.
! 1823: */
! 1824: sc->sc_msgpriq |= sc->sc_msgoutq;
! 1825: NCR_TRACE("msg_out: retrans priq=0x%x\n", sc->sc_msgpriq);
! 1826: } else {
! 1827: /* This is a continuation of the previous message. */
! 1828: n = sc->sc_omp - sc->sc_omess;
! 1829: NCR_TRACE("msg_out: continuation, n=%d\n", n);
! 1830: goto nextbyte;
! 1831: }
! 1832: }
! 1833:
! 1834: /* No messages transmitted so far. */
! 1835: sc->sc_msgoutq = 0;
! 1836:
! 1837: nextmsg:
! 1838: /* Pick up highest priority message. */
! 1839: sc->sc_msgout = sc->sc_msgpriq & -sc->sc_msgpriq;
! 1840: sc->sc_msgpriq &= ~sc->sc_msgout;
! 1841: sc->sc_msgoutq |= sc->sc_msgout;
! 1842:
! 1843: /* Build the outgoing message data. */
! 1844: switch (sc->sc_msgout) {
! 1845: case SEND_IDENTIFY:
! 1846: NCR_TRACE("msg_out: SEND_IDENTIFY\n", 0);
! 1847: if (sr == NULL) {
! 1848: printf("%s: SEND_IDENTIFY while not connected; sending NOOP\n",
! 1849: sc->sc_dev.dv_xname);
! 1850: NCR_BREAK();
! 1851: goto noop;
! 1852: }
! 1853: /*
! 1854: * The identify message we send determines whether
! 1855: * disconnect/reselect is allowed for this command.
! 1856: * 0xC0+LUN: allows it, 0x80+LUN disallows it.
! 1857: */
! 1858: msg = 0xc0; /* MSG_IDENTIFY(0,1) */
! 1859: if (sc->sc_no_disconnect & (1 << sr->sr_target))
! 1860: msg = 0x80;
! 1861: if (sr->sr_flags & (SR_IMMED | SR_SENSE))
! 1862: msg = 0x80;
! 1863: sc->sc_omess[0] = msg | sr->sr_lun;
! 1864: n = 1;
! 1865: break;
! 1866:
! 1867: case SEND_DEV_RESET:
! 1868: NCR_TRACE("msg_out: SEND_DEV_RESET\n", 0);
! 1869: /* Expect disconnect after this! */
! 1870: /* XXX: Kill jobs for this target? */
! 1871: act_flags |= (ACT_DISCONNECT | ACT_CMD_DONE);
! 1872: sc->sc_omess[0] = MSG_BUS_DEV_RESET;
! 1873: n = 1;
! 1874: break;
! 1875:
! 1876: case SEND_REJECT:
! 1877: NCR_TRACE("msg_out: SEND_REJECT\n", 0);
! 1878: sc->sc_omess[0] = MSG_MESSAGE_REJECT;
! 1879: n = 1;
! 1880: break;
! 1881:
! 1882: case SEND_PARITY_ERROR:
! 1883: NCR_TRACE("msg_out: SEND_PARITY_ERROR\n", 0);
! 1884: sc->sc_omess[0] = MSG_PARITY_ERROR;
! 1885: n = 1;
! 1886: break;
! 1887:
! 1888: case SEND_INIT_DET_ERR:
! 1889: NCR_TRACE("msg_out: SEND_INIT_DET_ERR\n", 0);
! 1890: sc->sc_omess[0] = MSG_INITIATOR_DET_ERR;
! 1891: n = 1;
! 1892: break;
! 1893:
! 1894: case SEND_ABORT:
! 1895: NCR_TRACE("msg_out: SEND_ABORT\n", 0);
! 1896: /* Expect disconnect after this! */
! 1897: /* XXX: Set error flag? */
! 1898: act_flags |= (ACT_DISCONNECT | ACT_CMD_DONE);
! 1899: sc->sc_omess[0] = MSG_ABORT;
! 1900: n = 1;
! 1901: break;
! 1902:
! 1903: case 0:
! 1904: printf("%s: unexpected MESSAGE OUT; sending NOOP\n",
! 1905: sc->sc_dev.dv_xname);
! 1906: NCR_BREAK();
! 1907: noop:
! 1908: NCR_TRACE("msg_out: send NOOP\n", 0);
! 1909: sc->sc_omess[0] = MSG_NOOP;
! 1910: n = 1;
! 1911: break;
! 1912:
! 1913: default:
! 1914: printf("%s: weird MESSAGE OUT; sending NOOP\n",
! 1915: sc->sc_dev.dv_xname);
! 1916: NCR_BREAK();
! 1917: goto noop;
! 1918: }
! 1919: sc->sc_omp = &sc->sc_omess[n];
! 1920:
! 1921: nextbyte:
! 1922: /* Send message bytes. */
! 1923: while (n > 0) {
! 1924: /*
! 1925: * Send a message byte.
! 1926: * First check BSY, REQ, phase...
! 1927: */
! 1928: if (!SCI_BUSY(sc)) {
! 1929: NCR_TRACE("msg_out: lost BSY, n=%d\n", n);
! 1930: goto out;
! 1931: }
! 1932: if (ncr5380_wait_req(sc)) {
! 1933: NCR_TRACE("msg_out: no REQ, n=%d\n", n);
! 1934: goto out;
! 1935: }
! 1936: phase = SCI_BUS_PHASE(*sc->sci_bus_csr);
! 1937: if (phase != PHASE_MSG_OUT) {
! 1938: /*
! 1939: * Target left MESSAGE OUT, possibly to reject
! 1940: * our message.
! 1941: */
! 1942: NCR_TRACE("msg_out: new phase=%d\n", phase);
! 1943: goto out;
! 1944: }
! 1945:
! 1946: /* Yes, we can send this message byte. */
! 1947: --n;
! 1948:
! 1949: /* Clear ATN before last byte if this is the last message. */
! 1950: if (n == 0 && sc->sc_msgpriq == 0) {
! 1951: icmd &= ~SCI_ICMD_ATN;
! 1952: *sc->sci_icmd = icmd;
! 1953: /* 2 deskew delays */
! 1954: delay(2); /* XXX */
! 1955: }
! 1956:
! 1957: /* Put data on the bus. */
! 1958: *sc->sci_odata = *--sc->sc_omp;
! 1959:
! 1960: /* Raise ACK to tell target data is on the bus. */
! 1961: icmd |= SCI_ICMD_ACK;
! 1962: *sc->sci_icmd = icmd;
! 1963:
! 1964: /* Wait for REQ to be negated. */
! 1965: if (ncr5380_wait_not_req(sc)) {
! 1966: NCR_TRACE("msg_out: stuck REQ, n=%d\n", n);
! 1967: act_flags |= ACT_RESET_BUS;
! 1968: }
! 1969:
! 1970: /* Finally, drop ACK. */
! 1971: icmd &= ~SCI_ICMD_ACK;
! 1972: *sc->sci_icmd = icmd;
! 1973:
! 1974: /* Stuck bus or something... */
! 1975: if (act_flags & ACT_RESET_BUS)
! 1976: goto out;
! 1977:
! 1978: }
! 1979: progress++;
! 1980:
! 1981: /* We get here only if the entire message has been transmitted. */
! 1982: if (sc->sc_msgpriq != 0) {
! 1983: /* There are more outgoing messages. */
! 1984: goto nextmsg;
! 1985: }
! 1986:
! 1987: /*
! 1988: * The last message has been transmitted. We need to remember the last
! 1989: * message transmitted (in case the target switches to MESSAGE IN phase
! 1990: * and sends a MESSAGE REJECT), and the list of messages transmitted
! 1991: * this time around (in case the target stays in MESSAGE OUT phase to
! 1992: * request a retransmit).
! 1993: */
! 1994:
! 1995: out:
! 1996: /* Stop driving the data bus. */
! 1997: icmd &= ~SCI_ICMD_DATA;
! 1998: *sc->sci_icmd = icmd;
! 1999:
! 2000: if (!progress)
! 2001: act_flags |= ACT_RESET_BUS;
! 2002:
! 2003: return (act_flags);
! 2004: }
! 2005:
! 2006:
! 2007: /*
! 2008: * Handle command phase.
! 2009: */
! 2010: static int
! 2011: ncr5380_command(sc)
! 2012: struct ncr5380_softc *sc;
! 2013: {
! 2014: struct sci_req *sr = sc->sc_current;
! 2015: struct scsi_xfer *xs = sr->sr_xs;
! 2016: struct scsi_sense rqs;
! 2017: int len;
! 2018:
! 2019: /* acknowledge phase change */
! 2020: *sc->sci_tcmd = PHASE_COMMAND;
! 2021:
! 2022: if (sr->sr_flags & SR_SENSE) {
! 2023: rqs.opcode = REQUEST_SENSE;
! 2024: rqs.byte2 = xs->sc_link->lun << 5;
! 2025: rqs.length = sizeof(xs->sense);
! 2026:
! 2027: rqs.unused[0] = rqs.unused[1] = rqs.control = 0;
! 2028: len = ncr5380_pio_out(sc, PHASE_COMMAND, sizeof(rqs),
! 2029: (u_char *)&rqs);
! 2030: }
! 2031: else {
! 2032: /* Assume command can be sent in one go. */
! 2033: /* XXX: Do this using DMA, and get a phase change intr? */
! 2034: len = ncr5380_pio_out(sc, PHASE_COMMAND, xs->cmdlen,
! 2035: (u_char *)xs->cmd);
! 2036: }
! 2037:
! 2038: if (len != xs->cmdlen) {
! 2039: #ifdef NCR5380_DEBUG
! 2040: printf("ncr5380_command: short transfer: wanted %d got %d.\n",
! 2041: xs->cmdlen, len);
! 2042: ncr5380_show_scsi_cmd(xs);
! 2043: NCR_BREAK();
! 2044: #endif
! 2045: if (len < 6) {
! 2046: xs->error = XS_DRIVER_STUFFUP;
! 2047: sc->sc_state |= NCR_ABORTING;
! 2048: ncr_sched_msgout(sc, SEND_ABORT);
! 2049: }
! 2050:
! 2051: }
! 2052:
! 2053: return ACT_CONTINUE;
! 2054: }
! 2055:
! 2056:
! 2057: /*
! 2058: * Handle either data_in or data_out
! 2059: */
! 2060: static int
! 2061: ncr5380_data_xfer(sc, phase)
! 2062: struct ncr5380_softc *sc;
! 2063: int phase;
! 2064: {
! 2065: struct sci_req *sr = sc->sc_current;
! 2066: struct scsi_xfer *xs = sr->sr_xs;
! 2067: int expected_phase;
! 2068: int len;
! 2069:
! 2070: if (sr->sr_flags & SR_SENSE) {
! 2071: NCR_TRACE("data_xfer: get sense, sr=0x%x\n", (long)sr);
! 2072: if (phase != PHASE_DATA_IN) {
! 2073: printf("%s: sense phase error\n", sc->sc_dev.dv_xname);
! 2074: goto abort;
! 2075: }
! 2076: /* acknowledge phase change */
! 2077: *sc->sci_tcmd = PHASE_DATA_IN;
! 2078: len = ncr5380_pio_in(sc, phase, sizeof(xs->sense),
! 2079: (u_char *)&xs->sense);
! 2080: return ACT_CONTINUE;
! 2081: }
! 2082:
! 2083: /*
! 2084: * When aborting a command, disallow any data phase.
! 2085: */
! 2086: if (sc->sc_state & NCR_ABORTING) {
! 2087: printf("%s: aborting, but phase=%s (reset)\n",
! 2088: sc->sc_dev.dv_xname, phase_names[phase & 7]);
! 2089: return ACT_RESET_BUS; /* XXX */
! 2090: }
! 2091:
! 2092: /* Validate expected phase (data_in or data_out) */
! 2093: expected_phase = (xs->flags & SCSI_DATA_OUT) ?
! 2094: PHASE_DATA_OUT : PHASE_DATA_IN;
! 2095: if (phase != expected_phase) {
! 2096: printf("%s: data phase error\n", sc->sc_dev.dv_xname);
! 2097: goto abort;
! 2098: }
! 2099:
! 2100: /* Make sure we have some data to move. */
! 2101: if (sc->sc_datalen <= 0) {
! 2102: /* Device needs padding. */
! 2103: if (phase == PHASE_DATA_IN)
! 2104: ncr5380_pio_in(sc, phase, 4096, NULL);
! 2105: else
! 2106: ncr5380_pio_out(sc, phase, 4096, NULL);
! 2107: /* Make sure that caused a phase change. */
! 2108: if (SCI_BUS_PHASE(*sc->sci_bus_csr) == phase) {
! 2109: /* More than 4k is just too much! */
! 2110: printf("%s: too much data padding\n",
! 2111: sc->sc_dev.dv_xname);
! 2112: goto abort;
! 2113: }
! 2114: return ACT_CONTINUE;
! 2115: }
! 2116:
! 2117: /*
! 2118: * Attempt DMA only if dma_alloc gave us a DMA handle AND
! 2119: * there is enough left to transfer so DMA is worth while.
! 2120: */
! 2121: if (sr->sr_dma_hand &&
! 2122: (sc->sc_datalen >= sc->sc_min_dma_len))
! 2123: {
! 2124: /*
! 2125: * OK, really start DMA. Note, the MD start function
! 2126: * is responsible for setting the TCMD register, etc.
! 2127: * (Acknowledge the phase change there, not here.)
! 2128: */
! 2129: NCR_TRACE("data_xfer: dma_start, dh=0x%x\n",
! 2130: (long) sr->sr_dma_hand);
! 2131: (*sc->sc_dma_start)(sc);
! 2132: return ACT_WAIT_DMA;
! 2133: }
! 2134:
! 2135: /*
! 2136: * Doing PIO for data transfer. (Possibly "Pseudo DMA")
! 2137: * XXX: Do PDMA functions need to set tcmd later?
! 2138: */
! 2139: NCR_TRACE("data_xfer: doing PIO, len=%d\n", sc->sc_datalen);
! 2140: /* acknowledge phase change */
! 2141: *sc->sci_tcmd = phase; /* XXX: OK for PDMA? */
! 2142: if (phase == PHASE_DATA_OUT) {
! 2143: len = (*sc->sc_pio_out)(sc, phase, sc->sc_datalen, sc->sc_dataptr);
! 2144: } else {
! 2145: len = (*sc->sc_pio_in) (sc, phase, sc->sc_datalen, sc->sc_dataptr);
! 2146: }
! 2147: sc->sc_dataptr += len;
! 2148: sc->sc_datalen -= len;
! 2149:
! 2150: NCR_TRACE("data_xfer: did PIO, resid=%d\n", sc->sc_datalen);
! 2151: return (ACT_CONTINUE);
! 2152:
! 2153: abort:
! 2154: sc->sc_state |= NCR_ABORTING;
! 2155: ncr_sched_msgout(sc, SEND_ABORT);
! 2156: return (ACT_CONTINUE);
! 2157: }
! 2158:
! 2159:
! 2160: static int
! 2161: ncr5380_status(sc)
! 2162: struct ncr5380_softc *sc;
! 2163: {
! 2164: int len;
! 2165: u_char status;
! 2166: struct sci_req *sr = sc->sc_current;
! 2167:
! 2168: /* acknowledge phase change */
! 2169: *sc->sci_tcmd = PHASE_STATUS;
! 2170:
! 2171: len = ncr5380_pio_in(sc, PHASE_STATUS, 1, &status);
! 2172: if (len) {
! 2173: sr->sr_status = status;
! 2174: } else {
! 2175: printf("ncr5380_status: none?\n");
! 2176: }
! 2177:
! 2178: return ACT_CONTINUE;
! 2179: }
! 2180:
! 2181:
! 2182: /*
! 2183: * This is the big state machine that follows SCSI phase changes.
! 2184: * This is somewhat like a co-routine. It will do a SCSI command,
! 2185: * and exit if the command is complete, or if it must wait, i.e.
! 2186: * for DMA to complete or for reselect to resume the job.
! 2187: *
! 2188: * The bus must be selected, and we need to know which command is
! 2189: * being undertaken.
! 2190: */
! 2191: static void
! 2192: ncr5380_machine(sc)
! 2193: struct ncr5380_softc *sc;
! 2194: {
! 2195: struct sci_req *sr;
! 2196: struct scsi_xfer *xs;
! 2197: int act_flags, phase, timo;
! 2198:
! 2199: #ifdef DIAGNOSTIC
! 2200: if (sc->sc_state == NCR_IDLE)
! 2201: panic("ncr5380_machine: state=idle");
! 2202: if (sc->sc_current == NULL)
! 2203: panic("ncr5380_machine: no current cmd");
! 2204: #endif
! 2205:
! 2206: sr = sc->sc_current;
! 2207: xs = sr->sr_xs;
! 2208: act_flags = ACT_CONTINUE;
! 2209:
! 2210: /*
! 2211: * This will be called by ncr5380_intr() when DMA is
! 2212: * complete. Must stop DMA before touching the 5380 or
! 2213: * there will be "register conflict" errors.
! 2214: */
! 2215: if (sc->sc_state & NCR_DOINGDMA) {
! 2216: /* Pick-up where where we left off... */
! 2217: goto dma_done;
! 2218: }
! 2219:
! 2220: next_phase:
! 2221:
! 2222: if (!SCI_BUSY(sc)) {
! 2223: /* Unexpected disconnect */
! 2224: printf("ncr5380_machine: unexpected disconnect.\n");
! 2225: xs->error = XS_DRIVER_STUFFUP;
! 2226: act_flags |= (ACT_DISCONNECT | ACT_CMD_DONE);
! 2227: goto do_actions;
! 2228: }
! 2229:
! 2230: /*
! 2231: * Wait for REQ before reading the phase.
! 2232: * Need to wait longer than usual here, because
! 2233: * some devices are just plain slow...
! 2234: */
! 2235: timo = ncr5380_wait_phase_timo;
! 2236: for (;;) {
! 2237: if (*sc->sci_bus_csr & SCI_BUS_REQ)
! 2238: break;
! 2239: if (--timo <= 0) {
! 2240: if (sc->sc_state & NCR_ABORTING) {
! 2241: printf("%s: no REQ while aborting, reset\n",
! 2242: sc->sc_dev.dv_xname);
! 2243: act_flags |= ACT_RESET_BUS;
! 2244: goto do_actions;
! 2245: }
! 2246: printf("%s: no REQ for next phase, abort\n",
! 2247: sc->sc_dev.dv_xname);
! 2248: sc->sc_state |= NCR_ABORTING;
! 2249: ncr_sched_msgout(sc, SEND_ABORT);
! 2250: goto next_phase;
! 2251: }
! 2252: delay(100);
! 2253: }
! 2254:
! 2255: phase = SCI_BUS_PHASE(*sc->sci_bus_csr);
! 2256: NCR_TRACE("machine: phase=%s\n",
! 2257: (long) phase_names[phase & 7]);
! 2258:
! 2259: /*
! 2260: * We assume that the device knows what it's doing,
! 2261: * so any phase is good.
! 2262: */
! 2263:
! 2264: #if 0
! 2265: /*
! 2266: * XXX: Do not ACK the phase yet! do it later...
! 2267: * XXX: ... each phase routine does that itself.
! 2268: * In particular, DMA needs it done LATER.
! 2269: */
! 2270: *sc->sci_tcmd = phase; /* acknowledge phase change */
! 2271: #endif
! 2272:
! 2273: switch (phase) {
! 2274:
! 2275: case PHASE_DATA_OUT:
! 2276: case PHASE_DATA_IN:
! 2277: act_flags = ncr5380_data_xfer(sc, phase);
! 2278: break;
! 2279:
! 2280: case PHASE_COMMAND:
! 2281: act_flags = ncr5380_command(sc);
! 2282: break;
! 2283:
! 2284: case PHASE_STATUS:
! 2285: act_flags = ncr5380_status(sc);
! 2286: break;
! 2287:
! 2288: case PHASE_MSG_OUT:
! 2289: act_flags = ncr5380_msg_out(sc);
! 2290: break;
! 2291:
! 2292: case PHASE_MSG_IN:
! 2293: act_flags = ncr5380_msg_in(sc);
! 2294: break;
! 2295:
! 2296: default:
! 2297: printf("ncr5380_machine: Unexpected phase 0x%x\n", phase);
! 2298: sc->sc_state |= NCR_ABORTING;
! 2299: ncr_sched_msgout(sc, SEND_ABORT);
! 2300: goto next_phase;
! 2301:
! 2302: } /* switch */
! 2303: sc->sc_prevphase = phase;
! 2304:
! 2305: do_actions:
! 2306: __asm("_ncr5380_actions:");
! 2307:
! 2308: if (act_flags & ACT_WAIT_DMA) {
! 2309: act_flags &= ~ACT_WAIT_DMA;
! 2310: /* Wait for DMA to complete (polling, or interrupt). */
! 2311: if ((sr->sr_flags & SR_IMMED) == 0) {
! 2312: NCR_TRACE("machine: wait for DMA intr.\n", 0);
! 2313: return; /* will resume at dma_done */
! 2314: }
! 2315: /* Busy-wait for it to finish. */
! 2316: NCR_TRACE("machine: dma_poll, dh=0x%x\n",
! 2317: (long) sr->sr_dma_hand);
! 2318: (*sc->sc_dma_poll)(sc);
! 2319: dma_done:
! 2320: /* Return here after interrupt. */
! 2321: if (sr->sr_flags & SR_OVERDUE)
! 2322: sc->sc_state |= NCR_ABORTING;
! 2323: NCR_TRACE("machine: dma_stop, dh=0x%x\n",
! 2324: (long) sr->sr_dma_hand);
! 2325: (*sc->sc_dma_stop)(sc);
! 2326: SCI_CLR_INTR(sc); /* XXX */
! 2327: /*
! 2328: * While DMA is running we can not touch the SBC,
! 2329: * so various places just set NCR_ABORTING and
! 2330: * expect us the "kick it" when DMA is done.
! 2331: */
! 2332: if (sc->sc_state & NCR_ABORTING) {
! 2333: ncr_sched_msgout(sc, SEND_ABORT);
! 2334: }
! 2335: }
! 2336:
! 2337: /*
! 2338: * Check for parity error.
! 2339: * XXX - better place to check?
! 2340: */
! 2341: if (*(sc->sci_csr) & SCI_CSR_PERR) {
! 2342: printf("%s: parity error!\n", sc->sc_dev.dv_xname);
! 2343: /* XXX: sc->sc_state |= NCR_ABORTING; */
! 2344: ncr_sched_msgout(sc, SEND_PARITY_ERROR);
! 2345: }
! 2346:
! 2347: if (act_flags == ACT_CONTINUE)
! 2348: goto next_phase;
! 2349: /* All other actions "break" from the loop. */
! 2350:
! 2351: NCR_TRACE("machine: act_flags=0x%x\n", act_flags);
! 2352:
! 2353: if (act_flags & ACT_RESET_BUS) {
! 2354: act_flags |= ACT_CMD_DONE;
! 2355: /*
! 2356: * Reset the SCSI bus, usually due to a timeout.
! 2357: * The error code XS_TIMEOUT allows retries.
! 2358: */
! 2359: sc->sc_state |= NCR_ABORTING;
! 2360: printf("%s: reset SCSI bus for TID=%d LUN=%d\n",
! 2361: sc->sc_dev.dv_xname, sr->sr_target, sr->sr_lun);
! 2362: ncr5380_reset_scsibus(sc);
! 2363: }
! 2364:
! 2365: if (act_flags & ACT_CMD_DONE) {
! 2366: act_flags |= ACT_DISCONNECT;
! 2367: /* Need to call scsi_done() */
! 2368: /* XXX: from the aic6360 driver, but why? */
! 2369: if (sc->sc_datalen < 0) {
! 2370: printf("%s: %d extra bytes from %d:%d\n",
! 2371: sc->sc_dev.dv_xname, -sc->sc_datalen,
! 2372: sr->sr_target, sr->sr_lun);
! 2373: sc->sc_datalen = 0;
! 2374: }
! 2375: xs->resid = sc->sc_datalen;
! 2376: /* Note: this will clear sc_current */
! 2377: NCR_TRACE("machine: call done, cur=0x%x\n", (long)sr);
! 2378: ncr5380_done(sc);
! 2379: }
! 2380:
! 2381: if (act_flags & ACT_DISCONNECT) {
! 2382: /*
! 2383: * The device has dropped BSY (or will soon).
! 2384: * We have to wait here for BSY to drop, otherwise
! 2385: * the next command may decide we need a bus reset.
! 2386: */
! 2387: timo = ncr5380_wait_req_timo; /* XXX */
! 2388: for (;;) {
! 2389: if (!SCI_BUSY(sc))
! 2390: goto busfree;
! 2391: if (--timo <= 0)
! 2392: break;
! 2393: delay(2);
! 2394: }
! 2395: /* Device is sitting on the bus! */
! 2396: printf("%s: Target %d LUN %d stuck busy, resetting...\n",
! 2397: sc->sc_dev.dv_xname, sr->sr_target, sr->sr_lun);
! 2398: ncr5380_reset_scsibus(sc);
! 2399: busfree:
! 2400: NCR_TRACE("machine: discon, waited %d\n",
! 2401: ncr5380_wait_req_timo - timo);
! 2402:
! 2403: *sc->sci_icmd = 0;
! 2404: *sc->sci_mode = 0;
! 2405: *sc->sci_tcmd = PHASE_INVALID;
! 2406: *sc->sci_sel_enb = 0;
! 2407: SCI_CLR_INTR(sc);
! 2408: *sc->sci_sel_enb = 0x80;
! 2409:
! 2410: if ((act_flags & ACT_CMD_DONE) == 0) {
! 2411: __asm("_ncr5380_disconnected:");
! 2412: NCR_TRACE("machine: discon, cur=0x%x\n", (long)sr);
! 2413: }
! 2414:
! 2415: /*
! 2416: * We may be here due to a disconnect message,
! 2417: * in which case we did NOT call ncr5380_done,
! 2418: * and we need to clear sc_current.
! 2419: */
! 2420: sc->sc_state = NCR_IDLE;
! 2421: sc->sc_current = NULL;
! 2422:
! 2423: /* Paranoia: clear everything. */
! 2424: sc->sc_dataptr = NULL;
! 2425: sc->sc_datalen = 0;
! 2426: sc->sc_prevphase = PHASE_INVALID;
! 2427: sc->sc_msgpriq = 0;
! 2428: sc->sc_msgoutq = 0;
! 2429: sc->sc_msgout = 0;
! 2430:
! 2431: /* Our caller will re-enable interrupts. */
! 2432: }
! 2433: }
! 2434:
! 2435:
! 2436: #ifdef NCR5380_DEBUG
! 2437:
! 2438: static void
! 2439: ncr5380_show_scsi_cmd(xs)
! 2440: struct scsi_xfer *xs;
! 2441: {
! 2442: u_char *b = (u_char *) xs->cmd;
! 2443: int i = 0;
! 2444:
! 2445: if ( ! ( xs->flags & SCSI_RESET ) ) {
! 2446: printf("si(%d:%d:%d)-",
! 2447: xs->sc_link->scsibus, xs->sc_link->target,
! 2448: xs->sc_link->lun);
! 2449: while (i < xs->cmdlen) {
! 2450: if (i) printf(",");
! 2451: printf("%x",b[i++]);
! 2452: }
! 2453: printf("-\n");
! 2454: } else {
! 2455: printf("si(%d:%d:%d)-RESET-\n",
! 2456: xs->sc_link->scsibus, xs->sc_link->target,
! 2457: xs->sc_link->lun);
! 2458: }
! 2459: }
! 2460:
! 2461:
! 2462: static void
! 2463: ncr5380_show_sense(xs)
! 2464: struct scsi_xfer *xs;
! 2465: {
! 2466: u_char *b = (u_char *)&xs->sense;
! 2467: int i;
! 2468:
! 2469: printf("sense:");
! 2470: for (i = 0; i < sizeof(xs->sense); i++)
! 2471: printf(" %02x", b[i]);
! 2472: printf("\n");
! 2473: }
! 2474:
! 2475: int ncr5380_traceidx = 0;
! 2476:
! 2477: #define TRACE_MAX 1024
! 2478: struct trace_ent {
! 2479: char *msg;
! 2480: long val;
! 2481: } ncr5380_tracebuf[TRACE_MAX];
! 2482:
! 2483: void
! 2484: ncr5380_trace(msg, val)
! 2485: char *msg;
! 2486: long val;
! 2487: {
! 2488: register struct trace_ent *tr;
! 2489: register int s;
! 2490:
! 2491: s = splbio();
! 2492:
! 2493: tr = &ncr5380_tracebuf[ncr5380_traceidx];
! 2494:
! 2495: ncr5380_traceidx++;
! 2496: if (ncr5380_traceidx >= TRACE_MAX)
! 2497: ncr5380_traceidx = 0;
! 2498:
! 2499: tr->msg = msg;
! 2500: tr->val = val;
! 2501:
! 2502: splx(s);
! 2503: }
! 2504:
! 2505: #ifdef DDB
! 2506: void
! 2507: ncr5380_clear_trace()
! 2508: {
! 2509: ncr5380_traceidx = 0;
! 2510: bzero((char *) ncr5380_tracebuf, sizeof(ncr5380_tracebuf));
! 2511: }
! 2512:
! 2513: void
! 2514: ncr5380_show_trace()
! 2515: {
! 2516: struct trace_ent *tr;
! 2517: int idx;
! 2518:
! 2519: idx = ncr5380_traceidx;
! 2520: do {
! 2521: tr = &ncr5380_tracebuf[idx];
! 2522: idx++;
! 2523: if (idx >= TRACE_MAX)
! 2524: idx = 0;
! 2525: if (tr->msg)
! 2526: db_printf(tr->msg, tr->val);
! 2527: } while (idx != ncr5380_traceidx);
! 2528: }
! 2529:
! 2530: void
! 2531: ncr5380_show_req(sr)
! 2532: struct sci_req *sr;
! 2533: {
! 2534: struct scsi_xfer *xs = sr->sr_xs;
! 2535:
! 2536: db_printf("TID=%d ", sr->sr_target);
! 2537: db_printf("LUN=%d ", sr->sr_lun);
! 2538: db_printf("dh=%p ", sr->sr_dma_hand);
! 2539: db_printf("dptr=%p ", sr->sr_dataptr);
! 2540: db_printf("dlen=0x%x ", sr->sr_datalen);
! 2541: db_printf("flags=%d ", sr->sr_flags);
! 2542: db_printf("stat=%d ", sr->sr_status);
! 2543:
! 2544: if (xs == NULL) {
! 2545: db_printf("(xs=NULL)\n");
! 2546: return;
! 2547: }
! 2548: db_printf("\n");
! 2549: #ifdef SCSIDEBUG
! 2550: show_scsi_xs(xs);
! 2551: #else
! 2552: db_printf("xs=%p\n", xs);
! 2553: #endif
! 2554: }
! 2555:
! 2556: void
! 2557: ncr5380_show_state()
! 2558: {
! 2559: struct ncr5380_softc *sc;
! 2560: struct sci_req *sr;
! 2561: int i, j, k;
! 2562:
! 2563: sc = ncr5380_debug_sc;
! 2564:
! 2565: if (sc == NULL) {
! 2566: db_printf("ncr5380_debug_sc == NULL\n");
! 2567: return;
! 2568: }
! 2569:
! 2570: db_printf("sc_ncmds=%d\n", sc->sc_ncmds);
! 2571: k = -1; /* which is current? */
! 2572: for (i = 0; i < SCI_OPENINGS; i++) {
! 2573: sr = &sc->sc_ring[i];
! 2574: if (sr->sr_xs) {
! 2575: if (sr == sc->sc_current)
! 2576: k = i;
! 2577: db_printf("req %d: (sr=%p)", i, (long)sr);
! 2578: ncr5380_show_req(sr);
! 2579: }
! 2580: }
! 2581: db_printf("sc_rr=%d, current=%d\n", sc->sc_rr, k);
! 2582:
! 2583: db_printf("Active request matrix:\n");
! 2584: for(i = 0; i < 8; i++) { /* targets */
! 2585: for (j = 0; j < 8; j++) { /* LUN */
! 2586: sr = sc->sc_matrix[i][j];
! 2587: if (sr) {
! 2588: db_printf("TID=%d LUN=%d sr=0x%x\n", i, j, (long)sr);
! 2589: }
! 2590: }
! 2591: }
! 2592:
! 2593: db_printf("sc_state=0x%x\n", sc->sc_state);
! 2594: db_printf("sc_current=%p\n", sc->sc_current);
! 2595: db_printf("sc_dataptr=%p\n", sc->sc_dataptr);
! 2596: db_printf("sc_datalen=0x%x\n", sc->sc_datalen);
! 2597:
! 2598: db_printf("sc_prevphase=%d\n", sc->sc_prevphase);
! 2599: db_printf("sc_msgpriq=0x%x\n", sc->sc_msgpriq);
! 2600: }
! 2601:
! 2602: #endif /* DDB */
! 2603: #endif /* NCR5380_DEBUG */
CVSweb