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