xref: /illumos-gate/usr/src/uts/sun4u/mpxu/io/tsalarm.c (revision 4de2612967d06c4fdbf524a62556a1e8118a006f)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <sys/conf.h>
32 #include <sys/modctl.h>
33 #include <sys/sunddi.h>
34 #include <sys/callb.h>
35 #include <sys/strlog.h>
36 #include <sys/file.h>
37 #include <sys/lom_io.h>
38 #include <sys/ddi.h>
39 #include <sys/time.h>
40 
41 #define	LOMIOCALCTL_OLD		_IOW('a', 4, ts_aldata_t)
42 #define	LOMIOCALSTATE_OLD	_IOWR('a', 5, ts_aldata_t)
43 
44 struct tsalarm_softc {
45 	dev_info_t *dip;
46 	kmutex_t mutex;
47 };
48 
49 #define	getsoftc(minor)	\
50 		((struct tsalarm_softc *)ddi_get_soft_state(statep, (minor)))
51 /*
52  * Driver entry points
53  */
54 
55 /* dev_ops and cb_ops entry point function declarations */
56 
57 static int	tsalarm_attach(dev_info_t *, ddi_attach_cmd_t);
58 static int	tsalarm_detach(dev_info_t *, ddi_detach_cmd_t);
59 static int	tsalarm_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
60 
61 static int	tsalarm_open(dev_t *, int, int, cred_t *);
62 static int	tsalarm_close(dev_t, int, int, cred_t *);
63 static int	tsalarm_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
64 
65 static struct cb_ops tsalarm_cb_ops = {
66 	tsalarm_open,	/* open */
67 	tsalarm_close,	/* close */
68 	nodev,		/* strategy() */
69 	nodev,		/* print() */
70 	nodev,		/* dump() */
71 	nodev,		/* read() */
72 	nodev,		/* write() */
73 	tsalarm_ioctl,	/* ioctl() */
74 	nodev,		/* devmap() */
75 	nodev,		/* mmap() */
76 	ddi_segmap,	/* segmap() */
77 	nochpoll,	/* poll() */
78 	ddi_prop_op,    /* prop_op() */
79 	NULL,		/* cb_str */
80 	D_NEW | D_MP	/* cb_flag */
81 };
82 
83 
84 static struct dev_ops tsalarm_ops = {
85 	DEVO_REV,
86 	0,			/* ref count */
87 	tsalarm_getinfo,	/* getinfo() */
88 	nulldev,		/* identify() */
89 	nulldev,		/* probe() */
90 	tsalarm_attach,		/* attach() */
91 	tsalarm_detach,		/* detach */
92 	nodev,			/* reset */
93 	&tsalarm_cb_ops,		/* pointer to cb_ops structure */
94 	(struct bus_ops *)NULL,
95 	nulldev			/* power() */
96 };
97 
98 /*
99  * Loadable module support.
100  */
101 extern struct mod_ops mod_driverops;
102 static void    *statep;
103 
104 static struct modldrv modldrv = {
105 	&mod_driverops,			/* Type of module. This is a driver */
106 	"tsalarm control driver v%I%",	/* Name of the module */
107 	&tsalarm_ops			/* pointer to the dev_ops structure */
108 };
109 
110 static struct modlinkage modlinkage = {
111 	MODREV_1,
112 	&modldrv,
113 	NULL
114 };
115 
116 extern int rmclomv_alarm_get(int alarm_type, int *alarm_state);
117 extern int rmclomv_alarm_set(int alarm_type, int new_state);
118 
119 int
120 _init(void)
121 {
122 	int    e;
123 
124 	if (e = ddi_soft_state_init(&statep,
125 				sizeof (struct tsalarm_softc), 1)) {
126 		return (e);
127 	}
128 
129 	if ((e = mod_install(&modlinkage)) != 0) {
130 		ddi_soft_state_fini(&statep);
131 	}
132 
133 	return (e);
134 }
135 
136 
137 int
138 _fini(void)
139 {
140 	int e;
141 
142 	if ((e = mod_remove(&modlinkage)) != 0) {
143 		return (e);
144 	}
145 
146 	ddi_soft_state_fini(&statep);
147 
148 	return (DDI_SUCCESS);
149 }
150 
151 
152 int
153 _info(struct modinfo *modinfop)
154 {
155 	return (mod_info(&modlinkage, modinfop));
156 }
157 
158 
159 /* ARGSUSED */
160 static int
161 tsalarm_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
162 {
163 	int	inst = getminor((dev_t)arg);
164 	int	retval = DDI_SUCCESS;
165 	struct tsalarm_softc *softc;
166 
167 	switch (cmd) {
168 
169 	case DDI_INFO_DEVT2DEVINFO:
170 		if ((softc = getsoftc(inst)) == NULL) {
171 			*result = (void *)NULL;
172 			retval = DDI_FAILURE;
173 		} else {
174 			*result = (void *)softc->dip;
175 		}
176 		break;
177 
178 	case DDI_INFO_DEVT2INSTANCE:
179 		*result = (void *)(uintptr_t)inst;
180 		break;
181 
182 	default:
183 		retval = DDI_FAILURE;
184 	}
185 
186 	return (retval);
187 }
188 
189 static int
190 tsalarm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
191 {
192 
193 	int inst;
194 	struct tsalarm_softc *softc = NULL;
195 
196 	switch (cmd) {
197 
198 	case DDI_ATTACH:
199 		inst = ddi_get_instance(dip);
200 		/*
201 		 * Allocate a soft state structure for this instance.
202 		 */
203 		if (ddi_soft_state_zalloc(statep, inst) != DDI_SUCCESS)
204 			goto attach_failed;
205 
206 		softc = getsoftc(inst);
207 		softc->dip = dip;
208 		mutex_init(&softc->mutex, NULL, MUTEX_DRIVER, NULL);
209 		/*
210 		 * Create minor node.  The minor device number, inst, has no
211 		 * meaning.  The model number above, which will be added to
212 		 * the device's softc, is used to direct peculiar behavior.
213 		 */
214 		if (ddi_create_minor_node(dip, "lom", S_IFCHR, 0,
215 				DDI_PSEUDO, NULL) == DDI_FAILURE)
216 			goto attach_failed;
217 
218 		ddi_report_dev(dip);
219 		return (DDI_SUCCESS);
220 
221 	case DDI_RESUME:
222 		return (DDI_SUCCESS);
223 
224 	default:
225 		return (DDI_FAILURE);
226 	}
227 
228 attach_failed:
229 	/* Free soft state, if allocated. remove minor node if added earlier */
230 	if (softc) {
231 		mutex_destroy(&softc->mutex);
232 		ddi_soft_state_free(statep, inst);
233 	}
234 
235 	ddi_remove_minor_node(dip, NULL);
236 
237 	return (DDI_FAILURE);
238 }
239 
240 static int
241 tsalarm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
242 {
243 	int inst;
244 	struct tsalarm_softc *softc;
245 
246 	switch (cmd) {
247 
248 	case DDI_DETACH:
249 		inst = ddi_get_instance(dip);
250 		if ((softc = getsoftc(inst)) == NULL)
251 			return (DDI_FAILURE);
252 		/*
253 		 * Free the soft state and remove minor node added earlier.
254 		 */
255 		ddi_remove_minor_node(dip, NULL);
256 		mutex_destroy(&softc->mutex);
257 		ddi_soft_state_free(statep, inst);
258 		return (DDI_SUCCESS);
259 
260 	case DDI_SUSPEND:
261 		return (DDI_SUCCESS);
262 
263 	default:
264 		return (DDI_FAILURE);
265 
266 	}
267 }
268 
269 /* ARGSUSED */
270 static int
271 tsalarm_open(dev_t *devp, int flag, int otyp, cred_t *credp)
272 {
273 	int	inst = getminor(*devp);
274 
275 	return (getsoftc(inst) == NULL ? ENXIO : 0);
276 }
277 
278 
279 /* ARGSUSED */
280 static int
281 tsalarm_close(dev_t dev, int flag, int otyp, cred_t *credp)
282 {
283 	int	inst = getminor(dev);
284 
285 	return (getsoftc(inst) == NULL ? ENXIO : 0);
286 }
287 
288 
289 /* ARGSUSED */
290 static int
291 tsalarm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
292 		cred_t *credp, int *rvalp)
293 {
294 	int		inst = getminor(dev);
295 	struct tsalarm_softc *softc;
296 	int retval = 0;
297 	ts_aldata_t ts_alinfo;
298 	int alarm_type, alarm_state = 0;
299 
300 	if ((softc = getsoftc(inst)) == NULL)
301 		return (ENXIO);
302 
303 	mutex_enter(&softc->mutex);
304 
305 	switch (cmd) {
306 
307 	case LOMIOCALSTATE:
308 	case LOMIOCALSTATE_OLD:
309 		{
310 			if (ddi_copyin((caddr_t)arg, (caddr_t)&ts_alinfo,
311 				sizeof (ts_aldata_t), mode) != 0) {
312 				retval = EFAULT;
313 				goto end;
314 			}
315 
316 			alarm_type = ts_alinfo.alarm_no;
317 			if ((alarm_type < ALARM_CRITICAL) ||
318 					(alarm_type > ALARM_USER)) {
319 				retval = EINVAL;
320 				goto end;
321 			}
322 
323 			retval = rmclomv_alarm_get(alarm_type, &alarm_state);
324 
325 			if (retval != 0)
326 				goto end;
327 
328 			if ((alarm_state != 0) && (alarm_state != 1)) {
329 				retval = EIO;
330 				goto end;
331 			}
332 
333 			ts_alinfo.alarm_state = alarm_state;
334 			if (ddi_copyout((caddr_t)&ts_alinfo, (caddr_t)arg,
335 				sizeof (ts_aldata_t), mode) != 0) {
336 				retval = EFAULT;
337 				goto end;
338 			}
339 
340 		}
341 		break;
342 
343 	case LOMIOCALCTL:
344 	case LOMIOCALCTL_OLD:
345 		{
346 			if (ddi_copyin((caddr_t)arg, (caddr_t)&ts_alinfo,
347 				sizeof (ts_aldata_t), mode) != 0) {
348 				retval = EFAULT;
349 				goto end;
350 			}
351 
352 			alarm_type = ts_alinfo.alarm_no;
353 			alarm_state = ts_alinfo.alarm_state;
354 
355 			if ((alarm_type < ALARM_CRITICAL) ||
356 					(alarm_type > ALARM_USER)) {
357 				retval = EINVAL;
358 				goto end;
359 			}
360 			if ((alarm_state < ALARM_OFF) ||
361 					(alarm_state > ALARM_ON)) {
362 				retval = EINVAL;
363 				goto end;
364 			}
365 
366 			retval = rmclomv_alarm_set(alarm_type, alarm_state);
367 		}
368 		break;
369 
370 	default:
371 		retval = EINVAL;
372 		break;
373 	}
374 
375 end:
376 	mutex_exit(&softc->mutex);
377 
378 	return (retval);
379 }
380