xref: /onnv-gate/usr/src/uts/sun4/io/px/px_devctl.c (revision 10923:df470fd79c3c)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51540Skini  * Common Development and Distribution License (the "License").
61540Skini  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
229537SErwin.Tsaur@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate  * PCI nexus HotPlug devctl interface
280Sstevel@tonic-gate  */
290Sstevel@tonic-gate #include <sys/types.h>
300Sstevel@tonic-gate #include <sys/conf.h>
310Sstevel@tonic-gate #include <sys/kmem.h>
320Sstevel@tonic-gate #include <sys/async.h>
330Sstevel@tonic-gate #include <sys/sysmacros.h>
340Sstevel@tonic-gate #include <sys/sunddi.h>
350Sstevel@tonic-gate #include <sys/sunndi.h>
360Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
370Sstevel@tonic-gate #include <sys/open.h>
380Sstevel@tonic-gate #include <sys/errno.h>
390Sstevel@tonic-gate #include <sys/file.h>
40624Sschwartz #include <sys/policy.h>
410Sstevel@tonic-gate #include "px_obj.h"
42624Sschwartz #include <sys/pci_tools.h>
43777Sschwartz #include "px_tools_ext.h"
4410187SKrishna.Elango@Sun.COM #include <sys/pcie_pwr.h>
450Sstevel@tonic-gate 
460Sstevel@tonic-gate /*LINTLIBRARY*/
470Sstevel@tonic-gate 
480Sstevel@tonic-gate static int px_open(dev_t *devp, int flags, int otyp, cred_t *credp);
490Sstevel@tonic-gate static int px_close(dev_t dev, int flags, int otyp, cred_t *credp);
500Sstevel@tonic-gate static int px_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
510Sstevel@tonic-gate 						cred_t *credp, int *rvalp);
520Sstevel@tonic-gate 
530Sstevel@tonic-gate struct cb_ops px_cb_ops = {
540Sstevel@tonic-gate 	px_open,			/* open */
550Sstevel@tonic-gate 	px_close,			/* close */
560Sstevel@tonic-gate 	nodev,				/* strategy */
570Sstevel@tonic-gate 	nodev,				/* print */
580Sstevel@tonic-gate 	nodev,				/* dump */
590Sstevel@tonic-gate 	nodev,				/* read */
600Sstevel@tonic-gate 	nodev,				/* write */
610Sstevel@tonic-gate 	px_ioctl,			/* ioctl */
620Sstevel@tonic-gate 	nodev,				/* devmap */
630Sstevel@tonic-gate 	nodev,				/* mmap */
640Sstevel@tonic-gate 	nodev,				/* segmap */
650Sstevel@tonic-gate 	nochpoll,			/* poll */
66*10923SEvan.Yan@Sun.COM 	pcie_prop_op,			/* cb_prop_op */
670Sstevel@tonic-gate 	NULL,				/* streamtab */
680Sstevel@tonic-gate 	D_NEW | D_MP | D_HOTPLUG,	/* Driver compatibility flag */
690Sstevel@tonic-gate 	CB_REV,				/* rev */
700Sstevel@tonic-gate 	nodev,				/* int (*cb_aread)() */
710Sstevel@tonic-gate 	nodev				/* int (*cb_awrite)() */
720Sstevel@tonic-gate };
730Sstevel@tonic-gate 
740Sstevel@tonic-gate /* ARGSUSED3 */
750Sstevel@tonic-gate static int
px_open(dev_t * devp,int flags,int otyp,cred_t * credp)760Sstevel@tonic-gate px_open(dev_t *devp, int flags, int otyp, cred_t *credp)
770Sstevel@tonic-gate {
78*10923SEvan.Yan@Sun.COM 	px_t		*px_p = PX_DEV_TO_SOFTSTATE(*devp);
79*10923SEvan.Yan@Sun.COM 	int		minor = getminor(*devp);
80*10923SEvan.Yan@Sun.COM 	int		rval;
810Sstevel@tonic-gate 
820Sstevel@tonic-gate 	/*
830Sstevel@tonic-gate 	 * Make sure the open is for the right file type.
840Sstevel@tonic-gate 	 */
850Sstevel@tonic-gate 	if (otyp != OTYP_CHR)
860Sstevel@tonic-gate 		return (EINVAL);
870Sstevel@tonic-gate 
880Sstevel@tonic-gate 	/*
890Sstevel@tonic-gate 	 * Get the soft state structure for the device.
900Sstevel@tonic-gate 	 */
910Sstevel@tonic-gate 	if (px_p == NULL)
920Sstevel@tonic-gate 		return (ENXIO);
930Sstevel@tonic-gate 
94*10923SEvan.Yan@Sun.COM 	DBG(DBG_OPEN, px_p->px_dip, "devp=%x: flags=%x\n", devp, flags);
95*10923SEvan.Yan@Sun.COM 
960Sstevel@tonic-gate 	/*
970Sstevel@tonic-gate 	 * Handle the open by tracking the device state.
980Sstevel@tonic-gate 	 */
990Sstevel@tonic-gate 	mutex_enter(&px_p->px_mutex);
100*10923SEvan.Yan@Sun.COM 
101*10923SEvan.Yan@Sun.COM 	switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
102*10923SEvan.Yan@Sun.COM 	case PCI_TOOL_REG_MINOR_NUM:
103*10923SEvan.Yan@Sun.COM 	case PCI_TOOL_INTR_MINOR_NUM:
104*10923SEvan.Yan@Sun.COM 		break;
105*10923SEvan.Yan@Sun.COM 	default:
106*10923SEvan.Yan@Sun.COM 		/* To handle devctl and hotplug related ioctls */
107*10923SEvan.Yan@Sun.COM 		if (rval = pcie_open(px_p->px_dip, devp, flags, otyp, credp)) {
108*10923SEvan.Yan@Sun.COM 			mutex_exit(&px_p->px_mutex);
109*10923SEvan.Yan@Sun.COM 			return (rval);
110*10923SEvan.Yan@Sun.COM 		}
111*10923SEvan.Yan@Sun.COM 	}
112*10923SEvan.Yan@Sun.COM 
1130Sstevel@tonic-gate 	if (flags & FEXCL) {
114*10923SEvan.Yan@Sun.COM 		if (px_p->px_soft_state != PCI_SOFT_STATE_CLOSED) {
1150Sstevel@tonic-gate 			mutex_exit(&px_p->px_mutex);
1160Sstevel@tonic-gate 			DBG(DBG_OPEN, px_p->px_dip, "busy\n");
1170Sstevel@tonic-gate 			return (EBUSY);
1180Sstevel@tonic-gate 		}
119*10923SEvan.Yan@Sun.COM 		px_p->px_soft_state = PCI_SOFT_STATE_OPEN_EXCL;
1200Sstevel@tonic-gate 	} else {
121*10923SEvan.Yan@Sun.COM 		if (px_p->px_soft_state == PCI_SOFT_STATE_OPEN_EXCL) {
1220Sstevel@tonic-gate 			mutex_exit(&px_p->px_mutex);
1230Sstevel@tonic-gate 			DBG(DBG_OPEN, px_p->px_dip, "busy\n");
1240Sstevel@tonic-gate 			return (EBUSY);
1250Sstevel@tonic-gate 		}
126*10923SEvan.Yan@Sun.COM 		px_p->px_soft_state = PCI_SOFT_STATE_OPEN;
1270Sstevel@tonic-gate 	}
1281531Skini 
1290Sstevel@tonic-gate 	mutex_exit(&px_p->px_mutex);
1300Sstevel@tonic-gate 	return (0);
1310Sstevel@tonic-gate }
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate /* ARGSUSED */
1350Sstevel@tonic-gate static int
px_close(dev_t dev,int flags,int otyp,cred_t * credp)1360Sstevel@tonic-gate px_close(dev_t dev, int flags, int otyp, cred_t *credp)
1370Sstevel@tonic-gate {
138*10923SEvan.Yan@Sun.COM 	px_t		*px_p = PX_DEV_TO_SOFTSTATE(dev);
139*10923SEvan.Yan@Sun.COM 	int		minor = getminor(dev);
140*10923SEvan.Yan@Sun.COM 	int		rval;
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate 	if (otyp != OTYP_CHR)
1430Sstevel@tonic-gate 		return (EINVAL);
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate 	if (px_p == NULL)
1460Sstevel@tonic-gate 		return (ENXIO);
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate 	DBG(DBG_CLOSE, px_p->px_dip, "dev=%x: flags=%x\n", dev, flags);
1490Sstevel@tonic-gate 	mutex_enter(&px_p->px_mutex);
1501531Skini 
151*10923SEvan.Yan@Sun.COM 	switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
152*10923SEvan.Yan@Sun.COM 	case PCI_TOOL_REG_MINOR_NUM:
153*10923SEvan.Yan@Sun.COM 	case PCI_TOOL_INTR_MINOR_NUM:
154*10923SEvan.Yan@Sun.COM 		break;
155*10923SEvan.Yan@Sun.COM 	default:
156*10923SEvan.Yan@Sun.COM 		/* To handle devctl and hotplug related ioctls */
157*10923SEvan.Yan@Sun.COM 		if (rval = pcie_close(px_p->px_dip, dev, flags, otyp, credp)) {
1581531Skini 			mutex_exit(&px_p->px_mutex);
1591531Skini 			return (rval);
1601531Skini 		}
161*10923SEvan.Yan@Sun.COM 	}
1621531Skini 
163*10923SEvan.Yan@Sun.COM 	px_p->px_soft_state = PCI_SOFT_STATE_CLOSED;
1640Sstevel@tonic-gate 	mutex_exit(&px_p->px_mutex);
1650Sstevel@tonic-gate 	return (0);
1660Sstevel@tonic-gate }
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate /* ARGSUSED */
1690Sstevel@tonic-gate static int
px_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)1700Sstevel@tonic-gate px_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp)
1710Sstevel@tonic-gate {
172*10923SEvan.Yan@Sun.COM 	px_t		*px_p = PX_DEV_TO_SOFTSTATE(dev);
173*10923SEvan.Yan@Sun.COM 	int		minor = getminor(dev);
174*10923SEvan.Yan@Sun.COM 	dev_info_t	*dip;
175*10923SEvan.Yan@Sun.COM 	int		rv = ENOTTY;
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate 	if (px_p == NULL)
1780Sstevel@tonic-gate 		return (ENXIO);
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate 	dip = px_p->px_dip;
1810Sstevel@tonic-gate 	DBG(DBG_IOCTL, dip, "dev=%x: cmd=%x\n", dev, cmd);
182624Sschwartz 
1830Sstevel@tonic-gate #ifdef	PX_DMA_TEST
1840Sstevel@tonic-gate 	if (IS_DMATEST(cmd)) {
1850Sstevel@tonic-gate 		*rvalp = px_dma_test(cmd, dip, px_p, arg);
1860Sstevel@tonic-gate 		return (0);
1870Sstevel@tonic-gate 	}
1880Sstevel@tonic-gate #endif	/* PX_DMA_TEST */
1890Sstevel@tonic-gate 
190*10923SEvan.Yan@Sun.COM 	switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
1910Sstevel@tonic-gate 	/*
1920Sstevel@tonic-gate 	 * PCI tools.
1930Sstevel@tonic-gate 	 */
194624Sschwartz 	case PCI_TOOL_REG_MINOR_NUM:
195624Sschwartz 		switch (cmd) {
196624Sschwartz 		case PCITOOL_DEVICE_SET_REG:
197624Sschwartz 		case PCITOOL_DEVICE_GET_REG:
198624Sschwartz 
199624Sschwartz 			/* Require full privileges. */
200624Sschwartz 			if (secpolicy_kmdb(credp))
201624Sschwartz 				rv = EPERM;
202624Sschwartz 			else
203624Sschwartz 				rv = pxtool_dev_reg_ops(dip,
204624Sschwartz 				    (void *)arg, cmd, mode);
205624Sschwartz 			break;
206624Sschwartz 
207624Sschwartz 		case PCITOOL_NEXUS_SET_REG:
208624Sschwartz 		case PCITOOL_NEXUS_GET_REG:
209624Sschwartz 
210624Sschwartz 			/* Require full privileges. */
211624Sschwartz 			if (secpolicy_kmdb(credp))
212624Sschwartz 				rv = EPERM;
213624Sschwartz 			else
214624Sschwartz 				rv = pxtool_bus_reg_ops(dip,
215624Sschwartz 				    (void *)arg, cmd, mode);
216624Sschwartz 			break;
217624Sschwartz 
218624Sschwartz 		default:
219624Sschwartz 			rv = ENOTTY;
220624Sschwartz 		}
221624Sschwartz 		return (rv);
222624Sschwartz 	case PCI_TOOL_INTR_MINOR_NUM:
223624Sschwartz 		switch (cmd) {
224624Sschwartz 		case PCITOOL_DEVICE_SET_INTR:
225624Sschwartz 
2269537SErwin.Tsaur@Sun.COM 			/* Require full privileges. */
2279537SErwin.Tsaur@Sun.COM 			if (secpolicy_kmdb(credp)) {
2289537SErwin.Tsaur@Sun.COM 				rv = EPERM;
2299537SErwin.Tsaur@Sun.COM 				break;
2309537SErwin.Tsaur@Sun.COM 			}
231624Sschwartz 
232624Sschwartz 		/*FALLTHRU*/
233624Sschwartz 		/* These require no special privileges. */
234624Sschwartz 		case PCITOOL_DEVICE_GET_INTR:
2354397Sschwartz 		case PCITOOL_SYSTEM_INTR_INFO:
236624Sschwartz 			rv = pxtool_intr(dip, (void *)arg, cmd, mode);
237624Sschwartz 			break;
238624Sschwartz 
239624Sschwartz 		default:
240624Sschwartz 			rv = ENOTTY;
241624Sschwartz 		}
242624Sschwartz 		return (rv);
243624Sschwartz 	default:
244*10923SEvan.Yan@Sun.COM 		/* To handle devctl and hotplug related ioctls */
245*10923SEvan.Yan@Sun.COM 		rv = pcie_ioctl(dip, dev, cmd, arg, mode, credp, rvalp);
246624Sschwartz 		break;
247624Sschwartz 	}
248624Sschwartz 
249624Sschwartz 	if ((cmd & ~PPMREQ_MASK) == PPMREQ) {
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 		/* Need privileges to use these ioctls. */
2520Sstevel@tonic-gate 		if (drv_priv(credp)) {
2530Sstevel@tonic-gate 			DBG(DBG_TOOLS, dip,
2540Sstevel@tonic-gate 			    "px_tools: Insufficient privileges\n");
2550Sstevel@tonic-gate 
256624Sschwartz 			return (EPERM);
2570Sstevel@tonic-gate 		}
258624Sschwartz 		return (px_lib_pmctl(cmd, px_p));
2590Sstevel@tonic-gate 	}
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 	return (rv);
2620Sstevel@tonic-gate }
263