diff options
Diffstat (limited to 'usr/src/lib')
| -rw-r--r-- | usr/src/lib/libpcp/Makefile.com | 2 | ||||
| -rw-r--r-- | usr/src/lib/libpcp/common/libpcp.c | 46 | ||||
| -rw-r--r-- | usr/src/lib/libpcp/common/pcp_utils.c | 358 | ||||
| -rw-r--r-- | usr/src/lib/libpcp/common/pcp_utils.h | 61 | ||||
| -rw-r--r-- | usr/src/lib/libpcp/sparc/Makefile | 7 |
5 files changed, 452 insertions, 22 deletions
diff --git a/usr/src/lib/libpcp/Makefile.com b/usr/src/lib/libpcp/Makefile.com index 654f77cb8a..f7f8d25ed4 100644 --- a/usr/src/lib/libpcp/Makefile.com +++ b/usr/src/lib/libpcp/Makefile.com @@ -49,7 +49,7 @@ LINKED_LLIBLPCP_DIR = \ LIBS = $(DYNLIB) $(LINTLIB) CFLAGS += $(CCVERBOSE) -LDLIBS += -lc -lumem +LDLIBS += -lc -lumem -ldevinfo PLATLIBS = $(USR_PLAT_DIR)/$(PLATFORM)/lib INS.slink6= $(RM) -r $@; $(SYMLINK) ../../$(PLATFORM)/lib/libpcp.so.1 $@ $(CHOWNLINK) $(CHGRPLINK) INS.slink7= $(RM) -r $@; $(SYMLINK) ../../$(PLATFORM)/lib/libpcp.so $@ $(CHOWNLINK) $(CHGRPLINK) diff --git a/usr/src/lib/libpcp/common/libpcp.c b/usr/src/lib/libpcp/common/libpcp.c index 6c9eb09263..7888f7588f 100644 --- a/usr/src/lib/libpcp/common/libpcp.c +++ b/usr/src/lib/libpcp/common/libpcp.c @@ -53,6 +53,8 @@ #include "libpcp.h" #include "pcp_common.h" +#include "pcp_utils.h" + /* * Following libpcp interfaces are exposed to user applications. @@ -165,14 +167,7 @@ static struct sigaction old_act; /* * Variables to support vldc based streaming transport */ -typedef enum { - GLVC_NON_STREAM, - VLDC_STREAMING -} xport_t; - -static int xport_type = GLVC_NON_STREAM; -#define CHANNEL_DEV "channel-devices" - +static pcp_xport_t xport_type = GLVC_NON_STREAM; #define VLDC_MTU_SIZE (2048) static void @@ -194,25 +189,38 @@ pcp_init(char *channel_name) { sigset_t oldset; int channel_fd; + char *dev_path; + vldc_opt_op_t op; if (channel_name == NULL) return (PCPL_INVALID_ARGS); /* + * Given the argument, try to locate a device in the device tree + */ + dev_path = platsvc_name_to_path(channel_name, &xport_type); + + /* + * Path exists ? + */ + if (NULL == dev_path) + return (PCPL_INVALID_ARGS); + + /* * Open virtual channel name. */ - if ((channel_fd = open(channel_name, O_RDWR|O_EXCL)) < 0) { + if ((channel_fd = open(dev_path, O_RDWR|O_EXCL)) < 0) { + free(dev_path); return (PCPL_GLVC_ERROR); } + free(dev_path); + /* - * Check if the channel-name points to a vldc node - * or a glvc node + * Handle transport-specific processing */ - if (strstr(channel_name, CHANNEL_DEV) != NULL) { - vldc_opt_op_t op; - - xport_type = VLDC_STREAMING; + switch (xport_type) { + case VLDC_STREAMING: mtu_size = VLDC_MTU_SIZE; op.op_sel = VLDC_OP_SET; @@ -222,17 +230,19 @@ pcp_init(char *channel_name) (void) close(channel_fd); return (PCPL_GLVC_ERROR); } - } else { - xport_type = GLVC_NON_STREAM; + break; + case GLVC_NON_STREAM: + default: /* * Get the Channel MTU size */ if (pcp_get_prop(channel_fd, GLVC_XPORT_OPT_MTU_SZ, - &mtu_size) != 0) { + &mtu_size) != 0) { (void) close(channel_fd); return (PCPL_GLVC_ERROR); } + break; } /* diff --git a/usr/src/lib/libpcp/common/pcp_utils.c b/usr/src/lib/libpcp/common/pcp_utils.c new file mode 100644 index 0000000000..3ae93ab09e --- /dev/null +++ b/usr/src/lib/libpcp/common/pcp_utils.c @@ -0,0 +1,358 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Implements auxiliary routines declared in pcp_utils.h to facilitate + * finding the appropriate communication transport & device path for a + * given service. This supports the transition from the legacy service channel + * transport (glvc) to the logical domain channel (vldc) transport native + * to platforms running Logical Domains (LDoms). + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <strings.h> +#include <stdlib.h> +#include <libgen.h> +#include <unistd.h> +#include <stdio.h> +#include <libdevinfo.h> + +#include "pcp_utils.h" + +typedef enum { false = 0, true = 1 } bool_t; + +#define SERVICE_PREFIX "SUNW,sun4v-" +#define DEVICES_DIR "/devices" +#define GLVC ":glvc" +#define VCHAN "virtual-channel@" +#define VCHAN_C "virtual-channel-client@" + +/* + * The mechanism to relate a service to a device path is different for + * vldc and glvc, due to the way the device pathnames are encoded: + * Sample service: sunvts + * Service Name: SUNW,sun4v-sunvts + * GLVC device path: + * "/devices/virtual-devices@100/sunvts@a:glvc" + * VLDC device path: + * "/devices/virtual-devices@100/channel-devices@200/virtual-channel@3:sunvts" + * + * As VLDC is the communication mechanism used in an LDoms environment, it is + * the preferred channel, and its existence is checked for first. + */ + +/* + * Extract from dev_path the "service name" portion. + * For vldc, the service corresponds to the minor name of the device path + * (e.g. virtual-channel@3:sunvts for sunvts). If service is non-NULL, it must + * match the extracted service name for the function to succeed. + * The service name is returned in match (if non-NULL), and the function + * itself returns true on success; false on failure. + */ +static bool_t +get_vldc_svc_name(char *dev_path, char *service, char **match) +{ + bool_t ret = false; + char *pathname = strdup(dev_path); + char *devname, *s; + + if (NULL == pathname) + return (false); + + devname = basename(pathname); + s = strrchr(devname, ':'); + + if (s++ == NULL) { + goto end; + } + + if ((strncmp(devname, VCHAN, strlen(VCHAN)) == 0) || + (strncmp(devname, VCHAN_C, strlen(VCHAN_C)) == 0)) { + /* + * If in addition, a service string is specified to + * be matched, do a comparison + */ + if (service != NULL) { + if (strcmp(s, service) == 0) { + if (match) + *match = strdup(s); + ret = true; + goto end; + } else { + ret = false; + goto end; + } + } else if (match) { + *match = strdup(s); + } + + ret = true; + goto end; + } +end: + + free(pathname); + return (ret); +} + +/* + * Extract from dev_path the "service name" portion. + * For glvc, the service corresponds to the node name of the device path + * (e.g. sunvts@a:glvc for sunvts). If service is non-NULL, it must + * match the extracted service name for the function to succeed. + * The service name is returned in match (if non-NULL), and the function + * itself returns true on success; false on failure. + */ +static bool_t +get_glvc_svc_name(char *dev_path, char *service, char **match) +{ + bool_t ret = true; + char *pathname = strdup(dev_path); + char *devname, *substr, *t; + int len; + + if (NULL == pathname) + return (false); + + devname = basename(pathname); + substr = strstr(devname, GLVC); + + if (!((substr != NULL) && (strcmp(substr, GLVC) == 0))) { + ret = false; + goto end; + } + + if ((t = strrchr(devname, '@')) == NULL) { + ret = false; + goto end; + } + + len = t - devname; + + /* + * If a service string is specified, check if there + * is a match + */ + if ((service != NULL) && (strncmp(devname, service, len) != 0)) + ret = false; + + if ((ret == true) && (match != NULL)) { + *match = calloc(len + 1, 1); + if (*match) + (void) strncpy(*match, devname, len); + } + +end: + free(pathname); + return (ret); +} + +/* + * This routine accepts either a prefixed service name or a legacy full + * pathname (which might not even exist in the filesystem), and in either case + * returns a canonical service name. If the parameter is neither a service + * name (i.e. with a "SUNW,sun4v-" prefix), nor a path to a legacy glvc or + * vldc device, NULL is returned. + */ +char * +platsvc_extract_svc_name(char *devname) +{ + char *sname = NULL; + char *vldc_path, *glvc_path; + + /* + * First check whether a service name + */ + if (strncmp(devname, SERVICE_PREFIX, strlen(SERVICE_PREFIX)) == 0) { + sname = strdup(devname + strlen(SERVICE_PREFIX)); + return (sname); + } + + /* + * Not a service name, check if it's a valid pathname + */ + if (!(devname[0] == '/' || devname[0] == '.')) { + return (NULL); + } + + /* + * Ideally, we should only check for a valid glvc pathname, + * requiring all vldc access to be only via service names. But + * to prevent a flag day with code that's already passing in + * vldc full pathnames (e.g. sunMC), we allow them here. + */ + if (get_vldc_svc_name(devname, NULL, &vldc_path) == true) { + return (vldc_path); + } else if (get_glvc_svc_name(devname, NULL, &glvc_path) == true) { + return (glvc_path); + } + + return (NULL); +} + +/* + * Walk all "service" device nodes to find the one with the + * matching glvc minor name + */ +static char * +svc_name_to_glvc_dev_path(char *service) +{ + di_node_t root_node, service_node; + char *glvc_path; + char *minor_name; + di_minor_t minor; + char *dev_path = NULL; + + if (service == NULL) + return (NULL); + + /* Get device node */ + root_node = di_init("/", DINFOCPYALL); + if (root_node == DI_NODE_NIL) { + return (dev_path); + } + + service_node = di_drv_first_node("glvc", root_node); + + while (service_node != DI_NODE_NIL) { + /* Make sure node name matches service name */ + if (strcmp(service, di_node_name(service_node)) == 0) { + /* Walk minor nodes */ + minor = di_minor_next(service_node, DI_NODE_NIL); + + while (minor != DI_NODE_NIL) { + glvc_path = di_devfs_minor_path(minor); + minor_name = di_minor_name(minor); + + if (strcmp(minor_name, "glvc") == 0) { + dev_path = malloc(strlen(glvc_path) + + strlen(DEVICES_DIR) + 1); + (void) strcpy(dev_path, DEVICES_DIR); + (void) strcat(dev_path, glvc_path); + di_devfs_path_free(glvc_path); + break; + } + + di_devfs_path_free(glvc_path); + minor = di_minor_next(service_node, minor); + } + } + if (dev_path != NULL) + break; + + service_node = di_drv_next_node(service_node); + } + + di_fini(root_node); + return (dev_path); +} + +/* + * Walk all vldc device nodes to find the one with the + * matching minor name + */ +static char * +svc_name_to_vldc_dev_path(char *service) +{ + di_node_t root_node, vldc_node; + char *vldc_path; + char *minor_name; + di_minor_t minor; + char *dev_path = NULL; + + /* Get device node */ + root_node = di_init("/", DINFOCPYALL); + if (root_node == DI_NODE_NIL) { + return (dev_path); + } + + vldc_node = di_drv_first_node("vldc", root_node); + + while (vldc_node != DI_NODE_NIL) { + /* Walk minor nodes */ + minor = di_minor_next(vldc_node, DI_NODE_NIL); + + while (minor != DI_NODE_NIL) { + vldc_path = di_devfs_minor_path(minor); + minor_name = di_minor_name(minor); + + if (strcmp(minor_name, service) == 0) { + dev_path = malloc(strlen(vldc_path) + + strlen(DEVICES_DIR) + 1); + (void) strcpy(dev_path, DEVICES_DIR); + (void) strcat(dev_path, vldc_path); + di_devfs_path_free(vldc_path); + break; + } + + di_devfs_path_free(vldc_path); + minor = di_minor_next(vldc_node, minor); + } + if (dev_path != NULL) + break; + + vldc_node = di_drv_next_node(vldc_node); + } + + di_fini(root_node); + return (dev_path); +} + +/* + * Given a service name or a full legacy pathname, return + * the full pathname to the appropriate vldc or glvc device. + */ +char * +platsvc_name_to_path(char *svc_or_path, pcp_xport_t *type) +{ + char *pathn_p; + char *service; + + if ((service = platsvc_extract_svc_name(svc_or_path)) == NULL) + return (NULL); + + /* + * First lookup vldc nodes + */ + pathn_p = svc_name_to_vldc_dev_path(service); + if (pathn_p != NULL) { + *type = VLDC_STREAMING; + } else { + /* + * If no vldc, try to find a glvc node + */ + pathn_p = svc_name_to_glvc_dev_path(service); + if (pathn_p != NULL) { + *type = GLVC_NON_STREAM; + } + } + + free(service); + return (pathn_p); +} diff --git a/usr/src/lib/libpcp/common/pcp_utils.h b/usr/src/lib/libpcp/common/pcp_utils.h new file mode 100644 index 0000000000..bd501e5d72 --- /dev/null +++ b/usr/src/lib/libpcp/common/pcp_utils.h @@ -0,0 +1,61 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _PCP_UTILS_H +#define _PCP_UTILS_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Enum to differentiate supported transport types + */ +typedef enum { + GLVC_NON_STREAM, + VLDC_STREAMING +} pcp_xport_t; + +/* + * This file contains some auxiliary routines to enable libpcp to + * automatically find the device pathname of a given SP service + * (e.g. SUNW,sun4v-fma). In addition, glvc pathnames are + * converted to a service name and then a device path to maintain + * backward compatibility for applications still using full glvc + * device paths. The routines are defined in a separate source + * file, so any program can separately link with the .o file + * directly instead of using libpcp. + */ + +char *platsvc_extract_svc_name(char *devname); +char *platsvc_name_to_path(char *, pcp_xport_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* _PCP_UTILS_H */ diff --git a/usr/src/lib/libpcp/sparc/Makefile b/usr/src/lib/libpcp/sparc/Makefile index 9b9d7c7098..bb9fbc3935 100644 --- a/usr/src/lib/libpcp/sparc/Makefile +++ b/usr/src/lib/libpcp/sparc/Makefile @@ -30,13 +30,14 @@ UTSBASE= ../../../uts PLATINCS += -I$(USR_PLAT_DIR)/sun4v/include -I$(UTSBASE)/sun4v -PLATFORM_OBJECTS= libpcp.o +PLATFORM_OBJECTS= libpcp.o pcp_utils.o # # platform library directory (/usr/platform/SUNW,Sun-Fire-T200/lib) # -PLATFORM=SUNW,Sun-Fire-T200 -LINKED_PLATFORMS = SUNW,Netra-CP3060 +PLATFORM=sun4v +LINKED_PLATFORMS = SUNW,Sun-Fire-T200 \ + SUNW,Netra-CP3060 include ../Makefile.com |
