diff --git a/Makefile b/Makefile
index a91950c..f8199f6 100644
--- a/Makefile
+++ b/Makefile
@@ -22,7 +22,10 @@ WARNINGS := -Wall -Wextra -Wno-missing-field-initializers -Wno-unused-parameter
# CONFIG_DISKDB = 1
TRIGGERS=cache-error-trigger dimm-error-trigger page-error-trigger \
- socket-memory-error-trigger
+ socket-memory-error-trigger \
+ bus-error-trigger \
+ iomca-error-trigger \
+ unknown-error-trigger
all: mcelog
@@ -32,7 +35,7 @@ OBJ := p4.o k8.o mcelog.o dmi.o tsc.o core2.o bitfield.o intel.o \
nehalem.o dunnington.o tulsa.o config.o memutil.o msg.o \
eventloop.o leaky-bucket.o memdb.o server.o trigger.o \
client.o cache.o sysfs.o yellow.o page.o rbtree.o \
- xeon75xx.o sandy-bridge.o ivy-bridge.o haswell.o msr.o
+ xeon75xx.o sandy-bridge.o ivy-bridge.o haswell.o msr.o bus.o unknown.o
DISKDB_OBJ := diskdb.o dimm.o db.o
CLEAN := mcelog dmi tsc dbquery .depend .depend.X dbquery.o ${DISKDB_OBJ}
DOC := mce.pdf
diff --git a/bus.c b/bus.c
new file mode 100644
index 0000000..f48bc38
--- /dev/null
+++ b/bus.c
@@ -0,0 +1,129 @@
+/* Copyright (C) 20014 Intel Corporation
+ Author: Rui Wang
+ Handle 'Bus and Interconnect' error threshold indications.
+
+ mcelog is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; version
+ 2.
+
+ mcelog is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should find a copy of v2 of the GNU General Public License somewhere
+ on your Linux system. */
+#define _GNU_SOURCE 1
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include "memutil.h"
+#include "mcelog.h"
+#include "config.h"
+#include "trigger.h"
+#include "bus.h"
+
+static char *bus_trigger, *iomca_trigger;
+
+enum {
+ MAX_ENV = 20,
+};
+
+void bus_setup(void)
+{
+ bus_trigger = config_string("socket", "bus-uc-threshold-trigger");
+ if (bus_trigger && trigger_check(bus_trigger) < 0) {
+ SYSERRprintf("Cannot access bus threshold trigger `%s'",
+ bus_trigger);
+ exit(1);
+ }
+
+ iomca_trigger = config_string("socket", "iomca-threshold-trigger");
+ if (iomca_trigger && trigger_check(iomca_trigger) < 0) {
+ SYSERRprintf("Cannot access iomca threshold trigger `%s'",
+ iomca_trigger);
+ exit(1);
+ }
+}
+
+void run_bus_trigger(int socket, int cpu, char *level, char *pp, char *rrrr,
+ char *ii, char *timeout)
+{
+ int ei = 0;
+ char *env[MAX_ENV];
+ int i;
+ char *msg;
+ char *location;
+
+ if (socket >= 0)
+ asprintf(&location, "CPU %d on socket %d", cpu, socket);
+ else
+ asprintf(&location, "CPU %d", cpu);
+ asprintf(&msg, "%s received Bus and Interconnect Errors in %s",
+ location, ii);
+ asprintf(&env[ei++], "LOCATION=%s", location);
+ free(location);
+
+ if (!bus_trigger)
+ goto out;
+
+ if (socket >= 0)
+ asprintf(&env[ei++], "SOCKETID=%d", socket);
+ asprintf(&env[ei++], "MESSAGE=%s", msg);
+ asprintf(&env[ei++], "CPU=%d", cpu);
+ asprintf(&env[ei++], "LEVEL=%s", level);
+ asprintf(&env[ei++], "PARTICIPATION=%s", pp);
+ asprintf(&env[ei++], "REQUEST=%s", rrrr);
+ asprintf(&env[ei++], "ORIGIN=%s", ii);
+ asprintf(&env[ei++], "TIMEOUT=%s", timeout);
+ env[ei] = NULL;
+ assert(ei < MAX_ENV);
+
+ run_trigger(bus_trigger, NULL, env);
+ for (i = 0; i < ei; i++)
+ free(env[i]);
+out:
+ free(msg);
+}
+
+void run_iomca_trigger(int socket, int cpu, int seg, int bus, int dev, int fn)
+{
+ int ei = 0;
+ char *env[MAX_ENV];
+ int i;
+ char *msg;
+ char *location;
+
+ if (socket >= 0)
+ asprintf(&location, "CPU %d on socket %d", cpu, socket);
+ else
+ asprintf(&location, "CPU %d", cpu);
+ asprintf(&msg, "%s received IO MCA Errors from %x:%02x:%02x.%x",
+ location, seg, bus, dev, fn);
+ asprintf(&env[ei++], "LOCATION=%s", location);
+ free(location);
+
+ if (!iomca_trigger)
+ goto out;
+
+ if (socket >= 0)
+ asprintf(&env[ei++], "SOCKETID=%d", socket);
+ asprintf(&env[ei++], "MESSAGE=%s", msg);
+ asprintf(&env[ei++], "CPU=%d", cpu);
+ asprintf(&env[ei++], "SEG=%x", seg);
+ asprintf(&env[ei++], "BUS=%02x", bus);
+ asprintf(&env[ei++], "DEVICE=%02x", dev);
+ asprintf(&env[ei++], "FUNCTION=%x", fn);
+ env[ei] = NULL;
+ assert(ei < MAX_ENV);
+
+ run_trigger(iomca_trigger, NULL, env);
+ for (i = 0; i < ei; i++)
+ free(env[i]);
+out:
+ free(msg);
+
+}
diff --git a/bus.h b/bus.h
new file mode 100644
index 0000000..37ac592
--- /dev/null
+++ b/bus.h
@@ -0,0 +1,4 @@
+void bus_setup(void);
+void run_bus_trigger(int socket, int cpu, char *level, char *pp, char *rrrr,
+ char *ii, char *timeout);
+void run_iomca_trigger(int socket, int cpu, int seg, int bus, int dev, int fn);
diff --git a/input/iomca b/input/iomca
new file mode 100644
index 0000000..9a1e27d
--- /dev/null
+++ b/input/iomca
@@ -0,0 +1,4 @@
+CPU 0 BANK 1
+STATUS 0x9c00000000000e0b
+MISC 0xabcdef
+ADDR 0xabcd
diff --git a/input/unknown b/input/unknown
new file mode 100644
index 0000000..29a2436
--- /dev/null
+++ b/input/unknown
@@ -0,0 +1,4 @@
+CPU 0 BANK 1
+STATUS 0x9c0000000000040b
+MISC 0xabcdef
+ADDR 0xabcd
diff --git a/mcelog.c b/mcelog.c
index 89bb537..95a913f 100644
--- a/mcelog.c
+++ b/mcelog.c
@@ -58,6 +58,8 @@
#include "msg.h"
#include "yellow.h"
#include "page.h"
+#include "bus.h"
+#include "unknown.h"
enum cputype cputype = CPU_GENERIC;
@@ -567,6 +569,12 @@ static char *skipgunk(char *s)
if (*s == ']')
++s;
}
+
+ s = skipspace(s);
+
+ if (strncmp(s, "mce: [Hardware Error]:", 22) == 0)
+ s += 22;
+
return skipspace(s);
}
@@ -1153,6 +1161,8 @@ static void general_setup(void)
{
trigger_setup();
yellow_setup();
+ bus_setup();
+ unknown_setup();
config_cred("global", "run-credentials", &runcred);
if (config_bool("global", "filter-memory-errors") == 1)
filter_memory_errors = 1;
diff --git a/mcelog.conf b/mcelog.conf
index 1bab3ee..6a2be26 100644
--- a/mcelog.conf
+++ b/mcelog.conf
@@ -127,6 +127,9 @@ mem-ce-error-threshold = 100 / 24h
# Log socket error threshold explicitely?
mem-ce-error-log = yes
+bus-uc-threshold-trigger = bus-error-trigger
+iomca-threshold-trigger = iomca-error-trigger
+unknown-threshold-trigger = unknown-error-trigger
[cache]
# Processing of cache error thresholds reported by Intel CPUs
diff --git a/msr.c b/msr.c
index 2eef9d2..665cac3 100644
--- a/msr.c
+++ b/msr.c
@@ -36,10 +36,8 @@ static void domsr(int cpu, int msr, int bit)
SYSERRprintf("Cannot re-read MSR_ERROR_CONTROL from %s\n", fpath);
exit(1);
}
- if ((data & bit) == 0) {
- SYSERRprintf("Failed to set imc_log on cpu %d\n", cpu);
- exit(1);
- }
+ if ((data & bit) == 0)
+ Lprintf("No DIMM detection available on cpu %d (normal in virtual environments)\n", cpu);
close(fd);
}
@@ -54,6 +52,8 @@ void set_imc_log(int cputype)
msr = 0x17f; /* MSR_ERROR_CONTROL */
bit = 0x2; /* MemError Log Enable */
break;
+ default:
+ return;
}
for (cpu = 0; cpu < ncpus; cpu++)
diff --git a/p4.c b/p4.c
index 8a3b5a6..f938196 100644
--- a/p4.c
+++ b/p4.c
@@ -30,6 +30,8 @@
#include "tulsa.h"
#include "intel.h"
#include "yellow.h"
+#include "bus.h"
+#include "unknown.h"
#include "bitfield.h"
#include "sandy-bridge.h"
#include "ivy-bridge.h"
@@ -116,7 +118,7 @@ static char* get_II_str(__u8 i)
return II[i];
}
-static void decode_mca(__u32 mca, u64 track, int cpu, int *ismemerr, int socket)
+static int decode_mca(u64 status, u64 misc, u64 track, int cpu, int *ismemerr, int socket)
{
#define TLB_LL_MASK 0x3 /*bit 0, bit 1*/
#define TLB_LL_SHIFT 0x0
@@ -141,6 +143,8 @@ static void decode_mca(__u32 mca, u64 track, int cpu, int *ismemerr, int socket)
#define BUS_PP_MASK 0x600 /*bit 9, bit 10*/
#define BUS_PP_SHIFT 0x9
+ u32 mca;
+ int ret = 0;
static char *msg[] = {
[0] = "No Error",
[1] = "Unclassified",
@@ -151,6 +155,7 @@ static void decode_mca(__u32 mca, u64 track, int cpu, int *ismemerr, int socket)
[6] = "SMM Handler Code Access Violation",
};
+ mca = status & 0xffff;
if (mca & (1UL << 12)) {
Wprintf("corrected filtering (some unreported errors in same region)\n");
mca &= ~(1UL << 12);
@@ -158,16 +163,27 @@ static void decode_mca(__u32 mca, u64 track, int cpu, int *ismemerr, int socket)
if (mca < NELE(msg)) {
Wprintf("%s\n", msg[mca]);
- return;
+ return ret;
}
if ((mca >> 2) == 3) {
- Wprintf("%s Generic memory hierarchy error\n", get_LL_str(mca & 3));
+ unsigned levelnum;
+ char *level;
+ levelnum = mca & 3;
+ level = get_LL_str(levelnum);
+ Wprintf("%s Generic cache hierarchy error\n", level);
+ if (track == 2)
+ run_yellow_trigger(cpu, -1, levelnum, "unknown", level, socket);
} else if (test_prefix(4, mca)) {
- Wprintf("%s TLB %s Error\n",
- get_TT_str((mca & TLB_TT_MASK) >> TLB_TT_SHIFT),
- get_LL_str((mca & TLB_LL_MASK) >>
- TLB_LL_SHIFT));
+ unsigned levelnum, typenum;
+ char *level, *type;
+ typenum = (mca & TLB_TT_MASK) >> TLB_TT_SHIFT;
+ type = get_TT_str(typenum);
+ levelnum = (mca & TLB_LL_MASK) >> TLB_LL_SHIFT;
+ level = get_LL_str(levelnum);
+ Wprintf("%s TLB %s Error\n", type, level);
+ if (track == 2)
+ run_yellow_trigger(cpu, typenum, levelnum, type, level, socket);
} else if (test_prefix(8, mca)) {
unsigned typenum = (mca & CACHE_TT_MASK) >> CACHE_TT_SHIFT;
unsigned levelnum = (mca & CACHE_LL_MASK) >> CACHE_LL_SHIFT;
@@ -177,25 +193,51 @@ static void decode_mca(__u32 mca, u64 track, int cpu, int *ismemerr, int socket)
get_RRRR_str((mca & CACHE_RRRR_MASK) >>
CACHE_RRRR_SHIFT));
if (track == 2)
- run_yellow_trigger(cpu, typenum, levelnum, type, level, socket);
+ run_yellow_trigger(cpu, typenum, levelnum, type, level,socket);
} else if (test_prefix(10, mca)) {
if (mca == 0x400)
Wprintf("Internal Timer error\n");
else
Wprintf("Internal unclassified error: %x\n", mca & 0xffff);
+
+ ret = 1;
} else if (test_prefix(11, mca)) {
- Wprintf("BUS %s %s %s %s %s Error\n",
- get_LL_str((mca & BUS_LL_MASK) >> BUS_LL_SHIFT),
- get_PP_str((mca & BUS_PP_MASK) >> BUS_PP_SHIFT),
- get_RRRR_str((mca & BUS_RRRR_MASK) >>
- BUS_RRRR_SHIFT),
- get_II_str((mca & BUS_II_MASK) >> BUS_II_SHIFT),
- get_T_str((mca & BUS_T_MASK) >> BUS_T_SHIFT));
+ char *level, *pp, *rrrr, *ii, *timeout;
+
+ level = get_LL_str((mca & BUS_LL_MASK) >> BUS_LL_SHIFT);
+ pp = get_PP_str((mca & BUS_PP_MASK) >> BUS_PP_SHIFT);
+ rrrr = get_RRRR_str((mca & BUS_RRRR_MASK) >> BUS_RRRR_SHIFT);
+ ii = get_II_str((mca & BUS_II_MASK) >> BUS_II_SHIFT);
+ timeout = get_T_str((mca & BUS_T_MASK) >> BUS_T_SHIFT);
+
+ Wprintf("BUS error: %d %d %s %s %s %s %s\n", socket, cpu,
+ level, pp, rrrr, ii, timeout);
+ run_bus_trigger(socket, cpu, level, pp, rrrr, ii, timeout);
+ /* IO MCA - reported as bus/interconnect with specific PP,T,RRRR,II,LL values
+ * and MISCV set. MISC register points to root port that reported the error
+ * need to cross check with AER logs for more details.
+ * See: http://www.intel.com/content/www/us/en/architecture-and-technology/enhanced-mca-logging-xeon-paper.html
+ */
+ if ((status & MCI_STATUS_MISCV) &&
+ (status & 0xefff) == 0x0e0b) {
+ int seg, bus, dev, fn;
+
+ seg = EXTRACT(misc, 32, 39);
+ bus = EXTRACT(misc, 24, 31);
+ dev = EXTRACT(misc, 19, 23);
+ fn = EXTRACT(misc, 16, 18);
+ Wprintf("IO MCA reported by root port %x:%02x:%02x.%x\n",
+ seg, bus, dev, fn);
+ run_iomca_trigger(socket, cpu, seg, bus, dev, fn);
+ }
} else if (test_prefix(7, mca)) {
decode_memory_controller(mca);
*ismemerr = 1;
- } else
+ } else {
Wprintf("Unknown Error %x\n", mca);
+ ret = 1;
+ }
+ return ret;
}
static void p4_decode_model(__u32 model)
@@ -243,7 +285,7 @@ static const char *arstate[4] = {
[3] = "SRAR"
};
-static void decode_mci(__u64 status, int cpu, unsigned mcgcap, int *ismemerr,
+static int decode_mci(__u64 status, __u64 misc, int cpu, unsigned mcgcap, int *ismemerr,
int socket)
{
u64 track = 0;
@@ -280,7 +322,7 @@ static void decode_mci(__u64 status, int cpu, unsigned mcgcap, int *ismemerr,
decode_tracking(track);
}
Wprintf("MCA: ");
- decode_mca(status & 0xffffL, track, cpu, ismemerr, socket);
+ return decode_mca(status, misc, track, cpu, ismemerr, socket);
}
static void decode_mcg(__u64 mcgstatus)
@@ -314,11 +356,14 @@ void decode_intel_mc(struct mce *log, int cputype, int *ismemerr, unsigned size)
if (log->bank == MCE_THERMAL_BANK) {
decode_thermal(log, cpu);
+ run_unknown_trigger(socket, cpu, log);
return;
}
decode_mcg(log->mcgstatus);
- decode_mci(log->status, cpu, log->mcgcap, ismemerr, socket);
+ if (decode_mci(log->status, log->misc, cpu, log->mcgcap, ismemerr,
+ socket))
+ run_unknown_trigger(socket, cpu, log);
if (test_prefix(11, (log->status & 0xffffL))) {
switch (cputype) {
@@ -365,23 +410,6 @@ void decode_intel_mc(struct mce *log, int cputype, int *ismemerr, unsigned size)
hsw_decode_model(cputype, log->bank, log->status, log->misc);
break;
}
-
- /* IO MCA - reported as bus/interconnect with specific PP,T,RRRR,II,LL values
- * and MISCV set. MISC register points to root port that reported the error
- * need to cross check with AER logs for more details.
- * See: http://www.intel.com/content/www/us/en/architecture-and-technology/enhanced-mca-logging-xeon-paper.html
- */
- if ((log->status & MCI_STATUS_MISCV) &&
- (log->status & 0xefff) == 0x0e0b) {
- int seg, bus, dev, fn;
-
- seg = EXTRACT(log->misc, 32, 39);
- bus = EXTRACT(log->misc, 24, 31);
- dev = EXTRACT(log->misc, 19, 23);
- fn = EXTRACT(log->misc, 16, 18);
- Wprintf("IO MCA reported by root port %x:%02x:%02x.%x\n",
- seg, bus, dev, fn);
- }
}
char *intel_bank_name(int num)
diff --git a/tests/unknown/inject b/tests/unknown/inject
new file mode 100755
index 0000000..7be39a7
--- /dev/null
+++ b/tests/unknown/inject
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+B=$(pwd)/../..
+
+PATH=$PATH:$B/../mce-inject
+
+mce-inject $B/input/iomca
+mce-inject $B/input/unknown
diff --git a/tests/unknown/unknown.conf b/tests/unknown/unknown.conf
new file mode 100644
index 0000000..4b86db7
--- /dev/null
+++ b/tests/unknown/unknown.conf
@@ -0,0 +1,11 @@
+# trigger: 3
+
+num-errors = 2
+
+[socket]
+bus-uc-threshold-trigger = ../trigger
+iomca-threshold-trigger = ../trigger
+unknown-threshold-trigger = ../trigger
+
+[trigger]
+directory = .
diff --git a/triggers/bus-error-trigger b/triggers/bus-error-trigger
new file mode 100644
index 0000000..c996001
--- /dev/null
+++ b/triggers/bus-error-trigger
@@ -0,0 +1,23 @@
+#!/bin/sh
+# This shell script can be executed by mcelog in daemon mode when a sockets
+# receives Bus and Interconnect errors
+#
+# environment:
+# MESSAGE Human readable consolidated error message
+# LOCATION Consolidated location as a single string
+# SOCKETID Socket ID of CPU that includes the memory controller with the DIMM
+# LEVEL Interconnect level
+# PARTICIPATION Processor Participation (Originator, Responder or Observer)
+# REQUEST Request type (read, write, prefetch, etc.)
+# ORIGIN Memory or IO
+# TIMEOUT The request timed out or not
+#
+# note: will run as mcelog configured user
+# this can be changed in mcelog.conf
+
+logger -s -p daemon.err -t mcelog "$MESSAGE"
+logger -s -p daemon.err -t mcelog "Location: $LOCATION"
+
+[ -x ./bus-error-trigger.local ] && . ./bus-error-trigger.local
+
+exit 0
diff --git a/triggers/iomca-error-trigger b/triggers/iomca-error-trigger
new file mode 100644
index 0000000..3888461
--- /dev/null
+++ b/triggers/iomca-error-trigger
@@ -0,0 +1,23 @@
+#!/bin/sh
+# This shell script can be executed by mcelog in daemon mode when a sockets
+# receives Bus and Interconnect errors
+#
+# environment:
+# MESSAGE Human readable consolidated error message
+# LOCATION Consolidated location as a single string
+# SOCKETID Socket ID of CPU that includes the memory controller with the DIMM
+# CPU Linux CPU number that triggered the error
+# SET PCI segment number
+# BUS PCI bus number
+# DEVICE PCI device number
+# FUNCTION PCI function number
+#
+# note: will run as mcelog configured user
+# this can be changed in mcelog.conf
+
+logger -s -p daemon.err -t mcelog "$MESSAGE"
+logger -s -p daemon.err -t mcelog "Location: $LOCATION"
+
+[ -x ./iomca-error-trigger.local ] && . ./iomca-error-trigger.local
+
+exit 0
diff --git a/triggers/unknown-error-trigger b/triggers/unknown-error-trigger
new file mode 100644
index 0000000..b924a0e
--- /dev/null
+++ b/triggers/unknown-error-trigger
@@ -0,0 +1,26 @@
+#!/bin/sh
+# This shell script is executed by mcelog in daemon mode when
+# an not otherwise handled machine check error happens.
+#
+# environment:
+# MESSAGE Human readable consolidated error message
+# LOCATION Consolidated location as a single string
+# SOCKETID Socket ID of CPU that includes the memory controller with the DIMM
+# CPU Linux CPU number that triggered the error
+# STATUS IA32_MCi_STATUS register value
+# ADDR IA32_MCi_ADDR register value
+# MISC IA32_MCi_MISC regiser value
+# MCGSTATUS IA32_MCG_STATUS register value
+# MCGCAP IA32_MCG_CAP register value
+# For details on the register layout please see the Intel SDM http://www.intel.com/sdm
+# volume 3, chapter 15
+#
+# note: will run as mcelog configured user
+# this can be changed in mcelog.conf
+
+logger -s -p daemon.err -t mcelog "$MESSAGE"
+logger -s -p daemon.err -t mcelog "Location: $LOCATION"
+
+[ -x ./unknown-error-trigger.local ] && . ./unknown-error-trigger.local
+
+exit 0
diff --git a/unknown.c b/unknown.c
new file mode 100644
index 0000000..482c29e
--- /dev/null
+++ b/unknown.c
@@ -0,0 +1,82 @@
+/* Copyright (C) 20014 Intel Corporation
+ Author: Rui Wang
+ Handle all other unknown error requests.
+
+ mcelog is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; version
+ 2.
+
+ mcelog is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should find a copy of v2 of the GNU General Public License somewhere
+ on your Linux system. */
+#define _GNU_SOURCE 1
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include "memutil.h"
+#include "mcelog.h"
+#include "config.h"
+#include "trigger.h"
+#include "unknown.h"
+
+static char *unknown_trigger;
+
+enum {
+ MAX_ENV = 20,
+};
+
+void unknown_setup(void)
+{
+ unknown_trigger = config_string("socket", "unknown-threshold-trigger");
+ if (unknown_trigger && trigger_check(unknown_trigger) < 0) {
+ SYSERRprintf("Cannot access unknown threshold trigger `%s'",
+ unknown_trigger);
+ exit(1);
+ }
+}
+
+void run_unknown_trigger(int socket, int cpu, struct mce *log)
+{
+ int ei = 0;
+ char *env[MAX_ENV];
+ int i;
+ char *msg;
+ char *location;
+
+ if (socket >= 0)
+ asprintf(&location, "CPU %d on socket %d", cpu, socket);
+ else
+ asprintf(&location, "CPU %d", cpu);
+ asprintf(&msg, "%s received unknown error", location);
+ asprintf(&env[ei++], "LOCATION=%s", location);
+ free(location);
+
+ if (!unknown_trigger)
+ goto out;
+
+ if (socket >= 0)
+ asprintf(&env[ei++], "SOCKETID=%d", socket);
+ asprintf(&env[ei++], "MESSAGE=%s", msg);
+ asprintf(&env[ei++], "CPU=%d", cpu);
+ asprintf(&env[ei++], "STATUS=%llx", log->status);
+ asprintf(&env[ei++], "MISC=%llx", log->misc);
+ asprintf(&env[ei++], "ADDR=%llx", log->addr);
+ asprintf(&env[ei++], "MCGSTATUS=%llx", log->mcgstatus);
+ asprintf(&env[ei++], "MCGCAP=%llx", log->mcgcap);
+ env[ei] = NULL;
+ assert(ei < MAX_ENV);
+
+ run_trigger(unknown_trigger, NULL, env);
+ for (i = 0; i < ei; i++)
+ free(env[i]);
+out:
+ free(msg);
+}
+
diff --git a/unknown.h b/unknown.h
new file mode 100644
index 0000000..0c6d876
--- /dev/null
+++ b/unknown.h
@@ -0,0 +1,2 @@
+void unknown_setup(void);
+void run_unknown_trigger(int socket, int cpu, struct mce *log);
diff --git a/yellow.c b/yellow.c
index 0f8ccd0..57978ee 100644
--- a/yellow.c
+++ b/yellow.c
@@ -90,6 +90,8 @@ void run_yellow_trigger(int cpu, int tnum, int lnum, char *ts, char *ls, int soc
asprintf(&env[ei++], "TYPE=%s", ts);
if (cache_to_cpus(cpu, lnum, tnum, &cpumasklen, &cpumask) >= 0)
env[ei++] = cpulist("AFFECTED_CPUS=", cpumask, cpumasklen);
+ else
+ asprintf(&env[ei++], "AFFECTED_CPUS=unknown");
env[ei] = NULL;
assert(ei < MAX_ENV);