Print this page
XXXX introduce drv_sectohz
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/sun4u/excalibur/io/xcalwd.c
+++ new/usr/src/uts/sun4u/excalibur/io/xcalwd.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 26
27 27 /*
28 28 * Excalibur fans watchdog module
29 29 */
30 30
31 31 #include <sys/conf.h>
32 32 #include <sys/types.h>
33 33 #include <sys/mkdev.h>
34 34 #include <sys/ddi.h>
35 35 #include <sys/stat.h>
36 36 #include <sys/modctl.h>
37 37 #include <sys/sunddi.h>
38 38 #include <sys/sunndi.h>
39 39 #include <sys/ksynch.h>
40 40 #include <sys/file.h>
41 41 #include <sys/errno.h>
42 42 #include <sys/open.h>
43 43 #include <sys/cred.h>
44 44 #include <sys/xcalwd.h>
45 45 #include <sys/policy.h>
46 46 #include <sys/platform_module.h>
47 47
48 48 extern struct mod_ops mod_driverops;
49 49
50 50 #define MINOR_DEVICE_NAME "xcalwd"
51 51
52 52 /*
53 53 * Define your per instance state data
54 54 */
55 55 typedef struct xcalwd_state {
56 56 kmutex_t lock;
57 57 boolean_t started;
58 58 int intvl;
59 59 timeout_id_t tid;
60 60 dev_info_t *dip;
61 61 } xcalwd_state_t;
62 62
63 63 /*
64 64 * Pointer to soft states
65 65 */
66 66 static void *xcalwd_statep;
67 67
68 68 /*
69 69 * dev_ops
70 70 */
71 71 static int xcalwd_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd,
72 72 void *arg, void **resultp);
73 73 static int xcalwd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
74 74 static int xcalwd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
75 75
76 76 /*
77 77 * cb_ops
78 78 */
79 79 static int xcalwd_open(dev_t *devp, int flag, int otyp, cred_t *credp);
80 80 static int xcalwd_close(dev_t dev, int flag, int otyp, cred_t *credp);
81 81 static int xcalwd_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
82 82 cred_t *credp, int *rvalp);
83 83 /*
84 84 * timeout handler
85 85 */
86 86 static void xcalwd_timeout(void *arg);
87 87
88 88 /*
89 89 * cb_ops
90 90 */
91 91 static struct cb_ops xcalwd_cb_ops = {
92 92 xcalwd_open, /* open */
93 93 xcalwd_close, /* close */
94 94 nodev, /* strategy */
95 95 nodev, /* print */
96 96 nodev, /* dump */
97 97 nodev, /* read */
98 98 nodev, /* write */
99 99 xcalwd_ioctl, /* ioctl */
100 100 nodev, /* devmap */
101 101 nodev, /* mmap */
102 102 nodev, /* segmap */
103 103 nochpoll, /* chpoll */
104 104 ddi_prop_op, /* prop_op */
105 105 NULL, /* streamtab */
106 106 D_NEW | D_MP | D_64BIT, /* cb_flag */
107 107 CB_REV, /* rev */
108 108 nodev, /* int (*cb_aread)() */
109 109 nodev /* int (*cb_awrite)() */
110 110 };
111 111
112 112 /*
113 113 * dev_ops
114 114 */
115 115 static struct dev_ops xcalwd_dev_ops = {
116 116 DEVO_REV, /* devo_rev */
117 117 0, /* devo_refcnt */
118 118 xcalwd_getinfo, /* getinfo */
119 119 nulldev, /* identify */
120 120 nulldev, /* probe */
121 121 xcalwd_attach, /* attach */
122 122 xcalwd_detach, /* detach */
123 123 nodev, /* devo_reset */
124 124 &xcalwd_cb_ops, /* devo_cb_ops */
125 125 NULL, /* devo_bus_ops */
126 126 NULL, /* devo_power */
127 127 ddi_quiesce_not_needed, /* devo_quiesce */
128 128 };
129 129
130 130 /*
131 131 * modldrv
132 132 */
133 133 static struct modldrv xcalwd_modldrv = {
134 134 &mod_driverops, /* drv_modops */
135 135 "Excalibur watchdog timer v1.7 ", /* drv_linkinfo */
136 136 &xcalwd_dev_ops /* drv_dev_ops */
137 137 };
138 138
139 139 /*
140 140 * modlinkage
141 141 */
142 142 static struct modlinkage xcalwd_modlinkage = {
143 143 MODREV_1,
144 144 &xcalwd_modldrv,
145 145 NULL
146 146 };
147 147
148 148 int
149 149 _init(void)
150 150 {
151 151 int error;
152 152
153 153 /*
154 154 * Initialize the module state structure
155 155 */
156 156 error = ddi_soft_state_init(&xcalwd_statep,
157 157 sizeof (xcalwd_state_t), 0);
158 158 if (error) {
159 159 return (error);
160 160 }
161 161
162 162 /*
163 163 * Link the driver into the system
164 164 */
165 165 error = mod_install(&xcalwd_modlinkage);
166 166 if (error) {
167 167 ddi_soft_state_fini(&xcalwd_statep);
168 168 return (error);
169 169 }
170 170 return (0);
171 171 }
172 172
173 173 int
174 174 _fini(void)
175 175 {
176 176 int error;
177 177
178 178 error = mod_remove(&xcalwd_modlinkage);
179 179 if (error != 0) {
180 180 return (error);
181 181 }
182 182
183 183 /*
184 184 * Cleanup resources allocated in _init
185 185 */
186 186 ddi_soft_state_fini(&xcalwd_statep);
187 187 return (0);
188 188 }
189 189
190 190 int
191 191 _info(struct modinfo *modinfop)
192 192 {
193 193 return (mod_info(&xcalwd_modlinkage, modinfop));
194 194 }
195 195
196 196 /*ARGSUSED*/
197 197 static int
198 198 xcalwd_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd,
199 199 void *arg, void **resultp)
200 200 {
201 201 int retval;
202 202 dev_t dev = (dev_t)arg;
203 203 int instance;
204 204 xcalwd_state_t *tsp;
205 205
206 206 retval = DDI_FAILURE;
207 207 switch (cmd) {
208 208 case DDI_INFO_DEVT2DEVINFO:
209 209 instance = getminor(dev);
210 210 tsp = ddi_get_soft_state(xcalwd_statep, instance);
211 211 if (tsp == NULL)
212 212 *resultp = NULL;
213 213 else {
214 214 *resultp = tsp->dip;
215 215 retval = DDI_SUCCESS;
216 216 }
217 217 break;
218 218 case DDI_INFO_DEVT2INSTANCE:
219 219 *resultp = (void *)(uintptr_t)getminor(dev);
220 220 retval = DDI_SUCCESS;
221 221 break;
222 222 default:
223 223 break;
224 224 }
225 225 return (retval);
226 226 }
227 227
228 228 static int
229 229 xcalwd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
230 230 {
231 231 int instance;
232 232 xcalwd_state_t *tsp;
233 233
234 234 switch (cmd) {
235 235 case DDI_ATTACH:
236 236 instance = ddi_get_instance(dip);
237 237
238 238 if (&plat_fan_blast == NULL) {
239 239 cmn_err(CE_WARN, "missing plat_fan_blast function");
240 240 return (DDI_FAILURE);
241 241 }
242 242
243 243 if (ddi_soft_state_zalloc(xcalwd_statep, instance) !=
244 244 DDI_SUCCESS) {
245 245 cmn_err(CE_WARN, "attach could not alloc"
246 246 "%d state structure", instance);
247 247 return (DDI_FAILURE);
248 248 }
249 249
250 250 tsp = ddi_get_soft_state(xcalwd_statep, instance);
251 251 if (tsp == NULL) {
252 252 cmn_err(CE_WARN, "get state failed %d",
253 253 instance);
254 254 return (DDI_FAILURE);
255 255 }
256 256
257 257 if (ddi_create_minor_node(dip, MINOR_DEVICE_NAME,
258 258 S_IFCHR, instance, DDI_PSEUDO, NULL) == DDI_FAILURE) {
259 259 cmn_err(CE_WARN, "create minor node failed\n");
260 260 return (DDI_FAILURE);
261 261 }
262 262
263 263 mutex_init(&tsp->lock, NULL, MUTEX_DRIVER, NULL);
264 264 tsp->started = B_FALSE;
265 265 tsp->intvl = 0;
266 266 tsp->tid = 0;
267 267 tsp->dip = dip;
268 268 ddi_report_dev(dip);
269 269 return (DDI_SUCCESS);
270 270
271 271 case DDI_RESUME:
272 272 return (DDI_SUCCESS);
273 273 default:
274 274 break;
275 275 }
276 276 return (DDI_FAILURE);
277 277 }
278 278
279 279 static int
280 280 xcalwd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
281 281 {
282 282 xcalwd_state_t *tsp;
283 283 int instance;
284 284
285 285 switch (cmd) {
286 286 case DDI_DETACH:
287 287 instance = ddi_get_instance(dip);
288 288 tsp = ddi_get_soft_state(xcalwd_statep, instance);
289 289 ddi_remove_minor_node(dip, NULL);
290 290 mutex_destroy(&tsp->lock);
291 291 ddi_soft_state_free(xcalwd_statep, instance);
292 292 return (DDI_SUCCESS);
293 293 case DDI_SUSPEND:
294 294 return (DDI_SUCCESS);
295 295 default:
296 296 break;
297 297 }
298 298 return (DDI_FAILURE);
299 299 }
300 300
301 301 /*
302 302 * Watchdog timeout handler that calls plat_fan_blast to take
303 303 * the failsafe action.
304 304 */
305 305 static void
306 306 xcalwd_timeout(void *arg)
307 307 {
308 308 int instance = (int)(uintptr_t)arg;
309 309 xcalwd_state_t *tsp;
310 310
311 311 if (instance < 0)
312 312 return;
313 313
314 314 tsp = ddi_get_soft_state(xcalwd_statep, instance);
315 315 if (tsp == NULL)
316 316 return;
317 317
318 318 mutex_enter(&tsp->lock);
319 319 if (tsp->started == B_FALSE || tsp->tid == 0) {
320 320 tsp->tid = 0;
321 321 mutex_exit(&tsp->lock);
322 322 return;
323 323 }
324 324 mutex_exit(&tsp->lock);
325 325
326 326 plat_fan_blast();
327 327 }
328 328
329 329 /*ARGSUSED*/
330 330 static int
331 331 xcalwd_open(dev_t *devp, int flag, int otyp, cred_t *credp)
332 332 {
333 333 int instance;
334 334
335 335 if (secpolicy_sys_config(credp, B_FALSE) != 0)
336 336 return (EPERM);
337 337
338 338 if (otyp != OTYP_CHR)
339 339 return (EINVAL);
340 340
341 341 instance = getminor(*devp);
342 342 if (instance < 0)
343 343 return (ENXIO);
344 344
345 345 if (ddi_get_soft_state(xcalwd_statep, instance) == NULL) {
346 346 return (ENXIO);
347 347 }
348 348
349 349 return (0);
350 350 }
351 351
352 352 /*ARGSUSED*/
353 353 static int
354 354 xcalwd_close(dev_t dev, int flag, int otyp, cred_t *credp)
355 355 {
356 356 xcalwd_state_t *tsp;
357 357 int instance;
358 358 timeout_id_t tid;
359 359
360 360 instance = getminor(dev);
361 361 if (instance < 0)
362 362 return (ENXIO);
363 363 tsp = ddi_get_soft_state(xcalwd_statep, instance);
364 364 if (tsp == NULL)
365 365 return (ENXIO);
366 366
367 367 mutex_enter(&tsp->lock);
368 368 if (tsp->started == B_FALSE) {
369 369 tsp->tid = 0;
370 370 mutex_exit(&tsp->lock);
371 371 return (0);
372 372 }
373 373 /*
374 374 * The watchdog is enabled. Cancel the pending timer
375 375 * and call plat_fan_blast.
376 376 */
377 377 tsp->started = B_FALSE;
378 378 tid = tsp->tid;
379 379 tsp->tid = 0;
380 380 mutex_exit(&tsp->lock);
381 381 if (tid != 0)
382 382 (void) untimeout(tid);
383 383 plat_fan_blast();
384 384
385 385 return (0);
386 386 }
387 387
388 388 /*
389 389 * These are private ioctls for PICL environmental control plug-in
390 390 * to use. The plug-in enables the watchdog before performing
391 391 * altering fan speeds. It also periodically issues a keepalive
392 392 * to the watchdog to cancel and reinstate the watchdog timer.
393 393 * The watchdog timeout handler when executed with the watchdog
394 394 * enabled sets fans to full blast by calling plat_fan_blast.
395 395 */
396 396 /*ARGSUSED*/
397 397 static int
398 398 xcalwd_ioctl(dev_t dev, int cmd, intptr_t arg, int flag,
399 399 cred_t *cred_p, int *rvalp)
400 400 {
401 401 int instance;
402 402 xcalwd_state_t *tsp;
403 403 int intvl;
404 404 int o_intvl;
405 405 boolean_t curstate;
406 406 timeout_id_t tid;
407 407
408 408 if (secpolicy_sys_config(cred_p, B_FALSE) != 0)
409 409 return (EPERM);
410 410
411 411 instance = getminor(dev);
412 412 if (instance < 0)
413 413 return (ENXIO);
414 414
415 415 tsp = ddi_get_soft_state(xcalwd_statep, instance);
416 416 if (tsp == NULL)
417 417 return (ENXIO);
418 418
419 419 switch (cmd) {
420 420 case XCALWD_STOPWATCHDOG:
421 421 /*
422 422 * cancels any pending timer and disables the timer.
423 423 */
424 424 tid = 0;
425 425 mutex_enter(&tsp->lock);
426 426 if (tsp->started == B_FALSE) {
427 427 mutex_exit(&tsp->lock);
428 428 return (0);
429 429 }
430 430 tid = tsp->tid;
431 431 tsp->started = B_FALSE;
432 432 tsp->tid = 0;
433 433 mutex_exit(&tsp->lock);
434 434 if (tid != 0)
435 435 (void) untimeout(tid);
436 436 return (0);
437 437 case XCALWD_STARTWATCHDOG:
438 438 if (ddi_copyin((void *)arg, &intvl, sizeof (intvl), flag))
439 439 return (EFAULT);
440 440 if (intvl == 0)
441 441 return (EINVAL);
442 442
443 443 mutex_enter(&tsp->lock);
444 444 o_intvl = tsp->intvl;
445 445 mutex_exit(&tsp->lock);
446 446
447 447 if (ddi_copyout((const void *)&o_intvl, (void *)arg,
448 448 sizeof (o_intvl), flag))
↓ open down ↓ |
448 lines elided |
↑ open up ↑ |
449 449 return (EFAULT);
450 450
451 451 mutex_enter(&tsp->lock);
452 452 if (tsp->started == B_TRUE) {
453 453 mutex_exit(&tsp->lock);
454 454 return (EINVAL);
455 455 }
456 456 tsp->intvl = intvl;
457 457 tsp->tid = realtime_timeout(xcalwd_timeout,
458 458 (void *)(uintptr_t)instance,
459 - drv_usectohz(1000000) * tsp->intvl);
459 + drv_sectohz(tsp->intvl));
460 460 tsp->started = B_TRUE;
461 461 mutex_exit(&tsp->lock);
462 462 return (0);
463 463 case XCALWD_KEEPALIVE:
464 464 tid = 0;
465 465 mutex_enter(&tsp->lock);
466 466 tid = tsp->tid;
467 467 tsp->tid = 0;
468 468 mutex_exit(&tsp->lock);
469 469 if (tid != 0)
470 470 (void) untimeout(tid); /* cancel */
471 471
472 472 mutex_enter(&tsp->lock);
473 473 if (tsp->started == B_TRUE) /* reinstate */
474 474 tsp->tid = realtime_timeout(xcalwd_timeout,
475 475 (void *)(uintptr_t)instance,
476 - drv_usectohz(1000000) * tsp->intvl);
476 + drv_sectohz(tsp->intvl));
477 477 mutex_exit(&tsp->lock);
478 478 return (0);
479 479 case XCALWD_GETSTATE:
480 480 mutex_enter(&tsp->lock);
481 481 curstate = tsp->started;
482 482 mutex_exit(&tsp->lock);
483 483 if (ddi_copyout((const void *)&curstate, (void *)arg,
484 484 sizeof (curstate), flag))
485 485 return (EFAULT);
486 486 return (0);
487 487 default:
488 488 return (EINVAL);
489 489 }
490 490 /*NOTREACHED*/
491 491 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX