#include <devfsadm.h>
#include <stdio.h>
#include <strings.h>
#include <stdlib.h>
#include <stdarg.h>
#include <limits.h>
#include <unistd.h>
#include <config_admin.h>
#include <cfg_link.h>
#include <sys/types.h>
#include <sys/mkdev.h>
#include <sys/hotplug/pci/pcihp.h>
#ifdef DEBUG
#define dprint(args) devfsadm_errprint args
#define DRVINST(node) di_driver_name(node), di_instance(node)
#else
#define dprint(args)
#endif
static int scsi_cfg_creat_cb(di_minor_t minor, di_node_t node);
static int sbd_cfg_creat_cb(di_minor_t minor, di_node_t node);
static int usb_cfg_creat_cb(di_minor_t minor, di_node_t node);
static char *get_roothub(const char *path, void *cb_arg);
static int pci_cfg_creat_cb(di_minor_t minor, di_node_t node);
static int ib_cfg_creat_cb(di_minor_t minor, di_node_t node);
static int sata_cfg_creat_cb(di_minor_t minor, di_node_t node);
static int sdcard_cfg_creat_cb(di_minor_t minor, di_node_t node);
static int ccid_cfg_creat_cb(di_minor_t minor, di_node_t node);
static di_node_t pci_cfg_chassis_node(di_node_t, di_prom_handle_t);
static char *pci_cfg_slotname(di_node_t, di_prom_handle_t, minor_t);
static int pci_cfg_ap_node(minor_t, di_node_t, di_prom_handle_t,
char *, int, int);
static int pci_cfg_iob_name(di_minor_t, di_node_t, di_prom_handle_t,
char *, int);
static minor_t pci_cfg_pcidev(di_node_t, di_prom_handle_t);
static int pci_cfg_ap_path(di_minor_t, di_node_t, di_prom_handle_t,
char *, int, char **);
static char *pci_cfg_info_data(char *);
static int pci_cfg_is_ap_path(di_node_t, di_prom_handle_t);
static int pci_cfg_ap_legacy(di_minor_t, di_node_t, di_prom_handle_t,
char *, int);
static void pci_cfg_rm_invalid_links(char *, char *);
static void pci_cfg_rm_link(char *);
static void pci_cfg_rm_all(char *);
static char *pci_cfg_devpath(di_node_t, di_minor_t);
static di_node_t pci_cfg_snapshot(di_node_t, di_minor_t,
di_node_t *, di_minor_t *);
#define DIPROP_PRI_NODE 0x0
#define DIPROP_PRI_PROM 0x1
static int di_propall_lookup_ints(di_prom_handle_t, int,
dev_t, di_node_t, const char *, int **);
static int di_propall_lookup_strings(di_prom_handle_t, int,
dev_t, di_node_t, const char *, char **);
static int serid_printable(uint64_t *seridp);
static int di_propall_lookup_slot_names(di_prom_handle_t, int,
dev_t, di_node_t, di_slot_name_t **);
static devfsadm_create_t cfg_create_cbt[] = {
{ "attachment-point", DDI_NT_SCSI_ATTACHMENT_POINT, NULL,
TYPE_EXACT | CREATE_DEFER, ILEVEL_0, scsi_cfg_creat_cb
},
{ "attachment-point", DDI_NT_SBD_ATTACHMENT_POINT, NULL,
TYPE_EXACT, ILEVEL_0, sbd_cfg_creat_cb
},
{ "fc-attachment-point", DDI_NT_FC_ATTACHMENT_POINT, NULL,
TYPE_EXACT | CREATE_DEFER, ILEVEL_0, scsi_cfg_creat_cb
},
{ "attachment-point", DDI_NT_USB_ATTACHMENT_POINT, NULL,
TYPE_EXACT, ILEVEL_0, usb_cfg_creat_cb
},
{ "attachment-point", DDI_NT_PCI_ATTACHMENT_POINT, NULL,
TYPE_EXACT, ILEVEL_0, pci_cfg_creat_cb
},
{ "attachment-point", DDI_NT_IB_ATTACHMENT_POINT, NULL,
TYPE_EXACT, ILEVEL_0, ib_cfg_creat_cb
},
{ "attachment-point", DDI_NT_SATA_ATTACHMENT_POINT, NULL,
TYPE_EXACT, ILEVEL_0, sata_cfg_creat_cb
},
{ "attachment-point", DDI_NT_SDCARD_ATTACHMENT_POINT, NULL,
TYPE_EXACT, ILEVEL_0, sdcard_cfg_creat_cb
},
{ "attachment-point", DDI_NT_CCID_ATTACHMENT_POINT, NULL,
TYPE_EXACT, ILEVEL_0, ccid_cfg_creat_cb
}
};
DEVFSADM_CREATE_INIT_V0(cfg_create_cbt);
static devfsadm_remove_t cfg_remove_cbt[] = {
{ "attachment-point", SCSI_CFG_LINK_RE, RM_POST,
ILEVEL_0, devfsadm_rm_all
},
{ "attachment-point", SBD_CFG_LINK_RE, RM_POST,
ILEVEL_0, devfsadm_rm_all
},
{ "fc-attachment-point", SCSI_CFG_LINK_RE, RM_POST,
ILEVEL_0, devfsadm_rm_all
},
{ "attachment-point", USB_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS,
ILEVEL_0, devfsadm_rm_all
},
{ "attachment-point", PCI_CFG_LINK_RE, RM_POST,
ILEVEL_0, devfsadm_rm_all
},
{ "attachment-point", PCI_CFG_PATH_LINK_RE, RM_POST|RM_HOT,
ILEVEL_0, pci_cfg_rm_all
},
{ "attachment-point", IB_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS,
ILEVEL_0, devfsadm_rm_all
},
{ "attachment-point", SATA_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS,
ILEVEL_0, devfsadm_rm_all
},
{ "attachment-point", SDCARD_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS,
ILEVEL_0, devfsadm_rm_all
},
{ "attachment-point", CCID_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS,
ILEVEL_0, devfsadm_rm_all
}
};
DEVFSADM_REMOVE_INIT_V0(cfg_remove_cbt);
static int
scsi_cfg_creat_cb(di_minor_t minor, di_node_t node)
{
char path[PATH_MAX + 1];
char *c_num = NULL, *devfs_path, *mn;
devfsadm_enumerate_t rules[3] = {
{"^r?dsk$/^c([0-9]+)", 1, MATCH_PARENT},
{"^cfg$/^c([0-9]+)$", 1, MATCH_ADDR},
{"^scsi$/^.+$/^c([0-9]+)", 1, MATCH_PARENT}
};
mn = di_minor_name(minor);
if ((devfs_path = di_devfs_path(node)) == NULL) {
return (DEVFSADM_CONTINUE);
}
(void) strcpy(path, devfs_path);
(void) strcat(path, ":");
(void) strcat(path, mn);
di_devfs_path_free(devfs_path);
if (ctrl_enumerate_int(path, 1, &c_num, rules, 3, 0, B_FALSE)
== DEVFSADM_FAILURE) {
return (DEVFSADM_CONTINUE);
}
(void) strcpy(path, CFG_DIRNAME);
(void) strcat(path, "/c");
(void) strcat(path, c_num);
free(c_num);
(void) devfsadm_mklink(path, node, minor, 0);
return (DEVFSADM_CONTINUE);
}
static int
sbd_cfg_creat_cb(di_minor_t minor, di_node_t node)
{
char path[PATH_MAX + 1];
(void) strcpy(path, CFG_DIRNAME);
(void) strcat(path, "/");
(void) strcat(path, di_minor_name(minor));
(void) devfsadm_mklink(path, node, minor, 0);
return (DEVFSADM_CONTINUE);
}
static int
usb_cfg_creat_cb(di_minor_t minor, di_node_t node)
{
char *cp, path[PATH_MAX + 1];
devfsadm_enumerate_t rules[1] =
{"^cfg$/^usb([0-9]+)$", 1, MATCH_CALLBACK, NULL, get_roothub};
if ((cp = di_devfs_path(node)) == NULL) {
return (DEVFSADM_CONTINUE);
}
(void) snprintf(path, sizeof (path), "%s:%s", cp, di_minor_name(minor));
di_devfs_path_free(cp);
if (ctrl_enumerate_int(path, 0, &cp, rules, 1, 0, B_FALSE)) {
return (DEVFSADM_CONTINUE);
}
(void) snprintf(path, sizeof (path), "%s/usb%s/%s", CFG_DIRNAME, cp,
di_minor_name(minor));
free(cp);
(void) devfsadm_mklink(path, node, minor, 0);
return (DEVFSADM_CONTINUE);
}
static int
sata_cfg_creat_cb(di_minor_t minor, di_node_t node)
{
char path[PATH_MAX + 1], l_path[PATH_MAX], *buf, *devfspath;
char *minor_nm;
devfsadm_enumerate_t rules[1] =
{"^cfg$/^sata([0-9]+)$", 1, MATCH_ADDR};
minor_nm = di_minor_name(minor);
if (minor_nm == NULL)
return (DEVFSADM_CONTINUE);
devfspath = di_devfs_path(node);
if (devfspath == NULL)
return (DEVFSADM_CONTINUE);
(void) strlcpy(path, devfspath, sizeof (path));
(void) strlcat(path, ":", sizeof (path));
(void) strlcat(path, minor_nm, sizeof (path));
di_devfs_path_free(devfspath);
if (ctrl_enumerate_int(path, 0, &buf, rules, 1, 0, B_FALSE) ==
DEVFSADM_FAILURE) {
return (DEVFSADM_CONTINUE);
}
(void) snprintf(l_path, sizeof (l_path), "%s/sata%s/%s", CFG_DIRNAME,
buf, minor_nm);
free(buf);
(void) devfsadm_mklink(l_path, node, minor, 0);
return (DEVFSADM_CONTINUE);
}
static int
sdcard_cfg_creat_cb(di_minor_t minor, di_node_t node)
{
char path[PATH_MAX +1], l_path[PATH_MAX], *buf, *devfspath;
char *minor_nm;
devfsadm_enumerate_t rules[1] =
{"^cfg$/^sdcard([0-9]+)$", 1, MATCH_ADDR};
minor_nm = di_minor_name(minor);
if (minor_nm == NULL)
return (DEVFSADM_CONTINUE);
devfspath = di_devfs_path(node);
if (devfspath == NULL)
return (DEVFSADM_CONTINUE);
(void) snprintf(path, sizeof (path), "%s:%s", devfspath, minor_nm);
di_devfs_path_free(devfspath);
if (ctrl_enumerate_int(path, 0, &buf, rules, 1, 0, B_FALSE) ==
DEVFSADM_FAILURE) {
return (DEVFSADM_CONTINUE);
}
(void) snprintf(l_path, sizeof (l_path), "%s/sdcard%s/%s",
CFG_DIRNAME, buf, minor_nm);
free(buf);
(void) devfsadm_mklink(l_path, node, minor, 0);
return (DEVFSADM_CONTINUE);
}
static char *
get_roothub(const char *path, void *cb_arg)
{
int i, count = 0;
char *physpath, *cp;
if ((physpath = strdup(path)) == NULL) {
return (NULL);
}
if ((cp = strrchr(physpath, ':')) == NULL) {
free(physpath);
return (NULL);
}
*cp++ = '\0';
if (strchr(cp, '.') == NULL) {
return (physpath);
}
while (*cp) {
if (*cp == '.')
count++;
cp++;
}
for (i = 0; i < count; i++) {
if ((cp = strrchr(physpath, '/')) == NULL || (cp == physpath)) {
free(physpath);
return (NULL);
}
if (strstr(cp, "miscellaneous") != NULL) {
count++;
}
*cp = '\0';
}
if ((cp = strrchr(physpath, '/')) != NULL && (cp != physpath)) {
if (strstr(cp, "miscellaneous") != NULL) {
*cp = '\0';
}
}
return (physpath);
}
static char *
pci_cfg_devpath(di_node_t node, di_minor_t minor)
{
char *path;
char *bufp;
char *minor_nm;
int buflen;
path = di_devfs_path(node);
minor_nm = di_minor_name(minor);
buflen = snprintf(NULL, 0, "%s:%s", path, minor_nm) + 1;
bufp = malloc(sizeof (char) * buflen);
if (bufp != NULL)
(void) snprintf(bufp, buflen, "%s:%s", path, minor_nm);
di_devfs_path_free(path);
return (bufp);
}
static int
di_propall_lookup_ints(di_prom_handle_t ph, int flags,
dev_t dev, di_node_t node, const char *prop_name, int **prop_data)
{
int rv;
if (flags & DIPROP_PRI_PROM) {
rv = di_prom_prop_lookup_ints(ph, node, prop_name, prop_data);
if (rv < 0)
rv = di_prop_lookup_ints(dev, node, prop_name,
prop_data);
} else {
rv = di_prop_lookup_ints(dev, node, prop_name, prop_data);
if (rv < 0)
rv = di_prom_prop_lookup_ints(ph, node, prop_name,
prop_data);
}
return (rv);
}
static int
di_propall_lookup_strings(di_prom_handle_t ph, int flags,
dev_t dev, di_node_t node, const char *prop_name, char **prop_data)
{
int rv;
if (flags & DIPROP_PRI_PROM) {
rv = di_prom_prop_lookup_strings(ph, node, prop_name,
prop_data);
if (rv < 0)
rv = di_prop_lookup_strings(dev, node, prop_name,
prop_data);
} else {
rv = di_prop_lookup_strings(dev, node, prop_name, prop_data);
if (rv < 0)
rv = di_prom_prop_lookup_strings(ph, node, prop_name,
prop_data);
}
return (rv);
}
static di_node_t
pci_cfg_chassis_node(di_node_t node, di_prom_handle_t ph)
{
di_node_t curnode = node;
int *firstchas;
do {
if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, curnode,
DI_PROP_FIRST_CHAS, &firstchas) >= 0)
return (curnode);
} while ((curnode = di_parent_node(curnode)) != DI_NODE_NIL);
return (DI_NODE_NIL);
}
static int
di_propall_lookup_slot_names(di_prom_handle_t ph, int flags,
dev_t dev, di_node_t node, di_slot_name_t **prop_data)
{
int rv;
if (flags & DIPROP_PRI_PROM) {
rv = di_prom_prop_lookup_slot_names(ph, node, prop_data);
if (rv < 0)
rv = di_prop_lookup_slot_names(dev, node, prop_data);
} else {
rv = di_prop_lookup_slot_names(dev, node, prop_data);
if (rv < 0)
rv = di_prom_prop_lookup_slot_names(ph, node,
prop_data);
}
return (rv);
}
static char *
pci_cfg_slotname(di_node_t node, di_prom_handle_t ph, minor_t pci_dev)
{
#ifdef DEBUG
char *fnm = "pci_cfg_slotname";
#endif
int i, count;
char *name = NULL;
di_slot_name_t *slot_names = NULL;
count = di_propall_lookup_slot_names(ph, 0, DDI_DEV_T_ANY, node,
&slot_names);
if (count < 0)
return (NULL);
for (i = 0; i < count; i++) {
if (slot_names[i].num == (int)pci_dev) {
name = strdup(slot_names[i].name);
break;
}
}
#ifdef DEBUG
if (name == NULL)
dprint(("%s: slot w/ pci_dev %d not found in %s for %s%d\n",
fnm, (int)pci_dev, DI_PROP_SLOT_NAMES, DRVINST(node)));
#endif
if (count > 0)
di_slot_names_free(count, slot_names);
return (name);
}
static int
pci_cfg_ap_node(minor_t pci_dev, di_node_t node, di_prom_handle_t ph,
char *buf, int bufsz, int flags)
{
int *nump;
int rv;
char *str, *devtype;
rv = di_propall_lookup_strings(ph, 0, DDI_DEV_T_ANY, node,
DI_PROP_DEV_TYPE, &devtype);
if (rv < 1)
return (0);
if (strcmp(devtype, PROPVAL_PCIEX) == 0)
devtype = DEVTYPE_PCIE;
if (flags & APNODE_DEFNAME)
goto DEF;
str = pci_cfg_slotname(node, ph, pci_dev);
if (str != NULL) {
(void) strlcpy(buf, str, bufsz);
free(str);
return (1);
}
if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node,
DI_PROP_PHYS_SLOT, &nump) > 0) {
if (*nump > 0) {
(void) snprintf(buf, bufsz, "%s%d", devtype, *nump);
return (1);
}
}
DEF:
(void) snprintf(buf, bufsz, "%s%d.%s%d",
di_driver_name(node), di_instance(node), devtype, pci_dev);
return (1);
}
static int
pci_cfg_iob_name(di_minor_t minor, di_node_t node, di_prom_handle_t ph,
char *buf, int bufsz)
{
int64_t *seridp;
uint64_t serid;
char *idstr;
if (di_prop_lookup_int64(DDI_DEV_T_ANY, node, DI_PROP_SERID,
&seridp) < 1) {
(void) strlcpy(buf, IOB_PRE, bufsz);
return (1);
}
serid = (uint64_t)*seridp;
if ((serid >> 40) != (uint64_t)IEEE_SUN_ID ||
!serid_printable(&serid)) {
(void) snprintf(buf, bufsz, "%s%llx", IOB_PRE, serid);
return (1);
}
serid <<= 24;
idstr = (char *)&serid;
idstr[sizeof (serid) -1] = '\0';
(void) snprintf(buf, bufsz, "%s%s", IOB_PRE, idstr);
return (1);
}
static minor_t
pci_cfg_pcidev(di_node_t node, di_prom_handle_t ph)
{
int rv;
int *regp;
rv = di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node, DI_PROP_REG,
®p);
if (rv < 1) {
dprint(("pci_cfg_pcidev: property %s not found "
"for %s%d\n", DI_PROP_REG, DRVINST(node)));
return (PCIDEV_NIL);
}
return (REG_PCIDEV(regp));
}
static int
pci_cfg_ap_path(di_minor_t minor, di_node_t node, di_prom_handle_t ph,
char *ap_path, int ap_pathsz, char **pathret)
{
#ifdef DEBUG
char *fnm = "pci_cfg_ap_path";
#endif
#define seplen (sizeof (AP_PATH_SEP) - 1)
#define iob_pre_len (sizeof (IOB_PRE) - 1)
#define ap_path_iob_sep_len (sizeof (AP_PATH_IOB_SEP) - 1)
char *bufptr;
char buf[MAXPATHLEN];
char pathbuf[MAXPATHLEN];
int bufsz;
char *pathptr;
char *pathend = NULL;
int len;
int rv = 0;
int chasflag = 0;
di_node_t curnode = node;
di_node_t chasnode = DI_NODE_NIL;
minor_t pci_dev;
buf[0] = '\0';
pathbuf[0] = '\0';
pathptr = &pathbuf[sizeof (pathbuf) - 1];
*pathptr = '\0';
pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(di_minor_devt(minor));
do {
bufptr = buf;
bufsz = sizeof (buf);
chasnode = pci_cfg_chassis_node(curnode, ph);
if (chasnode != DI_NODE_NIL) {
rv = pci_cfg_iob_name(minor, chasnode, ph,
bufptr, bufsz);
if (rv == 0) {
dprint(("%s: cannot create iob name "
"for %s%d\n", fnm, DRVINST(node)));
*pathptr = '\0';
goto OUT;
}
(void) strncat(bufptr, AP_PATH_IOB_SEP, bufsz);
len = strlen(bufptr);
bufptr += len;
bufsz -= len - 1;
if (curnode == node)
chasflag = 1;
}
rv = pci_cfg_ap_node(pci_dev, curnode, ph, bufptr, bufsz, 0);
if (rv == 0) {
dprint(("%s: cannot create ap node name "
"for %s%d\n", fnm, DRVINST(node)));
*pathptr = '\0';
goto OUT;
}
if (curnode != node) {
pathptr -= seplen;
if (pathptr < pathbuf) {
pathptr = pathbuf;
*pathptr = '\0';
goto DEF;
}
(void) memcpy(pathptr, AP_PATH_SEP, seplen);
}
len = strlen(buf);
pathptr -= len;
if (pathptr < pathbuf) {
pathptr = pathbuf;
*pathptr = '\0';
goto DEF;
}
(void) memcpy(pathptr, buf, len);
if (curnode == node)
pathend = pathptr;
if (chasnode == DI_NODE_NIL)
break;
curnode = chasnode;
pci_dev = pci_cfg_pcidev(curnode, ph);
if (pci_dev == PCIDEV_NIL) {
dprint(("%s: cannot obtain pci device number "
"for %s%d\n", fnm, DRVINST(node)));
*pathptr = '\0';
goto OUT;
}
} while ((curnode = di_parent_node(curnode)) != DI_NODE_NIL);
pathbuf[sizeof (pathbuf) - 1] = '\0';
if (strlen(pathptr) < ap_pathsz) {
(void) strlcpy(ap_path, pathptr, ap_pathsz);
rv = 1;
goto OUT;
}
DEF:
if (chasflag && pathend != NULL) {
if ((strncmp(pathend + iob_pre_len, AP_PATH_IOB_SEP,
ap_path_iob_sep_len) != 0) &&
(strlen(pathend) < ap_pathsz)) {
(void) strlcpy(ap_path, pathend, ap_pathsz);
rv = 1;
goto OUT;
}
}
pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(di_minor_devt(minor));
rv = pci_cfg_ap_node(pci_dev, node, ph, buf, bufsz, APNODE_DEFNAME);
if (rv == 0) {
dprint(("%s: cannot create default ap node name for %s%d\n",
fnm, DRVINST(node)));
*pathptr = '\0';
goto OUT;
}
if (strlen(buf) < ap_pathsz) {
(void) strlcpy(ap_path, buf, ap_pathsz);
rv = 1;
goto OUT;
}
rv = 0;
dprint(("%s: cannot create apid for %s%d within length of %d\n",
fnm, DRVINST(node), ap_pathsz));
OUT:
ap_path[ap_pathsz - 1] = '\0';
*pathret = (*pathptr == '\0') ? NULL : strdup(pathptr);
return (rv);
#undef seplen
#undef iob_pre_len
#undef ap_path_iob_sep_len
}
static int
pci_cfg_ap_legacy(di_minor_t minor, di_node_t node, di_prom_handle_t ph,
char *ap_path, int ap_pathsz)
{
minor_t pci_dev;
int *anp;
if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node, DI_PROP_AP_NAMES,
&anp) < 1)
return (0);
pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(di_minor_devt(minor));
if ((*anp & (1 << pci_dev)) == 0)
return (0);
(void) strlcpy(ap_path, di_minor_name(minor), ap_pathsz);
return (1);
}
static int
pci_cfg_is_ap_path(di_node_t node, di_prom_handle_t ph)
{
char *devtype;
di_node_t curnode = node;
do {
if (di_propall_lookup_strings(ph, 0, DDI_DEV_T_ANY, curnode,
DI_PROP_DEV_TYPE, &devtype) > 0)
if (strcmp(devtype, PROPVAL_PCIEX) == 0)
return (1);
} while ((curnode = di_parent_node(curnode)) != DI_NODE_NIL);
return (0);
}
static char *
pci_cfg_info_data(char *path)
{
#define head "Location: "
#define headlen (sizeof (head) - 1)
#define seplen (sizeof (AP_PATH_SEP) - 1)
char *sep, *prev, *np;
char *newpath;
int pathlen = strlen(path);
int len;
newpath = malloc(sizeof (char) * (headlen + pathlen + 1));
np = newpath;
(void) strcpy(np, head);
np += headlen;
prev = path;
while ((sep = strstr(prev, AP_PATH_SEP)) != NULL) {
len = sep - prev;
(void) memcpy(np, prev, len);
np += len;
*np++ = '/';
prev = sep + seplen;
}
(void) strcpy(np, prev);
return (newpath);
#undef head
#undef headlen
#undef seplen
}
static void
pci_cfg_rm_link(char *file)
{
char *dlipath;
dlipath = di_dli_name(file);
(void) unlink(dlipath);
devfsadm_rm_all(file);
free(dlipath);
}
static void
pci_cfg_rm_invalid_links(char *physpath, char *valid)
{
char **dnp;
char *cp, *vcp;
int i, dnlen;
dnp = devfsadm_lookup_dev_names(physpath, NULL, &dnlen);
if (dnp == NULL)
return;
if (valid != NULL) {
if (strncmp(valid, DEV "/", DEV_LEN + 1) == 0)
vcp = valid + DEV_LEN + 1;
else
vcp = valid;
}
for (i = 0; i < dnlen; i++) {
if (strncmp(dnp[i], DEV "/", DEV_LEN + 1) == 0)
cp = dnp[i] + DEV_LEN + 1;
else
cp = dnp[i];
if (valid != NULL) {
if (strcmp(vcp, cp) == 0)
continue;
}
pci_cfg_rm_link(cp);
}
devfsadm_free_dev_names(dnp, dnlen);
}
static di_node_t
pci_cfg_snapshot(di_node_t pci_node, di_minor_t pci_minor,
di_node_t *ret_node, di_minor_t *ret_minor)
{
di_node_t root_node;
di_node_t node;
di_minor_t minor;
int pci_inst;
dev_t pci_devt;
*ret_node = DI_NODE_NIL;
*ret_minor = DI_MINOR_NIL;
root_node = di_init("/", DINFOCPYALL);
if (root_node == DI_NODE_NIL)
return (DI_NODE_NIL);
if (pci_node == DI_NODE_NIL)
return (root_node);
pci_inst = di_instance(pci_node);
node = di_drv_first_node(di_driver_name(pci_node), root_node);
do {
if (pci_inst == di_instance(node)) {
*ret_node = node;
break;
}
} while ((node = di_drv_next_node(node)) != DI_NODE_NIL);
if (node == DI_NODE_NIL)
return (root_node);
if (pci_minor == DI_MINOR_NIL)
return (root_node);
pci_devt = di_minor_devt(pci_minor);
minor = DI_MINOR_NIL;
while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
if (pci_devt == di_minor_devt(minor)) {
*ret_minor = minor;
break;
}
}
return (root_node);
}
static int
pci_cfg_creat_cb(di_minor_t pci_minor, di_node_t pci_node)
{
#ifdef DEBUG
char *fnm = "pci_cfg_creat_cb";
#endif
#define ap_pathsz (sizeof (ap_path))
char ap_path[CFGA_LOG_EXT_LEN];
char linkbuf[MAXPATHLEN];
char *fullpath = NULL;
char *pathinfo = NULL;
char *devpath = NULL;
int rv, fd = -1;
size_t sz;
di_prom_handle_t ph;
di_node_t node;
di_node_t root_node = DI_NODE_NIL;
di_minor_t minor;
ph = di_prom_init();
if (ph == DI_PROM_HANDLE_NIL) {
dprint(("%s: di_prom_init() failed for %s%d\n",
fnm, DRVINST(pci_node)));
goto OUT;
}
root_node = pci_cfg_snapshot(pci_node, pci_minor, &node, &minor);
if (root_node == DI_NODE_NIL || node == DI_NODE_NIL ||
minor == DI_MINOR_NIL) {
dprint(("%s: devinfo snapshot or search failed for %s%d\n",
fnm, DRVINST(pci_node)));
goto OUT;
}
if (pci_cfg_is_ap_path(node, ph)) {
rv = pci_cfg_ap_path(minor, node, ph, ap_path, ap_pathsz,
&fullpath);
if (rv == 0)
goto OUT;
(void) snprintf(linkbuf, sizeof (linkbuf), "%s/%s",
CFG_DIRNAME, ap_path);
devpath = pci_cfg_devpath(node, minor);
if (devpath == NULL)
goto OUT;
pci_cfg_rm_invalid_links(devpath, linkbuf);
free(devpath);
(void) devfsadm_mklink(linkbuf, node, minor, 0);
pathinfo = pci_cfg_info_data(fullpath);
fd = di_dli_openw(linkbuf);
if (fd < 0)
goto OUT;
sz = strlen(pathinfo) + 1;
rv = write(fd, pathinfo, sz);
if (rv < sz) {
dprint(("%s: could not write full pathinfo to dli "
"file for %s%d\n", fnm, DRVINST(node)));
goto OUT;
}
di_dli_close(fd);
} else {
rv = pci_cfg_ap_legacy(minor, node, ph, ap_path,
ap_pathsz);
if (rv == 0)
goto OUT;
(void) snprintf(linkbuf, sizeof (linkbuf), "%s/%s",
CFG_DIRNAME, ap_path);
(void) devfsadm_mklink(linkbuf, node, minor, 0);
}
OUT:
if (fd >= 0)
di_dli_close(fd);
if (fullpath != NULL)
free(fullpath);
if (pathinfo != NULL)
free(pathinfo);
if (ph != DI_PROM_HANDLE_NIL)
di_prom_fini(ph);
if (root_node != DI_NODE_NIL)
di_fini(root_node);
return (DEVFSADM_CONTINUE);
#undef ap_pathsz
}
static void
pci_cfg_rm_all(char *file)
{
pci_cfg_rm_link(file);
}
static int
ib_cfg_creat_cb(di_minor_t minor, di_node_t node)
{
char *cp;
char path[PATH_MAX + 1];
if ((cp = di_devfs_path(node)) == NULL) {
return (DEVFSADM_CONTINUE);
}
(void) snprintf(path, sizeof (path), "%s:%s", cp, di_minor_name(minor));
di_devfs_path_free(cp);
if (strstr(path, "ib:fabric") != NULL) {
(void) snprintf(path, sizeof (path), "%s/ib", CFG_DIRNAME);
} else {
(void) snprintf(path, sizeof (path), "%s/hca:%s", CFG_DIRNAME,
di_minor_name(minor));
}
(void) devfsadm_mklink(path, node, minor, 0);
return (DEVFSADM_CONTINUE);
}
static int
serid_printable(uint64_t *seridp)
{
char *ptr;
int i = 0;
for (ptr = (char *)seridp+3; i < 5; ptr++, i++)
if (*ptr < 0x21 || *ptr >= 0x7f)
return (0);
return (1);
}
static int
ccid_cfg_creat_cb(di_minor_t minor, di_node_t node)
{
const char *minor_nm;
char cfg_path[MAXPATHLEN];
if ((minor_nm = di_minor_name(minor)) == NULL) {
return (DEVFSADM_CONTINUE);
}
(void) snprintf(cfg_path, sizeof (cfg_path), "%s/ccid%d/%s",
CFG_DIRNAME, di_instance(node), minor_nm);
(void) devfsadm_mklink(cfg_path, node, minor, 0);
return (DEVFSADM_CONTINUE);
}