diff options
Diffstat (limited to 'usr/src/cmd/fm')
| -rw-r--r-- | usr/src/cmd/fm/Makefile | 6 | ||||
| -rw-r--r-- | usr/src/cmd/fm/fmdump/common/nvlrender.c | 2 | ||||
| -rw-r--r-- | usr/src/cmd/fm/mcdecode/Makefile | 59 | ||||
| -rw-r--r-- | usr/src/cmd/fm/mcdecode/mcdecode.c | 284 | ||||
| -rw-r--r-- | usr/src/cmd/fm/modules/common/fabric-xlate/fabric-xlate.h | 31 | ||||
| -rw-r--r-- | usr/src/cmd/fm/modules/common/fabric-xlate/fx_fabric.c | 55 | ||||
| -rw-r--r-- | usr/src/cmd/fm/modules/common/fabric-xlate/fx_subr.c | 20 | ||||
| -rw-r--r-- | usr/src/cmd/fm/modules/common/zfs-diagnosis/zfs_de.c | 38 | ||||
| -rw-r--r-- | usr/src/cmd/fm/modules/common/zfs-retire/zfs_retire.c | 21 |
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); |
