xref: /titanic_50/usr/src/cmd/fm/modules/sun4/cpumem-diagnosis/cmd_mem.c (revision 5e992ba3a9b8749890ab15d3ca96a0b1a79641ac)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * Support routines for managing state related to memory modules.
28  */
29 
30 #include <cmd_mem.h>
31 #include <cmd_dimm.h>
32 #include <cmd_bank.h>
33 #include <cmd.h>
34 #ifdef sun4u
35 #include <cmd_dp.h>
36 #endif
37 #ifdef sun4v
38 #include <cmd_branch.h>
39 #endif
40 
41 #include <errno.h>
42 #include <strings.h>
43 #include <ctype.h>
44 #include <fcntl.h>
45 #include <unistd.h>
46 #include <fm/fmd_api.h>
47 #include <sys/fm/protocol.h>
48 #include <sys/mem.h>
49 #include <sys/nvpair.h>
50 
51 const char *
cmd_fmri_get_unum(nvlist_t * fmri)52 cmd_fmri_get_unum(nvlist_t *fmri)
53 {
54 	const char *scheme, *unum;
55 	uint8_t vers;
56 
57 	if (nvlist_lookup_pairs(fmri, 0,
58 	    FM_VERSION, DATA_TYPE_UINT8, &vers,
59 	    FM_FMRI_SCHEME, DATA_TYPE_STRING, &scheme,
60 	    FM_FMRI_MEM_UNUM, DATA_TYPE_STRING, &unum,
61 	    NULL) != 0 || vers > FM_MEM_SCHEME_VERSION ||
62 	    strcmp(scheme, FM_FMRI_SCHEME_MEM) != 0)
63 		return (NULL);
64 
65 	return (unum);
66 }
67 
68 char *
cmd_mem_serdnm_create(fmd_hdl_t * hdl,const char * serdbase,const char * unum)69 cmd_mem_serdnm_create(fmd_hdl_t *hdl, const char *serdbase, const char *unum)
70 {
71 	const char *fmt = "%s_%s_serd";
72 	size_t sz = snprintf(NULL, 0, fmt, serdbase, unum) + 1;
73 	char *nm = fmd_hdl_alloc(hdl, sz, FMD_SLEEP);
74 	(void) snprintf(nm, sz, fmt, serdbase, unum);
75 
76 	return (nm);
77 }
78 
79 char *
cmd_page_serdnm_create(fmd_hdl_t * hdl,const char * serdbase,uint64_t phys_addr)80 cmd_page_serdnm_create(fmd_hdl_t *hdl, const char *serdbase,
81     uint64_t phys_addr)
82 {
83 	const char *fmt = "%s_%llXserd";
84 	size_t sz = snprintf(NULL, 0, fmt, serdbase, phys_addr) + 1;
85 	char *nm = fmd_hdl_alloc(hdl, sz, FMD_SLEEP);
86 	(void) snprintf(nm, sz, fmt, serdbase, phys_addr);
87 
88 	return (nm);
89 }
90 
91 char *
cmd_mq_serdnm_create(fmd_hdl_t * hdl,const char * serdbase,uint64_t phys_addr,uint16_t cw,uint16_t pos)92 cmd_mq_serdnm_create(fmd_hdl_t *hdl, const char *serdbase,
93     uint64_t phys_addr, uint16_t cw, uint16_t pos)
94 {
95 	const char *fmt = "%s_%llX_%x_%x_serd";
96 	size_t sz = snprintf(NULL, 0, fmt, serdbase, phys_addr, cw, pos) + 1;
97 	char *nm = fmd_hdl_alloc(hdl, sz, FMD_SLEEP);
98 	(void) snprintf(nm, sz, fmt, serdbase, phys_addr, cw, pos);
99 
100 	return (nm);
101 }
102 
103 void
cmd_mem_case_restore(fmd_hdl_t * hdl,cmd_case_t * cc,fmd_case_t * cp,const char * serdbase,const char * unum)104 cmd_mem_case_restore(fmd_hdl_t *hdl, cmd_case_t *cc, fmd_case_t *cp,
105     const char *serdbase, const char *unum)
106 {
107 	cmd_case_restore(hdl, cc, cp, cmd_mem_serdnm_create(hdl, serdbase,
108 	    unum));
109 }
110 
111 void
cmd_mem_retirestat_create(fmd_hdl_t * hdl,fmd_stat_t * st,const char * unum,uint64_t value,const char * prefix)112 cmd_mem_retirestat_create(fmd_hdl_t *hdl, fmd_stat_t *st, const char *unum,
113     uint64_t value, const char *prefix)
114 {
115 	char *c;
116 
117 	/*
118 	 * Prior to Niagara-2, every bank had to have at least two dimms; it
119 	 * was therefore impossible for the retirestat of a bank to ever have
120 	 * the same name (strcmp() == 0) as that of a dimm.
121 	 *
122 	 * Niagara-2 and VF, in "single channel mode" , retrieve an entire
123 	 * cache line from a single dimm.  We therefore use a different
124 	 * prefix to name the bank retirestat vs. the dimm retirestat,
125 	 * or else the DE will abort trying to register a duplicate stat name
126 	 * with fmd.
127 	 */
128 	(void) snprintf(st->fmds_name, sizeof (st->fmds_name), "%s%s",
129 	    prefix, unum);
130 	(void) snprintf(st->fmds_desc, sizeof (st->fmds_desc),
131 	    "retirements for %s", unum);
132 	st->fmds_type = FMD_TYPE_UINT64;
133 	st->fmds_value.ui64 = value;
134 
135 	/*
136 	 * Sanitize the name of the statistic -- standard unums won't get
137 	 * by fmd's validity checker.
138 	 */
139 	for (c = st->fmds_name; *c != '\0'; c++) {
140 		if (!isupper(*c) && !islower(*c) &&
141 		    !isdigit(*c) && *c != '-' && *c != '_' && *c != '.')
142 			*c = '_';
143 	}
144 
145 	(void) fmd_stat_create(hdl, FMD_STAT_NOALLOC, 1, st);
146 }
147 
148 int
cmd_mem_thresh_check(fmd_hdl_t * hdl,uint_t nret)149 cmd_mem_thresh_check(fmd_hdl_t *hdl, uint_t nret)
150 {
151 	ulong_t npages = cmd_mem_get_phys_pages(hdl);
152 	ulong_t wrnpgs;
153 
154 	fmd_hdl_debug(hdl, "thresh_check: npages is %lu\n", npages);
155 	if (npages == 0) {
156 		return (0);
157 	}
158 
159 	if (cmd.cmd_thresh_abs_sysmem != 0) {
160 		wrnpgs = cmd.cmd_thresh_abs_sysmem;
161 	} else {
162 		/* threshold is in thousandths of a percent */
163 		wrnpgs = npages * cmd.cmd_thresh_tpct_sysmem / 100000;
164 	}
165 
166 	fmd_hdl_debug(hdl, "thresh_check: nret %u, wrn %lu\n", nret, wrnpgs);
167 
168 	return (nret > wrnpgs);
169 }
170 
171 nvlist_t *
cmd_mem_fmri_create(const char * unum,char ** serids,size_t nserids)172 cmd_mem_fmri_create(const char *unum, char **serids, size_t nserids)
173 {
174 	nvlist_t *fmri;
175 
176 	if ((errno = nvlist_alloc(&fmri, NV_UNIQUE_NAME, 0)) != 0)
177 		return (NULL);
178 
179 	if ((errno = nvlist_add_uint8(fmri, FM_VERSION,
180 	    FM_MEM_SCHEME_VERSION)) != 0 || (errno = nvlist_add_string(fmri,
181 	    FM_FMRI_SCHEME, FM_FMRI_SCHEME_MEM)) != 0 || (errno =
182 	    nvlist_add_string(fmri, FM_FMRI_MEM_UNUM, unum)) != 0) {
183 		nvlist_free(fmri);
184 		return (NULL);
185 	}
186 
187 	if ((nserids > 0) && (serids != NULL)) {
188 		(void) nvlist_add_string_array(fmri, FM_FMRI_MEM_SERIAL_ID,
189 		    serids, nserids);
190 	}
191 	return (fmri);
192 }
193 
194 nvlist_t *
cmd_mem_fmri_derive(fmd_hdl_t * hdl,uint64_t afar,uint64_t afsr,uint16_t synd)195 cmd_mem_fmri_derive(fmd_hdl_t *hdl, uint64_t afar, uint64_t afsr, uint16_t synd)
196 {
197 	mem_name_t mn;
198 	nvlist_t *fmri;
199 	int fd;
200 
201 	if ((fd = open("/dev/mem", O_RDONLY)) < 0)
202 		return (NULL);
203 
204 	mn.m_addr = afar;
205 	mn.m_synd = synd;
206 	mn.m_type[0] = afsr;
207 	mn.m_type[1] = 0;
208 	mn.m_namelen = 100;
209 
210 	for (;;) {
211 		mn.m_name = fmd_hdl_alloc(hdl, mn.m_namelen, FMD_SLEEP);
212 
213 		if (ioctl(fd, MEM_NAME, &mn) == 0)
214 			break;
215 
216 		fmd_hdl_free(hdl, mn.m_name, mn.m_namelen);
217 
218 		if (errno != ENOSPC) {
219 			(void) close(fd);
220 			return (NULL);
221 		}
222 
223 		mn.m_namelen *= 2;
224 	}
225 
226 	(void) close(fd);
227 
228 	fmri = cmd_mem_fmri_create(mn.m_name, NULL, 0);
229 	fmd_hdl_free(hdl, mn.m_name, mn.m_namelen);
230 
231 	return (fmri);
232 }
233 
234 void
cmd_iorxefrx_queue(fmd_hdl_t * hdl,cmd_iorxefrx_t * rf)235 cmd_iorxefrx_queue(fmd_hdl_t *hdl, cmd_iorxefrx_t *rf)
236 {
237 
238 	fmd_hdl_debug(hdl, "queueing IOxE/RxE/FRx for matching\n");
239 
240 	rf->rf_expid = fmd_timer_install(hdl, (void *)CMD_TIMERTYPE_MEM, NULL,
241 	    cmd.cmd_iorxefrx_window);
242 	cmd_list_append(&cmd.cmd_iorxefrx, rf);
243 }
244 
245 void
cmd_iorxefrx_free(fmd_hdl_t * hdl,cmd_iorxefrx_t * rf)246 cmd_iorxefrx_free(fmd_hdl_t *hdl, cmd_iorxefrx_t *rf)
247 {
248 	/* It's not persisted, so just remove it */
249 	cmd_list_delete(&cmd.cmd_iorxefrx, rf);
250 	fmd_hdl_free(hdl, rf, sizeof (cmd_iorxefrx_t));
251 }
252 
253 void
cmd_mem_timeout(fmd_hdl_t * hdl,id_t id)254 cmd_mem_timeout(fmd_hdl_t *hdl, id_t id)
255 {
256 	cmd_iorxefrx_t *rf;
257 
258 	for (rf = cmd_list_next(&cmd.cmd_iorxefrx); rf != NULL;
259 	    rf = cmd_list_next(rf)) {
260 		if (rf->rf_expid == id) {
261 			fmd_hdl_debug(hdl, "reclaiming iorxefrx tid %d\n", id);
262 			cmd_iorxefrx_free(hdl, rf);
263 			return;
264 		}
265 	}
266 }
267 
268 void
cmd_mem_gc(fmd_hdl_t * hdl)269 cmd_mem_gc(fmd_hdl_t *hdl)
270 {
271 	cmd_dimm_gc(hdl);
272 	cmd_bank_gc(hdl);
273 #ifdef sun4v
274 	cmd_branch_gc(hdl);
275 #endif
276 }
277 
278 void
cmd_mem_fini(fmd_hdl_t * hdl)279 cmd_mem_fini(fmd_hdl_t *hdl)
280 {
281 	cmd_iorxefrx_t *rf;
282 
283 	cmd_dimm_fini(hdl);
284 	cmd_bank_fini(hdl);
285 #ifdef sun4v
286 	cmd_branch_fini(hdl);
287 #endif
288 
289 	while ((rf = cmd_list_next(&cmd.cmd_iorxefrx)) != NULL)
290 		cmd_iorxefrx_free(hdl, rf);
291 }
292