root/sys/dev/ic/gdtvar.h
/*      $OpenBSD: gdtvar.h,v 1.27 2024/09/01 03:08:56 jsg Exp $ */

/*
 * Copyright (c) 1999, 2000 Niklas Hallqvist.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * This driver would not have written if it was not for the hardware donations
 * from both ICP-Vortex and Öko.neT.  I want to thank them for their support.
 */

#define DEVNAME(s)  ((s)->sc_dev.dv_xname)
#define GDT_CMD_RESERVE 4       /* Internal driver cmd reserve. */

#define GDT_SCRATCH_SZ 4096

#ifdef _KERNEL

/* Debugging */
/* #define GDT_DEBUG    GDT_D_IOCTL | GDT_D_INFO */
#ifdef GDT_DEBUG
#define GDT_DPRINTF(mask, args) if (gdt_debug & (mask)) printf args
#define GDT_D_INTR      0x01
#define GDT_D_MISC      0x02
#define GDT_D_CMD       0x04
#define GDT_D_QUEUE     0x08
#define GDT_D_IO        0x10
#define GDT_D_IOCTL     0x20
#define GDT_D_INFO      0x40
extern int gdt_debug;
#else
#define GDT_DPRINTF(mask, args)
#endif

/* Miscellaneous constants */
#define GDT_RETRIES             100000000       /* 100000 * 1us = 100s */
#define GDT_TIMEOUT             100000000       /* 100000 * 1us = 100s */
#define GDT_POLL_TIMEOUT        10000           /* 10000 * 1ms = 10s */
#define GDT_WATCH_TIMEOUT       10000           /* 10000 * 1ms = 10s */

/* Context structure for interrupt services */
struct gdt_intr_ctx {
        u_int32_t info, info2;
        u_int16_t cmd_status, service;
        u_int8_t istatus;
};

/*
 * A command control block, one for each corresponding command index of the
 * controller.
 */
struct gdt_ccb {
        TAILQ_ENTRY(gdt_ccb) gc_chain;
        struct scsi_xfer *gc_xs;
        bus_dmamap_t gc_dmamap_xfer;
        int gc_timeout;
        u_int32_t gc_info;
        u_int32_t gc_blockno;
        u_int32_t gc_blockcnt;
        u_int16_t gc_status;
        u_int8_t gc_service;
        u_int8_t gc_cmd_index;
        u_int8_t gc_flags;
#define GDT_GCF_CMD_MASK        0x3
#define GDT_GCF_UNUSED          0       
#define GDT_GCF_INTERNAL        1
#define GDT_GCF_SCREEN          2
#define GDT_GCF_SCSI            3
#define GDT_GCF_WATCHDOG        0x4
};

static inline int gdt_ccb_set_cmd(struct gdt_ccb *, int);
static inline int
gdt_ccb_set_cmd(struct gdt_ccb *ccb, int flag)
{
        int rv = ccb->gc_flags & GDT_GCF_CMD_MASK;

        ccb->gc_flags &= ~GDT_GCF_CMD_MASK;
        ccb->gc_flags |= flag;
        return (rv);
}

struct gdt_softc {
        struct  device sc_dev;
        void   *sc_ih;

        int     sc_class;               /* Controller class */
#define GDT_ISA         0x01
#define GDT_EISA        0x02
#define GDT_PCI         0x03
#define GDT_PCINEW      0x04
#define GDT_MPR         0x05
#define GDT_CLASS_MASK  0x07
#define GDT_FC          0x10
#define GDT_CLASS(gdt)  ((gdt)->sc_class & GDT_CLASS_MASK)

        bus_space_tag_t sc_dpmemt;
        bus_space_handle_t sc_dpmemh;
        bus_addr_t sc_dpmembase;
        bus_dma_tag_t sc_dmat;

        /* XXX These could go into a class-dependent opaque struct instead */
        bus_space_tag_t sc_iot;
        bus_space_handle_t sc_ioh;
        bus_addr_t sc_iobase;

        u_int16_t sc_ic_all_size;

        struct gdt_ccb sc_ccbs[GDT_MAXCMDS];
        TAILQ_HEAD(, gdt_ccb) sc_free_ccb, sc_ccbq;
        struct scsi_xfer_list sc_queue;

        struct mutex            sc_ccb_mtx;
        struct scsi_iopool      sc_iopool;

        int     sc_ndevs;

        u_int16_t sc_cmd_len;
        u_int16_t sc_cmd_off;
        u_int16_t sc_cmd_cnt;
        u_int8_t sc_cmd[GDT_CMD_SZ];

        u_int32_t sc_info;
        u_int32_t sc_info2;
        bus_dma_segment_t sc_scratch_seg;
        caddr_t sc_scratch;
        u_int16_t sc_status;

        u_int8_t sc_bus_cnt;
        u_int8_t sc_bus_id[GDT_MAXBUS];
        u_int8_t sc_more_proc;

        u_int32_t sc_total_disks;

        struct {
                u_int8_t hd_present;
                u_int8_t hd_is_logdrv;
                u_int8_t hd_is_arraydrv;
                u_int8_t hd_is_master;
                u_int8_t hd_is_parity;
                u_int8_t hd_is_hotfix;
                u_int8_t hd_master_no;
                u_int8_t hd_lock;
                u_int8_t hd_heads;
                u_int8_t hd_secs;
                u_int16_t hd_devtype;
                u_int32_t hd_size;
                u_int8_t hd_ldr_no;
                u_int8_t hd_rw_attribs;
                u_int32_t hd_start_sec;
        } sc_hdr[GDT_MAX_HDRIVES];

        struct {
                u_int8_t        ra_lock;        /* chan locked? (hot plug */
                u_int8_t        ra_phys_cnt;    /* physical disk count */
                u_int8_t        ra_local_no;    /* local channel number */
                u_int8_t        ra_io_cnt[GDT_MAXID];   /* current IO count */
                u_int32_t       ra_address;     /* channel address */
                u_int32_t       ra_id_list[GDT_MAXID];  /* IDs of phys disks */
        } sc_raw[GDT_MAXBUS];                   /* SCSI channels */

        struct {
                u_int32_t cp_version;
                u_int16_t cp_state;
                u_int16_t cp_strategy;
                u_int16_t cp_write_back;
                u_int16_t cp_block_size;
        } sc_cpar;

        struct {
                u_int32_t bi_ser_no;            /* serial number */
                u_int8_t bi_oem_id[2];          /* u_int8_t OEM ID */
                u_int16_t bi_ep_flags;          /* eprom flags */
                u_int32_t bi_proc_id;           /* processor ID */
                u_int32_t bi_memsize;           /* memory size (bytes) */
                u_int8_t bi_mem_banks;          /* memory banks */
                u_int8_t bi_chan_type;          /* channel type */
                u_int8_t bi_chan_count;         /* channel count */
                u_int8_t bi_rdongle_pres;       /* dongle present */
                u_int32_t bi_epr_fw_ver;        /* (eprom) firmware ver */
                u_int32_t bi_upd_fw_ver;        /* (update) firmware ver */
                u_int32_t bi_upd_revision;      /* update revision */
                char bi_type_string[16];        /* char controller name */
                char bi_raid_string[16];        /* char RAID firmware name */
                u_int8_t bi_update_pres;        /* update present? */
                u_int8_t bi_xor_pres;           /* XOR engine present */
                u_int8_t bi_prom_type;          /* ROM type (eprom/flash) */
                u_int8_t bi_prom_count;         /* number of ROM devices */
                u_int32_t bi_dup_pres;          /* duplexing module pres? */
                u_int32_t bi_chan_pres;         /* # of exp. channels */
                u_int32_t bi_mem_pres;          /* memory expansion inst? */
                u_int8_t bi_ft_bus_system;      /* fault bus supported? */
                u_int8_t bi_subtype_valid;      /* board_subtype valid */
                u_int8_t bi_board_subtype;      /* subtype/hardware level */
                u_int8_t bi_rampar_pres;        /* RAM parity check hw? */
        } sc_binfo;

        struct {
                u_int8_t bf_chaining;   /* chaining supported */
                u_int8_t bf_striping;   /* striping (RAID-0) supported */
                u_int8_t bf_mirroring;  /* mirroring (RAID-1) supported */
                u_int8_t bf_raid;       /* RAID-4/5/10 supported */
        } sc_bfeat;

        u_int16_t sc_raw_feat;
        u_int16_t sc_cache_feat;

        void (*sc_copy_cmd)(struct gdt_softc *, struct gdt_ccb *);
        u_int8_t (*sc_get_status)(struct gdt_softc *);
        void (*sc_intr)(struct gdt_softc *, struct gdt_intr_ctx *);
        void (*sc_release_event)(struct gdt_softc *, struct gdt_ccb *);
        void (*sc_set_sema0)(struct gdt_softc *);
        int (*sc_test_busy)(struct gdt_softc *);
};

int     gdt_attach(struct gdt_softc *);
int     gdt_intr(void *);

/* These all require correctly aligned buffers */
static inline void gdt_enc16(u_int8_t *, u_int16_t);
static inline void gdt_enc32(u_int8_t *, u_int32_t);
static inline u_int8_t gdt_dec8(u_int8_t *);
static inline u_int16_t gdt_dec16(u_int8_t *);
static inline u_int32_t gdt_dec32(u_int8_t *);

static inline void
gdt_enc16(u_int8_t *addr, u_int16_t value)
{
        *(u_int16_t *)addr = htole16(value);
}

static inline void
gdt_enc32(u_int8_t *addr, u_int32_t value)
{
        *(u_int32_t *)addr = htole32(value);
}

static inline u_int8_t
gdt_dec8(u_int8_t *addr)
{
        return *(u_int8_t *)addr;
}

static inline u_int16_t
gdt_dec16(u_int8_t *addr)
{
        return letoh16(*(u_int16_t *)addr);
}

static inline u_int32_t
gdt_dec32(u_int8_t *addr)
{
        return letoh32(*(u_int32_t *)addr);
}

extern u_int8_t gdt_polling;

#endif