125cf1a30Sjl139090 /*
225cf1a30Sjl139090 * CDDL HEADER START
325cf1a30Sjl139090 *
425cf1a30Sjl139090 * The contents of this file are subject to the terms of the
525cf1a30Sjl139090 * Common Development and Distribution License (the "License").
625cf1a30Sjl139090 * You may not use this file except in compliance with the License.
725cf1a30Sjl139090 *
825cf1a30Sjl139090 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
925cf1a30Sjl139090 * or http://www.opensolaris.org/os/licensing.
1025cf1a30Sjl139090 * See the License for the specific language governing permissions
1125cf1a30Sjl139090 * and limitations under the License.
1225cf1a30Sjl139090 *
1325cf1a30Sjl139090 * When distributing Covered Code, include this CDDL HEADER in each
1425cf1a30Sjl139090 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1525cf1a30Sjl139090 * If applicable, add the following below this CDDL HEADER, with the
1625cf1a30Sjl139090 * fields enclosed by brackets "[]" replaced with your own identifying
1725cf1a30Sjl139090 * information: Portions Copyright [yyyy] [name of copyright owner]
1825cf1a30Sjl139090 *
1925cf1a30Sjl139090 * CDDL HEADER END
2025cf1a30Sjl139090 */
2125cf1a30Sjl139090 /*
22*392e836bSGavin Maltby * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
231e2e7a75Shuah */
241e2e7a75Shuah /*
2578ed97a7Sjl139090 * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2008
2625cf1a30Sjl139090 */
2725cf1a30Sjl139090
2825cf1a30Sjl139090 #include <sys/types.h>
2925cf1a30Sjl139090 #include <sys/sysmacros.h>
3025cf1a30Sjl139090 #include <sys/conf.h>
3125cf1a30Sjl139090 #include <sys/modctl.h>
3225cf1a30Sjl139090 #include <sys/stat.h>
3325cf1a30Sjl139090 #include <sys/async.h>
341e2e7a75Shuah #include <sys/machcpuvar.h>
3525cf1a30Sjl139090 #include <sys/machsystm.h>
360cc8ae86Sav145390 #include <sys/promif.h>
3725cf1a30Sjl139090 #include <sys/ksynch.h>
3825cf1a30Sjl139090 #include <sys/ddi.h>
3925cf1a30Sjl139090 #include <sys/sunddi.h>
40d8a0cca9Swh31274 #include <sys/sunndi.h>
4125cf1a30Sjl139090 #include <sys/ddifm.h>
4225cf1a30Sjl139090 #include <sys/fm/protocol.h>
4325cf1a30Sjl139090 #include <sys/fm/util.h>
4425cf1a30Sjl139090 #include <sys/kmem.h>
4525cf1a30Sjl139090 #include <sys/fm/io/opl_mc_fm.h>
4625cf1a30Sjl139090 #include <sys/memlist.h>
4725cf1a30Sjl139090 #include <sys/param.h>
480cc8ae86Sav145390 #include <sys/disp.h>
4925cf1a30Sjl139090 #include <vm/page.h>
5025cf1a30Sjl139090 #include <sys/mc-opl.h>
510cc8ae86Sav145390 #include <sys/opl.h>
520cc8ae86Sav145390 #include <sys/opl_dimm.h>
530cc8ae86Sav145390 #include <sys/scfd/scfostoescf.h>
54cfb9e062Shyw #include <sys/cpu_module.h>
55cfb9e062Shyw #include <vm/seg_kmem.h>
56cfb9e062Shyw #include <sys/vmem.h>
57cfb9e062Shyw #include <vm/hat_sfmmu.h>
58cfb9e062Shyw #include <sys/vmsystm.h>
59738dd194Shyw #include <sys/membar.h>
600b240fcdSwh31274 #include <sys/mem.h>
6125cf1a30Sjl139090
6225cf1a30Sjl139090 /*
6325cf1a30Sjl139090 * Function prototypes
6425cf1a30Sjl139090 */
6525cf1a30Sjl139090 static int mc_open(dev_t *, int, int, cred_t *);
6625cf1a30Sjl139090 static int mc_close(dev_t, int, int, cred_t *);
6725cf1a30Sjl139090 static int mc_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
6825cf1a30Sjl139090 static int mc_attach(dev_info_t *, ddi_attach_cmd_t);
6925cf1a30Sjl139090 static int mc_detach(dev_info_t *, ddi_detach_cmd_t);
7025cf1a30Sjl139090
710cc8ae86Sav145390 static int mc_poll_init(void);
720cc8ae86Sav145390 static void mc_poll_fini(void);
7325cf1a30Sjl139090 static int mc_board_add(mc_opl_t *mcp);
7425cf1a30Sjl139090 static int mc_board_del(mc_opl_t *mcp);
7525cf1a30Sjl139090 static int mc_suspend(mc_opl_t *mcp, uint32_t flag);
7625cf1a30Sjl139090 static int mc_resume(mc_opl_t *mcp, uint32_t flag);
770cc8ae86Sav145390 int opl_mc_suspend(void);
780cc8ae86Sav145390 int opl_mc_resume(void);
7925cf1a30Sjl139090
8025cf1a30Sjl139090 static void insert_mcp(mc_opl_t *mcp);
8125cf1a30Sjl139090 static void delete_mcp(mc_opl_t *mcp);
8225cf1a30Sjl139090
8325cf1a30Sjl139090 static int pa_to_maddr(mc_opl_t *mcp, uint64_t pa, mc_addr_t *maddr);
8425cf1a30Sjl139090
85738dd194Shyw static int mc_rangecheck_pa(mc_opl_t *mcp, uint64_t pa);
8625cf1a30Sjl139090
8725cf1a30Sjl139090 int mc_get_mem_unum(int, uint64_t, char *, int, int *);
880cc8ae86Sav145390 int mc_get_mem_addr(char *unum, char *sid, uint64_t offset, uint64_t *paddr);
890cc8ae86Sav145390 int mc_get_mem_offset(uint64_t paddr, uint64_t *offp);
900cc8ae86Sav145390 int mc_get_mem_sid(char *unum, char *buf, int buflen, int *lenp);
910cc8ae86Sav145390 int mc_get_mem_sid_dimm(mc_opl_t *mcp, char *dname, char *buf,
920cc8ae86Sav145390 int buflen, int *lenp);
930cc8ae86Sav145390 mc_dimm_info_t *mc_get_dimm_list(mc_opl_t *mcp);
940cc8ae86Sav145390 mc_dimm_info_t *mc_prepare_dimmlist(board_dimm_info_t *bd_dimmp);
950cc8ae86Sav145390 int mc_set_mem_sid(mc_opl_t *mcp, char *buf, int buflen, int lsb, int bank,
960cc8ae86Sav145390 uint32_t mf_type, uint32_t d_slot);
970cc8ae86Sav145390 static void mc_free_dimm_list(mc_dimm_info_t *d);
9825cf1a30Sjl139090 static void mc_get_mlist(mc_opl_t *);
990cc8ae86Sav145390 static void mc_polling(void);
1000cc8ae86Sav145390 static int mc_opl_get_physical_board(int);
1010cc8ae86Sav145390
102601c2e1eSdhain static void mc_clear_rewrite(mc_opl_t *mcp, int i);
103601c2e1eSdhain static void mc_set_rewrite(mc_opl_t *mcp, int bank, uint32_t addr, int state);
1040b240fcdSwh31274 static int mc_scf_log_event(mc_flt_page_t *flt_pag);
105601c2e1eSdhain
1060cc8ae86Sav145390 #ifdef DEBUG
1070cc8ae86Sav145390 static int mc_ioctl_debug(dev_t, int, intptr_t, int, cred_t *, int *);
1080cc8ae86Sav145390 void mc_dump_dimm(char *buf, int dnamesz, int serialsz, int partnumsz);
1090cc8ae86Sav145390 void mc_dump_dimm_info(board_dimm_info_t *bd_dimmp);
1100cc8ae86Sav145390 #endif
11125cf1a30Sjl139090
11225cf1a30Sjl139090 #pragma weak opl_get_physical_board
11325cf1a30Sjl139090 extern int opl_get_physical_board(int);
1140cc8ae86Sav145390 extern int plat_max_boards(void);
11525cf1a30Sjl139090
11625cf1a30Sjl139090 /*
11725cf1a30Sjl139090 * Configuration data structures
11825cf1a30Sjl139090 */
11925cf1a30Sjl139090 static struct cb_ops mc_cb_ops = {
12025cf1a30Sjl139090 mc_open, /* open */
12125cf1a30Sjl139090 mc_close, /* close */
12225cf1a30Sjl139090 nulldev, /* strategy */
12325cf1a30Sjl139090 nulldev, /* print */
12425cf1a30Sjl139090 nodev, /* dump */
12525cf1a30Sjl139090 nulldev, /* read */
12625cf1a30Sjl139090 nulldev, /* write */
12725cf1a30Sjl139090 mc_ioctl, /* ioctl */
12825cf1a30Sjl139090 nodev, /* devmap */
12925cf1a30Sjl139090 nodev, /* mmap */
13025cf1a30Sjl139090 nodev, /* segmap */
13125cf1a30Sjl139090 nochpoll, /* poll */
13225cf1a30Sjl139090 ddi_prop_op, /* cb_prop_op */
13325cf1a30Sjl139090 0, /* streamtab */
13425cf1a30Sjl139090 D_MP | D_NEW | D_HOTPLUG, /* Driver compatibility flag */
13525cf1a30Sjl139090 CB_REV, /* rev */
13625cf1a30Sjl139090 nodev, /* cb_aread */
13725cf1a30Sjl139090 nodev /* cb_awrite */
13825cf1a30Sjl139090 };
13925cf1a30Sjl139090
14025cf1a30Sjl139090 static struct dev_ops mc_ops = {
14125cf1a30Sjl139090 DEVO_REV, /* rev */
14225cf1a30Sjl139090 0, /* refcnt */
14325cf1a30Sjl139090 ddi_getinfo_1to1, /* getinfo */
14425cf1a30Sjl139090 nulldev, /* identify */
14525cf1a30Sjl139090 nulldev, /* probe */
14625cf1a30Sjl139090 mc_attach, /* attach */
14725cf1a30Sjl139090 mc_detach, /* detach */
14825cf1a30Sjl139090 nulldev, /* reset */
14925cf1a30Sjl139090 &mc_cb_ops, /* cb_ops */
15025cf1a30Sjl139090 (struct bus_ops *)0, /* bus_ops */
15119397407SSherry Moore nulldev, /* power */
15219397407SSherry Moore ddi_quiesce_not_needed, /* quiesce */
15325cf1a30Sjl139090 };
15425cf1a30Sjl139090
15525cf1a30Sjl139090 /*
15625cf1a30Sjl139090 * Driver globals
15725cf1a30Sjl139090 */
15825cf1a30Sjl139090
1590cc8ae86Sav145390 static enum {
16078ed97a7Sjl139090 MODEL_FF1,
16178ed97a7Sjl139090 MODEL_FF2,
16278ed97a7Sjl139090 MODEL_DC,
16378ed97a7Sjl139090 MODEL_IKKAKU
1640cc8ae86Sav145390 } plat_model = MODEL_DC; /* The default behaviour is DC */
16525cf1a30Sjl139090
1660cc8ae86Sav145390 static struct plat_model_names {
1670cc8ae86Sav145390 const char *unit_name;
1680cc8ae86Sav145390 const char *mem_name;
1690cc8ae86Sav145390 } model_names[] = {
1700cc8ae86Sav145390 { "MBU_A", "MEMB" },
1710cc8ae86Sav145390 { "MBU_B", "MEMB" },
17278ed97a7Sjl139090 { "CMU", "" },
17378ed97a7Sjl139090 { "MBU_A", "" }
1740cc8ae86Sav145390 };
1750cc8ae86Sav145390
1760cc8ae86Sav145390 /*
1770cc8ae86Sav145390 * The DIMM Names for DC platform.
1780cc8ae86Sav145390 * The index into this table is made up of (bank, dslot),
1790cc8ae86Sav145390 * Where dslot occupies bits 0-1 and bank occupies 2-4.
1800cc8ae86Sav145390 */
1810cc8ae86Sav145390 static char *mc_dc_dimm_unum_table[OPL_MAX_DIMMS] = {
1820cc8ae86Sav145390 /* --------CMUnn----------- */
1830cc8ae86Sav145390 /* --CS0-----|--CS1------ */
1840cc8ae86Sav145390 /* -H-|--L-- | -H- | -L-- */
185c964b0e6Sraghuram "03A", "02A", "03B", "02B", /* Bank 0 (MAC 0 bank 0) */
186c964b0e6Sraghuram "13A", "12A", "13B", "12B", /* Bank 1 (MAC 0 bank 1) */
187c964b0e6Sraghuram "23A", "22A", "23B", "22B", /* Bank 2 (MAC 1 bank 0) */
188c964b0e6Sraghuram "33A", "32A", "33B", "32B", /* Bank 3 (MAC 1 bank 1) */
189c964b0e6Sraghuram "01A", "00A", "01B", "00B", /* Bank 4 (MAC 2 bank 0) */
190c964b0e6Sraghuram "11A", "10A", "11B", "10B", /* Bank 5 (MAC 2 bank 1) */
191c964b0e6Sraghuram "21A", "20A", "21B", "20B", /* Bank 6 (MAC 3 bank 0) */
192c964b0e6Sraghuram "31A", "30A", "31B", "30B" /* Bank 7 (MAC 3 bank 1) */
1930cc8ae86Sav145390 };
1940cc8ae86Sav145390
1950cc8ae86Sav145390 /*
19678ed97a7Sjl139090 * The DIMM Names for FF1/FF2/IKKAKU platforms.
1970cc8ae86Sav145390 * The index into this table is made up of (board, bank, dslot),
1980cc8ae86Sav145390 * Where dslot occupies bits 0-1, bank occupies 2-4 and
1990cc8ae86Sav145390 * board occupies the bit 5.
2000cc8ae86Sav145390 */
2010cc8ae86Sav145390 static char *mc_ff_dimm_unum_table[2 * OPL_MAX_DIMMS] = {
2020cc8ae86Sav145390 /* --------CMU0---------- */
2030cc8ae86Sav145390 /* --CS0-----|--CS1------ */
2040cc8ae86Sav145390 /* -H-|--L-- | -H- | -L-- */
205c964b0e6Sraghuram "03A", "02A", "03B", "02B", /* Bank 0 (MAC 0 bank 0) */
206c964b0e6Sraghuram "01A", "00A", "01B", "00B", /* Bank 1 (MAC 0 bank 1) */
207c964b0e6Sraghuram "13A", "12A", "13B", "12B", /* Bank 2 (MAC 1 bank 0) */
208c964b0e6Sraghuram "11A", "10A", "11B", "10B", /* Bank 3 (MAC 1 bank 1) */
209c964b0e6Sraghuram "23A", "22A", "23B", "22B", /* Bank 4 (MAC 2 bank 0) */
210c964b0e6Sraghuram "21A", "20A", "21B", "20B", /* Bank 5 (MAC 2 bank 1) */
211c964b0e6Sraghuram "33A", "32A", "33B", "32B", /* Bank 6 (MAC 3 bank 0) */
212c964b0e6Sraghuram "31A", "30A", "31B", "30B", /* Bank 7 (MAC 3 bank 1) */
2130cc8ae86Sav145390 /* --------CMU1---------- */
2140cc8ae86Sav145390 /* --CS0-----|--CS1------ */
2150cc8ae86Sav145390 /* -H-|--L-- | -H- | -L-- */
216c964b0e6Sraghuram "43A", "42A", "43B", "42B", /* Bank 0 (MAC 0 bank 0) */
217c964b0e6Sraghuram "41A", "40A", "41B", "40B", /* Bank 1 (MAC 0 bank 1) */
218c964b0e6Sraghuram "53A", "52A", "53B", "52B", /* Bank 2 (MAC 1 bank 0) */
219c964b0e6Sraghuram "51A", "50A", "51B", "50B", /* Bank 3 (MAC 1 bank 1) */
220c964b0e6Sraghuram "63A", "62A", "63B", "62B", /* Bank 4 (MAC 2 bank 0) */
221c964b0e6Sraghuram "61A", "60A", "61B", "60B", /* Bank 5 (MAC 2 bank 1) */
222c964b0e6Sraghuram "73A", "72A", "73B", "72B", /* Bank 6 (MAC 3 bank 0) */
223c964b0e6Sraghuram "71A", "70A", "71B", "70B" /* Bank 7 (MAC 3 bank 1) */
2240cc8ae86Sav145390 };
2250cc8ae86Sav145390
2260cc8ae86Sav145390 #define BD_BK_SLOT_TO_INDEX(bd, bk, s) \
2270cc8ae86Sav145390 (((bd & 0x01) << 5) | ((bk & 0x07) << 2) | (s & 0x03))
2280cc8ae86Sav145390
2290cc8ae86Sav145390 #define INDEX_TO_BANK(i) (((i) & 0x1C) >> 2)
2300cc8ae86Sav145390 #define INDEX_TO_SLOT(i) ((i) & 0x03)
2310cc8ae86Sav145390
232aeb241b2Sav145390 #define SLOT_TO_CS(slot) ((slot & 0x3) >> 1)
233aeb241b2Sav145390
2340cc8ae86Sav145390 /* Isolation unit size is 64 MB */
2350cc8ae86Sav145390 #define MC_ISOLATION_BSIZE (64 * 1024 * 1024)
2360cc8ae86Sav145390
2370cc8ae86Sav145390 #define MC_MAX_SPEEDS 7
2380cc8ae86Sav145390
2390cc8ae86Sav145390 typedef struct {
2400cc8ae86Sav145390 uint32_t mc_speeds;
2410cc8ae86Sav145390 uint32_t mc_period;
2420cc8ae86Sav145390 } mc_scan_speed_t;
2430cc8ae86Sav145390
2440cc8ae86Sav145390 #define MC_CNTL_SPEED_SHIFT 26
2450cc8ae86Sav145390
24637afe445Shyw /*
24737afe445Shyw * In mirror mode, we normalized the bank idx to "even" since
24837afe445Shyw * the HW treats them as one unit w.r.t programming.
24937afe445Shyw * This bank index will be the "effective" bank index.
25037afe445Shyw * All mirrored bank state info on mc_period, mc_speedup_period
25137afe445Shyw * will be stored in the even bank structure to avoid code duplication.
25237afe445Shyw */
25337afe445Shyw #define MIRROR_IDX(bankidx) (bankidx & ~1)
25437afe445Shyw
2550cc8ae86Sav145390 static mc_scan_speed_t mc_scan_speeds[MC_MAX_SPEEDS] = {
2560cc8ae86Sav145390 {0x6 << MC_CNTL_SPEED_SHIFT, 0},
2570cc8ae86Sav145390 {0x5 << MC_CNTL_SPEED_SHIFT, 32},
2580cc8ae86Sav145390 {0x4 << MC_CNTL_SPEED_SHIFT, 64},
2590cc8ae86Sav145390 {0x3 << MC_CNTL_SPEED_SHIFT, 128},
2600cc8ae86Sav145390 {0x2 << MC_CNTL_SPEED_SHIFT, 256},
2610cc8ae86Sav145390 {0x1 << MC_CNTL_SPEED_SHIFT, 512},
2620cc8ae86Sav145390 {0x0 << MC_CNTL_SPEED_SHIFT, 1024}
2630cc8ae86Sav145390 };
2640cc8ae86Sav145390
2650cc8ae86Sav145390 static uint32_t mc_max_speed = (0x6 << 26);
2660cc8ae86Sav145390
2670cc8ae86Sav145390 int mc_isolation_bsize = MC_ISOLATION_BSIZE;
2680cc8ae86Sav145390 int mc_patrol_interval_sec = MC_PATROL_INTERVAL_SEC;
2690cc8ae86Sav145390 int mc_max_scf_retry = 16;
2700cc8ae86Sav145390 int mc_max_scf_logs = 64;
2710cc8ae86Sav145390 int mc_max_errlog_processed = BANKNUM_PER_SB*2;
2720cc8ae86Sav145390 int mc_scan_period = 12 * 60 * 60; /* 12 hours period */
2730cc8ae86Sav145390 int mc_max_rewrite_loop = 100;
2740cc8ae86Sav145390 int mc_rewrite_delay = 10;
2750cc8ae86Sav145390 /*
2760cc8ae86Sav145390 * it takes SCF about 300 m.s. to process a requst. We can bail out
2770cc8ae86Sav145390 * if it is busy. It does not pay to wait for it too long.
2780cc8ae86Sav145390 */
2790cc8ae86Sav145390 int mc_max_scf_loop = 2;
2800cc8ae86Sav145390 int mc_scf_delay = 100;
2810cc8ae86Sav145390 int mc_pce_dropped = 0;
2820cc8ae86Sav145390 int mc_poll_priority = MINCLSYSPRI;
283601c2e1eSdhain int mc_max_rewrite_retry = 6 * 60;
2840cc8ae86Sav145390
2850cc8ae86Sav145390
2860cc8ae86Sav145390 /*
2871039f409Sav145390 * Mutex hierarchy in mc-opl
2880cc8ae86Sav145390 * If both mcmutex and mc_lock must be held,
2890cc8ae86Sav145390 * mcmutex must be acquired first, and then mc_lock.
2900cc8ae86Sav145390 */
2910cc8ae86Sav145390
29225cf1a30Sjl139090 static kmutex_t mcmutex;
2930cc8ae86Sav145390 mc_opl_t *mc_instances[OPL_MAX_BOARDS];
29425cf1a30Sjl139090
2950cc8ae86Sav145390 static kmutex_t mc_polling_lock;
2960cc8ae86Sav145390 static kcondvar_t mc_polling_cv;
2970cc8ae86Sav145390 static kcondvar_t mc_poll_exit_cv;
2980cc8ae86Sav145390 static int mc_poll_cmd = 0;
2990cc8ae86Sav145390 static int mc_pollthr_running = 0;
3000cc8ae86Sav145390 int mc_timeout_period = 0; /* this is in m.s. */
30125cf1a30Sjl139090 void *mc_statep;
30225cf1a30Sjl139090
30325cf1a30Sjl139090 #ifdef DEBUG
3042742aa22Shyw int oplmc_debug = 0;
30525cf1a30Sjl139090 #endif
30625cf1a30Sjl139090
3070cc8ae86Sav145390 static int mc_debug_show_all = 0;
30825cf1a30Sjl139090
30925cf1a30Sjl139090 extern struct mod_ops mod_driverops;
31025cf1a30Sjl139090
31125cf1a30Sjl139090 static struct modldrv modldrv = {
31225cf1a30Sjl139090 &mod_driverops, /* module type, this one is a driver */
31319397407SSherry Moore "OPL Memory-controller", /* module name */
31425cf1a30Sjl139090 &mc_ops, /* driver ops */
31525cf1a30Sjl139090 };
31625cf1a30Sjl139090
31725cf1a30Sjl139090 static struct modlinkage modlinkage = {
31825cf1a30Sjl139090 MODREV_1, /* rev */
31925cf1a30Sjl139090 (void *)&modldrv,
32025cf1a30Sjl139090 NULL
32125cf1a30Sjl139090 };
32225cf1a30Sjl139090
32325cf1a30Sjl139090 #pragma weak opl_get_mem_unum
3240cc8ae86Sav145390 #pragma weak opl_get_mem_sid
3250cc8ae86Sav145390 #pragma weak opl_get_mem_offset
3260cc8ae86Sav145390 #pragma weak opl_get_mem_addr
3270cc8ae86Sav145390
32825cf1a30Sjl139090 extern int (*opl_get_mem_unum)(int, uint64_t, char *, int, int *);
3290cc8ae86Sav145390 extern int (*opl_get_mem_sid)(char *unum, char *buf, int buflen, int *lenp);
3300cc8ae86Sav145390 extern int (*opl_get_mem_offset)(uint64_t paddr, uint64_t *offp);
3310cc8ae86Sav145390 extern int (*opl_get_mem_addr)(char *unum, char *sid, uint64_t offset,
3320cc8ae86Sav145390 uint64_t *paddr);
3330cc8ae86Sav145390
33425cf1a30Sjl139090
33525cf1a30Sjl139090 /*
33625cf1a30Sjl139090 * pseudo-mc node portid format
33725cf1a30Sjl139090 *
33825cf1a30Sjl139090 * [10] = 0
33925cf1a30Sjl139090 * [9] = 1
34025cf1a30Sjl139090 * [8] = LSB_ID[4] = 0
34125cf1a30Sjl139090 * [7:4] = LSB_ID[3:0]
34225cf1a30Sjl139090 * [3:0] = 0
34325cf1a30Sjl139090 *
34425cf1a30Sjl139090 */
34525cf1a30Sjl139090
34625cf1a30Sjl139090 /*
34725cf1a30Sjl139090 * These are the module initialization routines.
34825cf1a30Sjl139090 */
34925cf1a30Sjl139090 int
_init(void)35025cf1a30Sjl139090 _init(void)
35125cf1a30Sjl139090 {
35225cf1a30Sjl139090 int error;
3530cc8ae86Sav145390 int plen;
3540cc8ae86Sav145390 char model[20];
3550cc8ae86Sav145390 pnode_t node;
35625cf1a30Sjl139090
35725cf1a30Sjl139090
35825cf1a30Sjl139090 if ((error = ddi_soft_state_init(&mc_statep,
35925cf1a30Sjl139090 sizeof (mc_opl_t), 1)) != 0)
36025cf1a30Sjl139090 return (error);
36125cf1a30Sjl139090
3620cc8ae86Sav145390 if ((error = mc_poll_init()) != 0) {
3630cc8ae86Sav145390 ddi_soft_state_fini(&mc_statep);
3640cc8ae86Sav145390 return (error);
3650cc8ae86Sav145390 }
3660cc8ae86Sav145390
36725cf1a30Sjl139090 mutex_init(&mcmutex, NULL, MUTEX_DRIVER, NULL);
36825cf1a30Sjl139090 if (&opl_get_mem_unum)
36925cf1a30Sjl139090 opl_get_mem_unum = mc_get_mem_unum;
3700cc8ae86Sav145390 if (&opl_get_mem_sid)
3710cc8ae86Sav145390 opl_get_mem_sid = mc_get_mem_sid;
3720cc8ae86Sav145390 if (&opl_get_mem_offset)
3730cc8ae86Sav145390 opl_get_mem_offset = mc_get_mem_offset;
3740cc8ae86Sav145390 if (&opl_get_mem_addr)
3750cc8ae86Sav145390 opl_get_mem_addr = mc_get_mem_addr;
3760cc8ae86Sav145390
3770cc8ae86Sav145390 node = prom_rootnode();
3780cc8ae86Sav145390 plen = prom_getproplen(node, "model");
3790cc8ae86Sav145390
3800cc8ae86Sav145390 if (plen > 0 && plen < sizeof (model)) {
3810cc8ae86Sav145390 (void) prom_getprop(node, "model", model);
3820cc8ae86Sav145390 model[plen] = '\0';
3830cc8ae86Sav145390 if (strcmp(model, "FF1") == 0)
3840cc8ae86Sav145390 plat_model = MODEL_FF1;
3850cc8ae86Sav145390 else if (strcmp(model, "FF2") == 0)
3860cc8ae86Sav145390 plat_model = MODEL_FF2;
3870cc8ae86Sav145390 else if (strncmp(model, "DC", 2) == 0)
3880cc8ae86Sav145390 plat_model = MODEL_DC;
38978ed97a7Sjl139090 else if (strcmp(model, "IKKAKU") == 0)
39078ed97a7Sjl139090 plat_model = MODEL_IKKAKU;
3910cc8ae86Sav145390 }
39225cf1a30Sjl139090
39325cf1a30Sjl139090 error = mod_install(&modlinkage);
39425cf1a30Sjl139090 if (error != 0) {
39525cf1a30Sjl139090 if (&opl_get_mem_unum)
39625cf1a30Sjl139090 opl_get_mem_unum = NULL;
3970cc8ae86Sav145390 if (&opl_get_mem_sid)
3980cc8ae86Sav145390 opl_get_mem_sid = NULL;
3990cc8ae86Sav145390 if (&opl_get_mem_offset)
4000cc8ae86Sav145390 opl_get_mem_offset = NULL;
4010cc8ae86Sav145390 if (&opl_get_mem_addr)
4020cc8ae86Sav145390 opl_get_mem_addr = NULL;
40325cf1a30Sjl139090 mutex_destroy(&mcmutex);
4040cc8ae86Sav145390 mc_poll_fini();
40525cf1a30Sjl139090 ddi_soft_state_fini(&mc_statep);
40625cf1a30Sjl139090 }
40725cf1a30Sjl139090 return (error);
40825cf1a30Sjl139090 }
40925cf1a30Sjl139090
41025cf1a30Sjl139090 int
_fini(void)41125cf1a30Sjl139090 _fini(void)
41225cf1a30Sjl139090 {
41325cf1a30Sjl139090 int error;
41425cf1a30Sjl139090
41525cf1a30Sjl139090 if ((error = mod_remove(&modlinkage)) != 0)
41625cf1a30Sjl139090 return (error);
41725cf1a30Sjl139090
41825cf1a30Sjl139090 if (&opl_get_mem_unum)
41925cf1a30Sjl139090 opl_get_mem_unum = NULL;
4200cc8ae86Sav145390 if (&opl_get_mem_sid)
4210cc8ae86Sav145390 opl_get_mem_sid = NULL;
4220cc8ae86Sav145390 if (&opl_get_mem_offset)
4230cc8ae86Sav145390 opl_get_mem_offset = NULL;
4240cc8ae86Sav145390 if (&opl_get_mem_addr)
4250cc8ae86Sav145390 opl_get_mem_addr = NULL;
42625cf1a30Sjl139090
4270cc8ae86Sav145390 mutex_destroy(&mcmutex);
4280cc8ae86Sav145390 mc_poll_fini();
42925cf1a30Sjl139090 ddi_soft_state_fini(&mc_statep);
43025cf1a30Sjl139090
43125cf1a30Sjl139090 return (0);
43225cf1a30Sjl139090 }
43325cf1a30Sjl139090
43425cf1a30Sjl139090 int
_info(struct modinfo * modinfop)43525cf1a30Sjl139090 _info(struct modinfo *modinfop)
43625cf1a30Sjl139090 {
43725cf1a30Sjl139090 return (mod_info(&modlinkage, modinfop));
43825cf1a30Sjl139090 }
43925cf1a30Sjl139090
4400cc8ae86Sav145390 static void
mc_polling_thread()4410cc8ae86Sav145390 mc_polling_thread()
4420cc8ae86Sav145390 {
4430cc8ae86Sav145390 mutex_enter(&mc_polling_lock);
4440cc8ae86Sav145390 mc_pollthr_running = 1;
4450cc8ae86Sav145390 while (!(mc_poll_cmd & MC_POLL_EXIT)) {
4460cc8ae86Sav145390 mc_polling();
44707d06da5SSurya Prakki (void) cv_reltimedwait(&mc_polling_cv, &mc_polling_lock,
448d3d50737SRafael Vanoni mc_timeout_period, TR_CLOCK_TICK);
4490cc8ae86Sav145390 }
4500cc8ae86Sav145390 mc_pollthr_running = 0;
4510cc8ae86Sav145390
4520cc8ae86Sav145390 /*
4530cc8ae86Sav145390 * signal if any one is waiting for this thread to exit.
4540cc8ae86Sav145390 */
4550cc8ae86Sav145390 cv_signal(&mc_poll_exit_cv);
4560cc8ae86Sav145390 mutex_exit(&mc_polling_lock);
4570cc8ae86Sav145390 thread_exit();
4580cc8ae86Sav145390 /* NOTREACHED */
4590cc8ae86Sav145390 }
4600cc8ae86Sav145390
4610cc8ae86Sav145390 static int
mc_poll_init()4620cc8ae86Sav145390 mc_poll_init()
4630cc8ae86Sav145390 {
4640cc8ae86Sav145390 mutex_init(&mc_polling_lock, NULL, MUTEX_DRIVER, NULL);
4650cc8ae86Sav145390 cv_init(&mc_polling_cv, NULL, CV_DRIVER, NULL);
4660cc8ae86Sav145390 cv_init(&mc_poll_exit_cv, NULL, CV_DRIVER, NULL);
4670cc8ae86Sav145390 return (0);
4680cc8ae86Sav145390 }
4690cc8ae86Sav145390
4700cc8ae86Sav145390 static void
mc_poll_fini()4710cc8ae86Sav145390 mc_poll_fini()
4720cc8ae86Sav145390 {
4730cc8ae86Sav145390 mutex_enter(&mc_polling_lock);
4740cc8ae86Sav145390 if (mc_pollthr_running) {
4750cc8ae86Sav145390 mc_poll_cmd = MC_POLL_EXIT;
4760cc8ae86Sav145390 cv_signal(&mc_polling_cv);
4770cc8ae86Sav145390 while (mc_pollthr_running) {
4780cc8ae86Sav145390 cv_wait(&mc_poll_exit_cv, &mc_polling_lock);
4790cc8ae86Sav145390 }
4800cc8ae86Sav145390 }
4810cc8ae86Sav145390 mutex_exit(&mc_polling_lock);
4820cc8ae86Sav145390 mutex_destroy(&mc_polling_lock);
4830cc8ae86Sav145390 cv_destroy(&mc_polling_cv);
4840cc8ae86Sav145390 cv_destroy(&mc_poll_exit_cv);
4850cc8ae86Sav145390 }
4860cc8ae86Sav145390
48725cf1a30Sjl139090 static int
mc_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)48825cf1a30Sjl139090 mc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
48925cf1a30Sjl139090 {
49025cf1a30Sjl139090 mc_opl_t *mcp;
49125cf1a30Sjl139090 int instance;
4920cc8ae86Sav145390 int rv;
49325cf1a30Sjl139090
49425cf1a30Sjl139090 /* get the instance of this devi */
49525cf1a30Sjl139090 instance = ddi_get_instance(devi);
49625cf1a30Sjl139090
49725cf1a30Sjl139090 switch (cmd) {
49825cf1a30Sjl139090 case DDI_ATTACH:
49925cf1a30Sjl139090 break;
50025cf1a30Sjl139090 case DDI_RESUME:
50125cf1a30Sjl139090 mcp = ddi_get_soft_state(mc_statep, instance);
5020cc8ae86Sav145390 rv = mc_resume(mcp, MC_DRIVER_SUSPENDED);
5030cc8ae86Sav145390 return (rv);
50425cf1a30Sjl139090 default:
50525cf1a30Sjl139090 return (DDI_FAILURE);
50625cf1a30Sjl139090 }
50725cf1a30Sjl139090
50825cf1a30Sjl139090 if (ddi_soft_state_zalloc(mc_statep, instance) != DDI_SUCCESS)
50925cf1a30Sjl139090 return (DDI_FAILURE);
51025cf1a30Sjl139090
5110b240fcdSwh31274 if (ddi_create_minor_node(devi, "mc-opl", S_IFCHR, instance,
5120b240fcdSwh31274 "ddi_mem_ctrl", 0) != DDI_SUCCESS) {
5130b240fcdSwh31274 MC_LOG("mc_attach: create_minor_node failed\n");
5140b240fcdSwh31274 return (DDI_FAILURE);
5150b240fcdSwh31274 }
5160b240fcdSwh31274
51725cf1a30Sjl139090 if ((mcp = ddi_get_soft_state(mc_statep, instance)) == NULL) {
51825cf1a30Sjl139090 goto bad;
51925cf1a30Sjl139090 }
52025cf1a30Sjl139090
5210cc8ae86Sav145390 if (mc_timeout_period == 0) {
5220cc8ae86Sav145390 mc_patrol_interval_sec = (int)ddi_getprop(DDI_DEV_T_ANY, devi,
5230cc8ae86Sav145390 DDI_PROP_DONTPASS, "mc-timeout-interval-sec",
5240cc8ae86Sav145390 mc_patrol_interval_sec);
525d8a0cca9Swh31274 mc_timeout_period = drv_usectohz(1000000 *
526d8a0cca9Swh31274 mc_patrol_interval_sec / OPL_MAX_BOARDS);
5270cc8ae86Sav145390 }
5280cc8ae86Sav145390
52925cf1a30Sjl139090 /* set informations in mc state */
53025cf1a30Sjl139090 mcp->mc_dip = devi;
53125cf1a30Sjl139090
53225cf1a30Sjl139090 if (mc_board_add(mcp))
53325cf1a30Sjl139090 goto bad;
53425cf1a30Sjl139090
53525cf1a30Sjl139090 insert_mcp(mcp);
5360cc8ae86Sav145390
5370cc8ae86Sav145390 /*
5380cc8ae86Sav145390 * Start the polling thread if it is not running already.
5390cc8ae86Sav145390 */
5400cc8ae86Sav145390 mutex_enter(&mc_polling_lock);
5410cc8ae86Sav145390 if (!mc_pollthr_running) {
5420cc8ae86Sav145390 (void) thread_create(NULL, 0, (void (*)())mc_polling_thread,
5430cc8ae86Sav145390 NULL, 0, &p0, TS_RUN, mc_poll_priority);
5440cc8ae86Sav145390 }
5450cc8ae86Sav145390 mutex_exit(&mc_polling_lock);
54625cf1a30Sjl139090 ddi_report_dev(devi);
54725cf1a30Sjl139090
54825cf1a30Sjl139090 return (DDI_SUCCESS);
54925cf1a30Sjl139090
55025cf1a30Sjl139090 bad:
5510b240fcdSwh31274 ddi_remove_minor_node(devi, NULL);
55225cf1a30Sjl139090 ddi_soft_state_free(mc_statep, instance);
55325cf1a30Sjl139090 return (DDI_FAILURE);
55425cf1a30Sjl139090 }
55525cf1a30Sjl139090
55625cf1a30Sjl139090 /* ARGSUSED */
55725cf1a30Sjl139090 static int
mc_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)55825cf1a30Sjl139090 mc_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
55925cf1a30Sjl139090 {
5600cc8ae86Sav145390 int rv;
56125cf1a30Sjl139090 int instance;
56225cf1a30Sjl139090 mc_opl_t *mcp;
56325cf1a30Sjl139090
56425cf1a30Sjl139090 /* get the instance of this devi */
56525cf1a30Sjl139090 instance = ddi_get_instance(devi);
56625cf1a30Sjl139090 if ((mcp = ddi_get_soft_state(mc_statep, instance)) == NULL) {
56725cf1a30Sjl139090 return (DDI_FAILURE);
56825cf1a30Sjl139090 }
56925cf1a30Sjl139090
57025cf1a30Sjl139090 switch (cmd) {
57125cf1a30Sjl139090 case DDI_SUSPEND:
5720cc8ae86Sav145390 rv = mc_suspend(mcp, MC_DRIVER_SUSPENDED);
5730cc8ae86Sav145390 return (rv);
57425cf1a30Sjl139090 case DDI_DETACH:
57525cf1a30Sjl139090 break;
57625cf1a30Sjl139090 default:
57725cf1a30Sjl139090 return (DDI_FAILURE);
57825cf1a30Sjl139090 }
57925cf1a30Sjl139090
5800cc8ae86Sav145390 delete_mcp(mcp);
58125cf1a30Sjl139090 if (mc_board_del(mcp) != DDI_SUCCESS) {
58225cf1a30Sjl139090 return (DDI_FAILURE);
58325cf1a30Sjl139090 }
58425cf1a30Sjl139090
5850b240fcdSwh31274 ddi_remove_minor_node(devi, NULL);
5860b240fcdSwh31274
58725cf1a30Sjl139090 /* free up the soft state */
58825cf1a30Sjl139090 ddi_soft_state_free(mc_statep, instance);
58925cf1a30Sjl139090
59025cf1a30Sjl139090 return (DDI_SUCCESS);
59125cf1a30Sjl139090 }
59225cf1a30Sjl139090
59325cf1a30Sjl139090 /* ARGSUSED */
59425cf1a30Sjl139090 static int
mc_open(dev_t * devp,int flag,int otyp,cred_t * credp)59525cf1a30Sjl139090 mc_open(dev_t *devp, int flag, int otyp, cred_t *credp)
59625cf1a30Sjl139090 {
59725cf1a30Sjl139090 return (0);
59825cf1a30Sjl139090 }
59925cf1a30Sjl139090
60025cf1a30Sjl139090 /* ARGSUSED */
60125cf1a30Sjl139090 static int
mc_close(dev_t devp,int flag,int otyp,cred_t * credp)60225cf1a30Sjl139090 mc_close(dev_t devp, int flag, int otyp, cred_t *credp)
60325cf1a30Sjl139090 {
60425cf1a30Sjl139090 return (0);
60525cf1a30Sjl139090 }
60625cf1a30Sjl139090
60725cf1a30Sjl139090 /* ARGSUSED */
60825cf1a30Sjl139090 static int
mc_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)60925cf1a30Sjl139090 mc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
61025cf1a30Sjl139090 int *rvalp)
61125cf1a30Sjl139090 {
6120b240fcdSwh31274 mc_flt_page_t flt_page;
6130b240fcdSwh31274
6140b240fcdSwh31274 if (cmd == MCIOC_FAULT_PAGE) {
6150b240fcdSwh31274 if (arg == NULL)
6160b240fcdSwh31274 return (EINVAL);
6170b240fcdSwh31274
6180b240fcdSwh31274 if (ddi_copyin((const void *)arg, (void *)&flt_page,
6190b240fcdSwh31274 sizeof (mc_flt_page_t), 0) < 0)
6200b240fcdSwh31274 return (EFAULT);
6210b240fcdSwh31274
6220b240fcdSwh31274 return (mc_scf_log_event(&flt_page));
6230b240fcdSwh31274 }
6240cc8ae86Sav145390 #ifdef DEBUG
6250cc8ae86Sav145390 return (mc_ioctl_debug(dev, cmd, arg, mode, credp, rvalp));
6260cc8ae86Sav145390 #else
6270b240fcdSwh31274 return (ENOTTY);
6280cc8ae86Sav145390 #endif
62925cf1a30Sjl139090 }
63025cf1a30Sjl139090
63125cf1a30Sjl139090 /*
63225cf1a30Sjl139090 * PA validity check:
633738dd194Shyw * This function return 1 if the PA is a valid PA
634738dd194Shyw * in the running Solaris instance i.e. in physinstall
635738dd194Shyw * Otherwise, return 0.
63625cf1a30Sjl139090 */
63725cf1a30Sjl139090
63825cf1a30Sjl139090 /* ARGSUSED */
63925cf1a30Sjl139090 static int
pa_is_valid(mc_opl_t * mcp,uint64_t addr)64025cf1a30Sjl139090 pa_is_valid(mc_opl_t *mcp, uint64_t addr)
64125cf1a30Sjl139090 {
64225cf1a30Sjl139090 if (mcp->mlist == NULL)
64325cf1a30Sjl139090 mc_get_mlist(mcp);
64425cf1a30Sjl139090
64525cf1a30Sjl139090 if (mcp->mlist && address_in_memlist(mcp->mlist, addr, 0)) {
64625cf1a30Sjl139090 return (1);
64725cf1a30Sjl139090 }
64825cf1a30Sjl139090 return (0);
64925cf1a30Sjl139090 }
65025cf1a30Sjl139090
65125cf1a30Sjl139090 /*
65225cf1a30Sjl139090 * mac-pa translation routines.
65325cf1a30Sjl139090 *
65425cf1a30Sjl139090 * Input: mc driver state, (LSB#, Bank#, DIMM address)
65525cf1a30Sjl139090 * Output: physical address
65625cf1a30Sjl139090 *
65725cf1a30Sjl139090 * Valid - return value: 0
65825cf1a30Sjl139090 * Invalid - return value: -1
65925cf1a30Sjl139090 */
66025cf1a30Sjl139090 static int
mcaddr_to_pa(mc_opl_t * mcp,mc_addr_t * maddr,uint64_t * pa)66125cf1a30Sjl139090 mcaddr_to_pa(mc_opl_t *mcp, mc_addr_t *maddr, uint64_t *pa)
66225cf1a30Sjl139090 {
66325cf1a30Sjl139090 int i;
66425cf1a30Sjl139090 uint64_t pa_offset = 0;
66525cf1a30Sjl139090 int cs = (maddr->ma_dimm_addr >> CS_SHIFT) & 1;
66625cf1a30Sjl139090 int bank = maddr->ma_bank;
66725cf1a30Sjl139090 mc_addr_t maddr1;
66825cf1a30Sjl139090 int bank0, bank1;
66925cf1a30Sjl139090
67025cf1a30Sjl139090 MC_LOG("mcaddr /LSB%d/B%d/%x\n", maddr->ma_bd, bank,
67125cf1a30Sjl139090 maddr->ma_dimm_addr);
67225cf1a30Sjl139090
67325cf1a30Sjl139090 /* loc validity check */
67425cf1a30Sjl139090 ASSERT(maddr->ma_bd >= 0 && OPL_BOARD_MAX > maddr->ma_bd);
67525cf1a30Sjl139090 ASSERT(bank >= 0 && OPL_BANK_MAX > bank);
67625cf1a30Sjl139090
67725cf1a30Sjl139090 /* Do translation */
67825cf1a30Sjl139090 for (i = 0; i < PA_BITS_FOR_MAC; i++) {
67925cf1a30Sjl139090 int pa_bit = 0;
68025cf1a30Sjl139090 int mc_bit = mcp->mc_trans_table[cs][i];
68125cf1a30Sjl139090 if (mc_bit < MC_ADDRESS_BITS) {
68225cf1a30Sjl139090 pa_bit = (maddr->ma_dimm_addr >> mc_bit) & 1;
68325cf1a30Sjl139090 } else if (mc_bit == MP_NONE) {
68425cf1a30Sjl139090 pa_bit = 0;
68525cf1a30Sjl139090 } else if (mc_bit == MP_BANK_0) {
68625cf1a30Sjl139090 pa_bit = bank & 1;
68725cf1a30Sjl139090 } else if (mc_bit == MP_BANK_1) {
68825cf1a30Sjl139090 pa_bit = (bank >> 1) & 1;
68925cf1a30Sjl139090 } else if (mc_bit == MP_BANK_2) {
69025cf1a30Sjl139090 pa_bit = (bank >> 2) & 1;
69125cf1a30Sjl139090 }
69225cf1a30Sjl139090 pa_offset |= ((uint64_t)pa_bit) << i;
69325cf1a30Sjl139090 }
69425cf1a30Sjl139090 *pa = mcp->mc_start_address + pa_offset;
69525cf1a30Sjl139090 MC_LOG("pa = %lx\n", *pa);
69625cf1a30Sjl139090
69725cf1a30Sjl139090 if (pa_to_maddr(mcp, *pa, &maddr1) == -1) {
6980cc8ae86Sav145390 cmn_err(CE_WARN, "mcaddr_to_pa: /LSB%d/B%d/%x failed to "
6990cc8ae86Sav145390 "convert PA %lx\n", maddr->ma_bd, bank,
7000cc8ae86Sav145390 maddr->ma_dimm_addr, *pa);
70125cf1a30Sjl139090 return (-1);
70225cf1a30Sjl139090 }
70325cf1a30Sjl139090
7040cc8ae86Sav145390 /*
7050cc8ae86Sav145390 * In mirror mode, PA is always translated to the even bank.
7060cc8ae86Sav145390 */
70725cf1a30Sjl139090 if (IS_MIRROR(mcp, maddr->ma_bank)) {
70825cf1a30Sjl139090 bank0 = maddr->ma_bank & ~(1);
70925cf1a30Sjl139090 bank1 = maddr1.ma_bank & ~(1);
71025cf1a30Sjl139090 } else {
71125cf1a30Sjl139090 bank0 = maddr->ma_bank;
71225cf1a30Sjl139090 bank1 = maddr1.ma_bank;
71325cf1a30Sjl139090 }
71425cf1a30Sjl139090 /*
71525cf1a30Sjl139090 * there is no need to check ma_bd because it is generated from
71625cf1a30Sjl139090 * mcp. They are the same.
71725cf1a30Sjl139090 */
718d8a0cca9Swh31274 if ((bank0 == bank1) && (maddr->ma_dimm_addr ==
719d8a0cca9Swh31274 maddr1.ma_dimm_addr)) {
72025cf1a30Sjl139090 return (0);
72125cf1a30Sjl139090 } else {
7220b240fcdSwh31274 MC_LOG("Translation error source /LSB%d/B%d/%x, "
723d8a0cca9Swh31274 "PA %lx, target /LSB%d/B%d/%x\n", maddr->ma_bd, bank,
724d8a0cca9Swh31274 maddr->ma_dimm_addr, *pa, maddr1.ma_bd, maddr1.ma_bank,
72525cf1a30Sjl139090 maddr1.ma_dimm_addr);
72625cf1a30Sjl139090 return (-1);
72725cf1a30Sjl139090 }
72825cf1a30Sjl139090 }
72925cf1a30Sjl139090
73025cf1a30Sjl139090 /*
73125cf1a30Sjl139090 * PA to CS (used by pa_to_maddr).
73225cf1a30Sjl139090 */
73325cf1a30Sjl139090 static int
pa_to_cs(mc_opl_t * mcp,uint64_t pa_offset)73425cf1a30Sjl139090 pa_to_cs(mc_opl_t *mcp, uint64_t pa_offset)
73525cf1a30Sjl139090 {
73625cf1a30Sjl139090 int i;
737738dd194Shyw int cs = 1;
73825cf1a30Sjl139090
73925cf1a30Sjl139090 for (i = 0; i < PA_BITS_FOR_MAC; i++) {
74025cf1a30Sjl139090 /* MAC address bit<29> is arranged on the same PA bit */
74125cf1a30Sjl139090 /* on both table. So we may use any table. */
74225cf1a30Sjl139090 if (mcp->mc_trans_table[0][i] == CS_SHIFT) {
74325cf1a30Sjl139090 cs = (pa_offset >> i) & 1;
74425cf1a30Sjl139090 break;
74525cf1a30Sjl139090 }
74625cf1a30Sjl139090 }
74725cf1a30Sjl139090 return (cs);
74825cf1a30Sjl139090 }
74925cf1a30Sjl139090
75025cf1a30Sjl139090 /*
75125cf1a30Sjl139090 * PA to DIMM (used by pa_to_maddr).
75225cf1a30Sjl139090 */
75325cf1a30Sjl139090 /* ARGSUSED */
75425cf1a30Sjl139090 static uint32_t
pa_to_dimm(mc_opl_t * mcp,uint64_t pa_offset)75525cf1a30Sjl139090 pa_to_dimm(mc_opl_t *mcp, uint64_t pa_offset)
75625cf1a30Sjl139090 {
75725cf1a30Sjl139090 int i;
75825cf1a30Sjl139090 int cs = pa_to_cs(mcp, pa_offset);
75925cf1a30Sjl139090 uint32_t dimm_addr = 0;
76025cf1a30Sjl139090
76125cf1a30Sjl139090 for (i = 0; i < PA_BITS_FOR_MAC; i++) {
76225cf1a30Sjl139090 int pa_bit_value = (pa_offset >> i) & 1;
76325cf1a30Sjl139090 int mc_bit = mcp->mc_trans_table[cs][i];
76425cf1a30Sjl139090 if (mc_bit < MC_ADDRESS_BITS) {
76525cf1a30Sjl139090 dimm_addr |= pa_bit_value << mc_bit;
76625cf1a30Sjl139090 }
76725cf1a30Sjl139090 }
768738dd194Shyw dimm_addr |= cs << CS_SHIFT;
76925cf1a30Sjl139090 return (dimm_addr);
77025cf1a30Sjl139090 }
77125cf1a30Sjl139090
77225cf1a30Sjl139090 /*
77325cf1a30Sjl139090 * PA to Bank (used by pa_to_maddr).
77425cf1a30Sjl139090 */
77525cf1a30Sjl139090 static int
pa_to_bank(mc_opl_t * mcp,uint64_t pa_offset)77625cf1a30Sjl139090 pa_to_bank(mc_opl_t *mcp, uint64_t pa_offset)
77725cf1a30Sjl139090 {
77825cf1a30Sjl139090 int i;
77925cf1a30Sjl139090 int cs = pa_to_cs(mcp, pa_offset);
78025cf1a30Sjl139090 int bankno = mcp->mc_trans_table[cs][INDEX_OF_BANK_SUPPLEMENT_BIT];
78125cf1a30Sjl139090
78225cf1a30Sjl139090
78325cf1a30Sjl139090 for (i = 0; i < PA_BITS_FOR_MAC; i++) {
78425cf1a30Sjl139090 int pa_bit_value = (pa_offset >> i) & 1;
78525cf1a30Sjl139090 int mc_bit = mcp->mc_trans_table[cs][i];
78625cf1a30Sjl139090 switch (mc_bit) {
78725cf1a30Sjl139090 case MP_BANK_0:
78825cf1a30Sjl139090 bankno |= pa_bit_value;
78925cf1a30Sjl139090 break;
79025cf1a30Sjl139090 case MP_BANK_1:
79125cf1a30Sjl139090 bankno |= pa_bit_value << 1;
79225cf1a30Sjl139090 break;
79325cf1a30Sjl139090 case MP_BANK_2:
79425cf1a30Sjl139090 bankno |= pa_bit_value << 2;
79525cf1a30Sjl139090 break;
79625cf1a30Sjl139090 }
79725cf1a30Sjl139090 }
79825cf1a30Sjl139090
79925cf1a30Sjl139090 return (bankno);
80025cf1a30Sjl139090 }
80125cf1a30Sjl139090
80225cf1a30Sjl139090 /*
80325cf1a30Sjl139090 * PA to MAC address translation
80425cf1a30Sjl139090 *
80525cf1a30Sjl139090 * Input: MAC driver state, physicall adress
80625cf1a30Sjl139090 * Output: LSB#, Bank id, mac address
80725cf1a30Sjl139090 *
80825cf1a30Sjl139090 * Valid - return value: 0
80925cf1a30Sjl139090 * Invalid - return value: -1
81025cf1a30Sjl139090 */
81125cf1a30Sjl139090
81225cf1a30Sjl139090 int
pa_to_maddr(mc_opl_t * mcp,uint64_t pa,mc_addr_t * maddr)81325cf1a30Sjl139090 pa_to_maddr(mc_opl_t *mcp, uint64_t pa, mc_addr_t *maddr)
81425cf1a30Sjl139090 {
81525cf1a30Sjl139090 uint64_t pa_offset;
81625cf1a30Sjl139090
817738dd194Shyw if (!mc_rangecheck_pa(mcp, pa))
81825cf1a30Sjl139090 return (-1);
81925cf1a30Sjl139090
82025cf1a30Sjl139090 /* Do translation */
82125cf1a30Sjl139090 pa_offset = pa - mcp->mc_start_address;
82225cf1a30Sjl139090
82325cf1a30Sjl139090 maddr->ma_bd = mcp->mc_board_num;
824aeb241b2Sav145390 maddr->ma_phys_bd = mcp->mc_phys_board_num;
82525cf1a30Sjl139090 maddr->ma_bank = pa_to_bank(mcp, pa_offset);
82625cf1a30Sjl139090 maddr->ma_dimm_addr = pa_to_dimm(mcp, pa_offset);
827d8a0cca9Swh31274 MC_LOG("pa %lx -> mcaddr /LSB%d/B%d/%x\n", pa_offset, maddr->ma_bd,
828d8a0cca9Swh31274 maddr->ma_bank, maddr->ma_dimm_addr);
82925cf1a30Sjl139090 return (0);
83025cf1a30Sjl139090 }
83125cf1a30Sjl139090
8320cc8ae86Sav145390 /*
8330cc8ae86Sav145390 * UNUM format for DC is "/CMUnn/MEMxyZ", where
8340cc8ae86Sav145390 * nn = 00..03 for DC1 and 00..07 for DC2 and 00..15 for DC3.
8350cc8ae86Sav145390 * x = MAC 0..3
8360cc8ae86Sav145390 * y = 0..3 (slot info).
8370cc8ae86Sav145390 * Z = 'A' or 'B'
8380cc8ae86Sav145390 *
8390cc8ae86Sav145390 * UNUM format for FF1 is "/MBU_A/MEMBx/MEMyZ", where
8400cc8ae86Sav145390 * x = 0..3 (MEMB number)
8410cc8ae86Sav145390 * y = 0..3 (slot info).
8420cc8ae86Sav145390 * Z = 'A' or 'B'
8430cc8ae86Sav145390 *
84478ed97a7Sjl139090 * UNUM format for FF2 is "/MBU_B/MEMBx/MEMyZ", where
8450cc8ae86Sav145390 * x = 0..7 (MEMB number)
8460cc8ae86Sav145390 * y = 0..3 (slot info).
8470cc8ae86Sav145390 * Z = 'A' or 'B'
84878ed97a7Sjl139090 *
84978ed97a7Sjl139090 * UNUM format for IKKAKU is "/MBU_A/MEMyZ", where
85078ed97a7Sjl139090 * y = 0..3 (slot info).
85178ed97a7Sjl139090 * Z = 'A' or 'B'
85278ed97a7Sjl139090 *
8530cc8ae86Sav145390 */
8540cc8ae86Sav145390 int
mc_set_mem_unum(char * buf,int buflen,int sb,int bank,uint32_t mf_type,uint32_t d_slot)855aeb241b2Sav145390 mc_set_mem_unum(char *buf, int buflen, int sb, int bank,
8560cc8ae86Sav145390 uint32_t mf_type, uint32_t d_slot)
8570cc8ae86Sav145390 {
8580cc8ae86Sav145390 char *dimmnm;
8590cc8ae86Sav145390 char memb_num;
860aeb241b2Sav145390 int cs;
8610cc8ae86Sav145390 int i;
862aeb241b2Sav145390 int j;
8630cc8ae86Sav145390
864aeb241b2Sav145390 cs = SLOT_TO_CS(d_slot);
8650cc8ae86Sav145390
86678ed97a7Sjl139090 switch (plat_model) {
86778ed97a7Sjl139090 case MODEL_DC:
868056c948bStsien if (mf_type == FLT_TYPE_INTERMITTENT_CE ||
869056c948bStsien mf_type == FLT_TYPE_PERMANENT_CE) {
8700cc8ae86Sav145390 i = BD_BK_SLOT_TO_INDEX(0, bank, d_slot);
8710cc8ae86Sav145390 dimmnm = mc_dc_dimm_unum_table[i];
87207d06da5SSurya Prakki (void) snprintf(buf, buflen, "/%s%02d/MEM%s",
8730cc8ae86Sav145390 model_names[plat_model].unit_name, sb, dimmnm);
8740cc8ae86Sav145390 } else {
8750cc8ae86Sav145390 i = BD_BK_SLOT_TO_INDEX(0, bank, 0);
876aeb241b2Sav145390 j = (cs == 0) ? i : i + 2;
87707d06da5SSurya Prakki (void) snprintf(buf, buflen, "/%s%02d/MEM%s MEM%s",
8780cc8ae86Sav145390 model_names[plat_model].unit_name, sb,
879aeb241b2Sav145390 mc_dc_dimm_unum_table[j],
880aeb241b2Sav145390 mc_dc_dimm_unum_table[j + 1]);
8810cc8ae86Sav145390 }
88278ed97a7Sjl139090 break;
88378ed97a7Sjl139090 case MODEL_FF1:
88478ed97a7Sjl139090 case MODEL_FF2:
885056c948bStsien if (mf_type == FLT_TYPE_INTERMITTENT_CE ||
886056c948bStsien mf_type == FLT_TYPE_PERMANENT_CE) {
887aeb241b2Sav145390 i = BD_BK_SLOT_TO_INDEX(sb, bank, d_slot);
8880cc8ae86Sav145390 dimmnm = mc_ff_dimm_unum_table[i];
8890cc8ae86Sav145390 memb_num = dimmnm[0];
89007d06da5SSurya Prakki (void) snprintf(buf, buflen, "/%s/%s%c/MEM%s",
8910cc8ae86Sav145390 model_names[plat_model].unit_name,
8920cc8ae86Sav145390 model_names[plat_model].mem_name,
8930cc8ae86Sav145390 memb_num, &dimmnm[1]);
8940cc8ae86Sav145390 } else {
8950cc8ae86Sav145390 i = BD_BK_SLOT_TO_INDEX(sb, bank, 0);
896aeb241b2Sav145390 j = (cs == 0) ? i : i + 2;
8970cc8ae86Sav145390 memb_num = mc_ff_dimm_unum_table[i][0],
89807d06da5SSurya Prakki (void) snprintf(buf, buflen, "/%s/%s%c/MEM%s MEM%s",
8990cc8ae86Sav145390 model_names[plat_model].unit_name,
9000cc8ae86Sav145390 model_names[plat_model].mem_name, memb_num,
901aeb241b2Sav145390 &mc_ff_dimm_unum_table[j][1],
902aeb241b2Sav145390 &mc_ff_dimm_unum_table[j + 1][1]);
9030cc8ae86Sav145390 }
90478ed97a7Sjl139090 break;
90578ed97a7Sjl139090 case MODEL_IKKAKU:
90678ed97a7Sjl139090 if (mf_type == FLT_TYPE_INTERMITTENT_CE ||
90778ed97a7Sjl139090 mf_type == FLT_TYPE_PERMANENT_CE) {
90878ed97a7Sjl139090 i = BD_BK_SLOT_TO_INDEX(sb, bank, d_slot);
90978ed97a7Sjl139090 dimmnm = mc_ff_dimm_unum_table[i];
91007d06da5SSurya Prakki (void) snprintf(buf, buflen, "/%s/MEM%s",
91178ed97a7Sjl139090 model_names[plat_model].unit_name, &dimmnm[1]);
91278ed97a7Sjl139090 } else {
91378ed97a7Sjl139090 i = BD_BK_SLOT_TO_INDEX(sb, bank, 0);
91478ed97a7Sjl139090 j = (cs == 0) ? i : i + 2;
91578ed97a7Sjl139090 memb_num = mc_ff_dimm_unum_table[i][0],
91607d06da5SSurya Prakki (void) snprintf(buf, buflen, "/%s/MEM%s MEM%s",
91778ed97a7Sjl139090 model_names[plat_model].unit_name,
91878ed97a7Sjl139090 &mc_ff_dimm_unum_table[j][1],
91978ed97a7Sjl139090 &mc_ff_dimm_unum_table[j + 1][1]);
92078ed97a7Sjl139090 }
92178ed97a7Sjl139090 break;
92278ed97a7Sjl139090 default:
92378ed97a7Sjl139090 return (-1);
9240cc8ae86Sav145390 }
9250cc8ae86Sav145390 return (0);
9260cc8ae86Sav145390 }
9270cc8ae86Sav145390
92825cf1a30Sjl139090 static void
mc_ereport_post(mc_aflt_t * mc_aflt)92925cf1a30Sjl139090 mc_ereport_post(mc_aflt_t *mc_aflt)
93025cf1a30Sjl139090 {
93125cf1a30Sjl139090 char buf[FM_MAX_CLASS];
93225cf1a30Sjl139090 char device_path[MAXPATHLEN];
9330cc8ae86Sav145390 char sid[MAXPATHLEN];
93425cf1a30Sjl139090 nv_alloc_t *nva = NULL;
93525cf1a30Sjl139090 nvlist_t *ereport, *detector, *resource;
93625cf1a30Sjl139090 errorq_elem_t *eqep;
93725cf1a30Sjl139090 int nflts;
93825cf1a30Sjl139090 mc_flt_stat_t *flt_stat;
9390cc8ae86Sav145390 int i, n;
9400cc8ae86Sav145390 int blen = MAXPATHLEN;
9410cc8ae86Sav145390 char *p, *s = NULL;
94225cf1a30Sjl139090 uint32_t values[2], synd[2], dslot[2];
9430cc8ae86Sav145390 uint64_t offset = (uint64_t)-1;
9440cc8ae86Sav145390 int ret = -1;
94525cf1a30Sjl139090
94625cf1a30Sjl139090 if (panicstr) {
94725cf1a30Sjl139090 eqep = errorq_reserve(ereport_errorq);
94825cf1a30Sjl139090 if (eqep == NULL)
94925cf1a30Sjl139090 return;
95025cf1a30Sjl139090 ereport = errorq_elem_nvl(ereport_errorq, eqep);
95125cf1a30Sjl139090 nva = errorq_elem_nva(ereport_errorq, eqep);
95225cf1a30Sjl139090 } else {
95325cf1a30Sjl139090 ereport = fm_nvlist_create(nva);
95425cf1a30Sjl139090 }
95525cf1a30Sjl139090
95625cf1a30Sjl139090 /*
95725cf1a30Sjl139090 * Create the scheme "dev" FMRI.
95825cf1a30Sjl139090 */
95925cf1a30Sjl139090 detector = fm_nvlist_create(nva);
96025cf1a30Sjl139090 resource = fm_nvlist_create(nva);
96125cf1a30Sjl139090
96225cf1a30Sjl139090 nflts = mc_aflt->mflt_nflts;
96325cf1a30Sjl139090
96425cf1a30Sjl139090 ASSERT(nflts >= 1 && nflts <= 2);
96525cf1a30Sjl139090
96625cf1a30Sjl139090 flt_stat = mc_aflt->mflt_stat[0];
96725cf1a30Sjl139090 (void) ddi_pathname(mc_aflt->mflt_mcp->mc_dip, device_path);
96825cf1a30Sjl139090 (void) fm_fmri_dev_set(detector, FM_DEV_SCHEME_VERSION, NULL,
969*392e836bSGavin Maltby device_path, NULL, NULL);
97025cf1a30Sjl139090
97125cf1a30Sjl139090 /*
97225cf1a30Sjl139090 * Encode all the common data into the ereport.
97325cf1a30Sjl139090 */
974d8a0cca9Swh31274 (void) snprintf(buf, FM_MAX_CLASS, "%s.%s-%s", MC_OPL_ERROR_CLASS,
975d8a0cca9Swh31274 mc_aflt->mflt_is_ptrl ? MC_OPL_PTRL_SUBCLASS : MC_OPL_MI_SUBCLASS,
97625cf1a30Sjl139090 mc_aflt->mflt_erpt_class);
97725cf1a30Sjl139090
97825cf1a30Sjl139090 MC_LOG("mc_ereport_post: ereport %s\n", buf);
97925cf1a30Sjl139090
98025cf1a30Sjl139090
98125cf1a30Sjl139090 fm_ereport_set(ereport, FM_EREPORT_VERSION, buf,
982d8a0cca9Swh31274 fm_ena_generate(mc_aflt->mflt_id, FM_ENA_FMT1), detector, NULL);
98325cf1a30Sjl139090
98425cf1a30Sjl139090 /*
98525cf1a30Sjl139090 * Set payload.
98625cf1a30Sjl139090 */
98725cf1a30Sjl139090 fm_payload_set(ereport, MC_OPL_BOARD, DATA_TYPE_UINT32,
98825cf1a30Sjl139090 flt_stat->mf_flt_maddr.ma_bd, NULL);
98925cf1a30Sjl139090
99025cf1a30Sjl139090 fm_payload_set(ereport, MC_OPL_PA, DATA_TYPE_UINT64,
99125cf1a30Sjl139090 flt_stat->mf_flt_paddr, NULL);
99225cf1a30Sjl139090
993056c948bStsien if (flt_stat->mf_type == FLT_TYPE_INTERMITTENT_CE ||
994056c948bStsien flt_stat->mf_type == FLT_TYPE_PERMANENT_CE) {
995d8a0cca9Swh31274 fm_payload_set(ereport, MC_OPL_FLT_TYPE, DATA_TYPE_UINT8,
996d8a0cca9Swh31274 ECC_STICKY, NULL);
99725cf1a30Sjl139090 }
99825cf1a30Sjl139090
99925cf1a30Sjl139090 for (i = 0; i < nflts; i++)
100025cf1a30Sjl139090 values[i] = mc_aflt->mflt_stat[i]->mf_flt_maddr.ma_bank;
100125cf1a30Sjl139090
1002d8a0cca9Swh31274 fm_payload_set(ereport, MC_OPL_BANK, DATA_TYPE_UINT32_ARRAY, nflts,
1003d8a0cca9Swh31274 values, NULL);
100425cf1a30Sjl139090
100525cf1a30Sjl139090 for (i = 0; i < nflts; i++)
100625cf1a30Sjl139090 values[i] = mc_aflt->mflt_stat[i]->mf_cntl;
100725cf1a30Sjl139090
1008d8a0cca9Swh31274 fm_payload_set(ereport, MC_OPL_STATUS, DATA_TYPE_UINT32_ARRAY, nflts,
1009d8a0cca9Swh31274 values, NULL);
101025cf1a30Sjl139090
101125cf1a30Sjl139090 for (i = 0; i < nflts; i++)
101225cf1a30Sjl139090 values[i] = mc_aflt->mflt_stat[i]->mf_err_add;
101325cf1a30Sjl139090
1014056c948bStsien /* offset is set only for PCE and ICE */
1015056c948bStsien if (mc_aflt->mflt_stat[0]->mf_type == FLT_TYPE_INTERMITTENT_CE ||
1016056c948bStsien mc_aflt->mflt_stat[0]->mf_type == FLT_TYPE_PERMANENT_CE) {
10170cc8ae86Sav145390 offset = values[0];
10180cc8ae86Sav145390
10190cc8ae86Sav145390 }
1020d8a0cca9Swh31274 fm_payload_set(ereport, MC_OPL_ERR_ADD, DATA_TYPE_UINT32_ARRAY, nflts,
1021d8a0cca9Swh31274 values, NULL);
102225cf1a30Sjl139090
102325cf1a30Sjl139090 for (i = 0; i < nflts; i++)
102425cf1a30Sjl139090 values[i] = mc_aflt->mflt_stat[i]->mf_err_log;
102525cf1a30Sjl139090
1026d8a0cca9Swh31274 fm_payload_set(ereport, MC_OPL_ERR_LOG, DATA_TYPE_UINT32_ARRAY, nflts,
1027d8a0cca9Swh31274 values, NULL);
102825cf1a30Sjl139090
102925cf1a30Sjl139090 for (i = 0; i < nflts; i++) {
103025cf1a30Sjl139090 flt_stat = mc_aflt->mflt_stat[i];
103125cf1a30Sjl139090 if (flt_stat->mf_errlog_valid) {
103225cf1a30Sjl139090 synd[i] = flt_stat->mf_synd;
103325cf1a30Sjl139090 dslot[i] = flt_stat->mf_dimm_slot;
103425cf1a30Sjl139090 values[i] = flt_stat->mf_dram_place;
103525cf1a30Sjl139090 } else {
103625cf1a30Sjl139090 synd[i] = 0;
103725cf1a30Sjl139090 dslot[i] = 0;
103825cf1a30Sjl139090 values[i] = 0;
103925cf1a30Sjl139090 }
104025cf1a30Sjl139090 }
104125cf1a30Sjl139090
1042d8a0cca9Swh31274 fm_payload_set(ereport, MC_OPL_ERR_SYND, DATA_TYPE_UINT32_ARRAY, nflts,
1043d8a0cca9Swh31274 synd, NULL);
104425cf1a30Sjl139090
1045d8a0cca9Swh31274 fm_payload_set(ereport, MC_OPL_ERR_DIMMSLOT, DATA_TYPE_UINT32_ARRAY,
1046d8a0cca9Swh31274 nflts, dslot, NULL);
104725cf1a30Sjl139090
1048d8a0cca9Swh31274 fm_payload_set(ereport, MC_OPL_ERR_DRAM, DATA_TYPE_UINT32_ARRAY, nflts,
1049d8a0cca9Swh31274 values, NULL);
105025cf1a30Sjl139090
105125cf1a30Sjl139090 device_path[0] = 0;
105225cf1a30Sjl139090 p = &device_path[0];
10530cc8ae86Sav145390 sid[0] = 0;
10540cc8ae86Sav145390 s = &sid[0];
10550cc8ae86Sav145390 ret = 0;
105625cf1a30Sjl139090
105725cf1a30Sjl139090 for (i = 0; i < nflts; i++) {
10580cc8ae86Sav145390 int bank;
105925cf1a30Sjl139090
106025cf1a30Sjl139090 flt_stat = mc_aflt->mflt_stat[i];
10610cc8ae86Sav145390 bank = flt_stat->mf_flt_maddr.ma_bank;
10620cc8ae86Sav145390 ret = mc_set_mem_unum(p + strlen(p), blen,
1063d8a0cca9Swh31274 flt_stat->mf_flt_maddr.ma_phys_bd, bank, flt_stat->mf_type,
1064d8a0cca9Swh31274 flt_stat->mf_dimm_slot);
106525cf1a30Sjl139090
10660cc8ae86Sav145390 if (ret != 0) {
10670cc8ae86Sav145390 cmn_err(CE_WARN,
10680cc8ae86Sav145390 "mc_ereport_post: Failed to determine the unum "
10690cc8ae86Sav145390 "for board=%d bank=%d type=0x%x slot=0x%x",
10700cc8ae86Sav145390 flt_stat->mf_flt_maddr.ma_bd, bank,
10710cc8ae86Sav145390 flt_stat->mf_type, flt_stat->mf_dimm_slot);
10720cc8ae86Sav145390 continue;
107325cf1a30Sjl139090 }
10740cc8ae86Sav145390 n = strlen(device_path);
107525cf1a30Sjl139090 blen = MAXPATHLEN - n;
107625cf1a30Sjl139090 p = &device_path[n];
107725cf1a30Sjl139090 if (i < (nflts - 1)) {
107807d06da5SSurya Prakki (void) snprintf(p, blen, " ");
10790cc8ae86Sav145390 blen--;
10800cc8ae86Sav145390 p++;
10810cc8ae86Sav145390 }
10820cc8ae86Sav145390
10830cc8ae86Sav145390 if (ret == 0) {
10840cc8ae86Sav145390 ret = mc_set_mem_sid(mc_aflt->mflt_mcp, s + strlen(s),
1085aeb241b2Sav145390 blen, flt_stat->mf_flt_maddr.ma_phys_bd, bank,
10860cc8ae86Sav145390 flt_stat->mf_type, flt_stat->mf_dimm_slot);
10870cc8ae86Sav145390
108825cf1a30Sjl139090 }
108925cf1a30Sjl139090 }
109025cf1a30Sjl139090
1091d8a0cca9Swh31274 (void) fm_fmri_mem_set(resource, FM_MEM_SCHEME_VERSION, NULL,
1092d8a0cca9Swh31274 device_path, (ret == 0) ? sid : NULL, (ret == 0) ? offset :
1093d8a0cca9Swh31274 (uint64_t)-1);
109425cf1a30Sjl139090
1095d8a0cca9Swh31274 fm_payload_set(ereport, MC_OPL_RESOURCE, DATA_TYPE_NVLIST, resource,
1096d8a0cca9Swh31274 NULL);
109725cf1a30Sjl139090
109825cf1a30Sjl139090 if (panicstr) {
109925cf1a30Sjl139090 errorq_commit(ereport_errorq, eqep, ERRORQ_SYNC);
110025cf1a30Sjl139090 } else {
110125cf1a30Sjl139090 (void) fm_ereport_post(ereport, EVCH_TRYHARD);
110225cf1a30Sjl139090 fm_nvlist_destroy(ereport, FM_NVA_FREE);
110325cf1a30Sjl139090 fm_nvlist_destroy(detector, FM_NVA_FREE);
110425cf1a30Sjl139090 fm_nvlist_destroy(resource, FM_NVA_FREE);
110525cf1a30Sjl139090 }
110625cf1a30Sjl139090 }
110725cf1a30Sjl139090
11080cc8ae86Sav145390
110925cf1a30Sjl139090 static void
mc_err_drain(mc_aflt_t * mc_aflt)111025cf1a30Sjl139090 mc_err_drain(mc_aflt_t *mc_aflt)
111125cf1a30Sjl139090 {
111225cf1a30Sjl139090 int rv;
111325cf1a30Sjl139090 uint64_t pa = (uint64_t)(-1);
11140cc8ae86Sav145390 int i;
111525cf1a30Sjl139090
1116d8a0cca9Swh31274 MC_LOG("mc_err_drain: %s\n", mc_aflt->mflt_erpt_class);
111725cf1a30Sjl139090 /*
111825cf1a30Sjl139090 * we come here only when we have:
11191039f409Sav145390 * In mirror mode: MUE, SUE
1120056c948bStsien * In normal mode: UE, Permanent CE, Intermittent CE
112125cf1a30Sjl139090 */
11220cc8ae86Sav145390 for (i = 0; i < mc_aflt->mflt_nflts; i++) {
112325cf1a30Sjl139090 rv = mcaddr_to_pa(mc_aflt->mflt_mcp,
11240cc8ae86Sav145390 &(mc_aflt->mflt_stat[i]->mf_flt_maddr), &pa);
1125738dd194Shyw
1126738dd194Shyw /* Ensure the pa is valid (not in isolated memory block) */
1127738dd194Shyw if (rv == 0 && pa_is_valid(mc_aflt->mflt_mcp, pa))
11280cc8ae86Sav145390 mc_aflt->mflt_stat[i]->mf_flt_paddr = pa;
112925cf1a30Sjl139090 else
11300cc8ae86Sav145390 mc_aflt->mflt_stat[i]->mf_flt_paddr = (uint64_t)-1;
11310cc8ae86Sav145390 }
11320cc8ae86Sav145390
1133cfb9e062Shyw MC_LOG("mc_err_drain:pa = %lx\n", pa);
1134cfb9e062Shyw
1135738dd194Shyw switch (page_retire_check(pa, NULL)) {
1136738dd194Shyw case 0:
1137738dd194Shyw case EAGAIN:
1138738dd194Shyw MC_LOG("Page retired or pending\n");
113925cf1a30Sjl139090 return;
1140738dd194Shyw case EIO:
1141738dd194Shyw /*
1142056c948bStsien * Do page retirement except for the PCE and ICE cases.
1143738dd194Shyw * This is taken care by the OPL DE
1144738dd194Shyw */
1145056c948bStsien if (mc_aflt->mflt_stat[0]->mf_type !=
1146056c948bStsien FLT_TYPE_INTERMITTENT_CE &&
1147056c948bStsien mc_aflt->mflt_stat[0]->mf_type != FLT_TYPE_PERMANENT_CE) {
1148cfb9e062Shyw MC_LOG("offline page at pa %lx error %x\n", pa,
114925cf1a30Sjl139090 mc_aflt->mflt_pr);
115025cf1a30Sjl139090 (void) page_retire(pa, mc_aflt->mflt_pr);
115125cf1a30Sjl139090 }
1152738dd194Shyw break;
1153738dd194Shyw case EINVAL:
1154738dd194Shyw default:
1155738dd194Shyw /*
1156738dd194Shyw * Some memory do not have page structure so
1157738dd194Shyw * we keep going in case of EINVAL.
1158738dd194Shyw */
1159738dd194Shyw break;
1160738dd194Shyw }
11610cc8ae86Sav145390
11620cc8ae86Sav145390 for (i = 0; i < mc_aflt->mflt_nflts; i++) {
11630cc8ae86Sav145390 mc_aflt_t mc_aflt0;
11640cc8ae86Sav145390 if (mc_aflt->mflt_stat[i]->mf_flt_paddr != (uint64_t)-1) {
11650cc8ae86Sav145390 mc_aflt0 = *mc_aflt;
11660cc8ae86Sav145390 mc_aflt0.mflt_nflts = 1;
11670cc8ae86Sav145390 mc_aflt0.mflt_stat[0] = mc_aflt->mflt_stat[i];
11680cc8ae86Sav145390 mc_ereport_post(&mc_aflt0);
116925cf1a30Sjl139090 }
11700cc8ae86Sav145390 }
11710cc8ae86Sav145390 }
117225cf1a30Sjl139090
117325cf1a30Sjl139090 /*
117425cf1a30Sjl139090 * The restart address is actually defined in unit of PA[37:6]
117525cf1a30Sjl139090 * the mac patrol will convert that to dimm offset. If the
117625cf1a30Sjl139090 * address is not in the bank, it will continue to search for
117725cf1a30Sjl139090 * the next PA that is within the bank.
117825cf1a30Sjl139090 *
117925cf1a30Sjl139090 * Also the mac patrol scans the dimms based on PA, not
118025cf1a30Sjl139090 * dimm offset.
118125cf1a30Sjl139090 */
118225cf1a30Sjl139090 static int
restart_patrol(mc_opl_t * mcp,int bank,mc_rsaddr_info_t * rsaddr_info)1183738dd194Shyw restart_patrol(mc_opl_t *mcp, int bank, mc_rsaddr_info_t *rsaddr_info)
118425cf1a30Sjl139090 {
118525cf1a30Sjl139090 uint64_t pa;
118625cf1a30Sjl139090 int rv;
118725cf1a30Sjl139090
1188601c2e1eSdhain if (MC_REWRITE_MODE(mcp, bank)) {
1189601c2e1eSdhain return (0);
1190601c2e1eSdhain }
1191738dd194Shyw if (rsaddr_info == NULL || (rsaddr_info->mi_valid == 0)) {
119225cf1a30Sjl139090 MAC_PTRL_START(mcp, bank);
119325cf1a30Sjl139090 return (0);
119425cf1a30Sjl139090 }
119525cf1a30Sjl139090
1196738dd194Shyw rv = mcaddr_to_pa(mcp, &rsaddr_info->mi_restartaddr, &pa);
119725cf1a30Sjl139090 if (rv != 0) {
119825cf1a30Sjl139090 MC_LOG("cannot convert mcaddr to pa. use auto restart\n");
119925cf1a30Sjl139090 MAC_PTRL_START(mcp, bank);
120025cf1a30Sjl139090 return (0);
120125cf1a30Sjl139090 }
120225cf1a30Sjl139090
1203738dd194Shyw if (!mc_rangecheck_pa(mcp, pa)) {
120425cf1a30Sjl139090 /* pa is not on this board, just retry */
120525cf1a30Sjl139090 cmn_err(CE_WARN, "restart_patrol: invalid address %lx "
120625cf1a30Sjl139090 "on board %d\n", pa, mcp->mc_board_num);
120725cf1a30Sjl139090 MAC_PTRL_START(mcp, bank);
120825cf1a30Sjl139090 return (0);
120925cf1a30Sjl139090 }
121025cf1a30Sjl139090
121125cf1a30Sjl139090 MC_LOG("restart_patrol: pa = %lx\n", pa);
121225cf1a30Sjl139090
1213738dd194Shyw if (!rsaddr_info->mi_injectrestart) {
1214738dd194Shyw /*
1215738dd194Shyw * For non-error injection restart we need to
1216738dd194Shyw * determine if the current restart pa/page is
1217738dd194Shyw * a "good" page. A "good" page is a page that
1218738dd194Shyw * has not been page retired. If the current
1219738dd194Shyw * page that contains the pa is "good", we will
1220738dd194Shyw * do a HW auto restart and let HW patrol continue
1221738dd194Shyw * where it last stopped. Most desired scenario.
1222738dd194Shyw *
1223738dd194Shyw * If the current page is not "good", we will advance
1224738dd194Shyw * to the next page to find the next "good" page and
1225738dd194Shyw * restart the patrol from there.
1226738dd194Shyw */
1227738dd194Shyw int wrapcount = 0;
1228738dd194Shyw uint64_t origpa = pa;
1229738dd194Shyw while (wrapcount < 2) {
1230738dd194Shyw if (!pa_is_valid(mcp, pa)) {
1231738dd194Shyw /*
1232738dd194Shyw * Not in physinstall - advance to the
1233738dd194Shyw * next memory isolation blocksize
1234738dd194Shyw */
123525cf1a30Sjl139090 MC_LOG("Invalid PA\n");
1236738dd194Shyw pa = roundup(pa + 1, mc_isolation_bsize);
123725cf1a30Sjl139090 } else {
1238738dd194Shyw int rv;
1239738dd194Shyw if ((rv = page_retire_check(pa, NULL)) != 0 &&
1240738dd194Shyw rv != EAGAIN) {
124125cf1a30Sjl139090 /*
1242d8a0cca9Swh31274 * The page is "good" (not retired),
1243d8a0cca9Swh31274 * we will use automatic HW restart
1244d8a0cca9Swh31274 * algorithm if this is the original
1245d8a0cca9Swh31274 * current starting page.
124625cf1a30Sjl139090 */
1247738dd194Shyw if (pa == origpa) {
1248d8a0cca9Swh31274 MC_LOG("Page has no error. "
1249d8a0cca9Swh31274 "Auto restart\n");
1250738dd194Shyw MAC_PTRL_START(mcp, bank);
1251738dd194Shyw return (0);
125225cf1a30Sjl139090 } else {
1253d8a0cca9Swh31274 /*
1254d8a0cca9Swh31274 * found a subsequent good page
1255d8a0cca9Swh31274 */
125625cf1a30Sjl139090 break;
125725cf1a30Sjl139090 }
1258738dd194Shyw }
1259738dd194Shyw
1260738dd194Shyw /*
1261738dd194Shyw * Skip to the next page
1262738dd194Shyw */
126325cf1a30Sjl139090 pa = roundup(pa + 1, PAGESIZE);
126425cf1a30Sjl139090 MC_LOG("Skipping bad page to %lx\n", pa);
126525cf1a30Sjl139090 }
1266738dd194Shyw
1267738dd194Shyw /* Check to see if we hit the end of the memory range */
126825cf1a30Sjl139090 if (pa >= (mcp->mc_start_address + mcp->mc_size)) {
126925cf1a30Sjl139090 MC_LOG("Wrap around\n");
127025cf1a30Sjl139090 pa = mcp->mc_start_address;
1271738dd194Shyw wrapcount++;
127225cf1a30Sjl139090 }
127325cf1a30Sjl139090 }
127425cf1a30Sjl139090
1275738dd194Shyw if (wrapcount > 1) {
1276738dd194Shyw MC_LOG("Failed to find a good page. Just restart\n");
1277738dd194Shyw MAC_PTRL_START(mcp, bank);
1278738dd194Shyw return (0);
1279738dd194Shyw }
1280738dd194Shyw }
1281738dd194Shyw
1282738dd194Shyw /*
1283738dd194Shyw * We reached here either:
1284738dd194Shyw * 1. We are doing an error injection restart that specify
1285738dd194Shyw * the exact pa/page to restart. OR
1286738dd194Shyw * 2. We found a subsequent good page different from the
1287738dd194Shyw * original restart pa/page.
1288738dd194Shyw * Restart MAC patrol: PA[37:6]
1289738dd194Shyw */
129025cf1a30Sjl139090 MC_LOG("restart at pa = %lx\n", pa);
129125cf1a30Sjl139090 ST_MAC_REG(MAC_RESTART_ADD(mcp, bank), MAC_RESTART_PA(pa));
129225cf1a30Sjl139090 MAC_PTRL_START_ADD(mcp, bank);
129325cf1a30Sjl139090
129425cf1a30Sjl139090 return (0);
129525cf1a30Sjl139090 }
129625cf1a30Sjl139090
1297601c2e1eSdhain static void
mc_retry_info_put(mc_retry_info_t ** q,mc_retry_info_t * p)1298601c2e1eSdhain mc_retry_info_put(mc_retry_info_t **q, mc_retry_info_t *p)
1299601c2e1eSdhain {
1300601c2e1eSdhain ASSERT(p != NULL);
1301601c2e1eSdhain p->ri_next = *q;
1302601c2e1eSdhain *q = p;
1303601c2e1eSdhain }
1304601c2e1eSdhain
1305601c2e1eSdhain static mc_retry_info_t *
mc_retry_info_get(mc_retry_info_t ** q)1306601c2e1eSdhain mc_retry_info_get(mc_retry_info_t **q)
1307601c2e1eSdhain {
1308601c2e1eSdhain mc_retry_info_t *p;
1309601c2e1eSdhain
1310601c2e1eSdhain if ((p = *q) != NULL) {
1311601c2e1eSdhain *q = p->ri_next;
1312601c2e1eSdhain return (p);
1313601c2e1eSdhain } else {
1314601c2e1eSdhain return (NULL);
1315601c2e1eSdhain }
1316601c2e1eSdhain }
1317601c2e1eSdhain
131825cf1a30Sjl139090 /*
131925cf1a30Sjl139090 * Rewriting is used for two purposes.
132025cf1a30Sjl139090 * - to correct the error in memory.
132125cf1a30Sjl139090 * - to determine whether the error is permanent or intermittent.
132225cf1a30Sjl139090 * It's done by writing the address in MAC_BANKm_REWRITE_ADD
132325cf1a30Sjl139090 * and issuing REW_REQ command in MAC_BANKm_PTRL_CNRL. After that,
132425cf1a30Sjl139090 * REW_END (and REW_CE/REW_UE if some error detected) is set when
132525cf1a30Sjl139090 * rewrite operation is done. See 4.7.3 and 4.7.11 in Columbus2 PRM.
132625cf1a30Sjl139090 *
132725cf1a30Sjl139090 * Note that rewrite operation doesn't change RAW_UE to Marked UE.
132825cf1a30Sjl139090 * Therefore, we use it only CE case.
132925cf1a30Sjl139090 */
1330601c2e1eSdhain
133125cf1a30Sjl139090 static uint32_t
do_rewrite(mc_opl_t * mcp,int bank,uint32_t dimm_addr,int retrying)1332601c2e1eSdhain do_rewrite(mc_opl_t *mcp, int bank, uint32_t dimm_addr, int retrying)
133325cf1a30Sjl139090 {
133425cf1a30Sjl139090 uint32_t cntl;
133525cf1a30Sjl139090 int count = 0;
1336601c2e1eSdhain int max_count;
1337601c2e1eSdhain int retry_state;
1338601c2e1eSdhain
1339601c2e1eSdhain if (retrying)
1340601c2e1eSdhain max_count = 1;
1341601c2e1eSdhain else
1342601c2e1eSdhain max_count = mc_max_rewrite_loop;
1343601c2e1eSdhain
1344601c2e1eSdhain retry_state = RETRY_STATE_PENDING;
1345601c2e1eSdhain
1346601c2e1eSdhain if (!retrying && MC_REWRITE_MODE(mcp, bank)) {
1347601c2e1eSdhain goto timeout;
1348601c2e1eSdhain }
1349601c2e1eSdhain
1350601c2e1eSdhain retry_state = RETRY_STATE_ACTIVE;
135125cf1a30Sjl139090
135225cf1a30Sjl139090 /* first wait to make sure PTRL_STATUS is 0 */
1353601c2e1eSdhain while (count++ < max_count) {
135425cf1a30Sjl139090 cntl = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank));
1355601c2e1eSdhain if (!(cntl & MAC_CNTL_PTRL_STATUS)) {
1356601c2e1eSdhain count = 0;
135725cf1a30Sjl139090 break;
1358601c2e1eSdhain }
13590cc8ae86Sav145390 drv_usecwait(mc_rewrite_delay);
136025cf1a30Sjl139090 }
1361601c2e1eSdhain if (count >= max_count)
1362601c2e1eSdhain goto timeout;
136325cf1a30Sjl139090
136425cf1a30Sjl139090 count = 0;
136525cf1a30Sjl139090
136625cf1a30Sjl139090 ST_MAC_REG(MAC_REWRITE_ADD(mcp, bank), dimm_addr);
136725cf1a30Sjl139090 MAC_REW_REQ(mcp, bank);
136825cf1a30Sjl139090
1369601c2e1eSdhain retry_state = RETRY_STATE_REWRITE;
1370601c2e1eSdhain
137125cf1a30Sjl139090 do {
1372601c2e1eSdhain if (count++ > max_count) {
1373601c2e1eSdhain goto timeout;
13740cc8ae86Sav145390 } else {
13750cc8ae86Sav145390 drv_usecwait(mc_rewrite_delay);
13760cc8ae86Sav145390 }
1377601c2e1eSdhain cntl = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank));
137825cf1a30Sjl139090 /*
137925cf1a30Sjl139090 * If there are other MEMORY or PCI activities, this
138025cf1a30Sjl139090 * will be BUSY, else it should be set immediately
138125cf1a30Sjl139090 */
138225cf1a30Sjl139090 } while (!(cntl & MAC_CNTL_REW_END));
138325cf1a30Sjl139090
138425cf1a30Sjl139090 MAC_CLEAR_ERRS(mcp, bank, MAC_CNTL_REW_ERRS);
138525cf1a30Sjl139090 return (cntl);
1386601c2e1eSdhain timeout:
1387601c2e1eSdhain mc_set_rewrite(mcp, bank, dimm_addr, retry_state);
1388601c2e1eSdhain
1389601c2e1eSdhain return (0);
139025cf1a30Sjl139090 }
1391601c2e1eSdhain
1392601c2e1eSdhain void
mc_clear_rewrite(mc_opl_t * mcp,int bank)1393601c2e1eSdhain mc_clear_rewrite(mc_opl_t *mcp, int bank)
1394601c2e1eSdhain {
1395601c2e1eSdhain struct mc_bank *bankp;
1396601c2e1eSdhain mc_retry_info_t *retry;
1397601c2e1eSdhain uint32_t rew_addr;
1398601c2e1eSdhain
1399601c2e1eSdhain bankp = &(mcp->mc_bank[bank]);
1400601c2e1eSdhain retry = bankp->mcb_active;
1401601c2e1eSdhain bankp->mcb_active = NULL;
1402601c2e1eSdhain mc_retry_info_put(&bankp->mcb_retry_freelist, retry);
1403601c2e1eSdhain
1404601c2e1eSdhain again:
1405601c2e1eSdhain bankp->mcb_rewrite_count = 0;
1406601c2e1eSdhain
1407601c2e1eSdhain while (retry = mc_retry_info_get(&bankp->mcb_retry_pending)) {
1408601c2e1eSdhain rew_addr = retry->ri_addr;
1409601c2e1eSdhain mc_retry_info_put(&bankp->mcb_retry_freelist, retry);
1410601c2e1eSdhain if (do_rewrite(mcp, bank, rew_addr, 1) == 0)
1411601c2e1eSdhain break;
1412601c2e1eSdhain }
1413601c2e1eSdhain
1414601c2e1eSdhain /* we break out if no more pending rewrite or we got timeout again */
1415601c2e1eSdhain
1416601c2e1eSdhain if (!bankp->mcb_active && !bankp->mcb_retry_pending) {
1417601c2e1eSdhain if (!IS_MIRROR(mcp, bank)) {
1418601c2e1eSdhain MC_CLEAR_REWRITE_MODE(mcp, bank);
1419601c2e1eSdhain } else {
1420601c2e1eSdhain int mbank = bank ^ 1;
1421601c2e1eSdhain bankp = &(mcp->mc_bank[mbank]);
1422601c2e1eSdhain if (!bankp->mcb_active && !bankp->mcb_retry_pending) {
1423601c2e1eSdhain MC_CLEAR_REWRITE_MODE(mcp, bank);
1424601c2e1eSdhain MC_CLEAR_REWRITE_MODE(mcp, mbank);
1425601c2e1eSdhain } else {
1426601c2e1eSdhain bank = mbank;
1427601c2e1eSdhain goto again;
1428601c2e1eSdhain }
1429601c2e1eSdhain }
1430601c2e1eSdhain }
1431601c2e1eSdhain }
1432601c2e1eSdhain
1433601c2e1eSdhain void
mc_set_rewrite(mc_opl_t * mcp,int bank,uint32_t addr,int state)1434601c2e1eSdhain mc_set_rewrite(mc_opl_t *mcp, int bank, uint32_t addr, int state)
1435601c2e1eSdhain {
1436601c2e1eSdhain mc_retry_info_t *retry;
1437601c2e1eSdhain struct mc_bank *bankp;
1438601c2e1eSdhain
1439601c2e1eSdhain bankp = &mcp->mc_bank[bank];
1440601c2e1eSdhain
1441601c2e1eSdhain retry = mc_retry_info_get(&bankp->mcb_retry_freelist);
1442601c2e1eSdhain
14430b240fcdSwh31274 if (retry == NULL) {
14440b240fcdSwh31274 mc_addr_t maddr;
14450b240fcdSwh31274 uint64_t paddr;
14460b240fcdSwh31274 /*
14470b240fcdSwh31274 * previous rewrite request has not completed yet.
14480b240fcdSwh31274 * So we discard this rewrite request.
14490b240fcdSwh31274 */
14500b240fcdSwh31274 maddr.ma_bd = mcp->mc_board_num;
14510b240fcdSwh31274 maddr.ma_bank = bank;
14520b240fcdSwh31274 maddr.ma_dimm_addr = addr;
14530b240fcdSwh31274 if (mcaddr_to_pa(mcp, &maddr, &paddr) == 0) {
14540b240fcdSwh31274 cmn_err(CE_WARN, "Discard CE rewrite request"
14550b240fcdSwh31274 " for 0x%lx (/LSB%d/B%d/%x).\n",
14560b240fcdSwh31274 paddr, mcp->mc_board_num, bank, addr);
14570b240fcdSwh31274 } else {
14580b240fcdSwh31274 cmn_err(CE_WARN, "Discard CE rewrite request"
14590b240fcdSwh31274 " for /LSB%d/B%d/%x.\n",
14600b240fcdSwh31274 mcp->mc_board_num, bank, addr);
14610b240fcdSwh31274 }
14620b240fcdSwh31274 return;
14630b240fcdSwh31274 }
1464601c2e1eSdhain
1465601c2e1eSdhain retry->ri_addr = addr;
1466601c2e1eSdhain retry->ri_state = state;
1467601c2e1eSdhain
1468601c2e1eSdhain MC_SET_REWRITE_MODE(mcp, bank);
1469601c2e1eSdhain
1470601c2e1eSdhain if ((state > RETRY_STATE_PENDING)) {
1471601c2e1eSdhain ASSERT(bankp->mcb_active == NULL);
1472601c2e1eSdhain bankp->mcb_active = retry;
1473601c2e1eSdhain } else {
1474601c2e1eSdhain mc_retry_info_put(&bankp->mcb_retry_pending, retry);
1475601c2e1eSdhain }
1476601c2e1eSdhain
1477601c2e1eSdhain if (IS_MIRROR(mcp, bank)) {
1478601c2e1eSdhain int mbank = bank ^1;
1479601c2e1eSdhain MC_SET_REWRITE_MODE(mcp, mbank);
1480601c2e1eSdhain }
1481601c2e1eSdhain }
1482601c2e1eSdhain
148325cf1a30Sjl139090 void
mc_process_scf_log(mc_opl_t * mcp)148425cf1a30Sjl139090 mc_process_scf_log(mc_opl_t *mcp)
148525cf1a30Sjl139090 {
14860cc8ae86Sav145390 int count;
14870cc8ae86Sav145390 int n = 0;
148825cf1a30Sjl139090 scf_log_t *p;
148925cf1a30Sjl139090 int bank;
149025cf1a30Sjl139090
14910cc8ae86Sav145390 for (bank = 0; bank < BANKNUM_PER_SB; bank++) {
14920cc8ae86Sav145390 while ((p = mcp->mc_scf_log[bank]) != NULL &&
14930cc8ae86Sav145390 (n < mc_max_errlog_processed)) {
14940cc8ae86Sav145390 ASSERT(bank == p->sl_bank);
14950cc8ae86Sav145390 count = 0;
149625cf1a30Sjl139090 while ((LD_MAC_REG(MAC_STATIC_ERR_ADD(mcp, p->sl_bank))
149725cf1a30Sjl139090 & MAC_STATIC_ERR_VLD)) {
14980cc8ae86Sav145390 if (count++ >= (mc_max_scf_loop)) {
149925cf1a30Sjl139090 break;
150025cf1a30Sjl139090 }
15010cc8ae86Sav145390 drv_usecwait(mc_scf_delay);
150225cf1a30Sjl139090 }
150325cf1a30Sjl139090
15040cc8ae86Sav145390 if (count < mc_max_scf_loop) {
150525cf1a30Sjl139090 ST_MAC_REG(MAC_STATIC_ERR_LOG(mcp, p->sl_bank),
150625cf1a30Sjl139090 p->sl_err_log);
150725cf1a30Sjl139090
150825cf1a30Sjl139090 ST_MAC_REG(MAC_STATIC_ERR_ADD(mcp, p->sl_bank),
150925cf1a30Sjl139090 p->sl_err_add|MAC_STATIC_ERR_VLD);
151025cf1a30Sjl139090 mcp->mc_scf_retry[bank] = 0;
151125cf1a30Sjl139090 } else {
1512d8a0cca9Swh31274 /*
1513d8a0cca9Swh31274 * if we try too many times, just drop the req
1514d8a0cca9Swh31274 */
1515d8a0cca9Swh31274 if (mcp->mc_scf_retry[bank]++ <=
1516d8a0cca9Swh31274 mc_max_scf_retry) {
151725cf1a30Sjl139090 return;
151825cf1a30Sjl139090 } else {
15190cc8ae86Sav145390 if ((++mc_pce_dropped & 0xff) == 0) {
1520d8a0cca9Swh31274 cmn_err(CE_WARN, "Cannot "
15210b240fcdSwh31274 "report CE to SCF\n");
152225cf1a30Sjl139090 }
152325cf1a30Sjl139090 }
15240cc8ae86Sav145390 }
15250cc8ae86Sav145390 n++;
15260cc8ae86Sav145390 mcp->mc_scf_log[bank] = p->sl_next;
15270cc8ae86Sav145390 mcp->mc_scf_total[bank]--;
15280cc8ae86Sav145390 ASSERT(mcp->mc_scf_total[bank] >= 0);
152925cf1a30Sjl139090 kmem_free(p, sizeof (scf_log_t));
153025cf1a30Sjl139090 }
153125cf1a30Sjl139090 }
15320cc8ae86Sav145390 }
153325cf1a30Sjl139090 void
mc_queue_scf_log(mc_opl_t * mcp,mc_flt_stat_t * flt_stat,int bank)153425cf1a30Sjl139090 mc_queue_scf_log(mc_opl_t *mcp, mc_flt_stat_t *flt_stat, int bank)
153525cf1a30Sjl139090 {
153625cf1a30Sjl139090 scf_log_t *p;
153725cf1a30Sjl139090
15380cc8ae86Sav145390 if (mcp->mc_scf_total[bank] >= mc_max_scf_logs) {
15390cc8ae86Sav145390 if ((++mc_pce_dropped & 0xff) == 0) {
15400b240fcdSwh31274 cmn_err(CE_WARN, "Too many CE requests.\n");
15410cc8ae86Sav145390 }
154225cf1a30Sjl139090 return;
154325cf1a30Sjl139090 }
154425cf1a30Sjl139090 p = kmem_zalloc(sizeof (scf_log_t), KM_SLEEP);
154525cf1a30Sjl139090 p->sl_next = 0;
154625cf1a30Sjl139090 p->sl_err_add = flt_stat->mf_err_add;
154725cf1a30Sjl139090 p->sl_err_log = flt_stat->mf_err_log;
154825cf1a30Sjl139090 p->sl_bank = bank;
154925cf1a30Sjl139090
15500cc8ae86Sav145390 if (mcp->mc_scf_log[bank] == NULL) {
155125cf1a30Sjl139090 /*
155225cf1a30Sjl139090 * we rely on mc_scf_log to detect NULL queue.
155325cf1a30Sjl139090 * mc_scf_log_tail is irrelevant is such case.
155425cf1a30Sjl139090 */
15550cc8ae86Sav145390 mcp->mc_scf_log_tail[bank] = mcp->mc_scf_log[bank] = p;
155625cf1a30Sjl139090 } else {
15570cc8ae86Sav145390 mcp->mc_scf_log_tail[bank]->sl_next = p;
15580cc8ae86Sav145390 mcp->mc_scf_log_tail[bank] = p;
155925cf1a30Sjl139090 }
15600cc8ae86Sav145390 mcp->mc_scf_total[bank]++;
156125cf1a30Sjl139090 }
156225cf1a30Sjl139090 /*
156325cf1a30Sjl139090 * This routine determines what kind of CE happens, intermittent
156425cf1a30Sjl139090 * or permanent as follows. (See 4.7.3 in Columbus2 PRM.)
156525cf1a30Sjl139090 * - Do rewrite by issuing REW_REQ command to MAC_PTRL_CNTL register.
156625cf1a30Sjl139090 * - If CE is still detected on the same address even after doing
156725cf1a30Sjl139090 * rewrite operation twice, it is determined as permanent error.
156825cf1a30Sjl139090 * - If error is not detected anymore, it is determined as intermittent
156925cf1a30Sjl139090 * error.
157025cf1a30Sjl139090 * - If UE is detected due to rewrite operation, it should be treated
157125cf1a30Sjl139090 * as UE.
157225cf1a30Sjl139090 */
157325cf1a30Sjl139090
157425cf1a30Sjl139090 /* ARGSUSED */
157525cf1a30Sjl139090 static void
mc_scrub_ce(mc_opl_t * mcp,int bank,mc_flt_stat_t * flt_stat,int ptrl_error)157625cf1a30Sjl139090 mc_scrub_ce(mc_opl_t *mcp, int bank, mc_flt_stat_t *flt_stat, int ptrl_error)
157725cf1a30Sjl139090 {
157825cf1a30Sjl139090 uint32_t cntl;
157925cf1a30Sjl139090 int i;
158025cf1a30Sjl139090
158125cf1a30Sjl139090 flt_stat->mf_type = FLT_TYPE_PERMANENT_CE;
158225cf1a30Sjl139090 /*
158325cf1a30Sjl139090 * rewrite request 1st time reads and correct error data
158425cf1a30Sjl139090 * and write to DIMM. 2nd rewrite request must be issued
158525cf1a30Sjl139090 * after REW_CE/UE/END is 0. When the 2nd request is completed,
158625cf1a30Sjl139090 * if REW_CE = 1, then it is permanent CE.
158725cf1a30Sjl139090 */
158825cf1a30Sjl139090 for (i = 0; i < 2; i++) {
1589601c2e1eSdhain cntl = do_rewrite(mcp, bank, flt_stat->mf_err_add, 0);
1590601c2e1eSdhain
1591601c2e1eSdhain if (cntl == 0) {
1592601c2e1eSdhain /* timeout case */
1593601c2e1eSdhain return;
1594601c2e1eSdhain }
159525cf1a30Sjl139090 /*
159625cf1a30Sjl139090 * If the error becomes UE or CMPE
159725cf1a30Sjl139090 * we return to the caller immediately.
159825cf1a30Sjl139090 */
159925cf1a30Sjl139090 if (cntl & MAC_CNTL_REW_UE) {
160025cf1a30Sjl139090 if (ptrl_error)
160125cf1a30Sjl139090 flt_stat->mf_cntl |= MAC_CNTL_PTRL_UE;
160225cf1a30Sjl139090 else
160325cf1a30Sjl139090 flt_stat->mf_cntl |= MAC_CNTL_MI_UE;
160425cf1a30Sjl139090 flt_stat->mf_type = FLT_TYPE_UE;
160525cf1a30Sjl139090 return;
160625cf1a30Sjl139090 }
160725cf1a30Sjl139090 if (cntl & MAC_CNTL_REW_CMPE) {
160825cf1a30Sjl139090 if (ptrl_error)
160925cf1a30Sjl139090 flt_stat->mf_cntl |= MAC_CNTL_PTRL_CMPE;
161025cf1a30Sjl139090 else
161125cf1a30Sjl139090 flt_stat->mf_cntl |= MAC_CNTL_MI_CMPE;
161225cf1a30Sjl139090 flt_stat->mf_type = FLT_TYPE_CMPE;
161325cf1a30Sjl139090 return;
161425cf1a30Sjl139090 }
161525cf1a30Sjl139090 }
161625cf1a30Sjl139090 if (!(cntl & MAC_CNTL_REW_CE)) {
161725cf1a30Sjl139090 flt_stat->mf_type = FLT_TYPE_INTERMITTENT_CE;
161825cf1a30Sjl139090 }
161925cf1a30Sjl139090
162025cf1a30Sjl139090 if (flt_stat->mf_type == FLT_TYPE_PERMANENT_CE) {
162125cf1a30Sjl139090 /* report PERMANENT_CE to SP via SCF */
162225cf1a30Sjl139090 if (!(flt_stat->mf_err_log & MAC_ERR_LOG_INVALID)) {
162325cf1a30Sjl139090 mc_queue_scf_log(mcp, flt_stat, bank);
162425cf1a30Sjl139090 }
162525cf1a30Sjl139090 }
162625cf1a30Sjl139090 }
162725cf1a30Sjl139090
162825cf1a30Sjl139090 #define IS_CMPE(cntl, f) ((cntl) & ((f) ? MAC_CNTL_PTRL_CMPE :\
162925cf1a30Sjl139090 MAC_CNTL_MI_CMPE))
163025cf1a30Sjl139090 #define IS_UE(cntl, f) ((cntl) & ((f) ? MAC_CNTL_PTRL_UE : MAC_CNTL_MI_UE))
163125cf1a30Sjl139090 #define IS_CE(cntl, f) ((cntl) & ((f) ? MAC_CNTL_PTRL_CE : MAC_CNTL_MI_CE))
163225cf1a30Sjl139090 #define IS_OK(cntl, f) (!((cntl) & ((f) ? MAC_CNTL_PTRL_ERRS : \
163325cf1a30Sjl139090 MAC_CNTL_MI_ERRS)))
163425cf1a30Sjl139090
163525cf1a30Sjl139090
163625cf1a30Sjl139090 static int
IS_CE_ONLY(uint32_t cntl,int ptrl_error)163725cf1a30Sjl139090 IS_CE_ONLY(uint32_t cntl, int ptrl_error)
163825cf1a30Sjl139090 {
163925cf1a30Sjl139090 if (ptrl_error) {
164025cf1a30Sjl139090 return ((cntl & MAC_CNTL_PTRL_ERRS) == MAC_CNTL_PTRL_CE);
164125cf1a30Sjl139090 } else {
164225cf1a30Sjl139090 return ((cntl & MAC_CNTL_MI_ERRS) == MAC_CNTL_MI_CE);
164325cf1a30Sjl139090 }
164425cf1a30Sjl139090 }
164525cf1a30Sjl139090
164625cf1a30Sjl139090 void
mc_write_cntl(mc_opl_t * mcp,int bank,uint32_t value)164725cf1a30Sjl139090 mc_write_cntl(mc_opl_t *mcp, int bank, uint32_t value)
164825cf1a30Sjl139090 {
164937afe445Shyw int ebank = (IS_MIRROR(mcp, bank)) ? MIRROR_IDX(bank) : bank;
165037afe445Shyw
165137afe445Shyw if (mcp->mc_speedup_period[ebank] > 0)
16520cc8ae86Sav145390 value |= mc_max_speed;
16530cc8ae86Sav145390 else
16540cc8ae86Sav145390 value |= mcp->mc_speed;
165525cf1a30Sjl139090 ST_MAC_REG(MAC_PTRL_CNTL(mcp, bank), value);
165625cf1a30Sjl139090 }
165725cf1a30Sjl139090
165825cf1a30Sjl139090 static void
mc_read_ptrl_reg(mc_opl_t * mcp,int bank,mc_flt_stat_t * flt_stat)165925cf1a30Sjl139090 mc_read_ptrl_reg(mc_opl_t *mcp, int bank, mc_flt_stat_t *flt_stat)
166025cf1a30Sjl139090 {
166125cf1a30Sjl139090 flt_stat->mf_cntl = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank)) &
166225cf1a30Sjl139090 MAC_CNTL_PTRL_ERRS;
166325cf1a30Sjl139090 flt_stat->mf_err_add = LD_MAC_REG(MAC_PTRL_ERR_ADD(mcp, bank));
166425cf1a30Sjl139090 flt_stat->mf_err_log = LD_MAC_REG(MAC_PTRL_ERR_LOG(mcp, bank));
166525cf1a30Sjl139090 flt_stat->mf_flt_maddr.ma_bd = mcp->mc_board_num;
1666aeb241b2Sav145390 flt_stat->mf_flt_maddr.ma_phys_bd = mcp->mc_phys_board_num;
166725cf1a30Sjl139090 flt_stat->mf_flt_maddr.ma_bank = bank;
166825cf1a30Sjl139090 flt_stat->mf_flt_maddr.ma_dimm_addr = flt_stat->mf_err_add;
166925cf1a30Sjl139090 }
167025cf1a30Sjl139090
167125cf1a30Sjl139090 static void
mc_read_mi_reg(mc_opl_t * mcp,int bank,mc_flt_stat_t * flt_stat)167225cf1a30Sjl139090 mc_read_mi_reg(mc_opl_t *mcp, int bank, mc_flt_stat_t *flt_stat)
167325cf1a30Sjl139090 {
167425cf1a30Sjl139090 uint32_t status, old_status;
167525cf1a30Sjl139090
1676d8a0cca9Swh31274 status = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank)) & MAC_CNTL_MI_ERRS;
167725cf1a30Sjl139090 old_status = 0;
167825cf1a30Sjl139090
167925cf1a30Sjl139090 /* we keep reading until the status is stable */
168025cf1a30Sjl139090 while (old_status != status) {
168125cf1a30Sjl139090 old_status = status;
1682d8a0cca9Swh31274 flt_stat->mf_err_add = LD_MAC_REG(MAC_MI_ERR_ADD(mcp, bank));
1683d8a0cca9Swh31274 flt_stat->mf_err_log = LD_MAC_REG(MAC_MI_ERR_LOG(mcp, bank));
168425cf1a30Sjl139090 status = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank)) &
168525cf1a30Sjl139090 MAC_CNTL_MI_ERRS;
168625cf1a30Sjl139090 if (status == old_status) {
168725cf1a30Sjl139090 break;
168825cf1a30Sjl139090 }
168925cf1a30Sjl139090 }
169025cf1a30Sjl139090
169125cf1a30Sjl139090 flt_stat->mf_cntl = status;
169225cf1a30Sjl139090 flt_stat->mf_flt_maddr.ma_bd = mcp->mc_board_num;
1693aeb241b2Sav145390 flt_stat->mf_flt_maddr.ma_phys_bd = mcp->mc_phys_board_num;
169425cf1a30Sjl139090 flt_stat->mf_flt_maddr.ma_bank = bank;
169525cf1a30Sjl139090 flt_stat->mf_flt_maddr.ma_dimm_addr = flt_stat->mf_err_add;
169625cf1a30Sjl139090 }
169725cf1a30Sjl139090
169825cf1a30Sjl139090
169925cf1a30Sjl139090 /*
170025cf1a30Sjl139090 * Error philosophy for mirror mode:
170125cf1a30Sjl139090 *
170225cf1a30Sjl139090 * PTRL (The error address for both banks are same, since ptrl stops if it
170325cf1a30Sjl139090 * detects error.)
17041039f409Sav145390 * - Compare error log CMPE.
170525cf1a30Sjl139090 *
170625cf1a30Sjl139090 * - UE-UE Report MUE. No rewrite.
170725cf1a30Sjl139090 *
170825cf1a30Sjl139090 * - UE-* UE-(CE/OK). Rewrite to scrub UE. Report SUE.
170925cf1a30Sjl139090 *
171025cf1a30Sjl139090 * - CE-* CE-(CE/OK). Scrub to determine if CE is permanent.
171125cf1a30Sjl139090 * If CE is permanent, inform SCF. Once for each
171225cf1a30Sjl139090 * Dimm. If CE becomes UE or CMPE, go back to above.
171325cf1a30Sjl139090 *
171425cf1a30Sjl139090 *
171525cf1a30Sjl139090 * MI (The error addresses for each bank are the same or different.)
17161039f409Sav145390 * - Compare error If addresses are the same. Just CMPE, so log CMPE.
171725cf1a30Sjl139090 * If addresses are different (this could happen
17181039f409Sav145390 * as a result of scrubbing. Report each separately.
171925cf1a30Sjl139090 * Only report error info on each side.
172025cf1a30Sjl139090 *
172125cf1a30Sjl139090 * - UE-UE Addresses are the same. Report MUE.
172225cf1a30Sjl139090 * Addresses are different. Report SUE on each bank.
172325cf1a30Sjl139090 * Rewrite to clear UE.
172425cf1a30Sjl139090 *
172525cf1a30Sjl139090 * - UE-* UE-(CE/OK)
172625cf1a30Sjl139090 * Rewrite to clear UE. Report SUE for the bank.
172725cf1a30Sjl139090 *
172825cf1a30Sjl139090 * - CE-* CE-(CE/OK). Scrub to determine if CE is permanent.
172925cf1a30Sjl139090 * If CE becomes UE or CMPE, go back to above.
173025cf1a30Sjl139090 *
173125cf1a30Sjl139090 */
173225cf1a30Sjl139090
173325cf1a30Sjl139090 static int
mc_process_error_mir(mc_opl_t * mcp,mc_aflt_t * mc_aflt,mc_flt_stat_t * flt_stat)173425cf1a30Sjl139090 mc_process_error_mir(mc_opl_t *mcp, mc_aflt_t *mc_aflt, mc_flt_stat_t *flt_stat)
173525cf1a30Sjl139090 {
173625cf1a30Sjl139090 int ptrl_error = mc_aflt->mflt_is_ptrl;
173725cf1a30Sjl139090 int i;
173825cf1a30Sjl139090 int rv = 0;
1739601c2e1eSdhain int bank;
1740601c2e1eSdhain int rewrite_timeout = 0;
174125cf1a30Sjl139090
174225cf1a30Sjl139090 MC_LOG("process mirror errors cntl[0] = %x, cntl[1] = %x\n",
174325cf1a30Sjl139090 flt_stat[0].mf_cntl, flt_stat[1].mf_cntl);
174425cf1a30Sjl139090
174525cf1a30Sjl139090 if (ptrl_error) {
1746d8a0cca9Swh31274 if (((flt_stat[0].mf_cntl | flt_stat[1].mf_cntl) &
1747d8a0cca9Swh31274 MAC_CNTL_PTRL_ERRS) == 0)
174825cf1a30Sjl139090 return (0);
174925cf1a30Sjl139090 } else {
1750d8a0cca9Swh31274 if (((flt_stat[0].mf_cntl | flt_stat[1].mf_cntl) &
1751d8a0cca9Swh31274 MAC_CNTL_MI_ERRS) == 0)
175225cf1a30Sjl139090 return (0);
175325cf1a30Sjl139090 }
175425cf1a30Sjl139090
175525cf1a30Sjl139090 /*
175625cf1a30Sjl139090 * First we take care of the case of CE
175725cf1a30Sjl139090 * because they can become UE or CMPE
175825cf1a30Sjl139090 */
175925cf1a30Sjl139090 for (i = 0; i < 2; i++) {
176025cf1a30Sjl139090 if (IS_CE_ONLY(flt_stat[i].mf_cntl, ptrl_error)) {
1761601c2e1eSdhain bank = flt_stat[i].mf_flt_maddr.ma_bank;
1762601c2e1eSdhain MC_LOG("CE detected on bank %d\n", bank);
1763601c2e1eSdhain mc_scrub_ce(mcp, bank, &flt_stat[i], ptrl_error);
1764601c2e1eSdhain if (MC_REWRITE_ACTIVE(mcp, bank)) {
1765601c2e1eSdhain rewrite_timeout = 1;
1766601c2e1eSdhain }
176725cf1a30Sjl139090 rv = 1;
176825cf1a30Sjl139090 }
176925cf1a30Sjl139090 }
177025cf1a30Sjl139090
1771601c2e1eSdhain if (rewrite_timeout)
1772601c2e1eSdhain return (0);
1773601c2e1eSdhain
177425cf1a30Sjl139090 /* The above scrubbing can turn CE into UE or CMPE */
177525cf1a30Sjl139090
177625cf1a30Sjl139090 /*
177725cf1a30Sjl139090 * Now we distinguish two cases: same address or not
177825cf1a30Sjl139090 * the same address. It might seem more intuitive to
177925cf1a30Sjl139090 * distinguish PTRL v.s. MI error but it is more
178025cf1a30Sjl139090 * complicated that way.
178125cf1a30Sjl139090 */
178225cf1a30Sjl139090
178325cf1a30Sjl139090 if (flt_stat[0].mf_err_add == flt_stat[1].mf_err_add) {
178425cf1a30Sjl139090
178525cf1a30Sjl139090 if (IS_CMPE(flt_stat[0].mf_cntl, ptrl_error) ||
178625cf1a30Sjl139090 IS_CMPE(flt_stat[1].mf_cntl, ptrl_error)) {
178725cf1a30Sjl139090 flt_stat[0].mf_type = FLT_TYPE_CMPE;
178825cf1a30Sjl139090 flt_stat[1].mf_type = FLT_TYPE_CMPE;
178925cf1a30Sjl139090 mc_aflt->mflt_erpt_class = MC_OPL_CMPE;
179025cf1a30Sjl139090 mc_aflt->mflt_nflts = 2;
179125cf1a30Sjl139090 mc_aflt->mflt_stat[0] = &flt_stat[0];
179225cf1a30Sjl139090 mc_aflt->mflt_stat[1] = &flt_stat[1];
179325cf1a30Sjl139090 mc_aflt->mflt_pr = PR_UE;
17941039f409Sav145390 /*
17951039f409Sav145390 * Compare error is result of MAC internal error, so
17961039f409Sav145390 * simply log it instead of publishing an ereport. SCF
17971039f409Sav145390 * diagnoses all the MAC internal and its i/f error.
17981039f409Sav145390 */
17991039f409Sav145390 MC_LOG("cmpe error detected\n");
180025cf1a30Sjl139090 return (1);
180125cf1a30Sjl139090 }
180225cf1a30Sjl139090
180325cf1a30Sjl139090 if (IS_UE(flt_stat[0].mf_cntl, ptrl_error) &&
180425cf1a30Sjl139090 IS_UE(flt_stat[1].mf_cntl, ptrl_error)) {
180525cf1a30Sjl139090 /* Both side are UE's */
180625cf1a30Sjl139090
180725cf1a30Sjl139090 MAC_SET_ERRLOG_INFO(&flt_stat[0]);
180825cf1a30Sjl139090 MAC_SET_ERRLOG_INFO(&flt_stat[1]);
180925cf1a30Sjl139090 MC_LOG("MUE detected\n");
18100cc8ae86Sav145390 flt_stat[0].mf_type = FLT_TYPE_MUE;
18110cc8ae86Sav145390 flt_stat[1].mf_type = FLT_TYPE_MUE;
181225cf1a30Sjl139090 mc_aflt->mflt_erpt_class = MC_OPL_MUE;
181325cf1a30Sjl139090 mc_aflt->mflt_nflts = 2;
181425cf1a30Sjl139090 mc_aflt->mflt_stat[0] = &flt_stat[0];
181525cf1a30Sjl139090 mc_aflt->mflt_stat[1] = &flt_stat[1];
181625cf1a30Sjl139090 mc_aflt->mflt_pr = PR_UE;
181725cf1a30Sjl139090 mc_err_drain(mc_aflt);
181825cf1a30Sjl139090 return (1);
181925cf1a30Sjl139090 }
182025cf1a30Sjl139090
182125cf1a30Sjl139090 /* Now the only case is UE/CE, UE/OK, or don't care */
182225cf1a30Sjl139090 for (i = 0; i < 2; i++) {
1823601c2e1eSdhain if (IS_UE(flt_stat[i].mf_cntl, ptrl_error)) {
18240cc8ae86Sav145390
18250cc8ae86Sav145390 /* rewrite can clear the one side UE error */
18260cc8ae86Sav145390
182725cf1a30Sjl139090 if (IS_OK(flt_stat[i^1].mf_cntl, ptrl_error)) {
182825cf1a30Sjl139090 (void) do_rewrite(mcp,
182925cf1a30Sjl139090 flt_stat[i].mf_flt_maddr.ma_bank,
1830601c2e1eSdhain flt_stat[i].mf_flt_maddr.ma_dimm_addr, 0);
183125cf1a30Sjl139090 }
183225cf1a30Sjl139090 flt_stat[i].mf_type = FLT_TYPE_UE;
183325cf1a30Sjl139090 MAC_SET_ERRLOG_INFO(&flt_stat[i]);
183425cf1a30Sjl139090 mc_aflt->mflt_erpt_class = MC_OPL_SUE;
183525cf1a30Sjl139090 mc_aflt->mflt_stat[0] = &flt_stat[i];
183625cf1a30Sjl139090 mc_aflt->mflt_nflts = 1;
183725cf1a30Sjl139090 mc_aflt->mflt_pr = PR_MCE;
183825cf1a30Sjl139090 mc_err_drain(mc_aflt);
183925cf1a30Sjl139090 /* Once we hit a UE/CE or UE/OK case, done */
184025cf1a30Sjl139090 return (1);
184125cf1a30Sjl139090 }
1842601c2e1eSdhain }
184325cf1a30Sjl139090
184425cf1a30Sjl139090 } else {
184525cf1a30Sjl139090 /*
184625cf1a30Sjl139090 * addresses are different. That means errors
184725cf1a30Sjl139090 * on the 2 banks are not related at all.
184825cf1a30Sjl139090 */
184925cf1a30Sjl139090 for (i = 0; i < 2; i++) {
185025cf1a30Sjl139090 if (IS_CMPE(flt_stat[i].mf_cntl, ptrl_error)) {
185125cf1a30Sjl139090 flt_stat[i].mf_type = FLT_TYPE_CMPE;
185225cf1a30Sjl139090 mc_aflt->mflt_erpt_class = MC_OPL_CMPE;
185325cf1a30Sjl139090 mc_aflt->mflt_nflts = 1;
185425cf1a30Sjl139090 mc_aflt->mflt_stat[0] = &flt_stat[i];
185525cf1a30Sjl139090 mc_aflt->mflt_pr = PR_UE;
18561039f409Sav145390 /*
1857d8a0cca9Swh31274 * Compare error is result of MAC internal
1858d8a0cca9Swh31274 * error, so simply log it instead of
1859d8a0cca9Swh31274 * publishing an ereport. SCF diagnoses all
1860d8a0cca9Swh31274 * the MAC internal and its interface error.
18611039f409Sav145390 */
18621039f409Sav145390 MC_LOG("cmpe error detected\n");
186325cf1a30Sjl139090 /* no more report on this bank */
186425cf1a30Sjl139090 flt_stat[i].mf_cntl = 0;
186525cf1a30Sjl139090 rv = 1;
186625cf1a30Sjl139090 }
186725cf1a30Sjl139090 }
186825cf1a30Sjl139090
18690cc8ae86Sav145390 /* rewrite can clear the one side UE error */
18700cc8ae86Sav145390
187125cf1a30Sjl139090 for (i = 0; i < 2; i++) {
187225cf1a30Sjl139090 if (IS_UE(flt_stat[i].mf_cntl, ptrl_error)) {
187325cf1a30Sjl139090 (void) do_rewrite(mcp,
187425cf1a30Sjl139090 flt_stat[i].mf_flt_maddr.ma_bank,
1875601c2e1eSdhain flt_stat[i].mf_flt_maddr.ma_dimm_addr,
1876601c2e1eSdhain 0);
187725cf1a30Sjl139090 flt_stat[i].mf_type = FLT_TYPE_UE;
187825cf1a30Sjl139090 MAC_SET_ERRLOG_INFO(&flt_stat[i]);
187925cf1a30Sjl139090 mc_aflt->mflt_erpt_class = MC_OPL_SUE;
188025cf1a30Sjl139090 mc_aflt->mflt_stat[0] = &flt_stat[i];
188125cf1a30Sjl139090 mc_aflt->mflt_nflts = 1;
188225cf1a30Sjl139090 mc_aflt->mflt_pr = PR_MCE;
188325cf1a30Sjl139090 mc_err_drain(mc_aflt);
188425cf1a30Sjl139090 rv = 1;
188525cf1a30Sjl139090 }
188625cf1a30Sjl139090 }
188725cf1a30Sjl139090 }
188825cf1a30Sjl139090 return (rv);
188925cf1a30Sjl139090 }
189025cf1a30Sjl139090 static void
mc_error_handler_mir(mc_opl_t * mcp,int bank,mc_rsaddr_info_t * rsaddr)1891738dd194Shyw mc_error_handler_mir(mc_opl_t *mcp, int bank, mc_rsaddr_info_t *rsaddr)
189225cf1a30Sjl139090 {
189325cf1a30Sjl139090 mc_aflt_t mc_aflt;
189425cf1a30Sjl139090 mc_flt_stat_t flt_stat[2], mi_flt_stat[2];
18950cc8ae86Sav145390 int i;
18960cc8ae86Sav145390 int mi_valid;
189725cf1a30Sjl139090
1898738dd194Shyw ASSERT(rsaddr);
1899738dd194Shyw
190025cf1a30Sjl139090 bzero(&mc_aflt, sizeof (mc_aflt_t));
190125cf1a30Sjl139090 bzero(&flt_stat, 2 * sizeof (mc_flt_stat_t));
190225cf1a30Sjl139090 bzero(&mi_flt_stat, 2 * sizeof (mc_flt_stat_t));
190325cf1a30Sjl139090
1904ad59b69dSbm42561
190525cf1a30Sjl139090 mc_aflt.mflt_mcp = mcp;
190625cf1a30Sjl139090 mc_aflt.mflt_id = gethrtime();
190725cf1a30Sjl139090
190825cf1a30Sjl139090 /* Now read all the registers into flt_stat */
190925cf1a30Sjl139090
19100cc8ae86Sav145390 for (i = 0; i < 2; i++) {
191125cf1a30Sjl139090 MC_LOG("Reading registers of bank %d\n", bank);
191225cf1a30Sjl139090 /* patrol registers */
19130cc8ae86Sav145390 mc_read_ptrl_reg(mcp, bank, &flt_stat[i]);
191425cf1a30Sjl139090
1915738dd194Shyw /*
1916738dd194Shyw * In mirror mode, it is possible that only one bank
1917738dd194Shyw * may report the error. We need to check for it to
1918738dd194Shyw * ensure we pick the right addr value for patrol restart.
1919738dd194Shyw * Note that if both banks reported errors, we pick the
1920738dd194Shyw * 2nd one. Both banks should reported the same error address.
1921738dd194Shyw */
1922738dd194Shyw if (flt_stat[i].mf_cntl & MAC_CNTL_PTRL_ERRS)
1923738dd194Shyw rsaddr->mi_restartaddr = flt_stat[i].mf_flt_maddr;
192425cf1a30Sjl139090
192525cf1a30Sjl139090 MC_LOG("ptrl registers cntl %x add %x log %x\n",
1926d8a0cca9Swh31274 flt_stat[i].mf_cntl, flt_stat[i].mf_err_add,
19270cc8ae86Sav145390 flt_stat[i].mf_err_log);
192825cf1a30Sjl139090
192925cf1a30Sjl139090 /* MI registers */
19300cc8ae86Sav145390 mc_read_mi_reg(mcp, bank, &mi_flt_stat[i]);
193125cf1a30Sjl139090
193225cf1a30Sjl139090 MC_LOG("MI registers cntl %x add %x log %x\n",
1933d8a0cca9Swh31274 mi_flt_stat[i].mf_cntl, mi_flt_stat[i].mf_err_add,
19340cc8ae86Sav145390 mi_flt_stat[i].mf_err_log);
193525cf1a30Sjl139090
19360cc8ae86Sav145390 bank = bank^1;
19370cc8ae86Sav145390 }
193825cf1a30Sjl139090
193925cf1a30Sjl139090 /* clear errors once we read all the registers */
1940d8a0cca9Swh31274 MAC_CLEAR_ERRS(mcp, bank, (MAC_CNTL_PTRL_ERRS|MAC_CNTL_MI_ERRS));
194125cf1a30Sjl139090
19420cc8ae86Sav145390 MAC_CLEAR_ERRS(mcp, bank ^ 1, (MAC_CNTL_PTRL_ERRS|MAC_CNTL_MI_ERRS));
194325cf1a30Sjl139090
19440cc8ae86Sav145390 /* Process MI errors first */
194525cf1a30Sjl139090
194625cf1a30Sjl139090 /* if not error mode, cntl1 is 0 */
19470cc8ae86Sav145390 if ((mi_flt_stat[0].mf_err_add & MAC_ERR_ADD_INVALID) ||
19480cc8ae86Sav145390 (mi_flt_stat[0].mf_err_log & MAC_ERR_LOG_INVALID))
19490cc8ae86Sav145390 mi_flt_stat[0].mf_cntl = 0;
19500cc8ae86Sav145390
19510cc8ae86Sav145390 if ((mi_flt_stat[1].mf_err_add & MAC_ERR_ADD_INVALID) ||
19520cc8ae86Sav145390 (mi_flt_stat[1].mf_err_log & MAC_ERR_LOG_INVALID))
19530cc8ae86Sav145390 mi_flt_stat[1].mf_cntl = 0;
19540cc8ae86Sav145390
19550cc8ae86Sav145390 mc_aflt.mflt_is_ptrl = 0;
19560cc8ae86Sav145390 mi_valid = mc_process_error_mir(mcp, &mc_aflt, &mi_flt_stat[0]);
19570cc8ae86Sav145390
19580cc8ae86Sav145390 if ((((flt_stat[0].mf_cntl & MAC_CNTL_PTRL_ERRS) >>
1959d8a0cca9Swh31274 MAC_CNTL_PTRL_ERR_SHIFT) == ((mi_flt_stat[0].mf_cntl &
1960d8a0cca9Swh31274 MAC_CNTL_MI_ERRS) >> MAC_CNTL_MI_ERR_SHIFT)) &&
19610b240fcdSwh31274 (flt_stat[0].mf_err_add ==
19620b240fcdSwh31274 ROUNDDOWN(mi_flt_stat[0].mf_err_add, MC_BOUND_BYTE)) &&
19630cc8ae86Sav145390 (((flt_stat[1].mf_cntl & MAC_CNTL_PTRL_ERRS) >>
1964d8a0cca9Swh31274 MAC_CNTL_PTRL_ERR_SHIFT) == ((mi_flt_stat[1].mf_cntl &
1965d8a0cca9Swh31274 MAC_CNTL_MI_ERRS) >> MAC_CNTL_MI_ERR_SHIFT)) &&
19660b240fcdSwh31274 (flt_stat[1].mf_err_add ==
19670b240fcdSwh31274 ROUNDDOWN(mi_flt_stat[1].mf_err_add, MC_BOUND_BYTE))) {
19680cc8ae86Sav145390 #ifdef DEBUG
19690cc8ae86Sav145390 MC_LOG("discarding PTRL error because "
19700cc8ae86Sav145390 "it is the same as MI\n");
19710cc8ae86Sav145390 #endif
1972738dd194Shyw rsaddr->mi_valid = mi_valid;
19730cc8ae86Sav145390 return;
19740cc8ae86Sav145390 }
19750cc8ae86Sav145390 /* if not error mode, cntl1 is 0 */
197625cf1a30Sjl139090 if ((flt_stat[0].mf_err_add & MAC_ERR_ADD_INVALID) ||
197725cf1a30Sjl139090 (flt_stat[0].mf_err_log & MAC_ERR_LOG_INVALID))
197825cf1a30Sjl139090 flt_stat[0].mf_cntl = 0;
197925cf1a30Sjl139090
198025cf1a30Sjl139090 if ((flt_stat[1].mf_err_add & MAC_ERR_ADD_INVALID) ||
198125cf1a30Sjl139090 (flt_stat[1].mf_err_log & MAC_ERR_LOG_INVALID))
198225cf1a30Sjl139090 flt_stat[1].mf_cntl = 0;
198325cf1a30Sjl139090
198425cf1a30Sjl139090 mc_aflt.mflt_is_ptrl = 1;
1985738dd194Shyw rsaddr->mi_valid = mc_process_error_mir(mcp, &mc_aflt, &flt_stat[0]);
198625cf1a30Sjl139090 }
198725cf1a30Sjl139090 static int
mc_process_error(mc_opl_t * mcp,int bank,mc_aflt_t * mc_aflt,mc_flt_stat_t * flt_stat)198825cf1a30Sjl139090 mc_process_error(mc_opl_t *mcp, int bank, mc_aflt_t *mc_aflt,
198925cf1a30Sjl139090 mc_flt_stat_t *flt_stat)
199025cf1a30Sjl139090 {
199125cf1a30Sjl139090 int ptrl_error = mc_aflt->mflt_is_ptrl;
199225cf1a30Sjl139090 int rv = 0;
199325cf1a30Sjl139090
199425cf1a30Sjl139090 mc_aflt->mflt_erpt_class = NULL;
199525cf1a30Sjl139090 if (IS_UE(flt_stat->mf_cntl, ptrl_error)) {
19961039f409Sav145390 MC_LOG("UE detected\n");
199725cf1a30Sjl139090 flt_stat->mf_type = FLT_TYPE_UE;
199825cf1a30Sjl139090 mc_aflt->mflt_erpt_class = MC_OPL_UE;
199925cf1a30Sjl139090 mc_aflt->mflt_pr = PR_UE;
200025cf1a30Sjl139090 MAC_SET_ERRLOG_INFO(flt_stat);
200125cf1a30Sjl139090 rv = 1;
200225cf1a30Sjl139090 } else if (IS_CE(flt_stat->mf_cntl, ptrl_error)) {
20031039f409Sav145390 MC_LOG("CE detected\n");
200425cf1a30Sjl139090 MAC_SET_ERRLOG_INFO(flt_stat);
200525cf1a30Sjl139090
20061039f409Sav145390 /* Error type can change after scrubbing */
200725cf1a30Sjl139090 mc_scrub_ce(mcp, bank, flt_stat, ptrl_error);
2008601c2e1eSdhain if (MC_REWRITE_ACTIVE(mcp, bank)) {
2009601c2e1eSdhain return (0);
2010601c2e1eSdhain }
201125cf1a30Sjl139090
2012056c948bStsien if (flt_stat->mf_type == FLT_TYPE_INTERMITTENT_CE) {
2013056c948bStsien mc_aflt->mflt_erpt_class = MC_OPL_ICE;
2014056c948bStsien mc_aflt->mflt_pr = PR_MCE;
2015056c948bStsien } else if (flt_stat->mf_type == FLT_TYPE_PERMANENT_CE) {
201625cf1a30Sjl139090 mc_aflt->mflt_erpt_class = MC_OPL_CE;
201725cf1a30Sjl139090 mc_aflt->mflt_pr = PR_MCE;
201825cf1a30Sjl139090 } else if (flt_stat->mf_type == FLT_TYPE_UE) {
201925cf1a30Sjl139090 mc_aflt->mflt_erpt_class = MC_OPL_UE;
202025cf1a30Sjl139090 mc_aflt->mflt_pr = PR_UE;
202125cf1a30Sjl139090 }
202225cf1a30Sjl139090 rv = 1;
202325cf1a30Sjl139090 }
2024d8a0cca9Swh31274 MC_LOG("mc_process_error: fault type %x erpt %s\n", flt_stat->mf_type,
202525cf1a30Sjl139090 mc_aflt->mflt_erpt_class);
202625cf1a30Sjl139090 if (mc_aflt->mflt_erpt_class) {
202725cf1a30Sjl139090 mc_aflt->mflt_stat[0] = flt_stat;
202825cf1a30Sjl139090 mc_aflt->mflt_nflts = 1;
202925cf1a30Sjl139090 mc_err_drain(mc_aflt);
203025cf1a30Sjl139090 }
203125cf1a30Sjl139090 return (rv);
203225cf1a30Sjl139090 }
203325cf1a30Sjl139090
203425cf1a30Sjl139090 static void
mc_error_handler(mc_opl_t * mcp,int bank,mc_rsaddr_info_t * rsaddr)2035738dd194Shyw mc_error_handler(mc_opl_t *mcp, int bank, mc_rsaddr_info_t *rsaddr)
203625cf1a30Sjl139090 {
203725cf1a30Sjl139090 mc_aflt_t mc_aflt;
203825cf1a30Sjl139090 mc_flt_stat_t flt_stat, mi_flt_stat;
20390cc8ae86Sav145390 int mi_valid;
204025cf1a30Sjl139090
204125cf1a30Sjl139090 bzero(&mc_aflt, sizeof (mc_aflt_t));
204225cf1a30Sjl139090 bzero(&flt_stat, sizeof (mc_flt_stat_t));
204325cf1a30Sjl139090 bzero(&mi_flt_stat, sizeof (mc_flt_stat_t));
204425cf1a30Sjl139090
204525cf1a30Sjl139090 mc_aflt.mflt_mcp = mcp;
204625cf1a30Sjl139090 mc_aflt.mflt_id = gethrtime();
204725cf1a30Sjl139090
204825cf1a30Sjl139090 /* patrol registers */
204925cf1a30Sjl139090 mc_read_ptrl_reg(mcp, bank, &flt_stat);
205025cf1a30Sjl139090
2051738dd194Shyw ASSERT(rsaddr);
2052738dd194Shyw rsaddr->mi_restartaddr = flt_stat.mf_flt_maddr;
205325cf1a30Sjl139090
2054d8a0cca9Swh31274 MC_LOG("ptrl registers cntl %x add %x log %x\n", flt_stat.mf_cntl,
2055d8a0cca9Swh31274 flt_stat.mf_err_add, flt_stat.mf_err_log);
205625cf1a30Sjl139090
205725cf1a30Sjl139090 /* MI registers */
205825cf1a30Sjl139090 mc_read_mi_reg(mcp, bank, &mi_flt_stat);
205925cf1a30Sjl139090
20600cc8ae86Sav145390
2061d8a0cca9Swh31274 MC_LOG("MI registers cntl %x add %x log %x\n", mi_flt_stat.mf_cntl,
2062d8a0cca9Swh31274 mi_flt_stat.mf_err_add, mi_flt_stat.mf_err_log);
206325cf1a30Sjl139090
206425cf1a30Sjl139090 /* clear errors once we read all the registers */
206525cf1a30Sjl139090 MAC_CLEAR_ERRS(mcp, bank, (MAC_CNTL_PTRL_ERRS|MAC_CNTL_MI_ERRS));
206625cf1a30Sjl139090
20670cc8ae86Sav145390 mc_aflt.mflt_is_ptrl = 0;
20680cc8ae86Sav145390 if ((mi_flt_stat.mf_cntl & MAC_CNTL_MI_ERRS) &&
20690cc8ae86Sav145390 ((mi_flt_stat.mf_err_add & MAC_ERR_ADD_INVALID) == 0) &&
20700cc8ae86Sav145390 ((mi_flt_stat.mf_err_log & MAC_ERR_LOG_INVALID) == 0)) {
20710cc8ae86Sav145390 mi_valid = mc_process_error(mcp, bank, &mc_aflt, &mi_flt_stat);
20720cc8ae86Sav145390 }
20730cc8ae86Sav145390
20740cc8ae86Sav145390 if ((((flt_stat.mf_cntl & MAC_CNTL_PTRL_ERRS) >>
2075d8a0cca9Swh31274 MAC_CNTL_PTRL_ERR_SHIFT) == ((mi_flt_stat.mf_cntl &
2076d8a0cca9Swh31274 MAC_CNTL_MI_ERRS) >> MAC_CNTL_MI_ERR_SHIFT)) &&
20770b240fcdSwh31274 (flt_stat.mf_err_add ==
20780b240fcdSwh31274 ROUNDDOWN(mi_flt_stat.mf_err_add, MC_BOUND_BYTE))) {
20790cc8ae86Sav145390 #ifdef DEBUG
20800cc8ae86Sav145390 MC_LOG("discarding PTRL error because "
20810cc8ae86Sav145390 "it is the same as MI\n");
20820cc8ae86Sav145390 #endif
2083738dd194Shyw rsaddr->mi_valid = mi_valid;
20840cc8ae86Sav145390 return;
20850cc8ae86Sav145390 }
20860cc8ae86Sav145390
208725cf1a30Sjl139090 mc_aflt.mflt_is_ptrl = 1;
208825cf1a30Sjl139090 if ((flt_stat.mf_cntl & MAC_CNTL_PTRL_ERRS) &&
208925cf1a30Sjl139090 ((flt_stat.mf_err_add & MAC_ERR_ADD_INVALID) == 0) &&
209025cf1a30Sjl139090 ((flt_stat.mf_err_log & MAC_ERR_LOG_INVALID) == 0)) {
2091d8a0cca9Swh31274 rsaddr->mi_valid = mc_process_error(mcp, bank, &mc_aflt,
2092d8a0cca9Swh31274 &flt_stat);
209325cf1a30Sjl139090 }
209425cf1a30Sjl139090 }
209525cf1a30Sjl139090 /*
209625cf1a30Sjl139090 * memory patrol error handling algorithm:
209725cf1a30Sjl139090 * timeout() is used to do periodic polling
209825cf1a30Sjl139090 * This is the flow chart.
209925cf1a30Sjl139090 * timeout ->
210025cf1a30Sjl139090 * mc_check_errors()
210125cf1a30Sjl139090 * if memory bank is installed, read the status register
210225cf1a30Sjl139090 * if any error bit is set,
210325cf1a30Sjl139090 * -> mc_error_handler()
21041039f409Sav145390 * -> read all error registers
210525cf1a30Sjl139090 * -> mc_process_error()
210625cf1a30Sjl139090 * determine error type
210725cf1a30Sjl139090 * rewrite to clear error or scrub to determine CE type
210825cf1a30Sjl139090 * inform SCF on permanent CE
210925cf1a30Sjl139090 * -> mc_err_drain
211025cf1a30Sjl139090 * page offline processing
211125cf1a30Sjl139090 * -> mc_ereport_post()
211225cf1a30Sjl139090 */
211325cf1a30Sjl139090
211425cf1a30Sjl139090 static void
mc_process_rewrite(mc_opl_t * mcp,int bank)2115601c2e1eSdhain mc_process_rewrite(mc_opl_t *mcp, int bank)
2116601c2e1eSdhain {
2117601c2e1eSdhain uint32_t rew_addr, cntl;
2118601c2e1eSdhain mc_retry_info_t *retry;
2119601c2e1eSdhain struct mc_bank *bankp;
2120601c2e1eSdhain
2121601c2e1eSdhain bankp = &(mcp->mc_bank[bank]);
2122601c2e1eSdhain retry = bankp->mcb_active;
2123601c2e1eSdhain if (retry == NULL)
2124601c2e1eSdhain return;
2125601c2e1eSdhain
2126601c2e1eSdhain if (retry->ri_state <= RETRY_STATE_ACTIVE) {
2127601c2e1eSdhain cntl = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank));
2128601c2e1eSdhain if (cntl & MAC_CNTL_PTRL_STATUS)
2129601c2e1eSdhain return;
2130601c2e1eSdhain rew_addr = retry->ri_addr;
2131601c2e1eSdhain ST_MAC_REG(MAC_REWRITE_ADD(mcp, bank), rew_addr);
2132601c2e1eSdhain MAC_REW_REQ(mcp, bank);
2133601c2e1eSdhain
2134601c2e1eSdhain retry->ri_state = RETRY_STATE_REWRITE;
2135601c2e1eSdhain }
2136601c2e1eSdhain
2137601c2e1eSdhain cntl = ldphysio(MAC_PTRL_CNTL(mcp, bank));
2138601c2e1eSdhain
2139601c2e1eSdhain if (cntl & MAC_CNTL_REW_END) {
2140601c2e1eSdhain MAC_CLEAR_ERRS(mcp, bank,
2141601c2e1eSdhain MAC_CNTL_REW_ERRS);
2142601c2e1eSdhain mc_clear_rewrite(mcp, bank);
2143601c2e1eSdhain } else {
2144601c2e1eSdhain /*
2145601c2e1eSdhain * If the rewrite does not complete in
2146601c2e1eSdhain * 1 hour, we have to consider this a HW
2147601c2e1eSdhain * failure. However, there is no recovery
2148601c2e1eSdhain * mechanism. The only thing we can do
2149601c2e1eSdhain * to to print a warning message to the
2150601c2e1eSdhain * console. We continue to increment the
2151601c2e1eSdhain * counter but we only print the message
2152601c2e1eSdhain * once. It will take the counter a long
2153601c2e1eSdhain * time to wrap around and the user might
2154601c2e1eSdhain * see a second message. In practice,
2155601c2e1eSdhain * we have never hit this condition but
2156601c2e1eSdhain * we have to keep the code here just in case.
2157601c2e1eSdhain */
2158601c2e1eSdhain if (++mcp->mc_bank[bank].mcb_rewrite_count
2159601c2e1eSdhain == mc_max_rewrite_retry) {
2160601c2e1eSdhain cmn_err(CE_WARN, "Memory patrol feature is"
2161601c2e1eSdhain " partly suspended on /LSB%d/B%d"
2162601c2e1eSdhain " due to heavy memory load,"
2163601c2e1eSdhain " and it will restart"
2164601c2e1eSdhain " automatically.\n", mcp->mc_board_num,
2165601c2e1eSdhain bank);
2166601c2e1eSdhain }
2167601c2e1eSdhain }
2168601c2e1eSdhain }
2169601c2e1eSdhain
2170601c2e1eSdhain static void
mc_check_errors_func(mc_opl_t * mcp)217125cf1a30Sjl139090 mc_check_errors_func(mc_opl_t *mcp)
217225cf1a30Sjl139090 {
2173738dd194Shyw mc_rsaddr_info_t rsaddr_info;
217425cf1a30Sjl139090 int i, error_count = 0;
217525cf1a30Sjl139090 uint32_t stat, cntl;
21760cc8ae86Sav145390 int running;
2177cfb9e062Shyw int wrapped;
217837afe445Shyw int ebk;
217925cf1a30Sjl139090
218025cf1a30Sjl139090 /*
218125cf1a30Sjl139090 * scan errors.
218225cf1a30Sjl139090 */
21830cc8ae86Sav145390 if (mcp->mc_status & MC_MEMORYLESS)
21840cc8ae86Sav145390 return;
21850cc8ae86Sav145390
218625cf1a30Sjl139090 for (i = 0; i < BANKNUM_PER_SB; i++) {
218725cf1a30Sjl139090 if (mcp->mc_bank[i].mcb_status & BANK_INSTALLED) {
2188601c2e1eSdhain if (MC_REWRITE_ACTIVE(mcp, i)) {
2189601c2e1eSdhain mc_process_rewrite(mcp, i);
2190601c2e1eSdhain }
219125cf1a30Sjl139090 stat = ldphysio(MAC_PTRL_STAT(mcp, i));
219225cf1a30Sjl139090 cntl = ldphysio(MAC_PTRL_CNTL(mcp, i));
21930cc8ae86Sav145390 running = cntl & MAC_CNTL_PTRL_START;
2194cfb9e062Shyw wrapped = cntl & MAC_CNTL_PTRL_ADD_MAX;
21950cc8ae86Sav145390
219637afe445Shyw /* Compute the effective bank idx */
219737afe445Shyw ebk = (IS_MIRROR(mcp, i)) ? MIRROR_IDX(i) : i;
219837afe445Shyw
2199cfb9e062Shyw if (mc_debug_show_all || stat) {
2200cfb9e062Shyw MC_LOG("/LSB%d/B%d stat %x cntl %x\n",
2201d8a0cca9Swh31274 mcp->mc_board_num, i, stat, cntl);
2202cfb9e062Shyw }
2203cfb9e062Shyw
2204cfb9e062Shyw /*
2205cfb9e062Shyw * Update stats and reset flag if the HW patrol
2206cfb9e062Shyw * wrapped around in its scan.
2207cfb9e062Shyw */
2208cfb9e062Shyw if (wrapped) {
220925cf1a30Sjl139090 MAC_CLEAR_MAX(mcp, i);
221037afe445Shyw mcp->mc_period[ebk]++;
221178ed97a7Sjl139090 if (IS_MIRROR(mcp, i)) {
221237afe445Shyw MC_LOG("mirror mc period %ld on "
221337afe445Shyw "/LSB%d/B%d\n", mcp->mc_period[ebk],
221437afe445Shyw mcp->mc_board_num, i);
221578ed97a7Sjl139090 } else {
221637afe445Shyw MC_LOG("mc period %ld on "
221737afe445Shyw "/LSB%d/B%d\n", mcp->mc_period[ebk],
221837afe445Shyw mcp->mc_board_num, i);
221937afe445Shyw }
2220cfb9e062Shyw }
2221cfb9e062Shyw
2222cfb9e062Shyw if (running) {
2223cfb9e062Shyw /*
2224cfb9e062Shyw * Mac patrol HW is still running.
2225cfb9e062Shyw * Normally when an error is detected,
2226cfb9e062Shyw * the HW patrol will stop so that we
2227cfb9e062Shyw * can collect error data for reporting.
2228cfb9e062Shyw * Certain errors (MI errors) detected may not
2229cfb9e062Shyw * cause the HW patrol to stop which is a
2230cfb9e062Shyw * problem since we cannot read error data while
2231cfb9e062Shyw * the HW patrol is running. SW is not allowed
2232cfb9e062Shyw * to stop the HW patrol while it is running
2233cfb9e062Shyw * as it may cause HW inconsistency. This is
2234cfb9e062Shyw * described in a HW errata.
2235cfb9e062Shyw * In situations where we detected errors
2236cfb9e062Shyw * that may not cause the HW patrol to stop.
2237cfb9e062Shyw * We speed up the HW patrol scanning in
2238cfb9e062Shyw * the hope that it will find the 'real' PTRL
2239cfb9e062Shyw * errors associated with the previous errors
2240cfb9e062Shyw * causing the HW to finally stop so that we
2241cfb9e062Shyw * can do the reporting.
2242cfb9e062Shyw */
2243cfb9e062Shyw /*
2244cfb9e062Shyw * Check to see if we did speed up
2245cfb9e062Shyw * the HW patrol due to previous errors
2246cfb9e062Shyw * detected that did not cause the patrol
2247cfb9e062Shyw * to stop. We only do it if HW patrol scan
2248cfb9e062Shyw * wrapped (counted as completing a 'period').
2249cfb9e062Shyw */
225037afe445Shyw if (mcp->mc_speedup_period[ebk] > 0) {
2251cfb9e062Shyw if (wrapped &&
2252d8a0cca9Swh31274 (--mcp->mc_speedup_period[ebk] ==
2253d8a0cca9Swh31274 0)) {
2254cfb9e062Shyw /*
2255cfb9e062Shyw * We did try to speed up.
2256d8a0cca9Swh31274 * The speed up period has
2257d8a0cca9Swh31274 * expired and the HW patrol
2258d8a0cca9Swh31274 * is still running. The
2259d8a0cca9Swh31274 * errors must be intermittent.
2260d8a0cca9Swh31274 * We have no choice but to
2261d8a0cca9Swh31274 * ignore them, reset the scan
2262d8a0cca9Swh31274 * speed to normal and clear
2263d8a0cca9Swh31274 * the MI error bits. For
2264d8a0cca9Swh31274 * mirror mode, we need to
2265d8a0cca9Swh31274 * clear errors on both banks.
2266cfb9e062Shyw */
2267cfb9e062Shyw MC_LOG("Clearing MI errors\n");
2268cfb9e062Shyw MAC_CLEAR_ERRS(mcp, i,
2269cfb9e062Shyw MAC_CNTL_MI_ERRS);
227037afe445Shyw
227137afe445Shyw if (IS_MIRROR(mcp, i)) {
2272d8a0cca9Swh31274 MC_LOG("Clearing "
2273d8a0cca9Swh31274 "Mirror MI errs\n");
2274d8a0cca9Swh31274 MAC_CLEAR_ERRS(mcp,
2275d8a0cca9Swh31274 i^1,
227637afe445Shyw MAC_CNTL_MI_ERRS);
227737afe445Shyw }
22780cc8ae86Sav145390 }
2279cfb9e062Shyw } else if (stat & MAC_STAT_MI_ERRS) {
2280cfb9e062Shyw /*
2281cfb9e062Shyw * MI errors detected but we cannot
2282cfb9e062Shyw * report them since the HW patrol
2283cfb9e062Shyw * is still running.
2284cfb9e062Shyw * We will attempt to speed up the
2285cfb9e062Shyw * scanning and hopefully the HW
2286cfb9e062Shyw * can detect PRTL errors at the same
2287cfb9e062Shyw * location that cause the HW patrol
2288cfb9e062Shyw * to stop.
2289cfb9e062Shyw */
229037afe445Shyw mcp->mc_speedup_period[ebk] = 2;
22910cc8ae86Sav145390 MAC_CMD(mcp, i, 0);
2292cfb9e062Shyw }
2293cfb9e062Shyw } else if (stat & (MAC_STAT_PTRL_ERRS |
2294cfb9e062Shyw MAC_STAT_MI_ERRS)) {
2295cfb9e062Shyw /*
2296cfb9e062Shyw * HW Patrol has stopped and we found errors.
2297cfb9e062Shyw * Proceed to collect and report error info.
2298cfb9e062Shyw */
229937afe445Shyw mcp->mc_speedup_period[ebk] = 0;
2300738dd194Shyw rsaddr_info.mi_valid = 0;
2301738dd194Shyw rsaddr_info.mi_injectrestart = 0;
2302738dd194Shyw if (IS_MIRROR(mcp, i)) {
2303d8a0cca9Swh31274 mc_error_handler_mir(mcp, i,
2304d8a0cca9Swh31274 &rsaddr_info);
2305738dd194Shyw } else {
2306738dd194Shyw mc_error_handler(mcp, i, &rsaddr_info);
2307738dd194Shyw }
230825cf1a30Sjl139090
230925cf1a30Sjl139090 error_count++;
231007d06da5SSurya Prakki (void) restart_patrol(mcp, i, &rsaddr_info);
231125cf1a30Sjl139090 } else {
2312cfb9e062Shyw /*
2313cfb9e062Shyw * HW patrol scan has apparently stopped
2314cfb9e062Shyw * but no errors detected/flagged.
2315cfb9e062Shyw * Restart the HW patrol just to be sure.
231637afe445Shyw * In mirror mode, the odd bank might have
231737afe445Shyw * reported errors that caused the patrol to
231837afe445Shyw * stop. We'll defer the restart to the odd
231937afe445Shyw * bank in this case.
2320cfb9e062Shyw */
232137afe445Shyw if (!IS_MIRROR(mcp, i) || (i & 0x1))
232207d06da5SSurya Prakki (void) restart_patrol(mcp, i, NULL);
232325cf1a30Sjl139090 }
232425cf1a30Sjl139090 }
232525cf1a30Sjl139090 }
232625cf1a30Sjl139090 if (error_count > 0)
232725cf1a30Sjl139090 mcp->mc_last_error += error_count;
232825cf1a30Sjl139090 else
232925cf1a30Sjl139090 mcp->mc_last_error = 0;
233025cf1a30Sjl139090 }
233125cf1a30Sjl139090
23320cc8ae86Sav145390 /*
23330cc8ae86Sav145390 * mc_polling -- Check errors for only one instance,
23340cc8ae86Sav145390 * but process errors for all instances to make sure we drain the errors
23350cc8ae86Sav145390 * faster than they can be accumulated.
23360cc8ae86Sav145390 *
23370cc8ae86Sav145390 * Polling on each board should be done only once per each
23380cc8ae86Sav145390 * mc_patrol_interval_sec. This is equivalent to setting mc_tick_left
23390cc8ae86Sav145390 * to OPL_MAX_BOARDS and decrement by 1 on each timeout.
23400cc8ae86Sav145390 * Once mc_tick_left becomes negative, the board becomes a candidate
23410cc8ae86Sav145390 * for polling because it has waited for at least
23420cc8ae86Sav145390 * mc_patrol_interval_sec's long. If mc_timeout_period is calculated
23430cc8ae86Sav145390 * differently, this has to be updated accordingly.
23440cc8ae86Sav145390 */
234525cf1a30Sjl139090
234625cf1a30Sjl139090 static void
mc_polling(void)23470cc8ae86Sav145390 mc_polling(void)
234825cf1a30Sjl139090 {
23490cc8ae86Sav145390 int i, scan_error;
23500cc8ae86Sav145390 mc_opl_t *mcp;
235125cf1a30Sjl139090
235225cf1a30Sjl139090
23530cc8ae86Sav145390 scan_error = 1;
23540cc8ae86Sav145390 for (i = 0; i < OPL_MAX_BOARDS; i++) {
23550cc8ae86Sav145390 mutex_enter(&mcmutex);
23560cc8ae86Sav145390 if ((mcp = mc_instances[i]) == NULL) {
23570cc8ae86Sav145390 mutex_exit(&mcmutex);
23580cc8ae86Sav145390 continue;
235925cf1a30Sjl139090 }
23600cc8ae86Sav145390 mutex_enter(&mcp->mc_lock);
23610cc8ae86Sav145390 mutex_exit(&mcmutex);
2362738dd194Shyw if (!(mcp->mc_status & MC_POLL_RUNNING)) {
2363738dd194Shyw mutex_exit(&mcp->mc_lock);
2364738dd194Shyw continue;
2365738dd194Shyw }
23660cc8ae86Sav145390 if (scan_error && mcp->mc_tick_left <= 0) {
23670cc8ae86Sav145390 mc_check_errors_func((void *)mcp);
23680cc8ae86Sav145390 mcp->mc_tick_left = OPL_MAX_BOARDS;
23690cc8ae86Sav145390 scan_error = 0;
23700cc8ae86Sav145390 } else {
23710cc8ae86Sav145390 mcp->mc_tick_left--;
23720cc8ae86Sav145390 }
23730cc8ae86Sav145390 mc_process_scf_log(mcp);
237425cf1a30Sjl139090 mutex_exit(&mcp->mc_lock);
237525cf1a30Sjl139090 }
23760cc8ae86Sav145390 }
237725cf1a30Sjl139090
237825cf1a30Sjl139090 static void
get_ptrl_start_address(mc_opl_t * mcp,int bank,mc_addr_t * maddr)237925cf1a30Sjl139090 get_ptrl_start_address(mc_opl_t *mcp, int bank, mc_addr_t *maddr)
238025cf1a30Sjl139090 {
238125cf1a30Sjl139090 maddr->ma_bd = mcp->mc_board_num;
238225cf1a30Sjl139090 maddr->ma_bank = bank;
238325cf1a30Sjl139090 maddr->ma_dimm_addr = 0;
238425cf1a30Sjl139090 }
238525cf1a30Sjl139090
238625cf1a30Sjl139090 typedef struct mc_mem_range {
238725cf1a30Sjl139090 uint64_t addr;
238825cf1a30Sjl139090 uint64_t size;
238925cf1a30Sjl139090 } mc_mem_range_t;
239025cf1a30Sjl139090
239125cf1a30Sjl139090 static int
get_base_address(mc_opl_t * mcp)239225cf1a30Sjl139090 get_base_address(mc_opl_t *mcp)
239325cf1a30Sjl139090 {
239425cf1a30Sjl139090 mc_mem_range_t *mem_range;
239525cf1a30Sjl139090 int len;
239625cf1a30Sjl139090
239725cf1a30Sjl139090 if (ddi_getlongprop(DDI_DEV_T_ANY, mcp->mc_dip, DDI_PROP_DONTPASS,
239825cf1a30Sjl139090 "sb-mem-ranges", (caddr_t)&mem_range, &len) != DDI_SUCCESS) {
239925cf1a30Sjl139090 return (DDI_FAILURE);
240025cf1a30Sjl139090 }
240125cf1a30Sjl139090
240225cf1a30Sjl139090 mcp->mc_start_address = mem_range->addr;
240325cf1a30Sjl139090 mcp->mc_size = mem_range->size;
240425cf1a30Sjl139090
240525cf1a30Sjl139090 kmem_free(mem_range, len);
240625cf1a30Sjl139090 return (DDI_SUCCESS);
240725cf1a30Sjl139090 }
240825cf1a30Sjl139090
240925cf1a30Sjl139090 struct mc_addr_spec {
241025cf1a30Sjl139090 uint32_t bank;
241125cf1a30Sjl139090 uint32_t phys_hi;
241225cf1a30Sjl139090 uint32_t phys_lo;
241325cf1a30Sjl139090 };
241425cf1a30Sjl139090
241525cf1a30Sjl139090 #define REGS_PA(m, i) ((((uint64_t)m[i].phys_hi)<<32) | m[i].phys_lo)
241625cf1a30Sjl139090
241725cf1a30Sjl139090 static char *mc_tbl_name[] = {
241825cf1a30Sjl139090 "cs0-mc-pa-trans-table",
241925cf1a30Sjl139090 "cs1-mc-pa-trans-table"
242025cf1a30Sjl139090 };
242125cf1a30Sjl139090
2422738dd194Shyw /*
2423738dd194Shyw * This routine performs a rangecheck for a given PA
2424738dd194Shyw * to see if it belongs to the memory range for this board.
2425738dd194Shyw * Return 1 if it is valid (within the range) and 0 otherwise
2426738dd194Shyw */
242725cf1a30Sjl139090 static int
mc_rangecheck_pa(mc_opl_t * mcp,uint64_t pa)2428738dd194Shyw mc_rangecheck_pa(mc_opl_t *mcp, uint64_t pa)
242925cf1a30Sjl139090 {
2430d8a0cca9Swh31274 if ((pa < mcp->mc_start_address) || (mcp->mc_start_address +
2431d8a0cca9Swh31274 mcp->mc_size <= pa))
243225cf1a30Sjl139090 return (0);
2433738dd194Shyw else
2434738dd194Shyw return (1);
243525cf1a30Sjl139090 }
243625cf1a30Sjl139090
243725cf1a30Sjl139090 static void
mc_memlist_delete(struct memlist * mlist)243825cf1a30Sjl139090 mc_memlist_delete(struct memlist *mlist)
243925cf1a30Sjl139090 {
244025cf1a30Sjl139090 struct memlist *ml;
244125cf1a30Sjl139090
244225cf1a30Sjl139090 for (ml = mlist; ml; ml = mlist) {
244356f33205SJonathan Adams mlist = ml->ml_next;
244425cf1a30Sjl139090 kmem_free(ml, sizeof (struct memlist));
244525cf1a30Sjl139090 }
244625cf1a30Sjl139090 }
244725cf1a30Sjl139090
244825cf1a30Sjl139090 static struct memlist *
mc_memlist_dup(struct memlist * mlist)244925cf1a30Sjl139090 mc_memlist_dup(struct memlist *mlist)
245025cf1a30Sjl139090 {
245125cf1a30Sjl139090 struct memlist *hl = NULL, *tl, **mlp;
245225cf1a30Sjl139090
245325cf1a30Sjl139090 if (mlist == NULL)
245425cf1a30Sjl139090 return (NULL);
245525cf1a30Sjl139090
245625cf1a30Sjl139090 mlp = &hl;
245725cf1a30Sjl139090 tl = *mlp;
245856f33205SJonathan Adams for (; mlist; mlist = mlist->ml_next) {
245925cf1a30Sjl139090 *mlp = kmem_alloc(sizeof (struct memlist), KM_SLEEP);
246056f33205SJonathan Adams (*mlp)->ml_address = mlist->ml_address;
246156f33205SJonathan Adams (*mlp)->ml_size = mlist->ml_size;
246256f33205SJonathan Adams (*mlp)->ml_prev = tl;
246325cf1a30Sjl139090 tl = *mlp;
246456f33205SJonathan Adams mlp = &((*mlp)->ml_next);
246525cf1a30Sjl139090 }
246625cf1a30Sjl139090 *mlp = NULL;
246725cf1a30Sjl139090
246825cf1a30Sjl139090 return (hl);
246925cf1a30Sjl139090 }
247025cf1a30Sjl139090
247125cf1a30Sjl139090
247225cf1a30Sjl139090 static struct memlist *
mc_memlist_del_span(struct memlist * mlist,uint64_t base,uint64_t len)247325cf1a30Sjl139090 mc_memlist_del_span(struct memlist *mlist, uint64_t base, uint64_t len)
247425cf1a30Sjl139090 {
247525cf1a30Sjl139090 uint64_t end;
247625cf1a30Sjl139090 struct memlist *ml, *tl, *nlp;
247725cf1a30Sjl139090
247825cf1a30Sjl139090 if (mlist == NULL)
247925cf1a30Sjl139090 return (NULL);
248025cf1a30Sjl139090
248125cf1a30Sjl139090 end = base + len;
248256f33205SJonathan Adams if ((end <= mlist->ml_address) || (base == end))
248325cf1a30Sjl139090 return (mlist);
248425cf1a30Sjl139090
248525cf1a30Sjl139090 for (tl = ml = mlist; ml; tl = ml, ml = nlp) {
248625cf1a30Sjl139090 uint64_t mend;
248725cf1a30Sjl139090
248856f33205SJonathan Adams nlp = ml->ml_next;
248925cf1a30Sjl139090
249056f33205SJonathan Adams if (end <= ml->ml_address)
249125cf1a30Sjl139090 break;
249225cf1a30Sjl139090
249356f33205SJonathan Adams mend = ml->ml_address + ml->ml_size;
249425cf1a30Sjl139090 if (base < mend) {
249556f33205SJonathan Adams if (base <= ml->ml_address) {
249656f33205SJonathan Adams ml->ml_address = end;
249725cf1a30Sjl139090 if (end >= mend)
249856f33205SJonathan Adams ml->ml_size = 0ull;
249925cf1a30Sjl139090 else
250056f33205SJonathan Adams ml->ml_size = mend - ml->ml_address;
250125cf1a30Sjl139090 } else {
250256f33205SJonathan Adams ml->ml_size = base - ml->ml_address;
250325cf1a30Sjl139090 if (end < mend) {
250425cf1a30Sjl139090 struct memlist *nl;
250525cf1a30Sjl139090 /*
250625cf1a30Sjl139090 * splitting an memlist entry.
250725cf1a30Sjl139090 */
250825cf1a30Sjl139090 nl = kmem_alloc(sizeof (struct memlist),
250925cf1a30Sjl139090 KM_SLEEP);
251056f33205SJonathan Adams nl->ml_address = end;
251156f33205SJonathan Adams nl->ml_size = mend - nl->ml_address;
251256f33205SJonathan Adams if ((nl->ml_next = nlp) != NULL)
251356f33205SJonathan Adams nlp->ml_prev = nl;
251456f33205SJonathan Adams nl->ml_prev = ml;
251556f33205SJonathan Adams ml->ml_next = nl;
251625cf1a30Sjl139090 nlp = nl;
251725cf1a30Sjl139090 }
251825cf1a30Sjl139090 }
251956f33205SJonathan Adams if (ml->ml_size == 0ull) {
252025cf1a30Sjl139090 if (ml == mlist) {
252125cf1a30Sjl139090 if ((mlist = nlp) != NULL)
252256f33205SJonathan Adams nlp->ml_prev = NULL;
252325cf1a30Sjl139090 kmem_free(ml, sizeof (struct memlist));
252425cf1a30Sjl139090 if (mlist == NULL)
252525cf1a30Sjl139090 break;
252625cf1a30Sjl139090 ml = nlp;
252725cf1a30Sjl139090 } else {
252856f33205SJonathan Adams if ((tl->ml_next = nlp) != NULL)
252956f33205SJonathan Adams nlp->ml_prev = tl;
253025cf1a30Sjl139090 kmem_free(ml, sizeof (struct memlist));
253125cf1a30Sjl139090 ml = tl;
253225cf1a30Sjl139090 }
253325cf1a30Sjl139090 }
253425cf1a30Sjl139090 }
253525cf1a30Sjl139090 }
253625cf1a30Sjl139090
253725cf1a30Sjl139090 return (mlist);
253825cf1a30Sjl139090 }
253925cf1a30Sjl139090
254025cf1a30Sjl139090 static void
mc_get_mlist(mc_opl_t * mcp)254125cf1a30Sjl139090 mc_get_mlist(mc_opl_t *mcp)
254225cf1a30Sjl139090 {
254325cf1a30Sjl139090 struct memlist *mlist;
254425cf1a30Sjl139090
254525cf1a30Sjl139090 memlist_read_lock();
254625cf1a30Sjl139090 mlist = mc_memlist_dup(phys_install);
254725cf1a30Sjl139090 memlist_read_unlock();
254825cf1a30Sjl139090
254925cf1a30Sjl139090 if (mlist) {
255025cf1a30Sjl139090 mlist = mc_memlist_del_span(mlist, 0ull, mcp->mc_start_address);
255125cf1a30Sjl139090 }
255225cf1a30Sjl139090
255325cf1a30Sjl139090 if (mlist) {
255425cf1a30Sjl139090 uint64_t startpa, endpa;
255525cf1a30Sjl139090
255625cf1a30Sjl139090 startpa = mcp->mc_start_address + mcp->mc_size;
255725cf1a30Sjl139090 endpa = ptob(physmax + 1);
255825cf1a30Sjl139090 if (endpa > startpa) {
2559d8a0cca9Swh31274 mlist = mc_memlist_del_span(mlist, startpa,
2560d8a0cca9Swh31274 endpa - startpa);
256125cf1a30Sjl139090 }
256225cf1a30Sjl139090 }
256325cf1a30Sjl139090
256425cf1a30Sjl139090 if (mlist) {
256525cf1a30Sjl139090 mcp->mlist = mlist;
256625cf1a30Sjl139090 }
256725cf1a30Sjl139090 }
256825cf1a30Sjl139090
256925cf1a30Sjl139090 int
mc_board_add(mc_opl_t * mcp)257025cf1a30Sjl139090 mc_board_add(mc_opl_t *mcp)
257125cf1a30Sjl139090 {
257225cf1a30Sjl139090 struct mc_addr_spec *macaddr;
25730cc8ae86Sav145390 cs_status_t *cs_status;
25740cc8ae86Sav145390 int len, len1, i, bk, cc;
2575738dd194Shyw mc_rsaddr_info_t rsaddr;
257625cf1a30Sjl139090 uint32_t mirr;
25770cc8ae86Sav145390 int nbanks = 0;
25780cc8ae86Sav145390 uint64_t nbytes = 0;
2579d8a0cca9Swh31274 int mirror_mode = 0;
2580d8a0cca9Swh31274 int ret;
258125cf1a30Sjl139090
258225cf1a30Sjl139090 /*
258325cf1a30Sjl139090 * Get configurations from "pseudo-mc" node which includes:
258425cf1a30Sjl139090 * board# : LSB number
258525cf1a30Sjl139090 * mac-addr : physical base address of MAC registers
258625cf1a30Sjl139090 * csX-mac-pa-trans-table: translation table from DIMM address
258725cf1a30Sjl139090 * to physical address or vice versa.
258825cf1a30Sjl139090 */
258925cf1a30Sjl139090 mcp->mc_board_num = (int)ddi_getprop(DDI_DEV_T_ANY, mcp->mc_dip,
259025cf1a30Sjl139090 DDI_PROP_DONTPASS, "board#", -1);
259125cf1a30Sjl139090
25920cc8ae86Sav145390 if (mcp->mc_board_num == -1) {
25930cc8ae86Sav145390 return (DDI_FAILURE);
25940cc8ae86Sav145390 }
25950cc8ae86Sav145390
259625cf1a30Sjl139090 /*
259725cf1a30Sjl139090 * Get start address in this CAB. It can be gotten from
259825cf1a30Sjl139090 * "sb-mem-ranges" property.
259925cf1a30Sjl139090 */
260025cf1a30Sjl139090
260125cf1a30Sjl139090 if (get_base_address(mcp) == DDI_FAILURE) {
260225cf1a30Sjl139090 return (DDI_FAILURE);
260325cf1a30Sjl139090 }
260425cf1a30Sjl139090 /* get mac-pa trans tables */
260525cf1a30Sjl139090 for (i = 0; i < MC_TT_CS; i++) {
260625cf1a30Sjl139090 len = MC_TT_ENTRIES;
260725cf1a30Sjl139090 cc = ddi_getlongprop_buf(DDI_DEV_T_ANY, mcp->mc_dip,
260825cf1a30Sjl139090 DDI_PROP_DONTPASS, mc_tbl_name[i],
260925cf1a30Sjl139090 (caddr_t)mcp->mc_trans_table[i], &len);
261025cf1a30Sjl139090
261125cf1a30Sjl139090 if (cc != DDI_SUCCESS) {
261225cf1a30Sjl139090 bzero(mcp->mc_trans_table[i], MC_TT_ENTRIES);
261325cf1a30Sjl139090 }
261425cf1a30Sjl139090 }
261525cf1a30Sjl139090 mcp->mlist = NULL;
261625cf1a30Sjl139090
261725cf1a30Sjl139090 mc_get_mlist(mcp);
261825cf1a30Sjl139090
261925cf1a30Sjl139090 /* initialize bank informations */
262025cf1a30Sjl139090 cc = ddi_getlongprop(DDI_DEV_T_ANY, mcp->mc_dip, DDI_PROP_DONTPASS,
262125cf1a30Sjl139090 "mc-addr", (caddr_t)&macaddr, &len);
262225cf1a30Sjl139090 if (cc != DDI_SUCCESS) {
262325cf1a30Sjl139090 cmn_err(CE_WARN, "Cannot get mc-addr. err=%d\n", cc);
262425cf1a30Sjl139090 return (DDI_FAILURE);
262525cf1a30Sjl139090 }
262625cf1a30Sjl139090
26270cc8ae86Sav145390 cc = ddi_getlongprop(DDI_DEV_T_ANY, mcp->mc_dip, DDI_PROP_DONTPASS,
26280cc8ae86Sav145390 "cs-status", (caddr_t)&cs_status, &len1);
26290cc8ae86Sav145390
26300cc8ae86Sav145390 if (cc != DDI_SUCCESS) {
26310cc8ae86Sav145390 if (len > 0)
26320cc8ae86Sav145390 kmem_free(macaddr, len);
26330cc8ae86Sav145390 cmn_err(CE_WARN, "Cannot get cs-status. err=%d\n", cc);
26340cc8ae86Sav145390 return (DDI_FAILURE);
26350cc8ae86Sav145390 }
2636aeb241b2Sav145390 /* get the physical board number for a given logical board number */
2637aeb241b2Sav145390 mcp->mc_phys_board_num = mc_opl_get_physical_board(mcp->mc_board_num);
2638aeb241b2Sav145390
2639aeb241b2Sav145390 if (mcp->mc_phys_board_num < 0) {
2640aeb241b2Sav145390 if (len > 0)
2641aeb241b2Sav145390 kmem_free(macaddr, len);
2642aeb241b2Sav145390 cmn_err(CE_WARN, "Unable to obtain the physical board number");
2643aeb241b2Sav145390 return (DDI_FAILURE);
2644aeb241b2Sav145390 }
26450cc8ae86Sav145390
26460cc8ae86Sav145390 mutex_init(&mcp->mc_lock, NULL, MUTEX_DRIVER, NULL);
26470cc8ae86Sav145390
26480cc8ae86Sav145390 for (i = 0; i < len1 / sizeof (cs_status_t); i++) {
26490cc8ae86Sav145390 nbytes += ((uint64_t)cs_status[i].cs_avail_hi << 32) |
26500cc8ae86Sav145390 ((uint64_t)cs_status[i].cs_avail_low);
26510cc8ae86Sav145390 }
26520cc8ae86Sav145390 if (len1 > 0)
26530cc8ae86Sav145390 kmem_free(cs_status, len1);
26540cc8ae86Sav145390 nbanks = len / sizeof (struct mc_addr_spec);
26550cc8ae86Sav145390
26560cc8ae86Sav145390 if (nbanks > 0)
26570cc8ae86Sav145390 nbytes /= nbanks;
26580cc8ae86Sav145390 else {
26590cc8ae86Sav145390 /* No need to free macaddr because len must be 0 */
26600cc8ae86Sav145390 mcp->mc_status |= MC_MEMORYLESS;
26610cc8ae86Sav145390 return (DDI_SUCCESS);
26620cc8ae86Sav145390 }
26630cc8ae86Sav145390
26640cc8ae86Sav145390 for (i = 0; i < BANKNUM_PER_SB; i++) {
26650cc8ae86Sav145390 mcp->mc_scf_retry[i] = 0;
26660cc8ae86Sav145390 mcp->mc_period[i] = 0;
26670cc8ae86Sav145390 mcp->mc_speedup_period[i] = 0;
26680cc8ae86Sav145390 }
26690cc8ae86Sav145390
26700cc8ae86Sav145390 /*
26710cc8ae86Sav145390 * Get the memory size here. Let it be B (bytes).
26720cc8ae86Sav145390 * Let T be the time in u.s. to scan 64 bytes.
26730cc8ae86Sav145390 * If we want to complete 1 round of scanning in P seconds.
26740cc8ae86Sav145390 *
26750cc8ae86Sav145390 * B * T * 10^(-6) = P
26760cc8ae86Sav145390 * ---------------
26770cc8ae86Sav145390 * 64
26780cc8ae86Sav145390 *
26790cc8ae86Sav145390 * T = P * 64 * 10^6
26800cc8ae86Sav145390 * -------------
26810cc8ae86Sav145390 * B
26820cc8ae86Sav145390 *
26830cc8ae86Sav145390 * = P * 64 * 10^6
26840cc8ae86Sav145390 * -------------
26850cc8ae86Sav145390 * B
26860cc8ae86Sav145390 *
26870cc8ae86Sav145390 * The timing bits are set in PTRL_CNTL[28:26] where
26880cc8ae86Sav145390 *
26890cc8ae86Sav145390 * 0 - 1 m.s
26900cc8ae86Sav145390 * 1 - 512 u.s.
26910cc8ae86Sav145390 * 10 - 256 u.s.
26920cc8ae86Sav145390 * 11 - 128 u.s.
26930cc8ae86Sav145390 * 100 - 64 u.s.
26940cc8ae86Sav145390 * 101 - 32 u.s.
26950cc8ae86Sav145390 * 110 - 0 u.s.
26960cc8ae86Sav145390 * 111 - reserved.
26970cc8ae86Sav145390 *
26980cc8ae86Sav145390 *
26990cc8ae86Sav145390 * a[0] = 110, a[1] = 101, ... a[6] = 0
27000cc8ae86Sav145390 *
27010cc8ae86Sav145390 * cs-status property is int x 7
27020cc8ae86Sav145390 * 0 - cs#
27030cc8ae86Sav145390 * 1 - cs-status
27040cc8ae86Sav145390 * 2 - cs-avail.hi
27050cc8ae86Sav145390 * 3 - cs-avail.lo
27060cc8ae86Sav145390 * 4 - dimm-capa.hi
27070cc8ae86Sav145390 * 5 - dimm-capa.lo
27080cc8ae86Sav145390 * 6 - #of dimms
27090cc8ae86Sav145390 */
27100cc8ae86Sav145390
27110cc8ae86Sav145390 if (nbytes > 0) {
27120cc8ae86Sav145390 int i;
27130cc8ae86Sav145390 uint64_t ms;
27140cc8ae86Sav145390 ms = ((uint64_t)mc_scan_period * 64 * 1000000)/nbytes;
27150cc8ae86Sav145390 mcp->mc_speed = mc_scan_speeds[MC_MAX_SPEEDS - 1].mc_speeds;
27160cc8ae86Sav145390 for (i = 0; i < MC_MAX_SPEEDS - 1; i++) {
27170cc8ae86Sav145390 if (ms < mc_scan_speeds[i + 1].mc_period) {
27180cc8ae86Sav145390 mcp->mc_speed = mc_scan_speeds[i].mc_speeds;
27190cc8ae86Sav145390 break;
27200cc8ae86Sav145390 }
27210cc8ae86Sav145390 }
27220cc8ae86Sav145390 } else
27230cc8ae86Sav145390 mcp->mc_speed = 0;
27240cc8ae86Sav145390
27250cc8ae86Sav145390
272625cf1a30Sjl139090 for (i = 0; i < len / sizeof (struct mc_addr_spec); i++) {
272725cf1a30Sjl139090 struct mc_bank *bankp;
2728601c2e1eSdhain mc_retry_info_t *retry;
272925cf1a30Sjl139090 uint32_t reg;
2730601c2e1eSdhain int k;
273125cf1a30Sjl139090
273225cf1a30Sjl139090 /*
273325cf1a30Sjl139090 * setup bank
273425cf1a30Sjl139090 */
273525cf1a30Sjl139090 bk = macaddr[i].bank;
273625cf1a30Sjl139090 bankp = &(mcp->mc_bank[bk]);
273725cf1a30Sjl139090 bankp->mcb_status = BANK_INSTALLED;
273825cf1a30Sjl139090 bankp->mcb_reg_base = REGS_PA(macaddr, i);
273925cf1a30Sjl139090
2740601c2e1eSdhain bankp->mcb_retry_freelist = NULL;
2741601c2e1eSdhain bankp->mcb_retry_pending = NULL;
2742601c2e1eSdhain bankp->mcb_active = NULL;
2743601c2e1eSdhain retry = &bankp->mcb_retry_infos[0];
2744601c2e1eSdhain for (k = 0; k < MC_RETRY_COUNT; k++, retry++) {
2745601c2e1eSdhain mc_retry_info_put(&bankp->mcb_retry_freelist, retry);
2746601c2e1eSdhain }
2747601c2e1eSdhain
274825cf1a30Sjl139090 reg = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bk));
274925cf1a30Sjl139090 bankp->mcb_ptrl_cntl = (reg & MAC_CNTL_PTRL_PRESERVE_BITS);
275025cf1a30Sjl139090
275125cf1a30Sjl139090 /*
275225cf1a30Sjl139090 * check if mirror mode
275325cf1a30Sjl139090 */
275425cf1a30Sjl139090 mirr = LD_MAC_REG(MAC_MIRR(mcp, bk));
275525cf1a30Sjl139090
275625cf1a30Sjl139090 if (mirr & MAC_MIRR_MIRROR_MODE) {
2757d8a0cca9Swh31274 MC_LOG("Mirror -> /LSB%d/B%d\n", mcp->mc_board_num,
2758d8a0cca9Swh31274 bk);
275925cf1a30Sjl139090 bankp->mcb_status |= BANK_MIRROR_MODE;
2760d8a0cca9Swh31274 mirror_mode = 1;
276125cf1a30Sjl139090 /*
276225cf1a30Sjl139090 * The following bit is only used for
276325cf1a30Sjl139090 * error injection. We should clear it
276425cf1a30Sjl139090 */
276525cf1a30Sjl139090 if (mirr & MAC_MIRR_BANK_EXCLUSIVE)
2766d8a0cca9Swh31274 ST_MAC_REG(MAC_MIRR(mcp, bk), 0);
276725cf1a30Sjl139090 }
276825cf1a30Sjl139090
276925cf1a30Sjl139090 /*
277025cf1a30Sjl139090 * restart if not mirror mode or the other bank
277125cf1a30Sjl139090 * of the mirror is not running
277225cf1a30Sjl139090 */
277325cf1a30Sjl139090 if (!(mirr & MAC_MIRR_MIRROR_MODE) ||
2774d8a0cca9Swh31274 !(mcp->mc_bank[bk^1].mcb_status & BANK_PTRL_RUNNING)) {
2775d8a0cca9Swh31274 MC_LOG("Starting up /LSB%d/B%d\n", mcp->mc_board_num,
2776d8a0cca9Swh31274 bk);
2777738dd194Shyw get_ptrl_start_address(mcp, bk, &rsaddr.mi_restartaddr);
2778738dd194Shyw rsaddr.mi_valid = 0;
2779738dd194Shyw rsaddr.mi_injectrestart = 0;
278007d06da5SSurya Prakki (void) restart_patrol(mcp, bk, &rsaddr);
278125cf1a30Sjl139090 } else {
278225cf1a30Sjl139090 MC_LOG("Not starting up /LSB%d/B%d\n",
278325cf1a30Sjl139090 mcp->mc_board_num, bk);
278425cf1a30Sjl139090 }
278525cf1a30Sjl139090 bankp->mcb_status |= BANK_PTRL_RUNNING;
278625cf1a30Sjl139090 }
27870cc8ae86Sav145390 if (len > 0)
278825cf1a30Sjl139090 kmem_free(macaddr, len);
278925cf1a30Sjl139090
2790d8a0cca9Swh31274 ret = ndi_prop_update_int(DDI_DEV_T_NONE, mcp->mc_dip, "mirror-mode",
2791d8a0cca9Swh31274 mirror_mode);
2792d8a0cca9Swh31274 if (ret != DDI_PROP_SUCCESS) {
2793d8a0cca9Swh31274 cmn_err(CE_WARN, "Unable to update mirror-mode property");
2794d8a0cca9Swh31274 }
2795d8a0cca9Swh31274
27960cc8ae86Sav145390 mcp->mc_dimm_list = mc_get_dimm_list(mcp);
27970cc8ae86Sav145390
279825cf1a30Sjl139090 /*
279925cf1a30Sjl139090 * set interval in HZ.
280025cf1a30Sjl139090 */
280125cf1a30Sjl139090 mcp->mc_last_error = 0;
280225cf1a30Sjl139090
280325cf1a30Sjl139090 /* restart memory patrol checking */
280425cf1a30Sjl139090 mcp->mc_status |= MC_POLL_RUNNING;
280525cf1a30Sjl139090
280625cf1a30Sjl139090 return (DDI_SUCCESS);
280725cf1a30Sjl139090 }
280825cf1a30Sjl139090
280925cf1a30Sjl139090 int
mc_board_del(mc_opl_t * mcp)281025cf1a30Sjl139090 mc_board_del(mc_opl_t *mcp)
281125cf1a30Sjl139090 {
281225cf1a30Sjl139090 int i;
281325cf1a30Sjl139090 scf_log_t *p;
281425cf1a30Sjl139090
281525cf1a30Sjl139090 /*
281625cf1a30Sjl139090 * cleanup mac state
281725cf1a30Sjl139090 */
281825cf1a30Sjl139090 mutex_enter(&mcp->mc_lock);
28190cc8ae86Sav145390 if (mcp->mc_status & MC_MEMORYLESS) {
28200cc8ae86Sav145390 mutex_exit(&mcp->mc_lock);
28210cc8ae86Sav145390 mutex_destroy(&mcp->mc_lock);
28220cc8ae86Sav145390 return (DDI_SUCCESS);
28230cc8ae86Sav145390 }
282425cf1a30Sjl139090 for (i = 0; i < BANKNUM_PER_SB; i++) {
282525cf1a30Sjl139090 if (mcp->mc_bank[i].mcb_status & BANK_INSTALLED) {
282625cf1a30Sjl139090 mcp->mc_bank[i].mcb_status &= ~BANK_INSTALLED;
282725cf1a30Sjl139090 }
282825cf1a30Sjl139090 }
282925cf1a30Sjl139090
283025cf1a30Sjl139090 /* stop memory patrol checking */
283125cf1a30Sjl139090 mcp->mc_status &= ~MC_POLL_RUNNING;
283225cf1a30Sjl139090
283325cf1a30Sjl139090 /* just throw away all the scf logs */
28340cc8ae86Sav145390 for (i = 0; i < BANKNUM_PER_SB; i++) {
28350cc8ae86Sav145390 while ((p = mcp->mc_scf_log[i]) != NULL) {
28360cc8ae86Sav145390 mcp->mc_scf_log[i] = p->sl_next;
28370cc8ae86Sav145390 mcp->mc_scf_total[i]--;
283825cf1a30Sjl139090 kmem_free(p, sizeof (scf_log_t));
283925cf1a30Sjl139090 }
28400cc8ae86Sav145390 }
284125cf1a30Sjl139090
284225cf1a30Sjl139090 if (mcp->mlist)
284325cf1a30Sjl139090 mc_memlist_delete(mcp->mlist);
284425cf1a30Sjl139090
28450cc8ae86Sav145390 if (mcp->mc_dimm_list)
28460cc8ae86Sav145390 mc_free_dimm_list(mcp->mc_dimm_list);
28470cc8ae86Sav145390
284825cf1a30Sjl139090 mutex_exit(&mcp->mc_lock);
284925cf1a30Sjl139090
285025cf1a30Sjl139090 mutex_destroy(&mcp->mc_lock);
285125cf1a30Sjl139090 return (DDI_SUCCESS);
285225cf1a30Sjl139090 }
285325cf1a30Sjl139090
285425cf1a30Sjl139090 int
mc_suspend(mc_opl_t * mcp,uint32_t flag)285525cf1a30Sjl139090 mc_suspend(mc_opl_t *mcp, uint32_t flag)
285625cf1a30Sjl139090 {
285725cf1a30Sjl139090 /* stop memory patrol checking */
285825cf1a30Sjl139090 mutex_enter(&mcp->mc_lock);
28590cc8ae86Sav145390 if (mcp->mc_status & MC_MEMORYLESS) {
286025cf1a30Sjl139090 mutex_exit(&mcp->mc_lock);
28610cc8ae86Sav145390 return (DDI_SUCCESS);
286225cf1a30Sjl139090 }
28630cc8ae86Sav145390
286425cf1a30Sjl139090 mcp->mc_status &= ~MC_POLL_RUNNING;
2865738dd194Shyw
286625cf1a30Sjl139090 mcp->mc_status |= flag;
286725cf1a30Sjl139090 mutex_exit(&mcp->mc_lock);
286825cf1a30Sjl139090
286925cf1a30Sjl139090 return (DDI_SUCCESS);
287025cf1a30Sjl139090 }
287125cf1a30Sjl139090
287268ac2337Sjl139090 void
opl_mc_update_mlist(void)287368ac2337Sjl139090 opl_mc_update_mlist(void)
287468ac2337Sjl139090 {
287568ac2337Sjl139090 int i;
287668ac2337Sjl139090 mc_opl_t *mcp;
287768ac2337Sjl139090
287868ac2337Sjl139090 /*
287968ac2337Sjl139090 * memory information is not updated until
288068ac2337Sjl139090 * the post attach/detach stage during DR.
288168ac2337Sjl139090 * This interface is used by dr_mem to inform
288268ac2337Sjl139090 * mc-opl to update the mlist.
288368ac2337Sjl139090 */
288468ac2337Sjl139090
288568ac2337Sjl139090 mutex_enter(&mcmutex);
288668ac2337Sjl139090 for (i = 0; i < OPL_MAX_BOARDS; i++) {
288768ac2337Sjl139090 if ((mcp = mc_instances[i]) == NULL)
288868ac2337Sjl139090 continue;
288968ac2337Sjl139090 mutex_enter(&mcp->mc_lock);
289068ac2337Sjl139090 if (mcp->mlist)
289168ac2337Sjl139090 mc_memlist_delete(mcp->mlist);
289268ac2337Sjl139090 mcp->mlist = NULL;
289368ac2337Sjl139090 mc_get_mlist(mcp);
289468ac2337Sjl139090 mutex_exit(&mcp->mc_lock);
289568ac2337Sjl139090 }
289668ac2337Sjl139090 mutex_exit(&mcmutex);
289768ac2337Sjl139090 }
289868ac2337Sjl139090
289925cf1a30Sjl139090 /* caller must clear the SUSPEND bits or this will do nothing */
290025cf1a30Sjl139090
290125cf1a30Sjl139090 int
mc_resume(mc_opl_t * mcp,uint32_t flag)290225cf1a30Sjl139090 mc_resume(mc_opl_t *mcp, uint32_t flag)
290325cf1a30Sjl139090 {
290425cf1a30Sjl139090 int i;
290525cf1a30Sjl139090 uint64_t basepa;
290625cf1a30Sjl139090
290725cf1a30Sjl139090 mutex_enter(&mcp->mc_lock);
29080cc8ae86Sav145390 if (mcp->mc_status & MC_MEMORYLESS) {
29090cc8ae86Sav145390 mutex_exit(&mcp->mc_lock);
29100cc8ae86Sav145390 return (DDI_SUCCESS);
29110cc8ae86Sav145390 }
291225cf1a30Sjl139090 basepa = mcp->mc_start_address;
291325cf1a30Sjl139090 if (get_base_address(mcp) == DDI_FAILURE) {
291425cf1a30Sjl139090 mutex_exit(&mcp->mc_lock);
291525cf1a30Sjl139090 return (DDI_FAILURE);
291625cf1a30Sjl139090 }
291725cf1a30Sjl139090
291825cf1a30Sjl139090 if (basepa != mcp->mc_start_address) {
291925cf1a30Sjl139090 if (mcp->mlist)
292025cf1a30Sjl139090 mc_memlist_delete(mcp->mlist);
292125cf1a30Sjl139090 mcp->mlist = NULL;
292225cf1a30Sjl139090 mc_get_mlist(mcp);
292325cf1a30Sjl139090 }
292425cf1a30Sjl139090
292525cf1a30Sjl139090 mcp->mc_status &= ~flag;
292625cf1a30Sjl139090
292725cf1a30Sjl139090 if (mcp->mc_status & (MC_SOFT_SUSPENDED | MC_DRIVER_SUSPENDED)) {
292825cf1a30Sjl139090 mutex_exit(&mcp->mc_lock);
292925cf1a30Sjl139090 return (DDI_SUCCESS);
293025cf1a30Sjl139090 }
293125cf1a30Sjl139090
293225cf1a30Sjl139090 if (!(mcp->mc_status & MC_POLL_RUNNING)) {
293325cf1a30Sjl139090 /* restart memory patrol checking */
293425cf1a30Sjl139090 mcp->mc_status |= MC_POLL_RUNNING;
293525cf1a30Sjl139090 for (i = 0; i < BANKNUM_PER_SB; i++) {
293625cf1a30Sjl139090 if (mcp->mc_bank[i].mcb_status & BANK_INSTALLED) {
2937601c2e1eSdhain mc_check_errors_func(mcp);
293825cf1a30Sjl139090 }
293925cf1a30Sjl139090 }
294025cf1a30Sjl139090 }
294125cf1a30Sjl139090 mutex_exit(&mcp->mc_lock);
294225cf1a30Sjl139090
294325cf1a30Sjl139090 return (DDI_SUCCESS);
294425cf1a30Sjl139090 }
294525cf1a30Sjl139090
294625cf1a30Sjl139090 static mc_opl_t *
mc_pa_to_mcp(uint64_t pa)294725cf1a30Sjl139090 mc_pa_to_mcp(uint64_t pa)
294825cf1a30Sjl139090 {
29490cc8ae86Sav145390 mc_opl_t *mcp;
29500cc8ae86Sav145390 int i;
29510cc8ae86Sav145390
295225cf1a30Sjl139090 ASSERT(MUTEX_HELD(&mcmutex));
29530cc8ae86Sav145390 for (i = 0; i < OPL_MAX_BOARDS; i++) {
29540cc8ae86Sav145390 if ((mcp = mc_instances[i]) == NULL)
295525cf1a30Sjl139090 continue;
29560cc8ae86Sav145390 /* if mac patrol is suspended, we cannot rely on it */
29570cc8ae86Sav145390 if (!(mcp->mc_status & MC_POLL_RUNNING) ||
29580cc8ae86Sav145390 (mcp->mc_status & MC_SOFT_SUSPENDED))
29590cc8ae86Sav145390 continue;
2960738dd194Shyw if (mc_rangecheck_pa(mcp, pa)) {
29610cc8ae86Sav145390 return (mcp);
296225cf1a30Sjl139090 }
296325cf1a30Sjl139090 }
296425cf1a30Sjl139090 return (NULL);
296525cf1a30Sjl139090 }
296625cf1a30Sjl139090
296725cf1a30Sjl139090 /*
296825cf1a30Sjl139090 * Get Physical Board number from Logical one.
296925cf1a30Sjl139090 */
297025cf1a30Sjl139090 static int
mc_opl_get_physical_board(int sb)297125cf1a30Sjl139090 mc_opl_get_physical_board(int sb)
297225cf1a30Sjl139090 {
297325cf1a30Sjl139090 if (&opl_get_physical_board) {
297425cf1a30Sjl139090 return (opl_get_physical_board(sb));
297525cf1a30Sjl139090 }
297625cf1a30Sjl139090
297725cf1a30Sjl139090 cmn_err(CE_NOTE, "!opl_get_physical_board() not loaded\n");
297825cf1a30Sjl139090 return (-1);
297925cf1a30Sjl139090 }
298025cf1a30Sjl139090
298125cf1a30Sjl139090 /* ARGSUSED */
298225cf1a30Sjl139090 int
mc_get_mem_unum(int synd_code,uint64_t flt_addr,char * buf,int buflen,int * lenp)298325cf1a30Sjl139090 mc_get_mem_unum(int synd_code, uint64_t flt_addr, char *buf, int buflen,
298425cf1a30Sjl139090 int *lenp)
298525cf1a30Sjl139090 {
29860cc8ae86Sav145390 int i;
2987aeb241b2Sav145390 int j;
298825cf1a30Sjl139090 int sb;
29890cc8ae86Sav145390 int bank;
2990aeb241b2Sav145390 int cs;
299178ed97a7Sjl139090 int rv = 0;
29920cc8ae86Sav145390 mc_opl_t *mcp;
29930cc8ae86Sav145390 char memb_num;
299425cf1a30Sjl139090
299525cf1a30Sjl139090 mutex_enter(&mcmutex);
299625cf1a30Sjl139090
299725cf1a30Sjl139090 if (((mcp = mc_pa_to_mcp(flt_addr)) == NULL) ||
299825cf1a30Sjl139090 (!pa_is_valid(mcp, flt_addr))) {
299925cf1a30Sjl139090 mutex_exit(&mcmutex);
300025cf1a30Sjl139090 if (snprintf(buf, buflen, "UNKNOWN") >= buflen) {
300125cf1a30Sjl139090 return (ENOSPC);
300225cf1a30Sjl139090 } else {
300325cf1a30Sjl139090 if (lenp)
300425cf1a30Sjl139090 *lenp = strlen(buf);
300525cf1a30Sjl139090 }
300625cf1a30Sjl139090 return (0);
300725cf1a30Sjl139090 }
300825cf1a30Sjl139090
300925cf1a30Sjl139090 bank = pa_to_bank(mcp, flt_addr - mcp->mc_start_address);
3010aeb241b2Sav145390 sb = mcp->mc_phys_board_num;
3011aeb241b2Sav145390 cs = pa_to_cs(mcp, flt_addr - mcp->mc_start_address);
301225cf1a30Sjl139090
301325cf1a30Sjl139090 if (sb == -1) {
301425cf1a30Sjl139090 mutex_exit(&mcmutex);
301525cf1a30Sjl139090 return (ENXIO);
301625cf1a30Sjl139090 }
301725cf1a30Sjl139090
301878ed97a7Sjl139090 switch (plat_model) {
301978ed97a7Sjl139090 case MODEL_DC:
30200cc8ae86Sav145390 i = BD_BK_SLOT_TO_INDEX(0, bank, 0);
3021aeb241b2Sav145390 j = (cs == 0) ? i : i + 2;
302207d06da5SSurya Prakki (void) snprintf(buf, buflen, "/%s%02d/MEM%s MEM%s",
30230cc8ae86Sav145390 model_names[plat_model].unit_name, sb,
3024aeb241b2Sav145390 mc_dc_dimm_unum_table[j],
3025aeb241b2Sav145390 mc_dc_dimm_unum_table[j + 1]);
302678ed97a7Sjl139090 break;
302778ed97a7Sjl139090 case MODEL_FF2:
302878ed97a7Sjl139090 case MODEL_FF1:
30290cc8ae86Sav145390 i = BD_BK_SLOT_TO_INDEX(sb, bank, 0);
3030aeb241b2Sav145390 j = (cs == 0) ? i : i + 2;
30310cc8ae86Sav145390 memb_num = mc_ff_dimm_unum_table[i][0];
303207d06da5SSurya Prakki (void) snprintf(buf, buflen, "/%s/%s%c/MEM%s MEM%s",
30330cc8ae86Sav145390 model_names[plat_model].unit_name,
30340cc8ae86Sav145390 model_names[plat_model].mem_name, memb_num,
3035aeb241b2Sav145390 &mc_ff_dimm_unum_table[j][1],
3036aeb241b2Sav145390 &mc_ff_dimm_unum_table[j + 1][1]);
303778ed97a7Sjl139090 break;
303878ed97a7Sjl139090 case MODEL_IKKAKU:
303978ed97a7Sjl139090 i = BD_BK_SLOT_TO_INDEX(sb, bank, 0);
304078ed97a7Sjl139090 j = (cs == 0) ? i : i + 2;
304107d06da5SSurya Prakki (void) snprintf(buf, buflen, "/%s/MEM%s MEM%s",
304278ed97a7Sjl139090 model_names[plat_model].unit_name,
304378ed97a7Sjl139090 &mc_ff_dimm_unum_table[j][1],
304478ed97a7Sjl139090 &mc_ff_dimm_unum_table[j + 1][1]);
304578ed97a7Sjl139090 break;
304678ed97a7Sjl139090 default:
304778ed97a7Sjl139090 rv = ENXIO;
30480cc8ae86Sav145390 }
30490cc8ae86Sav145390 if (lenp) {
305025cf1a30Sjl139090 *lenp = strlen(buf);
305125cf1a30Sjl139090 }
305225cf1a30Sjl139090 mutex_exit(&mcmutex);
305378ed97a7Sjl139090 return (rv);
305425cf1a30Sjl139090 }
305525cf1a30Sjl139090
305625cf1a30Sjl139090 int
opl_mc_suspend(void)30570cc8ae86Sav145390 opl_mc_suspend(void)
305825cf1a30Sjl139090 {
305925cf1a30Sjl139090 mc_opl_t *mcp;
30600cc8ae86Sav145390 int i;
306125cf1a30Sjl139090
306225cf1a30Sjl139090 mutex_enter(&mcmutex);
30630cc8ae86Sav145390 for (i = 0; i < OPL_MAX_BOARDS; i++) {
30640cc8ae86Sav145390 if ((mcp = mc_instances[i]) == NULL)
30650cc8ae86Sav145390 continue;
306607d06da5SSurya Prakki (void) mc_suspend(mcp, MC_SOFT_SUSPENDED);
306725cf1a30Sjl139090 }
306825cf1a30Sjl139090 mutex_exit(&mcmutex);
30690cc8ae86Sav145390
307025cf1a30Sjl139090 return (0);
307125cf1a30Sjl139090 }
307225cf1a30Sjl139090
307325cf1a30Sjl139090 int
opl_mc_resume(void)30740cc8ae86Sav145390 opl_mc_resume(void)
307525cf1a30Sjl139090 {
307625cf1a30Sjl139090 mc_opl_t *mcp;
30770cc8ae86Sav145390 int i;
307825cf1a30Sjl139090
307925cf1a30Sjl139090 mutex_enter(&mcmutex);
30800cc8ae86Sav145390 for (i = 0; i < OPL_MAX_BOARDS; i++) {
30810cc8ae86Sav145390 if ((mcp = mc_instances[i]) == NULL)
30820cc8ae86Sav145390 continue;
308307d06da5SSurya Prakki (void) mc_resume(mcp, MC_SOFT_SUSPENDED);
308425cf1a30Sjl139090 }
308525cf1a30Sjl139090 mutex_exit(&mcmutex);
30860cc8ae86Sav145390
308725cf1a30Sjl139090 return (0);
308825cf1a30Sjl139090 }
308925cf1a30Sjl139090 static void
insert_mcp(mc_opl_t * mcp)309025cf1a30Sjl139090 insert_mcp(mc_opl_t *mcp)
309125cf1a30Sjl139090 {
309225cf1a30Sjl139090 mutex_enter(&mcmutex);
30930cc8ae86Sav145390 if (mc_instances[mcp->mc_board_num] != NULL) {
30940cc8ae86Sav145390 MC_LOG("mc-opl instance for board# %d already exists\n",
30950cc8ae86Sav145390 mcp->mc_board_num);
30960cc8ae86Sav145390 }
30970cc8ae86Sav145390 mc_instances[mcp->mc_board_num] = mcp;
309825cf1a30Sjl139090 mutex_exit(&mcmutex);
309925cf1a30Sjl139090 }
310025cf1a30Sjl139090
310125cf1a30Sjl139090 static void
delete_mcp(mc_opl_t * mcp)310225cf1a30Sjl139090 delete_mcp(mc_opl_t *mcp)
310325cf1a30Sjl139090 {
31040cc8ae86Sav145390 mutex_enter(&mcmutex);
31050cc8ae86Sav145390 mc_instances[mcp->mc_board_num] = 0;
31060cc8ae86Sav145390 mutex_exit(&mcmutex);
310725cf1a30Sjl139090 }
310825cf1a30Sjl139090
310925cf1a30Sjl139090 /* Error injection interface */
311025cf1a30Sjl139090
3111cfb9e062Shyw static void
mc_lock_va(uint64_t pa,caddr_t new_va)3112cfb9e062Shyw mc_lock_va(uint64_t pa, caddr_t new_va)
3113cfb9e062Shyw {
3114cfb9e062Shyw tte_t tte;
3115cfb9e062Shyw
3116738dd194Shyw vtag_flushpage(new_va, (uint64_t)ksfmmup);
3117d8a0cca9Swh31274 sfmmu_memtte(&tte, pa >> PAGESHIFT, PROC_DATA|HAT_NOSYNC, TTE8K);
3118cfb9e062Shyw tte.tte_intlo |= TTE_LCK_INT;
3119cfb9e062Shyw sfmmu_dtlb_ld_kva(new_va, &tte);
3120cfb9e062Shyw }
3121cfb9e062Shyw
3122cfb9e062Shyw static void
mc_unlock_va(caddr_t va)3123cfb9e062Shyw mc_unlock_va(caddr_t va)
3124cfb9e062Shyw {
3125cfb9e062Shyw vtag_flushpage(va, (uint64_t)ksfmmup);
3126cfb9e062Shyw }
3127cfb9e062Shyw
312825cf1a30Sjl139090 /* ARGSUSED */
312925cf1a30Sjl139090 int
mc_inject_error(int error_type,uint64_t pa,uint32_t flags)313025cf1a30Sjl139090 mc_inject_error(int error_type, uint64_t pa, uint32_t flags)
313125cf1a30Sjl139090 {
313225cf1a30Sjl139090 mc_opl_t *mcp;
313325cf1a30Sjl139090 int bank;
313425cf1a30Sjl139090 uint32_t dimm_addr;
313525cf1a30Sjl139090 uint32_t cntl;
3136738dd194Shyw mc_rsaddr_info_t rsaddr;
313725cf1a30Sjl139090 uint32_t data, stat;
313825cf1a30Sjl139090 int both_sides = 0;
313925cf1a30Sjl139090 uint64_t pa0;
3140cfb9e062Shyw int extra_injection_needed = 0;
314125cf1a30Sjl139090 extern void cpu_flush_ecache(void);
314225cf1a30Sjl139090
314325cf1a30Sjl139090 MC_LOG("HW mc_inject_error(%x, %lx, %x)\n", error_type, pa, flags);
314425cf1a30Sjl139090
314525cf1a30Sjl139090 mutex_enter(&mcmutex);
314625cf1a30Sjl139090 if ((mcp = mc_pa_to_mcp(pa)) == NULL) {
314725cf1a30Sjl139090 mutex_exit(&mcmutex);
314825cf1a30Sjl139090 MC_LOG("mc_inject_error: invalid pa\n");
314925cf1a30Sjl139090 return (ENOTSUP);
315025cf1a30Sjl139090 }
315125cf1a30Sjl139090
315225cf1a30Sjl139090 mutex_enter(&mcp->mc_lock);
315325cf1a30Sjl139090 mutex_exit(&mcmutex);
315425cf1a30Sjl139090
315525cf1a30Sjl139090 if (mcp->mc_status & (MC_SOFT_SUSPENDED | MC_DRIVER_SUSPENDED)) {
315625cf1a30Sjl139090 mutex_exit(&mcp->mc_lock);
315725cf1a30Sjl139090 MC_LOG("mc-opl has been suspended. No error injection.\n");
315825cf1a30Sjl139090 return (EBUSY);
315925cf1a30Sjl139090 }
316025cf1a30Sjl139090
316125cf1a30Sjl139090 /* convert pa to offset within the board */
316225cf1a30Sjl139090 MC_LOG("pa %lx, offset %lx\n", pa, pa - mcp->mc_start_address);
316325cf1a30Sjl139090
316425cf1a30Sjl139090 if (!pa_is_valid(mcp, pa)) {
316525cf1a30Sjl139090 mutex_exit(&mcp->mc_lock);
316625cf1a30Sjl139090 return (EINVAL);
316725cf1a30Sjl139090 }
316825cf1a30Sjl139090
316925cf1a30Sjl139090 pa0 = pa - mcp->mc_start_address;
317025cf1a30Sjl139090
317125cf1a30Sjl139090 bank = pa_to_bank(mcp, pa0);
317225cf1a30Sjl139090
317325cf1a30Sjl139090 if (flags & MC_INJECT_FLAG_OTHER)
317425cf1a30Sjl139090 bank = bank ^ 1;
317525cf1a30Sjl139090
317625cf1a30Sjl139090 if (MC_INJECT_MIRROR(error_type) && !IS_MIRROR(mcp, bank)) {
317725cf1a30Sjl139090 mutex_exit(&mcp->mc_lock);
317825cf1a30Sjl139090 MC_LOG("Not mirror mode\n");
317925cf1a30Sjl139090 return (EINVAL);
318025cf1a30Sjl139090 }
318125cf1a30Sjl139090
318225cf1a30Sjl139090 dimm_addr = pa_to_dimm(mcp, pa0);
318325cf1a30Sjl139090
3184d8a0cca9Swh31274 MC_LOG("injecting error to /LSB%d/B%d/%x\n", mcp->mc_board_num, bank,
3185d8a0cca9Swh31274 dimm_addr);
318625cf1a30Sjl139090
318725cf1a30Sjl139090
318825cf1a30Sjl139090 switch (error_type) {
318925cf1a30Sjl139090 case MC_INJECT_INTERMITTENT_MCE:
319025cf1a30Sjl139090 case MC_INJECT_PERMANENT_MCE:
319125cf1a30Sjl139090 case MC_INJECT_MUE:
319225cf1a30Sjl139090 both_sides = 1;
319325cf1a30Sjl139090 }
319425cf1a30Sjl139090
319525cf1a30Sjl139090 if (flags & MC_INJECT_FLAG_RESET)
319625cf1a30Sjl139090 ST_MAC_REG(MAC_EG_CNTL(mcp, bank), 0);
319725cf1a30Sjl139090
319825cf1a30Sjl139090 ST_MAC_REG(MAC_EG_ADD(mcp, bank), dimm_addr & MAC_EG_ADD_MASK);
319925cf1a30Sjl139090
320025cf1a30Sjl139090 if (both_sides) {
320125cf1a30Sjl139090 ST_MAC_REG(MAC_EG_CNTL(mcp, bank^1), 0);
3202d8a0cca9Swh31274 ST_MAC_REG(MAC_EG_ADD(mcp, bank^1), dimm_addr &
3203d8a0cca9Swh31274 MAC_EG_ADD_MASK);
320425cf1a30Sjl139090 }
320525cf1a30Sjl139090
320625cf1a30Sjl139090 switch (error_type) {
320725cf1a30Sjl139090 case MC_INJECT_SUE:
3208cfb9e062Shyw extra_injection_needed = 1;
3209cfb9e062Shyw /*FALLTHROUGH*/
3210cfb9e062Shyw case MC_INJECT_UE:
321125cf1a30Sjl139090 case MC_INJECT_MUE:
321225cf1a30Sjl139090 if (flags & MC_INJECT_FLAG_PATH) {
3213d8a0cca9Swh31274 cntl = MAC_EG_ADD_FIX | MAC_EG_FORCE_READ00 |
3214d8a0cca9Swh31274 MAC_EG_FORCE_READ16 | MAC_EG_RDERR_ONCE;
321525cf1a30Sjl139090 } else {
3216d8a0cca9Swh31274 cntl = MAC_EG_ADD_FIX | MAC_EG_FORCE_DERR00 |
3217d8a0cca9Swh31274 MAC_EG_FORCE_DERR16 | MAC_EG_DERR_ONCE;
321825cf1a30Sjl139090 }
321925cf1a30Sjl139090 flags |= MC_INJECT_FLAG_ST;
322025cf1a30Sjl139090 break;
322125cf1a30Sjl139090 case MC_INJECT_INTERMITTENT_CE:
322225cf1a30Sjl139090 case MC_INJECT_INTERMITTENT_MCE:
322325cf1a30Sjl139090 if (flags & MC_INJECT_FLAG_PATH) {
3224d8a0cca9Swh31274 cntl = MAC_EG_ADD_FIX |MAC_EG_FORCE_READ00 |
3225d8a0cca9Swh31274 MAC_EG_RDERR_ONCE;
322625cf1a30Sjl139090 } else {
3227d8a0cca9Swh31274 cntl = MAC_EG_ADD_FIX | MAC_EG_FORCE_DERR16 |
3228d8a0cca9Swh31274 MAC_EG_DERR_ONCE;
322925cf1a30Sjl139090 }
3230cfb9e062Shyw extra_injection_needed = 1;
323125cf1a30Sjl139090 flags |= MC_INJECT_FLAG_ST;
323225cf1a30Sjl139090 break;
323325cf1a30Sjl139090 case MC_INJECT_PERMANENT_CE:
323425cf1a30Sjl139090 case MC_INJECT_PERMANENT_MCE:
323525cf1a30Sjl139090 if (flags & MC_INJECT_FLAG_PATH) {
3236d8a0cca9Swh31274 cntl = MAC_EG_ADD_FIX | MAC_EG_FORCE_READ00 |
3237d8a0cca9Swh31274 MAC_EG_RDERR_ALWAYS;
323825cf1a30Sjl139090 } else {
3239d8a0cca9Swh31274 cntl = MAC_EG_ADD_FIX | MAC_EG_FORCE_DERR16 |
3240d8a0cca9Swh31274 MAC_EG_DERR_ALWAYS;
324125cf1a30Sjl139090 }
324225cf1a30Sjl139090 flags |= MC_INJECT_FLAG_ST;
324325cf1a30Sjl139090 break;
324425cf1a30Sjl139090 case MC_INJECT_CMPE:
324525cf1a30Sjl139090 data = 0xabcdefab;
324625cf1a30Sjl139090 stphys(pa, data);
324725cf1a30Sjl139090 cpu_flush_ecache();
324825cf1a30Sjl139090 MC_LOG("CMPE: writing data %x to %lx\n", data, pa);
324925cf1a30Sjl139090 ST_MAC_REG(MAC_MIRR(mcp, bank), MAC_MIRR_BANK_EXCLUSIVE);
325025cf1a30Sjl139090 stphys(pa, data ^ 0xffffffff);
3251738dd194Shyw membar_sync();
325225cf1a30Sjl139090 cpu_flush_ecache();
325325cf1a30Sjl139090 ST_MAC_REG(MAC_MIRR(mcp, bank), 0);
325425cf1a30Sjl139090 MC_LOG("CMPE: write new data %xto %lx\n", data, pa);
325525cf1a30Sjl139090 cntl = 0;
325625cf1a30Sjl139090 break;
325725cf1a30Sjl139090 case MC_INJECT_NOP:
325825cf1a30Sjl139090 cntl = 0;
325925cf1a30Sjl139090 break;
326025cf1a30Sjl139090 default:
326125cf1a30Sjl139090 MC_LOG("mc_inject_error: invalid option\n");
326225cf1a30Sjl139090 cntl = 0;
326325cf1a30Sjl139090 }
326425cf1a30Sjl139090
326525cf1a30Sjl139090 if (cntl) {
326625cf1a30Sjl139090 ST_MAC_REG(MAC_EG_CNTL(mcp, bank), cntl & MAC_EG_SETUP_MASK);
326725cf1a30Sjl139090 ST_MAC_REG(MAC_EG_CNTL(mcp, bank), cntl);
326825cf1a30Sjl139090
326925cf1a30Sjl139090 if (both_sides) {
327025cf1a30Sjl139090 ST_MAC_REG(MAC_EG_CNTL(mcp, bank^1), cntl &
327125cf1a30Sjl139090 MAC_EG_SETUP_MASK);
327225cf1a30Sjl139090 ST_MAC_REG(MAC_EG_CNTL(mcp, bank^1), cntl);
327325cf1a30Sjl139090 }
327425cf1a30Sjl139090 }
327525cf1a30Sjl139090
327625cf1a30Sjl139090 /*
327725cf1a30Sjl139090 * For all injection cases except compare error, we
327825cf1a30Sjl139090 * must write to the PA to trigger the error.
327925cf1a30Sjl139090 */
328025cf1a30Sjl139090
328125cf1a30Sjl139090 if (flags & MC_INJECT_FLAG_ST) {
328225cf1a30Sjl139090 data = 0xf0e0d0c0;
328325cf1a30Sjl139090 MC_LOG("Writing %x to %lx\n", data, pa);
328425cf1a30Sjl139090 stphys(pa, data);
328525cf1a30Sjl139090 cpu_flush_ecache();
328625cf1a30Sjl139090 }
328725cf1a30Sjl139090
328825cf1a30Sjl139090
328925cf1a30Sjl139090 if (flags & MC_INJECT_FLAG_LD) {
3290cfb9e062Shyw if (flags & MC_INJECT_FLAG_PREFETCH) {
3291cfb9e062Shyw /*
3292cfb9e062Shyw * Use strong prefetch operation to
3293cfb9e062Shyw * inject MI errors.
3294cfb9e062Shyw */
3295cfb9e062Shyw page_t *pp;
3296cfb9e062Shyw extern void mc_prefetch(caddr_t);
3297cfb9e062Shyw
3298cfb9e062Shyw MC_LOG("prefetch\n");
3299cfb9e062Shyw
3300cfb9e062Shyw pp = page_numtopp_nolock(pa >> PAGESHIFT);
3301cfb9e062Shyw if (pp != NULL) {
3302cfb9e062Shyw caddr_t va, va1;
3303cfb9e062Shyw
3304cfb9e062Shyw va = ppmapin(pp, PROT_READ|PROT_WRITE,
3305cfb9e062Shyw (caddr_t)-1);
3306cfb9e062Shyw kpreempt_disable();
3307cfb9e062Shyw mc_lock_va((uint64_t)pa, va);
3308cfb9e062Shyw va1 = va + (pa & (PAGESIZE - 1));
3309cfb9e062Shyw mc_prefetch(va1);
3310cfb9e062Shyw mc_unlock_va(va);
3311cfb9e062Shyw kpreempt_enable();
3312cfb9e062Shyw ppmapout(va);
3313cfb9e062Shyw
3314cfb9e062Shyw /*
3315cfb9e062Shyw * For MI errors, we need one extra
3316cfb9e062Shyw * injection for HW patrol to stop.
3317cfb9e062Shyw */
3318cfb9e062Shyw extra_injection_needed = 1;
331925cf1a30Sjl139090 } else {
3320cfb9e062Shyw cmn_err(CE_WARN, "Cannot find page structure"
3321cfb9e062Shyw " for PA %lx\n", pa);
332225cf1a30Sjl139090 }
332325cf1a30Sjl139090 } else {
332425cf1a30Sjl139090 MC_LOG("Reading from %lx\n", pa);
332525cf1a30Sjl139090 data = ldphys(pa);
332625cf1a30Sjl139090 MC_LOG("data = %x\n", data);
332725cf1a30Sjl139090 }
3328cfb9e062Shyw
3329cfb9e062Shyw if (extra_injection_needed) {
3330cfb9e062Shyw /*
3331cfb9e062Shyw * These are the injection cases where the
3332cfb9e062Shyw * requested injected errors will not cause the HW
3333cfb9e062Shyw * patrol to stop. For these cases, we need to inject
3334cfb9e062Shyw * an extra 'real' PTRL error to force the
3335cfb9e062Shyw * HW patrol to stop so that we can report the
3336cfb9e062Shyw * errors injected. Note that we cannot read
3337cfb9e062Shyw * and report error status while the HW patrol
3338cfb9e062Shyw * is running.
3339cfb9e062Shyw */
3340cfb9e062Shyw ST_MAC_REG(MAC_EG_CNTL(mcp, bank),
3341cfb9e062Shyw cntl & MAC_EG_SETUP_MASK);
3342cfb9e062Shyw ST_MAC_REG(MAC_EG_CNTL(mcp, bank), cntl);
3343cfb9e062Shyw
3344cfb9e062Shyw if (both_sides) {
3345cfb9e062Shyw ST_MAC_REG(MAC_EG_CNTL(mcp, bank^1), cntl &
3346cfb9e062Shyw MAC_EG_SETUP_MASK);
3347cfb9e062Shyw ST_MAC_REG(MAC_EG_CNTL(mcp, bank^1), cntl);
3348cfb9e062Shyw }
3349cfb9e062Shyw data = 0xf0e0d0c0;
3350cfb9e062Shyw MC_LOG("Writing %x to %lx\n", data, pa);
3351cfb9e062Shyw stphys(pa, data);
3352cfb9e062Shyw cpu_flush_ecache();
3353cfb9e062Shyw }
335425cf1a30Sjl139090 }
335525cf1a30Sjl139090
335625cf1a30Sjl139090 if (flags & MC_INJECT_FLAG_RESTART) {
335725cf1a30Sjl139090 MC_LOG("Restart patrol\n");
3358738dd194Shyw rsaddr.mi_restartaddr.ma_bd = mcp->mc_board_num;
3359738dd194Shyw rsaddr.mi_restartaddr.ma_bank = bank;
3360738dd194Shyw rsaddr.mi_restartaddr.ma_dimm_addr = dimm_addr;
3361738dd194Shyw rsaddr.mi_valid = 1;
3362738dd194Shyw rsaddr.mi_injectrestart = 1;
336307d06da5SSurya Prakki (void) restart_patrol(mcp, bank, &rsaddr);
336425cf1a30Sjl139090 }
336525cf1a30Sjl139090
336625cf1a30Sjl139090 if (flags & MC_INJECT_FLAG_POLL) {
33670cc8ae86Sav145390 int running;
336837afe445Shyw int ebank = (IS_MIRROR(mcp, bank)) ? MIRROR_IDX(bank) : bank;
336925cf1a30Sjl139090
337025cf1a30Sjl139090 MC_LOG("Poll patrol error\n");
337125cf1a30Sjl139090 stat = LD_MAC_REG(MAC_PTRL_STAT(mcp, bank));
337225cf1a30Sjl139090 cntl = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank));
33730cc8ae86Sav145390 running = cntl & MAC_CNTL_PTRL_START;
3374cfb9e062Shyw
3375cfb9e062Shyw if (!running &&
3376cfb9e062Shyw (stat & (MAC_STAT_PTRL_ERRS|MAC_STAT_MI_ERRS))) {
3377cfb9e062Shyw /*
3378cfb9e062Shyw * HW patrol stopped and we have errors to
3379cfb9e062Shyw * report. Do it.
3380cfb9e062Shyw */
338137afe445Shyw mcp->mc_speedup_period[ebank] = 0;
3382738dd194Shyw rsaddr.mi_valid = 0;
3383738dd194Shyw rsaddr.mi_injectrestart = 0;
3384738dd194Shyw if (IS_MIRROR(mcp, bank)) {
3385738dd194Shyw mc_error_handler_mir(mcp, bank, &rsaddr);
3386738dd194Shyw } else {
3387738dd194Shyw mc_error_handler(mcp, bank, &rsaddr);
3388738dd194Shyw }
338925cf1a30Sjl139090
339007d06da5SSurya Prakki (void) restart_patrol(mcp, bank, &rsaddr);
3391cfb9e062Shyw } else {
3392cfb9e062Shyw /*
3393cfb9e062Shyw * We are expecting to report injected
3394cfb9e062Shyw * errors but the HW patrol is still running.
3395cfb9e062Shyw * Speed up the scanning
3396cfb9e062Shyw */
339737afe445Shyw mcp->mc_speedup_period[ebank] = 2;
3398cfb9e062Shyw MAC_CMD(mcp, bank, 0);
339907d06da5SSurya Prakki (void) restart_patrol(mcp, bank, NULL);
340025cf1a30Sjl139090 }
3401cfb9e062Shyw }
340225cf1a30Sjl139090
340325cf1a30Sjl139090 mutex_exit(&mcp->mc_lock);
340425cf1a30Sjl139090 return (0);
340525cf1a30Sjl139090 }
3406cfb9e062Shyw
340725cf1a30Sjl139090 void
mc_stphysio(uint64_t pa,uint32_t data)340825cf1a30Sjl139090 mc_stphysio(uint64_t pa, uint32_t data)
340925cf1a30Sjl139090 {
341025cf1a30Sjl139090 MC_LOG("0x%x -> pa(%lx)\n", data, pa);
341125cf1a30Sjl139090 stphysio(pa, data);
34120cc8ae86Sav145390
34130cc8ae86Sav145390 /* force the above write to be processed by mac patrol */
3414cfb9e062Shyw data = ldphysio(pa);
3415cfb9e062Shyw MC_LOG("pa(%lx) = 0x%x\n", pa, data);
341625cf1a30Sjl139090 }
341725cf1a30Sjl139090
341825cf1a30Sjl139090 uint32_t
mc_ldphysio(uint64_t pa)341925cf1a30Sjl139090 mc_ldphysio(uint64_t pa)
342025cf1a30Sjl139090 {
342125cf1a30Sjl139090 uint32_t rv;
342225cf1a30Sjl139090
342325cf1a30Sjl139090 rv = ldphysio(pa);
342425cf1a30Sjl139090 MC_LOG("pa(%lx) = 0x%x\n", pa, rv);
342525cf1a30Sjl139090 return (rv);
342625cf1a30Sjl139090 }
34270cc8ae86Sav145390
34280cc8ae86Sav145390 #define isdigit(ch) ((ch) >= '0' && (ch) <= '9')
34290cc8ae86Sav145390
34300cc8ae86Sav145390 /*
34310cc8ae86Sav145390 * parse_unum_memory -- extract the board number and the DIMM name from
34320cc8ae86Sav145390 * the unum.
34330cc8ae86Sav145390 *
34340cc8ae86Sav145390 * Return 0 for success and non-zero for a failure.
34350cc8ae86Sav145390 */
34360cc8ae86Sav145390 int
parse_unum_memory(char * unum,int * board,char * dname)34370cc8ae86Sav145390 parse_unum_memory(char *unum, int *board, char *dname)
34380cc8ae86Sav145390 {
34390cc8ae86Sav145390 char *c;
34400cc8ae86Sav145390 char x, y, z;
34410cc8ae86Sav145390
34420cc8ae86Sav145390 if ((c = strstr(unum, "CMU")) != NULL) {
34430cc8ae86Sav145390 /* DC Model */
34440cc8ae86Sav145390 c += 3;
34450cc8ae86Sav145390 *board = (uint8_t)stoi(&c);
34460cc8ae86Sav145390 if ((c = strstr(c, "MEM")) == NULL) {
34470cc8ae86Sav145390 return (1);
34480cc8ae86Sav145390 }
34490cc8ae86Sav145390 c += 3;
34500cc8ae86Sav145390 if (strlen(c) < 3) {
34510cc8ae86Sav145390 return (2);
34520cc8ae86Sav145390 }
34530cc8ae86Sav145390 if ((!isdigit(c[0])) || (!(isdigit(c[1]))) ||
34540cc8ae86Sav145390 ((c[2] != 'A') && (c[2] != 'B'))) {
34550cc8ae86Sav145390 return (3);
34560cc8ae86Sav145390 }
34570cc8ae86Sav145390 x = c[0];
34580cc8ae86Sav145390 y = c[1];
34590cc8ae86Sav145390 z = c[2];
34600cc8ae86Sav145390 } else if ((c = strstr(unum, "MBU_")) != NULL) {
346178ed97a7Sjl139090 /* FF1/FF2/Ikkaku Model */
34620cc8ae86Sav145390 c += 4;
34630cc8ae86Sav145390 if ((c[0] != 'A') && (c[0] != 'B')) {
34640cc8ae86Sav145390 return (4);
34650cc8ae86Sav145390 }
346678ed97a7Sjl139090 if (plat_model == MODEL_IKKAKU) {
346778ed97a7Sjl139090 /* Ikkaku Model */
346878ed97a7Sjl139090 x = '0';
346978ed97a7Sjl139090 *board = 0;
347078ed97a7Sjl139090 } else {
347178ed97a7Sjl139090 /* FF1/FF2 Model */
34720cc8ae86Sav145390 if ((c = strstr(c, "MEMB")) == NULL) {
34730cc8ae86Sav145390 return (5);
34740cc8ae86Sav145390 }
34750cc8ae86Sav145390 c += 4;
34760cc8ae86Sav145390
34770cc8ae86Sav145390 x = c[0];
34780cc8ae86Sav145390 *board = ((uint8_t)stoi(&c)) / 4;
347978ed97a7Sjl139090 }
348078ed97a7Sjl139090
34810cc8ae86Sav145390 if ((c = strstr(c, "MEM")) == NULL) {
34820cc8ae86Sav145390 return (6);
34830cc8ae86Sav145390 }
34840cc8ae86Sav145390 c += 3;
34850cc8ae86Sav145390 if (strlen(c) < 2) {
34860cc8ae86Sav145390 return (7);
34870cc8ae86Sav145390 }
34880cc8ae86Sav145390 if ((!isdigit(c[0])) || ((c[1] != 'A') && (c[1] != 'B'))) {
34890cc8ae86Sav145390 return (8);
34900cc8ae86Sav145390 }
34910cc8ae86Sav145390 y = c[0];
34920cc8ae86Sav145390 z = c[1];
34930cc8ae86Sav145390 } else {
34940cc8ae86Sav145390 return (9);
34950cc8ae86Sav145390 }
34960cc8ae86Sav145390 if (*board < 0) {
34970cc8ae86Sav145390 return (10);
34980cc8ae86Sav145390 }
34990cc8ae86Sav145390 dname[0] = x;
35000cc8ae86Sav145390 dname[1] = y;
35010cc8ae86Sav145390 dname[2] = z;
35020cc8ae86Sav145390 dname[3] = '\0';
35030cc8ae86Sav145390 return (0);
35040cc8ae86Sav145390 }
35050cc8ae86Sav145390
35060cc8ae86Sav145390 /*
35070cc8ae86Sav145390 * mc_get_mem_sid_dimm -- Get the serial-ID for a given board and
35080cc8ae86Sav145390 * the DIMM name.
35090cc8ae86Sav145390 */
35100cc8ae86Sav145390 int
mc_get_mem_sid_dimm(mc_opl_t * mcp,char * dname,char * buf,int buflen,int * lenp)35110cc8ae86Sav145390 mc_get_mem_sid_dimm(mc_opl_t *mcp, char *dname, char *buf,
35120cc8ae86Sav145390 int buflen, int *lenp)
35130cc8ae86Sav145390 {
35140cc8ae86Sav145390 int ret = ENODEV;
35150cc8ae86Sav145390 mc_dimm_info_t *d = NULL;
35160cc8ae86Sav145390
3517feb5832bSMary Beale if ((d = mcp->mc_dimm_list) == NULL) {
3518feb5832bSMary Beale MC_LOG("mc_get_mem_sid_dimm: mc_dimm_list is NULL\n");
3519feb5832bSMary Beale return (EINVAL);
3520feb5832bSMary Beale }
35210cc8ae86Sav145390
35220cc8ae86Sav145390 for (; d != NULL; d = d->md_next) {
35230cc8ae86Sav145390 if (strcmp(d->md_dimmname, dname) == 0) {
35240cc8ae86Sav145390 break;
35250cc8ae86Sav145390 }
35260cc8ae86Sav145390 }
35270cc8ae86Sav145390 if (d != NULL) {
35280cc8ae86Sav145390 *lenp = strlen(d->md_serial) + strlen(d->md_partnum);
35290cc8ae86Sav145390 if (buflen <= *lenp) {
35300cc8ae86Sav145390 cmn_err(CE_WARN, "mc_get_mem_sid_dimm: "
35310cc8ae86Sav145390 "buflen is smaller than %d\n", *lenp);
35320cc8ae86Sav145390 ret = ENOSPC;
35330cc8ae86Sav145390 } else {
353407d06da5SSurya Prakki (void) snprintf(buf, buflen, "%s:%s",
35350cc8ae86Sav145390 d->md_serial, d->md_partnum);
35360cc8ae86Sav145390 ret = 0;
35370cc8ae86Sav145390 }
35380cc8ae86Sav145390 }
35390cc8ae86Sav145390 MC_LOG("mc_get_mem_sid_dimm: Ret=%d Name=%s Serial-ID=%s\n",
35400cc8ae86Sav145390 ret, dname, (ret == 0) ? buf : "");
35410cc8ae86Sav145390 return (ret);
35420cc8ae86Sav145390 }
35430cc8ae86Sav145390
35440cc8ae86Sav145390 int
mc_set_mem_sid(mc_opl_t * mcp,char * buf,int buflen,int sb,int bank,uint32_t mf_type,uint32_t d_slot)3545aeb241b2Sav145390 mc_set_mem_sid(mc_opl_t *mcp, char *buf, int buflen, int sb,
35460cc8ae86Sav145390 int bank, uint32_t mf_type, uint32_t d_slot)
35470cc8ae86Sav145390 {
35480cc8ae86Sav145390 int lenp = buflen;
35490cc8ae86Sav145390 int id;
35500cc8ae86Sav145390 int ret;
35510cc8ae86Sav145390 char *dimmnm;
35520cc8ae86Sav145390
3553056c948bStsien if (mf_type == FLT_TYPE_INTERMITTENT_CE ||
3554056c948bStsien mf_type == FLT_TYPE_PERMANENT_CE) {
35550cc8ae86Sav145390 if (plat_model == MODEL_DC) {
355678ed97a7Sjl139090 /*
355778ed97a7Sjl139090 * All DC models
355878ed97a7Sjl139090 */
35590cc8ae86Sav145390 id = BD_BK_SLOT_TO_INDEX(0, bank, d_slot);
3560aeb241b2Sav145390 dimmnm = mc_dc_dimm_unum_table[id];
35610cc8ae86Sav145390 } else {
356278ed97a7Sjl139090 /*
356378ed97a7Sjl139090 * All FF and Ikkaku models
356478ed97a7Sjl139090 */
35650cc8ae86Sav145390 id = BD_BK_SLOT_TO_INDEX(sb, bank, d_slot);
3566aeb241b2Sav145390 dimmnm = mc_ff_dimm_unum_table[id];
35670cc8ae86Sav145390 }
35680cc8ae86Sav145390 if ((ret = mc_get_mem_sid_dimm(mcp, dimmnm, buf, buflen,
35690cc8ae86Sav145390 &lenp)) != 0) {
35700cc8ae86Sav145390 return (ret);
35710cc8ae86Sav145390 }
35720cc8ae86Sav145390 } else {
35730cc8ae86Sav145390 return (1);
35740cc8ae86Sav145390 }
35750cc8ae86Sav145390
35760cc8ae86Sav145390 return (0);
35770cc8ae86Sav145390 }
35780cc8ae86Sav145390
35790cc8ae86Sav145390 /*
35800cc8ae86Sav145390 * mc_get_mem_sid -- get the DIMM serial-ID corresponding to the unum.
35810cc8ae86Sav145390 */
35820cc8ae86Sav145390 int
mc_get_mem_sid(char * unum,char * buf,int buflen,int * lenp)35830cc8ae86Sav145390 mc_get_mem_sid(char *unum, char *buf, int buflen, int *lenp)
35840cc8ae86Sav145390 {
35850cc8ae86Sav145390 int i;
35860cc8ae86Sav145390 int ret = ENODEV;
35870cc8ae86Sav145390 int board;
35880cc8ae86Sav145390 char dname[MCOPL_MAX_DIMMNAME + 1];
35890cc8ae86Sav145390 mc_opl_t *mcp;
35900cc8ae86Sav145390
35910cc8ae86Sav145390 MC_LOG("mc_get_mem_sid: unum=%s buflen=%d\n", unum, buflen);
35920cc8ae86Sav145390 if ((ret = parse_unum_memory(unum, &board, dname)) != 0) {
35930cc8ae86Sav145390 MC_LOG("mc_get_mem_sid: unum(%s) parsing failed ret=%d\n",
35940cc8ae86Sav145390 unum, ret);
35950cc8ae86Sav145390 return (EINVAL);
35960cc8ae86Sav145390 }
35970cc8ae86Sav145390
35980cc8ae86Sav145390 if (board < 0) {
35990cc8ae86Sav145390 MC_LOG("mc_get_mem_sid: Invalid board=%d dimm=%s\n",
36000cc8ae86Sav145390 board, dname);
36010cc8ae86Sav145390 return (EINVAL);
36020cc8ae86Sav145390 }
36030cc8ae86Sav145390
36040cc8ae86Sav145390 mutex_enter(&mcmutex);
36051039f409Sav145390 /*
36061039f409Sav145390 * return ENOENT if we can not find the matching board.
36071039f409Sav145390 */
36081039f409Sav145390 ret = ENOENT;
36090cc8ae86Sav145390 for (i = 0; i < OPL_MAX_BOARDS; i++) {
36100cc8ae86Sav145390 if ((mcp = mc_instances[i]) == NULL)
36110cc8ae86Sav145390 continue;
36120cc8ae86Sav145390 mutex_enter(&mcp->mc_lock);
3613aeb241b2Sav145390 if (mcp->mc_phys_board_num != board) {
3614aeb241b2Sav145390 mutex_exit(&mcp->mc_lock);
3615aeb241b2Sav145390 continue;
3616aeb241b2Sav145390 }
3617aeb241b2Sav145390 ret = mc_get_mem_sid_dimm(mcp, dname, buf, buflen, lenp);
3618aeb241b2Sav145390 if (ret == 0) {
36190cc8ae86Sav145390 mutex_exit(&mcp->mc_lock);
36200cc8ae86Sav145390 break;
36210cc8ae86Sav145390 }
36220cc8ae86Sav145390 mutex_exit(&mcp->mc_lock);
36230cc8ae86Sav145390 }
36240cc8ae86Sav145390 mutex_exit(&mcmutex);
36250cc8ae86Sav145390 return (ret);
36260cc8ae86Sav145390 }
36270cc8ae86Sav145390
36280cc8ae86Sav145390 /*
36290cc8ae86Sav145390 * mc_get_mem_offset -- get the offset in a DIMM for a given physical address.
36300cc8ae86Sav145390 */
36310cc8ae86Sav145390 int
mc_get_mem_offset(uint64_t paddr,uint64_t * offp)36320cc8ae86Sav145390 mc_get_mem_offset(uint64_t paddr, uint64_t *offp)
36330cc8ae86Sav145390 {
36340cc8ae86Sav145390 int i;
36350cc8ae86Sav145390 int ret = ENODEV;
36360cc8ae86Sav145390 mc_addr_t maddr;
36370cc8ae86Sav145390 mc_opl_t *mcp;
36380cc8ae86Sav145390
36390cc8ae86Sav145390 mutex_enter(&mcmutex);
3640c964b0e6Sraghuram for (i = 0; ((i < OPL_MAX_BOARDS) && (ret != 0)); i++) {
36410cc8ae86Sav145390 if ((mcp = mc_instances[i]) == NULL)
36420cc8ae86Sav145390 continue;
36430cc8ae86Sav145390 mutex_enter(&mcp->mc_lock);
36440cc8ae86Sav145390 if (!pa_is_valid(mcp, paddr)) {
36450cc8ae86Sav145390 mutex_exit(&mcp->mc_lock);
36460cc8ae86Sav145390 continue;
36470cc8ae86Sav145390 }
36480cc8ae86Sav145390 if (pa_to_maddr(mcp, paddr, &maddr) == 0) {
36490cc8ae86Sav145390 *offp = maddr.ma_dimm_addr;
36500cc8ae86Sav145390 ret = 0;
36510cc8ae86Sav145390 }
36520cc8ae86Sav145390 mutex_exit(&mcp->mc_lock);
36530cc8ae86Sav145390 }
36540cc8ae86Sav145390 mutex_exit(&mcmutex);
36550cc8ae86Sav145390 MC_LOG("mc_get_mem_offset: Ret=%d paddr=0x%lx offset=0x%lx\n",
36560cc8ae86Sav145390 ret, paddr, *offp);
36570cc8ae86Sav145390 return (ret);
36580cc8ae86Sav145390 }
36590cc8ae86Sav145390
36600cc8ae86Sav145390 /*
36610cc8ae86Sav145390 * dname_to_bankslot - Get the bank and slot number from the DIMM name.
36620cc8ae86Sav145390 */
36630cc8ae86Sav145390 int
dname_to_bankslot(char * dname,int * bank,int * slot)36640cc8ae86Sav145390 dname_to_bankslot(char *dname, int *bank, int *slot)
36650cc8ae86Sav145390 {
36660cc8ae86Sav145390 int i;
36670cc8ae86Sav145390 int tsz;
36680cc8ae86Sav145390 char **tbl;
36690cc8ae86Sav145390
367078ed97a7Sjl139090 if (plat_model == MODEL_DC) {
367178ed97a7Sjl139090 /*
367278ed97a7Sjl139090 * All DC models
367378ed97a7Sjl139090 */
36740cc8ae86Sav145390 tbl = mc_dc_dimm_unum_table;
36750cc8ae86Sav145390 tsz = OPL_MAX_DIMMS;
36760cc8ae86Sav145390 } else {
367778ed97a7Sjl139090 /*
367878ed97a7Sjl139090 * All FF and Ikkaku models
367978ed97a7Sjl139090 */
36800cc8ae86Sav145390 tbl = mc_ff_dimm_unum_table;
36810cc8ae86Sav145390 tsz = 2 * OPL_MAX_DIMMS;
36820cc8ae86Sav145390 }
36830cc8ae86Sav145390
36840cc8ae86Sav145390 for (i = 0; i < tsz; i++) {
36850cc8ae86Sav145390 if (strcmp(dname, tbl[i]) == 0) {
36860cc8ae86Sav145390 break;
36870cc8ae86Sav145390 }
36880cc8ae86Sav145390 }
36890cc8ae86Sav145390 if (i == tsz) {
36900cc8ae86Sav145390 return (1);
36910cc8ae86Sav145390 }
36920cc8ae86Sav145390 *bank = INDEX_TO_BANK(i);
36930cc8ae86Sav145390 *slot = INDEX_TO_SLOT(i);
36940cc8ae86Sav145390 return (0);
36950cc8ae86Sav145390 }
36960cc8ae86Sav145390
36970cc8ae86Sav145390 /*
36980cc8ae86Sav145390 * mc_get_mem_addr -- get the physical address of a DIMM corresponding
36990cc8ae86Sav145390 * to the unum and sid.
37000cc8ae86Sav145390 */
37010cc8ae86Sav145390 int
mc_get_mem_addr(char * unum,char * sid,uint64_t offset,uint64_t * paddr)37020cc8ae86Sav145390 mc_get_mem_addr(char *unum, char *sid, uint64_t offset, uint64_t *paddr)
37030cc8ae86Sav145390 {
37040cc8ae86Sav145390 int board;
37050cc8ae86Sav145390 int bank;
37060cc8ae86Sav145390 int slot;
37070cc8ae86Sav145390 int i;
37080cc8ae86Sav145390 int ret = ENODEV;
37090cc8ae86Sav145390 char dname[MCOPL_MAX_DIMMNAME + 1];
37100cc8ae86Sav145390 mc_addr_t maddr;
37110cc8ae86Sav145390 mc_opl_t *mcp;
37120cc8ae86Sav145390
37130cc8ae86Sav145390 MC_LOG("mc_get_mem_addr: unum=%s sid=%s offset=0x%lx\n",
37140cc8ae86Sav145390 unum, sid, offset);
37150cc8ae86Sav145390 if (parse_unum_memory(unum, &board, dname) != 0) {
37160cc8ae86Sav145390 MC_LOG("mc_get_mem_sid: unum(%s) parsing failed ret=%d\n",
37170cc8ae86Sav145390 unum, ret);
37180cc8ae86Sav145390 return (EINVAL);
37190cc8ae86Sav145390 }
37200cc8ae86Sav145390
37210cc8ae86Sav145390 if (board < 0) {
37220cc8ae86Sav145390 MC_LOG("mc_get_mem_addr: Invalid board=%d dimm=%s\n",
37230cc8ae86Sav145390 board, dname);
37240cc8ae86Sav145390 return (EINVAL);
37250cc8ae86Sav145390 }
37260cc8ae86Sav145390
37270cc8ae86Sav145390 mutex_enter(&mcmutex);
37280cc8ae86Sav145390 for (i = 0; i < OPL_MAX_BOARDS; i++) {
37290cc8ae86Sav145390 if ((mcp = mc_instances[i]) == NULL)
37300cc8ae86Sav145390 continue;
37310cc8ae86Sav145390 mutex_enter(&mcp->mc_lock);
3732aeb241b2Sav145390 if (mcp->mc_phys_board_num != board) {
37330cc8ae86Sav145390 mutex_exit(&mcp->mc_lock);
37340cc8ae86Sav145390 continue;
37350cc8ae86Sav145390 }
37360cc8ae86Sav145390
37370cc8ae86Sav145390 ret = dname_to_bankslot(dname, &bank, &slot);
37380cc8ae86Sav145390 MC_LOG("mc_get_mem_addr: bank=%d slot=%d\n", bank, slot);
37390cc8ae86Sav145390 if (ret != 0) {
37400cc8ae86Sav145390 MC_LOG("mc_get_mem_addr: dname_to_bankslot failed\n");
37410cc8ae86Sav145390 ret = ENODEV;
37420cc8ae86Sav145390 } else {
3743aeb241b2Sav145390 maddr.ma_bd = mcp->mc_board_num;
37440cc8ae86Sav145390 maddr.ma_bank = bank;
37450cc8ae86Sav145390 maddr.ma_dimm_addr = offset;
37460cc8ae86Sav145390 ret = mcaddr_to_pa(mcp, &maddr, paddr);
37470cc8ae86Sav145390 if (ret != 0) {
37480cc8ae86Sav145390 MC_LOG("mc_get_mem_addr: "
37490cc8ae86Sav145390 "mcaddr_to_pa failed\n");
37500cc8ae86Sav145390 ret = ENODEV;
37510b240fcdSwh31274 mutex_exit(&mcp->mc_lock);
37520b240fcdSwh31274 continue;
37530cc8ae86Sav145390 }
3754aeb241b2Sav145390 mutex_exit(&mcp->mc_lock);
3755aeb241b2Sav145390 break;
37560cc8ae86Sav145390 }
37570cc8ae86Sav145390 mutex_exit(&mcp->mc_lock);
37580cc8ae86Sav145390 }
37590cc8ae86Sav145390 mutex_exit(&mcmutex);
37600cc8ae86Sav145390 MC_LOG("mc_get_mem_addr: Ret=%d, Paddr=0x%lx\n", ret, *paddr);
37610cc8ae86Sav145390 return (ret);
37620cc8ae86Sav145390 }
37630cc8ae86Sav145390
37640cc8ae86Sav145390 static void
mc_free_dimm_list(mc_dimm_info_t * d)37650cc8ae86Sav145390 mc_free_dimm_list(mc_dimm_info_t *d)
37660cc8ae86Sav145390 {
37670cc8ae86Sav145390 mc_dimm_info_t *next;
37680cc8ae86Sav145390
37690cc8ae86Sav145390 while (d != NULL) {
37700cc8ae86Sav145390 next = d->md_next;
37710cc8ae86Sav145390 kmem_free(d, sizeof (mc_dimm_info_t));
37720cc8ae86Sav145390 d = next;
37730cc8ae86Sav145390 }
37740cc8ae86Sav145390 }
37750cc8ae86Sav145390
37760cc8ae86Sav145390 /*
37770cc8ae86Sav145390 * mc_get_dimm_list -- get the list of dimms with serial-id info
37780cc8ae86Sav145390 * from the SP.
37790cc8ae86Sav145390 */
37800cc8ae86Sav145390 mc_dimm_info_t *
mc_get_dimm_list(mc_opl_t * mcp)37810cc8ae86Sav145390 mc_get_dimm_list(mc_opl_t *mcp)
37820cc8ae86Sav145390 {
37830cc8ae86Sav145390 uint32_t bufsz;
37840cc8ae86Sav145390 uint32_t maxbufsz;
37850cc8ae86Sav145390 int ret;
37860cc8ae86Sav145390 int sexp;
37870cc8ae86Sav145390 board_dimm_info_t *bd_dimmp;
37880cc8ae86Sav145390 mc_dimm_info_t *dimm_list = NULL;
37890cc8ae86Sav145390
37900cc8ae86Sav145390 maxbufsz = bufsz = sizeof (board_dimm_info_t) +
37910cc8ae86Sav145390 ((MCOPL_MAX_DIMMNAME + MCOPL_MAX_SERIAL +
37920cc8ae86Sav145390 MCOPL_MAX_PARTNUM) * OPL_MAX_DIMMS);
37930cc8ae86Sav145390
37940cc8ae86Sav145390 bd_dimmp = (board_dimm_info_t *)kmem_alloc(bufsz, KM_SLEEP);
37950cc8ae86Sav145390 ret = scf_get_dimminfo(mcp->mc_board_num, (void *)bd_dimmp, &bufsz);
37960cc8ae86Sav145390
37970cc8ae86Sav145390 MC_LOG("mc_get_dimm_list: scf_service_getinfo returned=%d\n", ret);
37980cc8ae86Sav145390 if (ret == 0) {
37990cc8ae86Sav145390 sexp = sizeof (board_dimm_info_t) +
38000cc8ae86Sav145390 ((bd_dimmp->bd_dnamesz + bd_dimmp->bd_serialsz +
38010cc8ae86Sav145390 bd_dimmp->bd_partnumsz) * bd_dimmp->bd_numdimms);
38020cc8ae86Sav145390
38030cc8ae86Sav145390 if ((bd_dimmp->bd_version == OPL_DIMM_INFO_VERSION) &&
38040cc8ae86Sav145390 (bd_dimmp->bd_dnamesz <= MCOPL_MAX_DIMMNAME) &&
38050cc8ae86Sav145390 (bd_dimmp->bd_serialsz <= MCOPL_MAX_SERIAL) &&
38060cc8ae86Sav145390 (bd_dimmp->bd_partnumsz <= MCOPL_MAX_PARTNUM) &&
38070cc8ae86Sav145390 (sexp <= bufsz)) {
38080cc8ae86Sav145390
38090cc8ae86Sav145390 #ifdef DEBUG
38100cc8ae86Sav145390 if (oplmc_debug)
38110cc8ae86Sav145390 mc_dump_dimm_info(bd_dimmp);
38120cc8ae86Sav145390 #endif
38130cc8ae86Sav145390 dimm_list = mc_prepare_dimmlist(bd_dimmp);
38140cc8ae86Sav145390
38150cc8ae86Sav145390 } else {
38160cc8ae86Sav145390 cmn_err(CE_WARN, "DIMM info version mismatch\n");
38170cc8ae86Sav145390 }
38180cc8ae86Sav145390 }
38190cc8ae86Sav145390 kmem_free(bd_dimmp, maxbufsz);
382007d06da5SSurya Prakki MC_LOG("mc_get_dimm_list: dimmlist=0x%p\n", (void *)dimm_list);
38210cc8ae86Sav145390 return (dimm_list);
38220cc8ae86Sav145390 }
38230cc8ae86Sav145390
38240cc8ae86Sav145390 /*
38251039f409Sav145390 * mc_prepare_dimmlist - Prepare the dimm list from the information
38261039f409Sav145390 * received from the SP.
38270cc8ae86Sav145390 */
38280cc8ae86Sav145390 mc_dimm_info_t *
mc_prepare_dimmlist(board_dimm_info_t * bd_dimmp)38290cc8ae86Sav145390 mc_prepare_dimmlist(board_dimm_info_t *bd_dimmp)
38300cc8ae86Sav145390 {
38310cc8ae86Sav145390 char *dimm_name;
38320cc8ae86Sav145390 char *serial;
38330cc8ae86Sav145390 char *part;
38340cc8ae86Sav145390 int dimm;
38350cc8ae86Sav145390 int dnamesz = bd_dimmp->bd_dnamesz;
38360cc8ae86Sav145390 int sersz = bd_dimmp->bd_serialsz;
38370cc8ae86Sav145390 int partsz = bd_dimmp->bd_partnumsz;
38380cc8ae86Sav145390 mc_dimm_info_t *dimm_list = NULL;
38390cc8ae86Sav145390 mc_dimm_info_t *d;
38400cc8ae86Sav145390
38410cc8ae86Sav145390 dimm_name = (char *)(bd_dimmp + 1);
38420cc8ae86Sav145390 for (dimm = 0; dimm < bd_dimmp->bd_numdimms; dimm++) {
38430cc8ae86Sav145390
38440cc8ae86Sav145390 d = (mc_dimm_info_t *)kmem_alloc(sizeof (mc_dimm_info_t),
38450cc8ae86Sav145390 KM_SLEEP);
3846ad59b69dSbm42561
3847ad59b69dSbm42561 bcopy(dimm_name, d->md_dimmname, dnamesz);
3848ad59b69dSbm42561 d->md_dimmname[dnamesz] = 0;
3849ad59b69dSbm42561
38500cc8ae86Sav145390 serial = dimm_name + dnamesz;
3851ad59b69dSbm42561 bcopy(serial, d->md_serial, sersz);
3852ad59b69dSbm42561 d->md_serial[sersz] = 0;
3853ad59b69dSbm42561
38540cc8ae86Sav145390 part = serial + sersz;
3855ad59b69dSbm42561 bcopy(part, d->md_partnum, partsz);
3856ad59b69dSbm42561 d->md_partnum[partsz] = 0;
38570cc8ae86Sav145390
38580cc8ae86Sav145390 d->md_next = dimm_list;
38590cc8ae86Sav145390 dimm_list = d;
38600cc8ae86Sav145390 dimm_name = part + partsz;
38610cc8ae86Sav145390 }
38620cc8ae86Sav145390 return (dimm_list);
38630cc8ae86Sav145390 }
38640cc8ae86Sav145390
38650b240fcdSwh31274 static int
mc_get_mem_fmri(mc_flt_page_t * fpag,char ** unum)38660b240fcdSwh31274 mc_get_mem_fmri(mc_flt_page_t *fpag, char **unum)
38670b240fcdSwh31274 {
38680b240fcdSwh31274 if (fpag->fmri_addr == 0 || fpag->fmri_sz > MEM_FMRI_MAX_BUFSIZE)
38690b240fcdSwh31274 return (EINVAL);
38700b240fcdSwh31274
38710b240fcdSwh31274 *unum = kmem_alloc(fpag->fmri_sz, KM_SLEEP);
38720b240fcdSwh31274 if (copyin((void *)fpag->fmri_addr, *unum, fpag->fmri_sz) != 0) {
38730b240fcdSwh31274 kmem_free(*unum, fpag->fmri_sz);
38740b240fcdSwh31274 return (EFAULT);
38750b240fcdSwh31274 }
38760b240fcdSwh31274 return (0);
38770b240fcdSwh31274 }
38780b240fcdSwh31274
38790b240fcdSwh31274 static int
mc_scf_log_event(mc_flt_page_t * flt_pag)38800b240fcdSwh31274 mc_scf_log_event(mc_flt_page_t *flt_pag)
38810b240fcdSwh31274 {
38820b240fcdSwh31274 mc_opl_t *mcp;
38830b240fcdSwh31274 int board, bank, slot;
38840b240fcdSwh31274 int len, rv = 0;
38850b240fcdSwh31274 char *unum, *sid;
38860b240fcdSwh31274 char dname[MCOPL_MAX_DIMMNAME + 1];
38870b240fcdSwh31274 size_t sid_sz;
38880b240fcdSwh31274 uint64_t pa;
38890b240fcdSwh31274 mc_flt_stat_t flt_stat;
38900b240fcdSwh31274
38910b240fcdSwh31274 if ((sid_sz = cpu_get_name_bufsize()) == 0)
38920b240fcdSwh31274 return (ENOTSUP);
38930b240fcdSwh31274
38940b240fcdSwh31274 if ((rv = mc_get_mem_fmri(flt_pag, &unum)) != 0) {
38950b240fcdSwh31274 MC_LOG("mc_scf_log_event: mc_get_mem_fmri failed\n");
38960b240fcdSwh31274 return (rv);
38970b240fcdSwh31274 }
38980b240fcdSwh31274
38990b240fcdSwh31274 sid = kmem_zalloc(sid_sz, KM_SLEEP);
39000b240fcdSwh31274
39010b240fcdSwh31274 if ((rv = mc_get_mem_sid(unum, sid, sid_sz, &len)) != 0) {
39020b240fcdSwh31274 MC_LOG("mc_scf_log_event: mc_get_mem_sid failed\n");
39030b240fcdSwh31274 goto out;
39040b240fcdSwh31274 }
39050b240fcdSwh31274
39060b240fcdSwh31274 if ((rv = mc_get_mem_addr(unum, sid, (uint64_t)flt_pag->err_add,
39070b240fcdSwh31274 &pa)) != 0) {
39080b240fcdSwh31274 MC_LOG("mc_scf_log_event: mc_get_mem_addr failed\n");
39090b240fcdSwh31274 goto out;
39100b240fcdSwh31274 }
39110b240fcdSwh31274
39120b240fcdSwh31274 if (parse_unum_memory(unum, &board, dname) != 0) {
39130b240fcdSwh31274 MC_LOG("mc_scf_log_event: parse_unum_memory failed\n");
39140b240fcdSwh31274 rv = EINVAL;
39150b240fcdSwh31274 goto out;
39160b240fcdSwh31274 }
39170b240fcdSwh31274
39180b240fcdSwh31274 if (board < 0) {
39190b240fcdSwh31274 MC_LOG("mc_scf_log_event: Invalid board=%d dimm=%s\n",
39200b240fcdSwh31274 board, dname);
39210b240fcdSwh31274 rv = EINVAL;
39220b240fcdSwh31274 goto out;
39230b240fcdSwh31274 }
39240b240fcdSwh31274
39250b240fcdSwh31274 if (dname_to_bankslot(dname, &bank, &slot) != 0) {
39260b240fcdSwh31274 MC_LOG("mc_scf_log_event: dname_to_bankslot failed\n");
39270b240fcdSwh31274 rv = EINVAL;
39280b240fcdSwh31274 goto out;
39290b240fcdSwh31274 }
39300b240fcdSwh31274
39310b240fcdSwh31274 mutex_enter(&mcmutex);
39320b240fcdSwh31274
39330b240fcdSwh31274 flt_stat.mf_err_add = flt_pag->err_add;
39340b240fcdSwh31274 flt_stat.mf_err_log = flt_pag->err_log;
39350b240fcdSwh31274 flt_stat.mf_flt_paddr = pa;
39360b240fcdSwh31274
39370b240fcdSwh31274 if ((mcp = mc_pa_to_mcp(pa)) == NULL) {
39380b240fcdSwh31274 mutex_exit(&mcmutex);
39390b240fcdSwh31274 MC_LOG("mc_scf_log_event: invalid pa\n");
39400b240fcdSwh31274 rv = EINVAL;
39410b240fcdSwh31274 goto out;
39420b240fcdSwh31274 }
39430b240fcdSwh31274
39440b240fcdSwh31274 MC_LOG("mc_scf_log_event: DIMM%s, /LSB%d/B%d/%x, pa %lx elog %x\n",
39450b240fcdSwh31274 unum, mcp->mc_board_num, bank, flt_pag->err_add, pa,
39460b240fcdSwh31274 flt_pag->err_log);
39470b240fcdSwh31274
39480b240fcdSwh31274 mutex_enter(&mcp->mc_lock);
39490b240fcdSwh31274
39500b240fcdSwh31274 if (!pa_is_valid(mcp, pa)) {
39510b240fcdSwh31274 mutex_exit(&mcp->mc_lock);
39520b240fcdSwh31274 mutex_exit(&mcmutex);
39530b240fcdSwh31274 rv = EINVAL;
39540b240fcdSwh31274 goto out;
39550b240fcdSwh31274 }
39560b240fcdSwh31274
39570b240fcdSwh31274 rv = 0;
39580b240fcdSwh31274
39590b240fcdSwh31274 mc_queue_scf_log(mcp, &flt_stat, bank);
39600b240fcdSwh31274
39610b240fcdSwh31274 mutex_exit(&mcp->mc_lock);
39620b240fcdSwh31274 mutex_exit(&mcmutex);
39630b240fcdSwh31274
39640b240fcdSwh31274 out:
39650b240fcdSwh31274 kmem_free(unum, flt_pag->fmri_sz);
39660b240fcdSwh31274 kmem_free(sid, sid_sz);
39670b240fcdSwh31274
39680b240fcdSwh31274 return (rv);
39690b240fcdSwh31274 }
39700b240fcdSwh31274
39710cc8ae86Sav145390 #ifdef DEBUG
39720cc8ae86Sav145390 void
mc_dump_dimm(char * buf,int dnamesz,int serialsz,int partnumsz)39730cc8ae86Sav145390 mc_dump_dimm(char *buf, int dnamesz, int serialsz, int partnumsz)
39740cc8ae86Sav145390 {
39750cc8ae86Sav145390 char dname[MCOPL_MAX_DIMMNAME + 1];
39760cc8ae86Sav145390 char serial[MCOPL_MAX_SERIAL + 1];
39770cc8ae86Sav145390 char part[ MCOPL_MAX_PARTNUM + 1];
39780cc8ae86Sav145390 char *b;
39790cc8ae86Sav145390
39800cc8ae86Sav145390 b = buf;
3981ad59b69dSbm42561 bcopy(b, dname, dnamesz);
3982ad59b69dSbm42561 dname[dnamesz] = 0;
3983ad59b69dSbm42561
39840cc8ae86Sav145390 b += dnamesz;
3985ad59b69dSbm42561 bcopy(b, serial, serialsz);
3986ad59b69dSbm42561 serial[serialsz] = 0;
3987ad59b69dSbm42561
39880cc8ae86Sav145390 b += serialsz;
3989ad59b69dSbm42561 bcopy(b, part, partnumsz);
3990ad59b69dSbm42561 part[partnumsz] = 0;
3991ad59b69dSbm42561
39920cc8ae86Sav145390 printf("DIMM=%s Serial=%s PartNum=%s\n", dname, serial, part);
39930cc8ae86Sav145390 }
39940cc8ae86Sav145390
39950cc8ae86Sav145390 void
mc_dump_dimm_info(board_dimm_info_t * bd_dimmp)39960cc8ae86Sav145390 mc_dump_dimm_info(board_dimm_info_t *bd_dimmp)
39970cc8ae86Sav145390 {
39980cc8ae86Sav145390 int dimm;
39990cc8ae86Sav145390 int dnamesz = bd_dimmp->bd_dnamesz;
40000cc8ae86Sav145390 int sersz = bd_dimmp->bd_serialsz;
40010cc8ae86Sav145390 int partsz = bd_dimmp->bd_partnumsz;
40020cc8ae86Sav145390 char *buf;
40030cc8ae86Sav145390
40040cc8ae86Sav145390 printf("Version=%d Board=%02d DIMMs=%d NameSize=%d "
40050cc8ae86Sav145390 "SerialSize=%d PartnumSize=%d\n", bd_dimmp->bd_version,
40060cc8ae86Sav145390 bd_dimmp->bd_boardnum, bd_dimmp->bd_numdimms, bd_dimmp->bd_dnamesz,
40070cc8ae86Sav145390 bd_dimmp->bd_serialsz, bd_dimmp->bd_partnumsz);
40080cc8ae86Sav145390 printf("======================================================\n");
40090cc8ae86Sav145390
40100cc8ae86Sav145390 buf = (char *)(bd_dimmp + 1);
40110cc8ae86Sav145390 for (dimm = 0; dimm < bd_dimmp->bd_numdimms; dimm++) {
40120cc8ae86Sav145390 mc_dump_dimm(buf, dnamesz, sersz, partsz);
40130cc8ae86Sav145390 buf += dnamesz + sersz + partsz;
40140cc8ae86Sav145390 }
40150cc8ae86Sav145390 printf("======================================================\n");
40160cc8ae86Sav145390 }
40170cc8ae86Sav145390
40180cc8ae86Sav145390
40190cc8ae86Sav145390 /* ARGSUSED */
40200cc8ae86Sav145390 static int
mc_ioctl_debug(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)40210cc8ae86Sav145390 mc_ioctl_debug(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
40220cc8ae86Sav145390 int *rvalp)
40230cc8ae86Sav145390 {
40240b240fcdSwh31274 caddr_t buf, kbuf;
40250cc8ae86Sav145390 uint64_t pa;
40260cc8ae86Sav145390 int rv = 0;
40270cc8ae86Sav145390 int i;
40280cc8ae86Sav145390 uint32_t flags;
40290cc8ae86Sav145390 static uint32_t offset = 0;
40300cc8ae86Sav145390
40310cc8ae86Sav145390
40320cc8ae86Sav145390 flags = (cmd >> 4) & 0xfffffff;
40330cc8ae86Sav145390
40340cc8ae86Sav145390 cmd &= 0xf;
40350cc8ae86Sav145390
40360cc8ae86Sav145390 MC_LOG("mc_ioctl(cmd = %x, flags = %x)\n", cmd, flags);
40370cc8ae86Sav145390
40380cc8ae86Sav145390 if (arg != NULL) {
40390cc8ae86Sav145390 if (ddi_copyin((const void *)arg, (void *)&pa,
40400cc8ae86Sav145390 sizeof (uint64_t), 0) < 0) {
40410cc8ae86Sav145390 rv = EFAULT;
40420cc8ae86Sav145390 return (rv);
40430cc8ae86Sav145390 }
40440cc8ae86Sav145390 buf = NULL;
40450cc8ae86Sav145390 } else {
40460cc8ae86Sav145390 buf = (caddr_t)kmem_alloc(PAGESIZE, KM_SLEEP);
40470cc8ae86Sav145390
40480cc8ae86Sav145390 pa = va_to_pa(buf);
40490cc8ae86Sav145390 pa += offset;
40500cc8ae86Sav145390
40510cc8ae86Sav145390 offset += 64;
40520cc8ae86Sav145390 if (offset >= PAGESIZE)
40530cc8ae86Sav145390 offset = 0;
40540cc8ae86Sav145390 }
40550cc8ae86Sav145390
40560cc8ae86Sav145390 switch (cmd) {
40570cc8ae86Sav145390 case MCI_CE:
405807d06da5SSurya Prakki (void) mc_inject_error(MC_INJECT_INTERMITTENT_CE, pa, flags);
40590cc8ae86Sav145390 break;
40600cc8ae86Sav145390 case MCI_PERM_CE:
406107d06da5SSurya Prakki (void) mc_inject_error(MC_INJECT_PERMANENT_CE, pa, flags);
40620cc8ae86Sav145390 break;
40630cc8ae86Sav145390 case MCI_UE:
406407d06da5SSurya Prakki (void) mc_inject_error(MC_INJECT_UE, pa, flags);
40650cc8ae86Sav145390 break;
40660cc8ae86Sav145390 case MCI_M_CE:
406707d06da5SSurya Prakki (void) mc_inject_error(MC_INJECT_INTERMITTENT_MCE, pa, flags);
40680cc8ae86Sav145390 break;
40690cc8ae86Sav145390 case MCI_M_PCE:
407007d06da5SSurya Prakki (void) mc_inject_error(MC_INJECT_PERMANENT_MCE, pa, flags);
40710cc8ae86Sav145390 break;
40720cc8ae86Sav145390 case MCI_M_UE:
407307d06da5SSurya Prakki (void) mc_inject_error(MC_INJECT_MUE, pa, flags);
40740cc8ae86Sav145390 break;
40750cc8ae86Sav145390 case MCI_CMP:
407607d06da5SSurya Prakki (void) mc_inject_error(MC_INJECT_CMPE, pa, flags);
40770cc8ae86Sav145390 break;
40780cc8ae86Sav145390 case MCI_NOP:
407907d06da5SSurya Prakki (void) mc_inject_error(MC_INJECT_NOP, pa, flags); break;
40800cc8ae86Sav145390 case MCI_SHOW_ALL:
40810cc8ae86Sav145390 mc_debug_show_all = 1;
40820cc8ae86Sav145390 break;
40830cc8ae86Sav145390 case MCI_SHOW_NONE:
40840cc8ae86Sav145390 mc_debug_show_all = 0;
40850cc8ae86Sav145390 break;
40860cc8ae86Sav145390 case MCI_ALLOC:
40870cc8ae86Sav145390 /*
40880cc8ae86Sav145390 * just allocate some kernel memory and never free it
40890cc8ae86Sav145390 * 512 MB seems to be the maximum size supported.
40900cc8ae86Sav145390 */
40910cc8ae86Sav145390 cmn_err(CE_NOTE, "Allocating kmem %d MB\n", flags * 512);
40920cc8ae86Sav145390 for (i = 0; i < flags; i++) {
40930b240fcdSwh31274 kbuf = kmem_alloc(512 * 1024 * 1024, KM_SLEEP);
40940cc8ae86Sav145390 cmn_err(CE_NOTE, "kmem buf %llx PA %llx\n",
40950b240fcdSwh31274 (u_longlong_t)kbuf, (u_longlong_t)va_to_pa(kbuf));
40960cc8ae86Sav145390 }
40970cc8ae86Sav145390 break;
40980cc8ae86Sav145390 case MCI_SUSPEND:
40990cc8ae86Sav145390 (void) opl_mc_suspend();
41000cc8ae86Sav145390 break;
41010cc8ae86Sav145390 case MCI_RESUME:
41020cc8ae86Sav145390 (void) opl_mc_resume();
41030cc8ae86Sav145390 break;
41040cc8ae86Sav145390 default:
41050cc8ae86Sav145390 rv = ENXIO;
41060cc8ae86Sav145390 }
41070b240fcdSwh31274 if (buf)
41080b240fcdSwh31274 kmem_free(buf, PAGESIZE);
41090b240fcdSwh31274
41100cc8ae86Sav145390 return (rv);
41110cc8ae86Sav145390 }
41120cc8ae86Sav145390
41130cc8ae86Sav145390 #endif /* DEBUG */
4114