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