1 /* 2 * CDDL HEADER START 3 * 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. 7 * 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. 12 * 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] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Logical Domains System Agent 29 */ 30 31 #include <errno.h> 32 #include <fcntl.h> 33 #include <libds.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <strings.h> 37 #include <synch.h> 38 #include <thread.h> 39 #include <unistd.h> 40 #include <sys/utsname.h> 41 #include <sys/mdesc.h> 42 #include <sys/mdesc_impl.h> 43 44 #include "ldma.h" 45 #include "pri.h" 46 47 #define LDMA_MODULE LDMA_NAME_SYSTEM 48 49 #define LDMA_NVERSIONS (sizeof (ldma_versions) / sizeof (ds_ver_t)) 50 #define LDMA_NHANDLERS (sizeof (ldma_handlers) / sizeof (ldma_msg_handler_t)) 51 52 static ldm_msg_func_t ldma_sys_get_sysinfo; 53 static ldm_msg_func_t ldma_sys_get_chassisno; 54 55 /* ptr to cached value of chassisno */ 56 static char *ldma_sys_chassisno = NULL; 57 mutex_t ldma_chassisno_lock = DEFAULTMUTEX; 58 59 static ds_ver_t ldma_versions[] = { { 1, 0 } }; 60 61 static ldma_msg_handler_t ldma_handlers[] = { 62 { LDMA_MSGSYS_GET_SYSINFO, LDMA_MSGFLG_ACCESS_ANY, 63 ldma_sys_get_sysinfo }, 64 { LDMA_MSGSYS_GET_CHASSISNO, LDMA_MSGFLG_ACCESS_ANY, 65 ldma_sys_get_chassisno } 66 }; 67 68 ldma_agent_info_t ldma_system_info = { 69 LDMA_NAME_SYSTEM, 70 ldma_versions, LDMA_NVERSIONS, 71 ldma_handlers, LDMA_NHANDLERS 72 }; 73 74 /*ARGSUSED*/ 75 static ldma_request_status_t 76 ldma_sys_get_sysinfo(ds_ver_t *ver, ldma_message_header_t *request, 77 size_t request_dlen, ldma_message_header_t **replyp, size_t *reply_dlenp) 78 { 79 ldma_message_header_t *reply; 80 struct utsname name; 81 size_t syslen, nodlen, rellen, maclen, verlen; 82 size_t rlen; 83 char *data; 84 int status; 85 86 LDMA_DBG("GET_SYSINFO"); 87 88 if (request->msg_info != 0 || request_dlen != 0) { 89 status = LDMA_REQ_INVALID; 90 goto done; 91 } 92 93 if (uname(&name) == -1) { 94 LDMA_DBG("GET_SYSINFO: uname failed with error %d", errno); 95 status = LDMA_REQ_FAILED; 96 goto done; 97 } 98 99 syslen = strlen(name.sysname) + 1; 100 nodlen = strlen(name.nodename) + 1; 101 rellen = strlen(name.release) + 1; 102 verlen = strlen(name.version) + 1; 103 maclen = strlen(name.machine) + 1; 104 105 rlen = syslen + nodlen + rellen + verlen + maclen; 106 107 reply = ldma_alloc_result_msg(request, rlen); 108 109 if (reply == NULL) { 110 status = LDMA_REQ_FAILED; 111 goto done; 112 } 113 114 reply->msg_info = rlen; 115 116 data = LDMA_HDR2DATA(reply); 117 118 (void) strcpy(data, name.sysname); 119 data += syslen; 120 121 (void) strcpy(data, name.nodename); 122 data += nodlen; 123 124 (void) strcpy(data, name.release); 125 data += rellen; 126 127 (void) strcpy(data, name.version); 128 data += verlen; 129 130 (void) strcpy(data, name.machine); 131 132 LDMA_DBG("GET_SYSINFO: return info=%u, {%s, %s, %s, %s, %s}", rlen, 133 name.sysname, name.nodename, name.release, name.version, 134 name.machine); 135 136 *replyp = reply; 137 *reply_dlenp = rlen; 138 139 return (LDMA_REQ_COMPLETED); 140 141 done: 142 LDMA_DBG("GET_SYSINFO: return error %d", status); 143 return (status); 144 } 145 146 /* 147 * Wrapper for MD free: need unused size argument. 148 */ 149 /* ARGSUSED */ 150 static void 151 ldma_md_free(void *buf, size_t n) 152 { 153 free(buf); 154 } 155 156 /* 157 * Wrapper for MD init: read PRI MD and invoke md_init_intern. 158 */ 159 static md_t * 160 ldma_md_init() 161 { 162 md_t *mdp; 163 uint64_t *buf = NULL; 164 uint64_t token; 165 ssize_t status; 166 167 if (pri_init() == -1) 168 return (NULL); 169 170 status = pri_get(PRI_GET, &token, &buf, malloc, ldma_md_free); 171 pri_fini(); 172 173 if (status == (ssize_t)(-1)) 174 return (NULL); 175 176 mdp = md_init_intern(buf, malloc, ldma_md_free); 177 178 return (mdp); 179 } 180 181 /* 182 * Wrapper for md_fini. Allow NULL md ptr and free MD buffer. 183 */ 184 static void 185 ldma_md_fini(void *md) 186 { 187 md_impl_t *mdp = (md_impl_t *)md; 188 189 if (mdp) { 190 free(mdp->caddr); 191 (void) md_fini(md); 192 } 193 } 194 195 static int 196 ldma_get_chassis_serialno(char **strp) 197 { 198 md_t *mdp; 199 mde_cookie_t *component_nodes, rootnode; 200 int list_size, ncomponents, num_nodes, i; 201 char *component_type, *serialno; 202 int rv = 0; 203 204 (void) mutex_lock(&ldma_chassisno_lock); 205 if (ldma_sys_chassisno != NULL) { 206 *strp = ldma_sys_chassisno; 207 (void) mutex_unlock(&ldma_chassisno_lock); 208 return (1); 209 } 210 211 mdp = ldma_md_init(); 212 if (mdp == NULL) { 213 (void) mutex_unlock(&ldma_chassisno_lock); 214 return (0); 215 } 216 217 num_nodes = md_node_count(mdp); 218 list_size = num_nodes * sizeof (mde_cookie_t); 219 component_nodes = malloc(list_size); 220 if (component_nodes == NULL) { 221 (void) mutex_unlock(&ldma_chassisno_lock); 222 ldma_md_fini(mdp); 223 return (0); 224 } 225 226 rootnode = md_root_node(mdp); 227 228 ncomponents = md_scan_dag(mdp, rootnode, md_find_name(mdp, "component"), 229 md_find_name(mdp, "fwd"), component_nodes); 230 231 for (i = 0; i < ncomponents; i++) { 232 if (md_get_prop_str(mdp, component_nodes[i], "type", 233 &component_type)) 234 continue; 235 if (strcmp(component_type, "chassis") != 0) 236 continue; 237 if (md_get_prop_str(mdp, component_nodes[i], 238 "serial_number", &serialno) == 0) { 239 ldma_sys_chassisno = strdup(serialno); 240 *strp = ldma_sys_chassisno; 241 rv = 1; 242 break; 243 } 244 } 245 (void) mutex_unlock(&ldma_chassisno_lock); 246 free(component_nodes); 247 ldma_md_fini(mdp); 248 return (rv); 249 } 250 251 /*ARGSUSED*/ 252 static ldma_request_status_t 253 ldma_sys_get_chassisno(ds_ver_t *ver, ldma_message_header_t *request, 254 size_t request_dlen, ldma_message_header_t **replyp, size_t *reply_dlenp) 255 { 256 ldma_message_header_t *reply; 257 char *str; 258 size_t rlen; 259 char *data; 260 int status; 261 262 LDMA_DBG("GET_CHASSISNO"); 263 264 if (request->msg_info != 0 || request_dlen != 0) { 265 status = LDMA_REQ_INVALID; 266 goto done; 267 } 268 269 if (ldma_get_chassis_serialno(&str) == 0) { 270 LDMA_DBG("GET_CHASSISNO: ldma_get_chassisno failed " 271 "with error %d", errno); 272 status = LDMA_REQ_FAILED; 273 goto done; 274 } 275 276 rlen = strlen(str) + 1; 277 278 reply = ldma_alloc_result_msg(request, rlen); 279 280 if (reply == NULL) { 281 status = LDMA_REQ_FAILED; 282 goto done; 283 } 284 285 reply->msg_info = rlen; 286 287 data = LDMA_HDR2DATA(reply); 288 289 (void) strcpy(data, str); 290 291 LDMA_DBG("GET_CHASSISNO: return info=%u, {%s}", rlen, str); 292 293 *replyp = reply; 294 *reply_dlenp = rlen; 295 296 return (LDMA_REQ_COMPLETED); 297 298 done: 299 LDMA_DBG("GET_CHASSISNO: return error %d", status); 300 return (status); 301 } 302