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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * This file contains ddi functions needed during boot and DR. 28 * Many functions in swapgeneric.c can be moved here. 29 * 30 * The object file is currently linked into unix. 31 */ 32 33 #include <sys/bootconf.h> 34 #include <sys/conf.h> 35 #include <sys/ddi_impldefs.h> 36 #include <sys/ddi_implfuncs.h> 37 #include <sys/hwconf.h> 38 #include <sys/instance.h> 39 #include <sys/kmem.h> 40 #include <sys/modctl.h> 41 #include <sys/promif.h> 42 #include <sys/sunndi.h> 43 #include <sys/ndi_impldefs.h> 44 #include <sys/systeminfo.h> 45 #include <sys/hwconf.h> 46 #include <sys/sysevent_impl.h> 47 #include <sys/sunldi_impl.h> 48 #include <sys/disp.h> 49 #include <sys/bootconf.h> 50 #include <sys/fm/util.h> 51 #include <sys/ddifm_impl.h> 52 53 extern dev_info_t *top_devinfo; 54 extern dev_info_t *scsi_vhci_dip; 55 extern struct hwc_class *hcl_head; 56 static char *rootname; /* node name of top_devinfo */ 57 58 /* 59 * This lock must be held while updating devi_sibling pointers of 60 * rootnex immediate children 61 */ 62 kmutex_t global_vhci_lock; 63 64 major_t mm_major; 65 major_t nulldriver_major; 66 67 /* 68 * Forward declarations 69 */ 70 static void impl_create_root_class(void); 71 static void create_devinfo_tree(void); 72 73 #if defined(__x86) 74 char *bootpath_prop = NULL; 75 char *fstype_prop = NULL; 76 #endif 77 78 /* 79 * Setup the DDI but don't necessarily init the DDI. This will happen 80 * later once /boot is released. 81 */ 82 void 83 setup_ddi(void) 84 { 85 impl_ddi_init_nodeid(); 86 impl_create_root_class(); 87 create_devinfo_tree(); 88 e_ddi_instance_init(); 89 impl_ddi_callback_init(); 90 log_event_init(); 91 fm_init(); 92 ndi_fm_init(); 93 irm_init(); 94 95 (void) i_ddi_load_drvconf(DDI_MAJOR_T_NONE); 96 97 ldi_init(); 98 99 i_ddi_devices_init(); 100 i_ddi_read_devices_files(); 101 } 102 103 /* 104 * Perform setup actions post startup (i_ddi_io_initialized) 105 */ 106 void 107 setup_ddi_poststartup(void) 108 { 109 extern void i_ddi_start_flush_daemon(void); 110 extern void i_ddi_irm_poststartup(void); 111 extern void i_ddi_intr_redist_all_cpus(void); 112 113 i_ddi_start_flush_daemon(); 114 115 /* Startup Interrupt Resource Management (IRM) */ 116 i_ddi_irm_poststartup(); 117 118 /* 119 * For platforms that support INTR_WEIGHTED_DIST, we perform a 120 * redistribution at this point (after NICs configured) so that 121 * "isolation" relative to "ddi-intr-weight" occurs. 122 */ 123 i_ddi_intr_redist_all_cpus(); 124 } 125 126 /* 127 * Create classes and major number bindings for the name of my root. 128 * Called immediately before 'loadrootmodules' 129 */ 130 static void 131 impl_create_root_class(void) 132 { 133 major_t major; 134 size_t size; 135 char *cp; 136 137 /* 138 * The name for the root nexus is exactly as the manufacturer 139 * placed it in the prom name property. No translation. 140 */ 141 if ((major = ddi_name_to_major("rootnex")) == DDI_MAJOR_T_NONE) 142 panic("Couldn't find major number for 'rootnex'"); 143 144 /* 145 * C OBP (Serengeti) does not include the NULL when returning 146 * the length of the name property, while this violates 1275, 147 * Solaris needs to work around this by allocating space for 148 * an extra character. 149 */ 150 size = (size_t)BOP_GETPROPLEN(bootops, "mfg-name") + 1; 151 rootname = kmem_zalloc(size, KM_SLEEP); 152 (void) BOP_GETPROP(bootops, "mfg-name", rootname); 153 154 /* 155 * Fix conflict between OBP names and filesystem names. 156 * Substitute '_' for '/' in the name. Ick. This is only 157 * needed for the root node since '/' is not a legal name 158 * character in an OBP device name. 159 */ 160 for (cp = rootname; *cp; cp++) 161 if (*cp == '/') 162 *cp = '_'; 163 164 /* 165 * Bind rootname to rootnex driver 166 */ 167 if (make_mbind(rootname, major, NULL, mb_hashtab) != 0) { 168 cmn_err(CE_WARN, "A driver or driver alias has already " 169 "registered the name \"%s\". The root nexus needs to " 170 "use this name, and will override the existing entry. " 171 "Please correct /etc/name_to_major and/or " 172 "/etc/driver_aliases and reboot.", rootname); 173 174 /* 175 * Resort to the emergency measure of blowing away the 176 * existing hash entry and replacing it with rootname's. 177 */ 178 delete_mbind(rootname, mb_hashtab); 179 if (make_mbind(rootname, major, NULL, mb_hashtab) != 0) 180 panic("mb_hashtab: inconsistent state."); 181 } 182 183 /* 184 * The `platform' or `implementation architecture' name has been 185 * translated by boot to be proper for file system use. It is 186 * the `name' of the platform actually booted. Note the assumption 187 * is that the name will `fit' in the buffer platform (which is 188 * of size SYS_NMLN, which is far bigger than will actually ever 189 * be needed). 190 */ 191 (void) BOP_GETPROP(bootops, "impl-arch-name", platform); 192 193 #if defined(__x86) 194 /* 195 * Retrieve and honor the bootpath and optional fstype properties 196 */ 197 size = (size_t)BOP_GETPROPLEN(bootops, "bootpath"); 198 if (size != -1) { 199 bootpath_prop = kmem_zalloc(size, KM_SLEEP); 200 (void) BOP_GETPROP(bootops, "bootpath", bootpath_prop); 201 setbootpath(bootpath_prop); 202 } 203 204 size = (size_t)BOP_GETPROPLEN(bootops, "fstype"); 205 if (size != -1) { 206 fstype_prop = kmem_zalloc(size, KM_SLEEP); 207 (void) BOP_GETPROP(bootops, "fstype", fstype_prop); 208 setbootfstype(fstype_prop); 209 } 210 #endif 211 } 212 213 /* 214 * Note that this routine does not take into account the endianness 215 * of the host or the device (or PROM) when retrieving properties. 216 */ 217 static int 218 getlongprop_buf(int id, char *name, char *buf, int maxlen) 219 { 220 int size; 221 222 size = prom_getproplen((pnode_t)id, name); 223 if (size <= 0 || (size > maxlen - 1)) 224 return (-1); 225 226 if (-1 == prom_getprop((pnode_t)id, name, buf)) 227 return (-1); 228 229 /* 230 * Workaround for bugid 1085575 - OBP may return a "name" property 231 * without null terminating the string with '\0'. When this occurs, 232 * append a '\0' and return (size + 1). 233 */ 234 if (strcmp("name", name) == 0) { 235 if (buf[size - 1] != '\0') { 236 buf[size] = '\0'; 237 size += 1; 238 } 239 } 240 241 return (size); 242 } 243 244 /*ARGSUSED1*/ 245 static int 246 get_neighbors(dev_info_t *di, int flag) 247 { 248 register int nid, snid, cnid; 249 dev_info_t *parent; 250 char buf[OBP_MAXPROPNAME]; 251 252 if (di == NULL) 253 return (DDI_WALK_CONTINUE); 254 255 nid = ddi_get_nodeid(di); 256 257 snid = cnid = 0; 258 switch (flag) { 259 case DDI_WALK_PRUNESIB: 260 cnid = (int)prom_childnode((pnode_t)nid); 261 break; 262 case DDI_WALK_PRUNECHILD: 263 snid = (int)prom_nextnode((pnode_t)nid); 264 break; 265 case 0: 266 snid = (int)prom_nextnode((pnode_t)nid); 267 cnid = (int)prom_childnode((pnode_t)nid); 268 break; 269 default: 270 return (DDI_WALK_TERMINATE); 271 } 272 273 274 if (snid && (snid != -1) && ((parent = ddi_get_parent(di)) != NULL)) { 275 /* 276 * add the first sibling that passes check_status() 277 */ 278 for (; snid && (snid != -1); 279 snid = (int)prom_nextnode((pnode_t)snid)) { 280 if (getlongprop_buf(snid, OBP_NAME, buf, 281 sizeof (buf)) > 0) { 282 if (check_status(snid, buf, parent) == 283 DDI_SUCCESS) { 284 (void) ddi_add_child(parent, buf, 285 snid, -1); 286 break; 287 } 288 } 289 } 290 } 291 292 if (cnid && (cnid != -1)) { 293 /* 294 * add the first child that passes check_status() 295 */ 296 if (getlongprop_buf(cnid, OBP_NAME, buf, sizeof (buf)) > 0) { 297 if (check_status(cnid, buf, di) == DDI_SUCCESS) { 298 (void) ddi_add_child(di, buf, cnid, -1); 299 } else { 300 for (cnid = (int)prom_nextnode((pnode_t)cnid); 301 cnid && (cnid != -1); 302 cnid = (int)prom_nextnode((pnode_t)cnid)) { 303 if (getlongprop_buf(cnid, OBP_NAME, 304 buf, sizeof (buf)) > 0) { 305 if (check_status(cnid, buf, di) 306 == DDI_SUCCESS) { 307 (void) ddi_add_child( 308 di, buf, cnid, -1); 309 break; 310 } 311 } 312 } 313 } 314 } 315 } 316 317 return (DDI_WALK_CONTINUE); 318 } 319 320 static void 321 di_dfs(dev_info_t *devi, int (*f)(dev_info_t *, int), caddr_t arg) 322 { 323 (void) (*f)(devi, 0); 324 if (devi) { 325 di_dfs((dev_info_t *)DEVI(devi)->devi_child, f, arg); 326 di_dfs((dev_info_t *)DEVI(devi)->devi_sibling, f, arg); 327 } 328 } 329 330 dev_info_t * 331 i_ddi_create_branch(dev_info_t *pdip, int nid) 332 { 333 char *buf; 334 dev_info_t *dip = NULL; 335 336 if (pdip == NULL || nid == OBP_NONODE || nid == OBP_BADNODE) 337 return (NULL); 338 339 buf = kmem_alloc(OBP_MAXPROPNAME, KM_SLEEP); 340 341 if (getlongprop_buf(nid, OBP_NAME, buf, OBP_MAXPROPNAME) > 0) { 342 if (check_status(nid, buf, pdip) == DDI_SUCCESS) 343 dip = ddi_add_child(pdip, buf, nid, -1); 344 } 345 346 kmem_free(buf, OBP_MAXPROPNAME); 347 348 if (dip == NULL) 349 return (NULL); 350 351 /* 352 * Don't create any siblings of the branch root, just 353 * children. 354 */ 355 (void) get_neighbors(dip, DDI_WALK_PRUNESIB); 356 357 di_dfs(ddi_get_child(dip), get_neighbors, 0); 358 359 return (dip); 360 } 361 362 static void 363 create_devinfo_tree(void) 364 { 365 major_t major; 366 pnode_t nodeid; 367 368 i_ddi_node_cache_init(); 369 #if defined(__sparc) 370 nodeid = prom_nextnode(0); 371 #else /* x86 */ 372 nodeid = DEVI_SID_NODEID; 373 #endif 374 top_devinfo = i_ddi_alloc_node(NULL, rootname, 375 nodeid, -1, NULL, KM_SLEEP); 376 ndi_hold_devi(top_devinfo); /* never release the root */ 377 378 i_ddi_add_devimap(top_devinfo); 379 380 /* 381 * Bind root node. 382 * This code is special because root node has no parent 383 */ 384 major = ddi_name_to_major("rootnex"); 385 ASSERT(major != DDI_MAJOR_T_NONE); 386 DEVI(top_devinfo)->devi_major = major; 387 devnamesp[major].dn_head = top_devinfo; 388 i_ddi_set_binding_name(top_devinfo, rootname); 389 i_ddi_set_node_state(top_devinfo, DS_BOUND); 390 391 /* 392 * Record that devinfos have been made for "rootnex." 393 * di_dfs() is used to read the prom because it doesn't get the 394 * next sibling until the function returns, unlike ddi_walk_devs(). 395 */ 396 di_dfs(ddi_root_node(), get_neighbors, 0); 397 398 #if !defined(__sparc) 399 /* 400 * On x86, there is no prom. Create device tree by 401 * probing pci config space 402 */ 403 { 404 extern void impl_setup_ddi(void); 405 impl_setup_ddi(); 406 } 407 #endif /* x86 */ 408 } 409 410 /* 411 * Init and attach the root node. root node is the first one to be 412 * attached, so the process is somewhat "handcrafted". 413 */ 414 void 415 i_ddi_init_root() 416 { 417 #ifdef DDI_PROP_DEBUG 418 (void) ddi_prop_debug(1); /* Enable property debugging */ 419 #endif /* DDI_PROP_DEBUG */ 420 421 /* 422 * Initialize root node 423 */ 424 if (impl_ddi_sunbus_initchild(top_devinfo) != DDI_SUCCESS) 425 panic("Could not initialize root nexus"); 426 427 /* 428 * Attach root node (no need to probe) 429 * Hold both devinfo and rootnex driver so they can't go away. 430 */ 431 DEVI(top_devinfo)->devi_ops = ndi_hold_driver(top_devinfo); 432 ASSERT(DEV_OPS_HELD(DEVI(top_devinfo)->devi_ops)); 433 DEVI(top_devinfo)->devi_instance = e_ddi_assign_instance(top_devinfo); 434 435 (void) i_ddi_load_drvconf(DEVI(top_devinfo)->devi_major); 436 437 mutex_enter(&(DEVI(top_devinfo)->devi_lock)); 438 DEVI_SET_ATTACHING(top_devinfo); 439 mutex_exit(&(DEVI(top_devinfo)->devi_lock)); 440 441 if (devi_attach(top_devinfo, DDI_ATTACH) != DDI_SUCCESS) 442 panic("Could not attach root nexus"); 443 444 mutex_enter(&(DEVI(top_devinfo)->devi_lock)); 445 DEVI_CLR_ATTACHING(top_devinfo); 446 mutex_exit(&(DEVI(top_devinfo)->devi_lock)); 447 448 mutex_init(&global_vhci_lock, NULL, MUTEX_DEFAULT, NULL); 449 450 ndi_hold_devi(top_devinfo); /* hold it forever */ 451 i_ddi_set_node_state(top_devinfo, DS_READY); 452 453 /* 454 * Now, expand .conf children of root 455 */ 456 (void) i_ndi_make_spec_children(top_devinfo, 0); 457 458 /* 459 * Must be set up before attaching root or pseudo drivers 460 */ 461 pm_init_locks(); 462 463 /* 464 * Attach options dip 465 */ 466 options_dip = i_ddi_attach_pseudo_node("options"); 467 468 /* 469 * Attach pseudo nexus and enumerate its children 470 */ 471 pseudo_dip = i_ddi_attach_pseudo_node(DEVI_PSEUDO_NEXNAME); 472 (void) i_ndi_make_spec_children(pseudo_dip, 0); 473 474 /* 475 * Attach and hold clone dip 476 */ 477 clone_dip = i_ddi_attach_pseudo_node("clone"); 478 clone_major = ddi_driver_major(clone_dip); 479 mm_major = ddi_name_to_major("mm"); 480 nulldriver_major = ddi_name_to_major("nulldriver"); 481 482 /* 483 * Attach scsi_vhci for MPXIO, this registers scsi vhci class 484 * with the MPXIO framework. 485 */ 486 scsi_vhci_dip = i_ddi_attach_pseudo_node("scsi_vhci"); 487 } 488