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.
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.
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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * Support routines for managing state related to memory modules.
38 #include <cmd_branch.h>
46 #include <fm/fmd_api.h>
47 #include <sys/fm/protocol.h>
49 #include <sys/nvpair.h>
52 cmd_fmri_get_unum(nvlist_t
*fmri
)
54 const char *scheme
, *unum
;
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)
69 cmd_mem_serdnm_create(fmd_hdl_t
*hdl
, const char *serdbase
, const char *unum
)
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
);
80 cmd_page_serdnm_create(fmd_hdl_t
*hdl
, const char *serdbase
,
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
);
92 cmd_mq_serdnm_create(fmd_hdl_t
*hdl
, const char *serdbase
,
93 uint64_t phys_addr
, uint16_t cw
, uint16_t pos
)
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
);
104 cmd_mem_case_restore(fmd_hdl_t
*hdl
, cmd_case_t
*cc
, fmd_case_t
*cp
,
105 const char *serdbase
, const char *unum
)
107 cmd_case_restore(hdl
, cc
, cp
, cmd_mem_serdnm_create(hdl
, serdbase
,
112 cmd_mem_retirestat_create(fmd_hdl_t
*hdl
, fmd_stat_t
*st
, const char *unum
,
113 uint64_t value
, const char *prefix
)
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.
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
128 (void) snprintf(st
->fmds_name
, sizeof (st
->fmds_name
), "%s%s",
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
;
136 * Sanitize the name of the statistic -- standard unums won't get
137 * by fmd's validity checker.
139 for (c
= st
->fmds_name
; *c
!= '\0'; c
++) {
140 if (!isupper(*c
) && !islower(*c
) &&
141 !isdigit(*c
) && *c
!= '-' && *c
!= '_' && *c
!= '.')
145 (void) fmd_stat_create(hdl
, FMD_STAT_NOALLOC
, 1, st
);
149 cmd_mem_thresh_check(fmd_hdl_t
*hdl
, uint_t nret
)
151 ulong_t npages
= cmd_mem_get_phys_pages(hdl
);
154 fmd_hdl_debug(hdl
, "thresh_check: npages is %lu\n", npages
);
159 if (cmd
.cmd_thresh_abs_sysmem
!= 0) {
160 wrnpgs
= cmd
.cmd_thresh_abs_sysmem
;
162 /* threshold is in thousandths of a percent */
163 wrnpgs
= npages
* cmd
.cmd_thresh_tpct_sysmem
/ 100000;
166 fmd_hdl_debug(hdl
, "thresh_check: nret %u, wrn %lu\n", nret
, wrnpgs
);
168 return (nret
> wrnpgs
);
172 cmd_mem_fmri_create(const char *unum
, char **serids
, size_t nserids
)
176 if ((errno
= nvlist_alloc(&fmri
, NV_UNIQUE_NAME
, 0)) != 0)
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) {
187 if ((nserids
> 0) && (serids
!= NULL
)) {
188 (void) nvlist_add_string_array(fmri
, FM_FMRI_MEM_SERIAL_ID
,
195 cmd_mem_fmri_derive(fmd_hdl_t
*hdl
, uint64_t afar
, uint64_t afsr
, uint16_t synd
)
201 if ((fd
= open("/dev/mem", O_RDONLY
)) < 0)
211 mn
.m_name
= fmd_hdl_alloc(hdl
, mn
.m_namelen
, FMD_SLEEP
);
213 if (ioctl(fd
, MEM_NAME
, &mn
) == 0)
216 fmd_hdl_free(hdl
, mn
.m_name
, mn
.m_namelen
);
218 if (errno
!= ENOSPC
) {
228 fmri
= cmd_mem_fmri_create(mn
.m_name
, NULL
, 0);
229 fmd_hdl_free(hdl
, mn
.m_name
, mn
.m_namelen
);
235 cmd_iorxefrx_queue(fmd_hdl_t
*hdl
, cmd_iorxefrx_t
*rf
)
238 fmd_hdl_debug(hdl
, "queueing IOxE/RxE/FRx for matching\n");
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
);
246 cmd_iorxefrx_free(fmd_hdl_t
*hdl
, cmd_iorxefrx_t
*rf
)
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
));
254 cmd_mem_timeout(fmd_hdl_t
*hdl
, id_t id
)
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
);
269 cmd_mem_gc(fmd_hdl_t
*hdl
)
279 cmd_mem_fini(fmd_hdl_t
*hdl
)
286 cmd_branch_fini(hdl
);
289 while ((rf
= cmd_list_next(&cmd
.cmd_iorxefrx
)) != NULL
)
290 cmd_iorxefrx_free(hdl
, rf
);