4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * Implements auxiliary routines declared in pcp_utils.h to facilitate
28 * finding the appropriate communication transport & device path for a
29 * given service. This supports the transition from the legacy service channel
30 * transport (glvc) to the logical domain channel (vldc) transport native
31 * to platforms running Logical Domains (LDoms).
35 #include <sys/types.h>
42 #include <libdevinfo.h>
44 #include "pcp_utils.h"
46 typedef enum { false = 0, true = 1 } bool_t
;
48 #define SERVICE_PREFIX "SUNW,sun4v-"
49 #define DEVICES_DIR "/devices"
51 #define VCHAN "virtual-channel@"
52 #define VCHAN_C "virtual-channel-client@"
55 * The mechanism to relate a service to a device path is different for
56 * vldc and glvc, due to the way the device pathnames are encoded:
57 * Sample service: sunvts
58 * Service Name: SUNW,sun4v-sunvts
60 * "/devices/virtual-devices@100/sunvts@a:glvc"
62 * "/devices/virtual-devices@100/channel-devices@200/virtual-channel@3:sunvts"
64 * As VLDC is the communication mechanism used in an LDoms environment, it is
65 * the preferred channel, and its existence is checked for first.
69 * Extract from dev_path the "service name" portion.
70 * For vldc, the service corresponds to the minor name of the device path
71 * (e.g. virtual-channel@3:sunvts for sunvts). If service is non-NULL, it must
72 * match the extracted service name for the function to succeed.
73 * The service name is returned in match (if non-NULL), and the function
74 * itself returns true on success; false on failure.
77 get_vldc_svc_name(char *dev_path
, char *service
, char **match
)
80 char *pathname
= strdup(dev_path
);
86 devname
= basename(pathname
);
87 s
= strrchr(devname
, ':');
93 if ((strncmp(devname
, VCHAN
, strlen(VCHAN
)) == 0) ||
94 (strncmp(devname
, VCHAN_C
, strlen(VCHAN_C
)) == 0)) {
96 * If in addition, a service string is specified to
97 * be matched, do a comparison
99 if (service
!= NULL
) {
100 if (strcmp(s
, service
) == 0) {
123 * Extract from dev_path the "service name" portion.
124 * For glvc, the service corresponds to the node name of the device path
125 * (e.g. sunvts@a:glvc for sunvts). If service is non-NULL, it must
126 * match the extracted service name for the function to succeed.
127 * The service name is returned in match (if non-NULL), and the function
128 * itself returns true on success; false on failure.
131 get_glvc_svc_name(char *dev_path
, char *service
, char **match
)
134 char *pathname
= strdup(dev_path
);
135 char *devname
, *substr
, *t
;
138 if (NULL
== pathname
)
141 devname
= basename(pathname
);
142 substr
= strstr(devname
, GLVC
);
144 if (!((substr
!= NULL
) && (strcmp(substr
, GLVC
) == 0))) {
149 if ((t
= strrchr(devname
, '@')) == NULL
) {
157 * If a service string is specified, check if there
160 if ((service
!= NULL
) && (strncmp(devname
, service
, len
) != 0))
163 if ((ret
== true) && (match
!= NULL
)) {
164 *match
= calloc(len
+ 1, 1);
166 (void) strncpy(*match
, devname
, len
);
175 * This routine accepts either a prefixed service name or a legacy full
176 * pathname (which might not even exist in the filesystem), and in either case
177 * returns a canonical service name. If the parameter is neither a service
178 * name (i.e. with a "SUNW,sun4v-" prefix), nor a path to a legacy glvc or
179 * vldc device, NULL is returned.
182 platsvc_extract_svc_name(char *devname
)
185 char *vldc_path
, *glvc_path
;
188 * First check whether a service name
190 if (strncmp(devname
, SERVICE_PREFIX
, strlen(SERVICE_PREFIX
)) == 0) {
191 sname
= strdup(devname
+ strlen(SERVICE_PREFIX
));
196 * Not a service name, check if it's a valid pathname
198 if (!(devname
[0] == '/' || devname
[0] == '.')) {
203 * Ideally, we should only check for a valid glvc pathname,
204 * requiring all vldc access to be only via service names. But
205 * to prevent a flag day with code that's already passing in
206 * vldc full pathnames (e.g. sunMC), we allow them here.
208 if (get_vldc_svc_name(devname
, NULL
, &vldc_path
) == true) {
210 } else if (get_glvc_svc_name(devname
, NULL
, &glvc_path
) == true) {
218 * Walk all "service" device nodes to find the one with the
219 * matching glvc minor name
222 svc_name_to_glvc_dev_path(char *service
)
224 di_node_t root_node
, service_node
;
228 char *dev_path
= NULL
;
233 /* Ensure that the 'glvc' driver is loaded */
234 root_node
= di_init_driver("glvc", DINFOCPYALL
);
235 if (root_node
== DI_NODE_NIL
) {
239 service_node
= di_drv_first_node("glvc", root_node
);
241 while (service_node
!= DI_NODE_NIL
) {
242 /* Make sure node name matches service name */
243 if (strcmp(service
, di_node_name(service_node
)) == 0) {
244 /* Walk minor nodes */
245 minor
= di_minor_next(service_node
, DI_NODE_NIL
);
247 while (minor
!= DI_NODE_NIL
) {
248 glvc_path
= di_devfs_minor_path(minor
);
249 minor_name
= di_minor_name(minor
);
251 if (strcmp(minor_name
, "glvc") == 0) {
252 dev_path
= malloc(strlen(glvc_path
) +
253 strlen(DEVICES_DIR
) + 1);
254 (void) strcpy(dev_path
, DEVICES_DIR
);
255 (void) strcat(dev_path
, glvc_path
);
256 di_devfs_path_free(glvc_path
);
260 di_devfs_path_free(glvc_path
);
261 minor
= di_minor_next(service_node
, minor
);
264 if (dev_path
!= NULL
)
267 service_node
= di_drv_next_node(service_node
);
275 * Walk all vldc device nodes to find the one with the
276 * matching minor name
279 svc_name_to_vldc_dev_path(char *service
)
281 di_node_t root_node
, vldc_node
;
285 char *dev_path
= NULL
;
287 /* Ensure that the 'vldc' driver is loaded */
288 root_node
= di_init_driver("vldc", DINFOCPYALL
);
289 if (root_node
== DI_NODE_NIL
) {
293 vldc_node
= di_drv_first_node("vldc", root_node
);
295 while (vldc_node
!= DI_NODE_NIL
) {
296 /* Walk minor nodes */
297 minor
= di_minor_next(vldc_node
, DI_NODE_NIL
);
299 while (minor
!= DI_NODE_NIL
) {
300 vldc_path
= di_devfs_minor_path(minor
);
301 minor_name
= di_minor_name(minor
);
303 if (strcmp(minor_name
, service
) == 0) {
304 dev_path
= malloc(strlen(vldc_path
) +
305 strlen(DEVICES_DIR
) + 1);
306 (void) strcpy(dev_path
, DEVICES_DIR
);
307 (void) strcat(dev_path
, vldc_path
);
308 di_devfs_path_free(vldc_path
);
312 di_devfs_path_free(vldc_path
);
313 minor
= di_minor_next(vldc_node
, minor
);
315 if (dev_path
!= NULL
)
318 vldc_node
= di_drv_next_node(vldc_node
);
326 * Given a service name or a full legacy pathname, return
327 * the full pathname to the appropriate vldc or glvc device.
330 platsvc_name_to_path(char *svc_or_path
, pcp_xport_t
*type
)
335 if ((service
= platsvc_extract_svc_name(svc_or_path
)) == NULL
)
339 * First lookup vldc nodes
341 pathn_p
= svc_name_to_vldc_dev_path(service
);
342 if (pathn_p
!= NULL
) {
343 *type
= VLDC_STREAMING
;
346 * If no vldc, try to find a glvc node
348 pathn_p
= svc_name_to_glvc_dev_path(service
);
349 if (pathn_p
!= NULL
) {
350 *type
= GLVC_NON_STREAM
;