xref: /onnv-gate/usr/src/cmd/fm/schemes/mem/mem_unum.c (revision 6803:6467d9e78cae)
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
51302Sjroberts  * Common Development and Distribution License (the "License").
61302Sjroberts  * 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  */
211302Sjroberts 
220Sstevel@tonic-gate /*
236297Sjl139090  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <mem.h>
300Sstevel@tonic-gate #include <fm/fmd_fmri.h>
311414Scindi #include <fm/libtopo.h>
320Sstevel@tonic-gate 
330Sstevel@tonic-gate #include <string.h>
340Sstevel@tonic-gate #include <strings.h>
350Sstevel@tonic-gate #include <ctype.h>
360Sstevel@tonic-gate 
371493Sgavinm #define	ISHCUNUM(unum) (strncmp(unum, "hc:/", 4) == 0)
381493Sgavinm 
390Sstevel@tonic-gate /*
400Sstevel@tonic-gate  * Given a DIMM or bank unum, mem_unum_burst will break it apart into individual
410Sstevel@tonic-gate  * DIMM names.  If it's a DIMM, one name will be returned.  If it's a bank, the
420Sstevel@tonic-gate  * unums for the individual DIMMs will be returned.
430Sstevel@tonic-gate  *
440Sstevel@tonic-gate  * Plain J-number DIMM and bank unums are simple.  J DIMMs have one J number.  J
450Sstevel@tonic-gate  * banks have multiple whitespace-separated J numbers.
460Sstevel@tonic-gate  *
470Sstevel@tonic-gate  * The others are more complex, and consist of a common portion c, a colon, and
480Sstevel@tonic-gate  * a DIMM-specific portion d.  DIMMs are of the form "c: d", while banks are of
490Sstevel@tonic-gate  * the form "c: d d ...".  The patterns are designed to handle the complex case,
500Sstevel@tonic-gate  * but also handle the simple ones as an afterthought.  bd_pat is used to
510Sstevel@tonic-gate  * match specific styles of unum.  In bd_pat, the first %n indicates the end of
520Sstevel@tonic-gate  * the common portion ("c" above).  The second %n marks the beginning of the
530Sstevel@tonic-gate  * repetitive portion ("d" above).  The third %n is used to determine whether or
540Sstevel@tonic-gate  * not the entire pattern matched.  bd_reppat is used to match instances of the
550Sstevel@tonic-gate  * repetitive part.
560Sstevel@tonic-gate  *
570Sstevel@tonic-gate  * sscanf is your disturbingly powerful friend.
58600Stsien  *
59600Stsien  * The "bd_subst" element of the bank_dimm structure was added for Ontario
60600Stsien  * in order to accommodate its bank string names.  Previously, to convert
61600Stsien  * from a bank representation <common piece> <dimm1> <dimm2> ...
62600Stsien  * we concatenated the common piece with each dimm-specific piece in turn,
63600Stsien  * possibly deleting some characters in between.  Ontario is the first
64600Stsien  * platform which requires that characters be substituted (like a vi s/1/2/)
65600Stsien  * in place of characters deleted.  "bd_subst" represents the character(s)
66600Stsien  * to be substituted between the common piece and each dimm-specific piece
67600Stsien  * as part of the bursting.  For prior platforms, this value is skipped.
68600Stsien  *
69600Stsien  * Example:
70600Stsien  * input: "MB/CMP0/CH3: R1/D0/J1901 R1/D1/J2001"
71600Stsien  * outputs: "MB/CMP0/CH3/R1/D0/J1901", "MB/CMP0/CH3/R1/D1/J2001"
720Sstevel@tonic-gate  */
730Sstevel@tonic-gate 
740Sstevel@tonic-gate typedef struct bank_dimm {
750Sstevel@tonic-gate 	const char *bd_pat;
760Sstevel@tonic-gate 	const char *bd_reppat;
77600Stsien 	const char *bd_subst;
780Sstevel@tonic-gate } bank_dimm_t;
790Sstevel@tonic-gate 
800Sstevel@tonic-gate static const bank_dimm_t bank_dimm[] = {
810Sstevel@tonic-gate 	{ "%n%nJ%*4d%n",			" J%*4d%n" },
820Sstevel@tonic-gate 	{ "MB/P%*d/%nB%*d:%n%n",		" B%*d/D%*d%n" },
830Sstevel@tonic-gate 	{ "MB/P%*d/%nB%*d/D%*d:%n%n",		" B%*d/D%*d%n" },
840Sstevel@tonic-gate 	{ "C%*d/P%*d/%nB%*d:%n%n",		" B%*d/D%*d%n" },
850Sstevel@tonic-gate 	{ "C%*d/P%*d/%nB%*d/D%*d:%n%n",		" B%*d/D%*d%n" },
860Sstevel@tonic-gate 	{ "Slot %*c: %n%nJ%*4d%n",		" J%*4d%n" },
870Sstevel@tonic-gate 	{ "%n%nDIMM%*d%n",			" DIMM%*d%n" },
880Sstevel@tonic-gate 	{ "MB/%nDIMM%*d MB/DIMM%*d: %n%n",	" DIMM%*d%n" },
890Sstevel@tonic-gate 	{ "MB/%nDIMM%*d:%n%n",			" DIMM%*d%n" },
90600Stsien 	{ "MB/CMP%*d/CH%*d%n:%n%n",		" R%*d/D%*d/J%*4d%n",	"/" },
91600Stsien 	{ "MB/CMP%*d/CH%*d%n%n%n",		"/R%*d/D%*d/J%*4d%n" },
921302Sjroberts 	{ "MB/C%*d/P%*d/%nB%*d:%n%n",		" B%*d/D%*d%n" },
931302Sjroberts 	{ "MB/C%*d/P%*d/%nB%*d/D%*d:%n%n",	" B%*d/D%*d%n" },
942214Sav145390 	{ "/MBU_A/MEMB%*d/%n%nMEM%*d%*1c%n",	" MEM%*d%*1c%n" },
952214Sav145390 	{ "/MBU_B/MEMB%*d/%n%nMEM%*d%*1c%n",	" MEM%*d%*1c%n" },
966297Sjl139090 	{ "/MBU_A/%n%nMEM%*d%*1c%n",		" MEM%*d%*1c%n" },
972214Sav145390 	{ "/CMU%*2d/%n%nMEM%*2d%*1c%n",		" MEM%*2d%*1c%n" },
983530Srb144127 	{ "MB/CMP%*d/BR%*d%n:%n%n",		" CH%*d/D%*d/J%*4d%n", "/" },
994759Ssd77468 	{ "%n%nMB/CMP%*d/BR%*d/CH%*d/D%*d/J%*4d%n",
1004759Ssd77468 	    "MB/CMP%*d/BR%*d/CH%*d/D%*d/J%*4d%n" },
1014759Ssd77468 	{ "%n%nMB/CMP%*d/BR%*d/CH%*d/D%*d%n", "MB/CMP%*d/BR%*d/CH%*d/D%*d%n" },
1025430Ssd77468 	{ "MB/CPU%*d/CMP%*d/BR%*d%n:%n%n",	" CH%*d/D%*d/J%*4d%n", "/"},
1035430Ssd77468 	{ "MB/MEM%*d/CMP%*d/BR%*d%n:%n%n",	" CH%*d/D%*d/J%*4d%n", "/"},
1045430Ssd77468 	{ "%n%nMB/MEM%*d/CMP%*d/BR%*d/CH%*d/D%*d/J%*4d%n",
1055430Ssd77468 	    "MB/MEM%*d/CMP%*d/BR%*d/CH%*d/D%*d/J%*4d%n" },
1065430Ssd77468 	{ "%n%nMB/CPU%*d/CMP%*d/BR%*d/CH%*d/D%*d/J%*4d%n",
1075430Ssd77468 	    "MB/CPU%*d/CMP%*d/BR%*d/CH%*d/D%*d/J%*4d%n" },
1085430Ssd77468 	{ "%n%nMB/MEM%*d/CMP%*d/BR%*d/CH%*d/D%*d%n",
1095430Ssd77468 	    "MB/MEM%*d/CMP%*d/BR%*d/CH%*d/D%*d%n"  },
1105430Ssd77468 	{ "%n%nMB/CPU%*d/CMP%*d/BR%*d/CH%*d/D%*d%n",
1115430Ssd77468 	    "MB/CPU%*d/CMP%*d/BR%*d/CH%*d/D%*d%n"  },
1120Sstevel@tonic-gate 	{ NULL }
1130Sstevel@tonic-gate };
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate /*
1161186Sayznaga  * Burst Serengeti and Starcat-style unums.
1171186Sayznaga  * A DIMM unum string is expected to be in this form:
1181186Sayznaga  * "[/N0/]SB12/P0/B0/D2 [J13500]"
1191186Sayznaga  * A bank unum string is expected to be in this form:
1201186Sayznaga  * "[/N0/]SB12/P0/B0 [J13500, ...]"
1211186Sayznaga  */
1221186Sayznaga static int
mem_unum_burst_sgsc(const char * pat,char *** dimmsp,size_t * ndimmsp)1231186Sayznaga mem_unum_burst_sgsc(const char *pat, char ***dimmsp, size_t *ndimmsp)
1241186Sayznaga {
1251186Sayznaga 	char buf[64];
1261186Sayznaga 	char **dimms;
1271186Sayznaga 	char *base;
1281186Sayznaga 	const char *c;
1291186Sayznaga 	char *copy;
1301186Sayznaga 	size_t copysz;
1311186Sayznaga 	int i;
1321186Sayznaga 
1331186Sayznaga 	/*
1341186Sayznaga 	 * No expansion is required for a DIMM unum
1351186Sayznaga 	 */
1361186Sayznaga 	if (strchr(pat, 'D') != NULL) {
1371186Sayznaga 		dimms = fmd_fmri_alloc(sizeof (char *));
1381186Sayznaga 		dimms[0] = fmd_fmri_strdup(pat);
1391186Sayznaga 		*dimmsp = dimms;
1401186Sayznaga 		*ndimmsp = 1;
1411186Sayznaga 		return (0);
1421186Sayznaga 	}
1431186Sayznaga 
1441186Sayznaga 	/*
1451186Sayznaga 	 * strtok is destructive so we need to work with
1461186Sayznaga 	 * a copy and keep track of the size allocated.
1471186Sayznaga 	 */
1481186Sayznaga 	copysz = strlen(pat) + 1;
1491186Sayznaga 	copy = fmd_fmri_alloc(copysz);
1501186Sayznaga 	(void) strcpy(copy, pat);
1511186Sayznaga 
1521186Sayznaga 	base = strtok(copy, " ");
1531186Sayznaga 
1541186Sayznaga 	/* There are four DIMMs in a bank */
1551186Sayznaga 	dimms = fmd_fmri_alloc(sizeof (char *) * 4);
1561186Sayznaga 
1571186Sayznaga 	for (i = 0; i < 4; i++) {
1581186Sayznaga 		(void) snprintf(buf, sizeof (buf), "%s/D%d", base, i);
1591186Sayznaga 
1601186Sayznaga 		if ((c = strtok(NULL, " ")) != NULL)
1611186Sayznaga 			(void) snprintf(buf, sizeof (buf), "%s %s", buf, c);
1621186Sayznaga 
1631186Sayznaga 		dimms[i] = fmd_fmri_strdup(buf);
1641186Sayznaga 	}
1651186Sayznaga 
1661186Sayznaga 	fmd_fmri_free(copy, copysz);
1671186Sayznaga 
1681186Sayznaga 	*dimmsp = dimms;
1691186Sayznaga 	*ndimmsp = 4;
1701186Sayznaga 	return (0);
1711186Sayznaga }
1721186Sayznaga 
1731186Sayznaga 
1741186Sayznaga /*
1750Sstevel@tonic-gate  * Returns 0 (with dimmsp and ndimmsp set) if the unum could be bursted, -1
1760Sstevel@tonic-gate  * otherwise.
1770Sstevel@tonic-gate  */
1781186Sayznaga static int
mem_unum_burst_pattern(const char * pat,char *** dimmsp,size_t * ndimmsp)1791186Sayznaga mem_unum_burst_pattern(const char *pat, char ***dimmsp, size_t *ndimmsp)
1800Sstevel@tonic-gate {
1810Sstevel@tonic-gate 	const bank_dimm_t *bd;
1820Sstevel@tonic-gate 	char **dimms = NULL, **newdimms;
1830Sstevel@tonic-gate 	size_t ndimms = 0;
1840Sstevel@tonic-gate 	const char *c;
1850Sstevel@tonic-gate 
1861186Sayznaga 
1870Sstevel@tonic-gate 	for (bd = bank_dimm; bd->bd_pat != NULL; bd++) {
1880Sstevel@tonic-gate 		int replace, start, matched;
1890Sstevel@tonic-gate 		char dimmname[64];
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate 		replace = start = matched = -1;
1920Sstevel@tonic-gate 		(void) sscanf(pat, bd->bd_pat, &replace, &start, &matched);
1930Sstevel@tonic-gate 		if (matched == -1)
1940Sstevel@tonic-gate 			continue;
1950Sstevel@tonic-gate 		(void) strlcpy(dimmname, pat, sizeof (dimmname));
196600Stsien 		if (bd->bd_subst != NULL) {
197600Stsien 			(void) strlcpy(dimmname+replace, bd->bd_subst,
198600Stsien 			    sizeof (dimmname) - strlen(bd->bd_subst));
199600Stsien 			replace += strlen(bd->bd_subst);
200600Stsien 		}
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate 		c = pat + start;
2030Sstevel@tonic-gate 		while (*c != '\0') {
2040Sstevel@tonic-gate 			int dimmlen = -1;
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 			(void) sscanf(c, bd->bd_reppat, &dimmlen);
2070Sstevel@tonic-gate 			if (dimmlen == -1)
2080Sstevel@tonic-gate 				break;
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 			while (*c == ' ') {
2110Sstevel@tonic-gate 				c++;
2120Sstevel@tonic-gate 				dimmlen--;
2130Sstevel@tonic-gate 			}
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate 			if (dimmlen > sizeof (dimmname) - replace)
2160Sstevel@tonic-gate 				break;
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 			(void) strlcpy(dimmname + replace, c, dimmlen + 1);
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate 			newdimms = fmd_fmri_alloc(sizeof (char *) *
2210Sstevel@tonic-gate 			    (ndimms + 1));
2220Sstevel@tonic-gate 			if (ndimms != 0) {
2230Sstevel@tonic-gate 				bcopy(dimms, newdimms, sizeof (char *) *
2240Sstevel@tonic-gate 				    ndimms);
2250Sstevel@tonic-gate 				fmd_fmri_free(dimms, sizeof (char *) * ndimms);
2260Sstevel@tonic-gate 			}
2270Sstevel@tonic-gate 			newdimms[ndimms++] = fmd_fmri_strdup(dimmname);
2280Sstevel@tonic-gate 			dimms = newdimms;
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 			c += dimmlen;
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate 			if (*c != ' ' && *c != '\0')
2330Sstevel@tonic-gate 				break;
2340Sstevel@tonic-gate 		}
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate 		if (*c != '\0')
2370Sstevel@tonic-gate 			break;
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate 		*dimmsp = dimms;
2400Sstevel@tonic-gate 		*ndimmsp = ndimms;
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate 		return (0);
2430Sstevel@tonic-gate 	}
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 	mem_strarray_free(dimms, ndimms);
2461186Sayznaga 
247*6803Spothier 	/*
248*6803Spothier 	 * Set errno to ENOTSUP and return -1. This allows support for DIMMs
249*6803Spothier 	 * with unknown unum strings and/or serial numbers. The only consumer
250*6803Spothier 	 * of mem_unum_burst_pattern() that cares/checks for the returned
251*6803Spothier 	 * errno is fmd_fmri_expand().
252*6803Spothier 	 */
253*6803Spothier 	return (fmd_fmri_set_errno(ENOTSUP));
2540Sstevel@tonic-gate }
2550Sstevel@tonic-gate 
2561186Sayznaga int
mem_unum_burst(const char * pat,char *** dimmsp,size_t * ndimmsp)2571186Sayznaga mem_unum_burst(const char *pat, char ***dimmsp, size_t *ndimmsp)
2581186Sayznaga {
2591186Sayznaga 	const char *platform = fmd_fmri_get_platform();
2601186Sayznaga 
2611186Sayznaga 	/*
2621186Sayznaga 	 * Call mem_unum_burst_sgsc() for Starcat, Serengeti, and
2631186Sayznaga 	 * Lightweight 8 platforms.  Call mem_unum_burst_pattern()
2641186Sayznaga 	 * for all other platforms.
2651186Sayznaga 	 */
2661186Sayznaga 	if (strcmp(platform, "SUNW,Sun-Fire-15000") == 0 ||
2671186Sayznaga 	    strcmp(platform, "SUNW,Sun-Fire") == 0 ||
2681186Sayznaga 	    strcmp(platform, "SUNW,Netra-T12") == 0)
2691186Sayznaga 		return (mem_unum_burst_sgsc(pat, dimmsp, ndimmsp));
2701186Sayznaga 	else
2711186Sayznaga 		return (mem_unum_burst_pattern(pat, dimmsp, ndimmsp));
2721186Sayznaga }
2731186Sayznaga 
2740Sstevel@tonic-gate /*
2750Sstevel@tonic-gate  * The unum containership operation is designed to tell the caller whether a
2760Sstevel@tonic-gate  * given FMRI contains another.  In the case of this plugin, we tell the caller
2770Sstevel@tonic-gate  * whether a given memory FMRI (usually a bank) contains another (usually a
2780Sstevel@tonic-gate  * DIMM).  We do this in one of two ways, depending on the platform.  For most
2790Sstevel@tonic-gate  * platforms, we can use the bursting routine to generate the list of member
2800Sstevel@tonic-gate  * unums from the container unum.  Membership can then be determined by
2810Sstevel@tonic-gate  * searching the bursted list for the containee's unum.
2820Sstevel@tonic-gate  *
2830Sstevel@tonic-gate  * Some platforms, however, cannot be bursted, as their bank unums do not
2840Sstevel@tonic-gate  * contain all of the information needed to generate the complete list of
2850Sstevel@tonic-gate  * member DIMM unums.  For these unums, we must make do with a substring
2860Sstevel@tonic-gate  * comparison.
2870Sstevel@tonic-gate  */
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate static int
unum_contains_bypat(const char * erunum,const char * eeunum)2900Sstevel@tonic-gate unum_contains_bypat(const char *erunum, const char *eeunum)
2910Sstevel@tonic-gate {
2920Sstevel@tonic-gate 	char **ernms, **eenms;
2931303Swesolows 	size_t nernms, neenms;
2940Sstevel@tonic-gate 	int i, j, rv = 1;
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate 	if (mem_unum_burst(erunum, &ernms, &nernms) < 0)
2970Sstevel@tonic-gate 		return (fmd_fmri_set_errno(EINVAL));
2980Sstevel@tonic-gate 	if (mem_unum_burst(eeunum, &eenms, &neenms) < 0) {
2990Sstevel@tonic-gate 		mem_strarray_free(ernms, nernms);
3000Sstevel@tonic-gate 		return (fmd_fmri_set_errno(EINVAL));
3010Sstevel@tonic-gate 	}
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate 	for (i = 0; i < neenms; i++) {
3040Sstevel@tonic-gate 		for (j = 0; j < nernms; j++) {
3050Sstevel@tonic-gate 			if (strcmp(eenms[i], ernms[j]) == 0)
3060Sstevel@tonic-gate 				break;
3070Sstevel@tonic-gate 		}
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate 		if (j == nernms) {
3100Sstevel@tonic-gate 			/*
3110Sstevel@tonic-gate 			 * This DIMM was not found in the container.
3120Sstevel@tonic-gate 			 */
3130Sstevel@tonic-gate 			rv = 0;
3140Sstevel@tonic-gate 			break;
3150Sstevel@tonic-gate 		}
3160Sstevel@tonic-gate 	}
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 	mem_strarray_free(ernms, nernms);
3190Sstevel@tonic-gate 	mem_strarray_free(eenms, neenms);
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 	return (rv);
3220Sstevel@tonic-gate }
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate static int
unum_strip_one_jnum(const char * unum,uint_t * endp)3250Sstevel@tonic-gate unum_strip_one_jnum(const char *unum, uint_t *endp)
3260Sstevel@tonic-gate {
3270Sstevel@tonic-gate 	char *c;
3280Sstevel@tonic-gate 	int i;
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate 	if ((c = strrchr(unum, 'J')) == NULL)
3310Sstevel@tonic-gate 		return (0);
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 	while (c > unum && isspace(c[-1]))
3340Sstevel@tonic-gate 		c--;
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 	(void) sscanf(c, " J%*[0-9] %n", &i);
3370Sstevel@tonic-gate 	if (i == 0 || (uintptr_t)(c - unum) + i != strlen(unum))
3380Sstevel@tonic-gate 		return (0);
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate 	*endp = (uint_t)(c - unum);
3410Sstevel@tonic-gate 	return (1);
3420Sstevel@tonic-gate }
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate static int
unum_contains_bysubstr(const char * erunum,const char * eeunum)3460Sstevel@tonic-gate unum_contains_bysubstr(const char *erunum, const char *eeunum)
3470Sstevel@tonic-gate {
3480Sstevel@tonic-gate 	uint_t erlen, eelen;
3491493Sgavinm 	int nojnumstrip = 0;
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate 	/*
3520Sstevel@tonic-gate 	 * This comparison method is only known to work on specific types of
3530Sstevel@tonic-gate 	 * unums.  Check for those types here.
3540Sstevel@tonic-gate 	 */
3550Sstevel@tonic-gate 	if ((strncmp(erunum, "/N", 2) != 0 && strncmp(erunum, "/IO", 3) != 0 &&
3560Sstevel@tonic-gate 	    strncmp(erunum, "/SB", 3) != 0) ||
3570Sstevel@tonic-gate 	    (strncmp(eeunum, "/N", 2) != 0 && strncmp(eeunum, "/IO", 3) != 0 &&
3581493Sgavinm 	    strncmp(eeunum, "/SB", 3) != 0)) {
3592869Sgavinm 		if (ISHCUNUM(erunum) && ISHCUNUM(eeunum)) {
3601493Sgavinm 			nojnumstrip = 1;
3612869Sgavinm 			erlen = strlen(erunum);
3622869Sgavinm 			eelen = strlen(eeunum);
3632869Sgavinm 		} else {
3641493Sgavinm 			return (fmd_fmri_set_errno(EINVAL));
3652869Sgavinm 		}
3661493Sgavinm 	}
3670Sstevel@tonic-gate 
3681493Sgavinm 	if (!nojnumstrip) {
3691493Sgavinm 		erlen = unum_strip_one_jnum(erunum, &erlen) ?
3701493Sgavinm 		    erlen : strlen(erunum);
3711493Sgavinm 		eelen = unum_strip_one_jnum(eeunum, &eelen) ?
3721493Sgavinm 		    eelen : strlen(eeunum);
3731493Sgavinm 	}
3740Sstevel@tonic-gate 
3750Sstevel@tonic-gate 	return (strncmp(erunum, eeunum, MIN(erlen, eelen)) == 0);
3760Sstevel@tonic-gate }
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate typedef int unum_cmptor_f(const char *, const char *);
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate static unum_cmptor_f *const unum_cmptors[] = {
3810Sstevel@tonic-gate 	unum_contains_bypat,
3820Sstevel@tonic-gate 	unum_contains_bysubstr
3830Sstevel@tonic-gate };
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate int
mem_unum_contains(const char * erunum,const char * eeunum)3860Sstevel@tonic-gate mem_unum_contains(const char *erunum, const char *eeunum)
3870Sstevel@tonic-gate {
3880Sstevel@tonic-gate 	static int cmptor = 0;
3890Sstevel@tonic-gate 	int rc;
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate 	while (isspace(*erunum))
3920Sstevel@tonic-gate 		erunum++;
3930Sstevel@tonic-gate 	while (isspace(*eeunum))
3940Sstevel@tonic-gate 		eeunum++;
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 	if ((rc = unum_cmptors[cmptor](erunum, eeunum)) >= 0)
3970Sstevel@tonic-gate 		return (rc);
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 	if ((rc = unum_cmptors[cmptor == 0](erunum, eeunum)) >= 0) {
4000Sstevel@tonic-gate 		/*
4010Sstevel@tonic-gate 		 * We succeeded with the non-default comparator.  Change the
4020Sstevel@tonic-gate 		 * default so we use the correct one next time.
4030Sstevel@tonic-gate 		 */
4040Sstevel@tonic-gate 		cmptor = (cmptor == 0);
4050Sstevel@tonic-gate 	}
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate 	return (rc);
4080Sstevel@tonic-gate }
4091414Scindi 
4101414Scindi /*
4111414Scindi  * If an asru has a unum string that is an hc path string then return
4121414Scindi  * a new nvl (to be freed by the caller) that is a duplicate of the
4131414Scindi  * original but with an additional member of a reconstituted hc fmri.
4141414Scindi  */
4151414Scindi int
mem_unum_rewrite(nvlist_t * nvl,nvlist_t ** rnvl)4161414Scindi mem_unum_rewrite(nvlist_t *nvl, nvlist_t **rnvl)
4171414Scindi {
4181414Scindi 	int err;
4191414Scindi 	char *unumstr;
4201414Scindi 	nvlist_t *unum;
4211414Scindi 	struct topo_hdl *thp;
4221414Scindi 
4231414Scindi 	if (nvlist_lookup_string(nvl, FM_FMRI_MEM_UNUM, &unumstr) != 0 ||
4241493Sgavinm 	    !ISHCUNUM(unumstr))
4251414Scindi 		return (0);
4261414Scindi 
4274198Seschrock 	if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL)
4284198Seschrock 		return (EINVAL);
4291414Scindi 
4304198Seschrock 	if (topo_fmri_str2nvl(thp, unumstr, &unum, &err) != 0) {
4314198Seschrock 		fmd_fmri_topo_rele(thp);
4321414Scindi 		return (EINVAL);
4334198Seschrock 	}
4344198Seschrock 
4354198Seschrock 	fmd_fmri_topo_rele(thp);
4361414Scindi 
4371414Scindi 	if ((err = nvlist_dup(nvl, rnvl, 0)) != 0) {
4381414Scindi 		nvlist_free(unum);
4391414Scindi 		return (err);
4401414Scindi 	}
4411414Scindi 
4421414Scindi 	err = nvlist_add_nvlist(*rnvl, FM_FMRI_MEM_UNUM "-fmri", unum);
4431414Scindi 	nvlist_free(unum);
4441414Scindi 
4451414Scindi 	if (err != 0)
4461414Scindi 		nvlist_free(*rnvl);
4471414Scindi 
4481414Scindi 	return (err);
4491414Scindi }
450