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