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