1 /* $FreeBSD: src/sys/dev/iir/iir_ctrl.c,v 1.17 2005/05/06 02:32:34 cperciva Exp $ */ 2 /*- 3 * Copyright (c) 2000-03 ICP vortex GmbH 4 * Copyright (c) 2002-03 Intel Corporation 5 * Copyright (c) 2003 Adaptec Inc. 6 * All Rights Reserved 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions, and the following disclaimer, 13 * without modification, immediately at the beginning of the file. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 24 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 /* 34 * iir_ctrl.c: Control functions and /dev entry points for /dev/iir* 35 * 36 * Written by: Achim Leubner <achim_leubner@adaptec.com> 37 * Fixes/Additions: Boji Tony Kannanthanam <boji.t.kannanthanam@intel.com> 38 * 39 * $Id: iir_ctrl.c 1.3 2003/08/26 12:31:15 achim Exp $" 40 */ 41 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/endian.h> 46 #include <sys/malloc.h> 47 #include <sys/kernel.h> 48 #include <sys/uio.h> 49 #include <sys/bus.h> 50 #include <sys/conf.h> 51 #include <sys/stat.h> 52 #include <sys/device.h> 53 #include <sys/thread2.h> 54 55 #include "pcidevs.h" 56 57 #include <vm/vm.h> 58 #include <vm/vm_kern.h> 59 #include <vm/vm_extern.h> 60 #include <vm/pmap.h> 61 62 #include "iir.h" 63 64 /* Entry points and other prototypes */ 65 static struct gdt_softc *gdt_minor2softc(int minor_no); 66 67 static d_open_t iir_open; 68 static d_close_t iir_close; 69 static d_write_t iir_write; 70 static d_read_t iir_read; 71 static d_ioctl_t iir_ioctl; 72 73 static struct dev_ops iir_ops = { 74 { "iir", 0, 0 }, 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 }; 81 82 #ifndef SDEV_PER_HBA 83 static int sdev_made = 0; 84 #endif 85 extern int gdt_cnt; 86 extern char ostype[]; 87 extern char osrelease[]; 88 extern gdt_statist_t gdt_stat; 89 90 /* 91 * Given a controller number, 92 * make a special device and return the cdev_t 93 */ 94 cdev_t 95 gdt_make_dev(int unit) 96 { 97 cdev_t dev; 98 99 #ifdef SDEV_PER_HBA 100 dev = make_dev(&iir_ops, hba2minor(unit), UID_ROOT, GID_OPERATOR, 101 S_IRUSR | S_IWUSR, "iir%d", unit); 102 #else 103 if (sdev_made) 104 return (0); 105 dev = make_dev(&iir_ops, 0, UID_ROOT, GID_OPERATOR, 106 S_IRUSR | S_IWUSR, "iir"); 107 sdev_made = 1; 108 #endif 109 reference_dev(dev); 110 return (dev); 111 } 112 113 void 114 gdt_destroy_dev(cdev_t dev) 115 { 116 if (dev != NULL) 117 destroy_dev(dev); 118 } 119 120 /* 121 * Given a minor device number, 122 * return the pointer to its softc structure 123 */ 124 static struct gdt_softc * 125 gdt_minor2softc(int minor_no) 126 { 127 struct gdt_softc *gdt; 128 int hanum; 129 130 #ifdef SDEV_PER_HBA 131 hanum = minor2hba(minor_no); 132 #else 133 hanum = minor_no; 134 #endif 135 136 for (gdt = TAILQ_FIRST(&gdt_softcs); 137 gdt != NULL && gdt->sc_hanum != hanum; 138 gdt = TAILQ_NEXT(gdt, links)); 139 140 return (gdt); 141 } 142 143 static int 144 iir_open(struct dev_open_args *ap) 145 { 146 GDT_DPRINTF(GDT_D_DEBUG, ("iir_open()\n")); 147 148 #ifdef SDEV_PER_HBA 149 int minor_no; 150 struct gdt_softc *gdt; 151 152 minor_no = minor(dev); 153 gdt = gdt_minor2softc(minor_no); 154 if (gdt == NULL) 155 return (ENXIO); 156 #endif 157 158 return (0); 159 } 160 161 static int 162 iir_close(struct dev_close_args *ap) 163 { 164 GDT_DPRINTF(GDT_D_DEBUG, ("iir_close()\n")); 165 166 #ifdef SDEV_PER_HBA 167 int minor_no; 168 struct gdt_softc *gdt; 169 170 minor_no = minor(dev); 171 gdt = gdt_minor2softc(minor_no); 172 if (gdt == NULL) 173 return (ENXIO); 174 #endif 175 176 return (0); 177 } 178 179 static int 180 iir_write(struct dev_write_args *ap) 181 { 182 GDT_DPRINTF(GDT_D_DEBUG, ("iir_write()\n")); 183 184 #ifdef SDEV_PER_HBA 185 int minor_no; 186 struct gdt_softc *gdt; 187 188 minor_no = minor(dev); 189 gdt = gdt_minor2softc(minor_no); 190 if (gdt == NULL) 191 return (ENXIO); 192 #endif 193 194 return (0); 195 } 196 197 static int 198 iir_read(struct dev_read_args *ap) 199 { 200 GDT_DPRINTF(GDT_D_DEBUG, ("iir_read()\n")); 201 202 #ifdef SDEV_PER_HBA 203 int minor_no; 204 struct gdt_softc *gdt; 205 206 minor_no = minor(dev); 207 gdt = gdt_minor2softc(minor_no); 208 if (gdt == NULL) 209 return (ENXIO); 210 #endif 211 212 return (0); 213 } 214 215 /** 216 * This is the control syscall interface. 217 * It should be binary compatible with UnixWare, 218 * if not totally syntatically so. 219 */ 220 221 static int 222 iir_ioctl(struct dev_ioctl_args *ap) 223 { 224 GDT_DPRINTF(GDT_D_DEBUG, ("iir_ioctl() cmd 0x%lx\n",cmd)); 225 226 #ifdef SDEV_PER_HBA 227 int minor_no; 228 struct gdt_softc *gdt; 229 230 minor_no = minor(dev); 231 gdt = gdt_minor2softc(minor_no); 232 if (gdt == NULL) 233 return (ENXIO); 234 #endif 235 ++gdt_stat.io_count_act; 236 if (gdt_stat.io_count_act > gdt_stat.io_count_max) 237 gdt_stat.io_count_max = gdt_stat.io_count_act; 238 239 switch (ap->a_cmd) { 240 case GDT_IOCTL_GENERAL: 241 { 242 gdt_ucmd_t *ucmd; 243 struct gdt_softc *gdt; 244 245 ucmd = (gdt_ucmd_t *)ap->a_data; 246 gdt = gdt_minor2softc(ucmd->io_node); 247 if (gdt == NULL) 248 return (ENXIO); 249 crit_enter(); 250 TAILQ_INSERT_TAIL(&gdt->sc_ucmd_queue, ucmd, links); 251 ucmd->complete_flag = FALSE; 252 crit_exit(); 253 gdt_next(gdt); 254 if (!ucmd->complete_flag) 255 (void) tsleep((void *)ucmd, PCATCH, "iirucw", 0); 256 break; 257 } 258 259 case GDT_IOCTL_DRVERS: 260 case GDT_IOCTL_DRVERS_OLD: 261 *(int *)ap->a_data = 262 (IIR_DRIVER_VERSION << 8) | IIR_DRIVER_SUBVERSION; 263 break; 264 265 case GDT_IOCTL_CTRTYPE: 266 case GDT_IOCTL_CTRTYPE_OLD: 267 { 268 gdt_ctrt_t *p; 269 struct gdt_softc *gdt; 270 271 p = (gdt_ctrt_t *)ap->a_data; 272 gdt = gdt_minor2softc(p->io_node); 273 if (gdt == NULL) 274 return (ENXIO); 275 /* only RP controllers */ 276 p->ext_type = 0x6000 | gdt->sc_device; 277 if (gdt->sc_vendor == PCI_VENDOR_INTEL) { 278 p->oem_id = OEM_ID_INTEL; 279 p->type = 0xfd; 280 /* new -> subdevice into ext_type */ 281 if (gdt->sc_device >= 0x600) 282 p->ext_type = 0x6000 | gdt->sc_subdevice; 283 } else { 284 p->oem_id = OEM_ID_ICP; 285 p->type = 0xfe; 286 /* new -> subdevice into ext_type */ 287 if (gdt->sc_device >= 0x300) 288 p->ext_type = 0x6000 | gdt->sc_subdevice; 289 } 290 p->info = (gdt->sc_bus << 8) | (gdt->sc_slot << 3); 291 p->device_id = gdt->sc_device; 292 p->sub_device_id = gdt->sc_subdevice; 293 break; 294 } 295 296 case GDT_IOCTL_OSVERS: 297 { 298 gdt_osv_t *p; 299 300 p = (gdt_osv_t *)ap->a_data; 301 p->oscode = 10; 302 p->version = osrelease[0] - '0'; 303 if (osrelease[1] == '.') 304 p->subversion = osrelease[2] - '0'; 305 else 306 p->subversion = 0; 307 if (osrelease[3] == '.') 308 p->revision = osrelease[4] - '0'; 309 else 310 p->revision = 0; 311 strcpy(p->name, ostype); 312 break; 313 } 314 315 case GDT_IOCTL_CTRCNT: 316 *(int *)ap->a_data = gdt_cnt; 317 break; 318 319 case GDT_IOCTL_EVENT: 320 { 321 gdt_event_t *p; 322 323 p = (gdt_event_t *)ap->a_data; 324 if (p->erase == 0xff) { 325 if (p->dvr.event_source == GDT_ES_TEST) 326 p->dvr.event_data.size = sizeof(p->dvr.event_data.eu.test); 327 else if (p->dvr.event_source == GDT_ES_DRIVER) 328 p->dvr.event_data.size= sizeof(p->dvr.event_data.eu.driver); 329 else if (p->dvr.event_source == GDT_ES_SYNC) 330 p->dvr.event_data.size = sizeof(p->dvr.event_data.eu.sync); 331 else 332 p->dvr.event_data.size = sizeof(p->dvr.event_data.eu.async); 333 crit_enter(); 334 gdt_store_event(p->dvr.event_source, p->dvr.event_idx, 335 &p->dvr.event_data); 336 crit_exit(); 337 } else if (p->erase == 0xfe) { 338 crit_enter(); 339 gdt_clear_events(); 340 crit_exit(); 341 } else if (p->erase == 0) { 342 p->handle = gdt_read_event(p->handle, &p->dvr); 343 } else { 344 gdt_readapp_event((u_int8_t)p->erase, &p->dvr); 345 } 346 break; 347 } 348 349 case GDT_IOCTL_STATIST: 350 { 351 gdt_statist_t *p; 352 353 p = (gdt_statist_t *)ap->a_data; 354 bcopy(&gdt_stat, p, sizeof(gdt_statist_t)); 355 break; 356 } 357 358 default: 359 break; 360 } 361 362 --gdt_stat.io_count_act; 363 return (0); 364 } 365 366