17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
50e75152Eric Saxe * Common Development and Distribution License (the "License").
60e75152Eric Saxe * You may not use this file except in compliance with the License.
77c478bdstevel@tonic-gate *
87c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bdstevel@tonic-gate * See the License for the specific language governing permissions
117c478bdstevel@tonic-gate * and limitations under the License.
127c478bdstevel@tonic-gate *
137c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bdstevel@tonic-gate *
197c478bdstevel@tonic-gate * CDDL HEADER END
207c478bdstevel@tonic-gate */
217c478bdstevel@tonic-gate/*
220e75152Eric Saxe * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bdstevel@tonic-gate * Use is subject to license terms.
247c478bdstevel@tonic-gate */
257c478bdstevel@tonic-gate
267c478bdstevel@tonic-gate#ifndef	_SYS_CALLB_H
277c478bdstevel@tonic-gate#define	_SYS_CALLB_H
287c478bdstevel@tonic-gate
297c478bdstevel@tonic-gate#include <sys/t_lock.h>
307c478bdstevel@tonic-gate#include <sys/thread.h>
317c478bdstevel@tonic-gate
327c478bdstevel@tonic-gate#ifdef	__cplusplus
337c478bdstevel@tonic-gateextern "C" {
347c478bdstevel@tonic-gate#endif
357c478bdstevel@tonic-gate
367c478bdstevel@tonic-gate/*
377c478bdstevel@tonic-gate * definitions of callback classes (c_class)
387c478bdstevel@tonic-gate *
397c478bdstevel@tonic-gate * Callbacks belong in the same class if (1) their callback routines
407c478bdstevel@tonic-gate * do the same kind of processing (ideally, using the same callback function)
417c478bdstevel@tonic-gate * and (2) they can/should be executed at the same time in a cpr
427c478bdstevel@tonic-gate * suspend/resume operation.
437c478bdstevel@tonic-gate *
447c478bdstevel@tonic-gate * Note: The DAEMON class, in particular, is for stopping kernel threads
457c478bdstevel@tonic-gate * and nothing else.  The CALLB_* macros below should be used to deal
467c478bdstevel@tonic-gate * with kernel threads, and the callback function should be callb_generic_cpr.
477c478bdstevel@tonic-gate * Another idiosyncrasy of the DAEMON class is that if a suspend operation
487c478bdstevel@tonic-gate * fails, some of the callback functions may be called with the RESUME
497c478bdstevel@tonic-gate * code which were never called with SUSPEND.  Not a problem currently,
507c478bdstevel@tonic-gate * but see bug 4201851.
517c478bdstevel@tonic-gate */
527c478bdstevel@tonic-gate#define	CB_CL_CPR_DAEMON	0
537c478bdstevel@tonic-gate#define	CB_CL_CPR_VM		1
547c478bdstevel@tonic-gate#define	CB_CL_CPR_CALLOUT	2
557c478bdstevel@tonic-gate#define	CB_CL_CPR_OBP		3
567c478bdstevel@tonic-gate#define	CB_CL_CPR_FB		4
577c478bdstevel@tonic-gate#define	CB_CL_PANIC		5
587c478bdstevel@tonic-gate#define	CB_CL_CPR_RPC		6
597c478bdstevel@tonic-gate#define	CB_CL_CPR_PROMPRINTF	7
607c478bdstevel@tonic-gate#define	CB_CL_UADMIN		8
617c478bdstevel@tonic-gate#define	CB_CL_CPR_PM		9
627c478bdstevel@tonic-gate#define	CB_CL_HALT		10
637c478bdstevel@tonic-gate#define	CB_CL_CPR_DMA		11
647c478bdstevel@tonic-gate#define	CB_CL_CPR_POST_USER	12
657c478bdstevel@tonic-gate#define	CB_CL_UADMIN_PRE_VFS    13
66edc4022achartre#define	CB_CL_MDBOOT		CB_CL_UADMIN
677c478bdstevel@tonic-gate#define	CB_CL_ENTER_DEBUGGER	14
687c478bdstevel@tonic-gate#define	CB_CL_CPR_POST_KERNEL	15
690e75152Eric Saxe#define	CB_CL_CPU_DEEP_IDLE	16
700e75152Eric Saxe#define	NCBCLASS		17 /* CHANGE ME if classes are added/removed */
717c478bdstevel@tonic-gate
727c478bdstevel@tonic-gate/*
737c478bdstevel@tonic-gate * CB_CL_CPR_DAEMON class specific definitions are given below:
747c478bdstevel@tonic-gate */
757c478bdstevel@tonic-gate
767c478bdstevel@tonic-gate/*
777c478bdstevel@tonic-gate * code for CPR callb_execute_class
787c478bdstevel@tonic-gate */
797c478bdstevel@tonic-gate#define	CB_CODE_CPR_CHKPT	0
807c478bdstevel@tonic-gate#define	CB_CODE_CPR_RESUME	1
817c478bdstevel@tonic-gate
827c478bdstevel@tonic-gatetypedef	void *		callb_id_t;
837c478bdstevel@tonic-gate/*
847c478bdstevel@tonic-gate * Per kernel thread structure for CPR daemon callbacks.
857c478bdstevel@tonic-gate * Must be protected by either a existing lock in the daemon or
867c478bdstevel@tonic-gate * a new lock created for such a purpose.
877c478bdstevel@tonic-gate */
887c478bdstevel@tonic-gatetypedef struct callb_cpr {
897c478bdstevel@tonic-gate	kmutex_t	*cc_lockp;	/* lock to protect this struct */
907c478bdstevel@tonic-gate	char		cc_events;	/* various events for CPR */
917c478bdstevel@tonic-gate	callb_id_t	cc_id;		/* callb id address */
927c478bdstevel@tonic-gate	kcondvar_t	cc_callb_cv;	/* cv for callback waiting */
937c478bdstevel@tonic-gate	kcondvar_t	cc_stop_cv;	/* cv to checkpoint block */
947c478bdstevel@tonic-gate} callb_cpr_t;
957c478bdstevel@tonic-gate
967c478bdstevel@tonic-gate/*
977c478bdstevel@tonic-gate * cc_events definitions
987c478bdstevel@tonic-gate */
997c478bdstevel@tonic-gate#define	CALLB_CPR_START		1	/* a checkpoint request's started */
1007c478bdstevel@tonic-gate#define	CALLB_CPR_SAFE		2	/* thread is safe for CPR */
1017c478bdstevel@tonic-gate#define	CALLB_CPR_ALWAYS_SAFE	4	/* thread is ALWAYS safe for CPR */
1027c478bdstevel@tonic-gate
1037c478bdstevel@tonic-gate/*
1047c478bdstevel@tonic-gate * Used when checking that all kernel threads are stopped.
1057c478bdstevel@tonic-gate */
1067c478bdstevel@tonic-gate#define	CALLB_MAX_RETRY		3	/* when waiting for kthread to sleep */
1077c478bdstevel@tonic-gate#define	CALLB_THREAD_DELAY	10	/* ticks allowed to reach sleep */
1087c478bdstevel@tonic-gate#define	CPR_KTHREAD_TIMEOUT_SEC	90	/* secs before callback times out -- */
1097c478bdstevel@tonic-gate					/* due to pwr mgmt of disks, make -- */
1107c478bdstevel@tonic-gate					/* big enough for worst spinup time */
1117c478bdstevel@tonic-gate
1127c478bdstevel@tonic-gate#ifdef  _KERNEL
1137c478bdstevel@tonic-gate/*
1147c478bdstevel@tonic-gate *
1157c478bdstevel@tonic-gate * CALLB_CPR_INIT macro is used by kernel threads to add their entry to
1167c478bdstevel@tonic-gate * the callback table and perform other initialization.  It automatically
1177c478bdstevel@tonic-gate * adds the thread as being in the callback class CB_CL_CPR_DAEMON.
1187c478bdstevel@tonic-gate *
1197c478bdstevel@tonic-gate *	cp    - ptr to the callb_cpr_t structure for this kernel thread
1207c478bdstevel@tonic-gate *
1217c478bdstevel@tonic-gate *	lockp - pointer to mutex protecting the callb_cpr_t stuct
1227c478bdstevel@tonic-gate *
1237c478bdstevel@tonic-gate *	func  - pointer to the callback function for this kernel thread.
1247c478bdstevel@tonic-gate *		It has the prototype boolean_t <func>(void *arg, int code)
1257c478bdstevel@tonic-gate *		where: arg	- ptr to the callb_cpr_t structure
1267c478bdstevel@tonic-gate *		       code	- not used for this type of callback
1277c478bdstevel@tonic-gate *		returns: B_TRUE if successful; B_FALSE if unsuccessful.
1287c478bdstevel@tonic-gate *
1297c478bdstevel@tonic-gate *	name  - a string giving the name of the kernel thread
1307c478bdstevel@tonic-gate *
1317c478bdstevel@tonic-gate * Note: lockp is the lock to protect the callb_cpr_t (cp) structure
1327c478bdstevel@tonic-gate * later on.  No lock held is needed for this initialization.
1337c478bdstevel@tonic-gate */
1347c478bdstevel@tonic-gate#define	CALLB_CPR_INIT(cp, lockp, func, name)	{			\
1357c478bdstevel@tonic-gate		bzero((caddr_t)(cp), sizeof (callb_cpr_t));		\
1367c478bdstevel@tonic-gate		(cp)->cc_lockp = lockp;					\
1377c478bdstevel@tonic-gate		(cp)->cc_id = callb_add(func, (void *)(cp),		\
1387c478bdstevel@tonic-gate			CB_CL_CPR_DAEMON, name);			\
1397c478bdstevel@tonic-gate	}
1407c478bdstevel@tonic-gate
1417c478bdstevel@tonic-gate#ifndef __lock_lint
1427c478bdstevel@tonic-gate#define	CALLB_CPR_ASSERT(cp)	ASSERT(MUTEX_HELD((cp)->cc_lockp));
1437c478bdstevel@tonic-gate#else
1447c478bdstevel@tonic-gate#define	CALLB_CPR_ASSERT(cp)
1457c478bdstevel@tonic-gate#endif
1467c478bdstevel@tonic-gate/*
1477c478bdstevel@tonic-gate * Some threads (like the idle threads) do not adhere to the callback
1487c478bdstevel@tonic-gate * protocol and are always considered safe.  Such threads must never exit.
1497c478bdstevel@tonic-gate * They register their presence by calling this macro during their
1507c478bdstevel@tonic-gate * initialization.
1517c478bdstevel@tonic-gate *
1527c478bdstevel@tonic-gate * Args:
1537c478bdstevel@tonic-gate *	t	- thread pointer of the client kernel thread
1547c478bdstevel@tonic-gate *	name	- a string giving the name of the kernel thread
1557c478bdstevel@tonic-gate */
1567c478bdstevel@tonic-gate#define	CALLB_CPR_INIT_SAFE(t, name) {					\
1577c478bdstevel@tonic-gate		(void) callb_add_thread(callb_generic_cpr_safe,		\
1587c478bdstevel@tonic-gate		(void *) &callb_cprinfo_safe, CB_CL_CPR_DAEMON,		\
1597c478bdstevel@tonic-gate		    name, t);						\
1607c478bdstevel@tonic-gate	}
1617c478bdstevel@tonic-gate/*
1627c478bdstevel@tonic-gate * The lock to protect cp's content must be held before
1637c478bdstevel@tonic-gate * calling the following two macros.
1647c478bdstevel@tonic-gate *
1657c478bdstevel@tonic-gate * Any code region between CALLB_CPR_SAFE_BEGIN and CALLB_CPR_SAFE_END
1667c478bdstevel@tonic-gate * is safe for checkpoint/resume.
1677c478bdstevel@tonic-gate */
1687c478bdstevel@tonic-gate#define	CALLB_CPR_SAFE_BEGIN(cp) { 			\
1697c478bdstevel@tonic-gate		CALLB_CPR_ASSERT(cp)			\
1707c478bdstevel@tonic-gate		(cp)->cc_events |= CALLB_CPR_SAFE;	\
1717c478bdstevel@tonic-gate		if ((cp)->cc_events & CALLB_CPR_START)	\
1727c478bdstevel@tonic-gate			cv_signal(&(cp)->cc_callb_cv);	\
1737c478bdstevel@tonic-gate	}
1747c478bdstevel@tonic-gate#define	CALLB_CPR_SAFE_END(cp, lockp) {				\
1757c478bdstevel@tonic-gate		CALLB_CPR_ASSERT(cp)				\
1767c478bdstevel@tonic-gate		while ((cp)->cc_events & CALLB_CPR_START)	\
1777c478bdstevel@tonic-gate			cv_wait(&(cp)->cc_stop_cv, lockp);	\
1787c478bdstevel@tonic-gate		(cp)->cc_events &= ~CALLB_CPR_SAFE;		\
1797c478bdstevel@tonic-gate	}
1807c478bdstevel@tonic-gate/*
1817c478bdstevel@tonic-gate * cv_destroy is nop right now but may be needed in the future.
1827c478bdstevel@tonic-gate */
1837c478bdstevel@tonic-gate#define	CALLB_CPR_EXIT(cp) {				\
1847c478bdstevel@tonic-gate		CALLB_CPR_ASSERT(cp)			\
1857c478bdstevel@tonic-gate		(cp)->cc_events |= CALLB_CPR_SAFE;	\
1867c478bdstevel@tonic-gate		if ((cp)->cc_events & CALLB_CPR_START)	\
1877c478bdstevel@tonic-gate			cv_signal(&(cp)->cc_callb_cv);	\
1887c478bdstevel@tonic-gate		mutex_exit((cp)->cc_lockp);		\
1897c478bdstevel@tonic-gate		(void) callb_delete((cp)->cc_id);	\
1907c478bdstevel@tonic-gate		cv_destroy(&(cp)->cc_callb_cv);		\
1917c478bdstevel@tonic-gate		cv_destroy(&(cp)->cc_stop_cv);		\
1927c478bdstevel@tonic-gate	}
1937c478bdstevel@tonic-gate
1947c478bdstevel@tonic-gateextern callb_cpr_t callb_cprinfo_safe;
1957c478bdstevel@tonic-gateextern void	callb_init(void);
1967c478bdstevel@tonic-gateextern callb_id_t callb_add(boolean_t  (*)(void *, int), void *, int, char *);
1977c478bdstevel@tonic-gateextern callb_id_t callb_add_thread(boolean_t (*)(void *, int),
1987c478bdstevel@tonic-gate    void *, int, char *, kthread_id_t);
1997c478bdstevel@tonic-gateextern int	callb_delete(callb_id_t);
2007c478bdstevel@tonic-gateextern void	callb_execute(callb_id_t, int);
2017c478bdstevel@tonic-gateextern void	*callb_execute_class(int, int);
2027c478bdstevel@tonic-gateextern boolean_t callb_generic_cpr(void *, int);
2037c478bdstevel@tonic-gateextern boolean_t callb_generic_cpr_safe(void *, int);
2047c478bdstevel@tonic-gateextern boolean_t callb_is_stopped(kthread_id_t, caddr_t *);
2057c478bdstevel@tonic-gateextern void	callb_lock_table(void);
2067c478bdstevel@tonic-gateextern void	callb_unlock_table(void);
2077c478bdstevel@tonic-gate#endif
2087c478bdstevel@tonic-gate
2097c478bdstevel@tonic-gate#ifdef	__cplusplus
2107c478bdstevel@tonic-gate}
2117c478bdstevel@tonic-gate#endif
2127c478bdstevel@tonic-gate
2137c478bdstevel@tonic-gate#endif	/* _SYS_CALLB_H */
214