dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / fm / modules / sun4v / generic-mem / gmem_page.c
blobe71a03df488e75039d3265995683970621fc33eb
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
22 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
27 * Support routines for managing per-page state.
30 #include <gmem_page.h>
31 #include <gmem_mem.h>
32 #include <gmem_dimm.h>
33 #include <gmem.h>
35 #include <errno.h>
36 #include <strings.h>
37 #include <fm/fmd_api.h>
38 #include <sys/fm/protocol.h>
40 static void
41 page_write(fmd_hdl_t *hdl, gmem_page_t *page)
43 fmd_buf_write(hdl, NULL, page->page_bufname, page,
44 sizeof (gmem_page_pers_t));
47 static void
48 gmem_page_free(fmd_hdl_t *hdl, gmem_page_t *page, int destroy)
50 gmem_case_t *cc = &page->page_case;
52 if (cc->cc_cp != NULL)
53 gmem_case_fini(hdl, cc->cc_cp, destroy);
55 if (cc->cc_serdnm != NULL) {
56 if (fmd_serd_exists(hdl, cc->cc_serdnm) && destroy)
57 fmd_serd_destroy(hdl, cc->cc_serdnm);
58 fmd_hdl_strfree(hdl, cc->cc_serdnm);
61 if (destroy)
62 fmd_buf_destroy(hdl, NULL, page->page_bufname);
64 gmem_fmri_fini(hdl, &page->page_asru, destroy);
66 gmem_list_delete(&gmem.gm_pages, page);
67 fmd_hdl_free(hdl, page, sizeof (gmem_page_t));
70 void
71 gmem_page_destroy(fmd_hdl_t *hdl, gmem_page_t *page)
73 fmd_hdl_debug(hdl, "destroying the page\n");
74 gmem_page_free(hdl, page, FMD_B_TRUE);
77 static gmem_page_t *
78 page_lookup_by_physaddr(uint64_t pa)
80 gmem_page_t *page;
82 for (page = gmem_list_next(&gmem.gm_pages); page != NULL;
83 page = gmem_list_next(page)) {
84 if (page->page_physbase == pa)
85 return (page);
88 return (NULL);
91 gmem_page_t *
92 gmem_page_create(fmd_hdl_t *hdl, nvlist_t *modasru, uint64_t pa,
93 uint64_t offset)
95 gmem_page_t *page;
96 nvlist_t *asru, *hsp;
98 pa = pa & gmem.gm_pagemask;
100 fmd_hdl_debug(hdl, "page_lookup: creating new page for %llx\n",
101 (u_longlong_t)pa);
102 GMEM_STAT_BUMP(page_creat);
104 page = fmd_hdl_zalloc(hdl, sizeof (gmem_page_t), FMD_SLEEP);
105 page->page_nodetype = GMEM_NT_PAGE;
106 page->page_version = CMD_PAGE_VERSION;
107 page->page_physbase = pa;
108 page->page_offset = offset;
110 gmem_bufname(page->page_bufname, sizeof (page->page_bufname),
111 "page_%llx", (u_longlong_t)pa);
113 if (nvlist_dup(modasru, &asru, 0) != 0) {
114 fmd_hdl_debug(hdl, "Page create nvlist dup failed");
115 return (NULL);
118 if (nvlist_alloc(&hsp, NV_UNIQUE_NAME, 0) != 0) {
119 fmd_hdl_debug(hdl, "Page create nvlist alloc failed");
120 nvlist_free(asru);
121 return (NULL);
124 if (nvlist_add_uint64(hsp, FM_FMRI_MEM_PHYSADDR,
125 page->page_physbase) != 0 ||
126 nvlist_add_uint64(hsp, FM_FMRI_HC_SPECIFIC_OFFSET,
127 page->page_offset) != 0 ||
128 nvlist_add_nvlist(asru, FM_FMRI_HC_SPECIFIC, hsp) != 0) {
129 fmd_hdl_debug(hdl, "Page create failed to build page fmri");
130 nvlist_free(asru);
131 nvlist_free(hsp);
132 return (NULL);
135 gmem_fmri_init(hdl, &page->page_asru, asru, "page_asru_%llx",
136 (u_longlong_t)pa);
138 nvlist_free(asru);
139 nvlist_free(hsp);
141 gmem_list_append(&gmem.gm_pages, page);
142 page_write(hdl, page);
144 return (page);
147 gmem_page_t *
148 gmem_page_lookup(uint64_t pa)
150 pa = pa & gmem.gm_pagemask;
152 return (page_lookup_by_physaddr(pa));
155 static gmem_page_t *
156 page_wrapv0(fmd_hdl_t *hdl, gmem_page_pers_t *pers, size_t psz)
158 gmem_page_t *page;
160 if (psz != sizeof (gmem_page_pers_t)) {
161 fmd_hdl_abort(hdl, "size of state doesn't match size of "
162 "version 0 state (%u bytes).\n", sizeof (gmem_page_pers_t));
165 page = fmd_hdl_zalloc(hdl, sizeof (gmem_page_t), FMD_SLEEP);
166 bcopy(pers, page, sizeof (gmem_page_pers_t));
167 fmd_hdl_free(hdl, pers, psz);
168 return (page);
171 void *
172 gmem_page_restore(fmd_hdl_t *hdl, fmd_case_t *cp, gmem_case_ptr_t *ptr)
174 gmem_page_t *page;
176 for (page = gmem_list_next(&gmem.gm_pages); page != NULL;
177 page = gmem_list_next(page)) {
178 if (strcmp(page->page_bufname, ptr->ptr_name) == 0)
179 break;
182 if (page == NULL) {
183 size_t pagesz;
185 fmd_hdl_debug(hdl, "restoring page from %s\n", ptr->ptr_name);
187 if ((pagesz = fmd_buf_size(hdl, NULL, ptr->ptr_name)) == 0) {
188 if (fmd_case_solved(hdl, cp) ||
189 fmd_case_closed(hdl, cp)) {
190 fmd_hdl_debug(hdl, "page %s from case %s not "
191 "found. Case is already solved or closed\n",
192 ptr->ptr_name, fmd_case_uuid(hdl, cp));
193 return (NULL);
194 } else {
195 fmd_hdl_abort(hdl, "page referenced by case %s "
196 "does not exist in saved state\n",
197 fmd_case_uuid(hdl, cp));
199 } else if (pagesz > CMD_PAGE_MAXSIZE ||
200 pagesz < CMD_PAGE_MINSIZE) {
201 fmd_hdl_abort(hdl, "page buffer referenced by case %s "
202 "is out of bounds (is %u bytes, max %u, min %u)\n",
203 fmd_case_uuid(hdl, cp), pagesz,
204 CMD_PAGE_MAXSIZE, CMD_PAGE_MINSIZE);
207 if ((page = gmem_buf_read(hdl, NULL, ptr->ptr_name,
208 pagesz)) == NULL) {
209 fmd_hdl_abort(hdl, "failed to read page buf %s",
210 ptr->ptr_name);
213 fmd_hdl_debug(hdl, "found %d in version field\n",
214 page->page_version);
216 switch (page->page_version) {
217 case CMD_PAGE_VERSION_0:
218 page = page_wrapv0(hdl, (gmem_page_pers_t *)page,
219 pagesz);
220 break;
221 default:
222 fmd_hdl_abort(hdl, "unknown version (found %d) "
223 "for page state referenced by case %s.\n",
224 page->page_version, fmd_case_uuid(hdl, cp));
225 break;
228 gmem_fmri_restore(hdl, &page->page_asru);
230 gmem_list_append(&gmem.gm_pages, page);
233 switch (ptr->ptr_subtype) {
234 case GMEM_PTR_PAGE_CASE:
235 gmem_case_restore(hdl, &page->page_case, cp,
236 gmem_page_serdnm_create(hdl, "page", page->page_physbase));
237 break;
238 default:
239 fmd_hdl_abort(hdl, "invalid %s subtype %d\n",
240 ptr->ptr_name, ptr->ptr_subtype);
243 return (page);
246 /*ARGSUSED*/
248 gmem_page_unusable(fmd_hdl_t *hdl, gmem_page_t *page)
250 nvlist_t *asru = NULL;
251 char *sn;
253 if (nvlist_lookup_string(page->page_asru_nvl,
254 FM_FMRI_HC_SERIAL_ID, &sn) != 0)
255 return (1);
258 * get asru in mem scheme from topology
260 asru = gmem_find_dimm_asru(hdl, sn);
261 if (asru == NULL)
262 return (1);
264 (void) nvlist_add_string_array(asru, FM_FMRI_MEM_SERIAL_ID, &sn, 1);
265 (void) nvlist_add_uint64(asru, FM_FMRI_MEM_PHYSADDR,
266 page->page_physbase);
267 (void) nvlist_add_uint64(asru, FM_FMRI_MEM_OFFSET, page->page_offset);
269 if (fmd_nvl_fmri_unusable(hdl, asru)) {
270 nvlist_free(asru);
271 return (1);
274 nvlist_free(asru);
276 return (0);
280 /*ARGSUSED*/
281 void
282 gmem_page_validate(fmd_hdl_t *hdl)
284 gmem_page_t *page, *next;
286 for (page = gmem_list_next(&gmem.gm_pages); page != NULL; page = next) {
287 next = gmem_list_next(page);
289 if (gmem_page_unusable(hdl, page))
290 gmem_page_destroy(hdl, page);
294 void
295 gmem_page_dirty(fmd_hdl_t *hdl, gmem_page_t *page)
297 if (fmd_buf_size(hdl, NULL, page->page_bufname) !=
298 sizeof (gmem_page_pers_t))
299 fmd_buf_destroy(hdl, NULL, page->page_bufname);
301 /* No need to rewrite the FMRIs in the page - they don't change */
302 fmd_buf_write(hdl, NULL, page->page_bufname, &page->page_pers,
303 sizeof (gmem_page_pers_t));
306 void
307 gmem_page_fini(fmd_hdl_t *hdl)
309 gmem_page_t *page;
311 while ((page = gmem_list_next(&gmem.gm_pages)) != NULL)
312 gmem_page_free(hdl, page, FMD_B_FALSE);
317 gmem_page_fault(fmd_hdl_t *hdl, nvlist_t *fru, nvlist_t *rsc,
318 fmd_event_t *ep, uint64_t afar, uint64_t offset)
320 gmem_page_t *page = NULL;
321 const char *uuid;
322 nvlist_t *flt, *hsp;
324 page = gmem_page_lookup(afar);
325 if (page != NULL) {
326 if (page->page_flags & GMEM_F_FAULTING ||
327 gmem_page_unusable(hdl, page)) {
328 nvlist_free(rsc);
329 page->page_flags |= GMEM_F_FAULTING;
330 return (0);
332 } else {
333 page = gmem_page_create(hdl, fru, afar, offset);
336 page->page_flags |= GMEM_F_FAULTING;
337 if (page->page_case.cc_cp == NULL)
338 page->page_case.cc_cp = gmem_case_create(hdl,
339 &page->page_header, GMEM_PTR_PAGE_CASE, &uuid);
341 if (nvlist_lookup_nvlist(page->page_asru_nvl, FM_FMRI_HC_SPECIFIC,
342 &hsp) == 0)
343 (void) nvlist_add_nvlist(rsc, FM_FMRI_HC_SPECIFIC, hsp);
345 flt = fmd_nvl_create_fault(hdl, GMEM_FAULT_PAGE, 100, NULL, fru, rsc);
346 nvlist_free(rsc);
348 if (nvlist_add_boolean_value(flt, FM_SUSPECT_MESSAGE, B_FALSE) != 0)
349 fmd_hdl_abort(hdl, "failed to add no-message member to fault");
351 fmd_case_add_ereport(hdl, page->page_case.cc_cp, ep);
352 fmd_case_add_suspect(hdl, page->page_case.cc_cp, flt);
353 fmd_case_solve(hdl, page->page_case.cc_cp);
354 return (1);
357 void
358 gmem_page_close(fmd_hdl_t *hdl, void *arg)
360 gmem_page_destroy(hdl, arg);