xref: /titanic_50/usr/src/uts/common/avs/ns/nsctl/nsc_power.c (revision fcf3ce441efd61da9bb2884968af01cb7c1452cc)
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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/types.h>
27 #include <sys/ksynch.h>
28 #include <sys/kmem.h>
29 #include <sys/file.h>
30 #include <sys/errno.h>
31 #include <sys/open.h>
32 #include <sys/cred.h>
33 #include <sys/conf.h>
34 #include <sys/uio.h>
35 #include <sys/cmn_err.h>
36 
37 #define	__NSC_GEN__
38 #include "nsc_dev.h"
39 #include "nsc_ioctl.h"
40 #include "nsc_power.h"
41 #include "../nsctl.h"
42 
43 extern nsc_mem_t *_nsc_local_mem;
44 static  int null_power(void);
45 
46 
47 typedef struct _nsc_power_s {
48 	struct _nsc_power_s *next;	/* chain */
49 	char *name;			/* module name */
50 	void (*pw_power_lost)(int);	/* callback power lost(rideout) */
51 	void (*pw_power_ok)(void);	/* callback power ok */
52 	void (*pw_power_down)(void);
53 				/* callback power down (shutdown imminent) */
54 } _nsc_power_t;
55 
56 #define	_P(x)	(((long)(&((_nsc_power_t *)0)->x))/sizeof (long))
57 
58 static nsc_def_t _nsc_power_def[] = {
59 	"Power_Lost",	(uintptr_t)null_power,	_P(pw_power_lost),
60 	"Power_OK",	(uintptr_t)null_power,	_P(pw_power_ok),
61 	"Power_Down",	(uintptr_t)null_power,	_P(pw_power_down),
62 	0,		0,			0,
63 };
64 
65 static _nsc_power_t *_power_clients;
66 static kmutex_t _power_mutex;
67 
68 
null_power(void)69 static int null_power(void)
70 /*
71  * init null_power - dummy power routine for clients that choose not
72  * to implement all the power hooks.
73  *
74  */
75 {
76 	return (0);
77 }
78 
79 /*
80  * int
81  * _nsc_power
82  *	Call registered clients of the generic power ioctls.
83  *
84  * Calling/Exit State:
85  *	Calls all the registered clients with a message describing the
86  *      current state of the power for the system.
87  */
88 int
_nsc_power(blind_t argp,int * rvp)89 _nsc_power(blind_t argp, int *rvp)
90 {
91 	nsc_power_ctl_t opc;
92 	_nsc_power_t *pp;
93 
94 	*rvp = 0;
95 	if (copyin((void *) argp, &opc, sizeof (nsc_power_ctl_t)))
96 		return (EFAULT);
97 	mutex_enter(&_power_mutex);
98 
99 	pp = _power_clients;
100 	while (pp) {
101 		switch ((nsc_power_ops_t)opc.msg) {
102 
103 	case Power_OK:
104 			(*pp->pw_power_ok)();
105 			break;
106 
107 	case Power_Down:
108 			(*pp->pw_power_down)();
109 			break;
110 
111 	case Power_Lost:
112 			(*pp->pw_power_lost)(opc.arg1);
113 			break;
114 
115 	default:
116 			mutex_exit(&_power_mutex);
117 			return (EINVAL);
118 		}
119 
120 		pp = pp->next;
121 	}
122 	mutex_exit(&_power_mutex);
123 	return (0);
124 }
125 
126 /*
127  * int
128  * _nsc_init_power (void)
129  *	Initialise power ioctl subsystem.
130  *
131  * Calling/Exit State:
132  *	Called at driver initialisation time to allocate necessary
133  *	data structures.
134  */
135 int
_nsc_init_power(void)136 _nsc_init_power(void)
137 {
138 	mutex_init(&_power_mutex, NULL, MUTEX_DRIVER, NULL);
139 	return (0);
140 }
141 
142 /*
143  * int
144  * _nsc_deinit_power (void)
145  *	Initialise power ioctl subsystem.
146  *
147  * Calling/Exit State:
148  *	Called at driver initialisation time to allocate necessary
149  *	data structures.
150  */
151 int
_nsc_deinit_power(void)152 _nsc_deinit_power(void)
153 {
154 	_nsc_power_t *pp, *npp;
155 
156 	mutex_enter(&_power_mutex);
157 	pp = _power_clients;
158 	while (pp) {
159 		npp = pp->next;
160 		nsc_kmem_free(pp, sizeof (_nsc_power_t));
161 		pp = npp;
162 	}
163 	_power_clients = NULL;
164 	mutex_exit(&_power_mutex);
165 	mutex_destroy(&_power_mutex);
166 	return (0);
167 }
168 
169 /*
170  * blind_t
171  * nsc_register_power (char *name, nsc_def_t *def)
172  *	Register an power ioctl client.
173  *
174  * Calling/Exit State:
175  *	Returns a token for use in future calls to nsc_unregister_power.
176  *      If a client with the same name is already registered then NULL
177  *      is return to indicate failure.
178  *	If registration fails NULL is returned.
179  *
180  * Description:
181  *	Registers an power ioctl client for notifications during subsequent
182  *      ioctl from UPS/PCU management.
183  */
184 blind_t
nsc_register_power(char * name,nsc_def_t * def)185 nsc_register_power(char *name, nsc_def_t *def)
186 {
187 	_nsc_power_t *entry, *pp;
188 
189 
190 	entry = nsc_kmem_alloc(sizeof (_nsc_power_t), 0, _nsc_local_mem);
191 
192 	if (entry == NULL)
193 		return (NULL);
194 	nsc_decode_param(def, _nsc_power_def, (long *)entry);
195 
196 	mutex_enter(&_power_mutex);
197 
198 	for (pp = _power_clients; pp; pp = pp->next) {
199 		if (strcmp(pp->name, name) == 0) {
200 			mutex_exit(&_power_mutex);
201 			nsc_kmem_free(entry, sizeof (_nsc_power_t));
202 			return (NULL);
203 		}
204 	}
205 	entry->name = name;
206 
207 	entry->next = _power_clients;
208 	_power_clients = entry;
209 	mutex_exit(&_power_mutex);
210 	return ((blind_t)entry);
211 }
212 
213 /*
214  * int
215  * nsc_unregister_power (blind_t powerp)
216  *	Un-register a power ioctl client.
217  *
218  * Calling/Exit State:
219  *	Returns 0 on success, otherwise returns an error code.
220  *
221  * Description:
222  *	The specified power ioctl client is un-registered if possible.
223  *      Zero is returned on success otherwise an error code.
224  */
225 int
nsc_unregister_power(blind_t powerp)226 nsc_unregister_power(blind_t powerp)
227 {
228 	_nsc_power_t **xpp, *entry;
229 
230 	entry = (_nsc_power_t *)powerp;
231 	if (entry == NULL)
232 		return (EINVAL);
233 
234 	mutex_enter(&_power_mutex);
235 
236 	for (xpp = &_power_clients; *xpp; xpp = &(*xpp)->next)
237 		if (*xpp == entry)
238 			break;
239 
240 	if (*xpp == NULL) {
241 		mutex_exit(&_power_mutex);
242 		return (EALREADY);
243 	}
244 	*xpp = entry->next;
245 	mutex_exit(&_power_mutex);
246 	nsc_kmem_free(entry, sizeof (_nsc_power_t));
247 
248 	return (0);
249 }
250