12535165Vuong Nguyen/*
22535165Vuong Nguyen * CDDL HEADER START
32535165Vuong Nguyen *
42535165Vuong Nguyen * The contents of this file are subject to the terms of the
52535165Vuong Nguyen * Common Development and Distribution License (the "License").
62535165Vuong Nguyen * You may not use this file except in compliance with the License.
72535165Vuong Nguyen *
82535165Vuong Nguyen * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92535165Vuong Nguyen * or http://www.opensolaris.org/os/licensing.
102535165Vuong Nguyen * See the License for the specific language governing permissions
112535165Vuong Nguyen * and limitations under the License.
122535165Vuong Nguyen *
132535165Vuong Nguyen * When distributing Covered Code, include this CDDL HEADER in each
142535165Vuong Nguyen * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152535165Vuong Nguyen * If applicable, add the following below this CDDL HEADER, with the
162535165Vuong Nguyen * fields enclosed by brackets "[]" replaced with your own identifying
172535165Vuong Nguyen * information: Portions Copyright [yyyy] [name of copyright owner]
182535165Vuong Nguyen *
192535165Vuong Nguyen * CDDL HEADER END
202535165Vuong Nguyen */
212535165Vuong Nguyen
222535165Vuong Nguyen/*
232535165Vuong Nguyen * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
242535165Vuong Nguyen * Use is subject to license terms.
252535165Vuong Nguyen */
262535165Vuong Nguyen
272535165Vuong Nguyen/*
282535165Vuong Nguyen * etm_ckpt.c
292535165Vuong Nguyen * Description:
302535165Vuong Nguyen *    Checkpoint the ereport events for persitence across fmd restart.
312535165Vuong Nguyen *
322535165Vuong Nguyen *    Each ereport is stored in a named buffer. Each ereport is uniquely
332535165Vuong Nguyen *    indentified by a id which is consists of a number of ereport fields. The
342535165Vuong Nguyen *    name of the buffer is derived from the id.
352535165Vuong Nguyen *
362535165Vuong Nguyen *    All ereport ids are stored in the circular list which is saved in a
372535165Vuong Nguyen *    separate buffer.
382535165Vuong Nguyen */
392535165Vuong Nguyen
402535165Vuong Nguyen#include <assert.h>
412535165Vuong Nguyen#include <stdio.h>
422535165Vuong Nguyen#include <pthread.h>
432535165Vuong Nguyen#include <strings.h>
442535165Vuong Nguyen#include <sys/types.h>
452535165Vuong Nguyen#include <sys/stat.h>
462535165Vuong Nguyen#include <sys/fm/ldom.h>
472535165Vuong Nguyen#include <sys/fm/protocol.h>
482535165Vuong Nguyen#include <fm/fmd_api.h>
492535165Vuong Nguyen#include <fm/libtopo.h>
502535165Vuong Nguyen#include <fm/topo_hc.h>
512535165Vuong Nguyen
522535165Vuong Nguyen#include "etm_etm_proto.h"
532535165Vuong Nguyen#include "etm_iosvc.h"
542535165Vuong Nguyen#include "etm_ckpt.h"
552535165Vuong Nguyen#include "etm_filter.h"
562535165Vuong Nguyen
572535165Vuong Nguyen#define	ETM_ATTR_PRIMARY	"primary"
582535165Vuong Nguyen#define	ETM_ATTR_TOD		"__tod"
592535165Vuong Nguyen#define	ETM_LDOM_PRIMARY	"primary"
602535165Vuong Nguyen
612535165Vuong Nguyen/*
622535165Vuong Nguyen * -------------------------- private variables ------------------------------
632535165Vuong Nguyen */
642535165Vuong Nguyen
652535165Vuong Nguyenstatic etm_ckpt_id_list_t *etm_id_lst = NULL;	/* list of ereports ids */
662535165Vuong Nguyen
672535165Vuong Nguyenstatic pthread_mutex_t etm_id_lst_lock;		/* list lock */
682535165Vuong Nguyen
692535165Vuong Nguyen/*
702535165Vuong Nguyen * -------------------------- functions --------------------------------------
712535165Vuong Nguyen */
722535165Vuong Nguyen
732535165Vuong Nguyen/*
742535165Vuong Nguyen * etm_ckpt_str_hash()
752535165Vuong Nguyen * Description:
762535165Vuong Nguyen *     Hash a class name to a number
772535165Vuong Nguyen */
782535165Vuong Nguyenstatic uint_t
792535165Vuong Nguyenetm_ckpt_str_hash(char *str)
802535165Vuong Nguyen{
812535165Vuong Nguyen	uint_t		hash = 0;	/* hash value */
822535165Vuong Nguyen
832535165Vuong Nguyen	if (str == NULL)
842535165Vuong Nguyen		return (0);
852535165Vuong Nguyen
862535165Vuong Nguyen	while (*str != '\0')
872535165Vuong Nguyen		hash += *str++;
882535165Vuong Nguyen
892535165Vuong Nguyen	return (hash);
902535165Vuong Nguyen}
912535165Vuong Nguyen
922535165Vuong Nguyen/*
932535165Vuong Nguyen * etm_ckpt_id2str()
942535165Vuong Nguyen * Description:
952535165Vuong Nguyen *     Get the string of an ereport id. It is used as the named buffer that
962535165Vuong Nguyen *     store the ereport.
972535165Vuong Nguyen */
982535165Vuong Nguyenstatic void
992535165Vuong Nguyenetm_ckpt_id2str(etm_ckpt_erpt_id_t *id, char *str, size_t size) {
1002535165Vuong Nguyen	(void) snprintf(str, size, "%s_%llx_%d_%x_%d", ETM_CKPT_ERPT_PREFIX,
1012535165Vuong Nguyen	    id->ei_ena, id->ei_hash, id->ei_tod1, id->ei_pri);
1022535165Vuong Nguyen}
1032535165Vuong Nguyen
1042535165Vuong Nguyen/*
1052535165Vuong Nguyen * etm_ckpt_erpt2id()
1062535165Vuong Nguyen * Description:
1072535165Vuong Nguyen *     Get the buffer name and ereport id of a given ereport
1082535165Vuong Nguyen */
1092535165Vuong Nguyenstatic int
1102535165Vuong Nguyenetm_ckpt_erpt2id(fmd_hdl_t *hdl, nvlist_t *erpt, etm_ckpt_erpt_id_t *id,
1112535165Vuong Nguyen    char *str, int size) {
1122535165Vuong Nguyen	char		*class = NULL;
1132535165Vuong Nguyen	uint64_t	*tod;
1142535165Vuong Nguyen	uint_t		sz;
1152535165Vuong Nguyen	boolean_t	pri = B_FALSE;
1162535165Vuong Nguyen
1172535165Vuong Nguyen	bzero(id, sizeof (etm_ckpt_erpt_id_t));
1182535165Vuong Nguyen
1192535165Vuong Nguyen	/* ena */
1202535165Vuong Nguyen	if (nvlist_lookup_uint64(erpt, FM_EREPORT_ENA, &id->ei_ena) != 0) {
1212535165Vuong Nguyen		fmd_hdl_debug(hdl, "Ena not found\n");
1222535165Vuong Nguyen		return (-1);
1232535165Vuong Nguyen	}
1242535165Vuong Nguyen
1252535165Vuong Nguyen	/* class name */
1262535165Vuong Nguyen	(void) nvlist_lookup_string(erpt, FM_CLASS, &class);
1272535165Vuong Nguyen	if (class == NULL) {
1282535165Vuong Nguyen		fmd_hdl_debug(hdl, "%s not found\n", FM_CLASS);
1292535165Vuong Nguyen		return (-1);
1302535165Vuong Nguyen	}
1312535165Vuong Nguyen	if (strncmp(class, FM_EREPORT_CLASS, strlen(FM_EREPORT_CLASS)) != 0) {
1322535165Vuong Nguyen		fmd_hdl_debug(hdl, "Only support checkpointing %s\n",
1332535165Vuong Nguyen		    FM_EREPORT_CLASS);
1342535165Vuong Nguyen		return (-1);
1352535165Vuong Nguyen	}
1362535165Vuong Nguyen	id->ei_hash = etm_ckpt_str_hash(class);
1372535165Vuong Nguyen
1382535165Vuong Nguyen	/* tod[1]: fractional of a second */
1392535165Vuong Nguyen	if (nvlist_lookup_uint64_array(erpt, ETM_ATTR_TOD, &tod, &sz) == 0) {
1402535165Vuong Nguyen		if (sz >= 2) {
1412535165Vuong Nguyen			id->ei_tod1 = (uint32_t)tod[1];
1422535165Vuong Nguyen		}
1432535165Vuong Nguyen	}
1442535165Vuong Nguyen
1452535165Vuong Nguyen	/* primary flag */
1462535165Vuong Nguyen	if (nvlist_lookup_boolean_value(erpt, ETM_ATTR_PRIMARY, &pri) == 0) {
1472535165Vuong Nguyen		id->ei_pri = pri ? 1 : 0;
1482535165Vuong Nguyen	}
1492535165Vuong Nguyen
1502535165Vuong Nguyen	etm_ckpt_id2str(id, str, size);
1512535165Vuong Nguyen
1522535165Vuong Nguyen	return (0);
1532535165Vuong Nguyen}
1542535165Vuong Nguyen
1552535165Vuong Nguyen/*
1562535165Vuong Nguyen * etm_ckpt_il_equal()
1572535165Vuong Nguyen * Description:
1582535165Vuong Nguyen *     Test if two ereport ids are equal.
1592535165Vuong Nguyen */
1602535165Vuong Nguyenstatic boolean_t
1612535165Vuong Nguyenetm_ckpt_il_equal(etm_ckpt_erpt_id_t *i1, etm_ckpt_erpt_id_t *i2)
1622535165Vuong Nguyen{
1632535165Vuong Nguyen	return ((i1->ei_ena == i2->ei_ena) && (i1->ei_tod1 == i2->ei_tod1) &&
1642535165Vuong Nguyen	    (i1->ei_pri == i2->ei_pri) && (i1->ei_hash == i2->ei_hash));
1652535165Vuong Nguyen}
1662535165Vuong Nguyen
1672535165Vuong Nguyen/*
1682535165Vuong Nguyen * etm_ckpt_il_resize()
1692535165Vuong Nguyen * Description:
1702535165Vuong Nguyen *     Increase the size of the circular list and pack its entries.
1712535165Vuong Nguyen */
1722535165Vuong Nguyenstatic void
1732535165Vuong Nguyenetm_ckpt_il_resize(fmd_hdl_t *hdl, uint_t factor)
1742535165Vuong Nguyen{
1752535165Vuong Nguyen	etm_ckpt_id_list_t	*il1, *il2;		/* temp lists */
1762535165Vuong Nguyen	size_t			sz1, sz2;		/* sizes of lists */
1772535165Vuong Nguyen	int			i, next;		/* temp counters */
1782535165Vuong Nguyen	etm_ckpt_erpt_id_t	*p1, *p2, *s1, *s2;	/* temp id pointers */
1792535165Vuong Nguyen	etm_ckpt_erpt_id_t	blank;			/* blank ereport id */
1802535165Vuong Nguyen
1812535165Vuong Nguyen	if (factor == 0)
1822535165Vuong Nguyen		return;
1832535165Vuong Nguyen
1842535165Vuong Nguyen	/* the present queue */
1852535165Vuong Nguyen	il1 = etm_id_lst;
1862535165Vuong Nguyen	sz1 = sizeof (etm_ckpt_id_list_t) + il1->il_ids_sz;
1872535165Vuong Nguyen
1882535165Vuong Nguyen	/* Create an empty queue with a new size */
1892535165Vuong Nguyen	sz2 = sizeof (etm_ckpt_id_list_t) + (factor * il1->il_ids_sz);
1902535165Vuong Nguyen	il2 = fmd_hdl_zalloc(hdl, sz2, FMD_SLEEP);
1912535165Vuong Nguyen	il2->il_ver = ETM_CKPT_VERSION;
1922535165Vuong Nguyen	il2->il_max = factor * etm_id_lst->il_max;
1932535165Vuong Nguyen	il2->il_ids_sz = factor * il1->il_ids_sz;
1942535165Vuong Nguyen
1952535165Vuong Nguyen	/* pointers to the two arrays of entries */
1962535165Vuong Nguyen	bzero(&blank, sizeof (blank));
1972535165Vuong Nguyen	s1 = (etm_ckpt_erpt_id_t *)
1982535165Vuong Nguyen	    ((ptrdiff_t)il1 + sizeof (etm_ckpt_id_list_t));
1992535165Vuong Nguyen	s2 = (etm_ckpt_erpt_id_t *)
2002535165Vuong Nguyen	    ((ptrdiff_t)il2 + sizeof (etm_ckpt_id_list_t));
2012535165Vuong Nguyen
2022535165Vuong Nguyen	/* copy non-empty ereport ids from list il1 to il2. Toss the blank. */
2032535165Vuong Nguyen	if (il1->il_head != il1->il_tail) {
2042535165Vuong Nguyen		for (i = il1->il_head; i != il1->il_tail; i = next) {
2052535165Vuong Nguyen			next = (i + 1) % il1->il_max;
2062535165Vuong Nguyen			p1 = s1 + next;
2072535165Vuong Nguyen			if (!etm_ckpt_il_equal(p1, &blank)) {
2082535165Vuong Nguyen				/* copy non-empty entries */
2092535165Vuong Nguyen				il2->il_tail = (il2->il_tail + 1) % il2->il_max;
2102535165Vuong Nguyen				fmd_hdl_debug(hdl, "Copying entry %d to %d\n",
2112535165Vuong Nguyen				    next, il2->il_tail);
2122535165Vuong Nguyen				p2 = s2 +  il2->il_tail;
2132535165Vuong Nguyen				*p2 = *p1;
2142535165Vuong Nguyen				il2->il_cnt++;
2152535165Vuong Nguyen			}
2162535165Vuong Nguyen		}
2172535165Vuong Nguyen	}
2182535165Vuong Nguyen
2192535165Vuong Nguyen	if (factor == 1) {
2202535165Vuong Nguyen		/* both lists have the same size, update the present list */
2212535165Vuong Nguyen		bcopy(il2, il1, sz1);
2222535165Vuong Nguyen		fmd_hdl_free(hdl, il2, sz2);
2232535165Vuong Nguyen		fmd_buf_write(hdl, NULL, ETM_CKPT_IL_BUF, (void *) il1, sz1);
2242535165Vuong Nguyen	} else {
2252535165Vuong Nguyen		/* replace the present list */
2262535165Vuong Nguyen		etm_id_lst = il2;
2272535165Vuong Nguyen		fmd_hdl_free(hdl, il1, sz1);
2282535165Vuong Nguyen		/* write to new buffer */
2292535165Vuong Nguyen		fmd_buf_destroy(hdl, NULL, ETM_CKPT_IL_BUF);
2302535165Vuong Nguyen		fmd_buf_create(hdl, NULL, ETM_CKPT_IL_BUF, sz2);
2312535165Vuong Nguyen		fmd_buf_write(hdl, NULL, ETM_CKPT_IL_BUF, (void *) il2, sz2);
2322535165Vuong Nguyen	}
2332535165Vuong Nguyen}
2342535165Vuong Nguyen
2352535165Vuong Nguyen/*
2362535165Vuong Nguyen * etm_ckpt_il_find()
2372535165Vuong Nguyen * Description:
2382535165Vuong Nguyen *     Find the ereport id in the list.
2392535165Vuong Nguyen */
2402535165Vuong Nguyen/* ARGSUSED */
2412535165Vuong Nguyenstatic int
2422535165Vuong Nguyenetm_ckpt_il_find(fmd_hdl_t *hdl, etm_ckpt_erpt_id_t *id)
2432535165Vuong Nguyen{
2442535165Vuong Nguyen	int			i, next;	/* temp counter */
2452535165Vuong Nguyen	etm_ckpt_erpt_id_t	*p, *s;		/* temp erpt id */
2462535165Vuong Nguyen
2472535165Vuong Nguyen	fmd_hdl_debug(hdl, "etm_ckpt_il_find()\n");
2482535165Vuong Nguyen
2492535165Vuong Nguyen	/* empty list */
2502535165Vuong Nguyen	if (etm_id_lst->il_head == etm_id_lst->il_tail) {
2512535165Vuong Nguyen		fmd_hdl_debug(hdl, "find an empty list\n");
2522535165Vuong Nguyen		return (-1);
2532535165Vuong Nguyen	}
2542535165Vuong Nguyen	s = (etm_ckpt_erpt_id_t *)((ptrdiff_t)etm_id_lst +
2552535165Vuong Nguyen	    sizeof (etm_ckpt_id_list_t));
2562535165Vuong Nguyen	for (i = etm_id_lst->il_head; i != etm_id_lst->il_tail; i = next) {
2572535165Vuong Nguyen		next = (i + 1) % etm_id_lst->il_max;
2582535165Vuong Nguyen		p = s + next;
2592535165Vuong Nguyen		if (etm_ckpt_il_equal(p, id))
2602535165Vuong Nguyen			return (i);
2612535165Vuong Nguyen	}
2622535165Vuong Nguyen
2632535165Vuong Nguyen	return (-1);
2642535165Vuong Nguyen}
2652535165Vuong Nguyen
2662535165Vuong Nguyen/*
2672535165Vuong Nguyen * etm_ckpt_il_add()
2682535165Vuong Nguyen * Description:
2692535165Vuong Nguyen *     Add an ereport id in the list.
2702535165Vuong Nguyen */
2712535165Vuong Nguyenstatic int
2722535165Vuong Nguyenetm_ckpt_il_add(fmd_hdl_t *hdl, etm_ckpt_erpt_id_t *id) {
2732535165Vuong Nguyen	int			next;
2742535165Vuong Nguyen	etm_ckpt_erpt_id_t	*p, *s;	/* temp id */
2752535165Vuong Nguyen
2762535165Vuong Nguyen	/*
2772535165Vuong Nguyen	 * resize the q if it is full.
2782535165Vuong Nguyen	 * If the capacity is less 80%, purge the emtpy entries to make more
2792535165Vuong Nguyen	 * room for new entries. Otherwise, double the queue size.
2802535165Vuong Nguyen	 */
2812535165Vuong Nguyen	next = (etm_id_lst->il_tail + 1) % etm_id_lst->il_max;
2822535165Vuong Nguyen	if (next == etm_id_lst->il_head) {
2832535165Vuong Nguyen		if ((etm_id_lst->il_cnt * 1.0 / etm_id_lst->il_max) < 0.8) {
2842535165Vuong Nguyen			etm_ckpt_il_resize(hdl, 1);
2852535165Vuong Nguyen		} else {
2862535165Vuong Nguyen			etm_ckpt_il_resize(hdl, 2);
2872535165Vuong Nguyen		}
2882535165Vuong Nguyen
2892535165Vuong Nguyen		/* test if the list again */
2902535165Vuong Nguyen		next = (etm_id_lst->il_tail + 1) % etm_id_lst->il_max;
2912535165Vuong Nguyen		if (next == etm_id_lst->il_head) {
2922535165Vuong Nguyen			fmd_hdl_error(hdl, "List is full %d %d\n",
2932535165Vuong Nguyen			    etm_id_lst->il_head, etm_id_lst->il_tail);
2942535165Vuong Nguyen		}
2952535165Vuong Nguyen	}
2962535165Vuong Nguyen
2972535165Vuong Nguyen	/* Add the id entry at the head */
2982535165Vuong Nguyen	s = (etm_ckpt_erpt_id_t *)((ptrdiff_t)etm_id_lst +
2992535165Vuong Nguyen	    sizeof (etm_ckpt_id_list_t));
3002535165Vuong Nguyen	etm_id_lst->il_tail = (etm_id_lst->il_tail + 1) % etm_id_lst->il_max;
3012535165Vuong Nguyen	p = s + etm_id_lst->il_tail;
3022535165Vuong Nguyen	*p = *id;
3032535165Vuong Nguyen	etm_id_lst->il_cnt++;
3042535165Vuong Nguyen
3052535165Vuong Nguyen	return (etm_id_lst->il_tail);
3062535165Vuong Nguyen}
3072535165Vuong Nguyen
3082535165Vuong Nguyen/*
3092535165Vuong Nguyen * etm_ckpt_il_delete()
3102535165Vuong Nguyen * Description:
3112535165Vuong Nguyen *     Delete an ereport id from the list.
3122535165Vuong Nguyen */
3132535165Vuong Nguyenint
3142535165Vuong Nguyenetm_ckpt_il_delete(fmd_hdl_t *hdl, etm_ckpt_erpt_id_t *id) {
3152535165Vuong Nguyen
3162535165Vuong Nguyen	int			i, next;	/* temp counter */
3172535165Vuong Nguyen	etm_ckpt_erpt_id_t	*p, *s;		/* temp id pointers */
3182535165Vuong Nguyen	etm_ckpt_erpt_id_t	blank;		/* blank id */
3192535165Vuong Nguyen
3202535165Vuong Nguyen	/* empty list */
3212535165Vuong Nguyen	if (etm_id_lst->il_tail == etm_id_lst->il_head) {
3222535165Vuong Nguyen		fmd_hdl_debug(hdl, "Empty queue(%d)\n", etm_id_lst->il_head);
3232535165Vuong Nguyen		return (-1);
3242535165Vuong Nguyen	}
3252535165Vuong Nguyen
3262535165Vuong Nguyen	bzero(&blank, sizeof (blank));
3272535165Vuong Nguyen	s = (etm_ckpt_erpt_id_t *)((ptrdiff_t)etm_id_lst +
3282535165Vuong Nguyen	    sizeof (etm_ckpt_id_list_t));
3292535165Vuong Nguyen
3302535165Vuong Nguyen	/* delete leading empty entries */
3312535165Vuong Nguyen	for (i = etm_id_lst->il_head; i != etm_id_lst->il_tail; i = next) {
3322535165Vuong Nguyen		next = (i + 1) % etm_id_lst->il_max;
3332535165Vuong Nguyen		p = s + next;
3342535165Vuong Nguyen		if (!etm_ckpt_il_equal(p, &blank)) {
3352535165Vuong Nguyen			break;
3362535165Vuong Nguyen		}
3372535165Vuong Nguyen		etm_id_lst->il_cnt--;
3382535165Vuong Nguyen		etm_id_lst->il_head = next;
3392535165Vuong Nguyen	}
3402535165Vuong Nguyen
3412535165Vuong Nguyen	/* empty queue */
3422535165Vuong Nguyen	if (etm_id_lst->il_head == etm_id_lst->il_tail) {
3432535165Vuong Nguyen		fmd_hdl_debug(hdl, "Empty queue(%d)\n", etm_id_lst->il_head);
3442535165Vuong Nguyen		return (-1);
3452535165Vuong Nguyen	}
3462535165Vuong Nguyen
3472535165Vuong Nguyen	/* find the entry and clear it */
3482535165Vuong Nguyen	for (i = etm_id_lst->il_head; i != etm_id_lst->il_tail; i = next) {
3492535165Vuong Nguyen		next = (i + 1) % etm_id_lst->il_max;
3502535165Vuong Nguyen		p = s + next;
3512535165Vuong Nguyen		if (etm_ckpt_il_equal(p, id)) {
3522535165Vuong Nguyen			/* clear the entry */
3532535165Vuong Nguyen			*p = blank;
3542535165Vuong Nguyen			etm_id_lst->il_cnt--;
3552535165Vuong Nguyen
3562535165Vuong Nguyen			/* remove the entry if it is the last one */
3572535165Vuong Nguyen			if (i == etm_id_lst->il_head) {
3582535165Vuong Nguyen				etm_id_lst->il_head = next;
3592535165Vuong Nguyen			}
3602535165Vuong Nguyen			return (i);
3612535165Vuong Nguyen		}
3622535165Vuong Nguyen	}
3632535165Vuong Nguyen
3642535165Vuong Nguyen	return (-1);
3652535165Vuong Nguyen}
3662535165Vuong Nguyen
3672535165Vuong Nguyen
3682535165Vuong Nguyen/*
3692535165Vuong Nguyen * etm_ckpt_il_restore()
3702535165Vuong Nguyen * Description:
3712535165Vuong Nguyen *     Restore the idlist named buffer which is the circular list of the
3722535165Vuong Nguyen *     the ereport ids.
3732535165Vuong Nguyen */
3742535165Vuong Nguyenvoid
3752535165Vuong Nguyenetm_ckpt_il_restore(fmd_hdl_t *hdl)
3762535165Vuong Nguyen{
3772535165Vuong Nguyen	size_t	size;		/* buffer size */
3782535165Vuong Nguyen
3792535165Vuong Nguyen	/* get the buffer of the id list */
3802535165Vuong Nguyen	size = fmd_buf_size(hdl, NULL, ETM_CKPT_IL_BUF);
3812535165Vuong Nguyen	if (size < sizeof (etm_ckpt_id_list_t)) {
3822535165Vuong Nguyen		fmd_hdl_debug(hdl, "Buffer name %s do not exist\n",
3832535165Vuong Nguyen		    ETM_CKPT_IL_BUF);
3842535165Vuong Nguyen		return;
3852535165Vuong Nguyen	}
3862535165Vuong Nguyen	etm_id_lst = (etm_ckpt_id_list_t *)fmd_hdl_zalloc(hdl, size, FMD_SLEEP);
3872535165Vuong Nguyen	fmd_buf_read(hdl, NULL, ETM_CKPT_IL_BUF, (void *) etm_id_lst, size);
3882535165Vuong Nguyen
3892535165Vuong Nguyen	/* check version */
3902535165Vuong Nguyen	if (etm_id_lst->il_ver > ETM_CKPT_VERSION) {
3912535165Vuong Nguyen
3922535165Vuong Nguyen		fmd_hdl_error(hdl, "Unsupport checkpoint version (%#x)\n",
3932535165Vuong Nguyen		    etm_id_lst->il_ver);
3942535165Vuong Nguyen		fmd_hdl_free(hdl, (void *) etm_id_lst, size);
3952535165Vuong Nguyen		etm_id_lst = NULL;
3962535165Vuong Nguyen		return;
3972535165Vuong Nguyen	}
3982535165Vuong Nguyen
3992535165Vuong Nguyen	/* check the length */
4002535165Vuong Nguyen	if (etm_id_lst->il_ids_sz != (size - sizeof (etm_ckpt_id_list_t))) {
4012535165Vuong Nguyen		fmd_hdl_debug(hdl, "Invalid ids buffer size (%d, %d)\n",
4022535165Vuong Nguyen		    etm_id_lst->il_ids_sz, size);
4032535165Vuong Nguyen		fmd_hdl_free(hdl, (void *) etm_id_lst, size);
4042535165Vuong Nguyen		etm_id_lst = NULL;
4052535165Vuong Nguyen		return;
4062535165Vuong Nguyen	}
4072535165Vuong Nguyen}
4082535165Vuong Nguyen
4092535165Vuong Nguyen/*
4102535165Vuong Nguyen * etm_ckpt_recover()
4112535165Vuong Nguyen * Description:
4122535165Vuong Nguyen *    Recover ereports from the checkpointed data and dispatch them to the
4132535165Vuong Nguyen *    ldom queue(s).
4142535165Vuong Nguyen */
4152535165Vuong Nguyenvoid
4162535165Vuong Nguyenetm_ckpt_recover(fmd_hdl_t *hdl)
4172535165Vuong Nguyen{
4182535165Vuong Nguyen	int			size;			/* buffer size */
4192535165Vuong Nguyen	int			i, next;		/* temp counter */
4202535165Vuong Nguyen	boolean_t		dirty = B_FALSE;	/* dirty flag */
4212535165Vuong Nguyen	uint64_t		did;			/* domain id */
4222535165Vuong Nguyen	char			name[ETM_LINE_LEN];	/* temp str */
4232535165Vuong Nguyen	char			ldom[ETM_LINE_LEN];	/* ldom id */
4242535165Vuong Nguyen	etm_ckpt_erpt_id_t	*p, *s;			/* temp ereport id */
4252535165Vuong Nguyen	etm_ckpt_erpt_id_t	blank;			/* blank ereport id */
4262535165Vuong Nguyen	etm_ckpt_erpt_buf_t	*ep;			/* ereport buffer */
4272535165Vuong Nguyen	size_t			sz;			/* size of ep */
4282535165Vuong Nguyen	char			*buf;			/* temp buf */
4292535165Vuong Nguyen	nvlist_t		*nvl;			/* ereport */
4302535165Vuong Nguyen	etm_iosvc_t		*iosvc;			/* iosvc data struct */
4312535165Vuong Nguyen
4322535165Vuong Nguyen	/*
4332535165Vuong Nguyen	 * restore the circular list of ereport ids
4342535165Vuong Nguyen	 */
4352535165Vuong Nguyen	etm_ckpt_il_restore(hdl);
4362535165Vuong Nguyen	if (etm_id_lst == NULL) {
4372535165Vuong Nguyen		fmd_hdl_debug(hdl, "Initialize a new id list\n");
4382535165Vuong Nguyen		size = sizeof (etm_ckpt_id_list_t) +
4392535165Vuong Nguyen		    ETM_CKPT_IL_MIN_SIZE * sizeof (etm_ckpt_erpt_id_t);
4402535165Vuong Nguyen		etm_id_lst = fmd_hdl_zalloc(hdl, size, FMD_SLEEP);
4412535165Vuong Nguyen		etm_id_lst->il_ver = ETM_CKPT_VERSION;
4422535165Vuong Nguyen		etm_id_lst->il_max = ETM_CKPT_IL_MIN_SIZE;
4432535165Vuong Nguyen		etm_id_lst->il_head = 0;
4442535165Vuong Nguyen		etm_id_lst->il_tail = 0;
4452535165Vuong Nguyen		etm_id_lst->il_ids_sz =
4462535165Vuong Nguyen		    ETM_CKPT_IL_MIN_SIZE * sizeof (etm_ckpt_erpt_id_t);
4472535165Vuong Nguyen		fmd_buf_destroy(hdl, NULL, ETM_CKPT_IL_BUF);
4482535165Vuong Nguyen		fmd_buf_create(hdl, NULL, ETM_CKPT_IL_BUF, size);
4492535165Vuong Nguyen		fmd_buf_write(hdl, NULL, ETM_CKPT_IL_BUF, (void *) etm_id_lst,
4502535165Vuong Nguyen		    size);
4512535165Vuong Nguyen
4522535165Vuong Nguyen		/* commit */
4532535165Vuong Nguyen		fmd_thr_checkpoint(hdl);
4542535165Vuong Nguyen
4552535165Vuong Nguyen		return;
4562535165Vuong Nguyen	}
4572535165Vuong Nguyen
4582535165Vuong Nguyen	/* Empty list */
4592535165Vuong Nguyen	if ((etm_id_lst->il_head == etm_id_lst->il_tail) ||
4602535165Vuong Nguyen	    (etm_id_lst->il_cnt == 0)) {
4612535165Vuong Nguyen		return;
4622535165Vuong Nguyen	}
4632535165Vuong Nguyen
4642535165Vuong Nguyen	/* Visit all the entries in the list */
4652535165Vuong Nguyen	bzero(&blank, sizeof (blank));
4662535165Vuong Nguyen	s = (etm_ckpt_erpt_id_t *)((ptrdiff_t)etm_id_lst +
4672535165Vuong Nguyen	    sizeof (etm_ckpt_id_list_t));
4682535165Vuong Nguyen	for (i = etm_id_lst->il_head; i != etm_id_lst->il_tail; i = next) {
4692535165Vuong Nguyen		next = (i + 1) % etm_id_lst->il_max;
4702535165Vuong Nguyen		p = s + next;
4712535165Vuong Nguyen		if (etm_ckpt_il_equal(p, &blank)) {
4722535165Vuong Nguyen			fmd_hdl_debug(hdl, "Skip empty entry %d\n", i);
4732535165Vuong Nguyen			continue;
4742535165Vuong Nguyen		}
4752535165Vuong Nguyen
4762535165Vuong Nguyen		etm_ckpt_id2str(p, name, sizeof (name));
4772535165Vuong Nguyen		fmd_hdl_debug(hdl, "Restoring entry %s\n", name);
4782535165Vuong Nguyen		if ((sz = fmd_buf_size(hdl, NULL, name)) == 0) {
4792535165Vuong Nguyen			fmd_hdl_error(hdl, "Clear the stale entry %s\n", name);
4802535165Vuong Nguyen			*p = blank;
4812535165Vuong Nguyen			continue;
4822535165Vuong Nguyen		}
4832535165Vuong Nguyen		ep = (etm_ckpt_erpt_buf_t *)fmd_hdl_zalloc(hdl, sz, FMD_SLEEP);
4842535165Vuong Nguyen		fmd_buf_read(hdl, NULL, name, (void *) ep, sz);
4852535165Vuong Nguyen		buf = (char *)((ptrdiff_t)ep + sizeof (etm_ckpt_erpt_buf_t));
4862535165Vuong Nguyen		nvl = NULL;
4872535165Vuong Nguyen		if (nvlist_unpack(buf, ep->eb_len, &nvl, 0)) {
4882535165Vuong Nguyen			fmd_hdl_debug(hdl, "failed to unpack %s\n", name);
4892535165Vuong Nguyen			fmd_hdl_free(hdl, ep, sz);
4902535165Vuong Nguyen			continue;
4912535165Vuong Nguyen		}
4922535165Vuong Nguyen		fmd_hdl_free(hdl, ep, sz);
4932535165Vuong Nguyen		if (etm_filter_find_ldom_id(hdl, nvl, ldom, ETM_LINE_LEN,
4942535165Vuong Nguyen		    &did) || (strcmp(name, ETM_LDOM_PRIMARY) == 0)) {
4952535165Vuong Nguyen			fmd_hdl_debug(hdl, "Discard event %s\n", name);
4962535165Vuong Nguyen			fmd_buf_destroy(hdl, NULL, name);
4972535165Vuong Nguyen			*p = blank;
4982535165Vuong Nguyen			nvlist_free(nvl);
4992535165Vuong Nguyen			dirty = B_TRUE;
5002535165Vuong Nguyen			continue;
5012535165Vuong Nguyen		}
5022535165Vuong Nguyen
5032535165Vuong Nguyen		fmd_hdl_debug(hdl, "Dispatch %s to ldom %s\n", name, ldom);
5042535165Vuong Nguyen
5052535165Vuong Nguyen		/*
5062535165Vuong Nguyen		 * Find the queue of the ldom, create it if not exist.
5072535165Vuong Nguyen		 * Then insert this event into the queue.
5082535165Vuong Nguyen		 */
5092535165Vuong Nguyen		iosvc = etm_iosvc_lookup(hdl, ldom, DS_INVALID_HDL, B_TRUE);
5102535165Vuong Nguyen		if (iosvc != NULL) {
5112535165Vuong Nguyen			(void) etm_pack_ds_msg(hdl, iosvc, NULL, 0, nvl, SP_MSG,
5122535165Vuong Nguyen			    ETM_CKPT_RESTORE);
5132535165Vuong Nguyen		}
5142535165Vuong Nguyen		nvlist_free(nvl);
5152535165Vuong Nguyen	}
5162535165Vuong Nguyen	if (dirty) {
5172535165Vuong Nguyen		/* update the buffer of the queue */
5182535165Vuong Nguyen		size = sizeof (etm_ckpt_id_list_t) + etm_id_lst->il_ids_sz;
5192535165Vuong Nguyen		fmd_buf_write(hdl, NULL, ETM_CKPT_IL_BUF, (void *) etm_id_lst,
5202535165Vuong Nguyen		    size);
5212535165Vuong Nguyen
5222535165Vuong Nguyen		/* commit */
5232535165Vuong Nguyen		fmd_thr_checkpoint(hdl);
5242535165Vuong Nguyen	}
5252535165Vuong Nguyen
5262535165Vuong Nguyen} /* etm_ckpt_recover */
5272535165Vuong Nguyen
5282535165Vuong Nguyen
5292535165Vuong Nguyen/*
5302535165Vuong Nguyen * etm_ckpt_add_entry()
5312535165Vuong Nguyen * Description:
5322535165Vuong Nguyen *     Save an ereport for persistence.
5332535165Vuong Nguyen */
5342535165Vuong Nguyenint
5352535165Vuong Nguyenetm_ckpt_add_entry(fmd_hdl_t *hdl, nvlist_t *erpt) {
5362535165Vuong Nguyen	etm_ckpt_erpt_id_t	id;
5372535165Vuong Nguyen	char			name[ETM_LINE_LEN];
5382535165Vuong Nguyen	int			rc;			/* gen use */
5392535165Vuong Nguyen	size_t			sz;			/* size */
5402535165Vuong Nguyen	size_t			buflen;			/* sz of packed erpt */
5412535165Vuong Nguyen	uint8_t			*buf;			/* buffer of erpt */
5422535165Vuong Nguyen	etm_ckpt_erpt_buf_t	*hdr;
5432535165Vuong Nguyen
5442535165Vuong Nguyen	/* map ereport to id */
5452535165Vuong Nguyen	bzero(name, ETM_LINE_LEN);
5462535165Vuong Nguyen	rc = etm_ckpt_erpt2id(hdl, erpt, &id, name, ETM_LINE_LEN);
5472535165Vuong Nguyen	if (rc != 0) {
5482535165Vuong Nguyen		fmd_hdl_debug(hdl, "Invalid ereport\n");
5492535165Vuong Nguyen		return (rc);
5502535165Vuong Nguyen	}
5512535165Vuong Nguyen
5522535165Vuong Nguyen	/*
5532535165Vuong Nguyen	 * check for a duplicate entry in the id list
5542535165Vuong Nguyen	 * find the ereport buffer and search for the id
5552535165Vuong Nguyen	 */
5562535165Vuong Nguyen	if (fmd_buf_size(hdl, NULL, name) > 0 &&
5572535165Vuong Nguyen	    etm_ckpt_il_find(hdl, &id) >= 0) {
5582535165Vuong Nguyen		fmd_hdl_debug(hdl, "Duplicate id %s\n", name);
5592535165Vuong Nguyen		return (-1);
5602535165Vuong Nguyen	}
5612535165Vuong Nguyen
5622535165Vuong Nguyen	/* Create the ereport buffer */
5632535165Vuong Nguyen	if (nvlist_size(erpt, &buflen, NV_ENCODE_XDR) != 0) {
5642535165Vuong Nguyen		fmd_hdl_debug(hdl, "nvlist_size fails\n");
5652535165Vuong Nguyen		return (-1);
5662535165Vuong Nguyen	}
5672535165Vuong Nguyen	sz = sizeof (etm_ckpt_erpt_buf_t) + buflen;
5682535165Vuong Nguyen	hdr = (etm_ckpt_erpt_buf_t *)fmd_hdl_zalloc(hdl, sz, FMD_SLEEP);
5692535165Vuong Nguyen	buf = (uint8_t *)((ptrdiff_t)hdr + sizeof (etm_ckpt_erpt_buf_t));
5702535165Vuong Nguyen	hdr->eb_ver = ETM_CKPT_VERSION;
5712535165Vuong Nguyen	hdr->eb_len = buflen;
5722535165Vuong Nguyen	if (nvlist_pack(erpt, (char **)&buf, &buflen, NV_ENCODE_XDR, 0) != 0) {
5732535165Vuong Nguyen		fmd_hdl_free(hdl, hdr, sz);
5742535165Vuong Nguyen		fmd_hdl_debug(hdl, "unpack fails\n");
5752535165Vuong Nguyen		return (-1);
5762535165Vuong Nguyen	}
5772535165Vuong Nguyen	fmd_hdl_debug(hdl, "Add ckpt event(%s, %d)\n", name, sz);
5782535165Vuong Nguyen	fmd_buf_create(hdl, NULL, name, sz);
5792535165Vuong Nguyen	fmd_buf_write(hdl, NULL, name, hdr, sz);
5802535165Vuong Nguyen	fmd_hdl_free(hdl, hdr, sz);
5812535165Vuong Nguyen
5822535165Vuong Nguyen	/* Insert the ereport id into the id list */
5832535165Vuong Nguyen	if (etm_ckpt_il_add(hdl, &id) < 0) {
5842535165Vuong Nguyen		fmd_hdl_debug(hdl, "Insert id %s failed\n", name);
5852535165Vuong Nguyen		fmd_buf_destroy(hdl, NULL, name);
5862535165Vuong Nguyen		return (-1);
5872535165Vuong Nguyen	}
5882535165Vuong Nguyen
5892535165Vuong Nguyen	/* update the buffer of the queue */
5902535165Vuong Nguyen	sz = sizeof (etm_ckpt_id_list_t) + etm_id_lst->il_ids_sz;
5912535165Vuong Nguyen	fmd_buf_write(hdl, NULL, ETM_CKPT_IL_BUF, (void *) etm_id_lst, sz);
5922535165Vuong Nguyen
5932535165Vuong Nguyen	/* commit */
5942535165Vuong Nguyen	fmd_thr_checkpoint(hdl);
5952535165Vuong Nguyen
5962535165Vuong Nguyen	return (0);
5972535165Vuong Nguyen}
5982535165Vuong Nguyen
5992535165Vuong Nguyen/*
6002535165Vuong Nguyen * etm_ckpt_delete_entry()
6012535165Vuong Nguyen * Description:
6022535165Vuong Nguyen *     Delete an ereport id in the list.
6032535165Vuong Nguyen */
6042535165Vuong Nguyenstatic int
6052535165Vuong Nguyenetm_ckpt_delete_entry(fmd_hdl_t *hdl, nvlist_t *erpt) {
6062535165Vuong Nguyen	etm_ckpt_erpt_id_t	id;
6072535165Vuong Nguyen	char			name[ETM_LINE_LEN];
6082535165Vuong Nguyen	int			rc;			/* return code */
6092535165Vuong Nguyen	size_t			sz;			/* size */
6102535165Vuong Nguyen
6112535165Vuong Nguyen	/* get id, id name */
6122535165Vuong Nguyen	bzero(name, ETM_LINE_LEN);
6132535165Vuong Nguyen	if (etm_ckpt_erpt2id(hdl, erpt, &id, name, ETM_LINE_LEN) != 0) {
6142535165Vuong Nguyen		fmd_hdl_debug(hdl, "Invalid ereport\n");
6152535165Vuong Nguyen		return (-1);
6162535165Vuong Nguyen	}
6172535165Vuong Nguyen	fmd_hdl_debug(hdl, "Delete ckpt event(%s)\n", name);
6182535165Vuong Nguyen
6192535165Vuong Nguyen	/* delete the ereport buffer */
6202535165Vuong Nguyen	if (fmd_buf_size(hdl, NULL, name) > 0) {
6212535165Vuong Nguyen		fmd_buf_destroy(hdl, NULL, name);
6222535165Vuong Nguyen	}
6232535165Vuong Nguyen
6242535165Vuong Nguyen	rc = etm_ckpt_il_delete(hdl, &id);
6252535165Vuong Nguyen	if (rc < 0) {
6262535165Vuong Nguyen		fmd_hdl_debug(hdl, "Delete id %s failed\n", name);
6272535165Vuong Nguyen		return (rc);
6282535165Vuong Nguyen	}
6292535165Vuong Nguyen
6302535165Vuong Nguyen	/* update the buffer of the queue */
6312535165Vuong Nguyen	sz = sizeof (etm_ckpt_id_list_t) + etm_id_lst->il_ids_sz;
6322535165Vuong Nguyen	fmd_buf_write(hdl, NULL, ETM_CKPT_IL_BUF, (void *) etm_id_lst, sz);
6332535165Vuong Nguyen
6342535165Vuong Nguyen	/* commit */
6352535165Vuong Nguyen	fmd_thr_checkpoint(hdl);
6362535165Vuong Nguyen
6372535165Vuong Nguyen	return (rc);
6382535165Vuong Nguyen}
6392535165Vuong Nguyen
6402535165Vuong Nguyenint
6412535165Vuong Nguyenetm_ckpt_add(fmd_hdl_t *hdl, nvlist_t *erpt) {
6422535165Vuong Nguyen
6432535165Vuong Nguyen	int		rc;		/* return code */
6442535165Vuong Nguyen
6452535165Vuong Nguyen	(void) pthread_mutex_lock(&etm_id_lst_lock);
6462535165Vuong Nguyen
6472535165Vuong Nguyen	rc = etm_ckpt_add_entry(hdl, erpt);
6482535165Vuong Nguyen
6492535165Vuong Nguyen	(void) pthread_mutex_unlock(&etm_id_lst_lock);
6502535165Vuong Nguyen
6512535165Vuong Nguyen	return (rc >= 0 ? 0 : rc);
6522535165Vuong Nguyen}
6532535165Vuong Nguyen
6542535165Vuong Nguyenint
6552535165Vuong Nguyenetm_ckpt_delete(fmd_hdl_t *hdl, nvlist_t *erpt) {
6562535165Vuong Nguyen	int		rc;		/* return code */
6572535165Vuong Nguyen
6582535165Vuong Nguyen	(void) pthread_mutex_lock(&etm_id_lst_lock);
6592535165Vuong Nguyen
6602535165Vuong Nguyen	rc = etm_ckpt_delete_entry(hdl, erpt);
6612535165Vuong Nguyen
6622535165Vuong Nguyen	(void) pthread_mutex_unlock(&etm_id_lst_lock);
6632535165Vuong Nguyen
6642535165Vuong Nguyen	return (rc >= 0 ? 0 : rc);
6652535165Vuong Nguyen}
6662535165Vuong Nguyen
6672535165Vuong Nguyen/* ARGSUSED */
6682535165Vuong Nguyenvoid
6692535165Vuong Nguyenetm_ckpt_init(fmd_hdl_t *hdl) {
6702535165Vuong Nguyen	(void) pthread_mutex_init(&etm_id_lst_lock, NULL);
6712535165Vuong Nguyen	etm_id_lst = NULL;
6722535165Vuong Nguyen}
6732535165Vuong Nguyen
6742535165Vuong Nguyenvoid
6752535165Vuong Nguyenetm_ckpt_fini(fmd_hdl_t *hdl) {
6762535165Vuong Nguyen	if (etm_id_lst != NULL) {
6772535165Vuong Nguyen		fmd_hdl_free(hdl, etm_id_lst,
6782535165Vuong Nguyen		    sizeof (etm_ckpt_id_list_t) + etm_id_lst->il_ids_sz);
6792535165Vuong Nguyen	}
6802535165Vuong Nguyen	(void) pthread_mutex_destroy(&etm_id_lst_lock);
6812535165Vuong Nguyen}