10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*3982Svb70745 * Common Development and Distribution License (the "License"). 6*3982Svb70745 * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*3982Svb70745 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate /* 290Sstevel@tonic-gate * cpr functions for supported sparc platforms 300Sstevel@tonic-gate */ 310Sstevel@tonic-gate #include <sys/types.h> 320Sstevel@tonic-gate #include <sys/systm.h> 330Sstevel@tonic-gate #include <sys/cpr.h> 340Sstevel@tonic-gate #include <sys/kmem.h> 350Sstevel@tonic-gate #include <sys/errno.h> 360Sstevel@tonic-gate 370Sstevel@tonic-gate /* 380Sstevel@tonic-gate * new_def_info is used as tmp space to store new values and write them 390Sstevel@tonic-gate * to nvram. orig_def_info gets filled with the original nvram values, 400Sstevel@tonic-gate * gets written to disk, and later used by cprboot to restore the 410Sstevel@tonic-gate * original nvram values. 420Sstevel@tonic-gate */ 430Sstevel@tonic-gate static cdef_t *new_def_info; 440Sstevel@tonic-gate 450Sstevel@tonic-gate static cdef_t orig_def_info = { 460Sstevel@tonic-gate 0, 0, 470Sstevel@tonic-gate 0, "boot-file", "", /* props[0] */ 480Sstevel@tonic-gate 0, "boot-device", "", /* props[1] */ 490Sstevel@tonic-gate 0, "auto-boot?", "", /* props[2] */ 500Sstevel@tonic-gate 0, "diag-file", "", /* props[3] */ 510Sstevel@tonic-gate 0, "diag-device", "", /* props[4] */ 520Sstevel@tonic-gate }; 530Sstevel@tonic-gate 540Sstevel@tonic-gate /* 550Sstevel@tonic-gate * since the above array is the only place where cprop_t content 560Sstevel@tonic-gate * is specified, these defines are provided for quick/direct access. 570Sstevel@tonic-gate */ 580Sstevel@tonic-gate #define CPR_BF_IDX 0 /* index for boot-file */ 590Sstevel@tonic-gate #define CPR_BD_IDX 1 /* index for boot-device */ 600Sstevel@tonic-gate #define CPR_AB_IDX 2 /* index for auto-boot? */ 610Sstevel@tonic-gate #define CPR_DF_IDX 3 /* index for diag-file */ 620Sstevel@tonic-gate #define CPR_DD_IDX 4 /* index for diag-device */ 630Sstevel@tonic-gate 640Sstevel@tonic-gate #define CPR_PROP_PTR(dfp, idx) &(dfp)->props[idx] 650Sstevel@tonic-gate 660Sstevel@tonic-gate 670Sstevel@tonic-gate static char *cpr_next_component(char **); 680Sstevel@tonic-gate static char *cpr_get_prefix(char *); 69789Sahrens static char *cpr_build_nodename(pnode_t); 700Sstevel@tonic-gate static void cpr_abbreviate_devpath(char *, char *); 710Sstevel@tonic-gate static int cpr_show_props = 0; 720Sstevel@tonic-gate 730Sstevel@tonic-gate 740Sstevel@tonic-gate static int 75789Sahrens cpr_get_options_node(pnode_t *nodep) 760Sstevel@tonic-gate { 770Sstevel@tonic-gate *nodep = prom_optionsnode(); 780Sstevel@tonic-gate if (*nodep == OBP_NONODE || *nodep == OBP_BADNODE) { 790Sstevel@tonic-gate cpr_err(CE_WARN, "cannot get \"options\" node"); 800Sstevel@tonic-gate return (ENOENT); 810Sstevel@tonic-gate } 820Sstevel@tonic-gate 830Sstevel@tonic-gate return (0); 840Sstevel@tonic-gate } 850Sstevel@tonic-gate 860Sstevel@tonic-gate 870Sstevel@tonic-gate /* 880Sstevel@tonic-gate * returns non-zero on error, otherwise returns 0 and 890Sstevel@tonic-gate * sets the result code based on (prop value == "true") 900Sstevel@tonic-gate */ 910Sstevel@tonic-gate static int 920Sstevel@tonic-gate cpr_get_bool_prop(char *name, int *result) 930Sstevel@tonic-gate { 940Sstevel@tonic-gate char value[PROP_BOOL_LEN]; 95789Sahrens pnode_t node; 960Sstevel@tonic-gate int len, err; 970Sstevel@tonic-gate 980Sstevel@tonic-gate if (err = cpr_get_options_node(&node)) 990Sstevel@tonic-gate return (err); 1000Sstevel@tonic-gate len = prom_getproplen(node, name); 1010Sstevel@tonic-gate if (len < 0 || len >= sizeof (value)) 1020Sstevel@tonic-gate return (ENXIO); 1030Sstevel@tonic-gate bzero(value, sizeof (value)); 1040Sstevel@tonic-gate if (prom_getprop(node, name, value) != len) 1050Sstevel@tonic-gate return (ENOENT); 1060Sstevel@tonic-gate *result = (strcmp(value, "true") == 0); 1070Sstevel@tonic-gate return (0); 1080Sstevel@tonic-gate } 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate 1110Sstevel@tonic-gate /* 1120Sstevel@tonic-gate * write new or original values to nvram 1130Sstevel@tonic-gate */ 1140Sstevel@tonic-gate int 1150Sstevel@tonic-gate cpr_update_nvram(cprop_t *props) 1160Sstevel@tonic-gate { 1170Sstevel@tonic-gate cprop_t *tail; 118789Sahrens pnode_t node; 1190Sstevel@tonic-gate int len, rc; 1200Sstevel@tonic-gate 1210Sstevel@tonic-gate if (rc = cpr_get_options_node(&node)) 1220Sstevel@tonic-gate return (rc); 1230Sstevel@tonic-gate 1240Sstevel@tonic-gate if (cpr_show_props) 1250Sstevel@tonic-gate prom_printf("\ncpr_show_props:\n"); 1260Sstevel@tonic-gate for (tail = props + CPR_MAXPROP; props < tail; props++) { 1270Sstevel@tonic-gate if (cpr_show_props) { 1280Sstevel@tonic-gate prom_printf("mod=%c, name \"%s\",\tvalue \"%s\"\n", 1290Sstevel@tonic-gate props->mod, props->name, props->value); 1300Sstevel@tonic-gate } 1310Sstevel@tonic-gate if (props->mod == PROP_NOMOD) 1320Sstevel@tonic-gate continue; 1330Sstevel@tonic-gate /* 1340Sstevel@tonic-gate * Note: When doing a prom_setprop you must include the 1350Sstevel@tonic-gate * trailing NULL in the length argument, but when calling 1360Sstevel@tonic-gate * prom_getproplen() the NULL is excluded from the count! 1370Sstevel@tonic-gate */ 1380Sstevel@tonic-gate len = strlen(props->value); 1390Sstevel@tonic-gate rc = prom_setprop(node, props->name, props->value, len + 1); 1400Sstevel@tonic-gate if (rc < 0 || prom_getproplen(node, props->name) != len) { 1410Sstevel@tonic-gate cpr_err(CE_WARN, "cannot set nvram \"%s\" to \"%s\"", 1420Sstevel@tonic-gate props->name, props->value); 1430Sstevel@tonic-gate return (ENXIO); 1440Sstevel@tonic-gate } 1450Sstevel@tonic-gate } 1460Sstevel@tonic-gate 1470Sstevel@tonic-gate return (0); 1480Sstevel@tonic-gate } 1490Sstevel@tonic-gate 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate /* 1520Sstevel@tonic-gate * update nvram with the new or original nvram values; 1530Sstevel@tonic-gate * this routine provides local access to both sets 1540Sstevel@tonic-gate */ 1550Sstevel@tonic-gate int 1560Sstevel@tonic-gate cpr_set_properties(int new) 1570Sstevel@tonic-gate { 1580Sstevel@tonic-gate cprop_t *props; 1590Sstevel@tonic-gate 1600Sstevel@tonic-gate props = new ? new_def_info->props : orig_def_info.props; 1610Sstevel@tonic-gate return (cpr_update_nvram(props)); 1620Sstevel@tonic-gate } 1630Sstevel@tonic-gate 1640Sstevel@tonic-gate 1650Sstevel@tonic-gate 1660Sstevel@tonic-gate /* 1670Sstevel@tonic-gate * update the .mod field in both new_def_info and orig_def_info; 1680Sstevel@tonic-gate * this tells cpr and cprboot which properties to set/reset. 1690Sstevel@tonic-gate * then copy the arg str into a new property value at index 1700Sstevel@tonic-gate */ 1710Sstevel@tonic-gate static void 1720Sstevel@tonic-gate cpr_prop_update(int index, char *str) 1730Sstevel@tonic-gate { 1740Sstevel@tonic-gate cprop_t *prop; 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate prop = CPR_PROP_PTR(&orig_def_info, index); 1770Sstevel@tonic-gate prop->mod = PROP_MOD; 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate prop = CPR_PROP_PTR(new_def_info, index); 1800Sstevel@tonic-gate prop->mod = PROP_MOD; 1810Sstevel@tonic-gate (void) strcpy(prop->value, str); 1820Sstevel@tonic-gate } 1830Sstevel@tonic-gate 1840Sstevel@tonic-gate 1850Sstevel@tonic-gate /* 1860Sstevel@tonic-gate * setup new property values within new_def_info; 1870Sstevel@tonic-gate * these are used later to udpate nvram 1880Sstevel@tonic-gate */ 1890Sstevel@tonic-gate static int 1900Sstevel@tonic-gate cpr_prop_setup(void) 1910Sstevel@tonic-gate { 1920Sstevel@tonic-gate int len, err, ds_ival, dev_idx, file_idx; 1930Sstevel@tonic-gate char bootdev[OBP_MAXPATHLEN], bootfile[OBP_MAXPATHLEN]; 1940Sstevel@tonic-gate char *cp, *sp; 1950Sstevel@tonic-gate 1960Sstevel@tonic-gate /* 1970Sstevel@tonic-gate * create a new boot-device value. for some older prom revs, 1980Sstevel@tonic-gate * a fully qualified device path can be truncated when stored 1990Sstevel@tonic-gate * to nvram. this call generates the shortest equivalent. 2000Sstevel@tonic-gate * using devaliases could be simpler in most cases. 2010Sstevel@tonic-gate */ 2020Sstevel@tonic-gate cpr_abbreviate_devpath(prom_bootpath(), bootdev); 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate /* 2050Sstevel@tonic-gate * create a new boot-file value; flags get appended when 206*3982Svb70745 * not reusable and when the statefile is a block device 2070Sstevel@tonic-gate */ 2080Sstevel@tonic-gate (void) strcpy(bootfile, CPRBOOT); 209*3982Svb70745 if (!cpr_reusable_mode && cpr_statefile_is_spec()) 2100Sstevel@tonic-gate sp = " -S "; 2110Sstevel@tonic-gate else 2120Sstevel@tonic-gate sp = NULL; 2130Sstevel@tonic-gate if (sp) { 2140Sstevel@tonic-gate (void) strcat(bootfile, sp); 2150Sstevel@tonic-gate len = strlen(bootfile); 2160Sstevel@tonic-gate sp = cpr_get_statefile_prom_path(); 2170Sstevel@tonic-gate cpr_abbreviate_devpath(sp, &bootfile[len]); 2180Sstevel@tonic-gate } 2190Sstevel@tonic-gate 2200Sstevel@tonic-gate /* 2210Sstevel@tonic-gate * record property info for booting with cprboot based on 2220Sstevel@tonic-gate * the value of diag-switch?. when "false", set boot-device 2230Sstevel@tonic-gate * and boot-file; when "true", set diag-device and diag-file 2240Sstevel@tonic-gate */ 2250Sstevel@tonic-gate if (err = cpr_get_bool_prop("diag-switch?", &ds_ival)) 2260Sstevel@tonic-gate return (err); 2270Sstevel@tonic-gate else if (ds_ival == 0) { 2280Sstevel@tonic-gate dev_idx = CPR_BD_IDX; 2290Sstevel@tonic-gate file_idx = CPR_BF_IDX; 2300Sstevel@tonic-gate } else { 2310Sstevel@tonic-gate dev_idx = CPR_DD_IDX; 2320Sstevel@tonic-gate file_idx = CPR_DF_IDX; 2330Sstevel@tonic-gate } 2340Sstevel@tonic-gate cpr_prop_update(dev_idx, bootdev); 235*3982Svb70745 236*3982Svb70745 if (!cpr_reusable_mode) 237*3982Svb70745 cpr_prop_update(file_idx, bootfile); 2380Sstevel@tonic-gate 2390Sstevel@tonic-gate /* 2400Sstevel@tonic-gate * check/set auto-boot? 2410Sstevel@tonic-gate */ 2420Sstevel@tonic-gate sp = orig_def_info.props[CPR_AB_IDX].value; 2430Sstevel@tonic-gate cp = "true"; 2440Sstevel@tonic-gate if (strcmp(sp, cp)) 2450Sstevel@tonic-gate cpr_prop_update(CPR_AB_IDX, cp); 2460Sstevel@tonic-gate 2470Sstevel@tonic-gate return (0); 2480Sstevel@tonic-gate } 2490Sstevel@tonic-gate 2500Sstevel@tonic-gate 2510Sstevel@tonic-gate /* 2520Sstevel@tonic-gate * setup the original and new sets of property names/values 2530Sstevel@tonic-gate */ 2540Sstevel@tonic-gate int 2550Sstevel@tonic-gate cpr_default_setup(int alloc) 2560Sstevel@tonic-gate { 2570Sstevel@tonic-gate cprop_t *orig, *new, *tail; 2580Sstevel@tonic-gate int len, err = 0; 259789Sahrens pnode_t node; 2600Sstevel@tonic-gate char *fmt; 2610Sstevel@tonic-gate 2620Sstevel@tonic-gate if (alloc == 0) { 2630Sstevel@tonic-gate ASSERT(new_def_info); 2640Sstevel@tonic-gate kmem_free(new_def_info, sizeof (*new_def_info)); 2650Sstevel@tonic-gate new_def_info = NULL; 2660Sstevel@tonic-gate return (0); 2670Sstevel@tonic-gate } 2680Sstevel@tonic-gate 2690Sstevel@tonic-gate if (err = cpr_get_options_node(&node)) 2700Sstevel@tonic-gate return (err); 2710Sstevel@tonic-gate 2720Sstevel@tonic-gate /* 2730Sstevel@tonic-gate * allocate space for new properties, get the original nvram 2740Sstevel@tonic-gate * property values, mark both property sets with PROP_NOMOD, 2750Sstevel@tonic-gate * and copy the original prop names to the new set. 2760Sstevel@tonic-gate */ 2770Sstevel@tonic-gate ASSERT(new_def_info == NULL); 2780Sstevel@tonic-gate new_def_info = kmem_zalloc(sizeof (*new_def_info), KM_SLEEP); 2790Sstevel@tonic-gate new = new_def_info->props; 2800Sstevel@tonic-gate 2810Sstevel@tonic-gate for (orig = orig_def_info.props, tail = orig + CPR_MAXPROP; 2820Sstevel@tonic-gate orig < tail; orig++, new++) { 2830Sstevel@tonic-gate len = prom_getproplen(node, orig->name); 2840Sstevel@tonic-gate if (len < 0 || len >= (int)sizeof (orig->value)) { 2850Sstevel@tonic-gate fmt = "invalid property or length for \"%s\""; 2860Sstevel@tonic-gate err = ENXIO; 2870Sstevel@tonic-gate break; 2880Sstevel@tonic-gate } 2890Sstevel@tonic-gate bzero(orig->value, sizeof (orig->value)); 2900Sstevel@tonic-gate if (prom_getprop(node, orig->name, orig->value) < 0) { 2910Sstevel@tonic-gate fmt = "cannot get \"%s\" value"; 2920Sstevel@tonic-gate err = ENXIO; 2930Sstevel@tonic-gate break; 2940Sstevel@tonic-gate } 2950Sstevel@tonic-gate 2960Sstevel@tonic-gate new->mod = orig->mod = PROP_NOMOD; 2970Sstevel@tonic-gate (void) strcpy(new->name, orig->name); 2980Sstevel@tonic-gate } 2990Sstevel@tonic-gate 3000Sstevel@tonic-gate if (err) { 3010Sstevel@tonic-gate kmem_free(new_def_info, sizeof (*new_def_info)); 3020Sstevel@tonic-gate new_def_info = NULL; 3030Sstevel@tonic-gate cpr_err(CE_WARN, fmt, orig->name); 3040Sstevel@tonic-gate } else 3050Sstevel@tonic-gate err = cpr_prop_setup(); 3060Sstevel@tonic-gate 3070Sstevel@tonic-gate return (err); 3080Sstevel@tonic-gate } 3090Sstevel@tonic-gate 3100Sstevel@tonic-gate 3110Sstevel@tonic-gate int 3120Sstevel@tonic-gate cpr_validate_definfo(int reusable) 3130Sstevel@tonic-gate { 3140Sstevel@tonic-gate orig_def_info.mini.magic = CPR->c_cprboot_magic = CPR_DEFAULT_MAGIC; 3150Sstevel@tonic-gate orig_def_info.mini.reusable = reusable; 3160Sstevel@tonic-gate return (cpr_write_deffile(&orig_def_info)); 3170Sstevel@tonic-gate } 3180Sstevel@tonic-gate 3190Sstevel@tonic-gate 3200Sstevel@tonic-gate void 3210Sstevel@tonic-gate cpr_send_notice(void) 3220Sstevel@tonic-gate { 3230Sstevel@tonic-gate static char cstr[] = "\014" "\033[1P" "\033[18;21H"; 3240Sstevel@tonic-gate 3250Sstevel@tonic-gate prom_printf(cstr); 3260Sstevel@tonic-gate prom_printf("Saving System State. Please Wait... "); 3270Sstevel@tonic-gate } 3280Sstevel@tonic-gate 3290Sstevel@tonic-gate void 3300Sstevel@tonic-gate cpr_spinning_bar(void) 3310Sstevel@tonic-gate { 3320Sstevel@tonic-gate static char *spin_strings[] = { "|\b", "/\b", "-\b", "\\\b" }; 3330Sstevel@tonic-gate static int idx; 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate prom_printf(spin_strings[idx]); 3360Sstevel@tonic-gate if (++idx == 4) 3370Sstevel@tonic-gate idx = 0; 3380Sstevel@tonic-gate } 3390Sstevel@tonic-gate 3400Sstevel@tonic-gate /* 3410Sstevel@tonic-gate * Convert a full device path to its shortest unambiguous equivalent. 3420Sstevel@tonic-gate * For example, a path which starts out /iommu@x,y/sbus@i,j/espdma . . . 3430Sstevel@tonic-gate * might be converted to /iommu/sbus/espdma . . . If we encounter 3440Sstevel@tonic-gate * problems at any point, just output the unabbreviated path. 3450Sstevel@tonic-gate */ 3460Sstevel@tonic-gate static void 3470Sstevel@tonic-gate cpr_abbreviate_devpath(char *in_path, char *out_path) 3480Sstevel@tonic-gate { 349789Sahrens static pnode_t cur_node; 3500Sstevel@tonic-gate char *position = in_path + 1; /* Skip the leading slash. */ 3510Sstevel@tonic-gate char *cmpt; 3520Sstevel@tonic-gate 3530Sstevel@tonic-gate cur_node = prom_nextnode(0); 3540Sstevel@tonic-gate *out_path = '\0'; 3550Sstevel@tonic-gate 3560Sstevel@tonic-gate while ((cmpt = cpr_next_component(&position)) != NULL) { 357789Sahrens pnode_t long_match = NULL; 358789Sahrens pnode_t short_match = NULL; 3590Sstevel@tonic-gate int short_hits = 0; 3600Sstevel@tonic-gate char *name; 3610Sstevel@tonic-gate char *prefix = cpr_get_prefix(cmpt); 3620Sstevel@tonic-gate 3630Sstevel@tonic-gate /* Go to next tree level by getting first child. */ 3640Sstevel@tonic-gate if ((cur_node = prom_childnode(cur_node)) == 0) { 3650Sstevel@tonic-gate (void) strcpy(out_path, in_path); 3660Sstevel@tonic-gate return; 3670Sstevel@tonic-gate } 3680Sstevel@tonic-gate 3690Sstevel@tonic-gate /* 3700Sstevel@tonic-gate * Traverse the current level and remember the node (if any) 3710Sstevel@tonic-gate * where we match on the fully qualified component name. 3720Sstevel@tonic-gate * Also remember the node of the most recent prefix match 3730Sstevel@tonic-gate * and the number of such matches. 3740Sstevel@tonic-gate */ 3750Sstevel@tonic-gate do { 3760Sstevel@tonic-gate name = cpr_build_nodename(cur_node); 3770Sstevel@tonic-gate if (strcmp(name, cmpt) == 0) 3780Sstevel@tonic-gate long_match = cur_node; 3790Sstevel@tonic-gate if (strncmp(prefix, name, strlen(prefix)) == 0) { 3800Sstevel@tonic-gate short_match = cur_node; 3810Sstevel@tonic-gate short_hits++; 3820Sstevel@tonic-gate } 3830Sstevel@tonic-gate } while ((cur_node = prom_nextnode(cur_node)) != 0); 3840Sstevel@tonic-gate 3850Sstevel@tonic-gate /* 3860Sstevel@tonic-gate * We don't want to be too dependent on what we know 3870Sstevel@tonic-gate * about how the names are stored. We just assume that 3880Sstevel@tonic-gate * if there is only one match on the prefix, we can 3890Sstevel@tonic-gate * use it, otherwise we need to use a fully qualified 3900Sstevel@tonic-gate * name. In the "impossible" cases we just give up 3910Sstevel@tonic-gate * and use the complete input devpath. 3920Sstevel@tonic-gate */ 3930Sstevel@tonic-gate (void) strcat(out_path, "/"); 3940Sstevel@tonic-gate if (short_hits == 1) { 3950Sstevel@tonic-gate (void) strcat(out_path, prefix); 3960Sstevel@tonic-gate cur_node = short_match; 3970Sstevel@tonic-gate } 3980Sstevel@tonic-gate else 3990Sstevel@tonic-gate if (long_match) { 4000Sstevel@tonic-gate (void) strcat(out_path, cmpt); 4010Sstevel@tonic-gate cur_node = long_match; 4020Sstevel@tonic-gate } else { 4030Sstevel@tonic-gate (void) strcpy(out_path, in_path); 4040Sstevel@tonic-gate return; 4050Sstevel@tonic-gate } 4060Sstevel@tonic-gate } 4070Sstevel@tonic-gate /* We need to copy the target and slice info manually. */ 4080Sstevel@tonic-gate (void) strcat(out_path, strrchr(in_path, '@')); 4090Sstevel@tonic-gate } 4100Sstevel@tonic-gate 4110Sstevel@tonic-gate /* 4120Sstevel@tonic-gate * Return a pointer to the next component of a device path or NULL if 4130Sstevel@tonic-gate * the entire path has been consumed. Note that we update the caller's 4140Sstevel@tonic-gate * pointer to the current position in the full pathname buffer. 4150Sstevel@tonic-gate */ 4160Sstevel@tonic-gate static char * 4170Sstevel@tonic-gate cpr_next_component(char **path) 4180Sstevel@tonic-gate { 4190Sstevel@tonic-gate static char obuf[64]; 4200Sstevel@tonic-gate char *slash; 4210Sstevel@tonic-gate int len = strlen(*path); 4220Sstevel@tonic-gate 4230Sstevel@tonic-gate if (len == 0) 4240Sstevel@tonic-gate return (NULL); 4250Sstevel@tonic-gate 4260Sstevel@tonic-gate if ((slash = strchr(*path, '/'))) { 4270Sstevel@tonic-gate len = slash - *path; 4280Sstevel@tonic-gate (void) strncpy(obuf, *path, len); 4290Sstevel@tonic-gate obuf[len] = '\0'; 4300Sstevel@tonic-gate *path += len + 1; /* Position beyond the slash. */ 4310Sstevel@tonic-gate } else { 4320Sstevel@tonic-gate (void) strcpy(obuf, *path); 4330Sstevel@tonic-gate *path += len; /* Position at the terminal NULL. */ 4340Sstevel@tonic-gate } 4350Sstevel@tonic-gate 4360Sstevel@tonic-gate return (obuf); 4370Sstevel@tonic-gate } 4380Sstevel@tonic-gate 4390Sstevel@tonic-gate /* 4400Sstevel@tonic-gate * Return a pointer to the prefix (i.e., the basic unqualified node name) 4410Sstevel@tonic-gate * Basically, this is the part of the fully qualified name before the @. 4420Sstevel@tonic-gate */ 4430Sstevel@tonic-gate static char * 4440Sstevel@tonic-gate cpr_get_prefix(char *cmpt) 4450Sstevel@tonic-gate { 4460Sstevel@tonic-gate static char prefix[OBP_MAXDRVNAME]; 4470Sstevel@tonic-gate char *at_sign = strchr(cmpt, '@'); 4480Sstevel@tonic-gate int len = at_sign ? at_sign - cmpt : strlen(cmpt); 4490Sstevel@tonic-gate 4500Sstevel@tonic-gate (void) strncpy(prefix, cmpt, len); 4510Sstevel@tonic-gate prefix[len] = '\0'; 4520Sstevel@tonic-gate 4530Sstevel@tonic-gate return (prefix); 4540Sstevel@tonic-gate } 4550Sstevel@tonic-gate 4560Sstevel@tonic-gate /* 4570Sstevel@tonic-gate * Build the unambiguous name for the current node, like iommu@f,e10000000. 4580Sstevel@tonic-gate * The prefix is just the "name" property, and the qualifier is constructed 4590Sstevel@tonic-gate * from the first two (binary) words of the "reg" property. 4600Sstevel@tonic-gate */ 4610Sstevel@tonic-gate static char * 462789Sahrens cpr_build_nodename(pnode_t node) 4630Sstevel@tonic-gate { 4640Sstevel@tonic-gate static char name[OBP_MAXPATHLEN]; 4650Sstevel@tonic-gate int reg[512]; 4660Sstevel@tonic-gate char buf[32]; /* must contain expansion of @%x,%x */ 4670Sstevel@tonic-gate int prop_len = prom_getproplen(node, OBP_NAME); 4680Sstevel@tonic-gate 4690Sstevel@tonic-gate if (prop_len < 0 || prop_len >= sizeof (name) || 4700Sstevel@tonic-gate prom_getprop(node, OBP_NAME, name) < 0) 4710Sstevel@tonic-gate return (""); 4720Sstevel@tonic-gate name[prop_len] = '\0'; 4730Sstevel@tonic-gate 4740Sstevel@tonic-gate if ((prop_len = prom_getproplen(node, OBP_REG)) < 4750Sstevel@tonic-gate 2 * sizeof (int) || prop_len >= sizeof (reg)) 4760Sstevel@tonic-gate return (name); 4770Sstevel@tonic-gate 4780Sstevel@tonic-gate if (prom_getprop(node, OBP_REG, (caddr_t)reg) < 0) 4790Sstevel@tonic-gate return (name); 4800Sstevel@tonic-gate 4810Sstevel@tonic-gate (void) sprintf(buf, "@%x,%x", reg[0], reg[1]); 4820Sstevel@tonic-gate (void) strcat(name, buf); 4830Sstevel@tonic-gate 4840Sstevel@tonic-gate return (name); 4850Sstevel@tonic-gate } 4860Sstevel@tonic-gate 4870Sstevel@tonic-gate /* 4880Sstevel@tonic-gate * Makes a printable list of prom_prop names for error messages 4890Sstevel@tonic-gate * Caller must free space. 4900Sstevel@tonic-gate */ 4910Sstevel@tonic-gate char * 4920Sstevel@tonic-gate cpr_enumerate_promprops(char **bufp, size_t *len) 4930Sstevel@tonic-gate { 4940Sstevel@tonic-gate cprop_t *prop, *tail; 4950Sstevel@tonic-gate size_t size = 2; /* for "." */ 4960Sstevel@tonic-gate char *buf; 4970Sstevel@tonic-gate 4980Sstevel@tonic-gate tail = &orig_def_info.props[CPR_MAXPROP]; 4990Sstevel@tonic-gate for (prop = orig_def_info.props; prop < tail; prop++) 5000Sstevel@tonic-gate size += strlen(prop->name) + 2; /* + ", " */ 5010Sstevel@tonic-gate 5020Sstevel@tonic-gate buf = kmem_alloc(size, KM_SLEEP); 5030Sstevel@tonic-gate *buf = '\0'; 5040Sstevel@tonic-gate 5050Sstevel@tonic-gate for (prop = orig_def_info.props; prop < tail; prop++) { 5060Sstevel@tonic-gate if (strlen(buf)) 5070Sstevel@tonic-gate (void) strcat(buf, ", "); 5080Sstevel@tonic-gate (void) strcat(buf, prop->name); 5090Sstevel@tonic-gate } 5100Sstevel@tonic-gate (void) strcat(buf, "."); 5110Sstevel@tonic-gate 5120Sstevel@tonic-gate *bufp = buf; 5130Sstevel@tonic-gate *len = size; 5140Sstevel@tonic-gate return (buf); 5150Sstevel@tonic-gate } 516