/* * Trim leading and trailing whitespace from the string. */ static char * disk_trim_whitespace(topo_mod_t *mod, const char *begin) { const char *end; char *buf; size_t count; if (begin == NULL) return (NULL); end = begin + strlen(begin); while (begin < end && isspace(*begin)) begin++; while (begin < end && isspace(*(end - 1))) end--; count = end - begin; if ((buf = topo_mod_alloc(mod, count + 1)) == NULL) return (NULL); (void) strlcpy(buf, begin, count + 1); return (buf); }
/*ARGSUSED*/ static int maybe_di_chars_copy(tnode_t *tn, did_t *pd, const char *dpnm, const char *tpgrp, const char *tpnm) { topo_mod_t *mp; uchar_t *typbuf; char *tmpbuf; int sz = -1; int err, e; if (di_bytes_get(did_mod(pd), did_dinode(pd), dpnm, &sz, &typbuf) < 0) return (0); mp = did_mod(pd); if ((tmpbuf = topo_mod_alloc(mp, sz + 1)) == NULL) return (topo_mod_seterrno(mp, EMOD_NOMEM)); bcopy(typbuf, tmpbuf, sz); tmpbuf[sz] = 0; e = topo_prop_set_string(tn, tpgrp, tpnm, TOPO_PROP_IMMUTABLE, tmpbuf, &err); topo_mod_free(mp, tmpbuf, sz + 1); if (e != 0) return (topo_mod_seterrno(mp, err)); return (0); }
static nvlist_t * amd_lookup_by_mcid(topo_mod_t *mod, topo_instance_t id) { mc_snapshot_info_t mcs; void *buf = NULL; uint8_t ver; nvlist_t *nvl = NULL; char path[64]; int fd, err; (void) snprintf(path, sizeof (path), "/dev/mc/mc%d", id); fd = open(path, O_RDONLY); if (fd == -1) { /* * Some v20z and v40z systems may have had the 3rd-party * NWSnps packagae installed which installs a /dev/mc * link. So try again via /devices. */ (void) snprintf(path, sizeof (path), "/devices/pci@0,0/pci1022,1102@%x,2:mc-amd", MC_AMD_DEV_OFFSET + id); fd = open(path, O_RDONLY); } if (fd == -1) return (NULL); /* do not whinge */ if (ioctl(fd, MC_IOC_SNAPSHOT_INFO, &mcs) == -1 || (buf = topo_mod_alloc(mod, mcs.mcs_size)) == NULL || ioctl(fd, MC_IOC_SNAPSHOT, buf) == -1) { whinge(mod, NULL, "mc failed to snapshot %s: %s\n", path, strerror(errno)); free(buf); (void) close(fd); return (NULL); } (void) close(fd); err = nvlist_unpack(buf, mcs.mcs_size, &nvl, 0); topo_mod_free(mod, buf, mcs.mcs_size); if (nvlist_lookup_uint8(nvl, MC_NVLIST_VERSTR, &ver) != 0) { whinge(mod, NULL, "mc nvlist is not versioned\n"); nvlist_free(nvl); return (NULL); } else if (ver != MC_NVLIST_VERS1) { whinge(mod, NULL, "mc nvlist version mismatch\n"); nvlist_free(nvl); return (NULL); } return (err ? NULL : nvl); }
static topo_mod_t * hb_enumr_load(topo_mod_t *mp, tnode_t *parent) { topo_mod_t *rp = NULL; char *plat, *mach; char *hbpath; char *rootdir; int err; plat = mach = NULL; if (topo_prop_get_string(parent, TOPO_PGROUP_SYSTEM, TOPO_PROP_PLATFORM, &plat, &err) < 0) { (void) topo_mod_seterrno(mp, err); return (NULL); } if (topo_prop_get_string(parent, TOPO_PGROUP_SYSTEM, TOPO_PROP_MACHINE, &mach, &err) < 0) { (void) topo_mod_seterrno(mp, err); return (NULL); } hbpath = topo_mod_alloc(mp, PATH_MAX); rootdir = topo_mod_rootdir(mp); (void) snprintf(hbpath, PATH_MAX, PATH_TO_HB_ENUM, rootdir ? rootdir : "", plat); if ((rp = topo_mod_load(mp, hbpath)) == NULL) { topo_mod_dprintf(mp, "%s enumerator could not load %s.\n", IOBOARD, hbpath); (void) snprintf(hbpath, PATH_MAX, PATH_TO_HB_ENUM, rootdir ? rootdir : "", mach); if ((rp = topo_mod_load(mp, hbpath)) == NULL) { topo_mod_dprintf(mp, "%s enumerator could not load %s.\n", IOBOARD, hbpath); } } topo_mod_strfree(mp, plat); topo_mod_strfree(mp, mach); topo_mod_free(mp, hbpath, PATH_MAX); return (rp); }
/* * fix_dev_prop -- sometimes di_devfs_path() doesn't tell the whole * story, leaving off the device and function number. Chances are if * devfs doesn't put these on then we'll never see this device as an * error detector called out in an ereport. Unfortunately, there are * races and we sometimes do get ereports from devices that devfs * decides aren't there. For example, the error injector card seems * to bounce in and out of existence according to devfs. We tack on * the missing dev and fn here so that the DEV property used to look * up the topology node is correct. */ static char * dev_path_fix(topo_mod_t *mp, char *path, int devno, int fnno) { char *lastslash; char *newpath; int need; /* * We only care about the last component of the dev path. If * we don't find a slash, something is weird. */ lastslash = strrchr(path, '/'); assert(lastslash != NULL); /* * If an @ sign is present in the last component, the * di_devfs_path() result had the device,fn unit-address. * In that case there's nothing we need do. */ if (strchr(lastslash, '@') != NULL) return (path); if (fnno == 0) need = snprintf(NULL, 0, "%s@%x", path, devno); else need = snprintf(NULL, 0, "%s@%x,%x", path, devno, fnno); need++; if ((newpath = topo_mod_alloc(mp, need)) == NULL) { topo_mod_strfree(mp, path); return (NULL); } if (fnno == 0) (void) snprintf(newpath, need, "%s@%x", path, devno); else (void) snprintf(newpath, need, "%s@%x,%x", path, devno, fnno); topo_mod_strfree(mp, path); return (newpath); }
static int rtld_init(topo_mod_t *mod, topo_version_t version) { int err; topo_rtld_t *rp; void *dlp; if ((dlp = dlopen(mod->tm_path, RTLD_LOCAL | RTLD_NOW)) == NULL) { topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR, "dlopen() failed: %s\n", dlerror()); return (topo_mod_seterrno(mod, ETOPO_RTLD_OPEN)); } if ((rp = mod->tm_data = topo_mod_alloc(mod, sizeof (topo_rtld_t))) == NULL) return (topo_mod_seterrno(mod, ETOPO_RTLD_OPEN)); rp->rtld_dlp = dlp; rp->rtld_init = (int (*)())dlsym(dlp, "_topo_init"); rp->rtld_fini = (void (*)())dlsym(dlp, "_topo_fini"); if (rp->rtld_init == NULL) { (void) dlclose(dlp); topo_free(rp, sizeof (topo_rtld_t)); return (topo_mod_seterrno(mod, ETOPO_RTLD_INIT)); } /* * Call _topo_init() in the module. */ err = rp->rtld_init(mod, version); if (err < 0 || !(mod->tm_flags & TOPO_MOD_REG)) { (void) rtld_fini(mod); return (topo_mod_seterrno(mod, ETOPO_MOD_NOREG)); } return (0); }
static topo_mod_t * module_load(topo_mod_t *mp, tnode_t *parent, const char *name) { topo_mod_t *rp = NULL; char *plat, *mach; char *path; char *rootdir; int err; plat = mach = NULL; if (topo_prop_get_string(parent, TOPO_PGROUP_SYSTEM, TOPO_PROP_PLATFORM, &plat, &err) < 0) { (void) topo_mod_seterrno(mp, err); return (NULL); } if (topo_prop_get_string(parent, TOPO_PGROUP_SYSTEM, TOPO_PROP_MACHINE, &mach, &err) < 0) { (void) topo_mod_seterrno(mp, err); return (NULL); } path = topo_mod_alloc(mp, PATH_MAX); rootdir = topo_mod_rootdir(mp); (void) snprintf(path, PATH_MAX, PATH_TEMPLATE, rootdir ? rootdir : "", plat, name); if ((rp = topo_mod_load(mp, path)) == NULL) { topo_mod_dprintf(mp, "Unable to load %s.\n", path); (void) snprintf(path, PATH_MAX, PATH_TEMPLATE, rootdir ? rootdir : "", mach, name); if ((rp = topo_mod_load(mp, path)) == NULL) topo_mod_dprintf(mp, "Unable to load %s.\n", path); } topo_mod_strfree(mp, plat); topo_mod_strfree(mp, mach); topo_mod_free(mp, path, PATH_MAX); return (rp); }
/* ARGSUSED */ int x86pi_check_comp(topo_mod_t *mod) { int rv; int fd; int32_t legacy; nvlist_t *nvl = NULL; fm_ioc_data_t fid; char *ibuf = NULL, *obuf = NULL; size_t insz = 0, outsz = 0; char *f = "x86pi_check_comp"; smbios_hdl_t *shp; shp = topo_mod_smbios(mod); if (shp == NULL) return (X86PI_NONE); /* open /dev/fm */ fd = open("/dev/fm", O_RDONLY); if (fd < 0) { topo_mod_dprintf(mod, "%s: failed to open /dev/fm.\n", f); return (X86PI_NONE); } /* set up buffers and ioctl data structure */ outsz = FM_IOC_MAXBUFSZ; obuf = topo_mod_alloc(mod, outsz); if (obuf == NULL) { perror("umem_alloc"); return (X86PI_NONE); } fid.fid_version = 1; fid.fid_insz = insz; fid.fid_inbuf = ibuf; fid.fid_outsz = outsz; fid.fid_outbuf = obuf; /* send the ioctl to /dev/fm to retrieve legacy variable */ rv = ioctl(fd, FM_IOC_GENTOPO_LEGACY, &fid); if (rv < 0) { topo_mod_dprintf(mod, "%s: ioctl to /dev/fm failed", f); perror("fm_ioctl"); (void) close(fd); return (X86PI_NONE); } (void) close(fd); (void) nvlist_unpack(fid.fid_outbuf, fid.fid_outsz, &nvl, 0); (void) nvlist_lookup_int32(nvl, FM_GENTOPO_LEGACY, &legacy); nvlist_free(nvl); topo_mod_free(mod, obuf, outsz); if (legacy == 1) { /* legacy kernel variable set; will do the same */ return (X86PI_NONE); } /* legacy kernel variable not set; generic topo enum */ return (X86PI_FULL); }
static int dev_di_node_add(di_node_t node, char *devid, disk_cbdata_t *cbp) { topo_mod_t *mod = cbp->dcb_mod; dev_di_node_t *dnode; di_path_t pnode; char *path; int mlen; char *minorpath; char *extn = ":a"; char *s; int64_t *nblocksp; uint64_t nblocks; int *dblksizep; uint_t dblksize; char lentry[MAXPATHLEN]; int pathcount; int *inq_dtype, itype; int i; if (devid) { /* * Check for list duplicate using devid search. * Note if there is no devid, then we can end up with duplicates * in the list, but this doesn't do any harm. */ for (dnode = topo_list_next(cbp->dcb_list); dnode != NULL; dnode = topo_list_next(dnode)) { if (dnode->ddn_devid && devid_str_compare(dnode->ddn_devid, devid) == 0) { topo_mod_dprintf(mod, "dev_di_node_add: " "already there %s\n", devid); return (0); } } } if ((dnode = topo_mod_zalloc(mod, sizeof (dev_di_node_t))) == NULL) return (-1); if (devid) { /* Establish the devid. */ dnode->ddn_devid = topo_mod_strdup(mod, devid); if (dnode->ddn_devid == NULL) goto error; } /* Establish the devinfo dpath */ if ((path = di_devfs_path(node)) == NULL) { (void) topo_mod_seterrno(mod, errno); goto error; } dnode->ddn_dpath = topo_mod_strdup(mod, path); di_devfs_path_free(path); if (dnode->ddn_dpath == NULL) goto error; /* * Establish the physical ppath and target ports. If the device is * non-mpxio then dpath and ppath are the same, and the target port is a * property of the device node. * * If dpath is a client node under scsi_vhci, then iterate over all * paths and get their physical paths and target port properrties. * di_path_client_next_path call below will * return non-NULL, and ppath is set to the physical path to the first * pathinfo node. * * NOTE: It is possible to get a generic.vs.non-generic path * for di_devfs_path.vs.di_path_devfs_path like: * xml: /pci@7b,0/pci1022,7458@11/pci1000,3060@2/sd@2,0 * pnode: /pci@7b,0/pci1022,7458@11/pci1000,3060@2/disk@2,0 * To resolve this issue disk_declare_path() needs to use the * special di_devfs_path_match() interface. */ pathcount = 0; pnode = NULL; while ((pnode = di_path_client_next_path(node, pnode)) != NULL) { pathcount++; } if (pathcount == 0) { if ((dnode->ddn_ppath = topo_mod_zalloc(mod, sizeof (char *))) == NULL) goto error; dnode->ddn_ppath_count = 1; if ((dnode->ddn_ppath[0] = topo_mod_strdup(mod, dnode->ddn_dpath)) == NULL) goto error; if ((dnode->ddn_target_port = topo_mod_zalloc(mod, sizeof (char *))) == NULL) goto error; if ((dnode->ddn_attached_port = topo_mod_zalloc(mod, sizeof (char *))) == NULL) goto error; if ((dnode->ddn_bridge_port = topo_mod_zalloc(mod, sizeof (char *))) == NULL) goto error; /* There should be only one target port for a devinfo node. */ if ((di_prop_lookup_strings(DDI_DEV_T_ANY, node, SCSI_ADDR_PROP_TARGET_PORT, &s)) == 1) { if ((dnode->ddn_target_port[0] = topo_mod_strdup(mod, scsi_wwnstr_skip_ua_prefix(s))) == NULL) goto error; } if ((di_prop_lookup_strings(DDI_DEV_T_ANY, node, SCSI_ADDR_PROP_ATTACHED_PORT, &s)) == 1) { /* There should be one attached port if any. */ if ((dnode->ddn_attached_port[0] = topo_mod_strdup(mod, scsi_wwnstr_skip_ua_prefix(s))) == NULL) goto error; } if ((di_prop_lookup_strings(DDI_DEV_T_ANY, node, SCSI_ADDR_PROP_BRIDGE_PORT, &s)) == 1) { /* There should be one bridge port if any. */ if ((dnode->ddn_bridge_port[0] = topo_mod_strdup(mod, scsi_wwnstr_skip_ua_prefix(s))) == NULL) goto error; } } else { /* processing a scsi_vhci device. */ if ((dnode->ddn_ppath = topo_mod_zalloc(mod, pathcount * sizeof (char *))) == NULL) goto error; dnode->ddn_ppath_count = pathcount; if ((dnode->ddn_target_port = topo_mod_zalloc(mod, pathcount * sizeof (char *))) == NULL) goto error; if ((dnode->ddn_attached_port = topo_mod_zalloc(mod, pathcount * sizeof (char *))) == NULL) goto error; if ((dnode->ddn_bridge_port = topo_mod_zalloc(mod, pathcount * sizeof (char *))) == NULL) goto error; pnode = NULL; pathcount = 0; while ((pnode = di_path_client_next_path(node, pnode)) != NULL) { if ((path = di_path_devfs_path(pnode)) == NULL) { (void) topo_mod_seterrno(mod, errno); goto error; } dnode->ddn_ppath[pathcount] = topo_mod_strdup(mod, path); di_devfs_path_free(path); if (dnode->ddn_ppath[pathcount] == NULL) goto error; if ((di_path_prop_lookup_strings(pnode, SCSI_ADDR_PROP_TARGET_PORT, &s)) == 1) { if ((dnode->ddn_target_port[pathcount] = topo_mod_strdup(mod, scsi_wwnstr_skip_ua_prefix(s))) == NULL) goto error; } if ((di_path_prop_lookup_strings(pnode, SCSI_ADDR_PROP_ATTACHED_PORT, &s)) == 1) { if ((dnode->ddn_attached_port[pathcount] = topo_mod_strdup(mod, scsi_wwnstr_skip_ua_prefix(s))) == NULL) goto error; } if ((di_path_prop_lookup_strings(pnode, SCSI_ADDR_PROP_BRIDGE_PORT, &s)) == 1) { if ((dnode->ddn_bridge_port[pathcount] = topo_mod_strdup(mod, scsi_wwnstr_skip_ua_prefix(s))) == NULL) goto error; } pathcount++; } } /* * Find the public /dev name for a disk by adding a minor name and using * di_devlink interface for reverse translation (use devinfo path). */ if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "inquiry-device-type", &inq_dtype) > 0) { dnode->ddn_dtype = *inq_dtype; itype = (*inq_dtype) & DTYPE_MASK; if (itype == DTYPE_DIRECT) { mlen = strlen(dnode->ddn_dpath) + strlen(extn) + 1; if ((minorpath = topo_mod_alloc(mod, mlen)) == NULL) goto error; (void) snprintf(minorpath, mlen, "%s%s", dnode->ddn_dpath, extn); cbp->dcb_dnode = dnode; (void) di_devlink_walk(cbp->dcb_devhdl, "^dsk/", minorpath, DI_PRIMARY_LINK, cbp, disk_devlink_callback); topo_mod_free(mod, minorpath, mlen); if (dnode->ddn_lpath == NULL) { topo_mod_dprintf(mod, "dev_di_node_add: " "failed to determine logical path"); } } } else { dnode->ddn_dtype = DTYPE_UNKNOWN; } /* cache various bits of optional information about the device. */ if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, INQUIRY_VENDOR_ID, &s) > 0) { if ((dnode->ddn_mfg = disk_trim_whitespace(mod, s)) == NULL) goto error; } if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, INQUIRY_PRODUCT_ID, &s) > 0) { if ((dnode->ddn_model = disk_trim_whitespace(mod, s)) == NULL) goto error; } if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, INQUIRY_REVISION_ID, &s) > 0) { if ((dnode->ddn_firm = disk_trim_whitespace(mod, s)) == NULL) goto error; } if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, INQUIRY_SERIAL_NO, &s) > 0) { if ((dnode->ddn_serial = disk_trim_whitespace(mod, s)) == NULL) goto error; } if (di_prop_lookup_int64(DDI_DEV_T_ANY, node, "device-nblocks", &nblocksp) > 0) { nblocks = (uint64_t)*nblocksp; /* * To save kernel memory, the driver may not define * "device-dblksize" when its value is default DEV_BSIZE. */ if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "device-dblksize", &dblksizep) > 0) dblksize = (uint_t)*dblksizep; else dblksize = DEV_BSIZE; /* default value */ (void) snprintf(lentry, sizeof (lentry), "%" PRIu64, nblocks * dblksize); if ((dnode->ddn_cap = topo_mod_strdup(mod, lentry)) == NULL) goto error; } topo_mod_dprintf(mod, "dev_di_node_add: " "adding %s\n", devid ? dnode->ddn_devid : "NULL devid"); topo_mod_dprintf(mod, " " " %s\n", dnode->ddn_dpath); for (i = 0; i < dnode->ddn_ppath_count; i++) { topo_mod_dprintf(mod, " " " %s\n", dnode->ddn_ppath[i]); } topo_list_append(cbp->dcb_list, dnode); return (0); error: dev_di_node_free(mod, dnode); return (-1); }
/* create the disk topo node */ static int disk_tnode_create(topo_mod_t *mod, tnode_t *parent, dev_di_node_t *dnode, const char *name, topo_instance_t i, tnode_t **rval) { int len; nvlist_t *fmri; tnode_t *dtn; char *part = NULL; nvlist_t *auth; char *mfg, *model, *firm, *serial; *rval = NULL; if (dnode != NULL) { mfg = topo_mod_clean_str(mod, dnode->ddn_mfg); model = topo_mod_clean_str(mod, dnode->ddn_model); firm = topo_mod_clean_str(mod, dnode->ddn_firm); serial = topo_mod_clean_str(mod, dnode->ddn_serial); } else { mfg = model = firm = serial = NULL; } /* form 'part=' of fmri as "<mfg>-<model>" */ if (mfg != NULL && model != NULL) { len = strlen(mfg) + 1 + strlen(model) + 1; if ((part = topo_mod_alloc(mod, len)) != NULL) (void) snprintf(part, len, "%s-%s", mfg, model); } auth = topo_mod_auth(mod, parent); fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION, name, i, NULL, auth, part ? part : model, firm, serial); nvlist_free(auth); topo_mod_strfree(mod, part); topo_mod_strfree(mod, mfg); topo_mod_strfree(mod, model); topo_mod_strfree(mod, firm); topo_mod_strfree(mod, serial); if (fmri == NULL) { topo_mod_dprintf(mod, "disk_tnode_create: " "hcfmri (%s%d/%s%d) error %s\n", topo_node_name(parent), topo_node_instance(parent), name, i, topo_strerror(topo_mod_errno(mod))); return (-1); } if ((dtn = topo_node_bind(mod, parent, name, i, fmri)) == NULL) { if (topo_mod_errno(mod) == EMOD_NODE_BOUND) { /* * if disk 0 is already there then we're done */ nvlist_free(fmri); return (0); } topo_mod_dprintf(mod, "disk_tnode_create: " "bind (%s%d/%s%d) error %s\n", topo_node_name(parent), topo_node_instance(parent), name, i, topo_strerror(topo_mod_errno(mod))); nvlist_free(fmri); return (-1); } nvlist_free(fmri); /* add the properties of the disk */ if (disk_set_props(mod, parent, dtn, dnode) != 0) { topo_mod_dprintf(mod, "disk_tnode_create: " "disk_set_props (%s%d/%s%d) error %s\n", topo_node_name(parent), topo_node_instance(parent), name, i, topo_strerror(topo_mod_errno(mod))); topo_node_unbind(dtn); return (-1); } if (dnode->ddn_devid != NULL && disk_add_temp_sensor(mod, dtn, dnode->ddn_devid) != 0) { topo_mod_dprintf(mod, "disk_tnode_create: failed to create " "temperature sensor node on bay=%d/disk=0", topo_node_instance(parent)); } *rval = dtn; return (0); }
/* * Query the current disk status. If successful, the disk status is returned * as an nvlist consisting of at least the following members: * * protocol string Supported protocol (currently "scsi") * * status nvlist Arbitrary protocol-specific information * about the current state of the disk. * * faults nvlist A list of supported faults. Each * element of this list is a boolean value. * An element's existence indicates that * the drive supports detecting this fault, * and the value indicates the current * state of the fault. * * <fault-name> nvlist For each fault named in 'faults', a * nvlist describing protocol-specific * attributes of the fault. * * This method relies on the libdiskstatus library to query this information. */ static int disk_status(topo_mod_t *mod, tnode_t *nodep, topo_version_t vers, nvlist_t *in_nvl, nvlist_t **out_nvl) { disk_status_t *dsp; char *devpath, *fullpath; size_t pathlen; nvlist_t *status; int err; *out_nvl = NULL; if (vers != TOPO_METH_DISK_STATUS_VERSION) return (topo_mod_seterrno(mod, EMOD_VER_NEW)); /* * If the caller specifies the "path" parameter, then this indicates * that we should use this instead of deriving it from the topo node * itself. */ if (nvlist_lookup_string(in_nvl, "path", &fullpath) == 0) { devpath = NULL; } else { /* * Get the /devices path and attempt to open the disk status * handle. */ if (topo_prop_get_string(nodep, TOPO_PGROUP_IO, TOPO_IO_DEV_PATH, &devpath, &err) != 0) return (topo_mod_seterrno(mod, EMOD_METHOD_NOTSUP)); /* * Note that sizeof(string) includes the terminating NULL byte */ pathlen = strlen(devpath) + sizeof ("/devices") + sizeof (PHYS_EXTN) - 1; if ((fullpath = topo_mod_alloc(mod, pathlen)) == NULL) return (topo_mod_seterrno(mod, EMOD_NOMEM)); (void) snprintf(fullpath, pathlen, "/devices%s%s", devpath, PHYS_EXTN); topo_mod_strfree(mod, devpath); } if ((dsp = disk_status_open(fullpath, &err)) == NULL) { if (devpath) topo_mod_free(mod, fullpath, pathlen); return (topo_mod_seterrno(mod, err == EDS_NOMEM ? EMOD_NOMEM : EMOD_METHOD_NOTSUP)); } if (devpath) topo_mod_free(mod, fullpath, pathlen); if ((status = disk_status_get(dsp)) == NULL) { err = (disk_status_errno(dsp) == EDS_NOMEM ? EMOD_NOMEM : EMOD_METHOD_NOTSUP); disk_status_close(dsp); return (topo_mod_seterrno(mod, err)); } *out_nvl = status; disk_status_close(dsp); return (0); }
static void * mb_topo_alloc(size_t size) { assert(mb_mod_hdl != NULL); return (topo_mod_alloc(mb_mod_hdl, size)); }
/* * Request the SAS address of the disk (if any) attached to this mpt_sas * instance at (Enclosure Number, Slot Number). The function returns * -1 on error and sets errno to ENOENT _only_ if the /devices node * (*devctl) does not exist. */ static int get_sas_address(topo_mod_t *mod, char *devctl, uint32_t enclosure, uint32_t slot, char **sas_address) { int ret = -1, en = ENXIO; int fd, i; mptsas_get_disk_info_t gdi; mptsas_disk_info_t *di; size_t disz; bzero(&gdi, sizeof (gdi)); if ((fd = open(devctl, O_RDWR)) == -1) { en = errno; topo_mod_dprintf(mod, "could not open '%s' for ioctl: %s\n", devctl, strerror(errno)); errno = en; return (-1); } if (ioctl(fd, MPTIOCTL_GET_DISK_INFO, &gdi) == -1) { if (errno != ENOENT) en = errno; topo_mod_dprintf(mod, "ioctl 1 on '%s' failed: %s\n", devctl, strerror(errno)); goto out; } gdi.DiskInfoArraySize = disz = sizeof (mptsas_disk_info_t) * gdi.DiskCount; gdi.PtrDiskInfoArray = di = topo_mod_alloc(mod, disz); if (di == NULL) { topo_mod_dprintf(mod, "memory allocation failed\n"); en = ENOMEM; goto out; } if (ioctl(fd, MPTIOCTL_GET_DISK_INFO, &gdi) == -1) { if (errno != ENOENT) en = errno; topo_mod_dprintf(mod, "ioctl 2 on '%s' failed: %s\n", devctl, strerror(errno)); topo_mod_free(mod, di, disz); goto out; } for (i = 0; i < gdi.DiskCount; i++) { if (di[i].Enclosure == enclosure && di[i].Slot == slot) { char sas[17]; /* 16 hex digits and NUL */ (void) snprintf(sas, 17, "%llx", di[i].SasAddress); topo_mod_dprintf(mod, "found mpt_sas disk (%d/%d) " "with adddress %s\n", enclosure, slot, sas); *sas_address = topo_mod_strdup(mod, sas); en = ret = 0; break; } } topo_mod_free(mod, di, disz); out: (void) close(fd); errno = en; return (ret); }
/*ARGSUSED*/ static int sw_fmri_nvl2str(topo_mod_t *mod, tnode_t *node, topo_version_t version, nvlist_t *nvl, nvlist_t **out) { nvlist_t *object, *site = NULL, *anvl = NULL; char *file, *func, *token; uint8_t scheme_version; char *path, *root; nvlist_t *fmristr; size_t buflen = 0; int linevalid = 0; char *buf = NULL; ssize_t size = 0; char linebuf[32]; int64_t line; int pass; int err; if (version > TOPO_METH_NVL2STR_VERSION) return (topo_mod_seterrno(mod, EMOD_VER_NEW)); if (nvlist_lookup_uint8(nvl, FM_VERSION, &scheme_version) != 0 || scheme_version > FM_SW_SCHEME_VERSION) return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); /* Get authority, if present */ err = nvlist_lookup_nvlist(nvl, FM_FMRI_AUTHORITY, &anvl); if (err != 0 && err != ENOENT) return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); /* * The 'object' nvlist is required. It must include the path, * but the root is optional. */ if (nvlist_lookup_nvlist(nvl, FM_FMRI_SW_OBJ, &object) != 0 || !lookup_string(object, FM_FMRI_SW_OBJ_PATH, &path, B_TRUE) || !lookup_string(object, FM_FMRI_SW_OBJ_ROOT, &root, B_FALSE)) return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); /* The 'site' nvlist is optional */ file = func = token = NULL; linevalid = 0; if ((err = nvlist_lookup_nvlist(nvl, FM_FMRI_SW_SITE, &site)) == 0) { /* * Prefer 'token' to file/func/line */ if (lookup_string(site, FM_FMRI_SW_SITE_TOKEN, &token, B_FALSE) <= 0) { /* * If no token then try file, func, line - but * func and line are meaningless without file. */ if (lookup_string(site, FM_FMRI_SW_SITE_FILE, &file, B_FALSE) == 1) { (void) lookup_string(site, FM_FMRI_SW_SITE_FUNC, &func, B_FALSE); if (nvlist_lookup_int64(site, FM_FMRI_SW_SITE_LINE, &line) == 0) linevalid = 1; } } } else if (err != ENOENT) { return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); } /* On the first pass buf is NULL and size and buflen are 0 */ pass = 1; again: /* * sw://[<authority>]/ * [:root=<object.root] * :path=<object.path> * [#<fragment-identifier>] * * <fragment-identifier> is one of * * :token=<site.token> * or * :file=<site.file>[:func=<site.func>][:line=<site.line>] */ /* sw:// */ topo_fmristr_build(&size, buf, buflen, FM_FMRI_SCHEME_SW, NULL, "://"); /* authority, if any */ if (anvl != NULL) { nvpair_t *apair; char *aname, *aval; for (apair = nvlist_next_nvpair(anvl, NULL); apair != NULL; apair = nvlist_next_nvpair(anvl, apair)) { if (nvpair_type(apair) != DATA_TYPE_STRING || nvpair_value_string(apair, &aval) != 0) continue; aname = nvpair_name(apair); topo_fmristr_build(&size, buf, buflen, ":", NULL, NULL); topo_fmristr_build(&size, buf, buflen, "=", aname, aval); } } /* separating slash */ topo_fmristr_build(&size, buf, buflen, "/", NULL, NULL); /* :root=... */ if (root) { topo_fmristr_build(&size, buf, buflen, root, ":" FM_FMRI_SW_OBJ_ROOT "=", NULL); } /* :path=... */ topo_fmristr_build(&size, buf, buflen, path, ":" FM_FMRI_SW_OBJ_PATH "=", NULL); if (token) { /* #:token=... */ topo_fmristr_build(&size, buf, buflen, token, "#:" FM_FMRI_SW_SITE_TOKEN "=", NULL); } else if (file) { /* #:file=... */ topo_fmristr_build(&size, buf, buflen, file, "#:" FM_FMRI_SW_SITE_FILE "=", NULL); /* :func=... */ if (func) { topo_fmristr_build(&size, buf, buflen, func, ":" FM_FMRI_SW_SITE_FUNC "=", NULL); } /* :line=... */ if (linevalid) { if (pass == 1) (void) snprintf(linebuf, sizeof (linebuf), "%lld", line); topo_fmristr_build(&size, buf, buflen, linebuf, ":" FM_FMRI_SW_SITE_LINE "=", NULL); } } if (buf == NULL) { if ((buf = topo_mod_alloc(mod, size + 1)) == NULL) return (topo_mod_seterrno(mod, EMOD_NOMEM)); buflen = size + 1; size = 0; pass = 2; goto again; } /* * Construct the nvlist to return as the result. */ if (topo_mod_nvalloc(mod, &fmristr, NV_UNIQUE_NAME) != 0) { topo_mod_strfree(mod, buf); return (topo_mod_seterrno(mod, EMOD_NOMEM)); } if (nvlist_add_string(fmristr, "fmri-string", buf) != 0) { topo_mod_strfree(mod, buf); nvlist_free(fmristr); return (topo_mod_seterrno(mod, EMOD_NOMEM)); } topo_mod_strfree(mod, buf); *out = fmristr; return (0); }
static void * xaui_topo_alloc(size_t size) { assert(xaui_mod_hdl != NULL); return (topo_mod_alloc(xaui_mod_hdl, size)); }