1 /* $FreeBSD: src/sys/dev/iir/iir_ctrl.c,v 1.17 2005/05/06 02:32:34 cperciva Exp $ */ 2 /* $DragonFly: src/sys/dev/raid/iir/iir_ctrl.c,v 1.13 2007/05/17 21:08:49 dillon Exp $ */ 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 <achim_leubner@adaptec.com> 38 * Fixes/Additions: Boji Tony Kannanthanam <boji.t.kannanthanam@intel.com> 39 * 40 * $Id: iir_ctrl.c 1.3 2003/08/26 12:31:15 achim Exp $" 41 */ 42 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/endian.h> 47 #include <sys/malloc.h> 48 #include <sys/kernel.h> 49 #include <sys/uio.h> 50 #include <sys/bus.h> 51 #include <sys/conf.h> 52 #include <sys/stat.h> 53 #include <sys/device.h> 54 #include <sys/thread2.h> 55 56 #include <vm/vm.h> 57 #include <vm/vm_kern.h> 58 #include <vm/vm_extern.h> 59 #include <vm/pmap.h> 60 61 #include "iir.h" 62 63 /* Entry points and other prototypes */ 64 static struct gdt_softc *gdt_minor2softc(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 #define CDEV_MAJOR IIR_CDEV_MAJOR 73 74 /* Normally, this is a static structure. But we need it in pci/iir_pci.c */ 75 static struct dev_ops iir_ops = { 76 { "iir", CDEV_MAJOR, 0 }, 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 }; 83 84 static int iir_devsw_installed = 0; 85 #ifndef SDEV_PER_HBA 86 static int sdev_made = 0; 87 #endif 88 extern int gdt_cnt; 89 extern char ostype[]; 90 extern char osrelease[]; 91 extern gdt_statist_t gdt_stat; 92 93 /* 94 * Given a controller number, 95 * make a special device and return the cdev_t 96 */ 97 cdev_t 98 gdt_make_dev(int unit) 99 { 100 cdev_t dev; 101 102 #ifdef SDEV_PER_HBA 103 dev = make_dev(&iir_ops, hba2minor(unit), UID_ROOT, GID_OPERATOR, 104 S_IRUSR | S_IWUSR, "iir%d", unit); 105 #else 106 if (sdev_made) 107 return (0); 108 dev = make_dev(&iir_ops, 0, UID_ROOT, GID_OPERATOR, 109 S_IRUSR | S_IWUSR, "iir"); 110 sdev_made = 1; 111 #endif 112 reference_dev(dev); 113 return (dev); 114 } 115 116 void 117 gdt_destroy_dev(cdev_t 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(int minor_no) 129 { 130 struct gdt_softc *gdt; 131 int hanum; 132 133 #ifdef SDEV_PER_HBA 134 hanum = minor2hba(minor_no); 135 #else 136 hanum = minor_no; 137 #endif 138 139 for (gdt = TAILQ_FIRST(&gdt_softcs); 140 gdt != NULL && gdt->sc_hanum != hanum; 141 gdt = TAILQ_NEXT(gdt, links)); 142 143 return (gdt); 144 } 145 146 static int 147 iir_open(struct dev_open_args *ap) 148 { 149 GDT_DPRINTF(GDT_D_DEBUG, ("iir_open()\n")); 150 151 #ifdef SDEV_PER_HBA 152 int minor_no; 153 struct gdt_softc *gdt; 154 155 minor_no = minor(dev); 156 gdt = gdt_minor2softc(minor_no); 157 if (gdt == NULL) 158 return (ENXIO); 159 #endif 160 161 return (0); 162 } 163 164 static int 165 iir_close(struct dev_close_args *ap) 166 { 167 GDT_DPRINTF(GDT_D_DEBUG, ("iir_close()\n")); 168 169 #ifdef SDEV_PER_HBA 170 int minor_no; 171 struct gdt_softc *gdt; 172 173 minor_no = minor(dev); 174 gdt = gdt_minor2softc(minor_no); 175 if (gdt == NULL) 176 return (ENXIO); 177 #endif 178 179 return (0); 180 } 181 182 static int 183 iir_write(struct dev_write_args *ap) 184 { 185 GDT_DPRINTF(GDT_D_DEBUG, ("iir_write()\n")); 186 187 #ifdef SDEV_PER_HBA 188 int minor_no; 189 struct gdt_softc *gdt; 190 191 minor_no = minor(dev); 192 gdt = gdt_minor2softc(minor_no); 193 if (gdt == NULL) 194 return (ENXIO); 195 #endif 196 197 return (0); 198 } 199 200 static int 201 iir_read(struct dev_read_args *ap) 202 { 203 GDT_DPRINTF(GDT_D_DEBUG, ("iir_read()\n")); 204 205 #ifdef SDEV_PER_HBA 206 int minor_no; 207 struct gdt_softc *gdt; 208 209 minor_no = minor(dev); 210 gdt = gdt_minor2softc(minor_no); 211 if (gdt == NULL) 212 return (ENXIO); 213 #endif 214 215 return (0); 216 } 217 218 /** 219 * This is the control syscall interface. 220 * It should be binary compatible with UnixWare, 221 * if not totally syntatically so. 222 */ 223 224 static int 225 iir_ioctl(struct dev_ioctl_args *ap) 226 { 227 GDT_DPRINTF(GDT_D_DEBUG, ("iir_ioctl() cmd 0x%lx\n",cmd)); 228 229 #ifdef SDEV_PER_HBA 230 int minor_no; 231 struct gdt_softc *gdt; 232 233 minor_no = minor(dev); 234 gdt = gdt_minor2softc(minor_no); 235 if (gdt == NULL) 236 return (ENXIO); 237 #endif 238 ++gdt_stat.io_count_act; 239 if (gdt_stat.io_count_act > gdt_stat.io_count_max) 240 gdt_stat.io_count_max = gdt_stat.io_count_act; 241 242 switch (ap->a_cmd) { 243 case GDT_IOCTL_GENERAL: 244 { 245 gdt_ucmd_t *ucmd; 246 struct gdt_softc *gdt; 247 248 ucmd = (gdt_ucmd_t *)ap->a_data; 249 gdt = gdt_minor2softc(ucmd->io_node); 250 if (gdt == NULL) 251 return (ENXIO); 252 crit_enter(); 253 TAILQ_INSERT_TAIL(&gdt->sc_ucmd_queue, ucmd, links); 254 ucmd->complete_flag = FALSE; 255 crit_exit(); 256 gdt_next(gdt); 257 if (!ucmd->complete_flag) 258 (void) tsleep((void *)ucmd, PCATCH, "iirucw", 0); 259 break; 260 } 261 262 case GDT_IOCTL_DRVERS: 263 case GDT_IOCTL_DRVERS_OLD: 264 *(int *)ap->a_data = 265 (IIR_DRIVER_VERSION << 8) | IIR_DRIVER_SUBVERSION; 266 break; 267 268 case GDT_IOCTL_CTRTYPE: 269 case GDT_IOCTL_CTRTYPE_OLD: 270 { 271 gdt_ctrt_t *p; 272 struct gdt_softc *gdt; 273 274 p = (gdt_ctrt_t *)ap->a_data; 275 gdt = gdt_minor2softc(p->io_node); 276 if (gdt == NULL) 277 return (ENXIO); 278 /* only RP controllers */ 279 p->ext_type = 0x6000 | gdt->sc_device; 280 if (gdt->sc_vendor == INTEL_VENDOR_ID) { 281 p->oem_id = OEM_ID_INTEL; 282 p->type = 0xfd; 283 /* new -> subdevice into ext_type */ 284 if (gdt->sc_device >= 0x600) 285 p->ext_type = 0x6000 | gdt->sc_subdevice; 286 } else { 287 p->oem_id = OEM_ID_ICP; 288 p->type = 0xfe; 289 /* new -> subdevice into ext_type */ 290 if (gdt->sc_device >= 0x300) 291 p->ext_type = 0x6000 | gdt->sc_subdevice; 292 } 293 p->info = (gdt->sc_bus << 8) | (gdt->sc_slot << 3); 294 p->device_id = gdt->sc_device; 295 p->sub_device_id = gdt->sc_subdevice; 296 break; 297 } 298 299 case GDT_IOCTL_OSVERS: 300 { 301 gdt_osv_t *p; 302 303 p = (gdt_osv_t *)ap->a_data; 304 p->oscode = 10; 305 p->version = osrelease[0] - '0'; 306 if (osrelease[1] == '.') 307 p->subversion = osrelease[2] - '0'; 308 else 309 p->subversion = 0; 310 if (osrelease[3] == '.') 311 p->revision = osrelease[4] - '0'; 312 else 313 p->revision = 0; 314 strcpy(p->name, ostype); 315 break; 316 } 317 318 case GDT_IOCTL_CTRCNT: 319 *(int *)ap->a_data = gdt_cnt; 320 break; 321 322 case GDT_IOCTL_EVENT: 323 { 324 gdt_event_t *p; 325 326 p = (gdt_event_t *)ap->a_data; 327 if (p->erase == 0xff) { 328 if (p->dvr.event_source == GDT_ES_TEST) 329 p->dvr.event_data.size = sizeof(p->dvr.event_data.eu.test); 330 else if (p->dvr.event_source == GDT_ES_DRIVER) 331 p->dvr.event_data.size= sizeof(p->dvr.event_data.eu.driver); 332 else if (p->dvr.event_source == GDT_ES_SYNC) 333 p->dvr.event_data.size = sizeof(p->dvr.event_data.eu.sync); 334 else 335 p->dvr.event_data.size = sizeof(p->dvr.event_data.eu.async); 336 crit_enter(); 337 gdt_store_event(p->dvr.event_source, p->dvr.event_idx, 338 &p->dvr.event_data); 339 crit_exit(); 340 } else if (p->erase == 0xfe) { 341 crit_enter(); 342 gdt_clear_events(); 343 crit_exit(); 344 } else if (p->erase == 0) { 345 p->handle = gdt_read_event(p->handle, &p->dvr); 346 } else { 347 gdt_readapp_event((u_int8_t)p->erase, &p->dvr); 348 } 349 break; 350 } 351 352 case GDT_IOCTL_STATIST: 353 { 354 gdt_statist_t *p; 355 356 p = (gdt_statist_t *)ap->a_data; 357 bcopy(&gdt_stat, p, sizeof(gdt_statist_t)); 358 break; 359 } 360 361 default: 362 break; 363 } 364 365 --gdt_stat.io_count_act; 366 return (0); 367 } 368 369 static void 370 iir_drvinit(void *unused) 371 { 372 GDT_DPRINTF(GDT_D_DEBUG, ("iir_drvinit()\n")); 373 374 if (!iir_devsw_installed) { 375 /* Add the I/O (data) channel */ 376 dev_ops_add(&iir_ops, 0, 0); 377 iir_devsw_installed = 1; 378 } 379 } 380 381 SYSINIT(iir_dev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE + CDEV_MAJOR, iir_drvinit, NULL) 382