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