/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <strings.h>
#include <umem.h>
#include <fm/topo_mod.h>
#include <fm/fmd_fmri.h>
#include <fm/fmd_agent.h>
#include <mem_mdesc.h>
/*
* This enumerator creates mem-schemed nodes for each dimm found in the
* sun4v Physical Resource Inventory (PRI).
* Each node exports five methods: present(), expand(), unusable(), replaced(),
* and contains().
*
*/
/* Forward declaration */
topo_instance_t, void *, void *);
nvlist_t **);
nvlist_t **);
nvlist_t **);
nvlist_t **);
nvlist_t **);
{ mem_enum, mem_release };
&mem_ops };
{ NULL }
};
int
{
if (getenv("TOPOPLATFORMMEMDBG"))
return (-1);
return (-1);
}
return (-1);
}
return (0);
}
void
{
}
/*ARGSUSED*/
static int
{
char **nvlserids;
/* sun4v platforms all support dimm serial numbers */
}
/* Find the dimm entry */
for (n = 0; n < nserids; n++) {
present = 1;
break;
}
}
/* return the present status */
nvlist_free(*out);
}
return (0);
}
/*ARGSUSED*/
static int
{
char **nvlserids;
/* sun4v platforms all support dimm serial numbers */
}
/* Find the dimm entry */
for (n = 0; n < nserids; n++) {
break;
}
}
/* return the replaced status */
nvlist_free(*out);
}
return (0);
}
void
{
int i;
for (i = 0; i < dim; i++) {
}
}
/*
* Niagara-1, Niagara-2, and Victoria Falls all have physical address
* spaces of 40 bits.
*/
/*
* The 'mask' argument to extract_bits has 1's in those bit positions of
* the physical address used to select the DIMM (or set of DIMMs) which will
* store the contents of the physical address. If we extract those bits, ie.
* remove them and collapse the holes, the result is the 'address' within the
* DIMM or set of DIMMs where the contents are stored.
*/
static uint64_t
{
to = 1;
to <<= 1;
}
}
return (result);
}
/*
* insert_bits is the reverse operation to extract_bits. Where extract_bits
* removes from the physical address those bits which select a DIMM or set
* of DIMMs, insert_bits reconstitutes a physical address given the DIMM
* selection 'mask' and the 'value' for the address bits denoted by 1s in
* the 'mask'.
*/
static uint64_t
{
from = 1;
from <<= 1;
} else {
}
}
return (result);
}
{
}
}
return ((uint64_t)-1);
}
void
{
/*
* The following additional expansions are all optional.
* Failure to retrieve a data value, or failure to add it
* successfully to the FMRI, does NOT cause a failure of
* fmd_fmri_expand. All optional expansions will be attempted
* once expand_opt is entered.
*/
(void) nvlist_add_uint64(nvl,
}
}
} else if (nvlist_lookup_uint64(nvl,
FM_FMRI_MEM_PHYSADDR, &physaddr) == 0) {
/*
* The mask & shift values for all banks in a
* segment are always the same; only the match
* values differ, in order to specify a
* dimm-pair. But we already have a full unum.
*/
(void) (nvlist_add_uint64(nvl,
}
}
}
}
/*
* The sun4v mem: scheme expand() now assumes that the FMRI -has- serial
* numbers, therefore we should never have to call mem_unum_burst again.
* Part numbers will be supplied in hc: scheme from the hc: enumeration.
* What's left: physical address and offset calculations.
*/
/*ARGSUSED*/
static int
{
int rc;
return (0);
else
return (-1);
}
int
{
int rc;
return (FMD_AGENT_RETIRE_FAIL);
}
return (FMD_AGENT_RETIRE_DONE);
return (FMD_AGENT_RETIRE_ASYNC);
return (FMD_AGENT_RETIRE_FAIL);
}
int
{
int rc;
return (FMD_AGENT_RETIRE_FAIL);
}
return (FMD_AGENT_RETIRE_DONE);
return (FMD_AGENT_RETIRE_ASYNC);
return (FMD_AGENT_RETIRE_FAIL);
}
int
{
int rc;
return (FMD_AGENT_RETIRE_FAIL);
}
return (FMD_AGENT_RETIRE_DONE);
return (FMD_AGENT_RETIRE_FAIL);
}
/*ARGSUSED*/
static int
{
return (0); /* no page, so assume it's still usable */
/*
* Ask the kernel if the page is retired, using
* the original mem FMRI with the specified offset or PA.
* Refer to the kernel's page_retire_check() for the error codes.
*/
if (rc == FMD_AGENT_RETIRE_FAIL) {
/*
* The page is not retired and is not scheduled for retirement
* (i.e. no request pending and has not seen any errors)
*/
retval = 0;
} else if (rc == FMD_AGENT_RETIRE_DONE ||
rc == FMD_AGENT_RETIRE_ASYNC) {
/*
* The page has been retired, is in the process of being
* retired, or doesn't exist. The latter is valid if the page
* existed in the past but has been DR'd out.
*/
retval = 1;
} else {
/*
* Errors are only signalled to the caller if they're the
* caller's fault. This isn't - it's a failure of the
* retirement-check code. We'll whine about it and tell
* the caller the page is unusable.
*/
"failed to determine page %s=%llx usability: "
retval = 1;
}
nvlist_free(*out);
}
return (0);
}
/* ARGSUSED */
static int
{
/*
* Unlike the other exported functions, the 'in' argument here is
* not a pass-through -- it is a composite of the 'container' and
* 'containee' FMRIs. Rather than checking the version of 'in',
* check the versions of the container and containee.
*/
/*
* Look up each 'ee' serial number in serial number list of 'er'.
* If any are not found, return "false"; if all are found, return
* "true".
*/
if (rc == 0)
break;
}
if (rc != 0) {
/* failed -- no containment */
ret = 0;
break;
}
}
/* success */
nvlist_free(*out);
}
return (0);
}
return (-1);
}
static nvlist_t *
{
int err;
return (NULL);
if (err != 0) {
return (NULL);
}
return (fmri);
}
static tnode_t *
{
"Unable to make nvlist for %s bind: %s.\n",
return (NULL);
}
"topo_node_bind (%s%d/%s%d) failed: %s\n",
name, i,
return (NULL);
}
return (ntn);
}
/*ARGSUSED*/
static int
{
int i;
int nerr = 0;
int ndimms = 0;
/*
* Count the dimms and create a range. The instance numbers
* are not meaningful in this context.
*/
ndimms++;
}
if (ndimms == 0)
return (-1);
return (-1);
}
/*
* Create the dimm nodes
*/
"failed to create dimm=%d node: %s\n",
i, topo_mod_errmsg(mod));
nerr++;
}
}
if (nerr != 0)
return (0);
}
/*ARGSUSED*/
static int
{
return (-1);
}
return (0);
}
/*ARGSUSED*/
static void
{
}