aic7xxx_inline.h
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:16k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  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#35 $
  41.  *
  42.  * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_inline.h,v 1.2.2.11 2002/04/29 19:36:31 gibbs Exp $
  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 struct scb*
  215. ahc_get_scb(struct ahc_softc *ahc);
  216. static __inline void ahc_free_scb(struct ahc_softc *ahc, struct scb *scb);
  217. static __inline void ahc_swap_with_next_hscb(struct ahc_softc *ahc,
  218. struct scb *scb);
  219. static __inline void ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb);
  220. static __inline struct scsi_sense_data *
  221. ahc_get_sense_buf(struct ahc_softc *ahc,
  222.   struct scb *scb);
  223. static __inline uint32_t
  224. ahc_get_sense_bufaddr(struct ahc_softc *ahc,
  225.       struct scb *scb);
  226. /*
  227.  * Determine whether the sequencer reported a residual
  228.  * for this SCB/transaction.
  229.  */
  230. static __inline void
  231. ahc_update_residual(struct ahc_softc *ahc, struct scb *scb)
  232. {
  233. uint32_t sgptr;
  234. sgptr = ahc_le32toh(scb->hscb->sgptr);
  235. if ((sgptr & SG_RESID_VALID) != 0)
  236. ahc_calc_residual(ahc, scb);
  237. }
  238. /*
  239.  * Return pointers to the transfer negotiation information
  240.  * for the specified our_id/remote_id pair.
  241.  */
  242. static __inline struct ahc_initiator_tinfo *
  243. ahc_fetch_transinfo(struct ahc_softc *ahc, char channel, u_int our_id,
  244.     u_int remote_id, struct ahc_tmode_tstate **tstate)
  245. {
  246. /*
  247.  * Transfer data structures are stored from the perspective
  248.  * of the target role.  Since the parameters for a connection
  249.  * in the initiator role to a given target are the same as
  250.  * when the roles are reversed, we pretend we are the target.
  251.  */
  252. if (channel == 'B')
  253. our_id += 8;
  254. *tstate = ahc->enabled_targets[our_id];
  255. return (&(*tstate)->transinfo[remote_id]);
  256. }
  257. /*
  258.  * Get a free scb. If there are none, see if we can allocate a new SCB.
  259.  */
  260. static __inline struct scb *
  261. ahc_get_scb(struct ahc_softc *ahc)
  262. {
  263. struct scb *scb;
  264. if ((scb = SLIST_FIRST(&ahc->scb_data->free_scbs)) == NULL) {
  265. ahc_alloc_scbs(ahc);
  266. scb = SLIST_FIRST(&ahc->scb_data->free_scbs);
  267. if (scb == NULL)
  268. return (NULL);
  269. }
  270. SLIST_REMOVE_HEAD(&ahc->scb_data->free_scbs, links.sle);
  271. return (scb);
  272. }
  273. /*
  274.  * Return an SCB resource to the free list.
  275.  */
  276. static __inline void
  277. ahc_free_scb(struct ahc_softc *ahc, struct scb *scb)
  278. {       
  279. struct hardware_scb *hscb;
  280. hscb = scb->hscb;
  281. /* Clean up for the next user */
  282. ahc->scb_data->scbindex[hscb->tag] = NULL;
  283. scb->flags = SCB_FREE;
  284. hscb->control = 0;
  285. SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs, scb, links.sle);
  286. /* Notify the OSM that a resource is now available. */
  287. ahc_platform_scb_free(ahc, scb);
  288. }
  289. static __inline struct scb *
  290. ahc_lookup_scb(struct ahc_softc *ahc, u_int tag)
  291. {
  292. struct scb* scb;
  293. scb = ahc->scb_data->scbindex[tag];
  294. if (scb != NULL)
  295. ahc_sync_scb(ahc, scb,
  296.      BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
  297. return (scb);
  298. }
  299. static __inline void
  300. ahc_swap_with_next_hscb(struct ahc_softc *ahc, struct scb *scb)
  301. {
  302. struct hardware_scb *q_hscb;
  303. u_int  saved_tag;
  304. /*
  305.  * Our queuing method is a bit tricky.  The card
  306.  * knows in advance which HSCB to download, and we
  307.  * can't disappoint it.  To achieve this, the next
  308.  * SCB to download is saved off in ahc->next_queued_scb.
  309.  * When we are called to queue "an arbitrary scb",
  310.  * we copy the contents of the incoming HSCB to the one
  311.  * the sequencer knows about, swap HSCB pointers and
  312.  * finally assign the SCB to the tag indexed location
  313.  * in the scb_array.  This makes sure that we can still
  314.  * locate the correct SCB by SCB_TAG.
  315.  */
  316. q_hscb = ahc->next_queued_scb->hscb;
  317. saved_tag = q_hscb->tag;
  318. memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb));
  319. if ((scb->flags & SCB_CDB32_PTR) != 0) {
  320. q_hscb->shared_data.cdb_ptr =
  321.     ahc_htole32(ahc_hscb_busaddr(ahc, q_hscb->tag)
  322.       + offsetof(struct hardware_scb, cdb32));
  323. }
  324. q_hscb->tag = saved_tag;
  325. q_hscb->next = scb->hscb->tag;
  326. /* Now swap HSCB pointers. */
  327. ahc->next_queued_scb->hscb = scb->hscb;
  328. scb->hscb = q_hscb;
  329. /* Now define the mapping from tag to SCB in the scbindex */
  330. ahc->scb_data->scbindex[scb->hscb->tag] = scb;
  331. }
  332. /*
  333.  * Tell the sequencer about a new transaction to execute.
  334.  */
  335. static __inline void
  336. ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb)
  337. {
  338. ahc_swap_with_next_hscb(ahc, scb);
  339. if (scb->hscb->tag == SCB_LIST_NULL
  340.  || scb->hscb->next == SCB_LIST_NULL)
  341. panic("Attempt to queue invalid SCB tag %x:%xn",
  342.       scb->hscb->tag, scb->hscb->next);
  343. /*
  344.  * Keep a history of SCBs we've downloaded in the qinfifo.
  345.  */
  346. ahc->qinfifo[ahc->qinfifonext++] = scb->hscb->tag;
  347. /*
  348.  * Make sure our data is consistant from the
  349.  * perspective of the adapter.
  350.  */
  351. ahc_sync_scb(ahc, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
  352. /* Tell the adapter about the newly queued SCB */
  353. if ((ahc->features & AHC_QUEUE_REGS) != 0) {
  354. ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext);
  355. } else {
  356. if ((ahc->features & AHC_AUTOPAUSE) == 0)
  357. ahc_pause(ahc);
  358. ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext);
  359. if ((ahc->features & AHC_AUTOPAUSE) == 0)
  360. ahc_unpause(ahc);
  361. }
  362. }
  363. static __inline struct scsi_sense_data *
  364. ahc_get_sense_buf(struct ahc_softc *ahc, struct scb *scb)
  365. {
  366. int offset;
  367. offset = scb - ahc->scb_data->scbarray;
  368. return (&ahc->scb_data->sense[offset]);
  369. }
  370. static __inline uint32_t
  371. ahc_get_sense_bufaddr(struct ahc_softc *ahc, struct scb *scb)
  372. {
  373. int offset;
  374. offset = scb - ahc->scb_data->scbarray;
  375. return (ahc->scb_data->sense_busaddr
  376.       + (offset * sizeof(struct scsi_sense_data)));
  377. }
  378. /************************** Interrupt Processing ******************************/
  379. static __inline void ahc_sync_qoutfifo(struct ahc_softc *ahc, int op);
  380. static __inline void ahc_sync_tqinfifo(struct ahc_softc *ahc, int op);
  381. static __inline u_int ahc_check_cmdcmpltqueues(struct ahc_softc *ahc);
  382. static __inline void ahc_intr(struct ahc_softc *ahc);
  383. static __inline void
  384. ahc_sync_qoutfifo(struct ahc_softc *ahc, int op)
  385. {
  386. ahc_dmamap_sync(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap,
  387. /*offset*/0, /*len*/256, op);
  388. }
  389. static __inline void
  390. ahc_sync_tqinfifo(struct ahc_softc *ahc, int op)
  391. {
  392. #ifdef AHC_TARGET_MODE
  393. if ((ahc->flags & AHC_TARGETROLE) != 0) {
  394. ahc_dmamap_sync(ahc, ahc->shared_data_dmat,
  395. ahc->shared_data_dmamap,
  396. ahc_targetcmd_offset(ahc, 0),
  397. sizeof(struct target_cmd) * AHC_TMODE_CMDS,
  398. op);
  399. }
  400. #endif
  401. }
  402. /*
  403.  * See if the firmware has posted any completed commands
  404.  * into our in-core command complete fifos.
  405.  */
  406. #define AHC_RUN_QOUTFIFO 0x1
  407. #define AHC_RUN_TQINFIFO 0x2
  408. static __inline u_int
  409. ahc_check_cmdcmpltqueues(struct ahc_softc *ahc)
  410. {
  411. u_int retval;
  412. retval = 0;
  413. ahc_dmamap_sync(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap,
  414. /*offset*/ahc->qoutfifonext, /*len*/1,
  415. BUS_DMASYNC_POSTREAD);
  416. if (ahc->qoutfifo[ahc->qoutfifonext] != SCB_LIST_NULL)
  417. retval |= AHC_RUN_QOUTFIFO;
  418. #ifdef AHC_TARGET_MODE
  419. if ((ahc->flags & AHC_TARGETROLE) != 0
  420.  && (ahc->flags & AHC_TQINFIFO_BLOCKED) == 0) {
  421. ahc_dmamap_sync(ahc, ahc->shared_data_dmat,
  422. ahc->shared_data_dmamap,
  423. ahc_targetcmd_offset(ahc, ahc->tqinfifofnext),
  424. /*len*/sizeof(struct target_cmd),
  425. BUS_DMASYNC_POSTREAD);
  426. if (ahc->targetcmds[ahc->tqinfifonext].cmd_valid != 0)
  427. retval |= AHC_RUN_TQINFIFO;
  428. }
  429. #endif
  430. return (retval);
  431. }
  432. /*
  433.  * Catch an interrupt from the adapter
  434.  */
  435. static __inline void
  436. ahc_intr(struct ahc_softc *ahc)
  437. {
  438. u_int intstat;
  439. /*
  440.  * Instead of directly reading the interrupt status register,
  441.  * infer the cause of the interrupt by checking our in-core
  442.  * completion queues.  This avoids a costly PCI bus read in
  443.  * most cases.
  444.  */
  445. if ((ahc->flags & (AHC_ALL_INTERRUPTS|AHC_EDGE_INTERRUPT)) == 0
  446.  && (ahc_check_cmdcmpltqueues(ahc) != 0))
  447. intstat = CMDCMPLT;
  448. else {
  449. intstat = ahc_inb(ahc, INTSTAT);
  450. }
  451. if (intstat & CMDCMPLT) {
  452. ahc_outb(ahc, CLRINT, CLRCMDINT);
  453. /*
  454.  * Ensure that the chip sees that we've cleared
  455.  * this interrupt before we walk the output fifo.
  456.  * Otherwise, we may, due to posted bus writes,
  457.  * clear the interrupt after we finish the scan,
  458.  * and after the sequencer has added new entries
  459.  * and asserted the interrupt again.
  460.  */
  461. ahc_flush_device_writes(ahc);
  462. ahc_run_qoutfifo(ahc);
  463. #ifdef AHC_TARGET_MODE
  464. if ((ahc->flags & AHC_TARGETROLE) != 0)
  465. ahc_run_tqinfifo(ahc, /*paused*/FALSE);
  466. #endif
  467. }
  468. if (intstat == 0xFF && (ahc->features & AHC_REMOVABLE) != 0)
  469. /* Hot eject */
  470. return;
  471. if ((intstat & INT_PEND) == 0) {
  472. #if AHC_PCI_CONFIG > 0
  473. if (ahc->unsolicited_ints > 500) {
  474. ahc->unsolicited_ints = 0;
  475. if ((ahc->chip & AHC_PCI) != 0
  476.  && (ahc_inb(ahc, ERROR) & PCIERRSTAT) != 0)
  477. ahc->bus_intr(ahc);
  478. }
  479. #endif
  480. ahc->unsolicited_ints++;
  481. return;
  482. }
  483. ahc->unsolicited_ints = 0;
  484. if (intstat & BRKADRINT) {
  485. ahc_handle_brkadrint(ahc);
  486. /* Fatal error, no more interrupts to handle. */
  487. return;
  488. }
  489. if ((intstat & (SEQINT|SCSIINT)) != 0)
  490. ahc_pause_bug_fix(ahc);
  491. if ((intstat & SEQINT) != 0)
  492. ahc_handle_seqint(ahc, intstat);
  493. if ((intstat & SCSIINT) != 0)
  494. ahc_handle_scsiint(ahc, intstat);
  495. }
  496. #endif  /* _AIC7XXX_INLINE_H_ */