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 <gmem_mem.h>
31 #include <gmem_dimm.h>
32 #include <gmem.h>
33 
34 #include <assert.h>
35 #include <errno.h>
36 #include <strings.h>
37 #include <ctype.h>
38 #include <fcntl.h>
39 #include <unistd.h>
40 #include <fm/fmd_api.h>
41 #include <sys/fm/protocol.h>
42 #include <sys/mem.h>
43 #include <sys/nvpair.h>
44 
45 char *
gmem_mem_serdnm_create(fmd_hdl_t * hdl,const char * serdbase,const char * serial)46 gmem_mem_serdnm_create(fmd_hdl_t *hdl, const char *serdbase, const char *serial)
47 {
48 	const char *fmt = "%s_%s_serd";
49 	size_t sz = snprintf(NULL, 0, fmt, serdbase, serial) + 1;
50 	char *nm = fmd_hdl_alloc(hdl, sz, FMD_SLEEP);
51 	(void) snprintf(nm, sz, fmt, serdbase, serial);
52 
53 	return (nm);
54 }
55 
56 char *
gmem_page_serdnm_create(fmd_hdl_t * hdl,const char * serdbase,uint64_t phys_addr)57 gmem_page_serdnm_create(fmd_hdl_t *hdl, const char *serdbase,
58     uint64_t phys_addr)
59 {
60 	const char *fmt = "%s_%llXserd";
61 	size_t sz = snprintf(NULL, 0, fmt, serdbase, phys_addr) + 1;
62 	char *nm = fmd_hdl_alloc(hdl, sz, FMD_SLEEP);
63 	(void) snprintf(nm, sz, fmt, serdbase, phys_addr);
64 
65 	return (nm);
66 }
67 
68 char *
gmem_mq_serdnm_create(fmd_hdl_t * hdl,const char * serdbase,uint64_t phys_addr,uint16_t cw,uint16_t pos)69 gmem_mq_serdnm_create(fmd_hdl_t *hdl, const char *serdbase,
70     uint64_t phys_addr, uint16_t cw, uint16_t pos)
71 {
72 	const char *fmt = "%s_%llX_%x_%x_serd";
73 	size_t sz = snprintf(NULL, 0, fmt, serdbase, phys_addr, cw, pos) + 1;
74 	char *nm = fmd_hdl_alloc(hdl, sz, FMD_SLEEP);
75 	(void) snprintf(nm, sz, fmt, serdbase, phys_addr, cw, pos);
76 
77 	return (nm);
78 }
79 
80 uint32_t
gmem_get_serd_filter_ratio(nvlist_t * nvl)81 gmem_get_serd_filter_ratio(nvlist_t *nvl)
82 {
83 	uint32_t filter_ratio = 0;
84 	uint32_t erpt_ratio;
85 
86 	if (gmem.gm_filter_ratio == 0) {
87 		if (nvlist_lookup_uint32(nvl,
88 		    GMEM_ERPT_PAYLOAD_FILTER_RATIO, &erpt_ratio) == 0)
89 			filter_ratio = erpt_ratio;
90 	} else
91 		filter_ratio = gmem.gm_filter_ratio;
92 
93 	return (filter_ratio);
94 }
95 
96 void
gmem_page_serd_create(fmd_hdl_t * hdl,gmem_page_t * page,nvlist_t * nvl)97 gmem_page_serd_create(fmd_hdl_t *hdl, gmem_page_t *page, nvlist_t *nvl)
98 {
99 	uint32_t erpt_serdn, serd_n;
100 	uint64_t erpt_serdt, serd_t;
101 
102 	serd_n = gmem.gm_ce_n;
103 	serd_t = gmem.gm_ce_t;
104 
105 	if (serd_n == DEFAULT_SERDN && serd_t == DEFAULT_SERDT) {
106 		if (nvlist_lookup_uint32(nvl, GMEM_ERPT_PAYLOAD_SERDN,
107 		    &erpt_serdn) == 0)
108 			serd_n = erpt_serdn;
109 		if (nvlist_lookup_uint64(nvl, GMEM_ERPT_PAYLOAD_SERDT,
110 		    &erpt_serdt) == 0)
111 			serd_t = erpt_serdt;
112 	}
113 
114 	page->page_case.cc_serdnm = gmem_page_serdnm_create(hdl, "page",
115 	    page->page_physbase);
116 
117 	fmd_serd_create(hdl, page->page_case.cc_serdnm, serd_n, serd_t);
118 }
119 
120 int
gmem_serd_record(fmd_hdl_t * hdl,const char * serdbaser,uint32_t ratio,fmd_event_t * ep)121 gmem_serd_record(fmd_hdl_t *hdl, const char *serdbaser, uint32_t ratio,
122     fmd_event_t *ep)
123 {
124 	int i, rc;
125 	if (ratio == 0)
126 		return (fmd_serd_record(hdl, serdbaser, ep));
127 	for (i = 0; i < ratio; i++) {
128 		rc = fmd_serd_record(hdl, serdbaser, ep);
129 		if (rc != FMD_B_FALSE)
130 			break;
131 	}
132 	return (rc);
133 }
134 
135 void
gmem_mem_case_restore(fmd_hdl_t * hdl,gmem_case_t * cc,fmd_case_t * cp,const char * serdbase,const char * serial)136 gmem_mem_case_restore(fmd_hdl_t *hdl, gmem_case_t *cc, fmd_case_t *cp,
137     const char *serdbase, const char *serial)
138 {
139 	gmem_case_restore(hdl, cc, cp, gmem_mem_serdnm_create(hdl, serdbase,
140 	    serial));
141 }
142 
143 void
gmem_mem_retirestat_create(fmd_hdl_t * hdl,fmd_stat_t * st,const char * serial,uint64_t value,const char * prefix)144 gmem_mem_retirestat_create(fmd_hdl_t *hdl, fmd_stat_t *st, const char *serial,
145     uint64_t value, const char *prefix)
146 {
147 
148 	(void) snprintf(st->fmds_name, sizeof (st->fmds_name), "%s%s",
149 	    prefix, serial);
150 	(void) snprintf(st->fmds_desc, sizeof (st->fmds_desc),
151 	    "retirements for %s%s", prefix, serial);
152 	st->fmds_type = FMD_TYPE_UINT64;
153 	st->fmds_value.ui64 = value;
154 
155 	(void) fmd_stat_create(hdl, FMD_STAT_NOALLOC, 1, st);
156 }
157 
158 void
gmem_mem_gc(fmd_hdl_t * hdl)159 gmem_mem_gc(fmd_hdl_t *hdl)
160 {
161 	gmem_dimm_gc(hdl);
162 }
163 
164 void
gmem_mem_fini(fmd_hdl_t * hdl)165 gmem_mem_fini(fmd_hdl_t *hdl)
166 {
167 	gmem_dimm_fini(hdl);
168 }
169