Print this page
patch tsoome-feedback
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/fm/modules/sun4v/generic-mem/gmem_page.c
+++ new/usr/src/cmd/fm/modules/sun4v/generic-mem/gmem_page.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
23 23 */
24 24
25 25
26 26 /*
27 27 * Support routines for managing per-page state.
28 28 */
29 29
30 30 #include <gmem_page.h>
31 31 #include <gmem_mem.h>
32 32 #include <gmem_dimm.h>
33 33 #include <gmem.h>
34 34
35 35 #include <errno.h>
36 36 #include <strings.h>
37 37 #include <fm/fmd_api.h>
38 38 #include <sys/fm/protocol.h>
39 39
40 40 static void
41 41 page_write(fmd_hdl_t *hdl, gmem_page_t *page)
42 42 {
43 43 fmd_buf_write(hdl, NULL, page->page_bufname, page,
44 44 sizeof (gmem_page_pers_t));
45 45 }
46 46
47 47 static void
48 48 gmem_page_free(fmd_hdl_t *hdl, gmem_page_t *page, int destroy)
49 49 {
50 50 gmem_case_t *cc = &page->page_case;
51 51
52 52 if (cc->cc_cp != NULL)
53 53 gmem_case_fini(hdl, cc->cc_cp, destroy);
54 54
55 55 if (cc->cc_serdnm != NULL) {
56 56 if (fmd_serd_exists(hdl, cc->cc_serdnm) && destroy)
57 57 fmd_serd_destroy(hdl, cc->cc_serdnm);
58 58 fmd_hdl_strfree(hdl, cc->cc_serdnm);
59 59 }
60 60
61 61 if (destroy)
62 62 fmd_buf_destroy(hdl, NULL, page->page_bufname);
63 63
64 64 gmem_fmri_fini(hdl, &page->page_asru, destroy);
65 65
66 66 gmem_list_delete(&gmem.gm_pages, page);
67 67 fmd_hdl_free(hdl, page, sizeof (gmem_page_t));
68 68 }
69 69
70 70 void
71 71 gmem_page_destroy(fmd_hdl_t *hdl, gmem_page_t *page)
72 72 {
73 73 fmd_hdl_debug(hdl, "destroying the page\n");
74 74 gmem_page_free(hdl, page, FMD_B_TRUE);
75 75 }
76 76
77 77 static gmem_page_t *
78 78 page_lookup_by_physaddr(uint64_t pa)
79 79 {
80 80 gmem_page_t *page;
81 81
82 82 for (page = gmem_list_next(&gmem.gm_pages); page != NULL;
83 83 page = gmem_list_next(page)) {
84 84 if (page->page_physbase == pa)
85 85 return (page);
86 86 }
87 87
88 88 return (NULL);
89 89 }
90 90
91 91 gmem_page_t *
92 92 gmem_page_create(fmd_hdl_t *hdl, nvlist_t *modasru, uint64_t pa,
93 93 uint64_t offset)
94 94 {
95 95 gmem_page_t *page;
96 96 nvlist_t *asru, *hsp;
97 97
98 98 pa = pa & gmem.gm_pagemask;
99 99
100 100 fmd_hdl_debug(hdl, "page_lookup: creating new page for %llx\n",
101 101 (u_longlong_t)pa);
102 102 GMEM_STAT_BUMP(page_creat);
103 103
104 104 page = fmd_hdl_zalloc(hdl, sizeof (gmem_page_t), FMD_SLEEP);
105 105 page->page_nodetype = GMEM_NT_PAGE;
106 106 page->page_version = CMD_PAGE_VERSION;
107 107 page->page_physbase = pa;
108 108 page->page_offset = offset;
109 109
110 110 gmem_bufname(page->page_bufname, sizeof (page->page_bufname),
111 111 "page_%llx", (u_longlong_t)pa);
112 112
113 113 if (nvlist_dup(modasru, &asru, 0) != 0) {
114 114 fmd_hdl_debug(hdl, "Page create nvlist dup failed");
115 115 return (NULL);
116 116 }
117 117
118 118 if (nvlist_alloc(&hsp, NV_UNIQUE_NAME, 0) != 0) {
119 119 fmd_hdl_debug(hdl, "Page create nvlist alloc failed");
120 120 nvlist_free(asru);
121 121 return (NULL);
122 122 }
123 123
124 124 if (nvlist_add_uint64(hsp, FM_FMRI_MEM_PHYSADDR,
125 125 page->page_physbase) != 0 ||
126 126 nvlist_add_uint64(hsp, FM_FMRI_HC_SPECIFIC_OFFSET,
127 127 page->page_offset) != 0 ||
128 128 nvlist_add_nvlist(asru, FM_FMRI_HC_SPECIFIC, hsp) != 0) {
129 129 fmd_hdl_debug(hdl, "Page create failed to build page fmri");
130 130 nvlist_free(asru);
131 131 nvlist_free(hsp);
132 132 return (NULL);
133 133 }
134 134
135 135 gmem_fmri_init(hdl, &page->page_asru, asru, "page_asru_%llx",
136 136 (u_longlong_t)pa);
137 137
138 138 nvlist_free(asru);
139 139 nvlist_free(hsp);
140 140
141 141 gmem_list_append(&gmem.gm_pages, page);
142 142 page_write(hdl, page);
143 143
144 144 return (page);
145 145 }
146 146
147 147 gmem_page_t *
148 148 gmem_page_lookup(uint64_t pa)
149 149 {
150 150 pa = pa & gmem.gm_pagemask;
151 151
152 152 return (page_lookup_by_physaddr(pa));
153 153 }
154 154
155 155 static gmem_page_t *
156 156 page_wrapv0(fmd_hdl_t *hdl, gmem_page_pers_t *pers, size_t psz)
157 157 {
158 158 gmem_page_t *page;
159 159
160 160 if (psz != sizeof (gmem_page_pers_t)) {
161 161 fmd_hdl_abort(hdl, "size of state doesn't match size of "
162 162 "version 0 state (%u bytes).\n", sizeof (gmem_page_pers_t));
163 163 }
164 164
165 165 page = fmd_hdl_zalloc(hdl, sizeof (gmem_page_t), FMD_SLEEP);
166 166 bcopy(pers, page, sizeof (gmem_page_pers_t));
167 167 fmd_hdl_free(hdl, pers, psz);
168 168 return (page);
169 169 }
170 170
171 171 void *
172 172 gmem_page_restore(fmd_hdl_t *hdl, fmd_case_t *cp, gmem_case_ptr_t *ptr)
173 173 {
174 174 gmem_page_t *page;
175 175
176 176 for (page = gmem_list_next(&gmem.gm_pages); page != NULL;
177 177 page = gmem_list_next(page)) {
178 178 if (strcmp(page->page_bufname, ptr->ptr_name) == 0)
179 179 break;
180 180 }
181 181
182 182 if (page == NULL) {
183 183 size_t pagesz;
184 184
185 185 fmd_hdl_debug(hdl, "restoring page from %s\n", ptr->ptr_name);
186 186
187 187 if ((pagesz = fmd_buf_size(hdl, NULL, ptr->ptr_name)) == 0) {
188 188 if (fmd_case_solved(hdl, cp) ||
189 189 fmd_case_closed(hdl, cp)) {
190 190 fmd_hdl_debug(hdl, "page %s from case %s not "
191 191 "found. Case is already solved or closed\n",
192 192 ptr->ptr_name, fmd_case_uuid(hdl, cp));
193 193 return (NULL);
194 194 } else {
195 195 fmd_hdl_abort(hdl, "page referenced by case %s "
196 196 "does not exist in saved state\n",
197 197 fmd_case_uuid(hdl, cp));
198 198 }
199 199 } else if (pagesz > CMD_PAGE_MAXSIZE ||
200 200 pagesz < CMD_PAGE_MINSIZE) {
201 201 fmd_hdl_abort(hdl, "page buffer referenced by case %s "
202 202 "is out of bounds (is %u bytes, max %u, min %u)\n",
203 203 fmd_case_uuid(hdl, cp), pagesz,
204 204 CMD_PAGE_MAXSIZE, CMD_PAGE_MINSIZE);
205 205 }
206 206
207 207 if ((page = gmem_buf_read(hdl, NULL, ptr->ptr_name,
208 208 pagesz)) == NULL) {
209 209 fmd_hdl_abort(hdl, "failed to read page buf %s",
210 210 ptr->ptr_name);
211 211 }
212 212
213 213 fmd_hdl_debug(hdl, "found %d in version field\n",
214 214 page->page_version);
215 215
216 216 switch (page->page_version) {
217 217 case CMD_PAGE_VERSION_0:
218 218 page = page_wrapv0(hdl, (gmem_page_pers_t *)page,
219 219 pagesz);
220 220 break;
221 221 default:
222 222 fmd_hdl_abort(hdl, "unknown version (found %d) "
223 223 "for page state referenced by case %s.\n",
224 224 page->page_version, fmd_case_uuid(hdl, cp));
225 225 break;
226 226 }
227 227
228 228 gmem_fmri_restore(hdl, &page->page_asru);
229 229
230 230 gmem_list_append(&gmem.gm_pages, page);
231 231 }
232 232
233 233 switch (ptr->ptr_subtype) {
234 234 case GMEM_PTR_PAGE_CASE:
235 235 gmem_case_restore(hdl, &page->page_case, cp,
236 236 gmem_page_serdnm_create(hdl, "page", page->page_physbase));
237 237 break;
238 238 default:
239 239 fmd_hdl_abort(hdl, "invalid %s subtype %d\n",
240 240 ptr->ptr_name, ptr->ptr_subtype);
241 241 }
242 242
243 243 return (page);
244 244 }
245 245
246 246 /*ARGSUSED*/
247 247 int
248 248 gmem_page_unusable(fmd_hdl_t *hdl, gmem_page_t *page)
249 249 {
250 250 nvlist_t *asru = NULL;
251 251 char *sn;
252 252
253 253 if (nvlist_lookup_string(page->page_asru_nvl,
254 254 FM_FMRI_HC_SERIAL_ID, &sn) != 0)
255 255 return (1);
256 256
257 257 /*
258 258 * get asru in mem scheme from topology
259 259 */
260 260 asru = gmem_find_dimm_asru(hdl, sn);
261 261 if (asru == NULL)
262 262 return (1);
263 263
↓ open down ↓ |
263 lines elided |
↑ open up ↑ |
264 264 (void) nvlist_add_string_array(asru, FM_FMRI_MEM_SERIAL_ID, &sn, 1);
265 265 (void) nvlist_add_uint64(asru, FM_FMRI_MEM_PHYSADDR,
266 266 page->page_physbase);
267 267 (void) nvlist_add_uint64(asru, FM_FMRI_MEM_OFFSET, page->page_offset);
268 268
269 269 if (fmd_nvl_fmri_unusable(hdl, asru)) {
270 270 nvlist_free(asru);
271 271 return (1);
272 272 }
273 273
274 - if (asru != NULL)
275 - nvlist_free(asru);
274 + nvlist_free(asru);
276 275
277 276 return (0);
278 277 }
279 278
280 279
281 280 /*ARGSUSED*/
282 281 void
283 282 gmem_page_validate(fmd_hdl_t *hdl)
284 283 {
285 284 gmem_page_t *page, *next;
286 285
287 286 for (page = gmem_list_next(&gmem.gm_pages); page != NULL; page = next) {
288 287 next = gmem_list_next(page);
289 288
290 289 if (gmem_page_unusable(hdl, page))
291 290 gmem_page_destroy(hdl, page);
292 291 }
293 292 }
294 293
295 294 void
296 295 gmem_page_dirty(fmd_hdl_t *hdl, gmem_page_t *page)
297 296 {
298 297 if (fmd_buf_size(hdl, NULL, page->page_bufname) !=
299 298 sizeof (gmem_page_pers_t))
300 299 fmd_buf_destroy(hdl, NULL, page->page_bufname);
301 300
302 301 /* No need to rewrite the FMRIs in the page - they don't change */
303 302 fmd_buf_write(hdl, NULL, page->page_bufname, &page->page_pers,
304 303 sizeof (gmem_page_pers_t));
305 304 }
306 305
307 306 void
308 307 gmem_page_fini(fmd_hdl_t *hdl)
309 308 {
310 309 gmem_page_t *page;
311 310
312 311 while ((page = gmem_list_next(&gmem.gm_pages)) != NULL)
313 312 gmem_page_free(hdl, page, FMD_B_FALSE);
314 313 }
315 314
316 315
317 316 int
318 317 gmem_page_fault(fmd_hdl_t *hdl, nvlist_t *fru, nvlist_t *rsc,
↓ open down ↓ |
33 lines elided |
↑ open up ↑ |
319 318 fmd_event_t *ep, uint64_t afar, uint64_t offset)
320 319 {
321 320 gmem_page_t *page = NULL;
322 321 const char *uuid;
323 322 nvlist_t *flt, *hsp;
324 323
325 324 page = gmem_page_lookup(afar);
326 325 if (page != NULL) {
327 326 if (page->page_flags & GMEM_F_FAULTING ||
328 327 gmem_page_unusable(hdl, page)) {
329 - if (rsc != NULL)
330 - nvlist_free(rsc);
328 + nvlist_free(rsc);
331 329 page->page_flags |= GMEM_F_FAULTING;
332 330 return (0);
333 331 }
334 332 } else {
335 333 page = gmem_page_create(hdl, fru, afar, offset);
336 334 }
337 335
338 336 page->page_flags |= GMEM_F_FAULTING;
339 337 if (page->page_case.cc_cp == NULL)
340 338 page->page_case.cc_cp = gmem_case_create(hdl,
341 339 &page->page_header, GMEM_PTR_PAGE_CASE, &uuid);
342 340
343 341 if (nvlist_lookup_nvlist(page->page_asru_nvl, FM_FMRI_HC_SPECIFIC,
344 342 &hsp) == 0)
345 343 (void) nvlist_add_nvlist(rsc, FM_FMRI_HC_SPECIFIC, hsp);
346 344
347 345 flt = fmd_nvl_create_fault(hdl, GMEM_FAULT_PAGE, 100, NULL, fru, rsc);
348 - if (rsc != NULL)
349 - nvlist_free(rsc);
346 + nvlist_free(rsc);
350 347
351 348 if (nvlist_add_boolean_value(flt, FM_SUSPECT_MESSAGE, B_FALSE) != 0)
352 349 fmd_hdl_abort(hdl, "failed to add no-message member to fault");
353 350
354 351 fmd_case_add_ereport(hdl, page->page_case.cc_cp, ep);
355 352 fmd_case_add_suspect(hdl, page->page_case.cc_cp, flt);
356 353 fmd_case_solve(hdl, page->page_case.cc_cp);
357 354 return (1);
358 355 }
359 356
360 357 void
361 358 gmem_page_close(fmd_hdl_t *hdl, void *arg)
362 359 {
363 360 gmem_page_destroy(hdl, arg);
364 361 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX