Annotation of sys/arch/mvme68k/dev/vs.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: vs.c,v 1.20 2006/06/02 18:53:56 miod Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 1999 Steve Murphree, Jr.
! 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:
! 36: /*
! 37: * MVME328 scsi adaptor driver
! 38: */
! 39:
! 40: #include <sys/param.h>
! 41: #include <sys/systm.h>
! 42: #include <sys/device.h>
! 43: #include <sys/disklabel.h>
! 44: #include <sys/dkstat.h>
! 45: #include <sys/buf.h>
! 46: #include <sys/malloc.h>
! 47:
! 48: #include <scsi/scsi_all.h>
! 49: #include <scsi/scsiconf.h>
! 50:
! 51: #include <machine/autoconf.h>
! 52: #include <machine/param.h>
! 53:
! 54: #include <uvm/uvm_param.h>
! 55:
! 56: #ifdef mvme88k
! 57: #include <mvme88k/dev/vsreg.h>
! 58: #include <mvme88k/dev/vsvar.h>
! 59: #include <machine/mmu.h>
! 60: #else
! 61: #include <mvme68k/dev/vsreg.h>
! 62: #include <mvme68k/dev/vsvar.h>
! 63: #endif
! 64:
! 65: void scopy(void *, void *, u_int);
! 66: void szero(void *, u_int);
! 67: int do_vspoll(struct vs_softc *, int, int);
! 68: void thaw_queue(struct vs_softc *, u_int8_t);
! 69: int vs_checkintr(struct vs_softc *, struct scsi_xfer *, int *);
! 70: void vs_chksense(struct scsi_xfer *);
! 71: void vs_reset(struct vs_softc *);
! 72: void vs_resync(struct vs_softc *);
! 73: void vs_initialize(struct vs_softc *);
! 74: void vs_intr(void *);
! 75: int vs_poll(struct vs_softc *, struct scsi_xfer *);
! 76: void vs_scsidone(struct scsi_xfer *, int);
! 77: M328_CQE *vs_getcqe(struct vs_softc *);
! 78: M328_IOPB *vs_getiopb(struct vs_softc *);
! 79: void vs_link_sg_element(sg_list_element_t *, vaddr_t, int);
! 80: void vs_link_sg_list(sg_list_element_t *, vaddr_t, int);
! 81:
! 82: /*
! 83: * 16 bit 's' memory functions. MVME328 is a D16 board.
! 84: * We must program with that in mind or else...
! 85: * bcopy/bzero (the 'b' meaning byte) is implemented in
! 86: * 32 bit operations for speed, so thay are not really
! 87: * 'byte' operations at all!! MVME1x7 can be set up to
! 88: * handle D32 -> D16 read/writes via VMEChip2 Address
! 89: * modifiers, however MVME188 can not. These next two
! 90: * functions insure 16 bit copy/zero operations. The
! 91: * structures are all implemented with 16 bit or less
! 92: * types. smurph
! 93: */
! 94:
! 95: void
! 96: scopy(src, dst, cnt)
! 97: void *src, *dst;
! 98: u_int cnt;
! 99: {
! 100: u_int16_t volatile *x, *y, z;
! 101:
! 102: z = cnt >> 1;
! 103: x = (u_int16_t *) src;
! 104: y = (u_int16_t *) dst;
! 105:
! 106: while (z--) {
! 107: *y++ = *x++;
! 108: }
! 109: }
! 110:
! 111: void
! 112: szero(src, cnt)
! 113: void *src;
! 114: u_int cnt;
! 115: {
! 116: u_int16_t *source;
! 117: u_int16_t zero = 0;
! 118: u_int16_t z;
! 119:
! 120: source = (u_int16_t *) src;
! 121: z = cnt >> 1;
! 122:
! 123: while (z--) {
! 124: *source++ = zero;
! 125: }
! 126: }
! 127:
! 128: /*
! 129: * default minphys routine for MVME328 based controllers
! 130: */
! 131: void
! 132: vs_minphys(bp)
! 133: struct buf *bp;
! 134: {
! 135: /*
! 136: * No max transfer at this level.
! 137: */
! 138: minphys(bp);
! 139: }
! 140:
! 141: int
! 142: do_vspoll(sc, to, canreset)
! 143: struct vs_softc *sc;
! 144: int to;
! 145: int canreset;
! 146: {
! 147: int i;
! 148:
! 149: if (to <= 0 ) to = 50000;
! 150: /* use cmd_wait values? */
! 151: i = 50000;
! 152: /*spl0();*/
! 153: while (!(CRSW & (M_CRSW_CRBV | M_CRSW_CC))) {
! 154: if (--i <= 0) {
! 155: #ifdef DEBUG
! 156: printf ("waiting: timeout %d crsw 0x%x\n", to, CRSW);
! 157: #endif
! 158: i = 50000;
! 159: --to;
! 160: if (to <= 0) {
! 161: /*splx(s);*/
! 162: if (canreset) {
! 163: vs_reset(sc);
! 164: vs_resync(sc);
! 165: }
! 166: printf ("timed out: timeout %d crsw 0x%x\n",
! 167: to, CRSW);
! 168: return 1;
! 169: }
! 170: }
! 171: }
! 172: return 0;
! 173: }
! 174:
! 175: int
! 176: vs_poll(sc, xs)
! 177: struct vs_softc *sc;
! 178: struct scsi_xfer *xs;
! 179: {
! 180: int status;
! 181: int to;
! 182:
! 183: /*s = splbio();*/
! 184: to = xs->timeout / 1000;
! 185: for (;;) {
! 186: if (do_vspoll(sc, to, 1)) break;
! 187: if (vs_checkintr(sc, xs, &status)) {
! 188: vs_scsidone(xs, status);
! 189: }
! 190: if (CRSW & M_CRSW_ER)
! 191: CRB_CLR_ER(CRSW);
! 192: CRB_CLR_DONE(CRSW);
! 193: if (xs->flags & ITSDONE) break;
! 194: }
! 195: return (COMPLETE);
! 196: }
! 197:
! 198: void
! 199: thaw_queue(sc, target)
! 200: struct vs_softc *sc;
! 201: u_int8_t target;
! 202: {
! 203: u_short t;
! 204: t = target << 8;
! 205: t |= 0x0001;
! 206: THAW_REG = t;
! 207: /* loop until thawed */
! 208: while (THAW_REG & 0x01);
! 209: }
! 210:
! 211: void
! 212: vs_scsidone (xs, stat)
! 213: struct scsi_xfer *xs;
! 214: int stat;
! 215: {
! 216: struct scsi_link *slp = xs->sc_link;
! 217: struct vs_softc *sc = slp->adapter_softc;
! 218: M328_IOPB *riopb = (M328_IOPB *)&sc->sc_vsreg->sh_RET_IOPB;
! 219:
! 220: xs->status = stat;
! 221: while (xs->status == SCSI_CHECK) {
! 222: vs_chksense(xs);
! 223: thaw_queue(sc, slp->target + 1);
! 224: }
! 225: xs->flags |= ITSDONE;
! 226: /*sc->sc_tinfo[slp->target].cmds++;*/
! 227: if (CRSW & M_CRSW_ER)
! 228: CRB_CLR_ER(CRSW);
! 229: CRB_CLR_DONE(CRSW);
! 230: thaw_queue(sc, slp->target + 1);
! 231: szero(riopb, sizeof(M328_IOPB));
! 232: scsi_done(xs);
! 233: }
! 234:
! 235: int
! 236: vs_scsicmd(xs)
! 237: struct scsi_xfer *xs;
! 238: {
! 239: struct scsi_link *slp = xs->sc_link;
! 240: struct vs_softc *sc = slp->adapter_softc;
! 241: int flags;
! 242: unsigned long buf, len;
! 243: u_short iopb_len;
! 244: M328_CQE *mc = (M328_CQE*)&sc->sc_vsreg->sh_MCE;
! 245: M328_CRB *crb = (M328_CRB *)&sc->sc_vsreg->sh_CRB;
! 246: M328_IOPB *miopb = (M328_IOPB *)&sc->sc_vsreg->sh_MCE_IOPB;
! 247: M328_CQE *cqep;
! 248: M328_IOPB *iopb;
! 249: M328_CMD *m328_cmd;
! 250:
! 251: /* If the target doesn't exist, abort */
! 252: if (!sc->sc_tinfo[slp->target].avail) {
! 253: xs->error = XS_SELTIMEOUT;
! 254: xs->status = -1;
! 255: xs->flags |= ITSDONE;
! 256: scsi_done(xs);
! 257: }
! 258:
! 259: flags = xs->flags;
! 260: #ifdef SDEBUG
! 261: printf("scsi_cmd() ");
! 262: if (xs->cmd->opcode == 0) {
! 263: printf("TEST_UNIT_READY ");
! 264: } else if (xs->cmd->opcode == REQUEST_SENSE) {
! 265: printf("REQUEST_SENSE ");
! 266: } else if (xs->cmd->opcode == INQUIRY) {
! 267: printf("INQUIRY ");
! 268: } else if (xs->cmd->opcode == MODE_SELECT) {
! 269: printf("MODE_SELECT ");
! 270: } else if (xs->cmd->opcode == MODE_SENSE) {
! 271: printf("MODE_SENSE ");
! 272: } else if (xs->cmd->opcode == START_STOP) {
! 273: printf("START_STOP ");
! 274: } else if (xs->cmd->opcode == RESERVE) {
! 275: printf("RESERVE ");
! 276: } else if (xs->cmd->opcode == RELEASE) {
! 277: printf("RELEASE ");
! 278: } else if (xs->cmd->opcode == PREVENT_ALLOW) {
! 279: printf("PREVENT_ALLOW ");
! 280: } else if (xs->cmd->opcode == POSITION_TO_ELEMENT) {
! 281: printf("POSITION_TO_EL ");
! 282: } else if (xs->cmd->opcode == CHANGE_DEFINITION) {
! 283: printf("CHANGE_DEF ");
! 284: } else if (xs->cmd->opcode == MODE_SENSE_BIG) {
! 285: printf("MODE_SENSE_BIG ");
! 286: } else if (xs->cmd->opcode == MODE_SELECT_BIG) {
! 287: printf("MODE_SELECT_BIG ");
! 288: } else if (xs->cmd->opcode == 0x25) {
! 289: printf("READ_CAPACITY ");
! 290: } else if (xs->cmd->opcode == 0x08) {
! 291: printf("READ_COMMAND ");
! 292: }
! 293: #endif
! 294: if (flags & SCSI_POLL) {
! 295: cqep = mc;
! 296: iopb = miopb;
! 297: } else {
! 298: cqep = vs_getcqe(sc);
! 299: if (cqep == NULL) {
! 300: return (TRY_AGAIN_LATER);
! 301: }
! 302: iopb = vs_getiopb(sc);
! 303: }
! 304:
! 305: /* s = splbio();*/
! 306: iopb_len = sizeof(M328_short_IOPB) + xs->cmdlen;
! 307: szero(iopb, sizeof(M328_IOPB));
! 308:
! 309: scopy(xs->cmd, &iopb->iopb_SCSI[0], xs->cmdlen);
! 310: iopb->iopb_CMD = IOPB_SCSI;
! 311: #if 0
! 312: LV(iopb->iopb_BUFF, kvtop(xs->data));
! 313: LV(iopb->iopb_LENGTH, xs->datalen);
! 314: #endif
! 315: iopb->iopb_UNIT = slp->lun << 3;
! 316: iopb->iopb_UNIT |= slp->target;
! 317: iopb->iopb_NVCT = (u_char)sc->sc_nvec;
! 318: iopb->iopb_EVCT = (u_char)sc->sc_evec;
! 319:
! 320: /*
! 321: * Since the 88k's don't support cache snooping, we have
! 322: * to flush the cache for a write and flush with inval for
! 323: * a read, prior to starting the IO.
! 324: */
! 325: if (xs->flags & SCSI_DATA_IN) { /* read */
! 326: #if defined(mvme88k)
! 327: dma_cachectl(xs->data, xs->datalen,
! 328: DMA_CACHE_SYNC_INVAL);
! 329: #endif
! 330: iopb->iopb_OPTION |= OPT_READ;
! 331: } else { /* write */
! 332: #if defined(mvme88k)
! 333: dma_cachectl(xs->data, xs->datalen,
! 334: DMA_CACHE_SYNC);
! 335: #endif
! 336: iopb->iopb_OPTION |= OPT_WRITE;
! 337: }
! 338:
! 339: if (flags & SCSI_POLL) {
! 340: iopb->iopb_OPTION |= OPT_INTDIS;
! 341: iopb->iopb_LEVEL = 0;
! 342: } else {
! 343: iopb->iopb_OPTION |= OPT_INTEN;
! 344: iopb->iopb_LEVEL = sc->sc_ipl;
! 345: }
! 346: iopb->iopb_ADDR = ADDR_MOD;
! 347:
! 348: /*
! 349: * Wait until we can use the command queue entry.
! 350: * Should only have to wait if the master command
! 351: * queue entry is busy.
! 352: */
! 353: while (cqep->cqe_QECR & M_QECR_GO);
! 354:
! 355: cqep->cqe_IOPB_ADDR = OFF(iopb);
! 356: cqep->cqe_IOPB_LENGTH = iopb_len;
! 357: if (flags & SCSI_POLL) {
! 358: cqep->cqe_WORK_QUEUE = slp->target + 1;
! 359: } else {
! 360: cqep->cqe_WORK_QUEUE = slp->target + 1;
! 361: }
! 362:
! 363: MALLOC(m328_cmd, M328_CMD*, sizeof(M328_CMD), M_DEVBUF, M_WAITOK);
! 364:
! 365: m328_cmd->xs = xs;
! 366: if (xs->datalen) {
! 367: m328_cmd->top_sg_list = vs_build_memory_structure(xs, iopb);
! 368: } else {
! 369: m328_cmd->top_sg_list = (M328_SG)0;
! 370: }
! 371:
! 372: LV(cqep->cqe_CTAG, m328_cmd);
! 373:
! 374: if (crb->crb_CRSW & M_CRSW_AQ) {
! 375: cqep->cqe_QECR = M_QECR_AA;
! 376: }
! 377: VL(buf, iopb->iopb_BUFF);
! 378: VL(len, iopb->iopb_LENGTH);
! 379: #ifdef SDEBUG
! 380: printf("tgt %d lun %d buf %x len %d wqn %d ipl %d\n", slp->target,
! 381: slp->lun, buf, len, cqep->cqe_WORK_QUEUE, iopb->iopb_LEVEL);
! 382: #endif
! 383: cqep->cqe_QECR |= M_QECR_GO;
! 384:
! 385: if (flags & SCSI_POLL) {
! 386: /* poll for the command to complete */
! 387: /*splx(s);*/
! 388: vs_poll(sc, xs);
! 389: return (COMPLETE);
! 390: }
! 391: /*splx(s);*/
! 392: return (SUCCESSFULLY_QUEUED);
! 393: }
! 394:
! 395: void
! 396: vs_chksense(xs)
! 397: struct scsi_xfer *xs;
! 398: {
! 399: int s;
! 400: struct scsi_link *slp = xs->sc_link;
! 401: struct vs_softc *sc = slp->adapter_softc;
! 402: struct scsi_sense *ss;
! 403: M328_CQE *mc = (M328_CQE*)&sc->sc_vsreg->sh_MCE;
! 404: M328_IOPB *riopb = (M328_IOPB *)&sc->sc_vsreg->sh_RET_IOPB;
! 405: M328_IOPB *miopb = (M328_IOPB *)&sc->sc_vsreg->sh_MCE_IOPB;
! 406:
! 407: /* ack and clear the error */
! 408: CRB_CLR_DONE(CRSW);
! 409: CRB_CLR_ER(CRSW);
! 410: xs->status = 0;
! 411:
! 412: szero(miopb, sizeof(M328_IOPB));
! 413: /* This is a command, so point to it */
! 414: ss = (void *)&miopb->iopb_SCSI[0];
! 415: szero(ss, sizeof(*ss));
! 416: ss->opcode = REQUEST_SENSE;
! 417: ss->byte2 = slp->lun << 5;
! 418: ss->length = sizeof(struct scsi_sense_data);
! 419:
! 420: miopb->iopb_CMD = IOPB_SCSI;
! 421: miopb->iopb_OPTION = OPT_READ;
! 422: miopb->iopb_NVCT = (u_char)sc->sc_nvec;
! 423: miopb->iopb_EVCT = (u_char)sc->sc_evec;
! 424: miopb->iopb_LEVEL = 0; /*sc->sc_ipl;*/
! 425: miopb->iopb_ADDR = ADDR_MOD;
! 426: LV(miopb->iopb_BUFF, kvtop((vaddr_t)&xs->sense));
! 427: LV(miopb->iopb_LENGTH, sizeof(struct scsi_sense_data));
! 428:
! 429: szero(mc, sizeof(M328_CQE));
! 430: mc->cqe_IOPB_ADDR = OFF(miopb);
! 431: mc->cqe_IOPB_LENGTH = sizeof(M328_short_IOPB) +
! 432: sizeof(struct scsi_sense);
! 433: mc->cqe_WORK_QUEUE = 0;
! 434: mc->cqe_QECR = M_QECR_GO;
! 435: /* poll for the command to complete */
! 436: s = splbio();
! 437: do_vspoll(sc, 0, 1);
! 438: /*
! 439: if (xs->cmd->opcode != PREVENT_ALLOW) {
! 440: xs->error = XS_SENSE;
! 441: }
! 442: */
! 443: xs->status = riopb->iopb_STATUS >> 8;
! 444: #ifdef SDEBUG
! 445: scsi_print_sense(xs);
! 446: #endif
! 447: splx(s);
! 448: }
! 449:
! 450: M328_CQE *
! 451: vs_getcqe(sc)
! 452: struct vs_softc *sc;
! 453: {
! 454: M328_MCSB *mcsb = (M328_MCSB *)&sc->sc_vsreg->sh_MCSB;
! 455: M328_CQE *cqep;
! 456:
! 457: cqep = (M328_CQE *)&sc->sc_vsreg->sh_CQE[mcsb->mcsb_QHDP];
! 458:
! 459: if (cqep->cqe_QECR & M_QECR_GO)
! 460: return NULL; /* Hopefully, this will never happen */
! 461: mcsb->mcsb_QHDP++;
! 462: if (mcsb->mcsb_QHDP == NUM_CQE) mcsb->mcsb_QHDP = 0;
! 463: szero(cqep, sizeof(M328_CQE));
! 464: return cqep;
! 465: }
! 466:
! 467: M328_IOPB *
! 468: vs_getiopb(sc)
! 469: struct vs_softc *sc;
! 470: {
! 471: M328_MCSB *mcsb = (M328_MCSB *)&sc->sc_vsreg->sh_MCSB;
! 472: M328_IOPB *iopb;
! 473: int slot;
! 474:
! 475: if (mcsb->mcsb_QHDP == 0) {
! 476: slot = NUM_CQE - 1;
! 477: } else {
! 478: slot = mcsb->mcsb_QHDP - 1;
! 479: }
! 480: iopb = (M328_IOPB *)&sc->sc_vsreg->sh_IOPB[slot];
! 481: szero(iopb, sizeof(M328_IOPB));
! 482: return iopb;
! 483: }
! 484:
! 485: void
! 486: vs_initialize(sc)
! 487: struct vs_softc *sc;
! 488: {
! 489: M328_CIB *cib = (M328_CIB *)&sc->sc_vsreg->sh_CIB;
! 490: M328_CQE *mc = (M328_CQE*)&sc->sc_vsreg->sh_MCE;
! 491: M328_CRB *crb = (M328_CRB *)&sc->sc_vsreg->sh_CRB;
! 492: M328_IOPB *riopb = (M328_IOPB *)&sc->sc_vsreg->sh_RET_IOPB;
! 493: M328_MCSB *mcsb = (M328_MCSB *)&sc->sc_vsreg->sh_MCSB;
! 494: M328_IOPB *iopb;
! 495: M328_WQCF *wiopb = (M328_WQCF *)&sc->sc_vsreg->sh_MCE_IOPB;
! 496: u_short i, crsw;
! 497: int failed = 0;
! 498:
! 499: CRB_CLR_DONE(CRSW);
! 500: szero(cib, sizeof(M328_CIB));
! 501: mcsb->mcsb_QHDP = 0;
! 502: sc->sc_qhp = 0;
! 503: cib->cib_NCQE = 10;
! 504: cib->cib_BURST = 0;
! 505: cib->cib_NVECT = sc->sc_ipl << 8;
! 506: cib->cib_NVECT |= sc->sc_nvec;
! 507: cib->cib_EVECT = sc->sc_ipl << 8;
! 508: cib->cib_EVECT |= sc->sc_evec;
! 509: cib->cib_PID = 0x07;
! 510: cib->cib_SID = 0x00;
! 511: cib->cib_CRBO = OFF(crb);
! 512: cib->cib_SELECT_msw = HI(SELECTION_TIMEOUT);
! 513: cib->cib_SELECT_lsw = LO(SELECTION_TIMEOUT);
! 514: cib->cib_WQ0TIMO_msw = HI(4);
! 515: cib->cib_WQ0TIMO_lsw = LO(4);
! 516: cib->cib_VMETIMO_msw = 0; /*HI(VME_BUS_TIMEOUT);*/
! 517: cib->cib_VMETIMO_lsw = 0; /*LO(VME_BUS_TIMEOUT);*/
! 518: cib->cib_SBRIV = sc->sc_ipl << 8;
! 519: cib->cib_SBRIV |= sc->sc_evec;
! 520: cib->cib_SOF0 = 0x15;
! 521: cib->cib_SRATE0 = 100/4;
! 522: cib->cib_SOF1 = 0x0;
! 523: cib->cib_SRATE1 = 0x0;
! 524:
! 525: iopb = (M328_IOPB *)&sc->sc_vsreg->sh_MCE_IOPB;
! 526: szero(iopb, sizeof(M328_IOPB));
! 527: iopb->iopb_CMD = CNTR_INIT;
! 528: iopb->iopb_OPTION = 0;
! 529: iopb->iopb_NVCT = (u_char)sc->sc_nvec;
! 530: iopb->iopb_EVCT = (u_char)sc->sc_evec;
! 531: iopb->iopb_LEVEL = 0; /*sc->sc_ipl;*/
! 532: iopb->iopb_ADDR = SHIO_MOD;
! 533: LV(iopb->iopb_BUFF, OFF(cib));
! 534: LV(iopb->iopb_LENGTH, sizeof(M328_CIB));
! 535:
! 536: szero(mc, sizeof(M328_CQE));
! 537: mc->cqe_IOPB_ADDR = OFF(iopb);
! 538: mc->cqe_IOPB_LENGTH = sizeof(M328_IOPB);
! 539: mc->cqe_WORK_QUEUE = 0;
! 540: mc->cqe_QECR = M_QECR_GO;
! 541: /* poll for the command to complete */
! 542: do_vspoll(sc, 0, 1);
! 543: CRB_CLR_DONE(CRSW);
! 544:
! 545: /* initialize work queues */
! 546: for (i=1; i<8; i++) {
! 547: szero(wiopb, sizeof(M328_IOPB));
! 548: wiopb->wqcf_CMD = CNTR_INIT_WORKQ;
! 549: wiopb->wqcf_OPTION = 0;
! 550: wiopb->wqcf_NVCT = (u_char)sc->sc_nvec;
! 551: wiopb->wqcf_EVCT = (u_char)sc->sc_evec;
! 552: wiopb->wqcf_ILVL = 0; /*sc->sc_ipl;*/
! 553: wiopb->wqcf_WORKQ = i;
! 554: wiopb->wqcf_WOPT = (WQO_FOE | WQO_INIT);
! 555: wiopb->wqcf_SLOTS = JAGUAR_MAX_Q_SIZ;
! 556: LV(wiopb->wqcf_CMDTO, 2);
! 557:
! 558: szero(mc, sizeof(M328_CQE));
! 559: mc->cqe_IOPB_ADDR = OFF(wiopb);
! 560: mc->cqe_IOPB_LENGTH = sizeof(M328_IOPB);
! 561: mc->cqe_WORK_QUEUE = 0;
! 562: mc->cqe_QECR = M_QECR_GO;
! 563: /* poll for the command to complete */
! 564: do_vspoll(sc, 0, 1);
! 565: if (CRSW & M_CRSW_ER) {
! 566: /*printf("\nerror: queue %d status = 0x%x\n",
! 567: i, riopb->iopb_STATUS);*/
! 568: /*failed = 1;*/
! 569: CRB_CLR_ER(CRSW);
! 570: }
! 571: CRB_CLR_DONE(CRSW);
! 572: delay(500);
! 573: }
! 574: /* start queue mode */
! 575: CRSW = 0;
! 576: mcsb->mcsb_MCR |= M_MCR_SQM;
! 577: crsw = CRSW;
! 578: do_vspoll(sc, 0, 1);
! 579: if (CRSW & M_CRSW_ER) {
! 580: printf("error: status = 0x%x\n", riopb->iopb_STATUS);
! 581: CRB_CLR_ER(CRSW);
! 582: }
! 583: CRB_CLR_DONE(CRSW);
! 584:
! 585: if (failed) {
! 586: printf(": failed!\n");
! 587: return;
! 588: }
! 589: /* reset SCSI bus */
! 590: vs_reset(sc);
! 591: /* sync all devices */
! 592: vs_resync(sc);
! 593: printf(": target %d\n", sc->sc_link.adapter_target);
! 594: }
! 595:
! 596: void
! 597: vs_resync(sc)
! 598: struct vs_softc *sc;
! 599: {
! 600: M328_CQE *mc = (M328_CQE*)&sc->sc_vsreg->sh_MCE;
! 601: M328_IOPB *riopb = (M328_IOPB *)&sc->sc_vsreg->sh_RET_IOPB;
! 602: M328_DRCF *devreset = (M328_DRCF *)&sc->sc_vsreg->sh_MCE_IOPB;
! 603: u_short i;
! 604:
! 605: for (i=0; i<7; i++) {
! 606: szero(devreset, sizeof(M328_DRCF));
! 607: devreset->drcf_CMD = CNTR_DEV_REINIT;
! 608: devreset->drcf_OPTION = 0x00; /* no interrupts yet... */
! 609: devreset->drcf_NVCT = sc->sc_nvec;
! 610: devreset->drcf_EVCT = sc->sc_evec;
! 611: devreset->drcf_ILVL = 0;
! 612: devreset->drcf_UNIT = i;
! 613:
! 614: szero(mc, sizeof(M328_CQE));
! 615: mc->cqe_IOPB_ADDR = OFF(devreset);
! 616: mc->cqe_IOPB_LENGTH = sizeof(M328_DRCF);
! 617: mc->cqe_WORK_QUEUE = 0;
! 618: mc->cqe_QECR = M_QECR_GO;
! 619: /* poll for the command to complete */
! 620: do_vspoll(sc, 0, 0);
! 621: if (riopb->iopb_STATUS) {
! 622: sc->sc_tinfo[i].avail = 0;
! 623: } else {
! 624: sc->sc_tinfo[i].avail = 1;
! 625: }
! 626: if (CRSW & M_CRSW_ER) {
! 627: CRB_CLR_ER(CRSW);
! 628: }
! 629: CRB_CLR_DONE(CRSW);
! 630: }
! 631: }
! 632:
! 633: void
! 634: vs_reset(sc)
! 635: struct vs_softc *sc;
! 636: {
! 637: u_int s;
! 638: M328_CQE *mc = (M328_CQE*)&sc->sc_vsreg->sh_MCE;
! 639: M328_IOPB *riopb = (M328_IOPB *)&sc->sc_vsreg->sh_RET_IOPB;
! 640: M328_SRCF *reset = (M328_SRCF *)&sc->sc_vsreg->sh_MCE_IOPB;
! 641:
! 642: szero(reset, sizeof(M328_SRCF));
! 643: reset->srcf_CMD = IOPB_RESET;
! 644: reset->srcf_OPTION = 0x00; /* no interrupts yet... */
! 645: reset->srcf_NVCT = sc->sc_nvec;
! 646: reset->srcf_EVCT = sc->sc_evec;
! 647: reset->srcf_ILVL = 0;
! 648: reset->srcf_BUSID = 0;
! 649: s = splbio();
! 650:
! 651: szero(mc, sizeof(M328_CQE));
! 652: mc->cqe_IOPB_ADDR = OFF(reset);
! 653: mc->cqe_IOPB_LENGTH = sizeof(M328_SRCF);
! 654: mc->cqe_WORK_QUEUE = 0;
! 655: mc->cqe_QECR = M_QECR_GO;
! 656: /* poll for the command to complete */
! 657: for (;;) {
! 658: do_vspoll(sc, 0, 0);
! 659: /* ack & clear scsi error condition cause by reset */
! 660: if (CRSW & M_CRSW_ER) {
! 661: CRB_CLR_ER(CRSW);
! 662: CRB_CLR_DONE(CRSW);
! 663: riopb->iopb_STATUS = 0;
! 664: break;
! 665: }
! 666: CRB_CLR_DONE(CRSW);
! 667: }
! 668: /* thaw all work queues */
! 669: thaw_queue(sc, 0xFF);
! 670: splx(s);
! 671: }
! 672:
! 673: /*
! 674: * Process an interrupt from the MVME328
! 675: * We'll generally update: xs->{flags,resid,error,sense,status} and
! 676: * occasionally xs->retries.
! 677: */
! 678:
! 679: int
! 680: vs_checkintr(sc, xs, status)
! 681: struct vs_softc *sc;
! 682: struct scsi_xfer *xs;
! 683: int *status;
! 684: {
! 685: int target = -1;
! 686: int lun = -1;
! 687: M328_IOPB *riopb = (M328_IOPB *)&sc->sc_vsreg->sh_RET_IOPB;
! 688: struct scsi_generic *cmd;
! 689: u_long buf;
! 690: u_long len;
! 691: u_char error;
! 692:
! 693: target = xs->sc_link->target;
! 694: lun = xs->sc_link->lun;
! 695: cmd = (struct scsi_generic *)&riopb->iopb_SCSI[0];
! 696:
! 697: VL(buf, riopb->iopb_BUFF);
! 698: VL(len, riopb->iopb_LENGTH);
! 699: *status = riopb->iopb_STATUS >> 8;
! 700: error = riopb->iopb_STATUS & 0xFF;
! 701:
! 702: #ifdef SDEBUG
! 703: printf("scsi_chk() ");
! 704:
! 705: if (xs->cmd->opcode == 0) {
! 706: printf("TEST_UNIT_READY ");
! 707: } else if (xs->cmd->opcode == REQUEST_SENSE) {
! 708: printf("REQUEST_SENSE ");
! 709: } else if (xs->cmd->opcode == INQUIRY) {
! 710: printf("INQUIRY ");
! 711: } else if (xs->cmd->opcode == MODE_SELECT) {
! 712: printf("MODE_SELECT ");
! 713: } else if (xs->cmd->opcode == MODE_SENSE) {
! 714: printf("MODE_SENSE ");
! 715: } else if (xs->cmd->opcode == START_STOP) {
! 716: printf("START_STOP ");
! 717: } else if (xs->cmd->opcode == RESERVE) {
! 718: printf("RESERVE ");
! 719: } else if (xs->cmd->opcode == RELEASE) {
! 720: printf("RELEASE ");
! 721: } else if (xs->cmd->opcode == PREVENT_ALLOW) {
! 722: printf("PREVENT_ALLOW ");
! 723: } else if (xs->cmd->opcode == POSITION_TO_ELEMENT) {
! 724: printf("POSITION_TO_EL ");
! 725: } else if (xs->cmd->opcode == CHANGE_DEFINITION) {
! 726: printf("CHANGE_DEF ");
! 727: } else if (xs->cmd->opcode == MODE_SENSE_BIG) {
! 728: printf("MODE_SENSE_BIG ");
! 729: } else if (xs->cmd->opcode == MODE_SELECT_BIG) {
! 730: printf("MODE_SELECT_BIG ");
! 731: } else if (xs->cmd->opcode == 0x25) {
! 732: printf("READ_CAPACITY ");
! 733: } else if (xs->cmd->opcode == 0x08) {
! 734: printf("READ_COMMAND ");
! 735: }
! 736:
! 737: printf("tgt %d lun %d buf %x len %d status %x ",
! 738: target, lun, buf, len, riopb->iopb_STATUS);
! 739:
! 740: if (CRSW & M_CRSW_EX) {
! 741: printf("[ex]");
! 742: }
! 743: if (CRSW & M_CRSW_QMS) {
! 744: printf("[qms]");
! 745: }
! 746: if (CRSW & M_CRSW_SC) {
! 747: printf("[sc]");
! 748: }
! 749: if (CRSW & M_CRSW_SE) {
! 750: printf("[se]");
! 751: }
! 752: if (CRSW & M_CRSW_AQ) {
! 753: printf("[aq]");
! 754: }
! 755: if (CRSW & M_CRSW_ER) {
! 756: printf("[er]");
! 757: }
! 758: printf("\n");
! 759: #endif
! 760: if (len != xs->datalen) {
! 761: xs->resid = xs->datalen - len;
! 762: } else {
! 763: xs->resid = 0;
! 764: }
! 765:
! 766: if (error == SCSI_SELECTION_TO) {
! 767: xs->error = XS_SELTIMEOUT;
! 768: xs->status = -1;
! 769: *status = -1;
! 770: }
! 771: return 1;
! 772: }
! 773:
! 774: void
! 775: vs_intr(arg)
! 776: void *arg;
! 777: {
! 778: struct vs_softc *sc = (struct vs_softc *)arg;
! 779: M328_CRB *crb = (M328_CRB *)&sc->sc_vsreg->sh_CRB;
! 780: struct scsi_xfer *xs;
! 781: M328_CMD *m328_cmd;
! 782: unsigned long loc;
! 783: int status;
! 784: int s;
! 785:
! 786: s = splbio();
! 787: /* Got a valid interrupt on this device */
! 788:
! 789: VL(loc, crb->crb_CTAG);
! 790: #ifdef SDEBUG
! 791: printf("Interrupt!!! ");
! 792: printf("loc == 0x%x\n", loc);
! 793: #endif
! 794: /*
! 795: * If this is a controller error, there won't be a m328_cmd
! 796: * pointer in the CTAG field. Bad things happen if you try
! 797: * to point to address 0. Controller error should be handled
! 798: * in vsdma.c I'll change this soon - steve.
! 799: */
! 800: if (loc) {
! 801: m328_cmd = (M328_CMD *)loc;
! 802: xs = m328_cmd->xs;
! 803: if (m328_cmd->top_sg_list) {
! 804: vs_dealloc_scatter_gather(m328_cmd->top_sg_list);
! 805: m328_cmd->top_sg_list = (M328_SG)0;
! 806: }
! 807:
! 808: FREE(m328_cmd, M_DEVBUF); /* free the command tag */
! 809: if (vs_checkintr (sc, xs, &status)) {
! 810: vs_scsidone(xs, status);
! 811: }
! 812: }
! 813: splx(s);
! 814: }
! 815:
! 816: /*
! 817: * Useful functions for scatter/gather list
! 818: */
! 819:
! 820: M328_SG
! 821: vs_alloc_scatter_gather()
! 822: {
! 823: M328_SG sg;
! 824:
! 825: MALLOC(sg, M328_SG, sizeof(struct m328_sg), M_DEVBUF, M_WAITOK);
! 826: bzero(sg, sizeof(struct m328_sg));
! 827:
! 828: return (sg);
! 829: }
! 830:
! 831: void
! 832: vs_dealloc_scatter_gather(sg)
! 833: M328_SG sg;
! 834: {
! 835: int i;
! 836:
! 837: if (sg->level > 0) {
! 838: for (i = 0; sg->down[i] && i<MAX_SG_ELEMENTS; i++) {
! 839: vs_dealloc_scatter_gather(sg->down[i]);
! 840: }
! 841: }
! 842: FREE(sg, M_DEVBUF);
! 843: }
! 844:
! 845: void
! 846: vs_link_sg_element(element, phys_add, len)
! 847: sg_list_element_t *element;
! 848: vaddr_t phys_add;
! 849: int len;
! 850: {
! 851:
! 852: element->count.bytes = len;
! 853: LV(element->address, phys_add);
! 854: element->link = 0; /* FALSE */
! 855: element->transfer_type = NORMAL_TYPE;
! 856: element->memory_type = LONG_TRANSFER;
! 857: element->address_modifier = 0xD;
! 858: }
! 859:
! 860: void
! 861: vs_link_sg_list(list, phys_add, elements)
! 862: sg_list_element_t *list;
! 863: vaddr_t phys_add;
! 864: int elements;
! 865: {
! 866:
! 867: list->count.scatter.gather = elements;
! 868: LV(list->address, phys_add);
! 869: list->link = 1; /* TRUE */
! 870: list->transfer_type = NORMAL_TYPE;
! 871: list->memory_type = LONG_TRANSFER;
! 872: list->address_modifier = 0xD;
! 873: }
! 874:
! 875: M328_SG
! 876: vs_build_memory_structure(xs, iopb)
! 877: struct scsi_xfer *xs;
! 878: M328_IOPB *iopb; /* the iopb */
! 879: {
! 880: M328_SG sg;
! 881: vaddr_t starting_point_virt, point_virt, virt;
! 882: paddr_t starting_point_phys, point1_phys, point2_phys;
! 883: u_int len;
! 884: int level;
! 885:
! 886: sg = (M328_SG)0; /* Hopefully we need no scatter/gather list */
! 887:
! 888: /*
! 889: * We have the following things:
! 890: * virt the virtual address of the contiguous virtual
! 891: * memory block
! 892: * len the length of the contiguous virtual memory
! 893: * block
! 894: * starting_point_virt the virtual address of the contiguous
! 895: * *physical* memory block
! 896: * starting_point_phys the *physical* address of the contiguous
! 897: * *physical* memory block
! 898: * point_virt the pointer to the virtual memory we are
! 899: * checking at the moment
! 900: * point1_phys the pointer to the *physical* memory we are
! 901: * checking at the moment
! 902: * point2_phys the pointer to the *physical* memory we are
! 903: * checking at the moment
! 904: */
! 905:
! 906: level = 0;
! 907: virt = starting_point_virt = (vaddr_t)xs->data;
! 908: point1_phys = starting_point_phys = kvtop((vaddr_t)xs->data);
! 909: len = xs->datalen;
! 910:
! 911: /*
! 912: * Check if we need scatter/gather
! 913: */
! 914: if (len > PAGE_SIZE) {
! 915: for (level = 0, point_virt = round_page(starting_point_virt+1);
! 916: /* if we do already scatter/gather we have to stay in
! 917: the loop and jump */
! 918: point_virt < virt + (vaddr_t)len || sg;
! 919: point_virt += PAGE_SIZE) { /* out later */
! 920:
! 921: point2_phys = kvtop(point_virt);
! 922:
! 923: if ((point2_phys - trunc_page(point1_phys) - PAGE_SIZE) ||
! 924: /* physical memory is not contiguous */
! 925: (point_virt - starting_point_virt >=
! 926: MAX_SG_BLOCK_SIZE && sg)) {
! 927: /* we only can access (1<<16)-1 bytes in
! 928: scatter/gather_mode */
! 929: if (point_virt - starting_point_virt >=
! 930: MAX_SG_BLOCK_SIZE) {
! 931: /* We were walking too far for one
! 932: scatter/gather block ... */
! 933: assert( MAX_SG_BLOCK_SIZE > PAGE_SIZE );
! 934: point_virt =
! 935: trunc_page(starting_point_virt +
! 936: MAX_SG_BLOCK_SIZE-1);
! 937: /* So go back to the beginning of the
! 938: last matching page and generate the
! 939: physical address of this location
! 940: for the next time. */
! 941: point2_phys = kvtop(point_virt);
! 942: }
! 943:
! 944: if (!sg) {
! 945: /* We allocate our fist scatter/gather
! 946: list */
! 947: sg = vs_alloc_scatter_gather();
! 948: }
! 949: #if 1 /* broken firmware */
! 950: if (sg->elements >= MAX_SG_ELEMENTS) {
! 951: vs_dealloc_scatter_gather(sg);
! 952: return (NULL);
! 953: }
! 954: #else /* if the firmware will ever get fixed */
! 955: while (sg->elements >= MAX_SG_ELEMENTS) {
! 956: /* If the list full in this layer ? */
! 957: if (!sg->up) {
! 958: sg->up =
! 959: vs_alloc_scatter_gather();
! 960: sg->up->level = sg->level+1;
! 961: sg->up->down[0] = sg;
! 962: sg->up->elements = 1;
! 963: }
! 964: /* link this full list also in physical
! 965: memory */
! 966: vs_link_sg_list(
! 967: &(sg->up->list[
! 968: sg->up->elements - 1]),
! 969: kvtop((vaddr_t)sg->list),
! 970: sg->elements);
! 971: sg = sg->up; /* Climb up */
! 972: }
! 973: /* As long as we are not a the base level */
! 974: while (sg->level) {
! 975: int i;
! 976:
! 977: i = sg->elements;
! 978: /* We need a new element */
! 979: sg->down[i] =
! 980: vs_alloc_scatter_gather();
! 981: sg->down[i]->level = sg->level - 1;
! 982: sg->down[i]->up = sg;
! 983: sg->elements++;
! 984: sg = sg->down[i]; /* Climb down */
! 985: }
! 986: #endif /* 1 */
! 987:
! 988: if (point_virt < virt+(vaddr_t)len) {
! 989: /* linking element */
! 990: vs_link_sg_element(
! 991: &(sg->list[sg->elements]),
! 992: starting_point_phys,
! 993: point_virt-starting_point_virt);
! 994: sg->elements++;
! 995: } else {
! 996: /* linking last element */
! 997: vs_link_sg_element(
! 998: &(sg->list[sg->elements]),
! 999: starting_point_phys,
! 1000: (vaddr_t)(virt + len) -
! 1001: starting_point_virt);
! 1002: sg->elements++;
! 1003: break;
! 1004: /* We have now collected all blocks */
! 1005: }
! 1006: starting_point_virt = point_virt;
! 1007: starting_point_phys = point2_phys;
! 1008: }
! 1009: point1_phys = point2_phys;
! 1010: }
! 1011: }
! 1012:
! 1013: /*
! 1014: * Climb up along the right side of the tree until we reach the top.
! 1015: */
! 1016:
! 1017: if (sg) {
! 1018: while (sg->up) {
! 1019: /* link this list also in physical memory */
! 1020: vs_link_sg_list(&(sg->up->list[sg->up->elements-1]),
! 1021: kvtop((vaddr_t)sg->list), sg->elements);
! 1022: sg = sg->up; /* Climb up */
! 1023: }
! 1024:
! 1025: iopb->iopb_OPTION |= M_OPT_SG;
! 1026: iopb->iopb_ADDR |= M_ADR_SG_LINK;
! 1027: LV(iopb->iopb_BUFF, kvtop((vaddr_t)sg->list));
! 1028: LV(iopb->iopb_LENGTH, sg->elements);
! 1029: LV(iopb->iopb_SGTTL, len);
! 1030: } else {
! 1031: /* no scatter/gather necessary */
! 1032: LV(iopb->iopb_BUFF, starting_point_phys);
! 1033: LV(iopb->iopb_LENGTH, len);
! 1034: }
! 1035: return (sg);
! 1036: }
CVSweb