xref: /openbmc/linux/drivers/scsi/aic7xxx/aic79xx_inline.h (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
1*1da177e4SLinus Torvalds /*
2*1da177e4SLinus Torvalds  * Inline routines shareable across OS platforms.
3*1da177e4SLinus Torvalds  *
4*1da177e4SLinus Torvalds  * Copyright (c) 1994-2001 Justin T. Gibbs.
5*1da177e4SLinus Torvalds  * Copyright (c) 2000-2003 Adaptec Inc.
6*1da177e4SLinus Torvalds  * All rights reserved.
7*1da177e4SLinus Torvalds  *
8*1da177e4SLinus Torvalds  * Redistribution and use in source and binary forms, with or without
9*1da177e4SLinus Torvalds  * modification, are permitted provided that the following conditions
10*1da177e4SLinus Torvalds  * are met:
11*1da177e4SLinus Torvalds  * 1. Redistributions of source code must retain the above copyright
12*1da177e4SLinus Torvalds  *    notice, this list of conditions, and the following disclaimer,
13*1da177e4SLinus Torvalds  *    without modification.
14*1da177e4SLinus Torvalds  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
15*1da177e4SLinus Torvalds  *    substantially similar to the "NO WARRANTY" disclaimer below
16*1da177e4SLinus Torvalds  *    ("Disclaimer") and any redistribution must be conditioned upon
17*1da177e4SLinus Torvalds  *    including a substantially similar Disclaimer requirement for further
18*1da177e4SLinus Torvalds  *    binary redistribution.
19*1da177e4SLinus Torvalds  * 3. Neither the names of the above-listed copyright holders nor the names
20*1da177e4SLinus Torvalds  *    of any contributors may be used to endorse or promote products derived
21*1da177e4SLinus Torvalds  *    from this software without specific prior written permission.
22*1da177e4SLinus Torvalds  *
23*1da177e4SLinus Torvalds  * Alternatively, this software may be distributed under the terms of the
24*1da177e4SLinus Torvalds  * GNU General Public License ("GPL") version 2 as published by the Free
25*1da177e4SLinus Torvalds  * Software Foundation.
26*1da177e4SLinus Torvalds  *
27*1da177e4SLinus Torvalds  * NO WARRANTY
28*1da177e4SLinus Torvalds  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29*1da177e4SLinus Torvalds  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30*1da177e4SLinus Torvalds  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
31*1da177e4SLinus Torvalds  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32*1da177e4SLinus Torvalds  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33*1da177e4SLinus Torvalds  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34*1da177e4SLinus Torvalds  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35*1da177e4SLinus Torvalds  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
36*1da177e4SLinus Torvalds  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
37*1da177e4SLinus Torvalds  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38*1da177e4SLinus Torvalds  * POSSIBILITY OF SUCH DAMAGES.
39*1da177e4SLinus Torvalds  *
40*1da177e4SLinus Torvalds  * $Id: //depot/aic7xxx/aic7xxx/aic79xx_inline.h#51 $
41*1da177e4SLinus Torvalds  *
42*1da177e4SLinus Torvalds  * $FreeBSD$
43*1da177e4SLinus Torvalds  */
44*1da177e4SLinus Torvalds 
45*1da177e4SLinus Torvalds #ifndef _AIC79XX_INLINE_H_
46*1da177e4SLinus Torvalds #define _AIC79XX_INLINE_H_
47*1da177e4SLinus Torvalds 
48*1da177e4SLinus Torvalds /******************************** Debugging ***********************************/
49*1da177e4SLinus Torvalds static __inline char *ahd_name(struct ahd_softc *ahd);
50*1da177e4SLinus Torvalds 
51*1da177e4SLinus Torvalds static __inline char *
52*1da177e4SLinus Torvalds ahd_name(struct ahd_softc *ahd)
53*1da177e4SLinus Torvalds {
54*1da177e4SLinus Torvalds 	return (ahd->name);
55*1da177e4SLinus Torvalds }
56*1da177e4SLinus Torvalds 
57*1da177e4SLinus Torvalds /************************ Sequencer Execution Control *************************/
58*1da177e4SLinus Torvalds static __inline void ahd_known_modes(struct ahd_softc *ahd,
59*1da177e4SLinus Torvalds 				     ahd_mode src, ahd_mode dst);
60*1da177e4SLinus Torvalds static __inline ahd_mode_state ahd_build_mode_state(struct ahd_softc *ahd,
61*1da177e4SLinus Torvalds 						    ahd_mode src,
62*1da177e4SLinus Torvalds 						    ahd_mode dst);
63*1da177e4SLinus Torvalds static __inline void ahd_extract_mode_state(struct ahd_softc *ahd,
64*1da177e4SLinus Torvalds 					    ahd_mode_state state,
65*1da177e4SLinus Torvalds 					    ahd_mode *src, ahd_mode *dst);
66*1da177e4SLinus Torvalds static __inline void ahd_set_modes(struct ahd_softc *ahd, ahd_mode src,
67*1da177e4SLinus Torvalds 				   ahd_mode dst);
68*1da177e4SLinus Torvalds static __inline void ahd_update_modes(struct ahd_softc *ahd);
69*1da177e4SLinus Torvalds static __inline void ahd_assert_modes(struct ahd_softc *ahd, ahd_mode srcmode,
70*1da177e4SLinus Torvalds 				      ahd_mode dstmode, const char *file,
71*1da177e4SLinus Torvalds 				      int line);
72*1da177e4SLinus Torvalds static __inline ahd_mode_state ahd_save_modes(struct ahd_softc *ahd);
73*1da177e4SLinus Torvalds static __inline void ahd_restore_modes(struct ahd_softc *ahd,
74*1da177e4SLinus Torvalds 				       ahd_mode_state state);
75*1da177e4SLinus Torvalds static __inline int  ahd_is_paused(struct ahd_softc *ahd);
76*1da177e4SLinus Torvalds static __inline void ahd_pause(struct ahd_softc *ahd);
77*1da177e4SLinus Torvalds static __inline void ahd_unpause(struct ahd_softc *ahd);
78*1da177e4SLinus Torvalds 
79*1da177e4SLinus Torvalds static __inline void
80*1da177e4SLinus Torvalds ahd_known_modes(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst)
81*1da177e4SLinus Torvalds {
82*1da177e4SLinus Torvalds 	ahd->src_mode = src;
83*1da177e4SLinus Torvalds 	ahd->dst_mode = dst;
84*1da177e4SLinus Torvalds 	ahd->saved_src_mode = src;
85*1da177e4SLinus Torvalds 	ahd->saved_dst_mode = dst;
86*1da177e4SLinus Torvalds }
87*1da177e4SLinus Torvalds 
88*1da177e4SLinus Torvalds static __inline ahd_mode_state
89*1da177e4SLinus Torvalds ahd_build_mode_state(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst)
90*1da177e4SLinus Torvalds {
91*1da177e4SLinus Torvalds 	return ((src << SRC_MODE_SHIFT) | (dst << DST_MODE_SHIFT));
92*1da177e4SLinus Torvalds }
93*1da177e4SLinus Torvalds 
94*1da177e4SLinus Torvalds static __inline void
95*1da177e4SLinus Torvalds ahd_extract_mode_state(struct ahd_softc *ahd, ahd_mode_state state,
96*1da177e4SLinus Torvalds 		       ahd_mode *src, ahd_mode *dst)
97*1da177e4SLinus Torvalds {
98*1da177e4SLinus Torvalds 	*src = (state & SRC_MODE) >> SRC_MODE_SHIFT;
99*1da177e4SLinus Torvalds 	*dst = (state & DST_MODE) >> DST_MODE_SHIFT;
100*1da177e4SLinus Torvalds }
101*1da177e4SLinus Torvalds 
102*1da177e4SLinus Torvalds static __inline void
103*1da177e4SLinus Torvalds ahd_set_modes(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst)
104*1da177e4SLinus Torvalds {
105*1da177e4SLinus Torvalds 	if (ahd->src_mode == src && ahd->dst_mode == dst)
106*1da177e4SLinus Torvalds 		return;
107*1da177e4SLinus Torvalds #ifdef AHD_DEBUG
108*1da177e4SLinus Torvalds 	if (ahd->src_mode == AHD_MODE_UNKNOWN
109*1da177e4SLinus Torvalds 	 || ahd->dst_mode == AHD_MODE_UNKNOWN)
110*1da177e4SLinus Torvalds 		panic("Setting mode prior to saving it.\n");
111*1da177e4SLinus Torvalds 	if ((ahd_debug & AHD_SHOW_MODEPTR) != 0)
112*1da177e4SLinus Torvalds 		printf("%s: Setting mode 0x%x\n", ahd_name(ahd),
113*1da177e4SLinus Torvalds 		       ahd_build_mode_state(ahd, src, dst));
114*1da177e4SLinus Torvalds #endif
115*1da177e4SLinus Torvalds 	ahd_outb(ahd, MODE_PTR, ahd_build_mode_state(ahd, src, dst));
116*1da177e4SLinus Torvalds 	ahd->src_mode = src;
117*1da177e4SLinus Torvalds 	ahd->dst_mode = dst;
118*1da177e4SLinus Torvalds }
119*1da177e4SLinus Torvalds 
120*1da177e4SLinus Torvalds static __inline void
121*1da177e4SLinus Torvalds ahd_update_modes(struct ahd_softc *ahd)
122*1da177e4SLinus Torvalds {
123*1da177e4SLinus Torvalds 	ahd_mode_state mode_ptr;
124*1da177e4SLinus Torvalds 	ahd_mode src;
125*1da177e4SLinus Torvalds 	ahd_mode dst;
126*1da177e4SLinus Torvalds 
127*1da177e4SLinus Torvalds 	mode_ptr = ahd_inb(ahd, MODE_PTR);
128*1da177e4SLinus Torvalds #ifdef AHD_DEBUG
129*1da177e4SLinus Torvalds 	if ((ahd_debug & AHD_SHOW_MODEPTR) != 0)
130*1da177e4SLinus Torvalds 		printf("Reading mode 0x%x\n", mode_ptr);
131*1da177e4SLinus Torvalds #endif
132*1da177e4SLinus Torvalds 	ahd_extract_mode_state(ahd, mode_ptr, &src, &dst);
133*1da177e4SLinus Torvalds 	ahd_known_modes(ahd, src, dst);
134*1da177e4SLinus Torvalds }
135*1da177e4SLinus Torvalds 
136*1da177e4SLinus Torvalds static __inline void
137*1da177e4SLinus Torvalds ahd_assert_modes(struct ahd_softc *ahd, ahd_mode srcmode,
138*1da177e4SLinus Torvalds 		 ahd_mode dstmode, const char *file, int line)
139*1da177e4SLinus Torvalds {
140*1da177e4SLinus Torvalds #ifdef AHD_DEBUG
141*1da177e4SLinus Torvalds 	if ((srcmode & AHD_MK_MSK(ahd->src_mode)) == 0
142*1da177e4SLinus Torvalds 	 || (dstmode & AHD_MK_MSK(ahd->dst_mode)) == 0) {
143*1da177e4SLinus Torvalds 		panic("%s:%s:%d: Mode assertion failed.\n",
144*1da177e4SLinus Torvalds 		       ahd_name(ahd), file, line);
145*1da177e4SLinus Torvalds 	}
146*1da177e4SLinus Torvalds #endif
147*1da177e4SLinus Torvalds }
148*1da177e4SLinus Torvalds 
149*1da177e4SLinus Torvalds static __inline ahd_mode_state
150*1da177e4SLinus Torvalds ahd_save_modes(struct ahd_softc *ahd)
151*1da177e4SLinus Torvalds {
152*1da177e4SLinus Torvalds 	if (ahd->src_mode == AHD_MODE_UNKNOWN
153*1da177e4SLinus Torvalds 	 || ahd->dst_mode == AHD_MODE_UNKNOWN)
154*1da177e4SLinus Torvalds 		ahd_update_modes(ahd);
155*1da177e4SLinus Torvalds 
156*1da177e4SLinus Torvalds 	return (ahd_build_mode_state(ahd, ahd->src_mode, ahd->dst_mode));
157*1da177e4SLinus Torvalds }
158*1da177e4SLinus Torvalds 
159*1da177e4SLinus Torvalds static __inline void
160*1da177e4SLinus Torvalds ahd_restore_modes(struct ahd_softc *ahd, ahd_mode_state state)
161*1da177e4SLinus Torvalds {
162*1da177e4SLinus Torvalds 	ahd_mode src;
163*1da177e4SLinus Torvalds 	ahd_mode dst;
164*1da177e4SLinus Torvalds 
165*1da177e4SLinus Torvalds 	ahd_extract_mode_state(ahd, state, &src, &dst);
166*1da177e4SLinus Torvalds 	ahd_set_modes(ahd, src, dst);
167*1da177e4SLinus Torvalds }
168*1da177e4SLinus Torvalds 
169*1da177e4SLinus Torvalds #define AHD_ASSERT_MODES(ahd, source, dest) \
170*1da177e4SLinus Torvalds 	ahd_assert_modes(ahd, source, dest, __FILE__, __LINE__);
171*1da177e4SLinus Torvalds 
172*1da177e4SLinus Torvalds /*
173*1da177e4SLinus Torvalds  * Determine whether the sequencer has halted code execution.
174*1da177e4SLinus Torvalds  * Returns non-zero status if the sequencer is stopped.
175*1da177e4SLinus Torvalds  */
176*1da177e4SLinus Torvalds static __inline int
177*1da177e4SLinus Torvalds ahd_is_paused(struct ahd_softc *ahd)
178*1da177e4SLinus Torvalds {
179*1da177e4SLinus Torvalds 	return ((ahd_inb(ahd, HCNTRL) & PAUSE) != 0);
180*1da177e4SLinus Torvalds }
181*1da177e4SLinus Torvalds 
182*1da177e4SLinus Torvalds /*
183*1da177e4SLinus Torvalds  * Request that the sequencer stop and wait, indefinitely, for it
184*1da177e4SLinus Torvalds  * to stop.  The sequencer will only acknowledge that it is paused
185*1da177e4SLinus Torvalds  * once it has reached an instruction boundary and PAUSEDIS is
186*1da177e4SLinus Torvalds  * cleared in the SEQCTL register.  The sequencer may use PAUSEDIS
187*1da177e4SLinus Torvalds  * for critical sections.
188*1da177e4SLinus Torvalds  */
189*1da177e4SLinus Torvalds static __inline void
190*1da177e4SLinus Torvalds ahd_pause(struct ahd_softc *ahd)
191*1da177e4SLinus Torvalds {
192*1da177e4SLinus Torvalds 	ahd_outb(ahd, HCNTRL, ahd->pause);
193*1da177e4SLinus Torvalds 
194*1da177e4SLinus Torvalds 	/*
195*1da177e4SLinus Torvalds 	 * Since the sequencer can disable pausing in a critical section, we
196*1da177e4SLinus Torvalds 	 * must loop until it actually stops.
197*1da177e4SLinus Torvalds 	 */
198*1da177e4SLinus Torvalds 	while (ahd_is_paused(ahd) == 0)
199*1da177e4SLinus Torvalds 		;
200*1da177e4SLinus Torvalds }
201*1da177e4SLinus Torvalds 
202*1da177e4SLinus Torvalds /*
203*1da177e4SLinus Torvalds  * Allow the sequencer to continue program execution.
204*1da177e4SLinus Torvalds  * We check here to ensure that no additional interrupt
205*1da177e4SLinus Torvalds  * sources that would cause the sequencer to halt have been
206*1da177e4SLinus Torvalds  * asserted.  If, for example, a SCSI bus reset is detected
207*1da177e4SLinus Torvalds  * while we are fielding a different, pausing, interrupt type,
208*1da177e4SLinus Torvalds  * we don't want to release the sequencer before going back
209*1da177e4SLinus Torvalds  * into our interrupt handler and dealing with this new
210*1da177e4SLinus Torvalds  * condition.
211*1da177e4SLinus Torvalds  */
212*1da177e4SLinus Torvalds static __inline void
213*1da177e4SLinus Torvalds ahd_unpause(struct ahd_softc *ahd)
214*1da177e4SLinus Torvalds {
215*1da177e4SLinus Torvalds 	/*
216*1da177e4SLinus Torvalds 	 * Automatically restore our modes to those saved
217*1da177e4SLinus Torvalds 	 * prior to the first change of the mode.
218*1da177e4SLinus Torvalds 	 */
219*1da177e4SLinus Torvalds 	if (ahd->saved_src_mode != AHD_MODE_UNKNOWN
220*1da177e4SLinus Torvalds 	 && ahd->saved_dst_mode != AHD_MODE_UNKNOWN) {
221*1da177e4SLinus Torvalds 		if ((ahd->flags & AHD_UPDATE_PEND_CMDS) != 0)
222*1da177e4SLinus Torvalds 			ahd_reset_cmds_pending(ahd);
223*1da177e4SLinus Torvalds 		ahd_set_modes(ahd, ahd->saved_src_mode, ahd->saved_dst_mode);
224*1da177e4SLinus Torvalds 	}
225*1da177e4SLinus Torvalds 
226*1da177e4SLinus Torvalds 	if ((ahd_inb(ahd, INTSTAT) & ~CMDCMPLT) == 0)
227*1da177e4SLinus Torvalds 		ahd_outb(ahd, HCNTRL, ahd->unpause);
228*1da177e4SLinus Torvalds 
229*1da177e4SLinus Torvalds 	ahd_known_modes(ahd, AHD_MODE_UNKNOWN, AHD_MODE_UNKNOWN);
230*1da177e4SLinus Torvalds }
231*1da177e4SLinus Torvalds 
232*1da177e4SLinus Torvalds /*********************** Scatter Gather List Handling *************************/
233*1da177e4SLinus Torvalds static __inline void	*ahd_sg_setup(struct ahd_softc *ahd, struct scb *scb,
234*1da177e4SLinus Torvalds 				      void *sgptr, dma_addr_t addr,
235*1da177e4SLinus Torvalds 				      bus_size_t len, int last);
236*1da177e4SLinus Torvalds static __inline void	 ahd_setup_scb_common(struct ahd_softc *ahd,
237*1da177e4SLinus Torvalds 					      struct scb *scb);
238*1da177e4SLinus Torvalds static __inline void	 ahd_setup_data_scb(struct ahd_softc *ahd,
239*1da177e4SLinus Torvalds 					    struct scb *scb);
240*1da177e4SLinus Torvalds static __inline void	 ahd_setup_noxfer_scb(struct ahd_softc *ahd,
241*1da177e4SLinus Torvalds 					      struct scb *scb);
242*1da177e4SLinus Torvalds 
243*1da177e4SLinus Torvalds static __inline void *
244*1da177e4SLinus Torvalds ahd_sg_setup(struct ahd_softc *ahd, struct scb *scb,
245*1da177e4SLinus Torvalds 	     void *sgptr, dma_addr_t addr, bus_size_t len, int last)
246*1da177e4SLinus Torvalds {
247*1da177e4SLinus Torvalds 	scb->sg_count++;
248*1da177e4SLinus Torvalds 	if (sizeof(dma_addr_t) > 4
249*1da177e4SLinus Torvalds 	 && (ahd->flags & AHD_64BIT_ADDRESSING) != 0) {
250*1da177e4SLinus Torvalds 		struct ahd_dma64_seg *sg;
251*1da177e4SLinus Torvalds 
252*1da177e4SLinus Torvalds 		sg = (struct ahd_dma64_seg *)sgptr;
253*1da177e4SLinus Torvalds 		sg->addr = ahd_htole64(addr);
254*1da177e4SLinus Torvalds 		sg->len = ahd_htole32(len | (last ? AHD_DMA_LAST_SEG : 0));
255*1da177e4SLinus Torvalds 		return (sg + 1);
256*1da177e4SLinus Torvalds 	} else {
257*1da177e4SLinus Torvalds 		struct ahd_dma_seg *sg;
258*1da177e4SLinus Torvalds 
259*1da177e4SLinus Torvalds 		sg = (struct ahd_dma_seg *)sgptr;
260*1da177e4SLinus Torvalds 		sg->addr = ahd_htole32(addr & 0xFFFFFFFF);
261*1da177e4SLinus Torvalds 		sg->len = ahd_htole32(len | ((addr >> 8) & 0x7F000000)
262*1da177e4SLinus Torvalds 				    | (last ? AHD_DMA_LAST_SEG : 0));
263*1da177e4SLinus Torvalds 		return (sg + 1);
264*1da177e4SLinus Torvalds 	}
265*1da177e4SLinus Torvalds }
266*1da177e4SLinus Torvalds 
267*1da177e4SLinus Torvalds static __inline void
268*1da177e4SLinus Torvalds ahd_setup_scb_common(struct ahd_softc *ahd, struct scb *scb)
269*1da177e4SLinus Torvalds {
270*1da177e4SLinus Torvalds 	/* XXX Handle target mode SCBs. */
271*1da177e4SLinus Torvalds 	scb->crc_retry_count = 0;
272*1da177e4SLinus Torvalds 	if ((scb->flags & SCB_PACKETIZED) != 0) {
273*1da177e4SLinus Torvalds 		/* XXX what about ACA??  It is type 4, but TAG_TYPE == 0x3. */
274*1da177e4SLinus Torvalds 		scb->hscb->task_attribute = scb->hscb->control & SCB_TAG_TYPE;
275*1da177e4SLinus Torvalds 	} else {
276*1da177e4SLinus Torvalds 		if (ahd_get_transfer_length(scb) & 0x01)
277*1da177e4SLinus Torvalds 			scb->hscb->task_attribute = SCB_XFERLEN_ODD;
278*1da177e4SLinus Torvalds 		else
279*1da177e4SLinus Torvalds 			scb->hscb->task_attribute = 0;
280*1da177e4SLinus Torvalds 	}
281*1da177e4SLinus Torvalds 
282*1da177e4SLinus Torvalds 	if (scb->hscb->cdb_len <= MAX_CDB_LEN_WITH_SENSE_ADDR
283*1da177e4SLinus Torvalds 	 || (scb->hscb->cdb_len & SCB_CDB_LEN_PTR) != 0)
284*1da177e4SLinus Torvalds 		scb->hscb->shared_data.idata.cdb_plus_saddr.sense_addr =
285*1da177e4SLinus Torvalds 		    ahd_htole32(scb->sense_busaddr);
286*1da177e4SLinus Torvalds }
287*1da177e4SLinus Torvalds 
288*1da177e4SLinus Torvalds static __inline void
289*1da177e4SLinus Torvalds ahd_setup_data_scb(struct ahd_softc *ahd, struct scb *scb)
290*1da177e4SLinus Torvalds {
291*1da177e4SLinus Torvalds 	/*
292*1da177e4SLinus Torvalds 	 * Copy the first SG into the "current" data ponter area.
293*1da177e4SLinus Torvalds 	 */
294*1da177e4SLinus Torvalds 	if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) {
295*1da177e4SLinus Torvalds 		struct ahd_dma64_seg *sg;
296*1da177e4SLinus Torvalds 
297*1da177e4SLinus Torvalds 		sg = (struct ahd_dma64_seg *)scb->sg_list;
298*1da177e4SLinus Torvalds 		scb->hscb->dataptr = sg->addr;
299*1da177e4SLinus Torvalds 		scb->hscb->datacnt = sg->len;
300*1da177e4SLinus Torvalds 	} else {
301*1da177e4SLinus Torvalds 		struct ahd_dma_seg *sg;
302*1da177e4SLinus Torvalds 		uint32_t *dataptr_words;
303*1da177e4SLinus Torvalds 
304*1da177e4SLinus Torvalds 		sg = (struct ahd_dma_seg *)scb->sg_list;
305*1da177e4SLinus Torvalds 		dataptr_words = (uint32_t*)&scb->hscb->dataptr;
306*1da177e4SLinus Torvalds 		dataptr_words[0] = sg->addr;
307*1da177e4SLinus Torvalds 		dataptr_words[1] = 0;
308*1da177e4SLinus Torvalds 		if ((ahd->flags & AHD_39BIT_ADDRESSING) != 0) {
309*1da177e4SLinus Torvalds 			uint64_t high_addr;
310*1da177e4SLinus Torvalds 
311*1da177e4SLinus Torvalds 			high_addr = ahd_le32toh(sg->len) & 0x7F000000;
312*1da177e4SLinus Torvalds 			scb->hscb->dataptr |= ahd_htole64(high_addr << 8);
313*1da177e4SLinus Torvalds 		}
314*1da177e4SLinus Torvalds 		scb->hscb->datacnt = sg->len;
315*1da177e4SLinus Torvalds 	}
316*1da177e4SLinus Torvalds 	/*
317*1da177e4SLinus Torvalds 	 * Note where to find the SG entries in bus space.
318*1da177e4SLinus Torvalds 	 * We also set the full residual flag which the
319*1da177e4SLinus Torvalds 	 * sequencer will clear as soon as a data transfer
320*1da177e4SLinus Torvalds 	 * occurs.
321*1da177e4SLinus Torvalds 	 */
322*1da177e4SLinus Torvalds 	scb->hscb->sgptr = ahd_htole32(scb->sg_list_busaddr|SG_FULL_RESID);
323*1da177e4SLinus Torvalds }
324*1da177e4SLinus Torvalds 
325*1da177e4SLinus Torvalds static __inline void
326*1da177e4SLinus Torvalds ahd_setup_noxfer_scb(struct ahd_softc *ahd, struct scb *scb)
327*1da177e4SLinus Torvalds {
328*1da177e4SLinus Torvalds 	scb->hscb->sgptr = ahd_htole32(SG_LIST_NULL);
329*1da177e4SLinus Torvalds 	scb->hscb->dataptr = 0;
330*1da177e4SLinus Torvalds 	scb->hscb->datacnt = 0;
331*1da177e4SLinus Torvalds }
332*1da177e4SLinus Torvalds 
333*1da177e4SLinus Torvalds /************************** Memory mapping routines ***************************/
334*1da177e4SLinus Torvalds static __inline size_t	ahd_sg_size(struct ahd_softc *ahd);
335*1da177e4SLinus Torvalds static __inline void *
336*1da177e4SLinus Torvalds 			ahd_sg_bus_to_virt(struct ahd_softc *ahd,
337*1da177e4SLinus Torvalds 					   struct scb *scb,
338*1da177e4SLinus Torvalds 					   uint32_t sg_busaddr);
339*1da177e4SLinus Torvalds static __inline uint32_t
340*1da177e4SLinus Torvalds 			ahd_sg_virt_to_bus(struct ahd_softc *ahd,
341*1da177e4SLinus Torvalds 					   struct scb *scb,
342*1da177e4SLinus Torvalds 					   void *sg);
343*1da177e4SLinus Torvalds static __inline void	ahd_sync_scb(struct ahd_softc *ahd,
344*1da177e4SLinus Torvalds 				     struct scb *scb, int op);
345*1da177e4SLinus Torvalds static __inline void	ahd_sync_sglist(struct ahd_softc *ahd,
346*1da177e4SLinus Torvalds 					struct scb *scb, int op);
347*1da177e4SLinus Torvalds static __inline void	ahd_sync_sense(struct ahd_softc *ahd,
348*1da177e4SLinus Torvalds 				       struct scb *scb, int op);
349*1da177e4SLinus Torvalds static __inline uint32_t
350*1da177e4SLinus Torvalds 			ahd_targetcmd_offset(struct ahd_softc *ahd,
351*1da177e4SLinus Torvalds 					     u_int index);
352*1da177e4SLinus Torvalds 
353*1da177e4SLinus Torvalds static __inline size_t
354*1da177e4SLinus Torvalds ahd_sg_size(struct ahd_softc *ahd)
355*1da177e4SLinus Torvalds {
356*1da177e4SLinus Torvalds 	if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0)
357*1da177e4SLinus Torvalds 		return (sizeof(struct ahd_dma64_seg));
358*1da177e4SLinus Torvalds 	return (sizeof(struct ahd_dma_seg));
359*1da177e4SLinus Torvalds }
360*1da177e4SLinus Torvalds 
361*1da177e4SLinus Torvalds static __inline void *
362*1da177e4SLinus Torvalds ahd_sg_bus_to_virt(struct ahd_softc *ahd, struct scb *scb, uint32_t sg_busaddr)
363*1da177e4SLinus Torvalds {
364*1da177e4SLinus Torvalds 	dma_addr_t sg_offset;
365*1da177e4SLinus Torvalds 
366*1da177e4SLinus Torvalds 	/* sg_list_phys points to entry 1, not 0 */
367*1da177e4SLinus Torvalds 	sg_offset = sg_busaddr - (scb->sg_list_busaddr - ahd_sg_size(ahd));
368*1da177e4SLinus Torvalds 	return ((uint8_t *)scb->sg_list + sg_offset);
369*1da177e4SLinus Torvalds }
370*1da177e4SLinus Torvalds 
371*1da177e4SLinus Torvalds static __inline uint32_t
372*1da177e4SLinus Torvalds ahd_sg_virt_to_bus(struct ahd_softc *ahd, struct scb *scb, void *sg)
373*1da177e4SLinus Torvalds {
374*1da177e4SLinus Torvalds 	dma_addr_t sg_offset;
375*1da177e4SLinus Torvalds 
376*1da177e4SLinus Torvalds 	/* sg_list_phys points to entry 1, not 0 */
377*1da177e4SLinus Torvalds 	sg_offset = ((uint8_t *)sg - (uint8_t *)scb->sg_list)
378*1da177e4SLinus Torvalds 		  - ahd_sg_size(ahd);
379*1da177e4SLinus Torvalds 
380*1da177e4SLinus Torvalds 	return (scb->sg_list_busaddr + sg_offset);
381*1da177e4SLinus Torvalds }
382*1da177e4SLinus Torvalds 
383*1da177e4SLinus Torvalds static __inline void
384*1da177e4SLinus Torvalds ahd_sync_scb(struct ahd_softc *ahd, struct scb *scb, int op)
385*1da177e4SLinus Torvalds {
386*1da177e4SLinus Torvalds 	ahd_dmamap_sync(ahd, ahd->scb_data.hscb_dmat,
387*1da177e4SLinus Torvalds 			scb->hscb_map->dmamap,
388*1da177e4SLinus Torvalds 			/*offset*/(uint8_t*)scb->hscb - scb->hscb_map->vaddr,
389*1da177e4SLinus Torvalds 			/*len*/sizeof(*scb->hscb), op);
390*1da177e4SLinus Torvalds }
391*1da177e4SLinus Torvalds 
392*1da177e4SLinus Torvalds static __inline void
393*1da177e4SLinus Torvalds ahd_sync_sglist(struct ahd_softc *ahd, struct scb *scb, int op)
394*1da177e4SLinus Torvalds {
395*1da177e4SLinus Torvalds 	if (scb->sg_count == 0)
396*1da177e4SLinus Torvalds 		return;
397*1da177e4SLinus Torvalds 
398*1da177e4SLinus Torvalds 	ahd_dmamap_sync(ahd, ahd->scb_data.sg_dmat,
399*1da177e4SLinus Torvalds 			scb->sg_map->dmamap,
400*1da177e4SLinus Torvalds 			/*offset*/scb->sg_list_busaddr - ahd_sg_size(ahd),
401*1da177e4SLinus Torvalds 			/*len*/ahd_sg_size(ahd) * scb->sg_count, op);
402*1da177e4SLinus Torvalds }
403*1da177e4SLinus Torvalds 
404*1da177e4SLinus Torvalds static __inline void
405*1da177e4SLinus Torvalds ahd_sync_sense(struct ahd_softc *ahd, struct scb *scb, int op)
406*1da177e4SLinus Torvalds {
407*1da177e4SLinus Torvalds 	ahd_dmamap_sync(ahd, ahd->scb_data.sense_dmat,
408*1da177e4SLinus Torvalds 			scb->sense_map->dmamap,
409*1da177e4SLinus Torvalds 			/*offset*/scb->sense_busaddr,
410*1da177e4SLinus Torvalds 			/*len*/AHD_SENSE_BUFSIZE, op);
411*1da177e4SLinus Torvalds }
412*1da177e4SLinus Torvalds 
413*1da177e4SLinus Torvalds static __inline uint32_t
414*1da177e4SLinus Torvalds ahd_targetcmd_offset(struct ahd_softc *ahd, u_int index)
415*1da177e4SLinus Torvalds {
416*1da177e4SLinus Torvalds 	return (((uint8_t *)&ahd->targetcmds[index])
417*1da177e4SLinus Torvalds 	       - (uint8_t *)ahd->qoutfifo);
418*1da177e4SLinus Torvalds }
419*1da177e4SLinus Torvalds 
420*1da177e4SLinus Torvalds /*********************** Miscelaneous Support Functions ***********************/
421*1da177e4SLinus Torvalds static __inline void	ahd_complete_scb(struct ahd_softc *ahd,
422*1da177e4SLinus Torvalds 					 struct scb *scb);
423*1da177e4SLinus Torvalds static __inline void	ahd_update_residual(struct ahd_softc *ahd,
424*1da177e4SLinus Torvalds 					    struct scb *scb);
425*1da177e4SLinus Torvalds static __inline struct ahd_initiator_tinfo *
426*1da177e4SLinus Torvalds 			ahd_fetch_transinfo(struct ahd_softc *ahd,
427*1da177e4SLinus Torvalds 					    char channel, u_int our_id,
428*1da177e4SLinus Torvalds 					    u_int remote_id,
429*1da177e4SLinus Torvalds 					    struct ahd_tmode_tstate **tstate);
430*1da177e4SLinus Torvalds static __inline uint16_t
431*1da177e4SLinus Torvalds 			ahd_inw(struct ahd_softc *ahd, u_int port);
432*1da177e4SLinus Torvalds static __inline void	ahd_outw(struct ahd_softc *ahd, u_int port,
433*1da177e4SLinus Torvalds 				 u_int value);
434*1da177e4SLinus Torvalds static __inline uint32_t
435*1da177e4SLinus Torvalds 			ahd_inl(struct ahd_softc *ahd, u_int port);
436*1da177e4SLinus Torvalds static __inline void	ahd_outl(struct ahd_softc *ahd, u_int port,
437*1da177e4SLinus Torvalds 				 uint32_t value);
438*1da177e4SLinus Torvalds static __inline uint64_t
439*1da177e4SLinus Torvalds 			ahd_inq(struct ahd_softc *ahd, u_int port);
440*1da177e4SLinus Torvalds static __inline void	ahd_outq(struct ahd_softc *ahd, u_int port,
441*1da177e4SLinus Torvalds 				 uint64_t value);
442*1da177e4SLinus Torvalds static __inline u_int	ahd_get_scbptr(struct ahd_softc *ahd);
443*1da177e4SLinus Torvalds static __inline void	ahd_set_scbptr(struct ahd_softc *ahd, u_int scbptr);
444*1da177e4SLinus Torvalds static __inline u_int	ahd_get_hnscb_qoff(struct ahd_softc *ahd);
445*1da177e4SLinus Torvalds static __inline void	ahd_set_hnscb_qoff(struct ahd_softc *ahd, u_int value);
446*1da177e4SLinus Torvalds static __inline u_int	ahd_get_hescb_qoff(struct ahd_softc *ahd);
447*1da177e4SLinus Torvalds static __inline void	ahd_set_hescb_qoff(struct ahd_softc *ahd, u_int value);
448*1da177e4SLinus Torvalds static __inline u_int	ahd_get_snscb_qoff(struct ahd_softc *ahd);
449*1da177e4SLinus Torvalds static __inline void	ahd_set_snscb_qoff(struct ahd_softc *ahd, u_int value);
450*1da177e4SLinus Torvalds static __inline u_int	ahd_get_sescb_qoff(struct ahd_softc *ahd);
451*1da177e4SLinus Torvalds static __inline void	ahd_set_sescb_qoff(struct ahd_softc *ahd, u_int value);
452*1da177e4SLinus Torvalds static __inline u_int	ahd_get_sdscb_qoff(struct ahd_softc *ahd);
453*1da177e4SLinus Torvalds static __inline void	ahd_set_sdscb_qoff(struct ahd_softc *ahd, u_int value);
454*1da177e4SLinus Torvalds static __inline u_int	ahd_inb_scbram(struct ahd_softc *ahd, u_int offset);
455*1da177e4SLinus Torvalds static __inline u_int	ahd_inw_scbram(struct ahd_softc *ahd, u_int offset);
456*1da177e4SLinus Torvalds static __inline uint32_t
457*1da177e4SLinus Torvalds 			ahd_inl_scbram(struct ahd_softc *ahd, u_int offset);
458*1da177e4SLinus Torvalds static __inline uint64_t
459*1da177e4SLinus Torvalds 			ahd_inq_scbram(struct ahd_softc *ahd, u_int offset);
460*1da177e4SLinus Torvalds static __inline void	ahd_swap_with_next_hscb(struct ahd_softc *ahd,
461*1da177e4SLinus Torvalds 						struct scb *scb);
462*1da177e4SLinus Torvalds static __inline void	ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb);
463*1da177e4SLinus Torvalds static __inline uint8_t *
464*1da177e4SLinus Torvalds 			ahd_get_sense_buf(struct ahd_softc *ahd,
465*1da177e4SLinus Torvalds 					  struct scb *scb);
466*1da177e4SLinus Torvalds static __inline uint32_t
467*1da177e4SLinus Torvalds 			ahd_get_sense_bufaddr(struct ahd_softc *ahd,
468*1da177e4SLinus Torvalds 					      struct scb *scb);
469*1da177e4SLinus Torvalds 
470*1da177e4SLinus Torvalds static __inline void
471*1da177e4SLinus Torvalds ahd_complete_scb(struct ahd_softc *ahd, struct scb *scb)
472*1da177e4SLinus Torvalds {
473*1da177e4SLinus Torvalds 	uint32_t sgptr;
474*1da177e4SLinus Torvalds 
475*1da177e4SLinus Torvalds 	sgptr = ahd_le32toh(scb->hscb->sgptr);
476*1da177e4SLinus Torvalds 	if ((sgptr & SG_STATUS_VALID) != 0)
477*1da177e4SLinus Torvalds 		ahd_handle_scb_status(ahd, scb);
478*1da177e4SLinus Torvalds 	else
479*1da177e4SLinus Torvalds 		ahd_done(ahd, scb);
480*1da177e4SLinus Torvalds }
481*1da177e4SLinus Torvalds 
482*1da177e4SLinus Torvalds /*
483*1da177e4SLinus Torvalds  * Determine whether the sequencer reported a residual
484*1da177e4SLinus Torvalds  * for this SCB/transaction.
485*1da177e4SLinus Torvalds  */
486*1da177e4SLinus Torvalds static __inline void
487*1da177e4SLinus Torvalds ahd_update_residual(struct ahd_softc *ahd, struct scb *scb)
488*1da177e4SLinus Torvalds {
489*1da177e4SLinus Torvalds 	uint32_t sgptr;
490*1da177e4SLinus Torvalds 
491*1da177e4SLinus Torvalds 	sgptr = ahd_le32toh(scb->hscb->sgptr);
492*1da177e4SLinus Torvalds 	if ((sgptr & SG_STATUS_VALID) != 0)
493*1da177e4SLinus Torvalds 		ahd_calc_residual(ahd, scb);
494*1da177e4SLinus Torvalds }
495*1da177e4SLinus Torvalds 
496*1da177e4SLinus Torvalds /*
497*1da177e4SLinus Torvalds  * Return pointers to the transfer negotiation information
498*1da177e4SLinus Torvalds  * for the specified our_id/remote_id pair.
499*1da177e4SLinus Torvalds  */
500*1da177e4SLinus Torvalds static __inline struct ahd_initiator_tinfo *
501*1da177e4SLinus Torvalds ahd_fetch_transinfo(struct ahd_softc *ahd, char channel, u_int our_id,
502*1da177e4SLinus Torvalds 		    u_int remote_id, struct ahd_tmode_tstate **tstate)
503*1da177e4SLinus Torvalds {
504*1da177e4SLinus Torvalds 	/*
505*1da177e4SLinus Torvalds 	 * Transfer data structures are stored from the perspective
506*1da177e4SLinus Torvalds 	 * of the target role.  Since the parameters for a connection
507*1da177e4SLinus Torvalds 	 * in the initiator role to a given target are the same as
508*1da177e4SLinus Torvalds 	 * when the roles are reversed, we pretend we are the target.
509*1da177e4SLinus Torvalds 	 */
510*1da177e4SLinus Torvalds 	if (channel == 'B')
511*1da177e4SLinus Torvalds 		our_id += 8;
512*1da177e4SLinus Torvalds 	*tstate = ahd->enabled_targets[our_id];
513*1da177e4SLinus Torvalds 	return (&(*tstate)->transinfo[remote_id]);
514*1da177e4SLinus Torvalds }
515*1da177e4SLinus Torvalds 
516*1da177e4SLinus Torvalds #define AHD_COPY_COL_IDX(dst, src)				\
517*1da177e4SLinus Torvalds do {								\
518*1da177e4SLinus Torvalds 	dst->hscb->scsiid = src->hscb->scsiid;			\
519*1da177e4SLinus Torvalds 	dst->hscb->lun = src->hscb->lun;			\
520*1da177e4SLinus Torvalds } while (0)
521*1da177e4SLinus Torvalds 
522*1da177e4SLinus Torvalds static __inline uint16_t
523*1da177e4SLinus Torvalds ahd_inw(struct ahd_softc *ahd, u_int port)
524*1da177e4SLinus Torvalds {
525*1da177e4SLinus Torvalds 	return ((ahd_inb(ahd, port+1) << 8) | ahd_inb(ahd, port));
526*1da177e4SLinus Torvalds }
527*1da177e4SLinus Torvalds 
528*1da177e4SLinus Torvalds static __inline void
529*1da177e4SLinus Torvalds ahd_outw(struct ahd_softc *ahd, u_int port, u_int value)
530*1da177e4SLinus Torvalds {
531*1da177e4SLinus Torvalds 	ahd_outb(ahd, port, value & 0xFF);
532*1da177e4SLinus Torvalds 	ahd_outb(ahd, port+1, (value >> 8) & 0xFF);
533*1da177e4SLinus Torvalds }
534*1da177e4SLinus Torvalds 
535*1da177e4SLinus Torvalds static __inline uint32_t
536*1da177e4SLinus Torvalds ahd_inl(struct ahd_softc *ahd, u_int port)
537*1da177e4SLinus Torvalds {
538*1da177e4SLinus Torvalds 	return ((ahd_inb(ahd, port))
539*1da177e4SLinus Torvalds 	      | (ahd_inb(ahd, port+1) << 8)
540*1da177e4SLinus Torvalds 	      | (ahd_inb(ahd, port+2) << 16)
541*1da177e4SLinus Torvalds 	      | (ahd_inb(ahd, port+3) << 24));
542*1da177e4SLinus Torvalds }
543*1da177e4SLinus Torvalds 
544*1da177e4SLinus Torvalds static __inline void
545*1da177e4SLinus Torvalds ahd_outl(struct ahd_softc *ahd, u_int port, uint32_t value)
546*1da177e4SLinus Torvalds {
547*1da177e4SLinus Torvalds 	ahd_outb(ahd, port, (value) & 0xFF);
548*1da177e4SLinus Torvalds 	ahd_outb(ahd, port+1, ((value) >> 8) & 0xFF);
549*1da177e4SLinus Torvalds 	ahd_outb(ahd, port+2, ((value) >> 16) & 0xFF);
550*1da177e4SLinus Torvalds 	ahd_outb(ahd, port+3, ((value) >> 24) & 0xFF);
551*1da177e4SLinus Torvalds }
552*1da177e4SLinus Torvalds 
553*1da177e4SLinus Torvalds static __inline uint64_t
554*1da177e4SLinus Torvalds ahd_inq(struct ahd_softc *ahd, u_int port)
555*1da177e4SLinus Torvalds {
556*1da177e4SLinus Torvalds 	return ((ahd_inb(ahd, port))
557*1da177e4SLinus Torvalds 	      | (ahd_inb(ahd, port+1) << 8)
558*1da177e4SLinus Torvalds 	      | (ahd_inb(ahd, port+2) << 16)
559*1da177e4SLinus Torvalds 	      | (ahd_inb(ahd, port+3) << 24)
560*1da177e4SLinus Torvalds 	      | (((uint64_t)ahd_inb(ahd, port+4)) << 32)
561*1da177e4SLinus Torvalds 	      | (((uint64_t)ahd_inb(ahd, port+5)) << 40)
562*1da177e4SLinus Torvalds 	      | (((uint64_t)ahd_inb(ahd, port+6)) << 48)
563*1da177e4SLinus Torvalds 	      | (((uint64_t)ahd_inb(ahd, port+7)) << 56));
564*1da177e4SLinus Torvalds }
565*1da177e4SLinus Torvalds 
566*1da177e4SLinus Torvalds static __inline void
567*1da177e4SLinus Torvalds ahd_outq(struct ahd_softc *ahd, u_int port, uint64_t value)
568*1da177e4SLinus Torvalds {
569*1da177e4SLinus Torvalds 	ahd_outb(ahd, port, value & 0xFF);
570*1da177e4SLinus Torvalds 	ahd_outb(ahd, port+1, (value >> 8) & 0xFF);
571*1da177e4SLinus Torvalds 	ahd_outb(ahd, port+2, (value >> 16) & 0xFF);
572*1da177e4SLinus Torvalds 	ahd_outb(ahd, port+3, (value >> 24) & 0xFF);
573*1da177e4SLinus Torvalds 	ahd_outb(ahd, port+4, (value >> 32) & 0xFF);
574*1da177e4SLinus Torvalds 	ahd_outb(ahd, port+5, (value >> 40) & 0xFF);
575*1da177e4SLinus Torvalds 	ahd_outb(ahd, port+6, (value >> 48) & 0xFF);
576*1da177e4SLinus Torvalds 	ahd_outb(ahd, port+7, (value >> 56) & 0xFF);
577*1da177e4SLinus Torvalds }
578*1da177e4SLinus Torvalds 
579*1da177e4SLinus Torvalds static __inline u_int
580*1da177e4SLinus Torvalds ahd_get_scbptr(struct ahd_softc *ahd)
581*1da177e4SLinus Torvalds {
582*1da177e4SLinus Torvalds 	AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK),
583*1da177e4SLinus Torvalds 			 ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK));
584*1da177e4SLinus Torvalds 	return (ahd_inb(ahd, SCBPTR) | (ahd_inb(ahd, SCBPTR + 1) << 8));
585*1da177e4SLinus Torvalds }
586*1da177e4SLinus Torvalds 
587*1da177e4SLinus Torvalds static __inline void
588*1da177e4SLinus Torvalds ahd_set_scbptr(struct ahd_softc *ahd, u_int scbptr)
589*1da177e4SLinus Torvalds {
590*1da177e4SLinus Torvalds 	AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK),
591*1da177e4SLinus Torvalds 			 ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK));
592*1da177e4SLinus Torvalds 	ahd_outb(ahd, SCBPTR, scbptr & 0xFF);
593*1da177e4SLinus Torvalds 	ahd_outb(ahd, SCBPTR+1, (scbptr >> 8) & 0xFF);
594*1da177e4SLinus Torvalds }
595*1da177e4SLinus Torvalds 
596*1da177e4SLinus Torvalds static __inline u_int
597*1da177e4SLinus Torvalds ahd_get_hnscb_qoff(struct ahd_softc *ahd)
598*1da177e4SLinus Torvalds {
599*1da177e4SLinus Torvalds 	return (ahd_inw_atomic(ahd, HNSCB_QOFF));
600*1da177e4SLinus Torvalds }
601*1da177e4SLinus Torvalds 
602*1da177e4SLinus Torvalds static __inline void
603*1da177e4SLinus Torvalds ahd_set_hnscb_qoff(struct ahd_softc *ahd, u_int value)
604*1da177e4SLinus Torvalds {
605*1da177e4SLinus Torvalds 	ahd_outw_atomic(ahd, HNSCB_QOFF, value);
606*1da177e4SLinus Torvalds }
607*1da177e4SLinus Torvalds 
608*1da177e4SLinus Torvalds static __inline u_int
609*1da177e4SLinus Torvalds ahd_get_hescb_qoff(struct ahd_softc *ahd)
610*1da177e4SLinus Torvalds {
611*1da177e4SLinus Torvalds 	return (ahd_inb(ahd, HESCB_QOFF));
612*1da177e4SLinus Torvalds }
613*1da177e4SLinus Torvalds 
614*1da177e4SLinus Torvalds static __inline void
615*1da177e4SLinus Torvalds ahd_set_hescb_qoff(struct ahd_softc *ahd, u_int value)
616*1da177e4SLinus Torvalds {
617*1da177e4SLinus Torvalds 	ahd_outb(ahd, HESCB_QOFF, value);
618*1da177e4SLinus Torvalds }
619*1da177e4SLinus Torvalds 
620*1da177e4SLinus Torvalds static __inline u_int
621*1da177e4SLinus Torvalds ahd_get_snscb_qoff(struct ahd_softc *ahd)
622*1da177e4SLinus Torvalds {
623*1da177e4SLinus Torvalds 	u_int oldvalue;
624*1da177e4SLinus Torvalds 
625*1da177e4SLinus Torvalds 	AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
626*1da177e4SLinus Torvalds 	oldvalue = ahd_inw(ahd, SNSCB_QOFF);
627*1da177e4SLinus Torvalds 	ahd_outw(ahd, SNSCB_QOFF, oldvalue);
628*1da177e4SLinus Torvalds 	return (oldvalue);
629*1da177e4SLinus Torvalds }
630*1da177e4SLinus Torvalds 
631*1da177e4SLinus Torvalds static __inline void
632*1da177e4SLinus Torvalds ahd_set_snscb_qoff(struct ahd_softc *ahd, u_int value)
633*1da177e4SLinus Torvalds {
634*1da177e4SLinus Torvalds 	AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
635*1da177e4SLinus Torvalds 	ahd_outw(ahd, SNSCB_QOFF, value);
636*1da177e4SLinus Torvalds }
637*1da177e4SLinus Torvalds 
638*1da177e4SLinus Torvalds static __inline u_int
639*1da177e4SLinus Torvalds ahd_get_sescb_qoff(struct ahd_softc *ahd)
640*1da177e4SLinus Torvalds {
641*1da177e4SLinus Torvalds 	AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
642*1da177e4SLinus Torvalds 	return (ahd_inb(ahd, SESCB_QOFF));
643*1da177e4SLinus Torvalds }
644*1da177e4SLinus Torvalds 
645*1da177e4SLinus Torvalds static __inline void
646*1da177e4SLinus Torvalds ahd_set_sescb_qoff(struct ahd_softc *ahd, u_int value)
647*1da177e4SLinus Torvalds {
648*1da177e4SLinus Torvalds 	AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
649*1da177e4SLinus Torvalds 	ahd_outb(ahd, SESCB_QOFF, value);
650*1da177e4SLinus Torvalds }
651*1da177e4SLinus Torvalds 
652*1da177e4SLinus Torvalds static __inline u_int
653*1da177e4SLinus Torvalds ahd_get_sdscb_qoff(struct ahd_softc *ahd)
654*1da177e4SLinus Torvalds {
655*1da177e4SLinus Torvalds 	AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
656*1da177e4SLinus Torvalds 	return (ahd_inb(ahd, SDSCB_QOFF) | (ahd_inb(ahd, SDSCB_QOFF + 1) << 8));
657*1da177e4SLinus Torvalds }
658*1da177e4SLinus Torvalds 
659*1da177e4SLinus Torvalds static __inline void
660*1da177e4SLinus Torvalds ahd_set_sdscb_qoff(struct ahd_softc *ahd, u_int value)
661*1da177e4SLinus Torvalds {
662*1da177e4SLinus Torvalds 	AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
663*1da177e4SLinus Torvalds 	ahd_outb(ahd, SDSCB_QOFF, value & 0xFF);
664*1da177e4SLinus Torvalds 	ahd_outb(ahd, SDSCB_QOFF+1, (value >> 8) & 0xFF);
665*1da177e4SLinus Torvalds }
666*1da177e4SLinus Torvalds 
667*1da177e4SLinus Torvalds static __inline u_int
668*1da177e4SLinus Torvalds ahd_inb_scbram(struct ahd_softc *ahd, u_int offset)
669*1da177e4SLinus Torvalds {
670*1da177e4SLinus Torvalds 	u_int value;
671*1da177e4SLinus Torvalds 
672*1da177e4SLinus Torvalds 	/*
673*1da177e4SLinus Torvalds 	 * Workaround PCI-X Rev A. hardware bug.
674*1da177e4SLinus Torvalds 	 * After a host read of SCB memory, the chip
675*1da177e4SLinus Torvalds 	 * may become confused into thinking prefetch
676*1da177e4SLinus Torvalds 	 * was required.  This starts the discard timer
677*1da177e4SLinus Torvalds 	 * running and can cause an unexpected discard
678*1da177e4SLinus Torvalds 	 * timer interrupt.  The work around is to read
679*1da177e4SLinus Torvalds 	 * a normal register prior to the exhaustion of
680*1da177e4SLinus Torvalds 	 * the discard timer.  The mode pointer register
681*1da177e4SLinus Torvalds 	 * has no side effects and so serves well for
682*1da177e4SLinus Torvalds 	 * this purpose.
683*1da177e4SLinus Torvalds 	 *
684*1da177e4SLinus Torvalds 	 * Razor #528
685*1da177e4SLinus Torvalds 	 */
686*1da177e4SLinus Torvalds 	value = ahd_inb(ahd, offset);
687*1da177e4SLinus Torvalds 	if ((ahd->flags & AHD_PCIX_SCBRAM_RD_BUG) != 0)
688*1da177e4SLinus Torvalds 		ahd_inb(ahd, MODE_PTR);
689*1da177e4SLinus Torvalds 	return (value);
690*1da177e4SLinus Torvalds }
691*1da177e4SLinus Torvalds 
692*1da177e4SLinus Torvalds static __inline u_int
693*1da177e4SLinus Torvalds ahd_inw_scbram(struct ahd_softc *ahd, u_int offset)
694*1da177e4SLinus Torvalds {
695*1da177e4SLinus Torvalds 	return (ahd_inb_scbram(ahd, offset)
696*1da177e4SLinus Torvalds 	      | (ahd_inb_scbram(ahd, offset+1) << 8));
697*1da177e4SLinus Torvalds }
698*1da177e4SLinus Torvalds 
699*1da177e4SLinus Torvalds static __inline uint32_t
700*1da177e4SLinus Torvalds ahd_inl_scbram(struct ahd_softc *ahd, u_int offset)
701*1da177e4SLinus Torvalds {
702*1da177e4SLinus Torvalds 	return (ahd_inw_scbram(ahd, offset)
703*1da177e4SLinus Torvalds 	      | (ahd_inw_scbram(ahd, offset+2) << 16));
704*1da177e4SLinus Torvalds }
705*1da177e4SLinus Torvalds 
706*1da177e4SLinus Torvalds static __inline uint64_t
707*1da177e4SLinus Torvalds ahd_inq_scbram(struct ahd_softc *ahd, u_int offset)
708*1da177e4SLinus Torvalds {
709*1da177e4SLinus Torvalds 	return (ahd_inl_scbram(ahd, offset)
710*1da177e4SLinus Torvalds 	      | ((uint64_t)ahd_inl_scbram(ahd, offset+4)) << 32);
711*1da177e4SLinus Torvalds }
712*1da177e4SLinus Torvalds 
713*1da177e4SLinus Torvalds static __inline struct scb *
714*1da177e4SLinus Torvalds ahd_lookup_scb(struct ahd_softc *ahd, u_int tag)
715*1da177e4SLinus Torvalds {
716*1da177e4SLinus Torvalds 	struct scb* scb;
717*1da177e4SLinus Torvalds 
718*1da177e4SLinus Torvalds 	if (tag >= AHD_SCB_MAX)
719*1da177e4SLinus Torvalds 		return (NULL);
720*1da177e4SLinus Torvalds 	scb = ahd->scb_data.scbindex[tag];
721*1da177e4SLinus Torvalds 	if (scb != NULL)
722*1da177e4SLinus Torvalds 		ahd_sync_scb(ahd, scb,
723*1da177e4SLinus Torvalds 			     BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
724*1da177e4SLinus Torvalds 	return (scb);
725*1da177e4SLinus Torvalds }
726*1da177e4SLinus Torvalds 
727*1da177e4SLinus Torvalds static __inline void
728*1da177e4SLinus Torvalds ahd_swap_with_next_hscb(struct ahd_softc *ahd, struct scb *scb)
729*1da177e4SLinus Torvalds {
730*1da177e4SLinus Torvalds 	struct hardware_scb *q_hscb;
731*1da177e4SLinus Torvalds 	uint32_t saved_hscb_busaddr;
732*1da177e4SLinus Torvalds 
733*1da177e4SLinus Torvalds 	/*
734*1da177e4SLinus Torvalds 	 * Our queuing method is a bit tricky.  The card
735*1da177e4SLinus Torvalds 	 * knows in advance which HSCB (by address) to download,
736*1da177e4SLinus Torvalds 	 * and we can't disappoint it.  To achieve this, the next
737*1da177e4SLinus Torvalds 	 * HSCB to download is saved off in ahd->next_queued_hscb.
738*1da177e4SLinus Torvalds 	 * When we are called to queue "an arbitrary scb",
739*1da177e4SLinus Torvalds 	 * we copy the contents of the incoming HSCB to the one
740*1da177e4SLinus Torvalds 	 * the sequencer knows about, swap HSCB pointers and
741*1da177e4SLinus Torvalds 	 * finally assign the SCB to the tag indexed location
742*1da177e4SLinus Torvalds 	 * in the scb_array.  This makes sure that we can still
743*1da177e4SLinus Torvalds 	 * locate the correct SCB by SCB_TAG.
744*1da177e4SLinus Torvalds 	 */
745*1da177e4SLinus Torvalds 	q_hscb = ahd->next_queued_hscb;
746*1da177e4SLinus Torvalds 	saved_hscb_busaddr = q_hscb->hscb_busaddr;
747*1da177e4SLinus Torvalds 	memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb));
748*1da177e4SLinus Torvalds 	q_hscb->hscb_busaddr = saved_hscb_busaddr;
749*1da177e4SLinus Torvalds 	q_hscb->next_hscb_busaddr = scb->hscb->hscb_busaddr;
750*1da177e4SLinus Torvalds 
751*1da177e4SLinus Torvalds 	/* Now swap HSCB pointers. */
752*1da177e4SLinus Torvalds 	ahd->next_queued_hscb = scb->hscb;
753*1da177e4SLinus Torvalds 	scb->hscb = q_hscb;
754*1da177e4SLinus Torvalds 
755*1da177e4SLinus Torvalds 	/* Now define the mapping from tag to SCB in the scbindex */
756*1da177e4SLinus Torvalds 	ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = scb;
757*1da177e4SLinus Torvalds }
758*1da177e4SLinus Torvalds 
759*1da177e4SLinus Torvalds /*
760*1da177e4SLinus Torvalds  * Tell the sequencer about a new transaction to execute.
761*1da177e4SLinus Torvalds  */
762*1da177e4SLinus Torvalds static __inline void
763*1da177e4SLinus Torvalds ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb)
764*1da177e4SLinus Torvalds {
765*1da177e4SLinus Torvalds 	ahd_swap_with_next_hscb(ahd, scb);
766*1da177e4SLinus Torvalds 
767*1da177e4SLinus Torvalds 	if (SCBID_IS_NULL(SCB_GET_TAG(scb)))
768*1da177e4SLinus Torvalds 		panic("Attempt to queue invalid SCB tag %x\n",
769*1da177e4SLinus Torvalds 		      SCB_GET_TAG(scb));
770*1da177e4SLinus Torvalds 
771*1da177e4SLinus Torvalds 	/*
772*1da177e4SLinus Torvalds 	 * Keep a history of SCBs we've downloaded in the qinfifo.
773*1da177e4SLinus Torvalds 	 */
774*1da177e4SLinus Torvalds 	ahd->qinfifo[AHD_QIN_WRAP(ahd->qinfifonext)] = SCB_GET_TAG(scb);
775*1da177e4SLinus Torvalds 	ahd->qinfifonext++;
776*1da177e4SLinus Torvalds 
777*1da177e4SLinus Torvalds 	if (scb->sg_count != 0)
778*1da177e4SLinus Torvalds 		ahd_setup_data_scb(ahd, scb);
779*1da177e4SLinus Torvalds 	else
780*1da177e4SLinus Torvalds 		ahd_setup_noxfer_scb(ahd, scb);
781*1da177e4SLinus Torvalds 	ahd_setup_scb_common(ahd, scb);
782*1da177e4SLinus Torvalds 
783*1da177e4SLinus Torvalds 	/*
784*1da177e4SLinus Torvalds 	 * Make sure our data is consistent from the
785*1da177e4SLinus Torvalds 	 * perspective of the adapter.
786*1da177e4SLinus Torvalds 	 */
787*1da177e4SLinus Torvalds 	ahd_sync_scb(ahd, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
788*1da177e4SLinus Torvalds 
789*1da177e4SLinus Torvalds #ifdef AHD_DEBUG
790*1da177e4SLinus Torvalds 	if ((ahd_debug & AHD_SHOW_QUEUE) != 0) {
791*1da177e4SLinus Torvalds 		uint64_t host_dataptr;
792*1da177e4SLinus Torvalds 
793*1da177e4SLinus Torvalds 		host_dataptr = ahd_le64toh(scb->hscb->dataptr);
794*1da177e4SLinus Torvalds 		printf("%s: Queueing SCB 0x%x bus addr 0x%x - 0x%x%x/0x%x\n",
795*1da177e4SLinus Torvalds 		       ahd_name(ahd),
796*1da177e4SLinus Torvalds 		       SCB_GET_TAG(scb), ahd_le32toh(scb->hscb->hscb_busaddr),
797*1da177e4SLinus Torvalds 		       (u_int)((host_dataptr >> 32) & 0xFFFFFFFF),
798*1da177e4SLinus Torvalds 		       (u_int)(host_dataptr & 0xFFFFFFFF),
799*1da177e4SLinus Torvalds 		       ahd_le32toh(scb->hscb->datacnt));
800*1da177e4SLinus Torvalds 	}
801*1da177e4SLinus Torvalds #endif
802*1da177e4SLinus Torvalds 	/* Tell the adapter about the newly queued SCB */
803*1da177e4SLinus Torvalds 	ahd_set_hnscb_qoff(ahd, ahd->qinfifonext);
804*1da177e4SLinus Torvalds }
805*1da177e4SLinus Torvalds 
806*1da177e4SLinus Torvalds static __inline uint8_t *
807*1da177e4SLinus Torvalds ahd_get_sense_buf(struct ahd_softc *ahd, struct scb *scb)
808*1da177e4SLinus Torvalds {
809*1da177e4SLinus Torvalds 	return (scb->sense_data);
810*1da177e4SLinus Torvalds }
811*1da177e4SLinus Torvalds 
812*1da177e4SLinus Torvalds static __inline uint32_t
813*1da177e4SLinus Torvalds ahd_get_sense_bufaddr(struct ahd_softc *ahd, struct scb *scb)
814*1da177e4SLinus Torvalds {
815*1da177e4SLinus Torvalds 	return (scb->sense_busaddr);
816*1da177e4SLinus Torvalds }
817*1da177e4SLinus Torvalds 
818*1da177e4SLinus Torvalds /************************** Interrupt Processing ******************************/
819*1da177e4SLinus Torvalds static __inline void	ahd_sync_qoutfifo(struct ahd_softc *ahd, int op);
820*1da177e4SLinus Torvalds static __inline void	ahd_sync_tqinfifo(struct ahd_softc *ahd, int op);
821*1da177e4SLinus Torvalds static __inline u_int	ahd_check_cmdcmpltqueues(struct ahd_softc *ahd);
822*1da177e4SLinus Torvalds static __inline int	ahd_intr(struct ahd_softc *ahd);
823*1da177e4SLinus Torvalds 
824*1da177e4SLinus Torvalds static __inline void
825*1da177e4SLinus Torvalds ahd_sync_qoutfifo(struct ahd_softc *ahd, int op)
826*1da177e4SLinus Torvalds {
827*1da177e4SLinus Torvalds 	ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_dmamap,
828*1da177e4SLinus Torvalds 			/*offset*/0, /*len*/AHC_SCB_MAX * sizeof(uint16_t), op);
829*1da177e4SLinus Torvalds }
830*1da177e4SLinus Torvalds 
831*1da177e4SLinus Torvalds static __inline void
832*1da177e4SLinus Torvalds ahd_sync_tqinfifo(struct ahd_softc *ahd, int op)
833*1da177e4SLinus Torvalds {
834*1da177e4SLinus Torvalds #ifdef AHD_TARGET_MODE
835*1da177e4SLinus Torvalds 	if ((ahd->flags & AHD_TARGETROLE) != 0) {
836*1da177e4SLinus Torvalds 		ahd_dmamap_sync(ahd, ahd->shared_data_dmat,
837*1da177e4SLinus Torvalds 				ahd->shared_data_dmamap,
838*1da177e4SLinus Torvalds 				ahd_targetcmd_offset(ahd, 0),
839*1da177e4SLinus Torvalds 				sizeof(struct target_cmd) * AHD_TMODE_CMDS,
840*1da177e4SLinus Torvalds 				op);
841*1da177e4SLinus Torvalds 	}
842*1da177e4SLinus Torvalds #endif
843*1da177e4SLinus Torvalds }
844*1da177e4SLinus Torvalds 
845*1da177e4SLinus Torvalds /*
846*1da177e4SLinus Torvalds  * See if the firmware has posted any completed commands
847*1da177e4SLinus Torvalds  * into our in-core command complete fifos.
848*1da177e4SLinus Torvalds  */
849*1da177e4SLinus Torvalds #define AHD_RUN_QOUTFIFO 0x1
850*1da177e4SLinus Torvalds #define AHD_RUN_TQINFIFO 0x2
851*1da177e4SLinus Torvalds static __inline u_int
852*1da177e4SLinus Torvalds ahd_check_cmdcmpltqueues(struct ahd_softc *ahd)
853*1da177e4SLinus Torvalds {
854*1da177e4SLinus Torvalds 	u_int retval;
855*1da177e4SLinus Torvalds 
856*1da177e4SLinus Torvalds 	retval = 0;
857*1da177e4SLinus Torvalds 	ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_dmamap,
858*1da177e4SLinus Torvalds 			/*offset*/ahd->qoutfifonext, /*len*/2,
859*1da177e4SLinus Torvalds 			BUS_DMASYNC_POSTREAD);
860*1da177e4SLinus Torvalds 	if ((ahd->qoutfifo[ahd->qoutfifonext]
861*1da177e4SLinus Torvalds 	     & QOUTFIFO_ENTRY_VALID_LE) == ahd->qoutfifonext_valid_tag)
862*1da177e4SLinus Torvalds 		retval |= AHD_RUN_QOUTFIFO;
863*1da177e4SLinus Torvalds #ifdef AHD_TARGET_MODE
864*1da177e4SLinus Torvalds 	if ((ahd->flags & AHD_TARGETROLE) != 0
865*1da177e4SLinus Torvalds 	 && (ahd->flags & AHD_TQINFIFO_BLOCKED) == 0) {
866*1da177e4SLinus Torvalds 		ahd_dmamap_sync(ahd, ahd->shared_data_dmat,
867*1da177e4SLinus Torvalds 				ahd->shared_data_dmamap,
868*1da177e4SLinus Torvalds 				ahd_targetcmd_offset(ahd, ahd->tqinfifofnext),
869*1da177e4SLinus Torvalds 				/*len*/sizeof(struct target_cmd),
870*1da177e4SLinus Torvalds 				BUS_DMASYNC_POSTREAD);
871*1da177e4SLinus Torvalds 		if (ahd->targetcmds[ahd->tqinfifonext].cmd_valid != 0)
872*1da177e4SLinus Torvalds 			retval |= AHD_RUN_TQINFIFO;
873*1da177e4SLinus Torvalds 	}
874*1da177e4SLinus Torvalds #endif
875*1da177e4SLinus Torvalds 	return (retval);
876*1da177e4SLinus Torvalds }
877*1da177e4SLinus Torvalds 
878*1da177e4SLinus Torvalds /*
879*1da177e4SLinus Torvalds  * Catch an interrupt from the adapter
880*1da177e4SLinus Torvalds  */
881*1da177e4SLinus Torvalds static __inline int
882*1da177e4SLinus Torvalds ahd_intr(struct ahd_softc *ahd)
883*1da177e4SLinus Torvalds {
884*1da177e4SLinus Torvalds 	u_int	intstat;
885*1da177e4SLinus Torvalds 
886*1da177e4SLinus Torvalds 	if ((ahd->pause & INTEN) == 0) {
887*1da177e4SLinus Torvalds 		/*
888*1da177e4SLinus Torvalds 		 * Our interrupt is not enabled on the chip
889*1da177e4SLinus Torvalds 		 * and may be disabled for re-entrancy reasons,
890*1da177e4SLinus Torvalds 		 * so just return.  This is likely just a shared
891*1da177e4SLinus Torvalds 		 * interrupt.
892*1da177e4SLinus Torvalds 		 */
893*1da177e4SLinus Torvalds 		return (0);
894*1da177e4SLinus Torvalds 	}
895*1da177e4SLinus Torvalds 
896*1da177e4SLinus Torvalds 	/*
897*1da177e4SLinus Torvalds 	 * Instead of directly reading the interrupt status register,
898*1da177e4SLinus Torvalds 	 * infer the cause of the interrupt by checking our in-core
899*1da177e4SLinus Torvalds 	 * completion queues.  This avoids a costly PCI bus read in
900*1da177e4SLinus Torvalds 	 * most cases.
901*1da177e4SLinus Torvalds 	 */
902*1da177e4SLinus Torvalds 	if ((ahd->flags & AHD_ALL_INTERRUPTS) == 0
903*1da177e4SLinus Torvalds 	 && (ahd_check_cmdcmpltqueues(ahd) != 0))
904*1da177e4SLinus Torvalds 		intstat = CMDCMPLT;
905*1da177e4SLinus Torvalds 	else
906*1da177e4SLinus Torvalds 		intstat = ahd_inb(ahd, INTSTAT);
907*1da177e4SLinus Torvalds 
908*1da177e4SLinus Torvalds 	if ((intstat & INT_PEND) == 0)
909*1da177e4SLinus Torvalds 		return (0);
910*1da177e4SLinus Torvalds 
911*1da177e4SLinus Torvalds 	if (intstat & CMDCMPLT) {
912*1da177e4SLinus Torvalds 		ahd_outb(ahd, CLRINT, CLRCMDINT);
913*1da177e4SLinus Torvalds 
914*1da177e4SLinus Torvalds 		/*
915*1da177e4SLinus Torvalds 		 * Ensure that the chip sees that we've cleared
916*1da177e4SLinus Torvalds 		 * this interrupt before we walk the output fifo.
917*1da177e4SLinus Torvalds 		 * Otherwise, we may, due to posted bus writes,
918*1da177e4SLinus Torvalds 		 * clear the interrupt after we finish the scan,
919*1da177e4SLinus Torvalds 		 * and after the sequencer has added new entries
920*1da177e4SLinus Torvalds 		 * and asserted the interrupt again.
921*1da177e4SLinus Torvalds 		 */
922*1da177e4SLinus Torvalds 		if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) {
923*1da177e4SLinus Torvalds 			if (ahd_is_paused(ahd)) {
924*1da177e4SLinus Torvalds 				/*
925*1da177e4SLinus Torvalds 				 * Potentially lost SEQINT.
926*1da177e4SLinus Torvalds 				 * If SEQINTCODE is non-zero,
927*1da177e4SLinus Torvalds 				 * simulate the SEQINT.
928*1da177e4SLinus Torvalds 				 */
929*1da177e4SLinus Torvalds 				if (ahd_inb(ahd, SEQINTCODE) != NO_SEQINT)
930*1da177e4SLinus Torvalds 					intstat |= SEQINT;
931*1da177e4SLinus Torvalds 			}
932*1da177e4SLinus Torvalds 		} else {
933*1da177e4SLinus Torvalds 			ahd_flush_device_writes(ahd);
934*1da177e4SLinus Torvalds 		}
935*1da177e4SLinus Torvalds 		ahd_run_qoutfifo(ahd);
936*1da177e4SLinus Torvalds 		ahd->cmdcmplt_counts[ahd->cmdcmplt_bucket]++;
937*1da177e4SLinus Torvalds 		ahd->cmdcmplt_total++;
938*1da177e4SLinus Torvalds #ifdef AHD_TARGET_MODE
939*1da177e4SLinus Torvalds 		if ((ahd->flags & AHD_TARGETROLE) != 0)
940*1da177e4SLinus Torvalds 			ahd_run_tqinfifo(ahd, /*paused*/FALSE);
941*1da177e4SLinus Torvalds #endif
942*1da177e4SLinus Torvalds 	}
943*1da177e4SLinus Torvalds 
944*1da177e4SLinus Torvalds 	/*
945*1da177e4SLinus Torvalds 	 * Handle statuses that may invalidate our cached
946*1da177e4SLinus Torvalds 	 * copy of INTSTAT separately.
947*1da177e4SLinus Torvalds 	 */
948*1da177e4SLinus Torvalds 	if (intstat == 0xFF && (ahd->features & AHD_REMOVABLE) != 0) {
949*1da177e4SLinus Torvalds 		/* Hot eject.  Do nothing */
950*1da177e4SLinus Torvalds 	} else if (intstat & HWERRINT) {
951*1da177e4SLinus Torvalds 		ahd_handle_hwerrint(ahd);
952*1da177e4SLinus Torvalds 	} else if ((intstat & (PCIINT|SPLTINT)) != 0) {
953*1da177e4SLinus Torvalds 		ahd->bus_intr(ahd);
954*1da177e4SLinus Torvalds 	} else {
955*1da177e4SLinus Torvalds 
956*1da177e4SLinus Torvalds 		if ((intstat & SEQINT) != 0)
957*1da177e4SLinus Torvalds 			ahd_handle_seqint(ahd, intstat);
958*1da177e4SLinus Torvalds 
959*1da177e4SLinus Torvalds 		if ((intstat & SCSIINT) != 0)
960*1da177e4SLinus Torvalds 			ahd_handle_scsiint(ahd, intstat);
961*1da177e4SLinus Torvalds 	}
962*1da177e4SLinus Torvalds 	return (1);
963*1da177e4SLinus Torvalds }
964*1da177e4SLinus Torvalds 
965*1da177e4SLinus Torvalds #endif  /* _AIC79XX_INLINE_H_ */
966