Annotation of sys/dev/ic/aic7xxx_inline.h, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: aic7xxx_inline.h,v 1.14 2007/05/14 01:37:49 deraadt Exp $ */
! 2: /* $NetBSD: aic7xxx_inline.h,v 1.4 2003/11/02 11:07:44 wiz Exp $ */
! 3:
! 4: /*
! 5: * Inline routines shareable across OS platforms.
! 6: *
! 7: * Copyright (c) 1994-2001 Justin T. Gibbs.
! 8: * Copyright (c) 2000-2001 Adaptec Inc.
! 9: * All rights reserved.
! 10: *
! 11: * Redistribution and use in source and binary forms, with or without
! 12: * modification, are permitted provided that the following conditions
! 13: * are met:
! 14: * 1. Redistributions of source code must retain the above copyright
! 15: * notice, this list of conditions, and the following disclaimer,
! 16: * without modification.
! 17: * 2. Redistributions in binary form must reproduce at minimum a disclaimer
! 18: * substantially similar to the "NO WARRANTY" disclaimer below
! 19: * ("Disclaimer") and any redistribution must be conditioned upon
! 20: * including a substantially similar Disclaimer requirement for further
! 21: * binary redistribution.
! 22: * 3. Neither the names of the above-listed copyright holders nor the names
! 23: * of any contributors may be used to endorse or promote products derived
! 24: * from this software without specific prior written permission.
! 25: *
! 26: * Alternatively, this software may be distributed under the terms of the
! 27: * GNU General Public License ("GPL") version 2 as published by the Free
! 28: * Software Foundation.
! 29: *
! 30: * NO WARRANTY
! 31: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
! 32: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
! 33: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
! 34: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
! 35: * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 36: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 37: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 38: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
! 39: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
! 40: * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 41: * POSSIBILITY OF SUCH DAMAGES.
! 42: *
! 43: * //depot/aic7xxx/aic7xxx/aic7xxx_inline.h#39 $
! 44: *
! 45: * $FreeBSD: /repoman/r/ncvs/src/sys/dev/aic7xxx/aic7xxx_inline.h,v 1.20 2003/01/20 20:44:55 gibbs Exp $
! 46: */
! 47: /*
! 48: * Ported from FreeBSD by Pascal Renauld, Network Storage Solutions, Inc. - April 2003
! 49: */
! 50:
! 51: #ifndef _AIC7XXX_INLINE_H_
! 52: #define _AIC7XXX_INLINE_H_
! 53:
! 54: #ifdef SMALL_KERNEL
! 55: #define IO_INLINE
! 56: #else
! 57: #define IO_INLINE static __inline
! 58: #define IO_EXPAND
! 59: #endif
! 60:
! 61: /************************* Sequencer Execution Control ************************/
! 62: IO_INLINE void ahc_pause_bug_fix(struct ahc_softc *ahc);
! 63: IO_INLINE int ahc_is_paused(struct ahc_softc *ahc);
! 64: IO_INLINE void ahc_pause(struct ahc_softc *ahc);
! 65: IO_INLINE void ahc_unpause(struct ahc_softc *ahc);
! 66:
! 67: #ifdef IO_EXPAND
! 68: /*
! 69: * Work around any chip bugs related to halting sequencer execution.
! 70: * On Ultra2 controllers, we must clear the CIOBUS stretch signal by
! 71: * reading a register that will set this signal and deassert it.
! 72: * Without this workaround, if the chip is paused, by an interrupt or
! 73: * manual pause while accessing scb ram, accesses to certain registers
! 74: * will hang the system (infinite pci retries).
! 75: */
! 76: IO_INLINE void
! 77: ahc_pause_bug_fix(struct ahc_softc *ahc)
! 78: {
! 79: if ((ahc->features & AHC_ULTRA2) != 0)
! 80: (void)ahc_inb(ahc, CCSCBCTL);
! 81: }
! 82:
! 83: /*
! 84: * Determine whether the sequencer has halted code execution.
! 85: * Returns non-zero status if the sequencer is stopped.
! 86: */
! 87: IO_INLINE int
! 88: ahc_is_paused(struct ahc_softc *ahc)
! 89: {
! 90: return ((ahc_inb(ahc, HCNTRL) & PAUSE) != 0);
! 91: }
! 92:
! 93: /*
! 94: * Request that the sequencer stop and wait, indefinitely, for it
! 95: * to stop. The sequencer will only acknowledge that it is paused
! 96: * once it has reached an instruction boundary and PAUSEDIS is
! 97: * cleared in the SEQCTL register. The sequencer may use PAUSEDIS
! 98: * for critical sections.
! 99: */
! 100: IO_INLINE void
! 101: ahc_pause(struct ahc_softc *ahc)
! 102: {
! 103: ahc_outb(ahc, HCNTRL, ahc->pause);
! 104:
! 105: /*
! 106: * Since the sequencer can disable pausing in a critical section, we
! 107: * must loop until it actually stops.
! 108: */
! 109: while (ahc_is_paused(ahc) == 0)
! 110: ;
! 111:
! 112: ahc_pause_bug_fix(ahc);
! 113: }
! 114:
! 115: /*
! 116: * Allow the sequencer to continue program execution.
! 117: * We check here to ensure that no additional interrupt
! 118: * sources that would cause the sequencer to halt have been
! 119: * asserted. If, for example, a SCSI bus reset is detected
! 120: * while we are fielding a different, pausing, interrupt type,
! 121: * we don't want to release the sequencer before going back
! 122: * into our interrupt handler and dealing with this new
! 123: * condition.
! 124: */
! 125: IO_INLINE void
! 126: ahc_unpause(struct ahc_softc *ahc)
! 127: {
! 128: if ((ahc_inb(ahc, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0)
! 129: ahc_outb(ahc, HCNTRL, ahc->unpause);
! 130: }
! 131: #endif /* IO_EXPAND */
! 132:
! 133: /*********************** Untagged Transaction Routines ************************/
! 134: IO_INLINE void ahc_freeze_untagged_queues(struct ahc_softc *ahc);
! 135: IO_INLINE void ahc_release_untagged_queues(struct ahc_softc *ahc);
! 136:
! 137: #ifdef IO_EXPAND
! 138: /*
! 139: * Block our completion routine from starting the next untagged
! 140: * transaction for this target or target lun.
! 141: */
! 142: IO_INLINE void
! 143: ahc_freeze_untagged_queues(struct ahc_softc *ahc)
! 144: {
! 145: if ((ahc->flags & AHC_SCB_BTT) == 0)
! 146: ahc->untagged_queue_lock++;
! 147: }
! 148:
! 149: /*
! 150: * Allow the next untagged transaction for this target or target lun
! 151: * to be executed. We use a counting semaphore to allow the lock
! 152: * to be acquired recursively. Once the count drops to zero, the
! 153: * transaction queues will be run.
! 154: */
! 155: IO_INLINE void
! 156: ahc_release_untagged_queues(struct ahc_softc *ahc)
! 157: {
! 158: if ((ahc->flags & AHC_SCB_BTT) == 0) {
! 159: ahc->untagged_queue_lock--;
! 160: if (ahc->untagged_queue_lock == 0)
! 161: ahc_run_untagged_queues(ahc);
! 162: }
! 163: }
! 164: #endif /* IO_EXPAND */
! 165:
! 166:
! 167: /************************** Memory mapping routines ***************************/
! 168: IO_INLINE struct ahc_dma_seg *
! 169: ahc_sg_bus_to_virt(struct scb *scb,
! 170: uint32_t sg_busaddr);
! 171: IO_INLINE uint32_t
! 172: ahc_sg_virt_to_bus(struct scb *scb,
! 173: struct ahc_dma_seg *sg);
! 174: IO_INLINE uint32_t
! 175: ahc_hscb_busaddr(struct ahc_softc *ahc, u_int index);
! 176: IO_INLINE void ahc_sync_scb(struct ahc_softc *ahc,
! 177: struct scb *scb, int op);
! 178: #ifdef AHC_TARGET_MODE
! 179: IO_INLINE uint32_t
! 180: ahc_targetcmd_offset(struct ahc_softc *ahc,
! 181: u_int index);
! 182: #endif
! 183:
! 184: #ifdef IO_EXPAND
! 185:
! 186: IO_INLINE struct ahc_dma_seg *
! 187: ahc_sg_bus_to_virt(struct scb *scb, uint32_t sg_busaddr)
! 188: {
! 189: int sg_index;
! 190:
! 191: sg_index = (sg_busaddr - scb->sg_list_phys)/sizeof(struct ahc_dma_seg);
! 192: /* sg_list_phys points to entry 1, not 0 */
! 193: sg_index++;
! 194:
! 195: return (&scb->sg_list[sg_index]);
! 196: }
! 197:
! 198: IO_INLINE uint32_t
! 199: ahc_sg_virt_to_bus(struct scb *scb, struct ahc_dma_seg *sg)
! 200: {
! 201: int sg_index;
! 202:
! 203: /* sg_list_phys points to entry 1, not 0 */
! 204: sg_index = sg - &scb->sg_list[1];
! 205:
! 206: return (scb->sg_list_phys + (sg_index * sizeof(*scb->sg_list)));
! 207: }
! 208:
! 209: IO_INLINE uint32_t
! 210: ahc_hscb_busaddr(struct ahc_softc *ahc, u_int index)
! 211: {
! 212: return (ahc->scb_data->hscb_busaddr
! 213: + (sizeof(struct hardware_scb) * index));
! 214: }
! 215:
! 216: IO_INLINE void
! 217: ahc_sync_scb(struct ahc_softc *ahc, struct scb *scb, int op)
! 218: {
! 219: ahc_dmamap_sync(ahc, ahc->parent_dmat,
! 220: ahc->scb_data->hscb_dmamap,
! 221: /*offset*/(scb->hscb - ahc->scb_data->hscbs) * sizeof(*scb->hscb),
! 222: /*len*/sizeof(*scb->hscb), op);
! 223: }
! 224:
! 225: #ifdef AHC_TARGET_MODE
! 226: IO_INLINE uint32_t
! 227: ahc_targetcmd_offset(struct ahc_softc *ahc, u_int index)
! 228: {
! 229: return (((uint8_t *)&ahc->targetcmds[index]) - ahc->qoutfifo);
! 230: }
! 231: #endif /* AHC_TARGET_MODE */
! 232: #endif /* IO_EXPAND */
! 233:
! 234: /******************************** Debugging ***********************************/
! 235: static __inline char *ahc_name(struct ahc_softc *ahc);
! 236:
! 237: static __inline char *
! 238: ahc_name(struct ahc_softc *ahc)
! 239: {
! 240: return (ahc->name);
! 241: }
! 242:
! 243: /*********************** Miscellaneous Support Functions ***********************/
! 244:
! 245: IO_INLINE void ahc_update_residual(struct ahc_softc *ahc,
! 246: struct scb *scb);
! 247: IO_INLINE struct ahc_initiator_tinfo *
! 248: ahc_fetch_transinfo(struct ahc_softc *ahc,
! 249: char channel, u_int our_id,
! 250: u_int remote_id,
! 251: struct ahc_tmode_tstate **tstate);
! 252:
! 253: IO_INLINE uint16_t
! 254: ahc_inw(struct ahc_softc *ahc, u_int port);
! 255: IO_INLINE void ahc_outw(struct ahc_softc *ahc, u_int port,
! 256: u_int value);
! 257: IO_INLINE uint32_t
! 258: ahc_inl(struct ahc_softc *ahc, u_int port);
! 259: IO_INLINE void ahc_outl(struct ahc_softc *ahc, u_int port,
! 260: uint32_t value);
! 261: IO_INLINE struct scb*
! 262: ahc_get_scb(struct ahc_softc *ahc);
! 263: IO_INLINE void ahc_free_scb(struct ahc_softc *ahc, struct scb *scb);
! 264: IO_INLINE struct scb *ahc_lookup_scb(struct ahc_softc *ahc, u_int tag);
! 265: IO_INLINE void ahc_swap_with_next_hscb(struct ahc_softc *ahc,
! 266: struct scb *scb);
! 267: IO_INLINE void ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb);
! 268: IO_INLINE struct scsi_sense_data *
! 269: ahc_get_sense_buf(struct ahc_softc *ahc,
! 270: struct scb *scb);
! 271: IO_INLINE uint32_t
! 272: ahc_get_sense_bufaddr(struct ahc_softc *ahc,
! 273: struct scb *scb);
! 274:
! 275: #ifdef IO_EXPAND
! 276:
! 277: /*
! 278: * Determine whether the sequencer reported a residual
! 279: * for this SCB/transaction.
! 280: */
! 281: IO_INLINE void
! 282: ahc_update_residual(struct ahc_softc *ahc, struct scb *scb)
! 283: {
! 284: uint32_t sgptr;
! 285:
! 286: sgptr = aic_le32toh(scb->hscb->sgptr);
! 287: if ((sgptr & SG_RESID_VALID) != 0)
! 288: ahc_calc_residual(ahc, scb);
! 289: }
! 290:
! 291: /*
! 292: * Return pointers to the transfer negotiation information
! 293: * for the specified our_id/remote_id pair.
! 294: */
! 295: IO_INLINE struct ahc_initiator_tinfo *
! 296: ahc_fetch_transinfo(struct ahc_softc *ahc, char channel, u_int our_id,
! 297: u_int remote_id, struct ahc_tmode_tstate **tstate)
! 298: {
! 299: /*
! 300: * Transfer data structures are stored from the perspective
! 301: * of the target role. Since the parameters for a connection
! 302: * in the initiator role to a given target are the same as
! 303: * when the roles are reversed, we pretend we are the target.
! 304: */
! 305: /*if (channel == 'B')
! 306: our_id += 8;*/
! 307: *tstate = ahc->enabled_targets[our_id];
! 308: return (&(*tstate)->transinfo[remote_id]);
! 309: }
! 310:
! 311: IO_INLINE uint16_t
! 312: ahc_inw(struct ahc_softc *ahc, u_int port)
! 313: {
! 314: return ((ahc_inb(ahc, port+1) << 8) | ahc_inb(ahc, port));
! 315: }
! 316:
! 317: IO_INLINE void
! 318: ahc_outw(struct ahc_softc *ahc, u_int port, u_int value)
! 319: {
! 320: ahc_outb(ahc, port, value & 0xFF);
! 321: ahc_outb(ahc, port+1, (value >> 8) & 0xFF);
! 322: }
! 323:
! 324: IO_INLINE uint32_t
! 325: ahc_inl(struct ahc_softc *ahc, u_int port)
! 326: {
! 327: return ((ahc_inb(ahc, port))
! 328: | (ahc_inb(ahc, port+1) << 8)
! 329: | (ahc_inb(ahc, port+2) << 16)
! 330: | (ahc_inb(ahc, port+3) << 24));
! 331: }
! 332:
! 333: IO_INLINE void
! 334: ahc_outl(struct ahc_softc *ahc, u_int port, uint32_t value)
! 335: {
! 336: ahc_outb(ahc, port, (value) & 0xFF);
! 337: ahc_outb(ahc, port+1, ((value) >> 8) & 0xFF);
! 338: ahc_outb(ahc, port+2, ((value) >> 16) & 0xFF);
! 339: ahc_outb(ahc, port+3, ((value) >> 24) & 0xFF);
! 340: }
! 341:
! 342: /*
! 343: * Get a free scb. If there are none, see if we can allocate a new SCB.
! 344: */
! 345: IO_INLINE struct scb *
! 346: ahc_get_scb(struct ahc_softc *ahc)
! 347: {
! 348: struct scb *scb;
! 349:
! 350: scb = SLIST_FIRST(&ahc->scb_data->free_scbs);
! 351:
! 352: if (scb != NULL)
! 353: SLIST_REMOVE_HEAD(&ahc->scb_data->free_scbs, links.sle);
! 354:
! 355: return (scb);
! 356: }
! 357:
! 358: /*
! 359: * Return an SCB resource to the free list.
! 360: */
! 361: IO_INLINE void
! 362: ahc_free_scb(struct ahc_softc *ahc, struct scb *scb)
! 363: {
! 364: struct hardware_scb *hscb;
! 365:
! 366: hscb = scb->hscb;
! 367: /* Clean up for the next user */
! 368: ahc->scb_data->scbindex[hscb->tag] = NULL;
! 369: scb->flags = SCB_FLAG_NONE;
! 370: hscb->control = 0;
! 371:
! 372: SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs, scb, links.sle);
! 373:
! 374: /* Notify the OSM that a resource is now available. */
! 375: ahc_platform_scb_free(ahc, scb);
! 376: }
! 377:
! 378:
! 379: IO_INLINE struct scb *
! 380: ahc_lookup_scb(struct ahc_softc *ahc, u_int tag)
! 381: {
! 382: struct scb* scb;
! 383:
! 384: scb = ahc->scb_data->scbindex[tag];
! 385: if (scb != NULL)
! 386: ahc_sync_scb(ahc, scb,
! 387: BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
! 388: return (scb);
! 389: }
! 390:
! 391:
! 392: IO_INLINE void
! 393: ahc_swap_with_next_hscb(struct ahc_softc *ahc, struct scb *scb)
! 394: {
! 395: struct hardware_scb *q_hscb;
! 396: u_int saved_tag;
! 397:
! 398: /*
! 399: * Our queuing method is a bit tricky. The card
! 400: * knows in advance which HSCB to download, and we
! 401: * can't disappoint it. To achieve this, the next
! 402: * SCB to download is saved off in ahc->next_queued_scb.
! 403: * When we are called to queue "an arbitrary scb",
! 404: * we copy the contents of the incoming HSCB to the one
! 405: * the sequencer knows about, swap HSCB pointers and
! 406: * finally assign the SCB to the tag indexed location
! 407: * in the scb_array. This makes sure that we can still
! 408: * locate the correct SCB by SCB_TAG.
! 409: */
! 410: q_hscb = ahc->next_queued_scb->hscb;
! 411: saved_tag = q_hscb->tag;
! 412: memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb));
! 413: if ((scb->flags & SCB_CDB32_PTR) != 0) {
! 414: q_hscb->shared_data.cdb_ptr =
! 415: aic_htole32(ahc_hscb_busaddr(ahc, q_hscb->tag)
! 416: + offsetof(struct hardware_scb, cdb32));
! 417: }
! 418: q_hscb->tag = saved_tag;
! 419: q_hscb->next = scb->hscb->tag;
! 420:
! 421: /* Now swap HSCB pointers. */
! 422: ahc->next_queued_scb->hscb = scb->hscb;
! 423: scb->hscb = q_hscb;
! 424:
! 425: /* Now define the mapping from tag to SCB in the scbindex */
! 426: ahc->scb_data->scbindex[scb->hscb->tag] = scb;
! 427: }
! 428:
! 429: /*
! 430: * Tell the sequencer about a new transaction to execute.
! 431: */
! 432: IO_INLINE void
! 433: ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb)
! 434: {
! 435: ahc_swap_with_next_hscb(ahc, scb);
! 436:
! 437: if (scb->hscb->tag == SCB_LIST_NULL
! 438: || scb->hscb->next == SCB_LIST_NULL)
! 439: panic("Attempt to queue invalid SCB tag %x:%x",
! 440: scb->hscb->tag, scb->hscb->next);
! 441:
! 442: /*
! 443: * Setup data "oddness".
! 444: */
! 445: scb->hscb->lun &= LID;
! 446: if (ahc_get_transfer_length(scb) & 0x1)
! 447: scb->hscb->lun |= SCB_XFERLEN_ODD;
! 448:
! 449: /*
! 450: * Keep a history of SCBs we've downloaded in the qinfifo.
! 451: */
! 452: ahc->qinfifo[ahc->qinfifonext] = scb->hscb->tag;
! 453: ahc_dmamap_sync(ahc, ahc->parent_dmat, ahc->shared_data_dmamap,
! 454: /*offset*/ahc->qinfifonext+256, /*len*/1,
! 455: BUS_DMASYNC_PREWRITE);
! 456: ahc->qinfifonext++;
! 457:
! 458: /*
! 459: * Make sure our data is consistent from the
! 460: * perspective of the adapter.
! 461: */
! 462: ahc_sync_scb(ahc, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
! 463:
! 464: /* Tell the adapter about the newly queued SCB */
! 465: if ((ahc->features & AHC_QUEUE_REGS) != 0) {
! 466: ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext);
! 467: } else {
! 468: if ((ahc->features & AHC_AUTOPAUSE) == 0)
! 469: ahc_pause(ahc);
! 470: ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext);
! 471: if ((ahc->features & AHC_AUTOPAUSE) == 0)
! 472: ahc_unpause(ahc);
! 473: }
! 474: }
! 475:
! 476:
! 477: IO_INLINE struct scsi_sense_data *
! 478: ahc_get_sense_buf(struct ahc_softc *ahc, struct scb *scb)
! 479: {
! 480: int offset;
! 481:
! 482: offset = scb - ahc->scb_data->scbarray;
! 483: return (&ahc->scb_data->sense[offset]);
! 484: }
! 485:
! 486: IO_INLINE uint32_t
! 487: ahc_get_sense_bufaddr(struct ahc_softc *ahc, struct scb *scb)
! 488: {
! 489: int offset;
! 490:
! 491: offset = scb - ahc->scb_data->scbarray;
! 492: return (ahc->scb_data->sense_busaddr
! 493: + (offset * sizeof(struct scsi_sense_data)));
! 494: }
! 495: #endif /* IO_EXPAND */
! 496:
! 497: /************************** Interrupt Processing ******************************/
! 498: IO_INLINE void ahc_sync_qoutfifo(struct ahc_softc *ahc, int op);
! 499: IO_INLINE void ahc_sync_tqinfifo(struct ahc_softc *ahc, int op);
! 500: IO_INLINE u_int ahc_check_cmdcmpltqueues(struct ahc_softc *ahc);
! 501: IO_INLINE int ahc_intr(struct ahc_softc *ahc);
! 502:
! 503: #ifdef IO_EXPAND
! 504: IO_INLINE void
! 505: ahc_sync_qoutfifo(struct ahc_softc *ahc, int op)
! 506: {
! 507: ahc_dmamap_sync(ahc, ahc->parent_dmat, ahc->shared_data_dmamap,
! 508: /*offset*/0, /*len*/256, op);
! 509: }
! 510:
! 511: IO_INLINE void
! 512: ahc_sync_tqinfifo(struct ahc_softc *ahc, int op)
! 513: {
! 514: #ifdef AHC_TARGET_MODE
! 515: if ((ahc->flags & AHC_TARGETROLE) != 0) {
! 516: ahc_dmamap_sync(ahc, ahc->parent_dmat /*shared_data_dmat*/,
! 517: ahc->shared_data_dmamap,
! 518: ahc_targetcmd_offset(ahc, 0),
! 519: sizeof(struct target_cmd) * AHC_TMODE_CMDS,
! 520: op);
! 521: }
! 522: #endif
! 523: }
! 524:
! 525: /*
! 526: * See if the firmware has posted any completed commands
! 527: * into our in-core command complete fifos.
! 528: */
! 529: #define AHC_RUN_QOUTFIFO 0x1
! 530: #define AHC_RUN_TQINFIFO 0x2
! 531: IO_INLINE u_int
! 532: ahc_check_cmdcmpltqueues(struct ahc_softc *ahc)
! 533: {
! 534: u_int retval;
! 535:
! 536: retval = 0;
! 537: ahc_dmamap_sync(ahc, ahc->parent_dmat /*shared_data_dmat*/, ahc->shared_data_dmamap,
! 538: /*offset*/ahc->qoutfifonext, /*len*/1,
! 539: BUS_DMASYNC_POSTREAD);
! 540: if (ahc->qoutfifo[ahc->qoutfifonext] != SCB_LIST_NULL)
! 541: retval |= AHC_RUN_QOUTFIFO;
! 542: #ifdef AHC_TARGET_MODE
! 543: if ((ahc->flags & AHC_TARGETROLE) != 0
! 544: && (ahc->flags & AHC_TQINFIFO_BLOCKED) == 0) {
! 545: ahc_dmamap_sync(ahc, ahc->parent_dmat /*shared_data_dmat*/,
! 546: ahc->shared_data_dmamap,
! 547: ahc_targetcmd_offset(ahc, ahc->tqinfifonext),
! 548: /*len*/sizeof(struct target_cmd),
! 549: BUS_DMASYNC_POSTREAD);
! 550: if (ahc->targetcmds[ahc->tqinfifonext].cmd_valid != 0)
! 551: retval |= AHC_RUN_TQINFIFO;
! 552: }
! 553: #endif
! 554: return (retval);
! 555: }
! 556:
! 557:
! 558: /*
! 559: * Catch an interrupt from the adapter
! 560: */
! 561: IO_INLINE int
! 562: ahc_intr(struct ahc_softc *ahc)
! 563: {
! 564: u_int intstat;
! 565:
! 566: if ((ahc->pause & INTEN) == 0) {
! 567: /*
! 568: * Our interrupt is not enabled on the chip
! 569: * and may be disabled for re-entrancy reasons,
! 570: * so just return. This is likely just a shared
! 571: * interrupt.
! 572: */
! 573: return (0);
! 574: }
! 575: /*
! 576: * Instead of directly reading the interrupt status register,
! 577: * infer the cause of the interrupt by checking our in-core
! 578: * completion queues. This avoids a costly PCI bus read in
! 579: * most cases.
! 580: */
! 581: if ((ahc->flags & (AHC_ALL_INTERRUPTS|AHC_EDGE_INTERRUPT)) == 0
! 582: && (ahc_check_cmdcmpltqueues(ahc) != 0))
! 583: intstat = CMDCMPLT;
! 584: else {
! 585: intstat = ahc_inb(ahc, INTSTAT);
! 586: }
! 587:
! 588: if (intstat & CMDCMPLT) {
! 589: ahc_outb(ahc, CLRINT, CLRCMDINT);
! 590:
! 591: /*
! 592: * Ensure that the chip sees that we've cleared
! 593: * this interrupt before we walk the output fifo.
! 594: * Otherwise, we may, due to posted bus writes,
! 595: * clear the interrupt after we finish the scan,
! 596: * and after the sequencer has added new entries
! 597: * and asserted the interrupt again.
! 598: */
! 599: ahc_flush_device_writes(ahc);
! 600: ahc_run_qoutfifo(ahc);
! 601: #ifdef AHC_TARGET_MODE
! 602: if ((ahc->flags & AHC_TARGETROLE) != 0)
! 603: ahc_run_tqinfifo(ahc, /*paused*/FALSE);
! 604: #endif
! 605: }
! 606:
! 607: if (intstat == 0xFF && (ahc->features & AHC_REMOVABLE) != 0)
! 608: /* Hot eject */
! 609: return 1;
! 610:
! 611: if ((intstat & INT_PEND) == 0) {
! 612: #if AHC_PCI_CONFIG > 0
! 613: if (ahc->unsolicited_ints > 500) {
! 614: ahc->unsolicited_ints = 0;
! 615: if ((ahc->chip & AHC_PCI) != 0
! 616: && (ahc_inb(ahc, ERROR) & PCIERRSTAT) != 0)
! 617: ahc->bus_intr(ahc);
! 618: }
! 619: ahc->unsolicited_ints++;
! 620: #endif
! 621: return 0;
! 622: }
! 623: ahc->unsolicited_ints = 0;
! 624:
! 625: if (intstat & BRKADRINT) {
! 626: ahc_handle_brkadrint(ahc);
! 627: /* Fatal error, no more interrupts to handle. */
! 628: return 1;
! 629: }
! 630:
! 631: if ((intstat & (SEQINT|SCSIINT)) != 0)
! 632: ahc_pause_bug_fix(ahc);
! 633:
! 634: if ((intstat & SEQINT) != 0)
! 635: ahc_handle_seqint(ahc, intstat);
! 636:
! 637: if ((intstat & SCSIINT) != 0)
! 638: ahc_handle_scsiint(ahc, intstat);
! 639:
! 640: return (1);
! 641: }
! 642:
! 643: #endif /* IO_EXPAND */
! 644:
! 645: #endif /* _AIC7XXX_INLINE_H_ */
CVSweb