[BACK]Return to gdt_common.c CVS log [TXT][DIR] Up to [local] / sys / dev / ic

Annotation of sys/dev/ic/gdt_common.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: gdt_common.c,v 1.39 2007/04/28 00:35:16 deraadt Exp $ */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 1999, 2000, 2003 Niklas Hallqvist.  All rights reserved.
        !             5:  *
        !             6:  * Redistribution and use in source and binary forms, with or without
        !             7:  * modification, are permitted provided that the following conditions
        !             8:  * are met:
        !             9:  * 1. Redistributions of source code must retain the above copyright
        !            10:  *    notice, this list of conditions and the following disclaimer.
        !            11:  * 2. Redistributions in binary form must reproduce the above copyright
        !            12:  *    notice, this list of conditions and the following disclaimer in the
        !            13:  *    documentation and/or other materials provided with the distribution.
        !            14:  *
        !            15:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            16:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            17:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            18:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
        !            19:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
        !            20:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
        !            21:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
        !            22:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
        !            23:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
        !            24:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            25:  */
        !            26:
        !            27: /*
        !            28:  * This driver would not have written if it was not for the hardware donations
        !            29:  * from both ICP-Vortex and Öko.neT.  I want to thank them for their support.
        !            30:  */
        !            31:
        !            32: #include <sys/param.h>
        !            33: #include <sys/buf.h>
        !            34: #include <sys/device.h>
        !            35: #include <sys/ioctl.h>
        !            36: #include <sys/kernel.h>
        !            37: #include <sys/malloc.h>
        !            38: #include <sys/systm.h>
        !            39:
        !            40: #include <machine/bus.h>
        !            41:
        !            42: #include <uvm/uvm_extern.h>
        !            43:
        !            44: #include <scsi/scsi_all.h>
        !            45: #include <scsi/scsi_disk.h>
        !            46: #include <scsi/scsiconf.h>
        !            47:
        !            48: #include <dev/biovar.h>
        !            49: #include <dev/ic/gdtreg.h>
        !            50: #include <dev/ic/gdtvar.h>
        !            51:
        !            52: #include "bio.h"
        !            53:
        !            54: #ifdef GDT_DEBUG
        !            55: int gdt_maxcmds = GDT_MAXCMDS;
        !            56: #undef GDT_MAXCMDS
        !            57: #define GDT_MAXCMDS gdt_maxcmds
        !            58: #endif
        !            59:
        !            60: #define GDT_DRIVER_VERSION 1
        !            61: #define GDT_DRIVER_SUBVERSION 2
        !            62:
        !            63: int    gdt_async_event(struct gdt_softc *, int);
        !            64: void   gdt_chain(struct gdt_softc *);
        !            65: void   gdt_clear_events(struct gdt_softc *);
        !            66: void   gdt_copy_internal_data(struct scsi_xfer *, u_int8_t *, size_t);
        !            67: struct scsi_xfer *gdt_dequeue(struct gdt_softc *);
        !            68: void   gdt_enqueue(struct gdt_softc *, struct scsi_xfer *, int);
        !            69: void   gdt_enqueue_ccb(struct gdt_softc *, struct gdt_ccb *);
        !            70: void   gdt_eval_mapping(u_int32_t, int *, int *, int *);
        !            71: int    gdt_exec_ccb(struct gdt_ccb *);
        !            72: void   gdt_free_ccb(struct gdt_softc *, struct gdt_ccb *);
        !            73: struct gdt_ccb *gdt_get_ccb(struct gdt_softc *, int);
        !            74: void   gdt_internal_cache_cmd(struct scsi_xfer *);
        !            75: int    gdt_internal_cmd(struct gdt_softc *, u_int8_t, u_int16_t,
        !            76:     u_int32_t, u_int32_t, u_int32_t);
        !            77: #if NBIO > 0
        !            78: int    gdt_ioctl(struct device *, u_long, caddr_t);
        !            79: int    gdt_ioctl_inq(struct gdt_softc *, struct bioc_inq *);
        !            80: int    gdt_ioctl_vol(struct gdt_softc *, struct bioc_vol *);
        !            81: int    gdt_ioctl_disk(struct gdt_softc *, struct bioc_disk *);
        !            82: int    gdt_ioctl_alarm(struct gdt_softc *, struct bioc_alarm *);
        !            83: int    gdt_ioctl_setstate(struct gdt_softc *, struct bioc_setstate *);
        !            84: #endif /* NBIO > 0 */
        !            85: int    gdt_raw_scsi_cmd(struct scsi_xfer *);
        !            86: int    gdt_scsi_cmd(struct scsi_xfer *);
        !            87: void   gdt_start_ccbs(struct gdt_softc *);
        !            88: int    gdt_sync_event(struct gdt_softc *, int, u_int8_t,
        !            89:     struct scsi_xfer *);
        !            90: void   gdt_timeout(void *);
        !            91: int    gdt_wait(struct gdt_softc *, struct gdt_ccb *, int);
        !            92: void   gdt_watchdog(void *);
        !            93:
        !            94: struct cfdriver gdt_cd = {
        !            95:        NULL, "gdt", DV_DULL
        !            96: };
        !            97:
        !            98: struct scsi_adapter gdt_switch = {
        !            99:        gdt_scsi_cmd, gdtminphys, 0, 0,
        !           100: };
        !           101:
        !           102: struct scsi_adapter gdt_raw_switch = {
        !           103:        gdt_raw_scsi_cmd, gdtminphys, 0, 0,
        !           104: };
        !           105:
        !           106: struct scsi_device gdt_dev = {
        !           107:        NULL, NULL, NULL, NULL
        !           108: };
        !           109:
        !           110: int gdt_cnt = 0;
        !           111: u_int8_t gdt_polling;
        !           112: u_int8_t gdt_from_wait;
        !           113: struct gdt_softc *gdt_wait_gdt;
        !           114: int    gdt_wait_index;
        !           115: #ifdef GDT_DEBUG
        !           116: int    gdt_debug = GDT_DEBUG;
        !           117: #endif
        !           118:
        !           119: int
        !           120: gdt_attach(gdt)
        !           121:        struct gdt_softc *gdt;
        !           122: {
        !           123:        struct scsibus_attach_args saa;
        !           124:        u_int16_t cdev_cnt;
        !           125:        int i, id, drv_cyls, drv_hds, drv_secs, error, nsegs;
        !           126:
        !           127:        gdt_polling = 1;
        !           128:        gdt_from_wait = 0;
        !           129:
        !           130:        if (bus_dmamem_alloc(gdt->sc_dmat, GDT_SCRATCH_SZ, PAGE_SIZE, 0,
        !           131:            &gdt->sc_scratch_seg, 1, &nsegs, BUS_DMA_NOWAIT))
        !           132:            panic("%s: bus_dmamem_alloc failed", DEVNAME(gdt));
        !           133:        if (bus_dmamem_map(gdt->sc_dmat, &gdt->sc_scratch_seg, 1,
        !           134:            GDT_SCRATCH_SZ, &gdt->sc_scratch, BUS_DMA_NOWAIT))
        !           135:            panic("%s: bus_dmamem_map failed", DEVNAME(gdt));
        !           136:
        !           137:        gdt_clear_events(gdt);
        !           138:
        !           139:        TAILQ_INIT(&gdt->sc_free_ccb);
        !           140:        TAILQ_INIT(&gdt->sc_ccbq);
        !           141:        TAILQ_INIT(&gdt->sc_ucmdq);
        !           142:        LIST_INIT(&gdt->sc_queue);
        !           143:
        !           144:        /* Initialize the ccbs */
        !           145:        for (i = 0; i < GDT_MAXCMDS; i++) {
        !           146:                gdt->sc_ccbs[i].gc_cmd_index = i + 2;
        !           147:                error = bus_dmamap_create(gdt->sc_dmat,
        !           148:                    (GDT_MAXOFFSETS - 1) << PGSHIFT, GDT_MAXOFFSETS,
        !           149:                    (GDT_MAXOFFSETS - 1) << PGSHIFT, 0,
        !           150:                    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
        !           151:                    &gdt->sc_ccbs[i].gc_dmamap_xfer);
        !           152:                if (error) {
        !           153:                        printf("%s: cannot create ccb dmamap (%d)",
        !           154:                            DEVNAME(gdt), error);
        !           155:                        return (1);
        !           156:                }
        !           157:                (void)gdt_ccb_set_cmd(gdt->sc_ccbs + i, GDT_GCF_UNUSED);
        !           158:                TAILQ_INSERT_TAIL(&gdt->sc_free_ccb, &gdt->sc_ccbs[i],
        !           159:                    gc_chain);
        !           160:        }
        !           161:
        !           162:        /* Fill in the prototype scsi_link. */
        !           163:        gdt->sc_link.adapter_softc = gdt;
        !           164:        gdt->sc_link.adapter = &gdt_switch;
        !           165:        gdt->sc_link.device = &gdt_dev;
        !           166:        /* openings will be filled in later. */
        !           167:        gdt->sc_link.adapter_buswidth =
        !           168:            (gdt->sc_class & GDT_FC) ? GDT_MAXID : GDT_MAX_HDRIVES;
        !           169:        gdt->sc_link.adapter_target = gdt->sc_link.adapter_buswidth;
        !           170:
        !           171:        if (!gdt_internal_cmd(gdt, GDT_SCREENSERVICE, GDT_INIT, 0, 0, 0)) {
        !           172:                printf("screen service initialization error %d\n",
        !           173:                     gdt->sc_status);
        !           174:                return (1);
        !           175:        }
        !           176:
        !           177:        if (!gdt_internal_cmd(gdt, GDT_CACHESERVICE, GDT_INIT, GDT_LINUX_OS, 0,
        !           178:            0)) {
        !           179:                printf("cache service initialization error %d\n",
        !           180:                    gdt->sc_status);
        !           181:                return (1);
        !           182:        }
        !           183:
        !           184:        cdev_cnt = (u_int16_t)gdt->sc_info;
        !           185:
        !           186:        /* Detect number of busses */
        !           187:        gdt_enc32(gdt->sc_scratch + GDT_IOC_VERSION, GDT_IOC_NEWEST);
        !           188:        gdt->sc_scratch[GDT_IOC_LIST_ENTRIES] = GDT_MAXBUS;
        !           189:        gdt->sc_scratch[GDT_IOC_FIRST_CHAN] = 0;
        !           190:        gdt->sc_scratch[GDT_IOC_LAST_CHAN] = GDT_MAXBUS - 1;
        !           191:        gdt_enc32(gdt->sc_scratch + GDT_IOC_LIST_OFFSET, GDT_IOC_HDR_SZ);
        !           192:        if (gdt_internal_cmd(gdt, GDT_CACHESERVICE, GDT_IOCTL,
        !           193:            GDT_IOCHAN_RAW_DESC, GDT_INVALID_CHANNEL,
        !           194:            GDT_IOC_HDR_SZ + GDT_RAWIOC_SZ)) {
        !           195:                gdt->sc_bus_cnt = gdt->sc_scratch[GDT_IOC_CHAN_COUNT];
        !           196:                for (i = 0; i < gdt->sc_bus_cnt; i++) {
        !           197:                        id = gdt->sc_scratch[GDT_IOC_HDR_SZ +
        !           198:                            i * GDT_RAWIOC_SZ + GDT_RAWIOC_PROC_ID];
        !           199:                        gdt->sc_bus_id[id] = id < GDT_MAXBUS ? id : 0xff;
        !           200:                }
        !           201:
        !           202:        } else {
        !           203:                /* New method failed, use fallback. */
        !           204:                gdt_enc32(gdt->sc_scratch + GDT_GETCH_CHANNEL_NO, i);
        !           205:                for (i = 0; i < GDT_MAXBUS; i++) {
        !           206:                        if (!gdt_internal_cmd(gdt, GDT_CACHESERVICE, GDT_IOCTL,
        !           207:                            GDT_SCSI_CHAN_CNT | GDT_L_CTRL_PATTERN,
        !           208:                            GDT_IO_CHANNEL | GDT_INVALID_CHANNEL,
        !           209:                            GDT_GETCH_SZ)) {
        !           210:                                if (i == 0) {
        !           211:                                        printf("cannot get channel count, "
        !           212:                                            "error %d\n", gdt->sc_status);
        !           213:                                        return (1);
        !           214:                                }
        !           215:                                break;
        !           216:                        }
        !           217:                        gdt->sc_bus_id[i] =
        !           218:                            (gdt->sc_scratch[GDT_GETCH_SIOP_ID] < GDT_MAXID) ?
        !           219:                            gdt->sc_scratch[GDT_GETCH_SIOP_ID] : 0xff;
        !           220:                }
        !           221:                gdt->sc_bus_cnt = i;
        !           222:        }
        !           223:
        !           224:        /* Read cache configuration */
        !           225:        if (!gdt_internal_cmd(gdt, GDT_CACHESERVICE, GDT_IOCTL, GDT_CACHE_INFO,
        !           226:            GDT_INVALID_CHANNEL, GDT_CINFO_SZ)) {
        !           227:                printf("cannot get cache info, error %d\n", gdt->sc_status);
        !           228:                return (1);
        !           229:        }
        !           230:        gdt->sc_cpar.cp_version =
        !           231:            gdt_dec32(gdt->sc_scratch + GDT_CPAR_VERSION);
        !           232:        gdt->sc_cpar.cp_state = gdt_dec16(gdt->sc_scratch + GDT_CPAR_STATE);
        !           233:        gdt->sc_cpar.cp_strategy =
        !           234:            gdt_dec16(gdt->sc_scratch + GDT_CPAR_STRATEGY);
        !           235:        gdt->sc_cpar.cp_write_back =
        !           236:            gdt_dec16(gdt->sc_scratch + GDT_CPAR_WRITE_BACK);
        !           237:        gdt->sc_cpar.cp_block_size =
        !           238:            gdt_dec16(gdt->sc_scratch + GDT_CPAR_BLOCK_SIZE);
        !           239:
        !           240:        /* Read board information and features */
        !           241:        gdt->sc_more_proc = 0;
        !           242:        if (gdt_internal_cmd(gdt, GDT_CACHESERVICE, GDT_IOCTL, GDT_BOARD_INFO,
        !           243:            GDT_INVALID_CHANNEL, GDT_BINFO_SZ)) {
        !           244:                /* XXX A lot of these assignments can probably go later */
        !           245:                gdt->sc_binfo.bi_ser_no =
        !           246:                    gdt_dec32(gdt->sc_scratch + GDT_BINFO_SER_NO);
        !           247:                bcopy(gdt->sc_scratch + GDT_BINFO_OEM_ID,
        !           248:                    gdt->sc_binfo.bi_oem_id, sizeof gdt->sc_binfo.bi_oem_id);
        !           249:                gdt->sc_binfo.bi_ep_flags =
        !           250:                    gdt_dec16(gdt->sc_scratch + GDT_BINFO_EP_FLAGS);
        !           251:                gdt->sc_binfo.bi_proc_id =
        !           252:                    gdt_dec32(gdt->sc_scratch + GDT_BINFO_PROC_ID);
        !           253:                gdt->sc_binfo.bi_memsize =
        !           254:                    gdt_dec32(gdt->sc_scratch + GDT_BINFO_MEMSIZE);
        !           255:                gdt->sc_binfo.bi_mem_banks =
        !           256:                    gdt->sc_scratch[GDT_BINFO_MEM_BANKS];
        !           257:                gdt->sc_binfo.bi_chan_type =
        !           258:                    gdt->sc_scratch[GDT_BINFO_CHAN_TYPE];
        !           259:                gdt->sc_binfo.bi_chan_count =
        !           260:                    gdt->sc_scratch[GDT_BINFO_CHAN_COUNT];
        !           261:                gdt->sc_binfo.bi_rdongle_pres =
        !           262:                    gdt->sc_scratch[GDT_BINFO_RDONGLE_PRES];
        !           263:                gdt->sc_binfo.bi_epr_fw_ver =
        !           264:                    gdt_dec32(gdt->sc_scratch + GDT_BINFO_EPR_FW_VER);
        !           265:                gdt->sc_binfo.bi_upd_fw_ver =
        !           266:                    gdt_dec32(gdt->sc_scratch + GDT_BINFO_UPD_FW_VER);
        !           267:                gdt->sc_binfo.bi_upd_revision =
        !           268:                    gdt_dec32(gdt->sc_scratch + GDT_BINFO_UPD_REVISION);
        !           269:                bcopy(gdt->sc_scratch + GDT_BINFO_TYPE_STRING,
        !           270:                    gdt->sc_binfo.bi_type_string,
        !           271:                    sizeof gdt->sc_binfo.bi_type_string);
        !           272:                bcopy(gdt->sc_scratch + GDT_BINFO_RAID_STRING,
        !           273:                    gdt->sc_binfo.bi_raid_string,
        !           274:                    sizeof gdt->sc_binfo.bi_raid_string);
        !           275:                gdt->sc_binfo.bi_update_pres =
        !           276:                    gdt->sc_scratch[GDT_BINFO_UPDATE_PRES];
        !           277:                gdt->sc_binfo.bi_xor_pres =
        !           278:                    gdt->sc_scratch[GDT_BINFO_XOR_PRES];
        !           279:                gdt->sc_binfo.bi_prom_type =
        !           280:                    gdt->sc_scratch[GDT_BINFO_PROM_TYPE];
        !           281:                gdt->sc_binfo.bi_prom_count =
        !           282:                    gdt->sc_scratch[GDT_BINFO_PROM_COUNT];
        !           283:                gdt->sc_binfo.bi_dup_pres =
        !           284:                    gdt_dec32(gdt->sc_scratch + GDT_BINFO_DUP_PRES);
        !           285:                gdt->sc_binfo.bi_chan_pres =
        !           286:                    gdt_dec32(gdt->sc_scratch + GDT_BINFO_CHAN_PRES);
        !           287:                gdt->sc_binfo.bi_mem_pres =
        !           288:                    gdt_dec32(gdt->sc_scratch + GDT_BINFO_MEM_PRES);
        !           289:                gdt->sc_binfo.bi_ft_bus_system =
        !           290:                    gdt->sc_scratch[GDT_BINFO_FT_BUS_SYSTEM];
        !           291:                gdt->sc_binfo.bi_subtype_valid =
        !           292:                    gdt->sc_scratch[GDT_BINFO_SUBTYPE_VALID];
        !           293:                gdt->sc_binfo.bi_board_subtype =
        !           294:                    gdt->sc_scratch[GDT_BINFO_BOARD_SUBTYPE];
        !           295:                gdt->sc_binfo.bi_rampar_pres =
        !           296:                    gdt->sc_scratch[GDT_BINFO_RAMPAR_PRES];
        !           297:
        !           298:                if (gdt_internal_cmd(gdt, GDT_CACHESERVICE, GDT_IOCTL,
        !           299:                    GDT_BOARD_FEATURES, GDT_INVALID_CHANNEL, GDT_BFEAT_SZ)) {
        !           300:                        gdt->sc_bfeat.bf_chaining =
        !           301:                            gdt->sc_scratch[GDT_BFEAT_CHAINING];
        !           302:                        gdt->sc_bfeat.bf_striping =
        !           303:                            gdt->sc_scratch[GDT_BFEAT_STRIPING];
        !           304:                        gdt->sc_bfeat.bf_mirroring =
        !           305:                            gdt->sc_scratch[GDT_BFEAT_MIRRORING];
        !           306:                        gdt->sc_bfeat.bf_raid =
        !           307:                            gdt->sc_scratch[GDT_BFEAT_RAID];
        !           308:                        gdt->sc_more_proc = 1;
        !           309:                }
        !           310:        } else {
        !           311:                /* XXX Not implemented yet */
        !           312:        }
        !           313:
        !           314:        /* Read more information */
        !           315:        if (gdt->sc_more_proc) {
        !           316:                int bus, j;
        !           317:                /* physical drives, channel addresses */
        !           318:                /* step 1: get magical bus number from firmware */
        !           319:                gdt_enc32(gdt->sc_scratch + GDT_IOC_VERSION, GDT_IOC_NEWEST);
        !           320:                gdt->sc_scratch[GDT_IOC_LIST_ENTRIES] = GDT_MAXBUS;
        !           321:                gdt->sc_scratch[GDT_IOC_FIRST_CHAN] = 0;
        !           322:                gdt->sc_scratch[GDT_IOC_LAST_CHAN] = GDT_MAXBUS - 1;
        !           323:                gdt_enc32(gdt->sc_scratch + GDT_IOC_LIST_OFFSET, GDT_IOC_HDR_SZ);
        !           324:                if (gdt_internal_cmd(gdt, GDT_CACHESERVICE, GDT_IOCTL,
        !           325:                    GDT_IOCHAN_DESC, GDT_INVALID_CHANNEL,
        !           326:                    GDT_IOC_HDR_SZ + GDT_IOC_SZ * GDT_MAXBUS)) {
        !           327:                        GDT_DPRINTF(GDT_D_INFO, ("method 1\n"));
        !           328:                        for (bus = 0; bus < gdt->sc_bus_cnt; bus++) {
        !           329:                                gdt->sc_raw[bus].ra_address =
        !           330:                                    gdt_dec32(gdt->sc_scratch +
        !           331:                                    GDT_IOC_HDR_SZ +
        !           332:                                    GDT_IOC_SZ * bus +
        !           333:                                    GDT_IOC_ADDRESS);
        !           334:                                gdt->sc_raw[bus].ra_local_no =
        !           335:                                    gdt_dec8(gdt->sc_scratch +
        !           336:                                    GDT_IOC_HDR_SZ +
        !           337:                                    GDT_IOC_SZ * bus +
        !           338:                                    GDT_IOC_LOCAL_NO);
        !           339:                                GDT_DPRINTF(GDT_D_INFO, (
        !           340:                                    "bus: %d address: %x local: %x\n",
        !           341:                                    bus,
        !           342:                                    gdt->sc_raw[bus].ra_address,
        !           343:                                    gdt->sc_raw[bus].ra_local_no));
        !           344:                        }
        !           345:                } else {
        !           346:                        GDT_DPRINTF(GDT_D_INFO, ("method 2\n"));
        !           347:                        for (bus = 0; bus < gdt->sc_bus_cnt; bus++) {
        !           348:                                gdt->sc_raw[bus].ra_address = GDT_IO_CHANNEL;
        !           349:                                gdt->sc_raw[bus].ra_local_no = bus;
        !           350:                                GDT_DPRINTF(GDT_D_INFO, (
        !           351:                                    "bus: %d address: %x local: %x\n",
        !           352:                                    bus,
        !           353:                                    gdt->sc_raw[bus].ra_address,
        !           354:                                    gdt->sc_raw[bus].ra_local_no));
        !           355:                        }
        !           356:                }
        !           357:                /* step 2: use magical bus number to get nr of phys disks */
        !           358:                for (bus = 0; bus < gdt->sc_bus_cnt; bus++) {
        !           359:                        gdt_enc32(gdt->sc_scratch + GDT_GETCH_CHANNEL_NO,
        !           360:                            gdt->sc_raw[bus].ra_local_no);
        !           361:                        if (gdt_internal_cmd(gdt, GDT_CACHESERVICE, GDT_IOCTL,
        !           362:                            GDT_SCSI_CHAN_CNT | GDT_L_CTRL_PATTERN,
        !           363:                            gdt->sc_raw[bus].ra_address | GDT_INVALID_CHANNEL,
        !           364:                            GDT_GETCH_SZ)) {
        !           365:                                gdt->sc_raw[bus].ra_phys_cnt =
        !           366:                                    gdt_dec32(gdt->sc_scratch +
        !           367:                                    GDT_GETCH_DRIVE_CNT);
        !           368:                                GDT_DPRINTF(GDT_D_INFO, ("chan: %d disks: %d\n",
        !           369:                                    bus, gdt->sc_raw[bus].ra_phys_cnt));
        !           370:                        }
        !           371:
        !           372:                        /* step 3: get scsi disk nr */
        !           373:                        if (gdt->sc_raw[bus].ra_phys_cnt > 0) {
        !           374:                                gdt_enc32(gdt->sc_scratch +
        !           375:                                    GDT_GETSCSI_CHAN,
        !           376:                                    gdt->sc_raw[bus].ra_local_no);
        !           377:                                gdt_enc32(gdt->sc_scratch +
        !           378:                                    GDT_GETSCSI_CNT,
        !           379:                                    gdt->sc_raw[bus].ra_phys_cnt);
        !           380:                                if (gdt_internal_cmd(gdt, GDT_CACHESERVICE,
        !           381:                                    GDT_IOCTL,
        !           382:                                    GDT_SCSI_DR_LIST | GDT_L_CTRL_PATTERN,
        !           383:                                    gdt->sc_raw[bus].ra_address |
        !           384:                                    GDT_INVALID_CHANNEL,
        !           385:                                    GDT_GETSCSI_SZ))
        !           386:                                        for (j = 0;
        !           387:                                            j < gdt->sc_raw[bus].ra_phys_cnt;
        !           388:                                            j++) {
        !           389:                                                gdt->sc_raw[bus].ra_id_list[j] =
        !           390:                                                    gdt_dec32(gdt->sc_scratch +
        !           391:                                                    GDT_GETSCSI_LIST +
        !           392:                                                    GDT_GETSCSI_LIST_SZ * j);
        !           393:                                                GDT_DPRINTF(GDT_D_INFO,
        !           394:                                                    ("  diskid: %d\n",
        !           395:                                                    gdt->sc_raw[bus].ra_id_list[j]));
        !           396:                                        }
        !           397:                                else
        !           398:                                        gdt->sc_raw[bus].ra_phys_cnt = 0;
        !           399:                        }
        !           400:                        /* add found disks to grand total */
        !           401:                        gdt->sc_total_disks += gdt->sc_raw[bus].ra_phys_cnt;
        !           402:                }
        !           403:        } /* if (gdt->sc_more_proc) */
        !           404:
        !           405:        if (!gdt_internal_cmd(gdt, GDT_SCSIRAWSERVICE, GDT_INIT, 0, 0, 0)) {
        !           406:                printf("raw service initialization error %d\n",
        !           407:                    gdt->sc_status);
        !           408:                return (1);
        !           409:        }
        !           410:
        !           411:        /* Set/get features raw service (scatter/gather) */
        !           412:        gdt->sc_raw_feat = 0;
        !           413:        if (gdt_internal_cmd(gdt, GDT_SCSIRAWSERVICE, GDT_SET_FEAT,
        !           414:            GDT_SCATTER_GATHER, 0, 0))
        !           415:                if (gdt_internal_cmd(gdt, GDT_SCSIRAWSERVICE, GDT_GET_FEAT, 0,
        !           416:                    0, 0))
        !           417:                        gdt->sc_raw_feat = gdt->sc_info;
        !           418:
        !           419:        /* Set/get features cache service (scatter/gather) */
        !           420:        gdt->sc_cache_feat = 0;
        !           421:        if (gdt_internal_cmd(gdt, GDT_CACHESERVICE, GDT_SET_FEAT, 0,
        !           422:            GDT_SCATTER_GATHER, 0))
        !           423:                if (gdt_internal_cmd(gdt, GDT_CACHESERVICE, GDT_GET_FEAT, 0, 0,
        !           424:                    0))
        !           425:                        gdt->sc_cache_feat = gdt->sc_info;
        !           426:
        !           427:        /* XXX Linux reserve drives here, potentially */
        !           428:
        !           429:        gdt->sc_ndevs = 0;
        !           430:        /* Scan for cache devices */
        !           431:        for (i = 0; i < cdev_cnt && i < GDT_MAX_HDRIVES; i++)
        !           432:                if (gdt_internal_cmd(gdt, GDT_CACHESERVICE, GDT_INFO, i, 0,
        !           433:                    0)) {
        !           434:                        gdt->sc_hdr[i].hd_present = 1;
        !           435:                        gdt->sc_hdr[i].hd_size = gdt->sc_info;
        !           436:
        !           437:                        if (gdt->sc_hdr[i].hd_size > 0)
        !           438:                                gdt->sc_ndevs++;
        !           439:
        !           440:                        /*
        !           441:                         * Evaluate mapping (sectors per head, heads per cyl)
        !           442:                         */
        !           443:                        gdt->sc_hdr[i].hd_size &= ~GDT_SECS32;
        !           444:                        if (gdt->sc_info2 == 0)
        !           445:                                gdt_eval_mapping(gdt->sc_hdr[i].hd_size,
        !           446:                                    &drv_cyls, &drv_hds, &drv_secs);
        !           447:                        else {
        !           448:                                drv_hds = gdt->sc_info2 & 0xff;
        !           449:                                drv_secs = (gdt->sc_info2 >> 8) & 0xff;
        !           450:                                drv_cyls = gdt->sc_hdr[i].hd_size / drv_hds /
        !           451:                                    drv_secs;
        !           452:                        }
        !           453:                        gdt->sc_hdr[i].hd_heads = drv_hds;
        !           454:                        gdt->sc_hdr[i].hd_secs = drv_secs;
        !           455:                        /* Round the size */
        !           456:                        gdt->sc_hdr[i].hd_size = drv_cyls * drv_hds * drv_secs;
        !           457:
        !           458:                        if (gdt_internal_cmd(gdt, GDT_CACHESERVICE,
        !           459:                            GDT_DEVTYPE, i, 0, 0))
        !           460:                                gdt->sc_hdr[i].hd_devtype = gdt->sc_info;
        !           461:                }
        !           462:
        !           463:        if (gdt->sc_ndevs == 0)
        !           464:                gdt->sc_link.openings = 0;
        !           465:        else
        !           466:                gdt->sc_link.openings = (GDT_MAXCMDS - GDT_CMD_RESERVE) /
        !           467:                    gdt->sc_ndevs;
        !           468:
        !           469:        printf("dpmem %llx %d-bus %d cache device%s\n",
        !           470:            (long long)gdt->sc_dpmembase,
        !           471:            gdt->sc_bus_cnt, cdev_cnt, cdev_cnt == 1 ? "" : "s");
        !           472:        printf("%s: ver %x, cache %s, strategy %d, writeback %s, blksz %d\n",
        !           473:            DEVNAME(gdt), gdt->sc_cpar.cp_version,
        !           474:            gdt->sc_cpar.cp_state ? "on" : "off", gdt->sc_cpar.cp_strategy,
        !           475:            gdt->sc_cpar.cp_write_back ? "on" : "off",
        !           476:            gdt->sc_cpar.cp_block_size);
        !           477: #if 1
        !           478:        printf("%s: raw feat %x cache feat %x\n", DEVNAME(gdt),
        !           479:            gdt->sc_raw_feat, gdt->sc_cache_feat);
        !           480: #endif
        !           481:
        !           482: #if NBIO > 0
        !           483:        if (bio_register(&gdt->sc_dev, gdt_ioctl) != 0)
        !           484:                panic("%s: controller registration failed", DEVNAME(gdt));
        !           485: #endif
        !           486:        gdt_cnt++;
        !           487:
        !           488:        bzero(&saa, sizeof(saa));
        !           489:        saa.saa_sc_link = &gdt->sc_link;
        !           490:
        !           491:        config_found(&gdt->sc_dev, &saa, scsiprint);
        !           492:
        !           493:        gdt->sc_raw_link = malloc(gdt->sc_bus_cnt * sizeof (struct scsi_link),
        !           494:                                  M_DEVBUF, M_NOWAIT);
        !           495:        if (gdt->sc_raw_link == NULL)
        !           496:                panic("gdt_attach");
        !           497:        bzero(gdt->sc_raw_link, gdt->sc_bus_cnt * sizeof (struct scsi_link));
        !           498:
        !           499:        for (i = 0; i < gdt->sc_bus_cnt; i++) {
        !           500:                /* Fill in the prototype scsi_link. */
        !           501:                gdt->sc_raw_link[i].adapter_softc = gdt;
        !           502:                gdt->sc_raw_link[i].adapter = &gdt_raw_switch;
        !           503:                gdt->sc_raw_link[i].adapter_target = 7;
        !           504:                gdt->sc_raw_link[i].device = &gdt_dev;
        !           505:                gdt->sc_raw_link[i].openings = 4;       /* XXX a guess */
        !           506:                gdt->sc_raw_link[i].adapter_buswidth =
        !           507:                    (gdt->sc_class & GDT_FC) ? GDT_MAXID : 16;  /* XXX */
        !           508:
        !           509:                bzero(&saa, sizeof(saa));
        !           510:                saa.saa_sc_link = &gdt->sc_raw_link[i];
        !           511:
        !           512:                config_found(&gdt->sc_dev, &saa, scsiprint);
        !           513:        }
        !           514:
        !           515:        gdt_polling = 0;
        !           516:        return (0);
        !           517: }
        !           518:
        !           519: void
        !           520: gdt_eval_mapping(size, cyls, heads, secs)
        !           521:        u_int32_t size;
        !           522:        int *cyls, *heads, *secs;
        !           523: {
        !           524:        *cyls = size / GDT_HEADS / GDT_SECS;
        !           525:        if (*cyls < GDT_MAXCYLS) {
        !           526:                *heads = GDT_HEADS;
        !           527:                *secs = GDT_SECS;
        !           528:        } else {
        !           529:                /* Too high for 64 * 32 */
        !           530:                *cyls = size / GDT_MEDHEADS / GDT_MEDSECS;
        !           531:                if (*cyls < GDT_MAXCYLS) {
        !           532:                        *heads = GDT_MEDHEADS;
        !           533:                        *secs = GDT_MEDSECS;
        !           534:                } else {
        !           535:                        /* Too high for 127 * 63 */
        !           536:                        *cyls = size / GDT_BIGHEADS / GDT_BIGSECS;
        !           537:                        *heads = GDT_BIGHEADS;
        !           538:                        *secs = GDT_BIGSECS;
        !           539:                }
        !           540:        }
        !           541: }
        !           542:
        !           543: /*
        !           544:  * Insert a command into the driver queue, either at the front or at the tail.
        !           545:  * It's ok to overload the freelist link as these structures are never on
        !           546:  * the freelist at this time.
        !           547:  */
        !           548: void
        !           549: gdt_enqueue(gdt, xs, infront)
        !           550:        struct gdt_softc *gdt;
        !           551:        struct scsi_xfer *xs;
        !           552:        int infront;
        !           553: {
        !           554:        if (infront || LIST_FIRST(&gdt->sc_queue) == NULL) {
        !           555:                if (LIST_FIRST(&gdt->sc_queue) == NULL)
        !           556:                        gdt->sc_queuelast = xs;
        !           557:                LIST_INSERT_HEAD(&gdt->sc_queue, xs, free_list);
        !           558:                return;
        !           559:        }
        !           560:        LIST_INSERT_AFTER(gdt->sc_queuelast, xs, free_list);
        !           561:        gdt->sc_queuelast = xs;
        !           562: }
        !           563:
        !           564: /*
        !           565:  * Pull a command off the front of the driver queue.
        !           566:  */
        !           567: struct scsi_xfer *
        !           568: gdt_dequeue(gdt)
        !           569:        struct gdt_softc *gdt;
        !           570: {
        !           571:        struct scsi_xfer *xs;
        !           572:
        !           573:        xs = LIST_FIRST(&gdt->sc_queue);
        !           574:        if (xs == NULL)
        !           575:                return (NULL);
        !           576:        LIST_REMOVE(xs, free_list);
        !           577:
        !           578:        if (LIST_FIRST(&gdt->sc_queue) == NULL)
        !           579:                gdt->sc_queuelast = NULL;
        !           580:
        !           581:        return (xs);
        !           582: }
        !           583:
        !           584: /*
        !           585:  * Start a SCSI operation on a cache device.
        !           586:  * XXX Polled operation is not yet complete.  What kind of locking do we need?
        !           587:  */
        !           588: int
        !           589: gdt_scsi_cmd(xs)
        !           590:        struct scsi_xfer *xs;
        !           591: {
        !           592:        struct scsi_link *link = xs->sc_link;
        !           593:        struct gdt_softc *gdt = link->adapter_softc;
        !           594:        u_int8_t target = link->target;
        !           595:        struct gdt_ccb *ccb;
        !           596: #if 0
        !           597:        struct gdt_ucmd *ucmd;
        !           598: #endif
        !           599:        u_int32_t blockno, blockcnt;
        !           600:        struct scsi_rw *rw;
        !           601:        struct scsi_rw_big *rwb;
        !           602:        bus_dmamap_t xfer;
        !           603:        int error, retval = SUCCESSFULLY_QUEUED;
        !           604:        int s;
        !           605:
        !           606:        GDT_DPRINTF(GDT_D_CMD, ("gdt_scsi_cmd "));
        !           607:
        !           608:        xs->error = XS_NOERROR;
        !           609:
        !           610:        if (target >= GDT_MAX_HDRIVES || !gdt->sc_hdr[target].hd_present ||
        !           611:            link->lun != 0) {
        !           612:                /*
        !           613:                 * XXX Should be XS_SENSE but that would require setting up a
        !           614:                 * faked sense too.
        !           615:                 */
        !           616:                xs->error = XS_DRIVER_STUFFUP;
        !           617:                xs->flags |= ITSDONE;
        !           618:                s = splbio();
        !           619:                scsi_done(xs);
        !           620:                splx(s);
        !           621:                return (COMPLETE);
        !           622:        }
        !           623:
        !           624:        s = splbio();
        !           625:
        !           626:        /* Don't double enqueue if we came from gdt_chain. */
        !           627:        if (xs != LIST_FIRST(&gdt->sc_queue))
        !           628:                gdt_enqueue(gdt, xs, 0);
        !           629:
        !           630:        while ((xs = gdt_dequeue(gdt)) != NULL) {
        !           631:                xs->error = XS_NOERROR;
        !           632:                ccb = NULL;
        !           633:                link = xs->sc_link;
        !           634:                target = link->target;
        !           635:
        !           636:                if (!gdt_polling && !(xs->flags & SCSI_POLL) &&
        !           637:                    gdt->sc_test_busy(gdt)) {
        !           638:                        /*
        !           639:                         * Put it back in front.  XXX Should we instead
        !           640:                         * set xs->error to XS_BUSY?
        !           641:                         */
        !           642:                        gdt_enqueue(gdt, xs, 1);
        !           643:                        break;
        !           644:                }
        !           645:
        !           646:                switch (xs->cmd->opcode) {
        !           647:                case TEST_UNIT_READY:
        !           648:                case REQUEST_SENSE:
        !           649:                case INQUIRY:
        !           650:                case MODE_SENSE:
        !           651:                case START_STOP:
        !           652:                case READ_CAPACITY:
        !           653: #if 0
        !           654:                case VERIFY:
        !           655: #endif
        !           656:                        gdt_internal_cache_cmd(xs);
        !           657:                        xs->flags |= ITSDONE;
        !           658:                        scsi_done(xs);
        !           659:                        goto ready;
        !           660:
        !           661:                case PREVENT_ALLOW:
        !           662:                        GDT_DPRINTF(GDT_D_CMD, ("PREVENT/ALLOW "));
        !           663:                        /* XXX Not yet implemented */
        !           664:                        xs->error = XS_NOERROR;
        !           665:                        xs->flags |= ITSDONE;
        !           666:                        scsi_done(xs);
        !           667:                        goto ready;
        !           668:
        !           669:                default:
        !           670:                        GDT_DPRINTF(GDT_D_CMD,
        !           671:                            ("unknown opc %d ", xs->cmd->opcode));
        !           672:                        /* XXX Not yet implemented */
        !           673:                        xs->error = XS_DRIVER_STUFFUP;
        !           674:                        xs->flags |= ITSDONE;
        !           675:                        scsi_done(xs);
        !           676:                        goto ready;
        !           677:
        !           678:                case READ_COMMAND:
        !           679:                case READ_BIG:
        !           680:                case WRITE_COMMAND:
        !           681:                case WRITE_BIG:
        !           682:                case SYNCHRONIZE_CACHE:
        !           683:                        /*
        !           684:                         * A new command chain, start from the beginning.
        !           685:                         */
        !           686:                        gdt->sc_cmd_off = 0;
        !           687:
        !           688:                        if (xs->cmd->opcode != SYNCHRONIZE_CACHE) {
        !           689:                                /* A read or write operation. */
        !           690:                                if (xs->cmdlen == 6) {
        !           691:                                        rw = (struct scsi_rw *)xs->cmd;
        !           692:                                        blockno = _3btol(rw->addr) &
        !           693:                                            (SRW_TOPADDR << 16 | 0xffff);
        !           694:                                        blockcnt =
        !           695:                                            rw->length ? rw->length : 0x100;
        !           696:                                } else {
        !           697:                                        rwb = (struct scsi_rw_big *)xs->cmd;
        !           698:                                        blockno = _4btol(rwb->addr);
        !           699:                                        blockcnt = _2btol(rwb->length);
        !           700:                                }
        !           701:                                if (blockno >= gdt->sc_hdr[target].hd_size ||
        !           702:                                    blockno + blockcnt >
        !           703:                                    gdt->sc_hdr[target].hd_size) {
        !           704:                                        printf(
        !           705:                                            "%s: out of bounds %u-%u >= %u\n",
        !           706:                                            DEVNAME(gdt), blockno,
        !           707:                                            blockcnt,
        !           708:                                            gdt->sc_hdr[target].hd_size);
        !           709:                                        /*
        !           710:                                         * XXX Should be XS_SENSE but that
        !           711:                                         * would require setting up a faked
        !           712:                                         * sense too.
        !           713:                                         */
        !           714:                                        xs->error = XS_DRIVER_STUFFUP;
        !           715:                                        xs->flags |= ITSDONE;
        !           716:                                        scsi_done(xs);
        !           717:                                        goto ready;
        !           718:                                }
        !           719:                        }
        !           720:
        !           721:                        ccb = gdt_get_ccb(gdt, xs->flags);
        !           722:                        /*
        !           723:                         * We are out of commands, try again in a little while.
        !           724:                         */
        !           725:                        if (ccb == NULL) {
        !           726:                                splx(s);
        !           727:                                return (TRY_AGAIN_LATER);
        !           728:                        }
        !           729:
        !           730:                        ccb->gc_blockno = blockno;
        !           731:                        ccb->gc_blockcnt = blockcnt;
        !           732:                        ccb->gc_xs = xs;
        !           733:                        ccb->gc_timeout = xs->timeout;
        !           734:                        ccb->gc_service = GDT_CACHESERVICE;
        !           735:                        gdt_ccb_set_cmd(ccb, GDT_GCF_SCSI);
        !           736:
        !           737:                        if (xs->cmd->opcode != SYNCHRONIZE_CACHE) {
        !           738:                                xfer = ccb->gc_dmamap_xfer;
        !           739:                                error = bus_dmamap_load(gdt->sc_dmat, xfer,
        !           740:                                    xs->data, xs->datalen, NULL,
        !           741:                                    (xs->flags & SCSI_NOSLEEP) ?
        !           742:                                    BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
        !           743:                                if (error) {
        !           744:                                        printf("%s: gdt_scsi_cmd: ",
        !           745:                                            DEVNAME(gdt));
        !           746:                                        if (error == EFBIG)
        !           747:                                                printf(
        !           748:                                                    "more than %d dma segs\n",
        !           749:                                                    GDT_MAXOFFSETS);
        !           750:                                        else
        !           751:                                                printf("error %d "
        !           752:                                                    "loading dma map\n",
        !           753:                                                    error);
        !           754:
        !           755:                                        gdt_free_ccb(gdt, ccb);
        !           756:                                        xs->error = XS_DRIVER_STUFFUP;
        !           757:                                        xs->flags |= ITSDONE;
        !           758:                                        scsi_done(xs);
        !           759:                                        goto ready;
        !           760:                                }
        !           761:                                bus_dmamap_sync(gdt->sc_dmat, xfer, 0,
        !           762:                                    xfer->dm_mapsize,
        !           763:                                    (xs->flags & SCSI_DATA_IN) ?
        !           764:                                    BUS_DMASYNC_PREREAD :
        !           765:                                    BUS_DMASYNC_PREWRITE);
        !           766:                        }
        !           767:
        !           768:                        gdt_enqueue_ccb(gdt, ccb);
        !           769:                        /* XXX what if enqueue did not start a transfer? */
        !           770:                        if (gdt_polling || (xs->flags & SCSI_POLL)) {
        !           771:                                if (!gdt_wait(gdt, ccb, ccb->gc_timeout)) {
        !           772:                                        splx(s);
        !           773:                                        printf("%s: command %d timed out\n",
        !           774:                                            DEVNAME(gdt),
        !           775:                                            ccb->gc_cmd_index);
        !           776:                                        return (TRY_AGAIN_LATER);
        !           777:                                }
        !           778:                                xs->flags |= ITSDONE;
        !           779:                                scsi_done(xs);
        !           780:                        }
        !           781:                }
        !           782:
        !           783:        ready:
        !           784:                /*
        !           785:                 * Don't process the queue if we are polling.
        !           786:                 */
        !           787:                if (xs->flags & SCSI_POLL) {
        !           788:                        retval = COMPLETE;
        !           789:                        break;
        !           790:                }
        !           791:        }
        !           792:
        !           793:        splx(s);
        !           794:        return (retval);
        !           795: }
        !           796:
        !           797: /* XXX Currently only for cacheservice, returns 0 if busy */
        !           798: int
        !           799: gdt_exec_ccb(ccb)
        !           800:        struct gdt_ccb *ccb;
        !           801: {
        !           802:        struct scsi_xfer *xs = ccb->gc_xs;
        !           803:        struct scsi_link *link = xs->sc_link;
        !           804:        struct gdt_softc *gdt = link->adapter_softc;
        !           805:        u_int8_t target = link->target;
        !           806:        u_int32_t sg_canz;
        !           807:        bus_dmamap_t xfer;
        !           808:        int i;
        !           809: #if 1 /* XXX */
        !           810:        static int __level = 0;
        !           811:
        !           812:        if (__level++ > 0)
        !           813:                panic("level > 0");
        !           814: #endif
        !           815:        GDT_DPRINTF(GDT_D_CMD, ("gdt_exec_ccb(%p, %p) ", xs, ccb));
        !           816:
        !           817:        gdt->sc_cmd_cnt = 0;
        !           818:
        !           819:        /*
        !           820:         * XXX Yeah I know it's an always-true condition, but that may change
        !           821:         * later.
        !           822:         */
        !           823:        if (gdt->sc_cmd_cnt == 0)
        !           824:                gdt->sc_set_sema0(gdt);
        !           825:
        !           826:        gdt_enc32(gdt->sc_cmd + GDT_CMD_COMMANDINDEX, ccb->gc_cmd_index);
        !           827:        gdt_enc32(gdt->sc_cmd + GDT_CMD_BOARDNODE, GDT_LOCALBOARD);
        !           828:        gdt_enc16(gdt->sc_cmd + GDT_CMD_UNION + GDT_CACHE_DEVICENO,
        !           829:            target);
        !           830:
        !           831:        switch (xs->cmd->opcode) {
        !           832:        case PREVENT_ALLOW:
        !           833:        case SYNCHRONIZE_CACHE:
        !           834:                if (xs->cmd->opcode == PREVENT_ALLOW) {
        !           835:                        /* XXX PREVENT_ALLOW support goes here */
        !           836:                } else {
        !           837:                        GDT_DPRINTF(GDT_D_CMD,
        !           838:                            ("SYNCHRONIZE CACHE tgt %d ", target));
        !           839:                        gdt->sc_cmd[GDT_CMD_OPCODE] = GDT_FLUSH;
        !           840:                }
        !           841:                gdt_enc32(gdt->sc_cmd + GDT_CMD_UNION + GDT_CACHE_BLOCKNO,
        !           842:                    1);
        !           843:                sg_canz = 0;
        !           844:                break;
        !           845:
        !           846:        case WRITE_COMMAND:
        !           847:        case WRITE_BIG:
        !           848:                /* XXX WRITE_THR could be supported too */
        !           849:                gdt->sc_cmd[GDT_CMD_OPCODE] = GDT_WRITE;
        !           850:                break;
        !           851:
        !           852:        case READ_COMMAND:
        !           853:        case READ_BIG:
        !           854:                gdt->sc_cmd[GDT_CMD_OPCODE] = GDT_READ;
        !           855:                break;
        !           856:        }
        !           857:
        !           858:        if (xs->cmd->opcode != PREVENT_ALLOW &&
        !           859:            xs->cmd->opcode != SYNCHRONIZE_CACHE) {
        !           860:                gdt_enc32(gdt->sc_cmd + GDT_CMD_UNION + GDT_CACHE_BLOCKNO,
        !           861:                    ccb->gc_blockno);
        !           862:                gdt_enc32(gdt->sc_cmd + GDT_CMD_UNION + GDT_CACHE_BLOCKCNT,
        !           863:                    ccb->gc_blockcnt);
        !           864:
        !           865:                xfer = ccb->gc_dmamap_xfer;
        !           866:                if (gdt->sc_cache_feat & GDT_SCATTER_GATHER) {
        !           867:                        gdt_enc32(
        !           868:                            gdt->sc_cmd + GDT_CMD_UNION + GDT_CACHE_DESTADDR,
        !           869:                            0xffffffff);
        !           870:                        for (i = 0; i < xfer->dm_nsegs; i++) {
        !           871:                                gdt_enc32(gdt->sc_cmd + GDT_CMD_UNION +
        !           872:                                    GDT_CACHE_SG_LST + i * GDT_SG_SZ +
        !           873:                                    GDT_SG_PTR,
        !           874:                                    xfer->dm_segs[i].ds_addr);
        !           875:                                gdt_enc32(gdt->sc_cmd + GDT_CMD_UNION +
        !           876:                                    GDT_CACHE_SG_LST + i * GDT_SG_SZ +
        !           877:                                    GDT_SG_LEN,
        !           878:                                    xfer->dm_segs[i].ds_len);
        !           879:                                GDT_DPRINTF(GDT_D_IO,
        !           880:                                    ("#%d va %p pa %p len %x\n", i, buf,
        !           881:                                    xfer->dm_segs[i].ds_addr,
        !           882:                                    xfer->dm_segs[i].ds_len));
        !           883:                        }
        !           884:                        sg_canz = xfer->dm_nsegs;
        !           885:                        gdt_enc32(
        !           886:                            gdt->sc_cmd + GDT_CMD_UNION + GDT_CACHE_SG_LST +
        !           887:                            sg_canz * GDT_SG_SZ + GDT_SG_LEN, 0);
        !           888:                } else {
        !           889:                        /* XXX Hardly correct */
        !           890:                        gdt_enc32(
        !           891:                            gdt->sc_cmd + GDT_CMD_UNION + GDT_CACHE_DESTADDR,
        !           892:                            xfer->dm_segs[0].ds_addr);
        !           893:                        sg_canz = 0;
        !           894:                }
        !           895:        }
        !           896:        gdt_enc32(gdt->sc_cmd + GDT_CMD_UNION + GDT_CACHE_SG_CANZ, sg_canz);
        !           897:
        !           898:        gdt->sc_cmd_len =
        !           899:            roundup(GDT_CMD_UNION + GDT_CACHE_SG_LST + sg_canz * GDT_SG_SZ,
        !           900:            sizeof (u_int32_t));
        !           901:
        !           902:        if (gdt->sc_cmd_cnt > 0 &&
        !           903:            gdt->sc_cmd_off + gdt->sc_cmd_len + GDT_DPMEM_COMMAND_OFFSET >
        !           904:            gdt->sc_ic_all_size) {
        !           905:                printf("%s: DPMEM overflow\n", DEVNAME(gdt));
        !           906:                gdt_free_ccb(gdt, ccb);
        !           907:                xs->error = XS_BUSY;
        !           908: #if 1 /* XXX */
        !           909:                __level--;
        !           910: #endif
        !           911:                return (0);
        !           912:        }
        !           913:
        !           914:        gdt->sc_copy_cmd(gdt, ccb);
        !           915:        gdt->sc_release_event(gdt, ccb);
        !           916:
        !           917:        xs->error = XS_NOERROR;
        !           918:        xs->resid = 0;
        !           919: #if 1 /* XXX */
        !           920:        __level--;
        !           921: #endif
        !           922:        return (1);
        !           923: }
        !           924:
        !           925: void
        !           926: gdt_copy_internal_data(xs, data, size)
        !           927:        struct scsi_xfer *xs;
        !           928:        u_int8_t *data;
        !           929:        size_t size;
        !           930: {
        !           931:        size_t copy_cnt;
        !           932:
        !           933:        GDT_DPRINTF(GDT_D_MISC, ("gdt_copy_internal_data "));
        !           934:
        !           935:        if (!xs->datalen)
        !           936:                printf("uio move not yet supported\n");
        !           937:        else {
        !           938:                copy_cnt = MIN(size, xs->datalen);
        !           939:                bcopy(data, xs->data, copy_cnt);
        !           940:        }
        !           941: }
        !           942:
        !           943: /* Emulated SCSI operation on cache device */
        !           944: void
        !           945: gdt_internal_cache_cmd(xs)
        !           946:        struct scsi_xfer *xs;
        !           947: {
        !           948:        struct scsi_link *link = xs->sc_link;
        !           949:        struct gdt_softc *gdt = link->adapter_softc;
        !           950:        struct scsi_inquiry_data inq;
        !           951:        struct scsi_sense_data sd;
        !           952:        struct scsi_read_cap_data rcd;
        !           953:        u_int8_t target = link->target;
        !           954:
        !           955:        GDT_DPRINTF(GDT_D_CMD, ("gdt_internal_cache_cmd "));
        !           956:
        !           957:        switch (xs->cmd->opcode) {
        !           958:        case TEST_UNIT_READY:
        !           959:        case START_STOP:
        !           960: #if 0
        !           961:        case VERIFY:
        !           962: #endif
        !           963:                GDT_DPRINTF(GDT_D_CMD, ("opc %d tgt %d ", xs->cmd->opcode,
        !           964:                    target));
        !           965:                break;
        !           966:
        !           967:        case REQUEST_SENSE:
        !           968:                GDT_DPRINTF(GDT_D_CMD, ("REQUEST SENSE tgt %d ", target));
        !           969:                bzero(&sd, sizeof sd);
        !           970:                sd.error_code = 0x70;
        !           971:                sd.segment = 0;
        !           972:                sd.flags = SKEY_NO_SENSE;
        !           973:                gdt_enc32(sd.info, 0);
        !           974:                sd.extra_len = 0;
        !           975:                gdt_copy_internal_data(xs, (u_int8_t *)&sd, sizeof sd);
        !           976:                break;
        !           977:
        !           978:        case INQUIRY:
        !           979:                GDT_DPRINTF(GDT_D_CMD, ("INQUIRY tgt %d devtype %x ", target,
        !           980:                    gdt->sc_hdr[target].hd_devtype));
        !           981:                bzero(&inq, sizeof inq);
        !           982:                inq.device =
        !           983:                    (gdt->sc_hdr[target].hd_devtype & 4) ? T_CDROM : T_DIRECT;
        !           984:                inq.dev_qual2 =
        !           985:                    (gdt->sc_hdr[target].hd_devtype & 1) ? SID_REMOVABLE : 0;
        !           986:                inq.version = 2;
        !           987:                inq.response_format = 2;
        !           988:                inq.additional_length = 32;
        !           989:                strlcpy(inq.vendor, "ICP           ", sizeof inq.vendor);
        !           990:                snprintf(inq.product, sizeof inq.product, "Host drive  #%02d",
        !           991:                    target);
        !           992:                strlcpy(inq.revision, "  ", sizeof inq.revision);
        !           993:                gdt_copy_internal_data(xs, (u_int8_t *)&inq, sizeof inq);
        !           994:                break;
        !           995:
        !           996:        case READ_CAPACITY:
        !           997:                GDT_DPRINTF(GDT_D_CMD, ("READ CAPACITY tgt %d ", target));
        !           998:                bzero(&rcd, sizeof rcd);
        !           999:                _lto4b(gdt->sc_hdr[target].hd_size - 1, rcd.addr);
        !          1000:                _lto4b(GDT_SECTOR_SIZE, rcd.length);
        !          1001:                gdt_copy_internal_data(xs, (u_int8_t *)&rcd, sizeof rcd);
        !          1002:                break;
        !          1003:
        !          1004:        default:
        !          1005:                GDT_DPRINTF(GDT_D_CMD, ("unsupported scsi command %#x tgt %d ",
        !          1006:                    xs->cmd->opcode, target));
        !          1007:                xs->error = XS_DRIVER_STUFFUP;
        !          1008:                return;
        !          1009:        }
        !          1010:
        !          1011:        xs->error = XS_NOERROR;
        !          1012: }
        !          1013:
        !          1014: /* Start a raw SCSI operation */
        !          1015: int
        !          1016: gdt_raw_scsi_cmd(xs)
        !          1017:        struct scsi_xfer *xs;
        !          1018: {
        !          1019:        struct scsi_link *link = xs->sc_link;
        !          1020:        struct gdt_softc *gdt = link->adapter_softc;
        !          1021:        struct gdt_ccb *ccb;
        !          1022:        int s;
        !          1023:
        !          1024:        GDT_DPRINTF(GDT_D_CMD, ("gdt_raw_scsi_cmd "));
        !          1025:
        !          1026:        if (xs->cmdlen > 12 /* XXX create #define */) {
        !          1027:                GDT_DPRINTF(GDT_D_CMD, ("CDB too big %p ", xs));
        !          1028:                bzero(&xs->sense, sizeof(xs->sense));
        !          1029:                xs->sense.error_code = SSD_ERRCODE_VALID | 0x70;
        !          1030:                xs->sense.flags = SKEY_ILLEGAL_REQUEST;
        !          1031:                xs->sense.add_sense_code = 0x20; /* illcmd, 0x24 illfield */
        !          1032:                xs->error = XS_SENSE;
        !          1033:                s = splbio();
        !          1034:                scsi_done(xs);
        !          1035:                splx(s);
        !          1036:                return (COMPLETE);
        !          1037:        }
        !          1038:
        !          1039:        if ((ccb = gdt_get_ccb(gdt, xs->flags)) == NULL) {
        !          1040:                GDT_DPRINTF(GDT_D_CMD, ("no ccb available for %p ", xs));
        !          1041:                xs->error = XS_DRIVER_STUFFUP;
        !          1042:                s = splbio();
        !          1043:                scsi_done(xs);
        !          1044:                splx(s);
        !          1045:                return (COMPLETE);
        !          1046:        }
        !          1047:
        !          1048:        xs->error = XS_DRIVER_STUFFUP;
        !          1049:        xs->flags |= ITSDONE;
        !          1050:        s = splbio();
        !          1051:        scsi_done(xs);
        !          1052:        gdt_free_ccb(gdt, ccb);
        !          1053:
        !          1054:        splx(s);
        !          1055:
        !          1056:        return (COMPLETE);
        !          1057: }
        !          1058:
        !          1059: void
        !          1060: gdt_clear_events(gdt)
        !          1061:        struct gdt_softc *gdt;
        !          1062: {
        !          1063:        GDT_DPRINTF(GDT_D_MISC, ("gdt_clear_events(%p) ", gdt));
        !          1064:
        !          1065:        /* XXX To be implemented */
        !          1066: }
        !          1067:
        !          1068: int
        !          1069: gdt_async_event(gdt, service)
        !          1070:        struct gdt_softc *gdt;
        !          1071:        int service;
        !          1072: {
        !          1073:        GDT_DPRINTF(GDT_D_INTR, ("gdt_async_event(%p, %d) ", gdt, service));
        !          1074:
        !          1075:        if (service == GDT_SCREENSERVICE) {
        !          1076:                /* XXX To be implemented */
        !          1077:        } else {
        !          1078:                /* XXX To be implemented */
        !          1079:        }
        !          1080:
        !          1081:        return (0);
        !          1082: }
        !          1083:
        !          1084: int
        !          1085: gdt_sync_event(gdt, service, index, xs)
        !          1086:        struct gdt_softc *gdt;
        !          1087:        int service;
        !          1088:        u_int8_t index;
        !          1089:        struct scsi_xfer *xs;
        !          1090: {
        !          1091:        GDT_DPRINTF(GDT_D_INTR,
        !          1092:            ("gdt_sync_event(%p, %d, %d, %p) ", gdt, service, index, xs));
        !          1093:
        !          1094:        if (service == GDT_SCREENSERVICE) {
        !          1095:                GDT_DPRINTF(GDT_D_INTR, ("service == GDT_SCREENSERVICE "));
        !          1096:                /* XXX To be implemented */
        !          1097:                return (0);
        !          1098:        } else {
        !          1099:                switch (gdt->sc_status) {
        !          1100:                case GDT_S_OK:
        !          1101:                        GDT_DPRINTF(GDT_D_INTR, ("sc_status == GDT_S_OK "));
        !          1102:                        /* XXX To be implemented */
        !          1103:                        break;
        !          1104:                case GDT_S_BSY:
        !          1105:                        GDT_DPRINTF(GDT_D_INTR, ("sc_status == GDT_S_BSY "));
        !          1106:                        /* XXX To be implemented */
        !          1107:                        return (2);
        !          1108:                default:
        !          1109:                        GDT_DPRINTF(GDT_D_INTR, ("sc_status is %d ",
        !          1110:                            gdt->sc_status));
        !          1111:                        /* XXX To be implemented */
        !          1112:                        return (0);
        !          1113:                }
        !          1114:        }
        !          1115:
        !          1116:        return (1);
        !          1117: }
        !          1118:
        !          1119: int
        !          1120: gdt_intr(arg)
        !          1121:        void *arg;
        !          1122: {
        !          1123:        struct gdt_softc *gdt = arg;
        !          1124:        struct gdt_intr_ctx ctx;
        !          1125:        int chain = 1;
        !          1126:        int sync_val = 0;
        !          1127:        struct scsi_xfer *xs;
        !          1128:        int prev_cmd;
        !          1129:        struct gdt_ccb *ccb;
        !          1130:        int s;
        !          1131:
        !          1132:        GDT_DPRINTF(GDT_D_INTR, ("gdt_intr(%p) ", gdt));
        !          1133:
        !          1134:        /* If polling and we were not called from gdt_wait, just return */
        !          1135:        if (gdt_polling && !gdt_from_wait)
        !          1136:                return (0);
        !          1137:
        !          1138:        if (!gdt_polling)
        !          1139:                s = splbio();
        !          1140:
        !          1141:        ctx.istatus = gdt->sc_get_status(gdt);
        !          1142:        if (!ctx.istatus) {
        !          1143:                if (!gdt_polling)
        !          1144:                        splx(s);
        !          1145:                gdt->sc_status = GDT_S_NO_STATUS;
        !          1146:                return (0);
        !          1147:        }
        !          1148:
        !          1149:        gdt_wait_index = 0;
        !          1150:        ctx.service = ctx.info2 = 0;
        !          1151:
        !          1152:        gdt->sc_intr(gdt, &ctx);
        !          1153:
        !          1154:        gdt->sc_status = ctx.cmd_status;
        !          1155:        gdt->sc_info = ctx.info;
        !          1156:        gdt->sc_info2 = ctx.info2;
        !          1157:
        !          1158:        if (gdt_from_wait) {
        !          1159:                gdt_wait_gdt = gdt;
        !          1160:                gdt_wait_index = ctx.istatus;
        !          1161:        }
        !          1162:
        !          1163:        switch (ctx.istatus) {
        !          1164:        case GDT_ASYNCINDEX:
        !          1165:                gdt_async_event(gdt, ctx.service);
        !          1166:                goto finish;
        !          1167:
        !          1168:        case GDT_SPEZINDEX:
        !          1169:                printf("%s: uninitialized or unknown service (%d %d)\n",
        !          1170:                    DEVNAME(gdt), ctx.info, ctx.info2);
        !          1171:                chain = 0;
        !          1172:                goto finish;
        !          1173:        }
        !          1174:
        !          1175:        ccb = &gdt->sc_ccbs[ctx.istatus - 2];
        !          1176:        xs = ccb->gc_xs;
        !          1177:        if (!gdt_polling)
        !          1178:                timeout_del(&xs->stimeout);
        !          1179:        ctx.service = ccb->gc_service;
        !          1180:        prev_cmd = ccb->gc_flags & GDT_GCF_CMD_MASK;
        !          1181:        if (xs && xs->cmd->opcode != PREVENT_ALLOW &&
        !          1182:            xs->cmd->opcode != SYNCHRONIZE_CACHE) {
        !          1183:                bus_dmamap_sync(gdt->sc_dmat, ccb->gc_dmamap_xfer, 0,
        !          1184:                    ccb->gc_dmamap_xfer->dm_mapsize,
        !          1185:                    (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_POSTREAD :
        !          1186:                    BUS_DMASYNC_POSTWRITE);
        !          1187:                bus_dmamap_unload(gdt->sc_dmat, ccb->gc_dmamap_xfer);
        !          1188:        }
        !          1189:        gdt_free_ccb(gdt, ccb);
        !          1190:        switch (prev_cmd) {
        !          1191:        case GDT_GCF_UNUSED:
        !          1192:                /* XXX Not yet implemented */
        !          1193:                chain = 0;
        !          1194:                goto finish;
        !          1195:        case GDT_GCF_INTERNAL:
        !          1196:                chain = 0;
        !          1197:                goto finish;
        !          1198:        }
        !          1199:
        !          1200:        sync_val = gdt_sync_event(gdt, ctx.service, ctx.istatus, xs);
        !          1201:
        !          1202:  finish:
        !          1203:        if (!gdt_polling)
        !          1204:                splx(s);
        !          1205:
        !          1206:        switch (sync_val) {
        !          1207:        case 1:
        !          1208:                xs->flags |= ITSDONE;
        !          1209:                scsi_done(xs);
        !          1210:                break;
        !          1211:
        !          1212:        case 2:
        !          1213:                gdt_enqueue(gdt, xs, 0);
        !          1214:        }
        !          1215:
        !          1216:        if (chain)
        !          1217:                gdt_chain(gdt);
        !          1218:        return (1);
        !          1219: }
        !          1220:
        !          1221: void
        !          1222: gdtminphys(bp)
        !          1223:        struct buf *bp;
        !          1224: {
        !          1225:        GDT_DPRINTF(GDT_D_MISC, ("gdtminphys(0x%x) ", bp));
        !          1226:
        !          1227:        /* As this is way more than MAXPHYS it's really not necessary. */
        !          1228:        if ((GDT_MAXOFFSETS - 1) * PAGE_SIZE < MAXPHYS &&
        !          1229:            bp->b_bcount > ((GDT_MAXOFFSETS - 1) * PAGE_SIZE))
        !          1230:                bp->b_bcount = ((GDT_MAXOFFSETS - 1) * PAGE_SIZE);
        !          1231:
        !          1232:        minphys(bp);
        !          1233: }
        !          1234:
        !          1235: int
        !          1236: gdt_wait(gdt, ccb, timeout)
        !          1237:        struct gdt_softc *gdt;
        !          1238:        struct gdt_ccb *ccb;
        !          1239:        int timeout;
        !          1240: {
        !          1241:        int rv = 0;
        !          1242:
        !          1243:        GDT_DPRINTF(GDT_D_MISC,
        !          1244:            ("gdt_wait(%p, %p, %d) ", gdt, ccb, timeout));
        !          1245:
        !          1246:        gdt_from_wait = 1;
        !          1247:        do {
        !          1248:                if (gdt_intr(gdt) && gdt == gdt_wait_gdt &&
        !          1249:                    ccb->gc_cmd_index == gdt_wait_index) {
        !          1250:                        rv = 1;
        !          1251:                        break;
        !          1252:                }
        !          1253:                DELAY(1);
        !          1254:        } while (--timeout);
        !          1255:        gdt_from_wait = 0;
        !          1256:
        !          1257:        while (gdt->sc_test_busy(gdt))
        !          1258:                DELAY(0);               /* XXX correct? */
        !          1259:
        !          1260:        return (rv);
        !          1261: }
        !          1262:
        !          1263: int
        !          1264: gdt_internal_cmd(gdt, service, opcode, arg1, arg2, arg3)
        !          1265:        struct gdt_softc *gdt;
        !          1266:        u_int8_t service;
        !          1267:        u_int16_t opcode;
        !          1268:        u_int32_t arg1, arg2, arg3;
        !          1269: {
        !          1270:        int retries;
        !          1271:        struct gdt_ccb *ccb;
        !          1272:
        !          1273:        GDT_DPRINTF(GDT_D_CMD, ("gdt_internal_cmd(%p, %d, %d, %d, %d, %d) ",
        !          1274:            gdt, service, opcode, arg1, arg2, arg3));
        !          1275:
        !          1276:        bzero(gdt->sc_cmd, GDT_CMD_SZ);
        !          1277:
        !          1278:        for (retries = GDT_RETRIES; ; ) {
        !          1279:                ccb = gdt_get_ccb(gdt, SCSI_NOSLEEP);
        !          1280:                if (ccb == NULL) {
        !          1281:                        printf("%s: no free command index found\n",
        !          1282:                            DEVNAME(gdt));
        !          1283:                        return (0);
        !          1284:                }
        !          1285:                ccb->gc_service = service;
        !          1286:                gdt_ccb_set_cmd(ccb, GDT_GCF_INTERNAL);
        !          1287:
        !          1288:                gdt->sc_set_sema0(gdt);
        !          1289:                gdt_enc32(gdt->sc_cmd + GDT_CMD_COMMANDINDEX,
        !          1290:                    ccb->gc_cmd_index);
        !          1291:                gdt_enc16(gdt->sc_cmd + GDT_CMD_OPCODE, opcode);
        !          1292:                gdt_enc32(gdt->sc_cmd + GDT_CMD_BOARDNODE, GDT_LOCALBOARD);
        !          1293:
        !          1294:                switch (service) {
        !          1295:                case GDT_CACHESERVICE:
        !          1296:                        if (opcode == GDT_IOCTL) {
        !          1297:                                gdt_enc32(gdt->sc_cmd + GDT_CMD_UNION +
        !          1298:                                    GDT_IOCTL_SUBFUNC, arg1);
        !          1299:                                gdt_enc32(gdt->sc_cmd + GDT_CMD_UNION +
        !          1300:                                    GDT_IOCTL_CHANNEL, arg2);
        !          1301:                                gdt_enc16(gdt->sc_cmd + GDT_CMD_UNION +
        !          1302:                                    GDT_IOCTL_PARAM_SIZE, (u_int16_t)arg3);
        !          1303:                                gdt_enc32(gdt->sc_cmd + GDT_CMD_UNION +
        !          1304:                                    GDT_IOCTL_P_PARAM,
        !          1305:                                    gdt->sc_scratch_seg.ds_addr);
        !          1306:                        } else {
        !          1307:                                gdt_enc16(gdt->sc_cmd + GDT_CMD_UNION +
        !          1308:                                    GDT_CACHE_DEVICENO, (u_int16_t)arg1);
        !          1309:                                gdt_enc32(gdt->sc_cmd + GDT_CMD_UNION +
        !          1310:                                    GDT_CACHE_BLOCKNO, arg2);
        !          1311:                        }
        !          1312:                        break;
        !          1313:
        !          1314:                case GDT_SCSIRAWSERVICE:
        !          1315:                        gdt_enc32(gdt->sc_cmd + GDT_CMD_UNION +
        !          1316:                            GDT_RAW_DIRECTION, arg1);
        !          1317:                        gdt->sc_cmd[GDT_CMD_UNION + GDT_RAW_BUS] =
        !          1318:                            (u_int8_t)arg2;
        !          1319:                        gdt->sc_cmd[GDT_CMD_UNION + GDT_RAW_TARGET] =
        !          1320:                            (u_int8_t)arg3;
        !          1321:                        gdt->sc_cmd[GDT_CMD_UNION + GDT_RAW_LUN] =
        !          1322:                            (u_int8_t)(arg3 >> 8);
        !          1323:                }
        !          1324:
        !          1325:                gdt->sc_cmd_len = GDT_CMD_SZ;
        !          1326:                gdt->sc_cmd_off = 0;
        !          1327:                gdt->sc_cmd_cnt = 0;
        !          1328:                gdt->sc_copy_cmd(gdt, ccb);
        !          1329:                gdt->sc_release_event(gdt, ccb);
        !          1330:                DELAY(20);
        !          1331:                if (!gdt_wait(gdt, ccb, GDT_POLL_TIMEOUT))
        !          1332:                        return (0);
        !          1333:                if (gdt->sc_status != GDT_S_BSY || --retries == 0)
        !          1334:                        break;
        !          1335:                DELAY(1);
        !          1336:        }
        !          1337:        return (gdt->sc_status == GDT_S_OK);
        !          1338: }
        !          1339:
        !          1340: struct gdt_ccb *
        !          1341: gdt_get_ccb(gdt, flags)
        !          1342:        struct gdt_softc *gdt;
        !          1343:        int flags;
        !          1344: {
        !          1345:        struct gdt_ccb *ccb;
        !          1346:        int s;
        !          1347:
        !          1348:        GDT_DPRINTF(GDT_D_QUEUE, ("gdt_get_ccb(%p, 0x%x) ", gdt, flags));
        !          1349:
        !          1350:        s = splbio();
        !          1351:
        !          1352:        for (;;) {
        !          1353:                ccb = TAILQ_FIRST(&gdt->sc_free_ccb);
        !          1354:                if (ccb != NULL)
        !          1355:                        break;
        !          1356:                if (flags & SCSI_NOSLEEP)
        !          1357:                        goto bail_out;
        !          1358:                tsleep(&gdt->sc_free_ccb, PRIBIO, "gdt_ccb", 0);
        !          1359:        }
        !          1360:
        !          1361:        TAILQ_REMOVE(&gdt->sc_free_ccb, ccb, gc_chain);
        !          1362:
        !          1363:  bail_out:
        !          1364:        splx(s);
        !          1365:        return (ccb);
        !          1366: }
        !          1367:
        !          1368: void
        !          1369: gdt_free_ccb(gdt, ccb)
        !          1370:        struct gdt_softc *gdt;
        !          1371:        struct gdt_ccb *ccb;
        !          1372: {
        !          1373:        int s;
        !          1374:
        !          1375:        GDT_DPRINTF(GDT_D_QUEUE, ("gdt_free_ccb(%p, %p) ", gdt, ccb));
        !          1376:
        !          1377:        s = splbio();
        !          1378:
        !          1379:        TAILQ_INSERT_HEAD(&gdt->sc_free_ccb, ccb, gc_chain);
        !          1380:
        !          1381:        /* If the free list was empty, wake up potential waiters. */
        !          1382:        if (TAILQ_NEXT(ccb, gc_chain) == NULL)
        !          1383:                wakeup(&gdt->sc_free_ccb);
        !          1384:
        !          1385:        splx(s);
        !          1386: }
        !          1387:
        !          1388: void
        !          1389: gdt_enqueue_ccb(gdt, ccb)
        !          1390:        struct gdt_softc *gdt;
        !          1391:        struct gdt_ccb *ccb;
        !          1392: {
        !          1393:        GDT_DPRINTF(GDT_D_QUEUE, ("gdt_enqueue_ccb(%p, %p) ", gdt, ccb));
        !          1394:
        !          1395:        timeout_set(&ccb->gc_xs->stimeout, gdt_timeout, ccb);
        !          1396:        TAILQ_INSERT_TAIL(&gdt->sc_ccbq, ccb, gc_chain);
        !          1397:        gdt_start_ccbs(gdt);
        !          1398: }
        !          1399:
        !          1400: void
        !          1401: gdt_start_ccbs(gdt)
        !          1402:        struct gdt_softc *gdt;
        !          1403: {
        !          1404:        struct gdt_ccb *ccb;
        !          1405:        struct scsi_xfer *xs;
        !          1406:
        !          1407:        GDT_DPRINTF(GDT_D_QUEUE, ("gdt_start_ccbs(%p) ", gdt));
        !          1408:
        !          1409:        while ((ccb = TAILQ_FIRST(&gdt->sc_ccbq)) != NULL) {
        !          1410:
        !          1411:                xs = ccb->gc_xs;
        !          1412:                if (ccb->gc_flags & GDT_GCF_WATCHDOG)
        !          1413:                        timeout_del(&xs->stimeout);
        !          1414:
        !          1415:                if (gdt_exec_ccb(ccb) == 0) {
        !          1416:                        ccb->gc_flags |= GDT_GCF_WATCHDOG;
        !          1417:                        timeout_set(&ccb->gc_xs->stimeout, gdt_watchdog, ccb);
        !          1418:                        timeout_add(&xs->stimeout,
        !          1419:                            (GDT_WATCH_TIMEOUT * hz) / 1000);
        !          1420:                        break;
        !          1421:                }
        !          1422:                TAILQ_REMOVE(&gdt->sc_ccbq, ccb, gc_chain);
        !          1423:
        !          1424:                if ((xs->flags & SCSI_POLL) == 0) {
        !          1425:                        timeout_set(&ccb->gc_xs->stimeout, gdt_timeout, ccb);
        !          1426:                        timeout_add(&xs->stimeout,
        !          1427:                            (ccb->gc_timeout * hz) / 1000);
        !          1428:                }
        !          1429:        }
        !          1430: }
        !          1431:
        !          1432: void
        !          1433: gdt_chain(gdt)
        !          1434:        struct gdt_softc *gdt;
        !          1435: {
        !          1436:        GDT_DPRINTF(GDT_D_INTR, ("gdt_chain(%p) ", gdt));
        !          1437:
        !          1438:        if (LIST_FIRST(&gdt->sc_queue))
        !          1439:                gdt_scsi_cmd(LIST_FIRST(&gdt->sc_queue));
        !          1440: }
        !          1441:
        !          1442: void
        !          1443: gdt_timeout(arg)
        !          1444:        void *arg;
        !          1445: {
        !          1446:        struct gdt_ccb *ccb = arg;
        !          1447:        struct scsi_link *link = ccb->gc_xs->sc_link;
        !          1448:        struct gdt_softc *gdt = link->adapter_softc;
        !          1449:        int s;
        !          1450:
        !          1451:        sc_print_addr(link);
        !          1452:        printf("timed out\n");
        !          1453:
        !          1454:        /* XXX Test for multiple timeouts */
        !          1455:
        !          1456:        ccb->gc_xs->error = XS_TIMEOUT;
        !          1457:        s = splbio();
        !          1458:        gdt_enqueue_ccb(gdt, ccb);
        !          1459:        splx(s);
        !          1460: }
        !          1461:
        !          1462: void
        !          1463: gdt_watchdog(arg)
        !          1464:        void *arg;
        !          1465: {
        !          1466:        struct gdt_ccb *ccb = arg;
        !          1467:        struct scsi_link *link = ccb->gc_xs->sc_link;
        !          1468:        struct gdt_softc *gdt = link->adapter_softc;
        !          1469:        int s;
        !          1470:
        !          1471:        s = splbio();
        !          1472:        ccb->gc_flags &= ~GDT_GCF_WATCHDOG;
        !          1473:        gdt_start_ccbs(gdt);
        !          1474:        splx(s);
        !          1475: }
        !          1476:
        !          1477: #if NBIO > 0
        !          1478: int
        !          1479: gdt_ioctl(struct device *dev, u_long cmd, caddr_t addr)
        !          1480: {
        !          1481:        struct gdt_softc *sc = (struct gdt_softc *)dev;
        !          1482:        int error = 0;
        !          1483:
        !          1484:        GDT_DPRINTF(GDT_D_IOCTL, ("%s: ioctl ", DEVNAME(sc)));
        !          1485:
        !          1486:        switch (cmd) {
        !          1487:        case BIOCINQ:
        !          1488:                GDT_DPRINTF(GDT_D_IOCTL, ("inq "));
        !          1489:                error = gdt_ioctl_inq(sc, (struct bioc_inq *)addr);
        !          1490:                break;
        !          1491:
        !          1492:        case BIOCVOL:
        !          1493:                GDT_DPRINTF(GDT_D_IOCTL, ("vol "));
        !          1494:                error = gdt_ioctl_vol(sc, (struct bioc_vol *)addr);
        !          1495:                break;
        !          1496:
        !          1497:        case BIOCDISK:
        !          1498:                GDT_DPRINTF(GDT_D_IOCTL, ("disk "));
        !          1499:                error = gdt_ioctl_disk(sc, (struct bioc_disk *)addr);
        !          1500:                break;
        !          1501:
        !          1502:        case BIOCALARM:
        !          1503:                GDT_DPRINTF(GDT_D_IOCTL, ("alarm "));
        !          1504:                error = gdt_ioctl_alarm(sc, (struct bioc_alarm *)addr);
        !          1505:                break;
        !          1506:
        !          1507:        case BIOCSETSTATE:
        !          1508:                GDT_DPRINTF(GDT_D_IOCTL, ("setstate "));
        !          1509:                error = gdt_ioctl_setstate(sc, (struct bioc_setstate *)addr);
        !          1510:                break;
        !          1511:
        !          1512:        default:
        !          1513:                GDT_DPRINTF(GDT_D_IOCTL, (" invalid ioctl\n"));
        !          1514:                error = EINVAL;
        !          1515:        }
        !          1516:
        !          1517:        return (error);
        !          1518: }
        !          1519:
        !          1520: int
        !          1521: gdt_ioctl_inq(struct gdt_softc *sc, struct bioc_inq *bi)
        !          1522: {
        !          1523:        bi->bi_novol = sc->sc_ndevs;
        !          1524:        bi->bi_nodisk = sc->sc_total_disks;
        !          1525:
        !          1526:        strlcpy(bi->bi_dev, DEVNAME(sc), sizeof(bi->bi_dev));
        !          1527:
        !          1528:        return (0);
        !          1529: }
        !          1530:
        !          1531: int
        !          1532: gdt_ioctl_vol(struct gdt_softc *sc, struct bioc_vol *bv)
        !          1533: {
        !          1534:        return (1); /* XXX not yet */
        !          1535: }
        !          1536:
        !          1537: int
        !          1538: gdt_ioctl_disk(struct gdt_softc *sc, struct bioc_disk *bd)
        !          1539: {
        !          1540:        return (1); /* XXX not yet */
        !          1541: }
        !          1542:
        !          1543: int
        !          1544: gdt_ioctl_alarm(struct gdt_softc *sc, struct bioc_alarm *ba)
        !          1545: {
        !          1546:        return (1); /* XXX not yet */
        !          1547: }
        !          1548:
        !          1549: int
        !          1550: gdt_ioctl_setstate(struct gdt_softc *sc, struct bioc_setstate *bs)
        !          1551: {
        !          1552:        return (1); /* XXX not yet */
        !          1553: }
        !          1554:
        !          1555: #if 0
        !          1556: int
        !          1557: gdt_ioctl(dev, cmd, addr)
        !          1558:        struct device *dev;
        !          1559:        u_long cmd;
        !          1560:        caddr_t addr;
        !          1561: {
        !          1562:        int error = 0;
        !          1563:        struct gdt_dummy *dummy;
        !          1564:
        !          1565:        switch (cmd) {
        !          1566:        case GDT_IOCTL_DUMMY:
        !          1567:                dummy = (struct gdt_dummy *)addr;
        !          1568:                printf("%s: GDT_IOCTL_DUMMY %d\n", dev->dv_xname, dummy->x++);
        !          1569:                break;
        !          1570:
        !          1571:        case GDT_IOCTL_GENERAL: {
        !          1572:                gdt_ucmd_t *ucmd;
        !          1573:                struct gdt_softc *gdt = (struct gdt_softc *)dev;
        !          1574:                int s;
        !          1575:
        !          1576:                ucmd = (gdt_ucmd_t *)addr;
        !          1577:                s = splbio();
        !          1578:                TAILQ_INSERT_TAIL(&gdt->sc_ucmdq, ucmd, links);
        !          1579:                ucmd->complete_flag = FALSE;
        !          1580:                splx(s);
        !          1581:                gdt_chain(gdt);
        !          1582:                if (!ucmd->complete_flag)
        !          1583:                        (void)tsleep((void *)ucmd, PCATCH | PRIBIO, "gdtucw",
        !          1584:                            0);
        !          1585:                break;
        !          1586:        }
        !          1587:
        !          1588:        case GDT_IOCTL_DRVERS:
        !          1589:                ((gdt_drvers_t *)addr)->vers =
        !          1590:                    (GDT_DRIVER_VERSION << 8) | GDT_DRIVER_SUBVERSION;
        !          1591:                break;
        !          1592:
        !          1593:        case GDT_IOCTL_CTRCNT:
        !          1594:                ((gdt_ctrcnt_t *)addr)->cnt = gdt_cnt;
        !          1595:                break;
        !          1596:
        !          1597: #ifdef notyet
        !          1598:        case GDT_IOCTL_CTRTYPE: {
        !          1599:                gdt_ctrt_t *p;
        !          1600:                struct gdt_softc *gdt = (struct gdt_softc *)dev;
        !          1601:
        !          1602:                p = (gdt_ctrt_t *)addr;
        !          1603:                p->oem_id = 0x8000;
        !          1604:                p->type = 0xfd;
        !          1605:                p->info = (gdt->sc_bus << 8) | (gdt->sc_slot << 3);
        !          1606:                p->ext_type = 0x6000 | gdt->sc_subdevice;
        !          1607:                p->device_id = gdt->sc_device;
        !          1608:                p->sub_device_id = gdt->sc_subdevice;
        !          1609:                break;
        !          1610:        }
        !          1611: #endif
        !          1612:
        !          1613:        case GDT_IOCTL_OSVERS: {
        !          1614:                gdt_osv_t *p;
        !          1615:
        !          1616:                p = (gdt_osv_t *)addr;
        !          1617:                p->oscode = 10;
        !          1618:                p->version = osrelease[0] - '0';
        !          1619:                if (osrelease[1] == '.')
        !          1620:                        p->subversion = osrelease[2] - '0';
        !          1621:                else
        !          1622:                        p->subversion = 0;
        !          1623:                if (osrelease[3] == '.')
        !          1624:                        p->revision = osrelease[4] - '0';
        !          1625:                else
        !          1626:                        p->revision = 0;
        !          1627:                strlcpy(p->name, ostype, sizeof p->name);
        !          1628:                break;
        !          1629:        }
        !          1630:
        !          1631: #ifdef notyet
        !          1632:        case GDT_IOCTL_EVENT: {
        !          1633:                gdt_event_t *p;
        !          1634:                int s;
        !          1635:
        !          1636:                p = (gdt_event_t *)addr;
        !          1637:                if (p->erase == 0xff) {
        !          1638:                        if (p->dvr.event_source == GDT_ES_TEST)
        !          1639:                                p->dvr.event_data.size =
        !          1640:                                    sizeof(p->dvr.event_data.eu.test);
        !          1641:                        else if (p->dvr.event_source == GDT_ES_DRIVER)
        !          1642:                                p->dvr.event_data.size =
        !          1643:                                    sizeof(p->dvr.event_data.eu.driver);
        !          1644:                        else if (p->dvr.event_source == GDT_ES_SYNC)
        !          1645:                                p->dvr.event_data.size =
        !          1646:                                    sizeof(p->dvr.event_data.eu.sync);
        !          1647:                        else
        !          1648:                                p->dvr.event_data.size =
        !          1649:                                    sizeof(p->dvr.event_data.eu.async);
        !          1650:                        s = splbio();
        !          1651:                        gdt_store_event(p->dvr.event_source, p->dvr.event_idx,
        !          1652:                            &p->dvr.event_data);
        !          1653:                        splx(s);
        !          1654:                } else if (p->erase == 0xfe) {
        !          1655:                        s = splbio();
        !          1656:                        gdt_clear_events();
        !          1657:                        splx(s);
        !          1658:                } else if (p->erase == 0) {
        !          1659:                        p->handle = gdt_read_event(p->handle, &p->dvr);
        !          1660:                } else {
        !          1661:                        gdt_readapp_event((u_int8_t)p->erase, &p->dvr);
        !          1662:                }
        !          1663:                break;
        !          1664:        }
        !          1665: #endif
        !          1666:
        !          1667:        case GDT_IOCTL_STATIST:
        !          1668: #if 0
        !          1669:                bcopy(&gdt_stat, (gdt_statist_t *)addr, sizeof gdt_stat);
        !          1670: #else
        !          1671:                error = EOPNOTSUPP;
        !          1672: #endif
        !          1673:                break;
        !          1674:
        !          1675:        default:
        !          1676:                error = EINVAL;
        !          1677:        }
        !          1678:        return (error);
        !          1679: }
        !          1680: #endif /* 0 */
        !          1681: #endif /* NBIO > 0 */

CVSweb