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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 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/fm/util.h> 53 54 extern dev_info_t *top_devinfo; 55 extern dev_info_t *scsi_vhci_dip; 56 extern struct hwc_class *hcl_head; 57 static char *rootname; /* node name of top_devinfo */ 58 59 /* 60 * This lock must be held while updating devi_sibling pointers of 61 * rootnex immediate children 62 */ 63 kmutex_t global_vhci_lock; 64 65 major_t mm_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 93 (void) i_ddi_load_drvconf((major_t)-1); 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 extern struct bootops *bootops; 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")) == (major_t)-1) 137 panic("Couldn't find major number for 'rootnex'"); 138 139 size = (size_t)BOP_GETPROPLEN(bootops, "mfg-name"); 140 rootname = kmem_zalloc(size, KM_SLEEP); 141 (void) BOP_GETPROP(bootops, "mfg-name", rootname); 142 143 /* 144 * Fix conflict between OBP names and filesystem names. 145 * Substitute '_' for '/' in the name. Ick. This is only 146 * needed for the root node since '/' is not a legal name 147 * character in an OBP device name. 148 */ 149 for (cp = rootname; *cp; cp++) 150 if (*cp == '/') 151 *cp = '_'; 152 153 /* 154 * Bind rootname to rootnex driver 155 */ 156 if (make_mbind(rootname, major, NULL, mb_hashtab) != 0) { 157 cmn_err(CE_WARN, "A driver or driver alias has already " 158 "registered the name \"%s\". The root nexus needs to " 159 "use this name, and will override the existing entry. " 160 "Please correct /etc/name_to_major and/or " 161 "/etc/driver_aliases and reboot.", rootname); 162 163 /* 164 * Resort to the emergency measure of blowing away the 165 * existing hash entry and replacing it with rootname's. 166 */ 167 delete_mbind(rootname, mb_hashtab); 168 if (make_mbind(rootname, major, NULL, mb_hashtab) != 0) 169 panic("mb_hashtab: inconsistent state."); 170 } 171 172 /* 173 * The `platform' or `implementation architecture' name has been 174 * translated by boot to be proper for file system use. It is 175 * the `name' of the platform actually booted. Note the assumption 176 * is that the name will `fit' in the buffer platform (which is 177 * of size SYS_NMLN, which is far bigger than will actually ever 178 * be needed). 179 */ 180 (void) BOP_GETPROP(bootops, "impl-arch-name", platform); 181 182 #if defined(__x86) 183 /* 184 * Retrieve and honor the bootpath and optional fstype properties 185 */ 186 size = (size_t)BOP_GETPROPLEN(bootops, "bootpath"); 187 if (size != -1) { 188 bootpath_prop = kmem_zalloc(size, KM_SLEEP); 189 (void) BOP_GETPROP(bootops, "bootpath", bootpath_prop); 190 setbootpath(bootpath_prop); 191 } 192 193 size = (size_t)BOP_GETPROPLEN(bootops, "fstype"); 194 if (size != -1) { 195 fstype_prop = kmem_zalloc(size, KM_SLEEP); 196 (void) BOP_GETPROP(bootops, "fstype", fstype_prop); 197 setbootfstype(fstype_prop); 198 } 199 #endif 200 } 201 202 /* 203 * Note that this routine does not take into account the endianness 204 * of the host or the device (or PROM) when retrieving properties. 205 */ 206 static int 207 getlongprop_buf(int id, char *name, char *buf, int maxlen) 208 { 209 int size; 210 211 size = prom_getproplen((dnode_t)id, name); 212 if (size <= 0 || (size > maxlen - 1)) 213 return (-1); 214 215 if (-1 == prom_getprop((dnode_t)id, name, buf)) 216 return (-1); 217 218 /* 219 * Workaround for bugid 1085575 - OBP may return a "name" property 220 * without null terminating the string with '\0'. When this occurs, 221 * append a '\0' and return (size + 1). 222 */ 223 if (strcmp("name", name) == 0) { 224 if (buf[size - 1] != '\0') { 225 buf[size] = '\0'; 226 size += 1; 227 } 228 } 229 230 return (size); 231 } 232 233 /*ARGSUSED1*/ 234 static int 235 get_neighbors(dev_info_t *di, int flag) 236 { 237 register int nid, snid, cnid; 238 dev_info_t *parent; 239 char buf[OBP_MAXPROPNAME]; 240 241 if (di == NULL) 242 return (DDI_WALK_CONTINUE); 243 244 nid = ddi_get_nodeid(di); 245 246 snid = cnid = 0; 247 switch (flag) { 248 case DDI_WALK_PRUNESIB: 249 cnid = (int)prom_childnode((dnode_t)nid); 250 break; 251 case DDI_WALK_PRUNECHILD: 252 snid = (int)prom_nextnode((dnode_t)nid); 253 break; 254 case 0: 255 snid = (int)prom_nextnode((dnode_t)nid); 256 cnid = (int)prom_childnode((dnode_t)nid); 257 break; 258 default: 259 return (DDI_WALK_TERMINATE); 260 } 261 262 263 if (snid && (snid != -1) && ((parent = ddi_get_parent(di)) != NULL)) { 264 /* 265 * add the first sibling that passes check_status() 266 */ 267 for (; snid && (snid != -1); 268 snid = (int)prom_nextnode((dnode_t)snid)) { 269 if (getlongprop_buf(snid, OBP_NAME, buf, 270 sizeof (buf)) > 0) { 271 if (check_status(snid, buf, parent) == 272 DDI_SUCCESS) { 273 (void) ddi_add_child(parent, buf, 274 snid, -1); 275 break; 276 } 277 } 278 } 279 } 280 281 if (cnid && (cnid != -1)) { 282 /* 283 * add the first child that passes check_status() 284 */ 285 if (getlongprop_buf(cnid, OBP_NAME, buf, sizeof (buf)) > 0) { 286 if (check_status(cnid, buf, di) == DDI_SUCCESS) { 287 (void) ddi_add_child(di, buf, cnid, -1); 288 } else { 289 for (cnid = (int)prom_nextnode((dnode_t)cnid); 290 cnid && (cnid != -1); 291 cnid = (int)prom_nextnode((dnode_t)cnid)) { 292 if (getlongprop_buf(cnid, OBP_NAME, 293 buf, sizeof (buf)) > 0) { 294 if (check_status(cnid, buf, di) 295 == DDI_SUCCESS) { 296 (void) ddi_add_child( 297 di, buf, cnid, -1); 298 break; 299 } 300 } 301 } 302 } 303 } 304 } 305 306 return (DDI_WALK_CONTINUE); 307 } 308 309 static void 310 di_dfs(dev_info_t *devi, int (*f)(dev_info_t *, int), caddr_t arg) 311 { 312 (void) (*f)(devi, 0); 313 if (devi) { 314 di_dfs((dev_info_t *)DEVI(devi)->devi_child, f, arg); 315 di_dfs((dev_info_t *)DEVI(devi)->devi_sibling, f, arg); 316 } 317 } 318 319 dev_info_t * 320 i_ddi_create_branch(dev_info_t *pdip, int nid) 321 { 322 char *buf; 323 dev_info_t *dip = NULL; 324 325 if (pdip == NULL || nid == OBP_NONODE || nid == OBP_BADNODE) 326 return (NULL); 327 328 buf = kmem_alloc(OBP_MAXPROPNAME, KM_SLEEP); 329 330 if (getlongprop_buf(nid, OBP_NAME, buf, OBP_MAXPROPNAME) > 0) { 331 if (check_status(nid, buf, pdip) == DDI_SUCCESS) 332 dip = ddi_add_child(pdip, buf, nid, -1); 333 } 334 335 kmem_free(buf, OBP_MAXPROPNAME); 336 337 if (dip == NULL) 338 return (NULL); 339 340 /* 341 * Don't create any siblings of the branch root, just 342 * children. 343 */ 344 (void) get_neighbors(dip, DDI_WALK_PRUNESIB); 345 346 di_dfs(ddi_get_child(dip), get_neighbors, 0); 347 348 return (dip); 349 } 350 351 static void 352 create_devinfo_tree(void) 353 { 354 major_t major; 355 dnode_t nodeid; 356 357 i_ddi_node_cache_init(); 358 #if defined(__sparc) 359 nodeid = prom_nextnode(0); 360 #else /* x86 */ 361 nodeid = DEVI_SID_NODEID; 362 #endif 363 top_devinfo = i_ddi_alloc_node(NULL, rootname, 364 nodeid, -1, NULL, KM_SLEEP); 365 ndi_hold_devi(top_devinfo); /* never release the root */ 366 367 i_ddi_add_devimap(top_devinfo); 368 369 /* 370 * Bind root node. 371 * This code is special because root node has no parent 372 */ 373 major = ddi_name_to_major("rootnex"); 374 ASSERT(major != (major_t)-1); 375 DEVI(top_devinfo)->devi_major = major; 376 devnamesp[major].dn_head = top_devinfo; 377 i_ddi_set_binding_name(top_devinfo, rootname); 378 i_ddi_set_node_state(top_devinfo, DS_BOUND); 379 380 /* 381 * Record that devinfos have been made for "rootnex." 382 * di_dfs() is used to read the prom because it doesn't get the 383 * next sibling until the function returns, unlike ddi_walk_devs(). 384 */ 385 di_dfs(ddi_root_node(), get_neighbors, 0); 386 } 387 388 /* 389 * Init and attach the root node. root node is the first one to be 390 * attached, so the process is somewhat "handcrafted". 391 */ 392 void 393 i_ddi_init_root() 394 { 395 extern int i_ndi_make_spec_children(dev_info_t *, uint_t); 396 397 #ifdef DDI_PROP_DEBUG 398 (void) ddi_prop_debug(1); /* Enable property debugging */ 399 #endif /* DDI_PROP_DEBUG */ 400 401 /* 402 * Initialize root node 403 */ 404 if (impl_ddi_sunbus_initchild(top_devinfo) != DDI_SUCCESS) 405 panic("Could not initialize root nexus"); 406 407 /* 408 * Attach root node (no need to probe) 409 * Hold both devinfo and rootnex driver so they can't go away. 410 */ 411 DEVI(top_devinfo)->devi_ops = ndi_hold_driver(top_devinfo); 412 ASSERT(DEV_OPS_HELD(DEVI(top_devinfo)->devi_ops)); 413 DEVI(top_devinfo)->devi_instance = e_ddi_assign_instance(top_devinfo); 414 415 DEVI_SET_ATTACHING(top_devinfo); 416 if (devi_attach(top_devinfo, DDI_ATTACH) != DDI_SUCCESS) 417 panic("Could not attach root nexus"); 418 DEVI_CLR_ATTACHING(top_devinfo); 419 420 mutex_init(&global_vhci_lock, NULL, MUTEX_DEFAULT, NULL); 421 422 ndi_hold_devi(top_devinfo); /* hold it forever */ 423 i_ddi_set_node_state(top_devinfo, DS_READY); 424 425 /* 426 * Now, expand .conf children of root 427 */ 428 (void) i_ndi_make_spec_children(top_devinfo, 0); 429 430 /* 431 * Must be set up before attaching root or pseudo drivers 432 */ 433 pm_init_locks(); 434 435 /* 436 * Attach options dip 437 */ 438 options_dip = i_ddi_attach_pseudo_node("options"); 439 440 /* 441 * Attach pseudo nexus and enumerate its children 442 */ 443 pseudo_dip = i_ddi_attach_pseudo_node(DEVI_PSEUDO_NEXNAME); 444 (void) i_ndi_make_spec_children(pseudo_dip, 0); 445 446 /* 447 * Attach and hold clone dip 448 */ 449 clone_dip = i_ddi_attach_pseudo_node("clone"); 450 clone_major = ddi_driver_major(clone_dip); 451 mm_major = ddi_name_to_major("mm"); 452 453 /* 454 * Attach scsi_vhci for MPXIO, this registers scsi vhci class 455 * with the MPXIO framework. 456 */ 457 scsi_vhci_dip = i_ddi_attach_pseudo_node("scsi_vhci"); 458 } 459