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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * PICL Cherrystone platform plug-in to remove environment tree nodes 29 * if corresponding physical device is not present. For creating 30 * the picltree nodes, see: 31 * usr/src/cmd/picl/plugins/sun4u/psvc/psvcplugin/psvcplugin.c 32 */ 33 #define _POSIX_PRIORITY_SCHEDULING 1 34 35 #include <picl.h> 36 #include <picltree.h> 37 #include <stdio.h> 38 #include <time.h> 39 #include <fcntl.h> 40 #include <unistd.h> 41 #include <stdlib.h> 42 #include <stdio.h> 43 #include <libintl.h> 44 #include <limits.h> 45 #include <ctype.h> 46 #include <errno.h> 47 #include <semaphore.h> 48 #include <syslog.h> 49 #include <string.h> 50 #include <sys/types.h> 51 #include <sys/systeminfo.h> 52 #include <psvc_objects.h> 53 54 static psvc_opaque_t hdlp; 55 56 #define PSVC_PLUGIN_VERSION PICLD_PLUGIN_VERSION_1 57 58 #pragma init(psvc_psr_plugin_register) /* place in .init section */ 59 60 typedef struct { 61 char name[32]; 62 picl_nodehdl_t node; 63 } picl_psvc_t; 64 65 extern struct handle { 66 uint32_t obj_count; 67 picl_psvc_t *objects; 68 FILE *fp; 69 } psvc_hdl; 70 71 void psvc_psr_plugin_init(void); 72 void psvc_psr_plugin_fini(void); 73 74 picld_plugin_reg_t psvc_psr_reg = { 75 PSVC_PLUGIN_VERSION, 76 PICLD_PLUGIN_CRITICAL, 77 "PSVC_PSR", 78 psvc_psr_plugin_init, 79 psvc_psr_plugin_fini 80 }; 81 82 #define PSVC_INIT_ERR gettext("%s: Error in psvc_init(): %s\n") 83 #define PTREE_DELETE_NODE_ERR gettext("%s: ptree_delete_node() failed: %s\n") 84 #define PTREE_GET_NODE_ERR \ 85 gettext("%s: ptree_get_node_by_path() failed: %s\n") 86 87 extern int ptree_get_node_by_path(const char *, picl_nodehdl_t *); 88 89 /* ======================================== */ 90 struct node_file { 91 char path[256]; 92 char file[256]; 93 } dev_pr_info[] = { 94 /* Search for memory */ 95 {"/SYSTEM/MOTHERBOARD/CPU_0_2_MOD_SLOT/CPU_0_2_MOD_CARD/24C02_A0_0", 96 "/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@0,a0:fru"}, 97 {"/SYSTEM/MOTHERBOARD/CPU_0_2_MOD_SLOT/CPU_0_2_MOD_CARD/24C02_A2_0", 98 "/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@0,a2:fru"}, 99 {"/SYSTEM/MOTHERBOARD/CPU_0_2_MOD_SLOT/CPU_0_2_MOD_CARD/24C02_A4_0", 100 "/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@0,a4:fru"}, 101 {"/SYSTEM/MOTHERBOARD/CPU_0_2_MOD_SLOT/CPU_0_2_MOD_CARD/24C02_A6_0", 102 "/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@0,a6:fru"}, 103 {"/SYSTEM/MOTHERBOARD/CPU_0_2_MOD_SLOT/CPU_0_2_MOD_CARD/24C02_A8_0", 104 "/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@0,a8:fru"}, 105 {"/SYSTEM/MOTHERBOARD/CPU_0_2_MOD_SLOT/CPU_0_2_MOD_CARD/24C02_AA_0", 106 "/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@0,aa:fru"}, 107 {"/SYSTEM/MOTHERBOARD/CPU_0_2_MOD_SLOT/CPU_0_2_MOD_CARD/24C02_AC_0", 108 "/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@0,ac:fru"}, 109 {"/SYSTEM/MOTHERBOARD/CPU_0_2_MOD_SLOT/CPU_0_2_MOD_CARD/24C02_AE_0", 110 "/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@0,ae:fru"}, 111 {"/SYSTEM/MOTHERBOARD/CPU_1_3_MOD_SLOT/CPU_1_3_MOD_CARD/24C02_A0_1", 112 "/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@1,a0:fru"}, 113 {"/SYSTEM/MOTHERBOARD/CPU_1_3_MOD_SLOT/CPU_1_3_MOD_CARD/24C02_A2_1", 114 "/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@1,a2:fru"}, 115 {"/SYSTEM/MOTHERBOARD/CPU_1_3_MOD_SLOT/CPU_1_3_MOD_CARD/24C02_A4_1", 116 "/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@1,a4:fru"}, 117 {"/SYSTEM/MOTHERBOARD/CPU_1_3_MOD_SLOT/CPU_1_3_MOD_CARD/24C02_A6_1", 118 "/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@1,a6:fru"}, 119 {"/SYSTEM/MOTHERBOARD/CPU_1_3_MOD_SLOT/CPU_1_3_MOD_CARD/24C02_A8_1", 120 "/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@1,a8:fru"}, 121 {"/SYSTEM/MOTHERBOARD/CPU_1_3_MOD_SLOT/CPU_1_3_MOD_CARD/24C02_AA_1", 122 "/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@1,aa:fru"}, 123 {"/SYSTEM/MOTHERBOARD/CPU_1_3_MOD_SLOT/CPU_1_3_MOD_CARD/24C02_AC_1", 124 "/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@1,ac:fru"}, 125 {"/SYSTEM/MOTHERBOARD/CPU_1_3_MOD_SLOT/CPU_1_3_MOD_CARD/24C02_AE_1", 126 "/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@1,ae:fru"}, 127 {"/SYSTEM/MOTHERBOARD/CPU_0_2_MOD_SLOT/CPU_0_2_MOD_CARD/24C02_A0_2", 128 "/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@2,a0:fru"}, 129 {"/SYSTEM/MOTHERBOARD/CPU_0_2_MOD_SLOT/CPU_0_2_MOD_CARD/24C02_A2_2", 130 "/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@2,a2:fru"}, 131 {"/SYSTEM/MOTHERBOARD/CPU_0_2_MOD_SLOT/CPU_0_2_MOD_CARD/24C02_A4_2", 132 "/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@2,a4:fru"}, 133 {"/SYSTEM/MOTHERBOARD/CPU_0_2_MOD_SLOT/CPU_0_2_MOD_CARD/24C02_A6_2", 134 "/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@2,a6:fru"}, 135 {"/SYSTEM/MOTHERBOARD/CPU_0_2_MOD_SLOT/CPU_0_2_MOD_CARD/24C02_A8_2", 136 "/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@2,a8:fru"}, 137 {"/SYSTEM/MOTHERBOARD/CPU_0_2_MOD_SLOT/CPU_0_2_MOD_CARD/24C02_AA_2", 138 "/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@2,aa:fru"}, 139 {"/SYSTEM/MOTHERBOARD/CPU_0_2_MOD_SLOT/CPU_0_2_MOD_CARD/24C02_AC_2", 140 "/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@2,ac:fru"}, 141 {"/SYSTEM/MOTHERBOARD/CPU_0_2_MOD_SLOT/CPU_0_2_MOD_CARD/24C02_AE_2", 142 "/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@2,ae:fru"}, 143 {"/SYSTEM/MOTHERBOARD/CPU_1_3_MOD_SLOT/CPU_1_3_MOD_CARD/24C02_A0_3", 144 "/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@3,a0:fru"}, 145 {"/SYSTEM/MOTHERBOARD/CPU_1_3_MOD_SLOT/CPU_1_3_MOD_CARD/24C02_A2_3", 146 "/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@3,a2:fru"}, 147 {"/SYSTEM/MOTHERBOARD/CPU_1_3_MOD_SLOT/CPU_1_3_MOD_CARD/24C02_A4_3", 148 "/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@3,a4:fru"}, 149 {"/SYSTEM/MOTHERBOARD/CPU_1_3_MOD_SLOT/CPU_1_3_MOD_CARD/24C02_A6_3", 150 "/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@3,a6:fru"}, 151 {"/SYSTEM/MOTHERBOARD/CPU_1_3_MOD_SLOT/CPU_1_3_MOD_CARD/24C02_A8_3", 152 "/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@3,a8:fru"}, 153 {"/SYSTEM/MOTHERBOARD/CPU_1_3_MOD_SLOT/CPU_1_3_MOD_CARD/24C02_AA_3", 154 "/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@3,aa:fru"}, 155 {"/SYSTEM/MOTHERBOARD/CPU_1_3_MOD_SLOT/CPU_1_3_MOD_CARD/24C02_AC_3", 156 "/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@3,ac:fru"}, 157 {"/SYSTEM/MOTHERBOARD/CPU_1_3_MOD_SLOT/CPU_1_3_MOD_CARD/24C02_AE_3", 158 "/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@3,ae:fru"}, 159 /* Search for 64Kbit SPD */ 160 {"/SYSTEM/MOTHERBOARD/CPU_0_2_MOD_SLOT/CPU_0_2_MOD_CARD/24C64_A0_4", 161 "/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@4,a0:fru"}, 162 {"/SYSTEM/MOTHERBOARD/CPU_1_3_MOD_SLOT/CPU_1_3_MOD_CARD/24C64_A2_4", 163 "/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@4,a2:fru"}, 164 165 /* 166 * Search for CPU Module cards. We check one cpu's die temperature 167 * sensor If not present, then we remove the entire node since module 168 * cards come with two cpus in them, each cpu having a die temperature 169 * sensor 170 */ 171 172 {"/SYSTEM/MOTHERBOARD/CPU_0_2_MOD_SLOT/CPU_0_2_MOD_CARD", 173 "/devices/pci@9,700000/ebus@1/i2c@1,30/temperature@0,30:die_temp"}, 174 {"/SYSTEM/MOTHERBOARD/CPU_1_3_MOD_SLOT/CPU_1_3_MOD_CARD", 175 "/devices/pci@9,700000/ebus@1/i2c@1,30/temperature@0,52:die_temp"}, 176 {"/SYSTEM/SIB_BOARD", 177 "/devices/pci@9,700000/ebus@1/i2c@1,30/temperature@0,98:die_temp"}, 178 /* 179 * Check to see if RSC Card FRU is present. If it is not present, 180 * then RSC Card is not present, and so we remove those nodes from 181 * picl tree as well. 182 */ 183 {"/SYSTEM/RSC_SLOT/RSC_CARD/24C64_A6_5", 184 "/devices/pci@9,700000/ebus@1/i2c@1,30/fru@0,a6:fru"}, 185 {"/SYSTEM/RSC_SLOT/RSC_CARD", 186 "/devices/pci@9,700000/ebus@1/i2c@1,30/fru@0,a6:fru"} 187 }; 188 189 #define DEV_PR_COUNT (sizeof (dev_pr_info) / sizeof (struct node_file)) 190 191 static void init_err(char *fmt, char *arg1, char *arg2) 192 { 193 char msg[256]; 194 195 sprintf(msg, fmt, arg1, arg2); 196 syslog(LOG_ERR, msg); 197 } 198 199 void 200 psvc_psr_plugin_init(void) 201 { 202 char *funcname = "psvc_plugin_psr_init"; 203 int32_t i; 204 int err; 205 boolean_t present; 206 /* 207 * So the volatile read/write routines can retrieve data from 208 * psvc or picl 209 */ 210 err = psvc_init(&hdlp); 211 if (err != 0) { 212 init_err(PSVC_INIT_ERR, funcname, strerror(errno)); 213 214 } 215 216 /* 217 * Remove nodes whose devices aren't present from the picl tree. 218 */ 219 for (i = 0; i < psvc_hdl.obj_count; ++i) { 220 picl_psvc_t *objp; 221 uint64_t features; 222 objp = &psvc_hdl.objects[i]; 223 224 err = psvc_get_attr(hdlp, objp->name, PSVC_PRESENCE_ATTR, 225 &present); 226 if (err != PSVC_SUCCESS) 227 continue; 228 err = psvc_get_attr(hdlp, objp->name, PSVC_FEATURES_ATTR, 229 &features); 230 if (err != PSVC_SUCCESS) 231 continue; 232 if ((features & (PSVC_DEV_HOTPLUG | PSVC_DEV_OPTION)) && 233 (present == PSVC_ABSENT)) { 234 err = ptree_delete_node(objp->node); 235 if (err != 0) { 236 init_err(PTREE_DELETE_NODE_ERR, funcname, 237 picl_strerror(err)); 238 return; 239 } 240 } 241 } 242 243 /* 244 * Remove PICL device nodes if their /devices file isn't present or 245 * if the device file is present but the open returns ENXIO 246 * which indicates that the node file doesn't represent a device 247 * tree node and is probably a relic from some previous boot config 248 */ 249 for (i = 0; i < DEV_PR_COUNT; ++i) { 250 picl_nodehdl_t dev_pr_node; 251 int fd; 252 fd = open(dev_pr_info[i].file, O_RDONLY); 253 if (fd != -1) { 254 close(fd); 255 continue; 256 } 257 if ((errno != ENOENT) && (errno != ENXIO)) 258 continue; 259 260 err = ptree_get_node_by_path(dev_pr_info[i].path, &dev_pr_node); 261 if (err != 0) { 262 syslog(LOG_ERR, "Bad path: %s", dev_pr_info[i].path); 263 init_err(PTREE_GET_NODE_ERR, funcname, 264 picl_strerror(err)); 265 return; 266 } 267 268 err = ptree_delete_node(dev_pr_node); 269 if (err != 0) { 270 init_err(PTREE_DELETE_NODE_ERR, funcname, 271 picl_strerror(err)); 272 return; 273 } 274 } 275 free(psvc_hdl.objects); 276 } 277 278 void 279 psvc_psr_plugin_fini(void) 280 { 281 psvc_fini(hdlp); 282 hdlp = NULL; 283 } 284 285 void 286 psvc_psr_plugin_register(void) 287 { 288 picld_plugin_register(&psvc_psr_reg); 289 } 290