xref: /titanic_52/usr/src/cmd/fm/schemes/mem/mem_unum.c (revision 84ab085a13f931bc78e7415e7ce921dbaa14fcb3)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <mem.h>
30 #include <fm/fmd_fmri.h>
31 
32 #include <string.h>
33 #include <strings.h>
34 #include <ctype.h>
35 
36 /*
37  * Given a DIMM or bank unum, mem_unum_burst will break it apart into individual
38  * DIMM names.  If it's a DIMM, one name will be returned.  If it's a bank, the
39  * unums for the individual DIMMs will be returned.
40  *
41  * Plain J-number DIMM and bank unums are simple.  J DIMMs have one J number.  J
42  * banks have multiple whitespace-separated J numbers.
43  *
44  * The others are more complex, and consist of a common portion c, a colon, and
45  * a DIMM-specific portion d.  DIMMs are of the form "c: d", while banks are of
46  * the form "c: d d ...".  The patterns are designed to handle the complex case,
47  * but also handle the simple ones as an afterthought.  bd_pat is used to
48  * match specific styles of unum.  In bd_pat, the first %n indicates the end of
49  * the common portion ("c" above).  The second %n marks the beginning of the
50  * repetitive portion ("d" above).  The third %n is used to determine whether or
51  * not the entire pattern matched.  bd_reppat is used to match instances of the
52  * repetitive part.
53  *
54  * sscanf is your disturbingly powerful friend.
55  */
56 
57 typedef struct bank_dimm {
58 	const char *bd_pat;
59 	const char *bd_reppat;
60 } bank_dimm_t;
61 
62 static const bank_dimm_t bank_dimm[] = {
63 	{ "%n%nJ%*4d%n",			" J%*4d%n" },
64 	{ "MB/P%*d/%nB%*d:%n%n",		" B%*d/D%*d%n" },
65 	{ "MB/P%*d/%nB%*d/D%*d:%n%n",		" B%*d/D%*d%n" },
66 	{ "C%*d/P%*d/%nB%*d:%n%n",		" B%*d/D%*d%n" },
67 	{ "C%*d/P%*d/%nB%*d/D%*d:%n%n",		" B%*d/D%*d%n" },
68 	{ "Slot %*c: %n%nJ%*4d%n",		" J%*4d%n" },
69 	{ "%n%nDIMM%*d%n",			" DIMM%*d%n" },
70 	{ "MB/%nDIMM%*d MB/DIMM%*d: %n%n",	" DIMM%*d%n" },
71 	{ "MB/%nDIMM%*d:%n%n",			" DIMM%*d%n" },
72 	{ NULL }
73 };
74 
75 /*
76  * Returns 0 (with dimmsp and ndimmsp set) if the unum could be bursted, -1
77  * otherwise.
78  */
79 int
80 mem_unum_burst(const char *pat, char ***dimmsp, size_t *ndimmsp)
81 {
82 	const bank_dimm_t *bd;
83 	char **dimms = NULL, **newdimms;
84 	size_t ndimms = 0;
85 	const char *c;
86 
87 	for (bd = bank_dimm; bd->bd_pat != NULL; bd++) {
88 		int replace, start, matched;
89 		char dimmname[64];
90 
91 		replace = start = matched = -1;
92 		(void) sscanf(pat, bd->bd_pat, &replace, &start, &matched);
93 		if (matched == -1)
94 			continue;
95 
96 		(void) strlcpy(dimmname, pat, sizeof (dimmname));
97 
98 		c = pat + start;
99 		while (*c != '\0') {
100 			int dimmlen = -1;
101 
102 			(void) sscanf(c, bd->bd_reppat, &dimmlen);
103 			if (dimmlen == -1)
104 				break;
105 
106 			while (*c == ' ') {
107 				c++;
108 				dimmlen--;
109 			}
110 
111 			if (dimmlen > sizeof (dimmname) - replace)
112 				break;
113 
114 			(void) strlcpy(dimmname + replace, c, dimmlen + 1);
115 
116 			newdimms = fmd_fmri_alloc(sizeof (char *) *
117 			    (ndimms + 1));
118 			if (ndimms != 0) {
119 				bcopy(dimms, newdimms, sizeof (char *) *
120 				    ndimms);
121 				fmd_fmri_free(dimms, sizeof (char *) * ndimms);
122 			}
123 			newdimms[ndimms++] = fmd_fmri_strdup(dimmname);
124 			dimms = newdimms;
125 
126 			c += dimmlen;
127 
128 			if (*c != ' ' && *c != '\0')
129 				break;
130 		}
131 
132 		if (*c != '\0')
133 			break;
134 
135 		*dimmsp = dimms;
136 		*ndimmsp = ndimms;
137 
138 		return (0);
139 	}
140 
141 	mem_strarray_free(dimms, ndimms);
142 	return (fmd_fmri_set_errno(EINVAL));
143 }
144 
145 /*
146  * The unum containership operation is designed to tell the caller whether a
147  * given FMRI contains another.  In the case of this plugin, we tell the caller
148  * whether a given memory FMRI (usually a bank) contains another (usually a
149  * DIMM).  We do this in one of two ways, depending on the platform.  For most
150  * platforms, we can use the bursting routine to generate the list of member
151  * unums from the container unum.  Membership can then be determined by
152  * searching the bursted list for the containee's unum.
153  *
154  * Some platforms, however, cannot be bursted, as their bank unums do not
155  * contain all of the information needed to generate the complete list of
156  * member DIMM unums.  For these unums, we must make do with a substring
157  * comparison.
158  */
159 
160 static int
161 unum_contains_bypat(const char *erunum, const char *eeunum)
162 {
163 	char **ernms, **eenms;
164 	uint_t nernms, neenms;
165 	int i, j, rv = 1;
166 
167 	if (mem_unum_burst(erunum, &ernms, &nernms) < 0)
168 		return (fmd_fmri_set_errno(EINVAL));
169 	if (mem_unum_burst(eeunum, &eenms, &neenms) < 0) {
170 		mem_strarray_free(ernms, nernms);
171 		return (fmd_fmri_set_errno(EINVAL));
172 	}
173 
174 	for (i = 0; i < neenms; i++) {
175 		for (j = 0; j < nernms; j++) {
176 			if (strcmp(eenms[i], ernms[j]) == 0)
177 				break;
178 		}
179 
180 		if (j == nernms) {
181 			/*
182 			 * This DIMM was not found in the container.
183 			 */
184 			rv = 0;
185 			break;
186 		}
187 	}
188 
189 	mem_strarray_free(ernms, nernms);
190 	mem_strarray_free(eenms, neenms);
191 
192 	return (rv);
193 }
194 
195 static int
196 unum_strip_one_jnum(const char *unum, uint_t *endp)
197 {
198 	char *c;
199 	int i;
200 
201 	if ((c = strrchr(unum, 'J')) == NULL)
202 		return (0);
203 
204 	while (c > unum && isspace(c[-1]))
205 		c--;
206 
207 	(void) sscanf(c, " J%*[0-9] %n", &i);
208 	if (i == 0 || (uintptr_t)(c - unum) + i != strlen(unum))
209 		return (0);
210 
211 	*endp = (uint_t)(c - unum);
212 	return (1);
213 }
214 
215 
216 static int
217 unum_contains_bysubstr(const char *erunum, const char *eeunum)
218 {
219 	uint_t erlen, eelen;
220 
221 	/*
222 	 * This comparison method is only known to work on specific types of
223 	 * unums.  Check for those types here.
224 	 */
225 	if ((strncmp(erunum, "/N", 2) != 0 && strncmp(erunum, "/IO", 3) != 0 &&
226 	    strncmp(erunum, "/SB", 3) != 0) ||
227 	    (strncmp(eeunum, "/N", 2) != 0 && strncmp(eeunum, "/IO", 3) != 0 &&
228 	    strncmp(eeunum, "/SB", 3) != 0))
229 		return (fmd_fmri_set_errno(EINVAL));
230 
231 	erlen = unum_strip_one_jnum(erunum, &erlen) ? erlen : strlen(erunum);
232 	eelen = unum_strip_one_jnum(eeunum, &eelen) ? eelen : strlen(eeunum);
233 
234 	return (strncmp(erunum, eeunum, MIN(erlen, eelen)) == 0);
235 }
236 
237 typedef int unum_cmptor_f(const char *, const char *);
238 
239 static unum_cmptor_f *const unum_cmptors[] = {
240 	unum_contains_bypat,
241 	unum_contains_bysubstr
242 };
243 
244 int
245 mem_unum_contains(const char *erunum, const char *eeunum)
246 {
247 	static int cmptor = 0;
248 	int rc;
249 
250 	while (isspace(*erunum))
251 		erunum++;
252 	while (isspace(*eeunum))
253 		eeunum++;
254 
255 	if ((rc = unum_cmptors[cmptor](erunum, eeunum)) >= 0)
256 		return (rc);
257 
258 	if ((rc = unum_cmptors[cmptor == 0](erunum, eeunum)) >= 0) {
259 		/*
260 		 * We succeeded with the non-default comparator.  Change the
261 		 * default so we use the correct one next time.
262 		 */
263 		cmptor = (cmptor == 0);
264 	}
265 
266 	return (rc);
267 }
268