"Fossies" - the Fresh Open Source Software Archive

Member "open-fcoe-3.19/libhbalinux/lport.c" (15 Apr 2015, 20802 Bytes) of package /linux/misc/open-fcoe-3.19.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "lport.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.11_vs_3.19.

    1 /*
    2  * Copyright (c) 2008, Intel Corporation.
    3  *
    4  * This program is free software; you can redistribute it and/or modify it
    5  * under the terms and conditions of the GNU Lesser General Public License,
    6  * version 2.1, as published by the Free Software Foundation.
    7  *
    8  * This program is distributed in the hope it will be useful, but WITHOUT
    9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
   11  * for more details.
   12  *
   13  * You should have received a copy of the GNU Lesser General Public License
   14  * along with this program; if not, write to the Free Software Foundation, Inc.,
   15  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
   16  *
   17  */
   18 
   19 #include "utils.h"
   20 #include "api_lib.h"
   21 #include "adapt_impl.h"
   22 
   23 #ifndef HBA_STATUS_ERROR_ILLEGAL_FCID
   24 #define HBA_STATUS_ERROR_ILLEGAL_FCID 33    /* defined after HBA-API 2.2 */
   25 #endif
   26 #define SEND_CT_TIMEOUT     (3 * 1000)  /* timeout in milliseconds */
   27 
   28 /*
   29  * The following are temporary settings until we can find a way to
   30  * collect these information.
   31  */
   32 #define HBA_ROM_VERSION         ""
   33 #define HBA_FW_VERSION          ""
   34 #define HBA_VENDOR_SPECIFIC_ID  0
   35 
   36 /*
   37  * table of /sys port types strings to HBA-API values.
   38  */
   39 struct sa_nameval port_types_table[] = {
   40     { "Unknown",        HBA_PORTTYPE_UNKNOWN },
   41     { "Other",      HBA_PORTTYPE_OTHER },
   42     { "Not Present",    HBA_PORTTYPE_NOTPRESENT },
   43     { "NPort (fabric via point-to-point)",  HBA_PORTTYPE_NPORT },
   44     { "NLPort (fabric via loop)",   HBA_PORTTYPE_NLPORT },
   45     { "LPort (private loop)",   HBA_PORTTYPE_LPORT },
   46     { "Point-To-Point (direct nport connection)",   HBA_PORTTYPE_PTP },
   47     {  "NPIV VPORT",    HBA_PORTTYPE_NPORT },
   48     { NULL, 0 }
   49 };
   50 
   51 /*
   52  * table of /sys port state strings to HBA-API values.
   53  */
   54 struct sa_nameval port_states_table[] = {
   55     { "Not Present",    HBA_PORTSTATE_UNKNOWN },
   56     { "Online",         HBA_PORTSTATE_ONLINE },
   57     { "Offline",        HBA_PORTSTATE_OFFLINE },
   58     { "Blocked",        HBA_PORTSTATE_UNKNOWN },
   59     { "Bypassed",       HBA_PORTSTATE_BYPASSED },
   60     { "Diagnostics",    HBA_PORTSTATE_DIAGNOSTICS },
   61     { "Linkdown",       HBA_PORTSTATE_LINKDOWN },
   62     { "Error",          HBA_PORTSTATE_ERROR },
   63     { "Loopback",       HBA_PORTSTATE_LOOPBACK },
   64     { "Deleted",        HBA_PORTSTATE_UNKNOWN },
   65     { NULL, 0 }
   66 };
   67 
   68 /*
   69  * table of /sys port speed strings to HBA-API values.
   70  */
   71 struct sa_nameval port_speeds_table[] = {
   72     { "Unknown",        HBA_PORTSPEED_UNKNOWN },
   73     { "1 Gbit",         HBA_PORTSPEED_1GBIT },
   74     { "2 Gbit",         HBA_PORTSPEED_2GBIT },
   75     { "4 Gbit",         HBA_PORTSPEED_4GBIT },
   76     { "10 Gbit",        HBA_PORTSPEED_10GBIT },
   77     { "8 Gbit",         HBA_PORTSPEED_8GBIT },
   78     { "16 Gbit",        HBA_PORTSPEED_16GBIT },
   79     { "32 Gbit",        HBA_PORTSPEED_32GBIT },
   80     { "20 Gbit",        HBA_PORTSPEED_20GBIT },
   81     { "40 Gbit",        HBA_PORTSPEED_40GBIT },
   82     { "Not Negotiated", HBA_PORTSPEED_NOT_NEGOTIATED },
   83     { NULL, 0 }
   84 };
   85 
   86 /*
   87  * parse strings from /sys port speed/support_speeds files
   88  * and convert them to bitmasks for the HBA_PORTSPEED supported
   89  * Format expected: "1 Gbit[, 10 Gbit]", etc.
   90  */
   91 static int sys_read_speed(const char *dir, const char *file, char *buf,
   92               size_t buflen, HBA_PORTSPEED *speeds)
   93 {
   94     int rc = 0;
   95     u_int32_t val = 0;
   96     int len = 0;
   97     char *cp;
   98     struct sa_nameval *tp = port_speeds_table;
   99 
  100     rc = sa_sys_read_line(dir, file, buf, buflen);
  101     if (rc == 0 && strstr(buf, "Unknown") == NULL) {
  102         for (cp = buf; *cp != '\0';) {
  103             for (; tp->nv_name != NULL; tp++) {
  104                 len = strlen(tp->nv_name);
  105                 if (strncasecmp(tp->nv_name, cp, len) == 0) {
  106                     val |= tp->nv_val;
  107                     cp += len;
  108                     break;
  109                 }
  110             }
  111             if (*cp == '\0')
  112                 break;
  113             if (*cp == ',') {
  114                 cp++;
  115                 if (*cp == ' ')
  116                     cp++;
  117             }
  118             else
  119                 break; /* invalid string */
  120         }
  121     }
  122 
  123     *speeds = val;
  124 
  125     return rc;
  126 }
  127 
  128 /*
  129  * Code for OpenFC-supported adapters.
  130  */
  131 
  132 static int
  133 counting_rports(struct dirent *dp, void *arg)
  134 {
  135     int *count = (int *)arg;
  136 
  137     if (!strstr(dp->d_name, "rport-"))
  138         return HBA_STATUS_OK;
  139     (*count)++;
  140     return HBA_STATUS_OK;
  141 }
  142 
  143 static int
  144 check_ifindex(struct dirent *dp, void *arg)
  145 {
  146     char *ifindex = (char *)arg;
  147     char hba_dir[256];
  148     char buf[256];
  149     int rc;
  150 
  151     snprintf(hba_dir, sizeof(hba_dir),
  152          SYSFS_HBA_DIR "/%s", dp->d_name);
  153     memset(buf, 0, sizeof(buf));
  154     rc = sa_sys_read_line(hba_dir, "ifindex", buf, sizeof(buf) - 1);
  155     if (rc)
  156         return 0;
  157     if (!strncmp(ifindex, buf, sizeof(buf))) {
  158         strcpy(arg, dp->d_name);
  159         return 1;
  160     }
  161     return 0;
  162 }
  163 
  164 /*
  165  * find_phys_if - find the regular network interface name that
  166  *                has the ifindex that matches the specified iflink.
  167  *                This ifname will be used to find the PCI info
  168  *                of a VLAN interface.
  169  * hba_dir: hba_dir of VLAN interface.
  170  * buf: returns ifname of regular network interface.
  171  */
  172 static int
  173 find_phys_if(char *hba_dir, char *buf, size_t len)
  174 {
  175     int rc;
  176 
  177     rc = sa_sys_read_line(hba_dir, "iflink", buf, len);
  178     if (rc)
  179         return 1;
  180     /*
  181      * Search for the regular network interface and
  182      * return the interface name in the buf.
  183      */
  184     sa_dir_read(SYSFS_HBA_DIR, check_ifindex, buf);
  185     return 0;
  186 }
  187 
  188 static int
  189 sysfs_scan(struct dirent *dp, void *arg)
  190 {
  191     HBA_ADAPTERATTRIBUTES *atp;
  192     HBA_PORTATTRIBUTES *pap;
  193     HBA_WWN wwnn;
  194     struct hba_info hba_info;
  195     struct adapter_info *ap;
  196     struct port_info *pp;
  197     char host_dir[80], hba_dir[80], drv_dir[80];
  198     char dev_dir[128];
  199     char ifname[20], buf[256];
  200     char *driverName;
  201     int data[32], rc, i;
  202     char *cp;
  203     char *saveptr;  /* for strtok_r */
  204     unsigned int ifindex;
  205     unsigned int iflink;
  206 
  207     memset(&hba_info, 0, sizeof(hba_info));
  208 
  209     /*
  210      * Create a new HBA entry (ap) for the local port
  211      * We will create a new HBA entry for each local port.
  212      */
  213     ap = malloc(sizeof(*ap));
  214     if (!ap) {
  215         fprintf(stderr, "%s: malloc failed, errno=0x%x\n",
  216             __func__, errno);
  217         return HBA_STATUS_ERROR;
  218     }
  219     memset(ap, 0, sizeof(*ap));
  220     ap->ad_kern_index = atoi(dp->d_name + sizeof("host") - 1);
  221     ap->ad_port_count = 1;
  222 
  223     /* atp points to the HBA attributes structure */
  224     atp = &ap->ad_attr;
  225 
  226     /*
  227      * Create a new local port entry
  228      */
  229     pp = malloc(sizeof(*pp));
  230     if (pp == NULL) {
  231         fprintf(stderr,
  232             "%s: malloc for local port %d failed,"
  233             " errno=0x%x\n", __func__,
  234             ap->ad_port_count - 1, errno);
  235         free(ap);
  236         return 0;
  237     }
  238 
  239     memset(pp, 0, sizeof(*pp));
  240     pp->ap_adapt = ap;
  241     pp->ap_index = ap->ad_port_count - 1;
  242     pp->ap_kern_hba = atoi(dp->d_name + sizeof("host") - 1);
  243 
  244     /* pap points to the local port attributes structure */
  245     pap = &pp->ap_attr;
  246 
  247     /* Construct the host directory name from the input name */
  248     snprintf(host_dir, sizeof(host_dir),
  249         SYSFS_HOST_DIR "/%s", dp->d_name);
  250 
  251     rc = sa_sys_read_line(host_dir, "symbolic_name", buf, sizeof(buf));
  252 
  253     /* Get PortSymbolicName */
  254     sa_strncpy_safe(pap->PortSymbolicName, sizeof(pap->PortSymbolicName),
  255             buf, sizeof(buf));
  256 
  257     /* Skip the HBA if it isn't OpenFC */
  258     cp = strstr(pap->PortSymbolicName, " over ");
  259     if (!cp)
  260         goto skip;
  261 
  262     /*
  263      * See if <host_dir>/device is a PCI symlink.
  264      * If not, try it as a net device.
  265      */
  266     snprintf(dev_dir, sizeof(dev_dir), "%s/device", host_dir);
  267     i = readlink(dev_dir, buf, sizeof(buf) - 1);
  268     if (i < 0)
  269         i = 0;
  270     buf[i] = '\0';
  271 
  272     if (strstr(buf, "devices/pci") && !strstr(buf, "/net/")) {
  273         snprintf(hba_dir, sizeof(hba_dir), "%s/device/..", host_dir);
  274     } else {
  275         /* assume a net device */
  276         cp += 6;
  277         sa_strncpy_safe(ifname, sizeof(ifname), cp, strlen(cp));
  278         snprintf(hba_dir, sizeof(hba_dir),
  279              SYSFS_HBA_DIR "/%s", ifname);
  280         /*
  281          * Try as VLAN device or other virtual net device.
  282          * If this is the case, ifindex and iflink will be different.
  283          * iflink is the ifindex of the physical device.
  284          */
  285         rc = sa_sys_read_u32(hba_dir, "ifindex", &ifindex);
  286         if (rc < 0)
  287             goto skip;
  288         rc = sa_sys_read_u32(hba_dir, "iflink", &iflink);
  289         if (rc < 0)
  290             goto skip;
  291         if (ifindex != iflink) {
  292             rc = find_phys_if(hba_dir, buf, sizeof(buf));
  293             if (rc)
  294                 goto skip;
  295             strncpy(ifname, buf, sizeof(ifname));
  296         }
  297 
  298         snprintf(hba_dir, sizeof(hba_dir),
  299              SYSFS_HBA_DIR "/%s/device", ifname);
  300         i = readlink(hba_dir, buf, sizeof(buf) - 1);
  301         if (i < 0)
  302             goto skip;
  303         buf[i] = '\0';
  304     }
  305 
  306     /*
  307      * Assume a PCI symlink value is in buf.
  308      * Back up to the last path component that looks like a PCI element.
  309      * A sample link value is like:
  310      *  ../../devices/pci*.../0000:03:00.0
  311      */
  312     rc = 0;
  313     do {
  314         cp = strrchr(buf, '/');
  315         if (!cp)
  316             break;
  317         rc = sscanf(cp + 1, "%x:%x:%x.%x",
  318                 &hba_info.domain, &hba_info.bus,
  319                 &hba_info.dev, &hba_info.func);
  320         if (rc == 4)
  321             break;
  322         *cp = '\0';
  323     } while (cp && cp > buf);
  324 
  325     if (rc != 4)
  326         goto skip;
  327 
  328     /*
  329      * Save the host directory and the hba directory
  330      * in local port structure
  331      */
  332     sa_strncpy_safe(pp->host_dir, sizeof(pp->host_dir),
  333             host_dir, sizeof(host_dir));
  334 
  335     /* Get NodeWWN */
  336     rc = sys_read_wwn(pp->host_dir, "node_name", &wwnn);
  337     memcpy(&pap->NodeWWN, &wwnn, sizeof(wwnn));
  338 
  339     /* Get PortWWN */
  340     rc = sys_read_wwn(pp->host_dir, "port_name", &pap->PortWWN);
  341 
  342     /* Get PortFcId */
  343     rc = sa_sys_read_u32(pp->host_dir, "port_id", &pap->PortFcId);
  344 
  345     /* Get PortType */
  346     rc = sa_sys_read_line(pp->host_dir, "port_type", buf, sizeof(buf));
  347     rc = sa_enum_encode(port_types_table, buf, &pap->PortType);
  348 
  349     /* Get PortState */
  350     rc = sa_sys_read_line(pp->host_dir, "port_state", buf, sizeof(buf));
  351     rc = sa_enum_encode(port_states_table, buf, &pap->PortState);
  352 
  353     /* Get PortSpeed */
  354     rc = sys_read_speed(pp->host_dir, "speed",
  355                 buf, sizeof(buf),
  356                 &pap->PortSpeed);
  357 
  358     /* Get PortSupportedSpeed */
  359     rc = sys_read_speed(pp->host_dir, "supported_speeds",
  360                 buf, sizeof(buf),
  361                 &pap->PortSupportedSpeed);
  362 
  363     /* Get PortMaxFrameSize */
  364     rc = sa_sys_read_line(pp->host_dir, "maxframe_size", buf, sizeof(buf));
  365     sscanf(buf, "%d", &pap->PortMaxFrameSize);
  366 
  367     /* Get PortSupportedFc4Types */
  368     rc = sa_sys_read_line(pp->host_dir, "supported_fc4s", buf, sizeof(buf));
  369     sscanf(buf, "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x "
  370             "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x "
  371             "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x "
  372             "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",
  373         &data[0], &data[1], &data[2], &data[3], &data[4], &data[5],
  374         &data[6], &data[7], &data[8], &data[9], &data[10], &data[11],
  375         &data[12], &data[13], &data[14], &data[15], &data[16],
  376         &data[17], &data[18], &data[19], &data[20], &data[21],
  377         &data[22], &data[23], &data[24], &data[25], &data[26],
  378         &data[27], &data[28], &data[29], &data[30], &data[31]);
  379     for (i = 0; i < 32; i++)
  380         pap->PortSupportedFc4Types.bits[i] = data[i];
  381 
  382     /* Get PortActiveFc4Types */
  383     rc = sa_sys_read_line(pp->host_dir, "active_fc4s", buf, sizeof(buf));
  384     sscanf(buf, "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x "
  385             "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x "
  386             "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x "
  387             "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",
  388         &data[0], &data[1], &data[2], &data[3], &data[4], &data[5],
  389         &data[6], &data[7], &data[8], &data[9], &data[10], &data[11],
  390         &data[12], &data[13], &data[14], &data[15], &data[16],
  391         &data[17], &data[18], &data[19], &data[20], &data[21],
  392         &data[22], &data[23], &data[24], &data[25], &data[26],
  393         &data[27], &data[28], &data[29], &data[30], &data[31]);
  394     for (i = 0; i < 32; i++)
  395         pap->PortActiveFc4Types.bits[i] = data[i];
  396 
  397     /* Get FabricName */
  398     rc = sys_read_wwn(pp->host_dir, "fabric_name", &pap->FabricName);
  399 
  400     /* Get PortSupportedClassofService */
  401     rc = sa_sys_read_line(pp->host_dir, "supported_classes",
  402                 buf, sizeof(buf));
  403 
  404     cp = strstr(buf, "Class");
  405     if (cp)
  406         pap->PortSupportedClassofService = *(cp + 6) - '0';
  407 
  408     /* Get OSDeviceName */
  409     sa_strncpy_safe(pap->OSDeviceName, sizeof(pap->OSDeviceName),
  410             dp->d_name, sizeof(dp->d_name));
  411 
  412     /* Get NumberofDiscoveredPorts */
  413     snprintf(buf, sizeof(buf), "%s/device", pp->host_dir);
  414     sa_dir_read(buf, counting_rports, &pap->NumberofDiscoveredPorts);
  415 
  416     /*
  417      * Add the local port structure into local port table within
  418      * the HBA structure.
  419      */
  420     if (sa_table_insert(&ap->ad_ports, pp->ap_index, pp) < 0) {
  421         fprintf(stderr,
  422             "%s: insert of HBA %d port %d failed\n",
  423             __func__, ap->ad_kern_index, pp->ap_index);
  424         goto skip;
  425     }
  426 
  427     /* Create adapter name */
  428     snprintf(buf, sizeof(buf), "fcoe:%s", ifname);
  429     ap->ad_name = strdup(buf);
  430 
  431     /* Get vendor_id */
  432     rc = sa_sys_read_u32(hba_dir, "vendor", &hba_info.vendor_id);
  433 
  434     /* Get device_id */
  435     rc = sa_sys_read_u32(hba_dir, "device", &hba_info.device_id);
  436 
  437     /* Get subsystem_vendor_id */
  438     rc = sa_sys_read_u32(hba_dir, "subsystem_vendor",
  439                 &hba_info.subsystem_vendor_id);
  440 
  441     /* Get subsystem_device_id */
  442     rc = sa_sys_read_u32(hba_dir, "subsystem_device",
  443                 &hba_info.subsystem_device_id);
  444 
  445     /* Get device_class */
  446     rc = sa_sys_read_u32(hba_dir, "class", &hba_info.device_class);
  447     hba_info.device_class = hba_info.device_class>>8;
  448 
  449     /*
  450      * Get Hardware Information via PCI Library
  451      */
  452     (void) find_pci_device(&hba_info);
  453 
  454     /* Get Number of Ports */
  455     atp->NumberOfPorts = hba_info.NumberOfPorts;
  456 
  457     /* Get Manufacturer */
  458     sa_strncpy_safe(atp->Manufacturer, sizeof(atp->Manufacturer),
  459             hba_info.Manufacturer, sizeof(hba_info.Manufacturer));
  460 
  461     /* Get SerialNumber */
  462     sa_strncpy_safe(atp->SerialNumber, sizeof(atp->SerialNumber),
  463             hba_info.SerialNumber, sizeof(hba_info.SerialNumber));
  464 
  465 
  466     /* Get ModelDescription */
  467     sa_strncpy_safe(atp->ModelDescription, sizeof(atp->ModelDescription),
  468             hba_info.ModelDescription,
  469             sizeof(hba_info.ModelDescription));
  470     if (!strncmp(hba_info.ModelDescription, "Unknown",
  471          sizeof(hba_info.ModelDescription))) {
  472         snprintf(atp->ModelDescription, sizeof(atp->ModelDescription),
  473             "[%04x:%04x]-[%04x:%04x]-(%04x)",
  474             hba_info.vendor_id, hba_info.device_id,
  475             hba_info.subsystem_vendor_id,
  476             hba_info.subsystem_device_id,
  477             hba_info.device_class);
  478         /*
  479          * Get Model
  480          *
  481          * If the device is a newly developed product, and
  482          * the model description is not in pci.ids yet, use
  483          * the model description constructed above as the
  484          * model string.
  485          */
  486         sa_strncpy_safe(atp->Model, sizeof(atp->Model),
  487                 atp->ModelDescription,
  488                 sizeof(atp->ModelDescription));
  489     }
  490 
  491     /*
  492      * Get Model
  493      *
  494      * If the device name has already been added into
  495      * the pci.ids file, use the first word of the model
  496      * description as the model. If the space after the
  497      * first word is not found (new product), use the
  498      * model description as the model.
  499      */
  500     sa_strncpy_safe(buf, sizeof(buf), atp->ModelDescription,
  501             sizeof(atp->ModelDescription));
  502     if (strtok_r(buf, " ", &saveptr))
  503         sa_strncpy_safe(atp->Model, sizeof(atp->Model),
  504                 buf, strnlen(buf, sizeof(buf)));
  505     else
  506         sa_strncpy_safe(atp->Model, sizeof(atp->Model),
  507                 atp->ModelDescription,
  508                 sizeof(atp->ModelDescription));
  509 
  510     /* Get HardwareVersion */
  511     sa_strncpy_safe(atp->HardwareVersion, sizeof(atp->HardwareVersion),
  512             hba_info.HardwareVersion,
  513             sizeof(hba_info.HardwareVersion));
  514 
  515     /* Get OptionROMVersion (TODO) */
  516     sa_strncpy_safe(atp->OptionROMVersion, sizeof(atp->OptionROMVersion),
  517             HBA_ROM_VERSION, sizeof(HBA_ROM_VERSION));
  518 
  519     /* Get FirmwareVersion (TODO) */
  520     sa_strncpy_safe(atp->FirmwareVersion, sizeof(atp->FirmwareVersion),
  521             HBA_FW_VERSION, sizeof(HBA_FW_VERSION));
  522 
  523     /* Get VendorSpecificID (TODO) */
  524     atp->VendorSpecificID = HBA_VENDOR_SPECIFIC_ID;
  525 
  526     /* Get DriverVersion */
  527     rc = sa_sys_read_line(hba_dir, SYSFS_MODULE_VER,
  528             atp->DriverVersion, sizeof(atp->DriverVersion));
  529 
  530     /* Get NodeSymbolicName */
  531     sa_strncpy_safe(atp->NodeSymbolicName, sizeof(atp->NodeSymbolicName),
  532             ap->ad_name, sizeof(atp->NodeSymbolicName));
  533 
  534     /* Get NodeWWN - The NodeWWN is the same as
  535      *               the NodeWWN of the local port.
  536      */
  537     memcpy((char *)&atp->NodeWWN, (char *)&pap->NodeWWN,
  538         sizeof(pap->NodeWWN));
  539 
  540     /* Get DriverName */
  541     snprintf(drv_dir, sizeof(drv_dir), "%s" SYSFS_MODULE , hba_dir);
  542     i = readlink(drv_dir, buf, sizeof(buf));
  543     if (i < 0)
  544         i = 0;
  545     buf[i] = '\0';
  546     if (!strstr(buf, "module")) {
  547         /*
  548          * Does not find "module" in the string.
  549          * This should not happen. In this case, set
  550          * the driver name to "Unknown".
  551          */
  552         driverName = "Unknown";
  553     } else
  554         driverName = strstr(buf, "module") + 7;
  555     sa_strncpy_safe(atp->DriverName, sizeof(atp->DriverName),
  556             driverName, sizeof(atp->DriverName));
  557 
  558     /*
  559      * Give HBA to library
  560      */
  561     rc = adapter_create(ap);
  562     if (rc != HBA_STATUS_OK) {
  563         fprintf(stderr, "%s: adapter_create failed, status=%d\n",
  564             __func__, rc);
  565         adapter_destroy(ap);      /* free adapter and ports */
  566     }
  567 
  568     return 0;
  569 
  570 skip:
  571     free(pp);
  572     free(ap);
  573     return 0;
  574 }
  575 
  576 void
  577 copy_wwn(HBA_WWN *dest, fc_wwn_t src)
  578 {
  579     dest->wwn[0] = (u_char) (src >> 56);
  580     dest->wwn[1] = (u_char) (src >> 48);
  581     dest->wwn[2] = (u_char) (src >> 40);
  582     dest->wwn[3] = (u_char) (src >> 32);
  583     dest->wwn[4] = (u_char) (src >> 24);
  584     dest->wwn[5] = (u_char) (src >> 16);
  585     dest->wwn[6] = (u_char) (src >> 8);
  586     dest->wwn[7] = (u_char) src;
  587 }
  588 
  589 /* Test for a non-zero WWN */
  590 int
  591 is_wwn_nonzero(HBA_WWN *wwn)
  592 {
  593     return (wwn->wwn[0] | wwn->wwn[1] | wwn->wwn[2] | wwn->wwn[3] |
  594         wwn->wwn[4] | wwn->wwn[5] | wwn->wwn[6] | wwn->wwn[7]) != 0;
  595 }
  596 
  597 int
  598 sys_read_wwn(const char *dir, const char *file, HBA_WWN *wwn)
  599 {
  600     int rc;
  601     u_int64_t val;
  602 
  603     rc = sa_sys_read_u64(dir, file, &val);
  604     if (rc == 0)
  605         copy_wwn(wwn, val);
  606     return rc;
  607 }
  608 
  609 /* Port Statistics */
  610 HBA_STATUS
  611 sysfs_get_port_stats(char *dir, HBA_PORTSTATISTICS *sp)
  612 {
  613     int rc;
  614 
  615     rc  = sa_sys_read_u64(dir, "seconds_since_last_reset",
  616                 (u_int64_t *)&sp->SecondsSinceLastReset);
  617     rc |= sa_sys_read_u64(dir, "tx_frames", (u_int64_t *)&sp->TxFrames);
  618     rc |= sa_sys_read_u64(dir, "tx_words", (u_int64_t *)&sp->TxWords);
  619     rc |= sa_sys_read_u64(dir, "rx_frames", (u_int64_t *)&sp->RxFrames);
  620     rc |= sa_sys_read_u64(dir, "rx_words", (u_int64_t *)&sp->RxWords);
  621     rc |= sa_sys_read_u64(dir, "lip_count", (u_int64_t *)&sp->LIPCount);
  622     rc |= sa_sys_read_u64(dir, "nos_count", (u_int64_t *)&sp->NOSCount);
  623     rc |= sa_sys_read_u64(dir, "error_frames",
  624                 (u_int64_t *)&sp->ErrorFrames);
  625     rc |= sa_sys_read_u64(dir, "dumped_frames",
  626                 (u_int64_t *)&sp->DumpedFrames);
  627     rc |= sa_sys_read_u64(dir, "link_failure_count",
  628                 (u_int64_t *)&sp->LinkFailureCount);
  629     rc |= sa_sys_read_u64(dir, "loss_of_sync_count",
  630                 (u_int64_t *)&sp->LossOfSyncCount);
  631     rc |= sa_sys_read_u64(dir, "loss_of_signal_count",
  632                 (u_int64_t *)&sp->LossOfSignalCount);
  633     rc |= sa_sys_read_u64(dir, "prim_seq_protocol_err_count",
  634                 (u_int64_t *)&sp->PrimitiveSeqProtocolErrCount);
  635     rc |= sa_sys_read_u64(dir, "invalid_tx_word_count",
  636                 (u_int64_t *)&sp->InvalidTxWordCount);
  637     rc |= sa_sys_read_u64(dir, "invalid_crc_count",
  638                 (u_int64_t *)&sp->InvalidCRCCount);
  639 
  640     return rc;
  641 }
  642 
  643 /* Port FC-4 Statistics */
  644 HBA_STATUS
  645 sysfs_get_port_fc4stats(char *dir, HBA_FC4STATISTICS *fc4sp)
  646 {
  647     int rc;
  648 
  649     rc  = sa_sys_read_u64(dir, "fcp_input_requests",
  650                 (u_int64_t *)&fc4sp->InputRequests);
  651     rc |= sa_sys_read_u64(dir, "fcp_output_requests",
  652                 (u_int64_t *)&fc4sp->OutputRequests);
  653     rc |= sa_sys_read_u64(dir, "fcp_control_requests",
  654                 (u_int64_t *)&fc4sp->ControlRequests);
  655     rc |= sa_sys_read_u64(dir, "fcp_input_megabytes",
  656                 (u_int64_t *)&fc4sp->InputMegabytes);
  657     rc |= sa_sys_read_u64(dir, "fcp_output_megabytes",
  658                 (u_int64_t *)&fc4sp->OutputMegabytes);
  659 
  660     return rc;
  661 }
  662 /*
  663  * Open device and read adapter info if available.
  664  */
  665 void
  666 adapter_init(void)
  667 {
  668     sa_dir_read(SYSFS_HOST_DIR, sysfs_scan, NULL);
  669 }
  670 
  671 void
  672 adapter_shutdown(void)
  673 {
  674 }
  675 
  676 HBA_STATUS
  677 get_port_statistics(HBA_HANDLE handle, HBA_UINT32 port, HBA_PORTSTATISTICS *sp)
  678 {
  679     struct port_info *pp;
  680     char dir[80];
  681     int rc;
  682 
  683     memset(sp, 0xff, sizeof(*sp)); /* unsupported statistics give -1 */
  684     pp = adapter_get_port(handle, port);
  685     if (pp == NULL) {
  686         fprintf(stderr, "%s: lookup failed. handle 0x%x port 0x%x\n",
  687             __func__, handle, port);
  688         return HBA_STATUS_ERROR;
  689     }
  690 
  691     snprintf(dir, sizeof(dir), "%s/statistics", pp->host_dir);
  692     rc = sysfs_get_port_stats(dir, sp);
  693     if (rc != 0) {
  694         fprintf(stderr, "%s: sysfs_get_port_stats() failed,"
  695             " hba index=%d port index=%d, -rc=0x%x\n",
  696             __func__, pp->ap_adapt->ad_kern_index,
  697             pp->ap_index, -rc);
  698         return HBA_STATUS_ERROR;
  699     }
  700     return HBA_STATUS_OK;
  701 }
  702 
  703 /*
  704  * Get FC4 statistics.
  705  */
  706 HBA_STATUS
  707 get_port_fc4_statistics(HBA_HANDLE handle, HBA_WWN wwn,
  708                HBA_UINT8 fc4_type, HBA_FC4STATISTICS *sp)
  709 {
  710     struct port_info *pp;
  711     char dir[80];
  712     int count;
  713     int rc;
  714 
  715     memset(sp, 0xff, sizeof(*sp)); /* unsupported statistics give -1 */
  716 
  717     pp = adapter_get_port_by_wwn(handle, wwn, &count);
  718     if (count > 1)
  719         return HBA_STATUS_ERROR_AMBIGUOUS_WWN;
  720     else if (pp == NULL)
  721         return HBA_STATUS_ERROR_ILLEGAL_WWN;
  722 
  723     snprintf(dir, sizeof(dir), "%s/statistics", pp->host_dir);
  724     rc = sysfs_get_port_fc4stats(dir, sp);
  725     if (rc != 0) {
  726         fprintf(stderr, "%s: sysfs_get_port_fc4stats() failed,"
  727             " hba index=%d port index=%d, -rc=0x%x\n",
  728             __func__, pp->ap_adapt->ad_kern_index,
  729             pp->ap_index, -rc);
  730         return HBA_STATUS_ERROR;
  731     }
  732     return HBA_STATUS_OK;
  733 }
  734