17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 548aa2e6aSseb * Common Development and Distribution License (the "License"). 648aa2e6aSseb * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* ONC_PLUS EXTRACT START */ 227c478bd9Sstevel@tonic-gate /* 23*f4da9be0Scth * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate /* ONC_PLUS EXTRACT END */ 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate /* 317c478bd9Sstevel@tonic-gate * Configure root, swap and dump devices. 327c478bd9Sstevel@tonic-gate */ 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate #include <sys/types.h> 357c478bd9Sstevel@tonic-gate #include <sys/param.h> 367c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 377c478bd9Sstevel@tonic-gate #include <sys/signal.h> 387c478bd9Sstevel@tonic-gate #include <sys/cred.h> 397c478bd9Sstevel@tonic-gate #include <sys/proc.h> 407c478bd9Sstevel@tonic-gate #include <sys/user.h> 417c478bd9Sstevel@tonic-gate #include <sys/conf.h> 427c478bd9Sstevel@tonic-gate #include <sys/buf.h> 437c478bd9Sstevel@tonic-gate #include <sys/systm.h> 447c478bd9Sstevel@tonic-gate #include <sys/vm.h> 457c478bd9Sstevel@tonic-gate #include <sys/reboot.h> 467c478bd9Sstevel@tonic-gate #include <sys/file.h> 477c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 487c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 497c478bd9Sstevel@tonic-gate #include <sys/errno.h> 507c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 517c478bd9Sstevel@tonic-gate #include <sys/uio.h> 527c478bd9Sstevel@tonic-gate #include <sys/open.h> 537c478bd9Sstevel@tonic-gate #include <sys/mount.h> 547c478bd9Sstevel@tonic-gate #include <sys/kobj.h> 557c478bd9Sstevel@tonic-gate #include <sys/bootconf.h> 567c478bd9Sstevel@tonic-gate #include <sys/sysconf.h> 577c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 587c478bd9Sstevel@tonic-gate #include <sys/autoconf.h> 597c478bd9Sstevel@tonic-gate #include <sys/debug.h> 607c478bd9Sstevel@tonic-gate #include <sys/fs/snode.h> 617c478bd9Sstevel@tonic-gate #include <fs/fs_subr.h> 627c478bd9Sstevel@tonic-gate #include <sys/socket.h> 637c478bd9Sstevel@tonic-gate #include <net/if.h> 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate #include <sys/mkdev.h> 667c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 677c478bd9Sstevel@tonic-gate #include <sys/console.h> 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate #include <sys/conf.h> 707c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 717c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 727c478bd9Sstevel@tonic-gate #include <sys/hwconf.h> 737c478bd9Sstevel@tonic-gate #include <sys/dc_ki.h> 747c478bd9Sstevel@tonic-gate #include <sys/promif.h> 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate /* 787c478bd9Sstevel@tonic-gate * Local routines 797c478bd9Sstevel@tonic-gate */ 807c478bd9Sstevel@tonic-gate static int preload_module(struct sysparam *, void *); 817c478bd9Sstevel@tonic-gate static struct vfssw *getfstype(char *, char *, size_t); 827c478bd9Sstevel@tonic-gate static int getphysdev(char *, char *, size_t); 837c478bd9Sstevel@tonic-gate static int load_bootpath_drivers(char *bootpath); 847c478bd9Sstevel@tonic-gate static int load_boot_driver(char *drv); 857c478bd9Sstevel@tonic-gate static int load_boot_platform_modules(char *drv); 867c478bd9Sstevel@tonic-gate static dev_info_t *path_to_devinfo(char *path); 877c478bd9Sstevel@tonic-gate static boolean_t netboot_over_ib(char *bootpath); 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate /* 917c478bd9Sstevel@tonic-gate * Module linkage information for the kernel. 927c478bd9Sstevel@tonic-gate */ 937c478bd9Sstevel@tonic-gate static struct modlmisc modlmisc = { 947c478bd9Sstevel@tonic-gate &mod_miscops, "root and swap configuration %I%" 957c478bd9Sstevel@tonic-gate }; 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 987c478bd9Sstevel@tonic-gate MODREV_1, (void *)&modlmisc, NULL 997c478bd9Sstevel@tonic-gate }; 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate int 1027c478bd9Sstevel@tonic-gate _init(void) 1037c478bd9Sstevel@tonic-gate { 1047c478bd9Sstevel@tonic-gate return (mod_install(&modlinkage)); 1057c478bd9Sstevel@tonic-gate } 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate int 1087c478bd9Sstevel@tonic-gate _fini(void) 1097c478bd9Sstevel@tonic-gate { 1107c478bd9Sstevel@tonic-gate return (mod_remove(&modlinkage)); 1117c478bd9Sstevel@tonic-gate } 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate int 1147c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 1157c478bd9Sstevel@tonic-gate { 1167c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 1177c478bd9Sstevel@tonic-gate } 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate /* 1207c478bd9Sstevel@tonic-gate * Configure root file system. 1217c478bd9Sstevel@tonic-gate */ 1227c478bd9Sstevel@tonic-gate int 1237c478bd9Sstevel@tonic-gate rootconf(void) 1247c478bd9Sstevel@tonic-gate { 1257c478bd9Sstevel@tonic-gate int error; 1267c478bd9Sstevel@tonic-gate struct vfssw *vsw; 1277c478bd9Sstevel@tonic-gate extern void pm_init(void); 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate BMDPRINTF(("rootconf: fstype %s\n", rootfs.bo_fstype)); 1307c478bd9Sstevel@tonic-gate BMDPRINTF(("rootconf: name %s\n", rootfs.bo_name)); 1317c478bd9Sstevel@tonic-gate BMDPRINTF(("rootconf: flags 0x%x\n", rootfs.bo_flags)); 1327c478bd9Sstevel@tonic-gate BMDPRINTF(("rootconf: obp_bootpath %s\n", obp_bootpath)); 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate /* 1357c478bd9Sstevel@tonic-gate * Install cluster modules that were only loaded during 1367c478bd9Sstevel@tonic-gate * loadrootmodules(). 1377c478bd9Sstevel@tonic-gate */ 1387c478bd9Sstevel@tonic-gate if (error = clboot_rootconf()) 1397c478bd9Sstevel@tonic-gate return (error); 1407c478bd9Sstevel@tonic-gate 1417c478bd9Sstevel@tonic-gate if (root_is_svm) { 1427c478bd9Sstevel@tonic-gate (void) strncpy(rootfs.bo_name, obp_bootpath, BO_MAXOBJNAME); 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate BMDPRINTF(("rootconf: svm: rootfs name %s\n", rootfs.bo_name)); 1457c478bd9Sstevel@tonic-gate BMDPRINTF(("rootconf: svm: svm name %s\n", svm_bootpath)); 1467c478bd9Sstevel@tonic-gate } 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate /* 1497c478bd9Sstevel@tonic-gate * Run _init on the root filesystem (we already loaded it 1507c478bd9Sstevel@tonic-gate * but we've been waiting until now to _init it) which will 1517c478bd9Sstevel@tonic-gate * have the side-effect of running vsw_init() on this vfs. 1527c478bd9Sstevel@tonic-gate * Because all the nfs filesystems are lumped into one 1537c478bd9Sstevel@tonic-gate * module we need to special case it. 1547c478bd9Sstevel@tonic-gate */ 1557c478bd9Sstevel@tonic-gate if (strncmp(rootfs.bo_fstype, "nfs", 3) == 0) { 1567c478bd9Sstevel@tonic-gate if (modload("fs", "nfs") == -1) { 1577c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "Cannot initialize %s filesystem\n", 1587c478bd9Sstevel@tonic-gate rootfs.bo_fstype); 1597c478bd9Sstevel@tonic-gate return (ENXIO); 1607c478bd9Sstevel@tonic-gate } 1617c478bd9Sstevel@tonic-gate } else { 1627c478bd9Sstevel@tonic-gate if (modload("fs", rootfs.bo_fstype) == -1) { 1637c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "Cannot initialize %s filesystem\n", 1647c478bd9Sstevel@tonic-gate rootfs.bo_fstype); 1657c478bd9Sstevel@tonic-gate return (ENXIO); 1667c478bd9Sstevel@tonic-gate } 1677c478bd9Sstevel@tonic-gate } 1687c478bd9Sstevel@tonic-gate RLOCK_VFSSW(); 1697c478bd9Sstevel@tonic-gate vsw = vfs_getvfsswbyname(rootfs.bo_fstype); 1707c478bd9Sstevel@tonic-gate RUNLOCK_VFSSW(); 1717c478bd9Sstevel@tonic-gate VFS_INIT(rootvfs, &vsw->vsw_vfsops, (caddr_t)0); 1727c478bd9Sstevel@tonic-gate VFS_HOLD(rootvfs); 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate if (root_is_svm) { 1757c478bd9Sstevel@tonic-gate rootvfs->vfs_flag |= VFS_RDONLY; 1767c478bd9Sstevel@tonic-gate } 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate /* 1797c478bd9Sstevel@tonic-gate * This pm-releated call has to occur before root is mounted since we 1807c478bd9Sstevel@tonic-gate * need to power up all devices. It is placed after VFS_INIT() such 1817c478bd9Sstevel@tonic-gate * that opening a device via ddi_lyr_ interface just before root has 1827c478bd9Sstevel@tonic-gate * been mounted would work. 1837c478bd9Sstevel@tonic-gate */ 1847c478bd9Sstevel@tonic-gate pm_init(); 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate if (netboot) { 1877c478bd9Sstevel@tonic-gate if ((error = strplumb()) != 0) { 1887c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "Cannot plumb network device\n"); 1897c478bd9Sstevel@tonic-gate return (error); 1907c478bd9Sstevel@tonic-gate } 1917c478bd9Sstevel@tonic-gate } 1927c478bd9Sstevel@tonic-gate 1937c478bd9Sstevel@tonic-gate /* 1947c478bd9Sstevel@tonic-gate * ufs_mountroot() ends up calling getrootdev() 1957c478bd9Sstevel@tonic-gate * (below) which actually triggers the _init, identify, 1967c478bd9Sstevel@tonic-gate * probe and attach of the drivers that make up root device 1977c478bd9Sstevel@tonic-gate * bush; these are also quietly waiting in memory. 1987c478bd9Sstevel@tonic-gate */ 1997c478bd9Sstevel@tonic-gate BMDPRINTF(("rootconf: calling VFS_MOUNTROOT %s\n", rootfs.bo_fstype)); 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate error = VFS_MOUNTROOT(rootvfs, ROOT_INIT); 2027c478bd9Sstevel@tonic-gate vfs_unrefvfssw(vsw); 2037c478bd9Sstevel@tonic-gate rootdev = rootvfs->vfs_dev; 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate if (error) 2067c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "Cannot mount root on %s fstype %s\n", 2077c478bd9Sstevel@tonic-gate rootfs.bo_name, rootfs.bo_fstype); 2087c478bd9Sstevel@tonic-gate else 2097c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "?root on %s fstype %s\n", 2107c478bd9Sstevel@tonic-gate rootfs.bo_name, rootfs.bo_fstype); 2117c478bd9Sstevel@tonic-gate return (error); 2127c478bd9Sstevel@tonic-gate } 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate /* 2157c478bd9Sstevel@tonic-gate * Remount root on an SVM mirror root device 2167c478bd9Sstevel@tonic-gate * Only supported on UFS filesystems at present 2177c478bd9Sstevel@tonic-gate */ 2187c478bd9Sstevel@tonic-gate int 2197c478bd9Sstevel@tonic-gate svm_rootconf(void) 2207c478bd9Sstevel@tonic-gate { 2217c478bd9Sstevel@tonic-gate int error; 2227c478bd9Sstevel@tonic-gate extern int ufs_remountroot(struct vfs *vfsp); 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate ASSERT(root_is_svm == 1); 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate if (strcmp(rootfs.bo_fstype, "ufs") != 0) { 2277c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "Mounting root on %s with filesystem " 2287c478bd9Sstevel@tonic-gate "type %s is not supported\n", 2297c478bd9Sstevel@tonic-gate rootfs.bo_name, rootfs.bo_fstype); 2307c478bd9Sstevel@tonic-gate return (EINVAL); 2317c478bd9Sstevel@tonic-gate } 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate (void) strncpy(rootfs.bo_name, svm_bootpath, BO_MAXOBJNAME); 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate BMDPRINTF(("svm_rootconf: rootfs %s\n", rootfs.bo_name)); 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate error = ufs_remountroot(rootvfs); 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate if (error) { 2407c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "Cannot remount root on %s fstype %s\n", 2417c478bd9Sstevel@tonic-gate rootfs.bo_name, rootfs.bo_fstype); 2427c478bd9Sstevel@tonic-gate } else { 2437c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "?root remounted on %s fstype %s\n", 2447c478bd9Sstevel@tonic-gate rootfs.bo_name, rootfs.bo_fstype); 2457c478bd9Sstevel@tonic-gate } 2467c478bd9Sstevel@tonic-gate return (error); 2477c478bd9Sstevel@tonic-gate } 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate /* 2507c478bd9Sstevel@tonic-gate * Under the assumption that our root file system is on a 2517c478bd9Sstevel@tonic-gate * disk partition, get the dev_t of the partition in question. 2527c478bd9Sstevel@tonic-gate * 2537c478bd9Sstevel@tonic-gate * By now, boot has faithfully loaded all our modules into memory, and 2547c478bd9Sstevel@tonic-gate * we've taken over resource management. Before we go any further, we 2557c478bd9Sstevel@tonic-gate * have to fire up the device drivers and stuff we need to mount the 2567c478bd9Sstevel@tonic-gate * root filesystem. That's what we do here. Fingers crossed. 2577c478bd9Sstevel@tonic-gate */ 2587c478bd9Sstevel@tonic-gate dev_t 2597c478bd9Sstevel@tonic-gate getrootdev(void) 2607c478bd9Sstevel@tonic-gate { 2617c478bd9Sstevel@tonic-gate dev_t d; 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate if ((d = ddi_pathname_to_dev_t(rootfs.bo_name)) == NODEV) 2647c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "Cannot assemble drivers for root %s\n", 2657c478bd9Sstevel@tonic-gate rootfs.bo_name); 2667c478bd9Sstevel@tonic-gate return (d); 2677c478bd9Sstevel@tonic-gate } 2687c478bd9Sstevel@tonic-gate 2697c478bd9Sstevel@tonic-gate /* 2707c478bd9Sstevel@tonic-gate * If booted with ASKNAME, prompt on the console for a filesystem 2717c478bd9Sstevel@tonic-gate * name and return it. 2727c478bd9Sstevel@tonic-gate */ 2737c478bd9Sstevel@tonic-gate void 2747c478bd9Sstevel@tonic-gate getfsname(char *askfor, char *name, size_t namelen) 2757c478bd9Sstevel@tonic-gate { 2767c478bd9Sstevel@tonic-gate if (boothowto & RB_ASKNAME) { 2777c478bd9Sstevel@tonic-gate printf("%s name: ", askfor); 2787c478bd9Sstevel@tonic-gate console_gets(name, namelen); 2797c478bd9Sstevel@tonic-gate } 2807c478bd9Sstevel@tonic-gate } 2817c478bd9Sstevel@tonic-gate 2827c478bd9Sstevel@tonic-gate /*ARGSUSED1*/ 2837c478bd9Sstevel@tonic-gate static int 2847c478bd9Sstevel@tonic-gate preload_module(struct sysparam *sysp, void *p) 2857c478bd9Sstevel@tonic-gate { 2867c478bd9Sstevel@tonic-gate static char *wmesg = "forceload of %s failed"; 2877c478bd9Sstevel@tonic-gate char *name; 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate name = sysp->sys_ptr; 2907c478bd9Sstevel@tonic-gate BMDPRINTF(("preload_module: %s\n", name)); 2917c478bd9Sstevel@tonic-gate if (modloadonly(NULL, name) < 0) 2927c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, wmesg, name); 2937c478bd9Sstevel@tonic-gate return (0); 2947c478bd9Sstevel@tonic-gate } 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate /* ONC_PLUS EXTRACT START */ 2977c478bd9Sstevel@tonic-gate /* 2987c478bd9Sstevel@tonic-gate * We want to load all the modules needed to mount the root filesystem, 2997c478bd9Sstevel@tonic-gate * so that when we start the ball rolling in 'getrootdev', every module 3007c478bd9Sstevel@tonic-gate * should already be in memory, just waiting to be init-ed. 3017c478bd9Sstevel@tonic-gate */ 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate int 3047c478bd9Sstevel@tonic-gate loadrootmodules(void) 3057c478bd9Sstevel@tonic-gate { 3067c478bd9Sstevel@tonic-gate struct vfssw *vsw; 3077c478bd9Sstevel@tonic-gate char *this; 3087c478bd9Sstevel@tonic-gate char *name; 3097c478bd9Sstevel@tonic-gate int err; 3107c478bd9Sstevel@tonic-gate /* ONC_PLUS EXTRACT END */ 3117c478bd9Sstevel@tonic-gate int i, proplen, dhcacklen; 3127c478bd9Sstevel@tonic-gate extern char *impl_module_list[]; 3137c478bd9Sstevel@tonic-gate extern char *platform_module_list[]; 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate /* Make sure that the PROM's devinfo tree has been created */ 3167c478bd9Sstevel@tonic-gate ASSERT(ddi_root_node()); 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate BMDPRINTF(("loadrootmodules: fstype %s\n", rootfs.bo_fstype)); 3197c478bd9Sstevel@tonic-gate BMDPRINTF(("loadrootmodules: name %s\n", rootfs.bo_name)); 3207c478bd9Sstevel@tonic-gate BMDPRINTF(("loadrootmodules: flags 0x%x\n", rootfs.bo_flags)); 3217c478bd9Sstevel@tonic-gate 3227c478bd9Sstevel@tonic-gate /* 3237c478bd9Sstevel@tonic-gate * zzz We need to honor what's in rootfs if it's not null. 3247c478bd9Sstevel@tonic-gate * non-null means use what's there. This way we can 3257c478bd9Sstevel@tonic-gate * change rootfs with /etc/system AND with tunetool. 3267c478bd9Sstevel@tonic-gate */ 3277c478bd9Sstevel@tonic-gate if (root_is_svm) { 3287c478bd9Sstevel@tonic-gate /* user replaced rootdev, record obp_bootpath */ 3297c478bd9Sstevel@tonic-gate obp_bootpath[0] = '\0'; 3307c478bd9Sstevel@tonic-gate (void) getphysdev("root", obp_bootpath, BO_MAXOBJNAME); 3317c478bd9Sstevel@tonic-gate BMDPRINTF(("loadrootmodules: obp_bootpath %s\n", obp_bootpath)); 3327c478bd9Sstevel@tonic-gate } else { 3337c478bd9Sstevel@tonic-gate /* 3347c478bd9Sstevel@tonic-gate * Get the root fstype and root device path from boot. 3357c478bd9Sstevel@tonic-gate */ 3367c478bd9Sstevel@tonic-gate rootfs.bo_fstype[0] = '\0'; 3377c478bd9Sstevel@tonic-gate rootfs.bo_name[0] = '\0'; 3387c478bd9Sstevel@tonic-gate } 3397c478bd9Sstevel@tonic-gate 3407c478bd9Sstevel@tonic-gate /* 3417c478bd9Sstevel@tonic-gate * This lookup will result in modloadonly-ing the root 3427c478bd9Sstevel@tonic-gate * filesystem module - it gets _init-ed in rootconf() 3437c478bd9Sstevel@tonic-gate */ 3447c478bd9Sstevel@tonic-gate if ((vsw = getfstype("root", rootfs.bo_fstype, BO_MAXFSNAME)) == NULL) 3457c478bd9Sstevel@tonic-gate return (ENXIO); /* in case we have no file system types */ 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate (void) strcpy(rootfs.bo_fstype, vsw->vsw_name); 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate vfs_unrefvfssw(vsw); 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate /* 3527c478bd9Sstevel@tonic-gate * Load the favored drivers of the implementation. 3537c478bd9Sstevel@tonic-gate * e.g. 'sbus' and possibly 'zs' (even). 3547c478bd9Sstevel@tonic-gate * 3557c478bd9Sstevel@tonic-gate * Called whilst boot is still loaded (because boot does 3567c478bd9Sstevel@tonic-gate * the i/o for us), and DDI services are unavailable. 3577c478bd9Sstevel@tonic-gate */ 3587c478bd9Sstevel@tonic-gate BMDPRINTF(("loadrootmodules: impl_module_list\n")); 3597c478bd9Sstevel@tonic-gate for (i = 0; (this = impl_module_list[i]) != NULL; i++) { 3607c478bd9Sstevel@tonic-gate if ((err = load_boot_driver(this)) != 0) { 3617c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "Cannot load drv/%s", this); 3627c478bd9Sstevel@tonic-gate return (err); 3637c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3647c478bd9Sstevel@tonic-gate } 3657c478bd9Sstevel@tonic-gate } 3667c478bd9Sstevel@tonic-gate /* 3677c478bd9Sstevel@tonic-gate * Now load the platform modules (if any) 3687c478bd9Sstevel@tonic-gate */ 3697c478bd9Sstevel@tonic-gate BMDPRINTF(("loadrootmodules: platform_module_list\n")); 3707c478bd9Sstevel@tonic-gate for (i = 0; (this = platform_module_list[i]) != NULL; i++) { 3717c478bd9Sstevel@tonic-gate if ((err = load_boot_platform_modules(this)) != 0) { 3727c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "Cannot load drv/%s", this); 3737c478bd9Sstevel@tonic-gate return (err); 3747c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3757c478bd9Sstevel@tonic-gate } 3767c478bd9Sstevel@tonic-gate } 3777c478bd9Sstevel@tonic-gate 3787c478bd9Sstevel@tonic-gate loop: 3797c478bd9Sstevel@tonic-gate (void) getphysdev("root", rootfs.bo_name, BO_MAXOBJNAME); 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate /* 3827c478bd9Sstevel@tonic-gate * Given a physical pathname, load the correct set of driver 3837c478bd9Sstevel@tonic-gate * modules into memory, including all possible parents. 3847c478bd9Sstevel@tonic-gate * 3857c478bd9Sstevel@tonic-gate * NB: The code sets the variable 'name' for error reporting. 3867c478bd9Sstevel@tonic-gate */ 3877c478bd9Sstevel@tonic-gate err = 0; 3887c478bd9Sstevel@tonic-gate BMDPRINTF(("loadrootmodules: rootfs %s\n", rootfs.bo_name)); 3897c478bd9Sstevel@tonic-gate if (root_is_svm == 0) { 3907c478bd9Sstevel@tonic-gate BMDPRINTF(("loadrootmodules: rootfs %s\n", rootfs.bo_name)); 3917c478bd9Sstevel@tonic-gate name = rootfs.bo_name; 3927c478bd9Sstevel@tonic-gate err = load_bootpath_drivers(rootfs.bo_name); 3937c478bd9Sstevel@tonic-gate } 3947c478bd9Sstevel@tonic-gate 3957c478bd9Sstevel@tonic-gate /* 3967c478bd9Sstevel@tonic-gate * Load driver modules in obp_bootpath, this is always 3977c478bd9Sstevel@tonic-gate * required for mountroot to succeed. obp_bootpath is 3987c478bd9Sstevel@tonic-gate * is set if rootdev is set via /etc/system, which is 3997c478bd9Sstevel@tonic-gate * the case if booting of a SVM/VxVM mirror. 4007c478bd9Sstevel@tonic-gate */ 4017c478bd9Sstevel@tonic-gate if ((err == 0) && obp_bootpath[0] != '\0') { 4027c478bd9Sstevel@tonic-gate BMDPRINTF(("loadrootmodules: obp_bootpath %s\n", obp_bootpath)); 4037c478bd9Sstevel@tonic-gate name = obp_bootpath; 4047c478bd9Sstevel@tonic-gate err = load_bootpath_drivers(obp_bootpath); 4057c478bd9Sstevel@tonic-gate } 4067c478bd9Sstevel@tonic-gate 4077c478bd9Sstevel@tonic-gate if (err != 0) { 4087c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "Cannot load drivers for %s\n", name); 4097c478bd9Sstevel@tonic-gate goto out; 4107c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4117c478bd9Sstevel@tonic-gate } 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate /* 4147c478bd9Sstevel@tonic-gate * Check to see if the booter performed DHCP configuration 4157c478bd9Sstevel@tonic-gate * ("bootp-response" boot property exists). If so, then before 4167c478bd9Sstevel@tonic-gate * bootops disappears we need to save the value of this property 4177c478bd9Sstevel@tonic-gate * such that the userland dhcpagent can adopt the DHCP management 4187c478bd9Sstevel@tonic-gate * of our primary network interface. We leave room at the beginning of 4197c478bd9Sstevel@tonic-gate * saved property to cache the interface name we used to boot the 4207c478bd9Sstevel@tonic-gate * client. This context is necessary for the user land dhcpagent 4217c478bd9Sstevel@tonic-gate * to do its job properly on a multi-homed system. 4227c478bd9Sstevel@tonic-gate */ 4237c478bd9Sstevel@tonic-gate proplen = BOP_GETPROPLEN(bootops, "bootp-response"); 4247c478bd9Sstevel@tonic-gate if (proplen > 0) { 4257c478bd9Sstevel@tonic-gate dhcacklen = proplen + IFNAMSIZ; 4267c478bd9Sstevel@tonic-gate dhcack = kmem_zalloc(dhcacklen, KM_SLEEP); 4277c478bd9Sstevel@tonic-gate if (BOP_GETPROP(bootops, "bootp-response", 4287c478bd9Sstevel@tonic-gate (uchar_t *)&dhcack[IFNAMSIZ]) == -1) { 4297c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "BOP_GETPROP of " 4307c478bd9Sstevel@tonic-gate "\"bootp-response\" failed\n"); 4317c478bd9Sstevel@tonic-gate kmem_free(dhcack, dhcacklen); 4327c478bd9Sstevel@tonic-gate dhcack = NULL; 4337c478bd9Sstevel@tonic-gate goto out; 4347c478bd9Sstevel@tonic-gate } 4357c478bd9Sstevel@tonic-gate 4367c478bd9Sstevel@tonic-gate /* 4377c478bd9Sstevel@tonic-gate * Fetch the "netdev-path" boot property (if it exists), and 4387c478bd9Sstevel@tonic-gate * stash it for later use by sysinfo(SI_DHCP_CACHE, ...). 4397c478bd9Sstevel@tonic-gate */ 4407c478bd9Sstevel@tonic-gate proplen = BOP_GETPROPLEN(bootops, "netdev-path"); 4417c478bd9Sstevel@tonic-gate if (proplen > 0) { 4427c478bd9Sstevel@tonic-gate netdev_path = kmem_zalloc(proplen, KM_SLEEP); 4437c478bd9Sstevel@tonic-gate if (BOP_GETPROP(bootops, "netdev-path", 4447c478bd9Sstevel@tonic-gate (uchar_t *)netdev_path) == -1) { 4457c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "BOP_GETPROP of " 4467c478bd9Sstevel@tonic-gate "\"netdev-path\" failed\n"); 4477c478bd9Sstevel@tonic-gate kmem_free(netdev_path, proplen); 4487c478bd9Sstevel@tonic-gate goto out; 4497c478bd9Sstevel@tonic-gate } 4507c478bd9Sstevel@tonic-gate } 4517c478bd9Sstevel@tonic-gate } 4527c478bd9Sstevel@tonic-gate 4537c478bd9Sstevel@tonic-gate /* 4547c478bd9Sstevel@tonic-gate * Preload (load-only, no init) all modules which 4557c478bd9Sstevel@tonic-gate * were added to the /etc/system file with the 4567c478bd9Sstevel@tonic-gate * FORCELOAD keyword. 4577c478bd9Sstevel@tonic-gate */ 4587c478bd9Sstevel@tonic-gate BMDPRINTF(("loadrootmodules: preload_module\n")); 4597c478bd9Sstevel@tonic-gate (void) mod_sysctl_type(MOD_FORCELOAD, preload_module, NULL); 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate /* ONC_PLUS EXTRACT START */ 4627c478bd9Sstevel@tonic-gate /* 4637c478bd9Sstevel@tonic-gate * If we booted otw then load in the plumbing 4647c478bd9Sstevel@tonic-gate * routine now while we still can. If we didn't 4657c478bd9Sstevel@tonic-gate * boot otw then we will load strplumb in main(). 4667c478bd9Sstevel@tonic-gate * 4677c478bd9Sstevel@tonic-gate * NFS is actually a set of modules, the core routines, 4687c478bd9Sstevel@tonic-gate * a diskless helper module, rpcmod, and the tli interface. Load 4697c478bd9Sstevel@tonic-gate * them now while we still can. 4707c478bd9Sstevel@tonic-gate * 4717c478bd9Sstevel@tonic-gate * Because we glomb all versions of nfs into a single module 4727c478bd9Sstevel@tonic-gate * we check based on the initial string "nfs". 4737c478bd9Sstevel@tonic-gate * 4747c478bd9Sstevel@tonic-gate * XXX: A better test for this is to see if device_type 4757c478bd9Sstevel@tonic-gate * XXX: from the PROM is "network". 4767c478bd9Sstevel@tonic-gate */ 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate if (strncmp(rootfs.bo_fstype, "nfs", 3) == 0) { 4797c478bd9Sstevel@tonic-gate ++netboot; 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate if ((err = modload("misc", "tlimod")) < 0) { 4827c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "Cannot load misc/tlimod\n"); 4837c478bd9Sstevel@tonic-gate goto out; 4847c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4857c478bd9Sstevel@tonic-gate } 4867c478bd9Sstevel@tonic-gate if ((err = modload("strmod", "rpcmod")) < 0) { 4877c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "Cannot load strmod/rpcmod\n"); 4887c478bd9Sstevel@tonic-gate goto out; 4897c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4907c478bd9Sstevel@tonic-gate } 4917c478bd9Sstevel@tonic-gate if ((err = modload("misc", "nfs_dlboot")) < 0) { 4927c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "Cannot load misc/nfs_dlboot\n"); 4937c478bd9Sstevel@tonic-gate goto out; 4947c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4957c478bd9Sstevel@tonic-gate } 49648aa2e6aSseb if ((err = modload("mac", "mac_ether")) < 0) { 49748aa2e6aSseb cmn_err(CE_CONT, "Cannot load mac/mac_ether\n"); 49848aa2e6aSseb goto out; 49948aa2e6aSseb /* NOTREACHED */ 50048aa2e6aSseb } 5017c478bd9Sstevel@tonic-gate if ((err = modload("misc", "strplumb")) < 0) { 5027c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "Cannot load misc/strplumb\n"); 5037c478bd9Sstevel@tonic-gate goto out; 5047c478bd9Sstevel@tonic-gate /* NOTREACHED */ 5057c478bd9Sstevel@tonic-gate } 5067c478bd9Sstevel@tonic-gate if ((err = strplumb_load()) < 0) { 5077c478bd9Sstevel@tonic-gate goto out; 5087c478bd9Sstevel@tonic-gate /* NOTREACHED */ 5097c478bd9Sstevel@tonic-gate } 5107c478bd9Sstevel@tonic-gate } 5117c478bd9Sstevel@tonic-gate 5127c478bd9Sstevel@tonic-gate /* 5137c478bd9Sstevel@tonic-gate * Preload modules needed for booting as a cluster. 5147c478bd9Sstevel@tonic-gate */ 5157c478bd9Sstevel@tonic-gate err = clboot_loadrootmodules(); 5167c478bd9Sstevel@tonic-gate 5177c478bd9Sstevel@tonic-gate out: 5187c478bd9Sstevel@tonic-gate if (err != 0 && (boothowto & RB_ASKNAME)) 5197c478bd9Sstevel@tonic-gate goto loop; 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate return (err); 5227c478bd9Sstevel@tonic-gate } 5237c478bd9Sstevel@tonic-gate /* ONC_PLUS EXTRACT END */ 5247c478bd9Sstevel@tonic-gate 5257c478bd9Sstevel@tonic-gate /* 5267c478bd9Sstevel@tonic-gate * Get the name of the root or swap filesystem type, and return 5277c478bd9Sstevel@tonic-gate * the corresponding entry in the vfs switch. 5287c478bd9Sstevel@tonic-gate * 5297c478bd9Sstevel@tonic-gate * If we're not asking the user, and we're trying to find the 5307c478bd9Sstevel@tonic-gate * root filesystem type, we ask boot for the filesystem 5317c478bd9Sstevel@tonic-gate * type that it came from and use that. Similarly, if we're 5327c478bd9Sstevel@tonic-gate * trying to find the swap filesystem, we try and derive it from 5337c478bd9Sstevel@tonic-gate * the root filesystem type. 5347c478bd9Sstevel@tonic-gate * 5357c478bd9Sstevel@tonic-gate * If we are booting via NFS we currently have these options: 5367c478bd9Sstevel@tonic-gate * nfs - dynamically choose NFS V2. V3, or V4 (default) 5377c478bd9Sstevel@tonic-gate * nfs2 - force NFS V2 5387c478bd9Sstevel@tonic-gate * nfs3 - force NFS V3 5397c478bd9Sstevel@tonic-gate * nfs4 - force NFS V4 5407c478bd9Sstevel@tonic-gate * Because we need to maintain backward compatibility with the naming 5417c478bd9Sstevel@tonic-gate * convention that the NFS V2 filesystem name is "nfs" (see vfs_conf.c) 5427c478bd9Sstevel@tonic-gate * we need to map "nfs" => "nfsdyn" and "nfs2" => "nfs". The dynamic 5437c478bd9Sstevel@tonic-gate * nfs module will map the type back to either "nfs", "nfs3", or "nfs4". 5447c478bd9Sstevel@tonic-gate * This is only for root filesystems, all other uses such as cachefs 5457c478bd9Sstevel@tonic-gate * will expect that "nfs" == NFS V2. 5467c478bd9Sstevel@tonic-gate * 5477c478bd9Sstevel@tonic-gate * If the filesystem isn't already loaded, vfs_getvfssw() will load 5487c478bd9Sstevel@tonic-gate * it for us, but if (at the time we call it) modrootloaded is 5497c478bd9Sstevel@tonic-gate * still not set, it won't run the filesystems _init routine (and 5507c478bd9Sstevel@tonic-gate * implicitly it won't run the filesystems vsw_init() entry either). 5517c478bd9Sstevel@tonic-gate * We do that explicitly in rootconf(). 5527c478bd9Sstevel@tonic-gate */ 5537c478bd9Sstevel@tonic-gate static struct vfssw * 5547c478bd9Sstevel@tonic-gate getfstype(char *askfor, char *fsname, size_t fsnamelen) 5557c478bd9Sstevel@tonic-gate { 5567c478bd9Sstevel@tonic-gate struct vfssw *vsw; 5577c478bd9Sstevel@tonic-gate static char defaultfs[BO_MAXFSNAME]; 5587c478bd9Sstevel@tonic-gate int root = 0; 5597c478bd9Sstevel@tonic-gate 5607c478bd9Sstevel@tonic-gate if (strcmp(askfor, "root") == 0) { 5617c478bd9Sstevel@tonic-gate (void) BOP_GETPROP(bootops, "fstype", defaultfs); 5627c478bd9Sstevel@tonic-gate root++; 5637c478bd9Sstevel@tonic-gate } else { 5647c478bd9Sstevel@tonic-gate (void) strcpy(defaultfs, "swapfs"); 5657c478bd9Sstevel@tonic-gate } 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate if (boothowto & RB_ASKNAME) { 5687c478bd9Sstevel@tonic-gate for (*fsname = '\0'; *fsname == '\0'; *fsname = '\0') { 5697c478bd9Sstevel@tonic-gate printf("%s filesystem type [%s]: ", askfor, defaultfs); 5707c478bd9Sstevel@tonic-gate console_gets(fsname, fsnamelen); 5717c478bd9Sstevel@tonic-gate if (*fsname == '\0') 5727c478bd9Sstevel@tonic-gate (void) strcpy(fsname, defaultfs); 5737c478bd9Sstevel@tonic-gate if (root) { 5747c478bd9Sstevel@tonic-gate if (strcmp(fsname, "nfs2") == 0) 5757c478bd9Sstevel@tonic-gate (void) strcpy(fsname, "nfs"); 5767c478bd9Sstevel@tonic-gate else if (strcmp(fsname, "nfs") == 0) 5777c478bd9Sstevel@tonic-gate (void) strcpy(fsname, "nfsdyn"); 5787c478bd9Sstevel@tonic-gate } 5797c478bd9Sstevel@tonic-gate if ((vsw = vfs_getvfssw(fsname)) != NULL) 5807c478bd9Sstevel@tonic-gate return (vsw); 5817c478bd9Sstevel@tonic-gate printf("Unknown filesystem type '%s'\n", fsname); 5827c478bd9Sstevel@tonic-gate } 5837c478bd9Sstevel@tonic-gate } else if (*fsname == '\0') { 5847c478bd9Sstevel@tonic-gate fsname = defaultfs; 5857c478bd9Sstevel@tonic-gate } 5867c478bd9Sstevel@tonic-gate if (*fsname == '\0') { 5877c478bd9Sstevel@tonic-gate return (NULL); 5887c478bd9Sstevel@tonic-gate } 5897c478bd9Sstevel@tonic-gate 5907c478bd9Sstevel@tonic-gate if (root) { 5917c478bd9Sstevel@tonic-gate if (strcmp(fsname, "nfs2") == 0) 5927c478bd9Sstevel@tonic-gate (void) strcpy(fsname, "nfs"); 5937c478bd9Sstevel@tonic-gate else if (strcmp(fsname, "nfs") == 0) 5947c478bd9Sstevel@tonic-gate (void) strcpy(fsname, "nfsdyn"); 5957c478bd9Sstevel@tonic-gate } 5967c478bd9Sstevel@tonic-gate 5977c478bd9Sstevel@tonic-gate return (vfs_getvfssw(fsname)); 5987c478bd9Sstevel@tonic-gate } 5997c478bd9Sstevel@tonic-gate 6007c478bd9Sstevel@tonic-gate 6017c478bd9Sstevel@tonic-gate /* 6027c478bd9Sstevel@tonic-gate * Get a physical device name, and maybe load and attach 6037c478bd9Sstevel@tonic-gate * the driver. 6047c478bd9Sstevel@tonic-gate * 6057c478bd9Sstevel@tonic-gate * XXX Need better checking of whether or not a device 6067c478bd9Sstevel@tonic-gate * actually exists if the user typed in a pathname. 6077c478bd9Sstevel@tonic-gate * 6087c478bd9Sstevel@tonic-gate * XXX Are we sure we want to expose users to this sort 6097c478bd9Sstevel@tonic-gate * of physical namespace gobbledygook (now there's 6107c478bd9Sstevel@tonic-gate * a word to conjure with..) 6117c478bd9Sstevel@tonic-gate * 6127c478bd9Sstevel@tonic-gate * XXX Note that on an OBP machine, we can easily ask the 6137c478bd9Sstevel@tonic-gate * prom and pretty-print some plausible set of bootable 6147c478bd9Sstevel@tonic-gate * devices. We can also user the prom to verify any 6157c478bd9Sstevel@tonic-gate * such device. Later tim.. later. 6167c478bd9Sstevel@tonic-gate */ 6177c478bd9Sstevel@tonic-gate static int 6187c478bd9Sstevel@tonic-gate getphysdev(char *askfor, char *name, size_t namelen) 6197c478bd9Sstevel@tonic-gate { 6207c478bd9Sstevel@tonic-gate static char fmt[] = "Enter physical name of %s device\n[%s]: "; 6217c478bd9Sstevel@tonic-gate dev_t dev; 6227c478bd9Sstevel@tonic-gate static char defaultpath[BO_MAXOBJNAME]; 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate /* 6257c478bd9Sstevel@tonic-gate * Establish 'default' values - we get the root device from 6267c478bd9Sstevel@tonic-gate * boot, and we infer the swap device is the same but with 6277c478bd9Sstevel@tonic-gate * a 'b' on the end instead of an 'a'. A first stab at 6287c478bd9Sstevel@tonic-gate * ease-of-use .. 6297c478bd9Sstevel@tonic-gate */ 6307c478bd9Sstevel@tonic-gate if (strcmp(askfor, "root") == 0) { 6317c478bd9Sstevel@tonic-gate /* 6327c478bd9Sstevel@tonic-gate * Look for the 1275 compliant name 'bootpath' first, 6337c478bd9Sstevel@tonic-gate * but make certain it has a non-NULL value as well. 6347c478bd9Sstevel@tonic-gate */ 6357c478bd9Sstevel@tonic-gate if ((BOP_GETPROP(bootops, "bootpath", defaultpath) == -1) || 6367c478bd9Sstevel@tonic-gate strlen(defaultpath) == 0) { 6377c478bd9Sstevel@tonic-gate if (BOP_GETPROP(bootops, 6387c478bd9Sstevel@tonic-gate "boot-path", defaultpath) == -1) 6397c478bd9Sstevel@tonic-gate boothowto |= RB_ASKNAME | RB_VERBOSE; 6407c478bd9Sstevel@tonic-gate } 6417c478bd9Sstevel@tonic-gate } else { 6427c478bd9Sstevel@tonic-gate (void) strcpy(defaultpath, rootfs.bo_name); 6437c478bd9Sstevel@tonic-gate defaultpath[strlen(defaultpath) - 1] = 'b'; 6447c478bd9Sstevel@tonic-gate } 6457c478bd9Sstevel@tonic-gate 6467c478bd9Sstevel@tonic-gate retry: 6477c478bd9Sstevel@tonic-gate if (boothowto & RB_ASKNAME) { 6487c478bd9Sstevel@tonic-gate printf(fmt, askfor, defaultpath); 6497c478bd9Sstevel@tonic-gate console_gets(name, namelen); 6507c478bd9Sstevel@tonic-gate } 6517c478bd9Sstevel@tonic-gate if (*name == '\0') 6527c478bd9Sstevel@tonic-gate (void) strcpy(name, defaultpath); 6537c478bd9Sstevel@tonic-gate 6547c478bd9Sstevel@tonic-gate if (strcmp(askfor, "swap") == 0) { 6557c478bd9Sstevel@tonic-gate 6567c478bd9Sstevel@tonic-gate /* 6577c478bd9Sstevel@tonic-gate * Try to load and install the swap device driver. 6587c478bd9Sstevel@tonic-gate */ 6597c478bd9Sstevel@tonic-gate dev = ddi_pathname_to_dev_t(name); 6607c478bd9Sstevel@tonic-gate 6617c478bd9Sstevel@tonic-gate if (dev == (dev_t)-1) { 6627c478bd9Sstevel@tonic-gate printf("Not a supported device for swap.\n"); 6637c478bd9Sstevel@tonic-gate boothowto |= RB_ASKNAME | RB_VERBOSE; 6647c478bd9Sstevel@tonic-gate goto retry; 6657c478bd9Sstevel@tonic-gate } 6667c478bd9Sstevel@tonic-gate 6677c478bd9Sstevel@tonic-gate /* 6687c478bd9Sstevel@tonic-gate * Ensure that we're not trying to swap on the floppy. 6697c478bd9Sstevel@tonic-gate */ 6707c478bd9Sstevel@tonic-gate if (strncmp(ddi_major_to_name(getmajor(dev)), "fd", 2) == 0) { 6717c478bd9Sstevel@tonic-gate printf("Too dangerous to swap on the floppy\n"); 6727c478bd9Sstevel@tonic-gate if (boothowto & RB_ASKNAME) 6737c478bd9Sstevel@tonic-gate goto retry; 6747c478bd9Sstevel@tonic-gate return (-1); 6757c478bd9Sstevel@tonic-gate } 6767c478bd9Sstevel@tonic-gate } 6777c478bd9Sstevel@tonic-gate 6787c478bd9Sstevel@tonic-gate return (0); 6797c478bd9Sstevel@tonic-gate } 6807c478bd9Sstevel@tonic-gate 6817c478bd9Sstevel@tonic-gate 6827c478bd9Sstevel@tonic-gate /* 6837c478bd9Sstevel@tonic-gate * Load a driver needed to boot. 6847c478bd9Sstevel@tonic-gate */ 6857c478bd9Sstevel@tonic-gate static int 6867c478bd9Sstevel@tonic-gate load_boot_driver(char *drv) 6877c478bd9Sstevel@tonic-gate { 6887c478bd9Sstevel@tonic-gate char *drvname; 6897c478bd9Sstevel@tonic-gate major_t major; 6907c478bd9Sstevel@tonic-gate 6917c478bd9Sstevel@tonic-gate if ((major = ddi_name_to_major(drv)) == (major_t)-1) { 6927c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "%s: no major number\n", drv); 6937c478bd9Sstevel@tonic-gate return (-1); 6947c478bd9Sstevel@tonic-gate } 6957c478bd9Sstevel@tonic-gate /* 6967c478bd9Sstevel@tonic-gate * resolve aliases 6977c478bd9Sstevel@tonic-gate */ 6987c478bd9Sstevel@tonic-gate drvname = ddi_major_to_name(major); 6997c478bd9Sstevel@tonic-gate 7007c478bd9Sstevel@tonic-gate #ifdef DEBUG 7017c478bd9Sstevel@tonic-gate if (strcmp(drv, drvname) == 0) { 7027c478bd9Sstevel@tonic-gate BMDPRINTF(("load_boot_driver: %s\n", drv)); 7037c478bd9Sstevel@tonic-gate } else { 7047c478bd9Sstevel@tonic-gate BMDPRINTF(("load_boot_driver: %s -> %s\n", drv, drvname)); 7057c478bd9Sstevel@tonic-gate } 7067c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 7077c478bd9Sstevel@tonic-gate 7087c478bd9Sstevel@tonic-gate if (modloadonly("drv", drvname) == -1) { 7097c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "%s: cannot load driver\n", drvname); 7107c478bd9Sstevel@tonic-gate return (-1); 7117c478bd9Sstevel@tonic-gate } 7127c478bd9Sstevel@tonic-gate 7137c478bd9Sstevel@tonic-gate return (0); 7147c478bd9Sstevel@tonic-gate } 7157c478bd9Sstevel@tonic-gate 7167c478bd9Sstevel@tonic-gate 7177c478bd9Sstevel@tonic-gate /* 7187c478bd9Sstevel@tonic-gate * For a given instance, load that driver and its parents 7197c478bd9Sstevel@tonic-gate */ 7207c478bd9Sstevel@tonic-gate static int 721*f4da9be0Scth load_parent_drivers(dev_info_t *dip, char *path) 7227c478bd9Sstevel@tonic-gate { 7237c478bd9Sstevel@tonic-gate int rval = 0; 724*f4da9be0Scth major_t major = (major_t)-1; 7257c478bd9Sstevel@tonic-gate char *drv; 726*f4da9be0Scth char *p; 7277c478bd9Sstevel@tonic-gate 7287c478bd9Sstevel@tonic-gate while (dip) { 729*f4da9be0Scth /* check for path-oriented alias */ 730*f4da9be0Scth if (path) 731*f4da9be0Scth major = ddi_name_to_major(path); 732*f4da9be0Scth else 733*f4da9be0Scth major = (major_t)-1; 734*f4da9be0Scth 735*f4da9be0Scth if (major != (major_t)-1) 736*f4da9be0Scth drv = ddi_major_to_name(major); 737*f4da9be0Scth else 738*f4da9be0Scth drv = ddi_binding_name(dip); 739*f4da9be0Scth 7407c478bd9Sstevel@tonic-gate if (load_boot_driver(drv) != 0) 7417c478bd9Sstevel@tonic-gate rval = -1; 742*f4da9be0Scth 7437c478bd9Sstevel@tonic-gate dip = ddi_get_parent(dip); 744*f4da9be0Scth if (path) { 745*f4da9be0Scth p = strrchr(path, '/'); 746*f4da9be0Scth if (p) 747*f4da9be0Scth *p = 0; 748*f4da9be0Scth } 7497c478bd9Sstevel@tonic-gate } 7507c478bd9Sstevel@tonic-gate 7517c478bd9Sstevel@tonic-gate return (rval); 7527c478bd9Sstevel@tonic-gate } 7537c478bd9Sstevel@tonic-gate 7547c478bd9Sstevel@tonic-gate 7557c478bd9Sstevel@tonic-gate /* 7567c478bd9Sstevel@tonic-gate * For a given path to a boot device, 7577c478bd9Sstevel@tonic-gate * load that driver and all its parents. 7587c478bd9Sstevel@tonic-gate */ 7597c478bd9Sstevel@tonic-gate static int 7607c478bd9Sstevel@tonic-gate load_bootpath_drivers(char *bootpath) 7617c478bd9Sstevel@tonic-gate { 7627c478bd9Sstevel@tonic-gate dev_info_t *dip; 763*f4da9be0Scth char *pathcopy; 764*f4da9be0Scth int pathcopy_len; 765*f4da9be0Scth int rval; 766*f4da9be0Scth char *p; 7677c478bd9Sstevel@tonic-gate 7687c478bd9Sstevel@tonic-gate if (bootpath == NULL || *bootpath == 0) 7697c478bd9Sstevel@tonic-gate return (-1); 7707c478bd9Sstevel@tonic-gate 7717c478bd9Sstevel@tonic-gate BMDPRINTF(("load_bootpath_drivers: %s\n", bootpath)); 7727c478bd9Sstevel@tonic-gate 773*f4da9be0Scth pathcopy = i_ddi_strdup(bootpath, KM_SLEEP); 774*f4da9be0Scth pathcopy_len = strlen(pathcopy) + 1; 775*f4da9be0Scth 776*f4da9be0Scth dip = path_to_devinfo(pathcopy); 7777c478bd9Sstevel@tonic-gate 7787c478bd9Sstevel@tonic-gate #if defined(__i386) || defined(__amd64) 7797c478bd9Sstevel@tonic-gate /* 7807c478bd9Sstevel@tonic-gate * i386 does not provide stub nodes for all boot devices, 7817c478bd9Sstevel@tonic-gate * but we should be able to find the node for the parent, 7827c478bd9Sstevel@tonic-gate * and the leaf of the boot path should be the driver name, 7837c478bd9Sstevel@tonic-gate * which we go ahead and load here. 7847c478bd9Sstevel@tonic-gate */ 7857c478bd9Sstevel@tonic-gate if (dip == NULL) { 786*f4da9be0Scth char *leaf; 7877c478bd9Sstevel@tonic-gate 7887c478bd9Sstevel@tonic-gate /* 789*f4da9be0Scth * Find last slash to build the full path to the 790*f4da9be0Scth * parent of the leaf boot device 7917c478bd9Sstevel@tonic-gate */ 792*f4da9be0Scth p = strrchr(pathcopy, '/'); 7937c478bd9Sstevel@tonic-gate *p++ = 0; 7947c478bd9Sstevel@tonic-gate 7957c478bd9Sstevel@tonic-gate /* 7967c478bd9Sstevel@tonic-gate * Now isolate the driver name of the leaf device 7977c478bd9Sstevel@tonic-gate */ 798*f4da9be0Scth leaf = p; 799*f4da9be0Scth p = strchr(leaf, '@'); 8007c478bd9Sstevel@tonic-gate *p = 0; 8017c478bd9Sstevel@tonic-gate 8027c478bd9Sstevel@tonic-gate BMDPRINTF(("load_bootpath_drivers: parent=%s leaf=%s\n", 803*f4da9be0Scth bootpath, leaf)); 8047c478bd9Sstevel@tonic-gate 8057c478bd9Sstevel@tonic-gate dip = path_to_devinfo(pathcopy); 806*f4da9be0Scth if (leaf) { 807*f4da9be0Scth rval = load_boot_driver(leaf, NULL); 808*f4da9be0Scth if (rval == -1) { 809*f4da9be0Scth kmem_free(pathcopy, pathcopy_len); 8107c478bd9Sstevel@tonic-gate return (NULL); 811*f4da9be0Scth } 812*f4da9be0Scth } 8137c478bd9Sstevel@tonic-gate } 8147c478bd9Sstevel@tonic-gate #endif 8157c478bd9Sstevel@tonic-gate 8167c478bd9Sstevel@tonic-gate if (dip == NULL) { 8177c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "can't bind driver for boot path <%s>", 8187c478bd9Sstevel@tonic-gate bootpath); 819*f4da9be0Scth kmem_free(pathcopy, pathcopy_len); 8207c478bd9Sstevel@tonic-gate return (NULL); 8217c478bd9Sstevel@tonic-gate } 8227c478bd9Sstevel@tonic-gate 8237c478bd9Sstevel@tonic-gate /* 8247c478bd9Sstevel@tonic-gate * Load IP over IB driver when netbooting over IB. 8257c478bd9Sstevel@tonic-gate * As per IB 1275 binding, IP over IB is represented as 8267c478bd9Sstevel@tonic-gate * service on the top of the HCA node. So, there is no 8277c478bd9Sstevel@tonic-gate * PROM node and generic framework cannot pre-load 8287c478bd9Sstevel@tonic-gate * IP over IB driver based on the bootpath. The following 8297c478bd9Sstevel@tonic-gate * code preloads IP over IB driver when doing netboot over 8307c478bd9Sstevel@tonic-gate * InfiniBand. 8317c478bd9Sstevel@tonic-gate */ 8327c478bd9Sstevel@tonic-gate if (netboot_over_ib(bootpath) && 8337c478bd9Sstevel@tonic-gate modloadonly("drv", "ibd") == -1) { 8347c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "ibd: cannot load platform driver\n"); 835*f4da9be0Scth kmem_free(pathcopy, pathcopy_len); 8367c478bd9Sstevel@tonic-gate return (NULL); 8377c478bd9Sstevel@tonic-gate } 8387c478bd9Sstevel@tonic-gate 839*f4da9be0Scth /* get rid of minor node at end of copy (if not already done above) */ 840*f4da9be0Scth p = strrchr(pathcopy, '/'); 841*f4da9be0Scth if (p) { 842*f4da9be0Scth p = strchr(p, ':'); 843*f4da9be0Scth if (p) 844*f4da9be0Scth *p = 0; 845*f4da9be0Scth } 846*f4da9be0Scth 847*f4da9be0Scth rval = load_parent_drivers(dip, pathcopy); 848*f4da9be0Scth kmem_free(pathcopy, pathcopy_len); 849*f4da9be0Scth return (rval); 8507c478bd9Sstevel@tonic-gate } 8517c478bd9Sstevel@tonic-gate 8527c478bd9Sstevel@tonic-gate 8537c478bd9Sstevel@tonic-gate 8547c478bd9Sstevel@tonic-gate 8557c478bd9Sstevel@tonic-gate /* 8567c478bd9Sstevel@tonic-gate * Load drivers required for a platform 8577c478bd9Sstevel@tonic-gate * Since all hardware nodes should be available in the device 8587c478bd9Sstevel@tonic-gate * tree, walk the per-driver list and load the parents of 8597c478bd9Sstevel@tonic-gate * each node found. If not a hardware node, try to load it. 8607c478bd9Sstevel@tonic-gate * Pseudo nexus is already loaded. 8617c478bd9Sstevel@tonic-gate */ 8627c478bd9Sstevel@tonic-gate static int 8637c478bd9Sstevel@tonic-gate load_boot_platform_modules(char *drv) 8647c478bd9Sstevel@tonic-gate { 8657c478bd9Sstevel@tonic-gate major_t major; 8667c478bd9Sstevel@tonic-gate dev_info_t *dip; 8677c478bd9Sstevel@tonic-gate char *drvname; 8687c478bd9Sstevel@tonic-gate int rval = 0; 8697c478bd9Sstevel@tonic-gate 8707c478bd9Sstevel@tonic-gate if ((major = ddi_name_to_major(drv)) == (major_t)-1) { 8717c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "%s: no major number\n", drv); 8727c478bd9Sstevel@tonic-gate return (-1); 8737c478bd9Sstevel@tonic-gate } 8747c478bd9Sstevel@tonic-gate 8757c478bd9Sstevel@tonic-gate /* 8767c478bd9Sstevel@tonic-gate * resolve aliases 8777c478bd9Sstevel@tonic-gate */ 8787c478bd9Sstevel@tonic-gate drvname = ddi_major_to_name(major); 8797c478bd9Sstevel@tonic-gate if ((major = ddi_name_to_major(drvname)) == (major_t)-1) 8807c478bd9Sstevel@tonic-gate return (-1); 8817c478bd9Sstevel@tonic-gate 8827c478bd9Sstevel@tonic-gate #ifdef DEBUG 8837c478bd9Sstevel@tonic-gate if (strcmp(drv, drvname) == 0) { 8847c478bd9Sstevel@tonic-gate BMDPRINTF(("load_boot_platform_modules: %s\n", drv)); 8857c478bd9Sstevel@tonic-gate } else { 8867c478bd9Sstevel@tonic-gate BMDPRINTF(("load_boot_platform_modules: %s -> %s\n", 8877c478bd9Sstevel@tonic-gate drv, drvname)); 8887c478bd9Sstevel@tonic-gate } 8897c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 8907c478bd9Sstevel@tonic-gate 8917c478bd9Sstevel@tonic-gate dip = devnamesp[major].dn_head; 8927c478bd9Sstevel@tonic-gate if (dip == NULL) { 8937c478bd9Sstevel@tonic-gate /* pseudo node, not-enumerated, needs to be loaded */ 8947c478bd9Sstevel@tonic-gate if (modloadonly("drv", drvname) == -1) { 8957c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "%s: cannot load platform driver\n", 8967c478bd9Sstevel@tonic-gate drvname); 8977c478bd9Sstevel@tonic-gate rval = -1; 8987c478bd9Sstevel@tonic-gate } 8997c478bd9Sstevel@tonic-gate } else { 9007c478bd9Sstevel@tonic-gate while (dip) { 901*f4da9be0Scth if (load_parent_drivers(dip, NULL) != 0) 9027c478bd9Sstevel@tonic-gate rval = -1; 9037c478bd9Sstevel@tonic-gate dip = ddi_get_next(dip); 9047c478bd9Sstevel@tonic-gate } 9057c478bd9Sstevel@tonic-gate } 9067c478bd9Sstevel@tonic-gate 9077c478bd9Sstevel@tonic-gate return (rval); 9087c478bd9Sstevel@tonic-gate } 9097c478bd9Sstevel@tonic-gate 9107c478bd9Sstevel@tonic-gate 9117c478bd9Sstevel@tonic-gate /* 9127c478bd9Sstevel@tonic-gate * i_find_node: Internal routine used by path_to_devinfo 9137c478bd9Sstevel@tonic-gate * to locate a given nodeid in the device tree. 9147c478bd9Sstevel@tonic-gate */ 9157c478bd9Sstevel@tonic-gate struct i_path_findnode { 916fa9e4066Sahrens pnode_t nodeid; 9177c478bd9Sstevel@tonic-gate dev_info_t *dip; 9187c478bd9Sstevel@tonic-gate }; 9197c478bd9Sstevel@tonic-gate 9207c478bd9Sstevel@tonic-gate static int 9217c478bd9Sstevel@tonic-gate i_path_find_node(dev_info_t *dev, void *arg) 9227c478bd9Sstevel@tonic-gate { 9237c478bd9Sstevel@tonic-gate struct i_path_findnode *f = (struct i_path_findnode *)arg; 9247c478bd9Sstevel@tonic-gate 9257c478bd9Sstevel@tonic-gate 9267c478bd9Sstevel@tonic-gate if (ddi_get_nodeid(dev) == (int)f->nodeid) { 9277c478bd9Sstevel@tonic-gate f->dip = dev; 9287c478bd9Sstevel@tonic-gate return (DDI_WALK_TERMINATE); 9297c478bd9Sstevel@tonic-gate } 9307c478bd9Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 9317c478bd9Sstevel@tonic-gate } 9327c478bd9Sstevel@tonic-gate 9337c478bd9Sstevel@tonic-gate /* 9347c478bd9Sstevel@tonic-gate * Return the devinfo node to a boot device 9357c478bd9Sstevel@tonic-gate */ 9367c478bd9Sstevel@tonic-gate static dev_info_t * 9377c478bd9Sstevel@tonic-gate path_to_devinfo(char *path) 9387c478bd9Sstevel@tonic-gate { 9397c478bd9Sstevel@tonic-gate struct i_path_findnode fn; 9407c478bd9Sstevel@tonic-gate extern dev_info_t *top_devinfo; 9417c478bd9Sstevel@tonic-gate 9427c478bd9Sstevel@tonic-gate /* 9437c478bd9Sstevel@tonic-gate * Get the nodeid of the given pathname, if such a mapping exists. 9447c478bd9Sstevel@tonic-gate */ 9457c478bd9Sstevel@tonic-gate fn.dip = NULL; 9467c478bd9Sstevel@tonic-gate fn.nodeid = prom_finddevice(path); 9477c478bd9Sstevel@tonic-gate if (fn.nodeid != OBP_BADNODE) { 9487c478bd9Sstevel@tonic-gate /* 9497c478bd9Sstevel@tonic-gate * Find the nodeid in our copy of the device tree and return 9507c478bd9Sstevel@tonic-gate * whatever name we used to bind this node to a driver. 9517c478bd9Sstevel@tonic-gate */ 9527c478bd9Sstevel@tonic-gate ddi_walk_devs(top_devinfo, i_path_find_node, (void *)(&fn)); 9537c478bd9Sstevel@tonic-gate } 9547c478bd9Sstevel@tonic-gate 9557c478bd9Sstevel@tonic-gate #ifdef DEBUG 9567c478bd9Sstevel@tonic-gate /* 9577c478bd9Sstevel@tonic-gate * If we're bound to something other than the nodename, 9587c478bd9Sstevel@tonic-gate * note that in the message buffer and system log. 9597c478bd9Sstevel@tonic-gate */ 9607c478bd9Sstevel@tonic-gate if (fn.dip) { 9617c478bd9Sstevel@tonic-gate char *p, *q; 9627c478bd9Sstevel@tonic-gate 9637c478bd9Sstevel@tonic-gate p = ddi_binding_name(fn.dip); 9647c478bd9Sstevel@tonic-gate q = ddi_node_name(fn.dip); 9657c478bd9Sstevel@tonic-gate if (p && q && (strcmp(p, q) != 0)) { 9667c478bd9Sstevel@tonic-gate BMDPRINTF(("path_to_devinfo: %s bound to %s\n", 9677c478bd9Sstevel@tonic-gate path, p)); 9687c478bd9Sstevel@tonic-gate } 9697c478bd9Sstevel@tonic-gate } 9707c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 9717c478bd9Sstevel@tonic-gate 9727c478bd9Sstevel@tonic-gate return (fn.dip); 9737c478bd9Sstevel@tonic-gate } 9747c478bd9Sstevel@tonic-gate 9757c478bd9Sstevel@tonic-gate /* 9767c478bd9Sstevel@tonic-gate * This routine returns B_TRUE if the bootpath corresponds to 9777c478bd9Sstevel@tonic-gate * IP over IB driver. 9787c478bd9Sstevel@tonic-gate * 9797c478bd9Sstevel@tonic-gate * The format of the bootpath for the IP over IB looks like 9807c478bd9Sstevel@tonic-gate * /pci@1f,700000/pci@1/ib@0:port=1,pkey=8001,protocol=ip 9817c478bd9Sstevel@tonic-gate * 9827c478bd9Sstevel@tonic-gate * The minor node portion "port=1,pkey=8001,protocol=ip" represents 9837c478bd9Sstevel@tonic-gate * IP over IB driver. 9847c478bd9Sstevel@tonic-gate */ 9857c478bd9Sstevel@tonic-gate static boolean_t 9867c478bd9Sstevel@tonic-gate netboot_over_ib(char *bootpath) 9877c478bd9Sstevel@tonic-gate { 9887c478bd9Sstevel@tonic-gate 9897c478bd9Sstevel@tonic-gate char *temp; 9907c478bd9Sstevel@tonic-gate boolean_t ret = B_FALSE; 991fa9e4066Sahrens pnode_t node = prom_finddevice(bootpath); 9927c478bd9Sstevel@tonic-gate int len; 9937c478bd9Sstevel@tonic-gate char devicetype[OBP_MAXDRVNAME]; 9947c478bd9Sstevel@tonic-gate 9957c478bd9Sstevel@tonic-gate /* Is this IB node ? */ 9967c478bd9Sstevel@tonic-gate len = prom_getproplen(node, OBP_DEVICETYPE); 9977c478bd9Sstevel@tonic-gate if (len <= 1 || len >= OBP_MAXDRVNAME) 9987c478bd9Sstevel@tonic-gate return (B_FALSE); 9997c478bd9Sstevel@tonic-gate 10007c478bd9Sstevel@tonic-gate (void) prom_getprop(node, OBP_DEVICETYPE, (caddr_t)devicetype); 10017c478bd9Sstevel@tonic-gate 10027c478bd9Sstevel@tonic-gate if (strncmp("ib", devicetype, 2) == 0) { 10037c478bd9Sstevel@tonic-gate /* Check for proper IP over IB string */ 10047c478bd9Sstevel@tonic-gate if ((temp = strstr(bootpath, ":port=")) != NULL) { 10057c478bd9Sstevel@tonic-gate if ((temp = strstr(temp, ",pkey=")) != NULL) 10067c478bd9Sstevel@tonic-gate if ((temp = strstr(temp, 10077c478bd9Sstevel@tonic-gate ",protocol=ip")) != NULL) { 10087c478bd9Sstevel@tonic-gate ret = B_TRUE; 10097c478bd9Sstevel@tonic-gate } 10107c478bd9Sstevel@tonic-gate } 10117c478bd9Sstevel@tonic-gate } 10127c478bd9Sstevel@tonic-gate return (ret); 10137c478bd9Sstevel@tonic-gate } 1014