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$");
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
7489580Smsmithstruct gdt_softc *gdt_wait_gdt;
7589580Smsmithint     gdt_wait_index;
7689580Smsmith
7789580Smsmith#ifdef GDT_DEBUG
7889580Smsmithint     gdt_debug = GDT_DEBUG;
7989580Smsmith#ifdef __SERIAL__
8089580Smsmith#define MAX_SERBUF 160
8189580Smsmithstatic void ser_init(void);
8289580Smsmithstatic void ser_puts(char *str);
8389580Smsmithstatic void ser_putc(int c);
8489580Smsmithstatic char strbuf[MAX_SERBUF+1];
8589580Smsmith#ifdef __COM2__
8689580Smsmith#define COM_BASE 0x2f8
8789580Smsmith#else
8889580Smsmith#define COM_BASE 0x3f8
8989580Smsmith#endif
9089580Smsmithstatic void ser_init()
9189580Smsmith{
9289580Smsmith    unsigned port=COM_BASE;
9389580Smsmith
9489580Smsmith    outb(port+3, 0x80);
9589580Smsmith    outb(port+1, 0);
9689580Smsmith    /* 19200 Baud, if 9600: outb(12,port) */
9789580Smsmith    outb(port, 6);
9889580Smsmith    outb(port+3, 3);
9989580Smsmith    outb(port+1, 0);
10089580Smsmith}
10189580Smsmith
10289580Smsmithstatic void ser_puts(char *str)
10389580Smsmith{
10489580Smsmith    char *ptr;
10589580Smsmith
10689580Smsmith    ser_init();
10789580Smsmith    for (ptr=str;*ptr;++ptr)
10889580Smsmith        ser_putc((int)(*ptr));
10989580Smsmith}
11089580Smsmith
11189580Smsmithstatic void ser_putc(int c)
11289580Smsmith{
11389580Smsmith    unsigned port=COM_BASE;
11489580Smsmith
11589580Smsmith    while ((inb(port+5) & 0x20)==0);
11689580Smsmith    outb(port, c);
11789580Smsmith    if (c==0x0a)
11889580Smsmith    {
11989580Smsmith        while ((inb(port+5) & 0x20)==0);
12089580Smsmith        outb(port, 0x0d);
12189580Smsmith    }
12289580Smsmith}
12389580Smsmith
12489580Smsmithint ser_printf(const char *fmt, ...)
12589580Smsmith{
12689580Smsmith    va_list args;
12789580Smsmith    int i;
12889580Smsmith
12989580Smsmith    va_start(args,fmt);
13089580Smsmith    i = vsprintf(strbuf,fmt,args);
13189580Smsmith    ser_puts(strbuf);
13289580Smsmith    va_end(args);
13389580Smsmith    return i;
13489580Smsmith}
13589580Smsmith#endif
13689580Smsmith#endif
13789580Smsmith
13889580Smsmith/* The linked list of softc structures */
13989580Smsmithstruct gdt_softc_list gdt_softcs = TAILQ_HEAD_INITIALIZER(gdt_softcs);
14089580Smsmith/* controller cnt. */
14189580Smsmithint gdt_cnt = 0;
14289580Smsmith/* event buffer */
14389580Smsmithstatic gdt_evt_str ebuffer[GDT_MAX_EVENTS];
14489580Smsmithstatic int elastidx, eoldidx;
14589580Smsmith/* statistics */
14689580Smsmithgdt_statist_t gdt_stat;
14789580Smsmith
14889580Smsmith/* Definitions for our use of the SIM private CCB area */
14989580Smsmith#define ccb_sim_ptr     spriv_ptr0
15089580Smsmith#define ccb_priority    spriv_field1
15189580Smsmith
15289580Smsmithstatic void     iir_action(struct cam_sim *sim, union ccb *ccb);
15389580Smsmithstatic void     iir_poll(struct cam_sim *sim);
15489580Smsmithstatic void     iir_shutdown(void *arg, int howto);
15589580Smsmithstatic void     iir_timeout(void *arg);
15689580Smsmith
15789580Smsmithstatic void     gdt_eval_mapping(u_int32_t size, int *cyls, int *heads,
15889580Smsmith                                 int *secs);
15989580Smsmithstatic int      gdt_internal_cmd(struct gdt_softc *gdt, struct gdt_ccb *gccb,
16089580Smsmith                                 u_int8_t service, u_int16_t opcode,
16189580Smsmith                                 u_int32_t arg1, u_int32_t arg2, u_int32_t arg3);
16289580Smsmithstatic int      gdt_wait(struct gdt_softc *gdt, struct gdt_ccb *ccb,
16389580Smsmith                         int timeout);
16489580Smsmith
16589580Smsmithstatic struct gdt_ccb *gdt_get_ccb(struct gdt_softc *gdt);
16689580Smsmith
16789580Smsmithstatic int      gdt_sync_event(struct gdt_softc *gdt, int service,
16889580Smsmith                               u_int8_t index, struct gdt_ccb *gccb);
16989580Smsmithstatic int      gdt_async_event(struct gdt_softc *gdt, int service);
17089580Smsmithstatic struct gdt_ccb *gdt_raw_cmd(struct gdt_softc *gdt,
17189580Smsmith                                   union ccb *ccb, int *lock);
17289580Smsmithstatic struct gdt_ccb *gdt_cache_cmd(struct gdt_softc *gdt,
17389580Smsmith                                     union ccb *ccb, int *lock);
17489580Smsmithstatic struct gdt_ccb *gdt_ioctl_cmd(struct gdt_softc *gdt,
17589580Smsmith                                     gdt_ucmd_t *ucmd, int *lock);
17689580Smsmithstatic void     gdt_internal_cache_cmd(struct gdt_softc *gdt,union ccb *ccb);
17789580Smsmith
17889580Smsmithstatic void     gdtmapmem(void *arg, bus_dma_segment_t *dm_segs,
17989580Smsmith                          int nseg, int error);
18089580Smsmithstatic void     gdtexecuteccb(void *arg, bus_dma_segment_t *dm_segs,
18189580Smsmith                              int nseg, int error);
18289580Smsmith
18389580Smsmithint
18489580Smsmithiir_init(struct gdt_softc *gdt)
18589580Smsmith{
18689580Smsmith    u_int16_t cdev_cnt;
18789580Smsmith    int i, id, drv_cyls, drv_hds, drv_secs;
18889580Smsmith    struct gdt_ccb *gccb;
18989580Smsmith
19089580Smsmith    GDT_DPRINTF(GDT_D_DEBUG, ("iir_init()\n"));
19189580Smsmith
19289580Smsmith    gdt->sc_state = GDT_POLLING;
19389580Smsmith    gdt_clear_events();
19489580Smsmith    bzero(&gdt_stat, sizeof(gdt_statist_t));
19589580Smsmith
19689580Smsmith    SLIST_INIT(&gdt->sc_free_gccb);
19789580Smsmith    SLIST_INIT(&gdt->sc_pending_gccb);
19889580Smsmith    TAILQ_INIT(&gdt->sc_ccb_queue);
19989580Smsmith    TAILQ_INIT(&gdt->sc_ucmd_queue);
20089580Smsmith    TAILQ_INSERT_TAIL(&gdt_softcs, gdt, links);
20189580Smsmith
20289580Smsmith    /* DMA tag for mapping buffers into device visible space. */
20389580Smsmith    if (bus_dma_tag_create(gdt->sc_parent_dmat, /*alignment*/1, /*boundary*/0,
204114001Sscottl                           /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
20589580Smsmith                           /*highaddr*/BUS_SPACE_MAXADDR,
20689580Smsmith                           /*filter*/NULL, /*filterarg*/NULL,
20789580Smsmith                           /*maxsize*/MAXBSIZE, /*nsegments*/GDT_MAXSG,
20889580Smsmith                           /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
20989580Smsmith                           /*flags*/BUS_DMA_ALLOCNOW,
210117126Sscottl			   /*lockfunc*/busdma_lock_mutex, /*lockarg*/&Giant,
21189580Smsmith                           &gdt->sc_buffer_dmat) != 0) {
21289580Smsmith        printf("iir%d: bus_dma_tag_create(...,gdt->sc_buffer_dmat) failed\n",
21389580Smsmith               gdt->sc_hanum);
21489580Smsmith        return (1);
21589580Smsmith    }
21689580Smsmith    gdt->sc_init_level++;
21789580Smsmith
21889580Smsmith    /* DMA tag for our ccb structures */
219114001Sscottl    if (bus_dma_tag_create(gdt->sc_parent_dmat,
220114001Sscottl			   /*alignment*/1,
221114001Sscottl			   /*boundary*/0,
222114001Sscottl                           /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
22389580Smsmith                           /*highaddr*/BUS_SPACE_MAXADDR,
224114001Sscottl                           /*filter*/NULL,
225114001Sscottl			   /*filterarg*/NULL,
226156139Sscottl                           GDT_MAXCMDS * GDT_SCRATCH_SZ, /* maxsize */
22789580Smsmith                           /*nsegments*/1,
22889580Smsmith                           /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
229117126Sscottl			   /*flags*/0, /*lockfunc*/busdma_lock_mutex,
230156139Sscottl			   /*lockarg*/&Giant, &gdt->sc_gcscratch_dmat) != 0) {
231156139Sscottl        printf("iir%d: bus_dma_tag_create(...,gdt->sc_gcscratch_dmat) failed\n",
23289580Smsmith               gdt->sc_hanum);
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) {
24089580Smsmith        printf("iir%d: bus_dmamem_alloc(...,&gdt->sc_gccbs,...) failed\n",
24189580Smsmith               gdt->sc_hanum);
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) {
259156139Sscottl        printf("iir%d: no memory for gccbs.\n", gdt->sc_hanum);
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;
271156139Sscottl	gccb->gc_scratch = &gdt->sc_gcscratch[GDT_SCRATCH_SZ * i];
272156139Sscottl        gccb->gc_scratch_busbase = gdt->sc_gcscratch_busbase + GDT_SCRATCH_SZ * i;
273255871Sscottl	callout_handle_init(&gccb->gc_timeout_ch);
274156139Sscottl        SLIST_INSERT_HEAD(&gdt->sc_free_gccb, gccb, sle);
27589580Smsmith    }
27689580Smsmith    gdt->sc_init_level++;
27789580Smsmith
27889580Smsmith    /* create the control device */
27989580Smsmith    gdt->sc_dev = gdt_make_dev(gdt->sc_hanum);
28089580Smsmith
28189580Smsmith    /* allocate ccb for gdt_internal_cmd() */
28289580Smsmith    gccb = gdt_get_ccb(gdt);
28389580Smsmith    if (gccb == NULL) {
28489580Smsmith        printf("iir%d: No free command index found\n",
28589580Smsmith               gdt->sc_hanum);
28689580Smsmith        return (1);
28789580Smsmith    }
288156139Sscottl    bzero(gccb->gc_cmd, GDT_CMD_SZ);
28989580Smsmith
29089580Smsmith    if (!gdt_internal_cmd(gdt, gccb, GDT_SCREENSERVICE, GDT_INIT,
29189580Smsmith                          0, 0, 0)) {
29289580Smsmith        printf("iir%d: Screen service initialization error %d\n",
29389580Smsmith               gdt->sc_hanum, gdt->sc_status);
29489580Smsmith        gdt_free_ccb(gdt, gccb);
29589580Smsmith        return (1);
29689580Smsmith    }
29789580Smsmith
29889580Smsmith    gdt_internal_cmd(gdt, gccb, GDT_CACHESERVICE, GDT_UNFREEZE_IO,
29989580Smsmith                     0, 0, 0);
30089580Smsmith
30189580Smsmith    if (!gdt_internal_cmd(gdt, gccb, GDT_CACHESERVICE, GDT_INIT,
30289580Smsmith                          GDT_LINUX_OS, 0, 0)) {
303129449Sscottl        printf("iir%d: Cache service initialization error %d\n",
30489580Smsmith               gdt->sc_hanum, gdt->sc_status);
30589580Smsmith        gdt_free_ccb(gdt, gccb);
30689580Smsmith        return (1);
30789580Smsmith    }
30889580Smsmith    cdev_cnt = (u_int16_t)gdt->sc_info;
30989580Smsmith    gdt->sc_fw_vers = gdt->sc_service;
31089580Smsmith
31189580Smsmith    /* Detect number of buses */
31289580Smsmith    gdt_enc32(gccb->gc_scratch + GDT_IOC_VERSION, GDT_IOC_NEWEST);
31389580Smsmith    gccb->gc_scratch[GDT_IOC_LIST_ENTRIES] = GDT_MAXBUS;
31489580Smsmith    gccb->gc_scratch[GDT_IOC_FIRST_CHAN] = 0;
31589580Smsmith    gccb->gc_scratch[GDT_IOC_LAST_CHAN] = GDT_MAXBUS - 1;
31689580Smsmith    gdt_enc32(gccb->gc_scratch + GDT_IOC_LIST_OFFSET, GDT_IOC_HDR_SZ);
31789580Smsmith    if (gdt_internal_cmd(gdt, gccb, GDT_CACHESERVICE, GDT_IOCTL,
31889580Smsmith                         GDT_IOCHAN_RAW_DESC, GDT_INVALID_CHANNEL,
31989580Smsmith                         GDT_IOC_HDR_SZ + GDT_MAXBUS * GDT_RAWIOC_SZ)) {
32089580Smsmith        gdt->sc_bus_cnt = gccb->gc_scratch[GDT_IOC_CHAN_COUNT];
32189580Smsmith        for (i = 0; i < gdt->sc_bus_cnt; i++) {
32289580Smsmith            id = gccb->gc_scratch[GDT_IOC_HDR_SZ +
32389580Smsmith                                 i * GDT_RAWIOC_SZ + GDT_RAWIOC_PROC_ID];
32489580Smsmith            gdt->sc_bus_id[i] = id < GDT_MAXID_FC ? id : 0xff;
32589580Smsmith        }
32689580Smsmith    } else {
32789580Smsmith        /* New method failed, use fallback. */
32889580Smsmith        for (i = 0; i < GDT_MAXBUS; i++) {
32989580Smsmith            gdt_enc32(gccb->gc_scratch + GDT_GETCH_CHANNEL_NO, i);
33089580Smsmith            if (!gdt_internal_cmd(gdt, gccb, GDT_CACHESERVICE, GDT_IOCTL,
33189580Smsmith                                  GDT_SCSI_CHAN_CNT | GDT_L_CTRL_PATTERN,
33289580Smsmith                                  GDT_IO_CHANNEL | GDT_INVALID_CHANNEL,
33389580Smsmith                                  GDT_GETCH_SZ)) {
33489580Smsmith                if (i == 0) {
33589580Smsmith                    printf("iir%d: Cannot get channel count, "
33689580Smsmith                           "error %d\n", gdt->sc_hanum, gdt->sc_status);
33789580Smsmith                    gdt_free_ccb(gdt, gccb);
33889580Smsmith                    return (1);
33989580Smsmith                }
34089580Smsmith                break;
34189580Smsmith            }
34289580Smsmith            gdt->sc_bus_id[i] =
34389580Smsmith                (gccb->gc_scratch[GDT_GETCH_SIOP_ID] < GDT_MAXID_FC) ?
34489580Smsmith                gccb->gc_scratch[GDT_GETCH_SIOP_ID] : 0xff;
34589580Smsmith        }
34689580Smsmith        gdt->sc_bus_cnt = i;
34789580Smsmith    }
34889580Smsmith    /* add one "virtual" channel for the host drives */
34989580Smsmith    gdt->sc_virt_bus = gdt->sc_bus_cnt;
35089580Smsmith    gdt->sc_bus_cnt++;
35189580Smsmith
35289580Smsmith    if (!gdt_internal_cmd(gdt, gccb, GDT_SCSIRAWSERVICE, GDT_INIT,
35389580Smsmith                          0, 0, 0)) {
35489580Smsmith            printf("iir%d: Raw service initialization error %d\n",
35589580Smsmith                   gdt->sc_hanum, gdt->sc_status);
35689580Smsmith            gdt_free_ccb(gdt, gccb);
35789580Smsmith            return (1);
35889580Smsmith    }
35989580Smsmith
36089580Smsmith    /* Set/get features raw service (scatter/gather) */
36189580Smsmith    gdt->sc_raw_feat = 0;
36289580Smsmith    if (gdt_internal_cmd(gdt, gccb, GDT_SCSIRAWSERVICE, GDT_SET_FEAT,
36389580Smsmith                         GDT_SCATTER_GATHER, 0, 0)) {
36489580Smsmith        if (gdt_internal_cmd(gdt, gccb, GDT_SCSIRAWSERVICE, GDT_GET_FEAT,
36589580Smsmith                             0, 0, 0)) {
36689580Smsmith            gdt->sc_raw_feat = gdt->sc_info;
36789580Smsmith            if (!(gdt->sc_info & GDT_SCATTER_GATHER)) {
36889580Smsmith                panic("iir%d: Scatter/Gather Raw Service "
36989580Smsmith                      "required but not supported!\n", gdt->sc_hanum);
37089580Smsmith                gdt_free_ccb(gdt, gccb);
37189580Smsmith                return (1);
37289580Smsmith            }
37389580Smsmith        }
37489580Smsmith    }
37589580Smsmith
37689580Smsmith    /* Set/get features cache service (scatter/gather) */
37789580Smsmith    gdt->sc_cache_feat = 0;
37889580Smsmith    if (gdt_internal_cmd(gdt, gccb, GDT_CACHESERVICE, GDT_SET_FEAT,
37989580Smsmith                         0, GDT_SCATTER_GATHER, 0)) {
38089580Smsmith        if (gdt_internal_cmd(gdt, gccb, GDT_CACHESERVICE, GDT_GET_FEAT,
38189580Smsmith                             0, 0, 0)) {
38289580Smsmith            gdt->sc_cache_feat = gdt->sc_info;
38389580Smsmith            if (!(gdt->sc_info & GDT_SCATTER_GATHER)) {
38489580Smsmith                panic("iir%d: Scatter/Gather Cache Service "
38589580Smsmith                  "required but not supported!\n", gdt->sc_hanum);
38689580Smsmith                gdt_free_ccb(gdt, gccb);
38789580Smsmith                return (1);
38889580Smsmith            }
38989580Smsmith        }
39089580Smsmith    }
39189580Smsmith
392114001Sscottl    /* OEM */
393114001Sscottl    gdt_enc32(gccb->gc_scratch + GDT_OEM_VERSION, 0x01);
394114001Sscottl    gdt_enc32(gccb->gc_scratch + GDT_OEM_BUFSIZE, sizeof(gdt_oem_record_t));
395114001Sscottl    if (gdt_internal_cmd(gdt, gccb, GDT_CACHESERVICE, GDT_IOCTL,
396114001Sscottl                         GDT_OEM_STR_RECORD, GDT_INVALID_CHANNEL,
397114001Sscottl                         sizeof(gdt_oem_str_record_t))) {
398114001Sscottl	    strncpy(gdt->oem_name, ((gdt_oem_str_record_t *)
399114001Sscottl            gccb->gc_scratch)->text.scsi_host_drive_inquiry_vendor_id, 7);
400114001Sscottl		gdt->oem_name[7]='\0';
401114001Sscottl	} else {
402114001Sscottl		/* Old method, based on PCI ID */
403254379Sjkim		if (gdt->sc_vendor == INTEL_VENDOR_ID_IIR)
404114001Sscottl            strcpy(gdt->oem_name,"Intel  ");
405114001Sscottl        else
406114001Sscottl       	    strcpy(gdt->oem_name,"ICP    ");
407114001Sscottl    }
408114001Sscottl
40989580Smsmith    /* Scan for cache devices */
41089580Smsmith    for (i = 0; i < cdev_cnt && i < GDT_MAX_HDRIVES; i++) {
41189580Smsmith        if (gdt_internal_cmd(gdt, gccb, GDT_CACHESERVICE, GDT_INFO,
41289580Smsmith                             i, 0, 0)) {
41389580Smsmith            gdt->sc_hdr[i].hd_present = 1;
41489580Smsmith            gdt->sc_hdr[i].hd_size = gdt->sc_info;
41589580Smsmith
41689580Smsmith            /*
41789580Smsmith             * Evaluate mapping (sectors per head, heads per cyl)
41889580Smsmith             */
41989580Smsmith            gdt->sc_hdr[i].hd_size &= ~GDT_SECS32;
42089580Smsmith            if (gdt->sc_info2 == 0)
42189580Smsmith                gdt_eval_mapping(gdt->sc_hdr[i].hd_size,
42289580Smsmith                                 &drv_cyls, &drv_hds, &drv_secs);
42389580Smsmith            else {
42489580Smsmith                drv_hds = gdt->sc_info2 & 0xff;
42589580Smsmith                drv_secs = (gdt->sc_info2 >> 8) & 0xff;
42689580Smsmith                drv_cyls = gdt->sc_hdr[i].hd_size / drv_hds /
42789580Smsmith                    drv_secs;
42889580Smsmith            }
42989580Smsmith            gdt->sc_hdr[i].hd_heads = drv_hds;
43089580Smsmith            gdt->sc_hdr[i].hd_secs = drv_secs;
43189580Smsmith            /* Round the size */
43289580Smsmith            gdt->sc_hdr[i].hd_size = drv_cyls * drv_hds * drv_secs;
43389580Smsmith
43489580Smsmith            if (gdt_internal_cmd(gdt, gccb, GDT_CACHESERVICE,
43589580Smsmith                                 GDT_DEVTYPE, i, 0, 0))
43689580Smsmith                gdt->sc_hdr[i].hd_devtype = gdt->sc_info;
43789580Smsmith        }
43889580Smsmith    }
43989580Smsmith
44089580Smsmith    GDT_DPRINTF(GDT_D_INIT, ("dpmem %x %d-bus %d cache device%s\n",
44189580Smsmith                             gdt->sc_dpmembase,
44289580Smsmith                             gdt->sc_bus_cnt, cdev_cnt,
44389580Smsmith                             cdev_cnt == 1 ? "" : "s"));
44489580Smsmith    gdt_free_ccb(gdt, gccb);
44589580Smsmith
44689580Smsmith    gdt_cnt++;
44789580Smsmith    return (0);
44889580Smsmith}
44989580Smsmith
45089580Smsmithvoid
45189580Smsmithiir_free(struct gdt_softc *gdt)
45289580Smsmith{
45389580Smsmith    int i;
45489580Smsmith
45589580Smsmith    GDT_DPRINTF(GDT_D_INIT, ("iir_free()\n"));
45689580Smsmith
45789580Smsmith    switch (gdt->sc_init_level) {
45889580Smsmith      default:
45989580Smsmith        gdt_destroy_dev(gdt->sc_dev);
46089580Smsmith      case 5:
46189580Smsmith        for (i = GDT_MAXCMDS-1; i >= 0; i--)
46289580Smsmith            if (gdt->sc_gccbs[i].gc_map_flag)
46389580Smsmith                bus_dmamap_destroy(gdt->sc_buffer_dmat,
46489580Smsmith                                   gdt->sc_gccbs[i].gc_dmamap);
465156139Sscottl        bus_dmamap_unload(gdt->sc_gcscratch_dmat, gdt->sc_gcscratch_dmamap);
466156139Sscottl        free(gdt->sc_gccbs, M_GDTBUF);
46789580Smsmith      case 4:
468156139Sscottl        bus_dmamem_free(gdt->sc_gcscratch_dmat, gdt->sc_gcscratch, gdt->sc_gcscratch_dmamap);
46989580Smsmith      case 3:
470156139Sscottl        bus_dma_tag_destroy(gdt->sc_gcscratch_dmat);
47189580Smsmith      case 2:
47289580Smsmith        bus_dma_tag_destroy(gdt->sc_buffer_dmat);
47389580Smsmith      case 1:
47489580Smsmith        bus_dma_tag_destroy(gdt->sc_parent_dmat);
47589580Smsmith      case 0:
47689580Smsmith        break;
47789580Smsmith    }
47889580Smsmith    TAILQ_REMOVE(&gdt_softcs, gdt, links);
47989580Smsmith}
48089580Smsmith
48189580Smsmithvoid
48289580Smsmithiir_attach(struct gdt_softc *gdt)
48389580Smsmith{
48489580Smsmith    struct cam_devq *devq;
48589580Smsmith    int i;
48689580Smsmith
48789580Smsmith    GDT_DPRINTF(GDT_D_INIT, ("iir_attach()\n"));
48889580Smsmith
48989580Smsmith    /*
49089580Smsmith     * Create the device queue for our SIM.
491156139Sscottl     * XXX Throttle this down since the card has problems under load.
49289580Smsmith     */
493156139Sscottl    devq = cam_simq_alloc(32);
49489580Smsmith    if (devq == NULL)
49589580Smsmith        return;
49689580Smsmith
49789580Smsmith    for (i = 0; i < gdt->sc_bus_cnt; i++) {
49889580Smsmith        /*
49989580Smsmith         * Construct our SIM entry
50089580Smsmith         */
50189580Smsmith        gdt->sims[i] = cam_sim_alloc(iir_action, iir_poll, "iir",
502168752Sscottl                                     gdt, gdt->sc_hanum, &Giant,
503168752Sscottl				     /*untagged*/1,
50489580Smsmith                                     /*tagged*/GDT_MAXCMDS, devq);
505170872Sscottl        if (xpt_bus_register(gdt->sims[i], gdt->sc_devnode, i) != CAM_SUCCESS) {
50689580Smsmith            cam_sim_free(gdt->sims[i], /*free_devq*/i == 0);
50789580Smsmith            break;
50889580Smsmith        }
50989580Smsmith
51089580Smsmith        if (xpt_create_path(&gdt->paths[i], /*periph*/NULL,
51189580Smsmith                            cam_sim_path(gdt->sims[i]),
51289580Smsmith                            CAM_TARGET_WILDCARD,
51389580Smsmith                            CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
51489580Smsmith            xpt_bus_deregister(cam_sim_path(gdt->sims[i]));
51589580Smsmith            cam_sim_free(gdt->sims[i], /*free_devq*/i == 0);
51689580Smsmith            break;
51789580Smsmith        }
51889580Smsmith    }
51989580Smsmith    if (i > 0)
52089580Smsmith        EVENTHANDLER_REGISTER(shutdown_final, iir_shutdown,
52189580Smsmith                              gdt, SHUTDOWN_PRI_DEFAULT);
52289580Smsmith    /* iir_watchdog(gdt); */
52389580Smsmith    gdt->sc_state = GDT_NORMAL;
52489580Smsmith}
52589580Smsmith
52689580Smsmithstatic void
52789580Smsmithgdt_eval_mapping(u_int32_t size, int *cyls, int *heads, int *secs)
52889580Smsmith{
52989580Smsmith    *cyls = size / GDT_HEADS / GDT_SECS;
53089580Smsmith    if (*cyls < GDT_MAXCYLS) {
53189580Smsmith        *heads = GDT_HEADS;
53289580Smsmith        *secs = GDT_SECS;
53389580Smsmith    } else {
53489580Smsmith        /* Too high for 64 * 32 */
53589580Smsmith        *cyls = size / GDT_MEDHEADS / GDT_MEDSECS;
53689580Smsmith        if (*cyls < GDT_MAXCYLS) {
53789580Smsmith            *heads = GDT_MEDHEADS;
53889580Smsmith            *secs = GDT_MEDSECS;
53989580Smsmith        } else {
54089580Smsmith            /* Too high for 127 * 63 */
54189580Smsmith            *cyls = size / GDT_BIGHEADS / GDT_BIGSECS;
54289580Smsmith            *heads = GDT_BIGHEADS;
54389580Smsmith            *secs = GDT_BIGSECS;
54489580Smsmith        }
54589580Smsmith    }
54689580Smsmith}
54789580Smsmith
54889580Smsmithstatic int
54989580Smsmithgdt_wait(struct gdt_softc *gdt, struct gdt_ccb *gccb,
55089580Smsmith         int timeout)
55189580Smsmith{
55289580Smsmith    int rv = 0;
55389580Smsmith
55489580Smsmith    GDT_DPRINTF(GDT_D_INIT,
55589580Smsmith                ("gdt_wait(%p, %p, %d)\n", gdt, gccb, timeout));
55689580Smsmith
55789580Smsmith    gdt->sc_state |= GDT_POLL_WAIT;
55889580Smsmith    do {
55989580Smsmith        iir_intr(gdt);
56089580Smsmith        if (gdt == gdt_wait_gdt &&
56189580Smsmith            gccb->gc_cmd_index == gdt_wait_index) {
56289580Smsmith            rv = 1;
56389580Smsmith            break;
56489580Smsmith        }
56589580Smsmith        DELAY(1);
56689580Smsmith    } while (--timeout);
56789580Smsmith    gdt->sc_state &= ~GDT_POLL_WAIT;
56889580Smsmith
56989580Smsmith    while (gdt->sc_test_busy(gdt))
57089580Smsmith        DELAY(1);               /* XXX correct? */
57189580Smsmith
57289580Smsmith    return (rv);
57389580Smsmith}
57489580Smsmith
57589580Smsmithstatic int
57689580Smsmithgdt_internal_cmd(struct gdt_softc *gdt, struct gdt_ccb *gccb,
57789580Smsmith                 u_int8_t service, u_int16_t opcode,
57889580Smsmith                 u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
57989580Smsmith{
58089580Smsmith    int retries;
58189580Smsmith
58289580Smsmith    GDT_DPRINTF(GDT_D_CMD, ("gdt_internal_cmd(%p, %d, %d, %d, %d, %d)\n",
58389580Smsmith                            gdt, service, opcode, arg1, arg2, arg3));
58489580Smsmith
585156139Sscottl    bzero(gccb->gc_cmd, GDT_CMD_SZ);
58689580Smsmith
58789580Smsmith    for (retries = GDT_RETRIES; ; ) {
58889580Smsmith        gccb->gc_service = service;
58989580Smsmith        gccb->gc_flags = GDT_GCF_INTERNAL;
59089580Smsmith
591156139Sscottl        gdt_enc32(gccb->gc_cmd + GDT_CMD_COMMANDINDEX,
59289580Smsmith                  gccb->gc_cmd_index);
593156139Sscottl        gdt_enc16(gccb->gc_cmd + GDT_CMD_OPCODE, opcode);
59489580Smsmith
59589580Smsmith        switch (service) {
59689580Smsmith          case GDT_CACHESERVICE:
59789580Smsmith            if (opcode == GDT_IOCTL) {
598156139Sscottl                gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION +
59989580Smsmith                          GDT_IOCTL_SUBFUNC, arg1);
600156139Sscottl                gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION +
60189580Smsmith                          GDT_IOCTL_CHANNEL, arg2);
602156139Sscottl                gdt_enc16(gccb->gc_cmd + GDT_CMD_UNION +
60389580Smsmith                          GDT_IOCTL_PARAM_SIZE, (u_int16_t)arg3);
604156139Sscottl                gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_IOCTL_P_PARAM,
605156139Sscottl                          gccb->gc_scratch_busbase);
60689580Smsmith            } else {
607156139Sscottl                gdt_enc16(gccb->gc_cmd + GDT_CMD_UNION +
60889580Smsmith                          GDT_CACHE_DEVICENO, (u_int16_t)arg1);
609156139Sscottl                gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION +
61089580Smsmith                          GDT_CACHE_BLOCKNO, arg2);
61189580Smsmith            }
61289580Smsmith            break;
61389580Smsmith
61489580Smsmith          case GDT_SCSIRAWSERVICE:
615156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION +
61689580Smsmith                      GDT_RAW_DIRECTION, arg1);
617156139Sscottl            gccb->gc_cmd[GDT_CMD_UNION + GDT_RAW_BUS] =
61889580Smsmith                (u_int8_t)arg2;
619156139Sscottl            gccb->gc_cmd[GDT_CMD_UNION + GDT_RAW_TARGET] =
62089580Smsmith                (u_int8_t)arg3;
621156139Sscottl            gccb->gc_cmd[GDT_CMD_UNION + GDT_RAW_LUN] =
62289580Smsmith                (u_int8_t)(arg3 >> 8);
62389580Smsmith        }
62489580Smsmith
625156139Sscottl        gdt->sc_set_sema0(gdt);
626156139Sscottl        gccb->gc_cmd_len = GDT_CMD_SZ;
62789580Smsmith        gdt->sc_cmd_off = 0;
62889580Smsmith        gdt->sc_cmd_cnt = 0;
62989580Smsmith        gdt->sc_copy_cmd(gdt, gccb);
63089580Smsmith        gdt->sc_release_event(gdt);
63189580Smsmith        DELAY(20);
63289580Smsmith        if (!gdt_wait(gdt, gccb, GDT_POLL_TIMEOUT))
63389580Smsmith            return (0);
63489580Smsmith        if (gdt->sc_status != GDT_S_BSY || --retries == 0)
63589580Smsmith            break;
63689580Smsmith        DELAY(1);
63789580Smsmith    }
63889580Smsmith    return (gdt->sc_status == GDT_S_OK);
63989580Smsmith}
64089580Smsmith
64189580Smsmithstatic struct gdt_ccb *
64289580Smsmithgdt_get_ccb(struct gdt_softc *gdt)
64389580Smsmith{
64489580Smsmith    struct gdt_ccb *gccb;
64589580Smsmith    int lock;
64689580Smsmith
64789580Smsmith    GDT_DPRINTF(GDT_D_QUEUE, ("gdt_get_ccb(%p)\n", gdt));
64889580Smsmith
64989580Smsmith    lock = splcam();
65089580Smsmith    gccb = SLIST_FIRST(&gdt->sc_free_gccb);
65189580Smsmith    if (gccb != NULL) {
65289580Smsmith        SLIST_REMOVE_HEAD(&gdt->sc_free_gccb, sle);
65389580Smsmith        SLIST_INSERT_HEAD(&gdt->sc_pending_gccb, gccb, sle);
65489580Smsmith        ++gdt_stat.cmd_index_act;
65589580Smsmith        if (gdt_stat.cmd_index_act > gdt_stat.cmd_index_max)
65689580Smsmith            gdt_stat.cmd_index_max = gdt_stat.cmd_index_act;
65789580Smsmith    }
65889580Smsmith    splx(lock);
65989580Smsmith    return (gccb);
66089580Smsmith}
66189580Smsmith
66289580Smsmithvoid
66389580Smsmithgdt_free_ccb(struct gdt_softc *gdt, struct gdt_ccb *gccb)
66489580Smsmith{
66589580Smsmith    int lock;
66689580Smsmith
66789580Smsmith    GDT_DPRINTF(GDT_D_QUEUE, ("gdt_free_ccb(%p, %p)\n", gdt, gccb));
66889580Smsmith
66989580Smsmith    lock = splcam();
67089580Smsmith    gccb->gc_flags = GDT_GCF_UNUSED;
67189580Smsmith    SLIST_REMOVE(&gdt->sc_pending_gccb, gccb, gdt_ccb, sle);
67289580Smsmith    SLIST_INSERT_HEAD(&gdt->sc_free_gccb, gccb, sle);
67389580Smsmith    --gdt_stat.cmd_index_act;
67489580Smsmith    splx(lock);
67589580Smsmith    if (gdt->sc_state & GDT_SHUTDOWN)
67689580Smsmith        wakeup(gccb);
67789580Smsmith}
67889580Smsmith
67989580Smsmithvoid
68089580Smsmithgdt_next(struct gdt_softc *gdt)
68189580Smsmith{
68289580Smsmith    int lock;
68389580Smsmith    union ccb *ccb;
68489580Smsmith    gdt_ucmd_t *ucmd;
68589580Smsmith    struct cam_sim *sim;
68689580Smsmith    int bus, target, lun;
68789580Smsmith    int next_cmd;
68889580Smsmith
68989580Smsmith    struct ccb_scsiio *csio;
69089580Smsmith    struct ccb_hdr *ccbh;
69189580Smsmith    struct gdt_ccb *gccb = NULL;
69289580Smsmith    u_int8_t cmd;
69389580Smsmith
69489580Smsmith    GDT_DPRINTF(GDT_D_QUEUE, ("gdt_next(%p)\n", gdt));
69589580Smsmith
69689580Smsmith    lock = splcam();
69789580Smsmith    if (gdt->sc_test_busy(gdt)) {
69889580Smsmith        if (!(gdt->sc_state & GDT_POLLING)) {
69989580Smsmith            splx(lock);
70089580Smsmith            return;
70189580Smsmith        }
70289580Smsmith        while (gdt->sc_test_busy(gdt))
70389580Smsmith            DELAY(1);
70489580Smsmith    }
70589580Smsmith
70689580Smsmith    gdt->sc_cmd_cnt = gdt->sc_cmd_off = 0;
70789580Smsmith    next_cmd = TRUE;
70889580Smsmith    for (;;) {
70989580Smsmith        /* I/Os in queue? controller ready? */
71089580Smsmith        if (!TAILQ_FIRST(&gdt->sc_ucmd_queue) &&
71189580Smsmith            !TAILQ_FIRST(&gdt->sc_ccb_queue))
71289580Smsmith            break;
71389580Smsmith
71489580Smsmith        /* 1.: I/Os without ccb (IOCTLs) */
71589580Smsmith        ucmd = TAILQ_FIRST(&gdt->sc_ucmd_queue);
71689580Smsmith        if (ucmd != NULL) {
71789580Smsmith            TAILQ_REMOVE(&gdt->sc_ucmd_queue, ucmd, links);
71889580Smsmith            if ((gccb = gdt_ioctl_cmd(gdt, ucmd, &lock)) == NULL) {
71989580Smsmith                TAILQ_INSERT_HEAD(&gdt->sc_ucmd_queue, ucmd, links);
72089580Smsmith                break;
72189580Smsmith            }
72289580Smsmith            break;
72389580Smsmith            /* wenn mehrere Kdos. zulassen: if (!gdt_polling) continue; */
72489580Smsmith        }
72589580Smsmith
72689580Smsmith        /* 2.: I/Os with ccb */
72789580Smsmith        ccb = (union ccb *)TAILQ_FIRST(&gdt->sc_ccb_queue);
72889580Smsmith        /* ist dann immer != NULL, da oben getestet */
72989580Smsmith        sim = (struct cam_sim *)ccb->ccb_h.ccb_sim_ptr;
73089580Smsmith        bus = cam_sim_bus(sim);
73189580Smsmith        target = ccb->ccb_h.target_id;
73289580Smsmith        lun = ccb->ccb_h.target_lun;
73389580Smsmith
73489580Smsmith        TAILQ_REMOVE(&gdt->sc_ccb_queue, &ccb->ccb_h, sim_links.tqe);
73589580Smsmith        --gdt_stat.req_queue_act;
73689580Smsmith        /* ccb->ccb_h.func_code is XPT_SCSI_IO */
73789580Smsmith        GDT_DPRINTF(GDT_D_QUEUE, ("XPT_SCSI_IO flags 0x%x)\n",
73889580Smsmith                                  ccb->ccb_h.flags));
73989580Smsmith        csio = &ccb->csio;
74089580Smsmith        ccbh = &ccb->ccb_h;
74189580Smsmith        cmd  = csio->cdb_io.cdb_bytes[0];
74289580Smsmith        /* Max CDB length is 12 bytes */
74389580Smsmith        if (csio->cdb_len > 12) {
74489580Smsmith            ccbh->status = CAM_REQ_INVALID;
74589580Smsmith            --gdt_stat.io_count_act;
74689580Smsmith            xpt_done(ccb);
74789580Smsmith        } else if (bus != gdt->sc_virt_bus) {
74889580Smsmith            /* raw service command */
74989580Smsmith            if ((gccb = gdt_raw_cmd(gdt, ccb, &lock)) == NULL) {
75089580Smsmith                TAILQ_INSERT_HEAD(&gdt->sc_ccb_queue, &ccb->ccb_h,
75189580Smsmith                                  sim_links.tqe);
75289580Smsmith                ++gdt_stat.req_queue_act;
75389580Smsmith                if (gdt_stat.req_queue_act > gdt_stat.req_queue_max)
75489580Smsmith                    gdt_stat.req_queue_max = gdt_stat.req_queue_act;
75589580Smsmith                next_cmd = FALSE;
75689580Smsmith            }
75789580Smsmith        } else if (target >= GDT_MAX_HDRIVES ||
75889580Smsmith                   !gdt->sc_hdr[target].hd_present || lun != 0) {
759114001Sscottl            ccbh->status = CAM_DEV_NOT_THERE;
76089580Smsmith            --gdt_stat.io_count_act;
76189580Smsmith            xpt_done(ccb);
76289580Smsmith        } else {
76389580Smsmith            /* cache service command */
76489580Smsmith            if (cmd == READ_6  || cmd == WRITE_6 ||
76589580Smsmith                cmd == READ_10 || cmd == WRITE_10) {
76689580Smsmith                if ((gccb = gdt_cache_cmd(gdt, ccb, &lock)) == NULL) {
76789580Smsmith                    TAILQ_INSERT_HEAD(&gdt->sc_ccb_queue, &ccb->ccb_h,
76889580Smsmith                                      sim_links.tqe);
76989580Smsmith                    ++gdt_stat.req_queue_act;
77089580Smsmith                    if (gdt_stat.req_queue_act > gdt_stat.req_queue_max)
77189580Smsmith                        gdt_stat.req_queue_max = gdt_stat.req_queue_act;
77289580Smsmith                    next_cmd = FALSE;
77389580Smsmith                }
77489580Smsmith            } else {
77589580Smsmith                splx(lock);
77689580Smsmith                gdt_internal_cache_cmd(gdt, ccb);
77789580Smsmith                lock = splcam();
77889580Smsmith            }
77989580Smsmith        }
78089580Smsmith        if ((gdt->sc_state & GDT_POLLING) || !next_cmd)
78189580Smsmith            break;
78289580Smsmith    }
78389580Smsmith    if (gdt->sc_cmd_cnt > 0)
78489580Smsmith        gdt->sc_release_event(gdt);
78589580Smsmith
78689580Smsmith    splx(lock);
78789580Smsmith
78889580Smsmith    if ((gdt->sc_state & GDT_POLLING) && gdt->sc_cmd_cnt > 0) {
78989580Smsmith        gdt_wait(gdt, gccb, GDT_POLL_TIMEOUT);
79089580Smsmith    }
79189580Smsmith}
79289580Smsmith
79389580Smsmithstatic struct gdt_ccb *
79489580Smsmithgdt_raw_cmd(struct gdt_softc *gdt, union ccb *ccb, int *lock)
79589580Smsmith{
79689580Smsmith    struct gdt_ccb *gccb;
79789580Smsmith    struct cam_sim *sim;
798246713Skib    int error;
79989580Smsmith
80089580Smsmith    GDT_DPRINTF(GDT_D_CMD, ("gdt_raw_cmd(%p, %p)\n", gdt, ccb));
80189580Smsmith
80289580Smsmith    if (roundup(GDT_CMD_UNION + GDT_RAW_SZ, sizeof(u_int32_t)) +
80389580Smsmith        gdt->sc_cmd_off + GDT_DPMEM_COMMAND_OFFSET >
80489580Smsmith        gdt->sc_ic_all_size) {
80589580Smsmith        GDT_DPRINTF(GDT_D_INVALID, ("iir%d: gdt_raw_cmd(): DPMEM overflow\n",
80689580Smsmith                                    gdt->sc_hanum));
80789580Smsmith        return (NULL);
80889580Smsmith    }
80989580Smsmith
81089580Smsmith    gccb = gdt_get_ccb(gdt);
81189580Smsmith    if (gccb == NULL) {
81289580Smsmith        GDT_DPRINTF(GDT_D_INVALID, ("iir%d: No free command index found\n",
81389580Smsmith                                    gdt->sc_hanum));
81489580Smsmith        return (gccb);
81589580Smsmith    }
816156139Sscottl    bzero(gccb->gc_cmd, GDT_CMD_SZ);
81789580Smsmith    sim = (struct cam_sim *)ccb->ccb_h.ccb_sim_ptr;
81889580Smsmith    gccb->gc_ccb = ccb;
81989580Smsmith    gccb->gc_service = GDT_SCSIRAWSERVICE;
82089580Smsmith    gccb->gc_flags = GDT_GCF_SCSI;
82189580Smsmith
82289580Smsmith    if (gdt->sc_cmd_cnt == 0)
82389580Smsmith        gdt->sc_set_sema0(gdt);
82489580Smsmith    splx(*lock);
825156139Sscottl    gdt_enc32(gccb->gc_cmd + GDT_CMD_COMMANDINDEX,
82689580Smsmith              gccb->gc_cmd_index);
827156139Sscottl    gdt_enc16(gccb->gc_cmd + GDT_CMD_OPCODE, GDT_WRITE);
82889580Smsmith
829156139Sscottl    gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_DIRECTION,
83089580Smsmith              (ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN ?
83189580Smsmith              GDT_DATA_IN : GDT_DATA_OUT);
832156139Sscottl    gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SDLEN,
83389580Smsmith              ccb->csio.dxfer_len);
834156139Sscottl    gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_CLEN,
83589580Smsmith              ccb->csio.cdb_len);
836156139Sscottl    bcopy(ccb->csio.cdb_io.cdb_bytes, gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_CMD,
83789580Smsmith          ccb->csio.cdb_len);
838156139Sscottl    gccb->gc_cmd[GDT_CMD_UNION + GDT_RAW_TARGET] =
83989580Smsmith        ccb->ccb_h.target_id;
840156139Sscottl    gccb->gc_cmd[GDT_CMD_UNION + GDT_RAW_LUN] =
84189580Smsmith        ccb->ccb_h.target_lun;
842156139Sscottl    gccb->gc_cmd[GDT_CMD_UNION + GDT_RAW_BUS] =
84389580Smsmith        cam_sim_bus(sim);
844156139Sscottl    gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SENSE_LEN,
84589580Smsmith              sizeof(struct scsi_sense_data));
846156139Sscottl    gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SENSE_DATA,
847156139Sscottl              gccb->gc_scratch_busbase);
84889580Smsmith
849246713Skib    error = bus_dmamap_load_ccb(gdt->sc_buffer_dmat,
850246713Skib			        gccb->gc_dmamap,
851246713Skib			        ccb,
852246713Skib			        gdtexecuteccb,
853246713Skib			        gccb, /*flags*/0);
854246713Skib    if (error == EINPROGRESS) {
855246713Skib        xpt_freeze_simq(sim, 1);
856246713Skib        gccb->gc_ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
85789580Smsmith    }
85889580Smsmith
85989580Smsmith    *lock = splcam();
86089580Smsmith    return (gccb);
86189580Smsmith}
86289580Smsmith
86389580Smsmithstatic struct gdt_ccb *
86489580Smsmithgdt_cache_cmd(struct gdt_softc *gdt, union ccb *ccb, int *lock)
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) {
87889580Smsmith        GDT_DPRINTF(GDT_D_INVALID, ("iir%d: gdt_cache_cmd(): DPMEM overflow\n",
87989580Smsmith                                    gdt->sc_hanum));
88089580Smsmith        return (NULL);
88189580Smsmith    }
88289580Smsmith
88389580Smsmith    gccb = gdt_get_ccb(gdt);
88489580Smsmith    if (gccb == NULL) {
88589580Smsmith        GDT_DPRINTF(GDT_D_DEBUG, ("iir%d: No free command index found\n",
88689580Smsmith                                  gdt->sc_hanum));
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);
89789580Smsmith    splx(*lock);
898156139Sscottl    gdt_enc32(gccb->gc_cmd + GDT_CMD_COMMANDINDEX,
89989580Smsmith              gccb->gc_cmd_index);
90089580Smsmith    cmdp = ccb->csio.cdb_io.cdb_bytes;
90189580Smsmith    opcode = (*cmdp == WRITE_6 || *cmdp == WRITE_10) ? GDT_WRITE : GDT_READ;
90289580Smsmith    if ((gdt->sc_state & GDT_SHUTDOWN) && opcode == GDT_WRITE)
90389580Smsmith        opcode = GDT_WRITE_THR;
904156139Sscottl    gdt_enc16(gccb->gc_cmd + GDT_CMD_OPCODE, opcode);
90589580Smsmith
906156139Sscottl    gdt_enc16(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_DEVICENO,
90789580Smsmith              ccb->ccb_h.target_id);
90889580Smsmith    if (ccb->csio.cdb_len == 6) {
90989580Smsmith        struct scsi_rw_6 *rw = (struct scsi_rw_6 *)cmdp;
91089580Smsmith        blockno = scsi_3btoul(rw->addr) & ((SRW_TOPADDR<<16) | 0xffff);
91189580Smsmith        blockcnt = rw->length ? rw->length : 0x100;
91289580Smsmith    } else {
91389580Smsmith        struct scsi_rw_10 *rw = (struct scsi_rw_10 *)cmdp;
91489580Smsmith        blockno = scsi_4btoul(rw->addr);
91589580Smsmith        blockcnt = scsi_2btoul(rw->length);
91689580Smsmith    }
917156139Sscottl    gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_BLOCKNO,
91889580Smsmith              blockno);
919156139Sscottl    gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_BLOCKCNT,
92089580Smsmith              blockcnt);
92189580Smsmith
922246713Skib    error = bus_dmamap_load_ccb(gdt->sc_buffer_dmat,
92389580Smsmith                                gccb->gc_dmamap,
924246713Skib                                ccb,
92589580Smsmith                                gdtexecuteccb,
92689580Smsmith                                gccb, /*flags*/0);
927246713Skib    if (error == EINPROGRESS) {
928246713Skib        xpt_freeze_simq(sim, 1);
929246713Skib        gccb->gc_ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
93089580Smsmith    }
93189580Smsmith    *lock = splcam();
93289580Smsmith    return (gccb);
93389580Smsmith}
93489580Smsmith
93589580Smsmithstatic struct gdt_ccb *
93689580Smsmithgdt_ioctl_cmd(struct gdt_softc *gdt, gdt_ucmd_t *ucmd, int *lock)
93789580Smsmith{
93889580Smsmith    struct gdt_ccb *gccb;
93989580Smsmith    u_int32_t cnt;
94089580Smsmith
94189580Smsmith    GDT_DPRINTF(GDT_D_DEBUG, ("gdt_ioctl_cmd(%p, %p)\n", gdt, ucmd));
94289580Smsmith
94389580Smsmith    gccb = gdt_get_ccb(gdt);
94489580Smsmith    if (gccb == NULL) {
94589580Smsmith        GDT_DPRINTF(GDT_D_DEBUG, ("iir%d: No free command index found\n",
94689580Smsmith                                  gdt->sc_hanum));
94789580Smsmith        return (gccb);
94889580Smsmith    }
949156139Sscottl    bzero(gccb->gc_cmd, GDT_CMD_SZ);
95089580Smsmith    gccb->gc_ucmd = ucmd;
95189580Smsmith    gccb->gc_service = ucmd->service;
95289580Smsmith    gccb->gc_flags = GDT_GCF_IOCTL;
95389580Smsmith
95489580Smsmith    /* check DPMEM space, copy data buffer from user space */
95589580Smsmith    if (ucmd->service == GDT_CACHESERVICE) {
95689580Smsmith        if (ucmd->OpCode == GDT_IOCTL) {
957156139Sscottl            gccb->gc_cmd_len = roundup(GDT_CMD_UNION + GDT_IOCTL_SZ,
95889580Smsmith                                      sizeof(u_int32_t));
95989580Smsmith            cnt = ucmd->u.ioctl.param_size;
96089580Smsmith            if (cnt > GDT_SCRATCH_SZ) {
96189580Smsmith                printf("iir%d: Scratch buffer too small (%d/%d)\n",
96289580Smsmith                       gdt->sc_hanum, GDT_SCRATCH_SZ, cnt);
96389580Smsmith                gdt_free_ccb(gdt, gccb);
96489580Smsmith                return (NULL);
96589580Smsmith            }
96689580Smsmith        } else {
967156139Sscottl            gccb->gc_cmd_len = roundup(GDT_CMD_UNION + GDT_CACHE_SG_LST +
96889580Smsmith                                      GDT_SG_SZ, sizeof(u_int32_t));
96989580Smsmith            cnt = ucmd->u.cache.BlockCnt * GDT_SECTOR_SIZE;
97089580Smsmith            if (cnt > GDT_SCRATCH_SZ) {
97189580Smsmith                printf("iir%d: Scratch buffer too small (%d/%d)\n",
97289580Smsmith                       gdt->sc_hanum, GDT_SCRATCH_SZ, cnt);
97389580Smsmith                gdt_free_ccb(gdt, gccb);
97489580Smsmith                return (NULL);
97589580Smsmith            }
97689580Smsmith        }
97789580Smsmith    } else {
978156139Sscottl        gccb->gc_cmd_len = roundup(GDT_CMD_UNION + GDT_RAW_SG_LST +
97989580Smsmith                                  GDT_SG_SZ, sizeof(u_int32_t));
98089580Smsmith        cnt = ucmd->u.raw.sdlen;
98189580Smsmith        if (cnt + ucmd->u.raw.sense_len > GDT_SCRATCH_SZ) {
98289580Smsmith            printf("iir%d: Scratch buffer too small (%d/%d)\n",
98389580Smsmith                   gdt->sc_hanum, GDT_SCRATCH_SZ, cnt + ucmd->u.raw.sense_len);
98489580Smsmith            gdt_free_ccb(gdt, gccb);
98589580Smsmith            return (NULL);
98689580Smsmith        }
98789580Smsmith    }
98889580Smsmith    if (cnt != 0)
98989580Smsmith        bcopy(ucmd->data, gccb->gc_scratch, cnt);
99089580Smsmith
991156139Sscottl    if (gdt->sc_cmd_off + gccb->gc_cmd_len + GDT_DPMEM_COMMAND_OFFSET >
99289580Smsmith        gdt->sc_ic_all_size) {
99389580Smsmith        GDT_DPRINTF(GDT_D_INVALID, ("iir%d: gdt_ioctl_cmd(): DPMEM overflow\n",
99489580Smsmith                                    gdt->sc_hanum));
99589580Smsmith        gdt_free_ccb(gdt, gccb);
99689580Smsmith        return (NULL);
99789580Smsmith    }
99889580Smsmith
99989580Smsmith    if (gdt->sc_cmd_cnt == 0)
100089580Smsmith        gdt->sc_set_sema0(gdt);
100189580Smsmith    splx(*lock);
100289580Smsmith
100389580Smsmith    /* fill cmd structure */
1004156139Sscottl    gdt_enc32(gccb->gc_cmd + GDT_CMD_COMMANDINDEX,
100589580Smsmith              gccb->gc_cmd_index);
1006156139Sscottl    gdt_enc16(gccb->gc_cmd + GDT_CMD_OPCODE,
100789580Smsmith              ucmd->OpCode);
100889580Smsmith
100989580Smsmith    if (ucmd->service == GDT_CACHESERVICE) {
101089580Smsmith        if (ucmd->OpCode == GDT_IOCTL) {
101189580Smsmith            /* IOCTL */
1012156139Sscottl            gdt_enc16(gccb->gc_cmd + GDT_CMD_UNION + GDT_IOCTL_PARAM_SIZE,
101389580Smsmith                      ucmd->u.ioctl.param_size);
1014156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_IOCTL_SUBFUNC,
101589580Smsmith                      ucmd->u.ioctl.subfunc);
1016156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_IOCTL_CHANNEL,
101789580Smsmith                      ucmd->u.ioctl.channel);
1018156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_IOCTL_P_PARAM,
1019156139Sscottl                      gccb->gc_scratch_busbase);
102089580Smsmith        } else {
102189580Smsmith            /* cache service command */
1022156139Sscottl            gdt_enc16(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_DEVICENO,
102389580Smsmith                      ucmd->u.cache.DeviceNo);
1024156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_BLOCKNO,
102589580Smsmith                      ucmd->u.cache.BlockNo);
1026156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_BLOCKCNT,
102789580Smsmith                      ucmd->u.cache.BlockCnt);
1028156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_DESTADDR,
102989580Smsmith                      0xffffffffUL);
1030156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_SG_CANZ,
103189580Smsmith                      1);
1032156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_SG_LST +
1033156139Sscottl                      GDT_SG_PTR, gccb->gc_scratch_busbase);
1034156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_SG_LST +
103589580Smsmith                      GDT_SG_LEN, ucmd->u.cache.BlockCnt * GDT_SECTOR_SIZE);
103689580Smsmith        }
103789580Smsmith    } else {
103889580Smsmith        /* raw service command */
1039156139Sscottl        gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_DIRECTION,
104089580Smsmith                  ucmd->u.raw.direction);
1041156139Sscottl        gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SDATA,
104289580Smsmith                  0xffffffffUL);
1043156139Sscottl        gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SDLEN,
104489580Smsmith                  ucmd->u.raw.sdlen);
1045156139Sscottl        gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_CLEN,
104689580Smsmith                  ucmd->u.raw.clen);
1047156139Sscottl        bcopy(ucmd->u.raw.cmd, gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_CMD,
104889580Smsmith              12);
1049156139Sscottl        gccb->gc_cmd[GDT_CMD_UNION + GDT_RAW_TARGET] =
105089580Smsmith            ucmd->u.raw.target;
1051156139Sscottl        gccb->gc_cmd[GDT_CMD_UNION + GDT_RAW_LUN] =
105289580Smsmith            ucmd->u.raw.lun;
1053156139Sscottl        gccb->gc_cmd[GDT_CMD_UNION + GDT_RAW_BUS] =
105489580Smsmith            ucmd->u.raw.bus;
1055156139Sscottl        gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SENSE_LEN,
105689580Smsmith                  ucmd->u.raw.sense_len);
1057156139Sscottl        gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SENSE_DATA,
1058156139Sscottl                  gccb->gc_scratch_busbase + ucmd->u.raw.sdlen);
1059156139Sscottl        gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SG_RANZ,
106089580Smsmith                  1);
1061156139Sscottl        gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SG_LST +
1062156139Sscottl                  GDT_SG_PTR, gccb->gc_scratch_busbase);
1063156139Sscottl        gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SG_LST +
106489580Smsmith                  GDT_SG_LEN, ucmd->u.raw.sdlen);
106589580Smsmith    }
106689580Smsmith
106789580Smsmith    *lock = splcam();
106889580Smsmith    gdt_stat.sg_count_act = 1;
106989580Smsmith    gdt->sc_copy_cmd(gdt, gccb);
107089580Smsmith    return (gccb);
107189580Smsmith}
107289580Smsmith
107389580Smsmithstatic void
107489580Smsmithgdt_internal_cache_cmd(struct gdt_softc *gdt,union ccb *ccb)
107589580Smsmith{
107689580Smsmith    int t;
107789580Smsmith
107889580Smsmith    t = ccb->ccb_h.target_id;
107989580Smsmith    GDT_DPRINTF(GDT_D_CMD, ("gdt_internal_cache_cmd(%p, %p, 0x%x, %d)\n",
108089580Smsmith        gdt, ccb, ccb->csio.cdb_io.cdb_bytes[0], t));
108189580Smsmith
108289580Smsmith    switch (ccb->csio.cdb_io.cdb_bytes[0]) {
108389580Smsmith      case TEST_UNIT_READY:
108489580Smsmith      case START_STOP:
108589580Smsmith        break;
108689580Smsmith      case REQUEST_SENSE:
108789580Smsmith        GDT_DPRINTF(GDT_D_MISC, ("REQUEST_SENSE\n"));
108889580Smsmith        break;
108989580Smsmith      case INQUIRY:
109089580Smsmith        {
1091175197Sscottl            struct scsi_inquiry_data inq;
1092175197Sscottl            size_t copylen = MIN(sizeof(inq), ccb->csio.dxfer_len);
109389580Smsmith
1094175197Sscottl            bzero(&inq, sizeof(inq));
1095175197Sscottl            inq.device = (gdt->sc_hdr[t].hd_devtype & 4) ?
109689580Smsmith                T_CDROM : T_DIRECT;
1097175197Sscottl            inq.dev_qual2 = (gdt->sc_hdr[t].hd_devtype & 1) ? 0x80 : 0;
1098175197Sscottl            inq.version = SCSI_REV_2;
1099175197Sscottl            inq.response_format = 2;
1100175197Sscottl            inq.additional_length = 32;
1101175197Sscottl            inq.flags = SID_CmdQue | SID_Sync;
1102175197Sscottl            strncpy(inq.vendor, gdt->oem_name, sizeof(inq.vendor));
1103175197Sscottl            snprintf(inq.product, sizeof(inq.product),
1104175197Sscottl                     "Host Drive   #%02d", t);
1105175197Sscottl            strncpy(inq.revision, "   ", sizeof(inq.revision));
1106175197Sscottl            bcopy(&inq, ccb->csio.data_ptr, copylen );
1107175197Sscottl            if( ccb->csio.dxfer_len > copylen )
1108175197Sscottl                bzero( ccb->csio.data_ptr+copylen,
1109175197Sscottl                       ccb->csio.dxfer_len - copylen );
111089580Smsmith            break;
111189580Smsmith        }
111289580Smsmith      case MODE_SENSE_6:
111389580Smsmith        {
111489580Smsmith            struct mpd_data {
111589580Smsmith                struct scsi_mode_hdr_6 hd;
111689580Smsmith                struct scsi_mode_block_descr bd;
111789580Smsmith                struct scsi_control_page cp;
1118175197Sscottl            } mpd;
1119175197Sscottl            size_t copylen = MIN(sizeof(mpd), ccb->csio.dxfer_len);
112089580Smsmith            u_int8_t page;
112189580Smsmith
1122175197Sscottl            /*mpd = (struct mpd_data *)ccb->csio.data_ptr;*/
1123175197Sscottl            bzero(&mpd, sizeof(mpd));
1124175197Sscottl            mpd.hd.datalen = sizeof(struct scsi_mode_hdr_6) +
112589580Smsmith                sizeof(struct scsi_mode_block_descr);
1126175197Sscottl            mpd.hd.dev_specific = (gdt->sc_hdr[t].hd_devtype & 2) ? 0x80 : 0;
1127175197Sscottl            mpd.hd.block_descr_len = sizeof(struct scsi_mode_block_descr);
1128175197Sscottl            mpd.bd.block_len[0] = (GDT_SECTOR_SIZE & 0x00ff0000) >> 16;
1129175197Sscottl            mpd.bd.block_len[1] = (GDT_SECTOR_SIZE & 0x0000ff00) >> 8;
1130175197Sscottl            mpd.bd.block_len[2] = (GDT_SECTOR_SIZE & 0x000000ff);
1131175197Sscottl
1132175197Sscottl            bcopy(&mpd, ccb->csio.data_ptr, copylen );
1133175197Sscottl            if( ccb->csio.dxfer_len > copylen )
1134175197Sscottl                bzero( ccb->csio.data_ptr+copylen,
1135175197Sscottl                       ccb->csio.dxfer_len - copylen );
113689580Smsmith            page=((struct scsi_mode_sense_6 *)ccb->csio.cdb_io.cdb_bytes)->page;
113789580Smsmith            switch (page) {
113889580Smsmith              default:
113989580Smsmith                GDT_DPRINTF(GDT_D_MISC, ("MODE_SENSE_6: page 0x%x\n", page));
114089580Smsmith                break;
114189580Smsmith            }
114289580Smsmith            break;
114389580Smsmith        }
114489580Smsmith      case READ_CAPACITY:
114589580Smsmith        {
1146175197Sscottl            struct scsi_read_capacity_data rcd;
1147175197Sscottl            size_t copylen = MIN(sizeof(rcd), ccb->csio.dxfer_len);
114889580Smsmith
1149175197Sscottl            /*rcd = (struct scsi_read_capacity_data *)ccb->csio.data_ptr;*/
1150175197Sscottl            bzero(&rcd, sizeof(rcd));
1151175197Sscottl            scsi_ulto4b(gdt->sc_hdr[t].hd_size - 1, rcd.addr);
1152175197Sscottl            scsi_ulto4b(GDT_SECTOR_SIZE, rcd.length);
1153175197Sscottl            bcopy(&rcd, ccb->csio.data_ptr, copylen );
1154175197Sscottl            if( ccb->csio.dxfer_len > copylen )
1155175197Sscottl                bzero( ccb->csio.data_ptr+copylen,
1156175197Sscottl                       ccb->csio.dxfer_len - copylen );
115789580Smsmith            break;
115889580Smsmith        }
115989580Smsmith      default:
116089580Smsmith        GDT_DPRINTF(GDT_D_MISC, ("gdt_internal_cache_cmd(%d) unknown\n",
116189580Smsmith                                    ccb->csio.cdb_io.cdb_bytes[0]));
116289580Smsmith        break;
116389580Smsmith    }
1164156139Sscottl    ccb->ccb_h.status |= CAM_REQ_CMP;
116589580Smsmith    --gdt_stat.io_count_act;
116689580Smsmith    xpt_done(ccb);
116789580Smsmith}
116889580Smsmith
116989580Smsmithstatic void
117089580Smsmithgdtmapmem(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
117189580Smsmith{
117289580Smsmith    bus_addr_t *busaddrp;
117389580Smsmith
117489580Smsmith    busaddrp = (bus_addr_t *)arg;
117589580Smsmith    *busaddrp = dm_segs->ds_addr;
117689580Smsmith}
117789580Smsmith
117889580Smsmithstatic void
117989580Smsmithgdtexecuteccb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
118089580Smsmith{
118189580Smsmith    struct gdt_ccb *gccb;
118289580Smsmith    union ccb *ccb;
118389580Smsmith    struct gdt_softc *gdt;
118489580Smsmith    int i, lock;
118589580Smsmith
118689580Smsmith    lock = splcam();
118789580Smsmith
118889580Smsmith    gccb = (struct gdt_ccb *)arg;
118989580Smsmith    ccb = gccb->gc_ccb;
119089580Smsmith    gdt = cam_sim_softc((struct cam_sim *)ccb->ccb_h.ccb_sim_ptr);
119189580Smsmith
119289580Smsmith    GDT_DPRINTF(GDT_D_CMD, ("gdtexecuteccb(%p, %p, %p, %d, %d)\n",
119389580Smsmith                            gdt, gccb, dm_segs, nseg, error));
119489580Smsmith    gdt_stat.sg_count_act = nseg;
119589580Smsmith    if (nseg > gdt_stat.sg_count_max)
119689580Smsmith        gdt_stat.sg_count_max = nseg;
119789580Smsmith
119889580Smsmith    /* Copy the segments into our SG list */
119989580Smsmith    if (gccb->gc_service == GDT_CACHESERVICE) {
120089580Smsmith        for (i = 0; i < nseg; ++i) {
1201156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_SG_LST +
120289580Smsmith                      i * GDT_SG_SZ + GDT_SG_PTR, dm_segs->ds_addr);
1203156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_SG_LST +
120489580Smsmith                      i * GDT_SG_SZ + GDT_SG_LEN, dm_segs->ds_len);
120589580Smsmith            dm_segs++;
120689580Smsmith        }
1207156139Sscottl        gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_SG_CANZ,
120889580Smsmith                  nseg);
1209156139Sscottl        gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_CACHE_DESTADDR,
121089580Smsmith                  0xffffffffUL);
121189580Smsmith
1212156139Sscottl        gccb->gc_cmd_len = roundup(GDT_CMD_UNION + GDT_CACHE_SG_LST +
121389580Smsmith                                  nseg * GDT_SG_SZ, sizeof(u_int32_t));
121489580Smsmith    } else {
121589580Smsmith        for (i = 0; i < nseg; ++i) {
1216156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SG_LST +
121789580Smsmith                      i * GDT_SG_SZ + GDT_SG_PTR, dm_segs->ds_addr);
1218156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SG_LST +
121989580Smsmith                      i * GDT_SG_SZ + GDT_SG_LEN, dm_segs->ds_len);
122089580Smsmith            dm_segs++;
122189580Smsmith        }
1222156139Sscottl        gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SG_RANZ,
122389580Smsmith                  nseg);
1224156139Sscottl        gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_RAW_SDATA,
122589580Smsmith                  0xffffffffUL);
122689580Smsmith
1227156139Sscottl        gccb->gc_cmd_len = roundup(GDT_CMD_UNION + GDT_RAW_SG_LST +
122889580Smsmith                                  nseg * GDT_SG_SZ, sizeof(u_int32_t));
122989580Smsmith    }
123089580Smsmith
123189580Smsmith    if (nseg != 0) {
1232114001Sscottl        bus_dmamap_sync(gdt->sc_buffer_dmat, gccb->gc_dmamap,
1233114001Sscottl            (ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN ?
1234114001Sscottl            BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
123589580Smsmith    }
123689580Smsmith
123789580Smsmith    /* We must NOT abort the command here if CAM_REQ_INPROG is not set,
123889580Smsmith     * because command semaphore is already set!
123989580Smsmith     */
124089580Smsmith
124189580Smsmith    ccb->ccb_h.status |= CAM_SIM_QUEUED;
124289580Smsmith    /* timeout handling */
1243255871Sscottl    gccb->gc_timeout_ch =
124489580Smsmith        timeout(iir_timeout, (caddr_t)gccb,
124589580Smsmith                (ccb->ccb_h.timeout * hz) / 1000);
124689580Smsmith
124789580Smsmith    gdt->sc_copy_cmd(gdt, gccb);
124889580Smsmith    splx(lock);
124989580Smsmith}
125089580Smsmith
125189580Smsmith
125289580Smsmithstatic void
125389580Smsmithiir_action( struct cam_sim *sim, union ccb *ccb )
125489580Smsmith{
125589580Smsmith    struct gdt_softc *gdt;
125689580Smsmith    int lock, bus, target, lun;
125789580Smsmith
125889580Smsmith    gdt = (struct gdt_softc *)cam_sim_softc( sim );
125989580Smsmith    ccb->ccb_h.ccb_sim_ptr = sim;
126089580Smsmith    bus = cam_sim_bus(sim);
126189580Smsmith    target = ccb->ccb_h.target_id;
126289580Smsmith    lun = ccb->ccb_h.target_lun;
126389580Smsmith    GDT_DPRINTF(GDT_D_CMD,
126489580Smsmith                ("iir_action(%p) func 0x%x cmd 0x%x bus %d target %d lun %d\n",
126589580Smsmith                 gdt, ccb->ccb_h.func_code, ccb->csio.cdb_io.cdb_bytes[0],
126689580Smsmith                 bus, target, lun));
126789580Smsmith    ++gdt_stat.io_count_act;
126889580Smsmith    if (gdt_stat.io_count_act > gdt_stat.io_count_max)
126989580Smsmith        gdt_stat.io_count_max = gdt_stat.io_count_act;
127089580Smsmith
127189580Smsmith    switch (ccb->ccb_h.func_code) {
127289580Smsmith      case XPT_SCSI_IO:
127389580Smsmith        lock = splcam();
127489580Smsmith        TAILQ_INSERT_TAIL(&gdt->sc_ccb_queue, &ccb->ccb_h, sim_links.tqe);
127589580Smsmith        ++gdt_stat.req_queue_act;
127689580Smsmith        if (gdt_stat.req_queue_act > gdt_stat.req_queue_max)
127789580Smsmith            gdt_stat.req_queue_max = gdt_stat.req_queue_act;
127889580Smsmith        splx(lock);
127989580Smsmith        gdt_next(gdt);
128089580Smsmith        break;
128189580Smsmith      case XPT_RESET_DEV:   /* Bus Device Reset the specified SCSI device */
128289580Smsmith      case XPT_ABORT:                       /* Abort the specified CCB */
128389580Smsmith        /* XXX Implement */
128489580Smsmith        ccb->ccb_h.status = CAM_REQ_INVALID;
128589580Smsmith        --gdt_stat.io_count_act;
128689580Smsmith        xpt_done(ccb);
128789580Smsmith        break;
128889580Smsmith      case XPT_SET_TRAN_SETTINGS:
128989580Smsmith        ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
129089580Smsmith        --gdt_stat.io_count_act;
129189580Smsmith        xpt_done(ccb);
129289580Smsmith        break;
129389580Smsmith      case XPT_GET_TRAN_SETTINGS:
129489580Smsmith        /* Get default/user set transfer settings for the target */
129589580Smsmith          {
1296163816Smjacob              struct        ccb_trans_settings *cts = &ccb->cts;
1297163816Smjacob              struct ccb_trans_settings_scsi *scsi = &cts->proto_specific.scsi;
1298163816Smjacob              struct ccb_trans_settings_spi *spi = &cts->xport_specific.spi;
1299163816Smjacob
1300163816Smjacob              cts->protocol = PROTO_SCSI;
1301163816Smjacob              cts->protocol_version = SCSI_REV_2;
1302163816Smjacob              cts->transport = XPORT_SPI;
1303163816Smjacob              cts->transport_version = 2;
1304163816Smjacob
1305163816Smjacob              if (cts->type == CTS_TYPE_USER_SETTINGS) {
1306163816Smjacob		  spi->flags = CTS_SPI_FLAGS_DISC_ENB;
1307163816Smjacob                  scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
1308163816Smjacob                  spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
1309163816Smjacob                  spi->sync_period = 25; /* 10MHz */
1310163816Smjacob                  if (spi->sync_period != 0)
1311163816Smjacob                      spi->sync_offset = 15;
1312163816Smjacob
1313163816Smjacob                  spi->valid = CTS_SPI_VALID_SYNC_RATE
1314163816Smjacob                      | CTS_SPI_VALID_SYNC_OFFSET
1315163816Smjacob                      | CTS_SPI_VALID_BUS_WIDTH
1316163816Smjacob                      | CTS_SPI_VALID_DISC;
1317163816Smjacob                  scsi->valid = CTS_SCSI_VALID_TQ;
1318163816Smjacob                  ccb->ccb_h.status = CAM_REQ_CMP;
1319163816Smjacob              } else {
1320163816Smjacob                  ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
1321163816Smjacob              }
132289580Smsmith              --gdt_stat.io_count_act;
132389580Smsmith              xpt_done(ccb);
132489580Smsmith              break;
132589580Smsmith          }
132689580Smsmith      case XPT_CALC_GEOMETRY:
132789580Smsmith          {
132889580Smsmith              struct ccb_calc_geometry *ccg;
132989580Smsmith              u_int32_t secs_per_cylinder;
133089580Smsmith
133189580Smsmith              ccg = &ccb->ccg;
133289580Smsmith              ccg->heads = gdt->sc_hdr[target].hd_heads;
133389580Smsmith              ccg->secs_per_track = gdt->sc_hdr[target].hd_secs;
133489580Smsmith              secs_per_cylinder = ccg->heads * ccg->secs_per_track;
133589580Smsmith              ccg->cylinders = ccg->volume_size / secs_per_cylinder;
133689580Smsmith              ccb->ccb_h.status = CAM_REQ_CMP;
133789580Smsmith              --gdt_stat.io_count_act;
133889580Smsmith              xpt_done(ccb);
133989580Smsmith              break;
134089580Smsmith          }
134189580Smsmith      case XPT_RESET_BUS:           /* Reset the specified SCSI bus */
134289580Smsmith          {
134389580Smsmith              /* XXX Implement */
134489580Smsmith              ccb->ccb_h.status = CAM_REQ_CMP;
134589580Smsmith              --gdt_stat.io_count_act;
134689580Smsmith              xpt_done(ccb);
134789580Smsmith              break;
134889580Smsmith          }
134989580Smsmith      case XPT_TERM_IO:             /* Terminate the I/O process */
135089580Smsmith        /* XXX Implement */
135189580Smsmith        ccb->ccb_h.status = CAM_REQ_INVALID;
135289580Smsmith        --gdt_stat.io_count_act;
135389580Smsmith        xpt_done(ccb);
135489580Smsmith        break;
135589580Smsmith      case XPT_PATH_INQ:            /* Path routing inquiry */
135689580Smsmith          {
135789580Smsmith              struct ccb_pathinq *cpi = &ccb->cpi;
135889580Smsmith
135989580Smsmith              cpi->version_num = 1;
136089580Smsmith              cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE;
136189580Smsmith              cpi->hba_inquiry |= PI_WIDE_16;
136289580Smsmith              cpi->target_sprt = 1;
136389580Smsmith              cpi->hba_misc = 0;
136489580Smsmith              cpi->hba_eng_cnt = 0;
136589580Smsmith              if (bus == gdt->sc_virt_bus)
136689580Smsmith                  cpi->max_target = GDT_MAX_HDRIVES - 1;
136789580Smsmith              else if (gdt->sc_class & GDT_FC)
136889580Smsmith                  cpi->max_target = GDT_MAXID_FC - 1;
136989580Smsmith              else
137089580Smsmith                  cpi->max_target = GDT_MAXID - 1;
137189580Smsmith              cpi->max_lun = 7;
137289580Smsmith              cpi->unit_number = cam_sim_unit(sim);
137389580Smsmith              cpi->bus_id = bus;
137489580Smsmith              cpi->initiator_id =
137589580Smsmith                  (bus == gdt->sc_virt_bus ? 127 : gdt->sc_bus_id[bus]);
137689580Smsmith              cpi->base_transfer_speed = 3300;
137789580Smsmith              strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
1378254379Sjkim              if (gdt->sc_vendor == INTEL_VENDOR_ID_IIR)
1379120477Sscottl                  strncpy(cpi->hba_vid, "Intel Corp.", HBA_IDLEN);
1380120477Sscottl              else
1381120477Sscottl                  strncpy(cpi->hba_vid, "ICP vortex ", HBA_IDLEN);
138289580Smsmith              strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
1383163816Smjacob              cpi->transport = XPORT_SPI;
1384163816Smjacob              cpi->transport_version = 2;
1385163816Smjacob              cpi->protocol = PROTO_SCSI;
1386163816Smjacob              cpi->protocol_version = SCSI_REV_2;
138789580Smsmith              cpi->ccb_h.status = CAM_REQ_CMP;
138889580Smsmith              --gdt_stat.io_count_act;
138989580Smsmith              xpt_done(ccb);
139089580Smsmith              break;
139189580Smsmith          }
139289580Smsmith      default:
139389580Smsmith        GDT_DPRINTF(GDT_D_INVALID, ("gdt_next(%p) cmd 0x%x invalid\n",
139489580Smsmith                                    gdt, ccb->ccb_h.func_code));
139589580Smsmith        ccb->ccb_h.status = CAM_REQ_INVALID;
139689580Smsmith        --gdt_stat.io_count_act;
139789580Smsmith        xpt_done(ccb);
139889580Smsmith        break;
139989580Smsmith    }
140089580Smsmith}
140189580Smsmith
140289580Smsmithstatic void
140389580Smsmithiir_poll( struct cam_sim *sim )
140489580Smsmith{
140589580Smsmith    struct gdt_softc *gdt;
140689580Smsmith
140789580Smsmith    gdt = (struct gdt_softc *)cam_sim_softc( sim );
140889580Smsmith    GDT_DPRINTF(GDT_D_CMD, ("iir_poll sim %p gdt %p\n", sim, gdt));
140989580Smsmith    iir_intr(gdt);
141089580Smsmith}
141189580Smsmith
141289580Smsmithstatic void
141389580Smsmithiir_timeout(void *arg)
141489580Smsmith{
1415156139Sscottl    GDT_DPRINTF(GDT_D_TIMEOUT, ("iir_timeout(%p)\n", gccb));
141689580Smsmith}
141789580Smsmith
141889580Smsmithstatic void
141989580Smsmithiir_shutdown( void *arg, int howto )
142089580Smsmith{
142189580Smsmith    struct gdt_softc *gdt;
142289580Smsmith    struct gdt_ccb *gccb;
142389580Smsmith    gdt_ucmd_t *ucmd;
142489580Smsmith    int lock, i;
142589580Smsmith
142689580Smsmith    gdt = (struct gdt_softc *)arg;
142789580Smsmith    GDT_DPRINTF(GDT_D_CMD, ("iir_shutdown(%p, %d)\n", gdt, howto));
142889580Smsmith
142989580Smsmith    printf("iir%d: Flushing all Host Drives. Please wait ...  ",
143089580Smsmith           gdt->sc_hanum);
143189580Smsmith
143289580Smsmith    /* allocate ucmd buffer */
1433156139Sscottl    ucmd = malloc(sizeof(gdt_ucmd_t), M_GDTBUF, M_NOWAIT);
143489580Smsmith    if (ucmd == NULL) {
143589580Smsmith        printf("iir%d: iir_shutdown(): Cannot allocate resource\n",
143689580Smsmith               gdt->sc_hanum);
143789580Smsmith        return;
143889580Smsmith    }
143989580Smsmith    bzero(ucmd, sizeof(gdt_ucmd_t));
144089580Smsmith
144189580Smsmith    /* wait for pending IOs */
144289580Smsmith    lock = splcam();
144389580Smsmith    gdt->sc_state = GDT_SHUTDOWN;
144489580Smsmith    splx(lock);
144589580Smsmith    if ((gccb = SLIST_FIRST(&gdt->sc_pending_gccb)) != NULL)
144689580Smsmith        (void) tsleep((void *)gccb, PCATCH | PRIBIO, "iirshw", 100 * hz);
144789580Smsmith
144889580Smsmith    /* flush */
144989580Smsmith    for (i = 0; i < GDT_MAX_HDRIVES; ++i) {
145089580Smsmith        if (gdt->sc_hdr[i].hd_present) {
145189580Smsmith            ucmd->service = GDT_CACHESERVICE;
145289580Smsmith            ucmd->OpCode = GDT_FLUSH;
145389580Smsmith            ucmd->u.cache.DeviceNo = i;
145489580Smsmith            lock = splcam();
145589580Smsmith            TAILQ_INSERT_TAIL(&gdt->sc_ucmd_queue, ucmd, links);
145689580Smsmith            ucmd->complete_flag = FALSE;
145789580Smsmith            splx(lock);
145889580Smsmith            gdt_next(gdt);
145989580Smsmith            if (!ucmd->complete_flag)
146089580Smsmith                (void) tsleep((void *)ucmd, PCATCH|PRIBIO, "iirshw", 10*hz);
146189580Smsmith        }
146289580Smsmith    }
146389580Smsmith
146489580Smsmith    free(ucmd, M_DEVBUF);
146589580Smsmith    printf("Done.\n");
146689580Smsmith}
146789580Smsmith
146889580Smsmithvoid
146989580Smsmithiir_intr(void *arg)
147089580Smsmith{
147189580Smsmith    struct gdt_softc *gdt = arg;
147289580Smsmith    struct gdt_intr_ctx ctx;
147389580Smsmith    int lock = 0;
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
148089580Smsmith    /* If polling and we were not called from gdt_wait, just return */
148189580Smsmith    if ((gdt->sc_state & GDT_POLLING) &&
148289580Smsmith        !(gdt->sc_state & GDT_POLL_WAIT))
148389580Smsmith        return;
148489580Smsmith
148589580Smsmith    if (!(gdt->sc_state & GDT_POLLING))
148689580Smsmith        lock = splcam();
148789580Smsmith    gdt_wait_index = 0;
148889580Smsmith
148989580Smsmith    ctx.istatus = gdt->sc_get_status(gdt);
1490156139Sscottl    if (ctx.istatus == 0x00) {
149189580Smsmith        if (!(gdt->sc_state & GDT_POLLING))
149289580Smsmith            splx(lock);
149389580Smsmith        gdt->sc_status = GDT_S_NO_STATUS;
149489580Smsmith        return;
149589580Smsmith    }
149689580Smsmith
149789580Smsmith    gdt->sc_intr(gdt, &ctx);
149889580Smsmith
149989580Smsmith    gdt->sc_status = ctx.cmd_status;
150089580Smsmith    gdt->sc_service = ctx.service;
150189580Smsmith    gdt->sc_info = ctx.info;
150289580Smsmith    gdt->sc_info2 = ctx.info2;
150389580Smsmith
150489580Smsmith    if (gdt->sc_state & GDT_POLL_WAIT) {
150589580Smsmith        gdt_wait_gdt = gdt;
150689580Smsmith        gdt_wait_index = ctx.istatus;
150789580Smsmith    }
150889580Smsmith
150989580Smsmith    if (ctx.istatus == GDT_ASYNCINDEX) {
151089580Smsmith        gdt_async_event(gdt, ctx.service);
151189580Smsmith        if (!(gdt->sc_state & GDT_POLLING))
151289580Smsmith            splx(lock);
151389580Smsmith        return;
151489580Smsmith    }
151589580Smsmith    if (ctx.istatus == GDT_SPEZINDEX) {
151689580Smsmith        GDT_DPRINTF(GDT_D_INVALID,
151789580Smsmith                    ("iir%d: Service unknown or not initialized!\n",
151889580Smsmith                     gdt->sc_hanum));
151989580Smsmith        gdt->sc_dvr.size = sizeof(gdt->sc_dvr.eu.driver);
152089580Smsmith        gdt->sc_dvr.eu.driver.ionode = gdt->sc_hanum;
152189580Smsmith        gdt_store_event(GDT_ES_DRIVER, 4, &gdt->sc_dvr);
152289580Smsmith        if (!(gdt->sc_state & GDT_POLLING))
152389580Smsmith            splx(lock);
152489580Smsmith        return;
152589580Smsmith    }
152689580Smsmith
152789580Smsmith    gccb = &gdt->sc_gccbs[ctx.istatus - 2];
152889580Smsmith    ctx.service = gccb->gc_service;
152989580Smsmith
153089580Smsmith    switch (gccb->gc_flags) {
153189580Smsmith      case GDT_GCF_UNUSED:
153289580Smsmith        GDT_DPRINTF(GDT_D_INVALID, ("iir%d: Index (%d) to unused command!\n",
153389580Smsmith                    gdt->sc_hanum, ctx.istatus));
153489580Smsmith        gdt->sc_dvr.size = sizeof(gdt->sc_dvr.eu.driver);
153589580Smsmith        gdt->sc_dvr.eu.driver.ionode = gdt->sc_hanum;
153689580Smsmith        gdt->sc_dvr.eu.driver.index = ctx.istatus;
153789580Smsmith        gdt_store_event(GDT_ES_DRIVER, 1, &gdt->sc_dvr);
153889580Smsmith        gdt_free_ccb(gdt, gccb);
153989580Smsmith        /* fallthrough */
154089580Smsmith
154189580Smsmith      case GDT_GCF_INTERNAL:
154289580Smsmith        if (!(gdt->sc_state & GDT_POLLING))
154389580Smsmith            splx(lock);
154489580Smsmith        break;
154589580Smsmith
154689580Smsmith      case GDT_GCF_IOCTL:
154789580Smsmith        ucmd = gccb->gc_ucmd;
154889580Smsmith        if (gdt->sc_status == GDT_S_BSY) {
154989580Smsmith            GDT_DPRINTF(GDT_D_DEBUG, ("iir_intr(%p) ioctl: gccb %p busy\n",
155089580Smsmith                                      gdt, gccb));
155189580Smsmith            TAILQ_INSERT_HEAD(&gdt->sc_ucmd_queue, ucmd, links);
155289580Smsmith            if (!(gdt->sc_state & GDT_POLLING))
155389580Smsmith                splx(lock);
155489580Smsmith        } else {
155589580Smsmith            ucmd->status = gdt->sc_status;
155689580Smsmith            ucmd->info = gdt->sc_info;
155789580Smsmith            ucmd->complete_flag = TRUE;
155889580Smsmith            if (ucmd->service == GDT_CACHESERVICE) {
155989580Smsmith                if (ucmd->OpCode == GDT_IOCTL) {
156089580Smsmith                    cnt = ucmd->u.ioctl.param_size;
156189580Smsmith                    if (cnt != 0)
156289580Smsmith                        bcopy(gccb->gc_scratch, ucmd->data, cnt);
156389580Smsmith                } else {
156489580Smsmith                    cnt = ucmd->u.cache.BlockCnt * GDT_SECTOR_SIZE;
156589580Smsmith                    if (cnt != 0)
156689580Smsmith                        bcopy(gccb->gc_scratch, ucmd->data, cnt);
156789580Smsmith                }
156889580Smsmith            } else {
156989580Smsmith                cnt = ucmd->u.raw.sdlen;
157089580Smsmith                if (cnt != 0)
157189580Smsmith                    bcopy(gccb->gc_scratch, ucmd->data, cnt);
157289580Smsmith                if (ucmd->u.raw.sense_len != 0)
157389580Smsmith                    bcopy(gccb->gc_scratch, ucmd->data, cnt);
157489580Smsmith            }
157589580Smsmith            gdt_free_ccb(gdt, gccb);
157689580Smsmith            if (!(gdt->sc_state & GDT_POLLING))
157789580Smsmith                splx(lock);
157889580Smsmith            /* wakeup */
157989580Smsmith            wakeup(ucmd);
158089580Smsmith        }
158189580Smsmith        gdt_next(gdt);
158289580Smsmith        break;
158389580Smsmith
158489580Smsmith      default:
158589580Smsmith        gdt_free_ccb(gdt, gccb);
158689580Smsmith        gdt_sync_event(gdt, ctx.service, ctx.istatus, gccb);
158789580Smsmith        if (!(gdt->sc_state & GDT_POLLING))
158889580Smsmith            splx(lock);
158989580Smsmith        gdt_next(gdt);
159089580Smsmith        break;
159189580Smsmith    }
159289580Smsmith}
159389580Smsmith
1594114001Sscottlint
159589580Smsmithgdt_async_event(struct gdt_softc *gdt, int service)
159689580Smsmith{
159789580Smsmith    struct gdt_ccb *gccb;
159889580Smsmith
159989580Smsmith    GDT_DPRINTF(GDT_D_INTR, ("gdt_async_event(%p, %d)\n", gdt, service));
160089580Smsmith
160189580Smsmith    if (service == GDT_SCREENSERVICE) {
160289580Smsmith        if (gdt->sc_status == GDT_MSG_REQUEST) {
160389580Smsmith            while (gdt->sc_test_busy(gdt))
160489580Smsmith                DELAY(1);
160589580Smsmith            gccb = gdt_get_ccb(gdt);
160689580Smsmith            if (gccb == NULL) {
160789580Smsmith                printf("iir%d: No free command index found\n",
160889580Smsmith                       gdt->sc_hanum);
160989580Smsmith                return (1);
161089580Smsmith            }
1611156139Sscottl            bzero(gccb->gc_cmd, GDT_CMD_SZ);
161289580Smsmith            gccb->gc_service = service;
161389580Smsmith            gccb->gc_flags = GDT_GCF_SCREEN;
1614156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_COMMANDINDEX,
161589580Smsmith                      gccb->gc_cmd_index);
1616156139Sscottl            gdt_enc16(gccb->gc_cmd + GDT_CMD_OPCODE, GDT_READ);
1617156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_SCREEN_MSG_HANDLE,
161889580Smsmith                      GDT_MSG_INV_HANDLE);
1619156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_SCREEN_MSG_ADDR,
1620156139Sscottl                      gccb->gc_scratch_busbase);
1621156139Sscottl            gdt->sc_set_sema0(gdt);
162289580Smsmith            gdt->sc_cmd_off = 0;
1623156139Sscottl            gccb->gc_cmd_len = roundup(GDT_CMD_UNION + GDT_SCREEN_SZ,
162489580Smsmith                                      sizeof(u_int32_t));
162589580Smsmith            gdt->sc_cmd_cnt = 0;
162689580Smsmith            gdt->sc_copy_cmd(gdt, gccb);
162789580Smsmith            printf("iir%d: [PCI %d/%d] ",
162889580Smsmith                gdt->sc_hanum,gdt->sc_bus,gdt->sc_slot);
162989580Smsmith            gdt->sc_release_event(gdt);
163089580Smsmith        }
163189580Smsmith
163289580Smsmith    } else {
163389580Smsmith        if ((gdt->sc_fw_vers & 0xff) >= 0x1a) {
163489580Smsmith            gdt->sc_dvr.size = 0;
163589580Smsmith            gdt->sc_dvr.eu.async.ionode = gdt->sc_hanum;
163689580Smsmith            gdt->sc_dvr.eu.async.status  = gdt->sc_status;
163789580Smsmith            /* severity and event_string already set! */
163889580Smsmith        } else {
163989580Smsmith            gdt->sc_dvr.size = sizeof(gdt->sc_dvr.eu.async);
164089580Smsmith            gdt->sc_dvr.eu.async.ionode   = gdt->sc_hanum;
164189580Smsmith            gdt->sc_dvr.eu.async.service = service;
164289580Smsmith            gdt->sc_dvr.eu.async.status  = gdt->sc_status;
164389580Smsmith            gdt->sc_dvr.eu.async.info    = gdt->sc_info;
164489580Smsmith            *(u_int32_t *)gdt->sc_dvr.eu.async.scsi_coord  = gdt->sc_info2;
164589580Smsmith        }
164689580Smsmith        gdt_store_event(GDT_ES_ASYNC, service, &gdt->sc_dvr);
164789580Smsmith        printf("iir%d: %s\n", gdt->sc_hanum, gdt->sc_dvr.event_string);
164889580Smsmith    }
164989580Smsmith
165089580Smsmith    return (0);
165189580Smsmith}
165289580Smsmith
1653114001Sscottlint
165489580Smsmithgdt_sync_event(struct gdt_softc *gdt, int service,
165589580Smsmith               u_int8_t index, struct gdt_ccb *gccb)
165689580Smsmith{
165789580Smsmith    union ccb *ccb;
165889580Smsmith
165989580Smsmith    GDT_DPRINTF(GDT_D_INTR,
166089580Smsmith                ("gdt_sync_event(%p, %d, %d, %p)\n", gdt,service,index,gccb));
166189580Smsmith
166289580Smsmith    ccb = gccb->gc_ccb;
166389580Smsmith
166489580Smsmith    if (service == GDT_SCREENSERVICE) {
166589580Smsmith        u_int32_t msg_len;
166689580Smsmith
166789580Smsmith        msg_len = gdt_dec32(gccb->gc_scratch + GDT_SCR_MSG_LEN);
166889580Smsmith        if (msg_len)
166989580Smsmith            if (!(gccb->gc_scratch[GDT_SCR_MSG_ANSWER] &&
167089580Smsmith                  gccb->gc_scratch[GDT_SCR_MSG_EXT])) {
167189580Smsmith                gccb->gc_scratch[GDT_SCR_MSG_TEXT + msg_len] = '\0';
167289580Smsmith                printf("%s",&gccb->gc_scratch[GDT_SCR_MSG_TEXT]);
167389580Smsmith            }
167489580Smsmith
167589580Smsmith        if (gccb->gc_scratch[GDT_SCR_MSG_EXT] &&
167689580Smsmith            !gccb->gc_scratch[GDT_SCR_MSG_ANSWER]) {
167789580Smsmith            while (gdt->sc_test_busy(gdt))
167889580Smsmith                DELAY(1);
1679156139Sscottl            bzero(gccb->gc_cmd, GDT_CMD_SZ);
168089580Smsmith            gccb = gdt_get_ccb(gdt);
168189580Smsmith            if (gccb == NULL) {
168289580Smsmith                printf("iir%d: No free command index found\n",
168389580Smsmith                       gdt->sc_hanum);
168489580Smsmith                return (1);
168589580Smsmith            }
168689580Smsmith            gccb->gc_service = service;
168789580Smsmith            gccb->gc_flags = GDT_GCF_SCREEN;
1688156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_COMMANDINDEX,
168989580Smsmith                      gccb->gc_cmd_index);
1690156139Sscottl            gdt_enc16(gccb->gc_cmd + GDT_CMD_OPCODE, GDT_READ);
1691156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_SCREEN_MSG_HANDLE,
169289580Smsmith                      gccb->gc_scratch[GDT_SCR_MSG_HANDLE]);
1693156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_SCREEN_MSG_ADDR,
1694156139Sscottl                      gccb->gc_scratch_busbase);
1695156139Sscottl            gdt->sc_set_sema0(gdt);
169689580Smsmith            gdt->sc_cmd_off = 0;
1697156139Sscottl            gccb->gc_cmd_len = roundup(GDT_CMD_UNION + GDT_SCREEN_SZ,
169889580Smsmith                                      sizeof(u_int32_t));
169989580Smsmith            gdt->sc_cmd_cnt = 0;
170089580Smsmith            gdt->sc_copy_cmd(gdt, gccb);
170189580Smsmith            gdt->sc_release_event(gdt);
170289580Smsmith            return (0);
170389580Smsmith        }
170489580Smsmith
170589580Smsmith        if (gccb->gc_scratch[GDT_SCR_MSG_ANSWER] &&
170689580Smsmith            gdt_dec32(gccb->gc_scratch + GDT_SCR_MSG_ALEN)) {
170789580Smsmith            /* default answers (getchar() not possible) */
170889580Smsmith            if (gdt_dec32(gccb->gc_scratch + GDT_SCR_MSG_ALEN) == 1) {
170989580Smsmith                gdt_enc32(gccb->gc_scratch + GDT_SCR_MSG_ALEN, 0);
171089580Smsmith                gdt_enc32(gccb->gc_scratch + GDT_SCR_MSG_LEN, 1);
171189580Smsmith                gccb->gc_scratch[GDT_SCR_MSG_TEXT] = 0;
171289580Smsmith            } else {
171389580Smsmith                gdt_enc32(gccb->gc_scratch + GDT_SCR_MSG_ALEN,
171489580Smsmith                          gdt_dec32(gccb->gc_scratch + GDT_SCR_MSG_ALEN) - 2);
171589580Smsmith                gdt_enc32(gccb->gc_scratch + GDT_SCR_MSG_LEN, 2);
171689580Smsmith                gccb->gc_scratch[GDT_SCR_MSG_TEXT] = 1;
171789580Smsmith                gccb->gc_scratch[GDT_SCR_MSG_TEXT + 1] = 0;
171889580Smsmith            }
171989580Smsmith            gccb->gc_scratch[GDT_SCR_MSG_EXT] = 0;
172089580Smsmith            gccb->gc_scratch[GDT_SCR_MSG_ANSWER] = 0;
172189580Smsmith            while (gdt->sc_test_busy(gdt))
172289580Smsmith                DELAY(1);
1723156139Sscottl            bzero(gccb->gc_cmd, GDT_CMD_SZ);
172489580Smsmith            gccb = gdt_get_ccb(gdt);
172589580Smsmith            if (gccb == NULL) {
172689580Smsmith                printf("iir%d: No free command index found\n",
172789580Smsmith                       gdt->sc_hanum);
172889580Smsmith                return (1);
172989580Smsmith            }
173089580Smsmith            gccb->gc_service = service;
173189580Smsmith            gccb->gc_flags = GDT_GCF_SCREEN;
1732156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_COMMANDINDEX,
173389580Smsmith                      gccb->gc_cmd_index);
1734156139Sscottl            gdt_enc16(gccb->gc_cmd + GDT_CMD_OPCODE, GDT_WRITE);
1735156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_SCREEN_MSG_HANDLE,
173689580Smsmith                      gccb->gc_scratch[GDT_SCR_MSG_HANDLE]);
1737156139Sscottl            gdt_enc32(gccb->gc_cmd + GDT_CMD_UNION + GDT_SCREEN_MSG_ADDR,
1738156139Sscottl                      gccb->gc_scratch_busbase);
1739156139Sscottl            gdt->sc_set_sema0(gdt);
174089580Smsmith            gdt->sc_cmd_off = 0;
1741156139Sscottl            gccb->gc_cmd_len = roundup(GDT_CMD_UNION + GDT_SCREEN_SZ,
174289580Smsmith                                      sizeof(u_int32_t));
174389580Smsmith            gdt->sc_cmd_cnt = 0;
174489580Smsmith            gdt->sc_copy_cmd(gdt, gccb);
174589580Smsmith            gdt->sc_release_event(gdt);
174689580Smsmith            return (0);
174789580Smsmith        }
174889580Smsmith        printf("\n");
174989580Smsmith        return (0);
175089580Smsmith    } else {
1751255871Sscottl        untimeout(iir_timeout, gccb, gccb->gc_timeout_ch);
175289580Smsmith        if (gdt->sc_status == GDT_S_BSY) {
175389580Smsmith            GDT_DPRINTF(GDT_D_DEBUG, ("gdt_sync_event(%p) gccb %p busy\n",
175489580Smsmith                                      gdt, gccb));
175589580Smsmith            TAILQ_INSERT_HEAD(&gdt->sc_ccb_queue, &ccb->ccb_h, sim_links.tqe);
175689580Smsmith            ++gdt_stat.req_queue_act;
175789580Smsmith            if (gdt_stat.req_queue_act > gdt_stat.req_queue_max)
175889580Smsmith                gdt_stat.req_queue_max = gdt_stat.req_queue_act;
175989580Smsmith            return (2);
176089580Smsmith        }
176189580Smsmith
1762114001Sscottl        bus_dmamap_sync(gdt->sc_buffer_dmat, gccb->gc_dmamap,
1763114001Sscottl            (ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN ?
1764114001Sscottl            BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
1765156139Sscottl        bus_dmamap_unload(gdt->sc_buffer_dmat, gccb->gc_dmamap);
176689580Smsmith
176789580Smsmith        ccb->csio.resid = 0;
176889580Smsmith        if (gdt->sc_status == GDT_S_OK) {
1769156139Sscottl            ccb->ccb_h.status |= CAM_REQ_CMP;
1770156139Sscottl            ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
177189580Smsmith        } else {
177289580Smsmith            /* error */
177389580Smsmith            if (gccb->gc_service == GDT_CACHESERVICE) {
1774225950Sken                struct scsi_sense_data *sense;
1775225950Sken
1776156139Sscottl                ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID;
1777156139Sscottl                ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
177889580Smsmith                ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
177989580Smsmith                bzero(&ccb->csio.sense_data, ccb->csio.sense_len);
1780225950Sken                sense = &ccb->csio.sense_data;
1781225950Sken                scsi_set_sense_data(sense,
1782225950Sken                                    /*sense_format*/ SSD_TYPE_NONE,
1783225950Sken                                    /*current_error*/ 1,
1784225950Sken                                    /*sense_key*/ SSD_KEY_NOT_READY,
1785225950Sken                                    /*asc*/ 0x4,
1786225950Sken                                    /*ascq*/ 0x01,
1787225950Sken                                    SSD_ELEM_NONE);
178889580Smsmith
178989580Smsmith                gdt->sc_dvr.size = sizeof(gdt->sc_dvr.eu.sync);
179089580Smsmith                gdt->sc_dvr.eu.sync.ionode  = gdt->sc_hanum;
179189580Smsmith                gdt->sc_dvr.eu.sync.service = service;
179289580Smsmith                gdt->sc_dvr.eu.sync.status  = gdt->sc_status;
179389580Smsmith                gdt->sc_dvr.eu.sync.info    = gdt->sc_info;
179489580Smsmith                gdt->sc_dvr.eu.sync.hostdrive = ccb->ccb_h.target_id;
179589580Smsmith                if (gdt->sc_status >= 0x8000)
179689580Smsmith                    gdt_store_event(GDT_ES_SYNC, 0, &gdt->sc_dvr);
179789580Smsmith                else
179889580Smsmith                    gdt_store_event(GDT_ES_SYNC, service, &gdt->sc_dvr);
179989580Smsmith            } else {
180089580Smsmith                /* raw service */
180189580Smsmith                if (gdt->sc_status != GDT_S_RAW_SCSI || gdt->sc_info >= 0x100) {
1802114001Sscottl                    ccb->ccb_h.status = CAM_DEV_NOT_THERE;
180389580Smsmith                } else {
1804156139Sscottl                    ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR|CAM_AUTOSNS_VALID;
1805156139Sscottl                    ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
180689580Smsmith                    ccb->csio.scsi_status = gdt->sc_info;
180789580Smsmith                    bcopy(gccb->gc_scratch, &ccb->csio.sense_data,
180889580Smsmith                          ccb->csio.sense_len);
180989580Smsmith                }
181089580Smsmith            }
181189580Smsmith        }
181289580Smsmith        --gdt_stat.io_count_act;
181389580Smsmith        xpt_done(ccb);
181489580Smsmith    }
181589580Smsmith    return (0);
181689580Smsmith}
181789580Smsmith
181889580Smsmith/* Controller event handling functions */
181989580Smsmithgdt_evt_str *gdt_store_event(u_int16_t source, u_int16_t idx,
182089580Smsmith                             gdt_evt_data *evt)
182189580Smsmith{
182289580Smsmith    gdt_evt_str *e;
182389580Smsmith    struct timeval tv;
182489580Smsmith
182589580Smsmith    GDT_DPRINTF(GDT_D_MISC, ("gdt_store_event(%d, %d)\n", source, idx));
182689580Smsmith    if (source == 0)                        /* no source -> no event */
182789580Smsmith        return 0;
182889580Smsmith
182989580Smsmith    if (ebuffer[elastidx].event_source == source &&
183089580Smsmith        ebuffer[elastidx].event_idx == idx &&
183189580Smsmith        ((evt->size != 0 && ebuffer[elastidx].event_data.size != 0 &&
183289580Smsmith          !memcmp((char *)&ebuffer[elastidx].event_data.eu,
183389580Smsmith                  (char *)&evt->eu, evt->size)) ||
183489580Smsmith         (evt->size == 0 && ebuffer[elastidx].event_data.size == 0 &&
183589580Smsmith          !strcmp((char *)&ebuffer[elastidx].event_data.event_string,
183689580Smsmith                  (char *)&evt->event_string)))) {
183789580Smsmith        e = &ebuffer[elastidx];
183889580Smsmith        getmicrotime(&tv);
183989580Smsmith        e->last_stamp = tv.tv_sec;
184089580Smsmith        ++e->same_count;
184189580Smsmith    } else {
184289580Smsmith        if (ebuffer[elastidx].event_source != 0) {  /* entry not free ? */
184389580Smsmith            ++elastidx;
184489580Smsmith            if (elastidx == GDT_MAX_EVENTS)
184589580Smsmith                elastidx = 0;
184689580Smsmith            if (elastidx == eoldidx) {              /* reached mark ? */
184789580Smsmith                ++eoldidx;
184889580Smsmith                if (eoldidx == GDT_MAX_EVENTS)
184989580Smsmith                    eoldidx = 0;
185089580Smsmith            }
185189580Smsmith        }
185289580Smsmith        e = &ebuffer[elastidx];
185389580Smsmith        e->event_source = source;
185489580Smsmith        e->event_idx = idx;
185589580Smsmith        getmicrotime(&tv);
185689580Smsmith        e->first_stamp = e->last_stamp = tv.tv_sec;
185789580Smsmith        e->same_count = 1;
185889580Smsmith        e->event_data = *evt;
185989580Smsmith        e->application = 0;
186089580Smsmith    }
186189580Smsmith    return e;
186289580Smsmith}
186389580Smsmith
186489580Smsmithint gdt_read_event(int handle, gdt_evt_str *estr)
186589580Smsmith{
186689580Smsmith    gdt_evt_str *e;
186789580Smsmith    int eindex, lock;
186889580Smsmith
186989580Smsmith    GDT_DPRINTF(GDT_D_MISC, ("gdt_read_event(%d)\n", handle));
187089580Smsmith    lock = splcam();
187189580Smsmith    if (handle == -1)
187289580Smsmith        eindex = eoldidx;
187389580Smsmith    else
187489580Smsmith        eindex = handle;
187589580Smsmith    estr->event_source = 0;
187689580Smsmith
187789580Smsmith    if (eindex >= GDT_MAX_EVENTS) {
187889580Smsmith        splx(lock);
187989580Smsmith        return eindex;
188089580Smsmith    }
188189580Smsmith    e = &ebuffer[eindex];
188289580Smsmith    if (e->event_source != 0) {
188389580Smsmith        if (eindex != elastidx) {
188489580Smsmith            if (++eindex == GDT_MAX_EVENTS)
188589580Smsmith                eindex = 0;
188689580Smsmith        } else {
188789580Smsmith            eindex = -1;
188889580Smsmith        }
188989580Smsmith        memcpy(estr, e, sizeof(gdt_evt_str));
189089580Smsmith    }
189189580Smsmith    splx(lock);
189289580Smsmith    return eindex;
189389580Smsmith}
189489580Smsmith
189589580Smsmithvoid gdt_readapp_event(u_int8_t application, gdt_evt_str *estr)
189689580Smsmith{
189789580Smsmith    gdt_evt_str *e;
189889580Smsmith    int found = FALSE;
189989580Smsmith    int eindex, lock;
190089580Smsmith
190189580Smsmith    GDT_DPRINTF(GDT_D_MISC, ("gdt_readapp_event(%d)\n", application));
190289580Smsmith    lock = splcam();
190389580Smsmith    eindex = eoldidx;
190489580Smsmith    for (;;) {
190589580Smsmith        e = &ebuffer[eindex];
190689580Smsmith        if (e->event_source == 0)
190789580Smsmith            break;
190889580Smsmith        if ((e->application & application) == 0) {
190989580Smsmith            e->application |= application;
191089580Smsmith            found = TRUE;
191189580Smsmith            break;
191289580Smsmith        }
191389580Smsmith        if (eindex == elastidx)
191489580Smsmith            break;
191589580Smsmith        if (++eindex == GDT_MAX_EVENTS)
191689580Smsmith            eindex = 0;
191789580Smsmith    }
191889580Smsmith    if (found)
191989580Smsmith        memcpy(estr, e, sizeof(gdt_evt_str));
192089580Smsmith    else
192189580Smsmith        estr->event_source = 0;
192289580Smsmith    splx(lock);
192389580Smsmith}
192489580Smsmith
192589580Smsmithvoid gdt_clear_events()
192689580Smsmith{
192789580Smsmith    GDT_DPRINTF(GDT_D_MISC, ("gdt_clear_events\n"));
192889580Smsmith
192989580Smsmith    eoldidx = elastidx = 0;
193089580Smsmith    ebuffer[0].event_source = 0;
193189580Smsmith}
1932