11772Sjl139090 /*
21772Sjl139090 * CDDL HEADER START
31772Sjl139090 *
41772Sjl139090 * The contents of this file are subject to the terms of the
51772Sjl139090 * Common Development and Distribution License (the "License").
61772Sjl139090 * You may not use this file except in compliance with the License.
71772Sjl139090 *
81772Sjl139090 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91772Sjl139090 * or http://www.opensolaris.org/os/licensing.
101772Sjl139090 * See the License for the specific language governing permissions
111772Sjl139090 * and limitations under the License.
121772Sjl139090 *
131772Sjl139090 * When distributing Covered Code, include this CDDL HEADER in each
141772Sjl139090 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151772Sjl139090 * If applicable, add the following below this CDDL HEADER, with the
161772Sjl139090 * fields enclosed by brackets "[]" replaced with your own identifying
171772Sjl139090 * information: Portions Copyright [yyyy] [name of copyright owner]
181772Sjl139090 *
191772Sjl139090 * CDDL HEADER END
201772Sjl139090 */
211772Sjl139090 /*
22*12213SGavin.Maltby@Sun.COM * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
232241Shuah */
242241Shuah /*
256297Sjl139090 * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2008
261772Sjl139090 */
271772Sjl139090
281772Sjl139090 #include <sys/types.h>
291772Sjl139090 #include <sys/sysmacros.h>
301772Sjl139090 #include <sys/conf.h>
311772Sjl139090 #include <sys/modctl.h>
321772Sjl139090 #include <sys/stat.h>
331772Sjl139090 #include <sys/async.h>
342241Shuah #include <sys/machcpuvar.h>
351772Sjl139090 #include <sys/machsystm.h>
362214Sav145390 #include <sys/promif.h>
371772Sjl139090 #include <sys/ksynch.h>
381772Sjl139090 #include <sys/ddi.h>
391772Sjl139090 #include <sys/sunddi.h>
405080Swh31274 #include <sys/sunndi.h>
411772Sjl139090 #include <sys/ddifm.h>
421772Sjl139090 #include <sys/fm/protocol.h>
431772Sjl139090 #include <sys/fm/util.h>
441772Sjl139090 #include <sys/kmem.h>
451772Sjl139090 #include <sys/fm/io/opl_mc_fm.h>
461772Sjl139090 #include <sys/memlist.h>
471772Sjl139090 #include <sys/param.h>
482214Sav145390 #include <sys/disp.h>
491772Sjl139090 #include <vm/page.h>
501772Sjl139090 #include <sys/mc-opl.h>
512214Sav145390 #include <sys/opl.h>
522214Sav145390 #include <sys/opl_dimm.h>
532214Sav145390 #include <sys/scfd/scfostoescf.h>
542494Shyw #include <sys/cpu_module.h>
552494Shyw #include <vm/seg_kmem.h>
562494Shyw #include <sys/vmem.h>
572494Shyw #include <vm/hat_sfmmu.h>
582494Shyw #include <sys/vmsystm.h>
592662Shyw #include <sys/membar.h>
606693Swh31274 #include <sys/mem.h>
611772Sjl139090
621772Sjl139090 /*
631772Sjl139090 * Function prototypes
641772Sjl139090 */
651772Sjl139090 static int mc_open(dev_t *, int, int, cred_t *);
661772Sjl139090 static int mc_close(dev_t, int, int, cred_t *);
671772Sjl139090 static int mc_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
681772Sjl139090 static int mc_attach(dev_info_t *, ddi_attach_cmd_t);
691772Sjl139090 static int mc_detach(dev_info_t *, ddi_detach_cmd_t);
701772Sjl139090
712214Sav145390 static int mc_poll_init(void);
722214Sav145390 static void mc_poll_fini(void);
731772Sjl139090 static int mc_board_add(mc_opl_t *mcp);
741772Sjl139090 static int mc_board_del(mc_opl_t *mcp);
751772Sjl139090 static int mc_suspend(mc_opl_t *mcp, uint32_t flag);
761772Sjl139090 static int mc_resume(mc_opl_t *mcp, uint32_t flag);
772214Sav145390 int opl_mc_suspend(void);
782214Sav145390 int opl_mc_resume(void);
791772Sjl139090
801772Sjl139090 static void insert_mcp(mc_opl_t *mcp);
811772Sjl139090 static void delete_mcp(mc_opl_t *mcp);
821772Sjl139090
831772Sjl139090 static int pa_to_maddr(mc_opl_t *mcp, uint64_t pa, mc_addr_t *maddr);
841772Sjl139090
852662Shyw static int mc_rangecheck_pa(mc_opl_t *mcp, uint64_t pa);
861772Sjl139090
871772Sjl139090 int mc_get_mem_unum(int, uint64_t, char *, int, int *);
882214Sav145390 int mc_get_mem_addr(char *unum, char *sid, uint64_t offset, uint64_t *paddr);
892214Sav145390 int mc_get_mem_offset(uint64_t paddr, uint64_t *offp);
902214Sav145390 int mc_get_mem_sid(char *unum, char *buf, int buflen, int *lenp);
912214Sav145390 int mc_get_mem_sid_dimm(mc_opl_t *mcp, char *dname, char *buf,
922214Sav145390 int buflen, int *lenp);
932214Sav145390 mc_dimm_info_t *mc_get_dimm_list(mc_opl_t *mcp);
942214Sav145390 mc_dimm_info_t *mc_prepare_dimmlist(board_dimm_info_t *bd_dimmp);
952214Sav145390 int mc_set_mem_sid(mc_opl_t *mcp, char *buf, int buflen, int lsb, int bank,
962214Sav145390 uint32_t mf_type, uint32_t d_slot);
972214Sav145390 static void mc_free_dimm_list(mc_dimm_info_t *d);
981772Sjl139090 static void mc_get_mlist(mc_opl_t *);
992214Sav145390 static void mc_polling(void);
1002214Sav145390 static int mc_opl_get_physical_board(int);
1012214Sav145390
1025310Sdhain static void mc_clear_rewrite(mc_opl_t *mcp, int i);
1035310Sdhain static void mc_set_rewrite(mc_opl_t *mcp, int bank, uint32_t addr, int state);
1046693Swh31274 static int mc_scf_log_event(mc_flt_page_t *flt_pag);
1055310Sdhain
1062214Sav145390 #ifdef DEBUG
1072214Sav145390 static int mc_ioctl_debug(dev_t, int, intptr_t, int, cred_t *, int *);
1082214Sav145390 void mc_dump_dimm(char *buf, int dnamesz, int serialsz, int partnumsz);
1092214Sav145390 void mc_dump_dimm_info(board_dimm_info_t *bd_dimmp);
1102214Sav145390 #endif
1111772Sjl139090
1121772Sjl139090 #pragma weak opl_get_physical_board
1131772Sjl139090 extern int opl_get_physical_board(int);
1142214Sav145390 extern int plat_max_boards(void);
1151772Sjl139090
1161772Sjl139090 /*
1171772Sjl139090 * Configuration data structures
1181772Sjl139090 */
1191772Sjl139090 static struct cb_ops mc_cb_ops = {
1201772Sjl139090 mc_open, /* open */
1211772Sjl139090 mc_close, /* close */
1221772Sjl139090 nulldev, /* strategy */
1231772Sjl139090 nulldev, /* print */
1241772Sjl139090 nodev, /* dump */
1251772Sjl139090 nulldev, /* read */
1261772Sjl139090 nulldev, /* write */
1271772Sjl139090 mc_ioctl, /* ioctl */
1281772Sjl139090 nodev, /* devmap */
1291772Sjl139090 nodev, /* mmap */
1301772Sjl139090 nodev, /* segmap */
1311772Sjl139090 nochpoll, /* poll */
1321772Sjl139090 ddi_prop_op, /* cb_prop_op */
1331772Sjl139090 0, /* streamtab */
1341772Sjl139090 D_MP | D_NEW | D_HOTPLUG, /* Driver compatibility flag */
1351772Sjl139090 CB_REV, /* rev */
1361772Sjl139090 nodev, /* cb_aread */
1371772Sjl139090 nodev /* cb_awrite */
1381772Sjl139090 };
1391772Sjl139090
1401772Sjl139090 static struct dev_ops mc_ops = {
1411772Sjl139090 DEVO_REV, /* rev */
1421772Sjl139090 0, /* refcnt */
1431772Sjl139090 ddi_getinfo_1to1, /* getinfo */
1441772Sjl139090 nulldev, /* identify */
1451772Sjl139090 nulldev, /* probe */
1461772Sjl139090 mc_attach, /* attach */
1471772Sjl139090 mc_detach, /* detach */
1481772Sjl139090 nulldev, /* reset */
1491772Sjl139090 &mc_cb_ops, /* cb_ops */
1501772Sjl139090 (struct bus_ops *)0, /* bus_ops */
1517656SSherry.Moore@Sun.COM nulldev, /* power */
1527656SSherry.Moore@Sun.COM ddi_quiesce_not_needed, /* quiesce */
1531772Sjl139090 };
1541772Sjl139090
1551772Sjl139090 /*
1561772Sjl139090 * Driver globals
1571772Sjl139090 */
1582214Sav145390
1592214Sav145390 static enum {
1606297Sjl139090 MODEL_FF1,
1616297Sjl139090 MODEL_FF2,
1626297Sjl139090 MODEL_DC,
1636297Sjl139090 MODEL_IKKAKU
1642214Sav145390 } plat_model = MODEL_DC; /* The default behaviour is DC */
1652214Sav145390
1662214Sav145390 static struct plat_model_names {
1672214Sav145390 const char *unit_name;
1682214Sav145390 const char *mem_name;
1692214Sav145390 } model_names[] = {
1702214Sav145390 { "MBU_A", "MEMB" },
1712214Sav145390 { "MBU_B", "MEMB" },
1726297Sjl139090 { "CMU", "" },
1736297Sjl139090 { "MBU_A", "" }
1742214Sav145390 };
1752214Sav145390
1762214Sav145390 /*
1772214Sav145390 * The DIMM Names for DC platform.
1782214Sav145390 * The index into this table is made up of (bank, dslot),
1792214Sav145390 * Where dslot occupies bits 0-1 and bank occupies 2-4.
1802214Sav145390 */
1812214Sav145390 static char *mc_dc_dimm_unum_table[OPL_MAX_DIMMS] = {
1822214Sav145390 /* --------CMUnn----------- */
1832214Sav145390 /* --CS0-----|--CS1------ */
1842214Sav145390 /* -H-|--L-- | -H- | -L-- */
1852501Sraghuram "03A", "02A", "03B", "02B", /* Bank 0 (MAC 0 bank 0) */
1862501Sraghuram "13A", "12A", "13B", "12B", /* Bank 1 (MAC 0 bank 1) */
1872501Sraghuram "23A", "22A", "23B", "22B", /* Bank 2 (MAC 1 bank 0) */
1882501Sraghuram "33A", "32A", "33B", "32B", /* Bank 3 (MAC 1 bank 1) */
1892501Sraghuram "01A", "00A", "01B", "00B", /* Bank 4 (MAC 2 bank 0) */
1902501Sraghuram "11A", "10A", "11B", "10B", /* Bank 5 (MAC 2 bank 1) */
1912501Sraghuram "21A", "20A", "21B", "20B", /* Bank 6 (MAC 3 bank 0) */
1922501Sraghuram "31A", "30A", "31B", "30B" /* Bank 7 (MAC 3 bank 1) */
1932214Sav145390 };
1942214Sav145390
1952214Sav145390 /*
1966297Sjl139090 * The DIMM Names for FF1/FF2/IKKAKU platforms.
1972214Sav145390 * The index into this table is made up of (board, bank, dslot),
1982214Sav145390 * Where dslot occupies bits 0-1, bank occupies 2-4 and
1992214Sav145390 * board occupies the bit 5.
2002214Sav145390 */
2012214Sav145390 static char *mc_ff_dimm_unum_table[2 * OPL_MAX_DIMMS] = {
2022214Sav145390 /* --------CMU0---------- */
2032214Sav145390 /* --CS0-----|--CS1------ */
2042214Sav145390 /* -H-|--L-- | -H- | -L-- */
2052501Sraghuram "03A", "02A", "03B", "02B", /* Bank 0 (MAC 0 bank 0) */
2062501Sraghuram "01A", "00A", "01B", "00B", /* Bank 1 (MAC 0 bank 1) */
2072501Sraghuram "13A", "12A", "13B", "12B", /* Bank 2 (MAC 1 bank 0) */
2082501Sraghuram "11A", "10A", "11B", "10B", /* Bank 3 (MAC 1 bank 1) */
2092501Sraghuram "23A", "22A", "23B", "22B", /* Bank 4 (MAC 2 bank 0) */
2102501Sraghuram "21A", "20A", "21B", "20B", /* Bank 5 (MAC 2 bank 1) */
2112501Sraghuram "33A", "32A", "33B", "32B", /* Bank 6 (MAC 3 bank 0) */
2122501Sraghuram "31A", "30A", "31B", "30B", /* Bank 7 (MAC 3 bank 1) */
2132214Sav145390 /* --------CMU1---------- */
2142214Sav145390 /* --CS0-----|--CS1------ */
2152214Sav145390 /* -H-|--L-- | -H- | -L-- */
2162501Sraghuram "43A", "42A", "43B", "42B", /* Bank 0 (MAC 0 bank 0) */
2172501Sraghuram "41A", "40A", "41B", "40B", /* Bank 1 (MAC 0 bank 1) */
2182501Sraghuram "53A", "52A", "53B", "52B", /* Bank 2 (MAC 1 bank 0) */
2192501Sraghuram "51A", "50A", "51B", "50B", /* Bank 3 (MAC 1 bank 1) */
2202501Sraghuram "63A", "62A", "63B", "62B", /* Bank 4 (MAC 2 bank 0) */
2212501Sraghuram "61A", "60A", "61B", "60B", /* Bank 5 (MAC 2 bank 1) */
2222501Sraghuram "73A", "72A", "73B", "72B", /* Bank 6 (MAC 3 bank 0) */
2232501Sraghuram "71A", "70A", "71B", "70B" /* Bank 7 (MAC 3 bank 1) */
2242214Sav145390 };
2252214Sav145390
2262214Sav145390 #define BD_BK_SLOT_TO_INDEX(bd, bk, s) \
2272214Sav145390 (((bd & 0x01) << 5) | ((bk & 0x07) << 2) | (s & 0x03))
2282214Sav145390
2292214Sav145390 #define INDEX_TO_BANK(i) (((i) & 0x1C) >> 2)
2302214Sav145390 #define INDEX_TO_SLOT(i) ((i) & 0x03)
2312214Sav145390
2323045Sav145390 #define SLOT_TO_CS(slot) ((slot & 0x3) >> 1)
2333045Sav145390
2342214Sav145390 /* Isolation unit size is 64 MB */
2352214Sav145390 #define MC_ISOLATION_BSIZE (64 * 1024 * 1024)
2362214Sav145390
2372214Sav145390 #define MC_MAX_SPEEDS 7
2382214Sav145390
2392214Sav145390 typedef struct {
2402214Sav145390 uint32_t mc_speeds;
2412214Sav145390 uint32_t mc_period;
2422214Sav145390 } mc_scan_speed_t;
2432214Sav145390
2442214Sav145390 #define MC_CNTL_SPEED_SHIFT 26
2452214Sav145390
2462867Shyw /*
2472867Shyw * In mirror mode, we normalized the bank idx to "even" since
2482867Shyw * the HW treats them as one unit w.r.t programming.
2492867Shyw * This bank index will be the "effective" bank index.
2502867Shyw * All mirrored bank state info on mc_period, mc_speedup_period
2512867Shyw * will be stored in the even bank structure to avoid code duplication.
2522867Shyw */
2532867Shyw #define MIRROR_IDX(bankidx) (bankidx & ~1)
2542867Shyw
2552214Sav145390 static mc_scan_speed_t mc_scan_speeds[MC_MAX_SPEEDS] = {
2562214Sav145390 {0x6 << MC_CNTL_SPEED_SHIFT, 0},
2572214Sav145390 {0x5 << MC_CNTL_SPEED_SHIFT, 32},
2582214Sav145390 {0x4 << MC_CNTL_SPEED_SHIFT, 64},
2592214Sav145390 {0x3 << MC_CNTL_SPEED_SHIFT, 128},
2602214Sav145390 {0x2 << MC_CNTL_SPEED_SHIFT, 256},
2612214Sav145390 {0x1 << MC_CNTL_SPEED_SHIFT, 512},
2622214Sav145390 {0x0 << MC_CNTL_SPEED_SHIFT, 1024}
2632214Sav145390 };
2642214Sav145390
2652214Sav145390 static uint32_t mc_max_speed = (0x6 << 26);
2662214Sav145390
2672214Sav145390 int mc_isolation_bsize = MC_ISOLATION_BSIZE;
2682214Sav145390 int mc_patrol_interval_sec = MC_PATROL_INTERVAL_SEC;
2692214Sav145390 int mc_max_scf_retry = 16;
2702214Sav145390 int mc_max_scf_logs = 64;
2712214Sav145390 int mc_max_errlog_processed = BANKNUM_PER_SB*2;
2722214Sav145390 int mc_scan_period = 12 * 60 * 60; /* 12 hours period */
2732214Sav145390 int mc_max_rewrite_loop = 100;
2742214Sav145390 int mc_rewrite_delay = 10;
2752214Sav145390 /*
2762214Sav145390 * it takes SCF about 300 m.s. to process a requst. We can bail out
2772214Sav145390 * if it is busy. It does not pay to wait for it too long.
2782214Sav145390 */
2792214Sav145390 int mc_max_scf_loop = 2;
2802214Sav145390 int mc_scf_delay = 100;
2812214Sav145390 int mc_pce_dropped = 0;
2822214Sav145390 int mc_poll_priority = MINCLSYSPRI;
2835310Sdhain int mc_max_rewrite_retry = 6 * 60;
2842214Sav145390
2852214Sav145390
2862214Sav145390 /*
2873152Sav145390 * Mutex hierarchy in mc-opl
2882214Sav145390 * If both mcmutex and mc_lock must be held,
2892214Sav145390 * mcmutex must be acquired first, and then mc_lock.
2902214Sav145390 */
2912214Sav145390
2921772Sjl139090 static kmutex_t mcmutex;
2932214Sav145390 mc_opl_t *mc_instances[OPL_MAX_BOARDS];
2942214Sav145390
2952214Sav145390 static kmutex_t mc_polling_lock;
2962214Sav145390 static kcondvar_t mc_polling_cv;
2972214Sav145390 static kcondvar_t mc_poll_exit_cv;
2982214Sav145390 static int mc_poll_cmd = 0;
2992214Sav145390 static int mc_pollthr_running = 0;
3002214Sav145390 int mc_timeout_period = 0; /* this is in m.s. */
3011772Sjl139090 void *mc_statep;
3021772Sjl139090
3031772Sjl139090 #ifdef DEBUG
3041809Shyw int oplmc_debug = 0;
3051772Sjl139090 #endif
3061772Sjl139090
3072214Sav145390 static int mc_debug_show_all = 0;
3081772Sjl139090
3091772Sjl139090 extern struct mod_ops mod_driverops;
3101772Sjl139090
3111772Sjl139090 static struct modldrv modldrv = {
3121772Sjl139090 &mod_driverops, /* module type, this one is a driver */
3137656SSherry.Moore@Sun.COM "OPL Memory-controller", /* module name */
3141772Sjl139090 &mc_ops, /* driver ops */
3151772Sjl139090 };
3161772Sjl139090
3171772Sjl139090 static struct modlinkage modlinkage = {
3181772Sjl139090 MODREV_1, /* rev */
3191772Sjl139090 (void *)&modldrv,
3201772Sjl139090 NULL
3211772Sjl139090 };
3221772Sjl139090
3231772Sjl139090 #pragma weak opl_get_mem_unum
3242214Sav145390 #pragma weak opl_get_mem_sid
3252214Sav145390 #pragma weak opl_get_mem_offset
3262214Sav145390 #pragma weak opl_get_mem_addr
3272214Sav145390
3281772Sjl139090 extern int (*opl_get_mem_unum)(int, uint64_t, char *, int, int *);
3292214Sav145390 extern int (*opl_get_mem_sid)(char *unum, char *buf, int buflen, int *lenp);
3302214Sav145390 extern int (*opl_get_mem_offset)(uint64_t paddr, uint64_t *offp);
3312214Sav145390 extern int (*opl_get_mem_addr)(char *unum, char *sid, uint64_t offset,
3322214Sav145390 uint64_t *paddr);
3332214Sav145390
3341772Sjl139090
3351772Sjl139090 /*
3361772Sjl139090 * pseudo-mc node portid format
3371772Sjl139090 *
3381772Sjl139090 * [10] = 0
3391772Sjl139090 * [9] = 1
3401772Sjl139090 * [8] = LSB_ID[4] = 0
3411772Sjl139090 * [7:4] = LSB_ID[3:0]
3421772Sjl139090 * [3:0] = 0
3431772Sjl139090 *
3441772Sjl139090 */
3451772Sjl139090
3461772Sjl139090 /*
3471772Sjl139090 * These are the module initialization routines.
3481772Sjl139090 */
3491772Sjl139090 int
_init(void)3501772Sjl139090 _init(void)
3511772Sjl139090 {
3522214Sav145390 int error;
3532214Sav145390 int plen;
3542214Sav145390 char model[20];
3552214Sav145390 pnode_t node;
3561772Sjl139090
3571772Sjl139090
3581772Sjl139090 if ((error = ddi_soft_state_init(&mc_statep,
3591772Sjl139090 sizeof (mc_opl_t), 1)) != 0)
3601772Sjl139090 return (error);
3611772Sjl139090
3622214Sav145390 if ((error = mc_poll_init()) != 0) {
3632214Sav145390 ddi_soft_state_fini(&mc_statep);
3642214Sav145390 return (error);
3652214Sav145390 }
3662214Sav145390
3671772Sjl139090 mutex_init(&mcmutex, NULL, MUTEX_DRIVER, NULL);
3681772Sjl139090 if (&opl_get_mem_unum)
3691772Sjl139090 opl_get_mem_unum = mc_get_mem_unum;
3702214Sav145390 if (&opl_get_mem_sid)
3712214Sav145390 opl_get_mem_sid = mc_get_mem_sid;
3722214Sav145390 if (&opl_get_mem_offset)
3732214Sav145390 opl_get_mem_offset = mc_get_mem_offset;
3742214Sav145390 if (&opl_get_mem_addr)
3752214Sav145390 opl_get_mem_addr = mc_get_mem_addr;
3762214Sav145390
3772214Sav145390 node = prom_rootnode();
3782214Sav145390 plen = prom_getproplen(node, "model");
3792214Sav145390
3802214Sav145390 if (plen > 0 && plen < sizeof (model)) {
3812214Sav145390 (void) prom_getprop(node, "model", model);
3822214Sav145390 model[plen] = '\0';
3832214Sav145390 if (strcmp(model, "FF1") == 0)
3842214Sav145390 plat_model = MODEL_FF1;
3852214Sav145390 else if (strcmp(model, "FF2") == 0)
3862214Sav145390 plat_model = MODEL_FF2;
3872214Sav145390 else if (strncmp(model, "DC", 2) == 0)
3882214Sav145390 plat_model = MODEL_DC;
3896297Sjl139090 else if (strcmp(model, "IKKAKU") == 0)
3906297Sjl139090 plat_model = MODEL_IKKAKU;
3912214Sav145390 }
3921772Sjl139090
3931772Sjl139090 error = mod_install(&modlinkage);
3941772Sjl139090 if (error != 0) {
3951772Sjl139090 if (&opl_get_mem_unum)
3961772Sjl139090 opl_get_mem_unum = NULL;
3972214Sav145390 if (&opl_get_mem_sid)
3982214Sav145390 opl_get_mem_sid = NULL;
3992214Sav145390 if (&opl_get_mem_offset)
4002214Sav145390 opl_get_mem_offset = NULL;
4012214Sav145390 if (&opl_get_mem_addr)
4022214Sav145390 opl_get_mem_addr = NULL;
4031772Sjl139090 mutex_destroy(&mcmutex);
4042214Sav145390 mc_poll_fini();
4051772Sjl139090 ddi_soft_state_fini(&mc_statep);
4061772Sjl139090 }
4071772Sjl139090 return (error);
4081772Sjl139090 }
4091772Sjl139090
4101772Sjl139090 int
_fini(void)4111772Sjl139090 _fini(void)
4121772Sjl139090 {
4131772Sjl139090 int error;
4141772Sjl139090
4151772Sjl139090 if ((error = mod_remove(&modlinkage)) != 0)
4161772Sjl139090 return (error);
4171772Sjl139090
4181772Sjl139090 if (&opl_get_mem_unum)
4191772Sjl139090 opl_get_mem_unum = NULL;
4202214Sav145390 if (&opl_get_mem_sid)
4212214Sav145390 opl_get_mem_sid = NULL;
4222214Sav145390 if (&opl_get_mem_offset)
4232214Sav145390 opl_get_mem_offset = NULL;
4242214Sav145390 if (&opl_get_mem_addr)
4252214Sav145390 opl_get_mem_addr = NULL;
4262214Sav145390
4272214Sav145390 mutex_destroy(&mcmutex);
4282214Sav145390 mc_poll_fini();
4291772Sjl139090 ddi_soft_state_fini(&mc_statep);
4301772Sjl139090
4311772Sjl139090 return (0);
4321772Sjl139090 }
4331772Sjl139090
4341772Sjl139090 int
_info(struct modinfo * modinfop)4351772Sjl139090 _info(struct modinfo *modinfop)
4361772Sjl139090 {
4371772Sjl139090 return (mod_info(&modlinkage, modinfop));
4381772Sjl139090 }
4391772Sjl139090
4402214Sav145390 static void
mc_polling_thread()4412214Sav145390 mc_polling_thread()
4422214Sav145390 {
4432214Sav145390 mutex_enter(&mc_polling_lock);
4442214Sav145390 mc_pollthr_running = 1;
4452214Sav145390 while (!(mc_poll_cmd & MC_POLL_EXIT)) {
4462214Sav145390 mc_polling();
44711311SSurya.Prakki@Sun.COM (void) cv_reltimedwait(&mc_polling_cv, &mc_polling_lock,
44811066Srafael.vanoni@sun.com mc_timeout_period, TR_CLOCK_TICK);
4492214Sav145390 }
4502214Sav145390 mc_pollthr_running = 0;
4512214Sav145390
4522214Sav145390 /*
4532214Sav145390 * signal if any one is waiting for this thread to exit.
4542214Sav145390 */
4552214Sav145390 cv_signal(&mc_poll_exit_cv);
4562214Sav145390 mutex_exit(&mc_polling_lock);
4572214Sav145390 thread_exit();
4582214Sav145390 /* NOTREACHED */
4592214Sav145390 }
4602214Sav145390
4612214Sav145390 static int
mc_poll_init()4622214Sav145390 mc_poll_init()
4632214Sav145390 {
4642214Sav145390 mutex_init(&mc_polling_lock, NULL, MUTEX_DRIVER, NULL);
4652214Sav145390 cv_init(&mc_polling_cv, NULL, CV_DRIVER, NULL);
4662214Sav145390 cv_init(&mc_poll_exit_cv, NULL, CV_DRIVER, NULL);
4672214Sav145390 return (0);
4682214Sav145390 }
4692214Sav145390
4702214Sav145390 static void
mc_poll_fini()4712214Sav145390 mc_poll_fini()
4722214Sav145390 {
4732214Sav145390 mutex_enter(&mc_polling_lock);
4742214Sav145390 if (mc_pollthr_running) {
4752214Sav145390 mc_poll_cmd = MC_POLL_EXIT;
4762214Sav145390 cv_signal(&mc_polling_cv);
4772214Sav145390 while (mc_pollthr_running) {
4782214Sav145390 cv_wait(&mc_poll_exit_cv, &mc_polling_lock);
4792214Sav145390 }
4802214Sav145390 }
4812214Sav145390 mutex_exit(&mc_polling_lock);
4822214Sav145390 mutex_destroy(&mc_polling_lock);
4832214Sav145390 cv_destroy(&mc_polling_cv);
4842214Sav145390 cv_destroy(&mc_poll_exit_cv);
4852214Sav145390 }
4862214Sav145390
4871772Sjl139090 static int
mc_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)4881772Sjl139090 mc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
4891772Sjl139090 {
4901772Sjl139090 mc_opl_t *mcp;
4911772Sjl139090 int instance;
4922214Sav145390 int rv;
4931772Sjl139090
4941772Sjl139090 /* get the instance of this devi */
4951772Sjl139090 instance = ddi_get_instance(devi);
4961772Sjl139090
4971772Sjl139090 switch (cmd) {
4981772Sjl139090 case DDI_ATTACH:
4991772Sjl139090 break;
5001772Sjl139090 case DDI_RESUME:
5011772Sjl139090 mcp = ddi_get_soft_state(mc_statep, instance);
5022214Sav145390 rv = mc_resume(mcp, MC_DRIVER_SUSPENDED);
5032214Sav145390 return (rv);
5041772Sjl139090 default:
5051772Sjl139090 return (DDI_FAILURE);
5061772Sjl139090 }
5071772Sjl139090
5081772Sjl139090 if (ddi_soft_state_zalloc(mc_statep, instance) != DDI_SUCCESS)
5091772Sjl139090 return (DDI_FAILURE);
5101772Sjl139090
5116693Swh31274 if (ddi_create_minor_node(devi, "mc-opl", S_IFCHR, instance,
5126693Swh31274 "ddi_mem_ctrl", 0) != DDI_SUCCESS) {
5136693Swh31274 MC_LOG("mc_attach: create_minor_node failed\n");
5146693Swh31274 return (DDI_FAILURE);
5156693Swh31274 }
5166693Swh31274
5171772Sjl139090 if ((mcp = ddi_get_soft_state(mc_statep, instance)) == NULL) {
5181772Sjl139090 goto bad;
5191772Sjl139090 }
5201772Sjl139090
5212214Sav145390 if (mc_timeout_period == 0) {
5222214Sav145390 mc_patrol_interval_sec = (int)ddi_getprop(DDI_DEV_T_ANY, devi,
5235080Swh31274 DDI_PROP_DONTPASS, "mc-timeout-interval-sec",
5245080Swh31274 mc_patrol_interval_sec);
5255080Swh31274 mc_timeout_period = drv_usectohz(1000000 *
5265080Swh31274 mc_patrol_interval_sec / OPL_MAX_BOARDS);
5272214Sav145390 }
5282214Sav145390
5291772Sjl139090 /* set informations in mc state */
5301772Sjl139090 mcp->mc_dip = devi;
5311772Sjl139090
5321772Sjl139090 if (mc_board_add(mcp))
5331772Sjl139090 goto bad;
5341772Sjl139090
5351772Sjl139090 insert_mcp(mcp);
5362214Sav145390
5372214Sav145390 /*
5382214Sav145390 * Start the polling thread if it is not running already.
5392214Sav145390 */
5402214Sav145390 mutex_enter(&mc_polling_lock);
5412214Sav145390 if (!mc_pollthr_running) {
5422214Sav145390 (void) thread_create(NULL, 0, (void (*)())mc_polling_thread,
5435080Swh31274 NULL, 0, &p0, TS_RUN, mc_poll_priority);
5442214Sav145390 }
5452214Sav145390 mutex_exit(&mc_polling_lock);
5461772Sjl139090 ddi_report_dev(devi);
5471772Sjl139090
5481772Sjl139090 return (DDI_SUCCESS);
5491772Sjl139090
5501772Sjl139090 bad:
5516693Swh31274 ddi_remove_minor_node(devi, NULL);
5521772Sjl139090 ddi_soft_state_free(mc_statep, instance);
5531772Sjl139090 return (DDI_FAILURE);
5541772Sjl139090 }
5551772Sjl139090
5561772Sjl139090 /* ARGSUSED */
5571772Sjl139090 static int
mc_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)5581772Sjl139090 mc_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
5591772Sjl139090 {
5602214Sav145390 int rv;
5611772Sjl139090 int instance;
5621772Sjl139090 mc_opl_t *mcp;
5631772Sjl139090
5641772Sjl139090 /* get the instance of this devi */
5651772Sjl139090 instance = ddi_get_instance(devi);
5661772Sjl139090 if ((mcp = ddi_get_soft_state(mc_statep, instance)) == NULL) {
5671772Sjl139090 return (DDI_FAILURE);
5681772Sjl139090 }
5691772Sjl139090
5701772Sjl139090 switch (cmd) {
5711772Sjl139090 case DDI_SUSPEND:
5722214Sav145390 rv = mc_suspend(mcp, MC_DRIVER_SUSPENDED);
5732214Sav145390 return (rv);
5741772Sjl139090 case DDI_DETACH:
5751772Sjl139090 break;
5761772Sjl139090 default:
5771772Sjl139090 return (DDI_FAILURE);
5781772Sjl139090 }
5791772Sjl139090
5802214Sav145390 delete_mcp(mcp);
5811772Sjl139090 if (mc_board_del(mcp) != DDI_SUCCESS) {
5821772Sjl139090 return (DDI_FAILURE);
5831772Sjl139090 }
5841772Sjl139090
5856693Swh31274 ddi_remove_minor_node(devi, NULL);
5866693Swh31274
5871772Sjl139090 /* free up the soft state */
5881772Sjl139090 ddi_soft_state_free(mc_statep, instance);
5891772Sjl139090
5901772Sjl139090 return (DDI_SUCCESS);
5911772Sjl139090 }
5921772Sjl139090
5931772Sjl139090 /* ARGSUSED */
5941772Sjl139090 static int
mc_open(dev_t * devp,int flag,int otyp,cred_t * credp)5951772Sjl139090 mc_open(dev_t *devp, int flag, int otyp, cred_t *credp)
5961772Sjl139090 {
5971772Sjl139090 return (0);
5981772Sjl139090 }
5991772Sjl139090
6001772Sjl139090 /* ARGSUSED */
6011772Sjl139090 static int
mc_close(dev_t devp,int flag,int otyp,cred_t * credp)6021772Sjl139090 mc_close(dev_t devp, int flag, int otyp, cred_t *credp)
6031772Sjl139090 {
6041772Sjl139090 return (0);
6051772Sjl139090 }
6061772Sjl139090
6071772Sjl139090 /* ARGSUSED */
6081772Sjl139090 static int
mc_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)6091772Sjl139090 mc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
6101772Sjl139090 int *rvalp)
6111772Sjl139090 {
6126693Swh31274 mc_flt_page_t flt_page;
6136693Swh31274
6146693Swh31274 if (cmd == MCIOC_FAULT_PAGE) {
6156693Swh31274 if (arg == NULL)
6166693Swh31274 return (EINVAL);
6176693Swh31274
6186693Swh31274 if (ddi_copyin((const void *)arg, (void *)&flt_page,
6196693Swh31274 sizeof (mc_flt_page_t), 0) < 0)
6206693Swh31274 return (EFAULT);
6216693Swh31274
6226693Swh31274 return (mc_scf_log_event(&flt_page));
6236693Swh31274 }
6242214Sav145390 #ifdef DEBUG
6252214Sav145390 return (mc_ioctl_debug(dev, cmd, arg, mode, credp, rvalp));
6262214Sav145390 #else
6276693Swh31274 return (ENOTTY);
6282214Sav145390 #endif
6291772Sjl139090 }
6301772Sjl139090
6311772Sjl139090 /*
6321772Sjl139090 * PA validity check:
6332662Shyw * This function return 1 if the PA is a valid PA
6342662Shyw * in the running Solaris instance i.e. in physinstall
6352662Shyw * Otherwise, return 0.
6361772Sjl139090 */
6371772Sjl139090
6381772Sjl139090 /* ARGSUSED */
6391772Sjl139090 static int
pa_is_valid(mc_opl_t * mcp,uint64_t addr)6401772Sjl139090 pa_is_valid(mc_opl_t *mcp, uint64_t addr)
6411772Sjl139090 {
6421772Sjl139090 if (mcp->mlist == NULL)
6431772Sjl139090 mc_get_mlist(mcp);
6441772Sjl139090
6451772Sjl139090 if (mcp->mlist && address_in_memlist(mcp->mlist, addr, 0)) {
6461772Sjl139090 return (1);
6471772Sjl139090 }
6481772Sjl139090 return (0);
6491772Sjl139090 }
6501772Sjl139090
6511772Sjl139090 /*
6521772Sjl139090 * mac-pa translation routines.
6531772Sjl139090 *
6541772Sjl139090 * Input: mc driver state, (LSB#, Bank#, DIMM address)
6551772Sjl139090 * Output: physical address
6561772Sjl139090 *
6571772Sjl139090 * Valid - return value: 0
6581772Sjl139090 * Invalid - return value: -1
6591772Sjl139090 */
6601772Sjl139090 static int
mcaddr_to_pa(mc_opl_t * mcp,mc_addr_t * maddr,uint64_t * pa)6611772Sjl139090 mcaddr_to_pa(mc_opl_t *mcp, mc_addr_t *maddr, uint64_t *pa)
6621772Sjl139090 {
6631772Sjl139090 int i;
6641772Sjl139090 uint64_t pa_offset = 0;
6651772Sjl139090 int cs = (maddr->ma_dimm_addr >> CS_SHIFT) & 1;
6661772Sjl139090 int bank = maddr->ma_bank;
6671772Sjl139090 mc_addr_t maddr1;
6681772Sjl139090 int bank0, bank1;
6691772Sjl139090
6701772Sjl139090 MC_LOG("mcaddr /LSB%d/B%d/%x\n", maddr->ma_bd, bank,
6715080Swh31274 maddr->ma_dimm_addr);
6721772Sjl139090
6731772Sjl139090 /* loc validity check */
6741772Sjl139090 ASSERT(maddr->ma_bd >= 0 && OPL_BOARD_MAX > maddr->ma_bd);
6751772Sjl139090 ASSERT(bank >= 0 && OPL_BANK_MAX > bank);
6761772Sjl139090
6771772Sjl139090 /* Do translation */
6781772Sjl139090 for (i = 0; i < PA_BITS_FOR_MAC; i++) {
6791772Sjl139090 int pa_bit = 0;
6801772Sjl139090 int mc_bit = mcp->mc_trans_table[cs][i];
6811772Sjl139090 if (mc_bit < MC_ADDRESS_BITS) {
6821772Sjl139090 pa_bit = (maddr->ma_dimm_addr >> mc_bit) & 1;
6831772Sjl139090 } else if (mc_bit == MP_NONE) {
6841772Sjl139090 pa_bit = 0;
6851772Sjl139090 } else if (mc_bit == MP_BANK_0) {
6861772Sjl139090 pa_bit = bank & 1;
6871772Sjl139090 } else if (mc_bit == MP_BANK_1) {
6881772Sjl139090 pa_bit = (bank >> 1) & 1;
6891772Sjl139090 } else if (mc_bit == MP_BANK_2) {
6901772Sjl139090 pa_bit = (bank >> 2) & 1;
6911772Sjl139090 }
6921772Sjl139090 pa_offset |= ((uint64_t)pa_bit) << i;
6931772Sjl139090 }
6941772Sjl139090 *pa = mcp->mc_start_address + pa_offset;
6951772Sjl139090 MC_LOG("pa = %lx\n", *pa);
6961772Sjl139090
6971772Sjl139090 if (pa_to_maddr(mcp, *pa, &maddr1) == -1) {
6982214Sav145390 cmn_err(CE_WARN, "mcaddr_to_pa: /LSB%d/B%d/%x failed to "
6992214Sav145390 "convert PA %lx\n", maddr->ma_bd, bank,
7002214Sav145390 maddr->ma_dimm_addr, *pa);
7011772Sjl139090 return (-1);
7021772Sjl139090 }
7031772Sjl139090
7042214Sav145390 /*
7052214Sav145390 * In mirror mode, PA is always translated to the even bank.
7062214Sav145390 */
7071772Sjl139090 if (IS_MIRROR(mcp, maddr->ma_bank)) {
7081772Sjl139090 bank0 = maddr->ma_bank & ~(1);
7091772Sjl139090 bank1 = maddr1.ma_bank & ~(1);
7101772Sjl139090 } else {
7111772Sjl139090 bank0 = maddr->ma_bank;
7121772Sjl139090 bank1 = maddr1.ma_bank;
7131772Sjl139090 }
7141772Sjl139090 /*
7151772Sjl139090 * there is no need to check ma_bd because it is generated from
7161772Sjl139090 * mcp. They are the same.
7171772Sjl139090 */
7185080Swh31274 if ((bank0 == bank1) && (maddr->ma_dimm_addr ==
7195080Swh31274 maddr1.ma_dimm_addr)) {
7201772Sjl139090 return (0);
7211772Sjl139090 } else {
7226693Swh31274 MC_LOG("Translation error source /LSB%d/B%d/%x, "
7235080Swh31274 "PA %lx, target /LSB%d/B%d/%x\n", maddr->ma_bd, bank,
7245080Swh31274 maddr->ma_dimm_addr, *pa, maddr1.ma_bd, maddr1.ma_bank,
7255080Swh31274 maddr1.ma_dimm_addr);
7261772Sjl139090 return (-1);
7271772Sjl139090 }
7281772Sjl139090 }
7291772Sjl139090
7301772Sjl139090 /*
7311772Sjl139090 * PA to CS (used by pa_to_maddr).
7321772Sjl139090 */
7331772Sjl139090 static int
pa_to_cs(mc_opl_t * mcp,uint64_t pa_offset)7341772Sjl139090 pa_to_cs(mc_opl_t *mcp, uint64_t pa_offset)
7351772Sjl139090 {
7361772Sjl139090 int i;
7372662Shyw int cs = 1;
7381772Sjl139090
7391772Sjl139090 for (i = 0; i < PA_BITS_FOR_MAC; i++) {
7401772Sjl139090 /* MAC address bit<29> is arranged on the same PA bit */
7411772Sjl139090 /* on both table. So we may use any table. */
7421772Sjl139090 if (mcp->mc_trans_table[0][i] == CS_SHIFT) {
7431772Sjl139090 cs = (pa_offset >> i) & 1;
7441772Sjl139090 break;
7451772Sjl139090 }
7461772Sjl139090 }
7471772Sjl139090 return (cs);
7481772Sjl139090 }
7491772Sjl139090
7501772Sjl139090 /*
7511772Sjl139090 * PA to DIMM (used by pa_to_maddr).
7521772Sjl139090 */
7531772Sjl139090 /* ARGSUSED */
7541772Sjl139090 static uint32_t
pa_to_dimm(mc_opl_t * mcp,uint64_t pa_offset)7551772Sjl139090 pa_to_dimm(mc_opl_t *mcp, uint64_t pa_offset)
7561772Sjl139090 {
7571772Sjl139090 int i;
7581772Sjl139090 int cs = pa_to_cs(mcp, pa_offset);
7591772Sjl139090 uint32_t dimm_addr = 0;
7601772Sjl139090
7611772Sjl139090 for (i = 0; i < PA_BITS_FOR_MAC; i++) {
7621772Sjl139090 int pa_bit_value = (pa_offset >> i) & 1;
7631772Sjl139090 int mc_bit = mcp->mc_trans_table[cs][i];
7641772Sjl139090 if (mc_bit < MC_ADDRESS_BITS) {
7651772Sjl139090 dimm_addr |= pa_bit_value << mc_bit;
7661772Sjl139090 }
7671772Sjl139090 }
7682662Shyw dimm_addr |= cs << CS_SHIFT;
7691772Sjl139090 return (dimm_addr);
7701772Sjl139090 }
7711772Sjl139090
7721772Sjl139090 /*
7731772Sjl139090 * PA to Bank (used by pa_to_maddr).
7741772Sjl139090 */
7751772Sjl139090 static int
pa_to_bank(mc_opl_t * mcp,uint64_t pa_offset)7761772Sjl139090 pa_to_bank(mc_opl_t *mcp, uint64_t pa_offset)
7771772Sjl139090 {
7781772Sjl139090 int i;
7791772Sjl139090 int cs = pa_to_cs(mcp, pa_offset);
7801772Sjl139090 int bankno = mcp->mc_trans_table[cs][INDEX_OF_BANK_SUPPLEMENT_BIT];
7811772Sjl139090
7821772Sjl139090
7831772Sjl139090 for (i = 0; i < PA_BITS_FOR_MAC; i++) {
7841772Sjl139090 int pa_bit_value = (pa_offset >> i) & 1;
7851772Sjl139090 int mc_bit = mcp->mc_trans_table[cs][i];
7861772Sjl139090 switch (mc_bit) {
7871772Sjl139090 case MP_BANK_0:
7881772Sjl139090 bankno |= pa_bit_value;
7891772Sjl139090 break;
7901772Sjl139090 case MP_BANK_1:
7911772Sjl139090 bankno |= pa_bit_value << 1;
7921772Sjl139090 break;
7931772Sjl139090 case MP_BANK_2:
7941772Sjl139090 bankno |= pa_bit_value << 2;
7951772Sjl139090 break;
7961772Sjl139090 }
7971772Sjl139090 }
7981772Sjl139090
7991772Sjl139090 return (bankno);
8001772Sjl139090 }
8011772Sjl139090
8021772Sjl139090 /*
8031772Sjl139090 * PA to MAC address translation
8041772Sjl139090 *
8051772Sjl139090 * Input: MAC driver state, physicall adress
8061772Sjl139090 * Output: LSB#, Bank id, mac address
8071772Sjl139090 *
8081772Sjl139090 * Valid - return value: 0
8091772Sjl139090 * Invalid - return value: -1
8101772Sjl139090 */
8111772Sjl139090
8121772Sjl139090 int
pa_to_maddr(mc_opl_t * mcp,uint64_t pa,mc_addr_t * maddr)8131772Sjl139090 pa_to_maddr(mc_opl_t *mcp, uint64_t pa, mc_addr_t *maddr)
8141772Sjl139090 {
8151772Sjl139090 uint64_t pa_offset;
8161772Sjl139090
8172662Shyw if (!mc_rangecheck_pa(mcp, pa))
8181772Sjl139090 return (-1);
8191772Sjl139090
8201772Sjl139090 /* Do translation */
8211772Sjl139090 pa_offset = pa - mcp->mc_start_address;
8221772Sjl139090
8231772Sjl139090 maddr->ma_bd = mcp->mc_board_num;
8243045Sav145390 maddr->ma_phys_bd = mcp->mc_phys_board_num;
8251772Sjl139090 maddr->ma_bank = pa_to_bank(mcp, pa_offset);
8261772Sjl139090 maddr->ma_dimm_addr = pa_to_dimm(mcp, pa_offset);
8275080Swh31274 MC_LOG("pa %lx -> mcaddr /LSB%d/B%d/%x\n", pa_offset, maddr->ma_bd,
8285080Swh31274 maddr->ma_bank, maddr->ma_dimm_addr);
8291772Sjl139090 return (0);
8301772Sjl139090 }
8311772Sjl139090
8322214Sav145390 /*
8332214Sav145390 * UNUM format for DC is "/CMUnn/MEMxyZ", where
8342214Sav145390 * nn = 00..03 for DC1 and 00..07 for DC2 and 00..15 for DC3.
8352214Sav145390 * x = MAC 0..3
8362214Sav145390 * y = 0..3 (slot info).
8372214Sav145390 * Z = 'A' or 'B'
8382214Sav145390 *
8392214Sav145390 * UNUM format for FF1 is "/MBU_A/MEMBx/MEMyZ", where
8402214Sav145390 * x = 0..3 (MEMB number)
8412214Sav145390 * y = 0..3 (slot info).
8422214Sav145390 * Z = 'A' or 'B'
8432214Sav145390 *
8446297Sjl139090 * UNUM format for FF2 is "/MBU_B/MEMBx/MEMyZ", where
8452214Sav145390 * x = 0..7 (MEMB number)
8462214Sav145390 * y = 0..3 (slot info).
8472214Sav145390 * Z = 'A' or 'B'
8486297Sjl139090 *
8496297Sjl139090 * UNUM format for IKKAKU is "/MBU_A/MEMyZ", where
8506297Sjl139090 * y = 0..3 (slot info).
8516297Sjl139090 * Z = 'A' or 'B'
8526297Sjl139090 *
8532214Sav145390 */
8542214Sav145390 int
mc_set_mem_unum(char * buf,int buflen,int sb,int bank,uint32_t mf_type,uint32_t d_slot)8553045Sav145390 mc_set_mem_unum(char *buf, int buflen, int sb, int bank,
8562214Sav145390 uint32_t mf_type, uint32_t d_slot)
8572214Sav145390 {
8582214Sav145390 char *dimmnm;
8592214Sav145390 char memb_num;
8603045Sav145390 int cs;
8612214Sav145390 int i;
8623045Sav145390 int j;
8633045Sav145390
8643045Sav145390 cs = SLOT_TO_CS(d_slot);
8652214Sav145390
8666297Sjl139090 switch (plat_model) {
8676297Sjl139090 case MODEL_DC:
8685275Stsien if (mf_type == FLT_TYPE_INTERMITTENT_CE ||
8695275Stsien mf_type == FLT_TYPE_PERMANENT_CE) {
8702214Sav145390 i = BD_BK_SLOT_TO_INDEX(0, bank, d_slot);
8712214Sav145390 dimmnm = mc_dc_dimm_unum_table[i];
87211311SSurya.Prakki@Sun.COM (void) snprintf(buf, buflen, "/%s%02d/MEM%s",
8732214Sav145390 model_names[plat_model].unit_name, sb, dimmnm);
8742214Sav145390 } else {
8752214Sav145390 i = BD_BK_SLOT_TO_INDEX(0, bank, 0);
8763045Sav145390 j = (cs == 0) ? i : i + 2;
87711311SSurya.Prakki@Sun.COM (void) snprintf(buf, buflen, "/%s%02d/MEM%s MEM%s",
8782214Sav145390 model_names[plat_model].unit_name, sb,
8793045Sav145390 mc_dc_dimm_unum_table[j],
8803045Sav145390 mc_dc_dimm_unum_table[j + 1]);
8812214Sav145390 }
8826297Sjl139090 break;
8836297Sjl139090 case MODEL_FF1:
8846297Sjl139090 case MODEL_FF2:
8855275Stsien if (mf_type == FLT_TYPE_INTERMITTENT_CE ||
8865275Stsien mf_type == FLT_TYPE_PERMANENT_CE) {
8873045Sav145390 i = BD_BK_SLOT_TO_INDEX(sb, bank, d_slot);
8882214Sav145390 dimmnm = mc_ff_dimm_unum_table[i];
8892214Sav145390 memb_num = dimmnm[0];
89011311SSurya.Prakki@Sun.COM (void) snprintf(buf, buflen, "/%s/%s%c/MEM%s",
8912214Sav145390 model_names[plat_model].unit_name,
8922214Sav145390 model_names[plat_model].mem_name,
8932214Sav145390 memb_num, &dimmnm[1]);
8942214Sav145390 } else {
8952214Sav145390 i = BD_BK_SLOT_TO_INDEX(sb, bank, 0);
8963045Sav145390 j = (cs == 0) ? i : i + 2;
8972214Sav145390 memb_num = mc_ff_dimm_unum_table[i][0],
89811311SSurya.Prakki@Sun.COM (void) snprintf(buf, buflen, "/%s/%s%c/MEM%s MEM%s",
8992214Sav145390 model_names[plat_model].unit_name,
9002214Sav145390 model_names[plat_model].mem_name, memb_num,
9013045Sav145390 &mc_ff_dimm_unum_table[j][1],
9023045Sav145390 &mc_ff_dimm_unum_table[j + 1][1]);
9032214Sav145390 }
9046297Sjl139090 break;
9056297Sjl139090 case MODEL_IKKAKU:
9066297Sjl139090 if (mf_type == FLT_TYPE_INTERMITTENT_CE ||
9076297Sjl139090 mf_type == FLT_TYPE_PERMANENT_CE) {
9086297Sjl139090 i = BD_BK_SLOT_TO_INDEX(sb, bank, d_slot);
9096297Sjl139090 dimmnm = mc_ff_dimm_unum_table[i];
91011311SSurya.Prakki@Sun.COM (void) snprintf(buf, buflen, "/%s/MEM%s",
9116297Sjl139090 model_names[plat_model].unit_name, &dimmnm[1]);
9126297Sjl139090 } else {
9136297Sjl139090 i = BD_BK_SLOT_TO_INDEX(sb, bank, 0);
9146297Sjl139090 j = (cs == 0) ? i : i + 2;
9156297Sjl139090 memb_num = mc_ff_dimm_unum_table[i][0],
91611311SSurya.Prakki@Sun.COM (void) snprintf(buf, buflen, "/%s/MEM%s MEM%s",
9176297Sjl139090 model_names[plat_model].unit_name,
9186297Sjl139090 &mc_ff_dimm_unum_table[j][1],
9196297Sjl139090 &mc_ff_dimm_unum_table[j + 1][1]);
9206297Sjl139090 }
9216297Sjl139090 break;
9226297Sjl139090 default:
9236297Sjl139090 return (-1);
9242214Sav145390 }
9252214Sav145390 return (0);
9262214Sav145390 }
9272214Sav145390
9281772Sjl139090 static void
mc_ereport_post(mc_aflt_t * mc_aflt)9291772Sjl139090 mc_ereport_post(mc_aflt_t *mc_aflt)
9301772Sjl139090 {
9311772Sjl139090 char buf[FM_MAX_CLASS];
9321772Sjl139090 char device_path[MAXPATHLEN];
9332214Sav145390 char sid[MAXPATHLEN];
9341772Sjl139090 nv_alloc_t *nva = NULL;
9351772Sjl139090 nvlist_t *ereport, *detector, *resource;
9361772Sjl139090 errorq_elem_t *eqep;
9371772Sjl139090 int nflts;
9381772Sjl139090 mc_flt_stat_t *flt_stat;
9392214Sav145390 int i, n;
9402214Sav145390 int blen = MAXPATHLEN;
9412214Sav145390 char *p, *s = NULL;
9421772Sjl139090 uint32_t values[2], synd[2], dslot[2];
9432214Sav145390 uint64_t offset = (uint64_t)-1;
9442214Sav145390 int ret = -1;
9451772Sjl139090
9461772Sjl139090 if (panicstr) {
9471772Sjl139090 eqep = errorq_reserve(ereport_errorq);
9481772Sjl139090 if (eqep == NULL)
9491772Sjl139090 return;
9501772Sjl139090 ereport = errorq_elem_nvl(ereport_errorq, eqep);
9511772Sjl139090 nva = errorq_elem_nva(ereport_errorq, eqep);
9521772Sjl139090 } else {
9531772Sjl139090 ereport = fm_nvlist_create(nva);
9541772Sjl139090 }
9551772Sjl139090
9561772Sjl139090 /*
9571772Sjl139090 * Create the scheme "dev" FMRI.
9581772Sjl139090 */
9591772Sjl139090 detector = fm_nvlist_create(nva);
9601772Sjl139090 resource = fm_nvlist_create(nva);
9611772Sjl139090
9621772Sjl139090 nflts = mc_aflt->mflt_nflts;
9631772Sjl139090
9641772Sjl139090 ASSERT(nflts >= 1 && nflts <= 2);
9651772Sjl139090
9661772Sjl139090 flt_stat = mc_aflt->mflt_stat[0];
9671772Sjl139090 (void) ddi_pathname(mc_aflt->mflt_mcp->mc_dip, device_path);
9681772Sjl139090 (void) fm_fmri_dev_set(detector, FM_DEV_SCHEME_VERSION, NULL,
969*12213SGavin.Maltby@Sun.COM device_path, NULL, NULL);
9701772Sjl139090
9711772Sjl139090 /*
9721772Sjl139090 * Encode all the common data into the ereport.
9731772Sjl139090 */
9745080Swh31274 (void) snprintf(buf, FM_MAX_CLASS, "%s.%s-%s", MC_OPL_ERROR_CLASS,
9755080Swh31274 mc_aflt->mflt_is_ptrl ? MC_OPL_PTRL_SUBCLASS : MC_OPL_MI_SUBCLASS,
9765080Swh31274 mc_aflt->mflt_erpt_class);
9771772Sjl139090
9781772Sjl139090 MC_LOG("mc_ereport_post: ereport %s\n", buf);
9791772Sjl139090
9801772Sjl139090
9811772Sjl139090 fm_ereport_set(ereport, FM_EREPORT_VERSION, buf,
9825080Swh31274 fm_ena_generate(mc_aflt->mflt_id, FM_ENA_FMT1), detector, NULL);
9831772Sjl139090
9841772Sjl139090 /*
9851772Sjl139090 * Set payload.
9861772Sjl139090 */
9871772Sjl139090 fm_payload_set(ereport, MC_OPL_BOARD, DATA_TYPE_UINT32,
9885080Swh31274 flt_stat->mf_flt_maddr.ma_bd, NULL);
9891772Sjl139090
9901772Sjl139090 fm_payload_set(ereport, MC_OPL_PA, DATA_TYPE_UINT64,
9915080Swh31274 flt_stat->mf_flt_paddr, NULL);
9921772Sjl139090
9935275Stsien if (flt_stat->mf_type == FLT_TYPE_INTERMITTENT_CE ||
9945275Stsien flt_stat->mf_type == FLT_TYPE_PERMANENT_CE) {
9955080Swh31274 fm_payload_set(ereport, MC_OPL_FLT_TYPE, DATA_TYPE_UINT8,
9965080Swh31274 ECC_STICKY, NULL);
9971772Sjl139090 }
9981772Sjl139090
9991772Sjl139090 for (i = 0; i < nflts; i++)
10001772Sjl139090 values[i] = mc_aflt->mflt_stat[i]->mf_flt_maddr.ma_bank;
10011772Sjl139090
10025080Swh31274 fm_payload_set(ereport, MC_OPL_BANK, DATA_TYPE_UINT32_ARRAY, nflts,
10035080Swh31274 values, NULL);
10041772Sjl139090
10051772Sjl139090 for (i = 0; i < nflts; i++)
10061772Sjl139090 values[i] = mc_aflt->mflt_stat[i]->mf_cntl;
10071772Sjl139090
10085080Swh31274 fm_payload_set(ereport, MC_OPL_STATUS, DATA_TYPE_UINT32_ARRAY, nflts,
10095080Swh31274 values, NULL);
10101772Sjl139090
10111772Sjl139090 for (i = 0; i < nflts; i++)
10121772Sjl139090 values[i] = mc_aflt->mflt_stat[i]->mf_err_add;
10131772Sjl139090
10145275Stsien /* offset is set only for PCE and ICE */
10155275Stsien if (mc_aflt->mflt_stat[0]->mf_type == FLT_TYPE_INTERMITTENT_CE ||
10165275Stsien mc_aflt->mflt_stat[0]->mf_type == FLT_TYPE_PERMANENT_CE) {
10172214Sav145390 offset = values[0];
10182214Sav145390
10192214Sav145390 }
10205080Swh31274 fm_payload_set(ereport, MC_OPL_ERR_ADD, DATA_TYPE_UINT32_ARRAY, nflts,
10215080Swh31274 values, NULL);
10221772Sjl139090
10231772Sjl139090 for (i = 0; i < nflts; i++)
10241772Sjl139090 values[i] = mc_aflt->mflt_stat[i]->mf_err_log;
10251772Sjl139090
10265080Swh31274 fm_payload_set(ereport, MC_OPL_ERR_LOG, DATA_TYPE_UINT32_ARRAY, nflts,
10275080Swh31274 values, NULL);
10281772Sjl139090
10291772Sjl139090 for (i = 0; i < nflts; i++) {
10301772Sjl139090 flt_stat = mc_aflt->mflt_stat[i];
10311772Sjl139090 if (flt_stat->mf_errlog_valid) {
10321772Sjl139090 synd[i] = flt_stat->mf_synd;
10331772Sjl139090 dslot[i] = flt_stat->mf_dimm_slot;
10341772Sjl139090 values[i] = flt_stat->mf_dram_place;
10351772Sjl139090 } else {
10361772Sjl139090 synd[i] = 0;
10371772Sjl139090 dslot[i] = 0;
10381772Sjl139090 values[i] = 0;
10391772Sjl139090 }
10401772Sjl139090 }
10411772Sjl139090
10425080Swh31274 fm_payload_set(ereport, MC_OPL_ERR_SYND, DATA_TYPE_UINT32_ARRAY, nflts,
10435080Swh31274 synd, NULL);
10445080Swh31274
10455080Swh31274 fm_payload_set(ereport, MC_OPL_ERR_DIMMSLOT, DATA_TYPE_UINT32_ARRAY,
10465080Swh31274 nflts, dslot, NULL);
10475080Swh31274
10485080Swh31274 fm_payload_set(ereport, MC_OPL_ERR_DRAM, DATA_TYPE_UINT32_ARRAY, nflts,
10495080Swh31274 values, NULL);
10501772Sjl139090
10511772Sjl139090 device_path[0] = 0;
10521772Sjl139090 p = &device_path[0];
10532214Sav145390 sid[0] = 0;
10542214Sav145390 s = &sid[0];
10552214Sav145390 ret = 0;
10561772Sjl139090
10571772Sjl139090 for (i = 0; i < nflts; i++) {
10582214Sav145390 int bank;
10591772Sjl139090
10601772Sjl139090 flt_stat = mc_aflt->mflt_stat[i];
10612214Sav145390 bank = flt_stat->mf_flt_maddr.ma_bank;
10625080Swh31274 ret = mc_set_mem_unum(p + strlen(p), blen,
10635080Swh31274 flt_stat->mf_flt_maddr.ma_phys_bd, bank, flt_stat->mf_type,
10645080Swh31274 flt_stat->mf_dimm_slot);
10652214Sav145390
10662214Sav145390 if (ret != 0) {
10672214Sav145390 cmn_err(CE_WARN,
10682214Sav145390 "mc_ereport_post: Failed to determine the unum "
10692214Sav145390 "for board=%d bank=%d type=0x%x slot=0x%x",
10702214Sav145390 flt_stat->mf_flt_maddr.ma_bd, bank,
10712214Sav145390 flt_stat->mf_type, flt_stat->mf_dimm_slot);
10722214Sav145390 continue;
10731772Sjl139090 }
10742214Sav145390 n = strlen(device_path);
10751772Sjl139090 blen = MAXPATHLEN - n;
10761772Sjl139090 p = &device_path[n];
10771772Sjl139090 if (i < (nflts - 1)) {
107811311SSurya.Prakki@Sun.COM (void) snprintf(p, blen, " ");
10792214Sav145390 blen--;
10802214Sav145390 p++;
10812214Sav145390 }
10822214Sav145390
10832214Sav145390 if (ret == 0) {
10842214Sav145390 ret = mc_set_mem_sid(mc_aflt->mflt_mcp, s + strlen(s),
10853045Sav145390 blen, flt_stat->mf_flt_maddr.ma_phys_bd, bank,
10862214Sav145390 flt_stat->mf_type, flt_stat->mf_dimm_slot);
10872214Sav145390
10881772Sjl139090 }
10891772Sjl139090 }
10901772Sjl139090
10915080Swh31274 (void) fm_fmri_mem_set(resource, FM_MEM_SCHEME_VERSION, NULL,
10925080Swh31274 device_path, (ret == 0) ? sid : NULL, (ret == 0) ? offset :
10935080Swh31274 (uint64_t)-1);
10945080Swh31274
10955080Swh31274 fm_payload_set(ereport, MC_OPL_RESOURCE, DATA_TYPE_NVLIST, resource,
10965080Swh31274 NULL);
10971772Sjl139090
10981772Sjl139090 if (panicstr) {
10991772Sjl139090 errorq_commit(ereport_errorq, eqep, ERRORQ_SYNC);
11001772Sjl139090 } else {
11011772Sjl139090 (void) fm_ereport_post(ereport, EVCH_TRYHARD);
11021772Sjl139090 fm_nvlist_destroy(ereport, FM_NVA_FREE);
11031772Sjl139090 fm_nvlist_destroy(detector, FM_NVA_FREE);
11041772Sjl139090 fm_nvlist_destroy(resource, FM_NVA_FREE);
11051772Sjl139090 }
11061772Sjl139090 }
11071772Sjl139090
11082214Sav145390
11091772Sjl139090 static void
mc_err_drain(mc_aflt_t * mc_aflt)11101772Sjl139090 mc_err_drain(mc_aflt_t *mc_aflt)
11111772Sjl139090 {
11121772Sjl139090 int rv;
11131772Sjl139090 uint64_t pa = (uint64_t)(-1);
11142214Sav145390 int i;
11151772Sjl139090
11165080Swh31274 MC_LOG("mc_err_drain: %s\n", mc_aflt->mflt_erpt_class);
11171772Sjl139090 /*
11181772Sjl139090 * we come here only when we have:
11193152Sav145390 * In mirror mode: MUE, SUE
11205275Stsien * In normal mode: UE, Permanent CE, Intermittent CE
11211772Sjl139090 */
11222214Sav145390 for (i = 0; i < mc_aflt->mflt_nflts; i++) {
11232214Sav145390 rv = mcaddr_to_pa(mc_aflt->mflt_mcp,
11245080Swh31274 &(mc_aflt->mflt_stat[i]->mf_flt_maddr), &pa);
11252662Shyw
11262662Shyw /* Ensure the pa is valid (not in isolated memory block) */
11272662Shyw if (rv == 0 && pa_is_valid(mc_aflt->mflt_mcp, pa))
11282214Sav145390 mc_aflt->mflt_stat[i]->mf_flt_paddr = pa;
11292214Sav145390 else
11302214Sav145390 mc_aflt->mflt_stat[i]->mf_flt_paddr = (uint64_t)-1;
11312214Sav145390 }
11322214Sav145390
11332662Shyw MC_LOG("mc_err_drain:pa = %lx\n", pa);
11342662Shyw
11352662Shyw switch (page_retire_check(pa, NULL)) {
11362662Shyw case 0:
11372662Shyw case EAGAIN:
11382662Shyw MC_LOG("Page retired or pending\n");
11392662Shyw return;
11402662Shyw case EIO:
11412662Shyw /*
11425275Stsien * Do page retirement except for the PCE and ICE cases.
11432662Shyw * This is taken care by the OPL DE
11442662Shyw */
11455275Stsien if (mc_aflt->mflt_stat[0]->mf_type !=
11465275Stsien FLT_TYPE_INTERMITTENT_CE &&
11475275Stsien mc_aflt->mflt_stat[0]->mf_type != FLT_TYPE_PERMANENT_CE) {
11482662Shyw MC_LOG("offline page at pa %lx error %x\n", pa,
11495080Swh31274 mc_aflt->mflt_pr);
11502662Shyw (void) page_retire(pa, mc_aflt->mflt_pr);
11511772Sjl139090 }
11522662Shyw break;
11532662Shyw case EINVAL:
11542662Shyw default:
11552662Shyw /*
11562662Shyw * Some memory do not have page structure so
11572662Shyw * we keep going in case of EINVAL.
11582662Shyw */
11592662Shyw break;
11601772Sjl139090 }
11612214Sav145390
11622214Sav145390 for (i = 0; i < mc_aflt->mflt_nflts; i++) {
11632214Sav145390 mc_aflt_t mc_aflt0;
11642214Sav145390 if (mc_aflt->mflt_stat[i]->mf_flt_paddr != (uint64_t)-1) {
11652214Sav145390 mc_aflt0 = *mc_aflt;
11662214Sav145390 mc_aflt0.mflt_nflts = 1;
11672214Sav145390 mc_aflt0.mflt_stat[0] = mc_aflt->mflt_stat[i];
11682214Sav145390 mc_ereport_post(&mc_aflt0);
11692214Sav145390 }
11702214Sav145390 }
11711772Sjl139090 }
11721772Sjl139090
11731772Sjl139090 /*
11741772Sjl139090 * The restart address is actually defined in unit of PA[37:6]
11751772Sjl139090 * the mac patrol will convert that to dimm offset. If the
11761772Sjl139090 * address is not in the bank, it will continue to search for
11771772Sjl139090 * the next PA that is within the bank.
11781772Sjl139090 *
11791772Sjl139090 * Also the mac patrol scans the dimms based on PA, not
11801772Sjl139090 * dimm offset.
11811772Sjl139090 */
11821772Sjl139090 static int
restart_patrol(mc_opl_t * mcp,int bank,mc_rsaddr_info_t * rsaddr_info)11832662Shyw restart_patrol(mc_opl_t *mcp, int bank, mc_rsaddr_info_t *rsaddr_info)
11841772Sjl139090 {
11851772Sjl139090 uint64_t pa;
11861772Sjl139090 int rv;
11872662Shyw
11885310Sdhain if (MC_REWRITE_MODE(mcp, bank)) {
11895310Sdhain return (0);
11905310Sdhain }
11912662Shyw if (rsaddr_info == NULL || (rsaddr_info->mi_valid == 0)) {
11921772Sjl139090 MAC_PTRL_START(mcp, bank);
11931772Sjl139090 return (0);
11941772Sjl139090 }
11951772Sjl139090
11962662Shyw rv = mcaddr_to_pa(mcp, &rsaddr_info->mi_restartaddr, &pa);
11971772Sjl139090 if (rv != 0) {
11981772Sjl139090 MC_LOG("cannot convert mcaddr to pa. use auto restart\n");
11991772Sjl139090 MAC_PTRL_START(mcp, bank);
12001772Sjl139090 return (0);
12011772Sjl139090 }
12021772Sjl139090
12032662Shyw if (!mc_rangecheck_pa(mcp, pa)) {
12041772Sjl139090 /* pa is not on this board, just retry */
12051772Sjl139090 cmn_err(CE_WARN, "restart_patrol: invalid address %lx "
12065080Swh31274 "on board %d\n", pa, mcp->mc_board_num);
12071772Sjl139090 MAC_PTRL_START(mcp, bank);
12081772Sjl139090 return (0);
12091772Sjl139090 }
12101772Sjl139090
12111772Sjl139090 MC_LOG("restart_patrol: pa = %lx\n", pa);
12122662Shyw
12132662Shyw if (!rsaddr_info->mi_injectrestart) {
12142662Shyw /*
12153152Sav145390 * For non-error injection restart we need to
12162662Shyw * determine if the current restart pa/page is
12172662Shyw * a "good" page. A "good" page is a page that
12182662Shyw * has not been page retired. If the current
12192662Shyw * page that contains the pa is "good", we will
12202662Shyw * do a HW auto restart and let HW patrol continue
12212662Shyw * where it last stopped. Most desired scenario.
12222662Shyw *
12232662Shyw * If the current page is not "good", we will advance
12242662Shyw * to the next page to find the next "good" page and
12252662Shyw * restart the patrol from there.
12262662Shyw */
12272662Shyw int wrapcount = 0;
12282662Shyw uint64_t origpa = pa;
12292662Shyw while (wrapcount < 2) {
12305080Swh31274 if (!pa_is_valid(mcp, pa)) {
12315310Sdhain /*
12325310Sdhain * Not in physinstall - advance to the
12335310Sdhain * next memory isolation blocksize
12345310Sdhain */
12355310Sdhain MC_LOG("Invalid PA\n");
12365310Sdhain pa = roundup(pa + 1, mc_isolation_bsize);
12375080Swh31274 } else {
12385310Sdhain int rv;
12395310Sdhain if ((rv = page_retire_check(pa, NULL)) != 0 &&
12405310Sdhain rv != EAGAIN) {
12415080Swh31274 /*
12425080Swh31274 * The page is "good" (not retired),
12435080Swh31274 * we will use automatic HW restart
12445080Swh31274 * algorithm if this is the original
12455080Swh31274 * current starting page.
12465080Swh31274 */
12475310Sdhain if (pa == origpa) {
12485310Sdhain MC_LOG("Page has no error. "
12495310Sdhain "Auto restart\n");
12505310Sdhain MAC_PTRL_START(mcp, bank);
12515310Sdhain return (0);
12525310Sdhain } else {
12535310Sdhain /*
12545310Sdhain * found a subsequent good page
12555310Sdhain */
12565310Sdhain break;
12572662Shyw }
12581772Sjl139090 }
12592662Shyw
12605310Sdhain /*
12615310Sdhain * Skip to the next page
12625310Sdhain */
12635310Sdhain pa = roundup(pa + 1, PAGESIZE);
12645310Sdhain MC_LOG("Skipping bad page to %lx\n", pa);
12655310Sdhain }
12665310Sdhain
12675310Sdhain /* Check to see if we hit the end of the memory range */
12685080Swh31274 if (pa >= (mcp->mc_start_address + mcp->mc_size)) {
12695310Sdhain MC_LOG("Wrap around\n");
12705310Sdhain pa = mcp->mc_start_address;
12715310Sdhain wrapcount++;
12725080Swh31274 }
12732662Shyw }
12742662Shyw
12752662Shyw if (wrapcount > 1) {
12765080Swh31274 MC_LOG("Failed to find a good page. Just restart\n");
12775080Swh31274 MAC_PTRL_START(mcp, bank);
12785080Swh31274 return (0);
12791772Sjl139090 }
12801772Sjl139090 }
12811772Sjl139090
12821772Sjl139090 /*
12832662Shyw * We reached here either:
12842662Shyw * 1. We are doing an error injection restart that specify
12852662Shyw * the exact pa/page to restart. OR
12862662Shyw * 2. We found a subsequent good page different from the
12872662Shyw * original restart pa/page.
12882662Shyw * Restart MAC patrol: PA[37:6]
12891772Sjl139090 */
12901772Sjl139090 MC_LOG("restart at pa = %lx\n", pa);
12911772Sjl139090 ST_MAC_REG(MAC_RESTART_ADD(mcp, bank), MAC_RESTART_PA(pa));
12921772Sjl139090 MAC_PTRL_START_ADD(mcp, bank);
12931772Sjl139090
12941772Sjl139090 return (0);
12951772Sjl139090 }
12961772Sjl139090
12975310Sdhain static void
mc_retry_info_put(mc_retry_info_t ** q,mc_retry_info_t * p)12985310Sdhain mc_retry_info_put(mc_retry_info_t **q, mc_retry_info_t *p)
12995310Sdhain {
13005310Sdhain ASSERT(p != NULL);
13015310Sdhain p->ri_next = *q;
13025310Sdhain *q = p;
13035310Sdhain }
13045310Sdhain
13055310Sdhain static mc_retry_info_t *
mc_retry_info_get(mc_retry_info_t ** q)13065310Sdhain mc_retry_info_get(mc_retry_info_t **q)
13075310Sdhain {
13085310Sdhain mc_retry_info_t *p;
13095310Sdhain
13105310Sdhain if ((p = *q) != NULL) {
13115310Sdhain *q = p->ri_next;
13125310Sdhain return (p);
13135310Sdhain } else {
13145310Sdhain return (NULL);
13155310Sdhain }
13165310Sdhain }
13175310Sdhain
13181772Sjl139090 /*
13191772Sjl139090 * Rewriting is used for two purposes.
13201772Sjl139090 * - to correct the error in memory.
13211772Sjl139090 * - to determine whether the error is permanent or intermittent.
13221772Sjl139090 * It's done by writing the address in MAC_BANKm_REWRITE_ADD
13231772Sjl139090 * and issuing REW_REQ command in MAC_BANKm_PTRL_CNRL. After that,
13241772Sjl139090 * REW_END (and REW_CE/REW_UE if some error detected) is set when
13251772Sjl139090 * rewrite operation is done. See 4.7.3 and 4.7.11 in Columbus2 PRM.
13261772Sjl139090 *
13271772Sjl139090 * Note that rewrite operation doesn't change RAW_UE to Marked UE.
13281772Sjl139090 * Therefore, we use it only CE case.
13291772Sjl139090 */
13305310Sdhain
13311772Sjl139090 static uint32_t
do_rewrite(mc_opl_t * mcp,int bank,uint32_t dimm_addr,int retrying)13325310Sdhain do_rewrite(mc_opl_t *mcp, int bank, uint32_t dimm_addr, int retrying)
13331772Sjl139090 {
13341772Sjl139090 uint32_t cntl;
13351772Sjl139090 int count = 0;
13365310Sdhain int max_count;
13375310Sdhain int retry_state;
13385310Sdhain
13395310Sdhain if (retrying)
13405310Sdhain max_count = 1;
13415310Sdhain else
13425310Sdhain max_count = mc_max_rewrite_loop;
13435310Sdhain
13445310Sdhain retry_state = RETRY_STATE_PENDING;
13455310Sdhain
13465310Sdhain if (!retrying && MC_REWRITE_MODE(mcp, bank)) {
13475310Sdhain goto timeout;
13485310Sdhain }
13495310Sdhain
13505310Sdhain retry_state = RETRY_STATE_ACTIVE;
13511772Sjl139090
13521772Sjl139090 /* first wait to make sure PTRL_STATUS is 0 */
13535310Sdhain while (count++ < max_count) {
13541772Sjl139090 cntl = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank));
13555310Sdhain if (!(cntl & MAC_CNTL_PTRL_STATUS)) {
13565310Sdhain count = 0;
13571772Sjl139090 break;
13585310Sdhain }
13592214Sav145390 drv_usecwait(mc_rewrite_delay);
13601772Sjl139090 }
13615310Sdhain if (count >= max_count)
13625310Sdhain goto timeout;
13631772Sjl139090
13641772Sjl139090 count = 0;
13651772Sjl139090
13661772Sjl139090 ST_MAC_REG(MAC_REWRITE_ADD(mcp, bank), dimm_addr);
13671772Sjl139090 MAC_REW_REQ(mcp, bank);
13681772Sjl139090
13695310Sdhain retry_state = RETRY_STATE_REWRITE;
13705310Sdhain
13711772Sjl139090 do {
13725310Sdhain if (count++ > max_count) {
13735310Sdhain goto timeout;
13742214Sav145390 } else {
13752214Sav145390 drv_usecwait(mc_rewrite_delay);
13762214Sav145390 }
13775310Sdhain cntl = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank));
13781772Sjl139090 /*
13791772Sjl139090 * If there are other MEMORY or PCI activities, this
13801772Sjl139090 * will be BUSY, else it should be set immediately
13811772Sjl139090 */
13821772Sjl139090 } while (!(cntl & MAC_CNTL_REW_END));
13831772Sjl139090
13841772Sjl139090 MAC_CLEAR_ERRS(mcp, bank, MAC_CNTL_REW_ERRS);
13851772Sjl139090 return (cntl);
13865310Sdhain timeout:
13875310Sdhain mc_set_rewrite(mcp, bank, dimm_addr, retry_state);
13885310Sdhain
13895310Sdhain return (0);
13901772Sjl139090 }
13915310Sdhain
13925310Sdhain void
mc_clear_rewrite(mc_opl_t * mcp,int bank)13935310Sdhain mc_clear_rewrite(mc_opl_t *mcp, int bank)
13945310Sdhain {
13955310Sdhain struct mc_bank *bankp;
13965310Sdhain mc_retry_info_t *retry;
13975310Sdhain uint32_t rew_addr;
13985310Sdhain
13995310Sdhain bankp = &(mcp->mc_bank[bank]);
14005310Sdhain retry = bankp->mcb_active;
14015310Sdhain bankp->mcb_active = NULL;
14025310Sdhain mc_retry_info_put(&bankp->mcb_retry_freelist, retry);
14035310Sdhain
14045310Sdhain again:
14055310Sdhain bankp->mcb_rewrite_count = 0;
14065310Sdhain
14075310Sdhain while (retry = mc_retry_info_get(&bankp->mcb_retry_pending)) {
14085310Sdhain rew_addr = retry->ri_addr;
14095310Sdhain mc_retry_info_put(&bankp->mcb_retry_freelist, retry);
14105310Sdhain if (do_rewrite(mcp, bank, rew_addr, 1) == 0)
14115310Sdhain break;
14125310Sdhain }
14135310Sdhain
14145310Sdhain /* we break out if no more pending rewrite or we got timeout again */
14155310Sdhain
14165310Sdhain if (!bankp->mcb_active && !bankp->mcb_retry_pending) {
14175310Sdhain if (!IS_MIRROR(mcp, bank)) {
14185310Sdhain MC_CLEAR_REWRITE_MODE(mcp, bank);
14195310Sdhain } else {
14205310Sdhain int mbank = bank ^ 1;
14215310Sdhain bankp = &(mcp->mc_bank[mbank]);
14225310Sdhain if (!bankp->mcb_active && !bankp->mcb_retry_pending) {
14235310Sdhain MC_CLEAR_REWRITE_MODE(mcp, bank);
14245310Sdhain MC_CLEAR_REWRITE_MODE(mcp, mbank);
14255310Sdhain } else {
14265310Sdhain bank = mbank;
14275310Sdhain goto again;
14285310Sdhain }
14295310Sdhain }
14305310Sdhain }
14315310Sdhain }
14325310Sdhain
14335310Sdhain void
mc_set_rewrite(mc_opl_t * mcp,int bank,uint32_t addr,int state)14345310Sdhain mc_set_rewrite(mc_opl_t *mcp, int bank, uint32_t addr, int state)
14355310Sdhain {
14365310Sdhain mc_retry_info_t *retry;
14375310Sdhain struct mc_bank *bankp;
14385310Sdhain
14395310Sdhain bankp = &mcp->mc_bank[bank];
14405310Sdhain
14415310Sdhain retry = mc_retry_info_get(&bankp->mcb_retry_freelist);
14425310Sdhain
14436693Swh31274 if (retry == NULL) {
14446693Swh31274 mc_addr_t maddr;
14456693Swh31274 uint64_t paddr;
14466693Swh31274 /*
14476693Swh31274 * previous rewrite request has not completed yet.
14486693Swh31274 * So we discard this rewrite request.
14496693Swh31274 */
14506693Swh31274 maddr.ma_bd = mcp->mc_board_num;
14516693Swh31274 maddr.ma_bank = bank;
14526693Swh31274 maddr.ma_dimm_addr = addr;
14536693Swh31274 if (mcaddr_to_pa(mcp, &maddr, &paddr) == 0) {
14546693Swh31274 cmn_err(CE_WARN, "Discard CE rewrite request"
14556693Swh31274 " for 0x%lx (/LSB%d/B%d/%x).\n",
14566693Swh31274 paddr, mcp->mc_board_num, bank, addr);
14576693Swh31274 } else {
14586693Swh31274 cmn_err(CE_WARN, "Discard CE rewrite request"
14596693Swh31274 " for /LSB%d/B%d/%x.\n",
14606693Swh31274 mcp->mc_board_num, bank, addr);
14616693Swh31274 }
14626693Swh31274 return;
14636693Swh31274 }
14645310Sdhain
14655310Sdhain retry->ri_addr = addr;
14665310Sdhain retry->ri_state = state;
14675310Sdhain
14685310Sdhain MC_SET_REWRITE_MODE(mcp, bank);
14695310Sdhain
14705310Sdhain if ((state > RETRY_STATE_PENDING)) {
14715310Sdhain ASSERT(bankp->mcb_active == NULL);
14725310Sdhain bankp->mcb_active = retry;
14735310Sdhain } else {
14745310Sdhain mc_retry_info_put(&bankp->mcb_retry_pending, retry);
14755310Sdhain }
14765310Sdhain
14775310Sdhain if (IS_MIRROR(mcp, bank)) {
14785310Sdhain int mbank = bank ^1;
14795310Sdhain MC_SET_REWRITE_MODE(mcp, mbank);
14805310Sdhain }
14815310Sdhain }
14825310Sdhain
14831772Sjl139090 void
mc_process_scf_log(mc_opl_t * mcp)14841772Sjl139090 mc_process_scf_log(mc_opl_t *mcp)
14851772Sjl139090 {
14862214Sav145390 int count;
14872214Sav145390 int n = 0;
14881772Sjl139090 scf_log_t *p;
14891772Sjl139090 int bank;
14901772Sjl139090
14912214Sav145390 for (bank = 0; bank < BANKNUM_PER_SB; bank++) {
14925080Swh31274 while ((p = mcp->mc_scf_log[bank]) != NULL &&
14935080Swh31274 (n < mc_max_errlog_processed)) {
14945310Sdhain ASSERT(bank == p->sl_bank);
14955310Sdhain count = 0;
14965310Sdhain while ((LD_MAC_REG(MAC_STATIC_ERR_ADD(mcp, p->sl_bank))
14975310Sdhain & MAC_STATIC_ERR_VLD)) {
14985310Sdhain if (count++ >= (mc_max_scf_loop)) {
14995310Sdhain break;
15001772Sjl139090 }
15015310Sdhain drv_usecwait(mc_scf_delay);
15025310Sdhain }
15035310Sdhain
15045310Sdhain if (count < mc_max_scf_loop) {
15055310Sdhain ST_MAC_REG(MAC_STATIC_ERR_LOG(mcp, p->sl_bank),
15065310Sdhain p->sl_err_log);
15075310Sdhain
15085310Sdhain ST_MAC_REG(MAC_STATIC_ERR_ADD(mcp, p->sl_bank),
15095310Sdhain p->sl_err_add|MAC_STATIC_ERR_VLD);
15105310Sdhain mcp->mc_scf_retry[bank] = 0;
15115310Sdhain } else {
15125310Sdhain /*
15135310Sdhain * if we try too many times, just drop the req
15145310Sdhain */
15155310Sdhain if (mcp->mc_scf_retry[bank]++ <=
15165310Sdhain mc_max_scf_retry) {
15175310Sdhain return;
15185080Swh31274 } else {
15195310Sdhain if ((++mc_pce_dropped & 0xff) == 0) {
15205310Sdhain cmn_err(CE_WARN, "Cannot "
15216693Swh31274 "report CE to SCF\n");
15225080Swh31274 }
15235080Swh31274 }
15245310Sdhain }
15255310Sdhain n++;
15265310Sdhain mcp->mc_scf_log[bank] = p->sl_next;
15275310Sdhain mcp->mc_scf_total[bank]--;
15285310Sdhain ASSERT(mcp->mc_scf_total[bank] >= 0);
15295310Sdhain kmem_free(p, sizeof (scf_log_t));
15301772Sjl139090 }
15311772Sjl139090 }
15321772Sjl139090 }
15331772Sjl139090 void
mc_queue_scf_log(mc_opl_t * mcp,mc_flt_stat_t * flt_stat,int bank)15341772Sjl139090 mc_queue_scf_log(mc_opl_t *mcp, mc_flt_stat_t *flt_stat, int bank)
15351772Sjl139090 {
15361772Sjl139090 scf_log_t *p;
15371772Sjl139090
15382214Sav145390 if (mcp->mc_scf_total[bank] >= mc_max_scf_logs) {
15392214Sav145390 if ((++mc_pce_dropped & 0xff) == 0) {
15406693Swh31274 cmn_err(CE_WARN, "Too many CE requests.\n");
15412214Sav145390 }
15421772Sjl139090 return;
15431772Sjl139090 }
15441772Sjl139090 p = kmem_zalloc(sizeof (scf_log_t), KM_SLEEP);
15451772Sjl139090 p->sl_next = 0;
15461772Sjl139090 p->sl_err_add = flt_stat->mf_err_add;
15471772Sjl139090 p->sl_err_log = flt_stat->mf_err_log;
15481772Sjl139090 p->sl_bank = bank;
15491772Sjl139090
15502214Sav145390 if (mcp->mc_scf_log[bank] == NULL) {
15511772Sjl139090 /*
15521772Sjl139090 * we rely on mc_scf_log to detect NULL queue.
15531772Sjl139090 * mc_scf_log_tail is irrelevant is such case.
15541772Sjl139090 */
15552214Sav145390 mcp->mc_scf_log_tail[bank] = mcp->mc_scf_log[bank] = p;
15561772Sjl139090 } else {
15572214Sav145390 mcp->mc_scf_log_tail[bank]->sl_next = p;
15582214Sav145390 mcp->mc_scf_log_tail[bank] = p;
15591772Sjl139090 }
15602214Sav145390 mcp->mc_scf_total[bank]++;
15611772Sjl139090 }
15621772Sjl139090 /*
15631772Sjl139090 * This routine determines what kind of CE happens, intermittent
15641772Sjl139090 * or permanent as follows. (See 4.7.3 in Columbus2 PRM.)
15651772Sjl139090 * - Do rewrite by issuing REW_REQ command to MAC_PTRL_CNTL register.
15661772Sjl139090 * - If CE is still detected on the same address even after doing
15671772Sjl139090 * rewrite operation twice, it is determined as permanent error.
15681772Sjl139090 * - If error is not detected anymore, it is determined as intermittent
15691772Sjl139090 * error.
15701772Sjl139090 * - If UE is detected due to rewrite operation, it should be treated
15711772Sjl139090 * as UE.
15721772Sjl139090 */
15731772Sjl139090
15741772Sjl139090 /* ARGSUSED */
15751772Sjl139090 static void
mc_scrub_ce(mc_opl_t * mcp,int bank,mc_flt_stat_t * flt_stat,int ptrl_error)15761772Sjl139090 mc_scrub_ce(mc_opl_t *mcp, int bank, mc_flt_stat_t *flt_stat, int ptrl_error)
15771772Sjl139090 {
15781772Sjl139090 uint32_t cntl;
15791772Sjl139090 int i;
15801772Sjl139090
15811772Sjl139090 flt_stat->mf_type = FLT_TYPE_PERMANENT_CE;
15821772Sjl139090 /*
15831772Sjl139090 * rewrite request 1st time reads and correct error data
15841772Sjl139090 * and write to DIMM. 2nd rewrite request must be issued
15851772Sjl139090 * after REW_CE/UE/END is 0. When the 2nd request is completed,
15861772Sjl139090 * if REW_CE = 1, then it is permanent CE.
15871772Sjl139090 */
15881772Sjl139090 for (i = 0; i < 2; i++) {
15895310Sdhain cntl = do_rewrite(mcp, bank, flt_stat->mf_err_add, 0);
15905310Sdhain
15915310Sdhain if (cntl == 0) {
15925310Sdhain /* timeout case */
15935310Sdhain return;
15945310Sdhain }
15951772Sjl139090 /*
15961772Sjl139090 * If the error becomes UE or CMPE
15971772Sjl139090 * we return to the caller immediately.
15981772Sjl139090 */
15991772Sjl139090 if (cntl & MAC_CNTL_REW_UE) {
16001772Sjl139090 if (ptrl_error)
16011772Sjl139090 flt_stat->mf_cntl |= MAC_CNTL_PTRL_UE;
16021772Sjl139090 else
16031772Sjl139090 flt_stat->mf_cntl |= MAC_CNTL_MI_UE;
16041772Sjl139090 flt_stat->mf_type = FLT_TYPE_UE;
16051772Sjl139090 return;
16061772Sjl139090 }
16071772Sjl139090 if (cntl & MAC_CNTL_REW_CMPE) {
16081772Sjl139090 if (ptrl_error)
16091772Sjl139090 flt_stat->mf_cntl |= MAC_CNTL_PTRL_CMPE;
16101772Sjl139090 else
16111772Sjl139090 flt_stat->mf_cntl |= MAC_CNTL_MI_CMPE;
16121772Sjl139090 flt_stat->mf_type = FLT_TYPE_CMPE;
16131772Sjl139090 return;
16141772Sjl139090 }
16151772Sjl139090 }
16161772Sjl139090 if (!(cntl & MAC_CNTL_REW_CE)) {
16171772Sjl139090 flt_stat->mf_type = FLT_TYPE_INTERMITTENT_CE;
16181772Sjl139090 }
16191772Sjl139090
16201772Sjl139090 if (flt_stat->mf_type == FLT_TYPE_PERMANENT_CE) {
16211772Sjl139090 /* report PERMANENT_CE to SP via SCF */
16221772Sjl139090 if (!(flt_stat->mf_err_log & MAC_ERR_LOG_INVALID)) {
16231772Sjl139090 mc_queue_scf_log(mcp, flt_stat, bank);
16241772Sjl139090 }
16251772Sjl139090 }
16261772Sjl139090 }
16271772Sjl139090
16281772Sjl139090 #define IS_CMPE(cntl, f) ((cntl) & ((f) ? MAC_CNTL_PTRL_CMPE :\
16291772Sjl139090 MAC_CNTL_MI_CMPE))
16301772Sjl139090 #define IS_UE(cntl, f) ((cntl) & ((f) ? MAC_CNTL_PTRL_UE : MAC_CNTL_MI_UE))
16311772Sjl139090 #define IS_CE(cntl, f) ((cntl) & ((f) ? MAC_CNTL_PTRL_CE : MAC_CNTL_MI_CE))
16321772Sjl139090 #define IS_OK(cntl, f) (!((cntl) & ((f) ? MAC_CNTL_PTRL_ERRS : \
16331772Sjl139090 MAC_CNTL_MI_ERRS)))
16341772Sjl139090
16351772Sjl139090
16361772Sjl139090 static int
IS_CE_ONLY(uint32_t cntl,int ptrl_error)16371772Sjl139090 IS_CE_ONLY(uint32_t cntl, int ptrl_error)
16381772Sjl139090 {
16391772Sjl139090 if (ptrl_error) {
16401772Sjl139090 return ((cntl & MAC_CNTL_PTRL_ERRS) == MAC_CNTL_PTRL_CE);
16411772Sjl139090 } else {
16421772Sjl139090 return ((cntl & MAC_CNTL_MI_ERRS) == MAC_CNTL_MI_CE);
16431772Sjl139090 }
16441772Sjl139090 }
16451772Sjl139090
16461772Sjl139090 void
mc_write_cntl(mc_opl_t * mcp,int bank,uint32_t value)16471772Sjl139090 mc_write_cntl(mc_opl_t *mcp, int bank, uint32_t value)
16481772Sjl139090 {
16492867Shyw int ebank = (IS_MIRROR(mcp, bank)) ? MIRROR_IDX(bank) : bank;
16502867Shyw
16512867Shyw if (mcp->mc_speedup_period[ebank] > 0)
16522214Sav145390 value |= mc_max_speed;
16532214Sav145390 else
16542214Sav145390 value |= mcp->mc_speed;
16551772Sjl139090 ST_MAC_REG(MAC_PTRL_CNTL(mcp, bank), value);
16561772Sjl139090 }
16571772Sjl139090
16581772Sjl139090 static void
mc_read_ptrl_reg(mc_opl_t * mcp,int bank,mc_flt_stat_t * flt_stat)16591772Sjl139090 mc_read_ptrl_reg(mc_opl_t *mcp, int bank, mc_flt_stat_t *flt_stat)
16601772Sjl139090 {
16611772Sjl139090 flt_stat->mf_cntl = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank)) &
16625080Swh31274 MAC_CNTL_PTRL_ERRS;
16631772Sjl139090 flt_stat->mf_err_add = LD_MAC_REG(MAC_PTRL_ERR_ADD(mcp, bank));
16641772Sjl139090 flt_stat->mf_err_log = LD_MAC_REG(MAC_PTRL_ERR_LOG(mcp, bank));
16651772Sjl139090 flt_stat->mf_flt_maddr.ma_bd = mcp->mc_board_num;
16663045Sav145390 flt_stat->mf_flt_maddr.ma_phys_bd = mcp->mc_phys_board_num;
16671772Sjl139090 flt_stat->mf_flt_maddr.ma_bank = bank;
16681772Sjl139090 flt_stat->mf_flt_maddr.ma_dimm_addr = flt_stat->mf_err_add;
16691772Sjl139090 }
16701772Sjl139090
16711772Sjl139090 static void
mc_read_mi_reg(mc_opl_t * mcp,int bank,mc_flt_stat_t * flt_stat)16721772Sjl139090 mc_read_mi_reg(mc_opl_t *mcp, int bank, mc_flt_stat_t *flt_stat)
16731772Sjl139090 {
16741772Sjl139090 uint32_t status, old_status;
16751772Sjl139090
16765080Swh31274 status = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank)) & MAC_CNTL_MI_ERRS;
16771772Sjl139090 old_status = 0;
16781772Sjl139090
16791772Sjl139090 /* we keep reading until the status is stable */
16801772Sjl139090 while (old_status != status) {
16811772Sjl139090 old_status = status;
16825080Swh31274 flt_stat->mf_err_add = LD_MAC_REG(MAC_MI_ERR_ADD(mcp, bank));
16835080Swh31274 flt_stat->mf_err_log = LD_MAC_REG(MAC_MI_ERR_LOG(mcp, bank));
16841772Sjl139090 status = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank)) &
16855080Swh31274 MAC_CNTL_MI_ERRS;
16861772Sjl139090 if (status == old_status) {
16871772Sjl139090 break;
16881772Sjl139090 }
16891772Sjl139090 }
16901772Sjl139090
16911772Sjl139090 flt_stat->mf_cntl = status;
16921772Sjl139090 flt_stat->mf_flt_maddr.ma_bd = mcp->mc_board_num;
16933045Sav145390 flt_stat->mf_flt_maddr.ma_phys_bd = mcp->mc_phys_board_num;
16941772Sjl139090 flt_stat->mf_flt_maddr.ma_bank = bank;
16951772Sjl139090 flt_stat->mf_flt_maddr.ma_dimm_addr = flt_stat->mf_err_add;
16961772Sjl139090 }
16971772Sjl139090
16981772Sjl139090
16991772Sjl139090 /*
17001772Sjl139090 * Error philosophy for mirror mode:
17011772Sjl139090 *
17021772Sjl139090 * PTRL (The error address for both banks are same, since ptrl stops if it
17031772Sjl139090 * detects error.)
17043152Sav145390 * - Compare error log CMPE.
17051772Sjl139090 *
17061772Sjl139090 * - UE-UE Report MUE. No rewrite.
17071772Sjl139090 *
17081772Sjl139090 * - UE-* UE-(CE/OK). Rewrite to scrub UE. Report SUE.
17091772Sjl139090 *
17101772Sjl139090 * - CE-* CE-(CE/OK). Scrub to determine if CE is permanent.
17111772Sjl139090 * If CE is permanent, inform SCF. Once for each
17121772Sjl139090 * Dimm. If CE becomes UE or CMPE, go back to above.
17131772Sjl139090 *
17141772Sjl139090 *
17151772Sjl139090 * MI (The error addresses for each bank are the same or different.)
17163152Sav145390 * - Compare error If addresses are the same. Just CMPE, so log CMPE.
17171772Sjl139090 * If addresses are different (this could happen
17183152Sav145390 * as a result of scrubbing. Report each separately.
17191772Sjl139090 * Only report error info on each side.
17201772Sjl139090 *
17211772Sjl139090 * - UE-UE Addresses are the same. Report MUE.
17221772Sjl139090 * Addresses are different. Report SUE on each bank.
17231772Sjl139090 * Rewrite to clear UE.
17241772Sjl139090 *
17251772Sjl139090 * - UE-* UE-(CE/OK)
17261772Sjl139090 * Rewrite to clear UE. Report SUE for the bank.
17271772Sjl139090 *
17281772Sjl139090 * - CE-* CE-(CE/OK). Scrub to determine if CE is permanent.
17291772Sjl139090 * If CE becomes UE or CMPE, go back to above.
17301772Sjl139090 *
17311772Sjl139090 */
17321772Sjl139090
17331772Sjl139090 static int
mc_process_error_mir(mc_opl_t * mcp,mc_aflt_t * mc_aflt,mc_flt_stat_t * flt_stat)17341772Sjl139090 mc_process_error_mir(mc_opl_t *mcp, mc_aflt_t *mc_aflt, mc_flt_stat_t *flt_stat)
17351772Sjl139090 {
17361772Sjl139090 int ptrl_error = mc_aflt->mflt_is_ptrl;
17371772Sjl139090 int i;
17381772Sjl139090 int rv = 0;
17395310Sdhain int bank;
17405310Sdhain int rewrite_timeout = 0;
17411772Sjl139090
17421772Sjl139090 MC_LOG("process mirror errors cntl[0] = %x, cntl[1] = %x\n",
17435080Swh31274 flt_stat[0].mf_cntl, flt_stat[1].mf_cntl);
17441772Sjl139090
17451772Sjl139090 if (ptrl_error) {
17465080Swh31274 if (((flt_stat[0].mf_cntl | flt_stat[1].mf_cntl) &
17475080Swh31274 MAC_CNTL_PTRL_ERRS) == 0)
17481772Sjl139090 return (0);
17491772Sjl139090 } else {
17505080Swh31274 if (((flt_stat[0].mf_cntl | flt_stat[1].mf_cntl) &
17515080Swh31274 MAC_CNTL_MI_ERRS) == 0)
17521772Sjl139090 return (0);
17531772Sjl139090 }
17541772Sjl139090
17551772Sjl139090 /*
17561772Sjl139090 * First we take care of the case of CE
17571772Sjl139090 * because they can become UE or CMPE
17581772Sjl139090 */
17591772Sjl139090 for (i = 0; i < 2; i++) {
17601772Sjl139090 if (IS_CE_ONLY(flt_stat[i].mf_cntl, ptrl_error)) {
17615310Sdhain bank = flt_stat[i].mf_flt_maddr.ma_bank;
17625310Sdhain MC_LOG("CE detected on bank %d\n", bank);
17635310Sdhain mc_scrub_ce(mcp, bank, &flt_stat[i], ptrl_error);
17645310Sdhain if (MC_REWRITE_ACTIVE(mcp, bank)) {
17655310Sdhain rewrite_timeout = 1;
17665310Sdhain }
17671772Sjl139090 rv = 1;
17681772Sjl139090 }
17691772Sjl139090 }
17701772Sjl139090
17715310Sdhain if (rewrite_timeout)
17725310Sdhain return (0);
17735310Sdhain
17741772Sjl139090 /* The above scrubbing can turn CE into UE or CMPE */
17751772Sjl139090
17761772Sjl139090 /*
17771772Sjl139090 * Now we distinguish two cases: same address or not
17781772Sjl139090 * the same address. It might seem more intuitive to
17791772Sjl139090 * distinguish PTRL v.s. MI error but it is more
17801772Sjl139090 * complicated that way.
17811772Sjl139090 */
17821772Sjl139090
17831772Sjl139090 if (flt_stat[0].mf_err_add == flt_stat[1].mf_err_add) {
17841772Sjl139090
17851772Sjl139090 if (IS_CMPE(flt_stat[0].mf_cntl, ptrl_error) ||
17861772Sjl139090 IS_CMPE(flt_stat[1].mf_cntl, ptrl_error)) {
17871772Sjl139090 flt_stat[0].mf_type = FLT_TYPE_CMPE;
17881772Sjl139090 flt_stat[1].mf_type = FLT_TYPE_CMPE;
17891772Sjl139090 mc_aflt->mflt_erpt_class = MC_OPL_CMPE;
17901772Sjl139090 mc_aflt->mflt_nflts = 2;
17911772Sjl139090 mc_aflt->mflt_stat[0] = &flt_stat[0];
17921772Sjl139090 mc_aflt->mflt_stat[1] = &flt_stat[1];
17931772Sjl139090 mc_aflt->mflt_pr = PR_UE;
17943152Sav145390 /*
17953152Sav145390 * Compare error is result of MAC internal error, so
17963152Sav145390 * simply log it instead of publishing an ereport. SCF
17973152Sav145390 * diagnoses all the MAC internal and its i/f error.
17983152Sav145390 */
17993152Sav145390 MC_LOG("cmpe error detected\n");
18001772Sjl139090 return (1);
18011772Sjl139090 }
18021772Sjl139090
18031772Sjl139090 if (IS_UE(flt_stat[0].mf_cntl, ptrl_error) &&
18045080Swh31274 IS_UE(flt_stat[1].mf_cntl, ptrl_error)) {
18051772Sjl139090 /* Both side are UE's */
18061772Sjl139090
18071772Sjl139090 MAC_SET_ERRLOG_INFO(&flt_stat[0]);
18081772Sjl139090 MAC_SET_ERRLOG_INFO(&flt_stat[1]);
18091772Sjl139090 MC_LOG("MUE detected\n");
18102214Sav145390 flt_stat[0].mf_type = FLT_TYPE_MUE;
18112214Sav145390 flt_stat[1].mf_type = FLT_TYPE_MUE;
18121772Sjl139090 mc_aflt->mflt_erpt_class = MC_OPL_MUE;
18131772Sjl139090 mc_aflt->mflt_nflts = 2;
18141772Sjl139090 mc_aflt->mflt_stat[0] = &flt_stat[0];
18151772Sjl139090 mc_aflt->mflt_stat[1] = &flt_stat[1];
18161772Sjl139090 mc_aflt->mflt_pr = PR_UE;
18171772Sjl139090 mc_err_drain(mc_aflt);
18181772Sjl139090 return (1);
18191772Sjl139090 }
18201772Sjl139090
18211772Sjl139090 /* Now the only case is UE/CE, UE/OK, or don't care */
18221772Sjl139090 for (i = 0; i < 2; i++) {
18235310Sdhain if (IS_UE(flt_stat[i].mf_cntl, ptrl_error)) {
18242214Sav145390
18252214Sav145390 /* rewrite can clear the one side UE error */
18262214Sav145390
18271772Sjl139090 if (IS_OK(flt_stat[i^1].mf_cntl, ptrl_error)) {
18281772Sjl139090 (void) do_rewrite(mcp,
18291772Sjl139090 flt_stat[i].mf_flt_maddr.ma_bank,
18305310Sdhain flt_stat[i].mf_flt_maddr.ma_dimm_addr, 0);
18311772Sjl139090 }
18321772Sjl139090 flt_stat[i].mf_type = FLT_TYPE_UE;
18331772Sjl139090 MAC_SET_ERRLOG_INFO(&flt_stat[i]);
18341772Sjl139090 mc_aflt->mflt_erpt_class = MC_OPL_SUE;
18351772Sjl139090 mc_aflt->mflt_stat[0] = &flt_stat[i];
18361772Sjl139090 mc_aflt->mflt_nflts = 1;
18371772Sjl139090 mc_aflt->mflt_pr = PR_MCE;
18381772Sjl139090 mc_err_drain(mc_aflt);
18391772Sjl139090 /* Once we hit a UE/CE or UE/OK case, done */
18401772Sjl139090 return (1);
18415310Sdhain }
18421772Sjl139090 }
18431772Sjl139090
18441772Sjl139090 } else {
18451772Sjl139090 /*
18461772Sjl139090 * addresses are different. That means errors
18471772Sjl139090 * on the 2 banks are not related at all.
18481772Sjl139090 */
18491772Sjl139090 for (i = 0; i < 2; i++) {
18505080Swh31274 if (IS_CMPE(flt_stat[i].mf_cntl, ptrl_error)) {
18515080Swh31274 flt_stat[i].mf_type = FLT_TYPE_CMPE;
18525080Swh31274 mc_aflt->mflt_erpt_class = MC_OPL_CMPE;
18535080Swh31274 mc_aflt->mflt_nflts = 1;
18545080Swh31274 mc_aflt->mflt_stat[0] = &flt_stat[i];
18555080Swh31274 mc_aflt->mflt_pr = PR_UE;
18565080Swh31274 /*
18575080Swh31274 * Compare error is result of MAC internal
18585080Swh31274 * error, so simply log it instead of
18595080Swh31274 * publishing an ereport. SCF diagnoses all
18605080Swh31274 * the MAC internal and its interface error.
18615080Swh31274 */
18625080Swh31274 MC_LOG("cmpe error detected\n");
18635080Swh31274 /* no more report on this bank */
18645080Swh31274 flt_stat[i].mf_cntl = 0;
18655080Swh31274 rv = 1;
18665080Swh31274 }
18671772Sjl139090 }
18681772Sjl139090
18692214Sav145390 /* rewrite can clear the one side UE error */
18702214Sav145390
18711772Sjl139090 for (i = 0; i < 2; i++) {
18725080Swh31274 if (IS_UE(flt_stat[i].mf_cntl, ptrl_error)) {
18735080Swh31274 (void) do_rewrite(mcp,
18745080Swh31274 flt_stat[i].mf_flt_maddr.ma_bank,
18755310Sdhain flt_stat[i].mf_flt_maddr.ma_dimm_addr,
18765310Sdhain 0);
18775080Swh31274 flt_stat[i].mf_type = FLT_TYPE_UE;
18785080Swh31274 MAC_SET_ERRLOG_INFO(&flt_stat[i]);
18795080Swh31274 mc_aflt->mflt_erpt_class = MC_OPL_SUE;
18805080Swh31274 mc_aflt->mflt_stat[0] = &flt_stat[i];
18815080Swh31274 mc_aflt->mflt_nflts = 1;
18825080Swh31274 mc_aflt->mflt_pr = PR_MCE;
18835080Swh31274 mc_err_drain(mc_aflt);
18845080Swh31274 rv = 1;
18855080Swh31274 }
18861772Sjl139090 }
18871772Sjl139090 }
18881772Sjl139090 return (rv);
18891772Sjl139090 }
18901772Sjl139090 static void
mc_error_handler_mir(mc_opl_t * mcp,int bank,mc_rsaddr_info_t * rsaddr)18912662Shyw mc_error_handler_mir(mc_opl_t *mcp, int bank, mc_rsaddr_info_t *rsaddr)
18921772Sjl139090 {
18931772Sjl139090 mc_aflt_t mc_aflt;
18941772Sjl139090 mc_flt_stat_t flt_stat[2], mi_flt_stat[2];
18952214Sav145390 int i;
18962214Sav145390 int mi_valid;
18972214Sav145390
18982662Shyw ASSERT(rsaddr);
18992662Shyw
19001772Sjl139090 bzero(&mc_aflt, sizeof (mc_aflt_t));
19011772Sjl139090 bzero(&flt_stat, 2 * sizeof (mc_flt_stat_t));
19021772Sjl139090 bzero(&mi_flt_stat, 2 * sizeof (mc_flt_stat_t));
19031772Sjl139090
19043373Sbm42561
19051772Sjl139090 mc_aflt.mflt_mcp = mcp;
19061772Sjl139090 mc_aflt.mflt_id = gethrtime();
19071772Sjl139090
19081772Sjl139090 /* Now read all the registers into flt_stat */
19091772Sjl139090
19102214Sav145390 for (i = 0; i < 2; i++) {
19112214Sav145390 MC_LOG("Reading registers of bank %d\n", bank);
19122214Sav145390 /* patrol registers */
19132214Sav145390 mc_read_ptrl_reg(mcp, bank, &flt_stat[i]);
19142214Sav145390
19152662Shyw /*
19162662Shyw * In mirror mode, it is possible that only one bank
19172662Shyw * may report the error. We need to check for it to
19182662Shyw * ensure we pick the right addr value for patrol restart.
19192662Shyw * Note that if both banks reported errors, we pick the
19202662Shyw * 2nd one. Both banks should reported the same error address.
19212662Shyw */
19222662Shyw if (flt_stat[i].mf_cntl & MAC_CNTL_PTRL_ERRS)
19232662Shyw rsaddr->mi_restartaddr = flt_stat[i].mf_flt_maddr;
19242214Sav145390
19252214Sav145390 MC_LOG("ptrl registers cntl %x add %x log %x\n",
19265080Swh31274 flt_stat[i].mf_cntl, flt_stat[i].mf_err_add,
19275080Swh31274 flt_stat[i].mf_err_log);
19282214Sav145390
19292214Sav145390 /* MI registers */
19302214Sav145390 mc_read_mi_reg(mcp, bank, &mi_flt_stat[i]);
19312214Sav145390
19322214Sav145390 MC_LOG("MI registers cntl %x add %x log %x\n",
19335080Swh31274 mi_flt_stat[i].mf_cntl, mi_flt_stat[i].mf_err_add,
19345080Swh31274 mi_flt_stat[i].mf_err_log);
19352214Sav145390
19362214Sav145390 bank = bank^1;
19372214Sav145390 }
19381772Sjl139090
19391772Sjl139090 /* clear errors once we read all the registers */
19405080Swh31274 MAC_CLEAR_ERRS(mcp, bank, (MAC_CNTL_PTRL_ERRS|MAC_CNTL_MI_ERRS));
19411772Sjl139090
19422214Sav145390 MAC_CLEAR_ERRS(mcp, bank ^ 1, (MAC_CNTL_PTRL_ERRS|MAC_CNTL_MI_ERRS));
19432214Sav145390
19442214Sav145390 /* Process MI errors first */
19452214Sav145390
19462214Sav145390 /* if not error mode, cntl1 is 0 */
19472214Sav145390 if ((mi_flt_stat[0].mf_err_add & MAC_ERR_ADD_INVALID) ||
19485080Swh31274 (mi_flt_stat[0].mf_err_log & MAC_ERR_LOG_INVALID))
19492214Sav145390 mi_flt_stat[0].mf_cntl = 0;
19502214Sav145390
19512214Sav145390 if ((mi_flt_stat[1].mf_err_add & MAC_ERR_ADD_INVALID) ||
19525080Swh31274 (mi_flt_stat[1].mf_err_log & MAC_ERR_LOG_INVALID))
19532214Sav145390 mi_flt_stat[1].mf_cntl = 0;
19542214Sav145390
19552214Sav145390 mc_aflt.mflt_is_ptrl = 0;
19562214Sav145390 mi_valid = mc_process_error_mir(mcp, &mc_aflt, &mi_flt_stat[0]);
19572214Sav145390
19582214Sav145390 if ((((flt_stat[0].mf_cntl & MAC_CNTL_PTRL_ERRS) >>
19595080Swh31274 MAC_CNTL_PTRL_ERR_SHIFT) == ((mi_flt_stat[0].mf_cntl &
19605080Swh31274 MAC_CNTL_MI_ERRS) >> MAC_CNTL_MI_ERR_SHIFT)) &&
19616693Swh31274 (flt_stat[0].mf_err_add ==
19626693Swh31274 ROUNDDOWN(mi_flt_stat[0].mf_err_add, MC_BOUND_BYTE)) &&
19635080Swh31274 (((flt_stat[1].mf_cntl & MAC_CNTL_PTRL_ERRS) >>
19645080Swh31274 MAC_CNTL_PTRL_ERR_SHIFT) == ((mi_flt_stat[1].mf_cntl &
19655080Swh31274 MAC_CNTL_MI_ERRS) >> MAC_CNTL_MI_ERR_SHIFT)) &&
19666693Swh31274 (flt_stat[1].mf_err_add ==
19676693Swh31274 ROUNDDOWN(mi_flt_stat[1].mf_err_add, MC_BOUND_BYTE))) {
19682214Sav145390 #ifdef DEBUG
19692214Sav145390 MC_LOG("discarding PTRL error because "
19702214Sav145390 "it is the same as MI\n");
19712214Sav145390 #endif
19722662Shyw rsaddr->mi_valid = mi_valid;
19732214Sav145390 return;
19742214Sav145390 }
19751772Sjl139090 /* if not error mode, cntl1 is 0 */
19761772Sjl139090 if ((flt_stat[0].mf_err_add & MAC_ERR_ADD_INVALID) ||
19775080Swh31274 (flt_stat[0].mf_err_log & MAC_ERR_LOG_INVALID))
19781772Sjl139090 flt_stat[0].mf_cntl = 0;
19791772Sjl139090
19801772Sjl139090 if ((flt_stat[1].mf_err_add & MAC_ERR_ADD_INVALID) ||
19815080Swh31274 (flt_stat[1].mf_err_log & MAC_ERR_LOG_INVALID))
19821772Sjl139090 flt_stat[1].mf_cntl = 0;
19831772Sjl139090
19841772Sjl139090 mc_aflt.mflt_is_ptrl = 1;
19852662Shyw rsaddr->mi_valid = mc_process_error_mir(mcp, &mc_aflt, &flt_stat[0]);
19861772Sjl139090 }
19871772Sjl139090 static int
mc_process_error(mc_opl_t * mcp,int bank,mc_aflt_t * mc_aflt,mc_flt_stat_t * flt_stat)19881772Sjl139090 mc_process_error(mc_opl_t *mcp, int bank, mc_aflt_t *mc_aflt,
19891772Sjl139090 mc_flt_stat_t *flt_stat)
19901772Sjl139090 {
19911772Sjl139090 int ptrl_error = mc_aflt->mflt_is_ptrl;
19921772Sjl139090 int rv = 0;
19931772Sjl139090
19941772Sjl139090 mc_aflt->mflt_erpt_class = NULL;
19951772Sjl139090 if (IS_UE(flt_stat->mf_cntl, ptrl_error)) {
19963152Sav145390 MC_LOG("UE detected\n");
19971772Sjl139090 flt_stat->mf_type = FLT_TYPE_UE;
19981772Sjl139090 mc_aflt->mflt_erpt_class = MC_OPL_UE;
19991772Sjl139090 mc_aflt->mflt_pr = PR_UE;
20001772Sjl139090 MAC_SET_ERRLOG_INFO(flt_stat);
20011772Sjl139090 rv = 1;
20021772Sjl139090 } else if (IS_CE(flt_stat->mf_cntl, ptrl_error)) {
20033152Sav145390 MC_LOG("CE detected\n");
20041772Sjl139090 MAC_SET_ERRLOG_INFO(flt_stat);
20051772Sjl139090
20063152Sav145390 /* Error type can change after scrubbing */
20071772Sjl139090 mc_scrub_ce(mcp, bank, flt_stat, ptrl_error);
20085310Sdhain if (MC_REWRITE_ACTIVE(mcp, bank)) {
20095310Sdhain return (0);
20105310Sdhain }
20111772Sjl139090
20125275Stsien if (flt_stat->mf_type == FLT_TYPE_INTERMITTENT_CE) {
20135275Stsien mc_aflt->mflt_erpt_class = MC_OPL_ICE;
20145275Stsien mc_aflt->mflt_pr = PR_MCE;
20155275Stsien } else if (flt_stat->mf_type == FLT_TYPE_PERMANENT_CE) {
20161772Sjl139090 mc_aflt->mflt_erpt_class = MC_OPL_CE;
20171772Sjl139090 mc_aflt->mflt_pr = PR_MCE;
20181772Sjl139090 } else if (flt_stat->mf_type == FLT_TYPE_UE) {
20191772Sjl139090 mc_aflt->mflt_erpt_class = MC_OPL_UE;
20201772Sjl139090 mc_aflt->mflt_pr = PR_UE;
20211772Sjl139090 }
20221772Sjl139090 rv = 1;
20231772Sjl139090 }
20245080Swh31274 MC_LOG("mc_process_error: fault type %x erpt %s\n", flt_stat->mf_type,
20255080Swh31274 mc_aflt->mflt_erpt_class);
20261772Sjl139090 if (mc_aflt->mflt_erpt_class) {
20271772Sjl139090 mc_aflt->mflt_stat[0] = flt_stat;
20281772Sjl139090 mc_aflt->mflt_nflts = 1;
20291772Sjl139090 mc_err_drain(mc_aflt);
20301772Sjl139090 }
20311772Sjl139090 return (rv);
20321772Sjl139090 }
20331772Sjl139090
20341772Sjl139090 static void
mc_error_handler(mc_opl_t * mcp,int bank,mc_rsaddr_info_t * rsaddr)20352662Shyw mc_error_handler(mc_opl_t *mcp, int bank, mc_rsaddr_info_t *rsaddr)
20361772Sjl139090 {
20371772Sjl139090 mc_aflt_t mc_aflt;
20381772Sjl139090 mc_flt_stat_t flt_stat, mi_flt_stat;
20392214Sav145390 int mi_valid;
20401772Sjl139090
20411772Sjl139090 bzero(&mc_aflt, sizeof (mc_aflt_t));
20421772Sjl139090 bzero(&flt_stat, sizeof (mc_flt_stat_t));
20431772Sjl139090 bzero(&mi_flt_stat, sizeof (mc_flt_stat_t));
20441772Sjl139090
20451772Sjl139090 mc_aflt.mflt_mcp = mcp;
20461772Sjl139090 mc_aflt.mflt_id = gethrtime();
20471772Sjl139090
20481772Sjl139090 /* patrol registers */
20491772Sjl139090 mc_read_ptrl_reg(mcp, bank, &flt_stat);
20501772Sjl139090
20512662Shyw ASSERT(rsaddr);
20522662Shyw rsaddr->mi_restartaddr = flt_stat.mf_flt_maddr;
20531772Sjl139090
20545080Swh31274 MC_LOG("ptrl registers cntl %x add %x log %x\n", flt_stat.mf_cntl,
20555080Swh31274 flt_stat.mf_err_add, flt_stat.mf_err_log);
20561772Sjl139090
20571772Sjl139090 /* MI registers */
20581772Sjl139090 mc_read_mi_reg(mcp, bank, &mi_flt_stat);
20591772Sjl139090
20602214Sav145390
20615080Swh31274 MC_LOG("MI registers cntl %x add %x log %x\n", mi_flt_stat.mf_cntl,
20625080Swh31274 mi_flt_stat.mf_err_add, mi_flt_stat.mf_err_log);
20631772Sjl139090
20641772Sjl139090 /* clear errors once we read all the registers */
20651772Sjl139090 MAC_CLEAR_ERRS(mcp, bank, (MAC_CNTL_PTRL_ERRS|MAC_CNTL_MI_ERRS));
20661772Sjl139090
20672214Sav145390 mc_aflt.mflt_is_ptrl = 0;
20682214Sav145390 if ((mi_flt_stat.mf_cntl & MAC_CNTL_MI_ERRS) &&
20695080Swh31274 ((mi_flt_stat.mf_err_add & MAC_ERR_ADD_INVALID) == 0) &&
20705080Swh31274 ((mi_flt_stat.mf_err_log & MAC_ERR_LOG_INVALID) == 0)) {
20712214Sav145390 mi_valid = mc_process_error(mcp, bank, &mc_aflt, &mi_flt_stat);
20722214Sav145390 }
20732214Sav145390
20742214Sav145390 if ((((flt_stat.mf_cntl & MAC_CNTL_PTRL_ERRS) >>
20755080Swh31274 MAC_CNTL_PTRL_ERR_SHIFT) == ((mi_flt_stat.mf_cntl &
20765080Swh31274 MAC_CNTL_MI_ERRS) >> MAC_CNTL_MI_ERR_SHIFT)) &&
20776693Swh31274 (flt_stat.mf_err_add ==
20786693Swh31274 ROUNDDOWN(mi_flt_stat.mf_err_add, MC_BOUND_BYTE))) {
20792214Sav145390 #ifdef DEBUG
20802214Sav145390 MC_LOG("discarding PTRL error because "
20812214Sav145390 "it is the same as MI\n");
20822214Sav145390 #endif
20832662Shyw rsaddr->mi_valid = mi_valid;
20842214Sav145390 return;
20852214Sav145390 }
20862214Sav145390
20871772Sjl139090 mc_aflt.mflt_is_ptrl = 1;
20881772Sjl139090 if ((flt_stat.mf_cntl & MAC_CNTL_PTRL_ERRS) &&
20895080Swh31274 ((flt_stat.mf_err_add & MAC_ERR_ADD_INVALID) == 0) &&
20905080Swh31274 ((flt_stat.mf_err_log & MAC_ERR_LOG_INVALID) == 0)) {
20915080Swh31274 rsaddr->mi_valid = mc_process_error(mcp, bank, &mc_aflt,
20925080Swh31274 &flt_stat);
20931772Sjl139090 }
20941772Sjl139090 }
20951772Sjl139090 /*
20961772Sjl139090 * memory patrol error handling algorithm:
20971772Sjl139090 * timeout() is used to do periodic polling
20981772Sjl139090 * This is the flow chart.
20991772Sjl139090 * timeout ->
21001772Sjl139090 * mc_check_errors()
21011772Sjl139090 * if memory bank is installed, read the status register
21021772Sjl139090 * if any error bit is set,
21031772Sjl139090 * -> mc_error_handler()
21043152Sav145390 * -> read all error registers
21051772Sjl139090 * -> mc_process_error()
21061772Sjl139090 * determine error type
21071772Sjl139090 * rewrite to clear error or scrub to determine CE type
21081772Sjl139090 * inform SCF on permanent CE
21091772Sjl139090 * -> mc_err_drain
21101772Sjl139090 * page offline processing
21111772Sjl139090 * -> mc_ereport_post()
21121772Sjl139090 */
21131772Sjl139090
21141772Sjl139090 static void
mc_process_rewrite(mc_opl_t * mcp,int bank)21155310Sdhain mc_process_rewrite(mc_opl_t *mcp, int bank)
21165310Sdhain {
21175310Sdhain uint32_t rew_addr, cntl;
21185310Sdhain mc_retry_info_t *retry;
21195310Sdhain struct mc_bank *bankp;
21205310Sdhain
21215310Sdhain bankp = &(mcp->mc_bank[bank]);
21225310Sdhain retry = bankp->mcb_active;
21235310Sdhain if (retry == NULL)
21245310Sdhain return;
21255310Sdhain
21265310Sdhain if (retry->ri_state <= RETRY_STATE_ACTIVE) {
21275310Sdhain cntl = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank));
21285310Sdhain if (cntl & MAC_CNTL_PTRL_STATUS)
21295310Sdhain return;
21305310Sdhain rew_addr = retry->ri_addr;
21315310Sdhain ST_MAC_REG(MAC_REWRITE_ADD(mcp, bank), rew_addr);
21325310Sdhain MAC_REW_REQ(mcp, bank);
21335310Sdhain
21345310Sdhain retry->ri_state = RETRY_STATE_REWRITE;
21355310Sdhain }
21365310Sdhain
21375310Sdhain cntl = ldphysio(MAC_PTRL_CNTL(mcp, bank));
21385310Sdhain
21395310Sdhain if (cntl & MAC_CNTL_REW_END) {
21405310Sdhain MAC_CLEAR_ERRS(mcp, bank,
21415310Sdhain MAC_CNTL_REW_ERRS);
21425310Sdhain mc_clear_rewrite(mcp, bank);
21435310Sdhain } else {
21445310Sdhain /*
21455310Sdhain * If the rewrite does not complete in
21465310Sdhain * 1 hour, we have to consider this a HW
21475310Sdhain * failure. However, there is no recovery
21485310Sdhain * mechanism. The only thing we can do
21495310Sdhain * to to print a warning message to the
21505310Sdhain * console. We continue to increment the
21515310Sdhain * counter but we only print the message
21525310Sdhain * once. It will take the counter a long
21535310Sdhain * time to wrap around and the user might
21545310Sdhain * see a second message. In practice,
21555310Sdhain * we have never hit this condition but
21565310Sdhain * we have to keep the code here just in case.
21575310Sdhain */
21585310Sdhain if (++mcp->mc_bank[bank].mcb_rewrite_count
21595310Sdhain == mc_max_rewrite_retry) {
21605310Sdhain cmn_err(CE_WARN, "Memory patrol feature is"
21615310Sdhain " partly suspended on /LSB%d/B%d"
21625310Sdhain " due to heavy memory load,"
21635310Sdhain " and it will restart"
21645310Sdhain " automatically.\n", mcp->mc_board_num,
21655310Sdhain bank);
21665310Sdhain }
21675310Sdhain }
21685310Sdhain }
21695310Sdhain
21705310Sdhain static void
mc_check_errors_func(mc_opl_t * mcp)21711772Sjl139090 mc_check_errors_func(mc_opl_t *mcp)
21721772Sjl139090 {
21732662Shyw mc_rsaddr_info_t rsaddr_info;
21741772Sjl139090 int i, error_count = 0;
21751772Sjl139090 uint32_t stat, cntl;
21762214Sav145390 int running;
21772494Shyw int wrapped;
21782867Shyw int ebk;
21791772Sjl139090
21801772Sjl139090 /*
21811772Sjl139090 * scan errors.
21821772Sjl139090 */
21832214Sav145390 if (mcp->mc_status & MC_MEMORYLESS)
21842214Sav145390 return;
21852214Sav145390
21861772Sjl139090 for (i = 0; i < BANKNUM_PER_SB; i++) {
21871772Sjl139090 if (mcp->mc_bank[i].mcb_status & BANK_INSTALLED) {
21885310Sdhain if (MC_REWRITE_ACTIVE(mcp, i)) {
21895310Sdhain mc_process_rewrite(mcp, i);
21905310Sdhain }
21911772Sjl139090 stat = ldphysio(MAC_PTRL_STAT(mcp, i));
21921772Sjl139090 cntl = ldphysio(MAC_PTRL_CNTL(mcp, i));
21932214Sav145390 running = cntl & MAC_CNTL_PTRL_START;
21942494Shyw wrapped = cntl & MAC_CNTL_PTRL_ADD_MAX;
21952494Shyw
21962867Shyw /* Compute the effective bank idx */
21972867Shyw ebk = (IS_MIRROR(mcp, i)) ? MIRROR_IDX(i) : i;
21982867Shyw
21992494Shyw if (mc_debug_show_all || stat) {
22002494Shyw MC_LOG("/LSB%d/B%d stat %x cntl %x\n",
22015080Swh31274 mcp->mc_board_num, i, stat, cntl);
22022494Shyw }
22032494Shyw
22042494Shyw /*
22052494Shyw * Update stats and reset flag if the HW patrol
22062494Shyw * wrapped around in its scan.
22072494Shyw */
22082494Shyw if (wrapped) {
22091772Sjl139090 MAC_CLEAR_MAX(mcp, i);
22102867Shyw mcp->mc_period[ebk]++;
22116297Sjl139090 if (IS_MIRROR(mcp, i)) {
22125080Swh31274 MC_LOG("mirror mc period %ld on "
22135080Swh31274 "/LSB%d/B%d\n", mcp->mc_period[ebk],
22145080Swh31274 mcp->mc_board_num, i);
22156297Sjl139090 } else {
22165080Swh31274 MC_LOG("mc period %ld on "
22175080Swh31274 "/LSB%d/B%d\n", mcp->mc_period[ebk],
22185080Swh31274 mcp->mc_board_num, i);
22192867Shyw }
22202494Shyw }
22212494Shyw
22222494Shyw if (running) {
22232494Shyw /*
22242494Shyw * Mac patrol HW is still running.
22252494Shyw * Normally when an error is detected,
22262494Shyw * the HW patrol will stop so that we
22272494Shyw * can collect error data for reporting.
22282494Shyw * Certain errors (MI errors) detected may not
22292494Shyw * cause the HW patrol to stop which is a
22302494Shyw * problem since we cannot read error data while
22312494Shyw * the HW patrol is running. SW is not allowed
22322494Shyw * to stop the HW patrol while it is running
22332494Shyw * as it may cause HW inconsistency. This is
22342494Shyw * described in a HW errata.
22352494Shyw * In situations where we detected errors
22362494Shyw * that may not cause the HW patrol to stop.
22372494Shyw * We speed up the HW patrol scanning in
22382494Shyw * the hope that it will find the 'real' PTRL
22392494Shyw * errors associated with the previous errors
22402494Shyw * causing the HW to finally stop so that we
22412494Shyw * can do the reporting.
22422494Shyw */
22432494Shyw /*
22442494Shyw * Check to see if we did speed up
22452494Shyw * the HW patrol due to previous errors
22462494Shyw * detected that did not cause the patrol
22472494Shyw * to stop. We only do it if HW patrol scan
22482494Shyw * wrapped (counted as completing a 'period').
22492494Shyw */
22502867Shyw if (mcp->mc_speedup_period[ebk] > 0) {
22515080Swh31274 if (wrapped &&
22525080Swh31274 (--mcp->mc_speedup_period[ebk] ==
22535080Swh31274 0)) {
22545080Swh31274 /*
22555080Swh31274 * We did try to speed up.
22565080Swh31274 * The speed up period has
22575080Swh31274 * expired and the HW patrol
22585080Swh31274 * is still running. The
22595080Swh31274 * errors must be intermittent.
22605080Swh31274 * We have no choice but to
22615080Swh31274 * ignore them, reset the scan
22625080Swh31274 * speed to normal and clear
22635080Swh31274 * the MI error bits. For
22645080Swh31274 * mirror mode, we need to
22655080Swh31274 * clear errors on both banks.
22665080Swh31274 */
22675080Swh31274 MC_LOG("Clearing MI errors\n");
22685080Swh31274 MAC_CLEAR_ERRS(mcp, i,
22695080Swh31274 MAC_CNTL_MI_ERRS);
22705080Swh31274
22715080Swh31274 if (IS_MIRROR(mcp, i)) {
22725080Swh31274 MC_LOG("Clearing "
22735080Swh31274 "Mirror MI errs\n");
22745080Swh31274 MAC_CLEAR_ERRS(mcp,
22755080Swh31274 i^1,
22765080Swh31274 MAC_CNTL_MI_ERRS);
22775080Swh31274 }
22782867Shyw }
22792494Shyw } else if (stat & MAC_STAT_MI_ERRS) {
22802494Shyw /*
22812494Shyw * MI errors detected but we cannot
22822494Shyw * report them since the HW patrol
22832494Shyw * is still running.
22842494Shyw * We will attempt to speed up the
22852494Shyw * scanning and hopefully the HW
22862494Shyw * can detect PRTL errors at the same
22872494Shyw * location that cause the HW patrol
22882494Shyw * to stop.
22892494Shyw */
22902867Shyw mcp->mc_speedup_period[ebk] = 2;
22912214Sav145390 MAC_CMD(mcp, i, 0);
22922214Sav145390 }
22932494Shyw } else if (stat & (MAC_STAT_PTRL_ERRS |
22942494Shyw MAC_STAT_MI_ERRS)) {
22952494Shyw /*
22962494Shyw * HW Patrol has stopped and we found errors.
22972494Shyw * Proceed to collect and report error info.
22982494Shyw */
22992867Shyw mcp->mc_speedup_period[ebk] = 0;
23002662Shyw rsaddr_info.mi_valid = 0;
23012662Shyw rsaddr_info.mi_injectrestart = 0;
23022662Shyw if (IS_MIRROR(mcp, i)) {
23035080Swh31274 mc_error_handler_mir(mcp, i,
23045080Swh31274 &rsaddr_info);
23052662Shyw } else {
23065080Swh31274 mc_error_handler(mcp, i, &rsaddr_info);
23072662Shyw }
23082494Shyw
23092494Shyw error_count++;
231011311SSurya.Prakki@Sun.COM (void) restart_patrol(mcp, i, &rsaddr_info);
23111772Sjl139090 } else {
23122494Shyw /*
23132494Shyw * HW patrol scan has apparently stopped
23142494Shyw * but no errors detected/flagged.
23152494Shyw * Restart the HW patrol just to be sure.
23162867Shyw * In mirror mode, the odd bank might have
23172867Shyw * reported errors that caused the patrol to
23182867Shyw * stop. We'll defer the restart to the odd
23192867Shyw * bank in this case.
23202494Shyw */
23212867Shyw if (!IS_MIRROR(mcp, i) || (i & 0x1))
232211311SSurya.Prakki@Sun.COM (void) restart_patrol(mcp, i, NULL);
23231772Sjl139090 }
23241772Sjl139090 }
23251772Sjl139090 }
23261772Sjl139090 if (error_count > 0)
23271772Sjl139090 mcp->mc_last_error += error_count;
23281772Sjl139090 else
23291772Sjl139090 mcp->mc_last_error = 0;
23301772Sjl139090 }
23311772Sjl139090
23322214Sav145390 /*
23332214Sav145390 * mc_polling -- Check errors for only one instance,
23342214Sav145390 * but process errors for all instances to make sure we drain the errors
23352214Sav145390 * faster than they can be accumulated.
23362214Sav145390 *
23372214Sav145390 * Polling on each board should be done only once per each
23382214Sav145390 * mc_patrol_interval_sec. This is equivalent to setting mc_tick_left
23392214Sav145390 * to OPL_MAX_BOARDS and decrement by 1 on each timeout.
23402214Sav145390 * Once mc_tick_left becomes negative, the board becomes a candidate
23412214Sav145390 * for polling because it has waited for at least
23422214Sav145390 * mc_patrol_interval_sec's long. If mc_timeout_period is calculated
23433152Sav145390 * differently, this has to be updated accordingly.
23442214Sav145390 */
23451772Sjl139090
23461772Sjl139090 static void
mc_polling(void)23472214Sav145390 mc_polling(void)
23481772Sjl139090 {
23492214Sav145390 int i, scan_error;
23502214Sav145390 mc_opl_t *mcp;
23512214Sav145390
23522214Sav145390
23532214Sav145390 scan_error = 1;
23542214Sav145390 for (i = 0; i < OPL_MAX_BOARDS; i++) {
23552214Sav145390 mutex_enter(&mcmutex);
23562214Sav145390 if ((mcp = mc_instances[i]) == NULL) {
23572214Sav145390 mutex_exit(&mcmutex);
23582214Sav145390 continue;
23592214Sav145390 }
23602214Sav145390 mutex_enter(&mcp->mc_lock);
23612214Sav145390 mutex_exit(&mcmutex);
23622662Shyw if (!(mcp->mc_status & MC_POLL_RUNNING)) {
23632662Shyw mutex_exit(&mcp->mc_lock);
23642662Shyw continue;
23652662Shyw }
23662214Sav145390 if (scan_error && mcp->mc_tick_left <= 0) {
23672214Sav145390 mc_check_errors_func((void *)mcp);
23682214Sav145390 mcp->mc_tick_left = OPL_MAX_BOARDS;
23692214Sav145390 scan_error = 0;
23702214Sav145390 } else {
23712214Sav145390 mcp->mc_tick_left--;
23722214Sav145390 }
23732214Sav145390 mc_process_scf_log(mcp);
23742214Sav145390 mutex_exit(&mcp->mc_lock);
23751772Sjl139090 }
23761772Sjl139090 }
23771772Sjl139090
23781772Sjl139090 static void
get_ptrl_start_address(mc_opl_t * mcp,int bank,mc_addr_t * maddr)23791772Sjl139090 get_ptrl_start_address(mc_opl_t *mcp, int bank, mc_addr_t *maddr)
23801772Sjl139090 {
23811772Sjl139090 maddr->ma_bd = mcp->mc_board_num;
23821772Sjl139090 maddr->ma_bank = bank;
23831772Sjl139090 maddr->ma_dimm_addr = 0;
23841772Sjl139090 }
23851772Sjl139090
23861772Sjl139090 typedef struct mc_mem_range {
23871772Sjl139090 uint64_t addr;
23881772Sjl139090 uint64_t size;
23891772Sjl139090 } mc_mem_range_t;
23901772Sjl139090
23911772Sjl139090 static int
get_base_address(mc_opl_t * mcp)23921772Sjl139090 get_base_address(mc_opl_t *mcp)
23931772Sjl139090 {
23941772Sjl139090 mc_mem_range_t *mem_range;
23951772Sjl139090 int len;
23961772Sjl139090
23971772Sjl139090 if (ddi_getlongprop(DDI_DEV_T_ANY, mcp->mc_dip, DDI_PROP_DONTPASS,
23985080Swh31274 "sb-mem-ranges", (caddr_t)&mem_range, &len) != DDI_SUCCESS) {
23991772Sjl139090 return (DDI_FAILURE);
24001772Sjl139090 }
24011772Sjl139090
24021772Sjl139090 mcp->mc_start_address = mem_range->addr;
24031772Sjl139090 mcp->mc_size = mem_range->size;
24041772Sjl139090
24051772Sjl139090 kmem_free(mem_range, len);
24061772Sjl139090 return (DDI_SUCCESS);
24071772Sjl139090 }
24081772Sjl139090
24091772Sjl139090 struct mc_addr_spec {
24101772Sjl139090 uint32_t bank;
24111772Sjl139090 uint32_t phys_hi;
24121772Sjl139090 uint32_t phys_lo;
24131772Sjl139090 };
24141772Sjl139090
24151772Sjl139090 #define REGS_PA(m, i) ((((uint64_t)m[i].phys_hi)<<32) | m[i].phys_lo)
24161772Sjl139090
24171772Sjl139090 static char *mc_tbl_name[] = {
24181772Sjl139090 "cs0-mc-pa-trans-table",
24191772Sjl139090 "cs1-mc-pa-trans-table"
24201772Sjl139090 };
24211772Sjl139090
24222662Shyw /*
24232662Shyw * This routine performs a rangecheck for a given PA
24242662Shyw * to see if it belongs to the memory range for this board.
24252662Shyw * Return 1 if it is valid (within the range) and 0 otherwise
24262662Shyw */
24271772Sjl139090 static int
mc_rangecheck_pa(mc_opl_t * mcp,uint64_t pa)24282662Shyw mc_rangecheck_pa(mc_opl_t *mcp, uint64_t pa)
24291772Sjl139090 {
24305080Swh31274 if ((pa < mcp->mc_start_address) || (mcp->mc_start_address +
24315080Swh31274 mcp->mc_size <= pa))
24322662Shyw return (0);
24332662Shyw else
24342662Shyw return (1);
24351772Sjl139090 }
24361772Sjl139090
24371772Sjl139090 static void
mc_memlist_delete(struct memlist * mlist)24381772Sjl139090 mc_memlist_delete(struct memlist *mlist)
24391772Sjl139090 {
24401772Sjl139090 struct memlist *ml;
24411772Sjl139090
24421772Sjl139090 for (ml = mlist; ml; ml = mlist) {
244311474SJonathan.Adams@Sun.COM mlist = ml->ml_next;
24441772Sjl139090 kmem_free(ml, sizeof (struct memlist));
24451772Sjl139090 }
24461772Sjl139090 }
24471772Sjl139090
24481772Sjl139090 static struct memlist *
mc_memlist_dup(struct memlist * mlist)24491772Sjl139090 mc_memlist_dup(struct memlist *mlist)
24501772Sjl139090 {
24511772Sjl139090 struct memlist *hl = NULL, *tl, **mlp;
24521772Sjl139090
24531772Sjl139090 if (mlist == NULL)
24541772Sjl139090 return (NULL);
24551772Sjl139090
24561772Sjl139090 mlp = &hl;
24571772Sjl139090 tl = *mlp;
245811474SJonathan.Adams@Sun.COM for (; mlist; mlist = mlist->ml_next) {
24591772Sjl139090 *mlp = kmem_alloc(sizeof (struct memlist), KM_SLEEP);
246011474SJonathan.Adams@Sun.COM (*mlp)->ml_address = mlist->ml_address;
246111474SJonathan.Adams@Sun.COM (*mlp)->ml_size = mlist->ml_size;
246211474SJonathan.Adams@Sun.COM (*mlp)->ml_prev = tl;
24631772Sjl139090 tl = *mlp;
246411474SJonathan.Adams@Sun.COM mlp = &((*mlp)->ml_next);
24651772Sjl139090 }
24661772Sjl139090 *mlp = NULL;
24671772Sjl139090
24681772Sjl139090 return (hl);
24691772Sjl139090 }
24701772Sjl139090
24711772Sjl139090
24721772Sjl139090 static struct memlist *
mc_memlist_del_span(struct memlist * mlist,uint64_t base,uint64_t len)24731772Sjl139090 mc_memlist_del_span(struct memlist *mlist, uint64_t base, uint64_t len)
24741772Sjl139090 {
24751772Sjl139090 uint64_t end;
24761772Sjl139090 struct memlist *ml, *tl, *nlp;
24771772Sjl139090
24781772Sjl139090 if (mlist == NULL)
24791772Sjl139090 return (NULL);
24801772Sjl139090
24811772Sjl139090 end = base + len;
248211474SJonathan.Adams@Sun.COM if ((end <= mlist->ml_address) || (base == end))
24831772Sjl139090 return (mlist);
24841772Sjl139090
24851772Sjl139090 for (tl = ml = mlist; ml; tl = ml, ml = nlp) {
24861772Sjl139090 uint64_t mend;
24871772Sjl139090
248811474SJonathan.Adams@Sun.COM nlp = ml->ml_next;
248911474SJonathan.Adams@Sun.COM
249011474SJonathan.Adams@Sun.COM if (end <= ml->ml_address)
24911772Sjl139090 break;
24921772Sjl139090
249311474SJonathan.Adams@Sun.COM mend = ml->ml_address + ml->ml_size;
24941772Sjl139090 if (base < mend) {
249511474SJonathan.Adams@Sun.COM if (base <= ml->ml_address) {
249611474SJonathan.Adams@Sun.COM ml->ml_address = end;
24971772Sjl139090 if (end >= mend)
249811474SJonathan.Adams@Sun.COM ml->ml_size = 0ull;
24991772Sjl139090 else
250011474SJonathan.Adams@Sun.COM ml->ml_size = mend - ml->ml_address;
25011772Sjl139090 } else {
250211474SJonathan.Adams@Sun.COM ml->ml_size = base - ml->ml_address;
25031772Sjl139090 if (end < mend) {
25041772Sjl139090 struct memlist *nl;
25051772Sjl139090 /*
25061772Sjl139090 * splitting an memlist entry.
25071772Sjl139090 */
25081772Sjl139090 nl = kmem_alloc(sizeof (struct memlist),
25095080Swh31274 KM_SLEEP);
251011474SJonathan.Adams@Sun.COM nl->ml_address = end;
251111474SJonathan.Adams@Sun.COM nl->ml_size = mend - nl->ml_address;
251211474SJonathan.Adams@Sun.COM if ((nl->ml_next = nlp) != NULL)
251311474SJonathan.Adams@Sun.COM nlp->ml_prev = nl;
251411474SJonathan.Adams@Sun.COM nl->ml_prev = ml;
251511474SJonathan.Adams@Sun.COM ml->ml_next = nl;
25161772Sjl139090 nlp = nl;
25171772Sjl139090 }
25181772Sjl139090 }
251911474SJonathan.Adams@Sun.COM if (ml->ml_size == 0ull) {
25201772Sjl139090 if (ml == mlist) {
25211772Sjl139090 if ((mlist = nlp) != NULL)
252211474SJonathan.Adams@Sun.COM nlp->ml_prev = NULL;
25231772Sjl139090 kmem_free(ml, sizeof (struct memlist));
25241772Sjl139090 if (mlist == NULL)
25251772Sjl139090 break;
25261772Sjl139090 ml = nlp;
25271772Sjl139090 } else {
252811474SJonathan.Adams@Sun.COM if ((tl->ml_next = nlp) != NULL)
252911474SJonathan.Adams@Sun.COM nlp->ml_prev = tl;
25301772Sjl139090 kmem_free(ml, sizeof (struct memlist));
25311772Sjl139090 ml = tl;
25321772Sjl139090 }
25331772Sjl139090 }
25341772Sjl139090 }
25351772Sjl139090 }
25361772Sjl139090
25371772Sjl139090 return (mlist);
25381772Sjl139090 }
25391772Sjl139090
25401772Sjl139090 static void
mc_get_mlist(mc_opl_t * mcp)25411772Sjl139090 mc_get_mlist(mc_opl_t *mcp)
25421772Sjl139090 {
25431772Sjl139090 struct memlist *mlist;
25441772Sjl139090
25451772Sjl139090 memlist_read_lock();
25461772Sjl139090 mlist = mc_memlist_dup(phys_install);
25471772Sjl139090 memlist_read_unlock();
25481772Sjl139090
25491772Sjl139090 if (mlist) {
25501772Sjl139090 mlist = mc_memlist_del_span(mlist, 0ull, mcp->mc_start_address);
25511772Sjl139090 }
25521772Sjl139090
25531772Sjl139090 if (mlist) {
25541772Sjl139090 uint64_t startpa, endpa;
25551772Sjl139090
25561772Sjl139090 startpa = mcp->mc_start_address + mcp->mc_size;
25571772Sjl139090 endpa = ptob(physmax + 1);
25581772Sjl139090 if (endpa > startpa) {
25595080Swh31274 mlist = mc_memlist_del_span(mlist, startpa,
25605080Swh31274 endpa - startpa);
25611772Sjl139090 }
25621772Sjl139090 }
25631772Sjl139090
25641772Sjl139090 if (mlist) {
25651772Sjl139090 mcp->mlist = mlist;
25661772Sjl139090 }
25671772Sjl139090 }
25681772Sjl139090
25691772Sjl139090 int
mc_board_add(mc_opl_t * mcp)25701772Sjl139090 mc_board_add(mc_opl_t *mcp)
25711772Sjl139090 {
25721772Sjl139090 struct mc_addr_spec *macaddr;
25732214Sav145390 cs_status_t *cs_status;
25742214Sav145390 int len, len1, i, bk, cc;
25752662Shyw mc_rsaddr_info_t rsaddr;
25761772Sjl139090 uint32_t mirr;
25772214Sav145390 int nbanks = 0;
25782214Sav145390 uint64_t nbytes = 0;
25795080Swh31274 int mirror_mode = 0;
25805080Swh31274 int ret;
25811772Sjl139090
25821772Sjl139090 /*
25831772Sjl139090 * Get configurations from "pseudo-mc" node which includes:
25841772Sjl139090 * board# : LSB number
25851772Sjl139090 * mac-addr : physical base address of MAC registers
25861772Sjl139090 * csX-mac-pa-trans-table: translation table from DIMM address
25871772Sjl139090 * to physical address or vice versa.
25881772Sjl139090 */
25891772Sjl139090 mcp->mc_board_num = (int)ddi_getprop(DDI_DEV_T_ANY, mcp->mc_dip,
25905080Swh31274 DDI_PROP_DONTPASS, "board#", -1);
25911772Sjl139090
25922214Sav145390 if (mcp->mc_board_num == -1) {
25932214Sav145390 return (DDI_FAILURE);
25942214Sav145390 }
25952214Sav145390
25961772Sjl139090 /*
25971772Sjl139090 * Get start address in this CAB. It can be gotten from
25981772Sjl139090 * "sb-mem-ranges" property.
25991772Sjl139090 */
26001772Sjl139090
26011772Sjl139090 if (get_base_address(mcp) == DDI_FAILURE) {
26021772Sjl139090 return (DDI_FAILURE);
26031772Sjl139090 }
26041772Sjl139090 /* get mac-pa trans tables */
26051772Sjl139090 for (i = 0; i < MC_TT_CS; i++) {
26061772Sjl139090 len = MC_TT_ENTRIES;
26071772Sjl139090 cc = ddi_getlongprop_buf(DDI_DEV_T_ANY, mcp->mc_dip,
26085080Swh31274 DDI_PROP_DONTPASS, mc_tbl_name[i],
26095080Swh31274 (caddr_t)mcp->mc_trans_table[i], &len);
26101772Sjl139090
26111772Sjl139090 if (cc != DDI_SUCCESS) {
26121772Sjl139090 bzero(mcp->mc_trans_table[i], MC_TT_ENTRIES);
26131772Sjl139090 }
26141772Sjl139090 }
26151772Sjl139090 mcp->mlist = NULL;
26161772Sjl139090
26171772Sjl139090 mc_get_mlist(mcp);
26181772Sjl139090
26191772Sjl139090 /* initialize bank informations */
26201772Sjl139090 cc = ddi_getlongprop(DDI_DEV_T_ANY, mcp->mc_dip, DDI_PROP_DONTPASS,
26215080Swh31274 "mc-addr", (caddr_t)&macaddr, &len);
26221772Sjl139090 if (cc != DDI_SUCCESS) {
26231772Sjl139090 cmn_err(CE_WARN, "Cannot get mc-addr. err=%d\n", cc);
26242214Sav145390 return (DDI_FAILURE);
26252214Sav145390 }
26262214Sav145390
26272214Sav145390 cc = ddi_getlongprop(DDI_DEV_T_ANY, mcp->mc_dip, DDI_PROP_DONTPASS,
26285080Swh31274 "cs-status", (caddr_t)&cs_status, &len1);
26292214Sav145390
26302214Sav145390 if (cc != DDI_SUCCESS) {
26312214Sav145390 if (len > 0)
26322214Sav145390 kmem_free(macaddr, len);
26332214Sav145390 cmn_err(CE_WARN, "Cannot get cs-status. err=%d\n", cc);
26341772Sjl139090 return (DDI_FAILURE);
26351772Sjl139090 }
26363045Sav145390 /* get the physical board number for a given logical board number */
26373045Sav145390 mcp->mc_phys_board_num = mc_opl_get_physical_board(mcp->mc_board_num);
26383045Sav145390
26393045Sav145390 if (mcp->mc_phys_board_num < 0) {
26403045Sav145390 if (len > 0)
26413045Sav145390 kmem_free(macaddr, len);
26423045Sav145390 cmn_err(CE_WARN, "Unable to obtain the physical board number");
26433045Sav145390 return (DDI_FAILURE);
26443045Sav145390 }
26451772Sjl139090
26462214Sav145390 mutex_init(&mcp->mc_lock, NULL, MUTEX_DRIVER, NULL);
26472214Sav145390
26482214Sav145390 for (i = 0; i < len1 / sizeof (cs_status_t); i++) {
26492214Sav145390 nbytes += ((uint64_t)cs_status[i].cs_avail_hi << 32) |
26505080Swh31274 ((uint64_t)cs_status[i].cs_avail_low);
26512214Sav145390 }
26522214Sav145390 if (len1 > 0)
26532214Sav145390 kmem_free(cs_status, len1);
26542214Sav145390 nbanks = len / sizeof (struct mc_addr_spec);
26552214Sav145390
26562214Sav145390 if (nbanks > 0)
26572214Sav145390 nbytes /= nbanks;
26582214Sav145390 else {
26592214Sav145390 /* No need to free macaddr because len must be 0 */
26602214Sav145390 mcp->mc_status |= MC_MEMORYLESS;
26612214Sav145390 return (DDI_SUCCESS);
26622214Sav145390 }
26632214Sav145390
26642214Sav145390 for (i = 0; i < BANKNUM_PER_SB; i++) {
26652214Sav145390 mcp->mc_scf_retry[i] = 0;
26662214Sav145390 mcp->mc_period[i] = 0;
26672214Sav145390 mcp->mc_speedup_period[i] = 0;
26682214Sav145390 }
26692214Sav145390
26702214Sav145390 /*
26712214Sav145390 * Get the memory size here. Let it be B (bytes).
26722214Sav145390 * Let T be the time in u.s. to scan 64 bytes.
26732214Sav145390 * If we want to complete 1 round of scanning in P seconds.
26742214Sav145390 *
26752214Sav145390 * B * T * 10^(-6) = P
26762214Sav145390 * ---------------
26772214Sav145390 * 64
26782214Sav145390 *
26792214Sav145390 * T = P * 64 * 10^6
26802214Sav145390 * -------------
26812214Sav145390 * B
26822214Sav145390 *
26832214Sav145390 * = P * 64 * 10^6
26842214Sav145390 * -------------
26852214Sav145390 * B
26862214Sav145390 *
26872214Sav145390 * The timing bits are set in PTRL_CNTL[28:26] where
26882214Sav145390 *
26892214Sav145390 * 0 - 1 m.s
26902214Sav145390 * 1 - 512 u.s.
26912214Sav145390 * 10 - 256 u.s.
26922214Sav145390 * 11 - 128 u.s.
26932214Sav145390 * 100 - 64 u.s.
26942214Sav145390 * 101 - 32 u.s.
26952214Sav145390 * 110 - 0 u.s.
26962214Sav145390 * 111 - reserved.
26972214Sav145390 *
26982214Sav145390 *
26992214Sav145390 * a[0] = 110, a[1] = 101, ... a[6] = 0
27002214Sav145390 *
27012214Sav145390 * cs-status property is int x 7
27022214Sav145390 * 0 - cs#
27032214Sav145390 * 1 - cs-status
27042214Sav145390 * 2 - cs-avail.hi
27052214Sav145390 * 3 - cs-avail.lo
27062214Sav145390 * 4 - dimm-capa.hi
27072214Sav145390 * 5 - dimm-capa.lo
27082214Sav145390 * 6 - #of dimms
27092214Sav145390 */
27102214Sav145390
27112214Sav145390 if (nbytes > 0) {
27122214Sav145390 int i;
27132214Sav145390 uint64_t ms;
27142214Sav145390 ms = ((uint64_t)mc_scan_period * 64 * 1000000)/nbytes;
27152214Sav145390 mcp->mc_speed = mc_scan_speeds[MC_MAX_SPEEDS - 1].mc_speeds;
27162214Sav145390 for (i = 0; i < MC_MAX_SPEEDS - 1; i++) {
27172214Sav145390 if (ms < mc_scan_speeds[i + 1].mc_period) {
27182214Sav145390 mcp->mc_speed = mc_scan_speeds[i].mc_speeds;
27192214Sav145390 break;
27202214Sav145390 }
27212214Sav145390 }
27222214Sav145390 } else
27232214Sav145390 mcp->mc_speed = 0;
27242214Sav145390
27252214Sav145390
27261772Sjl139090 for (i = 0; i < len / sizeof (struct mc_addr_spec); i++) {
27271772Sjl139090 struct mc_bank *bankp;
27285310Sdhain mc_retry_info_t *retry;
27291772Sjl139090 uint32_t reg;
27305310Sdhain int k;
27311772Sjl139090
27321772Sjl139090 /*
27331772Sjl139090 * setup bank
27341772Sjl139090 */
27351772Sjl139090 bk = macaddr[i].bank;
27361772Sjl139090 bankp = &(mcp->mc_bank[bk]);
27371772Sjl139090 bankp->mcb_status = BANK_INSTALLED;
27381772Sjl139090 bankp->mcb_reg_base = REGS_PA(macaddr, i);
27391772Sjl139090
27405310Sdhain bankp->mcb_retry_freelist = NULL;
27415310Sdhain bankp->mcb_retry_pending = NULL;
27425310Sdhain bankp->mcb_active = NULL;
27435310Sdhain retry = &bankp->mcb_retry_infos[0];
27445310Sdhain for (k = 0; k < MC_RETRY_COUNT; k++, retry++) {
27455310Sdhain mc_retry_info_put(&bankp->mcb_retry_freelist, retry);
27465310Sdhain }
27475310Sdhain
27481772Sjl139090 reg = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bk));
27491772Sjl139090 bankp->mcb_ptrl_cntl = (reg & MAC_CNTL_PTRL_PRESERVE_BITS);
27501772Sjl139090
27511772Sjl139090 /*
27521772Sjl139090 * check if mirror mode
27531772Sjl139090 */
27541772Sjl139090 mirr = LD_MAC_REG(MAC_MIRR(mcp, bk));
27551772Sjl139090
27561772Sjl139090 if (mirr & MAC_MIRR_MIRROR_MODE) {
27575080Swh31274 MC_LOG("Mirror -> /LSB%d/B%d\n", mcp->mc_board_num,
27585080Swh31274 bk);
27591772Sjl139090 bankp->mcb_status |= BANK_MIRROR_MODE;
27605080Swh31274 mirror_mode = 1;
27611772Sjl139090 /*
27621772Sjl139090 * The following bit is only used for
27631772Sjl139090 * error injection. We should clear it
27641772Sjl139090 */
27651772Sjl139090 if (mirr & MAC_MIRR_BANK_EXCLUSIVE)
27665080Swh31274 ST_MAC_REG(MAC_MIRR(mcp, bk), 0);
27671772Sjl139090 }
27681772Sjl139090
27691772Sjl139090 /*
27701772Sjl139090 * restart if not mirror mode or the other bank
27711772Sjl139090 * of the mirror is not running
27721772Sjl139090 */
27731772Sjl139090 if (!(mirr & MAC_MIRR_MIRROR_MODE) ||
27745080Swh31274 !(mcp->mc_bank[bk^1].mcb_status & BANK_PTRL_RUNNING)) {
27755080Swh31274 MC_LOG("Starting up /LSB%d/B%d\n", mcp->mc_board_num,
27765080Swh31274 bk);
27772662Shyw get_ptrl_start_address(mcp, bk, &rsaddr.mi_restartaddr);
27782662Shyw rsaddr.mi_valid = 0;
27792662Shyw rsaddr.mi_injectrestart = 0;
278011311SSurya.Prakki@Sun.COM (void) restart_patrol(mcp, bk, &rsaddr);
27811772Sjl139090 } else {
27821772Sjl139090 MC_LOG("Not starting up /LSB%d/B%d\n",
27835080Swh31274 mcp->mc_board_num, bk);
27841772Sjl139090 }
27851772Sjl139090 bankp->mcb_status |= BANK_PTRL_RUNNING;
27861772Sjl139090 }
27872214Sav145390 if (len > 0)
27882214Sav145390 kmem_free(macaddr, len);
27892214Sav145390
27905080Swh31274 ret = ndi_prop_update_int(DDI_DEV_T_NONE, mcp->mc_dip, "mirror-mode",
27915080Swh31274 mirror_mode);
27925080Swh31274 if (ret != DDI_PROP_SUCCESS) {
27935080Swh31274 cmn_err(CE_WARN, "Unable to update mirror-mode property");
27945080Swh31274 }
27955080Swh31274
27962214Sav145390 mcp->mc_dimm_list = mc_get_dimm_list(mcp);
27971772Sjl139090
27981772Sjl139090 /*
27991772Sjl139090 * set interval in HZ.
28001772Sjl139090 */
28011772Sjl139090 mcp->mc_last_error = 0;
28022214Sav145390
28031772Sjl139090 /* restart memory patrol checking */
28041772Sjl139090 mcp->mc_status |= MC_POLL_RUNNING;
28051772Sjl139090
28061772Sjl139090 return (DDI_SUCCESS);
28071772Sjl139090 }
28081772Sjl139090
28091772Sjl139090 int
mc_board_del(mc_opl_t * mcp)28101772Sjl139090 mc_board_del(mc_opl_t *mcp)
28111772Sjl139090 {
28121772Sjl139090 int i;
28131772Sjl139090 scf_log_t *p;
28141772Sjl139090
28151772Sjl139090 /*
28161772Sjl139090 * cleanup mac state
28171772Sjl139090 */
28181772Sjl139090 mutex_enter(&mcp->mc_lock);
28192214Sav145390 if (mcp->mc_status & MC_MEMORYLESS) {
28202214Sav145390 mutex_exit(&mcp->mc_lock);
28212214Sav145390 mutex_destroy(&mcp->mc_lock);
28222214Sav145390 return (DDI_SUCCESS);
28232214Sav145390 }
28241772Sjl139090 for (i = 0; i < BANKNUM_PER_SB; i++) {
28251772Sjl139090 if (mcp->mc_bank[i].mcb_status & BANK_INSTALLED) {
28261772Sjl139090 mcp->mc_bank[i].mcb_status &= ~BANK_INSTALLED;
28271772Sjl139090 }
28281772Sjl139090 }
28291772Sjl139090
28301772Sjl139090 /* stop memory patrol checking */
28312662Shyw mcp->mc_status &= ~MC_POLL_RUNNING;
28321772Sjl139090
28331772Sjl139090 /* just throw away all the scf logs */
28342214Sav145390 for (i = 0; i < BANKNUM_PER_SB; i++) {
28355080Swh31274 while ((p = mcp->mc_scf_log[i]) != NULL) {
28365080Swh31274 mcp->mc_scf_log[i] = p->sl_next;
28375080Swh31274 mcp->mc_scf_total[i]--;
28385080Swh31274 kmem_free(p, sizeof (scf_log_t));
28395080Swh31274 }
28401772Sjl139090 }
28411772Sjl139090
28421772Sjl139090 if (mcp->mlist)
28431772Sjl139090 mc_memlist_delete(mcp->mlist);
28441772Sjl139090
28452214Sav145390 if (mcp->mc_dimm_list)
28462214Sav145390 mc_free_dimm_list(mcp->mc_dimm_list);
28472214Sav145390
28481772Sjl139090 mutex_exit(&mcp->mc_lock);
28491772Sjl139090
28501772Sjl139090 mutex_destroy(&mcp->mc_lock);
28511772Sjl139090 return (DDI_SUCCESS);
28521772Sjl139090 }
28531772Sjl139090
28541772Sjl139090 int
mc_suspend(mc_opl_t * mcp,uint32_t flag)28551772Sjl139090 mc_suspend(mc_opl_t *mcp, uint32_t flag)
28561772Sjl139090 {
28571772Sjl139090 /* stop memory patrol checking */
28581772Sjl139090 mutex_enter(&mcp->mc_lock);
28592214Sav145390 if (mcp->mc_status & MC_MEMORYLESS) {
28602214Sav145390 mutex_exit(&mcp->mc_lock);
28612214Sav145390 return (DDI_SUCCESS);
28622214Sav145390 }
28632214Sav145390
28642662Shyw mcp->mc_status &= ~MC_POLL_RUNNING;
28652662Shyw
28661772Sjl139090 mcp->mc_status |= flag;
28671772Sjl139090 mutex_exit(&mcp->mc_lock);
28681772Sjl139090
28691772Sjl139090 return (DDI_SUCCESS);
28701772Sjl139090 }
28711772Sjl139090
28723354Sjl139090 void
opl_mc_update_mlist(void)28733354Sjl139090 opl_mc_update_mlist(void)
28743354Sjl139090 {
28753354Sjl139090 int i;
28763354Sjl139090 mc_opl_t *mcp;
28773354Sjl139090
28783354Sjl139090 /*
28793354Sjl139090 * memory information is not updated until
28803354Sjl139090 * the post attach/detach stage during DR.
28813354Sjl139090 * This interface is used by dr_mem to inform
28823354Sjl139090 * mc-opl to update the mlist.
28833354Sjl139090 */
28843354Sjl139090
28853354Sjl139090 mutex_enter(&mcmutex);
28863354Sjl139090 for (i = 0; i < OPL_MAX_BOARDS; i++) {
28873354Sjl139090 if ((mcp = mc_instances[i]) == NULL)
28883354Sjl139090 continue;
28893354Sjl139090 mutex_enter(&mcp->mc_lock);
28903354Sjl139090 if (mcp->mlist)
28913354Sjl139090 mc_memlist_delete(mcp->mlist);
28923354Sjl139090 mcp->mlist = NULL;
28933354Sjl139090 mc_get_mlist(mcp);
28943354Sjl139090 mutex_exit(&mcp->mc_lock);
28953354Sjl139090 }
28963354Sjl139090 mutex_exit(&mcmutex);
28973354Sjl139090 }
28983354Sjl139090
28991772Sjl139090 /* caller must clear the SUSPEND bits or this will do nothing */
29001772Sjl139090
29011772Sjl139090 int
mc_resume(mc_opl_t * mcp,uint32_t flag)29021772Sjl139090 mc_resume(mc_opl_t *mcp, uint32_t flag)
29031772Sjl139090 {
29041772Sjl139090 int i;
29051772Sjl139090 uint64_t basepa;
29061772Sjl139090
29071772Sjl139090 mutex_enter(&mcp->mc_lock);
29082214Sav145390 if (mcp->mc_status & MC_MEMORYLESS) {
29092214Sav145390 mutex_exit(&mcp->mc_lock);
29102214Sav145390 return (DDI_SUCCESS);
29112214Sav145390 }
29121772Sjl139090 basepa = mcp->mc_start_address;
29131772Sjl139090 if (get_base_address(mcp) == DDI_FAILURE) {
29141772Sjl139090 mutex_exit(&mcp->mc_lock);
29151772Sjl139090 return (DDI_FAILURE);
29161772Sjl139090 }
29171772Sjl139090
29181772Sjl139090 if (basepa != mcp->mc_start_address) {
29191772Sjl139090 if (mcp->mlist)
29201772Sjl139090 mc_memlist_delete(mcp->mlist);
29211772Sjl139090 mcp->mlist = NULL;
29221772Sjl139090 mc_get_mlist(mcp);
29231772Sjl139090 }
29241772Sjl139090
29251772Sjl139090 mcp->mc_status &= ~flag;
29261772Sjl139090
29271772Sjl139090 if (mcp->mc_status & (MC_SOFT_SUSPENDED | MC_DRIVER_SUSPENDED)) {
29281772Sjl139090 mutex_exit(&mcp->mc_lock);
29291772Sjl139090 return (DDI_SUCCESS);
29301772Sjl139090 }
29311772Sjl139090
29321772Sjl139090 if (!(mcp->mc_status & MC_POLL_RUNNING)) {
29331772Sjl139090 /* restart memory patrol checking */
29341772Sjl139090 mcp->mc_status |= MC_POLL_RUNNING;
29351772Sjl139090 for (i = 0; i < BANKNUM_PER_SB; i++) {
29361772Sjl139090 if (mcp->mc_bank[i].mcb_status & BANK_INSTALLED) {
29375310Sdhain mc_check_errors_func(mcp);
29381772Sjl139090 }
29391772Sjl139090 }
29401772Sjl139090 }
29411772Sjl139090 mutex_exit(&mcp->mc_lock);
29421772Sjl139090
29431772Sjl139090 return (DDI_SUCCESS);
29441772Sjl139090 }
29451772Sjl139090
29461772Sjl139090 static mc_opl_t *
mc_pa_to_mcp(uint64_t pa)29471772Sjl139090 mc_pa_to_mcp(uint64_t pa)
29481772Sjl139090 {
29492214Sav145390 mc_opl_t *mcp;
29502214Sav145390 int i;
29512214Sav145390
29521772Sjl139090 ASSERT(MUTEX_HELD(&mcmutex));
29532214Sav145390 for (i = 0; i < OPL_MAX_BOARDS; i++) {
29542214Sav145390 if ((mcp = mc_instances[i]) == NULL)
29552214Sav145390 continue;
29561772Sjl139090 /* if mac patrol is suspended, we cannot rely on it */
29572214Sav145390 if (!(mcp->mc_status & MC_POLL_RUNNING) ||
29585080Swh31274 (mcp->mc_status & MC_SOFT_SUSPENDED))
29591772Sjl139090 continue;
29602662Shyw if (mc_rangecheck_pa(mcp, pa)) {
29612214Sav145390 return (mcp);
29621772Sjl139090 }
29631772Sjl139090 }
29641772Sjl139090 return (NULL);
29651772Sjl139090 }
29661772Sjl139090
29671772Sjl139090 /*
29681772Sjl139090 * Get Physical Board number from Logical one.
29691772Sjl139090 */
29701772Sjl139090 static int
mc_opl_get_physical_board(int sb)29711772Sjl139090 mc_opl_get_physical_board(int sb)
29721772Sjl139090 {
29731772Sjl139090 if (&opl_get_physical_board) {
29741772Sjl139090 return (opl_get_physical_board(sb));
29751772Sjl139090 }
29761772Sjl139090
29771772Sjl139090 cmn_err(CE_NOTE, "!opl_get_physical_board() not loaded\n");
29781772Sjl139090 return (-1);
29791772Sjl139090 }
29801772Sjl139090
29811772Sjl139090 /* ARGSUSED */
29821772Sjl139090 int
mc_get_mem_unum(int synd_code,uint64_t flt_addr,char * buf,int buflen,int * lenp)29831772Sjl139090 mc_get_mem_unum(int synd_code, uint64_t flt_addr, char *buf, int buflen,
29841772Sjl139090 int *lenp)
29851772Sjl139090 {
29862214Sav145390 int i;
29873045Sav145390 int j;
29882214Sav145390 int sb;
29891772Sjl139090 int bank;
29903045Sav145390 int cs;
29916297Sjl139090 int rv = 0;
29922214Sav145390 mc_opl_t *mcp;
29932214Sav145390 char memb_num;
29941772Sjl139090
29951772Sjl139090 mutex_enter(&mcmutex);
29961772Sjl139090
29971772Sjl139090 if (((mcp = mc_pa_to_mcp(flt_addr)) == NULL) ||
29985080Swh31274 (!pa_is_valid(mcp, flt_addr))) {
29991772Sjl139090 mutex_exit(&mcmutex);
30001772Sjl139090 if (snprintf(buf, buflen, "UNKNOWN") >= buflen) {
30011772Sjl139090 return (ENOSPC);
30021772Sjl139090 } else {
30031772Sjl139090 if (lenp)
30041772Sjl139090 *lenp = strlen(buf);
30051772Sjl139090 }
30061772Sjl139090 return (0);
30071772Sjl139090 }
30081772Sjl139090
30091772Sjl139090 bank = pa_to_bank(mcp, flt_addr - mcp->mc_start_address);
30103045Sav145390 sb = mcp->mc_phys_board_num;
30113045Sav145390 cs = pa_to_cs(mcp, flt_addr - mcp->mc_start_address);
30121772Sjl139090
30131772Sjl139090 if (sb == -1) {
30141772Sjl139090 mutex_exit(&mcmutex);
30151772Sjl139090 return (ENXIO);
30161772Sjl139090 }
30171772Sjl139090
30186297Sjl139090 switch (plat_model) {
30196297Sjl139090 case MODEL_DC:
30202214Sav145390 i = BD_BK_SLOT_TO_INDEX(0, bank, 0);
30213045Sav145390 j = (cs == 0) ? i : i + 2;
302211311SSurya.Prakki@Sun.COM (void) snprintf(buf, buflen, "/%s%02d/MEM%s MEM%s",
30232214Sav145390 model_names[plat_model].unit_name, sb,
30243045Sav145390 mc_dc_dimm_unum_table[j],
30253045Sav145390 mc_dc_dimm_unum_table[j + 1]);
30266297Sjl139090 break;
30276297Sjl139090 case MODEL_FF2:
30286297Sjl139090 case MODEL_FF1:
30292214Sav145390 i = BD_BK_SLOT_TO_INDEX(sb, bank, 0);
30303045Sav145390 j = (cs == 0) ? i : i + 2;
30312214Sav145390 memb_num = mc_ff_dimm_unum_table[i][0];
303211311SSurya.Prakki@Sun.COM (void) snprintf(buf, buflen, "/%s/%s%c/MEM%s MEM%s",
30332214Sav145390 model_names[plat_model].unit_name,
30342214Sav145390 model_names[plat_model].mem_name, memb_num,
30353045Sav145390 &mc_ff_dimm_unum_table[j][1],
30363045Sav145390 &mc_ff_dimm_unum_table[j + 1][1]);
30376297Sjl139090 break;
30386297Sjl139090 case MODEL_IKKAKU:
30396297Sjl139090 i = BD_BK_SLOT_TO_INDEX(sb, bank, 0);
30406297Sjl139090 j = (cs == 0) ? i : i + 2;
304111311SSurya.Prakki@Sun.COM (void) snprintf(buf, buflen, "/%s/MEM%s MEM%s",
30426297Sjl139090 model_names[plat_model].unit_name,
30436297Sjl139090 &mc_ff_dimm_unum_table[j][1],
30446297Sjl139090 &mc_ff_dimm_unum_table[j + 1][1]);
30456297Sjl139090 break;
30466297Sjl139090 default:
30476297Sjl139090 rv = ENXIO;
30482214Sav145390 }
30492214Sav145390 if (lenp) {
30502214Sav145390 *lenp = strlen(buf);
30511772Sjl139090 }
30521772Sjl139090 mutex_exit(&mcmutex);
30536297Sjl139090 return (rv);
30541772Sjl139090 }
30551772Sjl139090
30561772Sjl139090 int
opl_mc_suspend(void)30572214Sav145390 opl_mc_suspend(void)
30581772Sjl139090 {
30591772Sjl139090 mc_opl_t *mcp;
30602214Sav145390 int i;
30611772Sjl139090
30621772Sjl139090 mutex_enter(&mcmutex);
30632214Sav145390 for (i = 0; i < OPL_MAX_BOARDS; i++) {
30642214Sav145390 if ((mcp = mc_instances[i]) == NULL)
30652214Sav145390 continue;
306611311SSurya.Prakki@Sun.COM (void) mc_suspend(mcp, MC_SOFT_SUSPENDED);
30671772Sjl139090 }
30681772Sjl139090 mutex_exit(&mcmutex);
30692214Sav145390
30701772Sjl139090 return (0);
30711772Sjl139090 }
30721772Sjl139090
30731772Sjl139090 int
opl_mc_resume(void)30742214Sav145390 opl_mc_resume(void)
30751772Sjl139090 {
30761772Sjl139090 mc_opl_t *mcp;
30772214Sav145390 int i;
30781772Sjl139090
30791772Sjl139090 mutex_enter(&mcmutex);
30802214Sav145390 for (i = 0; i < OPL_MAX_BOARDS; i++) {
30812214Sav145390 if ((mcp = mc_instances[i]) == NULL)
30822214Sav145390 continue;
308311311SSurya.Prakki@Sun.COM (void) mc_resume(mcp, MC_SOFT_SUSPENDED);
30841772Sjl139090 }
30851772Sjl139090 mutex_exit(&mcmutex);
30862214Sav145390
30871772Sjl139090 return (0);
30881772Sjl139090 }
30891772Sjl139090 static void
insert_mcp(mc_opl_t * mcp)30901772Sjl139090 insert_mcp(mc_opl_t *mcp)
30911772Sjl139090 {
30921772Sjl139090 mutex_enter(&mcmutex);
30932214Sav145390 if (mc_instances[mcp->mc_board_num] != NULL) {
30942214Sav145390 MC_LOG("mc-opl instance for board# %d already exists\n",
30955080Swh31274 mcp->mc_board_num);
30962214Sav145390 }
30972214Sav145390 mc_instances[mcp->mc_board_num] = mcp;
30981772Sjl139090 mutex_exit(&mcmutex);
30991772Sjl139090 }
31001772Sjl139090
31011772Sjl139090 static void
delete_mcp(mc_opl_t * mcp)31021772Sjl139090 delete_mcp(mc_opl_t *mcp)
31031772Sjl139090 {
31042214Sav145390 mutex_enter(&mcmutex);
31052214Sav145390 mc_instances[mcp->mc_board_num] = 0;
31062214Sav145390 mutex_exit(&mcmutex);
31071772Sjl139090 }
31081772Sjl139090
31091772Sjl139090 /* Error injection interface */
31101772Sjl139090
31112494Shyw static void
mc_lock_va(uint64_t pa,caddr_t new_va)31122494Shyw mc_lock_va(uint64_t pa, caddr_t new_va)
31132494Shyw {
31142494Shyw tte_t tte;
31152494Shyw
31162662Shyw vtag_flushpage(new_va, (uint64_t)ksfmmup);
31175080Swh31274 sfmmu_memtte(&tte, pa >> PAGESHIFT, PROC_DATA|HAT_NOSYNC, TTE8K);
31182494Shyw tte.tte_intlo |= TTE_LCK_INT;
31192494Shyw sfmmu_dtlb_ld_kva(new_va, &tte);
31202494Shyw }
31212494Shyw
31222494Shyw static void
mc_unlock_va(caddr_t va)31232494Shyw mc_unlock_va(caddr_t va)
31242494Shyw {
31252494Shyw vtag_flushpage(va, (uint64_t)ksfmmup);
31262494Shyw }
31272494Shyw
31281772Sjl139090 /* ARGSUSED */
31291772Sjl139090 int
mc_inject_error(int error_type,uint64_t pa,uint32_t flags)31301772Sjl139090 mc_inject_error(int error_type, uint64_t pa, uint32_t flags)
31311772Sjl139090 {
31321772Sjl139090 mc_opl_t *mcp;
31331772Sjl139090 int bank;
31341772Sjl139090 uint32_t dimm_addr;
31351772Sjl139090 uint32_t cntl;
31362662Shyw mc_rsaddr_info_t rsaddr;
31371772Sjl139090 uint32_t data, stat;
31381772Sjl139090 int both_sides = 0;
31391772Sjl139090 uint64_t pa0;
31402494Shyw int extra_injection_needed = 0;
31411772Sjl139090 extern void cpu_flush_ecache(void);
31421772Sjl139090
31431772Sjl139090 MC_LOG("HW mc_inject_error(%x, %lx, %x)\n", error_type, pa, flags);
31441772Sjl139090
31451772Sjl139090 mutex_enter(&mcmutex);
31461772Sjl139090 if ((mcp = mc_pa_to_mcp(pa)) == NULL) {
31471772Sjl139090 mutex_exit(&mcmutex);
31481772Sjl139090 MC_LOG("mc_inject_error: invalid pa\n");
31491772Sjl139090 return (ENOTSUP);
31501772Sjl139090 }
31511772Sjl139090
31521772Sjl139090 mutex_enter(&mcp->mc_lock);
31531772Sjl139090 mutex_exit(&mcmutex);
31541772Sjl139090
31551772Sjl139090 if (mcp->mc_status & (MC_SOFT_SUSPENDED | MC_DRIVER_SUSPENDED)) {
31561772Sjl139090 mutex_exit(&mcp->mc_lock);
31571772Sjl139090 MC_LOG("mc-opl has been suspended. No error injection.\n");
31581772Sjl139090 return (EBUSY);
31591772Sjl139090 }
31601772Sjl139090
31611772Sjl139090 /* convert pa to offset within the board */
31621772Sjl139090 MC_LOG("pa %lx, offset %lx\n", pa, pa - mcp->mc_start_address);
31631772Sjl139090
31641772Sjl139090 if (!pa_is_valid(mcp, pa)) {
31651772Sjl139090 mutex_exit(&mcp->mc_lock);
31661772Sjl139090 return (EINVAL);
31671772Sjl139090 }
31681772Sjl139090
31691772Sjl139090 pa0 = pa - mcp->mc_start_address;
31701772Sjl139090
31711772Sjl139090 bank = pa_to_bank(mcp, pa0);
31721772Sjl139090
31731772Sjl139090 if (flags & MC_INJECT_FLAG_OTHER)
31741772Sjl139090 bank = bank ^ 1;
31751772Sjl139090
31761772Sjl139090 if (MC_INJECT_MIRROR(error_type) && !IS_MIRROR(mcp, bank)) {
31771772Sjl139090 mutex_exit(&mcp->mc_lock);
31781772Sjl139090 MC_LOG("Not mirror mode\n");
31791772Sjl139090 return (EINVAL);
31801772Sjl139090 }
31811772Sjl139090
31821772Sjl139090 dimm_addr = pa_to_dimm(mcp, pa0);
31831772Sjl139090
31845080Swh31274 MC_LOG("injecting error to /LSB%d/B%d/%x\n", mcp->mc_board_num, bank,
31855080Swh31274 dimm_addr);
31861772Sjl139090
31871772Sjl139090
31881772Sjl139090 switch (error_type) {
31891772Sjl139090 case MC_INJECT_INTERMITTENT_MCE:
31901772Sjl139090 case MC_INJECT_PERMANENT_MCE:
31911772Sjl139090 case MC_INJECT_MUE:
31921772Sjl139090 both_sides = 1;
31931772Sjl139090 }
31941772Sjl139090
31951772Sjl139090 if (flags & MC_INJECT_FLAG_RESET)
31961772Sjl139090 ST_MAC_REG(MAC_EG_CNTL(mcp, bank), 0);
31971772Sjl139090
31981772Sjl139090 ST_MAC_REG(MAC_EG_ADD(mcp, bank), dimm_addr & MAC_EG_ADD_MASK);
31991772Sjl139090
32001772Sjl139090 if (both_sides) {
32011772Sjl139090 ST_MAC_REG(MAC_EG_CNTL(mcp, bank^1), 0);
32025080Swh31274 ST_MAC_REG(MAC_EG_ADD(mcp, bank^1), dimm_addr &
32035080Swh31274 MAC_EG_ADD_MASK);
32041772Sjl139090 }
32051772Sjl139090
32061772Sjl139090 switch (error_type) {
32072494Shyw case MC_INJECT_SUE:
32082494Shyw extra_injection_needed = 1;
32092494Shyw /*FALLTHROUGH*/
32101772Sjl139090 case MC_INJECT_UE:
32111772Sjl139090 case MC_INJECT_MUE:
32121772Sjl139090 if (flags & MC_INJECT_FLAG_PATH) {
32135080Swh31274 cntl = MAC_EG_ADD_FIX | MAC_EG_FORCE_READ00 |
32145080Swh31274 MAC_EG_FORCE_READ16 | MAC_EG_RDERR_ONCE;
32151772Sjl139090 } else {
32165080Swh31274 cntl = MAC_EG_ADD_FIX | MAC_EG_FORCE_DERR00 |
32175080Swh31274 MAC_EG_FORCE_DERR16 | MAC_EG_DERR_ONCE;
32181772Sjl139090 }
32191772Sjl139090 flags |= MC_INJECT_FLAG_ST;
32201772Sjl139090 break;
32211772Sjl139090 case MC_INJECT_INTERMITTENT_CE:
32221772Sjl139090 case MC_INJECT_INTERMITTENT_MCE:
32231772Sjl139090 if (flags & MC_INJECT_FLAG_PATH) {
32245080Swh31274 cntl = MAC_EG_ADD_FIX |MAC_EG_FORCE_READ00 |
32255080Swh31274 MAC_EG_RDERR_ONCE;
32261772Sjl139090 } else {
32275080Swh31274 cntl = MAC_EG_ADD_FIX | MAC_EG_FORCE_DERR16 |
32285080Swh31274 MAC_EG_DERR_ONCE;
32291772Sjl139090 }
32302494Shyw extra_injection_needed = 1;
32311772Sjl139090 flags |= MC_INJECT_FLAG_ST;
32321772Sjl139090 break;
32331772Sjl139090 case MC_INJECT_PERMANENT_CE:
32341772Sjl139090 case MC_INJECT_PERMANENT_MCE:
32351772Sjl139090 if (flags & MC_INJECT_FLAG_PATH) {
32365080Swh31274 cntl = MAC_EG_ADD_FIX | MAC_EG_FORCE_READ00 |
32375080Swh31274 MAC_EG_RDERR_ALWAYS;
32381772Sjl139090 } else {
32395080Swh31274 cntl = MAC_EG_ADD_FIX | MAC_EG_FORCE_DERR16 |
32405080Swh31274 MAC_EG_DERR_ALWAYS;
32411772Sjl139090 }
32421772Sjl139090 flags |= MC_INJECT_FLAG_ST;
32431772Sjl139090 break;
32441772Sjl139090 case MC_INJECT_CMPE:
32451772Sjl139090 data = 0xabcdefab;
32461772Sjl139090 stphys(pa, data);
32471772Sjl139090 cpu_flush_ecache();
32481772Sjl139090 MC_LOG("CMPE: writing data %x to %lx\n", data, pa);
32491772Sjl139090 ST_MAC_REG(MAC_MIRR(mcp, bank), MAC_MIRR_BANK_EXCLUSIVE);
32501772Sjl139090 stphys(pa, data ^ 0xffffffff);
32512662Shyw membar_sync();
32521772Sjl139090 cpu_flush_ecache();
32531772Sjl139090 ST_MAC_REG(MAC_MIRR(mcp, bank), 0);
32541772Sjl139090 MC_LOG("CMPE: write new data %xto %lx\n", data, pa);
32551772Sjl139090 cntl = 0;
32561772Sjl139090 break;
32571772Sjl139090 case MC_INJECT_NOP:
32581772Sjl139090 cntl = 0;
32591772Sjl139090 break;
32601772Sjl139090 default:
32611772Sjl139090 MC_LOG("mc_inject_error: invalid option\n");
32621772Sjl139090 cntl = 0;
32631772Sjl139090 }
32641772Sjl139090
32651772Sjl139090 if (cntl) {
32661772Sjl139090 ST_MAC_REG(MAC_EG_CNTL(mcp, bank), cntl & MAC_EG_SETUP_MASK);
32671772Sjl139090 ST_MAC_REG(MAC_EG_CNTL(mcp, bank), cntl);
32681772Sjl139090
32691772Sjl139090 if (both_sides) {
32701772Sjl139090 ST_MAC_REG(MAC_EG_CNTL(mcp, bank^1), cntl &
32715080Swh31274 MAC_EG_SETUP_MASK);
32721772Sjl139090 ST_MAC_REG(MAC_EG_CNTL(mcp, bank^1), cntl);
32731772Sjl139090 }
32741772Sjl139090 }
32751772Sjl139090
32761772Sjl139090 /*
32771772Sjl139090 * For all injection cases except compare error, we
32781772Sjl139090 * must write to the PA to trigger the error.
32791772Sjl139090 */
32801772Sjl139090
32811772Sjl139090 if (flags & MC_INJECT_FLAG_ST) {
32821772Sjl139090 data = 0xf0e0d0c0;
32831772Sjl139090 MC_LOG("Writing %x to %lx\n", data, pa);
32841772Sjl139090 stphys(pa, data);
32851772Sjl139090 cpu_flush_ecache();
32861772Sjl139090 }
32871772Sjl139090
32881772Sjl139090
32891772Sjl139090 if (flags & MC_INJECT_FLAG_LD) {
32902494Shyw if (flags & MC_INJECT_FLAG_PREFETCH) {
32912494Shyw /*
32922494Shyw * Use strong prefetch operation to
32932494Shyw * inject MI errors.
32942494Shyw */
32952494Shyw page_t *pp;
32962494Shyw extern void mc_prefetch(caddr_t);
32972494Shyw
32982494Shyw MC_LOG("prefetch\n");
32992494Shyw
33002494Shyw pp = page_numtopp_nolock(pa >> PAGESHIFT);
33012494Shyw if (pp != NULL) {
33022494Shyw caddr_t va, va1;
33032494Shyw
33042494Shyw va = ppmapin(pp, PROT_READ|PROT_WRITE,
33055080Swh31274 (caddr_t)-1);
33062494Shyw kpreempt_disable();
33072494Shyw mc_lock_va((uint64_t)pa, va);
33082494Shyw va1 = va + (pa & (PAGESIZE - 1));
33092494Shyw mc_prefetch(va1);
33102494Shyw mc_unlock_va(va);
33112494Shyw kpreempt_enable();
33122494Shyw ppmapout(va);
33132494Shyw
33142494Shyw /*
33152494Shyw * For MI errors, we need one extra
33162494Shyw * injection for HW patrol to stop.
33172494Shyw */
33182494Shyw extra_injection_needed = 1;
33191772Sjl139090 } else {
33202494Shyw cmn_err(CE_WARN, "Cannot find page structure"
33215080Swh31274 " for PA %lx\n", pa);
33221772Sjl139090 }
33231772Sjl139090 } else {
33241772Sjl139090 MC_LOG("Reading from %lx\n", pa);
33251772Sjl139090 data = ldphys(pa);
33261772Sjl139090 MC_LOG("data = %x\n", data);
33271772Sjl139090 }
33282494Shyw
33292494Shyw if (extra_injection_needed) {
33302494Shyw /*
33312494Shyw * These are the injection cases where the
33322494Shyw * requested injected errors will not cause the HW
33332494Shyw * patrol to stop. For these cases, we need to inject
33342494Shyw * an extra 'real' PTRL error to force the
33352494Shyw * HW patrol to stop so that we can report the
33362494Shyw * errors injected. Note that we cannot read
33372494Shyw * and report error status while the HW patrol
33382494Shyw * is running.
33392494Shyw */
33402494Shyw ST_MAC_REG(MAC_EG_CNTL(mcp, bank),
33415080Swh31274 cntl & MAC_EG_SETUP_MASK);
33422494Shyw ST_MAC_REG(MAC_EG_CNTL(mcp, bank), cntl);
33432494Shyw
33442494Shyw if (both_sides) {
33455080Swh31274 ST_MAC_REG(MAC_EG_CNTL(mcp, bank^1), cntl &
33465080Swh31274 MAC_EG_SETUP_MASK);
33475080Swh31274 ST_MAC_REG(MAC_EG_CNTL(mcp, bank^1), cntl);
33482494Shyw }
33492494Shyw data = 0xf0e0d0c0;
33502494Shyw MC_LOG("Writing %x to %lx\n", data, pa);
33512494Shyw stphys(pa, data);
33522494Shyw cpu_flush_ecache();
33532494Shyw }
33541772Sjl139090 }
33551772Sjl139090
33561772Sjl139090 if (flags & MC_INJECT_FLAG_RESTART) {
33571772Sjl139090 MC_LOG("Restart patrol\n");
33582662Shyw rsaddr.mi_restartaddr.ma_bd = mcp->mc_board_num;
33592662Shyw rsaddr.mi_restartaddr.ma_bank = bank;
33602662Shyw rsaddr.mi_restartaddr.ma_dimm_addr = dimm_addr;
33612662Shyw rsaddr.mi_valid = 1;
33622662Shyw rsaddr.mi_injectrestart = 1;
336311311SSurya.Prakki@Sun.COM (void) restart_patrol(mcp, bank, &rsaddr);
33641772Sjl139090 }
33651772Sjl139090
33661772Sjl139090 if (flags & MC_INJECT_FLAG_POLL) {
33672214Sav145390 int running;
33682867Shyw int ebank = (IS_MIRROR(mcp, bank)) ? MIRROR_IDX(bank) : bank;
33691772Sjl139090
33701772Sjl139090 MC_LOG("Poll patrol error\n");
33711772Sjl139090 stat = LD_MAC_REG(MAC_PTRL_STAT(mcp, bank));
33721772Sjl139090 cntl = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank));
33732214Sav145390 running = cntl & MAC_CNTL_PTRL_START;
33742494Shyw
33752494Shyw if (!running &&
33762494Shyw (stat & (MAC_STAT_PTRL_ERRS|MAC_STAT_MI_ERRS))) {
33772494Shyw /*
33782494Shyw * HW patrol stopped and we have errors to
33792494Shyw * report. Do it.
33802494Shyw */
33812867Shyw mcp->mc_speedup_period[ebank] = 0;
33822662Shyw rsaddr.mi_valid = 0;
33832662Shyw rsaddr.mi_injectrestart = 0;
33842662Shyw if (IS_MIRROR(mcp, bank)) {
33852662Shyw mc_error_handler_mir(mcp, bank, &rsaddr);
33862662Shyw } else {
33872662Shyw mc_error_handler(mcp, bank, &rsaddr);
33882662Shyw }
33892662Shyw
339011311SSurya.Prakki@Sun.COM (void) restart_patrol(mcp, bank, &rsaddr);
33912494Shyw } else {
33922494Shyw /*
33932494Shyw * We are expecting to report injected
33942494Shyw * errors but the HW patrol is still running.
33952494Shyw * Speed up the scanning
33962494Shyw */
33972867Shyw mcp->mc_speedup_period[ebank] = 2;
33982494Shyw MAC_CMD(mcp, bank, 0);
339911311SSurya.Prakki@Sun.COM (void) restart_patrol(mcp, bank, NULL);
34002494Shyw }
34011772Sjl139090 }
34021772Sjl139090
34031772Sjl139090 mutex_exit(&mcp->mc_lock);
34041772Sjl139090 return (0);
34051772Sjl139090 }
34062494Shyw
34071772Sjl139090 void
mc_stphysio(uint64_t pa,uint32_t data)34081772Sjl139090 mc_stphysio(uint64_t pa, uint32_t data)
34091772Sjl139090 {
34101772Sjl139090 MC_LOG("0x%x -> pa(%lx)\n", data, pa);
34111772Sjl139090 stphysio(pa, data);
34122214Sav145390
34132214Sav145390 /* force the above write to be processed by mac patrol */
34142494Shyw data = ldphysio(pa);
34152494Shyw MC_LOG("pa(%lx) = 0x%x\n", pa, data);
34161772Sjl139090 }
34171772Sjl139090
34181772Sjl139090 uint32_t
mc_ldphysio(uint64_t pa)34191772Sjl139090 mc_ldphysio(uint64_t pa)
34201772Sjl139090 {
34211772Sjl139090 uint32_t rv;
34221772Sjl139090
34231772Sjl139090 rv = ldphysio(pa);
34241772Sjl139090 MC_LOG("pa(%lx) = 0x%x\n", pa, rv);
34251772Sjl139090 return (rv);
34261772Sjl139090 }
34272214Sav145390
34282214Sav145390 #define isdigit(ch) ((ch) >= '0' && (ch) <= '9')
34292214Sav145390
34302214Sav145390 /*
34312214Sav145390 * parse_unum_memory -- extract the board number and the DIMM name from
34322214Sav145390 * the unum.
34332214Sav145390 *
34342214Sav145390 * Return 0 for success and non-zero for a failure.
34352214Sav145390 */
34362214Sav145390 int
parse_unum_memory(char * unum,int * board,char * dname)34372214Sav145390 parse_unum_memory(char *unum, int *board, char *dname)
34382214Sav145390 {
34392214Sav145390 char *c;
34402214Sav145390 char x, y, z;
34412214Sav145390
34422214Sav145390 if ((c = strstr(unum, "CMU")) != NULL) {
34432214Sav145390 /* DC Model */
34442214Sav145390 c += 3;
34452214Sav145390 *board = (uint8_t)stoi(&c);
34462214Sav145390 if ((c = strstr(c, "MEM")) == NULL) {
34472214Sav145390 return (1);
34482214Sav145390 }
34492214Sav145390 c += 3;
34502214Sav145390 if (strlen(c) < 3) {
34512214Sav145390 return (2);
34522214Sav145390 }
34532214Sav145390 if ((!isdigit(c[0])) || (!(isdigit(c[1]))) ||
34542214Sav145390 ((c[2] != 'A') && (c[2] != 'B'))) {
34552214Sav145390 return (3);
34562214Sav145390 }
34572214Sav145390 x = c[0];
34582214Sav145390 y = c[1];
34592214Sav145390 z = c[2];
34602214Sav145390 } else if ((c = strstr(unum, "MBU_")) != NULL) {
34616297Sjl139090 /* FF1/FF2/Ikkaku Model */
34622214Sav145390 c += 4;
34632214Sav145390 if ((c[0] != 'A') && (c[0] != 'B')) {
34642214Sav145390 return (4);
34652214Sav145390 }
34666297Sjl139090 if (plat_model == MODEL_IKKAKU) {
34676297Sjl139090 /* Ikkaku Model */
34686297Sjl139090 x = '0';
34696297Sjl139090 *board = 0;
34706297Sjl139090 } else {
34716297Sjl139090 /* FF1/FF2 Model */
34726297Sjl139090 if ((c = strstr(c, "MEMB")) == NULL) {
34736297Sjl139090 return (5);
34746297Sjl139090 }
34756297Sjl139090 c += 4;
34766297Sjl139090
34776297Sjl139090 x = c[0];
34786297Sjl139090 *board = ((uint8_t)stoi(&c)) / 4;
34792214Sav145390 }
34806297Sjl139090
34812214Sav145390 if ((c = strstr(c, "MEM")) == NULL) {
34822214Sav145390 return (6);
34832214Sav145390 }
34842214Sav145390 c += 3;
34852214Sav145390 if (strlen(c) < 2) {
34862214Sav145390 return (7);
34872214Sav145390 }
34882214Sav145390 if ((!isdigit(c[0])) || ((c[1] != 'A') && (c[1] != 'B'))) {
34892214Sav145390 return (8);
34902214Sav145390 }
34912214Sav145390 y = c[0];
34922214Sav145390 z = c[1];
34932214Sav145390 } else {
34942214Sav145390 return (9);
34952214Sav145390 }
34962214Sav145390 if (*board < 0) {
34972214Sav145390 return (10);
34982214Sav145390 }
34992214Sav145390 dname[0] = x;
35002214Sav145390 dname[1] = y;
35012214Sav145390 dname[2] = z;
35022214Sav145390 dname[3] = '\0';
35032214Sav145390 return (0);
35042214Sav145390 }
35052214Sav145390
35062214Sav145390 /*
35072214Sav145390 * mc_get_mem_sid_dimm -- Get the serial-ID for a given board and
35082214Sav145390 * the DIMM name.
35092214Sav145390 */
35102214Sav145390 int
mc_get_mem_sid_dimm(mc_opl_t * mcp,char * dname,char * buf,int buflen,int * lenp)35112214Sav145390 mc_get_mem_sid_dimm(mc_opl_t *mcp, char *dname, char *buf,
35122214Sav145390 int buflen, int *lenp)
35132214Sav145390 {
35142214Sav145390 int ret = ENODEV;
35152214Sav145390 mc_dimm_info_t *d = NULL;
35162214Sav145390
351710794SMary.Beale@Sun.COM if ((d = mcp->mc_dimm_list) == NULL) {
351810794SMary.Beale@Sun.COM MC_LOG("mc_get_mem_sid_dimm: mc_dimm_list is NULL\n");
351910794SMary.Beale@Sun.COM return (EINVAL);
352010794SMary.Beale@Sun.COM }
35212214Sav145390
35222214Sav145390 for (; d != NULL; d = d->md_next) {
35232214Sav145390 if (strcmp(d->md_dimmname, dname) == 0) {
35242214Sav145390 break;
35252214Sav145390 }
35262214Sav145390 }
35272214Sav145390 if (d != NULL) {
35282214Sav145390 *lenp = strlen(d->md_serial) + strlen(d->md_partnum);
35292214Sav145390 if (buflen <= *lenp) {
35302214Sav145390 cmn_err(CE_WARN, "mc_get_mem_sid_dimm: "
35312214Sav145390 "buflen is smaller than %d\n", *lenp);
35322214Sav145390 ret = ENOSPC;
35332214Sav145390 } else {
353411311SSurya.Prakki@Sun.COM (void) snprintf(buf, buflen, "%s:%s",
35352214Sav145390 d->md_serial, d->md_partnum);
35362214Sav145390 ret = 0;
35372214Sav145390 }
35382214Sav145390 }
35392214Sav145390 MC_LOG("mc_get_mem_sid_dimm: Ret=%d Name=%s Serial-ID=%s\n",
35402214Sav145390 ret, dname, (ret == 0) ? buf : "");
35412214Sav145390 return (ret);
35422214Sav145390 }
35432214Sav145390
35442214Sav145390 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)35453045Sav145390 mc_set_mem_sid(mc_opl_t *mcp, char *buf, int buflen, int sb,
35462214Sav145390 int bank, uint32_t mf_type, uint32_t d_slot)
35472214Sav145390 {
35482214Sav145390 int lenp = buflen;
35492214Sav145390 int id;
35502214Sav145390 int ret;
35512214Sav145390 char *dimmnm;
35522214Sav145390
35535275Stsien if (mf_type == FLT_TYPE_INTERMITTENT_CE ||
35545275Stsien mf_type == FLT_TYPE_PERMANENT_CE) {
35552214Sav145390 if (plat_model == MODEL_DC) {
35566297Sjl139090 /*
35576297Sjl139090 * All DC models
35586297Sjl139090 */
35592214Sav145390 id = BD_BK_SLOT_TO_INDEX(0, bank, d_slot);
35603045Sav145390 dimmnm = mc_dc_dimm_unum_table[id];
35612214Sav145390 } else {
35626297Sjl139090 /*
35636297Sjl139090 * All FF and Ikkaku models
35646297Sjl139090 */
35652214Sav145390 id = BD_BK_SLOT_TO_INDEX(sb, bank, d_slot);
35663045Sav145390 dimmnm = mc_ff_dimm_unum_table[id];
35672214Sav145390 }
35682214Sav145390 if ((ret = mc_get_mem_sid_dimm(mcp, dimmnm, buf, buflen,
35692214Sav145390 &lenp)) != 0) {
35702214Sav145390 return (ret);
35712214Sav145390 }
35722214Sav145390 } else {
35732214Sav145390 return (1);
35742214Sav145390 }
35752214Sav145390
35762214Sav145390 return (0);
35772214Sav145390 }
35782214Sav145390
35792214Sav145390 /*
35802214Sav145390 * mc_get_mem_sid -- get the DIMM serial-ID corresponding to the unum.
35812214Sav145390 */
35822214Sav145390 int
mc_get_mem_sid(char * unum,char * buf,int buflen,int * lenp)35832214Sav145390 mc_get_mem_sid(char *unum, char *buf, int buflen, int *lenp)
35842214Sav145390 {
35852214Sav145390 int i;
35862214Sav145390 int ret = ENODEV;
35872214Sav145390 int board;
35882214Sav145390 char dname[MCOPL_MAX_DIMMNAME + 1];
35892214Sav145390 mc_opl_t *mcp;
35902214Sav145390
35912214Sav145390 MC_LOG("mc_get_mem_sid: unum=%s buflen=%d\n", unum, buflen);
35922214Sav145390 if ((ret = parse_unum_memory(unum, &board, dname)) != 0) {
35932214Sav145390 MC_LOG("mc_get_mem_sid: unum(%s) parsing failed ret=%d\n",
35942214Sav145390 unum, ret);
35952214Sav145390 return (EINVAL);
35962214Sav145390 }
35972214Sav145390
35982214Sav145390 if (board < 0) {
35992214Sav145390 MC_LOG("mc_get_mem_sid: Invalid board=%d dimm=%s\n",
36002214Sav145390 board, dname);
36012214Sav145390 return (EINVAL);
36022214Sav145390 }
36032214Sav145390
36042214Sav145390 mutex_enter(&mcmutex);
36053152Sav145390 /*
36063152Sav145390 * return ENOENT if we can not find the matching board.
36073152Sav145390 */
36083152Sav145390 ret = ENOENT;
36092214Sav145390 for (i = 0; i < OPL_MAX_BOARDS; i++) {
36102214Sav145390 if ((mcp = mc_instances[i]) == NULL)
36112214Sav145390 continue;
36122214Sav145390 mutex_enter(&mcp->mc_lock);
36133045Sav145390 if (mcp->mc_phys_board_num != board) {
36143045Sav145390 mutex_exit(&mcp->mc_lock);
36153045Sav145390 continue;
36163045Sav145390 }
36173045Sav145390 ret = mc_get_mem_sid_dimm(mcp, dname, buf, buflen, lenp);
36183045Sav145390 if (ret == 0) {
36192214Sav145390 mutex_exit(&mcp->mc_lock);
36202214Sav145390 break;
36212214Sav145390 }
36222214Sav145390 mutex_exit(&mcp->mc_lock);
36232214Sav145390 }
36242214Sav145390 mutex_exit(&mcmutex);
36252214Sav145390 return (ret);
36262214Sav145390 }
36272214Sav145390
36282214Sav145390 /*
36292214Sav145390 * mc_get_mem_offset -- get the offset in a DIMM for a given physical address.
36302214Sav145390 */
36312214Sav145390 int
mc_get_mem_offset(uint64_t paddr,uint64_t * offp)36322214Sav145390 mc_get_mem_offset(uint64_t paddr, uint64_t *offp)
36332214Sav145390 {
36342214Sav145390 int i;
36352214Sav145390 int ret = ENODEV;
36362214Sav145390 mc_addr_t maddr;
36372214Sav145390 mc_opl_t *mcp;
36382214Sav145390
36392214Sav145390 mutex_enter(&mcmutex);
36402501Sraghuram for (i = 0; ((i < OPL_MAX_BOARDS) && (ret != 0)); i++) {
36412214Sav145390 if ((mcp = mc_instances[i]) == NULL)
36422214Sav145390 continue;
36432214Sav145390 mutex_enter(&mcp->mc_lock);
36442214Sav145390 if (!pa_is_valid(mcp, paddr)) {
36452214Sav145390 mutex_exit(&mcp->mc_lock);
36462214Sav145390 continue;
36472214Sav145390 }
36482214Sav145390 if (pa_to_maddr(mcp, paddr, &maddr) == 0) {
36492214Sav145390 *offp = maddr.ma_dimm_addr;
36502214Sav145390 ret = 0;
36512214Sav145390 }
36522214Sav145390 mutex_exit(&mcp->mc_lock);
36532214Sav145390 }
36542214Sav145390 mutex_exit(&mcmutex);
36552214Sav145390 MC_LOG("mc_get_mem_offset: Ret=%d paddr=0x%lx offset=0x%lx\n",
36562214Sav145390 ret, paddr, *offp);
36572214Sav145390 return (ret);
36582214Sav145390 }
36592214Sav145390
36602214Sav145390 /*
36612214Sav145390 * dname_to_bankslot - Get the bank and slot number from the DIMM name.
36622214Sav145390 */
36632214Sav145390 int
dname_to_bankslot(char * dname,int * bank,int * slot)36642214Sav145390 dname_to_bankslot(char *dname, int *bank, int *slot)
36652214Sav145390 {
36662214Sav145390 int i;
36672214Sav145390 int tsz;
36682214Sav145390 char **tbl;
36692214Sav145390
36706297Sjl139090 if (plat_model == MODEL_DC) {
36716297Sjl139090 /*
36726297Sjl139090 * All DC models
36736297Sjl139090 */
36742214Sav145390 tbl = mc_dc_dimm_unum_table;
36752214Sav145390 tsz = OPL_MAX_DIMMS;
36762214Sav145390 } else {
36776297Sjl139090 /*
36786297Sjl139090 * All FF and Ikkaku models
36796297Sjl139090 */
36802214Sav145390 tbl = mc_ff_dimm_unum_table;
36812214Sav145390 tsz = 2 * OPL_MAX_DIMMS;
36822214Sav145390 }
36832214Sav145390
36842214Sav145390 for (i = 0; i < tsz; i++) {
36852214Sav145390 if (strcmp(dname, tbl[i]) == 0) {
36862214Sav145390 break;
36872214Sav145390 }
36882214Sav145390 }
36892214Sav145390 if (i == tsz) {
36902214Sav145390 return (1);
36912214Sav145390 }
36922214Sav145390 *bank = INDEX_TO_BANK(i);
36932214Sav145390 *slot = INDEX_TO_SLOT(i);
36942214Sav145390 return (0);
36952214Sav145390 }
36962214Sav145390
36972214Sav145390 /*
36982214Sav145390 * mc_get_mem_addr -- get the physical address of a DIMM corresponding
36992214Sav145390 * to the unum and sid.
37002214Sav145390 */
37012214Sav145390 int
mc_get_mem_addr(char * unum,char * sid,uint64_t offset,uint64_t * paddr)37022214Sav145390 mc_get_mem_addr(char *unum, char *sid, uint64_t offset, uint64_t *paddr)
37032214Sav145390 {
37042214Sav145390 int board;
37052214Sav145390 int bank;
37062214Sav145390 int slot;
37072214Sav145390 int i;
37082214Sav145390 int ret = ENODEV;
37092214Sav145390 char dname[MCOPL_MAX_DIMMNAME + 1];
37102214Sav145390 mc_addr_t maddr;
37112214Sav145390 mc_opl_t *mcp;
37122214Sav145390
37132214Sav145390 MC_LOG("mc_get_mem_addr: unum=%s sid=%s offset=0x%lx\n",
37142214Sav145390 unum, sid, offset);
37152214Sav145390 if (parse_unum_memory(unum, &board, dname) != 0) {
37162214Sav145390 MC_LOG("mc_get_mem_sid: unum(%s) parsing failed ret=%d\n",
37172214Sav145390 unum, ret);
37182214Sav145390 return (EINVAL);
37192214Sav145390 }
37202214Sav145390
37212214Sav145390 if (board < 0) {
37222214Sav145390 MC_LOG("mc_get_mem_addr: Invalid board=%d dimm=%s\n",
37232214Sav145390 board, dname);
37242214Sav145390 return (EINVAL);
37252214Sav145390 }
37262214Sav145390
37272214Sav145390 mutex_enter(&mcmutex);
37282214Sav145390 for (i = 0; i < OPL_MAX_BOARDS; i++) {
37292214Sav145390 if ((mcp = mc_instances[i]) == NULL)
37302214Sav145390 continue;
37312214Sav145390 mutex_enter(&mcp->mc_lock);
37323045Sav145390 if (mcp->mc_phys_board_num != board) {
37332214Sav145390 mutex_exit(&mcp->mc_lock);
37342214Sav145390 continue;
37352214Sav145390 }
37362214Sav145390
37372214Sav145390 ret = dname_to_bankslot(dname, &bank, &slot);
37382214Sav145390 MC_LOG("mc_get_mem_addr: bank=%d slot=%d\n", bank, slot);
37392214Sav145390 if (ret != 0) {
37402214Sav145390 MC_LOG("mc_get_mem_addr: dname_to_bankslot failed\n");
37412214Sav145390 ret = ENODEV;
37422214Sav145390 } else {
37433045Sav145390 maddr.ma_bd = mcp->mc_board_num;
37442214Sav145390 maddr.ma_bank = bank;
37452214Sav145390 maddr.ma_dimm_addr = offset;
37462214Sav145390 ret = mcaddr_to_pa(mcp, &maddr, paddr);
37472214Sav145390 if (ret != 0) {
37482214Sav145390 MC_LOG("mc_get_mem_addr: "
37492214Sav145390 "mcaddr_to_pa failed\n");
37502214Sav145390 ret = ENODEV;
37516693Swh31274 mutex_exit(&mcp->mc_lock);
37526693Swh31274 continue;
37532214Sav145390 }
37543045Sav145390 mutex_exit(&mcp->mc_lock);
37553045Sav145390 break;
37562214Sav145390 }
37572214Sav145390 mutex_exit(&mcp->mc_lock);
37582214Sav145390 }
37592214Sav145390 mutex_exit(&mcmutex);
37602214Sav145390 MC_LOG("mc_get_mem_addr: Ret=%d, Paddr=0x%lx\n", ret, *paddr);
37612214Sav145390 return (ret);
37622214Sav145390 }
37632214Sav145390
37642214Sav145390 static void
mc_free_dimm_list(mc_dimm_info_t * d)37652214Sav145390 mc_free_dimm_list(mc_dimm_info_t *d)
37662214Sav145390 {
37672214Sav145390 mc_dimm_info_t *next;
37682214Sav145390
37692214Sav145390 while (d != NULL) {
37702214Sav145390 next = d->md_next;
37712214Sav145390 kmem_free(d, sizeof (mc_dimm_info_t));
37722214Sav145390 d = next;
37732214Sav145390 }
37742214Sav145390 }
37752214Sav145390
37762214Sav145390 /*
37772214Sav145390 * mc_get_dimm_list -- get the list of dimms with serial-id info
37782214Sav145390 * from the SP.
37792214Sav145390 */
37802214Sav145390 mc_dimm_info_t *
mc_get_dimm_list(mc_opl_t * mcp)37812214Sav145390 mc_get_dimm_list(mc_opl_t *mcp)
37822214Sav145390 {
37832214Sav145390 uint32_t bufsz;
37842214Sav145390 uint32_t maxbufsz;
37852214Sav145390 int ret;
37862214Sav145390 int sexp;
37872214Sav145390 board_dimm_info_t *bd_dimmp;
37882214Sav145390 mc_dimm_info_t *dimm_list = NULL;
37892214Sav145390
37902214Sav145390 maxbufsz = bufsz = sizeof (board_dimm_info_t) +
37912214Sav145390 ((MCOPL_MAX_DIMMNAME + MCOPL_MAX_SERIAL +
37922214Sav145390 MCOPL_MAX_PARTNUM) * OPL_MAX_DIMMS);
37932214Sav145390
37942214Sav145390 bd_dimmp = (board_dimm_info_t *)kmem_alloc(bufsz, KM_SLEEP);
37952214Sav145390 ret = scf_get_dimminfo(mcp->mc_board_num, (void *)bd_dimmp, &bufsz);
37962214Sav145390
37972214Sav145390 MC_LOG("mc_get_dimm_list: scf_service_getinfo returned=%d\n", ret);
37982214Sav145390 if (ret == 0) {
37992214Sav145390 sexp = sizeof (board_dimm_info_t) +
38002214Sav145390 ((bd_dimmp->bd_dnamesz + bd_dimmp->bd_serialsz +
38012214Sav145390 bd_dimmp->bd_partnumsz) * bd_dimmp->bd_numdimms);
38022214Sav145390
38032214Sav145390 if ((bd_dimmp->bd_version == OPL_DIMM_INFO_VERSION) &&
38042214Sav145390 (bd_dimmp->bd_dnamesz <= MCOPL_MAX_DIMMNAME) &&
38052214Sav145390 (bd_dimmp->bd_serialsz <= MCOPL_MAX_SERIAL) &&
38062214Sav145390 (bd_dimmp->bd_partnumsz <= MCOPL_MAX_PARTNUM) &&
38072214Sav145390 (sexp <= bufsz)) {
38082214Sav145390
38092214Sav145390 #ifdef DEBUG
38102214Sav145390 if (oplmc_debug)
38112214Sav145390 mc_dump_dimm_info(bd_dimmp);
38122214Sav145390 #endif
38132214Sav145390 dimm_list = mc_prepare_dimmlist(bd_dimmp);
38142214Sav145390
38152214Sav145390 } else {
38162214Sav145390 cmn_err(CE_WARN, "DIMM info version mismatch\n");
38172214Sav145390 }
38182214Sav145390 }
38192214Sav145390 kmem_free(bd_dimmp, maxbufsz);
382011311SSurya.Prakki@Sun.COM MC_LOG("mc_get_dimm_list: dimmlist=0x%p\n", (void *)dimm_list);
38212214Sav145390 return (dimm_list);
38222214Sav145390 }
38232214Sav145390
38242214Sav145390 /*
38253152Sav145390 * mc_prepare_dimmlist - Prepare the dimm list from the information
38263152Sav145390 * received from the SP.
38272214Sav145390 */
38282214Sav145390 mc_dimm_info_t *
mc_prepare_dimmlist(board_dimm_info_t * bd_dimmp)38292214Sav145390 mc_prepare_dimmlist(board_dimm_info_t *bd_dimmp)
38302214Sav145390 {
38312214Sav145390 char *dimm_name;
38322214Sav145390 char *serial;
38332214Sav145390 char *part;
38342214Sav145390 int dimm;
38352214Sav145390 int dnamesz = bd_dimmp->bd_dnamesz;
38362214Sav145390 int sersz = bd_dimmp->bd_serialsz;
38372214Sav145390 int partsz = bd_dimmp->bd_partnumsz;
38382214Sav145390 mc_dimm_info_t *dimm_list = NULL;
38392214Sav145390 mc_dimm_info_t *d;
38402214Sav145390
38412214Sav145390 dimm_name = (char *)(bd_dimmp + 1);
38422214Sav145390 for (dimm = 0; dimm < bd_dimmp->bd_numdimms; dimm++) {
38432214Sav145390
38442214Sav145390 d = (mc_dimm_info_t *)kmem_alloc(sizeof (mc_dimm_info_t),
38452214Sav145390 KM_SLEEP);
38463373Sbm42561
38473373Sbm42561 bcopy(dimm_name, d->md_dimmname, dnamesz);
38483373Sbm42561 d->md_dimmname[dnamesz] = 0;
38493373Sbm42561
38502214Sav145390 serial = dimm_name + dnamesz;
38513373Sbm42561 bcopy(serial, d->md_serial, sersz);
38523373Sbm42561 d->md_serial[sersz] = 0;
38533373Sbm42561
38542214Sav145390 part = serial + sersz;
38553373Sbm42561 bcopy(part, d->md_partnum, partsz);
38563373Sbm42561 d->md_partnum[partsz] = 0;
38572214Sav145390
38582214Sav145390 d->md_next = dimm_list;
38592214Sav145390 dimm_list = d;
38602214Sav145390 dimm_name = part + partsz;
38612214Sav145390 }
38622214Sav145390 return (dimm_list);
38632214Sav145390 }
38642214Sav145390
38656693Swh31274 static int
mc_get_mem_fmri(mc_flt_page_t * fpag,char ** unum)38666693Swh31274 mc_get_mem_fmri(mc_flt_page_t *fpag, char **unum)
38676693Swh31274 {
38686693Swh31274 if (fpag->fmri_addr == 0 || fpag->fmri_sz > MEM_FMRI_MAX_BUFSIZE)
38696693Swh31274 return (EINVAL);
38706693Swh31274
38716693Swh31274 *unum = kmem_alloc(fpag->fmri_sz, KM_SLEEP);
38726693Swh31274 if (copyin((void *)fpag->fmri_addr, *unum, fpag->fmri_sz) != 0) {
38736693Swh31274 kmem_free(*unum, fpag->fmri_sz);
38746693Swh31274 return (EFAULT);
38756693Swh31274 }
38766693Swh31274 return (0);
38776693Swh31274 }
38786693Swh31274
38796693Swh31274 static int
mc_scf_log_event(mc_flt_page_t * flt_pag)38806693Swh31274 mc_scf_log_event(mc_flt_page_t *flt_pag)
38816693Swh31274 {
38826693Swh31274 mc_opl_t *mcp;
38836693Swh31274 int board, bank, slot;
38846693Swh31274 int len, rv = 0;
38856693Swh31274 char *unum, *sid;
38866693Swh31274 char dname[MCOPL_MAX_DIMMNAME + 1];
38876693Swh31274 size_t sid_sz;
38886693Swh31274 uint64_t pa;
38896693Swh31274 mc_flt_stat_t flt_stat;
38906693Swh31274
38916693Swh31274 if ((sid_sz = cpu_get_name_bufsize()) == 0)
38926693Swh31274 return (ENOTSUP);
38936693Swh31274
38946693Swh31274 if ((rv = mc_get_mem_fmri(flt_pag, &unum)) != 0) {
38956693Swh31274 MC_LOG("mc_scf_log_event: mc_get_mem_fmri failed\n");
38966693Swh31274 return (rv);
38976693Swh31274 }
38986693Swh31274
38996693Swh31274 sid = kmem_zalloc(sid_sz, KM_SLEEP);
39006693Swh31274
39016693Swh31274 if ((rv = mc_get_mem_sid(unum, sid, sid_sz, &len)) != 0) {
39026693Swh31274 MC_LOG("mc_scf_log_event: mc_get_mem_sid failed\n");
39036693Swh31274 goto out;
39046693Swh31274 }
39056693Swh31274
39066693Swh31274 if ((rv = mc_get_mem_addr(unum, sid, (uint64_t)flt_pag->err_add,
39076693Swh31274 &pa)) != 0) {
39086693Swh31274 MC_LOG("mc_scf_log_event: mc_get_mem_addr failed\n");
39096693Swh31274 goto out;
39106693Swh31274 }
39116693Swh31274
39126693Swh31274 if (parse_unum_memory(unum, &board, dname) != 0) {
39136693Swh31274 MC_LOG("mc_scf_log_event: parse_unum_memory failed\n");
39146693Swh31274 rv = EINVAL;
39156693Swh31274 goto out;
39166693Swh31274 }
39176693Swh31274
39186693Swh31274 if (board < 0) {
39196693Swh31274 MC_LOG("mc_scf_log_event: Invalid board=%d dimm=%s\n",
39206693Swh31274 board, dname);
39216693Swh31274 rv = EINVAL;
39226693Swh31274 goto out;
39236693Swh31274 }
39246693Swh31274
39256693Swh31274 if (dname_to_bankslot(dname, &bank, &slot) != 0) {
39266693Swh31274 MC_LOG("mc_scf_log_event: dname_to_bankslot failed\n");
39276693Swh31274 rv = EINVAL;
39286693Swh31274 goto out;
39296693Swh31274 }
39306693Swh31274
39316693Swh31274 mutex_enter(&mcmutex);
39326693Swh31274
39336693Swh31274 flt_stat.mf_err_add = flt_pag->err_add;
39346693Swh31274 flt_stat.mf_err_log = flt_pag->err_log;
39356693Swh31274 flt_stat.mf_flt_paddr = pa;
39366693Swh31274
39376693Swh31274 if ((mcp = mc_pa_to_mcp(pa)) == NULL) {
39386693Swh31274 mutex_exit(&mcmutex);
39396693Swh31274 MC_LOG("mc_scf_log_event: invalid pa\n");
39406693Swh31274 rv = EINVAL;
39416693Swh31274 goto out;
39426693Swh31274 }
39436693Swh31274
39446693Swh31274 MC_LOG("mc_scf_log_event: DIMM%s, /LSB%d/B%d/%x, pa %lx elog %x\n",
39456693Swh31274 unum, mcp->mc_board_num, bank, flt_pag->err_add, pa,
39466693Swh31274 flt_pag->err_log);
39476693Swh31274
39486693Swh31274 mutex_enter(&mcp->mc_lock);
39496693Swh31274
39506693Swh31274 if (!pa_is_valid(mcp, pa)) {
39516693Swh31274 mutex_exit(&mcp->mc_lock);
39526693Swh31274 mutex_exit(&mcmutex);
39536693Swh31274 rv = EINVAL;
39546693Swh31274 goto out;
39556693Swh31274 }
39566693Swh31274
39576693Swh31274 rv = 0;
39586693Swh31274
39596693Swh31274 mc_queue_scf_log(mcp, &flt_stat, bank);
39606693Swh31274
39616693Swh31274 mutex_exit(&mcp->mc_lock);
39626693Swh31274 mutex_exit(&mcmutex);
39636693Swh31274
39646693Swh31274 out:
39656693Swh31274 kmem_free(unum, flt_pag->fmri_sz);
39666693Swh31274 kmem_free(sid, sid_sz);
39676693Swh31274
39686693Swh31274 return (rv);
39696693Swh31274 }
39706693Swh31274
39712214Sav145390 #ifdef DEBUG
39722214Sav145390 void
mc_dump_dimm(char * buf,int dnamesz,int serialsz,int partnumsz)39732214Sav145390 mc_dump_dimm(char *buf, int dnamesz, int serialsz, int partnumsz)
39742214Sav145390 {
39752214Sav145390 char dname[MCOPL_MAX_DIMMNAME + 1];
39762214Sav145390 char serial[MCOPL_MAX_SERIAL + 1];
39772214Sav145390 char part[ MCOPL_MAX_PARTNUM + 1];
39782214Sav145390 char *b;
39792214Sav145390
39802214Sav145390 b = buf;
39813373Sbm42561 bcopy(b, dname, dnamesz);
39823373Sbm42561 dname[dnamesz] = 0;
39833373Sbm42561
39842214Sav145390 b += dnamesz;
39853373Sbm42561 bcopy(b, serial, serialsz);
39863373Sbm42561 serial[serialsz] = 0;
39873373Sbm42561
39882214Sav145390 b += serialsz;
39893373Sbm42561 bcopy(b, part, partnumsz);
39903373Sbm42561 part[partnumsz] = 0;
39913373Sbm42561
39922214Sav145390 printf("DIMM=%s Serial=%s PartNum=%s\n", dname, serial, part);
39932214Sav145390 }
39942214Sav145390
39952214Sav145390 void
mc_dump_dimm_info(board_dimm_info_t * bd_dimmp)39962214Sav145390 mc_dump_dimm_info(board_dimm_info_t *bd_dimmp)
39972214Sav145390 {
39982214Sav145390 int dimm;
39992214Sav145390 int dnamesz = bd_dimmp->bd_dnamesz;
40002214Sav145390 int sersz = bd_dimmp->bd_serialsz;
40012214Sav145390 int partsz = bd_dimmp->bd_partnumsz;
40022214Sav145390 char *buf;
40032214Sav145390
40042214Sav145390 printf("Version=%d Board=%02d DIMMs=%d NameSize=%d "
40052214Sav145390 "SerialSize=%d PartnumSize=%d\n", bd_dimmp->bd_version,
40062214Sav145390 bd_dimmp->bd_boardnum, bd_dimmp->bd_numdimms, bd_dimmp->bd_dnamesz,
40072214Sav145390 bd_dimmp->bd_serialsz, bd_dimmp->bd_partnumsz);
40082214Sav145390 printf("======================================================\n");
40092214Sav145390
40102214Sav145390 buf = (char *)(bd_dimmp + 1);
40112214Sav145390 for (dimm = 0; dimm < bd_dimmp->bd_numdimms; dimm++) {
40122214Sav145390 mc_dump_dimm(buf, dnamesz, sersz, partsz);
40132214Sav145390 buf += dnamesz + sersz + partsz;
40142214Sav145390 }
40152214Sav145390 printf("======================================================\n");
40162214Sav145390 }
40172214Sav145390
40182214Sav145390
40192214Sav145390 /* ARGSUSED */
40202214Sav145390 static int
mc_ioctl_debug(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)40212214Sav145390 mc_ioctl_debug(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
40222214Sav145390 int *rvalp)
40232214Sav145390 {
40246693Swh31274 caddr_t buf, kbuf;
40252214Sav145390 uint64_t pa;
40262214Sav145390 int rv = 0;
40272214Sav145390 int i;
40282214Sav145390 uint32_t flags;
40292214Sav145390 static uint32_t offset = 0;
40302214Sav145390
40312214Sav145390
40322214Sav145390 flags = (cmd >> 4) & 0xfffffff;
40332214Sav145390
40342214Sav145390 cmd &= 0xf;
40352214Sav145390
40362214Sav145390 MC_LOG("mc_ioctl(cmd = %x, flags = %x)\n", cmd, flags);
40372214Sav145390
40382214Sav145390 if (arg != NULL) {
40392214Sav145390 if (ddi_copyin((const void *)arg, (void *)&pa,
40405080Swh31274 sizeof (uint64_t), 0) < 0) {
40412214Sav145390 rv = EFAULT;
40422214Sav145390 return (rv);
40432214Sav145390 }
40442214Sav145390 buf = NULL;
40452214Sav145390 } else {
40462214Sav145390 buf = (caddr_t)kmem_alloc(PAGESIZE, KM_SLEEP);
40472214Sav145390
40482214Sav145390 pa = va_to_pa(buf);
40492214Sav145390 pa += offset;
40502214Sav145390
40512214Sav145390 offset += 64;
40522214Sav145390 if (offset >= PAGESIZE)
40532214Sav145390 offset = 0;
40542214Sav145390 }
40552214Sav145390
40562214Sav145390 switch (cmd) {
40572214Sav145390 case MCI_CE:
405811311SSurya.Prakki@Sun.COM (void) mc_inject_error(MC_INJECT_INTERMITTENT_CE, pa, flags);
40592214Sav145390 break;
40602214Sav145390 case MCI_PERM_CE:
406111311SSurya.Prakki@Sun.COM (void) mc_inject_error(MC_INJECT_PERMANENT_CE, pa, flags);
40622214Sav145390 break;
40632214Sav145390 case MCI_UE:
406411311SSurya.Prakki@Sun.COM (void) mc_inject_error(MC_INJECT_UE, pa, flags);
40652214Sav145390 break;
40662214Sav145390 case MCI_M_CE:
406711311SSurya.Prakki@Sun.COM (void) mc_inject_error(MC_INJECT_INTERMITTENT_MCE, pa, flags);
40682214Sav145390 break;
40692214Sav145390 case MCI_M_PCE:
407011311SSurya.Prakki@Sun.COM (void) mc_inject_error(MC_INJECT_PERMANENT_MCE, pa, flags);
40712214Sav145390 break;
40722214Sav145390 case MCI_M_UE:
407311311SSurya.Prakki@Sun.COM (void) mc_inject_error(MC_INJECT_MUE, pa, flags);
40742214Sav145390 break;
40752214Sav145390 case MCI_CMP:
407611311SSurya.Prakki@Sun.COM (void) mc_inject_error(MC_INJECT_CMPE, pa, flags);
40772214Sav145390 break;
40782214Sav145390 case MCI_NOP:
407911311SSurya.Prakki@Sun.COM (void) mc_inject_error(MC_INJECT_NOP, pa, flags); break;
40802214Sav145390 case MCI_SHOW_ALL:
40812214Sav145390 mc_debug_show_all = 1;
40822214Sav145390 break;
40832214Sav145390 case MCI_SHOW_NONE:
40842214Sav145390 mc_debug_show_all = 0;
40852214Sav145390 break;
40862214Sav145390 case MCI_ALLOC:
40872214Sav145390 /*
40882214Sav145390 * just allocate some kernel memory and never free it
40892214Sav145390 * 512 MB seems to be the maximum size supported.
40902214Sav145390 */
40912214Sav145390 cmn_err(CE_NOTE, "Allocating kmem %d MB\n", flags * 512);
40922214Sav145390 for (i = 0; i < flags; i++) {
40936693Swh31274 kbuf = kmem_alloc(512 * 1024 * 1024, KM_SLEEP);
40942214Sav145390 cmn_err(CE_NOTE, "kmem buf %llx PA %llx\n",
40956693Swh31274 (u_longlong_t)kbuf, (u_longlong_t)va_to_pa(kbuf));
40962214Sav145390 }
40972214Sav145390 break;
40982214Sav145390 case MCI_SUSPEND:
40992214Sav145390 (void) opl_mc_suspend();
41002214Sav145390 break;
41012214Sav145390 case MCI_RESUME:
41022214Sav145390 (void) opl_mc_resume();
41032214Sav145390 break;
41042214Sav145390 default:
41052214Sav145390 rv = ENXIO;
41062214Sav145390 }
41076693Swh31274 if (buf)
41086693Swh31274 kmem_free(buf, PAGESIZE);
41096693Swh31274
41102214Sav145390 return (rv);
41112214Sav145390 }
41122214Sav145390
41132214Sav145390 #endif /* DEBUG */
4114