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/ocs_fc/ocs_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) 2017 Broadcom. All rights reserved.
    3  * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions are met:
    7  *
    8  * 1. Redistributions of source code must retain the above copyright notice,
    9  *    this list of conditions and the following disclaimer.
   10  *
   11  * 2. Redistributions in binary form must reproduce the above copyright notice,
   12  *    this list of conditions and the following disclaimer in the documentation
   13  *    and/or other materials provided with the distribution.
   14  *
   15  * 3. Neither the name of the copyright holder nor the names of its contributors
   16  *    may be used to endorse or promote products derived from this software
   17  *    without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   29  * POSSIBILITY OF SUCH DAMAGE.
   30  *
   31  * $FreeBSD$
   32  */
   33 
   34 #define OCS_COPYRIGHT "Copyright (C) 2017 Broadcom. All rights reserved."
   35 
   36 /**
   37  * @file
   38  * Implementation of required FreeBSD PCI interface functions
   39  */
   40 
   41 #include "ocs.h"
   42 #include "version.h"
   43 #include <sys/sysctl.h>
   44 #include <sys/malloc.h>
   45 
   46 static MALLOC_DEFINE(M_OCS, "OCS", "OneCore Storage data");
   47 
   48 #include <dev/pci/pcireg.h>
   49 #include <dev/pci/pcivar.h>
   50 
   51 #include <machine/bus.h>
   52 
   53 /**
   54  * Tunable parameters for transport
   55  */
   56 int logmask = 0;
   57 int ctrlmask = 2;
   58 int logdest = 1;
   59 int loglevel = LOG_INFO;
   60 int ramlog_size = 1*1024*1024;
   61 int ddump_saved_size = 0;
   62 static const char *queue_topology = "eq cq rq cq mq $nulp($nwq(cq wq:ulp=$rpt1)) cq wq:len=256:class=1";
   63 
   64 static void ocs_release_bus(struct ocs_softc *);
   65 static int32_t ocs_intr_alloc(struct ocs_softc *);
   66 static int32_t ocs_intr_setup(struct ocs_softc *);
   67 static int32_t ocs_intr_teardown(struct ocs_softc *);
   68 static int ocs_pci_intx_filter(void *);
   69 static void ocs_pci_intr(void *);
   70 static int32_t ocs_init_dma_tag(struct ocs_softc *ocs);
   71 
   72 static int32_t ocs_setup_fcports(ocs_t *ocs);
   73 
   74 ocs_t *ocs_devices[MAX_OCS_DEVICES];
   75 
   76 /**
   77  * @brief Check support for the given device
   78  *
   79  * Determine support for a given device by examining the PCI vendor and
   80  * device IDs
   81  *
   82  * @param dev device abstraction
   83  *
   84  * @return 0 if device is supported, ENXIO otherwise
   85  */
   86 static int
   87 ocs_pci_probe(device_t dev)
   88 {
   89         char    *desc = NULL;
   90 
   91         if (pci_get_vendor(dev) != PCI_VENDOR_EMULEX) { 
   92                 return ENXIO;
   93         }
   94 
   95         switch (pci_get_device(dev)) {
   96         case PCI_PRODUCT_EMULEX_OCE16001:
   97                 desc = "Emulex LightPulse FC Adapter";
   98                 break;
   99         case PCI_PRODUCT_EMULEX_LPE31004:
  100                 desc = "Emulex LightPulse FC Adapter";
  101                 break;
  102         case PCI_PRODUCT_EMULEX_OCE50102:
  103                 desc = "Emulex LightPulse 10GbE FCoE/NIC Adapter";
  104                 break;
  105         case PCI_PRODUCT_EMULEX_LANCER_G7:
  106                 desc = "Emulex LightPulse G7 FC Adapter";
  107                 break;
  108         default:
  109                 return ENXIO;
  110         }
  111 
  112         device_set_desc(dev, desc);
  113 
  114         return BUS_PROBE_DEFAULT;
  115 }
  116 
  117 static int
  118 ocs_map_g7_bars(device_t dev, struct ocs_softc *ocs)
  119 {
  120         int i, r;
  121         uint32_t  val = 0;
  122 
  123         for (i = 0, r = 0; i < PCI_MAX_BAR; i++) {
  124                 val = pci_read_config(dev, PCIR_BAR(i), 4);
  125                 if (!PCI_BAR_MEM(val)) {
  126                         continue;
  127                 }
  128                 if (!(val & PCIM_BAR_MEM_BASE)) {
  129                         /* no address */
  130                         continue;
  131                 }
  132                 ocs->reg[r].rid = PCIR_BAR(i);
  133                 ocs->reg[r].res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
  134                                 &ocs->reg[r].rid, RF_ACTIVE);
  135                 if (ocs->reg[r].res) {
  136                         ocs->reg[r].btag = rman_get_bustag(ocs->reg[r].res);
  137                         ocs->reg[r].bhandle = rman_get_bushandle(ocs->reg[r].res);
  138                         r++;
  139                 } else {
  140                         device_printf(dev, "bus_alloc_resource failed rid=%#x\n",
  141                         ocs->reg[r].rid);
  142                         ocs_release_bus(ocs);
  143                         return ENXIO;
  144                 }
  145 
  146                 /*
  147                  * If the 64-bit attribute is set, both this BAR and the
  148                  * next form the complete address. Skip processing the
  149                  * next BAR.
  150                  */
  151                 if (val & PCIM_BAR_MEM_64) {
  152                         i++;
  153                 }
  154         }
  155 
  156         return 0;
  157 }
  158 
  159 static int
  160 ocs_map_bars(device_t dev, struct ocs_softc *ocs)
  161 {
  162         /*
  163          * Map PCI BAR0 register into the CPU's space.
  164          */
  165 
  166         ocs->reg[0].rid = PCIR_BAR(PCI_64BIT_BAR0);
  167         ocs->reg[0].res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
  168                         &ocs->reg[0].rid, RF_ACTIVE);
  169 
  170         if (ocs->reg[0].res == NULL) {
  171                 device_printf(dev, "bus_alloc_resource failed rid=%#x\n",
  172                                 ocs->reg[0].rid);
  173                 return ENXIO;
  174         }
  175 
  176         ocs->reg[0].btag = rman_get_bustag(ocs->reg[0].res);
  177         ocs->reg[0].bhandle = rman_get_bushandle(ocs->reg[0].res);
  178         return 0;
  179 }
  180 
  181 static int
  182 ocs_setup_params(struct ocs_softc *ocs)
  183 {
  184         int32_t i = 0;
  185         const char      *hw_war_version;
  186         /* Setup tunable parameters */
  187         ocs->ctrlmask = ctrlmask;
  188         ocs->speed = 0;
  189         ocs->topology = 0;
  190         ocs->ethernet_license = 0;
  191         ocs->num_scsi_ios = 8192;
  192         ocs->enable_hlm = 0;
  193         ocs->hlm_group_size = 8;
  194         ocs->logmask = logmask;
  195 
  196         ocs->config_tgt = FALSE;
  197         if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
  198                                         "target", &i)) {
  199                 if (1 == i) {
  200                         ocs->config_tgt = TRUE;
  201                         device_printf(ocs->dev, "Enabling target\n");
  202                 }
  203         }
  204 
  205         ocs->config_ini = TRUE;
  206         if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
  207                                         "initiator", &i)) {
  208                 if (0 == i) {
  209                         ocs->config_ini = FALSE;
  210                         device_printf(ocs->dev, "Disabling initiator\n");
  211                 }
  212         }
  213         ocs->enable_ini = ocs->config_ini;
  214 
  215         if (!ocs->config_ini && !ocs->config_tgt) {
  216                 device_printf(ocs->dev, "Unsupported, both initiator and target mode disabled.\n");
  217                 return 1;
  218         }
  219 
  220         if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
  221                                         "logmask", &logmask)) {
  222                 device_printf(ocs->dev, "logmask = %#x\n", logmask);
  223         }
  224 
  225         if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
  226                                         "logdest", &logdest)) {
  227                 device_printf(ocs->dev, "logdest = %#x\n", logdest);
  228         }
  229 
  230         if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
  231                                         "loglevel", &loglevel)) {
  232                 device_printf(ocs->dev, "loglevel = %#x\n", loglevel);
  233         }
  234 
  235         if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
  236                                         "ramlog_size", &ramlog_size)) {
  237                 device_printf(ocs->dev, "ramlog_size = %#x\n", ramlog_size);
  238         }
  239 
  240         if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
  241                                         "ddump_saved_size", &ddump_saved_size)) {
  242                 device_printf(ocs->dev, "ddump_saved_size= %#x\n", ddump_saved_size);
  243         }
  244 
  245         /* If enabled, initailize a RAM logging buffer */
  246         if (logdest & 2) {
  247                 ocs->ramlog = ocs_ramlog_init(ocs, ramlog_size/OCS_RAMLOG_DEFAULT_BUFFERS,
  248                         OCS_RAMLOG_DEFAULT_BUFFERS);
  249                 /* If NULL was returned, then we'll simply skip using the ramlog but */
  250                 /* set logdest to 1 to ensure that we at least get default logging.  */
  251                 if (ocs->ramlog == NULL) {
  252                         logdest = 1;
  253                 }
  254         }
  255 
  256         /* initialize a saved ddump */
  257         if (ddump_saved_size) {
  258                 if (ocs_textbuf_alloc(ocs, &ocs->ddump_saved, ddump_saved_size)) {
  259                         ocs_log_err(ocs, "failed to allocate memory for saved ddump\n");
  260                 }
  261         }
  262 
  263         if (0 == resource_string_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
  264                                         "hw_war_version", &hw_war_version)) {
  265                 device_printf(ocs->dev, "hw_war_version = %s\n", hw_war_version);
  266                 ocs->hw_war_version = strdup(hw_war_version, M_OCS);
  267         }
  268 
  269         if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
  270                                     "explicit_buffer_list", &i)) {
  271                 ocs->explicit_buffer_list = i;
  272         }
  273 
  274         if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
  275                                         "ethernet_license", &i)) {
  276                 ocs->ethernet_license = i;
  277         }
  278 
  279         if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
  280                                         "speed", &i)) {
  281                 device_printf(ocs->dev, "speed = %d Mbps\n", i);
  282                 ocs->speed = i;
  283         }
  284         ocs->desc = device_get_desc(ocs->dev);
  285 
  286         ocs_device_lock_init(ocs);
  287         ocs->driver_version = STR_BE_MAJOR "." STR_BE_MINOR "." STR_BE_BUILD "." STR_BE_BRANCH;
  288         ocs->model = ocs_pci_model(ocs->pci_vendor, ocs->pci_device);
  289 
  290         if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
  291                                     "enable_hlm", &i)) {
  292                 device_printf(ocs->dev, "enable_hlm = %d\n", i);
  293                 ocs->enable_hlm = i;
  294                 if (ocs->enable_hlm) {
  295                         ocs->hlm_group_size = 8;
  296 
  297                         if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
  298                                                     "hlm_group_size", &i)) {
  299                                 ocs->hlm_group_size = i;
  300                         }
  301                         device_printf(ocs->dev, "hlm_group_size = %d\n", i);
  302                 }
  303         }
  304 
  305         if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
  306                                         "num_scsi_ios", &i)) {
  307                 ocs->num_scsi_ios = i;
  308                 device_printf(ocs->dev, "num_scsi_ios = %d\n", ocs->num_scsi_ios);
  309         } else {
  310                 ocs->num_scsi_ios = 8192;
  311         }
  312 
  313         if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
  314                                         "topology", &i)) {
  315                 ocs->topology = i;
  316                 device_printf(ocs->dev, "Setting topology=%#x\n", i);
  317         }
  318 
  319         if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
  320                                     "num_vports", &i)) {
  321                 if (i >= 0 && i <= 254) {
  322                         device_printf(ocs->dev, "num_vports = %d\n", i);
  323                         ocs->num_vports = i;
  324                 } else {
  325                         device_printf(ocs->dev, "num_vports: %d not supported \n", i);
  326                 }
  327         }
  328 
  329         if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
  330                                     "external_loopback", &i)) {
  331                 device_printf(ocs->dev, "external_loopback = %d\n", i);
  332                 ocs->external_loopback = i;
  333         }
  334 
  335         if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
  336                                     "tgt_rscn_delay", &i)) {
  337                 device_printf(ocs->dev, "tgt_rscn_delay = %d\n", i);
  338                 ocs->tgt_rscn_delay_msec = i * 1000;
  339         }
  340 
  341         if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
  342                                     "tgt_rscn_period", &i)) {
  343                 device_printf(ocs->dev, "tgt_rscn_period = %d\n", i);
  344                 ocs->tgt_rscn_period_msec = i * 1000;
  345         }
  346 
  347         if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
  348                                     "target_io_timer", &i)) {
  349                 device_printf(ocs->dev, "target_io_timer = %d\n", i);
  350                 ocs->target_io_timer_sec = i;
  351         }
  352 
  353         hw_global.queue_topology_string = queue_topology;
  354         ocs->rq_selection_policy = 0;
  355         ocs->rr_quanta = 1;
  356         ocs->filter_def = "0,0,0,0";
  357 
  358         return 0;
  359 }
  360 
  361 static int32_t
  362 ocs_setup_fcports(ocs_t *ocs)
  363 {
  364         uint32_t        i = 0, role = 0;
  365         uint64_t sli_wwpn, sli_wwnn;
  366         size_t size;
  367         ocs_xport_t *xport = ocs->xport;
  368         ocs_vport_spec_t *vport;
  369         ocs_fcport *fcp = NULL;
  370 
  371         size = sizeof(ocs_fcport) * (ocs->num_vports + 1);
  372 
  373         ocs->fcports = ocs_malloc(ocs, size, M_ZERO|M_NOWAIT);
  374         if (ocs->fcports == NULL) {
  375                 device_printf(ocs->dev, "Can't allocate fcport \n");
  376                 return 1;
  377         }
  378 
  379         role = (ocs->enable_ini)? KNOB_ROLE_INITIATOR: 0 |
  380                 (ocs->enable_tgt)? KNOB_ROLE_TARGET: 0;
  381 
  382         fcp = FCPORT(ocs, i);
  383         fcp->role = role;
  384         i++;
  385 
  386         ocs_list_foreach(&xport->vport_list, vport) {
  387                 fcp = FCPORT(ocs, i);
  388                 vport->tgt_data = fcp;
  389                 fcp->vport = vport;
  390                 fcp->role = role;
  391 
  392                 if (ocs_hw_get_def_wwn(ocs, i, &sli_wwpn, &sli_wwnn)) {
  393                         ocs_log_err(ocs, "Get default wwn failed \n");
  394                         i++;
  395                         continue;
  396                 }
  397 
  398                 vport->wwpn = ocs_be64toh(sli_wwpn);
  399                 vport->wwnn = ocs_be64toh(sli_wwnn);
  400                 i++;
  401                 ocs_log_debug(ocs, "VPort wwpn: %lx wwnn: %lx \n", vport->wwpn, vport->wwnn);
  402         }
  403 
  404         return 0;
  405 }
  406 
  407 int32_t
  408 ocs_device_attach(ocs_t *ocs)
  409 {
  410         int32_t i;
  411         ocs_io_t *io = NULL;
  412 
  413         if (ocs->attached) {
  414                 ocs_log_warn(ocs, "%s: Device is already attached\n", __func__);
  415                 return -1;
  416         } 
  417 
  418         /* Allocate transport object and bring online */
  419         ocs->xport = ocs_xport_alloc(ocs);
  420         if (ocs->xport == NULL) {
  421                 device_printf(ocs->dev, "failed to allocate transport object\n");
  422                 return ENOMEM;
  423         } else if (ocs_xport_attach(ocs->xport) != 0) {
  424                 device_printf(ocs->dev, "%s: failed to attach transport object\n", __func__);
  425                 goto fail_xport_attach;
  426         } else if (ocs_xport_initialize(ocs->xport) != 0) {
  427                 device_printf(ocs->dev, "%s: failed to initialize transport object\n", __func__);
  428                 goto fail_xport_init;
  429         }
  430 
  431         if (ocs_init_dma_tag(ocs)) {
  432                 goto fail_intr_setup; 
  433         }
  434 
  435         for (i = 0; (io = ocs_io_get_instance(ocs, i)); i++) {
  436                 if (bus_dmamap_create(ocs->buf_dmat, 0, &io->tgt_io.dmap)) {
  437                         device_printf(ocs->dev, "%s: bad dma map create\n", __func__);
  438                 }
  439 
  440                 io->tgt_io.state = OCS_CAM_IO_FREE;
  441         }
  442 
  443         if (ocs_setup_fcports(ocs)) {
  444                 device_printf(ocs->dev, "FCports creation failed\n");
  445                 goto fail_intr_setup;
  446         }
  447 
  448         if (ocs_cam_attach(ocs)) {
  449                 device_printf(ocs->dev, "cam attach failed \n");
  450                 goto fail_intr_setup;
  451         }
  452 
  453         if (ocs_intr_setup(ocs)) {
  454                 device_printf(ocs->dev, "Interrupt setup failed\n");
  455                 goto fail_intr_setup;
  456         }
  457 
  458         if (ocs->enable_ini || ocs->enable_tgt) {
  459                 if (ocs_xport_control(ocs->xport, OCS_XPORT_PORT_ONLINE)) {
  460                         device_printf(ocs->dev, "Can't init port\n");
  461                         goto fail_xport_online;
  462                 }
  463         }
  464 
  465         ocs->attached = true;
  466 
  467         return 0;
  468 
  469 fail_xport_online:
  470         if (ocs_xport_control(ocs->xport, OCS_XPORT_SHUTDOWN)) {
  471                 device_printf(ocs->dev, "Transport Shutdown timed out\n");
  472         }
  473         ocs_intr_teardown(ocs);
  474 fail_intr_setup:
  475 fail_xport_init:
  476         ocs_xport_detach(ocs->xport);
  477         if (ocs->config_tgt)
  478                 ocs_scsi_tgt_del_device(ocs);
  479 
  480         ocs_xport_free(ocs->xport);
  481         ocs->xport = NULL;
  482 fail_xport_attach:
  483         if (ocs->xport) 
  484                 ocs_free(ocs, ocs->xport, sizeof(*(ocs->xport)));
  485         ocs->xport = NULL;
  486         return ENXIO;
  487 }
  488 
  489 /**
  490  * @brief Connect the driver to the given device
  491  *
  492  * If the probe routine is successful, the OS will give the driver
  493  * the opportunity to connect itself to the device. This routine
  494  * maps PCI resources (memory BARs and interrupts) and initialize a
  495  * hardware object.
  496  *
  497  * @param dev device abstraction
  498  *
  499  * @return 0 if the driver attaches to the device, ENXIO otherwise
  500  */
  501 
  502 static int
  503 ocs_pci_attach(device_t dev)
  504 {
  505         struct ocs_softc        *ocs;
  506         int                     instance;
  507 
  508         instance = device_get_unit(dev);
  509 
  510         ocs = (struct ocs_softc *)device_get_softc(dev);
  511         if (NULL == ocs) {
  512                 device_printf(dev, "cannot allocate softc\n");
  513                 return ENOMEM;
  514         }
  515         memset(ocs, 0, sizeof(struct ocs_softc));
  516 
  517         if (instance < ARRAY_SIZE(ocs_devices)) {
  518                 ocs_devices[instance] = ocs;
  519         } else {
  520                 device_printf(dev, "got unexpected ocs instance number %d\n", instance);
  521         }
  522 
  523         ocs->instance_index = instance;
  524 
  525         ocs->dev = dev;
  526 
  527         pci_enable_io(dev, SYS_RES_MEMORY);
  528         pci_enable_busmaster(dev);
  529 
  530         ocs->pci_vendor = pci_get_vendor(dev);
  531         ocs->pci_device = pci_get_device(dev);
  532         ocs->pci_subsystem_vendor = pci_get_subvendor(dev);
  533         ocs->pci_subsystem_device = pci_get_subdevice(dev);
  534 
  535         snprintf(ocs->businfo, sizeof(ocs->businfo), "%02X:%02X:%02X",
  536                 pci_get_bus(dev), pci_get_slot(dev), pci_get_function(dev));
  537 
  538         /* Map all memory BARs */
  539         if (ocs->pci_device == PCI_PRODUCT_EMULEX_LANCER_G7) {
  540                 if(ocs_map_g7_bars(dev,ocs)) {
  541                         device_printf(dev, "Failed to map pci bars\n");
  542                         goto release_bus;
  543                 }
  544         } else {
  545                 if (ocs_map_bars(dev, ocs)) {
  546                         device_printf(dev, "Failed to map pci bars\n");
  547                         goto release_bus;
  548                 }
  549         }
  550 
  551         /* create a root DMA tag for the device */
  552         if (bus_dma_tag_create(bus_get_dma_tag(dev),
  553                                 1,              /* byte alignment */
  554                                 0,              /* no boundary restrictions */
  555                                 BUS_SPACE_MAXADDR, /* no minimum low address */
  556                                 BUS_SPACE_MAXADDR, /* no maximum high address */
  557                                 NULL,           /* no filter function */
  558                                 NULL,           /* or arguments */
  559                                 BUS_SPACE_MAXSIZE, /* max size covered by tag */
  560                                 BUS_SPACE_UNRESTRICTED, /* no segment count restrictions */
  561                                 BUS_SPACE_MAXSIZE, /* no segment length restrictions */
  562                                 0,              /* flags */
  563                                 NULL,           /* no lock manipulation function */
  564                                 NULL,           /* or arguments */
  565                                 &ocs->dmat)) {
  566                 device_printf(dev, "parent DMA tag allocation failed\n");
  567                 goto release_bus;
  568         }
  569 
  570         if (ocs_intr_alloc(ocs)) {
  571                 device_printf(dev, "Interrupt allocation failed\n");
  572                 goto release_bus;
  573         }
  574 
  575         if (PCIC_SERIALBUS == pci_get_class(dev) &&
  576                         PCIS_SERIALBUS_FC == pci_get_subclass(dev))
  577                 ocs->ocs_xport = OCS_XPORT_FC;
  578         else {
  579                 device_printf(dev, "unsupported class (%#x : %#x)\n",
  580                                 pci_get_class(dev),
  581                                 pci_get_class(dev));
  582                 goto release_bus;
  583         }
  584 
  585         /* Setup tunable parameters */
  586         if (ocs_setup_params(ocs)) {
  587                 device_printf(ocs->dev, "failed to setup params\n");
  588                 goto release_bus;
  589         }
  590 
  591         if (ocs_device_attach(ocs)) {
  592                 device_printf(ocs->dev, "failed to attach device\n");
  593                 goto release_params;
  594         }
  595 
  596         ocs->fc_type = FC_TYPE_FCP;
  597 
  598         ocs_debug_attach(ocs);
  599 
  600         return 0;
  601 
  602 release_params:
  603         ocs_ramlog_free(ocs, ocs->ramlog);
  604         ocs_device_lock_free(ocs);
  605         free(ocs->hw_war_version, M_OCS);
  606 release_bus:
  607         ocs_release_bus(ocs);
  608         return ENXIO;
  609 }
  610 
  611 /**
  612  * @brief free resources when pci device detach
  613  *
  614  * @param ocs pointer to ocs structure
  615  *
  616  * @return 0 for success, a negative error code value for failure.
  617  */
  618 
  619 int32_t
  620 ocs_device_detach(ocs_t *ocs)
  621 {
  622         int32_t rc = 0, i;
  623         ocs_io_t *io = NULL;
  624 
  625         if (ocs != NULL) {
  626                 if (!ocs->attached) {
  627                         ocs_log_warn(ocs, "%s: Device is not attached\n", __func__);
  628                         return -1;
  629                 }
  630 
  631                 ocs->attached = FALSE;
  632 
  633                 rc = ocs_xport_control(ocs->xport, OCS_XPORT_SHUTDOWN);
  634                 if (rc) {
  635                         ocs_log_err(ocs, "%s: Transport Shutdown timed out\n", __func__);
  636                 }
  637 
  638                 ocs_intr_teardown(ocs);
  639 
  640                 if (ocs_xport_detach(ocs->xport) != 0) {
  641                         ocs_log_err(ocs, "%s: Transport detach failed\n", __func__);
  642                 }
  643 
  644                 ocs_cam_detach(ocs);
  645                 ocs_free(ocs, ocs->fcports, sizeof(*(ocs->fcports)));
  646 
  647                 for (i = 0; (io = ocs_io_get_instance(ocs, i)); i++) {
  648                         if (bus_dmamap_destroy(ocs->buf_dmat, io->tgt_io.dmap)) {
  649                                 device_printf(ocs->dev, "%s: bad dma map destroy\n", __func__);
  650                         }
  651                 }
  652                 bus_dma_tag_destroy(ocs->dmat);
  653                 ocs_xport_free(ocs->xport);
  654                 ocs->xport = NULL;
  655         }
  656 
  657         return 0;
  658 }
  659 
  660 /**
  661  * @brief Detach the driver from the given device
  662  *
  663  * If the driver is a loadable module, this routine gets called at unload
  664  * time. This routine will stop the device and free any allocated resources.
  665  *
  666  * @param dev device abstraction
  667  *
  668  * @return 0 if the driver detaches from the device, ENXIO otherwise
  669  */
  670 static int
  671 ocs_pci_detach(device_t dev)
  672 {
  673         struct ocs_softc        *ocs;
  674 
  675         ocs = (struct ocs_softc *)device_get_softc(dev);
  676         if (!ocs) {
  677                 device_printf(dev, "no driver context?!?\n");
  678                 return -1;
  679         }
  680 
  681         if (ocs->config_tgt && ocs->enable_tgt) {
  682                 device_printf(dev, "can't detach with target mode enabled\n");
  683                 return EBUSY;
  684         }
  685 
  686         ocs_device_detach(ocs);
  687 
  688         /*
  689          * Workaround for OCS SCSI Transport quirk.
  690          *
  691          * CTL requires that target mode is disabled prior to unloading the
  692          * driver (ie ocs->enable_tgt = FALSE), but once the target is disabled,
  693          * the transport will not call ocs_scsi_tgt_del_device() which deallocates
  694          * CAM resources. The workaround is to explicitly make the call here.
  695          */
  696         if (ocs->config_tgt)
  697                 ocs_scsi_tgt_del_device(ocs);
  698         
  699         /* free strdup created buffer.*/
  700         free(ocs->hw_war_version, M_OCS);
  701 
  702         ocs_device_lock_free(ocs);
  703 
  704         ocs_debug_detach(ocs);
  705 
  706         ocs_ramlog_free(ocs, ocs->ramlog);
  707 
  708         ocs_release_bus(ocs);
  709 
  710         return 0;
  711 }
  712 
  713 /**
  714  * @brief Notify driver of system shutdown
  715  *
  716  * @param dev device abstraction
  717  *
  718  * @return 0 if the driver attaches to the device, ENXIO otherwise
  719  */
  720 static int
  721 ocs_pci_shutdown(device_t dev)
  722 {
  723         device_printf(dev, "%s\n", __func__);
  724         return 0;
  725 }
  726 
  727 /**
  728  * @brief Release bus resources allocated within the soft context
  729  *
  730  * @param ocs Pointer to the driver's context
  731  *
  732  * @return none
  733  */
  734 static void
  735 ocs_release_bus(struct ocs_softc *ocs)
  736 {
  737 
  738         if (NULL != ocs) {
  739                 uint32_t        i;
  740 
  741                 ocs_intr_teardown(ocs);
  742 
  743                 if (ocs->irq) {
  744                         bus_release_resource(ocs->dev, SYS_RES_IRQ,
  745                                         rman_get_rid(ocs->irq), ocs->irq);
  746 
  747                         if (ocs->n_vec) {
  748                                 pci_release_msi(ocs->dev);
  749                                 ocs->n_vec = 0;
  750                         }
  751 
  752                         ocs->irq = NULL;
  753                 }
  754 
  755                 bus_dma_tag_destroy(ocs->dmat);
  756 
  757                 for (i = 0; i < PCI_MAX_BAR; i++) {
  758                         if (ocs->reg[i].res) {
  759                                 bus_release_resource(ocs->dev, SYS_RES_MEMORY,
  760                                                 ocs->reg[i].rid,
  761                                                 ocs->reg[i].res);
  762                         }
  763                 }
  764         }
  765 }
  766 
  767 /**
  768  * @brief Allocate and initialize interrupts
  769  *
  770  * @param ocs Pointer to the driver's context
  771  *
  772  * @return none
  773  */
  774 static int32_t
  775 ocs_intr_alloc(struct ocs_softc *ocs)
  776 {
  777 
  778         ocs->n_vec = 1;
  779         if (pci_alloc_msix(ocs->dev, &ocs->n_vec)) {
  780                 device_printf(ocs->dev, "MSI-X allocation failed\n");
  781                 if (pci_alloc_msi(ocs->dev, &ocs->n_vec)) {
  782                         device_printf(ocs->dev, "MSI allocation failed \n");
  783                         ocs->irqid = 0;
  784                         ocs->n_vec = 0;
  785                 } else 
  786                         ocs->irqid = 1;
  787         } else {
  788                 ocs->irqid = 1;
  789         }
  790 
  791         ocs->irq = bus_alloc_resource_any(ocs->dev, SYS_RES_IRQ, &ocs->irqid,
  792                         RF_ACTIVE | RF_SHAREABLE);
  793         if (NULL == ocs->irq) {
  794                 device_printf(ocs->dev, "could not allocate interrupt\n");
  795                 return -1;
  796         }
  797 
  798         ocs->intr_ctx.vec = 0;
  799         ocs->intr_ctx.softc = ocs;
  800         snprintf(ocs->intr_ctx.name, sizeof(ocs->intr_ctx.name),
  801                         "%s_intr_%d",
  802                         device_get_nameunit(ocs->dev),
  803                         ocs->intr_ctx.vec);
  804 
  805         return 0;
  806 }
  807 
  808 /**
  809  * @brief Create and attach an interrupt handler
  810  *
  811  * @param ocs Pointer to the driver's context
  812  *
  813  * @return 0 on success, non-zero otherwise
  814  */
  815 static int32_t
  816 ocs_intr_setup(struct ocs_softc *ocs)
  817 {
  818         driver_filter_t *filter = NULL;
  819 
  820         if (0 == ocs->n_vec) {
  821                 filter = ocs_pci_intx_filter;
  822         }
  823 
  824         if (bus_setup_intr(ocs->dev, ocs->irq, INTR_MPSAFE | INTR_TYPE_CAM,
  825                                 filter, ocs_pci_intr, &ocs->intr_ctx,
  826                                 &ocs->tag)) {
  827                 device_printf(ocs->dev, "could not initialize interrupt\n");
  828                 return -1;
  829         }
  830 
  831         return 0;
  832 }
  833 
  834 /**
  835  * @brief Detach an interrupt handler
  836  *
  837  * @param ocs Pointer to the driver's context
  838  *
  839  * @return 0 on success, non-zero otherwise
  840  */
  841 static int32_t
  842 ocs_intr_teardown(struct ocs_softc *ocs)
  843 {
  844 
  845         if (!ocs) {
  846                 printf("%s: bad driver context?!?\n", __func__);
  847                 return -1;
  848         }
  849 
  850         if (ocs->tag) {
  851                 bus_teardown_intr(ocs->dev, ocs->irq, ocs->tag);
  852                 ocs->tag = NULL;
  853         }
  854 
  855         return 0;
  856 }
  857 
  858 /**
  859  * @brief PCI interrupt handler
  860  *
  861  * @param arg pointer to the driver's software context
  862  *
  863  * @return FILTER_HANDLED if interrupt is processed, FILTER_STRAY otherwise
  864  */
  865 static int
  866 ocs_pci_intx_filter(void *arg)
  867 {
  868         ocs_intr_ctx_t  *intr = arg;
  869         struct ocs_softc *ocs = NULL;
  870         uint16_t        val = 0;
  871 
  872         if (NULL == intr) {
  873                 return FILTER_STRAY;
  874         }
  875 
  876         ocs = intr->softc;
  877 #ifndef PCIM_STATUS_INTR
  878 #define PCIM_STATUS_INTR        0x0008
  879 #endif
  880         val = pci_read_config(ocs->dev, PCIR_STATUS, 2);
  881         if (0xffff == val) {
  882                 device_printf(ocs->dev, "%s: pci_read_config(PCIR_STATUS) failed\n", __func__);
  883                 return FILTER_STRAY;
  884         }
  885         if (0 == (val & PCIM_STATUS_INTR)) {
  886                 return FILTER_STRAY;
  887         }
  888 
  889         val = pci_read_config(ocs->dev, PCIR_COMMAND, 2);
  890         val |= PCIM_CMD_INTxDIS;
  891         pci_write_config(ocs->dev, PCIR_COMMAND, val, 2);
  892 
  893         return FILTER_SCHEDULE_THREAD;
  894 }
  895 
  896 /**
  897  * @brief interrupt handler
  898  *
  899  * @param context pointer to the interrupt context
  900  */
  901 static void
  902 ocs_pci_intr(void *context)
  903 {
  904         ocs_intr_ctx_t  *intr = context;
  905         struct ocs_softc *ocs = intr->softc;
  906 
  907         mtx_lock(&ocs->sim_lock);
  908                 ocs_hw_process(&ocs->hw, intr->vec, OCS_OS_MAX_ISR_TIME_MSEC);
  909         mtx_unlock(&ocs->sim_lock);
  910 }
  911 
  912 /**
  913  * @brief Initialize DMA tag
  914  *
  915  * @param ocs the driver instance's software context
  916  *
  917  * @return 0 on success, non-zero otherwise
  918  */
  919 static int32_t
  920 ocs_init_dma_tag(struct ocs_softc *ocs)
  921 {
  922         uint32_t        max_sgl = 0;
  923         uint32_t        max_sge = 0;
  924 
  925         /*
  926          * IOs can't use the parent DMA tag and must create their
  927          * own, based primarily on a restricted number of DMA segments.
  928          * This is more of a BSD requirement than a SLI Port requirement
  929          */
  930         ocs_hw_get(&ocs->hw, OCS_HW_N_SGL, &max_sgl);
  931         ocs_hw_get(&ocs->hw, OCS_HW_MAX_SGE, &max_sge);
  932 
  933         if (bus_dma_tag_create(ocs->dmat,
  934                                 1,              /* byte alignment */
  935                                 0,              /* no boundary restrictions */
  936                                 BUS_SPACE_MAXADDR, /* no minimum low address */
  937                                 BUS_SPACE_MAXADDR, /* no maximum high address */
  938                                 NULL,           /* no filter function */
  939                                 NULL,           /* or arguments */
  940                                 BUS_SPACE_MAXSIZE, /* max size covered by tag */
  941                                 max_sgl,        /* segment count restrictions */
  942                                 max_sge,        /* segment length restrictions */
  943                                 0,              /* flags */
  944                                 NULL,           /* no lock manipulation function */
  945                                 NULL,           /* or arguments */
  946                                 &ocs->buf_dmat)) {
  947                 device_printf(ocs->dev, "%s: bad bus_dma_tag_create(buf_dmat)\n", __func__);
  948                 return -1;
  949         }
  950         return 0;
  951 }
  952 
  953 int32_t
  954 ocs_get_property(const char *prop_name, char *buffer, uint32_t buffer_len)
  955 {
  956         return -1;
  957 }
  958 
  959 /**
  960  * @brief return pointer to ocs structure given instance index
  961  *
  962  * A pointer to an ocs structure is returned given an instance index.
  963  *
  964  * @param index index to ocs_devices array
  965  *
  966  * @return ocs pointer
  967  */
  968 
  969 ocs_t *ocs_get_instance(uint32_t index)
  970 {
  971         if (index < ARRAY_SIZE(ocs_devices)) {
  972                 return ocs_devices[index];
  973         }
  974         return NULL;
  975 }
  976 
  977 /**
  978  * @brief Return instance index of an opaque ocs structure
  979  *
  980  * Returns the ocs instance index
  981  *
  982  * @param os pointer to ocs instance
  983  *
  984  * @return pointer to ocs instance index
  985  */
  986 uint32_t
  987 ocs_instance(void *os)
  988 {
  989         ocs_t *ocs = os;
  990         return ocs->instance_index;
  991 }
  992 
  993 static device_method_t ocs_methods[] = {
  994         DEVMETHOD(device_probe,         ocs_pci_probe),
  995         DEVMETHOD(device_attach,        ocs_pci_attach),
  996         DEVMETHOD(device_detach,        ocs_pci_detach),
  997         DEVMETHOD(device_shutdown,      ocs_pci_shutdown),
  998         {0, 0}
  999 };
 1000 
 1001 static driver_t ocs_driver = {
 1002         "ocs_fc",
 1003         ocs_methods,
 1004         sizeof(struct ocs_softc)
 1005 };
 1006 
 1007 DRIVER_MODULE(ocs_fc, pci, ocs_driver, 0, 0);
 1008 MODULE_VERSION(ocs_fc, 1);

Cache object: a0341fa18c6815a5bbf4081c137b49f3


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