16330Sjc25722 /*
26330Sjc25722  * CDDL HEADER START
36330Sjc25722  *
46330Sjc25722  * The contents of this file are subject to the terms of the
56330Sjc25722  * Common Development and Distribution License (the "License").
66330Sjc25722  * You may not use this file except in compliance with the License.
76330Sjc25722  *
86330Sjc25722  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96330Sjc25722  * or http://www.opensolaris.org/os/licensing.
106330Sjc25722  * See the License for the specific language governing permissions
116330Sjc25722  * and limitations under the License.
126330Sjc25722  *
136330Sjc25722  * When distributing Covered Code, include this CDDL HEADER in each
146330Sjc25722  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156330Sjc25722  * If applicable, add the following below this CDDL HEADER, with the
166330Sjc25722  * fields enclosed by brackets "[]" replaced with your own identifying
176330Sjc25722  * information: Portions Copyright [yyyy] [name of copyright owner]
186330Sjc25722  *
196330Sjc25722  * CDDL HEADER END
206330Sjc25722  */
216330Sjc25722 /*
22*10784Ssinanallur.balasubramanian@sun.com  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
236330Sjc25722  * Use is subject to license terms.
246330Sjc25722  */
256330Sjc25722 
266330Sjc25722 
276330Sjc25722 /*
286330Sjc25722  * Support routines for managing per-Lxcache state.
296330Sjc25722  */
306330Sjc25722 
316330Sjc25722 #include <sys/types.h>
326330Sjc25722 #include <errno.h>
336330Sjc25722 #include <strings.h>
346330Sjc25722 #include <sys/stat.h>
356330Sjc25722 #include <fcntl.h>
366330Sjc25722 #include <unistd.h>
376330Sjc25722 #include <stropts.h>
386330Sjc25722 #include <fm/fmd_api.h>
396330Sjc25722 #include <sys/fm/protocol.h>
406330Sjc25722 #include <sys/fm/cpu/UltraSPARC-III.h>
416330Sjc25722 #include <sys/cpuvar.h>
426330Sjc25722 #include <cmd_Lxcache.h>
436330Sjc25722 #include <cmd_mem.h>
446330Sjc25722 #include <cmd_cpu.h>
456330Sjc25722 #include <cmd_state.h>
466330Sjc25722 #include <cmd.h>
476330Sjc25722 #define	_KERNEL
486330Sjc25722 #include <sys/cheetahregs.h>
496330Sjc25722 #include <sys/mem_cache.h>
506330Sjc25722 #undef _KERNEL
516330Sjc25722 #include <sys/errclassify.h>
526330Sjc25722 #include <sys/fm/io/sun4upci.h>
536330Sjc25722 
546330Sjc25722 #include <fmd_adm.h>
556330Sjc25722 #include <fmd_adm_impl.h>
566330Sjc25722 #include <fmd_rpc_adm.h>
576330Sjc25722 
586330Sjc25722 #define	PN_CACHE_ERRORS (CMD_ERRCL_UCC | CMD_ERRCL_WDC | \
596330Sjc25722 			    CMD_ERRCL_CPC | CMD_ERRCL_EDC | \
606330Sjc25722 			    CMD_ERRCL_L3_UCC | CMD_ERRCL_L3_CPC |\
616330Sjc25722 			    CMD_ERRCL_L3_WDC | CMD_ERRCL_L3_EDC)
626330Sjc25722 
636330Sjc25722 /* Note that these are the same for panther L2 and L3 (see prm) */
646330Sjc25722 
656330Sjc25722 #define	LX_INDEX_MASK		PN_L2_INDEX_MASK
666330Sjc25722 #define	LX_INDEX_SHIFT		6
676330Sjc25722 #define	PN_ECSTATE_NA	5
68*10784Ssinanallur.balasubramanian@sun.com #define	PN_ECSTATE_INV	0
696330Sjc25722 
70*10784Ssinanallur.balasubramanian@sun.com #define	PN_L3_INDEX_MASK	PN_L3_TAG_RD_MASK
716330Sjc25722 
72*10784Ssinanallur.balasubramanian@sun.com static const errdata_t l3errdata =
736330Sjc25722 	{ &cmd.cmd_l3data_serd, "l3cachedata", CMD_PTR_LxCACHE_CASE };
74*10784Ssinanallur.balasubramanian@sun.com static const errdata_t l2errdata =
756330Sjc25722 	{ &cmd.cmd_l2data_serd, "l2cachedata", CMD_PTR_LxCACHE_CASE };
766330Sjc25722 
77*10784Ssinanallur.balasubramanian@sun.com /* Macro for putting 64-bit onto stack as two 32-bit ints */
78*10784Ssinanallur.balasubramanian@sun.com #define	PRTF_64_TO_32(x)	(uint32_t)((x)>>32), (uint32_t)(x)
796330Sjc25722 
806330Sjc25722 #define	LX_PA_MASK2_32BIT_CORRECT	16
816330Sjc25722 #define	LX_PA_MASK3_32BIT_CORRECT	24
826330Sjc25722 #define	LX_PA_MASK2 0x7fffff8
836330Sjc25722 #define	LX_PA_MASK3 0x7ffff8
846330Sjc25722 
856330Sjc25722 
866330Sjc25722 #define	MAX_RETRIES_FOR_ECC_MATCH	3
876330Sjc25722 #define	PN_TAG_ECC_MASK 0x7fc0
886330Sjc25722 #define	PN_L2_PTAG_SHIFT	19
896330Sjc25722 #define	PN_L3_PTAG_SHIFT	24
906330Sjc25722 #define	L2_PTAG_MASK		0xffffff
916330Sjc25722 #define	L3_PTAG_MASK		0xfffff
926330Sjc25722 #define	BIT_MASK		0x7f
936330Sjc25722 #define	MSB_BIT			0x8000
94*10784Ssinanallur.balasubramanian@sun.com #define	SET_MSB_BIT		0x8000
95*10784Ssinanallur.balasubramanian@sun.com #define	CLEAR_MSB_BIT		0x7fff
96*10784Ssinanallur.balasubramanian@sun.com #define	PN_LX_TAG_ECC_START_BIT	6
97*10784Ssinanallur.balasubramanian@sun.com #define	PN_LX_TAG_ECC_END_BIT	14
98*10784Ssinanallur.balasubramanian@sun.com #define	PN_LX_STATE_END_BIT	2
99*10784Ssinanallur.balasubramanian@sun.com #define	PN_LX_NUM_OF_BITS_IN_ECC	9
1006330Sjc25722 
1016330Sjc25722 #define	LX_NWAYS		4
1026330Sjc25722 
1036330Sjc25722 int test_mode = 0;	/* should be 0 in production version. */
104*10784Ssinanallur.balasubramanian@sun.com #define	FM_EREPORT_RECHECK_OF_TAGS "recheck_tags"
105*10784Ssinanallur.balasubramanian@sun.com #define	RETRIES_TO_BE_DONE_WHEN_SYND_IS_ZERO	3
106*10784Ssinanallur.balasubramanian@sun.com uint32_t cmd_Lxcache_recheck_tags_delay
107*10784Ssinanallur.balasubramanian@sun.com 	[RETRIES_TO_BE_DONE_WHEN_SYND_IS_ZERO + 1] = {0, 1, 2, 4};
1086330Sjc25722 
1096330Sjc25722 /*
1106330Sjc25722  * e (for ecctable) maps single bit positions (0-127, or 0-0x7F) to the
1116330Sjc25722  * corresponding ECC syndromes for an error in that position.
1126330Sjc25722  */
1136330Sjc25722 int e[] = {
1146330Sjc25722 	/* From Table P-4, JPS1 US-III Supplement */
1156330Sjc25722 		/* 0	1	2	3	4	5	6	7 */
1166330Sjc25722 /* 00 */	0x03B,	0x127,	0x067,	0x097,	0x10F,	0x08F,	0x04F,	0x02C,
1176330Sjc25722 /* 08 */	0x147,	0x0C7,	0x02F,	0x01C,	0x117,	0x032,	0x08A,	0x04A,
1186330Sjc25722 /* 10 */	0x01F,	0x086,	0x046,	0x026,	0x09B,	0x08C,	0x0C1,	0x0A1,
1196330Sjc25722 /* 18 */	0x01A,	0x016,	0x061,	0x091,	0x052,	0x00E,	0x109,	0x029,
1206330Sjc25722 /* 20 */	0x02A,	0x019,	0x105,	0x085,	0x045,	0x025,	0x015,	0x103,
1216330Sjc25722 /* 28 */	0x031,	0x00D,	0x083,	0x043,	0x051,	0x089,	0x023,	0x007,
1226330Sjc25722 /* 30 */	0x0B9,	0x049,	0x013,	0x0A7,	0x057,	0x00B,	0x07A,	0x187,
1236330Sjc25722 /* 38 */	0x0F8,	0x11B,	0x079,	0x034,	0x178,	0x1D8,	0x05B,	0x04C,
1246330Sjc25722 /* 40 */	0x064,	0x1B4,	0x037,	0x03D,	0x058,	0x13C,	0x1B1,	0x03E,
1256330Sjc25722 /* 48 */	0x1C3,	0x0BC,	0x1A0,	0x1D4,	0x1CA,	0x190,	0x124,	0x13A,
1266330Sjc25722 /* 50 */	0x1C0,	0x188,	0x122,	0x114,	0x184,	0x182,	0x160,	0x118,
1276330Sjc25722 /* 58 */	0x181,	0x150,	0x148,	0x144,	0x142,	0x141,	0x130,	0x0A8,
1286330Sjc25722 /* 60 */	0x128,	0x121,	0x0E0,	0x094,	0x112,	0x10C,	0x0D0,	0x0B0,
1296330Sjc25722 /* 68 */	0x10A,	0x106,	0x062,	0x1B2,	0x0C8,	0x0C4,	0x0C2,	0x1F0,
1306330Sjc25722 /* 70 */	0x0A4,	0x0A2,	0x098,	0x1D1,	0x070,	0x1E8,	0x1C6,	0x1C5,
1316330Sjc25722 /* 78 */	0x068,	0x1E4,	0x1E2,	0x1E1,	0x1D2,	0x1CC,	0x1C9,	0x1B8,
1326330Sjc25722 	/* Now we have the check bits */
1336330Sjc25722 	/* C0	C1	C2	C3	C4	C5	C6	C7	C8 */
1346330Sjc25722 	0x001,	0x002,	0x004,	0x008,	0x010,	0x020,	0x040,	0x080,	0x100,
1356330Sjc25722 };
1366330Sjc25722 
1376330Sjc25722 #define	NBITS (sizeof (e)/sizeof (e[0]))
1386330Sjc25722 #define	NDATABITS (128)
1396330Sjc25722 /*
1406330Sjc25722  * This table is used to determine which bit(s) is(are) bad when an ECC
1416330Sjc25722  * error occurs.  The array is indexed by an 9-bit syndrome.  The entries
1426330Sjc25722  * of this array have the following semantics:
1436330Sjc25722  *
1446330Sjc25722  *      00-127  The number of the bad bit, when only one bit is bad.
1456330Sjc25722  *      128     ECC bit C0 is bad.
1466330Sjc25722  *      129     ECC bit C1 is bad.
1476330Sjc25722  *      130     ECC bit C2 is bad.
1486330Sjc25722  *      131     ECC bit C3 is bad.
1496330Sjc25722  *      132     ECC bit C4 is bad.
1506330Sjc25722  *      133     ECC bit C5 is bad.
1516330Sjc25722  *      134     ECC bit C6 is bad.
1526330Sjc25722  *      135     ECC bit C7 is bad.
1536330Sjc25722  *      136     ECC bit C8 is bad.
1546330Sjc25722  *	137-143 reserved for Mtag Data and ECC.
1556330Sjc25722  *      144(M2) Two bits are bad within a nibble.
1566330Sjc25722  *      145(M3) Three bits are bad within a nibble.
1576330Sjc25722  *      146(M3) Four bits are bad within a nibble.
1586330Sjc25722  *      147(M)  Multiple bits (5 or more) are bad.
1596330Sjc25722  *      148     NO bits are bad.
1606330Sjc25722  * Based on "Cheetah Programmer's Reference Manual" rev 1.1, Tables 11-4,11-5.
1616330Sjc25722  */
1626330Sjc25722 
1636330Sjc25722 #define	C0	128
1646330Sjc25722 #define	C1	129
1656330Sjc25722 #define	C2	130
1666330Sjc25722 #define	C3	131
1676330Sjc25722 #define	C4	132
1686330Sjc25722 #define	C5	133
1696330Sjc25722 #define	C6	134
1706330Sjc25722 #define	C7	135
1716330Sjc25722 #define	C8	136
1726330Sjc25722 #define	MT0	137	/* Mtag Data bit 0 */
1736330Sjc25722 #define	MT1	138
1746330Sjc25722 #define	MT2	139
1756330Sjc25722 #define	MTC0	140	/* Mtag Check bit 0 */
1766330Sjc25722 #define	MTC1	141
1776330Sjc25722 #define	MTC2	142
1786330Sjc25722 #define	MTC3	143
1796330Sjc25722 #define	M2	144
1806330Sjc25722 #define	M3	145
1816330Sjc25722 #define	M4	146
1826330Sjc25722 #define	M	147
1836330Sjc25722 #define	NA	148
1846330Sjc25722 #if defined(JALAPENO) || defined(SERRANO)
1856330Sjc25722 #define	S003	149	/* Syndrome 0x003 => likely from CPU/EDU:ST/FRU/BP */
1866330Sjc25722 #define	S003MEM	150	/* Syndrome 0x003 => likely from WDU/WBP */
1876330Sjc25722 #define	SLAST	S003MEM	/* last special syndrome */
1886330Sjc25722 #else /* JALAPENO || SERRANO */
1896330Sjc25722 #define	S003	149	/* Syndrome 0x003 => likely from EDU:ST */
1906330Sjc25722 #define	S071	150	/* Syndrome 0x071 => likely from WDU/CPU */
1916330Sjc25722 #define	S11C	151	/* Syndrome 0x11c => likely from BERR/DBERR */
1926330Sjc25722 #define	SLAST	S11C	/* last special syndrome */
1936330Sjc25722 #endif /* JALAPENO || SERRANO */
1946330Sjc25722 #if defined(JALAPENO) || defined(SERRANO)
1956330Sjc25722 #define	BPAR0	152	/* syndrom 152 through 167 for bus parity */
1966330Sjc25722 #define	BPAR15	167
1976330Sjc25722 #endif	/* JALAPENO || SERRANO */
1986330Sjc25722 
1996330Sjc25722 static uint8_t ecc_syndrome_tab[] =
2006330Sjc25722 {
2016330Sjc25722 NA,  C0,  C1, S003, C2,  M2,  M3,  47,  C3,  M2,  M2,  53,  M2,  41,  29,   M,
2026330Sjc25722 C4,   M,   M,  50,  M2,  38,  25,  M2,  M2,  33,  24,  M2,  11,   M,  M2,  16,
2036330Sjc25722 C5,   M,   M,  46,  M2,  37,  19,  M2,   M,  31,  32,   M,   7,  M2,  M2,  10,
2046330Sjc25722 M2,  40,  13,  M2,  59,   M,  M2,  66,   M,  M2,  M2,   0,  M2,  67,  71,   M,
2056330Sjc25722 C6,   M,   M,  43,   M,  36,  18,   M,  M2,  49,  15,   M,  63,  M2,  M2,   6,
2066330Sjc25722 M2,  44,  28,  M2,   M,  M2,  M2,  52,  68,  M2,  M2,  62,  M2,  M3,  M3,  M4,
2076330Sjc25722 M2,  26, 106,  M2,  64,   M,  M2,   2, 120,   M,  M2,  M3,   M,  M3,  M3,  M4,
2086330Sjc25722 #if defined(JALAPENO) || defined(SERRANO)
2096330Sjc25722 116, M2,  M2,  M3,  M2,  M3,   M,  M4,  M2,  58,  54,  M2,   M,  M4,  M4,  M3,
2106330Sjc25722 #else	/* JALAPENO || SERRANO */
2116330Sjc25722 116, S071, M2,  M3,  M2,  M3,   M,  M4,  M2,  58,  54,  M2,   M,  M4,  M4,  M3,
2126330Sjc25722 #endif	/* JALAPENO || SERRANO */
2136330Sjc25722 C7,  M2,   M,  42,   M,  35,  17,  M2,   M,  45,  14,  M2,  21,  M2,  M2,   5,
2146330Sjc25722 M,   27,   M,   M,  99,   M,   M,   3, 114,  M2,  M2,  20,  M2,  M3,  M3,   M,
2156330Sjc25722 M2,  23, 113,  M2, 112,  M2,   M,  51,  95,   M,  M2,  M3,  M2,  M3,  M3,  M2,
2166330Sjc25722 103,  M,  M2,  M3,  M2,  M3,  M3,  M4,  M2,  48,   M,   M,  73,  M2,   M,  M3,
2176330Sjc25722 M2,  22, 110,  M2, 109,  M2,   M,   9, 108,  M2,   M,  M3,  M2,  M3,  M3,   M,
2186330Sjc25722 102, M2,   M,   M,  M2,  M3,  M3,   M,  M2,  M3,  M3,  M2,   M,  M4,   M,  M3,
2196330Sjc25722 98,   M,  M2,  M3,  M2,   M,  M3,  M4,  M2,  M3,  M3,  M4,  M3,   M,   M,   M,
2206330Sjc25722 M2,  M3,  M3,   M,  M3,   M,   M,   M,  56,  M4,   M,  M3,  M4,   M,   M,   M,
2216330Sjc25722 C8,   M,  M2,  39,   M,  34, 105,  M2,   M,  30, 104,   M, 101,   M,   M,   4,
2226330Sjc25722 #if defined(JALAPENO) || defined(SERRANO)
2236330Sjc25722 M,    M, 100,   M,  83,   M,  M2,  12,  87,   M,   M,  57,  M2,   M,  M3,   M,
2246330Sjc25722 #else	/* JALAPENO || SERRANO */
2256330Sjc25722 M,    M, 100,   M,  83,   M,  M2,  12,  87,   M,   M,  57, S11C,  M,  M3,   M,
2266330Sjc25722 #endif	/* JALAPENO || SERRANO */
2276330Sjc25722 M2,  97,  82,  M2,  78,  M2,  M2,   1,  96,   M,   M,   M,   M,   M,  M3,  M2,
2286330Sjc25722 94,   M,  M2,  M3,  M2,   M,  M3,   M,  M2,   M,  79,   M,  69,   M,  M4,   M,
2296330Sjc25722 M2,  93,  92,   M,  91,   M,  M2,   8,  90,  M2,  M2,   M,   M,   M,   M,  M4,
2306330Sjc25722 89,   M,   M,  M3,  M2,  M3,  M3,   M,   M,   M,  M3,  M2,  M3,  M2,   M,  M3,
2316330Sjc25722 86,   M,  M2,  M3,  M2,   M,  M3,   M,  M2,   M,  M3,   M,  M3,   M,   M,  M3,
2326330Sjc25722 M,    M,  M3,  M2,  M3,  M2,  M4,   M,  60,   M,  M2,  M3,  M4,   M,   M,  M2,
2336330Sjc25722 M2,  88,  85,  M2,  84,   M,  M2,  55,  81,  M2,  M2,  M3,  M2,  M3,  M3,  M4,
2346330Sjc25722 77,   M,   M,   M,  M2,  M3,   M,   M,  M2,  M3,  M3,  M4,  M3,  M2,   M,   M,
2356330Sjc25722 74,   M,  M2,  M3,   M,   M,  M3,   M,   M,   M,  M3,   M,  M3,   M,  M4,  M3,
2366330Sjc25722 M2,  70, 107,  M4,  65,  M2,  M2,   M, 127,   M,   M,   M,  M2,  M3,  M3,   M,
2376330Sjc25722 80,  M2,  M2,  72,   M, 119, 118,   M,  M2, 126,  76,   M, 125,   M,  M4,  M3,
2386330Sjc25722 M2, 115, 124,   M,  75,   M,   M,  M3,  61,   M,  M4,   M,  M4,   M,   M,   M,
2396330Sjc25722 M,  123, 122,  M4, 121,  M4,   M,  M3, 117,  M2,  M2,  M3,  M4,  M3,   M,   M,
2406330Sjc25722 111,  M,   M,   M,  M4,  M3,  M3,   M,   M,   M,  M3,   M,  M3,  M2,   M,   M
2416330Sjc25722 };
2426330Sjc25722 
2436330Sjc25722 #define	ESYND_TBL_SIZE	(sizeof (ecc_syndrome_tab) / sizeof (uint8_t))
2446330Sjc25722 
245*10784Ssinanallur.balasubramanian@sun.com int8_t L2TAG_bit_to_way_map[128] = {
2466330Sjc25722 /*	1   2   3   4   5   6   7   8   9   10  11  12  13  14  15  16 */
2476330Sjc25722 /* 1 */ 0,  0,  0,  1,  1,  1,  2,  2,  2,  3,  3,  3,  0,  0,  0,  0,
2486330Sjc25722 /* 2 */ 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
2496330Sjc25722 /* 3 */ 0,  0,  0,  0,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
250*10784Ssinanallur.balasubramanian@sun.com /* 4 */ 2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, -1, -1, -1, -1,
251*10784Ssinanallur.balasubramanian@sun.com /* 5 */-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  1,  1,  1,  1,
2526330Sjc25722 /* 6 */ 1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
2536330Sjc25722 /* 7 */ 1,  1,  1,  1,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
254*10784Ssinanallur.balasubramanian@sun.com /* 8 */ 3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3, -1, -1, -1, -1,
2556330Sjc25722 };
2566330Sjc25722 
2576330Sjc25722 uint8_t L2TAG_bit_to_way_bit[128] = {
2586330Sjc25722 /*	1   2   3   4   5   6   7   8   9   10  11  12  13  14  15  16 */
2596330Sjc25722 /* 1 */ 0,  1,  2,  0,  1,  2,  0,  1,  2,  0,  1,  2,  19, 20, 21, 22,
2606330Sjc25722 /* 2 */23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
2616330Sjc25722 /* 3 */39, 40, 41, 42, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
2626330Sjc25722 /* 4 */31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, C0, C0, C0, C0,
2636330Sjc25722 /* 5 */C0, C0, C0, C0, C0, C0, C0, C0, C0, C0, C0, C0, 19, 20, 21, 22,
2646330Sjc25722 /* 6 */23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
2656330Sjc25722 /* 7 */39, 40, 41, 42, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
2666330Sjc25722 /* 8 */31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, C0, C0, C0, C0,
2676330Sjc25722 };
2686330Sjc25722 
269*10784Ssinanallur.balasubramanian@sun.com int8_t L3TAG_bit_to_way_map[128] = {
2706330Sjc25722 /*	1   2   3   4   5   6   7   8   9   10  11  12  13  14  15  16 */
2716330Sjc25722 /* 1 */ 1,  3,  1,  3,  1,  3,  1,  3,  1,  3,  1,  3,  1,  3,  1,  3,
2726330Sjc25722 /* 2 */ 1,  3,  1,  3,  1,  3,  1,  3,  1,  3,  1,  3,  1,  3,  1,  3,
273*10784Ssinanallur.balasubramanian@sun.com /* 3 */ 1,  3,  1,  3,  1,  3,  1,  3,  1,  3,  1,  3,  1,  3, -1, -1,
274*10784Ssinanallur.balasubramanian@sun.com /* 4 */-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2756330Sjc25722 /* 5 */ 0,  2,  0,  2,  0,  2,  0,  2,  0,  2,  0,  2,  0,  2,  0,  2,
2766330Sjc25722 /* 6 */ 0,  2,  0,  2,  0,  2,  0,  2,  0,  2,  0,  2,  0,  2,  0,  2,
277*10784Ssinanallur.balasubramanian@sun.com /* 7 */ 0,  2,  0,  2,  0,  2,  0,  2,  0,  2,  0,  2,  0,  2, -1, -1,
278*10784Ssinanallur.balasubramanian@sun.com /* 8 */-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2796330Sjc25722 };
2806330Sjc25722 
2816330Sjc25722 uint8_t L3TAG_bit_to_way_bit[128] = {
2826330Sjc25722 /*	1   2   3   4   5   6   7   8   9   10  11  12  13  14  15  16 */
2836330Sjc25722 /* 1 */ 0,  0,  1,  1,  2,  2, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28,
2846330Sjc25722 /* 2 */29, 29, 30, 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 36,
2856330Sjc25722 /* 3 */37, 37, 38, 38, 39, 39, 40, 40, 41, 41, 42, 42, 43, 43, C0, C0,
2866330Sjc25722 /* 4 */C0, C0, C0, C0, C0, C0, C0, C0, C0, C0, C0, C0, C0, C0, C0, C0,
2876330Sjc25722 /* 5 */ 0,  0,  1,  1,  2,  2, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28,
2886330Sjc25722 /* 6 */29, 29, 30, 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 36,
2896330Sjc25722 /* 7 */37, 37, 38, 38, 39, 39, 40, 40, 41, 41, 42, 42, 43, 43, C0, C0,
2906330Sjc25722 /* 8 */C0, C0, C0, C0, C0, C0, C0, C0, C0, C0, C0, C0, C0, C0, C0, C0,
2916330Sjc25722 };
2926330Sjc25722 
2936330Sjc25722 uint16_t
calcecc(uint64_t chi,uint64_t clo)2946330Sjc25722 calcecc(uint64_t chi, uint64_t clo)
2956330Sjc25722 {
2966330Sjc25722 	int i;
2976330Sjc25722 	uint64_t syndrome = 0;
2986330Sjc25722 
2996330Sjc25722 	for (i = 0; i < (NDATABITS/2); i++) {
3006330Sjc25722 		syndrome ^= ((chi & 1) ? e[(NDATABITS/2) + i] : 0) ^
3016330Sjc25722 		    ((clo & 1) ? e[i] : 0);
3026330Sjc25722 		chi >>= 1;
3036330Sjc25722 		clo >>= 1;
3046330Sjc25722 	}
3056330Sjc25722 	return (uint16_t)(syndrome);
3066330Sjc25722 }
3076330Sjc25722 
308*10784Ssinanallur.balasubramanian@sun.com uint64_t
calcsynd(uint64_t chi,uint64_t clo,uint64_t ecc)309*10784Ssinanallur.balasubramanian@sun.com calcsynd(uint64_t chi, uint64_t clo, uint64_t ecc)
310*10784Ssinanallur.balasubramanian@sun.com {
311*10784Ssinanallur.balasubramanian@sun.com 	return (calcecc(chi, clo) ^ ecc);
312*10784Ssinanallur.balasubramanian@sun.com }
313*10784Ssinanallur.balasubramanian@sun.com 
3146330Sjc25722 static uint8_t
tag_bit_to_way_bit(cmd_ptrsubtype_t pstype,int16_t tag_bit)315*10784Ssinanallur.balasubramanian@sun.com tag_bit_to_way_bit(cmd_ptrsubtype_t pstype, int16_t tag_bit)
3166330Sjc25722 {
317*10784Ssinanallur.balasubramanian@sun.com 	uint8_t way_bit = C0;
3186330Sjc25722 
3196330Sjc25722 	switch (pstype) {
3206330Sjc25722 		case CMD_PTR_CPU_L2TAG:
3216330Sjc25722 			way_bit = L2TAG_bit_to_way_bit[tag_bit];
3226330Sjc25722 			break;
3236330Sjc25722 		case CMD_PTR_CPU_L3TAG:
3246330Sjc25722 			way_bit = L3TAG_bit_to_way_bit[tag_bit];
3256330Sjc25722 			break;
3266330Sjc25722 	}
3276330Sjc25722 	return (way_bit);
3286330Sjc25722 }
3296330Sjc25722 
330*10784Ssinanallur.balasubramanian@sun.com static int8_t
bit_to_way(cmd_ptrsubtype_t pstype,uint32_t bit)3316330Sjc25722 bit_to_way(cmd_ptrsubtype_t pstype, uint32_t bit)
3326330Sjc25722 {
333*10784Ssinanallur.balasubramanian@sun.com 	int8_t way = -1;
3346330Sjc25722 
3356330Sjc25722 	switch (pstype) {
3366330Sjc25722 		case CMD_PTR_CPU_L2TAG:
3376330Sjc25722 			way = L2TAG_bit_to_way_map[bit & BIT_MASK];
3386330Sjc25722 			break;
3396330Sjc25722 		case CMD_PTR_CPU_L3TAG:
3406330Sjc25722 			way = L3TAG_bit_to_way_map[bit & BIT_MASK];
3416330Sjc25722 			break;
3426330Sjc25722 	}
3436330Sjc25722 	return (way);
3446330Sjc25722 }
3456330Sjc25722 
346*10784Ssinanallur.balasubramanian@sun.com static int32_t
get_index(cmd_ptrsubtype_t pstype,uint64_t tag_afar)3476330Sjc25722 get_index(cmd_ptrsubtype_t pstype, uint64_t tag_afar)
3486330Sjc25722 {
349*10784Ssinanallur.balasubramanian@sun.com 	int32_t	index = -1;
3506330Sjc25722 
3516330Sjc25722 	switch (pstype) {
3526330Sjc25722 		case CMD_PTR_CPU_L2TAG:
353*10784Ssinanallur.balasubramanian@sun.com 			index = (int32_t)((tag_afar & PN_L2_INDEX_MASK)
3546330Sjc25722 			    >> PN_CACHE_LINE_SHIFT);
3556330Sjc25722 			break;
3566330Sjc25722 		case CMD_PTR_CPU_L3TAG:
357*10784Ssinanallur.balasubramanian@sun.com 			index = (int32_t)((tag_afar & PN_L3_TAG_RD_MASK)
3586330Sjc25722 			    >> PN_CACHE_LINE_SHIFT);
3596330Sjc25722 			break;
3606330Sjc25722 	}
3616330Sjc25722 	return (index);
3626330Sjc25722 }
3636330Sjc25722 
364*10784Ssinanallur.balasubramanian@sun.com static int
get_retired_ways(uint64_t * tag_data)365*10784Ssinanallur.balasubramanian@sun.com get_retired_ways(uint64_t *tag_data)
366*10784Ssinanallur.balasubramanian@sun.com {
367*10784Ssinanallur.balasubramanian@sun.com 	int		i, retired_ways;
368*10784Ssinanallur.balasubramanian@sun.com 
369*10784Ssinanallur.balasubramanian@sun.com 	retired_ways = 0;
370*10784Ssinanallur.balasubramanian@sun.com 	for (i = 0; i < PN_CACHE_NWAYS; i++) {
371*10784Ssinanallur.balasubramanian@sun.com 		if ((tag_data[i] & CH_ECSTATE_MASK) ==
372*10784Ssinanallur.balasubramanian@sun.com 		    PN_ECSTATE_NA)
373*10784Ssinanallur.balasubramanian@sun.com 			retired_ways++;
374*10784Ssinanallur.balasubramanian@sun.com 	}
375*10784Ssinanallur.balasubramanian@sun.com 	return (retired_ways);
376*10784Ssinanallur.balasubramanian@sun.com }
377*10784Ssinanallur.balasubramanian@sun.com 
3786330Sjc25722 static cmd_evdisp_t
extract_data_from_ereport_payload(fmd_hdl_t * hdl,nvlist_t * nvl,cmd_cpu_t * cpu,cmd_ptrsubtype_t pstype,uint64_t * afarp,uint64_t * tag_data,const char * fltnm)3796330Sjc25722 extract_data_from_ereport_payload(fmd_hdl_t *hdl, nvlist_t *nvl,
3806330Sjc25722 				    cmd_cpu_t *cpu,
3816330Sjc25722 				    cmd_ptrsubtype_t pstype,
3826330Sjc25722 				    uint64_t *afarp, uint64_t *tag_data,
3836330Sjc25722 				    const char *fltnm)
3846330Sjc25722 {
3856330Sjc25722 	ch_ec_data_t	*ec_data;
3866330Sjc25722 	char		*payload_namep;
387*10784Ssinanallur.balasubramanian@sun.com 	int		tag_afar_status;
3886330Sjc25722 	uint64_t	tag_afar;
3896330Sjc25722 	int		i;
3906330Sjc25722 	uint_t		sz;
391*10784Ssinanallur.balasubramanian@sun.com 	int32_t	index;
392*10784Ssinanallur.balasubramanian@sun.com 	int32_t		recheck_of_tags;
3936330Sjc25722 
394*10784Ssinanallur.balasubramanian@sun.com 	tag_afar_status = cmd_afar_valid(hdl, nvl, 0, &tag_afar);
395*10784Ssinanallur.balasubramanian@sun.com 	if (tag_afar_status == -1) {
3966330Sjc25722 		fmd_hdl_debug(hdl,
397*10784Ssinanallur.balasubramanian@sun.com 		    "\n%s:cpu_id = %d Invalid afar status in nvlist\n",
3986330Sjc25722 		    fltnm, cpu->cpu_cpuid);
3996330Sjc25722 		return (CMD_EVD_BAD);
4006330Sjc25722 	}
4016330Sjc25722 	*afarp = tag_afar;
4026330Sjc25722 	index = get_index(pstype, tag_afar);
4036330Sjc25722 	switch (pstype) {
4046330Sjc25722 		case CMD_PTR_CPU_L2TAG:
4056330Sjc25722 			payload_namep = FM_EREPORT_PAYLOAD_NAME_L2_DATA;
4066330Sjc25722 			break;
4076330Sjc25722 		case CMD_PTR_CPU_L3TAG:
4086330Sjc25722 			payload_namep = FM_EREPORT_PAYLOAD_NAME_L3_DATA;
4096330Sjc25722 			break;
410*10784Ssinanallur.balasubramanian@sun.com 		default:
411*10784Ssinanallur.balasubramanian@sun.com 			return (CMD_EVD_BAD);
4126330Sjc25722 	}
413*10784Ssinanallur.balasubramanian@sun.com 	if (nvlist_lookup_int32(nvl, FM_EREPORT_RECHECK_OF_TAGS,
414*10784Ssinanallur.balasubramanian@sun.com 	    &recheck_of_tags) != 0)
415*10784Ssinanallur.balasubramanian@sun.com 		recheck_of_tags = 0;
416*10784Ssinanallur.balasubramanian@sun.com 	if ((recheck_of_tags) || (test_mode))
417*10784Ssinanallur.balasubramanian@sun.com 		return (get_tagdata(cpu, pstype, index, tag_data));
418*10784Ssinanallur.balasubramanian@sun.com 	if (nvlist_lookup_uint64_array(nvl, payload_namep,
419*10784Ssinanallur.balasubramanian@sun.com 	    (uint64_t **)&ec_data, &sz) != 0) {
420*10784Ssinanallur.balasubramanian@sun.com 		fmd_hdl_debug(hdl,
421*10784Ssinanallur.balasubramanian@sun.com 		    "\n%s: cpu_id = %d index = %d could not find %s"
422*10784Ssinanallur.balasubramanian@sun.com 		    " in nvlist\n",
423*10784Ssinanallur.balasubramanian@sun.com 		    fltnm, cpu->cpu_cpuid, index, payload_namep);
424*10784Ssinanallur.balasubramanian@sun.com 		fmd_hdl_debug(hdl,
425*10784Ssinanallur.balasubramanian@sun.com 		    "\n%s: cpu_id = %d Reading tag data through"
426*10784Ssinanallur.balasubramanian@sun.com 		    " mem_cache driver.\n",
427*10784Ssinanallur.balasubramanian@sun.com 		    fltnm, cpu->cpu_cpuid);
4286330Sjc25722 		return (get_tagdata(cpu, pstype, index,
4296330Sjc25722 		    tag_data));
4306330Sjc25722 	}
4316330Sjc25722 	for (i = 0; i < PN_CACHE_NWAYS; i++) {
4326330Sjc25722 		tag_data[i] = ec_data[i].ec_tag;
4336330Sjc25722 	}
4346330Sjc25722 	return (CMD_EVD_OK);
4356330Sjc25722 }
4366330Sjc25722 
4376330Sjc25722 static void
print_ecc(fmd_hdl_t * hdl,cmd_cpu_t * cpu,const char * fltnm,uint64_t * tag_data)4386330Sjc25722 print_ecc(fmd_hdl_t *hdl, cmd_cpu_t *cpu, const char *fltnm, uint64_t *tag_data)
4396330Sjc25722 {
4406330Sjc25722 	int	i;
4416330Sjc25722 	uint16_t	tag_ecc[PN_CACHE_NWAYS];
4426330Sjc25722 
4436330Sjc25722 	for (i = 0; i < PN_CACHE_NWAYS; i++) {
444*10784Ssinanallur.balasubramanian@sun.com 		tag_ecc[i] =
445*10784Ssinanallur.balasubramanian@sun.com 		    ((tag_data[i] & PN_TAG_ECC_MASK)
446*10784Ssinanallur.balasubramanian@sun.com 		    >> PN_LX_TAG_ECC_START_BIT);
4476330Sjc25722 	}
4486330Sjc25722 	fmd_hdl_debug(hdl,
449*10784Ssinanallur.balasubramanian@sun.com 	    "\n%s: cpu_id = %d ecc[0] = 0x%03x ecc[1] = 0x%03x"
450*10784Ssinanallur.balasubramanian@sun.com 	    " ecc[2] = 0x%03x ecc[3] = 0x%03x\n",
4516330Sjc25722 	    fltnm, cpu->cpu_cpuid, tag_ecc[0], tag_ecc[1], tag_ecc[2],
4526330Sjc25722 	    tag_ecc[3]);
4536330Sjc25722 
4546330Sjc25722 }
4556330Sjc25722 
4566330Sjc25722 static int
matching_ecc(uint64_t * tag_data)4576330Sjc25722 matching_ecc(uint64_t *tag_data)
4586330Sjc25722 {
4596330Sjc25722 	int	i;
4606330Sjc25722 	uint16_t	tag_ecc[PN_CACHE_NWAYS];
4616330Sjc25722 
4626330Sjc25722 	for (i = 0; i < PN_CACHE_NWAYS; i++) {
463*10784Ssinanallur.balasubramanian@sun.com 		tag_ecc[i] =
464*10784Ssinanallur.balasubramanian@sun.com 		    ((tag_data[i] & PN_TAG_ECC_MASK)
465*10784Ssinanallur.balasubramanian@sun.com 		    >> PN_LX_TAG_ECC_START_BIT);
4666330Sjc25722 		if (tag_ecc[i] != tag_ecc[0]) {
4676330Sjc25722 			return (1);
4686330Sjc25722 		}
4696330Sjc25722 	}
4706330Sjc25722 	return (0);
4716330Sjc25722 }
4726330Sjc25722 
4736330Sjc25722 static void
gen_data_for_ecc(uint64_t * tag_data,uint64_t * data_for_ecc_gen,cmd_ptrsubtype_t pstype)4746330Sjc25722 gen_data_for_ecc(uint64_t *tag_data, uint64_t *data_for_ecc_gen,
4756330Sjc25722 		    cmd_ptrsubtype_t pstype)
4766330Sjc25722 {
4776330Sjc25722 	uint64_t	ptag[PN_CACHE_NWAYS];
4786330Sjc25722 	uint8_t		state[PN_CACHE_NWAYS];
4796330Sjc25722 	int		i;
4806330Sjc25722 	uint16_t	tag_ecc[PN_CACHE_NWAYS];
4816330Sjc25722 	uint8_t		bit_position;
4826330Sjc25722 
4836330Sjc25722 	for (i = 0; i < PN_CACHE_NWAYS; i++) {
4846330Sjc25722 		state[i] = tag_data[i] & CH_ECSTATE_MASK;
485*10784Ssinanallur.balasubramanian@sun.com 		tag_ecc[i] =
486*10784Ssinanallur.balasubramanian@sun.com 		    ((tag_data[i] & PN_TAG_ECC_MASK)
487*10784Ssinanallur.balasubramanian@sun.com 		    >> PN_LX_TAG_ECC_START_BIT);
4886330Sjc25722 		switch (pstype) {
4896330Sjc25722 			case CMD_PTR_CPU_L2TAG:
4906330Sjc25722 				ptag[i] = (tag_data[i] >> PN_L2_PTAG_SHIFT) &
4916330Sjc25722 				    L2_PTAG_MASK;
4926330Sjc25722 				break;
4936330Sjc25722 			case CMD_PTR_CPU_L3TAG:
4946330Sjc25722 				ptag[i] = (tag_data[i] >> PN_L3_PTAG_SHIFT) &
4956330Sjc25722 				    L3_PTAG_MASK;
4966330Sjc25722 				break;
4976330Sjc25722 		}
4986330Sjc25722 	}
4996330Sjc25722 	/*
5006330Sjc25722 	 * We now assemble the 128 bit data swizzling the Physical tags
5016330Sjc25722 	 * and states we obtained for all the 4 ways.
5026330Sjc25722 	 */
5036330Sjc25722 	data_for_ecc_gen[0] = 0;	/* high order 64 bits */
5046330Sjc25722 	data_for_ecc_gen[1] = 0;	/* low order 64 bits */
5056330Sjc25722 	switch (pstype) {
5066330Sjc25722 		case CMD_PTR_CPU_L2TAG:
5076330Sjc25722 			data_for_ecc_gen[1] = state[0];	/* way 0 state */
5086330Sjc25722 			data_for_ecc_gen[1] |=
5096330Sjc25722 			    (state[1] << 3); /* way 1 state */
5106330Sjc25722 			data_for_ecc_gen[1] |=
5116330Sjc25722 			    (state[2] << 6); /* way 2 state */
5126330Sjc25722 			data_for_ecc_gen[1] |=
5136330Sjc25722 			    (state[3] << 9); /* way 3 state */
5146330Sjc25722 			data_for_ecc_gen[1] |= (ptag[0] << 12); /* way 0 ptag */
5156330Sjc25722 			data_for_ecc_gen[1] |= (ptag[2] << 36); /* way 2 ptag */
5166330Sjc25722 			/* bits 63:60 of low order 64 bits are 0s */
5176330Sjc25722 
5186330Sjc25722 			/*
5196330Sjc25722 			 * We now start with hig order 64 bits.
5206330Sjc25722 			 * the low 12 bits are 0s
5216330Sjc25722 			 */
5226330Sjc25722 			data_for_ecc_gen[0] |= (ptag[1] << 12); /* way 1 ptag */
5236330Sjc25722 			data_for_ecc_gen[0] |= (ptag[3] << 36); /* way 3 ptag */
5246330Sjc25722 			break;
5256330Sjc25722 		case CMD_PTR_CPU_L3TAG:
5266330Sjc25722 			bit_position = 0;
5276330Sjc25722 			/*
5286330Sjc25722 			 * Swizzle state bits for way 1 and way 3
5296330Sjc25722 			 */
5306330Sjc25722 			for (i = 0; i < 3; i++) {
5316330Sjc25722 				data_for_ecc_gen[1] |=
5326330Sjc25722 				    (((state[1] >> i) & 1) << bit_position);
5336330Sjc25722 				bit_position++;
5346330Sjc25722 				data_for_ecc_gen[1] |=
5356330Sjc25722 				    (((state[3] >> i) & 1) << bit_position);
5366330Sjc25722 				bit_position++;
5376330Sjc25722 			}
5386330Sjc25722 			/*
5396330Sjc25722 			 * Swizzle physical tag bits for way 1 and way 3
5406330Sjc25722 			 */
5416330Sjc25722 			for (i = 0; i < 20; i++) {
5426330Sjc25722 				data_for_ecc_gen[1] |=
5436330Sjc25722 				    (((ptag[1] >> i) & 1) << bit_position);
5446330Sjc25722 				bit_position++;
5456330Sjc25722 				data_for_ecc_gen[1] |=
5466330Sjc25722 				    (((ptag[3] >> i) & 1) << bit_position);
5476330Sjc25722 				bit_position++;
5486330Sjc25722 			}
5496330Sjc25722 			/*
5506330Sjc25722 			 * start the high order 64 bits.
5516330Sjc25722 			 */
5526330Sjc25722 			bit_position = 0;
5536330Sjc25722 			/*
5546330Sjc25722 			 * Swizzle state bits for way 0 and way 2
5556330Sjc25722 			 */
5566330Sjc25722 			for (i = 0; i < 3; i++) {
5576330Sjc25722 				data_for_ecc_gen[0] |=
5586330Sjc25722 				    (((state[0] >> i) & 1) << bit_position);
5596330Sjc25722 				bit_position++;
5606330Sjc25722 				data_for_ecc_gen[0] |=
5616330Sjc25722 				    (((state[2] >> i) & 1) << bit_position);
5626330Sjc25722 				bit_position++;
5636330Sjc25722 			}
5646330Sjc25722 			/*
5656330Sjc25722 			 * Swizzle physical tag bits for way 0 and way 2
5666330Sjc25722 			 */
5676330Sjc25722 			for (i = 0; i < 20; i++) {
5686330Sjc25722 				data_for_ecc_gen[0] |=
5696330Sjc25722 				    (((ptag[0] >> i) & 1) << bit_position);
5706330Sjc25722 				bit_position++;
5716330Sjc25722 				data_for_ecc_gen[0] |=
5726330Sjc25722 				    (((ptag[2] >> i) & 1) << bit_position);
5736330Sjc25722 				bit_position++;
5746330Sjc25722 			}
5756330Sjc25722 			break;
5766330Sjc25722 	}
5776330Sjc25722 }
5786330Sjc25722 
5796330Sjc25722 static uint16_t
compute_syndrome(uint64_t * tag_data,cmd_ptrsubtype_t pstype)5806330Sjc25722 compute_syndrome(uint64_t *tag_data, cmd_ptrsubtype_t pstype)
5816330Sjc25722 {
5826330Sjc25722 	uint64_t	tag_synd;
5836330Sjc25722 	uint64_t	data_for_ecc_gen[2];
5846330Sjc25722 	uint16_t	tag_ecc;
5856330Sjc25722 
5866330Sjc25722 	gen_data_for_ecc(tag_data, data_for_ecc_gen, pstype);
587*10784Ssinanallur.balasubramanian@sun.com 	tag_ecc = ((tag_data[0] & PN_TAG_ECC_MASK) >> PN_LX_TAG_ECC_START_BIT);
5886330Sjc25722 	tag_synd = calcsynd(data_for_ecc_gen[0], data_for_ecc_gen[1],
5896330Sjc25722 	    (uint64_t)tag_ecc);
5906330Sjc25722 	return (tag_synd);
5916330Sjc25722 }
5926330Sjc25722 
593*10784Ssinanallur.balasubramanian@sun.com static int16_t
find_bit_stickiness(uint64_t * tag_data,int8_t way,int16_t bit)594*10784Ssinanallur.balasubramanian@sun.com find_bit_stickiness(uint64_t *tag_data, int8_t way, int16_t bit)
595*10784Ssinanallur.balasubramanian@sun.com {
596*10784Ssinanallur.balasubramanian@sun.com 	int16_t	sticky_bit;
597*10784Ssinanallur.balasubramanian@sun.com 
598*10784Ssinanallur.balasubramanian@sun.com 	sticky_bit = bit;
599*10784Ssinanallur.balasubramanian@sun.com 	if ((tag_data[way] & ((uint64_t)1 << bit)) != 0)
600*10784Ssinanallur.balasubramanian@sun.com 		sticky_bit |= MSB_BIT;
601*10784Ssinanallur.balasubramanian@sun.com 	return (sticky_bit);
602*10784Ssinanallur.balasubramanian@sun.com }
603*10784Ssinanallur.balasubramanian@sun.com 
604*10784Ssinanallur.balasubramanian@sun.com static cmd_Lxcache_t *
cmd_create_and_destroy_Lxcache(fmd_hdl_t * hdl,cmd_cpu_t * cpu,cmd_Lxcache_t * Lxcache)605*10784Ssinanallur.balasubramanian@sun.com cmd_create_and_destroy_Lxcache(fmd_hdl_t *hdl, cmd_cpu_t *cpu,
606*10784Ssinanallur.balasubramanian@sun.com 	cmd_Lxcache_t *Lxcache)
607*10784Ssinanallur.balasubramanian@sun.com {
608*10784Ssinanallur.balasubramanian@sun.com 	const char		*fltnm;
609*10784Ssinanallur.balasubramanian@sun.com 	cmd_Lxcache_t	*new_Lxcache;
610*10784Ssinanallur.balasubramanian@sun.com 
611*10784Ssinanallur.balasubramanian@sun.com 	fltnm = cmd_type_to_str(Lxcache->Lxcache_type);
612*10784Ssinanallur.balasubramanian@sun.com 
613*10784Ssinanallur.balasubramanian@sun.com 	/*
614*10784Ssinanallur.balasubramanian@sun.com 	 * We first create a new Lxcache and add the event ep
615*10784Ssinanallur.balasubramanian@sun.com 	 * that is in Lxcache to the new case we create.
616*10784Ssinanallur.balasubramanian@sun.com 	 * we then destroy the Lxcache that has the event ep in its SERD engine.
617*10784Ssinanallur.balasubramanian@sun.com 	 */
618*10784Ssinanallur.balasubramanian@sun.com 	new_Lxcache = cmd_Lxcache_create(hdl, Lxcache->xr, cpu,
619*10784Ssinanallur.balasubramanian@sun.com 	    cpu->cpu_asru_nvl,
620*10784Ssinanallur.balasubramanian@sun.com 	    Lxcache->Lxcache_type,
621*10784Ssinanallur.balasubramanian@sun.com 	    Lxcache->Lxcache_index, Lxcache->Lxcache_way, Lxcache->Lxcache_bit);
622*10784Ssinanallur.balasubramanian@sun.com 	if (new_Lxcache == NULL) {
623*10784Ssinanallur.balasubramanian@sun.com 		fmd_hdl_debug(hdl,
624*10784Ssinanallur.balasubramanian@sun.com 		    "\n%s:cpu_id %d:Failed to create a Lxcache for"
625*10784Ssinanallur.balasubramanian@sun.com 		    " index %d way %d bit %d\n",
626*10784Ssinanallur.balasubramanian@sun.com 		    fltnm, cpu->cpu_cpuid, Lxcache->Lxcache_index,
627*10784Ssinanallur.balasubramanian@sun.com 		    Lxcache->Lxcache_way, Lxcache->Lxcache_bit);
628*10784Ssinanallur.balasubramanian@sun.com 		return (NULL);
629*10784Ssinanallur.balasubramanian@sun.com 	}
630*10784Ssinanallur.balasubramanian@sun.com 	(void) cmd_create_case_for_Lxcache(hdl, cpu, new_Lxcache);
631*10784Ssinanallur.balasubramanian@sun.com 	cmd_Lxcache_destroy(hdl, cpu, Lxcache);
632*10784Ssinanallur.balasubramanian@sun.com 	return (new_Lxcache);
633*10784Ssinanallur.balasubramanian@sun.com }
634*10784Ssinanallur.balasubramanian@sun.com 
635*10784Ssinanallur.balasubramanian@sun.com int
cmd_Lxcache_retire_as_reason(fmd_hdl_t * hdl,cmd_cpu_t * cpu,cmd_Lxcache_t * Lxcache,const char * fltnm,int32_t reason)636*10784Ssinanallur.balasubramanian@sun.com cmd_Lxcache_retire_as_reason(fmd_hdl_t *hdl, cmd_cpu_t *cpu,
637*10784Ssinanallur.balasubramanian@sun.com     cmd_Lxcache_t *Lxcache, const char *fltnm, int32_t reason)
6386330Sjc25722 {
639*10784Ssinanallur.balasubramanian@sun.com 	boolean_t	ret;
640*10784Ssinanallur.balasubramanian@sun.com 	uint_t		certainty;
641*10784Ssinanallur.balasubramanian@sun.com 
642*10784Ssinanallur.balasubramanian@sun.com 	if (reason == CMD_LXSUSPECT_0_TAG) {
643*10784Ssinanallur.balasubramanian@sun.com 		/*
644*10784Ssinanallur.balasubramanian@sun.com 		 * clear MSB bit to retire as SUSPECT_0_TAG
645*10784Ssinanallur.balasubramanian@sun.com 		 * We need to update the Lxcache asru to reflect
646*10784Ssinanallur.balasubramanian@sun.com 		 * the change in bit value.
647*10784Ssinanallur.balasubramanian@sun.com 		 */
648*10784Ssinanallur.balasubramanian@sun.com 		Lxcache->Lxcache_bit &= CLEAR_MSB_BIT;
649*10784Ssinanallur.balasubramanian@sun.com 		errno = nvlist_add_uint16(
650*10784Ssinanallur.balasubramanian@sun.com 		    Lxcache->Lxcache_asru_nvl,
651*10784Ssinanallur.balasubramanian@sun.com 		    FM_FMRI_CPU_CACHE_BIT,
652*10784Ssinanallur.balasubramanian@sun.com 		    Lxcache->Lxcache_bit);
653*10784Ssinanallur.balasubramanian@sun.com 		if (errno) {
654*10784Ssinanallur.balasubramanian@sun.com 			fmd_hdl_debug(hdl,
655*10784Ssinanallur.balasubramanian@sun.com 			    "\n%s:cpu_id %d: failed to update",
656*10784Ssinanallur.balasubramanian@sun.com 			    " CACHE_BIT in asru.\n",
657*10784Ssinanallur.balasubramanian@sun.com 			    fltnm, cpu->cpu_cpuid);
658*10784Ssinanallur.balasubramanian@sun.com 			return (CMD_EVD_BAD);
659*10784Ssinanallur.balasubramanian@sun.com 		}
660*10784Ssinanallur.balasubramanian@sun.com 	}
661*10784Ssinanallur.balasubramanian@sun.com 	if (reason == CMD_LXCONVICTED)
662*10784Ssinanallur.balasubramanian@sun.com 		certainty = HUNDRED_PERCENT;
663*10784Ssinanallur.balasubramanian@sun.com 	else
664*10784Ssinanallur.balasubramanian@sun.com 		certainty = SUSPECT_PERCENT;
665*10784Ssinanallur.balasubramanian@sun.com 	ret = cmd_Lxcache_retire(hdl, cpu, Lxcache, fltnm, certainty);
666*10784Ssinanallur.balasubramanian@sun.com 	if (reason == CMD_LXSUSPECT_0_TAG)
667*10784Ssinanallur.balasubramanian@sun.com 		Lxcache->Lxcache_bit |= SET_MSB_BIT;
668*10784Ssinanallur.balasubramanian@sun.com 	if (ret == B_FALSE)
669*10784Ssinanallur.balasubramanian@sun.com 		return (CMD_EVD_BAD);
670*10784Ssinanallur.balasubramanian@sun.com 	Lxcache->Lxcache_reason = reason;
671*10784Ssinanallur.balasubramanian@sun.com 	/*
672*10784Ssinanallur.balasubramanian@sun.com 	 * Update the persistence storage of
673*10784Ssinanallur.balasubramanian@sun.com 	 * Lxcache.
674*10784Ssinanallur.balasubramanian@sun.com 	 */
675*10784Ssinanallur.balasubramanian@sun.com 	fmd_hdl_debug(hdl,
676*10784Ssinanallur.balasubramanian@sun.com 	    "\n%s:cpu_id %d:reason = %s flags = %s\n",
677*10784Ssinanallur.balasubramanian@sun.com 	    fltnm, cpu->cpu_cpuid,
678*10784Ssinanallur.balasubramanian@sun.com 	    cmd_reason_to_str(Lxcache->Lxcache_reason),
679*10784Ssinanallur.balasubramanian@sun.com 	    cmd_flags_to_str(Lxcache->Lxcache_flags));
680*10784Ssinanallur.balasubramanian@sun.com 	cmd_Lxcache_write(hdl, Lxcache);
681*10784Ssinanallur.balasubramanian@sun.com 	return (CMD_EVD_OK);
682*10784Ssinanallur.balasubramanian@sun.com }
683*10784Ssinanallur.balasubramanian@sun.com 
684*10784Ssinanallur.balasubramanian@sun.com int
retire_lowest_retirable_way_as_suspect(fmd_hdl_t * hdl,cmd_cpu_t * cpu,cmd_Lxcache_t * anonymous_Lxcache,const char * fltnm)685*10784Ssinanallur.balasubramanian@sun.com retire_lowest_retirable_way_as_suspect(fmd_hdl_t *hdl, cmd_cpu_t *cpu,
686*10784Ssinanallur.balasubramanian@sun.com     cmd_Lxcache_t *anonymous_Lxcache, const char *fltnm)
687*10784Ssinanallur.balasubramanian@sun.com {
688*10784Ssinanallur.balasubramanian@sun.com 	/*
689*10784Ssinanallur.balasubramanian@sun.com 	 * This routine is called only when handling anonymous TAG or DATA
690*10784Ssinanallur.balasubramanian@sun.com 	 * errors. When we exit this routine we would have destroyed the
691*10784Ssinanallur.balasubramanian@sun.com 	 * anonymous_Lxcache structure that was passed to us and created
692*10784Ssinanallur.balasubramanian@sun.com 	 * a new Lxcache if we were successful in determining a way to retire.
693*10784Ssinanallur.balasubramanian@sun.com 	 */
694*10784Ssinanallur.balasubramanian@sun.com 	int8_t	lowest_retirable_way, ways_retired;
695*10784Ssinanallur.balasubramanian@sun.com 	int32_t	reason;
696*10784Ssinanallur.balasubramanian@sun.com 	cmd_ptrsubtype_t type;
697*10784Ssinanallur.balasubramanian@sun.com 	cmd_Lxcache_t *new_Lxcache;
6986330Sjc25722 
699*10784Ssinanallur.balasubramanian@sun.com 	ways_retired = get_index_retired_ways(cpu,
700*10784Ssinanallur.balasubramanian@sun.com 	    anonymous_Lxcache->Lxcache_type,
701*10784Ssinanallur.balasubramanian@sun.com 	    anonymous_Lxcache->Lxcache_index);
702*10784Ssinanallur.balasubramanian@sun.com 	if (ways_retired == -1) {
703*10784Ssinanallur.balasubramanian@sun.com 		/*
704*10784Ssinanallur.balasubramanian@sun.com 		 * Couldn't determine how many ways have been retired at this
705*10784Ssinanallur.balasubramanian@sun.com 		 * index. Destroy the anonymous_Lxcache and return failure.
706*10784Ssinanallur.balasubramanian@sun.com 		 */
707*10784Ssinanallur.balasubramanian@sun.com 		cmd_Lxcache_destroy(hdl, cpu, anonymous_Lxcache);
708*10784Ssinanallur.balasubramanian@sun.com 		return (CMD_EVD_BAD);
709*10784Ssinanallur.balasubramanian@sun.com 	}
710*10784Ssinanallur.balasubramanian@sun.com 	/*
711*10784Ssinanallur.balasubramanian@sun.com 	 * Before retiring a way check if we have already
712*10784Ssinanallur.balasubramanian@sun.com 	 * retired 3 ways for this index.
713*10784Ssinanallur.balasubramanian@sun.com 	 * For TAG errors we will not perform this check because
714*10784Ssinanallur.balasubramanian@sun.com 	 * we could reretire cachlines retired for DATA errors.
715*10784Ssinanallur.balasubramanian@sun.com 	 * The get_lowest_retirable_way() will ensure that we do
716*10784Ssinanallur.balasubramanian@sun.com 	 * not end up retiring all 4 ways.
717*10784Ssinanallur.balasubramanian@sun.com 	 */
718*10784Ssinanallur.balasubramanian@sun.com 	if (!IS_TAG(anonymous_Lxcache->Lxcache_type)) {
719*10784Ssinanallur.balasubramanian@sun.com 		if (ways_retired >= 3) {
720*10784Ssinanallur.balasubramanian@sun.com 			fmd_hdl_debug(hdl,
721*10784Ssinanallur.balasubramanian@sun.com 			    "\n%s: cpu %d: num of ways retired for index %d"
722*10784Ssinanallur.balasubramanian@sun.com 			    " is %d will fault the CPU\n",
723*10784Ssinanallur.balasubramanian@sun.com 			    fltnm, cpu->cpu_cpuid,
724*10784Ssinanallur.balasubramanian@sun.com 			    anonymous_Lxcache->Lxcache_index, ways_retired);
725*10784Ssinanallur.balasubramanian@sun.com 			type = anonymous_Lxcache->Lxcache_type;
726*10784Ssinanallur.balasubramanian@sun.com 			/*
727*10784Ssinanallur.balasubramanian@sun.com 			 * destroy the anonymous_Lxcache
728*10784Ssinanallur.balasubramanian@sun.com 			 */
729*10784Ssinanallur.balasubramanian@sun.com 			cmd_Lxcache_destroy(hdl, cpu, anonymous_Lxcache);
730*10784Ssinanallur.balasubramanian@sun.com 			cmd_fault_the_cpu(hdl, cpu, type, fltnm);
731*10784Ssinanallur.balasubramanian@sun.com 			return (CMD_EVD_OK);
732*10784Ssinanallur.balasubramanian@sun.com 		}
733*10784Ssinanallur.balasubramanian@sun.com 	}
734*10784Ssinanallur.balasubramanian@sun.com 	/*
735*10784Ssinanallur.balasubramanian@sun.com 	 * No ways have been retired as "SUSPECT" for this bit.
736*10784Ssinanallur.balasubramanian@sun.com 	 * We need to retire the lowest unretired way as suspect.
737*10784Ssinanallur.balasubramanian@sun.com 	 */
738*10784Ssinanallur.balasubramanian@sun.com 	fmd_hdl_debug(hdl,
739*10784Ssinanallur.balasubramanian@sun.com 	    "\n%s: cpu_id %d Checking for the lowest retirable"
740*10784Ssinanallur.balasubramanian@sun.com 	    " way at index %d\n",
741*10784Ssinanallur.balasubramanian@sun.com 	    fltnm, cpu->cpu_cpuid, anonymous_Lxcache->Lxcache_index);
742*10784Ssinanallur.balasubramanian@sun.com 	lowest_retirable_way = cmd_Lxcache_get_lowest_retirable_way(cpu,
743*10784Ssinanallur.balasubramanian@sun.com 	    anonymous_Lxcache->Lxcache_index, anonymous_Lxcache->Lxcache_type);
744*10784Ssinanallur.balasubramanian@sun.com 	if (lowest_retirable_way != -1) {
745*10784Ssinanallur.balasubramanian@sun.com 		fmd_hdl_debug(hdl,
746*10784Ssinanallur.balasubramanian@sun.com 		    "\n%s: cpu_id %d lowest retirable way is %d\n",
747*10784Ssinanallur.balasubramanian@sun.com 		    fltnm, cpu->cpu_cpuid, lowest_retirable_way);
748*10784Ssinanallur.balasubramanian@sun.com 		anonymous_Lxcache->Lxcache_way = lowest_retirable_way;
749*10784Ssinanallur.balasubramanian@sun.com 		new_Lxcache = cmd_create_and_destroy_Lxcache(hdl, cpu,
750*10784Ssinanallur.balasubramanian@sun.com 		    anonymous_Lxcache);
751*10784Ssinanallur.balasubramanian@sun.com 		if ((new_Lxcache == NULL) ||
752*10784Ssinanallur.balasubramanian@sun.com 		    (new_Lxcache->Lxcache_case.cc_cp == NULL)) {
753*10784Ssinanallur.balasubramanian@sun.com 			return (CMD_EVD_BAD);
754*10784Ssinanallur.balasubramanian@sun.com 		}
755*10784Ssinanallur.balasubramanian@sun.com 		if (IS_TAG(new_Lxcache->Lxcache_type))
756*10784Ssinanallur.balasubramanian@sun.com 			reason = CMD_LXSUSPECT_0_TAG;
757*10784Ssinanallur.balasubramanian@sun.com 		else
758*10784Ssinanallur.balasubramanian@sun.com 			reason = CMD_LXSUSPECT_DATA;
759*10784Ssinanallur.balasubramanian@sun.com 		return (cmd_Lxcache_retire_as_reason(hdl, cpu, new_Lxcache,
760*10784Ssinanallur.balasubramanian@sun.com 		    fltnm, reason));
761*10784Ssinanallur.balasubramanian@sun.com 	} else {
762*10784Ssinanallur.balasubramanian@sun.com 		fmd_hdl_debug(hdl,
763*10784Ssinanallur.balasubramanian@sun.com 		    "\n%s:cpu_id %d we are unable to determine which"
764*10784Ssinanallur.balasubramanian@sun.com 		    " way is faulty at cache index %d."
765*10784Ssinanallur.balasubramanian@sun.com 		    " Will retire the CPU.\nRecommended-Action:"
766*10784Ssinanallur.balasubramanian@sun.com 		    " Service action required\n",
767*10784Ssinanallur.balasubramanian@sun.com 		    fltnm, cpu->cpu_cpuid, anonymous_Lxcache->Lxcache_index);
768*10784Ssinanallur.balasubramanian@sun.com 		type = anonymous_Lxcache->Lxcache_type;
769*10784Ssinanallur.balasubramanian@sun.com 		/*
770*10784Ssinanallur.balasubramanian@sun.com 		 * destroy the anonymous_Lxcache
771*10784Ssinanallur.balasubramanian@sun.com 		 */
772*10784Ssinanallur.balasubramanian@sun.com 		cmd_Lxcache_destroy(hdl, cpu, anonymous_Lxcache);
773*10784Ssinanallur.balasubramanian@sun.com 		cmd_fault_the_cpu(hdl, cpu, type, fltnm);
774*10784Ssinanallur.balasubramanian@sun.com 		return (CMD_EVD_OK);
7756330Sjc25722 	}
776*10784Ssinanallur.balasubramanian@sun.com }
777*10784Ssinanallur.balasubramanian@sun.com 
778*10784Ssinanallur.balasubramanian@sun.com int
unretire_suspect_and_retire_next_retirable_way(fmd_hdl_t * hdl,cmd_cpu_t * cpu,cmd_Lxcache_t * suspect_Lxcache,cmd_Lxcache_t * anonymous_Lxcache,const char * fltnm)779*10784Ssinanallur.balasubramanian@sun.com unretire_suspect_and_retire_next_retirable_way(fmd_hdl_t *hdl, cmd_cpu_t *cpu,
780*10784Ssinanallur.balasubramanian@sun.com     cmd_Lxcache_t *suspect_Lxcache, cmd_Lxcache_t *anonymous_Lxcache,
781*10784Ssinanallur.balasubramanian@sun.com     const char *fltnm)
782*10784Ssinanallur.balasubramanian@sun.com {
783*10784Ssinanallur.balasubramanian@sun.com 	int8_t	retired_way, next_retirable_way;
784*10784Ssinanallur.balasubramanian@sun.com 	int32_t	retired_index;
785*10784Ssinanallur.balasubramanian@sun.com 	cmd_ptrsubtype_t retired_type;
786*10784Ssinanallur.balasubramanian@sun.com 	int32_t	reason;
787*10784Ssinanallur.balasubramanian@sun.com 	cmd_Lxcache_t *new_Lxcache;
788*10784Ssinanallur.balasubramanian@sun.com 
789*10784Ssinanallur.balasubramanian@sun.com 	/*
790*10784Ssinanallur.balasubramanian@sun.com 	 * This routine is called only when handling anonymous TAG or DATA
791*10784Ssinanallur.balasubramanian@sun.com 	 * errors. When we exit this routine we would have destroyed the
792*10784Ssinanallur.balasubramanian@sun.com 	 * anonymous_Lxcache structure that was passed to us.
793*10784Ssinanallur.balasubramanian@sun.com 	 */
794*10784Ssinanallur.balasubramanian@sun.com 	fmd_hdl_debug(hdl,
795*10784Ssinanallur.balasubramanian@sun.com 	    "\n%s:cpu_id %d found index %d way %d"
796*10784Ssinanallur.balasubramanian@sun.com 	    " bit %d retired as %s. Will unretire this now.\n",
797*10784Ssinanallur.balasubramanian@sun.com 	    fltnm, cpu->cpu_cpuid, suspect_Lxcache->Lxcache_index,
798*10784Ssinanallur.balasubramanian@sun.com 	    suspect_Lxcache->Lxcache_way, suspect_Lxcache->Lxcache_bit,
799*10784Ssinanallur.balasubramanian@sun.com 	    cmd_reason_to_str(suspect_Lxcache->Lxcache_reason));
800*10784Ssinanallur.balasubramanian@sun.com 	/*
801*10784Ssinanallur.balasubramanian@sun.com 	 * Save the way because we will destroy the
802*10784Ssinanallur.balasubramanian@sun.com 	 * suspect_Lxcache after we successfully unretire it.
803*10784Ssinanallur.balasubramanian@sun.com 	 */
804*10784Ssinanallur.balasubramanian@sun.com 	retired_way = suspect_Lxcache->Lxcache_way;
805*10784Ssinanallur.balasubramanian@sun.com 	retired_index = suspect_Lxcache->Lxcache_index;
806*10784Ssinanallur.balasubramanian@sun.com 	retired_type = suspect_Lxcache->Lxcache_type;
807*10784Ssinanallur.balasubramanian@sun.com 	/*
808*10784Ssinanallur.balasubramanian@sun.com 	 * unretire the retired_way.
809*10784Ssinanallur.balasubramanian@sun.com 	 */
810*10784Ssinanallur.balasubramanian@sun.com 	if (cmd_Lxcache_unretire(hdl, cpu, suspect_Lxcache,
811*10784Ssinanallur.balasubramanian@sun.com 	    fltnm)
812*10784Ssinanallur.balasubramanian@sun.com 	    == B_TRUE) {
813*10784Ssinanallur.balasubramanian@sun.com 		suspect_Lxcache->Lxcache_reason =
814*10784Ssinanallur.balasubramanian@sun.com 		    CMD_LXFUNCTIONING;
815*10784Ssinanallur.balasubramanian@sun.com 		fmd_hdl_debug(hdl,
816*10784Ssinanallur.balasubramanian@sun.com 		    "\n%s:cpu_id %d index %d way %d"
817*10784Ssinanallur.balasubramanian@sun.com 		    " successfully unretired. Will"
818*10784Ssinanallur.balasubramanian@sun.com 		    " destroy this Lxcache now.\n",
819*10784Ssinanallur.balasubramanian@sun.com 		    fltnm, cpu->cpu_cpuid, suspect_Lxcache->Lxcache_index,
820*10784Ssinanallur.balasubramanian@sun.com 		    suspect_Lxcache->Lxcache_way);
821*10784Ssinanallur.balasubramanian@sun.com 		cmd_Lxcache_destroy(hdl, cpu, suspect_Lxcache);
822*10784Ssinanallur.balasubramanian@sun.com 	} else {
823*10784Ssinanallur.balasubramanian@sun.com 		/*
824*10784Ssinanallur.balasubramanian@sun.com 		 * destroy the anonymous_Lxcache
825*10784Ssinanallur.balasubramanian@sun.com 		 */
826*10784Ssinanallur.balasubramanian@sun.com 		cmd_Lxcache_destroy(hdl, cpu, anonymous_Lxcache);
827*10784Ssinanallur.balasubramanian@sun.com 		return (CMD_EVD_BAD);
828*10784Ssinanallur.balasubramanian@sun.com 	}
829*10784Ssinanallur.balasubramanian@sun.com 	/*
830*10784Ssinanallur.balasubramanian@sun.com 	 * retire the next retirable way
831*10784Ssinanallur.balasubramanian@sun.com 	 */
832*10784Ssinanallur.balasubramanian@sun.com 	next_retirable_way = cmd_Lxcache_get_next_retirable_way(cpu,
833*10784Ssinanallur.balasubramanian@sun.com 	    retired_index,
834*10784Ssinanallur.balasubramanian@sun.com 	    retired_type, retired_way);
835*10784Ssinanallur.balasubramanian@sun.com 	if (next_retirable_way == -1) {
836*10784Ssinanallur.balasubramanian@sun.com 		/*
837*10784Ssinanallur.balasubramanian@sun.com 		 * There is no retirable way that is next to the
838*10784Ssinanallur.balasubramanian@sun.com 		 * one we just retired. We need to offline the
839*10784Ssinanallur.balasubramanian@sun.com 		 * CPU since we are unable to determine which
840*10784Ssinanallur.balasubramanian@sun.com 		 * way is reporting the errors.
841*10784Ssinanallur.balasubramanian@sun.com 		 */
842*10784Ssinanallur.balasubramanian@sun.com 		fmd_hdl_debug(hdl,
843*10784Ssinanallur.balasubramanian@sun.com 		    "\n%s:cpu_id %d we are unable to determine"
844*10784Ssinanallur.balasubramanian@sun.com 		    " which way is faulty at cache index %d."
845*10784Ssinanallur.balasubramanian@sun.com 		    " It is likely that we have a leaky bit"
846*10784Ssinanallur.balasubramanian@sun.com 		    " that gets corrected.\n Will retire"
847*10784Ssinanallur.balasubramanian@sun.com 		    " the CPU.\nRecommended-Action: Service"
848*10784Ssinanallur.balasubramanian@sun.com 		    " action required\n",
849*10784Ssinanallur.balasubramanian@sun.com 		    fltnm, cpu->cpu_cpuid, retired_index);
850*10784Ssinanallur.balasubramanian@sun.com 		/*
851*10784Ssinanallur.balasubramanian@sun.com 		 * destroy the anonymous_Lxcache
852*10784Ssinanallur.balasubramanian@sun.com 		 */
853*10784Ssinanallur.balasubramanian@sun.com 		cmd_Lxcache_destroy(hdl, cpu, anonymous_Lxcache);
854*10784Ssinanallur.balasubramanian@sun.com 		cmd_fault_the_cpu(hdl, cpu, retired_type, fltnm);
855*10784Ssinanallur.balasubramanian@sun.com 		return (CMD_EVD_OK);
856*10784Ssinanallur.balasubramanian@sun.com 	} else {
857*10784Ssinanallur.balasubramanian@sun.com 		fmd_hdl_debug(hdl,
858*10784Ssinanallur.balasubramanian@sun.com 		    "\n%s:cpu_id %d found way %d at index %d to"
859*10784Ssinanallur.balasubramanian@sun.com 		    " retire as SUSPECT_0/SUSPECT_DATA\n",
860*10784Ssinanallur.balasubramanian@sun.com 		    fltnm, cpu->cpu_cpuid, next_retirable_way, retired_index);
861*10784Ssinanallur.balasubramanian@sun.com 		/*
862*10784Ssinanallur.balasubramanian@sun.com 		 * We need to create a new Lxcache struture.
863*10784Ssinanallur.balasubramanian@sun.com 		 * The existing Lxcache is for anonymous way.
864*10784Ssinanallur.balasubramanian@sun.com 		 */
865*10784Ssinanallur.balasubramanian@sun.com 		anonymous_Lxcache->Lxcache_way = next_retirable_way;
866*10784Ssinanallur.balasubramanian@sun.com 		new_Lxcache = cmd_create_and_destroy_Lxcache(hdl,
867*10784Ssinanallur.balasubramanian@sun.com 		    cpu, anonymous_Lxcache);
868*10784Ssinanallur.balasubramanian@sun.com 		if ((new_Lxcache == NULL) ||
869*10784Ssinanallur.balasubramanian@sun.com 		    (new_Lxcache->Lxcache_case.cc_cp == NULL)) {
870*10784Ssinanallur.balasubramanian@sun.com 			return (CMD_EVD_BAD);
871*10784Ssinanallur.balasubramanian@sun.com 		}
872*10784Ssinanallur.balasubramanian@sun.com 		if (IS_TAG(new_Lxcache->Lxcache_type))
873*10784Ssinanallur.balasubramanian@sun.com 			reason = CMD_LXSUSPECT_0_TAG;
874*10784Ssinanallur.balasubramanian@sun.com 		else
875*10784Ssinanallur.balasubramanian@sun.com 			reason = CMD_LXSUSPECT_DATA;
876*10784Ssinanallur.balasubramanian@sun.com 		return (cmd_Lxcache_retire_as_reason(hdl, cpu, new_Lxcache,
877*10784Ssinanallur.balasubramanian@sun.com 		    fltnm, reason));
878*10784Ssinanallur.balasubramanian@sun.com 	}
879*10784Ssinanallur.balasubramanian@sun.com }
880*10784Ssinanallur.balasubramanian@sun.com 
881*10784Ssinanallur.balasubramanian@sun.com void
find_and_destroy_anonymous_Lxcache(fmd_hdl_t * hdl,cmd_cpu_t * cpu,cmd_ptrsubtype_t pstype,int32_t index)882*10784Ssinanallur.balasubramanian@sun.com find_and_destroy_anonymous_Lxcache(fmd_hdl_t *hdl, cmd_cpu_t *cpu,
883*10784Ssinanallur.balasubramanian@sun.com     cmd_ptrsubtype_t pstype, int32_t index)
884*10784Ssinanallur.balasubramanian@sun.com {
885*10784Ssinanallur.balasubramanian@sun.com 	cmd_Lxcache_t *anonymous_Lxcache;
886*10784Ssinanallur.balasubramanian@sun.com 	const char	*fltnm;
887*10784Ssinanallur.balasubramanian@sun.com 
888*10784Ssinanallur.balasubramanian@sun.com 	fltnm = cmd_type_to_str(pstype);
889*10784Ssinanallur.balasubramanian@sun.com 	anonymous_Lxcache =
890*10784Ssinanallur.balasubramanian@sun.com 	    cmd_Lxcache_lookup_by_type_index_way_bit(cpu,
891*10784Ssinanallur.balasubramanian@sun.com 	    pstype, index, -1, -1);
892*10784Ssinanallur.balasubramanian@sun.com 	if (anonymous_Lxcache != NULL) {
893*10784Ssinanallur.balasubramanian@sun.com 		fmd_hdl_debug(hdl,
894*10784Ssinanallur.balasubramanian@sun.com 		    "\n%s:cpu_id = %d index = %d We are destroying the"
895*10784Ssinanallur.balasubramanian@sun.com 		    " anonymous Lxcache now.\n",
896*10784Ssinanallur.balasubramanian@sun.com 		    fltnm, cpu->cpu_cpuid, index);
897*10784Ssinanallur.balasubramanian@sun.com 		/*
898*10784Ssinanallur.balasubramanian@sun.com 		 * Free the resources allocated to handle
899*10784Ssinanallur.balasubramanian@sun.com 		 * recheck_of_tags. Delete the Lxcache.
900*10784Ssinanallur.balasubramanian@sun.com 		 */
901*10784Ssinanallur.balasubramanian@sun.com 		cmd_Lxcache_destroy(hdl, cpu,
902*10784Ssinanallur.balasubramanian@sun.com 		    anonymous_Lxcache);
903*10784Ssinanallur.balasubramanian@sun.com 	}
904*10784Ssinanallur.balasubramanian@sun.com }
905*10784Ssinanallur.balasubramanian@sun.com 
906*10784Ssinanallur.balasubramanian@sun.com void
cmd_Lxcache_anonymous_tag_error_timeout(fmd_hdl_t * hdl,id_t id)907*10784Ssinanallur.balasubramanian@sun.com cmd_Lxcache_anonymous_tag_error_timeout(fmd_hdl_t *hdl, id_t id)
908*10784Ssinanallur.balasubramanian@sun.com {
909*10784Ssinanallur.balasubramanian@sun.com 	cmd_Lxcache_t	*Lxcache;
910*10784Ssinanallur.balasubramanian@sun.com 	const char	*class;
911*10784Ssinanallur.balasubramanian@sun.com 
912*10784Ssinanallur.balasubramanian@sun.com 
913*10784Ssinanallur.balasubramanian@sun.com 	/*
914*10784Ssinanallur.balasubramanian@sun.com 	 * We search thru the entire Lxcache structures to find
915*10784Ssinanallur.balasubramanian@sun.com 	 * a matching id.
916*10784Ssinanallur.balasubramanian@sun.com 	 */
917*10784Ssinanallur.balasubramanian@sun.com 	Lxcache = cmd_Lxcache_lookup_by_timeout_id(id);
918*10784Ssinanallur.balasubramanian@sun.com 	if (Lxcache == NULL) {
919*10784Ssinanallur.balasubramanian@sun.com 		fmd_hdl_debug(hdl,
920*10784Ssinanallur.balasubramanian@sun.com 		    "Could not find Lxcache for timeout_id 0x%x\n", id);
921*10784Ssinanallur.balasubramanian@sun.com 		return;
922*10784Ssinanallur.balasubramanian@sun.com 	}
923*10784Ssinanallur.balasubramanian@sun.com 	fmd_hdl_debug(hdl,
924*10784Ssinanallur.balasubramanian@sun.com 	    "\n%s:anonymous_tag_error_timeout:index = %d\n",
925*10784Ssinanallur.balasubramanian@sun.com 	    cmd_type_to_str(Lxcache->Lxcache_type),
926*10784Ssinanallur.balasubramanian@sun.com 	    Lxcache->Lxcache_index);
927*10784Ssinanallur.balasubramanian@sun.com 	/*
928*10784Ssinanallur.balasubramanian@sun.com 	 * Set timeout_id to -1 to indicate that we have processed the
929*10784Ssinanallur.balasubramanian@sun.com 	 * timeout.
930*10784Ssinanallur.balasubramanian@sun.com 	 */
931*10784Ssinanallur.balasubramanian@sun.com 	Lxcache->Lxcache_timeout_id = -1;
932*10784Ssinanallur.balasubramanian@sun.com 	switch (Lxcache->Lxcache_type) {
933*10784Ssinanallur.balasubramanian@sun.com 		case CMD_PTR_CPU_L2TAG:
934*10784Ssinanallur.balasubramanian@sun.com 			class = "ereport.cpu.ultraSPARC-IVplus.thce";
935*10784Ssinanallur.balasubramanian@sun.com 			(void) cmd_txce(hdl, Lxcache->Lxcache_ep,
936*10784Ssinanallur.balasubramanian@sun.com 			    Lxcache->Lxcache_nvl,
937*10784Ssinanallur.balasubramanian@sun.com 			    class, Lxcache->Lxcache_clcode);
938*10784Ssinanallur.balasubramanian@sun.com 			break;
939*10784Ssinanallur.balasubramanian@sun.com 		case CMD_PTR_CPU_L3TAG:
940*10784Ssinanallur.balasubramanian@sun.com 			class = "ereport.cpu.ultraSPARC-IVplus.l3-thce";
941*10784Ssinanallur.balasubramanian@sun.com 			(void) cmd_l3_thce(hdl, Lxcache->Lxcache_ep,
942*10784Ssinanallur.balasubramanian@sun.com 			    Lxcache->Lxcache_nvl,
943*10784Ssinanallur.balasubramanian@sun.com 			    class, Lxcache->Lxcache_clcode);
944*10784Ssinanallur.balasubramanian@sun.com 			break;
945*10784Ssinanallur.balasubramanian@sun.com 		default:
946*10784Ssinanallur.balasubramanian@sun.com 			fmd_hdl_debug(hdl,
947*10784Ssinanallur.balasubramanian@sun.com 			    "Unexpected pstype 0x%x found in"
948*10784Ssinanallur.balasubramanian@sun.com 			    " anonymous_tag_error_timeout: index = %d\n",
949*10784Ssinanallur.balasubramanian@sun.com 			    Lxcache->Lxcache_type,
950*10784Ssinanallur.balasubramanian@sun.com 			    Lxcache->Lxcache_index);
951*10784Ssinanallur.balasubramanian@sun.com 			return;
952*10784Ssinanallur.balasubramanian@sun.com 	}
9536330Sjc25722 }
9546330Sjc25722 
9556330Sjc25722 cmd_evdisp_t
cmd_us4plus_tag_err(fmd_hdl_t * hdl,fmd_event_t * ep,nvlist_t * nvl,cmd_cpu_t * cpu,cmd_ptrsubtype_t pstype,const char * serdn,const char * serdt,const char * fltnm,cmd_errcl_t clcode)9566330Sjc25722 cmd_us4plus_tag_err(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl,
957*10784Ssinanallur.balasubramanian@sun.com 		cmd_cpu_t *cpu, cmd_ptrsubtype_t pstype,
958*10784Ssinanallur.balasubramanian@sun.com 		const char *serdn, const char *serdt,
959*10784Ssinanallur.balasubramanian@sun.com 		const char *fltnm, cmd_errcl_t clcode)
9606330Sjc25722 {
9616330Sjc25722 	uint64_t	tag_afar;
962*10784Ssinanallur.balasubramanian@sun.com 	int32_t	index;
963*10784Ssinanallur.balasubramanian@sun.com 	int8_t		way;
964*10784Ssinanallur.balasubramanian@sun.com 	int16_t		tag_bit, bit, sticky_bit;
965*10784Ssinanallur.balasubramanian@sun.com 	cmd_Lxcache_t	*Lxcache, *suspect_Lxcache, *retired_Lxcache;
966*10784Ssinanallur.balasubramanian@sun.com 	cmd_Lxcache_t	*anonymous_Lxcache;
9676330Sjc25722 	uint64_t	tag_synd;
9686330Sjc25722 	uint64_t	tag_data[PN_CACHE_NWAYS];
969*10784Ssinanallur.balasubramanian@sun.com 	uint8_t		state;
9706330Sjc25722 	int		ways_retired, ret;
971*10784Ssinanallur.balasubramanian@sun.com 	int		retries_for_ecc_match;
972*10784Ssinanallur.balasubramanian@sun.com 	int32_t		recheck_of_tags;
973*10784Ssinanallur.balasubramanian@sun.com 	int		way_already_retired = 0;
9746330Sjc25722 
9756330Sjc25722 	/*
9766330Sjc25722 	 * We now extract physical tags and states
9776330Sjc25722 	 * and also look for matching ECC on all 4 ways.
9786330Sjc25722 	 */
9796330Sjc25722 	ret = extract_data_from_ereport_payload(hdl, nvl, cpu, pstype,
9806330Sjc25722 	    &tag_afar, tag_data, fltnm);
9816330Sjc25722 	if (ret != 0)
9826330Sjc25722 		return (ret);
9836330Sjc25722 	index = get_index(pstype, tag_afar);
9846330Sjc25722 	retries_for_ecc_match = 0;
9856330Sjc25722 	while (matching_ecc(tag_data) != 0) {
9866330Sjc25722 		if (retries_for_ecc_match >= MAX_RETRIES_FOR_ECC_MATCH)
9876330Sjc25722 			return (CMD_EVD_BAD);
9886330Sjc25722 		print_ecc(hdl, cpu, fltnm, tag_data);
9896330Sjc25722 		fmd_hdl_debug(hdl,
990*10784Ssinanallur.balasubramanian@sun.com 		    "\n%s:cpu_id = %d index = %d ECCs don't match.\n"
9916330Sjc25722 		    "Reading tag info again.\n",
9926330Sjc25722 		    fltnm, cpu->cpu_cpuid, index);
9936330Sjc25722 		(void) get_tagdata(cpu, pstype, index, tag_data);
9946330Sjc25722 		retries_for_ecc_match++;
9956330Sjc25722 	}
996*10784Ssinanallur.balasubramanian@sun.com 	ways_retired = get_retired_ways(tag_data);
997*10784Ssinanallur.balasubramanian@sun.com 	fmd_hdl_debug(hdl,
998*10784Ssinanallur.balasubramanian@sun.com 	    "\n%s:cpu_id %d: found %d ways retired at the index %d\n",
999*10784Ssinanallur.balasubramanian@sun.com 	    fltnm, cpu->cpu_cpuid, ways_retired, index);
10006330Sjc25722 	tag_synd = compute_syndrome(tag_data, pstype);
1001*10784Ssinanallur.balasubramanian@sun.com 	ret = nvlist_lookup_int32(nvl, FM_EREPORT_RECHECK_OF_TAGS,
1002*10784Ssinanallur.balasubramanian@sun.com 	    &recheck_of_tags);
1003*10784Ssinanallur.balasubramanian@sun.com 	if (ret != CMD_EVD_OK) {
1004*10784Ssinanallur.balasubramanian@sun.com 		fmd_hdl_debug(hdl,
1005*10784Ssinanallur.balasubramanian@sun.com 		    "ret value = %d for nvlist_lookup of recheck_of_tags\n",
1006*10784Ssinanallur.balasubramanian@sun.com 		    ret);
1007*10784Ssinanallur.balasubramanian@sun.com 		recheck_of_tags = 0;
1008*10784Ssinanallur.balasubramanian@sun.com 	}
10096330Sjc25722 	if (tag_synd == 0) {
10106330Sjc25722 		/*
10116330Sjc25722 		 * The bit has been corrected by writeback, we will
1012*10784Ssinanallur.balasubramanian@sun.com 		 * first check if we are processing the re-check of tags
1013*10784Ssinanallur.balasubramanian@sun.com 		 * that we scheduled thru the timeout call.
1014*10784Ssinanallur.balasubramanian@sun.com 		 * if so we will exit if we reached the max retries.
1015*10784Ssinanallur.balasubramanian@sun.com 		 * Else we start a timeout and exit.
1016*10784Ssinanallur.balasubramanian@sun.com 		 * We will create a Lxcache structure for this index with way
1017*10784Ssinanallur.balasubramanian@sun.com 		 * as -1 and bit as -1. We will also keep a count of
1018*10784Ssinanallur.balasubramanian@sun.com 		 * attempts we made to check the tag data at this index.
1019*10784Ssinanallur.balasubramanian@sun.com 		 *
10206330Sjc25722 		 */
1021*10784Ssinanallur.balasubramanian@sun.com 		way = -1;
1022*10784Ssinanallur.balasubramanian@sun.com 		bit = -1;
1023*10784Ssinanallur.balasubramanian@sun.com 		Lxcache = cmd_Lxcache_lookup_by_type_index_way_bit(cpu, pstype,
1024*10784Ssinanallur.balasubramanian@sun.com 		    index, way, bit);
1025*10784Ssinanallur.balasubramanian@sun.com 		if (recheck_of_tags) {
1026*10784Ssinanallur.balasubramanian@sun.com 			/*
1027*10784Ssinanallur.balasubramanian@sun.com 			 * We are processing the re-read of tags scheduled by
1028*10784Ssinanallur.balasubramanian@sun.com 			 * timeout. Exit if retry limit has been
1029*10784Ssinanallur.balasubramanian@sun.com 			 * reached. Else start another timeout.
1030*10784Ssinanallur.balasubramanian@sun.com 			 */
1031*10784Ssinanallur.balasubramanian@sun.com 			if (Lxcache == NULL) {
1032*10784Ssinanallur.balasubramanian@sun.com 				/*
1033*10784Ssinanallur.balasubramanian@sun.com 				 * This shouldn't happen.
1034*10784Ssinanallur.balasubramanian@sun.com 				 */
1035*10784Ssinanallur.balasubramanian@sun.com 				fmd_hdl_debug(hdl,
1036*10784Ssinanallur.balasubramanian@sun.com 				    "\n%s: cpu_id = %d failed to lookup"
1037*10784Ssinanallur.balasubramanian@sun.com 				    " index = %d way %d bit %d\n",
1038*10784Ssinanallur.balasubramanian@sun.com 				    fltnm, cpu->cpu_cpuid, index, way, bit);
1039*10784Ssinanallur.balasubramanian@sun.com 				return (CMD_EVD_BAD);
1040*10784Ssinanallur.balasubramanian@sun.com 			}
1041*10784Ssinanallur.balasubramanian@sun.com 			fmd_hdl_debug(hdl,
1042*10784Ssinanallur.balasubramanian@sun.com 			    "\n%s: cpu_id = %d index = %d syndrome"
1043*10784Ssinanallur.balasubramanian@sun.com 			    " computed is 0 in attempt #%d.\n",
1044*10784Ssinanallur.balasubramanian@sun.com 			    fltnm, cpu->cpu_cpuid, index,
1045*10784Ssinanallur.balasubramanian@sun.com 			    Lxcache->Lxcache_retry_count);
1046*10784Ssinanallur.balasubramanian@sun.com 			if (Lxcache->Lxcache_retry_count >=
1047*10784Ssinanallur.balasubramanian@sun.com 			    RETRIES_TO_BE_DONE_WHEN_SYND_IS_ZERO) {
1048*10784Ssinanallur.balasubramanian@sun.com 				/*
1049*10784Ssinanallur.balasubramanian@sun.com 				 * We free only the nvl list here.
1050*10784Ssinanallur.balasubramanian@sun.com 				 * anonymous SERD engine will be freed
1051*10784Ssinanallur.balasubramanian@sun.com 				 * when the Lxcache gets destroyed.
1052*10784Ssinanallur.balasubramanian@sun.com 				 * We need the anonymous SERD engine still
1053*10784Ssinanallur.balasubramanian@sun.com 				 * because it has the event ep.
1054*10784Ssinanallur.balasubramanian@sun.com 				 * reset or destroy of SERD engine frees the
1055*10784Ssinanallur.balasubramanian@sun.com 				 * event ep.
1056*10784Ssinanallur.balasubramanian@sun.com 				 */
1057*10784Ssinanallur.balasubramanian@sun.com 				if (Lxcache->Lxcache_nvl != NULL) {
1058*10784Ssinanallur.balasubramanian@sun.com 					nvlist_free(Lxcache->Lxcache_nvl);
1059*10784Ssinanallur.balasubramanian@sun.com 					Lxcache->Lxcache_nvl = NULL;
1060*10784Ssinanallur.balasubramanian@sun.com 				}
1061*10784Ssinanallur.balasubramanian@sun.com 				fmd_hdl_debug(hdl,
1062*10784Ssinanallur.balasubramanian@sun.com 		    "\n%s:cpu_id %d Max retry count reached. Giving up.\n",
1063*10784Ssinanallur.balasubramanian@sun.com 				    fltnm, cpu->cpu_cpuid);
1064*10784Ssinanallur.balasubramanian@sun.com 				Lxcache->Lxcache_timeout_id = -1;
1065*10784Ssinanallur.balasubramanian@sun.com 				Lxcache->Lxcache_retry_count = 0;
1066*10784Ssinanallur.balasubramanian@sun.com 				goto process_after_finding_way_bit;
1067*10784Ssinanallur.balasubramanian@sun.com 			} else {
1068*10784Ssinanallur.balasubramanian@sun.com 				Lxcache->Lxcache_retry_count++;
1069*10784Ssinanallur.balasubramanian@sun.com 				Lxcache->Lxcache_timeout_id =
1070*10784Ssinanallur.balasubramanian@sun.com 				    fmd_timer_install(hdl,
1071*10784Ssinanallur.balasubramanian@sun.com 				    (void *)CMD_TIMERTYPE_ANONYMOUS_TAG_ERROR,
1072*10784Ssinanallur.balasubramanian@sun.com 				    NULL,
1073*10784Ssinanallur.balasubramanian@sun.com 				    (cmd_Lxcache_recheck_tags_delay[
1074*10784Ssinanallur.balasubramanian@sun.com 				    Lxcache->Lxcache_retry_count] * NANOSEC));
1075*10784Ssinanallur.balasubramanian@sun.com 				return (CMD_EVD_OK);
1076*10784Ssinanallur.balasubramanian@sun.com 			}
1077*10784Ssinanallur.balasubramanian@sun.com 		}
1078*10784Ssinanallur.balasubramanian@sun.com 		/*
1079*10784Ssinanallur.balasubramanian@sun.com 		 * Check if we already have a Lxcache structure
1080*10784Ssinanallur.balasubramanian@sun.com 		 * with anonymous way and bit created.
1081*10784Ssinanallur.balasubramanian@sun.com 		 */
1082*10784Ssinanallur.balasubramanian@sun.com 		if (Lxcache == NULL) {
1083*10784Ssinanallur.balasubramanian@sun.com 			Lxcache = cmd_Lxcache_create(hdl, 0, cpu,
1084*10784Ssinanallur.balasubramanian@sun.com 			    cpu->cpu_asru_nvl, pstype, index, way, bit);
1085*10784Ssinanallur.balasubramanian@sun.com 			if (Lxcache == NULL) {
1086*10784Ssinanallur.balasubramanian@sun.com 				fmd_hdl_debug(hdl,
1087*10784Ssinanallur.balasubramanian@sun.com 				    "\n%s:cpu_id %d Failed to create Lxcache"
1088*10784Ssinanallur.balasubramanian@sun.com 				    " for index=%d\n",
1089*10784Ssinanallur.balasubramanian@sun.com 				    fltnm, cpu->cpu_cpuid, index);
1090*10784Ssinanallur.balasubramanian@sun.com 				return (CMD_EVD_BAD);
1091*10784Ssinanallur.balasubramanian@sun.com 			}
1092*10784Ssinanallur.balasubramanian@sun.com 		}
1093*10784Ssinanallur.balasubramanian@sun.com 		if (Lxcache->Lxcache_timeout_id != -1) {
1094*10784Ssinanallur.balasubramanian@sun.com 			/*
1095*10784Ssinanallur.balasubramanian@sun.com 			 * We have another syndrome = 0 condition while we are
1096*10784Ssinanallur.balasubramanian@sun.com 			 * still in the process of retrying for the previous
1097*10784Ssinanallur.balasubramanian@sun.com 			 * condition.
1098*10784Ssinanallur.balasubramanian@sun.com 			 */
1099*10784Ssinanallur.balasubramanian@sun.com 			fmd_hdl_debug(hdl,
1100*10784Ssinanallur.balasubramanian@sun.com 			    "\n%s: cpu_id = %d index = %d We have another"
1101*10784Ssinanallur.balasubramanian@sun.com 			    " syndrome = 0 condition while we have already"
1102*10784Ssinanallur.balasubramanian@sun.com 			    " scheduled a timeout. We will ignore this"
1103*10784Ssinanallur.balasubramanian@sun.com 			    " event.\n",
1104*10784Ssinanallur.balasubramanian@sun.com 			    fltnm, cpu->cpu_cpuid, index);
1105*10784Ssinanallur.balasubramanian@sun.com 			return (CMD_EVD_OK);
1106*10784Ssinanallur.balasubramanian@sun.com 		}
11076330Sjc25722 		fmd_hdl_debug(hdl,
1108*10784Ssinanallur.balasubramanian@sun.com 		    "\n%s: cpu_id = %d index = %d syndrome computed is 0."
11096330Sjc25722 		    "Looks like the bit got corrected."
11106330Sjc25722 		    " Will check later to see if it is OK.\n",
11116330Sjc25722 		    fltnm, cpu->cpu_cpuid, index);
1112*10784Ssinanallur.balasubramanian@sun.com 		/*
1113*10784Ssinanallur.balasubramanian@sun.com 		 * We need to store the following arguments passed to
1114*10784Ssinanallur.balasubramanian@sun.com 		 * this function(tag_error_handler) so that we can
1115*10784Ssinanallur.balasubramanian@sun.com 		 * invoke this function from timeout routine.
1116*10784Ssinanallur.balasubramanian@sun.com 		 *
1117*10784Ssinanallur.balasubramanian@sun.com 		 * nvl, ep, clcode
1118*10784Ssinanallur.balasubramanian@sun.com 		 */
1119*10784Ssinanallur.balasubramanian@sun.com 		if (Lxcache->Lxcache_nvl == NULL) {
1120*10784Ssinanallur.balasubramanian@sun.com 			if (nvlist_dup(nvl, &Lxcache->Lxcache_nvl, 0) != 0) {
1121*10784Ssinanallur.balasubramanian@sun.com 				fmd_hdl_debug(hdl,
1122*10784Ssinanallur.balasubramanian@sun.com 				    "\n%s:cpu_id %d Failed to duplicate nvl"
1123*10784Ssinanallur.balasubramanian@sun.com 				    " for index=%d\n",
1124*10784Ssinanallur.balasubramanian@sun.com 				    fltnm, cpu->cpu_cpuid, index);
1125*10784Ssinanallur.balasubramanian@sun.com 				return (CMD_EVD_BAD);
1126*10784Ssinanallur.balasubramanian@sun.com 			}
1127*10784Ssinanallur.balasubramanian@sun.com 			if (nvlist_add_int32(Lxcache->Lxcache_nvl,
1128*10784Ssinanallur.balasubramanian@sun.com 			    FM_EREPORT_RECHECK_OF_TAGS, 1) != 0) {
1129*10784Ssinanallur.balasubramanian@sun.com 				fmd_hdl_debug(hdl,
1130*10784Ssinanallur.balasubramanian@sun.com 				    "\n%s:cpu_id %d Failed to add"
1131*10784Ssinanallur.balasubramanian@sun.com 				    " RECHECK_OF_TAGS in nvl for index=%d\n",
1132*10784Ssinanallur.balasubramanian@sun.com 				    fltnm, cpu->cpu_cpuid, index);
1133*10784Ssinanallur.balasubramanian@sun.com 				return (CMD_EVD_BAD);
1134*10784Ssinanallur.balasubramanian@sun.com 			}
1135*10784Ssinanallur.balasubramanian@sun.com 		}
11366330Sjc25722 		/*
1137*10784Ssinanallur.balasubramanian@sun.com 		 * We are called with CMP_CPU_LEVEL_CORE masked out
1138*10784Ssinanallur.balasubramanian@sun.com 		 * from cmd_txce(), cmd_l3_thce() routines.
1139*10784Ssinanallur.balasubramanian@sun.com 		 * We need to set CMD_CPU_LEVEL_CORE because we want to handle
1140*10784Ssinanallur.balasubramanian@sun.com 		 * both the cores on the Chip as one single cpu_id.
11416330Sjc25722 		 */
1142*10784Ssinanallur.balasubramanian@sun.com 		Lxcache->Lxcache_clcode = (clcode | CMD_CPU_LEVEL_CORE);
1143*10784Ssinanallur.balasubramanian@sun.com 		if (Lxcache->Lxcache_ep == NULL) {
1144*10784Ssinanallur.balasubramanian@sun.com 			Lxcache->Lxcache_ep = ep;
1145*10784Ssinanallur.balasubramanian@sun.com 			/*
1146*10784Ssinanallur.balasubramanian@sun.com 			 * we need to preserve the event ep so that it does
1147*10784Ssinanallur.balasubramanian@sun.com 			 * not get destroyed when we return from this call.
1148*10784Ssinanallur.balasubramanian@sun.com 			 * We do that by adding the event ep to the SERD engine.
1149*10784Ssinanallur.balasubramanian@sun.com 			 * The SERD engine we create is different from the one
1150*10784Ssinanallur.balasubramanian@sun.com 			 * we create when we handle the actual event at label
1151*10784Ssinanallur.balasubramanian@sun.com 			 * process_after_finding_way_bit.
1152*10784Ssinanallur.balasubramanian@sun.com 			 */
1153*10784Ssinanallur.balasubramanian@sun.com 			Lxcache->Lxcache_serdnm =
1154*10784Ssinanallur.balasubramanian@sun.com 			    cmd_Lxcache_anonymous_serdnm_create(hdl,
1155*10784Ssinanallur.balasubramanian@sun.com 			    cpu->cpu_cpuid, pstype, index,
1156*10784Ssinanallur.balasubramanian@sun.com 			    way, bit);
1157*10784Ssinanallur.balasubramanian@sun.com 			if (!fmd_serd_exists(hdl, Lxcache->Lxcache_serdnm)) {
1158*10784Ssinanallur.balasubramanian@sun.com 				fmd_serd_create(hdl, Lxcache->Lxcache_serdnm,
1159*10784Ssinanallur.balasubramanian@sun.com 				    fmd_prop_get_int32(hdl, serdn),
1160*10784Ssinanallur.balasubramanian@sun.com 				    fmd_prop_get_int64(hdl, serdt));
1161*10784Ssinanallur.balasubramanian@sun.com 				fmd_hdl_debug(hdl,
1162*10784Ssinanallur.balasubramanian@sun.com 				    "\n%s: cpu_id %d: created a SERD engine"
1163*10784Ssinanallur.balasubramanian@sun.com 				    " %s\n",
1164*10784Ssinanallur.balasubramanian@sun.com 				    fltnm, cpu->cpu_cpuid,
1165*10784Ssinanallur.balasubramanian@sun.com 				    Lxcache->Lxcache_serdnm);
1166*10784Ssinanallur.balasubramanian@sun.com 			}
1167*10784Ssinanallur.balasubramanian@sun.com 			(void) fmd_serd_record(hdl,
1168*10784Ssinanallur.balasubramanian@sun.com 			    Lxcache->Lxcache_serdnm,
1169*10784Ssinanallur.balasubramanian@sun.com 			    ep);
1170*10784Ssinanallur.balasubramanian@sun.com 		}
1171*10784Ssinanallur.balasubramanian@sun.com 		Lxcache->Lxcache_retry_count++;
1172*10784Ssinanallur.balasubramanian@sun.com 		Lxcache->Lxcache_timeout_id =
1173*10784Ssinanallur.balasubramanian@sun.com 		    fmd_timer_install(hdl,
1174*10784Ssinanallur.balasubramanian@sun.com 		    (void *)CMD_TIMERTYPE_ANONYMOUS_TAG_ERROR, NULL,
1175*10784Ssinanallur.balasubramanian@sun.com 		    (cmd_Lxcache_recheck_tags_delay[
1176*10784Ssinanallur.balasubramanian@sun.com 		    Lxcache->Lxcache_retry_count] * NANOSEC));
1177*10784Ssinanallur.balasubramanian@sun.com 		return (CMD_EVD_OK);
1178*10784Ssinanallur.balasubramanian@sun.com 
11796330Sjc25722 	} else {
1180*10784Ssinanallur.balasubramanian@sun.com 		/*
1181*10784Ssinanallur.balasubramanian@sun.com 		 * tag_synd != 0
1182*10784Ssinanallur.balasubramanian@sun.com 		 * determine way and bit
1183*10784Ssinanallur.balasubramanian@sun.com 		 */
1184*10784Ssinanallur.balasubramanian@sun.com 		tag_bit = ecc_syndrome_tab[tag_synd & 0x1ff];
1185*10784Ssinanallur.balasubramanian@sun.com 		fmd_hdl_debug(hdl,
1186*10784Ssinanallur.balasubramanian@sun.com 		    "\n%s: cpu_id = %d index = %d tag_bit %03d is faulty.\n",
1187*10784Ssinanallur.balasubramanian@sun.com 		    fltnm, cpu->cpu_cpuid, index, tag_bit);
1188*10784Ssinanallur.balasubramanian@sun.com 		if ((tag_bit > C8)) {
1189*10784Ssinanallur.balasubramanian@sun.com 			fmd_hdl_debug(hdl, "%s: cpu_id = %d"
1190*10784Ssinanallur.balasubramanian@sun.com 			    " Unexpected MTAG or Multiple bit error detected\n",
1191*10784Ssinanallur.balasubramanian@sun.com 			    fltnm, cpu->cpu_cpuid);
1192*10784Ssinanallur.balasubramanian@sun.com 			find_and_destroy_anonymous_Lxcache(hdl, cpu, pstype,
1193*10784Ssinanallur.balasubramanian@sun.com 			    index);
11946330Sjc25722 			return (CMD_EVD_BAD);
11956330Sjc25722 		}
1196*10784Ssinanallur.balasubramanian@sun.com 		if ((tag_bit >= C0) && (tag_bit <= C8)) {
1197*10784Ssinanallur.balasubramanian@sun.com 			/*
1198*10784Ssinanallur.balasubramanian@sun.com 			 * ECC bit is corrupted.
1199*10784Ssinanallur.balasubramanian@sun.com 			 * Need to offline the CPU
1200*10784Ssinanallur.balasubramanian@sun.com 			 */
1201*10784Ssinanallur.balasubramanian@sun.com 			bit = (tag_bit - C0) + PN_LX_TAG_ECC_START_BIT;
1202*10784Ssinanallur.balasubramanian@sun.com 			way = 0;
1203*10784Ssinanallur.balasubramanian@sun.com 			fmd_hdl_debug(hdl,
1204*10784Ssinanallur.balasubramanian@sun.com 			    "\n%s: cpu_id = %d ECC bit is faulty.\n",
1205*10784Ssinanallur.balasubramanian@sun.com 			    fltnm, cpu->cpu_cpuid);
1206*10784Ssinanallur.balasubramanian@sun.com 		} else {
1207*10784Ssinanallur.balasubramanian@sun.com 			bit = tag_bit_to_way_bit(pstype, tag_bit);
1208*10784Ssinanallur.balasubramanian@sun.com 			way = bit_to_way(pstype, tag_bit);
1209*10784Ssinanallur.balasubramanian@sun.com 			if (way < 0) {
1210*10784Ssinanallur.balasubramanian@sun.com 				fmd_hdl_debug(hdl,
1211*10784Ssinanallur.balasubramanian@sun.com 				    "\n%s: cpu_id = %d %d bit indicted is a"
1212*10784Ssinanallur.balasubramanian@sun.com 				    " meta bit  !!\n",
1213*10784Ssinanallur.balasubramanian@sun.com 				    fltnm, cpu->cpu_cpuid, bit);
1214*10784Ssinanallur.balasubramanian@sun.com 				find_and_destroy_anonymous_Lxcache(hdl, cpu,
1215*10784Ssinanallur.balasubramanian@sun.com 				    pstype,
1216*10784Ssinanallur.balasubramanian@sun.com 				    index);
1217*10784Ssinanallur.balasubramanian@sun.com 				return (CMD_EVD_BAD);
1218*10784Ssinanallur.balasubramanian@sun.com 			}
1219*10784Ssinanallur.balasubramanian@sun.com 		}
1220*10784Ssinanallur.balasubramanian@sun.com 	}	/* end of tag_synd != 0 */
1221*10784Ssinanallur.balasubramanian@sun.com process_after_finding_way_bit:
1222*10784Ssinanallur.balasubramanian@sun.com 	if ((Lxcache = cmd_Lxcache_lookup_by_type_index_way_bit(cpu, pstype,
1223*10784Ssinanallur.balasubramanian@sun.com 	    index, way,
12246330Sjc25722 	    bit)) != NULL &&
12256330Sjc25722 	    Lxcache->Lxcache_case.cc_cp != NULL &&
12266330Sjc25722 	    fmd_case_solved(hdl, Lxcache->Lxcache_case.cc_cp)) {
12276330Sjc25722 		fmd_hdl_debug(hdl,
1228*10784Ssinanallur.balasubramanian@sun.com 		    "\n%s:cpu %d: the case for %s is already solved.\n",
12296330Sjc25722 		    fltnm, cpu->cpu_cpuid, Lxcache->Lxcache_bufname);
1230*10784Ssinanallur.balasubramanian@sun.com 		find_and_destroy_anonymous_Lxcache(hdl, cpu, pstype, index);
12316330Sjc25722 		return (CMD_EVD_REDUND);
12326330Sjc25722 	}
12336330Sjc25722 
12346330Sjc25722 	if (Lxcache == NULL)
12356330Sjc25722 		Lxcache = cmd_Lxcache_create(hdl, 0, cpu, cpu->cpu_asru_nvl,
12366330Sjc25722 		    pstype, index, way, bit);
1237*10784Ssinanallur.balasubramanian@sun.com 	if (Lxcache == NULL) {
12386330Sjc25722 		fmd_hdl_debug(hdl,
1239*10784Ssinanallur.balasubramanian@sun.com 		    "\n%s:cpu %d: Failed to create Lxcache for index %d",
1240*10784Ssinanallur.balasubramanian@sun.com 		    " way %d bit %d\n",
12416330Sjc25722 		    fltnm, cpu->cpu_cpuid, index, way, bit);
1242*10784Ssinanallur.balasubramanian@sun.com 		find_and_destroy_anonymous_Lxcache(hdl, cpu, pstype, index);
1243*10784Ssinanallur.balasubramanian@sun.com 		return (CMD_EVD_BAD);
1244*10784Ssinanallur.balasubramanian@sun.com 	}
1245*10784Ssinanallur.balasubramanian@sun.com 	if (cmd_create_case_for_Lxcache(hdl, cpu, Lxcache) == B_FALSE) {
1246*10784Ssinanallur.balasubramanian@sun.com 		find_and_destroy_anonymous_Lxcache(hdl, cpu, pstype, index);
1247*10784Ssinanallur.balasubramanian@sun.com 		return (CMD_EVD_BAD);
12486330Sjc25722 	}
12496330Sjc25722 	if (Lxcache->Lxcache_case.cc_serdnm == NULL) {
12506330Sjc25722 		Lxcache->Lxcache_case.cc_serdnm = cmd_Lxcache_serdnm_create(hdl,
12516330Sjc25722 		    cpu->cpu_cpuid, pstype, index,
12526330Sjc25722 		    way, bit);
1253*10784Ssinanallur.balasubramanian@sun.com 		if (!fmd_serd_exists(hdl, Lxcache->Lxcache_case.cc_serdnm)) {
1254*10784Ssinanallur.balasubramanian@sun.com 			fmd_serd_create(hdl, Lxcache->Lxcache_case.cc_serdnm,
1255*10784Ssinanallur.balasubramanian@sun.com 			    fmd_prop_get_int32(hdl, serdn),
1256*10784Ssinanallur.balasubramanian@sun.com 			    fmd_prop_get_int64(hdl, serdt));
1257*10784Ssinanallur.balasubramanian@sun.com 			fmd_hdl_debug(hdl,
1258*10784Ssinanallur.balasubramanian@sun.com 			    "\n%s: cpu_id %d: created a SERD engine %s\n",
1259*10784Ssinanallur.balasubramanian@sun.com 			    fltnm, cpu->cpu_cpuid,
1260*10784Ssinanallur.balasubramanian@sun.com 			    Lxcache->Lxcache_case.cc_serdnm);
1261*10784Ssinanallur.balasubramanian@sun.com 		}
12626330Sjc25722 	}
12636330Sjc25722 	fmd_hdl_debug(hdl,
1264*10784Ssinanallur.balasubramanian@sun.com 	    "\n%s:cpu_id %d: Checking if the SERD engine %s has fired.\n",
12656330Sjc25722 	    fltnm, cpu->cpu_cpuid, Lxcache->Lxcache_case.cc_serdnm);
12666330Sjc25722 
1267*10784Ssinanallur.balasubramanian@sun.com 	(void) fmd_serd_record(hdl, Lxcache->Lxcache_case.cc_serdnm, ep);
1268*10784Ssinanallur.balasubramanian@sun.com 	if (way >= 0) {
1269*10784Ssinanallur.balasubramanian@sun.com 		/*
1270*10784Ssinanallur.balasubramanian@sun.com 		 * Now that we have recorded the event ep we can do the
1271*10784Ssinanallur.balasubramanian@sun.com 		 * necessary cleanup of resources allocated for recheck of tags.
1272*10784Ssinanallur.balasubramanian@sun.com 		 */
1273*10784Ssinanallur.balasubramanian@sun.com 		find_and_destroy_anonymous_Lxcache(hdl, cpu, pstype, index);
1274*10784Ssinanallur.balasubramanian@sun.com 	}
1275*10784Ssinanallur.balasubramanian@sun.com 	if (fmd_serd_fired(hdl, Lxcache->Lxcache_case.cc_serdnm) ==
12766330Sjc25722 	    FMD_B_FALSE)
1277*10784Ssinanallur.balasubramanian@sun.com 		return (CMD_EVD_OK);
12786330Sjc25722 
1279*10784Ssinanallur.balasubramanian@sun.com 	fmd_hdl_debug(hdl, "\n%s: cpu_id = %d creating fault %s\n",
12806330Sjc25722 	    fltnm, cpu->cpu_cpuid, Lxcache->Lxcache_case.cc_serdnm);
12816330Sjc25722 	fmd_case_add_serd(hdl, Lxcache->Lxcache_case.cc_cp,
12826330Sjc25722 	    Lxcache->Lxcache_case.cc_serdnm);
12836330Sjc25722 	fmd_serd_reset(hdl, Lxcache->Lxcache_case.cc_serdnm);
1284*10784Ssinanallur.balasubramanian@sun.com 	if (way == -1) {
1285*10784Ssinanallur.balasubramanian@sun.com 		/*
1286*10784Ssinanallur.balasubramanian@sun.com 		 * The assignment below is to make the code easier to maintain.
1287*10784Ssinanallur.balasubramanian@sun.com 		 * We need to destroy the anonymous_Lxcache after we have
1288*10784Ssinanallur.balasubramanian@sun.com 		 * identifed a way to retire. If we cannot detrmine a way to
1289*10784Ssinanallur.balasubramanian@sun.com 		 * retire we will destrory the anonymous_Lxcache and fault the
1290*10784Ssinanallur.balasubramanian@sun.com 		 * cpu.
1291*10784Ssinanallur.balasubramanian@sun.com 		 */
1292*10784Ssinanallur.balasubramanian@sun.com 		anonymous_Lxcache = Lxcache;
1293*10784Ssinanallur.balasubramanian@sun.com 		/*
1294*10784Ssinanallur.balasubramanian@sun.com 		 * Anonymous TAG way retirement.
1295*10784Ssinanallur.balasubramanian@sun.com 		 * - if a way at this index has already been retired as
1296*10784Ssinanallur.balasubramanian@sun.com 		 *   "suspect-1", unretire that way, and retire the next
1297*10784Ssinanallur.balasubramanian@sun.com 		 *   unretired way as "suspect-0", using a pattern of all zeros
1298*10784Ssinanallur.balasubramanian@sun.com 		 *   for the PA bits.
1299*10784Ssinanallur.balasubramanian@sun.com 		 * - if a way at this index has already been retired as
1300*10784Ssinanallur.balasubramanian@sun.com 		 *   "suspect-0", re-retire that way as "suspect-1", using a
1301*10784Ssinanallur.balasubramanian@sun.com 		 *   pattern of all ones for the PA bits.
1302*10784Ssinanallur.balasubramanian@sun.com 		 * - if no ways have been retired as "suspect" for this index,
1303*10784Ssinanallur.balasubramanian@sun.com 		 *   retire the lowest unretired way as "suspect-0" for this
1304*10784Ssinanallur.balasubramanian@sun.com 		 *   bit, using a pattern of all zeros for the PA bits.
1305*10784Ssinanallur.balasubramanian@sun.com 		 * - if there is no next retirable way, fault the CPU.
1306*10784Ssinanallur.balasubramanian@sun.com 		 */
1307*10784Ssinanallur.balasubramanian@sun.com 		suspect_Lxcache = cmd_Lxcache_lookup_by_type_index_bit_reason(
1308*10784Ssinanallur.balasubramanian@sun.com 		    cpu, pstype, index, bit, CMD_LXSUSPECT_1_TAG);
1309*10784Ssinanallur.balasubramanian@sun.com 		anonymous_Lxcache->Lxcache_ep = ep;
1310*10784Ssinanallur.balasubramanian@sun.com 		if (suspect_Lxcache) {
1311*10784Ssinanallur.balasubramanian@sun.com 			ret = unretire_suspect_and_retire_next_retirable_way(
1312*10784Ssinanallur.balasubramanian@sun.com 			    hdl, cpu, suspect_Lxcache, anonymous_Lxcache,
1313*10784Ssinanallur.balasubramanian@sun.com 			    fltnm);
1314*10784Ssinanallur.balasubramanian@sun.com 			return (ret);
1315*10784Ssinanallur.balasubramanian@sun.com 		}	/* end SUSPECT_1_TAG */
1316*10784Ssinanallur.balasubramanian@sun.com 		suspect_Lxcache = cmd_Lxcache_lookup_by_type_index_bit_reason(
1317*10784Ssinanallur.balasubramanian@sun.com 		    cpu, pstype, index, bit, CMD_LXSUSPECT_0_TAG);
1318*10784Ssinanallur.balasubramanian@sun.com 		if (suspect_Lxcache) {
1319*10784Ssinanallur.balasubramanian@sun.com 			fmd_hdl_debug(hdl,
1320*10784Ssinanallur.balasubramanian@sun.com 			    "\n%s:cpu_id %d found index %d way %d"
1321*10784Ssinanallur.balasubramanian@sun.com 			    " bit %d retired as SUSPECT_0_TAG. Will"
1322*10784Ssinanallur.balasubramanian@sun.com 			    " re-retire this now as SUSPECT_1_TAG.\n",
1323*10784Ssinanallur.balasubramanian@sun.com 			    fltnm, cpu->cpu_cpuid, index,
1324*10784Ssinanallur.balasubramanian@sun.com 			    suspect_Lxcache->Lxcache_way, bit);
1325*10784Ssinanallur.balasubramanian@sun.com 			/*
1326*10784Ssinanallur.balasubramanian@sun.com 			 * destroy the anonymous_Lxcache
1327*10784Ssinanallur.balasubramanian@sun.com 			 */
1328*10784Ssinanallur.balasubramanian@sun.com 			cmd_Lxcache_destroy(hdl, cpu, anonymous_Lxcache);
1329*10784Ssinanallur.balasubramanian@sun.com 			suspect_Lxcache->Lxcache_ep = ep;
1330*10784Ssinanallur.balasubramanian@sun.com 			/*
1331*10784Ssinanallur.balasubramanian@sun.com 			 * We need to update the FM_FMRI_CPU_CACHE_BIT entry
1332*10784Ssinanallur.balasubramanian@sun.com 			 * in the Lxcache_asru_nvl. This entry was last updated
1333*10784Ssinanallur.balasubramanian@sun.com 			 * when the cacheline was retired as SUSPECT_0.
1334*10784Ssinanallur.balasubramanian@sun.com 			 * Therefore the MSB of FM_FMRI_CPU_CACHE_BIT entry
1335*10784Ssinanallur.balasubramanian@sun.com 			 * value will be reset. To retire cacheline as
1336*10784Ssinanallur.balasubramanian@sun.com 			 * SUSPECT_1 the MSB has to be set.
1337*10784Ssinanallur.balasubramanian@sun.com 			 */
1338*10784Ssinanallur.balasubramanian@sun.com 			errno = nvlist_add_uint16(
1339*10784Ssinanallur.balasubramanian@sun.com 			    suspect_Lxcache->Lxcache_asru_nvl,
1340*10784Ssinanallur.balasubramanian@sun.com 			    FM_FMRI_CPU_CACHE_BIT,
1341*10784Ssinanallur.balasubramanian@sun.com 			    suspect_Lxcache->Lxcache_bit);
1342*10784Ssinanallur.balasubramanian@sun.com 			if (errno) {
1343*10784Ssinanallur.balasubramanian@sun.com 				fmd_hdl_debug(hdl,
1344*10784Ssinanallur.balasubramanian@sun.com 				    "\n%s:cpu_id %d: failed to update",
1345*10784Ssinanallur.balasubramanian@sun.com 				    " CACHE_BIT in asru.\n",
1346*10784Ssinanallur.balasubramanian@sun.com 				    fltnm, cpu->cpu_cpuid);
1347*10784Ssinanallur.balasubramanian@sun.com 			}
1348*10784Ssinanallur.balasubramanian@sun.com 			return (cmd_Lxcache_retire_as_reason(hdl, cpu,
1349*10784Ssinanallur.balasubramanian@sun.com 			    suspect_Lxcache, fltnm, CMD_LXSUSPECT_1_TAG));
1350*10784Ssinanallur.balasubramanian@sun.com 		}	/* end of SUSPECT_0_TAG */
1351*10784Ssinanallur.balasubramanian@sun.com 		/*
1352*10784Ssinanallur.balasubramanian@sun.com 		 * No ways have been retired as "SUSPECT_x" for this bit.
1353*10784Ssinanallur.balasubramanian@sun.com 		 * We need to retire the lowest unretired way as suspect.
1354*10784Ssinanallur.balasubramanian@sun.com 		 */
1355*10784Ssinanallur.balasubramanian@sun.com 		ret = retire_lowest_retirable_way_as_suspect(hdl, cpu,
1356*10784Ssinanallur.balasubramanian@sun.com 		    anonymous_Lxcache,
1357*10784Ssinanallur.balasubramanian@sun.com 		    fltnm);
1358*10784Ssinanallur.balasubramanian@sun.com 		return (ret);
1359*10784Ssinanallur.balasubramanian@sun.com 	}	/* End of Anonymous TAG retirement */
1360*10784Ssinanallur.balasubramanian@sun.com 	/*
1361*10784Ssinanallur.balasubramanian@sun.com 	 * Identified bit and way has fired.
1362*10784Ssinanallur.balasubramanian@sun.com 	 * - Destroy any anonymous SERD engine at that index.
1363*10784Ssinanallur.balasubramanian@sun.com 	 * - If the bad bit is an ECC bit, fault the CPU.
1364*10784Ssinanallur.balasubramanian@sun.com 	 * - If the way was already convicted due to tag errors, fault the CPU.
1365*10784Ssinanallur.balasubramanian@sun.com 	 * - If the bad bit is a state bit, then:
1366*10784Ssinanallur.balasubramanian@sun.com 	 * - if the stable value of the bad bit will hold the NA encoding,
1367*10784Ssinanallur.balasubramanian@sun.com 	 *   retire the containing way as "convicted".
1368*10784Ssinanallur.balasubramanian@sun.com 	 * - if the stable value of the bad bit will not hold the NA
1369*10784Ssinanallur.balasubramanian@sun.com 	 *   encoding, fault the CPU.
1370*10784Ssinanallur.balasubramanian@sun.com 	 */
1371*10784Ssinanallur.balasubramanian@sun.com 	cmd_Lxcache_destroy_anonymous_serd_engines(hdl, cpu, pstype, index, -1);
13726330Sjc25722 	sticky_bit = find_bit_stickiness(tag_data, way, bit);
1373*10784Ssinanallur.balasubramanian@sun.com 	if ((bit >= PN_LX_TAG_ECC_START_BIT) &&
1374*10784Ssinanallur.balasubramanian@sun.com 	    (bit <= PN_LX_TAG_ECC_END_BIT)) {
1375*10784Ssinanallur.balasubramanian@sun.com 		fmd_hdl_debug(hdl,
1376*10784Ssinanallur.balasubramanian@sun.com 		    "\n%s:cpu_id %d Bad ECC bit %d at cache index %d way %d"
1377*10784Ssinanallur.balasubramanian@sun.com 		    " detected. Will offline the CPU.\n",
1378*10784Ssinanallur.balasubramanian@sun.com 		    fltnm, cpu->cpu_cpuid, bit, index, way);
13796330Sjc25722 		cmd_fault_the_cpu(hdl, cpu, pstype, fltnm);
13806330Sjc25722 		return (CMD_EVD_OK);
13816330Sjc25722 	}
13826330Sjc25722 	/*
13836330Sjc25722 	 * Check if a STATE bit is faulty.
13846330Sjc25722 	 * If so we need to ensure that we will be able to
13856330Sjc25722 	 * make the way NA, else fault the CPU.
13866330Sjc25722 	 */
1387*10784Ssinanallur.balasubramanian@sun.com 	if (bit <= PN_LX_STATE_END_BIT) {
13886330Sjc25722 		fmd_hdl_debug(hdl,
13896330Sjc25722 		    "%s cpu_id = %d: STATE bit %d is faulty.\n",
13906330Sjc25722 		    fltnm, cpu->cpu_cpuid, bit);
13916330Sjc25722 		/*
13926330Sjc25722 		 * If the stable value of bit will hold the NA encoding
13936330Sjc25722 		 * retire the containing way Else fault the cpu.
13946330Sjc25722 		 */
1395*10784Ssinanallur.balasubramanian@sun.com 		state = tag_data[way] & CH_ECSTATE_MASK;
1396*10784Ssinanallur.balasubramanian@sun.com 		if ((state & (1 << bit)) != (PN_ECSTATE_NA & (1 << bit))) {
13976330Sjc25722 			/*
1398*10784Ssinanallur.balasubramanian@sun.com 			 * The stable value of the bad bit will not hold the
1399*10784Ssinanallur.balasubramanian@sun.com 			 * NA encoding. will fault the CPU.
14006330Sjc25722 			 */
1401*10784Ssinanallur.balasubramanian@sun.com 			fmd_hdl_debug(hdl,
1402*10784Ssinanallur.balasubramanian@sun.com 			    "\n%s:cpu_id %d STATE bit %d is faulty at"
1403*10784Ssinanallur.balasubramanian@sun.com 			    " cache index %d way %d. STATE = 0x%x\n"
1404*10784Ssinanallur.balasubramanian@sun.com 			    " The bad bit will not hold the encoding we need"
1405*10784Ssinanallur.balasubramanian@sun.com 			    " to mark the cacheline as retired, so will offline"
1406*10784Ssinanallur.balasubramanian@sun.com 			    " the CPU.\n",
1407*10784Ssinanallur.balasubramanian@sun.com 			    fltnm, cpu->cpu_cpuid, bit, index, way, state);
14086330Sjc25722 			cmd_fault_the_cpu(hdl, cpu, pstype, fltnm);
14096330Sjc25722 			return (CMD_EVD_OK);
14106330Sjc25722 		}
14116330Sjc25722 	}
14126330Sjc25722 	/*
1413*10784Ssinanallur.balasubramanian@sun.com 	 * Check if we are getting fault on a way that is already retired.
1414*10784Ssinanallur.balasubramanian@sun.com 	 * if the way was already convicted due to tag errors, fault the CPU.
1415*10784Ssinanallur.balasubramanian@sun.com 	 * Note that the way could have previously been retired due to
1416*10784Ssinanallur.balasubramanian@sun.com 	 * data errors.  This is okay; we just re-retire it due to tag errors,
1417*10784Ssinanallur.balasubramanian@sun.com 	 * so that we can write the offending tag bit to a stable value.
14186330Sjc25722 	 */
1419*10784Ssinanallur.balasubramanian@sun.com 	if ((tag_data[way] & CH_ECSTATE_MASK) == PN_ECSTATE_NA) {
1420*10784Ssinanallur.balasubramanian@sun.com 		/*
1421*10784Ssinanallur.balasubramanian@sun.com 		 * Looking for CONVICTED TAG fault first.
1422*10784Ssinanallur.balasubramanian@sun.com 		 * If found retire the CPU.
1423*10784Ssinanallur.balasubramanian@sun.com 		 */
1424*10784Ssinanallur.balasubramanian@sun.com 		retired_Lxcache = cmd_Lxcache_lookup_by_type_index_way_reason(
1425*10784Ssinanallur.balasubramanian@sun.com 		    cpu, pstype, index, way, CMD_LXCONVICTED);
1426*10784Ssinanallur.balasubramanian@sun.com 		if (retired_Lxcache) {
1427*10784Ssinanallur.balasubramanian@sun.com 			fmd_hdl_debug(hdl,
1428*10784Ssinanallur.balasubramanian@sun.com 			    "\n%s: cpu %d: The cache index %d way %d previously"
1429*10784Ssinanallur.balasubramanian@sun.com 			    " retired for %s fault at bit %d is reporting"
1430*10784Ssinanallur.balasubramanian@sun.com 			    " fault. Will fault the CPU\n",
1431*10784Ssinanallur.balasubramanian@sun.com 			    fltnm, cpu->cpu_cpuid, index, way,
1432*10784Ssinanallur.balasubramanian@sun.com 			    cmd_type_to_str(
1433*10784Ssinanallur.balasubramanian@sun.com 			    retired_Lxcache->Lxcache_type),
1434*10784Ssinanallur.balasubramanian@sun.com 			    retired_Lxcache->Lxcache_bit);
1435*10784Ssinanallur.balasubramanian@sun.com 			cmd_fault_the_cpu(hdl, cpu, pstype, fltnm);
1436*10784Ssinanallur.balasubramanian@sun.com 			return (CMD_EVD_OK);
1437*10784Ssinanallur.balasubramanian@sun.com 		}
1438*10784Ssinanallur.balasubramanian@sun.com 		way_already_retired = 1;
14396330Sjc25722 	}
14406330Sjc25722 	/*
1441*10784Ssinanallur.balasubramanian@sun.com 	 * If any way(Including the current way) at this index is retired as
1442*10784Ssinanallur.balasubramanian@sun.com 	 * "suspect" due to tag errors, unretire it.  (If that suspect way
1443*10784Ssinanallur.balasubramanian@sun.com 	 * really was bad, it will start producing errors again and will
1444*10784Ssinanallur.balasubramanian@sun.com 	 * eventually be retired again.)
14456330Sjc25722 	 */
1446*10784Ssinanallur.balasubramanian@sun.com 	suspect_Lxcache = cmd_Lxcache_lookup_by_type_index_bit_reason(
1447*10784Ssinanallur.balasubramanian@sun.com 	    cpu, pstype, index,  -1,
1448*10784Ssinanallur.balasubramanian@sun.com 	    (CMD_LXSUSPECT_0_TAG | CMD_LXSUSPECT_1_TAG));
1449*10784Ssinanallur.balasubramanian@sun.com 	if (suspect_Lxcache) {
14506330Sjc25722 		fmd_hdl_debug(hdl,
1451*10784Ssinanallur.balasubramanian@sun.com 		    "\n%s:cpu_id %d found index %d way %d"
1452*10784Ssinanallur.balasubramanian@sun.com 		    " bit %d retired as SUSPECT_x. Will"
1453*10784Ssinanallur.balasubramanian@sun.com 		    "  unretire this now.\n",
1454*10784Ssinanallur.balasubramanian@sun.com 		    fltnm, cpu->cpu_cpuid, index,
1455*10784Ssinanallur.balasubramanian@sun.com 		    suspect_Lxcache->Lxcache_way, -1);
1456*10784Ssinanallur.balasubramanian@sun.com 		/*
1457*10784Ssinanallur.balasubramanian@sun.com 		 * unretire the suspect_x retired_way.
1458*10784Ssinanallur.balasubramanian@sun.com 		 */
1459*10784Ssinanallur.balasubramanian@sun.com 		if (cmd_Lxcache_unretire(hdl, cpu, suspect_Lxcache, fltnm)
1460*10784Ssinanallur.balasubramanian@sun.com 		    == B_TRUE) {
1461*10784Ssinanallur.balasubramanian@sun.com 			suspect_Lxcache->Lxcache_reason =
1462*10784Ssinanallur.balasubramanian@sun.com 			    CMD_LXFUNCTIONING;
1463*10784Ssinanallur.balasubramanian@sun.com 			fmd_hdl_debug(hdl,
1464*10784Ssinanallur.balasubramanian@sun.com 			    "\n%s:cpu_id %d index %d way %d"
1465*10784Ssinanallur.balasubramanian@sun.com 			    " successfully unretired. Will"
1466*10784Ssinanallur.balasubramanian@sun.com 			    " destroy this Lxcache now.\n",
1467*10784Ssinanallur.balasubramanian@sun.com 			    fltnm, cpu->cpu_cpuid, index,
1468*10784Ssinanallur.balasubramanian@sun.com 			    suspect_Lxcache->Lxcache_way);
1469*10784Ssinanallur.balasubramanian@sun.com 			cmd_Lxcache_destroy(hdl, cpu, suspect_Lxcache);
1470*10784Ssinanallur.balasubramanian@sun.com 		} else {
1471*10784Ssinanallur.balasubramanian@sun.com 			/*
1472*10784Ssinanallur.balasubramanian@sun.com 			 * We are unable to unretire the previously retired
1473*10784Ssinanallur.balasubramanian@sun.com 			 * SUSPECT way at the fault index.
1474*10784Ssinanallur.balasubramanian@sun.com 			 * If the previously retired way is same as the way
1475*10784Ssinanallur.balasubramanian@sun.com 			 * we are attempting to retire then return failure.
1476*10784Ssinanallur.balasubramanian@sun.com 			 */
1477*10784Ssinanallur.balasubramanian@sun.com 			if (suspect_Lxcache->Lxcache_way ==
1478*10784Ssinanallur.balasubramanian@sun.com 			    Lxcache->Lxcache_way)
1479*10784Ssinanallur.balasubramanian@sun.com 				return (CMD_EVD_BAD);
1480*10784Ssinanallur.balasubramanian@sun.com 		}
14816330Sjc25722 	}
1482*10784Ssinanallur.balasubramanian@sun.com 	ways_retired = get_index_retired_ways(cpu, pstype, index);
1483*10784Ssinanallur.balasubramanian@sun.com 	if (ways_retired == -1)
1484*10784Ssinanallur.balasubramanian@sun.com 		return (CMD_EVD_BAD);
1485*10784Ssinanallur.balasubramanian@sun.com 	/*
1486*10784Ssinanallur.balasubramanian@sun.com 	 * Before retiring a way check if we have already
1487*10784Ssinanallur.balasubramanian@sun.com 	 * retired 3 ways for this index.
1488*10784Ssinanallur.balasubramanian@sun.com 	 * If the way was already retired due to DATA error or
1489*10784Ssinanallur.balasubramanian@sun.com 	 * SUSPECT_X TAG error then we skip the check.
1490*10784Ssinanallur.balasubramanian@sun.com 	 */
1491*10784Ssinanallur.balasubramanian@sun.com 	if (!way_already_retired) {
1492*10784Ssinanallur.balasubramanian@sun.com 		if (ways_retired >= 3) {
1493*10784Ssinanallur.balasubramanian@sun.com 			fmd_hdl_debug(hdl,
1494*10784Ssinanallur.balasubramanian@sun.com 			    "\n%s: cpu %d: num of ways retired for index %d"
1495*10784Ssinanallur.balasubramanian@sun.com 			    " is %d will fault the CPU\n",
1496*10784Ssinanallur.balasubramanian@sun.com 			    fltnm, cpu->cpu_cpuid, index, ways_retired);
1497*10784Ssinanallur.balasubramanian@sun.com 			cmd_fault_the_cpu(hdl, cpu, pstype, fltnm);
1498*10784Ssinanallur.balasubramanian@sun.com 			return (CMD_EVD_OK);
1499*10784Ssinanallur.balasubramanian@sun.com 		}
1500*10784Ssinanallur.balasubramanian@sun.com 	}
15016330Sjc25722 	fmd_hdl_debug(hdl,
1502*10784Ssinanallur.balasubramanian@sun.com 	    "\n%s: cpu %d: num of ways retired for index %d is %d\n",
15036330Sjc25722 	    fltnm, cpu->cpu_cpuid, index, ways_retired);
15046330Sjc25722 	if ((errno = nvlist_add_uint16(Lxcache->Lxcache_asru_nvl,
15056330Sjc25722 	    FM_FMRI_CPU_CACHE_BIT,
15066330Sjc25722 	    sticky_bit)) != 0 ||
15076330Sjc25722 	    (errno = fmd_nvl_fmri_expand(hdl, Lxcache->Lxcache_asru_nvl)) != 0)
15086330Sjc25722 		fmd_hdl_abort(hdl, "failed to build Lxcache fmri");
1509*10784Ssinanallur.balasubramanian@sun.com 	Lxcache->Lxcache_ep = ep;
1510*10784Ssinanallur.balasubramanian@sun.com 	return (cmd_Lxcache_retire_as_reason(hdl, cpu, Lxcache, fltnm,
1511*10784Ssinanallur.balasubramanian@sun.com 	    CMD_LXCONVICTED));
15126330Sjc25722 }
15136330Sjc25722 
1514*10784Ssinanallur.balasubramanian@sun.com static boolean_t
pn_there_is_a_matching_synd(fmd_hdl_t * hdl,cmd_xr_t * xr)1515*10784Ssinanallur.balasubramanian@sun.com pn_there_is_a_matching_synd(fmd_hdl_t *hdl, cmd_xr_t *xr)
15166330Sjc25722 {
1517*10784Ssinanallur.balasubramanian@sun.com 	int ec_data_idx, i;
1518*10784Ssinanallur.balasubramanian@sun.com 	int8_t	way;
1519*10784Ssinanallur.balasubramanian@sun.com 	uint64_t ec_tag, data_hi, data_lo;
1520*10784Ssinanallur.balasubramanian@sun.com 	int ecc, calc_synd;
1521*10784Ssinanallur.balasubramanian@sun.com 	ec_data_elm_t *ecdptr = NULL;
1522*10784Ssinanallur.balasubramanian@sun.com 	uint8_t state;
1523*10784Ssinanallur.balasubramanian@sun.com 	ch_ec_data_t	*ecp;
15246330Sjc25722 
1525*10784Ssinanallur.balasubramanian@sun.com 	ecp = (ch_ec_data_t *)(xr->xr_cache_data);
1526*10784Ssinanallur.balasubramanian@sun.com 	for (way = 0; way < xr->xr_num_ways; way++, ecp++) {
1527*10784Ssinanallur.balasubramanian@sun.com 		ec_tag = ecp->ec_tag;
1528*10784Ssinanallur.balasubramanian@sun.com 		/*
1529*10784Ssinanallur.balasubramanian@sun.com 		 * skip Retired and Invalid ways
1530*10784Ssinanallur.balasubramanian@sun.com 		 */
1531*10784Ssinanallur.balasubramanian@sun.com 		state = ec_tag & CH_ECSTATE_MASK;
1532*10784Ssinanallur.balasubramanian@sun.com 		if ((state == PN_ECSTATE_NA) ||
1533*10784Ssinanallur.balasubramanian@sun.com 		    (state == CH_ECSTATE_INV))
1534*10784Ssinanallur.balasubramanian@sun.com 			continue;
1535*10784Ssinanallur.balasubramanian@sun.com 		/*
1536*10784Ssinanallur.balasubramanian@sun.com 		 * Each 16 bytes of data are protected by 9-bit ECC field.
1537*10784Ssinanallur.balasubramanian@sun.com 		 */
1538*10784Ssinanallur.balasubramanian@sun.com 
1539*10784Ssinanallur.balasubramanian@sun.com 		for (i = 0; i < (CH_ECACHE_SUBBLK_SIZE/16); i++) {
1540*10784Ssinanallur.balasubramanian@sun.com 			ec_data_idx = (i/2);
1541*10784Ssinanallur.balasubramanian@sun.com 
1542*10784Ssinanallur.balasubramanian@sun.com 			ecdptr = &ecp->ec_data[ec_data_idx];
1543*10784Ssinanallur.balasubramanian@sun.com 			if ((i & 1) == 0) {
1544*10784Ssinanallur.balasubramanian@sun.com 				ecc = (ecdptr->ec_eccd >> 9) & 0x1ff;
1545*10784Ssinanallur.balasubramanian@sun.com 				data_hi = ecdptr->ec_d8[0];
1546*10784Ssinanallur.balasubramanian@sun.com 				data_lo = ecdptr->ec_d8[1];
1547*10784Ssinanallur.balasubramanian@sun.com 			} else {
1548*10784Ssinanallur.balasubramanian@sun.com 				ecc = ecdptr->ec_eccd & 0x1ff;
1549*10784Ssinanallur.balasubramanian@sun.com 				data_hi = ecdptr->ec_d8[2];
1550*10784Ssinanallur.balasubramanian@sun.com 				data_lo = ecdptr->ec_d8[3];
15516330Sjc25722 			}
1552*10784Ssinanallur.balasubramanian@sun.com 
1553*10784Ssinanallur.balasubramanian@sun.com 			calc_synd = calcsynd(data_hi, data_lo, ecc);
1554*10784Ssinanallur.balasubramanian@sun.com 			if ((calc_synd != 0) &&
1555*10784Ssinanallur.balasubramanian@sun.com 			    (xr->xr_synd == calc_synd)) {
1556*10784Ssinanallur.balasubramanian@sun.com 				if (xr->xr_num_ways == 1) {
1557*10784Ssinanallur.balasubramanian@sun.com 					fmd_hdl_debug(hdl,
1558*10784Ssinanallur.balasubramanian@sun.com 			"\ncomputed syndrome matches with the reported syndrome"
1559*10784Ssinanallur.balasubramanian@sun.com 			" 0x%x index = %d way = %d\n",
1560*10784Ssinanallur.balasubramanian@sun.com 					    xr->xr_synd, xr->xr_error_index,
1561*10784Ssinanallur.balasubramanian@sun.com 					    xr->xr_error_way);
15626330Sjc25722 				} else {
1563*10784Ssinanallur.balasubramanian@sun.com 					fmd_hdl_debug(hdl,
1564*10784Ssinanallur.balasubramanian@sun.com 					    "\ncomputed syndrome matches with"
1565*10784Ssinanallur.balasubramanian@sun.com 					    " the reported syndrome"
1566*10784Ssinanallur.balasubramanian@sun.com 					    " 0x%x index = %d way = %d\n",
1567*10784Ssinanallur.balasubramanian@sun.com 					    xr->xr_synd, xr->xr_error_index,
1568*10784Ssinanallur.balasubramanian@sun.com 					    way);
1569*10784Ssinanallur.balasubramanian@sun.com 					xr->xr_error_way = way;
15706330Sjc25722 				}
1571*10784Ssinanallur.balasubramanian@sun.com 				return (B_TRUE);
1572*10784Ssinanallur.balasubramanian@sun.com 			}
15736330Sjc25722 		}
15746330Sjc25722 	}
1575*10784Ssinanallur.balasubramanian@sun.com 	return (B_FALSE);
15766330Sjc25722 }
15776330Sjc25722 
1578*10784Ssinanallur.balasubramanian@sun.com /* add to cheetahregs.h */
1579*10784Ssinanallur.balasubramanian@sun.com #define	CH_ECSTATE_NA 	5
15806330Sjc25722 
1581*10784Ssinanallur.balasubramanian@sun.com static int32_t
pn_extract_index(int32_t type,uint64_t afar)1582*10784Ssinanallur.balasubramanian@sun.com pn_extract_index(int32_t type, uint64_t afar)
15836330Sjc25722 {
1584*10784Ssinanallur.balasubramanian@sun.com 	int32_t index = -1;
15856330Sjc25722 
1586*10784Ssinanallur.balasubramanian@sun.com 	switch (type) {
1587*10784Ssinanallur.balasubramanian@sun.com 		case CMD_PTR_CPU_L2DATA:
1588*10784Ssinanallur.balasubramanian@sun.com 			index = (int32_t)((afar & PN_L2_INDEX_MASK)
1589*10784Ssinanallur.balasubramanian@sun.com 			    >> PN_CACHE_LINE_SHIFT);
1590*10784Ssinanallur.balasubramanian@sun.com 			break;
1591*10784Ssinanallur.balasubramanian@sun.com 		case CMD_PTR_CPU_L3DATA:
1592*10784Ssinanallur.balasubramanian@sun.com 			index = (int32_t)((afar & PN_L3_INDEX_MASK)
1593*10784Ssinanallur.balasubramanian@sun.com 			    >> PN_CACHE_LINE_SHIFT);
1594*10784Ssinanallur.balasubramanian@sun.com 			break;
15956330Sjc25722 	}
1596*10784Ssinanallur.balasubramanian@sun.com 	return (index);
15976330Sjc25722 }
15986330Sjc25722 
15996330Sjc25722 /*
16006330Sjc25722  *	cmd_cache_ce_panther
16016330Sjc25722  *
16026330Sjc25722  *	This routine handles L2 and L3 cachedata errors for the Panther.
16036330Sjc25722  *	It's called when the train processing for L2 and L3 correctable
16046330Sjc25722  *	data errors are about to issue a fault.
16056330Sjc25722  *
16066330Sjc25722  *	This routine retrieves payload information gathered during the XR
16076330Sjc25722  *	processing and generates a unique SERD engine and cache data
16086330Sjc25722  *	associated with the CPU if one does not exist.
16096330Sjc25722  *	If the SERD fires for the given engine it will initiate a cache
16106330Sjc25722  *	line fault if the way is not anonomyous.
16116330Sjc25722  *	If the way is anonomyous, it will attempt to choose a way for the
16126330Sjc25722  *	given index to fault. If the maximum for the index has not been
16136330Sjc25722  *	reached, it will attempt to unretire a different way previously retired
16146330Sjc25722  * 	under suspicion for the index prior to faulting
16156330Sjc25722  *	the selected way.
16166330Sjc25722  *	The routine will also fault the CPU if the maximum number of
16176330Sjc25722  *	retired ways for the CPU has been exceeded based on the category.
16186330Sjc25722  */
16196330Sjc25722 /*ARGSUSED*/
16206330Sjc25722 int
cmd_cache_ce_panther(fmd_hdl_t * hdl,fmd_event_t * ep,cmd_xr_t * xr)16216330Sjc25722 cmd_cache_ce_panther(fmd_hdl_t *hdl, fmd_event_t *ep, cmd_xr_t *xr)
16226330Sjc25722 {
1623*10784Ssinanallur.balasubramanian@sun.com 	cmd_Lxcache_t *suspect_Lxcache, *Lxcache, *anonymous_Lxcache;
16246330Sjc25722 	cmd_cpu_t *cpu = xr->xr_cpu;
16256330Sjc25722 	cmd_case_t *cpu_cc;
16266330Sjc25722 	cmd_ptrsubtype_t type;
16276330Sjc25722 	const errdata_t *cache_ed;
1628*10784Ssinanallur.balasubramanian@sun.com 	uint16_t offset;
1629*10784Ssinanallur.balasubramanian@sun.com 	int16_t bit;
1630*10784Ssinanallur.balasubramanian@sun.com 	int	ways_retired;
1631*10784Ssinanallur.balasubramanian@sun.com 	int	ret;
16326330Sjc25722 
16336330Sjc25722 	/*
1634*10784Ssinanallur.balasubramanian@sun.com 	 * The caller of this routine cmd_xxc_hdlr() expects us to
1635*10784Ssinanallur.balasubramanian@sun.com 	 * return CMD_EVD_OK for success and CMD_EVD_BAD for failures.
16366330Sjc25722 	 * If this is not a Panther or one of the Panther specific
16376330Sjc25722 	 * errors that we handle here, then exit
16386330Sjc25722 	 */
16396330Sjc25722 
1640*10784Ssinanallur.balasubramanian@sun.com 	if (cpu->cpu_pers.cpup_type != CPU_ULTRASPARC_IVplus)
1641*10784Ssinanallur.balasubramanian@sun.com 		return (CMD_EVD_BAD);
16426330Sjc25722 
16436330Sjc25722 	if (!(xr->xr_clcode & (int)PN_CACHE_ERRORS))
1644*10784Ssinanallur.balasubramanian@sun.com 		return (CMD_EVD_BAD);
16456330Sjc25722 
16466330Sjc25722 
16476330Sjc25722 	/* Set up Cache specific structs */
16486330Sjc25722 
16496330Sjc25722 	if (CMD_ERRCL_ISL2XXCU(xr->xr_clcode)) {
16506330Sjc25722 		type = CMD_PTR_CPU_L2DATA;
16516330Sjc25722 		cpu_cc = &cpu->cpu_l2data;
1652*10784Ssinanallur.balasubramanian@sun.com 		cache_ed = &l2errdata;
16536330Sjc25722 	} else {
16546330Sjc25722 		type = CMD_PTR_CPU_L3DATA;
16556330Sjc25722 		cpu_cc = &cpu->cpu_l3data;
1656*10784Ssinanallur.balasubramanian@sun.com 		cache_ed = &l3errdata;
16576330Sjc25722 	}
16586330Sjc25722 
16596330Sjc25722 	/* Ensure that our case is not solved */
16606330Sjc25722 
16616330Sjc25722 	if (cpu->cpu_faulting || (cpu_cc->cc_cp != NULL &&
16626330Sjc25722 	    fmd_case_solved(hdl, cpu_cc->cc_cp)))
1663*10784Ssinanallur.balasubramanian@sun.com 			return (CMD_EVD_OK);
16646330Sjc25722 
1665*10784Ssinanallur.balasubramanian@sun.com 	fmd_hdl_debug(hdl, "Processing Panther %s Error\n",
16666330Sjc25722 	    cache_ed->ed_fltnm);
16676330Sjc25722 
16686330Sjc25722 	/* L3 errors arrive as mem scheme errors - convert to CPU */
16696330Sjc25722 	if (type == CMD_PTR_CPU_L3DATA) {
16706330Sjc25722 		cmd_fmri_init(hdl, &xr->xr_rsrc,
16716330Sjc25722 		    xr->xr_detector_nvlist, "%s_rsrc",
16726330Sjc25722 		    fmd_case_uuid(hdl, xr->xr_case));
16736330Sjc25722 	}
1674*10784Ssinanallur.balasubramanian@sun.com 	bit = (uint8_t)ecc_syndrome_tab[xr->xr_synd];
1675*10784Ssinanallur.balasubramanian@sun.com 	offset = (uint16_t)xr->xr_afar & 0x3f;
1676*10784Ssinanallur.balasubramanian@sun.com 	if (bit > C8) {
1677*10784Ssinanallur.balasubramanian@sun.com 		fmd_hdl_debug(hdl, "xxC/LDxC dropped due to syndrome\n");
1678*10784Ssinanallur.balasubramanian@sun.com 		return (CMD_EVD_BAD);
1679*10784Ssinanallur.balasubramanian@sun.com 	}
1680*10784Ssinanallur.balasubramanian@sun.com 	if (bit < C0) {
1681*10784Ssinanallur.balasubramanian@sun.com 		/*
1682*10784Ssinanallur.balasubramanian@sun.com 		 * Data bit. Set bit in the range 0-511
1683*10784Ssinanallur.balasubramanian@sun.com 		 */
1684*10784Ssinanallur.balasubramanian@sun.com 		bit += ((3 - (offset/16)) * 128);
1685*10784Ssinanallur.balasubramanian@sun.com 	} else {
1686*10784Ssinanallur.balasubramanian@sun.com 		/*
1687*10784Ssinanallur.balasubramanian@sun.com 		 * ECC bit. Set bit in the range 512-547
1688*10784Ssinanallur.balasubramanian@sun.com 		 */
1689*10784Ssinanallur.balasubramanian@sun.com 		bit -= C0;
1690*10784Ssinanallur.balasubramanian@sun.com 		bit += 512 + ((3 - (offset/16)) * PN_LX_NUM_OF_BITS_IN_ECC);
16916330Sjc25722 	}
1692*10784Ssinanallur.balasubramanian@sun.com 	xr->xr_error_index = pn_extract_index(type, xr->xr_afar);
1693*10784Ssinanallur.balasubramanian@sun.com 	if (xr->xr_error_index == 0xffffffff) {
1694*10784Ssinanallur.balasubramanian@sun.com 		fmd_hdl_debug(hdl, "xxC/LDxC dropped due to index\n");
1695*10784Ssinanallur.balasubramanian@sun.com 		return (CMD_EVD_BAD);
1696*10784Ssinanallur.balasubramanian@sun.com 	}
1697*10784Ssinanallur.balasubramanian@sun.com 	fmd_hdl_debug(hdl, "cpu_id: %d, syndrome: 0x%x, afar: 0x%llx\n",
1698*10784Ssinanallur.balasubramanian@sun.com 	    xr->xr_cpuid, xr->xr_synd, xr->xr_afar);
1699*10784Ssinanallur.balasubramanian@sun.com 	fmd_hdl_debug(hdl, "index: 0x%x(%d) bit: %d\n",
1700*10784Ssinanallur.balasubramanian@sun.com 	    xr->xr_error_index, xr->xr_error_index, bit);
1701*10784Ssinanallur.balasubramanian@sun.com 	/*
1702*10784Ssinanallur.balasubramanian@sun.com 	 * The payload information for the DATA errors are assembled
1703*10784Ssinanallur.balasubramanian@sun.com 	 * after first looking for a valid line that matches the fault AFAR.
1704*10784Ssinanallur.balasubramanian@sun.com 	 * If no match is found all 4 ways are logged and xr_num_ways
1705*10784Ssinanallur.balasubramanian@sun.com 	 * will be 4. If a matching way is found only that entry is logged
1706*10784Ssinanallur.balasubramanian@sun.com 	 * and xr_num_ways is set as 1.
1707*10784Ssinanallur.balasubramanian@sun.com 	 * The xr_error_way is set as -1 when xr_num_ways is 4, else
1708*10784Ssinanallur.balasubramanian@sun.com 	 * xr_error_way is set to the matching way.
1709*10784Ssinanallur.balasubramanian@sun.com 	 * what we do below is to force the xr_error_way to -1 for WDC/CPC
1710*10784Ssinanallur.balasubramanian@sun.com 	 * errors.
1711*10784Ssinanallur.balasubramanian@sun.com 	 * For UCC and EDC errors the xr_error_way will be set correctly.
1712*10784Ssinanallur.balasubramanian@sun.com 	 */
17136330Sjc25722 
1714*10784Ssinanallur.balasubramanian@sun.com 	switch (xr->xr_clcode) {
1715*10784Ssinanallur.balasubramanian@sun.com 		case CMD_ERRCL_WDC:
1716*10784Ssinanallur.balasubramanian@sun.com 		case CMD_ERRCL_L3_WDC:
1717*10784Ssinanallur.balasubramanian@sun.com 			/*
1718*10784Ssinanallur.balasubramanian@sun.com 			 * WDC is a disrupting trap, and invalidates and
1719*10784Ssinanallur.balasubramanian@sun.com 			 * overwrites the problematic way.  Any match is due to
1720*10784Ssinanallur.balasubramanian@sun.com 			 * a refetch of the AFAR, which could have been to any
1721*10784Ssinanallur.balasubramanian@sun.com 			 * way. So these are treated as "anonymous".
1722*10784Ssinanallur.balasubramanian@sun.com 			 */
1723*10784Ssinanallur.balasubramanian@sun.com 			fmd_hdl_debug(hdl, "WDC fault detected\n");
1724*10784Ssinanallur.balasubramanian@sun.com 			xr->xr_error_way = (uint32_t)CMD_ANON_WAY;
1725*10784Ssinanallur.balasubramanian@sun.com 			break;
1726*10784Ssinanallur.balasubramanian@sun.com 		case CMD_ERRCL_CPC:
1727*10784Ssinanallur.balasubramanian@sun.com 		case CMD_ERRCL_L3_CPC:
1728*10784Ssinanallur.balasubramanian@sun.com 			/*
1729*10784Ssinanallur.balasubramanian@sun.com 			 * CPC is a disrupting trap, but since it happens due to
1730*10784Ssinanallur.balasubramanian@sun.com 			 * a snoop, the problematic way could become invalid,
1731*10784Ssinanallur.balasubramanian@sun.com 			 * overwritten by a different cache line, and then the
1732*10784Ssinanallur.balasubramanian@sun.com 			 * AFAR accessed and pulled into a different way,
1733*10784Ssinanallur.balasubramanian@sun.com 			 * causing a false positive match.  So it's best to not
1734*10784Ssinanallur.balasubramanian@sun.com 			 * look for a matching way and just ascribe these to
1735*10784Ssinanallur.balasubramanian@sun.com 			 *  the "anonymous" way.
1736*10784Ssinanallur.balasubramanian@sun.com 			 */
1737*10784Ssinanallur.balasubramanian@sun.com 			fmd_hdl_debug(hdl, "CPC fault detected\n");
1738*10784Ssinanallur.balasubramanian@sun.com 			xr->xr_error_way = (uint32_t)CMD_ANON_WAY;
1739*10784Ssinanallur.balasubramanian@sun.com 			break;
1740*10784Ssinanallur.balasubramanian@sun.com 		case CMD_ERRCL_UCC:
1741*10784Ssinanallur.balasubramanian@sun.com 		case CMD_ERRCL_L3_UCC:
1742*10784Ssinanallur.balasubramanian@sun.com 			/*
1743*10784Ssinanallur.balasubramanian@sun.com 			 * UCC is a precise trap, so, absent activity from the
1744*10784Ssinanallur.balasubramanian@sun.com 			 * other core, the tag address values read by the TL=1
1745*10784Ssinanallur.balasubramanian@sun.com 			 * trap handler are likely to be the same as those at
1746*10784Ssinanallur.balasubramanian@sun.com 			 * the time of the trap.
1747*10784Ssinanallur.balasubramanian@sun.com 			 * (A snoop from another CPU might cause a change in
1748*10784Ssinanallur.balasubramanian@sun.com 			 * state from valid to invalid, but the  tag address
1749*10784Ssinanallur.balasubramanian@sun.com 			 * won't change.) If we find a matching valid tag,
1750*10784Ssinanallur.balasubramanian@sun.com 			 * that identifies the way.
1751*10784Ssinanallur.balasubramanian@sun.com 			 */
1752*10784Ssinanallur.balasubramanian@sun.com 			fmd_hdl_debug(hdl, "UCC fault detected\n");
1753*10784Ssinanallur.balasubramanian@sun.com 			fmd_hdl_debug(hdl, "# of ways collected are %d\n",
1754*10784Ssinanallur.balasubramanian@sun.com 			    xr->xr_num_ways);
1755*10784Ssinanallur.balasubramanian@sun.com 			fmd_hdl_debug(hdl,
1756*10784Ssinanallur.balasubramanian@sun.com 			    "\n%s:cpu_id %d: error way = %d\n",
1757*10784Ssinanallur.balasubramanian@sun.com 			    cache_ed->ed_fltnm, cpu->cpu_cpuid,
1758*10784Ssinanallur.balasubramanian@sun.com 			    xr->xr_error_way);
1759*10784Ssinanallur.balasubramanian@sun.com 			break;
1760*10784Ssinanallur.balasubramanian@sun.com 		case CMD_ERRCL_EDC:
1761*10784Ssinanallur.balasubramanian@sun.com 		case CMD_ERRCL_L3_EDC:
1762*10784Ssinanallur.balasubramanian@sun.com 			/*
1763*10784Ssinanallur.balasubramanian@sun.com 			 * EDC is a disrupting trap, but again if a matching
1764*10784Ssinanallur.balasubramanian@sun.com 			 * valid way is found, it is likely to be the correct
1765*10784Ssinanallur.balasubramanian@sun.com 			 * way.
1766*10784Ssinanallur.balasubramanian@sun.com 			 */
1767*10784Ssinanallur.balasubramanian@sun.com 			fmd_hdl_debug(hdl, "EDC fault detected\n");
1768*10784Ssinanallur.balasubramanian@sun.com 			fmd_hdl_debug(hdl, "# of ways collected are %d\n",
1769*10784Ssinanallur.balasubramanian@sun.com 			    xr->xr_num_ways);
1770*10784Ssinanallur.balasubramanian@sun.com 			fmd_hdl_debug(hdl,
1771*10784Ssinanallur.balasubramanian@sun.com 			    "\n%s:cpu_id %d: error way = %d\n",
1772*10784Ssinanallur.balasubramanian@sun.com 			    cache_ed->ed_fltnm, cpu->cpu_cpuid,
1773*10784Ssinanallur.balasubramanian@sun.com 			    xr->xr_error_way);
1774*10784Ssinanallur.balasubramanian@sun.com 			break;
1775*10784Ssinanallur.balasubramanian@sun.com 		default:
1776*10784Ssinanallur.balasubramanian@sun.com 			fmd_hdl_debug(hdl, "Unexpected fault detected\n");
1777*10784Ssinanallur.balasubramanian@sun.com 			xr->xr_error_way = (uint32_t)CMD_ANON_WAY;
17786330Sjc25722 	}
1779*10784Ssinanallur.balasubramanian@sun.com 	if ((type == CMD_PTR_CPU_L2DATA) &&
1780*10784Ssinanallur.balasubramanian@sun.com 	    (xr->xr_cache_data != NULL) &&
1781*10784Ssinanallur.balasubramanian@sun.com 	    (!pn_there_is_a_matching_synd(hdl, xr))) {
1782*10784Ssinanallur.balasubramanian@sun.com 		fmd_hdl_debug(hdl, "No matching syndrome\n");
17836330Sjc25722 	}
1784*10784Ssinanallur.balasubramanian@sun.com 	Lxcache = cmd_Lxcache_lookup_by_type_index_way_bit(xr->xr_cpu, type,
17856330Sjc25722 	    xr->xr_error_index, xr->xr_error_way, bit);
17866330Sjc25722 
1787*10784Ssinanallur.balasubramanian@sun.com 	if (Lxcache == NULL) {
17886330Sjc25722 		fmd_hdl_debug(hdl,
1789*10784Ssinanallur.balasubramanian@sun.com 		    "\n%s: cpu %d: creating a case for index %d way %d"
1790*10784Ssinanallur.balasubramanian@sun.com 		    " bit %d\n",
17916330Sjc25722 		    cache_ed->ed_fltnm, xr->xr_cpuid,
17926330Sjc25722 		    xr->xr_error_index, xr->xr_error_way, bit);
1793*10784Ssinanallur.balasubramanian@sun.com 		Lxcache = cmd_Lxcache_create(hdl, xr, xr->xr_cpu,
17946330Sjc25722 		    xr->xr_cpu->cpu_asru_nvl,
17956330Sjc25722 		    type, xr->xr_error_index,
17966330Sjc25722 		    xr->xr_error_way, bit);
1797*10784Ssinanallur.balasubramanian@sun.com 		if (Lxcache == NULL) {
1798*10784Ssinanallur.balasubramanian@sun.com 			fmd_hdl_debug(hdl,
1799*10784Ssinanallur.balasubramanian@sun.com 			    "\n%s:cpu_id %d:Failed to create a Lxcache for"
1800*10784Ssinanallur.balasubramanian@sun.com 			    " index %d way %d bit %d\n",
1801*10784Ssinanallur.balasubramanian@sun.com 			    cache_ed->ed_fltnm, cpu->cpu_cpuid,
1802*10784Ssinanallur.balasubramanian@sun.com 			    Lxcache->Lxcache_index,
1803*10784Ssinanallur.balasubramanian@sun.com 			    Lxcache->Lxcache_way, Lxcache->Lxcache_bit);
1804*10784Ssinanallur.balasubramanian@sun.com 			return (CMD_EVD_BAD);
1805*10784Ssinanallur.balasubramanian@sun.com 		}
1806*10784Ssinanallur.balasubramanian@sun.com 	}
1807*10784Ssinanallur.balasubramanian@sun.com 	if (cmd_create_case_for_Lxcache(hdl, cpu, Lxcache) == B_FALSE)
1808*10784Ssinanallur.balasubramanian@sun.com 		return (CMD_EVD_BAD);
1809*10784Ssinanallur.balasubramanian@sun.com 	if (Lxcache->Lxcache_case.cc_serdnm == NULL) {
1810*10784Ssinanallur.balasubramanian@sun.com 		Lxcache->Lxcache_case.cc_serdnm =
18116330Sjc25722 		    cmd_Lxcache_serdnm_create(hdl, xr->xr_cpuid,
18126330Sjc25722 		    type, xr->xr_error_index, xr->xr_error_way, bit);
18136330Sjc25722 
18146330Sjc25722 		if (!fmd_serd_exists(hdl,
1815*10784Ssinanallur.balasubramanian@sun.com 		    Lxcache->Lxcache_case.cc_serdnm)) {
18166330Sjc25722 			fmd_serd_create(hdl,
1817*10784Ssinanallur.balasubramanian@sun.com 			    Lxcache->Lxcache_case.cc_serdnm,
18186330Sjc25722 			    cache_ed->ed_serd->cs_n,
18196330Sjc25722 			    cache_ed->ed_serd->cs_t);
1820*10784Ssinanallur.balasubramanian@sun.com 			fmd_hdl_debug(hdl,
1821*10784Ssinanallur.balasubramanian@sun.com 			    "\n%s: cpu_id %d: created a SERD engine %s\n",
1822*10784Ssinanallur.balasubramanian@sun.com 			    cache_ed->ed_fltnm, cpu->cpu_cpuid,
1823*10784Ssinanallur.balasubramanian@sun.com 			    Lxcache->Lxcache_case.cc_serdnm);
18246330Sjc25722 		}
18256330Sjc25722 	}
18266330Sjc25722 	/* Ensure that our case is not solved */
1827*10784Ssinanallur.balasubramanian@sun.com 	if ((Lxcache->Lxcache_case.cc_cp != NULL) &&
1828*10784Ssinanallur.balasubramanian@sun.com 	    fmd_case_solved(hdl, Lxcache->Lxcache_case.cc_cp)) {
1829*10784Ssinanallur.balasubramanian@sun.com 		fmd_hdl_debug(hdl,
1830*10784Ssinanallur.balasubramanian@sun.com 		    "\n%s:cpu %d: the case for %s is already solved.\n",
1831*10784Ssinanallur.balasubramanian@sun.com 		    cache_ed->ed_fltnm, cpu->cpu_cpuid,
1832*10784Ssinanallur.balasubramanian@sun.com 		    Lxcache->Lxcache_bufname);
1833*10784Ssinanallur.balasubramanian@sun.com 		return (CMD_EVD_REDUND);
18346330Sjc25722 	}
18356330Sjc25722 
1836*10784Ssinanallur.balasubramanian@sun.com 	fmd_hdl_debug(hdl,
1837*10784Ssinanallur.balasubramanian@sun.com 	    "\n%s:cpu_id %d: checking if SERD engine %s has fired.\n",
1838*10784Ssinanallur.balasubramanian@sun.com 	    cache_ed->ed_fltnm, xr->xr_cpuid, Lxcache->Lxcache_case.cc_serdnm);
18396330Sjc25722 
1840*10784Ssinanallur.balasubramanian@sun.com 	if (fmd_serd_record(hdl, Lxcache->Lxcache_case.cc_serdnm, ep)
1841*10784Ssinanallur.balasubramanian@sun.com 	    == FMD_B_FALSE)
1842*10784Ssinanallur.balasubramanian@sun.com 		return (CMD_EVD_OK); /* serd engine hasn't fired yet */
18436330Sjc25722 
1844*10784Ssinanallur.balasubramanian@sun.com 	fmd_hdl_debug(hdl, "\n%s: cpu_id = %d creating fault %s\n",
1845*10784Ssinanallur.balasubramanian@sun.com 	    cache_ed->ed_fltnm, cpu->cpu_cpuid,
1846*10784Ssinanallur.balasubramanian@sun.com 	    Lxcache->Lxcache_case.cc_serdnm);
1847*10784Ssinanallur.balasubramanian@sun.com 	fmd_case_add_serd(hdl, Lxcache->Lxcache_case.cc_cp,
1848*10784Ssinanallur.balasubramanian@sun.com 	    Lxcache->Lxcache_case.cc_serdnm);
1849*10784Ssinanallur.balasubramanian@sun.com 	fmd_serd_reset(hdl, Lxcache->Lxcache_case.cc_serdnm);
1850*10784Ssinanallur.balasubramanian@sun.com 	/*
1851*10784Ssinanallur.balasubramanian@sun.com 	 * Find out if there is a way at the fault index/bit that was retired
1852*10784Ssinanallur.balasubramanian@sun.com 	 * as suspect. We need this information for both anonymous way and
1853*10784Ssinanallur.balasubramanian@sun.com 	 * identified way handling. We store this info in suspect_Lxcache.
1854*10784Ssinanallur.balasubramanian@sun.com 	 */
1855*10784Ssinanallur.balasubramanian@sun.com 	fmd_hdl_debug(hdl,
1856*10784Ssinanallur.balasubramanian@sun.com 	    "\n%s:cpu_id %d checking if there is a way at"
1857*10784Ssinanallur.balasubramanian@sun.com 	    " index %d retired as suspect due to bit %d\n",
1858*10784Ssinanallur.balasubramanian@sun.com 	    cache_ed->ed_fltnm, cpu->cpu_cpuid,
1859*10784Ssinanallur.balasubramanian@sun.com 	    Lxcache->Lxcache_index, Lxcache->Lxcache_bit);
1860*10784Ssinanallur.balasubramanian@sun.com 	suspect_Lxcache = cmd_Lxcache_lookup_by_type_index_bit_reason(
1861*10784Ssinanallur.balasubramanian@sun.com 	    cpu, type, Lxcache->Lxcache_index, Lxcache->Lxcache_bit,
1862*10784Ssinanallur.balasubramanian@sun.com 	    CMD_LXSUSPECT_DATA);
1863*10784Ssinanallur.balasubramanian@sun.com 	if (xr->xr_error_way != (uint32_t)CMD_ANON_WAY) {
1864*10784Ssinanallur.balasubramanian@sun.com 		/*
1865*10784Ssinanallur.balasubramanian@sun.com 		 * IDENTIFIED WAY DATA error handling.
1866*10784Ssinanallur.balasubramanian@sun.com 		 *
1867*10784Ssinanallur.balasubramanian@sun.com 		 * If there is a way at that index retired as suspect due
1868*10784Ssinanallur.balasubramanian@sun.com 		 * to that bit, unretire it.
1869*10784Ssinanallur.balasubramanian@sun.com 		 * retire the identified way, and mark the way as "convicted"
1870*10784Ssinanallur.balasubramanian@sun.com 		 * for this bit. Destroy any anonymous SERD engine named by
1871*10784Ssinanallur.balasubramanian@sun.com 		 * that index and bit.
1872*10784Ssinanallur.balasubramanian@sun.com 		 */
1873*10784Ssinanallur.balasubramanian@sun.com 		if (suspect_Lxcache != NULL) {
18746330Sjc25722 			fmd_hdl_debug(hdl,
1875*10784Ssinanallur.balasubramanian@sun.com 			    "\n%s:cpu_id %d found index %d way %d"
1876*10784Ssinanallur.balasubramanian@sun.com 			    " bit %d retired on suspicion. Will"
1877*10784Ssinanallur.balasubramanian@sun.com 			    "  unretire this now.\n",
1878*10784Ssinanallur.balasubramanian@sun.com 			    cache_ed->ed_fltnm, cpu->cpu_cpuid,
1879*10784Ssinanallur.balasubramanian@sun.com 			    suspect_Lxcache->Lxcache_index,
1880*10784Ssinanallur.balasubramanian@sun.com 			    suspect_Lxcache->Lxcache_way,
1881*10784Ssinanallur.balasubramanian@sun.com 			    suspect_Lxcache->Lxcache_bit);
1882*10784Ssinanallur.balasubramanian@sun.com 			/*
1883*10784Ssinanallur.balasubramanian@sun.com 			 * unretire the retired_way.
1884*10784Ssinanallur.balasubramanian@sun.com 			 */
1885*10784Ssinanallur.balasubramanian@sun.com 			if (cmd_Lxcache_unretire(hdl, cpu, suspect_Lxcache,
1886*10784Ssinanallur.balasubramanian@sun.com 			    cache_ed->ed_fltnm) == B_TRUE) {
1887*10784Ssinanallur.balasubramanian@sun.com 				suspect_Lxcache->Lxcache_reason =
1888*10784Ssinanallur.balasubramanian@sun.com 				    CMD_LXFUNCTIONING;
1889*10784Ssinanallur.balasubramanian@sun.com 				cmd_Lxcache_destroy(hdl, cpu, suspect_Lxcache);
18906330Sjc25722 			}
18916330Sjc25722 			/*
1892*10784Ssinanallur.balasubramanian@sun.com 			 * We proceed to retire the identified way even if
1893*10784Ssinanallur.balasubramanian@sun.com 			 * we are unable to unretire the suspect way.
1894*10784Ssinanallur.balasubramanian@sun.com 			 * We will not end up retiring all 4 ways because
1895*10784Ssinanallur.balasubramanian@sun.com 			 * we check the actual number of ways retired
1896*10784Ssinanallur.balasubramanian@sun.com 			 * at this index by reading the info from processor
1897*10784Ssinanallur.balasubramanian@sun.com 			 * directly. The call to get_index_retired_ways() does
1898*10784Ssinanallur.balasubramanian@sun.com 			 * that.
18996330Sjc25722 			 */
1900*10784Ssinanallur.balasubramanian@sun.com 		}
1901*10784Ssinanallur.balasubramanian@sun.com 		/*
1902*10784Ssinanallur.balasubramanian@sun.com 		 * Before retiring a way check if we have already
1903*10784Ssinanallur.balasubramanian@sun.com 		 * retired 3 ways for this index.
1904*10784Ssinanallur.balasubramanian@sun.com 		 */
1905*10784Ssinanallur.balasubramanian@sun.com 		ways_retired = get_index_retired_ways(cpu, type,
1906*10784Ssinanallur.balasubramanian@sun.com 		    Lxcache->Lxcache_index);
1907*10784Ssinanallur.balasubramanian@sun.com 		if (ways_retired == -1) {
1908*10784Ssinanallur.balasubramanian@sun.com 			fmd_hdl_debug(hdl,
1909*10784Ssinanallur.balasubramanian@sun.com 			    "\n%s: cpu %d: We are unable to determine how many"
1910*10784Ssinanallur.balasubramanian@sun.com 			    " ways are retired at this index. We will not be"
1911*10784Ssinanallur.balasubramanian@sun.com 			    " retiring the identified cacheline at index %d"
1912*10784Ssinanallur.balasubramanian@sun.com 			    " way %d\n",
1913*10784Ssinanallur.balasubramanian@sun.com 			    cache_ed->ed_fltnm, cpu->cpu_cpuid,
1914*10784Ssinanallur.balasubramanian@sun.com 			    Lxcache->Lxcache_index, Lxcache->Lxcache_way);
1915*10784Ssinanallur.balasubramanian@sun.com 			return (CMD_EVD_BAD);
1916*10784Ssinanallur.balasubramanian@sun.com 		}
1917*10784Ssinanallur.balasubramanian@sun.com 		if (ways_retired >= 3) {
1918*10784Ssinanallur.balasubramanian@sun.com 			fmd_hdl_debug(hdl,
1919*10784Ssinanallur.balasubramanian@sun.com 			    "\n%s: cpu %d: num of ways retired for index %d"
1920*10784Ssinanallur.balasubramanian@sun.com 			    " is %d. Will fault the CPU\n",
1921*10784Ssinanallur.balasubramanian@sun.com 			    cache_ed->ed_fltnm, cpu->cpu_cpuid,
1922*10784Ssinanallur.balasubramanian@sun.com 			    Lxcache->Lxcache_index, ways_retired);
1923*10784Ssinanallur.balasubramanian@sun.com 			cmd_fault_the_cpu(hdl, cpu, type, cache_ed->ed_fltnm);
1924*10784Ssinanallur.balasubramanian@sun.com 			return (CMD_EVD_OK);
19256330Sjc25722 		}
1926*10784Ssinanallur.balasubramanian@sun.com 		/*
1927*10784Ssinanallur.balasubramanian@sun.com 		 * retire the cache line
1928*10784Ssinanallur.balasubramanian@sun.com 		 */
1929*10784Ssinanallur.balasubramanian@sun.com 		ret = cmd_Lxcache_retire_as_reason(hdl, cpu, Lxcache,
1930*10784Ssinanallur.balasubramanian@sun.com 		    cache_ed->ed_fltnm, CMD_LXCONVICTED);
1931*10784Ssinanallur.balasubramanian@sun.com 		if (ret != CMD_EVD_OK)
1932*10784Ssinanallur.balasubramanian@sun.com 			return (ret);
1933*10784Ssinanallur.balasubramanian@sun.com 		/*
1934*10784Ssinanallur.balasubramanian@sun.com 		 * anonymous serd engines for DATA faults will have valid bit
1935*10784Ssinanallur.balasubramanian@sun.com 		 * but way as -1.
1936*10784Ssinanallur.balasubramanian@sun.com 		 */
1937*10784Ssinanallur.balasubramanian@sun.com 		cmd_Lxcache_destroy_anonymous_serd_engines(hdl, cpu, type,
1938*10784Ssinanallur.balasubramanian@sun.com 		    Lxcache->Lxcache_index,
1939*10784Ssinanallur.balasubramanian@sun.com 		    bit);
1940*10784Ssinanallur.balasubramanian@sun.com 		return (CMD_EVD_OK);
1941*10784Ssinanallur.balasubramanian@sun.com 	}	/* end of IDENTIFIED WAY error handling */
19426330Sjc25722 	/*
1943*10784Ssinanallur.balasubramanian@sun.com 	 * ANONYMOUS WAY DATA error handling.
1944*10784Ssinanallur.balasubramanian@sun.com 	 *
1945*10784Ssinanallur.balasubramanian@sun.com 	 * - if a way at this index has already been retired as "suspect"
1946*10784Ssinanallur.balasubramanian@sun.com 	 * for this bit, unretire that way, and retire the next retirable
1947*10784Ssinanallur.balasubramanian@sun.com 	 * way as "suspect" for this bit.
1948*10784Ssinanallur.balasubramanian@sun.com 	 * - if no ways have been retired as "suspect" for this bit,
1949*10784Ssinanallur.balasubramanian@sun.com 	 * retire the lowest unretired way as "suspect" for this bit.
1950*10784Ssinanallur.balasubramanian@sun.com 	 * - if there is no next retirable way, fault the CPU.
19516330Sjc25722 	 */
1952*10784Ssinanallur.balasubramanian@sun.com 	/*
1953*10784Ssinanallur.balasubramanian@sun.com 	 * The assignment below is to make the code easier to maintain.
1954*10784Ssinanallur.balasubramanian@sun.com 	 * We need to destroy the anonymous_Lxcache after we have
1955*10784Ssinanallur.balasubramanian@sun.com 	 * identifed a way to retire. If we cannot detrmine a way to
1956*10784Ssinanallur.balasubramanian@sun.com 	 * retire we will destrory the anonymous_Lxcache and fault the cpu.
1957*10784Ssinanallur.balasubramanian@sun.com 	 */
1958*10784Ssinanallur.balasubramanian@sun.com 	anonymous_Lxcache = Lxcache;
1959*10784Ssinanallur.balasubramanian@sun.com 	anonymous_Lxcache->Lxcache_ep = ep;
1960*10784Ssinanallur.balasubramanian@sun.com 	if (suspect_Lxcache != NULL) {
1961*10784Ssinanallur.balasubramanian@sun.com 		ret = unretire_suspect_and_retire_next_retirable_way(hdl,
1962*10784Ssinanallur.balasubramanian@sun.com 		    cpu, suspect_Lxcache, anonymous_Lxcache,
1963*10784Ssinanallur.balasubramanian@sun.com 		    cache_ed->ed_fltnm);
1964*10784Ssinanallur.balasubramanian@sun.com 	} else {
1965*10784Ssinanallur.balasubramanian@sun.com 		ret = retire_lowest_retirable_way_as_suspect(hdl, cpu,
1966*10784Ssinanallur.balasubramanian@sun.com 		    anonymous_Lxcache, cache_ed->ed_fltnm);
19676330Sjc25722 	}
1968*10784Ssinanallur.balasubramanian@sun.com 	return (ret);
19696330Sjc25722 }
19706330Sjc25722 
19716330Sjc25722 /* ARGSUSED */
19726330Sjc25722 int
cmd_xr_pn_cache_fill(fmd_hdl_t * hdl,nvlist_t * nvl,cmd_xr_t * xr,cmd_cpu_t * cpu,cmd_errcl_t clcode)19736330Sjc25722 cmd_xr_pn_cache_fill(fmd_hdl_t *hdl, nvlist_t *nvl, cmd_xr_t *xr,
19746330Sjc25722     cmd_cpu_t *cpu, cmd_errcl_t clcode)
19756330Sjc25722 {
19766330Sjc25722 	struct ch_ec_data *data_ptr;
1977*10784Ssinanallur.balasubramanian@sun.com 	uint64_t *cache_data = NULL;
19786330Sjc25722 	uint_t sz;
19796330Sjc25722 
19806330Sjc25722 	if (cpu->cpu_pers.cpup_type != CPU_ULTRASPARC_IVplus)
19816330Sjc25722 		return (0);
19826330Sjc25722 
19836330Sjc25722 	if (nvlist_lookup_nvlist(nvl, FM_EREPORT_DETECTOR,
1984*10784Ssinanallur.balasubramanian@sun.com 	    &xr->xr_detector_nvlist) != 0) {
1985*10784Ssinanallur.balasubramanian@sun.com 		fmd_hdl_debug(hdl, "look up for FM_EREPORT_DETECTOR failed\n");
19866330Sjc25722 		return (-1);
1987*10784Ssinanallur.balasubramanian@sun.com 	}
19886330Sjc25722 	if (nvlist_lookup_uint64(nvl, FM_EREPORT_PAYLOAD_NAME_AFSR,
1989*10784Ssinanallur.balasubramanian@sun.com 	    &xr->xr_afsr) != 0) {
1990*10784Ssinanallur.balasubramanian@sun.com 		fmd_hdl_debug(hdl,
1991*10784Ssinanallur.balasubramanian@sun.com 		    "look up for FM_EREPORT_PAYLOAD_NAME_AFSR failed\n");
19926330Sjc25722 		return (-1);
1993*10784Ssinanallur.balasubramanian@sun.com 	}
19946330Sjc25722 
19956330Sjc25722 	/* check clcode for l2/l3 first */
19966330Sjc25722 	if (CMD_ERRCL_ISL3XXCU(clcode)) {
19976330Sjc25722 		if (nvlist_lookup_uint8(nvl, FM_EREPORT_PAYLOAD_NAME_L3_WAYS,
1998*10784Ssinanallur.balasubramanian@sun.com 		    &xr->xr_num_ways) != 0) {
1999*10784Ssinanallur.balasubramanian@sun.com 			fmd_hdl_debug(hdl,
2000*10784Ssinanallur.balasubramanian@sun.com 		    "look up for FM_EREPORT_PAYLOAD_NAME_L3_WAYS failed\n");
20016330Sjc25722 			return (-1);
2002*10784Ssinanallur.balasubramanian@sun.com 		}
20036330Sjc25722 
20046330Sjc25722 		if (nvlist_lookup_uint64_array(nvl,
20056330Sjc25722 		    FM_EREPORT_PAYLOAD_NAME_L3_DATA, (uint64_t **)&cache_data,
2006*10784Ssinanallur.balasubramanian@sun.com 		    &sz) != 0) {
2007*10784Ssinanallur.balasubramanian@sun.com 			fmd_hdl_debug(hdl,
2008*10784Ssinanallur.balasubramanian@sun.com 		    "look up for FM_EREPORT_PAYLOAD_NAME_L3_DATA failed\n");
2009*10784Ssinanallur.balasubramanian@sun.com 		}
20106330Sjc25722 	} else {
20116330Sjc25722 		if (nvlist_lookup_uint8(nvl, FM_EREPORT_PAYLOAD_NAME_L2_WAYS,
2012*10784Ssinanallur.balasubramanian@sun.com 		    &xr->xr_num_ways) != 0) {
2013*10784Ssinanallur.balasubramanian@sun.com 			fmd_hdl_debug(hdl,
2014*10784Ssinanallur.balasubramanian@sun.com 		    "look up for FM_EREPORT_PAYLOAD_NAME_L2_WAYS failed\n");
20156330Sjc25722 			return (-1);
2016*10784Ssinanallur.balasubramanian@sun.com 		}
20176330Sjc25722 
20186330Sjc25722 		if (nvlist_lookup_uint64_array(nvl,
20196330Sjc25722 		    FM_EREPORT_PAYLOAD_NAME_L2_DATA, (uint64_t **)&cache_data,
2020*10784Ssinanallur.balasubramanian@sun.com 		    &sz) != 0) {
2021*10784Ssinanallur.balasubramanian@sun.com 			fmd_hdl_debug(hdl,
2022*10784Ssinanallur.balasubramanian@sun.com 		    "look up for FM_EREPORT_PAYLOAD_NAME_L2_DATA failed\n");
2023*10784Ssinanallur.balasubramanian@sun.com 		}
20246330Sjc25722 	}
2025*10784Ssinanallur.balasubramanian@sun.com 	if (xr->xr_num_ways > PN_CACHE_NWAYS) {
2026*10784Ssinanallur.balasubramanian@sun.com 		fmd_hdl_debug(hdl,
2027*10784Ssinanallur.balasubramanian@sun.com 		    "xr_num_ways > PN_CACHE_WAYS\n");
20286330Sjc25722 		return (-1);
2029*10784Ssinanallur.balasubramanian@sun.com 	}
20306330Sjc25722 
20316330Sjc25722 	xr->xr_cache_data = cache_data;
20326330Sjc25722 	data_ptr = (struct ch_ec_data *)cache_data;
2033*10784Ssinanallur.balasubramanian@sun.com 	if (cache_data == NULL) {
2034*10784Ssinanallur.balasubramanian@sun.com 		xr->xr_error_way = (uint32_t)CMD_ANON_WAY;
2035*10784Ssinanallur.balasubramanian@sun.com 		return (0);
20366330Sjc25722 	}
2037*10784Ssinanallur.balasubramanian@sun.com 
2038*10784Ssinanallur.balasubramanian@sun.com 	/*
2039*10784Ssinanallur.balasubramanian@sun.com 	 * Our error handler checks for a matching valid way
2040*10784Ssinanallur.balasubramanian@sun.com 	 * If there is a match, there is only 1 data set, the set
2041*10784Ssinanallur.balasubramanian@sun.com 	 * associated with the cache-line/way that was "valid"
2042*10784Ssinanallur.balasubramanian@sun.com 	 * Otherwise, it stores all of the ways
2043*10784Ssinanallur.balasubramanian@sun.com 	 */
2044*10784Ssinanallur.balasubramanian@sun.com 	xr->xr_error_tag = data_ptr[0].ec_tag;
2045*10784Ssinanallur.balasubramanian@sun.com 	xr->xr_error_way = (uint32_t)data_ptr[0].ec_way;
2046*10784Ssinanallur.balasubramanian@sun.com 
20476330Sjc25722 	/* If there is more than 1 way structure, set way to Anonymous */
20486330Sjc25722 	if (xr->xr_num_ways > 1)
20496330Sjc25722 		xr->xr_error_way = (uint32_t)CMD_ANON_WAY;
20506330Sjc25722 
20516330Sjc25722 	return (0);
20526330Sjc25722 }
2053