Emulex Logo
OneCoreā„¢ Storage SDK Release 11.2
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
elxu_linux.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011-2015, Emulex
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 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  */
32 
33 #define _GNU_SOURCE
34 #include <stdio.h>
35 #include <stdint.h>
36 #include <stdlib.h>
37 #include <stdarg.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <assert.h>
41 #include <string.h>
42 #include <sys/types.h>
43 #include <sys/ioctl.h>
44 #include <fcntl.h>
45 #include <dirent.h>
46 #include <unistd.h>
47 #include <fts.h>
48 #include <errno.h>
49 
50 #include <ocs_ioctl.h>
51 
52 #include <elxu_device.h>
53 #include <elxu_sli4.h>
54 #include <elxu_mbox.h>
55 #include "elxu_common.h"
56 #include "elx_pt_ioctl.h"
57 
58 #include <ocsu_io.h>
59 
60 #define MAXDEVS 1024
61 #define ELX_PT_SERIAL_NUM_SIZE 32
62 
63 /*
64  * This file contains functions specific to Linux.
65  * Any non-static functions here should:
66  * - be declared in elxu_common.h
67  * - have an equivalent in elxu_bsd.c, even if it's a stub
68  */
69 
70 static char* format_ip_address(uint8_t *address, uint8_t address_type);
71 static void pt_device_init(elxu_device_t *device);
72 
73 static int os_create_device_files(char *driver_path)
74 {
75  int major;
76  int count;
77  int total;
78  int rc;
79  FILE *proc_file;
80  int idx;
81  char path[FILENAME_MAX];
82  FTS *ftsp;
83  FTSENT *ftsent;
84  FTSENT *chp;
85  char *dirs[2];
86  char *drv;
87  char *p;
88 
89  if (driver_path)
90  dirs[0] = driver_path;
91  else
92  dirs[0] = "/proc";
93 
94  dirs[1] = NULL;
95 
96  ftsp = fts_open(dirs, FTS_COMFOLLOW | FTS_NOCHDIR, NULL);
97  if (ftsp == NULL) {
98  // can't initialize fts
99  return -1;
100  }
101  chp = fts_children(ftsp, 0);
102  if (chp == NULL) {
103  // child initialization failed
104  return -1;
105  }
106 
107  /*
108  * Bug 181400 - Remove any device special files before creating new ones.
109  * Since drivers can be unloaded, then we must walk the /dev/ocs_XX and remove
110  * all that exist and then recreate them.
111  */
112  total = 0;
113  do {
114  snprintf(path, sizeof(path), "/dev/%s_%d", "ocs", total);
115  rc = remove(path);
116  if (rc != 0 && errno != ENOENT) {
117  perror("Error removing /dev/ocs*\n");
118  }
119  total++;
120  } while (rc == 0);
121 
122  total = 0;
123  while((ftsent = fts_read(ftsp)) != NULL) {
124  if (ftsent->fts_info != FTS_F) {
125  continue;
126  }
127  if (strncmp(ftsent->fts_path, "/proc/ocs", strlen("/proc/ocs"))) {
128  continue;
129  }
130 
131  /*
132  * Don't process /proc/ocsu. That's for the user space shim, and
133  * we don't want to access those directly.
134  */
135  if (strncmp(ftsent->fts_path, "/proc/ocsu", strlen("/proc/ocsu")) == 0) {
136  continue;
137  }
138 
139  proc_file = fopen(ftsent->fts_path, "r");
140 
141  if (proc_file == NULL) {
142  // Can't open /proc/ocs to get driver info
143  return -1;
144  }
145 
146  rc = fscanf(proc_file, "%d,%d", &major, &count);
147  fclose(proc_file);
148 
149  if (rc != 2) {
150  // Didn't get major and count from /proc/ocs
151  return -1;
152  }
153  drv = strdup(ftsent->fts_path + strlen("/proc/"));
154  if (drv == NULL) {
155  // Allocation failed
156  return -1;
157  }
158 
159  if ((p = strchr(drv, '_'))) {
160  *p = 0;
161  }
162 
163  for (idx = 0; idx < count; idx ++) {
164  snprintf(path, sizeof(path), "/dev/%s_%d", drv, total);
165  // Try to make the device file. If it fails, ignore the error and continue.
166  rc = mknod(path, S_IFCHR | 0644, makedev(major, idx));
167  if (rc) {
168  printf("Failed creating %s\n", path);
169  perror("Error =\n");
170  }
171  total++;
172  }
173  free(drv);
174  }
175  return 0;
176 }
177 
178 /**
179  * @ingroup dev_mgmt
180  * @brief Build a list of devices
181  *
182  * @par Description
183  * This function locates all devices on the system that the utility can manage
184  * and builds the device list. It is only concerned with devices accessed directly
185  * through the PCI bus, not with user space devices accessed through sockets.
186  *
187  * For each Emulex device found on the bus it will determine the driver controlling
188  * the device, and will only add the device to the list if the driver is either one
189  * of the ocs_* drivers or is elx_pt.
190  *
191  * @return Returns a pointer to the first device in the list. May be NULL if no
192  * devices are found.
193  */
195 {
196  DIR *pci_dir;
197  struct dirent *entry;
198  elxu_device_t *new_device;
199  elxu_device_t *list;
200  char config_file_name[1024];
201  int config_file;
202  char driver_link_name[1024];
203  char driver_path[1024];
204  char *driver_name;
205  uint16_t vendor_id;
206  uint16_t device_id;
207  int n;
208  int next_index;
209  int ocs_index;
210 
211  pci_dir = opendir("/sys/bus/pci/devices");
212  if (pci_dir == NULL) {
213  return NULL;
214  }
215 
216  /* Create device files for OCS drivers, if needed */
218 
219  list = NULL;
220  next_index=0;
221 
222  /*
223  * Find OCS devices first, so that instance numbers agree with
224  * /dev/ocs_* filenames (for backwards compatibility).
225  */
226  ocs_index = 0;
227  while (1) {
228  char device_file_name[256];
229  int fd;
230  int rc;
232 
233  sprintf(device_file_name, "/dev/ocs_%d", ocs_index);
234  fd = open(device_file_name, O_RDONLY);
235  if (fd < 0) {
236  break;
237  }
238 
239  rc = ioctl(fd, OCS_IOCTL_CMD_DRIVER_INFO, &info);
240  if (rc == 0) {
241  new_device = malloc(sizeof(elxu_device_t));
242  /* Should check for malloc failure here */
243  bzero(new_device, sizeof(*new_device));
244 
245  /* Add the device to the global list */
246  new_device->next = list;
247  list = new_device;
248 
249  new_device->driver = DEVICE_DRIVER_OCS;
250  strcpy(new_device->device_file_name, device_file_name);
251  new_device->vendor = info.pci_vendor;
252  new_device->device = info.pci_device;
253  strcpy(new_device->bus_addr, info.businfo);
254  new_device->type = DEVICE_TYPE_UNKNOWN;
255  set_protocol(new_device);
256  new_device->deviceIndex = next_index++;
257  }
258 
259  ++ocs_index;
260  close(fd);
261  }
262 
263  /*
264  * Now scan the PCI devices for any other devices we want to manage.
265  */
266  while ((entry = readdir(pci_dir))) {
267  snprintf(config_file_name, sizeof(config_file_name),
268  "/sys/bus/pci/devices/%s/config", entry->d_name);
269  config_file = open(config_file_name, O_RDWR);
270  if (config_file < 0) {
271  continue;
272  }
273  if ((read(config_file, &vendor_id, sizeof(vendor_id)) < sizeof(vendor_id)) ||
274  (read(config_file, &device_id, sizeof(device_id)) < sizeof(device_id))) {
275  fprintf(stderr , "couldn't read vendor ID or device ID");
276  }
277  if (vendor_id == PCI_VENDOR_ID_EMULEX) {
278  new_device = malloc(sizeof(elxu_device_t));
279  /* Should check for malloc failure here */
280  bzero(new_device, sizeof(*new_device));
281 
282  /* Add the device to the global list */
283  new_device->next = list;
284  list = new_device;
285 
286  /* Fill in information which applies to all drivers */
287  new_device->vendor = vendor_id;
288  new_device->device = device_id;
289  strcpy(new_device->bus_addr, entry->d_name);
290  set_protocol(new_device);
291  new_device->deviceIndex = next_index++;
292 
293  /* Figure out the driver */
294  snprintf(driver_link_name, sizeof(driver_link_name),
295  "/sys/bus/pci/devices/%s/driver", entry->d_name);
296  n = readlink(driver_link_name, driver_path, sizeof(driver_path) - 1);
297 
298  /*
299  * Take driver specific actions, including possibly removing the
300  * device from the list if it's not a driver we handle.
301  */
302  if (n < 0) {
303  /*
304  * If we support CSII (mailbox access with no driver) in the
305  * future then we'll keep this device and mark it with
306  * DEVICE_DRIVER_NONE. For now we'll just take it off the list.
307  */
308  list = new_device->next;
309  --next_index;
310  free(new_device);
311  } else {
312  driver_path[n] = '\0';
313  driver_name = strrchr(driver_path, '/') + 1;
314  if (strncmp(driver_name, "ocs_", 4) == 0) {
315  /* OCS drivers were handled already */
316  list = new_device->next;
317  --next_index;
318  free(new_device);
319  } else if (strcmp(driver_name, "elx_pt") == 0) {
320  pt_device_init(new_device);
321  } else if (strcmp(driver_name, "be2net") == 0) {
322  /*
323  * If we support be2net passthrough in the future
324  * we'll keep this device and mark it with DEVICE_DRIVER_BE2NET.
325  * For now we'll just take it off the list.
326  */
327  list = new_device->next;
328  --next_index;
329  free(new_device);
330  } else {
331  /*
332  * If it has a driver we don't recognize (lpfc?) we just
333  * ignore it.
334  */
335  list = new_device->next;
336  --next_index;
337  free(new_device);
338  }
339  }
340  }
341  }
342  closedir(pci_dir);
343  return list;
344 }
345 
347 {
348  int devidx = 0;
349  elxu_device_t *device_p;
350  elxu_device_t *list;
351  void *desc;
352 
353  list = NULL;
354 
355  while(1) {
357  int rc;
358 
359  desc = ocsu_open(hostname, devidx);
360  if (desc == NULL) {
361  break;
362  }
363 
364  device_p = malloc(sizeof(elxu_device_t));
365  /* Should check for malloc failure here */
366  memset(device_p, '\0', sizeof(*device_p));
367 
368  snprintf(device_p->device_file_name, sizeof(device_p->device_file_name),
369  "%s[%d]", hostname, devidx);
370  device_p->desc = desc;
371  device_p->driver = DEVICE_DRIVER_OCS;
372  rc = ocsu_ioctl(desc, OCS_IOCTL_CMD_DRIVER_INFO, &info);
373  if (rc == 0) {
374  device_p->vendor = info.pci_vendor;
375  device_p->device = info.pci_device;
376  strncpy(device_p->bus_addr, info.businfo, sizeof(device_p->bus_addr));
377  }
378 
379  device_p->type = DEVICE_TYPE_UNKNOWN;
380  set_protocol(device_p);
381  fill_device_details(device_p);
382 
383  device_p->next = list;
384  list = device_p;
385  device_p->deviceIndex = devidx;
386  ++devidx;
387 
388  ocsu_close(device_p->desc);
389  }
390 
391  return list;
392 }
393 
394 static void pt_device_init(elxu_device_t *device)
395 {
396  int major;
397  int minor;
398  char driver_name[80];
399  char line[80];
400  FILE *proc_file;
401  char dev_file_name[80];
402  int i;
403  int fd;
404  int rc;
405  elx_pt_ioctl_info_t info;
406  char *serial_num = NULL;
407 
408  /* Get major number from /proc/devices */
409  proc_file = fopen("/proc/devices", "r");
410  if (proc_file == NULL) {
411  return;
412  }
413 
414  major = -1;
415  while (fgets(line, sizeof(line), proc_file)) {
416  if (strstr(line, "elx_pt")) {
417  sscanf(line, "%d %s", &i, driver_name);
418  if (strcmp(driver_name, "elx_pt") == 0) {
419  major = i;
420  break;
421  }
422  }
423  }
424  fclose(proc_file);
425  if (major == -1) {
426  return;
427  }
428 
429  /* Try each minor number */
430  for (minor=0; minor<MAXDEVS; minor++) {
431  /* Open the device file, creating it if necessary */
432  snprintf(dev_file_name, sizeof(dev_file_name), "/dev/elx_pt%d", minor);
433  fd = open(dev_file_name, O_RDWR);
434  if (fd < 0) {
435  if (errno == EBUSY) {
436  perror("Device");
437  device->fd = -1;
438  return;
439  }
440  rc = mknod(dev_file_name, S_IFCHR, makedev(major, minor));
441  if (rc != 0) {
442  return;
443  }
444  fd = open(dev_file_name, O_RDWR);
445  if (fd < 0) {
446  return;
447  }
448  }
449 
450  device->fd = fd;
451 
452  /* Get driver info from the device file */
453  bzero(&info, sizeof(info));
454  rc = ioctl(fd, IOCTL_CMD_ELX_PT_GET_INFO, &info);
455  if (rc != 0) {
456  close(fd);
457  device->fd = -1;
458  continue;
459  }
460 
461  /* See if this device is the correct one */
462  if (strcmp(info.bus_addr, device->bus_addr) == 0) {
464  elx_pt_ioctl_mbox_t mbox;
465 
466  strcpy(device->device_file_name, dev_file_name);
467  device->vendor = info.vendor;
468  device->device = info.device;
469  device->asic_id = info.asic_id;
470  device->sli_intf = info.sli_intf;
471  device->driver = DEVICE_DRIVER_PT;
472 
473  bzero(&attr, sizeof(attr));
476  attr.hdr.req.request_length = sizeof(attr);
477 
478  mbox.words = (uint32_t *)&attr;
479  mbox.num_words = (sizeof(attr) + 3) / 4;
480 
481  rc = ioctl(fd, IOCTL_CMD_ELX_PT_MBOX, &mbox);
482  if (rc == 0) {
483  device->modeldesc = strdup((char *)attr.controller_description);
484  strcpy(device->fwrev, (char *)attr.firmware_version_string);
485  if (is_iscsi(device) || is_nic(device)) {
486  device->serialnum = strdup((char *)attr.controller_serial_number);
487  }
488  if (is_fc(device)) {
489  serial_num = zmalloc(ELX_PT_SERIAL_NUM_SIZE);
490  if (serial_num) {
491  mbox_get_serialnum_pt(device, serial_num, ELX_PT_SERIAL_NUM_SIZE);
492  device->serialnum = strdup((char *)serial_num);
493  } else {
494  device->serialnum = NULL;
495  }
496  }
497  }
498 
499  if (is_iscsi(device) || is_nic(device)) {
500  mbox_get_mac_pt(device, device->mac_addr);
501  }
502  if (is_fc(device)) {
503  mbox_get_wwn_pt(fd, device->wwnn, device->wwpn);
504  }
505 
506  device->fd = -1;
507  if (serial_num)
508  free(serial_num);
509  close(fd);
510  return;
511  }
512 
513  device->fd = -1;
514  close(fd);
515  if (serial_num)
516  free(serial_num);
517  }
518 }
519 
521 {
522  elxu_device_t *device = NULL;
523  char path[FILENAME_MAX];
524 
525  device = elxu_device_by_index(devname->devidx);
526 
527  if (device == NULL) {
528  /* Device index not found in list */
529  return NULL;
530  }
531 
532  /* if devname->hostname is non-null, then open device special file, otherwise
533  * open a socket.
534  */
535 
536  if (devname->hostname == NULL) {
537  /* Open device */
538  device->fd = open(device->device_file_name, O_RDWR);
539 
540  if (device->fd < 0) {
541  return NULL;
542  }
543  } else {
544  device->desc = ocsu_open(devname->hostname, devname->devidx);
545  if (device->desc == NULL) {
546  return NULL;
547  }
548  snprintf(path, sizeof(path), "%s[%d]", devname->hostname, devname->devidx);
549  strncpy(device->device_file_name, path , sizeof(device->device_file_name) - 1);
550  }
551 
552  return device;
553 }
554 
555 int os_ioctl_device(elxu_device_t *device, int req, void *arg)
556 {
557  int rc;
558 
559  if (device->desc != NULL) {
560  rc = ocsu_ioctl(device->desc, req, arg);
561  } else {
562  rc = ioctl(device->fd, req, arg);
563  }
564  return rc;
565 }
566 
568 {
569  if (device->desc != NULL) {
570  ocsu_close(device->desc);
571  } else {
572  close(device->fd);
573  }
574 }
575 
577 {
578  return remove(device->device_file_name);
579 }
580 
582 {
583 #define MAX_CONNECTIONS 256
584  ocs_ioctl_connection_info_t *info = calloc(MAX_CONNECTIONS, sizeof(*info));
586  int rval;
587  int i;
588 
589  req.connections = info;
591 
592  rval = elxu_ioctl_device(device, OCS_IOCTL_CMD_CONNECTION_INFO, &req);
593 
594  if (rval < 0) {
595  perror("ioctl");
596  return;
597  }
598 
599  if (req.num_connections == 0) {
600  printf("No connections found\n");
601  return;
602  }
603 
604  for (i=0; i<req.num_connections; i++) {
605  printf("[%d]\n", i);
606  printf(" Connection ID: 0x%x\n", info[i].connection_id);
607  printf(" Connection Handle: 0x%x\n", info[i].connection_handle);
608  printf(" Source Address: %s\n",
609  format_ip_address(info[i].source_ip, info[i].source_ip_type));
610  printf(" Source Port: %d\n", info[i].source_port);
611  printf(" Dest Address: %s\n",
612  format_ip_address(info[i].dest_ip, info[i].dest_ip_type));
613  printf(" Dest Port: %d\n", info[i].dest_port);
614  }
615 }
616 
617 static char* format_ip_address(uint8_t *address, uint8_t address_type)
618 {
619  static char ret[40];
620 
621  // TODO: These IP type numbers should be #defines somewhere
622  if (address_type < 3) {
623  /* Print the IP address in IPV4 format */
624  sprintf(ret, "%d.%d.%d.%d",
625  address[0],
626  address[1],
627  address[2],
628  address[3]);
629  } else {
630  /* Print the IP address in IPV6 format */
631  sprintf(ret,"%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
632  address[0], address[1],
633  address[2], address[3],
634  address[4], address[5],
635  address[6], address[7],
636  address[8], address[9],
637  address[10], address[11],
638  address[12], address[13],
639  address[14], address[15]);
640  }
641 
642  return ret;
643 }
char * modeldesc
Definition: elxu_device.h:94
uint8_t wwpn[8]
Definition: elxu_device.h:99
sli4_ioctl_request_header_t req
Definition: elxu_sli4.h:943
char fwrev[32]
Definition: elxu_device.h:92
int is_fc(elxu_device_t *device_p)
Return true IFF the HBA is a FC HBA.
Definition: elxu_device.c:1185
static char * format_ip_address(uint8_t *address, uint8_t address_type)
Definition: elxu_linux.c:617
#define OCS_IOCTL_CMD_CONNECTION_INFO
Definition: ocs_ioctl.h:487
elxu_device_t * os_build_device_list(char *path)
Definition: elxu_bsd.c:71
#define PCI_VENDOR_ID_EMULEX
Definition: elxu_device.h:39
connection info ioctl structure
Definition: ocs_ioctl.h:247
uint16_t device
Definition: elxu_device.h:82
uint32_t sli_intf
Definition: elxu_device.h:86
void os_close_device(elxu_device_t *device)
Close a device file.
Definition: elxu_bsd.c:187
int os_ioctl_device(elxu_device_t *device, int req, void *arg)
Send an ioctl to an open device.
Definition: elxu_bsd.c:211
uint16_t vendor
Definition: elxu_device.h:81
struct elxu_device_struct * next
Definition: elxu_device.h:79
#define EBUSY
Definition: elxu_mgmt.c:57
elxu_device_type_e type
Definition: elxu_device.h:88
#define OCS_IOCTL_CMD_DRIVER_INFO
Definition: ecdtest.c:109
device name specifier This structure is used to describe the type and name of the device ioctl connec...
Definition: elxu_device.h:113
void * zmalloc(uint32_t len)
Allocates and zeroes memory to be used.
Definition: elxu_common.c:63
int elxu_ioctl_device(elxu_device_t *device, int req, void *arg)
Send an ioctl to a device.
Definition: elxu_device.c:322
#define ELX_PT_SERIAL_NUM_SIZE
Definition: elxu_linux.c:61
uint32_t asic_id
Definition: elxu_device.h:87
static void pt_device_init(elxu_device_t *device)
Definition: elxu_linux.c:394
static int os_create_device_files(char *driver_path)
Definition: elxu_linux.c:73
void fill_device_details(elxu_device_t *device)
Definition: elxu_device.c:225
void mbox_get_wwn_pt(int fd, uint8_t *wwnn, uint8_t *wwpn)
Definition: elxu_mbox.c:1029
#define OPCODE_COMMON_GET_CNTL_ATTRIBUTES
Definition: elxu_sli4.h:82
#define MBOX_SUBSYSTEM_COMMON
Definition: elxu_sli4.h:76
uint32_t deviceIndex
Definition: elxu_device.h:85
char * serialnum
Definition: elxu_device.h:95
void elxu_get_connection_info(elxu_device_t *device)
Print iSCSI connection info for the given device.
Definition: elxu_bsd.c:230
elxu_device_t * elxu_device_by_index(int index)
Return a pointer to a device given an index.
Definition: elxu_device.c:730
int is_nic(elxu_device_t *device_p)
Return true IFF the HBA is a NIC HBA.
Definition: elxu_device.c:1168
ocs_ioctl_connection_info_t * connections
Definition: ocs_ioctl.h:261
#define MAX_CONNECTIONS
int is_iscsi(elxu_device_t *device_p)
Return true IFF the HBA is an iSCSI HBA.
Definition: elxu_device.c:1151
DRIVER_INFO ioctl structure.
Definition: ecdtest.c:73
void set_protocol(elxu_device_t *device)
Definition: elxu_device.c:1129
void mbox_get_mac_pt(elxu_device_t *device, uint8_t *mac_addr)
Definition: elxu_mbox.c:950
elxu_device_t * os_open_device(elxu_device_name_t *devname)
Open a device file.
Definition: elxu_bsd.c:148
#define MAXDEVS
Definition: elxu_linux.c:60
elxu_device_t * os_build_device_list_uspace(char *hostname)
Definition: elxu_bsd.c:123
elxu_device_driver_e driver
Definition: elxu_device.h:90
char device_file_name[1024]
Definition: elxu_device.h:102
char bus_addr[256]
Definition: elxu_device.h:80
uint8_t mac_addr[6]
Definition: elxu_device.h:100
uint8_t wwnn[8]
Definition: elxu_device.h:98
int mbox_get_serialnum_pt(elxu_device_t *device, char *serial_num, int serial_num_size)
Definition: elxu_mbox.c:1053
int os_remove_device(elxu_device_t *device)
Definition: elxu_bsd.c:193