xref: /onnv-gate/usr/src/uts/sun4/io/px/px_devctl.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * PCI nexus HotPlug devctl interface
31*0Sstevel@tonic-gate  */
32*0Sstevel@tonic-gate #include <sys/types.h>
33*0Sstevel@tonic-gate #include <sys/conf.h>
34*0Sstevel@tonic-gate #include <sys/kmem.h>
35*0Sstevel@tonic-gate #include <sys/async.h>
36*0Sstevel@tonic-gate #include <sys/sysmacros.h>
37*0Sstevel@tonic-gate #include <sys/sunddi.h>
38*0Sstevel@tonic-gate #include <sys/sunndi.h>
39*0Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
40*0Sstevel@tonic-gate #include <sys/open.h>
41*0Sstevel@tonic-gate #include <sys/errno.h>
42*0Sstevel@tonic-gate #include <sys/file.h>
43*0Sstevel@tonic-gate #include <sys/hotplug/pci/pcihp.h>
44*0Sstevel@tonic-gate #include "px_obj.h"
45*0Sstevel@tonic-gate #include "px_tools.h"
46*0Sstevel@tonic-gate #include "pcie_pwr.h"
47*0Sstevel@tonic-gate 
48*0Sstevel@tonic-gate /*LINTLIBRARY*/
49*0Sstevel@tonic-gate 
50*0Sstevel@tonic-gate static int px_open(dev_t *devp, int flags, int otyp, cred_t *credp);
51*0Sstevel@tonic-gate static int px_close(dev_t dev, int flags, int otyp, cred_t *credp);
52*0Sstevel@tonic-gate static int px_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
53*0Sstevel@tonic-gate 						cred_t *credp, int *rvalp);
54*0Sstevel@tonic-gate static int px_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
55*0Sstevel@tonic-gate     int flags, char *name, caddr_t valuep, int *lengthp);
56*0Sstevel@tonic-gate 
57*0Sstevel@tonic-gate struct cb_ops px_cb_ops = {
58*0Sstevel@tonic-gate 	px_open,			/* open */
59*0Sstevel@tonic-gate 	px_close,			/* close */
60*0Sstevel@tonic-gate 	nodev,				/* strategy */
61*0Sstevel@tonic-gate 	nodev,				/* print */
62*0Sstevel@tonic-gate 	nodev,				/* dump */
63*0Sstevel@tonic-gate 	nodev,				/* read */
64*0Sstevel@tonic-gate 	nodev,				/* write */
65*0Sstevel@tonic-gate 	px_ioctl,			/* ioctl */
66*0Sstevel@tonic-gate 	nodev,				/* devmap */
67*0Sstevel@tonic-gate 	nodev,				/* mmap */
68*0Sstevel@tonic-gate 	nodev,				/* segmap */
69*0Sstevel@tonic-gate 	nochpoll,			/* poll */
70*0Sstevel@tonic-gate 	px_prop_op,			/* cb_prop_op */
71*0Sstevel@tonic-gate 	NULL,				/* streamtab */
72*0Sstevel@tonic-gate 	D_NEW | D_MP | D_HOTPLUG,	/* Driver compatibility flag */
73*0Sstevel@tonic-gate 	CB_REV,				/* rev */
74*0Sstevel@tonic-gate 	nodev,				/* int (*cb_aread)() */
75*0Sstevel@tonic-gate 	nodev				/* int (*cb_awrite)() */
76*0Sstevel@tonic-gate };
77*0Sstevel@tonic-gate 
78*0Sstevel@tonic-gate /* ARGSUSED3 */
79*0Sstevel@tonic-gate static int
80*0Sstevel@tonic-gate px_open(dev_t *devp, int flags, int otyp, cred_t *credp)
81*0Sstevel@tonic-gate {
82*0Sstevel@tonic-gate 	px_t *px_p;
83*0Sstevel@tonic-gate 
84*0Sstevel@tonic-gate 	/*
85*0Sstevel@tonic-gate 	 * Make sure the open is for the right file type.
86*0Sstevel@tonic-gate 	 */
87*0Sstevel@tonic-gate 	if (otyp != OTYP_CHR)
88*0Sstevel@tonic-gate 		return (EINVAL);
89*0Sstevel@tonic-gate 
90*0Sstevel@tonic-gate 	/*
91*0Sstevel@tonic-gate 	 * Get the soft state structure for the device.
92*0Sstevel@tonic-gate 	 */
93*0Sstevel@tonic-gate 	px_p = DEV_TO_SOFTSTATE(*devp);
94*0Sstevel@tonic-gate 	if (px_p == NULL)
95*0Sstevel@tonic-gate 		return (ENXIO);
96*0Sstevel@tonic-gate 
97*0Sstevel@tonic-gate 	/*
98*0Sstevel@tonic-gate 	 * Handle the open by tracking the device state.
99*0Sstevel@tonic-gate 	 */
100*0Sstevel@tonic-gate 	DBG(DBG_OPEN, px_p->px_dip, "devp=%x: flags=%x\n", devp, flags);
101*0Sstevel@tonic-gate 	mutex_enter(&px_p->px_mutex);
102*0Sstevel@tonic-gate 	if (flags & FEXCL) {
103*0Sstevel@tonic-gate 		if (px_p->px_soft_state != PX_SOFT_STATE_CLOSED) {
104*0Sstevel@tonic-gate 			mutex_exit(&px_p->px_mutex);
105*0Sstevel@tonic-gate 			DBG(DBG_OPEN, px_p->px_dip, "busy\n");
106*0Sstevel@tonic-gate 			return (EBUSY);
107*0Sstevel@tonic-gate 		}
108*0Sstevel@tonic-gate 		px_p->px_soft_state = PX_SOFT_STATE_OPEN_EXCL;
109*0Sstevel@tonic-gate 	} else {
110*0Sstevel@tonic-gate 		if (px_p->px_soft_state == PX_SOFT_STATE_OPEN_EXCL) {
111*0Sstevel@tonic-gate 			mutex_exit(&px_p->px_mutex);
112*0Sstevel@tonic-gate 			DBG(DBG_OPEN, px_p->px_dip, "busy\n");
113*0Sstevel@tonic-gate 			return (EBUSY);
114*0Sstevel@tonic-gate 		}
115*0Sstevel@tonic-gate 		px_p->px_soft_state = PX_SOFT_STATE_OPEN;
116*0Sstevel@tonic-gate 	}
117*0Sstevel@tonic-gate 	px_p->px_open_count++;
118*0Sstevel@tonic-gate 	mutex_exit(&px_p->px_mutex);
119*0Sstevel@tonic-gate 	return (0);
120*0Sstevel@tonic-gate }
121*0Sstevel@tonic-gate 
122*0Sstevel@tonic-gate 
123*0Sstevel@tonic-gate /* ARGSUSED */
124*0Sstevel@tonic-gate static int
125*0Sstevel@tonic-gate px_close(dev_t dev, int flags, int otyp, cred_t *credp)
126*0Sstevel@tonic-gate {
127*0Sstevel@tonic-gate 	px_t *px_p;
128*0Sstevel@tonic-gate 
129*0Sstevel@tonic-gate 	if (otyp != OTYP_CHR)
130*0Sstevel@tonic-gate 		return (EINVAL);
131*0Sstevel@tonic-gate 
132*0Sstevel@tonic-gate 	px_p = DEV_TO_SOFTSTATE(dev);
133*0Sstevel@tonic-gate 	if (px_p == NULL)
134*0Sstevel@tonic-gate 		return (ENXIO);
135*0Sstevel@tonic-gate 
136*0Sstevel@tonic-gate 	DBG(DBG_CLOSE, px_p->px_dip, "dev=%x: flags=%x\n", dev, flags);
137*0Sstevel@tonic-gate 	mutex_enter(&px_p->px_mutex);
138*0Sstevel@tonic-gate 	px_p->px_soft_state = PX_SOFT_STATE_CLOSED;
139*0Sstevel@tonic-gate 	px_p->px_open_count = 0;
140*0Sstevel@tonic-gate 	mutex_exit(&px_p->px_mutex);
141*0Sstevel@tonic-gate 	return (0);
142*0Sstevel@tonic-gate }
143*0Sstevel@tonic-gate 
144*0Sstevel@tonic-gate /* ARGSUSED */
145*0Sstevel@tonic-gate static int
146*0Sstevel@tonic-gate px_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp)
147*0Sstevel@tonic-gate {
148*0Sstevel@tonic-gate 	px_t *px_p;
149*0Sstevel@tonic-gate 	dev_info_t *dip;
150*0Sstevel@tonic-gate 	struct devctl_iocdata *dcp;
151*0Sstevel@tonic-gate 	uint_t bus_state;
152*0Sstevel@tonic-gate 	int rv = DDI_SUCCESS;
153*0Sstevel@tonic-gate 
154*0Sstevel@tonic-gate 	px_p = DEV_TO_SOFTSTATE(dev);
155*0Sstevel@tonic-gate 	if (px_p == NULL)
156*0Sstevel@tonic-gate 		return (ENXIO);
157*0Sstevel@tonic-gate 
158*0Sstevel@tonic-gate 	dip = px_p->px_dip;
159*0Sstevel@tonic-gate 	DBG(DBG_IOCTL, dip, "dev=%x: cmd=%x\n", dev, cmd);
160*0Sstevel@tonic-gate #ifdef	PX_DMA_TEST
161*0Sstevel@tonic-gate 	if (IS_DMATEST(cmd)) {
162*0Sstevel@tonic-gate 		*rvalp = px_dma_test(cmd, dip, px_p, arg);
163*0Sstevel@tonic-gate 		return (0);
164*0Sstevel@tonic-gate 	}
165*0Sstevel@tonic-gate #endif	/* PX_DMA_TEST */
166*0Sstevel@tonic-gate 
167*0Sstevel@tonic-gate 	/*
168*0Sstevel@tonic-gate 	 * PCI tools.
169*0Sstevel@tonic-gate 	 */
170*0Sstevel@tonic-gate 
171*0Sstevel@tonic-gate 	if ((cmd & ~IOCPARM_MASK) == PCITOOL_IOC ||
172*0Sstevel@tonic-gate 	    (cmd & ~PPMREQ_MASK) == PPMREQ) {
173*0Sstevel@tonic-gate 
174*0Sstevel@tonic-gate 		/* Need privileges to use these ioctls. */
175*0Sstevel@tonic-gate 		if (drv_priv(credp)) {
176*0Sstevel@tonic-gate 			DBG(DBG_TOOLS, dip,
177*0Sstevel@tonic-gate 			    "px_tools: Insufficient privileges\n");
178*0Sstevel@tonic-gate 
179*0Sstevel@tonic-gate 		return (EPERM);
180*0Sstevel@tonic-gate 		}
181*0Sstevel@tonic-gate 	}
182*0Sstevel@tonic-gate 
183*0Sstevel@tonic-gate 	switch (cmd) {
184*0Sstevel@tonic-gate 	case PCITOOL_DEVICE_GET_REG:
185*0Sstevel@tonic-gate 	case PCITOOL_DEVICE_SET_REG:
186*0Sstevel@tonic-gate 		rv = px_lib_tools_dev_reg_ops(dip, (void *)arg, cmd, mode);
187*0Sstevel@tonic-gate 		return (rv);
188*0Sstevel@tonic-gate 	case PCITOOL_NEXUS_SET_REG:
189*0Sstevel@tonic-gate 	case PCITOOL_NEXUS_GET_REG:
190*0Sstevel@tonic-gate 		rv = px_lib_tools_bus_reg_ops(dip, (void *)arg, cmd, mode);
191*0Sstevel@tonic-gate 		return (rv);
192*0Sstevel@tonic-gate 	case PCITOOL_DEVICE_GET_INTR:
193*0Sstevel@tonic-gate 	case PCITOOL_DEVICE_SET_INTR:
194*0Sstevel@tonic-gate 	case PCITOOL_DEVICE_NUM_INTR:
195*0Sstevel@tonic-gate 		rv = px_lib_tools_intr_admn(dip, (void *)arg, cmd, mode);
196*0Sstevel@tonic-gate 		return (rv);
197*0Sstevel@tonic-gate 	default:
198*0Sstevel@tonic-gate 		break;
199*0Sstevel@tonic-gate 
200*0Sstevel@tonic-gate 	}
201*0Sstevel@tonic-gate 
202*0Sstevel@tonic-gate 	if ((cmd & ~PPMREQ_MASK) == PPMREQ)
203*0Sstevel@tonic-gate 		return (px_lib_pmctl(cmd, px_p));
204*0Sstevel@tonic-gate 
205*0Sstevel@tonic-gate 	/*
206*0Sstevel@tonic-gate 	 * We can use the generic implementation for these ioctls
207*0Sstevel@tonic-gate 	 */
208*0Sstevel@tonic-gate 	switch (cmd) {
209*0Sstevel@tonic-gate 	case DEVCTL_DEVICE_GETSTATE:
210*0Sstevel@tonic-gate 	case DEVCTL_DEVICE_ONLINE:
211*0Sstevel@tonic-gate 	case DEVCTL_DEVICE_OFFLINE:
212*0Sstevel@tonic-gate 	case DEVCTL_BUS_GETSTATE:
213*0Sstevel@tonic-gate 		return (ndi_devctl_ioctl(dip, cmd, arg, mode, 0));
214*0Sstevel@tonic-gate 	}
215*0Sstevel@tonic-gate 
216*0Sstevel@tonic-gate 	/*
217*0Sstevel@tonic-gate 	 * read devctl ioctl data
218*0Sstevel@tonic-gate 	 */
219*0Sstevel@tonic-gate 	if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)
220*0Sstevel@tonic-gate 		return (EFAULT);
221*0Sstevel@tonic-gate 
222*0Sstevel@tonic-gate 	switch (cmd) {
223*0Sstevel@tonic-gate 
224*0Sstevel@tonic-gate 	case DEVCTL_DEVICE_RESET:
225*0Sstevel@tonic-gate 		DBG(DBG_IOCTL, dip, "DEVCTL_DEVICE_RESET\n");
226*0Sstevel@tonic-gate 		rv = ENOTSUP;
227*0Sstevel@tonic-gate 		break;
228*0Sstevel@tonic-gate 
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate 	case DEVCTL_BUS_QUIESCE:
231*0Sstevel@tonic-gate 		DBG(DBG_IOCTL, dip, "DEVCTL_BUS_QUIESCE\n");
232*0Sstevel@tonic-gate 		if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS)
233*0Sstevel@tonic-gate 			if (bus_state == BUS_QUIESCED)
234*0Sstevel@tonic-gate 				break;
235*0Sstevel@tonic-gate 		(void) ndi_set_bus_state(dip, BUS_QUIESCED);
236*0Sstevel@tonic-gate 		break;
237*0Sstevel@tonic-gate 
238*0Sstevel@tonic-gate 	case DEVCTL_BUS_UNQUIESCE:
239*0Sstevel@tonic-gate 		DBG(DBG_IOCTL, dip, "DEVCTL_BUS_UNQUIESCE\n");
240*0Sstevel@tonic-gate 		if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS)
241*0Sstevel@tonic-gate 			if (bus_state == BUS_ACTIVE)
242*0Sstevel@tonic-gate 				break;
243*0Sstevel@tonic-gate 		(void) ndi_set_bus_state(dip, BUS_ACTIVE);
244*0Sstevel@tonic-gate 		break;
245*0Sstevel@tonic-gate 
246*0Sstevel@tonic-gate 	case DEVCTL_BUS_RESET:
247*0Sstevel@tonic-gate 		DBG(DBG_IOCTL, dip, "DEVCTL_BUS_RESET\n");
248*0Sstevel@tonic-gate 		rv = ENOTSUP;
249*0Sstevel@tonic-gate 		break;
250*0Sstevel@tonic-gate 
251*0Sstevel@tonic-gate 	case DEVCTL_BUS_RESETALL:
252*0Sstevel@tonic-gate 		DBG(DBG_IOCTL, dip, "DEVCTL_BUS_RESETALL\n");
253*0Sstevel@tonic-gate 		rv = ENOTSUP;
254*0Sstevel@tonic-gate 		break;
255*0Sstevel@tonic-gate 
256*0Sstevel@tonic-gate 	default:
257*0Sstevel@tonic-gate 		rv = ENOTTY;
258*0Sstevel@tonic-gate 	}
259*0Sstevel@tonic-gate 
260*0Sstevel@tonic-gate 	ndi_dc_freehdl(dcp);
261*0Sstevel@tonic-gate 	return (rv);
262*0Sstevel@tonic-gate }
263*0Sstevel@tonic-gate 
264*0Sstevel@tonic-gate static int px_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
265*0Sstevel@tonic-gate     int flags, char *name, caddr_t valuep, int *lengthp)
266*0Sstevel@tonic-gate {
267*0Sstevel@tonic-gate 	if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
268*0Sstevel@tonic-gate 	    "hotplug-capable"))
269*0Sstevel@tonic-gate 		return ((pcihp_get_cb_ops())->cb_prop_op(dev, dip,
270*0Sstevel@tonic-gate 		    prop_op, flags, name, valuep, lengthp));
271*0Sstevel@tonic-gate 
272*0Sstevel@tonic-gate 	return (ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp));
273*0Sstevel@tonic-gate }
274