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