Annotation of sys/dev/eisa/aha1742.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: aha1742.c,v 1.25 2007/05/08 16:03:20 deraadt Exp $ */
! 2: /* $NetBSD: aha1742.c,v 1.61 1996/05/12 23:40:01 mycroft Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1994 Charles Hannum. All rights reserved.
! 6: *
! 7: * Redistribution and use in source and binary forms, with or without
! 8: * modification, are permitted provided that the following conditions
! 9: * are met:
! 10: * 1. Redistributions of source code must retain the above copyright
! 11: * notice, this list of conditions and the following disclaimer.
! 12: * 2. Redistributions in binary form must reproduce the above copyright
! 13: * notice, this list of conditions and the following disclaimer in the
! 14: * documentation and/or other materials provided with the distribution.
! 15: * 3. All advertising materials mentioning features or use of this software
! 16: * must display the following acknowledgement:
! 17: * This product includes software developed by Charles Hannum.
! 18: * 4. The name of the author may not be used to endorse or promote products
! 19: * derived from this software without specific prior written permission.
! 20: *
! 21: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 22: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 23: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 24: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 25: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 26: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 27: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 28: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 29: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 30: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 31: */
! 32:
! 33: /*
! 34: * Originally written by Julian Elischer (julian@tfs.com)
! 35: * for TRW Financial Systems for use under the MACH(2.5) operating system.
! 36: *
! 37: * TRW Financial Systems, in accordance with their agreement with Carnegie
! 38: * Mellon University, makes this software available to CMU to distribute
! 39: * or use in any manner that they see fit as long as this message is kept with
! 40: * the software. For this reason TFS also grants any other persons or
! 41: * organisations permission to use or modify this software.
! 42: *
! 43: * TFS supplies this software to be publicly redistributed
! 44: * on the understanding that TFS is not responsible for the correct
! 45: * functioning of this software in any circumstances.
! 46: *
! 47: * commenced: Sun Sep 27 18:14:01 PDT 1992
! 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:
! 62: #include <machine/bus.h>
! 63: #include <machine/intr.h>
! 64:
! 65: #include <dev/eisa/eisareg.h>
! 66: #include <dev/eisa/eisavar.h>
! 67: #include <dev/eisa/eisadevs.h>
! 68:
! 69: #include <scsi/scsi_all.h>
! 70: #include <scsi/scsiconf.h>
! 71:
! 72: #ifndef DDB
! 73: #define Debugger() panic("should call debugger here (aha1742.c)")
! 74: #endif /* ! DDB */
! 75:
! 76: typedef u_long physaddr;
! 77: typedef u_long physlen;
! 78:
! 79: #define KVTOPHYS(x) kvtop((caddr_t)x)
! 80:
! 81: #define AHB_ECB_MAX 32 /* store up to 32 ECBs at one time */
! 82: #define ECB_HASH_SIZE 32 /* hash table size for phystokv */
! 83: #define ECB_HASH_SHIFT 9
! 84: #define ECB_HASH(x) ((((long)(x))>>ECB_HASH_SHIFT) & (ECB_HASH_SIZE - 1))
! 85:
! 86: #define AHB_NSEG 33 /* number of dma segments supported */
! 87:
! 88: /*
! 89: * EISA registers (offset from slot base)
! 90: */
! 91: #define EISA_VENDOR 0x0c80 /* vendor ID (2 ports) */
! 92: #define EISA_MODEL 0x0c82 /* model number (2 ports) */
! 93: #define EISA_CONTROL 0x0c84
! 94: #define EISA_RESET 0x04
! 95: #define EISA_ERROR 0x02
! 96: #define EISA_ENABLE 0x01
! 97:
! 98: /*
! 99: * AHA1740 EISA board mode registers (Offset from slot base)
! 100: */
! 101: #define PORTADDR 0xCC0
! 102: #define PORTADDR_ENHANCED 0x80
! 103: #define BIOSADDR 0xCC1
! 104: #define INTDEF 0xCC2
! 105: #define SCSIDEF 0xCC3
! 106: #define BUSDEF 0xCC4
! 107: #define RESV0 0xCC5
! 108: #define RESV1 0xCC6
! 109: #define RESV2 0xCC7
! 110: /**** bit definitions for INTDEF ****/
! 111: #define INT9 0x00
! 112: #define INT10 0x01
! 113: #define INT11 0x02
! 114: #define INT12 0x03
! 115: #define INT14 0x05
! 116: #define INT15 0x06
! 117: #define INTHIGH 0x08 /* int high=ACTIVE (else edge) */
! 118: #define INTEN 0x10
! 119: /**** bit definitions for SCSIDEF ****/
! 120: #define HSCSIID 0x0F /* our SCSI ID */
! 121: #define RSTPWR 0x10 /* reset scsi bus on power up or reset */
! 122: /**** bit definitions for BUSDEF ****/
! 123: #define B0uS 0x00 /* give up bus immediately */
! 124: #define B4uS 0x01 /* delay 4uSec. */
! 125: #define B8uS 0x02
! 126:
! 127: /*
! 128: * AHA1740 ENHANCED mode mailbox control regs (Offset from slot base)
! 129: */
! 130: #define MBOXOUT0 0xCD0
! 131: #define MBOXOUT1 0xCD1
! 132: #define MBOXOUT2 0xCD2
! 133: #define MBOXOUT3 0xCD3
! 134:
! 135: #define ATTN 0xCD4
! 136: #define G2CNTRL 0xCD5
! 137: #define G2INTST 0xCD6
! 138: #define G2STAT 0xCD7
! 139:
! 140: #define MBOXIN0 0xCD8
! 141: #define MBOXIN1 0xCD9
! 142: #define MBOXIN2 0xCDA
! 143: #define MBOXIN3 0xCDB
! 144:
! 145: #define G2STAT2 0xCDC
! 146:
! 147: /*
! 148: * Bit definitions for the 5 control/status registers
! 149: */
! 150: #define ATTN_TARGET 0x0F
! 151: #define ATTN_OPCODE 0xF0
! 152: #define OP_IMMED 0x10
! 153: #define AHB_TARG_RESET 0x80
! 154: #define OP_START_ECB 0x40
! 155: #define OP_ABORT_ECB 0x50
! 156:
! 157: #define G2CNTRL_SET_HOST_READY 0x20
! 158: #define G2CNTRL_CLEAR_EISA_INT 0x40
! 159: #define G2CNTRL_HARD_RESET 0x80
! 160:
! 161: #define G2INTST_TARGET 0x0F
! 162: #define G2INTST_INT_STAT 0xF0
! 163: #define AHB_ECB_OK 0x10
! 164: #define AHB_ECB_RECOVERED 0x50
! 165: #define AHB_HW_ERR 0x70
! 166: #define AHB_IMMED_OK 0xA0
! 167: #define AHB_ECB_ERR 0xC0
! 168: #define AHB_ASN 0xD0 /* for target mode */
! 169: #define AHB_IMMED_ERR 0xE0
! 170:
! 171: #define G2STAT_BUSY 0x01
! 172: #define G2STAT_INT_PEND 0x02
! 173: #define G2STAT_MBOX_EMPTY 0x04
! 174:
! 175: #define G2STAT2_HOST_READY 0x01
! 176:
! 177: struct ahb_dma_seg {
! 178: physaddr seg_addr;
! 179: physlen seg_len;
! 180: };
! 181:
! 182: struct ahb_ecb_status {
! 183: u_short status;
! 184: #define ST_DON 0x0001
! 185: #define ST_DU 0x0002
! 186: #define ST_QF 0x0008
! 187: #define ST_SC 0x0010
! 188: #define ST_DO 0x0020
! 189: #define ST_CH 0x0040
! 190: #define ST_INT 0x0080
! 191: #define ST_ASA 0x0100
! 192: #define ST_SNS 0x0200
! 193: #define ST_INI 0x0800
! 194: #define ST_ME 0x1000
! 195: #define ST_ECA 0x4000
! 196: u_char host_stat;
! 197: #define HS_OK 0x00
! 198: #define HS_CMD_ABORTED_HOST 0x04
! 199: #define HS_CMD_ABORTED_ADAPTER 0x05
! 200: #define HS_TIMED_OUT 0x11
! 201: #define HS_HARDWARE_ERR 0x20
! 202: #define HS_SCSI_RESET_ADAPTER 0x22
! 203: #define HS_SCSI_RESET_INCOMING 0x23
! 204: u_char target_stat;
! 205: u_long resid_count;
! 206: u_long resid_addr;
! 207: u_short addit_status;
! 208: u_char sense_len;
! 209: u_char unused[9];
! 210: u_char cdb[6];
! 211: };
! 212:
! 213: struct ahb_ecb {
! 214: u_char opcode;
! 215: #define ECB_SCSI_OP 0x01
! 216: u_char:4;
! 217: u_char options:3;
! 218: u_char:1;
! 219: short opt1;
! 220: #define ECB_CNE 0x0001
! 221: #define ECB_DI 0x0080
! 222: #define ECB_SES 0x0400
! 223: #define ECB_S_G 0x1000
! 224: #define ECB_DSB 0x4000
! 225: #define ECB_ARS 0x8000
! 226: short opt2;
! 227: #define ECB_LUN 0x0007
! 228: #define ECB_TAG 0x0008
! 229: #define ECB_TT 0x0030
! 230: #define ECB_ND 0x0040
! 231: #define ECB_DAT 0x0100
! 232: #define ECB_DIR 0x0200
! 233: #define ECB_ST 0x0400
! 234: #define ECB_CHK 0x0800
! 235: #define ECB_REC 0x4000
! 236: #define ECB_NRB 0x8000
! 237: u_short unused1;
! 238: physaddr data_addr;
! 239: physlen data_length;
! 240: physaddr status;
! 241: physaddr link_addr;
! 242: short unused2;
! 243: short unused3;
! 244: physaddr sense_ptr;
! 245: u_char req_sense_length;
! 246: u_char scsi_cmd_length;
! 247: short cksum;
! 248: struct scsi_generic scsi_cmd;
! 249: /*-----------------end of hardware supported fields----------------*/
! 250: TAILQ_ENTRY(ahb_ecb) chain;
! 251: struct ahb_ecb *nexthash;
! 252: long hashkey;
! 253: struct scsi_xfer *xs; /* the scsi_xfer for this cmd */
! 254: int flags;
! 255: #define ECB_FREE 0
! 256: #define ECB_ACTIVE 1
! 257: #define ECB_ABORTED 2
! 258: #define ECB_IMMED 4
! 259: #define ECB_IMMED_FAIL 8
! 260: struct ahb_dma_seg ahb_dma[AHB_NSEG];
! 261: struct ahb_ecb_status ecb_status;
! 262: struct scsi_sense_data ecb_sense;
! 263: };
! 264:
! 265: struct ahb_softc {
! 266: struct device sc_dev;
! 267: bus_space_tag_t sc_iot;
! 268: eisa_chipset_tag_t sc_ec;
! 269:
! 270: bus_space_handle_t sc_ioh;
! 271: int sc_irq;
! 272: void *sc_ih;
! 273:
! 274: struct ahb_ecb *immed_ecb; /* an outstanding immediete command */
! 275: struct ahb_ecb *ecbhash[ECB_HASH_SIZE];
! 276: TAILQ_HEAD(, ahb_ecb) free_ecb;
! 277: int numecbs;
! 278: int ahb_scsi_dev; /* our scsi id */
! 279: struct scsi_link sc_link;
! 280: };
! 281:
! 282: void ahb_send_mbox(struct ahb_softc *, int, struct ahb_ecb *);
! 283: int ahb_poll(struct ahb_softc *, struct scsi_xfer *, int);
! 284: void ahb_send_immed(struct ahb_softc *, int, u_long);
! 285: int ahbintr(void *);
! 286: void ahb_done(struct ahb_softc *, struct ahb_ecb *);
! 287: void ahb_free_ecb(struct ahb_softc *, struct ahb_ecb *, int);
! 288: struct ahb_ecb *ahb_get_ecb(struct ahb_softc *, int);
! 289: struct ahb_ecb *ahb_ecb_phys_kv(struct ahb_softc *, physaddr);
! 290: int ahb_find(bus_space_tag_t, bus_space_handle_t, struct ahb_softc *);
! 291: void ahb_init(struct ahb_softc *);
! 292: void ahbminphys(struct buf *);
! 293: int ahb_scsi_cmd(struct scsi_xfer *);
! 294: void ahb_timeout(void *);
! 295: void ahb_print_ecb(struct ahb_ecb *);
! 296: void ahb_print_active_ecb(struct ahb_softc *);
! 297: int ahbprint(void *, const char *);
! 298:
! 299: #define MAX_SLOTS 15
! 300:
! 301: #ifdef AHBDEBUG
! 302: int ahb_debug = 0;
! 303: #endif /* AHBDEBUG */
! 304: #define AHB_SHOWECBS 0x01
! 305: #define AHB_SHOWINTS 0x02
! 306: #define AHB_SHOWCMDS 0x04
! 307: #define AHB_SHOWMISC 0x08
! 308:
! 309: struct scsi_adapter ahb_switch = {
! 310: ahb_scsi_cmd,
! 311: ahbminphys,
! 312: 0,
! 313: 0,
! 314: };
! 315:
! 316: /* the below structure is so we have a default dev struct for our link struct */
! 317: struct scsi_device ahb_dev = {
! 318: NULL, /* Use default error handler */
! 319: NULL, /* have a queue, served by this */
! 320: NULL, /* have no async handler */
! 321: NULL, /* Use default 'done' routine */
! 322: };
! 323:
! 324: int ahbmatch(struct device *, void *, void *);
! 325: void ahbattach(struct device *, struct device *, void *);
! 326:
! 327: struct cfattach ahb_ca = {
! 328: sizeof(struct ahb_softc), ahbmatch, ahbattach
! 329: };
! 330:
! 331: struct cfdriver ahb_cd = {
! 332: NULL, "ahb", DV_DULL
! 333: };
! 334:
! 335: /*
! 336: * Function to send a command out through a mailbox
! 337: */
! 338: void
! 339: ahb_send_mbox(sc, opcode, ecb)
! 340: struct ahb_softc *sc;
! 341: int opcode;
! 342: struct ahb_ecb *ecb;
! 343: {
! 344: bus_space_tag_t iot = sc->sc_iot;
! 345: bus_space_handle_t ioh = sc->sc_ioh;
! 346: int wait = 300; /* 1ms should be enough */
! 347:
! 348: while (--wait) {
! 349: if ((bus_space_read_1(iot, ioh, G2STAT) &
! 350: (G2STAT_BUSY | G2STAT_MBOX_EMPTY)) == (G2STAT_MBOX_EMPTY))
! 351: break;
! 352: delay(10);
! 353: }
! 354: if (!wait) {
! 355: printf("%s: board not responding\n", sc->sc_dev.dv_xname);
! 356: Debugger();
! 357: }
! 358:
! 359: /* don't know this will work */
! 360: bus_space_write_4(iot, ioh, MBOXOUT0, KVTOPHYS(ecb));
! 361: bus_space_write_1(iot, ioh, ATTN, opcode | ecb->xs->sc_link->target);
! 362: }
! 363:
! 364: /*
! 365: * Function to poll for command completion when in poll mode
! 366: */
! 367: int
! 368: ahb_poll(sc, xs, count)
! 369: struct ahb_softc *sc;
! 370: struct scsi_xfer *xs;
! 371: int count;
! 372: { /* in msec */
! 373: bus_space_tag_t iot = sc->sc_iot;
! 374: bus_space_handle_t ioh = sc->sc_ioh;
! 375:
! 376: while (count) {
! 377: /*
! 378: * If we had interrupts enabled, would we
! 379: * have got an interrupt?
! 380: */
! 381: if (bus_space_read_1(iot, ioh, G2STAT) & G2STAT_INT_PEND)
! 382: ahbintr(sc);
! 383: if (xs->flags & ITSDONE)
! 384: return 0;
! 385: delay(1000);
! 386: count--;
! 387: }
! 388: return 1;
! 389: }
! 390:
! 391: /*
! 392: * Function to send an immediate type command to the adapter
! 393: */
! 394: void
! 395: ahb_send_immed(sc, target, cmd)
! 396: struct ahb_softc *sc;
! 397: int target;
! 398: u_long cmd;
! 399: {
! 400: bus_space_tag_t iot = sc->sc_iot;
! 401: bus_space_handle_t ioh = sc->sc_ioh;
! 402: int wait = 100; /* 1 ms enough? */
! 403:
! 404: while (--wait) {
! 405: if ((bus_space_read_1(iot, ioh, G2STAT) &
! 406: (G2STAT_BUSY | G2STAT_MBOX_EMPTY)) == (G2STAT_MBOX_EMPTY))
! 407: break;
! 408: delay(10);
! 409: }
! 410: if (!wait) {
! 411: printf("%s: board not responding\n", sc->sc_dev.dv_xname);
! 412: Debugger();
! 413: }
! 414:
! 415: /* don't know this will work */
! 416: bus_space_write_4(iot, ioh, MBOXOUT0, cmd);
! 417: bus_space_write_1(iot, ioh, G2CNTRL, G2CNTRL_SET_HOST_READY);
! 418: bus_space_write_1(iot, ioh, ATTN, OP_IMMED | target);
! 419: }
! 420:
! 421: /*
! 422: * Check the slots looking for a board we recognise
! 423: * If we find one, note its address (slot) and call
! 424: * the actual probe routine to check it out.
! 425: */
! 426: int
! 427: ahbmatch(parent, match, aux)
! 428: struct device *parent;
! 429: void *match, *aux;
! 430: {
! 431: struct eisa_attach_args *ea = aux;
! 432: bus_space_tag_t iot = ea->ea_iot;
! 433: bus_space_handle_t ioh;
! 434: int rv;
! 435:
! 436: /* must match one of our known ID strings */
! 437: if (strcmp(ea->ea_idstring, "ADP0000") &&
! 438: strcmp(ea->ea_idstring, "ADP0001") &&
! 439: strcmp(ea->ea_idstring, "ADP0002") &&
! 440: strcmp(ea->ea_idstring, "ADP0400"))
! 441: return (0);
! 442:
! 443: if (bus_space_map(iot, EISA_SLOT_ADDR(ea->ea_slot), EISA_SLOT_SIZE, 0,
! 444: &ioh))
! 445: return (0);
! 446:
! 447: #ifdef notyet
! 448: /* This won't compile as-is, anyway. */
! 449: bus_space_write_1(iot, ioh, EISA_CONTROL, EISA_ENABLE | EISA_RESET);
! 450: delay(10);
! 451: bus_space_write_1(iot, ioh, EISA_CONTROL, EISA_ENABLE);
! 452: /* Wait for reset? */
! 453: delay(1000);
! 454: #endif
! 455:
! 456: rv = !ahb_find(iot, ioh, NULL);
! 457:
! 458: bus_space_unmap(ea->ea_iot, ioh, EISA_SLOT_SIZE);
! 459:
! 460: return (rv);
! 461: }
! 462:
! 463: int
! 464: ahbprint(aux, name)
! 465: void *aux;
! 466: const char *name;
! 467: {
! 468: return UNCONF;
! 469: }
! 470:
! 471: /*
! 472: * Attach all the sub-devices we can find
! 473: */
! 474: void
! 475: ahbattach(parent, self, aux)
! 476: struct device *parent, *self;
! 477: void *aux;
! 478: {
! 479: struct eisa_attach_args *ea = aux;
! 480: struct ahb_softc *sc = (void *)self;
! 481: struct scsibus_attach_args saa;
! 482: bus_space_tag_t iot = ea->ea_iot;
! 483: bus_space_handle_t ioh;
! 484: eisa_chipset_tag_t ec = ea->ea_ec;
! 485: eisa_intr_handle_t ih;
! 486: const char *model, *intrstr;
! 487:
! 488: sc->sc_iot = iot;
! 489: sc->sc_ec = ec;
! 490:
! 491: if (bus_space_map(iot, EISA_SLOT_ADDR(ea->ea_slot), EISA_SLOT_SIZE, 0,
! 492: &ioh))
! 493: panic("ahbattach: could not map I/O addresses");
! 494: sc->sc_ioh = ioh;
! 495: if (ahb_find(iot, ioh, sc))
! 496: panic("ahbattach: ahb_find failed!");
! 497:
! 498: ahb_init(sc);
! 499: TAILQ_INIT(&sc->free_ecb);
! 500:
! 501: /*
! 502: * fill in the prototype scsi_link.
! 503: */
! 504: sc->sc_link.adapter_softc = sc;
! 505: sc->sc_link.adapter_target = sc->ahb_scsi_dev;
! 506: sc->sc_link.adapter = &ahb_switch;
! 507: sc->sc_link.device = &ahb_dev;
! 508: sc->sc_link.openings = 2;
! 509:
! 510: if (!strcmp(ea->ea_idstring, "ADP0000"))
! 511: model = EISA_PRODUCT_ADP0000;
! 512: else if (!strcmp(ea->ea_idstring, "ADP0001"))
! 513: model = EISA_PRODUCT_ADP0001;
! 514: else if (!strcmp(ea->ea_idstring, "ADP0002"))
! 515: model = EISA_PRODUCT_ADP0002;
! 516: else if (!strcmp(ea->ea_idstring, "ADP0400"))
! 517: model = EISA_PRODUCT_ADP0400;
! 518: else
! 519: model = "unknown model!";
! 520: printf(": <%s> ", model);
! 521:
! 522: if (eisa_intr_map(ec, sc->sc_irq, &ih)) {
! 523: printf("%s: couldn't map interrupt (%d)\n",
! 524: sc->sc_dev.dv_xname, sc->sc_irq);
! 525: return;
! 526: }
! 527: intrstr = eisa_intr_string(ec, ih);
! 528: sc->sc_ih = eisa_intr_establish(ec, ih, IST_LEVEL, IPL_BIO,
! 529: ahbintr, sc, sc->sc_dev.dv_xname);
! 530: if (sc->sc_ih == NULL) {
! 531: printf("%s: couldn't establish interrupt",
! 532: sc->sc_dev.dv_xname);
! 533: if (intrstr != NULL)
! 534: printf(" at %s", intrstr);
! 535: printf("\n");
! 536: return;
! 537: }
! 538: if (intrstr != NULL)
! 539: printf("%s\n", intrstr);
! 540:
! 541: bzero(&saa, sizeof(saa));
! 542: saa.saa_sc_link = &sc->sc_link;
! 543:
! 544: /*
! 545: * ask the adapter what subunits are present
! 546: */
! 547: config_found(self, &saa, ahbprint);
! 548: }
! 549:
! 550: /*
! 551: * Catch an interrupt from the adaptor
! 552: */
! 553: int
! 554: ahbintr(arg)
! 555: void *arg;
! 556: {
! 557: struct ahb_softc *sc = arg;
! 558: bus_space_tag_t iot = sc->sc_iot;
! 559: bus_space_handle_t ioh = sc->sc_ioh;
! 560: struct ahb_ecb *ecb;
! 561: u_char ahbstat;
! 562: u_long mboxval;
! 563:
! 564: #ifdef AHBDEBUG
! 565: printf("%s: ahbintr ", sc->sc_dev.dv_xname);
! 566: #endif /* AHBDEBUG */
! 567:
! 568: if ((bus_space_read_1(iot, ioh, G2STAT) & G2STAT_INT_PEND) == 0)
! 569: return 0;
! 570:
! 571: for (;;) {
! 572: /*
! 573: * First get all the information and then
! 574: * acknowledge the interrupt
! 575: */
! 576: ahbstat = bus_space_read_1(iot, ioh, G2INTST);
! 577: mboxval = bus_space_read_4(iot, ioh, MBOXIN0);
! 578: bus_space_write_1(iot, ioh, G2CNTRL, G2CNTRL_CLEAR_EISA_INT);
! 579:
! 580: #ifdef AHBDEBUG
! 581: printf("status = 0x%x ", ahbstat);
! 582: #endif /*AHBDEBUG */
! 583:
! 584: /*
! 585: * Process the completed operation
! 586: */
! 587: switch (ahbstat & G2INTST_INT_STAT) {
! 588: case AHB_ECB_OK:
! 589: case AHB_ECB_RECOVERED:
! 590: case AHB_ECB_ERR:
! 591: ecb = ahb_ecb_phys_kv(sc, mboxval);
! 592: if (!ecb) {
! 593: printf("%s: BAD ECB RETURNED!\n",
! 594: sc->sc_dev.dv_xname);
! 595: continue; /* whatever it was, it'll timeout */
! 596: }
! 597: break;
! 598:
! 599: case AHB_IMMED_ERR:
! 600: ecb->flags |= ECB_IMMED_FAIL;
! 601: case AHB_IMMED_OK:
! 602: ecb = sc->immed_ecb;
! 603: sc->immed_ecb = 0;
! 604: break;
! 605:
! 606: default:
! 607: printf("%s: unexpected interrupt %x\n",
! 608: sc->sc_dev.dv_xname, ahbstat);
! 609: ecb = 0;
! 610: break;
! 611: }
! 612: if (ecb) {
! 613: #ifdef AHBDEBUG
! 614: if (ahb_debug & AHB_SHOWCMDS)
! 615: show_scsi_cmd(ecb->xs);
! 616: if ((ahb_debug & AHB_SHOWECBS) && ecb)
! 617: printf("<int ecb(%x)>", ecb);
! 618: #endif /*AHBDEBUG */
! 619: timeout_del(&ecb->xs->stimeout);
! 620: ahb_done(sc, ecb);
! 621: }
! 622:
! 623: if ((bus_space_read_1(iot, ioh, G2STAT) & G2STAT_INT_PEND) ==
! 624: 0)
! 625: return 1;
! 626: }
! 627: }
! 628:
! 629: /*
! 630: * We have a ecb which has been processed by the adaptor, now we look to see
! 631: * how the operation went.
! 632: */
! 633: void
! 634: ahb_done(sc, ecb)
! 635: struct ahb_softc *sc;
! 636: struct ahb_ecb *ecb;
! 637: {
! 638: struct ahb_ecb_status *stat = &ecb->ecb_status;
! 639: struct scsi_sense_data *s1, *s2;
! 640: struct scsi_xfer *xs = ecb->xs;
! 641:
! 642: SC_DEBUG(xs->sc_link, SDEV_DB2, ("ahb_done\n"));
! 643: /*
! 644: * Otherwise, put the results of the operation
! 645: * into the xfer and call whoever started it
! 646: */
! 647: if (ecb->flags & ECB_IMMED) {
! 648: if (ecb->flags & ECB_IMMED_FAIL)
! 649: xs->error = XS_DRIVER_STUFFUP;
! 650: goto done;
! 651: }
! 652: if (xs->error == XS_NOERROR) {
! 653: if (stat->host_stat != HS_OK) {
! 654: switch (stat->host_stat) {
! 655: case HS_SCSI_RESET_ADAPTER:
! 656: break;
! 657: case HS_SCSI_RESET_INCOMING:
! 658: break;
! 659: case HS_CMD_ABORTED_HOST:
! 660: case HS_CMD_ABORTED_ADAPTER:
! 661: xs->error = XS_DRIVER_STUFFUP;
! 662: break;
! 663: case HS_TIMED_OUT: /* No response */
! 664: xs->error = XS_SELTIMEOUT;
! 665: break;
! 666: default: /* Other scsi protocol messes */
! 667: printf("%s: host_stat %x\n",
! 668: sc->sc_dev.dv_xname, stat->host_stat);
! 669: xs->error = XS_DRIVER_STUFFUP;
! 670: }
! 671: } else if (stat->target_stat != SCSI_OK) {
! 672: switch (stat->target_stat) {
! 673: case SCSI_CHECK:
! 674: s1 = &ecb->ecb_sense;
! 675: s2 = &xs->sense;
! 676: *s2 = *s1;
! 677: xs->error = XS_SENSE;
! 678: break;
! 679: case SCSI_BUSY:
! 680: xs->error = XS_BUSY;
! 681: break;
! 682: default:
! 683: printf("%s: target_stat %x\n",
! 684: sc->sc_dev.dv_xname, stat->target_stat);
! 685: xs->error = XS_DRIVER_STUFFUP;
! 686: }
! 687: } else
! 688: xs->resid = 0;
! 689: }
! 690: done:
! 691: xs->flags |= ITSDONE;
! 692: ahb_free_ecb(sc, ecb, xs->flags);
! 693: scsi_done(xs);
! 694: }
! 695:
! 696: /*
! 697: * A ecb (and hence a mbx-out is put onto the
! 698: * free list.
! 699: */
! 700: void
! 701: ahb_free_ecb(sc, ecb, flags)
! 702: struct ahb_softc *sc;
! 703: struct ahb_ecb *ecb;
! 704: int flags;
! 705: {
! 706: int s;
! 707:
! 708: s = splbio();
! 709:
! 710: ecb->flags = ECB_FREE;
! 711: TAILQ_INSERT_HEAD(&sc->free_ecb, ecb, chain);
! 712:
! 713: /*
! 714: * If there were none, wake anybody waiting for one to come free,
! 715: * starting with queued entries.
! 716: */
! 717: if (TAILQ_NEXT(ecb, chain) == NULL)
! 718: wakeup(&sc->free_ecb);
! 719:
! 720: splx(s);
! 721: }
! 722:
! 723: static inline void ahb_init_ecb(struct ahb_softc *, struct ahb_ecb *);
! 724:
! 725: static inline void
! 726: ahb_init_ecb(sc, ecb)
! 727: struct ahb_softc *sc;
! 728: struct ahb_ecb *ecb;
! 729: {
! 730: int hashnum;
! 731:
! 732: bzero(ecb, sizeof(struct ahb_ecb));
! 733: /*
! 734: * put in the phystokv hash table
! 735: * Never gets taken out.
! 736: */
! 737: ecb->hashkey = KVTOPHYS(ecb);
! 738: hashnum = ECB_HASH(ecb->hashkey);
! 739: ecb->nexthash = sc->ecbhash[hashnum];
! 740: sc->ecbhash[hashnum] = ecb;
! 741: }
! 742:
! 743: static inline void ahb_reset_ecb(struct ahb_softc *, struct ahb_ecb *);
! 744:
! 745: static inline void
! 746: ahb_reset_ecb(sc, ecb)
! 747: struct ahb_softc *sc;
! 748: struct ahb_ecb *ecb;
! 749: {
! 750:
! 751: }
! 752:
! 753: /*
! 754: * Get a free ecb
! 755: *
! 756: * If there are none, see if we can allocate a new one. If so, put it in the
! 757: * hash table too otherwise either return an error or sleep.
! 758: */
! 759: struct ahb_ecb *
! 760: ahb_get_ecb(sc, flags)
! 761: struct ahb_softc *sc;
! 762: int flags;
! 763: {
! 764: struct ahb_ecb *ecb;
! 765: int s;
! 766:
! 767: s = splbio();
! 768:
! 769: /*
! 770: * If we can and have to, sleep waiting for one to come free
! 771: * but only if we can't allocate a new one.
! 772: */
! 773: for (;;) {
! 774: ecb = TAILQ_FIRST(&sc->free_ecb);
! 775: if (ecb) {
! 776: TAILQ_REMOVE(&sc->free_ecb, ecb, chain);
! 777: break;
! 778: }
! 779: if (sc->numecbs < AHB_ECB_MAX) {
! 780: ecb = (struct ahb_ecb *) malloc(sizeof(struct ahb_ecb),
! 781: M_TEMP, M_NOWAIT);
! 782: if (ecb) {
! 783: ahb_init_ecb(sc, ecb);
! 784: sc->numecbs++;
! 785: } else {
! 786: printf("%s: can't malloc ecb\n",
! 787: sc->sc_dev.dv_xname);
! 788: goto out;
! 789: }
! 790: break;
! 791: }
! 792: if ((flags & SCSI_NOSLEEP) != 0)
! 793: goto out;
! 794: tsleep(&sc->free_ecb, PRIBIO, "ahbecb", 0);
! 795: }
! 796:
! 797: ahb_reset_ecb(sc, ecb);
! 798: ecb->flags = ECB_ACTIVE;
! 799:
! 800: out:
! 801: splx(s);
! 802: return ecb;
! 803: }
! 804:
! 805: /*
! 806: * given a physical address, find the ecb that it corresponds to.
! 807: */
! 808: struct ahb_ecb *
! 809: ahb_ecb_phys_kv(sc, ecb_phys)
! 810: struct ahb_softc *sc;
! 811: physaddr ecb_phys;
! 812: {
! 813: int hashnum = ECB_HASH(ecb_phys);
! 814: struct ahb_ecb *ecb = sc->ecbhash[hashnum];
! 815:
! 816: while (ecb) {
! 817: if (ecb->hashkey == ecb_phys)
! 818: break;
! 819: ecb = ecb->nexthash;
! 820: }
! 821: return ecb;
! 822: }
! 823:
! 824: /*
! 825: * Start the board, ready for normal operation
! 826: */
! 827: int
! 828: ahb_find(iot, ioh, sc)
! 829: bus_space_tag_t iot;
! 830: bus_space_handle_t ioh;
! 831: struct ahb_softc *sc;
! 832: {
! 833: u_char intdef;
! 834: int i, irq, busid;
! 835: int wait = 1000; /* 1 sec enough? */
! 836:
! 837: bus_space_write_1(iot, ioh, PORTADDR, PORTADDR_ENHANCED);
! 838:
! 839: #define NO_NO 1
! 840: #ifdef NO_NO
! 841: /*
! 842: * reset board, If it doesn't respond, assume
! 843: * that it's not there.. good for the probe
! 844: */
! 845: bus_space_write_1(iot, ioh, G2CNTRL, G2CNTRL_HARD_RESET);
! 846: delay(1000);
! 847: bus_space_write_1(iot, ioh, G2CNTRL, 0);
! 848: delay(10000);
! 849: while (--wait) {
! 850: if ((bus_space_read_1(iot, ioh, G2STAT) & G2STAT_BUSY) == 0)
! 851: break;
! 852: delay(1000);
! 853: }
! 854: if (!wait) {
! 855: #ifdef AHBDEBUG
! 856: if (ahb_debug & AHB_SHOWMISC)
! 857: printf("ahb_find: No answer from aha1742 board\n");
! 858: #endif /*AHBDEBUG */
! 859: return ENXIO;
! 860: }
! 861: i = bus_space_read_1(iot, ioh, MBOXIN0);
! 862: if (i) {
! 863: printf("self test failed, val = 0x%x\n", i);
! 864: return EIO;
! 865: }
! 866:
! 867: /* Set it again, just to be sure. */
! 868: bus_space_write_1(iot, ioh, PORTADDR, PORTADDR_ENHANCED);
! 869: #endif
! 870:
! 871: while (bus_space_read_1(iot, ioh, G2STAT) & G2STAT_INT_PEND) {
! 872: printf(".");
! 873: bus_space_write_1(iot, ioh, G2CNTRL, G2CNTRL_CLEAR_EISA_INT);
! 874: delay(10000);
! 875: }
! 876:
! 877: intdef = bus_space_read_1(iot, ioh, INTDEF);
! 878: switch (intdef & 0x07) {
! 879: case INT9:
! 880: irq = 9;
! 881: break;
! 882: case INT10:
! 883: irq = 10;
! 884: break;
! 885: case INT11:
! 886: irq = 11;
! 887: break;
! 888: case INT12:
! 889: irq = 12;
! 890: break;
! 891: case INT14:
! 892: irq = 14;
! 893: break;
! 894: case INT15:
! 895: irq = 15;
! 896: break;
! 897: default:
! 898: printf("illegal int setting %x\n", intdef);
! 899: return EIO;
! 900: }
! 901:
! 902: /* make sure we can interrupt */
! 903: bus_space_write_1(iot, ioh, INTDEF, (intdef | INTEN));
! 904:
! 905: /* who are we on the scsi bus? */
! 906: busid = (bus_space_read_1(iot, ioh, SCSIDEF) & HSCSIID);
! 907:
! 908: /* if we want to fill in softc, do so now */
! 909: if (sc != NULL) {
! 910: sc->sc_irq = irq;
! 911: sc->ahb_scsi_dev = busid;
! 912: }
! 913:
! 914: /*
! 915: * Note that we are going and return (to probe)
! 916: */
! 917: return 0;
! 918: }
! 919:
! 920: void
! 921: ahb_init(sc)
! 922: struct ahb_softc *sc;
! 923: {
! 924:
! 925: }
! 926:
! 927: void
! 928: ahbminphys(bp)
! 929: struct buf *bp;
! 930: {
! 931:
! 932: if (bp->b_bcount > ((AHB_NSEG - 1) << PGSHIFT))
! 933: bp->b_bcount = ((AHB_NSEG - 1) << PGSHIFT);
! 934: minphys(bp);
! 935: }
! 936:
! 937: /*
! 938: * start a scsi operation given the command and the data address. Also needs
! 939: * the unit, target and lu.
! 940: */
! 941: int
! 942: ahb_scsi_cmd(xs)
! 943: struct scsi_xfer *xs;
! 944: {
! 945: struct scsi_link *sc_link = xs->sc_link;
! 946: struct ahb_softc *sc = sc_link->adapter_softc;
! 947: struct ahb_ecb *ecb;
! 948: struct ahb_dma_seg *sg;
! 949: int seg; /* scatter gather seg being worked on */
! 950: u_long thiskv, thisphys, nextphys;
! 951: int bytes_this_seg, bytes_this_page, datalen, flags;
! 952: #ifdef TFS
! 953: struct iovec *iovp;
! 954: #endif
! 955: int s;
! 956:
! 957: SC_DEBUG(sc_link, SDEV_DB2, ("ahb_scsi_cmd\n"));
! 958: /*
! 959: * get a ecb (mbox-out) to use. If the transfer
! 960: * is from a buf (possibly from interrupt time)
! 961: * then we can't allow it to sleep
! 962: */
! 963: flags = xs->flags;
! 964: if (flags & ITSDONE) {
! 965: printf("%s: done?\n", sc->sc_dev.dv_xname);
! 966: xs->flags &= ~ITSDONE;
! 967: }
! 968: if ((ecb = ahb_get_ecb(sc, flags)) == NULL) {
! 969: return TRY_AGAIN_LATER;
! 970: }
! 971: ecb->xs = xs;
! 972: timeout_set(&ecb->xs->stimeout, ahb_timeout, ecb);
! 973:
! 974: /*
! 975: * If it's a reset, we need to do an 'immediate'
! 976: * command, and store its ecb for later
! 977: * if there is already an immediate waiting,
! 978: * then WE must wait
! 979: */
! 980: if (flags & SCSI_RESET) {
! 981: ecb->flags |= ECB_IMMED;
! 982: if (sc->immed_ecb)
! 983: return TRY_AGAIN_LATER;
! 984: sc->immed_ecb = ecb;
! 985:
! 986: s = splbio();
! 987:
! 988: ahb_send_immed(sc, sc_link->target, AHB_TARG_RESET);
! 989:
! 990: if ((flags & SCSI_POLL) == 0) {
! 991: splx(s);
! 992: timeout_add(&ecb->xs->stimeout, (xs->timeout * hz) / 1000);
! 993: return SUCCESSFULLY_QUEUED;
! 994: }
! 995:
! 996: splx(s);
! 997:
! 998: /*
! 999: * If we can't use interrupts, poll on completion
! 1000: */
! 1001: if (ahb_poll(sc, xs, xs->timeout))
! 1002: ahb_timeout(ecb);
! 1003: return COMPLETE;
! 1004: }
! 1005:
! 1006: /*
! 1007: * Put all the arguments for the xfer in the ecb
! 1008: */
! 1009: ecb->opcode = ECB_SCSI_OP;
! 1010: ecb->opt1 = ECB_SES | ECB_DSB | ECB_ARS;
! 1011: if (xs->datalen)
! 1012: ecb->opt1 |= ECB_S_G;
! 1013: ecb->opt2 = sc_link->lun | ECB_NRB;
! 1014: ecb->scsi_cmd_length = xs->cmdlen;
! 1015: ecb->sense_ptr = KVTOPHYS(&ecb->ecb_sense);
! 1016: ecb->req_sense_length = sizeof(ecb->ecb_sense);
! 1017: ecb->status = KVTOPHYS(&ecb->ecb_status);
! 1018: ecb->ecb_status.host_stat = 0x00;
! 1019: ecb->ecb_status.target_stat = 0x00;
! 1020:
! 1021: if (xs->datalen && (flags & SCSI_RESET) == 0) {
! 1022: ecb->data_addr = KVTOPHYS(ecb->ahb_dma);
! 1023: sg = ecb->ahb_dma;
! 1024: seg = 0;
! 1025: #ifdef TFS
! 1026: if (flags & SCSI_DATA_UIO) {
! 1027: iovp = ((struct uio *) xs->data)->uio_iov;
! 1028: datalen = ((struct uio *) xs->data)->uio_iovcnt;
! 1029: xs->datalen = 0;
! 1030: while (datalen && seg < AHB_NSEG) {
! 1031: sg->seg_addr = (physaddr)iovp->iov_base;
! 1032: sg->seg_len = iovp->iov_len;
! 1033: xs->datalen += iovp->iov_len;
! 1034: SC_DEBUGN(sc_link, SDEV_DB4, ("(0x%x@0x%x)",
! 1035: iovp->iov_len, iovp->iov_base));
! 1036: sg++;
! 1037: iovp++;
! 1038: seg++;
! 1039: datalen--;
! 1040: }
! 1041: }
! 1042: else
! 1043: #endif /*TFS */
! 1044: {
! 1045: /*
! 1046: * Set up the scatter gather block
! 1047: */
! 1048: SC_DEBUG(sc_link, SDEV_DB4,
! 1049: ("%d @0x%x:- ", xs->datalen, xs->data));
! 1050: datalen = xs->datalen;
! 1051: thiskv = (long) xs->data;
! 1052: thisphys = KVTOPHYS(thiskv);
! 1053:
! 1054: while (datalen && seg < AHB_NSEG) {
! 1055: bytes_this_seg = 0;
! 1056:
! 1057: /* put in the base address */
! 1058: sg->seg_addr = thisphys;
! 1059:
! 1060: SC_DEBUGN(sc_link, SDEV_DB4, ("0x%x", thisphys));
! 1061:
! 1062: /* do it at least once */
! 1063: nextphys = thisphys;
! 1064: while (datalen && thisphys == nextphys) {
! 1065: /*
! 1066: * This page is contiguous (physically)
! 1067: * with the last, just extend the
! 1068: * length
! 1069: */
! 1070: /* how far to the end of the page */
! 1071: nextphys = (thisphys & ~PGOFSET) + NBPG;
! 1072: bytes_this_page = nextphys - thisphys;
! 1073: /**** or the data ****/
! 1074: bytes_this_page = min(bytes_this_page,
! 1075: datalen);
! 1076: bytes_this_seg += bytes_this_page;
! 1077: datalen -= bytes_this_page;
! 1078:
! 1079: /* get more ready for the next page */
! 1080: thiskv = (thiskv & ~PGOFSET) + NBPG;
! 1081: if (datalen)
! 1082: thisphys = KVTOPHYS(thiskv);
! 1083: }
! 1084: /*
! 1085: * next page isn't contiguous, finish the seg
! 1086: */
! 1087: SC_DEBUGN(sc_link, SDEV_DB4,
! 1088: ("(0x%x)", bytes_this_seg));
! 1089: sg->seg_len = bytes_this_seg;
! 1090: sg++;
! 1091: seg++;
! 1092: }
! 1093: }
! 1094: /*end of iov/kv decision */
! 1095: ecb->data_length = seg * sizeof(struct ahb_dma_seg);
! 1096: SC_DEBUGN(sc_link, SDEV_DB4, ("\n"));
! 1097: if (datalen) {
! 1098: /*
! 1099: * there's still data, must have run out of segs!
! 1100: */
! 1101: printf("%s: ahb_scsi_cmd, more than %d dma segs\n",
! 1102: sc->sc_dev.dv_xname, AHB_NSEG);
! 1103: xs->error = XS_DRIVER_STUFFUP;
! 1104: ahb_free_ecb(sc, ecb, flags);
! 1105: return COMPLETE;
! 1106: }
! 1107: } else { /* No data xfer, use non S/G values */
! 1108: ecb->data_addr = (physaddr)0;
! 1109: ecb->data_length = 0;
! 1110: }
! 1111: ecb->link_addr = (physaddr)0;
! 1112:
! 1113: /*
! 1114: * Put the scsi command in the ecb and start it
! 1115: */
! 1116: if ((flags & SCSI_RESET) == 0)
! 1117: bcopy(xs->cmd, &ecb->scsi_cmd, ecb->scsi_cmd_length);
! 1118:
! 1119: s = splbio();
! 1120:
! 1121: ahb_send_mbox(sc, OP_START_ECB, ecb);
! 1122:
! 1123: /*
! 1124: * Usually return SUCCESSFULLY QUEUED
! 1125: */
! 1126: if ((flags & SCSI_POLL) == 0) {
! 1127: splx(s);
! 1128: timeout_add(&ecb->xs->stimeout, (xs->timeout * hz) / 1000);
! 1129: return SUCCESSFULLY_QUEUED;
! 1130: }
! 1131:
! 1132: splx(s);
! 1133:
! 1134: /*
! 1135: * If we can't use interrupts, poll on completion
! 1136: */
! 1137: if (ahb_poll(sc, xs, xs->timeout)) {
! 1138: ahb_timeout(ecb);
! 1139: if (ahb_poll(sc, xs, 2000))
! 1140: ahb_timeout(ecb);
! 1141: }
! 1142: return COMPLETE;
! 1143: }
! 1144:
! 1145: void
! 1146: ahb_timeout(arg)
! 1147: void *arg;
! 1148: {
! 1149: struct ahb_ecb *ecb = arg;
! 1150: struct scsi_xfer *xs = ecb->xs;
! 1151: struct scsi_link *sc_link = xs->sc_link;
! 1152: struct ahb_softc *sc = sc_link->adapter_softc;
! 1153: int s;
! 1154:
! 1155: sc_print_addr(sc_link);
! 1156: printf("timed out");
! 1157:
! 1158: s = splbio();
! 1159:
! 1160: if (ecb->flags & ECB_IMMED) {
! 1161: printf("\n");
! 1162: ecb->xs->retries = 0; /* I MEAN IT ! */
! 1163: ecb->flags |= ECB_IMMED_FAIL;
! 1164: ahb_done(sc, ecb);
! 1165: splx(s);
! 1166: return;
! 1167: }
! 1168:
! 1169: /*
! 1170: * If it has been through before, then
! 1171: * a previous abort has failed, don't
! 1172: * try abort again
! 1173: */
! 1174: if (ecb->flags == ECB_ABORTED) {
! 1175: /* abort timed out */
! 1176: printf(" AGAIN\n");
! 1177: ecb->xs->retries = 0; /* I MEAN IT ! */
! 1178: ahb_done(sc, ecb);
! 1179: } else {
! 1180: /* abort the operation that has timed out */
! 1181: printf("\n");
! 1182: ecb->xs->error = XS_TIMEOUT;
! 1183: ecb->flags = ECB_ABORTED;
! 1184: ahb_send_mbox(sc, OP_ABORT_ECB, ecb);
! 1185: /* 2 secs for the abort */
! 1186: if ((xs->flags & SCSI_POLL) == 0)
! 1187: timeout_add(&ecb->xs->stimeout, 2 * hz);
! 1188: }
! 1189:
! 1190: splx(s);
! 1191: }
! 1192:
! 1193: #ifdef AHBDEBUG
! 1194: void
! 1195: ahb_print_ecb(ecb)
! 1196: struct ahb_ecb *ecb;
! 1197: {
! 1198: printf("ecb:%x op:%x cmdlen:%d senlen:%d\n",
! 1199: ecb, ecb->opcode, ecb->cdblen, ecb->senselen);
! 1200: printf(" datlen:%d hstat:%x tstat:%x flags:%x\n",
! 1201: ecb->datalen, ecb->ecb_status.host_stat,
! 1202: ecb->ecb_status.target_stat, ecb->flags);
! 1203: show_scsi_cmd(ecb->xs);
! 1204: }
! 1205:
! 1206: void
! 1207: ahb_print_active_ecb(sc)
! 1208: struct ahb_softc *sc;
! 1209: {
! 1210: struct ahb_ecb *ecb;
! 1211: int i = 0;
! 1212:
! 1213: while (i++ < ECB_HASH_SIZE) {
! 1214: ecb = sc->ecb_hash_list[i];
! 1215: while (ecb) {
! 1216: if (ecb->flags != ECB_FREE)
! 1217: ahb_print_ecb(ecb);
! 1218: ecb = ecb->hash_list;
! 1219: }
! 1220: }
! 1221: }
! 1222: #endif /* AHBDEBUG */
CVSweb