1*25cf1a30Sjl /* 2*25cf1a30Sjl * CDDL HEADER START 3*25cf1a30Sjl * 4*25cf1a30Sjl * The contents of this file are subject to the terms of the 5*25cf1a30Sjl * Common Development and Distribution License (the "License"). 6*25cf1a30Sjl * You may not use this file except in compliance with the License. 7*25cf1a30Sjl * 8*25cf1a30Sjl * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*25cf1a30Sjl * or http://www.opensolaris.org/os/licensing. 10*25cf1a30Sjl * See the License for the specific language governing permissions 11*25cf1a30Sjl * and limitations under the License. 12*25cf1a30Sjl * 13*25cf1a30Sjl * When distributing Covered Code, include this CDDL HEADER in each 14*25cf1a30Sjl * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*25cf1a30Sjl * If applicable, add the following below this CDDL HEADER, with the 16*25cf1a30Sjl * fields enclosed by brackets "[]" replaced with your own identifying 17*25cf1a30Sjl * information: Portions Copyright [yyyy] [name of copyright owner] 18*25cf1a30Sjl * 19*25cf1a30Sjl * CDDL HEADER END 20*25cf1a30Sjl */ 21*25cf1a30Sjl /* 22*25cf1a30Sjl * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 23*25cf1a30Sjl */ 24*25cf1a30Sjl 25*25cf1a30Sjl #pragma ident "%Z%%M% %I% %E% SMI" 26*25cf1a30Sjl 27*25cf1a30Sjl #include <sys/types.h> 28*25cf1a30Sjl #include <sys/sysmacros.h> 29*25cf1a30Sjl #include <sys/conf.h> 30*25cf1a30Sjl #include <sys/modctl.h> 31*25cf1a30Sjl #include <sys/stat.h> 32*25cf1a30Sjl #include <sys/async.h> 33*25cf1a30Sjl #include <sys/machsystm.h> 34*25cf1a30Sjl #include <sys/ksynch.h> 35*25cf1a30Sjl #include <sys/ddi.h> 36*25cf1a30Sjl #include <sys/sunddi.h> 37*25cf1a30Sjl #include <sys/ddifm.h> 38*25cf1a30Sjl #include <sys/fm/protocol.h> 39*25cf1a30Sjl #include <sys/fm/util.h> 40*25cf1a30Sjl #include <sys/kmem.h> 41*25cf1a30Sjl #include <sys/fm/io/opl_mc_fm.h> 42*25cf1a30Sjl #include <sys/memlist.h> 43*25cf1a30Sjl #include <sys/param.h> 44*25cf1a30Sjl #include <sys/ontrap.h> 45*25cf1a30Sjl #include <vm/page.h> 46*25cf1a30Sjl #include <sys/mc-opl.h> 47*25cf1a30Sjl 48*25cf1a30Sjl /* 49*25cf1a30Sjl * Function prototypes 50*25cf1a30Sjl */ 51*25cf1a30Sjl static int mc_open(dev_t *, int, int, cred_t *); 52*25cf1a30Sjl static int mc_close(dev_t, int, int, cred_t *); 53*25cf1a30Sjl static int mc_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 54*25cf1a30Sjl static int mc_attach(dev_info_t *, ddi_attach_cmd_t); 55*25cf1a30Sjl static int mc_detach(dev_info_t *, ddi_detach_cmd_t); 56*25cf1a30Sjl 57*25cf1a30Sjl static int mc_board_add(mc_opl_t *mcp); 58*25cf1a30Sjl static int mc_board_del(mc_opl_t *mcp); 59*25cf1a30Sjl static int mc_suspend(mc_opl_t *mcp, uint32_t flag); 60*25cf1a30Sjl static int mc_resume(mc_opl_t *mcp, uint32_t flag); 61*25cf1a30Sjl 62*25cf1a30Sjl static void insert_mcp(mc_opl_t *mcp); 63*25cf1a30Sjl static void delete_mcp(mc_opl_t *mcp); 64*25cf1a30Sjl 65*25cf1a30Sjl static int pa_to_maddr(mc_opl_t *mcp, uint64_t pa, mc_addr_t *maddr); 66*25cf1a30Sjl 67*25cf1a30Sjl static int mc_valid_pa(mc_opl_t *mcp, uint64_t pa); 68*25cf1a30Sjl 69*25cf1a30Sjl int mc_get_mem_unum(int, uint64_t, char *, int, int *); 70*25cf1a30Sjl extern int plat_max_boards(void); 71*25cf1a30Sjl 72*25cf1a30Sjl static void mc_get_mlist(mc_opl_t *); 73*25cf1a30Sjl 74*25cf1a30Sjl #pragma weak opl_get_physical_board 75*25cf1a30Sjl extern int opl_get_physical_board(int); 76*25cf1a30Sjl static int mc_opl_get_physical_board(int); 77*25cf1a30Sjl 78*25cf1a30Sjl /* 79*25cf1a30Sjl * Configuration data structures 80*25cf1a30Sjl */ 81*25cf1a30Sjl static struct cb_ops mc_cb_ops = { 82*25cf1a30Sjl mc_open, /* open */ 83*25cf1a30Sjl mc_close, /* close */ 84*25cf1a30Sjl nulldev, /* strategy */ 85*25cf1a30Sjl nulldev, /* print */ 86*25cf1a30Sjl nodev, /* dump */ 87*25cf1a30Sjl nulldev, /* read */ 88*25cf1a30Sjl nulldev, /* write */ 89*25cf1a30Sjl mc_ioctl, /* ioctl */ 90*25cf1a30Sjl nodev, /* devmap */ 91*25cf1a30Sjl nodev, /* mmap */ 92*25cf1a30Sjl nodev, /* segmap */ 93*25cf1a30Sjl nochpoll, /* poll */ 94*25cf1a30Sjl ddi_prop_op, /* cb_prop_op */ 95*25cf1a30Sjl 0, /* streamtab */ 96*25cf1a30Sjl D_MP | D_NEW | D_HOTPLUG, /* Driver compatibility flag */ 97*25cf1a30Sjl CB_REV, /* rev */ 98*25cf1a30Sjl nodev, /* cb_aread */ 99*25cf1a30Sjl nodev /* cb_awrite */ 100*25cf1a30Sjl }; 101*25cf1a30Sjl 102*25cf1a30Sjl static struct dev_ops mc_ops = { 103*25cf1a30Sjl DEVO_REV, /* rev */ 104*25cf1a30Sjl 0, /* refcnt */ 105*25cf1a30Sjl ddi_getinfo_1to1, /* getinfo */ 106*25cf1a30Sjl nulldev, /* identify */ 107*25cf1a30Sjl nulldev, /* probe */ 108*25cf1a30Sjl mc_attach, /* attach */ 109*25cf1a30Sjl mc_detach, /* detach */ 110*25cf1a30Sjl nulldev, /* reset */ 111*25cf1a30Sjl &mc_cb_ops, /* cb_ops */ 112*25cf1a30Sjl (struct bus_ops *)0, /* bus_ops */ 113*25cf1a30Sjl nulldev /* power */ 114*25cf1a30Sjl }; 115*25cf1a30Sjl 116*25cf1a30Sjl /* 117*25cf1a30Sjl * Driver globals 118*25cf1a30Sjl */ 119*25cf1a30Sjl int mc_patrol_interval_sec = 10; 120*25cf1a30Sjl 121*25cf1a30Sjl int inject_op_delay = 5; 122*25cf1a30Sjl 123*25cf1a30Sjl mc_inst_list_t *mc_instances; 124*25cf1a30Sjl static kmutex_t mcmutex; 125*25cf1a30Sjl 126*25cf1a30Sjl void *mc_statep; 127*25cf1a30Sjl 128*25cf1a30Sjl #ifdef DEBUG 129*25cf1a30Sjl int oplmc_debug = 1; 130*25cf1a30Sjl #endif 131*25cf1a30Sjl 132*25cf1a30Sjl static int mc_debug_show_all; 133*25cf1a30Sjl 134*25cf1a30Sjl extern struct mod_ops mod_driverops; 135*25cf1a30Sjl 136*25cf1a30Sjl static struct modldrv modldrv = { 137*25cf1a30Sjl &mod_driverops, /* module type, this one is a driver */ 138*25cf1a30Sjl "OPL Memory-controller 1.1", /* module name */ 139*25cf1a30Sjl &mc_ops, /* driver ops */ 140*25cf1a30Sjl }; 141*25cf1a30Sjl 142*25cf1a30Sjl static struct modlinkage modlinkage = { 143*25cf1a30Sjl MODREV_1, /* rev */ 144*25cf1a30Sjl (void *)&modldrv, 145*25cf1a30Sjl NULL 146*25cf1a30Sjl }; 147*25cf1a30Sjl 148*25cf1a30Sjl #pragma weak opl_get_mem_unum 149*25cf1a30Sjl extern int (*opl_get_mem_unum)(int, uint64_t, char *, int, int *); 150*25cf1a30Sjl 151*25cf1a30Sjl /* 152*25cf1a30Sjl * pseudo-mc node portid format 153*25cf1a30Sjl * 154*25cf1a30Sjl * [10] = 0 155*25cf1a30Sjl * [9] = 1 156*25cf1a30Sjl * [8] = LSB_ID[4] = 0 157*25cf1a30Sjl * [7:4] = LSB_ID[3:0] 158*25cf1a30Sjl * [3:0] = 0 159*25cf1a30Sjl * 160*25cf1a30Sjl */ 161*25cf1a30Sjl 162*25cf1a30Sjl /* 163*25cf1a30Sjl * These are the module initialization routines. 164*25cf1a30Sjl */ 165*25cf1a30Sjl int 166*25cf1a30Sjl _init(void) 167*25cf1a30Sjl { 168*25cf1a30Sjl int error; 169*25cf1a30Sjl 170*25cf1a30Sjl 171*25cf1a30Sjl if ((error = ddi_soft_state_init(&mc_statep, 172*25cf1a30Sjl sizeof (mc_opl_t), 1)) != 0) 173*25cf1a30Sjl return (error); 174*25cf1a30Sjl 175*25cf1a30Sjl mutex_init(&mcmutex, NULL, MUTEX_DRIVER, NULL); 176*25cf1a30Sjl if (&opl_get_mem_unum) 177*25cf1a30Sjl opl_get_mem_unum = mc_get_mem_unum; 178*25cf1a30Sjl 179*25cf1a30Sjl error = mod_install(&modlinkage); 180*25cf1a30Sjl if (error != 0) { 181*25cf1a30Sjl if (&opl_get_mem_unum) 182*25cf1a30Sjl opl_get_mem_unum = NULL; 183*25cf1a30Sjl mutex_destroy(&mcmutex); 184*25cf1a30Sjl ddi_soft_state_fini(&mc_statep); 185*25cf1a30Sjl } 186*25cf1a30Sjl 187*25cf1a30Sjl return (error); 188*25cf1a30Sjl } 189*25cf1a30Sjl 190*25cf1a30Sjl int 191*25cf1a30Sjl _fini(void) 192*25cf1a30Sjl { 193*25cf1a30Sjl int error; 194*25cf1a30Sjl 195*25cf1a30Sjl if ((error = mod_remove(&modlinkage)) != 0) 196*25cf1a30Sjl return (error); 197*25cf1a30Sjl 198*25cf1a30Sjl mutex_destroy(&mcmutex); 199*25cf1a30Sjl 200*25cf1a30Sjl if (&opl_get_mem_unum) 201*25cf1a30Sjl opl_get_mem_unum = NULL; 202*25cf1a30Sjl 203*25cf1a30Sjl ddi_soft_state_fini(&mc_statep); 204*25cf1a30Sjl 205*25cf1a30Sjl return (0); 206*25cf1a30Sjl } 207*25cf1a30Sjl 208*25cf1a30Sjl int 209*25cf1a30Sjl _info(struct modinfo *modinfop) 210*25cf1a30Sjl { 211*25cf1a30Sjl return (mod_info(&modlinkage, modinfop)); 212*25cf1a30Sjl } 213*25cf1a30Sjl 214*25cf1a30Sjl static int 215*25cf1a30Sjl mc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 216*25cf1a30Sjl { 217*25cf1a30Sjl mc_opl_t *mcp; 218*25cf1a30Sjl int instance; 219*25cf1a30Sjl 220*25cf1a30Sjl /* get the instance of this devi */ 221*25cf1a30Sjl instance = ddi_get_instance(devi); 222*25cf1a30Sjl 223*25cf1a30Sjl switch (cmd) { 224*25cf1a30Sjl case DDI_ATTACH: 225*25cf1a30Sjl break; 226*25cf1a30Sjl case DDI_RESUME: 227*25cf1a30Sjl mcp = ddi_get_soft_state(mc_statep, instance); 228*25cf1a30Sjl return (mc_resume(mcp, MC_DRIVER_SUSPENDED)); 229*25cf1a30Sjl default: 230*25cf1a30Sjl return (DDI_FAILURE); 231*25cf1a30Sjl } 232*25cf1a30Sjl 233*25cf1a30Sjl 234*25cf1a30Sjl if (ddi_soft_state_zalloc(mc_statep, instance) != DDI_SUCCESS) 235*25cf1a30Sjl return (DDI_FAILURE); 236*25cf1a30Sjl 237*25cf1a30Sjl if ((mcp = ddi_get_soft_state(mc_statep, instance)) == NULL) { 238*25cf1a30Sjl goto bad; 239*25cf1a30Sjl } 240*25cf1a30Sjl 241*25cf1a30Sjl /* set informations in mc state */ 242*25cf1a30Sjl mcp->mc_dip = devi; 243*25cf1a30Sjl 244*25cf1a30Sjl if (mc_board_add(mcp)) 245*25cf1a30Sjl goto bad; 246*25cf1a30Sjl 247*25cf1a30Sjl insert_mcp(mcp); 248*25cf1a30Sjl ddi_report_dev(devi); 249*25cf1a30Sjl 250*25cf1a30Sjl return (DDI_SUCCESS); 251*25cf1a30Sjl 252*25cf1a30Sjl bad: 253*25cf1a30Sjl ddi_soft_state_free(mc_statep, instance); 254*25cf1a30Sjl return (DDI_FAILURE); 255*25cf1a30Sjl } 256*25cf1a30Sjl 257*25cf1a30Sjl /* ARGSUSED */ 258*25cf1a30Sjl static int 259*25cf1a30Sjl mc_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 260*25cf1a30Sjl { 261*25cf1a30Sjl int instance; 262*25cf1a30Sjl mc_opl_t *mcp; 263*25cf1a30Sjl 264*25cf1a30Sjl /* get the instance of this devi */ 265*25cf1a30Sjl instance = ddi_get_instance(devi); 266*25cf1a30Sjl if ((mcp = ddi_get_soft_state(mc_statep, instance)) == NULL) { 267*25cf1a30Sjl return (DDI_FAILURE); 268*25cf1a30Sjl } 269*25cf1a30Sjl 270*25cf1a30Sjl switch (cmd) { 271*25cf1a30Sjl case DDI_SUSPEND: 272*25cf1a30Sjl return (mc_suspend(mcp, MC_DRIVER_SUSPENDED)); 273*25cf1a30Sjl case DDI_DETACH: 274*25cf1a30Sjl break; 275*25cf1a30Sjl default: 276*25cf1a30Sjl return (DDI_FAILURE); 277*25cf1a30Sjl } 278*25cf1a30Sjl 279*25cf1a30Sjl mutex_enter(&mcmutex); 280*25cf1a30Sjl if (mc_board_del(mcp) != DDI_SUCCESS) { 281*25cf1a30Sjl mutex_exit(&mcmutex); 282*25cf1a30Sjl return (DDI_FAILURE); 283*25cf1a30Sjl } 284*25cf1a30Sjl 285*25cf1a30Sjl delete_mcp(mcp); 286*25cf1a30Sjl mutex_exit(&mcmutex); 287*25cf1a30Sjl 288*25cf1a30Sjl /* free up the soft state */ 289*25cf1a30Sjl ddi_soft_state_free(mc_statep, instance); 290*25cf1a30Sjl 291*25cf1a30Sjl return (DDI_SUCCESS); 292*25cf1a30Sjl } 293*25cf1a30Sjl 294*25cf1a30Sjl /* ARGSUSED */ 295*25cf1a30Sjl static int 296*25cf1a30Sjl mc_open(dev_t *devp, int flag, int otyp, cred_t *credp) 297*25cf1a30Sjl { 298*25cf1a30Sjl return (0); 299*25cf1a30Sjl } 300*25cf1a30Sjl 301*25cf1a30Sjl /* ARGSUSED */ 302*25cf1a30Sjl static int 303*25cf1a30Sjl mc_close(dev_t devp, int flag, int otyp, cred_t *credp) 304*25cf1a30Sjl { 305*25cf1a30Sjl return (0); 306*25cf1a30Sjl } 307*25cf1a30Sjl 308*25cf1a30Sjl /* ARGSUSED */ 309*25cf1a30Sjl static int 310*25cf1a30Sjl mc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 311*25cf1a30Sjl int *rvalp) 312*25cf1a30Sjl { 313*25cf1a30Sjl return (ENXIO); 314*25cf1a30Sjl } 315*25cf1a30Sjl 316*25cf1a30Sjl /* 317*25cf1a30Sjl * PA validity check: 318*25cf1a30Sjl * This function return 1 if the PA is valid, otherwise 319*25cf1a30Sjl * return 0. 320*25cf1a30Sjl */ 321*25cf1a30Sjl 322*25cf1a30Sjl /* ARGSUSED */ 323*25cf1a30Sjl static int 324*25cf1a30Sjl pa_is_valid(mc_opl_t *mcp, uint64_t addr) 325*25cf1a30Sjl { 326*25cf1a30Sjl /* 327*25cf1a30Sjl * Check if the addr is on the board. 328*25cf1a30Sjl */ 329*25cf1a30Sjl if ((addr < mcp->mc_start_address) || 330*25cf1a30Sjl (mcp->mc_start_address + mcp->mc_size <= addr)) 331*25cf1a30Sjl return (0); 332*25cf1a30Sjl 333*25cf1a30Sjl if (mcp->mlist == NULL) 334*25cf1a30Sjl mc_get_mlist(mcp); 335*25cf1a30Sjl 336*25cf1a30Sjl if (mcp->mlist && address_in_memlist(mcp->mlist, addr, 0)) { 337*25cf1a30Sjl return (1); 338*25cf1a30Sjl } 339*25cf1a30Sjl return (0); 340*25cf1a30Sjl } 341*25cf1a30Sjl 342*25cf1a30Sjl /* 343*25cf1a30Sjl * mac-pa translation routines. 344*25cf1a30Sjl * 345*25cf1a30Sjl * Input: mc driver state, (LSB#, Bank#, DIMM address) 346*25cf1a30Sjl * Output: physical address 347*25cf1a30Sjl * 348*25cf1a30Sjl * Valid - return value: 0 349*25cf1a30Sjl * Invalid - return value: -1 350*25cf1a30Sjl */ 351*25cf1a30Sjl static int 352*25cf1a30Sjl mcaddr_to_pa(mc_opl_t *mcp, mc_addr_t *maddr, uint64_t *pa) 353*25cf1a30Sjl { 354*25cf1a30Sjl int i; 355*25cf1a30Sjl uint64_t pa_offset = 0; 356*25cf1a30Sjl int cs = (maddr->ma_dimm_addr >> CS_SHIFT) & 1; 357*25cf1a30Sjl int bank = maddr->ma_bank; 358*25cf1a30Sjl mc_addr_t maddr1; 359*25cf1a30Sjl int bank0, bank1; 360*25cf1a30Sjl 361*25cf1a30Sjl MC_LOG("mcaddr /LSB%d/B%d/%x\n", maddr->ma_bd, bank, 362*25cf1a30Sjl maddr->ma_dimm_addr); 363*25cf1a30Sjl 364*25cf1a30Sjl /* loc validity check */ 365*25cf1a30Sjl ASSERT(maddr->ma_bd >= 0 && OPL_BOARD_MAX > maddr->ma_bd); 366*25cf1a30Sjl ASSERT(bank >= 0 && OPL_BANK_MAX > bank); 367*25cf1a30Sjl 368*25cf1a30Sjl /* Do translation */ 369*25cf1a30Sjl for (i = 0; i < PA_BITS_FOR_MAC; i++) { 370*25cf1a30Sjl int pa_bit = 0; 371*25cf1a30Sjl int mc_bit = mcp->mc_trans_table[cs][i]; 372*25cf1a30Sjl if (mc_bit < MC_ADDRESS_BITS) { 373*25cf1a30Sjl pa_bit = (maddr->ma_dimm_addr >> mc_bit) & 1; 374*25cf1a30Sjl } else if (mc_bit == MP_NONE) { 375*25cf1a30Sjl pa_bit = 0; 376*25cf1a30Sjl } else if (mc_bit == MP_BANK_0) { 377*25cf1a30Sjl pa_bit = bank & 1; 378*25cf1a30Sjl } else if (mc_bit == MP_BANK_1) { 379*25cf1a30Sjl pa_bit = (bank >> 1) & 1; 380*25cf1a30Sjl } else if (mc_bit == MP_BANK_2) { 381*25cf1a30Sjl pa_bit = (bank >> 2) & 1; 382*25cf1a30Sjl } 383*25cf1a30Sjl pa_offset |= ((uint64_t)pa_bit) << i; 384*25cf1a30Sjl } 385*25cf1a30Sjl *pa = mcp->mc_start_address + pa_offset; 386*25cf1a30Sjl MC_LOG("pa = %lx\n", *pa); 387*25cf1a30Sjl 388*25cf1a30Sjl if (pa_to_maddr(mcp, *pa, &maddr1) == -1) { 389*25cf1a30Sjl return (-1); 390*25cf1a30Sjl } 391*25cf1a30Sjl 392*25cf1a30Sjl 393*25cf1a30Sjl if (IS_MIRROR(mcp, maddr->ma_bank)) { 394*25cf1a30Sjl bank0 = maddr->ma_bank & ~(1); 395*25cf1a30Sjl bank1 = maddr1.ma_bank & ~(1); 396*25cf1a30Sjl } else { 397*25cf1a30Sjl bank0 = maddr->ma_bank; 398*25cf1a30Sjl bank1 = maddr1.ma_bank; 399*25cf1a30Sjl } 400*25cf1a30Sjl /* 401*25cf1a30Sjl * there is no need to check ma_bd because it is generated from 402*25cf1a30Sjl * mcp. They are the same. 403*25cf1a30Sjl */ 404*25cf1a30Sjl if ((bank0 == bank1) && 405*25cf1a30Sjl (maddr->ma_dimm_addr == maddr1.ma_dimm_addr)) { 406*25cf1a30Sjl return (0); 407*25cf1a30Sjl } else { 408*25cf1a30Sjl cmn_err(CE_WARN, "Translation error source /LSB%d/B%d/%x, " 409*25cf1a30Sjl "PA %lx, target /LSB%d/B%d/%x\n", 410*25cf1a30Sjl maddr->ma_bd, bank, maddr->ma_dimm_addr, 411*25cf1a30Sjl *pa, maddr1.ma_bd, maddr1.ma_bank, 412*25cf1a30Sjl maddr1.ma_dimm_addr); 413*25cf1a30Sjl return (-1); 414*25cf1a30Sjl } 415*25cf1a30Sjl } 416*25cf1a30Sjl 417*25cf1a30Sjl /* 418*25cf1a30Sjl * PA to CS (used by pa_to_maddr). 419*25cf1a30Sjl */ 420*25cf1a30Sjl static int 421*25cf1a30Sjl pa_to_cs(mc_opl_t *mcp, uint64_t pa_offset) 422*25cf1a30Sjl { 423*25cf1a30Sjl int i; 424*25cf1a30Sjl int cs = 0; 425*25cf1a30Sjl 426*25cf1a30Sjl for (i = 0; i < PA_BITS_FOR_MAC; i++) { 427*25cf1a30Sjl /* MAC address bit<29> is arranged on the same PA bit */ 428*25cf1a30Sjl /* on both table. So we may use any table. */ 429*25cf1a30Sjl if (mcp->mc_trans_table[0][i] == CS_SHIFT) { 430*25cf1a30Sjl cs = (pa_offset >> i) & 1; 431*25cf1a30Sjl break; 432*25cf1a30Sjl } 433*25cf1a30Sjl } 434*25cf1a30Sjl return (cs); 435*25cf1a30Sjl } 436*25cf1a30Sjl 437*25cf1a30Sjl /* 438*25cf1a30Sjl * PA to DIMM (used by pa_to_maddr). 439*25cf1a30Sjl */ 440*25cf1a30Sjl /* ARGSUSED */ 441*25cf1a30Sjl static uint32_t 442*25cf1a30Sjl pa_to_dimm(mc_opl_t *mcp, uint64_t pa_offset) 443*25cf1a30Sjl { 444*25cf1a30Sjl int i; 445*25cf1a30Sjl int cs = pa_to_cs(mcp, pa_offset); 446*25cf1a30Sjl uint32_t dimm_addr = 0; 447*25cf1a30Sjl 448*25cf1a30Sjl for (i = 0; i < PA_BITS_FOR_MAC; i++) { 449*25cf1a30Sjl int pa_bit_value = (pa_offset >> i) & 1; 450*25cf1a30Sjl int mc_bit = mcp->mc_trans_table[cs][i]; 451*25cf1a30Sjl if (mc_bit < MC_ADDRESS_BITS) { 452*25cf1a30Sjl dimm_addr |= pa_bit_value << mc_bit; 453*25cf1a30Sjl } 454*25cf1a30Sjl } 455*25cf1a30Sjl return (dimm_addr); 456*25cf1a30Sjl } 457*25cf1a30Sjl 458*25cf1a30Sjl /* 459*25cf1a30Sjl * PA to Bank (used by pa_to_maddr). 460*25cf1a30Sjl */ 461*25cf1a30Sjl static int 462*25cf1a30Sjl pa_to_bank(mc_opl_t *mcp, uint64_t pa_offset) 463*25cf1a30Sjl { 464*25cf1a30Sjl int i; 465*25cf1a30Sjl int cs = pa_to_cs(mcp, pa_offset); 466*25cf1a30Sjl int bankno = mcp->mc_trans_table[cs][INDEX_OF_BANK_SUPPLEMENT_BIT]; 467*25cf1a30Sjl 468*25cf1a30Sjl 469*25cf1a30Sjl for (i = 0; i < PA_BITS_FOR_MAC; i++) { 470*25cf1a30Sjl int pa_bit_value = (pa_offset >> i) & 1; 471*25cf1a30Sjl int mc_bit = mcp->mc_trans_table[cs][i]; 472*25cf1a30Sjl switch (mc_bit) { 473*25cf1a30Sjl case MP_BANK_0: 474*25cf1a30Sjl bankno |= pa_bit_value; 475*25cf1a30Sjl break; 476*25cf1a30Sjl case MP_BANK_1: 477*25cf1a30Sjl bankno |= pa_bit_value << 1; 478*25cf1a30Sjl break; 479*25cf1a30Sjl case MP_BANK_2: 480*25cf1a30Sjl bankno |= pa_bit_value << 2; 481*25cf1a30Sjl break; 482*25cf1a30Sjl } 483*25cf1a30Sjl } 484*25cf1a30Sjl 485*25cf1a30Sjl return (bankno); 486*25cf1a30Sjl } 487*25cf1a30Sjl 488*25cf1a30Sjl /* 489*25cf1a30Sjl * PA to MAC address translation 490*25cf1a30Sjl * 491*25cf1a30Sjl * Input: MAC driver state, physicall adress 492*25cf1a30Sjl * Output: LSB#, Bank id, mac address 493*25cf1a30Sjl * 494*25cf1a30Sjl * Valid - return value: 0 495*25cf1a30Sjl * Invalid - return value: -1 496*25cf1a30Sjl */ 497*25cf1a30Sjl 498*25cf1a30Sjl int 499*25cf1a30Sjl pa_to_maddr(mc_opl_t *mcp, uint64_t pa, mc_addr_t *maddr) 500*25cf1a30Sjl { 501*25cf1a30Sjl uint64_t pa_offset; 502*25cf1a30Sjl 503*25cf1a30Sjl /* PA validity check */ 504*25cf1a30Sjl if (!pa_is_valid(mcp, pa)) 505*25cf1a30Sjl return (-1); 506*25cf1a30Sjl 507*25cf1a30Sjl 508*25cf1a30Sjl /* Do translation */ 509*25cf1a30Sjl pa_offset = pa - mcp->mc_start_address; 510*25cf1a30Sjl 511*25cf1a30Sjl maddr->ma_bd = mcp->mc_board_num; 512*25cf1a30Sjl maddr->ma_bank = pa_to_bank(mcp, pa_offset); 513*25cf1a30Sjl maddr->ma_dimm_addr = pa_to_dimm(mcp, pa_offset); 514*25cf1a30Sjl MC_LOG("pa %lx -> mcaddr /LSB%d/B%d/%x\n", 515*25cf1a30Sjl pa_offset, maddr->ma_bd, maddr->ma_bank, maddr->ma_dimm_addr); 516*25cf1a30Sjl return (0); 517*25cf1a30Sjl } 518*25cf1a30Sjl 519*25cf1a30Sjl static void 520*25cf1a30Sjl mc_ereport_post(mc_aflt_t *mc_aflt) 521*25cf1a30Sjl { 522*25cf1a30Sjl char buf[FM_MAX_CLASS]; 523*25cf1a30Sjl char device_path[MAXPATHLEN]; 524*25cf1a30Sjl nv_alloc_t *nva = NULL; 525*25cf1a30Sjl nvlist_t *ereport, *detector, *resource; 526*25cf1a30Sjl errorq_elem_t *eqep; 527*25cf1a30Sjl int nflts; 528*25cf1a30Sjl mc_flt_stat_t *flt_stat; 529*25cf1a30Sjl int i, n, blen; 530*25cf1a30Sjl char *p; 531*25cf1a30Sjl uint32_t values[2], synd[2], dslot[2]; 532*25cf1a30Sjl 533*25cf1a30Sjl if (panicstr) { 534*25cf1a30Sjl eqep = errorq_reserve(ereport_errorq); 535*25cf1a30Sjl if (eqep == NULL) 536*25cf1a30Sjl return; 537*25cf1a30Sjl ereport = errorq_elem_nvl(ereport_errorq, eqep); 538*25cf1a30Sjl nva = errorq_elem_nva(ereport_errorq, eqep); 539*25cf1a30Sjl } else { 540*25cf1a30Sjl ereport = fm_nvlist_create(nva); 541*25cf1a30Sjl } 542*25cf1a30Sjl 543*25cf1a30Sjl /* 544*25cf1a30Sjl * Create the scheme "dev" FMRI. 545*25cf1a30Sjl */ 546*25cf1a30Sjl detector = fm_nvlist_create(nva); 547*25cf1a30Sjl resource = fm_nvlist_create(nva); 548*25cf1a30Sjl 549*25cf1a30Sjl nflts = mc_aflt->mflt_nflts; 550*25cf1a30Sjl 551*25cf1a30Sjl ASSERT(nflts >= 1 && nflts <= 2); 552*25cf1a30Sjl 553*25cf1a30Sjl flt_stat = mc_aflt->mflt_stat[0]; 554*25cf1a30Sjl (void) ddi_pathname(mc_aflt->mflt_mcp->mc_dip, device_path); 555*25cf1a30Sjl (void) fm_fmri_dev_set(detector, FM_DEV_SCHEME_VERSION, NULL, 556*25cf1a30Sjl device_path, NULL); 557*25cf1a30Sjl 558*25cf1a30Sjl /* 559*25cf1a30Sjl * Encode all the common data into the ereport. 560*25cf1a30Sjl */ 561*25cf1a30Sjl (void) snprintf(buf, FM_MAX_CLASS, "%s.%s-%s", 562*25cf1a30Sjl MC_OPL_ERROR_CLASS, 563*25cf1a30Sjl mc_aflt->mflt_is_ptrl ? MC_OPL_PTRL_SUBCLASS : 564*25cf1a30Sjl MC_OPL_MI_SUBCLASS, 565*25cf1a30Sjl mc_aflt->mflt_erpt_class); 566*25cf1a30Sjl 567*25cf1a30Sjl MC_LOG("mc_ereport_post: ereport %s\n", buf); 568*25cf1a30Sjl 569*25cf1a30Sjl 570*25cf1a30Sjl fm_ereport_set(ereport, FM_EREPORT_VERSION, buf, 571*25cf1a30Sjl fm_ena_generate(mc_aflt->mflt_id, FM_ENA_FMT1), 572*25cf1a30Sjl detector, NULL); 573*25cf1a30Sjl 574*25cf1a30Sjl /* 575*25cf1a30Sjl * Set payload. 576*25cf1a30Sjl */ 577*25cf1a30Sjl fm_payload_set(ereport, MC_OPL_BOARD, DATA_TYPE_UINT32, 578*25cf1a30Sjl flt_stat->mf_flt_maddr.ma_bd, NULL); 579*25cf1a30Sjl 580*25cf1a30Sjl fm_payload_set(ereport, MC_OPL_PA, DATA_TYPE_UINT64, 581*25cf1a30Sjl flt_stat->mf_flt_paddr, NULL); 582*25cf1a30Sjl 583*25cf1a30Sjl if (flt_stat->mf_type == FLT_TYPE_PERMANENT_CE) { 584*25cf1a30Sjl fm_payload_set(ereport, MC_OPL_FLT_TYPE, 585*25cf1a30Sjl DATA_TYPE_UINT8, ECC_STICKY, NULL); 586*25cf1a30Sjl } 587*25cf1a30Sjl 588*25cf1a30Sjl for (i = 0; i < nflts; i++) 589*25cf1a30Sjl values[i] = mc_aflt->mflt_stat[i]->mf_flt_maddr.ma_bank; 590*25cf1a30Sjl 591*25cf1a30Sjl fm_payload_set(ereport, MC_OPL_BANK, DATA_TYPE_UINT32_ARRAY, 592*25cf1a30Sjl nflts, values, NULL); 593*25cf1a30Sjl 594*25cf1a30Sjl for (i = 0; i < nflts; i++) 595*25cf1a30Sjl values[i] = mc_aflt->mflt_stat[i]->mf_cntl; 596*25cf1a30Sjl 597*25cf1a30Sjl fm_payload_set(ereport, MC_OPL_STATUS, DATA_TYPE_UINT32_ARRAY, 598*25cf1a30Sjl nflts, values, NULL); 599*25cf1a30Sjl 600*25cf1a30Sjl for (i = 0; i < nflts; i++) 601*25cf1a30Sjl values[i] = mc_aflt->mflt_stat[i]->mf_err_add; 602*25cf1a30Sjl 603*25cf1a30Sjl fm_payload_set(ereport, MC_OPL_ERR_ADD, DATA_TYPE_UINT32_ARRAY, 604*25cf1a30Sjl nflts, values, NULL); 605*25cf1a30Sjl 606*25cf1a30Sjl for (i = 0; i < nflts; i++) 607*25cf1a30Sjl values[i] = mc_aflt->mflt_stat[i]->mf_err_log; 608*25cf1a30Sjl 609*25cf1a30Sjl fm_payload_set(ereport, MC_OPL_ERR_LOG, DATA_TYPE_UINT32_ARRAY, 610*25cf1a30Sjl nflts, values, NULL); 611*25cf1a30Sjl 612*25cf1a30Sjl for (i = 0; i < nflts; i++) { 613*25cf1a30Sjl flt_stat = mc_aflt->mflt_stat[i]; 614*25cf1a30Sjl if (flt_stat->mf_errlog_valid) { 615*25cf1a30Sjl synd[i] = flt_stat->mf_synd; 616*25cf1a30Sjl dslot[i] = flt_stat->mf_dimm_slot; 617*25cf1a30Sjl values[i] = flt_stat->mf_dram_place; 618*25cf1a30Sjl } else { 619*25cf1a30Sjl synd[i] = 0; 620*25cf1a30Sjl dslot[i] = 0; 621*25cf1a30Sjl values[i] = 0; 622*25cf1a30Sjl } 623*25cf1a30Sjl } 624*25cf1a30Sjl 625*25cf1a30Sjl fm_payload_set(ereport, MC_OPL_ERR_SYND, 626*25cf1a30Sjl DATA_TYPE_UINT32_ARRAY, nflts, synd, NULL); 627*25cf1a30Sjl 628*25cf1a30Sjl fm_payload_set(ereport, MC_OPL_ERR_DIMMSLOT, 629*25cf1a30Sjl DATA_TYPE_UINT32_ARRAY, nflts, dslot, NULL); 630*25cf1a30Sjl 631*25cf1a30Sjl fm_payload_set(ereport, MC_OPL_ERR_DRAM, 632*25cf1a30Sjl DATA_TYPE_UINT32_ARRAY, nflts, values, NULL); 633*25cf1a30Sjl 634*25cf1a30Sjl blen = MAXPATHLEN; 635*25cf1a30Sjl device_path[0] = 0; 636*25cf1a30Sjl p = &device_path[0]; 637*25cf1a30Sjl 638*25cf1a30Sjl for (i = 0; i < nflts; i++) { 639*25cf1a30Sjl int bank = flt_stat->mf_flt_maddr.ma_bank; 640*25cf1a30Sjl int psb = -1; 641*25cf1a30Sjl 642*25cf1a30Sjl flt_stat = mc_aflt->mflt_stat[i]; 643*25cf1a30Sjl psb = mc_opl_get_physical_board( 644*25cf1a30Sjl flt_stat->mf_flt_maddr.ma_bd); 645*25cf1a30Sjl 646*25cf1a30Sjl if (psb != -1) { 647*25cf1a30Sjl snprintf(p, blen, "/CMU%d/B%d", psb, bank); 648*25cf1a30Sjl } else { 649*25cf1a30Sjl snprintf(p, blen, "/CMU/B%d", bank); 650*25cf1a30Sjl } 651*25cf1a30Sjl 652*25cf1a30Sjl if (flt_stat->mf_errlog_valid) { 653*25cf1a30Sjl snprintf(p + strlen(p), blen, "/MEM%d%d%c", 654*25cf1a30Sjl bank/2, (bank & 0x1) * 2 + dslot[i] & 1, 655*25cf1a30Sjl (dslot[i] & 0x2) ? 'B' : 'A'); 656*25cf1a30Sjl } 657*25cf1a30Sjl 658*25cf1a30Sjl n = strlen(&device_path[0]); 659*25cf1a30Sjl blen = MAXPATHLEN - n; 660*25cf1a30Sjl p = &device_path[n]; 661*25cf1a30Sjl if (i < (nflts - 1)) { 662*25cf1a30Sjl snprintf(p, blen, " "); 663*25cf1a30Sjl n += 1; blen -= 1; p += 1; 664*25cf1a30Sjl } 665*25cf1a30Sjl } 666*25cf1a30Sjl 667*25cf1a30Sjl /* 668*25cf1a30Sjl * UNUM format /LSB#/B#/MEMxyZ 669*25cf1a30Sjl * where x is the MAC# = Bank#/2 670*25cf1a30Sjl * y is slot info = (Bank# & 0x1)*2 + {0, 1} 0 for DIMM-L, 1 for DIMM-H 671*25cf1a30Sjl * DIMM-L is 0 in bit 13, DIMM-H is 1 in bit 13. 672*25cf1a30Sjl * Z is A(CS0) or B(CS1) given by bit 14 673*25cf1a30Sjl */ 674*25cf1a30Sjl (void) fm_fmri_mem_set(resource, FM_MEM_SCHEME_VERSION, 675*25cf1a30Sjl NULL, device_path, NULL, 0); 676*25cf1a30Sjl 677*25cf1a30Sjl fm_payload_set(ereport, MC_OPL_RESOURCE, DATA_TYPE_NVLIST, 678*25cf1a30Sjl resource, NULL); 679*25cf1a30Sjl 680*25cf1a30Sjl if (panicstr) { 681*25cf1a30Sjl errorq_commit(ereport_errorq, eqep, ERRORQ_SYNC); 682*25cf1a30Sjl } else { 683*25cf1a30Sjl (void) fm_ereport_post(ereport, EVCH_TRYHARD); 684*25cf1a30Sjl fm_nvlist_destroy(ereport, FM_NVA_FREE); 685*25cf1a30Sjl fm_nvlist_destroy(detector, FM_NVA_FREE); 686*25cf1a30Sjl fm_nvlist_destroy(resource, FM_NVA_FREE); 687*25cf1a30Sjl } 688*25cf1a30Sjl } 689*25cf1a30Sjl 690*25cf1a30Sjl static void 691*25cf1a30Sjl mc_err_drain(mc_aflt_t *mc_aflt) 692*25cf1a30Sjl { 693*25cf1a30Sjl int rv; 694*25cf1a30Sjl page_t *pp; 695*25cf1a30Sjl uint64_t errors; 696*25cf1a30Sjl uint64_t pa = (uint64_t)(-1); 697*25cf1a30Sjl 698*25cf1a30Sjl MC_LOG("mc_err_drain: %s\n", 699*25cf1a30Sjl mc_aflt->mflt_erpt_class); 700*25cf1a30Sjl /* 701*25cf1a30Sjl * we come here only when we have: 702*25cf1a30Sjl * In mirror mode: CMPE, MUE, SUE 703*25cf1a30Sjl * In normal mode: UE, Permanent CE 704*25cf1a30Sjl */ 705*25cf1a30Sjl rv = mcaddr_to_pa(mc_aflt->mflt_mcp, 706*25cf1a30Sjl &(mc_aflt->mflt_stat[0]->mf_flt_maddr), &pa); 707*25cf1a30Sjl if (rv == 0) 708*25cf1a30Sjl mc_aflt->mflt_stat[0]->mf_flt_paddr = pa; 709*25cf1a30Sjl else 710*25cf1a30Sjl mc_aflt->mflt_stat[0]->mf_flt_paddr = (uint64_t)-1; 711*25cf1a30Sjl if (rv == 0) { 712*25cf1a30Sjl MC_LOG("mc_err_drain:pa = %lx\n", pa); 713*25cf1a30Sjl pp = page_numtopp_nolock(pa >> PAGESHIFT); 714*25cf1a30Sjl 715*25cf1a30Sjl if (pp) { 716*25cf1a30Sjl /* 717*25cf1a30Sjl * Don't keep retiring and make ereports 718*25cf1a30Sjl * on bad pages in PTRL case 719*25cf1a30Sjl */ 720*25cf1a30Sjl MC_LOG("mc_err_drain:pp = %p\n", pp); 721*25cf1a30Sjl if (mc_aflt->mflt_is_ptrl) { 722*25cf1a30Sjl errors = 0; 723*25cf1a30Sjl if (page_retire_check(pa, &errors) == 0) { 724*25cf1a30Sjl MC_LOG("Page retired\n"); 725*25cf1a30Sjl return; 726*25cf1a30Sjl } 727*25cf1a30Sjl if (errors & mc_aflt->mflt_pr) { 728*25cf1a30Sjl MC_LOG("errors %lx, mflt_pr %x\n", 729*25cf1a30Sjl errors, mc_aflt->mflt_pr); 730*25cf1a30Sjl return; 731*25cf1a30Sjl } 732*25cf1a30Sjl } 733*25cf1a30Sjl MC_LOG("offline page %p error %x\n", pp, 734*25cf1a30Sjl mc_aflt->mflt_pr); 735*25cf1a30Sjl (void) page_retire(pa, mc_aflt->mflt_pr); 736*25cf1a30Sjl } 737*25cf1a30Sjl } 738*25cf1a30Sjl mc_ereport_post(mc_aflt); 739*25cf1a30Sjl } 740*25cf1a30Sjl 741*25cf1a30Sjl #define DIMM_SIZE 0x80000000 742*25cf1a30Sjl 743*25cf1a30Sjl #define INC_DIMM_ADDR(p, n) \ 744*25cf1a30Sjl (p)->ma_dimm_addr += n; \ 745*25cf1a30Sjl (p)->ma_dimm_addr &= (DIMM_SIZE - 1) 746*25cf1a30Sjl 747*25cf1a30Sjl /* 748*25cf1a30Sjl * The restart address is actually defined in unit of PA[37:6] 749*25cf1a30Sjl * the mac patrol will convert that to dimm offset. If the 750*25cf1a30Sjl * address is not in the bank, it will continue to search for 751*25cf1a30Sjl * the next PA that is within the bank. 752*25cf1a30Sjl * 753*25cf1a30Sjl * Also the mac patrol scans the dimms based on PA, not 754*25cf1a30Sjl * dimm offset. 755*25cf1a30Sjl */ 756*25cf1a30Sjl 757*25cf1a30Sjl static int 758*25cf1a30Sjl restart_patrol(mc_opl_t *mcp, int bank, mc_addr_info_t *maddr_info) 759*25cf1a30Sjl { 760*25cf1a30Sjl page_t *pp; 761*25cf1a30Sjl uint32_t reg; 762*25cf1a30Sjl uint64_t pa; 763*25cf1a30Sjl int rv; 764*25cf1a30Sjl int loop_count = 0; 765*25cf1a30Sjl 766*25cf1a30Sjl reg = ldphysio(MAC_PTRL_CNTL(mcp, bank)); 767*25cf1a30Sjl 768*25cf1a30Sjl /* already running, so we just return */ 769*25cf1a30Sjl if (reg & MAC_CNTL_PTRL_START) 770*25cf1a30Sjl return (0); 771*25cf1a30Sjl 772*25cf1a30Sjl if (maddr_info == NULL || (maddr_info->mi_valid == 0)) { 773*25cf1a30Sjl MAC_PTRL_START(mcp, bank); 774*25cf1a30Sjl return (0); 775*25cf1a30Sjl } 776*25cf1a30Sjl 777*25cf1a30Sjl 778*25cf1a30Sjl rv = mcaddr_to_pa(mcp, &maddr_info->mi_maddr, &pa); 779*25cf1a30Sjl if (rv != 0) { 780*25cf1a30Sjl MC_LOG("cannot convert mcaddr to pa. use auto restart\n"); 781*25cf1a30Sjl MAC_PTRL_START(mcp, bank); 782*25cf1a30Sjl return (0); 783*25cf1a30Sjl } 784*25cf1a30Sjl 785*25cf1a30Sjl /* 786*25cf1a30Sjl * pa is the last address scanned by the mac patrol 787*25cf1a30Sjl * we calculate the next restart address as follows: 788*25cf1a30Sjl * first we always advance it by 64 byte. Then begin the loop. 789*25cf1a30Sjl * loop { 790*25cf1a30Sjl * if it is not in phys_install, we advance to next 64 MB boundary 791*25cf1a30Sjl * if it is not backed by a page structure, done 792*25cf1a30Sjl * if the page is bad, advance to the next page boundary. 793*25cf1a30Sjl * else done 794*25cf1a30Sjl * if the new address exceeds the board, wrap around. 795*25cf1a30Sjl * } <stop if we come back to the same page> 796*25cf1a30Sjl */ 797*25cf1a30Sjl 798*25cf1a30Sjl if (pa < mcp->mc_start_address || pa >= (mcp->mc_start_address 799*25cf1a30Sjl + mcp->mc_size)) { 800*25cf1a30Sjl /* pa is not on this board, just retry */ 801*25cf1a30Sjl cmn_err(CE_WARN, "restart_patrol: invalid address %lx " 802*25cf1a30Sjl "on board %d\n", pa, mcp->mc_board_num); 803*25cf1a30Sjl MAC_PTRL_START(mcp, bank); 804*25cf1a30Sjl return (0); 805*25cf1a30Sjl } 806*25cf1a30Sjl 807*25cf1a30Sjl MC_LOG("restart_patrol: pa = %lx\n", pa); 808*25cf1a30Sjl if (maddr_info->mi_advance) { 809*25cf1a30Sjl uint64_t new_pa; 810*25cf1a30Sjl 811*25cf1a30Sjl if (IS_MIRROR(mcp, bank)) 812*25cf1a30Sjl new_pa = pa + 64 * 2; 813*25cf1a30Sjl else 814*25cf1a30Sjl new_pa = pa + 64; 815*25cf1a30Sjl 816*25cf1a30Sjl if (!mc_valid_pa(mcp, new_pa)) { 817*25cf1a30Sjl /* Isolation unit size is 64 MB */ 818*25cf1a30Sjl #define MC_ISOLATION_BSIZE (64 * 1024 * 1024) 819*25cf1a30Sjl MC_LOG("Invalid PA\n"); 820*25cf1a30Sjl pa = roundup(new_pa + 1, MC_ISOLATION_BSIZE); 821*25cf1a30Sjl } else { 822*25cf1a30Sjl pp = page_numtopp_nolock(new_pa >> PAGESHIFT); 823*25cf1a30Sjl if (pp != NULL) { 824*25cf1a30Sjl uint64_t errors = 0; 825*25cf1a30Sjl if (page_retire_check(new_pa, &errors) && 826*25cf1a30Sjl (errors == 0)) { 827*25cf1a30Sjl MC_LOG("Page has no error\n"); 828*25cf1a30Sjl MAC_PTRL_START(mcp, bank); 829*25cf1a30Sjl return (0); 830*25cf1a30Sjl } 831*25cf1a30Sjl /* 832*25cf1a30Sjl * skip bad pages 833*25cf1a30Sjl * and let the following loop to take care 834*25cf1a30Sjl */ 835*25cf1a30Sjl pa = roundup(new_pa + 1, PAGESIZE); 836*25cf1a30Sjl MC_LOG("Skipping bad page to %lx\n", pa); 837*25cf1a30Sjl } else { 838*25cf1a30Sjl MC_LOG("Page has no page structure\n"); 839*25cf1a30Sjl MAC_PTRL_START(mcp, bank); 840*25cf1a30Sjl return (0); 841*25cf1a30Sjl } 842*25cf1a30Sjl } 843*25cf1a30Sjl } 844*25cf1a30Sjl 845*25cf1a30Sjl /* 846*25cf1a30Sjl * if we wrap around twice, we just give up and let 847*25cf1a30Sjl * mac patrol decide. 848*25cf1a30Sjl */ 849*25cf1a30Sjl MC_LOG("pa is now %lx\n", pa); 850*25cf1a30Sjl while (loop_count <= 1) { 851*25cf1a30Sjl if (!mc_valid_pa(mcp, pa)) { 852*25cf1a30Sjl MC_LOG("pa is not valid. round up to 64 MB\n"); 853*25cf1a30Sjl pa = roundup(pa + 1, 64 * 1024 * 1024); 854*25cf1a30Sjl } else { 855*25cf1a30Sjl pp = page_numtopp_nolock(pa >> PAGESHIFT); 856*25cf1a30Sjl if (pp != NULL) { 857*25cf1a30Sjl uint64_t errors = 0; 858*25cf1a30Sjl if (page_retire_check(pa, &errors) && 859*25cf1a30Sjl (errors == 0)) { 860*25cf1a30Sjl MC_LOG("Page has no error\n"); 861*25cf1a30Sjl break; 862*25cf1a30Sjl } 863*25cf1a30Sjl /* skip bad pages */ 864*25cf1a30Sjl pa = roundup(pa + 1, PAGESIZE); 865*25cf1a30Sjl MC_LOG("Skipping bad page to %lx\n", pa); 866*25cf1a30Sjl } else { 867*25cf1a30Sjl MC_LOG("Page has no page structure\n"); 868*25cf1a30Sjl break; 869*25cf1a30Sjl } 870*25cf1a30Sjl } 871*25cf1a30Sjl if (pa >= (mcp->mc_start_address + mcp->mc_size)) { 872*25cf1a30Sjl MC_LOG("Wrap around\n"); 873*25cf1a30Sjl pa = mcp->mc_start_address; 874*25cf1a30Sjl loop_count++; 875*25cf1a30Sjl } 876*25cf1a30Sjl } 877*25cf1a30Sjl 878*25cf1a30Sjl /* retstart MAC patrol: PA[37:6] */ 879*25cf1a30Sjl MC_LOG("restart at pa = %lx\n", pa); 880*25cf1a30Sjl ST_MAC_REG(MAC_RESTART_ADD(mcp, bank), MAC_RESTART_PA(pa)); 881*25cf1a30Sjl MAC_PTRL_START_ADD(mcp, bank); 882*25cf1a30Sjl 883*25cf1a30Sjl return (0); 884*25cf1a30Sjl } 885*25cf1a30Sjl 886*25cf1a30Sjl /* 887*25cf1a30Sjl * Rewriting is used for two purposes. 888*25cf1a30Sjl * - to correct the error in memory. 889*25cf1a30Sjl * - to determine whether the error is permanent or intermittent. 890*25cf1a30Sjl * It's done by writing the address in MAC_BANKm_REWRITE_ADD 891*25cf1a30Sjl * and issuing REW_REQ command in MAC_BANKm_PTRL_CNRL. After that, 892*25cf1a30Sjl * REW_END (and REW_CE/REW_UE if some error detected) is set when 893*25cf1a30Sjl * rewrite operation is done. See 4.7.3 and 4.7.11 in Columbus2 PRM. 894*25cf1a30Sjl * 895*25cf1a30Sjl * Note that rewrite operation doesn't change RAW_UE to Marked UE. 896*25cf1a30Sjl * Therefore, we use it only CE case. 897*25cf1a30Sjl */ 898*25cf1a30Sjl static uint32_t 899*25cf1a30Sjl do_rewrite(mc_opl_t *mcp, int bank, uint32_t dimm_addr) 900*25cf1a30Sjl { 901*25cf1a30Sjl uint32_t cntl; 902*25cf1a30Sjl int count = 0; 903*25cf1a30Sjl 904*25cf1a30Sjl /* first wait to make sure PTRL_STATUS is 0 */ 905*25cf1a30Sjl while (count++ < MAX_MC_LOOP_COUNT) { 906*25cf1a30Sjl cntl = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank)); 907*25cf1a30Sjl if (!(cntl & MAC_CNTL_PTRL_STATUS)) 908*25cf1a30Sjl break; 909*25cf1a30Sjl delay(drv_usectohz(10 * 1000)); /* 10 m.s. */ 910*25cf1a30Sjl } 911*25cf1a30Sjl if (count >= MAX_MC_LOOP_COUNT) 912*25cf1a30Sjl goto bad; 913*25cf1a30Sjl 914*25cf1a30Sjl count = 0; 915*25cf1a30Sjl 916*25cf1a30Sjl ST_MAC_REG(MAC_REWRITE_ADD(mcp, bank), dimm_addr); 917*25cf1a30Sjl MAC_REW_REQ(mcp, bank); 918*25cf1a30Sjl 919*25cf1a30Sjl do { 920*25cf1a30Sjl cntl = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank)); 921*25cf1a30Sjl if (count++ >= MAX_MC_LOOP_COUNT) { 922*25cf1a30Sjl goto bad; 923*25cf1a30Sjl } else 924*25cf1a30Sjl delay(drv_usectohz(10 * 1000)); /* 10 m.s. */ 925*25cf1a30Sjl /* 926*25cf1a30Sjl * If there are other MEMORY or PCI activities, this 927*25cf1a30Sjl * will be BUSY, else it should be set immediately 928*25cf1a30Sjl */ 929*25cf1a30Sjl } while (!(cntl & MAC_CNTL_REW_END)); 930*25cf1a30Sjl 931*25cf1a30Sjl MAC_CLEAR_ERRS(mcp, bank, MAC_CNTL_REW_ERRS); 932*25cf1a30Sjl return (cntl); 933*25cf1a30Sjl bad: 934*25cf1a30Sjl /* This is bad. Just reset the circuit */ 935*25cf1a30Sjl cmn_err(CE_WARN, "mc-opl rewrite timeout on /LSB%d/B%d\n", 936*25cf1a30Sjl mcp->mc_board_num, bank); 937*25cf1a30Sjl cntl = MAC_CNTL_REW_END; 938*25cf1a30Sjl MAC_CMD(mcp, bank, MAC_CNTL_PTRL_RESET); 939*25cf1a30Sjl MAC_CLEAR_ERRS(mcp, bank, MAC_CNTL_REW_ERRS); 940*25cf1a30Sjl return (cntl); 941*25cf1a30Sjl } 942*25cf1a30Sjl 943*25cf1a30Sjl void 944*25cf1a30Sjl mc_process_scf_log(mc_opl_t *mcp) 945*25cf1a30Sjl { 946*25cf1a30Sjl int count = 0; 947*25cf1a30Sjl scf_log_t *p; 948*25cf1a30Sjl int bank; 949*25cf1a30Sjl 950*25cf1a30Sjl while ((p = mcp->mc_scf_log) != NULL) { 951*25cf1a30Sjl bank = p->sl_bank; 952*25cf1a30Sjl while ((LD_MAC_REG(MAC_STATIC_ERR_ADD(mcp, p->sl_bank)) 953*25cf1a30Sjl & MAC_STATIC_ERR_VLD)) { 954*25cf1a30Sjl if (count++ >= (MAX_MC_LOOP_COUNT)) { 955*25cf1a30Sjl break; 956*25cf1a30Sjl } 957*25cf1a30Sjl delay(drv_usectohz(10 * 1000)); /* 10 m.s. */ 958*25cf1a30Sjl } 959*25cf1a30Sjl 960*25cf1a30Sjl if (count < MAX_MC_LOOP_COUNT) { 961*25cf1a30Sjl ST_MAC_REG(MAC_STATIC_ERR_LOG(mcp, p->sl_bank), 962*25cf1a30Sjl p->sl_err_log); 963*25cf1a30Sjl 964*25cf1a30Sjl ST_MAC_REG(MAC_STATIC_ERR_ADD(mcp, p->sl_bank), 965*25cf1a30Sjl p->sl_err_add|MAC_STATIC_ERR_VLD); 966*25cf1a30Sjl mcp->mc_scf_retry[bank] = 0; 967*25cf1a30Sjl } else { 968*25cf1a30Sjl /* if we try too many times, just drop the req */ 969*25cf1a30Sjl if (mcp->mc_scf_retry[bank]++ <= MAX_SCF_RETRY) { 970*25cf1a30Sjl return; 971*25cf1a30Sjl } else { 972*25cf1a30Sjl cmn_err(CE_WARN, "SCF is not responding. " 973*25cf1a30Sjl "Dropping the SCF LOG\n"); 974*25cf1a30Sjl } 975*25cf1a30Sjl } 976*25cf1a30Sjl mcp->mc_scf_log = p->sl_next; 977*25cf1a30Sjl mcp->mc_scf_total--; 978*25cf1a30Sjl ASSERT(mcp->mc_scf_total >= 0); 979*25cf1a30Sjl kmem_free(p, sizeof (scf_log_t)); 980*25cf1a30Sjl } 981*25cf1a30Sjl } 982*25cf1a30Sjl 983*25cf1a30Sjl void 984*25cf1a30Sjl mc_queue_scf_log(mc_opl_t *mcp, mc_flt_stat_t *flt_stat, int bank) 985*25cf1a30Sjl { 986*25cf1a30Sjl scf_log_t *p; 987*25cf1a30Sjl 988*25cf1a30Sjl if (mcp->mc_scf_total >= MAX_SCF_LOGS) { 989*25cf1a30Sjl cmn_err(CE_WARN, 990*25cf1a30Sjl "Max# SCF logs excceded on /LSB%d/B%d\n", 991*25cf1a30Sjl mcp->mc_board_num, bank); 992*25cf1a30Sjl return; 993*25cf1a30Sjl } 994*25cf1a30Sjl p = kmem_zalloc(sizeof (scf_log_t), KM_SLEEP); 995*25cf1a30Sjl p->sl_next = 0; 996*25cf1a30Sjl p->sl_err_add = flt_stat->mf_err_add; 997*25cf1a30Sjl p->sl_err_log = flt_stat->mf_err_log; 998*25cf1a30Sjl p->sl_bank = bank; 999*25cf1a30Sjl 1000*25cf1a30Sjl if (mcp->mc_scf_log == NULL) { 1001*25cf1a30Sjl /* 1002*25cf1a30Sjl * we rely on mc_scf_log to detect NULL queue. 1003*25cf1a30Sjl * mc_scf_log_tail is irrelevant is such case. 1004*25cf1a30Sjl */ 1005*25cf1a30Sjl mcp->mc_scf_log_tail = mcp->mc_scf_log = p; 1006*25cf1a30Sjl } else { 1007*25cf1a30Sjl mcp->mc_scf_log_tail->sl_next = p; 1008*25cf1a30Sjl mcp->mc_scf_log_tail = p; 1009*25cf1a30Sjl } 1010*25cf1a30Sjl mcp->mc_scf_total++; 1011*25cf1a30Sjl } 1012*25cf1a30Sjl 1013*25cf1a30Sjl /* 1014*25cf1a30Sjl * This routine determines what kind of CE happens, intermittent 1015*25cf1a30Sjl * or permanent as follows. (See 4.7.3 in Columbus2 PRM.) 1016*25cf1a30Sjl * - Do rewrite by issuing REW_REQ command to MAC_PTRL_CNTL register. 1017*25cf1a30Sjl * - If CE is still detected on the same address even after doing 1018*25cf1a30Sjl * rewrite operation twice, it is determined as permanent error. 1019*25cf1a30Sjl * - If error is not detected anymore, it is determined as intermittent 1020*25cf1a30Sjl * error. 1021*25cf1a30Sjl * - If UE is detected due to rewrite operation, it should be treated 1022*25cf1a30Sjl * as UE. 1023*25cf1a30Sjl */ 1024*25cf1a30Sjl 1025*25cf1a30Sjl /* ARGSUSED */ 1026*25cf1a30Sjl static void 1027*25cf1a30Sjl mc_scrub_ce(mc_opl_t *mcp, int bank, mc_flt_stat_t *flt_stat, int ptrl_error) 1028*25cf1a30Sjl { 1029*25cf1a30Sjl uint32_t cntl; 1030*25cf1a30Sjl int i; 1031*25cf1a30Sjl 1032*25cf1a30Sjl flt_stat->mf_type = FLT_TYPE_PERMANENT_CE; 1033*25cf1a30Sjl /* 1034*25cf1a30Sjl * rewrite request 1st time reads and correct error data 1035*25cf1a30Sjl * and write to DIMM. 2nd rewrite request must be issued 1036*25cf1a30Sjl * after REW_CE/UE/END is 0. When the 2nd request is completed, 1037*25cf1a30Sjl * if REW_CE = 1, then it is permanent CE. 1038*25cf1a30Sjl */ 1039*25cf1a30Sjl for (i = 0; i < 2; i++) { 1040*25cf1a30Sjl cntl = do_rewrite(mcp, bank, flt_stat->mf_err_add); 1041*25cf1a30Sjl /* 1042*25cf1a30Sjl * If the error becomes UE or CMPE 1043*25cf1a30Sjl * we return to the caller immediately. 1044*25cf1a30Sjl */ 1045*25cf1a30Sjl if (cntl & MAC_CNTL_REW_UE) { 1046*25cf1a30Sjl if (ptrl_error) 1047*25cf1a30Sjl flt_stat->mf_cntl |= MAC_CNTL_PTRL_UE; 1048*25cf1a30Sjl else 1049*25cf1a30Sjl flt_stat->mf_cntl |= MAC_CNTL_MI_UE; 1050*25cf1a30Sjl flt_stat->mf_type = FLT_TYPE_UE; 1051*25cf1a30Sjl return; 1052*25cf1a30Sjl } 1053*25cf1a30Sjl if (cntl & MAC_CNTL_REW_CMPE) { 1054*25cf1a30Sjl if (ptrl_error) 1055*25cf1a30Sjl flt_stat->mf_cntl |= MAC_CNTL_PTRL_CMPE; 1056*25cf1a30Sjl else 1057*25cf1a30Sjl flt_stat->mf_cntl |= MAC_CNTL_MI_CMPE; 1058*25cf1a30Sjl flt_stat->mf_type = FLT_TYPE_CMPE; 1059*25cf1a30Sjl return; 1060*25cf1a30Sjl } 1061*25cf1a30Sjl } 1062*25cf1a30Sjl if (!(cntl & MAC_CNTL_REW_CE)) { 1063*25cf1a30Sjl flt_stat->mf_type = FLT_TYPE_INTERMITTENT_CE; 1064*25cf1a30Sjl } 1065*25cf1a30Sjl 1066*25cf1a30Sjl if (flt_stat->mf_type == FLT_TYPE_PERMANENT_CE) { 1067*25cf1a30Sjl /* report PERMANENT_CE to SP via SCF */ 1068*25cf1a30Sjl if (!(flt_stat->mf_err_log & MAC_ERR_LOG_INVALID)) { 1069*25cf1a30Sjl mc_queue_scf_log(mcp, flt_stat, bank); 1070*25cf1a30Sjl } 1071*25cf1a30Sjl } 1072*25cf1a30Sjl } 1073*25cf1a30Sjl 1074*25cf1a30Sjl #define IS_CMPE(cntl, f) ((cntl) & ((f) ? MAC_CNTL_PTRL_CMPE :\ 1075*25cf1a30Sjl MAC_CNTL_MI_CMPE)) 1076*25cf1a30Sjl #define IS_UE(cntl, f) ((cntl) & ((f) ? MAC_CNTL_PTRL_UE : MAC_CNTL_MI_UE)) 1077*25cf1a30Sjl #define IS_CE(cntl, f) ((cntl) & ((f) ? MAC_CNTL_PTRL_CE : MAC_CNTL_MI_CE)) 1078*25cf1a30Sjl #define IS_OK(cntl, f) (!((cntl) & ((f) ? MAC_CNTL_PTRL_ERRS : \ 1079*25cf1a30Sjl MAC_CNTL_MI_ERRS))) 1080*25cf1a30Sjl 1081*25cf1a30Sjl 1082*25cf1a30Sjl static int 1083*25cf1a30Sjl IS_CE_ONLY(uint32_t cntl, int ptrl_error) 1084*25cf1a30Sjl { 1085*25cf1a30Sjl if (ptrl_error) { 1086*25cf1a30Sjl return ((cntl & MAC_CNTL_PTRL_ERRS) == MAC_CNTL_PTRL_CE); 1087*25cf1a30Sjl } else { 1088*25cf1a30Sjl return ((cntl & MAC_CNTL_MI_ERRS) == MAC_CNTL_MI_CE); 1089*25cf1a30Sjl } 1090*25cf1a30Sjl } 1091*25cf1a30Sjl 1092*25cf1a30Sjl void 1093*25cf1a30Sjl mc_write_cntl(mc_opl_t *mcp, int bank, uint32_t value) 1094*25cf1a30Sjl { 1095*25cf1a30Sjl value |= mcp->mc_bank[bank].mcb_ptrl_cntl; 1096*25cf1a30Sjl ST_MAC_REG(MAC_PTRL_CNTL(mcp, bank), value); 1097*25cf1a30Sjl } 1098*25cf1a30Sjl 1099*25cf1a30Sjl static int 1100*25cf1a30Sjl mc_stop(mc_opl_t *mcp, int bank) 1101*25cf1a30Sjl { 1102*25cf1a30Sjl uint32_t reg; 1103*25cf1a30Sjl int count = 0; 1104*25cf1a30Sjl 1105*25cf1a30Sjl reg = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank)); 1106*25cf1a30Sjl 1107*25cf1a30Sjl if (reg & MAC_CNTL_PTRL_START) 1108*25cf1a30Sjl MAC_PTRL_STOP(mcp, bank); 1109*25cf1a30Sjl 1110*25cf1a30Sjl while (count++ <= MAX_MC_LOOP_COUNT) { 1111*25cf1a30Sjl reg = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank)); 1112*25cf1a30Sjl if ((reg & MAC_CNTL_PTRL_STATUS) == 0) 1113*25cf1a30Sjl return (0); 1114*25cf1a30Sjl delay(drv_usectohz(10 * 1000)); /* 10 m.s. */ 1115*25cf1a30Sjl } 1116*25cf1a30Sjl return (-1); 1117*25cf1a30Sjl } 1118*25cf1a30Sjl 1119*25cf1a30Sjl static void 1120*25cf1a30Sjl mc_read_ptrl_reg(mc_opl_t *mcp, int bank, mc_flt_stat_t *flt_stat) 1121*25cf1a30Sjl { 1122*25cf1a30Sjl flt_stat->mf_cntl = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank)) & 1123*25cf1a30Sjl MAC_CNTL_PTRL_ERRS; 1124*25cf1a30Sjl flt_stat->mf_err_add = LD_MAC_REG(MAC_PTRL_ERR_ADD(mcp, bank)); 1125*25cf1a30Sjl flt_stat->mf_err_log = LD_MAC_REG(MAC_PTRL_ERR_LOG(mcp, bank)); 1126*25cf1a30Sjl flt_stat->mf_flt_maddr.ma_bd = mcp->mc_board_num; 1127*25cf1a30Sjl flt_stat->mf_flt_maddr.ma_bank = bank; 1128*25cf1a30Sjl flt_stat->mf_flt_maddr.ma_dimm_addr = flt_stat->mf_err_add; 1129*25cf1a30Sjl } 1130*25cf1a30Sjl 1131*25cf1a30Sjl static void 1132*25cf1a30Sjl mc_read_mi_reg(mc_opl_t *mcp, int bank, mc_flt_stat_t *flt_stat) 1133*25cf1a30Sjl { 1134*25cf1a30Sjl uint32_t status, old_status; 1135*25cf1a30Sjl 1136*25cf1a30Sjl status = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank)) & 1137*25cf1a30Sjl MAC_CNTL_MI_ERRS; 1138*25cf1a30Sjl old_status = 0; 1139*25cf1a30Sjl 1140*25cf1a30Sjl /* we keep reading until the status is stable */ 1141*25cf1a30Sjl while (old_status != status) { 1142*25cf1a30Sjl old_status = status; 1143*25cf1a30Sjl flt_stat->mf_err_add = 1144*25cf1a30Sjl LD_MAC_REG(MAC_MI_ERR_ADD(mcp, bank)); 1145*25cf1a30Sjl flt_stat->mf_err_log = 1146*25cf1a30Sjl LD_MAC_REG(MAC_MI_ERR_LOG(mcp, bank)); 1147*25cf1a30Sjl status = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank)) & 1148*25cf1a30Sjl MAC_CNTL_MI_ERRS; 1149*25cf1a30Sjl if (status == old_status) { 1150*25cf1a30Sjl break; 1151*25cf1a30Sjl } 1152*25cf1a30Sjl } 1153*25cf1a30Sjl 1154*25cf1a30Sjl flt_stat->mf_cntl = status; 1155*25cf1a30Sjl flt_stat->mf_flt_maddr.ma_bd = mcp->mc_board_num; 1156*25cf1a30Sjl flt_stat->mf_flt_maddr.ma_bank = bank; 1157*25cf1a30Sjl flt_stat->mf_flt_maddr.ma_dimm_addr = flt_stat->mf_err_add; 1158*25cf1a30Sjl } 1159*25cf1a30Sjl 1160*25cf1a30Sjl 1161*25cf1a30Sjl /* 1162*25cf1a30Sjl * Error philosophy for mirror mode: 1163*25cf1a30Sjl * 1164*25cf1a30Sjl * PTRL (The error address for both banks are same, since ptrl stops if it 1165*25cf1a30Sjl * detects error.) 1166*25cf1a30Sjl * - Compaire error Report CMPE. 1167*25cf1a30Sjl * 1168*25cf1a30Sjl * - UE-UE Report MUE. No rewrite. 1169*25cf1a30Sjl * 1170*25cf1a30Sjl * - UE-* UE-(CE/OK). Rewrite to scrub UE. Report SUE. 1171*25cf1a30Sjl * 1172*25cf1a30Sjl * - CE-* CE-(CE/OK). Scrub to determine if CE is permanent. 1173*25cf1a30Sjl * If CE is permanent, inform SCF. Once for each 1174*25cf1a30Sjl * Dimm. If CE becomes UE or CMPE, go back to above. 1175*25cf1a30Sjl * 1176*25cf1a30Sjl * 1177*25cf1a30Sjl * MI (The error addresses for each bank are the same or different.) 1178*25cf1a30Sjl * - Compair error If addresses are the same. Just CMPE. 1179*25cf1a30Sjl * If addresses are different (this could happen 1180*25cf1a30Sjl * as a result of scrubbing. Report each seperately. 1181*25cf1a30Sjl * Only report error info on each side. 1182*25cf1a30Sjl * 1183*25cf1a30Sjl * - UE-UE Addresses are the same. Report MUE. 1184*25cf1a30Sjl * Addresses are different. Report SUE on each bank. 1185*25cf1a30Sjl * Rewrite to clear UE. 1186*25cf1a30Sjl * 1187*25cf1a30Sjl * - UE-* UE-(CE/OK) 1188*25cf1a30Sjl * Rewrite to clear UE. Report SUE for the bank. 1189*25cf1a30Sjl * 1190*25cf1a30Sjl * - CE-* CE-(CE/OK). Scrub to determine if CE is permanent. 1191*25cf1a30Sjl * If CE becomes UE or CMPE, go back to above. 1192*25cf1a30Sjl * 1193*25cf1a30Sjl */ 1194*25cf1a30Sjl 1195*25cf1a30Sjl static int 1196*25cf1a30Sjl mc_process_error_mir(mc_opl_t *mcp, mc_aflt_t *mc_aflt, mc_flt_stat_t *flt_stat) 1197*25cf1a30Sjl { 1198*25cf1a30Sjl int ptrl_error = mc_aflt->mflt_is_ptrl; 1199*25cf1a30Sjl int i; 1200*25cf1a30Sjl int rv = 0; 1201*25cf1a30Sjl 1202*25cf1a30Sjl MC_LOG("process mirror errors cntl[0] = %x, cntl[1] = %x\n", 1203*25cf1a30Sjl flt_stat[0].mf_cntl, flt_stat[1].mf_cntl); 1204*25cf1a30Sjl 1205*25cf1a30Sjl if (ptrl_error) { 1206*25cf1a30Sjl if (((flt_stat[0].mf_cntl | flt_stat[1].mf_cntl) 1207*25cf1a30Sjl & MAC_CNTL_PTRL_ERRS) == 0) 1208*25cf1a30Sjl return (0); 1209*25cf1a30Sjl } else { 1210*25cf1a30Sjl if (((flt_stat[0].mf_cntl | flt_stat[1].mf_cntl) 1211*25cf1a30Sjl & MAC_CNTL_MI_ERRS) == 0) 1212*25cf1a30Sjl return (0); 1213*25cf1a30Sjl } 1214*25cf1a30Sjl 1215*25cf1a30Sjl /* 1216*25cf1a30Sjl * First we take care of the case of CE 1217*25cf1a30Sjl * because they can become UE or CMPE 1218*25cf1a30Sjl */ 1219*25cf1a30Sjl for (i = 0; i < 2; i++) { 1220*25cf1a30Sjl if (IS_CE_ONLY(flt_stat[i].mf_cntl, ptrl_error)) { 1221*25cf1a30Sjl MC_LOG("CE detected on bank %d\n", 1222*25cf1a30Sjl flt_stat[i].mf_flt_maddr.ma_bank); 1223*25cf1a30Sjl mc_scrub_ce(mcp, flt_stat[i].mf_flt_maddr.ma_bank, 1224*25cf1a30Sjl &flt_stat[i], ptrl_error); 1225*25cf1a30Sjl rv = 1; 1226*25cf1a30Sjl } 1227*25cf1a30Sjl } 1228*25cf1a30Sjl 1229*25cf1a30Sjl /* The above scrubbing can turn CE into UE or CMPE */ 1230*25cf1a30Sjl 1231*25cf1a30Sjl /* 1232*25cf1a30Sjl * Now we distinguish two cases: same address or not 1233*25cf1a30Sjl * the same address. It might seem more intuitive to 1234*25cf1a30Sjl * distinguish PTRL v.s. MI error but it is more 1235*25cf1a30Sjl * complicated that way. 1236*25cf1a30Sjl */ 1237*25cf1a30Sjl 1238*25cf1a30Sjl if (flt_stat[0].mf_err_add == flt_stat[1].mf_err_add) { 1239*25cf1a30Sjl 1240*25cf1a30Sjl if (IS_CMPE(flt_stat[0].mf_cntl, ptrl_error) || 1241*25cf1a30Sjl IS_CMPE(flt_stat[1].mf_cntl, ptrl_error)) { 1242*25cf1a30Sjl flt_stat[0].mf_type = FLT_TYPE_CMPE; 1243*25cf1a30Sjl flt_stat[1].mf_type = FLT_TYPE_CMPE; 1244*25cf1a30Sjl mc_aflt->mflt_erpt_class = MC_OPL_CMPE; 1245*25cf1a30Sjl MC_LOG("cmpe error detected\n"); 1246*25cf1a30Sjl mc_aflt->mflt_nflts = 2; 1247*25cf1a30Sjl mc_aflt->mflt_stat[0] = &flt_stat[0]; 1248*25cf1a30Sjl mc_aflt->mflt_stat[1] = &flt_stat[1]; 1249*25cf1a30Sjl mc_aflt->mflt_pr = PR_UE; 1250*25cf1a30Sjl mc_err_drain(mc_aflt); 1251*25cf1a30Sjl return (1); 1252*25cf1a30Sjl } 1253*25cf1a30Sjl 1254*25cf1a30Sjl if (IS_UE(flt_stat[0].mf_cntl, ptrl_error) && 1255*25cf1a30Sjl IS_UE(flt_stat[1].mf_cntl, ptrl_error)) { 1256*25cf1a30Sjl /* Both side are UE's */ 1257*25cf1a30Sjl 1258*25cf1a30Sjl MAC_SET_ERRLOG_INFO(&flt_stat[0]); 1259*25cf1a30Sjl MAC_SET_ERRLOG_INFO(&flt_stat[1]); 1260*25cf1a30Sjl MC_LOG("MUE detected\n"); 1261*25cf1a30Sjl flt_stat[0].mf_type = flt_stat[1].mf_type = 1262*25cf1a30Sjl FLT_TYPE_MUE; 1263*25cf1a30Sjl mc_aflt->mflt_erpt_class = MC_OPL_MUE; 1264*25cf1a30Sjl mc_aflt->mflt_nflts = 2; 1265*25cf1a30Sjl mc_aflt->mflt_stat[0] = &flt_stat[0]; 1266*25cf1a30Sjl mc_aflt->mflt_stat[1] = &flt_stat[1]; 1267*25cf1a30Sjl mc_aflt->mflt_pr = PR_UE; 1268*25cf1a30Sjl mc_err_drain(mc_aflt); 1269*25cf1a30Sjl return (1); 1270*25cf1a30Sjl } 1271*25cf1a30Sjl 1272*25cf1a30Sjl /* Now the only case is UE/CE, UE/OK, or don't care */ 1273*25cf1a30Sjl for (i = 0; i < 2; i++) { 1274*25cf1a30Sjl if (IS_UE(flt_stat[i].mf_cntl, ptrl_error)) { 1275*25cf1a30Sjl /* If we have CE, we would have done REW */ 1276*25cf1a30Sjl if (IS_OK(flt_stat[i^1].mf_cntl, ptrl_error)) { 1277*25cf1a30Sjl (void) do_rewrite(mcp, 1278*25cf1a30Sjl flt_stat[i].mf_flt_maddr.ma_bank, 1279*25cf1a30Sjl flt_stat[i].mf_flt_maddr.ma_dimm_addr); 1280*25cf1a30Sjl } 1281*25cf1a30Sjl flt_stat[i].mf_type = FLT_TYPE_UE; 1282*25cf1a30Sjl MAC_SET_ERRLOG_INFO(&flt_stat[i]); 1283*25cf1a30Sjl mc_aflt->mflt_erpt_class = MC_OPL_SUE; 1284*25cf1a30Sjl mc_aflt->mflt_stat[0] = &flt_stat[i]; 1285*25cf1a30Sjl mc_aflt->mflt_nflts = 1; 1286*25cf1a30Sjl mc_aflt->mflt_pr = PR_MCE; 1287*25cf1a30Sjl mc_err_drain(mc_aflt); 1288*25cf1a30Sjl /* Once we hit a UE/CE or UE/OK case, done */ 1289*25cf1a30Sjl return (1); 1290*25cf1a30Sjl } 1291*25cf1a30Sjl } 1292*25cf1a30Sjl 1293*25cf1a30Sjl } else { 1294*25cf1a30Sjl /* 1295*25cf1a30Sjl * addresses are different. That means errors 1296*25cf1a30Sjl * on the 2 banks are not related at all. 1297*25cf1a30Sjl */ 1298*25cf1a30Sjl for (i = 0; i < 2; i++) { 1299*25cf1a30Sjl if (IS_CMPE(flt_stat[i].mf_cntl, ptrl_error)) { 1300*25cf1a30Sjl flt_stat[i].mf_type = FLT_TYPE_CMPE; 1301*25cf1a30Sjl mc_aflt->mflt_erpt_class = MC_OPL_CMPE; 1302*25cf1a30Sjl MC_LOG("cmpe error detected\n"); 1303*25cf1a30Sjl mc_aflt->mflt_nflts = 1; 1304*25cf1a30Sjl mc_aflt->mflt_stat[0] = &flt_stat[i]; 1305*25cf1a30Sjl mc_aflt->mflt_pr = PR_UE; 1306*25cf1a30Sjl mc_err_drain(mc_aflt); 1307*25cf1a30Sjl /* no more report on this bank */ 1308*25cf1a30Sjl flt_stat[i].mf_cntl = 0; 1309*25cf1a30Sjl rv = 1; 1310*25cf1a30Sjl } 1311*25cf1a30Sjl } 1312*25cf1a30Sjl 1313*25cf1a30Sjl for (i = 0; i < 2; i++) { 1314*25cf1a30Sjl if (IS_UE(flt_stat[i].mf_cntl, ptrl_error)) { 1315*25cf1a30Sjl (void) do_rewrite(mcp, 1316*25cf1a30Sjl flt_stat[i].mf_flt_maddr.ma_bank, 1317*25cf1a30Sjl flt_stat[i].mf_flt_maddr.ma_dimm_addr); 1318*25cf1a30Sjl flt_stat[i].mf_type = FLT_TYPE_UE; 1319*25cf1a30Sjl MAC_SET_ERRLOG_INFO(&flt_stat[i]); 1320*25cf1a30Sjl mc_aflt->mflt_erpt_class = MC_OPL_SUE; 1321*25cf1a30Sjl mc_aflt->mflt_stat[0] = &flt_stat[i]; 1322*25cf1a30Sjl mc_aflt->mflt_nflts = 1; 1323*25cf1a30Sjl mc_aflt->mflt_pr = PR_MCE; 1324*25cf1a30Sjl mc_err_drain(mc_aflt); 1325*25cf1a30Sjl rv = 1; 1326*25cf1a30Sjl } 1327*25cf1a30Sjl } 1328*25cf1a30Sjl } 1329*25cf1a30Sjl return (rv); 1330*25cf1a30Sjl } 1331*25cf1a30Sjl 1332*25cf1a30Sjl static void 1333*25cf1a30Sjl mc_error_handler_mir(mc_opl_t *mcp, int bank, mc_addr_info_t *maddr) 1334*25cf1a30Sjl { 1335*25cf1a30Sjl mc_aflt_t mc_aflt; 1336*25cf1a30Sjl mc_flt_stat_t flt_stat[2], mi_flt_stat[2]; 1337*25cf1a30Sjl int other_bank; 1338*25cf1a30Sjl 1339*25cf1a30Sjl if (mc_stop(mcp, bank)) { 1340*25cf1a30Sjl cmn_err(CE_WARN, "Cannot stop Memory Patrol at /LSB%d/B%d\n", 1341*25cf1a30Sjl mcp->mc_board_num, bank); 1342*25cf1a30Sjl return; 1343*25cf1a30Sjl } 1344*25cf1a30Sjl bzero(&mc_aflt, sizeof (mc_aflt_t)); 1345*25cf1a30Sjl bzero(&flt_stat, 2 * sizeof (mc_flt_stat_t)); 1346*25cf1a30Sjl bzero(&mi_flt_stat, 2 * sizeof (mc_flt_stat_t)); 1347*25cf1a30Sjl 1348*25cf1a30Sjl mc_aflt.mflt_mcp = mcp; 1349*25cf1a30Sjl mc_aflt.mflt_id = gethrtime(); 1350*25cf1a30Sjl 1351*25cf1a30Sjl /* Now read all the registers into flt_stat */ 1352*25cf1a30Sjl 1353*25cf1a30Sjl MC_LOG("Reading registers of bank %d\n", bank); 1354*25cf1a30Sjl /* patrol registers */ 1355*25cf1a30Sjl mc_read_ptrl_reg(mcp, bank, &flt_stat[0]); 1356*25cf1a30Sjl 1357*25cf1a30Sjl ASSERT(maddr); 1358*25cf1a30Sjl maddr->mi_maddr = flt_stat[0].mf_flt_maddr; 1359*25cf1a30Sjl 1360*25cf1a30Sjl MC_LOG("ptrl registers cntl %x add %x log %x\n", 1361*25cf1a30Sjl flt_stat[0].mf_cntl, 1362*25cf1a30Sjl flt_stat[0].mf_err_add, 1363*25cf1a30Sjl flt_stat[0].mf_err_log); 1364*25cf1a30Sjl 1365*25cf1a30Sjl /* MI registers */ 1366*25cf1a30Sjl mc_read_mi_reg(mcp, bank, &mi_flt_stat[0]); 1367*25cf1a30Sjl 1368*25cf1a30Sjl MC_LOG("MI registers cntl %x add %x log %x\n", 1369*25cf1a30Sjl mi_flt_stat[0].mf_cntl, 1370*25cf1a30Sjl mi_flt_stat[0].mf_err_add, 1371*25cf1a30Sjl mi_flt_stat[0].mf_err_log); 1372*25cf1a30Sjl 1373*25cf1a30Sjl other_bank = bank^1; 1374*25cf1a30Sjl 1375*25cf1a30Sjl MC_LOG("Reading registers of bank %d\n", other_bank); 1376*25cf1a30Sjl 1377*25cf1a30Sjl ASSERT(mcp->mc_bank[other_bank].mcb_status & BANK_INSTALLED); 1378*25cf1a30Sjl 1379*25cf1a30Sjl mc_read_ptrl_reg(mcp, other_bank, &flt_stat[1]); 1380*25cf1a30Sjl MC_LOG("ptrl registers cntl %x add %x log %x\n", 1381*25cf1a30Sjl flt_stat[1].mf_cntl, 1382*25cf1a30Sjl flt_stat[1].mf_err_add, 1383*25cf1a30Sjl flt_stat[1].mf_err_log); 1384*25cf1a30Sjl 1385*25cf1a30Sjl /* MI registers */ 1386*25cf1a30Sjl mc_read_mi_reg(mcp, other_bank, &mi_flt_stat[1]); 1387*25cf1a30Sjl MC_LOG("MI registers cntl %x add %x log %x\n", 1388*25cf1a30Sjl mi_flt_stat[1].mf_cntl, 1389*25cf1a30Sjl mi_flt_stat[1].mf_err_add, 1390*25cf1a30Sjl mi_flt_stat[1].mf_err_log); 1391*25cf1a30Sjl 1392*25cf1a30Sjl /* clear errors once we read all the registers */ 1393*25cf1a30Sjl MAC_CLEAR_ERRS(mcp, other_bank, 1394*25cf1a30Sjl (MAC_CNTL_PTRL_ERRS|MAC_CNTL_MI_ERRS)); 1395*25cf1a30Sjl 1396*25cf1a30Sjl MAC_CLEAR_ERRS(mcp, bank, (MAC_CNTL_PTRL_ERRS|MAC_CNTL_MI_ERRS)); 1397*25cf1a30Sjl 1398*25cf1a30Sjl /* Process PTRL errors first */ 1399*25cf1a30Sjl 1400*25cf1a30Sjl /* if not error mode, cntl1 is 0 */ 1401*25cf1a30Sjl if ((flt_stat[0].mf_err_add & MAC_ERR_ADD_INVALID) || 1402*25cf1a30Sjl (flt_stat[0].mf_err_log & MAC_ERR_LOG_INVALID)) 1403*25cf1a30Sjl flt_stat[0].mf_cntl = 0; 1404*25cf1a30Sjl 1405*25cf1a30Sjl if ((flt_stat[1].mf_err_add & MAC_ERR_ADD_INVALID) || 1406*25cf1a30Sjl (flt_stat[1].mf_err_log & MAC_ERR_LOG_INVALID)) 1407*25cf1a30Sjl flt_stat[1].mf_cntl = 0; 1408*25cf1a30Sjl 1409*25cf1a30Sjl mc_aflt.mflt_is_ptrl = 1; 1410*25cf1a30Sjl maddr->mi_valid = mc_process_error_mir(mcp, &mc_aflt, &flt_stat[0]); 1411*25cf1a30Sjl 1412*25cf1a30Sjl mc_aflt.mflt_is_ptrl = 0; 1413*25cf1a30Sjl mc_process_error_mir(mcp, &mc_aflt, &mi_flt_stat[0]); 1414*25cf1a30Sjl } 1415*25cf1a30Sjl 1416*25cf1a30Sjl static int 1417*25cf1a30Sjl mc_process_error(mc_opl_t *mcp, int bank, mc_aflt_t *mc_aflt, 1418*25cf1a30Sjl mc_flt_stat_t *flt_stat) 1419*25cf1a30Sjl { 1420*25cf1a30Sjl int ptrl_error = mc_aflt->mflt_is_ptrl; 1421*25cf1a30Sjl int rv = 0; 1422*25cf1a30Sjl 1423*25cf1a30Sjl mc_aflt->mflt_erpt_class = NULL; 1424*25cf1a30Sjl if (IS_UE(flt_stat->mf_cntl, ptrl_error)) { 1425*25cf1a30Sjl MC_LOG("UE deteceted\n"); 1426*25cf1a30Sjl flt_stat->mf_type = FLT_TYPE_UE; 1427*25cf1a30Sjl mc_aflt->mflt_erpt_class = MC_OPL_UE; 1428*25cf1a30Sjl mc_aflt->mflt_pr = PR_UE; 1429*25cf1a30Sjl MAC_SET_ERRLOG_INFO(flt_stat); 1430*25cf1a30Sjl rv = 1; 1431*25cf1a30Sjl } else if (IS_CE(flt_stat->mf_cntl, ptrl_error)) { 1432*25cf1a30Sjl MC_LOG("CE deteceted\n"); 1433*25cf1a30Sjl MAC_SET_ERRLOG_INFO(flt_stat); 1434*25cf1a30Sjl 1435*25cf1a30Sjl /* Error type can change after scrubing */ 1436*25cf1a30Sjl mc_scrub_ce(mcp, bank, flt_stat, ptrl_error); 1437*25cf1a30Sjl 1438*25cf1a30Sjl if (flt_stat->mf_type == FLT_TYPE_PERMANENT_CE) { 1439*25cf1a30Sjl mc_aflt->mflt_erpt_class = MC_OPL_CE; 1440*25cf1a30Sjl mc_aflt->mflt_pr = PR_MCE; 1441*25cf1a30Sjl } else if (flt_stat->mf_type == FLT_TYPE_UE) { 1442*25cf1a30Sjl mc_aflt->mflt_erpt_class = MC_OPL_UE; 1443*25cf1a30Sjl mc_aflt->mflt_pr = PR_UE; 1444*25cf1a30Sjl } 1445*25cf1a30Sjl rv = 1; 1446*25cf1a30Sjl } 1447*25cf1a30Sjl MC_LOG("mc_process_error: fault type %x erpt %s\n", 1448*25cf1a30Sjl flt_stat->mf_type, 1449*25cf1a30Sjl mc_aflt->mflt_erpt_class); 1450*25cf1a30Sjl if (mc_aflt->mflt_erpt_class) { 1451*25cf1a30Sjl mc_aflt->mflt_stat[0] = flt_stat; 1452*25cf1a30Sjl mc_aflt->mflt_nflts = 1; 1453*25cf1a30Sjl mc_err_drain(mc_aflt); 1454*25cf1a30Sjl } 1455*25cf1a30Sjl return (rv); 1456*25cf1a30Sjl } 1457*25cf1a30Sjl 1458*25cf1a30Sjl static void 1459*25cf1a30Sjl mc_error_handler(mc_opl_t *mcp, int bank, mc_addr_info_t *maddr) 1460*25cf1a30Sjl { 1461*25cf1a30Sjl mc_aflt_t mc_aflt; 1462*25cf1a30Sjl mc_flt_stat_t flt_stat, mi_flt_stat; 1463*25cf1a30Sjl 1464*25cf1a30Sjl if (mc_stop(mcp, bank)) { 1465*25cf1a30Sjl cmn_err(CE_WARN, "Cannot stop Memory Patrol at /LSB%d/B%d\n", 1466*25cf1a30Sjl mcp->mc_board_num, bank); 1467*25cf1a30Sjl return; 1468*25cf1a30Sjl } 1469*25cf1a30Sjl 1470*25cf1a30Sjl bzero(&mc_aflt, sizeof (mc_aflt_t)); 1471*25cf1a30Sjl bzero(&flt_stat, sizeof (mc_flt_stat_t)); 1472*25cf1a30Sjl bzero(&mi_flt_stat, sizeof (mc_flt_stat_t)); 1473*25cf1a30Sjl 1474*25cf1a30Sjl mc_aflt.mflt_mcp = mcp; 1475*25cf1a30Sjl mc_aflt.mflt_id = gethrtime(); 1476*25cf1a30Sjl 1477*25cf1a30Sjl /* patrol registers */ 1478*25cf1a30Sjl mc_read_ptrl_reg(mcp, bank, &flt_stat); 1479*25cf1a30Sjl 1480*25cf1a30Sjl ASSERT(maddr); 1481*25cf1a30Sjl maddr->mi_maddr = flt_stat.mf_flt_maddr; 1482*25cf1a30Sjl 1483*25cf1a30Sjl MC_LOG("ptrl registers cntl %x add %x log %x\n", 1484*25cf1a30Sjl flt_stat.mf_cntl, 1485*25cf1a30Sjl flt_stat.mf_err_add, 1486*25cf1a30Sjl flt_stat.mf_err_log); 1487*25cf1a30Sjl 1488*25cf1a30Sjl /* MI registers */ 1489*25cf1a30Sjl mc_read_mi_reg(mcp, bank, &mi_flt_stat); 1490*25cf1a30Sjl 1491*25cf1a30Sjl MC_LOG("MI registers cntl %x add %x log %x\n", 1492*25cf1a30Sjl mi_flt_stat.mf_cntl, 1493*25cf1a30Sjl mi_flt_stat.mf_err_add, 1494*25cf1a30Sjl mi_flt_stat.mf_err_log); 1495*25cf1a30Sjl 1496*25cf1a30Sjl /* clear errors once we read all the registers */ 1497*25cf1a30Sjl MAC_CLEAR_ERRS(mcp, bank, (MAC_CNTL_PTRL_ERRS|MAC_CNTL_MI_ERRS)); 1498*25cf1a30Sjl 1499*25cf1a30Sjl mc_aflt.mflt_is_ptrl = 1; 1500*25cf1a30Sjl if ((flt_stat.mf_cntl & MAC_CNTL_PTRL_ERRS) && 1501*25cf1a30Sjl ((flt_stat.mf_err_add & MAC_ERR_ADD_INVALID) == 0) && 1502*25cf1a30Sjl ((flt_stat.mf_err_log & MAC_ERR_LOG_INVALID) == 0)) { 1503*25cf1a30Sjl maddr->mi_valid = mc_process_error(mcp, bank, 1504*25cf1a30Sjl &mc_aflt, &flt_stat); 1505*25cf1a30Sjl } 1506*25cf1a30Sjl mc_aflt.mflt_is_ptrl = 0; 1507*25cf1a30Sjl if ((mi_flt_stat.mf_cntl & MAC_CNTL_MI_ERRS) && 1508*25cf1a30Sjl ((mi_flt_stat.mf_err_add & MAC_ERR_ADD_INVALID) == 0) && 1509*25cf1a30Sjl ((mi_flt_stat.mf_err_log & MAC_ERR_LOG_INVALID) == 0)) { 1510*25cf1a30Sjl mc_process_error(mcp, bank, &mc_aflt, &mi_flt_stat); 1511*25cf1a30Sjl } 1512*25cf1a30Sjl } 1513*25cf1a30Sjl 1514*25cf1a30Sjl /* 1515*25cf1a30Sjl * memory patrol error handling algorithm: 1516*25cf1a30Sjl * timeout() is used to do periodic polling 1517*25cf1a30Sjl * This is the flow chart. 1518*25cf1a30Sjl * timeout -> 1519*25cf1a30Sjl * mc_check_errors() 1520*25cf1a30Sjl * if memory bank is installed, read the status register 1521*25cf1a30Sjl * if any error bit is set, 1522*25cf1a30Sjl * -> mc_error_handler() 1523*25cf1a30Sjl * -> mc_stop() 1524*25cf1a30Sjl * -> read all error regsiters 1525*25cf1a30Sjl * -> mc_process_error() 1526*25cf1a30Sjl * determine error type 1527*25cf1a30Sjl * rewrite to clear error or scrub to determine CE type 1528*25cf1a30Sjl * inform SCF on permanent CE 1529*25cf1a30Sjl * -> mc_err_drain 1530*25cf1a30Sjl * page offline processing 1531*25cf1a30Sjl * -> mc_ereport_post() 1532*25cf1a30Sjl */ 1533*25cf1a30Sjl 1534*25cf1a30Sjl static void 1535*25cf1a30Sjl mc_check_errors_func(mc_opl_t *mcp) 1536*25cf1a30Sjl { 1537*25cf1a30Sjl mc_addr_info_t maddr_info; 1538*25cf1a30Sjl int i, error_count = 0; 1539*25cf1a30Sjl uint32_t stat, cntl; 1540*25cf1a30Sjl 1541*25cf1a30Sjl /* 1542*25cf1a30Sjl * scan errors. 1543*25cf1a30Sjl */ 1544*25cf1a30Sjl for (i = 0; i < BANKNUM_PER_SB; i++) { 1545*25cf1a30Sjl if (mcp->mc_bank[i].mcb_status & BANK_INSTALLED) { 1546*25cf1a30Sjl stat = ldphysio(MAC_PTRL_STAT(mcp, i)); 1547*25cf1a30Sjl cntl = ldphysio(MAC_PTRL_CNTL(mcp, i)); 1548*25cf1a30Sjl if (cntl & MAC_CNTL_PTRL_ADD_MAX) { 1549*25cf1a30Sjl mcp->mc_period++; 1550*25cf1a30Sjl MC_LOG("mc period %ld on " 1551*25cf1a30Sjl "/LSB%d/B%d\n", mcp->mc_period, 1552*25cf1a30Sjl mcp->mc_board_num, i); 1553*25cf1a30Sjl MAC_CLEAR_MAX(mcp, i); 1554*25cf1a30Sjl } 1555*25cf1a30Sjl if (mc_debug_show_all) { 1556*25cf1a30Sjl MC_LOG("/LSB%d/B%d stat %x cntl %x\n", 1557*25cf1a30Sjl mcp->mc_board_num, i, 1558*25cf1a30Sjl stat, cntl); 1559*25cf1a30Sjl } 1560*25cf1a30Sjl if (stat & (MAC_STAT_PTRL_ERRS|MAC_STAT_MI_ERRS)) { 1561*25cf1a30Sjl maddr_info.mi_valid = 0; 1562*25cf1a30Sjl maddr_info.mi_advance = 1; 1563*25cf1a30Sjl if (IS_MIRROR(mcp, i)) 1564*25cf1a30Sjl mc_error_handler_mir(mcp, i, 1565*25cf1a30Sjl &maddr_info); 1566*25cf1a30Sjl else 1567*25cf1a30Sjl mc_error_handler(mcp, i, &maddr_info); 1568*25cf1a30Sjl 1569*25cf1a30Sjl error_count++; 1570*25cf1a30Sjl restart_patrol(mcp, i, &maddr_info); 1571*25cf1a30Sjl } else { 1572*25cf1a30Sjl restart_patrol(mcp, i, NULL); 1573*25cf1a30Sjl } 1574*25cf1a30Sjl } 1575*25cf1a30Sjl } 1576*25cf1a30Sjl mc_process_scf_log(mcp); 1577*25cf1a30Sjl if (error_count > 0) 1578*25cf1a30Sjl mcp->mc_last_error += error_count; 1579*25cf1a30Sjl else 1580*25cf1a30Sjl mcp->mc_last_error = 0; 1581*25cf1a30Sjl } 1582*25cf1a30Sjl 1583*25cf1a30Sjl /* this is just a wrapper for the above func */ 1584*25cf1a30Sjl 1585*25cf1a30Sjl static void 1586*25cf1a30Sjl mc_check_errors(void *arg) 1587*25cf1a30Sjl { 1588*25cf1a30Sjl mc_opl_t *mcp = (mc_opl_t *)arg; 1589*25cf1a30Sjl clock_t interval; 1590*25cf1a30Sjl 1591*25cf1a30Sjl /* 1592*25cf1a30Sjl * scan errors. 1593*25cf1a30Sjl */ 1594*25cf1a30Sjl mutex_enter(&mcp->mc_lock); 1595*25cf1a30Sjl mcp->mc_tid = 0; 1596*25cf1a30Sjl if ((mcp->mc_status & MC_POLL_RUNNING) && 1597*25cf1a30Sjl !(mcp->mc_status & MC_SOFT_SUSPENDED)) { 1598*25cf1a30Sjl mc_check_errors_func(mcp); 1599*25cf1a30Sjl 1600*25cf1a30Sjl if (mcp->mc_last_error > 0) { 1601*25cf1a30Sjl interval = (mcp->mc_interval_hz) >> mcp->mc_last_error; 1602*25cf1a30Sjl if (interval < 1) 1603*25cf1a30Sjl interval = 1; 1604*25cf1a30Sjl } else 1605*25cf1a30Sjl interval = mcp->mc_interval_hz; 1606*25cf1a30Sjl 1607*25cf1a30Sjl mcp->mc_tid = timeout(mc_check_errors, mcp, 1608*25cf1a30Sjl interval); 1609*25cf1a30Sjl } 1610*25cf1a30Sjl mutex_exit(&mcp->mc_lock); 1611*25cf1a30Sjl } 1612*25cf1a30Sjl 1613*25cf1a30Sjl static void 1614*25cf1a30Sjl get_ptrl_start_address(mc_opl_t *mcp, int bank, mc_addr_t *maddr) 1615*25cf1a30Sjl { 1616*25cf1a30Sjl maddr->ma_bd = mcp->mc_board_num; 1617*25cf1a30Sjl maddr->ma_bank = bank; 1618*25cf1a30Sjl maddr->ma_dimm_addr = 0; 1619*25cf1a30Sjl } 1620*25cf1a30Sjl 1621*25cf1a30Sjl typedef struct mc_mem_range { 1622*25cf1a30Sjl uint64_t addr; 1623*25cf1a30Sjl uint64_t size; 1624*25cf1a30Sjl } mc_mem_range_t; 1625*25cf1a30Sjl 1626*25cf1a30Sjl static int 1627*25cf1a30Sjl get_base_address(mc_opl_t *mcp) 1628*25cf1a30Sjl { 1629*25cf1a30Sjl mc_mem_range_t *mem_range; 1630*25cf1a30Sjl int len; 1631*25cf1a30Sjl 1632*25cf1a30Sjl if (ddi_getlongprop(DDI_DEV_T_ANY, mcp->mc_dip, DDI_PROP_DONTPASS, 1633*25cf1a30Sjl "sb-mem-ranges", (caddr_t)&mem_range, &len) != DDI_SUCCESS) { 1634*25cf1a30Sjl return (DDI_FAILURE); 1635*25cf1a30Sjl } 1636*25cf1a30Sjl 1637*25cf1a30Sjl mcp->mc_start_address = mem_range->addr; 1638*25cf1a30Sjl mcp->mc_size = mem_range->size; 1639*25cf1a30Sjl 1640*25cf1a30Sjl kmem_free(mem_range, len); 1641*25cf1a30Sjl return (DDI_SUCCESS); 1642*25cf1a30Sjl } 1643*25cf1a30Sjl 1644*25cf1a30Sjl struct mc_addr_spec { 1645*25cf1a30Sjl uint32_t bank; 1646*25cf1a30Sjl uint32_t phys_hi; 1647*25cf1a30Sjl uint32_t phys_lo; 1648*25cf1a30Sjl }; 1649*25cf1a30Sjl 1650*25cf1a30Sjl #define REGS_PA(m, i) ((((uint64_t)m[i].phys_hi)<<32) | m[i].phys_lo) 1651*25cf1a30Sjl 1652*25cf1a30Sjl static char *mc_tbl_name[] = { 1653*25cf1a30Sjl "cs0-mc-pa-trans-table", 1654*25cf1a30Sjl "cs1-mc-pa-trans-table" 1655*25cf1a30Sjl }; 1656*25cf1a30Sjl 1657*25cf1a30Sjl static int 1658*25cf1a30Sjl mc_valid_pa(mc_opl_t *mcp, uint64_t pa) 1659*25cf1a30Sjl { 1660*25cf1a30Sjl struct memlist *ml; 1661*25cf1a30Sjl 1662*25cf1a30Sjl if (mcp->mlist == NULL) 1663*25cf1a30Sjl mc_get_mlist(mcp); 1664*25cf1a30Sjl 1665*25cf1a30Sjl for (ml = mcp->mlist; ml; ml = ml->next) { 1666*25cf1a30Sjl if (ml->address <= pa && pa < (ml->address + ml->size)) 1667*25cf1a30Sjl return (1); 1668*25cf1a30Sjl } 1669*25cf1a30Sjl return (0); 1670*25cf1a30Sjl } 1671*25cf1a30Sjl 1672*25cf1a30Sjl static void 1673*25cf1a30Sjl mc_memlist_delete(struct memlist *mlist) 1674*25cf1a30Sjl { 1675*25cf1a30Sjl struct memlist *ml; 1676*25cf1a30Sjl 1677*25cf1a30Sjl for (ml = mlist; ml; ml = mlist) { 1678*25cf1a30Sjl mlist = ml->next; 1679*25cf1a30Sjl kmem_free(ml, sizeof (struct memlist)); 1680*25cf1a30Sjl } 1681*25cf1a30Sjl } 1682*25cf1a30Sjl 1683*25cf1a30Sjl static struct memlist * 1684*25cf1a30Sjl mc_memlist_dup(struct memlist *mlist) 1685*25cf1a30Sjl { 1686*25cf1a30Sjl struct memlist *hl = NULL, *tl, **mlp; 1687*25cf1a30Sjl 1688*25cf1a30Sjl if (mlist == NULL) 1689*25cf1a30Sjl return (NULL); 1690*25cf1a30Sjl 1691*25cf1a30Sjl mlp = &hl; 1692*25cf1a30Sjl tl = *mlp; 1693*25cf1a30Sjl for (; mlist; mlist = mlist->next) { 1694*25cf1a30Sjl *mlp = kmem_alloc(sizeof (struct memlist), KM_SLEEP); 1695*25cf1a30Sjl (*mlp)->address = mlist->address; 1696*25cf1a30Sjl (*mlp)->size = mlist->size; 1697*25cf1a30Sjl (*mlp)->prev = tl; 1698*25cf1a30Sjl tl = *mlp; 1699*25cf1a30Sjl mlp = &((*mlp)->next); 1700*25cf1a30Sjl } 1701*25cf1a30Sjl *mlp = NULL; 1702*25cf1a30Sjl 1703*25cf1a30Sjl return (hl); 1704*25cf1a30Sjl } 1705*25cf1a30Sjl 1706*25cf1a30Sjl 1707*25cf1a30Sjl static struct memlist * 1708*25cf1a30Sjl mc_memlist_del_span(struct memlist *mlist, uint64_t base, uint64_t len) 1709*25cf1a30Sjl { 1710*25cf1a30Sjl uint64_t end; 1711*25cf1a30Sjl struct memlist *ml, *tl, *nlp; 1712*25cf1a30Sjl 1713*25cf1a30Sjl if (mlist == NULL) 1714*25cf1a30Sjl return (NULL); 1715*25cf1a30Sjl 1716*25cf1a30Sjl end = base + len; 1717*25cf1a30Sjl if ((end <= mlist->address) || (base == end)) 1718*25cf1a30Sjl return (mlist); 1719*25cf1a30Sjl 1720*25cf1a30Sjl for (tl = ml = mlist; ml; tl = ml, ml = nlp) { 1721*25cf1a30Sjl uint64_t mend; 1722*25cf1a30Sjl 1723*25cf1a30Sjl nlp = ml->next; 1724*25cf1a30Sjl 1725*25cf1a30Sjl if (end <= ml->address) 1726*25cf1a30Sjl break; 1727*25cf1a30Sjl 1728*25cf1a30Sjl mend = ml->address + ml->size; 1729*25cf1a30Sjl if (base < mend) { 1730*25cf1a30Sjl if (base <= ml->address) { 1731*25cf1a30Sjl ml->address = end; 1732*25cf1a30Sjl if (end >= mend) 1733*25cf1a30Sjl ml->size = 0ull; 1734*25cf1a30Sjl else 1735*25cf1a30Sjl ml->size = mend - ml->address; 1736*25cf1a30Sjl } else { 1737*25cf1a30Sjl ml->size = base - ml->address; 1738*25cf1a30Sjl if (end < mend) { 1739*25cf1a30Sjl struct memlist *nl; 1740*25cf1a30Sjl /* 1741*25cf1a30Sjl * splitting an memlist entry. 1742*25cf1a30Sjl */ 1743*25cf1a30Sjl nl = kmem_alloc(sizeof (struct memlist), 1744*25cf1a30Sjl KM_SLEEP); 1745*25cf1a30Sjl nl->address = end; 1746*25cf1a30Sjl nl->size = mend - nl->address; 1747*25cf1a30Sjl if ((nl->next = nlp) != NULL) 1748*25cf1a30Sjl nlp->prev = nl; 1749*25cf1a30Sjl nl->prev = ml; 1750*25cf1a30Sjl ml->next = nl; 1751*25cf1a30Sjl nlp = nl; 1752*25cf1a30Sjl } 1753*25cf1a30Sjl } 1754*25cf1a30Sjl if (ml->size == 0ull) { 1755*25cf1a30Sjl if (ml == mlist) { 1756*25cf1a30Sjl if ((mlist = nlp) != NULL) 1757*25cf1a30Sjl nlp->prev = NULL; 1758*25cf1a30Sjl kmem_free(ml, sizeof (struct memlist)); 1759*25cf1a30Sjl if (mlist == NULL) 1760*25cf1a30Sjl break; 1761*25cf1a30Sjl ml = nlp; 1762*25cf1a30Sjl } else { 1763*25cf1a30Sjl if ((tl->next = nlp) != NULL) 1764*25cf1a30Sjl nlp->prev = tl; 1765*25cf1a30Sjl kmem_free(ml, sizeof (struct memlist)); 1766*25cf1a30Sjl ml = tl; 1767*25cf1a30Sjl } 1768*25cf1a30Sjl } 1769*25cf1a30Sjl } 1770*25cf1a30Sjl } 1771*25cf1a30Sjl 1772*25cf1a30Sjl return (mlist); 1773*25cf1a30Sjl } 1774*25cf1a30Sjl 1775*25cf1a30Sjl static void 1776*25cf1a30Sjl mc_get_mlist(mc_opl_t *mcp) 1777*25cf1a30Sjl { 1778*25cf1a30Sjl struct memlist *mlist; 1779*25cf1a30Sjl 1780*25cf1a30Sjl memlist_read_lock(); 1781*25cf1a30Sjl mlist = mc_memlist_dup(phys_install); 1782*25cf1a30Sjl memlist_read_unlock(); 1783*25cf1a30Sjl 1784*25cf1a30Sjl if (mlist) { 1785*25cf1a30Sjl mlist = mc_memlist_del_span(mlist, 0ull, mcp->mc_start_address); 1786*25cf1a30Sjl } 1787*25cf1a30Sjl 1788*25cf1a30Sjl if (mlist) { 1789*25cf1a30Sjl uint64_t startpa, endpa; 1790*25cf1a30Sjl 1791*25cf1a30Sjl startpa = mcp->mc_start_address + mcp->mc_size; 1792*25cf1a30Sjl endpa = ptob(physmax + 1); 1793*25cf1a30Sjl if (endpa > startpa) { 1794*25cf1a30Sjl mlist = mc_memlist_del_span(mlist, 1795*25cf1a30Sjl startpa, endpa - startpa); 1796*25cf1a30Sjl } 1797*25cf1a30Sjl } 1798*25cf1a30Sjl 1799*25cf1a30Sjl if (mlist) { 1800*25cf1a30Sjl mcp->mlist = mlist; 1801*25cf1a30Sjl } 1802*25cf1a30Sjl } 1803*25cf1a30Sjl 1804*25cf1a30Sjl int 1805*25cf1a30Sjl mc_board_add(mc_opl_t *mcp) 1806*25cf1a30Sjl { 1807*25cf1a30Sjl struct mc_addr_spec *macaddr; 1808*25cf1a30Sjl int len, i, bk, cc; 1809*25cf1a30Sjl mc_addr_info_t maddr; 1810*25cf1a30Sjl uint32_t mirr; 1811*25cf1a30Sjl 1812*25cf1a30Sjl mutex_init(&mcp->mc_lock, NULL, MUTEX_DRIVER, NULL); 1813*25cf1a30Sjl 1814*25cf1a30Sjl /* 1815*25cf1a30Sjl * Get configurations from "pseudo-mc" node which includes: 1816*25cf1a30Sjl * board# : LSB number 1817*25cf1a30Sjl * mac-addr : physical base address of MAC registers 1818*25cf1a30Sjl * csX-mac-pa-trans-table: translation table from DIMM address 1819*25cf1a30Sjl * to physical address or vice versa. 1820*25cf1a30Sjl */ 1821*25cf1a30Sjl mcp->mc_board_num = (int)ddi_getprop(DDI_DEV_T_ANY, mcp->mc_dip, 1822*25cf1a30Sjl DDI_PROP_DONTPASS, "board#", -1); 1823*25cf1a30Sjl 1824*25cf1a30Sjl /* 1825*25cf1a30Sjl * Get start address in this CAB. It can be gotten from 1826*25cf1a30Sjl * "sb-mem-ranges" property. 1827*25cf1a30Sjl */ 1828*25cf1a30Sjl 1829*25cf1a30Sjl if (get_base_address(mcp) == DDI_FAILURE) { 1830*25cf1a30Sjl mutex_destroy(&mcp->mc_lock); 1831*25cf1a30Sjl return (DDI_FAILURE); 1832*25cf1a30Sjl } 1833*25cf1a30Sjl /* get mac-pa trans tables */ 1834*25cf1a30Sjl for (i = 0; i < MC_TT_CS; i++) { 1835*25cf1a30Sjl len = MC_TT_ENTRIES; 1836*25cf1a30Sjl cc = ddi_getlongprop_buf(DDI_DEV_T_ANY, mcp->mc_dip, 1837*25cf1a30Sjl DDI_PROP_DONTPASS, mc_tbl_name[i], 1838*25cf1a30Sjl (caddr_t)mcp->mc_trans_table[i], &len); 1839*25cf1a30Sjl 1840*25cf1a30Sjl if (cc != DDI_SUCCESS) { 1841*25cf1a30Sjl bzero(mcp->mc_trans_table[i], MC_TT_ENTRIES); 1842*25cf1a30Sjl } 1843*25cf1a30Sjl } 1844*25cf1a30Sjl mcp->mlist = NULL; 1845*25cf1a30Sjl 1846*25cf1a30Sjl mc_get_mlist(mcp); 1847*25cf1a30Sjl 1848*25cf1a30Sjl /* initialize bank informations */ 1849*25cf1a30Sjl cc = ddi_getlongprop(DDI_DEV_T_ANY, mcp->mc_dip, DDI_PROP_DONTPASS, 1850*25cf1a30Sjl "mc-addr", (caddr_t)&macaddr, &len); 1851*25cf1a30Sjl if (cc != DDI_SUCCESS) { 1852*25cf1a30Sjl cmn_err(CE_WARN, "Cannot get mc-addr. err=%d\n", cc); 1853*25cf1a30Sjl mutex_destroy(&mcp->mc_lock); 1854*25cf1a30Sjl return (DDI_FAILURE); 1855*25cf1a30Sjl } 1856*25cf1a30Sjl 1857*25cf1a30Sjl for (i = 0; i < len / sizeof (struct mc_addr_spec); i++) { 1858*25cf1a30Sjl struct mc_bank *bankp; 1859*25cf1a30Sjl uint32_t reg; 1860*25cf1a30Sjl 1861*25cf1a30Sjl /* 1862*25cf1a30Sjl * setup bank 1863*25cf1a30Sjl */ 1864*25cf1a30Sjl bk = macaddr[i].bank; 1865*25cf1a30Sjl bankp = &(mcp->mc_bank[bk]); 1866*25cf1a30Sjl bankp->mcb_status = BANK_INSTALLED; 1867*25cf1a30Sjl bankp->mcb_reg_base = REGS_PA(macaddr, i); 1868*25cf1a30Sjl 1869*25cf1a30Sjl reg = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bk)); 1870*25cf1a30Sjl bankp->mcb_ptrl_cntl = (reg & MAC_CNTL_PTRL_PRESERVE_BITS); 1871*25cf1a30Sjl 1872*25cf1a30Sjl /* 1873*25cf1a30Sjl * check if mirror mode 1874*25cf1a30Sjl */ 1875*25cf1a30Sjl mirr = LD_MAC_REG(MAC_MIRR(mcp, bk)); 1876*25cf1a30Sjl 1877*25cf1a30Sjl if (mirr & MAC_MIRR_MIRROR_MODE) { 1878*25cf1a30Sjl MC_LOG("Mirror -> /LSB%d/B%d\n", 1879*25cf1a30Sjl mcp->mc_board_num, bk); 1880*25cf1a30Sjl bankp->mcb_status |= BANK_MIRROR_MODE; 1881*25cf1a30Sjl /* 1882*25cf1a30Sjl * The following bit is only used for 1883*25cf1a30Sjl * error injection. We should clear it 1884*25cf1a30Sjl */ 1885*25cf1a30Sjl if (mirr & MAC_MIRR_BANK_EXCLUSIVE) 1886*25cf1a30Sjl ST_MAC_REG(MAC_MIRR(mcp, bk), 1887*25cf1a30Sjl 0); 1888*25cf1a30Sjl } 1889*25cf1a30Sjl 1890*25cf1a30Sjl /* 1891*25cf1a30Sjl * restart if not mirror mode or the other bank 1892*25cf1a30Sjl * of the mirror is not running 1893*25cf1a30Sjl */ 1894*25cf1a30Sjl if (!(mirr & MAC_MIRR_MIRROR_MODE) || 1895*25cf1a30Sjl !(mcp->mc_bank[bk^1].mcb_status & 1896*25cf1a30Sjl BANK_PTRL_RUNNING)) { 1897*25cf1a30Sjl MC_LOG("Starting up /LSB%d/B%d\n", 1898*25cf1a30Sjl mcp->mc_board_num, bk); 1899*25cf1a30Sjl get_ptrl_start_address(mcp, bk, &maddr.mi_maddr); 1900*25cf1a30Sjl maddr.mi_valid = 1; 1901*25cf1a30Sjl maddr.mi_advance = 0; 1902*25cf1a30Sjl restart_patrol(mcp, bk, &maddr); 1903*25cf1a30Sjl } else { 1904*25cf1a30Sjl MC_LOG("Not starting up /LSB%d/B%d\n", 1905*25cf1a30Sjl mcp->mc_board_num, bk); 1906*25cf1a30Sjl } 1907*25cf1a30Sjl bankp->mcb_status |= BANK_PTRL_RUNNING; 1908*25cf1a30Sjl } 1909*25cf1a30Sjl kmem_free(macaddr, len); 1910*25cf1a30Sjl 1911*25cf1a30Sjl /* 1912*25cf1a30Sjl * set interval in HZ. 1913*25cf1a30Sjl */ 1914*25cf1a30Sjl for (i = 0; i < BANKNUM_PER_SB; i++) { 1915*25cf1a30Sjl mcp->mc_scf_retry[i] = 0; 1916*25cf1a30Sjl } 1917*25cf1a30Sjl mcp->mc_last_error = 0; 1918*25cf1a30Sjl mcp->mc_period = 0; 1919*25cf1a30Sjl 1920*25cf1a30Sjl mcp->mc_interval_hz = drv_usectohz(mc_patrol_interval_sec * 1000000); 1921*25cf1a30Sjl /* restart memory patrol checking */ 1922*25cf1a30Sjl mcp->mc_status |= MC_POLL_RUNNING; 1923*25cf1a30Sjl mcp->mc_tid = timeout(mc_check_errors, mcp, mcp->mc_interval_hz); 1924*25cf1a30Sjl 1925*25cf1a30Sjl return (DDI_SUCCESS); 1926*25cf1a30Sjl } 1927*25cf1a30Sjl 1928*25cf1a30Sjl int 1929*25cf1a30Sjl mc_board_del(mc_opl_t *mcp) 1930*25cf1a30Sjl { 1931*25cf1a30Sjl int i; 1932*25cf1a30Sjl scf_log_t *p; 1933*25cf1a30Sjl timeout_id_t tid = 0; 1934*25cf1a30Sjl 1935*25cf1a30Sjl /* 1936*25cf1a30Sjl * cleanup mac state 1937*25cf1a30Sjl */ 1938*25cf1a30Sjl mutex_enter(&mcp->mc_lock); 1939*25cf1a30Sjl for (i = 0; i < BANKNUM_PER_SB; i++) { 1940*25cf1a30Sjl if (mcp->mc_bank[i].mcb_status & BANK_INSTALLED) { 1941*25cf1a30Sjl if (mc_stop(mcp, i)) { 1942*25cf1a30Sjl mutex_exit(&mcp->mc_lock); 1943*25cf1a30Sjl return (-1); 1944*25cf1a30Sjl } 1945*25cf1a30Sjl mcp->mc_bank[i].mcb_status &= ~BANK_INSTALLED; 1946*25cf1a30Sjl } 1947*25cf1a30Sjl } 1948*25cf1a30Sjl 1949*25cf1a30Sjl /* stop memory patrol checking */ 1950*25cf1a30Sjl if (mcp->mc_status & MC_POLL_RUNNING) { 1951*25cf1a30Sjl mcp->mc_status &= ~MC_POLL_RUNNING; 1952*25cf1a30Sjl tid = mcp->mc_tid; 1953*25cf1a30Sjl mcp->mc_tid = 0; 1954*25cf1a30Sjl } 1955*25cf1a30Sjl 1956*25cf1a30Sjl /* just throw away all the scf logs */ 1957*25cf1a30Sjl while ((p = mcp->mc_scf_log) != NULL) { 1958*25cf1a30Sjl mcp->mc_scf_log = p->sl_next; 1959*25cf1a30Sjl mcp->mc_scf_total--; 1960*25cf1a30Sjl kmem_free(p, sizeof (scf_log_t)); 1961*25cf1a30Sjl } 1962*25cf1a30Sjl 1963*25cf1a30Sjl if (mcp->mlist) 1964*25cf1a30Sjl mc_memlist_delete(mcp->mlist); 1965*25cf1a30Sjl 1966*25cf1a30Sjl mutex_exit(&mcp->mc_lock); 1967*25cf1a30Sjl if (tid) 1968*25cf1a30Sjl (void) untimeout(tid); 1969*25cf1a30Sjl 1970*25cf1a30Sjl mutex_destroy(&mcp->mc_lock); 1971*25cf1a30Sjl return (DDI_SUCCESS); 1972*25cf1a30Sjl } 1973*25cf1a30Sjl 1974*25cf1a30Sjl int 1975*25cf1a30Sjl mc_suspend(mc_opl_t *mcp, uint32_t flag) 1976*25cf1a30Sjl { 1977*25cf1a30Sjl timeout_id_t tid = 0; 1978*25cf1a30Sjl int i; 1979*25cf1a30Sjl /* stop memory patrol checking */ 1980*25cf1a30Sjl mutex_enter(&mcp->mc_lock); 1981*25cf1a30Sjl if (mcp->mc_status & MC_POLL_RUNNING) { 1982*25cf1a30Sjl for (i = 0; i < BANKNUM_PER_SB; i++) { 1983*25cf1a30Sjl if (mcp->mc_bank[i].mcb_status & BANK_INSTALLED) { 1984*25cf1a30Sjl if (mc_stop(mcp, i)) { 1985*25cf1a30Sjl mutex_exit(&mcp->mc_lock); 1986*25cf1a30Sjl return (-1); 1987*25cf1a30Sjl } 1988*25cf1a30Sjl } 1989*25cf1a30Sjl } 1990*25cf1a30Sjl mcp->mc_status &= ~MC_POLL_RUNNING; 1991*25cf1a30Sjl tid = mcp->mc_tid; 1992*25cf1a30Sjl } 1993*25cf1a30Sjl mcp->mc_status |= flag; 1994*25cf1a30Sjl mcp->mc_tid = 0; 1995*25cf1a30Sjl mutex_exit(&mcp->mc_lock); 1996*25cf1a30Sjl if (tid) 1997*25cf1a30Sjl (void) untimeout(tid); 1998*25cf1a30Sjl 1999*25cf1a30Sjl return (DDI_SUCCESS); 2000*25cf1a30Sjl } 2001*25cf1a30Sjl 2002*25cf1a30Sjl /* caller must clear the SUSPEND bits or this will do nothing */ 2003*25cf1a30Sjl 2004*25cf1a30Sjl int 2005*25cf1a30Sjl mc_resume(mc_opl_t *mcp, uint32_t flag) 2006*25cf1a30Sjl { 2007*25cf1a30Sjl int i; 2008*25cf1a30Sjl uint64_t basepa; 2009*25cf1a30Sjl 2010*25cf1a30Sjl mutex_enter(&mcp->mc_lock); 2011*25cf1a30Sjl basepa = mcp->mc_start_address; 2012*25cf1a30Sjl if (get_base_address(mcp) == DDI_FAILURE) { 2013*25cf1a30Sjl mutex_exit(&mcp->mc_lock); 2014*25cf1a30Sjl return (DDI_FAILURE); 2015*25cf1a30Sjl } 2016*25cf1a30Sjl 2017*25cf1a30Sjl if (basepa != mcp->mc_start_address) { 2018*25cf1a30Sjl if (mcp->mlist) 2019*25cf1a30Sjl mc_memlist_delete(mcp->mlist); 2020*25cf1a30Sjl mcp->mlist = NULL; 2021*25cf1a30Sjl mc_get_mlist(mcp); 2022*25cf1a30Sjl } 2023*25cf1a30Sjl 2024*25cf1a30Sjl mcp->mc_status &= ~flag; 2025*25cf1a30Sjl mcp->mc_list->mc_start_address = mcp->mc_start_address; 2026*25cf1a30Sjl 2027*25cf1a30Sjl if (mcp->mc_status & (MC_SOFT_SUSPENDED | MC_DRIVER_SUSPENDED)) { 2028*25cf1a30Sjl mutex_exit(&mcp->mc_lock); 2029*25cf1a30Sjl return (DDI_SUCCESS); 2030*25cf1a30Sjl } 2031*25cf1a30Sjl 2032*25cf1a30Sjl if (!(mcp->mc_status & MC_POLL_RUNNING)) { 2033*25cf1a30Sjl /* restart memory patrol checking */ 2034*25cf1a30Sjl mcp->mc_status |= MC_POLL_RUNNING; 2035*25cf1a30Sjl for (i = 0; i < BANKNUM_PER_SB; i++) { 2036*25cf1a30Sjl if (mcp->mc_bank[i].mcb_status & BANK_INSTALLED) { 2037*25cf1a30Sjl restart_patrol(mcp, i, NULL); 2038*25cf1a30Sjl } 2039*25cf1a30Sjl } 2040*25cf1a30Sjl /* check error asap */ 2041*25cf1a30Sjl mcp->mc_tid = timeout(mc_check_errors, mcp, 1); 2042*25cf1a30Sjl } 2043*25cf1a30Sjl mutex_exit(&mcp->mc_lock); 2044*25cf1a30Sjl 2045*25cf1a30Sjl return (DDI_SUCCESS); 2046*25cf1a30Sjl } 2047*25cf1a30Sjl 2048*25cf1a30Sjl static mc_opl_t * 2049*25cf1a30Sjl mc_pa_to_mcp(uint64_t pa) 2050*25cf1a30Sjl { 2051*25cf1a30Sjl mc_inst_list_t *p; 2052*25cf1a30Sjl ASSERT(MUTEX_HELD(&mcmutex)); 2053*25cf1a30Sjl for (p = mc_instances; p; p = p->next) { 2054*25cf1a30Sjl /* if mac patrol is suspended, we cannot rely on it */ 2055*25cf1a30Sjl if (!(p->mc_opl->mc_status & MC_POLL_RUNNING) || 2056*25cf1a30Sjl (p->mc_opl->mc_status & MC_SOFT_SUSPENDED)) 2057*25cf1a30Sjl continue; 2058*25cf1a30Sjl if ((p->mc_start_address <= pa) && 2059*25cf1a30Sjl (pa < (p->mc_start_address + p->mc_size))) { 2060*25cf1a30Sjl return (p->mc_opl); 2061*25cf1a30Sjl } 2062*25cf1a30Sjl } 2063*25cf1a30Sjl return (NULL); 2064*25cf1a30Sjl } 2065*25cf1a30Sjl 2066*25cf1a30Sjl /* 2067*25cf1a30Sjl * Get Physical Board number from Logical one. 2068*25cf1a30Sjl */ 2069*25cf1a30Sjl static int 2070*25cf1a30Sjl mc_opl_get_physical_board(int sb) 2071*25cf1a30Sjl { 2072*25cf1a30Sjl if (&opl_get_physical_board) { 2073*25cf1a30Sjl return (opl_get_physical_board(sb)); 2074*25cf1a30Sjl } 2075*25cf1a30Sjl 2076*25cf1a30Sjl cmn_err(CE_NOTE, "!opl_get_physical_board() not loaded\n"); 2077*25cf1a30Sjl return (-1); 2078*25cf1a30Sjl } 2079*25cf1a30Sjl 2080*25cf1a30Sjl /* ARGSUSED */ 2081*25cf1a30Sjl int 2082*25cf1a30Sjl mc_get_mem_unum(int synd_code, uint64_t flt_addr, char *buf, int buflen, 2083*25cf1a30Sjl int *lenp) 2084*25cf1a30Sjl { 2085*25cf1a30Sjl mc_opl_t *mcp; 2086*25cf1a30Sjl int bank; 2087*25cf1a30Sjl int sb; 2088*25cf1a30Sjl 2089*25cf1a30Sjl mutex_enter(&mcmutex); 2090*25cf1a30Sjl 2091*25cf1a30Sjl if (((mcp = mc_pa_to_mcp(flt_addr)) == NULL) || 2092*25cf1a30Sjl (!pa_is_valid(mcp, flt_addr))) { 2093*25cf1a30Sjl mutex_exit(&mcmutex); 2094*25cf1a30Sjl if (snprintf(buf, buflen, "UNKNOWN") >= buflen) { 2095*25cf1a30Sjl return (ENOSPC); 2096*25cf1a30Sjl } else { 2097*25cf1a30Sjl if (lenp) 2098*25cf1a30Sjl *lenp = strlen(buf); 2099*25cf1a30Sjl } 2100*25cf1a30Sjl return (0); 2101*25cf1a30Sjl } 2102*25cf1a30Sjl 2103*25cf1a30Sjl bank = pa_to_bank(mcp, flt_addr - mcp->mc_start_address); 2104*25cf1a30Sjl sb = mc_opl_get_physical_board(mcp->mc_board_num); 2105*25cf1a30Sjl 2106*25cf1a30Sjl if (sb == -1) { 2107*25cf1a30Sjl mutex_exit(&mcmutex); 2108*25cf1a30Sjl return (ENXIO); 2109*25cf1a30Sjl } 2110*25cf1a30Sjl 2111*25cf1a30Sjl if (snprintf(buf, buflen, "/CMU%d/B%d", sb, bank) >= buflen) { 2112*25cf1a30Sjl mutex_exit(&mcmutex); 2113*25cf1a30Sjl return (ENOSPC); 2114*25cf1a30Sjl } else { 2115*25cf1a30Sjl if (lenp) 2116*25cf1a30Sjl *lenp = strlen(buf); 2117*25cf1a30Sjl } 2118*25cf1a30Sjl mutex_exit(&mcmutex); 2119*25cf1a30Sjl return (0); 2120*25cf1a30Sjl } 2121*25cf1a30Sjl 2122*25cf1a30Sjl int 2123*25cf1a30Sjl opl_mc_suspend() 2124*25cf1a30Sjl { 2125*25cf1a30Sjl mc_opl_t *mcp; 2126*25cf1a30Sjl mc_inst_list_t *p; 2127*25cf1a30Sjl 2128*25cf1a30Sjl mutex_enter(&mcmutex); 2129*25cf1a30Sjl 2130*25cf1a30Sjl for (p = mc_instances; p; p = p->next) { 2131*25cf1a30Sjl mcp = p->mc_opl; 2132*25cf1a30Sjl (void) mc_suspend(mcp, MC_SOFT_SUSPENDED); 2133*25cf1a30Sjl } 2134*25cf1a30Sjl 2135*25cf1a30Sjl mutex_exit(&mcmutex); 2136*25cf1a30Sjl return (0); 2137*25cf1a30Sjl } 2138*25cf1a30Sjl 2139*25cf1a30Sjl int 2140*25cf1a30Sjl opl_mc_resume() 2141*25cf1a30Sjl { 2142*25cf1a30Sjl mc_opl_t *mcp; 2143*25cf1a30Sjl mc_inst_list_t *p; 2144*25cf1a30Sjl 2145*25cf1a30Sjl mutex_enter(&mcmutex); 2146*25cf1a30Sjl 2147*25cf1a30Sjl for (p = mc_instances; p; p = p->next) { 2148*25cf1a30Sjl mcp = p->mc_opl; 2149*25cf1a30Sjl (void) mc_resume(mcp, MC_SOFT_SUSPENDED); 2150*25cf1a30Sjl } 2151*25cf1a30Sjl 2152*25cf1a30Sjl mutex_exit(&mcmutex); 2153*25cf1a30Sjl return (0); 2154*25cf1a30Sjl } 2155*25cf1a30Sjl 2156*25cf1a30Sjl static void 2157*25cf1a30Sjl insert_mcp(mc_opl_t *mcp) 2158*25cf1a30Sjl { 2159*25cf1a30Sjl mc_inst_list_t *p; 2160*25cf1a30Sjl 2161*25cf1a30Sjl p = kmem_zalloc(sizeof (mc_inst_list_t), KM_SLEEP); 2162*25cf1a30Sjl p->mc_opl = mcp; 2163*25cf1a30Sjl p->mc_board_num = mcp->mc_board_num; 2164*25cf1a30Sjl p->mc_start_address = mcp->mc_start_address; 2165*25cf1a30Sjl p->mc_size = mcp->mc_size; 2166*25cf1a30Sjl mcp->mc_list = p; 2167*25cf1a30Sjl 2168*25cf1a30Sjl mutex_enter(&mcmutex); 2169*25cf1a30Sjl 2170*25cf1a30Sjl p->next = mc_instances; 2171*25cf1a30Sjl mc_instances = p; 2172*25cf1a30Sjl 2173*25cf1a30Sjl mutex_exit(&mcmutex); 2174*25cf1a30Sjl } 2175*25cf1a30Sjl 2176*25cf1a30Sjl static void 2177*25cf1a30Sjl delete_mcp(mc_opl_t *mcp) 2178*25cf1a30Sjl { 2179*25cf1a30Sjl mc_inst_list_t *prev, *current; 2180*25cf1a30Sjl mc_inst_list_t *p; 2181*25cf1a30Sjl 2182*25cf1a30Sjl p = mcp->mc_list; 2183*25cf1a30Sjl 2184*25cf1a30Sjl if (mc_instances == p) { 2185*25cf1a30Sjl mc_instances = p->next; 2186*25cf1a30Sjl kmem_free(p, sizeof (mc_inst_list_t)); 2187*25cf1a30Sjl return; 2188*25cf1a30Sjl } 2189*25cf1a30Sjl prev = mc_instances; 2190*25cf1a30Sjl for (current = mc_instances; current != NULL; current = current->next) { 2191*25cf1a30Sjl if (current == p) { 2192*25cf1a30Sjl prev->next = p->next; 2193*25cf1a30Sjl kmem_free(p, sizeof (mc_inst_list_t)); 2194*25cf1a30Sjl return; 2195*25cf1a30Sjl } 2196*25cf1a30Sjl prev = current; 2197*25cf1a30Sjl } 2198*25cf1a30Sjl } 2199*25cf1a30Sjl 2200*25cf1a30Sjl /* Error injection interface */ 2201*25cf1a30Sjl 2202*25cf1a30Sjl /* ARGSUSED */ 2203*25cf1a30Sjl int 2204*25cf1a30Sjl mc_inject_error(int error_type, uint64_t pa, uint32_t flags) 2205*25cf1a30Sjl { 2206*25cf1a30Sjl mc_opl_t *mcp; 2207*25cf1a30Sjl int bank; 2208*25cf1a30Sjl uint32_t dimm_addr; 2209*25cf1a30Sjl uint32_t cntl; 2210*25cf1a30Sjl mc_addr_info_t maddr; 2211*25cf1a30Sjl uint32_t data, stat; 2212*25cf1a30Sjl int both_sides = 0; 2213*25cf1a30Sjl uint64_t pa0; 2214*25cf1a30Sjl on_trap_data_t otd; 2215*25cf1a30Sjl extern void cpu_flush_ecache(void); 2216*25cf1a30Sjl 2217*25cf1a30Sjl MC_LOG("HW mc_inject_error(%x, %lx, %x)\n", error_type, pa, flags); 2218*25cf1a30Sjl 2219*25cf1a30Sjl mutex_enter(&mcmutex); 2220*25cf1a30Sjl 2221*25cf1a30Sjl if ((mcp = mc_pa_to_mcp(pa)) == NULL) { 2222*25cf1a30Sjl mutex_exit(&mcmutex); 2223*25cf1a30Sjl MC_LOG("mc_inject_error: invalid pa\n"); 2224*25cf1a30Sjl return (ENOTSUP); 2225*25cf1a30Sjl } 2226*25cf1a30Sjl 2227*25cf1a30Sjl mutex_enter(&mcp->mc_lock); 2228*25cf1a30Sjl mutex_exit(&mcmutex); 2229*25cf1a30Sjl 2230*25cf1a30Sjl if (mcp->mc_status & (MC_SOFT_SUSPENDED | MC_DRIVER_SUSPENDED)) { 2231*25cf1a30Sjl mutex_exit(&mcp->mc_lock); 2232*25cf1a30Sjl MC_LOG("mc-opl has been suspended. No error injection.\n"); 2233*25cf1a30Sjl return (EBUSY); 2234*25cf1a30Sjl } 2235*25cf1a30Sjl 2236*25cf1a30Sjl /* convert pa to offset within the board */ 2237*25cf1a30Sjl MC_LOG("pa %lx, offset %lx\n", pa, pa - mcp->mc_start_address); 2238*25cf1a30Sjl 2239*25cf1a30Sjl if (!pa_is_valid(mcp, pa)) { 2240*25cf1a30Sjl mutex_exit(&mcp->mc_lock); 2241*25cf1a30Sjl return (EINVAL); 2242*25cf1a30Sjl } 2243*25cf1a30Sjl 2244*25cf1a30Sjl pa0 = pa - mcp->mc_start_address; 2245*25cf1a30Sjl 2246*25cf1a30Sjl bank = pa_to_bank(mcp, pa0); 2247*25cf1a30Sjl 2248*25cf1a30Sjl if (flags & MC_INJECT_FLAG_OTHER) 2249*25cf1a30Sjl bank = bank ^ 1; 2250*25cf1a30Sjl 2251*25cf1a30Sjl if (MC_INJECT_MIRROR(error_type) && !IS_MIRROR(mcp, bank)) { 2252*25cf1a30Sjl mutex_exit(&mcp->mc_lock); 2253*25cf1a30Sjl MC_LOG("Not mirror mode\n"); 2254*25cf1a30Sjl return (EINVAL); 2255*25cf1a30Sjl } 2256*25cf1a30Sjl 2257*25cf1a30Sjl dimm_addr = pa_to_dimm(mcp, pa0); 2258*25cf1a30Sjl 2259*25cf1a30Sjl MC_LOG("injecting error to /LSB%d/B%d/D%x\n", 2260*25cf1a30Sjl mcp->mc_board_num, bank, dimm_addr); 2261*25cf1a30Sjl 2262*25cf1a30Sjl 2263*25cf1a30Sjl switch (error_type) { 2264*25cf1a30Sjl case MC_INJECT_INTERMITTENT_MCE: 2265*25cf1a30Sjl case MC_INJECT_PERMANENT_MCE: 2266*25cf1a30Sjl case MC_INJECT_MUE: 2267*25cf1a30Sjl both_sides = 1; 2268*25cf1a30Sjl } 2269*25cf1a30Sjl 2270*25cf1a30Sjl if (flags & MC_INJECT_FLAG_RESET) 2271*25cf1a30Sjl ST_MAC_REG(MAC_EG_CNTL(mcp, bank), 0); 2272*25cf1a30Sjl 2273*25cf1a30Sjl ST_MAC_REG(MAC_EG_ADD(mcp, bank), dimm_addr & MAC_EG_ADD_MASK); 2274*25cf1a30Sjl 2275*25cf1a30Sjl if (both_sides) { 2276*25cf1a30Sjl ST_MAC_REG(MAC_EG_CNTL(mcp, bank^1), 0); 2277*25cf1a30Sjl ST_MAC_REG(MAC_EG_ADD(mcp, bank^1), 2278*25cf1a30Sjl dimm_addr & MAC_EG_ADD_MASK); 2279*25cf1a30Sjl } 2280*25cf1a30Sjl 2281*25cf1a30Sjl switch (error_type) { 2282*25cf1a30Sjl case MC_INJECT_UE: 2283*25cf1a30Sjl case MC_INJECT_SUE: 2284*25cf1a30Sjl case MC_INJECT_MUE: 2285*25cf1a30Sjl if (flags & MC_INJECT_FLAG_PATH) { 2286*25cf1a30Sjl cntl = MAC_EG_ADD_FIX 2287*25cf1a30Sjl |MAC_EG_FORCE_READ00|MAC_EG_FORCE_READ16 2288*25cf1a30Sjl |MAC_EG_DERR_ONCE; 2289*25cf1a30Sjl } else { 2290*25cf1a30Sjl cntl = MAC_EG_ADD_FIX|MAC_EG_FORCE_DERR00 2291*25cf1a30Sjl |MAC_EG_FORCE_DERR16|MAC_EG_DERR_ONCE; 2292*25cf1a30Sjl } 2293*25cf1a30Sjl flags |= MC_INJECT_FLAG_ST; 2294*25cf1a30Sjl break; 2295*25cf1a30Sjl case MC_INJECT_INTERMITTENT_CE: 2296*25cf1a30Sjl case MC_INJECT_INTERMITTENT_MCE: 2297*25cf1a30Sjl if (flags & MC_INJECT_FLAG_PATH) { 2298*25cf1a30Sjl cntl = MAC_EG_ADD_FIX 2299*25cf1a30Sjl |MAC_EG_FORCE_READ00 2300*25cf1a30Sjl |MAC_EG_DERR_ONCE; 2301*25cf1a30Sjl } else { 2302*25cf1a30Sjl cntl = MAC_EG_ADD_FIX 2303*25cf1a30Sjl |MAC_EG_FORCE_DERR16 2304*25cf1a30Sjl |MAC_EG_DERR_ONCE; 2305*25cf1a30Sjl } 2306*25cf1a30Sjl flags |= MC_INJECT_FLAG_ST; 2307*25cf1a30Sjl break; 2308*25cf1a30Sjl case MC_INJECT_PERMANENT_CE: 2309*25cf1a30Sjl case MC_INJECT_PERMANENT_MCE: 2310*25cf1a30Sjl if (flags & MC_INJECT_FLAG_PATH) { 2311*25cf1a30Sjl cntl = MAC_EG_ADD_FIX 2312*25cf1a30Sjl |MAC_EG_FORCE_READ00 2313*25cf1a30Sjl |MAC_EG_DERR_ALWAYS; 2314*25cf1a30Sjl } else { 2315*25cf1a30Sjl cntl = MAC_EG_ADD_FIX 2316*25cf1a30Sjl |MAC_EG_FORCE_DERR16 2317*25cf1a30Sjl |MAC_EG_DERR_ALWAYS; 2318*25cf1a30Sjl } 2319*25cf1a30Sjl flags |= MC_INJECT_FLAG_ST; 2320*25cf1a30Sjl break; 2321*25cf1a30Sjl case MC_INJECT_CMPE: 2322*25cf1a30Sjl data = 0xabcdefab; 2323*25cf1a30Sjl stphys(pa, data); 2324*25cf1a30Sjl cpu_flush_ecache(); 2325*25cf1a30Sjl MC_LOG("CMPE: writing data %x to %lx\n", data, pa); 2326*25cf1a30Sjl ST_MAC_REG(MAC_MIRR(mcp, bank), MAC_MIRR_BANK_EXCLUSIVE); 2327*25cf1a30Sjl stphys(pa, data ^ 0xffffffff); 2328*25cf1a30Sjl cpu_flush_ecache(); 2329*25cf1a30Sjl ST_MAC_REG(MAC_MIRR(mcp, bank), 0); 2330*25cf1a30Sjl MC_LOG("CMPE: write new data %xto %lx\n", data, pa); 2331*25cf1a30Sjl cntl = 0; 2332*25cf1a30Sjl break; 2333*25cf1a30Sjl case MC_INJECT_NOP: 2334*25cf1a30Sjl cntl = 0; 2335*25cf1a30Sjl break; 2336*25cf1a30Sjl default: 2337*25cf1a30Sjl MC_LOG("mc_inject_error: invalid option\n"); 2338*25cf1a30Sjl cntl = 0; 2339*25cf1a30Sjl } 2340*25cf1a30Sjl 2341*25cf1a30Sjl if (cntl) { 2342*25cf1a30Sjl ST_MAC_REG(MAC_EG_CNTL(mcp, bank), cntl & MAC_EG_SETUP_MASK); 2343*25cf1a30Sjl ST_MAC_REG(MAC_EG_CNTL(mcp, bank), cntl); 2344*25cf1a30Sjl 2345*25cf1a30Sjl if (both_sides) { 2346*25cf1a30Sjl ST_MAC_REG(MAC_EG_CNTL(mcp, bank^1), cntl & 2347*25cf1a30Sjl MAC_EG_SETUP_MASK); 2348*25cf1a30Sjl ST_MAC_REG(MAC_EG_CNTL(mcp, bank^1), cntl); 2349*25cf1a30Sjl } 2350*25cf1a30Sjl } 2351*25cf1a30Sjl 2352*25cf1a30Sjl /* 2353*25cf1a30Sjl * For all injection cases except compare error, we 2354*25cf1a30Sjl * must write to the PA to trigger the error. 2355*25cf1a30Sjl */ 2356*25cf1a30Sjl 2357*25cf1a30Sjl if (flags & MC_INJECT_FLAG_ST) { 2358*25cf1a30Sjl data = 0xf0e0d0c0; 2359*25cf1a30Sjl MC_LOG("Writing %x to %lx\n", data, pa); 2360*25cf1a30Sjl stphys(pa, data); 2361*25cf1a30Sjl cpu_flush_ecache(); 2362*25cf1a30Sjl } 2363*25cf1a30Sjl 2364*25cf1a30Sjl delay(inject_op_delay * drv_usectohz(1000 * 1000)); 2365*25cf1a30Sjl 2366*25cf1a30Sjl 2367*25cf1a30Sjl if (flags & MC_INJECT_FLAG_LD) { 2368*25cf1a30Sjl if (flags & MC_INJECT_FLAG_NO_TRAP) { 2369*25cf1a30Sjl if (on_trap(&otd, OT_DATA_EC)) { 2370*25cf1a30Sjl no_trap(); 2371*25cf1a30Sjl MC_LOG("Trap occurred\n"); 2372*25cf1a30Sjl } else { 2373*25cf1a30Sjl MC_LOG("On-trap Reading from %lx\n", pa); 2374*25cf1a30Sjl data = ldphys(pa); 2375*25cf1a30Sjl no_trap(); 2376*25cf1a30Sjl MC_LOG("data = %x\n", data); 2377*25cf1a30Sjl } 2378*25cf1a30Sjl } else { 2379*25cf1a30Sjl MC_LOG("Reading from %lx\n", pa); 2380*25cf1a30Sjl data = ldphys(pa); 2381*25cf1a30Sjl MC_LOG("data = %x\n", data); 2382*25cf1a30Sjl } 2383*25cf1a30Sjl } 2384*25cf1a30Sjl 2385*25cf1a30Sjl if (flags & MC_INJECT_FLAG_RESTART) { 2386*25cf1a30Sjl delay(inject_op_delay * drv_usectohz(1000 * 1000)); 2387*25cf1a30Sjl 2388*25cf1a30Sjl MC_LOG("Restart patrol\n"); 2389*25cf1a30Sjl if (mc_stop(mcp, bank)) { 2390*25cf1a30Sjl cmn_err(CE_WARN, "Cannot stop Memory Patrol at " 2391*25cf1a30Sjl "/LSB%d/B%d\n", mcp->mc_board_num, bank); 2392*25cf1a30Sjl mutex_exit(&mcp->mc_lock); 2393*25cf1a30Sjl return (EIO); 2394*25cf1a30Sjl } 2395*25cf1a30Sjl maddr.mi_maddr.ma_bd = mcp->mc_board_num; 2396*25cf1a30Sjl maddr.mi_maddr.ma_bank = bank; 2397*25cf1a30Sjl maddr.mi_maddr.ma_dimm_addr = dimm_addr; 2398*25cf1a30Sjl maddr.mi_valid = 1; 2399*25cf1a30Sjl maddr.mi_advance = 0; 2400*25cf1a30Sjl restart_patrol(mcp, bank, &maddr); 2401*25cf1a30Sjl } 2402*25cf1a30Sjl 2403*25cf1a30Sjl if (flags & MC_INJECT_FLAG_POLL) { 2404*25cf1a30Sjl delay(inject_op_delay * drv_usectohz(1000 * 1000)); 2405*25cf1a30Sjl 2406*25cf1a30Sjl MC_LOG("Poll patrol error\n"); 2407*25cf1a30Sjl stat = LD_MAC_REG(MAC_PTRL_STAT(mcp, bank)); 2408*25cf1a30Sjl cntl = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank)); 2409*25cf1a30Sjl if (stat & (MAC_STAT_PTRL_ERRS|MAC_STAT_MI_ERRS)) { 2410*25cf1a30Sjl maddr.mi_valid = 0; 2411*25cf1a30Sjl maddr.mi_advance = 1; 2412*25cf1a30Sjl if (IS_MIRROR(mcp, bank)) 2413*25cf1a30Sjl mc_error_handler_mir(mcp, bank, 2414*25cf1a30Sjl &maddr); 2415*25cf1a30Sjl else 2416*25cf1a30Sjl mc_error_handler(mcp, bank, &maddr); 2417*25cf1a30Sjl 2418*25cf1a30Sjl restart_patrol(mcp, bank, &maddr); 2419*25cf1a30Sjl } else 2420*25cf1a30Sjl restart_patrol(mcp, bank, NULL); 2421*25cf1a30Sjl } 2422*25cf1a30Sjl 2423*25cf1a30Sjl mutex_exit(&mcp->mc_lock); 2424*25cf1a30Sjl return (0); 2425*25cf1a30Sjl } 2426*25cf1a30Sjl 2427*25cf1a30Sjl void 2428*25cf1a30Sjl mc_stphysio(uint64_t pa, uint32_t data) 2429*25cf1a30Sjl { 2430*25cf1a30Sjl MC_LOG("0x%x -> pa(%lx)\n", data, pa); 2431*25cf1a30Sjl stphysio(pa, data); 2432*25cf1a30Sjl } 2433*25cf1a30Sjl 2434*25cf1a30Sjl uint32_t 2435*25cf1a30Sjl mc_ldphysio(uint64_t pa) 2436*25cf1a30Sjl { 2437*25cf1a30Sjl uint32_t rv; 2438*25cf1a30Sjl 2439*25cf1a30Sjl rv = ldphysio(pa); 2440*25cf1a30Sjl MC_LOG("pa(%lx) = 0x%x\n", pa, rv); 2441*25cf1a30Sjl return (rv); 2442*25cf1a30Sjl } 2443