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*66ea8494SVikram Hegde * Copyright 2009 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 #include <fcntl.h> 354bac2208Snarayan #include <sys/types.h> 364bac2208Snarayan #include <sys/stat.h> 374bac2208Snarayan #include <strings.h> 384bac2208Snarayan #include <stdlib.h> 394bac2208Snarayan #include <libgen.h> 404bac2208Snarayan #include <unistd.h> 414bac2208Snarayan #include <stdio.h> 424bac2208Snarayan #include <libdevinfo.h> 434bac2208Snarayan 444bac2208Snarayan #include "pcp_utils.h" 454bac2208Snarayan 464bac2208Snarayan typedef enum { false = 0, true = 1 } bool_t; 474bac2208Snarayan 484bac2208Snarayan #define SERVICE_PREFIX "SUNW,sun4v-" 494bac2208Snarayan #define DEVICES_DIR "/devices" 504bac2208Snarayan #define GLVC ":glvc" 514bac2208Snarayan #define VCHAN "virtual-channel@" 524bac2208Snarayan #define VCHAN_C "virtual-channel-client@" 534bac2208Snarayan 544bac2208Snarayan /* 554bac2208Snarayan * The mechanism to relate a service to a device path is different for 564bac2208Snarayan * vldc and glvc, due to the way the device pathnames are encoded: 574bac2208Snarayan * Sample service: sunvts 584bac2208Snarayan * Service Name: SUNW,sun4v-sunvts 594bac2208Snarayan * GLVC device path: 604bac2208Snarayan * "/devices/virtual-devices@100/sunvts@a:glvc" 614bac2208Snarayan * VLDC device path: 624bac2208Snarayan * "/devices/virtual-devices@100/channel-devices@200/virtual-channel@3:sunvts" 634bac2208Snarayan * 644bac2208Snarayan * As VLDC is the communication mechanism used in an LDoms environment, it is 654bac2208Snarayan * the preferred channel, and its existence is checked for first. 664bac2208Snarayan */ 674bac2208Snarayan 684bac2208Snarayan /* 694bac2208Snarayan * Extract from dev_path the "service name" portion. 704bac2208Snarayan * For vldc, the service corresponds to the minor name of the device path 714bac2208Snarayan * (e.g. virtual-channel@3:sunvts for sunvts). If service is non-NULL, it must 724bac2208Snarayan * match the extracted service name for the function to succeed. 734bac2208Snarayan * The service name is returned in match (if non-NULL), and the function 744bac2208Snarayan * itself returns true on success; false on failure. 754bac2208Snarayan */ 764bac2208Snarayan static bool_t 774bac2208Snarayan get_vldc_svc_name(char *dev_path, char *service, char **match) 784bac2208Snarayan { 794bac2208Snarayan bool_t ret = false; 804bac2208Snarayan char *pathname = strdup(dev_path); 814bac2208Snarayan char *devname, *s; 824bac2208Snarayan 834bac2208Snarayan if (NULL == pathname) 844bac2208Snarayan return (false); 854bac2208Snarayan 864bac2208Snarayan devname = basename(pathname); 874bac2208Snarayan s = strrchr(devname, ':'); 884bac2208Snarayan 894bac2208Snarayan if (s++ == NULL) { 904bac2208Snarayan goto end; 914bac2208Snarayan } 924bac2208Snarayan 934bac2208Snarayan if ((strncmp(devname, VCHAN, strlen(VCHAN)) == 0) || 944bac2208Snarayan (strncmp(devname, VCHAN_C, strlen(VCHAN_C)) == 0)) { 954bac2208Snarayan /* 964bac2208Snarayan * If in addition, a service string is specified to 974bac2208Snarayan * be matched, do a comparison 984bac2208Snarayan */ 994bac2208Snarayan if (service != NULL) { 1004bac2208Snarayan if (strcmp(s, service) == 0) { 1014bac2208Snarayan if (match) 1024bac2208Snarayan *match = strdup(s); 1034bac2208Snarayan ret = true; 1044bac2208Snarayan goto end; 1054bac2208Snarayan } else { 1064bac2208Snarayan ret = false; 1074bac2208Snarayan goto end; 1084bac2208Snarayan } 1094bac2208Snarayan } else if (match) { 1104bac2208Snarayan *match = strdup(s); 1114bac2208Snarayan } 1124bac2208Snarayan 1134bac2208Snarayan ret = true; 1144bac2208Snarayan goto end; 1154bac2208Snarayan } 1164bac2208Snarayan end: 1174bac2208Snarayan 1184bac2208Snarayan free(pathname); 1194bac2208Snarayan return (ret); 1204bac2208Snarayan } 1214bac2208Snarayan 1224bac2208Snarayan /* 1234bac2208Snarayan * Extract from dev_path the "service name" portion. 1244bac2208Snarayan * For glvc, the service corresponds to the node name of the device path 1254bac2208Snarayan * (e.g. sunvts@a:glvc for sunvts). If service is non-NULL, it must 1264bac2208Snarayan * match the extracted service name for the function to succeed. 1274bac2208Snarayan * The service name is returned in match (if non-NULL), and the function 1284bac2208Snarayan * itself returns true on success; false on failure. 1294bac2208Snarayan */ 1304bac2208Snarayan static bool_t 1314bac2208Snarayan get_glvc_svc_name(char *dev_path, char *service, char **match) 1324bac2208Snarayan { 1334bac2208Snarayan bool_t ret = true; 1344bac2208Snarayan char *pathname = strdup(dev_path); 1354bac2208Snarayan char *devname, *substr, *t; 1364bac2208Snarayan int len; 1374bac2208Snarayan 1384bac2208Snarayan if (NULL == pathname) 1394bac2208Snarayan return (false); 1404bac2208Snarayan 1414bac2208Snarayan devname = basename(pathname); 1424bac2208Snarayan substr = strstr(devname, GLVC); 1434bac2208Snarayan 1444bac2208Snarayan if (!((substr != NULL) && (strcmp(substr, GLVC) == 0))) { 1454bac2208Snarayan ret = false; 1464bac2208Snarayan goto end; 1474bac2208Snarayan } 1484bac2208Snarayan 1494bac2208Snarayan if ((t = strrchr(devname, '@')) == NULL) { 1504bac2208Snarayan ret = false; 1514bac2208Snarayan goto end; 1524bac2208Snarayan } 1534bac2208Snarayan 1544bac2208Snarayan len = t - devname; 1554bac2208Snarayan 1564bac2208Snarayan /* 1574bac2208Snarayan * If a service string is specified, check if there 1584bac2208Snarayan * is a match 1594bac2208Snarayan */ 1604bac2208Snarayan if ((service != NULL) && (strncmp(devname, service, len) != 0)) 1614bac2208Snarayan ret = false; 1624bac2208Snarayan 1634bac2208Snarayan if ((ret == true) && (match != NULL)) { 1644bac2208Snarayan *match = calloc(len + 1, 1); 1654bac2208Snarayan if (*match) 1664bac2208Snarayan (void) strncpy(*match, devname, len); 1674bac2208Snarayan } 1684bac2208Snarayan 1694bac2208Snarayan end: 1704bac2208Snarayan free(pathname); 1714bac2208Snarayan return (ret); 1724bac2208Snarayan } 1734bac2208Snarayan 1744bac2208Snarayan /* 1754bac2208Snarayan * This routine accepts either a prefixed service name or a legacy full 1764bac2208Snarayan * pathname (which might not even exist in the filesystem), and in either case 1774bac2208Snarayan * returns a canonical service name. If the parameter is neither a service 1784bac2208Snarayan * name (i.e. with a "SUNW,sun4v-" prefix), nor a path to a legacy glvc or 1794bac2208Snarayan * vldc device, NULL is returned. 1804bac2208Snarayan */ 1814bac2208Snarayan char * 1824bac2208Snarayan platsvc_extract_svc_name(char *devname) 1834bac2208Snarayan { 1844bac2208Snarayan char *sname = NULL; 1854bac2208Snarayan char *vldc_path, *glvc_path; 1864bac2208Snarayan 1874bac2208Snarayan /* 1884bac2208Snarayan * First check whether a service name 1894bac2208Snarayan */ 1904bac2208Snarayan if (strncmp(devname, SERVICE_PREFIX, strlen(SERVICE_PREFIX)) == 0) { 1914bac2208Snarayan sname = strdup(devname + strlen(SERVICE_PREFIX)); 1924bac2208Snarayan return (sname); 1934bac2208Snarayan } 1944bac2208Snarayan 1954bac2208Snarayan /* 1964bac2208Snarayan * Not a service name, check if it's a valid pathname 1974bac2208Snarayan */ 1984bac2208Snarayan if (!(devname[0] == '/' || devname[0] == '.')) { 1994bac2208Snarayan return (NULL); 2004bac2208Snarayan } 2014bac2208Snarayan 2024bac2208Snarayan /* 2034bac2208Snarayan * Ideally, we should only check for a valid glvc pathname, 2044bac2208Snarayan * requiring all vldc access to be only via service names. But 2054bac2208Snarayan * to prevent a flag day with code that's already passing in 2064bac2208Snarayan * vldc full pathnames (e.g. sunMC), we allow them here. 2074bac2208Snarayan */ 2084bac2208Snarayan if (get_vldc_svc_name(devname, NULL, &vldc_path) == true) { 2094bac2208Snarayan return (vldc_path); 2104bac2208Snarayan } else if (get_glvc_svc_name(devname, NULL, &glvc_path) == true) { 2114bac2208Snarayan return (glvc_path); 2124bac2208Snarayan } 2134bac2208Snarayan 2144bac2208Snarayan return (NULL); 2154bac2208Snarayan } 2164bac2208Snarayan 2174bac2208Snarayan /* 2184bac2208Snarayan * Walk all "service" device nodes to find the one with the 2194bac2208Snarayan * matching glvc minor name 2204bac2208Snarayan */ 2214bac2208Snarayan static char * 2224bac2208Snarayan svc_name_to_glvc_dev_path(char *service) 2234bac2208Snarayan { 2244bac2208Snarayan di_node_t root_node, service_node; 2254bac2208Snarayan char *glvc_path; 2264bac2208Snarayan char *minor_name; 2274bac2208Snarayan di_minor_t minor; 2284bac2208Snarayan char *dev_path = NULL; 2294bac2208Snarayan 2304bac2208Snarayan if (service == NULL) 2314bac2208Snarayan return (NULL); 2324bac2208Snarayan 2333af08d82Slm66018 /* Ensure that the 'glvc' driver is loaded */ 234*66ea8494SVikram Hegde root_node = di_init_driver("glvc", DINFOCPYALL); 2354bac2208Snarayan if (root_node == DI_NODE_NIL) { 2364bac2208Snarayan return (dev_path); 2374bac2208Snarayan } 2384bac2208Snarayan 2394bac2208Snarayan service_node = di_drv_first_node("glvc", root_node); 2404bac2208Snarayan 2414bac2208Snarayan while (service_node != DI_NODE_NIL) { 2424bac2208Snarayan /* Make sure node name matches service name */ 2434bac2208Snarayan if (strcmp(service, di_node_name(service_node)) == 0) { 2444bac2208Snarayan /* Walk minor nodes */ 2454bac2208Snarayan minor = di_minor_next(service_node, DI_NODE_NIL); 2464bac2208Snarayan 2474bac2208Snarayan while (minor != DI_NODE_NIL) { 2484bac2208Snarayan glvc_path = di_devfs_minor_path(minor); 2494bac2208Snarayan minor_name = di_minor_name(minor); 2504bac2208Snarayan 2514bac2208Snarayan if (strcmp(minor_name, "glvc") == 0) { 2524bac2208Snarayan dev_path = malloc(strlen(glvc_path) + 2534bac2208Snarayan strlen(DEVICES_DIR) + 1); 2544bac2208Snarayan (void) strcpy(dev_path, DEVICES_DIR); 2554bac2208Snarayan (void) strcat(dev_path, glvc_path); 2564bac2208Snarayan di_devfs_path_free(glvc_path); 2574bac2208Snarayan break; 2584bac2208Snarayan } 2594bac2208Snarayan 2604bac2208Snarayan di_devfs_path_free(glvc_path); 2614bac2208Snarayan minor = di_minor_next(service_node, minor); 2624bac2208Snarayan } 2634bac2208Snarayan } 2644bac2208Snarayan if (dev_path != NULL) 2654bac2208Snarayan break; 2664bac2208Snarayan 2674bac2208Snarayan service_node = di_drv_next_node(service_node); 2684bac2208Snarayan } 2694bac2208Snarayan 2704bac2208Snarayan di_fini(root_node); 2714bac2208Snarayan return (dev_path); 2724bac2208Snarayan } 2734bac2208Snarayan 2744bac2208Snarayan /* 2754bac2208Snarayan * Walk all vldc device nodes to find the one with the 2764bac2208Snarayan * matching minor name 2774bac2208Snarayan */ 2784bac2208Snarayan static char * 2794bac2208Snarayan svc_name_to_vldc_dev_path(char *service) 2804bac2208Snarayan { 2814bac2208Snarayan di_node_t root_node, vldc_node; 2824bac2208Snarayan char *vldc_path; 2834bac2208Snarayan char *minor_name; 2844bac2208Snarayan di_minor_t minor; 2854bac2208Snarayan char *dev_path = NULL; 2864bac2208Snarayan 28794048829Sranenc /* Ensure that the 'vldc' driver is loaded */ 288*66ea8494SVikram Hegde root_node = di_init_driver("vldc", DINFOCPYALL); 2894bac2208Snarayan if (root_node == DI_NODE_NIL) { 2904bac2208Snarayan return (dev_path); 2914bac2208Snarayan } 2924bac2208Snarayan 2934bac2208Snarayan vldc_node = di_drv_first_node("vldc", root_node); 2944bac2208Snarayan 2954bac2208Snarayan while (vldc_node != DI_NODE_NIL) { 2964bac2208Snarayan /* Walk minor nodes */ 2974bac2208Snarayan minor = di_minor_next(vldc_node, DI_NODE_NIL); 2984bac2208Snarayan 2994bac2208Snarayan while (minor != DI_NODE_NIL) { 3004bac2208Snarayan vldc_path = di_devfs_minor_path(minor); 3014bac2208Snarayan minor_name = di_minor_name(minor); 3024bac2208Snarayan 3034bac2208Snarayan if (strcmp(minor_name, service) == 0) { 3044bac2208Snarayan dev_path = malloc(strlen(vldc_path) + 3054bac2208Snarayan strlen(DEVICES_DIR) + 1); 3064bac2208Snarayan (void) strcpy(dev_path, DEVICES_DIR); 3074bac2208Snarayan (void) strcat(dev_path, vldc_path); 3084bac2208Snarayan di_devfs_path_free(vldc_path); 3094bac2208Snarayan break; 3104bac2208Snarayan } 3114bac2208Snarayan 3124bac2208Snarayan di_devfs_path_free(vldc_path); 3134bac2208Snarayan minor = di_minor_next(vldc_node, minor); 3144bac2208Snarayan } 3154bac2208Snarayan if (dev_path != NULL) 3164bac2208Snarayan break; 3174bac2208Snarayan 3184bac2208Snarayan vldc_node = di_drv_next_node(vldc_node); 3194bac2208Snarayan } 3204bac2208Snarayan 3214bac2208Snarayan di_fini(root_node); 3224bac2208Snarayan return (dev_path); 3234bac2208Snarayan } 3244bac2208Snarayan 3254bac2208Snarayan /* 3264bac2208Snarayan * Given a service name or a full legacy pathname, return 3274bac2208Snarayan * the full pathname to the appropriate vldc or glvc device. 3284bac2208Snarayan */ 3294bac2208Snarayan char * 3304bac2208Snarayan platsvc_name_to_path(char *svc_or_path, pcp_xport_t *type) 3314bac2208Snarayan { 3324bac2208Snarayan char *pathn_p; 3334bac2208Snarayan char *service; 3344bac2208Snarayan 3354bac2208Snarayan if ((service = platsvc_extract_svc_name(svc_or_path)) == NULL) 3364bac2208Snarayan return (NULL); 3374bac2208Snarayan 3384bac2208Snarayan /* 3394bac2208Snarayan * First lookup vldc nodes 3404bac2208Snarayan */ 3414bac2208Snarayan pathn_p = svc_name_to_vldc_dev_path(service); 3424bac2208Snarayan if (pathn_p != NULL) { 3434bac2208Snarayan *type = VLDC_STREAMING; 3444bac2208Snarayan } else { 3454bac2208Snarayan /* 3464bac2208Snarayan * If no vldc, try to find a glvc node 3474bac2208Snarayan */ 3484bac2208Snarayan pathn_p = svc_name_to_glvc_dev_path(service); 3494bac2208Snarayan if (pathn_p != NULL) { 3504bac2208Snarayan *type = GLVC_NON_STREAM; 3514bac2208Snarayan } 3524bac2208Snarayan } 3534bac2208Snarayan 3544bac2208Snarayan free(service); 3554bac2208Snarayan return (pathn_p); 3564bac2208Snarayan } 357