aic7xxx_inline.h 19 KB

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