1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 2000-03 ICP vortex GmbH 5 * Copyright (c) 2002-03 Intel Corporation 6 * Copyright (c) 2003 Adaptec Inc. 7 * All Rights Reserved 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions, and the following disclaimer, 14 * without modification, immediately at the beginning of the file. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 25 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 /* 35 * iir_ctrl.c: Control functions and /dev entry points for /dev/iir* 36 * 37 * Written by: Achim Leubner <[email protected]> 38 * Fixes/Additions: Boji Tony Kannanthanam <[email protected]> 39 * 40 * $Id: iir_ctrl.c 1.3 2003/08/26 12:31:15 achim Exp $" 41 */ 42 43 #include <sys/cdefs.h> 44 __FBSDID("$FreeBSD$"); 45 46 #include <sys/param.h> 47 #include <sys/systm.h> 48 #include <sys/bus.h> 49 #include <sys/endian.h> 50 #include <sys/malloc.h> 51 #include <sys/kernel.h> 52 #include <sys/uio.h> 53 #include <sys/conf.h> 54 #include <sys/disk.h> 55 #include <sys/stat.h> 56 #include <sys/disklabel.h> 57 #include <sys/sysctl.h> 58 #include <sys/sx.h> 59 #include <machine/bus.h> 60 61 #include <dev/iir/iir.h> 62 63 /* Entry points and other prototypes */ 64 static struct gdt_softc *gdt_minor2softc(struct cdev *dev, int minor_no); 65 66 static d_open_t iir_open; 67 static d_close_t iir_close; 68 static d_write_t iir_write; 69 static d_read_t iir_read; 70 static d_ioctl_t iir_ioctl; 71 72 /* Normally, this is a static structure. But we need it in pci/iir_pci.c */ 73 static struct cdevsw iir_cdevsw = { 74 .d_version = D_VERSION, 75 .d_open = iir_open, 76 .d_close = iir_close, 77 .d_read = iir_read, 78 .d_write = iir_write, 79 .d_ioctl = iir_ioctl, 80 .d_name = "iir", 81 }; 82 83 #ifndef SDEV_PER_HBA 84 static int sdev_made = 0; 85 static struct sx sdev_lock; 86 SX_SYSINIT(iir_sdev_lock, &sdev_lock, "iir sdev"); 87 #endif 88 extern int gdt_cnt; 89 extern gdt_statist_t gdt_stat; 90 91 /* 92 * Given a controller number, 93 * make a special device and return the dev_t 94 */ 95 struct cdev * 96 gdt_make_dev(struct gdt_softc *gdt) 97 { 98 struct cdev *dev; 99 100 #ifdef SDEV_PER_HBA 101 dev = make_dev(&iir_cdevsw, 0, UID_ROOT, GID_OPERATOR, 102 S_IRUSR | S_IWUSR, "iir%d", unit); 103 dev->si_drv1 = gdt; 104 #else 105 sx_xlock(&sdev_lock); 106 if (sdev_made) 107 return (NULL); 108 dev = make_dev(&iir_cdevsw, 0, UID_ROOT, GID_OPERATOR, 109 S_IRUSR | S_IWUSR, "iir"); 110 sdev_made = 1; 111 sx_xunlock(&sdev_lock); 112 #endif 113 return (dev); 114 } 115 116 void 117 gdt_destroy_dev(struct cdev *dev) 118 { 119 if (dev != NULL) 120 destroy_dev(dev); 121 } 122 123 /* 124 * Given a minor device number, 125 * return the pointer to its softc structure 126 */ 127 static struct gdt_softc * 128 gdt_minor2softc(struct cdev *dev, int minor_no) 129 { 130 #ifdef SDEV_PER_HBA 131 132 return (dev->si_drv1); 133 #else 134 devclass_t dc; 135 device_t child; 136 137 dc = devclass_find("iir"); 138 if (dc == NULL) 139 return (NULL); 140 child = devclass_get_device(dc, minor_no); 141 if (child == NULL) 142 return (NULL); 143 return (device_get_softc(child)); 144 #endif 145 } 146 147 static int 148 iir_open(struct cdev *dev, int flags, int fmt, struct thread * p) 149 { 150 GDT_DPRINTF(GDT_D_DEBUG, ("iir_open()\n")); 151 152 return (0); 153 } 154 155 static int 156 iir_close(struct cdev *dev, int flags, int fmt, struct thread * p) 157 { 158 GDT_DPRINTF(GDT_D_DEBUG, ("iir_close()\n")); 159 160 return (0); 161 } 162 163 static int 164 iir_write(struct cdev *dev, struct uio * uio, int ioflag) 165 { 166 GDT_DPRINTF(GDT_D_DEBUG, ("iir_write()\n")); 167 168 return (0); 169 } 170 171 static int 172 iir_read(struct cdev *dev, struct uio * uio, int ioflag) 173 { 174 GDT_DPRINTF(GDT_D_DEBUG, ("iir_read()\n")); 175 176 return (0); 177 } 178 179 /** 180 * This is the control syscall interface. 181 * It should be binary compatible with UnixWare, 182 * if not totally syntatically so. 183 */ 184 185 static int 186 iir_ioctl(struct cdev *dev, u_long cmd, caddr_t cmdarg, int flags, struct thread * p) 187 { 188 GDT_DPRINTF(GDT_D_DEBUG, ("iir_ioctl() cmd 0x%lx\n",cmd)); 189 190 ++gdt_stat.io_count_act; 191 if (gdt_stat.io_count_act > gdt_stat.io_count_max) 192 gdt_stat.io_count_max = gdt_stat.io_count_act; 193 194 switch (cmd) { 195 case GDT_IOCTL_GENERAL: 196 { 197 gdt_ucmd_t *ucmd; 198 struct gdt_softc *gdt; 199 200 ucmd = (gdt_ucmd_t *)cmdarg; 201 gdt = gdt_minor2softc(dev, ucmd->io_node); 202 if (gdt == NULL) 203 return (ENXIO); 204 mtx_lock(&gdt->sc_lock); 205 TAILQ_INSERT_TAIL(&gdt->sc_ucmd_queue, ucmd, links); 206 ucmd->complete_flag = FALSE; 207 gdt_next(gdt); 208 if (!ucmd->complete_flag) 209 (void) mtx_sleep(ucmd, &gdt->sc_lock, PCATCH | PRIBIO, "iirucw", 210 0); 211 mtx_unlock(&gdt->sc_lock); 212 break; 213 } 214 215 case GDT_IOCTL_DRVERS: 216 case GDT_IOCTL_DRVERS_OLD: 217 *(int *)cmdarg = 218 (IIR_DRIVER_VERSION << 8) | IIR_DRIVER_SUBVERSION; 219 break; 220 221 case GDT_IOCTL_CTRTYPE: 222 case GDT_IOCTL_CTRTYPE_OLD: 223 { 224 gdt_ctrt_t *p; 225 struct gdt_softc *gdt; 226 227 p = (gdt_ctrt_t *)cmdarg; 228 gdt = gdt_minor2softc(dev, p->io_node); 229 if (gdt == NULL) 230 return (ENXIO); 231 /* only RP controllers */ 232 p->ext_type = 0x6000 | gdt->sc_device; 233 if (gdt->sc_vendor == INTEL_VENDOR_ID_IIR) { 234 p->oem_id = OEM_ID_INTEL; 235 p->type = 0xfd; 236 /* new -> subdevice into ext_type */ 237 if (gdt->sc_device >= 0x600) 238 p->ext_type = 0x6000 | gdt->sc_subdevice; 239 } else { 240 p->oem_id = OEM_ID_ICP; 241 p->type = 0xfe; 242 /* new -> subdevice into ext_type */ 243 if (gdt->sc_device >= 0x300) 244 p->ext_type = 0x6000 | gdt->sc_subdevice; 245 } 246 p->info = (gdt->sc_bus << 8) | (gdt->sc_slot << 3); 247 p->device_id = gdt->sc_device; 248 p->sub_device_id = gdt->sc_subdevice; 249 break; 250 } 251 252 case GDT_IOCTL_OSVERS: 253 { 254 gdt_osv_t *p; 255 256 p = (gdt_osv_t *)cmdarg; 257 p->oscode = 10; 258 p->version = osreldate / 100000; 259 p->subversion = osreldate / 1000 % 100; 260 p->revision = 0; 261 strcpy(p->name, ostype); 262 break; 263 } 264 265 case GDT_IOCTL_CTRCNT: 266 *(int *)cmdarg = gdt_cnt; 267 break; 268 269 case GDT_IOCTL_EVENT: 270 { 271 gdt_event_t *p; 272 273 p = (gdt_event_t *)cmdarg; 274 if (p->erase == 0xff) { 275 if (p->dvr.event_source == GDT_ES_TEST) 276 p->dvr.event_data.size = sizeof(p->dvr.event_data.eu.test); 277 else if (p->dvr.event_source == GDT_ES_DRIVER) 278 p->dvr.event_data.size= sizeof(p->dvr.event_data.eu.driver); 279 else if (p->dvr.event_source == GDT_ES_SYNC) 280 p->dvr.event_data.size = sizeof(p->dvr.event_data.eu.sync); 281 else 282 p->dvr.event_data.size = sizeof(p->dvr.event_data.eu.async); 283 gdt_store_event(p->dvr.event_source, p->dvr.event_idx, 284 &p->dvr.event_data); 285 } else if (p->erase == 0xfe) { 286 gdt_clear_events(); 287 } else if (p->erase == 0) { 288 p->handle = gdt_read_event(p->handle, &p->dvr); 289 } else { 290 gdt_readapp_event((u_int8_t)p->erase, &p->dvr); 291 } 292 break; 293 } 294 295 case GDT_IOCTL_STATIST: 296 { 297 gdt_statist_t *p; 298 299 p = (gdt_statist_t *)cmdarg; 300 bcopy(&gdt_stat, p, sizeof(gdt_statist_t)); 301 break; 302 } 303 304 default: 305 break; 306 } 307 308 --gdt_stat.io_count_act; 309 return (0); 310 } 311