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