xref: /titanic_51/usr/src/uts/sun4/io/px/px_devctl.c (revision 1a7c1b724419d3cb5fa6eea75123c6b2060ba31b)
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 /*
30  * PCI nexus HotPlug devctl interface
31  */
32 #include <sys/types.h>
33 #include <sys/conf.h>
34 #include <sys/kmem.h>
35 #include <sys/async.h>
36 #include <sys/sysmacros.h>
37 #include <sys/sunddi.h>
38 #include <sys/sunndi.h>
39 #include <sys/ddi_impldefs.h>
40 #include <sys/open.h>
41 #include <sys/errno.h>
42 #include <sys/file.h>
43 #include <sys/hotplug/pci/pcihp.h>
44 #include "px_obj.h"
45 #include "px_tools.h"
46 #include "pcie_pwr.h"
47 
48 /*LINTLIBRARY*/
49 
50 static int px_open(dev_t *devp, int flags, int otyp, cred_t *credp);
51 static int px_close(dev_t dev, int flags, int otyp, cred_t *credp);
52 static int px_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
53 						cred_t *credp, int *rvalp);
54 static int px_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
55     int flags, char *name, caddr_t valuep, int *lengthp);
56 
57 struct cb_ops px_cb_ops = {
58 	px_open,			/* open */
59 	px_close,			/* close */
60 	nodev,				/* strategy */
61 	nodev,				/* print */
62 	nodev,				/* dump */
63 	nodev,				/* read */
64 	nodev,				/* write */
65 	px_ioctl,			/* ioctl */
66 	nodev,				/* devmap */
67 	nodev,				/* mmap */
68 	nodev,				/* segmap */
69 	nochpoll,			/* poll */
70 	px_prop_op,			/* cb_prop_op */
71 	NULL,				/* streamtab */
72 	D_NEW | D_MP | D_HOTPLUG,	/* Driver compatibility flag */
73 	CB_REV,				/* rev */
74 	nodev,				/* int (*cb_aread)() */
75 	nodev				/* int (*cb_awrite)() */
76 };
77 
78 /* ARGSUSED3 */
79 static int
80 px_open(dev_t *devp, int flags, int otyp, cred_t *credp)
81 {
82 	px_t *px_p;
83 
84 	/*
85 	 * Make sure the open is for the right file type.
86 	 */
87 	if (otyp != OTYP_CHR)
88 		return (EINVAL);
89 
90 	/*
91 	 * Get the soft state structure for the device.
92 	 */
93 	px_p = DEV_TO_SOFTSTATE(*devp);
94 	if (px_p == NULL)
95 		return (ENXIO);
96 
97 	/*
98 	 * Handle the open by tracking the device state.
99 	 */
100 	DBG(DBG_OPEN, px_p->px_dip, "devp=%x: flags=%x\n", devp, flags);
101 	mutex_enter(&px_p->px_mutex);
102 	if (flags & FEXCL) {
103 		if (px_p->px_soft_state != PX_SOFT_STATE_CLOSED) {
104 			mutex_exit(&px_p->px_mutex);
105 			DBG(DBG_OPEN, px_p->px_dip, "busy\n");
106 			return (EBUSY);
107 		}
108 		px_p->px_soft_state = PX_SOFT_STATE_OPEN_EXCL;
109 	} else {
110 		if (px_p->px_soft_state == PX_SOFT_STATE_OPEN_EXCL) {
111 			mutex_exit(&px_p->px_mutex);
112 			DBG(DBG_OPEN, px_p->px_dip, "busy\n");
113 			return (EBUSY);
114 		}
115 		px_p->px_soft_state = PX_SOFT_STATE_OPEN;
116 	}
117 	px_p->px_open_count++;
118 	mutex_exit(&px_p->px_mutex);
119 	return (0);
120 }
121 
122 
123 /* ARGSUSED */
124 static int
125 px_close(dev_t dev, int flags, int otyp, cred_t *credp)
126 {
127 	px_t *px_p;
128 
129 	if (otyp != OTYP_CHR)
130 		return (EINVAL);
131 
132 	px_p = DEV_TO_SOFTSTATE(dev);
133 	if (px_p == NULL)
134 		return (ENXIO);
135 
136 	DBG(DBG_CLOSE, px_p->px_dip, "dev=%x: flags=%x\n", dev, flags);
137 	mutex_enter(&px_p->px_mutex);
138 	px_p->px_soft_state = PX_SOFT_STATE_CLOSED;
139 	px_p->px_open_count = 0;
140 	mutex_exit(&px_p->px_mutex);
141 	return (0);
142 }
143 
144 /* ARGSUSED */
145 static int
146 px_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp)
147 {
148 	px_t *px_p;
149 	dev_info_t *dip;
150 	struct devctl_iocdata *dcp;
151 	uint_t bus_state;
152 	int rv = DDI_SUCCESS;
153 
154 	px_p = DEV_TO_SOFTSTATE(dev);
155 	if (px_p == NULL)
156 		return (ENXIO);
157 
158 	dip = px_p->px_dip;
159 	DBG(DBG_IOCTL, dip, "dev=%x: cmd=%x\n", dev, cmd);
160 #ifdef	PX_DMA_TEST
161 	if (IS_DMATEST(cmd)) {
162 		*rvalp = px_dma_test(cmd, dip, px_p, arg);
163 		return (0);
164 	}
165 #endif	/* PX_DMA_TEST */
166 
167 	/*
168 	 * PCI tools.
169 	 */
170 
171 	if ((cmd & ~IOCPARM_MASK) == PCITOOL_IOC ||
172 	    (cmd & ~PPMREQ_MASK) == PPMREQ) {
173 
174 		/* Need privileges to use these ioctls. */
175 		if (drv_priv(credp)) {
176 			DBG(DBG_TOOLS, dip,
177 			    "px_tools: Insufficient privileges\n");
178 
179 		return (EPERM);
180 		}
181 	}
182 
183 	switch (cmd) {
184 	case PCITOOL_DEVICE_GET_REG:
185 	case PCITOOL_DEVICE_SET_REG:
186 		rv = px_lib_tools_dev_reg_ops(dip, (void *)arg, cmd, mode);
187 		return (rv);
188 	case PCITOOL_NEXUS_SET_REG:
189 	case PCITOOL_NEXUS_GET_REG:
190 		rv = px_lib_tools_bus_reg_ops(dip, (void *)arg, cmd, mode);
191 		return (rv);
192 	case PCITOOL_DEVICE_GET_INTR:
193 	case PCITOOL_DEVICE_SET_INTR:
194 	case PCITOOL_DEVICE_NUM_INTR:
195 		rv = px_lib_tools_intr_admn(dip, (void *)arg, cmd, mode);
196 		return (rv);
197 	default:
198 		break;
199 
200 	}
201 
202 	if ((cmd & ~PPMREQ_MASK) == PPMREQ)
203 		return (px_lib_pmctl(cmd, px_p));
204 
205 	/*
206 	 * We can use the generic implementation for these ioctls
207 	 */
208 	switch (cmd) {
209 	case DEVCTL_DEVICE_GETSTATE:
210 	case DEVCTL_DEVICE_ONLINE:
211 	case DEVCTL_DEVICE_OFFLINE:
212 	case DEVCTL_BUS_GETSTATE:
213 		return (ndi_devctl_ioctl(dip, cmd, arg, mode, 0));
214 	}
215 
216 	/*
217 	 * read devctl ioctl data
218 	 */
219 	if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)
220 		return (EFAULT);
221 
222 	switch (cmd) {
223 
224 	case DEVCTL_DEVICE_RESET:
225 		DBG(DBG_IOCTL, dip, "DEVCTL_DEVICE_RESET\n");
226 		rv = ENOTSUP;
227 		break;
228 
229 
230 	case DEVCTL_BUS_QUIESCE:
231 		DBG(DBG_IOCTL, dip, "DEVCTL_BUS_QUIESCE\n");
232 		if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS)
233 			if (bus_state == BUS_QUIESCED)
234 				break;
235 		(void) ndi_set_bus_state(dip, BUS_QUIESCED);
236 		break;
237 
238 	case DEVCTL_BUS_UNQUIESCE:
239 		DBG(DBG_IOCTL, dip, "DEVCTL_BUS_UNQUIESCE\n");
240 		if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS)
241 			if (bus_state == BUS_ACTIVE)
242 				break;
243 		(void) ndi_set_bus_state(dip, BUS_ACTIVE);
244 		break;
245 
246 	case DEVCTL_BUS_RESET:
247 		DBG(DBG_IOCTL, dip, "DEVCTL_BUS_RESET\n");
248 		rv = ENOTSUP;
249 		break;
250 
251 	case DEVCTL_BUS_RESETALL:
252 		DBG(DBG_IOCTL, dip, "DEVCTL_BUS_RESETALL\n");
253 		rv = ENOTSUP;
254 		break;
255 
256 	default:
257 		rv = ENOTTY;
258 	}
259 
260 	ndi_dc_freehdl(dcp);
261 	return (rv);
262 }
263 
264 static int px_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
265     int flags, char *name, caddr_t valuep, int *lengthp)
266 {
267 	if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
268 	    "hotplug-capable"))
269 		return ((pcihp_get_cb_ops())->cb_prop_op(dev, dip,
270 		    prop_op, flags, name, valuep, lengthp));
271 
272 	return (ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp));
273 }
274