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 #ifndef   _SYS_CALLB_H
27 #define   _SYS_CALLB_H
28 
29 #include <sys/kcondvar.h>
30 
31 #ifdef    __cplusplus
32 extern "C" {
33 #endif
34 
35 /*
36  * definitions of callback classes (c_class)
37  *
38  * Callbacks belong in the same class if (1) their callback routines
39  * do the same kind of processing (ideally, using the same callback function)
40  * and (2) they can/should be executed at the same time in a cpr
41  * suspend/resume operation.
42  *
43  * Note: The DAEMON class, in particular, is for stopping kernel threads
44  * and nothing else.  The CALLB_* macros below should be used to deal
45  * with kernel threads, and the callback function should be callb_generic_cpr.
46  * Another idiosyncrasy of the DAEMON class is that if a suspend operation
47  * fails, some of the callback functions may be called with the RESUME
48  * code which were never called with SUSPEND.  Not a problem currently,
49  * but see bug 4201851.
50  */
51 #define   CB_CL_CPR_DAEMON    0
52 #define   CB_CL_CPR_VM                  1
53 #define   CB_CL_CPR_CALLOUT   2
54 #define   CB_CL_CPR_OBP                 3
55 #define   CB_CL_CPR_FB                  4
56 #define   CB_CL_PANIC                   5
57 #define   CB_CL_CPR_RPC                 6
58 #define   CB_CL_CPR_PROMPRINTF          7
59 #define   CB_CL_UADMIN                  8
60 #define   CB_CL_CPR_PM                  9
61 #define   CB_CL_HALT                    10
62 #define   CB_CL_CPR_DMA                 11
63 #define   CB_CL_CPR_POST_USER 12
64 #define   CB_CL_UADMIN_PRE_VFS    13
65 #define   CB_CL_MDBOOT                  CB_CL_UADMIN
66 #define   CB_CL_ENTER_DEBUGGER          14
67 #define   CB_CL_CPR_POST_KERNEL         15
68 #define   CB_CL_CPU_DEEP_IDLE 16
69 #define   NCBCLASS            17 /* CHANGE ME if classes are added/removed */
70 
71 /*
72  * CB_CL_CPR_DAEMON class specific definitions are given below:
73  */
74 
75 /*
76  * code for CPR callb_execute_class
77  */
78 #define   CB_CODE_CPR_CHKPT   0
79 #define   CB_CODE_CPR_RESUME  1
80 
81 typedef   void *              callb_id_t;
82 /*
83  * Per kernel thread structure for CPR daemon callbacks.
84  * Must be protected by either a existing lock in the daemon or
85  * a new lock created for such a purpose.
86  */
87 typedef struct callb_cpr {
88           kmutex_t  *cc_lockp;          /* lock to protect this struct */
89           char                cc_events;          /* various events for CPR */
90           callb_id_t          cc_id;              /* callb id address */
91           kcondvar_t          cc_callb_cv;        /* cv for callback waiting */
92           kcondvar_t          cc_stop_cv;         /* cv to checkpoint block */
93 } callb_cpr_t;
94 
95 /*
96  * cc_events definitions
97  */
98 #define   CALLB_CPR_START               1         /* a checkpoint request's started */
99 #define   CALLB_CPR_SAFE                2         /* thread is safe for CPR */
100 #define   CALLB_CPR_ALWAYS_SAFE         4         /* thread is ALWAYS safe for CPR */
101 
102 /*
103  * Used when checking that all kernel threads are stopped.
104  */
105 #define   CALLB_MAX_RETRY               3         /* when waiting for kthread to sleep */
106 #define   CALLB_THREAD_DELAY  10        /* ticks allowed to reach sleep */
107 #define   CPR_KTHREAD_TIMEOUT_SEC       90        /* secs before callback times out -- */
108                                                   /* due to pwr mgmt of disks, make -- */
109                                                   /* big enough for worst spinup time */
110 
111 #ifdef  _KERNEL
112 /*
113  *
114  * CALLB_CPR_INIT macro is used by kernel threads to add their entry to
115  * the callback table and perform other initialization.  It automatically
116  * adds the thread as being in the callback class CB_CL_CPR_DAEMON.
117  *
118  *        cp    - ptr to the callb_cpr_t structure for this kernel thread
119  *
120  *        lockp - pointer to mutex protecting the callb_cpr_t stuct
121  *
122  *        func  - pointer to the callback function for this kernel thread.
123  *                  It has the prototype boolean_t <func>(void *arg, int code)
124  *                  where: arg          - ptr to the callb_cpr_t structure
125  *                         code         - not used for this type of callback
126  *                  returns: B_TRUE if successful; B_FALSE if unsuccessful.
127  *
128  *        name  - a string giving the name of the kernel thread
129  *
130  * Note: lockp is the lock to protect the callb_cpr_t (cp) structure
131  * later on.  No lock held is needed for this initialization.
132  */
133 #ifdef __NetBSD__
134 #define   CALLB_CPR_INIT(cp, lockp, func, name)   {                             \
135                     /* XXXNETBSD set thread name */                                       \
136                     bzero((caddr_t)(cp), sizeof (callb_cpr_t));                 \
137                     (cp)->cc_lockp = lockp;                                               \
138                     (cp)->cc_id = callb_add(func, (void *)(cp),                 \
139                               CB_CL_CPR_DAEMON, name);                          \
140                     cv_init(&(cp)->cc_callb_cv, NULL, CV_DEFAULT, NULL);        \
141                     cv_init(&(cp)->cc_stop_cv, NULL, CV_DEFAULT, NULL);         \
142           }
143 #else
144 #define   CALLB_CPR_INIT(cp, lockp, func, name)   {                             \
145                     strlcpy(curthread->td_name, (name),                         \
146                         sizeof(curthread->td_name));                            \
147                     bzero((caddr_t)(cp), sizeof (callb_cpr_t));                 \
148                     (cp)->cc_lockp = lockp;                                               \
149                     (cp)->cc_id = callb_add(func, (void *)(cp),                 \
150                               CB_CL_CPR_DAEMON, name);                          \
151                     cv_init(&(cp)->cc_callb_cv, NULL, CV_DEFAULT, NULL);        \
152                     cv_init(&(cp)->cc_stop_cv, NULL, CV_DEFAULT, NULL);         \
153           }
154 #endif
155 
156 #ifndef __lock_lint
157 #define   CALLB_CPR_ASSERT(cp)          ASSERT(MUTEX_HELD((cp)->cc_lockp));
158 #else
159 #define   CALLB_CPR_ASSERT(cp)
160 #endif
161 /*
162  * Some threads (like the idle threads) do not adhere to the callback
163  * protocol and are always considered safe.  Such threads must never exit.
164  * They register their presence by calling this macro during their
165  * initialization.
166  *
167  * Args:
168  *        t         - thread pointer of the client kernel thread
169  *        name      - a string giving the name of the kernel thread
170  */
171 #define   CALLB_CPR_INIT_SAFE(t, name) {                                                  \
172                     (void) callb_add_thread(callb_generic_cpr_safe,             \
173                     (void *) &callb_cprinfo_safe, CB_CL_CPR_DAEMON,             \
174                         name, t);                                                         \
175           }
176 /*
177  * The lock to protect cp's content must be held before
178  * calling the following two macros.
179  *
180  * Any code region between CALLB_CPR_SAFE_BEGIN and CALLB_CPR_SAFE_END
181  * is safe for checkpoint/resume.
182  */
183 #define   CALLB_CPR_SAFE_BEGIN(cp) {                        \
184                     CALLB_CPR_ASSERT(cp)                              \
185                     (cp)->cc_events |= CALLB_CPR_SAFE;      \
186                     if ((cp)->cc_events & CALLB_CPR_START)  \
187                               cv_signal(&(cp)->cc_callb_cv);          \
188           }
189 #define   CALLB_CPR_SAFE_END(cp, lockp) {                                       \
190                     CALLB_CPR_ASSERT(cp)                                        \
191                     while ((cp)->cc_events & CALLB_CPR_START)         \
192                               cv_wait(&(cp)->cc_stop_cv, lockp);      \
193                     (cp)->cc_events &= ~CALLB_CPR_SAFE;               \
194           }
195 /*
196  * cv_destroy is nop right now but may be needed in the future.
197  */
198 #define   CALLB_CPR_EXIT(cp) {                                        \
199                     CALLB_CPR_ASSERT(cp)                              \
200                     (cp)->cc_events |= CALLB_CPR_SAFE;      \
201                     if ((cp)->cc_events & CALLB_CPR_START)  \
202                               cv_signal(&(cp)->cc_callb_cv);          \
203                     mutex_exit((cp)->cc_lockp);             \
204                     (void) callb_delete((cp)->cc_id);       \
205                     cv_destroy(&(cp)->cc_callb_cv);                   \
206                     cv_destroy(&(cp)->cc_stop_cv);                    \
207           }
208 
209 extern callb_cpr_t callb_cprinfo_safe;
210 extern callb_id_t callb_add(boolean_t  (*)(void *, int), void *, int, char *);
211 extern callb_id_t callb_add_thread(boolean_t (*)(void *, int),
212     void *, int, char *, kthread_id_t);
213 extern int          callb_delete(callb_id_t);
214 extern void         callb_execute(callb_id_t, int);
215 extern void         *callb_execute_class(int, int);
216 extern boolean_t callb_generic_cpr(void *, int);
217 extern boolean_t callb_generic_cpr_safe(void *, int);
218 extern boolean_t callb_is_stopped(kthread_id_t, caddr_t *);
219 extern void         callb_lock_table(void);
220 extern void         callb_unlock_table(void);
221 #ifdef __NetBSD__
222 extern void         callb_init(void *);
223 extern void         callb_fini(void *);
224 #endif
225 #endif
226 
227 #ifdef    __cplusplus
228 }
229 #endif
230 
231 #endif    /* _SYS_CALLB_H */
232