1139749Simp/*- 265942Sgibbs * Inline routines shareable across OS platforms. 365942Sgibbs * 471717Sgibbs * Copyright (c) 1994-2001 Justin T. Gibbs. 595378Sgibbs * Copyright (c) 2000-2001 Adaptec Inc. 665942Sgibbs * All rights reserved. 765942Sgibbs * 865942Sgibbs * Redistribution and use in source and binary forms, with or without 965942Sgibbs * modification, are permitted provided that the following conditions 1065942Sgibbs * are met: 1165942Sgibbs * 1. Redistributions of source code must retain the above copyright 1265942Sgibbs * notice, this list of conditions, and the following disclaimer, 1365942Sgibbs * without modification. 1495378Sgibbs * 2. Redistributions in binary form must reproduce at minimum a disclaimer 1595378Sgibbs * substantially similar to the "NO WARRANTY" disclaimer below 1695378Sgibbs * ("Disclaimer") and any redistribution must be conditioned upon 1795378Sgibbs * including a substantially similar Disclaimer requirement for further 1895378Sgibbs * binary redistribution. 1995378Sgibbs * 3. Neither the names of the above-listed copyright holders nor the names 2095378Sgibbs * of any contributors may be used to endorse or promote products derived 2195378Sgibbs * from this software without specific prior written permission. 2265942Sgibbs * 2365942Sgibbs * Alternatively, this software may be distributed under the terms of the 2495378Sgibbs * GNU General Public License ("GPL") version 2 as published by the Free 2595378Sgibbs * Software Foundation. 2665942Sgibbs * 2795378Sgibbs * NO WARRANTY 2895378Sgibbs * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2995378Sgibbs * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3095378Sgibbs * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 3195378Sgibbs * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3295378Sgibbs * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3365942Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3465942Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3595378Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 3695378Sgibbs * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 3795378Sgibbs * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3895378Sgibbs * POSSIBILITY OF SUCH DAMAGES. 3965942Sgibbs * 40123579Sgibbs * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_inline.h#47 $ 4165942Sgibbs * 4265942Sgibbs * $FreeBSD$ 4365942Sgibbs */ 4465942Sgibbs 4565942Sgibbs#ifndef _AIC7XXX_INLINE_H_ 4665942Sgibbs#define _AIC7XXX_INLINE_H_ 4765942Sgibbs 4865942Sgibbs/************************* Sequencer Execution Control ************************/ 4979874Sgibbsstatic __inline void ahc_pause_bug_fix(struct ahc_softc *ahc); 5074094Sgibbsstatic __inline int ahc_is_paused(struct ahc_softc *ahc); 5174094Sgibbsstatic __inline void ahc_pause(struct ahc_softc *ahc); 5274094Sgibbsstatic __inline void ahc_unpause(struct ahc_softc *ahc); 5365942Sgibbs 5465942Sgibbs/* 5565942Sgibbs * Work around any chip bugs related to halting sequencer execution. 5665942Sgibbs * On Ultra2 controllers, we must clear the CIOBUS stretch signal by 5765942Sgibbs * reading a register that will set this signal and deassert it. 5865942Sgibbs * Without this workaround, if the chip is paused, by an interrupt or 5965942Sgibbs * manual pause while accessing scb ram, accesses to certain registers 6065942Sgibbs * will hang the system (infinite pci retries). 6165942Sgibbs */ 6265942Sgibbsstatic __inline void 6365942Sgibbsahc_pause_bug_fix(struct ahc_softc *ahc) 6465942Sgibbs{ 6565942Sgibbs if ((ahc->features & AHC_ULTRA2) != 0) 6665942Sgibbs (void)ahc_inb(ahc, CCSCBCTL); 6765942Sgibbs} 6865942Sgibbs 6965942Sgibbs/* 7065942Sgibbs * Determine whether the sequencer has halted code execution. 7165942Sgibbs * Returns non-zero status if the sequencer is stopped. 7265942Sgibbs */ 7365942Sgibbsstatic __inline int 7474094Sgibbsahc_is_paused(struct ahc_softc *ahc) 7565942Sgibbs{ 7665942Sgibbs return ((ahc_inb(ahc, HCNTRL) & PAUSE) != 0); 7765942Sgibbs} 7865942Sgibbs 7965942Sgibbs/* 8065942Sgibbs * Request that the sequencer stop and wait, indefinitely, for it 8165942Sgibbs * to stop. The sequencer will only acknowledge that it is paused 8265942Sgibbs * once it has reached an instruction boundary and PAUSEDIS is 8365942Sgibbs * cleared in the SEQCTL register. The sequencer may use PAUSEDIS 8465942Sgibbs * for critical sections. 8565942Sgibbs */ 8665942Sgibbsstatic __inline void 8774094Sgibbsahc_pause(struct ahc_softc *ahc) 8865942Sgibbs{ 8965942Sgibbs ahc_outb(ahc, HCNTRL, ahc->pause); 9065942Sgibbs 9165942Sgibbs /* 9265942Sgibbs * Since the sequencer can disable pausing in a critical section, we 9365942Sgibbs * must loop until it actually stops. 9465942Sgibbs */ 9574094Sgibbs while (ahc_is_paused(ahc) == 0) 9665942Sgibbs ; 9765942Sgibbs 9865942Sgibbs ahc_pause_bug_fix(ahc); 9965942Sgibbs} 10065942Sgibbs 10165942Sgibbs/* 10265942Sgibbs * Allow the sequencer to continue program execution. 10365942Sgibbs * We check here to ensure that no additional interrupt 10465942Sgibbs * sources that would cause the sequencer to halt have been 10565942Sgibbs * asserted. If, for example, a SCSI bus reset is detected 10665942Sgibbs * while we are fielding a different, pausing, interrupt type, 10765942Sgibbs * we don't want to release the sequencer before going back 10865942Sgibbs * into our interrupt handler and dealing with this new 10965942Sgibbs * condition. 11065942Sgibbs */ 11165942Sgibbsstatic __inline void 11274094Sgibbsahc_unpause(struct ahc_softc *ahc) 11365942Sgibbs{ 11465942Sgibbs if ((ahc_inb(ahc, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0) 11565942Sgibbs ahc_outb(ahc, HCNTRL, ahc->unpause); 11665942Sgibbs} 11765942Sgibbs 11865942Sgibbs/*********************** Untagged Transaction Routines ************************/ 11965942Sgibbsstatic __inline void ahc_freeze_untagged_queues(struct ahc_softc *ahc); 12065942Sgibbsstatic __inline void ahc_release_untagged_queues(struct ahc_softc *ahc); 12165942Sgibbs 12265942Sgibbs/* 12365942Sgibbs * Block our completion routine from starting the next untagged 12465942Sgibbs * transaction for this target or target lun. 12565942Sgibbs */ 12665942Sgibbsstatic __inline void 12765942Sgibbsahc_freeze_untagged_queues(struct ahc_softc *ahc) 12865942Sgibbs{ 12971390Sgibbs if ((ahc->flags & AHC_SCB_BTT) == 0) 13065942Sgibbs ahc->untagged_queue_lock++; 13165942Sgibbs} 13265942Sgibbs 13365942Sgibbs/* 13465942Sgibbs * Allow the next untagged transaction for this target or target lun 13565942Sgibbs * to be executed. We use a counting semaphore to allow the lock 13665942Sgibbs * to be acquired recursively. Once the count drops to zero, the 13765942Sgibbs * transaction queues will be run. 13865942Sgibbs */ 13965942Sgibbsstatic __inline void 14065942Sgibbsahc_release_untagged_queues(struct ahc_softc *ahc) 14165942Sgibbs{ 14271390Sgibbs if ((ahc->flags & AHC_SCB_BTT) == 0) { 14365942Sgibbs ahc->untagged_queue_lock--; 14465942Sgibbs if (ahc->untagged_queue_lock == 0) 14565942Sgibbs ahc_run_untagged_queues(ahc); 14665942Sgibbs } 14765942Sgibbs} 14865942Sgibbs 14965942Sgibbs/************************** Memory mapping routines ***************************/ 15065942Sgibbsstatic __inline struct ahc_dma_seg * 15165942Sgibbs ahc_sg_bus_to_virt(struct scb *scb, 15265942Sgibbs uint32_t sg_busaddr); 15365942Sgibbsstatic __inline uint32_t 15465942Sgibbs ahc_sg_virt_to_bus(struct scb *scb, 15565942Sgibbs struct ahc_dma_seg *sg); 15665942Sgibbsstatic __inline uint32_t 15765942Sgibbs ahc_hscb_busaddr(struct ahc_softc *ahc, u_int index); 15879874Sgibbsstatic __inline void ahc_sync_scb(struct ahc_softc *ahc, 15979874Sgibbs struct scb *scb, int op); 16079874Sgibbsstatic __inline void ahc_sync_sglist(struct ahc_softc *ahc, 16179874Sgibbs struct scb *scb, int op); 16279874Sgibbsstatic __inline uint32_t 16379874Sgibbs ahc_targetcmd_offset(struct ahc_softc *ahc, 16479874Sgibbs u_int index); 16565942Sgibbs 16665942Sgibbsstatic __inline struct ahc_dma_seg * 16765942Sgibbsahc_sg_bus_to_virt(struct scb *scb, uint32_t sg_busaddr) 16865942Sgibbs{ 16965942Sgibbs int sg_index; 17065942Sgibbs 17165942Sgibbs sg_index = (sg_busaddr - scb->sg_list_phys)/sizeof(struct ahc_dma_seg); 17265942Sgibbs /* sg_list_phys points to entry 1, not 0 */ 17365942Sgibbs sg_index++; 17465942Sgibbs 17565942Sgibbs return (&scb->sg_list[sg_index]); 17665942Sgibbs} 17765942Sgibbs 17865942Sgibbsstatic __inline uint32_t 17965942Sgibbsahc_sg_virt_to_bus(struct scb *scb, struct ahc_dma_seg *sg) 18065942Sgibbs{ 18165942Sgibbs int sg_index; 18265942Sgibbs 18365942Sgibbs /* sg_list_phys points to entry 1, not 0 */ 18465942Sgibbs sg_index = sg - &scb->sg_list[1]; 18565942Sgibbs 18665942Sgibbs return (scb->sg_list_phys + (sg_index * sizeof(*scb->sg_list))); 18765942Sgibbs} 18865942Sgibbs 18965942Sgibbsstatic __inline uint32_t 19065942Sgibbsahc_hscb_busaddr(struct ahc_softc *ahc, u_int index) 19165942Sgibbs{ 19265942Sgibbs return (ahc->scb_data->hscb_busaddr 19365942Sgibbs + (sizeof(struct hardware_scb) * index)); 19465942Sgibbs} 19565942Sgibbs 19679874Sgibbsstatic __inline void 19779874Sgibbsahc_sync_scb(struct ahc_softc *ahc, struct scb *scb, int op) 19879874Sgibbs{ 199123579Sgibbs aic_dmamap_sync(ahc, ahc->scb_data->hscb_dmat, 20079874Sgibbs ahc->scb_data->hscb_dmamap, 20179874Sgibbs /*offset*/(scb->hscb - ahc->hscbs) * sizeof(*scb->hscb), 20279874Sgibbs /*len*/sizeof(*scb->hscb), op); 20379874Sgibbs} 20479874Sgibbs 20579874Sgibbsstatic __inline void 20679874Sgibbsahc_sync_sglist(struct ahc_softc *ahc, struct scb *scb, int op) 20779874Sgibbs{ 20879874Sgibbs if (scb->sg_count == 0) 20979874Sgibbs return; 21079874Sgibbs 211123579Sgibbs aic_dmamap_sync(ahc, ahc->scb_data->sg_dmat, scb->sg_map->sg_dmamap, 21279874Sgibbs /*offset*/(scb->sg_list - scb->sg_map->sg_vaddr) 21379874Sgibbs * sizeof(struct ahc_dma_seg), 21479874Sgibbs /*len*/sizeof(struct ahc_dma_seg) * scb->sg_count, op); 21579874Sgibbs} 21679874Sgibbs 21779874Sgibbsstatic __inline uint32_t 21879874Sgibbsahc_targetcmd_offset(struct ahc_softc *ahc, u_int index) 21979874Sgibbs{ 22079874Sgibbs return (((uint8_t *)&ahc->targetcmds[index]) - ahc->qoutfifo); 22179874Sgibbs} 22279874Sgibbs 22365942Sgibbs/******************************** Debugging ***********************************/ 22465942Sgibbsstatic __inline char *ahc_name(struct ahc_softc *ahc); 22565942Sgibbs 22665942Sgibbsstatic __inline char * 22765942Sgibbsahc_name(struct ahc_softc *ahc) 22865942Sgibbs{ 22965942Sgibbs return (ahc->name); 23065942Sgibbs} 23165942Sgibbs 23265942Sgibbs/*********************** Miscelaneous Support Functions ***********************/ 23365942Sgibbs 23495378Sgibbsstatic __inline void ahc_update_residual(struct ahc_softc *ahc, 23595378Sgibbs struct scb *scb); 23665942Sgibbsstatic __inline struct ahc_initiator_tinfo * 23765942Sgibbs ahc_fetch_transinfo(struct ahc_softc *ahc, 23865942Sgibbs char channel, u_int our_id, 23965942Sgibbs u_int remote_id, 24074972Sgibbs struct ahc_tmode_tstate **tstate); 241109590Sgibbsstatic __inline uint16_t 242109590Sgibbs ahc_inw(struct ahc_softc *ahc, u_int port); 243109590Sgibbsstatic __inline void ahc_outw(struct ahc_softc *ahc, u_int port, 244109590Sgibbs u_int value); 245109590Sgibbsstatic __inline uint32_t 246109590Sgibbs ahc_inl(struct ahc_softc *ahc, u_int port); 247109590Sgibbsstatic __inline void ahc_outl(struct ahc_softc *ahc, u_int port, 248109590Sgibbs uint32_t value); 249109590Sgibbsstatic __inline uint64_t 250109590Sgibbs ahc_inq(struct ahc_softc *ahc, u_int port); 251109590Sgibbsstatic __inline void ahc_outq(struct ahc_softc *ahc, u_int port, 252109590Sgibbs uint64_t value); 25365942Sgibbsstatic __inline struct scb* 25465942Sgibbs ahc_get_scb(struct ahc_softc *ahc); 25565942Sgibbsstatic __inline void ahc_free_scb(struct ahc_softc *ahc, struct scb *scb); 25668402Sgibbsstatic __inline void ahc_swap_with_next_hscb(struct ahc_softc *ahc, 25768402Sgibbs struct scb *scb); 25865942Sgibbsstatic __inline void ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb); 25970807Sgibbsstatic __inline struct scsi_sense_data * 26070807Sgibbs ahc_get_sense_buf(struct ahc_softc *ahc, 26170807Sgibbs struct scb *scb); 26270807Sgibbsstatic __inline uint32_t 26370807Sgibbs ahc_get_sense_bufaddr(struct ahc_softc *ahc, 26470807Sgibbs struct scb *scb); 26565942Sgibbs 26665942Sgibbs/* 26765942Sgibbs * Determine whether the sequencer reported a residual 26865942Sgibbs * for this SCB/transaction. 26965942Sgibbs */ 27076634Sgibbsstatic __inline void 27195378Sgibbsahc_update_residual(struct ahc_softc *ahc, struct scb *scb) 27265942Sgibbs{ 27376634Sgibbs uint32_t sgptr; 27465942Sgibbs 275123579Sgibbs sgptr = aic_le32toh(scb->hscb->sgptr); 27676634Sgibbs if ((sgptr & SG_RESID_VALID) != 0) 27795378Sgibbs ahc_calc_residual(ahc, scb); 27865942Sgibbs} 27965942Sgibbs 28065942Sgibbs/* 28165942Sgibbs * Return pointers to the transfer negotiation information 28265942Sgibbs * for the specified our_id/remote_id pair. 28365942Sgibbs */ 28465942Sgibbsstatic __inline struct ahc_initiator_tinfo * 28565942Sgibbsahc_fetch_transinfo(struct ahc_softc *ahc, char channel, u_int our_id, 28674972Sgibbs u_int remote_id, struct ahc_tmode_tstate **tstate) 28765942Sgibbs{ 28865942Sgibbs /* 28965942Sgibbs * Transfer data structures are stored from the perspective 29065942Sgibbs * of the target role. Since the parameters for a connection 29165942Sgibbs * in the initiator role to a given target are the same as 29265942Sgibbs * when the roles are reversed, we pretend we are the target. 29365942Sgibbs */ 29465942Sgibbs if (channel == 'B') 29565942Sgibbs our_id += 8; 29665942Sgibbs *tstate = ahc->enabled_targets[our_id]; 29765942Sgibbs return (&(*tstate)->transinfo[remote_id]); 29865942Sgibbs} 29965942Sgibbs 300109590Sgibbsstatic __inline uint16_t 301109590Sgibbsahc_inw(struct ahc_softc *ahc, u_int port) 302109590Sgibbs{ 303109590Sgibbs return ((ahc_inb(ahc, port+1) << 8) | ahc_inb(ahc, port)); 304109590Sgibbs} 305109590Sgibbs 306109590Sgibbsstatic __inline void 307109590Sgibbsahc_outw(struct ahc_softc *ahc, u_int port, u_int value) 308109590Sgibbs{ 309109590Sgibbs ahc_outb(ahc, port, value & 0xFF); 310109590Sgibbs ahc_outb(ahc, port+1, (value >> 8) & 0xFF); 311109590Sgibbs} 312109590Sgibbs 313109590Sgibbsstatic __inline uint32_t 314109590Sgibbsahc_inl(struct ahc_softc *ahc, u_int port) 315109590Sgibbs{ 316109590Sgibbs return ((ahc_inb(ahc, port)) 317109590Sgibbs | (ahc_inb(ahc, port+1) << 8) 318109590Sgibbs | (ahc_inb(ahc, port+2) << 16) 319109590Sgibbs | (ahc_inb(ahc, port+3) << 24)); 320109590Sgibbs} 321109590Sgibbs 322109590Sgibbsstatic __inline void 323109590Sgibbsahc_outl(struct ahc_softc *ahc, u_int port, uint32_t value) 324109590Sgibbs{ 325109590Sgibbs ahc_outb(ahc, port, (value) & 0xFF); 326109590Sgibbs ahc_outb(ahc, port+1, ((value) >> 8) & 0xFF); 327109590Sgibbs ahc_outb(ahc, port+2, ((value) >> 16) & 0xFF); 328109590Sgibbs ahc_outb(ahc, port+3, ((value) >> 24) & 0xFF); 329109590Sgibbs} 330109590Sgibbs 331109590Sgibbsstatic __inline uint64_t 332109590Sgibbsahc_inq(struct ahc_softc *ahc, u_int port) 333109590Sgibbs{ 334109590Sgibbs return ((ahc_inb(ahc, port)) 335109590Sgibbs | (ahc_inb(ahc, port+1) << 8) 336109590Sgibbs | (ahc_inb(ahc, port+2) << 16) 337109590Sgibbs | (ahc_inb(ahc, port+3) << 24) 338109590Sgibbs | (((uint64_t)ahc_inb(ahc, port+4)) << 32) 339109590Sgibbs | (((uint64_t)ahc_inb(ahc, port+5)) << 40) 340109590Sgibbs | (((uint64_t)ahc_inb(ahc, port+6)) << 48) 341109590Sgibbs | (((uint64_t)ahc_inb(ahc, port+7)) << 56)); 342109590Sgibbs} 343109590Sgibbs 344109590Sgibbsstatic __inline void 345109590Sgibbsahc_outq(struct ahc_softc *ahc, u_int port, uint64_t value) 346109590Sgibbs{ 347109590Sgibbs ahc_outb(ahc, port, value & 0xFF); 348109590Sgibbs ahc_outb(ahc, port+1, (value >> 8) & 0xFF); 349109590Sgibbs ahc_outb(ahc, port+2, (value >> 16) & 0xFF); 350109590Sgibbs ahc_outb(ahc, port+3, (value >> 24) & 0xFF); 351109590Sgibbs ahc_outb(ahc, port+4, (value >> 32) & 0xFF); 352109590Sgibbs ahc_outb(ahc, port+5, (value >> 40) & 0xFF); 353109590Sgibbs ahc_outb(ahc, port+6, (value >> 48) & 0xFF); 354109590Sgibbs ahc_outb(ahc, port+7, (value >> 56) & 0xFF); 355109590Sgibbs} 356109590Sgibbs 35765942Sgibbs/* 35865942Sgibbs * Get a free scb. If there are none, see if we can allocate a new SCB. 35965942Sgibbs */ 36065942Sgibbsstatic __inline struct scb * 36165942Sgibbsahc_get_scb(struct ahc_softc *ahc) 36265942Sgibbs{ 36366647Sgibbs struct scb *scb; 36465942Sgibbs 36566647Sgibbs if ((scb = SLIST_FIRST(&ahc->scb_data->free_scbs)) == NULL) { 366168873Sscottl if (ahc_alloc_scbs(ahc) == 0) 367168873Sscottl return (NULL); 36866647Sgibbs scb = SLIST_FIRST(&ahc->scb_data->free_scbs); 36966647Sgibbs if (scb == NULL) 37066647Sgibbs return (NULL); 37165942Sgibbs } 37266647Sgibbs SLIST_REMOVE_HEAD(&ahc->scb_data->free_scbs, links.sle); 37366647Sgibbs return (scb); 37465942Sgibbs} 37565942Sgibbs 37665942Sgibbs/* 37765942Sgibbs * Return an SCB resource to the free list. 37865942Sgibbs */ 37965942Sgibbsstatic __inline void 38065942Sgibbsahc_free_scb(struct ahc_softc *ahc, struct scb *scb) 38165942Sgibbs{ 38265942Sgibbs struct hardware_scb *hscb; 38365942Sgibbs 38465942Sgibbs hscb = scb->hscb; 38565942Sgibbs /* Clean up for the next user */ 38666647Sgibbs ahc->scb_data->scbindex[hscb->tag] = NULL; 387123579Sgibbs scb->flags = SCB_FLAG_NONE; 38865942Sgibbs hscb->control = 0; 38965942Sgibbs 39065942Sgibbs SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs, scb, links.sle); 39166647Sgibbs 39266647Sgibbs /* Notify the OSM that a resource is now available. */ 393123579Sgibbs aic_platform_scb_free(ahc, scb); 39465942Sgibbs} 39565942Sgibbs 39666647Sgibbsstatic __inline struct scb * 39766647Sgibbsahc_lookup_scb(struct ahc_softc *ahc, u_int tag) 39866647Sgibbs{ 39979874Sgibbs struct scb* scb; 40066647Sgibbs 40179874Sgibbs scb = ahc->scb_data->scbindex[tag]; 40279874Sgibbs if (scb != NULL) 40379874Sgibbs ahc_sync_scb(ahc, scb, 40479874Sgibbs BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 40579874Sgibbs return (scb); 40666647Sgibbs} 40766647Sgibbs 40865942Sgibbsstatic __inline void 40968402Sgibbsahc_swap_with_next_hscb(struct ahc_softc *ahc, struct scb *scb) 41065942Sgibbs{ 41166647Sgibbs struct hardware_scb *q_hscb; 41266647Sgibbs u_int saved_tag; 41366647Sgibbs 41466647Sgibbs /* 41566647Sgibbs * Our queuing method is a bit tricky. The card 41666647Sgibbs * knows in advance which HSCB to download, and we 41766647Sgibbs * can't disappoint it. To achieve this, the next 41866647Sgibbs * SCB to download is saved off in ahc->next_queued_scb. 41966647Sgibbs * When we are called to queue "an arbitrary scb", 42066647Sgibbs * we copy the contents of the incoming HSCB to the one 42166647Sgibbs * the sequencer knows about, swap HSCB pointers and 42268402Sgibbs * finally assign the SCB to the tag indexed location 42366647Sgibbs * in the scb_array. This makes sure that we can still 42466647Sgibbs * locate the correct SCB by SCB_TAG. 42566647Sgibbs */ 42666647Sgibbs q_hscb = ahc->next_queued_scb->hscb; 42766647Sgibbs saved_tag = q_hscb->tag; 42867019Sgibbs memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb)); 42968087Sgibbs if ((scb->flags & SCB_CDB32_PTR) != 0) { 43068087Sgibbs q_hscb->shared_data.cdb_ptr = 431123579Sgibbs aic_htole32(ahc_hscb_busaddr(ahc, q_hscb->tag) 43295378Sgibbs + offsetof(struct hardware_scb, cdb32)); 43368087Sgibbs } 43466647Sgibbs q_hscb->tag = saved_tag; 43566647Sgibbs q_hscb->next = scb->hscb->tag; 43666647Sgibbs 43766647Sgibbs /* Now swap HSCB pointers. */ 43866647Sgibbs ahc->next_queued_scb->hscb = scb->hscb; 43966647Sgibbs scb->hscb = q_hscb; 44066647Sgibbs 44166647Sgibbs /* Now define the mapping from tag to SCB in the scbindex */ 44266647Sgibbs ahc->scb_data->scbindex[scb->hscb->tag] = scb; 44368402Sgibbs} 44466647Sgibbs 44568402Sgibbs/* 44668402Sgibbs * Tell the sequencer about a new transaction to execute. 44768402Sgibbs */ 44868402Sgibbsstatic __inline void 44968402Sgibbsahc_queue_scb(struct ahc_softc *ahc, struct scb *scb) 45068402Sgibbs{ 45168402Sgibbs ahc_swap_with_next_hscb(ahc, scb); 45268402Sgibbs 45368087Sgibbs if (scb->hscb->tag == SCB_LIST_NULL 45468087Sgibbs || scb->hscb->next == SCB_LIST_NULL) 45568087Sgibbs panic("Attempt to queue invalid SCB tag %x:%x\n", 45668087Sgibbs scb->hscb->tag, scb->hscb->next); 45768087Sgibbs 45866647Sgibbs /* 459115333Sgibbs * Setup data "oddness". 460115333Sgibbs */ 461115333Sgibbs scb->hscb->lun &= LID; 462123579Sgibbs if (aic_get_transfer_length(scb) & 0x1) 463115333Sgibbs scb->hscb->lun |= SCB_XFERLEN_ODD; 464115333Sgibbs 465115333Sgibbs /* 46666647Sgibbs * Keep a history of SCBs we've downloaded in the qinfifo. 46766647Sgibbs */ 46865942Sgibbs ahc->qinfifo[ahc->qinfifonext++] = scb->hscb->tag; 46979874Sgibbs 47079874Sgibbs /* 471114621Sgibbs * Make sure our data is consistent from the 47279874Sgibbs * perspective of the adapter. 47379874Sgibbs */ 47479874Sgibbs ahc_sync_scb(ahc, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 47579874Sgibbs 47679874Sgibbs /* Tell the adapter about the newly queued SCB */ 47765942Sgibbs if ((ahc->features & AHC_QUEUE_REGS) != 0) { 47865942Sgibbs ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext); 47965942Sgibbs } else { 48065942Sgibbs if ((ahc->features & AHC_AUTOPAUSE) == 0) 48174094Sgibbs ahc_pause(ahc); 48265942Sgibbs ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext); 48365942Sgibbs if ((ahc->features & AHC_AUTOPAUSE) == 0) 48474094Sgibbs ahc_unpause(ahc); 48565942Sgibbs } 48665942Sgibbs} 48765942Sgibbs 48870807Sgibbsstatic __inline struct scsi_sense_data * 48970807Sgibbsahc_get_sense_buf(struct ahc_softc *ahc, struct scb *scb) 49070807Sgibbs{ 49170807Sgibbs int offset; 49270807Sgibbs 49370807Sgibbs offset = scb - ahc->scb_data->scbarray; 49470807Sgibbs return (&ahc->scb_data->sense[offset]); 49570807Sgibbs} 49670807Sgibbs 49770807Sgibbsstatic __inline uint32_t 49870807Sgibbsahc_get_sense_bufaddr(struct ahc_softc *ahc, struct scb *scb) 49970807Sgibbs{ 50070807Sgibbs int offset; 50170807Sgibbs 50270807Sgibbs offset = scb - ahc->scb_data->scbarray; 50370807Sgibbs return (ahc->scb_data->sense_busaddr 50470807Sgibbs + (offset * sizeof(struct scsi_sense_data))); 50570807Sgibbs} 50670807Sgibbs 50765942Sgibbs/************************** Interrupt Processing ******************************/ 50879874Sgibbsstatic __inline void ahc_sync_qoutfifo(struct ahc_softc *ahc, int op); 50979874Sgibbsstatic __inline void ahc_sync_tqinfifo(struct ahc_softc *ahc, int op); 51079874Sgibbsstatic __inline u_int ahc_check_cmdcmpltqueues(struct ahc_softc *ahc); 511114621Sgibbsstatic __inline int ahc_intr(struct ahc_softc *ahc); 51265942Sgibbs 51379874Sgibbsstatic __inline void 51479874Sgibbsahc_sync_qoutfifo(struct ahc_softc *ahc, int op) 51579874Sgibbs{ 516123579Sgibbs aic_dmamap_sync(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap, 51779874Sgibbs /*offset*/0, /*len*/256, op); 51879874Sgibbs} 51979874Sgibbs 52079874Sgibbsstatic __inline void 52179874Sgibbsahc_sync_tqinfifo(struct ahc_softc *ahc, int op) 52279874Sgibbs{ 52379874Sgibbs#ifdef AHC_TARGET_MODE 52479874Sgibbs if ((ahc->flags & AHC_TARGETROLE) != 0) { 525123579Sgibbs aic_dmamap_sync(ahc, ahc->shared_data_dmat, 52679874Sgibbs ahc->shared_data_dmamap, 52779874Sgibbs ahc_targetcmd_offset(ahc, 0), 52879874Sgibbs sizeof(struct target_cmd) * AHC_TMODE_CMDS, 52979874Sgibbs op); 53079874Sgibbs } 53179874Sgibbs#endif 53279874Sgibbs} 53379874Sgibbs 53465942Sgibbs/* 53570204Sgibbs * See if the firmware has posted any completed commands 53670204Sgibbs * into our in-core command complete fifos. 53770204Sgibbs */ 53870204Sgibbs#define AHC_RUN_QOUTFIFO 0x1 53970204Sgibbs#define AHC_RUN_TQINFIFO 0x2 54070204Sgibbsstatic __inline u_int 54170204Sgibbsahc_check_cmdcmpltqueues(struct ahc_softc *ahc) 54270204Sgibbs{ 54370204Sgibbs u_int retval; 54470204Sgibbs 54570204Sgibbs retval = 0; 546123579Sgibbs aic_dmamap_sync(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap, 54779874Sgibbs /*offset*/ahc->qoutfifonext, /*len*/1, 54879874Sgibbs BUS_DMASYNC_POSTREAD); 54970204Sgibbs if (ahc->qoutfifo[ahc->qoutfifonext] != SCB_LIST_NULL) 55070204Sgibbs retval |= AHC_RUN_QOUTFIFO; 55170204Sgibbs#ifdef AHC_TARGET_MODE 55295378Sgibbs if ((ahc->flags & AHC_TARGETROLE) != 0 55395378Sgibbs && (ahc->flags & AHC_TQINFIFO_BLOCKED) == 0) { 554123579Sgibbs aic_dmamap_sync(ahc, ahc->shared_data_dmat, 55579874Sgibbs ahc->shared_data_dmamap, 55679874Sgibbs ahc_targetcmd_offset(ahc, ahc->tqinfifofnext), 55779874Sgibbs /*len*/sizeof(struct target_cmd), 55879874Sgibbs BUS_DMASYNC_POSTREAD); 55979874Sgibbs if (ahc->targetcmds[ahc->tqinfifonext].cmd_valid != 0) 56079874Sgibbs retval |= AHC_RUN_TQINFIFO; 56179874Sgibbs } 56270204Sgibbs#endif 56370204Sgibbs return (retval); 56470204Sgibbs} 56570204Sgibbs 56670204Sgibbs/* 56765942Sgibbs * Catch an interrupt from the adapter 56865942Sgibbs */ 569114621Sgibbsstatic __inline int 57065942Sgibbsahc_intr(struct ahc_softc *ahc) 57165942Sgibbs{ 57265942Sgibbs u_int intstat; 57365942Sgibbs 574102678Sgibbs if ((ahc->pause & INTEN) == 0) { 575102678Sgibbs /* 576102678Sgibbs * Our interrupt is not enabled on the chip 577102678Sgibbs * and may be disabled for re-entrancy reasons, 578102678Sgibbs * so just return. This is likely just a shared 579102678Sgibbs * interrupt. 580102678Sgibbs */ 581114621Sgibbs return (0); 582102678Sgibbs } 58365942Sgibbs /* 58470204Sgibbs * Instead of directly reading the interrupt status register, 58570204Sgibbs * infer the cause of the interrupt by checking our in-core 58670204Sgibbs * completion queues. This avoids a costly PCI bus read in 58770204Sgibbs * most cases. 58865942Sgibbs */ 58974094Sgibbs if ((ahc->flags & (AHC_ALL_INTERRUPTS|AHC_EDGE_INTERRUPT)) == 0 59095378Sgibbs && (ahc_check_cmdcmpltqueues(ahc) != 0)) 59170204Sgibbs intstat = CMDCMPLT; 59274094Sgibbs else { 59370204Sgibbs intstat = ahc_inb(ahc, INTSTAT); 59470204Sgibbs } 59570204Sgibbs 596114621Sgibbs if ((intstat & INT_PEND) == 0) { 597123579Sgibbs#if AIC_PCI_CONFIG > 0 598114621Sgibbs if (ahc->unsolicited_ints > 500) { 599114621Sgibbs ahc->unsolicited_ints = 0; 600114621Sgibbs if ((ahc->chip & AHC_PCI) != 0 601114621Sgibbs && (ahc_inb(ahc, ERROR) & PCIERRSTAT) != 0) 602114621Sgibbs ahc->bus_intr(ahc); 603114621Sgibbs } 604114621Sgibbs#endif 605114621Sgibbs ahc->unsolicited_ints++; 606114621Sgibbs return (0); 607114621Sgibbs } 608114621Sgibbs ahc->unsolicited_ints = 0; 609114621Sgibbs 61065942Sgibbs if (intstat & CMDCMPLT) { 61165942Sgibbs ahc_outb(ahc, CLRINT, CLRCMDINT); 61270204Sgibbs 61365942Sgibbs /* 61465942Sgibbs * Ensure that the chip sees that we've cleared 61565942Sgibbs * this interrupt before we walk the output fifo. 61665942Sgibbs * Otherwise, we may, due to posted bus writes, 61765942Sgibbs * clear the interrupt after we finish the scan, 61865942Sgibbs * and after the sequencer has added new entries 61965942Sgibbs * and asserted the interrupt again. 62065942Sgibbs */ 62165942Sgibbs ahc_flush_device_writes(ahc); 62295378Sgibbs ahc_run_qoutfifo(ahc); 62365942Sgibbs#ifdef AHC_TARGET_MODE 62495378Sgibbs if ((ahc->flags & AHC_TARGETROLE) != 0) 62565942Sgibbs ahc_run_tqinfifo(ahc, /*paused*/FALSE); 62665942Sgibbs#endif 62765942Sgibbs } 62879874Sgibbs 629114621Sgibbs /* 630114621Sgibbs * Handle statuses that may invalidate our cached 631114621Sgibbs * copy of INTSTAT separately. 632114621Sgibbs */ 633114621Sgibbs if (intstat == 0xFF && (ahc->features & AHC_REMOVABLE) != 0) { 634114621Sgibbs /* Hot eject. Do nothing */ 635114621Sgibbs } else if (intstat & BRKADRINT) { 63665942Sgibbs ahc_handle_brkadrint(ahc); 637114621Sgibbs } else if ((intstat & (SEQINT|SCSIINT)) != 0) { 63865942Sgibbs 63965942Sgibbs ahc_pause_bug_fix(ahc); 64065942Sgibbs 641114621Sgibbs if ((intstat & SEQINT) != 0) 642114621Sgibbs ahc_handle_seqint(ahc, intstat); 64365942Sgibbs 644114621Sgibbs if ((intstat & SCSIINT) != 0) 645114621Sgibbs ahc_handle_scsiint(ahc, intstat); 646114621Sgibbs } 647114621Sgibbs return (1); 64865942Sgibbs} 64965942Sgibbs 65065942Sgibbs#endif /* _AIC7XXX_INLINE_H_ */ 651