diff --git a/grub-core/disk/ieee1275/ofdisk.c b/grub-core/disk/ieee1275/ofdisk.c index 55346849d3..5eaffc9c69 100644 --- a/grub-core/disk/ieee1275/ofdisk.c +++ b/grub-core/disk/ieee1275/ofdisk.c @@ -24,6 +24,8 @@ #include #include #include +#define EXTEND_PATH_64 64 +#define EXTEND_PATH_512 512 static char *last_devpath; static grub_ieee1275_ihandle_t last_ihandle; @@ -206,10 +208,319 @@ dev_iterate_real (const char *name, const char *path) return; } +static void +dev_iterate_fcp_disks(const struct grub_ieee1275_devalias *alias) +{ + /* + * If we are dealing with fcp devices, we need + * to find the WWPNs and LUNs to iterate them + */ + grub_ieee1275_ihandle_t ihandle; + grub_uint64_t *ptr_targets, *ptr_luns, k, l; + unsigned int i, j, pos; + char *buf, *bufptr; + struct set_fcp_targets_args + { + struct grub_ieee1275_common_hdr common; + grub_ieee1275_cell_t method; + grub_ieee1275_cell_t ihandle; + grub_ieee1275_cell_t catch_result; + grub_ieee1275_cell_t nentries; + grub_ieee1275_cell_t table; + } args_targets; + + struct set_fcp_luns_args + { + struct grub_ieee1275_common_hdr common; + grub_ieee1275_cell_t method; + grub_ieee1275_cell_t ihandle; + grub_ieee1275_cell_t wwpn_h; + grub_ieee1275_cell_t wwpn_l; + grub_ieee1275_cell_t catch_result; + grub_ieee1275_cell_t nentries; + grub_ieee1275_cell_t table; + } args_luns; + + struct args_ret + { + grub_uint64_t addr; + grub_uint64_t len; + }; + struct args_ret *targets_table; + struct args_ret *luns_table; + + if (grub_ieee1275_open (alias->path, &ihandle)) + { + grub_dprintf("disk", "failed to open the disk while iterating FCP disk path=%s\n", alias->path); + return; + } + + /* Setup the fcp-targets method to call via pfw*/ + INIT_IEEE1275_COMMON (&args_targets.common, "call-method", 2, 3); + args_targets.method = (grub_ieee1275_cell_t) "fcp-targets"; + args_targets.ihandle = ihandle; + + /* Setup the fcp-luns method to call via pfw */ + INIT_IEEE1275_COMMON (&args_luns.common, "call-method", 4, 3); + args_luns.method = (grub_ieee1275_cell_t) "fcp-luns"; + args_luns.ihandle = ihandle; + if (IEEE1275_CALL_ENTRY_FN (&args_targets) == -1) + { + grub_dprintf("disk", "failed to get the targets while iterating FCP disk path=%s\n", alias->path); + grub_ieee1275_close(ihandle); + return; + } + /* Allocate memory for building the path */ + buf = grub_malloc (grub_strlen (alias->path) + EXTEND_PATH_64); + if (!buf) + { + grub_ieee1275_close(ihandle); + return; + } + bufptr = grub_stpcpy (buf, alias->path); + + /* + * Iterate over entries returned by pfw. Each entry contains a + * pointer to wwpn table and his length. + */ + targets_table = (struct args_ret *)(args_targets.table); + for (i=0; i< args_targets.nentries; i++) + { + ptr_targets = (grub_uint64_t*) targets_table[i].addr; + /* Iterate over all wwpns in given table */ + for (k=0; k> 32); + pos = grub_snprintf (bufptr, 32, "/disk@%" PRIxGRUB_UINT64_T, + *ptr_targets++); + /* Get the luns for given wwpn target */ + if (IEEE1275_CALL_ENTRY_FN (&args_luns) == -1) + { + grub_dprintf("disk", "failed to get the LUNS while iterating FCP disk path=%s\n", buf); + grub_ieee1275_close (ihandle); + grub_free (buf); + return; + } + luns_table = (struct args_ret *)(args_luns.table); + + /* Iterate over all LUNs */ + for (j=0; jpath) + EXTEND_PATH_512); + if (!buf || !nvme_controllers_table) + { + grub_free(nvme_controllers_table); + grub_free(buf); + + return; + } + + /* Copy the alias->path to buf so we can work with */ + bufptr = grub_stpcpy (buf, alias->path); + grub_snprintf (bufptr, 32, "/nvme-of"); + + /* + * Open the nvme-of layer + * Ex. /pci@bus/fibre-channel@@dev,func/nvme-of + */ + if (grub_ieee1275_open (buf, &ihandle)) + { + grub_dprintf("disk", "failed to open the disk while iterating FCP disk path=%s\n", buf); + grub_free(nvme_controllers_table); + grub_free(buf); + return; + } + + /* + * Call to nvme-discovery-controllers method from the nvme-of layer + * to get a list of the NVMe discovery controllers per the binding + */ + INIT_IEEE1275_COMMON (&nvme_discovery_controllers_args.common, "call-method", 2, 2); + nvme_discovery_controllers_args.method = (grub_ieee1275_cell_t) "nvme-discovery-controllers"; + nvme_discovery_controllers_args.ihandle = ihandle; + if (IEEE1275_CALL_ENTRY_FN (&nvme_discovery_controllers_args) == -1) + { + grub_dprintf("disk", "failed to get the targets while iterating FCP disk path=%s\n", buf); + grub_free(nvme_controllers_table); + grub_free(buf); + grub_ieee1275_close(ihandle); + return; + } + + /* After closing the device, the info is lost. So lets copy each buffer in the buffers table */ + discovery_controllers_table.len = (grub_uint32_t) nvme_discovery_controllers_args.nentries; + + for (i = 0; i < discovery_controllers_table.len; i++) + { + discovery_controllers_table.table[i] = ((grub_uint64_t*)nvme_discovery_controllers_args.table)[i]; + } + + grub_ieee1275_close(ihandle); + grub_dprintf("ofdisk","NVMeoF: Found %d discovery controllers\n", discovery_controllers_table.len); + + /* For each nvme discovery controller */ + for (current_buffer_index = 0; current_buffer_index < (int) discovery_controllers_table.len; current_buffer_index++) + { + grub_snprintf (bufptr, 64, "/nvme-of/controller@%" PRIxGRUB_UINT64_T ",ffff", + discovery_controllers_table.table[current_buffer_index]); + grub_dprintf("ofdisk", "nvmeof controller=%s\n", buf); + if (grub_ieee1275_open (buf, &ihandle)) + { + grub_dprintf("ofdisk", "failed to open the disk while getting nvme-controllers path=%s\n", buf); + continue; + } + INIT_IEEE1275_COMMON (&nvme_controllers_args.common, "call-method", 2, 2); + nvme_controllers_args.method = (grub_ieee1275_cell_t) "nvme-controllers"; + nvme_controllers_args.ihandle = ihandle; + nvme_controllers_args.catch_result = 0; + + if (IEEE1275_CALL_ENTRY_FN (&nvme_controllers_args) == -1) + { + grub_dprintf("ofdisk", "failed to get the nvme-controllers while iterating FCP disk path\n"); + grub_ieee1275_close(ihandle); + continue; + } + + /* Copy the buffer list to nvme_controllers_table */ + nvme_controllers_table_entries = ((grub_uint32_t) nvme_controllers_args.nentries); + nvme_controllers_table_buf = (struct nvme_controllers_table_entry*) nvme_controllers_args.table; + for (i = 0; i < nvme_controllers_table_entries; i++) + { + nvme_controllers_table[i].id = (grub_uint16_t) nvme_controllers_table_buf[i].id; + grub_strcpy(nvme_controllers_table[i].wwpn, nvme_controllers_table_buf[i].wwpn); + grub_strcpy(nvme_controllers_table[i].nqn, nvme_controllers_table_buf[i].nqn); + } + grub_ieee1275_close(ihandle); + grub_dprintf("ofdisk", "NVMeoF: found %d nvme controllers\n", (int) nvme_controllers_args.nentries); + + /* For each nvme controller */ + for (nvme_controller_index = 0; nvme_controller_index < (int) nvme_controllers_args.nentries; nvme_controller_index++) + { + /* + * Open the nvme controller + * /pci@bus/fibre-channel@dev,func/nvme-of/controller@transport-addr,ctlr-id:nqn=tgt-subsystem-nqn + */ + bufptr_pos2 = grub_snprintf (bufptr, 512, "/nvme-of/controller@%s,ffff:nqn=%s", + nvme_controllers_table[nvme_controller_index].wwpn, nvme_controllers_table[nvme_controller_index].nqn); + grub_dprintf("ofdisk", "NVMeoF: nvmeof controller=%s\n", buf); + if(grub_ieee1275_open (buf, &ihandle)) + { + grub_dprintf("ofdisk", "failed to open the path=%s\n", buf); + continue; + } + INIT_IEEE1275_COMMON (&nvme_namespaces_args.common, "call-method", 2, 2); + nvme_namespaces_args.method = (grub_ieee1275_cell_t) "get-namespace-list"; + nvme_namespaces_args.ihandle = ihandle; + nvme_namespaces_args.catch_result = 0; + + if (IEEE1275_CALL_ENTRY_FN (&nvme_namespaces_args) == -1) + { + grub_dprintf("ofdisk", "failed to get the nvme-namespace-list while iterating FCP disk path\n"); + grub_ieee1275_close(ihandle); + continue; + } + grub_uint32_t *namespaces = (grub_uint32_t*) nvme_namespaces_args.table; + grub_dprintf("ofdisk", "NVMeoF: found %d namespaces\n", (int)nvme_namespaces_args.nentries); + grub_ieee1275_close(ihandle); + namespace_index = 0; + for (namespace_index=0; namespace_index < nvme_namespaces_args.nentries; namespace_index++) + { + grub_snprintf (bufptr+bufptr_pos2, 512, "/namespace@%"PRIxGRUB_UINT32_T,namespaces[namespace_index]); + grub_dprintf("ofdisk", "NVMeoF: namespace=%s\n", buf); + dev_iterate_real(buf, buf); + } + dev_iterate_real(buf, buf); + } + } + grub_free(buf); + grub_free(nvme_controllers_table); + return; +} + static void dev_iterate (const struct grub_ieee1275_devalias *alias) { - if (grub_strcmp (alias->type, "vscsi") == 0) + if (grub_strcmp (alias->type, "fcp") == 0) + { + /* Iterate disks */ + dev_iterate_fcp_disks(alias); + /* Iterate NVMeoF */ + dev_iterate_fcp_nvmeof(alias); + } + else if (grub_strcmp (alias->type, "vscsi") == 0) { static grub_ieee1275_ihandle_t ihandle; struct set_color_args diff --git a/grub-core/kern/ieee1275/openfw.c b/grub-core/kern/ieee1275/openfw.c index 0278054c61..b97104cb11 100644 --- a/grub-core/kern/ieee1275/openfw.c +++ b/grub-core/kern/ieee1275/openfw.c @@ -324,7 +324,7 @@ grub_claimmap (grub_addr_t addr, grub_size_t size) static char * grub_ieee1275_get_devargs (const char *path) { - char *colon = grub_strchr (path, ':'); + char *colon = grub_strrchr (path, ':'); if (! colon) return 0; @@ -339,6 +339,21 @@ grub_ieee1275_get_devname (const char *path) char *colon = grub_strchr (path, ':'); int pathlen = grub_strlen (path); struct grub_ieee1275_devalias curalias; + + /* Check some special cases */ + if(grub_strstr(path, "nvme-of")) + { + char *namespace_split = grub_strstr(path,"/namespace@"); + if(namespace_split) + { + colon = grub_strchr (namespace_split, ':'); + } + else + { + colon = NULL; + } + } + if (colon) pathlen = (int)(colon - path); @@ -579,7 +594,7 @@ grub_ieee1275_get_boot_dev (void) return NULL; } - bootpath = (char *) grub_malloc ((grub_size_t) bootpath_size + 64); + bootpath = (char *) grub_malloc ((grub_size_t) bootpath_size + 64 + 256); if (! bootpath) { grub_print_error (); diff --git a/grub-core/osdep/linux/ofpath.c b/grub-core/osdep/linux/ofpath.c index cc849d9c94..7582dd6011 100644 --- a/grub-core/osdep/linux/ofpath.c +++ b/grub-core/osdep/linux/ofpath.c @@ -137,7 +137,7 @@ trim_newline (char *path) *end-- = '\0'; } -#define MAX_DISK_CAT 64 +#define MAX_DISK_CAT 512 static char * find_obppath (const char *sysfs_path_orig) @@ -313,6 +313,92 @@ get_basename(char *p) return ret; } + +int +add_filename_to_pile(char *filename, struct ofpath_files_list_root* root) +{ + struct ofpath_files_list_node* file; + + file = malloc(sizeof(struct ofpath_files_list_node)); + if (!file) + return -1; + + file->filename = malloc(sizeof(char) * 1024); + if (!file->filename) + { + grub_free(file); + return -1; + } + + grub_strcpy (file->filename, filename); + if (root->first == NULL) + { + root->items = 1; + root->first = file; + file->next = NULL; + } + else + { + root->items++; + file->next = root->first; + root->first = file; + } + + return 0; +} + +void +find_file(char* filename, char* directory, struct ofpath_files_list_root* root, int max_depth, int depth) +{ + struct dirent *ep; + struct stat statbuf; + DIR *dp; + int ret_val=0; + char* full_path; + + if (depth > max_depth) + { + return; + } + + if ((dp = opendir(directory)) == NULL) + { + return; + } + + full_path = malloc(1024 * sizeof(char)); + if (!full_path) + return; + + while ((ep = readdir(dp)) != NULL) + { + snprintf(full_path,1024, "%s/%s", directory, ep->d_name); + lstat(full_path, &statbuf); + + if (S_ISLNK(statbuf.st_mode)) + { + continue; + } + + if (!strcmp(ep->d_name, ".") || !strcmp(ep->d_name, "..")) + { + continue; + } + + if (!strcmp(ep->d_name, filename)) + { + ret_val = add_filename_to_pile(full_path, root); + if (ret_val == -1) + continue; + } + + find_file(filename, full_path, root, max_depth, depth+1); + } + + grub_free(full_path); + closedir(dp); +} + static char * of_path_of_vdisk(const char *sys_devname __attribute__((unused)), const char *device, @@ -383,7 +469,200 @@ of_fc_port_name(const char *path, const char *subpath, char *port_name) free(basepath); } -#ifdef __sparc__ +void +free_ofpath_files_list(struct ofpath_files_list_root* root) +{ + struct ofpath_files_list_node* node = root->first; + struct ofpath_files_list_node* next; + + while (node!=NULL) + { + next = node->next; + grub_free(node->filename); + grub_free(node); + node = next; + } + + grub_free(root); + return; +} + +char* +of_find_fc_host(char* host_wwpn) +{ + FILE* fp; + char *buf; + char *ret_val; + char portname_filename[sizeof("port_name")] = "port_name"; + char devices_path[sizeof("/sys/devices")] = "/sys/devices"; + struct ofpath_files_list_root* portnames_file_list; + struct ofpath_files_list_node* node; + + ret_val = malloc(sizeof(char)*1024); + if (!ret_val) + return NULL; + + portnames_file_list = malloc(sizeof(struct ofpath_files_list_root)); + if (!portnames_file_list) + { + grub_free(ret_val); + return NULL; + } + + portnames_file_list->items = 0; + portnames_file_list->first = NULL; + find_file(portname_filename, devices_path, portnames_file_list, 10, 0); + node = portnames_file_list->first; + + while (node != NULL) + { + fp = fopen(node->filename, "r"); + buf = malloc(sizeof(char) * 512); + if (!buf) + break; + + fscanf(fp, "%s", buf); + fclose(fp); + + if ((strcmp(buf,host_wwpn) == 0) && grub_strstr(node->filename, "fc_host")) + { + grub_free(buf); + grub_strcpy(ret_val, node->filename); + free_ofpath_files_list(portnames_file_list); + return ret_val; + } + + node = node->next; + grub_free(buf); + } + free_ofpath_files_list(portnames_file_list); + grub_free(ret_val); + return NULL; +} + +int +of_path_get_nvmeof_adapter_info(char* sysfs_path, + struct ofpath_nvmeof_info* nvmeof_info) +{ + FILE *fp; + char *buf, *buf2, *buf3; + + nvmeof_info->host_wwpn = malloc(sizeof(char) * 256); + nvmeof_info->target_wwpn = malloc(sizeof(char) * 256); + nvmeof_info->nqn = malloc(sizeof(char) * 256); + + if (nvmeof_info->host_wwpn == NULL || nvmeof_info->target_wwpn == NULL || nvmeof_info->nqn == NULL) + { + grub_free(nvmeof_info->host_wwpn); + grub_free(nvmeof_info->target_wwpn); + grub_free(nvmeof_info->nqn); + return -1; + } + + buf = malloc(sizeof(char) * 512); + if (!buf) + { + grub_free(nvmeof_info->host_wwpn); + grub_free(nvmeof_info->target_wwpn); + grub_free(nvmeof_info->nqn); + return -1; + } + + snprintf(buf, 512, "%s/subsysnqn", sysfs_path); + fp = fopen(buf, "r"); + fscanf(fp, "%s", nvmeof_info->nqn); + fclose(fp); + + snprintf(buf, 512, "%s/cntlid", sysfs_path); + fp = fopen(buf, "r"); + fscanf(fp, "%u", &(nvmeof_info->cntlid)); + fclose(fp); + + snprintf(buf, 512, "%s/address", sysfs_path); + fp = fopen(buf, "r"); + buf2 = malloc(sizeof(char) * 512); + + if (!buf2) + { + grub_free(nvmeof_info->host_wwpn); + grub_free(nvmeof_info->target_wwpn); + grub_free(nvmeof_info->nqn); + grub_free(buf); + return -1; + } + + fscanf(fp, "%s", buf2); + fclose(fp); + + buf3 = strrchr(buf2, '-') + 1; + grub_memcpy(nvmeof_info->host_wwpn, buf3, 256); + buf3=strchr(buf2, '-') + 1; + buf3=strchr(buf3, '-') + 1; + buf3=strchr(buf3, 'x') + 1; + grub_memcpy(nvmeof_info->target_wwpn, buf3, 256); + buf3 = strchr(nvmeof_info->target_wwpn, ','); + *buf3 = '\0'; + grub_free(buf); + grub_free(buf2); + return 0; +} + +#define MAX_NVME_NSID_DIGITS 6 + +static char * +of_path_get_nvme_controller_name_node(const char* devname) +{ + char *controller_node, *end; + + controller_node = strdup(devname); + end = grub_strchr(controller_node + 1, 'n'); + if (end != NULL) + { + *end = '\0'; + } + + return controller_node; +} + +unsigned int +of_path_get_nvme_nsid(const char* devname) +{ + unsigned int nsid; + char *sysfs_path, *buf; + FILE *fp; + + buf = malloc(sizeof(char) * 512); + if (!buf) + return 0; + + sysfs_path = block_device_get_sysfs_path_and_link(devname); + snprintf(buf, 512, "%s/%s/nsid", sysfs_path,devname); + fp = fopen(buf, "r"); + fscanf(fp, "%u", &(nsid)); + fclose(fp); + + free(sysfs_path); + free(buf); + return nsid; +} + +static char * +nvme_get_syspath(const char *nvmedev) +{ + char *sysfs_path, *controller_node; + + sysfs_path = block_device_get_sysfs_path_and_link (nvmedev); + if (strstr(sysfs_path,"nvme-subsystem")) + { + controller_node = of_path_get_nvme_controller_name_node(nvmedev); + strcat(sysfs_path, "/"); + strcat(sysfs_path, controller_node); + sysfs_path = xrealpath(sysfs_path); + } + + return sysfs_path; +} + static char * of_path_of_nvme(const char *sys_devname __attribute__((unused)), const char *device, @@ -392,6 +671,8 @@ of_path_of_nvme(const char *sys_devname __attribute__((unused)), { char *sysfs_path, *of_path, disk[MAX_DISK_CAT]; const char *digit_string, *part_end; + int chars_written, ret_val; + struct ofpath_nvmeof_info* nvmeof_info; digit_string = trailing_digits (device); part_end = devicenode + strlen (devicenode) - 1; @@ -411,15 +692,90 @@ of_path_of_nvme(const char *sys_devname __attribute__((unused)), /* Remove the p. */ *end = '\0'; sscanf (digit_string, "%d", &part); - snprintf (disk, sizeof (disk), "/disk@1:%c", 'a' + (part - 1)); - sysfs_path = block_device_get_sysfs_path_and_link (nvmedev); + sysfs_path = nvme_get_syspath(nvmedev); + + /* If is a NVMeoF */ + if (strstr(sysfs_path,"nvme-fabrics")) + { + nvmeof_info = malloc(sizeof(struct ofpath_nvmeof_info)); + if (!nvmeof_info) + { + grub_free (nvmedev); + return NULL; + } + + ret_val = of_path_get_nvmeof_adapter_info(sysfs_path, nvmeof_info); + if (ret_val == -1) + { + grub_free (nvmedev); + grub_free (nvmeof_info); + return NULL; + } + + sysfs_path = of_find_fc_host(nvmeof_info->host_wwpn); + if (!sysfs_path) + { + grub_free (nvmedev); + grub_free (nvmeof_info); + return NULL; + } + + chars_written = snprintf(disk,sizeof(disk), "/nvme-of/controller@%s,%x:nqn=%s", + nvmeof_info->target_wwpn,0xffff, + nvmeof_info->nqn); + unsigned int nsid = of_path_get_nvme_nsid(nvmedev); + if (nsid) + { + snprintf(disk+chars_written, sizeof("/namespace@") + MAX_NVME_NSID_DIGITS, + "/namespace@%x:%d", nsid, part); + } + grub_free(nvmeof_info); + } + else + { + snprintf (disk, sizeof (disk), "/disk@1:%c", 'a' + (part - 1)); + } free (nvmedev); } else { /* We do not have the parition. */ - snprintf (disk, sizeof (disk), "/disk@1"); - sysfs_path = block_device_get_sysfs_path_and_link (device); + sysfs_path = nvme_get_syspath (device); + if(strstr(sysfs_path, "nvme-fabrics")) + { + nvmeof_info = malloc(sizeof(struct ofpath_nvmeof_info)); + if (!nvmeof_info) + return NULL; + + ret_val = of_path_get_nvmeof_adapter_info(sysfs_path, nvmeof_info); + if (ret_val == -1) + { + grub_free (nvmeof_info); + return NULL; + } + + sysfs_path = of_find_fc_host(nvmeof_info->host_wwpn); + if (!sysfs_path) + { + grub_free (nvmeof_info); + return NULL; + } + + chars_written = snprintf(disk,sizeof(disk), "/nvme-of/controller@%s,%x:nqn=%s", + nvmeof_info->target_wwpn, 0xffff, + nvmeof_info->nqn); + unsigned int nsid = of_path_get_nvme_nsid(device); + if(nsid) + { + snprintf(disk+chars_written,sizeof("/namespace@") + sizeof(char) * MAX_NVME_NSID_DIGITS, + "/namespace@%x", nsid); + } + grub_free(nvmeof_info); + } + else + { + snprintf (disk, sizeof (disk), "/disk@1"); + } } of_path = find_obppath (sysfs_path); @@ -430,7 +786,6 @@ of_path_of_nvme(const char *sys_devname __attribute__((unused)), free (sysfs_path); return of_path; } -#endif static int vendor_is_ATA(const char *path) @@ -841,11 +1196,9 @@ grub_util_devname_to_ofpath (const char *sys_devname) /* All the models I've seen have a devalias "floppy". New models have no floppy at all. */ ofpath = xstrdup ("floppy"); -#ifdef __sparc__ else if (device[0] == 'n' && device[1] == 'v' && device[2] == 'm' && device[3] == 'e') ofpath = of_path_of_nvme (name_buf, device, devnode, devicenode); -#endif else { grub_util_warn (_("unknown device type %s"), device); diff --git a/include/grub/util/ofpath.h b/include/grub/util/ofpath.h index b43c523cb2..5962322928 100644 --- a/include/grub/util/ofpath.h +++ b/include/grub/util/ofpath.h @@ -3,4 +3,32 @@ char *grub_util_devname_to_ofpath (const char *devname); +struct ofpath_files_list_node +{ + char* filename; + struct ofpath_files_list_node* next; +}; + +struct ofpath_files_list_root +{ + int items; + struct ofpath_files_list_node* first; +}; + +struct ofpath_nvmeof_info +{ + char* host_wwpn; + char* target_wwpn; + char* nqn; + int cntlid; + int nsid; +}; + +int of_path_get_nvmeof_adapter_info(char* sysfs_path, struct ofpath_nvmeof_info* nvmeof_info); +unsigned int of_path_get_nvme_nsid(const char* devname); +int add_filename_to_pile(char *filename, struct ofpath_files_list_root* root); +void find_file(char* filename, char* directory, struct ofpath_files_list_root* root, int max_depth, int depth); +char* of_find_fc_host(char* host_wwpn); +void free_ofpath_files_list(struct ofpath_files_list_root* root); + #endif /* ! GRUB_OFPATH_MACHINE_UTIL_HEADER */