1139749Simp/*-
2129449Sscottl *       Copyright (c) 2000-04 ICP vortex GmbH
3129449Sscottl *       Copyright (c) 2002-04 Intel Corporation
4129449Sscottl *       Copyright (c) 2003-04 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.c: SCSI dependant code for the Intel Integrated RAID Controller driver
3489580Smsmith *
35120477Sscottl * Written by: Achim Leubner <achim_leubner@adaptec.com>
3689580Smsmith * Fixes/Additions: Boji Tony Kannanthanam <boji.t.kannanthanam@intel.com>
3789580Smsmith *
3889580Smsmith * credits:     Niklas Hallqvist;       OpenBSD driver for the ICP Controllers.
3989580Smsmith *              Mike Smith;             Some driver source code.
4089580Smsmith *              FreeBSD.ORG;            Great O/S to work on and for.
4189580Smsmith *
42129449Sscottl * $Id: iir.c 1.5 2004/03/30 10:17:53 achim Exp $"
4389580Smsmith */
4489580Smsmith
45119418Sobrien#include <sys/cdefs.h>
46119418Sobrien__FBSDID("$FreeBSD: stable/10/sys/dev/iir/iir.c 315813 2017-03-23 06:41:13Z mav $");
4789580Smsmith
4889580Smsmith#define _IIR_C_
4989580Smsmith
5089580Smsmith/* #include "opt_iir.h" */
5189580Smsmith#include <sys/param.h>
5289580Smsmith#include <sys/systm.h>
5395533Smike#include <sys/endian.h>
5489580Smsmith#include <sys/eventhandler.h>
5589580Smsmith#include <sys/malloc.h>
5689580Smsmith#include <sys/kernel.h>
5789580Smsmith#include <sys/bus.h>
5889580Smsmith
5989580Smsmith#include <machine/bus.h>
6089580Smsmith#include <machine/stdarg.h>
6189580Smsmith
6289580Smsmith#include <cam/cam.h>
6389580Smsmith#include <cam/cam_ccb.h>
6489580Smsmith#include <cam/cam_sim.h>
6589580Smsmith#include <cam/cam_xpt_sim.h>
6689580Smsmith#include <cam/cam_debug.h>
6789580Smsmith#include <cam/scsi/scsi_all.h>
6889580Smsmith#include <cam/scsi/scsi_message.h>
6989580Smsmith
7089580Smsmith#include <dev/iir/iir.h>
7189580Smsmith
72227293Sedstatic MALLOC_DEFINE(M_GDTBUF, "iirbuf", "iir driver buffer");
73156139Sscottl
7489580Smsmith#ifdef GDT_DEBUG
7589580Smsmithint     gdt_debug = GDT_DEBUG;
7689580Smsmith#ifdef __SERIAL__
7789580Smsmith#define MAX_SERBUF 160
7889580Smsmithstatic void ser_init(void);
7989580Smsmithstatic void ser_puts(char *str);
8089580Smsmithstatic void ser_putc(int c);
8189580Smsmithstatic char strbuf[MAX_SERBUF+1];
8289580Smsmith#ifdef __COM2__
8389580Smsmith#define COM_BASE 0x2f8
8489580Smsmith#else
8589580Smsmith#define COM_BASE 0x3f8
8689580Smsmith#endif
8789580Smsmithstatic void ser_init()
8889580Smsmith{
8989580Smsmith    unsigned port=COM_BASE;
9089580Smsmith
9189580Smsmith    outb(port+3, 0x80);
9289580Smsmith    outb(port+1, 0);
9389580Smsmith    /* 19200 Baud, if 9600: outb(12,port) */
9489580Smsmith    outb(port, 6);
9589580Smsmith    outb(port+3, 3);
9689580Smsmith    outb(port+1, 0);
9789580Smsmith}
9889580Smsmith
9989580Smsmithstatic void ser_puts(char *str)
10089580Smsmith{
10189580Smsmith    char *ptr;
10289580Smsmith
10389580Smsmith    ser_init();
10489580Smsmith    for (ptr=str;*ptr;++ptr)
10589580Smsmith        ser_putc((int)(*ptr));
10689580Smsmith}
10789580Smsmith
10889580Smsmithstatic void ser_putc(int c)
10989580Smsmith{
11089580Smsmith    unsigned port=COM_BASE;
11189580Smsmith
11289580Smsmith    while ((inb(port+5) & 0x20)==0);
11389580Smsmith    outb(port, c);
11489580Smsmith    if (c==0x0a)
11589580Smsmith    {
11689580Smsmith        while ((inb(port+5) & 0x20)==0);
11789580Smsmith        outb(port, 0x0d);
11889580Smsmith    }
11989580Smsmith}
12089580Smsmith
12189580Smsmithint ser_printf(const char *fmt, ...)
12289580Smsmith{
12389580Smsmith    va_list args;
12489580Smsmith    int i;
12589580Smsmith
12689580Smsmith    va_start(args,fmt);
12789580Smsmith    i = vsprintf(strbuf,fmt,args);
12889580Smsmith    ser_puts(strbuf);
12989580Smsmith    va_end(args);
13089580Smsmith    return i;
13189580Smsmith}
13289580Smsmith#endif
13389580Smsmith#endif
13489580Smsmith
13589580Smsmith/* controller cnt. */
13689580Smsmithint gdt_cnt = 0;
13789580Smsmith/* event buffer */
13889580Smsmithstatic gdt_evt_str ebuffer[GDT_MAX_EVENTS];
13989580Smsmithstatic int elastidx, eoldidx;
140275975Ssmhstatic struct mtx elock;
141275975SsmhMTX_SYSINIT(iir_elock, &elock, "iir events", MTX_DEF);
14289580Smsmith/* statistics */
14389580Smsmithgdt_statist_t gdt_stat;
14489580Smsmith
14589580Smsmith/* Definitions for our use of the SIM private CCB area */
14689580Smsmith#define ccb_sim_ptr     spriv_ptr0
14789580Smsmith#define ccb_priority    spriv_field1
14889580Smsmith
14989580Smsmithstatic void     iir_action(struct cam_sim *sim, union ccb *ccb);
150275975Ssmhstatic int	iir_intr_locked(struct gdt_softc *gdt);
15189580Smsmithstatic void     iir_poll(struct cam_sim *sim);
15289580Smsmithstatic void     iir_shutdown(void *arg, int howto);
15389580Smsmithstatic void     iir_timeout(void *arg);
15489580Smsmith
15589580Smsmithstatic void     gdt_eval_mapping(u_int32_t size, int *cyls, int *heads,
15689580Smsmith                                 int *secs);
15789580Smsmithstatic int      gdt_internal_cmd(struct gdt_softc *gdt, struct gdt_ccb *gccb,
15889580Smsmith                                 u_int8_t service, u_int16_t opcode,
15989580Smsmith                                 u_int32_t arg1, u_int32_t arg2, u_int32_t arg3);
16089580Smsmithstatic int      gdt_wait(struct gdt_softc *gdt, struct gdt_ccb *ccb,
16189580Smsmith                         int timeout);
16289580Smsmith
16389580Smsmithstatic struct gdt_ccb *gdt_get_ccb(struct gdt_softc *gdt);
16489580Smsmith
16589580Smsmithstatic int      gdt_sync_event(struct gdt_softc *gdt, int service,
16689580Smsmith                               u_int8_t index, struct gdt_ccb *gccb);
16789580Smsmithstatic int      gdt_async_event(struct gdt_softc *gdt, int service);
16889580Smsmithstatic struct gdt_ccb *gdt_raw_cmd(struct gdt_softc *gdt,
169275975Ssmh                                   union ccb *ccb);
17089580Smsmithstatic struct gdt_ccb *gdt_cache_cmd(struct gdt_softc *gdt,
171275975Ssmh                                     union ccb *ccb);
17289580Smsmithstatic struct gdt_ccb *gdt_ioctl_cmd(struct gdt_softc *gdt,
173275975Ssmh                                     gdt_ucmd_t *ucmd);
174275975Ssmhstatic void     gdt_internal_cache_cmd(struct gdt_softc *gdt, union ccb *ccb);
17589580Smsmith
17689580Smsmithstatic void     gdtmapmem(void *arg, bus_dma_segment_t *dm_segs,
17789580Smsmith                          int nseg, int error);
17889580Smsmithstatic void     gdtexecuteccb(void *arg, bus_dma_segment_t *dm_segs,
17989580Smsmith                              int nseg, int error);
18089580Smsmith
18189580Smsmithint
18289580Smsmithiir_init(struct gdt_softc *gdt)
18389580Smsmith{
18489580Smsmith    u_int16_t cdev_cnt;
18589580Smsmith    int i, id, drv_cyls, drv_hds, drv_secs;
18689580Smsmith    struct gdt_ccb *gccb;
18789580Smsmith
18889580Smsmith    GDT_DPRINTF(GDT_D_DEBUG, ("iir_init()\n"));
18989580Smsmith
19089580Smsmith    gdt->sc_state = GDT_POLLING;
19189580Smsmith    gdt_clear_events();
19289580Smsmith    bzero(&gdt_stat, sizeof(gdt_statist_t));
19389580Smsmith
19489580Smsmith    SLIST_INIT(&gdt->sc_free_gccb);
19589580Smsmith    SLIST_INIT(&gdt->sc_pending_gccb);
19689580Smsmith    TAILQ_INIT(&gdt->sc_ccb_queue);
19789580Smsmith    TAILQ_INIT(&gdt->sc_ucmd_queue);
19889580Smsmith
19989580Smsmith    /* DMA tag for mapping buffers into device visible space. */
20089580Smsmith    if (bus_dma_tag_create(gdt->sc_parent_dmat, /*alignment*/1, /*boundary*/0,
201114001Sscottl                           /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
20289580Smsmith                           /*highaddr*/BUS_SPACE_MAXADDR,
20389580Smsmith                           /*filter*/NULL, /*filterarg*/NULL,
204281826Smav			   /*maxsize*/DFLTPHYS,
205281826Smav			   /*nsegments*/GDT_MAXSG,
20689580Smsmith                           /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
20789580Smsmith                           /*flags*/BUS_DMA_ALLOCNOW,
208275975Ssmh			   /*lockfunc*/busdma_lock_mutex,
209275975Ssmh			   /*lockarg*/&gdt->sc_lock,
21089580Smsmith                           &gdt->sc_buffer_dmat) != 0) {
211275975Ssmh	device_printf(gdt->sc_devnode,
212275975Ssmh	    "bus_dma_tag_create(..., gdt->sc_buffer_dmat) failed\n");
21389580Smsmith        return (1);
21489580Smsmith    }
21589580Smsmith    gdt->sc_init_level++;
21689580Smsmith
21789580Smsmith    /* DMA tag for our ccb structures */
218114001Sscottl    if (bus_dma_tag_create(gdt->sc_parent_dmat,
219114001Sscottl			   /*alignment*/1,
220114001Sscottl			   /*boundary*/0,
221114001Sscottl                           /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
22289580Smsmith                           /*highaddr*/BUS_SPACE_MAXADDR,
223114001Sscottl                           /*filter*/NULL,
224114001Sscottl			   /*filterarg*/NULL,
225156139Sscottl                           GDT_MAXCMDS * GDT_SCRATCH_SZ, /* maxsize */
22689580Smsmith                           /*nsegments*/1,
22789580Smsmith                           /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
228117126Sscottl			   /*flags*/0, /*lockfunc*/busdma_lock_mutex,
229275975Ssmh			   /*lockarg*/&gdt->sc_lock,
230275975Ssmh			   &gdt->sc_gcscratch_dmat) != 0) {
231275975Ssmh        device_printf(gdt->sc_devnode,
232275975Ssmh	    "bus_dma_tag_create(...,gdt->sc_gcscratch_dmat) failed\n");
23389580Smsmith        return (1);
23489580Smsmith    }
23589580Smsmith    gdt->sc_init_level++;
23689580Smsmith
237156139Sscottl    /* Allocation for our ccb scratch area */
238156139Sscottl    if (bus_dmamem_alloc(gdt->sc_gcscratch_dmat, (void **)&gdt->sc_gcscratch,
239156139Sscottl                         BUS_DMA_NOWAIT, &gdt->sc_gcscratch_dmamap) != 0) {
240275975Ssmh        device_printf(gdt->sc_devnode,
241275975Ssmh	    "bus_dmamem_alloc(...,&gdt->sc_gccbs,...) failed\n");
24289580Smsmith        return (1);
24389580Smsmith    }
24489580Smsmith    gdt->sc_init_level++;
24589580Smsmith
24689580Smsmith    /* And permanently map them */
247156139Sscottl    bus_dmamap_load(gdt->sc_gcscratch_dmat, gdt->sc_gcscratch_dmamap,
248156139Sscottl                    gdt->sc_gcscratch, GDT_MAXCMDS * GDT_SCRATCH_SZ,
249156139Sscottl                    gdtmapmem, &gdt->sc_gcscratch_busbase, /*flags*/0);
25089580Smsmith    gdt->sc_init_level++;
25189580Smsmith
25289580Smsmith    /* Clear them out. */
253156139Sscottl    bzero(gdt->sc_gcscratch, GDT_MAXCMDS * GDT_SCRATCH_SZ);
25489580Smsmith
25589580Smsmith    /* Initialize the ccbs */
256156139Sscottl    gdt->sc_gccbs = malloc(sizeof(struct gdt_ccb) * GDT_MAXCMDS, M_GDTBUF,
257156139Sscottl        M_NOWAIT | M_ZERO);
258156139Sscottl    if (gdt->sc_gccbs == NULL) {
259275975Ssmh        device_printf(gdt->sc_devnode, "no memory for gccbs.\n");
260156139Sscottl        return (1);
261156139Sscottl    }
26289580Smsmith    for (i = GDT_MAXCMDS-1; i >= 0; i--) {
263156139Sscottl        gccb = &gdt->sc_gccbs[i];
264156139Sscottl        gccb->gc_cmd_index = i + 2;
265156139Sscottl        gccb->gc_flags = GDT_GCF_UNUSED;
266156139Sscottl        gccb->gc_map_flag = FALSE;
26789580Smsmith        if (bus_dmamap_create(gdt->sc_buffer_dmat, /*flags*/0,
268156139Sscottl                              &gccb->gc_dmamap) != 0)
26989580Smsmith            return(1);
270156139Sscottl        gccb->gc_map_flag = TRUE;
271275982Ssmh        gccb->gc_scratch = &gdt->sc_gcscratch[GDT_SCRATCH_SZ * i];
272156139Sscottl        gccb->gc_scratch_busbase = gdt->sc_gcscratch_busbase + GDT_SCRATCH_SZ * i;
273275975Ssmh	callout_init_mtx(&gccb->gc_timeout, &gdt->sc_lock, 0);
274156139Sscottl        SLIST_INSERT_HEAD(&gdt->sc_free_gccb, gccb, sle);
27589580Smsmith    }
27689580Smsmith    gdt->sc_init_level++;
27789580Smsmith
27889580Smsmith    /* create the control device */
279275975Ssmh    gdt->sc_dev = gdt_make_dev(gdt);
28089580Smsmith
28189580Smsmith    /* allocate ccb for gdt_internal_cmd() */
282275975Ssmh    mtx_lock(&gdt->sc_lock);
28389580Smsmith    gccb = gdt_get_ccb(gdt);
28489580Smsmith    if (gccb == NULL) {
285275975Ssmh	mtx_unlock(&gdt->sc_lock);
286275975Ssmh        device_printf(gdt->sc_devnode, "No free command index found\n");
28789580Smsmith        return (1);
28889580Smsmith    }
289156139Sscottl    bzero(gccb->gc_cmd, GDT_CMD_SZ);
29089580Smsmith
29189580Smsmith    if (!gdt_internal_cmd(gdt, gccb, GDT_SCREENSERVICE, GDT_INIT,
29289580Smsmith                          0, 0, 0)) {
293275975Ssmh        device_printf(gdt->sc_devnode,
294275975Ssmh	    "Screen service initialization error %d\n", gdt->sc_status);
29589580Smsmith        gdt_free_ccb(gdt, gccb);
296275975Ssmh	mtx_unlock(&gdt->sc_lock);
29789580Smsmith        return (1);
29889580Smsmith    }
29989580Smsmith
30089580Smsmith    gdt_internal_cmd(gdt, gccb, GDT_CACHESERVICE, GDT_UNFREEZE_IO,
30189580Smsmith                     0, 0, 0);
30289580Smsmith
30389580Smsmith    if (!gdt_internal_cmd(gdt, gccb, GDT_CACHESERVICE, GDT_INIT,
30489580Smsmith                          GDT_LINUX_OS, 0, 0)) {
305275975Ssmh        device_printf(gdt->sc_devnode, "Cache service initialization error %d\n",
306275975Ssmh               gdt->sc_status);
30789580Smsmith        gdt_free_ccb(gdt, gccb);
308275975Ssmh	mtx_unlock(&gdt->sc_lock);
30989580Smsmith        return (1);
31089580Smsmith    }
31189580Smsmith    cdev_cnt = (u_int16_t)gdt->sc_info;
31289580Smsmith    gdt->sc_fw_vers = gdt->sc_service;
31389580Smsmith
31489580Smsmith    /* Detect number of buses */
31589580Smsmith    gdt_enc32(gccb->gc_scratch + GDT_IOC_VERSION, GDT_IOC_NEWEST);
31689580Smsmith    gccb->gc_scratch[GDT_IOC_LIST_ENTRIES] = GDT_MAXBUS;
31789580Smsmith    gccb->gc_scratch[GDT_IOC_FIRST_CHAN] = 0;
31889580Smsmith    gccb->gc_scratch[GDT_IOC_LAST_CHAN] = GDT_MAXBUS - 1;
31989580Smsmith    gdt_enc32(gccb->gc_scratch + GDT_IOC_LIST_OFFSET, GDT_IOC_HDR_SZ);
32089580Smsmith    if (gdt_internal_cmd(gdt, gccb, GDT_CACHESERVICE, GDT_IOCTL,
32189580Smsmith                         GDT_IOCHAN_RAW_DESC, GDT_INVALID_CHANNEL,
32289580Smsmith                         GDT_IOC_HDR_SZ + GDT_MAXBUS * GDT_RAWIOC_SZ)) {
32389580Smsmith        gdt->sc_bus_cnt = gccb->gc_scratch[GDT_IOC_CHAN_COUNT];
32489580Smsmith        for (i = 0; i < gdt->sc_bus_cnt; i++) {
32589580Smsmith            id = gccb->gc_scratch[GDT_IOC_HDR_SZ +
32689580Smsmith                                 i * GDT_RAWIOC_SZ + GDT_RAWIOC_PROC_ID];
32789580Smsmith            gdt->sc_bus_id[i] = id < GDT_MAXID_FC ? id : 0xff;
32889580Smsmith        }
32989580Smsmith    } else {
33089580Smsmith        /* New method failed, use fallback. */
33189580Smsmith        for (i = 0; i < GDT_MAXBUS; i++) {
33289580Smsmith            gdt_enc32(gccb->gc_scratch + GDT_GETCH_CHANNEL_NO, i);
33389580Smsmith            if (!gdt_internal_cmd(gdt, gccb, GDT_CACHESERVICE, GDT_IOCTL,
33489580Smsmith                                  GDT_SCSI_CHAN_CNT | GDT_L_CTRL_PATTERN,
33589580Smsmith                                  GDT_IO_CHANNEL | GDT_INVALID_CHANNEL,
33689580Smsmith                                  GDT_GETCH_SZ)) {
33789580Smsmith                if (i == 0) {
338275975Ssmh                    device_printf(gdt->sc_devnode, "Cannot get channel count, "
339275975Ssmh                           "error %d\n", gdt->sc_status);
34089580Smsmith                    gdt_free_ccb(gdt, gccb);
341275975Ssmh		    mtx_unlock(&gdt->sc_lock);
34289580Smsmith                    return (1);
34389580Smsmith                }
34489580Smsmith                break;
34589580Smsmith            }
34689580Smsmith            gdt->sc_bus_id[i] =
34789580Smsmith                (gccb->gc_scratch[GDT_GETCH_SIOP_ID] < GDT_MAXID_FC) ?
34889580Smsmith                gccb->gc_scratch[GDT_GETCH_SIOP_ID] : 0xff;
34989580Smsmith        }
35089580Smsmith        gdt->sc_bus_cnt = i;
35189580Smsmith    }
35289580Smsmith    /* add one "virtual" channel for the host drives */
35389580Smsmith    gdt->sc_virt_bus = gdt->sc_bus_cnt;
35489580Smsmith    gdt->sc_bus_cnt++;
35589580Smsmith
35689580Smsmith    if (!gdt_internal_cmd(gdt, gccb, GDT_SCSIRAWSERVICE, GDT_INIT,
35789580Smsmith                          0, 0, 0)) {
358275975Ssmh            device_printf(gdt->sc_devnode,
359275975Ssmh		"Raw service initialization error %d\n", gdt->sc_status);
36089580Smsmith            gdt_free_ccb(gdt, gccb);
361275975Ssmh	    mtx_unlock(&gdt->sc_lock);
36289580Smsmith            return (1);
36389580Smsmith    }
36489580Smsmith
36589580Smsmith    /* Set/get features raw service (scatter/gather) */
36689580Smsmith    gdt->sc_raw_feat = 0;
36789580Smsmith    if (gdt_internal_cmd(gdt, gccb, GDT_SCSIRAWSERVICE, GDT_SET_FEAT,
36889580Smsmith                         GDT_SCATTER_GATHER, 0, 0)) {
36989580Smsmith        if (gdt_internal_cmd(gdt, gccb, GDT_SCSIRAWSERVICE, GDT_GET_FEAT,
37089580Smsmith                             0, 0, 0)) {
37189580Smsmith            gdt->sc_raw_feat = gdt->sc_info;
37289580Smsmith            if (!(gdt->sc_info & GDT_SCATTER_GATHER)) {
373275975Ssmh                panic("%s: Scatter/Gather Raw Service "
374275975Ssmh		    "required but not supported!\n",
375275975Ssmh		    device_get_nameunit(gdt->sc_devnode));
37689580Smsmith                gdt_free_ccb(gdt, gccb);
377275975Ssmh		mtx_unlock(&gdt->sc_lock);
37889580Smsmith                return (1);
37989580Smsmith            }
38089580Smsmith        }
38189580Smsmith    }
38289580Smsmith
38389580Smsmith    /* Set/get features cache service (scatter/gather) */
38489580Smsmith    gdt->sc_cache_feat = 0;
38589580Smsmith    if (gdt_internal_cmd(gdt, gccb, GDT_CACHESERVICE, GDT_SET_FEAT,
38689580Smsmith                         0, GDT_SCATTER_GATHER, 0)) {
38789580Smsmith        if (gdt_internal_cmd(gdt, gccb, GDT_CACHESERVICE, GDT_GET_FEAT,
38889580Smsmith                             0, 0, 0)) {
38989580Smsmith            gdt->sc_cache_feat = gdt->sc_info;
39089580Smsmith            if (!(gdt->sc_info & GDT_SCATTER_GATHER)) {
391275975Ssmh                panic("%s: Scatter/Gather Cache Service "
392275975Ssmh		    "required but not supported!\n",
393275975Ssmh		    device_get_nameunit(gdt->sc_devnode));
39489580Smsmith                gdt_free_ccb(gdt, gccb);
395275975Ssmh		mtx_unlock(&gdt->sc_lock);
39689580Smsmith                return (1);
39789580Smsmith            }
39889580Smsmith        }
39989580Smsmith    }
40089580Smsmith
401114001Sscottl    /* OEM */
402114001Sscottl    gdt_enc32(gccb->gc_scratch + GDT_OEM_VERSION, 0x01);
403114001Sscottl    gdt_enc32(gccb->gc_scratch + GDT_OEM_BUFSIZE, sizeof(gdt_oem_record_t));
404114001Sscottl    if (gdt_internal_cmd(gdt, gccb, GDT_CACHESERVICE, GDT_IOCTL,
405114001Sscottl                         GDT_OEM_STR_RECORD, GDT_INVALID_CHANNEL,
406114001Sscottl                         sizeof(gdt_oem_str_record_t))) {
407114001Sscottl	    strncpy(gdt->oem_name, ((gdt_oem_str_record_t *)
408114001Sscottl            gccb->gc_scratch)->text.scsi_host_drive_inquiry_vendor_id, 7);
409114001Sscottl		gdt->oem_name[7]='\0';
410114001Sscottl	} else {
411114001Sscottl		/* Old method, based on PCI ID */
412254379Sjkim		if (gdt->sc_vendor == INTEL_VENDOR_ID_IIR)
413114001Sscottl            strcpy(gdt->oem_name,"Intel  ");
414114001Sscottl        else
415114001Sscottl       	    strcpy(gdt->oem_name,"ICP    ");
416114001Sscottl    }
417114001Sscottl
41889580Smsmith    /* Scan for cache devices */
41989580Smsmith    for (i = 0; i < cdev_cnt && i < GDT_MAX_HDRIVES; i++) {
42089580Smsmith        if (gdt_internal_cmd(gdt, gccb, GDT_CACHESERVICE, GDT_INFO,
42189580Smsmith                             i, 0, 0)) {
42289580Smsmith            gdt->sc_hdr[i].hd_present = 1;
42389580Smsmith            gdt->sc_hdr[i].hd_size = gdt->sc_info;
42489580Smsmith
42589580Smsmith            /*
42689580Smsmith             * Evaluate mapping (sectors per head, heads per cyl)
42789580Smsmith             */
42889580Smsmith            gdt->sc_hdr[i].hd_size &= ~GDT_SECS32;
42989580Smsmith            if (gdt->sc_info2 == 0)
43089580Smsmith                gdt_eval_mapping(gdt->sc_hdr[i].hd_size,
43189580Smsmith                                 &drv_cyls, &drv_hds, &drv_secs);
43289580Smsmith            else {
43389580Smsmith                drv_hds = gdt->sc_info2 & 0xff;
43489580Smsmith                drv_secs = (gdt->sc_info2 >> 8) & 0xff;
43589580Smsmith                drv_cyls = gdt->sc_hdr[i].hd_size / drv_hds /
43689580Smsmith                    drv_secs;
43789580Smsmith            }
43889580Smsmith            gdt->sc_hdr[i].hd_heads = drv_hds;
43989580Smsmith            gdt->sc_hdr[i].hd_secs = drv_secs;
44089580Smsmith            /* Round the size */
44189580Smsmith            gdt->sc_hdr[i].hd_size = drv_cyls * drv_hds * drv_secs;
44289580Smsmith
44389580Smsmith            if (gdt_internal_cmd(gdt, gccb, GDT_CACHESERVICE,
44489580Smsmith                                 GDT_DEVTYPE, i, 0, 0))
44589580Smsmith                gdt->sc_hdr[i].hd_devtype = gdt->sc_info;
44689580Smsmith        }
44789580Smsmith    }
44889580Smsmith
44989580Smsmith    GDT_DPRINTF(GDT_D_INIT, ("dpmem %x %d-bus %d cache device%s\n",
45089580Smsmith                             gdt->sc_dpmembase,
45189580Smsmith                             gdt->sc_bus_cnt, cdev_cnt,
45289580Smsmith                             cdev_cnt == 1 ? "" : "s"));
45389580Smsmith    gdt_free_ccb(gdt, gccb);
454275975Ssmh    mtx_unlock(&gdt->sc_lock);
45589580Smsmith
456275975Ssmh    atomic_add_int(&gdt_cnt, 1);
45789580Smsmith    return (0);
45889580Smsmith}
45989580Smsmith
46089580Smsmithvoid
46189580Smsmithiir_free(struct gdt_softc *gdt)
46289580Smsmith{
46389580Smsmith    int i;
46489580Smsmith
46589580Smsmith    GDT_DPRINTF(GDT_D_INIT, ("iir_free()\n"));
46689580Smsmith
46789580Smsmith    switch (gdt->sc_init_level) {
46889580Smsmith      default:
46989580Smsmith        gdt_destroy_dev(gdt->sc_dev);
47089580Smsmith      case 5:
47189580Smsmith        for (i = GDT_MAXCMDS-1; i >= 0; i--)
472275975Ssmh            if (gdt->sc_gccbs[i].gc_map_flag) {
473275975Ssmh		callout_drain(&gdt->sc_gccbs[i].gc_timeout);
47489580Smsmith                bus_dmamap_destroy(gdt->sc_buffer_dmat,
47589580Smsmith                                   gdt->sc_gccbs[i].gc_dmamap);
476275975Ssmh	    }
477156139Sscottl        bus_dmamap_unload(gdt->sc_gcscratch_dmat, gdt->sc_gcscratch_dmamap);
478156139Sscottl        free(gdt->sc_gccbs, M_GDTBUF);
47989580Smsmith      case 4:
480156139Sscottl        bus_dmamem_free(gdt->sc_gcscratch_dmat, gdt->sc_gcscratch, gdt->sc_gcscratch_dmamap);
48189580Smsmith      case 3:
482156139Sscottl        bus_dma_tag_destroy(gdt->sc_gcscratch_dmat);
48389580Smsmith      case 2:
48489580Smsmith        bus_dma_tag_destroy(gdt->sc_buffer_dmat);
48589580Smsmith      case 1:
48689580Smsmith        bus_dma_tag_destroy(gdt->sc_parent_dmat);
48789580Smsmith      case 0:
48889580Smsmith        break;
48989580Smsmith    }
49089580Smsmith}
49189580Smsmith
49289580Smsmithvoid
49389580Smsmithiir_attach(struct gdt_softc *gdt)
49489580Smsmith{
49589580Smsmith    struct cam_devq *devq;
49689580Smsmith    int i;
49789580Smsmith
49889580Smsmith    GDT_DPRINTF(GDT_D_INIT, ("iir_attach()\n"));
49989580Smsmith
50089580Smsmith    /*
50189580Smsmith     * Create the device queue for our SIM.
502156139Sscottl     * XXX Throttle this down since the card has problems under load.
50389580Smsmith     */
504156139Sscottl    devq = cam_simq_alloc(32);
50589580Smsmith    if (devq == NULL)
50689580Smsmith        return;
50789580Smsmith
50889580Smsmith    for (i = 0; i < gdt->sc_bus_cnt; i++) {
50989580Smsmith        /*
51089580Smsmith         * Construct our SIM entry
51189580Smsmith         */
51289580Smsmith        gdt->sims[i] = cam_sim_alloc(iir_action, iir_poll, "iir",
513275975Ssmh	    gdt, device_get_unit(gdt->sc_devnode), &gdt->sc_lock,
514275975Ssmh	    /*untagged*/1, /*tagged*/GDT_MAXCMDS, devq);
515275975Ssmh	mtx_lock(&gdt->sc_lock);
516170872Sscottl        if (xpt_bus_register(gdt->sims[i], gdt->sc_devnode, i) != CAM_SUCCESS) {
51789580Smsmith            cam_sim_free(gdt->sims[i], /*free_devq*/i == 0);
518275975Ssmh	    mtx_unlock(&gdt->sc_lock);
51989580Smsmith            break;
52089580Smsmith        }
52189580Smsmith
52289580Smsmith        if (xpt_create_path(&gdt->paths[i], /*periph*/NULL,
52389580Smsmith                            cam_sim_path(gdt->sims[i]),
52489580Smsmith                            CAM_TARGET_WILDCARD,
52589580Smsmith                            CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
52689580Smsmith            xpt_bus_deregister(cam_sim_path(gdt->sims[i]));
52789580Smsmith            cam_sim_free(gdt->sims[i], /*free_devq*/i == 0);
528275975Ssmh	    mtx_unlock(&gdt->sc_lock);
52989580Smsmith            break;
53089580Smsmith        }
531275975Ssmh	mtx_unlock(&gdt->sc_lock);
53289580Smsmith    }
53389580Smsmith    if (i > 0)
53489580Smsmith        EVENTHANDLER_REGISTER(shutdown_final, iir_shutdown,
53589580Smsmith                              gdt, SHUTDOWN_PRI_DEFAULT);
53689580Smsmith    /* iir_watchdog(gdt); */
53789580Smsmith    gdt->sc_state = GDT_NORMAL;
53889580Smsmith}
53989580Smsmith
54089580Smsmithstatic void
54189580Smsmithgdt_eval_mapping(u_int32_t size, int *cyls, int *heads, int *secs)
54289580Smsmith{
54389580Smsmith    *cyls = size / GDT_HEADS / GDT_SECS;
54489580Smsmith    if (*cyls < GDT_MAXCYLS) {
54589580Smsmith        *heads = GDT_HEADS;
54689580Smsmith        *secs = GDT_SECS;
54789580Smsmith    } else {
54889580Smsmith        /* Too high for 64 * 32 */
54989580Smsmith        *cyls = size / GDT_MEDHEADS / GDT_MEDSECS;
55089580Smsmith        if (*cyls < GDT_MAXCYLS) {
55189580Smsmith            *heads = GDT_MEDHEADS;
55289580Smsmith            *secs = GDT_MEDSECS;
55389580Smsmith        } else {
55489580Smsmith            /* Too high for 127 * 63 */
55589580Smsmith            *cyls = size / GDT_BIGHEADS / GDT_BIGSECS;
55689580Smsmith            *heads = GDT_BIGHEADS;
55789580Smsmith            *secs = GDT_BIGSECS;
55889580Smsmith        }
55989580Smsmith    }
56089580Smsmith}
56189580Smsmith
56289580Smsmithstatic int
56389580Smsmithgdt_wait(struct gdt_softc *gdt, struct gdt_ccb *gccb,
56489580Smsmith         int timeout)
56589580Smsmith{
56689580Smsmith    int rv = 0;
56789580Smsmith
56889580Smsmith    GDT_DPRINTF(GDT_D_INIT,
56989580Smsmith                ("gdt_wait(%p, %p, %d)\n", gdt, gccb, timeout));
57089580Smsmith
57189580Smsmith    gdt->sc_state |= GDT_POLL_WAIT;
57289580Smsmith    do {
573275975Ssmh        if (iir_intr_locked(gdt) == gccb->gc_cmd_index) {
57489580Smsmith            rv = 1;
57589580Smsmith            break;
57689580Smsmith        }
57789580Smsmith        DELAY(1);
57889580Smsmith    } while (--timeout);
57989580Smsmith    gdt->sc_state &= ~GDT_POLL_WAIT;
58089580Smsmith
58189580Smsmith    while (gdt->sc_test_busy(gdt))
58289580Smsmith        DELAY(1);               /* XXX correct? */
58389580Smsmith
58489580Smsmith    return (rv);
58589580Smsmith}
58689580Smsmith
58789580Smsmithstatic int
58889580Smsmithgdt_internal_cmd(struct gdt_softc *gdt, struct gdt_ccb *gccb,
58989580Smsmith                 u_int8_t service, u_int16_t opcode,
59089580Smsmith                 u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
59189580Smsmith{
59289580Smsmith    int retries;
59389580Smsmith
59489580Smsmith    GDT_DPRINTF(GDT_D_CMD, ("gdt_internal_cmd(%p, %d, %d, %d, %d, %d)\n",
59589580Smsmith                            gdt, service, opcode, arg1, arg2, arg3));
59689580Smsmith
597156139Sscottl    bzero(gccb->gc_cmd, GDT_CMD_SZ);
59889580Smsmith
59989580Smsmith    for (retries = GDT_RETRIES; ; ) {
60089580Smsmith        gccb->gc_service = service;
60189580Smsmith        gccb->gc_flags = GDT_GCF_INTERNAL;
60289580Smsmith
603156139Sscottl        gdt_enc32(gccb->gc_cmd + GDT_CMD_COMMANDINDEX,
60489580Smsmith                  gccb->gc_cmd_index);
605156139Sscottl        gdt_enc16(gccb->gc_cmd + GDT_CMD_OPCODE, opcode);
60689580Smsmith
60789580Smsmith        switch (service) {
60889580Smsmith          case GDT_CACHESERVICE:
60989580Smsmith            if (opcode == GDT_IOCTL) {
610156139Sscottl                gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION +
61189580Smsmith                          GDT_IOCTL_SUBFUNC, arg1);
612156139Sscottl                gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION +
61389580Smsmith                          GDT_IOCTL_CHANNEL, arg2);
614156139Sscottl                gdt_enc16(gccb->gc_cmd + GDT_CMD_UNION +
61589580Smsmith                          GDT_IOCTL_PARAM_SIZE, (u_int16_t)arg3);
616156139Sscottl                gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_IOCTL_P_PARAM,
617156139Sscottl                          gccb->gc_scratch_busbase);
61889580Smsmith            } else {
619156139Sscottl                gdt_enc16(gccb->gc_cmd + GDT_CMD_UNION +
62089580Smsmith                          GDT_CACHE_DEVICENO, (u_int16_t)arg1);
621156139Sscottl                gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION +
62289580Smsmith                          GDT_CACHE_BLOCKNO, arg2);
62389580Smsmith            }
62489580Smsmith            break;
62589580Smsmith
62689580Smsmith          case GDT_SCSIRAWSERVICE:
627156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION +
62889580Smsmith                      GDT_RAW_DIRECTION, arg1);
629156139Sscottl            gccb->gc_cmd[GDT_CMD_UNION + GDT_RAW_BUS] =
63089580Smsmith                (u_int8_t)arg2;
631156139Sscottl            gccb->gc_cmd[GDT_CMD_UNION + GDT_RAW_TARGET] =
63289580Smsmith                (u_int8_t)arg3;
633156139Sscottl            gccb->gc_cmd[GDT_CMD_UNION + GDT_RAW_LUN] =
63489580Smsmith                (u_int8_t)(arg3 >> 8);
63589580Smsmith        }
63689580Smsmith
637156139Sscottl        gdt->sc_set_sema0(gdt);
638156139Sscottl        gccb->gc_cmd_len = GDT_CMD_SZ;
63989580Smsmith        gdt->sc_cmd_off = 0;
64089580Smsmith        gdt->sc_cmd_cnt = 0;
64189580Smsmith        gdt->sc_copy_cmd(gdt, gccb);
64289580Smsmith        gdt->sc_release_event(gdt);
64389580Smsmith        DELAY(20);
64489580Smsmith        if (!gdt_wait(gdt, gccb, GDT_POLL_TIMEOUT))
64589580Smsmith            return (0);
64689580Smsmith        if (gdt->sc_status != GDT_S_BSY || --retries == 0)
64789580Smsmith            break;
64889580Smsmith        DELAY(1);
64989580Smsmith    }
65089580Smsmith    return (gdt->sc_status == GDT_S_OK);
65189580Smsmith}
65289580Smsmith
65389580Smsmithstatic struct gdt_ccb *
65489580Smsmithgdt_get_ccb(struct gdt_softc *gdt)
65589580Smsmith{
65689580Smsmith    struct gdt_ccb *gccb;
65789580Smsmith
65889580Smsmith    GDT_DPRINTF(GDT_D_QUEUE, ("gdt_get_ccb(%p)\n", gdt));
65989580Smsmith
660275975Ssmh    mtx_assert(&gdt->sc_lock, MA_OWNED);
66189580Smsmith    gccb = SLIST_FIRST(&gdt->sc_free_gccb);
66289580Smsmith    if (gccb != NULL) {
66389580Smsmith        SLIST_REMOVE_HEAD(&gdt->sc_free_gccb, sle);
66489580Smsmith        SLIST_INSERT_HEAD(&gdt->sc_pending_gccb, gccb, sle);
66589580Smsmith        ++gdt_stat.cmd_index_act;
66689580Smsmith        if (gdt_stat.cmd_index_act > gdt_stat.cmd_index_max)
66789580Smsmith            gdt_stat.cmd_index_max = gdt_stat.cmd_index_act;
66889580Smsmith    }
66989580Smsmith    return (gccb);
67089580Smsmith}
67189580Smsmith
67289580Smsmithvoid
67389580Smsmithgdt_free_ccb(struct gdt_softc *gdt, struct gdt_ccb *gccb)
67489580Smsmith{
67589580Smsmith
67689580Smsmith    GDT_DPRINTF(GDT_D_QUEUE, ("gdt_free_ccb(%p, %p)\n", gdt, gccb));
677275975Ssmh
678275975Ssmh    mtx_assert(&gdt->sc_lock, MA_OWNED);
67989580Smsmith    gccb->gc_flags = GDT_GCF_UNUSED;
68089580Smsmith    SLIST_REMOVE(&gdt->sc_pending_gccb, gccb, gdt_ccb, sle);
68189580Smsmith    SLIST_INSERT_HEAD(&gdt->sc_free_gccb, gccb, sle);
68289580Smsmith    --gdt_stat.cmd_index_act;
68389580Smsmith    if (gdt->sc_state & GDT_SHUTDOWN)
68489580Smsmith        wakeup(gccb);
68589580Smsmith}
68689580Smsmith
68789580Smsmithvoid
68889580Smsmithgdt_next(struct gdt_softc *gdt)
68989580Smsmith{
69089580Smsmith    union ccb *ccb;
69189580Smsmith    gdt_ucmd_t *ucmd;
69289580Smsmith    struct cam_sim *sim;
69389580Smsmith    int bus, target, lun;
69489580Smsmith    int next_cmd;
69589580Smsmith
69689580Smsmith    struct ccb_scsiio *csio;
69789580Smsmith    struct ccb_hdr *ccbh;
69889580Smsmith    struct gdt_ccb *gccb = NULL;
69989580Smsmith    u_int8_t cmd;
70089580Smsmith
70189580Smsmith    GDT_DPRINTF(GDT_D_QUEUE, ("gdt_next(%p)\n", gdt));
70289580Smsmith
703275975Ssmh    mtx_assert(&gdt->sc_lock, MA_OWNED);
70489580Smsmith    if (gdt->sc_test_busy(gdt)) {
70589580Smsmith        if (!(gdt->sc_state & GDT_POLLING)) {
70689580Smsmith            return;
70789580Smsmith        }
70889580Smsmith        while (gdt->sc_test_busy(gdt))
70989580Smsmith            DELAY(1);
71089580Smsmith    }
71189580Smsmith
71289580Smsmith    gdt->sc_cmd_cnt = gdt->sc_cmd_off = 0;
71389580Smsmith    next_cmd = TRUE;
71489580Smsmith    for (;;) {
71589580Smsmith        /* I/Os in queue? controller ready? */
71689580Smsmith        if (!TAILQ_FIRST(&gdt->sc_ucmd_queue) &&
71789580Smsmith            !TAILQ_FIRST(&gdt->sc_ccb_queue))
71889580Smsmith            break;
71989580Smsmith
72089580Smsmith        /* 1.: I/Os without ccb (IOCTLs) */
72189580Smsmith        ucmd = TAILQ_FIRST(&gdt->sc_ucmd_queue);
72289580Smsmith        if (ucmd != NULL) {
72389580Smsmith            TAILQ_REMOVE(&gdt->sc_ucmd_queue, ucmd, links);
724275975Ssmh            if ((gccb = gdt_ioctl_cmd(gdt, ucmd)) == NULL) {
72589580Smsmith                TAILQ_INSERT_HEAD(&gdt->sc_ucmd_queue, ucmd, links);
72689580Smsmith                break;
72789580Smsmith            }
72889580Smsmith            break;
72989580Smsmith            /* wenn mehrere Kdos. zulassen: if (!gdt_polling) continue; */
73089580Smsmith        }
73189580Smsmith
73289580Smsmith        /* 2.: I/Os with ccb */
73389580Smsmith        ccb = (union ccb *)TAILQ_FIRST(&gdt->sc_ccb_queue);
73489580Smsmith        /* ist dann immer != NULL, da oben getestet */
73589580Smsmith        sim = (struct cam_sim *)ccb->ccb_h.ccb_sim_ptr;
73689580Smsmith        bus = cam_sim_bus(sim);
73789580Smsmith        target = ccb->ccb_h.target_id;
73889580Smsmith        lun = ccb->ccb_h.target_lun;
73989580Smsmith
74089580Smsmith        TAILQ_REMOVE(&gdt->sc_ccb_queue, &ccb->ccb_h, sim_links.tqe);
74189580Smsmith        --gdt_stat.req_queue_act;
74289580Smsmith        /* ccb->ccb_h.func_code is XPT_SCSI_IO */
74389580Smsmith        GDT_DPRINTF(GDT_D_QUEUE, ("XPT_SCSI_IO flags 0x%x)\n",
74489580Smsmith                                  ccb->ccb_h.flags));
74589580Smsmith        csio = &ccb->csio;
74689580Smsmith        ccbh = &ccb->ccb_h;
747312850Smav        cmd  = scsiio_cdb_ptr(csio)[0];
748312850Smav        /* Max CDB length is 12 bytes, can't be phys addr */
749312850Smav        if (csio->cdb_len > 12 || (ccbh->flags & CAM_CDB_PHYS)) {
75089580Smsmith            ccbh->status = CAM_REQ_INVALID;
75189580Smsmith            --gdt_stat.io_count_act;
75289580Smsmith            xpt_done(ccb);
75389580Smsmith        } else if (bus != gdt->sc_virt_bus) {
75489580Smsmith            /* raw service command */
755275975Ssmh            if ((gccb = gdt_raw_cmd(gdt, ccb)) == NULL) {
75689580Smsmith                TAILQ_INSERT_HEAD(&gdt->sc_ccb_queue, &ccb->ccb_h,
75789580Smsmith                                  sim_links.tqe);
75889580Smsmith                ++gdt_stat.req_queue_act;
75989580Smsmith                if (gdt_stat.req_queue_act > gdt_stat.req_queue_max)
76089580Smsmith                    gdt_stat.req_queue_max = gdt_stat.req_queue_act;
76189580Smsmith                next_cmd = FALSE;
76289580Smsmith            }
76389580Smsmith        } else if (target >= GDT_MAX_HDRIVES ||
76489580Smsmith                   !gdt->sc_hdr[target].hd_present || lun != 0) {
765114001Sscottl            ccbh->status = CAM_DEV_NOT_THERE;
76689580Smsmith            --gdt_stat.io_count_act;
76789580Smsmith            xpt_done(ccb);
76889580Smsmith        } else {
76989580Smsmith            /* cache service command */
77089580Smsmith            if (cmd == READ_6  || cmd == WRITE_6 ||
77189580Smsmith                cmd == READ_10 || cmd == WRITE_10) {
772275975Ssmh                if ((gccb = gdt_cache_cmd(gdt, ccb)) == NULL) {
77389580Smsmith                    TAILQ_INSERT_HEAD(&gdt->sc_ccb_queue, &ccb->ccb_h,
77489580Smsmith                                      sim_links.tqe);
77589580Smsmith                    ++gdt_stat.req_queue_act;
77689580Smsmith                    if (gdt_stat.req_queue_act > gdt_stat.req_queue_max)
77789580Smsmith                        gdt_stat.req_queue_max = gdt_stat.req_queue_act;
77889580Smsmith                    next_cmd = FALSE;
77989580Smsmith                }
78089580Smsmith            } else {
78189580Smsmith                gdt_internal_cache_cmd(gdt, ccb);
78289580Smsmith            }
78389580Smsmith        }
78489580Smsmith        if ((gdt->sc_state & GDT_POLLING) || !next_cmd)
78589580Smsmith            break;
78689580Smsmith    }
78789580Smsmith    if (gdt->sc_cmd_cnt > 0)
78889580Smsmith        gdt->sc_release_event(gdt);
78989580Smsmith
79089580Smsmith    if ((gdt->sc_state & GDT_POLLING) && gdt->sc_cmd_cnt > 0) {
79189580Smsmith        gdt_wait(gdt, gccb, GDT_POLL_TIMEOUT);
79289580Smsmith    }
79389580Smsmith}
79489580Smsmith
79589580Smsmithstatic struct gdt_ccb *
796275975Ssmhgdt_raw_cmd(struct gdt_softc *gdt, union ccb *ccb)
79789580Smsmith{
79889580Smsmith    struct gdt_ccb *gccb;
79989580Smsmith    struct cam_sim *sim;
800246713Skib    int error;
80189580Smsmith
80289580Smsmith    GDT_DPRINTF(GDT_D_CMD, ("gdt_raw_cmd(%p, %p)\n", gdt, ccb));
80389580Smsmith
80489580Smsmith    if (roundup(GDT_CMD_UNION + GDT_RAW_SZ, sizeof(u_int32_t)) +
80589580Smsmith        gdt->sc_cmd_off + GDT_DPMEM_COMMAND_OFFSET >
80689580Smsmith        gdt->sc_ic_all_size) {
807275975Ssmh        GDT_DPRINTF(GDT_D_INVALID, ("%s: gdt_raw_cmd(): DPMEM overflow\n",
808275975Ssmh		device_get_nameunit(gdt->sc_devnode)));
80989580Smsmith        return (NULL);
81089580Smsmith    }
81189580Smsmith
81289580Smsmith    gccb = gdt_get_ccb(gdt);
81389580Smsmith    if (gccb == NULL) {
814275975Ssmh        GDT_DPRINTF(GDT_D_INVALID, ("%s: No free command index found\n",
815275975Ssmh		device_get_nameunit(gdt->sc_devnode)));
81689580Smsmith        return (gccb);
81789580Smsmith    }
818156139Sscottl    bzero(gccb->gc_cmd, GDT_CMD_SZ);
81989580Smsmith    sim = (struct cam_sim *)ccb->ccb_h.ccb_sim_ptr;
82089580Smsmith    gccb->gc_ccb = ccb;
82189580Smsmith    gccb->gc_service = GDT_SCSIRAWSERVICE;
82289580Smsmith    gccb->gc_flags = GDT_GCF_SCSI;
82389580Smsmith
82489580Smsmith    if (gdt->sc_cmd_cnt == 0)
82589580Smsmith        gdt->sc_set_sema0(gdt);
826156139Sscottl    gdt_enc32(gccb->gc_cmd + GDT_CMD_COMMANDINDEX,
82789580Smsmith              gccb->gc_cmd_index);
828156139Sscottl    gdt_enc16(gccb->gc_cmd + GDT_CMD_OPCODE, GDT_WRITE);
82989580Smsmith
830156139Sscottl    gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_DIRECTION,
83189580Smsmith              (ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN ?
83289580Smsmith              GDT_DATA_IN : GDT_DATA_OUT);
833156139Sscottl    gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SDLEN,
83489580Smsmith              ccb->csio.dxfer_len);
835156139Sscottl    gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_CLEN,
83689580Smsmith              ccb->csio.cdb_len);
837156139Sscottl    bcopy(ccb->csio.cdb_io.cdb_bytes, gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_CMD,
83889580Smsmith          ccb->csio.cdb_len);
839156139Sscottl    gccb->gc_cmd[GDT_CMD_UNION + GDT_RAW_TARGET] =
84089580Smsmith        ccb->ccb_h.target_id;
841156139Sscottl    gccb->gc_cmd[GDT_CMD_UNION + GDT_RAW_LUN] =
84289580Smsmith        ccb->ccb_h.target_lun;
843156139Sscottl    gccb->gc_cmd[GDT_CMD_UNION + GDT_RAW_BUS] =
84489580Smsmith        cam_sim_bus(sim);
845156139Sscottl    gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SENSE_LEN,
84689580Smsmith              sizeof(struct scsi_sense_data));
847156139Sscottl    gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SENSE_DATA,
848156139Sscottl              gccb->gc_scratch_busbase);
84989580Smsmith
850246713Skib    error = bus_dmamap_load_ccb(gdt->sc_buffer_dmat,
851246713Skib			        gccb->gc_dmamap,
852246713Skib			        ccb,
853246713Skib			        gdtexecuteccb,
854246713Skib			        gccb, /*flags*/0);
855246713Skib    if (error == EINPROGRESS) {
856246713Skib        xpt_freeze_simq(sim, 1);
857246713Skib        gccb->gc_ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
85889580Smsmith    }
85989580Smsmith
86089580Smsmith    return (gccb);
86189580Smsmith}
86289580Smsmith
86389580Smsmithstatic struct gdt_ccb *
864275975Ssmhgdt_cache_cmd(struct gdt_softc *gdt, union ccb *ccb)
86589580Smsmith{
86689580Smsmith    struct gdt_ccb *gccb;
86789580Smsmith    struct cam_sim *sim;
86889580Smsmith    u_int8_t *cmdp;
86989580Smsmith    u_int16_t opcode;
87089580Smsmith    u_int32_t blockno, blockcnt;
871246713Skib    int error;
87289580Smsmith
87389580Smsmith    GDT_DPRINTF(GDT_D_CMD, ("gdt_cache_cmd(%p, %p)\n", gdt, ccb));
87489580Smsmith
87589580Smsmith    if (roundup(GDT_CMD_UNION + GDT_CACHE_SZ, sizeof(u_int32_t)) +
87689580Smsmith        gdt->sc_cmd_off + GDT_DPMEM_COMMAND_OFFSET >
87789580Smsmith        gdt->sc_ic_all_size) {
878275975Ssmh        GDT_DPRINTF(GDT_D_INVALID, ("%s: gdt_cache_cmd(): DPMEM overflow\n",
879275975Ssmh		device_get_nameunit(gdt->sc_devnode)));
88089580Smsmith        return (NULL);
88189580Smsmith    }
88289580Smsmith
88389580Smsmith    gccb = gdt_get_ccb(gdt);
88489580Smsmith    if (gccb == NULL) {
885275975Ssmh        GDT_DPRINTF(GDT_D_DEBUG, ("%s: No free command index found\n",
886275975Ssmh		device_get_nameunit(gdt->sc_devnode)));
88789580Smsmith        return (gccb);
88889580Smsmith    }
889156139Sscottl    bzero(gccb->gc_cmd, GDT_CMD_SZ);
89089580Smsmith    sim = (struct cam_sim *)ccb->ccb_h.ccb_sim_ptr;
89189580Smsmith    gccb->gc_ccb = ccb;
89289580Smsmith    gccb->gc_service = GDT_CACHESERVICE;
89389580Smsmith    gccb->gc_flags = GDT_GCF_SCSI;
89489580Smsmith
89589580Smsmith    if (gdt->sc_cmd_cnt == 0)
89689580Smsmith        gdt->sc_set_sema0(gdt);
897156139Sscottl    gdt_enc32(gccb->gc_cmd + GDT_CMD_COMMANDINDEX,
89889580Smsmith              gccb->gc_cmd_index);
89989580Smsmith    cmdp = ccb->csio.cdb_io.cdb_bytes;
90089580Smsmith    opcode = (*cmdp == WRITE_6 || *cmdp == WRITE_10) ? GDT_WRITE : GDT_READ;
90189580Smsmith    if ((gdt->sc_state & GDT_SHUTDOWN) && opcode == GDT_WRITE)
90289580Smsmith        opcode = GDT_WRITE_THR;
903156139Sscottl    gdt_enc16(gccb->gc_cmd + GDT_CMD_OPCODE, opcode);
90489580Smsmith
905156139Sscottl    gdt_enc16(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_DEVICENO,
90689580Smsmith              ccb->ccb_h.target_id);
90789580Smsmith    if (ccb->csio.cdb_len == 6) {
90889580Smsmith        struct scsi_rw_6 *rw = (struct scsi_rw_6 *)cmdp;
90989580Smsmith        blockno = scsi_3btoul(rw->addr) & ((SRW_TOPADDR<<16) | 0xffff);
91089580Smsmith        blockcnt = rw->length ? rw->length : 0x100;
91189580Smsmith    } else {
91289580Smsmith        struct scsi_rw_10 *rw = (struct scsi_rw_10 *)cmdp;
91389580Smsmith        blockno = scsi_4btoul(rw->addr);
91489580Smsmith        blockcnt = scsi_2btoul(rw->length);
91589580Smsmith    }
916156139Sscottl    gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_BLOCKNO,
91789580Smsmith              blockno);
918156139Sscottl    gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_BLOCKCNT,
91989580Smsmith              blockcnt);
92089580Smsmith
921246713Skib    error = bus_dmamap_load_ccb(gdt->sc_buffer_dmat,
92289580Smsmith                                gccb->gc_dmamap,
923246713Skib                                ccb,
92489580Smsmith                                gdtexecuteccb,
92589580Smsmith                                gccb, /*flags*/0);
926246713Skib    if (error == EINPROGRESS) {
927246713Skib        xpt_freeze_simq(sim, 1);
928246713Skib        gccb->gc_ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
92989580Smsmith    }
93089580Smsmith    return (gccb);
93189580Smsmith}
93289580Smsmith
93389580Smsmithstatic struct gdt_ccb *
934275975Ssmhgdt_ioctl_cmd(struct gdt_softc *gdt, gdt_ucmd_t *ucmd)
93589580Smsmith{
93689580Smsmith    struct gdt_ccb *gccb;
93789580Smsmith    u_int32_t cnt;
93889580Smsmith
93989580Smsmith    GDT_DPRINTF(GDT_D_DEBUG, ("gdt_ioctl_cmd(%p, %p)\n", gdt, ucmd));
94089580Smsmith
94189580Smsmith    gccb = gdt_get_ccb(gdt);
94289580Smsmith    if (gccb == NULL) {
943275975Ssmh        GDT_DPRINTF(GDT_D_DEBUG, ("%s: No free command index found\n",
944275975Ssmh		device_get_nameunit(gdt->sc_devnode)));
94589580Smsmith        return (gccb);
94689580Smsmith    }
947156139Sscottl    bzero(gccb->gc_cmd, GDT_CMD_SZ);
94889580Smsmith    gccb->gc_ucmd = ucmd;
94989580Smsmith    gccb->gc_service = ucmd->service;
95089580Smsmith    gccb->gc_flags = GDT_GCF_IOCTL;
95189580Smsmith
95289580Smsmith    /* check DPMEM space, copy data buffer from user space */
95389580Smsmith    if (ucmd->service == GDT_CACHESERVICE) {
95489580Smsmith        if (ucmd->OpCode == GDT_IOCTL) {
955156139Sscottl            gccb->gc_cmd_len = roundup(GDT_CMD_UNION + GDT_IOCTL_SZ,
95689580Smsmith                                      sizeof(u_int32_t));
95789580Smsmith            cnt = ucmd->u.ioctl.param_size;
95889580Smsmith            if (cnt > GDT_SCRATCH_SZ) {
959275975Ssmh                device_printf(gdt->sc_devnode,
960275975Ssmh		    "Scratch buffer too small (%d/%d)\n", GDT_SCRATCH_SZ, cnt);
96189580Smsmith                gdt_free_ccb(gdt, gccb);
96289580Smsmith                return (NULL);
96389580Smsmith            }
96489580Smsmith        } else {
965156139Sscottl            gccb->gc_cmd_len = roundup(GDT_CMD_UNION + GDT_CACHE_SG_LST +
96689580Smsmith                                      GDT_SG_SZ, sizeof(u_int32_t));
96789580Smsmith            cnt = ucmd->u.cache.BlockCnt * GDT_SECTOR_SIZE;
96889580Smsmith            if (cnt > GDT_SCRATCH_SZ) {
969275975Ssmh                device_printf(gdt->sc_devnode,
970275975Ssmh		    "Scratch buffer too small (%d/%d)\n", GDT_SCRATCH_SZ, cnt);
97189580Smsmith                gdt_free_ccb(gdt, gccb);
97289580Smsmith                return (NULL);
97389580Smsmith            }
97489580Smsmith        }
97589580Smsmith    } else {
976156139Sscottl        gccb->gc_cmd_len = roundup(GDT_CMD_UNION + GDT_RAW_SG_LST +
97789580Smsmith                                  GDT_SG_SZ, sizeof(u_int32_t));
97889580Smsmith        cnt = ucmd->u.raw.sdlen;
97989580Smsmith        if (cnt + ucmd->u.raw.sense_len > GDT_SCRATCH_SZ) {
980275975Ssmh            device_printf(gdt->sc_devnode, "Scratch buffer too small (%d/%d)\n",
981275975Ssmh		GDT_SCRATCH_SZ, cnt + ucmd->u.raw.sense_len);
98289580Smsmith            gdt_free_ccb(gdt, gccb);
98389580Smsmith            return (NULL);
98489580Smsmith        }
98589580Smsmith    }
98689580Smsmith    if (cnt != 0)
98789580Smsmith        bcopy(ucmd->data, gccb->gc_scratch, cnt);
98889580Smsmith
989156139Sscottl    if (gdt->sc_cmd_off + gccb->gc_cmd_len + GDT_DPMEM_COMMAND_OFFSET >
99089580Smsmith        gdt->sc_ic_all_size) {
991275975Ssmh        GDT_DPRINTF(GDT_D_INVALID, ("%s: gdt_ioctl_cmd(): DPMEM overflow\n",
992275975Ssmh		device_get_nameunit(gdt->sc_devnode)));
99389580Smsmith        gdt_free_ccb(gdt, gccb);
99489580Smsmith        return (NULL);
99589580Smsmith    }
99689580Smsmith
99789580Smsmith    if (gdt->sc_cmd_cnt == 0)
99889580Smsmith        gdt->sc_set_sema0(gdt);
99989580Smsmith
100089580Smsmith    /* fill cmd structure */
1001156139Sscottl    gdt_enc32(gccb->gc_cmd + GDT_CMD_COMMANDINDEX,
100289580Smsmith              gccb->gc_cmd_index);
1003156139Sscottl    gdt_enc16(gccb->gc_cmd + GDT_CMD_OPCODE,
100489580Smsmith              ucmd->OpCode);
100589580Smsmith
100689580Smsmith    if (ucmd->service == GDT_CACHESERVICE) {
100789580Smsmith        if (ucmd->OpCode == GDT_IOCTL) {
100889580Smsmith            /* IOCTL */
1009156139Sscottl            gdt_enc16(gccb->gc_cmd + GDT_CMD_UNION + GDT_IOCTL_PARAM_SIZE,
101089580Smsmith                      ucmd->u.ioctl.param_size);
1011156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_IOCTL_SUBFUNC,
101289580Smsmith                      ucmd->u.ioctl.subfunc);
1013156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_IOCTL_CHANNEL,
101489580Smsmith                      ucmd->u.ioctl.channel);
1015156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_IOCTL_P_PARAM,
1016156139Sscottl                      gccb->gc_scratch_busbase);
101789580Smsmith        } else {
101889580Smsmith            /* cache service command */
1019156139Sscottl            gdt_enc16(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_DEVICENO,
102089580Smsmith                      ucmd->u.cache.DeviceNo);
1021156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_BLOCKNO,
102289580Smsmith                      ucmd->u.cache.BlockNo);
1023156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_BLOCKCNT,
102489580Smsmith                      ucmd->u.cache.BlockCnt);
1025156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_DESTADDR,
102689580Smsmith                      0xffffffffUL);
1027156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_SG_CANZ,
102889580Smsmith                      1);
1029156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_SG_LST +
1030156139Sscottl                      GDT_SG_PTR, gccb->gc_scratch_busbase);
1031156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_SG_LST +
103289580Smsmith                      GDT_SG_LEN, ucmd->u.cache.BlockCnt * GDT_SECTOR_SIZE);
103389580Smsmith        }
103489580Smsmith    } else {
103589580Smsmith        /* raw service command */
1036156139Sscottl        gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_DIRECTION,
103789580Smsmith                  ucmd->u.raw.direction);
1038156139Sscottl        gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SDATA,
103989580Smsmith                  0xffffffffUL);
1040156139Sscottl        gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SDLEN,
104189580Smsmith                  ucmd->u.raw.sdlen);
1042156139Sscottl        gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_CLEN,
104389580Smsmith                  ucmd->u.raw.clen);
1044156139Sscottl        bcopy(ucmd->u.raw.cmd, gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_CMD,
104589580Smsmith              12);
1046156139Sscottl        gccb->gc_cmd[GDT_CMD_UNION + GDT_RAW_TARGET] =
104789580Smsmith            ucmd->u.raw.target;
1048156139Sscottl        gccb->gc_cmd[GDT_CMD_UNION + GDT_RAW_LUN] =
104989580Smsmith            ucmd->u.raw.lun;
1050156139Sscottl        gccb->gc_cmd[GDT_CMD_UNION + GDT_RAW_BUS] =
105189580Smsmith            ucmd->u.raw.bus;
1052156139Sscottl        gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SENSE_LEN,
105389580Smsmith                  ucmd->u.raw.sense_len);
1054156139Sscottl        gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SENSE_DATA,
1055156139Sscottl                  gccb->gc_scratch_busbase + ucmd->u.raw.sdlen);
1056156139Sscottl        gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SG_RANZ,
105789580Smsmith                  1);
1058156139Sscottl        gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SG_LST +
1059156139Sscottl                  GDT_SG_PTR, gccb->gc_scratch_busbase);
1060156139Sscottl        gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SG_LST +
106189580Smsmith                  GDT_SG_LEN, ucmd->u.raw.sdlen);
106289580Smsmith    }
106389580Smsmith
106489580Smsmith    gdt_stat.sg_count_act = 1;
106589580Smsmith    gdt->sc_copy_cmd(gdt, gccb);
106689580Smsmith    return (gccb);
106789580Smsmith}
106889580Smsmith
106989580Smsmithstatic void
107089580Smsmithgdt_internal_cache_cmd(struct gdt_softc *gdt,union ccb *ccb)
107189580Smsmith{
107289580Smsmith    int t;
107389580Smsmith
107489580Smsmith    t = ccb->ccb_h.target_id;
107589580Smsmith    GDT_DPRINTF(GDT_D_CMD, ("gdt_internal_cache_cmd(%p, %p, 0x%x, %d)\n",
107689580Smsmith        gdt, ccb, ccb->csio.cdb_io.cdb_bytes[0], t));
107789580Smsmith
107889580Smsmith    switch (ccb->csio.cdb_io.cdb_bytes[0]) {
107989580Smsmith      case TEST_UNIT_READY:
108089580Smsmith      case START_STOP:
108189580Smsmith        break;
108289580Smsmith      case REQUEST_SENSE:
108389580Smsmith        GDT_DPRINTF(GDT_D_MISC, ("REQUEST_SENSE\n"));
108489580Smsmith        break;
108589580Smsmith      case INQUIRY:
108689580Smsmith        {
1087175197Sscottl            struct scsi_inquiry_data inq;
1088175197Sscottl            size_t copylen = MIN(sizeof(inq), ccb->csio.dxfer_len);
108989580Smsmith
1090175197Sscottl            bzero(&inq, sizeof(inq));
1091175197Sscottl            inq.device = (gdt->sc_hdr[t].hd_devtype & 4) ?
109289580Smsmith                T_CDROM : T_DIRECT;
1093175197Sscottl            inq.dev_qual2 = (gdt->sc_hdr[t].hd_devtype & 1) ? 0x80 : 0;
1094175197Sscottl            inq.version = SCSI_REV_2;
1095175197Sscottl            inq.response_format = 2;
1096175197Sscottl            inq.additional_length = 32;
1097175197Sscottl            inq.flags = SID_CmdQue | SID_Sync;
1098175197Sscottl            strncpy(inq.vendor, gdt->oem_name, sizeof(inq.vendor));
1099175197Sscottl            snprintf(inq.product, sizeof(inq.product),
1100175197Sscottl                     "Host Drive   #%02d", t);
1101175197Sscottl            strncpy(inq.revision, "   ", sizeof(inq.revision));
1102175197Sscottl            bcopy(&inq, ccb->csio.data_ptr, copylen );
1103175197Sscottl            if( ccb->csio.dxfer_len > copylen )
1104175197Sscottl                bzero( ccb->csio.data_ptr+copylen,
1105175197Sscottl                       ccb->csio.dxfer_len - copylen );
110689580Smsmith            break;
110789580Smsmith        }
110889580Smsmith      case MODE_SENSE_6:
110989580Smsmith        {
111089580Smsmith            struct mpd_data {
111189580Smsmith                struct scsi_mode_hdr_6 hd;
111289580Smsmith                struct scsi_mode_block_descr bd;
111389580Smsmith                struct scsi_control_page cp;
1114175197Sscottl            } mpd;
1115175197Sscottl            size_t copylen = MIN(sizeof(mpd), ccb->csio.dxfer_len);
111689580Smsmith            u_int8_t page;
111789580Smsmith
1118175197Sscottl            /*mpd = (struct mpd_data *)ccb->csio.data_ptr;*/
1119175197Sscottl            bzero(&mpd, sizeof(mpd));
1120175197Sscottl            mpd.hd.datalen = sizeof(struct scsi_mode_hdr_6) +
112189580Smsmith                sizeof(struct scsi_mode_block_descr);
1122175197Sscottl            mpd.hd.dev_specific = (gdt->sc_hdr[t].hd_devtype & 2) ? 0x80 : 0;
1123175197Sscottl            mpd.hd.block_descr_len = sizeof(struct scsi_mode_block_descr);
1124175197Sscottl            mpd.bd.block_len[0] = (GDT_SECTOR_SIZE & 0x00ff0000) >> 16;
1125175197Sscottl            mpd.bd.block_len[1] = (GDT_SECTOR_SIZE & 0x0000ff00) >> 8;
1126175197Sscottl            mpd.bd.block_len[2] = (GDT_SECTOR_SIZE & 0x000000ff);
1127175197Sscottl
1128175197Sscottl            bcopy(&mpd, ccb->csio.data_ptr, copylen );
1129175197Sscottl            if( ccb->csio.dxfer_len > copylen )
1130175197Sscottl                bzero( ccb->csio.data_ptr+copylen,
1131175197Sscottl                       ccb->csio.dxfer_len - copylen );
113289580Smsmith            page=((struct scsi_mode_sense_6 *)ccb->csio.cdb_io.cdb_bytes)->page;
113389580Smsmith            switch (page) {
113489580Smsmith              default:
113589580Smsmith                GDT_DPRINTF(GDT_D_MISC, ("MODE_SENSE_6: page 0x%x\n", page));
113689580Smsmith                break;
113789580Smsmith            }
113889580Smsmith            break;
113989580Smsmith        }
114089580Smsmith      case READ_CAPACITY:
114189580Smsmith        {
1142175197Sscottl            struct scsi_read_capacity_data rcd;
1143175197Sscottl            size_t copylen = MIN(sizeof(rcd), ccb->csio.dxfer_len);
114489580Smsmith
1145175197Sscottl            /*rcd = (struct scsi_read_capacity_data *)ccb->csio.data_ptr;*/
1146175197Sscottl            bzero(&rcd, sizeof(rcd));
1147175197Sscottl            scsi_ulto4b(gdt->sc_hdr[t].hd_size - 1, rcd.addr);
1148175197Sscottl            scsi_ulto4b(GDT_SECTOR_SIZE, rcd.length);
1149175197Sscottl            bcopy(&rcd, ccb->csio.data_ptr, copylen );
1150175197Sscottl            if( ccb->csio.dxfer_len > copylen )
1151175197Sscottl                bzero( ccb->csio.data_ptr+copylen,
1152175197Sscottl                       ccb->csio.dxfer_len - copylen );
115389580Smsmith            break;
115489580Smsmith        }
115589580Smsmith      default:
115689580Smsmith        GDT_DPRINTF(GDT_D_MISC, ("gdt_internal_cache_cmd(%d) unknown\n",
115789580Smsmith                                    ccb->csio.cdb_io.cdb_bytes[0]));
115889580Smsmith        break;
115989580Smsmith    }
1160156139Sscottl    ccb->ccb_h.status |= CAM_REQ_CMP;
116189580Smsmith    --gdt_stat.io_count_act;
116289580Smsmith    xpt_done(ccb);
116389580Smsmith}
116489580Smsmith
116589580Smsmithstatic void
116689580Smsmithgdtmapmem(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
116789580Smsmith{
116889580Smsmith    bus_addr_t *busaddrp;
116989580Smsmith
117089580Smsmith    busaddrp = (bus_addr_t *)arg;
117189580Smsmith    *busaddrp = dm_segs->ds_addr;
117289580Smsmith}
117389580Smsmith
117489580Smsmithstatic void
117589580Smsmithgdtexecuteccb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
117689580Smsmith{
117789580Smsmith    struct gdt_ccb *gccb;
117889580Smsmith    union ccb *ccb;
117989580Smsmith    struct gdt_softc *gdt;
1180275975Ssmh    int i;
118189580Smsmith
118289580Smsmith    gccb = (struct gdt_ccb *)arg;
118389580Smsmith    ccb = gccb->gc_ccb;
118489580Smsmith    gdt = cam_sim_softc((struct cam_sim *)ccb->ccb_h.ccb_sim_ptr);
1185275975Ssmh    mtx_assert(&gdt->sc_lock, MA_OWNED);
118689580Smsmith
118789580Smsmith    GDT_DPRINTF(GDT_D_CMD, ("gdtexecuteccb(%p, %p, %p, %d, %d)\n",
118889580Smsmith                            gdt, gccb, dm_segs, nseg, error));
118989580Smsmith    gdt_stat.sg_count_act = nseg;
119089580Smsmith    if (nseg > gdt_stat.sg_count_max)
119189580Smsmith        gdt_stat.sg_count_max = nseg;
119289580Smsmith
119389580Smsmith    /* Copy the segments into our SG list */
119489580Smsmith    if (gccb->gc_service == GDT_CACHESERVICE) {
119589580Smsmith        for (i = 0; i < nseg; ++i) {
1196156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_SG_LST +
119789580Smsmith                      i * GDT_SG_SZ + GDT_SG_PTR, dm_segs->ds_addr);
1198156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_SG_LST +
119989580Smsmith                      i * GDT_SG_SZ + GDT_SG_LEN, dm_segs->ds_len);
120089580Smsmith            dm_segs++;
120189580Smsmith        }
1202156139Sscottl        gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_SG_CANZ,
120389580Smsmith                  nseg);
1204156139Sscottl        gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_DESTADDR,
120589580Smsmith                  0xffffffffUL);
120689580Smsmith
1207156139Sscottl        gccb->gc_cmd_len = roundup(GDT_CMD_UNION + GDT_CACHE_SG_LST +
120889580Smsmith                                  nseg * GDT_SG_SZ, sizeof(u_int32_t));
120989580Smsmith    } else {
121089580Smsmith        for (i = 0; i < nseg; ++i) {
1211156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SG_LST +
121289580Smsmith                      i * GDT_SG_SZ + GDT_SG_PTR, dm_segs->ds_addr);
1213156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SG_LST +
121489580Smsmith                      i * GDT_SG_SZ + GDT_SG_LEN, dm_segs->ds_len);
121589580Smsmith            dm_segs++;
121689580Smsmith        }
1217156139Sscottl        gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SG_RANZ,
121889580Smsmith                  nseg);
1219156139Sscottl        gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SDATA,
122089580Smsmith                  0xffffffffUL);
122189580Smsmith
1222156139Sscottl        gccb->gc_cmd_len = roundup(GDT_CMD_UNION + GDT_RAW_SG_LST +
122389580Smsmith                                  nseg * GDT_SG_SZ, sizeof(u_int32_t));
122489580Smsmith    }
122589580Smsmith
122689580Smsmith    if (nseg != 0) {
1227114001Sscottl        bus_dmamap_sync(gdt->sc_buffer_dmat, gccb->gc_dmamap,
1228114001Sscottl            (ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN ?
1229114001Sscottl            BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
123089580Smsmith    }
123189580Smsmith
123289580Smsmith    /* We must NOT abort the command here if CAM_REQ_INPROG is not set,
123389580Smsmith     * because command semaphore is already set!
123489580Smsmith     */
123589580Smsmith
123689580Smsmith    ccb->ccb_h.status |= CAM_SIM_QUEUED;
123789580Smsmith    /* timeout handling */
1238275982Ssmh    callout_reset_sbt(&gccb->gc_timeout, SBT_1MS * ccb->ccb_h.timeout, 0,
1239275982Ssmh      iir_timeout, (caddr_t)gccb, 0);
124089580Smsmith
124189580Smsmith    gdt->sc_copy_cmd(gdt, gccb);
124289580Smsmith}
124389580Smsmith
124489580Smsmith
124589580Smsmithstatic void
124689580Smsmithiir_action( struct cam_sim *sim, union ccb *ccb )
124789580Smsmith{
124889580Smsmith    struct gdt_softc *gdt;
1249275975Ssmh    int bus, target, lun;
125089580Smsmith
125189580Smsmith    gdt = (struct gdt_softc *)cam_sim_softc( sim );
1252275975Ssmh    mtx_assert(&gdt->sc_lock, MA_OWNED);
125389580Smsmith    ccb->ccb_h.ccb_sim_ptr = sim;
125489580Smsmith    bus = cam_sim_bus(sim);
125589580Smsmith    target = ccb->ccb_h.target_id;
125689580Smsmith    lun = ccb->ccb_h.target_lun;
125789580Smsmith    GDT_DPRINTF(GDT_D_CMD,
125889580Smsmith                ("iir_action(%p) func 0x%x cmd 0x%x bus %d target %d lun %d\n",
125989580Smsmith                 gdt, ccb->ccb_h.func_code, ccb->csio.cdb_io.cdb_bytes[0],
126089580Smsmith                 bus, target, lun));
126189580Smsmith    ++gdt_stat.io_count_act;
126289580Smsmith    if (gdt_stat.io_count_act > gdt_stat.io_count_max)
126389580Smsmith        gdt_stat.io_count_max = gdt_stat.io_count_act;
126489580Smsmith
126589580Smsmith    switch (ccb->ccb_h.func_code) {
126689580Smsmith      case XPT_SCSI_IO:
126789580Smsmith        TAILQ_INSERT_TAIL(&gdt->sc_ccb_queue, &ccb->ccb_h, sim_links.tqe);
126889580Smsmith        ++gdt_stat.req_queue_act;
126989580Smsmith        if (gdt_stat.req_queue_act > gdt_stat.req_queue_max)
127089580Smsmith            gdt_stat.req_queue_max = gdt_stat.req_queue_act;
127189580Smsmith        gdt_next(gdt);
127289580Smsmith        break;
127389580Smsmith      case XPT_RESET_DEV:   /* Bus Device Reset the specified SCSI device */
127489580Smsmith      case XPT_ABORT:                       /* Abort the specified CCB */
127589580Smsmith        /* XXX Implement */
127689580Smsmith        ccb->ccb_h.status = CAM_REQ_INVALID;
127789580Smsmith        --gdt_stat.io_count_act;
127889580Smsmith        xpt_done(ccb);
127989580Smsmith        break;
128089580Smsmith      case XPT_SET_TRAN_SETTINGS:
128189580Smsmith        ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
128289580Smsmith        --gdt_stat.io_count_act;
128389580Smsmith        xpt_done(ccb);
128489580Smsmith        break;
128589580Smsmith      case XPT_GET_TRAN_SETTINGS:
128689580Smsmith        /* Get default/user set transfer settings for the target */
128789580Smsmith          {
1288163816Smjacob              struct        ccb_trans_settings *cts = &ccb->cts;
1289163816Smjacob              struct ccb_trans_settings_scsi *scsi = &cts->proto_specific.scsi;
1290163816Smjacob              struct ccb_trans_settings_spi *spi = &cts->xport_specific.spi;
1291163816Smjacob
1292163816Smjacob              cts->protocol = PROTO_SCSI;
1293163816Smjacob              cts->protocol_version = SCSI_REV_2;
1294163816Smjacob              cts->transport = XPORT_SPI;
1295163816Smjacob              cts->transport_version = 2;
1296163816Smjacob
1297163816Smjacob              if (cts->type == CTS_TYPE_USER_SETTINGS) {
1298163816Smjacob		  spi->flags = CTS_SPI_FLAGS_DISC_ENB;
1299163816Smjacob                  scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
1300163816Smjacob                  spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
1301163816Smjacob                  spi->sync_period = 25; /* 10MHz */
1302163816Smjacob                  if (spi->sync_period != 0)
1303163816Smjacob                      spi->sync_offset = 15;
1304163816Smjacob
1305163816Smjacob                  spi->valid = CTS_SPI_VALID_SYNC_RATE
1306163816Smjacob                      | CTS_SPI_VALID_SYNC_OFFSET
1307163816Smjacob                      | CTS_SPI_VALID_BUS_WIDTH
1308163816Smjacob                      | CTS_SPI_VALID_DISC;
1309163816Smjacob                  scsi->valid = CTS_SCSI_VALID_TQ;
1310163816Smjacob                  ccb->ccb_h.status = CAM_REQ_CMP;
1311163816Smjacob              } else {
1312163816Smjacob                  ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
1313163816Smjacob              }
131489580Smsmith              --gdt_stat.io_count_act;
131589580Smsmith              xpt_done(ccb);
131689580Smsmith              break;
131789580Smsmith          }
131889580Smsmith      case XPT_CALC_GEOMETRY:
131989580Smsmith          {
132089580Smsmith              struct ccb_calc_geometry *ccg;
132189580Smsmith              u_int32_t secs_per_cylinder;
132289580Smsmith
132389580Smsmith              ccg = &ccb->ccg;
132489580Smsmith              ccg->heads = gdt->sc_hdr[target].hd_heads;
132589580Smsmith              ccg->secs_per_track = gdt->sc_hdr[target].hd_secs;
132689580Smsmith              secs_per_cylinder = ccg->heads * ccg->secs_per_track;
132789580Smsmith              ccg->cylinders = ccg->volume_size / secs_per_cylinder;
132889580Smsmith              ccb->ccb_h.status = CAM_REQ_CMP;
132989580Smsmith              --gdt_stat.io_count_act;
133089580Smsmith              xpt_done(ccb);
133189580Smsmith              break;
133289580Smsmith          }
133389580Smsmith      case XPT_RESET_BUS:           /* Reset the specified SCSI bus */
133489580Smsmith          {
133589580Smsmith              /* XXX Implement */
133689580Smsmith              ccb->ccb_h.status = CAM_REQ_CMP;
133789580Smsmith              --gdt_stat.io_count_act;
133889580Smsmith              xpt_done(ccb);
133989580Smsmith              break;
134089580Smsmith          }
134189580Smsmith      case XPT_TERM_IO:             /* Terminate the I/O process */
134289580Smsmith        /* XXX Implement */
134389580Smsmith        ccb->ccb_h.status = CAM_REQ_INVALID;
134489580Smsmith        --gdt_stat.io_count_act;
134589580Smsmith        xpt_done(ccb);
134689580Smsmith        break;
134789580Smsmith      case XPT_PATH_INQ:            /* Path routing inquiry */
134889580Smsmith          {
134989580Smsmith              struct ccb_pathinq *cpi = &ccb->cpi;
135089580Smsmith
135189580Smsmith              cpi->version_num = 1;
135289580Smsmith              cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE;
135389580Smsmith              cpi->hba_inquiry |= PI_WIDE_16;
135489580Smsmith              cpi->target_sprt = 1;
135589580Smsmith              cpi->hba_misc = 0;
135689580Smsmith              cpi->hba_eng_cnt = 0;
135789580Smsmith              if (bus == gdt->sc_virt_bus)
135889580Smsmith                  cpi->max_target = GDT_MAX_HDRIVES - 1;
135989580Smsmith              else if (gdt->sc_class & GDT_FC)
136089580Smsmith                  cpi->max_target = GDT_MAXID_FC - 1;
136189580Smsmith              else
136289580Smsmith                  cpi->max_target = GDT_MAXID - 1;
136389580Smsmith              cpi->max_lun = 7;
136489580Smsmith              cpi->unit_number = cam_sim_unit(sim);
136589580Smsmith              cpi->bus_id = bus;
136689580Smsmith              cpi->initiator_id =
136789580Smsmith                  (bus == gdt->sc_virt_bus ? 127 : gdt->sc_bus_id[bus]);
136889580Smsmith              cpi->base_transfer_speed = 3300;
1369315813Smav              strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
1370254379Sjkim              if (gdt->sc_vendor == INTEL_VENDOR_ID_IIR)
1371315813Smav                  strlcpy(cpi->hba_vid, "Intel Corp.", HBA_IDLEN);
1372120477Sscottl              else
1373315813Smav                  strlcpy(cpi->hba_vid, "ICP vortex ", HBA_IDLEN);
1374315813Smav              strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
1375163816Smjacob              cpi->transport = XPORT_SPI;
1376163816Smjacob              cpi->transport_version = 2;
1377163816Smjacob              cpi->protocol = PROTO_SCSI;
1378163816Smjacob              cpi->protocol_version = SCSI_REV_2;
137989580Smsmith              cpi->ccb_h.status = CAM_REQ_CMP;
138089580Smsmith              --gdt_stat.io_count_act;
138189580Smsmith              xpt_done(ccb);
138289580Smsmith              break;
138389580Smsmith          }
138489580Smsmith      default:
138589580Smsmith        GDT_DPRINTF(GDT_D_INVALID, ("gdt_next(%p) cmd 0x%x invalid\n",
138689580Smsmith                                    gdt, ccb->ccb_h.func_code));
138789580Smsmith        ccb->ccb_h.status = CAM_REQ_INVALID;
138889580Smsmith        --gdt_stat.io_count_act;
138989580Smsmith        xpt_done(ccb);
139089580Smsmith        break;
139189580Smsmith    }
139289580Smsmith}
139389580Smsmith
139489580Smsmithstatic void
139589580Smsmithiir_poll( struct cam_sim *sim )
139689580Smsmith{
139789580Smsmith    struct gdt_softc *gdt;
139889580Smsmith
139989580Smsmith    gdt = (struct gdt_softc *)cam_sim_softc( sim );
140089580Smsmith    GDT_DPRINTF(GDT_D_CMD, ("iir_poll sim %p gdt %p\n", sim, gdt));
1401275975Ssmh    iir_intr_locked(gdt);
140289580Smsmith}
140389580Smsmith
140489580Smsmithstatic void
140589580Smsmithiir_timeout(void *arg)
140689580Smsmith{
1407156139Sscottl    GDT_DPRINTF(GDT_D_TIMEOUT, ("iir_timeout(%p)\n", gccb));
140889580Smsmith}
140989580Smsmith
141089580Smsmithstatic void
141189580Smsmithiir_shutdown( void *arg, int howto )
141289580Smsmith{
141389580Smsmith    struct gdt_softc *gdt;
141489580Smsmith    struct gdt_ccb *gccb;
141589580Smsmith    gdt_ucmd_t *ucmd;
1416275975Ssmh    int i;
141789580Smsmith
141889580Smsmith    gdt = (struct gdt_softc *)arg;
141989580Smsmith    GDT_DPRINTF(GDT_D_CMD, ("iir_shutdown(%p, %d)\n", gdt, howto));
142089580Smsmith
1421275975Ssmh    device_printf(gdt->sc_devnode,
1422275975Ssmh	"Flushing all Host Drives. Please wait ...  ");
142389580Smsmith
142489580Smsmith    /* allocate ucmd buffer */
1425156139Sscottl    ucmd = malloc(sizeof(gdt_ucmd_t), M_GDTBUF, M_NOWAIT);
142689580Smsmith    if (ucmd == NULL) {
1427275975Ssmh	printf("\n");
1428275975Ssmh        device_printf(gdt->sc_devnode,
1429275975Ssmh	    "iir_shutdown(): Cannot allocate resource\n");
143089580Smsmith        return;
143189580Smsmith    }
143289580Smsmith    bzero(ucmd, sizeof(gdt_ucmd_t));
143389580Smsmith
143489580Smsmith    /* wait for pending IOs */
1435275975Ssmh    mtx_lock(&gdt->sc_lock);
143689580Smsmith    gdt->sc_state = GDT_SHUTDOWN;
143789580Smsmith    if ((gccb = SLIST_FIRST(&gdt->sc_pending_gccb)) != NULL)
1438275975Ssmh        mtx_sleep(gccb, &gdt->sc_lock, PCATCH | PRIBIO, "iirshw", 100 * hz);
143989580Smsmith
144089580Smsmith    /* flush */
144189580Smsmith    for (i = 0; i < GDT_MAX_HDRIVES; ++i) {
144289580Smsmith        if (gdt->sc_hdr[i].hd_present) {
144389580Smsmith            ucmd->service = GDT_CACHESERVICE;
144489580Smsmith            ucmd->OpCode = GDT_FLUSH;
144589580Smsmith            ucmd->u.cache.DeviceNo = i;
144689580Smsmith            TAILQ_INSERT_TAIL(&gdt->sc_ucmd_queue, ucmd, links);
144789580Smsmith            ucmd->complete_flag = FALSE;
144889580Smsmith            gdt_next(gdt);
144989580Smsmith            if (!ucmd->complete_flag)
1450275975Ssmh                mtx_sleep(ucmd, &gdt->sc_lock, PCATCH | PRIBIO, "iirshw",
1451275975Ssmh		    10 * hz);
145289580Smsmith        }
145389580Smsmith    }
1454275975Ssmh    mtx_unlock(&gdt->sc_lock);
145589580Smsmith
145689580Smsmith    free(ucmd, M_DEVBUF);
145789580Smsmith    printf("Done.\n");
145889580Smsmith}
145989580Smsmith
146089580Smsmithvoid
146189580Smsmithiir_intr(void *arg)
146289580Smsmith{
146389580Smsmith    struct gdt_softc *gdt = arg;
1464275975Ssmh
1465275975Ssmh    mtx_lock(&gdt->sc_lock);
1466275975Ssmh    iir_intr_locked(gdt);
1467275975Ssmh    mtx_unlock(&gdt->sc_lock);
1468275975Ssmh}
1469275975Ssmh
1470275975Ssmhint
1471275975Ssmhiir_intr_locked(struct gdt_softc *gdt)
1472275975Ssmh{
147389580Smsmith    struct gdt_intr_ctx ctx;
147489580Smsmith    struct gdt_ccb *gccb;
147589580Smsmith    gdt_ucmd_t *ucmd;
147689580Smsmith    u_int32_t cnt;
147789580Smsmith
147889580Smsmith    GDT_DPRINTF(GDT_D_INTR, ("gdt_intr(%p)\n", gdt));
147989580Smsmith
1480275975Ssmh    mtx_assert(&gdt->sc_lock, MA_OWNED);
1481275975Ssmh
148289580Smsmith    /* If polling and we were not called from gdt_wait, just return */
148389580Smsmith    if ((gdt->sc_state & GDT_POLLING) &&
148489580Smsmith        !(gdt->sc_state & GDT_POLL_WAIT))
1485275975Ssmh        return (0);
148689580Smsmith
148789580Smsmith    ctx.istatus = gdt->sc_get_status(gdt);
1488156139Sscottl    if (ctx.istatus == 0x00) {
148989580Smsmith        gdt->sc_status = GDT_S_NO_STATUS;
1490275975Ssmh        return (ctx.istatus);
149189580Smsmith    }
149289580Smsmith
149389580Smsmith    gdt->sc_intr(gdt, &ctx);
149489580Smsmith
149589580Smsmith    gdt->sc_status = ctx.cmd_status;
149689580Smsmith    gdt->sc_service = ctx.service;
149789580Smsmith    gdt->sc_info = ctx.info;
149889580Smsmith    gdt->sc_info2 = ctx.info2;
149989580Smsmith
150089580Smsmith    if (ctx.istatus == GDT_ASYNCINDEX) {
150189580Smsmith        gdt_async_event(gdt, ctx.service);
1502275975Ssmh        return (ctx.istatus);
150389580Smsmith    }
150489580Smsmith    if (ctx.istatus == GDT_SPEZINDEX) {
150589580Smsmith        GDT_DPRINTF(GDT_D_INVALID,
1506275975Ssmh                    ("%s: Service unknown or not initialized!\n",
1507275975Ssmh		     device_get_nameunit(gdt->sc_devnode)));
150889580Smsmith        gdt->sc_dvr.size = sizeof(gdt->sc_dvr.eu.driver);
150989580Smsmith        gdt->sc_dvr.eu.driver.ionode = gdt->sc_hanum;
151089580Smsmith        gdt_store_event(GDT_ES_DRIVER, 4, &gdt->sc_dvr);
1511275975Ssmh        return (ctx.istatus);
151289580Smsmith    }
151389580Smsmith
151489580Smsmith    gccb = &gdt->sc_gccbs[ctx.istatus - 2];
151589580Smsmith    ctx.service = gccb->gc_service;
151689580Smsmith
151789580Smsmith    switch (gccb->gc_flags) {
151889580Smsmith      case GDT_GCF_UNUSED:
1519275975Ssmh        GDT_DPRINTF(GDT_D_INVALID, ("%s: Index (%d) to unused command!\n",
1520275975Ssmh		    device_get_nameunit(gdt->sc_devnode), ctx.istatus));
152189580Smsmith        gdt->sc_dvr.size = sizeof(gdt->sc_dvr.eu.driver);
152289580Smsmith        gdt->sc_dvr.eu.driver.ionode = gdt->sc_hanum;
152389580Smsmith        gdt->sc_dvr.eu.driver.index = ctx.istatus;
152489580Smsmith        gdt_store_event(GDT_ES_DRIVER, 1, &gdt->sc_dvr);
152589580Smsmith        gdt_free_ccb(gdt, gccb);
1526275975Ssmh	break;
152789580Smsmith
152889580Smsmith      case GDT_GCF_INTERNAL:
152989580Smsmith        break;
153089580Smsmith
153189580Smsmith      case GDT_GCF_IOCTL:
153289580Smsmith        ucmd = gccb->gc_ucmd;
153389580Smsmith        if (gdt->sc_status == GDT_S_BSY) {
153489580Smsmith            GDT_DPRINTF(GDT_D_DEBUG, ("iir_intr(%p) ioctl: gccb %p busy\n",
153589580Smsmith                                      gdt, gccb));
153689580Smsmith            TAILQ_INSERT_HEAD(&gdt->sc_ucmd_queue, ucmd, links);
153789580Smsmith        } else {
153889580Smsmith            ucmd->status = gdt->sc_status;
153989580Smsmith            ucmd->info = gdt->sc_info;
154089580Smsmith            ucmd->complete_flag = TRUE;
154189580Smsmith            if (ucmd->service == GDT_CACHESERVICE) {
154289580Smsmith                if (ucmd->OpCode == GDT_IOCTL) {
154389580Smsmith                    cnt = ucmd->u.ioctl.param_size;
154489580Smsmith                    if (cnt != 0)
154589580Smsmith                        bcopy(gccb->gc_scratch, ucmd->data, cnt);
154689580Smsmith                } else {
154789580Smsmith                    cnt = ucmd->u.cache.BlockCnt * GDT_SECTOR_SIZE;
154889580Smsmith                    if (cnt != 0)
154989580Smsmith                        bcopy(gccb->gc_scratch, ucmd->data, cnt);
155089580Smsmith                }
155189580Smsmith            } else {
155289580Smsmith                cnt = ucmd->u.raw.sdlen;
155389580Smsmith                if (cnt != 0)
155489580Smsmith                    bcopy(gccb->gc_scratch, ucmd->data, cnt);
155589580Smsmith                if (ucmd->u.raw.sense_len != 0)
155689580Smsmith                    bcopy(gccb->gc_scratch, ucmd->data, cnt);
155789580Smsmith            }
155889580Smsmith            gdt_free_ccb(gdt, gccb);
155989580Smsmith            /* wakeup */
156089580Smsmith            wakeup(ucmd);
156189580Smsmith        }
156289580Smsmith        gdt_next(gdt);
156389580Smsmith        break;
156489580Smsmith
156589580Smsmith      default:
156689580Smsmith        gdt_free_ccb(gdt, gccb);
156789580Smsmith        gdt_sync_event(gdt, ctx.service, ctx.istatus, gccb);
156889580Smsmith        gdt_next(gdt);
156989580Smsmith        break;
157089580Smsmith    }
1571275975Ssmh
1572275975Ssmh    return (ctx.istatus);
157389580Smsmith}
157489580Smsmith
1575114001Sscottlint
157689580Smsmithgdt_async_event(struct gdt_softc *gdt, int service)
157789580Smsmith{
157889580Smsmith    struct gdt_ccb *gccb;
157989580Smsmith
158089580Smsmith    GDT_DPRINTF(GDT_D_INTR, ("gdt_async_event(%p, %d)\n", gdt, service));
158189580Smsmith
158289580Smsmith    if (service == GDT_SCREENSERVICE) {
158389580Smsmith        if (gdt->sc_status == GDT_MSG_REQUEST) {
158489580Smsmith            while (gdt->sc_test_busy(gdt))
158589580Smsmith                DELAY(1);
158689580Smsmith            gccb = gdt_get_ccb(gdt);
158789580Smsmith            if (gccb == NULL) {
1588275975Ssmh                device_printf(gdt->sc_devnode, "No free command index found\n");
158989580Smsmith                return (1);
159089580Smsmith            }
1591156139Sscottl            bzero(gccb->gc_cmd, GDT_CMD_SZ);
159289580Smsmith            gccb->gc_service = service;
159389580Smsmith            gccb->gc_flags = GDT_GCF_SCREEN;
1594156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_COMMANDINDEX,
159589580Smsmith                      gccb->gc_cmd_index);
1596156139Sscottl            gdt_enc16(gccb->gc_cmd + GDT_CMD_OPCODE, GDT_READ);
1597156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_SCREEN_MSG_HANDLE,
159889580Smsmith                      GDT_MSG_INV_HANDLE);
1599156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_SCREEN_MSG_ADDR,
1600156139Sscottl                      gccb->gc_scratch_busbase);
1601156139Sscottl            gdt->sc_set_sema0(gdt);
160289580Smsmith            gdt->sc_cmd_off = 0;
1603156139Sscottl            gccb->gc_cmd_len = roundup(GDT_CMD_UNION + GDT_SCREEN_SZ,
160489580Smsmith                                      sizeof(u_int32_t));
160589580Smsmith            gdt->sc_cmd_cnt = 0;
160689580Smsmith            gdt->sc_copy_cmd(gdt, gccb);
1607275975Ssmh            device_printf(gdt->sc_devnode, "[PCI %d/%d] ", gdt->sc_bus,
1608275975Ssmh		gdt->sc_slot);
160989580Smsmith            gdt->sc_release_event(gdt);
161089580Smsmith        }
161189580Smsmith
161289580Smsmith    } else {
161389580Smsmith        if ((gdt->sc_fw_vers & 0xff) >= 0x1a) {
161489580Smsmith            gdt->sc_dvr.size = 0;
161589580Smsmith            gdt->sc_dvr.eu.async.ionode = gdt->sc_hanum;
161689580Smsmith            gdt->sc_dvr.eu.async.status  = gdt->sc_status;
161789580Smsmith            /* severity and event_string already set! */
161889580Smsmith        } else {
161989580Smsmith            gdt->sc_dvr.size = sizeof(gdt->sc_dvr.eu.async);
162089580Smsmith            gdt->sc_dvr.eu.async.ionode   = gdt->sc_hanum;
162189580Smsmith            gdt->sc_dvr.eu.async.service = service;
162289580Smsmith            gdt->sc_dvr.eu.async.status  = gdt->sc_status;
162389580Smsmith            gdt->sc_dvr.eu.async.info    = gdt->sc_info;
162489580Smsmith            *(u_int32_t *)gdt->sc_dvr.eu.async.scsi_coord  = gdt->sc_info2;
162589580Smsmith        }
162689580Smsmith        gdt_store_event(GDT_ES_ASYNC, service, &gdt->sc_dvr);
1627275975Ssmh        device_printf(gdt->sc_devnode, "%s\n", gdt->sc_dvr.event_string);
162889580Smsmith    }
162989580Smsmith
163089580Smsmith    return (0);
163189580Smsmith}
163289580Smsmith
1633114001Sscottlint
163489580Smsmithgdt_sync_event(struct gdt_softc *gdt, int service,
163589580Smsmith               u_int8_t index, struct gdt_ccb *gccb)
163689580Smsmith{
163789580Smsmith    union ccb *ccb;
163889580Smsmith
163989580Smsmith    GDT_DPRINTF(GDT_D_INTR,
164089580Smsmith                ("gdt_sync_event(%p, %d, %d, %p)\n", gdt,service,index,gccb));
164189580Smsmith
164289580Smsmith    ccb = gccb->gc_ccb;
164389580Smsmith
164489580Smsmith    if (service == GDT_SCREENSERVICE) {
164589580Smsmith        u_int32_t msg_len;
164689580Smsmith
164789580Smsmith        msg_len = gdt_dec32(gccb->gc_scratch + GDT_SCR_MSG_LEN);
164889580Smsmith        if (msg_len)
164989580Smsmith            if (!(gccb->gc_scratch[GDT_SCR_MSG_ANSWER] &&
165089580Smsmith                  gccb->gc_scratch[GDT_SCR_MSG_EXT])) {
165189580Smsmith                gccb->gc_scratch[GDT_SCR_MSG_TEXT + msg_len] = '\0';
165289580Smsmith                printf("%s",&gccb->gc_scratch[GDT_SCR_MSG_TEXT]);
165389580Smsmith            }
165489580Smsmith
165589580Smsmith        if (gccb->gc_scratch[GDT_SCR_MSG_EXT] &&
165689580Smsmith            !gccb->gc_scratch[GDT_SCR_MSG_ANSWER]) {
165789580Smsmith            while (gdt->sc_test_busy(gdt))
165889580Smsmith                DELAY(1);
1659156139Sscottl            bzero(gccb->gc_cmd, GDT_CMD_SZ);
166089580Smsmith            gccb = gdt_get_ccb(gdt);
166189580Smsmith            if (gccb == NULL) {
1662275975Ssmh                device_printf(gdt->sc_devnode, "No free command index found\n");
166389580Smsmith                return (1);
166489580Smsmith            }
166589580Smsmith            gccb->gc_service = service;
166689580Smsmith            gccb->gc_flags = GDT_GCF_SCREEN;
1667156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_COMMANDINDEX,
166889580Smsmith                      gccb->gc_cmd_index);
1669156139Sscottl            gdt_enc16(gccb->gc_cmd + GDT_CMD_OPCODE, GDT_READ);
1670156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_SCREEN_MSG_HANDLE,
167189580Smsmith                      gccb->gc_scratch[GDT_SCR_MSG_HANDLE]);
1672156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_SCREEN_MSG_ADDR,
1673156139Sscottl                      gccb->gc_scratch_busbase);
1674156139Sscottl            gdt->sc_set_sema0(gdt);
167589580Smsmith            gdt->sc_cmd_off = 0;
1676156139Sscottl            gccb->gc_cmd_len = roundup(GDT_CMD_UNION + GDT_SCREEN_SZ,
167789580Smsmith                                      sizeof(u_int32_t));
167889580Smsmith            gdt->sc_cmd_cnt = 0;
167989580Smsmith            gdt->sc_copy_cmd(gdt, gccb);
168089580Smsmith            gdt->sc_release_event(gdt);
168189580Smsmith            return (0);
168289580Smsmith        }
168389580Smsmith
168489580Smsmith        if (gccb->gc_scratch[GDT_SCR_MSG_ANSWER] &&
168589580Smsmith            gdt_dec32(gccb->gc_scratch + GDT_SCR_MSG_ALEN)) {
168689580Smsmith            /* default answers (getchar() not possible) */
168789580Smsmith            if (gdt_dec32(gccb->gc_scratch + GDT_SCR_MSG_ALEN) == 1) {
168889580Smsmith                gdt_enc32(gccb->gc_scratch + GDT_SCR_MSG_ALEN, 0);
168989580Smsmith                gdt_enc32(gccb->gc_scratch + GDT_SCR_MSG_LEN, 1);
169089580Smsmith                gccb->gc_scratch[GDT_SCR_MSG_TEXT] = 0;
169189580Smsmith            } else {
169289580Smsmith                gdt_enc32(gccb->gc_scratch + GDT_SCR_MSG_ALEN,
169389580Smsmith                          gdt_dec32(gccb->gc_scratch + GDT_SCR_MSG_ALEN) - 2);
169489580Smsmith                gdt_enc32(gccb->gc_scratch + GDT_SCR_MSG_LEN, 2);
169589580Smsmith                gccb->gc_scratch[GDT_SCR_MSG_TEXT] = 1;
169689580Smsmith                gccb->gc_scratch[GDT_SCR_MSG_TEXT + 1] = 0;
169789580Smsmith            }
169889580Smsmith            gccb->gc_scratch[GDT_SCR_MSG_EXT] = 0;
169989580Smsmith            gccb->gc_scratch[GDT_SCR_MSG_ANSWER] = 0;
170089580Smsmith            while (gdt->sc_test_busy(gdt))
170189580Smsmith                DELAY(1);
1702156139Sscottl            bzero(gccb->gc_cmd, GDT_CMD_SZ);
170389580Smsmith            gccb = gdt_get_ccb(gdt);
170489580Smsmith            if (gccb == NULL) {
1705275975Ssmh                device_printf(gdt->sc_devnode, "No free command index found\n");
170689580Smsmith                return (1);
170789580Smsmith            }
170889580Smsmith            gccb->gc_service = service;
170989580Smsmith            gccb->gc_flags = GDT_GCF_SCREEN;
1710156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_COMMANDINDEX,
171189580Smsmith                      gccb->gc_cmd_index);
1712156139Sscottl            gdt_enc16(gccb->gc_cmd + GDT_CMD_OPCODE, GDT_WRITE);
1713156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_SCREEN_MSG_HANDLE,
171489580Smsmith                      gccb->gc_scratch[GDT_SCR_MSG_HANDLE]);
1715156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_SCREEN_MSG_ADDR,
1716156139Sscottl                      gccb->gc_scratch_busbase);
1717156139Sscottl            gdt->sc_set_sema0(gdt);
171889580Smsmith            gdt->sc_cmd_off = 0;
1719156139Sscottl            gccb->gc_cmd_len = roundup(GDT_CMD_UNION + GDT_SCREEN_SZ,
172089580Smsmith                                      sizeof(u_int32_t));
172189580Smsmith            gdt->sc_cmd_cnt = 0;
172289580Smsmith            gdt->sc_copy_cmd(gdt, gccb);
172389580Smsmith            gdt->sc_release_event(gdt);
172489580Smsmith            return (0);
172589580Smsmith        }
172689580Smsmith        printf("\n");
172789580Smsmith        return (0);
172889580Smsmith    } else {
1729275975Ssmh	callout_stop(&gccb->gc_timeout);
173089580Smsmith        if (gdt->sc_status == GDT_S_BSY) {
173189580Smsmith            GDT_DPRINTF(GDT_D_DEBUG, ("gdt_sync_event(%p) gccb %p busy\n",
173289580Smsmith                                      gdt, gccb));
173389580Smsmith            TAILQ_INSERT_HEAD(&gdt->sc_ccb_queue, &ccb->ccb_h, sim_links.tqe);
173489580Smsmith            ++gdt_stat.req_queue_act;
173589580Smsmith            if (gdt_stat.req_queue_act > gdt_stat.req_queue_max)
173689580Smsmith                gdt_stat.req_queue_max = gdt_stat.req_queue_act;
173789580Smsmith            return (2);
173889580Smsmith        }
173989580Smsmith
1740114001Sscottl        bus_dmamap_sync(gdt->sc_buffer_dmat, gccb->gc_dmamap,
1741114001Sscottl            (ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN ?
1742114001Sscottl            BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
1743156139Sscottl        bus_dmamap_unload(gdt->sc_buffer_dmat, gccb->gc_dmamap);
174489580Smsmith
174589580Smsmith        ccb->csio.resid = 0;
174689580Smsmith        if (gdt->sc_status == GDT_S_OK) {
1747156139Sscottl            ccb->ccb_h.status |= CAM_REQ_CMP;
1748156139Sscottl            ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
174989580Smsmith        } else {
175089580Smsmith            /* error */
175189580Smsmith            if (gccb->gc_service == GDT_CACHESERVICE) {
1752225950Sken                struct scsi_sense_data *sense;
1753225950Sken
1754156139Sscottl                ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID;
1755156139Sscottl                ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
175689580Smsmith                ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
175789580Smsmith                bzero(&ccb->csio.sense_data, ccb->csio.sense_len);
1758225950Sken                sense = &ccb->csio.sense_data;
1759225950Sken                scsi_set_sense_data(sense,
1760225950Sken                                    /*sense_format*/ SSD_TYPE_NONE,
1761225950Sken                                    /*current_error*/ 1,
1762225950Sken                                    /*sense_key*/ SSD_KEY_NOT_READY,
1763225950Sken                                    /*asc*/ 0x4,
1764225950Sken                                    /*ascq*/ 0x01,
1765225950Sken                                    SSD_ELEM_NONE);
176689580Smsmith
176789580Smsmith                gdt->sc_dvr.size = sizeof(gdt->sc_dvr.eu.sync);
176889580Smsmith                gdt->sc_dvr.eu.sync.ionode  = gdt->sc_hanum;
176989580Smsmith                gdt->sc_dvr.eu.sync.service = service;
177089580Smsmith                gdt->sc_dvr.eu.sync.status  = gdt->sc_status;
177189580Smsmith                gdt->sc_dvr.eu.sync.info    = gdt->sc_info;
177289580Smsmith                gdt->sc_dvr.eu.sync.hostdrive = ccb->ccb_h.target_id;
177389580Smsmith                if (gdt->sc_status >= 0x8000)
177489580Smsmith                    gdt_store_event(GDT_ES_SYNC, 0, &gdt->sc_dvr);
177589580Smsmith                else
177689580Smsmith                    gdt_store_event(GDT_ES_SYNC, service, &gdt->sc_dvr);
177789580Smsmith            } else {
177889580Smsmith                /* raw service */
177989580Smsmith                if (gdt->sc_status != GDT_S_RAW_SCSI || gdt->sc_info >= 0x100) {
1780114001Sscottl                    ccb->ccb_h.status = CAM_DEV_NOT_THERE;
178189580Smsmith                } else {
1782156139Sscottl                    ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR|CAM_AUTOSNS_VALID;
1783156139Sscottl                    ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
178489580Smsmith                    ccb->csio.scsi_status = gdt->sc_info;
178589580Smsmith                    bcopy(gccb->gc_scratch, &ccb->csio.sense_data,
178689580Smsmith                          ccb->csio.sense_len);
178789580Smsmith                }
178889580Smsmith            }
178989580Smsmith        }
179089580Smsmith        --gdt_stat.io_count_act;
179189580Smsmith        xpt_done(ccb);
179289580Smsmith    }
179389580Smsmith    return (0);
179489580Smsmith}
179589580Smsmith
179689580Smsmith/* Controller event handling functions */
1797275975Ssmhvoid gdt_store_event(u_int16_t source, u_int16_t idx,
179889580Smsmith                             gdt_evt_data *evt)
179989580Smsmith{
180089580Smsmith    gdt_evt_str *e;
180189580Smsmith    struct timeval tv;
180289580Smsmith
180389580Smsmith    GDT_DPRINTF(GDT_D_MISC, ("gdt_store_event(%d, %d)\n", source, idx));
180489580Smsmith    if (source == 0)                        /* no source -> no event */
1805275975Ssmh        return;
180689580Smsmith
1807275975Ssmh    mtx_lock(&elock);
180889580Smsmith    if (ebuffer[elastidx].event_source == source &&
180989580Smsmith        ebuffer[elastidx].event_idx == idx &&
181089580Smsmith        ((evt->size != 0 && ebuffer[elastidx].event_data.size != 0 &&
181189580Smsmith          !memcmp((char *)&ebuffer[elastidx].event_data.eu,
181289580Smsmith                  (char *)&evt->eu, evt->size)) ||
181389580Smsmith         (evt->size == 0 && ebuffer[elastidx].event_data.size == 0 &&
181489580Smsmith          !strcmp((char *)&ebuffer[elastidx].event_data.event_string,
181589580Smsmith                  (char *)&evt->event_string)))) {
181689580Smsmith        e = &ebuffer[elastidx];
181789580Smsmith        getmicrotime(&tv);
181889580Smsmith        e->last_stamp = tv.tv_sec;
181989580Smsmith        ++e->same_count;
182089580Smsmith    } else {
182189580Smsmith        if (ebuffer[elastidx].event_source != 0) {  /* entry not free ? */
182289580Smsmith            ++elastidx;
182389580Smsmith            if (elastidx == GDT_MAX_EVENTS)
182489580Smsmith                elastidx = 0;
182589580Smsmith            if (elastidx == eoldidx) {              /* reached mark ? */
182689580Smsmith                ++eoldidx;
182789580Smsmith                if (eoldidx == GDT_MAX_EVENTS)
182889580Smsmith                    eoldidx = 0;
182989580Smsmith            }
183089580Smsmith        }
183189580Smsmith        e = &ebuffer[elastidx];
183289580Smsmith        e->event_source = source;
183389580Smsmith        e->event_idx = idx;
183489580Smsmith        getmicrotime(&tv);
183589580Smsmith        e->first_stamp = e->last_stamp = tv.tv_sec;
183689580Smsmith        e->same_count = 1;
183789580Smsmith        e->event_data = *evt;
183889580Smsmith        e->application = 0;
183989580Smsmith    }
1840275975Ssmh    mtx_unlock(&elock);
184189580Smsmith}
184289580Smsmith
184389580Smsmithint gdt_read_event(int handle, gdt_evt_str *estr)
184489580Smsmith{
184589580Smsmith    gdt_evt_str *e;
1846275975Ssmh    int eindex;
184789580Smsmith
184889580Smsmith    GDT_DPRINTF(GDT_D_MISC, ("gdt_read_event(%d)\n", handle));
1849275975Ssmh    mtx_lock(&elock);
185089580Smsmith    if (handle == -1)
185189580Smsmith        eindex = eoldidx;
185289580Smsmith    else
185389580Smsmith        eindex = handle;
185489580Smsmith    estr->event_source = 0;
185589580Smsmith
185689580Smsmith    if (eindex >= GDT_MAX_EVENTS) {
1857275975Ssmh	mtx_unlock(&elock);
185889580Smsmith        return eindex;
185989580Smsmith    }
186089580Smsmith    e = &ebuffer[eindex];
186189580Smsmith    if (e->event_source != 0) {
186289580Smsmith        if (eindex != elastidx) {
186389580Smsmith            if (++eindex == GDT_MAX_EVENTS)
186489580Smsmith                eindex = 0;
186589580Smsmith        } else {
186689580Smsmith            eindex = -1;
186789580Smsmith        }
186889580Smsmith        memcpy(estr, e, sizeof(gdt_evt_str));
186989580Smsmith    }
1870275975Ssmh    mtx_unlock(&elock);
187189580Smsmith    return eindex;
187289580Smsmith}
187389580Smsmith
187489580Smsmithvoid gdt_readapp_event(u_int8_t application, gdt_evt_str *estr)
187589580Smsmith{
187689580Smsmith    gdt_evt_str *e;
187789580Smsmith    int found = FALSE;
1878275975Ssmh    int eindex;
187989580Smsmith
188089580Smsmith    GDT_DPRINTF(GDT_D_MISC, ("gdt_readapp_event(%d)\n", application));
1881275975Ssmh    mtx_lock(&elock);
188289580Smsmith    eindex = eoldidx;
188389580Smsmith    for (;;) {
188489580Smsmith        e = &ebuffer[eindex];
188589580Smsmith        if (e->event_source == 0)
188689580Smsmith            break;
188789580Smsmith        if ((e->application & application) == 0) {
188889580Smsmith            e->application |= application;
188989580Smsmith            found = TRUE;
189089580Smsmith            break;
189189580Smsmith        }
189289580Smsmith        if (eindex == elastidx)
189389580Smsmith            break;
189489580Smsmith        if (++eindex == GDT_MAX_EVENTS)
189589580Smsmith            eindex = 0;
189689580Smsmith    }
189789580Smsmith    if (found)
189889580Smsmith        memcpy(estr, e, sizeof(gdt_evt_str));
189989580Smsmith    else
190089580Smsmith        estr->event_source = 0;
1901275975Ssmh    mtx_unlock(&elock);
190289580Smsmith}
190389580Smsmith
190489580Smsmithvoid gdt_clear_events()
190589580Smsmith{
190689580Smsmith    GDT_DPRINTF(GDT_D_MISC, ("gdt_clear_events\n"));
190789580Smsmith
1908275975Ssmh    mtx_lock(&elock);
190989580Smsmith    eoldidx = elastidx = 0;
191089580Smsmith    ebuffer[0].event_source = 0;
1911275975Ssmh    mtx_unlock(&elock);
191289580Smsmith}
1913