14bac2208Snarayan /* 24bac2208Snarayan * CDDL HEADER START 34bac2208Snarayan * 44bac2208Snarayan * The contents of this file are subject to the terms of the 54bac2208Snarayan * Common Development and Distribution License (the "License"). 64bac2208Snarayan * You may not use this file except in compliance with the License. 74bac2208Snarayan * 84bac2208Snarayan * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 94bac2208Snarayan * or http://www.opensolaris.org/os/licensing. 104bac2208Snarayan * See the License for the specific language governing permissions 114bac2208Snarayan * and limitations under the License. 124bac2208Snarayan * 134bac2208Snarayan * When distributing Covered Code, include this CDDL HEADER in each 144bac2208Snarayan * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 154bac2208Snarayan * If applicable, add the following below this CDDL HEADER, with the 164bac2208Snarayan * fields enclosed by brackets "[]" replaced with your own identifying 174bac2208Snarayan * information: Portions Copyright [yyyy] [name of copyright owner] 184bac2208Snarayan * 194bac2208Snarayan * CDDL HEADER END 204bac2208Snarayan */ 214bac2208Snarayan /* 22*94048829Sranenc * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 234bac2208Snarayan * Use is subject to license terms. 244bac2208Snarayan */ 254bac2208Snarayan 264bac2208Snarayan /* 274bac2208Snarayan * Implements auxiliary routines declared in pcp_utils.h to facilitate 284bac2208Snarayan * finding the appropriate communication transport & device path for a 294bac2208Snarayan * given service. This supports the transition from the legacy service channel 304bac2208Snarayan * transport (glvc) to the logical domain channel (vldc) transport native 314bac2208Snarayan * to platforms running Logical Domains (LDoms). 324bac2208Snarayan */ 334bac2208Snarayan 344bac2208Snarayan #pragma ident "%Z%%M% %I% %E% SMI" 354bac2208Snarayan 364bac2208Snarayan #include <fcntl.h> 374bac2208Snarayan #include <sys/types.h> 384bac2208Snarayan #include <sys/stat.h> 394bac2208Snarayan #include <strings.h> 404bac2208Snarayan #include <stdlib.h> 414bac2208Snarayan #include <libgen.h> 424bac2208Snarayan #include <unistd.h> 434bac2208Snarayan #include <stdio.h> 444bac2208Snarayan #include <libdevinfo.h> 454bac2208Snarayan 464bac2208Snarayan #include "pcp_utils.h" 474bac2208Snarayan 484bac2208Snarayan typedef enum { false = 0, true = 1 } bool_t; 494bac2208Snarayan 504bac2208Snarayan #define SERVICE_PREFIX "SUNW,sun4v-" 514bac2208Snarayan #define DEVICES_DIR "/devices" 524bac2208Snarayan #define GLVC ":glvc" 534bac2208Snarayan #define VCHAN "virtual-channel@" 544bac2208Snarayan #define VCHAN_C "virtual-channel-client@" 554bac2208Snarayan 564bac2208Snarayan /* 574bac2208Snarayan * The mechanism to relate a service to a device path is different for 584bac2208Snarayan * vldc and glvc, due to the way the device pathnames are encoded: 594bac2208Snarayan * Sample service: sunvts 604bac2208Snarayan * Service Name: SUNW,sun4v-sunvts 614bac2208Snarayan * GLVC device path: 624bac2208Snarayan * "/devices/virtual-devices@100/sunvts@a:glvc" 634bac2208Snarayan * VLDC device path: 644bac2208Snarayan * "/devices/virtual-devices@100/channel-devices@200/virtual-channel@3:sunvts" 654bac2208Snarayan * 664bac2208Snarayan * As VLDC is the communication mechanism used in an LDoms environment, it is 674bac2208Snarayan * the preferred channel, and its existence is checked for first. 684bac2208Snarayan */ 694bac2208Snarayan 704bac2208Snarayan /* 714bac2208Snarayan * Extract from dev_path the "service name" portion. 724bac2208Snarayan * For vldc, the service corresponds to the minor name of the device path 734bac2208Snarayan * (e.g. virtual-channel@3:sunvts for sunvts). If service is non-NULL, it must 744bac2208Snarayan * match the extracted service name for the function to succeed. 754bac2208Snarayan * The service name is returned in match (if non-NULL), and the function 764bac2208Snarayan * itself returns true on success; false on failure. 774bac2208Snarayan */ 784bac2208Snarayan static bool_t 794bac2208Snarayan get_vldc_svc_name(char *dev_path, char *service, char **match) 804bac2208Snarayan { 814bac2208Snarayan bool_t ret = false; 824bac2208Snarayan char *pathname = strdup(dev_path); 834bac2208Snarayan char *devname, *s; 844bac2208Snarayan 854bac2208Snarayan if (NULL == pathname) 864bac2208Snarayan return (false); 874bac2208Snarayan 884bac2208Snarayan devname = basename(pathname); 894bac2208Snarayan s = strrchr(devname, ':'); 904bac2208Snarayan 914bac2208Snarayan if (s++ == NULL) { 924bac2208Snarayan goto end; 934bac2208Snarayan } 944bac2208Snarayan 954bac2208Snarayan if ((strncmp(devname, VCHAN, strlen(VCHAN)) == 0) || 964bac2208Snarayan (strncmp(devname, VCHAN_C, strlen(VCHAN_C)) == 0)) { 974bac2208Snarayan /* 984bac2208Snarayan * If in addition, a service string is specified to 994bac2208Snarayan * be matched, do a comparison 1004bac2208Snarayan */ 1014bac2208Snarayan if (service != NULL) { 1024bac2208Snarayan if (strcmp(s, service) == 0) { 1034bac2208Snarayan if (match) 1044bac2208Snarayan *match = strdup(s); 1054bac2208Snarayan ret = true; 1064bac2208Snarayan goto end; 1074bac2208Snarayan } else { 1084bac2208Snarayan ret = false; 1094bac2208Snarayan goto end; 1104bac2208Snarayan } 1114bac2208Snarayan } else if (match) { 1124bac2208Snarayan *match = strdup(s); 1134bac2208Snarayan } 1144bac2208Snarayan 1154bac2208Snarayan ret = true; 1164bac2208Snarayan goto end; 1174bac2208Snarayan } 1184bac2208Snarayan end: 1194bac2208Snarayan 1204bac2208Snarayan free(pathname); 1214bac2208Snarayan return (ret); 1224bac2208Snarayan } 1234bac2208Snarayan 1244bac2208Snarayan /* 1254bac2208Snarayan * Extract from dev_path the "service name" portion. 1264bac2208Snarayan * For glvc, the service corresponds to the node name of the device path 1274bac2208Snarayan * (e.g. sunvts@a:glvc for sunvts). If service is non-NULL, it must 1284bac2208Snarayan * match the extracted service name for the function to succeed. 1294bac2208Snarayan * The service name is returned in match (if non-NULL), and the function 1304bac2208Snarayan * itself returns true on success; false on failure. 1314bac2208Snarayan */ 1324bac2208Snarayan static bool_t 1334bac2208Snarayan get_glvc_svc_name(char *dev_path, char *service, char **match) 1344bac2208Snarayan { 1354bac2208Snarayan bool_t ret = true; 1364bac2208Snarayan char *pathname = strdup(dev_path); 1374bac2208Snarayan char *devname, *substr, *t; 1384bac2208Snarayan int len; 1394bac2208Snarayan 1404bac2208Snarayan if (NULL == pathname) 1414bac2208Snarayan return (false); 1424bac2208Snarayan 1434bac2208Snarayan devname = basename(pathname); 1444bac2208Snarayan substr = strstr(devname, GLVC); 1454bac2208Snarayan 1464bac2208Snarayan if (!((substr != NULL) && (strcmp(substr, GLVC) == 0))) { 1474bac2208Snarayan ret = false; 1484bac2208Snarayan goto end; 1494bac2208Snarayan } 1504bac2208Snarayan 1514bac2208Snarayan if ((t = strrchr(devname, '@')) == NULL) { 1524bac2208Snarayan ret = false; 1534bac2208Snarayan goto end; 1544bac2208Snarayan } 1554bac2208Snarayan 1564bac2208Snarayan len = t - devname; 1574bac2208Snarayan 1584bac2208Snarayan /* 1594bac2208Snarayan * If a service string is specified, check if there 1604bac2208Snarayan * is a match 1614bac2208Snarayan */ 1624bac2208Snarayan if ((service != NULL) && (strncmp(devname, service, len) != 0)) 1634bac2208Snarayan ret = false; 1644bac2208Snarayan 1654bac2208Snarayan if ((ret == true) && (match != NULL)) { 1664bac2208Snarayan *match = calloc(len + 1, 1); 1674bac2208Snarayan if (*match) 1684bac2208Snarayan (void) strncpy(*match, devname, len); 1694bac2208Snarayan } 1704bac2208Snarayan 1714bac2208Snarayan end: 1724bac2208Snarayan free(pathname); 1734bac2208Snarayan return (ret); 1744bac2208Snarayan } 1754bac2208Snarayan 1764bac2208Snarayan /* 1774bac2208Snarayan * This routine accepts either a prefixed service name or a legacy full 1784bac2208Snarayan * pathname (which might not even exist in the filesystem), and in either case 1794bac2208Snarayan * returns a canonical service name. If the parameter is neither a service 1804bac2208Snarayan * name (i.e. with a "SUNW,sun4v-" prefix), nor a path to a legacy glvc or 1814bac2208Snarayan * vldc device, NULL is returned. 1824bac2208Snarayan */ 1834bac2208Snarayan char * 1844bac2208Snarayan platsvc_extract_svc_name(char *devname) 1854bac2208Snarayan { 1864bac2208Snarayan char *sname = NULL; 1874bac2208Snarayan char *vldc_path, *glvc_path; 1884bac2208Snarayan 1894bac2208Snarayan /* 1904bac2208Snarayan * First check whether a service name 1914bac2208Snarayan */ 1924bac2208Snarayan if (strncmp(devname, SERVICE_PREFIX, strlen(SERVICE_PREFIX)) == 0) { 1934bac2208Snarayan sname = strdup(devname + strlen(SERVICE_PREFIX)); 1944bac2208Snarayan return (sname); 1954bac2208Snarayan } 1964bac2208Snarayan 1974bac2208Snarayan /* 1984bac2208Snarayan * Not a service name, check if it's a valid pathname 1994bac2208Snarayan */ 2004bac2208Snarayan if (!(devname[0] == '/' || devname[0] == '.')) { 2014bac2208Snarayan return (NULL); 2024bac2208Snarayan } 2034bac2208Snarayan 2044bac2208Snarayan /* 2054bac2208Snarayan * Ideally, we should only check for a valid glvc pathname, 2064bac2208Snarayan * requiring all vldc access to be only via service names. But 2074bac2208Snarayan * to prevent a flag day with code that's already passing in 2084bac2208Snarayan * vldc full pathnames (e.g. sunMC), we allow them here. 2094bac2208Snarayan */ 2104bac2208Snarayan if (get_vldc_svc_name(devname, NULL, &vldc_path) == true) { 2114bac2208Snarayan return (vldc_path); 2124bac2208Snarayan } else if (get_glvc_svc_name(devname, NULL, &glvc_path) == true) { 2134bac2208Snarayan return (glvc_path); 2144bac2208Snarayan } 2154bac2208Snarayan 2164bac2208Snarayan return (NULL); 2174bac2208Snarayan } 2184bac2208Snarayan 2194bac2208Snarayan /* 2204bac2208Snarayan * Walk all "service" device nodes to find the one with the 2214bac2208Snarayan * matching glvc minor name 2224bac2208Snarayan */ 2234bac2208Snarayan static char * 2244bac2208Snarayan svc_name_to_glvc_dev_path(char *service) 2254bac2208Snarayan { 2264bac2208Snarayan di_node_t root_node, service_node; 2274bac2208Snarayan char *glvc_path; 2284bac2208Snarayan char *minor_name; 2294bac2208Snarayan di_minor_t minor; 2304bac2208Snarayan char *dev_path = NULL; 2314bac2208Snarayan 2324bac2208Snarayan if (service == NULL) 2334bac2208Snarayan return (NULL); 2344bac2208Snarayan 2353af08d82Slm /* Ensure that the 'glvc' driver is loaded */ 236468f746cSlm (void) di_init_driver("glvc", DI_CACHE_SNAPSHOT_FLAGS | DINFOFORCE); 2373af08d82Slm 2384bac2208Snarayan /* Get device node */ 2394bac2208Snarayan root_node = di_init("/", DINFOCPYALL); 2404bac2208Snarayan if (root_node == DI_NODE_NIL) { 2414bac2208Snarayan return (dev_path); 2424bac2208Snarayan } 2434bac2208Snarayan 2444bac2208Snarayan service_node = di_drv_first_node("glvc", root_node); 2454bac2208Snarayan 2464bac2208Snarayan while (service_node != DI_NODE_NIL) { 2474bac2208Snarayan /* Make sure node name matches service name */ 2484bac2208Snarayan if (strcmp(service, di_node_name(service_node)) == 0) { 2494bac2208Snarayan /* Walk minor nodes */ 2504bac2208Snarayan minor = di_minor_next(service_node, DI_NODE_NIL); 2514bac2208Snarayan 2524bac2208Snarayan while (minor != DI_NODE_NIL) { 2534bac2208Snarayan glvc_path = di_devfs_minor_path(minor); 2544bac2208Snarayan minor_name = di_minor_name(minor); 2554bac2208Snarayan 2564bac2208Snarayan if (strcmp(minor_name, "glvc") == 0) { 2574bac2208Snarayan dev_path = malloc(strlen(glvc_path) + 2584bac2208Snarayan strlen(DEVICES_DIR) + 1); 2594bac2208Snarayan (void) strcpy(dev_path, DEVICES_DIR); 2604bac2208Snarayan (void) strcat(dev_path, glvc_path); 2614bac2208Snarayan di_devfs_path_free(glvc_path); 2624bac2208Snarayan break; 2634bac2208Snarayan } 2644bac2208Snarayan 2654bac2208Snarayan di_devfs_path_free(glvc_path); 2664bac2208Snarayan minor = di_minor_next(service_node, minor); 2674bac2208Snarayan } 2684bac2208Snarayan } 2694bac2208Snarayan if (dev_path != NULL) 2704bac2208Snarayan break; 2714bac2208Snarayan 2724bac2208Snarayan service_node = di_drv_next_node(service_node); 2734bac2208Snarayan } 2744bac2208Snarayan 2754bac2208Snarayan di_fini(root_node); 2764bac2208Snarayan return (dev_path); 2774bac2208Snarayan } 2784bac2208Snarayan 2794bac2208Snarayan /* 2804bac2208Snarayan * Walk all vldc device nodes to find the one with the 2814bac2208Snarayan * matching minor name 2824bac2208Snarayan */ 2834bac2208Snarayan static char * 2844bac2208Snarayan svc_name_to_vldc_dev_path(char *service) 2854bac2208Snarayan { 2864bac2208Snarayan di_node_t root_node, vldc_node; 2874bac2208Snarayan char *vldc_path; 2884bac2208Snarayan char *minor_name; 2894bac2208Snarayan di_minor_t minor; 2904bac2208Snarayan char *dev_path = NULL; 2914bac2208Snarayan 292*94048829Sranenc /* Ensure that the 'vldc' driver is loaded */ 293*94048829Sranenc (void) di_init_driver("vldc", DI_CACHE_SNAPSHOT_FLAGS | DINFOFORCE); 294*94048829Sranenc 2954bac2208Snarayan /* Get device node */ 2964bac2208Snarayan root_node = di_init("/", DINFOCPYALL); 2974bac2208Snarayan if (root_node == DI_NODE_NIL) { 2984bac2208Snarayan return (dev_path); 2994bac2208Snarayan } 3004bac2208Snarayan 3014bac2208Snarayan vldc_node = di_drv_first_node("vldc", root_node); 3024bac2208Snarayan 3034bac2208Snarayan while (vldc_node != DI_NODE_NIL) { 3044bac2208Snarayan /* Walk minor nodes */ 3054bac2208Snarayan minor = di_minor_next(vldc_node, DI_NODE_NIL); 3064bac2208Snarayan 3074bac2208Snarayan while (minor != DI_NODE_NIL) { 3084bac2208Snarayan vldc_path = di_devfs_minor_path(minor); 3094bac2208Snarayan minor_name = di_minor_name(minor); 3104bac2208Snarayan 3114bac2208Snarayan if (strcmp(minor_name, service) == 0) { 3124bac2208Snarayan dev_path = malloc(strlen(vldc_path) + 3134bac2208Snarayan strlen(DEVICES_DIR) + 1); 3144bac2208Snarayan (void) strcpy(dev_path, DEVICES_DIR); 3154bac2208Snarayan (void) strcat(dev_path, vldc_path); 3164bac2208Snarayan di_devfs_path_free(vldc_path); 3174bac2208Snarayan break; 3184bac2208Snarayan } 3194bac2208Snarayan 3204bac2208Snarayan di_devfs_path_free(vldc_path); 3214bac2208Snarayan minor = di_minor_next(vldc_node, minor); 3224bac2208Snarayan } 3234bac2208Snarayan if (dev_path != NULL) 3244bac2208Snarayan break; 3254bac2208Snarayan 3264bac2208Snarayan vldc_node = di_drv_next_node(vldc_node); 3274bac2208Snarayan } 3284bac2208Snarayan 3294bac2208Snarayan di_fini(root_node); 3304bac2208Snarayan return (dev_path); 3314bac2208Snarayan } 3324bac2208Snarayan 3334bac2208Snarayan /* 3344bac2208Snarayan * Given a service name or a full legacy pathname, return 3354bac2208Snarayan * the full pathname to the appropriate vldc or glvc device. 3364bac2208Snarayan */ 3374bac2208Snarayan char * 3384bac2208Snarayan platsvc_name_to_path(char *svc_or_path, pcp_xport_t *type) 3394bac2208Snarayan { 3404bac2208Snarayan char *pathn_p; 3414bac2208Snarayan char *service; 3424bac2208Snarayan 3434bac2208Snarayan if ((service = platsvc_extract_svc_name(svc_or_path)) == NULL) 3444bac2208Snarayan return (NULL); 3454bac2208Snarayan 3464bac2208Snarayan /* 3474bac2208Snarayan * First lookup vldc nodes 3484bac2208Snarayan */ 3494bac2208Snarayan pathn_p = svc_name_to_vldc_dev_path(service); 3504bac2208Snarayan if (pathn_p != NULL) { 3514bac2208Snarayan *type = VLDC_STREAMING; 3524bac2208Snarayan } else { 3534bac2208Snarayan /* 3544bac2208Snarayan * If no vldc, try to find a glvc node 3554bac2208Snarayan */ 3564bac2208Snarayan pathn_p = svc_name_to_glvc_dev_path(service); 3574bac2208Snarayan if (pathn_p != NULL) { 3584bac2208Snarayan *type = GLVC_NON_STREAM; 3594bac2208Snarayan } 3604bac2208Snarayan } 3614bac2208Snarayan 3624bac2208Snarayan free(service); 3634bac2208Snarayan return (pathn_p); 3644bac2208Snarayan } 365