11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Inline routines shareable across OS platforms. 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (c) 1994-2001 Justin T. Gibbs. 51da177e4SLinus Torvalds * Copyright (c) 2000-2003 Adaptec Inc. 61da177e4SLinus Torvalds * All rights reserved. 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * Redistribution and use in source and binary forms, with or without 91da177e4SLinus Torvalds * modification, are permitted provided that the following conditions 101da177e4SLinus Torvalds * are met: 111da177e4SLinus Torvalds * 1. Redistributions of source code must retain the above copyright 121da177e4SLinus Torvalds * notice, this list of conditions, and the following disclaimer, 131da177e4SLinus Torvalds * without modification. 141da177e4SLinus Torvalds * 2. Redistributions in binary form must reproduce at minimum a disclaimer 151da177e4SLinus Torvalds * substantially similar to the "NO WARRANTY" disclaimer below 161da177e4SLinus Torvalds * ("Disclaimer") and any redistribution must be conditioned upon 171da177e4SLinus Torvalds * including a substantially similar Disclaimer requirement for further 181da177e4SLinus Torvalds * binary redistribution. 191da177e4SLinus Torvalds * 3. Neither the names of the above-listed copyright holders nor the names 201da177e4SLinus Torvalds * of any contributors may be used to endorse or promote products derived 211da177e4SLinus Torvalds * from this software without specific prior written permission. 221da177e4SLinus Torvalds * 231da177e4SLinus Torvalds * Alternatively, this software may be distributed under the terms of the 241da177e4SLinus Torvalds * GNU General Public License ("GPL") version 2 as published by the Free 251da177e4SLinus Torvalds * Software Foundation. 261da177e4SLinus Torvalds * 271da177e4SLinus Torvalds * NO WARRANTY 281da177e4SLinus Torvalds * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 291da177e4SLinus Torvalds * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 301da177e4SLinus Torvalds * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 311da177e4SLinus Torvalds * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 321da177e4SLinus Torvalds * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 331da177e4SLinus Torvalds * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 341da177e4SLinus Torvalds * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 351da177e4SLinus Torvalds * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 361da177e4SLinus Torvalds * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 371da177e4SLinus Torvalds * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 381da177e4SLinus Torvalds * POSSIBILITY OF SUCH DAMAGES. 391da177e4SLinus Torvalds * 4053467e63SHannes Reinecke * $Id: //depot/aic7xxx/aic7xxx/aic79xx_inline.h#59 $ 411da177e4SLinus Torvalds * 421da177e4SLinus Torvalds * $FreeBSD$ 431da177e4SLinus Torvalds */ 441da177e4SLinus Torvalds 451da177e4SLinus Torvalds #ifndef _AIC79XX_INLINE_H_ 461da177e4SLinus Torvalds #define _AIC79XX_INLINE_H_ 471da177e4SLinus Torvalds 481da177e4SLinus Torvalds /******************************** Debugging ***********************************/ 491da177e4SLinus Torvalds static __inline char *ahd_name(struct ahd_softc *ahd); 501da177e4SLinus Torvalds 511da177e4SLinus Torvalds static __inline char * 521da177e4SLinus Torvalds ahd_name(struct ahd_softc *ahd) 531da177e4SLinus Torvalds { 541da177e4SLinus Torvalds return (ahd->name); 551da177e4SLinus Torvalds } 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds /************************ Sequencer Execution Control *************************/ 581da177e4SLinus Torvalds static __inline void ahd_known_modes(struct ahd_softc *ahd, 591da177e4SLinus Torvalds ahd_mode src, ahd_mode dst); 601da177e4SLinus Torvalds static __inline ahd_mode_state ahd_build_mode_state(struct ahd_softc *ahd, 611da177e4SLinus Torvalds ahd_mode src, 621da177e4SLinus Torvalds ahd_mode dst); 631da177e4SLinus Torvalds static __inline void ahd_extract_mode_state(struct ahd_softc *ahd, 641da177e4SLinus Torvalds ahd_mode_state state, 651da177e4SLinus Torvalds ahd_mode *src, ahd_mode *dst); 661da177e4SLinus Torvalds static __inline void ahd_set_modes(struct ahd_softc *ahd, ahd_mode src, 671da177e4SLinus Torvalds ahd_mode dst); 681da177e4SLinus Torvalds static __inline void ahd_update_modes(struct ahd_softc *ahd); 691da177e4SLinus Torvalds static __inline void ahd_assert_modes(struct ahd_softc *ahd, ahd_mode srcmode, 701da177e4SLinus Torvalds ahd_mode dstmode, const char *file, 711da177e4SLinus Torvalds int line); 721da177e4SLinus Torvalds static __inline ahd_mode_state ahd_save_modes(struct ahd_softc *ahd); 731da177e4SLinus Torvalds static __inline void ahd_restore_modes(struct ahd_softc *ahd, 741da177e4SLinus Torvalds ahd_mode_state state); 751da177e4SLinus Torvalds static __inline int ahd_is_paused(struct ahd_softc *ahd); 761da177e4SLinus Torvalds static __inline void ahd_pause(struct ahd_softc *ahd); 771da177e4SLinus Torvalds static __inline void ahd_unpause(struct ahd_softc *ahd); 781da177e4SLinus Torvalds 791da177e4SLinus Torvalds static __inline void 801da177e4SLinus Torvalds ahd_known_modes(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst) 811da177e4SLinus Torvalds { 821da177e4SLinus Torvalds ahd->src_mode = src; 831da177e4SLinus Torvalds ahd->dst_mode = dst; 841da177e4SLinus Torvalds ahd->saved_src_mode = src; 851da177e4SLinus Torvalds ahd->saved_dst_mode = dst; 861da177e4SLinus Torvalds } 871da177e4SLinus Torvalds 881da177e4SLinus Torvalds static __inline ahd_mode_state 891da177e4SLinus Torvalds ahd_build_mode_state(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst) 901da177e4SLinus Torvalds { 911da177e4SLinus Torvalds return ((src << SRC_MODE_SHIFT) | (dst << DST_MODE_SHIFT)); 921da177e4SLinus Torvalds } 931da177e4SLinus Torvalds 941da177e4SLinus Torvalds static __inline void 951da177e4SLinus Torvalds ahd_extract_mode_state(struct ahd_softc *ahd, ahd_mode_state state, 961da177e4SLinus Torvalds ahd_mode *src, ahd_mode *dst) 971da177e4SLinus Torvalds { 981da177e4SLinus Torvalds *src = (state & SRC_MODE) >> SRC_MODE_SHIFT; 991da177e4SLinus Torvalds *dst = (state & DST_MODE) >> DST_MODE_SHIFT; 1001da177e4SLinus Torvalds } 1011da177e4SLinus Torvalds 1021da177e4SLinus Torvalds static __inline void 1031da177e4SLinus Torvalds ahd_set_modes(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst) 1041da177e4SLinus Torvalds { 1051da177e4SLinus Torvalds if (ahd->src_mode == src && ahd->dst_mode == dst) 1061da177e4SLinus Torvalds return; 1071da177e4SLinus Torvalds #ifdef AHD_DEBUG 1081da177e4SLinus Torvalds if (ahd->src_mode == AHD_MODE_UNKNOWN 1091da177e4SLinus Torvalds || ahd->dst_mode == AHD_MODE_UNKNOWN) 1101da177e4SLinus Torvalds panic("Setting mode prior to saving it.\n"); 1111da177e4SLinus Torvalds if ((ahd_debug & AHD_SHOW_MODEPTR) != 0) 1121da177e4SLinus Torvalds printf("%s: Setting mode 0x%x\n", ahd_name(ahd), 1131da177e4SLinus Torvalds ahd_build_mode_state(ahd, src, dst)); 1141da177e4SLinus Torvalds #endif 1151da177e4SLinus Torvalds ahd_outb(ahd, MODE_PTR, ahd_build_mode_state(ahd, src, dst)); 1161da177e4SLinus Torvalds ahd->src_mode = src; 1171da177e4SLinus Torvalds ahd->dst_mode = dst; 1181da177e4SLinus Torvalds } 1191da177e4SLinus Torvalds 1201da177e4SLinus Torvalds static __inline void 1211da177e4SLinus Torvalds ahd_update_modes(struct ahd_softc *ahd) 1221da177e4SLinus Torvalds { 1231da177e4SLinus Torvalds ahd_mode_state mode_ptr; 1241da177e4SLinus Torvalds ahd_mode src; 1251da177e4SLinus Torvalds ahd_mode dst; 1261da177e4SLinus Torvalds 1271da177e4SLinus Torvalds mode_ptr = ahd_inb(ahd, MODE_PTR); 1281da177e4SLinus Torvalds #ifdef AHD_DEBUG 1291da177e4SLinus Torvalds if ((ahd_debug & AHD_SHOW_MODEPTR) != 0) 1301da177e4SLinus Torvalds printf("Reading mode 0x%x\n", mode_ptr); 1311da177e4SLinus Torvalds #endif 1321da177e4SLinus Torvalds ahd_extract_mode_state(ahd, mode_ptr, &src, &dst); 1331da177e4SLinus Torvalds ahd_known_modes(ahd, src, dst); 1341da177e4SLinus Torvalds } 1351da177e4SLinus Torvalds 1361da177e4SLinus Torvalds static __inline void 1371da177e4SLinus Torvalds ahd_assert_modes(struct ahd_softc *ahd, ahd_mode srcmode, 1381da177e4SLinus Torvalds ahd_mode dstmode, const char *file, int line) 1391da177e4SLinus Torvalds { 1401da177e4SLinus Torvalds #ifdef AHD_DEBUG 1411da177e4SLinus Torvalds if ((srcmode & AHD_MK_MSK(ahd->src_mode)) == 0 1421da177e4SLinus Torvalds || (dstmode & AHD_MK_MSK(ahd->dst_mode)) == 0) { 1431da177e4SLinus Torvalds panic("%s:%s:%d: Mode assertion failed.\n", 1441da177e4SLinus Torvalds ahd_name(ahd), file, line); 1451da177e4SLinus Torvalds } 1461da177e4SLinus Torvalds #endif 1471da177e4SLinus Torvalds } 1481da177e4SLinus Torvalds 1491da177e4SLinus Torvalds static __inline ahd_mode_state 1501da177e4SLinus Torvalds ahd_save_modes(struct ahd_softc *ahd) 1511da177e4SLinus Torvalds { 1521da177e4SLinus Torvalds if (ahd->src_mode == AHD_MODE_UNKNOWN 1531da177e4SLinus Torvalds || ahd->dst_mode == AHD_MODE_UNKNOWN) 1541da177e4SLinus Torvalds ahd_update_modes(ahd); 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds return (ahd_build_mode_state(ahd, ahd->src_mode, ahd->dst_mode)); 1571da177e4SLinus Torvalds } 1581da177e4SLinus Torvalds 1591da177e4SLinus Torvalds static __inline void 1601da177e4SLinus Torvalds ahd_restore_modes(struct ahd_softc *ahd, ahd_mode_state state) 1611da177e4SLinus Torvalds { 1621da177e4SLinus Torvalds ahd_mode src; 1631da177e4SLinus Torvalds ahd_mode dst; 1641da177e4SLinus Torvalds 1651da177e4SLinus Torvalds ahd_extract_mode_state(ahd, state, &src, &dst); 1661da177e4SLinus Torvalds ahd_set_modes(ahd, src, dst); 1671da177e4SLinus Torvalds } 1681da177e4SLinus Torvalds 1691da177e4SLinus Torvalds #define AHD_ASSERT_MODES(ahd, source, dest) \ 1701da177e4SLinus Torvalds ahd_assert_modes(ahd, source, dest, __FILE__, __LINE__); 1711da177e4SLinus Torvalds 1721da177e4SLinus Torvalds /* 1731da177e4SLinus Torvalds * Determine whether the sequencer has halted code execution. 1741da177e4SLinus Torvalds * Returns non-zero status if the sequencer is stopped. 1751da177e4SLinus Torvalds */ 1761da177e4SLinus Torvalds static __inline int 1771da177e4SLinus Torvalds ahd_is_paused(struct ahd_softc *ahd) 1781da177e4SLinus Torvalds { 1791da177e4SLinus Torvalds return ((ahd_inb(ahd, HCNTRL) & PAUSE) != 0); 1801da177e4SLinus Torvalds } 1811da177e4SLinus Torvalds 1821da177e4SLinus Torvalds /* 1831da177e4SLinus Torvalds * Request that the sequencer stop and wait, indefinitely, for it 1841da177e4SLinus Torvalds * to stop. The sequencer will only acknowledge that it is paused 1851da177e4SLinus Torvalds * once it has reached an instruction boundary and PAUSEDIS is 1861da177e4SLinus Torvalds * cleared in the SEQCTL register. The sequencer may use PAUSEDIS 1871da177e4SLinus Torvalds * for critical sections. 1881da177e4SLinus Torvalds */ 1891da177e4SLinus Torvalds static __inline void 1901da177e4SLinus Torvalds ahd_pause(struct ahd_softc *ahd) 1911da177e4SLinus Torvalds { 1921da177e4SLinus Torvalds ahd_outb(ahd, HCNTRL, ahd->pause); 1931da177e4SLinus Torvalds 1941da177e4SLinus Torvalds /* 1951da177e4SLinus Torvalds * Since the sequencer can disable pausing in a critical section, we 1961da177e4SLinus Torvalds * must loop until it actually stops. 1971da177e4SLinus Torvalds */ 1981da177e4SLinus Torvalds while (ahd_is_paused(ahd) == 0) 1991da177e4SLinus Torvalds ; 2001da177e4SLinus Torvalds } 2011da177e4SLinus Torvalds 2021da177e4SLinus Torvalds /* 2031da177e4SLinus Torvalds * Allow the sequencer to continue program execution. 2041da177e4SLinus Torvalds * We check here to ensure that no additional interrupt 2051da177e4SLinus Torvalds * sources that would cause the sequencer to halt have been 2061da177e4SLinus Torvalds * asserted. If, for example, a SCSI bus reset is detected 2071da177e4SLinus Torvalds * while we are fielding a different, pausing, interrupt type, 2081da177e4SLinus Torvalds * we don't want to release the sequencer before going back 2091da177e4SLinus Torvalds * into our interrupt handler and dealing with this new 2101da177e4SLinus Torvalds * condition. 2111da177e4SLinus Torvalds */ 2121da177e4SLinus Torvalds static __inline void 2131da177e4SLinus Torvalds ahd_unpause(struct ahd_softc *ahd) 2141da177e4SLinus Torvalds { 2151da177e4SLinus Torvalds /* 2161da177e4SLinus Torvalds * Automatically restore our modes to those saved 2171da177e4SLinus Torvalds * prior to the first change of the mode. 2181da177e4SLinus Torvalds */ 2191da177e4SLinus Torvalds if (ahd->saved_src_mode != AHD_MODE_UNKNOWN 2201da177e4SLinus Torvalds && ahd->saved_dst_mode != AHD_MODE_UNKNOWN) { 2211da177e4SLinus Torvalds if ((ahd->flags & AHD_UPDATE_PEND_CMDS) != 0) 2221da177e4SLinus Torvalds ahd_reset_cmds_pending(ahd); 2231da177e4SLinus Torvalds ahd_set_modes(ahd, ahd->saved_src_mode, ahd->saved_dst_mode); 2241da177e4SLinus Torvalds } 2251da177e4SLinus Torvalds 2261da177e4SLinus Torvalds if ((ahd_inb(ahd, INTSTAT) & ~CMDCMPLT) == 0) 2271da177e4SLinus Torvalds ahd_outb(ahd, HCNTRL, ahd->unpause); 2281da177e4SLinus Torvalds 2291da177e4SLinus Torvalds ahd_known_modes(ahd, AHD_MODE_UNKNOWN, AHD_MODE_UNKNOWN); 2301da177e4SLinus Torvalds } 2311da177e4SLinus Torvalds 2321da177e4SLinus Torvalds /*********************** Scatter Gather List Handling *************************/ 2331da177e4SLinus Torvalds static __inline void *ahd_sg_setup(struct ahd_softc *ahd, struct scb *scb, 2341da177e4SLinus Torvalds void *sgptr, dma_addr_t addr, 2351da177e4SLinus Torvalds bus_size_t len, int last); 2361da177e4SLinus Torvalds static __inline void ahd_setup_scb_common(struct ahd_softc *ahd, 2371da177e4SLinus Torvalds struct scb *scb); 2381da177e4SLinus Torvalds static __inline void ahd_setup_data_scb(struct ahd_softc *ahd, 2391da177e4SLinus Torvalds struct scb *scb); 2401da177e4SLinus Torvalds static __inline void ahd_setup_noxfer_scb(struct ahd_softc *ahd, 2411da177e4SLinus Torvalds struct scb *scb); 2421da177e4SLinus Torvalds 2431da177e4SLinus Torvalds static __inline void * 2441da177e4SLinus Torvalds ahd_sg_setup(struct ahd_softc *ahd, struct scb *scb, 2451da177e4SLinus Torvalds void *sgptr, dma_addr_t addr, bus_size_t len, int last) 2461da177e4SLinus Torvalds { 2471da177e4SLinus Torvalds scb->sg_count++; 2481da177e4SLinus Torvalds if (sizeof(dma_addr_t) > 4 2491da177e4SLinus Torvalds && (ahd->flags & AHD_64BIT_ADDRESSING) != 0) { 2501da177e4SLinus Torvalds struct ahd_dma64_seg *sg; 2511da177e4SLinus Torvalds 2521da177e4SLinus Torvalds sg = (struct ahd_dma64_seg *)sgptr; 2531da177e4SLinus Torvalds sg->addr = ahd_htole64(addr); 2541da177e4SLinus Torvalds sg->len = ahd_htole32(len | (last ? AHD_DMA_LAST_SEG : 0)); 2551da177e4SLinus Torvalds return (sg + 1); 2561da177e4SLinus Torvalds } else { 2571da177e4SLinus Torvalds struct ahd_dma_seg *sg; 2581da177e4SLinus Torvalds 2591da177e4SLinus Torvalds sg = (struct ahd_dma_seg *)sgptr; 2601da177e4SLinus Torvalds sg->addr = ahd_htole32(addr & 0xFFFFFFFF); 2611da177e4SLinus Torvalds sg->len = ahd_htole32(len | ((addr >> 8) & 0x7F000000) 2621da177e4SLinus Torvalds | (last ? AHD_DMA_LAST_SEG : 0)); 2631da177e4SLinus Torvalds return (sg + 1); 2641da177e4SLinus Torvalds } 2651da177e4SLinus Torvalds } 2661da177e4SLinus Torvalds 2671da177e4SLinus Torvalds static __inline void 2681da177e4SLinus Torvalds ahd_setup_scb_common(struct ahd_softc *ahd, struct scb *scb) 2691da177e4SLinus Torvalds { 2701da177e4SLinus Torvalds /* XXX Handle target mode SCBs. */ 2711da177e4SLinus Torvalds scb->crc_retry_count = 0; 2721da177e4SLinus Torvalds if ((scb->flags & SCB_PACKETIZED) != 0) { 2731da177e4SLinus Torvalds /* XXX what about ACA?? It is type 4, but TAG_TYPE == 0x3. */ 2741da177e4SLinus Torvalds scb->hscb->task_attribute = scb->hscb->control & SCB_TAG_TYPE; 2751da177e4SLinus Torvalds } else { 2761da177e4SLinus Torvalds if (ahd_get_transfer_length(scb) & 0x01) 2771da177e4SLinus Torvalds scb->hscb->task_attribute = SCB_XFERLEN_ODD; 2781da177e4SLinus Torvalds else 2791da177e4SLinus Torvalds scb->hscb->task_attribute = 0; 2801da177e4SLinus Torvalds } 2811da177e4SLinus Torvalds 2821da177e4SLinus Torvalds if (scb->hscb->cdb_len <= MAX_CDB_LEN_WITH_SENSE_ADDR 2831da177e4SLinus Torvalds || (scb->hscb->cdb_len & SCB_CDB_LEN_PTR) != 0) 2841da177e4SLinus Torvalds scb->hscb->shared_data.idata.cdb_plus_saddr.sense_addr = 2851da177e4SLinus Torvalds ahd_htole32(scb->sense_busaddr); 2861da177e4SLinus Torvalds } 2871da177e4SLinus Torvalds 2881da177e4SLinus Torvalds static __inline void 2891da177e4SLinus Torvalds ahd_setup_data_scb(struct ahd_softc *ahd, struct scb *scb) 2901da177e4SLinus Torvalds { 2911da177e4SLinus Torvalds /* 2921da177e4SLinus Torvalds * Copy the first SG into the "current" data ponter area. 2931da177e4SLinus Torvalds */ 2941da177e4SLinus Torvalds if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) { 2951da177e4SLinus Torvalds struct ahd_dma64_seg *sg; 2961da177e4SLinus Torvalds 2971da177e4SLinus Torvalds sg = (struct ahd_dma64_seg *)scb->sg_list; 2981da177e4SLinus Torvalds scb->hscb->dataptr = sg->addr; 2991da177e4SLinus Torvalds scb->hscb->datacnt = sg->len; 3001da177e4SLinus Torvalds } else { 3011da177e4SLinus Torvalds struct ahd_dma_seg *sg; 3021da177e4SLinus Torvalds uint32_t *dataptr_words; 3031da177e4SLinus Torvalds 3041da177e4SLinus Torvalds sg = (struct ahd_dma_seg *)scb->sg_list; 3051da177e4SLinus Torvalds dataptr_words = (uint32_t*)&scb->hscb->dataptr; 3061da177e4SLinus Torvalds dataptr_words[0] = sg->addr; 3071da177e4SLinus Torvalds dataptr_words[1] = 0; 3081da177e4SLinus Torvalds if ((ahd->flags & AHD_39BIT_ADDRESSING) != 0) { 3091da177e4SLinus Torvalds uint64_t high_addr; 3101da177e4SLinus Torvalds 3111da177e4SLinus Torvalds high_addr = ahd_le32toh(sg->len) & 0x7F000000; 3121da177e4SLinus Torvalds scb->hscb->dataptr |= ahd_htole64(high_addr << 8); 3131da177e4SLinus Torvalds } 3141da177e4SLinus Torvalds scb->hscb->datacnt = sg->len; 3151da177e4SLinus Torvalds } 3161da177e4SLinus Torvalds /* 3171da177e4SLinus Torvalds * Note where to find the SG entries in bus space. 3181da177e4SLinus Torvalds * We also set the full residual flag which the 3191da177e4SLinus Torvalds * sequencer will clear as soon as a data transfer 3201da177e4SLinus Torvalds * occurs. 3211da177e4SLinus Torvalds */ 3221da177e4SLinus Torvalds scb->hscb->sgptr = ahd_htole32(scb->sg_list_busaddr|SG_FULL_RESID); 3231da177e4SLinus Torvalds } 3241da177e4SLinus Torvalds 3251da177e4SLinus Torvalds static __inline void 3261da177e4SLinus Torvalds ahd_setup_noxfer_scb(struct ahd_softc *ahd, struct scb *scb) 3271da177e4SLinus Torvalds { 3281da177e4SLinus Torvalds scb->hscb->sgptr = ahd_htole32(SG_LIST_NULL); 3291da177e4SLinus Torvalds scb->hscb->dataptr = 0; 3301da177e4SLinus Torvalds scb->hscb->datacnt = 0; 3311da177e4SLinus Torvalds } 3321da177e4SLinus Torvalds 3331da177e4SLinus Torvalds /************************** Memory mapping routines ***************************/ 3341da177e4SLinus Torvalds static __inline size_t ahd_sg_size(struct ahd_softc *ahd); 3351da177e4SLinus Torvalds static __inline void * 3361da177e4SLinus Torvalds ahd_sg_bus_to_virt(struct ahd_softc *ahd, 3371da177e4SLinus Torvalds struct scb *scb, 3381da177e4SLinus Torvalds uint32_t sg_busaddr); 3391da177e4SLinus Torvalds static __inline uint32_t 3401da177e4SLinus Torvalds ahd_sg_virt_to_bus(struct ahd_softc *ahd, 3411da177e4SLinus Torvalds struct scb *scb, 3421da177e4SLinus Torvalds void *sg); 3431da177e4SLinus Torvalds static __inline void ahd_sync_scb(struct ahd_softc *ahd, 3441da177e4SLinus Torvalds struct scb *scb, int op); 3451da177e4SLinus Torvalds static __inline void ahd_sync_sglist(struct ahd_softc *ahd, 3461da177e4SLinus Torvalds struct scb *scb, int op); 3471da177e4SLinus Torvalds static __inline void ahd_sync_sense(struct ahd_softc *ahd, 3481da177e4SLinus Torvalds struct scb *scb, int op); 3491da177e4SLinus Torvalds static __inline uint32_t 3501da177e4SLinus Torvalds ahd_targetcmd_offset(struct ahd_softc *ahd, 3511da177e4SLinus Torvalds u_int index); 3521da177e4SLinus Torvalds 3531da177e4SLinus Torvalds static __inline size_t 3541da177e4SLinus Torvalds ahd_sg_size(struct ahd_softc *ahd) 3551da177e4SLinus Torvalds { 3561da177e4SLinus Torvalds if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) 3571da177e4SLinus Torvalds return (sizeof(struct ahd_dma64_seg)); 3581da177e4SLinus Torvalds return (sizeof(struct ahd_dma_seg)); 3591da177e4SLinus Torvalds } 3601da177e4SLinus Torvalds 3611da177e4SLinus Torvalds static __inline void * 3621da177e4SLinus Torvalds ahd_sg_bus_to_virt(struct ahd_softc *ahd, struct scb *scb, uint32_t sg_busaddr) 3631da177e4SLinus Torvalds { 3641da177e4SLinus Torvalds dma_addr_t sg_offset; 3651da177e4SLinus Torvalds 3661da177e4SLinus Torvalds /* sg_list_phys points to entry 1, not 0 */ 3671da177e4SLinus Torvalds sg_offset = sg_busaddr - (scb->sg_list_busaddr - ahd_sg_size(ahd)); 3681da177e4SLinus Torvalds return ((uint8_t *)scb->sg_list + sg_offset); 3691da177e4SLinus Torvalds } 3701da177e4SLinus Torvalds 3711da177e4SLinus Torvalds static __inline uint32_t 3721da177e4SLinus Torvalds ahd_sg_virt_to_bus(struct ahd_softc *ahd, struct scb *scb, void *sg) 3731da177e4SLinus Torvalds { 3741da177e4SLinus Torvalds dma_addr_t sg_offset; 3751da177e4SLinus Torvalds 3761da177e4SLinus Torvalds /* sg_list_phys points to entry 1, not 0 */ 3771da177e4SLinus Torvalds sg_offset = ((uint8_t *)sg - (uint8_t *)scb->sg_list) 3781da177e4SLinus Torvalds - ahd_sg_size(ahd); 3791da177e4SLinus Torvalds 3801da177e4SLinus Torvalds return (scb->sg_list_busaddr + sg_offset); 3811da177e4SLinus Torvalds } 3821da177e4SLinus Torvalds 3831da177e4SLinus Torvalds static __inline void 3841da177e4SLinus Torvalds ahd_sync_scb(struct ahd_softc *ahd, struct scb *scb, int op) 3851da177e4SLinus Torvalds { 3861da177e4SLinus Torvalds ahd_dmamap_sync(ahd, ahd->scb_data.hscb_dmat, 3871da177e4SLinus Torvalds scb->hscb_map->dmamap, 3881da177e4SLinus Torvalds /*offset*/(uint8_t*)scb->hscb - scb->hscb_map->vaddr, 3891da177e4SLinus Torvalds /*len*/sizeof(*scb->hscb), op); 3901da177e4SLinus Torvalds } 3911da177e4SLinus Torvalds 3921da177e4SLinus Torvalds static __inline void 3931da177e4SLinus Torvalds ahd_sync_sglist(struct ahd_softc *ahd, struct scb *scb, int op) 3941da177e4SLinus Torvalds { 3951da177e4SLinus Torvalds if (scb->sg_count == 0) 3961da177e4SLinus Torvalds return; 3971da177e4SLinus Torvalds 3981da177e4SLinus Torvalds ahd_dmamap_sync(ahd, ahd->scb_data.sg_dmat, 3991da177e4SLinus Torvalds scb->sg_map->dmamap, 4001da177e4SLinus Torvalds /*offset*/scb->sg_list_busaddr - ahd_sg_size(ahd), 4011da177e4SLinus Torvalds /*len*/ahd_sg_size(ahd) * scb->sg_count, op); 4021da177e4SLinus Torvalds } 4031da177e4SLinus Torvalds 4041da177e4SLinus Torvalds static __inline void 4051da177e4SLinus Torvalds ahd_sync_sense(struct ahd_softc *ahd, struct scb *scb, int op) 4061da177e4SLinus Torvalds { 4071da177e4SLinus Torvalds ahd_dmamap_sync(ahd, ahd->scb_data.sense_dmat, 4081da177e4SLinus Torvalds scb->sense_map->dmamap, 4091da177e4SLinus Torvalds /*offset*/scb->sense_busaddr, 4101da177e4SLinus Torvalds /*len*/AHD_SENSE_BUFSIZE, op); 4111da177e4SLinus Torvalds } 4121da177e4SLinus Torvalds 4131da177e4SLinus Torvalds static __inline uint32_t 4141da177e4SLinus Torvalds ahd_targetcmd_offset(struct ahd_softc *ahd, u_int index) 4151da177e4SLinus Torvalds { 4161da177e4SLinus Torvalds return (((uint8_t *)&ahd->targetcmds[index]) 4171da177e4SLinus Torvalds - (uint8_t *)ahd->qoutfifo); 4181da177e4SLinus Torvalds } 4191da177e4SLinus Torvalds 420*b1c11812SJoe Perches /*********************** Miscellaneous Support Functions ***********************/ 4211da177e4SLinus Torvalds static __inline struct ahd_initiator_tinfo * 4221da177e4SLinus Torvalds ahd_fetch_transinfo(struct ahd_softc *ahd, 4231da177e4SLinus Torvalds char channel, u_int our_id, 4241da177e4SLinus Torvalds u_int remote_id, 4251da177e4SLinus Torvalds struct ahd_tmode_tstate **tstate); 4261da177e4SLinus Torvalds static __inline uint16_t 4271da177e4SLinus Torvalds ahd_inw(struct ahd_softc *ahd, u_int port); 4281da177e4SLinus Torvalds static __inline void ahd_outw(struct ahd_softc *ahd, u_int port, 4291da177e4SLinus Torvalds u_int value); 4301da177e4SLinus Torvalds static __inline uint32_t 4311da177e4SLinus Torvalds ahd_inl(struct ahd_softc *ahd, u_int port); 4321da177e4SLinus Torvalds static __inline void ahd_outl(struct ahd_softc *ahd, u_int port, 4331da177e4SLinus Torvalds uint32_t value); 4341da177e4SLinus Torvalds static __inline uint64_t 4351da177e4SLinus Torvalds ahd_inq(struct ahd_softc *ahd, u_int port); 4361da177e4SLinus Torvalds static __inline void ahd_outq(struct ahd_softc *ahd, u_int port, 4371da177e4SLinus Torvalds uint64_t value); 4381da177e4SLinus Torvalds static __inline u_int ahd_get_scbptr(struct ahd_softc *ahd); 4391da177e4SLinus Torvalds static __inline void ahd_set_scbptr(struct ahd_softc *ahd, u_int scbptr); 4401da177e4SLinus Torvalds static __inline u_int ahd_get_hnscb_qoff(struct ahd_softc *ahd); 4411da177e4SLinus Torvalds static __inline void ahd_set_hnscb_qoff(struct ahd_softc *ahd, u_int value); 4421da177e4SLinus Torvalds static __inline u_int ahd_get_hescb_qoff(struct ahd_softc *ahd); 4431da177e4SLinus Torvalds static __inline void ahd_set_hescb_qoff(struct ahd_softc *ahd, u_int value); 4441da177e4SLinus Torvalds static __inline u_int ahd_get_snscb_qoff(struct ahd_softc *ahd); 4451da177e4SLinus Torvalds static __inline void ahd_set_snscb_qoff(struct ahd_softc *ahd, u_int value); 4461da177e4SLinus Torvalds static __inline u_int ahd_get_sescb_qoff(struct ahd_softc *ahd); 4471da177e4SLinus Torvalds static __inline void ahd_set_sescb_qoff(struct ahd_softc *ahd, u_int value); 4481da177e4SLinus Torvalds static __inline u_int ahd_get_sdscb_qoff(struct ahd_softc *ahd); 4491da177e4SLinus Torvalds static __inline void ahd_set_sdscb_qoff(struct ahd_softc *ahd, u_int value); 4501da177e4SLinus Torvalds static __inline u_int ahd_inb_scbram(struct ahd_softc *ahd, u_int offset); 4511da177e4SLinus Torvalds static __inline u_int ahd_inw_scbram(struct ahd_softc *ahd, u_int offset); 4521da177e4SLinus Torvalds static __inline uint32_t 4531da177e4SLinus Torvalds ahd_inl_scbram(struct ahd_softc *ahd, u_int offset); 4541da177e4SLinus Torvalds static __inline uint64_t 4551da177e4SLinus Torvalds ahd_inq_scbram(struct ahd_softc *ahd, u_int offset); 4561da177e4SLinus Torvalds static __inline void ahd_swap_with_next_hscb(struct ahd_softc *ahd, 4571da177e4SLinus Torvalds struct scb *scb); 4581da177e4SLinus Torvalds static __inline void ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb); 4591da177e4SLinus Torvalds static __inline uint8_t * 4601da177e4SLinus Torvalds ahd_get_sense_buf(struct ahd_softc *ahd, 4611da177e4SLinus Torvalds struct scb *scb); 4621da177e4SLinus Torvalds static __inline uint32_t 4631da177e4SLinus Torvalds ahd_get_sense_bufaddr(struct ahd_softc *ahd, 4641da177e4SLinus Torvalds struct scb *scb); 4651da177e4SLinus Torvalds 4661da177e4SLinus Torvalds /* 4671da177e4SLinus Torvalds * Return pointers to the transfer negotiation information 4681da177e4SLinus Torvalds * for the specified our_id/remote_id pair. 4691da177e4SLinus Torvalds */ 4701da177e4SLinus Torvalds static __inline struct ahd_initiator_tinfo * 4711da177e4SLinus Torvalds ahd_fetch_transinfo(struct ahd_softc *ahd, char channel, u_int our_id, 4721da177e4SLinus Torvalds u_int remote_id, struct ahd_tmode_tstate **tstate) 4731da177e4SLinus Torvalds { 4741da177e4SLinus Torvalds /* 4751da177e4SLinus Torvalds * Transfer data structures are stored from the perspective 4761da177e4SLinus Torvalds * of the target role. Since the parameters for a connection 4771da177e4SLinus Torvalds * in the initiator role to a given target are the same as 4781da177e4SLinus Torvalds * when the roles are reversed, we pretend we are the target. 4791da177e4SLinus Torvalds */ 4801da177e4SLinus Torvalds if (channel == 'B') 4811da177e4SLinus Torvalds our_id += 8; 4821da177e4SLinus Torvalds *tstate = ahd->enabled_targets[our_id]; 4831da177e4SLinus Torvalds return (&(*tstate)->transinfo[remote_id]); 4841da177e4SLinus Torvalds } 4851da177e4SLinus Torvalds 4861da177e4SLinus Torvalds #define AHD_COPY_COL_IDX(dst, src) \ 4871da177e4SLinus Torvalds do { \ 4881da177e4SLinus Torvalds dst->hscb->scsiid = src->hscb->scsiid; \ 4891da177e4SLinus Torvalds dst->hscb->lun = src->hscb->lun; \ 4901da177e4SLinus Torvalds } while (0) 4911da177e4SLinus Torvalds 4921da177e4SLinus Torvalds static __inline uint16_t 4931da177e4SLinus Torvalds ahd_inw(struct ahd_softc *ahd, u_int port) 4941da177e4SLinus Torvalds { 49566a0683eSHannes Reinecke /* 49666a0683eSHannes Reinecke * Read high byte first as some registers increment 49766a0683eSHannes Reinecke * or have other side effects when the low byte is 49866a0683eSHannes Reinecke * read. 49966a0683eSHannes Reinecke */ 5007b75b990SDenis Vlasenko uint16_t r = ahd_inb(ahd, port+1) << 8; 5017b75b990SDenis Vlasenko return r | ahd_inb(ahd, port); 5021da177e4SLinus Torvalds } 5031da177e4SLinus Torvalds 5041da177e4SLinus Torvalds static __inline void 5051da177e4SLinus Torvalds ahd_outw(struct ahd_softc *ahd, u_int port, u_int value) 5061da177e4SLinus Torvalds { 50766a0683eSHannes Reinecke /* 50866a0683eSHannes Reinecke * Write low byte first to accomodate registers 50966a0683eSHannes Reinecke * such as PRGMCNT where the order maters. 51066a0683eSHannes Reinecke */ 5111da177e4SLinus Torvalds ahd_outb(ahd, port, value & 0xFF); 5121da177e4SLinus Torvalds ahd_outb(ahd, port+1, (value >> 8) & 0xFF); 5131da177e4SLinus Torvalds } 5141da177e4SLinus Torvalds 5151da177e4SLinus Torvalds static __inline uint32_t 5161da177e4SLinus Torvalds ahd_inl(struct ahd_softc *ahd, u_int port) 5171da177e4SLinus Torvalds { 5181da177e4SLinus Torvalds return ((ahd_inb(ahd, port)) 5191da177e4SLinus Torvalds | (ahd_inb(ahd, port+1) << 8) 5201da177e4SLinus Torvalds | (ahd_inb(ahd, port+2) << 16) 5211da177e4SLinus Torvalds | (ahd_inb(ahd, port+3) << 24)); 5221da177e4SLinus Torvalds } 5231da177e4SLinus Torvalds 5241da177e4SLinus Torvalds static __inline void 5251da177e4SLinus Torvalds ahd_outl(struct ahd_softc *ahd, u_int port, uint32_t value) 5261da177e4SLinus Torvalds { 5271da177e4SLinus Torvalds ahd_outb(ahd, port, (value) & 0xFF); 5281da177e4SLinus Torvalds ahd_outb(ahd, port+1, ((value) >> 8) & 0xFF); 5291da177e4SLinus Torvalds ahd_outb(ahd, port+2, ((value) >> 16) & 0xFF); 5301da177e4SLinus Torvalds ahd_outb(ahd, port+3, ((value) >> 24) & 0xFF); 5311da177e4SLinus Torvalds } 5321da177e4SLinus Torvalds 5331da177e4SLinus Torvalds static __inline uint64_t 5341da177e4SLinus Torvalds ahd_inq(struct ahd_softc *ahd, u_int port) 5351da177e4SLinus Torvalds { 5361da177e4SLinus Torvalds return ((ahd_inb(ahd, port)) 5371da177e4SLinus Torvalds | (ahd_inb(ahd, port+1) << 8) 5381da177e4SLinus Torvalds | (ahd_inb(ahd, port+2) << 16) 5391da177e4SLinus Torvalds | (ahd_inb(ahd, port+3) << 24) 5401da177e4SLinus Torvalds | (((uint64_t)ahd_inb(ahd, port+4)) << 32) 5411da177e4SLinus Torvalds | (((uint64_t)ahd_inb(ahd, port+5)) << 40) 5421da177e4SLinus Torvalds | (((uint64_t)ahd_inb(ahd, port+6)) << 48) 5431da177e4SLinus Torvalds | (((uint64_t)ahd_inb(ahd, port+7)) << 56)); 5441da177e4SLinus Torvalds } 5451da177e4SLinus Torvalds 5461da177e4SLinus Torvalds static __inline void 5471da177e4SLinus Torvalds ahd_outq(struct ahd_softc *ahd, u_int port, uint64_t value) 5481da177e4SLinus Torvalds { 5491da177e4SLinus Torvalds ahd_outb(ahd, port, value & 0xFF); 5501da177e4SLinus Torvalds ahd_outb(ahd, port+1, (value >> 8) & 0xFF); 5511da177e4SLinus Torvalds ahd_outb(ahd, port+2, (value >> 16) & 0xFF); 5521da177e4SLinus Torvalds ahd_outb(ahd, port+3, (value >> 24) & 0xFF); 5531da177e4SLinus Torvalds ahd_outb(ahd, port+4, (value >> 32) & 0xFF); 5541da177e4SLinus Torvalds ahd_outb(ahd, port+5, (value >> 40) & 0xFF); 5551da177e4SLinus Torvalds ahd_outb(ahd, port+6, (value >> 48) & 0xFF); 5561da177e4SLinus Torvalds ahd_outb(ahd, port+7, (value >> 56) & 0xFF); 5571da177e4SLinus Torvalds } 5581da177e4SLinus Torvalds 5591da177e4SLinus Torvalds static __inline u_int 5601da177e4SLinus Torvalds ahd_get_scbptr(struct ahd_softc *ahd) 5611da177e4SLinus Torvalds { 5621da177e4SLinus Torvalds AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK), 5631da177e4SLinus Torvalds ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK)); 5641da177e4SLinus Torvalds return (ahd_inb(ahd, SCBPTR) | (ahd_inb(ahd, SCBPTR + 1) << 8)); 5651da177e4SLinus Torvalds } 5661da177e4SLinus Torvalds 5671da177e4SLinus Torvalds static __inline void 5681da177e4SLinus Torvalds ahd_set_scbptr(struct ahd_softc *ahd, u_int scbptr) 5691da177e4SLinus Torvalds { 5701da177e4SLinus Torvalds AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK), 5711da177e4SLinus Torvalds ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK)); 5721da177e4SLinus Torvalds ahd_outb(ahd, SCBPTR, scbptr & 0xFF); 5731da177e4SLinus Torvalds ahd_outb(ahd, SCBPTR+1, (scbptr >> 8) & 0xFF); 5741da177e4SLinus Torvalds } 5751da177e4SLinus Torvalds 5761da177e4SLinus Torvalds static __inline u_int 5771da177e4SLinus Torvalds ahd_get_hnscb_qoff(struct ahd_softc *ahd) 5781da177e4SLinus Torvalds { 5791da177e4SLinus Torvalds return (ahd_inw_atomic(ahd, HNSCB_QOFF)); 5801da177e4SLinus Torvalds } 5811da177e4SLinus Torvalds 5821da177e4SLinus Torvalds static __inline void 5831da177e4SLinus Torvalds ahd_set_hnscb_qoff(struct ahd_softc *ahd, u_int value) 5841da177e4SLinus Torvalds { 5851da177e4SLinus Torvalds ahd_outw_atomic(ahd, HNSCB_QOFF, value); 5861da177e4SLinus Torvalds } 5871da177e4SLinus Torvalds 5881da177e4SLinus Torvalds static __inline u_int 5891da177e4SLinus Torvalds ahd_get_hescb_qoff(struct ahd_softc *ahd) 5901da177e4SLinus Torvalds { 5911da177e4SLinus Torvalds return (ahd_inb(ahd, HESCB_QOFF)); 5921da177e4SLinus Torvalds } 5931da177e4SLinus Torvalds 5941da177e4SLinus Torvalds static __inline void 5951da177e4SLinus Torvalds ahd_set_hescb_qoff(struct ahd_softc *ahd, u_int value) 5961da177e4SLinus Torvalds { 5971da177e4SLinus Torvalds ahd_outb(ahd, HESCB_QOFF, value); 5981da177e4SLinus Torvalds } 5991da177e4SLinus Torvalds 6001da177e4SLinus Torvalds static __inline u_int 6011da177e4SLinus Torvalds ahd_get_snscb_qoff(struct ahd_softc *ahd) 6021da177e4SLinus Torvalds { 6031da177e4SLinus Torvalds u_int oldvalue; 6041da177e4SLinus Torvalds 6051da177e4SLinus Torvalds AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 6061da177e4SLinus Torvalds oldvalue = ahd_inw(ahd, SNSCB_QOFF); 6071da177e4SLinus Torvalds ahd_outw(ahd, SNSCB_QOFF, oldvalue); 6081da177e4SLinus Torvalds return (oldvalue); 6091da177e4SLinus Torvalds } 6101da177e4SLinus Torvalds 6111da177e4SLinus Torvalds static __inline void 6121da177e4SLinus Torvalds ahd_set_snscb_qoff(struct ahd_softc *ahd, u_int value) 6131da177e4SLinus Torvalds { 6141da177e4SLinus Torvalds AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 6151da177e4SLinus Torvalds ahd_outw(ahd, SNSCB_QOFF, value); 6161da177e4SLinus Torvalds } 6171da177e4SLinus Torvalds 6181da177e4SLinus Torvalds static __inline u_int 6191da177e4SLinus Torvalds ahd_get_sescb_qoff(struct ahd_softc *ahd) 6201da177e4SLinus Torvalds { 6211da177e4SLinus Torvalds AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 6221da177e4SLinus Torvalds return (ahd_inb(ahd, SESCB_QOFF)); 6231da177e4SLinus Torvalds } 6241da177e4SLinus Torvalds 6251da177e4SLinus Torvalds static __inline void 6261da177e4SLinus Torvalds ahd_set_sescb_qoff(struct ahd_softc *ahd, u_int value) 6271da177e4SLinus Torvalds { 6281da177e4SLinus Torvalds AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 6291da177e4SLinus Torvalds ahd_outb(ahd, SESCB_QOFF, value); 6301da177e4SLinus Torvalds } 6311da177e4SLinus Torvalds 6321da177e4SLinus Torvalds static __inline u_int 6331da177e4SLinus Torvalds ahd_get_sdscb_qoff(struct ahd_softc *ahd) 6341da177e4SLinus Torvalds { 6351da177e4SLinus Torvalds AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 6361da177e4SLinus Torvalds return (ahd_inb(ahd, SDSCB_QOFF) | (ahd_inb(ahd, SDSCB_QOFF + 1) << 8)); 6371da177e4SLinus Torvalds } 6381da177e4SLinus Torvalds 6391da177e4SLinus Torvalds static __inline void 6401da177e4SLinus Torvalds ahd_set_sdscb_qoff(struct ahd_softc *ahd, u_int value) 6411da177e4SLinus Torvalds { 6421da177e4SLinus Torvalds AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 6431da177e4SLinus Torvalds ahd_outb(ahd, SDSCB_QOFF, value & 0xFF); 6441da177e4SLinus Torvalds ahd_outb(ahd, SDSCB_QOFF+1, (value >> 8) & 0xFF); 6451da177e4SLinus Torvalds } 6461da177e4SLinus Torvalds 6471da177e4SLinus Torvalds static __inline u_int 6481da177e4SLinus Torvalds ahd_inb_scbram(struct ahd_softc *ahd, u_int offset) 6491da177e4SLinus Torvalds { 6501da177e4SLinus Torvalds u_int value; 6511da177e4SLinus Torvalds 6521da177e4SLinus Torvalds /* 6531da177e4SLinus Torvalds * Workaround PCI-X Rev A. hardware bug. 6541da177e4SLinus Torvalds * After a host read of SCB memory, the chip 6551da177e4SLinus Torvalds * may become confused into thinking prefetch 6561da177e4SLinus Torvalds * was required. This starts the discard timer 6571da177e4SLinus Torvalds * running and can cause an unexpected discard 6581da177e4SLinus Torvalds * timer interrupt. The work around is to read 6591da177e4SLinus Torvalds * a normal register prior to the exhaustion of 6601da177e4SLinus Torvalds * the discard timer. The mode pointer register 6611da177e4SLinus Torvalds * has no side effects and so serves well for 6621da177e4SLinus Torvalds * this purpose. 6631da177e4SLinus Torvalds * 6641da177e4SLinus Torvalds * Razor #528 6651da177e4SLinus Torvalds */ 6661da177e4SLinus Torvalds value = ahd_inb(ahd, offset); 66766a0683eSHannes Reinecke if ((ahd->bugs & AHD_PCIX_SCBRAM_RD_BUG) != 0) 6681da177e4SLinus Torvalds ahd_inb(ahd, MODE_PTR); 6691da177e4SLinus Torvalds return (value); 6701da177e4SLinus Torvalds } 6711da177e4SLinus Torvalds 6721da177e4SLinus Torvalds static __inline u_int 6731da177e4SLinus Torvalds ahd_inw_scbram(struct ahd_softc *ahd, u_int offset) 6741da177e4SLinus Torvalds { 6751da177e4SLinus Torvalds return (ahd_inb_scbram(ahd, offset) 6761da177e4SLinus Torvalds | (ahd_inb_scbram(ahd, offset+1) << 8)); 6771da177e4SLinus Torvalds } 6781da177e4SLinus Torvalds 6791da177e4SLinus Torvalds static __inline uint32_t 6801da177e4SLinus Torvalds ahd_inl_scbram(struct ahd_softc *ahd, u_int offset) 6811da177e4SLinus Torvalds { 6821da177e4SLinus Torvalds return (ahd_inw_scbram(ahd, offset) 6831da177e4SLinus Torvalds | (ahd_inw_scbram(ahd, offset+2) << 16)); 6841da177e4SLinus Torvalds } 6851da177e4SLinus Torvalds 6861da177e4SLinus Torvalds static __inline uint64_t 6871da177e4SLinus Torvalds ahd_inq_scbram(struct ahd_softc *ahd, u_int offset) 6881da177e4SLinus Torvalds { 6891da177e4SLinus Torvalds return (ahd_inl_scbram(ahd, offset) 6901da177e4SLinus Torvalds | ((uint64_t)ahd_inl_scbram(ahd, offset+4)) << 32); 6911da177e4SLinus Torvalds } 6921da177e4SLinus Torvalds 6931da177e4SLinus Torvalds static __inline struct scb * 6941da177e4SLinus Torvalds ahd_lookup_scb(struct ahd_softc *ahd, u_int tag) 6951da177e4SLinus Torvalds { 6961da177e4SLinus Torvalds struct scb* scb; 6971da177e4SLinus Torvalds 6981da177e4SLinus Torvalds if (tag >= AHD_SCB_MAX) 6991da177e4SLinus Torvalds return (NULL); 7001da177e4SLinus Torvalds scb = ahd->scb_data.scbindex[tag]; 7011da177e4SLinus Torvalds if (scb != NULL) 7021da177e4SLinus Torvalds ahd_sync_scb(ahd, scb, 7031da177e4SLinus Torvalds BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 7041da177e4SLinus Torvalds return (scb); 7051da177e4SLinus Torvalds } 7061da177e4SLinus Torvalds 7071da177e4SLinus Torvalds static __inline void 7081da177e4SLinus Torvalds ahd_swap_with_next_hscb(struct ahd_softc *ahd, struct scb *scb) 7091da177e4SLinus Torvalds { 7101da177e4SLinus Torvalds struct hardware_scb *q_hscb; 71166a0683eSHannes Reinecke struct map_node *q_hscb_map; 7121da177e4SLinus Torvalds uint32_t saved_hscb_busaddr; 7131da177e4SLinus Torvalds 7141da177e4SLinus Torvalds /* 7151da177e4SLinus Torvalds * Our queuing method is a bit tricky. The card 7161da177e4SLinus Torvalds * knows in advance which HSCB (by address) to download, 7171da177e4SLinus Torvalds * and we can't disappoint it. To achieve this, the next 7181da177e4SLinus Torvalds * HSCB to download is saved off in ahd->next_queued_hscb. 7191da177e4SLinus Torvalds * When we are called to queue "an arbitrary scb", 7201da177e4SLinus Torvalds * we copy the contents of the incoming HSCB to the one 7211da177e4SLinus Torvalds * the sequencer knows about, swap HSCB pointers and 7221da177e4SLinus Torvalds * finally assign the SCB to the tag indexed location 7231da177e4SLinus Torvalds * in the scb_array. This makes sure that we can still 7241da177e4SLinus Torvalds * locate the correct SCB by SCB_TAG. 7251da177e4SLinus Torvalds */ 7261da177e4SLinus Torvalds q_hscb = ahd->next_queued_hscb; 72766a0683eSHannes Reinecke q_hscb_map = ahd->next_queued_hscb_map; 7281da177e4SLinus Torvalds saved_hscb_busaddr = q_hscb->hscb_busaddr; 7291da177e4SLinus Torvalds memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb)); 7301da177e4SLinus Torvalds q_hscb->hscb_busaddr = saved_hscb_busaddr; 7311da177e4SLinus Torvalds q_hscb->next_hscb_busaddr = scb->hscb->hscb_busaddr; 7321da177e4SLinus Torvalds 7331da177e4SLinus Torvalds /* Now swap HSCB pointers. */ 7341da177e4SLinus Torvalds ahd->next_queued_hscb = scb->hscb; 73566a0683eSHannes Reinecke ahd->next_queued_hscb_map = scb->hscb_map; 7361da177e4SLinus Torvalds scb->hscb = q_hscb; 73766a0683eSHannes Reinecke scb->hscb_map = q_hscb_map; 7381da177e4SLinus Torvalds 7391da177e4SLinus Torvalds /* Now define the mapping from tag to SCB in the scbindex */ 7401da177e4SLinus Torvalds ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = scb; 7411da177e4SLinus Torvalds } 7421da177e4SLinus Torvalds 7431da177e4SLinus Torvalds /* 7441da177e4SLinus Torvalds * Tell the sequencer about a new transaction to execute. 7451da177e4SLinus Torvalds */ 7461da177e4SLinus Torvalds static __inline void 7471da177e4SLinus Torvalds ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb) 7481da177e4SLinus Torvalds { 7491da177e4SLinus Torvalds ahd_swap_with_next_hscb(ahd, scb); 7501da177e4SLinus Torvalds 7511da177e4SLinus Torvalds if (SCBID_IS_NULL(SCB_GET_TAG(scb))) 7521da177e4SLinus Torvalds panic("Attempt to queue invalid SCB tag %x\n", 7531da177e4SLinus Torvalds SCB_GET_TAG(scb)); 7541da177e4SLinus Torvalds 7551da177e4SLinus Torvalds /* 7561da177e4SLinus Torvalds * Keep a history of SCBs we've downloaded in the qinfifo. 7571da177e4SLinus Torvalds */ 7581da177e4SLinus Torvalds ahd->qinfifo[AHD_QIN_WRAP(ahd->qinfifonext)] = SCB_GET_TAG(scb); 7591da177e4SLinus Torvalds ahd->qinfifonext++; 7601da177e4SLinus Torvalds 7611da177e4SLinus Torvalds if (scb->sg_count != 0) 7621da177e4SLinus Torvalds ahd_setup_data_scb(ahd, scb); 7631da177e4SLinus Torvalds else 7641da177e4SLinus Torvalds ahd_setup_noxfer_scb(ahd, scb); 7651da177e4SLinus Torvalds ahd_setup_scb_common(ahd, scb); 7661da177e4SLinus Torvalds 7671da177e4SLinus Torvalds /* 7681da177e4SLinus Torvalds * Make sure our data is consistent from the 7691da177e4SLinus Torvalds * perspective of the adapter. 7701da177e4SLinus Torvalds */ 7711da177e4SLinus Torvalds ahd_sync_scb(ahd, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 7721da177e4SLinus Torvalds 7731da177e4SLinus Torvalds #ifdef AHD_DEBUG 7741da177e4SLinus Torvalds if ((ahd_debug & AHD_SHOW_QUEUE) != 0) { 7751da177e4SLinus Torvalds uint64_t host_dataptr; 7761da177e4SLinus Torvalds 7771da177e4SLinus Torvalds host_dataptr = ahd_le64toh(scb->hscb->dataptr); 77853467e63SHannes Reinecke printf("%s: Queueing SCB %d:0x%x bus addr 0x%x - 0x%x%x/0x%x\n", 7791da177e4SLinus Torvalds ahd_name(ahd), 78053467e63SHannes Reinecke SCB_GET_TAG(scb), scb->hscb->scsiid, 78153467e63SHannes Reinecke ahd_le32toh(scb->hscb->hscb_busaddr), 7821da177e4SLinus Torvalds (u_int)((host_dataptr >> 32) & 0xFFFFFFFF), 7831da177e4SLinus Torvalds (u_int)(host_dataptr & 0xFFFFFFFF), 7841da177e4SLinus Torvalds ahd_le32toh(scb->hscb->datacnt)); 7851da177e4SLinus Torvalds } 7861da177e4SLinus Torvalds #endif 7871da177e4SLinus Torvalds /* Tell the adapter about the newly queued SCB */ 7881da177e4SLinus Torvalds ahd_set_hnscb_qoff(ahd, ahd->qinfifonext); 7891da177e4SLinus Torvalds } 7901da177e4SLinus Torvalds 7911da177e4SLinus Torvalds static __inline uint8_t * 7921da177e4SLinus Torvalds ahd_get_sense_buf(struct ahd_softc *ahd, struct scb *scb) 7931da177e4SLinus Torvalds { 7941da177e4SLinus Torvalds return (scb->sense_data); 7951da177e4SLinus Torvalds } 7961da177e4SLinus Torvalds 7971da177e4SLinus Torvalds static __inline uint32_t 7981da177e4SLinus Torvalds ahd_get_sense_bufaddr(struct ahd_softc *ahd, struct scb *scb) 7991da177e4SLinus Torvalds { 8001da177e4SLinus Torvalds return (scb->sense_busaddr); 8011da177e4SLinus Torvalds } 8021da177e4SLinus Torvalds 8031da177e4SLinus Torvalds /************************** Interrupt Processing ******************************/ 8041da177e4SLinus Torvalds static __inline void ahd_sync_qoutfifo(struct ahd_softc *ahd, int op); 8051da177e4SLinus Torvalds static __inline void ahd_sync_tqinfifo(struct ahd_softc *ahd, int op); 8061da177e4SLinus Torvalds static __inline u_int ahd_check_cmdcmpltqueues(struct ahd_softc *ahd); 8071da177e4SLinus Torvalds static __inline int ahd_intr(struct ahd_softc *ahd); 8081da177e4SLinus Torvalds 8091da177e4SLinus Torvalds static __inline void 8101da177e4SLinus Torvalds ahd_sync_qoutfifo(struct ahd_softc *ahd, int op) 8111da177e4SLinus Torvalds { 81266a0683eSHannes Reinecke ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_map.dmamap, 81366a0683eSHannes Reinecke /*offset*/0, 81411668bb6SHannes Reinecke /*len*/AHD_SCB_MAX * sizeof(struct ahd_completion), op); 8151da177e4SLinus Torvalds } 8161da177e4SLinus Torvalds 8171da177e4SLinus Torvalds static __inline void 8181da177e4SLinus Torvalds ahd_sync_tqinfifo(struct ahd_softc *ahd, int op) 8191da177e4SLinus Torvalds { 8201da177e4SLinus Torvalds #ifdef AHD_TARGET_MODE 8211da177e4SLinus Torvalds if ((ahd->flags & AHD_TARGETROLE) != 0) { 8221da177e4SLinus Torvalds ahd_dmamap_sync(ahd, ahd->shared_data_dmat, 82366a0683eSHannes Reinecke ahd->shared_data_map.dmamap, 8241da177e4SLinus Torvalds ahd_targetcmd_offset(ahd, 0), 8251da177e4SLinus Torvalds sizeof(struct target_cmd) * AHD_TMODE_CMDS, 8261da177e4SLinus Torvalds op); 8271da177e4SLinus Torvalds } 8281da177e4SLinus Torvalds #endif 8291da177e4SLinus Torvalds } 8301da177e4SLinus Torvalds 8311da177e4SLinus Torvalds /* 8321da177e4SLinus Torvalds * See if the firmware has posted any completed commands 8331da177e4SLinus Torvalds * into our in-core command complete fifos. 8341da177e4SLinus Torvalds */ 8351da177e4SLinus Torvalds #define AHD_RUN_QOUTFIFO 0x1 8361da177e4SLinus Torvalds #define AHD_RUN_TQINFIFO 0x2 8371da177e4SLinus Torvalds static __inline u_int 8381da177e4SLinus Torvalds ahd_check_cmdcmpltqueues(struct ahd_softc *ahd) 8391da177e4SLinus Torvalds { 8401da177e4SLinus Torvalds u_int retval; 8411da177e4SLinus Torvalds 8421da177e4SLinus Torvalds retval = 0; 84366a0683eSHannes Reinecke ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_map.dmamap, 84466a0683eSHannes Reinecke /*offset*/ahd->qoutfifonext * sizeof(*ahd->qoutfifo), 84566a0683eSHannes Reinecke /*len*/sizeof(*ahd->qoutfifo), BUS_DMASYNC_POSTREAD); 84611668bb6SHannes Reinecke if (ahd->qoutfifo[ahd->qoutfifonext].valid_tag 84711668bb6SHannes Reinecke == ahd->qoutfifonext_valid_tag) 8481da177e4SLinus Torvalds retval |= AHD_RUN_QOUTFIFO; 8491da177e4SLinus Torvalds #ifdef AHD_TARGET_MODE 8501da177e4SLinus Torvalds if ((ahd->flags & AHD_TARGETROLE) != 0 8511da177e4SLinus Torvalds && (ahd->flags & AHD_TQINFIFO_BLOCKED) == 0) { 8521da177e4SLinus Torvalds ahd_dmamap_sync(ahd, ahd->shared_data_dmat, 85366a0683eSHannes Reinecke ahd->shared_data_map.dmamap, 8541da177e4SLinus Torvalds ahd_targetcmd_offset(ahd, ahd->tqinfifofnext), 8551da177e4SLinus Torvalds /*len*/sizeof(struct target_cmd), 8561da177e4SLinus Torvalds BUS_DMASYNC_POSTREAD); 8571da177e4SLinus Torvalds if (ahd->targetcmds[ahd->tqinfifonext].cmd_valid != 0) 8581da177e4SLinus Torvalds retval |= AHD_RUN_TQINFIFO; 8591da177e4SLinus Torvalds } 8601da177e4SLinus Torvalds #endif 8611da177e4SLinus Torvalds return (retval); 8621da177e4SLinus Torvalds } 8631da177e4SLinus Torvalds 8641da177e4SLinus Torvalds /* 8651da177e4SLinus Torvalds * Catch an interrupt from the adapter 8661da177e4SLinus Torvalds */ 8671da177e4SLinus Torvalds static __inline int 8681da177e4SLinus Torvalds ahd_intr(struct ahd_softc *ahd) 8691da177e4SLinus Torvalds { 8701da177e4SLinus Torvalds u_int intstat; 8711da177e4SLinus Torvalds 8721da177e4SLinus Torvalds if ((ahd->pause & INTEN) == 0) { 8731da177e4SLinus Torvalds /* 8741da177e4SLinus Torvalds * Our interrupt is not enabled on the chip 8751da177e4SLinus Torvalds * and may be disabled for re-entrancy reasons, 8761da177e4SLinus Torvalds * so just return. This is likely just a shared 8771da177e4SLinus Torvalds * interrupt. 8781da177e4SLinus Torvalds */ 8791da177e4SLinus Torvalds return (0); 8801da177e4SLinus Torvalds } 8811da177e4SLinus Torvalds 8821da177e4SLinus Torvalds /* 8831da177e4SLinus Torvalds * Instead of directly reading the interrupt status register, 8841da177e4SLinus Torvalds * infer the cause of the interrupt by checking our in-core 8851da177e4SLinus Torvalds * completion queues. This avoids a costly PCI bus read in 8861da177e4SLinus Torvalds * most cases. 8871da177e4SLinus Torvalds */ 8881da177e4SLinus Torvalds if ((ahd->flags & AHD_ALL_INTERRUPTS) == 0 8891da177e4SLinus Torvalds && (ahd_check_cmdcmpltqueues(ahd) != 0)) 8901da177e4SLinus Torvalds intstat = CMDCMPLT; 8911da177e4SLinus Torvalds else 8921da177e4SLinus Torvalds intstat = ahd_inb(ahd, INTSTAT); 8931da177e4SLinus Torvalds 8941da177e4SLinus Torvalds if ((intstat & INT_PEND) == 0) 8951da177e4SLinus Torvalds return (0); 8961da177e4SLinus Torvalds 8971da177e4SLinus Torvalds if (intstat & CMDCMPLT) { 8981da177e4SLinus Torvalds ahd_outb(ahd, CLRINT, CLRCMDINT); 8991da177e4SLinus Torvalds 9001da177e4SLinus Torvalds /* 9011da177e4SLinus Torvalds * Ensure that the chip sees that we've cleared 9021da177e4SLinus Torvalds * this interrupt before we walk the output fifo. 9031da177e4SLinus Torvalds * Otherwise, we may, due to posted bus writes, 9041da177e4SLinus Torvalds * clear the interrupt after we finish the scan, 9051da177e4SLinus Torvalds * and after the sequencer has added new entries 9061da177e4SLinus Torvalds * and asserted the interrupt again. 9071da177e4SLinus Torvalds */ 9081da177e4SLinus Torvalds if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) { 9091da177e4SLinus Torvalds if (ahd_is_paused(ahd)) { 9101da177e4SLinus Torvalds /* 9111da177e4SLinus Torvalds * Potentially lost SEQINT. 9121da177e4SLinus Torvalds * If SEQINTCODE is non-zero, 9131da177e4SLinus Torvalds * simulate the SEQINT. 9141da177e4SLinus Torvalds */ 9151da177e4SLinus Torvalds if (ahd_inb(ahd, SEQINTCODE) != NO_SEQINT) 9161da177e4SLinus Torvalds intstat |= SEQINT; 9171da177e4SLinus Torvalds } 9181da177e4SLinus Torvalds } else { 9191da177e4SLinus Torvalds ahd_flush_device_writes(ahd); 9201da177e4SLinus Torvalds } 9211da177e4SLinus Torvalds ahd_run_qoutfifo(ahd); 9221da177e4SLinus Torvalds ahd->cmdcmplt_counts[ahd->cmdcmplt_bucket]++; 9231da177e4SLinus Torvalds ahd->cmdcmplt_total++; 9241da177e4SLinus Torvalds #ifdef AHD_TARGET_MODE 9251da177e4SLinus Torvalds if ((ahd->flags & AHD_TARGETROLE) != 0) 9261da177e4SLinus Torvalds ahd_run_tqinfifo(ahd, /*paused*/FALSE); 9271da177e4SLinus Torvalds #endif 9281da177e4SLinus Torvalds } 9291da177e4SLinus Torvalds 9301da177e4SLinus Torvalds /* 9311da177e4SLinus Torvalds * Handle statuses that may invalidate our cached 9321da177e4SLinus Torvalds * copy of INTSTAT separately. 9331da177e4SLinus Torvalds */ 9341da177e4SLinus Torvalds if (intstat == 0xFF && (ahd->features & AHD_REMOVABLE) != 0) { 9351da177e4SLinus Torvalds /* Hot eject. Do nothing */ 9361da177e4SLinus Torvalds } else if (intstat & HWERRINT) { 9371da177e4SLinus Torvalds ahd_handle_hwerrint(ahd); 9381da177e4SLinus Torvalds } else if ((intstat & (PCIINT|SPLTINT)) != 0) { 9391da177e4SLinus Torvalds ahd->bus_intr(ahd); 9401da177e4SLinus Torvalds } else { 9411da177e4SLinus Torvalds 9421da177e4SLinus Torvalds if ((intstat & SEQINT) != 0) 9431da177e4SLinus Torvalds ahd_handle_seqint(ahd, intstat); 9441da177e4SLinus Torvalds 9451da177e4SLinus Torvalds if ((intstat & SCSIINT) != 0) 9461da177e4SLinus Torvalds ahd_handle_scsiint(ahd, intstat); 9471da177e4SLinus Torvalds } 9481da177e4SLinus Torvalds return (1); 9491da177e4SLinus Torvalds } 9501da177e4SLinus Torvalds 9511da177e4SLinus Torvalds #endif /* _AIC79XX_INLINE_H_ */ 952