1962Stsien /*
2962Stsien  * CDDL HEADER START
3962Stsien  *
4962Stsien  * The contents of this file are subject to the terms of the
52828Sjc25722  * Common Development and Distribution License (the "License").
62828Sjc25722  * You may not use this file except in compliance with the License.
7962Stsien  *
8962Stsien  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9962Stsien  * or http://www.opensolaris.org/os/licensing.
10962Stsien  * See the License for the specific language governing permissions
11962Stsien  * and limitations under the License.
12962Stsien  *
13962Stsien  * When distributing Covered Code, include this CDDL HEADER in each
14962Stsien  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15962Stsien  * If applicable, add the following below this CDDL HEADER, with the
16962Stsien  * fields enclosed by brackets "[]" replaced with your own identifying
17962Stsien  * information: Portions Copyright [yyyy] [name of copyright owner]
18962Stsien  *
19962Stsien  * CDDL HEADER END
20962Stsien  */
21962Stsien /*
226369Std122701  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23962Stsien  * Use is subject to license terms.
24962Stsien  */
25962Stsien 
26962Stsien 
27962Stsien /*
28962Stsien  * Support routines for managing per-CPU state.
29962Stsien  */
30962Stsien 
31962Stsien #include <cmd_cpu.h>
32962Stsien #include <cmd_ecache.h>
33962Stsien #include <cmd_mem.h>
34962Stsien #include <cmd.h>
35962Stsien 
36962Stsien #include <stdio.h>
37962Stsien #include <string.h>
38962Stsien #include <strings.h>
39962Stsien #include <errno.h>
40962Stsien #include <kstat.h>
41962Stsien #include <fm/fmd_api.h>
42962Stsien #include <sys/async.h>
43962Stsien #include <sys/fm/protocol.h>
44962Stsien #include <sys/fm/cpu/UltraSPARC-III.h>
45962Stsien #include <sys/cheetahregs.h>
46962Stsien 
47962Stsien /*
48962Stsien  * The unused argument 'clcode' is needed for our sun4v sibling.
49962Stsien  */
50962Stsien 
51962Stsien /*ARGSUSED*/
52962Stsien int
cmd_xr_fill(fmd_hdl_t * hdl,nvlist_t * nvl,cmd_xr_t * xr,cmd_errcl_t clcode)53962Stsien cmd_xr_fill(fmd_hdl_t *hdl, nvlist_t *nvl, cmd_xr_t *xr, cmd_errcl_t clcode)
54962Stsien {
55962Stsien 	if (nvlist_lookup_uint16(nvl, FM_EREPORT_PAYLOAD_NAME_SYND,
56962Stsien 	    &xr->xr_synd) != 0)
57962Stsien 		return (-1);
58962Stsien 	if (nvlist_lookup_uint8(nvl, FM_EREPORT_PAYLOAD_NAME_SYND_STATUS,
59962Stsien 	    &xr->xr_synd_status) != 0)
60962Stsien 		return (-1);
61962Stsien 	if (nvlist_lookup_uint64(nvl, FM_EREPORT_PAYLOAD_NAME_AFAR,
62962Stsien 	    &xr->xr_afar) != 0)
63962Stsien 		return (-1);
64962Stsien 	if (nvlist_lookup_uint8(nvl, FM_EREPORT_PAYLOAD_NAME_AFAR_STATUS,
65962Stsien 	    &xr->xr_afar_status) != 0)
66962Stsien 		return (-1);
67962Stsien 	return (0);
68962Stsien }
69962Stsien 
706369Std122701 /*
716369Std122701  * Search for the entry that matches the ena and the AFAR
726369Std122701  * if we have a valid AFAR, otherwise just match the ENA
736369Std122701  */
746369Std122701 cmd_xxcu_trw_t *
cmd_trw_lookup(uint64_t ena,uint8_t afar_status,uint64_t afar)756369Std122701 cmd_trw_lookup(uint64_t ena, uint8_t afar_status, uint64_t afar)
766369Std122701 {
776369Std122701 	int i;
786369Std122701 
796369Std122701 	if (afar_status == AFLT_STAT_VALID) {
806369Std122701 		for (i = 0; i < cmd.cmd_xxcu_ntrw; i++) {
816369Std122701 			if (cmd.cmd_xxcu_trw[i].trw_ena == ena &&
826369Std122701 			    cmd.cmd_xxcu_trw[i].trw_afar == afar)
836369Std122701 				return (&cmd.cmd_xxcu_trw[i]);
846369Std122701 		}
856369Std122701 	} else  {
866369Std122701 		for (i = 0; i < cmd.cmd_xxcu_ntrw; i++) {
876369Std122701 		if (cmd.cmd_xxcu_trw[i].trw_ena == ena)
886369Std122701 			return (&cmd.cmd_xxcu_trw[i]);
896369Std122701 		}
906369Std122701 	}
916369Std122701 	return (NULL);
926369Std122701 }
936369Std122701 
946369Std122701 /*ARGSUSED*/
956369Std122701 cmd_errcl_t
cmd_train_match(cmd_errcl_t trw_mask,cmd_errcl_t resolved_err)966369Std122701 cmd_train_match(cmd_errcl_t trw_mask, cmd_errcl_t resolved_err)
976369Std122701 {
986369Std122701 	return (cmd_xxcu_train_match(trw_mask));
996369Std122701 }
1006369Std122701 
1016369Std122701 /*ARGSUSED*/
102962Stsien int
cmd_afar_status_check(uint8_t afar_status,cmd_errcl_t clcode)1036369Std122701 cmd_afar_status_check(uint8_t afar_status, cmd_errcl_t clcode)
1046369Std122701 {
1056369Std122701 	if (afar_status == AFLT_STAT_VALID)
1066369Std122701 		return (0);
1076369Std122701 	return (-1);
1086369Std122701 }
1096369Std122701 
1106369Std122701 const errdata_t l3errdata =
1116369Std122701 	{ &cmd.cmd_l3data_serd, "l3cachedata", CMD_PTR_CPU_L3DATA  };
1126369Std122701 const errdata_t l2errdata =
1136369Std122701 	{ &cmd.cmd_l2data_serd, "l2cachedata", CMD_PTR_CPU_L2DATA };
1146369Std122701 
1156369Std122701 void
cmd_fill_errdata(cmd_errcl_t clcode,cmd_cpu_t * cpu,cmd_case_t ** cc,const errdata_t ** ed)1166369Std122701 cmd_fill_errdata(cmd_errcl_t clcode, cmd_cpu_t *cpu, cmd_case_t **cc,
1176369Std122701     const errdata_t **ed)
1186369Std122701 {
1196369Std122701 	if (CMD_ERRCL_ISL2XXCU(clcode)) {
1206369Std122701 		*ed = &l2errdata;
1216369Std122701 		*cc = &cpu->cpu_l2data;
1226369Std122701 	} else {
1236369Std122701 		*ed = &l3errdata;
1246369Std122701 		*cc = &cpu->cpu_l3data;
1256369Std122701 	}
1266369Std122701 }
1276369Std122701 
1286369Std122701 /*ARGSUSED*/
1296369Std122701 int
cmd_cpu_synd_check(uint16_t synd,cmd_errcl_t clcode)1306369Std122701 cmd_cpu_synd_check(uint16_t synd, cmd_errcl_t clcode)
131962Stsien {
132962Stsien 	if (synd == CH_POISON_SYND_FROM_XXU_WRITE ||
133962Stsien 	    synd == CH_POISON_SYND_FROM_XXU_WRMERGE ||
134962Stsien 	    synd == CH_POISON_SYND_FROM_DSTAT23)
135962Stsien 		return (-1);
136962Stsien 	else
137962Stsien 		return (0);
138962Stsien }
1392833Sjc25722 /*ARGSUSED*/
1402828Sjc25722 int
cmd_afar_valid(fmd_hdl_t * hdl,nvlist_t * nvl,cmd_errcl_t clcode,uint64_t * afar)1412828Sjc25722 cmd_afar_valid(fmd_hdl_t *hdl, nvlist_t *nvl, cmd_errcl_t clcode,
1422828Sjc25722     uint64_t *afar)
1432828Sjc25722 {
1442828Sjc25722 	uint8_t afar_status;
1452828Sjc25722 
1462828Sjc25722 	if (nvlist_lookup_uint8(nvl,
1472828Sjc25722 	    FM_EREPORT_PAYLOAD_NAME_AFAR_STATUS, &afar_status) == 0) {
1482828Sjc25722 		if (afar_status == AFLT_STAT_VALID) {
1492828Sjc25722 			(void) nvlist_lookup_uint64(nvl,
1502828Sjc25722 			    FM_EREPORT_PAYLOAD_NAME_AFAR, afar);
1512828Sjc25722 			return (0);
1522828Sjc25722 		} else
1532828Sjc25722 			return (-1);
1543325Ssd77468 	} else
1553325Ssd77468 		return (-1);
1563325Ssd77468 }
1573325Ssd77468 
1583325Ssd77468 char *
cmd_cpu_getfrustr_by_id(fmd_hdl_t * hdl,uint32_t cpuid)1593325Ssd77468 cmd_cpu_getfrustr_by_id(fmd_hdl_t *hdl, uint32_t cpuid)
1603325Ssd77468 {
1613325Ssd77468 	kstat_named_t *kn;
1623325Ssd77468 	kstat_ctl_t *kc;
1633325Ssd77468 	kstat_t *ksp;
1643325Ssd77468 	int i;
1653325Ssd77468 
1663325Ssd77468 	if ((kc = kstat_open()) == NULL)
1673325Ssd77468 		return (NULL); /* errno is set for us */
1683325Ssd77468 
1693325Ssd77468 	if ((ksp = kstat_lookup(kc, "cpu_info", cpuid, NULL)) == NULL ||
1703325Ssd77468 	    kstat_read(kc, ksp, NULL) == -1) {
1713325Ssd77468 		int oserr = errno;
1723325Ssd77468 		(void) kstat_close(kc);
1733325Ssd77468 		(void) cmd_set_errno(oserr);
1743325Ssd77468 		return (NULL);
1752828Sjc25722 	}
1763325Ssd77468 
1773325Ssd77468 	for (kn = ksp->ks_data, i = 0; i < ksp->ks_ndata; i++, kn++) {
1783325Ssd77468 		if (strcmp(kn->name, "cpu_fru") == 0) {
1793325Ssd77468 			char *str = fmd_hdl_strdup(hdl,
1803325Ssd77468 			    KSTAT_NAMED_STR_PTR(kn), FMD_SLEEP);
1813325Ssd77468 			(void) kstat_close(kc);
1823325Ssd77468 			return (str);
1833325Ssd77468 		}
1843325Ssd77468 	}
1853325Ssd77468 
1863325Ssd77468 	(void) kstat_close(kc);
1873325Ssd77468 	(void) cmd_set_errno(ENOENT);
1883325Ssd77468 	return (NULL);
1892828Sjc25722 }
1903325Ssd77468 
1913325Ssd77468 char *
cmd_cpu_getfrustr(fmd_hdl_t * hdl,cmd_cpu_t * cp)1923325Ssd77468 cmd_cpu_getfrustr(fmd_hdl_t *hdl, cmd_cpu_t *cp)
1933325Ssd77468 {
1943325Ssd77468 	return (cmd_cpu_getfrustr_by_id(hdl, cp->cpu_cpuid));
1953325Ssd77468 }
1963325Ssd77468 
1973325Ssd77468 /*ARGSUSED*/
1983325Ssd77468 char *
cmd_cpu_getpartstr(fmd_hdl_t * hdl,cmd_cpu_t * cp)1993325Ssd77468 cmd_cpu_getpartstr(fmd_hdl_t *hdl, cmd_cpu_t *cp) {
2003325Ssd77468 	return (NULL);
2013325Ssd77468 }
2023325Ssd77468 
2033325Ssd77468 /*ARGSUSED*/
2043325Ssd77468 char *
cmd_cpu_getserialstr(fmd_hdl_t * hdl,cmd_cpu_t * cp)2053325Ssd77468 cmd_cpu_getserialstr(fmd_hdl_t *hdl, cmd_cpu_t *cp) {
2063325Ssd77468 	return (NULL);
2073325Ssd77468 }
2083657Stsien 
2095430Ssd77468 /*ARGSUSED*/
2103657Stsien nvlist_t *
cmd_cpu_mkfru(fmd_hdl_t * hdl,char * frustr,char * serialstr,char * partstr)2115430Ssd77468 cmd_cpu_mkfru(fmd_hdl_t *hdl, char *frustr, char *serialstr, char *partstr)
2123657Stsien {
2133657Stsien 	char *comp;
2143657Stsien 	nvlist_t *fru, *hcelem;
2153657Stsien 
2163657Stsien 	if (strncmp(frustr, CPU_FRU_FMRI, sizeof (CPU_FRU_FMRI) - 1) != 0)
2173657Stsien 		return (NULL);
2183657Stsien 
2193657Stsien 	comp = frustr + sizeof (CPU_FRU_FMRI) - 1;
2203657Stsien 
2213657Stsien 	if (nvlist_alloc(&hcelem, NV_UNIQUE_NAME, 0) != 0)
2223657Stsien 		return (NULL);
2233657Stsien 
2243657Stsien 	if (nvlist_add_string(hcelem, FM_FMRI_HC_NAME,
2253657Stsien 	    FM_FMRI_LEGACY_HC) != 0 ||
2263657Stsien 	    nvlist_add_string(hcelem, FM_FMRI_HC_ID, comp) != 0) {
2273657Stsien 		nvlist_free(hcelem);
2283657Stsien 		return (NULL);
2293657Stsien 	}
2303657Stsien 
2313657Stsien 	if (nvlist_alloc(&fru, NV_UNIQUE_NAME, 0) != 0) {
2323657Stsien 		nvlist_free(hcelem);
2333657Stsien 		return (NULL);
2343657Stsien 	}
2353657Stsien 
2363657Stsien 	if (nvlist_add_uint8(fru, FM_VERSION, FM_HC_SCHEME_VERSION) != 0 ||
2373657Stsien 	    nvlist_add_string(fru, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC) != 0 ||
2383657Stsien 	    (partstr != NULL &&
2395430Ssd77468 	    nvlist_add_string(fru, FM_FMRI_HC_PART, partstr) != 0) ||
2403657Stsien 	    (serialstr != NULL &&
2415430Ssd77468 	    nvlist_add_string(fru, FM_FMRI_HC_SERIAL_ID,
2425430Ssd77468 	    serialstr) != 0) ||
2433657Stsien 	    nvlist_add_string(fru, FM_FMRI_HC_ROOT, "") != 0 ||
2443657Stsien 	    nvlist_add_uint32(fru, FM_FMRI_HC_LIST_SZ, 1) != 0 ||
2453657Stsien 	    nvlist_add_nvlist_array(fru, FM_FMRI_HC_LIST, &hcelem, 1) != 0) {
2463657Stsien 		nvlist_free(hcelem);
2473657Stsien 		nvlist_free(fru);
2483657Stsien 		return (NULL);
2493657Stsien 	}
2503657Stsien 
2513657Stsien 	nvlist_free(hcelem);
2523657Stsien 	return (fru);
2533657Stsien }
254*8221SSean.Ye@Sun.COM 
255*8221SSean.Ye@Sun.COM 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*8221SSean.Ye@Sun.COM cmd_nvl_create_fault(fmd_hdl_t *hdl, const char *class, uint8_t cert,
257*8221SSean.Ye@Sun.COM     nvlist_t *asru, nvlist_t *fru, nvlist_t *rsrc)
258*8221SSean.Ye@Sun.COM {
259*8221SSean.Ye@Sun.COM 	(void) nvlist_add_nvlist(fru, FM_FMRI_AUTHORITY,
260*8221SSean.Ye@Sun.COM 	    cmd.cmd_auth);
261*8221SSean.Ye@Sun.COM 	return (fmd_nvl_create_fault(hdl, class, cert, asru, fru, rsrc));
262*8221SSean.Ye@Sun.COM }
263