mcamd_patounum.c revision 4156fc34b973159b0334e05ae5ec19344487bdc0
8b464eb836173b92f2b7a65623cd06c8c3c59289mec/*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * CDDL HEADER START
8b464eb836173b92f2b7a65623cd06c8c3c59289mec *
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * The contents of this file are subject to the terms of the
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Common Development and Distribution License (the "License").
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * You may not use this file except in compliance with the License.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec *
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * or http://www.opensolaris.org/os/licensing.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * See the License for the specific language governing permissions
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * and limitations under the License.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec *
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * When distributing Covered Code, include this CDDL HEADER in each
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * If applicable, add the following below this CDDL HEADER, with the
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * fields enclosed by brackets "[]" replaced with your own identifying
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * information: Portions Copyright [yyyy] [name of copyright owner]
8b464eb836173b92f2b7a65623cd06c8c3c59289mec *
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * CDDL HEADER END
8b464eb836173b92f2b7a65623cd06c8c3c59289mec *
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
193974072f41a843678abf5f61979c748687e66bSherry Moore * Use is subject to license terms.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec#pragma ident "%Z%%M% %I% %E% SMI"
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec/*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Given a physical address and an optional syndrome, determine the
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * name of the memory module that contains it.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec#include <sys/errno.h>
8b464eb836173b92f2b7a65623cd06c8c3c59289mec#include <sys/types.h>
8b464eb836173b92f2b7a65623cd06c8c3c59289mec#include <sys/mc.h>
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec#include <mcamd_api.h>
8b464eb836173b92f2b7a65623cd06c8c3c59289mec#include <mcamd_err.h>
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec#define MC_SYSADDR_MSB 39
8b464eb836173b92f2b7a65623cd06c8c3c59289mec#define MC_SYSADDR_LSB 3
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec#define CSDIMM1 0x1
8b464eb836173b92f2b7a65623cd06c8c3c59289mec#define CSDIMM2 0x2
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec#define BITS(val, high, low) \
aa59c4cb15a6ac5d4e585dadf7a055b580abf579rsb ((val) & (((2ULL << (high)) - 1) & ~((1ULL << (low)) - 1)))
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec/*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * iaddr_gen generates a "normalized" DRAM controller input address
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * from a system address (physical address) if it falls within the
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * mapped range for this memory controller. Normalisation is
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * performed by subtracting the node base address from the system address,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * allowing from hoisting, and excising any bits being used in node
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * interleaving.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mecstatic int
8b464eb836173b92f2b7a65623cd06c8c3c59289meciaddr_gen(struct mcamd_hdl *hdl, mcamd_node_t *mc, uint64_t pa,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec uint64_t *iaddrp)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec{
8b464eb836173b92f2b7a65623cd06c8c3c59289mec uint64_t orig = pa;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec uint64_t mcnum, base, lim, dramaddr, ilen, ilsel, top, holesz;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (!mcamd_get_numprops(hdl,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mc, MCAMD_PROP_NUM, &mcnum,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mc, MCAMD_PROP_BASE_ADDR, &base,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mc, MCAMD_PROP_LIM_ADDR, &lim,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mc, MCAMD_PROP_ILEN, &ilen,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mc, MCAMD_PROP_ILSEL, &ilsel,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mc, MCAMD_PROP_DRAMHOLE_SIZE, &holesz,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec NULL)) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_dprintf(hdl, MCAMD_DBG_ERR, "iaddr_gen: failed to "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "lookup required properties");
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID));
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * A node with no mapped memory (no active chip-selects is usually
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * mapped with base and lim both zero. We'll cover that case and
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * any other where the range is 0.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (base == lim)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (mcamd_set_errno(hdl, EMCAMD_NOADDR));
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (pa < base || pa > lim) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "iaddr_gen: PA 0x%llx not "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "in range [0x%llx, 0x%llx] of MC %d\n", pa, base, lim,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec (int)mcnum);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (mcamd_set_errno(hdl, EMCAMD_NOADDR));
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Rev E and later added the DRAM Hole Address Register for
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * memory hoisting. In earlier revisions memory hoisting is
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * achieved by following some algorithm to modify the CS bases etc,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * and this pa to unum algorithm will simply see those modified
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * values. But if the Hole Address Register is being used then
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * we need to reduce any address at or above 4GB by the size of
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * the hole.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (holesz != 0 && pa >= 0x100000000) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec pa -= holesz;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "iaddr_gen: dram hole "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "valid; pa decremented from 0x%llx to 0x%llx for "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "a dramhole size of 0x%llx\n", orig, pa, holesz);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
8b464eb836173b92f2b7a65623cd06c8c3c59289mec dramaddr = BITS(pa, 39, 0) - BITS(base, 39, 24);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (ilen != 0) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec int pailsel;
aa59c4cb15a6ac5d4e585dadf7a055b580abf579rsb
aa59c4cb15a6ac5d4e585dadf7a055b580abf579rsb if (ilen != 1 && ilen != 3 && ilen != 7) {
aa59c4cb15a6ac5d4e585dadf7a055b580abf579rsb mcamd_dprintf(hdl, MCAMD_DBG_ERR, "Invalid intlven "
aa59c4cb15a6ac5d4e585dadf7a055b580abf579rsb "of %d for MC %d\n", (int)ilen, (int)mcnum);
aa59c4cb15a6ac5d4e585dadf7a055b580abf579rsb return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID));
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if ((pailsel = BITS(pa, 14, 12) >> 12 & ilen) != ilsel) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "iaddr_gen: "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "PA 0x%llx in a %d-way node interleave indicates "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "selection %d, MC %d has ilsel of %d\n",
8b464eb836173b92f2b7a65623cd06c8c3c59289mec pa, (int)ilen + 1, pailsel, (int)mcnum, (int)ilsel);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (mcamd_set_errno(hdl, EMCAMD_NOADDR));
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (ilen == 1)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec top = BITS(dramaddr, 36, 13) >> 1;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec else if (ilen == 3)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec top = BITS(dramaddr, 37, 14) >> 2;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec else if (ilen == 7)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec top = BITS(dramaddr, 38, 15) >> 3;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec } else {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec top = BITS(dramaddr, 35, 12);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec *iaddrp = top | BITS(dramaddr, 11, 0);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "iaddr_gen: PA 0x%llx in range "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "[0x%llx, 0x%llx] of MC %d; normalized address for cs compare "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "is 0x%llx\n", pa, base, lim, (int)mcnum, *iaddrp);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (0);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec}
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec/*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * cs_match determines whether the given DRAM controller input address
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * would be responded to by the given chip-select (which may or may not
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * be interleaved with other chip-selects). Since we include nodes
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * for spare chip-selects (if any) and those marked TestFail (if any)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * we must check chip-select-bank-enable.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mecstatic int
8b464eb836173b92f2b7a65623cd06c8c3c59289meccs_match(struct mcamd_hdl *hdl, uint64_t iaddr, mcamd_node_t *cs)
cd64d6e9f50d70599efa5c3e990d0f88efbe4351mec{
8b464eb836173b92f2b7a65623cd06c8c3c59289mec uint64_t csnum, csbase, csmask, csbe;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec int match = 0;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (!mcamd_get_numprops(hdl,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec cs, MCAMD_PROP_NUM, &csnum,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec cs, MCAMD_PROP_BASE_ADDR, &csbase,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec cs, MCAMD_PROP_MASK, &csmask,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec cs, MCAMD_PROP_CSBE, &csbe,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec NULL)) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_dprintf(hdl, MCAMD_DBG_ERR, "cs_match: failed to lookup "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "required properties\n");
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (0);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (csbe) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec match = ((iaddr & ~csmask) == (csbase & ~csmask));
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "cs_match: iaddr 0x%llx "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "does %smatch CS %d (base 0x%llx, mask 0x%llx)\n", iaddr,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec match ? "" : "not ", (int)csnum, csbase, csmask);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec } else {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "cs_match: iaddr 0x%llx "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "does not match disabled CS %d\n", iaddr, (int)csnum);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (match);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec}
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec/*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Given a chip-select node determine whether it has been substituted
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * by the online spare chip-select.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mecstatic mcamd_node_t *
8b464eb836173b92f2b7a65623cd06c8c3c59289meccs_sparedto(struct mcamd_hdl *hdl, mcamd_node_t *cs, mcamd_node_t *mc)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec{
8b464eb836173b92f2b7a65623cd06c8c3c59289mec uint64_t csnum, badcsnum, sparecsnum, tmpcsnum;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (!mcamd_get_numprops(hdl,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec cs, MCAMD_PROP_NUM, &csnum,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mc, MCAMD_PROP_BADCS, &badcsnum,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mc, MCAMD_PROP_SPARECS, &sparecsnum,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec NULL)) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_dprintf(hdl, MCAMD_DBG_ERR, "cs_sparedto: failed to "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "lookup required properties\n");
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (NULL);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if ((badcsnum == MC_INVALNUM && sparecsnum == MC_INVALNUM) ||
8b464eb836173b92f2b7a65623cd06c8c3c59289mec csnum != badcsnum)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (NULL);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec for (cs = mcamd_cs_next(hdl, mc, NULL); cs != NULL;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec cs = mcamd_cs_next(hdl, mc, cs)) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (!mcamd_get_numprop(hdl, cs, MCAMD_PROP_NUM, &tmpcsnum)) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_dprintf(hdl, MCAMD_DBG_ERR, "cs_sparedto: "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "fail to lookup csnum - cannot reroute to spare\n");
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (NULL);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (tmpcsnum == sparecsnum)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec break;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (cs != NULL) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "cs_sparedto: cs#%d is "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "redirected to active online spare of cs#%d\n", csnum,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec sparecsnum);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec } else {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_dprintf(hdl, MCAMD_DBG_ERR, "cs_sparedto: cs#%d is "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "redirected but cannot find spare cs# - cannout reroute to "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "cs#%d\n", csnum, sparecsnum);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (cs);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec}
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec/*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Having determined which node and chip-select an address maps to,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * as well as whether it is a dimm1, dimm2 or dimm1/dimm2 pair
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * involved, fill the unum structure including an optional dimm offset
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * member.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mecstatic int
8b464eb836173b92f2b7a65623cd06c8c3c59289mecunum_fill(struct mcamd_hdl *hdl, mcamd_node_t *cs, int which,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec uint64_t iaddr, mc_unum_t *unump, int incloff)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec{
8b464eb836173b92f2b7a65623cd06c8c3c59289mec uint64_t chipnum, csnum, dimm1, dimm2, ranknum;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_node_t *mc, *dimm;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec int offsetdimm;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec int i;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if ((mc = mcamd_cs_mc(hdl, cs)) == NULL ||
8b464eb836173b92f2b7a65623cd06c8c3c59289mec !mcamd_get_numprops(hdl,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mc, MCAMD_PROP_NUM, &chipnum,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec cs, MCAMD_PROP_NUM, &csnum,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec cs, MCAMD_PROP_DIMMRANK, &ranknum,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec NULL)) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_dprintf(hdl, MCAMD_DBG_ERR, "unum_fill: failed to "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "lookup required properties\n");
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID));
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if ((which & CSDIMM1) &&
8b464eb836173b92f2b7a65623cd06c8c3c59289mec !mcamd_get_numprop(hdl, cs, MCAMD_PROP_CSDIMM1, &dimm1) ||
8b464eb836173b92f2b7a65623cd06c8c3c59289mec (which & CSDIMM2) &&
8b464eb836173b92f2b7a65623cd06c8c3c59289mec !mcamd_get_numprop(hdl, cs, MCAMD_PROP_CSDIMM2, &dimm2)) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_dprintf(hdl, MCAMD_DBG_ERR, "unum_fill: failed to "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "lookup dimm1/dimm2 properties\n");
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID));
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec unump->unum_board = 0;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec unump->unum_chip = chipnum;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec unump->unum_mc = 0;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec unump->unum_cs = csnum;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec unump->unum_rank = ranknum;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec for (i = 0; i < MC_UNUM_NDIMM; i++) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec unump->unum_dimms[i] = MC_INVALNUM;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec switch (which) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec case CSDIMM1:
8b464eb836173b92f2b7a65623cd06c8c3c59289mec unump->unum_dimms[0] = dimm1;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec offsetdimm = dimm1;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec break;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec case CSDIMM2:
8b464eb836173b92f2b7a65623cd06c8c3c59289mec unump->unum_dimms[0] = dimm2;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec offsetdimm = dimm2;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec break;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec case CSDIMM1 | CSDIMM2:
8b464eb836173b92f2b7a65623cd06c8c3c59289mec unump->unum_dimms[0] = dimm1;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec unump->unum_dimms[1] = dimm2;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec offsetdimm = dimm1;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec break;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (!incloff) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec unump->unum_offset = MCAMD_RC_INVALID_OFFSET;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (0);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * We wish to calculate a dimm offset. In the paired case we will
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * lookup dimm1 (see offsetdimm above).
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec for (dimm = mcamd_dimm_next(hdl, mc, NULL); dimm != NULL;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec dimm = mcamd_dimm_next(hdl, mc, dimm)) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec uint64_t dnum;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (!mcamd_get_numprop(hdl, dimm, MCAMD_PROP_NUM, &dnum)) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_dprintf(hdl, MCAMD_DBG_ERR, "unum_fill: failed "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "to lookup dimm number property\n");
8b464eb836173b92f2b7a65623cd06c8c3c59289mec continue;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (dnum == offsetdimm)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec break;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (dimm == NULL) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_dprintf(hdl, MCAMD_DBG_ERR, "unum_fill: failed to "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "find dimm with number %d for offset calculation\n",
8b464eb836173b92f2b7a65623cd06c8c3c59289mec offsetdimm);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec unump->unum_offset = MCAMD_RC_INVALID_OFFSET;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID));
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * mc_pa_to_offset sets the offset to an invalid value if
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * it hits an error.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec (void) mc_pa_to_offset(hdl, mc, cs, iaddr, &unump->unum_offset);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (0);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec}
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec/*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * We have translated a system address to a (node, chip-select), and wish
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * to determine the associated dimm or dimms.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec *
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * A (node, chip-select) pair identifies one (in 64-bit MC mode) or two (in
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * 128-bit MC mode) DIMMs. In the case of a single dimm it is usually in a
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * lodimm (channel A) slot, but if mismatched dimm support is present it may
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * be an updimm (channel B).
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw *
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Where just one dimm is associated with the chip-select we are done.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Where there are two dimms associated with the chip-select we can
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * use the ECC type and/or syndrome to determine which of the pair we
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * resolve to, if the error is correctable. If the error is uncorrectable
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * then in 64/8 ECC mode we can still resolve to a single dimm (since ECC
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * is calculated and checked on each half of the data separately), but
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * in ChipKill mode we cannot resolve down to a single dimm.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mecstatic int
8b464eb836173b92f2b7a65623cd06c8c3c59289mecmc_whichdimm(struct mcamd_hdl *hdl, mcamd_node_t *cs, uint64_t pa,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec uint8_t valid_lo, uint32_t synd, int syndtype)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec{
8b464eb836173b92f2b7a65623cd06c8c3c59289mec int lobit, hibit, data, check;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec uint64_t dimm1, dimm2;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec uint_t sym, pat;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec int ndimm;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Read the associated dimm instance numbers. The provider must
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * assure that if there is just one dimm then it is in the first
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * property, and if there are two then the first must be on
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * channel A.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (!mcamd_get_numprops(hdl,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec cs, MCAMD_PROP_CSDIMM1, &dimm1,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec cs, MCAMD_PROP_CSDIMM2, &dimm2,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec NULL)) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mc_whichdimm: failed to "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "lookup required properties");
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID));
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec ndimm = (dimm1 != MC_INVALNUM) + (dimm2 != MC_INVALNUM);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (ndimm == 0) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mc_whichdimm: found no "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "dimms associated with chip-select");
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID));
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (ndimm == 1) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_whichdimm: just one "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "dimm associated with this chip-select");
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (CSDIMM1);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * 64/8 ECC is checked separately for the upper and lower
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * halves, so even an uncorrectable error is contained within
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * one of the two halves. If we have sufficient address resolution
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * then we can determine which DIMM.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (syndtype == AMD_SYNDTYPE_ECC) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (valid_lo <= MC_SYSADDR_LSB) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_whichdimm: 64/8 "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "ECC in 128-bit mode, PA 0x%llx is in %s half\n",
8b464eb836173b92f2b7a65623cd06c8c3c59289mec pa, pa & 0x8 ? "upper" : "lower");
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (pa & 0x8 ? CSDIMM2 : CSDIMM1);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec } else {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_whichdimm: "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "64/8 ECC in 128-bit mode, PA 0x%llx with least "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "significant valid bit %d cannot be resolved to "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "a single DIMM\n", pa, valid_lo);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (mcamd_set_errno(hdl, EMCAMD_INSUFF_RES));
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * ChipKill ECC
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (mcamd_cksynd_decode(hdl, synd, &sym, &pat)) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * A correctable ChipKill syndrome and we can tell
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * which half the error was in from the symbol number.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (mcamd_cksym_decode(hdl, sym, &lobit, &hibit, &data,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec &check) == 0)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (mcamd_set_errno(hdl, EMCAMD_SYNDINVALID));
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (data && hibit <= 63 || check && hibit <= 7) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_whichdimm: "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "ChipKill symbol %d (%s %d..%d), so LODIMM\n", sym,
cd64d6e9f50d70599efa5c3e990d0f88efbe4351mec data ? "data" : "check", lobit, hibit);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (CSDIMM1);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec } else {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_whichdimm: "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "ChipKill symbol %d (%s %d..%d), so UPDIMM\n", sym,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec data ? "data" : "check", lobit, hibit);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (CSDIMM2);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec } else {
cd64d6e9f50d70599efa5c3e990d0f88efbe4351mec /*
cd64d6e9f50d70599efa5c3e990d0f88efbe4351mec * An uncorrectable error while in ChipKill ECC mode - can't
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * tell which dimm or dimms the errors lie within.
cd64d6e9f50d70599efa5c3e990d0f88efbe4351mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_whichhdimm: "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "uncorrectable ChipKill, could be either LODIMM "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "or UPDIMM\n");
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (CSDIMM1 | CSDIMM2);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec}
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec/*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Brute-force BKDG pa to cs translation, coded to look as much like the
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * BKDG code as possible.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mecstatic int
8b464eb836173b92f2b7a65623cd06c8c3c59289mecmc_bkdg_patounum(struct mcamd_hdl *hdl, mcamd_node_t *mc, uint64_t pa,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec uint8_t valid_lo, uint32_t synd, int syndtype,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mc_unum_t *unump)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec{
8b464eb836173b92f2b7a65623cd06c8c3c59289mec int which;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec uint64_t mcnum, rev;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_node_t *cs;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Raw registers as per BKDG
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec uint32_t HoleEn;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec uint32_t DramBase, DramLimit;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec uint32_t CSBase, CSMask;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Variables as per BKDG
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec int Ilog;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec uint32_t SystemAddr = (uint32_t)(pa >> 8);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec uint64_t IntlvEn, IntlvSel;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec uint32_t HoleOffset;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec uint32_t InputAddr, Temp;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (!mcamd_get_numprops(hdl,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mc, MCAMD_PROP_NUM, &mcnum,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mc, MCAMD_PROP_REV, &rev, NULL) || !mcamd_get_cfgregs(hdl,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mc, MCAMD_REG_DRAMBASE, &DramBase,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mc, MCAMD_REG_DRAMLIMIT, &DramLimit,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mc, MCAMD_REG_DRAMHOLE, &HoleEn, NULL)) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mc_bkdg_patounm: failed "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "to lookup required properties and registers\n");
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID));
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * BKDG line to skip Why
8b464eb836173b92f2b7a65623cd06c8c3c59289mec *
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * F1Offset = ... Register already read,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * DramBase = Get_PCI() and retrieved above.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * DramEn = ... Function only called for enabled nodes.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec IntlvEn = (DramBase & 0x00000700) >> 8;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec DramBase &= 0xffff0000;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /* DramLimit = Get_PCI() Retrieved above */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec IntlvSel = (DramLimit & 0x00000700) >> 8;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec DramLimit |= 0x0000ffff;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /* HoleEn = ... Retrieved above */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec HoleOffset = (HoleEn & 0x0000ff00) << 8;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec HoleEn &= 0x00000001;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (!(DramBase <= SystemAddr && SystemAddr <= DramLimit)) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_bkdg_patounum: "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "SystemAddr 0x%x derived from PA 0x%llx is not in the "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "address range [0x%x, 0x%x] of MC %d\n",
8b464eb836173b92f2b7a65623cd06c8c3c59289mec SystemAddr, pa, DramBase, DramLimit, (int)mcnum);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (mcamd_set_errno(hdl, EMCAMD_NOADDR));
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (HoleEn && SystemAddr > 0x00ffffff)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec InputAddr = SystemAddr - HoleOffset;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec InputAddr = SystemAddr - DramBase;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (IntlvEn) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (IntlvSel == ((SystemAddr >> 4) & IntlvEn)) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec switch (IntlvEn) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec case 1:
8b464eb836173b92f2b7a65623cd06c8c3c59289mec Ilog = 1;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec break;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec case 3:
8b464eb836173b92f2b7a65623cd06c8c3c59289mec Ilog = 2;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec break;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec case 7:
8b464eb836173b92f2b7a65623cd06c8c3c59289mec Ilog = 3;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec break;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec default:
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (mcamd_set_errno(hdl,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec EMCAMD_TREEINVALID));
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec Temp = (InputAddr >> (4 + Ilog)) << 4;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec InputAddr = (Temp | (SystemAddr & 0x0000000f));
8b464eb836173b92f2b7a65623cd06c8c3c59289mec } else {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /* not this node */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_bkdg_patounum: "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "Node interleaving, MC node %d not selected\n",
8b464eb836173b92f2b7a65623cd06c8c3c59289mec (int)mcnum);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (mcamd_set_errno(hdl, EMCAMD_NOADDR));
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (!MC_REV_MATCH(rev, MC_REVS_FG))
8b464eb836173b92f2b7a65623cd06c8c3c59289mec InputAddr <<= 4;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec for (cs = mcamd_cs_next(hdl, mc, NULL); cs != NULL;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec cs = mcamd_cs_next(hdl, mc, cs)) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec uint64_t csnum, CSEn;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (!mcamd_get_cfgregs(hdl,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec cs, MCAMD_REG_CSBASE, &CSBase,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec cs, MCAMD_REG_CSMASK, &CSMask,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec NULL) ||
8b464eb836173b92f2b7a65623cd06c8c3c59289mec !mcamd_get_numprops(hdl,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec cs, MCAMD_PROP_NUM, &csnum,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec cs, MCAMD_PROP_CSBE, &CSEn,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec NULL)) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mc_bkdg_patounm: "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "failed to read cs registers\n");
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID));
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * BKDG line to skip Why
8b464eb836173b92f2b7a65623cd06c8c3c59289mec *
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * F2Offset = Register already read,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * F2MaskOffset (rev F) Register already read
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * CSBase = Register already read
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * CSEn = We only keep enabled cs.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (MC_REV_MATCH(rev, MC_REVS_FG)) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec CSBase &= 0x1ff83fe0;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /* CSMask = Get_PCI() Retrieved above */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec CSMask = (CSMask | 0x0007c01f) & 0x1fffffff;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec } else {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec CSBase &= 0xffe0fe00;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /* CSMask = Get_PCI() Retrieved above */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec CSMask = (CSMask | 0x001f01ff) & 0x3fffffff;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (CSEn && (InputAddr & ~CSMask) == (CSBase & ~CSMask)) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_node_t *sparecs;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_bkdg_patounum: "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "match for chip select %d of MC %d\n", (int)csnum,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec (int)mcnum);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if ((sparecs = cs_sparedto(hdl, cs, mc)) != NULL)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec cs = sparecs;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if ((which = mc_whichdimm(hdl, cs, pa, valid_lo,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec synd, syndtype)) < 0)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (-1); /* errno is set for us */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * The BKDG algorithm drops low-order bits that
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * are unimportant in deriving chip-select but are
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * included in row/col/bank mapping, so do not
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * perform offset calculation in this case.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (unum_fill(hdl, cs, which, InputAddr, unump, 0) < 0)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (-1); /* errno is set for us */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (0);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mc_bkdg_patounum: in range "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "for MC %d but no cs responds\n", (int)mcnum);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (mcamd_set_errno(hdl, EMCAMD_NOADDR));
8b464eb836173b92f2b7a65623cd06c8c3c59289mec}
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec/*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Called for each memory controller to see if the given address is
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * mapped to this node (as determined in iaddr_gen) and, if so, which
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * chip-select on this node responds.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec/*ARGSUSED*/
8b464eb836173b92f2b7a65623cd06c8c3c59289mecstatic int
8b464eb836173b92f2b7a65623cd06c8c3c59289mecmc_patounum(struct mcamd_hdl *hdl, mcamd_node_t *mc, uint64_t pa,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec uint8_t valid_lo, uint32_t synd, int syndtype, mc_unum_t *unump)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec{
8b464eb836173b92f2b7a65623cd06c8c3c59289mec uint64_t iaddr;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_node_t *cs, *sparecs;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec int which;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec#ifdef DEBUG
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mc_unum_t bkdg_unum;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec int bkdgres;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * We perform the translation twice, once using the brute-force
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * approach of the BKDG and again using a more elegant but more
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * difficult to review against the BKDG approach.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "BKDG brute-force method begins\n");
8b464eb836173b92f2b7a65623cd06c8c3c59289mec bkdgres = mc_bkdg_patounum(hdl, mc, pa, valid_lo, synd,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec syndtype, &bkdg_unum);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "BKDG brute-force method ends\n");
8b464eb836173b92f2b7a65623cd06c8c3c59289mec#endif
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (iaddr_gen(hdl, mc, pa, &iaddr) < 0)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (-1); /* errno is set for us */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec for (cs = mcamd_cs_next(hdl, mc, NULL); cs != NULL;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec cs = mcamd_cs_next(hdl, mc, cs)) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (cs_match(hdl, iaddr, cs))
8b464eb836173b92f2b7a65623cd06c8c3c59289mec break;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (cs == NULL)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (mcamd_set_errno(hdl, EMCAMD_NOADDR));
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * If the spare chip-select has been swapped in for the one just
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * matched then it is really the spare that we are after. Note that
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * when the swap is done the csbase, csmask and CSBE of the spare
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * rank do not change - accesses to the bad rank (as nominated in
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * the Online Spare Control Register) are redirect to the spare.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
dc32d872cbeb56532bcea030255db9cd79bac7daJosef 'Jeff' Sipek if ((sparecs = cs_sparedto(hdl, cs, mc)) != NULL) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec cs = sparecs;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if ((which = mc_whichdimm(hdl, cs, pa, valid_lo, synd,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec syndtype)) < 0)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (-1); /* errno is set for us */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (unum_fill(hdl, cs, which, iaddr, unump, 1) < 0)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (-1); /* errno is set for us */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec#ifdef DEBUG
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "bkdgres=%d res=0\n", bkdgres);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /* offset is not checked - see note in BKDG algorithm */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (bkdgres != 0) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_dprintf(hdl, MCAMD_DBG_ERR, "BKDG alg failed while "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "ours succeeded\n");
8b464eb836173b92f2b7a65623cd06c8c3c59289mec } else if (!(unump->unum_board == bkdg_unum.unum_board &&
8b464eb836173b92f2b7a65623cd06c8c3c59289mec unump->unum_chip == bkdg_unum.unum_chip &&
8b464eb836173b92f2b7a65623cd06c8c3c59289mec unump->unum_mc == bkdg_unum.unum_mc &&
8b464eb836173b92f2b7a65623cd06c8c3c59289mec unump->unum_cs == bkdg_unum.unum_cs &&
8b464eb836173b92f2b7a65623cd06c8c3c59289mec unump->unum_dimms[0] == bkdg_unum.unum_dimms[0] &&
8b464eb836173b92f2b7a65623cd06c8c3c59289mec unump->unum_dimms[1] == bkdg_unum.unum_dimms[1])) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_dprintf(hdl, MCAMD_DBG_ERR,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "BKDG: node %d mc %d cs %d dimm(s) %d/%d\n"
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "Ours: node 5d mc %d cs %d dimm(s) %d/%d\n",
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw bkdg_unum.unum_chip, bkdg_unum.unum_mc, bkdg_unum.unum_cs,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec bkdg_unum.unum_dimms[0], bkdg_unum.unum_dimms[1],
8b464eb836173b92f2b7a65623cd06c8c3c59289mec unump->unum_chip, unump->unum_mc, unump->unum_cs,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec unump->unum_dimms[0], unump->unum_dimms[1]);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec#endif /* DEBUG */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "Result: chip %d mc %d cs %d "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "offset 0x%llx\n", unump->unum_chip, unump->unum_mc,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec unump->unum_cs, unump->unum_offset);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (0);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec}
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
8b464eb836173b92f2b7a65623cd06c8c3c59289mecint
8b464eb836173b92f2b7a65623cd06c8c3c59289mecmcamd_patounum(struct mcamd_hdl *hdl, mcamd_node_t *root, uint64_t pa,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec uint8_t valid_hi, uint8_t valid_lo, uint32_t synd, int syndtype,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mc_unum_t *unump)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec{
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_node_t *mc;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_patounum: pa=0x%llx, "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "synd=0x%x, syndtype=%d\n", pa, synd, syndtype);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (valid_hi < MC_SYSADDR_MSB) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_patounum: require "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "pa<%d> to be valid\n", MC_SYSADDR_MSB);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (mcamd_set_errno(hdl, EMCAMD_INSUFF_RES));
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (!mcamd_synd_validate(hdl, synd, syndtype))
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (mcamd_set_errno(hdl, EMCAMD_SYNDINVALID));
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec for (mc = mcamd_mc_next(hdl, root, NULL); mc != NULL;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mc = mcamd_mc_next(hdl, root, mc)) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (mc_patounum(hdl, mc, pa, valid_lo, synd,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec syndtype, unump) == 0)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (0);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (mcamd_errno(hdl) != EMCAMD_NOADDR)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec break;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (-1); /* errno is set for us */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec}
8b464eb836173b92f2b7a65623cd06c8c3c59289mec