xref: /illumos-gate/usr/src/uts/sun4u/io/epic.c (revision d58fda4376e4bf67072ce2e69f6f47036f9dbb68)
1*d58fda43Sjbeloro /*
2*d58fda43Sjbeloro  * CDDL HEADER START
3*d58fda43Sjbeloro  *
4*d58fda43Sjbeloro  * The contents of this file are subject to the terms of the
5*d58fda43Sjbeloro  * Common Development and Distribution License, Version 1.0 only
6*d58fda43Sjbeloro  * (the "License").  You may not use this file except in compliance
7*d58fda43Sjbeloro  * with the License.
8*d58fda43Sjbeloro  *
9*d58fda43Sjbeloro  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*d58fda43Sjbeloro  * or http://www.opensolaris.org/os/licensing.
11*d58fda43Sjbeloro  * See the License for the specific language governing permissions
12*d58fda43Sjbeloro  * and limitations under the License.
13*d58fda43Sjbeloro  *
14*d58fda43Sjbeloro  * When distributing Covered Code, include this CDDL HEADER in each
15*d58fda43Sjbeloro  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*d58fda43Sjbeloro  * If applicable, add the following below this CDDL HEADER, with the
17*d58fda43Sjbeloro  * fields enclosed by brackets "[]" replaced with your own identifying
18*d58fda43Sjbeloro  * information: Portions Copyright [yyyy] [name of copyright owner]
19*d58fda43Sjbeloro  *
20*d58fda43Sjbeloro  * CDDL HEADER END
21*d58fda43Sjbeloro  */
22*d58fda43Sjbeloro 
23*d58fda43Sjbeloro /*
24*d58fda43Sjbeloro  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
25*d58fda43Sjbeloro  * Use is subject to license terms.
26*d58fda43Sjbeloro  */
27*d58fda43Sjbeloro 
28*d58fda43Sjbeloro #pragma ident	"%Z%%M%	%I%	%E% SMI"
29*d58fda43Sjbeloro 
30*d58fda43Sjbeloro /*
31*d58fda43Sjbeloro  * Driver to control Alert and Power LEDs  for the Seattle platform.
32*d58fda43Sjbeloro  * Alert LED is also known as Service (required).
33*d58fda43Sjbeloro  * Power LED is also known as Activity.
34*d58fda43Sjbeloro  */
35*d58fda43Sjbeloro #include <sys/types.h>
36*d58fda43Sjbeloro #include <sys/time.h>
37*d58fda43Sjbeloro #include <sys/errno.h>
38*d58fda43Sjbeloro #include <sys/cmn_err.h>
39*d58fda43Sjbeloro #include <sys/param.h>
40*d58fda43Sjbeloro #include <sys/modctl.h>
41*d58fda43Sjbeloro #include <sys/conf.h>
42*d58fda43Sjbeloro #include <sys/open.h>
43*d58fda43Sjbeloro #include <sys/stat.h>
44*d58fda43Sjbeloro #include <sys/clock.h>
45*d58fda43Sjbeloro #include <sys/ddi.h>
46*d58fda43Sjbeloro #include <sys/sunddi.h>
47*d58fda43Sjbeloro #include <sys/file.h>
48*d58fda43Sjbeloro #include <sys/note.h>
49*d58fda43Sjbeloro #include <sys/epic.h>
50*d58fda43Sjbeloro 
51*d58fda43Sjbeloro 
52*d58fda43Sjbeloro /*
53*d58fda43Sjbeloro  * Some #defs that must be here as they differ for power.c
54*d58fda43Sjbeloro  * and epic.c
55*d58fda43Sjbeloro  */
56*d58fda43Sjbeloro #define	EPIC_REGS_OFFSET	0x00
57*d58fda43Sjbeloro #define	EPIC_REGS_LEN		0x80
58*d58fda43Sjbeloro 
59*d58fda43Sjbeloro #define	EPIC_IND_DATA		0x40
60*d58fda43Sjbeloro #define	EPIC_IND_ADDR		0x41
61*d58fda43Sjbeloro #define	EPIC_WRITE_MASK		0x80
62*d58fda43Sjbeloro 
63*d58fda43Sjbeloro /* dev_ops and cb_ops entry point function declarations */
64*d58fda43Sjbeloro static int	epic_attach(dev_info_t *, ddi_attach_cmd_t);
65*d58fda43Sjbeloro static int	epic_detach(dev_info_t *, ddi_detach_cmd_t);
66*d58fda43Sjbeloro static int	epic_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
67*d58fda43Sjbeloro static int	epic_open(dev_t *, int, int, cred_t *);
68*d58fda43Sjbeloro static int	epic_close(dev_t, int, int, cred_t *);
69*d58fda43Sjbeloro static int	epic_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
70*d58fda43Sjbeloro 
71*d58fda43Sjbeloro struct cb_ops epic_cb_ops = {
72*d58fda43Sjbeloro 	epic_open,		/* open */
73*d58fda43Sjbeloro 	epic_close,		/* close */
74*d58fda43Sjbeloro 	nodev,			/* strategy */
75*d58fda43Sjbeloro 	nodev,			/* print */
76*d58fda43Sjbeloro 	nodev,			/* dump */
77*d58fda43Sjbeloro 	nodev,			/* read */
78*d58fda43Sjbeloro 	nodev,			/* write */
79*d58fda43Sjbeloro 	epic_ioctl,		/* ioctl */
80*d58fda43Sjbeloro 	nodev,			/* devmap */
81*d58fda43Sjbeloro 	nodev,			/* mmap */
82*d58fda43Sjbeloro 	ddi_segmap,		/* segmap */
83*d58fda43Sjbeloro 	nochpoll,		/* poll */
84*d58fda43Sjbeloro 	ddi_prop_op,		/* cb_prop_op */
85*d58fda43Sjbeloro 	NULL,			/* streamtab - for STREAMS drivers */
86*d58fda43Sjbeloro 	D_NEW | D_MP		/* driver compatibility flag */
87*d58fda43Sjbeloro };
88*d58fda43Sjbeloro 
89*d58fda43Sjbeloro static struct dev_ops epic_dev_ops = {
90*d58fda43Sjbeloro 	DEVO_REV,		/* driver build version */
91*d58fda43Sjbeloro 	0,			/* device reference count */
92*d58fda43Sjbeloro 	epic_getinfo,
93*d58fda43Sjbeloro 	nulldev,
94*d58fda43Sjbeloro 	nulldev,		/* probe */
95*d58fda43Sjbeloro 	epic_attach,
96*d58fda43Sjbeloro 	epic_detach,
97*d58fda43Sjbeloro 	nulldev,		/* reset */
98*d58fda43Sjbeloro 	&epic_cb_ops,
99*d58fda43Sjbeloro 	(struct bus_ops *)NULL,
100*d58fda43Sjbeloro 	nulldev			/* power */
101*d58fda43Sjbeloro };
102*d58fda43Sjbeloro 
103*d58fda43Sjbeloro 
104*d58fda43Sjbeloro /*
105*d58fda43Sjbeloro  * Soft state
106*d58fda43Sjbeloro  */
107*d58fda43Sjbeloro struct epic_softc {
108*d58fda43Sjbeloro 	dev_info_t	*dip;
109*d58fda43Sjbeloro 	kmutex_t	mutex;
110*d58fda43Sjbeloro 	uint8_t		*cmd_reg;
111*d58fda43Sjbeloro 	ddi_acc_handle_t cmd_handle;
112*d58fda43Sjbeloro };
113*d58fda43Sjbeloro 
114*d58fda43Sjbeloro #define	getsoftc(inst)	((struct epic_softc *)ddi_get_soft_state(statep, \
115*d58fda43Sjbeloro (inst)))
116*d58fda43Sjbeloro 
117*d58fda43Sjbeloro /* module configuration stuff */
118*d58fda43Sjbeloro static void    *statep;
119*d58fda43Sjbeloro extern struct mod_ops mod_driverops;
120*d58fda43Sjbeloro 
121*d58fda43Sjbeloro static struct modldrv modldrv = {
122*d58fda43Sjbeloro 	&mod_driverops,
123*d58fda43Sjbeloro 	"epic_client driver v%I%",
124*d58fda43Sjbeloro 	&epic_dev_ops
125*d58fda43Sjbeloro };
126*d58fda43Sjbeloro 
127*d58fda43Sjbeloro static struct modlinkage modlinkage = {
128*d58fda43Sjbeloro 	MODREV_1,
129*d58fda43Sjbeloro 	&modldrv,
130*d58fda43Sjbeloro 	0
131*d58fda43Sjbeloro };
132*d58fda43Sjbeloro 
133*d58fda43Sjbeloro int
134*d58fda43Sjbeloro _init(void)
135*d58fda43Sjbeloro {
136*d58fda43Sjbeloro 	int e;
137*d58fda43Sjbeloro 
138*d58fda43Sjbeloro 	if ((e = ddi_soft_state_init(&statep,
139*d58fda43Sjbeloro 		sizeof (struct epic_softc), 0)) != 0) {
140*d58fda43Sjbeloro 		return (e);
141*d58fda43Sjbeloro 	}
142*d58fda43Sjbeloro 
143*d58fda43Sjbeloro 	if ((e = mod_install(&modlinkage)) != 0)
144*d58fda43Sjbeloro 		ddi_soft_state_fini(&statep);
145*d58fda43Sjbeloro 
146*d58fda43Sjbeloro 	return (e);
147*d58fda43Sjbeloro }
148*d58fda43Sjbeloro 
149*d58fda43Sjbeloro int
150*d58fda43Sjbeloro _fini(void)
151*d58fda43Sjbeloro {
152*d58fda43Sjbeloro 	int e;
153*d58fda43Sjbeloro 
154*d58fda43Sjbeloro 	if ((e = mod_remove(&modlinkage)) != 0)
155*d58fda43Sjbeloro 		return (e);
156*d58fda43Sjbeloro 
157*d58fda43Sjbeloro 	ddi_soft_state_fini(&statep);
158*d58fda43Sjbeloro 
159*d58fda43Sjbeloro 	return (DDI_SUCCESS);
160*d58fda43Sjbeloro }
161*d58fda43Sjbeloro 
162*d58fda43Sjbeloro int
163*d58fda43Sjbeloro _info(struct modinfo *modinfop)
164*d58fda43Sjbeloro {
165*d58fda43Sjbeloro 	return (mod_info(&modlinkage, modinfop));
166*d58fda43Sjbeloro }
167*d58fda43Sjbeloro 
168*d58fda43Sjbeloro /*ARGSUSED*/
169*d58fda43Sjbeloro static int
170*d58fda43Sjbeloro epic_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
171*d58fda43Sjbeloro {
172*d58fda43Sjbeloro 	int	inst;
173*d58fda43Sjbeloro 	int	retval = DDI_SUCCESS;
174*d58fda43Sjbeloro 	struct epic_softc *softc;
175*d58fda43Sjbeloro 
176*d58fda43Sjbeloro 	inst = (getminor((dev_t)arg));
177*d58fda43Sjbeloro 
178*d58fda43Sjbeloro 	switch (cmd) {
179*d58fda43Sjbeloro 	case DDI_INFO_DEVT2DEVINFO:
180*d58fda43Sjbeloro 		if ((softc = getsoftc(inst)) == NULL) {
181*d58fda43Sjbeloro 			*result = (void *)NULL;
182*d58fda43Sjbeloro 			retval = DDI_FAILURE;
183*d58fda43Sjbeloro 		} else
184*d58fda43Sjbeloro 			*result = (void *)softc->dip;
185*d58fda43Sjbeloro 		break;
186*d58fda43Sjbeloro 
187*d58fda43Sjbeloro 	case DDI_INFO_DEVT2INSTANCE:
188*d58fda43Sjbeloro 		*result = (void *)inst;
189*d58fda43Sjbeloro 		break;
190*d58fda43Sjbeloro 
191*d58fda43Sjbeloro 	default:
192*d58fda43Sjbeloro 		retval = DDI_FAILURE;
193*d58fda43Sjbeloro 	}
194*d58fda43Sjbeloro 
195*d58fda43Sjbeloro 	return (retval);
196*d58fda43Sjbeloro }
197*d58fda43Sjbeloro 
198*d58fda43Sjbeloro static int
199*d58fda43Sjbeloro epic_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
200*d58fda43Sjbeloro {
201*d58fda43Sjbeloro 	int inst;
202*d58fda43Sjbeloro 	struct epic_softc *softc = NULL;
203*d58fda43Sjbeloro 	int minor;
204*d58fda43Sjbeloro 	char name[MAXNAMELEN];
205*d58fda43Sjbeloro 	ddi_device_acc_attr_t dev_attr;
206*d58fda43Sjbeloro 	int res;
207*d58fda43Sjbeloro 
208*d58fda43Sjbeloro 	switch (cmd) {
209*d58fda43Sjbeloro 	case DDI_ATTACH:
210*d58fda43Sjbeloro 		inst = ddi_get_instance(dip);
211*d58fda43Sjbeloro 		(void) sprintf(name, "env-monitor%d", inst);
212*d58fda43Sjbeloro 		minor = inst;
213*d58fda43Sjbeloro 		if (ddi_create_minor_node(dip, name, S_IFCHR, minor,
214*d58fda43Sjbeloro 		    DDI_PSEUDO, NULL) == DDI_FAILURE) {
215*d58fda43Sjbeloro 			cmn_err(CE_WARN,
216*d58fda43Sjbeloro 			    "ddi_create_minor_node() failed for inst %d\n",
217*d58fda43Sjbeloro 			    inst);
218*d58fda43Sjbeloro 			return (DDI_FAILURE);
219*d58fda43Sjbeloro 		}
220*d58fda43Sjbeloro 
221*d58fda43Sjbeloro 		/* Allocate a soft state structure for this instance */
222*d58fda43Sjbeloro 		if (ddi_soft_state_zalloc(statep, inst) != DDI_SUCCESS) {
223*d58fda43Sjbeloro 			cmn_err(CE_WARN, " ddi_soft_state_zalloc() failed "
224*d58fda43Sjbeloro 			    "for inst %d\n", inst);
225*d58fda43Sjbeloro 			break;
226*d58fda43Sjbeloro 		}
227*d58fda43Sjbeloro 
228*d58fda43Sjbeloro 		/* Setup soft state */
229*d58fda43Sjbeloro 		if ((softc = getsoftc(inst)) == NULL) {
230*d58fda43Sjbeloro 			break;
231*d58fda43Sjbeloro 		}
232*d58fda43Sjbeloro 		softc->dip = dip;
233*d58fda43Sjbeloro 		mutex_init(&softc->mutex, NULL, MUTEX_DRIVER, NULL);
234*d58fda43Sjbeloro 
235*d58fda43Sjbeloro 		/* Setup device attributes */
236*d58fda43Sjbeloro 		dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
237*d58fda43Sjbeloro 		dev_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
238*d58fda43Sjbeloro 		dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
239*d58fda43Sjbeloro 
240*d58fda43Sjbeloro 		res = ddi_regs_map_setup(dip, 0, (caddr_t *)&softc->cmd_reg,
241*d58fda43Sjbeloro 			EPIC_REGS_OFFSET, EPIC_REGS_LEN, &dev_attr,
242*d58fda43Sjbeloro 			&softc->cmd_handle);
243*d58fda43Sjbeloro 
244*d58fda43Sjbeloro 		if (res != DDI_SUCCESS) {
245*d58fda43Sjbeloro 			cmn_err(CE_WARN, "ddi_regs_map_setup() failed\n");
246*d58fda43Sjbeloro 			break;
247*d58fda43Sjbeloro 		}
248*d58fda43Sjbeloro 
249*d58fda43Sjbeloro 		ddi_report_dev(dip);
250*d58fda43Sjbeloro 
251*d58fda43Sjbeloro 
252*d58fda43Sjbeloro 		return (DDI_SUCCESS);
253*d58fda43Sjbeloro 
254*d58fda43Sjbeloro 	case DDI_RESUME:
255*d58fda43Sjbeloro 		return (DDI_SUCCESS);
256*d58fda43Sjbeloro 
257*d58fda43Sjbeloro 	default:
258*d58fda43Sjbeloro 		return (DDI_FAILURE);
259*d58fda43Sjbeloro 	}
260*d58fda43Sjbeloro 
261*d58fda43Sjbeloro 	/* Attach failed */
262*d58fda43Sjbeloro 	/* Free soft state, if allocated. remove minor node if added earlier */
263*d58fda43Sjbeloro 	if (softc)
264*d58fda43Sjbeloro 		ddi_soft_state_free(statep, inst);
265*d58fda43Sjbeloro 
266*d58fda43Sjbeloro 	ddi_remove_minor_node(dip, NULL);
267*d58fda43Sjbeloro 
268*d58fda43Sjbeloro 	return (DDI_FAILURE);
269*d58fda43Sjbeloro }
270*d58fda43Sjbeloro 
271*d58fda43Sjbeloro static int
272*d58fda43Sjbeloro epic_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
273*d58fda43Sjbeloro {
274*d58fda43Sjbeloro 	int inst;
275*d58fda43Sjbeloro 	struct epic_softc *softc;
276*d58fda43Sjbeloro 
277*d58fda43Sjbeloro 	switch (cmd) {
278*d58fda43Sjbeloro 	case DDI_DETACH:
279*d58fda43Sjbeloro 		inst = ddi_get_instance(dip);
280*d58fda43Sjbeloro 		if ((softc = getsoftc(inst)) == NULL)
281*d58fda43Sjbeloro 			return (ENXIO);
282*d58fda43Sjbeloro 
283*d58fda43Sjbeloro 		(void) ddi_regs_map_free(&softc->cmd_handle);
284*d58fda43Sjbeloro 
285*d58fda43Sjbeloro 
286*d58fda43Sjbeloro 		/* Free the soft state and remove minor node added earlier */
287*d58fda43Sjbeloro 		mutex_destroy(&softc->mutex);
288*d58fda43Sjbeloro 		ddi_soft_state_free(statep, inst);
289*d58fda43Sjbeloro 		ddi_remove_minor_node(dip, NULL);
290*d58fda43Sjbeloro 		return (DDI_SUCCESS);
291*d58fda43Sjbeloro 
292*d58fda43Sjbeloro 	case DDI_SUSPEND:
293*d58fda43Sjbeloro 		return (DDI_SUCCESS);
294*d58fda43Sjbeloro 
295*d58fda43Sjbeloro 	default:
296*d58fda43Sjbeloro 		return (DDI_FAILURE);
297*d58fda43Sjbeloro 	}
298*d58fda43Sjbeloro }
299*d58fda43Sjbeloro 
300*d58fda43Sjbeloro /*ARGSUSED*/
301*d58fda43Sjbeloro static int
302*d58fda43Sjbeloro epic_open(dev_t *devp, int flag, int otyp, cred_t *credp)
303*d58fda43Sjbeloro {
304*d58fda43Sjbeloro 	_NOTE(ARGUNUSED(flag))
305*d58fda43Sjbeloro 	_NOTE(ARGUNUSED(otyp))
306*d58fda43Sjbeloro 	_NOTE(ARGUNUSED(credp))
307*d58fda43Sjbeloro 
308*d58fda43Sjbeloro 	int	inst = getminor(*devp);
309*d58fda43Sjbeloro 
310*d58fda43Sjbeloro 	return (getsoftc(inst) == NULL ? ENXIO : 0);
311*d58fda43Sjbeloro }
312*d58fda43Sjbeloro 
313*d58fda43Sjbeloro /*ARGSUSED*/
314*d58fda43Sjbeloro static int
315*d58fda43Sjbeloro epic_close(dev_t dev, int flag, int otyp, cred_t *credp)
316*d58fda43Sjbeloro {
317*d58fda43Sjbeloro 	_NOTE(ARGUNUSED(flag))
318*d58fda43Sjbeloro 	_NOTE(ARGUNUSED(otyp))
319*d58fda43Sjbeloro 	_NOTE(ARGUNUSED(credp))
320*d58fda43Sjbeloro 
321*d58fda43Sjbeloro 	int	inst = getminor(dev);
322*d58fda43Sjbeloro 
323*d58fda43Sjbeloro 	return (getsoftc(inst) == NULL ? ENXIO : 0);
324*d58fda43Sjbeloro }
325*d58fda43Sjbeloro 
326*d58fda43Sjbeloro /*ARGSUSED*/
327*d58fda43Sjbeloro static int
328*d58fda43Sjbeloro epic_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
329*d58fda43Sjbeloro int *rvalp)
330*d58fda43Sjbeloro {
331*d58fda43Sjbeloro 	_NOTE(ARGUNUSED(credp))
332*d58fda43Sjbeloro 
333*d58fda43Sjbeloro 	int	inst;
334*d58fda43Sjbeloro 	struct epic_softc *softc;
335*d58fda43Sjbeloro 	uint8_t	in_command;
336*d58fda43Sjbeloro 
337*d58fda43Sjbeloro 	inst = getminor(dev);
338*d58fda43Sjbeloro 	if ((softc = getsoftc(inst)) == NULL)
339*d58fda43Sjbeloro 		return (ENXIO);
340*d58fda43Sjbeloro 
341*d58fda43Sjbeloro 	mutex_enter(&softc->mutex);
342*d58fda43Sjbeloro 
343*d58fda43Sjbeloro 	switch (cmd) {
344*d58fda43Sjbeloro 	case EPIC_SET_POWER_LED:
345*d58fda43Sjbeloro 	    EPIC_WRITE(softc->cmd_handle, softc->cmd_reg,
346*d58fda43Sjbeloro 			EPIC_IND_LED_STATE0, EPIC_POWER_LED_MASK,
347*d58fda43Sjbeloro 			EPIC_POWER_LED_ON);
348*d58fda43Sjbeloro 	    break;
349*d58fda43Sjbeloro 	case EPIC_RESET_POWER_LED:
350*d58fda43Sjbeloro 	    EPIC_WRITE(softc->cmd_handle, softc->cmd_reg,
351*d58fda43Sjbeloro 			EPIC_IND_LED_STATE0, EPIC_POWER_LED_MASK,
352*d58fda43Sjbeloro 			EPIC_POWER_LED_OFF);
353*d58fda43Sjbeloro 	    break;
354*d58fda43Sjbeloro 	case EPIC_SB_BL_POWER_LED:
355*d58fda43Sjbeloro 	    EPIC_WRITE(softc->cmd_handle, softc->cmd_reg,
356*d58fda43Sjbeloro 			EPIC_IND_LED_STATE0, EPIC_POWER_LED_MASK,
357*d58fda43Sjbeloro 			EPIC_POWER_LED_SB_BLINK);
358*d58fda43Sjbeloro 	    break;
359*d58fda43Sjbeloro 	case EPIC_FAST_BL_POWER_LED:
360*d58fda43Sjbeloro 	    EPIC_WRITE(softc->cmd_handle, softc->cmd_reg,
361*d58fda43Sjbeloro 			EPIC_IND_LED_STATE0, EPIC_POWER_LED_MASK,
362*d58fda43Sjbeloro 			EPIC_POWER_LED_FAST_BLINK);
363*d58fda43Sjbeloro 	    break;
364*d58fda43Sjbeloro 	case EPIC_SET_ALERT_LED:
365*d58fda43Sjbeloro 	    EPIC_WRITE(softc->cmd_handle, softc->cmd_reg,
366*d58fda43Sjbeloro 			EPIC_IND_LED_STATE0, EPIC_ALERT_LED_MASK,
367*d58fda43Sjbeloro 			EPIC_ALERT_LED_ON);
368*d58fda43Sjbeloro 	    break;
369*d58fda43Sjbeloro 	case EPIC_RESET_ALERT_LED:
370*d58fda43Sjbeloro 	    EPIC_WRITE(softc->cmd_handle, softc->cmd_reg,
371*d58fda43Sjbeloro 			EPIC_IND_LED_STATE0, EPIC_ALERT_LED_MASK,
372*d58fda43Sjbeloro 			EPIC_ALERT_LED_OFF);
373*d58fda43Sjbeloro 	    break;
374*d58fda43Sjbeloro 	case EPIC_GET_FW:
375*d58fda43Sjbeloro 	    EPIC_READ(softc->cmd_handle, softc->cmd_reg,
376*d58fda43Sjbeloro 			in_command, EPIC_IND_FW_VERSION);
377*d58fda43Sjbeloro 	    if (ddi_copyout((void *)(&in_command), (void *)arg,
378*d58fda43Sjbeloro 			sizeof (in_command), mode) != DDI_SUCCESS) {
379*d58fda43Sjbeloro 		    mutex_exit(&softc->mutex);
380*d58fda43Sjbeloro 		    return (EFAULT);
381*d58fda43Sjbeloro 	    }
382*d58fda43Sjbeloro 	    break;
383*d58fda43Sjbeloro 	default:
384*d58fda43Sjbeloro 		mutex_exit(&softc->mutex);
385*d58fda43Sjbeloro 		cmn_err(CE_WARN, "epic: cmd %d is not valid", cmd);
386*d58fda43Sjbeloro 		return (EINVAL);
387*d58fda43Sjbeloro 	}
388*d58fda43Sjbeloro 
389*d58fda43Sjbeloro 	mutex_exit(&softc->mutex);
390*d58fda43Sjbeloro 	return (0);
391*d58fda43Sjbeloro }
392