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_ */ 646