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