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 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/types.h> 28 #include <sys/cmn_err.h> 29 #include <sys/conf.h> 30 #include <sys/autoconf.h> 31 #include <sys/systm.h> 32 #include <sys/modctl.h> 33 #include <sys/ddi.h> 34 #include <sys/sunddi.h> 35 #include <sys/sunndi.h> 36 #include <sys/ndi_impldefs.h> 37 #include <sys/ddi_impldefs.h> 38 #include <sys/promif.h> 39 #include <sys/stat.h> 40 #include <sys/kmem.h> 41 #include <sys/promif.h> 42 #include <sys/conf.h> 43 #include <sys/obpdefs.h> 44 #include <sys/sgsbbc_mailbox.h> 45 #include <sys/cpuvar.h> 46 #include <vm/seg_kmem.h> 47 #include <sys/prom_plat.h> 48 #include <sys/machsystm.h> 49 #include <sys/cheetahregs.h> 50 51 #include <sys/sbd_ioctl.h> 52 #include <sys/sbd.h> 53 #include <sys/sbdp_priv.h> 54 55 static int sbdp_detach_nodes(attach_pkt_t *); 56 static void 57 sbdp_walk_prom_tree_worker( 58 pnode_t node, 59 int(*f)(pnode_t, void *, uint_t), 60 void *arg) 61 { 62 /* 63 * Ignore return value from callback. Return value from callback 64 * does NOT indicate subsequent walk behavior. 65 */ 66 (void) (*f)(node, arg, 0); 67 68 if (node != OBP_NONODE) { 69 sbdp_walk_prom_tree_worker(prom_childnode(node), f, arg); 70 sbdp_walk_prom_tree_worker(prom_nextnode(node), f, arg); 71 } 72 } 73 74 struct sbdp_walk_prom_tree_args { 75 pnode_t node; 76 int (*f)(pnode_t, void *, uint_t); 77 void *arg; 78 }; 79 80 /*ARGSUSED*/ 81 static int 82 sbdp_walk_prom_tree_start(void *arg, int has_changed) 83 { 84 struct sbdp_walk_prom_tree_args *argbp = arg; 85 86 sbdp_walk_prom_tree_worker(argbp->node, argbp->f, argbp->arg); 87 return (0); 88 } 89 90 void 91 sbdp_walk_prom_tree(pnode_t node, int(*f)(pnode_t, void *, uint_t), void *arg) 92 { 93 struct sbdp_walk_prom_tree_args arg_block; 94 95 arg_block.node = node; 96 arg_block.f = f; 97 arg_block.arg = arg; 98 (void) prom_tree_access(sbdp_walk_prom_tree_start, &arg_block, NULL); 99 } 100 101 static void 102 sbdp_attach_branch(dev_info_t *pdip, pnode_t node, void *arg) 103 { 104 attach_pkt_t *apktp = (attach_pkt_t *)arg; 105 pnode_t child; 106 dev_info_t *dip = NULL; 107 static int err = 0; 108 static int len = 0; 109 char name[OBP_MAXDRVNAME]; 110 #if OBP_MAXDRVNAME == OBP_MAXPROPNAME 111 #define buf name 112 #else 113 char buf[OBP_MAXPROPNAME]; 114 #endif 115 static fn_t f = "sbdp_attach_branch"; 116 117 SBDP_DBG_FUNC("%s\n", f); 118 119 if (node == OBP_NONODE) 120 return; 121 122 /* 123 * Get the status for this node 124 * If it has failed we imitate boot by not creating a node 125 * in solaris. We just warn the user 126 */ 127 if (check_status(node, buf, pdip) != DDI_SUCCESS) { 128 SBDP_DBG_STATE("status failed skipping this node\n"); 129 return; 130 } 131 132 len = prom_getproplen(node, OBP_REG); 133 if (len <= 0) { 134 return; 135 } 136 137 (void) prom_getprop(node, OBP_NAME, (caddr_t)name); 138 err = ndi_devi_alloc(pdip, name, node, &dip); 139 if (err != NDI_SUCCESS) { 140 return; 141 } 142 SBDP_DBG_STATE("attaching %s\n", name); 143 err = ndi_devi_online(dip, NDI_DEVI_BIND); 144 if (err != NDI_SUCCESS) { 145 (void) ndi_devi_free(dip); 146 return; 147 } 148 child = prom_childnode(node); 149 if (child != OBP_NONODE) { 150 for (; child != OBP_NONODE; 151 child = prom_nextnode(child)) { 152 sbdp_attach_branch(dip, child, (void *)apktp); 153 } 154 } 155 #undef buf 156 } 157 158 static int 159 sbdp_find_ssm_dip(dev_info_t *dip, void *arg) 160 { 161 attach_pkt_t *apktp; 162 int node; 163 static fn_t f = "sbdp_find_ssm_dip"; 164 165 SBDP_DBG_FUNC("%s\n", f); 166 167 apktp = (attach_pkt_t *)arg; 168 169 if (apktp == NULL) { 170 SBDP_DBG_STATE("error on the argument\n"); 171 return (DDI_WALK_CONTINUE); 172 } 173 174 if ((node = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 175 "nodeid", -1)) == -1) 176 return (DDI_WALK_CONTINUE); 177 178 if (node == apktp->node) { 179 ndi_hold_devi(dip); 180 apktp->top_node = dip; 181 return (DDI_WALK_TERMINATE); 182 } 183 return (DDI_WALK_CONTINUE); 184 } 185 186 /*ARGSUSED*/ 187 int 188 sbdp_select_top_nodes(pnode_t node, void *arg, uint_t flags) 189 { 190 int board, bd; 191 attach_pkt_t *apktp = (attach_pkt_t *)arg; 192 char devtype[OBP_MAXDRVNAME]; 193 char devname[OBP_MAXDRVNAME]; 194 int i; 195 sbd_devattr_t *sbdp_top_nodes; 196 int wnode; 197 static fn_t f = "sbdp_select_top_nodes"; 198 199 SBDP_DBG_FUNC("%s\n", f); 200 201 if (apktp == NULL) { 202 SBDP_DBG_STATE("error on the argument\n"); 203 return (DDI_FAILURE); 204 } 205 206 board = apktp->board; 207 sbdp_top_nodes = sbdp_get_devattr(); 208 209 if (sbdp_get_bd_and_wnode_num(node, &bd, &wnode) < 0) 210 return (DDI_FAILURE); 211 212 if (bd != board) 213 return (DDI_FAILURE); 214 215 SBDP_DBG_MISC("%s: board is %d\n", f, bd); 216 217 (void) prom_getprop(node, OBP_DEVICETYPE, (caddr_t)devtype); 218 (void) prom_getprop(node, OBP_NAME, (caddr_t)devname); 219 220 if (strcmp(devname, "cmp") == 0) { 221 apktp->nodes[apktp->num_of_nodes] = node; 222 apktp->num_of_nodes++; 223 224 /* We want this node */ 225 return (DDI_SUCCESS); 226 } 227 228 for (i = 0; sbdp_top_nodes[i].s_obp_type != NULL; i++) { 229 if (strcmp(devtype, sbdp_top_nodes[i].s_obp_type) == 0) { 230 if (strcmp(devtype, "cpu") == 0) { 231 int cpuid; 232 int impl; 233 234 /* 235 * Check the status of the cpu 236 * If it is failed ignore it 237 */ 238 if (sbdp_get_comp_status(node) != SBD_COND_OK) 239 return (DDI_FAILURE); 240 241 if (prom_getprop(node, "cpuid", 242 (caddr_t)&cpuid) == -1) { 243 244 if (prom_getprop(node, "portid", 245 (caddr_t)&cpuid) == -1) { 246 247 return (DDI_WALK_TERMINATE); 248 } 249 } 250 251 if (sbdp_set_cpu_present(wnode, bd, 252 SG_CPUID_TO_CPU_UNIT(cpuid)) == -1) 253 return (DDI_WALK_TERMINATE); 254 255 (void) prom_getprop(node, "implementation#", 256 (caddr_t)&impl); 257 /* 258 * If it is a CPU under CMP, don't save 259 * the node as we will be saving the CMP 260 * node. 261 */ 262 if (CPU_IMPL_IS_CMP(impl)) 263 return (DDI_FAILURE); 264 } 265 266 /* 267 * Check to make sure we haven't run out of bounds 268 */ 269 if (apktp->num_of_nodes >= SBDP_MAX_NODES) 270 return (DDI_FAILURE); 271 272 /* Save node */ 273 apktp->nodes[apktp->num_of_nodes] = node; 274 apktp->num_of_nodes++; 275 276 /* We want this node */ 277 return (DDI_SUCCESS); 278 } 279 } 280 281 return (DDI_FAILURE); 282 } 283 284 void 285 sbdp_attach_bd(int node, int board) 286 { 287 devi_branch_t b = {0}; 288 attach_pkt_t apkt, *apktp = &apkt; 289 static fn_t f = "sbdp_attach_bd"; 290 291 SBDP_DBG_FUNC("%s\n", f); 292 293 apktp->node = node; 294 apktp->board = board; 295 apktp->num_of_nodes = 0; 296 apktp->flags = 0; 297 298 apktp->top_node = NULL; 299 300 /* 301 * Root node doesn't have to be held for ddi_walk_devs() 302 */ 303 ddi_walk_devs(ddi_root_node(), sbdp_find_ssm_dip, (void *) apktp); 304 305 if (apktp->top_node == NULL) { 306 SBDP_DBG_STATE("BAD Serengeti\n"); 307 return; 308 } 309 310 b.arg = (void *)apktp; 311 b.type = DEVI_BRANCH_PROM; 312 b.create.prom_branch_select = sbdp_select_top_nodes; 313 b.devi_branch_callback = NULL; 314 315 (void) e_ddi_branch_create(apktp->top_node, &b, NULL, 0); 316 317 /* 318 * Release hold acquired in sbdp_find_ssm_dip() 319 */ 320 ndi_rele_devi(apktp->top_node); 321 322 sbdp_cpu_in_reset(node, board, SBDP_ALL_CPUS, 1); 323 } 324 325 int 326 sbdp_detach_bd(int node, int board, sbd_error_t *sep) 327 { 328 int rv; 329 attach_pkt_t apkt, *apktp = &apkt; 330 static fn_t f = "sbdp_detach_bd"; 331 332 SBDP_DBG_FUNC("%s\n", f); 333 334 apktp->node = node; 335 apktp->board = board; 336 apktp->num_of_nodes = 0; 337 apktp->error = 0; 338 apktp->errstr = NULL; 339 sbdp_walk_prom_tree(prom_rootnode(), sbdp_select_top_nodes, 340 (void *) apktp); 341 342 if (rv = sbdp_detach_nodes(apktp)) { 343 sbdp_set_err(sep, ESBD_IO, NULL); 344 return (rv); 345 } 346 347 sbdp_cpu_in_reset(node, board, SBDP_ALL_CPUS, 1); 348 /* 349 * Clean up this board struct 350 */ 351 sbdp_cleanup_bd(node, board); 352 353 return (0); 354 } 355 356 static int 357 sbdp_detach_nodes(attach_pkt_t *apktp) 358 { 359 dev_info_t **dip; 360 dev_info_t **dev_list; 361 int dev_list_len = 0; 362 int i, rv = 0; 363 364 dev_list = kmem_zalloc(sizeof (dev_info_t *) * SBDP_MAX_NODES, 365 KM_SLEEP); 366 367 for (i = 0, dip = dev_list; i < apktp->num_of_nodes; i++) { 368 *dip = e_ddi_nodeid_to_dip(apktp->nodes[i]); 369 if (*dip != NULL) { 370 /* 371 * The branch rooted at dip should already be held, 372 * so release hold acquired in e_ddi_nodeid_to_dip() 373 */ 374 ddi_release_devi(*dip); 375 dip++; 376 ++dev_list_len; 377 } 378 } 379 380 for (i = dev_list_len, dip = &dev_list[i - 1]; i > 0; i--, dip--) { 381 dev_info_t *fdip = NULL; 382 383 ASSERT(e_ddi_branch_held(*dip)); 384 rv = e_ddi_branch_destroy(*dip, &fdip, 0); 385 if (rv) { 386 char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 387 388 /* 389 * If non-NULL, fdip is held and must be released. 390 */ 391 if (fdip != NULL) { 392 (void) ddi_pathname(fdip, path); 393 ddi_release_devi(fdip); 394 } else { 395 (void) ddi_pathname(*dip, path); 396 } 397 398 cmn_err(CE_WARN, "failed to remove node %s (%p): %d", 399 path, fdip ? (void *)fdip : (void *)*dip, rv); 400 401 kmem_free(path, MAXPATHLEN); 402 403 apktp->error = apktp->error ? apktp->error : rv; 404 break; 405 } 406 } 407 408 kmem_free(dev_list, sizeof (dev_info_t *) * SBDP_MAX_NODES); 409 410 return (rv); 411 } 412