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