kernel: remove unused utsname_set_machine()
[unleashed.git] / usr / src / uts / sun4u / excalibur / io / xcalwd.c
bloba712ae51026f96d272be1f81baf14c9e73cac1bf
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
28 * Excalibur fans watchdog module
31 #include <sys/conf.h>
32 #include <sys/types.h>
33 #include <sys/mkdev.h>
34 #include <sys/ddi.h>
35 #include <sys/stat.h>
36 #include <sys/modctl.h>
37 #include <sys/sunddi.h>
38 #include <sys/sunndi.h>
39 #include <sys/ksynch.h>
40 #include <sys/file.h>
41 #include <sys/errno.h>
42 #include <sys/open.h>
43 #include <sys/cred.h>
44 #include <sys/xcalwd.h>
45 #include <sys/policy.h>
46 #include <sys/platform_module.h>
48 extern struct mod_ops mod_driverops;
50 #define MINOR_DEVICE_NAME "xcalwd"
53 * Define your per instance state data
55 typedef struct xcalwd_state {
56 kmutex_t lock;
57 boolean_t started;
58 int intvl;
59 timeout_id_t tid;
60 dev_info_t *dip;
61 } xcalwd_state_t;
64 * Pointer to soft states
66 static void *xcalwd_statep;
69 * dev_ops
71 static int xcalwd_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd,
72 void *arg, void **resultp);
73 static int xcalwd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
74 static int xcalwd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
77 * cb_ops
79 static int xcalwd_open(dev_t *devp, int flag, int otyp, cred_t *credp);
80 static int xcalwd_close(dev_t dev, int flag, int otyp, cred_t *credp);
81 static int xcalwd_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
82 cred_t *credp, int *rvalp);
84 * timeout handler
86 static void xcalwd_timeout(void *arg);
89 * cb_ops
91 static struct cb_ops xcalwd_cb_ops = {
92 xcalwd_open, /* open */
93 xcalwd_close, /* close */
94 nodev, /* strategy */
95 nodev, /* print */
96 nodev, /* dump */
97 nodev, /* read */
98 nodev, /* write */
99 xcalwd_ioctl, /* ioctl */
100 nodev, /* devmap */
101 nodev, /* mmap */
102 nodev, /* segmap */
103 nochpoll, /* chpoll */
104 ddi_prop_op, /* prop_op */
105 NULL, /* streamtab */
106 D_NEW | D_MP | D_64BIT, /* cb_flag */
107 CB_REV, /* rev */
108 nodev, /* int (*cb_aread)() */
109 nodev /* int (*cb_awrite)() */
113 * dev_ops
115 static struct dev_ops xcalwd_dev_ops = {
116 DEVO_REV, /* devo_rev */
117 0, /* devo_refcnt */
118 xcalwd_getinfo, /* getinfo */
119 nulldev, /* identify */
120 nulldev, /* probe */
121 xcalwd_attach, /* attach */
122 xcalwd_detach, /* detach */
123 nodev, /* devo_reset */
124 &xcalwd_cb_ops, /* devo_cb_ops */
125 NULL, /* devo_bus_ops */
126 NULL, /* devo_power */
127 ddi_quiesce_not_needed, /* devo_quiesce */
131 * modldrv
133 static struct modldrv xcalwd_modldrv = {
134 &mod_driverops, /* drv_modops */
135 "Excalibur watchdog timer v1.7 ", /* drv_linkinfo */
136 &xcalwd_dev_ops /* drv_dev_ops */
140 * modlinkage
142 static struct modlinkage xcalwd_modlinkage = {
143 MODREV_1,
144 &xcalwd_modldrv,
145 NULL
149 _init(void)
151 int error;
154 * Initialize the module state structure
156 error = ddi_soft_state_init(&xcalwd_statep,
157 sizeof (xcalwd_state_t), 0);
158 if (error) {
159 return (error);
163 * Link the driver into the system
165 error = mod_install(&xcalwd_modlinkage);
166 if (error) {
167 ddi_soft_state_fini(&xcalwd_statep);
168 return (error);
170 return (0);
174 _fini(void)
176 int error;
178 error = mod_remove(&xcalwd_modlinkage);
179 if (error != 0) {
180 return (error);
184 * Cleanup resources allocated in _init
186 ddi_soft_state_fini(&xcalwd_statep);
187 return (0);
191 _info(struct modinfo *modinfop)
193 return (mod_info(&xcalwd_modlinkage, modinfop));
196 /*ARGSUSED*/
197 static int
198 xcalwd_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd,
199 void *arg, void **resultp)
201 int retval;
202 dev_t dev = (dev_t)arg;
203 int instance;
204 xcalwd_state_t *tsp;
206 retval = DDI_FAILURE;
207 switch (cmd) {
208 case DDI_INFO_DEVT2DEVINFO:
209 instance = getminor(dev);
210 tsp = ddi_get_soft_state(xcalwd_statep, instance);
211 if (tsp == NULL)
212 *resultp = NULL;
213 else {
214 *resultp = tsp->dip;
215 retval = DDI_SUCCESS;
217 break;
218 case DDI_INFO_DEVT2INSTANCE:
219 *resultp = (void *)(uintptr_t)getminor(dev);
220 retval = DDI_SUCCESS;
221 break;
222 default:
223 break;
225 return (retval);
228 static int
229 xcalwd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
231 int instance;
232 xcalwd_state_t *tsp;
234 switch (cmd) {
235 case DDI_ATTACH:
236 instance = ddi_get_instance(dip);
238 if (&plat_fan_blast == NULL) {
239 cmn_err(CE_WARN, "missing plat_fan_blast function");
240 return (DDI_FAILURE);
243 if (ddi_soft_state_zalloc(xcalwd_statep, instance) !=
244 DDI_SUCCESS) {
245 cmn_err(CE_WARN, "attach could not alloc"
246 "%d state structure", instance);
247 return (DDI_FAILURE);
250 tsp = ddi_get_soft_state(xcalwd_statep, instance);
251 if (tsp == NULL) {
252 cmn_err(CE_WARN, "get state failed %d",
253 instance);
254 return (DDI_FAILURE);
257 if (ddi_create_minor_node(dip, MINOR_DEVICE_NAME,
258 S_IFCHR, instance, DDI_PSEUDO, NULL) == DDI_FAILURE) {
259 cmn_err(CE_WARN, "create minor node failed\n");
260 return (DDI_FAILURE);
263 mutex_init(&tsp->lock, NULL, MUTEX_DRIVER, NULL);
264 tsp->started = B_FALSE;
265 tsp->intvl = 0;
266 tsp->tid = 0;
267 tsp->dip = dip;
268 ddi_report_dev(dip);
269 return (DDI_SUCCESS);
271 case DDI_RESUME:
272 return (DDI_SUCCESS);
273 default:
274 break;
276 return (DDI_FAILURE);
279 static int
280 xcalwd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
282 xcalwd_state_t *tsp;
283 int instance;
285 switch (cmd) {
286 case DDI_DETACH:
287 instance = ddi_get_instance(dip);
288 tsp = ddi_get_soft_state(xcalwd_statep, instance);
289 ddi_remove_minor_node(dip, NULL);
290 mutex_destroy(&tsp->lock);
291 ddi_soft_state_free(xcalwd_statep, instance);
292 return (DDI_SUCCESS);
293 case DDI_SUSPEND:
294 return (DDI_SUCCESS);
295 default:
296 break;
298 return (DDI_FAILURE);
302 * Watchdog timeout handler that calls plat_fan_blast to take
303 * the failsafe action.
305 static void
306 xcalwd_timeout(void *arg)
308 int instance = (int)(uintptr_t)arg;
309 xcalwd_state_t *tsp;
311 if (instance < 0)
312 return;
314 tsp = ddi_get_soft_state(xcalwd_statep, instance);
315 if (tsp == NULL)
316 return;
318 mutex_enter(&tsp->lock);
319 if (tsp->started == B_FALSE || tsp->tid == 0) {
320 tsp->tid = 0;
321 mutex_exit(&tsp->lock);
322 return;
324 mutex_exit(&tsp->lock);
326 plat_fan_blast();
329 /*ARGSUSED*/
330 static int
331 xcalwd_open(dev_t *devp, int flag, int otyp, cred_t *credp)
333 int instance;
335 if (secpolicy_sys_config(credp, B_FALSE) != 0)
336 return (EPERM);
338 if (otyp != OTYP_CHR)
339 return (EINVAL);
341 instance = getminor(*devp);
342 if (instance < 0)
343 return (ENXIO);
345 if (ddi_get_soft_state(xcalwd_statep, instance) == NULL) {
346 return (ENXIO);
349 return (0);
352 /*ARGSUSED*/
353 static int
354 xcalwd_close(dev_t dev, int flag, int otyp, cred_t *credp)
356 xcalwd_state_t *tsp;
357 int instance;
358 timeout_id_t tid;
360 instance = getminor(dev);
361 if (instance < 0)
362 return (ENXIO);
363 tsp = ddi_get_soft_state(xcalwd_statep, instance);
364 if (tsp == NULL)
365 return (ENXIO);
367 mutex_enter(&tsp->lock);
368 if (tsp->started == B_FALSE) {
369 tsp->tid = 0;
370 mutex_exit(&tsp->lock);
371 return (0);
374 * The watchdog is enabled. Cancel the pending timer
375 * and call plat_fan_blast.
377 tsp->started = B_FALSE;
378 tid = tsp->tid;
379 tsp->tid = 0;
380 mutex_exit(&tsp->lock);
381 if (tid != 0)
382 (void) untimeout(tid);
383 plat_fan_blast();
385 return (0);
389 * These are private ioctls for PICL environmental control plug-in
390 * to use. The plug-in enables the watchdog before performing
391 * altering fan speeds. It also periodically issues a keepalive
392 * to the watchdog to cancel and reinstate the watchdog timer.
393 * The watchdog timeout handler when executed with the watchdog
394 * enabled sets fans to full blast by calling plat_fan_blast.
396 /*ARGSUSED*/
397 static int
398 xcalwd_ioctl(dev_t dev, int cmd, intptr_t arg, int flag,
399 cred_t *cred_p, int *rvalp)
401 int instance;
402 xcalwd_state_t *tsp;
403 int intvl;
404 int o_intvl;
405 boolean_t curstate;
406 timeout_id_t tid;
408 if (secpolicy_sys_config(cred_p, B_FALSE) != 0)
409 return (EPERM);
411 instance = getminor(dev);
412 if (instance < 0)
413 return (ENXIO);
415 tsp = ddi_get_soft_state(xcalwd_statep, instance);
416 if (tsp == NULL)
417 return (ENXIO);
419 switch (cmd) {
420 case XCALWD_STOPWATCHDOG:
422 * cancels any pending timer and disables the timer.
424 tid = 0;
425 mutex_enter(&tsp->lock);
426 if (tsp->started == B_FALSE) {
427 mutex_exit(&tsp->lock);
428 return (0);
430 tid = tsp->tid;
431 tsp->started = B_FALSE;
432 tsp->tid = 0;
433 mutex_exit(&tsp->lock);
434 if (tid != 0)
435 (void) untimeout(tid);
436 return (0);
437 case XCALWD_STARTWATCHDOG:
438 if (ddi_copyin((void *)arg, &intvl, sizeof (intvl), flag))
439 return (EFAULT);
440 if (intvl == 0)
441 return (EINVAL);
443 mutex_enter(&tsp->lock);
444 o_intvl = tsp->intvl;
445 mutex_exit(&tsp->lock);
447 if (ddi_copyout((const void *)&o_intvl, (void *)arg,
448 sizeof (o_intvl), flag))
449 return (EFAULT);
451 mutex_enter(&tsp->lock);
452 if (tsp->started == B_TRUE) {
453 mutex_exit(&tsp->lock);
454 return (EINVAL);
456 tsp->intvl = intvl;
457 tsp->tid = realtime_timeout(xcalwd_timeout,
458 (void *)(uintptr_t)instance,
459 drv_usectohz(1000000) * tsp->intvl);
460 tsp->started = B_TRUE;
461 mutex_exit(&tsp->lock);
462 return (0);
463 case XCALWD_KEEPALIVE:
464 tid = 0;
465 mutex_enter(&tsp->lock);
466 tid = tsp->tid;
467 tsp->tid = 0;
468 mutex_exit(&tsp->lock);
469 if (tid != 0)
470 (void) untimeout(tid); /* cancel */
472 mutex_enter(&tsp->lock);
473 if (tsp->started == B_TRUE) /* reinstate */
474 tsp->tid = realtime_timeout(xcalwd_timeout,
475 (void *)(uintptr_t)instance,
476 drv_usectohz(1000000) * tsp->intvl);
477 mutex_exit(&tsp->lock);
478 return (0);
479 case XCALWD_GETSTATE:
480 mutex_enter(&tsp->lock);
481 curstate = tsp->started;
482 mutex_exit(&tsp->lock);
483 if (ddi_copyout((const void *)&curstate, (void *)arg,
484 sizeof (curstate), flag))
485 return (EFAULT);
486 return (0);
487 default:
488 return (EINVAL);
490 /*NOTREACHED*/