From 9b16421c86874e8f3615ce3e2b58b8f40710f7ff Mon Sep 17 00:00:00 2001 From: Avnish Chouhan Date: Sun, 29 Jan 2023 15:07:21 -0500 Subject: [PATCH 1/4] ieee1275: implement FCP methods for WWPN and LUNs This patch enables the fcp-targets and fcp-luns methods which are responsible to get WWPNs and LUNs for fibre channel devices. Those methods are specially necessary if the boot directory and grub installation are in different FCP disks, allowing the dev_iterate() to find the WWPNs and LUNs when called by searchfs.uuid tool. Signed-off-by: Diego Domingos Signed-off-by: Avnish Chouhan --- grub-core/disk/ieee1275/ofdisk.c | 111 ++++++++++++++++++++++++++++++- 1 file changed, 110 insertions(+), 1 deletion(-) diff --git a/grub-core/disk/ieee1275/ofdisk.c b/grub-core/disk/ieee1275/ofdisk.c index 55346849d3..afdc2723a1 100644 --- a/grub-core/disk/ieee1275/ofdisk.c +++ b/grub-core/disk/ieee1275/ofdisk.c @@ -209,7 +209,116 @@ dev_iterate_real (const char *name, const char *path) static void dev_iterate (const struct grub_ieee1275_devalias *alias) { - if (grub_strcmp (alias->type, "vscsi") == 0) + if (grub_strcmp (alias->type, "fcp") == 0) + { + /* + * 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; + }; + + 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; + } + buf = grub_malloc (grub_strlen (alias->path) + 32 + 32); + 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. + */ + struct args_ret *targets_table = (struct args_ret *)(args_targets.table); + for (i=0; i< args_targets.nentries; i++) + { + ptr_targets = (grub_uint64_t*)(grub_uint32_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; + } + struct args_ret *luns_table = (struct args_ret *)(args_luns.table); + + /* Iterate over all LUNs */ + for(j=0;jtype, "vscsi") == 0) { static grub_ieee1275_ihandle_t ihandle; struct set_color_args From d41c449d1de9d8ce30524ca838d2bb501afa78eb Mon Sep 17 00:00:00 2001 From: Avnish Chouhan Date: Mon, 20 Mar 2023 04:45:01 -0400 Subject: [PATCH 2/4] ieee1275: change the logic of ieee1275_get_devargs() Usually grub will parse the PFW arguments by searching for the first occurence of the character ':'. However, we can have this char more than once on NQN. This patch changes the logic to find the last occurence of this char so we can get the proper values for NVMeoFC Signed-off-by: Diego Domingos Signed-off-by: Avnish Chouhan --- grub-core/kern/ieee1275/openfw.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) 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 (); From e5fc271ce67f71c66d30a044cd0578326a23b928 Mon Sep 17 00:00:00 2001 From: Avnish Chouhan Date: Fri, 21 Apr 2023 08:53:18 -0400 Subject: [PATCH 3/4] ieee1275: add support for NVMeoFC This patch implements the functions to scan and discovery of NVMeoFC. Signed-off-by: Diego Domingos Signed-off-by: Avnish Chouhan --- grub-core/disk/ieee1275/ofdisk.c | 390 +++++++++++++++++++++++-------- 1 file changed, 296 insertions(+), 94 deletions(-) diff --git a/grub-core/disk/ieee1275/ofdisk.c b/grub-core/disk/ieee1275/ofdisk.c index afdc2723a1..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; @@ -207,116 +209,316 @@ dev_iterate_real (const char *name, const char *path) } static void -dev_iterate (const struct grub_ieee1275_devalias *alias) +dev_iterate_fcp_disks(const struct grub_ieee1275_devalias *alias) { - if (grub_strcmp (alias->type, "fcp") == 0) + /* + * 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)) { - /* - * 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; - }; + 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; - if(grub_ieee1275_open (alias->path, &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; kpath); - return; + args_luns.wwpn_l = (grub_ieee1275_cell_t) (*ptr_targets); + args_luns.wwpn_h = (grub_ieee1275_cell_t) (*ptr_targets >> 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; + } - /* 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) + /* 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("disk", "failed to get the targets while iterating FCP disk path=%s\n", alias->path); - grub_ieee1275_close(ihandle); - return; + grub_dprintf("ofdisk", "failed to open the disk while getting nvme-controllers path=%s\n", buf); + continue; } - buf = grub_malloc (grub_strlen (alias->path) + 32 + 32); - if (!buf) + 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); - return; + continue; } - bufptr = grub_stpcpy (buf, alias->path); - /* - * Iterate over entries returned by pfw. Each entry contains a - * pointer to wwpn table and his length. - */ - struct args_ret *targets_table = (struct args_ret *)(args_targets.table); - for (i=0; i< args_targets.nentries; i++) + /* 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++) { - ptr_targets = (grub_uint64_t*)(grub_uint32_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; - } - struct args_ret *luns_table = (struct args_ret *)(args_luns.table); + 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); - /* Iterate over all LUNs */ - for(j=0;jtype, "fcp") == 0) + { + /* Iterate disks */ + dev_iterate_fcp_disks(alias); + /* Iterate NVMeoF */ + dev_iterate_fcp_nvmeof(alias); } else if (grub_strcmp (alias->type, "vscsi") == 0) { From 8247f212fe0d982cd06b8d56ae803761b281b90b Mon Sep 17 00:00:00 2001 From: Avnish Chouhan Date: Fri, 5 May 2023 03:21:52 -0400 Subject: [PATCH 4/4] ieee1275: ofpath enable NVMeoF logical device translate This patch add code to enable the translation of logical devices to the of NVMeoFC paths. Signed-off-by: Diego Domingos Signed-off-by: Avnish Chouhan --- grub-core/osdep/linux/ofpath.c | 371 ++++++++++++++++++++++++++++++++- include/grub/util/ofpath.h | 28 +++ 2 files changed, 390 insertions(+), 9 deletions(-) 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 */