root/sys/arch/acorn32/podulebus/sfasvar.h
/* $NetBSD: sfasvar.h,v 1.10 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 _SFASVAR_H_
#define _SFASVAR_H_

#ifndef _SFASREG_H_
#include <acorn32/podulebus/sfasreg.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 == SFAS_CHAIN_PRG or flg == SFAS_CHAIN_BUMP then
 * ptr is a VIRTUAL address. If flg == SFAS_CHAIN_DMA then ptr is a PHYSICAL
 * address.
 */
struct  sfas_dma_chain {
        void            *ptr;
        u_short         len;
        short           flg;
};
#define SFAS_CHAIN_DMA  0x00
#define SFAS_CHAIN_BUMP 0x01
#define SFAS_CHAIN_PRG  0x02


/*
 * This struct contains the necessary info for a pending request. Pointer to
 * a scsipi_xfer struct.
 */
struct  sfas_pending {
        TAILQ_ENTRY(sfas_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 sfas_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 SFAS_NS_IDLE            0       /* Nexus idle */
#define SFAS_NS_SELECTED        1       /* Last command was a SELECT command */
#define SFAS_NS_DATA_IN         2       /* Last command was a TRANSFER_INFO */
                                        /* command during a data in phase */
#define SFAS_NS_DATA_OUT        3       /* Last command was a TRANSFER_INFO */
                                        /* command during a data out phase */
#define SFAS_NS_STATUS          4       /* We have send a COMMAND_COMPLETE */
                                        /* command and are awaiting status */
#define SFAS_NS_MSG_IN          5       /* Last phase was MESSAGE IN */
#define SFAS_NS_MSG_OUT         6       /* Last phase was MESSAGE OUT */
#define SFAS_NS_SVC             7       /* We have sent the command */
#define SFAS_NS_DISCONNECTING   8       /* We have received a disconnect msg */
#define SFAS_NS_DISCONNECTED    9       /* We are disconnected */
#define SFAS_NS_RESELECTED      10      /* We was reselected */
#define SFAS_NS_DONE            11      /* Done. Prephsase to FINISHED */
#define SFAS_NS_FINISHED        12      /* Really done. Call scsi_done */
#define SFAS_NS_RESET           13      /* We are resetting this unit */

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

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

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

#define SFAS_NF_DO_SDTR         0x0020  /* We should send a SDTR */
#define SFAS_NF_SDTR_SENT       0x0040  /* We have sent a SDTR */
#define SFAS_NF_SYNC_TESTED     0x0080  /* We have negotiated sync */

#define SFAS_NF_RESET           0x0100  /* Reset this nexus */
#define SFAS_NF_IMMEDIATE       0x0200  /* We are operating from sfasicmd */

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

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

struct  sfas_softc {
        device_t                 sc_dev;        /* System required struct */
        struct  scsipi_channel   sc_channel;
        struct  scsipi_adapter   sc_adapter;
        void                     *sc_ih;
        struct evcnt             sc_intrcnt;

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

        sfas_regmap_p            sc_fas;        /* 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 sfasinitialize */
        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)(void *, void *, int, int);
        int                    (*sc_build_dma_chain)(void *, void *, void *,
                                                     int);
        int                    (*sc_need_bump)(void *, void *, int);

/* Optional replacement ixfer */
        void                   (*sc_ixfer)(void *, int);

/* Generic Led data */
        int                      sc_led_status;
        void                   (*sc_led)(void *, 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 sfas_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_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 SFAS_DMA_READ   0
#define SFAS_DMA_WRITE  1
#define SFAS_DMA_CLEAR  2

/* sc_flags */
#define SFAS_ACTIVE      0x01
#define SFAS_DONT_WAIT   0x02

/* SCSI Selection modes */
#define SFAS_SELECT     0x00    /* Normal selection: No sync, no resel */
#define SFAS_SELECT_R   0x01    /* Reselection allowed */
#define SFAS_SELECT_S   0x02    /* Synchronous transfer allowed */
#define SFAS_SELECT_I   0x04    /* Selection for sfasicmd */
#define SFAS_SELECT_K   0x08    /* Send a BUS DEVICE RESET message (Kill) */

/* Nice abbreviations of the above */
#define SFAS_SELECT_RS  (SFAS_SELECT_R|SFAS_SELECT_S)
#define SFAS_SELECT_RI  (SFAS_SELECT_R|SFAS_SELECT_I)
#define SFAS_SELECT_SI  (SFAS_SELECT_S|SFAS_SELECT_I)
#define SFAS_SELECT_RSI (SFAS_SELECT_R|SFAS_SELECT_S|SFAS_SELECT_I)

/* sc_config_flags */
#define SFAS_NO_SYNCH    0x01   /* Disable synchronous transfer */
#define SFAS_NO_DMA      0x02   /* Do not use DMA! EVER! */
#define SFAS_NO_RESELECT 0x04   /* Do not allow reselection */
#define SFAS_SLOW_CABLE  0x08   /* Cable is "unsafe" for fast scsi-2 */
#define SFAS_SLOW_START  0x10   /* There are slow starters on the bus */

void    sfasinitialize(struct sfas_softc *sc);
void    sfas_minphys(struct buf *bp);
void    sfas_scsi_request(struct scsipi_channel *,
                                scsipi_adapter_req_t, void *);
void    sfasintr(struct sfas_softc *dev);

#endif /* _SFASVAR_H_ */