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