mem.c revision 822f48a6983f4a1c00853e59494674aa5ef65943
/*
* 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 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <mem.h>
#include <fm/fmd_fmri.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <time.h>
#ifdef sparc
#endif /* sparc */
#ifdef sparc
extern int mem_update_mdesc(void);
/*
* Retry values for handling the case where the kernel is not yet ready
* to provide DIMM serial ids. Some platforms acquire DIMM serial id
* information from their System Controller via a mailbox interface.
* The values chosen are for 10 retries 3 seconds apart to approximate the
* possible 30 second timeout length of a mailbox message request.
*/
#define MAX_MEM_SID_RETRIES 10
#define MEM_SID_RETRY_WAIT 3
static mem_dimm_map_t *
{
return (dm);
}
return (NULL);
}
/*
* Returns 0 with serial numbers if found, -1 (with errno set) for errors. If
* the unum (or a component of same) wasn't found, -1 is returned with errno
* set to ENOENT. If the kernel doesn't have support for serial numbers,
* -1 is returned with errno set to ENOTSUP.
*/
static int
{
int i, rc = 0;
int fd;
int retries = MAX_MEM_SID_RETRIES;
return (-1);
return (-1); /* errno is set for us */
}
for (i = 0; i < ndimms; i++) {
do {
break;
if (retries == 0) {
break;
}
/*
* EAGAIN indicates the kernel is
* not ready to provide DIMM serial
* ids. Sleep MEM_SID_RETRY_WAIT seconds
* and try again.
* nanosleep() is used instead of sleep()
* to avoid interfering with fmd timers.
*/
} while (retries--);
if (rc < 0) {
/*
* ENXIO can happen if the kernel memory driver
* doesn't have the MEM_SID ioctl (e.g. if the
* kernel hasn't been patched to provide the
* support).
*
* If the MEM_SID ioctl is available but the
* particular platform doesn't support providing
* serial ids, ENOTSUP will be returned by the ioctl.
*/
return (-1);
}
}
return (0);
}
/*
* Returns 0 with serial numbers if found, -1 (with errno set) for errors. If
* the unum (or a component of same) wasn't found, -1 is returned with errno
* set to ENOENT.
*/
static int
{
int i, rc = 0;
return (-1); /* errno is set for us */
for (i = 0; i < ndimms; i++) {
break;
}
/*
* We don't have a cached copy, or the copy we've got is
* out of date. Look it up again.
*/
break;
}
}
}
if (rc == 0) {
} else {
}
return (rc);
}
/*
* Returns 0 with serial numbers if found, -1 (with errno set) for errors. If
* the unum (or a component of same) wasn't found, -1 is returned with errno
* set to ENOENT.
*/
static int
{
int i, rc = 0;
return (-1); /* errno is set for us */
/*
* first go through dimms and see if dm_drgen entries are outdated
*/
for (i = 0; i < ndimms; i++) {
break;
}
if (i < ndimms && mem_update_mdesc() != 0) {
return (-1);
}
/*
* get to this point if an up-to-date mdesc (and corresponding
* entries in the global mem list) exists
*/
for (i = 0; i < ndimms; i++) {
break;
}
/*
* mdesc and dm entry was updated by an earlier call to
* mem_update_mdesc, so we go ahead and dup the serid
*/
}
if (rc == 0) {
} else {
}
return (rc);
}
/*
* Returns 0 with part numbers if found, returns -1 for errors.
*/
static int
{
int i, rc = 0;
return (-1); /* errno is set for us */
/*
* first go through dimms and see if dm_drgen entries are outdated
*/
for (i = 0; i < ndimms; i++) {
break;
}
if (i < ndimms && mem_update_mdesc() != 0) {
return (-1);
}
/*
* get to this point if an up-to-date mdesc (and corresponding
* entries in the global mem list) exists
*/
for (i = 0; i < ndimms; i++) {
break;
}
/*
* mdesc and dm entry was updated by an earlier call to
* mem_update_mdesc, so we go ahead and dup the part
*/
rc = -1;
break;
}
}
if (rc == 0) {
} else {
}
return (rc);
}
static int
{
return (-1);
else
}
#endif /* sparc */
/*ARGSUSED*/
static int
{
/*
* Some platforms do not support the caching of serial ids by the
* mem scheme plugin but instead support making serial ids available
* via the kernel.
*/
#ifdef sparc
return (0);
else
#else
return (-1);
#endif /* sparc */
}
static int
{
char *unum;
return (fmd_fmri_set_errno(EINVAL));
return (0);
}
{
char format[64];
int i;
return (-1); /* errno is set for us */
/*
* If we have a well-formed unum (hc-FMRI), use the string verbatim
* to form the initial mem:/// components. Otherwise use unum=%s.
*/
else
prefix = "";
/*
* If we have a DIMM offset, include it in the string. If we have a PA
* then use that. Otherwise just format the unum element.
*/
"%s:///%s%%1$s/%s=%%2$llx",
"%s:///%s%%1$s/%s=%%2$llx",
} else {
}
/*
* If we have a well-formed unum (hc-FMRI), we skip over the
* the scheme and authority prefix.
* Otherwise, the spaces and colons will be escaped,
* rendering the resulting FMRI pretty much unreadable.
* We're therefore going to do some escaping of our own first.
*/
rawunum += 5;
++rawunum;
/* LINTED: variable format specifier */
} else {
for (i = 0; i < presz - 1; i++) {
presz - (i + 2));
} else if (preunum[i] == ' ') {
preunum[i] = ',';
}
}
/* LINTED: variable format specifier */
}
return (size);
}
int
{
#ifdef sparc
char **parts;
#endif
int rc;
return (fmd_fmri_set_errno(EINVAL));
&serids, &nnvlserids)) == 0)
return (0); /* fmri is already expanded */
return (fmd_fmri_set_errno(EINVAL));
/* errno is set for us */
return (0); /* nothing to add - no s/n support */
else
return (-1);
}
nserids);
if (rc != 0)
return (fmd_fmri_set_errno(EINVAL));
#ifdef sparc
/*
* Continue with the process if there are no part numbers.
*/
return (0);
#endif
return (0);
}
static int
{
int i;
return (0);
for (i = 0; i < nserids1; i++) {
return (0);
}
return (1);
}
int
{
int rc;
return (-1); /* errno is set for us */
&nnvlserids) != 0) {
/*
* Some mem scheme FMRIs don't have serial ids because
* either the platform does not support them, or because
* the FMRI was created before support for serial ids was
* introduced. If this is the case, assume it is there.
*/
return (1);
else
return (fmd_fmri_set_errno(EINVAL));
}
/*
* Hypervisor will change the memconfig value when the mapping of
* pages to DIMMs changes, e.g. for change in DIMM size or interleave.
* If we detect such a change, we discard ereports associated with a
* previous memconfig value as invalid.
*
* The test (mem.mem_memconfig != 0) means we run on a system that
* actually suplies a memconfig value.
*/
return (0);
return (1); /* assume it's there, no s/n support here */
/*
* Errors are only signalled to the caller if they're
* the caller's fault. This isn't - it's a failure on
* our part to burst or read the serial numbers. We'll
* whine about it, and tell the caller the named
*/
fmd_fmri_warn("failed to retrieve serial number for "
"unum %s", unum);
}
return (0);
}
return (rc);
}
int
{
return (-1); /* errno is set for us */
return (nvlist_lookup_uint64(ee,
}
return (nvlist_lookup_uint64(ee,
}
return (1);
}
/*
* without page addresses will be reported as usable since Solaris has no
* way at present to dynamically disable an entire DIMM or DIMM pair.
*/
int
{
int retval;
return (fmd_fmri_set_errno(EINVAL));
return (0); /* no page, so assume it's still usable */
return (fmd_fmri_set_errno(EINVAL));
return (fmd_fmri_set_errno(err1));
/*
* Ask the kernel if the page is retired, using either the rewritten
* hc FMRI or the original mem FMRI with the specified offset or PA.
* Refer to the kernel's page_retire_check() for the error codes.
*/
/*
* The page is not retired and is not scheduled for retirement
* (i.e. no request pending and has not seen any errors)
*/
retval = 0;
/*
* 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.
*/
fmd_fmri_warn("failed to determine page %s=%llx usability: "
retval = 1;
}
if (nvlcp)
return (retval);
}
int
fmd_fmri_init(void)
{
#ifdef sparc
#endif /* sparc */
return (mem_discover());
}
void
fmd_fmri_fini(void)
{
}
#ifdef sparc
#endif /* sparc */
}