iir_ctrl.c revision 119418
189580Smsmith/*
289580Smsmith *       Copyright (c) 2000-01 Intel Corporation
389580Smsmith *       All Rights Reserved
489580Smsmith *
589580Smsmith * Redistribution and use in source and binary forms, with or without
689580Smsmith * modification, are permitted provided that the following conditions
789580Smsmith * are met:
889580Smsmith * 1. Redistributions of source code must retain the above copyright
989580Smsmith *    notice, this list of conditions, and the following disclaimer,
1089580Smsmith *    without modification, immediately at the beginning of the file.
1189580Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1289580Smsmith *    notice, this list of conditions and the following disclaimer in the
1389580Smsmith *    documentation and/or other materials provided with the distribution.
1489580Smsmith * 3. The name of the author may not be used to endorse or promote products
1589580Smsmith *    derived from this software without specific prior written permission.
1689580Smsmith *
1789580Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1889580Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1989580Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2089580Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
2189580Smsmith * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2289580Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2389580Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2489580Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2589580Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2689580Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2789580Smsmith * SUCH DAMAGE.
2889580Smsmith */
2989580Smsmith
3089580Smsmith/*
3189580Smsmith * iir_ctrl.c: Control functions and /dev entry points for /dev/iir*
3289580Smsmith *
3389580Smsmith * Written by: Achim Leubner <achim.leubner@intel.com>
3489580Smsmith * Fixes/Additions: Boji Tony Kannanthanam <boji.t.kannanthanam@intel.com>
3589580Smsmith *
3689580Smsmith * TODO:
3789580Smsmith */
3889580Smsmith
3989580Smsmith#ident "$Id: iir_ctrl.c 1.2 2001/07/18 11:17:22 achim Exp $"
40119418Sobrien#include <sys/cdefs.h>
41119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/iir/iir_ctrl.c 119418 2003-08-24 17:55:58Z obrien $");
4289580Smsmith
4389580Smsmith#include <sys/param.h>
4489580Smsmith#include <sys/systm.h>
4595533Smike#include <sys/endian.h>
4689580Smsmith#include <sys/malloc.h>
4789580Smsmith#include <sys/kernel.h>
4889580Smsmith#include <sys/uio.h>
4989580Smsmith#include <sys/conf.h>
50114001Sscottl#include <sys/disk.h>
5189580Smsmith#include <sys/stat.h>
52114001Sscottl#include <sys/disklabel.h>
5389580Smsmith#include <machine/bus.h>
5489580Smsmith#include <vm/vm.h>
5589580Smsmith#include <vm/vm_kern.h>
5689580Smsmith#include <vm/vm_extern.h>
5789580Smsmith#include <vm/pmap.h>
5889580Smsmith
5989580Smsmith#include <dev/iir/iir.h>
6089580Smsmith
6189580Smsmith/* Entry points and other prototypes */
6289580Smsmithstatic struct gdt_softc *gdt_minor2softc(int minor_no);
6389580Smsmith
6489580Smsmithstatic d_open_t		iir_open;
6589580Smsmithstatic d_close_t	iir_close;
6689580Smsmithstatic d_write_t	iir_write;
6789580Smsmithstatic d_read_t		iir_read;
6889580Smsmithstatic d_ioctl_t	iir_ioctl;
6989580Smsmith
7089580Smsmith#define CDEV_MAJOR          IIR_CDEV_MAJOR
7189580Smsmith
7289580Smsmith/* Normally, this is a static structure.  But we need it in pci/iir_pci.c */
7389580Smsmithstatic struct cdevsw iir_cdevsw = {
74111815Sphk	.d_open =	iir_open,
75111815Sphk	.d_close =	iir_close,
76111815Sphk	.d_read =	iir_read,
77111815Sphk	.d_write =	iir_write,
78111815Sphk	.d_ioctl =	iir_ioctl,
79111815Sphk	.d_name =	"iir",
80111815Sphk	.d_maj =	CDEV_MAJOR,
8189580Smsmith};
8289580Smsmith
83114001Sscottl/*
84114001Sscottlstatic int iir_devsw_installed = 0;
85114001Sscottl*/
8689580Smsmith#ifndef SDEV_PER_HBA
8789580Smsmithstatic int sdev_made = 0;
8889580Smsmith#endif
8989580Smsmithextern int gdt_cnt;
9089580Smsmithextern char ostype[];
9189580Smsmithextern char osrelease[];
9289580Smsmithextern gdt_statist_t gdt_stat;
9389580Smsmith
9489580Smsmith/*
9589580Smsmith * Given a controller number,
9689580Smsmith * make a special device and return the dev_t
9789580Smsmith */
9889580Smsmithdev_t
9989580Smsmithgdt_make_dev(int unit)
10089580Smsmith{
10189580Smsmith    dev_t dev;
10289580Smsmith
10389580Smsmith#ifdef SDEV_PER_HBA
10489580Smsmith    dev = make_dev(&iir_cdevsw, hba2minor(unit), UID_ROOT, GID_OPERATOR,
105114001Sscottl                   S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, "iir%d", unit);
10689580Smsmith#else
10789580Smsmith    if (sdev_made)
10889580Smsmith        return (0);
10989580Smsmith    dev = make_dev(&iir_cdevsw, 0, UID_ROOT, GID_OPERATOR,
110114001Sscottl                   S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, "iir");
11189580Smsmith    sdev_made = 1;
11289580Smsmith#endif
11389580Smsmith    return (dev);
11489580Smsmith}
11589580Smsmith
11689580Smsmithvoid
11789580Smsmithgdt_destroy_dev(dev_t dev)
11889580Smsmith{
11989580Smsmith    if (dev != NULL)
12089580Smsmith        destroy_dev(dev);
12189580Smsmith}
12289580Smsmith
12389580Smsmith/*
12489580Smsmith * Given a minor device number,
12589580Smsmith * return the pointer to its softc structure
12689580Smsmith */
12789580Smsmithstatic struct gdt_softc *
12889580Smsmithgdt_minor2softc(int minor_no)
12989580Smsmith{
13089580Smsmith    struct gdt_softc *gdt;
13189580Smsmith    int hanum;
13289580Smsmith
13389580Smsmith#ifdef SDEV_PER_HBA
13489580Smsmith    hanum = minor2hba(minor_no);
13589580Smsmith#else
13689580Smsmith    hanum = minor_no;
13789580Smsmith#endif
13889580Smsmith
13989580Smsmith    for (gdt = TAILQ_FIRST(&gdt_softcs);
14089580Smsmith         gdt != NULL && gdt->sc_hanum != hanum;
14189580Smsmith         gdt = TAILQ_NEXT(gdt, links));
14289580Smsmith
14389580Smsmith    return (gdt);
14489580Smsmith}
14589580Smsmith
14689580Smsmithstatic int
14789580Smsmithiir_open(dev_t dev, int flags, int fmt, d_thread_t * p)
14889580Smsmith{
14989580Smsmith    GDT_DPRINTF(GDT_D_DEBUG, ("iir_open()\n"));
15089580Smsmith
15189580Smsmith#ifdef SDEV_PER_HBA
15289580Smsmith    int minor_no;
15389580Smsmith    struct gdt_softc *gdt;
15489580Smsmith
15589580Smsmith    minor_no = minor(dev);
15689580Smsmith    gdt = gdt_minor2softc(minor_no);
15789580Smsmith    if (gdt == NULL)
15889580Smsmith        return (ENXIO);
15989580Smsmith#endif
16089580Smsmith
16189580Smsmith    return (0);
16289580Smsmith}
16389580Smsmith
16489580Smsmithstatic int
16589580Smsmithiir_close(dev_t dev, int flags, int fmt, d_thread_t * p)
16689580Smsmith{
16789580Smsmith    GDT_DPRINTF(GDT_D_DEBUG, ("iir_close()\n"));
16889580Smsmith
16989580Smsmith#ifdef SDEV_PER_HBA
17089580Smsmith    int minor_no;
17189580Smsmith    struct gdt_softc *gdt;
17289580Smsmith
17389580Smsmith    minor_no = minor(dev);
17489580Smsmith    gdt = gdt_minor2softc(minor_no);
17589580Smsmith    if (gdt == NULL)
17689580Smsmith        return (ENXIO);
17789580Smsmith#endif
17889580Smsmith
17989580Smsmith    return (0);
18089580Smsmith}
18189580Smsmith
18289580Smsmithstatic int
18389580Smsmithiir_write(dev_t dev, struct uio * uio, int ioflag)
18489580Smsmith{
18589580Smsmith    GDT_DPRINTF(GDT_D_DEBUG, ("iir_write()\n"));
18689580Smsmith
18789580Smsmith#ifdef SDEV_PER_HBA
18889580Smsmith    int minor_no;
18989580Smsmith    struct gdt_softc *gdt;
19089580Smsmith
19189580Smsmith    minor_no = minor(dev);
19289580Smsmith    gdt = gdt_minor2softc(minor_no);
19389580Smsmith    if (gdt == NULL)
19489580Smsmith        return (ENXIO);
19589580Smsmith#endif
19689580Smsmith
19789580Smsmith    return (0);
19889580Smsmith}
19989580Smsmith
20089580Smsmithstatic int
20189580Smsmithiir_read(dev_t dev, struct uio * uio, int ioflag)
20289580Smsmith{
20389580Smsmith    GDT_DPRINTF(GDT_D_DEBUG, ("iir_read()\n"));
20489580Smsmith
20589580Smsmith#ifdef SDEV_PER_HBA
20689580Smsmith    int minor_no;
20789580Smsmith    struct gdt_softc *gdt;
20889580Smsmith
20989580Smsmith    minor_no = minor(dev);
21089580Smsmith    gdt = gdt_minor2softc(minor_no);
21189580Smsmith    if (gdt == NULL)
21289580Smsmith        return (ENXIO);
21389580Smsmith#endif
21489580Smsmith
21589580Smsmith    return (0);
21689580Smsmith}
21789580Smsmith
21889580Smsmith/**
21989580Smsmith * This is the control syscall interface.
22089580Smsmith * It should be binary compatible with UnixWare,
22189580Smsmith * if not totally syntatically so.
22289580Smsmith */
22389580Smsmith
22489580Smsmithstatic int
22589580Smsmithiir_ioctl(dev_t dev, u_long cmd, caddr_t cmdarg, int flags, d_thread_t * p)
22689580Smsmith{
22789580Smsmith    GDT_DPRINTF(GDT_D_DEBUG, ("iir_ioctl() cmd 0x%lx\n",cmd));
22889580Smsmith
22989580Smsmith#ifdef SDEV_PER_HBA
23089580Smsmith    int minor_no;
23189580Smsmith    struct gdt_softc *gdt;
23289580Smsmith
23389580Smsmith    minor_no = minor(dev);
23489580Smsmith    gdt = gdt_minor2softc(minor_no);
23589580Smsmith    if (gdt == NULL)
23689580Smsmith        return (ENXIO);
23789580Smsmith#endif
23889580Smsmith    ++gdt_stat.io_count_act;
23989580Smsmith    if (gdt_stat.io_count_act > gdt_stat.io_count_max)
24089580Smsmith        gdt_stat.io_count_max = gdt_stat.io_count_act;
24189580Smsmith
24289580Smsmith    switch (cmd) {
24389580Smsmith      case GDT_IOCTL_GENERAL:
24489580Smsmith        {
24589580Smsmith            gdt_ucmd_t *ucmd;
24689580Smsmith            struct gdt_softc *gdt;
24789580Smsmith            int lock;
24889580Smsmith
24989580Smsmith            ucmd = (gdt_ucmd_t *)cmdarg;
25089580Smsmith            gdt = gdt_minor2softc(ucmd->io_node);
25189580Smsmith            if (gdt == NULL)
25289580Smsmith                return (ENXIO);
25389580Smsmith            lock = splcam();
25489580Smsmith            TAILQ_INSERT_TAIL(&gdt->sc_ucmd_queue, ucmd, links);
25589580Smsmith            ucmd->complete_flag = FALSE;
25689580Smsmith            splx(lock);
25789580Smsmith            gdt_next(gdt);
25889580Smsmith            if (!ucmd->complete_flag)
25989580Smsmith                (void) tsleep((void *)ucmd, PCATCH | PRIBIO, "iirucw", 0);
26089580Smsmith            break;
26189580Smsmith        }
26289580Smsmith
26389580Smsmith      case GDT_IOCTL_DRVERS:
26489580Smsmith        *(int *)cmdarg =
26589580Smsmith            (IIR_DRIVER_VERSION << 8) | IIR_DRIVER_SUBVERSION;
26689580Smsmith        break;
26789580Smsmith
26889580Smsmith      case GDT_IOCTL_CTRTYPE:
26989580Smsmith        {
27089580Smsmith            gdt_ctrt_t *p;
27189580Smsmith            struct gdt_softc *gdt;
27289580Smsmith
27389580Smsmith            p = (gdt_ctrt_t *)cmdarg;
27489580Smsmith            gdt = gdt_minor2softc(p->io_node);
27589580Smsmith            if (gdt == NULL)
27689580Smsmith                return (ENXIO);
27789580Smsmith            p->oem_id = 0x8000;
27889580Smsmith            p->type = 0xfd;
27989580Smsmith            p->info = (gdt->sc_bus << 8) | (gdt->sc_slot << 3);
28089580Smsmith            p->ext_type = 0x6000 | gdt->sc_subdevice;
28189580Smsmith            p->device_id = gdt->sc_device;
28289580Smsmith            p->sub_device_id = gdt->sc_subdevice;
28389580Smsmith            break;
28489580Smsmith        }
28589580Smsmith
28689580Smsmith      case GDT_IOCTL_OSVERS:
28789580Smsmith        {
28889580Smsmith            gdt_osv_t *p;
28989580Smsmith
29089580Smsmith            p = (gdt_osv_t *)cmdarg;
29189580Smsmith            p->oscode = 10;
29289580Smsmith            p->version = osrelease[0] - '0';
29389580Smsmith            if (osrelease[1] == '.')
29489580Smsmith                p->subversion = osrelease[2] - '0';
29589580Smsmith            else
29689580Smsmith                p->subversion = 0;
29789580Smsmith            if (osrelease[3] == '.')
29889580Smsmith                p->revision = osrelease[4] - '0';
29989580Smsmith            else
30089580Smsmith                p->revision = 0;
30189580Smsmith            strcpy(p->name, ostype);
30289580Smsmith            break;
30389580Smsmith        }
30489580Smsmith
30589580Smsmith      case GDT_IOCTL_CTRCNT:
30689580Smsmith        *(int *)cmdarg = gdt_cnt;
30789580Smsmith        break;
30889580Smsmith
30989580Smsmith      case GDT_IOCTL_EVENT:
31089580Smsmith        {
31189580Smsmith            gdt_event_t *p;
31289580Smsmith            int lock;
31389580Smsmith
31489580Smsmith            p = (gdt_event_t *)cmdarg;
31589580Smsmith            if (p->erase == 0xff) {
31689580Smsmith                if (p->dvr.event_source == GDT_ES_TEST)
31789580Smsmith                    p->dvr.event_data.size = sizeof(p->dvr.event_data.eu.test);
31889580Smsmith                else if (p->dvr.event_source == GDT_ES_DRIVER)
31989580Smsmith                    p->dvr.event_data.size= sizeof(p->dvr.event_data.eu.driver);
32089580Smsmith                else if (p->dvr.event_source == GDT_ES_SYNC)
32189580Smsmith                    p->dvr.event_data.size = sizeof(p->dvr.event_data.eu.sync);
32289580Smsmith                else
32389580Smsmith                    p->dvr.event_data.size = sizeof(p->dvr.event_data.eu.async);
32489580Smsmith                lock = splcam();
32589580Smsmith                gdt_store_event(p->dvr.event_source, p->dvr.event_idx,
32689580Smsmith                                &p->dvr.event_data);
32789580Smsmith                splx(lock);
32889580Smsmith            } else if (p->erase == 0xfe) {
32989580Smsmith                lock = splcam();
33089580Smsmith                gdt_clear_events();
33189580Smsmith                splx(lock);
33289580Smsmith            } else if (p->erase == 0) {
33389580Smsmith                p->handle = gdt_read_event(p->handle, &p->dvr);
33489580Smsmith            } else {
33589580Smsmith                gdt_readapp_event((u_int8_t)p->erase, &p->dvr);
33689580Smsmith            }
33789580Smsmith            break;
33889580Smsmith        }
33989580Smsmith
34089580Smsmith      case GDT_IOCTL_STATIST:
34189580Smsmith        {
34289580Smsmith            gdt_statist_t *p;
34389580Smsmith
34489580Smsmith            p = (gdt_statist_t *)cmdarg;
34589580Smsmith            bcopy(&gdt_stat, p, sizeof(gdt_statist_t));
34689580Smsmith            break;
34789580Smsmith        }
34889580Smsmith
34989580Smsmith      default:
35089580Smsmith        break;
35189580Smsmith    }
35289580Smsmith
35389580Smsmith    --gdt_stat.io_count_act;
35489580Smsmith    return (0);
35589580Smsmith}
356114001Sscottl
357114001Sscottl/*
358114001Sscottlstatic void
359114001Sscottliir_drvinit(void *unused)
360114001Sscottl{
361114001Sscottl    GDT_DPRINTF(GDT_D_DEBUG, ("iir_drvinit()\n"));
362114001Sscottl
363114001Sscottl    if (!iir_devsw_installed) {
364114001Sscottl        cdevsw_add(&iir_cdevsw);
365114001Sscottl        iir_devsw_installed = 1;
366114001Sscottl    }
367114001Sscottl}
368114001Sscottl
369114001SscottlSYSINIT(iir_dev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE + CDEV_MAJOR, iir_drvinit, NULL)
370114001Sscottl*/
371