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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 
27 /*
28  * Support routines for managing per-CPU state.
29  */
30 
31 #include <cmd_cpu.h>
32 #include <cmd_ecache.h>
33 #include <cmd_mem.h>
34 #include <cmd.h>
35 
36 #include <stdio.h>
37 #include <string.h>
38 #include <strings.h>
39 #include <errno.h>
40 #include <kstat.h>
41 #include <fm/fmd_api.h>
42 #include <sys/async.h>
43 #include <sys/fm/protocol.h>
44 #include <sys/fm/cpu/UltraSPARC-III.h>
45 #include <sys/cheetahregs.h>
46 
47 /*
48  * The unused argument 'clcode' is needed for our sun4v sibling.
49  */
50 
51 /*ARGSUSED*/
52 int
cmd_xr_fill(fmd_hdl_t * hdl,nvlist_t * nvl,cmd_xr_t * xr,cmd_errcl_t clcode)53 cmd_xr_fill(fmd_hdl_t *hdl, nvlist_t *nvl, cmd_xr_t *xr, cmd_errcl_t clcode)
54 {
55 	if (nvlist_lookup_uint16(nvl, FM_EREPORT_PAYLOAD_NAME_SYND,
56 	    &xr->xr_synd) != 0)
57 		return (-1);
58 	if (nvlist_lookup_uint8(nvl, FM_EREPORT_PAYLOAD_NAME_SYND_STATUS,
59 	    &xr->xr_synd_status) != 0)
60 		return (-1);
61 	if (nvlist_lookup_uint64(nvl, FM_EREPORT_PAYLOAD_NAME_AFAR,
62 	    &xr->xr_afar) != 0)
63 		return (-1);
64 	if (nvlist_lookup_uint8(nvl, FM_EREPORT_PAYLOAD_NAME_AFAR_STATUS,
65 	    &xr->xr_afar_status) != 0)
66 		return (-1);
67 	return (0);
68 }
69 
70 /*
71  * Search for the entry that matches the ena and the AFAR
72  * if we have a valid AFAR, otherwise just match the ENA
73  */
74 cmd_xxcu_trw_t *
cmd_trw_lookup(uint64_t ena,uint8_t afar_status,uint64_t afar)75 cmd_trw_lookup(uint64_t ena, uint8_t afar_status, uint64_t afar)
76 {
77 	int i;
78 
79 	if (afar_status == AFLT_STAT_VALID) {
80 		for (i = 0; i < cmd.cmd_xxcu_ntrw; i++) {
81 			if (cmd.cmd_xxcu_trw[i].trw_ena == ena &&
82 			    cmd.cmd_xxcu_trw[i].trw_afar == afar)
83 				return (&cmd.cmd_xxcu_trw[i]);
84 		}
85 	} else  {
86 		for (i = 0; i < cmd.cmd_xxcu_ntrw; i++) {
87 		if (cmd.cmd_xxcu_trw[i].trw_ena == ena)
88 			return (&cmd.cmd_xxcu_trw[i]);
89 		}
90 	}
91 	return (NULL);
92 }
93 
94 /*ARGSUSED*/
95 cmd_errcl_t
cmd_train_match(cmd_errcl_t trw_mask,cmd_errcl_t resolved_err)96 cmd_train_match(cmd_errcl_t trw_mask, cmd_errcl_t resolved_err)
97 {
98 	return (cmd_xxcu_train_match(trw_mask));
99 }
100 
101 /*ARGSUSED*/
102 int
cmd_afar_status_check(uint8_t afar_status,cmd_errcl_t clcode)103 cmd_afar_status_check(uint8_t afar_status, cmd_errcl_t clcode)
104 {
105 	if (afar_status == AFLT_STAT_VALID)
106 		return (0);
107 	return (-1);
108 }
109 
110 const errdata_t l3errdata =
111 	{ &cmd.cmd_l3data_serd, "l3cachedata", CMD_PTR_CPU_L3DATA  };
112 const errdata_t l2errdata =
113 	{ &cmd.cmd_l2data_serd, "l2cachedata", CMD_PTR_CPU_L2DATA };
114 
115 void
cmd_fill_errdata(cmd_errcl_t clcode,cmd_cpu_t * cpu,cmd_case_t ** cc,const errdata_t ** ed)116 cmd_fill_errdata(cmd_errcl_t clcode, cmd_cpu_t *cpu, cmd_case_t **cc,
117     const errdata_t **ed)
118 {
119 	if (CMD_ERRCL_ISL2XXCU(clcode)) {
120 		*ed = &l2errdata;
121 		*cc = &cpu->cpu_l2data;
122 	} else {
123 		*ed = &l3errdata;
124 		*cc = &cpu->cpu_l3data;
125 	}
126 }
127 
128 /*ARGSUSED*/
129 int
cmd_cpu_synd_check(uint16_t synd,cmd_errcl_t clcode)130 cmd_cpu_synd_check(uint16_t synd, cmd_errcl_t clcode)
131 {
132 	if (synd == CH_POISON_SYND_FROM_XXU_WRITE ||
133 	    synd == CH_POISON_SYND_FROM_XXU_WRMERGE ||
134 	    synd == CH_POISON_SYND_FROM_DSTAT23)
135 		return (-1);
136 	else
137 		return (0);
138 }
139 /*ARGSUSED*/
140 int
cmd_afar_valid(fmd_hdl_t * hdl,nvlist_t * nvl,cmd_errcl_t clcode,uint64_t * afar)141 cmd_afar_valid(fmd_hdl_t *hdl, nvlist_t *nvl, cmd_errcl_t clcode,
142     uint64_t *afar)
143 {
144 	uint8_t afar_status;
145 
146 	if (nvlist_lookup_uint8(nvl,
147 	    FM_EREPORT_PAYLOAD_NAME_AFAR_STATUS, &afar_status) == 0) {
148 		if (afar_status == AFLT_STAT_VALID) {
149 			(void) nvlist_lookup_uint64(nvl,
150 			    FM_EREPORT_PAYLOAD_NAME_AFAR, afar);
151 			return (0);
152 		} else
153 			return (-1);
154 	} else
155 		return (-1);
156 }
157 
158 char *
cmd_cpu_getfrustr_by_id(fmd_hdl_t * hdl,uint32_t cpuid)159 cmd_cpu_getfrustr_by_id(fmd_hdl_t *hdl, uint32_t cpuid)
160 {
161 	kstat_named_t *kn;
162 	kstat_ctl_t *kc;
163 	kstat_t *ksp;
164 	int i;
165 
166 	if ((kc = kstat_open()) == NULL)
167 		return (NULL); /* errno is set for us */
168 
169 	if ((ksp = kstat_lookup(kc, "cpu_info", cpuid, NULL)) == NULL ||
170 	    kstat_read(kc, ksp, NULL) == -1) {
171 		int oserr = errno;
172 		(void) kstat_close(kc);
173 		(void) cmd_set_errno(oserr);
174 		return (NULL);
175 	}
176 
177 	for (kn = ksp->ks_data, i = 0; i < ksp->ks_ndata; i++, kn++) {
178 		if (strcmp(kn->name, "cpu_fru") == 0) {
179 			char *str = fmd_hdl_strdup(hdl,
180 			    KSTAT_NAMED_STR_PTR(kn), FMD_SLEEP);
181 			(void) kstat_close(kc);
182 			return (str);
183 		}
184 	}
185 
186 	(void) kstat_close(kc);
187 	(void) cmd_set_errno(ENOENT);
188 	return (NULL);
189 }
190 
191 char *
cmd_cpu_getfrustr(fmd_hdl_t * hdl,cmd_cpu_t * cp)192 cmd_cpu_getfrustr(fmd_hdl_t *hdl, cmd_cpu_t *cp)
193 {
194 	return (cmd_cpu_getfrustr_by_id(hdl, cp->cpu_cpuid));
195 }
196 
197 /*ARGSUSED*/
198 char *
cmd_cpu_getpartstr(fmd_hdl_t * hdl,cmd_cpu_t * cp)199 cmd_cpu_getpartstr(fmd_hdl_t *hdl, cmd_cpu_t *cp) {
200 	return (NULL);
201 }
202 
203 /*ARGSUSED*/
204 char *
cmd_cpu_getserialstr(fmd_hdl_t * hdl,cmd_cpu_t * cp)205 cmd_cpu_getserialstr(fmd_hdl_t *hdl, cmd_cpu_t *cp) {
206 	return (NULL);
207 }
208 
209 /*ARGSUSED*/
210 nvlist_t *
cmd_cpu_mkfru(fmd_hdl_t * hdl,char * frustr,char * serialstr,char * partstr)211 cmd_cpu_mkfru(fmd_hdl_t *hdl, char *frustr, char *serialstr, char *partstr)
212 {
213 	char *comp;
214 	nvlist_t *fru, *hcelem;
215 
216 	if (strncmp(frustr, CPU_FRU_FMRI, sizeof (CPU_FRU_FMRI) - 1) != 0)
217 		return (NULL);
218 
219 	comp = frustr + sizeof (CPU_FRU_FMRI) - 1;
220 
221 	if (nvlist_alloc(&hcelem, NV_UNIQUE_NAME, 0) != 0)
222 		return (NULL);
223 
224 	if (nvlist_add_string(hcelem, FM_FMRI_HC_NAME,
225 	    FM_FMRI_LEGACY_HC) != 0 ||
226 	    nvlist_add_string(hcelem, FM_FMRI_HC_ID, comp) != 0) {
227 		nvlist_free(hcelem);
228 		return (NULL);
229 	}
230 
231 	if (nvlist_alloc(&fru, NV_UNIQUE_NAME, 0) != 0) {
232 		nvlist_free(hcelem);
233 		return (NULL);
234 	}
235 
236 	if (nvlist_add_uint8(fru, FM_VERSION, FM_HC_SCHEME_VERSION) != 0 ||
237 	    nvlist_add_string(fru, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC) != 0 ||
238 	    (partstr != NULL &&
239 	    nvlist_add_string(fru, FM_FMRI_HC_PART, partstr) != 0) ||
240 	    (serialstr != NULL &&
241 	    nvlist_add_string(fru, FM_FMRI_HC_SERIAL_ID,
242 	    serialstr) != 0) ||
243 	    nvlist_add_string(fru, FM_FMRI_HC_ROOT, "") != 0 ||
244 	    nvlist_add_uint32(fru, FM_FMRI_HC_LIST_SZ, 1) != 0 ||
245 	    nvlist_add_nvlist_array(fru, FM_FMRI_HC_LIST, &hcelem, 1) != 0) {
246 		nvlist_free(hcelem);
247 		nvlist_free(fru);
248 		return (NULL);
249 	}
250 
251 	nvlist_free(hcelem);
252 	return (fru);
253 }
254 
255 nvlist_t *
cmd_nvl_create_fault(fmd_hdl_t * hdl,const char * class,uint8_t cert,nvlist_t * asru,nvlist_t * fru,nvlist_t * rsrc)256 cmd_nvl_create_fault(fmd_hdl_t *hdl, const char *class, uint8_t cert,
257     nvlist_t *asru, nvlist_t *fru, nvlist_t *rsrc)
258 {
259 	(void) nvlist_add_nvlist(fru, FM_FMRI_AUTHORITY,
260 	    cmd.cmd_auth);
261 	return (fmd_nvl_create_fault(hdl, class, cert, asru, fru, rsrc));
262 }
263