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 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 
27 /*
28  * Case management and saved state restoration
29  */
30 
31 #include <cmd_state.h>
32 #include <cmd_cpu.h>
33 #include <cmd_mem.h>
34 #include <cmd_page.h>
35 #include <cmd_dimm.h>
36 #ifdef sun4u
37 #include <cmd_dp.h>
38 #include <cmd_dp_page.h>
39 #include <cmd_Lxcache.h>
40 #endif
41 #include <cmd_bank.h>
42 #include <cmd.h>
43 #ifdef sun4v
44 #include <cmd_branch.h>
45 #endif
46 
47 #include <string.h>
48 #include <fm/fmd_api.h>
49 
50 #ifdef sun4u
51 #include <cmd_opl.h>
52 #endif
53 
54 /* Must be in sync with cmd_ptrsubtype_t */
55 static cmd_case_closer_f *const cmd_case_closers[] = {
56 	NULL,
57 	cmd_cpuerr_close,	/* CMD_PTR_CPU_ICACHE */
58 	cmd_cpuerr_close,	/* CMD_PTR_CPU_DCACHE */
59 	cmd_cpuerr_close,	/* CMD_PTR_CPU_PCACHE */
60 	cmd_cpuerr_close,	/* CMD_PTR_CPU_ITLB */
61 	cmd_cpuerr_close,	/* CMD_PTR_CPU_DTLB */
62 	cmd_cpuerr_close,	/* CMD_PTR_CPU_L2DATA */
63 	cmd_cpuerr_close,	/* CMD_PTR_CPU_L2DATA_UERETRY */
64 	cmd_cpuerr_close,	/* CMD_PTR_CPU_L2TAG */
65 	cmd_cpuerr_close,	/* CMD_PTR_CPU_L3DATA */
66 	cmd_cpuerr_close,	/* CMD_PTR_CPU_L3DATA_UERETRY */
67 	cmd_cpuerr_close,	/* CMD_PTR_CPU_L3TAG */
68 	cmd_dimm_close,		/* CMD_PTR_DIMM_CASE */
69 	cmd_bank_close,		/* CMD_PTR_BANK_CASE */
70 	cmd_page_close,		/* CMD_PTR_PAGE_CASE */
71 	cmd_cpuerr_close,	/* CMD_PTR_CPU_FPU */
72 	NULL,			/* CMD_PTR_CPU_XR_RETRY */
73 	cmd_cpuerr_close,	/* CMD_PTR_CPU_IREG */
74 	cmd_cpuerr_close,	/* CMD_PTR_CPU_FREG */
75 	cmd_cpuerr_close,	/* CMD_PTR_CPU_MAU */
76 	cmd_cpuerr_close,	/* CMD_PTR_CPU_L2CTL */
77 #ifdef sun4u
78 	cmd_dp_close,		/* CMD_PTR_DP_CASE */
79 #else
80 	NULL,			/* CMD_PTR_DP_CASE */
81 #endif
82 	NULL,			/* CMD_PTR_DP_PAGE_DEFER */
83 	cmd_cpuerr_close,	/* CMD_PTR_CPU_INV_SFSR */
84 	cmd_cpuerr_close,	/* CMD_PTR_CPU_UE_DET_CPU */
85 	cmd_cpuerr_close,	/* CMD_PTR_CPU_UE_DET_IO */
86 	cmd_cpuerr_close,	/* CMD_PTR_CPU_MTLB */
87 	cmd_cpuerr_close,	/* CMD_PTR_CPU_TLBP */
88 	cmd_cpuerr_close,	/* CMD_PTR_CPU_UGESR_INV_URG */
89 	cmd_cpuerr_close,	/* CMD_PTR_CPU_UGESR_CRE */
90 	cmd_cpuerr_close,	/* CMD_PTR_CPU_UGESR_TSB_CTX */
91 	cmd_cpuerr_close,	/* CMD_PTR_CPU_UGESR_TSBP */
92 	cmd_cpuerr_close,	/* CMD_PTR_CPU_UGESR_PSTATE */
93 	cmd_cpuerr_close,	/* CMD_PTR_CPU_UGESR_TSTATE */
94 	cmd_cpuerr_close,	/* CMD_PTR_CPU_UGESR_IUG_F */
95 	cmd_cpuerr_close,	/* CMD_PTR_CPU_UGESR_IUG_R */
96 	cmd_cpuerr_close,	/* CMD_PTR_CPU_UGESR_SDC */
97 	cmd_cpuerr_close,	/* CMD_PTR_CPU_UGESR_WDT */
98 	cmd_cpuerr_close,	/* CMD_PTR_CPU_UGESR_DTLB */
99 	cmd_cpuerr_close,	/* CMD_PTR_CPU_UGESR_ITLB */
100 	cmd_cpuerr_close,	/* CMD_PTR_CPU_UGESR_CORE_ERR */
101 	cmd_cpuerr_close,	/* CMD_PTR_CPU_UGESR_DAE */
102 	cmd_cpuerr_close,	/* CMD_PTR_CPU_UGESR_IAE */
103 	cmd_cpuerr_close,	/* CMD_PTR_CPU_UGESR_UGE */
104 	cmd_cpuerr_close,	/* CMD_PTR_CPU_MISC_REGS */
105 	cmd_cpuerr_close,	/* CMD_PTR_CPU_LFU */
106 #ifdef sun4v
107 	cmd_branch_close	/* CMD_PTR_BRANCH_CASE */
108 #else
109 	NULL,
110 	cmd_Lxcache_close,	/* CMD_PTR_CACHE_CASE */
111 
112 #endif
113 };
114 
115 fmd_case_t *
cmd_case_create(fmd_hdl_t * hdl,cmd_header_t * hdr,cmd_ptrsubtype_t ptrsubtype,const char ** uuidp)116 cmd_case_create(fmd_hdl_t *hdl, cmd_header_t *hdr, cmd_ptrsubtype_t ptrsubtype,
117     const char **uuidp)
118 {
119 	cmd_case_ptr_t ptr;
120 	cmd_case_closer_t *cl;
121 	fmd_case_t *cp;
122 
123 	cl = fmd_hdl_alloc(hdl, sizeof (cmd_case_closer_t), FMD_SLEEP);
124 	cl->cl_func = cmd_case_closers[ptrsubtype];
125 	cl->cl_arg = hdr;
126 
127 	cp = fmd_case_open(hdl, cl);
128 
129 	ptr.ptr_type = hdr->hdr_nodetype;
130 	ptr.ptr_subtype = ptrsubtype;
131 	(void) strcpy(ptr.ptr_name, hdr->hdr_bufname);
132 
133 	*uuidp = fmd_case_uuid(hdl, cp);
134 	fmd_buf_write(hdl, cp, *uuidp, &ptr, sizeof (cmd_case_ptr_t));
135 
136 	return (cp);
137 }
138 
139 void
cmd_case_redirect(fmd_hdl_t * hdl,fmd_case_t * cp,cmd_ptrsubtype_t newsubtype)140 cmd_case_redirect(fmd_hdl_t *hdl, fmd_case_t *cp, cmd_ptrsubtype_t newsubtype)
141 {
142 	const char *uuid = fmd_case_uuid(hdl, cp);
143 	cmd_case_ptr_t ptr;
144 
145 	fmd_buf_read(hdl, cp, uuid, &ptr, sizeof (cmd_case_ptr_t));
146 	fmd_hdl_debug(hdl, "redirecting case %s from %d to %d\n", uuid,
147 	    ptr.ptr_subtype, newsubtype);
148 	ptr.ptr_subtype = newsubtype;
149 	fmd_buf_write(hdl, cp, uuid, &ptr, sizeof (cmd_case_ptr_t));
150 }
151 
152 void
cmd_case_fini(fmd_hdl_t * hdl,fmd_case_t * cp,int close)153 cmd_case_fini(fmd_hdl_t *hdl, fmd_case_t *cp, int close)
154 {
155 	const char *uuid = fmd_case_uuid(hdl, cp);
156 	cmd_case_closer_t *cl = fmd_case_getspecific(hdl, cp);
157 
158 	if (close) {
159 		fmd_hdl_debug(hdl, "closing case %s\n", uuid);
160 
161 		if (fmd_serd_exists(hdl, uuid))
162 			fmd_serd_destroy(hdl, uuid);
163 
164 		if (fmd_buf_size(hdl, cp, uuid) != 0)
165 			fmd_buf_destroy(hdl, cp, uuid);
166 
167 		fmd_case_setspecific(hdl, cp, NULL);
168 		fmd_case_close(hdl, cp);
169 	}
170 
171 	if (cl != NULL)
172 		fmd_hdl_free(hdl, cl, sizeof (cmd_case_closer_t));
173 }
174 
175 /* Must be in sync with cmd_nodetype_t */
176 static cmd_case_restorer_f *const cmd_case_restorers[] = {
177 	NULL,
178 	cmd_cpu_restore,	/* CMD_NT_CPU */
179 	cmd_dimm_restore,	/* CMD_NT_DIMM */
180 	cmd_bank_restore,	/* CMD_NT_BANK */
181 	cmd_page_restore,	/* CMD_NT_PAGE */
182 #ifdef sun4u
183 	cmd_dp_restore,		/* CMD_NT_DP */
184 	cmd_Lxcache_restore,	/* CMD_NT_CACHE */
185 #endif
186 #ifdef sun4v
187 	cmd_branch_restore	/* CMD_NT_BRANCH */
188 #endif
189 };
190 
191 int
cmd_state_restore(fmd_hdl_t * hdl)192 cmd_state_restore(fmd_hdl_t *hdl)
193 {
194 	fmd_case_t *cp = NULL;
195 
196 	while ((cp = fmd_case_next(hdl, cp)) != NULL) {
197 		const char *uuid = fmd_case_uuid(hdl, cp);
198 		cmd_case_closer_t *cl;
199 		cmd_case_ptr_t ptr;
200 		void *thing;
201 		size_t sz;
202 
203 		if ((sz = fmd_buf_size(hdl, cp, uuid)) == 0)
204 			continue;
205 		else if (sz != sizeof (cmd_case_ptr_t))
206 			return (cmd_set_errno(EINVAL));
207 
208 		fmd_buf_read(hdl, cp, fmd_case_uuid(hdl, cp), &ptr,
209 		    sizeof (cmd_case_ptr_t));
210 
211 		if (ptr.ptr_type == 0 || ptr.ptr_type >=
212 		    sizeof (cmd_case_restorers) /
213 		    sizeof (cmd_case_restorer_f *))
214 			return (cmd_set_errno(EINVAL));
215 
216 		if ((thing = cmd_case_restorers[ptr.ptr_type](hdl,
217 		    cp, &ptr)) == NULL) {
218 			fmd_hdl_debug(hdl, "Unable to restore case %s\n", uuid);
219 			continue;
220 		}
221 
222 		cl = fmd_hdl_alloc(hdl, sizeof (cmd_case_closer_t), FMD_SLEEP);
223 		cl->cl_func = cmd_case_closers[ptr.ptr_subtype];
224 		cl->cl_arg = thing;
225 		fmd_case_setspecific(hdl, cp, cl);
226 	}
227 
228 	cmd_trw_restore(hdl);
229 
230 	cmd_cpu_validate(hdl);
231 	cmd_bank_validate(hdl);
232 	cmd_dimm_validate(hdl);
233 #ifdef sun4u
234 	/*
235 	 * cmd_dp_page_validate() must be done before cmd_dp_validate()
236 	 * and cmd_page_validate()
237 	 */
238 	cmd_dp_page_validate(hdl);
239 	cmd_dp_validate(hdl);
240 #endif
241 	cmd_page_validate(hdl);
242 #ifdef sun4v
243 	cmd_branch_validate(hdl);
244 #endif
245 
246 	return (0);
247 }
248 
249 void
cmd_case_restore(fmd_hdl_t * hdl,cmd_case_t * cc,fmd_case_t * cp,char * serdnm)250 cmd_case_restore(fmd_hdl_t *hdl, cmd_case_t *cc, fmd_case_t *cp, char *serdnm)
251 {
252 	if (!fmd_serd_exists(hdl, serdnm)) {
253 		fmd_hdl_strfree(hdl, serdnm);
254 		serdnm = NULL;
255 	}
256 
257 	cc->cc_cp = cp;
258 	cc->cc_serdnm = serdnm;
259 }
260