/* * According to devfs path name, it will print device node name. */ static void print_node_name(char *drv_name, char *strdevfspath) { di_node_t curnode; char *devfspath = NULL; char *node_name = NULL; curnode = di_drv_first_node(drv_name, devinfo_root); for (; curnode != DI_NODE_NIL; curnode = di_drv_next_node(curnode)) { devfspath = di_devfs_path(curnode); logmsg(MSG_INFO, "find: devfspath %s\n", devfspath); if (devfspath == NULL) continue; if ((strlen(strdevfspath) == strlen(devfspath)) && (strncmp(strdevfspath, devfspath, strlen(devfspath)) == 0)) { node_name = find_link(curnode); if (node_name == NULL) { (void) printf("NOT MAPPED\n"); } else { (void) printf("%s\n", node_name); } return; } } }
/*ARGSUSED*/ static int niu_enum(topo_mod_t *mod, tnode_t *rnode, const char *name, topo_instance_t min, topo_instance_t max, void *arg, void *notused) { tnode_t *niun; di_node_t devtree; di_node_t dnode; if (strcmp(name, NIU) != 0) { topo_mod_dprintf(mod, "Currently only know how to enumerate %s components.\n", NIU); return (0); } if ((devtree = topo_mod_devinfo(mod)) == DI_NODE_NIL) { topo_mod_dprintf(mod, "devinfo init failed."); return (-1); } /* * Load XAUI Enum */ if (xaui_enum_load(mod) == NULL) return (-1); dnode = di_drv_first_node("niumx", devtree); if (dnode != DI_NODE_NIL) { niun = niu_declare(rnode, name, 0, dnode, mod); if (niun == NULL) { topo_mod_dprintf(mod, "Enumeration of niu failed: %s\n", topo_strerror(topo_mod_errno(mod))); return (-1); /* mod_errno already set */ } if (topo_node_range_create(mod, niun, NIUFN, 0, NIUFN_MAX) < 0) { topo_node_unbind(niun); topo_mod_dprintf(mod, "child_range_add of NIUFN" "failed: %s\n", topo_strerror(topo_mod_errno(mod))); return (-1); /* mod_errno already set */ } if (niufn_instantiate(niun, NIUFN, dnode, mod) < 0) { topo_mod_dprintf(mod, "Enumeration of niufn " "failed %s\n", topo_strerror(topo_mod_errno(mod))); } } if (di_drv_next_node(dnode) != DI_NODE_NIL) topo_mod_dprintf(mod, "Currently only know how to enumerate one niu " "components.\n"); return (0); }
/* * Walk all "service" device nodes to find the one with the * matching glvc minor name */ static char * svc_name_to_glvc_dev_path(char *service) { di_node_t root_node, service_node; char *glvc_path; char *minor_name; di_minor_t minor; char *dev_path = NULL; if (service == NULL) return (NULL); /* Get device node */ root_node = di_init("/", DINFOCPYALL); if (root_node == DI_NODE_NIL) { return (dev_path); } service_node = di_drv_first_node("glvc", root_node); while (service_node != DI_NODE_NIL) { /* Make sure node name matches service name */ if (strcmp(service, di_node_name(service_node)) == 0) { /* Walk minor nodes */ minor = di_minor_next(service_node, DI_NODE_NIL); while (minor != DI_NODE_NIL) { glvc_path = di_devfs_minor_path(minor); minor_name = di_minor_name(minor); if (strcmp(minor_name, "glvc") == 0) { dev_path = malloc(strlen(glvc_path) + strlen(DEVICES_DIR) + 1); (void) strcpy(dev_path, DEVICES_DIR); (void) strcat(dev_path, glvc_path); di_devfs_path_free(glvc_path); break; } di_devfs_path_free(glvc_path); minor = di_minor_next(service_node, minor); } } if (dev_path != NULL) break; service_node = di_drv_next_node(service_node); } di_fini(root_node); return (dev_path); }
/* * Walk all vldc device nodes to find the one with the * matching minor name */ static char * svc_name_to_vldc_dev_path(char *service) { di_node_t root_node, vldc_node; char *vldc_path; char *minor_name; di_minor_t minor; char *dev_path = NULL; /* Get device node */ root_node = di_init("/", DINFOCPYALL); if (root_node == DI_NODE_NIL) { return (dev_path); } vldc_node = di_drv_first_node("vldc", root_node); while (vldc_node != DI_NODE_NIL) { /* Walk minor nodes */ minor = di_minor_next(vldc_node, DI_NODE_NIL); while (minor != DI_NODE_NIL) { vldc_path = di_devfs_minor_path(minor); minor_name = di_minor_name(minor); if (strcmp(minor_name, service) == 0) { dev_path = malloc(strlen(vldc_path) + strlen(DEVICES_DIR) + 1); (void) strcpy(dev_path, DEVICES_DIR); (void) strcat(dev_path, vldc_path); di_devfs_path_free(vldc_path); break; } di_devfs_path_free(vldc_path); minor = di_minor_next(vldc_node, minor); } if (dev_path != NULL) break; vldc_node = di_drv_next_node(vldc_node); } di_fini(root_node); return (dev_path); }
static void print_mpx_capable(di_node_t curnode) { char *prop; char *path; char *aliases = NULL; if (cap_N_option) { aliases = calloc(1, MAXPATHLEN + 1); if (aliases == NULL) { logmsg(MSG_ERROR, gettext("Unable to allocate memory for a device " "alias list\n")); return; } } for (; curnode != DI_NODE_NIL; curnode = di_drv_next_node(curnode)) { if (di_prop_lookup_strings(DDI_DEV_T_ANY, curnode, "initiator-port", &prop) >= 0) { if ((path = di_devfs_path(curnode)) == NULL) { logmsg(MSG_INFO, "Unable to find devfs path for device " "%s: %s\n", &curnode, strerror(errno)); continue; } if (cap_N_option) { char *nodename = di_node_name(curnode); /* nodename is never going to be null */ if (strstr(aliases, nodename) == NULL) /* haven't seen this nodename before */ (void) snprintf(aliases, MAXPATHLEN + 1, "%s|%s", ((aliases != NULL) ? aliases : ""), nodename); } else (void) printf("%s\n", path); } } if (cap_N_option) (void) printf("%s\n", aliases); }
/* * Nodes belonging to the configured driver (dtls->fcal_driver) are * located in the device tree. A check is applied that any node found has * a physical address beginning with the configured search string * (dtls->fcal_disk_parent). For each suitable node found, get_drv_info() * is called to determine if a change of status has occurred. * Returns 1 if any status has changed - else 0. */ static int walk_disks(di_node_t node, led_dtls_t *dtls) { static char *sl_platform_sl = "/platform/"; int r = 0; int len; /* find "/platform/" */ char *ptr = strstr(dtls->fcal_disk_parent, sl_platform_sl); if (ptr == NULL) return (0); /* skip over "/platform" */ ptr += strlen(sl_platform_sl) - 1; len = strlen(ptr); for (node = di_drv_first_node(dtls->fcal_driver, node); node != DI_NODE_NIL; node = di_drv_next_node(node)) { char *dev_path = di_devfs_path(node); if (dev_path == NULL) { /* no memory, just hope things get better */ continue; } if (memcmp(dev_path, ptr, len) != 0) { /* * path name doesn't start right, skip this one */ free(dev_path); continue; } free(dev_path); if (get_drv_info(node, dtls) != 0) { r = 1; /* change observed */ } } return (r); }
/*ARGSUSED*/ int platform_iob_enum(topo_mod_t *mod, tnode_t *parent, topo_instance_t imin, topo_instance_t imax) { /* * An E15K and its successors may have up to 18 I/O boards, * numbered 0 through 17. Each board has two hostbridges, and * there are a pair of PCI buses under each hostbridge. We can * discover the existence of a board by the presence of * devinfo nodes for those hostbridges. We let the hostbridge * enumerator actually create nodes for the hostbridges, * passing them the did_t's for all the hostbridge nodes we * know indicate that the ioboard exists. */ di_node_t devtree; di_node_t pnode; did_t *iobs[18][2][2]; int brd, br, bus, i; devtree = topo_mod_devinfo(mod); if (devtree == DI_NODE_NIL) { topo_mod_dprintf(mod, "devinfo init failed."); return (-1); } for (i = 0; i < 18; i++) { iobs[i][0][0] = iobs[i][0][1] = NULL; iobs[i][1][0] = iobs[i][1][1] = NULL; } pnode = di_drv_first_node(SCHIZO, devtree); while (pnode != DI_NODE_NIL) { did_t *d; d = split_bus_address(mod, pnode, IOB_BASEADDR, BUS_ADDRDIST, 0, 17, &brd, &br, &bus); if (d == NULL) { pnode = di_drv_next_node(pnode); continue; } iobs[brd][br][bus] = d; pnode = di_drv_next_node(pnode); } for (i = 0; i < 18; i++) { tnode_t *ion; /* * Make sure we found all the buses and bridges */ if (iobs[i][0][0] == NULL || iobs[i][0][1] == NULL || iobs[i][1][0] == NULL || iobs[i][1][1] == NULL) continue; did_did_link_set(iobs[i][0][0], iobs[i][0][1]); did_did_link_set(iobs[i][1][0], iobs[i][1][1]); did_did_chain_set(iobs[i][0][0], iobs[i][1][0]); if ((ion = ioboard_declare(mod, parent, i, iobs[i][0][0])) == NULL) { topo_mod_dprintf(mod, "Creation of tnode for %s%d failed.\n", IOBOARD, i); continue; } if (topo_mod_enumerate(mod, ion, HOSTBRIDGE, HOSTBRIDGE, 0, 0, iobs[i][0][0]) < 0) { topo_mod_dprintf(mod, "Enumeration of %s%d/%s%d failed.\n", IOBOARD, i, HOSTBRIDGE, 0); continue; } if (topo_mod_enumerate(mod, ion, HOSTBRIDGE, HOSTBRIDGE, 1, 1, iobs[i][0][0]) < 0) { topo_mod_dprintf(mod, "Enumeration of %s%d/%s%d failed.\n", IOBOARD, i, HOSTBRIDGE, 1); continue; } } return (0); }
int emulex_update(char *file) { int fd, retval = 0; int devcnt = 0; uint_t state = 0, fflag = 0; static uchar_t bootpath[PATH_MAX]; int fcode_fd = -1; static struct utmpx *utmpp = NULL; di_node_t root; di_node_t node, sib_node, count_node; di_minor_t minor_node; char phys_path[PATH_MAX], *path; int errnum = 0, fcio_errno = 0; static uchar_t prom_ver_data[MAXNAMELEN]; static char ver_file[EMULEX_FCODE_VERSION_LENGTH]; void (*sigint)(); int prop_entries = -1; int *port_data = NULL; if (file) { /* set the fcode download flag */ fflag++; /* check for a valid file */ if ((fcode_fd = open(file, O_RDONLY)) < 0) { (void) fprintf(stderr, MSGSTR(21118, "Error: Could not open %s, failed " "with errno %d\n"), file, errno); return (1); } /* check for single user mode */ while ((utmpp = getutxent()) != NULL) { if (strstr(utmpp->ut_line, "run-level") && (strcmp(utmpp->ut_line, "run-level S") && strcmp(utmpp->ut_line, "run-level 1"))) { if (q_warn(1)) { (void) endutxent(); (void) close(fcode_fd); return (1); } break; } } (void) endutxent(); /* get bootpath */ if (!q_getbootdev((uchar_t *)&bootpath[0]) && getenv("_LUX_D_DEBUG") != NULL) { (void) fprintf(stdout, " Bootpath: %s\n", bootpath); } } /* * Download the Fcode to all the emulex cards found */ /* Create a snapshot of the kernel device tree */ if ((root = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) { (void) fprintf(stderr, MSGSTR(21114, "Error: Could not get /devices path to " "Emulex Devices.\n")); retval++; } /* point to first node which matches emulex driver */ node = di_drv_first_node("emlxs", root); if (node == DI_NODE_NIL) { /* * Could not find any emulex cards */ (void) di_fini(root); (void) fprintf(stderr, MSGSTR(21115, "\n Found Path to %d Emulex Devices.\n"), devcnt); retval++; } else { count_node = node; while (count_node != DI_NODE_NIL) { state = di_state(count_node); if ((state & DI_DRIVER_DETACHED) != DI_DRIVER_DETACHED) { sib_node = di_child_node(count_node); while (sib_node != DI_NODE_NIL) { state = di_state(sib_node); if ((state & DI_DRIVER_DETACHED) != DI_DRIVER_DETACHED) { /* Found an attached node */ prop_entries = di_prop_lookup_ints( DDI_DEV_T_ANY, sib_node, "port", &port_data); if (prop_entries != -1) { devcnt++; break; } } sib_node = di_sibling_node(sib_node); } } count_node = di_drv_next_node(count_node); } (void) fprintf(stdout, MSGSTR(21116, "\n Found Path to %d Emulex Devices.\n"), devcnt); } /* * Traverse device tree to find all emulex cards */ while (node != DI_NODE_NIL) { state = di_state(node); if ((state & DI_DRIVER_DETACHED) == DI_DRIVER_DETACHED) { node = di_drv_next_node(node); continue; } sib_node = di_child_node(node); while (sib_node != DI_NODE_NIL) { state = di_state(sib_node); if ((state & DI_DRIVER_DETACHED) != DI_DRIVER_DETACHED) { /* Found an attached node */ prop_entries = di_prop_lookup_ints( DDI_DEV_T_ANY, sib_node, "port", &port_data); if (prop_entries != -1) { /* Found a node with "port" property */ minor_node = di_minor_next(sib_node, DI_MINOR_NIL); break; } } sib_node = di_sibling_node(sib_node); } if (sib_node == DI_NODE_NIL) { goto try_next; } path = di_devfs_path(sib_node); (void) strcpy(phys_path, "/devices"); (void) strncat(phys_path, path, strlen(path)); di_devfs_path_free(path); if (fflag && (strstr((char *)bootpath, (char *)phys_path) != NULL)) { (void) fprintf(stderr, MSGSTR(21117, "Ignoring %s (bootpath)\n"), phys_path); node = di_drv_next_node(node); continue; } if (minor_node) { (void) strncat(phys_path, ":", 1); (void) strncat(phys_path, di_minor_name(minor_node), strlen(di_minor_name(minor_node))); } (void) fprintf(stdout, MSGSTR(21107, "\n Opening Device: %s\n"), phys_path); /* Check if the device is valid */ if ((fd = open(phys_path, O_RDWR)) < 0) { (void) fprintf(stderr, MSGSTR(21121, "Error: Could not open %s, failed " "with errno %d\n"), phys_path, errno); retval++; node = di_drv_next_node(node); continue; } (void) close(fd); /* * Check FCode version present on the adapter * (at last boot) */ memset(prom_ver_data, 0, sizeof (prom_ver_data)); if (emulex_fcodeversion(node, (uchar_t *)&prom_ver_data[0]) == 0) { errnum = 0; if (strlen((char *)prom_ver_data) == 0) { (void) fprintf(stdout, MSGSTR(21108, " Detected FCode Version:\tNo version available for this FCode\n")); } else { (void) fprintf(stdout, MSGSTR(21109, " Detected FCode Version:\t%s\n"), prom_ver_data); } } else { errnum = 2; /* can't get prom properties */ retval++; } if (fflag) { memset(ver_file, 0, sizeof (ver_file)); if (emulex_fcode_reader(fcode_fd, "fcode-version", ver_file, sizeof (ver_file)) == 0) { (void) fprintf(stdout, MSGSTR(21110, " New FCode Version:\t\t%s\n"), ver_file); } else { di_fini(root); (void) close(fcode_fd); return (1); } /* * Load the New FCode * Give warning if file doesn't appear to be correct */ if (!q_warn(errnum)) { /* Disable user-interrupt Control-C */ sigint = (void (*)(int)) signal(SIGINT, SIG_IGN); /* Load FCode */ (void) fprintf(stdout, MSGSTR(21111, " Loading FCode: %s\n"), file); if (fcode_load_file(fcode_fd, phys_path, &fcio_errno) == FCODE_SUCCESS) { (void) fprintf(stdout, MSGSTR(21112, " Successful FCode download: %s\n"), phys_path); } else { handle_emulex_error(fcio_errno, phys_path); retval++; } /* Restore SIGINT (user interrupt) setting */ (void) signal(SIGINT, sigint); } } try_next: node = di_drv_next_node(node); } di_fini(root); (void) fprintf(stdout, " "); (void) fprintf(stdout, MSGSTR(125, "Complete\n")); if (fcode_fd != -1) (void) close(fcode_fd); return (retval); }
static int do_driver_update_ioctl(char *drivername, char *node_desc, char *hca_desc, uint64_t inp_hca_guid, uint32_t update_flag) { di_node_t hcanode, childnode; char *devpath; char *access_devname; int devlength, devfd, rc = -1; uint64_t *hca_guid; char *desc_str = (node_desc ? node_desc : hca_desc); if ((hcanode = di_drv_first_node(drivername, di_rootnode)) == DI_NODE_NIL) { return (-1); } while (hca_desc && hcanode != DI_NODE_NIL) { childnode = di_child_node(hcanode); while (childnode != DI_NODE_NIL) { if (di_prop_lookup_int64(DDI_DEV_T_ANY, childnode, "hca-guid", (int64_t **)&hca_guid) != 1) { childnode = di_sibling_node(childnode); continue; } else { break; } } if (*hca_guid == inp_hca_guid) break; hcanode = di_drv_next_node(hcanode); } if ((hca_desc && childnode == DI_NODE_NIL) || hcanode == DI_NODE_NIL) { IBERROR("matching GUID not found"); return (-1); } devpath = di_devfs_path(hcanode); devlength = strlen(devpath_prefix) + strlen(devpath) + strlen(devpath_suffix) + 2; access_devname = malloc(devlength); (void) snprintf(access_devname, devlength, "%s%s%s", devpath_prefix, devpath, devpath_suffix); if ((devfd = open(access_devname, O_RDONLY)) < 0) { IBERROR("open device file %s failed", access_devname); free(access_devname); return (rc); } if (strcmp(drivername, "hermon") == 0) { hermon_nodedesc_ioctl_t nodedesc_ioctl; strncpy(nodedesc_ioctl.node_desc_str, desc_str, 64); if (update_flag & NODEDESC_UPDATE_STRING) nodedesc_ioctl.node_desc_update_flag = HERMON_NODEDESC_UPDATE_STRING; else if (update_flag & NODEDESC_UPDATE_HCA_STRING) nodedesc_ioctl.node_desc_update_flag = HERMON_NODEDESC_UPDATE_HCA_STRING; else { IBERROR("Invalid option"); exit(-1); } if ((rc = ioctl(devfd, HERMON_IOCTL_SET_NODEDESC, (void *)&nodedesc_ioctl)) != 0) { IBERROR("hermon ioctl failure"); } } else { IBERROR("drivername != hermon: %s", drivername); } free(access_devname); close(devfd); return (rc); }
static void do_driver_read_ioctl(char *drivername) { di_node_t hcanode, childnode; char *devpath; char *access_devname; int devlength, devfd, rc = -1; uint64_t *hca_guid; if ((hcanode = di_drv_first_node(drivername, di_rootnode)) == DI_NODE_NIL) { return; } while (hcanode != DI_NODE_NIL) { childnode = di_child_node(hcanode); while (childnode != DI_NODE_NIL) { if (di_prop_lookup_int64(DDI_DEV_T_ANY, childnode, "hca-guid", (int64_t **)&hca_guid) != 1) { childnode = di_sibling_node(childnode); continue; } else { break; } } if (childnode == DI_NODE_NIL) { hcanode = di_drv_next_node(hcanode); continue; } devpath = di_devfs_path(hcanode); devlength = strlen(devpath_prefix) + strlen(devpath) + strlen(devpath_suffix) + 2; access_devname = malloc(devlength); (void) snprintf(access_devname, devlength, "%s%s%s", devpath_prefix, devpath, devpath_suffix); if ((devfd = open(access_devname, O_RDONLY)) < 0) { IBERROR("open device file %s failed", access_devname); free(access_devname); hcanode = di_drv_next_node(hcanode); continue; } if (strcmp(drivername, "hermon") == 0) { hermon_nodedesc_ioctl_t nodedesc_ioctl; if ((rc = ioctl(devfd, HERMON_IOCTL_GET_NODEDESC, (void *)&nodedesc_ioctl)) != 0) { IBERROR("hermon ioctl failure"); free(access_devname); close(devfd); hcanode = di_drv_next_node(hcanode); continue; } add_read_info_arr((char *)nodedesc_ioctl.node_desc_str, *hca_guid); } else { IBERROR("drivername != hermon: %s", drivername); } free(access_devname); close(devfd); hcanode = di_drv_next_node(hcanode); } }
/* * The fw_identify() function walks the device * tree trying to find devices which this plugin * can work with. * * The parameter "start" gives us the starting index number * to give the device when we add it to the fw_devices list. * * firstdev is allocated by us and we add space as needed * * When we store the desired information, inquiry-serial-no * goes in thisdev->addresses[1], and client-guid goes in * thisdev->addresses[2]. */ int fw_identify(int start) { int idx = start; int fw_sata_disk = 0; int *exists; di_node_t thisnode; struct devicelist *newdev = NULL; char *devpath = NULL; char *driver = NULL; char *sp_temp; char *sp_temp_cut; /* We need to inquiry information manually by sending probe command */ libscsi_hdl_t *handle; libscsi_target_t *target; libscsi_errno_t serr; /* Just in case we've got an FC-attached device on sparc */ if (strcmp(self->drvname, "ssd") == 0) { driver = self->drvname; } else driver = drivername; thisnode = di_drv_first_node(driver, rootnode); if (thisnode == DI_NODE_NIL) { logmsg(MSG_INFO, "No %s nodes in this system\n", driver); return (FWFLASH_FAILURE); } if ((handle = libscsi_init(LIBSCSI_VERSION, &serr)) == NULL) { logmsg(MSG_ERROR, gettext("%s: failed to initialize " "libscsi\n"), newdev->drvname); return (FWFLASH_FAILURE); } /* we've found one, at least */ for (; thisnode != DI_NODE_NIL; thisnode = di_drv_next_node(thisnode)) { /* Need to free by di_devfs_path_free */ if ((devpath = di_devfs_path(thisnode)) == NULL) { logmsg(MSG_INFO, "unable to get device path for " "current node with errno %d\n", errno); continue; } /* * We check if this is removable device, in which case * we really aren't interested, so exit stage left */ if (di_prop_lookup_ints(DDI_DEV_T_ANY, thisnode, "removable-media", &exists) > -1) { logmsg(MSG_INFO, "%s: not interested in removable media device\n" "%s\n", driver, devpath); FW_SD_FREE_DEVPATH(devpath) continue; } if ((newdev = calloc(1, sizeof (struct devicelist))) == NULL) { logmsg(MSG_ERROR, gettext("%s: identification function unable " "to allocate space for device entry\n"), driver); libscsi_fini(handle); FW_SD_FREE_DEVPATH(devpath) return (FWFLASH_FAILURE); }
static int mpxio_nvl_boilerplate(di_node_t curnode) { int rv; char *strdevid; ddi_devid_t curdevid; nvlist_t *newnvl; for (; curnode != DI_NODE_NIL; curnode = di_drv_next_node(curnode)) { errno = 0; curdevid = NULL; get_devid(curnode, &curdevid); if (curdevid == NULL) /* * There's no devid registered for this device * so it's not cool enough to play with us */ continue; strdevid = devid_str_encode(curdevid, NULL); /* does this exist in the on-disk cache? */ rv = nvlist_lookup_nvlist(mapnvl, strdevid, &newnvl); if (rv == ENOENT) { logmsg(MSG_INFO, "nvlist for %s not found\n", strdevid); /* no, so alloc a new nvl to store it */ if (nvlist_alloc(&newnvl, NV_UNIQUE_NAME, 0) != 0) { logmsg(MSG_ERROR, gettext("Unable to allocate space for " "a devid property list: %s\n"), strerror(errno)); return (-1); } } else { if ((rv != ENOTSUP) && (rv != EINVAL)) logmsg(MSG_INFO, "%s exists in ondisknvl, verifying\n", strdevid); } if (popcheck_devnvl(curnode, newnvl, strdevid) != 0) { logmsg(MSG_ERROR, gettext("Unable to populate devid nvpair " "for device with devid %s\n"), strdevid); devid_str_free(strdevid); nvlist_free(newnvl); return (-1); } /* Now add newnvl into our cache. */ errno = 0; rv = nvlist_add_nvlist(mapnvl, strdevid, newnvl); if (rv) { logmsg(MSG_ERROR, gettext("Unable to add device (devid %s) " "to in-kernel nvl: %s (%d)\n"), strdevid, strerror(rv), rv); devid_str_free(strdevid); nvlist_free(newnvl); return (-1); } logmsg(MSG_INFO, gettext("added device (devid %s) to mapnvl\n\n"), strdevid); devid_str_free(strdevid); } return (0); }