root/usr/src/uts/sun/sys/scsi/adapters/fasreg.h
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright (c) 1996-1998 by Sun Microsystems, Inc.
 * All rights reserved.
 */

#ifndef _SYS_SCSI_ADAPTERS_FASREG_H
#define _SYS_SCSI_ADAPTERS_FASREG_H

#pragma ident   "%Z%%M% %I%     %E% SMI"

#include <sys/note.h>

#ifdef  __cplusplus
extern "C" {
#endif

/*
 * FAS register definitions.
 */

/*
 * All current Sun implementations use the following layout.
 * That is, the FAS registers are always byte-wide, but are
 * accessed longwords apart. Notice also that the byte-ordering
 * is big-endian.
 */

struct fasreg {
        uint8_t fas_xcnt_lo;            /* RW: transfer counter (low byte) */
                                        uint8_t _pad1, _pad2, _pad3;

        uint8_t fas_xcnt_mid;           /* RW: transfer counter (mid byte) */
                                        uint8_t _pad5, _pad6, _pad7;

        uint8_t fas_fifo_data;          /* RW: fifo data buffer */
                                        uint8_t _pad9, _pad10, _pad11;

        uint8_t fas_cmd;                /* RW: command register */
                                        uint8_t _pad13, _pad14, _pad15;

        uint8_t fas_stat;               /* R: status register */
#define fas_busid       fas_stat        /* W: bus id for sel/resel */
                                        uint8_t _pad17, _pad18, _pad19;


        uint8_t fas_intr;               /* R: interrupt status register */
#define fas_timeout     fas_intr        /* W: sel/resel timeout */
                                        uint8_t _pad21, _pad22, _pad23;


        uint8_t fas_step;               /* R: sequence step register */
#define fas_sync_period fas_step        /* W: synchronous period */
                                        uint8_t _pad25, _pad26, _pad27;


        uint8_t fas_fifo_flag;          /* R: fifo flag register */
#define fas_sync_offset fas_fifo_flag   /* W: synchronous offset */
                                        uint8_t _pad29, _pad30, _pad31;


        uint8_t fas_conf;               /* RW: configuration register */
                                        uint8_t _pad33, _pad34, _pad35;


        uint8_t fas_clock_conv;         /* W: clock conversion register */
                                        uint8_t _pad37, _pad38, _pad39;
#define fas_stat2       fas_clock_conv


        uint8_t fas_test;               /* RW: test register */
                                        uint8_t _pad41, _pad42, _pad43;
#define fas_conf4       fas_test


        uint8_t fas_conf2;              /* FAS-II configuration register */
                                        uint8_t _pad45, _pad46, _pad47;


        uint8_t fas_conf3;              /* FAS-III configuration register */
                                        uint8_t _pad49, _pad50, _pad51;
                                        uint8_t _pad_reserved[4];

        uint8_t fas_recmd_lo;           /* RW: fifo recmd counter lo */
#define fas_id_code fas_recmd_lo        /* R: part-unique id code */
                                        uint8_t _pad52, _pad53, _pad54;

        uint8_t fas_recmd_hi;           /* RW: fifo recmd counter lo */
                                        uint8_t _pad55, _pad56, _pad57;
};


/*
 * FAS command register definitions
 */

/*
 * These commands may be used at any time with the FAS chip.
 * None generate an interrupt, per se, although if you have
 * enabled detection of SCSI reset in setting the configuration
 * register, a CMD_RESET_SCSI will generate an interrupt.
 * Therefore, it is recommended that if you use the CMD_RESET_SCSI
 * command, you at least temporarily disable recognition of
 * SCSI reset in the configuration register.
 */
#define CMD_NOP         0x0
#define CMD_FLUSH       0x1
#define CMD_RESET_FAS   0x2
#define CMD_RESET_SCSI  0x3

/*
 * These commands will only work if the FAS is in the
 * 'disconnected' state:
 */
#define CMD_RESEL_SEQ   0x40
#define CMD_SEL_NOATN   0x41
#define CMD_SEL_ATN     0x42
#define CMD_SEL_STOP    0x43
#define CMD_EN_RESEL    0x44    /* (no interrupt generated) */
#define CMD_DIS_RESEL   0x45
#define CMD_SEL_ATN3    0x46

/*
 * These commands will only work if the FAS is connected as
 * an initiator to a target:
 */
#define CMD_TRAN_INFO   0x10
#define CMD_COMP_SEQ    0x11
#define CMD_MSG_ACPT    0x12
#define CMD_TRAN_PAD    0x18
#define CMD_SET_ATN     0x1a    /* (no interrupt generated) */
#define CMD_CLR_ATN     0x1b    /* (no interrupt generated) */

/*
 * These commands will only work if the FAS is connected as
 * a target to an initiator:
 */
#define CMD_DISCONNECT  0x27    /* (no interrupt generated) */

/*
 * DMA enable bit
 */
#define CMD_DMA         0x80

/*
 * FAS fifo register definitions (read only)
 */
#define FIFOSIZE                16
#define MAX_FIFO_FLAG           (FIFOSIZE-1)
#define FAS_FIFO_ONZ            0x20
#define FIFO_CNT_MASK           0x1f

/*
 * FAS status register definitions (read only)
 */
#define FAS_STAT_IPEND  0x80    /* interrupt pending */
#define FAS_STAT_GERR   0x40    /* gross error */
#define FAS_STAT_PERR   0x20    /* parity error */
#define FAS_STAT_XZERO  0x10    /* transfer counter zero */
#define FAS_STAT_XCMP   0x8     /* transfer completed (target mode only) */
#define FAS_STAT_MSG    0x4     /* scsi phase bit: MSG */
#define FAS_STAT_CD     0x2     /* scsi phase bit: CD */
#define FAS_STAT_IO     0x1     /* scsi phase bit: IO */

#define FAS_STAT_BITS   \
        "\20\10IPND\07GERR\06PERR\05XZERO\04XCMP\03MSG\02CD\01IO"

/*
 * settings of status to reflect different information transfer phases
 */
#define FAS_PHASE_MASK          (FAS_STAT_MSG | FAS_STAT_CD | FAS_STAT_IO)
#define FAS_PHASE_DATA_OUT      0
#define FAS_PHASE_DATA_IN       (FAS_STAT_IO)
#define FAS_PHASE_COMMAND       (FAS_STAT_CD)
#define FAS_PHASE_STATUS        (FAS_STAT_CD | FAS_STAT_IO)
#define FAS_PHASE_MSG_OUT       (FAS_STAT_MSG | FAS_STAT_CD)
#define FAS_PHASE_MSG_IN        (FAS_STAT_MSG | FAS_STAT_CD | FAS_STAT_IO)

/*
 * FAS interrupt status register definitions (read only)
 */

#define FAS_INT_RESET   0x80    /* SCSI reset detected */
#define FAS_INT_ILLEGAL 0x40    /* illegal cmd */
#define FAS_INT_DISCON  0x20    /* disconnect */
#define FAS_INT_BUS     0x10    /* bus service */
#define FAS_INT_FCMP    0x8     /* function completed */
#define FAS_INT_RESEL   0x4     /* reselected */
#define FAS_INT_SELATN  0x2     /* selected with ATN */
#define FAS_INT_SEL     0x1     /* selected without ATN */

#define FAS_INT_BITS    \
        "\20\10RST\07ILL\06DISC\05BUS\04FCMP\03RESEL\02SATN\01SEL"

/*
 * FAS step register- only the least significant 3 bits are valid
 */
#define FAS_STEP_MASK   0x7

#define FAS_STEP_ARBSEL 0       /* Arbitration and select completed. */
                                /* Not MESSAGE OUT phase. ATN* asserted. */

#define FAS_STEP_SENTID 1       /* Sent one message byte. ATN* asserted. */
                                /* (SELECT AND STOP command only). */

#define FAS_STEP_NOTCMD 2       /* For SELECT WITH ATN command: */
                                /*      Sent one message byte. ATN* off. */
                                /*      Not COMMAND phase. */
                                /* For SELECT WITHOUT ATN command: */
                                /*      Not COMMAND phase. */
                                /* For SELECT WITH ATN3 command: */
                                /*      Sent one to three message bytes. */
                                /*      Stopped due to unexpected phase */
                                /*      change. If third message byte */
                                /*      not sent, ATN* asserted.  */

#define FAS_STEP_PCMD   3       /* Not all of command bytes transferred */
                                /* due to premature phase change. */

#define FAS_STEP_DONE   4       /* Complete sequence. */

/*
 * FAS configuration register definitions (read/write)
 */
#define FAS_CONF_SLOWMODE       0x80    /* slow cable mode */
#define FAS_CONF_DISRINT        0x40    /* disable reset int */
#define FAS_CONF_PARTEST        0x20    /* parity test mode */
#define FAS_CONF_PAREN          0x10    /* enable parity */
#define FAS_CONF_CHIPTEST       0x8     /* chip test mode */
#define FAS_CONF_BUSID          0x7     /* last 3 bits to be host id */

#define DEFAULT_HOSTID          7

/*
 * FAS test register definitions (read/write)
 */
#define FAS_TEST_TGT            0x1     /* target test mode */
#define FAS_TEST_INI            0x2     /* initiator test mode */
#define FAS_TEST_TRI            0x4     /* tristate test mode */

/*
 * FAS configuration register #2 definitions (read/write)
 */
#define FAS_CONF2_XL32          0x80
#define FAS_CONF2_MKDONE        0x40
#define FAS_CONF2_PAUSE_INTR_DISABLE 0x20
#define FAS_CONF2_FENABLE       0x10    /* Features Enable */
#define FAS_CONF2_SCSI2         0x8     /* SCSI-2 mode (target mode only) */
#define FAS_CONF2_TGT_BAD_PRTY_ABORT 0x4
#define FAS_CONF2_DMA_PRTY_ENABLE    0x1

/*
 * FAS configuration #3 register definitions (read/write)
 */
#define FAS_CONF3_ODDBYTE_AUTO  0x80    /* auto push an odd-byte to dma */
#define FAS_CONF3_WIDE          0x40    /* enables wide */
#define FAS_CONF3_IDBIT3        0x20    /* extends scsi bus ID to 4 bits */
#define FAS_CONF3_IDRESCHK      0x10    /* ID message checking */
#define FAS_CONF3_QUENB         0x8     /* 3-byte msg support */
#define FAS_CONF3_CDB10         0x4     /* group 2 scsi-2 support */
#define FAS_CONF3_FASTSCSI      0x2     /* 10 MB/S fast scsi mode */
#define FAS_CONF3_FASTCLK       0x1     /* fast clock mode */

/*
 * FAS configuration #4 register definitions
 */
#define FAS_CONF4_PADMSGS       0x20

/*
 * FAS part-unique id code definitions (read only)
 */
#define FAS_REV_MASK            0x7     /* revision level mask */
#define FAS_FCODE_MASK          0xf8    /* revision family code mask */

/*
 * Macros to get/set an integer word into the 4 8-bit
 * registers that constitute the FAS's counter register.
 */
#define SET_FAS_COUNT(fasreg, val) {    \
        fas_reg_write(fas, &fasreg->fas_xcnt_lo, (uint8_t)val); \
        fas_reg_write(fas, &fasreg->fas_xcnt_mid, \
                (uint8_t)(val >>        8)); \
        fas_reg_write(fas, &fasreg->fas_recmd_lo, \
                ((uint8_t)(val >> 16)));        \
        fas_reg_write(fas, &fasreg->fas_recmd_hi, 0); \
}

/*
 * to save time, read back 3 registers
 */
#define GET_FAS_COUNT(fasreg, val) {    \
        uint8_t lo, mid, r_lo; \
        lo = fas_reg_read(fas, &fasreg->fas_xcnt_lo); \
        mid = fas_reg_read(fas, &fasreg->fas_xcnt_mid); \
        r_lo = fas_reg_read(fas, &fasreg->fas_recmd_lo); \
        (val) = (uint32_t)(lo | (mid << 8) | ((r_lo) << 16)); \
}



/*
 * FAS Clock constants
 */

/*
 * The probe routine will select amongst these values
 * and stuff it into the tag f_clock_conv in the private host
 * adapter structure (see below) (as well as the the register fas_clock_conv
 * on the chip)
 */
#define CLOCK_10MHZ             2
#define CLOCK_15MHZ             3
#define CLOCK_20MHZ             4
#define CLOCK_25MHZ             5
#define CLOCK_30MHZ             6
#define CLOCK_35MHZ             7
#define CLOCK_40MHZ             8       /* really 0 */
#define CLOCK_MASK              0x7

/*
 * This yields nanoseconds per input clock tick
 */

#define CLOCK_PERIOD(mhz)       (1000 * MEG) / (mhz / 1000)
#define CONVERT_PERIOD(time)    ((time) + 3) >> 2

/*
 * Formula to compute the select/reselect timeout register value:
 *
 *      Time_unit = 7682 * CCF * Input_Clock_Period
 *
 * where Time_unit && Input_Clock_Period should be in the same units.
 * CCF = Clock Conversion Factor from CLOCK_XMHZ above.
 * Desired_Timeout_Period = 250 ms.
 *
 */
#define FAS_CLOCK_DELAY 7682
#define FAS_CLOCK_TICK(fas)     \
        ((uint_t)FAS_CLOCK_DELAY * (uint_t)(fas)->f_clock_conv * \
        (uint_t)(fas)->f_clock_cycle) / (uint_t)1000
#define FAS_SEL_TIMEOUT (250 * MEG)
#define FAS_CLOCK_TIMEOUT(tick, selection_timeout) \
        (((selection_timeout) * MEG) + (tick) - 1) / (tick)

/*
 * Max/Min number of clock cycles for synchronous period
 */
#define MIN_SYNC_FAST(fas)      4
#define MIN_SYNC_SLOW(fas)      \
        (((fas)->e_fasconf & FAS_CONF_SLOWMODE) ? 6 : 5)
#define MIN_SYNC(fas)           (MIN_SYNC_FAST((fas)))
#define MAX_SYNC(fas)           35
#define SYNC_PERIOD_MASK        0x1F

/*
 * Max/Min time (in nanoseconds) between successive Req/Ack
 */
#define MIN_SYNC_TIME(fas)      \
        ((uint_t)MIN_SYNC((fas)) * (uint_t)((fas)->f_clock_cycle)) / \
            (uint_t)1000
#define MAX_SYNC_TIME(fas)      \
        ((uint_t)MAX_SYNC((fas)) * (uint_t)((fas)->f_clock_cycle)) / \
            (uint_t)1000

/*
 * Max/Min Period values (appropriate for SYNCHRONOUS message).
 * We round up here to make sure that we are always slower
 * (longer time period).
 */
#define MIN_SYNC_PERIOD(fas)    (CONVERT_PERIOD(MIN_SYNC_TIME((fas))))
#define MAX_SYNC_PERIOD(fas)    (CONVERT_PERIOD(MAX_SYNC_TIME((fas))))

/*
 * According to the Emulex application notes for this part,
 * the ability to receive synchronous data is independent
 * of the FAS chip's input clock rate, and is fixed at
 * a maximum 5.6 mb/s (180 ns/byte).
 *
 * Therefore, we could tell targets that we can *receive*
 * synchronous data this fast.
 * However, the rest of the transfer is still at 5.0 MB/sec so to keep it
 * simple, we negotiate 200 ns
 * On a c2,  a period of 45 and 50 result in the same register value (8) and
 * consequently 5 MB/sec.
 */
#define DEFAULT_SYNC_PERIOD             200             /* 5.0 MB/s */
#define DEFAULT_FASTSYNC_PERIOD         100             /* 10.0 MB/s */
#define FASTSCSI_THRESHOLD              50              /* 5.0 MB/s */

/*
 * Short hand macro convert parameter in
 * nanoseconds/byte into k-bytes/second.
 */
#define FAS_SYNC_KBPS(ns)       ((((1000 * MEG) / (ns)) + 999) / 1000)

/*
 * Default Synchronous offset.
 * (max # of allowable outstanding REQ)
 * IBS allows only 11 bytes offset
 */
#define DEFAULT_OFFSET  15

/*
 * Chip type defines && macros
 */
#define FAS366          0
#define FAST            5

/* status register #2 definitions (read only) */
#define FAS_STAT2_SEQCNT   0x01    /* Sequence counter bit 7-3 enabled */
#define FAS_STAT2_FLATCHED 0x02    /* FIFO flags register latched */
#define FAS_STAT2_CLATCHED 0x04    /* Xfer cntr & recommand ctr latched */
#define FAS_STAT2_CACTIVE  0x08    /* Command register is active */
#define FAS_STAT2_SCSI16   0x10    /* SCSI interface is wide */
#define FAS_STAT2_ISHUTTLE 0x20    /* FIFO Top register contains 1 byte */
#define FAS_STAT2_OSHUTTLE 0x40    /* next byte from FIFO is MSB */
#define FAS_STAT2_EMPTY    0x80    /* FIFO is empty */

/*
 * select/reselect bus id register
 */
#define FAS_BUSID_ENCODID       0x10    /* encode reselection ID */
#define FAS_BUSID_32BIT_COUNTER 0x40    /* xfer counter is 32 bit */

#ifdef  __cplusplus
}
#endif

#endif  /* _SYS_SCSI_ADAPTERS_FASREG_H */