Annotation of sys/dev/isa/aha.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: aha.c,v 1.57 2007/08/15 02:04:30 krw Exp $ */
! 2: /* $NetBSD: aha.c,v 1.11 1996/05/12 23:51:23 mycroft Exp $ */
! 3:
! 4: #undef AHADIAG
! 5:
! 6: /*
! 7: * Copyright (c) 1994, 1996 Charles M. Hannum. All rights reserved.
! 8: *
! 9: * Redistribution and use in source and binary forms, with or without
! 10: * modification, are permitted provided that the following conditions
! 11: * are met:
! 12: * 1. Redistributions of source code must retain the above copyright
! 13: * notice, this list of conditions and the following disclaimer.
! 14: * 2. Redistributions in binary form must reproduce the above copyright
! 15: * notice, this list of conditions and the following disclaimer in the
! 16: * documentation and/or other materials provided with the distribution.
! 17: * 3. All advertising materials mentioning features or use of this software
! 18: * must display the following acknowledgement:
! 19: * This product includes software developed by Charles M. Hannum.
! 20: * 4. The name of the author may not be used to endorse or promote products
! 21: * derived from this software without specific prior written permission.
! 22: *
! 23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 25: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 26: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 27: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 28: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 29: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 30: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 31: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 32: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 33: */
! 34:
! 35: /*
! 36: * Originally written by Julian Elischer (julian@tfs.com)
! 37: * for TRW Financial Systems for use under the MACH(2.5) operating system.
! 38: *
! 39: * TRW Financial Systems, in accordance with their agreement with Carnegie
! 40: * Mellon University, makes this software available to CMU to distribute
! 41: * or use in any manner that they see fit as long as this message is kept with
! 42: * the software. For this reason TFS also grants any other persons or
! 43: * organisations permission to use or modify this software.
! 44: *
! 45: * TFS supplies this software to be publicly redistributed
! 46: * on the understanding that TFS is not responsible for the correct
! 47: * functioning of this software in any circumstances.
! 48: */
! 49:
! 50: #include <sys/types.h>
! 51: #include <sys/param.h>
! 52: #include <sys/systm.h>
! 53: #include <sys/kernel.h>
! 54: #include <sys/errno.h>
! 55: #include <sys/ioctl.h>
! 56: #include <sys/device.h>
! 57: #include <sys/malloc.h>
! 58: #include <sys/buf.h>
! 59: #include <sys/proc.h>
! 60: #include <sys/user.h>
! 61: #include <sys/timeout.h>
! 62:
! 63: #include <uvm/uvm.h>
! 64: #include <uvm/uvm_extern.h>
! 65:
! 66: #include <machine/intr.h>
! 67: #include <machine/bus.h>
! 68:
! 69: #include <scsi/scsi_all.h>
! 70: #include <scsi/scsiconf.h>
! 71:
! 72: #include <dev/isa/isavar.h>
! 73: #include <dev/isa/isadmavar.h>
! 74: #include <dev/isa/ahareg.h>
! 75:
! 76: #ifndef DDB
! 77: #define Debugger() panic("should call debugger here (aha1542.c)")
! 78: #endif /* ! DDB */
! 79:
! 80: /* XXX fixme:
! 81: * on i386 at least, xfers to/from user memory
! 82: * cannot be serviced at interrupt time.
! 83: */
! 84: #ifdef i386
! 85: #define VOLATILE_XS(xs) \
! 86: ((xs)->datalen > 0 && (xs)->bp == NULL && \
! 87: ((xs)->flags & SCSI_POLL) == 0)
! 88: #else
! 89: #define VOLATILE_XS(xs) 0
! 90: #endif
! 91:
! 92: /*
! 93: * Mail box defs etc.
! 94: * these could be bigger but we need the aha_softc to fit on a single page..
! 95: */
! 96: #define AHA_MBX_SIZE 16 /* mail box size */
! 97:
! 98: #define AHA_CCB_MAX 16 /* store up to 32 CCBs at one time */
! 99: #define CCB_HASH_SIZE 16 /* hash table size for phystokv */
! 100: #define CCB_HASH_SHIFT 9
! 101: #define CCB_HASH(x) ((((long)(x))>>CCB_HASH_SHIFT) & (CCB_HASH_SIZE - 1))
! 102:
! 103: #define aha_nextmbx(wmb, mbx, mbio) \
! 104: if ((wmb) == &(mbx)->mbio[AHA_MBX_SIZE - 1]) \
! 105: (wmb) = &(mbx)->mbio[0]; \
! 106: else \
! 107: (wmb)++;
! 108:
! 109: struct aha_mbx {
! 110: struct aha_mbx_out mbo[AHA_MBX_SIZE];
! 111: struct aha_mbx_in mbi[AHA_MBX_SIZE];
! 112: struct aha_mbx_out *cmbo; /* Collection Mail Box out */
! 113: struct aha_mbx_out *tmbo; /* Target Mail Box out */
! 114: struct aha_mbx_in *tmbi; /* Target Mail Box in */
! 115: };
! 116:
! 117: struct aha_softc {
! 118: struct device sc_dev;
! 119: struct isadev sc_id;
! 120: void *sc_ih;
! 121: bus_dma_tag_t sc_dmat;
! 122:
! 123: int sc_iobase;
! 124: int sc_irq, sc_drq;
! 125:
! 126: char sc_model[18],
! 127: sc_firmware[4];
! 128:
! 129: struct aha_mbx *sc_mbx; /* all the mailboxes */
! 130: #define wmbx (sc->sc_mbx)
! 131: struct aha_ccb *sc_ccbhash[CCB_HASH_SIZE];
! 132: TAILQ_HEAD(, aha_ccb) sc_free_ccb, sc_waiting_ccb;
! 133: int sc_numccbs, sc_mbofull;
! 134: int sc_scsi_dev; /* our scsi id */
! 135: struct scsi_link sc_link;
! 136: };
! 137:
! 138: #ifdef AHADEBUG
! 139: int aha_debug = 1;
! 140: #endif /* AHADEBUG */
! 141:
! 142: int aha_cmd(int, struct aha_softc *, int, u_char *, int, u_char *);
! 143: void aha_finish_ccbs(struct aha_softc *);
! 144: int ahaintr(void *);
! 145: void aha_reset_ccb(struct aha_softc *, struct aha_ccb *);
! 146: void aha_free_ccb(struct aha_softc *, struct aha_ccb *);
! 147: int aha_init_ccb(struct aha_softc *, struct aha_ccb *, int);
! 148: struct aha_ccb *aha_get_ccb(struct aha_softc *, int);
! 149: struct aha_ccb *aha_ccb_phys_kv(struct aha_softc *, u_long);
! 150: void aha_queue_ccb(struct aha_softc *, struct aha_ccb *);
! 151: void aha_collect_mbo(struct aha_softc *);
! 152: void aha_start_ccbs(struct aha_softc *);
! 153: void aha_done(struct aha_softc *, struct aha_ccb *);
! 154: int aha_find(struct isa_attach_args *, struct aha_softc *, int);
! 155: void aha_init(struct aha_softc *);
! 156: void aha_inquire_setup_information(struct aha_softc *);
! 157: void ahaminphys(struct buf *);
! 158: int aha_scsi_cmd(struct scsi_xfer *);
! 159: int aha_poll(struct aha_softc *, struct scsi_xfer *, int);
! 160: void aha_timeout(void *arg);
! 161:
! 162: struct scsi_adapter aha_switch = {
! 163: aha_scsi_cmd,
! 164: ahaminphys,
! 165: 0,
! 166: 0,
! 167: };
! 168:
! 169: /* the below structure is so we have a default dev struct for out link struct */
! 170: struct scsi_device aha_dev = {
! 171: NULL, /* Use default error handler */
! 172: NULL, /* have a queue, served by this */
! 173: NULL, /* have no async handler */
! 174: NULL, /* Use default 'done' routine */
! 175: };
! 176:
! 177: int aha_isapnp_probe(struct device *, void *, void *);
! 178: int ahaprobe(struct device *, void *, void *);
! 179: void ahaattach(struct device *, struct device *, void *);
! 180:
! 181: struct cfattach aha_isapnp_ca = {
! 182: sizeof(struct aha_softc), aha_isapnp_probe, ahaattach
! 183: };
! 184:
! 185: struct cfattach aha_isa_ca = {
! 186: sizeof(struct aha_softc), ahaprobe, ahaattach
! 187: };
! 188:
! 189: struct cfdriver aha_cd = {
! 190: NULL, "aha", DV_DULL
! 191: };
! 192:
! 193: #define AHA_RESET_TIMEOUT 2000 /* time to wait for reset (mSec) */
! 194: #define AHA_ABORT_TIMEOUT 2000 /* time to wait for abort (mSec) */
! 195:
! 196: #include "bha.h"
! 197:
! 198: /*
! 199: * aha_cmd(iobase, sc, icnt, ibuf, ocnt, obuf)
! 200: *
! 201: * Activate Adapter command
! 202: * icnt: number of args (outbound bytes including opcode)
! 203: * ibuf: argument buffer
! 204: * ocnt: number of expected returned bytes
! 205: * obuf: result buffer
! 206: * wait: number of seconds to wait for response
! 207: *
! 208: * Performs an adapter command through the ports. Not to be confused with a
! 209: * scsi command, which is read in via the dma; one of the adapter commands
! 210: * tells it to read in a scsi command.
! 211: */
! 212: int
! 213: aha_cmd(iobase, sc, icnt, ibuf, ocnt, obuf)
! 214: int iobase;
! 215: struct aha_softc *sc;
! 216: int icnt, ocnt;
! 217: u_char *ibuf, *obuf;
! 218: {
! 219: const char *name;
! 220: register int i;
! 221: int wait;
! 222: u_char sts;
! 223: u_char opcode = ibuf[0];
! 224:
! 225: if (sc != NULL)
! 226: name = sc->sc_dev.dv_xname;
! 227: else
! 228: name = "(aha probe)";
! 229:
! 230: /*
! 231: * Calculate a reasonable timeout for the command.
! 232: */
! 233: switch (opcode) {
! 234: case AHA_INQUIRE_DEVICES:
! 235: wait = 15 * 20000;
! 236: break;
! 237: default:
! 238: wait = 1 * 20000;
! 239: break;
! 240: }
! 241:
! 242: /*
! 243: * Wait for the adapter to go idle, unless it's one of
! 244: * the commands which don't need this
! 245: */
! 246: if (opcode != AHA_MBO_INTR_EN) {
! 247: for (i = 20000; i; i--) { /* 1 sec? */
! 248: sts = inb(iobase + AHA_STAT_PORT);
! 249: if (sts & AHA_STAT_IDLE)
! 250: break;
! 251: delay(50);
! 252: }
! 253: if (!i) {
! 254: printf("%s: aha_cmd, host not idle(0x%x)\n",
! 255: name, sts);
! 256: return (ENXIO);
! 257: }
! 258: }
! 259: /*
! 260: * Now that it is idle, if we expect output, preflush the
! 261: * queue feeding to us.
! 262: */
! 263: if (ocnt) {
! 264: while ((inb(iobase + AHA_STAT_PORT)) & AHA_STAT_DF)
! 265: inb(iobase + AHA_DATA_PORT);
! 266: }
! 267: /*
! 268: * Output the command and the number of arguments given
! 269: * for each byte, first check the port is empty.
! 270: */
! 271: while (icnt--) {
! 272: for (i = wait; i; i--) {
! 273: sts = inb(iobase + AHA_STAT_PORT);
! 274: if (!(sts & AHA_STAT_CDF))
! 275: break;
! 276: delay(50);
! 277: }
! 278: if (!i) {
! 279: if (opcode != AHA_INQUIRE_REVISION)
! 280: printf("%s: aha_cmd, cmd/data port full\n",
! 281: name);
! 282: outb(iobase + AHA_CTRL_PORT, AHA_CTRL_SRST);
! 283: return (ENXIO);
! 284: }
! 285: outb(iobase + AHA_CMD_PORT, *ibuf++);
! 286: }
! 287: /*
! 288: * If we expect input, loop that many times, each time,
! 289: * looking for the data register to have valid data
! 290: */
! 291: while (ocnt--) {
! 292: for (i = wait; i; i--) {
! 293: sts = inb(iobase + AHA_STAT_PORT);
! 294: if (sts & AHA_STAT_DF)
! 295: break;
! 296: delay(50);
! 297: }
! 298: if (!i) {
! 299: if (opcode != AHA_INQUIRE_REVISION)
! 300: printf("%s: aha_cmd, cmd/data port empty %d\n",
! 301: name, ocnt);
! 302: outb(iobase + AHA_CTRL_PORT, AHA_CTRL_SRST);
! 303: return (ENXIO);
! 304: }
! 305: *obuf++ = inb(iobase + AHA_DATA_PORT);
! 306: }
! 307: /*
! 308: * Wait for the board to report a finished instruction.
! 309: * We may get an extra interrupt for the HACC signal, but this is
! 310: * unimportant.
! 311: */
! 312: if (opcode != AHA_MBO_INTR_EN) {
! 313: for (i = 20000; i; i--) { /* 1 sec? */
! 314: sts = inb(iobase + AHA_INTR_PORT);
! 315: /* XXX Need to save this in the interrupt handler? */
! 316: if (sts & AHA_INTR_HACC)
! 317: break;
! 318: delay(50);
! 319: }
! 320: if (!i) {
! 321: printf("%s: aha_cmd, host not finished(0x%x)\n",
! 322: name, sts);
! 323: return (ENXIO);
! 324: }
! 325: }
! 326: outb(iobase + AHA_CTRL_PORT, AHA_CTRL_IRST);
! 327: return (0);
! 328: }
! 329:
! 330: int
! 331: aha_isapnp_probe(parent, match, aux)
! 332: struct device *parent;
! 333: void *match, *aux;
! 334: {
! 335: return (1);
! 336: }
! 337:
! 338:
! 339: /*
! 340: * Check if the device can be found at the port given
! 341: * and if so, set it up ready for further work
! 342: * as an argument, takes the isa_device structure from
! 343: * autoconf.c
! 344: */
! 345: int
! 346: ahaprobe(parent, match, aux)
! 347: struct device *parent;
! 348: void *match, *aux;
! 349: {
! 350: register struct isa_attach_args *ia = aux;
! 351: #if NBHA > 0
! 352: extern int btports[], nbtports;
! 353: int i;
! 354:
! 355: for (i = 0; i < nbtports; i++)
! 356: if (btports[i] == ia->ia_iobase)
! 357: return (0);
! 358: #endif
! 359:
! 360: /* See if there is a unit at this location. */
! 361: if (aha_find(ia, NULL, 0) != 0)
! 362: return (0);
! 363:
! 364: ia->ia_msize = 0;
! 365: ia->ia_iosize = 4;
! 366: /* IRQ and DRQ set by aha_find(). */
! 367: return (1);
! 368: }
! 369:
! 370: /*
! 371: * Attach all the sub-devices we can find
! 372: */
! 373: void
! 374: ahaattach(parent, self, aux)
! 375: struct device *parent, *self;
! 376: void *aux;
! 377: {
! 378: struct isa_attach_args *ia = aux;
! 379: struct aha_softc *sc = (void *)self;
! 380: struct scsibus_attach_args saa;
! 381: int isapnp = !strcmp(parent->dv_cfdata->cf_driver->cd_name, "isapnp");
! 382:
! 383: if (isapnp) {
! 384: ia->ia_iobase = ia->ipa_io[0].base;
! 385: isadma_cascade(ia->ia_drq);
! 386: }
! 387:
! 388: if (aha_find(ia, sc, isapnp) != 0)
! 389: panic("ahaattach: aha_find of %s failed", self->dv_xname);
! 390: sc->sc_iobase = ia->ia_iobase;
! 391: sc->sc_dmat = ia->ia_dmat;
! 392:
! 393: if (sc->sc_drq != DRQUNK && isapnp == 0)
! 394: isadma_cascade(sc->sc_drq);
! 395:
! 396: aha_inquire_setup_information(sc);
! 397: aha_init(sc);
! 398: TAILQ_INIT(&sc->sc_free_ccb);
! 399: TAILQ_INIT(&sc->sc_waiting_ccb);
! 400:
! 401: /*
! 402: * fill in the prototype scsi_link.
! 403: */
! 404: sc->sc_link.adapter_softc = sc;
! 405: sc->sc_link.adapter_target = sc->sc_scsi_dev;
! 406: sc->sc_link.adapter = &aha_switch;
! 407: sc->sc_link.device = &aha_dev;
! 408: sc->sc_link.openings = 2;
! 409:
! 410: bzero(&saa, sizeof(saa));
! 411: saa.saa_sc_link = &sc->sc_link;
! 412:
! 413: sc->sc_ih = isa_intr_establish(ia->ia_ic, sc->sc_irq, IST_EDGE,
! 414: IPL_BIO, ahaintr, sc, sc->sc_dev.dv_xname);
! 415:
! 416: /*
! 417: * ask the adapter what subunits are present
! 418: */
! 419: config_found(self, &saa, scsiprint);
! 420: }
! 421:
! 422: void
! 423: aha_finish_ccbs(sc)
! 424: struct aha_softc *sc;
! 425: {
! 426: struct aha_mbx_in *wmbi;
! 427: struct aha_ccb *ccb;
! 428: int i;
! 429:
! 430: wmbi = wmbx->tmbi;
! 431:
! 432: if (wmbi->stat == AHA_MBI_FREE) {
! 433: for (i = 0; i < AHA_MBX_SIZE; i++) {
! 434: if (wmbi->stat != AHA_MBI_FREE) {
! 435: printf("%s: mbi not in round-robin order\n",
! 436: sc->sc_dev.dv_xname);
! 437: goto AGAIN;
! 438: }
! 439: aha_nextmbx(wmbi, wmbx, mbi);
! 440: }
! 441: #ifdef AHADIAGnot
! 442: printf("%s: mbi interrupt with no full mailboxes\n",
! 443: sc->sc_dev.dv_xname);
! 444: #endif
! 445: return;
! 446: }
! 447:
! 448: AGAIN:
! 449: do {
! 450: ccb = aha_ccb_phys_kv(sc, phystol(wmbi->ccb_addr));
! 451: if (!ccb) {
! 452: printf("%s: bad mbi ccb pointer; skipping\n",
! 453: sc->sc_dev.dv_xname);
! 454: goto next;
! 455: }
! 456:
! 457: #ifdef AHADEBUG
! 458: if (aha_debug) {
! 459: u_char *cp = (u_char *)&ccb->scsi_cmd;
! 460: printf("op=%x %x %x %x %x %x\n",
! 461: cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
! 462: printf("stat %x for mbi addr = 0x%08x, ",
! 463: wmbi->stat, wmbi);
! 464: printf("ccb addr = 0x%x\n", ccb);
! 465: }
! 466: #endif /* AHADEBUG */
! 467:
! 468: switch (wmbi->stat) {
! 469: case AHA_MBI_OK:
! 470: case AHA_MBI_ERROR:
! 471: if ((ccb->flags & CCB_ABORT) != 0) {
! 472: /*
! 473: * If we already started an abort, wait for it
! 474: * to complete before clearing the CCB. We
! 475: * could instead just clear CCB_SENDING, but
! 476: * what if the mailbox was already received?
! 477: * The worst that happens here is that we clear
! 478: * the CCB a bit later than we need to. BFD.
! 479: */
! 480: goto next;
! 481: }
! 482: break;
! 483:
! 484: case AHA_MBI_ABORT:
! 485: case AHA_MBI_UNKNOWN:
! 486: /*
! 487: * Even if the CCB wasn't found, we clear it anyway.
! 488: * See preceding comment.
! 489: */
! 490: break;
! 491:
! 492: default:
! 493: printf("%s: bad mbi status %02x; skipping\n",
! 494: sc->sc_dev.dv_xname, wmbi->stat);
! 495: goto next;
! 496: }
! 497:
! 498: if ((ccb->xs->flags & SCSI_POLL) == 0)
! 499: timeout_del(&ccb->xs->stimeout);
! 500: bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmam, 0,
! 501: ccb->ccb_dmam->dm_mapsize, BUS_DMASYNC_POSTREAD);
! 502: aha_done(sc, ccb);
! 503:
! 504: next:
! 505: wmbi->stat = AHA_MBI_FREE;
! 506: aha_nextmbx(wmbi, wmbx, mbi);
! 507: } while (wmbi->stat != AHA_MBI_FREE);
! 508:
! 509: wmbx->tmbi = wmbi;
! 510: }
! 511:
! 512: /*
! 513: * Catch an interrupt from the adaptor
! 514: */
! 515: int
! 516: ahaintr(arg)
! 517: void *arg;
! 518: {
! 519: struct aha_softc *sc = arg;
! 520: int iobase = sc->sc_iobase;
! 521: u_char sts;
! 522:
! 523: #ifdef AHADEBUG
! 524: if (aha_debug)
! 525: printf("%s: ahaintr ", sc->sc_dev.dv_xname);
! 526: #endif /*AHADEBUG */
! 527:
! 528: /*
! 529: * First acknowlege the interrupt, Then if it's not telling about
! 530: * a completed operation just return.
! 531: */
! 532: sts = inb(iobase + AHA_INTR_PORT);
! 533: if ((sts & AHA_INTR_ANYINTR) == 0)
! 534: return (0);
! 535: outb(iobase + AHA_CTRL_PORT, AHA_CTRL_IRST);
! 536:
! 537: #ifdef AHADIAG
! 538: /* Make sure we clear CCB_SENDING before finishing a CCB. */
! 539: aha_collect_mbo(sc);
! 540: #endif
! 541:
! 542: /* Mail box out empty? */
! 543: if (sts & AHA_INTR_MBOA) {
! 544: struct aha_toggle toggle;
! 545:
! 546: toggle.cmd.opcode = AHA_MBO_INTR_EN;
! 547: toggle.cmd.enable = 0;
! 548: aha_cmd(iobase, sc, sizeof(toggle.cmd), (u_char *)&toggle.cmd,
! 549: 0, (u_char *)0);
! 550: aha_start_ccbs(sc);
! 551: }
! 552:
! 553: /* Mail box in full? */
! 554: if (sts & AHA_INTR_MBIF)
! 555: aha_finish_ccbs(sc);
! 556:
! 557: return (1);
! 558: }
! 559:
! 560: void
! 561: aha_reset_ccb(sc, ccb)
! 562: struct aha_softc *sc;
! 563: struct aha_ccb *ccb;
! 564: {
! 565:
! 566: ccb->flags = 0;
! 567: }
! 568:
! 569: /*
! 570: * A ccb is put onto the free list.
! 571: */
! 572: void
! 573: aha_free_ccb(sc, ccb)
! 574: struct aha_softc *sc;
! 575: struct aha_ccb *ccb;
! 576: {
! 577: int s, hashnum;
! 578: struct aha_ccb **hashccb;
! 579:
! 580: s = splbio();
! 581:
! 582: if (ccb->ccb_dmam->dm_segs[0].ds_addr != 0)
! 583: bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmam);
! 584:
! 585: /* remove from hash table */
! 586:
! 587: hashnum = CCB_HASH(ccb->ccb_dmam->dm_segs[0].ds_addr);
! 588: hashccb = &sc->sc_ccbhash[hashnum];
! 589:
! 590: while (*hashccb) {
! 591: if ((*hashccb)->ccb_dmam->dm_segs[0].ds_addr ==
! 592: ccb->ccb_dmam->dm_segs[0].ds_addr) {
! 593: *hashccb = (*hashccb)->nexthash;
! 594: break;
! 595: }
! 596: hashccb = &(*hashccb)->nexthash;
! 597: }
! 598:
! 599: aha_reset_ccb(sc, ccb);
! 600: TAILQ_INSERT_HEAD(&sc->sc_free_ccb, ccb, chain);
! 601:
! 602: /*
! 603: * If there were none, wake anybody waiting for one to come free,
! 604: * starting with queued entries.
! 605: */
! 606: if (TAILQ_NEXT(ccb, chain) == NULL)
! 607: wakeup(&sc->sc_free_ccb);
! 608:
! 609: splx(s);
! 610: }
! 611:
! 612: int
! 613: aha_init_ccb(sc, ccb, flags)
! 614: struct aha_softc *sc;
! 615: struct aha_ccb *ccb;
! 616: int flags;
! 617: {
! 618: int error, wait, state = 0;
! 619:
! 620: bzero(ccb, sizeof(struct aha_ccb));
! 621: aha_reset_ccb(sc, ccb);
! 622:
! 623: wait = (flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK;
! 624: /* Create a DMA map for the data area. */
! 625: error = bus_dmamap_create(sc->sc_dmat, MAXPHYS, (MAXPHYS / NBPG) + 1,
! 626: MAXPHYS, 0, wait | BUS_DMA_ALLOCNOW, &ccb->dmam);
! 627: if (error)
! 628: goto fail;
! 629: state++;
! 630:
! 631: /* Create a DMA map for the command control block. */
! 632: error = bus_dmamap_create(sc->sc_dmat, CCB_PHYS_SIZE, 1, CCB_PHYS_SIZE,
! 633: 0, wait | BUS_DMA_ALLOCNOW, &ccb->ccb_dmam);
! 634: if (error)
! 635: goto fail;
! 636:
! 637: return (0);
! 638:
! 639: fail:
! 640: if (state > 0)
! 641: bus_dmamap_destroy(sc->sc_dmat, ccb->dmam);
! 642: return (error);
! 643: }
! 644:
! 645: /*
! 646: * Get a free ccb
! 647: *
! 648: * If there are none, see if we can allocate a new one. If so, put it in
! 649: * the hash table too otherwise either return an error or sleep.
! 650: */
! 651: struct aha_ccb *
! 652: aha_get_ccb(sc, flags)
! 653: struct aha_softc *sc;
! 654: int flags;
! 655: {
! 656: struct aha_ccb *ccb;
! 657: int hashnum, s;
! 658:
! 659: s = splbio();
! 660:
! 661: /*
! 662: * If we can and have to, sleep waiting for one to come free
! 663: * but only if we can't allocate a new one.
! 664: */
! 665: for (;;) {
! 666: ccb = TAILQ_FIRST(&sc->sc_free_ccb);
! 667: if (ccb) {
! 668: TAILQ_REMOVE(&sc->sc_free_ccb, ccb, chain);
! 669: break;
! 670: }
! 671: if (sc->sc_numccbs < AHA_CCB_MAX) {
! 672: MALLOC(ccb, struct aha_ccb *, sizeof *ccb, M_DEVBUF,
! 673: (flags & SCSI_NOSLEEP) ? M_NOWAIT : M_WAITOK);
! 674: if (ccb == NULL) {
! 675: printf("%s: can't malloc ccb\n",
! 676: sc->sc_dev.dv_xname);
! 677: goto out;
! 678: }
! 679: if (aha_init_ccb(sc, ccb, flags) == 0) {
! 680: sc->sc_numccbs++;
! 681: break;
! 682: }
! 683: FREE(ccb, M_DEVBUF);
! 684: ccb = NULL;
! 685: }
! 686: if (flags & SCSI_NOSLEEP)
! 687: goto out;
! 688: tsleep(&sc->sc_free_ccb, PRIBIO, "ahaccb", 0);
! 689: }
! 690:
! 691: ccb->flags |= CCB_ALLOC;
! 692:
! 693: if (bus_dmamap_load(sc->sc_dmat, ccb->ccb_dmam, ccb, CCB_PHYS_SIZE,
! 694: NULL, BUS_DMA_NOWAIT) != 0) {
! 695: aha_free_ccb(sc, ccb);
! 696: ccb = NULL;
! 697: } else {
! 698: hashnum = CCB_HASH(ccb->ccb_dmam->dm_segs[0].ds_addr);
! 699: ccb->nexthash = sc->sc_ccbhash[hashnum];
! 700: sc->sc_ccbhash[hashnum] = ccb;
! 701: }
! 702: out:
! 703: splx(s);
! 704: return (ccb);
! 705: }
! 706:
! 707: /*
! 708: * Given a physical address, find the ccb that it corresponds to.
! 709: */
! 710: struct aha_ccb *
! 711: aha_ccb_phys_kv(sc, ccb_phys)
! 712: struct aha_softc *sc;
! 713: u_long ccb_phys;
! 714: {
! 715: int hashnum = CCB_HASH(ccb_phys);
! 716: struct aha_ccb *ccb = sc->sc_ccbhash[hashnum];
! 717:
! 718: while (ccb) {
! 719: if (ccb->ccb_dmam->dm_segs[0].ds_addr == ccb_phys)
! 720: break;
! 721: ccb = ccb->nexthash;
! 722: }
! 723: return (ccb);
! 724: }
! 725:
! 726: /*
! 727: * Queue a CCB to be sent to the controller, and send it if possible.
! 728: */
! 729: void
! 730: aha_queue_ccb(sc, ccb)
! 731: struct aha_softc *sc;
! 732: struct aha_ccb *ccb;
! 733: {
! 734:
! 735: TAILQ_INSERT_TAIL(&sc->sc_waiting_ccb, ccb, chain);
! 736: aha_start_ccbs(sc);
! 737: }
! 738:
! 739: /*
! 740: * Garbage collect mailboxes that are no longer in use.
! 741: */
! 742: void
! 743: aha_collect_mbo(sc)
! 744: struct aha_softc *sc;
! 745: {
! 746: struct aha_mbx_out *wmbo; /* Mail Box Out pointer */
! 747: #ifdef AHADIAG
! 748: struct aha_ccb *ccb;
! 749: #endif
! 750:
! 751: wmbo = wmbx->cmbo;
! 752:
! 753: while (sc->sc_mbofull > 0) {
! 754: if (wmbo->cmd != AHA_MBO_FREE)
! 755: break;
! 756:
! 757: #ifdef AHADIAG
! 758: ccb = aha_ccb_phys_kv(sc, phystol(wmbo->ccb_addr));
! 759: if (!ccb) {
! 760: printf("%s: bad mbo ccb pointer; skipping\n",
! 761: sc->sc_dev.dv_xname);
! 762: } else
! 763: ccb->flags &= ~CCB_SENDING;
! 764: #endif
! 765:
! 766: --sc->sc_mbofull;
! 767: aha_nextmbx(wmbo, wmbx, mbo);
! 768: }
! 769:
! 770: wmbx->cmbo = wmbo;
! 771: }
! 772:
! 773: /*
! 774: * Send as many CCBs as we have empty mailboxes for.
! 775: */
! 776: void
! 777: aha_start_ccbs(sc)
! 778: struct aha_softc *sc;
! 779: {
! 780: int iobase = sc->sc_iobase;
! 781: struct aha_mbx_out *wmbo; /* Mail Box Out pointer */
! 782: struct aha_ccb *ccb;
! 783:
! 784: wmbo = wmbx->tmbo;
! 785:
! 786: while ((ccb = TAILQ_FIRST(&sc->sc_waiting_ccb)) != NULL) {
! 787: if (sc->sc_mbofull >= AHA_MBX_SIZE) {
! 788: aha_collect_mbo(sc);
! 789: if (sc->sc_mbofull >= AHA_MBX_SIZE) {
! 790: struct aha_toggle toggle;
! 791:
! 792: toggle.cmd.opcode = AHA_MBO_INTR_EN;
! 793: toggle.cmd.enable = 1;
! 794: aha_cmd(iobase, sc, sizeof(toggle.cmd),
! 795: (u_char *)&toggle.cmd, 0, (u_char *)0);
! 796: break;
! 797: }
! 798: }
! 799:
! 800: TAILQ_REMOVE(&sc->sc_waiting_ccb, ccb, chain);
! 801: #ifdef AHADIAG
! 802: ccb->flags |= CCB_SENDING;
! 803: #endif
! 804:
! 805: /* Link ccb to mbo. */
! 806: bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmam, 0,
! 807: ccb->ccb_dmam->dm_mapsize, BUS_DMASYNC_PREWRITE);
! 808: ltophys(ccb->ccb_dmam->dm_segs[0].ds_addr, wmbo->ccb_addr);
! 809: if (ccb->flags & CCB_ABORT)
! 810: wmbo->cmd = AHA_MBO_ABORT;
! 811: else
! 812: wmbo->cmd = AHA_MBO_START;
! 813:
! 814: /* Tell the card to poll immediately. */
! 815: outb(iobase + AHA_CMD_PORT, AHA_START_SCSI);
! 816:
! 817: if ((ccb->xs->flags & SCSI_POLL) == 0) {
! 818: timeout_set(&ccb->xs->stimeout, aha_timeout, ccb);
! 819: timeout_add(&ccb->xs->stimeout, (ccb->timeout * hz) / 1000);
! 820: }
! 821:
! 822: ++sc->sc_mbofull;
! 823: aha_nextmbx(wmbo, wmbx, mbo);
! 824: }
! 825:
! 826: wmbx->tmbo = wmbo;
! 827: }
! 828:
! 829: /*
! 830: * We have a ccb which has been processed by the
! 831: * adaptor, now we look to see how the operation
! 832: * went. Wake up the owner if waiting
! 833: */
! 834: void
! 835: aha_done(sc, ccb)
! 836: struct aha_softc *sc;
! 837: struct aha_ccb *ccb;
! 838: {
! 839: struct scsi_sense_data *s1, *s2;
! 840: struct scsi_xfer *xs = ccb->xs;
! 841:
! 842: SC_DEBUG(xs->sc_link, SDEV_DB2, ("aha_done\n"));
! 843: /*
! 844: * Otherwise, put the results of the operation
! 845: * into the xfer and call whoever started it
! 846: */
! 847: #ifdef AHADIAG
! 848: if (ccb->flags & CCB_SENDING) {
! 849: printf("%s: exiting ccb still in transit!\n",
! 850: sc->sc_dev.dv_xname);
! 851: Debugger();
! 852: return;
! 853: }
! 854: #endif
! 855: if ((ccb->flags & CCB_ALLOC) == 0) {
! 856: printf("%s: exiting ccb not allocated!\n",
! 857: sc->sc_dev.dv_xname);
! 858: Debugger();
! 859: return;
! 860: }
! 861: if (xs->error == XS_NOERROR) {
! 862: if (ccb->host_stat != AHA_OK) {
! 863: switch (ccb->host_stat) {
! 864: case AHA_SEL_TIMEOUT: /* No response */
! 865: xs->error = XS_SELTIMEOUT;
! 866: break;
! 867: default: /* Other scsi protocol messes */
! 868: printf("%s: host_stat %x\n",
! 869: sc->sc_dev.dv_xname, ccb->host_stat);
! 870: xs->error = XS_DRIVER_STUFFUP;
! 871: break;
! 872: }
! 873: } else if (ccb->target_stat != SCSI_OK) {
! 874: switch (ccb->target_stat) {
! 875: case SCSI_CHECK:
! 876: s1 = (struct scsi_sense_data *)
! 877: (((char *)(&ccb->scsi_cmd)) +
! 878: ccb->scsi_cmd_length);
! 879: s2 = &xs->sense;
! 880: *s2 = *s1;
! 881: xs->error = XS_SENSE;
! 882: break;
! 883: case SCSI_BUSY:
! 884: xs->error = XS_BUSY;
! 885: break;
! 886: default:
! 887: printf("%s: target_stat %x\n",
! 888: sc->sc_dev.dv_xname, ccb->target_stat);
! 889: xs->error = XS_DRIVER_STUFFUP;
! 890: break;
! 891: }
! 892: } else
! 893: xs->resid = 0;
! 894: }
! 895: xs->flags |= ITSDONE;
! 896:
! 897: if (VOLATILE_XS(xs)) {
! 898: wakeup(ccb);
! 899: return;
! 900: }
! 901:
! 902: if (ccb->dmam->dm_nsegs > 0) {
! 903: if (xs->flags & SCSI_DATA_IN)
! 904: bus_dmamap_sync(sc->sc_dmat, ccb->dmam, 0,
! 905: ccb->dmam->dm_mapsize, BUS_DMASYNC_POSTREAD);
! 906: if (xs->flags & SCSI_DATA_OUT)
! 907: bus_dmamap_sync(sc->sc_dmat, ccb->dmam, 0,
! 908: ccb->dmam->dm_mapsize, BUS_DMASYNC_POSTWRITE);
! 909: bus_dmamap_unload(sc->sc_dmat, ccb->dmam);
! 910: }
! 911: aha_free_ccb(sc, ccb);
! 912: scsi_done(xs);
! 913: }
! 914:
! 915: /*
! 916: * Find the board and find its irq/drq
! 917: */
! 918: int
! 919: aha_find(ia, sc, isapnp)
! 920: struct isa_attach_args *ia;
! 921: struct aha_softc *sc;
! 922: int isapnp;
! 923: {
! 924: int iobase = ia->ia_iobase;
! 925: int i;
! 926: u_char sts;
! 927: struct aha_config config;
! 928: int irq, drq;
! 929:
! 930: /*
! 931: * reset board, If it doesn't respond, assume
! 932: * that it's not there.. good for the probe
! 933: */
! 934:
! 935: outb(iobase + AHA_CTRL_PORT, AHA_CTRL_HRST | AHA_CTRL_SRST);
! 936:
! 937: delay(100);
! 938: for (i = AHA_RESET_TIMEOUT; i; i--) {
! 939: sts = inb(iobase + AHA_STAT_PORT);
! 940: if (sts == (AHA_STAT_IDLE | AHA_STAT_INIT))
! 941: break;
! 942: delay(1000); /* calibrated in msec */
! 943: }
! 944: if (!i) {
! 945: #ifdef AHADEBUG
! 946: if (aha_debug)
! 947: printf("aha_find: No answer from adaptec board\n");
! 948: #endif /* AHADEBUG */
! 949: return (1);
! 950: }
! 951:
! 952: /*
! 953: * setup dma channel from jumpers and save int
! 954: * level
! 955: */
! 956: delay(1000); /* for Bustek 545 */
! 957: config.cmd.opcode = AHA_INQUIRE_CONFIG;
! 958: aha_cmd(iobase, sc, sizeof(config.cmd), (u_char *)&config.cmd,
! 959: sizeof(config.reply), (u_char *)&config.reply);
! 960: switch (config.reply.chan) {
! 961: case EISADMA:
! 962: drq = DRQUNK; /* for EISA/VLB/PCI clones */
! 963: break;
! 964: case CHAN0:
! 965: drq = 0;
! 966: break;
! 967: case CHAN5:
! 968: drq = 5;
! 969: break;
! 970: case CHAN6:
! 971: drq = 6;
! 972: break;
! 973: case CHAN7:
! 974: drq = 7;
! 975: break;
! 976: default:
! 977: printf("aha_find: illegal drq setting %x\n",
! 978: config.reply.chan);
! 979: return (1);
! 980: }
! 981: if (isapnp)
! 982: irq = ia->ia_irq;
! 983:
! 984: switch (config.reply.intr) {
! 985: case INT9:
! 986: irq = 9;
! 987: break;
! 988: case INT10:
! 989: irq = 10;
! 990: break;
! 991: case INT11:
! 992: irq = 11;
! 993: break;
! 994: case INT12:
! 995: irq = 12;
! 996: break;
! 997: case INT14:
! 998: irq = 14;
! 999: break;
! 1000: case INT15:
! 1001: irq = 15;
! 1002: break;
! 1003: default:
! 1004: printf("aha_find: illegal irq setting %x\n",
! 1005: config.reply.intr);
! 1006: return (EIO);
! 1007: }
! 1008: if (isapnp)
! 1009: drq = ia->ia_drq;
! 1010:
! 1011: if (sc != NULL) {
! 1012: /* who are we on the scsi bus? */
! 1013: sc->sc_scsi_dev = config.reply.scsi_dev;
! 1014:
! 1015: sc->sc_iobase = iobase;
! 1016: sc->sc_irq = irq;
! 1017: sc->sc_drq = drq;
! 1018: } else {
! 1019: if (isapnp)
! 1020: return (0);
! 1021: if (ia->ia_irq == IRQUNK)
! 1022: ia->ia_irq = irq;
! 1023: else if (ia->ia_irq != irq)
! 1024: return (1);
! 1025: if (ia->ia_drq == DRQUNK)
! 1026: ia->ia_drq = drq;
! 1027: else if (ia->ia_drq != drq)
! 1028: return (1);
! 1029: }
! 1030:
! 1031: return (0);
! 1032: }
! 1033:
! 1034: /*
! 1035: * Start the board, ready for normal operation
! 1036: */
! 1037: void
! 1038: aha_init(sc)
! 1039: struct aha_softc *sc;
! 1040: {
! 1041: int iobase = sc->sc_iobase;
! 1042: struct aha_devices devices;
! 1043: struct aha_setup setup;
! 1044: struct aha_mailbox mailbox;
! 1045: struct pglist pglist;
! 1046: struct vm_page *pg;
! 1047: vaddr_t va;
! 1048: vsize_t size;
! 1049: int i;
! 1050:
! 1051: /*
! 1052: * XXX
! 1053: * If we are a 1542C or later, disable the extended BIOS so that the
! 1054: * mailbox interface is unlocked.
! 1055: * No need to check the extended BIOS flags as some of the
! 1056: * extensions that cause us problems are not flagged in that byte.
! 1057: */
! 1058: if (!strncmp(sc->sc_model, "1542C", 5)) {
! 1059: struct aha_extbios extbios;
! 1060: struct aha_unlock unlock;
! 1061:
! 1062: printf("%s: unlocking mailbox interface\n",
! 1063: sc->sc_dev.dv_xname);
! 1064: extbios.cmd.opcode = AHA_EXT_BIOS;
! 1065: aha_cmd(iobase, sc, sizeof(extbios.cmd),
! 1066: (u_char *)&extbios.cmd, sizeof(extbios.reply),
! 1067: (u_char *)&extbios.reply);
! 1068:
! 1069: #ifdef AHADEBUG
! 1070: printf("%s: flags=%02x, mailboxlock=%02x\n",
! 1071: sc->sc_dev.dv_xname,
! 1072: extbios.reply.flags, extbios.reply.mailboxlock);
! 1073: #endif /* AHADEBUG */
! 1074:
! 1075: unlock.cmd.opcode = AHA_MBX_ENABLE;
! 1076: unlock.cmd.junk = 0;
! 1077: unlock.cmd.magic = extbios.reply.mailboxlock;
! 1078: aha_cmd(iobase, sc, sizeof(unlock.cmd), (u_char *)&unlock.cmd,
! 1079: 0, (u_char *)0);
! 1080: }
! 1081:
! 1082: #if 0
! 1083: /*
! 1084: * Change the bus on/off times to not clash with other dma users.
! 1085: */
! 1086: aha_cmd(sc, 1, 0, 0, 0, AHA_BUS_ON_TIME_SET, 7);
! 1087: aha_cmd(sc, 1, 0, 0, 0, AHA_BUS_OFF_TIME_SET, 4);
! 1088: #endif
! 1089:
! 1090: /* Inquire Installed Devices (to force synchronous negotiation). */
! 1091: devices.cmd.opcode = AHA_INQUIRE_DEVICES;
! 1092: aha_cmd(iobase, sc, sizeof(devices.cmd), (u_char *)&devices.cmd,
! 1093: sizeof(devices.reply), (u_char *)&devices.reply);
! 1094:
! 1095: /* Obtain setup information from. */
! 1096: setup.cmd.opcode = AHA_INQUIRE_SETUP;
! 1097: setup.cmd.len = sizeof(setup.reply);
! 1098: aha_cmd(iobase, sc, sizeof(setup.cmd), (u_char *)&setup.cmd,
! 1099: sizeof(setup.reply), (u_char *)&setup.reply);
! 1100:
! 1101: printf("%s: %s, %s\n",
! 1102: sc->sc_dev.dv_xname,
! 1103: setup.reply.sync_neg ? "sync" : "async",
! 1104: setup.reply.parity ? "parity" : "no parity");
! 1105:
! 1106: for (i = 0; i < 8; i++) {
! 1107: if (!setup.reply.sync[i].valid ||
! 1108: (!setup.reply.sync[i].offset &&
! 1109: !setup.reply.sync[i].period))
! 1110: continue;
! 1111: printf("%s targ %d: sync, offset %d, period %dnsec\n",
! 1112: sc->sc_dev.dv_xname, i, setup.reply.sync[i].offset,
! 1113: setup.reply.sync[i].period * 50 + 200);
! 1114: }
! 1115:
! 1116: /*
! 1117: * Set up initial mail box for round-robin operation.
! 1118: */
! 1119:
! 1120: /*
! 1121: * XXX - this vm juggling is so wrong. use bus_dma instead!
! 1122: */
! 1123: size = round_page(sizeof(struct aha_mbx));
! 1124: TAILQ_INIT(&pglist);
! 1125: if (uvm_pglistalloc(size, 0, 0xffffff, PAGE_SIZE, 0, &pglist, 1, 0) ||
! 1126: uvm_map(kernel_map, &va, size, NULL, UVM_UNKNOWN_OFFSET, 0,
! 1127: UVM_MAPFLAG(UVM_PROT_ALL, UVM_PROT_ALL, UVM_INH_NONE,
! 1128: UVM_ADV_RANDOM, 0)))
! 1129: panic("aha_init: could not allocate mailbox");
! 1130:
! 1131: wmbx = (struct aha_mbx *)va;
! 1132: for (pg = TAILQ_FIRST(&pglist); pg != NULL;
! 1133: pg = TAILQ_NEXT(pg, pageq)) {
! 1134: pmap_kenter_pa(va, VM_PAGE_TO_PHYS(pg),
! 1135: VM_PROT_READ|VM_PROT_WRITE);
! 1136: va += PAGE_SIZE;
! 1137: }
! 1138: pmap_update(pmap_kernel());
! 1139: /*
! 1140: * XXXEND
! 1141: */
! 1142:
! 1143: for (i = 0; i < AHA_MBX_SIZE; i++) {
! 1144: wmbx->mbo[i].cmd = AHA_MBO_FREE;
! 1145: wmbx->mbi[i].stat = AHA_MBI_FREE;
! 1146: }
! 1147: wmbx->cmbo = wmbx->tmbo = &wmbx->mbo[0];
! 1148: wmbx->tmbi = &wmbx->mbi[0];
! 1149: sc->sc_mbofull = 0;
! 1150:
! 1151: /* Initialize mail box. */
! 1152: mailbox.cmd.opcode = AHA_MBX_INIT;
! 1153: mailbox.cmd.nmbx = AHA_MBX_SIZE;
! 1154: ltophys(vtophys((vaddr_t)wmbx), mailbox.cmd.addr);
! 1155: aha_cmd(iobase, sc, sizeof(mailbox.cmd), (u_char *)&mailbox.cmd,
! 1156: 0, (u_char *)0);
! 1157: }
! 1158:
! 1159: void
! 1160: aha_inquire_setup_information(sc)
! 1161: struct aha_softc *sc;
! 1162: {
! 1163: int iobase = sc->sc_iobase;
! 1164: struct aha_revision revision;
! 1165: u_char sts;
! 1166: int i;
! 1167: char *p;
! 1168:
! 1169: strlcpy(sc->sc_model, "unknown", sizeof sc->sc_model);
! 1170:
! 1171: /*
! 1172: * Assume we have a board at this stage, do an adapter inquire
! 1173: * to find out what type of controller it is. If the command
! 1174: * fails, we assume it's either a crusty board or an old 1542
! 1175: * clone, and skip the board-specific stuff.
! 1176: */
! 1177: revision.cmd.opcode = AHA_INQUIRE_REVISION;
! 1178: if (aha_cmd(iobase, sc, sizeof(revision.cmd), (u_char *)&revision.cmd,
! 1179: sizeof(revision.reply), (u_char *)&revision.reply)) {
! 1180: /*
! 1181: * aha_cmd() already started the reset. It's not clear we
! 1182: * even need to bother here.
! 1183: */
! 1184: for (i = AHA_RESET_TIMEOUT; i; i--) {
! 1185: sts = inb(iobase + AHA_STAT_PORT);
! 1186: if (sts == (AHA_STAT_IDLE | AHA_STAT_INIT))
! 1187: break;
! 1188: delay(1000);
! 1189: }
! 1190: if (!i) {
! 1191: #ifdef AHADEBUG
! 1192: printf("aha_init: soft reset failed\n");
! 1193: #endif /* AHADEBUG */
! 1194: return;
! 1195: }
! 1196: #ifdef AHADEBUG
! 1197: printf("aha_init: inquire command failed\n");
! 1198: #endif /* AHADEBUG */
! 1199: goto noinquire;
! 1200: }
! 1201:
! 1202: #ifdef AHADEBUG
! 1203: printf("%s: inquire %x, %x, %x, %x\n",
! 1204: sc->sc_dev.dv_xname,
! 1205: revision.reply.boardid, revision.reply.spec_opts,
! 1206: revision.reply.revision_1, revision.reply.revision_2);
! 1207: #endif /* AHADEBUG */
! 1208:
! 1209: switch (revision.reply.boardid) {
! 1210: case 0x31:
! 1211: strlcpy(sc->sc_model, "1540", sizeof sc->sc_model);
! 1212: break;
! 1213: case 0x41:
! 1214: strlcpy(sc->sc_model, "1540A/1542A/1542B", sizeof sc->sc_model);
! 1215: break;
! 1216: case 0x42:
! 1217: strlcpy(sc->sc_model, "1640", sizeof sc->sc_model);
! 1218: break;
! 1219: case 0x43:
! 1220: case 0x44: /* Is this 1542C or -CF? */
! 1221: strlcpy(sc->sc_model, "1542C", sizeof sc->sc_model);
! 1222: break;
! 1223: case 0x45:
! 1224: strlcpy(sc->sc_model, "1542CF", sizeof sc->sc_model);
! 1225: break;
! 1226: case 0x46:
! 1227: strlcpy(sc->sc_model, "1542CP", sizeof sc->sc_model);
! 1228: break;
! 1229: }
! 1230:
! 1231: p = sc->sc_firmware;
! 1232: *p++ = revision.reply.revision_1;
! 1233: *p++ = '.';
! 1234: *p++ = revision.reply.revision_2;
! 1235: *p = '\0';
! 1236:
! 1237: noinquire:
! 1238: printf(": model AHA-%s, firmware %s\n", sc->sc_model, sc->sc_firmware);
! 1239: }
! 1240:
! 1241: void
! 1242: ahaminphys(bp)
! 1243: struct buf *bp;
! 1244: {
! 1245:
! 1246: if (bp->b_bcount > ((AHA_NSEG - 1) << PGSHIFT))
! 1247: bp->b_bcount = ((AHA_NSEG - 1) << PGSHIFT);
! 1248: minphys(bp);
! 1249: }
! 1250:
! 1251: /*
! 1252: * start a scsi operation given the command and the data address. Also needs
! 1253: * the unit, target and lu.
! 1254: */
! 1255: int
! 1256: aha_scsi_cmd(xs)
! 1257: struct scsi_xfer *xs;
! 1258: {
! 1259: struct scsi_link *sc_link = xs->sc_link;
! 1260: struct aha_softc *sc = sc_link->adapter_softc;
! 1261: struct aha_ccb *ccb;
! 1262: struct aha_scat_gath *sg;
! 1263: int seg, flags;
! 1264: #ifdef TFS
! 1265: struct iovec *iovp;
! 1266: int datalen;
! 1267: #endif
! 1268: int s;
! 1269:
! 1270: SC_DEBUG(sc_link, SDEV_DB2, ("aha_scsi_cmd\n"));
! 1271: /*
! 1272: * get a ccb to use. If the transfer
! 1273: * is from a buf (possibly from interrupt time)
! 1274: * then we can't allow it to sleep
! 1275: */
! 1276: flags = xs->flags;
! 1277: if ((ccb = aha_get_ccb(sc, flags)) == NULL) {
! 1278: return (TRY_AGAIN_LATER);
! 1279: }
! 1280: ccb->xs = xs;
! 1281: ccb->timeout = xs->timeout;
! 1282:
! 1283: /*
! 1284: * Put all the arguments for the xfer in the ccb
! 1285: */
! 1286: if (flags & SCSI_RESET) {
! 1287: ccb->opcode = AHA_RESET_CCB;
! 1288: ccb->scsi_cmd_length = 0;
! 1289: } else {
! 1290: /* can't use S/G if zero length */
! 1291: ccb->opcode =
! 1292: (xs->datalen ? AHA_INIT_SCAT_GATH_CCB : AHA_INITIATOR_CCB);
! 1293: bcopy(xs->cmd, &ccb->scsi_cmd,
! 1294: ccb->scsi_cmd_length = xs->cmdlen);
! 1295: }
! 1296:
! 1297: if (xs->datalen) {
! 1298: sg = ccb->scat_gath;
! 1299: seg = 0;
! 1300: #ifdef TFS
! 1301: if (flags & SCSI_DATA_UIO) {
! 1302: iovp = ((struct uio *)xs->data)->uio_iov;
! 1303: datalen = ((struct uio *)xs->data)->uio_iovcnt;
! 1304: xs->datalen = 0;
! 1305: while (datalen && seg < AHA_NSEG) {
! 1306: ltophys(iovp->iov_base, sg->seg_addr);
! 1307: ltophys(iovp->iov_len, sg->seg_len);
! 1308: xs->datalen += iovp->iov_len;
! 1309: SC_DEBUGN(sc_link, SDEV_DB4, ("UIO(0x%x@0x%x)",
! 1310: iovp->iov_len, iovp->iov_base));
! 1311: sg++;
! 1312: iovp++;
! 1313: seg++;
! 1314: datalen--;
! 1315: }
! 1316: } else
! 1317: #endif /* TFS */
! 1318: {
! 1319: /*
! 1320: * Set up the scatter-gather block.
! 1321: */
! 1322: if (bus_dmamap_load(sc->sc_dmat, ccb->dmam, xs->data,
! 1323: xs->datalen, NULL, BUS_DMA_NOWAIT) != 0) {
! 1324: aha_free_ccb(sc, ccb);
! 1325: xs->error = XS_DRIVER_STUFFUP;
! 1326: return (TRY_AGAIN_LATER);
! 1327: }
! 1328: for (seg = 0; seg < ccb->dmam->dm_nsegs; seg++) {
! 1329: ltophys(ccb->dmam->dm_segs[seg].ds_addr,
! 1330: sg[seg].seg_addr);
! 1331: ltophys(ccb->dmam->dm_segs[seg].ds_len,
! 1332: sg[seg].seg_len);
! 1333: }
! 1334: }
! 1335: if (flags & SCSI_DATA_OUT)
! 1336: bus_dmamap_sync(sc->sc_dmat, ccb->dmam, 0,
! 1337: ccb->dmam->dm_mapsize, BUS_DMASYNC_PREWRITE);
! 1338: if (flags & SCSI_DATA_IN)
! 1339: bus_dmamap_sync(sc->sc_dmat, ccb->dmam, 0,
! 1340: ccb->dmam->dm_mapsize, BUS_DMASYNC_PREREAD);
! 1341: ltophys((unsigned)
! 1342: ((struct aha_ccb *)(ccb->ccb_dmam->dm_segs[0].ds_addr))->
! 1343: scat_gath,
! 1344: ccb->data_addr);
! 1345: ltophys(ccb->dmam->dm_nsegs * sizeof(struct aha_scat_gath),
! 1346: ccb->data_length);
! 1347: } else { /* No data xfer, use non S/G values */
! 1348: ltophys(0, ccb->data_addr);
! 1349: ltophys(0, ccb->data_length);
! 1350: }
! 1351:
! 1352: ccb->data_out = 0;
! 1353: ccb->data_in = 0;
! 1354: ccb->target = sc_link->target;
! 1355: ccb->lun = sc_link->lun;
! 1356: ccb->req_sense_length = sizeof(ccb->scsi_sense);
! 1357: ccb->host_stat = 0x00;
! 1358: ccb->target_stat = 0x00;
! 1359: ccb->link_id = 0;
! 1360: ltophys(0, ccb->link_addr);
! 1361:
! 1362: s = splbio();
! 1363: aha_queue_ccb(sc, ccb);
! 1364:
! 1365: /*
! 1366: * Usually return SUCCESSFULLY QUEUED
! 1367: */
! 1368: SC_DEBUG(sc_link, SDEV_DB3, ("cmd_sent\n"));
! 1369:
! 1370: if (VOLATILE_XS(xs)) {
! 1371: while ((ccb->xs->flags & ITSDONE) == 0) {
! 1372: tsleep(ccb, PRIBIO, "ahawait", 0);
! 1373: }
! 1374: if (ccb->dmam->dm_nsegs > 0) {
! 1375: if (flags & SCSI_DATA_OUT)
! 1376: bus_dmamap_sync(sc->sc_dmat, ccb->dmam, 0,
! 1377: ccb->dmam->dm_mapsize,
! 1378: BUS_DMASYNC_POSTWRITE);
! 1379: if (flags & SCSI_DATA_IN)
! 1380: bus_dmamap_sync(sc->sc_dmat, ccb->dmam, 0,
! 1381: ccb->dmam->dm_mapsize,
! 1382: BUS_DMASYNC_POSTREAD);
! 1383: bus_dmamap_unload(sc->sc_dmat, ccb->dmam);
! 1384: }
! 1385: aha_free_ccb(sc, ccb);
! 1386: scsi_done(xs);
! 1387: splx(s);
! 1388: return (COMPLETE);
! 1389: }
! 1390: splx(s);
! 1391:
! 1392: if ((flags & SCSI_POLL) == 0)
! 1393: return (SUCCESSFULLY_QUEUED);
! 1394:
! 1395: /*
! 1396: * If we can't use interrupts, poll on completion
! 1397: */
! 1398: if (aha_poll(sc, xs, ccb->timeout)) {
! 1399: aha_timeout(ccb);
! 1400: if (aha_poll(sc, xs, ccb->timeout))
! 1401: aha_timeout(ccb);
! 1402: }
! 1403: return (COMPLETE);
! 1404: }
! 1405:
! 1406: /*
! 1407: * Poll a particular unit, looking for a particular xs
! 1408: */
! 1409: int
! 1410: aha_poll(sc, xs, count)
! 1411: struct aha_softc *sc;
! 1412: struct scsi_xfer *xs;
! 1413: int count;
! 1414: {
! 1415: int iobase = sc->sc_iobase;
! 1416: int s;
! 1417:
! 1418: /* timeouts are in msec, so we loop in 1000 usec cycles */
! 1419: while (count) {
! 1420: /*
! 1421: * If we had interrupts enabled, would we
! 1422: * have got an interrupt?
! 1423: */
! 1424: if (inb(iobase + AHA_INTR_PORT) & AHA_INTR_ANYINTR) {
! 1425: s = splbio();
! 1426: ahaintr(sc);
! 1427: splx(s);
! 1428: }
! 1429: if (xs->flags & ITSDONE)
! 1430: return (0);
! 1431: delay(1000); /* only happens in boot so ok */
! 1432: count--;
! 1433: }
! 1434: return (1);
! 1435: }
! 1436:
! 1437: void
! 1438: aha_timeout(arg)
! 1439: void *arg;
! 1440: {
! 1441: struct aha_ccb *ccb = arg;
! 1442: struct scsi_xfer *xs;
! 1443: struct scsi_link *sc_link;
! 1444: struct aha_softc *sc;
! 1445: int s;
! 1446:
! 1447: s = splbio();
! 1448: bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmam, 0,
! 1449: ccb->ccb_dmam->dm_mapsize, BUS_DMASYNC_POSTREAD);
! 1450: xs = ccb->xs;
! 1451: sc_link = xs->sc_link;
! 1452: sc = sc_link->adapter_softc;
! 1453:
! 1454: sc_print_addr(sc_link);
! 1455: printf("timed out");
! 1456:
! 1457: #ifdef AHADIAG
! 1458: /*
! 1459: * If The ccb's mbx is not free, then the board has gone south?
! 1460: */
! 1461: aha_collect_mbo(sc);
! 1462: if (ccb->flags & CCB_SENDING) {
! 1463: printf("%s: not taking commands!\n", sc->sc_dev.dv_xname);
! 1464: Debugger();
! 1465: }
! 1466: #endif
! 1467:
! 1468: /*
! 1469: * If it has been through before, then
! 1470: * a previous abort has failed, don't
! 1471: * try abort again
! 1472: */
! 1473: if (ccb->flags & CCB_ABORT) {
! 1474: /* abort timed out */
! 1475: printf(" AGAIN\n");
! 1476: /* XXX Must reset! */
! 1477: } else {
! 1478: /* abort the operation that has timed out */
! 1479: printf("\n");
! 1480: ccb->xs->error = XS_TIMEOUT;
! 1481: ccb->timeout = AHA_ABORT_TIMEOUT;
! 1482: ccb->flags |= CCB_ABORT;
! 1483: aha_queue_ccb(sc, ccb);
! 1484: }
! 1485:
! 1486: splx(s);
! 1487: }
! 1488:
CVSweb