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/eisa/ahc_eisa.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 /*      $OpenBSD: ahc_eisa.c,v 1.25 2022/04/06 18:59:28 naddy Exp $     */
    2 /*      $NetBSD: ahc_eisa.c,v 1.10 1996/10/21 22:30:58 thorpej Exp $    */
    3 
    4 /*
    5  * Product specific probe and attach routines for:
    6  *      27/284X and aic7770 motherboard SCSI controllers
    7  *
    8  * Copyright (c) 1994, 1995, 1996 Justin T. Gibbs.
    9  * All rights reserved.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice immediately at the beginning of the file, without modification,
   16  *    this list of conditions, and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  * 3. The name of the author may not be used to endorse or promote products
   21  *    derived from this software without specific prior written permission.
   22  *
   23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   26  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
   27  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   33  * SUCH DAMAGE.
   34  *
   35  *      $Id: ahc_eisa.c,v 1.25 2022/04/06 18:59:28 naddy Exp $
   36  */
   37 
   38 #include <sys/param.h>
   39 #include <sys/systm.h>
   40 #include <sys/kernel.h>
   41 #include <sys/device.h>
   42 #include <machine/bus.h>
   43 #include <machine/intr.h>
   44 
   45 #include <scsi/scsi_all.h>
   46 #include <scsi/scsiconf.h>
   47 
   48 #include <dev/eisa/eisareg.h>
   49 #include <dev/eisa/eisavar.h>
   50 #include <dev/eisa/eisadevs.h>
   51 #include <dev/ic/aic7xxx_openbsd.h>
   52 #include <dev/ic/aic7xxx_inline.h>
   53 
   54 #define AHC_EISA_SLOT_OFFSET    0xc00
   55 #define AHC_EISA_IOSIZE         0x100
   56 
   57 int   ahc_eisa_irq(bus_space_tag_t, bus_space_handle_t);
   58 int   ahc_eisa_match(struct device *, void *, void *);
   59 void  ahc_eisa_attach(struct device *, struct device *, void *);
   60 
   61 
   62 const struct cfattach ahc_eisa_ca = {
   63         sizeof(struct ahc_softc), ahc_eisa_match, ahc_eisa_attach
   64 };
   65 
   66 /*
   67  * Return irq setting of the board, otherwise -1.
   68  */
   69 int
   70 ahc_eisa_irq(bus_space_tag_t iot, bus_space_handle_t ioh)
   71 {
   72         int irq;
   73         u_char intdef;
   74         u_char hcntrl;
   75         
   76         /* Pause the card preserving the IRQ type */
   77         hcntrl = bus_space_read_1(iot, ioh, HCNTRL) & IRQMS;
   78         bus_space_write_1(iot, ioh, HCNTRL, hcntrl | PAUSE);
   79         
   80         intdef = bus_space_read_1(iot, ioh, INTDEF);
   81         switch (irq = (intdef & VECTOR)) {
   82         case 9:
   83         case 10:
   84         case 11:
   85         case 12:
   86         case 14:
   87         case 15:
   88                 break;
   89         default:
   90                 printf("ahc_eisa_irq: illegal irq setting %d\n", intdef);
   91                 return -1;
   92         }
   93 
   94         /* Note that we are going and return (to probe) */
   95         return irq;
   96 }
   97 
   98 /*
   99  * Check the slots looking for a board we recognise
  100  * If we find one, note its address (slot) and call
  101  * the actual probe routine to check it out.
  102  */
  103 int
  104 ahc_eisa_match(struct device *parent, void *match, void *aux)
  105 {
  106         struct eisa_attach_args *ea = aux;
  107         bus_space_tag_t iot = ea->ea_iot;
  108         bus_space_handle_t ioh;
  109         int irq;
  110 
  111         /* must match one of our known ID strings */
  112         if (strcmp(ea->ea_idstring, "ADP7770") &&
  113                  strcmp(ea->ea_idstring, "ADP7771")
  114 #if 0
  115                  && strcmp(ea->ea_idstring, "ADP7756")  /* not EISA, but VL */
  116                  && strcmp(ea->ea_idstring, "ADP7757")  /* not EISA, but VL */
  117 #endif
  118                 )
  119                 return (0);
  120 
  121         if (bus_space_map(iot, EISA_SLOT_ADDR(ea->ea_slot) +
  122                           AHC_EISA_SLOT_OFFSET, AHC_EISA_IOSIZE, 0, &ioh))
  123                 return (0);
  124 
  125         irq = ahc_eisa_irq(iot, ioh);
  126 
  127         bus_space_unmap(iot, ioh, AHC_EISA_IOSIZE);
  128 
  129         return (irq >= 0);
  130 }
  131 
  132 void
  133 ahc_eisa_attach(struct device *parent, struct device *self, void *aux)
  134 {
  135         struct ahc_softc *ahc = (void *)self;
  136         struct eisa_attach_args *ea = aux;
  137         bus_space_tag_t iot = ea->ea_iot;
  138         bus_space_handle_t ioh;
  139         int irq;
  140         eisa_chipset_tag_t ec = ea->ea_ec;
  141         eisa_intr_handle_t ih;
  142         const char *model, *intrstr;
  143         u_int biosctrl;
  144         u_int scsiconf;
  145         u_int scsiconf1;
  146         u_int intdef;
  147         int i;
  148         
  149         ahc_set_name(ahc, ahc->sc_dev.dv_xname);
  150         ahc_set_unit(ahc, ahc->sc_dev.dv_unit);
  151         
  152         /* set dma tags */
  153         ahc->parent_dmat = ea->ea_dmat;
  154 
  155         if (bus_space_map(iot, EISA_SLOT_ADDR(ea->ea_slot) +
  156                           AHC_EISA_SLOT_OFFSET, AHC_EISA_IOSIZE, 0, &ioh))
  157                 panic("ahc_eisa_attach: can't map i/o addresses");
  158         if ((irq = ahc_eisa_irq(iot, ioh)) < 0)
  159                 panic("ahc_eisa_attach: ahc_eisa_irq failed!");
  160 
  161         if (strcmp(ea->ea_idstring, "ADP7770") == 0) {
  162                 model = EISA_PRODUCT_ADP7770;
  163         } else if (strcmp(ea->ea_idstring, "ADP7771") == 0) {
  164                 model = EISA_PRODUCT_ADP7771;
  165         } else {
  166                 panic("ahc_eisa_attach: Unknown device type %s",
  167                                 ea->ea_idstring);
  168         }
  169         printf(": %s\n", model);
  170         
  171         /*
  172          * Instead of ahc_alloc() as in FreeBSD, do the few relevant
  173          * initializations manually.
  174          */
  175         LIST_INIT(&ahc->pending_scbs);
  176         for (i = 0; i < AHC_NUM_TARGETS; i++)
  177                 TAILQ_INIT(&ahc->untagged_queues[i]);
  178 
  179         /*
  180          * SCSI_IS_SCSIBUS_B() must returns false until sc_channel_b
  181          * has been properly initialized.
  182          */
  183         ahc->sc_child_b = NULL;
  184 
  185         ahc->channel = 'A';
  186         ahc->chip = AHC_AIC7770|AHC_EISA;
  187         ahc->features = AHC_AIC7770_FE;
  188         ahc->bugs |= AHC_TMODE_WIDEODD_BUG;
  189         ahc->flags |= AHC_PAGESCBS;
  190         ahc->tag = iot;
  191         ahc->bsh = ioh;
  192         ahc->bus_chip_init = ahc_chip_init;
  193         ahc->instruction_ram_size = 512;
  194 
  195         if (ahc_softc_init(ahc) != 0)
  196                 return;
  197         
  198         if (ahc_reset(ahc, /*reinit*/FALSE) != 0)
  199                 return;
  200         
  201         /* See if we are edge triggered */
  202         intdef = ahc_inb(ahc, INTDEF);
  203         if ((intdef & EDGE_TRIG) != 0)
  204                 ahc->flags |= AHC_EDGE_INTERRUPT;
  205         
  206         if (eisa_intr_map(ec, irq, &ih)) {
  207                 printf("%s: couldn't map interrupt (%d)\n",
  208                        ahc->sc_dev.dv_xname, irq);
  209                 return;
  210         }
  211 
  212         /*
  213          * Tell the user what type of interrupts we're using.
  214          * useful for debugging irq problems
  215          */
  216         if (bootverbose) {
  217                 printf("%s: Using %s Interrupts\n",
  218                        ahc_name(ahc),
  219                        ahc->pause & IRQMS ?
  220                        "Level Sensitive" : "Edge Triggered");
  221         }
  222 
  223         /*
  224          * Now that we know we own the resources we need, do the 
  225          * card initialization.
  226          *
  227          * First, the aic7770 card specific setup.
  228          */
  229         biosctrl = ahc_inb(ahc, HA_274_BIOSCTRL);
  230         scsiconf = ahc_inb(ahc, SCSICONF);
  231         scsiconf1 = ahc_inb(ahc, SCSICONF + 1);
  232         
  233         /* Get the primary channel information */
  234         if ((biosctrl & CHANNEL_B_PRIMARY) != 0)
  235                 ahc->flags |= AHC_PRIMARY_CHANNEL;
  236 
  237         if ((biosctrl & BIOSMODE) == BIOSDISABLED) {
  238                 ahc->flags |= AHC_USEDEFAULTS;
  239         } else if ((ahc->features & AHC_WIDE) != 0) {
  240                 ahc->our_id = scsiconf1 & HWSCSIID;
  241                 if (scsiconf & TERM_ENB)
  242                         ahc->flags |= AHC_TERM_ENB_A;
  243         } else {
  244                 ahc->our_id = scsiconf & HSCSIID;
  245                 ahc->our_id_b = scsiconf1 & HSCSIID;
  246                 if (scsiconf & TERM_ENB)
  247                         ahc->flags |= AHC_TERM_ENB_A;
  248                 if (scsiconf1 & TERM_ENB)
  249                         ahc->flags |= AHC_TERM_ENB_B;
  250         }
  251         /*
  252          * We have no way to tell, so assume extended
  253          * translation is enabled.
  254          */
  255         
  256         ahc->flags |= AHC_EXTENDED_TRANS_A|AHC_EXTENDED_TRANS_B;
  257         
  258         /*      
  259          * See if we have a Rev E or higher aic7770. Anything below a
  260          * Rev E will have a R/O autoflush disable configuration bit.
  261          * It's still not clear exactly what is different about the Rev E.
  262          * We think it allows 8 bit entries in the QOUTFIFO to support
  263          * "paging" SCBs so you can have more than 4 commands active at
  264          * once.
  265          */
  266         {
  267                 char *id_string;
  268                 u_char sblkctl;
  269                 u_char sblkctl_orig;
  270 
  271                 sblkctl_orig = ahc_inb(ahc, SBLKCTL);
  272                 sblkctl = sblkctl_orig ^ AUTOFLUSHDIS;
  273                 ahc_outb(ahc, SBLKCTL, sblkctl);
  274                 sblkctl = ahc_inb(ahc, SBLKCTL);
  275                 if (sblkctl != sblkctl_orig) {
  276                         id_string = "aic7770 >= Rev E";
  277                         /*
  278                          * Ensure autoflush is enabled
  279                          */
  280                         sblkctl &= ~AUTOFLUSHDIS;
  281                         ahc_outb(ahc, SBLKCTL, sblkctl);
  282 
  283                         /* Allow paging on this adapter */
  284                         ahc->flags |= AHC_PAGESCBS;
  285                 } else
  286                         id_string = "aic7770 <= Rev C";
  287 
  288                 if (bootverbose)
  289                         printf("%s: %s\n", ahc_name(ahc), id_string);
  290         }
  291 
  292         /* Setup the FIFO threshold and the bus off time */
  293         {
  294                 u_char hostconf = ahc_inb(ahc, HOSTCONF);
  295                 ahc_outb(ahc, BUSSPD, hostconf & DFTHRSH);
  296                 ahc_outb(ahc, BUSTIME, (hostconf << 2) & BOFF);
  297         }
  298 
  299         /*
  300          * Generic aic7xxx initialization.
  301          */
  302         if (ahc_init(ahc)) {
  303                 ahc_free(ahc);
  304                 return;
  305         }
  306  
  307         /*
  308          * Link this softc in with all other ahc instances.
  309          */
  310         ahc_softc_insert(ahc);
  311         
  312         /*
  313          * Enable the board's BUS drivers
  314          */
  315         ahc_outb(ahc, BCTL, ENABLE);
  316 
  317         intrstr = eisa_intr_string(ec, ih);
  318         /*
  319          * The IRQMS bit enables level sensitive interrupts only allow
  320          * IRQ sharing if its set.
  321          */
  322         ahc->ih = eisa_intr_establish(ec, ih,
  323             ahc->pause & IRQMS ? IST_LEVEL : IST_EDGE, IPL_BIO,
  324             ahc_platform_intr, ahc, ahc->sc_dev.dv_xname);
  325         if (ahc->ih == NULL) {
  326                 printf("%s: couldn't establish interrupt",
  327                        ahc->sc_dev.dv_xname);
  328                 if (intrstr != NULL)
  329                         printf(" at %s", intrstr);
  330                 printf("\n");
  331                 ahc_free(ahc);
  332                 return;
  333         }
  334         if (intrstr != NULL)
  335                 printf("%s: interrupting at %s\n", ahc->sc_dev.dv_xname,
  336                     intrstr);
  337         
  338         ahc_intr_enable(ahc, TRUE);
  339 
  340         /* Attach sub-devices - always succeeds */
  341         ahc_attach(ahc);
  342 
  343 }

Cache object: 2df6355914a080ac07b1b34ebdd3655a


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