xref: /onnv-gate/usr/src/uts/sun4/io/px/px_devctl.c (revision 10187:ad62e2dfbe0c)
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 <sys/hotplug/pci/pcihp.h>
420Sstevel@tonic-gate #include "px_obj.h"
43624Sschwartz #include <sys/pci_tools.h>
44777Sschwartz #include "px_tools_ext.h"
45*10187SKrishna.Elango@Sun.COM #include <sys/pcie_pwr.h>
460Sstevel@tonic-gate 
470Sstevel@tonic-gate /*LINTLIBRARY*/
480Sstevel@tonic-gate 
490Sstevel@tonic-gate static int px_open(dev_t *devp, int flags, int otyp, cred_t *credp);
500Sstevel@tonic-gate static int px_close(dev_t dev, int flags, int otyp, cred_t *credp);
510Sstevel@tonic-gate static int px_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
520Sstevel@tonic-gate 						cred_t *credp, int *rvalp);
530Sstevel@tonic-gate static int px_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
540Sstevel@tonic-gate     int flags, char *name, caddr_t valuep, int *lengthp);
550Sstevel@tonic-gate 
560Sstevel@tonic-gate struct cb_ops px_cb_ops = {
570Sstevel@tonic-gate 	px_open,			/* open */
580Sstevel@tonic-gate 	px_close,			/* close */
590Sstevel@tonic-gate 	nodev,				/* strategy */
600Sstevel@tonic-gate 	nodev,				/* print */
610Sstevel@tonic-gate 	nodev,				/* dump */
620Sstevel@tonic-gate 	nodev,				/* read */
630Sstevel@tonic-gate 	nodev,				/* write */
640Sstevel@tonic-gate 	px_ioctl,			/* ioctl */
650Sstevel@tonic-gate 	nodev,				/* devmap */
660Sstevel@tonic-gate 	nodev,				/* mmap */
670Sstevel@tonic-gate 	nodev,				/* segmap */
680Sstevel@tonic-gate 	nochpoll,			/* poll */
690Sstevel@tonic-gate 	px_prop_op,			/* cb_prop_op */
700Sstevel@tonic-gate 	NULL,				/* streamtab */
710Sstevel@tonic-gate 	D_NEW | D_MP | D_HOTPLUG,	/* Driver compatibility flag */
720Sstevel@tonic-gate 	CB_REV,				/* rev */
730Sstevel@tonic-gate 	nodev,				/* int (*cb_aread)() */
740Sstevel@tonic-gate 	nodev				/* int (*cb_awrite)() */
750Sstevel@tonic-gate };
760Sstevel@tonic-gate 
770Sstevel@tonic-gate /* ARGSUSED3 */
780Sstevel@tonic-gate static int
790Sstevel@tonic-gate px_open(dev_t *devp, int flags, int otyp, cred_t *credp)
800Sstevel@tonic-gate {
810Sstevel@tonic-gate 	px_t *px_p;
821531Skini 	int rval;
831531Skini 	uint_t orig_px_soft_state;
840Sstevel@tonic-gate 
850Sstevel@tonic-gate 	/*
860Sstevel@tonic-gate 	 * Make sure the open is for the right file type.
870Sstevel@tonic-gate 	 */
880Sstevel@tonic-gate 	if (otyp != OTYP_CHR)
890Sstevel@tonic-gate 		return (EINVAL);
900Sstevel@tonic-gate 
910Sstevel@tonic-gate 	/*
920Sstevel@tonic-gate 	 * Get the soft state structure for the device.
930Sstevel@tonic-gate 	 */
94909Segillett 	px_p = PX_DEV_TO_SOFTSTATE(*devp);
950Sstevel@tonic-gate 	if (px_p == NULL)
960Sstevel@tonic-gate 		return (ENXIO);
970Sstevel@tonic-gate 
980Sstevel@tonic-gate 	/*
990Sstevel@tonic-gate 	 * Handle the open by tracking the device state.
1000Sstevel@tonic-gate 	 */
1010Sstevel@tonic-gate 	DBG(DBG_OPEN, px_p->px_dip, "devp=%x: flags=%x\n", devp, flags);
1020Sstevel@tonic-gate 	mutex_enter(&px_p->px_mutex);
1031531Skini 	orig_px_soft_state = px_p->px_soft_state;
1040Sstevel@tonic-gate 	if (flags & FEXCL) {
1050Sstevel@tonic-gate 		if (px_p->px_soft_state != PX_SOFT_STATE_CLOSED) {
1060Sstevel@tonic-gate 			mutex_exit(&px_p->px_mutex);
1070Sstevel@tonic-gate 			DBG(DBG_OPEN, px_p->px_dip, "busy\n");
1080Sstevel@tonic-gate 			return (EBUSY);
1090Sstevel@tonic-gate 		}
1100Sstevel@tonic-gate 		px_p->px_soft_state = PX_SOFT_STATE_OPEN_EXCL;
1110Sstevel@tonic-gate 	} else {
1120Sstevel@tonic-gate 		if (px_p->px_soft_state == PX_SOFT_STATE_OPEN_EXCL) {
1130Sstevel@tonic-gate 			mutex_exit(&px_p->px_mutex);
1140Sstevel@tonic-gate 			DBG(DBG_OPEN, px_p->px_dip, "busy\n");
1150Sstevel@tonic-gate 			return (EBUSY);
1160Sstevel@tonic-gate 		}
1170Sstevel@tonic-gate 		px_p->px_soft_state = PX_SOFT_STATE_OPEN;
1180Sstevel@tonic-gate 	}
1191531Skini 
1201531Skini 	if (px_p->px_dev_caps & PX_HOTPLUG_CAPABLE)
1211531Skini 		if (rval = (pcihp_get_cb_ops())->cb_open(devp, flags,
1221531Skini 		    otyp, credp)) {
1231531Skini 			px_p->px_soft_state = orig_px_soft_state;
1241531Skini 			mutex_exit(&px_p->px_mutex);
1251531Skini 			return (rval);
1261531Skini 		}
1271531Skini 
1280Sstevel@tonic-gate 	px_p->px_open_count++;
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
1360Sstevel@tonic-gate px_close(dev_t dev, int flags, int otyp, cred_t *credp)
1370Sstevel@tonic-gate {
1380Sstevel@tonic-gate 	px_t *px_p;
1391531Skini 	int rval;
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate 	if (otyp != OTYP_CHR)
1420Sstevel@tonic-gate 		return (EINVAL);
1430Sstevel@tonic-gate 
144909Segillett 	px_p = PX_DEV_TO_SOFTSTATE(dev);
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 
1511531Skini 	if (px_p->px_dev_caps & PX_HOTPLUG_CAPABLE)
1521531Skini 		if (rval = (pcihp_get_cb_ops())->cb_close(dev, flags,
1531531Skini 		    otyp, credp)) {
1541531Skini 			mutex_exit(&px_p->px_mutex);
1551531Skini 			return (rval);
1561531Skini 		}
1571531Skini 
1580Sstevel@tonic-gate 	px_p->px_soft_state = PX_SOFT_STATE_CLOSED;
1590Sstevel@tonic-gate 	px_p->px_open_count = 0;
1600Sstevel@tonic-gate 	mutex_exit(&px_p->px_mutex);
1610Sstevel@tonic-gate 	return (0);
1620Sstevel@tonic-gate }
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate /* ARGSUSED */
1650Sstevel@tonic-gate static int
1660Sstevel@tonic-gate px_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp)
1670Sstevel@tonic-gate {
1680Sstevel@tonic-gate 	px_t *px_p;
1690Sstevel@tonic-gate 	dev_info_t *dip;
1700Sstevel@tonic-gate 	struct devctl_iocdata *dcp;
1710Sstevel@tonic-gate 	uint_t bus_state;
1720Sstevel@tonic-gate 	int rv = DDI_SUCCESS;
173624Sschwartz 	int minor = getminor(dev);
1740Sstevel@tonic-gate 
175909Segillett 	px_p = PX_DEV_TO_SOFTSTATE(dev);
1760Sstevel@tonic-gate 	if (px_p == NULL)
1770Sstevel@tonic-gate 		return (ENXIO);
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 	dip = px_p->px_dip;
1800Sstevel@tonic-gate 	DBG(DBG_IOCTL, dip, "dev=%x: cmd=%x\n", dev, cmd);
181624Sschwartz 
1820Sstevel@tonic-gate #ifdef	PX_DMA_TEST
1830Sstevel@tonic-gate 	if (IS_DMATEST(cmd)) {
1840Sstevel@tonic-gate 		*rvalp = px_dma_test(cmd, dip, px_p, arg);
1850Sstevel@tonic-gate 		return (0);
1860Sstevel@tonic-gate 	}
1870Sstevel@tonic-gate #endif	/* PX_DMA_TEST */
1880Sstevel@tonic-gate 
189624Sschwartz 	switch (PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
190624Sschwartz 
1910Sstevel@tonic-gate 	/*
1920Sstevel@tonic-gate 	 * PCI tools.
1930Sstevel@tonic-gate 	 */
194624Sschwartz 	case PCI_TOOL_REG_MINOR_NUM:
1950Sstevel@tonic-gate 
196624Sschwartz 		switch (cmd) {
197624Sschwartz 		case PCITOOL_DEVICE_SET_REG:
198624Sschwartz 		case PCITOOL_DEVICE_GET_REG:
199624Sschwartz 
200624Sschwartz 			/* Require full privileges. */
201624Sschwartz 			if (secpolicy_kmdb(credp))
202624Sschwartz 				rv = EPERM;
203624Sschwartz 			else
204624Sschwartz 				rv = pxtool_dev_reg_ops(dip,
205624Sschwartz 				    (void *)arg, cmd, mode);
206624Sschwartz 			break;
207624Sschwartz 
208624Sschwartz 		case PCITOOL_NEXUS_SET_REG:
209624Sschwartz 		case PCITOOL_NEXUS_GET_REG:
210624Sschwartz 
211624Sschwartz 			/* Require full privileges. */
212624Sschwartz 			if (secpolicy_kmdb(credp))
213624Sschwartz 				rv = EPERM;
214624Sschwartz 			else
215624Sschwartz 				rv = pxtool_bus_reg_ops(dip,
216624Sschwartz 				    (void *)arg, cmd, mode);
217624Sschwartz 			break;
218624Sschwartz 
219624Sschwartz 		default:
220624Sschwartz 			rv = ENOTTY;
221624Sschwartz 		}
222624Sschwartz 		return (rv);
223624Sschwartz 
224624Sschwartz 	case PCI_TOOL_INTR_MINOR_NUM:
225624Sschwartz 
226624Sschwartz 		switch (cmd) {
227624Sschwartz 		case PCITOOL_DEVICE_SET_INTR:
228624Sschwartz 
2299537SErwin.Tsaur@Sun.COM 			/* Require full privileges. */
2309537SErwin.Tsaur@Sun.COM 			if (secpolicy_kmdb(credp)) {
2319537SErwin.Tsaur@Sun.COM 				rv = EPERM;
2329537SErwin.Tsaur@Sun.COM 				break;
2339537SErwin.Tsaur@Sun.COM 			}
234624Sschwartz 
235624Sschwartz 		/*FALLTHRU*/
236624Sschwartz 		/* These require no special privileges. */
237624Sschwartz 		case PCITOOL_DEVICE_GET_INTR:
2384397Sschwartz 		case PCITOOL_SYSTEM_INTR_INFO:
239624Sschwartz 			rv = pxtool_intr(dip, (void *)arg, cmd, mode);
240624Sschwartz 			break;
241624Sschwartz 
242624Sschwartz 		default:
243624Sschwartz 			rv = ENOTTY;
244624Sschwartz 		}
245624Sschwartz 		return (rv);
246624Sschwartz 
247624Sschwartz 	default:
2481531Skini 		if (px_p->px_dev_caps & PX_HOTPLUG_CAPABLE)
2491531Skini 			return ((pcihp_get_cb_ops())->cb_ioctl(dev, cmd,
2501531Skini 			    arg, mode, credp, rvalp));
251624Sschwartz 		break;
252624Sschwartz 	}
253624Sschwartz 
254624Sschwartz 	if ((cmd & ~PPMREQ_MASK) == PPMREQ) {
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate 		/* Need privileges to use these ioctls. */
2570Sstevel@tonic-gate 		if (drv_priv(credp)) {
2580Sstevel@tonic-gate 			DBG(DBG_TOOLS, dip,
2590Sstevel@tonic-gate 			    "px_tools: Insufficient privileges\n");
2600Sstevel@tonic-gate 
261624Sschwartz 			return (EPERM);
2620Sstevel@tonic-gate 		}
263624Sschwartz 		return (px_lib_pmctl(cmd, px_p));
2640Sstevel@tonic-gate 	}
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 	/*
2670Sstevel@tonic-gate 	 * We can use the generic implementation for these ioctls
2680Sstevel@tonic-gate 	 */
2690Sstevel@tonic-gate 	switch (cmd) {
2700Sstevel@tonic-gate 	case DEVCTL_DEVICE_GETSTATE:
2710Sstevel@tonic-gate 	case DEVCTL_DEVICE_ONLINE:
2720Sstevel@tonic-gate 	case DEVCTL_DEVICE_OFFLINE:
2730Sstevel@tonic-gate 	case DEVCTL_BUS_GETSTATE:
2740Sstevel@tonic-gate 		return (ndi_devctl_ioctl(dip, cmd, arg, mode, 0));
2750Sstevel@tonic-gate 	}
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 	/*
2780Sstevel@tonic-gate 	 * read devctl ioctl data
2790Sstevel@tonic-gate 	 */
2800Sstevel@tonic-gate 	if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)
2810Sstevel@tonic-gate 		return (EFAULT);
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 	switch (cmd) {
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate 	case DEVCTL_DEVICE_RESET:
2860Sstevel@tonic-gate 		DBG(DBG_IOCTL, dip, "DEVCTL_DEVICE_RESET\n");
2870Sstevel@tonic-gate 		rv = ENOTSUP;
2880Sstevel@tonic-gate 		break;
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 	case DEVCTL_BUS_QUIESCE:
2920Sstevel@tonic-gate 		DBG(DBG_IOCTL, dip, "DEVCTL_BUS_QUIESCE\n");
2930Sstevel@tonic-gate 		if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS)
2940Sstevel@tonic-gate 			if (bus_state == BUS_QUIESCED)
2950Sstevel@tonic-gate 				break;
2960Sstevel@tonic-gate 		(void) ndi_set_bus_state(dip, BUS_QUIESCED);
2970Sstevel@tonic-gate 		break;
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate 	case DEVCTL_BUS_UNQUIESCE:
3000Sstevel@tonic-gate 		DBG(DBG_IOCTL, dip, "DEVCTL_BUS_UNQUIESCE\n");
3010Sstevel@tonic-gate 		if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS)
3020Sstevel@tonic-gate 			if (bus_state == BUS_ACTIVE)
3030Sstevel@tonic-gate 				break;
3040Sstevel@tonic-gate 		(void) ndi_set_bus_state(dip, BUS_ACTIVE);
3050Sstevel@tonic-gate 		break;
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 	case DEVCTL_BUS_RESET:
3080Sstevel@tonic-gate 		DBG(DBG_IOCTL, dip, "DEVCTL_BUS_RESET\n");
3090Sstevel@tonic-gate 		rv = ENOTSUP;
3100Sstevel@tonic-gate 		break;
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate 	case DEVCTL_BUS_RESETALL:
3130Sstevel@tonic-gate 		DBG(DBG_IOCTL, dip, "DEVCTL_BUS_RESETALL\n");
3140Sstevel@tonic-gate 		rv = ENOTSUP;
3150Sstevel@tonic-gate 		break;
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate 	default:
3180Sstevel@tonic-gate 		rv = ENOTTY;
3190Sstevel@tonic-gate 	}
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 	ndi_dc_freehdl(dcp);
3220Sstevel@tonic-gate 	return (rv);
3230Sstevel@tonic-gate }
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate static int px_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
3260Sstevel@tonic-gate     int flags, char *name, caddr_t valuep, int *lengthp)
3270Sstevel@tonic-gate {
3280Sstevel@tonic-gate 	if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
3290Sstevel@tonic-gate 	    "hotplug-capable"))
3300Sstevel@tonic-gate 		return ((pcihp_get_cb_ops())->cb_prop_op(dev, dip,
3310Sstevel@tonic-gate 		    prop_op, flags, name, valuep, lengthp));
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 	return (ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp));
3340Sstevel@tonic-gate }
335