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/conf.h> 50 #include <sys/disk.h> 51 #include <sys/disklabel.h> 52 #include <sys/endian.h> 53 #include <sys/kernel.h> 54 #include <sys/lock.h> 55 #include <sys/malloc.h> 56 #include <sys/mutex.h> 57 #include <sys/stat.h> 58 #include <sys/sysctl.h> 59 #include <sys/sx.h> 60 #include <sys/uio.h> 61 #include <machine/bus.h> 62 63 #include <dev/iir/iir.h> 64 65 /* Entry points and other prototypes */ 66 static struct gdt_softc *gdt_minor2softc(struct cdev *dev, int minor_no); 67 68 static d_open_t iir_open; 69 static d_close_t iir_close; 70 static d_write_t iir_write; 71 static d_read_t iir_read; 72 static d_ioctl_t iir_ioctl; 73 74 /* Normally, this is a static structure. But we need it in pci/iir_pci.c */ 75 static struct cdevsw iir_cdevsw = { 76 .d_version = D_VERSION, 77 .d_open = iir_open, 78 .d_close = iir_close, 79 .d_read = iir_read, 80 .d_write = iir_write, 81 .d_ioctl = iir_ioctl, 82 .d_name = "iir", 83 }; 84 85 #ifndef SDEV_PER_HBA 86 static int sdev_made = 0; 87 static struct sx sdev_lock; 88 SX_SYSINIT(iir_sdev_lock, &sdev_lock, "iir sdev"); 89 #endif 90 extern int gdt_cnt; 91 extern gdt_statist_t gdt_stat; 92 93 /* 94 * Given a controller number, 95 * make a special device and return the dev_t 96 */ 97 struct cdev * 98 gdt_make_dev(struct gdt_softc *gdt) 99 { 100 struct cdev *dev; 101 102 #ifdef SDEV_PER_HBA 103 dev = make_dev(&iir_cdevsw, 0, UID_ROOT, GID_OPERATOR, 104 S_IRUSR | S_IWUSR, "iir%d", unit); 105 dev->si_drv1 = gdt; 106 #else 107 sx_xlock(&sdev_lock); 108 if (sdev_made) 109 return (NULL); 110 dev = make_dev(&iir_cdevsw, 0, UID_ROOT, GID_OPERATOR, 111 S_IRUSR | S_IWUSR, "iir"); 112 sdev_made = 1; 113 sx_xunlock(&sdev_lock); 114 #endif 115 return (dev); 116 } 117 118 void 119 gdt_destroy_dev(struct cdev *dev) 120 { 121 if (dev != NULL) 122 destroy_dev(dev); 123 } 124 125 /* 126 * Given a minor device number, 127 * return the pointer to its softc structure 128 */ 129 static struct gdt_softc * 130 gdt_minor2softc(struct cdev *dev, int minor_no) 131 { 132 #ifdef SDEV_PER_HBA 133 134 return (dev->si_drv1); 135 #else 136 devclass_t dc; 137 device_t child; 138 139 dc = devclass_find("iir"); 140 if (dc == NULL) 141 return (NULL); 142 child = devclass_get_device(dc, minor_no); 143 if (child == NULL) 144 return (NULL); 145 return (device_get_softc(child)); 146 #endif 147 } 148 149 static int 150 iir_open(struct cdev *dev, int flags, int fmt, struct thread * p) 151 { 152 GDT_DPRINTF(GDT_D_DEBUG, ("iir_open()\n")); 153 154 return (0); 155 } 156 157 static int 158 iir_close(struct cdev *dev, int flags, int fmt, struct thread * p) 159 { 160 GDT_DPRINTF(GDT_D_DEBUG, ("iir_close()\n")); 161 162 return (0); 163 } 164 165 static int 166 iir_write(struct cdev *dev, struct uio * uio, int ioflag) 167 { 168 GDT_DPRINTF(GDT_D_DEBUG, ("iir_write()\n")); 169 170 return (0); 171 } 172 173 static int 174 iir_read(struct cdev *dev, struct uio * uio, int ioflag) 175 { 176 GDT_DPRINTF(GDT_D_DEBUG, ("iir_read()\n")); 177 178 return (0); 179 } 180 181 /** 182 * This is the control syscall interface. 183 * It should be binary compatible with UnixWare, 184 * if not totally syntatically so. 185 */ 186 187 static int 188 iir_ioctl(struct cdev *dev, u_long cmd, caddr_t cmdarg, int flags, struct thread * p) 189 { 190 GDT_DPRINTF(GDT_D_DEBUG, ("iir_ioctl() cmd 0x%lx\n",cmd)); 191 192 ++gdt_stat.io_count_act; 193 if (gdt_stat.io_count_act > gdt_stat.io_count_max) 194 gdt_stat.io_count_max = gdt_stat.io_count_act; 195 196 switch (cmd) { 197 case GDT_IOCTL_GENERAL: 198 { 199 gdt_ucmd_t *ucmd; 200 struct gdt_softc *gdt; 201 202 ucmd = (gdt_ucmd_t *)cmdarg; 203 gdt = gdt_minor2softc(dev, ucmd->io_node); 204 if (gdt == NULL) 205 return (ENXIO); 206 mtx_lock(&gdt->sc_lock); 207 TAILQ_INSERT_TAIL(&gdt->sc_ucmd_queue, ucmd, links); 208 ucmd->complete_flag = FALSE; 209 gdt_next(gdt); 210 if (!ucmd->complete_flag) 211 (void) mtx_sleep(ucmd, &gdt->sc_lock, PCATCH | PRIBIO, "iirucw", 212 0); 213 mtx_unlock(&gdt->sc_lock); 214 break; 215 } 216 217 case GDT_IOCTL_DRVERS: 218 case GDT_IOCTL_DRVERS_OLD: 219 *(int *)cmdarg = 220 (IIR_DRIVER_VERSION << 8) | IIR_DRIVER_SUBVERSION; 221 break; 222 223 case GDT_IOCTL_CTRTYPE: 224 case GDT_IOCTL_CTRTYPE_OLD: 225 { 226 gdt_ctrt_t *p; 227 struct gdt_softc *gdt; 228 229 p = (gdt_ctrt_t *)cmdarg; 230 gdt = gdt_minor2softc(dev, p->io_node); 231 if (gdt == NULL) 232 return (ENXIO); 233 /* only RP controllers */ 234 p->ext_type = 0x6000 | gdt->sc_device; 235 if (gdt->sc_vendor == INTEL_VENDOR_ID_IIR) { 236 p->oem_id = OEM_ID_INTEL; 237 p->type = 0xfd; 238 /* new -> subdevice into ext_type */ 239 if (gdt->sc_device >= 0x600) 240 p->ext_type = 0x6000 | gdt->sc_subdevice; 241 } else { 242 p->oem_id = OEM_ID_ICP; 243 p->type = 0xfe; 244 /* new -> subdevice into ext_type */ 245 if (gdt->sc_device >= 0x300) 246 p->ext_type = 0x6000 | gdt->sc_subdevice; 247 } 248 p->info = (gdt->sc_bus << 8) | (gdt->sc_slot << 3); 249 p->device_id = gdt->sc_device; 250 p->sub_device_id = gdt->sc_subdevice; 251 break; 252 } 253 254 case GDT_IOCTL_OSVERS: 255 { 256 gdt_osv_t *p; 257 258 p = (gdt_osv_t *)cmdarg; 259 p->oscode = 10; 260 p->version = osreldate / 100000; 261 p->subversion = osreldate / 1000 % 100; 262 p->revision = 0; 263 strcpy(p->name, ostype); 264 break; 265 } 266 267 case GDT_IOCTL_CTRCNT: 268 *(int *)cmdarg = gdt_cnt; 269 break; 270 271 case GDT_IOCTL_EVENT: 272 { 273 gdt_event_t *p; 274 275 p = (gdt_event_t *)cmdarg; 276 if (p->erase == 0xff) { 277 if (p->dvr.event_source == GDT_ES_TEST) 278 p->dvr.event_data.size = sizeof(p->dvr.event_data.eu.test); 279 else if (p->dvr.event_source == GDT_ES_DRIVER) 280 p->dvr.event_data.size= sizeof(p->dvr.event_data.eu.driver); 281 else if (p->dvr.event_source == GDT_ES_SYNC) 282 p->dvr.event_data.size = sizeof(p->dvr.event_data.eu.sync); 283 else 284 p->dvr.event_data.size = sizeof(p->dvr.event_data.eu.async); 285 gdt_store_event(p->dvr.event_source, p->dvr.event_idx, 286 &p->dvr.event_data); 287 } else if (p->erase == 0xfe) { 288 gdt_clear_events(); 289 } else if (p->erase == 0) { 290 p->handle = gdt_read_event(p->handle, &p->dvr); 291 } else { 292 gdt_readapp_event((u_int8_t)p->erase, &p->dvr); 293 } 294 break; 295 } 296 297 case GDT_IOCTL_STATIST: 298 { 299 gdt_statist_t *p; 300 301 p = (gdt_statist_t *)cmdarg; 302 bcopy(&gdt_stat, p, sizeof(gdt_statist_t)); 303 break; 304 } 305 306 default: 307 break; 308 } 309 310 --gdt_stat.io_count_act; 311 return (0); 312 } 313