8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / fm / modules / sun4 / cpumem-diagnosis / cmd_bank.c
blobf58ad6acb917c9620d9ba830029ca52fe102862a
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 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
28 #include <cmd_mem.h>
29 #include <cmd_bank.h>
30 #include <cmd_dimm.h>
31 #include <cmd.h>
33 #include <errno.h>
34 #include <string.h>
35 #include <strings.h>
36 #include <fcntl.h>
37 #include <unistd.h>
38 #include <fm/fmd_api.h>
39 #include <sys/fm/protocol.h>
40 #include <sys/mem.h>
41 #include <sys/nvpair.h>
43 void
44 cmd_bank_add_dimm(fmd_hdl_t *hdl, cmd_bank_t *bank, cmd_dimm_t *dimm)
46 cmd_bank_memb_t *bm;
48 fmd_hdl_debug(hdl, "attaching dimm %s to bank %s\n", dimm->dimm_unum,
49 bank->bank_unum);
51 dimm->dimm_bank = bank;
53 bm = fmd_hdl_zalloc(hdl, sizeof (cmd_bank_memb_t), FMD_SLEEP);
54 bm->bm_dimm = dimm;
55 cmd_list_append(&bank->bank_dimms, bm);
58 void
59 cmd_bank_remove_dimm(fmd_hdl_t *hdl, cmd_bank_t *bank, cmd_dimm_t *dimm)
61 cmd_bank_memb_t *bm;
63 fmd_hdl_debug(hdl, "detaching dimm %s from bank %s\n", dimm->dimm_unum,
64 bank->bank_unum);
66 for (bm = cmd_list_next(&bank->bank_dimms); bm != NULL;
67 bm = cmd_list_next(bm)) {
68 if (bm->bm_dimm != dimm)
69 continue;
71 cmd_list_delete(&bank->bank_dimms, bm);
72 dimm->dimm_bank = NULL;
73 fmd_hdl_free(hdl, bm, sizeof (cmd_bank_memb_t));
74 return;
77 fmd_hdl_abort(hdl, "attempt to disconnect dimm from non-parent bank\n");
80 static void
81 bank_dimmlist_create(fmd_hdl_t *hdl, cmd_bank_t *bank)
83 cmd_dimm_t *dimm;
85 for (dimm = cmd_list_next(&cmd.cmd_dimms); dimm != NULL;
86 dimm = cmd_list_next(dimm)) {
87 if (fmd_nvl_fmri_contains(hdl, bank->bank_asru_nvl,
88 dimm->dimm_asru_nvl))
89 cmd_bank_add_dimm(hdl, bank, dimm);
93 static void
94 bank_dimmlist_free(fmd_hdl_t *hdl, cmd_bank_t *bank)
96 cmd_bank_memb_t *bm;
98 while ((bm = cmd_list_next(&bank->bank_dimms)) != NULL) {
99 cmd_list_delete(&bank->bank_dimms, bm);
100 bm->bm_dimm->dimm_bank = NULL;
101 fmd_hdl_free(hdl, bm, sizeof (cmd_bank_memb_t));
105 nvlist_t *
106 cmd_bank_fru(cmd_bank_t *bank)
108 return (bank->bank_asru_nvl);
111 nvlist_t *
112 cmd_bank_create_fault(fmd_hdl_t *hdl, cmd_bank_t *bank, const char *fltnm,
113 uint_t cert)
115 return (cmd_nvl_create_fault(hdl, fltnm, cert, bank->bank_asru_nvl,
116 bank->bank_asru_nvl, NULL));
119 static void
120 bank_free(fmd_hdl_t *hdl, cmd_bank_t *bank, int destroy)
122 if (bank->bank_case.cc_cp != NULL)
123 cmd_case_fini(hdl, bank->bank_case.cc_cp, destroy);
125 bank_dimmlist_free(hdl, bank);
126 cmd_fmri_fini(hdl, &bank->bank_asru, destroy);
128 if (destroy)
129 fmd_buf_destroy(hdl, NULL, bank->bank_bufname);
130 cmd_list_delete(&cmd.cmd_banks, bank);
131 fmd_hdl_free(hdl, bank, sizeof (cmd_bank_t));
134 void
135 cmd_bank_destroy(fmd_hdl_t *hdl, cmd_bank_t *bank)
137 fmd_stat_destroy(hdl, 1, &(bank->bank_retstat));
138 bank_free(hdl, bank, FMD_B_TRUE);
141 static cmd_bank_t *
142 bank_lookup_by_unum(const char *unum)
144 cmd_bank_t *bank;
146 for (bank = cmd_list_next(&cmd.cmd_banks); bank != NULL;
147 bank = cmd_list_next(bank)) {
148 if (strcmp(bank->bank_unum, unum) == 0)
149 return (bank);
152 return (NULL);
155 cmd_bank_t *
156 cmd_bank_create(fmd_hdl_t *hdl, nvlist_t *asru)
158 cmd_bank_t *bank;
159 const char *unum;
161 if (!fmd_nvl_fmri_present(hdl, asru)) {
162 fmd_hdl_debug(hdl, "dimm_lookup: discarding old ereport\n");
163 return (NULL);
166 if ((unum = cmd_fmri_get_unum(asru)) == NULL) {
167 CMD_STAT_BUMP(bad_mem_asru);
168 return (NULL);
171 fmd_hdl_debug(hdl, "bank_create: creating new bank %s\n", unum);
172 CMD_STAT_BUMP(bank_creat);
174 bank = fmd_hdl_zalloc(hdl, sizeof (cmd_bank_t), FMD_SLEEP);
175 bank->bank_nodetype = CMD_NT_BANK;
176 bank->bank_version = CMD_BANK_VERSION;
178 cmd_bufname(bank->bank_bufname, sizeof (bank->bank_bufname), "bank_%s",
179 unum);
180 cmd_fmri_init(hdl, &bank->bank_asru, asru, "bank_asru_%s", unum);
182 (void) nvlist_lookup_string(bank->bank_asru_nvl, FM_FMRI_MEM_UNUM,
183 (char **)&bank->bank_unum);
185 bank_dimmlist_create(hdl, bank);
187 cmd_mem_retirestat_create(hdl, &bank->bank_retstat, bank->bank_unum, 0,
188 CMD_BANK_STAT_PREFIX);
190 cmd_list_append(&cmd.cmd_banks, bank);
191 cmd_bank_dirty(hdl, bank);
193 return (bank);
196 cmd_bank_t *
197 cmd_bank_lookup(fmd_hdl_t *hdl, nvlist_t *asru)
199 cmd_bank_t *bank;
200 const char *unum;
202 if ((unum = cmd_fmri_get_unum(asru)) == NULL) {
203 CMD_STAT_BUMP(bad_mem_asru);
204 return (NULL);
207 bank = bank_lookup_by_unum(unum);
209 if (bank != NULL && !fmd_nvl_fmri_present(hdl, bank->bank_asru_nvl)) {
210 fmd_hdl_debug(hdl, "bank_lookup: discarding old bank\n");
211 cmd_bank_destroy(hdl, bank);
212 return (NULL);
215 return (bank);
218 static cmd_bank_t *
219 bank_v0tov1(fmd_hdl_t *hdl, cmd_bank_0_t *old, size_t oldsz)
221 cmd_bank_t *new;
223 if (oldsz != sizeof (cmd_bank_0_t)) {
224 fmd_hdl_abort(hdl, "size of state doesn't match size of "
225 "version 0 state (%u bytes).\n", sizeof (cmd_bank_0_t));
228 new = fmd_hdl_zalloc(hdl, sizeof (cmd_bank_t), FMD_SLEEP);
229 new->bank_header = old->bank0_header;
230 new->bank_version = CMD_BANK_VERSION;
231 new->bank_asru = old->bank0_asru;
232 new->bank_nretired = old->bank0_nretired;
234 fmd_hdl_free(hdl, old, oldsz);
235 return (new);
238 static cmd_bank_t *
239 bank_wrapv1(fmd_hdl_t *hdl, cmd_bank_pers_t *pers, size_t psz)
241 cmd_bank_t *bank;
243 if (psz != sizeof (cmd_bank_pers_t)) {
244 fmd_hdl_abort(hdl, "size of state doesn't match size of "
245 "version 1 state (%u bytes).\n", sizeof (cmd_bank_pers_t));
248 bank = fmd_hdl_zalloc(hdl, sizeof (cmd_bank_t), FMD_SLEEP);
249 bcopy(pers, bank, sizeof (cmd_bank_pers_t));
250 fmd_hdl_free(hdl, pers, psz);
251 return (bank);
254 void *
255 cmd_bank_restore(fmd_hdl_t *hdl, fmd_case_t *cp, cmd_case_ptr_t *ptr)
257 cmd_bank_t *bank;
259 for (bank = cmd_list_next(&cmd.cmd_banks); bank != NULL;
260 bank = cmd_list_next(bank)) {
261 if (strcmp(bank->bank_bufname, ptr->ptr_name) == 0)
262 break;
265 if (bank == NULL) {
266 int migrated = 0;
267 size_t banksz;
269 fmd_hdl_debug(hdl, "restoring bank from %s\n", ptr->ptr_name);
271 if ((banksz = fmd_buf_size(hdl, NULL, ptr->ptr_name)) == 0) {
272 fmd_hdl_abort(hdl, "bank referenced by case %s does "
273 "not exist in saved state\n",
274 fmd_case_uuid(hdl, cp));
275 } else if (banksz > CMD_BANK_MAXSIZE ||
276 banksz < CMD_BANK_MINSIZE) {
277 fmd_hdl_abort(hdl, "bank buffer referenced by case %s "
278 "is out of bounds (is %u bytes, max %u, min %u)\n",
279 fmd_case_uuid(hdl, cp), banksz,
280 CMD_BANK_MAXSIZE, CMD_BANK_MAXSIZE);
283 if ((bank = cmd_buf_read(hdl, NULL, ptr->ptr_name,
284 banksz)) == NULL) {
285 fmd_hdl_abort(hdl, "failed to read bank buf %s",
286 ptr->ptr_name);
289 fmd_hdl_debug(hdl, "found %d in version field\n",
290 bank->bank_version);
292 if (CMD_BANK_VERSIONED(bank)) {
293 switch (bank->bank_version) {
294 case CMD_BANK_VERSION_1:
295 bank = bank_wrapv1(hdl, (cmd_bank_pers_t *)bank,
296 banksz);
297 break;
298 default:
299 fmd_hdl_abort(hdl, "unknown version (found %d) "
300 "for bank state referenced by case %s.\n",
301 bank->bank_version, fmd_case_uuid(hdl, cp));
302 break;
304 } else {
305 bank = bank_v0tov1(hdl, (cmd_bank_0_t *)bank, banksz);
306 migrated = 1;
309 if (migrated) {
310 CMD_STAT_BUMP(bank_migrat);
311 cmd_bank_dirty(hdl, bank);
314 cmd_fmri_restore(hdl, &bank->bank_asru);
316 if ((errno = nvlist_lookup_string(bank->bank_asru_nvl,
317 FM_FMRI_MEM_UNUM, (char **)&bank->bank_unum)) != 0)
318 fmd_hdl_abort(hdl, "failed to retrieve nuum from asru");
320 bank_dimmlist_create(hdl, bank);
322 cmd_mem_retirestat_create(hdl, &bank->bank_retstat,
323 bank->bank_unum, bank->bank_nretired, CMD_BANK_STAT_PREFIX);
325 cmd_list_append(&cmd.cmd_banks, bank);
328 switch (ptr->ptr_subtype) {
329 case BUG_PTR_BANK_CASE:
330 fmd_hdl_debug(hdl, "recovering from out of order page ptr\n");
331 cmd_case_redirect(hdl, cp, CMD_PTR_BANK_CASE);
332 /*FALLTHROUGH*/
333 case CMD_PTR_BANK_CASE:
334 cmd_mem_case_restore(hdl, &bank->bank_case, cp, "bank",
335 bank->bank_unum);
336 break;
337 default:
338 fmd_hdl_abort(hdl, "invalid %s subtype %d\n",
339 ptr->ptr_name, ptr->ptr_subtype);
342 return (bank);
345 void
346 cmd_bank_validate(fmd_hdl_t *hdl)
348 cmd_bank_t *bank, *next;
350 for (bank = cmd_list_next(&cmd.cmd_banks); bank != NULL; bank = next) {
351 next = cmd_list_next(bank);
353 if (!fmd_nvl_fmri_present(hdl, bank->bank_asru_nvl))
354 cmd_bank_destroy(hdl, bank);
358 void
359 cmd_bank_dirty(fmd_hdl_t *hdl, cmd_bank_t *bank)
361 if (fmd_buf_size(hdl, NULL, bank->bank_bufname) !=
362 sizeof (cmd_bank_pers_t))
363 fmd_buf_destroy(hdl, NULL, bank->bank_bufname);
365 /* No need to rewrite the FMRIs in the bank - they don't change */
366 fmd_buf_write(hdl, NULL, bank->bank_bufname, &bank->bank_pers,
367 sizeof (cmd_bank_pers_t));
370 void
371 cmd_bank_gc(fmd_hdl_t *hdl)
373 cmd_bank_validate(hdl);
376 void
377 cmd_bank_fini(fmd_hdl_t *hdl)
379 cmd_bank_t *bank;
381 while ((bank = cmd_list_next(&cmd.cmd_banks)) != NULL)
382 bank_free(hdl, bank, FMD_B_FALSE);