root/sys/arch/acorn32/podulebus/escvar.h
/* $NetBSD: escvar.h,v 1.11 2025/12/01 07:53:51 andvar Exp $ */

/*
 * Copyright (c) 1995 Daniel Widenfalk
 *
 * 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.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by Daniel Widenfalk
 *      for the NetBSD Project.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission
 *
 * 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.
 */

#ifndef _ESCVAR_H_
#define _ESCVAR_H_

#ifndef _ESCREG_H_
#include <acorn32/podulebus/escreg.h>
#endif

/*
 * MAXCHAIN is the anticipated maximum number of chain blocks needed. This
 * assumes that we are NEVER requested to transfer more than MAXPHYS bytes.
 */
#define MAXCHAIN        (MAXPHYS/PAGE_SIZE+2)

/*
 * Maximum number of requests standing by. Could be anything, but I think 9
 * looks nice :-) NOTE: This does NOT include requests already started!
 */
#define MAXPENDING      9       /* 7 IDs + 2 extra */

/*
 * DMA chain block. If flg == ESC_CHAIN_PRG or flg == ESC_CHAIN_BUMP then
 * ptr is a VIRTUAL address. If flg == ESC_CHAIN_DMA then ptr is a PHYSICAL
 * address.
 */
struct  esc_dma_chain {
        void            *ptr;
        u_short         len;
        short           flg;
};
#define ESC_CHAIN_DMA   0x00
#define ESC_CHAIN_BUMP  0x01
#define ESC_CHAIN_PRG   0x02


/*
 * This struct contains the necessary info for a pending request. Pointer to
 * a scsipi_xfer struct.
 */
struct  esc_pending {
        TAILQ_ENTRY(esc_pending) link;
        struct scsipi_xfer       *xs;
};

/*
 * nexus contains all active data for one SCSI unit. Parts of the info in this
 * struct survives between scsi commands.
 */
struct nexus {
        struct  scsipi_xfer     *xs;            /* Pointer to request */

        u_char                   ID;            /* ID message to be sent */
        u_char                   clen;          /* scsi command length + */
        u_char                   cbuf[14];      /* the actual command bytes */

        struct esc_dma_chain     dma[MAXCHAIN]; /* DMA chain blocks */
        short                    max_link;      /* Maximum used of above */
        short                    cur_link;      /* Currently handled block */

        u_char                  *buf;           /* Virtual address of data */
        int                      len;           /* Bytes left to transfer */

        void                    *dma_buf;       /* Current DMA address */
        int                      dma_len;       /* Current DMA length */

        void                    *dma_blk_ptr;   /* Current chain address */
        int                      dma_blk_len;   /* Current chain length */
        u_char                   dma_blk_flg;   /* Current chain flags */

        u_char                   state;         /* Nexus state, see below */
        u_short                  flags;         /* Nexus flags, see below */

        short                    period;        /* Sync period to request */
        u_char                   offset;        /* Sync offset to request */

        u_char                   syncper;       /* FAS216 variable storage */
        u_char                   syncoff;       /* FAS216 variable storage */
        u_char                   config3;       /* FAS216 variable storage */

        u_char                   lun_unit;      /* (Lun<<4) | Unit of nexus */
        u_char                   status;        /* Status byte from unit*/

};

/* SCSI nexus_states */
#define ESC_NS_IDLE             0       /* Nexus idle */
#define ESC_NS_SELECTED 1       /* Last command was a SELECT command */
#define ESC_NS_DATA_IN          2       /* Last command was a TRANSFER_INFO */
                                        /* command during a data in phase */
#define ESC_NS_DATA_OUT 3       /* Last command was a TRANSFER_INFO */
                                        /* command during a data out phase */
#define ESC_NS_STATUS           4       /* We have send a COMMAND_COMPLETE */
                                        /* command and are awaiting status */
#define ESC_NS_MSG_IN           5       /* Last phase was MESSAGE IN */
#define ESC_NS_MSG_OUT          6       /* Last phase was MESSAGE OUT */
#define ESC_NS_SVC              7       /* We have sent the command */
#define ESC_NS_DISCONNECTING    8       /* We have received a disconnect msg */
#define ESC_NS_DISCONNECTED     9       /* We are disconnected */
#define ESC_NS_RESELECTED       10      /* We was reselected */
#define ESC_NS_DONE             11      /* Done. Prephsase to FINISHED */
#define ESC_NS_FINISHED         12      /* Really done. Call scsi_done */
#define ESC_NS_RESET            13      /* We are resetting this unit */

/* SCSI nexus flags */
#define ESC_NF_UNIT_BUSY        0x0001  /* Unit is not available */

#define ESC_NF_SELECT_ME        0x0002  /* Nexus is set up, waiting for bus */

#define ESC_NF_HAS_MSG          0x0010  /* We have received a complete msg */

#define ESC_NF_DO_SDTR          0x0020  /* We should send a SDTR */
#define ESC_NF_SDTR_SENT        0x0040  /* We have sent a SDTR */
#define ESC_NF_SYNC_TESTED      0x0080  /* We have negotiated sync */

#define ESC_NF_RESET            0x0100  /* Reset this nexus */
#define ESC_NF_IMMEDIATE        0x0200  /* We are operating from escicmd */

#define ESC_NF_RETRY_SELECT     0x1000  /* Selection needs retrying */

#define ESC_NF_DEBUG            0x8000  /* As it says: DEBUG */

struct  esc_softc {
        device_t                 sc_dev;        /* System required struct */
        struct  scsipi_channel   sc_channel;    /* For sub devices */
        struct  scsipi_adapter   sc_adapter;
        irqhandler_t             sc_ih;         /* Interrupt chain struct */

        TAILQ_HEAD(,esc_pending) sc_xs_pending;
        TAILQ_HEAD(,esc_pending) sc_xs_free;
        struct  esc_pending      sc_xs_store[MAXPENDING];

        esc_regmap_p             sc_esc;        /* FAS216 Address */
        void                    *sc_spec;       /* Board-specific data */

        u_char                  *sc_bump_va;    /* Bumpbuf virtual adr */
        void                    *sc_bump_pa;    /* Bumpbuf physical adr */
        int                      sc_bump_sz;    /* Bumpbuf size */

/* Configuration registers, must be set BEFORE escinitialize */
        u_char                   sc_clock_freq;
        u_short                  sc_timeout;
        u_char                   sc_host_id;
        u_char                   sc_config_flags;

/* Generic DMA functions */
        int                    (*sc_setup_dma)(struct esc_softc *, void *,
                                    int, int);
        int                    (*sc_build_dma_chain)(struct esc_softc *,
                                    struct esc_dma_chain *, void *, int);
        int                    (*sc_need_bump)(struct esc_softc *, void *,
                                    int);

/* Generic Led data */
        int                      sc_led_status;
        void                   (*sc_led)(struct esc_softc *, int);

/* Nexus list */
        struct nexus             sc_nexus[8];
        struct nexus            *sc_cur_nexus;
        struct nexus            *sc_sel_nexus;

/* Current transfer data */
        u_char                  *sc_buf;        /* va */
        int                      sc_len;

        void                    *sc_dma_buf;    /* pa */
        int                      sc_dma_len;
        void                    *sc_dma_blk_ptr;
        int                      sc_dma_blk_len;
        short                    sc_dma_blk_flg;

        struct esc_dma_chain    *sc_chain;      /* Current DMA chain */
        short                    sc_max_link;
        short                    sc_cur_link;

/* Interrupt registers */
        u_char                   sc_status;
        u_char                   sc_interrupt;
        u_char                   sc_resel[2];

        u_char                   sc_units_disconnected;

/* Storage for FAS216 config registers (current values) */
        u_char                   sc_config1;
        u_char                   sc_config2;
        u_char                   sc_config3;
        u_char                   sc_config4;
        u_char                   sc_clock_conv_fact;
        u_char                   sc_timeout_val;
        u_char                   sc_clock_period;

        u_char                   sc_msg_in[7];
        u_char                   sc_msg_in_len;

        u_char                   sc_msg_out[7];
        u_char                   sc_msg_out_len;

        u_char                   sc_unit;
        u_char                   sc_lun;
        u_char                   sc_flags;
};

#define ESC_DMA_READ    0
#define ESC_DMA_WRITE   1
#define ESC_DMA_CLEAR   2

/* sc_flags */
#define ESC_ACTIVE       0x01
#define ESC_DONT_WAIT    0x02

/* SCSI Selection modes */
#define ESC_SELECT      0x00    /* Normal selection: No sync, no resel */
#define ESC_SELECT_R    0x01    /* Reselection allowed */
#define ESC_SELECT_S    0x02    /* Synchronous transfer allowed */
#define ESC_SELECT_I    0x04    /* Selection for escicmd */
#define ESC_SELECT_K    0x08    /* Send a BUS DEVICE RESET message (Kill) */

/* Nice abbreviations of the above */
#define ESC_SELECT_RS   (ESC_SELECT_R|ESC_SELECT_S)
#define ESC_SELECT_RI   (ESC_SELECT_R|ESC_SELECT_I)
#define ESC_SELECT_SI   (ESC_SELECT_S|ESC_SELECT_I)
#define ESC_SELECT_RSI  (ESC_SELECT_R|ESC_SELECT_S|ESC_SELECT_I)

/* sc_config_flags */
#define ESC_NO_SYNCH     0x01   /* Disable synchronous transfer */
#define ESC_NO_DMA       0x02   /* Do not use DMA! EVER! */
#define ESC_NO_RESELECT 0x04    /* Do not allow reselection */
#define ESC_SLOW_CABLE   0x08   /* Cable is "unsafe" for fast scsi-2 */
#define ESC_SLOW_START   0x10   /* There are slow starters on the bus */

void    escinitialize(struct esc_softc *sc);
void    esc_minphys(struct buf *bp);
void    esc_scsi_request(struct scsipi_channel *,
                                scsipi_adapter_req_t, void *);
void    escintr(struct esc_softc *dev);

#endif /* _ESCVAR_H_ */