The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/aic7xxx/aic79xx_inline.h

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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#57 $
   41  *
   42  * $FreeBSD: src/sys/dev/aic7xxx/aic79xx_inline.h,v 1.16.2.1 2005/01/30 00:59:25 imp Exp $
   43  */
   44 
   45 #ifndef _AIC79XX_INLINE_H_
   46 #define _AIC79XX_INLINE_H_
   47 
   48 /******************************** Debugging ***********************************/
   49 static __inline char *ahd_name(struct ahd_softc *ahd);
   50 
   51 static __inline char *
   52 ahd_name(struct ahd_softc *ahd)
   53 {
   54         return (ahd->name);
   55 }
   56 
   57 /************************ Sequencer Execution Control *************************/
   58 static __inline void ahd_known_modes(struct ahd_softc *ahd,
   59                                      ahd_mode src, ahd_mode dst);
   60 static __inline ahd_mode_state ahd_build_mode_state(struct ahd_softc *ahd,
   61                                                     ahd_mode src,
   62                                                     ahd_mode dst);
   63 static __inline void ahd_extract_mode_state(struct ahd_softc *ahd,
   64                                             ahd_mode_state state,
   65                                             ahd_mode *src, ahd_mode *dst);
   66 static __inline void ahd_set_modes(struct ahd_softc *ahd, ahd_mode src,
   67                                    ahd_mode dst);
   68 static __inline void ahd_update_modes(struct ahd_softc *ahd);
   69 static __inline void ahd_assert_modes(struct ahd_softc *ahd, ahd_mode srcmode,
   70                                       ahd_mode dstmode, const char *file,
   71                                       int line);
   72 static __inline ahd_mode_state ahd_save_modes(struct ahd_softc *ahd);
   73 static __inline void ahd_restore_modes(struct ahd_softc *ahd,
   74                                        ahd_mode_state state);
   75 static __inline int  ahd_is_paused(struct ahd_softc *ahd);
   76 static __inline void ahd_pause(struct ahd_softc *ahd);
   77 static __inline void ahd_unpause(struct ahd_softc *ahd);
   78 
   79 static __inline void
   80 ahd_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 
   88 static __inline ahd_mode_state
   89 ahd_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 
   94 static __inline void
   95 ahd_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 
  102 static __inline void
  103 ahd_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 
  120 static __inline void
  121 ahd_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 
  136 static __inline void
  137 ahd_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 
  149 static __inline ahd_mode_state
  150 ahd_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 
  159 static __inline void
  160 ahd_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  */
  176 static __inline int
  177 ahd_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  */
  189 static __inline void
  190 ahd_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  */
  212 static __inline void
  213 ahd_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 *************************/
  233 static __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);
  236 static __inline void     ahd_setup_scb_common(struct ahd_softc *ahd,
  237                                               struct scb *scb);
  238 static __inline void     ahd_setup_data_scb(struct ahd_softc *ahd,
  239                                             struct scb *scb);
  240 static __inline void     ahd_setup_noxfer_scb(struct ahd_softc *ahd,
  241                                               struct scb *scb);
  242 
  243 static __inline void *
  244 ahd_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 = aic_htole64(addr);
  254                 sg->len = aic_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 = aic_htole32(addr & 0xFFFFFFFF);
  261                 sg->len = aic_htole32(len | ((addr >> 8) & 0x7F000000)
  262                                     | (last ? AHD_DMA_LAST_SEG : 0));
  263                 return (sg + 1);
  264         }
  265 }
  266 
  267 static __inline void
  268 ahd_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 (aic_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                     aic_htole32(scb->sense_busaddr);
  286 }
  287 
  288 static __inline void
  289 ahd_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 = aic_le32toh(sg->len) & 0x7F000000;
  312                         scb->hscb->dataptr |= aic_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 = aic_htole32(scb->sg_list_busaddr|SG_FULL_RESID);
  323 }
  324 
  325 static __inline void
  326 ahd_setup_noxfer_scb(struct ahd_softc *ahd, struct scb *scb)
  327 {
  328         scb->hscb->sgptr = aic_htole32(SG_LIST_NULL);
  329         scb->hscb->dataptr = 0;
  330         scb->hscb->datacnt = 0;
  331 }
  332 
  333 /************************** Memory mapping routines ***************************/
  334 static __inline size_t  ahd_sg_size(struct ahd_softc *ahd);
  335 static __inline void *
  336                         ahd_sg_bus_to_virt(struct ahd_softc *ahd,
  337                                            struct scb *scb,
  338                                            uint32_t sg_busaddr);
  339 static __inline uint32_t
  340                         ahd_sg_virt_to_bus(struct ahd_softc *ahd,
  341                                            struct scb *scb,
  342                                            void *sg);
  343 static __inline void    ahd_sync_scb(struct ahd_softc *ahd,
  344                                      struct scb *scb, int op);
  345 static __inline void    ahd_sync_sglist(struct ahd_softc *ahd,
  346                                         struct scb *scb, int op);
  347 static __inline void    ahd_sync_sense(struct ahd_softc *ahd,
  348                                        struct scb *scb, int op);
  349 static __inline uint32_t
  350                         ahd_targetcmd_offset(struct ahd_softc *ahd,
  351                                              u_int index);
  352 
  353 static __inline size_t
  354 ahd_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 
  361 static __inline void *
  362 ahd_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 
  371 static __inline uint32_t
  372 ahd_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 
  383 static __inline void
  384 ahd_sync_scb(struct ahd_softc *ahd, struct scb *scb, int op)
  385 {
  386         aic_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 
  392 static __inline void
  393 ahd_sync_sglist(struct ahd_softc *ahd, struct scb *scb, int op)
  394 {
  395         if (scb->sg_count == 0)
  396                 return;
  397 
  398         aic_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 
  404 static __inline void
  405 ahd_sync_sense(struct ahd_softc *ahd, struct scb *scb, int op)
  406 {
  407         aic_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 
  413 static __inline uint32_t
  414 ahd_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 ***********************/
  421 static __inline void    ahd_complete_scb(struct ahd_softc *ahd,
  422                                          struct scb *scb);
  423 static __inline void    ahd_update_residual(struct ahd_softc *ahd,
  424                                             struct scb *scb);
  425 static __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);
  430 static __inline uint16_t
  431                         ahd_inw(struct ahd_softc *ahd, u_int port);
  432 static __inline void    ahd_outw(struct ahd_softc *ahd, u_int port,
  433                                  u_int value);
  434 static __inline uint32_t
  435                         ahd_inl(struct ahd_softc *ahd, u_int port);
  436 static __inline void    ahd_outl(struct ahd_softc *ahd, u_int port,
  437                                  uint32_t value);
  438 static __inline uint64_t
  439                         ahd_inq(struct ahd_softc *ahd, u_int port);
  440 static __inline void    ahd_outq(struct ahd_softc *ahd, u_int port,
  441                                  uint64_t value);
  442 static __inline u_int   ahd_get_scbptr(struct ahd_softc *ahd);
  443 static __inline void    ahd_set_scbptr(struct ahd_softc *ahd, u_int scbptr);
  444 static __inline u_int   ahd_get_hnscb_qoff(struct ahd_softc *ahd);
  445 static __inline void    ahd_set_hnscb_qoff(struct ahd_softc *ahd, u_int value);
  446 static __inline u_int   ahd_get_hescb_qoff(struct ahd_softc *ahd);
  447 static __inline void    ahd_set_hescb_qoff(struct ahd_softc *ahd, u_int value);
  448 static __inline u_int   ahd_get_snscb_qoff(struct ahd_softc *ahd);
  449 static __inline void    ahd_set_snscb_qoff(struct ahd_softc *ahd, u_int value);
  450 static __inline u_int   ahd_get_sescb_qoff(struct ahd_softc *ahd);
  451 static __inline void    ahd_set_sescb_qoff(struct ahd_softc *ahd, u_int value);
  452 static __inline u_int   ahd_get_sdscb_qoff(struct ahd_softc *ahd);
  453 static __inline void    ahd_set_sdscb_qoff(struct ahd_softc *ahd, u_int value);
  454 static __inline u_int   ahd_inb_scbram(struct ahd_softc *ahd, u_int offset);
  455 static __inline u_int   ahd_inw_scbram(struct ahd_softc *ahd, u_int offset);
  456 static __inline uint32_t
  457                         ahd_inl_scbram(struct ahd_softc *ahd, u_int offset);
  458 static __inline uint64_t
  459                         ahd_inq_scbram(struct ahd_softc *ahd, u_int offset);
  460 static __inline void    ahd_swap_with_next_hscb(struct ahd_softc *ahd,
  461                                                 struct scb *scb);
  462 static __inline void    ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb);
  463 static __inline uint8_t *
  464                         ahd_get_sense_buf(struct ahd_softc *ahd,
  465                                           struct scb *scb);
  466 static __inline uint32_t
  467                         ahd_get_sense_bufaddr(struct ahd_softc *ahd,
  468                                               struct scb *scb);
  469 
  470 static __inline void
  471 ahd_complete_scb(struct ahd_softc *ahd, struct scb *scb)
  472 {
  473         uint32_t sgptr;
  474 
  475         sgptr = aic_le32toh(scb->hscb->sgptr);
  476         if ((sgptr & SG_STATUS_VALID) != 0)
  477                 ahd_handle_scb_status(ahd, scb);
  478         else
  479                 ahd_done(ahd, scb);
  480 }
  481 
  482 /*
  483  * Determine whether the sequencer reported a residual
  484  * for this SCB/transaction.
  485  */
  486 static __inline void
  487 ahd_update_residual(struct ahd_softc *ahd, struct scb *scb)
  488 {
  489         uint32_t sgptr;
  490 
  491         sgptr = aic_le32toh(scb->hscb->sgptr);
  492         if ((sgptr & SG_STATUS_VALID) != 0)
  493                 ahd_calc_residual(ahd, scb);
  494 }
  495 
  496 /*
  497  * Return pointers to the transfer negotiation information
  498  * for the specified our_id/remote_id pair.
  499  */
  500 static __inline struct ahd_initiator_tinfo *
  501 ahd_fetch_transinfo(struct ahd_softc *ahd, char channel, u_int our_id,
  502                     u_int remote_id, struct ahd_tmode_tstate **tstate)
  503 {
  504         /*
  505          * Transfer data structures are stored from the perspective
  506          * of the target role.  Since the parameters for a connection
  507          * in the initiator role to a given target are the same as
  508          * when the roles are reversed, we pretend we are the target.
  509          */
  510         if (channel == 'B')
  511                 our_id += 8;
  512         *tstate = ahd->enabled_targets[our_id];
  513         return (&(*tstate)->transinfo[remote_id]);
  514 }
  515 
  516 #define AHD_COPY_COL_IDX(dst, src)                              \
  517 do {                                                            \
  518         dst->hscb->scsiid = src->hscb->scsiid;                  \
  519         dst->hscb->lun = src->hscb->lun;                        \
  520 } while (0)
  521 
  522 static __inline uint16_t
  523 ahd_inw(struct ahd_softc *ahd, u_int port)
  524 {
  525         /*
  526          * Read high byte first as some registers increment
  527          * or have other side effects when the low byte is
  528          * read.
  529          */
  530         return ((ahd_inb(ahd, port+1) << 8) | ahd_inb(ahd, port));
  531 }
  532 
  533 static __inline void
  534 ahd_outw(struct ahd_softc *ahd, u_int port, u_int value)
  535 {
  536         /*
  537          * Write low byte first to accomodate registers
  538          * such as PRGMCNT where the order maters.
  539          */
  540         ahd_outb(ahd, port, value & 0xFF);
  541         ahd_outb(ahd, port+1, (value >> 8) & 0xFF);
  542 }
  543 
  544 static __inline uint32_t
  545 ahd_inl(struct ahd_softc *ahd, u_int port)
  546 {
  547         return ((ahd_inb(ahd, port))
  548               | (ahd_inb(ahd, port+1) << 8)
  549               | (ahd_inb(ahd, port+2) << 16)
  550               | (ahd_inb(ahd, port+3) << 24));
  551 }
  552 
  553 static __inline void
  554 ahd_outl(struct ahd_softc *ahd, u_int port, uint32_t value)
  555 {
  556         ahd_outb(ahd, port, (value) & 0xFF);
  557         ahd_outb(ahd, port+1, ((value) >> 8) & 0xFF);
  558         ahd_outb(ahd, port+2, ((value) >> 16) & 0xFF);
  559         ahd_outb(ahd, port+3, ((value) >> 24) & 0xFF);
  560 }
  561 
  562 static __inline uint64_t
  563 ahd_inq(struct ahd_softc *ahd, u_int port)
  564 {
  565         return ((ahd_inb(ahd, port))
  566               | (ahd_inb(ahd, port+1) << 8)
  567               | (ahd_inb(ahd, port+2) << 16)
  568               | (ahd_inb(ahd, port+3) << 24)
  569               | (((uint64_t)ahd_inb(ahd, port+4)) << 32)
  570               | (((uint64_t)ahd_inb(ahd, port+5)) << 40)
  571               | (((uint64_t)ahd_inb(ahd, port+6)) << 48)
  572               | (((uint64_t)ahd_inb(ahd, port+7)) << 56));
  573 }
  574 
  575 static __inline void
  576 ahd_outq(struct ahd_softc *ahd, u_int port, uint64_t value)
  577 {
  578         ahd_outb(ahd, port, value & 0xFF);
  579         ahd_outb(ahd, port+1, (value >> 8) & 0xFF);
  580         ahd_outb(ahd, port+2, (value >> 16) & 0xFF);
  581         ahd_outb(ahd, port+3, (value >> 24) & 0xFF);
  582         ahd_outb(ahd, port+4, (value >> 32) & 0xFF);
  583         ahd_outb(ahd, port+5, (value >> 40) & 0xFF);
  584         ahd_outb(ahd, port+6, (value >> 48) & 0xFF);
  585         ahd_outb(ahd, port+7, (value >> 56) & 0xFF);
  586 }
  587 
  588 static __inline u_int
  589 ahd_get_scbptr(struct ahd_softc *ahd)
  590 {
  591         AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK),
  592                          ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK));
  593         return (ahd_inb(ahd, SCBPTR) | (ahd_inb(ahd, SCBPTR + 1) << 8));
  594 }
  595 
  596 static __inline void
  597 ahd_set_scbptr(struct ahd_softc *ahd, u_int scbptr)
  598 {
  599         AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK),
  600                          ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK));
  601         ahd_outb(ahd, SCBPTR, scbptr & 0xFF);
  602         ahd_outb(ahd, SCBPTR+1, (scbptr >> 8) & 0xFF);
  603 }
  604 
  605 static __inline u_int
  606 ahd_get_hnscb_qoff(struct ahd_softc *ahd)
  607 {
  608         return (ahd_inw_atomic(ahd, HNSCB_QOFF));
  609 }
  610 
  611 static __inline void
  612 ahd_set_hnscb_qoff(struct ahd_softc *ahd, u_int value)
  613 {
  614         ahd_outw_atomic(ahd, HNSCB_QOFF, value);
  615 }
  616 
  617 static __inline u_int
  618 ahd_get_hescb_qoff(struct ahd_softc *ahd)
  619 {
  620         return (ahd_inb(ahd, HESCB_QOFF));
  621 }
  622 
  623 static __inline void
  624 ahd_set_hescb_qoff(struct ahd_softc *ahd, u_int value)
  625 {
  626         ahd_outb(ahd, HESCB_QOFF, value);
  627 }
  628 
  629 static __inline u_int
  630 ahd_get_snscb_qoff(struct ahd_softc *ahd)
  631 {
  632         u_int oldvalue;
  633 
  634         AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
  635         oldvalue = ahd_inw(ahd, SNSCB_QOFF);
  636         ahd_outw(ahd, SNSCB_QOFF, oldvalue);
  637         return (oldvalue);
  638 }
  639 
  640 static __inline void
  641 ahd_set_snscb_qoff(struct ahd_softc *ahd, u_int value)
  642 {
  643         AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
  644         ahd_outw(ahd, SNSCB_QOFF, value);
  645 }
  646 
  647 static __inline u_int
  648 ahd_get_sescb_qoff(struct ahd_softc *ahd)
  649 {
  650         AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
  651         return (ahd_inb(ahd, SESCB_QOFF));
  652 }
  653 
  654 static __inline void
  655 ahd_set_sescb_qoff(struct ahd_softc *ahd, u_int value)
  656 {
  657         AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
  658         ahd_outb(ahd, SESCB_QOFF, value);
  659 }
  660 
  661 static __inline u_int
  662 ahd_get_sdscb_qoff(struct ahd_softc *ahd)
  663 {
  664         AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
  665         return (ahd_inb(ahd, SDSCB_QOFF) | (ahd_inb(ahd, SDSCB_QOFF + 1) << 8));
  666 }
  667 
  668 static __inline void
  669 ahd_set_sdscb_qoff(struct ahd_softc *ahd, u_int value)
  670 {
  671         AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
  672         ahd_outb(ahd, SDSCB_QOFF, value & 0xFF);
  673         ahd_outb(ahd, SDSCB_QOFF+1, (value >> 8) & 0xFF);
  674 }
  675 
  676 static __inline u_int
  677 ahd_inb_scbram(struct ahd_softc *ahd, u_int offset)
  678 {
  679         u_int value;
  680 
  681         /*
  682          * Workaround PCI-X Rev A. hardware bug.
  683          * After a host read of SCB memory, the chip
  684          * may become confused into thinking prefetch
  685          * was required.  This starts the discard timer
  686          * running and can cause an unexpected discard
  687          * timer interrupt.  The work around is to read
  688          * a normal register prior to the exhaustion of
  689          * the discard timer.  The mode pointer register
  690          * has no side effects and so serves well for
  691          * this purpose.
  692          *
  693          * Razor #528
  694          */
  695         value = ahd_inb(ahd, offset);
  696         if ((ahd->bugs & AHD_PCIX_SCBRAM_RD_BUG) != 0)
  697                 ahd_inb(ahd, MODE_PTR);
  698         return (value);
  699 }
  700 
  701 static __inline u_int
  702 ahd_inw_scbram(struct ahd_softc *ahd, u_int offset)
  703 {
  704         return (ahd_inb_scbram(ahd, offset)
  705               | (ahd_inb_scbram(ahd, offset+1) << 8));
  706 }
  707 
  708 static __inline uint32_t
  709 ahd_inl_scbram(struct ahd_softc *ahd, u_int offset)
  710 {
  711         return (ahd_inw_scbram(ahd, offset)
  712               | (ahd_inw_scbram(ahd, offset+2) << 16));
  713 }
  714 
  715 static __inline uint64_t
  716 ahd_inq_scbram(struct ahd_softc *ahd, u_int offset)
  717 {
  718         return (ahd_inl_scbram(ahd, offset)
  719               | ((uint64_t)ahd_inl_scbram(ahd, offset+4)) << 32);
  720 }
  721 
  722 static __inline struct scb *
  723 ahd_lookup_scb(struct ahd_softc *ahd, u_int tag)
  724 {
  725         struct scb* scb;
  726 
  727         if (tag >= AHD_SCB_MAX)
  728                 return (NULL);
  729         scb = ahd->scb_data.scbindex[tag];
  730         if (scb != NULL)
  731                 ahd_sync_scb(ahd, scb,
  732                              BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
  733         return (scb);
  734 }
  735 
  736 static __inline void
  737 ahd_swap_with_next_hscb(struct ahd_softc *ahd, struct scb *scb)
  738 {
  739         struct   hardware_scb *q_hscb;
  740         struct   map_node *q_hscb_map;
  741         uint32_t saved_hscb_busaddr;
  742 
  743         /*
  744          * Our queuing method is a bit tricky.  The card
  745          * knows in advance which HSCB (by address) to download,
  746          * and we can't disappoint it.  To achieve this, the next
  747          * HSCB to download is saved off in ahd->next_queued_hscb.
  748          * When we are called to queue "an arbitrary scb",
  749          * we copy the contents of the incoming HSCB to the one
  750          * the sequencer knows about, swap HSCB pointers and
  751          * finally assign the SCB to the tag indexed location
  752          * in the scb_array.  This makes sure that we can still
  753          * locate the correct SCB by SCB_TAG.
  754          */
  755         q_hscb = ahd->next_queued_hscb;
  756         q_hscb_map = ahd->next_queued_hscb_map;
  757         saved_hscb_busaddr = q_hscb->hscb_busaddr;
  758         memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb));
  759         q_hscb->hscb_busaddr = saved_hscb_busaddr;
  760         q_hscb->next_hscb_busaddr = scb->hscb->hscb_busaddr;
  761 
  762         /* Now swap HSCB pointers. */
  763         ahd->next_queued_hscb = scb->hscb;
  764         ahd->next_queued_hscb_map = scb->hscb_map;
  765         scb->hscb = q_hscb;
  766         scb->hscb_map = q_hscb_map;
  767 
  768         /* Now define the mapping from tag to SCB in the scbindex */
  769         ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = scb;
  770 }
  771 
  772 /*
  773  * Tell the sequencer about a new transaction to execute.
  774  */
  775 static __inline void
  776 ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb)
  777 {
  778         ahd_swap_with_next_hscb(ahd, scb);
  779 
  780         if (SCBID_IS_NULL(SCB_GET_TAG(scb)))
  781                 panic("Attempt to queue invalid SCB tag %x\n",
  782                       SCB_GET_TAG(scb));
  783 
  784         /*
  785          * Keep a history of SCBs we've downloaded in the qinfifo.
  786          */
  787         ahd->qinfifo[AHD_QIN_WRAP(ahd->qinfifonext)] = SCB_GET_TAG(scb);
  788         ahd->qinfifonext++;
  789 
  790         if (scb->sg_count != 0)
  791                 ahd_setup_data_scb(ahd, scb);
  792         else
  793                 ahd_setup_noxfer_scb(ahd, scb);
  794         ahd_setup_scb_common(ahd, scb);
  795 
  796         /*
  797          * Make sure our data is consistent from the
  798          * perspective of the adapter.
  799          */
  800         ahd_sync_scb(ahd, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
  801 
  802 #ifdef AHD_DEBUG
  803         if ((ahd_debug & AHD_SHOW_QUEUE) != 0) {
  804                 uint64_t host_dataptr;
  805 
  806                 host_dataptr = aic_le64toh(scb->hscb->dataptr);
  807                 printf("%s: Queueing SCB %d:0x%x bus addr 0x%x - 0x%x%x/0x%x\n",
  808                        ahd_name(ahd),
  809                        SCB_GET_TAG(scb), scb->hscb->scsiid,
  810                        aic_le32toh(scb->hscb->hscb_busaddr),
  811                        (u_int)((host_dataptr >> 32) & 0xFFFFFFFF),
  812                        (u_int)(host_dataptr & 0xFFFFFFFF),
  813                        aic_le32toh(scb->hscb->datacnt));
  814         }
  815 #endif
  816         /* Tell the adapter about the newly queued SCB */
  817         ahd_set_hnscb_qoff(ahd, ahd->qinfifonext);
  818 }
  819 
  820 static __inline uint8_t *
  821 ahd_get_sense_buf(struct ahd_softc *ahd, struct scb *scb)
  822 {
  823         return (scb->sense_data);
  824 }
  825 
  826 static __inline uint32_t
  827 ahd_get_sense_bufaddr(struct ahd_softc *ahd, struct scb *scb)
  828 {
  829         return (scb->sense_busaddr);
  830 }
  831 
  832 /************************** Interrupt Processing ******************************/
  833 static __inline void    ahd_sync_qoutfifo(struct ahd_softc *ahd, int op);
  834 static __inline void    ahd_sync_tqinfifo(struct ahd_softc *ahd, int op);
  835 static __inline u_int   ahd_check_cmdcmpltqueues(struct ahd_softc *ahd);
  836 static __inline int     ahd_intr(struct ahd_softc *ahd);
  837 
  838 static __inline void
  839 ahd_sync_qoutfifo(struct ahd_softc *ahd, int op)
  840 {
  841         aic_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_map.dmamap,
  842                         /*offset*/0,
  843                         /*len*/AHD_SCB_MAX * sizeof(struct ahd_completion), op);
  844 }
  845 
  846 static __inline void
  847 ahd_sync_tqinfifo(struct ahd_softc *ahd, int op)
  848 {
  849 #ifdef AHD_TARGET_MODE
  850         if ((ahd->flags & AHD_TARGETROLE) != 0) {
  851                 aic_dmamap_sync(ahd, ahd->shared_data_dmat,
  852                                 ahd->shared_data_map.dmamap,
  853                                 ahd_targetcmd_offset(ahd, 0),
  854                                 sizeof(struct target_cmd) * AHD_TMODE_CMDS,
  855                                 op);
  856         }
  857 #endif
  858 }
  859 
  860 /*
  861  * See if the firmware has posted any completed commands
  862  * into our in-core command complete fifos.
  863  */
  864 #define AHD_RUN_QOUTFIFO 0x1
  865 #define AHD_RUN_TQINFIFO 0x2
  866 static __inline u_int
  867 ahd_check_cmdcmpltqueues(struct ahd_softc *ahd)
  868 {
  869         u_int retval;
  870 
  871         retval = 0;
  872         aic_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_map.dmamap,
  873                         /*offset*/ahd->qoutfifonext * sizeof(*ahd->qoutfifo),
  874                         /*len*/sizeof(*ahd->qoutfifo), BUS_DMASYNC_POSTREAD);
  875         if (ahd->qoutfifo[ahd->qoutfifonext].valid_tag
  876           == ahd->qoutfifonext_valid_tag)
  877                 retval |= AHD_RUN_QOUTFIFO;
  878 #ifdef AHD_TARGET_MODE
  879         if ((ahd->flags & AHD_TARGETROLE) != 0
  880          && (ahd->flags & AHD_TQINFIFO_BLOCKED) == 0) {
  881                 aic_dmamap_sync(ahd, ahd->shared_data_dmat,
  882                                 ahd->shared_data_map.dmamap,
  883                                 ahd_targetcmd_offset(ahd, ahd->tqinfifofnext),
  884                                 /*len*/sizeof(struct target_cmd),
  885                                 BUS_DMASYNC_POSTREAD);
  886                 if (ahd->targetcmds[ahd->tqinfifonext].cmd_valid != 0)
  887                         retval |= AHD_RUN_TQINFIFO;
  888         }
  889 #endif
  890         return (retval);
  891 }
  892 
  893 /*
  894  * Catch an interrupt from the adapter
  895  */
  896 static __inline int
  897 ahd_intr(struct ahd_softc *ahd)
  898 {
  899         u_int   intstat;
  900 
  901         if ((ahd->pause & INTEN) == 0) {
  902                 /*
  903                  * Our interrupt is not enabled on the chip
  904                  * and may be disabled for re-entrancy reasons,
  905                  * so just return.  This is likely just a shared
  906                  * interrupt.
  907                  */
  908                 return (0);
  909         }
  910 
  911         /*
  912          * Instead of directly reading the interrupt status register,
  913          * infer the cause of the interrupt by checking our in-core
  914          * completion queues.  This avoids a costly PCI bus read in
  915          * most cases.
  916          */
  917         if ((ahd->flags & AHD_ALL_INTERRUPTS) == 0
  918          && (ahd_check_cmdcmpltqueues(ahd) != 0))
  919                 intstat = CMDCMPLT;
  920         else
  921                 intstat = ahd_inb(ahd, INTSTAT);
  922 
  923         if ((intstat & INT_PEND) == 0)
  924                 return (0);
  925 
  926         if (intstat & CMDCMPLT) {
  927                 ahd_outb(ahd, CLRINT, CLRCMDINT);
  928 
  929                 /*
  930                  * Ensure that the chip sees that we've cleared
  931                  * this interrupt before we walk the output fifo.
  932                  * Otherwise, we may, due to posted bus writes,
  933                  * clear the interrupt after we finish the scan,
  934                  * and after the sequencer has added new entries
  935                  * and asserted the interrupt again.
  936                  */
  937                 if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) {
  938                         if (ahd_is_paused(ahd)) {
  939                                 /*
  940                                  * Potentially lost SEQINT.
  941                                  * If SEQINTCODE is non-zero,
  942                                  * simulate the SEQINT.
  943                                  */
  944                                 if (ahd_inb(ahd, SEQINTCODE) != NO_SEQINT)
  945                                         intstat |= SEQINT;
  946                         }
  947                 } else {
  948                         ahd_flush_device_writes(ahd);
  949                 }
  950                 ahd_run_qoutfifo(ahd);
  951                 ahd->cmdcmplt_counts[ahd->cmdcmplt_bucket]++;
  952                 ahd->cmdcmplt_total++;
  953 #ifdef AHD_TARGET_MODE
  954                 if ((ahd->flags & AHD_TARGETROLE) != 0)
  955                         ahd_run_tqinfifo(ahd, /*paused*/FALSE);
  956 #endif
  957         }
  958 
  959         /*
  960          * Handle statuses that may invalidate our cached
  961          * copy of INTSTAT separately.
  962          */
  963         if (intstat == 0xFF && (ahd->features & AHD_REMOVABLE) != 0) {
  964                 /* Hot eject.  Do nothing */
  965         } else if (intstat & HWERRINT) {
  966                 ahd_handle_hwerrint(ahd);
  967         } else if ((intstat & (PCIINT|SPLTINT)) != 0) {
  968                 ahd->bus_intr(ahd);
  969         } else {
  970 
  971                 if ((intstat & SEQINT) != 0)
  972                         ahd_handle_seqint(ahd, intstat);
  973 
  974                 if ((intstat & SCSIINT) != 0)
  975                         ahd_handle_scsiint(ahd, intstat);
  976         }
  977         return (1);
  978 }
  979 
  980 #endif  /* _AIC79XX_INLINE_H_ */

Cache object: a130d84250907e535963cf6330e28b7d


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.