1139749Simp/*- 2120477Sscottl * Copyright (c) 2000-03 ICP vortex GmbH 3120477Sscottl * Copyright (c) 2002-03 Intel Corporation 4120477Sscottl * Copyright (c) 2003 Adaptec Inc. 589580Smsmith * All Rights Reserved 689580Smsmith * 789580Smsmith * Redistribution and use in source and binary forms, with or without 889580Smsmith * modification, are permitted provided that the following conditions 989580Smsmith * are met: 1089580Smsmith * 1. Redistributions of source code must retain the above copyright 1189580Smsmith * notice, this list of conditions, and the following disclaimer, 1289580Smsmith * without modification, immediately at the beginning of the file. 1389580Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1489580Smsmith * notice, this list of conditions and the following disclaimer in the 1589580Smsmith * documentation and/or other materials provided with the distribution. 1689580Smsmith * 3. The name of the author may not be used to endorse or promote products 1789580Smsmith * derived from this software without specific prior written permission. 1889580Smsmith * 1989580Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2089580Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2189580Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2289580Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2389580Smsmith * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2489580Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2589580Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2689580Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2789580Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2889580Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2989580Smsmith * SUCH DAMAGE. 3089580Smsmith */ 3189580Smsmith 3289580Smsmith/* 3389580Smsmith * iir_ctrl.c: Control functions and /dev entry points for /dev/iir* 3489580Smsmith * 35120477Sscottl * Written by: Achim Leubner <achim_leubner@adaptec.com> 3689580Smsmith * Fixes/Additions: Boji Tony Kannanthanam <boji.t.kannanthanam@intel.com> 3789580Smsmith * 38120477Sscottl * $Id: iir_ctrl.c 1.3 2003/08/26 12:31:15 achim Exp $" 3989580Smsmith */ 4089580Smsmith 41119418Sobrien#include <sys/cdefs.h> 42119418Sobrien__FBSDID("$FreeBSD$"); 4389580Smsmith 4489580Smsmith#include <sys/param.h> 4589580Smsmith#include <sys/systm.h> 4695533Smike#include <sys/endian.h> 4789580Smsmith#include <sys/malloc.h> 4889580Smsmith#include <sys/kernel.h> 4989580Smsmith#include <sys/uio.h> 5089580Smsmith#include <sys/conf.h> 51114001Sscottl#include <sys/disk.h> 5289580Smsmith#include <sys/stat.h> 53114001Sscottl#include <sys/disklabel.h> 54200045Smarcel#include <sys/sysctl.h> 5589580Smsmith#include <machine/bus.h> 5689580Smsmith 5789580Smsmith#include <dev/iir/iir.h> 5889580Smsmith 5989580Smsmith/* Entry points and other prototypes */ 6089580Smsmithstatic struct gdt_softc *gdt_minor2softc(int minor_no); 6189580Smsmith 6289580Smsmithstatic d_open_t iir_open; 6389580Smsmithstatic d_close_t iir_close; 6489580Smsmithstatic d_write_t iir_write; 6589580Smsmithstatic d_read_t iir_read; 6689580Smsmithstatic d_ioctl_t iir_ioctl; 6789580Smsmith 6889580Smsmith/* Normally, this is a static structure. But we need it in pci/iir_pci.c */ 6989580Smsmithstatic struct cdevsw iir_cdevsw = { 70126080Sphk .d_version = D_VERSION, 71126080Sphk .d_flags = D_NEEDGIANT, 72111815Sphk .d_open = iir_open, 73111815Sphk .d_close = iir_close, 74111815Sphk .d_read = iir_read, 75111815Sphk .d_write = iir_write, 76111815Sphk .d_ioctl = iir_ioctl, 77111815Sphk .d_name = "iir", 7889580Smsmith}; 7989580Smsmith 80114001Sscottl/* 81114001Sscottlstatic int iir_devsw_installed = 0; 82114001Sscottl*/ 8389580Smsmith#ifndef SDEV_PER_HBA 8489580Smsmithstatic int sdev_made = 0; 8589580Smsmith#endif 8689580Smsmithextern int gdt_cnt; 8789580Smsmithextern gdt_statist_t gdt_stat; 8889580Smsmith 8989580Smsmith/* 9089580Smsmith * Given a controller number, 9189580Smsmith * make a special device and return the dev_t 9289580Smsmith */ 93130585Sphkstruct cdev * 9489580Smsmithgdt_make_dev(int unit) 9589580Smsmith{ 96130585Sphk struct cdev *dev; 9789580Smsmith 9889580Smsmith#ifdef SDEV_PER_HBA 9989580Smsmith dev = make_dev(&iir_cdevsw, hba2minor(unit), UID_ROOT, GID_OPERATOR, 100145947Scperciva S_IRUSR | S_IWUSR, "iir%d", unit); 10189580Smsmith#else 10289580Smsmith if (sdev_made) 10389580Smsmith return (0); 10489580Smsmith dev = make_dev(&iir_cdevsw, 0, UID_ROOT, GID_OPERATOR, 105145947Scperciva S_IRUSR | S_IWUSR, "iir"); 10689580Smsmith sdev_made = 1; 10789580Smsmith#endif 10889580Smsmith return (dev); 10989580Smsmith} 11089580Smsmith 11189580Smsmithvoid 112130585Sphkgdt_destroy_dev(struct cdev *dev) 11389580Smsmith{ 11489580Smsmith if (dev != NULL) 11589580Smsmith destroy_dev(dev); 11689580Smsmith} 11789580Smsmith 11889580Smsmith/* 11989580Smsmith * Given a minor device number, 12089580Smsmith * return the pointer to its softc structure 12189580Smsmith */ 12289580Smsmithstatic struct gdt_softc * 12389580Smsmithgdt_minor2softc(int minor_no) 12489580Smsmith{ 12589580Smsmith struct gdt_softc *gdt; 12689580Smsmith int hanum; 12789580Smsmith 12889580Smsmith#ifdef SDEV_PER_HBA 12989580Smsmith hanum = minor2hba(minor_no); 13089580Smsmith#else 13189580Smsmith hanum = minor_no; 13289580Smsmith#endif 13389580Smsmith 13489580Smsmith for (gdt = TAILQ_FIRST(&gdt_softcs); 13589580Smsmith gdt != NULL && gdt->sc_hanum != hanum; 13689580Smsmith gdt = TAILQ_NEXT(gdt, links)); 13789580Smsmith 13889580Smsmith return (gdt); 13989580Smsmith} 14089580Smsmith 14189580Smsmithstatic int 142192450Simpiir_open(struct cdev *dev, int flags, int fmt, struct thread * p) 14389580Smsmith{ 14489580Smsmith GDT_DPRINTF(GDT_D_DEBUG, ("iir_open()\n")); 14589580Smsmith 14689580Smsmith#ifdef SDEV_PER_HBA 14789580Smsmith int minor_no; 14889580Smsmith struct gdt_softc *gdt; 14989580Smsmith 150183397Sed minor_no = dev2unit(dev); 15189580Smsmith gdt = gdt_minor2softc(minor_no); 15289580Smsmith if (gdt == NULL) 15389580Smsmith return (ENXIO); 15489580Smsmith#endif 15589580Smsmith 15689580Smsmith return (0); 15789580Smsmith} 15889580Smsmith 15989580Smsmithstatic int 160192450Simpiir_close(struct cdev *dev, int flags, int fmt, struct thread * p) 16189580Smsmith{ 16289580Smsmith GDT_DPRINTF(GDT_D_DEBUG, ("iir_close()\n")); 16389580Smsmith 16489580Smsmith#ifdef SDEV_PER_HBA 16589580Smsmith int minor_no; 16689580Smsmith struct gdt_softc *gdt; 16789580Smsmith 168183397Sed minor_no = dev2unit(dev); 16989580Smsmith gdt = gdt_minor2softc(minor_no); 17089580Smsmith if (gdt == NULL) 17189580Smsmith return (ENXIO); 17289580Smsmith#endif 17389580Smsmith 17489580Smsmith return (0); 17589580Smsmith} 17689580Smsmith 17789580Smsmithstatic int 178130585Sphkiir_write(struct cdev *dev, struct uio * uio, int ioflag) 17989580Smsmith{ 18089580Smsmith GDT_DPRINTF(GDT_D_DEBUG, ("iir_write()\n")); 18189580Smsmith 18289580Smsmith#ifdef SDEV_PER_HBA 18389580Smsmith int minor_no; 18489580Smsmith struct gdt_softc *gdt; 18589580Smsmith 186183397Sed minor_no = dev2unit(dev); 18789580Smsmith gdt = gdt_minor2softc(minor_no); 18889580Smsmith if (gdt == NULL) 18989580Smsmith return (ENXIO); 19089580Smsmith#endif 19189580Smsmith 19289580Smsmith return (0); 19389580Smsmith} 19489580Smsmith 19589580Smsmithstatic int 196130585Sphkiir_read(struct cdev *dev, struct uio * uio, int ioflag) 19789580Smsmith{ 19889580Smsmith GDT_DPRINTF(GDT_D_DEBUG, ("iir_read()\n")); 19989580Smsmith 20089580Smsmith#ifdef SDEV_PER_HBA 20189580Smsmith int minor_no; 20289580Smsmith struct gdt_softc *gdt; 20389580Smsmith 204183397Sed minor_no = dev2unit(dev); 20589580Smsmith gdt = gdt_minor2softc(minor_no); 20689580Smsmith if (gdt == NULL) 20789580Smsmith return (ENXIO); 20889580Smsmith#endif 20989580Smsmith 21089580Smsmith return (0); 21189580Smsmith} 21289580Smsmith 21389580Smsmith/** 21489580Smsmith * This is the control syscall interface. 21589580Smsmith * It should be binary compatible with UnixWare, 21689580Smsmith * if not totally syntatically so. 21789580Smsmith */ 21889580Smsmith 21989580Smsmithstatic int 220192450Simpiir_ioctl(struct cdev *dev, u_long cmd, caddr_t cmdarg, int flags, struct thread * p) 22189580Smsmith{ 22289580Smsmith GDT_DPRINTF(GDT_D_DEBUG, ("iir_ioctl() cmd 0x%lx\n",cmd)); 22389580Smsmith 22489580Smsmith#ifdef SDEV_PER_HBA 22589580Smsmith int minor_no; 22689580Smsmith struct gdt_softc *gdt; 22789580Smsmith 228183397Sed minor_no = dev2unit(dev); 22989580Smsmith gdt = gdt_minor2softc(minor_no); 23089580Smsmith if (gdt == NULL) 23189580Smsmith return (ENXIO); 23289580Smsmith#endif 23389580Smsmith ++gdt_stat.io_count_act; 23489580Smsmith if (gdt_stat.io_count_act > gdt_stat.io_count_max) 23589580Smsmith gdt_stat.io_count_max = gdt_stat.io_count_act; 23689580Smsmith 23789580Smsmith switch (cmd) { 23889580Smsmith case GDT_IOCTL_GENERAL: 23989580Smsmith { 24089580Smsmith gdt_ucmd_t *ucmd; 24189580Smsmith struct gdt_softc *gdt; 24289580Smsmith int lock; 24389580Smsmith 24489580Smsmith ucmd = (gdt_ucmd_t *)cmdarg; 24589580Smsmith gdt = gdt_minor2softc(ucmd->io_node); 24689580Smsmith if (gdt == NULL) 24789580Smsmith return (ENXIO); 24889580Smsmith lock = splcam(); 24989580Smsmith TAILQ_INSERT_TAIL(&gdt->sc_ucmd_queue, ucmd, links); 25089580Smsmith ucmd->complete_flag = FALSE; 25189580Smsmith splx(lock); 25289580Smsmith gdt_next(gdt); 25389580Smsmith if (!ucmd->complete_flag) 25489580Smsmith (void) tsleep((void *)ucmd, PCATCH | PRIBIO, "iirucw", 0); 25589580Smsmith break; 25689580Smsmith } 25789580Smsmith 25889580Smsmith case GDT_IOCTL_DRVERS: 259129449Sscottl case GDT_IOCTL_DRVERS_OLD: 26089580Smsmith *(int *)cmdarg = 26189580Smsmith (IIR_DRIVER_VERSION << 8) | IIR_DRIVER_SUBVERSION; 26289580Smsmith break; 26389580Smsmith 26489580Smsmith case GDT_IOCTL_CTRTYPE: 265129449Sscottl case GDT_IOCTL_CTRTYPE_OLD: 26689580Smsmith { 26789580Smsmith gdt_ctrt_t *p; 26889580Smsmith struct gdt_softc *gdt; 26989580Smsmith 27089580Smsmith p = (gdt_ctrt_t *)cmdarg; 27189580Smsmith gdt = gdt_minor2softc(p->io_node); 27289580Smsmith if (gdt == NULL) 27389580Smsmith return (ENXIO); 274120477Sscottl /* only RP controllers */ 275120477Sscottl p->ext_type = 0x6000 | gdt->sc_device; 276262751Sdumbbell if (gdt->sc_vendor == INTEL_VENDOR_ID_IIR) { 277120477Sscottl p->oem_id = OEM_ID_INTEL; 278120477Sscottl p->type = 0xfd; 279120477Sscottl /* new -> subdevice into ext_type */ 280120477Sscottl if (gdt->sc_device >= 0x600) 281120477Sscottl p->ext_type = 0x6000 | gdt->sc_subdevice; 282120477Sscottl } else { 283120477Sscottl p->oem_id = OEM_ID_ICP; 284120477Sscottl p->type = 0xfe; 285120477Sscottl /* new -> subdevice into ext_type */ 286120477Sscottl if (gdt->sc_device >= 0x300) 287120477Sscottl p->ext_type = 0x6000 | gdt->sc_subdevice; 288120477Sscottl } 28989580Smsmith p->info = (gdt->sc_bus << 8) | (gdt->sc_slot << 3); 29089580Smsmith p->device_id = gdt->sc_device; 29189580Smsmith p->sub_device_id = gdt->sc_subdevice; 29289580Smsmith break; 29389580Smsmith } 29489580Smsmith 29589580Smsmith case GDT_IOCTL_OSVERS: 29689580Smsmith { 29789580Smsmith gdt_osv_t *p; 29889580Smsmith 29989580Smsmith p = (gdt_osv_t *)cmdarg; 30089580Smsmith p->oscode = 10; 30189580Smsmith p->version = osrelease[0] - '0'; 30289580Smsmith if (osrelease[1] == '.') 30389580Smsmith p->subversion = osrelease[2] - '0'; 30489580Smsmith else 30589580Smsmith p->subversion = 0; 30689580Smsmith if (osrelease[3] == '.') 30789580Smsmith p->revision = osrelease[4] - '0'; 30889580Smsmith else 30989580Smsmith p->revision = 0; 31089580Smsmith strcpy(p->name, ostype); 31189580Smsmith break; 31289580Smsmith } 31389580Smsmith 31489580Smsmith case GDT_IOCTL_CTRCNT: 31589580Smsmith *(int *)cmdarg = gdt_cnt; 31689580Smsmith break; 31789580Smsmith 31889580Smsmith case GDT_IOCTL_EVENT: 31989580Smsmith { 32089580Smsmith gdt_event_t *p; 32189580Smsmith int lock; 32289580Smsmith 32389580Smsmith p = (gdt_event_t *)cmdarg; 32489580Smsmith if (p->erase == 0xff) { 32589580Smsmith if (p->dvr.event_source == GDT_ES_TEST) 32689580Smsmith p->dvr.event_data.size = sizeof(p->dvr.event_data.eu.test); 32789580Smsmith else if (p->dvr.event_source == GDT_ES_DRIVER) 32889580Smsmith p->dvr.event_data.size= sizeof(p->dvr.event_data.eu.driver); 32989580Smsmith else if (p->dvr.event_source == GDT_ES_SYNC) 33089580Smsmith p->dvr.event_data.size = sizeof(p->dvr.event_data.eu.sync); 33189580Smsmith else 33289580Smsmith p->dvr.event_data.size = sizeof(p->dvr.event_data.eu.async); 33389580Smsmith lock = splcam(); 33489580Smsmith gdt_store_event(p->dvr.event_source, p->dvr.event_idx, 33589580Smsmith &p->dvr.event_data); 33689580Smsmith splx(lock); 33789580Smsmith } else if (p->erase == 0xfe) { 33889580Smsmith lock = splcam(); 33989580Smsmith gdt_clear_events(); 34089580Smsmith splx(lock); 34189580Smsmith } else if (p->erase == 0) { 34289580Smsmith p->handle = gdt_read_event(p->handle, &p->dvr); 34389580Smsmith } else { 34489580Smsmith gdt_readapp_event((u_int8_t)p->erase, &p->dvr); 34589580Smsmith } 34689580Smsmith break; 34789580Smsmith } 34889580Smsmith 34989580Smsmith case GDT_IOCTL_STATIST: 35089580Smsmith { 35189580Smsmith gdt_statist_t *p; 35289580Smsmith 35389580Smsmith p = (gdt_statist_t *)cmdarg; 35489580Smsmith bcopy(&gdt_stat, p, sizeof(gdt_statist_t)); 35589580Smsmith break; 35689580Smsmith } 35789580Smsmith 35889580Smsmith default: 35989580Smsmith break; 36089580Smsmith } 36189580Smsmith 36289580Smsmith --gdt_stat.io_count_act; 36389580Smsmith return (0); 36489580Smsmith} 365114001Sscottl 366114001Sscottl/* 367114001Sscottlstatic void 368114001Sscottliir_drvinit(void *unused) 369114001Sscottl{ 370114001Sscottl GDT_DPRINTF(GDT_D_DEBUG, ("iir_drvinit()\n")); 371114001Sscottl 372114001Sscottl if (!iir_devsw_installed) { 373114001Sscottl cdevsw_add(&iir_cdevsw); 374114001Sscottl iir_devsw_installed = 1; 375114001Sscottl } 376114001Sscottl} 377114001Sscottl 378125834SscottlSYSINIT(iir_dev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, iir_drvinit, NULL) 379114001Sscottl*/ 380