1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  24  */
  25 
  26 /*
  27  * Intel model-specific support.  Right now all this conists of is
  28  * to modify the ereport subclass to produce different ereport classes
  29  * so that we can have different diagnosis rules and corresponding faults.
  30  */
  31 
  32 #include <sys/types.h>
  33 #include <sys/cmn_err.h>
  34 #include <sys/modctl.h>
  35 #include <sys/mca_x86.h>
  36 #include <sys/cpu_module_ms_impl.h>
  37 #include <sys/mc_intel.h>
  38 #include <sys/pci_cfgspace.h>
  39 #include <sys/fm/protocol.h>
  40 #include <sys/fm/util.h>
  41 #include <sys/fm/smb/fmsmb.h>
  42 
  43 extern int x86gentopo_legacy;
  44 
  45 int gintel_ms_support_disable = 0;
  46 int gintel_error_action_return = 0;
  47 int gintel_ms_unconstrained = 0;
  48 
  49 int quickpath;
  50 int max_bus_number = 0xff;
  51 
  52 #define ERR_COUNTER_INDEX       2
  53 #define MAX_CPU_NODES           2
  54 #define N_MC_COR_ECC_CNT        6
  55 uint32_t err_counter_array[MAX_CPU_NODES][ERR_COUNTER_INDEX][N_MC_COR_ECC_CNT];
  56 uint8_t err_counter_index[MAX_CPU_NODES];
  57 
  58 #define MAX_BUS_NUMBER  max_bus_number
  59 #define SOCKET_BUS(cpu) (MAX_BUS_NUMBER - (cpu))
  60 
  61 #define MC_COR_ECC_CNT(chipid, reg)     (*pci_getl_func)(SOCKET_BUS(chipid), \
  62     NEHALEM_EP_MEMORY_CONTROLLER_DEV, NEHALEM_EP_MEMORY_CONTROLLER_FUNC, \
  63     0x80 + (reg) * 4)
  64 
  65 #define MSCOD_MEM_ECC_READ      0x1
  66 #define MSCOD_MEM_ECC_SCRUB     0x2
  67 #define MSCOD_MEM_WR_PARITY     0x4
  68 #define MSCOD_MEM_REDUNDANT_MEM 0x8
  69 #define MSCOD_MEM_SPARE_MEM     0x10
  70 #define MSCOD_MEM_ILLEGAL_ADDR  0x20
  71 #define MSCOD_MEM_BAD_ID        0x40
  72 #define MSCOD_MEM_ADDR_PARITY   0x80
  73 #define MSCOD_MEM_BYTE_PARITY   0x100
  74 
  75 #define GINTEL_ERROR_MEM        0x1000
  76 #define GINTEL_ERROR_QUICKPATH  0x2000
  77 #define GINTEL_ERROR_UNKNOWN    0x4000
  78 
  79 #define GINTEL_ERR_SPARE_MEM    (GINTEL_ERROR_MEM | 1)
  80 #define GINTEL_ERR_MEM_UE       (GINTEL_ERROR_MEM | 2)
  81 #define GINTEL_ERR_MEM_CE       (GINTEL_ERROR_MEM | 3)
  82 #define GINTEL_ERR_MEM_PARITY   (GINTEL_ERROR_MEM | 4)
  83 #define GINTEL_ERR_MEM_ADDR_PARITY      (GINTEL_ERROR_MEM | 5)
  84 #define GINTEL_ERR_MEM_REDUNDANT (GINTEL_ERROR_MEM | 6)
  85 #define GINTEL_ERR_MEM_BAD_ADDR (GINTEL_ERROR_MEM | 7)
  86 #define GINTEL_ERR_MEM_BAD_ID   (GINTEL_ERROR_MEM | 8)
  87 #define GINTEL_ERR_MEM_UNKNOWN  (GINTEL_ERROR_MEM | 0xfff)
  88 
  89 #define MSR_MC_MISC_MEM_CHANNEL_MASK    0x00000000000c0000ULL
  90 #define MSR_MC_MISC_MEM_CHANNEL_SHIFT   18
  91 #define MSR_MC_MISC_MEM_DIMM_MASK       0x0000000000030000ULL
  92 #define MSR_MC_MISC_MEM_DIMM_SHIFT      16
  93 #define MSR_MC_MISC_MEM_SYNDROME_MASK   0xffffffff00000000ULL
  94 #define MSR_MC_MISC_MEM_SYNDROME_SHIFT  32
  95 
  96 #define CPU_GENERATION_DONT_CARE        0
  97 #define CPU_GENERATION_NEHALEM_EP       1
  98 
  99 #define INTEL_CPU_6_ID                  0x6
 100 #define INTEL_NEHALEM_CPU_FAMILY_ID     0x6
 101 #define INTEL_NEHALEM_CPU_MODEL_ID      0x1A
 102 
 103 #define NEHALEM_EP_MEMORY_CONTROLLER_DEV        0x3
 104 #define NEHALEM_EP_MEMORY_CONTROLLER_FUNC       0x2
 105 
 106 /*ARGSUSED*/
 107 int
 108 gintel_init(cmi_hdl_t hdl, void **datap)
 109 {
 110         uint32_t nb_chipset;
 111 
 112         if (gintel_ms_support_disable)
 113                 return (ENOTSUP);
 114 
 115         if (!is_x86_feature(x86_featureset, X86FSET_MCA))
 116                 return (ENOTSUP);
 117 
 118         nb_chipset = (*pci_getl_func)(0, 0, 0, 0x0);
 119         switch (nb_chipset) {
 120         case INTEL_NB_7300:
 121         case INTEL_NB_5000P:
 122         case INTEL_NB_5000X:
 123         case INTEL_NB_5000V:
 124         case INTEL_NB_5000Z:
 125         case INTEL_NB_5400:
 126         case INTEL_NB_5400A:
 127         case INTEL_NB_5400B:
 128                 if (!gintel_ms_unconstrained)
 129                         gintel_error_action_return |= CMS_ERRSCOPE_POISONED;
 130                 break;
 131         case INTEL_QP_IO:
 132         case INTEL_QP_WP:
 133         case INTEL_QP_36D:
 134         case INTEL_QP_24D:
 135         case INTEL_QP_U1:
 136         case INTEL_QP_U2:
 137         case INTEL_QP_U3:
 138         case INTEL_QP_U4:
 139         case INTEL_QP_JF:
 140         case INTEL_QP_JF0:
 141         case INTEL_QP_JF1:
 142         case INTEL_QP_JF2:
 143         case INTEL_QP_JF3:
 144         case INTEL_QP_JF4:
 145         case INTEL_QP_JF5:
 146         case INTEL_QP_JF6:
 147         case INTEL_QP_JF7:
 148         case INTEL_QP_JF8:
 149         case INTEL_QP_JF9:
 150         case INTEL_QP_JFa:
 151         case INTEL_QP_JFb:
 152         case INTEL_QP_JFc:
 153         case INTEL_QP_JFd:
 154         case INTEL_QP_JFe:
 155         case INTEL_QP_JFf:
 156                 quickpath = 1;
 157                 break;
 158         default:
 159                 break;
 160         }
 161         return (0);
 162 }
 163 
 164 /*ARGSUSED*/
 165 uint32_t
 166 gintel_error_action(cmi_hdl_t hdl, int ismc, int bank,
 167     uint64_t status, uint64_t addr, uint64_t misc, void *mslogout)
 168 {
 169         uint32_t rc;
 170 
 171         if (ismc == 0 && bank == 0 &&
 172             cmi_hdl_family(hdl) == INTEL_CPU_6_ID &&
 173             cmi_hdl_model(hdl) < INTEL_NEHALEM_CPU_MODEL_ID &&
 174             MCAX86_ERRCODE_ISBUS_INTERCONNECT(MCAX86_ERRCODE(status)) &&
 175             MCAX86_MSERRCODE(status) == 0) {
 176                 rc = CMS_ERRSCOPE_CURCONTEXT_OK | CMS_ERRSCOPE_CLEARED_UC;
 177         } else if ((status & MSR_MC_STATUS_PCC) == 0) {
 178                 rc = gintel_error_action_return;
 179         } else {
 180                 rc = gintel_error_action_return & ~CMS_ERRSCOPE_POISONED;
 181         }
 182         return (rc);
 183 }
 184 
 185 /*ARGSUSED*/
 186 cms_cookie_t
 187 gintel_disp_match(cmi_hdl_t hdl, int ismc, int bank, uint64_t status,
 188     uint64_t addr, uint64_t misc, void *mslogout)
 189 {
 190         cms_cookie_t rt = (cms_cookie_t)NULL;
 191         uint16_t mcacode = MCAX86_ERRCODE(status);
 192         uint16_t mscode = MCAX86_MSERRCODE(status);
 193 
 194         if (MCAX86_ERRCODE_ISMEMORY_CONTROLLER(mcacode)) {
 195                 /*
 196                  * memory controller errors
 197                  */
 198                 if (mscode & MSCOD_MEM_SPARE_MEM) {
 199                         rt = (cms_cookie_t)GINTEL_ERR_SPARE_MEM;
 200                 } else if (mscode & (MSCOD_MEM_ECC_READ |
 201                     MSCOD_MEM_ECC_SCRUB)) {
 202                         if (status & MSR_MC_STATUS_UC)
 203                                 rt = (cms_cookie_t)GINTEL_ERR_MEM_UE;
 204                         else
 205                                 rt = (cms_cookie_t)GINTEL_ERR_MEM_CE;
 206                 } else if (mscode & (MSCOD_MEM_WR_PARITY |
 207                     MSCOD_MEM_BYTE_PARITY)) {
 208                         rt = (cms_cookie_t)GINTEL_ERR_MEM_PARITY;
 209                 } else if (mscode & MSCOD_MEM_ADDR_PARITY) {
 210                         rt = (cms_cookie_t)GINTEL_ERR_MEM_ADDR_PARITY;
 211                 } else if (mscode & MSCOD_MEM_REDUNDANT_MEM) {
 212                         rt = (cms_cookie_t)GINTEL_ERR_MEM_REDUNDANT;
 213                 } else if (mscode & MSCOD_MEM_ILLEGAL_ADDR) {
 214                         rt = (cms_cookie_t)GINTEL_ERR_MEM_BAD_ADDR;
 215                 } else if (mscode & MSCOD_MEM_BAD_ID) {
 216                         rt = (cms_cookie_t)GINTEL_ERR_MEM_BAD_ID;
 217                 } else {
 218                         rt = (cms_cookie_t)GINTEL_ERR_MEM_UNKNOWN;
 219                 }
 220         } else if (quickpath &&
 221             MCAX86_ERRCODE_ISBUS_INTERCONNECT(MCAX86_ERRCODE(status))) {
 222                 rt = (cms_cookie_t)GINTEL_ERROR_QUICKPATH;
 223         } else if (ismc == 0 && bank == 0 &&
 224             cmi_hdl_family(hdl) == INTEL_CPU_6_ID &&
 225             cmi_hdl_model(hdl) < INTEL_NEHALEM_CPU_MODEL_ID &&
 226             MCAX86_ERRCODE_ISBUS_INTERCONNECT(MCAX86_ERRCODE(status)) &&
 227             MCAX86_MSERRCODE(status) == 0) {
 228                 rt = (cms_cookie_t)GINTEL_ERROR_UNKNOWN;
 229         }
 230         return (rt);
 231 }
 232 
 233 /*ARGSUSED*/
 234 void
 235 gintel_ereport_class(cmi_hdl_t hdl, cms_cookie_t mscookie,
 236     const char **cpuclsp, const char **leafclsp)
 237 {
 238         *cpuclsp = FM_EREPORT_CPU_INTEL;
 239         switch ((uintptr_t)mscookie) {
 240         case GINTEL_ERROR_QUICKPATH:
 241                 *leafclsp = "quickpath.interconnect";
 242                 break;
 243         case GINTEL_ERR_SPARE_MEM:
 244                 *leafclsp = "quickpath.mem_spare";
 245                 break;
 246         case GINTEL_ERR_MEM_UE:
 247                 *leafclsp = "quickpath.mem_ue";
 248                 break;
 249         case GINTEL_ERR_MEM_CE:
 250                 *leafclsp = "quickpath.mem_ce";
 251                 break;
 252         case GINTEL_ERR_MEM_PARITY:
 253                 *leafclsp = "quickpath.mem_parity";
 254                 break;
 255         case GINTEL_ERR_MEM_ADDR_PARITY:
 256                 *leafclsp = "quickpath.mem_addr_parity";
 257                 break;
 258         case GINTEL_ERR_MEM_REDUNDANT:
 259                 *leafclsp = "quickpath.mem_redundant";
 260                 break;
 261         case GINTEL_ERR_MEM_BAD_ADDR:
 262                 *leafclsp = "quickpath.mem_bad_addr";
 263                 break;
 264         case GINTEL_ERR_MEM_BAD_ID:
 265                 *leafclsp = "quickpath.mem_bad_id";
 266                 break;
 267         case GINTEL_ERR_MEM_UNKNOWN:
 268                 *leafclsp = "quickpath.mem_unknown";
 269                 break;
 270         case GINTEL_ERROR_UNKNOWN:
 271                 *leafclsp = "unknown";
 272                 break;
 273         }
 274 }
 275 
 276 static nvlist_t *
 277 gintel_gentopo_ereport_detector(cmi_hdl_t hdl, cms_cookie_t mscookie,
 278     nv_alloc_t *nva)
 279 {
 280         nvlist_t *nvl = (nvlist_t *)NULL;
 281         nvlist_t *board_list = (nvlist_t *)NULL;
 282 
 283         if (mscookie) {
 284                 board_list = cmi_hdl_smb_bboard(hdl);
 285 
 286                 if (board_list == NULL)
 287                         return (NULL);
 288 
 289                 if ((nvl = fm_nvlist_create(nva)) == NULL)
 290                         return (NULL);
 291 
 292                 if ((uintptr_t)mscookie & GINTEL_ERROR_QUICKPATH) {
 293                         fm_fmri_hc_create(nvl, FM_HC_SCHEME_VERSION,
 294                             NULL, NULL, board_list, 1,
 295                             "chip", cmi_hdl_smb_chipid(hdl));
 296                 } else {
 297                         fm_fmri_hc_create(nvl, FM_HC_SCHEME_VERSION,
 298                             NULL, NULL, board_list, 2,
 299                             "chip", cmi_hdl_smb_chipid(hdl),
 300                             "memory-controller", 0);
 301                 }
 302         }
 303         return (nvl);
 304 }
 305 
 306 /*ARGSUSED*/
 307 nvlist_t *
 308 gintel_ereport_detector(cmi_hdl_t hdl, int bankno, cms_cookie_t mscookie,
 309     nv_alloc_t *nva)
 310 {
 311         nvlist_t *nvl = (nvlist_t *)NULL;
 312 
 313         if (!x86gentopo_legacy) {
 314                 nvl = gintel_gentopo_ereport_detector(hdl, mscookie, nva);
 315                 return (nvl);
 316         }
 317 
 318         if (mscookie) {
 319                 if ((nvl = fm_nvlist_create(nva)) == NULL)
 320                         return (NULL);
 321                 if (((uintptr_t)mscookie & GINTEL_ERROR_QUICKPATH) ||
 322                     ((uintptr_t)mscookie & GINTEL_ERROR_UNKNOWN)) {
 323                         fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, NULL, 2,
 324                             "motherboard", 0,
 325                             "chip", cmi_hdl_chipid(hdl));
 326                 } else {
 327                         fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, NULL, 3,
 328                             "motherboard", 0,
 329                             "chip", cmi_hdl_chipid(hdl),
 330                             "memory-controller", 0);
 331                 }
 332         }
 333         return (nvl);
 334 }
 335 
 336 static nvlist_t *
 337 gintel_gentopo_ereport_create_resource_elem(cmi_hdl_t hdl, nv_alloc_t *nva,
 338     mc_unum_t *unump)
 339 {
 340         nvlist_t *nvl, *snvl;
 341         nvlist_t *board_list = NULL;
 342 
 343         board_list = cmi_hdl_smb_bboard(hdl);
 344         if (board_list == NULL) {
 345                 return (NULL);
 346         }
 347 
 348         if ((nvl = fm_nvlist_create(nva)) == NULL)      /* freed by caller */
 349                 return (NULL);
 350 
 351         if ((snvl = fm_nvlist_create(nva)) == NULL) {
 352                 fm_nvlist_destroy(nvl, nva ? FM_NVA_RETAIN : FM_NVA_FREE);
 353                 return (NULL);
 354         }
 355 
 356         (void) nvlist_add_uint64(snvl, FM_FMRI_HC_SPECIFIC_OFFSET,
 357             unump->unum_offset);
 358 
 359         if (unump->unum_chan == -1) {
 360                 fm_fmri_hc_create(nvl, FM_HC_SCHEME_VERSION, NULL, snvl,
 361                     board_list, 2,
 362                     "chip", cmi_hdl_smb_chipid(hdl),
 363                     "memory-controller", unump->unum_mc);
 364         } else if (unump->unum_cs == -1) {
 365                 fm_fmri_hc_create(nvl, FM_HC_SCHEME_VERSION, NULL, snvl,
 366                     board_list, 3,
 367                     "chip", cmi_hdl_smb_chipid(hdl),
 368                     "memory-controller", unump->unum_mc,
 369                     "dram-channel", unump->unum_chan);
 370         } else if (unump->unum_rank == -1) {
 371                 fm_fmri_hc_create(nvl, FM_HC_SCHEME_VERSION, NULL, snvl,
 372                     board_list, 4,
 373                     "chip", cmi_hdl_smb_chipid(hdl),
 374                     "memory-controller", unump->unum_mc,
 375                     "dram-channel", unump->unum_chan,
 376                     "dimm", unump->unum_cs);
 377         } else {
 378                 fm_fmri_hc_create(nvl, FM_HC_SCHEME_VERSION, NULL, snvl,
 379                     board_list, 5,
 380                     "chip", cmi_hdl_smb_chipid(hdl),
 381                     "memory-controller", unump->unum_mc,
 382                     "dram-channel", unump->unum_chan,
 383                     "dimm", unump->unum_cs,
 384                     "rank", unump->unum_rank);
 385         }
 386 
 387         fm_nvlist_destroy(snvl, nva ? FM_NVA_RETAIN : FM_NVA_FREE);
 388 
 389         return (nvl);
 390 }
 391 
 392 static nvlist_t *
 393 gintel_ereport_create_resource_elem(nv_alloc_t *nva, mc_unum_t *unump)
 394 {
 395         nvlist_t *nvl, *snvl;
 396 
 397         if ((nvl = fm_nvlist_create(nva)) == NULL)      /* freed by caller */
 398                 return (NULL);
 399 
 400         if ((snvl = fm_nvlist_create(nva)) == NULL) {
 401                 fm_nvlist_destroy(nvl, nva ? FM_NVA_RETAIN : FM_NVA_FREE);
 402                 return (NULL);
 403         }
 404 
 405         (void) nvlist_add_uint64(snvl, FM_FMRI_HC_SPECIFIC_OFFSET,
 406             unump->unum_offset);
 407 
 408         if (unump->unum_chan == -1) {
 409                 fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, snvl, 3,
 410                     "motherboard", unump->unum_board,
 411                     "chip", unump->unum_chip,
 412                     "memory-controller", unump->unum_mc);
 413         } else if (unump->unum_cs == -1) {
 414                 fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, snvl, 4,
 415                     "motherboard", unump->unum_board,
 416                     "chip", unump->unum_chip,
 417                     "memory-controller", unump->unum_mc,
 418                     "dram-channel", unump->unum_chan);
 419         } else if (unump->unum_rank == -1) {
 420                 fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, snvl, 5,
 421                     "motherboard", unump->unum_board,
 422                     "chip", unump->unum_chip,
 423                     "memory-controller", unump->unum_mc,
 424                     "dram-channel", unump->unum_chan,
 425                     "dimm", unump->unum_cs);
 426         } else {
 427                 fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, snvl, 6,
 428                     "motherboard", unump->unum_board,
 429                     "chip", unump->unum_chip,
 430                     "memory-controller", unump->unum_mc,
 431                     "dram-channel", unump->unum_chan,
 432                     "dimm", unump->unum_cs,
 433                     "rank", unump->unum_rank);
 434         }
 435 
 436         fm_nvlist_destroy(snvl, nva ? FM_NVA_RETAIN : FM_NVA_FREE);
 437 
 438         return (nvl);
 439 }
 440 
 441 static void
 442 nehalem_ep_ereport_add_memory_error_counter(uint_t  chipid,
 443     uint32_t *this_err_counter_array)
 444 {
 445         int     index;
 446 
 447         for (index = 0; index < N_MC_COR_ECC_CNT; index ++)
 448                 this_err_counter_array[index] = MC_COR_ECC_CNT(chipid, index);
 449 }
 450 
 451 static int
 452 gintel_cpu_generation(cmi_hdl_t hdl)
 453 {
 454         int     cpu_generation = CPU_GENERATION_DONT_CARE;
 455 
 456         if ((cmi_hdl_family(hdl) == INTEL_NEHALEM_CPU_FAMILY_ID) &&
 457             (cmi_hdl_model(hdl) == INTEL_NEHALEM_CPU_MODEL_ID))
 458                 cpu_generation = CPU_GENERATION_NEHALEM_EP;
 459 
 460         return (cpu_generation);
 461 }
 462 
 463 /*ARGSUSED*/
 464 void
 465 gintel_ereport_add_logout(cmi_hdl_t hdl, nvlist_t *ereport,
 466     nv_alloc_t *nva, int banknum, uint64_t status, uint64_t addr,
 467     uint64_t misc, void *mslogout, cms_cookie_t mscookie)
 468 {
 469         mc_unum_t unum;
 470         nvlist_t *resource;
 471         uint32_t synd = 0;
 472         int  chan = MCAX86_ERRCODE_CCCC(status);
 473         uint8_t last_index, this_index;
 474         int chipid;
 475 
 476         if (chan == 0xf)
 477                 chan = -1;
 478 
 479         if ((uintptr_t)mscookie & GINTEL_ERROR_MEM) {
 480                 unum.unum_board = 0;
 481                 unum.unum_chip = cmi_hdl_chipid(hdl);
 482                 unum.unum_mc = 0;
 483                 unum.unum_chan = chan;
 484                 unum.unum_cs = -1;
 485                 unum.unum_rank = -1;
 486                 unum.unum_offset = -1ULL;
 487                 if (status & MSR_MC_STATUS_MISCV) {
 488                         unum.unum_chan =
 489                             (misc & MSR_MC_MISC_MEM_CHANNEL_MASK) >>
 490                             MSR_MC_MISC_MEM_CHANNEL_SHIFT;
 491                         unum.unum_cs =
 492                             (misc & MSR_MC_MISC_MEM_DIMM_MASK) >>
 493                             MSR_MC_MISC_MEM_DIMM_SHIFT;
 494                         synd = (misc & MSR_MC_MISC_MEM_SYNDROME_MASK) >>
 495                             MSR_MC_MISC_MEM_SYNDROME_SHIFT;
 496                         fm_payload_set(ereport, FM_EREPORT_PAYLOAD_ECC_SYND,
 497                             DATA_TYPE_UINT32, synd, 0);
 498                 }
 499                 if (status & MSR_MC_STATUS_ADDRV) {
 500                         fm_payload_set(ereport, FM_FMRI_MEM_PHYSADDR,
 501                             DATA_TYPE_UINT64, addr, NULL);
 502                         (void) cmi_mc_patounum(addr, 0, 0, synd, 0, &unum);
 503                         if (unum.unum_offset != -1ULL &&
 504                             (unum.unum_offset & OFFSET_ROW_BANK_COL) != 0) {
 505                                 fm_payload_set(ereport,
 506                                     FM_EREPORT_PAYLOAD_NAME_BANK,
 507                                     DATA_TYPE_INT32,
 508                                     TCODE_OFFSET_BANK(unum.unum_offset), NULL);
 509                                 fm_payload_set(ereport,
 510                                     FM_EREPORT_PAYLOAD_NAME_CAS,
 511                                     DATA_TYPE_INT32,
 512                                     TCODE_OFFSET_CAS(unum.unum_offset), NULL);
 513                                 fm_payload_set(ereport,
 514                                     FM_EREPORT_PAYLOAD_NAME_RAS,
 515                                     DATA_TYPE_INT32,
 516                                     TCODE_OFFSET_RAS(unum.unum_offset), NULL);
 517                         }
 518                 }
 519 
 520                 if (!x86gentopo_legacy) {
 521                         resource = gintel_gentopo_ereport_create_resource_elem(
 522                             hdl, nva, &unum);
 523                 } else {
 524                         resource = gintel_ereport_create_resource_elem(nva,
 525                             &unum);
 526                 }
 527 
 528                 fm_payload_set(ereport, FM_EREPORT_PAYLOAD_NAME_RESOURCE,
 529                     DATA_TYPE_NVLIST_ARRAY, 1, &resource, NULL);
 530                 fm_nvlist_destroy(resource, nva ? FM_NVA_RETAIN:FM_NVA_FREE);
 531 
 532                 if (gintel_cpu_generation(hdl) == CPU_GENERATION_NEHALEM_EP) {
 533 
 534                         chipid = unum.unum_chip;
 535                         if (chipid < MAX_CPU_NODES) {
 536                                 last_index = err_counter_index[chipid];
 537                                 this_index =
 538                                     (last_index + 1) % ERR_COUNTER_INDEX;
 539                                 err_counter_index[chipid] = this_index;
 540                                 nehalem_ep_ereport_add_memory_error_counter(
 541                                     chipid,
 542                                     err_counter_array[chipid][this_index]);
 543                                 fm_payload_set(ereport,
 544                                     FM_EREPORT_PAYLOAD_MEM_ECC_COUNTER_THIS,
 545                                     DATA_TYPE_UINT32_ARRAY, N_MC_COR_ECC_CNT,
 546                                     err_counter_array[chipid][this_index],
 547                                     NULL);
 548                                 fm_payload_set(ereport,
 549                                     FM_EREPORT_PAYLOAD_MEM_ECC_COUNTER_LAST,
 550                                     DATA_TYPE_UINT32_ARRAY, N_MC_COR_ECC_CNT,
 551                                     err_counter_array[chipid][last_index],
 552                                     NULL);
 553                         }
 554                 }
 555         }
 556 }
 557 
 558 boolean_t
 559 gintel_bankctl_skipinit(cmi_hdl_t hdl, int banknum)
 560 {
 561         /*
 562          * On Intel family 6 before QuickPath we must not enable machine check
 563          * from bank 0 detectors. bank 0 is reserved for the platform
 564          */
 565 
 566         if (banknum == 0 &&
 567             cmi_hdl_family(hdl) == INTEL_NEHALEM_CPU_FAMILY_ID &&
 568             cmi_hdl_model(hdl) < INTEL_NEHALEM_CPU_MODEL_ID)
 569                 return (1);
 570         else
 571                 return (0);
 572 }
 573 
 574 cms_api_ver_t _cms_api_version = CMS_API_VERSION_2;
 575 
 576 const cms_ops_t _cms_ops = {
 577         gintel_init,            /* cms_init */
 578         NULL,                   /* cms_post_startup */
 579         NULL,                   /* cms_post_mpstartup */
 580         NULL,                   /* cms_logout_size */
 581         NULL,                   /* cms_mcgctl_val */
 582         gintel_bankctl_skipinit, /* cms_bankctl_skipinit */
 583         NULL,                   /* cms_bankctl_val */
 584         NULL,                   /* cms_bankstatus_skipinit */
 585         NULL,                   /* cms_bankstatus_val */
 586         NULL,                   /* cms_mca_init */
 587         NULL,                   /* cms_poll_ownermask */
 588         NULL,                   /* cms_bank_logout */
 589         gintel_error_action,    /* cms_error_action */
 590         gintel_disp_match,      /* cms_disp_match */
 591         gintel_ereport_class,   /* cms_ereport_class */
 592         gintel_ereport_detector,        /* cms_ereport_detector */
 593         NULL,                   /* cms_ereport_includestack */
 594         gintel_ereport_add_logout,      /* cms_ereport_add_logout */
 595         NULL,                   /* cms_msrinject */
 596         NULL,                   /* cms_fini */
 597 };
 598 
 599 static struct modlcpu modlcpu = {
 600         &mod_cpuops,
 601         "Generic Intel model-specific MCA"
 602 };
 603 
 604 static struct modlinkage modlinkage = {
 605         MODREV_1,
 606         { (void *)&modlcpu, NULL }
 607 };
 608 
 609 int
 610 _init(void)
 611 {
 612         return (mod_install(&modlinkage));
 613 }
 614 
 615 int
 616 _info(struct modinfo *modinfop)
 617 {
 618         return (mod_info(&modlinkage, modinfop));
 619 }
 620 
 621 int
 622 _fini(void)
 623 {
 624         return (mod_remove(&modlinkage));
 625 }