xref: /illumos-gate/usr/src/uts/sun4/io/px/px_devctl.c (revision 26947304)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57aadd8d4Skini  * Common Development and Distribution License (the "License").
67aadd8d4Skini  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22d5ace945SErwin T Tsaur  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * PCI nexus HotPlug devctl interface
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate #include <sys/types.h>
307c478bd9Sstevel@tonic-gate #include <sys/conf.h>
317c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
327c478bd9Sstevel@tonic-gate #include <sys/async.h>
337c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
347c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
357c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
367c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
377c478bd9Sstevel@tonic-gate #include <sys/open.h>
387c478bd9Sstevel@tonic-gate #include <sys/errno.h>
397c478bd9Sstevel@tonic-gate #include <sys/file.h>
4069cd775fSschwartz #include <sys/policy.h>
417c478bd9Sstevel@tonic-gate #include "px_obj.h"
4269cd775fSschwartz #include <sys/pci_tools.h>
43d4476ccbSschwartz #include "px_tools_ext.h"
44d4bc0535SKrishna Elango #include <sys/pcie_pwr.h>
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate /*LINTLIBRARY*/
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate static int px_open(dev_t *devp, int flags, int otyp, cred_t *credp);
497c478bd9Sstevel@tonic-gate static int px_close(dev_t dev, int flags, int otyp, cred_t *credp);
507c478bd9Sstevel@tonic-gate static int px_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
517c478bd9Sstevel@tonic-gate 						cred_t *credp, int *rvalp);
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate struct cb_ops px_cb_ops = {
547c478bd9Sstevel@tonic-gate 	px_open,			/* open */
557c478bd9Sstevel@tonic-gate 	px_close,			/* close */
567c478bd9Sstevel@tonic-gate 	nodev,				/* strategy */
577c478bd9Sstevel@tonic-gate 	nodev,				/* print */
587c478bd9Sstevel@tonic-gate 	nodev,				/* dump */
597c478bd9Sstevel@tonic-gate 	nodev,				/* read */
607c478bd9Sstevel@tonic-gate 	nodev,				/* write */
617c478bd9Sstevel@tonic-gate 	px_ioctl,			/* ioctl */
627c478bd9Sstevel@tonic-gate 	nodev,				/* devmap */
637c478bd9Sstevel@tonic-gate 	nodev,				/* mmap */
647c478bd9Sstevel@tonic-gate 	nodev,				/* segmap */
657c478bd9Sstevel@tonic-gate 	nochpoll,			/* poll */
66*26947304SEvan Yan 	pcie_prop_op,			/* cb_prop_op */
677c478bd9Sstevel@tonic-gate 	NULL,				/* streamtab */
687c478bd9Sstevel@tonic-gate 	D_NEW | D_MP | D_HOTPLUG,	/* Driver compatibility flag */
697c478bd9Sstevel@tonic-gate 	CB_REV,				/* rev */
707c478bd9Sstevel@tonic-gate 	nodev,				/* int (*cb_aread)() */
717c478bd9Sstevel@tonic-gate 	nodev				/* int (*cb_awrite)() */
727c478bd9Sstevel@tonic-gate };
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate /* ARGSUSED3 */
757c478bd9Sstevel@tonic-gate static int
px_open(dev_t * devp,int flags,int otyp,cred_t * credp)767c478bd9Sstevel@tonic-gate px_open(dev_t *devp, int flags, int otyp, cred_t *credp)
777c478bd9Sstevel@tonic-gate {
78*26947304SEvan Yan 	px_t		*px_p = PX_DEV_TO_SOFTSTATE(*devp);
79*26947304SEvan Yan 	int		minor = getminor(*devp);
80*26947304SEvan Yan 	int		rval;
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate 	/*
837c478bd9Sstevel@tonic-gate 	 * Make sure the open is for the right file type.
847c478bd9Sstevel@tonic-gate 	 */
857c478bd9Sstevel@tonic-gate 	if (otyp != OTYP_CHR)
867c478bd9Sstevel@tonic-gate 		return (EINVAL);
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate 	/*
897c478bd9Sstevel@tonic-gate 	 * Get the soft state structure for the device.
907c478bd9Sstevel@tonic-gate 	 */
917c478bd9Sstevel@tonic-gate 	if (px_p == NULL)
927c478bd9Sstevel@tonic-gate 		return (ENXIO);
937c478bd9Sstevel@tonic-gate 
94*26947304SEvan Yan 	DBG(DBG_OPEN, px_p->px_dip, "devp=%x: flags=%x\n", devp, flags);
95*26947304SEvan Yan 
967c478bd9Sstevel@tonic-gate 	/*
977c478bd9Sstevel@tonic-gate 	 * Handle the open by tracking the device state.
987c478bd9Sstevel@tonic-gate 	 */
997c478bd9Sstevel@tonic-gate 	mutex_enter(&px_p->px_mutex);
100*26947304SEvan Yan 
101*26947304SEvan Yan 	switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
102*26947304SEvan Yan 	case PCI_TOOL_REG_MINOR_NUM:
103*26947304SEvan Yan 	case PCI_TOOL_INTR_MINOR_NUM:
104*26947304SEvan Yan 		break;
105*26947304SEvan Yan 	default:
106*26947304SEvan Yan 		/* To handle devctl and hotplug related ioctls */
107*26947304SEvan Yan 		if (rval = pcie_open(px_p->px_dip, devp, flags, otyp, credp)) {
108*26947304SEvan Yan 			mutex_exit(&px_p->px_mutex);
109*26947304SEvan Yan 			return (rval);
110*26947304SEvan Yan 		}
111*26947304SEvan Yan 	}
112*26947304SEvan Yan 
1137c478bd9Sstevel@tonic-gate 	if (flags & FEXCL) {
114*26947304SEvan Yan 		if (px_p->px_soft_state != PCI_SOFT_STATE_CLOSED) {
1157c478bd9Sstevel@tonic-gate 			mutex_exit(&px_p->px_mutex);
1167c478bd9Sstevel@tonic-gate 			DBG(DBG_OPEN, px_p->px_dip, "busy\n");
1177c478bd9Sstevel@tonic-gate 			return (EBUSY);
1187c478bd9Sstevel@tonic-gate 		}
119*26947304SEvan Yan 		px_p->px_soft_state = PCI_SOFT_STATE_OPEN_EXCL;
1207c478bd9Sstevel@tonic-gate 	} else {
121*26947304SEvan Yan 		if (px_p->px_soft_state == PCI_SOFT_STATE_OPEN_EXCL) {
1227c478bd9Sstevel@tonic-gate 			mutex_exit(&px_p->px_mutex);
1237c478bd9Sstevel@tonic-gate 			DBG(DBG_OPEN, px_p->px_dip, "busy\n");
1247c478bd9Sstevel@tonic-gate 			return (EBUSY);
1257c478bd9Sstevel@tonic-gate 		}
126*26947304SEvan Yan 		px_p->px_soft_state = PCI_SOFT_STATE_OPEN;
1277c478bd9Sstevel@tonic-gate 	}
128b65731f1Skini 
1297c478bd9Sstevel@tonic-gate 	mutex_exit(&px_p->px_mutex);
1307c478bd9Sstevel@tonic-gate 	return (0);
1317c478bd9Sstevel@tonic-gate }
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate /* ARGSUSED */
1357c478bd9Sstevel@tonic-gate static int
px_close(dev_t dev,int flags,int otyp,cred_t * credp)1367c478bd9Sstevel@tonic-gate px_close(dev_t dev, int flags, int otyp, cred_t *credp)
1377c478bd9Sstevel@tonic-gate {
138*26947304SEvan Yan 	px_t		*px_p = PX_DEV_TO_SOFTSTATE(dev);
139*26947304SEvan Yan 	int		minor = getminor(dev);
140*26947304SEvan Yan 	int		rval;
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate 	if (otyp != OTYP_CHR)
1437c478bd9Sstevel@tonic-gate 		return (EINVAL);
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 	if (px_p == NULL)
1467c478bd9Sstevel@tonic-gate 		return (ENXIO);
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 	DBG(DBG_CLOSE, px_p->px_dip, "dev=%x: flags=%x\n", dev, flags);
1497c478bd9Sstevel@tonic-gate 	mutex_enter(&px_p->px_mutex);
150b65731f1Skini 
151*26947304SEvan Yan 	switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
152*26947304SEvan Yan 	case PCI_TOOL_REG_MINOR_NUM:
153*26947304SEvan Yan 	case PCI_TOOL_INTR_MINOR_NUM:
154*26947304SEvan Yan 		break;
155*26947304SEvan Yan 	default:
156*26947304SEvan Yan 		/* To handle devctl and hotplug related ioctls */
157*26947304SEvan Yan 		if (rval = pcie_close(px_p->px_dip, dev, flags, otyp, credp)) {
158b65731f1Skini 			mutex_exit(&px_p->px_mutex);
159b65731f1Skini 			return (rval);
160b65731f1Skini 		}
161*26947304SEvan Yan 	}
162b65731f1Skini 
163*26947304SEvan Yan 	px_p->px_soft_state = PCI_SOFT_STATE_CLOSED;
1647c478bd9Sstevel@tonic-gate 	mutex_exit(&px_p->px_mutex);
1657c478bd9Sstevel@tonic-gate 	return (0);
1667c478bd9Sstevel@tonic-gate }
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate /* ARGSUSED */
1697c478bd9Sstevel@tonic-gate static int
px_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)1707c478bd9Sstevel@tonic-gate px_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp)
1717c478bd9Sstevel@tonic-gate {
172*26947304SEvan Yan 	px_t		*px_p = PX_DEV_TO_SOFTSTATE(dev);
173*26947304SEvan Yan 	int		minor = getminor(dev);
174*26947304SEvan Yan 	dev_info_t	*dip;
175*26947304SEvan Yan 	int		rv = ENOTTY;
176*26947304SEvan Yan 
1777c478bd9Sstevel@tonic-gate 	if (px_p == NULL)
1787c478bd9Sstevel@tonic-gate 		return (ENXIO);
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	dip = px_p->px_dip;
1817c478bd9Sstevel@tonic-gate 	DBG(DBG_IOCTL, dip, "dev=%x: cmd=%x\n", dev, cmd);
18269cd775fSschwartz 
1837c478bd9Sstevel@tonic-gate #ifdef	PX_DMA_TEST
1847c478bd9Sstevel@tonic-gate 	if (IS_DMATEST(cmd)) {
1857c478bd9Sstevel@tonic-gate 		*rvalp = px_dma_test(cmd, dip, px_p, arg);
1867c478bd9Sstevel@tonic-gate 		return (0);
1877c478bd9Sstevel@tonic-gate 	}
1887c478bd9Sstevel@tonic-gate #endif	/* PX_DMA_TEST */
1897c478bd9Sstevel@tonic-gate 
190*26947304SEvan Yan 	switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
1917c478bd9Sstevel@tonic-gate 	/*
1927c478bd9Sstevel@tonic-gate 	 * PCI tools.
1937c478bd9Sstevel@tonic-gate 	 */
19469cd775fSschwartz 	case PCI_TOOL_REG_MINOR_NUM:
19569cd775fSschwartz 		switch (cmd) {
19669cd775fSschwartz 		case PCITOOL_DEVICE_SET_REG:
19769cd775fSschwartz 		case PCITOOL_DEVICE_GET_REG:
1987c478bd9Sstevel@tonic-gate 
19969cd775fSschwartz 			/* Require full privileges. */
20069cd775fSschwartz 			if (secpolicy_kmdb(credp))
20169cd775fSschwartz 				rv = EPERM;
20269cd775fSschwartz 			else
20369cd775fSschwartz 				rv = pxtool_dev_reg_ops(dip,
20469cd775fSschwartz 				    (void *)arg, cmd, mode);
20569cd775fSschwartz 			break;
2067c478bd9Sstevel@tonic-gate 
20769cd775fSschwartz 		case PCITOOL_NEXUS_SET_REG:
20869cd775fSschwartz 		case PCITOOL_NEXUS_GET_REG:
2097c478bd9Sstevel@tonic-gate 
21069cd775fSschwartz 			/* Require full privileges. */
21169cd775fSschwartz 			if (secpolicy_kmdb(credp))
21269cd775fSschwartz 				rv = EPERM;
21369cd775fSschwartz 			else
21469cd775fSschwartz 				rv = pxtool_bus_reg_ops(dip,
21569cd775fSschwartz 				    (void *)arg, cmd, mode);
21669cd775fSschwartz 			break;
21769cd775fSschwartz 
21869cd775fSschwartz 		default:
21969cd775fSschwartz 			rv = ENOTTY;
22069cd775fSschwartz 		}
2217c478bd9Sstevel@tonic-gate 		return (rv);
22269cd775fSschwartz 	case PCI_TOOL_INTR_MINOR_NUM:
22369cd775fSschwartz 		switch (cmd) {
22469cd775fSschwartz 		case PCITOOL_DEVICE_SET_INTR:
22569cd775fSschwartz 
226d5ace945SErwin T Tsaur 			/* Require full privileges. */
227d5ace945SErwin T Tsaur 			if (secpolicy_kmdb(credp)) {
228d5ace945SErwin T Tsaur 				rv = EPERM;
229d5ace945SErwin T Tsaur 				break;
230d5ace945SErwin T Tsaur 			}
23169cd775fSschwartz 
23269cd775fSschwartz 		/*FALLTHRU*/
23369cd775fSschwartz 		/* These require no special privileges. */
23469cd775fSschwartz 		case PCITOOL_DEVICE_GET_INTR:
2352917a9c9Sschwartz 		case PCITOOL_SYSTEM_INTR_INFO:
23669cd775fSschwartz 			rv = pxtool_intr(dip, (void *)arg, cmd, mode);
23769cd775fSschwartz 			break;
23869cd775fSschwartz 
23969cd775fSschwartz 		default:
24069cd775fSschwartz 			rv = ENOTTY;
24169cd775fSschwartz 		}
2427c478bd9Sstevel@tonic-gate 		return (rv);
2437c478bd9Sstevel@tonic-gate 	default:
244*26947304SEvan Yan 		/* To handle devctl and hotplug related ioctls */
245*26947304SEvan Yan 		rv = pcie_ioctl(dip, dev, cmd, arg, mode, credp, rvalp);
2467c478bd9Sstevel@tonic-gate 		break;
2477c478bd9Sstevel@tonic-gate 	}
2487c478bd9Sstevel@tonic-gate 
24969cd775fSschwartz 	if ((cmd & ~PPMREQ_MASK) == PPMREQ) {
25069cd775fSschwartz 
25169cd775fSschwartz 		/* Need privileges to use these ioctls. */
25269cd775fSschwartz 		if (drv_priv(credp)) {
25369cd775fSschwartz 			DBG(DBG_TOOLS, dip,
25469cd775fSschwartz 			    "px_tools: Insufficient privileges\n");
25569cd775fSschwartz 
25669cd775fSschwartz 			return (EPERM);
25769cd775fSschwartz 		}
2587c478bd9Sstevel@tonic-gate 		return (px_lib_pmctl(cmd, px_p));
25969cd775fSschwartz 	}
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate 	return (rv);
2627c478bd9Sstevel@tonic-gate }
263