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