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