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/pci/mpt_pci.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: mpt_pci.c,v 1.2.2.1 2004/09/18 16:52:31 he Exp $       */
    2 
    3 /*
    4  * Copyright (c) 2003 Wasabi Systems, Inc.
    5  * All rights reserved.
    6  *
    7  * Written by Jason R. Thorpe for Wasabi Systems, Inc.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   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. All advertising materials mentioning features or use of this software
   18  *    must display the following acknowledgement:
   19  *      This product includes software developed for the NetBSD Project by
   20  *      Wasabi Systems, Inc.
   21  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
   22  *    or promote products derived from this software without specific prior
   23  *    written permission.
   24  *
   25  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
   26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   27  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   28  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
   29  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   33  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   35  * POSSIBILITY OF SUCH DAMAGE.
   36  */
   37 
   38 /* 
   39  * mpt_pci.c:
   40  *
   41  * NetBSD PCI-specific routines for LSI Fusion adapters.
   42  */     
   43 
   44 #include <sys/cdefs.h>
   45 __KERNEL_RCSID(0, "$NetBSD: mpt_pci.c,v 1.2.2.1 2004/09/18 16:52:31 he Exp $");
   46 
   47 #include <dev/ic/mpt.h>                 /* pulls in all headers */
   48 
   49 #include <dev/pci/pcireg.h>
   50 #include <dev/pci/pcivar.h>
   51 #include <dev/pci/pcidevs.h>
   52 
   53 #define MPT_PCI_MMBA            (PCI_MAPREG_START+0x04)
   54 
   55 struct mpt_pci_softc {
   56         mpt_softc_t sc_mpt;
   57 
   58         pci_chipset_tag_t sc_pc;
   59         pcitag_t sc_tag;
   60 
   61         void *sc_ih;
   62 
   63         /* Saved volatile PCI configuration registers. */
   64         pcireg_t sc_pci_csr;
   65         pcireg_t sc_pci_bhlc;
   66         pcireg_t sc_pci_io_bar;
   67         pcireg_t sc_pci_mem0_bar[2];
   68         pcireg_t sc_pci_mem1_bar[2];
   69         pcireg_t sc_pci_rom_bar;
   70         pcireg_t sc_pci_int;
   71         pcireg_t sc_pci_pmcsr;
   72 };
   73 
   74 static void     mpt_pci_link_peer(mpt_softc_t *);
   75 static void     mpt_pci_read_config_regs(mpt_softc_t *);
   76 static void     mpt_pci_set_config_regs(mpt_softc_t *);
   77 
   78 #define MPP_F_FC        0x01    /* Fibre Channel adapter */
   79 #define MPP_F_DUAL      0x02    /* Dual port adapter */
   80 
   81 static const struct mpt_pci_product {
   82         pci_vendor_id_t         mpp_vendor;
   83         pci_product_id_t        mpp_product;
   84         int                     mpp_flags;
   85         const char              *mpp_name;
   86 } mpt_pci_products[] = {
   87         { PCI_VENDOR_SYMBIOS,   PCI_PRODUCT_SYMBIOS_1030,
   88           MPP_F_DUAL,
   89           "LSI Logic 53c1030 Ultra320 SCSI" },
   90 
   91         { PCI_VENDOR_SYMBIOS,   PCI_PRODUCT_SYMBIOS_FC909,
   92           MPP_F_FC,
   93           "LSI Logic FC909 FC Adapter" },
   94         { PCI_VENDOR_SYMBIOS,   PCI_PRODUCT_SYMBIOS_FC909A,
   95           MPP_F_FC,
   96           "LSI Logic FC909A FC Adapter" },
   97         { PCI_VENDOR_SYMBIOS,   PCI_PRODUCT_SYMBIOS_FC929,
   98           MPP_F_FC | MPP_F_DUAL,
   99           "LSI Logic FC929 FC Adapter" },
  100         { PCI_VENDOR_SYMBIOS,   PCI_PRODUCT_SYMBIOS_FC929_1,
  101           MPP_F_FC | MPP_F_DUAL,
  102           "LSI Logic FC929 FC Adapter" },
  103         { PCI_VENDOR_SYMBIOS,   PCI_PRODUCT_SYMBIOS_FC919,
  104           MPP_F_FC,
  105           "LSI Logic FC919 FC Adapter" },
  106         { PCI_VENDOR_SYMBIOS,   PCI_PRODUCT_SYMBIOS_FC919_1,
  107           MPP_F_FC,
  108           "LSI Logic FC919 FC Adapter" },
  109         { PCI_VENDOR_SYMBIOS,   PCI_PRODUCT_SYMBIOS_FC929X,
  110           MPP_F_FC | MPP_F_DUAL,
  111           "LSI Logic FC929X FC Adapter" },
  112 
  113         { 0,                    0,
  114           0,
  115           NULL },
  116 };
  117 
  118 static const struct mpt_pci_product *
  119 mpt_pci_lookup(const struct pci_attach_args *pa)
  120 {
  121         const struct mpt_pci_product *mpp;
  122 
  123         for (mpp = mpt_pci_products; mpp->mpp_name != NULL; mpp++) {
  124                 if (PCI_VENDOR(pa->pa_id) == mpp->mpp_vendor &&
  125                     PCI_PRODUCT(pa->pa_id) == mpp->mpp_product)
  126                         return (mpp);
  127         }
  128         return (NULL);
  129 }
  130 
  131 static int
  132 mpt_pci_match(struct device *parent, struct cfdata *cf, void *aux)
  133 {
  134         struct pci_attach_args *pa = aux;
  135 
  136         if (mpt_pci_lookup(pa) != NULL)
  137                 return (1);
  138 
  139         return (0);
  140 }
  141 
  142 static void
  143 mpt_pci_attach(struct device *parent, struct device *self, void *aux)
  144 {
  145         struct mpt_pci_softc *psc = (void *) self;
  146         mpt_softc_t *mpt = &psc->sc_mpt;
  147         struct pci_attach_args *pa = aux;
  148         const struct mpt_pci_product *mpp;
  149         pci_intr_handle_t ih;
  150         const char *intrstr;
  151         pcireg_t reg, memtype;
  152         bus_space_tag_t memt;
  153         bus_space_handle_t memh;
  154         int memh_valid;
  155 
  156         mpp = mpt_pci_lookup(pa);
  157         if (mpp == NULL) {
  158                 printf("\n");
  159                 panic("mpt_pci_attach");
  160         }
  161 
  162         if (mpp->mpp_flags & MPP_F_FC) {
  163                 mpt->is_fc = 1;
  164                 aprint_naive(": Fibre Channel controller\n");
  165         } else
  166                 aprint_naive(": SCSI controller\n");
  167         aprint_normal(": %s\n", mpp->mpp_name);
  168 
  169         psc->sc_pc = pa->pa_pc;
  170         psc->sc_tag = pa->pa_tag;
  171 
  172         mpt->sc_dmat = pa->pa_dmat;
  173         mpt->sc_set_config_regs = mpt_pci_set_config_regs;
  174 
  175         /*
  176          * Map the device.
  177          */
  178         memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, MPT_PCI_MMBA);
  179         switch (memtype) {
  180         case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT:
  181         case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT:
  182                 memh_valid = (pci_mapreg_map(pa, MPT_PCI_MMBA,
  183                     memtype, 0, &memt, &memh, NULL, NULL) == 0);
  184                 break;
  185 
  186         default:
  187                 memh_valid = 0;
  188         }
  189 
  190         if (memh_valid) {
  191                 mpt->sc_st = memt;
  192                 mpt->sc_sh = memh;
  193         } else {
  194                 aprint_error("%s: unable to map device registers\n",
  195                     mpt->sc_dev.dv_xname);
  196                 return;
  197         }
  198 
  199         /*
  200          * Make sure the PCI command register is properly configured.
  201          */
  202         reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
  203         reg |= PCI_COMMAND_MASTER_ENABLE;
  204         /* XXX PCI_COMMAND_INVALIDATE_ENABLE */
  205         /* XXX PCI_COMMAND_PARITY_ENABLE */
  206         /* XXX PCI_COMMAND_SERR_ENABLE */
  207         pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, reg);
  208 
  209         /*
  210          * Ensure that the ROM is diabled.
  211          */
  212         reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_MAPREG_ROM);
  213         reg &= ~1;
  214         pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_MAPREG_ROM, reg);
  215 
  216         /*
  217          * Map and establish our interrupt.
  218          */
  219         if (pci_intr_map(pa, &ih) != 0) {
  220                 aprint_error("%s: unable to map interrupt\n",
  221                     mpt->sc_dev.dv_xname);
  222                 return;
  223         }
  224         intrstr = pci_intr_string(pa->pa_pc, ih);
  225         psc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO, mpt_intr, mpt);
  226         if (psc->sc_ih == NULL) {
  227                 aprint_error("%s: unable to establish interrupt",
  228                     mpt->sc_dev.dv_xname);
  229                 if (intrstr != NULL)
  230                         aprint_normal(" at %s", intrstr);
  231                 aprint_normal("\n");
  232                 return;
  233         }
  234         aprint_normal("%s: interrupting at %s\n", mpt->sc_dev.dv_xname,
  235             intrstr);
  236 
  237         /* Disable interrupts on the part. */
  238         mpt_disable_ints(mpt);
  239 
  240         /* Allocate DMA memory. */
  241         if (mpt_dma_mem_alloc(mpt) != 0) {
  242                 aprint_error("%s: unable to allocate DMA memory\n",
  243                     mpt->sc_dev.dv_xname);
  244                 return;
  245         }
  246 
  247         /*
  248          * Save the PCI config register values.
  249          *
  250          * Hard resets are known to screw up the BAR for diagnostic
  251          * memory accesses (Mem1).
  252          *
  253          * Using Mem1 is know to make the chip stop responding to
  254          * configuration cycles, so we need to save it now.
  255          */
  256         mpt_pci_read_config_regs(mpt);
  257 
  258         /*
  259          * If we're a dual-port adapter, try to find our peer.  We
  260          * need to fix his PCI config registers, too.
  261          */
  262         if (mpp->mpp_flags & MPP_F_DUAL)
  263                 mpt_pci_link_peer(mpt);
  264 
  265         /* Initialize the hardware. */
  266         if (mpt_init(mpt, MPT_DB_INIT_HOST) != 0) {
  267                 /* Error message already printed. */
  268                 return;
  269         }
  270 
  271         /* Attach to scsipi. */
  272         mpt_scsipi_attach(mpt);
  273 }
  274 
  275 CFATTACH_DECL(mpt_pci, sizeof(struct mpt_pci_softc),
  276     mpt_pci_match, mpt_pci_attach, NULL, NULL);
  277 
  278 /*
  279  * Find and remember our peer PCI function on a dual-port device.
  280  */
  281 static void
  282 mpt_pci_link_peer(mpt_softc_t *mpt)
  283 {
  284         extern struct cfdriver mpt_cd;
  285 
  286         struct mpt_pci_softc *peer_psc, *psc = (void *) mpt;
  287         struct device *dev;
  288         int unit, b, d, f, peer_b, peer_d, peer_f;
  289 
  290         pci_decompose_tag(psc->sc_pc, psc->sc_tag, &b, &d, &f);
  291 
  292         for (unit = 0; unit < mpt_cd.cd_ndevs; unit++) {
  293                 if (unit == mpt->sc_dev.dv_unit)
  294                         continue;
  295                 dev = device_lookup(&mpt_cd, unit);
  296                 if (dev == NULL)
  297                         continue;
  298                 if (dev->dv_cfattach != &mpt_pci_ca)
  299                         continue;
  300                 peer_psc = (void *) dev;
  301                 if (peer_psc->sc_pc != psc->sc_pc)
  302                         continue;
  303                 pci_decompose_tag(peer_psc->sc_pc, peer_psc->sc_tag,
  304                     &peer_b, &peer_d, &peer_f);
  305                 if (peer_b == b && peer_d == d) {
  306                         if (mpt->verbose)
  307                                 mpt_prt(mpt, "linking with peer: %s",
  308                                     peer_psc->sc_mpt.sc_dev.dv_xname);
  309                         mpt->mpt2 = (mpt_softc_t *) peer_psc;
  310                         peer_psc->sc_mpt.mpt2 = mpt;
  311                         return;
  312                 }
  313         }
  314 }
  315 
  316 /*
  317  * Save the volatile PCI configuration registers.
  318  */
  319 static void
  320 mpt_pci_read_config_regs(mpt_softc_t *mpt)
  321 {
  322         struct mpt_pci_softc *psc = (void *) mpt;
  323 
  324         psc->sc_pci_csr = pci_conf_read(psc->sc_pc, psc->sc_tag,
  325             PCI_COMMAND_STATUS_REG);
  326         psc->sc_pci_bhlc = pci_conf_read(psc->sc_pc, psc->sc_tag,
  327             PCI_BHLC_REG);
  328         psc->sc_pci_io_bar = pci_conf_read(psc->sc_pc, psc->sc_tag,
  329             PCI_MAPREG_START);
  330         psc->sc_pci_mem0_bar[0] = pci_conf_read(psc->sc_pc, psc->sc_tag,
  331             PCI_MAPREG_START+0x04);
  332         psc->sc_pci_mem0_bar[1] = pci_conf_read(psc->sc_pc, psc->sc_tag,
  333             PCI_MAPREG_START+0x08);
  334         psc->sc_pci_mem1_bar[0] = pci_conf_read(psc->sc_pc, psc->sc_tag,
  335             PCI_MAPREG_START+0x0c);
  336         psc->sc_pci_mem1_bar[1] = pci_conf_read(psc->sc_pc, psc->sc_tag,
  337             PCI_MAPREG_START+0x10);
  338         psc->sc_pci_rom_bar = pci_conf_read(psc->sc_pc, psc->sc_tag,
  339             PCI_MAPREG_ROM);
  340         psc->sc_pci_int = pci_conf_read(psc->sc_pc, psc->sc_tag,
  341             PCI_INTERRUPT_REG);
  342         psc->sc_pci_pmcsr = pci_conf_read(psc->sc_pc, psc->sc_tag, 0x44);
  343 }
  344 
  345 /*
  346  * Restore the volatile PCI configuration registers.
  347  */
  348 static void
  349 mpt_pci_set_config_regs(mpt_softc_t *mpt)
  350 {
  351         struct mpt_pci_softc *psc = (void *) mpt;
  352 
  353         pci_conf_write(psc->sc_pc, psc->sc_tag, PCI_COMMAND_STATUS_REG,
  354             psc->sc_pci_csr);
  355         pci_conf_write(psc->sc_pc, psc->sc_tag, PCI_BHLC_REG,
  356             psc->sc_pci_bhlc);
  357         pci_conf_write(psc->sc_pc, psc->sc_tag, PCI_MAPREG_START,
  358             psc->sc_pci_io_bar);
  359         pci_conf_write(psc->sc_pc, psc->sc_tag, PCI_MAPREG_START+0x04,
  360             psc->sc_pci_mem0_bar[0]);
  361         pci_conf_write(psc->sc_pc, psc->sc_tag, PCI_MAPREG_START+0x08,
  362             psc->sc_pci_mem0_bar[1]);
  363         pci_conf_write(psc->sc_pc, psc->sc_tag, PCI_MAPREG_START+0x0c,
  364             psc->sc_pci_mem1_bar[0]);
  365         pci_conf_write(psc->sc_pc, psc->sc_tag, PCI_MAPREG_START+0x10,
  366             psc->sc_pci_mem1_bar[1]);
  367         pci_conf_write(psc->sc_pc, psc->sc_tag, PCI_MAPREG_ROM,
  368             psc->sc_pci_rom_bar);
  369         pci_conf_write(psc->sc_pc, psc->sc_tag, PCI_INTERRUPT_REG,
  370             psc->sc_pci_int);
  371         pci_conf_write(psc->sc_pc, psc->sc_tag, 0x44, psc->sc_pci_pmcsr);
  372 }

Cache object: 3ce37410cb39f1e15a8fbad2698aaf7a


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