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); }
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); } }
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 int disk_callback_sas(di_minor_t minor, di_node_t node) { char disk[DISK_SUBPATH_MAX]; int lun64_found = 0; scsi_lun64_t lun64, sl; scsi_lun_t lun; int64_t *lun64p; uint64_t wwn; int *intp; char *tgt_port; uchar_t addr_method; /* Get lun property */ if (di_prop_lookup_int64(DDI_DEV_T_ANY, node, SCSI_ADDR_PROP_LUN64, &lun64p) > 0) { if (*lun64p != SCSI_LUN64_ILLEGAL) { lun64_found = 1; lun64 = (uint64_t)*lun64p; } } if ((!lun64_found) && (di_prop_lookup_ints(DDI_DEV_T_ANY, node, SCSI_ADDR_PROP_LUN, &intp) > 0)) { lun64 = (uint64_t)*intp; } lun = scsi_lun64_to_lun(lun64); addr_method = (lun.sl_lun1_msb & SCSI_LUN_AM_MASK); if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, SCSI_ADDR_PROP_TARGET_PORT, &tgt_port) > 0) { (void) scsi_wwnstr_to_wwn(tgt_port, &wwn); if ((addr_method == SCSI_LUN_AM_PDEV) && (lun.sl_lun2_msb == 0) && (lun.sl_lun2_lsb == 0) && (lun.sl_lun3_msb == 0) && (lun.sl_lun3_lsb == 0) && (lun.sl_lun4_msb == 0) && (lun.sl_lun4_lsb == 0)) { (void) snprintf(disk, DISK_SUBPATH_MAX, "t%"PRIX64"d%"PRId64, wwn, lun64); } else if ((addr_method == SCSI_LUN_AM_FLAT) && (lun.sl_lun2_msb == 0) && (lun.sl_lun2_lsb == 0) && (lun.sl_lun3_msb == 0) && (lun.sl_lun3_lsb == 0) && (lun.sl_lun4_msb == 0) && (lun.sl_lun4_lsb == 0)) { sl = (lun.sl_lun1_msb << 8) | lun.sl_lun1_lsb; (void) snprintf(disk, DISK_SUBPATH_MAX, "t%"PRIX64"d%"PRIX16, wwn, sl); } else { (void) snprintf(disk, DISK_SUBPATH_MAX, "t%"PRIX64"d%"PRIX64, wwn, lun64); } } else if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, SCSI_ADDR_PROP_SATA_PHY, &intp) > 0) { /* Use phy format naming, for SATA devices without wwn */ if ((addr_method == SCSI_LUN_AM_PDEV) && (lun.sl_lun2_msb == 0) && (lun.sl_lun2_lsb == 0) && (lun.sl_lun3_msb == 0) && (lun.sl_lun3_lsb == 0) && (lun.sl_lun4_msb == 0) && (lun.sl_lun4_lsb == 0)) { (void) snprintf(disk, DISK_SUBPATH_MAX, "t%dd%"PRId64, *intp, lun64); } else if ((addr_method == SCSI_LUN_AM_FLAT) && (lun.sl_lun2_msb == 0) && (lun.sl_lun2_lsb == 0) && (lun.sl_lun3_msb == 0) && (lun.sl_lun3_lsb == 0) && (lun.sl_lun4_msb == 0) && (lun.sl_lun4_lsb == 0)) { sl = (lun.sl_lun1_msb << 8) | lun.sl_lun1_lsb; (void) snprintf(disk, DISK_SUBPATH_MAX, "t%dd%"PRIX16, *intp, sl); } else { (void) snprintf(disk, DISK_SUBPATH_MAX, "t%dd%"PRIX64, *intp, lun64); } } else { return (DEVFSADM_CONTINUE); } disk_common(minor, node, disk, RM_STALE); return (DEVFSADM_CONTINUE); }