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/ic/aic7xxx_seeprom.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 /*      $NetBSD: aic7xxx_seeprom.c,v 1.14 2022/09/25 18:43:32 thorpej Exp $     */
    2 
    3 /*
    4  * Product specific probe and attach routines for:
    5  *      3940, 2940, aic7895, aic7890, aic7880,
    6  *      aic7870, aic7860 and aic7850 SCSI controllers
    7  *
    8  * Copyright (c) 1994-2001 Justin T. Gibbs.
    9  * Copyright (c) 2000-2001 Adaptec Inc.
   10  * All rights reserved.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions, and the following disclaimer,
   17  *    without modification.
   18  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
   19  *    substantially similar to the "NO WARRANTY" disclaimer below
   20  *    ("Disclaimer") and any redistribution must be conditioned upon
   21  *    including a substantially similar Disclaimer requirement for further
   22  *    binary redistribution.
   23  * 3. Neither the names of the above-listed copyright holders nor the names
   24  *    of any contributors may be used to endorse or promote products derived
   25  *    from this software without specific prior written permission.
   26  *
   27  * Alternatively, this software may be distributed under the terms of the
   28  * GNU General Public License ("GPL") version 2 as published by the Free
   29  * Software Foundation.
   30  *
   31  * NO WARRANTY
   32  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   33  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   34  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
   35  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   36  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   40  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
   41  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   42  * POSSIBILITY OF SUCH DAMAGES.
   43  *
   44  * This file was originally split off from the PCI code by
   45  * Jason Thorpe <thorpej@NetBSD.org>. This version was split off
   46  * from the FreeBSD source file aic7xxx_pci.c by Frank van der Linden
   47  * <fvdl@NetBSD.org>
   48  *
   49  * $Id: aic7xxx_seeprom.c,v 1.14 2022/09/25 18:43:32 thorpej Exp $
   50  *
   51  * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_pci.c,v 1.22 2003/01/20 20:44:55 gibbs Exp $
   52  */
   53 
   54 #include <sys/cdefs.h>
   55 __KERNEL_RCSID(0, "$NetBSD: aic7xxx_seeprom.c,v 1.14 2022/09/25 18:43:32 thorpej Exp $");
   56 
   57 #include <sys/param.h>
   58 #include <sys/systm.h>
   59 #include <sys/kernel.h>
   60 #include <sys/queue.h>
   61 #include <sys/device.h>
   62 #include <sys/reboot.h>         /* for AB_* needed by bootverbose */
   63 
   64 #include <sys/bus.h>
   65 #include <sys/intr.h>
   66 
   67 #include <dev/scsipi/scsi_all.h>
   68 #include <dev/scsipi/scsipi_all.h>
   69 #include <dev/scsipi/scsiconf.h>
   70 
   71 #include <dev/ic/aic7xxx_osm.h>
   72 #include <dev/ic/aic7xxx_inline.h>
   73 
   74 #include <dev/ic/smc93cx6var.h>
   75 
   76 #define DEVCONFIG       0x40
   77 #define STPWLEVEL       0x00000002
   78 
   79 static void configure_termination(struct ahc_softc *,
   80                                   struct seeprom_descriptor *, u_int, u_int *);
   81 static int verify_seeprom_cksum(struct seeprom_config *sc);
   82 
   83 static void ahc_new_term_detect(struct ahc_softc *, int *, int *, int *,
   84                                    int *, int *);
   85 static void aic787X_cable_detect(struct ahc_softc *, int *, int *, int *,
   86                                  int *);
   87 static void aic785X_cable_detect(struct ahc_softc *, int *, int *, int *);
   88 static void write_brdctl(struct ahc_softc *, u_int8_t);
   89 static u_int8_t read_brdctl(struct ahc_softc *);
   90 static void ahc_parse_pci_eeprom(struct ahc_softc *, struct seeprom_config *);
   91 
   92 /*
   93  * Check the external port logic for a serial eeprom
   94  * and termination/cable detection contrls.
   95  */
   96 void
   97 ahc_check_extport(struct ahc_softc *ahc, u_int *sxfrctl1)
   98 {
   99         struct  seeprom_descriptor sd;
  100         struct  seeprom_config *sc;
  101         int     have_seeprom;
  102         int     have_autoterm;
  103 
  104         sd.sd_tag = ahc->tag;
  105         sd.sd_bsh = ahc->bsh;
  106         sd.sd_regsize = 1;
  107         sd.sd_control_offset = SEECTL;
  108         sd.sd_status_offset = SEECTL;
  109         sd.sd_dataout_offset = SEECTL;
  110         sc = ahc->seep_config;
  111 
  112         /*
  113          * For some multi-channel devices, the c46 is simply too
  114          * small to work.  For the other controller types, we can
  115          * get our information from either SEEPROM type.  Set the
  116          * type to start our probe with accordingly.
  117          */
  118         if (ahc->flags & AHC_LARGE_SEEPROM)
  119                 sd.sd_chip = C56_66;
  120         else
  121                 sd.sd_chip = C46;
  122 
  123         sd.sd_MS = SEEMS;
  124         sd.sd_RDY = SEERDY;
  125         sd.sd_CS = SEECS;
  126         sd.sd_CK = SEECK;
  127         sd.sd_DO = SEEDO;
  128         sd.sd_DI = SEEDI;
  129 
  130         have_seeprom = ahc_acquire_seeprom(ahc, &sd);
  131         if (have_seeprom) {
  132 
  133                 if (bootverbose)
  134                         printf("%s: Reading SEEPROM...", ahc_name(ahc));
  135 
  136                 for (;;) {
  137                         u_int start_addr;
  138 
  139                         start_addr = 32 * (ahc->channel - 'A');
  140                         have_seeprom = read_seeprom(&sd, (uint16_t *)sc,
  141                                                         start_addr,
  142                                                         sizeof(*sc)/2);
  143 
  144                         if (have_seeprom)
  145                                 have_seeprom = verify_seeprom_cksum(sc);
  146 
  147                         if (have_seeprom != 0 || sd.sd_chip == C56_66) {
  148                                 if (bootverbose) {
  149                                         if (have_seeprom == 0)
  150                                                 printf ("checksum error\n");
  151                                         else
  152                                                 printf ("done.\n");
  153                                 }
  154                                 break;
  155                         }
  156                         sd.sd_chip = C56_66;
  157                 }
  158                 ahc_release_seeprom(&sd);
  159         }
  160 
  161         if (!have_seeprom) {
  162                 /*
  163                  * Pull scratch ram settings and treat them as
  164                  * if they are the contents of an seeprom if
  165                  * the 'ADPT' signature is found in SCB2.
  166                  * We manually compose the data as 16bit values
  167                  * to avoid endian issues.
  168                  */
  169                 ahc_outb(ahc, SCBPTR, 2);
  170                 if (ahc_inb(ahc, SCB_BASE) == 'A'
  171                  && ahc_inb(ahc, SCB_BASE + 1) == 'D'
  172                  && ahc_inb(ahc, SCB_BASE + 2) == 'P'
  173                  && ahc_inb(ahc, SCB_BASE + 3) == 'T') {
  174                         uint16_t *sc_data;
  175                         int       i;
  176 
  177                         sc_data = (uint16_t *)sc;
  178                         for (i = 0; i < 32; i++, sc_data++) {
  179                                 int     j;
  180 
  181                                 j = i * 2;
  182                                 *sc_data = ahc_inb(ahc, SRAM_BASE + j)
  183                                          | ahc_inb(ahc, SRAM_BASE + j + 1) << 8;
  184                         }
  185                         have_seeprom = verify_seeprom_cksum(sc);
  186                         if (have_seeprom)
  187                                 ahc->flags |= AHC_SCB_CONFIG_USED;
  188                 }
  189                 /*
  190                  * Clear any SCB parity errors in case this data and
  191                  * its associated parity was not initialized by the BIOS
  192                  */
  193                 ahc_outb(ahc, CLRINT, CLRPARERR);
  194                 ahc_outb(ahc, CLRINT, CLRBRKADRINT);
  195         }
  196 
  197         if (!have_seeprom) {
  198                 if (bootverbose)
  199                         printf("%s: No SEEPROM available.\n", ahc_name(ahc));
  200                 ahc->flags |= AHC_USEDEFAULTS;
  201                 free(ahc->seep_config, M_DEVBUF);
  202                 ahc->seep_config = NULL;
  203                 sc = NULL;
  204         } else {
  205                 ahc_parse_pci_eeprom(ahc, sc);
  206         }
  207 
  208         /*
  209          * Cards that have the external logic necessary to talk to
  210          * a SEEPROM, are almost certain to have the remaining logic
  211          * necessary for auto-termination control.  This assumption
  212          * hasn't failed yet...
  213          */
  214         have_autoterm = have_seeprom;
  215 
  216         /*
  217          * Some low-cost chips have SEEPROM and auto-term control built
  218          * in, instead of using a GAL.  They can tell us directly
  219          * if the termination logic is enabled.
  220          */
  221         if ((ahc->features & AHC_SPIOCAP) != 0) {
  222                 if ((ahc_inb(ahc, SPIOCAP) & SSPIOCPS) == 0)
  223                         have_autoterm = FALSE;
  224         }
  225 
  226         if (have_autoterm) {
  227                 ahc_acquire_seeprom(ahc, &sd);
  228                 configure_termination(ahc, &sd, sc->adapter_control, sxfrctl1);
  229                 ahc_release_seeprom(&sd);
  230         } else if (have_seeprom) {
  231                 *sxfrctl1 &= ~STPWEN;
  232                 if ((sc->adapter_control & CFSTERM) != 0)
  233                         *sxfrctl1 |= STPWEN;
  234                 if (bootverbose)
  235                         printf("%s: Low byte termination %sabled\n",
  236                                ahc_name(ahc),
  237                                (*sxfrctl1 & STPWEN) ? "en" : "dis");
  238         }
  239 }
  240 
  241 static void
  242 ahc_parse_pci_eeprom(struct ahc_softc *ahc, struct seeprom_config *sc)
  243 {
  244         /*
  245          * Put the data we've collected down into SRAM
  246          * where ahc_init will find it.
  247          */
  248         int      i;
  249         int      max_targ = sc->max_targets & CFMAXTARG;
  250         u_int    scsi_conf;
  251         uint16_t discenable;
  252         uint16_t ultraenb;
  253 
  254         discenable = 0;
  255         ultraenb = 0;
  256         if ((sc->adapter_control & CFULTRAEN) != 0) {
  257                 /*
  258                  * Determine if this adapter has a "newstyle"
  259                  * SEEPROM format.
  260                  */
  261                 for (i = 0; i < max_targ; i++) {
  262                         if ((sc->device_flags[i] & CFSYNCHISULTRA) != 0) {
  263                                 ahc->flags |= AHC_NEWEEPROM_FMT;
  264                                 break;
  265                         }
  266                 }
  267         }
  268 
  269         for (i = 0; i < max_targ; i++) {
  270                 u_int     scsirate;
  271                 uint16_t target_mask;
  272 
  273                 target_mask = 0x01 << i;
  274                 if (sc->device_flags[i] & CFDISC)
  275                         discenable |= target_mask;
  276                 if ((ahc->flags & AHC_NEWEEPROM_FMT) != 0) {
  277                         if ((sc->device_flags[i] & CFSYNCHISULTRA) != 0)
  278                                 ultraenb |= target_mask;
  279                 } else if ((sc->adapter_control & CFULTRAEN) != 0) {
  280                         ultraenb |= target_mask;
  281                 }
  282                 if ((sc->device_flags[i] & CFXFER) == 0x04
  283                     && (ultraenb & target_mask) != 0) {
  284                         /* Treat 10MHz as a non-ultra speed */
  285                         sc->device_flags[i] &= ~CFXFER;
  286                         ultraenb &= ~target_mask;
  287                 }
  288                 if ((ahc->features & AHC_ULTRA2) != 0) {
  289                         u_int offset;
  290 
  291                         if (sc->device_flags[i] & CFSYNCH)
  292                                 offset = MAX_OFFSET_ULTRA2;
  293                         else
  294                                 offset = 0;
  295                         ahc_outb(ahc, TARG_OFFSET + i, offset);
  296 
  297                         /*
  298                          * The ultra enable bits contain the
  299                          * high bit of the ultra2 sync rate
  300                          * field.
  301                          */
  302                         scsirate = (sc->device_flags[i] & CFXFER)
  303                                  | ((ultraenb & target_mask) ? 0x8 : 0x0);
  304                         if (sc->device_flags[i] & CFWIDEB)
  305                                 scsirate |= WIDEXFER;
  306                 } else {
  307                         scsirate = (sc->device_flags[i] & CFXFER) << 4;
  308                         if (sc->device_flags[i] & CFSYNCH)
  309                                 scsirate |= SOFS;
  310                         if (sc->device_flags[i] & CFWIDEB)
  311                                 scsirate |= WIDEXFER;
  312                 }
  313                 ahc_outb(ahc, TARG_SCSIRATE + i, scsirate);
  314         }
  315         ahc->our_id = sc->brtime_id & CFSCSIID;
  316 
  317         scsi_conf = (ahc->our_id & 0x7);
  318         if (sc->adapter_control & CFSPARITY)
  319                 scsi_conf |= ENSPCHK;
  320         if (sc->adapter_control & CFRESETB)
  321                 scsi_conf |= RESET_SCSI;
  322 
  323         ahc->flags |= (sc->adapter_control & CFBOOTCHAN) >> CFBOOTCHANSHIFT;
  324 
  325         if (sc->bios_control & CFEXTEND)
  326                 ahc->flags |= AHC_EXTENDED_TRANS_A;
  327 
  328         if (sc->bios_control & CFBIOSEN)
  329                 ahc->flags |= AHC_BIOS_ENABLED;
  330         if (ahc->features & AHC_ULTRA
  331             && (ahc->flags & AHC_NEWEEPROM_FMT) == 0) {
  332                 /* Should we enable Ultra mode? */
  333                 if (!(sc->adapter_control & CFULTRAEN))
  334                         /* Treat us as a non-ultra card */
  335                         ultraenb = 0;
  336         }
  337 
  338         if (sc->signature == CFSIGNATURE
  339             || sc->signature == CFSIGNATURE2) {
  340                 uint32_t devconfig;
  341 
  342                 /* Honor the STPWLEVEL settings */
  343                 devconfig = pci_conf_read(ahc->bd->pc, ahc->bd->tag, DEVCONFIG);
  344                 devconfig &= ~STPWLEVEL;
  345                 if ((sc->bios_control & CFSTPWLEVEL) != 0)
  346                         devconfig |= STPWLEVEL;
  347                 pci_conf_write(ahc->bd->pc, ahc->bd->tag, DEVCONFIG,  devconfig);
  348         }
  349         /* Set SCSICONF info */
  350         ahc_outb(ahc, SCSICONF, scsi_conf);
  351         ahc_outb(ahc, DISC_DSB, ~(discenable & 0xff));
  352         ahc_outb(ahc, DISC_DSB + 1, ~((discenable >> 8) & 0xff));
  353         ahc_outb(ahc, ULTRA_ENB, ultraenb & 0xff);
  354         ahc_outb(ahc, ULTRA_ENB + 1, (ultraenb >> 8) & 0xff);
  355 }
  356 
  357 static void
  358 configure_termination(struct ahc_softc *ahc,
  359                       struct seeprom_descriptor *sd,
  360                       u_int adapter_control,
  361                       u_int *sxfrctl1)
  362 {
  363         uint8_t brddat;
  364 
  365         brddat = 0;
  366 
  367         /*
  368          * Update the settings in sxfrctl1 to match the
  369          * termination settings
  370          */
  371         *sxfrctl1 = 0;
  372 
  373         /*
  374          * SEECS must be on for the GALS to latch
  375          * the data properly.  Be sure to leave MS
  376          * on or we will release the seeprom.
  377          */
  378         SEEPROM_OUTB(sd, sd->sd_MS | sd->sd_CS);
  379         if ((adapter_control & CFAUTOTERM) != 0
  380          || (ahc->features & AHC_NEW_TERMCTL) != 0) {
  381                 int internal50_present;
  382                 int internal68_present;
  383                 int externalcable_present;
  384                 int eeprom_present;
  385                 int enableSEC_low;
  386                 int enableSEC_high;
  387                 int enablePRI_low;
  388                 int enablePRI_high;
  389                 int sum;
  390 
  391                 enableSEC_low = 0;
  392                 enableSEC_high = 0;
  393                 enablePRI_low = 0;
  394                 enablePRI_high = 0;
  395                 if ((ahc->features & AHC_NEW_TERMCTL) != 0) {
  396                         ahc_new_term_detect(ahc, &enableSEC_low,
  397                                             &enableSEC_high,
  398                                             &enablePRI_low,
  399                                             &enablePRI_high,
  400                                             &eeprom_present);
  401                         if ((adapter_control & CFSEAUTOTERM) == 0) {
  402                                 if (bootverbose)
  403                                         printf("%s: Manual SE Termination\n",
  404                                                ahc_name(ahc));
  405                                 enableSEC_low = (adapter_control & CFSELOWTERM);
  406                                 enableSEC_high =
  407                                     (adapter_control & CFSEHIGHTERM);
  408                         }
  409                         if ((adapter_control & CFAUTOTERM) == 0) {
  410                                 if (bootverbose)
  411                                         printf("%s: Manual LVD Termination\n",
  412                                                ahc_name(ahc));
  413                                 enablePRI_low = (adapter_control & CFSTERM);
  414                                 enablePRI_high = (adapter_control & CFWSTERM);
  415                         }
  416                         /* Make the table calculations below happy */
  417                         internal50_present = 0;
  418                         internal68_present = 1;
  419                         externalcable_present = 1;
  420                 } else if ((ahc->features & AHC_SPIOCAP) != 0) {
  421                         aic785X_cable_detect(ahc, &internal50_present,
  422                                              &externalcable_present,
  423                                              &eeprom_present);
  424                         /* Can never support a wide connector. */
  425                         internal68_present = 0;
  426                 } else {
  427                         aic787X_cable_detect(ahc, &internal50_present,
  428                                              &internal68_present,
  429                                              &externalcable_present,
  430                                              &eeprom_present);
  431                 }
  432 
  433                 if ((ahc->features & AHC_WIDE) == 0)
  434                         internal68_present = 0;
  435 
  436                 if (bootverbose
  437                  && (ahc->features & AHC_ULTRA2) == 0) {
  438                         printf("%s: internal 50 cable %s present",
  439                                ahc_name(ahc),
  440                                internal50_present ? "is":"not");
  441 
  442                         if ((ahc->features & AHC_WIDE) != 0)
  443                                 printf(", internal 68 cable %s present",
  444                                        internal68_present ? "is":"not");
  445                         printf("\n%s: external cable %s present\n",
  446                                ahc_name(ahc),
  447                                externalcable_present ? "is":"not");
  448                 }
  449                 if (bootverbose)
  450                         printf("%s: BIOS eeprom %s present\n",
  451                                ahc_name(ahc), eeprom_present ? "is" : "not");
  452 
  453                 if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0) {
  454                         /*
  455                          * The 50 pin connector is a separate bus,
  456                          * so force it to always be terminated.
  457                          * In the future, perform current sensing
  458                          * to determine if we are in the middle of
  459                          * a properly terminated bus.
  460                          */
  461                         internal50_present = 0;
  462                 }
  463 
  464                 /*
  465                  * Now set the termination based on what
  466                  * we found.
  467                  * Flash Enable = BRDDAT7
  468                  * Secondary High Term Enable = BRDDAT6
  469                  * Secondary Low Term Enable = BRDDAT5 (7890)
  470                  * Primary High Term Enable = BRDDAT4 (7890)
  471                  */
  472                 if ((ahc->features & AHC_ULTRA2) == 0
  473                  && (internal50_present != 0)
  474                  && (internal68_present != 0)
  475                  && (externalcable_present != 0)) {
  476                         printf("%s: Illegal cable configuration!!. "
  477                                "Only two connectors on the "
  478                                "adapter may be used at a "
  479                                "time!\n", ahc_name(ahc));
  480 
  481                         /*
  482                          * Pretend there are no cables in the hope
  483                          * that having all of the termination on
  484                          * gives us a more stable bus.
  485                          */
  486                         internal50_present = 0;
  487                         internal68_present = 0;
  488                         externalcable_present = 0;
  489                 }
  490 
  491                 if ((ahc->features & AHC_WIDE) != 0
  492                  && ((externalcable_present == 0)
  493                   || (internal68_present == 0)
  494                   || (enableSEC_high != 0))) {
  495                         brddat |= BRDDAT6;
  496                         if (bootverbose) {
  497                                 if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0)
  498                                         printf("%s: 68 pin termination "
  499                                                "Enabled\n", ahc_name(ahc));
  500                                 else
  501                                         printf("%s: %sHigh byte termination "
  502                                                "Enabled\n", ahc_name(ahc),
  503                                                enableSEC_high ? "Secondary "
  504                                                               : "");
  505                         }
  506                 }
  507 
  508                 sum = internal50_present + internal68_present
  509                     + externalcable_present;
  510                 if (sum < 2 || (enableSEC_low != 0)) {
  511                         if ((ahc->features & AHC_ULTRA2) != 0)
  512                                 brddat |= BRDDAT5;
  513                         else
  514                                 *sxfrctl1 |= STPWEN;
  515                         if (bootverbose) {
  516                                 if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0)
  517                                         printf("%s: 50 pin termination "
  518                                                "Enabled\n", ahc_name(ahc));
  519                                 else
  520                                         printf("%s: %sLow byte termination "
  521                                                "Enabled\n", ahc_name(ahc),
  522                                                enableSEC_low ? "Secondary "
  523                                                              : "");
  524                         }
  525                 }
  526 
  527                 if (enablePRI_low != 0) {
  528                         *sxfrctl1 |= STPWEN;
  529                         if (bootverbose)
  530                                 printf("%s: Primary Low Byte termination "
  531                                        "Enabled\n", ahc_name(ahc));
  532                 }
  533 
  534                 /*
  535                  * Setup STPWEN before setting up the rest of
  536                  * the termination per the tech note on the U160 cards.
  537                  */
  538                 ahc_outb(ahc, SXFRCTL1, *sxfrctl1);
  539 
  540                 if (enablePRI_high != 0) {
  541                         brddat |= BRDDAT4;
  542                         if (bootverbose)
  543                                 printf("%s: Primary High Byte "
  544                                        "termination Enabled\n",
  545                                        ahc_name(ahc));
  546                 }
  547 
  548                 write_brdctl(ahc, brddat);
  549 
  550         } else {
  551                 if ((adapter_control & CFSTERM) != 0) {
  552                         *sxfrctl1 |= STPWEN;
  553 
  554                         if (bootverbose)
  555                                 printf("%s: %sLow byte termination Enabled\n",
  556                                        ahc_name(ahc),
  557                                        (ahc->features & AHC_ULTRA2) ? "Primary "
  558                                                                     : "");
  559                 }
  560 
  561                 if ((adapter_control & CFWSTERM) != 0
  562                  && (ahc->features & AHC_WIDE) != 0) {
  563                         brddat |= BRDDAT6;
  564                         if (bootverbose)
  565                                 printf("%s: %sHigh byte termination Enabled\n",
  566                                        ahc_name(ahc),
  567                                        (ahc->features & AHC_ULTRA2)
  568                                      ? "Secondary " : "");
  569                 }
  570 
  571                 /*
  572                  * Setup STPWEN before setting up the rest of
  573                  * the termination per the tech note on the U160 cards.
  574                  */
  575                 ahc_outb(ahc, SXFRCTL1, *sxfrctl1);
  576 
  577                 if ((ahc->features & AHC_WIDE) != 0)
  578                         write_brdctl(ahc, brddat);
  579         }
  580         SEEPROM_OUTB(sd, sd->sd_MS); /* Clear CS */
  581 }
  582 
  583 static void
  584 ahc_new_term_detect(struct ahc_softc *ahc, int *enableSEC_low,
  585                     int *enableSEC_high, int *enablePRI_low,
  586                     int *enablePRI_high, int *eeprom_present)
  587 {
  588         uint8_t brdctl;
  589 
  590         /*
  591          * BRDDAT7 = Eeprom
  592          * BRDDAT6 = Enable Secondary High Byte termination
  593          * BRDDAT5 = Enable Secondary Low Byte termination
  594          * BRDDAT4 = Enable Primary high byte termination
  595          * BRDDAT3 = Enable Primary low byte termination
  596          */
  597         brdctl = read_brdctl(ahc);
  598         *eeprom_present = brdctl & BRDDAT7;
  599         *enableSEC_high = (brdctl & BRDDAT6);
  600         *enableSEC_low = (brdctl & BRDDAT5);
  601         *enablePRI_high = (brdctl & BRDDAT4);
  602         *enablePRI_low = (brdctl & BRDDAT3);
  603 }
  604 
  605 static void
  606 aic787X_cable_detect(struct ahc_softc *ahc, int *internal50_present,
  607                      int *internal68_present, int *externalcable_present,
  608                      int *eeprom_present)
  609 {
  610         uint8_t brdctl;
  611 
  612         /*
  613          * First read the status of our cables.
  614          * Set the rom bank to 0 since the
  615          * bank setting serves as a multiplexor
  616          * for the cable detection logic.
  617          * BRDDAT5 controls the bank switch.
  618          */
  619         write_brdctl(ahc, 0);
  620 
  621         /*
  622          * Now read the state of the internal
  623          * connectors.  BRDDAT6 is INT50 and
  624          * BRDDAT7 is INT68.
  625          */
  626         brdctl = read_brdctl(ahc);
  627         *internal50_present = (brdctl & BRDDAT6) ? 0 : 1;
  628         *internal68_present = (brdctl & BRDDAT7) ? 0 : 1;
  629 
  630         /*
  631          * Set the rom bank to 1 and determine
  632          * the other signals.
  633          */
  634         write_brdctl(ahc, BRDDAT5);
  635 
  636         /*
  637          * Now read the state of the external
  638          * connectors.  BRDDAT6 is EXT68 and
  639          * BRDDAT7 is EPROMPS.
  640          */
  641         brdctl = read_brdctl(ahc);
  642         *externalcable_present = (brdctl & BRDDAT6) ? 0 : 1;
  643         *eeprom_present = (brdctl & BRDDAT7) ? 1 : 0;
  644 }
  645 
  646 static void
  647 aic785X_cable_detect(struct ahc_softc *ahc, int *internal50_present,
  648                      int *externalcable_present, int *eeprom_present)
  649 {
  650         uint8_t brdctl;
  651         uint8_t spiocap;
  652 
  653         spiocap = ahc_inb(ahc, SPIOCAP);
  654         spiocap &= ~SOFTCMDEN;
  655         spiocap |= EXT_BRDCTL;
  656         ahc_outb(ahc, SPIOCAP, spiocap);
  657         ahc_outb(ahc, BRDCTL, BRDRW|BRDCS);
  658         ahc_outb(ahc, BRDCTL, 0);
  659         brdctl = ahc_inb(ahc, BRDCTL);
  660         *internal50_present = (brdctl & BRDDAT5) ? 0 : 1;
  661         *externalcable_present = (brdctl & BRDDAT6) ? 0 : 1;
  662 
  663         *eeprom_present = (ahc_inb(ahc, SPIOCAP) & EEPROM) ? 1 : 0;
  664 }
  665 
  666 int
  667 ahc_acquire_seeprom(struct ahc_softc *ahc, struct seeprom_descriptor *sd)
  668 {
  669         int wait;
  670 
  671         if ((ahc->features & AHC_SPIOCAP) != 0
  672             && (ahc_inb(ahc, SPIOCAP) & SEEPROM) == 0)
  673                 return (0);
  674 
  675         /*
  676          * Request access of the memory port.  When access is
  677          * granted, SEERDY will go high.  We use a 1 second
  678          * timeout which should be near 1 second more than
  679          * is needed.  Reason: after the chip reset, there
  680          * should be no contention.
  681          */
  682         SEEPROM_OUTB(sd, sd->sd_MS);
  683         wait = 1000;  /* 1 second timeout in msec */
  684         while (--wait && ((SEEPROM_STATUS_INB(sd) & sd->sd_RDY) == 0)) {
  685                 ahc_delay(1000);  /* delay 1 msec */
  686         }
  687         if ((SEEPROM_STATUS_INB(sd) & sd->sd_RDY) == 0) {
  688                 SEEPROM_OUTB(sd, 0);
  689                 return (0);
  690         }
  691         return(1);
  692 }
  693 
  694 void
  695 ahc_release_seeprom(struct seeprom_descriptor *sd)
  696 {
  697         /* Release access to the memory port and the serial EEPROM. */
  698         SEEPROM_OUTB(sd, 0);
  699 }
  700 
  701 static void
  702 write_brdctl(struct ahc_softc *ahc, uint8_t value)
  703 {
  704         uint8_t brdctl;
  705 
  706         if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7895) {
  707                 brdctl = BRDSTB;
  708                 if (ahc->channel == 'B')
  709                         brdctl |= BRDCS;
  710         } else if ((ahc->features & AHC_ULTRA2) != 0) {
  711                 brdctl = 0;
  712         } else {
  713                 brdctl = BRDSTB|BRDCS;
  714         }
  715         ahc_outb(ahc, BRDCTL, brdctl);
  716         ahc_flush_device_writes(ahc);
  717         brdctl |= value;
  718         ahc_outb(ahc, BRDCTL, brdctl);
  719         ahc_flush_device_writes(ahc);
  720         if ((ahc->features & AHC_ULTRA2) != 0)
  721                 brdctl |= BRDSTB_ULTRA2;
  722         else
  723                 brdctl &= ~BRDSTB;
  724         ahc_outb(ahc, BRDCTL, brdctl);
  725         ahc_flush_device_writes(ahc);
  726         if ((ahc->features & AHC_ULTRA2) != 0)
  727                 brdctl = 0;
  728         else
  729                 brdctl &= ~BRDCS;
  730         ahc_outb(ahc, BRDCTL, brdctl);
  731 }
  732 
  733 static uint8_t
  734 read_brdctl(struct ahc_softc *ahc)
  735 {
  736         uint8_t brdctl;
  737         uint8_t value;
  738 
  739         if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7895) {
  740                 brdctl = BRDRW;
  741                 if (ahc->channel == 'B')
  742                         brdctl |= BRDCS;
  743         } else if ((ahc->features & AHC_ULTRA2) != 0) {
  744                 brdctl = BRDRW_ULTRA2;
  745         } else {
  746                 brdctl = BRDRW|BRDCS;
  747         }
  748         ahc_outb(ahc, BRDCTL, brdctl);
  749         ahc_flush_device_writes(ahc);
  750         value = ahc_inb(ahc, BRDCTL);
  751         ahc_outb(ahc, BRDCTL, 0);
  752         return (value);
  753 }
  754 
  755 static int
  756 verify_seeprom_cksum(struct seeprom_config *sc)
  757 {
  758         int i;
  759         int maxaddr;
  760         uint32_t checksum;
  761         uint16_t *scarray;
  762 
  763         maxaddr = (sizeof(*sc)/2) - 1;
  764         checksum = 0;
  765         scarray = (uint16_t *)sc;
  766 
  767         for (i = 0; i < maxaddr; i++)
  768                 checksum = checksum + scarray[i];
  769         if (checksum == 0
  770          || (checksum & 0xFFFF) != sc->checksum) {
  771                 return (0);
  772         } else {
  773                 return(1);
  774         }
  775 }

Cache object: 761ed874e13fd8ac45012ce0b6af31ca


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