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