117d24755SJustin T. Gibbs /* 217d24755SJustin T. Gibbs * Inline routines shareable across OS platforms. 317d24755SJustin T. Gibbs * 417d24755SJustin T. Gibbs * Copyright (c) 1994-2001 Justin T. Gibbs. 5adcf242eSJustin T. Gibbs * Copyright (c) 2000-2002 Adaptec Inc. 617d24755SJustin T. Gibbs * All rights reserved. 717d24755SJustin T. Gibbs * 817d24755SJustin T. Gibbs * Redistribution and use in source and binary forms, with or without 917d24755SJustin T. Gibbs * modification, are permitted provided that the following conditions 1017d24755SJustin T. Gibbs * are met: 1117d24755SJustin T. Gibbs * 1. Redistributions of source code must retain the above copyright 1217d24755SJustin T. Gibbs * notice, this list of conditions, and the following disclaimer, 1317d24755SJustin T. Gibbs * without modification. 1417d24755SJustin T. Gibbs * 2. Redistributions in binary form must reproduce at minimum a disclaimer 1517d24755SJustin T. Gibbs * substantially similar to the "NO WARRANTY" disclaimer below 1617d24755SJustin T. Gibbs * ("Disclaimer") and any redistribution must be conditioned upon 1717d24755SJustin T. Gibbs * including a substantially similar Disclaimer requirement for further 1817d24755SJustin T. Gibbs * binary redistribution. 1917d24755SJustin T. Gibbs * 3. Neither the names of the above-listed copyright holders nor the names 2017d24755SJustin T. Gibbs * of any contributors may be used to endorse or promote products derived 2117d24755SJustin T. Gibbs * from this software without specific prior written permission. 2217d24755SJustin T. Gibbs * 2317d24755SJustin T. Gibbs * Alternatively, this software may be distributed under the terms of the 2417d24755SJustin T. Gibbs * GNU General Public License ("GPL") version 2 as published by the Free 2517d24755SJustin T. Gibbs * Software Foundation. 2617d24755SJustin T. Gibbs * 2717d24755SJustin T. Gibbs * NO WARRANTY 2817d24755SJustin T. Gibbs * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2917d24755SJustin T. Gibbs * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3017d24755SJustin T. Gibbs * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 3117d24755SJustin T. Gibbs * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3217d24755SJustin T. Gibbs * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3317d24755SJustin T. Gibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3417d24755SJustin T. Gibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3517d24755SJustin T. Gibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 3617d24755SJustin T. Gibbs * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 3717d24755SJustin T. Gibbs * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3817d24755SJustin T. Gibbs * POSSIBILITY OF SUCH DAMAGES. 3917d24755SJustin T. Gibbs * 40fc2aa1d1SScott Long * $Id: //depot/aic7xxx/aic7xxx/aic79xx_inline.h#39 $ 4117d24755SJustin T. Gibbs * 4217d24755SJustin T. Gibbs * $FreeBSD$ 4317d24755SJustin T. Gibbs */ 4417d24755SJustin T. Gibbs 4517d24755SJustin T. Gibbs #ifndef _AIC79XX_INLINE_H_ 4617d24755SJustin T. Gibbs #define _AIC79XX_INLINE_H_ 4717d24755SJustin T. Gibbs 4817d24755SJustin T. Gibbs /******************************** Debugging ***********************************/ 4917d24755SJustin T. Gibbs static __inline char *ahd_name(struct ahd_softc *ahd); 5017d24755SJustin T. Gibbs 5117d24755SJustin T. Gibbs static __inline char * 5217d24755SJustin T. Gibbs ahd_name(struct ahd_softc *ahd) 5317d24755SJustin T. Gibbs { 5417d24755SJustin T. Gibbs return (ahd->name); 5517d24755SJustin T. Gibbs } 5617d24755SJustin T. Gibbs 5717d24755SJustin T. Gibbs /************************ Sequencer Execution Control *************************/ 5817d24755SJustin T. Gibbs static __inline void ahd_known_modes(struct ahd_softc *ahd, 5917d24755SJustin T. Gibbs ahd_mode src, ahd_mode dst); 6017d24755SJustin T. Gibbs static __inline ahd_mode_state ahd_build_mode_state(struct ahd_softc *ahd, 6117d24755SJustin T. Gibbs ahd_mode src, 6217d24755SJustin T. Gibbs ahd_mode dst); 6317d24755SJustin T. Gibbs static __inline void ahd_extract_mode_state(struct ahd_softc *ahd, 6417d24755SJustin T. Gibbs ahd_mode_state state, 6517d24755SJustin T. Gibbs ahd_mode *src, ahd_mode *dst); 6617d24755SJustin T. Gibbs static __inline void ahd_set_modes(struct ahd_softc *ahd, ahd_mode src, 6717d24755SJustin T. Gibbs ahd_mode dst); 6817d24755SJustin T. Gibbs static __inline void ahd_update_modes(struct ahd_softc *ahd); 6917d24755SJustin T. Gibbs static __inline void ahd_assert_modes(struct ahd_softc *ahd, ahd_mode srcmode, 7017d24755SJustin T. Gibbs ahd_mode dstmode, const char *file, 7117d24755SJustin T. Gibbs int line); 7217d24755SJustin T. Gibbs static __inline ahd_mode_state ahd_save_modes(struct ahd_softc *ahd); 7317d24755SJustin T. Gibbs static __inline void ahd_restore_modes(struct ahd_softc *ahd, 7417d24755SJustin T. Gibbs ahd_mode_state state); 7517d24755SJustin T. Gibbs static __inline int ahd_is_paused(struct ahd_softc *ahd); 7617d24755SJustin T. Gibbs static __inline void ahd_pause(struct ahd_softc *ahd); 7717d24755SJustin T. Gibbs static __inline void ahd_unpause(struct ahd_softc *ahd); 7817d24755SJustin T. Gibbs 7917d24755SJustin T. Gibbs static __inline void 8017d24755SJustin T. Gibbs ahd_known_modes(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst) 8117d24755SJustin T. Gibbs { 8217d24755SJustin T. Gibbs ahd->src_mode = src; 8317d24755SJustin T. Gibbs ahd->dst_mode = dst; 8417d24755SJustin T. Gibbs ahd->saved_src_mode = src; 8517d24755SJustin T. Gibbs ahd->saved_dst_mode = dst; 8617d24755SJustin T. Gibbs } 8717d24755SJustin T. Gibbs 8817d24755SJustin T. Gibbs static __inline ahd_mode_state 8917d24755SJustin T. Gibbs ahd_build_mode_state(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst) 9017d24755SJustin T. Gibbs { 9117d24755SJustin T. Gibbs return ((src << SRC_MODE_SHIFT) | (dst << DST_MODE_SHIFT)); 9217d24755SJustin T. Gibbs } 9317d24755SJustin T. Gibbs 9417d24755SJustin T. Gibbs static __inline void 9517d24755SJustin T. Gibbs ahd_extract_mode_state(struct ahd_softc *ahd, ahd_mode_state state, 9617d24755SJustin T. Gibbs ahd_mode *src, ahd_mode *dst) 9717d24755SJustin T. Gibbs { 9817d24755SJustin T. Gibbs *src = (state & SRC_MODE) >> SRC_MODE_SHIFT; 9917d24755SJustin T. Gibbs *dst = (state & DST_MODE) >> DST_MODE_SHIFT; 10017d24755SJustin T. Gibbs } 10117d24755SJustin T. Gibbs 10217d24755SJustin T. Gibbs static __inline void 10317d24755SJustin T. Gibbs ahd_set_modes(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst) 10417d24755SJustin T. Gibbs { 10517d24755SJustin T. Gibbs if (ahd->src_mode == src && ahd->dst_mode == dst) 10617d24755SJustin T. Gibbs return; 10717d24755SJustin T. Gibbs #ifdef AHD_DEBUG 10817d24755SJustin T. Gibbs if (ahd->src_mode == AHD_MODE_UNKNOWN 10917d24755SJustin T. Gibbs || ahd->dst_mode == AHD_MODE_UNKNOWN) 11017d24755SJustin T. Gibbs panic("Setting mode prior to saving it.\n"); 11117d24755SJustin T. Gibbs if ((ahd_debug & AHD_SHOW_MODEPTR) != 0) 112fc2aa1d1SScott Long printf("%s: Setting mode 0x%x\n", ahd_name(ahd), 11317d24755SJustin T. Gibbs ahd_build_mode_state(ahd, src, dst)); 11417d24755SJustin T. Gibbs #endif 11517d24755SJustin T. Gibbs ahd_outb(ahd, MODE_PTR, ahd_build_mode_state(ahd, src, dst)); 11617d24755SJustin T. Gibbs ahd->src_mode = src; 11717d24755SJustin T. Gibbs ahd->dst_mode = dst; 11817d24755SJustin T. Gibbs } 11917d24755SJustin T. Gibbs 12017d24755SJustin T. Gibbs static __inline void 12117d24755SJustin T. Gibbs ahd_update_modes(struct ahd_softc *ahd) 12217d24755SJustin T. Gibbs { 12317d24755SJustin T. Gibbs ahd_mode_state mode_ptr; 12417d24755SJustin T. Gibbs ahd_mode src; 12517d24755SJustin T. Gibbs ahd_mode dst; 12617d24755SJustin T. Gibbs 12717d24755SJustin T. Gibbs mode_ptr = ahd_inb(ahd, MODE_PTR); 12817d24755SJustin T. Gibbs #ifdef AHD_DEBUG 12917d24755SJustin T. Gibbs if ((ahd_debug & AHD_SHOW_MODEPTR) != 0) 13017d24755SJustin T. Gibbs printf("Reading mode 0x%x\n", mode_ptr); 13117d24755SJustin T. Gibbs #endif 13217d24755SJustin T. Gibbs ahd_extract_mode_state(ahd, mode_ptr, &src, &dst); 13317d24755SJustin T. Gibbs ahd_known_modes(ahd, src, dst); 13417d24755SJustin T. Gibbs } 13517d24755SJustin T. Gibbs 13617d24755SJustin T. Gibbs static __inline void 13717d24755SJustin T. Gibbs ahd_assert_modes(struct ahd_softc *ahd, ahd_mode srcmode, 13817d24755SJustin T. Gibbs ahd_mode dstmode, const char *file, int line) 13917d24755SJustin T. Gibbs { 14017d24755SJustin T. Gibbs #ifdef AHD_DEBUG 14117d24755SJustin T. Gibbs if ((srcmode & AHD_MK_MSK(ahd->src_mode)) == 0 14217d24755SJustin T. Gibbs || (dstmode & AHD_MK_MSK(ahd->dst_mode)) == 0) { 14317d24755SJustin T. Gibbs panic("%s:%s:%d: Mode assertion failed.\n", 14417d24755SJustin T. Gibbs ahd_name(ahd), file, line); 14517d24755SJustin T. Gibbs } 14617d24755SJustin T. Gibbs #endif 14717d24755SJustin T. Gibbs } 14817d24755SJustin T. Gibbs 14917d24755SJustin T. Gibbs static __inline ahd_mode_state 15017d24755SJustin T. Gibbs ahd_save_modes(struct ahd_softc *ahd) 15117d24755SJustin T. Gibbs { 15217d24755SJustin T. Gibbs if (ahd->src_mode == AHD_MODE_UNKNOWN 15317d24755SJustin T. Gibbs || ahd->dst_mode == AHD_MODE_UNKNOWN) 15417d24755SJustin T. Gibbs ahd_update_modes(ahd); 15517d24755SJustin T. Gibbs 15617d24755SJustin T. Gibbs return (ahd_build_mode_state(ahd, ahd->src_mode, ahd->dst_mode)); 15717d24755SJustin T. Gibbs } 15817d24755SJustin T. Gibbs 15917d24755SJustin T. Gibbs static __inline void 16017d24755SJustin T. Gibbs ahd_restore_modes(struct ahd_softc *ahd, ahd_mode_state state) 16117d24755SJustin T. Gibbs { 16217d24755SJustin T. Gibbs ahd_mode src; 16317d24755SJustin T. Gibbs ahd_mode dst; 16417d24755SJustin T. Gibbs 16517d24755SJustin T. Gibbs ahd_extract_mode_state(ahd, state, &src, &dst); 16617d24755SJustin T. Gibbs ahd_set_modes(ahd, src, dst); 16717d24755SJustin T. Gibbs } 16817d24755SJustin T. Gibbs 16917d24755SJustin T. Gibbs #define AHD_ASSERT_MODES(ahd, source, dest) \ 17017d24755SJustin T. Gibbs ahd_assert_modes(ahd, source, dest, __FILE__, __LINE__); 17117d24755SJustin T. Gibbs 17217d24755SJustin T. Gibbs /* 17317d24755SJustin T. Gibbs * Determine whether the sequencer has halted code execution. 17417d24755SJustin T. Gibbs * Returns non-zero status if the sequencer is stopped. 17517d24755SJustin T. Gibbs */ 17617d24755SJustin T. Gibbs static __inline int 17717d24755SJustin T. Gibbs ahd_is_paused(struct ahd_softc *ahd) 17817d24755SJustin T. Gibbs { 17917d24755SJustin T. Gibbs return ((ahd_inb(ahd, HCNTRL) & PAUSE) != 0); 18017d24755SJustin T. Gibbs } 18117d24755SJustin T. Gibbs 18217d24755SJustin T. Gibbs /* 18317d24755SJustin T. Gibbs * Request that the sequencer stop and wait, indefinitely, for it 18417d24755SJustin T. Gibbs * to stop. The sequencer will only acknowledge that it is paused 18517d24755SJustin T. Gibbs * once it has reached an instruction boundary and PAUSEDIS is 18617d24755SJustin T. Gibbs * cleared in the SEQCTL register. The sequencer may use PAUSEDIS 18717d24755SJustin T. Gibbs * for critical sections. 18817d24755SJustin T. Gibbs */ 18917d24755SJustin T. Gibbs static __inline void 19017d24755SJustin T. Gibbs ahd_pause(struct ahd_softc *ahd) 19117d24755SJustin T. Gibbs { 19217d24755SJustin T. Gibbs ahd_outb(ahd, HCNTRL, ahd->pause); 19317d24755SJustin T. Gibbs 19417d24755SJustin T. Gibbs /* 19517d24755SJustin T. Gibbs * Since the sequencer can disable pausing in a critical section, we 19617d24755SJustin T. Gibbs * must loop until it actually stops. 19717d24755SJustin T. Gibbs */ 19817d24755SJustin T. Gibbs while (ahd_is_paused(ahd) == 0) 19917d24755SJustin T. Gibbs ; 20017d24755SJustin T. Gibbs } 20117d24755SJustin T. Gibbs 20217d24755SJustin T. Gibbs /* 20317d24755SJustin T. Gibbs * Allow the sequencer to continue program execution. 20417d24755SJustin T. Gibbs * We check here to ensure that no additional interrupt 20517d24755SJustin T. Gibbs * sources that would cause the sequencer to halt have been 20617d24755SJustin T. Gibbs * asserted. If, for example, a SCSI bus reset is detected 20717d24755SJustin T. Gibbs * while we are fielding a different, pausing, interrupt type, 20817d24755SJustin T. Gibbs * we don't want to release the sequencer before going back 20917d24755SJustin T. Gibbs * into our interrupt handler and dealing with this new 21017d24755SJustin T. Gibbs * condition. 21117d24755SJustin T. Gibbs */ 21217d24755SJustin T. Gibbs static __inline void 21317d24755SJustin T. Gibbs ahd_unpause(struct ahd_softc *ahd) 21417d24755SJustin T. Gibbs { 21517d24755SJustin T. Gibbs /* 21617d24755SJustin T. Gibbs * Automatically restore our modes to those saved 21717d24755SJustin T. Gibbs * prior to the first change of the mode. 21817d24755SJustin T. Gibbs */ 21917d24755SJustin T. Gibbs if (ahd->saved_src_mode != AHD_MODE_UNKNOWN 22017d24755SJustin T. Gibbs && ahd->saved_dst_mode != AHD_MODE_UNKNOWN) 22117d24755SJustin T. Gibbs ahd_set_modes(ahd, ahd->saved_src_mode, ahd->saved_dst_mode); 22217d24755SJustin T. Gibbs 22317d24755SJustin T. Gibbs if ((ahd_inb(ahd, INTSTAT) & ~(SWTMINT | CMDCMPLT)) == 0) 22417d24755SJustin T. Gibbs ahd_outb(ahd, HCNTRL, ahd->unpause); 22517d24755SJustin T. Gibbs 22617d24755SJustin T. Gibbs ahd_known_modes(ahd, AHD_MODE_UNKNOWN, AHD_MODE_UNKNOWN); 22717d24755SJustin T. Gibbs } 22817d24755SJustin T. Gibbs 22917d24755SJustin T. Gibbs /*********************** Scatter Gather List Handling *************************/ 23017d24755SJustin T. Gibbs static __inline void *ahd_sg_setup(struct ahd_softc *ahd, struct scb *scb, 23117d24755SJustin T. Gibbs void *sgptr, bus_addr_t addr, 23217d24755SJustin T. Gibbs bus_size_t len, int last); 23317d24755SJustin T. Gibbs static __inline void ahd_setup_scb_common(struct ahd_softc *ahd, 23417d24755SJustin T. Gibbs struct scb *scb); 23517d24755SJustin T. Gibbs static __inline void ahd_setup_data_scb(struct ahd_softc *ahd, 23617d24755SJustin T. Gibbs struct scb *scb); 23717d24755SJustin T. Gibbs static __inline void ahd_setup_noxfer_scb(struct ahd_softc *ahd, 23817d24755SJustin T. Gibbs struct scb *scb); 23917d24755SJustin T. Gibbs 24017d24755SJustin T. Gibbs static __inline void * 24117d24755SJustin T. Gibbs ahd_sg_setup(struct ahd_softc *ahd, struct scb *scb, 24217d24755SJustin T. Gibbs void *sgptr, bus_addr_t addr, bus_size_t len, int last) 24317d24755SJustin T. Gibbs { 24417d24755SJustin T. Gibbs scb->sg_count++; 24517d24755SJustin T. Gibbs if (sizeof(bus_addr_t) > 4 24617d24755SJustin T. Gibbs && (ahd->flags & AHD_64BIT_ADDRESSING) != 0) { 24717d24755SJustin T. Gibbs struct ahd_dma64_seg *sg; 24817d24755SJustin T. Gibbs 24917d24755SJustin T. Gibbs sg = (struct ahd_dma64_seg *)sgptr; 25017d24755SJustin T. Gibbs sg->addr = ahd_htole64(addr); 25117d24755SJustin T. Gibbs sg->len = ahd_htole32(len | (last ? AHD_DMA_LAST_SEG : 0)); 25217d24755SJustin T. Gibbs return (sg + 1); 25317d24755SJustin T. Gibbs } else { 25417d24755SJustin T. Gibbs struct ahd_dma_seg *sg; 25517d24755SJustin T. Gibbs 25617d24755SJustin T. Gibbs sg = (struct ahd_dma_seg *)sgptr; 257c59c8a72SJustin T. Gibbs sg->addr = ahd_htole32(addr & 0xFFFFFFFF); 25817d24755SJustin T. Gibbs sg->len = ahd_htole32(len | ((addr >> 8) & 0x7F000000) 25917d24755SJustin T. Gibbs | (last ? AHD_DMA_LAST_SEG : 0)); 26017d24755SJustin T. Gibbs return (sg + 1); 26117d24755SJustin T. Gibbs } 26217d24755SJustin T. Gibbs } 26317d24755SJustin T. Gibbs 26417d24755SJustin T. Gibbs static __inline void 26517d24755SJustin T. Gibbs ahd_setup_scb_common(struct ahd_softc *ahd, struct scb *scb) 26617d24755SJustin T. Gibbs { 26717d24755SJustin T. Gibbs /* XXX Handle target mode SCBs. */ 268fc2aa1d1SScott Long scb->crc_retry_count = 0; 26917d24755SJustin T. Gibbs if ((scb->flags & SCB_PACKETIZED) != 0) { 27017d24755SJustin T. Gibbs /* XXX what about ACA?? It is type 4, but TAG_TYPE == 0x3. */ 271c59c8a72SJustin T. Gibbs scb->hscb->task_attribute= scb->hscb->control & SCB_TAG_TYPE; 27217d24755SJustin T. Gibbs scb->hscb->task_management = 0; 273adcf242eSJustin T. Gibbs /* 274adcf242eSJustin T. Gibbs * For Rev A short lun workaround. 275adcf242eSJustin T. Gibbs */ 276adcf242eSJustin T. Gibbs scb->hscb->pkt_long_lun[6] = scb->hscb->lun; 27717d24755SJustin T. Gibbs } 27817d24755SJustin T. Gibbs 27917d24755SJustin T. Gibbs if (scb->hscb->cdb_len <= MAX_CDB_LEN_WITH_SENSE_ADDR 28017d24755SJustin T. Gibbs || (scb->hscb->cdb_len & SCB_CDB_LEN_PTR) != 0) 28117d24755SJustin T. Gibbs scb->hscb->shared_data.idata.cdb_plus_saddr.sense_addr = 28217d24755SJustin T. Gibbs ahd_htole32(scb->sense_busaddr); 28317d24755SJustin T. Gibbs } 28417d24755SJustin T. Gibbs 28517d24755SJustin T. Gibbs static __inline void 28617d24755SJustin T. Gibbs ahd_setup_data_scb(struct ahd_softc *ahd, struct scb *scb) 28717d24755SJustin T. Gibbs { 28817d24755SJustin T. Gibbs /* 28917d24755SJustin T. Gibbs * Copy the first SG into the "current" data ponter area. 29017d24755SJustin T. Gibbs */ 29117d24755SJustin T. Gibbs if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) { 29217d24755SJustin T. Gibbs struct ahd_dma64_seg *sg; 29317d24755SJustin T. Gibbs 29417d24755SJustin T. Gibbs sg = (struct ahd_dma64_seg *)scb->sg_list; 29517d24755SJustin T. Gibbs scb->hscb->dataptr = sg->addr; 29617d24755SJustin T. Gibbs scb->hscb->datacnt = sg->len; 29717d24755SJustin T. Gibbs } else { 29817d24755SJustin T. Gibbs struct ahd_dma_seg *sg; 29917d24755SJustin T. Gibbs 30017d24755SJustin T. Gibbs sg = (struct ahd_dma_seg *)scb->sg_list; 30117d24755SJustin T. Gibbs scb->hscb->dataptr = sg->addr; 30217d24755SJustin T. Gibbs if ((ahd->flags & AHD_39BIT_ADDRESSING) != 0) { 30317d24755SJustin T. Gibbs uint64_t high_addr; 30417d24755SJustin T. Gibbs 305cdd49e97SJustin T. Gibbs high_addr = ahd_le32toh(sg->len) & 0x7F000000; 306cdd49e97SJustin T. Gibbs scb->hscb->dataptr |= ahd_htole64(high_addr << 8); 30717d24755SJustin T. Gibbs } 30817d24755SJustin T. Gibbs scb->hscb->datacnt = sg->len; 30917d24755SJustin T. Gibbs } 31017d24755SJustin T. Gibbs /* 31117d24755SJustin T. Gibbs * Note where to find the SG entries in bus space. 31217d24755SJustin T. Gibbs * We also set the full residual flag which the 31317d24755SJustin T. Gibbs * sequencer will clear as soon as a data transfer 31417d24755SJustin T. Gibbs * occurs. 31517d24755SJustin T. Gibbs */ 31617d24755SJustin T. Gibbs scb->hscb->sgptr = ahd_htole32(scb->sg_list_busaddr|SG_FULL_RESID); 31717d24755SJustin T. Gibbs } 31817d24755SJustin T. Gibbs 31917d24755SJustin T. Gibbs static __inline void 32017d24755SJustin T. Gibbs ahd_setup_noxfer_scb(struct ahd_softc *ahd, struct scb *scb) 32117d24755SJustin T. Gibbs { 32217d24755SJustin T. Gibbs scb->hscb->sgptr = ahd_htole32(SG_LIST_NULL); 32317d24755SJustin T. Gibbs scb->hscb->dataptr = 0; 32417d24755SJustin T. Gibbs scb->hscb->datacnt = 0; 32517d24755SJustin T. Gibbs } 32617d24755SJustin T. Gibbs 32717d24755SJustin T. Gibbs /************************** Memory mapping routines ***************************/ 32817d24755SJustin T. Gibbs static __inline size_t ahd_sg_size(struct ahd_softc *ahd); 32917d24755SJustin T. Gibbs static __inline void * 33017d24755SJustin T. Gibbs ahd_sg_bus_to_virt(struct ahd_softc *ahd, 33117d24755SJustin T. Gibbs struct scb *scb, 33217d24755SJustin T. Gibbs uint32_t sg_busaddr); 33317d24755SJustin T. Gibbs static __inline uint32_t 33417d24755SJustin T. Gibbs ahd_sg_virt_to_bus(struct ahd_softc *ahd, 33517d24755SJustin T. Gibbs struct scb *scb, 33617d24755SJustin T. Gibbs void *sg); 33717d24755SJustin T. Gibbs static __inline void ahd_sync_scb(struct ahd_softc *ahd, 33817d24755SJustin T. Gibbs struct scb *scb, int op); 33917d24755SJustin T. Gibbs static __inline void ahd_sync_sglist(struct ahd_softc *ahd, 34017d24755SJustin T. Gibbs struct scb *scb, int op); 34117d24755SJustin T. Gibbs static __inline void ahd_sync_sense(struct ahd_softc *ahd, 34217d24755SJustin T. Gibbs struct scb *scb, int op); 34317d24755SJustin T. Gibbs static __inline uint32_t 34417d24755SJustin T. Gibbs ahd_targetcmd_offset(struct ahd_softc *ahd, 34517d24755SJustin T. Gibbs u_int index); 34617d24755SJustin T. Gibbs 34717d24755SJustin T. Gibbs static __inline size_t 34817d24755SJustin T. Gibbs ahd_sg_size(struct ahd_softc *ahd) 34917d24755SJustin T. Gibbs { 35017d24755SJustin T. Gibbs if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) 35117d24755SJustin T. Gibbs return (sizeof(struct ahd_dma64_seg)); 35217d24755SJustin T. Gibbs return (sizeof(struct ahd_dma_seg)); 35317d24755SJustin T. Gibbs } 35417d24755SJustin T. Gibbs 35517d24755SJustin T. Gibbs static __inline void * 35617d24755SJustin T. Gibbs ahd_sg_bus_to_virt(struct ahd_softc *ahd, struct scb *scb, uint32_t sg_busaddr) 35717d24755SJustin T. Gibbs { 35817d24755SJustin T. Gibbs bus_addr_t sg_offset; 35917d24755SJustin T. Gibbs 36017d24755SJustin T. Gibbs /* sg_list_phys points to entry 1, not 0 */ 36117d24755SJustin T. Gibbs sg_offset = sg_busaddr - (scb->sg_list_busaddr - ahd_sg_size(ahd)); 36217d24755SJustin T. Gibbs return ((uint8_t *)scb->sg_list + sg_offset); 36317d24755SJustin T. Gibbs } 36417d24755SJustin T. Gibbs 36517d24755SJustin T. Gibbs static __inline uint32_t 36617d24755SJustin T. Gibbs ahd_sg_virt_to_bus(struct ahd_softc *ahd, struct scb *scb, void *sg) 36717d24755SJustin T. Gibbs { 36817d24755SJustin T. Gibbs bus_addr_t sg_offset; 36917d24755SJustin T. Gibbs 37017d24755SJustin T. Gibbs /* sg_list_phys points to entry 1, not 0 */ 37117d24755SJustin T. Gibbs sg_offset = ((uint8_t *)sg - (uint8_t *)scb->sg_list) 37217d24755SJustin T. Gibbs - ahd_sg_size(ahd); 37317d24755SJustin T. Gibbs 37417d24755SJustin T. Gibbs return (scb->sg_list_busaddr + sg_offset); 37517d24755SJustin T. Gibbs } 37617d24755SJustin T. Gibbs 37717d24755SJustin T. Gibbs static __inline void 37817d24755SJustin T. Gibbs ahd_sync_scb(struct ahd_softc *ahd, struct scb *scb, int op) 37917d24755SJustin T. Gibbs { 38017d24755SJustin T. Gibbs ahd_dmamap_sync(ahd, ahd->scb_data.hscb_dmat, 38117d24755SJustin T. Gibbs scb->hscb_map->dmamap, 38217d24755SJustin T. Gibbs /*offset*/(uint8_t*)scb->hscb - scb->hscb_map->vaddr, 38317d24755SJustin T. Gibbs /*len*/sizeof(*scb->hscb), op); 38417d24755SJustin T. Gibbs } 38517d24755SJustin T. Gibbs 38617d24755SJustin T. Gibbs static __inline void 38717d24755SJustin T. Gibbs ahd_sync_sglist(struct ahd_softc *ahd, struct scb *scb, int op) 38817d24755SJustin T. Gibbs { 38917d24755SJustin T. Gibbs if (scb->sg_count == 0) 39017d24755SJustin T. Gibbs return; 39117d24755SJustin T. Gibbs 39217d24755SJustin T. Gibbs ahd_dmamap_sync(ahd, ahd->scb_data.sg_dmat, 39317d24755SJustin T. Gibbs scb->sg_map->dmamap, 39417d24755SJustin T. Gibbs /*offset*/scb->sg_list_busaddr - ahd_sg_size(ahd), 39517d24755SJustin T. Gibbs /*len*/ahd_sg_size(ahd) * scb->sg_count, op); 39617d24755SJustin T. Gibbs } 39717d24755SJustin T. Gibbs 39817d24755SJustin T. Gibbs static __inline void 39917d24755SJustin T. Gibbs ahd_sync_sense(struct ahd_softc *ahd, struct scb *scb, int op) 40017d24755SJustin T. Gibbs { 40117d24755SJustin T. Gibbs ahd_dmamap_sync(ahd, ahd->scb_data.sense_dmat, 40217d24755SJustin T. Gibbs scb->sense_map->dmamap, 40317d24755SJustin T. Gibbs /*offset*/scb->sense_busaddr, 40417d24755SJustin T. Gibbs /*len*/AHD_SENSE_BUFSIZE, op); 40517d24755SJustin T. Gibbs } 40617d24755SJustin T. Gibbs 40717d24755SJustin T. Gibbs static __inline uint32_t 40817d24755SJustin T. Gibbs ahd_targetcmd_offset(struct ahd_softc *ahd, u_int index) 40917d24755SJustin T. Gibbs { 41017d24755SJustin T. Gibbs return (((uint8_t *)&ahd->targetcmds[index]) 41117d24755SJustin T. Gibbs - (uint8_t *)ahd->qoutfifo); 41217d24755SJustin T. Gibbs } 41317d24755SJustin T. Gibbs 41417d24755SJustin T. Gibbs /*********************** Miscelaneous Support Functions ***********************/ 41517d24755SJustin T. Gibbs static __inline void ahd_complete_scb(struct ahd_softc *ahd, 41617d24755SJustin T. Gibbs struct scb *scb); 41717d24755SJustin T. Gibbs static __inline void ahd_update_residual(struct ahd_softc *ahd, 41817d24755SJustin T. Gibbs struct scb *scb); 41917d24755SJustin T. Gibbs static __inline struct ahd_initiator_tinfo * 42017d24755SJustin T. Gibbs ahd_fetch_transinfo(struct ahd_softc *ahd, 42117d24755SJustin T. Gibbs char channel, u_int our_id, 42217d24755SJustin T. Gibbs u_int remote_id, 42317d24755SJustin T. Gibbs struct ahd_tmode_tstate **tstate); 42417d24755SJustin T. Gibbs static __inline uint16_t 42517d24755SJustin T. Gibbs ahd_inw(struct ahd_softc *ahd, u_int port); 42617d24755SJustin T. Gibbs static __inline void ahd_outw(struct ahd_softc *ahd, u_int port, 42717d24755SJustin T. Gibbs u_int value); 42817d24755SJustin T. Gibbs static __inline uint32_t 42917d24755SJustin T. Gibbs ahd_inl(struct ahd_softc *ahd, u_int port); 43017d24755SJustin T. Gibbs static __inline void ahd_outl(struct ahd_softc *ahd, u_int port, 43117d24755SJustin T. Gibbs uint32_t value); 43217d24755SJustin T. Gibbs static __inline uint64_t 43317d24755SJustin T. Gibbs ahd_inq(struct ahd_softc *ahd, u_int port); 43417d24755SJustin T. Gibbs static __inline void ahd_outq(struct ahd_softc *ahd, u_int port, 43517d24755SJustin T. Gibbs uint64_t value); 43617d24755SJustin T. Gibbs static __inline u_int ahd_get_scbptr(struct ahd_softc *ahd); 43717d24755SJustin T. Gibbs static __inline void ahd_set_scbptr(struct ahd_softc *ahd, u_int scbptr); 43817d24755SJustin T. Gibbs static __inline u_int ahd_get_hnscb_qoff(struct ahd_softc *ahd); 43917d24755SJustin T. Gibbs static __inline void ahd_set_hnscb_qoff(struct ahd_softc *ahd, u_int value); 44017d24755SJustin T. Gibbs static __inline u_int ahd_get_hescb_qoff(struct ahd_softc *ahd); 44117d24755SJustin T. Gibbs static __inline void ahd_set_hescb_qoff(struct ahd_softc *ahd, u_int value); 44217d24755SJustin T. Gibbs static __inline u_int ahd_get_snscb_qoff(struct ahd_softc *ahd); 44317d24755SJustin T. Gibbs static __inline void ahd_set_snscb_qoff(struct ahd_softc *ahd, u_int value); 44417d24755SJustin T. Gibbs static __inline u_int ahd_get_sescb_qoff(struct ahd_softc *ahd); 44517d24755SJustin T. Gibbs static __inline void ahd_set_sescb_qoff(struct ahd_softc *ahd, u_int value); 44617d24755SJustin T. Gibbs static __inline u_int ahd_get_sdscb_qoff(struct ahd_softc *ahd); 44717d24755SJustin T. Gibbs static __inline void ahd_set_sdscb_qoff(struct ahd_softc *ahd, u_int value); 44817d24755SJustin T. Gibbs static __inline u_int ahd_inb_scbram(struct ahd_softc *ahd, u_int offset); 44917d24755SJustin T. Gibbs static __inline u_int ahd_inw_scbram(struct ahd_softc *ahd, u_int offset); 45017d24755SJustin T. Gibbs static __inline uint32_t 45117d24755SJustin T. Gibbs ahd_inl_scbram(struct ahd_softc *ahd, u_int offset); 45217d24755SJustin T. Gibbs static __inline void ahd_swap_with_next_hscb(struct ahd_softc *ahd, 45317d24755SJustin T. Gibbs struct scb *scb); 45417d24755SJustin T. Gibbs static __inline void ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb); 45517d24755SJustin T. Gibbs static __inline uint8_t * 45617d24755SJustin T. Gibbs ahd_get_sense_buf(struct ahd_softc *ahd, 45717d24755SJustin T. Gibbs struct scb *scb); 45817d24755SJustin T. Gibbs static __inline uint32_t 45917d24755SJustin T. Gibbs ahd_get_sense_bufaddr(struct ahd_softc *ahd, 46017d24755SJustin T. Gibbs struct scb *scb); 46117d24755SJustin T. Gibbs 46217d24755SJustin T. Gibbs static __inline void 46317d24755SJustin T. Gibbs ahd_complete_scb(struct ahd_softc *ahd, struct scb *scb) 46417d24755SJustin T. Gibbs { 46517d24755SJustin T. Gibbs uint32_t sgptr; 46617d24755SJustin T. Gibbs 46717d24755SJustin T. Gibbs sgptr = ahd_le32toh(scb->hscb->sgptr); 46817d24755SJustin T. Gibbs if ((sgptr & SG_STATUS_VALID) != 0) 46917d24755SJustin T. Gibbs ahd_handle_scb_status(ahd, scb); 47017d24755SJustin T. Gibbs else 47117d24755SJustin T. Gibbs ahd_done(ahd, scb); 47217d24755SJustin T. Gibbs } 47317d24755SJustin T. Gibbs 47417d24755SJustin T. Gibbs /* 47517d24755SJustin T. Gibbs * Determine whether the sequencer reported a residual 47617d24755SJustin T. Gibbs * for this SCB/transaction. 47717d24755SJustin T. Gibbs */ 47817d24755SJustin T. Gibbs static __inline void 47917d24755SJustin T. Gibbs ahd_update_residual(struct ahd_softc *ahd, struct scb *scb) 48017d24755SJustin T. Gibbs { 48117d24755SJustin T. Gibbs uint32_t sgptr; 48217d24755SJustin T. Gibbs 48317d24755SJustin T. Gibbs sgptr = ahd_le32toh(scb->hscb->sgptr); 48417d24755SJustin T. Gibbs if ((sgptr & SG_STATUS_VALID) != 0) 48517d24755SJustin T. Gibbs ahd_calc_residual(ahd, scb); 48617d24755SJustin T. Gibbs } 48717d24755SJustin T. Gibbs 48817d24755SJustin T. Gibbs /* 48917d24755SJustin T. Gibbs * Return pointers to the transfer negotiation information 49017d24755SJustin T. Gibbs * for the specified our_id/remote_id pair. 49117d24755SJustin T. Gibbs */ 49217d24755SJustin T. Gibbs static __inline struct ahd_initiator_tinfo * 49317d24755SJustin T. Gibbs ahd_fetch_transinfo(struct ahd_softc *ahd, char channel, u_int our_id, 49417d24755SJustin T. Gibbs u_int remote_id, struct ahd_tmode_tstate **tstate) 49517d24755SJustin T. Gibbs { 49617d24755SJustin T. Gibbs /* 49717d24755SJustin T. Gibbs * Transfer data structures are stored from the perspective 49817d24755SJustin T. Gibbs * of the target role. Since the parameters for a connection 49917d24755SJustin T. Gibbs * in the initiator role to a given target are the same as 50017d24755SJustin T. Gibbs * when the roles are reversed, we pretend we are the target. 50117d24755SJustin T. Gibbs */ 50217d24755SJustin T. Gibbs if (channel == 'B') 50317d24755SJustin T. Gibbs our_id += 8; 50417d24755SJustin T. Gibbs *tstate = ahd->enabled_targets[our_id]; 50517d24755SJustin T. Gibbs return (&(*tstate)->transinfo[remote_id]); 50617d24755SJustin T. Gibbs } 50717d24755SJustin T. Gibbs 508adcf242eSJustin T. Gibbs #define AHD_COPY_COL_IDX(dst, src) \ 509adcf242eSJustin T. Gibbs do { \ 510adcf242eSJustin T. Gibbs dst->hscb->scsiid = src->hscb->scsiid; \ 511adcf242eSJustin T. Gibbs dst->hscb->lun = src->hscb->lun; \ 512adcf242eSJustin T. Gibbs } while (0) 51317d24755SJustin T. Gibbs 51417d24755SJustin T. Gibbs static __inline uint16_t 51517d24755SJustin T. Gibbs ahd_inw(struct ahd_softc *ahd, u_int port) 51617d24755SJustin T. Gibbs { 51717d24755SJustin T. Gibbs return ((ahd_inb(ahd, port+1) << 8) | ahd_inb(ahd, port)); 51817d24755SJustin T. Gibbs } 51917d24755SJustin T. Gibbs 52017d24755SJustin T. Gibbs static __inline void 52117d24755SJustin T. Gibbs ahd_outw(struct ahd_softc *ahd, u_int port, u_int value) 52217d24755SJustin T. Gibbs { 52317d24755SJustin T. Gibbs ahd_outb(ahd, port, value & 0xFF); 52417d24755SJustin T. Gibbs ahd_outb(ahd, port+1, (value >> 8) & 0xFF); 52517d24755SJustin T. Gibbs } 52617d24755SJustin T. Gibbs 52717d24755SJustin T. Gibbs static __inline uint32_t 52817d24755SJustin T. Gibbs ahd_inl(struct ahd_softc *ahd, u_int port) 52917d24755SJustin T. Gibbs { 53017d24755SJustin T. Gibbs return ((ahd_inb(ahd, port)) 53117d24755SJustin T. Gibbs | (ahd_inb(ahd, port+1) << 8) 53217d24755SJustin T. Gibbs | (ahd_inb(ahd, port+2) << 16) 53317d24755SJustin T. Gibbs | (ahd_inb(ahd, port+3) << 24)); 53417d24755SJustin T. Gibbs } 53517d24755SJustin T. Gibbs 53617d24755SJustin T. Gibbs static __inline void 53717d24755SJustin T. Gibbs ahd_outl(struct ahd_softc *ahd, u_int port, uint32_t value) 53817d24755SJustin T. Gibbs { 53917d24755SJustin T. Gibbs ahd_outb(ahd, port, (value) & 0xFF); 54017d24755SJustin T. Gibbs ahd_outb(ahd, port+1, ((value) >> 8) & 0xFF); 54117d24755SJustin T. Gibbs ahd_outb(ahd, port+2, ((value) >> 16) & 0xFF); 54217d24755SJustin T. Gibbs ahd_outb(ahd, port+3, ((value) >> 24) & 0xFF); 54317d24755SJustin T. Gibbs } 54417d24755SJustin T. Gibbs 54517d24755SJustin T. Gibbs static __inline uint64_t 54617d24755SJustin T. Gibbs ahd_inq(struct ahd_softc *ahd, u_int port) 54717d24755SJustin T. Gibbs { 54817d24755SJustin T. Gibbs return ((ahd_inb(ahd, port)) 54917d24755SJustin T. Gibbs | (ahd_inb(ahd, port+1) << 8) 55017d24755SJustin T. Gibbs | (ahd_inb(ahd, port+2) << 16) 55117d24755SJustin T. Gibbs | (ahd_inb(ahd, port+3) << 24) 55217d24755SJustin T. Gibbs | (((uint64_t)ahd_inb(ahd, port+4)) << 32) 55317d24755SJustin T. Gibbs | (((uint64_t)ahd_inb(ahd, port+5)) << 40) 55417d24755SJustin T. Gibbs | (((uint64_t)ahd_inb(ahd, port+6)) << 48) 55517d24755SJustin T. Gibbs | (((uint64_t)ahd_inb(ahd, port+7)) << 56)); 55617d24755SJustin T. Gibbs } 55717d24755SJustin T. Gibbs 55817d24755SJustin T. Gibbs static __inline void 55917d24755SJustin T. Gibbs ahd_outq(struct ahd_softc *ahd, u_int port, uint64_t value) 56017d24755SJustin T. Gibbs { 56117d24755SJustin T. Gibbs ahd_outb(ahd, port, value & 0xFF); 56217d24755SJustin T. Gibbs ahd_outb(ahd, port+1, (value >> 8) & 0xFF); 56317d24755SJustin T. Gibbs ahd_outb(ahd, port+2, (value >> 16) & 0xFF); 56417d24755SJustin T. Gibbs ahd_outb(ahd, port+3, (value >> 24) & 0xFF); 56517d24755SJustin T. Gibbs ahd_outb(ahd, port+4, (value >> 32) & 0xFF); 56617d24755SJustin T. Gibbs ahd_outb(ahd, port+5, (value >> 40) & 0xFF); 56717d24755SJustin T. Gibbs ahd_outb(ahd, port+6, (value >> 48) & 0xFF); 56817d24755SJustin T. Gibbs ahd_outb(ahd, port+7, (value >> 56) & 0xFF); 56917d24755SJustin T. Gibbs } 57017d24755SJustin T. Gibbs 57117d24755SJustin T. Gibbs static __inline u_int 57217d24755SJustin T. Gibbs ahd_get_scbptr(struct ahd_softc *ahd) 57317d24755SJustin T. Gibbs { 57417d24755SJustin T. Gibbs AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK), 57517d24755SJustin T. Gibbs ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK)); 57617d24755SJustin T. Gibbs return (ahd_inb(ahd, SCBPTR) | (ahd_inb(ahd, SCBPTR + 1) << 8)); 57717d24755SJustin T. Gibbs } 57817d24755SJustin T. Gibbs 57917d24755SJustin T. Gibbs static __inline void 58017d24755SJustin T. Gibbs ahd_set_scbptr(struct ahd_softc *ahd, u_int scbptr) 58117d24755SJustin T. Gibbs { 58217d24755SJustin T. Gibbs AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK), 58317d24755SJustin T. Gibbs ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK)); 58417d24755SJustin T. Gibbs ahd_outb(ahd, SCBPTR, scbptr & 0xFF); 58517d24755SJustin T. Gibbs ahd_outb(ahd, SCBPTR+1, (scbptr >> 8) & 0xFF); 58617d24755SJustin T. Gibbs } 58717d24755SJustin T. Gibbs 58817d24755SJustin T. Gibbs static __inline u_int 58917d24755SJustin T. Gibbs ahd_get_hnscb_qoff(struct ahd_softc *ahd) 59017d24755SJustin T. Gibbs { 59117d24755SJustin T. Gibbs return (ahd_inw_atomic(ahd, HNSCB_QOFF)); 59217d24755SJustin T. Gibbs } 59317d24755SJustin T. Gibbs 59417d24755SJustin T. Gibbs static __inline void 59517d24755SJustin T. Gibbs ahd_set_hnscb_qoff(struct ahd_softc *ahd, u_int value) 59617d24755SJustin T. Gibbs { 59717d24755SJustin T. Gibbs ahd_outw_atomic(ahd, HNSCB_QOFF, value); 59817d24755SJustin T. Gibbs } 59917d24755SJustin T. Gibbs 60017d24755SJustin T. Gibbs static __inline u_int 60117d24755SJustin T. Gibbs ahd_get_hescb_qoff(struct ahd_softc *ahd) 60217d24755SJustin T. Gibbs { 60317d24755SJustin T. Gibbs return (ahd_inb(ahd, HESCB_QOFF)); 60417d24755SJustin T. Gibbs } 60517d24755SJustin T. Gibbs 60617d24755SJustin T. Gibbs static __inline void 60717d24755SJustin T. Gibbs ahd_set_hescb_qoff(struct ahd_softc *ahd, u_int value) 60817d24755SJustin T. Gibbs { 60917d24755SJustin T. Gibbs ahd_outb(ahd, HESCB_QOFF, value); 61017d24755SJustin T. Gibbs } 61117d24755SJustin T. Gibbs 61217d24755SJustin T. Gibbs static __inline u_int 61317d24755SJustin T. Gibbs ahd_get_snscb_qoff(struct ahd_softc *ahd) 61417d24755SJustin T. Gibbs { 61517d24755SJustin T. Gibbs u_int oldvalue; 61617d24755SJustin T. Gibbs 61717d24755SJustin T. Gibbs AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 61817d24755SJustin T. Gibbs oldvalue = ahd_inw(ahd, SNSCB_QOFF); 61917d24755SJustin T. Gibbs ahd_outw(ahd, SNSCB_QOFF, oldvalue); 62017d24755SJustin T. Gibbs return (oldvalue); 62117d24755SJustin T. Gibbs } 62217d24755SJustin T. Gibbs 62317d24755SJustin T. Gibbs static __inline void 62417d24755SJustin T. Gibbs ahd_set_snscb_qoff(struct ahd_softc *ahd, u_int value) 62517d24755SJustin T. Gibbs { 62617d24755SJustin T. Gibbs AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 62717d24755SJustin T. Gibbs ahd_outw(ahd, SNSCB_QOFF, value); 62817d24755SJustin T. Gibbs } 62917d24755SJustin T. Gibbs 63017d24755SJustin T. Gibbs static __inline u_int 63117d24755SJustin T. Gibbs ahd_get_sescb_qoff(struct ahd_softc *ahd) 63217d24755SJustin T. Gibbs { 63317d24755SJustin T. Gibbs AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 63417d24755SJustin T. Gibbs return (ahd_inb(ahd, SESCB_QOFF)); 63517d24755SJustin T. Gibbs } 63617d24755SJustin T. Gibbs 63717d24755SJustin T. Gibbs static __inline void 63817d24755SJustin T. Gibbs ahd_set_sescb_qoff(struct ahd_softc *ahd, u_int value) 63917d24755SJustin T. Gibbs { 64017d24755SJustin T. Gibbs AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 64117d24755SJustin T. Gibbs ahd_outb(ahd, SESCB_QOFF, value); 64217d24755SJustin T. Gibbs } 64317d24755SJustin T. Gibbs 64417d24755SJustin T. Gibbs static __inline u_int 64517d24755SJustin T. Gibbs ahd_get_sdscb_qoff(struct ahd_softc *ahd) 64617d24755SJustin T. Gibbs { 64717d24755SJustin T. Gibbs AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 64817d24755SJustin T. Gibbs return (ahd_inb(ahd, SDSCB_QOFF) | (ahd_inb(ahd, SDSCB_QOFF + 1) << 8)); 64917d24755SJustin T. Gibbs } 65017d24755SJustin T. Gibbs 65117d24755SJustin T. Gibbs static __inline void 65217d24755SJustin T. Gibbs ahd_set_sdscb_qoff(struct ahd_softc *ahd, u_int value) 65317d24755SJustin T. Gibbs { 65417d24755SJustin T. Gibbs AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 65517d24755SJustin T. Gibbs ahd_outb(ahd, SDSCB_QOFF, value & 0xFF); 65617d24755SJustin T. Gibbs ahd_outb(ahd, SDSCB_QOFF+1, (value >> 8) & 0xFF); 65717d24755SJustin T. Gibbs } 65817d24755SJustin T. Gibbs 65917d24755SJustin T. Gibbs static __inline u_int 66017d24755SJustin T. Gibbs ahd_inb_scbram(struct ahd_softc *ahd, u_int offset) 66117d24755SJustin T. Gibbs { 66217d24755SJustin T. Gibbs u_int value; 66317d24755SJustin T. Gibbs 66417d24755SJustin T. Gibbs /* 66517d24755SJustin T. Gibbs * Workaround PCI-X Rev A. hardware bug. 66617d24755SJustin T. Gibbs * After a host read of SCB memory, the chip 66717d24755SJustin T. Gibbs * may become confused into thinking prefetch 66817d24755SJustin T. Gibbs * was required. This starts the discard timer 66917d24755SJustin T. Gibbs * running and can cause an unexpected discard 67017d24755SJustin T. Gibbs * timer interrupt. The work around is to read 67117d24755SJustin T. Gibbs * a normal register prior to the exhaustion of 67217d24755SJustin T. Gibbs * the discard timer. The mode pointer register 67317d24755SJustin T. Gibbs * has no side effects and so serves well for 67417d24755SJustin T. Gibbs * this purpose. 67517d24755SJustin T. Gibbs * 67617d24755SJustin T. Gibbs * Razor #528 67717d24755SJustin T. Gibbs */ 67817d24755SJustin T. Gibbs value = ahd_inb(ahd, offset); 67917d24755SJustin T. Gibbs ahd_inb(ahd, MODE_PTR); 68017d24755SJustin T. Gibbs return (value); 68117d24755SJustin T. Gibbs } 68217d24755SJustin T. Gibbs 68317d24755SJustin T. Gibbs static __inline u_int 68417d24755SJustin T. Gibbs ahd_inw_scbram(struct ahd_softc *ahd, u_int offset) 68517d24755SJustin T. Gibbs { 68617d24755SJustin T. Gibbs return (ahd_inb_scbram(ahd, offset) 68717d24755SJustin T. Gibbs | (ahd_inb_scbram(ahd, offset+1) << 8)); 68817d24755SJustin T. Gibbs } 68917d24755SJustin T. Gibbs 69017d24755SJustin T. Gibbs static __inline uint32_t 69117d24755SJustin T. Gibbs ahd_inl_scbram(struct ahd_softc *ahd, u_int offset) 69217d24755SJustin T. Gibbs { 69317d24755SJustin T. Gibbs return (ahd_inb_scbram(ahd, offset) 69417d24755SJustin T. Gibbs | (ahd_inb_scbram(ahd, offset+1) << 8) 69517d24755SJustin T. Gibbs | (ahd_inb_scbram(ahd, offset+2) << 16) 69617d24755SJustin T. Gibbs | (ahd_inb_scbram(ahd, offset+3) << 24)); 69717d24755SJustin T. Gibbs } 69817d24755SJustin T. Gibbs 69917d24755SJustin T. Gibbs static __inline struct scb * 70017d24755SJustin T. Gibbs ahd_lookup_scb(struct ahd_softc *ahd, u_int tag) 70117d24755SJustin T. Gibbs { 70217d24755SJustin T. Gibbs struct scb* scb; 70317d24755SJustin T. Gibbs 70417d24755SJustin T. Gibbs if (tag >= AHD_SCB_MAX) 70517d24755SJustin T. Gibbs return (NULL); 70617d24755SJustin T. Gibbs scb = ahd->scb_data.scbindex[tag]; 70717d24755SJustin T. Gibbs if (scb != NULL) 70817d24755SJustin T. Gibbs ahd_sync_scb(ahd, scb, 70917d24755SJustin T. Gibbs BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 71017d24755SJustin T. Gibbs return (scb); 71117d24755SJustin T. Gibbs } 71217d24755SJustin T. Gibbs 71317d24755SJustin T. Gibbs static __inline void 71417d24755SJustin T. Gibbs ahd_swap_with_next_hscb(struct ahd_softc *ahd, struct scb *scb) 71517d24755SJustin T. Gibbs { 71617d24755SJustin T. Gibbs struct hardware_scb *q_hscb; 71717d24755SJustin T. Gibbs uint32_t saved_hscb_busaddr; 71817d24755SJustin T. Gibbs 71917d24755SJustin T. Gibbs /* 72017d24755SJustin T. Gibbs * Our queuing method is a bit tricky. The card 72117d24755SJustin T. Gibbs * knows in advance which HSCB (by address) to download, 72217d24755SJustin T. Gibbs * and we can't disappoint it. To achieve this, the next 723adcf242eSJustin T. Gibbs * HSCB to download is saved off in ahd->next_queued_hscb. 72417d24755SJustin T. Gibbs * When we are called to queue "an arbitrary scb", 72517d24755SJustin T. Gibbs * we copy the contents of the incoming HSCB to the one 72617d24755SJustin T. Gibbs * the sequencer knows about, swap HSCB pointers and 72717d24755SJustin T. Gibbs * finally assign the SCB to the tag indexed location 72817d24755SJustin T. Gibbs * in the scb_array. This makes sure that we can still 72917d24755SJustin T. Gibbs * locate the correct SCB by SCB_TAG. 73017d24755SJustin T. Gibbs */ 731adcf242eSJustin T. Gibbs q_hscb = ahd->next_queued_hscb; 73217d24755SJustin T. Gibbs saved_hscb_busaddr = q_hscb->hscb_busaddr; 73317d24755SJustin T. Gibbs memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb)); 73417d24755SJustin T. Gibbs q_hscb->hscb_busaddr = saved_hscb_busaddr; 73517d24755SJustin T. Gibbs q_hscb->next_hscb_busaddr = scb->hscb->hscb_busaddr; 73617d24755SJustin T. Gibbs 73717d24755SJustin T. Gibbs /* Now swap HSCB pointers. */ 738adcf242eSJustin T. Gibbs ahd->next_queued_hscb = scb->hscb; 73917d24755SJustin T. Gibbs scb->hscb = q_hscb; 74017d24755SJustin T. Gibbs 74117d24755SJustin T. Gibbs /* Now define the mapping from tag to SCB in the scbindex */ 74217d24755SJustin T. Gibbs ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = scb; 74317d24755SJustin T. Gibbs } 74417d24755SJustin T. Gibbs 74517d24755SJustin T. Gibbs /* 74617d24755SJustin T. Gibbs * Tell the sequencer about a new transaction to execute. 74717d24755SJustin T. Gibbs */ 74817d24755SJustin T. Gibbs static __inline void 74917d24755SJustin T. Gibbs ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb) 75017d24755SJustin T. Gibbs { 75117d24755SJustin T. Gibbs ahd_swap_with_next_hscb(ahd, scb); 75217d24755SJustin T. Gibbs 75317d24755SJustin T. Gibbs if (SCBID_IS_NULL(SCB_GET_TAG(scb))) 75417d24755SJustin T. Gibbs panic("Attempt to queue invalid SCB tag %x\n", 75517d24755SJustin T. Gibbs SCB_GET_TAG(scb)); 75617d24755SJustin T. Gibbs 75717d24755SJustin T. Gibbs /* 75817d24755SJustin T. Gibbs * Keep a history of SCBs we've downloaded in the qinfifo. 75917d24755SJustin T. Gibbs */ 76017d24755SJustin T. Gibbs ahd->qinfifo[AHD_QIN_WRAP(ahd->qinfifonext)] = SCB_GET_TAG(scb); 76117d24755SJustin T. Gibbs ahd->qinfifonext++; 76217d24755SJustin T. Gibbs 76317d24755SJustin T. Gibbs if (scb->sg_count != 0) 76417d24755SJustin T. Gibbs ahd_setup_data_scb(ahd, scb); 76517d24755SJustin T. Gibbs else 76617d24755SJustin T. Gibbs ahd_setup_noxfer_scb(ahd, scb); 76717d24755SJustin T. Gibbs ahd_setup_scb_common(ahd, scb); 76817d24755SJustin T. Gibbs 76917d24755SJustin T. Gibbs /* 77017d24755SJustin T. Gibbs * Make sure our data is consistant from the 77117d24755SJustin T. Gibbs * perspective of the adapter. 77217d24755SJustin T. Gibbs */ 77317d24755SJustin T. Gibbs ahd_sync_scb(ahd, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 77417d24755SJustin T. Gibbs 77517d24755SJustin T. Gibbs #ifdef AHD_DEBUG 77617d24755SJustin T. Gibbs if ((ahd_debug & AHD_SHOW_QUEUE) != 0) { 77717d24755SJustin T. Gibbs printf("%s: Queueing SCB 0x%x bus addr 0x%x - 0x%x%x/0x%x\n", 77817d24755SJustin T. Gibbs ahd_name(ahd), 77917d24755SJustin T. Gibbs SCB_GET_TAG(scb), scb->hscb->hscb_busaddr, 78017d24755SJustin T. Gibbs (u_int)((scb->hscb->dataptr >> 32) & 0xFFFFFFFF), 78117d24755SJustin T. Gibbs (u_int)(scb->hscb->dataptr & 0xFFFFFFFF), 78217d24755SJustin T. Gibbs scb->hscb->datacnt); 78317d24755SJustin T. Gibbs } 78417d24755SJustin T. Gibbs #endif 78517d24755SJustin T. Gibbs /* Tell the adapter about the newly queued SCB */ 78617d24755SJustin T. Gibbs ahd_set_hnscb_qoff(ahd, ahd->qinfifonext); 78717d24755SJustin T. Gibbs } 78817d24755SJustin T. Gibbs 78917d24755SJustin T. Gibbs static __inline uint8_t * 79017d24755SJustin T. Gibbs ahd_get_sense_buf(struct ahd_softc *ahd, struct scb *scb) 79117d24755SJustin T. Gibbs { 79217d24755SJustin T. Gibbs return (scb->sense_data); 79317d24755SJustin T. Gibbs } 79417d24755SJustin T. Gibbs 79517d24755SJustin T. Gibbs static __inline uint32_t 79617d24755SJustin T. Gibbs ahd_get_sense_bufaddr(struct ahd_softc *ahd, struct scb *scb) 79717d24755SJustin T. Gibbs { 79817d24755SJustin T. Gibbs return (scb->sense_busaddr); 79917d24755SJustin T. Gibbs } 80017d24755SJustin T. Gibbs 80117d24755SJustin T. Gibbs /************************** Interrupt Processing ******************************/ 80217d24755SJustin T. Gibbs static __inline void ahd_sync_qoutfifo(struct ahd_softc *ahd, int op); 80317d24755SJustin T. Gibbs static __inline void ahd_sync_tqinfifo(struct ahd_softc *ahd, int op); 80417d24755SJustin T. Gibbs static __inline u_int ahd_check_cmdcmpltqueues(struct ahd_softc *ahd); 80517d24755SJustin T. Gibbs static __inline void ahd_intr(struct ahd_softc *ahd); 80617d24755SJustin T. Gibbs 80717d24755SJustin T. Gibbs static __inline void 80817d24755SJustin T. Gibbs ahd_sync_qoutfifo(struct ahd_softc *ahd, int op) 80917d24755SJustin T. Gibbs { 81017d24755SJustin T. Gibbs ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_dmamap, 81117d24755SJustin T. Gibbs /*offset*/0, /*len*/AHC_SCB_MAX * sizeof(uint16_t), op); 81217d24755SJustin T. Gibbs } 81317d24755SJustin T. Gibbs 81417d24755SJustin T. Gibbs static __inline void 81517d24755SJustin T. Gibbs ahd_sync_tqinfifo(struct ahd_softc *ahd, int op) 81617d24755SJustin T. Gibbs { 81717d24755SJustin T. Gibbs #ifdef AHD_TARGET_MODE 81817d24755SJustin T. Gibbs if ((ahd->flags & AHD_TARGETROLE) != 0) { 81917d24755SJustin T. Gibbs ahd_dmamap_sync(ahd, ahd->shared_data_dmat, 82017d24755SJustin T. Gibbs ahd->shared_data_dmamap, 82117d24755SJustin T. Gibbs ahd_targetcmd_offset(ahd, 0), 82217d24755SJustin T. Gibbs sizeof(struct target_cmd) * AHD_TMODE_CMDS, 82317d24755SJustin T. Gibbs op); 82417d24755SJustin T. Gibbs } 82517d24755SJustin T. Gibbs #endif 82617d24755SJustin T. Gibbs } 82717d24755SJustin T. Gibbs 82817d24755SJustin T. Gibbs /* 82917d24755SJustin T. Gibbs * See if the firmware has posted any completed commands 83017d24755SJustin T. Gibbs * into our in-core command complete fifos. 83117d24755SJustin T. Gibbs */ 83217d24755SJustin T. Gibbs #define AHD_RUN_QOUTFIFO 0x1 83317d24755SJustin T. Gibbs #define AHD_RUN_TQINFIFO 0x2 83417d24755SJustin T. Gibbs static __inline u_int 83517d24755SJustin T. Gibbs ahd_check_cmdcmpltqueues(struct ahd_softc *ahd) 83617d24755SJustin T. Gibbs { 83717d24755SJustin T. Gibbs u_int retval; 83817d24755SJustin T. Gibbs 83917d24755SJustin T. Gibbs retval = 0; 84017d24755SJustin T. Gibbs ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_dmamap, 84117d24755SJustin T. Gibbs /*offset*/ahd->qoutfifonext, /*len*/2, 84217d24755SJustin T. Gibbs BUS_DMASYNC_POSTREAD); 843adcf242eSJustin T. Gibbs if ((ahd->qoutfifo[ahd->qoutfifonext] 844adcf242eSJustin T. Gibbs & QOUTFIFO_ENTRY_VALID_LE) == ahd->qoutfifonext_valid_tag) 84517d24755SJustin T. Gibbs retval |= AHD_RUN_QOUTFIFO; 84617d24755SJustin T. Gibbs #ifdef AHD_TARGET_MODE 84717d24755SJustin T. Gibbs if ((ahd->flags & AHD_TARGETROLE) != 0 84817d24755SJustin T. Gibbs && (ahd->flags & AHD_TQINFIFO_BLOCKED) == 0) { 84917d24755SJustin T. Gibbs ahd_dmamap_sync(ahd, ahd->shared_data_dmat, 85017d24755SJustin T. Gibbs ahd->shared_data_dmamap, 85117d24755SJustin T. Gibbs ahd_targetcmd_offset(ahd, ahd->tqinfifofnext), 85217d24755SJustin T. Gibbs /*len*/sizeof(struct target_cmd), 85317d24755SJustin T. Gibbs BUS_DMASYNC_POSTREAD); 85417d24755SJustin T. Gibbs if (ahd->targetcmds[ahd->tqinfifonext].cmd_valid != 0) 85517d24755SJustin T. Gibbs retval |= AHD_RUN_TQINFIFO; 85617d24755SJustin T. Gibbs } 85717d24755SJustin T. Gibbs #endif 85817d24755SJustin T. Gibbs return (retval); 85917d24755SJustin T. Gibbs } 86017d24755SJustin T. Gibbs 86117d24755SJustin T. Gibbs /* 86217d24755SJustin T. Gibbs * Catch an interrupt from the adapter 86317d24755SJustin T. Gibbs */ 86417d24755SJustin T. Gibbs static __inline void 86517d24755SJustin T. Gibbs ahd_intr(struct ahd_softc *ahd) 86617d24755SJustin T. Gibbs { 86717d24755SJustin T. Gibbs u_int intstat; 86817d24755SJustin T. Gibbs 869adcf242eSJustin T. Gibbs if ((ahd->pause & INTEN) == 0) { 870adcf242eSJustin T. Gibbs /* 871adcf242eSJustin T. Gibbs * Our interrupt is not enabled on the chip 872adcf242eSJustin T. Gibbs * and may be disabled for re-entrancy reasons, 873adcf242eSJustin T. Gibbs * so just return. This is likely just a shared 874adcf242eSJustin T. Gibbs * interrupt. 875adcf242eSJustin T. Gibbs */ 876adcf242eSJustin T. Gibbs return; 877adcf242eSJustin T. Gibbs } 878adcf242eSJustin T. Gibbs 87917d24755SJustin T. Gibbs /* 88017d24755SJustin T. Gibbs * Instead of directly reading the interrupt status register, 88117d24755SJustin T. Gibbs * infer the cause of the interrupt by checking our in-core 88217d24755SJustin T. Gibbs * completion queues. This avoids a costly PCI bus read in 88317d24755SJustin T. Gibbs * most cases. 88417d24755SJustin T. Gibbs */ 88517d24755SJustin T. Gibbs if ((ahd->flags & AHD_ALL_INTERRUPTS) == 0 88617d24755SJustin T. Gibbs && (ahd_check_cmdcmpltqueues(ahd) != 0)) 88717d24755SJustin T. Gibbs intstat = CMDCMPLT; 88817d24755SJustin T. Gibbs else 88917d24755SJustin T. Gibbs intstat = ahd_inb(ahd, INTSTAT); 89017d24755SJustin T. Gibbs 89117d24755SJustin T. Gibbs if (intstat & CMDCMPLT) { 89217d24755SJustin T. Gibbs ahd_outb(ahd, CLRINT, CLRCMDINT); 89317d24755SJustin T. Gibbs 89417d24755SJustin T. Gibbs /* 89517d24755SJustin T. Gibbs * Ensure that the chip sees that we've cleared 89617d24755SJustin T. Gibbs * this interrupt before we walk the output fifo. 89717d24755SJustin T. Gibbs * Otherwise, we may, due to posted bus writes, 89817d24755SJustin T. Gibbs * clear the interrupt after we finish the scan, 89917d24755SJustin T. Gibbs * and after the sequencer has added new entries 90017d24755SJustin T. Gibbs * and asserted the interrupt again. 90117d24755SJustin T. Gibbs */ 902fc2aa1d1SScott Long if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) { 903fc2aa1d1SScott Long if (ahd_is_paused(ahd)) { 904fc2aa1d1SScott Long /* 905fc2aa1d1SScott Long * Potentially lost SEQINT. 906fc2aa1d1SScott Long * If SEQINTCODE is non-zero, 907fc2aa1d1SScott Long * simulate the SEQINT. 908fc2aa1d1SScott Long */ 909fc2aa1d1SScott Long if (ahd_inb(ahd, SEQINTCODE) != NO_SEQINT) 910fc2aa1d1SScott Long intstat |= SEQINT; 911fc2aa1d1SScott Long } 912fc2aa1d1SScott Long } else { 91317d24755SJustin T. Gibbs ahd_flush_device_writes(ahd); 914fc2aa1d1SScott Long } 91517d24755SJustin T. Gibbs ahd_run_qoutfifo(ahd); 91617d24755SJustin T. Gibbs #ifdef AHD_TARGET_MODE 91717d24755SJustin T. Gibbs if ((ahd->flags & AHD_TARGETROLE) != 0) 91817d24755SJustin T. Gibbs ahd_run_tqinfifo(ahd, /*paused*/FALSE); 91917d24755SJustin T. Gibbs #endif 92017d24755SJustin T. Gibbs } 92117d24755SJustin T. Gibbs 92217d24755SJustin T. Gibbs if (intstat == 0xFF && (ahd->features & AHD_REMOVABLE) != 0) 92317d24755SJustin T. Gibbs /* Hot eject */ 92417d24755SJustin T. Gibbs return; 92517d24755SJustin T. Gibbs 92617d24755SJustin T. Gibbs if ((intstat & INT_PEND) == 0) 92717d24755SJustin T. Gibbs return; 92817d24755SJustin T. Gibbs 92917d24755SJustin T. Gibbs if (intstat & HWERRINT) { 93017d24755SJustin T. Gibbs ahd_handle_hwerrint(ahd); 93117d24755SJustin T. Gibbs return; 93217d24755SJustin T. Gibbs } 93317d24755SJustin T. Gibbs 93417d24755SJustin T. Gibbs if ((intstat & (PCIINT|SPLTINT)) != 0) { 93517d24755SJustin T. Gibbs ahd->bus_intr(ahd); 93617d24755SJustin T. Gibbs return; 93717d24755SJustin T. Gibbs } 93817d24755SJustin T. Gibbs 93917d24755SJustin T. Gibbs if ((intstat & SEQINT) != 0) 94017d24755SJustin T. Gibbs ahd_handle_seqint(ahd, intstat); 94117d24755SJustin T. Gibbs 94217d24755SJustin T. Gibbs if ((intstat & SCSIINT) != 0) 94317d24755SJustin T. Gibbs ahd_handle_scsiint(ahd, intstat); 94417d24755SJustin T. Gibbs } 94517d24755SJustin T. Gibbs 94617d24755SJustin T. Gibbs #endif /* _AIC79XX_INLINE_H_ */ 947