root/usr/src/uts/sun4u/sunfire/io/jtag.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (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 1999 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#include <sys/types.h>
#include <sys/param.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/ddi_impldefs.h>
#include <sys/obpdefs.h>
#include <sys/cmn_err.h>
#include <sys/errno.h>
#include <sys/debug.h>
#include <sys/fhc.h>
#include <sys/jtag.h>
#include <sys/ac.h>
#include <sys/machsystm.h>
#include <sys/cpu.h>
#include <sys/cpuvar.h>

/*
 * Defines for data structures used only in this module. They will
 * not be exported to external modules.
 */

/*
 * Define the hardware structure of JTAG
 */

#define JTAG_CSR_BASE ((jtag_csr *)0xF0300000)


#define JTAG_CR 0x08000f0
#define JTAG_CMD 0x0800100

/* JTAG status flags */
#define JTAG_BUSY_BIT 0x100

/* JTAG commands */
#define JTAG_SEL_RING   0x6000
#define JTAG_SEL_DR     0x5050
#define JTAG_SEL_IR     0x5068
#define JTAG_SHIFT      0x00A0
#define JTAG_RUNIDLE    0x50C0
#define JTAG_IR_TO_DR   0x50E8
#define JTAG_DR_TO_IR   0x50F4
#define JTAG_TAP_RESET  0x50FF


/*
 * Definitions of data types.
 *
 */

/*
 * Most routines in this interface return a negative value when
 * an error occurs. In the normal case, the routines return a non-negative
 * value, which may be of interest to the caller. The following enumeration
 * provides the meaning of each error return code.
 */

/*
 * When calling verify_jtag_chip, you must pass PRINT_ERR if you
 * want the cmn_err call to occur. This is because sometimes
 * when we verify rings, (checking for NPB's) we do not want to
 * print error messages.
 */
#define PRINT_JTAG_ERR  5

/*
 * You must pass in the proper chip masks when calling
 * config board()
 */
#define AC_INIT         1
#define DCU1500_INIT    2
#define DCU1600_INIT    2
#define DCU1700_INIT    2
#define DCU1800_INIT    2
#define DCU1900_INIT    2
#define DCU2000_INIT    2
#define DCU2100_INIT    2
#define DCU2200_INIT    2
#define FHC_INIT        4

#define SYSIO_INIT      8

/* scan ring numbers */
#define RING0           0
#define RING1           1
#define RING2           2

/*
 * Scan ring 0 lengths. Boards are typed by their scan ring length. This
 * is inherently flawed if a new board type has the same number of
 * components as one of the original boards.
 *
 * The inherently flawed scenario now exists with the introduction
 * of the soc+ versions of the 2-SBus and UPA/SBus boards. Argh...
 */
#define CPU_TYPE_LEN    12              /* CPU board ring length */
#define IO_TYPE1_LEN    15              /* 2 sysio 1 HM */
#define IO_TYPE2_LEN    14              /* 1 sysio 1 ffb */
#define PCI_TYPE_LEN    16              /* PCI board ring length */
#define PCI_TYPEA_LEN   110             /* PCI ISP off ring */
#define PCI_TYPEB_LEN   104             /* PCI ISP in ring */
#define DSK_TYPE_LEN    2               /* Disk board ring length */
#define IO_TYPE4_LEN    126             /* 2 sysio soc+ */
#define IO_TYPE5_LEN    110             /* 1 sysio 1 ffb soc+ */

#define CPU_0_5_LEN     8               /* 0.5 Meg Module ring length */
#define CPU_1_0_LEN     12              /* 1 Meg and 2 Meg ring length */
#define FFB_SNG_LEN     6               /* Single bufferef FFB */
#define FFB_DBL_LEN     18              /* Double buffered FFB */

/*
 * Component IDs of various SRAM chips. The only way to distinguish between
 * 1M, 2M, and 4M Ecache is via the component IDs of the SRAMs.
 */
#define SRAM_256K       0x00000000
#define SRAM_128K       0x000090E3
#define SRAM_64K_1      0x000000E3
#define SRAM_64K_2      0x01901149

typedef enum {
        JTAG_OK = 0,            /* no error */
        JTAG_FAIL = -1,         /* generic JTAG failure */
        TAP_TIMEOUT = -1,       /* JTAG TAP state machine not responding */
        BAD_ARGS = -2,          /* incorrect arguments passed by caller */
        BAD_CID = -3,           /* JTAG component ID does not match */
        RING_BROKEN = -4,       /* JTAG ring continuity test failed */
        INIT_MISMATCH = -5,     /* State after initialization not expected */
        LENGTH_MISMATCH = -6    /* Ring length does not match expected */
} jtag_error;

typedef u_short jtag_instruction;
typedef u_char jtag_ring;       /* format is bbbb rrrr in binary */

/* Internal macros */
static int tap_issue_cmd(volatile u_int *, u_int);

/* TAP register access macros */

/* NOTE the only status is the busy bit (8) */

/* read the jtag data bits */
#define jtag_data(reg, nbits) (*(reg) >> (32 - (nbits)))

#define JTAG_TIMEOUT 0x10000

#define TAP_DECLARE int timeout;

#define TAP_WAIT(reg)  timeout = JTAG_TIMEOUT;          \
        while ((*(reg) & JTAG_BUSY_BIT) != 0)           \
                if ((--timeout) < 0)                    \
                        return (TAP_TIMEOUT)

#define TAP_SHIFT(reg, data, nbits)                             \
        *(reg) = ((data<<16) | ((nbits-1)<<12) | JTAG_SHIFT);   \
        TAP_WAIT(reg)

/* Error-checking macros to simplify the coding */

#define TAP_ISSUE_CMD(reg, cmd, status)         \
        status = tap_issue_cmd(reg, cmd);       \
        if (status < 0)                         \
                return (status)

#define TAP_SHIFT_CONSTANT(reg, val, nbits, status)     \
        status = tap_shift_constant(reg, val, nbits);   \
        if (status < 0)                                 \
                return (status)

#define TAP_SHIFT_SINGLE(reg, val, nbits, status)       \
        status = tap_shift_single(reg, val, nbits);     \
        if (status < 0)                                 \
                return (status)

#define TAP_SHIFT_MULTIPLE(reg, in, nbits, out, status)         \
        status = tap_shift_multiple(reg, in, nbits, out);       \
        if (status < 0)                                         \
                return (status)

/*
 * A jtag_log_comp describes a component as seen by JTAG.
 *
 * Since there are multiple versions & revision for a single
 * component, this can be a bit complicated...
 *
 * The implementation assumes that all components which can be used
 * interchangeably have the exact same programming model regarding
 * JTAG programming. Then, interchangeable components differ only by
 * their component IDs. The field id points to a NULL-terminated list
 * of component IDs. Allowable component IDs may differ only in the rev
 * number, which must be higher than or equal to the one in the list.
 *
 * The init_pdesc field points to a byte string which describes how to
 * initialize the component. The structure of this byte string is not
 * exported (see the implementation of jtag_init_chip).
 *
 * The fmt_desc field points to a byte string which describes how to
 * convert the scan-out format to the more usual DCSR format. The
 * structure of this string is not exported (see the implementation
 * of jtag_scanout_chip).
 */

typedef struct {
        u_int *id;              /* Pointer to component IDs, 0 if no CID */
        u_char ir_len;          /* number of bits in instruction register */
        u_char dr_len;          /* number of bits in DR for init/dump */
        jtag_instruction id_code;       /* instruction to read component ID */
        jtag_instruction init_code;     /* instruction to write parameters */
        jtag_instruction dump_code;     /* instruction to read parameters */
        u_char *init_pdesc;             /* initialization patch descriptors */
        u_char *fmt_desc;               /* reformat descriptor */
} jtag_log_comp;


/* A jtag_phys_comp describes a component position inside a ring */

typedef struct {
        jtag_log_comp *chip;    /* pointer to chip descriptor */
        short ir_after;         /* number of IR bits after chip in ring */
        short ir_before;        /* number of IR bits before chip in ring */
        short by_after;         /* number of bypass bits after chip in ring */
        short by_before;        /* number of bypass bits before chip in ring */
} jtag_phys_comp;


/* Board ring description */

typedef struct {
        int size;
        jtag_phys_comp *components;
} jtag_ring_desc;

/*
 *      Initialization options
 *
 * These data types describe the options for each type of component
 * internally to the jtag_init_*_ring routines. They can all be
 * recast into arrays of unsigned integers.
 *
 * Note that these types DEPEND on the *_init_pdesc structures, which
 * use indices to the components of the *_options types. As a result,
 * the data structure & the type must be modified simultaneously,
 * although this dependency is not immediately visible. This is ugly,
 * but it makes the initialization routines much more readable.
 */

typedef struct {
        u_int frozen;
        u_int reset_a;
        u_int reset_b;
        u_int board_id;
        u_int mask_hwerr;
        u_int arb_fast;
        u_int node_id;
        u_int pcr_hi;
        u_int pcr_lo;
        u_int pcc_ctl1;
        u_int pcc_ctl0;
        u_int pcc_tctrl;
} ac_options;

struct ac_regs {
        unsigned int bcsr;
        unsigned int brscr;
        unsigned int esr_hi;
        unsigned int esr_lo;
        unsigned int emr_hi;
        unsigned int emr_lo;
        unsigned int ccr;
        unsigned int cntr_hi;
        unsigned int cntr_lo;
};

typedef struct {
        u_int frozen;
        u_int mask_pe;
        u_int mask_oe;
} dc_options;

typedef struct {
        u_int csr_hi;           /* CSR 20:18 */
        u_int csr_mid;          /* CSR 16:8 */
        u_int csr_midlo;        /* CSR 6:4 */
} fhc_options;


struct fhc_regs {
        u_int por;
        u_int csr;
        u_int rcsr;
        u_int bsr;
};

/* Structure to capture the scan data from the bct8244's. */
struct bct_fields {
        u_int disk1_pres;
        u_int disk0_pres;
        u_int disk1_id;
        u_int disk0_id;
};

/* Collective type for *_options * */
typedef u_int *jtag_opt;

/*
 * The following definitions are the action flags used in the byte
 * string which is used to describe component initialization. The
 * only piece of code which understands those flags is jtag_init_chip.
 *
 * Initializing a component consists of scanning successive values
 * into the component. The data for each pass is obtained by applying
 * successive patches to a reference pattern. The patch descriptors
 * are a byte string which form a succession of operations. The first
 * byte of an operation is a set of flags defining the action:
 */
#define JTIN_INDEX      0x0F
#define JTIN_INSERT     0x10
#define JTIN_UPDATE     0x20
#define JTIN_COMPARE    0x40
#define JTIN_END        0x80

/*
 * When JTIN_INSERT is specified, the flag byte is followed by
 * two bytes indicating the lsb and msb of the field to be updated, and
 * the JTIN_INDEX part of the flags indicate which value should be
 * inserted: if JTIN_INDEX is zero, the value to insert is the next
 * byte in the aray, extended to a 32-bit word; if JTIN_INDEX is
 * non-zero, the value to insert is at word offset index in the patch
 * array passed to jtag_init_chip.
 */

/*
 * The fmt_desc field points to a reformat table which converts the
 * scan-out format to the standard DSCR-style format. The format descriptor
 * is a byte string, with special bytes indicating functional operations
 * as indicated by bit fields in the following table:
 */
#define JTSO_END        0x80    /* end of table */
#define JTSO_XTRACT     0x40    /* extract & merge [lsb, msb] */
#define JTSO_ST         0x20    /* store & increment */
#define JTSO_SHIFT      0x1F    /* shift count for extract & merge */

/*
 * Function Declarations
 */
static void jtag_error_print(int, jtag_error);
static int jtag_get_comp_id(volatile u_int *, jtag_phys_comp *);

/*
 *      Bit-field manipulations
 */
static u_int jtag_bf_extract(u_char *s, int lsb, int msb);
static void jtag_bf_insert(u_char *s, int lsb, int msb, int value);
static void jtag_bf_zero(u_char *s, int nbits);
static int jtag_bf_cmp(u_char *s1, u_char *s2, int nbits);

/*
 *      Test-access port interface
 */
static int tap_wait(volatile u_int *);
static int tap_shift_single(volatile u_int *, int, int);
static int tap_shift_multiple(volatile u_int *, u_char *, int, u_char *);

/*
 *    Ring-level interface
 */

static int select_ring(volatile u_int *, jtag_ring, int);
static int jtag_rescan_IR_DR(volatile u_int *, jtag_phys_comp *,
        jtag_instruction, u_char *, int, u_char *);
static int jtag_single_IR_DR(volatile u_int *, jtag_phys_comp *,
        jtag_instruction, u_char *, int, u_char *);
static int jtag_ring_length(volatile u_int *, jtag_ring);
static int jtag_ring_ir_length(volatile u_int *, jtag_ring);

/*
 *    Component-level interface
 */

static int jtag_scanout_chip(volatile u_int *, jtag_ring, jtag_phys_comp *,
        u_int *);
static int jtag_init_chip(volatile u_int *, jtag_ring, jtag_phys_comp *,
        const u_int *, u_char *);
static jtag_phys_comp *find_chip(jtag_ring_desc *, jtag_log_comp *, int);
static void format_chip_data(u_char *, u_int *, u_char *);
static int jtag_init_ac(volatile u_int *, int, enum board_type);

/*
 * Data tables.
 *
 * The JTAG implementation is data table driven. These tables describe
 * the chip, ring, and board components.
 */

/*
 *    Data structures describing the scannable components
 */

static char jtag_err[] = "JTAG ERROR";

/* Constants defining the IR lengths for each of the chips */

#define IR_LEN 8        /* all sunfire asics, spitfire, and sdb  are 8 bits */
#define HM_LEN 4        /* happy meal is 4 bits */
#define NDP_LEN 2       /* ndp83840 is 2 bits */
#define SOC_LEN 4       /* SOC is 4 bits */
#define SOCPLUS_LEN 8   /* SOC+ is 8 bits */
#define SIO_LEN 16      /* sysio asic is 16 bits */
#define PSYO_LEN 4      /* psycho asic is 4 bits */
#define CHEO_LEN 4      /* cheerio asic is 4 bits */
#define EC_LEN 3        /* ecache tag rams is 3 bits each */

#define FFB_LEN 16      /* ffb module is 16 bits */
#define THREED_LEN      4       /* IR length for three D rams */
#define BT498_LEN 4     /* IR length for bt 498 chip (ramdac) */



/* Standard instructions */
#define IDCODE          0xFFFE
#define INITCODE        0xbe
#define DUMPCODE        0xbe

#define CID_TO_REV(cid) ((cid) >> 28)

/* ASIC Jag IDs */
static u_int cid_sf[] = {
        0x0002502f,
        0
};

static u_int cid_sdb[] = {
        0x0002602f,
        0
};

static u_int cid_fbc[] = {
        0x1241906d,
        0
};

static u_int cid_lvt[] = {
        0x0001d02f,
        0
};

static u_int cid_3dram[] = {
        0X0E9A103B,
        0
};

static u_int cid_bt498[] = {
        0x0001d02f,
        0
};

static u_int cid_sio[] = {
        0x0ef0703b,
        0
};

static u_int cid_hm[] = {
        0x01792045,
        0
};

static u_int cid_ac[] = {
        0x10f9e07d,
        0
};

static u_int cid_dc[] = {
        0x10f9f07d,
        0
};

static u_int cid_fhc[] = {
        0x10fa007d,
        0
};

static u_int cid_psyo[] = {
        0x3195401d,
        0
};

static u_int cid_cheo[] = {
        0x11791022,
        0
};


/*
 * NOTE the following chips are ignored for the most part by the POST JTAG
 * If if is later determined that scan data may be of interest then we need
 * to fill in the blanks below.
 */

static u_char ec_init_pdesc[] = {
        JTIN_END|JTIN_INSERT|0, 0, 0, 0x0
};

static u_char ec_fmt[] = {
        JTSO_ST|JTSO_XTRACT|JTSO_END| 0, 0, 4
};

static u_char sio_init_pdesc[] = {
        JTIN_END|JTIN_INSERT|0, 0, 0, 0x0
};

static u_char sio_fmt[] = {
        JTSO_ST|JTSO_XTRACT|JTSO_END| 0, 0, 4
};

static u_char psyo_init_pdesc[] = {
        JTIN_END|JTIN_INSERT|0, 0, 0, 0x0
};

static u_char psyo_fmt[] = {
        JTSO_ST|JTSO_XTRACT|JTSO_END| 0, 0, 4
};

static u_char hm_init_pdesc[] = {
        JTIN_END|JTIN_INSERT|0, 0, 0, 0x0
};

static u_char hm_fmt[] = {
        JTSO_ST|JTSO_XTRACT|JTSO_END| 0, 0, 4
};

static u_char ndp_init_pdesc[] = {
        JTIN_END|JTIN_INSERT|0, 0, 0, 0x0
};

static u_char ndp_fmt[] = {
        JTSO_ST|JTSO_XTRACT|JTSO_END| 0, 0, 4
};

static u_char cheo_init_pdesc[] = {
        JTIN_END|JTIN_INSERT|0, 0, 0, 0x0
};

static u_char cheo_fmt[] = {
        JTSO_ST|JTSO_XTRACT|JTSO_END| 0, 0, 4
};


/* The main ASCIS of interest are the AC, DC and FHC */

/*
 * The initialization of DC is as follows:
 *
 * Do NOT change the following data structure without checking
 * _options in jtag_private.h, which depends on it.
 */
static u_char dc_init_pdesc[] = {
        JTIN_INSERT|1,   0,   0,        /* NFZN */
        JTIN_INSERT|2,   4,   4,        /* Mask PE */
        JTIN_INSERT|3,   3,   3,        /* Mask OE */
        JTIN_INSERT|0,   1,   2,  3,    /* W1C Errors */
        JTIN_END|JTIN_UPDATE,
};

static u_char dc_fmt[] = {
        JTSO_ST|JTSO_XTRACT|JTSO_END| 0, 0, 4    /* DC[4:0] */
};

/*
 * The initialization of AC is as follows:
 *
 * Do NOT change the following data structure without checking
 * _options in jtag_private.h, which depends on it.
 */
static u_char ac_init_pdesc[] = {
        JTIN_INSERT|0, 161, 161, 1,     /* BOARD ADDR 40 */
        JTIN_INSERT|7, 159, 160,        /* BOARD ADDR 39:38, wfi node */
        JTIN_INSERT|4, 155, 158,        /* BOARD ADDR 37:34 */
        JTIN_INSERT|4, 151, 154,        /* BOARD ID */
        JTIN_INSERT|6, 146, 146,        /* ARB_FAST */
        JTIN_INSERT|1, 134, 134,        /* NFZN */
        JTIN_INSERT|0, 133, 133, 0,     /* ENWAKPOR  */
        JTIN_INSERT|2, 135, 135,        /* Reset B */
        JTIN_INSERT|3, 136, 136,        /* Reset A */
        JTIN_INSERT|0, 99, 106, 0xff,   /* W1C Errors */
        JTIN_INSERT|0, 107, 114, 0xff,  /* W1C Errors */
        JTIN_INSERT|0, 115, 122, 0xff,  /* W1C Errors */
        JTIN_INSERT|0, 123, 130, 0xff,  /* W1C Errors */
        JTIN_INSERT|0, 131, 132, 0xff,  /* W1C Errors */
        JTIN_INSERT|5, 88, 98,          /* Error Masks */
        JTIN_INSERT|12, 76, 87,         /* CNT1_CTL_<27:16> */
        JTIN_INSERT|10, 70, 75,         /* CNT1_CTL <13:8> */
        JTIN_INSERT|11, 64, 69,         /* CNT0_CTL <5:0> */
        JTIN_INSERT|8, 32, 63,          /* CNT1 */
        JTIN_INSERT|9, 0, 31,           /* CNT0 */
        JTIN_END|JTIN_UPDATE,           /* Clears counters */
};

static u_char ac_fmt[] = {
        JTSO_XTRACT|17,                 148,    162,    /* BCSR[31:17] */
        JTSO_XTRACT|15,                 147,    147,    /* BSCR[15] */
        JTSO_XTRACT|5,                  138,    146,    /* BSCR[13:5] */
        JTSO_ST|JTSO_XTRACT|0,          134,    137,    /* BSCR[3:0] */
        JTSO_ST|JTSO_XTRACT|22,         133,    133,    /* BRSCR[22] */
        JTSO_XTRACT|16,                 131,    132,    /* ESR[49:48] */
        JTSO_XTRACT|8,                  124,    130,    /* ESR[46:40] */
        JTSO_XTRACT|4,                  122,    123,    /* ESR[37:36] */
        JTSO_ST|JTSO_XTRACT|0,          120,    121,    /* ESR[33:32] */
        JTSO_XTRACT|28,                 116,    119,    /* ESR[31:28] */
        JTSO_XTRACT|24,                 115,    115,    /* ESR[24] */
        JTSO_XTRACT|20,                 112,    114,    /* ESR[22:20] */
        JTSO_XTRACT|12,                 107,    111,    /* ESR[16:12] */
        JTSO_XTRACT|4,                  101,    106,    /* ESR[9:4] */
        JTSO_ST|JTSO_XTRACT|0,          99,     100,    /* ESR[1:0] */
        JTSO_XTRACT|16,                 97,     98,     /* EMR[49:48] */
        JTSO_XTRACT|8,                  96,     96,     /* EMR[40] */
        JTSO_ST|JTSO_XTRACT|4,          94,     95,     /* EMR[37:36] */
        JTSO_XTRACT|28,                 93,     93,     /* EMR[28] */
        JTSO_XTRACT|24,                 92,     92,     /* EMR[24] */
        JTSO_XTRACT|20,                 91,     91,     /* EMR[20] */
        JTSO_XTRACT|12,                 90,     90,     /* EMR[12] */
        JTSO_XTRACT|8,                  89,     89,     /* EMR[8] */
        JTSO_ST|JTSO_XTRACT|4,          88,     88,     /* EMR[4] */
        JTSO_XTRACT|16,                 76,     87,     /* CCR[27:16] */
        JTSO_XTRACT|8,                  70,     75,     /* CCR[13:8] */
        JTSO_ST|JTSO_XTRACT|0,          64,     69,     /* CCR[5:0] */
        JTSO_ST|JTSO_XTRACT|0,          32,     63,     /* CNT[63:32] */
        JTSO_ST|JTSO_XTRACT|JTSO_END|0, 0,      31      /* CNT[31:0] */
};

/*
 */

/*
 * The following structure has three variable elements, as noted
 * by the 1,2 and 3 digits or'ed in with the JTIN_INSERT flags.
 * The number nad position of these elements must correspond with
 * the fhc_ structure apssed into fhc_chip_init.
 */
static u_char fhc_init_pdesc[] = {
        JTIN_INSERT|0,  41,     41,     0,              /* POR */
        JTIN_INSERT|1,  38,     40,                     /* CSR[20:18] */
        JTIN_INSERT|2,  29,     37,                     /* CSR[16:8] */
        JTIN_INSERT|3,  26,     28,                     /* CSR[6:4] */
        JTIN_INSERT|0,  24,     25,     0x0,            /* CSR[1:0] */
        JTIN_INSERT|0,  16,     23,     0x0,            /* RCSR[31:24] */
        JTIN_INSERT|0,  2,      15,     0x0,            /* BSR[18:5] */
        JTIN_INSERT|0,  0,      1,      0x0,            /* BSR[1:0] */
        JTIN_END|JTIN_UPDATE,
};

static u_char fhc_fmt[] = {
        JTSO_ST|JTSO_XTRACT|0,          41,     41,     /* POR State */
        JTSO_XTRACT|18,                 38,     40,     /* CSR[20:18] */
        JTSO_XTRACT|8,                  29,     37,     /* CSR[16:8] */
        JTSO_XTRACT|4,                  26,     28,     /* CSR[6:4] */
        JTSO_ST|JTSO_XTRACT|0,          24,     25,     /* CSR[1:0] */
        JTSO_ST|JTSO_XTRACT|24,         16,     23,     /* RCSR[31:24] */
        JTSO_XTRACT|5,                  2,      15,     /* BSR[18:5] */
        JTSO_ST|JTSO_XTRACT|JTSO_END|0, 0,      1,      /* BSR[1:0] */
};


static u_char bct8244_fmt[] = {
        JTSO_ST|JTSO_XTRACT|0,          17,     17,     /* Disk 1 present */
        JTSO_ST|JTSO_XTRACT|0,          16,     16,     /* Disk 0 present */
        JTSO_ST|JTSO_XTRACT|0,          12,     15,     /* Disk 1 Target */
        JTSO_ST|JTSO_XTRACT|JTSO_END|0, 8,      11,     /* Disk 0 Target */
};

/* A jtag_log_comp describes a component as seen by JTAG. */

static jtag_log_comp chip_ac = {
        cid_ac,
        IR_LEN, 163,
        IDCODE, INITCODE, DUMPCODE,
        ac_init_pdesc, ac_fmt
};

static jtag_log_comp chip_bct8244 = {
        0,
        IR_LEN, 18,
        0x2, 0x2, 0x2,
        NULL, bct8244_fmt
};

static jtag_log_comp chip_dc = {
        cid_dc,
        IR_LEN, 5,
        IDCODE, INITCODE, DUMPCODE,
        dc_init_pdesc, dc_fmt
};

static jtag_log_comp chip_fhc = {
        cid_fhc,
        IR_LEN, 42,
        IDCODE, INITCODE, DUMPCODE,
        fhc_init_pdesc, fhc_fmt
};

static jtag_log_comp chip_ec = {
        0,
        EC_LEN, 42,
        1, INITCODE, IDCODE,
        ec_init_pdesc, ec_fmt
};

static jtag_log_comp chip_fbc = {
        cid_fbc,
        FFB_LEN, 42,
        0xb000, 0xb000, 0xb000,
        NULL, NULL
};

static jtag_log_comp chip_lvt = {
        cid_lvt,
        IR_LEN, 42,
        IDCODE, INITCODE, DUMPCODE,
        NULL, NULL
};

static jtag_log_comp chip_3dram = {
        cid_3dram,
        THREED_LEN, 42,
        IDCODE, INITCODE, DUMPCODE,
        NULL, NULL
};

static jtag_log_comp chip_bt498 = {
        cid_bt498,
        BT498_LEN, 42,
        IDCODE, INITCODE, DUMPCODE,
        NULL, NULL
};

static jtag_log_comp chip_sio = {
        cid_sio,
        SIO_LEN, 42,
        0xb000, 0xb000, 0xb000,
        sio_init_pdesc, sio_fmt
};

static jtag_log_comp chip_hm = {
        cid_hm,
        HM_LEN, 42,
        0xe, 0xe, 0xe,
        hm_init_pdesc, hm_fmt
};

static jtag_log_comp chip_ndp = {
        0,
        NDP_LEN, 42,
        2, 2, 2,
        ndp_init_pdesc, ndp_fmt
};

static jtag_log_comp chip_soc = {
        0,
        SOC_LEN, 42,
        4, 4, 4,
        NULL, NULL
};

static jtag_log_comp chip_socplus = {
        0,
        SOCPLUS_LEN, 42,
        0xfe, 4, 4,
        NULL, NULL
};

static jtag_log_comp chip_spitfire = {
        cid_sf,
        IR_LEN, 42,
        0xfe, 0xfe, 0xfe,
        NULL, NULL
};


static jtag_log_comp chip_sdb = {
        cid_sdb,
        IR_LEN,  42,
        0xfe, 0xfe, 0xfe,
        NULL, NULL
};

static jtag_log_comp chip_psyo = {
        cid_psyo,
        PSYO_LEN, 42,
        0xb000, 0xb000, 0xb000,
        psyo_init_pdesc, psyo_fmt
};

static jtag_log_comp chip_cheo = {
        cid_cheo,
        CHEO_LEN, 42,
        0xb000, 0xb000, 0xb000,
        cheo_init_pdesc, cheo_fmt
};

/*
 *    Ring descriptions for sunfire boards
 *
 * For each ring, there is a generic type descriptor which describes
 * the order of chips in the static data structure describing the
 * ring.
 *
 * Rings are described by an array of physical components, and are
 * recast into the specific ring type by routines which use them, see
 * for example the jtag_init_*_ring routines.
 *
 * Although the ring data structures are declared as jtag_phys_comp[],
 * the components must be ordered as required by the corresponding
 * *_*_ring type (in jtag_private.h).
 */

/*
 *    Data structures describing the system board rings
 */

static jtag_phys_comp cpu_sysbd_ring_components[] = {
        { &chip_ac, 11*IR_LEN,  0,              11,     0 },    /* AC */
        { &chip_dc, 10*IR_LEN,  1*IR_LEN,       10,     1 },    /* DC 1 */
        { &chip_dc, 9*IR_LEN,   2*IR_LEN,       9,      2 },    /* DC 2 */
        { &chip_dc, 8*IR_LEN,   3*IR_LEN,       8,      3 },    /* DC 3 */
        { &chip_dc, 7*IR_LEN,   4*IR_LEN,       7,      4 },    /* DC 4 */
        { &chip_dc, 6*IR_LEN,   5*IR_LEN,       6,      5 },    /* DC 5 */
        { &chip_dc, 5*IR_LEN,   6*IR_LEN,       5,      6 },    /* DC 6 */
        { &chip_dc, 4*IR_LEN,   7*IR_LEN,       4,      7 },    /* DC 7 */
        { &chip_dc, 3*IR_LEN,   8*IR_LEN,       3,      8 },    /* DC 8 */
        { &chip_fhc, 2*IR_LEN,  9*IR_LEN,       2,      9 },    /* FHC */
        { &chip_ec, 1*IR_LEN,   10*IR_LEN,      1,      10 },   /* RAM 0 */
        { &chip_ec, 0*IR_LEN,   11*IR_LEN,      0,      11 },   /* RAM 1 */
};

static jtag_ring_desc  cpu_sysbd_ring = {
        12, cpu_sysbd_ring_components
};


static jtag_phys_comp cpu_mod_1m_ring_components[] = {
        { &chip_spitfire, 43,   0,      11,     0 },    /* Spitfire */
        { &chip_ec,     40,     8,      10,     1 },    /* Parity chip */
        { &chip_ec,     37,     11,     9,      2 },    /* Byte 0 */
        { &chip_ec,     34,     14,     8,      3 },    /* Byte 1 */
        { &chip_ec,     31,     17,     7,      4 },    /* Byte 2 */
        { &chip_ec,     28,     20,     6,      5 },    /* Byte 3 */
        { &chip_ec,     25,     23,     5,      6 },    /* Byte 4 */
        { &chip_ec,     22,     26,     4,      7 },    /* Byte 5 */
        { &chip_ec,     19,     29,     3,      8 },    /* Byte 6 */
        { &chip_ec,     16,     32,     2,      9 },    /* Byte 7 */
        { &chip_sdb,    8,      35,     1,      10 },   /* SDB */
        { &chip_sdb,    0,      43,     0,      11 },   /* SDB */
};

static jtag_ring_desc  cpu_mod_1m_ring = {
        12, cpu_mod_1m_ring_components
};

static jtag_phys_comp cpu_mod_ring_components[] = {
        { &chip_spitfire, 31,   0,      7,      0 },    /* Spitfire */
        { &chip_ec,     28,     8,      6,      1 },    /* Parity chip */
        { &chip_ec,     25,     11,     5,      2 },    /* Byte 0 */
        { &chip_ec,     22,     14,     4,      3 },    /* Byte 1 */
        { &chip_ec,     19,     17,     3,      4 },    /* Byte 2 */
        { &chip_ec,     16,     20,     2,      5 },    /* Byte 3 */
        { &chip_sdb,    8,      23,     1,      6 },    /* SDB */
        { &chip_sdb,    0,      31,     0,      7 },    /* SDB */
};

static jtag_ring_desc  cpu_mod_ring = {
        8, cpu_mod_ring_components
};

static jtag_phys_comp io1_sysbd_ring_components[] = {
        { &chip_ac,     114,    0,      14,     0 },    /* AC */
        { &chip_dc,     106,    8,      13,     1 },    /* DC 1 */
        { &chip_dc,     98,     16,     12,     2 },    /* DC 2 */
        { &chip_dc,     90,     24,     11,     3 },    /* DC 3 */
        { &chip_dc,     82,     32,     10,     4 },    /* DC 4 */
        { &chip_dc,     74,     40,     9,      5 },    /* DC 5 */
        { &chip_dc,     66,     48,     8,      6 },    /* DC 6 */
        { &chip_dc,     58,     56,     7,      7 },    /* DC 7 */
        { &chip_dc,     50,     64,     6,      8 },    /* DC 8 */
        { &chip_fhc,    42,     72,     5,      9 },    /* FHC */
        { &chip_sio,    26,     80,     4,      10 },   /* SIO 0 */
        { &chip_sio,    10,     96,     3,      11 },   /* SIO 1 */
        { &chip_hm,     6,      112,    2,      12 },   /* HM */
        { &chip_ndp,    4,      116,    1,      13 },   /* NDP */
        { &chip_soc,    0,      118,    0,      14 },   /* SOC */
};

static jtag_phys_comp io2_sysbd_ring_components[] = {
        { &chip_ac,     98,     0,      13,     0 },    /* AC */
        { &chip_dc,     90,     8,      12,     1 },    /* DC 1 */
        { &chip_dc,     82,     16,     11,     2 },    /* DC 2 */
        { &chip_dc,     74,     24,     10,     3 },    /* DC 3 */
        { &chip_dc,     66,     32,     9,      4 },    /* DC 4 */
        { &chip_dc,     58,     40,     8,      5 },    /* DC 5 */
        { &chip_dc,     50,     48,     7,      6 },    /* DC 6 */
        { &chip_dc,     42,     56,     6,      7 },    /* DC 7 */
        { &chip_dc,     34,     64,     5,      8 },    /* DC 8 */
        { &chip_fhc,    26,     72,     4,      9 },    /* FHC */
        { &chip_sio,    10,     80,     3,      10 },   /* SIO */
        { &chip_hm,     6,      96,     2,      11 },   /* HM */
        { &chip_ndp,    4,      100,    1,      12 },   /* NDP */
        { &chip_soc,    0,      102,    0,      13 },   /* SOC */
};

static jtag_phys_comp io1plus_sysbd_ring_components[] = {
        { &chip_ac,     118,    0,      14,     0 },    /* AC */
        { &chip_dc,     110,    8,      13,     1 },    /* DC 1 */
        { &chip_dc,     102,    16,     12,     2 },    /* DC 2 */
        { &chip_dc,     94,     24,     11,     3 },    /* DC 3 */
        { &chip_dc,     86,     32,     10,     4 },    /* DC 4 */
        { &chip_dc,     78,     40,     9,      5 },    /* DC 5 */
        { &chip_dc,     70,     48,     8,      6 },    /* DC 6 */
        { &chip_dc,     62,     56,     7,      7 },    /* DC 7 */
        { &chip_dc,     54,     64,     6,      8 },    /* DC 8 */
        { &chip_fhc,    46,     72,     5,      9 },    /* FHC */
        { &chip_sio,    30,     80,     4,      10 },   /* SIO 0 */
        { &chip_sio,    14,     96,     3,      11 },   /* SIO 1 */
        { &chip_hm,     10,     112,    2,      12 },   /* HM */
        { &chip_ndp,    8,      116,    1,      13 },   /* NDP */
        { &chip_socplus, 0,     118,    0,      14 },   /* SOC+ */
};

static jtag_phys_comp io2plus_sysbd_ring_components[] = {
        { &chip_ac,     102,    0,      13,     0 },    /* AC */
        { &chip_dc,     94,     8,      12,     1 },    /* DC 1 */
        { &chip_dc,     86,     16,     11,     2 },    /* DC 2 */
        { &chip_dc,     78,     24,     10,     3 },    /* DC 3 */
        { &chip_dc,     70,     32,     9,      4 },    /* DC 4 */
        { &chip_dc,     62,     40,     8,      5 },    /* DC 5 */
        { &chip_dc,     54,     48,     7,      6 },    /* DC 6 */
        { &chip_dc,     46,     56,     6,      7 },    /* DC 7 */
        { &chip_dc,     38,     64,     5,      8 },    /* DC 8 */
        { &chip_fhc,    30,     72,     4,      9 },    /* FHC */
        { &chip_sio,    14,     80,     3,      10 },   /* SIO */
        { &chip_hm,     10,     96,     2,      11 },   /* HM */
        { &chip_ndp,    8,      100,    1,      12 },   /* NDP */
        { &chip_socplus, 0,     102,    0,      13 },   /* SOC+ */
};

static jtag_phys_comp io3_sysbd_ring_components[] = {
        { &chip_ac,     102,    0,      15,     0 },    /* AC */
        { &chip_dc,     94,     8,      14,     1 },    /* DC 1 */
        { &chip_dc,     86,     16,     13,     2 },    /* DC 2 */
        { &chip_dc,     78,     24,     12,     3 },    /* DC 3 */
        { &chip_dc,     70,     32,     11,     4 },    /* DC 4 */
        { &chip_dc,     62,     40,     10,     5 },    /* DC 5 */
        { &chip_dc,     54,     48,     9,      6 },    /* DC 6 */
        { &chip_dc,     46,     56,     8,      7 },    /* DC 7 */
        { &chip_dc,     38,     64,     7,      8 },    /* DC 8 */
        { &chip_fhc,    30,     72,     6,      9 },    /* FHC */
        { &chip_psyo,   26,     80,     5,      10 },   /* PSYO 0 */
        { &chip_cheo,   22,     84,     4,      11 },   /* CHEO */
        { &chip_ndp,    20,     88,     3,      12 },   /* NDP */
        { &chip_psyo,   16,     90,     2,      13 },   /* PSYO 1 */
        { &chip_bct8244,        8,      94,     1,      14 },   /* BCT 8244 */
        { &chip_bct8244,        0,      102,    0,      15 },   /* BCT 8244 */
};

static jtag_phys_comp dsk_sysbd_ring_components[] = {
        { &chip_bct8244, 8,     0,      1,      0 },    /* BCT 8244 */
        { &chip_fhc,    0,      8,      0,      1 },    /* FHC */
};

static jtag_ring_desc  io1_sysbd_ring = {
        15, io1_sysbd_ring_components
};

static jtag_ring_desc  io1plus_sysbd_ring = {
        15, io1plus_sysbd_ring_components
};

static jtag_ring_desc  io2_sysbd_ring = {
        14, io2_sysbd_ring_components
};

static jtag_ring_desc  io2plus_sysbd_ring = {
        14, io2plus_sysbd_ring_components
};

static jtag_ring_desc  io3_sysbd_ring = {
        16, io3_sysbd_ring_components
};

static jtag_ring_desc dsk_sysbd_ring = {
        2, dsk_sysbd_ring_components
};

/*
 * Ring descriptors for single and double buffered FFB boards.
 * Note - Only the FBC has a component ID register. None of the
 * other chips on the FFB board has one, so do not check them.
 */
static jtag_phys_comp ffb_sngl_ring_components[] = {
        { &chip_fbc,    20,     0,      5,      0 },    /* FBC */
        { &chip_3dram,  16,     16,     4,      1 },    /* 3DRAM */
        { &chip_3dram,  12,     20,     3,      2 },    /* 3DRAM */
        { &chip_3dram,  8,      24,     2,      3 },    /* 3DRAM */
        { &chip_3dram,  4,      28,     1,      4 },    /* 3DRAM */
        { &chip_bt498,  0,      32,     0,      5 },    /* RAMDAC */
};

static jtag_phys_comp ffb_dbl_ring_components[] = {
        { &chip_fbc,    84,     0,      17,     0 },    /* FBC */
        { &chip_lvt,    76,     16,     16,     1 },    /* LVT */
        { &chip_lvt,    68,     24,     15,     2 },    /* LVT */
        { &chip_lvt,    60,     32,     14,     3 },    /* LVT */
        { &chip_lvt,    52,     40,     13,     4 },    /* LVT */
        { &chip_3dram,  48,     48,     12,     5 },    /* 3DRAM */
        { &chip_3dram,  44,     52,     11,     6 },    /* 3DRAM */
        { &chip_3dram,  40,     56,     10,     7 },    /* 3DRAM */
        { &chip_3dram,  36,     60,     9,      8 },    /* 3DRAM */
        { &chip_3dram,  32,     64,     8,      9 },    /* 3DRAM */
        { &chip_3dram,  28,     68,     7,      10 },   /* 3DRAM */
        { &chip_3dram,  24,     72,     6,      11 },   /* 3DRAM */
        { &chip_3dram,  20,     76,     5,      12 },   /* 3DRAM */
        { &chip_3dram,  16,     80,     4,      13 },   /* 3DRAM */
        { &chip_3dram,  12,     84,     3,      14 },   /* 3DRAM */
        { &chip_3dram,  8,      88,     2,      15 },   /* 3DRAM */
        { &chip_3dram,  4,      92,     1,      16 },   /* 3DRAM */
        { &chip_bt498,  0,      96,     0,      17 },   /* RAMDAC */
};

static jtag_ring_desc ffb_sngl_ring = {
        6, ffb_sngl_ring_components
};

static jtag_ring_desc ffb_dbl_ring = {
        18, ffb_dbl_ring_components
};

/*
 *    Board descriptions
 */

static jtag_ring_desc *cpu_system_board[] = {
        &cpu_sysbd_ring,                /* Ring 0 */
        &cpu_mod_ring,                  /* Ring 1 */
        &cpu_mod_ring,                  /* Ring 2 */
};

static jtag_ring_desc *io1_system_board[] = {
        &io1_sysbd_ring,                        /* Ring 0 */
        (jtag_ring_desc *) NULL,                /* Ring 1 */
        (jtag_ring_desc *) NULL,                /* Ring 2 */
};

static jtag_ring_desc *io1plus_system_board[] = {
        &io1plus_sysbd_ring,                    /* Ring 0 */
        (jtag_ring_desc *) NULL,                /* Ring 1 */
        (jtag_ring_desc *) NULL,                /* Ring 2 */
};

static jtag_ring_desc *io2_system_board[] = {
        &io2_sysbd_ring,                        /* Ring 0 */
        (jtag_ring_desc *) NULL,                /* Ring 1 (ffb) */
        (jtag_ring_desc *) NULL,                /* Ring 2  */
};

static jtag_ring_desc *io2plus_system_board[] = {
        &io2plus_sysbd_ring,                    /* Ring 0 */
        (jtag_ring_desc *) NULL,                /* Ring 1 (ffb) */
        (jtag_ring_desc *) NULL,                /* Ring 2  */
};

static jtag_ring_desc *io3_system_board[] = {
        &io3_sysbd_ring,                        /* Ring 0 */
        (jtag_ring_desc *) NULL,                /* Ring 1 */
        (jtag_ring_desc *) NULL,                /* Ring 2 */
};

static jtag_ring_desc *disk_system_board[] = {
        &dsk_sysbd_ring,                        /* Ring 0 */
        (jtag_ring_desc *) NULL,                /* Ring 1 */
        (jtag_ring_desc *) NULL,                /* Ring 2 */
};

/*
 * Function Definitions:
 * ---------------------
 */

/* For sunfire there will be a ring descriptor for each type of board */
static jtag_ring_desc *
get_ring_descriptor_bytype(int ring, enum board_type type)
{

        switch (type) {
        case CPU_BOARD:
                return (cpu_system_board[ring & 0xf]);

        case IO_2SBUS_BOARD:
                return (io1_system_board[ring & 0xf]);

        case IO_2SBUS_SOCPLUS_BOARD:
                return (io1plus_system_board[ring & 0xf]);

        case IO_SBUS_FFB_BOARD:
                return (io2_system_board[ring & 0xf]);

        case IO_SBUS_FFB_SOCPLUS_BOARD:
                return (io2plus_system_board[ring & 0xf]);

        case IO_PCI_BOARD:
                return (io3_system_board[ring & 0xf]);

        case DISK_BOARD:
                return (disk_system_board[ring & 0xf]);

        default:
                return (NULL);
        }
}

static void
jtag_check_plus_board(
        volatile u_int *jreg,
        jtag_ring ring,
        jtag_phys_comp *comp,
        sysc_cfga_stat_t *sc)
{
        struct fhc_regs fhc_data;

        /*
         * the FHC Board Status Register indicates whether
         * the board 100 Mhz capable or not.
         */
        fhc_data.bsr = (u_int)0xffffffff;

        if ((jtag_scanout_chip(jreg, ring, comp, (u_int *)&fhc_data) >= 0) &&
            (FHC_BSR_TO_BD(fhc_data.bsr) == sc->board) &&
            ISPLUSBRD(fhc_data.bsr))
                sc->plus_board = 1;
}

/*
 * Returns (positive) board type if something detected, including
 * UNKNOWN_BOARD.
 * Returns EMPTY_BOARD if nothing there.
 */
enum board_type
jtag_get_board_type(volatile u_int *jreg, sysc_cfga_stat_t *sc)
{
        int len;
        int ring;
        int result;
        int board;
        int status;

        /*
         * Select Board Ring 0 to scan. This contains the AC, FHC,
         * and DC ASICs
         */

        /*
         * Ring number is JTAG Board (7:4) and ring number (3:0)
         */
        board = sc->board;
        ring = (board << 4) | 0;

        if ((status = select_ring(jreg, ring, 1)) < 0) {
                cmn_err(CE_WARN, "Select ring error %d\n", status);
        }

        len = jtag_ring_length(jreg, ring);
        switch (len) {
        case CPU_TYPE_LEN:
                result = CPU_BOARD;

                jtag_check_plus_board(jreg, ring,
                        &cpu_sysbd_ring_components[9], sc);

                break;

        case IO_TYPE1_LEN:
                switch (jtag_ring_ir_length(jreg, ring)) {
                case RING_BROKEN:
                        result = UNKNOWN_BOARD;
                        break;
                case IO_TYPE4_LEN:
                        result = IO_2SBUS_SOCPLUS_BOARD;
                        jtag_check_plus_board(jreg, ring,
                            &io1plus_sysbd_ring_components[9], sc);
                        break;
                default:
                        result = IO_2SBUS_BOARD;
                        jtag_check_plus_board(jreg, ring,
                            &io1_sysbd_ring_components[9], sc);
                        break;
                }

                break;

        case IO_TYPE2_LEN:
                switch (jtag_ring_ir_length(jreg, ring)) {
                case RING_BROKEN:
                        result = UNKNOWN_BOARD;
                        break;
                case IO_TYPE5_LEN:
                        result = IO_SBUS_FFB_SOCPLUS_BOARD;
                        jtag_check_plus_board(jreg, ring,
                            &io2plus_sysbd_ring_components[9], sc);
                        break;
                default:
                        result = IO_SBUS_FFB_BOARD;
                        jtag_check_plus_board(jreg, ring,
                            &io2_sysbd_ring_components[9], sc);
                        break;
                }

                break;

        case PCI_TYPE_LEN:
                switch (jtag_ring_ir_length(jreg, ring)) {
                case RING_BROKEN:
                        result = UNKNOWN_BOARD;
                        break;
                case PCI_TYPEA_LEN:
                        result = IO_PCI_BOARD;
                        jtag_check_plus_board(jreg, ring,
                            &io3_sysbd_ring_components[9], sc);
                        break;
                case PCI_TYPEB_LEN:
                default:
                        result = UNKNOWN_BOARD;
                        break;
                }
                break;

        case DSK_TYPE_LEN:
                result = DISK_BOARD;
                break;

        case RING_BROKEN:
                result = EMPTY_BOARD;
                break;

        default:
                result = UNKNOWN_BOARD;
                break;
        }

        TAP_ISSUE_CMD(jreg, JTAG_TAP_RESET, status);

        return (result);
}

#ifndef RFE_4174486
/*
 * Until the RFE is fully investigated the likelyhood is that the
 * CPU frequency may be incorrectly displayed. Coupled with the lack of
 * Ecache size information and no information at all unless the
 * CPU board is physically plugged in, the default is not to get any
 * CPU information.
 * This patchable flag is provided so that more testing can be done
 * without re-compilation.
 */
static int jtag_cpu_scan_enable = 0;
#endif /* RFE_4174486 */

int
jtag_get_board_info(volatile u_int *jreg, sysc_cfga_stat_t *sc)
{
        jtag_ring_desc *rd;
        jtag_phys_comp *rc;
        int status;
        int ring;
        int len;
        int i;
        struct cpu_info *cpu;
        struct bct_fields bct_data;

        /* fill in the board info structure */

        ring = sc->board << 4;

        if ((status = select_ring(jreg, ring, 1)) < 0) {
                return (status);
        }

        rd = get_ring_descriptor_bytype(ring, sc->type);

        if (rd == NULL) {
                return (JTAG_FAIL);
        }

        /* scan in the generic data common to all board types. */

        /* get the AC component ID */
        rc = find_chip(rd, &chip_ac, 0);
        if (rc != NULL) {
                sc->ac_compid = jtag_get_comp_id(jreg, rc);
        }

        /* get the FHC component ID */
        rc = find_chip(rd, &chip_fhc, 0);
        if (rc != NULL) {
                sc->fhc_compid = jtag_get_comp_id(jreg, rc);
        }

        /* Now scan the board type dependent components */
        switch (sc->type) {
        case CPU_BOARD:
                /*
                 * first determine the cache size of each module, then
                 * use that ring descriptor.
                 */

                for (i = 0, cpu = &sc->bd.cpu[i]; i < 2; i++, cpu++) {
                        bzero(cpu, sizeof (*cpu));
#ifndef RFE_4174486
                        if (!jtag_cpu_scan_enable)
                                continue;
#endif /* RFE_4174486 */
                        if (select_ring(jreg, ring | (i + 1), 1) < 0) {
                                continue;
                        }

                        len = jtag_ring_length(jreg, ring | (i + 1));

                        switch (len) {
                        case CPU_0_5_LEN:
                                rd = &cpu_mod_ring;
                                cpu->cpu_detected = 1;
                                break;

                        case CPU_1_0_LEN:
                                rd = &cpu_mod_1m_ring;
                                cpu->cpu_detected = 1;
                                break;

                        case RING_BROKEN:
                        default:
                                rd = NULL;
                                break;
                        }

                        if (!cpu->cpu_detected)
                                continue;

                        if (rd != NULL) {
                                rc = find_chip(rd, &chip_spitfire, 0);
                                if (rc != NULL) {
                                        cpu->cpu_compid =
                                                jtag_get_comp_id(jreg, rc);
                                }

                                /*
                                 * Do not get the component ID from the
                                 * first E$ chip. This is the tag chip
                                 * and does not help determine cache size.
                                 */
                                rc = find_chip(rd, &chip_ec, 1);
                                if (rc != NULL) {
                                        cpu->ec_compid =
                                                jtag_get_comp_id(jreg, rc);
                                }

                                rc = find_chip(rd, &chip_sdb, 0);
                                if (rc != NULL) {
                                        cpu->sdb0_compid =
                                                jtag_get_comp_id(jreg, rc);
                                }

                                rc = find_chip(rd, &chip_sdb, 1);
                                if (rc != NULL) {
                                        cpu->sdb1_compid =
                                                jtag_get_comp_id(jreg, rc);
                                }
                        }

#ifdef RFE_4174486
                        /* Work out Ecache size. */
                        switch (len) {
                        case CPU_0_5_LEN:
                                cpu->cache_size = 0x80000;
                                break;

                        case CPU_1_0_LEN:
                                /* default cache size for 9 SRAM chips */
                                cpu->cache_size = 0x100000;
                                break;

                        default:
                                break;
                        }
#endif /* RFE_4174486 */
                }

                break;

        case IO_2SBUS_BOARD:
                rc = find_chip(rd, &chip_sio, 0);
                if (rc != NULL) {
                        sc->bd.io1.sio0_compid =
                                jtag_get_comp_id(jreg, rc);
                }

                rc = find_chip(rd, &chip_sio, 1);
                if (rc != NULL) {
                        sc->bd.io1.sio1_compid =
                                jtag_get_comp_id(jreg, rc);
                }

                rc = find_chip(rd, &chip_hm, 0);
                if (rc != NULL) {
                        sc->bd.io1.hme_compid = jtag_get_comp_id(jreg, rc);
                }

                rc = find_chip(rd, &chip_soc, 0);
                if (rc != NULL) {
                        sc->bd.io1.soc_compid = jtag_get_comp_id(jreg, rc);
                }

                break;

        case IO_2SBUS_SOCPLUS_BOARD:
                rc = find_chip(rd, &chip_sio, 0);
                if (rc != NULL) {
                        sc->bd.io1.sio0_compid =
                                jtag_get_comp_id(jreg, rc);
                }

                rc = find_chip(rd, &chip_sio, 1);
                if (rc != NULL) {
                        sc->bd.io1.sio1_compid =
                                jtag_get_comp_id(jreg, rc);
                }

                rc = find_chip(rd, &chip_hm, 0);
                if (rc != NULL) {
                        sc->bd.io1.hme_compid = jtag_get_comp_id(jreg, rc);
                }

                rc = find_chip(rd, &chip_socplus, 0);
                if (rc != NULL) {
                        sc->bd.io1plus.socplus_compid =
                                        jtag_get_comp_id(jreg, rc);
                }

                break;

        case IO_SBUS_FFB_BOARD:
                rc = find_chip(rd, &chip_sio, 0);
                if (rc != NULL) {
                        sc->bd.io2.sio1_compid = jtag_get_comp_id(jreg, rc);
                }

                rc = find_chip(rd, &chip_hm, 0);
                if (rc != NULL) {
                        sc->bd.io2.hme_compid = jtag_get_comp_id(jreg, rc);
                }

                rc = find_chip(rd, &chip_soc, 0);
                if (rc != NULL) {
                        sc->bd.io2.soc_compid = jtag_get_comp_id(jreg, rc);
                }

                /* Now scan for an FFB board */
                if (select_ring(jreg, ring | 1, 1) < 0) {
                        len = RING_BROKEN;
                } else {
                        len = jtag_ring_length(jreg, ring | 1);
                }

                switch (len) {
                case FFB_SNG_LEN:
                        rd = &ffb_sngl_ring;
                        sc->bd.io2.ffb_size = FFB_SINGLE;
                        break;

                case FFB_DBL_LEN:
                        rd = &ffb_dbl_ring;
                        sc->bd.io2.ffb_size = FFB_DOUBLE;
                        break;

                case RING_BROKEN:
                        rd = NULL;
                        sc->bd.io2.ffb_size = FFB_NOT_FOUND;
                        break;

                default:
                        rd = NULL;
                        sc->bd.io2.ffb_size = FFB_FAILED;
                        break;
                }

                /* Now scan out the FBC component ID */
                if (rd != NULL) {
                        rc = find_chip(rd, &chip_fbc, 0);
                }

                if (rc != NULL) {
                        sc->bd.io2.fbc_compid = jtag_get_comp_id(jreg, rc);
                }
                break;

        case IO_SBUS_FFB_SOCPLUS_BOARD:
                rc = find_chip(rd, &chip_sio, 0);
                if (rc != NULL) {
                        sc->bd.io2.sio1_compid = jtag_get_comp_id(jreg, rc);
                }

                rc = find_chip(rd, &chip_hm, 0);
                if (rc != NULL) {
                        sc->bd.io2.hme_compid = jtag_get_comp_id(jreg, rc);
                }

                rc = find_chip(rd, &chip_socplus, 0);
                if (rc != NULL) {
                        sc->bd.io2plus.socplus_compid =
                                jtag_get_comp_id(jreg, rc);
                }

                /* Now scan for an FFB board */
                if (select_ring(jreg, ring | 1, 1) < 0) {
                        len = RING_BROKEN;
                } else {
                        len = jtag_ring_length(jreg, ring | 1);
                }

                switch (len) {
                case FFB_SNG_LEN:
                        rd = &ffb_sngl_ring;
                        sc->bd.io2.ffb_size = FFB_SINGLE;
                        break;

                case FFB_DBL_LEN:
                        rd = &ffb_dbl_ring;
                        sc->bd.io2.ffb_size = FFB_DOUBLE;
                        break;

                case RING_BROKEN:
                        rd = NULL;
                        sc->bd.io2.ffb_size = FFB_NOT_FOUND;
                        break;

                default:
                        rd = NULL;
                        sc->bd.io2.ffb_size = FFB_FAILED;
                        break;
                }

                /* Now scan out the FBC component ID */
                if (rd != NULL) {
                        rc = find_chip(rd, &chip_fbc, 0);
                }

                if (rc != NULL) {
                        sc->bd.io2.fbc_compid = jtag_get_comp_id(jreg, rc);
                }
                break;

        case IO_PCI_BOARD:
                rc = find_chip(rd, &chip_psyo, 0);
                if (rc != NULL) {
                        sc->bd.io3.psyo0_compid =
                                jtag_get_comp_id(jreg, rc);
                }

                rc = find_chip(rd, &chip_psyo, 1);
                if (rc != NULL) {
                        sc->bd.io3.psyo1_compid =
                                jtag_get_comp_id(jreg, rc);
                }

                rc = find_chip(rd, &chip_cheo, 0);
                if (rc != NULL) {
                        sc->bd.io3.cheo_compid = jtag_get_comp_id(jreg, rc);
                }

                break;

        case DISK_BOARD:
                /*
                 * Scan the BCT8244 to get the disk drive info out of
                 * the chip.
                 */
                if (jtag_scanout_chip(jreg, ring,
                    &dsk_sysbd_ring_components[0], (u_int *)&bct_data) < 0) {
                        TAP_ISSUE_CMD(jreg, JTAG_TAP_RESET, status);
                        return (-1);
                }

                if ((bct_data.disk0_pres && 0x1) == 0) {
                        sc->bd.dsk.disk_pres[0] = 1;
                        sc->bd.dsk.disk_id[0] = 0xf & ~bct_data.disk0_id;
                } else {
                        sc->bd.dsk.disk_pres[0] = 0;
                }

                if ((bct_data.disk1_pres && 0x1) == 0) {
                        sc->bd.dsk.disk_pres[1] = 1;
                        sc->bd.dsk.disk_id[1] = 0xf & ~bct_data.disk1_id;
                } else {
                        sc->bd.dsk.disk_pres[1] = 0;
                }

                break;

        default:
                break;
        }

        return (JTAG_OK);
}

static jtag_phys_comp *
find_chip(jtag_ring_desc *rd, jtag_log_comp *chip, int instance)
{
        int i;
        int found = 0;
        jtag_phys_comp *rc;

        for (i = rd->size, rc = rd->components; i != 0; rc++, i--) {
                if (rc->chip == chip) {
                        if (found == instance) {
                                return (rc);
                        } else {
                                found++;
                        }
                }
        }
        return (NULL);
}

/*
 * Function jtag_error() :
 *
 *      This function centrailizes the use of the JTAG error strings.
 * It should be called with the JTAG error code anytime the programmer
 * wants to print the type of JTAG error encountered. Just call with the
 * error code returned by the JTAG function. If no error occurred, nothing
 * is printed.
 */
static void
jtag_error_print(int ring, jtag_error code)
{
        char *ring_str = "System Board";

        switch (code) {
        case JTAG_OK :
                break;

        case TAP_TIMEOUT :
                cmn_err(CE_WARN, "%s : TAP controller timeout\n", jtag_err);
                break;

        case BAD_ARGS :
                cmn_err(CE_WARN,
                        "%s : routine reports bad args: Board %d, %s Ring\n",
                        jtag_err, ring >> 4, ring_str);
                break;

        case BAD_CID :
                cmn_err(CE_WARN,
                        "%s : Bad component ID detected: Board %d, %s Ring\n",
                        jtag_err, ring >> 4, ring_str);
                break;

        case RING_BROKEN :
                cmn_err(CE_WARN, "%s : ring broken: Board %d, %s Ring\n",
                        jtag_err, ring >> 4, ring_str);
                break;

        case INIT_MISMATCH:
                cmn_err(CE_WARN,
                        "%s : State after init not expected: Board %d, "
                        "%s Ring\n", jtag_err, ring >> 4, ring_str);
                break;

        case LENGTH_MISMATCH :
                cmn_err(CE_WARN,
                        "%s : Scan Chain Length mismatch: Board %d,"
                        " %s Ring\n",
                        jtag_err, ring >> 4, ring_str);
                break;

        }       /* end of switch on code */
}       /* end of jtag_error_print() */


static int
jtag_get_comp_id(volatile u_int *jreg, jtag_phys_comp *comp)
{
        u_char b[4];
        u_int id;
        int status;

        status = jtag_single_IR_DR(jreg, comp, comp->chip->id_code,
                b, 32, b);

        /* Reorder the bytes of the ID read out */
        id = b[0] | (b[1] << 8) | (b[2] << 16) | (b[3] << 24);

        if (status < 0) {
                return (0);
        } else {
                return (id);
        }
}

/*
 *    Bit-manipulation routines
 */

/*
 * jtag_bf_extract()
 *
 * This routine extracts bit strings from JTAG data scanout strings. This
 * routine is used to decode data scanned out of chips via JTAG.
 */
static u_int
jtag_bf_extract(u_char *s, int lsb, int msb)
{
        u_int result = 0;

        ASSERT(s);

        /*
         * lsb and msb are assumed to be within string,
         * and to span 32 bits at most
         */
        for (; msb >= lsb; msb--) {
                result = (result << 1) | ((s[msb>>3] >> (msb & 7)) & 1);
        }
        return (result);
}

/*
 * jtag_bf_insert()
 *
 * This routine is used to build bit strings for scanning into the
 * shadow chains of ASICs.
 */
static void
jtag_bf_insert(u_char *s, int lsb, int msb, int value)
{
        ASSERT(s);

        /*
         * lsb and msb are assumed to be within string,
         * and to span 32 bits at most
         */

        for (; msb >= lsb; lsb++) {
                s[lsb>>3] = (s[lsb>>3] & ~ (1 << (lsb & 7))) |
                        ((value & 1) << (lsb & 7));
                value = value >> 1;
        }
}

/*
 *
 */
static void
jtag_bf_zero(u_char *s, int nbits)
{
        int nbytes = (nbits+7)>>3;

        while (nbytes-- != 0) {
                *s++ = 0;
        }
}

/*
 * Return 0 if equal, != 0 else
 */
static int
jtag_bf_cmp(u_char *s1, u_char *s2, int nbits)
{
        int mask;
        for (nbits -= 8; nbits > 0; nbits -= 8) {
                if (*s1++ != *s2++) {
                        return (-1);
                }
                mask = 0xFF >> (-nbits);
                if ((*s1++ & mask) != (*s2++ & mask)) {
                        return (-1);
                }
        }

        return (0);
}


/*
 * Generic chip-level top routines
 */
static int
jtag_init_chip(
        volatile u_int *jreg,
        jtag_ring ring,
        jtag_phys_comp *component,
        const u_int *pval,
        u_char scan_out[32])
{
        int status;
        jtag_log_comp *chip;
        u_char scan_in[32];
        u_char *pdesc;

        status = select_ring(jreg, ring, 1);
        if (status < 0) {
                return (status);
        }

        pval = pval - 1; /* adjust pval since indices start at 1 */
        chip = component->chip;
        pdesc = chip->init_pdesc;

        /* Zero out the scan-in area */
        jtag_bf_zero(scan_in, 8*32);
        jtag_bf_zero(scan_out, 8*32);

        for (;;) {
                u_int flags, lsb, msb, patch;
                flags = *pdesc++;
                if ((flags & JTIN_INSERT) != 0) {
                        lsb = *pdesc++;
                        msb = *pdesc++;
                        if ((flags & JTIN_INDEX) != 0) {
                                patch = pval[flags & JTIN_INDEX];
                        } else {
                                patch = *pdesc++;
                        }
                        jtag_bf_insert(scan_in, lsb, msb, patch);
                }

                if ((flags & JTIN_UPDATE) != 0) {
                        status = jtag_single_IR_DR(jreg, component,
                                chip->init_code, scan_in, chip->dr_len,
                                scan_out);

                        if (status < 0) {
                                return (status);
                        }

                        if ((status = select_ring(jreg, ring, 1)) < 0) {
                                return (status);
                        }
                }

                if ((flags & JTIN_COMPARE) != 0) {
                        if (jtag_bf_cmp(scan_in, scan_out, chip->dr_len) != 0)
                                return (INIT_MISMATCH);
                }

                if ((flags & JTIN_END) != 0) {
                        break;
                }
        }

        return (JTAG_OK);    /* all is OK... */
}

/*
 * Dump the info from a chip.
 * Return the number of bytes used, or <0 if failed
 */
static int
jtag_scanout_chip(
        volatile u_int *jreg,
        jtag_ring ring,
        jtag_phys_comp *component,
        u_int *result)
{
        int status;
        jtag_log_comp *chip;
        u_char scan_in[32];
        u_char scan_out[32];
        u_char *p;
        u_int value;
        int bytes_used = 0;

        if ((status = select_ring(jreg, ring, 1)) < 0) {
                return (status);
        }

        chip = component->chip;

        p = chip->fmt_desc;
        if (p == NULL) {
                return (bytes_used);
        }

        status = jtag_rescan_IR_DR(jreg, component, chip->dump_code, scan_in,
                chip->dr_len, scan_out);

        if (status < 0) {
                return (status);
        }

        if ((status = select_ring(jreg, ring, 1)) < 0) {
                return (status);
        }

        for (value = 0; ; ) {
                u_char cmd = *p++;

                if ((cmd & JTSO_XTRACT) != 0) {
                        u_int lsb, msb;
                        lsb = *p++;
                        msb = *p++;
                        value |= jtag_bf_extract(scan_out, lsb, msb) <<
                                (cmd & JTSO_SHIFT);
                }

                if ((cmd & JTSO_ST) != 0) {
                        *result++ = value;
                        bytes_used += 4;
                        value = 0;
                }

                if ((cmd & JTSO_END) != 0) {
                        break;
                }
        }
        return (bytes_used);
}

/*
 * Set the AC into hotplug mode upon insertion
 */
static int
jtag_init_ac(volatile u_int *jreg, int bid, enum board_type brdtype)
{
        int rc = JTAG_OK;
        int status;
        int ring = (bid << 4);
        ac_options ac_opt;
        u_char scan_out[64];
        uint_t cs_value;

        if (brdtype == UNKNOWN_BOARD)
                return (rc);

        ac_opt.frozen = 0;      /* 0 = frozen */
        ac_opt.reset_a = 1;
        ac_opt.reset_b = 1;
        ac_opt.board_id = bid;
        ac_opt.mask_hwerr = (uint_t)-1;
        ac_opt.node_id = 3;

        /* Get a good AC BCSR value from the board we are running on. */
        cs_value = ldphysio(AC_BCSR(FHC_CPU2BOARD(CPU->cpu_id)));

        ac_opt.arb_fast = (cs_value & AC_ARB_FAST) ? 1 : 0;
        ac_opt.pcr_hi = 0;
        ac_opt.pcr_lo = 0x80000000LL - 0x9ac4  - (bid << 3);
        ac_opt.pcc_ctl0 = 0x3f;
        ac_opt.pcc_ctl1 = 0x3f;
        ac_opt.pcc_tctrl = (1 << 11); /* TREN */

        if ((brdtype == CPU_BOARD) || (brdtype == MEM_BOARD)) {
                rc = jtag_init_chip(jreg, ring, &cpu_sysbd_ring_components[0],
                        (jtag_opt)&ac_opt, scan_out);
        } else if (brdtype == IO_2SBUS_BOARD) {
                rc = jtag_init_chip(jreg, ring, &io1_sysbd_ring_components[0],
                        (jtag_opt)&ac_opt, scan_out);
        } else if (brdtype == IO_2SBUS_SOCPLUS_BOARD) {
                rc = jtag_init_chip(jreg, ring,
                        &io1plus_sysbd_ring_components[0],
                        (jtag_opt)&ac_opt, scan_out);
        } else if (brdtype == IO_SBUS_FFB_BOARD) {
                rc = jtag_init_chip(jreg, ring, &io2_sysbd_ring_components[0],
                        (jtag_opt)&ac_opt, scan_out);
        } else if (brdtype == IO_SBUS_FFB_SOCPLUS_BOARD) {
                rc = jtag_init_chip(jreg, ring,
                        &io2plus_sysbd_ring_components[0],
                        (jtag_opt)&ac_opt, scan_out);
        } else if (brdtype == IO_PCI_BOARD) {
                rc = jtag_init_chip(jreg, ring, &io3_sysbd_ring_components[0],
                        (jtag_opt)&ac_opt, scan_out);
        } else {
                cmn_err(CE_NOTE, " jtag_init_ac() Board %d"
                    " unsupported type %2X", bid, brdtype);
        }

        TAP_ISSUE_CMD(jreg, JTAG_TAP_RESET, status);

        if (rc != JTAG_OK) {
                jtag_error_print(ring, rc);
        }

        return (rc);
}

#define EN_LOC_FATAL            0x02
#define MOD_OFF                 0x80
#define ACDC_OFF                0x40
#define EPDA_OFF                0x10
#define EPDB_OFF                0x08
#define NOT_BRD_PRESENT         0x02
#define NOT_BRD_LED_LEFT        0x04
#define BRD_LED_MID             0x02
#define BRD_LED_RIGHT           0x01

/*
 * Each board has an FHC asic.
 */
int
jtag_powerdown_board(volatile u_int *jreg, int board, enum board_type type,
        u_int *fhc_csr, u_int *fhc_bsr, int intr)
{
        int rc = JTAG_OK;
        fhc_options fhc_opt;
        struct fhc_regs fhc_data;
        u_char scan_out[32];
        int status;
        int ring;

        if (type == UNKNOWN_BOARD) {
                sysc_cfga_stat_t asc;

                bzero(&asc, sizeof (asc));
                asc.board = board;
                type = jtag_get_board_type(jreg, &asc);
        }

        if (!intr)
                (void) jtag_init_ac(jreg, board, type);

        ring = board << 4;

        fhc_opt.csr_hi = 0;
        fhc_opt.csr_mid = MOD_OFF | EPDA_OFF | EPDB_OFF | NOT_BRD_PRESENT;
        if (intr) {
                /*
                 * by not setting NOT_BRD_PRESENT we can simulate a board
                 * insertion
                 */
                fhc_opt.csr_mid &= ~NOT_BRD_PRESENT;
        }

        fhc_opt.csr_midlo = NOT_BRD_LED_LEFT | BRD_LED_MID;

        if ((type == CPU_BOARD) || (type == MEM_BOARD)) {
                rc = jtag_init_chip(jreg, ring, &cpu_sysbd_ring_components[9],
                        (jtag_opt)&fhc_opt, scan_out);
        } else if (type == IO_2SBUS_BOARD) {
                rc = jtag_init_chip(jreg, ring, &io1_sysbd_ring_components[9],
                        (jtag_opt)&fhc_opt, scan_out);
        } else if (type == IO_2SBUS_SOCPLUS_BOARD) {
                rc = jtag_init_chip(jreg, ring,
                        &io1plus_sysbd_ring_components[9],
                        (jtag_opt)&fhc_opt, scan_out);
        } else if (type == IO_SBUS_FFB_BOARD) {
                rc = jtag_init_chip(jreg, ring, &io2_sysbd_ring_components[9],
                        (jtag_opt)&fhc_opt, scan_out);
        } else if (type == IO_SBUS_FFB_SOCPLUS_BOARD) {
                rc = jtag_init_chip(jreg, ring,
                        &io2plus_sysbd_ring_components[9],
                        (jtag_opt)&fhc_opt, scan_out);
        } else if (type == IO_PCI_BOARD) {
                rc = jtag_init_chip(jreg, ring, &io3_sysbd_ring_components[9],
                        (jtag_opt)&fhc_opt, scan_out);
        } else if (type == UNKNOWN_BOARD) {
                rc = jtag_init_chip(jreg, ring, &cpu_sysbd_ring_components[9],
                        (jtag_opt)&fhc_opt, scan_out);
        } else {
                cmn_err(CE_WARN, "Unsupported Board type %2X\n",
                        fhc_bd_type(board));
        }

        TAP_ISSUE_CMD(jreg, JTAG_TAP_RESET, status);

        if (rc != JTAG_OK) {
                jtag_error_print(ring, rc);
        }

        /* Reformat the FHC shadow chain scan data */
        format_chip_data(chip_fhc.fmt_desc, (u_int *)&fhc_data,
                scan_out);

        *fhc_csr = fhc_data.csr;
        *fhc_bsr = fhc_data.bsr;


        return (rc);
}

/*
 * This function performs the fhc initialization for a disk board. The
 * hotplug variable tells the function whether to put the LED into low
 * power mode or not.
 */
int
jtag_init_disk_board(volatile u_int *jreg, int board,
        u_int *fhc_csr, u_int *fhc_bsr)
{
        int rc = JTAG_OK;
        fhc_options fhc_opt;
        struct fhc_regs fhc_data;
        u_char scan_out[32];
        int status;
        int ring;

        ring = board << 4;

        fhc_opt.csr_hi = 0;
        fhc_opt.csr_mid = NOT_BRD_PRESENT;
        fhc_opt.csr_midlo = NOT_BRD_LED_LEFT | BRD_LED_MID;

        rc = jtag_init_chip(jreg, ring, &dsk_sysbd_ring_components[1],
                (jtag_opt)&fhc_opt, scan_out);

        TAP_ISSUE_CMD(jreg, JTAG_TAP_RESET, status);

        if (rc != JTAG_OK) {
                jtag_error_print(ring, rc);
                return (-1);
        }

        /* Reformat the FHC shadow chain scan data */
        format_chip_data(chip_fhc.fmt_desc, (u_int *)&fhc_data,
                scan_out);

        *fhc_csr = fhc_data.csr;
        *fhc_bsr = fhc_data.bsr;

        return (0);
}

/*
 * NOTES:
 *      1. Scan data streams are little-endian sequences of bytes: byte 0
 *         will provide the 8 lsb of the scan chain, and so on. If the last
 *         byte is not full (count not a multiple of 8), the least significant
 *         bits are used.
 *      2. All procedures assume that the JTAG control register
 *         is non-busy on entry, and return with the control register
 *         non-busy. It is a good idea to call tap_wait as part of the JTAG
 *         sanity check sequence to verify there is no obvious malfunction.
 */


/*
 *      Non-data TAP commands
 */

/*
 * Wait for the TAP to be idle.
 * Return <0 if error, >=0 if OK.
 */

int
tap_wait(volatile u_int *jreg)
{
        TAP_DECLARE;
        TAP_WAIT(jreg);
        return (JTAG_OK);
}

/*
 * Send a TAP command, wait for completion.
 * Return <0 if error, >=0 if OK.
 */

static int
tap_issue_cmd(volatile u_int *jreg, u_int command)
{
        TAP_DECLARE;

        *jreg = command;
        TAP_WAIT(jreg);
        return (JTAG_OK);
}

/*
 *      Data TAP commands
 */

/*
 * Shift 1 to 16 bits into the component.
 * Return <0 if error, the shifted out bits (always >=0) if OK.
 */

int
tap_shift_single(volatile u_int *jreg, int data, int nbits)
{
        /* Return <0 if error, >0 (16-bit data) if OK */
        TAP_DECLARE;
        TAP_SHIFT(jreg, data, nbits);
        return (jtag_data(jreg, nbits));
}

/*
 * Shift the required number of bits from in into the component,
 * retrieve the bits shifted out.
 * Return <0 if error, >=0 if OK.
 */

int
tap_shift_multiple(
        volatile u_int *jreg,
        u_char *data_in,
        int nbits,
        u_char *data_out)    /* data_out may be NULL if not needed */
{
        TAP_DECLARE;

        /*
         * The loop is done a byte at a time to avoid stepping out
         * of the caller's buffer
         */
        for (; nbits > 0; nbits = nbits - 8) {
                int bits_this_pass = nbits > 8 ? 8 : nbits;
                TAP_SHIFT(jreg, *data_in++, bits_this_pass);
                if (data_out != NULL) {
                        *data_out = jtag_data(jreg, bits_this_pass);
                        data_out++;
                }
        }

        return (JTAG_OK);
}

/*
 * Shift the required number of bits of the specified
 * value into the selected register. Note that this routine makes
 * sense only for value = 0 and value = -1.
 * Return <0 if error, >=0 if OK.
 */

static int
tap_shift_constant(volatile u_int *jreg, int value, int nbits)
{
        TAP_DECLARE;

        TAP_WAIT(jreg);

        /*
         * The loop is done a half-word at a time
         */
        for (; nbits > 0; nbits = nbits - 16) {
                int bits_this_pass = nbits > 16 ? 16 : nbits;
                TAP_SHIFT(jreg, value, bits_this_pass);
        }

        return (JTAG_OK);
}


/*
 *      Ring-level commands
 */

/*
 * Select the required ring. Reset it if required (reset != 0).
 * Return <0 if error, >=0 if OK.
 */

static int
select_ring(volatile u_int *jreg, jtag_ring ring, int reset)
{
        int status;
        jtag_ring jring;

        status = tap_wait(jreg);
        if (status < 0) {
                return (status);
        }

        /* Translate a Physical Board number to a JTAG board number */
        jring = ((u_int)(ring & 0x10) << 3) | ((u_int)(ring & 0xE0) >> 1) |
                (ring & 0xF);
        status = tap_issue_cmd(jreg, (jring << 16) | JTAG_SEL_RING);
        if (status < 0) {
                return (status);
        }

        if (reset != 0) {
                status = tap_issue_cmd(jreg, JTAG_TAP_RESET);
        }

        return (status);
}

/*
 * Shift the specified instruction into the component, then
 * shift the required data in & retrieve the data out.
 * Return <0 if error, >=0 if OK.
 */

static int
jtag_single_IR_DR(
        volatile u_int *jreg,
        jtag_phys_comp *component,
        jtag_instruction instr,
        u_char *in,
        int nbits,
        u_char *out)
{
        int status;

        TAP_ISSUE_CMD(jreg, JTAG_SEL_IR, status);
        TAP_SHIFT_CONSTANT(jreg, -1, component->ir_after, status);
        TAP_SHIFT_SINGLE(jreg, instr, component->chip->ir_len, status);
        TAP_SHIFT_CONSTANT(jreg, -1, component->ir_before, status);
        TAP_ISSUE_CMD(jreg, JTAG_IR_TO_DR, status);
        TAP_SHIFT_CONSTANT(jreg, 0, component->by_after, status);
        TAP_SHIFT_MULTIPLE(jreg, in, nbits, out, status);
        TAP_SHIFT_CONSTANT(jreg, 0, component->by_before, status);
        TAP_ISSUE_CMD(jreg, JTAG_RUNIDLE, status);

        return (status);
}

/*
 * jtag_rescan_IR_DR()
 *
 * This function is used in order to rescan the DC ASICs when taking
 * them out of the frozen state. This is necessary because of a problem
 * when taking DCs out of the frozen state. Sometimes the operation must
 * be retryed.
 *
 * TODO - Eliminate the *in input parameter if able to.
 */

/* ARGSUSED */
static int
jtag_rescan_IR_DR(
        volatile u_int *jreg,
        jtag_phys_comp *component,
        jtag_instruction instr,
        u_char *in,
        int nbits,
        u_char *out)
{
        int status, i;
        u_char tmp[32];

        for (i = 0; i < 32; i++)
                tmp[i] = 0;

        TAP_ISSUE_CMD(jreg, JTAG_SEL_IR, status);
        TAP_SHIFT_CONSTANT(jreg, -1, component->ir_after, status);
        TAP_SHIFT_SINGLE(jreg, instr, component->chip->ir_len, status);
        TAP_SHIFT_CONSTANT(jreg, -1, component->ir_before, status);
        TAP_ISSUE_CMD(jreg, JTAG_IR_TO_DR, status);

        /* scan the chip out */
        TAP_SHIFT_CONSTANT(jreg, 0, component->by_after, status);
        TAP_SHIFT_MULTIPLE(jreg, tmp, nbits, out, status);
        TAP_SHIFT_CONSTANT(jreg, 0, component->by_before, status);

        /* re scan the chip */
        TAP_SHIFT_CONSTANT(jreg, 0, component->by_after, status);
        TAP_SHIFT_MULTIPLE(jreg, out, nbits, tmp, status);
        TAP_SHIFT_CONSTANT(jreg, 0, component->by_before, status);

        TAP_ISSUE_CMD(jreg, JTAG_RUNIDLE, status);

        return (status);
}

/*
 * Return the number of components of the current ring, or <0 if failed
 */
static int
jtag_ring_length(volatile u_int *jreg, jtag_ring ring)
{
        int status, length;

        /*
         * Reset the ring & check that there is a component
         * This is based on the fact that TAP reset forces the IDCODE,
         * or BYPASS (with 0 preloaded) if there is no ID
         */

        status = select_ring(jreg, ring, 1);
        if (status < 0) {
                cmn_err(CE_WARN, "select ring error jtag status %x\n",
                        status);
                return (status);
        }

        TAP_ISSUE_CMD(jreg, JTAG_SEL_DR, status);
        TAP_SHIFT_SINGLE(jreg, -1, 8, status);
        if (status == 0xFF) {
                return (RING_BROKEN); /* no CID detected */
        }

        /*
         * Put all components in BYPASS. This assumes the chain has
         * at most 32 components, and that each IR is at most 16-bits.
         * Note that the algorithm depends on the bypass FF to be cleared
         * on a tap reset!
         */
        TAP_ISSUE_CMD(jreg, JTAG_TAP_RESET, status);
        TAP_ISSUE_CMD(jreg, JTAG_SEL_IR, status);
        TAP_SHIFT_CONSTANT(jreg, -1, 32*16, status);
        TAP_ISSUE_CMD(jreg, JTAG_IR_TO_DR, status);
        TAP_SHIFT_CONSTANT(jreg, 0, 32, status);

        for (length = 0; length <= 33; length++) { /* bit by bit */
                TAP_SHIFT_SINGLE(jreg, -1, 1, status);

                if (status != 0) {
                        break;
                }
        }
        TAP_ISSUE_CMD(jreg, JTAG_RUNIDLE, status);
        /* more than 32 components ??? */
        return ((length <= 32) ? length : RING_BROKEN);
}

/*
 * Return the total number of instruction register bits in the
 * current ring,  or < 0 if failed.
 */
int
jtag_ring_ir_length(volatile u_int *jreg, jtag_ring ring)
{
        int status, length;

        /*
         * Reset the ring & check that there is a component
         * This is based on the fact that TAP reset forces the IDCODE,
         * or BYPASS (with 0 preloaded) if there is no ID
         */
        status = select_ring(jreg, ring, 1);
        if (status < 0) {
                cmn_err(CE_WARN, "select error status %x", status);
                return (status);
        }

        /*
         * Reset, Select IR, Shift in all 1's assuming the chain has
         * at most 32 components, and that each IR is at most 16-bits.
         * Then shift in 0's and count until a 0 comes out.
         * And cleanup by flushing with all 1's before reset or idle
         * --- FATAL's if you don't as you go through update-ir state
         */
        TAP_ISSUE_CMD(jreg, JTAG_TAP_RESET, status);
        TAP_ISSUE_CMD(jreg, JTAG_SEL_IR, status);

        /* 1 fill, look for 0 */
        TAP_SHIFT_CONSTANT(jreg, -1, 32 * 16, status);
        for (length = 0; length <= 32 * 16; length++) { /* bit by bit */
                TAP_SHIFT_SINGLE(jreg, 0, 1, status);
                if (status == 0)
                        break;
        }

        /* bypass should be safe */
        TAP_SHIFT_CONSTANT(jreg, -1, 32 * 16, status);
        TAP_ISSUE_CMD(jreg, JTAG_RUNIDLE, status);
        /* more than 32*16 ir bits ??? */
        return ((length <= 32 * 16) ? length : RING_BROKEN);
}

/*
 * Format the jtag shadow scan data from scan_out bit string and store
 * in the array on u_ints. The datap represents the registers from
 * the chip under scan.
 * XXX - How to represent 64 bit registers here?
 */
static void
format_chip_data(u_char *fmt, u_int *datap, u_char *scan_out)
{
        u_int value;

        for (value = 0; ; ) {
                u_char cmd = *fmt++;

                if ((cmd & JTSO_XTRACT) != 0) {
                        u_int lsb, msb;
                        lsb = *fmt++;
                        msb = *fmt++;
                        value |= jtag_bf_extract(scan_out, lsb, msb) <<
                                (cmd & JTSO_SHIFT);
                }

                if ((cmd & JTSO_ST) != 0) {
                        *datap++ = value;
                        value = 0;
                }

                if ((cmd & JTSO_END) != 0) {
                        break;
                }
        }
}