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 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * This file contains ddi functions needed during boot and DR. 30 * Many functions in swapgeneric.c can be moved here. 31 * 32 * The object file is currently linked into unix. 33 */ 34 35 #include <sys/bootconf.h> 36 #include <sys/conf.h> 37 #include <sys/ddi_impldefs.h> 38 #include <sys/ddi_implfuncs.h> 39 #include <sys/hwconf.h> 40 #include <sys/instance.h> 41 #include <sys/kmem.h> 42 #include <sys/modctl.h> 43 #include <sys/promif.h> 44 #include <sys/sunndi.h> 45 #include <sys/ndi_impldefs.h> 46 #include <sys/systeminfo.h> 47 #include <sys/hwconf.h> 48 #include <sys/sysevent_impl.h> 49 #include <sys/sunldi_impl.h> 50 #include <sys/disp.h> 51 #include <sys/bootconf.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 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")) == (major_t)-1) 136 panic("Couldn't find major number for 'rootnex'"); 137 138 size = (size_t)BOP_GETPROPLEN(bootops, "mfg-name"); 139 rootname = kmem_zalloc(size, KM_SLEEP); 140 (void) BOP_GETPROP(bootops, "mfg-name", rootname); 141 142 /* 143 * Fix conflict between OBP names and filesystem names. 144 * Substitute '_' for '/' in the name. Ick. This is only 145 * needed for the root node since '/' is not a legal name 146 * character in an OBP device name. 147 */ 148 for (cp = rootname; *cp; cp++) 149 if (*cp == '/') 150 *cp = '_'; 151 152 /* 153 * Bind rootname to rootnex driver 154 */ 155 if (make_mbind(rootname, major, NULL, mb_hashtab) != 0) { 156 cmn_err(CE_WARN, "A driver or driver alias has already " 157 "registered the name \"%s\". The root nexus needs to " 158 "use this name, and will override the existing entry. " 159 "Please correct /etc/name_to_major and/or " 160 "/etc/driver_aliases and reboot.", rootname); 161 162 /* 163 * Resort to the emergency measure of blowing away the 164 * existing hash entry and replacing it with rootname's. 165 */ 166 delete_mbind(rootname, mb_hashtab); 167 if (make_mbind(rootname, major, NULL, mb_hashtab) != 0) 168 panic("mb_hashtab: inconsistent state."); 169 } 170 171 /* 172 * The `platform' or `implementation architecture' name has been 173 * translated by boot to be proper for file system use. It is 174 * the `name' of the platform actually booted. Note the assumption 175 * is that the name will `fit' in the buffer platform (which is 176 * of size SYS_NMLN, which is far bigger than will actually ever 177 * be needed). 178 */ 179 (void) BOP_GETPROP(bootops, "impl-arch-name", platform); 180 181 #if defined(__x86) 182 /* 183 * Retrieve and honor the bootpath and optional fstype properties 184 */ 185 size = (size_t)BOP_GETPROPLEN(bootops, "bootpath"); 186 if (size != -1) { 187 bootpath_prop = kmem_zalloc(size, KM_SLEEP); 188 (void) BOP_GETPROP(bootops, "bootpath", bootpath_prop); 189 setbootpath(bootpath_prop); 190 } 191 192 size = (size_t)BOP_GETPROPLEN(bootops, "fstype"); 193 if (size != -1) { 194 fstype_prop = kmem_zalloc(size, KM_SLEEP); 195 (void) BOP_GETPROP(bootops, "fstype", fstype_prop); 196 setbootfstype(fstype_prop); 197 } 198 #endif 199 } 200 201 /* 202 * Note that this routine does not take into account the endianness 203 * of the host or the device (or PROM) when retrieving properties. 204 */ 205 static int 206 getlongprop_buf(int id, char *name, char *buf, int maxlen) 207 { 208 int size; 209 210 size = prom_getproplen((pnode_t)id, name); 211 if (size <= 0 || (size > maxlen - 1)) 212 return (-1); 213 214 if (-1 == prom_getprop((pnode_t)id, name, buf)) 215 return (-1); 216 217 /* 218 * Workaround for bugid 1085575 - OBP may return a "name" property 219 * without null terminating the string with '\0'. When this occurs, 220 * append a '\0' and return (size + 1). 221 */ 222 if (strcmp("name", name) == 0) { 223 if (buf[size - 1] != '\0') { 224 buf[size] = '\0'; 225 size += 1; 226 } 227 } 228 229 return (size); 230 } 231 232 /*ARGSUSED1*/ 233 static int 234 get_neighbors(dev_info_t *di, int flag) 235 { 236 register int nid, snid, cnid; 237 dev_info_t *parent; 238 char buf[OBP_MAXPROPNAME]; 239 240 if (di == NULL) 241 return (DDI_WALK_CONTINUE); 242 243 nid = ddi_get_nodeid(di); 244 245 snid = cnid = 0; 246 switch (flag) { 247 case DDI_WALK_PRUNESIB: 248 cnid = (int)prom_childnode((pnode_t)nid); 249 break; 250 case DDI_WALK_PRUNECHILD: 251 snid = (int)prom_nextnode((pnode_t)nid); 252 break; 253 case 0: 254 snid = (int)prom_nextnode((pnode_t)nid); 255 cnid = (int)prom_childnode((pnode_t)nid); 256 break; 257 default: 258 return (DDI_WALK_TERMINATE); 259 } 260 261 262 if (snid && (snid != -1) && ((parent = ddi_get_parent(di)) != NULL)) { 263 /* 264 * add the first sibling that passes check_status() 265 */ 266 for (; snid && (snid != -1); 267 snid = (int)prom_nextnode((pnode_t)snid)) { 268 if (getlongprop_buf(snid, OBP_NAME, buf, 269 sizeof (buf)) > 0) { 270 if (check_status(snid, buf, parent) == 271 DDI_SUCCESS) { 272 (void) ddi_add_child(parent, buf, 273 snid, -1); 274 break; 275 } 276 } 277 } 278 } 279 280 if (cnid && (cnid != -1)) { 281 /* 282 * add the first child that passes check_status() 283 */ 284 if (getlongprop_buf(cnid, OBP_NAME, buf, sizeof (buf)) > 0) { 285 if (check_status(cnid, buf, di) == DDI_SUCCESS) { 286 (void) ddi_add_child(di, buf, cnid, -1); 287 } else { 288 for (cnid = (int)prom_nextnode((pnode_t)cnid); 289 cnid && (cnid != -1); 290 cnid = (int)prom_nextnode((pnode_t)cnid)) { 291 if (getlongprop_buf(cnid, OBP_NAME, 292 buf, sizeof (buf)) > 0) { 293 if (check_status(cnid, buf, di) 294 == DDI_SUCCESS) { 295 (void) ddi_add_child( 296 di, buf, cnid, -1); 297 break; 298 } 299 } 300 } 301 } 302 } 303 } 304 305 return (DDI_WALK_CONTINUE); 306 } 307 308 static void 309 di_dfs(dev_info_t *devi, int (*f)(dev_info_t *, int), caddr_t arg) 310 { 311 (void) (*f)(devi, 0); 312 if (devi) { 313 di_dfs((dev_info_t *)DEVI(devi)->devi_child, f, arg); 314 di_dfs((dev_info_t *)DEVI(devi)->devi_sibling, f, arg); 315 } 316 } 317 318 dev_info_t * 319 i_ddi_create_branch(dev_info_t *pdip, int nid) 320 { 321 char *buf; 322 dev_info_t *dip = NULL; 323 324 if (pdip == NULL || nid == OBP_NONODE || nid == OBP_BADNODE) 325 return (NULL); 326 327 buf = kmem_alloc(OBP_MAXPROPNAME, KM_SLEEP); 328 329 if (getlongprop_buf(nid, OBP_NAME, buf, OBP_MAXPROPNAME) > 0) { 330 if (check_status(nid, buf, pdip) == DDI_SUCCESS) 331 dip = ddi_add_child(pdip, buf, nid, -1); 332 } 333 334 kmem_free(buf, OBP_MAXPROPNAME); 335 336 if (dip == NULL) 337 return (NULL); 338 339 /* 340 * Don't create any siblings of the branch root, just 341 * children. 342 */ 343 (void) get_neighbors(dip, DDI_WALK_PRUNESIB); 344 345 di_dfs(ddi_get_child(dip), get_neighbors, 0); 346 347 return (dip); 348 } 349 350 static void 351 create_devinfo_tree(void) 352 { 353 major_t major; 354 pnode_t nodeid; 355 356 i_ddi_node_cache_init(); 357 #if defined(__sparc) 358 nodeid = prom_nextnode(0); 359 #else /* x86 */ 360 nodeid = DEVI_SID_NODEID; 361 #endif 362 top_devinfo = i_ddi_alloc_node(NULL, rootname, 363 nodeid, -1, NULL, KM_SLEEP); 364 ndi_hold_devi(top_devinfo); /* never release the root */ 365 366 i_ddi_add_devimap(top_devinfo); 367 368 /* 369 * Bind root node. 370 * This code is special because root node has no parent 371 */ 372 major = ddi_name_to_major("rootnex"); 373 ASSERT(major != (major_t)-1); 374 DEVI(top_devinfo)->devi_major = major; 375 devnamesp[major].dn_head = top_devinfo; 376 i_ddi_set_binding_name(top_devinfo, rootname); 377 i_ddi_set_node_state(top_devinfo, DS_BOUND); 378 379 /* 380 * Record that devinfos have been made for "rootnex." 381 * di_dfs() is used to read the prom because it doesn't get the 382 * next sibling until the function returns, unlike ddi_walk_devs(). 383 */ 384 di_dfs(ddi_root_node(), get_neighbors, 0); 385 386 #if !defined(__sparc) 387 /* 388 * On x86, there is no prom. Create device tree by 389 * probing pci config space 390 */ 391 { 392 extern void impl_setup_ddi(void); 393 impl_setup_ddi(); 394 } 395 #endif /* x86 */ 396 } 397 398 /* 399 * Init and attach the root node. root node is the first one to be 400 * attached, so the process is somewhat "handcrafted". 401 */ 402 void 403 i_ddi_init_root() 404 { 405 #ifdef DDI_PROP_DEBUG 406 (void) ddi_prop_debug(1); /* Enable property debugging */ 407 #endif /* DDI_PROP_DEBUG */ 408 409 /* 410 * Initialize root node 411 */ 412 if (impl_ddi_sunbus_initchild(top_devinfo) != DDI_SUCCESS) 413 panic("Could not initialize root nexus"); 414 415 /* 416 * Attach root node (no need to probe) 417 * Hold both devinfo and rootnex driver so they can't go away. 418 */ 419 DEVI(top_devinfo)->devi_ops = ndi_hold_driver(top_devinfo); 420 ASSERT(DEV_OPS_HELD(DEVI(top_devinfo)->devi_ops)); 421 DEVI(top_devinfo)->devi_instance = e_ddi_assign_instance(top_devinfo); 422 423 mutex_enter(&(DEVI(top_devinfo)->devi_lock)); 424 DEVI_SET_ATTACHING(top_devinfo); 425 mutex_exit(&(DEVI(top_devinfo)->devi_lock)); 426 427 if (devi_attach(top_devinfo, DDI_ATTACH) != DDI_SUCCESS) 428 panic("Could not attach root nexus"); 429 430 mutex_enter(&(DEVI(top_devinfo)->devi_lock)); 431 DEVI_CLR_ATTACHING(top_devinfo); 432 mutex_exit(&(DEVI(top_devinfo)->devi_lock)); 433 434 mutex_init(&global_vhci_lock, NULL, MUTEX_DEFAULT, NULL); 435 436 ndi_hold_devi(top_devinfo); /* hold it forever */ 437 i_ddi_set_node_state(top_devinfo, DS_READY); 438 439 /* 440 * Now, expand .conf children of root 441 */ 442 (void) i_ndi_make_spec_children(top_devinfo, 0); 443 444 /* 445 * Must be set up before attaching root or pseudo drivers 446 */ 447 pm_init_locks(); 448 449 /* 450 * Attach options dip 451 */ 452 options_dip = i_ddi_attach_pseudo_node("options"); 453 454 /* 455 * Attach pseudo nexus and enumerate its children 456 */ 457 pseudo_dip = i_ddi_attach_pseudo_node(DEVI_PSEUDO_NEXNAME); 458 (void) i_ndi_make_spec_children(pseudo_dip, 0); 459 460 /* 461 * Attach and hold clone dip 462 */ 463 clone_dip = i_ddi_attach_pseudo_node("clone"); 464 clone_major = ddi_driver_major(clone_dip); 465 mm_major = ddi_name_to_major("mm"); 466 467 /* 468 * Attach scsi_vhci for MPXIO, this registers scsi vhci class 469 * with the MPXIO framework. 470 */ 471 scsi_vhci_dip = i_ddi_attach_pseudo_node("scsi_vhci"); 472 } 473