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