1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#include <cma.h>
27#include <fcntl.h>
28#include <strings.h>
29#include <unistd.h>
30#include <errno.h>
31#include <fm/fmd_api.h>
32#include <sys/fm/protocol.h>
33#include <sys/mem_cache.h>
34
35int
36/* ARGSUSED 4 */
37cma_cache_way_retire(fmd_hdl_t *hdl, nvlist_t *nvl, nvlist_t *asru,
38    const char *uuid, boolean_t repair)
39{
40	uint_t 		cpuid;
41	uint32_t 	way;
42	uint32_t	index;
43	uint16_t	bit = 0;
44	uint8_t		type;
45	cache_info_t    cache_info;
46	int ret, fd;
47	int	err;
48
49	fmd_hdl_debug(hdl, "cpu cache *line* fault processing\n");
50	fmd_hdl_debug(hdl, "asru %lx\n", asru);
51
52	/*
53	 * This added expansion is needed to cover the situation where a
54	 * cpu fault from the resource cache is replayed at fmd restart,
55	 * and the cpu resource has been remapped or replaced.  The stored
56	 * FMRI is expanded, but may have stale data.
57	 */
58
59	if (fmd_nvl_fmri_expand(hdl, asru) < 0) {
60		fmd_hdl_debug(hdl, "failed to expand cpu asru\n");
61		cma_stats.bad_flts.fmds_value.ui64++;
62		return (CMA_RA_FAILURE);
63	}
64
65	if (nvlist_lookup_uint32(asru, FM_FMRI_CPU_ID, &cpuid) != 0) {
66		fmd_hdl_debug(hdl, "cpu cache fault missing '%s'\n",
67		    FM_FMRI_CPU_ID);
68		cma_stats.bad_flts.fmds_value.ui64++;
69		return (CMA_RA_FAILURE);
70	}
71
72	if (nvlist_lookup_uint32(asru, FM_FMRI_CPU_CACHE_INDEX, &index) != 0) {
73		fmd_hdl_debug(hdl, "cpu cache fault missing '%s'\n",
74		    FM_FMRI_CPU_CACHE_INDEX);
75		cma_stats.bad_flts.fmds_value.ui64++;
76		return (CMA_RA_FAILURE);
77	}
78
79	if (nvlist_lookup_uint32(asru, FM_FMRI_CPU_CACHE_WAY, &way) != 0) {
80		fmd_hdl_debug(hdl, "cpu cache fault missing '%s'\n",
81		    FM_FMRI_CPU_CACHE_WAY);
82		cma_stats.bad_flts.fmds_value.ui64++;
83		return (CMA_RA_FAILURE);
84	}
85
86	if (nvlist_lookup_uint8(asru, FM_FMRI_CPU_CACHE_TYPE, &type) != 0) {
87		fmd_hdl_debug(hdl, "cpu cache fault missing '%s'\n",
88		    FM_FMRI_CPU_CACHE_TYPE);
89		cma_stats.bad_flts.fmds_value.ui64++;
90		return (CMA_RA_FAILURE);
91	}
92
93	/*
94	 * Tag faults will use it to set the bit to a stable state
95	 */
96
97	if (nvlist_lookup_uint16(asru, FM_FMRI_CPU_CACHE_BIT, &bit) != 0) {
98		fmd_hdl_debug(hdl, "cpu cache fault missing '%s'\n",
99		    FM_FMRI_CPU_CACHE_BIT);
100		cma_stats.bad_flts.fmds_value.ui64++;
101		return (CMA_RA_FAILURE);
102	}
103	if (repair) {
104		fmd_hdl_debug(hdl,
105		    "cpu %d: Unretire for index %d, way %d\n bit %d"
106		    " type 0x%02x is being called now. We will not unretire"
107		    " cacheline. This message is for information.\n",
108		    cpuid, index, way, bit, type);
109		/*
110		 * The DE will do the actual unretire.
111		 * The agent is called because the DE informs the fmd
112		 * that the resource is repaired.
113		 */
114		return (CMA_RA_SUCCESS);
115	}
116	fmd_hdl_debug(hdl,
117	    "cpu %d: Retiring index %d, way %d\n bit %d"
118	    " type 0x%02x", cpuid, index, way, bit, type);
119	fd = open(mem_cache_device, O_RDWR);
120	if (fd == -1) {
121		fmd_hdl_debug(hdl, "Driver open failed\n");
122		return (CMA_RA_FAILURE);
123	}
124	cache_info.cpu_id = cpuid;
125	cache_info.way = way;
126	cache_info.bit = bit;
127	cache_info.index = index;
128	cache_info.cache = type == FM_FMRI_CPU_CACHE_TYPE_L3 ?
129	    L3_CACHE_DATA : L2_CACHE_DATA;
130
131	ret = ioctl(fd, MEM_CACHE_RETIRE, &cache_info);
132	/*
133	 * save errno before we call close.
134	 * Need errno to display the error if ioctl fails.
135	 */
136	err = errno;
137	(void) close(fd);
138	if (ret == -1) {
139		fmd_hdl_debug(hdl, "Driver call failed errno = %d\n", err);
140		return (CMA_RA_FAILURE);
141	}
142	return (CMA_RA_SUCCESS);
143}
144