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