Annotation of sys/arch/luna88k/dev/mb89352.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: mb89352.c,v 1.7 2006/11/28 23:59:45 dlg Exp $ */
! 2: /* $NetBSD: mb89352.c,v 1.5 2000/03/23 07:01:31 thorpej Exp $ */
! 3: /* NecBSD: mb89352.c,v 1.4 1998/03/14 07:31:20 kmatsuda Exp */
! 4:
! 5: #ifdef DDB
! 6: #define integrate
! 7: #else
! 8: #define integrate __inline static
! 9: #endif
! 10:
! 11: /*-
! 12: * Copyright (c) 1996,97,98,99 The NetBSD Foundation, Inc.
! 13: * All rights reserved.
! 14: *
! 15: * This code is derived from software contributed to The NetBSD Foundation
! 16: * by Charles M. Hannum, Masaru Oki and Kouichi Matsuda.
! 17: *
! 18: * Redistribution and use in source and binary forms, with or without
! 19: * modification, are permitted provided that the following conditions
! 20: * are met:
! 21: * 1. Redistributions of source code must retain the above copyright
! 22: * notice, this list of conditions and the following disclaimer.
! 23: * 2. Redistributions in binary form must reproduce the above copyright
! 24: * notice, this list of conditions and the following disclaimer in the
! 25: * documentation and/or other materials provided with the distribution.
! 26: * 3. All advertising materials mentioning features or use of this software
! 27: * must display the following acknowledgement:
! 28: * This product includes software developed by Charles M. Hannum.
! 29: * 4. The name of the author may not be used to endorse or promote products
! 30: * derived from this software without specific prior written permission.
! 31: *
! 32: * Copyright (c) 1994 Jarle Greipsland
! 33: * All rights reserved.
! 34: *
! 35: * Redistribution and use in source and binary forms, with or without
! 36: * modification, are permitted provided that the following conditions
! 37: * are met:
! 38: * 1. Redistributions of source code must retain the above copyright
! 39: * notice, this list of conditions and the following disclaimer.
! 40: * 2. Redistributions in binary form must reproduce the above copyright
! 41: * notice, this list of conditions and the following disclaimer in the
! 42: * documentation and/or other materials provided with the distribution.
! 43: * 3. The name of the author may not be used to endorse or promote products
! 44: * derived from this software without specific prior written permission.
! 45: *
! 46: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 47: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
! 48: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
! 49: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
! 50: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
! 51: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
! 52: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 53: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
! 54: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
! 55: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 56: * POSSIBILITY OF SUCH DAMAGE.
! 57: */
! 58: /*
! 59: * [NetBSD for NEC PC-98 series]
! 60: * Copyright (c) 1996, 1997, 1998
! 61: * NetBSD/pc98 porting staff. All rights reserved.
! 62: * Copyright (c) 1996, 1997, 1998
! 63: * Kouichi Matsuda. All rights reserved.
! 64: */
! 65:
! 66: /*
! 67: * Acknowledgements: Many of the algorithms used in this driver are
! 68: * inspired by the work of Julian Elischer (julian@tfs.com) and
! 69: * Charles Hannum (mycroft@duality.gnu.ai.mit.edu). Thanks a million!
! 70: */
! 71:
! 72: /* TODO list:
! 73: * 1) Get the DMA stuff working.
! 74: * 2) Get the iov/uio stuff working. Is this a good thing ???
! 75: * 3) Get the synch stuff working.
! 76: * 4) Rewrite it to use malloc for the acb structs instead of static alloc.?
! 77: */
! 78:
! 79: /*
! 80: * A few customizable items:
! 81: */
! 82:
! 83: /* Synchronous data transfers? */
! 84: #define SPC_USE_SYNCHRONOUS 0
! 85: #define SPC_SYNC_REQ_ACK_OFS 8
! 86:
! 87: /* Wide data transfers? */
! 88: #define SPC_USE_WIDE 0
! 89: #define SPC_MAX_WIDTH 0
! 90:
! 91: /* Max attempts made to transmit a message */
! 92: #define SPC_MSG_MAX_ATTEMPT 3 /* Not used now XXX */
! 93:
! 94: /*
! 95: * Some spin loop parameters (essentially how long to wait some places)
! 96: * The problem(?) is that sometimes we expect either to be able to transmit a
! 97: * byte or to get a new one from the SCSI bus pretty soon. In order to avoid
! 98: * returning from the interrupt just to get yanked back for the next byte we
! 99: * may spin in the interrupt routine waiting for this byte to come. How long?
! 100: * This is really (SCSI) device and processor dependent. Tuneable, I guess.
! 101: */
! 102: #define SPC_MSGIN_SPIN 1 /* Will spinwait upto ?ms for a new msg byte */
! 103: #define SPC_MSGOUT_SPIN 1
! 104:
! 105: /*
! 106: * Include debug functions? At the end of this file there are a bunch of
! 107: * functions that will print out various information regarding queued SCSI
! 108: * commands, driver state and chip contents. You can call them from the
! 109: * kernel debugger. If you set SPC_DEBUG to 0 they are not included (the
! 110: * kernel uses less memory) but you lose the debugging facilities.
! 111: */
! 112: /* #define SPC_DEBUG */
! 113:
! 114: #define SPC_ABORT_TIMEOUT 2000 /* time to wait for abort */
! 115:
! 116: /* End of customizable parameters */
! 117:
! 118: /*
! 119: * MB89352 SCSI Protocol Controller (SPC) routines.
! 120: */
! 121:
! 122: #include <sys/param.h>
! 123: #include <sys/systm.h>
! 124: #include <sys/kernel.h>
! 125: #include <sys/errno.h>
! 126: #include <sys/ioctl.h>
! 127: #include <sys/device.h>
! 128: #include <sys/buf.h>
! 129: #include <sys/proc.h>
! 130: #include <sys/user.h>
! 131: #include <sys/queue.h>
! 132:
! 133: #include <machine/intr.h>
! 134: #include <machine/bus.h>
! 135:
! 136: #include <scsi/scsi_all.h>
! 137: #include <scsi/scsi_message.h>
! 138: #include <scsi/scsiconf.h>
! 139:
! 140: #include <luna88k/dev/mb89352reg.h>
! 141: #include <luna88k/dev/mb89352var.h>
! 142:
! 143: #ifndef DDB
! 144: #define Debugger() panic("should call debugger here (mb89352.c)")
! 145: #endif /* ! DDB */
! 146:
! 147: #ifdef SPC_DEBUG
! 148: int spc_debug = 0x00; /* SPC_SHOWSTART|SPC_SHOWMISC|SPC_SHOWTRACE; */
! 149: #endif
! 150:
! 151: void spc_done (struct spc_softc *, struct spc_acb *);
! 152: void spc_dequeue (struct spc_softc *, struct spc_acb *);
! 153: int spc_scsi_cmd (struct scsi_xfer *);
! 154: int spc_poll (struct spc_softc *, struct scsi_xfer *, int);
! 155: integrate void spc_sched_msgout(struct spc_softc *, u_char);
! 156: integrate void spc_setsync(struct spc_softc *, struct spc_tinfo *);
! 157: void spc_select (struct spc_softc *, struct spc_acb *);
! 158: void spc_timeout (void *);
! 159: void spc_scsi_reset (struct spc_softc *);
! 160: void spc_reset (struct spc_softc *);
! 161: void spc_free_acb (struct spc_softc *, struct spc_acb *, int);
! 162: struct spc_acb* spc_get_acb(struct spc_softc *, int);
! 163: int spc_reselect (struct spc_softc *, int);
! 164: void spc_sense (struct spc_softc *, struct spc_acb *);
! 165: void spc_msgin (struct spc_softc *);
! 166: void spc_abort (struct spc_softc *, struct spc_acb *);
! 167: void spc_msgout (struct spc_softc *);
! 168: int spc_dataout_pio (struct spc_softc *, u_char *, int);
! 169: int spc_datain_pio (struct spc_softc *, u_char *, int);
! 170: #ifdef SPC_DEBUG
! 171: void spc_print_acb (struct spc_acb *);
! 172: void spc_dump_driver (struct spc_softc *);
! 173: void spc_dump89352 (struct spc_softc *);
! 174: void spc_show_scsi_cmd(struct spc_acb *);
! 175: void spc_print_active_acb(void);
! 176: #endif
! 177:
! 178: extern struct cfdriver spc_cd;
! 179:
! 180: struct scsi_device spc_dev = {
! 181: NULL, /* Use default error handler */
! 182: NULL, /* have a queue, served by this */
! 183: NULL, /* have no async handler */
! 184: NULL, /* Use default 'done' routine */
! 185: };
! 186:
! 187: /*
! 188: * INITIALIZATION ROUTINES (probe, attach ++)
! 189: */
! 190:
! 191: void
! 192: /* spc_attach(sc) */
! 193: spc_attach(sc, adapter)
! 194: struct spc_softc *sc;
! 195: struct scsi_adapter *adapter;
! 196: {
! 197: struct scsibus_attach_args saa;
! 198: SPC_TRACE(("spc_attach "));
! 199: sc->sc_state = SPC_INIT;
! 200:
! 201: sc->sc_freq = 20; /* XXXX Assume 20 MHz. */
! 202:
! 203: #if SPC_USE_SYNCHRONOUS
! 204: /*
! 205: * These are the bounds of the sync period, based on the frequency of
! 206: * the chip's clock input and the size and offset of the sync period
! 207: * register.
! 208: *
! 209: * For a 20MHz clock, this gives us 25, or 100nS, or 10MB/s, as a
! 210: * maximum transfer rate, and 112.5, or 450nS, or 2.22MB/s, as a
! 211: * minimum transfer rate.
! 212: */
! 213: sc->sc_minsync = (2 * 250) / sc->sc_freq;
! 214: sc->sc_maxsync = (9 * 250) / sc->sc_freq;
! 215: #endif
! 216:
! 217: spc_init(sc); /* Init chip and driver */
! 218:
! 219: /*
! 220: * Fill in the adapter.
! 221: */
! 222: sc->sc_link.adapter_softc = sc;
! 223: sc->sc_link.adapter_target = sc->sc_initiator;
! 224: sc->sc_link.adapter = adapter;
! 225: sc->sc_link.device = &spc_dev;
! 226: sc->sc_link.openings = 2;
! 227:
! 228: bzero(&saa, sizeof(saa));
! 229: saa.saa_sc_link = &sc->sc_link;
! 230:
! 231: /*
! 232: * ask the adapter what subunits are present
! 233: */
! 234: config_found(&sc->sc_dev, &saa, scsiprint);
! 235: }
! 236:
! 237: /*
! 238: * Initialize MB89352 chip itself
! 239: * The following conditions should hold:
! 240: * spc_isa_probe should have succeeded, i.e. the iobase address in spc_softc
! 241: * must be valid.
! 242: */
! 243: void
! 244: spc_reset(sc)
! 245: struct spc_softc *sc;
! 246: {
! 247: bus_space_tag_t iot = sc->sc_iot;
! 248: bus_space_handle_t ioh = sc->sc_ioh;
! 249:
! 250: SPC_TRACE(("spc_reset "));
! 251: /*
! 252: * Disable interrupts then reset the FUJITSU chip.
! 253: */
! 254: bus_space_write_1(iot, ioh, SCTL, SCTL_DISABLE | SCTL_CTRLRST);
! 255: bus_space_write_1(iot, ioh, SCMD, 0);
! 256: bus_space_write_1(iot, ioh, TMOD, 0);
! 257: bus_space_write_1(iot, ioh, PCTL, 0);
! 258: bus_space_write_1(iot, ioh, TEMP, 0);
! 259: bus_space_write_1(iot, ioh, TCH, 0);
! 260: bus_space_write_1(iot, ioh, TCM, 0);
! 261: bus_space_write_1(iot, ioh, TCL, 0);
! 262: bus_space_write_1(iot, ioh, INTS, 0);
! 263: bus_space_write_1(iot, ioh, SCTL,
! 264: SCTL_DISABLE | SCTL_ABRT_ENAB | SCTL_PARITY_ENAB | SCTL_RESEL_ENAB);
! 265: bus_space_write_1(iot, ioh, BDID, sc->sc_initiator);
! 266: delay(400);
! 267: bus_space_write_1(iot, ioh, SCTL,
! 268: bus_space_read_1(iot, ioh, SCTL) & ~SCTL_DISABLE);
! 269: }
! 270:
! 271:
! 272: /*
! 273: * Pull the SCSI RST line for 500us.
! 274: */
! 275: void
! 276: spc_scsi_reset(sc)
! 277: struct spc_softc *sc;
! 278: {
! 279: bus_space_tag_t iot = sc->sc_iot;
! 280: bus_space_handle_t ioh = sc->sc_ioh;
! 281:
! 282: SPC_TRACE(("spc_scsi_reset "));
! 283: bus_space_write_1(iot, ioh, SCMD, bus_space_read_1(iot, ioh, SCMD) | SCMD_RST);
! 284: delay(500);
! 285: bus_space_write_1(iot, ioh, SCMD, bus_space_read_1(iot, ioh, SCMD) & ~SCMD_RST);
! 286: delay(50);
! 287: }
! 288:
! 289: /*
! 290: * Initialize spc SCSI driver.
! 291: */
! 292: void
! 293: spc_init(sc)
! 294: struct spc_softc *sc;
! 295: {
! 296: struct spc_acb *acb;
! 297: int r;
! 298:
! 299: SPC_TRACE(("spc_init "));
! 300: spc_reset(sc);
! 301: spc_scsi_reset(sc);
! 302: spc_reset(sc);
! 303:
! 304: if (sc->sc_state == SPC_INIT) {
! 305: /* First time through; initialize. */
! 306: TAILQ_INIT(&sc->ready_list);
! 307: TAILQ_INIT(&sc->nexus_list);
! 308: TAILQ_INIT(&sc->free_list);
! 309: sc->sc_nexus = NULL;
! 310: acb = sc->sc_acb;
! 311: bzero(acb, sizeof(sc->sc_acb));
! 312: for (r = 0; r < sizeof(sc->sc_acb) / sizeof(*acb); r++) {
! 313: TAILQ_INSERT_TAIL(&sc->free_list, acb, chain);
! 314: acb++;
! 315: }
! 316: bzero(&sc->sc_tinfo, sizeof(sc->sc_tinfo));
! 317: } else {
! 318: /* Cancel any active commands. */
! 319: sc->sc_state = SPC_CLEANING;
! 320: if ((acb = sc->sc_nexus) != NULL) {
! 321: acb->xs->error = XS_DRIVER_STUFFUP;
! 322: timeout_del(&acb->xs->stimeout);
! 323: spc_done(sc, acb);
! 324: }
! 325: while ((acb = TAILQ_FIRST(&sc->nexus_list)) != NULL) {
! 326: acb->xs->error = XS_DRIVER_STUFFUP;
! 327: timeout_del(&acb->xs->stimeout);
! 328: spc_done(sc, acb);
! 329: }
! 330: }
! 331:
! 332: sc->sc_prevphase = PH_INVALID;
! 333: for (r = 0; r < 8; r++) {
! 334: struct spc_tinfo *ti = &sc->sc_tinfo[r];
! 335:
! 336: ti->flags = 0;
! 337: #if SPC_USE_SYNCHRONOUS
! 338: ti->flags |= DO_SYNC;
! 339: ti->period = sc->sc_minsync;
! 340: ti->offset = SPC_SYNC_REQ_ACK_OFS;
! 341: #else
! 342: ti->period = ti->offset = 0;
! 343: #endif
! 344: #if SPC_USE_WIDE
! 345: ti->flags |= DO_WIDE;
! 346: ti->width = SPC_MAX_WIDTH;
! 347: #else
! 348: ti->width = 0;
! 349: #endif
! 350: }
! 351:
! 352: sc->sc_state = SPC_IDLE;
! 353: bus_space_write_1(sc->sc_iot, sc->sc_ioh, SCTL,
! 354: bus_space_read_1(sc->sc_iot, sc->sc_ioh, SCTL) | SCTL_INTR_ENAB);
! 355: }
! 356:
! 357: void
! 358: spc_free_acb(sc, acb, flags)
! 359: struct spc_softc *sc;
! 360: struct spc_acb *acb;
! 361: int flags;
! 362: {
! 363: int s;
! 364:
! 365: SPC_TRACE(("spc_free_acb "));
! 366: s = splbio();
! 367:
! 368: acb->flags = 0;
! 369: TAILQ_INSERT_HEAD(&sc->free_list, acb, chain);
! 370:
! 371: /*
! 372: * If there were none, wake anybody waiting for one to come free,
! 373: * starting with queued entries.
! 374: */
! 375: if (TAILQ_NEXT(acb, chain) == NULL)
! 376: wakeup(&sc->free_list);
! 377:
! 378: splx(s);
! 379: }
! 380:
! 381: struct spc_acb *
! 382: spc_get_acb(sc, flags)
! 383: struct spc_softc *sc;
! 384: int flags;
! 385: {
! 386: struct spc_acb *acb;
! 387: int s;
! 388:
! 389: SPC_TRACE(("spc_get_acb "));
! 390: s = splbio();
! 391:
! 392: while ((acb = TAILQ_FIRST(&sc->free_list)) == NULL &&
! 393: (flags & SCSI_NOSLEEP) == 0)
! 394: tsleep(&sc->free_list, PRIBIO, "spcacb", 0);
! 395: if (acb) {
! 396: TAILQ_REMOVE(&sc->free_list, acb, chain);
! 397: acb->flags |= ACB_ALLOC;
! 398: }
! 399:
! 400: splx(s);
! 401: return acb;
! 402: }
! 403:
! 404: /*
! 405: * DRIVER FUNCTIONS CALLABLE FROM HIGHER LEVEL DRIVERS
! 406: */
! 407:
! 408: /*
! 409: * Expected sequence:
! 410: * 1) Command inserted into ready list
! 411: * 2) Command selected for execution
! 412: * 3) Command won arbitration and has selected target device
! 413: * 4) Send message out (identify message, eventually also sync.negotiations)
! 414: * 5) Send command
! 415: * 5a) Receive disconnect message, disconnect.
! 416: * 5b) Reselected by target
! 417: * 5c) Receive identify message from target.
! 418: * 6) Send or receive data
! 419: * 7) Receive status
! 420: * 8) Receive message (command complete etc.)
! 421: * 9) If status == SCSI_CHECK construct a synthetic request sense SCSI cmd.
! 422: * Repeat 2-8 (no disconnects please...)
! 423: */
! 424:
! 425: /*
! 426: * Start a SCSI-command
! 427: * This function is called by the higher level SCSI-driver to queue/run
! 428: * SCSI-commands.
! 429: */
! 430: int
! 431: spc_scsi_cmd(xs)
! 432: struct scsi_xfer *xs;
! 433: {
! 434: struct scsi_link *sc_link = xs->sc_link;
! 435: struct spc_softc *sc = sc_link->adapter_softc;
! 436: struct spc_acb *acb;
! 437: int s, flags;
! 438:
! 439: SPC_TRACE(("spc_scsi_cmd "));
! 440: SPC_CMDS(("[0x%x, %d]->%d ", (int)xs->cmd->opcode, xs->cmdlen,
! 441: sc_link->target));
! 442:
! 443: flags = xs->flags;
! 444: if ((acb = spc_get_acb(sc, flags)) == NULL) {
! 445: return TRY_AGAIN_LATER;
! 446: }
! 447:
! 448: /* Initialize acb */
! 449: acb->xs = xs;
! 450: acb->timeout = xs->timeout;
! 451:
! 452: if (xs->flags & SCSI_RESET) {
! 453: acb->flags |= ACB_RESET;
! 454: acb->scsi_cmd_length = 0;
! 455: acb->data_length = 0;
! 456: } else {
! 457: bcopy(xs->cmd, &acb->scsi_cmd, xs->cmdlen);
! 458: acb->scsi_cmd_length = xs->cmdlen;
! 459: acb->data_addr = xs->data;
! 460: acb->data_length = xs->datalen;
! 461: }
! 462: acb->target_stat = 0;
! 463:
! 464: s = splbio();
! 465:
! 466: TAILQ_INSERT_TAIL(&sc->ready_list, acb, chain);
! 467: /*
! 468: * Start scheduling unless a queue process is in progress.
! 469: */
! 470: if (sc->sc_state == SPC_IDLE)
! 471: spc_sched(sc);
! 472: /*
! 473: * After successful sending, check if we should return just now.
! 474: * If so, return SUCCESSFULLY_QUEUED.
! 475: */
! 476:
! 477: splx(s);
! 478:
! 479: if ((flags & SCSI_POLL) == 0)
! 480: return SUCCESSFULLY_QUEUED;
! 481:
! 482: /* Not allowed to use interrupts, use polling instead */
! 483: s = splbio();
! 484: if (spc_poll(sc, xs, acb->timeout)) {
! 485: spc_timeout(acb);
! 486: if (spc_poll(sc, xs, acb->timeout))
! 487: spc_timeout(acb);
! 488: }
! 489: splx(s);
! 490: return COMPLETE;
! 491: }
! 492:
! 493: /*
! 494: * Used when interrupt driven I/O isn't allowed, e.g. during boot.
! 495: */
! 496: int
! 497: spc_poll(sc, xs, count)
! 498: struct spc_softc *sc;
! 499: struct scsi_xfer *xs;
! 500: int count;
! 501: {
! 502: bus_space_tag_t iot = sc->sc_iot;
! 503: bus_space_handle_t ioh = sc->sc_ioh;
! 504:
! 505: SPC_TRACE(("spc_poll "));
! 506: while (count) {
! 507: /*
! 508: * If we had interrupts enabled, would we
! 509: * have got an interrupt?
! 510: */
! 511: if (bus_space_read_1(iot, ioh, INTS) != 0)
! 512: spc_intr(sc);
! 513: if ((xs->flags & ITSDONE) != 0)
! 514: return 0;
! 515: delay(1000);
! 516: count--;
! 517: }
! 518: return 1;
! 519: }
! 520:
! 521: /*
! 522: * LOW LEVEL SCSI UTILITIES
! 523: */
! 524:
! 525: integrate void
! 526: spc_sched_msgout(sc, m)
! 527: struct spc_softc *sc;
! 528: u_char m;
! 529: {
! 530: bus_space_tag_t iot = sc->sc_iot;
! 531: bus_space_handle_t ioh = sc->sc_ioh;
! 532:
! 533: SPC_TRACE(("spc_sched_msgout "));
! 534: if (sc->sc_msgpriq == 0)
! 535: bus_space_write_1(iot, ioh, SCMD, SCMD_SET_ATN);
! 536: sc->sc_msgpriq |= m;
! 537: }
! 538:
! 539: /*
! 540: * Set synchronous transfer offset and period.
! 541: */
! 542: integrate void
! 543: spc_setsync(sc, ti)
! 544: struct spc_softc *sc;
! 545: struct spc_tinfo *ti;
! 546: {
! 547: #if SPC_USE_SYNCHRONOUS
! 548: bus_space_tag_t iot = sc->sc_iot;
! 549: bus_space_handle_t ioh = sc->sc_ioh;
! 550:
! 551: SPC_TRACE(("spc_setsync "));
! 552: if (ti->offset != 0)
! 553: bus_space_write_1(iot, ioh, TMOD,
! 554: ((ti->period * sc->sc_freq) / 250 - 2) << 4 | ti->offset);
! 555: else
! 556: bus_space_write_1(iot, ioh, TMOD, 0);
! 557: #endif
! 558: }
! 559:
! 560: /*
! 561: * Start a selection. This is used by spc_sched() to select an idle target,
! 562: * and by spc_done() to immediately reselect a target to get sense information.
! 563: */
! 564: void
! 565: spc_select(sc, acb)
! 566: struct spc_softc *sc;
! 567: struct spc_acb *acb;
! 568: {
! 569: struct scsi_link *sc_link = acb->xs->sc_link;
! 570: int target = sc_link->target;
! 571: struct spc_tinfo *ti = &sc->sc_tinfo[target];
! 572: bus_space_tag_t iot = sc->sc_iot;
! 573: bus_space_handle_t ioh = sc->sc_ioh;
! 574:
! 575: SPC_TRACE(("spc_select "));
! 576: spc_setsync(sc, ti);
! 577:
! 578: #if 0
! 579: bus_space_write_1(iot, ioh, SCMD, SCMD_SET_ATN);
! 580: #endif
! 581:
! 582: bus_space_write_1(iot, ioh, PCTL, 0);
! 583: bus_space_write_1(iot, ioh, TEMP,
! 584: (1 << sc->sc_initiator) | (1 << target));
! 585: /*
! 586: * Setup BSY timeout (selection timeout).
! 587: * 250ms according to the SCSI specification.
! 588: * T = (X * 256 + 15) * Tclf * 2 (Tclf = 200ns on x68k)
! 589: * To setup 256ms timeout,
! 590: * 128000ns/200ns = X * 256 + 15
! 591: * 640 - 15 = X * 256
! 592: * X = 625 / 256
! 593: * X = 2 + 113 / 256
! 594: * ==> tch = 2, tcm = 113 (correct?)
! 595: */
! 596: /* Time to the information transfer phase start. */
! 597: /* XXX These values should be calculated from sc_freq */
! 598: bus_space_write_1(iot, ioh, TCH, 2);
! 599: bus_space_write_1(iot, ioh, TCM, 113);
! 600: bus_space_write_1(iot, ioh, TCL, 3);
! 601: bus_space_write_1(iot, ioh, SCMD, SCMD_SELECT);
! 602:
! 603: sc->sc_state = SPC_SELECTING;
! 604: }
! 605:
! 606: int
! 607: spc_reselect(sc, message)
! 608: struct spc_softc *sc;
! 609: int message;
! 610: {
! 611: u_char selid, target, lun;
! 612: struct spc_acb *acb;
! 613: struct scsi_link *sc_link;
! 614: struct spc_tinfo *ti;
! 615:
! 616: SPC_TRACE(("spc_reselect "));
! 617: /*
! 618: * The SCSI chip made a snapshot of the data bus while the reselection
! 619: * was being negotiated. This enables us to determine which target did
! 620: * the reselect.
! 621: */
! 622: selid = sc->sc_selid & ~(1 << sc->sc_initiator);
! 623: if (selid & (selid - 1)) {
! 624: printf("%s: reselect with invalid selid %02x; "
! 625: "sending DEVICE RESET\n", sc->sc_dev.dv_xname, selid);
! 626: SPC_BREAK();
! 627: goto reset;
! 628: }
! 629:
! 630: /*
! 631: * Search wait queue for disconnected cmd
! 632: * The list should be short, so I haven't bothered with
! 633: * any more sophisticated structures than a simple
! 634: * singly linked list.
! 635: */
! 636: target = ffs(selid) - 1;
! 637: lun = message & 0x07;
! 638: TAILQ_FOREACH(acb, &sc->nexus_list, chain) {
! 639: sc_link = acb->xs->sc_link;
! 640: if (sc_link->target == target &&
! 641: sc_link->lun == lun)
! 642: break;
! 643: }
! 644: if (acb == NULL) {
! 645: printf("%s: reselect from target %d lun %d with no nexus; "
! 646: "sending ABORT\n", sc->sc_dev.dv_xname, target, lun);
! 647: SPC_BREAK();
! 648: goto abort;
! 649: }
! 650:
! 651: /* Make this nexus active again. */
! 652: TAILQ_REMOVE(&sc->nexus_list, acb, chain);
! 653: sc->sc_state = SPC_CONNECTED;
! 654: sc->sc_nexus = acb;
! 655: ti = &sc->sc_tinfo[target];
! 656: ti->lubusy |= (1 << lun);
! 657: spc_setsync(sc, ti);
! 658:
! 659: if (acb->flags & ACB_RESET)
! 660: spc_sched_msgout(sc, SEND_DEV_RESET);
! 661: else if (acb->flags & ACB_ABORT)
! 662: spc_sched_msgout(sc, SEND_ABORT);
! 663:
! 664: /* Do an implicit RESTORE POINTERS. */
! 665: sc->sc_dp = acb->data_addr;
! 666: sc->sc_dleft = acb->data_length;
! 667: sc->sc_cp = (u_char *)&acb->scsi_cmd;
! 668: sc->sc_cleft = acb->scsi_cmd_length;
! 669:
! 670: return (0);
! 671:
! 672: reset:
! 673: spc_sched_msgout(sc, SEND_DEV_RESET);
! 674: return (1);
! 675:
! 676: abort:
! 677: spc_sched_msgout(sc, SEND_ABORT);
! 678: return (1);
! 679: }
! 680:
! 681: /*
! 682: * Schedule a SCSI operation. This has now been pulled out of the interrupt
! 683: * handler so that we may call it from spc_scsi_cmd and spc_done. This may
! 684: * save us an unnecessary interrupt just to get things going. Should only be
! 685: * called when state == SPC_IDLE and at bio pl.
! 686: */
! 687: void
! 688: spc_sched(sc)
! 689: struct spc_softc *sc;
! 690: {
! 691: struct spc_acb *acb;
! 692: struct scsi_link *sc_link;
! 693: struct spc_tinfo *ti;
! 694:
! 695: /* missing the hw, just return and wait for our hw */
! 696: if (sc->sc_flags & SPC_INACTIVE)
! 697: return;
! 698: SPC_TRACE(("spc_sched "));
! 699: /*
! 700: * Find first acb in ready queue that is for a target/lunit pair that
! 701: * is not busy.
! 702: */
! 703: TAILQ_FOREACH(acb, &sc->ready_list, chain) {
! 704: sc_link = acb->xs->sc_link;
! 705: ti = &sc->sc_tinfo[sc_link->target];
! 706: if ((ti->lubusy & (1 << sc_link->lun)) == 0) {
! 707: SPC_MISC(("selecting %d:%d ",
! 708: sc_link->target, sc_link->lun));
! 709: TAILQ_REMOVE(&sc->ready_list, acb, chain);
! 710: sc->sc_nexus = acb;
! 711: spc_select(sc, acb);
! 712: return;
! 713: } else
! 714: SPC_MISC(("%d:%d busy\n",
! 715: sc_link->target, sc_link->lun));
! 716: }
! 717: SPC_MISC(("idle "));
! 718: /* Nothing to start; just enable reselections and wait. */
! 719: }
! 720:
! 721: void
! 722: spc_sense(sc, acb)
! 723: struct spc_softc *sc;
! 724: struct spc_acb *acb;
! 725: {
! 726: struct scsi_xfer *xs = acb->xs;
! 727: struct scsi_link *sc_link = xs->sc_link;
! 728: struct spc_tinfo *ti = &sc->sc_tinfo[sc_link->target];
! 729: struct scsi_sense *ss = (void *)&acb->scsi_cmd;
! 730:
! 731: SPC_MISC(("requesting sense "));
! 732: /* Next, setup a request sense command block */
! 733: bzero(ss, sizeof(*ss));
! 734: ss->opcode = REQUEST_SENSE;
! 735: ss->byte2 = sc_link->lun << 5;
! 736: ss->length = sizeof(struct scsi_sense_data);
! 737: acb->scsi_cmd_length = sizeof(*ss);
! 738: acb->data_addr = (char *)&xs->sense;
! 739: acb->data_length = sizeof(struct scsi_sense_data);
! 740: acb->flags |= ACB_SENSE;
! 741: ti->senses++;
! 742: if (acb->flags & ACB_NEXUS)
! 743: ti->lubusy &= ~(1 << sc_link->lun);
! 744: if (acb == sc->sc_nexus) {
! 745: spc_select(sc, acb);
! 746: } else {
! 747: spc_dequeue(sc, acb);
! 748: TAILQ_INSERT_HEAD(&sc->ready_list, acb, chain);
! 749: if (sc->sc_state == SPC_IDLE)
! 750: spc_sched(sc);
! 751: }
! 752: }
! 753:
! 754: /*
! 755: * POST PROCESSING OF SCSI_CMD (usually current)
! 756: */
! 757: void
! 758: spc_done(sc, acb)
! 759: struct spc_softc *sc;
! 760: struct spc_acb *acb;
! 761: {
! 762: struct scsi_xfer *xs = acb->xs;
! 763: struct scsi_link *sc_link = xs->sc_link;
! 764: struct spc_tinfo *ti = &sc->sc_tinfo[sc_link->target];
! 765:
! 766: SPC_TRACE(("spc_done "));
! 767:
! 768: /*
! 769: * Now, if we've come here with no error code, i.e. we've kept the
! 770: * initial XS_NOERROR, and the status code signals that we should
! 771: * check sense, we'll need to set up a request sense cmd block and
! 772: * push the command back into the ready queue *before* any other
! 773: * commands for this target/lunit, else we lose the sense info.
! 774: * We don't support chk sense conditions for the request sense cmd.
! 775: */
! 776: if (xs->error == XS_NOERROR) {
! 777: if (acb->flags & ACB_ABORT) {
! 778: xs->error = XS_DRIVER_STUFFUP;
! 779: } else if (acb->flags & ACB_SENSE) {
! 780: xs->error = XS_SENSE;
! 781: } else {
! 782: switch (acb->target_stat) {
! 783: case SCSI_CHECK:
! 784: /* First, save the return values */
! 785: xs->resid = acb->data_length;
! 786: xs->status = acb->target_stat;
! 787: spc_sense(sc, acb);
! 788: return;
! 789: case SCSI_BUSY:
! 790: xs->error = XS_BUSY;
! 791: break;
! 792: case SCSI_OK:
! 793: xs->resid = acb->data_length;
! 794: break;
! 795: default:
! 796: xs->error = XS_DRIVER_STUFFUP;
! 797: #ifdef SPC_DEBUG
! 798: printf("%s: spc_done: bad stat 0x%x\n",
! 799: sc->sc_dev.dv_xname, acb->target_stat);
! 800: #endif
! 801: break;
! 802: }
! 803: }
! 804: }
! 805:
! 806: xs->flags |= ITSDONE;
! 807:
! 808: #ifdef SPC_DEBUG
! 809: if ((spc_debug & SPC_SHOWMISC) != 0) {
! 810: if (xs->resid != 0)
! 811: printf("resid=%d ", xs->resid);
! 812: if (xs->error == XS_SENSE)
! 813: printf("sense=0x%02x\n", xs->sense.error_code);
! 814: else
! 815: printf("error=%d\n", xs->error);
! 816: }
! 817: #endif
! 818:
! 819: /*
! 820: * Remove the ACB from whatever queue it happens to be on.
! 821: */
! 822: if (acb->flags & ACB_NEXUS)
! 823: ti->lubusy &= ~(1 << sc_link->lun);
! 824: if (acb == sc->sc_nexus) {
! 825: sc->sc_nexus = NULL;
! 826: sc->sc_state = SPC_IDLE;
! 827: spc_sched(sc);
! 828: } else
! 829: spc_dequeue(sc, acb);
! 830:
! 831: spc_free_acb(sc, acb, xs->flags);
! 832: ti->cmds++;
! 833: scsi_done(xs);
! 834: }
! 835:
! 836: void
! 837: spc_dequeue(sc, acb)
! 838: struct spc_softc *sc;
! 839: struct spc_acb *acb;
! 840: {
! 841:
! 842: SPC_TRACE(("spc_dequeue "));
! 843: if (acb->flags & ACB_NEXUS)
! 844: TAILQ_REMOVE(&sc->nexus_list, acb, chain);
! 845: else
! 846: TAILQ_REMOVE(&sc->ready_list, acb, chain);
! 847: }
! 848:
! 849: /*
! 850: * INTERRUPT/PROTOCOL ENGINE
! 851: */
! 852:
! 853: #define IS1BYTEMSG(m) (((m) != 0x01 && (m) < 0x20) || (m) >= 0x80)
! 854: #define IS2BYTEMSG(m) (((m) & 0xf0) == 0x20)
! 855: #define ISEXTMSG(m) ((m) == 0x01)
! 856:
! 857: /*
! 858: * Precondition:
! 859: * The SCSI bus is already in the MSGI phase and there is a message byte
! 860: * on the bus, along with an asserted REQ signal.
! 861: */
! 862: void
! 863: spc_msgin(sc)
! 864: struct spc_softc *sc;
! 865: {
! 866: bus_space_tag_t iot = sc->sc_iot;
! 867: bus_space_handle_t ioh = sc->sc_ioh;
! 868: int n;
! 869:
! 870: SPC_TRACE(("spc_msgin "));
! 871:
! 872: if (sc->sc_prevphase == PH_MSGIN) {
! 873: /* This is a continuation of the previous message. */
! 874: n = sc->sc_imp - sc->sc_imess;
! 875: goto nextbyte;
! 876: }
! 877:
! 878: /* This is a new MESSAGE IN phase. Clean up our state. */
! 879: sc->sc_flags &= ~SPC_DROP_MSGIN;
! 880:
! 881: nextmsg:
! 882: n = 0;
! 883: sc->sc_imp = &sc->sc_imess[n];
! 884:
! 885: nextbyte:
! 886: /*
! 887: * Read a whole message, but don't ack the last byte. If we reject the
! 888: * message, we have to assert ATN during the message transfer phase
! 889: * itself.
! 890: */
! 891: for (;;) {
! 892: #if 0
! 893: for (;;) {
! 894: if ((bus_space_read_1(iot, ioh, PSNS) & PSNS_REQ) != 0)
! 895: break;
! 896: /* Wait for REQINIT. XXX Need timeout. */
! 897: }
! 898: #endif
! 899: if (bus_space_read_1(iot, ioh, INTS) != 0) {
! 900: /*
! 901: * Target left MESSAGE IN, probably because it
! 902: * a) noticed our ATN signal, or
! 903: * b) ran out of messages.
! 904: */
! 905: goto out;
! 906: }
! 907:
! 908: /* If parity error, just dump everything on the floor. */
! 909: if ((bus_space_read_1(iot, ioh, SERR) &
! 910: (SERR_SCSI_PAR|SERR_SPC_PAR)) != 0) {
! 911: sc->sc_flags |= SPC_DROP_MSGIN;
! 912: spc_sched_msgout(sc, SEND_PARITY_ERROR);
! 913: }
! 914:
! 915: /* send TRANSFER command. */
! 916: bus_space_write_1(iot, ioh, TCH, 0);
! 917: bus_space_write_1(iot, ioh, TCM, 0);
! 918: bus_space_write_1(iot, ioh, TCL, 1);
! 919: bus_space_write_1(iot, ioh, PCTL,
! 920: sc->sc_phase | PCTL_BFINT_ENAB);
! 921: #ifdef x68k
! 922: bus_space_write_1(iot, ioh, SCMD, SCMD_XFR); /* | SCMD_PROG_XFR */
! 923: #else
! 924: bus_space_write_1(iot, ioh, SCMD, SCMD_XFR | SCMD_PROG_XFR); /* XXX */
! 925: #endif
! 926: for (;;) {
! 927: /*if ((bus_space_read_1(iot, ioh, SSTS) & SSTS_BUSY) != 0
! 928: && (bus_space_read_1(iot, ioh, SSTS) & SSTS_DREG_EMPTY) != 0)*/
! 929: if ((bus_space_read_1(iot, ioh, SSTS) & SSTS_DREG_EMPTY) == 0)
! 930: break;
! 931: if (bus_space_read_1(iot, ioh, INTS) != 0)
! 932: goto out;
! 933: }
! 934:
! 935: /* Gather incoming message bytes if needed. */
! 936: if ((sc->sc_flags & SPC_DROP_MSGIN) == 0) {
! 937: if (n >= SPC_MAX_MSG_LEN) {
! 938: (void) bus_space_read_1(iot, ioh, DREG);
! 939: sc->sc_flags |= SPC_DROP_MSGIN;
! 940: spc_sched_msgout(sc, SEND_REJECT);
! 941: } else {
! 942: *sc->sc_imp++ = bus_space_read_1(iot, ioh, DREG);
! 943: n++;
! 944: /*
! 945: * This testing is suboptimal, but most
! 946: * messages will be of the one byte variety, so
! 947: * it should not affect performance
! 948: * significantly.
! 949: */
! 950: if (n == 1 && IS1BYTEMSG(sc->sc_imess[0]))
! 951: break;
! 952: if (n == 2 && IS2BYTEMSG(sc->sc_imess[0]))
! 953: break;
! 954: if (n >= 3 && ISEXTMSG(sc->sc_imess[0]) &&
! 955: n == sc->sc_imess[1] + 2)
! 956: break;
! 957: }
! 958: } else
! 959: (void) bus_space_read_1(iot, ioh, DREG);
! 960:
! 961: /*
! 962: * If we reach this spot we're either:
! 963: * a) in the middle of a multi-byte message, or
! 964: * b) dropping bytes.
! 965: */
! 966: #if 0
! 967: /* Ack the last byte read. */
! 968: /*(void) bus_space_read_1(iot, ioh, DREG);*/
! 969: while ((bus_space_read_1(iot, ioh, PSNS) & ACKI) != 0)
! 970: ;
! 971: #endif
! 972: }
! 973:
! 974: SPC_MISC(("n=%d imess=0x%02x ", n, sc->sc_imess[0]));
! 975:
! 976: /* We now have a complete message. Parse it. */
! 977: switch (sc->sc_state) {
! 978: struct spc_acb *acb;
! 979: struct scsi_link *sc_link;
! 980: struct spc_tinfo *ti;
! 981:
! 982: case SPC_CONNECTED:
! 983: SPC_ASSERT(sc->sc_nexus != NULL);
! 984: acb = sc->sc_nexus;
! 985: ti = &sc->sc_tinfo[acb->xs->sc_link->target];
! 986:
! 987: switch (sc->sc_imess[0]) {
! 988: case MSG_CMDCOMPLETE:
! 989: if (sc->sc_dleft < 0) {
! 990: sc_link = acb->xs->sc_link;
! 991: printf("%s: %d extra bytes from %d:%d\n",
! 992: sc->sc_dev.dv_xname, -sc->sc_dleft,
! 993: sc_link->target, sc_link->lun);
! 994: acb->data_length = 0;
! 995: }
! 996: acb->xs->resid = acb->data_length = sc->sc_dleft;
! 997: sc->sc_state = SPC_CMDCOMPLETE;
! 998: break;
! 999:
! 1000: case MSG_PARITY_ERROR:
! 1001: /* Resend the last message. */
! 1002: spc_sched_msgout(sc, sc->sc_lastmsg);
! 1003: break;
! 1004:
! 1005: case MSG_MESSAGE_REJECT:
! 1006: SPC_MISC(("message rejected %02x ", sc->sc_lastmsg));
! 1007: switch (sc->sc_lastmsg) {
! 1008: #if SPC_USE_SYNCHRONOUS + SPC_USE_WIDE
! 1009: case SEND_IDENTIFY:
! 1010: ti->flags &= ~(DO_SYNC | DO_WIDE);
! 1011: ti->period = ti->offset = 0;
! 1012: spc_setsync(sc, ti);
! 1013: ti->width = 0;
! 1014: break;
! 1015: #endif
! 1016: #if SPC_USE_SYNCHRONOUS
! 1017: case SEND_SDTR:
! 1018: ti->flags &= ~DO_SYNC;
! 1019: ti->period = ti->offset = 0;
! 1020: spc_setsync(sc, ti);
! 1021: break;
! 1022: #endif
! 1023: #if SPC_USE_WIDE
! 1024: case SEND_WDTR:
! 1025: ti->flags &= ~DO_WIDE;
! 1026: ti->width = 0;
! 1027: break;
! 1028: #endif
! 1029: case SEND_INIT_DET_ERR:
! 1030: spc_sched_msgout(sc, SEND_ABORT);
! 1031: break;
! 1032: }
! 1033: break;
! 1034:
! 1035: case MSG_NOOP:
! 1036: break;
! 1037:
! 1038: case MSG_DISCONNECT:
! 1039: ti->dconns++;
! 1040: sc->sc_state = SPC_DISCONNECT;
! 1041: break;
! 1042:
! 1043: case MSG_SAVEDATAPOINTER:
! 1044: acb->data_addr = sc->sc_dp;
! 1045: acb->data_length = sc->sc_dleft;
! 1046: break;
! 1047:
! 1048: case MSG_RESTOREPOINTERS:
! 1049: sc->sc_dp = acb->data_addr;
! 1050: sc->sc_dleft = acb->data_length;
! 1051: sc->sc_cp = (u_char *)&acb->scsi_cmd;
! 1052: sc->sc_cleft = acb->scsi_cmd_length;
! 1053: break;
! 1054:
! 1055: case MSG_EXTENDED:
! 1056: switch (sc->sc_imess[2]) {
! 1057: #if SPC_USE_SYNCHRONOUS
! 1058: case MSG_EXT_SDTR:
! 1059: if (sc->sc_imess[1] != 3)
! 1060: goto reject;
! 1061: ti->period = sc->sc_imess[3];
! 1062: ti->offset = sc->sc_imess[4];
! 1063: ti->flags &= ~DO_SYNC;
! 1064: if (ti->offset == 0) {
! 1065: } else if (ti->period < sc->sc_minsync ||
! 1066: ti->period > sc->sc_maxsync ||
! 1067: ti->offset > 8) {
! 1068: ti->period = ti->offset = 0;
! 1069: spc_sched_msgout(sc, SEND_SDTR);
! 1070: } else {
! 1071: sc_print_addr(acb->xs->sc_link);
! 1072: printf("sync, offset %d, "
! 1073: "period %dnsec\n",
! 1074: ti->offset, ti->period * 4);
! 1075: }
! 1076: spc_setsync(sc, ti);
! 1077: break;
! 1078: #endif
! 1079:
! 1080: #if SPC_USE_WIDE
! 1081: case MSG_EXT_WDTR:
! 1082: if (sc->sc_imess[1] != 2)
! 1083: goto reject;
! 1084: ti->width = sc->sc_imess[3];
! 1085: ti->flags &= ~DO_WIDE;
! 1086: if (ti->width == 0) {
! 1087: } else if (ti->width > SPC_MAX_WIDTH) {
! 1088: ti->width = 0;
! 1089: spc_sched_msgout(sc, SEND_WDTR);
! 1090: } else {
! 1091: sc_print_addr(acb->xs->sc_link);
! 1092: printf("wide, width %d\n",
! 1093: 1 << (3 + ti->width));
! 1094: }
! 1095: break;
! 1096: #endif
! 1097:
! 1098: default:
! 1099: printf("%s: unrecognized MESSAGE EXTENDED; "
! 1100: "sending REJECT\n", sc->sc_dev.dv_xname);
! 1101: SPC_BREAK();
! 1102: goto reject;
! 1103: }
! 1104: break;
! 1105:
! 1106: default:
! 1107: printf("%s: unrecognized MESSAGE; sending REJECT\n",
! 1108: sc->sc_dev.dv_xname);
! 1109: SPC_BREAK();
! 1110: reject:
! 1111: spc_sched_msgout(sc, SEND_REJECT);
! 1112: break;
! 1113: }
! 1114: break;
! 1115:
! 1116: case SPC_RESELECTED:
! 1117: if (!MSG_ISIDENTIFY(sc->sc_imess[0])) {
! 1118: printf("%s: reselect without IDENTIFY; "
! 1119: "sending DEVICE RESET\n", sc->sc_dev.dv_xname);
! 1120: SPC_BREAK();
! 1121: goto reset;
! 1122: }
! 1123:
! 1124: (void) spc_reselect(sc, sc->sc_imess[0]);
! 1125: break;
! 1126:
! 1127: default:
! 1128: printf("%s: unexpected MESSAGE IN; sending DEVICE RESET\n",
! 1129: sc->sc_dev.dv_xname);
! 1130: SPC_BREAK();
! 1131: reset:
! 1132: spc_sched_msgout(sc, SEND_DEV_RESET);
! 1133: break;
! 1134:
! 1135: #ifdef notdef
! 1136: abort:
! 1137: spc_sched_msgout(sc, SEND_ABORT);
! 1138: break;
! 1139: #endif
! 1140: }
! 1141:
! 1142: /* Ack the last message byte. */
! 1143: #if 0 /* XXX? */
! 1144: (void) bus_space_read_1(iot, ioh, DREG);
! 1145: while ((bus_space_read_1(iot, ioh, PSNS) & ACKI) != 0)
! 1146: ;
! 1147: #endif
! 1148:
! 1149: /* Go get the next message, if any. */
! 1150: goto nextmsg;
! 1151:
! 1152: out:
! 1153: bus_space_write_1(iot, ioh, SCMD, SCMD_RST_ACK);
! 1154: SPC_MISC(("n=%d imess=0x%02x ", n, sc->sc_imess[0]));
! 1155: }
! 1156:
! 1157: /*
! 1158: * Send the highest priority, scheduled message.
! 1159: */
! 1160: void
! 1161: spc_msgout(sc)
! 1162: struct spc_softc *sc;
! 1163: {
! 1164: bus_space_tag_t iot = sc->sc_iot;
! 1165: bus_space_handle_t ioh = sc->sc_ioh;
! 1166: #if SPC_USE_SYNCHRONOUS
! 1167: struct spc_tinfo *ti;
! 1168: #endif
! 1169: int n;
! 1170:
! 1171: SPC_TRACE(("spc_msgout "));
! 1172:
! 1173: if (sc->sc_prevphase == PH_MSGOUT) {
! 1174: if (sc->sc_omp == sc->sc_omess) {
! 1175: /*
! 1176: * This is a retransmission.
! 1177: *
! 1178: * We get here if the target stayed in MESSAGE OUT
! 1179: * phase. Section 5.1.9.2 of the SCSI 2 spec indicates
! 1180: * that all of the previously transmitted messages must
! 1181: * be sent again, in the same order. Therefore, we
! 1182: * requeue all the previously transmitted messages, and
! 1183: * start again from the top. Our simple priority
! 1184: * scheme keeps the messages in the right order.
! 1185: */
! 1186: SPC_MISC(("retransmitting "));
! 1187: sc->sc_msgpriq |= sc->sc_msgoutq;
! 1188: /*
! 1189: * Set ATN. If we're just sending a trivial 1-byte
! 1190: * message, we'll clear ATN later on anyway.
! 1191: */
! 1192: bus_space_write_1(iot, ioh, SCMD,
! 1193: SCMD_SET_ATN); /* XXX? */
! 1194: } else {
! 1195: /* This is a continuation of the previous message. */
! 1196: n = sc->sc_omp - sc->sc_omess;
! 1197: goto nextbyte;
! 1198: }
! 1199: }
! 1200:
! 1201: /* No messages transmitted so far. */
! 1202: sc->sc_msgoutq = 0;
! 1203: sc->sc_lastmsg = 0;
! 1204:
! 1205: nextmsg:
! 1206: /* Pick up highest priority message. */
! 1207: sc->sc_currmsg = sc->sc_msgpriq & -sc->sc_msgpriq;
! 1208: sc->sc_msgpriq &= ~sc->sc_currmsg;
! 1209: sc->sc_msgoutq |= sc->sc_currmsg;
! 1210:
! 1211: /* Build the outgoing message data. */
! 1212: switch (sc->sc_currmsg) {
! 1213: case SEND_IDENTIFY:
! 1214: SPC_ASSERT(sc->sc_nexus != NULL);
! 1215: sc->sc_omess[0] =
! 1216: MSG_IDENTIFY(sc->sc_nexus->xs->sc_link->lun, 1);
! 1217: n = 1;
! 1218: break;
! 1219:
! 1220: #if SPC_USE_SYNCHRONOUS
! 1221: case SEND_SDTR:
! 1222: SPC_ASSERT(sc->sc_nexus != NULL);
! 1223: ti = &sc->sc_tinfo[sc->sc_nexus->xs->sc_link->target];
! 1224: sc->sc_omess[4] = MSG_EXTENDED;
! 1225: sc->sc_omess[3] = MSG_EXT_SDTR_LEN;
! 1226: sc->sc_omess[2] = MSG_EXT_SDTR;
! 1227: sc->sc_omess[1] = ti->period >> 2;
! 1228: sc->sc_omess[0] = ti->offset;
! 1229: n = 5;
! 1230: break;
! 1231: #endif
! 1232:
! 1233: #if SPC_USE_WIDE
! 1234: case SEND_WDTR:
! 1235: SPC_ASSERT(sc->sc_nexus != NULL);
! 1236: ti = &sc->sc_tinfo[sc->sc_nexus->xs->sc_link->target];
! 1237: sc->sc_omess[3] = MSG_EXTENDED;
! 1238: sc->sc_omess[2] = MSG_EXT_WDTR_LEN;
! 1239: sc->sc_omess[1] = MSG_EXT_WDTR;
! 1240: sc->sc_omess[0] = ti->width;
! 1241: n = 4;
! 1242: break;
! 1243: #endif
! 1244:
! 1245: case SEND_DEV_RESET:
! 1246: sc->sc_flags |= SPC_ABORTING;
! 1247: sc->sc_omess[0] = MSG_BUS_DEV_RESET;
! 1248: n = 1;
! 1249: break;
! 1250:
! 1251: case SEND_REJECT:
! 1252: sc->sc_omess[0] = MSG_MESSAGE_REJECT;
! 1253: n = 1;
! 1254: break;
! 1255:
! 1256: case SEND_PARITY_ERROR:
! 1257: sc->sc_omess[0] = MSG_PARITY_ERROR;
! 1258: n = 1;
! 1259: break;
! 1260:
! 1261: case SEND_INIT_DET_ERR:
! 1262: sc->sc_omess[0] = MSG_INITIATOR_DET_ERR;
! 1263: n = 1;
! 1264: break;
! 1265:
! 1266: case SEND_ABORT:
! 1267: sc->sc_flags |= SPC_ABORTING;
! 1268: sc->sc_omess[0] = MSG_ABORT;
! 1269: n = 1;
! 1270: break;
! 1271:
! 1272: default:
! 1273: printf("%s: unexpected MESSAGE OUT; sending NOOP\n",
! 1274: sc->sc_dev.dv_xname);
! 1275: SPC_BREAK();
! 1276: sc->sc_omess[0] = MSG_NOOP;
! 1277: n = 1;
! 1278: break;
! 1279: }
! 1280: sc->sc_omp = &sc->sc_omess[n];
! 1281:
! 1282: nextbyte:
! 1283: /* Send message bytes. */
! 1284: /* send TRANSFER command. */
! 1285: bus_space_write_1(iot, ioh, TCH, n >> 16);
! 1286: bus_space_write_1(iot, ioh, TCM, n >> 8);
! 1287: bus_space_write_1(iot, ioh, TCL, n);
! 1288: bus_space_write_1(iot, ioh, PCTL, sc->sc_phase | PCTL_BFINT_ENAB);
! 1289: #ifdef x68k
! 1290: bus_space_write_1(iot, ioh, SCMD, SCMD_XFR); /* XXX */
! 1291: #else
! 1292: bus_space_write_1(iot, ioh, SCMD,
! 1293: SCMD_XFR | SCMD_PROG_XFR | SCMD_ICPT_XFR);
! 1294: #endif
! 1295: for (;;) {
! 1296: if ((bus_space_read_1(iot, ioh, SSTS) & SSTS_BUSY) != 0)
! 1297: break;
! 1298: if (bus_space_read_1(iot, ioh, INTS) != 0)
! 1299: goto out;
! 1300: }
! 1301: for (;;) {
! 1302: #if 0
! 1303: for (;;) {
! 1304: if ((bus_space_read_1(iot, ioh, PSNS) & PSNS_REQ) != 0)
! 1305: break;
! 1306: /* Wait for REQINIT. XXX Need timeout. */
! 1307: }
! 1308: #endif
! 1309: if (bus_space_read_1(iot, ioh, INTS) != 0) {
! 1310: /*
! 1311: * Target left MESSAGE OUT, possibly to reject
! 1312: * our message.
! 1313: *
! 1314: * If this is the last message being sent, then we
! 1315: * deassert ATN, since either the target is going to
! 1316: * ignore this message, or it's going to ask for a
! 1317: * retransmission via MESSAGE PARITY ERROR (in which
! 1318: * case we reassert ATN anyway).
! 1319: */
! 1320: #if 0
! 1321: if (sc->sc_msgpriq == 0)
! 1322: bus_space_write_1(iot, ioh, SCMD, SCMD_RST_ATN);
! 1323: #endif
! 1324: goto out;
! 1325: }
! 1326:
! 1327: #if 0
! 1328: /* Clear ATN before last byte if this is the last message. */
! 1329: if (n == 1 && sc->sc_msgpriq == 0)
! 1330: bus_space_write_1(iot, ioh, SCMD, SCMD_RST_ATN);
! 1331: #endif
! 1332:
! 1333: while ((bus_space_read_1(iot, ioh, SSTS) & SSTS_DREG_FULL) != 0)
! 1334: ;
! 1335: /* Send message byte. */
! 1336: bus_space_write_1(iot, ioh, DREG, *--sc->sc_omp);
! 1337: --n;
! 1338: /* Keep track of the last message we've sent any bytes of. */
! 1339: sc->sc_lastmsg = sc->sc_currmsg;
! 1340: #if 0
! 1341: /* Wait for ACK to be negated. XXX Need timeout. */
! 1342: while ((bus_space_read_1(iot, ioh, PSNS) & ACKI) != 0)
! 1343: ;
! 1344: #endif
! 1345:
! 1346: if (n == 0)
! 1347: break;
! 1348: }
! 1349:
! 1350: /* We get here only if the entire message has been transmitted. */
! 1351: if (sc->sc_msgpriq != 0) {
! 1352: /* There are more outgoing messages. */
! 1353: goto nextmsg;
! 1354: }
! 1355:
! 1356: /*
! 1357: * The last message has been transmitted. We need to remember the last
! 1358: * message transmitted (in case the target switches to MESSAGE IN phase
! 1359: * and sends a MESSAGE REJECT), and the list of messages transmitted
! 1360: * this time around (in case the target stays in MESSAGE OUT phase to
! 1361: * request a retransmit).
! 1362: */
! 1363:
! 1364: out:
! 1365: /* Disable REQ/ACK protocol. */
! 1366: return;
! 1367: }
! 1368:
! 1369: /*
! 1370: * spc_dataout_pio: perform a data transfer using the FIFO datapath in the spc
! 1371: * Precondition: The SCSI bus should be in the DOUT phase, with REQ asserted
! 1372: * and ACK deasserted (i.e. waiting for a data byte).
! 1373: *
! 1374: * This new revision has been optimized (I tried) to make the common case fast,
! 1375: * and the rarer cases (as a result) somewhat more complex.
! 1376: */
! 1377: int
! 1378: spc_dataout_pio(sc, p, n)
! 1379: struct spc_softc *sc;
! 1380: u_char *p;
! 1381: int n;
! 1382: {
! 1383: bus_space_tag_t iot = sc->sc_iot;
! 1384: bus_space_handle_t ioh = sc->sc_ioh;
! 1385: u_char intstat = 0;
! 1386: int out = 0;
! 1387: #define DOUTAMOUNT 8 /* Full FIFO */
! 1388:
! 1389: SPC_TRACE(("spc_dataout_pio "));
! 1390: /* send TRANSFER command. */
! 1391: bus_space_write_1(iot, ioh, TCH, n >> 16);
! 1392: bus_space_write_1(iot, ioh, TCM, n >> 8);
! 1393: bus_space_write_1(iot, ioh, TCL, n);
! 1394: bus_space_write_1(iot, ioh, PCTL, sc->sc_phase | PCTL_BFINT_ENAB);
! 1395: #ifdef x68k
! 1396: bus_space_write_1(iot, ioh, SCMD, SCMD_XFR); /* XXX */
! 1397: #else
! 1398: bus_space_write_1(iot, ioh, SCMD,
! 1399: SCMD_XFR | SCMD_PROG_XFR | SCMD_ICPT_XFR); /* XXX */
! 1400: #endif
! 1401: for (;;) {
! 1402: if ((bus_space_read_1(iot, ioh, SSTS) & SSTS_BUSY) != 0)
! 1403: break;
! 1404: if (bus_space_read_1(iot, ioh, INTS) != 0)
! 1405: break;
! 1406: }
! 1407:
! 1408: /*
! 1409: * I have tried to make the main loop as tight as possible. This
! 1410: * means that some of the code following the loop is a bit more
! 1411: * complex than otherwise.
! 1412: */
! 1413: while (n > 0) {
! 1414: int xfer;
! 1415:
! 1416: for (;;) {
! 1417: intstat = bus_space_read_1(iot, ioh, INTS);
! 1418: /* Wait till buffer is empty. */
! 1419: if ((bus_space_read_1(iot, ioh, SSTS) &
! 1420: SSTS_DREG_EMPTY) != 0)
! 1421: break;
! 1422: /* Break on interrupt. */
! 1423: if (intstat != 0)
! 1424: goto phasechange;
! 1425: }
! 1426:
! 1427: xfer = min(DOUTAMOUNT, n);
! 1428:
! 1429: SPC_MISC(("%d> ", xfer));
! 1430:
! 1431: n -= xfer;
! 1432: out += xfer;
! 1433: bus_space_write_multi_1(iot, ioh, DREG, p, xfer);
! 1434: p += xfer;
! 1435: }
! 1436:
! 1437: if (out == 0) {
! 1438: for (;;) {
! 1439: if (bus_space_read_1(iot, ioh, INTS) != 0)
! 1440: break;
! 1441: }
! 1442: SPC_MISC(("extra data "));
! 1443: } else {
! 1444: /* See the bytes off chip */
! 1445: for (;;) {
! 1446: /* Wait till buffer is empty. */
! 1447: if ((bus_space_read_1(iot, ioh, SSTS) &
! 1448: SSTS_DREG_EMPTY) != 0)
! 1449: break;
! 1450: intstat = bus_space_read_1(iot, ioh, INTS);
! 1451: /* Break on interrupt. */
! 1452: if (intstat != 0)
! 1453: goto phasechange;
! 1454: }
! 1455: }
! 1456:
! 1457: phasechange:
! 1458: /* Stop the FIFO data path. */
! 1459:
! 1460: if (intstat != 0) {
! 1461: /* Some sort of phase change. */
! 1462: int amount;
! 1463:
! 1464: amount = ((bus_space_read_1(iot, ioh, TCH) << 16) |
! 1465: (bus_space_read_1(iot, ioh, TCM) << 8) |
! 1466: bus_space_read_1(iot, ioh, TCL));
! 1467: if (amount > 0) {
! 1468: out -= amount;
! 1469: SPC_MISC(("+%d ", amount));
! 1470: }
! 1471: }
! 1472:
! 1473: return out;
! 1474: }
! 1475:
! 1476: /*
! 1477: * spc_datain_pio: perform data transfers using the FIFO datapath in the spc
! 1478: * Precondition: The SCSI bus should be in the DIN phase, with REQ asserted
! 1479: * and ACK deasserted (i.e. at least one byte is ready).
! 1480: *
! 1481: * For now, uses a pretty dumb algorithm, hangs around until all data has been
! 1482: * transferred. This, is OK for fast targets, but not so smart for slow
! 1483: * targets which don't disconnect or for huge transfers.
! 1484: */
! 1485: int
! 1486: spc_datain_pio(sc, p, n)
! 1487: struct spc_softc *sc;
! 1488: u_char *p;
! 1489: int n;
! 1490: {
! 1491: bus_space_tag_t iot = sc->sc_iot;
! 1492: bus_space_handle_t ioh = sc->sc_ioh;
! 1493: u_int8_t intstat, sstat;
! 1494: int in = 0;
! 1495: #define DINAMOUNT 8 /* Full FIFO */
! 1496:
! 1497: SPC_TRACE(("spc_datain_pio "));
! 1498: /* send TRANSFER command. */
! 1499: bus_space_write_1(iot, ioh, TCH, n >> 16);
! 1500: bus_space_write_1(iot, ioh, TCM, n >> 8);
! 1501: bus_space_write_1(iot, ioh, TCL, n);
! 1502: bus_space_write_1(iot, ioh, PCTL, sc->sc_phase | PCTL_BFINT_ENAB);
! 1503: #ifdef x68k
! 1504: bus_space_write_1(iot, ioh, SCMD, SCMD_XFR); /* XXX */
! 1505: #else
! 1506: bus_space_write_1(iot, ioh, SCMD,
! 1507: SCMD_XFR | SCMD_PROG_XFR); /* XXX */
! 1508: #endif
! 1509: for (;;) {
! 1510: if ((bus_space_read_1(iot, ioh, SSTS) & SSTS_BUSY) != 0)
! 1511: break;
! 1512: if (bus_space_read_1(iot, ioh, INTS) != 0)
! 1513: goto phasechange;
! 1514: }
! 1515:
! 1516: /*
! 1517: * We leave this loop if one or more of the following is true:
! 1518: * a) phase != PH_DATAIN && FIFOs are empty
! 1519: * b) reset has occurred or busfree is detected.
! 1520: */
! 1521: while (n > 0) {
! 1522: int xfer;
! 1523:
! 1524: /* Wait for fifo half full or phase mismatch */
! 1525: for (;;) {
! 1526: intstat = bus_space_read_1(iot, ioh, INTS);
! 1527: sstat = bus_space_read_1(iot, ioh, SSTS);
! 1528: if (intstat != 0 ||
! 1529: (sstat & SSTS_DREG_FULL) != 0 ||
! 1530: (sstat & SSTS_DREG_EMPTY) == 0)
! 1531: break;
! 1532: }
! 1533:
! 1534: #if 1
! 1535: if (intstat != 0)
! 1536: goto phasechange;
! 1537: #else
! 1538: if (intstat != 0 &&
! 1539: (sstat & SSTS_DREG_EMPTY) != 0)
! 1540: goto phasechange;
! 1541: #endif
! 1542: if ((sstat & SSTS_DREG_FULL) != 0)
! 1543: xfer = min(DINAMOUNT, n);
! 1544: else
! 1545: xfer = 1;
! 1546:
! 1547: SPC_MISC((">%d ", xfer));
! 1548:
! 1549: n -= xfer;
! 1550: in += xfer;
! 1551: bus_space_read_multi_1(iot, ioh, DREG, p, xfer);
! 1552: p += xfer;
! 1553:
! 1554: if (intstat != 0)
! 1555: goto phasechange;
! 1556: }
! 1557:
! 1558: /*
! 1559: * Some SCSI-devices are rude enough to transfer more data than what
! 1560: * was requested, e.g. 2048 bytes from a CD-ROM instead of the
! 1561: * requested 512. Test for progress, i.e. real transfers. If no real
! 1562: * transfers have been performed (n is probably already zero) and the
! 1563: * FIFO is not empty, waste some bytes....
! 1564: */
! 1565: if (in == 0) {
! 1566: for (;;) {
! 1567: /* XXX needs timeout */
! 1568: if (bus_space_read_1(iot, ioh, INTS) != 0)
! 1569: break;
! 1570: }
! 1571: SPC_MISC(("extra data "));
! 1572: }
! 1573:
! 1574: phasechange:
! 1575: /* Stop the FIFO data path. */
! 1576:
! 1577: return in;
! 1578: }
! 1579:
! 1580: /*
! 1581: * Catch an interrupt from the adaptor
! 1582: */
! 1583: /*
! 1584: * This is the workhorse routine of the driver.
! 1585: * Deficiencies (for now):
! 1586: * 1) always uses programmed I/O
! 1587: */
! 1588: int
! 1589: spc_intr(arg)
! 1590: void *arg;
! 1591: {
! 1592: struct spc_softc *sc = arg;
! 1593: bus_space_tag_t iot = sc->sc_iot;
! 1594: bus_space_handle_t ioh = sc->sc_ioh;
! 1595: u_char ints;
! 1596: struct spc_acb *acb;
! 1597: struct scsi_link *sc_link;
! 1598: struct spc_tinfo *ti;
! 1599: int n;
! 1600:
! 1601: /*
! 1602: * Disable interrupt.
! 1603: */
! 1604: bus_space_write_1(iot, ioh, SCTL,
! 1605: bus_space_read_1(iot, ioh, SCTL) & ~SCTL_INTR_ENAB);
! 1606:
! 1607: SPC_TRACE(("spc_intr "));
! 1608:
! 1609: loop:
! 1610: /*
! 1611: * Loop until transfer completion.
! 1612: */
! 1613: /*
! 1614: * First check for abnormal conditions, such as reset.
! 1615: */
! 1616: #ifdef x68k /* XXX? */
! 1617: while ((ints = bus_space_read_1(iot, ioh, INTS)) == 0)
! 1618: delay(1);
! 1619: SPC_MISC(("ints = 0x%x ", ints));
! 1620: #else
! 1621: ints = bus_space_read_1(iot, ioh, INTS);
! 1622: SPC_MISC(("ints = 0x%x ", ints));
! 1623: #endif
! 1624:
! 1625: if ((ints & INTS_RST) != 0) {
! 1626: printf("%s: SCSI bus reset\n", sc->sc_dev.dv_xname);
! 1627: goto reset;
! 1628: }
! 1629:
! 1630: /*
! 1631: * Check for less serious errors.
! 1632: */
! 1633: if ((bus_space_read_1(iot, ioh, SERR) & (SERR_SCSI_PAR|SERR_SPC_PAR))
! 1634: != 0) {
! 1635: printf("%s: SCSI bus parity error\n", sc->sc_dev.dv_xname);
! 1636: if (sc->sc_prevphase == PH_MSGIN) {
! 1637: sc->sc_flags |= SPC_DROP_MSGIN;
! 1638: spc_sched_msgout(sc, SEND_PARITY_ERROR);
! 1639: } else
! 1640: spc_sched_msgout(sc, SEND_INIT_DET_ERR);
! 1641: }
! 1642:
! 1643: /*
! 1644: * If we're not already busy doing something test for the following
! 1645: * conditions:
! 1646: * 1) We have been reselected by something
! 1647: * 2) We have selected something successfully
! 1648: * 3) Our selection process has timed out
! 1649: * 4) This is really a bus free interrupt just to get a new command
! 1650: * going?
! 1651: * 5) Spurious interrupt?
! 1652: */
! 1653: switch (sc->sc_state) {
! 1654: case SPC_IDLE:
! 1655: case SPC_SELECTING:
! 1656: SPC_MISC(("ints:0x%02x ", ints));
! 1657:
! 1658: if ((ints & INTS_SEL) != 0) {
! 1659: /*
! 1660: * We don't currently support target mode.
! 1661: */
! 1662: printf("%s: target mode selected; going to BUS FREE\n",
! 1663: sc->sc_dev.dv_xname);
! 1664:
! 1665: goto sched;
! 1666: } else if ((ints & INTS_RESEL) != 0) {
! 1667: SPC_MISC(("reselected "));
! 1668:
! 1669: /*
! 1670: * If we're trying to select a target ourselves,
! 1671: * push our command back into the ready list.
! 1672: */
! 1673: if (sc->sc_state == SPC_SELECTING) {
! 1674: SPC_MISC(("backoff selector "));
! 1675: SPC_ASSERT(sc->sc_nexus != NULL);
! 1676: acb = sc->sc_nexus;
! 1677: sc->sc_nexus = NULL;
! 1678: TAILQ_INSERT_HEAD(&sc->ready_list, acb, chain);
! 1679: }
! 1680:
! 1681: /* Save reselection ID. */
! 1682: sc->sc_selid = bus_space_read_1(iot, ioh, TEMP);
! 1683:
! 1684: sc->sc_state = SPC_RESELECTED;
! 1685: } else if ((ints & INTS_CMD_DONE) != 0) {
! 1686: SPC_MISC(("selected "));
! 1687:
! 1688: /*
! 1689: * We have selected a target. Things to do:
! 1690: * a) Determine what message(s) to send.
! 1691: * b) Verify that we're still selecting the target.
! 1692: * c) Mark device as busy.
! 1693: */
! 1694: if (sc->sc_state != SPC_SELECTING) {
! 1695: printf("%s: selection out while idle; "
! 1696: "resetting\n", sc->sc_dev.dv_xname);
! 1697: SPC_BREAK();
! 1698: goto reset;
! 1699: }
! 1700: SPC_ASSERT(sc->sc_nexus != NULL);
! 1701: acb = sc->sc_nexus;
! 1702: sc_link = acb->xs->sc_link;
! 1703: ti = &sc->sc_tinfo[sc_link->target];
! 1704:
! 1705: sc->sc_msgpriq = SEND_IDENTIFY;
! 1706: if (acb->flags & ACB_RESET)
! 1707: sc->sc_msgpriq |= SEND_DEV_RESET;
! 1708: else if (acb->flags & ACB_ABORT)
! 1709: sc->sc_msgpriq |= SEND_ABORT;
! 1710: else {
! 1711: #if SPC_USE_SYNCHRONOUS
! 1712: if ((ti->flags & DO_SYNC) != 0)
! 1713: sc->sc_msgpriq |= SEND_SDTR;
! 1714: #endif
! 1715: #if SPC_USE_WIDE
! 1716: if ((ti->flags & DO_WIDE) != 0)
! 1717: sc->sc_msgpriq |= SEND_WDTR;
! 1718: #endif
! 1719: }
! 1720:
! 1721: acb->flags |= ACB_NEXUS;
! 1722: ti->lubusy |= (1 << sc_link->lun);
! 1723:
! 1724: /* Do an implicit RESTORE POINTERS. */
! 1725: sc->sc_dp = acb->data_addr;
! 1726: sc->sc_dleft = acb->data_length;
! 1727: sc->sc_cp = (u_char *)&acb->scsi_cmd;
! 1728: sc->sc_cleft = acb->scsi_cmd_length;
! 1729:
! 1730: /* On our first connection, schedule a timeout. */
! 1731: if ((acb->xs->flags & SCSI_POLL) == 0) {
! 1732: timeout_set(&acb->xs->stimeout, spc_timeout,
! 1733: acb);
! 1734: timeout_add(&acb->xs->stimeout,
! 1735: (acb->timeout * hz) / 1000);
! 1736: }
! 1737: sc->sc_state = SPC_CONNECTED;
! 1738: } else if ((ints & INTS_TIMEOUT) != 0) {
! 1739: SPC_MISC(("selection timeout "));
! 1740:
! 1741: if (sc->sc_state != SPC_SELECTING) {
! 1742: printf("%s: selection timeout while idle; "
! 1743: "resetting\n", sc->sc_dev.dv_xname);
! 1744: SPC_BREAK();
! 1745: goto reset;
! 1746: }
! 1747: SPC_ASSERT(sc->sc_nexus != NULL);
! 1748: acb = sc->sc_nexus;
! 1749:
! 1750: delay(250);
! 1751:
! 1752: acb->xs->error = XS_SELTIMEOUT;
! 1753: goto finish;
! 1754: } else {
! 1755: if (sc->sc_state != SPC_IDLE) {
! 1756: printf("%s: BUS FREE while not idle; "
! 1757: "state=%d\n",
! 1758: sc->sc_dev.dv_xname, sc->sc_state);
! 1759: SPC_BREAK();
! 1760: goto out;
! 1761: }
! 1762:
! 1763: goto sched;
! 1764: }
! 1765:
! 1766: /*
! 1767: * Turn off selection stuff, and prepare to catch bus free
! 1768: * interrupts, parity errors, and phase changes.
! 1769: */
! 1770:
! 1771: sc->sc_flags = 0;
! 1772: sc->sc_prevphase = PH_INVALID;
! 1773: goto dophase;
! 1774: }
! 1775:
! 1776: if ((ints & INTS_DISCON) != 0) {
! 1777: /* disable disconnect interrupt */
! 1778: bus_space_write_1(iot, ioh, PCTL,
! 1779: bus_space_read_1(iot, ioh, PCTL) & ~PCTL_BFINT_ENAB);
! 1780: /* XXX reset interrput */
! 1781: bus_space_write_1(iot, ioh, INTS, ints);
! 1782:
! 1783: switch (sc->sc_state) {
! 1784: case SPC_RESELECTED:
! 1785: goto sched;
! 1786:
! 1787: case SPC_CONNECTED:
! 1788: SPC_ASSERT(sc->sc_nexus != NULL);
! 1789: acb = sc->sc_nexus;
! 1790:
! 1791: #if SPC_USE_SYNCHRONOUS + SPC_USE_WIDE
! 1792: if (sc->sc_prevphase == PH_MSGOUT) {
! 1793: /*
! 1794: * If the target went to BUS FREE phase during
! 1795: * or immediately after sending a SDTR or WDTR
! 1796: * message, disable negotiation.
! 1797: */
! 1798: sc_link = acb->xs->sc_link;
! 1799: ti = &sc->sc_tinfo[sc_link->target];
! 1800: switch (sc->sc_lastmsg) {
! 1801: #if SPC_USE_SYNCHRONOUS
! 1802: case SEND_SDTR:
! 1803: ti->flags &= ~DO_SYNC;
! 1804: ti->period = ti->offset = 0;
! 1805: break;
! 1806: #endif
! 1807: #if SPC_USE_WIDE
! 1808: case SEND_WDTR:
! 1809: ti->flags &= ~DO_WIDE;
! 1810: ti->width = 0;
! 1811: break;
! 1812: #endif
! 1813: }
! 1814: }
! 1815: #endif
! 1816:
! 1817: if ((sc->sc_flags & SPC_ABORTING) == 0) {
! 1818: /*
! 1819: * Section 5.1.1 of the SCSI 2 spec suggests
! 1820: * issuing a REQUEST SENSE following an
! 1821: * unexpected disconnect. Some devices go into
! 1822: * a contingent allegiance condition when
! 1823: * disconnecting, and this is necessary to
! 1824: * clean up their state.
! 1825: */
! 1826: printf("%s: unexpected disconnect; "
! 1827: "sending REQUEST SENSE\n",
! 1828: sc->sc_dev.dv_xname);
! 1829: SPC_BREAK();
! 1830: spc_sense(sc, acb);
! 1831: goto out;
! 1832: }
! 1833:
! 1834: acb->xs->error = XS_DRIVER_STUFFUP;
! 1835: goto finish;
! 1836:
! 1837: case SPC_DISCONNECT:
! 1838: SPC_ASSERT(sc->sc_nexus != NULL);
! 1839: acb = sc->sc_nexus;
! 1840: TAILQ_INSERT_HEAD(&sc->nexus_list, acb, chain);
! 1841: sc->sc_nexus = NULL;
! 1842: goto sched;
! 1843:
! 1844: case SPC_CMDCOMPLETE:
! 1845: SPC_ASSERT(sc->sc_nexus != NULL);
! 1846: acb = sc->sc_nexus;
! 1847: goto finish;
! 1848: }
! 1849: }
! 1850: else if ((ints & INTS_CMD_DONE) != 0 &&
! 1851: sc->sc_prevphase == PH_MSGIN && sc->sc_state != SPC_CONNECTED)
! 1852: goto out;
! 1853:
! 1854: dophase:
! 1855: #if 0
! 1856: if ((bus_space_read_1(iot, ioh, PSNS) & PSNS_REQ) == 0) {
! 1857: /* Wait for REQINIT. */
! 1858: goto out;
! 1859: }
! 1860: #else
! 1861: bus_space_write_1(iot, ioh, INTS, ints);
! 1862: ints = 0;
! 1863: while ((bus_space_read_1(iot, ioh, PSNS) & PSNS_REQ) == 0)
! 1864: delay(1); /* need timeout XXX */
! 1865: #endif
! 1866:
! 1867: /*
! 1868: * State transition.
! 1869: */
! 1870: sc->sc_phase = bus_space_read_1(iot, ioh, PSNS) & PH_MASK;
! 1871: #if 0
! 1872: bus_space_write_1(iot, ioh, PCTL, sc->sc_phase);
! 1873: #endif
! 1874:
! 1875: SPC_MISC(("phase=%d\n", sc->sc_phase));
! 1876: switch (sc->sc_phase) {
! 1877: case PH_MSGOUT:
! 1878: if (sc->sc_state != SPC_CONNECTED &&
! 1879: sc->sc_state != SPC_RESELECTED)
! 1880: break;
! 1881: spc_msgout(sc);
! 1882: sc->sc_prevphase = PH_MSGOUT;
! 1883: goto loop;
! 1884:
! 1885: case PH_MSGIN:
! 1886: if (sc->sc_state != SPC_CONNECTED &&
! 1887: sc->sc_state != SPC_RESELECTED)
! 1888: break;
! 1889: spc_msgin(sc);
! 1890: sc->sc_prevphase = PH_MSGIN;
! 1891: goto loop;
! 1892:
! 1893: case PH_CMD:
! 1894: if (sc->sc_state != SPC_CONNECTED)
! 1895: break;
! 1896: #ifdef SPC_DEBUG
! 1897: if ((spc_debug & SPC_SHOWMISC) != 0) {
! 1898: SPC_ASSERT(sc->sc_nexus != NULL);
! 1899: acb = sc->sc_nexus;
! 1900: printf("cmd=0x%02x+%d ",
! 1901: acb->scsi_cmd.opcode, acb->scsi_cmd_length - 1);
! 1902: }
! 1903: #endif
! 1904: n = spc_dataout_pio(sc, sc->sc_cp, sc->sc_cleft);
! 1905: sc->sc_cp += n;
! 1906: sc->sc_cleft -= n;
! 1907: sc->sc_prevphase = PH_CMD;
! 1908: goto loop;
! 1909:
! 1910: case PH_DATAOUT:
! 1911: if (sc->sc_state != SPC_CONNECTED)
! 1912: break;
! 1913: SPC_MISC(("dataout dleft=%d ", sc->sc_dleft));
! 1914: n = spc_dataout_pio(sc, sc->sc_dp, sc->sc_dleft);
! 1915: sc->sc_dp += n;
! 1916: sc->sc_dleft -= n;
! 1917: sc->sc_prevphase = PH_DATAOUT;
! 1918: goto loop;
! 1919:
! 1920: case PH_DATAIN:
! 1921: if (sc->sc_state != SPC_CONNECTED)
! 1922: break;
! 1923: SPC_MISC(("datain "));
! 1924: n = spc_datain_pio(sc, sc->sc_dp, sc->sc_dleft);
! 1925: sc->sc_dp += n;
! 1926: sc->sc_dleft -= n;
! 1927: sc->sc_prevphase = PH_DATAIN;
! 1928: goto loop;
! 1929:
! 1930: case PH_STAT:
! 1931: if (sc->sc_state != SPC_CONNECTED)
! 1932: break;
! 1933: SPC_ASSERT(sc->sc_nexus != NULL);
! 1934: acb = sc->sc_nexus;
! 1935: /*acb->target_stat = bus_space_read_1(iot, ioh, DREG);*/
! 1936: spc_datain_pio(sc, &acb->target_stat, 1);
! 1937: SPC_MISC(("target_stat=0x%02x ", acb->target_stat));
! 1938: sc->sc_prevphase = PH_STAT;
! 1939: goto loop;
! 1940: }
! 1941:
! 1942: printf("%s: unexpected bus phase; resetting\n", sc->sc_dev.dv_xname);
! 1943: SPC_BREAK();
! 1944: reset:
! 1945: spc_init(sc);
! 1946: return 1;
! 1947:
! 1948: finish:
! 1949: timeout_del(&acb->xs->stimeout);
! 1950: bus_space_write_1(iot, ioh, INTS, ints);
! 1951: ints = 0;
! 1952: spc_done(sc, acb);
! 1953: goto out;
! 1954:
! 1955: sched:
! 1956: sc->sc_state = SPC_IDLE;
! 1957: spc_sched(sc);
! 1958: goto out;
! 1959:
! 1960: out:
! 1961: if (ints)
! 1962: bus_space_write_1(iot, ioh, INTS, ints);
! 1963: bus_space_write_1(iot, ioh, SCTL,
! 1964: bus_space_read_1(iot, ioh, SCTL) | SCTL_INTR_ENAB);
! 1965: return 1;
! 1966: }
! 1967:
! 1968: void
! 1969: spc_abort(sc, acb)
! 1970: struct spc_softc *sc;
! 1971: struct spc_acb *acb;
! 1972: {
! 1973:
! 1974: /* 2 secs for the abort */
! 1975: acb->timeout = SPC_ABORT_TIMEOUT;
! 1976: acb->flags |= ACB_ABORT;
! 1977:
! 1978: if (acb == sc->sc_nexus) {
! 1979: /*
! 1980: * If we're still selecting, the message will be scheduled
! 1981: * after selection is complete.
! 1982: */
! 1983: if (sc->sc_state == SPC_CONNECTED)
! 1984: spc_sched_msgout(sc, SEND_ABORT);
! 1985: } else {
! 1986: spc_dequeue(sc, acb);
! 1987: TAILQ_INSERT_HEAD(&sc->ready_list, acb, chain);
! 1988: if (sc->sc_state == SPC_IDLE)
! 1989: spc_sched(sc);
! 1990: }
! 1991: }
! 1992:
! 1993: void
! 1994: spc_timeout(arg)
! 1995: void *arg;
! 1996: {
! 1997: struct spc_acb *acb = arg;
! 1998: struct scsi_xfer *xs = acb->xs;
! 1999: struct scsi_link *sc_link = xs->sc_link;
! 2000: struct spc_softc *sc = sc_link->adapter_softc;
! 2001: int s;
! 2002:
! 2003: sc_print_addr(sc_link);
! 2004: printf("timed out");
! 2005:
! 2006: s = splbio();
! 2007:
! 2008: if (acb->flags & ACB_ABORT) {
! 2009: /* abort timed out */
! 2010: printf(" AGAIN\n");
! 2011: /* XXX Must reset! */
! 2012: } else {
! 2013: /* abort the operation that has timed out */
! 2014: printf("\n");
! 2015: acb->xs->error = XS_TIMEOUT;
! 2016: spc_abort(sc, acb);
! 2017: }
! 2018:
! 2019: splx(s);
! 2020: }
! 2021:
! 2022: #ifdef SPC_DEBUG
! 2023: /*
! 2024: * The following functions are mostly used for debugging purposes, either
! 2025: * directly called from the driver or from the kernel debugger.
! 2026: */
! 2027:
! 2028: void
! 2029: spc_show_scsi_cmd(acb)
! 2030: struct spc_acb *acb;
! 2031: {
! 2032: u_char *b = (u_char *)&acb->scsi_cmd;
! 2033: struct scsi_link *sc_link = acb->xs->sc_link;
! 2034: int i;
! 2035:
! 2036: sc_print_addr(sc_link);
! 2037: if ((acb->xs->flags & SCSI_RESET) == 0) {
! 2038: for (i = 0; i < acb->scsi_cmd_length; i++) {
! 2039: if (i)
! 2040: printf(",");
! 2041: printf("%x", b[i]);
! 2042: }
! 2043: printf("\n");
! 2044: } else
! 2045: printf("RESET\n");
! 2046: }
! 2047:
! 2048: void
! 2049: spc_print_acb(acb)
! 2050: struct spc_acb *acb;
! 2051: {
! 2052:
! 2053: printf("acb@%p xs=%p flags=%x", acb, acb->xs, acb->flags);
! 2054: printf(" dp=%p dleft=%d target_stat=%x\n",
! 2055: acb->data_addr, acb->data_length, acb->target_stat);
! 2056: spc_show_scsi_cmd(acb);
! 2057: }
! 2058:
! 2059: void
! 2060: spc_print_active_acb()
! 2061: {
! 2062: struct spc_acb *acb;
! 2063: struct spc_softc *sc = spc_cd.cd_devs[0]; /* XXX */
! 2064:
! 2065: printf("ready list:\n");
! 2066: TAILQ_FOREACH(acb, &sc->ready_list, chain)
! 2067: spc_print_acb(acb);
! 2068: printf("nexus:\n");
! 2069: if (sc->sc_nexus != NULL)
! 2070: spc_print_acb(sc->sc_nexus);
! 2071: printf("nexus list:\n");
! 2072: TAILQ_FOREACH(acb, &sc->nexus_list, chain)
! 2073: spc_print_acb(acb);
! 2074: }
! 2075:
! 2076: void
! 2077: spc_dump89352(sc)
! 2078: struct spc_softc *sc;
! 2079: {
! 2080: bus_space_tag_t iot = sc->sc_iot;
! 2081: bus_space_handle_t ioh = sc->sc_ioh;
! 2082:
! 2083: printf("mb89352: BDID=%x SCTL=%x SCMD=%x TMOD=%x\n",
! 2084: bus_space_read_1(iot, ioh, BDID),
! 2085: bus_space_read_1(iot, ioh, SCTL),
! 2086: bus_space_read_1(iot, ioh, SCMD),
! 2087: bus_space_read_1(iot, ioh, TMOD));
! 2088: printf(" INTS=%x PSNS=%x SSTS=%x SERR=%x PCTL=%x\n",
! 2089: bus_space_read_1(iot, ioh, INTS),
! 2090: bus_space_read_1(iot, ioh, PSNS),
! 2091: bus_space_read_1(iot, ioh, SSTS),
! 2092: bus_space_read_1(iot, ioh, SERR),
! 2093: bus_space_read_1(iot, ioh, PCTL));
! 2094: printf(" MBC=%x DREG=%x TEMP=%x TCH=%x TCM=%x\n",
! 2095: bus_space_read_1(iot, ioh, MBC),
! 2096: #if 0
! 2097: bus_space_read_1(iot, ioh, DREG),
! 2098: #else
! 2099: 0,
! 2100: #endif
! 2101: bus_space_read_1(iot, ioh, TEMP),
! 2102: bus_space_read_1(iot, ioh, TCH),
! 2103: bus_space_read_1(iot, ioh, TCM));
! 2104: printf(" TCL=%x EXBF=%x\n",
! 2105: bus_space_read_1(iot, ioh, TCL),
! 2106: bus_space_read_1(iot, ioh, EXBF));
! 2107: }
! 2108:
! 2109: void
! 2110: spc_dump_driver(sc)
! 2111: struct spc_softc *sc;
! 2112: {
! 2113: struct spc_tinfo *ti;
! 2114: int i;
! 2115:
! 2116: printf("nexus=%p prevphase=%x\n", sc->sc_nexus, sc->sc_prevphase);
! 2117: printf("state=%x msgin=%x msgpriq=%x msgoutq=%x lastmsg=%x "
! 2118: "currmsg=%x\n", sc->sc_state, sc->sc_imess[0],
! 2119: sc->sc_msgpriq, sc->sc_msgoutq, sc->sc_lastmsg, sc->sc_currmsg);
! 2120: for (i = 0; i < 7; i++) {
! 2121: ti = &sc->sc_tinfo[i];
! 2122: printf("tinfo%d: %d cmds %d disconnects %d timeouts",
! 2123: i, ti->cmds, ti->dconns, ti->touts);
! 2124: printf(" %d senses flags=%x\n", ti->senses, ti->flags);
! 2125: }
! 2126: }
! 2127: #endif
CVSweb