summaryrefslogtreecommitdiff
path: root/usr/src/cmd/fm
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/fm')
-rw-r--r--usr/src/cmd/fm/Makefile6
-rw-r--r--usr/src/cmd/fm/fmdump/common/nvlrender.c2
-rw-r--r--usr/src/cmd/fm/mcdecode/Makefile59
-rw-r--r--usr/src/cmd/fm/mcdecode/mcdecode.c284
-rw-r--r--usr/src/cmd/fm/modules/common/fabric-xlate/fabric-xlate.h31
-rw-r--r--usr/src/cmd/fm/modules/common/fabric-xlate/fx_fabric.c55
-rw-r--r--usr/src/cmd/fm/modules/common/fabric-xlate/fx_subr.c20
-rw-r--r--usr/src/cmd/fm/modules/common/zfs-diagnosis/zfs_de.c38
-rw-r--r--usr/src/cmd/fm/modules/common/zfs-retire/zfs_retire.c21
9 files changed, 487 insertions, 29 deletions
diff --git a/usr/src/cmd/fm/Makefile b/usr/src/cmd/fm/Makefile
index 4243767346..7b5d28d307 100644
--- a/usr/src/cmd/fm/Makefile
+++ b/usr/src/cmd/fm/Makefile
@@ -21,8 +21,11 @@
#
# Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2019 Joyent, Inc.
#
+i386_SUBDIRS = mcdecode
+
SUBDIRS = \
fmd \
fmadm \
@@ -36,7 +39,8 @@ SUBDIRS = \
modules \
dicts \
eversholt \
- notify
+ notify \
+ $($(MACH)_SUBDIRS)
include ./Makefile.subdirs
diff --git a/usr/src/cmd/fm/fmdump/common/nvlrender.c b/usr/src/cmd/fm/fmdump/common/nvlrender.c
index 2c2f5ca662..99f027a77d 100644
--- a/usr/src/cmd/fm/fmdump/common/nvlrender.c
+++ b/usr/src/cmd/fm/fmdump/common/nvlrender.c
@@ -83,7 +83,7 @@ fmdump_render_nvlist(nvlist_prtctl_t pctl, void *private, nvlist_t *nvl,
int
fmdump_print_json(fmd_log_t *lp, const fmd_log_record_t *rp, FILE *fp)
{
- if (nvlist_print_json(fp, rp->rec_nvl) != 0 || fprintf(fp, "\n") < 0 ||
+ if (nvlist_print_json(fp, rp->rec_nvl) < 0 || fprintf(fp, "\n") < 0 ||
fflush(fp) != 0)
return (-1);
diff --git a/usr/src/cmd/fm/mcdecode/Makefile b/usr/src/cmd/fm/mcdecode/Makefile
new file mode 100644
index 0000000000..6cfbde5556
--- /dev/null
+++ b/usr/src/cmd/fm/mcdecode/Makefile
@@ -0,0 +1,59 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2019 Joyent, Inc.
+#
+
+include ../../Makefile.cmd
+include ../../Makefile.ctf
+
+SRCS += mcdecode.c imc_decode.o imc_dump.o
+OBJS = $(SRCS:%.c=%.o)
+
+PROG = mcdecode
+
+ROOTLIBFM = $(ROOT)/usr/lib/fm
+ROOTLIBFMD = $(ROOT)/usr/lib/fm/fmd
+ROOTPROG = $(ROOTLIBFMD)/$(PROG)
+
+$(NOT_RELEASE_BUILD)CPPFLAGS += -DDEBUG
+CPPFLAGS += -I$(SRC)/uts/i86pc/io/imc
+LDLIBS += -lnvpair
+
+CSTD = $(CSTD_GNU99)
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+ $(LINK.c) $(OBJS) -o $@ $(LDLIBS)
+ $(POST_PROCESS)
+
+%.o: %.c
+ $(COMPILE.c) $<
+ $(POST_PROCESS_O)
+
+%.o: $(SRC)/common/mc/imc/%.c
+ $(COMPILE.c) $<
+ $(POST_PROCESS_O)
+
+clean:
+ $(RM) $(OBJS) $(LINTFILES)
+
+clobber: clean
+ $(RM) $(PROG)
+
+$(ROOTLIBFMD)/%: %
+ $(INS.file)
+
+install_h:
+
+install: all $(ROOTPROG)
diff --git a/usr/src/cmd/fm/mcdecode/mcdecode.c b/usr/src/cmd/fm/mcdecode/mcdecode.c
new file mode 100644
index 0000000000..e6b8b62ce7
--- /dev/null
+++ b/usr/src/cmd/fm/mcdecode/mcdecode.c
@@ -0,0 +1,284 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2019 Joyent, Inc.
+ */
+
+/*
+ * Command utility to drive synthetic memory decoding.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <err.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <strings.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <libnvpair.h>
+
+#include <sys/mc.h>
+#include "imc.h"
+
+#define MCDECODE_USAGE 2
+
+/*
+ * Write in 32k chunks.
+ */
+#define MCDECODE_WRITE (1024 * 32)
+
+static void
+mcdecode_usage(void)
+{
+ (void) fprintf(stderr,
+ "Usage: mcdecode [-f infile] [-d address | -w outfile] device\n"
+ "\n"
+ "\t-d decode physical address to the correspond dimm\n"
+ "\t-f use decoder image from infile\n"
+ "\t-w write decoder snapshot state to the specified file\n");
+ exit(MCDECODE_USAGE);
+}
+
+static void
+mcdecode_from_file(const char *file, uint64_t pa)
+{
+ int fd, ret;
+ struct stat st;
+ void *addr;
+ nvlist_t *nvl;
+ imc_t imc;
+ imc_decode_state_t dec;
+ char *driver;
+
+ if ((fd = open(file, O_RDONLY)) < 0) {
+ err(EXIT_FAILURE, "failed to open %s", file);
+ }
+
+ if (fstat(fd, &st) != 0) {
+ err(EXIT_FAILURE, "failed to get file information for %s",
+ file);
+ }
+
+ addr = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE,
+ fd, 0);
+ if (addr == MAP_FAILED) {
+ err(EXIT_FAILURE, "failed to map %s", file);
+ }
+ ret = nvlist_unpack(addr, st.st_size, &nvl, 0);
+ if (ret != 0) {
+ errx(EXIT_FAILURE, "failed to unpack %s: %s",
+ strerror(ret));
+ }
+ if (munmap(addr, st.st_size) != 0) {
+ err(EXIT_FAILURE, "failed to unmap %s", file);
+ }
+ if (close(fd) != 0) {
+ err(EXIT_FAILURE, "failed to close fd for %s", file);
+ }
+
+ if (nvlist_lookup_string(nvl, "mc_dump_driver", &driver) != 0) {
+ errx(EXIT_FAILURE, "missing driver indication in dump %s",
+ file);
+ }
+
+ if (strcmp(driver, "imc") != 0) {
+ errx(EXIT_FAILURE, "unknown driver dump source %s\n", driver);
+ }
+
+ if (!imc_restore_decoder(nvl, &imc)) {
+ errx(EXIT_FAILURE, "failed to restore memory controller "
+ "snapshot in %s", file);
+ }
+
+ bzero(&dec, sizeof (dec));
+
+ if (!imc_decode_pa(&imc, pa, &dec)) {
+ errx(EXIT_FAILURE, "failed to decode address 0x%" PRIx64, pa);
+ }
+
+ (void) printf("Decoded physical address 0x%" PRIx64 "\n"
+ "\tchip:\t\t\t%u\n"
+ "\tmemory controller:\t%u\n"
+ "\tchannel:\t\t%u\n"
+ "\tdimm:\t\t\t%u\n"
+ "\trank:\t\t\t%u\n",
+ pa, dec.ids_nodeid, dec.ids_tadid, dec.ids_channelid,
+ dec.ids_dimmid, dec.ids_rankid);
+
+ nvlist_free(nvl);
+}
+
+static void
+mcdecode_pa(const char *device, uint64_t pa)
+{
+ int fd;
+ mc_encode_ioc_t ioc;
+
+ bzero(&ioc, sizeof (ioc));
+ ioc.mcei_pa = pa;
+
+ if ((fd = open(device, O_RDONLY)) < 0) {
+ err(EXIT_FAILURE, "failed to open %s", device);
+ }
+
+ if (ioctl(fd, MC_IOC_DECODE_PA, &ioc) != 0) {
+ err(EXIT_FAILURE, "failed to issue decode ioctl");
+ }
+
+ if (ioc.mcei_err != 0) {
+ (void) fprintf(stderr, "decoding of address 0x%" PRIx64
+ " failed with error 0x%x\n", pa, ioc.mcei_err);
+ exit(EXIT_FAILURE);
+ }
+
+ (void) printf("Decoded physical address 0x%" PRIx64 "\n"
+ "\tchip:\t\t\t%u\n"
+ "\tmemory controller:\t%u\n"
+ "\tchannel:\t\t%u\n"
+ "\tdimm:\t\t\t%u\n"
+ "\trank:\t\t\t%u\n",
+ pa, ioc.mcei_chip, ioc.mcei_mc, ioc.mcei_chan, ioc.mcei_dimm,
+ ioc.mcei_rank);
+
+ (void) close(fd);
+}
+
+static void
+mcdecode_dump(const char *device, const char *outfile)
+{
+ int fd;
+ mc_snapshot_info_t mcs;
+ char *buf;
+
+ if ((fd = open(device, O_RDONLY)) < 0) {
+ err(EXIT_FAILURE, "failed to open %s", device);
+ }
+
+ bzero(&mcs, sizeof (mcs));
+ if (ioctl(fd, MC_IOC_DECODE_SNAPSHOT_INFO, &mcs) != 0) {
+ err(EXIT_FAILURE, "failed to get decode snapshot information");
+ }
+
+ if ((buf = malloc(mcs.mcs_size)) == NULL) {
+ err(EXIT_FAILURE, "failed to allocate %u bytes for the "
+ "dump snapshot", mcs.mcs_size);
+ }
+
+ if (ioctl(fd, MC_IOC_DECODE_SNAPSHOT, buf) != 0) {
+ err(EXIT_FAILURE, "failed to retrieve decode snapshot");
+ }
+ (void) close(fd);
+
+ if ((fd = open(outfile, O_RDWR | O_CREAT | O_TRUNC, 0644)) < 0) {
+ err(EXIT_FAILURE, "failed to create output file %s", outfile);
+ }
+
+ while (mcs.mcs_size > 0) {
+ ssize_t ret;
+ size_t out = mcs.mcs_size > MCDECODE_WRITE ? MCDECODE_WRITE :
+ mcs.mcs_size;
+
+ ret = write(fd, buf, out);
+ if (ret < 0) {
+ warn("failed to write to output file %s", outfile);
+ (void) unlink(outfile);
+ exit(EXIT_FAILURE);
+ }
+
+ buf += ret;
+ mcs.mcs_size -= ret;
+ }
+
+ if (fsync(fd) != 0) {
+ warn("failed to sync output file %s", outfile);
+ (void) unlink(outfile);
+ exit(EXIT_FAILURE);
+ }
+
+ (void) close(fd);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int c;
+ uint64_t pa = UINT64_MAX;
+ const char *outfile = NULL;
+ const char *infile = NULL;
+
+ while ((c = getopt(argc, argv, "d:f:w:")) != -1) {
+ char *eptr;
+ unsigned long long tmp;
+
+ switch (c) {
+ case 'd':
+ errno = 0;
+ tmp = strtoull(optarg, &eptr, 0);
+ if (errno != 0 || *eptr != '\0') {
+ errx(EXIT_FAILURE, "failed to parse address "
+ "'%s'", eptr);
+ }
+ pa = (uint64_t)tmp;
+ break;
+ case 'f':
+ infile = optarg;
+ break;
+ case 'w':
+ outfile = optarg;
+ break;
+ case ':':
+ warnx("Option -%c requires an operand", optopt);
+ mcdecode_usage();
+ break;
+ case '?':
+ warnx("Unknown option: -%c", optopt);
+ mcdecode_usage();
+ break;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (outfile != NULL && infile != NULL) {
+ errx(EXIT_FAILURE, "-f and -w cannot be used together");
+ }
+
+ if (pa != UINT64_MAX && outfile != NULL) {
+ errx(EXIT_FAILURE, "-w and -d cannot be used together");
+ }
+
+ if (pa == UINT64_MAX && outfile == NULL) {
+ warnx("missing either -d or -w\n");
+ mcdecode_usage();
+
+ }
+
+ if (argc != 1 && infile == NULL) {
+ errx(EXIT_FAILURE, "missing device argument");
+ }
+
+
+ if (pa != UINT64_MAX) {
+ if (infile != NULL) {
+ mcdecode_from_file(infile, pa);
+ } else {
+ mcdecode_pa(argv[0], pa);
+ }
+ } else {
+ mcdecode_dump(argv[0], outfile);
+ }
+ return (0);
+}
diff --git a/usr/src/cmd/fm/modules/common/fabric-xlate/fabric-xlate.h b/usr/src/cmd/fm/modules/common/fabric-xlate/fabric-xlate.h
index f33ea9ecd6..96e1a956af 100644
--- a/usr/src/cmd/fm/modules/common/fabric-xlate/fabric-xlate.h
+++ b/usr/src/cmd/fm/modules/common/fabric-xlate/fabric-xlate.h
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2019 Joyent, Inc.
*/
#ifndef _FABRIC_XLATE_H
@@ -31,6 +32,7 @@
#include <sys/types.h>
#include <sys/pcie.h>
#include <sys/fm/io/pci.h>
+#include <limits.h>
#ifdef __cplusplus
extern "C" {
@@ -45,6 +47,17 @@ extern "C" {
#define PF_ADDR_PIO (1 << 1)
#define PF_ADDR_CFG (1 << 2)
+
+/*
+ * The fabric ereport preparation functions (fab_prep_*) in fab_erpt_tbl_t
+ * structures may return an error if the ereport could not be set up properly.
+ * Typically, these errors are errnos. It is possible that based on incoming
+ * ereport payload data, we might not want to generate an ereport at all: In
+ * this case, the preparation functions may instead return PF_EREPORT_IGNORE,
+ * which is set at a high value so as not to collide with the errnos.
+ */
+#define PF_EREPORT_IGNORE INT_MAX
+
extern fmd_xprt_t *fab_fmd_xprt; /* FMD transport layer handle */
extern char fab_buf[];
@@ -121,8 +134,21 @@ typedef struct fab_data {
uint16_t pcie_rp_ctl; /* root complex control register */
uint32_t pcie_rp_err_status; /* pcie root complex error status reg */
uint32_t pcie_rp_err_cmd; /* pcie root complex error cmd reg */
- uint16_t pcie_rp_ce_src_id; /* pcie root complex ce sourpe id */
- uint16_t pcie_rp_ue_src_id; /* pcie root complex ue sourpe id */
+ uint16_t pcie_rp_ce_src_id; /* pcie root complex ce source id */
+ uint16_t pcie_rp_ue_src_id; /* pcie root complex ue source id */
+
+ /*
+ * The slot register values refer to the registers of the component's
+ * parent slot, not the component itself.
+ *
+ * You should only use the register values -- i.e.,
+ * pcie_slot_{cap,control,status} -- if pcie_slot_data_valid is set to
+ * true.
+ */
+ boolean_t pcie_slot_data_valid; /* true if slot data is valid */
+ uint32_t pcie_slot_cap; /* pcie slot capabilities */
+ uint16_t pcie_slot_control; /* pcie slot control */
+ uint16_t pcie_slot_status; /* pcie slot status */
/* Flags */
boolean_t pcie_rp_send_all; /* need to send ereports on all rps */
@@ -131,7 +157,6 @@ typedef struct fab_data {
typedef struct fab_erpt_tbl {
const char *err_class; /* Final Ereport Class */
uint32_t reg_bit; /* Error Bit Mask */
- /* Pointer to function that prepares the ereport body */
const char *tgt_class; /* Target Ereport Class */
} fab_erpt_tbl_t;
diff --git a/usr/src/cmd/fm/modules/common/fabric-xlate/fx_fabric.c b/usr/src/cmd/fm/modules/common/fabric-xlate/fx_fabric.c
index 69ecf1aa8d..14ae738863 100644
--- a/usr/src/cmd/fm/modules/common/fabric-xlate/fx_fabric.c
+++ b/usr/src/cmd/fm/modules/common/fabric-xlate/fx_fabric.c
@@ -22,10 +22,13 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2019 Joyent, Inc.
*/
#include <stddef.h>
#include <strings.h>
#include <sys/fm/util.h>
+#include <sys/pcie.h>
#include "fabric-xlate.h"
@@ -271,6 +274,24 @@ fab_pci_fabric_to_data(fmd_hdl_t *hdl, nvlist_t *nvl, fab_data_t *data)
FAB_LOOKUP(32, "pcie_adv_rp_command", &data->pcie_rp_err_cmd);
FAB_LOOKUP(16, "pcie_adv_rp_ce_src_id", &data->pcie_rp_ce_src_id);
FAB_LOOKUP(16, "pcie_adv_rp_ue_src_id", &data->pcie_rp_ue_src_id);
+
+ /*
+ * PCIe Parent Slot Registers
+ *
+ * These are only passed in the ereport if the parent PCIe component
+ * supports the registers and the registers have valid data. As such, we
+ * look up one slot register value first: If that value is present in
+ * the input ereport data, then we know the others should be there as
+ * well. We also set the pcie_slot_data_valid flag to ensure we know
+ * the slot register data is safe to use in the module.
+ */
+ data->pcie_slot_data_valid = B_FALSE;
+ if (nvlist_lookup_uint32(nvl, "pcie_slot_cap", &data->pcie_slot_cap) ==
+ 0) {
+ FAB_LOOKUP(16, "pcie_slot_control", &data->pcie_slot_control);
+ FAB_LOOKUP(16, "pcie_slot_status", &data->pcie_slot_status);
+ data->pcie_slot_data_valid = B_TRUE;
+ }
}
static int
@@ -358,6 +379,38 @@ fab_prep_pcie_ue_erpt(fmd_hdl_t *hdl, fab_data_t *data, nvlist_t *erpt,
PCIE_AER_CTL_FST_ERR_PTR_MASK);
int err = fab_prep_basic_erpt(hdl, data->nvl, erpt, B_FALSE);
+ if (data->pcie_slot_data_valid) {
+ (void) nvlist_add_uint32(erpt, "pcie_slot_cap",
+ data->pcie_slot_cap);
+ (void) nvlist_add_uint16(erpt, "pcie_slot_control",
+ data->pcie_slot_control);
+ (void) nvlist_add_uint16(erpt, "pcie_slot_status",
+ data->pcie_slot_status);
+
+ /*
+ * It is possible to see uncorrectable errors for a slot that
+ * are related to the slot's child device being physically
+ * removed from the slot. As such, in the case that the slot
+ * reports that it is empty, we do not want to generate an
+ * ereport for all errors. Generating an ereport here will cause
+ * the eft module to fault the device and io-retire to
+ * subsequently retire the device. Retiring the device makes
+ * little sense given that the device is physically gone; more
+ * confusingly, if plugged back into the slot, it would be
+ * marked retired already.
+ *
+ * The only error ignored for this case is Completion Timeout.
+ * It is possible more errors should be ignored, and if they
+ * are seen in the field it might be worth broadening the set
+ * of ignored errors.
+ */
+ if (tbl->reg_bit == PCIE_AER_UCE_TO &&
+ ((data->pcie_slot_status &
+ PCIE_SLOTSTS_PRESENCE_DETECTED) == 0x0)) {
+ return (PF_EREPORT_IGNORE);
+ }
+ }
+
/* Generate an ereport for this error bit. */
(void) snprintf(fab_buf, FM_MAX_CLASS, "ereport.io.%s.%s",
PCIEX_ERROR_SUBCLASS, class);
@@ -776,7 +829,7 @@ fab_xlate_pcie_erpts(fmd_hdl_t *hdl, fab_data_t *data)
fmd_hdl_debug(hdl, "Sending Ereports Now");
- /* Go through the error logs and send the relavant reports */
+ /* Go through the error logs and send the relevant reports */
for (tbl = fab_master_err_tbl; tbl->erpt_tbl; tbl++) {
fab_send_erpt(hdl, data, tbl);
}
diff --git a/usr/src/cmd/fm/modules/common/fabric-xlate/fx_subr.c b/usr/src/cmd/fm/modules/common/fabric-xlate/fx_subr.c
index 8593144b28..94678dbd47 100644
--- a/usr/src/cmd/fm/modules/common/fabric-xlate/fx_subr.c
+++ b/usr/src/cmd/fm/modules/common/fabric-xlate/fx_subr.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2019 Joyent, Inc.
*/
#include <strings.h>
#include <fm/topo_hc.h>
@@ -185,6 +186,7 @@ fab_send_erpt(fmd_hdl_t *hdl, fab_data_t *data, fab_err_tbl_t *tbl)
fab_erpt_tbl_t *erpt_tbl, *entry;
nvlist_t *erpt;
uint32_t reg;
+ int err;
erpt_tbl = tbl->erpt_tbl;
if (tbl->reg_size == 16) {
@@ -200,7 +202,9 @@ fab_send_erpt(fmd_hdl_t *hdl, fab_data_t *data, fab_err_tbl_t *tbl)
if (nvlist_alloc(&erpt, NV_UNIQUE_NAME, 0) != 0)
goto done;
- if (tbl->fab_prep(hdl, data, erpt, entry) != 0) {
+
+ err = tbl->fab_prep(hdl, data, erpt, entry);
+ if (err != 0 && err != PF_EREPORT_IGNORE) {
fmd_hdl_debug(hdl, "Prepping ereport failed: "
"class = %s\n", entry->err_class);
nvlist_free(erpt);
@@ -394,7 +398,7 @@ fab_find_rppath_by_devbdf(fmd_hdl_t *hdl, nvlist_t *nvl, pcie_req_id_t bdf)
xmlXPathObjectPtr xpathObj;
xmlNodeSetPtr nodes;
xmlNodePtr devNode;
- char *retval, *temp;
+ char *retval, *temp;
char query[500];
int i, size, bus, dev, fn;
char *hcpath;
@@ -577,7 +581,7 @@ fail:
char *
fab_find_bdf(fmd_hdl_t *hdl, nvlist_t *nvl, pcie_req_id_t bdf)
{
- char *retval;
+ char *retval;
char query[500];
int bus, dev, fn;
char rcpath[255];
@@ -705,7 +709,7 @@ found:
propgroup:
/* Retrive the "dev" propval and return */
for (devNode = devNode->children; devNode; devNode = devNode->next) {
- char *tprop;
+ char *tprop;
tprop = GET_PROP(devNode, "name");
if (STRCMP(devNode->name, "propval") &&
@@ -866,8 +870,8 @@ fab_pr(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl)
char *
fab_get_rpdev(fmd_hdl_t *hdl)
{
- char *retval;
- char query[500];
+ char *retval;
+ char query[500];
(void) snprintf(query, sizeof (query), "//propval["
"@name='extended-capabilities' and contains(@value, '%s')]"
@@ -888,8 +892,8 @@ fab_send_erpt_all_rps(fmd_hdl_t *hdl, nvlist_t *erpt)
{
xmlXPathObjectPtr xpathObj;
xmlNodeSetPtr nodes;
- char *rppath, *hbpath;
- char query[600];
+ char *rppath, *hbpath;
+ char query[600];
nvlist_t *detector, *nvl;
uint_t i, size;
size_t len;
diff --git a/usr/src/cmd/fm/modules/common/zfs-diagnosis/zfs_de.c b/usr/src/cmd/fm/modules/common/zfs-diagnosis/zfs_de.c
index d1206a34d3..5295c012bc 100644
--- a/usr/src/cmd/fm/modules/common/zfs-diagnosis/zfs_de.c
+++ b/usr/src/cmd/fm/modules/common/zfs-diagnosis/zfs_de.c
@@ -22,6 +22,7 @@
/*
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2019 Joyent, Inc.
*/
#include <assert.h>
@@ -38,9 +39,9 @@
#include <sys/fm/fs/zfs.h>
/*
- * Our serd engines are named 'zfs_<pool_guid>_<vdev_guid>_{checksum,io}'. This
- * #define reserves enough space for two 64-bit hex values plus the length of
- * the longest string.
+ * Our serd engines are named 'zfs_<pool_guid>_<vdev_guid>_{checksum,io,probe}'.
+ * This #define reserves enough space for two 64-bit hex values plus the length
+ * of the longest string.
*/
#define MAX_SERDLEN (16 * 2 + sizeof ("zfs___checksum"))
@@ -58,6 +59,7 @@ typedef struct zfs_case_data {
int zc_pool_state;
char zc_serd_checksum[MAX_SERDLEN];
char zc_serd_io[MAX_SERDLEN];
+ char zc_serd_probe[MAX_SERDLEN];
int zc_has_remove_timer;
} zfs_case_data_t;
@@ -370,8 +372,8 @@ zfs_purge_cases(fmd_hdl_t *hdl)
}
/*
- * Construct the name of a serd engine given the pool/vdev GUID and type (io or
- * checksum).
+ * Construct the name of a serd engine given the pool/vdev GUID and type (io,
+ * checksum, or probe).
*/
static void
zfs_serd_name(char *buf, uint64_t pool_guid, uint64_t vdev_guid,
@@ -627,7 +629,8 @@ zfs_fm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class)
pool_found = B_TRUE;
pool_load = zcp->zc_when;
}
- if (zcp->zc_data.zc_vdev_guid == vdev_guid)
+ if (zcp->zc_data.zc_vdev_guid == vdev_guid &&
+ zcp->zc_data.zc_pool_guid == pool_guid)
break;
}
@@ -775,6 +778,8 @@ zfs_fm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class)
if (zcp->zc_data.zc_serd_checksum[0] != '\0')
fmd_serd_reset(hdl,
zcp->zc_data.zc_serd_checksum);
+ if (zcp->zc_data.zc_serd_probe[0] != '\0')
+ fmd_serd_reset(hdl, zcp->zc_data.zc_serd_probe);
}
zfs_stats.resource_drops.fmds_value.ui64++;
return;
@@ -843,8 +848,8 @@ zfs_fm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class)
boolean_t checkremove = B_FALSE;
/*
- * If this is a checksum or I/O error, then toss it into the
- * appropriate SERD engine and check to see if it has fired.
+ * If this is a checksum, I/O, or probe error, then toss it into
+ * the appropriate SERD engine and check to see if it has fired.
* Ideally, we want to do something more sophisticated,
* (persistent errors for a single data block, etc). For now,
* a single SERD engine is sufficient.
@@ -894,7 +899,18 @@ zfs_fm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class)
}
} else if (fmd_nvl_class_match(hdl, nvl,
ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_PROBE_FAILURE))) {
- checkremove = B_TRUE;
+ if (zcp->zc_data.zc_serd_probe[0] == '\0') {
+ zfs_serd_name(zcp->zc_data.zc_serd_probe,
+ pool_guid, vdev_guid, "probe");
+ fmd_serd_create(hdl, zcp->zc_data.zc_serd_probe,
+ fmd_prop_get_int32(hdl, "probe_N"),
+ fmd_prop_get_int64(hdl, "probe_T"));
+ zfs_case_serialize(hdl, zcp);
+ }
+ if (fmd_serd_record(hdl,
+ zcp->zc_data.zc_serd_probe, ep)) {
+ checkremove = B_TRUE;
+ }
}
/*
@@ -938,6 +954,8 @@ zfs_fm_close(fmd_hdl_t *hdl, fmd_case_t *cs)
fmd_serd_destroy(hdl, zcp->zc_data.zc_serd_checksum);
if (zcp->zc_data.zc_serd_io[0] != '\0')
fmd_serd_destroy(hdl, zcp->zc_data.zc_serd_io);
+ if (zcp->zc_data.zc_serd_probe[0] != '\0')
+ fmd_serd_destroy(hdl, zcp->zc_data.zc_serd_probe);
if (zcp->zc_data.zc_has_remove_timer)
fmd_timer_remove(hdl, zcp->zc_remove_timer);
uu_list_remove(zfs_cases, zcp);
@@ -967,6 +985,8 @@ static const fmd_prop_t fmd_props[] = {
{ "checksum_T", FMD_TYPE_TIME, "10min" },
{ "io_N", FMD_TYPE_UINT32, "10" },
{ "io_T", FMD_TYPE_TIME, "10min" },
+ { "probe_N", FMD_TYPE_UINT32, "5" },
+ { "probe_T", FMD_TYPE_TIME, "24hour" },
{ "remove_timeout", FMD_TYPE_TIME, "15sec" },
{ NULL, 0, NULL }
};
diff --git a/usr/src/cmd/fm/modules/common/zfs-retire/zfs_retire.c b/usr/src/cmd/fm/modules/common/zfs-retire/zfs_retire.c
index 3c70122067..85d9dfc904 100644
--- a/usr/src/cmd/fm/modules/common/zfs-retire/zfs_retire.c
+++ b/usr/src/cmd/fm/modules/common/zfs-retire/zfs_retire.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2019 Joyent, Inc.
*/
/*
* Copyright 2019 Joyent, Inc.
@@ -124,13 +125,21 @@ find_vdev(libzfs_handle_t *zhdl, nvlist_t *nv, const char *search_fru,
}
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
- &child, &children) != 0)
- return (NULL);
+ &child, &children) == 0) {
+ for (c = 0; c < children; c++) {
+ if ((ret = find_vdev(zhdl, child[c], search_fru,
+ search_guid)) != NULL)
+ return (ret);
+ }
+ }
- for (c = 0; c < children; c++) {
- if ((ret = find_vdev(zhdl, child[c], search_fru,
- search_guid)) != NULL)
- return (ret);
+ if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
+ &child, &children) == 0) {
+ for (c = 0; c < children; c++) {
+ if ((ret = find_vdev(zhdl, child[c], search_fru,
+ search_guid)) != NULL)
+ return (ret);
+ }
}
return (NULL);