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/advansys/adwlib.c

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  * Low level routines for Second Generation
    3  * Advanced Systems Inc. SCSI controllers chips
    4  *
    5  * Copyright (c) 1998 Justin Gibbs.
    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, immediately at the beginning of the file.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  * 3. The name of the author may not be used to endorse or promote products
   18  *    derived from this software without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
   24  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  *
   32  * $FreeBSD$
   33  */
   34 /*
   35  * Ported from:
   36  * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
   37  *     
   38  * Copyright (c) 1995-1998 Advanced System Products, Inc.
   39  * All Rights Reserved.
   40  *   
   41  * Redistribution and use in source and binary forms, with or without
   42  * modification, are permitted provided that redistributions of source
   43  * code retain the above copyright notice and this comment without
   44  * modification.
   45  */
   46 
   47 #include <sys/types.h>
   48 #include <sys/systm.h>
   49 
   50 #include <machine/bus_pio.h>
   51 #include <machine/bus_memio.h>
   52 #include <machine/bus.h>
   53 #include <machine/clock.h>
   54 
   55 #include <cam/cam.h>
   56 #include <cam/scsi/scsi_all.h>
   57 
   58 #include <dev/advansys/adwlib.h>
   59 
   60 struct adw_eeprom adw_default_eeprom = {
   61         ADW_EEPROM_BIOS_ENABLE, /* cfg_lsw */
   62         0x0000,                 /* cfg_msw */
   63         0xFFFF,                 /* disc_enable */
   64         0xFFFF,                 /* wdtr_able */
   65         0xFFFF,                 /* sdtr_able */
   66         0xFFFF,                 /* start_motor */
   67         0xFFFF,                 /* tagqng_able */
   68         0xFFFF,                 /* bios_scan */
   69         0,                      /* scam_tolerant */
   70         7,                      /* adapter_scsi_id */
   71         0,                      /* bios_boot_delay */
   72         3,                      /* scsi_reset_delay */
   73         0,                      /* bios_id_lun */
   74         0,                      /* termination */
   75         0,                      /* reserved1 */
   76         {                       /* Bios Ctrl */
   77           1, 1, 1, 1, 1,
   78           1, 1, 1, 1, 1,
   79         },
   80         0xFFFF,                 /* ultra_able */
   81         0,                      /* reserved2 */
   82         ADW_DEF_MAX_HOST_QNG,   /* max_host_qng */
   83         ADW_DEF_MAX_DVC_QNG,    /* max_dvc_qng */
   84         0,                      /* dvc_cntl */
   85         0,                      /* bug_fix */
   86         { 0, 0, 0 },            /* serial_number */
   87         0,                      /* check_sum */
   88         {                       /* oem_name[16] */
   89           0, 0, 0, 0, 0, 0, 0, 0,
   90           0, 0, 0, 0, 0, 0, 0, 0
   91         },
   92         0,                      /* dvc_err_code */
   93         0,                      /* adv_err_code */
   94         0,                      /* adv_err_addr */
   95         0,                      /* saved_dvc_err_code */
   96         0,                      /* saved_adv_err_code */
   97         0,                      /* saved_adv_err_addr */
   98         0                       /* num_of_err */
   99 };
  100 
  101 static u_int16_t        adw_eeprom_read_16(struct adw_softc *adw, int addr);
  102 static void             adw_eeprom_write_16(struct adw_softc *adw, int addr,
  103                                             u_int data);
  104 static void             adw_eeprom_wait(struct adw_softc *adw);
  105 
  106 int
  107 adw_find_signature(bus_space_tag_t tag, bus_space_handle_t bsh)
  108 {
  109         if (bus_space_read_1(tag, bsh, ADW_SIGNATURE_BYTE) == ADW_CHIP_ID_BYTE
  110          && bus_space_read_2(tag, bsh, ADW_SIGNATURE_WORD) == ADW_CHIP_ID_WORD)
  111                 return (1);
  112         return (0);
  113 }
  114 
  115 /*
  116  * Reset Chip.
  117  */
  118 void
  119 adw_reset_chip(struct adw_softc *adw)
  120 {
  121         adw_outw(adw, ADW_CTRL_REG, ADW_CTRL_REG_CMD_RESET);
  122         DELAY(100);
  123         adw_outw(adw, ADW_CTRL_REG, ADW_CTRL_REG_CMD_WR_IO_REG);
  124 
  125         /*
  126          * Initialize Chip registers.
  127          */
  128         adw_outb(adw, ADW_MEM_CFG,
  129                  adw_inb(adw, ADW_MEM_CFG) | ADW_MEM_CFG_RAM_SZ_8KB);
  130 
  131         adw_outw(adw, ADW_SCSI_CFG1,
  132                  adw_inw(adw, ADW_SCSI_CFG1) & ~ADW_SCSI_CFG1_BIG_ENDIAN);
  133 
  134         /*
  135          * Setting the START_CTL_EM_FU 3:2 bits sets a FIFO threshold
  136          * of 128 bytes. This register is only accessible to the host.
  137          */
  138         adw_outb(adw, ADW_DMA_CFG0,
  139                  ADW_DMA_CFG0_START_CTL_EM_FU|ADW_DMA_CFG0_READ_CMD_MRM);
  140 }
  141 
  142 /*
  143  * Read the specified EEPROM location
  144  */
  145 static u_int16_t
  146 adw_eeprom_read_16(struct adw_softc *adw, int addr)
  147 {
  148         adw_outw(adw, ADW_EEP_CMD, ADW_EEP_CMD_READ | addr);
  149         adw_eeprom_wait(adw);
  150         return (adw_inw(adw, ADW_EEP_DATA));
  151 }
  152 
  153 static void
  154 adw_eeprom_write_16(struct adw_softc *adw, int addr, u_int data)
  155 {
  156         adw_outw(adw, ADW_EEP_DATA, data);
  157         adw_outw(adw, ADW_EEP_CMD, ADW_EEP_CMD_WRITE | addr);
  158         adw_eeprom_wait(adw);
  159 }
  160 
  161 /*
  162  * Wait for and EEPROM command to complete
  163  */
  164 static void
  165 adw_eeprom_wait(struct adw_softc *adw)
  166 {
  167         int i;
  168 
  169         for (i = 0; i < ADW_EEP_DELAY_MS; i++) {
  170                 if ((adw_inw(adw, ADW_EEP_CMD) & ADW_EEP_CMD_DONE) != 0)
  171                         break;
  172                 DELAY(1000);
  173         }
  174         if (i == ADW_EEP_DELAY_MS)
  175                 panic("%s: Timedout Reading EEPROM", adw_name(adw));
  176 }
  177 
  178 /*
  179  * Read EEPROM configuration into the specified buffer.
  180  *
  181  * Return a checksum based on the EEPROM configuration read.
  182  */
  183 u_int16_t
  184 adw_eeprom_read(struct adw_softc *adw, struct adw_eeprom *eep_buf)
  185 {
  186         u_int16_t *wbuf;
  187         u_int16_t  wval;
  188         u_int16_t  chksum;
  189         int        eep_addr;
  190 
  191         wbuf = (u_int16_t *)eep_buf;
  192         chksum = 0;
  193 
  194         for (eep_addr = ADW_EEP_DVC_CFG_BEGIN;
  195              eep_addr < ADW_EEP_DVC_CFG_END;
  196              eep_addr++, wbuf++) {
  197                 wval = adw_eeprom_read_16(adw, eep_addr);
  198                 chksum += wval;
  199                 *wbuf = wval;
  200         }
  201 
  202         /* checksum field is not counted in the checksum */
  203         *wbuf = adw_eeprom_read_16(adw, eep_addr);
  204         wbuf++;
  205         
  206         /* Driver seeprom variables are not included in the checksum */
  207         for (eep_addr = ADW_EEP_DVC_CTL_BEGIN;
  208              eep_addr < ADW_EEP_MAX_WORD_ADDR;
  209              eep_addr++, wbuf++)
  210                 *wbuf = adw_eeprom_read_16(adw, eep_addr);
  211 
  212         return (chksum);
  213 }
  214 
  215 void
  216 adw_eeprom_write(struct adw_softc *adw, struct adw_eeprom *eep_buf)
  217 {
  218         u_int16_t *wbuf;
  219         u_int16_t  addr;
  220         u_int16_t  chksum;
  221 
  222         wbuf = (u_int16_t *)eep_buf;
  223         chksum = 0;
  224 
  225         adw_outw(adw, ADW_EEP_CMD, ADW_EEP_CMD_WRITE_ABLE);
  226         adw_eeprom_wait(adw);
  227 
  228         /*
  229          * Write EEPROM until checksum.
  230          */
  231         for (addr = ADW_EEP_DVC_CFG_BEGIN;
  232              addr < ADW_EEP_DVC_CFG_END; addr++, wbuf++) {
  233                 chksum += *wbuf;
  234                 adw_eeprom_write_16(adw, addr, *wbuf);
  235         }
  236 
  237         /*
  238          * Write calculated EEPROM checksum
  239          */
  240         adw_eeprom_write_16(adw, addr, chksum);
  241 
  242         /* skip over buffer's checksum */
  243         wbuf++;
  244 
  245         /*
  246          * Write the rest.
  247          */
  248         for (addr = ADW_EEP_DVC_CTL_BEGIN;
  249              addr < ADW_EEP_MAX_WORD_ADDR; addr++, wbuf++)
  250                 adw_eeprom_write_16(adw, addr, *wbuf);
  251 
  252         adw_outw(adw, ADW_EEP_CMD, ADW_EEP_CMD_WRITE_DISABLE);
  253         adw_eeprom_wait(adw);
  254 }
  255 
  256 int
  257 adw_init_chip(struct adw_softc *adw, u_int term_scsicfg1)
  258 {
  259         u_int8_t   biosmem[ADW_MC_BIOSLEN];
  260         u_int16_t *mcodebuf;
  261         u_int      addr;
  262         u_int      end_addr;
  263         u_int      checksum;
  264         u_int      scsicfg1;
  265         u_int      i;
  266 
  267         /*
  268          * Save the RISC memory BIOS region before writing the microcode.
  269          * The BIOS may already be loaded and using its RISC LRAM region
  270          * so its region must be saved and restored.
  271          */
  272         for (addr = 0; addr < ADW_MC_BIOSLEN; addr++)
  273                 biosmem[addr] = adw_lram_read_8(adw, ADW_MC_BIOSMEM + addr);
  274 
  275         /*
  276          * Load the Microcode.  Casting here was less work than
  277          * reformatting the supplied microcode into an array of
  278          * 16bit values...
  279          */
  280         mcodebuf = (u_int16_t *)adw_mcode;
  281         adw_outw(adw, ADW_RAM_ADDR, 0);
  282         for (addr = 0; addr < adw_mcode_size/2; addr++)
  283                 adw_outw(adw, ADW_RAM_DATA, mcodebuf[addr]);
  284 
  285         /*
  286          * Clear the rest of LRAM.
  287          */
  288         for (; addr < ADW_CONDOR_MEMSIZE/2; addr++)
  289                 adw_outw(adw, ADW_RAM_DATA, 0);
  290 
  291         /*
  292          * Verify the microcode checksum.
  293          */
  294         checksum = 0;
  295         adw_outw(adw, ADW_RAM_ADDR, 0);
  296         for (addr = 0; addr < adw_mcode_size/2; addr++)
  297                 checksum += adw_inw(adw, ADW_RAM_DATA);
  298 
  299         if (checksum != adw_mcode_chksum) {
  300                 printf("%s: Firmware load failed!\n", adw_name(adw));
  301                 return (-1);
  302         }
  303 
  304         /*
  305          * Restore the RISC memory BIOS region.
  306          */
  307         for (addr = 0; addr < ADW_MC_BIOSLEN; addr++)
  308                 adw_lram_write_8(adw, addr + ADW_MC_BIOSLEN, biosmem[addr]);
  309 
  310         /*
  311          * Calculate and write the microcode code checksum to
  312          * the microcode code checksum location.
  313          */
  314         addr = adw_lram_read_16(adw, ADW_MC_CODE_BEGIN_ADDR) / 2;
  315         end_addr = adw_lram_read_16(adw, ADW_MC_CODE_END_ADDR) / 2;
  316         checksum = 0;
  317         for (; addr < end_addr; addr++)
  318                 checksum += mcodebuf[addr];
  319         adw_lram_write_16(adw, ADW_MC_CODE_CHK_SUM, checksum);
  320 
  321         /*
  322          * Initialize microcode operating variables
  323          */
  324         adw_lram_write_16(adw, ADW_MC_ADAPTER_SCSI_ID, adw->initiator_id);
  325 
  326         /*
  327          * Leave WDTR and SDTR negotiation disabled until the XPT has
  328          * informed us of device capabilities, but do set the ultra mask
  329          * in case we receive an SDTR request from the target before we
  330          * negotiate.  We turn on tagged queuing at the microcode level
  331          * for all devices, and modulate this on a per command basis.
  332          */
  333         adw_lram_write_16(adw, ADW_MC_ULTRA_ABLE, adw->user_ultra);
  334         adw_lram_write_16(adw, ADW_MC_DISC_ENABLE, adw->user_discenb);
  335         adw_lram_write_16(adw, ADW_MC_TAGQNG_ABLE, ~0);
  336 
  337         /*
  338          * Set SCSI_CFG0 Microcode Default Value.
  339          *
  340          * The microcode will set the SCSI_CFG0 register using this value
  341          * after it is started.
  342          */
  343         adw_lram_write_16(adw, ADW_MC_DEFAULT_SCSI_CFG0,
  344                           ADW_SCSI_CFG0_PARITY_EN|ADW_SCSI_CFG0_SEL_TMO_LONG|
  345                           ADW_SCSI_CFG0_OUR_ID_EN|adw->initiator_id);
  346   
  347         /*
  348          * Determine SCSI_CFG1 Microcode Default Value.
  349          *
  350          * The microcode will set the SCSI_CFG1 register using this value
  351          * after it is started below.
  352          */
  353         scsicfg1 = adw_inw(adw, ADW_SCSI_CFG1);
  354 
  355         /*
  356          * If all three connectors are in use, return an error.
  357          */
  358         if ((scsicfg1 & ADW_SCSI_CFG1_ILLEGAL_CABLE_CONF_A_MASK) == 0
  359          || (scsicfg1 & ADW_SCSI_CFG1_ILLEGAL_CABLE_CONF_B_MASK) == 0) {
  360                 printf("%s: Illegal Cable Config!\n", adw_name(adw));
  361                 printf("%s: Only Two Ports may be used at a time!\n",
  362                        adw_name(adw));
  363                 return (-1);
  364         }
  365 
  366         /*
  367          * If the internal narrow cable is reversed all of the SCSI_CTRL
  368          * register signals will be set. Check for and return an error if
  369          * this condition is found.
  370          */
  371         if ((adw_inw(adw, ADW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
  372                 printf("%s: Illegal Cable Config!\n", adw_name(adw));
  373                 printf("%s: Internal cable is reversed!\n", adw_name(adw));
  374                 return (-1);
  375         }
  376 
  377         /*
  378          * If this is a differential board and a single-ended device
  379          * is attached to one of the connectors, return an error.
  380          */
  381         if ((scsicfg1 & ADW_SCSI_CFG1_DIFF_MODE) != 0
  382          && (scsicfg1 & ADW_SCSI_CFG1_DIFF_SENSE) == 0) {
  383                 printf("%s: A Single Ended Device is attached to our "
  384                        "differential bus!\n", adw_name(adw));
  385                 return (-1);
  386         }
  387 
  388         /*
  389          * Perform automatic termination control if desired.
  390          */
  391         if (term_scsicfg1 == 0) {
  392                 switch(scsicfg1 & ADW_SCSI_CFG1_CABLE_DETECT) {
  393                 case (ADW_SCSI_CFG1_INT16_MASK|ADW_SCSI_CFG1_INT8_MASK):
  394                 case (ADW_SCSI_CFG1_INT16_MASK|
  395                       ADW_SCSI_CFG1_INT8_MASK|ADW_SCSI_CFG1_EXT8_MASK):
  396                 case (ADW_SCSI_CFG1_INT16_MASK|
  397                       ADW_SCSI_CFG1_INT8_MASK|ADW_SCSI_CFG1_EXT16_MASK):
  398                 case (ADW_SCSI_CFG1_INT16_MASK|
  399                       ADW_SCSI_CFG1_EXT8_MASK|ADW_SCSI_CFG1_EXT16_MASK):
  400                 case (ADW_SCSI_CFG1_INT8_MASK|
  401                       ADW_SCSI_CFG1_EXT8_MASK|ADW_SCSI_CFG1_EXT16_MASK):
  402                 case (ADW_SCSI_CFG1_INT16_MASK|ADW_SCSI_CFG1_INT8_MASK|
  403                       ADW_SCSI_CFG1_EXT8_MASK|ADW_SCSI_CFG1_EXT16_MASK):
  404                         /* Two out of three cables missing.  Both on. */
  405                         term_scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_L
  406                                       |  ADW_SCSI_CFG1_TERM_CTL_H;
  407                         break;
  408                 case (ADW_SCSI_CFG1_INT16_MASK):
  409                 case (ADW_SCSI_CFG1_INT16_MASK|ADW_SCSI_CFG1_EXT8_MASK):
  410                 case (ADW_SCSI_CFG1_INT16_MASK|ADW_SCSI_CFG1_EXT16_MASK):
  411                 case (ADW_SCSI_CFG1_INT8_MASK|ADW_SCSI_CFG1_EXT16_MASK):
  412                 case (ADW_SCSI_CFG1_EXT8_MASK|ADW_SCSI_CFG1_EXT16_MASK):
  413                         /* No two 16bit cables present.  High on. */
  414                         term_scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_H;
  415                         break;
  416                 case (ADW_SCSI_CFG1_INT8_MASK):
  417                 case (ADW_SCSI_CFG1_INT8_MASK|ADW_SCSI_CFG1_EXT8_MASK):
  418                         /* Wide -> Wide or Narrow -> Wide. Both off */
  419                         break;
  420                 }
  421         }
  422 
  423         /* Tell the user about our decission */
  424         switch (term_scsicfg1 & ADW_SCSI_CFG1_TERM_CTL_MASK) {
  425         case ADW_SCSI_CFG1_TERM_CTL_MASK:
  426                 printf("High & Low Termination Enabled, ");
  427                 break;
  428         case ADW_SCSI_CFG1_TERM_CTL_H:
  429                 printf("High Termination Enabled, ");
  430                 break;
  431         case ADW_SCSI_CFG1_TERM_CTL_L:
  432                 printf("Low Termination Enabled, ");
  433                 break;
  434         default:
  435                 break;
  436         }
  437 
  438         /*
  439          * Invert the TERM_CTL_H and TERM_CTL_L bits and then
  440          * set 'scsicfg1'. The TERM_POL bit does not need to be
  441          * referenced, because the hardware internally inverts
  442          * the Termination High and Low bits if TERM_POL is set.
  443          */
  444         term_scsicfg1 = ~term_scsicfg1 & ADW_SCSI_CFG1_TERM_CTL_MASK;
  445         scsicfg1 &= ~ADW_SCSI_CFG1_TERM_CTL_MASK;
  446         scsicfg1 |= term_scsicfg1 | ADW_SCSI_CFG1_TERM_CTL_MANUAL;
  447 
  448         /*
  449          * Set SCSI_CFG1 Microcode Default Value
  450          *
  451          * Set filter value and possibly modified termination control
  452          * bits in the Microcode SCSI_CFG1 Register Value.
  453          *
  454          * The microcode will set the SCSI_CFG1 register using this value
  455          * after it is started below.
  456          */
  457         adw_lram_write_16(adw, ADW_MC_DEFAULT_SCSI_CFG1,
  458                           scsicfg1 | ADW_SCSI_CFG1_FLTR_11_TO_20NS);
  459 
  460         /*
  461          * Only accept selections on our initiator target id.
  462          * This may change in target mode scenarios...
  463          */
  464         adw_lram_write_16(adw, ADW_MC_DEFAULT_SEL_MASK,
  465                           (0x01 << adw->initiator_id));
  466 
  467         /*
  468          * Link all the RISC Queue Lists together in a doubly-linked
  469          * NULL terminated list.
  470          *
  471          * Skip the NULL (0) queue which is not used.
  472          */
  473         for (i = 1, addr = ADW_MC_RISC_Q_LIST_BASE + ADW_MC_RISC_Q_LIST_SIZE;
  474              i < ADW_MC_RISC_Q_TOTAL_CNT;
  475              i++, addr += ADW_MC_RISC_Q_LIST_SIZE) {
  476 
  477                 /*
  478                  * Set the current RISC Queue List's
  479                  * RQL_FWD and RQL_BWD pointers in a
  480                  * one word write and set the state
  481                  * (RQL_STATE) to free.
  482                  */
  483                 adw_lram_write_16(adw, addr, ((i + 1) | ((i - 1) << 8)));
  484                 adw_lram_write_8(adw, addr + RQL_STATE, ADW_MC_QS_FREE);
  485         }
  486 
  487         /*
  488          * Set the Host and RISC Queue List pointers.
  489          *
  490          * Both sets of pointers are initialized with the same values:
  491          * ADW_MC_RISC_Q_FIRST(0x01) and ADW_MC_RISC_Q_LAST (0xFF).
  492          */
  493         adw_lram_write_8(adw, ADW_MC_HOST_NEXT_READY, ADW_MC_RISC_Q_FIRST);
  494         adw_lram_write_8(adw, ADW_MC_HOST_NEXT_DONE, ADW_MC_RISC_Q_LAST);
  495 
  496         adw_lram_write_8(adw, ADW_MC_RISC_NEXT_READY, ADW_MC_RISC_Q_FIRST);
  497         adw_lram_write_8(adw, ADW_MC_RISC_NEXT_DONE, ADW_MC_RISC_Q_LAST);
  498 
  499         /*
  500          * Set up the last RISC Queue List (255) with a NULL forward pointer.
  501          */
  502         adw_lram_write_16(adw, addr, (ADW_MC_NULL_Q + ((i - 1) << 8)));
  503         adw_lram_write_8(adw, addr + RQL_STATE, ADW_MC_QS_FREE);
  504 
  505         adw_outb(adw, ADW_INTR_ENABLES,
  506                  ADW_INTR_ENABLE_HOST_INTR|ADW_INTR_ENABLE_GLOBAL_INTR);
  507 
  508         adw_outw(adw, ADW_PC, adw_lram_read_16(adw, ADW_MC_CODE_BEGIN_ADDR));
  509 
  510         return (0);
  511 }
  512 
  513 /*
  514  * Send an idle command to the chip and optionally wait for completion.
  515  */
  516 void
  517 adw_idle_cmd_send(struct adw_softc *adw, adw_idle_cmd_t cmd, u_int parameter)
  518 {
  519         int s;
  520 
  521         adw->idle_command_cmp = 0;
  522 
  523         s = splcam();   
  524 
  525         if (adw->idle_cmd != ADW_IDLE_CMD_COMPLETED)
  526                 printf("%s: Warning! Overlapped Idle Commands Attempted\n",
  527                        adw_name(adw));
  528         adw->idle_cmd = cmd;
  529         adw->idle_cmd_param = parameter;
  530 
  531         /*
  532          * Write the idle command value after the idle command parameter
  533          * has been written to avoid a race condition. If the order is not
  534          * followed, the microcode may process the idle command before the
  535          * parameters have been written to LRAM.
  536          */
  537         adw_lram_write_16(adw, ADW_MC_IDLE_PARA_STAT, parameter);
  538         adw_lram_write_16(adw, ADW_MC_IDLE_CMD, cmd);
  539         splx(s);
  540 }
  541 
  542 /* Wait for an idle command to complete */
  543 adw_idle_cmd_status_t
  544 adw_idle_cmd_wait(struct adw_softc *adw)
  545 {
  546         u_int                 timeout;
  547         adw_idle_cmd_status_t status;
  548         int                   s;
  549 
  550         /* Wait for up to 10 seconds for the command to complete */
  551         timeout = 10000;
  552         while (--timeout) {
  553                 if (adw->idle_command_cmp != 0)
  554                         break;
  555                 DELAY(1000);
  556         }
  557 
  558         if (timeout == 0)
  559                 panic("%s: Idle Command Timed Out!\n", adw_name(adw));
  560         s = splcam();
  561         status = adw_lram_read_16(adw, ADW_MC_IDLE_PARA_STAT);
  562         splx(s);
  563         return (status);
  564 }

Cache object: 51616af3bbce7d724601a286b229ffc5


[ 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.