linux-old/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#50 $
  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, bus_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, bus_addr_t addr, bus_size_t len, int last)
 246{
 247        scb->sg_count++;
 248        if (sizeof(bus_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        bus_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        bus_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 void    ahd_complete_scb(struct ahd_softc *ahd,
 422                                         struct scb *scb);
 423static __inline void    ahd_update_residual(struct ahd_softc *ahd,
 424                                            struct scb *scb);
 425static __inline struct ahd_initiator_tinfo *
 426                        ahd_fetch_transinfo(struct ahd_softc *ahd,
 427                                            char channel, u_int our_id,
 428                                            u_int remote_id,
 429                                            struct ahd_tmode_tstate **tstate);
 430static __inline uint16_t
 431                        ahd_inw(struct ahd_softc *ahd, u_int port);
 432static __inline void    ahd_outw(struct ahd_softc *ahd, u_int port,
 433                                 u_int value);
 434static __inline uint32_t
 435                        ahd_inl(struct ahd_softc *ahd, u_int port);
 436static __inline void    ahd_outl(struct ahd_softc *ahd, u_int port,
 437                                 uint32_t value);
 438static __inline uint64_t
 439                        ahd_inq(struct ahd_softc *ahd, u_int port);
 440static __inline void    ahd_outq(struct ahd_softc *ahd, u_int port,
 441                                 uint64_t value);
 442static __inline u_int   ahd_get_scbptr(struct ahd_softc *ahd);
 443static __inline void    ahd_set_scbptr(struct ahd_softc *ahd, u_int scbptr);
 444static __inline u_int   ahd_get_hnscb_qoff(struct ahd_softc *ahd);
 445static __inline void    ahd_set_hnscb_qoff(struct ahd_softc *ahd, u_int value);
 446static __inline u_int   ahd_get_hescb_qoff(struct ahd_softc *ahd);
 447static __inline void    ahd_set_hescb_qoff(struct ahd_softc *ahd, u_int value);
 448static __inline u_int   ahd_get_snscb_qoff(struct ahd_softc *ahd);
 449static __inline void    ahd_set_snscb_qoff(struct ahd_softc *ahd, u_int value);
 450static __inline u_int   ahd_get_sescb_qoff(struct ahd_softc *ahd);
 451static __inline void    ahd_set_sescb_qoff(struct ahd_softc *ahd, u_int value);
 452static __inline u_int   ahd_get_sdscb_qoff(struct ahd_softc *ahd);
 453static __inline void    ahd_set_sdscb_qoff(struct ahd_softc *ahd, u_int value);
 454static __inline u_int   ahd_inb_scbram(struct ahd_softc *ahd, u_int offset);
 455static __inline u_int   ahd_inw_scbram(struct ahd_softc *ahd, u_int offset);
 456static __inline uint32_t
 457                        ahd_inl_scbram(struct ahd_softc *ahd, u_int offset);
 458static __inline void    ahd_swap_with_next_hscb(struct ahd_softc *ahd,
 459                                                struct scb *scb);
 460static __inline void    ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb);
 461static __inline uint8_t *
 462                        ahd_get_sense_buf(struct ahd_softc *ahd,
 463                                          struct scb *scb);
 464static __inline uint32_t
 465                        ahd_get_sense_bufaddr(struct ahd_softc *ahd,
 466                                              struct scb *scb);
 467
 468static __inline void
 469ahd_complete_scb(struct ahd_softc *ahd, struct scb *scb)
 470{
 471        uint32_t sgptr;
 472
 473        sgptr = ahd_le32toh(scb->hscb->sgptr);
 474        if ((sgptr & SG_STATUS_VALID) != 0)
 475                ahd_handle_scb_status(ahd, scb);
 476        else
 477                ahd_done(ahd, scb);
 478}
 479
 480/*
 481 * Determine whether the sequencer reported a residual
 482 * for this SCB/transaction.
 483 */
 484static __inline void
 485ahd_update_residual(struct ahd_softc *ahd, struct scb *scb)
 486{
 487        uint32_t sgptr;
 488
 489        sgptr = ahd_le32toh(scb->hscb->sgptr);
 490        if ((sgptr & SG_STATUS_VALID) != 0)
 491                ahd_calc_residual(ahd, scb);
 492}
 493
 494/*
 495 * Return pointers to the transfer negotiation information
 496 * for the specified our_id/remote_id pair.
 497 */
 498static __inline struct ahd_initiator_tinfo *
 499ahd_fetch_transinfo(struct ahd_softc *ahd, char channel, u_int our_id,
 500                    u_int remote_id, struct ahd_tmode_tstate **tstate)
 501{
 502        /*
 503         * Transfer data structures are stored from the perspective
 504         * of the target role.  Since the parameters for a connection
 505         * in the initiator role to a given target are the same as
 506         * when the roles are reversed, we pretend we are the target.
 507         */
 508        if (channel == 'B')
 509                our_id += 8;
 510        *tstate = ahd->enabled_targets[our_id];
 511        return (&(*tstate)->transinfo[remote_id]);
 512}
 513
 514#define AHD_COPY_COL_IDX(dst, src)                              \
 515do {                                                            \
 516        dst->hscb->scsiid = src->hscb->scsiid;                  \
 517        dst->hscb->lun = src->hscb->lun;                        \
 518} while (0)
 519
 520static __inline uint16_t
 521ahd_inw(struct ahd_softc *ahd, u_int port)
 522{
 523        return ((ahd_inb(ahd, port+1) << 8) | ahd_inb(ahd, port));
 524}
 525
 526static __inline void
 527ahd_outw(struct ahd_softc *ahd, u_int port, u_int value)
 528{
 529        ahd_outb(ahd, port, value & 0xFF);
 530        ahd_outb(ahd, port+1, (value >> 8) & 0xFF);
 531}
 532
 533static __inline uint32_t
 534ahd_inl(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}
 541
 542static __inline void
 543ahd_outl(struct ahd_softc *ahd, u_int port, uint32_t value)
 544{
 545        ahd_outb(ahd, port, (value) & 0xFF);
 546        ahd_outb(ahd, port+1, ((value) >> 8) & 0xFF);
 547        ahd_outb(ahd, port+2, ((value) >> 16) & 0xFF);
 548        ahd_outb(ahd, port+3, ((value) >> 24) & 0xFF);
 549}
 550
 551static __inline uint64_t
 552ahd_inq(struct ahd_softc *ahd, u_int port)
 553{
 554        return ((ahd_inb(ahd, port))
 555              | (ahd_inb(ahd, port+1) << 8)
 556              | (ahd_inb(ahd, port+2) << 16)
 557              | (ahd_inb(ahd, port+3) << 24)
 558              | (((uint64_t)ahd_inb(ahd, port+4)) << 32)
 559              | (((uint64_t)ahd_inb(ahd, port+5)) << 40)
 560              | (((uint64_t)ahd_inb(ahd, port+6)) << 48)
 561              | (((uint64_t)ahd_inb(ahd, port+7)) << 56));
 562}
 563
 564static __inline void
 565ahd_outq(struct ahd_softc *ahd, u_int port, uint64_t value)
 566{
 567        ahd_outb(ahd, port, value & 0xFF);
 568        ahd_outb(ahd, port+1, (value >> 8) & 0xFF);
 569        ahd_outb(ahd, port+2, (value >> 16) & 0xFF);
 570        ahd_outb(ahd, port+3, (value >> 24) & 0xFF);
 571        ahd_outb(ahd, port+4, (value >> 32) & 0xFF);
 572        ahd_outb(ahd, port+5, (value >> 40) & 0xFF);
 573        ahd_outb(ahd, port+6, (value >> 48) & 0xFF);
 574        ahd_outb(ahd, port+7, (value >> 56) & 0xFF);
 575}
 576
 577static __inline u_int
 578ahd_get_scbptr(struct ahd_softc *ahd)
 579{
 580        AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK),
 581                         ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK));
 582        return (ahd_inb(ahd, SCBPTR) | (ahd_inb(ahd, SCBPTR + 1) << 8));
 583}
 584
 585static __inline void
 586ahd_set_scbptr(struct ahd_softc *ahd, u_int scbptr)
 587{
 588        AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK),
 589                         ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK));
 590        ahd_outb(ahd, SCBPTR, scbptr & 0xFF);
 591        ahd_outb(ahd, SCBPTR+1, (scbptr >> 8) & 0xFF);
 592}
 593
 594static __inline u_int
 595ahd_get_hnscb_qoff(struct ahd_softc *ahd)
 596{
 597        return (ahd_inw_atomic(ahd, HNSCB_QOFF));
 598}
 599
 600static __inline void
 601ahd_set_hnscb_qoff(struct ahd_softc *ahd, u_int value)
 602{
 603        ahd_outw_atomic(ahd, HNSCB_QOFF, value);
 604}
 605
 606static __inline u_int
 607ahd_get_hescb_qoff(struct ahd_softc *ahd)
 608{
 609        return (ahd_inb(ahd, HESCB_QOFF));
 610}
 611
 612static __inline void
 613ahd_set_hescb_qoff(struct ahd_softc *ahd, u_int value)
 614{
 615        ahd_outb(ahd, HESCB_QOFF, value);
 616}
 617
 618static __inline u_int
 619ahd_get_snscb_qoff(struct ahd_softc *ahd)
 620{
 621        u_int oldvalue;
 622
 623        AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
 624        oldvalue = ahd_inw(ahd, SNSCB_QOFF);
 625        ahd_outw(ahd, SNSCB_QOFF, oldvalue);
 626        return (oldvalue);
 627}
 628
 629static __inline void
 630ahd_set_snscb_qoff(struct ahd_softc *ahd, u_int value)
 631{
 632        AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
 633        ahd_outw(ahd, SNSCB_QOFF, value);
 634}
 635
 636static __inline u_int
 637ahd_get_sescb_qoff(struct ahd_softc *ahd)
 638{
 639        AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
 640        return (ahd_inb(ahd, SESCB_QOFF));
 641}
 642
 643static __inline void
 644ahd_set_sescb_qoff(struct ahd_softc *ahd, u_int value)
 645{
 646        AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
 647        ahd_outb(ahd, SESCB_QOFF, value);
 648}
 649
 650static __inline u_int
 651ahd_get_sdscb_qoff(struct ahd_softc *ahd)
 652{
 653        AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
 654        return (ahd_inb(ahd, SDSCB_QOFF) | (ahd_inb(ahd, SDSCB_QOFF + 1) << 8));
 655}
 656
 657static __inline void
 658ahd_set_sdscb_qoff(struct ahd_softc *ahd, u_int value)
 659{
 660        AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
 661        ahd_outb(ahd, SDSCB_QOFF, value & 0xFF);
 662        ahd_outb(ahd, SDSCB_QOFF+1, (value >> 8) & 0xFF);
 663}
 664
 665static __inline u_int
 666ahd_inb_scbram(struct ahd_softc *ahd, u_int offset)
 667{
 668        u_int value;
 669
 670        /*
 671         * Workaround PCI-X Rev A. hardware bug.
 672         * After a host read of SCB memory, the chip
 673         * may become confused into thinking prefetch
 674         * was required.  This starts the discard timer
 675         * running and can cause an unexpected discard
 676         * timer interrupt.  The work around is to read
 677         * a normal register prior to the exhaustion of
 678         * the discard timer.  The mode pointer register
 679         * has no side effects and so serves well for
 680         * this purpose.
 681         *
 682         * Razor #528
 683         */
 684        value = ahd_inb(ahd, offset);
 685        if ((ahd->flags & AHD_PCIX_SCBRAM_RD_BUG) != 0)
 686                ahd_inb(ahd, MODE_PTR);
 687        return (value);
 688}
 689
 690static __inline u_int
 691ahd_inw_scbram(struct ahd_softc *ahd, u_int offset)
 692{
 693        return (ahd_inb_scbram(ahd, offset)
 694              | (ahd_inb_scbram(ahd, offset+1) << 8));
 695}
 696
 697static __inline uint32_t
 698ahd_inl_scbram(struct ahd_softc *ahd, u_int offset)
 699{
 700        return (ahd_inb_scbram(ahd, offset)
 701              | (ahd_inb_scbram(ahd, offset+1) << 8)
 702              | (ahd_inb_scbram(ahd, offset+2) << 16)
 703              | (ahd_inb_scbram(ahd, offset+3) << 24));
 704}
 705
 706static __inline struct scb *
 707ahd_lookup_scb(struct ahd_softc *ahd, u_int tag)
 708{
 709        struct scb* scb;
 710
 711        if (tag >= AHD_SCB_MAX)
 712                return (NULL);
 713        scb = ahd->scb_data.scbindex[tag];
 714        if (scb != NULL)
 715                ahd_sync_scb(ahd, scb,
 716                             BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
 717        return (scb);
 718}
 719
 720static __inline void
 721ahd_swap_with_next_hscb(struct ahd_softc *ahd, struct scb *scb)
 722{
 723        struct hardware_scb *q_hscb;
 724        uint32_t saved_hscb_busaddr;
 725
 726        /*
 727         * Our queuing method is a bit tricky.  The card
 728         * knows in advance which HSCB (by address) to download,
 729         * and we can't disappoint it.  To achieve this, the next
 730         * HSCB to download is saved off in ahd->next_queued_hscb.
 731         * When we are called to queue "an arbitrary scb",
 732         * we copy the contents of the incoming HSCB to the one
 733         * the sequencer knows about, swap HSCB pointers and
 734         * finally assign the SCB to the tag indexed location
 735         * in the scb_array.  This makes sure that we can still
 736         * locate the correct SCB by SCB_TAG.
 737         */
 738        q_hscb = ahd->next_queued_hscb;
 739        saved_hscb_busaddr = q_hscb->hscb_busaddr;
 740        memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb));
 741        q_hscb->hscb_busaddr = saved_hscb_busaddr;
 742        q_hscb->next_hscb_busaddr = scb->hscb->hscb_busaddr;
 743
 744        /* Now swap HSCB pointers. */
 745        ahd->next_queued_hscb = scb->hscb;
 746        scb->hscb = q_hscb;
 747
 748        /* Now define the mapping from tag to SCB in the scbindex */
 749        ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = scb;
 750}
 751
 752/*
 753 * Tell the sequencer about a new transaction to execute.
 754 */
 755static __inline void
 756ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb)
 757{
 758        ahd_swap_with_next_hscb(ahd, scb);
 759
 760        if (SCBID_IS_NULL(SCB_GET_TAG(scb)))
 761                panic("Attempt to queue invalid SCB tag %x\n",
 762                      SCB_GET_TAG(scb));
 763
 764        /*
 765         * Keep a history of SCBs we've downloaded in the qinfifo.
 766         */
 767        ahd->qinfifo[AHD_QIN_WRAP(ahd->qinfifonext)] = SCB_GET_TAG(scb);
 768        ahd->qinfifonext++;
 769
 770        if (scb->sg_count != 0)
 771                ahd_setup_data_scb(ahd, scb);
 772        else
 773                ahd_setup_noxfer_scb(ahd, scb);
 774        ahd_setup_scb_common(ahd, scb);
 775
 776        /*
 777         * Make sure our data is consistent from the
 778         * perspective of the adapter.
 779         */
 780        ahd_sync_scb(ahd, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
 781
 782#ifdef AHD_DEBUG
 783        if ((ahd_debug & AHD_SHOW_QUEUE) != 0) {
 784                uint64_t host_dataptr;
 785
 786                host_dataptr = ahd_le64toh(scb->hscb->dataptr);
 787                printf("%s: Queueing SCB 0x%x bus addr 0x%x - 0x%x%x/0x%x\n",
 788                       ahd_name(ahd),
 789                       SCB_GET_TAG(scb), ahd_le32toh(scb->hscb->hscb_busaddr),
 790                       (u_int)((host_dataptr >> 32) & 0xFFFFFFFF),
 791                       (u_int)(host_dataptr & 0xFFFFFFFF),
 792                       ahd_le32toh(scb->hscb->datacnt));
 793        }
 794#endif
 795        /* Tell the adapter about the newly queued SCB */
 796        ahd_set_hnscb_qoff(ahd, ahd->qinfifonext);
 797}
 798
 799static __inline uint8_t *
 800ahd_get_sense_buf(struct ahd_softc *ahd, struct scb *scb)
 801{
 802        return (scb->sense_data);
 803}
 804
 805static __inline uint32_t
 806ahd_get_sense_bufaddr(struct ahd_softc *ahd, struct scb *scb)
 807{
 808        return (scb->sense_busaddr);
 809}
 810
 811/************************** Interrupt Processing ******************************/
 812static __inline void    ahd_sync_qoutfifo(struct ahd_softc *ahd, int op);
 813static __inline void    ahd_sync_tqinfifo(struct ahd_softc *ahd, int op);
 814static __inline u_int   ahd_check_cmdcmpltqueues(struct ahd_softc *ahd);
 815static __inline int     ahd_intr(struct ahd_softc *ahd);
 816
 817static __inline void
 818ahd_sync_qoutfifo(struct ahd_softc *ahd, int op)
 819{
 820        ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_dmamap,
 821                        /*offset*/0, /*len*/AHC_SCB_MAX * sizeof(uint16_t), op);
 822}
 823
 824static __inline void
 825ahd_sync_tqinfifo(struct ahd_softc *ahd, int op)
 826{
 827#ifdef AHD_TARGET_MODE
 828        if ((ahd->flags & AHD_TARGETROLE) != 0) {
 829                ahd_dmamap_sync(ahd, ahd->shared_data_dmat,
 830                                ahd->shared_data_dmamap,
 831                                ahd_targetcmd_offset(ahd, 0),
 832                                sizeof(struct target_cmd) * AHD_TMODE_CMDS,
 833                                op);
 834        }
 835#endif
 836}
 837
 838/*
 839 * See if the firmware has posted any completed commands
 840 * into our in-core command complete fifos.
 841 */
 842#define AHD_RUN_QOUTFIFO 0x1
 843#define AHD_RUN_TQINFIFO 0x2
 844static __inline u_int
 845ahd_check_cmdcmpltqueues(struct ahd_softc *ahd)
 846{
 847        u_int retval;
 848
 849        retval = 0;
 850        ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_dmamap,
 851                        /*offset*/ahd->qoutfifonext, /*len*/2,
 852                        BUS_DMASYNC_POSTREAD);
 853        if ((ahd->qoutfifo[ahd->qoutfifonext]
 854             & QOUTFIFO_ENTRY_VALID_LE) == ahd->qoutfifonext_valid_tag)
 855                retval |= AHD_RUN_QOUTFIFO;
 856#ifdef AHD_TARGET_MODE
 857        if ((ahd->flags & AHD_TARGETROLE) != 0
 858         && (ahd->flags & AHD_TQINFIFO_BLOCKED) == 0) {
 859                ahd_dmamap_sync(ahd, ahd->shared_data_dmat,
 860                                ahd->shared_data_dmamap,
 861                                ahd_targetcmd_offset(ahd, ahd->tqinfifofnext),
 862                                /*len*/sizeof(struct target_cmd),
 863                                BUS_DMASYNC_POSTREAD);
 864                if (ahd->targetcmds[ahd->tqinfifonext].cmd_valid != 0)
 865                        retval |= AHD_RUN_TQINFIFO;
 866        }
 867#endif
 868        return (retval);
 869}
 870
 871/*
 872 * Catch an interrupt from the adapter
 873 */
 874static __inline int
 875ahd_intr(struct ahd_softc *ahd)
 876{
 877        u_int   intstat;
 878
 879        if ((ahd->pause & INTEN) == 0) {
 880                /*
 881                 * Our interrupt is not enabled on the chip
 882                 * and may be disabled for re-entrancy reasons,
 883                 * so just return.  This is likely just a shared
 884                 * interrupt.
 885                 */
 886                return (0);
 887        }
 888
 889        /*
 890         * Instead of directly reading the interrupt status register,
 891         * infer the cause of the interrupt by checking our in-core
 892         * completion queues.  This avoids a costly PCI bus read in
 893         * most cases.
 894         */
 895        if ((ahd->flags & AHD_ALL_INTERRUPTS) == 0
 896         && (ahd_check_cmdcmpltqueues(ahd) != 0))
 897                intstat = CMDCMPLT;
 898        else
 899                intstat = ahd_inb(ahd, INTSTAT);
 900
 901        if ((intstat & INT_PEND) == 0)
 902                return (0);
 903
 904        if (intstat & CMDCMPLT) {
 905                ahd_outb(ahd, CLRINT, CLRCMDINT);
 906
 907                /*
 908                 * Ensure that the chip sees that we've cleared
 909                 * this interrupt before we walk the output fifo.
 910                 * Otherwise, we may, due to posted bus writes,
 911                 * clear the interrupt after we finish the scan,
 912                 * and after the sequencer has added new entries
 913                 * and asserted the interrupt again.
 914                 */
 915                if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) {
 916                        if (ahd_is_paused(ahd)) {
 917                                /*
 918                                 * Potentially lost SEQINT.
 919                                 * If SEQINTCODE is non-zero,
 920                                 * simulate the SEQINT.
 921                                 */
 922                                if (ahd_inb(ahd, SEQINTCODE) != NO_SEQINT)
 923                                        intstat |= SEQINT;
 924                        }
 925                } else {
 926                        ahd_flush_device_writes(ahd);
 927                }
 928                ahd_run_qoutfifo(ahd);
 929                ahd->cmdcmplt_counts[ahd->cmdcmplt_bucket]++;
 930                ahd->cmdcmplt_total++;
 931#ifdef AHD_TARGET_MODE
 932                if ((ahd->flags & AHD_TARGETROLE) != 0)
 933                        ahd_run_tqinfifo(ahd, /*paused*/FALSE);
 934#endif
 935        }
 936
 937        /*
 938         * Handle statuses that may invalidate our cached
 939         * copy of INTSTAT separately.
 940         */
 941        if (intstat == 0xFF && (ahd->features & AHD_REMOVABLE) != 0) {
 942                /* Hot eject.  Do nothing */
 943        } else if (intstat & HWERRINT) {
 944                ahd_handle_hwerrint(ahd);
 945        } else if ((intstat & (PCIINT|SPLTINT)) != 0) {
 946                ahd->bus_intr(ahd);
 947        } else {
 948
 949                if ((intstat & SEQINT) != 0)
 950                        ahd_handle_seqint(ahd, intstat);
 951
 952                if ((intstat & SCSIINT) != 0)
 953                        ahd_handle_scsiint(ahd, intstat);
 954        }
 955        return (1);
 956}
 957
 958#endif  /* _AIC79XX_INLINE_H_ */
 959
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.