Annotation of sys/dev/ic/bha.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: bha.c,v 1.10 2007/04/10 17:47:55 miod Exp $ */
! 2: /* $NetBSD: bha.c,v 1.27 1998/11/19 21:53:00 thorpej Exp $ */
! 3:
! 4: #undef BHADEBUG
! 5: #ifdef DDB
! 6: #define integrate
! 7: #else
! 8: #define integrate static inline
! 9: #endif
! 10:
! 11: /*-
! 12: * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
! 13: * All rights reserved.
! 14: *
! 15: * This code is derived from software contributed to The NetBSD Foundation
! 16: * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace
! 17: * Simulation Facility, NASA Ames Research Center.
! 18: *
! 19: * Redistribution and use in source and binary forms, with or without
! 20: * modification, are permitted provided that the following conditions
! 21: * are met:
! 22: * 1. Redistributions of source code must retain the above copyright
! 23: * notice, this list of conditions and the following disclaimer.
! 24: * 2. Redistributions in binary form must reproduce the above copyright
! 25: * notice, this list of conditions and the following disclaimer in the
! 26: * documentation and/or other materials provided with the distribution.
! 27: * 3. All advertising materials mentioning features or use of this software
! 28: * must display the following acknowledgement:
! 29: * This product includes software developed by the NetBSD
! 30: * Foundation, Inc. and its contributors.
! 31: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 32: * contributors may be used to endorse or promote products derived
! 33: * from this software without specific prior written permission.
! 34: *
! 35: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 36: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 37: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 38: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 39: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 40: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 41: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 42: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 43: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 44: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 45: * POSSIBILITY OF SUCH DAMAGE.
! 46: */
! 47:
! 48: /*
! 49: * Originally written by Julian Elischer (julian@tfs.com)
! 50: * for TRW Financial Systems for use under the MACH(2.5) operating system.
! 51: *
! 52: * TRW Financial Systems, in accordance with their agreement with Carnegie
! 53: * Mellon University, makes this software available to CMU to distribute
! 54: * or use in any manner that they see fit as long as this message is kept with
! 55: * the software. For this reason TFS also grants any other persons or
! 56: * organisations permission to use or modify this software.
! 57: *
! 58: * TFS supplies this software to be publicly redistributed
! 59: * on the understanding that TFS is not responsible for the correct
! 60: * functioning of this software in any circumstances.
! 61: */
! 62:
! 63: #include <sys/types.h>
! 64: #include <sys/param.h>
! 65: #include <sys/systm.h>
! 66: #include <sys/kernel.h>
! 67: #include <sys/errno.h>
! 68: #include <sys/ioctl.h>
! 69: #include <sys/device.h>
! 70: #include <sys/malloc.h>
! 71: #include <sys/buf.h>
! 72: #include <sys/proc.h>
! 73: #include <sys/user.h>
! 74:
! 75: #include <machine/bus.h>
! 76: #include <machine/intr.h>
! 77:
! 78: #include <scsi/scsi_all.h>
! 79: #include <scsi/scsiconf.h>
! 80:
! 81: #include <dev/ic/bhareg.h>
! 82: #include <dev/ic/bhavar.h>
! 83:
! 84: #ifndef DDB
! 85: #define Debugger() panic("should call debugger here (bha.c)")
! 86: #endif /* ! DDB */
! 87:
! 88: #define BHA_MAXXFER ((BHA_NSEG - 1) << PGSHIFT)
! 89: #define ISWIDE(sc) ((sc)->sc_iswide)
! 90:
! 91: #ifdef BHADEBUG
! 92: int bha_debug = 1;
! 93: #endif /* BHADEBUG */
! 94:
! 95: integrate void bha_finish_ccbs(struct bha_softc *);
! 96: integrate void bha_reset_ccb(struct bha_softc *, struct bha_ccb *);
! 97: void bha_free_ccb(struct bha_softc *, struct bha_ccb *);
! 98: integrate int bha_init_ccb(struct bha_softc *, struct bha_ccb *);
! 99: struct bha_ccb *bha_get_ccb(struct bha_softc *, int);
! 100: struct bha_ccb *bha_ccb_phys_kv(struct bha_softc *, u_long);
! 101: void bha_queue_ccb(struct bha_softc *, struct bha_ccb *);
! 102: void bha_collect_mbo(struct bha_softc *);
! 103: void bha_start_ccbs(struct bha_softc *);
! 104: void bha_done(struct bha_softc *, struct bha_ccb *);
! 105: int bha_init(struct bha_softc *);
! 106: void bhaminphys(struct buf *);
! 107: int bha_scsi_cmd(struct scsi_xfer *);
! 108: int bha_poll(struct bha_softc *, struct scsi_xfer *, int);
! 109: void bha_timeout(void *arg);
! 110: int bha_create_ccbs(struct bha_softc *, struct bha_ccb *, int);
! 111: void bha_enqueue(struct bha_softc *, struct scsi_xfer *, int);
! 112: struct scsi_xfer *bha_dequeue(struct bha_softc *);
! 113:
! 114: struct cfdriver bha_cd = {
! 115: NULL, "bha", DV_DULL
! 116: };
! 117:
! 118: /* the below structure is so we have a default dev struct for out link struct */
! 119: struct scsi_device bha_dev = {
! 120: NULL, /* Use default error handler */
! 121: NULL, /* have a queue, served by this */
! 122: NULL, /* have no async handler */
! 123: NULL, /* Use default 'done' routine */
! 124: };
! 125:
! 126: #define BHA_RESET_TIMEOUT 2000 /* time to wait for reset (mSec) */
! 127: #define BHA_ABORT_TIMEOUT 2000 /* time to wait for abort (mSec) */
! 128:
! 129: /*
! 130: * Insert a scsi_xfer into the software queue. We overload xs->free_list
! 131: * to avoid having to allocate additional resources (since we're used
! 132: * only during resource shortages anyhow.
! 133: */
! 134: void
! 135: bha_enqueue(sc, xs, infront)
! 136: struct bha_softc *sc;
! 137: struct scsi_xfer *xs;
! 138: int infront;
! 139: {
! 140:
! 141: if (infront || LIST_EMPTY(&sc->sc_queue)) {
! 142: if (LIST_EMPTY(&sc->sc_queue))
! 143: sc->sc_queuelast = xs;
! 144: LIST_INSERT_HEAD(&sc->sc_queue, xs, free_list);
! 145: return;
! 146: }
! 147:
! 148: LIST_INSERT_AFTER(sc->sc_queuelast, xs, free_list);
! 149: sc->sc_queuelast = xs;
! 150: }
! 151:
! 152: /*
! 153: * Pull a scsi_xfer off the front of the software queue.
! 154: */
! 155: struct scsi_xfer *
! 156: bha_dequeue(sc)
! 157: struct bha_softc *sc;
! 158: {
! 159: struct scsi_xfer *xs;
! 160:
! 161: xs = LIST_FIRST(&sc->sc_queue);
! 162: LIST_REMOVE(xs, free_list);
! 163:
! 164: if (LIST_EMPTY(&sc->sc_queue))
! 165: sc->sc_queuelast = NULL;
! 166:
! 167: return (xs);
! 168: }
! 169:
! 170: /*
! 171: * bha_cmd(iot, ioh, sc, icnt, ibuf, ocnt, obuf)
! 172: *
! 173: * Activate Adapter command
! 174: * icnt: number of args (outbound bytes including opcode)
! 175: * ibuf: argument buffer
! 176: * ocnt: number of expected returned bytes
! 177: * obuf: result buffer
! 178: * wait: number of seconds to wait for response
! 179: *
! 180: * Performs an adapter command through the ports. Not to be confused with a
! 181: * scsi command, which is read in via the dma; one of the adapter commands
! 182: * tells it to read in a scsi command.
! 183: */
! 184: int
! 185: bha_cmd(iot, ioh, sc, icnt, ibuf, ocnt, obuf)
! 186: bus_space_tag_t iot;
! 187: bus_space_handle_t ioh;
! 188: struct bha_softc *sc;
! 189: int icnt, ocnt;
! 190: u_char *ibuf, *obuf;
! 191: {
! 192: const char *name;
! 193: register int i;
! 194: int wait;
! 195: u_char sts;
! 196: u_char opcode = ibuf[0];
! 197:
! 198: if (sc != NULL)
! 199: name = sc->sc_dev.dv_xname;
! 200: else
! 201: name = "(bha probe)";
! 202:
! 203: /*
! 204: * Calculate a reasonable timeout for the command.
! 205: */
! 206: switch (opcode) {
! 207: case BHA_INQUIRE_DEVICES:
! 208: case BHA_INQUIRE_DEVICES_2:
! 209: wait = 90 * 20000;
! 210: break;
! 211: default:
! 212: wait = 1 * 20000;
! 213: break;
! 214: }
! 215:
! 216: /*
! 217: * Wait for the adapter to go idle, unless it's one of
! 218: * the commands which don't need this
! 219: */
! 220: if (opcode != BHA_MBO_INTR_EN) {
! 221: for (i = 20000; i; i--) { /* 1 sec? */
! 222: sts = bus_space_read_1(iot, ioh, BHA_STAT_PORT);
! 223: if (sts & BHA_STAT_IDLE)
! 224: break;
! 225: delay(50);
! 226: }
! 227: if (!i) {
! 228: printf("%s: bha_cmd, host not idle(0x%x)\n",
! 229: name, sts);
! 230: return (1);
! 231: }
! 232: }
! 233: /*
! 234: * Now that it is idle, if we expect output, preflush the
! 235: * queue feeding to us.
! 236: */
! 237: if (ocnt) {
! 238: while ((bus_space_read_1(iot, ioh, BHA_STAT_PORT)) &
! 239: BHA_STAT_DF)
! 240: bus_space_read_1(iot, ioh, BHA_DATA_PORT);
! 241: }
! 242: /*
! 243: * Output the command and the number of arguments given
! 244: * for each byte, first check the port is empty.
! 245: */
! 246: while (icnt--) {
! 247: for (i = wait; i; i--) {
! 248: sts = bus_space_read_1(iot, ioh, BHA_STAT_PORT);
! 249: if (!(sts & BHA_STAT_CDF))
! 250: break;
! 251: delay(50);
! 252: }
! 253: if (!i) {
! 254: if (opcode != BHA_INQUIRE_REVISION)
! 255: printf("%s: bha_cmd, cmd/data port full\n",
! 256: name);
! 257: goto bad;
! 258: }
! 259: bus_space_write_1(iot, ioh, BHA_CMD_PORT, *ibuf++);
! 260: }
! 261: /*
! 262: * If we expect input, loop that many times, each time,
! 263: * looking for the data register to have valid data
! 264: */
! 265: while (ocnt--) {
! 266: for (i = wait; i; i--) {
! 267: sts = bus_space_read_1(iot, ioh, BHA_STAT_PORT);
! 268: if (sts & BHA_STAT_DF)
! 269: break;
! 270: delay(50);
! 271: }
! 272: if (!i) {
! 273: if (opcode != BHA_INQUIRE_REVISION)
! 274: printf("%s: bha_cmd, cmd/data port empty %d\n",
! 275: name, ocnt);
! 276: goto bad;
! 277: }
! 278: *obuf++ = bus_space_read_1(iot, ioh, BHA_DATA_PORT);
! 279: }
! 280: /*
! 281: * Wait for the board to report a finished instruction.
! 282: * We may get an extra interrupt for the HACC signal, but this is
! 283: * unimportant.
! 284: */
! 285: if (opcode != BHA_MBO_INTR_EN && opcode != BHA_MODIFY_IOPORT) {
! 286: for (i = 20000; i; i--) { /* 1 sec? */
! 287: sts = bus_space_read_1(iot, ioh, BHA_INTR_PORT);
! 288: /* XXX Need to save this in the interrupt handler? */
! 289: if (sts & BHA_INTR_HACC)
! 290: break;
! 291: delay(50);
! 292: }
! 293: if (!i) {
! 294: printf("%s: bha_cmd, host not finished(0x%x)\n",
! 295: name, sts);
! 296: return (1);
! 297: }
! 298: }
! 299: bus_space_write_1(iot, ioh, BHA_CTRL_PORT, BHA_CTRL_IRST);
! 300: return (0);
! 301:
! 302: bad:
! 303: bus_space_write_1(iot, ioh, BHA_CTRL_PORT, BHA_CTRL_SRST);
! 304: return (1);
! 305: }
! 306:
! 307: /*
! 308: * Attach all the sub-devices we can find
! 309: */
! 310: void
! 311: bha_attach(sc, bpd)
! 312: struct bha_softc *sc;
! 313: struct bha_probe_data *bpd;
! 314: {
! 315: struct scsibus_attach_args saa;
! 316: int s;
! 317:
! 318: /*
! 319: * Fill in the adapter.
! 320: */
! 321: sc->sc_adapter.scsi_cmd = bha_scsi_cmd;
! 322: sc->sc_adapter.scsi_minphys = bhaminphys;
! 323:
! 324: /*
! 325: * fill in the prototype scsi_link.
! 326: */
! 327: sc->sc_link.adapter_softc = sc;
! 328: sc->sc_link.adapter_target = bpd->sc_scsi_dev;
! 329: sc->sc_link.adapter = &sc->sc_adapter;
! 330: sc->sc_link.device = &bha_dev;
! 331: sc->sc_link.openings = 4;
! 332:
! 333: TAILQ_INIT(&sc->sc_free_ccb);
! 334: TAILQ_INIT(&sc->sc_waiting_ccb);
! 335: LIST_INIT(&sc->sc_queue);
! 336:
! 337: s = splbio();
! 338: bha_inquire_setup_information(sc);
! 339:
! 340: printf("%s: model BT-%s, firmware %s\n", sc->sc_dev.dv_xname,
! 341: sc->sc_model, sc->sc_firmware);
! 342:
! 343: if (bha_init(sc) != 0) {
! 344: /* Error during initialization! */
! 345: splx(s);
! 346: return;
! 347: }
! 348:
! 349: splx(s);
! 350:
! 351: bzero(&saa, sizeof(saa));
! 352: saa.saa_sc_link = &sc->sc_link;
! 353:
! 354: /*
! 355: * ask the adapter what subunits are present
! 356: */
! 357: config_found(&sc->sc_dev, &saa, scsiprint);
! 358: }
! 359:
! 360: integrate void
! 361: bha_finish_ccbs(sc)
! 362: struct bha_softc *sc;
! 363: {
! 364: struct bha_mbx_in *wmbi;
! 365: struct bha_ccb *ccb;
! 366: int i;
! 367:
! 368: wmbi = wmbx->tmbi;
! 369:
! 370: bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_control,
! 371: 0, sc->sc_dmamap_control->dm_mapsize,
! 372: BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
! 373:
! 374: if (wmbi->comp_stat == BHA_MBI_FREE) {
! 375: for (i = 0; i < BHA_MBX_SIZE; i++) {
! 376: if (wmbi->comp_stat != BHA_MBI_FREE) {
! 377: printf("%s: mbi not in round-robin order\n",
! 378: sc->sc_dev.dv_xname);
! 379: goto AGAIN;
! 380: }
! 381: bha_nextmbx(wmbi, wmbx, mbi);
! 382: bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_control,
! 383: 0, sc->sc_dmamap_control->dm_mapsize,
! 384: BUS_DMASYNC_POSTREAD);
! 385: }
! 386: #ifdef BHADIAGnot
! 387: printf("%s: mbi interrupt with no full mailboxes\n",
! 388: sc->sc_dev.dv_xname);
! 389: #endif
! 390: return;
! 391: }
! 392:
! 393: AGAIN:
! 394: do {
! 395: ccb = bha_ccb_phys_kv(sc, phystol(wmbi->ccb_addr));
! 396: if (!ccb) {
! 397: printf("%s: bad mbi ccb pointer; skipping\n",
! 398: sc->sc_dev.dv_xname);
! 399: goto next;
! 400: }
! 401:
! 402: bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_control,
! 403: 0, sc->sc_dmamap_control->dm_mapsize,
! 404: BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
! 405:
! 406: #ifdef BHADEBUG
! 407: if (bha_debug) {
! 408: u_int8_t *cp = ccb->scsi_cmd.bytes;
! 409: printf("op=%x %x %x %x %x %x\n",
! 410: ccb->scsi_cmd.opcode,
! 411: cp[0], cp[1], cp[2], cp[3], cp[4]);
! 412: printf("stat %x for mbi addr = 0x%08x, ",
! 413: wmbi->comp_stat, wmbi);
! 414: printf("ccb addr = 0x%x\n", ccb);
! 415: }
! 416: #endif /* BHADEBUG */
! 417:
! 418: switch (wmbi->comp_stat) {
! 419: case BHA_MBI_OK:
! 420: case BHA_MBI_ERROR:
! 421: if ((ccb->flags & CCB_ABORT) != 0) {
! 422: /*
! 423: * If we already started an abort, wait for it
! 424: * to complete before clearing the CCB. We
! 425: * could instead just clear CCB_SENDING, but
! 426: * what if the mailbox was already received?
! 427: * The worst that happens here is that we clear
! 428: * the CCB a bit later than we need to. BFD.
! 429: */
! 430: goto next;
! 431: }
! 432: break;
! 433:
! 434: case BHA_MBI_ABORT:
! 435: case BHA_MBI_UNKNOWN:
! 436: /*
! 437: * Even if the CCB wasn't found, we clear it anyway.
! 438: * See preceding comment.
! 439: */
! 440: break;
! 441:
! 442: default:
! 443: printf("%s: bad mbi status %02x; skipping\n",
! 444: sc->sc_dev.dv_xname, wmbi->comp_stat);
! 445: goto next;
! 446: }
! 447:
! 448: timeout_del(&ccb->xs->stimeout);
! 449: bha_done(sc, ccb);
! 450:
! 451: next:
! 452: wmbi->comp_stat = BHA_MBI_FREE;
! 453: bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_control,
! 454: 0, sc->sc_dmamap_control->dm_mapsize,
! 455: BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
! 456: bha_nextmbx(wmbi, wmbx, mbi);
! 457: bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_control,
! 458: 0, sc->sc_dmamap_control->dm_mapsize,
! 459: BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
! 460: } while (wmbi->comp_stat != BHA_MBI_FREE);
! 461:
! 462: wmbx->tmbi = wmbi;
! 463: }
! 464:
! 465: /*
! 466: * Catch an interrupt from the adaptor
! 467: */
! 468: int
! 469: bha_intr(arg)
! 470: void *arg;
! 471: {
! 472: struct bha_softc *sc = arg;
! 473: bus_space_tag_t iot = sc->sc_iot;
! 474: bus_space_handle_t ioh = sc->sc_ioh;
! 475: u_char sts;
! 476:
! 477: #ifdef BHADEBUG
! 478: printf("%s: bha_intr ", sc->sc_dev.dv_xname);
! 479: #endif /* BHADEBUG */
! 480:
! 481: /*
! 482: * First acknowledge the interrupt, Then if it's not telling about
! 483: * a completed operation just return.
! 484: */
! 485: sts = bus_space_read_1(iot, ioh, BHA_INTR_PORT);
! 486: if ((sts & BHA_INTR_ANYINTR) == 0)
! 487: return (0);
! 488: bus_space_write_1(iot, ioh, BHA_CTRL_PORT, BHA_CTRL_IRST);
! 489:
! 490: #ifdef BHADIAG
! 491: /* Make sure we clear CCB_SENDING before finishing a CCB. */
! 492: bha_collect_mbo(sc);
! 493: #endif
! 494:
! 495: /* Mail box out empty? */
! 496: if (sts & BHA_INTR_MBOA) {
! 497: struct bha_toggle toggle;
! 498:
! 499: toggle.cmd.opcode = BHA_MBO_INTR_EN;
! 500: toggle.cmd.enable = 0;
! 501: bha_cmd(iot, ioh, sc,
! 502: sizeof(toggle.cmd), (u_char *)&toggle.cmd,
! 503: 0, (u_char *)0);
! 504: bha_start_ccbs(sc);
! 505: }
! 506:
! 507: /* Mail box in full? */
! 508: if (sts & BHA_INTR_MBIF)
! 509: bha_finish_ccbs(sc);
! 510:
! 511: return (1);
! 512: }
! 513:
! 514: integrate void
! 515: bha_reset_ccb(sc, ccb)
! 516: struct bha_softc *sc;
! 517: struct bha_ccb *ccb;
! 518: {
! 519:
! 520: ccb->flags = 0;
! 521: }
! 522:
! 523: /*
! 524: * A ccb is put onto the free list.
! 525: */
! 526: void
! 527: bha_free_ccb(sc, ccb)
! 528: struct bha_softc *sc;
! 529: struct bha_ccb *ccb;
! 530: {
! 531: int s;
! 532:
! 533: s = splbio();
! 534:
! 535: bha_reset_ccb(sc, ccb);
! 536: TAILQ_INSERT_HEAD(&sc->sc_free_ccb, ccb, chain);
! 537:
! 538: /*
! 539: * If there were none, wake anybody waiting for one to come free,
! 540: * starting with queued entries.
! 541: */
! 542: if (TAILQ_NEXT(ccb, chain) == NULL)
! 543: wakeup(&sc->sc_free_ccb);
! 544:
! 545: splx(s);
! 546: }
! 547:
! 548: integrate int
! 549: bha_init_ccb(sc, ccb)
! 550: struct bha_softc *sc;
! 551: struct bha_ccb *ccb;
! 552: {
! 553: bus_dma_tag_t dmat = sc->sc_dmat;
! 554: int hashnum, error;
! 555:
! 556: /*
! 557: * Create the DMA map for this CCB.
! 558: */
! 559: error = bus_dmamap_create(dmat, BHA_MAXXFER, BHA_NSEG, BHA_MAXXFER,
! 560: 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW | sc->sc_dmaflags,
! 561: &ccb->dmamap_xfer);
! 562: if (error) {
! 563: printf("%s: unable to create ccb DMA map, error = %d\n",
! 564: sc->sc_dev.dv_xname, error);
! 565: return (error);
! 566: }
! 567:
! 568: /*
! 569: * put in the phystokv hash table
! 570: * Never gets taken out.
! 571: */
! 572: ccb->hashkey = sc->sc_dmamap_control->dm_segs[0].ds_addr +
! 573: BHA_CCB_OFF(ccb);
! 574: hashnum = CCB_HASH(ccb->hashkey);
! 575: ccb->nexthash = sc->sc_ccbhash[hashnum];
! 576: sc->sc_ccbhash[hashnum] = ccb;
! 577: bha_reset_ccb(sc, ccb);
! 578: return (0);
! 579: }
! 580:
! 581: /*
! 582: * Create a set of ccbs and add them to the free list. Called once
! 583: * by bha_init(). We return the number of CCBs successfully created.
! 584: */
! 585: int
! 586: bha_create_ccbs(sc, ccbstore, count)
! 587: struct bha_softc *sc;
! 588: struct bha_ccb *ccbstore;
! 589: int count;
! 590: {
! 591: struct bha_ccb *ccb;
! 592: int i, error;
! 593:
! 594: bzero(ccbstore, sizeof(struct bha_ccb) * count);
! 595: for (i = 0; i < count; i++) {
! 596: ccb = &ccbstore[i];
! 597: if ((error = bha_init_ccb(sc, ccb)) != 0) {
! 598: printf("%s: unable to initialize ccb, error = %d\n",
! 599: sc->sc_dev.dv_xname, error);
! 600: goto out;
! 601: }
! 602: TAILQ_INSERT_TAIL(&sc->sc_free_ccb, ccb, chain);
! 603: }
! 604: out:
! 605: return (i);
! 606: }
! 607:
! 608: /*
! 609: * Get a free ccb
! 610: *
! 611: * If there are none, see if we can allocate a new one. If so, put it in
! 612: * the hash table too otherwise either return an error or sleep.
! 613: */
! 614: struct bha_ccb *
! 615: bha_get_ccb(sc, flags)
! 616: struct bha_softc *sc;
! 617: int flags;
! 618: {
! 619: struct bha_ccb *ccb;
! 620: int s;
! 621:
! 622: s = splbio();
! 623:
! 624: /*
! 625: * If we can and have to, sleep waiting for one to come free
! 626: * but only if we can't allocate a new one.
! 627: */
! 628: for (;;) {
! 629: ccb = TAILQ_FIRST(&sc->sc_free_ccb);
! 630: if (ccb) {
! 631: TAILQ_REMOVE(&sc->sc_free_ccb, ccb, chain);
! 632: break;
! 633: }
! 634: if ((flags & SCSI_NOSLEEP) != 0)
! 635: goto out;
! 636: tsleep(&sc->sc_free_ccb, PRIBIO, "bhaccb", 0);
! 637: }
! 638:
! 639: ccb->flags |= CCB_ALLOC;
! 640:
! 641: out:
! 642: splx(s);
! 643: return (ccb);
! 644: }
! 645:
! 646: /*
! 647: * Given a physical address, find the ccb that it corresponds to.
! 648: */
! 649: struct bha_ccb *
! 650: bha_ccb_phys_kv(sc, ccb_phys)
! 651: struct bha_softc *sc;
! 652: u_long ccb_phys;
! 653: {
! 654: int hashnum = CCB_HASH(ccb_phys);
! 655: struct bha_ccb *ccb = sc->sc_ccbhash[hashnum];
! 656:
! 657: while (ccb) {
! 658: if (ccb->hashkey == ccb_phys)
! 659: break;
! 660: ccb = ccb->nexthash;
! 661: }
! 662: return (ccb);
! 663: }
! 664:
! 665: /*
! 666: * Queue a CCB to be sent to the controller, and send it if possible.
! 667: */
! 668: void
! 669: bha_queue_ccb(sc, ccb)
! 670: struct bha_softc *sc;
! 671: struct bha_ccb *ccb;
! 672: {
! 673:
! 674: timeout_set(&ccb->xs->stimeout, bha_timeout, ccb);
! 675: TAILQ_INSERT_TAIL(&sc->sc_waiting_ccb, ccb, chain);
! 676: bha_start_ccbs(sc);
! 677: }
! 678:
! 679: /*
! 680: * Garbage collect mailboxes that are no longer in use.
! 681: */
! 682: void
! 683: bha_collect_mbo(sc)
! 684: struct bha_softc *sc;
! 685: {
! 686: struct bha_mbx_out *wmbo; /* Mail Box Out pointer */
! 687: #ifdef BHADIAG
! 688: struct bha_ccb *ccb;
! 689: #endif
! 690:
! 691: wmbo = wmbx->cmbo;
! 692:
! 693: while (sc->sc_mbofull > 0) {
! 694: bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_control,
! 695: 0, sc->sc_dmamap_control->dm_mapsize,
! 696: BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
! 697: if (wmbo->cmd != BHA_MBO_FREE)
! 698: break;
! 699:
! 700: #ifdef BHADIAG
! 701: ccb = bha_ccb_phys_kv(sc, phystol(wmbo->ccb_addr));
! 702: ccb->flags &= ~CCB_SENDING;
! 703: #endif
! 704:
! 705: --sc->sc_mbofull;
! 706: bha_nextmbx(wmbo, wmbx, mbo);
! 707: }
! 708:
! 709: wmbx->cmbo = wmbo;
! 710: }
! 711:
! 712: /*
! 713: * Send as many CCBs as we have empty mailboxes for.
! 714: */
! 715: void
! 716: bha_start_ccbs(sc)
! 717: struct bha_softc *sc;
! 718: {
! 719: bus_space_tag_t iot = sc->sc_iot;
! 720: bus_space_handle_t ioh = sc->sc_ioh;
! 721: struct bha_mbx_out *wmbo; /* Mail Box Out pointer */
! 722: struct bha_ccb *ccb;
! 723: struct scsi_xfer *xs;
! 724:
! 725: wmbo = wmbx->tmbo;
! 726:
! 727: while ((ccb = TAILQ_FIRST(&sc->sc_waiting_ccb)) != NULL) {
! 728:
! 729: xs = ccb->xs;
! 730: if (sc->sc_mbofull >= BHA_MBX_SIZE) {
! 731: bha_collect_mbo(sc);
! 732: if (sc->sc_mbofull >= BHA_MBX_SIZE) {
! 733: struct bha_toggle toggle;
! 734:
! 735: toggle.cmd.opcode = BHA_MBO_INTR_EN;
! 736: toggle.cmd.enable = 1;
! 737: bha_cmd(iot, ioh, sc,
! 738: sizeof(toggle.cmd), (u_char *)&toggle.cmd,
! 739: 0, (u_char *)0);
! 740: break;
! 741: }
! 742: }
! 743:
! 744: TAILQ_REMOVE(&sc->sc_waiting_ccb, ccb, chain);
! 745: #ifdef BHADIAG
! 746: ccb->flags |= CCB_SENDING;
! 747: #endif
! 748:
! 749: /* Link ccb to mbo. */
! 750: ltophys(sc->sc_dmamap_control->dm_segs[0].ds_addr +
! 751: BHA_CCB_OFF(ccb), wmbo->ccb_addr);
! 752: if (ccb->flags & CCB_ABORT)
! 753: wmbo->cmd = BHA_MBO_ABORT;
! 754: else
! 755: wmbo->cmd = BHA_MBO_START;
! 756:
! 757: bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_control,
! 758: 0, sc->sc_dmamap_control->dm_mapsize,
! 759: BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
! 760:
! 761: /* Tell the card to poll immediately. */
! 762: bus_space_write_1(iot, ioh, BHA_CMD_PORT, BHA_START_SCSI);
! 763:
! 764: if ((xs->flags & SCSI_POLL) == 0)
! 765: timeout_add(&xs->stimeout, (ccb->timeout * hz) / 1000);
! 766:
! 767: ++sc->sc_mbofull;
! 768: bha_nextmbx(wmbo, wmbx, mbo);
! 769: }
! 770:
! 771: wmbx->tmbo = wmbo;
! 772: }
! 773:
! 774: /*
! 775: * We have a ccb which has been processed by the
! 776: * adaptor, now we look to see how the operation
! 777: * went. Wake up the owner if waiting
! 778: */
! 779: void
! 780: bha_done(sc, ccb)
! 781: struct bha_softc *sc;
! 782: struct bha_ccb *ccb;
! 783: {
! 784: bus_dma_tag_t dmat = sc->sc_dmat;
! 785: struct scsi_sense_data *s1, *s2;
! 786: struct scsi_xfer *xs = ccb->xs;
! 787:
! 788: SC_DEBUG(xs->sc_link, SDEV_DB2, ("bha_done\n"));
! 789:
! 790: /*
! 791: * If we were a data transfer, unload the map that described
! 792: * the data buffer.
! 793: */
! 794: if (xs->datalen) {
! 795: bus_dmamap_sync(dmat, ccb->dmamap_xfer,
! 796: 0, ccb->dmamap_xfer->dm_mapsize,
! 797: (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_POSTREAD :
! 798: BUS_DMASYNC_POSTWRITE);
! 799: bus_dmamap_unload(dmat, ccb->dmamap_xfer);
! 800: }
! 801:
! 802: /*
! 803: * Otherwise, put the results of the operation
! 804: * into the xfer and call whoever started it
! 805: */
! 806: #ifdef BHADIAG
! 807: if (ccb->flags & CCB_SENDING) {
! 808: printf("%s: exiting ccb still in transit!\n",
! 809: sc->sc_dev.dv_xname);
! 810: Debugger();
! 811: return;
! 812: }
! 813: #endif
! 814: if ((ccb->flags & CCB_ALLOC) == 0) {
! 815: printf("%s: exiting ccb not allocated!\n",
! 816: sc->sc_dev.dv_xname);
! 817: Debugger();
! 818: return;
! 819: }
! 820: if (xs->error == XS_NOERROR) {
! 821: if (ccb->host_stat != BHA_OK) {
! 822: switch (ccb->host_stat) {
! 823: case BHA_SEL_TIMEOUT: /* No response */
! 824: xs->error = XS_SELTIMEOUT;
! 825: break;
! 826: default: /* Other scsi protocol messes */
! 827: printf("%s: host_stat %x\n",
! 828: sc->sc_dev.dv_xname, ccb->host_stat);
! 829: xs->error = XS_DRIVER_STUFFUP;
! 830: break;
! 831: }
! 832: } else if (ccb->target_stat != SCSI_OK) {
! 833: switch (ccb->target_stat) {
! 834: case SCSI_CHECK:
! 835: s1 = &ccb->scsi_sense;
! 836: s2 = &xs->sense;
! 837: *s2 = *s1;
! 838: xs->error = XS_SENSE;
! 839: break;
! 840: case SCSI_BUSY:
! 841: xs->error = XS_BUSY;
! 842: break;
! 843: default:
! 844: printf("%s: target_stat %x\n",
! 845: sc->sc_dev.dv_xname, ccb->target_stat);
! 846: xs->error = XS_DRIVER_STUFFUP;
! 847: break;
! 848: }
! 849: } else
! 850: xs->resid = 0;
! 851: }
! 852: bha_free_ccb(sc, ccb);
! 853: xs->flags |= ITSDONE;
! 854: scsi_done(xs);
! 855:
! 856: /*
! 857: * If there are queue entries in the software queue, try to
! 858: * run the first one. We should be more or less guaranteed
! 859: * to succeed, since we just freed a CCB.
! 860: *
! 861: * NOTE: bha_scsi_cmd() relies on our calling it with
! 862: * the first entry in the queue.
! 863: */
! 864: if ((xs = LIST_FIRST(&sc->sc_queue)) != NULL)
! 865: (void) bha_scsi_cmd(xs);
! 866: }
! 867:
! 868: /*
! 869: * Find the board and find its irq/drq
! 870: */
! 871: int
! 872: bha_find(iot, ioh, sc)
! 873: bus_space_tag_t iot;
! 874: bus_space_handle_t ioh;
! 875: struct bha_probe_data *sc;
! 876: {
! 877: int i, iswide;
! 878: u_char sts;
! 879: struct bha_extended_inquire inquire;
! 880: struct bha_config config;
! 881: int irq, drq;
! 882:
! 883: /* Check something is at the ports we need to access */
! 884: sts = bus_space_read_1(iot, ioh, BHA_STAT_PORT);
! 885: if (sts == 0xFF) {
! 886: #ifdef BHADEBUG
! 887: if (bha_debug)
! 888: printf("bha_find: Not present\n");
! 889: #endif /* BHADEBUG */
! 890: return (0);
! 891: }
! 892:
! 893: /*
! 894: * Reset board, If it doesn't respond, assume
! 895: * that it's not there.. good for the probe
! 896: */
! 897:
! 898: bus_space_write_1(iot, ioh, BHA_CTRL_PORT,
! 899: BHA_CTRL_HRST | BHA_CTRL_SRST);
! 900:
! 901: for (i = BHA_RESET_TIMEOUT; i--;) {
! 902: delay(100);
! 903: sts = bus_space_read_1(iot, ioh, BHA_STAT_PORT);
! 904: if (sts == (BHA_STAT_IDLE | BHA_STAT_INIT))
! 905: break;
! 906: }
! 907: if (i < 0) {
! 908: #ifdef BHADEBUG
! 909: if (bha_debug)
! 910: printf("bha_find: No answer from board a=%x sts=%b\n",
! 911: ioh, sts, BHA_STAT_BITS);
! 912: #endif /* BHADEBUG */
! 913: return (0);
! 914: }
! 915:
! 916: /*
! 917: * The BusLogic cards implement an Adaptec 1542 (aha)-compatible
! 918: * interface. The native bha interface is not compatible with
! 919: * an aha. 1542. We need to ensure that we never match an
! 920: * Adaptec 1542. We must also avoid sending Adaptec-compatible
! 921: * commands to a real bha, lest it go into 1542 emulation mode.
! 922: * (On an indirect bus like ISA, we should always probe for BusLogic
! 923: * interfaces before Adaptec interfaces).
! 924: */
! 925:
! 926: /*
! 927: * Make sure we don't match an AHA-1542A or AHA-1542B, by checking
! 928: * for an extended-geometry register. The 1542[AB] don't have one.
! 929: */
! 930: sts = bus_space_read_1(iot, ioh, BHA_EXTGEOM_PORT);
! 931: if (sts == 0xFF)
! 932: return (0);
! 933:
! 934: /*
! 935: * Check that we actually know how to use this board.
! 936: */
! 937: delay(1000);
! 938: inquire.cmd.opcode = BHA_INQUIRE_EXTENDED;
! 939: inquire.cmd.len = sizeof(inquire.reply);
! 940: i = bha_cmd(iot, ioh, NULL,
! 941: sizeof(inquire.cmd), (u_char *)&inquire.cmd,
! 942: sizeof(inquire.reply), (u_char *)&inquire.reply);
! 943:
! 944: /*
! 945: * Some 1542Cs (CP, perhaps not CF, may depend on firmware rev)
! 946: * have the extended-geometry register and also respond to
! 947: * BHA_INQUIRE_EXTENDED. Make sure we never match such cards,
! 948: * by checking the size of the reply is what a BusLogic card returns.
! 949: */
! 950: if (i) {
! 951: #ifdef BHADEBUG
! 952: printf("bha_find: board returned %d instead of %d to %s\n",
! 953: i, sizeof(inquire.reply), "INQUIRE_EXTENDED");
! 954: #endif
! 955: return (0);
! 956: }
! 957:
! 958: /* OK, we know we've found a buslogic adaptor. */
! 959:
! 960: switch (inquire.reply.bus_type) {
! 961: case BHA_BUS_TYPE_24BIT:
! 962: case BHA_BUS_TYPE_32BIT:
! 963: break;
! 964: case BHA_BUS_TYPE_MCA:
! 965: /* We don't grok MicroChannel (yet). */
! 966: return (0);
! 967: default:
! 968: printf("bha_find: illegal bus type %c\n",
! 969: inquire.reply.bus_type);
! 970: return (0);
! 971: }
! 972:
! 973: /* Note if we have a wide bus. */
! 974: iswide = inquire.reply.scsi_flags & BHA_SCSI_WIDE;
! 975:
! 976: /*
! 977: * Assume we have a board at this stage setup dma channel from
! 978: * jumpers and save int level
! 979: */
! 980: delay(1000);
! 981: config.cmd.opcode = BHA_INQUIRE_CONFIG;
! 982: bha_cmd(iot, ioh, NULL,
! 983: sizeof(config.cmd), (u_char *)&config.cmd,
! 984: sizeof(config.reply), (u_char *)&config.reply);
! 985: switch (config.reply.chan) {
! 986: case EISADMA:
! 987: drq = -1;
! 988: break;
! 989: case CHAN0:
! 990: drq = 0;
! 991: break;
! 992: case CHAN5:
! 993: drq = 5;
! 994: break;
! 995: case CHAN6:
! 996: drq = 6;
! 997: break;
! 998: case CHAN7:
! 999: drq = 7;
! 1000: break;
! 1001: default:
! 1002: printf("bha_find: illegal drq setting %x\n",
! 1003: config.reply.chan);
! 1004: return (0);
! 1005: }
! 1006:
! 1007: switch (config.reply.intr) {
! 1008: case INT9:
! 1009: irq = 9;
! 1010: break;
! 1011: case INT10:
! 1012: irq = 10;
! 1013: break;
! 1014: case INT11:
! 1015: irq = 11;
! 1016: break;
! 1017: case INT12:
! 1018: irq = 12;
! 1019: break;
! 1020: case INT14:
! 1021: irq = 14;
! 1022: break;
! 1023: case INT15:
! 1024: irq = 15;
! 1025: break;
! 1026: default:
! 1027: printf("bha_find: illegal irq setting %x\n",
! 1028: config.reply.intr);
! 1029: return (0);
! 1030: }
! 1031:
! 1032: /* if we want to fill in softc, do so now */
! 1033: if (sc != NULL) {
! 1034: sc->sc_irq = irq;
! 1035: sc->sc_drq = drq;
! 1036: sc->sc_scsi_dev = config.reply.scsi_dev;
! 1037: sc->sc_iswide = iswide;
! 1038: }
! 1039:
! 1040: return (1);
! 1041: }
! 1042:
! 1043:
! 1044: /*
! 1045: * Disable the ISA-compatibility ioports on PCI bha devices,
! 1046: * to ensure they're not autoconfigured a second time as an ISA bha.
! 1047: */
! 1048: int
! 1049: bha_disable_isacompat(sc)
! 1050: struct bha_softc *sc;
! 1051: {
! 1052: struct bha_isadisable isa_disable;
! 1053:
! 1054: isa_disable.cmd.opcode = BHA_MODIFY_IOPORT;
! 1055: isa_disable.cmd.modifier = BHA_IOMODIFY_DISABLE1;
! 1056: bha_cmd(sc->sc_iot, sc->sc_ioh, sc,
! 1057: sizeof(isa_disable.cmd), (u_char *)&isa_disable.cmd,
! 1058: 0, (u_char *)0);
! 1059: return (0);
! 1060: }
! 1061:
! 1062:
! 1063: /*
! 1064: * Start the board, ready for normal operation
! 1065: */
! 1066: int
! 1067: bha_init(sc)
! 1068: struct bha_softc *sc;
! 1069: {
! 1070: bus_space_tag_t iot = sc->sc_iot;
! 1071: bus_space_handle_t ioh = sc->sc_ioh;
! 1072: bus_dma_segment_t seg;
! 1073: struct bha_devices devices;
! 1074: struct bha_setup setup;
! 1075: struct bha_mailbox mailbox;
! 1076: struct bha_period period;
! 1077: int error, i, j, initial_ccbs, rlen, rseg;
! 1078:
! 1079: /* Enable round-robin scheme - appeared at firmware rev. 3.31. */
! 1080: if (strcmp(sc->sc_firmware, "3.31") >= 0) {
! 1081: struct bha_toggle toggle;
! 1082:
! 1083: toggle.cmd.opcode = BHA_ROUND_ROBIN;
! 1084: toggle.cmd.enable = 1;
! 1085: bha_cmd(iot, ioh, sc,
! 1086: sizeof(toggle.cmd), (u_char *)&toggle.cmd,
! 1087: 0, (u_char *)0);
! 1088: }
! 1089:
! 1090: /*
! 1091: * Inquire installed devices (to force synchronous negotiation).
! 1092: */
! 1093:
! 1094: /*
! 1095: * Poll targets 0 - 7.
! 1096: */
! 1097: devices.cmd.opcode = BHA_INQUIRE_DEVICES;
! 1098: bha_cmd(iot, ioh, sc,
! 1099: sizeof(devices.cmd), (u_char *)&devices.cmd,
! 1100: sizeof(devices.reply), (u_char *)&devices.reply);
! 1101:
! 1102: /* Count installed units. */
! 1103: initial_ccbs = 0;
! 1104: for (i = 0; i < 8; i++) {
! 1105: for (j = 0; j < 8; j++) {
! 1106: if (((devices.reply.lun_map[i] >> j) & 1) == 1)
! 1107: initial_ccbs++;
! 1108: }
! 1109: }
! 1110:
! 1111: /*
! 1112: * Poll targets 8 - 15 if we have a wide bus.
! 1113: */
! 1114: if (ISWIDE(sc)) {
! 1115: devices.cmd.opcode = BHA_INQUIRE_DEVICES_2;
! 1116: bha_cmd(iot, ioh, sc,
! 1117: sizeof(devices.cmd), (u_char *)&devices.cmd,
! 1118: sizeof(devices.reply), (u_char *)&devices.reply);
! 1119:
! 1120: for (i = 0; i < 8; i++) {
! 1121: for (j = 0; j < 8; j++) {
! 1122: if (((devices.reply.lun_map[i] >> j) & 1) == 1)
! 1123: initial_ccbs++;
! 1124: }
! 1125: }
! 1126: }
! 1127:
! 1128: initial_ccbs *= sc->sc_link.openings;
! 1129: if (initial_ccbs > BHA_CCB_MAX)
! 1130: initial_ccbs = BHA_CCB_MAX;
! 1131: if (initial_ccbs == 0) /* yes, this can happen */
! 1132: initial_ccbs = sc->sc_link.openings;
! 1133:
! 1134: /* Obtain setup information from. */
! 1135: rlen = sizeof(setup.reply) +
! 1136: (ISWIDE(sc) ? sizeof(setup.reply_w) : 0);
! 1137: setup.cmd.opcode = BHA_INQUIRE_SETUP;
! 1138: setup.cmd.len = rlen;
! 1139: bha_cmd(iot, ioh, sc,
! 1140: sizeof(setup.cmd), (u_char *)&setup.cmd,
! 1141: rlen, (u_char *)&setup.reply);
! 1142:
! 1143: printf("%s: %s, %s\n", sc->sc_dev.dv_xname,
! 1144: setup.reply.sync_neg ? "sync" : "async",
! 1145: setup.reply.parity ? "parity" : "no parity");
! 1146:
! 1147: for (i = 0; i < 8; i++)
! 1148: period.reply.period[i] = setup.reply.sync[i].period * 5 + 20;
! 1149: if (ISWIDE(sc)) {
! 1150: for (i = 0; i < 8; i++)
! 1151: period.reply_w.period[i] =
! 1152: setup.reply_w.sync_high[i].period * 5 + 20;
! 1153: }
! 1154:
! 1155: if (sc->sc_firmware[0] >= '3') {
! 1156: rlen = sizeof(period.reply) +
! 1157: (ISWIDE(sc) ? sizeof(period.reply_w) : 0);
! 1158: period.cmd.opcode = BHA_INQUIRE_PERIOD;
! 1159: period.cmd.len = sizeof(period.reply);
! 1160: bha_cmd(iot, ioh, sc,
! 1161: sizeof(period.cmd), (u_char *)&period.cmd,
! 1162: rlen, (u_char *)&period.reply);
! 1163: }
! 1164:
! 1165: for (i = 0; i < 8; i++) {
! 1166: if (!setup.reply.sync[i].valid ||
! 1167: (!setup.reply.sync[i].offset &&
! 1168: !setup.reply.sync[i].period))
! 1169: continue;
! 1170: printf("%s targ %d: sync, offset %d, period %dnsec\n",
! 1171: sc->sc_dev.dv_xname, i,
! 1172: setup.reply.sync[i].offset, period.reply.period[i] * 10);
! 1173: }
! 1174: if (ISWIDE(sc)) {
! 1175: for (i = 0; i < 8; i++) {
! 1176: if (!setup.reply_w.sync_high[i].valid ||
! 1177: (!setup.reply_w.sync_high[i].offset &&
! 1178: !setup.reply_w.sync_high[i].period))
! 1179: continue;
! 1180: printf("%s targ %d: sync, offset %d, period %dnsec\n",
! 1181: sc->sc_dev.dv_xname, i + 8,
! 1182: setup.reply_w.sync_high[i].offset,
! 1183: period.reply_w.period[i] * 10);
! 1184: }
! 1185: }
! 1186:
! 1187: /*
! 1188: * Allocate the mailbox and control blocks.
! 1189: */
! 1190: if ((error = bus_dmamem_alloc(sc->sc_dmat, sizeof(struct bha_control),
! 1191: NBPG, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT)) != 0) {
! 1192: printf("%s: unable to allocate control structures, "
! 1193: "error = %d\n", sc->sc_dev.dv_xname, error);
! 1194: return (error);
! 1195: }
! 1196: if ((error = bus_dmamem_map(sc->sc_dmat, &seg, rseg,
! 1197: sizeof(struct bha_control), (caddr_t *)&sc->sc_control,
! 1198: BUS_DMA_NOWAIT)) != 0) {
! 1199: printf("%s: unable to map control structures, error = %d\n",
! 1200: sc->sc_dev.dv_xname, error);
! 1201: return (error);
! 1202: }
! 1203:
! 1204: /*
! 1205: * Create and load the DMA map used for the mailbox and
! 1206: * control blocks.
! 1207: */
! 1208: if ((error = bus_dmamap_create(sc->sc_dmat, sizeof(struct bha_control),
! 1209: 1, sizeof(struct bha_control), 0, BUS_DMA_NOWAIT | sc->sc_dmaflags,
! 1210: &sc->sc_dmamap_control)) != 0) {
! 1211: printf("%s: unable to create control DMA map, error = %d\n",
! 1212: sc->sc_dev.dv_xname, error);
! 1213: return (error);
! 1214: }
! 1215: if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap_control,
! 1216: sc->sc_control, sizeof(struct bha_control), NULL,
! 1217: BUS_DMA_NOWAIT)) != 0) {
! 1218: printf("%s: unable to load control DMA map, error = %d\n",
! 1219: sc->sc_dev.dv_xname, error);
! 1220: return (error);
! 1221: }
! 1222:
! 1223: /*
! 1224: * Initialize the control blocks.
! 1225: */
! 1226: i = bha_create_ccbs(sc, sc->sc_control->bc_ccbs, initial_ccbs);
! 1227: if (i == 0) {
! 1228: printf("%s: unable to create control blocks\n",
! 1229: sc->sc_dev.dv_xname);
! 1230: return (ENOMEM);
! 1231: } else if (i != initial_ccbs) {
! 1232: printf("%s: WARNING: only %d of %d control blocks created\n",
! 1233: sc->sc_dev.dv_xname, i, initial_ccbs);
! 1234: }
! 1235:
! 1236: /*
! 1237: * Set up initial mail box for round-robin operation.
! 1238: */
! 1239: for (i = 0; i < BHA_MBX_SIZE; i++) {
! 1240: wmbx->mbo[i].cmd = BHA_MBO_FREE;
! 1241: bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_control,
! 1242: 0, sc->sc_dmamap_control->dm_mapsize,
! 1243: BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
! 1244: wmbx->mbi[i].comp_stat = BHA_MBI_FREE;
! 1245: bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_control,
! 1246: 0, sc->sc_dmamap_control->dm_mapsize,
! 1247: BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
! 1248: }
! 1249: wmbx->cmbo = wmbx->tmbo = &wmbx->mbo[0];
! 1250: wmbx->tmbi = &wmbx->mbi[0];
! 1251: sc->sc_mbofull = 0;
! 1252:
! 1253: /* Initialize mail box. */
! 1254: mailbox.cmd.opcode = BHA_MBX_INIT_EXTENDED;
! 1255: mailbox.cmd.nmbx = BHA_MBX_SIZE;
! 1256: ltophys(sc->sc_dmamap_control->dm_segs[0].ds_addr +
! 1257: offsetof(struct bha_control, bc_mbx), mailbox.cmd.addr);
! 1258: bha_cmd(iot, ioh, sc,
! 1259: sizeof(mailbox.cmd), (u_char *)&mailbox.cmd,
! 1260: 0, (u_char *)0);
! 1261: return (0);
! 1262: }
! 1263:
! 1264: void
! 1265: bha_inquire_setup_information(sc)
! 1266: struct bha_softc *sc;
! 1267: {
! 1268: bus_space_tag_t iot = sc->sc_iot;
! 1269: bus_space_handle_t ioh = sc->sc_ioh;
! 1270: struct bha_model model;
! 1271: struct bha_revision revision;
! 1272: struct bha_digit digit;
! 1273: char *p;
! 1274:
! 1275: /*
! 1276: * Get the firmware revision.
! 1277: */
! 1278: p = sc->sc_firmware;
! 1279: revision.cmd.opcode = BHA_INQUIRE_REVISION;
! 1280: bha_cmd(iot, ioh, sc,
! 1281: sizeof(revision.cmd), (u_char *)&revision.cmd,
! 1282: sizeof(revision.reply), (u_char *)&revision.reply);
! 1283: *p++ = revision.reply.firm_revision;
! 1284: *p++ = '.';
! 1285: *p++ = revision.reply.firm_version;
! 1286: digit.cmd.opcode = BHA_INQUIRE_REVISION_3;
! 1287: bha_cmd(iot, ioh, sc,
! 1288: sizeof(digit.cmd), (u_char *)&digit.cmd,
! 1289: sizeof(digit.reply), (u_char *)&digit.reply);
! 1290: *p++ = digit.reply.digit;
! 1291: if (revision.reply.firm_revision >= '3' ||
! 1292: (revision.reply.firm_revision == '3' &&
! 1293: revision.reply.firm_version >= '3')) {
! 1294: digit.cmd.opcode = BHA_INQUIRE_REVISION_4;
! 1295: bha_cmd(iot, ioh, sc,
! 1296: sizeof(digit.cmd), (u_char *)&digit.cmd,
! 1297: sizeof(digit.reply), (u_char *)&digit.reply);
! 1298: *p++ = digit.reply.digit;
! 1299: }
! 1300: while (p > sc->sc_firmware && (p[-1] == ' ' || p[-1] == '\0'))
! 1301: p--;
! 1302: *p = '\0';
! 1303:
! 1304: /*
! 1305: * Get the model number.
! 1306: */
! 1307: if (revision.reply.firm_revision >= '3') {
! 1308: p = sc->sc_model;
! 1309: model.cmd.opcode = BHA_INQUIRE_MODEL;
! 1310: model.cmd.len = sizeof(model.reply);
! 1311: bha_cmd(iot, ioh, sc,
! 1312: sizeof(model.cmd), (u_char *)&model.cmd,
! 1313: sizeof(model.reply), (u_char *)&model.reply);
! 1314: *p++ = model.reply.id[0];
! 1315: *p++ = model.reply.id[1];
! 1316: *p++ = model.reply.id[2];
! 1317: *p++ = model.reply.id[3];
! 1318: while (p > sc->sc_model && (p[-1] == ' ' || p[-1] == '\0'))
! 1319: p--;
! 1320: *p++ = model.reply.version[0];
! 1321: *p++ = model.reply.version[1];
! 1322: while (p > sc->sc_model && (p[-1] == ' ' || p[-1] == '\0'))
! 1323: p--;
! 1324: *p = '\0';
! 1325: } else
! 1326: strlcpy(sc->sc_model, "542B", sizeof sc->sc_model);
! 1327: }
! 1328:
! 1329: void
! 1330: bhaminphys(bp)
! 1331: struct buf *bp;
! 1332: {
! 1333:
! 1334: if (bp->b_bcount > BHA_MAXXFER)
! 1335: bp->b_bcount = BHA_MAXXFER;
! 1336: minphys(bp);
! 1337: }
! 1338:
! 1339: /*
! 1340: * start a scsi operation given the command and the data address. Also needs
! 1341: * the unit, target and lu.
! 1342: */
! 1343: int
! 1344: bha_scsi_cmd(xs)
! 1345: struct scsi_xfer *xs;
! 1346: {
! 1347: struct scsi_link *sc_link = xs->sc_link;
! 1348: struct bha_softc *sc = sc_link->adapter_softc;
! 1349: bus_dma_tag_t dmat = sc->sc_dmat;
! 1350: struct bha_ccb *ccb;
! 1351: int error, seg, flags, s;
! 1352: int fromqueue = 0, dontqueue = 0;
! 1353:
! 1354: SC_DEBUG(sc_link, SDEV_DB2, ("bha_scsi_cmd\n"));
! 1355:
! 1356: s = splbio(); /* protect the queue */
! 1357:
! 1358: /*
! 1359: * If we're running the queue from bha_done(), we've been
! 1360: * called with the first queue entry as our argument.
! 1361: */
! 1362: if (xs == LIST_FIRST(&sc->sc_queue)) {
! 1363: xs = bha_dequeue(sc);
! 1364: fromqueue = 1;
! 1365: goto get_ccb;
! 1366: }
! 1367:
! 1368: /* Polled requests can't be queued for later. */
! 1369: dontqueue = xs->flags & SCSI_POLL;
! 1370:
! 1371: /*
! 1372: * If there are jobs in the queue, run them first.
! 1373: */
! 1374: if (!LIST_EMPTY(&sc->sc_queue)) {
! 1375: /*
! 1376: * If we can't queue, we have to abort, since
! 1377: * we have to preserve order.
! 1378: */
! 1379: if (dontqueue) {
! 1380: splx(s);
! 1381: return (TRY_AGAIN_LATER);
! 1382: }
! 1383:
! 1384: /*
! 1385: * Swap with the first queue entry.
! 1386: */
! 1387: bha_enqueue(sc, xs, 0);
! 1388: xs = bha_dequeue(sc);
! 1389: fromqueue = 1;
! 1390: }
! 1391:
! 1392: get_ccb:
! 1393: /*
! 1394: * get a ccb to use. If the transfer
! 1395: * is from a buf (possibly from interrupt time)
! 1396: * then we can't allow it to sleep
! 1397: */
! 1398: flags = xs->flags;
! 1399: if ((ccb = bha_get_ccb(sc, flags)) == NULL) {
! 1400: /*
! 1401: * If we can't queue, we lose.
! 1402: */
! 1403: if (dontqueue) {
! 1404: splx(s);
! 1405: return (TRY_AGAIN_LATER);
! 1406: }
! 1407:
! 1408: /*
! 1409: * Stuff ourselves into the queue, in front
! 1410: * if we came off in the first place.
! 1411: */
! 1412: bha_enqueue(sc, xs, fromqueue);
! 1413: splx(s);
! 1414: return (SUCCESSFULLY_QUEUED);
! 1415: }
! 1416:
! 1417: splx(s); /* done playing with the queue */
! 1418:
! 1419: ccb->xs = xs;
! 1420: ccb->timeout = xs->timeout;
! 1421:
! 1422: /*
! 1423: * Put all the arguments for the xfer in the ccb
! 1424: */
! 1425: if (flags & SCSI_RESET) {
! 1426: ccb->opcode = BHA_RESET_CCB;
! 1427: ccb->scsi_cmd_length = 0;
! 1428: } else {
! 1429: /* can't use S/G if zero length */
! 1430: ccb->opcode = (xs->datalen ? BHA_INIT_SCAT_GATH_CCB
! 1431: : BHA_INITIATOR_CCB);
! 1432: bcopy(xs->cmd, &ccb->scsi_cmd,
! 1433: ccb->scsi_cmd_length = xs->cmdlen);
! 1434: }
! 1435:
! 1436: if (xs->datalen) {
! 1437: /*
! 1438: * Map the DMA transfer.
! 1439: */
! 1440: #ifdef TFS
! 1441: if (flags & SCSI_DATA_UIO) {
! 1442: error = bus_dmamap_load_uio(dmat,
! 1443: ccb->dmamap_xfer, (struct uio *)xs->data,
! 1444: (flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT :
! 1445: BUS_DMA_WAITOK);
! 1446: } else
! 1447: #endif /* TFS */
! 1448: {
! 1449: error = bus_dmamap_load(dmat,
! 1450: ccb->dmamap_xfer, xs->data, xs->datalen, NULL,
! 1451: (flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT :
! 1452: BUS_DMA_WAITOK);
! 1453: }
! 1454:
! 1455: if (error) {
! 1456: if (error == EFBIG) {
! 1457: printf("%s: bha_scsi_cmd, more than %d"
! 1458: " dma segments\n",
! 1459: sc->sc_dev.dv_xname, BHA_NSEG);
! 1460: } else {
! 1461: printf("%s: bha_scsi_cmd, error %d loading"
! 1462: " dma map\n",
! 1463: sc->sc_dev.dv_xname, error);
! 1464: }
! 1465: goto bad;
! 1466: }
! 1467:
! 1468: bus_dmamap_sync(dmat, ccb->dmamap_xfer,
! 1469: 0, ccb->dmamap_xfer->dm_mapsize,
! 1470: (flags & SCSI_DATA_IN) ? BUS_DMASYNC_PREREAD :
! 1471: BUS_DMASYNC_PREWRITE);
! 1472:
! 1473: /*
! 1474: * Load the hardware scatter/gather map with the
! 1475: * contents of the DMA map.
! 1476: */
! 1477: for (seg = 0; seg < ccb->dmamap_xfer->dm_nsegs; seg++) {
! 1478: ltophys(ccb->dmamap_xfer->dm_segs[seg].ds_addr,
! 1479: ccb->scat_gath[seg].seg_addr);
! 1480: ltophys(ccb->dmamap_xfer->dm_segs[seg].ds_len,
! 1481: ccb->scat_gath[seg].seg_len);
! 1482: }
! 1483:
! 1484: ltophys(sc->sc_dmamap_control->dm_segs[0].ds_addr +
! 1485: BHA_CCB_OFF(ccb) + offsetof(struct bha_ccb, scat_gath),
! 1486: ccb->data_addr);
! 1487: ltophys(ccb->dmamap_xfer->dm_nsegs *
! 1488: sizeof(struct bha_scat_gath), ccb->data_length);
! 1489: } else {
! 1490: /*
! 1491: * No data xfer, use non S/G values.
! 1492: */
! 1493: ltophys(0, ccb->data_addr);
! 1494: ltophys(0, ccb->data_length);
! 1495: }
! 1496:
! 1497: ccb->data_out = 0;
! 1498: ccb->data_in = 0;
! 1499: ccb->target = sc_link->target;
! 1500: ccb->lun = sc_link->lun;
! 1501: ltophys(sc->sc_dmamap_control->dm_segs[0].ds_addr +
! 1502: BHA_CCB_OFF(ccb) + offsetof(struct bha_ccb, scsi_sense),
! 1503: ccb->sense_ptr);
! 1504: ccb->req_sense_length = sizeof(ccb->scsi_sense);
! 1505: ccb->host_stat = 0x00;
! 1506: ccb->target_stat = 0x00;
! 1507: ccb->link_id = 0;
! 1508: ltophys(0, ccb->link_addr);
! 1509:
! 1510: bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_control,
! 1511: 0, sc->sc_dmamap_control->dm_mapsize,
! 1512: BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
! 1513:
! 1514: s = splbio();
! 1515: bha_queue_ccb(sc, ccb);
! 1516: splx(s);
! 1517:
! 1518: /*
! 1519: * Usually return SUCCESSFULLY QUEUED
! 1520: */
! 1521: SC_DEBUG(sc_link, SDEV_DB3, ("cmd_sent\n"));
! 1522: if ((flags & SCSI_POLL) == 0)
! 1523: return (SUCCESSFULLY_QUEUED);
! 1524:
! 1525: /*
! 1526: * If we can't use interrupts, poll on completion
! 1527: */
! 1528: if (bha_poll(sc, xs, ccb->timeout)) {
! 1529: bha_timeout(ccb);
! 1530: if (bha_poll(sc, xs, ccb->timeout))
! 1531: bha_timeout(ccb);
! 1532: }
! 1533: return (COMPLETE);
! 1534:
! 1535: bad:
! 1536: xs->error = XS_DRIVER_STUFFUP;
! 1537: bha_free_ccb(sc, ccb);
! 1538: return (COMPLETE);
! 1539: }
! 1540:
! 1541: /*
! 1542: * Poll a particular unit, looking for a particular xs
! 1543: */
! 1544: int
! 1545: bha_poll(sc, xs, count)
! 1546: struct bha_softc *sc;
! 1547: struct scsi_xfer *xs;
! 1548: int count;
! 1549: {
! 1550: bus_space_tag_t iot = sc->sc_iot;
! 1551: bus_space_handle_t ioh = sc->sc_ioh;
! 1552:
! 1553: /* timeouts are in msec, so we loop in 1000 usec cycles */
! 1554: while (count) {
! 1555: /*
! 1556: * If we had interrupts enabled, would we
! 1557: * have got an interrupt?
! 1558: */
! 1559: if (bus_space_read_1(iot, ioh, BHA_INTR_PORT) &
! 1560: BHA_INTR_ANYINTR)
! 1561: bha_intr(sc);
! 1562: if (xs->flags & ITSDONE)
! 1563: return (0);
! 1564: delay(1000); /* only happens in boot so ok */
! 1565: count--;
! 1566: }
! 1567: return (1);
! 1568: }
! 1569:
! 1570: void
! 1571: bha_timeout(arg)
! 1572: void *arg;
! 1573: {
! 1574: struct bha_ccb *ccb = arg;
! 1575: struct scsi_xfer *xs = ccb->xs;
! 1576: struct scsi_link *sc_link = xs->sc_link;
! 1577: struct bha_softc *sc = sc_link->adapter_softc;
! 1578: int s;
! 1579:
! 1580: sc_print_addr(sc_link);
! 1581: printf("timed out");
! 1582:
! 1583: s = splbio();
! 1584:
! 1585: #ifdef BHADIAG
! 1586: /*
! 1587: * If the ccb's mbx is not free, then the board has gone Far East?
! 1588: */
! 1589: bha_collect_mbo(sc);
! 1590: if (ccb->flags & CCB_SENDING) {
! 1591: printf("%s: not taking commands!\n", sc->sc_dev.dv_xname);
! 1592: Debugger();
! 1593: }
! 1594: #endif
! 1595:
! 1596: /*
! 1597: * If it has been through before, then
! 1598: * a previous abort has failed, don't
! 1599: * try abort again
! 1600: */
! 1601: if (ccb->flags & CCB_ABORT) {
! 1602: /* abort timed out */
! 1603: printf(" AGAIN\n");
! 1604: /* XXX Must reset! */
! 1605: } else {
! 1606: /* abort the operation that has timed out */
! 1607: printf("\n");
! 1608: ccb->xs->error = XS_TIMEOUT;
! 1609: ccb->timeout = BHA_ABORT_TIMEOUT;
! 1610: ccb->flags |= CCB_ABORT;
! 1611: bha_queue_ccb(sc, ccb);
! 1612: }
! 1613:
! 1614: splx(s);
! 1615: }
CVSweb