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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * PCI nexus HotPlug devctl interface 28 */ 29 #include <sys/types.h> 30 #include <sys/conf.h> 31 #include <sys/kmem.h> 32 #include <sys/async.h> 33 #include <sys/sysmacros.h> 34 #include <sys/sunddi.h> 35 #include <sys/sunndi.h> 36 #include <sys/ddi_impldefs.h> 37 #include <sys/open.h> 38 #include <sys/errno.h> 39 #include <sys/file.h> 40 #include <sys/policy.h> 41 #include "px_obj.h" 42 #include <sys/pci_tools.h> 43 #include "px_tools_ext.h" 44 #include <sys/pcie_pwr.h> 45 46 /*LINTLIBRARY*/ 47 48 static int px_open(dev_t *devp, int flags, int otyp, cred_t *credp); 49 static int px_close(dev_t dev, int flags, int otyp, cred_t *credp); 50 static int px_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 51 cred_t *credp, int *rvalp); 52 53 struct cb_ops px_cb_ops = { 54 px_open, /* open */ 55 px_close, /* close */ 56 nodev, /* strategy */ 57 nodev, /* print */ 58 nodev, /* dump */ 59 nodev, /* read */ 60 nodev, /* write */ 61 px_ioctl, /* ioctl */ 62 nodev, /* devmap */ 63 nodev, /* mmap */ 64 nodev, /* segmap */ 65 nochpoll, /* poll */ 66 pcie_prop_op, /* cb_prop_op */ 67 NULL, /* streamtab */ 68 D_NEW | D_MP | D_HOTPLUG, /* Driver compatibility flag */ 69 CB_REV, /* rev */ 70 nodev, /* int (*cb_aread)() */ 71 nodev /* int (*cb_awrite)() */ 72 }; 73 74 /* ARGSUSED3 */ 75 static int 76 px_open(dev_t *devp, int flags, int otyp, cred_t *credp) 77 { 78 px_t *px_p = PX_DEV_TO_SOFTSTATE(*devp); 79 int minor = getminor(*devp); 80 int rval; 81 82 /* 83 * Make sure the open is for the right file type. 84 */ 85 if (otyp != OTYP_CHR) 86 return (EINVAL); 87 88 /* 89 * Get the soft state structure for the device. 90 */ 91 if (px_p == NULL) 92 return (ENXIO); 93 94 DBG(DBG_OPEN, px_p->px_dip, "devp=%x: flags=%x\n", devp, flags); 95 96 /* 97 * Handle the open by tracking the device state. 98 */ 99 mutex_enter(&px_p->px_mutex); 100 101 switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) { 102 case PCI_TOOL_REG_MINOR_NUM: 103 case PCI_TOOL_INTR_MINOR_NUM: 104 break; 105 default: 106 /* To handle devctl and hotplug related ioctls */ 107 if (rval = pcie_open(px_p->px_dip, devp, flags, otyp, credp)) { 108 mutex_exit(&px_p->px_mutex); 109 return (rval); 110 } 111 } 112 113 if (flags & FEXCL) { 114 if (px_p->px_soft_state != PCI_SOFT_STATE_CLOSED) { 115 mutex_exit(&px_p->px_mutex); 116 DBG(DBG_OPEN, px_p->px_dip, "busy\n"); 117 return (EBUSY); 118 } 119 px_p->px_soft_state = PCI_SOFT_STATE_OPEN_EXCL; 120 } else { 121 if (px_p->px_soft_state == PCI_SOFT_STATE_OPEN_EXCL) { 122 mutex_exit(&px_p->px_mutex); 123 DBG(DBG_OPEN, px_p->px_dip, "busy\n"); 124 return (EBUSY); 125 } 126 px_p->px_soft_state = PCI_SOFT_STATE_OPEN; 127 } 128 129 mutex_exit(&px_p->px_mutex); 130 return (0); 131 } 132 133 134 /* ARGSUSED */ 135 static int 136 px_close(dev_t dev, int flags, int otyp, cred_t *credp) 137 { 138 px_t *px_p = PX_DEV_TO_SOFTSTATE(dev); 139 int minor = getminor(dev); 140 int rval; 141 142 if (otyp != OTYP_CHR) 143 return (EINVAL); 144 145 if (px_p == NULL) 146 return (ENXIO); 147 148 DBG(DBG_CLOSE, px_p->px_dip, "dev=%x: flags=%x\n", dev, flags); 149 mutex_enter(&px_p->px_mutex); 150 151 switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) { 152 case PCI_TOOL_REG_MINOR_NUM: 153 case PCI_TOOL_INTR_MINOR_NUM: 154 break; 155 default: 156 /* To handle devctl and hotplug related ioctls */ 157 if (rval = pcie_close(px_p->px_dip, dev, flags, otyp, credp)) { 158 mutex_exit(&px_p->px_mutex); 159 return (rval); 160 } 161 } 162 163 px_p->px_soft_state = PCI_SOFT_STATE_CLOSED; 164 mutex_exit(&px_p->px_mutex); 165 return (0); 166 } 167 168 /* ARGSUSED */ 169 static int 170 px_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp) 171 { 172 px_t *px_p = PX_DEV_TO_SOFTSTATE(dev); 173 int minor = getminor(dev); 174 dev_info_t *dip; 175 int rv = ENOTTY; 176 177 if (px_p == NULL) 178 return (ENXIO); 179 180 dip = px_p->px_dip; 181 DBG(DBG_IOCTL, dip, "dev=%x: cmd=%x\n", dev, cmd); 182 183 #ifdef PX_DMA_TEST 184 if (IS_DMATEST(cmd)) { 185 *rvalp = px_dma_test(cmd, dip, px_p, arg); 186 return (0); 187 } 188 #endif /* PX_DMA_TEST */ 189 190 switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) { 191 /* 192 * PCI tools. 193 */ 194 case PCI_TOOL_REG_MINOR_NUM: 195 switch (cmd) { 196 case PCITOOL_DEVICE_SET_REG: 197 case PCITOOL_DEVICE_GET_REG: 198 199 /* Require full privileges. */ 200 if (secpolicy_kmdb(credp)) 201 rv = EPERM; 202 else 203 rv = pxtool_dev_reg_ops(dip, 204 (void *)arg, cmd, mode); 205 break; 206 207 case PCITOOL_NEXUS_SET_REG: 208 case PCITOOL_NEXUS_GET_REG: 209 210 /* Require full privileges. */ 211 if (secpolicy_kmdb(credp)) 212 rv = EPERM; 213 else 214 rv = pxtool_bus_reg_ops(dip, 215 (void *)arg, cmd, mode); 216 break; 217 218 default: 219 rv = ENOTTY; 220 } 221 return (rv); 222 case PCI_TOOL_INTR_MINOR_NUM: 223 switch (cmd) { 224 case PCITOOL_DEVICE_SET_INTR: 225 226 /* Require full privileges. */ 227 if (secpolicy_kmdb(credp)) { 228 rv = EPERM; 229 break; 230 } 231 232 /*FALLTHRU*/ 233 /* These require no special privileges. */ 234 case PCITOOL_DEVICE_GET_INTR: 235 case PCITOOL_SYSTEM_INTR_INFO: 236 rv = pxtool_intr(dip, (void *)arg, cmd, mode); 237 break; 238 239 default: 240 rv = ENOTTY; 241 } 242 return (rv); 243 default: 244 /* To handle devctl and hotplug related ioctls */ 245 rv = pcie_ioctl(dip, dev, cmd, arg, mode, credp, rvalp); 246 break; 247 } 248 249 if ((cmd & ~PPMREQ_MASK) == PPMREQ) { 250 251 /* Need privileges to use these ioctls. */ 252 if (drv_priv(credp)) { 253 DBG(DBG_TOOLS, dip, 254 "px_tools: Insufficient privileges\n"); 255 256 return (EPERM); 257 } 258 return (px_lib_pmctl(cmd, px_p)); 259 } 260 261 return (rv); 262 } 263