Annotation of sys/arch/mvme68k/dev/ssh.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: ssh.c,v 1.16 2007/05/29 13:56:13 pyr Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 1994 Michael L. Hitch
! 5: * Copyright (c) 1990 The Regents of the University of California.
! 6: * All rights reserved.
! 7: *
! 8: * This code is derived from software contributed to Berkeley by
! 9: * Van Jacobson of Lawrence Berkeley Laboratory.
! 10: *
! 11: * Redistribution and use in source and binary forms, with or without
! 12: * modification, are permitted provided that the following conditions
! 13: * are met:
! 14: * 1. Redistributions of source code must retain the above copyright
! 15: * notice, this list of conditions and the following disclaimer.
! 16: * 2. Redistributions in binary form must reproduce the above copyright
! 17: * notice, this list of conditions and the following disclaimer in the
! 18: * documentation and/or other materials provided with the distribution.
! 19: * 3. Neither the name of the University nor the names of its contributors
! 20: * may be used to endorse or promote products derived from this software
! 21: * without specific prior written permission.
! 22: *
! 23: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 24: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 26: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 27: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 28: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 29: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 31: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 33: * SUCH DAMAGE.
! 34: *
! 35: * @(#)ssh.c 7.5 (Berkeley) 5/4/91
! 36: */
! 37:
! 38: /*
! 39: * 53C710 scsi adaptor driver
! 40: */
! 41:
! 42: #include <sys/param.h>
! 43: #include <sys/systm.h>
! 44: #include <sys/device.h>
! 45: #include <sys/disklabel.h>
! 46: #include <sys/dkstat.h>
! 47: #include <sys/buf.h>
! 48: #include <sys/malloc.h>
! 49: #include <sys/queue.h>
! 50:
! 51: #include <scsi/scsi_all.h>
! 52: #include <scsi/scsiconf.h>
! 53:
! 54: #include <machine/autoconf.h>
! 55: #include <machine/cpu.h>
! 56:
! 57: #include <mvme68k/dev/sshreg.h>
! 58: #include <mvme68k/dev/sshvar.h>
! 59:
! 60: /*
! 61: * SCSI delays
! 62: * In u-seconds, primarily for state changes on the SPC.
! 63: */
! 64: #define SCSI_CMD_WAIT 500000 /* wait per step of 'immediate' cmds */
! 65: #define SCSI_DATA_WAIT 500000 /* wait per data in/out step */
! 66: #define SCSI_INIT_WAIT 500000 /* wait per step (both) during init */
! 67:
! 68: void ssh_select(struct ssh_softc *);
! 69: void sshabort(struct ssh_softc *, ssh_regmap_p, char *);
! 70: void ssherror(struct ssh_softc *, ssh_regmap_p, u_char);
! 71: void sshstart(struct ssh_softc *);
! 72: void sshreset(struct ssh_softc *);
! 73: void sshsetdelay(int);
! 74: void ssh_scsidone(struct ssh_acb *, int);
! 75: void ssh_sched(struct ssh_softc *);
! 76: int ssh_poll(struct ssh_softc *, struct ssh_acb *);
! 77: void sshintr(struct ssh_softc *);
! 78: void sshinitialize(struct ssh_softc *);
! 79: void ssh_start(struct ssh_softc *, int, int, u_char *, int, u_char *, int);
! 80: int ssh_checkintr(struct ssh_softc *, u_char, u_char, u_char, int *);
! 81: void scsi_period_to_ssh(struct ssh_softc *, int);
! 82:
! 83: /* 53C710 script */
! 84: const
! 85: #include <mvme68k/dev/ssh_script.out>
! 86:
! 87: /* default to not inhibit sync negotiation on any drive */
! 88: u_char ssh_inhibit_sync[8] = { 0, 0, 0, 0, 0, 0, 0}; /* initialize, so patchable */
! 89: u_char ssh_allow_disc[8] = { 3, 3, 3, 3, 3, 3, 3, 3};
! 90: int ssh_no_dma = 0;
! 91:
! 92: int ssh_reset_delay = 250; /* delay after reset, in milleseconds */
! 93:
! 94: int ssh_cmd_wait = SCSI_CMD_WAIT;
! 95: int ssh_data_wait = SCSI_DATA_WAIT;
! 96: int ssh_init_wait = SCSI_INIT_WAIT;
! 97:
! 98: #ifdef DEBUG
! 99: /*
! 100: * 0x01 - full debug
! 101: * 0x02 - DMA chaining
! 102: * 0x04 - sshintr
! 103: * 0x08 - phase mismatch
! 104: * 0x10 - <not used>
! 105: * 0x20 - panic on unhandled exceptions
! 106: * 0x100 - disconnect/reselect
! 107: */
! 108: int ssh_debug = 0;
! 109: int sshsync_debug = 0;
! 110: int sshdma_hits = 0;
! 111: int sshdma_misses = 0;
! 112: int sshchain_ints = 0;
! 113: int sshstarts = 0;
! 114: int sshints = 0;
! 115: int sshphmm = 0;
! 116: #define SSH_TRACE_SIZE 128
! 117: #define SSH_TRACE(a,b,c,d) \
! 118: ssh_trbuf[ssh_trix] = (a); \
! 119: ssh_trbuf[ssh_trix+1] = (b); \
! 120: ssh_trbuf[ssh_trix+2] = (c); \
! 121: ssh_trbuf[ssh_trix+3] = (d); \
! 122: ssh_trix = (ssh_trix + 4) & (SSH_TRACE_SIZE - 1);
! 123: u_char ssh_trbuf[SSH_TRACE_SIZE];
! 124: int ssh_trix;
! 125: #else
! 126: #define SSH_TRACE(a,b,c,d)
! 127: #endif
! 128:
! 129:
! 130: /*
! 131: * default minphys routine for ssh based controllers
! 132: */
! 133: void
! 134: ssh_minphys(bp)
! 135: struct buf *bp;
! 136: {
! 137:
! 138: /*
! 139: * No max transfer at this level.
! 140: */
! 141: minphys(bp);
! 142: }
! 143:
! 144: /*
! 145: * used by specific ssh controller
! 146: *
! 147: */
! 148: int
! 149: ssh_scsicmd(xs)
! 150: struct scsi_xfer *xs;
! 151: {
! 152: struct ssh_acb *acb;
! 153: struct ssh_softc *sc;
! 154: struct scsi_link *slp;
! 155: int flags, s;
! 156:
! 157: slp = xs->sc_link;
! 158: sc = slp->adapter_softc;
! 159: flags = xs->flags;
! 160:
! 161: /* XXXX ?? */
! 162: if (flags & SCSI_DATA_UIO)
! 163: panic("ssh: scsi data uio requested");
! 164:
! 165: /* XXXX ?? */
! 166: if (sc->sc_nexus && flags & SCSI_POLL)
! 167: panic("ssh_scsicmd: busy");
! 168:
! 169: s = splbio();
! 170: acb = TAILQ_FIRST(&sc->free_list);
! 171: if (acb) {
! 172: TAILQ_REMOVE(&sc->free_list, acb, chain);
! 173: }
! 174: splx(s);
! 175:
! 176: if (acb == NULL) {
! 177: return (TRY_AGAIN_LATER);
! 178: }
! 179:
! 180: acb->flags = ACB_ACTIVE;
! 181: acb->xs = xs;
! 182: bcopy(xs->cmd, &acb->cmd, xs->cmdlen);
! 183: acb->clen = xs->cmdlen;
! 184: acb->daddr = xs->data;
! 185: acb->dleft = xs->datalen;
! 186:
! 187: s = splbio();
! 188: TAILQ_INSERT_TAIL(&sc->ready_list, acb, chain);
! 189:
! 190: if (sc->sc_nexus == NULL)
! 191: ssh_sched(sc);
! 192:
! 193: splx(s);
! 194:
! 195: if (flags & SCSI_POLL || ssh_no_dma)
! 196: return (ssh_poll(sc, acb));
! 197: return (SUCCESSFULLY_QUEUED);
! 198: }
! 199:
! 200: int
! 201: ssh_poll(sc, acb)
! 202: struct ssh_softc *sc;
! 203: struct ssh_acb *acb;
! 204: {
! 205: ssh_regmap_p rp = sc->sc_sshp;
! 206: struct scsi_xfer *xs = acb->xs;
! 207: int i;
! 208: int status;
! 209: u_char istat;
! 210: u_char dstat;
! 211: u_char sstat0;
! 212: int s;
! 213: int to;
! 214:
! 215: s = splbio();
! 216: to = xs->timeout / 1000;
! 217: if (!TAILQ_EMPTY(&sc->nexus_list))
! 218: printf("%s: ssh_poll called with disconnected device\n",
! 219: sc->sc_dev.dv_xname);
! 220: for (;;) {
! 221: /* use cmd_wait values? */
! 222: i = 50000;
! 223: while (((istat = rp->ssh_istat) &
! 224: (SSH_ISTAT_SIP | SSH_ISTAT_DIP)) == 0) {
! 225: if (--i <= 0) {
! 226: #ifdef DEBUG
! 227: printf ("waiting: tgt %d cmd %02x sbcl %02x dsp %x (+%x) dcmd %x ds %x timeout %d\n",
! 228: xs->sc_link->target, acb->cmd.opcode,
! 229: rp->ssh_sbcl, rp->ssh_dsp,
! 230: rp->ssh_dsp - sc->sc_scriptspa,
! 231: *((long *)&rp->ssh_dcmd), &acb->ds, acb->xs->timeout);
! 232: #endif
! 233: i = 50000;
! 234: --to;
! 235: if (to <= 0) {
! 236: sshreset(sc);
! 237: return (COMPLETE);
! 238: }
! 239: }
! 240: delay(10);
! 241: }
! 242: sstat0 = rp->ssh_sstat0;
! 243: dstat = rp->ssh_dstat;
! 244: if (ssh_checkintr(sc, istat, dstat, sstat0, &status)) {
! 245: if (acb != sc->sc_nexus)
! 246: printf("%s: ssh_poll disconnected device completed\n",
! 247: sc->sc_dev.dv_xname);
! 248: else if ((sc->sc_flags & SSH_INTDEFER) == 0) {
! 249: sc->sc_flags &= ~SSH_INTSOFF;
! 250: rp->ssh_sien = sc->sc_sien;
! 251: rp->ssh_dien = sc->sc_dien;
! 252: }
! 253: ssh_scsidone(sc->sc_nexus, status);
! 254: }
! 255: if (xs->flags & ITSDONE)
! 256: break;
! 257: }
! 258: splx(s);
! 259: return (COMPLETE);
! 260: }
! 261:
! 262: /*
! 263: * start next command that's ready
! 264: */
! 265: void
! 266: ssh_sched(sc)
! 267: struct ssh_softc *sc;
! 268: {
! 269: struct scsi_link *slp;
! 270: struct ssh_acb *acb;
! 271: int i;
! 272:
! 273: #ifdef DEBUG
! 274: if (sc->sc_nexus) {
! 275: printf("%s: ssh_sched- nexus %x/%d ready %x/%d\n",
! 276: sc->sc_dev.dv_xname, sc->sc_nexus,
! 277: sc->sc_nexus->xs->sc_link->target,
! 278: TAILQ_FIRST(&sc->ready_list),
! 279: TAILQ_FIRST(&sc->ready_list)->xs->sc_link->target);
! 280: return;
! 281: }
! 282: #endif
! 283: TAILQ_FOREACH(acb, &sc->ready_list, chain) {
! 284: slp = acb->xs->sc_link;
! 285: i = slp->target;
! 286: if (!(sc->sc_tinfo[i].lubusy & (1 << slp->lun))) {
! 287: struct ssh_tinfo *ti = &sc->sc_tinfo[i];
! 288:
! 289: TAILQ_REMOVE(&sc->ready_list, acb, chain);
! 290: sc->sc_nexus = acb;
! 291: slp = acb->xs->sc_link;
! 292: ti = &sc->sc_tinfo[slp->target];
! 293: ti->lubusy |= (1 << slp->lun);
! 294: break;
! 295: }
! 296: }
! 297:
! 298: if (acb == NULL) {
! 299: #ifdef DEBUGXXX
! 300: printf("%s: ssh_sched didn't find ready command\n",
! 301: sc->sc_dev.dv_xname);
! 302: #endif
! 303: return;
! 304: }
! 305:
! 306: if (acb->xs->flags & SCSI_RESET)
! 307: sshreset(sc);
! 308:
! 309: #if 0
! 310: acb->cmd.bytes[0] |= slp->lun << 5; /* XXXX */
! 311: #endif
! 312: ++sc->sc_active;
! 313: ssh_select(sc);
! 314: }
! 315:
! 316: void
! 317: ssh_scsidone(acb, stat)
! 318: struct ssh_acb *acb;
! 319: int stat;
! 320: {
! 321: struct scsi_xfer *xs;
! 322: struct scsi_link *slp;
! 323: struct ssh_softc *sc;
! 324: int dosched = 0;
! 325:
! 326: if (acb == NULL || (xs = acb->xs) == NULL) {
! 327: #ifdef DIAGNOSTIC
! 328: printf("ssh_scsidone: NULL acb or scsi_xfer\n");
! 329: #if defined(DEBUG) && defined(DDB)
! 330: Debugger();
! 331: #endif
! 332: #endif
! 333: return;
! 334: }
! 335: slp = xs->sc_link;
! 336: sc = slp->adapter_softc;
! 337:
! 338: /*
! 339: * is this right?
! 340: */
! 341: xs->status = stat;
! 342:
! 343: if (xs->error == XS_NOERROR && !(acb->flags & ACB_CHKSENSE)) {
! 344: if (stat == SCSI_CHECK) {
! 345: struct scsi_sense *ss = (void *)&acb->cmd;
! 346: bzero(ss, sizeof(*ss));
! 347: ss->opcode = REQUEST_SENSE;
! 348: ss->byte2 = slp->lun << 5;
! 349: ss->length = sizeof(struct scsi_sense_data);
! 350: acb->clen = sizeof(*ss);
! 351: acb->daddr = (char *)&xs->sense;
! 352: acb->dleft = sizeof(struct scsi_sense_data);
! 353: acb->flags = ACB_ACTIVE | ACB_CHKSENSE;
! 354: TAILQ_INSERT_HEAD(&sc->ready_list, acb, chain);
! 355: --sc->sc_active;
! 356: sc->sc_tinfo[slp->target].lubusy &=
! 357: ~(1 << slp->lun);
! 358: sc->sc_tinfo[slp->target].senses++;
! 359: if (sc->sc_nexus == acb) {
! 360: sc->sc_nexus = NULL;
! 361: ssh_sched(sc);
! 362: }
! 363: SSH_TRACE('d','s',0,0)
! 364: return;
! 365: }
! 366: }
! 367: if (xs->error == XS_NOERROR && (acb->flags & ACB_CHKSENSE)) {
! 368: xs->error = XS_SENSE;
! 369: } else {
! 370: xs->resid = 0; /* XXXX */
! 371: }
! 372:
! 373: #if whataboutthisone
! 374: case SCSI_BUSY:
! 375: xs->error = XS_BUSY;
! 376: break;
! 377: #endif
! 378:
! 379: xs->flags |= ITSDONE;
! 380:
! 381: /*
! 382: * Remove the ACB from whatever queue it's on. We have to do a bit of
! 383: * a hack to figure out which queue it's on. Note that it is *not*
! 384: * necessary to cdr down the ready queue, but we must cdr down the
! 385: * nexus queue and see if it's there, so we can mark the unit as no
! 386: * longer busy. This code is sickening, but it works.
! 387: */
! 388: if (acb == sc->sc_nexus) {
! 389: sc->sc_nexus = NULL;
! 390: sc->sc_tinfo[slp->target].lubusy &= ~(1<<slp->lun);
! 391: if (!TAILQ_EMPTY(&sc->ready_list))
! 392: dosched = 1; /* start next command */
! 393: --sc->sc_active;
! 394: SSH_TRACE('d','a',stat,0)
! 395: } else if (TAILQ_LAST(&sc->ready_list, acb_list) ==
! 396: TAILQ_NEXT(acb, chain)) {
! 397: TAILQ_REMOVE(&sc->ready_list, acb, chain);
! 398: SSH_TRACE('d','r',stat,0)
! 399: } else {
! 400: register struct ssh_acb *acb2;
! 401: TAILQ_FOREACH(acb2, &sc->nexus_list, chain)
! 402: if (acb2 == acb) {
! 403: TAILQ_REMOVE(&sc->nexus_list, acb, chain);
! 404: sc->sc_tinfo[slp->target].lubusy
! 405: &= ~(1<<slp->lun);
! 406: --sc->sc_active;
! 407: break;
! 408: }
! 409: if (acb2)
! 410: ;
! 411: else if (TAILQ_NEXT(acb, chain) != NULL) {
! 412: TAILQ_REMOVE(&sc->ready_list, acb, chain);
! 413: --sc->sc_active;
! 414: } else {
! 415: printf("%s: can't find matching acb\n",
! 416: sc->sc_dev.dv_xname);
! 417: #ifdef DDB
! 418: /* Debugger(); */
! 419: #endif
! 420: }
! 421: SSH_TRACE('d','n',stat,0);
! 422: }
! 423: /* Put it on the free list. */
! 424: acb->flags = ACB_FREE;
! 425: TAILQ_INSERT_HEAD(&sc->free_list, acb, chain);
! 426:
! 427: sc->sc_tinfo[slp->target].cmds++;
! 428:
! 429: scsi_done(xs);
! 430:
! 431: if (dosched && sc->sc_nexus == NULL)
! 432: ssh_sched(sc);
! 433: }
! 434:
! 435: void
! 436: sshabort(sc, rp, where)
! 437: register struct ssh_softc *sc;
! 438: ssh_regmap_p rp;
! 439: char *where;
! 440: {
! 441: #ifdef fix_this
! 442: int i;
! 443: #endif
! 444:
! 445: printf ("%s: abort %s: dstat %02x, sstat0 %02x sbcl %02x\n",
! 446: sc->sc_dev.dv_xname,
! 447: where, rp->ssh_dstat, rp->ssh_sstat0, rp->ssh_sbcl);
! 448:
! 449: if (sc->sc_active > 0) {
! 450: #ifdef TODO
! 451: SET_SBIC_cmd (rp, SBIC_CMD_ABORT);
! 452: WAIT_CIP (rp);
! 453:
! 454: GET_SBIC_asr (rp, asr);
! 455: if (asr & (SBIC_ASR_BSY|SBIC_ASR_LCI)) {
! 456: /* ok, get more drastic.. */
! 457:
! 458: SET_SBIC_cmd (rp, SBIC_CMD_RESET);
! 459: delay(25);
! 460: SBIC_WAIT(rp, SBIC_ASR_INT, 0);
! 461: GET_SBIC_csr (rp, csr); /* clears interrupt also */
! 462:
! 463: return;
! 464: }
! 465:
! 466: do {
! 467: SBIC_WAIT (rp, SBIC_ASR_INT, 0);
! 468: GET_SBIC_csr (rp, csr);
! 469: }
! 470: while ((csr != SBIC_CSR_DISC) && (csr != SBIC_CSR_DISC_1)
! 471: && (csr != SBIC_CSR_CMD_INVALID));
! 472: #endif
! 473:
! 474: /* lets just hope it worked.. */
! 475: #ifdef fix_this
! 476: for (i = 0; i < 2; ++i) {
! 477: if (sc->sc_iob[i].sc_xs && &sc->sc_iob[i] !=
! 478: sc->sc_cur) {
! 479: printf ("sshabort: cleanup!\n");
! 480: sc->sc_iob[i].sc_xs = NULL;
! 481: }
! 482: }
! 483: #endif /* fix_this */
! 484: /* sc->sc_active = 0; */
! 485: }
! 486: }
! 487:
! 488: void
! 489: sshinitialize(sc)
! 490: struct ssh_softc *sc;
! 491: {
! 492: /*
! 493: * Need to check that scripts is on a long word boundary
! 494: * Also should verify that dev doesn't span non-contiguous
! 495: * physical pages.
! 496: */
! 497: sc->sc_scriptspa = kvtop((vaddr_t)scripts);
! 498:
! 499: /*
! 500: * malloc sc_acb to ensure that DS is on a long word boundary.
! 501: */
! 502:
! 503: MALLOC(sc->sc_acb, struct ssh_acb *,
! 504: sizeof(struct ssh_acb) * SSH_NACB, M_DEVBUF, M_NOWAIT);
! 505: if (sc->sc_acb == NULL)
! 506: panic("sshinitialize: ACB malloc failed!");
! 507:
! 508: sc->sc_tcp[1] = 1000 / sc->sc_clock_freq;
! 509: sc->sc_tcp[2] = 1500 / sc->sc_clock_freq;
! 510: sc->sc_tcp[3] = 2000 / sc->sc_clock_freq;
! 511: sc->sc_minsync = sc->sc_tcp[1]; /* in 4ns units */
! 512: if (sc->sc_minsync < 25)
! 513: sc->sc_minsync = 25;
! 514: #if not_used
! 515: if (sc->sc_clock_freq <= 25)
! 516: sc->sc_tcp[0] = sc->sc_tcp[1];
! 517: else if (sc->sc_clock_freq <= 37)
! 518: sc->sc_tcp[0] = sc->sc_tcp[2];
! 519: else if (sc->sc_clock_freq <= 50)
! 520: sc->sc_tcp[0] = sc->sc_tcp[3];
! 521: else
! 522: sc->sc_tcp[0] = 3000 / sc->sc_clock_freq;
! 523: #endif
! 524:
! 525: sshreset (sc);
! 526: }
! 527:
! 528: void
! 529: sshreset(sc)
! 530: struct ssh_softc *sc;
! 531: {
! 532: ssh_regmap_p rp;
! 533: u_int i, s;
! 534: u_char dummy;
! 535: struct ssh_acb *acb;
! 536:
! 537: rp = sc->sc_sshp;
! 538:
! 539: if (sc->sc_flags & SSH_ALIVE)
! 540: sshabort(sc, rp, "reset");
! 541:
! 542: s = splbio();
! 543:
! 544: /*
! 545: * Reset the chip
! 546: * XXX - is this really needed?
! 547: */
! 548: rp->ssh_istat |= SSH_ISTAT_ABRT; /* abort current script */
! 549: rp->ssh_istat |= SSH_ISTAT_RST; /* reset chip */
! 550: rp->ssh_istat &= ~SSH_ISTAT_RST;
! 551: /*
! 552: * Reset SCSI bus (do we really want this?)
! 553: */
! 554: rp->ssh_sien = 0;
! 555: rp->ssh_scntl1 |= SSH_SCNTL1_RST;
! 556: delay(1);
! 557: rp->ssh_scntl1 &= ~SSH_SCNTL1_RST;
! 558:
! 559: /*
! 560: * Set up various chip parameters
! 561: */
! 562: rp->ssh_scntl0 = SSH_ARB_FULL | SSH_SCNTL0_EPC | SSH_SCNTL0_EPG;
! 563: rp->ssh_scntl1 = SSH_SCNTL1_ESR;
! 564: rp->ssh_dcntl = sc->sc_dcntl;
! 565: rp->ssh_dmode = 0x80; /* burst length = 4 */
! 566: rp->ssh_sien = 0x00; /* don't enable interrupts yet */
! 567: rp->ssh_dien = 0x00; /* don't enable interrupts yet */
! 568: rp->ssh_scid = 1 << sc->sc_link.adapter_target;
! 569: rp->ssh_dwt = 0x00;
! 570: rp->ssh_ctest0 |= SSH_CTEST0_BTD | SSH_CTEST0_EAN;
! 571: rp->ssh_ctest7 = sc->sc_ctest7;
! 572:
! 573: /* will need to re-negotiate sync xfers */
! 574: bzero(&sc->sc_sync, sizeof (sc->sc_sync));
! 575:
! 576: i = rp->ssh_istat;
! 577: if (i & SSH_ISTAT_SIP)
! 578: dummy = rp->ssh_sstat0;
! 579: if (i & SSH_ISTAT_DIP)
! 580: dummy = rp->ssh_dstat;
! 581:
! 582: splx(s);
! 583:
! 584: delay(ssh_reset_delay * 1000);
! 585: printf(": version %d target %d\n", rp->ssh_ctest8 >> 4,
! 586: sc->sc_link.adapter_target);
! 587:
! 588: if ((sc->sc_flags & SSH_ALIVE) == 0) {
! 589: TAILQ_INIT(&sc->ready_list);
! 590: TAILQ_INIT(&sc->nexus_list);
! 591: TAILQ_INIT(&sc->free_list);
! 592: sc->sc_nexus = NULL;
! 593: acb = sc->sc_acb;
! 594: bzero(acb, sizeof(struct ssh_acb) * SSH_NACB);
! 595: for (i = 0; i < SSH_NACB; i++) {
! 596: TAILQ_INSERT_TAIL(&sc->free_list, acb, chain);
! 597: acb++;
! 598: }
! 599: bzero(sc->sc_tinfo, sizeof(sc->sc_tinfo));
! 600: } else {
! 601: if (sc->sc_nexus != NULL) {
! 602: sc->sc_nexus->xs->error = XS_DRIVER_STUFFUP;
! 603: ssh_scsidone(sc->sc_nexus, sc->sc_nexus->stat[0]);
! 604: }
! 605: while ((acb = TAILQ_FIRST(&sc->nexus_list))) {
! 606: acb->xs->error = XS_DRIVER_STUFFUP;
! 607: ssh_scsidone(acb, acb->stat[0]);
! 608: }
! 609: }
! 610:
! 611: sc->sc_flags |= SSH_ALIVE;
! 612: sc->sc_flags &= ~(SSH_INTDEFER|SSH_INTSOFF);
! 613: /* enable SCSI and DMA interrupts */
! 614: sc->sc_sien = SSH_SIEN_M_A | SSH_SIEN_STO | /*SSH_SIEN_SEL |*/ SSH_SIEN_SGE |
! 615: SSH_SIEN_UDC | SSH_SIEN_RST | SSH_SIEN_PAR;
! 616: sc->sc_dien = SSH_DIEN_BF | SSH_DIEN_ABRT | SSH_DIEN_SIR |
! 617: /*SSH_DIEN_WTD |*/ SSH_DIEN_IID;
! 618: rp->ssh_sien = sc->sc_sien;
! 619: rp->ssh_dien = sc->sc_dien;
! 620: }
! 621:
! 622: /*
! 623: * Setup Data Storage for 53C710 and start SCRIPTS processing
! 624: */
! 625:
! 626: void
! 627: ssh_start (sc, target, lun, cbuf, clen, buf, len)
! 628: struct ssh_softc *sc;
! 629: int target;
! 630: int lun;
! 631: u_char *cbuf;
! 632: int clen;
! 633: u_char *buf;
! 634: int len;
! 635: {
! 636: ssh_regmap_p rp = sc->sc_sshp;
! 637: #ifdef DEBUG
! 638: int i;
! 639: #endif
! 640: int nchain;
! 641: int count, tcount;
! 642: char *addr, *dmaend;
! 643: struct ssh_acb *acb = sc->sc_nexus;
! 644:
! 645: #ifdef DEBUG
! 646: if (ssh_debug & 0x100 && rp->ssh_sbcl & SSH_BSY) {
! 647: printf ("ACK! ssh was busy: rp %x script %x dsa %x active %d\n",
! 648: rp, &scripts, &acb->ds, sc->sc_active);
! 649: printf ("istat %02x sfbr %02x lcrc %02x sien %02x dien %02x\n",
! 650: rp->ssh_istat, rp->ssh_sfbr, rp->ssh_lcrc,
! 651: rp->ssh_sien, rp->ssh_dien);
! 652: #ifdef DDB
! 653: /*Debugger();*/
! 654: #endif
! 655: }
! 656: #endif
! 657: acb->msgout[0] = MSG_IDENTIFY | lun;
! 658: if (ssh_allow_disc[target] & 2 ||
! 659: (ssh_allow_disc[target] && len == 0))
! 660: acb->msgout[0] = MSG_IDENTIFY_DR | lun;
! 661: acb->status = 0;
! 662: acb->stat[0] = -1;
! 663: acb->msg[0] = -1;
! 664: acb->ds.scsi_addr = (0x10000 << target) | (sc->sc_sync[target].sxfer << 8);
! 665: acb->ds.idlen = 1;
! 666: acb->ds.idbuf = (char *) kvtop((vaddr_t)&acb->msgout[0]);
! 667: acb->ds.cmdlen = clen;
! 668: acb->ds.cmdbuf = (char *) kvtop((vaddr_t)cbuf);
! 669: acb->ds.stslen = 1;
! 670: acb->ds.stsbuf = (char *) kvtop((vaddr_t)&acb->stat[0]);
! 671: acb->ds.msglen = 1;
! 672: acb->ds.msgbuf = (char *) kvtop((vaddr_t)&acb->msg[0]);
! 673: acb->msg[1] = -1;
! 674: acb->ds.msginlen = 1;
! 675: acb->ds.extmsglen = 1;
! 676: acb->ds.synmsglen = 3;
! 677: acb->ds.msginbuf = (char *) kvtop((vaddr_t)&acb->msg[1]);
! 678: acb->ds.extmsgbuf = (char *) kvtop((vaddr_t)&acb->msg[2]);
! 679: acb->ds.synmsgbuf = (char *) kvtop((vaddr_t)&acb->msg[3]);
! 680: bzero(&acb->ds.chain, sizeof (acb->ds.chain));
! 681:
! 682: if (sc->sc_sync[target].state == SYNC_START) {
! 683: if (ssh_inhibit_sync[target]) {
! 684: sc->sc_sync[target].state = SYNC_DONE;
! 685: sc->sc_sync[target].sbcl = 0;
! 686: sc->sc_sync[target].sxfer = 0;
! 687: #ifdef DEBUG
! 688: if (sshsync_debug)
! 689: printf ("Forcing target %d asynchronous\n", target);
! 690: #endif
! 691: } else {
! 692: acb->msg[2] = -1;
! 693: acb->msgout[1] = MSG_EXT_MESSAGE;
! 694: acb->msgout[2] = 3;
! 695: acb->msgout[3] = MSG_SYNC_REQ;
! 696: #ifdef MAXTOR_SYNC_KLUDGE
! 697: acb->msgout[4] = 50 / 4; /* ask for ridiculous period */
! 698: #else
! 699: acb->msgout[4] = sc->sc_minsync;
! 700: #endif
! 701: acb->msgout[5] = SSH_MAX_OFFSET;
! 702: acb->ds.idlen = 6;
! 703: sc->sc_sync[target].state = SYNC_SENT;
! 704: #ifdef DEBUG
! 705: if (sshsync_debug)
! 706: printf ("Sending sync request to target %d\n", target);
! 707: #endif
! 708: }
! 709: }
! 710:
! 711: /*
! 712: * Build physical DMA addresses for scatter/gather I/O
! 713: */
! 714: acb->iob_buf = buf;
! 715: acb->iob_len = len;
! 716: acb->iob_curbuf = acb->iob_curlen = 0;
! 717: nchain = 0;
! 718: count = len;
! 719: addr = buf;
! 720: dmaend = NULL;
! 721: while (count > 0) {
! 722: acb->ds.chain[nchain].databuf = (char *) kvtop ((vaddr_t)addr);
! 723: if (count < (tcount = NBPG - ((int) addr & PGOFSET)))
! 724: tcount = count;
! 725: acb->ds.chain[nchain].datalen = tcount;
! 726: addr += tcount;
! 727: count -= tcount;
! 728: if (acb->ds.chain[nchain].databuf == dmaend) {
! 729: dmaend += acb->ds.chain[nchain].datalen;
! 730: acb->ds.chain[nchain].datalen = 0;
! 731: acb->ds.chain[--nchain].datalen += tcount;
! 732: #ifdef DEBUG
! 733: ++sshdma_hits;
! 734: #endif
! 735: } else {
! 736: dmaend = acb->ds.chain[nchain].databuf +
! 737: acb->ds.chain[nchain].datalen;
! 738: acb->ds.chain[nchain].datalen = tcount;
! 739: #ifdef DEBUG
! 740: if (nchain) /* Don't count miss on first one */
! 741: ++sshdma_misses;
! 742: #endif
! 743: }
! 744: ++nchain;
! 745: }
! 746: #ifdef DEBUG
! 747: if (nchain != 1 && len != 0 && ssh_debug & 3) {
! 748: printf ("DMA chaining set: %d\n", nchain);
! 749: for (i = 0; i < nchain; ++i) {
! 750: printf (" [%d] %8x %4x\n", i, acb->ds.chain[i].databuf,
! 751: acb->ds.chain[i].datalen);
! 752: }
! 753: }
! 754: #endif
! 755:
! 756: /* push data cache for all data the 53c710 needs to access */
! 757: dma_cachectl((caddr_t)acb, sizeof (struct ssh_acb));
! 758: dma_cachectl(cbuf, clen);
! 759: if (buf != NULL && len != 0)
! 760: dma_cachectl(buf, len);
! 761:
! 762: #ifdef DEBUG
! 763: if (ssh_debug & 0x100 && rp->ssh_sbcl & SSH_BSY) {
! 764: printf ("ACK! ssh was busy at start: rp %x script %x dsa %x active %d\n",
! 765: rp, &scripts, &acb->ds, sc->sc_active);
! 766: #ifdef DDB
! 767: /*Debugger();*/
! 768: #endif
! 769: }
! 770: #endif
! 771:
! 772: if (TAILQ_EMPTY(&sc->nexus_list)) {
! 773: if (rp->ssh_istat & SSH_ISTAT_CON)
! 774: printf("%s: ssh_select while connected?\n",
! 775: sc->sc_dev.dv_xname);
! 776: rp->ssh_temp = 0;
! 777: rp->ssh_sbcl = sc->sc_sync[target].sbcl;
! 778: rp->ssh_dsa = kvtop((vaddr_t)&acb->ds);
! 779: rp->ssh_dsp = sc->sc_scriptspa;
! 780: SSH_TRACE('s',1,0,0)
! 781: } else {
! 782: if ((rp->ssh_istat & SSH_ISTAT_CON) == 0) {
! 783: rp->ssh_istat = SSH_ISTAT_SIGP;
! 784: SSH_TRACE('s',2,0,0);
! 785: } else {
! 786: SSH_TRACE('s',3,rp->ssh_istat,0);
! 787: }
! 788: }
! 789: #ifdef DEBUG
! 790: ++sshstarts;
! 791: #endif
! 792: }
! 793:
! 794: /*
! 795: * Process a DMA or SCSI interrupt from the 53C710 SSH
! 796: */
! 797:
! 798: int
! 799: ssh_checkintr(sc, istat, dstat, sstat0, status)
! 800: struct ssh_softc *sc;
! 801: u_char istat;
! 802: u_char dstat;
! 803: u_char sstat0;
! 804: int *status;
! 805: {
! 806: ssh_regmap_p rp = sc->sc_sshp;
! 807: struct ssh_acb *acb = sc->sc_nexus;
! 808: int target;
! 809: int dfifo, dbc, sstat1;
! 810:
! 811: dfifo = rp->ssh_dfifo;
! 812: dbc = rp->ssh_dbc0;
! 813: sstat1 = rp->ssh_sstat1;
! 814: rp->ssh_ctest8 |= SSH_CTEST8_CLF;
! 815: while ((rp->ssh_ctest1 & SSH_CTEST1_FMT) != SSH_CTEST1_FMT)
! 816: ;
! 817: rp->ssh_ctest8 &= ~SSH_CTEST8_CLF;
! 818: #ifdef DEBUG
! 819: ++sshints;
! 820: #if 0
! 821: if (ssh_debug & 0x100) {
! 822: dma_cachectl(&acb->stat[0], 1);
! 823: printf ("sshchkintr: istat %x dstat %x sstat0 %x dsps %x sbcl %x sts %x msg %x\n",
! 824: istat, dstat, sstat0, rp->ssh_dsps, rp->ssh_sbcl, acb->stat[0], acb->msg[0]);
! 825: printf ("sync msg in: %02x %02x %02x %02x %02x %02x\n",
! 826: acb->msg[0], acb->msg[1], acb->msg[2],
! 827: acb->msg[3], acb->msg[4], acb->msg[5]);
! 828: }
! 829: #endif
! 830: if (rp->ssh_dsp && (rp->ssh_dsp < sc->sc_scriptspa ||
! 831: rp->ssh_dsp >= sc->sc_scriptspa + sizeof(scripts))) {
! 832: printf ("%s: dsp not within script dsp %x scripts %x:%x",
! 833: sc->sc_dev.dv_xname, rp->ssh_dsp, sc->sc_scriptspa,
! 834: sc->sc_scriptspa + sizeof(scripts));
! 835: printf(" istat %x dstat %x sstat0 %x\n",
! 836: istat, dstat, sstat0);
! 837: Debugger();
! 838: }
! 839: #endif
! 840: SSH_TRACE('i',dstat,istat,(istat&SSH_ISTAT_DIP)?rp->ssh_dsps&0xff:sstat0);
! 841: if (dstat & SSH_DSTAT_SIR && rp->ssh_dsps == 0xff00) {
! 842: /* Normal completion status, or check condition */
! 843: #ifdef DEBUG
! 844: if (rp->ssh_dsa != kvtop(&acb->ds)) {
! 845: printf ("ssh: invalid dsa: %x %x\n", rp->ssh_dsa,
! 846: kvtop(&acb->ds));
! 847: panic("*** ssh DSA invalid ***");
! 848: }
! 849: #endif
! 850: target = acb->xs->sc_link->target;
! 851: if (sc->sc_sync[target].state == SYNC_SENT) {
! 852: #ifdef DEBUG
! 853: if (sshsync_debug)
! 854: printf ("sync msg in: %02x %02x %02x %02x %02x %02x\n",
! 855: acb->msg[0], acb->msg[1], acb->msg[2],
! 856: acb->msg[3], acb->msg[4], acb->msg[5]);
! 857: #endif
! 858: if (acb->msg[1] == 0xff)
! 859: printf ("%s: target %d ignored sync request\n",
! 860: sc->sc_dev.dv_xname, target);
! 861: else if (acb->msg[1] == MSG_REJECT)
! 862: printf ("%s: target %d rejected sync request\n",
! 863: sc->sc_dev.dv_xname, target);
! 864: sc->sc_sync[target].state = SYNC_DONE;
! 865: sc->sc_sync[target].sxfer = 0;
! 866: sc->sc_sync[target].sbcl = 0;
! 867: if (acb->msg[2] == 3 &&
! 868: acb->msg[3] == MSG_SYNC_REQ &&
! 869: acb->msg[5] != 0) {
! 870: #ifdef MAXTOR_KLUDGE
! 871: /*
! 872: * Kludge for my Maxtor XT8580S
! 873: * It accepts whatever we request, even
! 874: * though it won't work. So we ask for
! 875: * a short period than we can handle. If
! 876: * the device says it can do it, use 208ns.
! 877: * If the device says it can do less than
! 878: * 100ns, then we limit it to 100ns.
! 879: */
! 880: if (acb->msg[4] && acb->msg[4] < 100 / 4) {
! 881: #ifdef DEBUG
! 882: printf ("%d: target %d wanted %dns period\n",
! 883: sc->sc_dev.dv_xname, target,
! 884: acb->msg[4] * 4);
! 885: #endif
! 886: if (acb->msg[4] == 50 / 4)
! 887: acb->msg[4] = 208 / 4;
! 888: else
! 889: acb->msg[4] = 100 / 4;
! 890: }
! 891: #endif /* MAXTOR_KLUDGE */
! 892: printf ("%s: target %d now synchronous, period=%dns, offset=%d\n",
! 893: sc->sc_dev.dv_xname, target,
! 894: acb->msg[4] * 4, acb->msg[5]);
! 895: scsi_period_to_ssh (sc, target);
! 896: }
! 897: }
! 898: dma_cachectl(&acb->stat[0], 1);
! 899: *status = acb->stat[0];
! 900: #ifdef DEBUG
! 901: if (rp->ssh_sbcl & SSH_BSY) {
! 902: /*printf ("ACK! ssh was busy at end: rp %x script %x dsa %x\n",
! 903: rp, &scripts, &acb->ds);*/
! 904: #ifdef DDB
! 905: /*Debugger();*/
! 906: #endif
! 907: }
! 908: if (acb->msg[0] != 0x00)
! 909: printf("%s: message was not COMMAND COMPLETE: %x\n",
! 910: sc->sc_dev.dv_xname, acb->msg[0]);
! 911: #endif
! 912: if (!TAILQ_EMPTY(&sc->nexus_list))
! 913: rp->ssh_dcntl |= SSH_DCNTL_STD;
! 914: return 1;
! 915: }
! 916: if (sstat0 & SSH_SSTAT0_M_A) { /* Phase mismatch */
! 917: #ifdef DEBUG
! 918: ++sshphmm;
! 919: if (acb == NULL)
! 920: printf("%s: Phase mismatch with no active command?\n",
! 921: sc->sc_dev.dv_xname);
! 922: #endif
! 923: if (acb->iob_len) {
! 924: int adjust;
! 925: adjust = ((dfifo - (dbc & 0x7f)) & 0x7f);
! 926: if (sstat1 & SSH_SSTAT1_ORF)
! 927: ++adjust;
! 928: if (sstat1 & SSH_SSTAT1_OLF)
! 929: ++adjust;
! 930: acb->iob_curlen = *((long *)&rp->ssh_dcmd) & 0xffffff;
! 931: acb->iob_curlen += adjust;
! 932: acb->iob_curbuf = *((long *)&rp->ssh_dnad) - adjust;
! 933: #ifdef DEBUG
! 934: if (ssh_debug & 0x100) {
! 935: int i;
! 936: printf ("Phase mismatch: curbuf %x curlen %x dfifo %x dbc %x sstat1 %x adjust %x sbcl %x starts %d acb %x\n",
! 937: acb->iob_curbuf, acb->iob_curlen, dfifo,
! 938: dbc, sstat1, adjust, rp->ssh_sbcl, sshstarts, acb);
! 939: if (acb->ds.chain[1].datalen) {
! 940: for (i = 0; acb->ds.chain[i].datalen; ++i)
! 941: printf("chain[%d] addr %x len %x\n",
! 942: i, acb->ds.chain[i].databuf,
! 943: acb->ds.chain[i].datalen);
! 944: }
! 945: }
! 946: #endif
! 947: dma_cachectl((caddr_t)acb, sizeof(*acb));
! 948: }
! 949: #ifdef DEBUG
! 950: SSH_TRACE('m',rp->ssh_sbcl,(rp->ssh_dsp>>8),rp->ssh_dsp);
! 951: if (ssh_debug & 9)
! 952: printf ("Phase mismatch: %x dsp +%x dcmd %x\n",
! 953: rp->ssh_sbcl,
! 954: rp->ssh_dsp - sc->sc_scriptspa,
! 955: *((long *)&rp->ssh_dcmd));
! 956: #endif
! 957: if ((rp->ssh_sbcl & SSH_REQ) == 0) {
! 958: printf ("Phase mismatch: REQ not asserted! %02x dsp %lx\n",
! 959: rp->ssh_sbcl, rp->ssh_dsp);
! 960: #ifdef DEBUG
! 961: Debugger();
! 962: #endif
! 963: }
! 964: switch (rp->ssh_sbcl & 7) {
! 965: case 0: /* data out */
! 966: case 1: /* data in */
! 967: case 2: /* status */
! 968: case 3: /* command */
! 969: case 6: /* message in */
! 970: case 7: /* message out */
! 971: rp->ssh_dsp = sc->sc_scriptspa + Ent_switch;
! 972: break;
! 973: default:
! 974: goto bad_phase;
! 975: }
! 976: return 0;
! 977: }
! 978: if (sstat0 & SSH_SSTAT0_STO) { /* Select timed out */
! 979: #ifdef DEBUG
! 980: if (acb == NULL)
! 981: printf("%s: Select timeout with no active command?\n",
! 982: sc->sc_dev.dv_xname);
! 983: if (rp->ssh_sbcl & SSH_BSY) {
! 984: printf ("ACK! ssh was busy at timeout: rp %x script %x dsa %x\n",
! 985: rp, &scripts, &acb->ds);
! 986: printf(" sbcl %x sdid %x istat %x dstat %x sstat0 %x\n",
! 987: rp->ssh_sbcl, rp->ssh_sdid, istat, dstat, sstat0);
! 988: if (!(rp->ssh_sbcl & SSH_BSY)) {
! 989: printf ("Yikes, it's not busy now!\n");
! 990: #if 0
! 991: *status = -1;
! 992: if (!TAILQ_EMPTY(&sc->nexus_list))
! 993: rp->ssh_dsp = sc->sc_scriptspa + Ent_wait_reselect;
! 994: return 1;
! 995: #endif
! 996: }
! 997: /* rp->ssh_dcntl |= SSH_DCNTL_STD;*/
! 998: return (0);
! 999: #ifdef DDB
! 1000: Debugger();
! 1001: #endif
! 1002: }
! 1003: #endif
! 1004: *status = -1;
! 1005: acb->xs->error = XS_SELTIMEOUT;
! 1006: if (!TAILQ_EMPTY(&sc->nexus_list))
! 1007: rp->ssh_dsp = sc->sc_scriptspa + Ent_wait_reselect;
! 1008: return 1;
! 1009: }
! 1010: if (acb)
! 1011: target = acb->xs->sc_link->target;
! 1012: else
! 1013: target = 7;
! 1014: if (sstat0 & SSH_SSTAT0_UDC) {
! 1015: #ifdef DEBUG
! 1016: if (acb == NULL)
! 1017: printf("%s: Unexpected disconnect with no active command?\n",
! 1018: sc->sc_dev.dv_xname);
! 1019: printf ("%s: target %d disconnected unexpectedly\n",
! 1020: sc->sc_dev.dv_xname, target);
! 1021: #endif
! 1022: #if 0
! 1023: sshabort (sc, rp, "sshchkintr");
! 1024: #endif
! 1025: *status = STS_BUSY;
! 1026: if (!TAILQ_EMPTY(&sc->nexus_list))
! 1027: rp->ssh_dsp = sc->sc_scriptspa + Ent_wait_reselect;
! 1028: return 1;
! 1029: }
! 1030: if (dstat & SSH_DSTAT_SIR && (rp->ssh_dsps == 0xff01 ||
! 1031: rp->ssh_dsps == 0xff02)) {
! 1032: #ifdef DEBUG
! 1033: if (ssh_debug & 0x100)
! 1034: printf ("%s: ID %02x disconnected TEMP %x (+%x) curbuf %x curlen %x buf %x len %x dfifo %x dbc %x sstat1 %x starts %d acb %x\n",
! 1035: sc->sc_dev.dv_xname, 1 << target, rp->ssh_temp,
! 1036: rp->ssh_temp ? rp->ssh_temp - sc->sc_scriptspa : 0,
! 1037: acb->iob_curbuf, acb->iob_curlen,
! 1038: acb->ds.chain[0].databuf, acb->ds.chain[0].datalen, dfifo, dbc, sstat1, sshstarts, acb);
! 1039: #endif
! 1040: if (acb == NULL) {
! 1041: printf("%s: Disconnect with no active command?\n",
! 1042: sc->sc_dev.dv_xname);
! 1043: return (0);
! 1044: }
! 1045: /*
! 1046: * XXXX need to update iob_curbuf/iob_curlen to reflect
! 1047: * current data transferred. If device disconnected in
! 1048: * the middle of a DMA block, they should already be set
! 1049: * by the phase change interrupt. If the disconnect
! 1050: * occurs on a DMA block boundary, we have to figure out
! 1051: * which DMA block it was.
! 1052: */
! 1053: if (acb->iob_len && rp->ssh_temp) {
! 1054: int n = rp->ssh_temp - sc->sc_scriptspa;
! 1055:
! 1056: if (acb->iob_curlen && acb->iob_curlen != acb->ds.chain[0].datalen)
! 1057: printf("%s: iob_curbuf/len already set? n %x iob %lx/%lx chain[0] %p/%lx\n",
! 1058: sc->sc_dev.dv_xname, n, acb->iob_curbuf, acb->iob_curlen,
! 1059: acb->ds.chain[0].databuf, acb->ds.chain[0].datalen);
! 1060: if (n < Ent_datain)
! 1061: n = (n - Ent_dataout) / 16;
! 1062: else
! 1063: n = (n - Ent_datain) / 16;
! 1064: if (n <= 0 || n >= DMAMAXIO)
! 1065: printf("TEMP invalid %d\n", n);
! 1066: else {
! 1067: acb->iob_curbuf = (u_long)acb->ds.chain[n].databuf;
! 1068: acb->iob_curlen = acb->ds.chain[n].datalen;
! 1069: }
! 1070: #ifdef DEBUG
! 1071: if (ssh_debug & 0x100) {
! 1072: printf("%s: TEMP offset %d", sc->sc_dev.dv_xname, n);
! 1073: printf(" curbuf %x curlen %x\n", acb->iob_curbuf,
! 1074: acb->iob_curlen);
! 1075: }
! 1076: #endif
! 1077: }
! 1078: /*
! 1079: * If data transfer was interrupted by disconnect, iob_curbuf
! 1080: * and iob_curlen should reflect the point of interruption.
! 1081: * Adjust the DMA chain so that the data transfer begins
! 1082: * at the appropriate place upon reselection.
! 1083: * XXX This should only be done on save data pointer message?
! 1084: */
! 1085: if (acb->iob_curlen) {
! 1086: int i, j;
! 1087:
! 1088: #ifdef DEBUG
! 1089: if (ssh_debug & 0x100)
! 1090: printf ("%s: adjusting DMA chain\n",
! 1091: sc->sc_dev.dv_xname);
! 1092: if (rp->ssh_dsps == 0xff02)
! 1093: printf ("%s: ID %02x disconnected without Save Data Pointers\n",
! 1094: sc->sc_dev.dv_xname, 1 << target);
! 1095: #endif
! 1096: for (i = 0; i < DMAMAXIO; ++i) {
! 1097: if (acb->ds.chain[i].datalen == 0)
! 1098: break;
! 1099: if (acb->iob_curbuf >= (long)acb->ds.chain[i].databuf &&
! 1100: acb->iob_curbuf < (long)(acb->ds.chain[i].databuf +
! 1101: acb->ds.chain[i].datalen))
! 1102: break;
! 1103: }
! 1104: if (i >= DMAMAXIO || acb->ds.chain[i].datalen == 0)
! 1105: printf("couldn't find saved data pointer\n");
! 1106: #ifdef DEBUG
! 1107: if (ssh_debug & 0x100)
! 1108: printf(" chain[0]: %x/%x -> %x/%x\n",
! 1109: acb->ds.chain[0].databuf,
! 1110: acb->ds.chain[0].datalen,
! 1111: acb->iob_curbuf,
! 1112: acb->iob_curlen);
! 1113: #endif
! 1114: acb->ds.chain[0].databuf = (char *)acb->iob_curbuf;
! 1115: acb->ds.chain[0].datalen = acb->iob_curlen;
! 1116: for (j = 1, ++i; i < DMAMAXIO && acb->ds.chain[i].datalen; ++i, ++j) {
! 1117: #ifdef DEBUG
! 1118: if (ssh_debug & 0x100)
! 1119: printf(" chain[%d]: %x/%x -> %x/%x\n", j,
! 1120: acb->ds.chain[j].databuf,
! 1121: acb->ds.chain[j].datalen,
! 1122: acb->ds.chain[i].databuf,
! 1123: acb->ds.chain[i].datalen);
! 1124: #endif
! 1125: acb->ds.chain[j].databuf = acb->ds.chain[i].databuf;
! 1126: acb->ds.chain[j].datalen = acb->ds.chain[i].datalen;
! 1127: }
! 1128: if (j < DMAMAXIO)
! 1129: acb->ds.chain[j++].datalen = 0;
! 1130: dma_cachectl((caddr_t)&acb->ds.chain,
! 1131: j * sizeof(acb->ds.chain[0]));
! 1132: }
! 1133: ++sc->sc_tinfo[target].dconns;
! 1134: /*
! 1135: * add nexus to waiting list
! 1136: * clear nexus
! 1137: * try to start another command for another target/lun
! 1138: */
! 1139: acb->status = sc->sc_flags & SSH_INTSOFF;
! 1140: TAILQ_INSERT_HEAD(&sc->nexus_list, acb, chain);
! 1141: sc->sc_nexus = NULL; /* no current device */
! 1142: /* start script to wait for reselect */
! 1143: if (sc->sc_nexus == NULL)
! 1144: rp->ssh_dsp = sc->sc_scriptspa + Ent_wait_reselect;
! 1145: /* XXXX start another command ? */
! 1146: if (!TAILQ_EMPTY(&sc->ready_list))
! 1147: ssh_sched(sc);
! 1148: return (0);
! 1149: }
! 1150: if (dstat & SSH_DSTAT_SIR && rp->ssh_dsps == 0xff03) {
! 1151: int reselid = rp->ssh_scratch & 0x7f;
! 1152: int reselun = rp->ssh_sfbr & 0x07;
! 1153:
! 1154: sc->sc_sstat1 = rp->ssh_sbcl; /* XXXX save current SBCL */
! 1155: #ifdef DEBUG
! 1156: if (ssh_debug & 0x100)
! 1157: printf ("%s: target ID %02x reselected dsps %x\n",
! 1158: sc->sc_dev.dv_xname, reselid,
! 1159: rp->ssh_dsps);
! 1160: if ((rp->ssh_sfbr & 0x80) == 0)
! 1161: printf("%s: Reselect message in was not identify: %x\n",
! 1162: sc->sc_dev.dv_xname, rp->ssh_sfbr);
! 1163: #endif
! 1164: if (sc->sc_nexus) {
! 1165: #ifdef DEBUG
! 1166: if (ssh_debug & 0x100)
! 1167: printf ("%s: reselect ID %02x w/active\n",
! 1168: sc->sc_dev.dv_xname, reselid);
! 1169: #endif
! 1170: TAILQ_INSERT_HEAD(&sc->ready_list, sc->sc_nexus, chain);
! 1171: sc->sc_tinfo[sc->sc_nexus->xs->sc_link->target].lubusy
! 1172: &= ~(1 << sc->sc_nexus->xs->sc_link->lun);
! 1173: --sc->sc_active;
! 1174: }
! 1175: /*
! 1176: * locate acb of reselecting device
! 1177: * set sc->sc_nexus to acb
! 1178: */
! 1179: TAILQ_FOREACH(acb, &sc->nexus_list, chain) {
! 1180: if (reselid != (acb->ds.scsi_addr >> 16) ||
! 1181: reselun != (acb->msgout[0] & 0x07))
! 1182: continue;
! 1183: TAILQ_REMOVE(&sc->nexus_list, acb, chain);
! 1184: sc->sc_nexus = acb;
! 1185: sc->sc_flags |= acb->status;
! 1186: acb->status = 0;
! 1187: dma_cachectl(&acb->stat[0], 1); /* XXX necessary? */
! 1188: rp->ssh_dsa = kvtop((vaddr_t)&acb->ds);
! 1189: rp->ssh_sxfer = sc->sc_sync[acb->xs->sc_link->target].sxfer;
! 1190: rp->ssh_sbcl = sc->sc_sync[acb->xs->sc_link->target].sbcl;
! 1191: break;
! 1192: }
! 1193: if (acb == NULL) {
! 1194: printf("%s: target ID %02x reselect nexus_list %p\n",
! 1195: sc->sc_dev.dv_xname, reselid,
! 1196: TAILQ_FIRST(&sc->nexus_list));
! 1197: panic("unable to find reselecting device");
! 1198: }
! 1199: dma_cachectl((caddr_t)acb, sizeof(*acb));
! 1200: rp->ssh_temp = 0;
! 1201: rp->ssh_dcntl |= SSH_DCNTL_STD;
! 1202: return (0);
! 1203: }
! 1204: if (dstat & SSH_DSTAT_SIR && rp->ssh_dsps == 0xff04) {
! 1205: #ifdef DEBUG
! 1206: u_short ctest2 = rp->ssh_ctest2;
! 1207:
! 1208: /* reselect was interrupted (by Sig_P or select) */
! 1209: if (ssh_debug & 0x100 ||
! 1210: (ctest2 & SSH_CTEST2_SIGP) == 0)
! 1211: printf ("%s: reselect interrupted (Sig_P?) scntl1 %x ctest2 %x
! 1212: sfbr %x istat %x/%x\n", sc->sc_dev.dv_xname, rp->ssh_scntl1,
! 1213: ctest2, rp->ssh_sfbr, istat, rp->ssh_istat);
! 1214: #endif
! 1215: /* XXX assumes it was not select */
! 1216: if (sc->sc_nexus == NULL) {
! 1217: printf("%s: reselect interrupted, sc_nexus == NULL\n",
! 1218: sc->sc_dev.dv_xname);
! 1219: #if 0
! 1220: ssh_dump(sc);
! 1221: #ifdef DDB
! 1222: Debugger();
! 1223: #endif
! 1224: #endif
! 1225: rp->ssh_dcntl |= SSH_DCNTL_STD;
! 1226: return (0);
! 1227: }
! 1228: target = sc->sc_nexus->xs->sc_link->target;
! 1229: rp->ssh_temp = 0;
! 1230: rp->ssh_dsa = kvtop((vaddr_t)&sc->sc_nexus->ds);
! 1231: rp->ssh_sxfer = sc->sc_sync[target].sxfer;
! 1232: rp->ssh_sbcl = sc->sc_sync[target].sbcl;
! 1233: rp->ssh_dsp = sc->sc_scriptspa;
! 1234: return (0);
! 1235: }
! 1236: if (dstat & SSH_DSTAT_SIR && rp->ssh_dsps == 0xff06) {
! 1237: if (acb == NULL)
! 1238: printf("%s: Bad message-in with no active command?\n",
! 1239: sc->sc_dev.dv_xname);
! 1240: /* Unrecognized message in byte */
! 1241: dma_cachectl(&acb->msg[1],1);
! 1242: printf ("%s: Unrecognized message in data sfbr %x msg %x sbcl %x\n",
! 1243: sc->sc_dev.dv_xname, rp->ssh_sfbr, acb->msg[1], rp->ssh_sbcl);
! 1244: /* what should be done here? */
! 1245: rp->ssh_dsp = sc->sc_scriptspa + Ent_switch;
! 1246: return (0);
! 1247: }
! 1248: if (dstat & SSH_DSTAT_SIR && rp->ssh_dsps == 0xff0a) {
! 1249: /* Status phase wasn't followed by message in phase? */
! 1250: printf ("%s: Status phase not followed by message in phase? sbcl %x sbdl %x\n",
! 1251: sc->sc_dev.dv_xname, rp->ssh_sbcl, rp->ssh_sbdl);
! 1252: if (rp->ssh_sbcl == 0xa7) {
! 1253: /* It is now, just continue the script? */
! 1254: rp->ssh_dcntl |= SSH_DCNTL_STD;
! 1255: return (0);
! 1256: }
! 1257: }
! 1258: if (sstat0 == 0 && dstat & SSH_DSTAT_SIR) {
! 1259: dma_cachectl(&acb->stat[0], 1);
! 1260: dma_cachectl(&acb->msg[0], 1);
! 1261: printf ("SSH interrupt: %lx sts %x msg %x %x sbcl %x\n",
! 1262: rp->ssh_dsps, acb->stat[0], acb->msg[0], acb->msg[1],
! 1263: rp->ssh_sbcl);
! 1264: sshreset (sc);
! 1265: *status = -1;
! 1266: return 0; /* sshreset has cleaned up */
! 1267: }
! 1268: if (sstat0 & SSH_SSTAT0_SGE)
! 1269: printf ("SSH: SCSI Gross Error\n");
! 1270: if (sstat0 & SSH_SSTAT0_PAR)
! 1271: printf ("SSH: Parity Error\n");
! 1272: if (dstat & SSH_DSTAT_IID)
! 1273: printf ("SSH: Invalid instruction detected\n");
! 1274: bad_phase:
! 1275: /*
! 1276: * temporary panic for unhandled conditions
! 1277: * displays various things about the 53C710 status and registers
! 1278: * then panics.
! 1279: * XXXX need to clean this up to print out the info, reset, and continue
! 1280: */
! 1281: printf ("sshchkintr: target %x ds %p\n", target, &acb->ds);
! 1282: printf ("scripts %lx ds %lx rp %lx dsp %lx dcmd %lx\n", sc->sc_scriptspa,
! 1283: kvtop((vaddr_t)&acb->ds), kvtop((vaddr_t)rp), rp->ssh_dsp,
! 1284: *((long *)&rp->ssh_dcmd));
! 1285: printf ("sshchkintr: istat %x dstat %x sstat0 %x dsps %lx "
! 1286: "dsa %lx sbcl %x sts %x msg %x %x sfbr %x\n",
! 1287: istat, dstat, sstat0, rp->ssh_dsps, rp->ssh_dsa,
! 1288: rp->ssh_sbcl, acb->stat[0], acb->msg[0], acb->msg[1],
! 1289: rp->ssh_sfbr);
! 1290: #ifdef DEBUG
! 1291: if (ssh_debug & 0x20)
! 1292: panic("sshchkintr: **** temp ****");
! 1293: #ifdef DDB
! 1294: /* Debugger(); */
! 1295: #endif
! 1296: #endif
! 1297: sshreset (sc); /* hard reset */
! 1298: *status = -1;
! 1299: return 0; /* sshreset cleaned up */
! 1300: }
! 1301:
! 1302: void
! 1303: ssh_select(sc)
! 1304: struct ssh_softc *sc;
! 1305: {
! 1306: ssh_regmap_p rp;
! 1307: struct ssh_acb *acb = sc->sc_nexus;
! 1308:
! 1309: #ifdef DEBUG
! 1310: if (ssh_debug & 1)
! 1311: printf ("%s: select ", sc->sc_dev.dv_xname);
! 1312: #endif
! 1313:
! 1314: rp = sc->sc_sshp;
! 1315: if (acb->xs->flags & SCSI_POLL || ssh_no_dma) {
! 1316: sc->sc_flags |= SSH_INTSOFF;
! 1317: sc->sc_flags &= ~SSH_INTDEFER;
! 1318: if ((rp->ssh_istat & 0x08) == 0) {
! 1319: rp->ssh_sien = 0;
! 1320: rp->ssh_dien = 0;
! 1321: }
! 1322: #if 0
! 1323: } else if ((sc->sc_flags & SSH_INTDEFER) == 0) {
! 1324: sc->sc_flags &= ~SSH_INTSOFF;
! 1325: if ((rp->ssh_istat & 0x08) == 0) {
! 1326: rp->ssh_sien = sc->sc_sien;
! 1327: rp->ssh_dien = sc->sc_dien;
! 1328: }
! 1329: #endif
! 1330: }
! 1331: #ifdef DEBUG
! 1332: if (ssh_debug & 1)
! 1333: printf ("ssh_select: target %x cmd %02x ds %x\n",
! 1334: acb->xs->sc_link->target, acb->cmd.opcode,
! 1335: &sc->sc_nexus->ds);
! 1336: #endif
! 1337:
! 1338: ssh_start(sc, acb->xs->sc_link->target, acb->xs->sc_link->lun,
! 1339: (u_char *)&acb->cmd, acb->clen, acb->daddr, acb->dleft);
! 1340:
! 1341: return;
! 1342: }
! 1343:
! 1344: /*
! 1345: * 53C710 interrupt handler
! 1346: */
! 1347: void
! 1348: sshintr(sc)
! 1349: register struct ssh_softc *sc;
! 1350: {
! 1351: ssh_regmap_p rp;
! 1352: register u_char istat, dstat, sstat0;
! 1353: int status;
! 1354: int s = splbio();
! 1355:
! 1356: istat = sc->sc_istat;
! 1357: if ((istat & (SSH_ISTAT_SIP | SSH_ISTAT_DIP)) == 0) {
! 1358: splx(s);
! 1359: return;
! 1360: }
! 1361:
! 1362: /* Got a valid interrupt on this device */
! 1363: rp = sc->sc_sshp;
! 1364: dstat = sc->sc_dstat;
! 1365: sstat0 = sc->sc_sstat0;
! 1366: if (dstat & SSH_DSTAT_SIR)
! 1367: sc->sc_intcode = rp->ssh_dsps;
! 1368: sc->sc_istat = 0;
! 1369:
! 1370: #ifdef DEBUG
! 1371: if (ssh_debug & 1)
! 1372: printf ("%s: intr istat %x dstat %x sstat0 %x\n",
! 1373: sc->sc_dev.dv_xname, istat, dstat, sstat0);
! 1374: if (!sc->sc_active) {
! 1375: printf ("%s: spurious interrupt? istat %x dstat %x sstat0 %x status %x\n",
! 1376: sc->sc_dev.dv_xname, istat, dstat, sstat0, sc->sc_nexus->stat[0]);
! 1377: }
! 1378: #else
! 1379: if (!sc->sc_active) {
! 1380: printf ("%s: spurious interrupt? istat %x dstat %x sstat0 %x status %x\n",
! 1381: sc->sc_dev.dv_xname, istat, dstat, sstat0, sc->sc_nexus->stat[0]);
! 1382: return;
! 1383: }
! 1384: #endif
! 1385:
! 1386: #ifdef DEBUG
! 1387: if (ssh_debug & 5) {
! 1388: dma_cachectl(&sc->sc_nexus->stat[0], 1);
! 1389: printf ("%s: intr istat %x dstat %x sstat0 %x dsps %x sbcl %x sts %x msg %x\n",
! 1390: sc->sc_dev.dv_xname, istat, dstat, sstat0,
! 1391: rp->ssh_dsps, rp->ssh_sbcl,
! 1392: sc->sc_nexus->stat[0], sc->sc_nexus->msg[0]);
! 1393: }
! 1394: #endif
! 1395: if (sc->sc_flags & SSH_INTDEFER) {
! 1396: sc->sc_flags &= ~(SSH_INTDEFER | SSH_INTSOFF);
! 1397: rp->ssh_sien = sc->sc_sien;
! 1398: rp->ssh_dien = sc->sc_dien;
! 1399: }
! 1400: if (ssh_checkintr (sc, istat, dstat, sstat0, &status)) {
! 1401: #if 1
! 1402: if (status == 0xff)
! 1403: printf ("sshintr: status == 0xff\n");
! 1404: #endif
! 1405: if ((sc->sc_flags & (SSH_INTSOFF | SSH_INTDEFER)) != SSH_INTSOFF) {
! 1406: #if 0
! 1407: if (rp->ssh_sbcl & SSH_BSY) {
! 1408: printf ("%s: SCSI bus busy at completion",
! 1409: sc->sc_dev.dv_xname);
! 1410: printf(" targ %d sbcl %02x sfbr %x lcrc %02x dsp +%x\n",
! 1411: sc->sc_nexus->xs->sc_link->target,
! 1412: rp->ssh_sbcl, rp->ssh_sfbr, rp->ssh_lcrc,
! 1413: rp->ssh_dsp - sc->sc_scriptspa);
! 1414: }
! 1415: #endif
! 1416: ssh_scsidone(sc->sc_nexus, sc->sc_nexus->stat[0]);
! 1417: }
! 1418: }
! 1419: splx(s);
! 1420: }
! 1421:
! 1422: /*
! 1423: * This is based on the Progressive Peripherals 33MHz Zeus driver and will
! 1424: * not be correct for other 53c710 boards.
! 1425: *
! 1426: */
! 1427: void
! 1428: scsi_period_to_ssh (sc, target)
! 1429: struct ssh_softc *sc;
! 1430: int target;
! 1431: {
! 1432: int period, offset, sxfer, sbcl;
! 1433:
! 1434: period = sc->sc_nexus->msg[4];
! 1435: offset = sc->sc_nexus->msg[5];
! 1436: for (sbcl = 1; sbcl < 4; ++sbcl) {
! 1437: sxfer = (period * 4 - 1) / sc->sc_tcp[sbcl] - 3;
! 1438: if (sxfer >= 0 && sxfer <= 7)
! 1439: break;
! 1440: }
! 1441: if (sbcl > 3) {
! 1442: printf("ssh_sync: unable to compute sync params for period %dns\n",
! 1443: period * 4);
! 1444: /*
! 1445: * XXX need to pick a value we can do and renegotiate
! 1446: */
! 1447: sxfer = sbcl = 0;
! 1448: } else
! 1449: sxfer = (sxfer << 4) | ((offset <= SSH_MAX_OFFSET) ?
! 1450: offset : SSH_MAX_OFFSET);
! 1451: sc->sc_sync[target].sxfer = sxfer;
! 1452: sc->sc_sync[target].sbcl = sbcl;
! 1453: #ifdef DEBUG
! 1454: printf ("ssh sync: ssh_sxfr %02x, ssh_sbcl %02x\n", sxfer, sbcl);
! 1455: #endif
! 1456: }
! 1457:
! 1458: #ifdef DEBUG
! 1459:
! 1460: #if SSH_TRACE_SIZE
! 1461: void
! 1462: ssh_dump_trace()
! 1463: {
! 1464: int i;
! 1465:
! 1466: printf("ssh trace: next index %d\n", ssh_trix);
! 1467: i = ssh_trix;
! 1468: do {
! 1469: printf("%3d: '%c' %02x %02x %02x\n", i, ssh_trbuf[i],
! 1470: ssh_trbuf[i + 1], ssh_trbuf[i + 2], ssh_trbuf[i + 3]);
! 1471: i = (i + 4) & (SSH_TRACE_SIZE - 1);
! 1472: } while (i != ssh_trix);
! 1473: }
! 1474: #endif
! 1475:
! 1476: void
! 1477: ssh_dump_acb(acb)
! 1478: struct ssh_acb *acb;
! 1479: {
! 1480: u_char *b = (u_char *) &acb->cmd;
! 1481: int i;
! 1482:
! 1483: #if SSH_TRACE_SIZE
! 1484: ssh_dump_trace();
! 1485: #endif
! 1486: printf("acb@%x ", acb);
! 1487: if (acb->xs == NULL) {
! 1488: printf("<unused>\n");
! 1489: return;
! 1490: }
! 1491: printf("(%d:%d) flags %2x clen %2d cmd ", acb->xs->sc_link->target,
! 1492: acb->xs->sc_link->lun, acb->flags, acb->clen);
! 1493: for (i = acb->clen; i; --i)
! 1494: printf(" %02x", *b++);
! 1495: printf("\n");
! 1496: printf(" xs: %08x data %8x:%04x ", acb->xs, acb->xs->data,
! 1497: acb->xs->datalen);
! 1498: printf("va %8x:%04x ", acb->iob_buf, acb->iob_len);
! 1499: printf("cur %8x:%04x\n", acb->iob_curbuf, acb->iob_curlen);
! 1500: }
! 1501:
! 1502: void
! 1503: ssh_dump(sc)
! 1504: struct ssh_softc *sc;
! 1505: {
! 1506: struct ssh_acb *acb;
! 1507: ssh_regmap_p rp = sc->sc_sshp;
! 1508: int s;
! 1509: int i;
! 1510:
! 1511: s = splbio();
! 1512: printf("%s@%x regs %x istat %x\n",
! 1513: sc->sc_dev.dv_xname, sc, rp, rp->ssh_istat);
! 1514: if (acb = TAILQ_FIRST(&sc->free_list)) {
! 1515: printf("Free list:\n");
! 1516: while (acb) {
! 1517: ssh_dump_acb(acb);
! 1518: acb = TAILQ_NEXT(acb, chain);
! 1519: }
! 1520: }
! 1521: if (acb = TAILQ_FIRST(&sc->ready_list)) {
! 1522: printf("Ready list:\n");
! 1523: while (acb) {
! 1524: ssh_dump_acb(acb);
! 1525: acb = TAILQ_NEXT(acb, chain);
! 1526: }
! 1527: }
! 1528: if (acb = TAILQ_FIRST(&sc->nexus_list)) {
! 1529: printf("Nexus list:\n");
! 1530: while (acb) {
! 1531: ssh_dump_acb(acb);
! 1532: acb = TAILQ_NEXT(acb, chain);
! 1533: }
! 1534: }
! 1535: if (sc->sc_nexus) {
! 1536: printf("Nexus:\n");
! 1537: ssh_dump_acb(sc->sc_nexus);
! 1538: }
! 1539: for (i = 0; i < 8; ++i) {
! 1540: if (sc->sc_tinfo[i].cmds > 2) {
! 1541: printf("tgt %d: cmds %d disc %d senses %d lubusy %x\n",
! 1542: i, sc->sc_tinfo[i].cmds,
! 1543: sc->sc_tinfo[i].dconns,
! 1544: sc->sc_tinfo[i].senses,
! 1545: sc->sc_tinfo[i].lubusy);
! 1546: }
! 1547: }
! 1548: splx(s);
! 1549: }
! 1550: #endif
CVSweb