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.
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.
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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
31 #include <fm/fmd_api.h>
32 #include <sys/fm/protocol.h>
33 #include <sys/async.h>
36 #include <cmd_state.h>
39 #include <cmd_dp_page.h>
40 #include <libnvpair.h>
44 #include <sys/plat_datapath.h>
48 dp_cpu_fmri(fmd_hdl_t
*hdl
, uint32_t cpuid
, uint64_t serial_id
)
52 char sbuf
[21]; /* sizeof (UINT64_MAX) + '\0' */
54 if (nvlist_alloc(&nvl
, NV_UNIQUE_NAME
, 0) != 0)
57 err
= nvlist_add_string(nvl
, FM_FMRI_SCHEME
, FM_FMRI_SCHEME_CPU
);
58 err
|= nvlist_add_uint8(nvl
, FM_VERSION
, FM_CPU_SCHEME_VERSION
);
59 err
|= nvlist_add_uint32(nvl
, FM_FMRI_CPU_ID
, cpuid
);
62 * Version 1 calls for a string-based serial number
64 (void) snprintf(sbuf
, sizeof (sbuf
), "%llX", (u_longlong_t
)serial_id
);
65 err
|= nvlist_add_string(nvl
, FM_FMRI_CPU_SERIAL_ID
, sbuf
);
74 cmd_dp_lookup_fault(fmd_hdl_t
*hdl
, uint32_t cpuid
)
80 * Scan the cmd.cmd_datapaths list to see if there is
81 * a fault event present that impacts 'cpuid'
83 for (ptr
= cmd_list_next(&cmd
.cmd_datapaths
); ptr
!= NULL
;
84 ptr
= cmd_list_next(ptr
)) {
85 if (ptr
->dp_erpt_type
== DP_FAULT
) {
86 for (i
= 0; i
< ptr
->dp_ncpus
; i
++) {
87 if (ptr
->dp_cpuid_list
[i
] == cpuid
) {
98 * Check if the FMRI for the found cpuid exists in the domain.
99 * If it does not, it implies a DR has been done and this DP_FAULT
100 * is no longer needed.
105 nvl
= dp_cpu_fmri(hdl
, ptr
->dp_cpuid_list
[i
],
106 ptr
->dp_serid_list
[i
]);
109 if (!fmd_nvl_fmri_present(hdl
, nvl
)) {
110 cmd_dp_destroy(hdl
, ptr
);
120 cmd_dp_lookup_error(cmd_dp_t
*dp
)
125 * Scan the cmd.cmd_datapaths list to see if there is
126 * an existing error that matches 'dp'. A match is if
127 * both dp_err and the base cpuid are identical
129 for (ptr
= cmd_list_next(&cmd
.cmd_datapaths
); ptr
!= NULL
;
130 ptr
= cmd_list_next(ptr
)) {
131 if (ptr
->dp_erpt_type
== DP_ERROR
) {
132 if ((ptr
->dp_err
== dp
->dp_err
) &&
133 (ptr
->dp_cpuid_list
[0] == dp
->dp_cpuid_list
[0]))
141 * Allocates an nvlist_t, and sets ASRU information according to
142 * the cmd_dp_t provided.
146 cmd_dp_setasru(fmd_hdl_t
*hdl
, cmd_dp_t
*dpt
)
148 nvlist_t
*asru
, *hcelem
[DP_MAX_ASRUS
];
150 char buf
[DP_MAX_BUF
];
154 /* put ASRUs in an nvlist */
155 for (i
= 0; i
< sz
; i
++) {
156 (void) snprintf(buf
, DP_MAX_BUF
, "%d", dpt
->dp_cpuid_list
[i
]);
157 if (nvlist_alloc(&hcelem
[i
], NV_UNIQUE_NAME
, 0) != 0)
160 err
= nvlist_add_string(hcelem
[i
], FM_FMRI_HC_NAME
,
162 err
|= nvlist_add_string(hcelem
[i
], FM_FMRI_HC_ID
, buf
);
164 for (j
= 0; j
< i
+ 1; j
++)
165 nvlist_free(hcelem
[j
]);
170 /* put it in an HC scheme */
171 if (nvlist_alloc(&asru
, NV_UNIQUE_NAME
, 0) != 0) {
172 for (j
= 0; j
< sz
; j
++)
173 nvlist_free(hcelem
[j
]);
176 err
= nvlist_add_uint8(asru
, FM_VERSION
, FM_HC_SCHEME_VERSION
);
177 err
|= nvlist_add_string(asru
, FM_FMRI_SCHEME
, FM_FMRI_SCHEME_HC
);
178 err
|= nvlist_add_string(asru
, FM_FMRI_HC_ROOT
, "");
179 err
|= nvlist_add_uint32(asru
, FM_FMRI_HC_LIST_SZ
, sz
);
180 err
|= nvlist_add_nvlist_array(asru
, FM_FMRI_HC_LIST
, &hcelem
[0],
183 for (j
= 0; j
< sz
; j
++)
184 nvlist_free(hcelem
[j
]);
190 for (j
= 0; j
< sz
; j
++)
191 nvlist_free(hcelem
[j
]);
193 /* return the ASRU */
198 dp_buf_write(fmd_hdl_t
*hdl
, cmd_dp_t
*dp
)
202 if ((sz
= fmd_buf_size(hdl
, NULL
, dp
->dp_bufname
)) != 0 &&
203 sz
!= sizeof (cmd_dp_pers_t
))
204 fmd_buf_destroy(hdl
, NULL
, dp
->dp_bufname
);
206 fmd_buf_write(hdl
, NULL
, dp
->dp_bufname
, &dp
->dp_pers
,
207 sizeof (cmd_dp_pers_t
));
211 dp_wrapv0(fmd_hdl_t
*hdl
, cmd_dp_pers_t
*pers
, size_t psz
)
215 if (psz
!= sizeof (cmd_dp_pers_t
)) {
216 fmd_hdl_abort(hdl
, "size of state doesn't match size of "
217 "version 1 state (%u bytes).\n", sizeof (cmd_dp_pers_t
));
220 dp
= fmd_hdl_zalloc(hdl
, sizeof (cmd_dp_t
), FMD_SLEEP
);
221 bcopy(pers
, dp
, sizeof (cmd_dp_pers_t
));
222 fmd_hdl_free(hdl
, pers
, psz
);
227 cmd_dp_restore(fmd_hdl_t
*hdl
, fmd_case_t
*cp
, cmd_case_ptr_t
*ptr
)
231 for (dp
= cmd_list_next(&cmd
.cmd_datapaths
); dp
!= NULL
;
232 dp
= cmd_list_next(dp
)) {
233 if (dp
->dp_case
== cp
)
240 fmd_hdl_debug(hdl
, "restoring dp from %s\n", ptr
->ptr_name
);
242 if ((dpsz
= fmd_buf_size(hdl
, NULL
, ptr
->ptr_name
)) == 0) {
243 if (fmd_case_solved(hdl
, cp
) ||
244 fmd_case_closed(hdl
, cp
)) {
245 fmd_hdl_debug(hdl
, "dp %s from case %s not "
246 "found. Case is already solved or closed\n",
247 ptr
->ptr_name
, fmd_case_uuid(hdl
, cp
));
250 fmd_hdl_abort(hdl
, "dp referenced by case %s "
251 "does not exist in saved state\n",
252 fmd_case_uuid(hdl
, cp
));
254 } else if (dpsz
> CMD_DP_MAXSIZE
||
255 dpsz
< CMD_DP_MINSIZE
) {
256 fmd_hdl_abort(hdl
, "dp buffer referenced by "
257 "case %s is out of bounds (is %u bytes, "
258 "max %u, min %u)\n", fmd_case_uuid(hdl
, cp
),
259 dpsz
, CMD_DP_MAXSIZE
, CMD_DP_MINSIZE
);
262 if ((dp
= cmd_buf_read(hdl
, NULL
, ptr
->ptr_name
, dpsz
)) == NULL
)
263 fmd_hdl_abort(hdl
, "failed to read dp buf %s",
266 switch (dp
->dp_version
) {
267 case CMD_DP_VERSION_0
:
268 dp
= dp_wrapv0(hdl
, (cmd_dp_pers_t
*)dp
, dpsz
);
271 fmd_hdl_abort(hdl
, "unknown version (found %d) "
272 "for dp state referenced by case %s.\n",
273 dp
->dp_version
, fmd_case_uuid(hdl
, cp
));
279 if (dp
->dp_erpt_type
== DP_ERROR
) {
280 fmd_event_t
*ep
= fmd_case_getprincipal(hdl
, cp
);
284 dp
->dp_id
= fmd_timer_install(hdl
,
285 (void *)CMD_TIMERTYPE_DP
, ep
,
286 (hrtime_t
)NANOSEC
* (dp
->dp_t_value
+ 120));
289 cmd_list_append(&cmd
.cmd_datapaths
, dp
);
296 cmd_dp_close(fmd_hdl_t
*hdl
, void *arg
)
298 cmd_dp_destroy(hdl
, arg
);
302 cmd_dp_timeout(fmd_hdl_t
*hdl
, id_t id
)
306 /* close case associated with the timer */
307 for (dp
= cmd_list_next(&cmd
.cmd_datapaths
); dp
!= NULL
;
308 dp
= cmd_list_next(dp
)) {
309 if (dp
->dp_id
== id
) {
310 cmd_dp_destroy(hdl
, dp
);
315 fmd_hdl_debug(hdl
, "cmd_dp_timeout() complete\n");
319 * Validate by matching each cmd_dp_t cpu and serial id to what is
320 * installed and active on this machine or domain. Delete the cmd_dp_t
321 * if no match is made.
324 cmd_dp_validate(fmd_hdl_t
*hdl
)
330 for (dp
= cmd_list_next(&cmd
.cmd_datapaths
); dp
!= NULL
; dp
= next
) {
331 next
= cmd_list_next(dp
);
333 for (i
= 0, no_match
= 0; i
< dp
->dp_ncpus
; i
++) {
334 nvl
= dp_cpu_fmri(hdl
, dp
->dp_cpuid_list
[i
],
335 dp
->dp_serid_list
[i
]);
338 fmd_hdl_abort(hdl
, "could not make CPU fmri");
340 if (!fmd_nvl_fmri_present(hdl
, nvl
))
346 cmd_dp_destroy(hdl
, dp
);
354 cmd_dp_free(fmd_hdl_t
*hdl
, cmd_dp_t
*dp
, int destroy
)
356 if (dp
->dp_case
!= NULL
)
357 cmd_case_fini(hdl
, dp
->dp_case
, destroy
);
359 if (destroy
&& dp
->dp_erpt_type
== DP_ERROR
) {
362 * If there are no active datapath events, replay any
363 * pages that were deferred.
365 if (cmd
.cmd_dp_flag
== 0)
366 cmd_dp_page_replay(hdl
);
370 fmd_buf_destroy(hdl
, NULL
, dp
->dp_bufname
);
372 cmd_list_delete(&cmd
.cmd_datapaths
, dp
);
373 fmd_hdl_free(hdl
, dp
, sizeof (cmd_dp_t
));
377 cmd_dp_destroy(fmd_hdl_t
*hdl
, cmd_dp_t
*dp
)
379 cmd_dp_free(hdl
, dp
, FMD_B_TRUE
);
384 cmd_dp_error(fmd_hdl_t
*hdl
)
393 cmd_dp_get_mcid(uint64_t addr
, int *mcid
)
398 if ((fd
= open("/dev/mem", O_RDONLY
)) < 0)
403 if ((rc
= ioctl(fd
, MEM_INFO
, &data
)) < 0) {
416 cmd_dp_fault(fmd_hdl_t
*hdl
, uint64_t addr
)
420 if (cmd_dp_get_mcid(addr
, &mcid
) < 0)
421 fmd_hdl_abort(hdl
, "cmd_dp_get_mcid failed");
423 if (cmd_dp_lookup_fault(hdl
, mcid
) != NULL
)
430 cmd_dp_fini(fmd_hdl_t
*hdl
)
433 cmd_dp_defer_t
*dpage
;
435 while ((dp
= cmd_list_next(&cmd
.cmd_datapaths
)) != NULL
)
436 cmd_dp_free(hdl
, dp
, FMD_B_FALSE
);
438 while ((dpage
= cmd_list_next(&cmd
.cmd_deferred_pages
)) != NULL
) {
439 cmd_list_delete(&cmd
.cmd_deferred_pages
, dpage
);
440 fmd_hdl_free(hdl
, dpage
, sizeof (cmd_dp_defer_t
));