int topo_method_register(topo_mod_t *mod, tnode_t *node, const topo_method_t *mp) { topo_imethod_t *imp; const topo_method_t *meth; /* * Initialize module methods */ for (meth = &mp[0]; meth->tm_name != NULL; meth++) { topo_node_lock(node); if (topo_method_lookup(node, meth->tm_name) != NULL) { topo_node_unlock(node); continue; } if (meth->tm_stability < TOPO_STABILITY_INTERNAL || meth->tm_stability > TOPO_STABILITY_MAX || meth->tm_func == NULL) return (set_methregister_error(mod, node, NULL, ETOPO_METHOD_INVAL)); imp = topo_mod_zalloc(mod, sizeof (topo_imethod_t)); if (imp == NULL) return (set_methregister_error(mod, node, imp, ETOPO_METHOD_NOMEM)); if ((imp->tim_name = topo_mod_strdup(mod, meth->tm_name)) == NULL) return (set_methregister_error(mod, node, imp, ETOPO_METHOD_NOMEM)); if ((imp->tim_desc = topo_mod_strdup(mod, meth->tm_desc)) == NULL) return (set_methregister_error(mod, node, imp, ETOPO_METHOD_NOMEM)); imp->tim_stability = meth->tm_stability; imp->tim_version = meth->tm_version; imp->tim_func = meth->tm_func; imp->tim_mod = mod; topo_list_append(&node->tn_methods, imp); topo_node_unlock(node); topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC, "registered module %s method " "%s for %s=%d\n", mod->tm_name, imp->tim_name, topo_node_name(node), topo_node_instance(node)); } return (0); }
int topo_prop_inherit(tnode_t *node, const char *pgname, const char *name, int *err) { topo_hdl_t *thp = node->tn_hdl; tnode_t *pnode = node->tn_parent; topo_pgroup_t *pg; topo_propval_t *pv; topo_proplist_t *pvl; topo_node_lock(pnode); topo_node_lock(node); /* * Check if the requested property group and prop val are already set * on the node. */ if (propval_get(pgroup_get(node, pgname), name) != NULL) return (inherit_seterror(node, err, ETOPO_PROP_DEFD)); /* * Check if the requested property group and prop val exists on the * parent node */ if ((pv = propval_get(pgroup_get(pnode, pgname), name)) == NULL) return (inherit_seterror(node, err, ETOPO_PROP_NOENT)); /* * Can this propval be inherited? */ if (pv->tp_flag & TOPO_PROP_MUTABLE) return (inherit_seterror(node, err, ETOPO_PROP_NOINHERIT)); /* * Property group should already exist: bump the ref count for this * propval and add it to the node's property group */ if ((pg = pgroup_get(node, pgname)) == NULL) return (inherit_seterror(node, err, ETOPO_PROP_NOENT)); if ((pvl = topo_hdl_zalloc(thp, sizeof (topo_proplist_t))) == NULL) return (inherit_seterror(node, err, ETOPO_NOMEM)); topo_prop_hold(pv); pvl->tp_pval = pv; topo_list_append(&pg->tpg_pvals, pvl); topo_node_unlock(node); topo_node_unlock(pnode); return (0); }
int topo_node_range_create(topo_mod_t *mod, tnode_t *pnode, const char *name, topo_instance_t min, topo_instance_t max) { topo_nodehash_t *nhp; topo_node_lock(pnode); assert((pnode->tn_state & TOPO_NODE_BOUND) || (pnode->tn_state & TOPO_NODE_ROOT)); for (nhp = topo_list_next(&pnode->tn_children); nhp != NULL; nhp = topo_list_next(nhp)) { if (strcmp(nhp->th_name, name) == 0) return (node_create_seterror(mod, pnode, NULL, ETOPO_NODE_DUP)); } if (min < 0 || max < min) return (node_create_seterror(mod, pnode, NULL, ETOPO_NODE_INVAL)); if ((nhp = topo_mod_zalloc(mod, sizeof (topo_nodehash_t))) == NULL) return (node_create_seterror(mod, pnode, nhp, ETOPO_NOMEM)); if ((nhp->th_name = topo_mod_strdup(mod, name)) == NULL) return (node_create_seterror(mod, pnode, nhp, ETOPO_NOMEM)); nhp->th_arrlen = max - min + 1; if ((nhp->th_nodearr = topo_mod_zalloc(mod, nhp->th_arrlen * sizeof (tnode_t *))) == NULL) return (node_create_seterror(mod, pnode, nhp, ETOPO_NOMEM)); nhp->th_range.tr_min = min; nhp->th_range.tr_max = max; nhp->th_enum = mod; topo_mod_hold(mod); /* * Add these nodes to parent child list */ topo_list_append(&pnode->tn_children, nhp); topo_node_unlock(pnode); topo_dprintf(TOPO_DBG_MOD, "created node range %s[%d-%d]\n", name, min, max); return (0); }
static topo_propval_t * prop_create(tnode_t *node, const char *pgname, const char *pname, topo_type_t type, int flag, int *err) { topo_hdl_t *thp = node->tn_hdl; topo_pgroup_t *pg; topo_propval_t *pv; topo_proplist_t *pvl; /* * Replace existing prop value with new one */ if ((pg = pgroup_get(node, pgname)) == NULL) { topo_node_unlock(node); *err = ETOPO_PROP_NOENT; return (NULL); } if ((pv = propval_get(pg, pname)) != NULL) { if (pv->tp_type != type) return (set_seterror(node, NULL, err, ETOPO_PROP_TYPE)); else if (! (pv->tp_flag & TOPO_PROP_MUTABLE)) return (set_seterror(node, NULL, err, ETOPO_PROP_DEFD)); nvlist_free(pv->tp_val); pv->tp_val = NULL; } else { if ((pvl = topo_hdl_zalloc(thp, sizeof (topo_proplist_t))) == NULL) return (set_seterror(node, NULL, err, ETOPO_NOMEM)); if ((pv = topo_hdl_zalloc(thp, sizeof (topo_propval_t))) == NULL) return (set_seterror(node, pvl, err, ETOPO_NOMEM)); pv->tp_hdl = thp; pvl->tp_pval = pv; if ((pv->tp_name = topo_hdl_strdup(thp, pname)) == NULL) return (set_seterror(node, pvl, err, ETOPO_NOMEM)); pv->tp_flag = flag; pv->tp_type = type; topo_prop_hold(pv); topo_list_append(&pg->tpg_pvals, pvl); } return (pv); }
int topo_pgroup_create(tnode_t *node, const topo_pgroup_info_t *pinfo, int *err) { topo_pgroup_t *pg; topo_ipgroup_info_t *pip; topo_hdl_t *thp = node->tn_hdl; *err = 0; topo_node_lock(node); /* * Check for an existing pgroup */ for (pg = topo_list_next(&node->tn_pgroups); pg != NULL; pg = topo_list_next(pg)) { if (strcmp(pg->tpg_info->tpi_name, pinfo->tpi_name) == 0) { *err = ETOPO_PROP_DEFD; topo_node_unlock(node); return (-1); } } if ((pg = topo_hdl_zalloc(thp, sizeof (topo_pgroup_t))) == NULL) { *err = ETOPO_NOMEM; topo_node_unlock(node); return (-1); } if ((pip = topo_hdl_zalloc(thp, sizeof (topo_ipgroup_info_t))) == NULL) return (pgroup_seterr(node, pg, pip, err)); if ((pip->tpi_name = topo_hdl_strdup(thp, pinfo->tpi_name)) == NULL) return (pgroup_seterr(node, pg, pip, err)); pip->tpi_namestab = pinfo->tpi_namestab; pip->tpi_datastab = pinfo->tpi_datastab; pip->tpi_version = pinfo->tpi_version; pg->tpg_info = pip; topo_list_append(&node->tn_pgroups, pg); topo_node_unlock(node); return (0); }
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); }