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/pci/dpt_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 /*
    2  *       Copyright (c) 1997 by Simon Shapiro
    3  *       All Rights Reserved
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions, and the following disclaimer,
   10  *    without modification, immediately at the beginning of the file.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  * 3. The name of the author may not be used to endorse or promote products
   15  *    derived from this software without specific prior written permission.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
   21  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  *
   29  */
   30 
   31 /*
   32  *  dptpci.c:  Pseudo device drivers for DPT on PCI on FreeBSD 
   33  *
   34  *  caveats:   We may need an eisa and an isa files too
   35  */
   36 
   37 #ident "$FreeBSD: src/sys/pci/dpt_pci.c,v 1.4.2.5 1999/09/05 08:20:59 peter Exp $"
   38 
   39 #include "opt_devfs.h"
   40 #include "opt_dpt.h"
   41 
   42 #include <sys/param.h>
   43 #include <sys/systm.h>
   44 #include <sys/malloc.h>
   45 #include <sys/buf.h>
   46 #include <sys/kernel.h>
   47 
   48 #include <scsi/scsiconf.h>
   49 
   50 #include <pci/pcireg.h>
   51 #include <pci/pcivar.h>
   52 
   53 #include <sys/dpt.h>
   54 #include <pci/dpt_pci.h>
   55 
   56 #include <vm/vm.h>
   57 #include <vm/pmap.h>
   58 
   59 #define PCI_BASEADR0  PCI_MAP_REG_START  /* I/O Address */
   60 #define PCI_BASEADR1  PCI_MAP_REG_START + 4  /* Mem I/O Address */
   61 
   62 #define ISA_PRIMARY_WD_ADDRESS    0x1f8
   63 
   64 /* Global variables */
   65 
   66 /* Function Prototypes */
   67 
   68 static char    *dpt_pci_probe(pcici_t tag, pcidi_t type);
   69 static void     dpt_pci_attach(pcici_t config_id, int unit);
   70 static int      dpt_pci_shutdown(int foo, int bar);
   71 
   72 extern struct cdevsw dpt_cdevsw;
   73 
   74 static  struct pci_device dpt_pci_driver =
   75 {
   76     "dpt",
   77     dpt_pci_probe,
   78     dpt_pci_attach,
   79     &dpt_unit,
   80     dpt_pci_shutdown
   81 };
   82 
   83 DATA_SET(pcidevice_set, dpt_pci_driver);
   84 
   85 /*
   86  * Probe the PCI device.
   87  * Some of this work will have to be duplicated in _attach
   88  * because we do not know for sure how the two relate.
   89  */
   90 
   91 static char *
   92 dpt_pci_probe(pcici_t tag, pcidi_t type)
   93 {
   94     static char silly_message[64];
   95     static int  already_announced = 0;
   96 
   97     u_int32_t  dpt_id;
   98     u_int32_t command;
   99     u_int32_t class;
  100 
  101 #define pci_device  tag.cfg2.port
  102 #define pci_bus     tag.cfg2.forward
  103 #define pci_index   tag.cfg2.enable
  104 
  105 #ifndef PCI_COMMAND_MASTER_ENABLE
  106 #define PCI_COMMAND_MASTER_ENABLE 0x00000004
  107 #endif
  108 
  109 #ifndef PCI_SUBCLASS_MASS_STORAGE_SCSI
  110 #define PCI_SUBCLASS_MASS_STORAGE_SCSI 0x00000000
  111 #endif
  112 
  113     if ( bootverbose && !already_announced ) {
  114         printf("DPT:  PCI SCSI HBA Driver, version %d.%d.%d\n",
  115                DPT_RELEASE, DPT_VERSION, DPT_PATCH);
  116         ++already_announced;
  117     }
  118 
  119     if ((dpt_id = (type & 0xffff0000) >> 16) == DPT_DEVICE_ID) {
  120         /* This one appears to belong to us, but what is it? */
  121         class = pci_conf_read(tag, PCI_CLASS_REG);
  122         if (((class & PCI_CLASS_MASK) == PCI_CLASS_MASS_STORAGE) &&
  123             ((class & PCI_SUBCLASS_MASK) == PCI_SUBCLASS_MASS_STORAGE_SCSI) ) {
  124             /* It is a SCSI storage device.  How do talk to it? */
  125             command = pci_conf_read(tag, PCI_COMMAND_STATUS_REG);
  126 #ifdef DPT_ALLOW_MEMIO
  127             if ( ((command & PCI_COMMAND_IO_ENABLE) == 0)
  128                  && ((command & PCI_COMMAND_MEM_ENABLE) == 0) )
  129 #else
  130             if ( ((command & PCI_COMMAND_IO_ENABLE) == 0) )
  131 #endif /* DPT_ALLOW_MEMIO */
  132                 {
  133                     printf("DPT:  Cannot map the controller registers :-(\n");
  134                     return(NULL);
  135                 }
  136         } else {
  137             printf("DPT:  Device is not Mass Storage, nor SCSI controller\n");
  138             return(NULL);
  139         }
  140 
  141         command = pci_conf_read(tag, PCI_COMMAND_STATUS_REG);
  142         if ( (command & PCI_COMMAND_MASTER_ENABLE) == 0 ) {
  143             printf("DPT:  Cannot be functional without BUSMASTER. :-(\n");
  144             return (NULL);
  145         }
  146 
  147 #ifdef DPT_DEBUG_PCI
  148         printf("DPT:  Controller is %s mapable\n",
  149                (command & PCI_COMMAND_MEM_ENABLE)
  150                ? "MEMORY"
  151                : ((command & PCI_COMMAND_IO_ENABLE)
  152                   ? "I/O"
  153                   : "NOT"));
  154 #endif
  155         return ("DPT Caching SCSI RAID Controller");
  156     } 
  157 
  158 #if defined(DPT_DEBUG_PCI) && defined(DPT_DEBUG_WARN)
  159     printf("DPT:  Unknown Controller Type %x Found\n", dpt_id);
  160     printf("     (class = %x, command = %x\n", class, command);
  161 #endif
  162     return (NULL);
  163 }
  164 
  165 static void
  166 dpt_pci_attach(pcici_t config_id, int unit)
  167 {
  168     int          ospl;
  169     int          result;
  170     int          ndx;
  171 
  172     vm_offset_t  vaddr;
  173     vm_offset_t  paddr;
  174     u_int16_t    io_base;
  175     u_int32_t    command;
  176     u_int32_t    data;
  177     dpt_conf_t  *config;
  178     dpt_softc_t *dpt;
  179 
  180     if (dpt_controllers_present >= DPT_MAX_ADAPTERS) {
  181           printf("dpt%d: More than %d Adapters found!  Adapter rejected\n",
  182                          unit, DPT_MAX_ADAPTERS);
  183           return;
  184     }
  185 
  186     if ((dpt = (dpt_softc_t *) malloc(sizeof(dpt_softc_t), M_DEVBUF, M_NOWAIT))
  187                 == NULL) {
  188           printf("dpt%d: Failed to allocate %d bytes for a DPT softc\n",
  189                          unit, sizeof(dpt_softc_t));
  190           return;
  191     }
  192 
  193     /*
  194      * Initialize the queues.  See dpt.h for details. We do this here,
  195      * as we may get hit with interrupts at any moment and we want to
  196      * have a minimal structure in place to handle them. We also want to
  197      * register interrupts correctly. To do so, we need a valid dpt
  198      * structure. To have that, we need this  minimal setup here.
  199      */
  200     bzero(dpt, sizeof(dpt_softc_t));
  201     
  202     TAILQ_INIT(&dpt->free_ccbs);
  203     TAILQ_INIT(&dpt->waiting_ccbs);
  204     TAILQ_INIT(&dpt->submitted_ccbs);
  205     TAILQ_INIT(&dpt->completed_ccbs);
  206 
  207     if (TAILQ_EMPTY(&dpt_softc_list)) {
  208           TAILQ_INIT(&dpt_softc_list);
  209     }
  210 
  211     TAILQ_INSERT_TAIL(&dpt_softc_list, dpt, links);
  212     dpt->queue_status       = DPT_QUEUES_NONE_ACTIVE;
  213     dpt->commands_processed = 0;
  214 
  215 #ifdef DPT_MEASURE_PERFORMANCE
  216     /* Zero out all command counters */
  217     bzero((void *)&dpt->performance, sizeof(dpt_perf_t));
  218     for ( ndx = 0; ndx < 256; ndx ++ )
  219           dpt->performance.min_command_time[ndx] = BIG_ENOUGH;
  220     
  221     dpt->performance.min_intr_time     = BIG_ENOUGH;
  222     dpt->performance.min_waiting_time  = BIG_ENOUGH;
  223     dpt->performance.min_submit_time   = BIG_ENOUGH;
  224     dpt->performance.min_complete_time = BIG_ENOUGH;
  225     dpt->performance.min_eata_tries    = BIG_ENOUGH;
  226     
  227     for (ndx = 0; ndx < 10; ndx++ ) {
  228             dpt->performance.read_by_size_min_time[ndx] = BIG_ENOUGH;
  229             dpt->performance.write_by_size_min_time[ndx] = BIG_ENOUGH;
  230     }
  231 #endif        /* DPT_MEASURE_PERFORMANCE */
  232 
  233     dpt->unit = unit;
  234     dpt->handle_interrupts = 0;  /* 
  235                                                                   * Do not set to 1 until all
  236                                                                   * initialization is done 
  237                                                                   */
  238     dpt->v_membase = NULL;
  239     dpt->p_membase = NULL;
  240     io_base = 0;
  241     vaddr   = 0;
  242     paddr   = 0;
  243     command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG);
  244 
  245 #ifdef DPT_ALLOW_MEMIO
  246     if ( (command & PCI_COMMAND_MEM_ENABLE) == 0 ) {
  247 #ifdef DPT_DEBUG_PCI
  248           printf("dpt%d: Cannot be memory mapped\n", unit);
  249 #endif
  250         force_io:
  251           if ((command & PCI_COMMAND_IO_ENABLE) == 0 ) {
  252             printf("dpt%d: Cannot be I/O mapped either :-(\n", unit);
  253             free(dpt, M_DEVBUF);
  254             return;
  255           } else {
  256             data = pci_conf_read(config_id, PCI_MAP_REG_START);
  257             if ( pci_map_port(config_id, PCI_MAP_REG_START, &io_base) == 0 ) {
  258 #ifdef DPT_DEBUG_ERROR
  259                   printf("dpt%d: Failed to map as I/O :-(\n", unit);
  260 #endif
  261                   free(dpt, M_DEVBUF);
  262                   return;
  263             } else {
  264                   dpt->io_base = io_base + 0x10;
  265 #ifdef DPT_DEBUG_PCI
  266                   printf("dpt%d: Mapped registers to I/O space, "
  267                                  "starting at %x\n",
  268                                  dpt->unit, dpt->io_base);
  269 #endif
  270             }
  271           }
  272     } else {
  273           if ( pci_map_mem(config_id, PCI_MAP_REG_START + 4, &vaddr,
  274                                            &paddr) == 0 ) {
  275 #ifdef DPT_DEBUG_ERROR
  276             printf("dpt%d: Failed to map as MEMORY.\n"
  277                            "  Attemting to force I/O mapping\n", unit);
  278 #endif
  279             goto force_io;
  280           } else {
  281             dpt->v_membase = (volatile u_int8_t *)(vaddr + 0x10);
  282             dpt->p_membase = (volatile u_int8_t *)(paddr + 0x10);
  283 #ifdef DPT_DEBUG_PCI
  284             printf("dpt%d: Mapped registers to MEMORY space, "
  285                            "starting at %x/%x\n",
  286                            dpt->unit, dpt->v_membase, dpt->p_membase);
  287 #endif
  288           }
  289     }
  290 
  291 #else /* !DPT_ALLOW_MEMIO */
  292     data = pci_conf_read(config_id, PCI_MAP_REG_START);
  293     if ((command & PCI_COMMAND_IO_ENABLE) == 0 ) {
  294           printf("dpt%d: Registers cannot be I/O mapped :-(\n", unit);
  295           free(dpt, M_DEVBUF);
  296           return;
  297     } else {
  298           if ( pci_map_port(config_id, PCI_MAP_REG_START, &io_base) == 0 ) {
  299 #ifdef DPT_DEBUG_ERROR
  300             printf("dpt%d: Failed to map registers as I/O :-(\n", unit);
  301 #endif
  302             free(dpt, M_DEVBUF);
  303             return;
  304           } else {
  305             dpt->io_base = io_base + 0x10;
  306 #ifdef DPT_DEBUG_PCI
  307             printf("dpt%d: Mapped registers to I/O space, starting at %x\n",
  308                            dpt->unit, dpt->io_base);
  309 #endif
  310           }
  311     }
  312 #endif /* !DPT_ALLOW_MEMIO */
  313   
  314     if (pci_map_int(config_id, dpt_intr, (void *)dpt, &cam_imask) == 0) {
  315 #ifdef DPT_DEBUG_WARN
  316           printf("dpt%d: Failed to map interrupt :-(\n", unit);
  317 #endif
  318           free(dpt, M_DEVBUF);
  319           return;
  320     }
  321 
  322     /* If the DPT is mapped as an IDE controller, let it be IDE controller */
  323     if (io_base == (ISA_PRIMARY_WD_ADDRESS)) {
  324 #ifdef DPT_DEBUG_WARN
  325           printf("dpt%d: Mapped as an IDE controller.  "
  326                          "Disabling SCSI setup\n", unit);
  327 #endif
  328           free(dpt, M_DEVBUF);
  329           return;
  330     } else {
  331           if ((config = dpt_get_conf(dpt, 0xc1, 7,
  332                                                                  sizeof(dpt_conf_t), 1)) == NULL) {
  333 #ifdef DPT_DEBUG_ERROR
  334             printf("dpt%d: Failed to get board configuration (%x)\n",
  335                            unit, BaseRegister(dpt));
  336 #endif
  337             free(dpt, M_DEVBUF);
  338             return;
  339           }
  340     }
  341 
  342     dpt->max_id      = config->MAX_ID;
  343     dpt->max_lun     = config->MAX_LUN;
  344     dpt->irq         = config->IRQ;
  345     dpt->channels    = config->MAX_CHAN;
  346     dpt->dma_channel = (8 - config->DMA_channel) & 7;
  347 
  348 #ifdef DPT_DEBUG_SETUP
  349     printf("dpt%d: max_id = %d, max_chan = %d, max_lun = %d\n",
  350                    dpt->unit, dpt->max_id, dpt->channels, dpt->max_lun);
  351 #endif
  352 
  353     if (result = dpt_setup(dpt, config)) {
  354           free(config, M_TEMP);
  355           free(dpt, M_DEVBUF);
  356           printf("dpt%d: dpt_setup failed (%d).  Driver Disabled :-(\n",
  357                          dpt->unit, result);
  358     } else {
  359           /* clean up the informational data, and display */
  360           char clean_vendor[9];
  361           char clean_model[17];
  362           char clean_firmware[5];
  363           char clean_protocol[5];
  364           char clean_other[7];
  365 
  366           int     ndx;
  367 
  368           strncpy(clean_other, dpt->board_data.otherData, 8);
  369           clean_other[6] = '\0';
  370           for (ndx = 5; ndx >= 0; ndx--) {
  371             if (clean_other[ndx] == ' ')
  372                   clean_other[ndx] = '\0';
  373             else
  374                   break;
  375           }
  376           strncpy(dpt->board_data.otherData, clean_other, 6);
  377 
  378           strncpy(clean_vendor, dpt->board_data.vendor, 8);
  379           clean_vendor[8] = '\0';
  380           for (ndx = 7; ndx >= 0; ndx--) {
  381             if (clean_vendor[ndx] == ' ')
  382                   clean_vendor[ndx] = '\0';
  383             else
  384                   break;
  385           }
  386           strncpy(dpt->board_data.vendor, clean_vendor, 8);
  387 
  388           strncpy(clean_model, dpt->board_data.modelNum, 16);
  389           clean_model[16] = '\0';
  390           for (ndx = 15; ndx >= 0; ndx--) {
  391             if (clean_model[ndx] == ' ')
  392                   clean_model[ndx] = '\0';
  393             else
  394                   break;
  395           }
  396           strncpy(dpt->board_data.modelNum, clean_model, 16);
  397 
  398           strncpy(clean_firmware, dpt->board_data.firmware, 4);
  399           clean_firmware[4] = '\0';
  400           for (ndx = 3; ndx >= 0; ndx--) {
  401             if (clean_firmware[ndx] == ' ')
  402                   clean_firmware[ndx] = '\0';
  403             else
  404                   break;
  405           }
  406           strncpy(dpt->board_data.firmware, clean_firmware, 4);
  407 
  408           strncpy(clean_protocol, dpt->board_data.protocol, 4);
  409           clean_protocol[4] = '\0';
  410           for (ndx = 3; ndx >= 0; ndx--) {
  411             if (clean_protocol[ndx] == ' ')
  412                   clean_protocol[ndx] = '\0';
  413             else
  414                   break;
  415           }
  416           strncpy(dpt->board_data.protocol, clean_protocol, 4);
  417 
  418           dpt_detect_cache(dpt);
  419 
  420           printf("dpt%d: %s type %x, model %s firmware %s, Protocol %s \n"
  421                          "      on port %x with %s cache.  LED = %s\n",
  422                          dpt->unit, clean_vendor, dpt->board_data.deviceType,
  423                          clean_model, clean_firmware, clean_protocol, dpt->io_base,
  424                          (dpt->cache_type == DPT_NO_CACHE)
  425                          ? "Disabled"
  426                          : (dpt->cache_type == DPT_CACHE_WRITETHROUGH)
  427                          ? "Write-Through"
  428                          : "Write-Back",
  429                          i2bin(dpt_blinking_led(dpt), 8));
  430           printf("dpt%d: Enabled Options:\n", dpt->unit);
  431 #ifdef DPT_LOST_IRQ
  432           printf("      Recover Lost Interrupts\n");
  433 #endif
  434 #ifdef DPT_VERIFY_HINTR
  435           printf("      Verify Lost Transactions\n");
  436 #endif
  437 #ifdef DPT_RESTRICTED_FREELIST
  438           printf("      Restrict the Freelist Size\n");
  439 #endif
  440 #ifdef DPT_MEASURE_PERFORMANCE
  441           printf("      Collect Metrics\n");
  442 #endif
  443 #ifdef DPT_FREELIST_IS_STACK
  444           printf("      Optimize CPU Cache\n");
  445 #endif
  446 #ifdef DPT_HANDLE_TIMEOUTS
  447           printf("      Handle Timeouts\n");
  448 #endif
  449 #ifdef DPT_ALLOW_MEMIO
  450           printf("      Allow I/O to be Memeory Mapped\n");
  451 #endif
  452 #ifdef DPT_HINTR_CHECK_SOFTC
  453           printf("      Validate SoftC at Interrupt\n");
  454 #endif
  455 
  456           /* register shutdown handlers */
  457           result = at_shutdown((bootlist_fn)dpt_shutdown, (void *)dpt,
  458                                                    SHUTDOWN_POST_SYNC);
  459           switch ( result ) {
  460           case 0:
  461 #ifdef DPT_DEBUG_SHUTDOWN
  462                 printf("dpt%d: Shutdown handler registered\n", dpt->unit);
  463 #endif
  464                 break;
  465           default:
  466 #ifdef DPT_DEBUG_WARN
  467                 printf("dpt%d: Failed to register shutdown handler (%d)\n",
  468                            dpt->unit, result);
  469 #endif
  470                 break;
  471           }
  472 
  473           /* Attach SCSI devices */
  474           dpt_attach(dpt);
  475           ++dpt_controllers_present;
  476 
  477           /*
  478            * Now we create the DEVFS entry.
  479            * This would be normally done from dpt_control.c,
  480            * But since it appears to be called before we do here,
  481            * We never get the entries made.
  482        */
  483 #ifdef DEVFS
  484           dpt->devfs_data_token = devfs_add_devswf(&dpt_cdevsw, dpt->unit, DV_CHR,
  485                                                                                            UID_ROOT, GID_WHEEL, 0600,
  486                                                                                            "dpt%d", dpt->unit);
  487           dpt->devfs_ctl_token = devfs_add_devswf(&dpt_cdevsw,
  488                                                                                           dpt->unit | SCSI_CONTROL_MASK,
  489                                                                                           DV_CHR,
  490                                                                                           UID_ROOT, GID_WHEEL, 0600,
  491                                                                                           "dpt%d.ctl", dpt->unit);
  492 #endif
  493     }
  494 }
  495 
  496 static int
  497 dpt_pci_shutdown(int foo, int bar)
  498 {
  499 #ifdef DPT_DEBUG_WARN
  500     printf("dpt_pci_shutdown(%x, %x)\n", foo, bar);
  501 #endif
  502     return (0);
  503 }
  504 
  505 /* End of the DPT PCI part of the driver */
  506 
  507 /*
  508  * Hello emacs, these are the
  509  * Local Variables:
  510  *  c-indent-level:               8
  511  *  c-continued-statement-offset: 8
  512  *  c-continued-brace-offset:     0
  513  *  c-brace-offset:              -8
  514  *  c-brace-imaginary-offset:     0
  515  *  c-argdecl-indent:             8
  516  *  c-label-offset:              -8
  517  *  c++-hanging-braces:           1
  518  *  c++-access-specifier-offset: -8
  519  *  c++-empty-arglist-indent:     8
  520  *  c++-friend-offset:            0
  521  * End:
  522  */

Cache object: 08a8ca36fa10bd103edfacc1706c9816


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