Skip to content
This repository has been archived by the owner on Aug 5, 2022. It is now read-only.

Commit

Permalink
Add new software trigger for inject error command
Browse files Browse the repository at this point in the history
Add new inject error type ERROR_TYPE_DIRTY_SHUTDOWN in the API.
Add new inject error property DirtyShutdown=1 in the CLI.

Signed-off-by: Roy, Sunanda <[email protected]>
  • Loading branch information
Sunanda Roy authored and Juston Li committed Oct 18, 2017
1 parent ec60173 commit 66fa361
Show file tree
Hide file tree
Showing 8 changed files with 135 additions and 14 deletions.
45 changes: 44 additions & 1 deletion src/cli/features/core/ValidationFeature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ void cli::nvmcli::ValidationFeature::getPaths(cli::framework::CommandSpecList &l
injectError.addProperty(FATAL_MEDIA_ERROR_PROPERTYNAME, false, "1", true,
TR("Inject a fake media fatal error which will cause the firmware to generate an error log "
"and an alert."));
injectError.addProperty(DIRTY_SHUTDOWN_PROPERTYNAME, false, "1", true,
TR("Inject an ADR failure resulting in dirty shutdown upon reboot."));

list.push_back(injectError);
}
Expand All @@ -101,7 +103,7 @@ void cli::nvmcli::ValidationFeature::getPaths(cli::framework::CommandSpecList &l
cli::nvmcli::ValidationFeature::ValidationFeature() : cli::nvmcli::VerboseFeatureBase(),
m_dimmUid(""), m_poisontype(POISON_MEMORY_TYPE_PATROLSCRUB), m_temperature(0), m_poison(0), m_clearStateExists(false),
m_temperatureExists(false), m_poisonExists(false), m_poisonTypeExists(false), m_dieSparingExists(false),
m_spareAlarmExists(false), m_fatalMediaErrorExists(false)
m_spareAlarmExists(false), m_fatalMediaErrorExists(false), m_dirtyShutdownExists(false)
{ }

/*
Expand Down Expand Up @@ -170,6 +172,14 @@ void cli::nvmcli::ValidationFeature::inject_error(std::string &prefixMsg,
m_DimmProvider.injectSoftwareTrigger(*iUid, ERROR_TYPE_MEDIA_FATAL_ERROR);
listResult.insert(prefixMsg + cli::framework::SUCCESS_MSG);
}
else if (m_dirtyShutdownExists)
{
prefixMsg = framework::ResultBase::stringFromArgList(
SETDIRTYSHUTDOWN_MSG_PREFIX.c_str(), m_dimmUid.c_str());
prefixMsg += ": ";
m_DimmProvider.injectSoftwareTrigger(*iUid, ERROR_TYPE_DIRTY_SHUTDOWN);
listResult.insert(prefixMsg + cli::framework::SUCCESS_MSG);
}
}

void cli::nvmcli::ValidationFeature::clear_injected_error(std::string &prefixMsg,
Expand Down Expand Up @@ -199,6 +209,14 @@ void cli::nvmcli::ValidationFeature::clear_injected_error(std::string &prefixMsg
m_DimmProvider.clearSoftwareTrigger(*iUid, ERROR_TYPE_DIE_SPARING);
listResult.insert(prefixMsg + cli::framework::SUCCESS_MSG);
}
else if (m_dirtyShutdownExists)
{
prefixMsg = framework::ResultBase::stringFromArgList(
CLEARDIRTYSHUTDOWN_MSG_PREFIX.c_str(), m_dimmUid.c_str());
prefixMsg += ": ";
m_DimmProvider.clearSoftwareTrigger(*iUid, ERROR_TYPE_DIRTY_SHUTDOWN);
listResult.insert(prefixMsg + cli::framework::SUCCESS_MSG);
}
}

/*
Expand Down Expand Up @@ -433,6 +451,23 @@ cli::framework::ResultBase* cli::nvmcli::ValidationFeature::parseFatalMediaError
return pResult;
}

cli::framework::ResultBase* cli::nvmcli::ValidationFeature::parseDirtyShutdownProperty(
const framework::ParsedCommand& parsedCommand)
{
LogEnterExit logging(__FUNCTION__, __FILE__, __LINE__);
framework::ResultBase *pResult = NULL;

std::string propValue =
framework::Parser::getPropertyValue(parsedCommand, DIRTY_SHUTDOWN_PROPERTYNAME, &m_dirtyShutdownExists);
if (m_dirtyShutdownExists)
{
pResult = verifySWTriggerPropertyValue(propValue, DIRTY_SHUTDOWN_PROPERTYNAME);
}

return pResult;
}


cli::framework::ResultBase* cli::nvmcli::ValidationFeature::getInjectErrorAttributes(
const framework::ParsedCommand& parsedCommand)
{
Expand Down Expand Up @@ -464,6 +499,10 @@ cli::framework::ResultBase* cli::nvmcli::ValidationFeature::getInjectErrorAttrib
{
pResult = parseFatalMediaErrorProperty(parsedCommand);
}
if (!pResult)
{
pResult = parseDirtyShutdownProperty(parsedCommand);
}

if (!pResult)
{
Expand Down Expand Up @@ -499,6 +538,10 @@ cli::framework::ResultBase* cli::nvmcli::ValidationFeature::errorIfMoreThanOnePr
{
list.push_back(FATAL_MEDIA_ERROR_PROPERTYNAME);
}
if (m_dirtyShutdownExists)
{
list.push_back(DIRTY_SHUTDOWN_PROPERTYNAME);
}

if (list.size() > 1)
{
Expand Down
7 changes: 7 additions & 0 deletions src/cli/features/core/ValidationFeature.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,14 @@ static const std::string SETPOISON_MSG_PREFIX = N_TR("Poison address %llu on " N
static const std::string SETDIESPARING_MSG_PREFIX = N_TR("Trigger die sparing on " NVM_DIMM_NAME " %s");
static const std::string SETSPARECAPACITYALARM_MSG_PREFIX = N_TR("Trigger a spare capacity on " NVM_DIMM_NAME " %s");
static const std::string SETFATALERROR_MSG_PREFIX = N_TR("Create a media fatal error on " NVM_DIMM_NAME " %s");
static const std::string SETDIRTYSHUTDOWN_MSG_PREFIX = N_TR("Set dirty shutdown on " NVM_DIMM_NAME " %s");

static const std::string CLEARPOISON_MSG_PREFIX = N_TR("Clear poison of address %llu on " NVM_DIMM_NAME " %s");
static const std::string CLEARTEMPERATURE_MSG_PREFIX = N_TR("Clear injected temperature on " NVM_DIMM_NAME " %s");
static const std::string CLEARDIESPARING_MSG_PREFIX = N_TR("Clear injected die sparing on " NVM_DIMM_NAME " %s");
static const std::string CLEARSPARECAPACITYALARM_MSG_PREFIX = N_TR("Clear injected spare capacity alarm on " NVM_DIMM_NAME " %s");
static const std::string CLEARFATALERROR_MSG_PREFIX = N_TR("Clear injected media fatal error on " NVM_DIMM_NAME " %s");
static const std::string CLEARDIRTYSHUTDOWN_MSG_PREFIX = N_TR("Clear dirty shutdown on " NVM_DIMM_NAME " %s");

static std::string CLEAR_PROPERTYNAME = "Clear";
static std::string TEMPERATURE_PROPERTYNAME = "Temperature";
Expand All @@ -61,6 +63,7 @@ static std::string POISON_MEMORY_TYPE_PROPERTYNAME = "PoisonType";
static std::string DIE_SPARING_PROPERTYNAME = "DieSparing";
static std::string SPARE_ALARM_PROPERTYNAME = "SpareAlarm";
static std::string FATAL_MEDIA_ERROR_PROPERTYNAME = "FatalMediaError";
static std::string DIRTY_SHUTDOWN_PROPERTYNAME = "DirtyShutdown";

// memory type to poison strings
static std::string MEMORY_TYPE_STR_MEMORYMODE = "MemoryMode";
Expand Down Expand Up @@ -116,6 +119,7 @@ class NVM_API ValidationFeature : public cli::nvmcli::VerboseFeatureBase
bool m_dieSparingExists;
bool m_spareAlarmExists;
bool m_fatalMediaErrorExists;
bool m_dirtyShutdownExists;

/*
* Helper for inject error.
Expand Down Expand Up @@ -153,6 +157,9 @@ class NVM_API ValidationFeature : public cli::nvmcli::VerboseFeatureBase
cli::framework::ResultBase* parseFatalMediaErrorProperty(
const framework::ParsedCommand& parsedCommand);

cli::framework::ResultBase* parseDirtyShutdownProperty(
const framework::ParsedCommand& parsedCommand);

cli::framework::ResultBase* verifyPropertyCount(
const framework::ParsedCommand& parsedCommand);

Expand Down
34 changes: 23 additions & 11 deletions src/common/persistence/schema.c
Original file line number Diff line number Diff line change
Expand Up @@ -1927,15 +1927,17 @@ tables[populate_index++] = ((struct table){"software_trigger_info",
device_handle INTEGER PRIMARY KEY NOT NULL UNIQUE , \
die_sparing_trigger INTEGER , \
user_spare_block_alarm_trip_trigger INTEGER , \
fatal_error_trigger INTEGER \
fatal_error_trigger INTEGER , \
dirty_shutdown_trigger INTEGER \
);"});
tables[populate_index++] = ((struct table){"software_trigger_info_history",
"CREATE TABLE software_trigger_info_history ( \
history_id INTEGER NOT NULL, \
device_handle INTEGER , \
die_sparing_trigger INTEGER , \
user_spare_block_alarm_trip_trigger INTEGER , \
fatal_error_trigger INTEGER \
fatal_error_trigger INTEGER , \
dirty_shutdown_trigger INTEGER \
);"});
tables[populate_index++] = ((struct table){"performance",
"CREATE TABLE performance ( \
Expand Down Expand Up @@ -33127,6 +33129,7 @@ void local_bind_software_trigger_info(sqlite3_stmt *p_stmt, struct db_software_t
BIND_INTEGER(p_stmt, "$die_sparing_trigger", (unsigned int)p_software_trigger_info->die_sparing_trigger);
BIND_INTEGER(p_stmt, "$user_spare_block_alarm_trip_trigger", (unsigned int)p_software_trigger_info->user_spare_block_alarm_trip_trigger);
BIND_INTEGER(p_stmt, "$fatal_error_trigger", (unsigned int)p_software_trigger_info->fatal_error_trigger);
BIND_INTEGER(p_stmt, "$dirty_shutdown_trigger", (unsigned int)p_software_trigger_info->dirty_shutdown_trigger);
}
void local_get_software_trigger_info_relationships(const PersistentStore *p_ps,
sqlite3_stmt *p_stmt, struct db_software_trigger_info *p_software_trigger_info)
Expand Down Expand Up @@ -33154,26 +33157,31 @@ void local_row_to_software_trigger_info(const PersistentStore *p_ps,
INTEGER_COLUMN(p_stmt,
3,
p_software_trigger_info->fatal_error_trigger);
INTEGER_COLUMN(p_stmt,
4,
p_software_trigger_info->dirty_shutdown_trigger);
}
void db_print_software_trigger_info(struct db_software_trigger_info *p_value)
{
printf("software_trigger_info.device_handle: %u\n", p_value->device_handle);
printf("software_trigger_info.die_sparing_trigger: %u\n", p_value->die_sparing_trigger);
printf("software_trigger_info.user_spare_block_alarm_trip_trigger: %u\n", p_value->user_spare_block_alarm_trip_trigger);
printf("software_trigger_info.fatal_error_trigger: %u\n", p_value->fatal_error_trigger);
printf("software_trigger_info.dirty_shutdown_trigger: %u\n", p_value->dirty_shutdown_trigger);
}
enum db_return_codes db_add_software_trigger_info(const PersistentStore *p_ps,
struct db_software_trigger_info *p_software_trigger_info)
{
enum db_return_codes rc = DB_ERR_FAILURE;
sqlite3_stmt *p_stmt;
char *sql = "INSERT INTO software_trigger_info \
(device_handle, die_sparing_trigger, user_spare_block_alarm_trip_trigger, fatal_error_trigger) \
(device_handle, die_sparing_trigger, user_spare_block_alarm_trip_trigger, fatal_error_trigger, dirty_shutdown_trigger) \
VALUES \
($device_handle, \
$die_sparing_trigger, \
$user_spare_block_alarm_trip_trigger, \
$fatal_error_trigger) ";
$fatal_error_trigger, \
$dirty_shutdown_trigger) ";
int sql_rc;
if ((sql_rc = SQLITE_PREPARE(p_ps->db, sql, p_stmt)) == SQLITE_OK)
{
Expand Down Expand Up @@ -33211,9 +33219,10 @@ int db_get_software_trigger_infos(const PersistentStore *p_ps,
, die_sparing_trigger \
, user_spare_block_alarm_trip_trigger \
, fatal_error_trigger \
, dirty_shutdown_trigger \
\
FROM software_trigger_info \
\
\
\
";
sqlite3_stmt *p_stmt;
Expand Down Expand Up @@ -33265,12 +33274,13 @@ enum db_return_codes db_save_software_trigger_info_state(const PersistentStore *
{
sqlite3_stmt *p_stmt;
char *sql = "INSERT INTO software_trigger_info \
( device_handle , die_sparing_trigger , user_spare_block_alarm_trip_trigger , fatal_error_trigger ) \
( device_handle , die_sparing_trigger , user_spare_block_alarm_trip_trigger , fatal_error_trigger , dirty_shutdown_trigger ) \
VALUES \
($device_handle, \
$die_sparing_trigger, \
$user_spare_block_alarm_trip_trigger, \
$fatal_error_trigger) ";
$fatal_error_trigger, \
$dirty_shutdown_trigger) ";
int sql_rc;
if ((sql_rc = SQLITE_PREPARE(p_ps->db, sql, p_stmt)) == SQLITE_OK)
{
Expand All @@ -33297,12 +33307,13 @@ enum db_return_codes db_save_software_trigger_info_state(const PersistentStore *
sqlite3_stmt *p_stmt;
char *sql = "INSERT INTO software_trigger_info_history \
(history_id, \
device_handle, die_sparing_trigger, user_spare_block_alarm_trip_trigger, fatal_error_trigger) \
device_handle, die_sparing_trigger, user_spare_block_alarm_trip_trigger, fatal_error_trigger, dirty_shutdown_trigger) \
VALUES ($history_id, \
$device_handle , \
$die_sparing_trigger , \
$user_spare_block_alarm_trip_trigger , \
$fatal_error_trigger )";
$fatal_error_trigger , \
$dirty_shutdown_trigger )";
int sql_rc;
if ((sql_rc = SQLITE_PREPARE(p_ps->db, sql, p_stmt)) == SQLITE_OK)
{
Expand Down Expand Up @@ -33338,7 +33349,7 @@ enum db_return_codes db_get_software_trigger_info_by_device_handle(const Persist
enum db_return_codes rc = DB_ERR_FAILURE;
sqlite3_stmt *p_stmt;
char *sql = "SELECT \
device_handle, die_sparing_trigger, user_spare_block_alarm_trip_trigger, fatal_error_trigger \
device_handle, die_sparing_trigger, user_spare_block_alarm_trip_trigger, fatal_error_trigger, dirty_shutdown_trigger \
FROM software_trigger_info \
WHERE device_handle = $device_handle";
int sql_rc;
Expand Down Expand Up @@ -33379,6 +33390,7 @@ enum db_return_codes db_update_software_trigger_info_by_device_handle(const Pers
, die_sparing_trigger=$die_sparing_trigger \
, user_spare_block_alarm_trip_trigger=$user_spare_block_alarm_trip_trigger \
, fatal_error_trigger=$fatal_error_trigger \
, dirty_shutdown_trigger=$dirty_shutdown_trigger \
\
WHERE device_handle=$device_handle ";
int sql_rc;
Expand Down Expand Up @@ -33503,7 +33515,7 @@ int db_get_software_trigger_info_history_by_history_id(const PersistentStore *p_
memset(p_software_trigger_info, 0, sizeof (struct db_software_trigger_info) * software_trigger_info_count);
sqlite3_stmt *p_stmt;
char *sql = "SELECT \
device_handle, die_sparing_trigger, user_spare_block_alarm_trip_trigger, fatal_error_trigger \
device_handle, die_sparing_trigger, user_spare_block_alarm_trip_trigger, fatal_error_trigger, dirty_shutdown_trigger \
FROM software_trigger_info_history WHERE history_id = $history_id";
int sql_rc;
if ((sql_rc = SQLITE_PREPARE(p_ps->db, sql, p_stmt)) == SQLITE_OK)
Expand Down
1 change: 1 addition & 0 deletions src/common/persistence/schema.h
Original file line number Diff line number Diff line change
Expand Up @@ -11107,6 +11107,7 @@ struct db_software_trigger_info
unsigned int die_sparing_trigger;
unsigned int user_spare_block_alarm_trip_trigger;
unsigned int fatal_error_trigger;
unsigned int dirty_shutdown_trigger;
};
/*!
* Helper function to print a db_software_trigger_info to the screen.
Expand Down
1 change: 1 addition & 0 deletions src/common/persistence/schema.txt
Original file line number Diff line number Diff line change
Expand Up @@ -724,6 +724,7 @@ Attributes:
unsigned int die_sparing_trigger
unsigned int user_spare_block_alarm_trip_trigger
unsigned int fatal_error_trigger
unsigned int dirty_shutdown_trigger

Table(s): db_performance
Description: Monitor stored DIMM performance metrics.
Expand Down
38 changes: 38 additions & 0 deletions src/lib/error_injection.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ int inject_temperature_error(NVM_UINT32 device_handle, NVM_UINT64 temperature,
NVM_BOOL enable_injection);
int inject_software_trigger(struct device_discovery *p_discovery, enum error_type type,
NVM_BOOL enable_trigger);
int inject_dirty_shutdown_trigger(struct device_discovery * p_discovery, NVM_BOOL enable_trigger);

/*
* Helper function to enable/disable software trigger
Expand Down Expand Up @@ -131,6 +132,37 @@ int inject_temperature_error(NVM_UINT32 device_handle, NVM_UINT64 temperature,
return rc;
}

/*
* Helper function to inject dirty shutdown trigger
*/
int inject_dirty_shutdown_trigger(struct device_discovery *p_discovery, NVM_BOOL enable_trigger)
{
COMMON_LOG_ENTRY();
int rc = NVM_SUCCESS;

// Set up input payload
struct pt_payload_sw_triggers input;
memset(&input, 0, sizeof (input));
input.triggers_to_modify = 0x1 << 4; // unsafe shutdown trigger
input.unsafe_shutdown_trigger = enable_trigger;

struct fw_cmd cmd;
memset(&cmd, 0, sizeof (cmd));
cmd.device_handle = p_discovery->device_handle.handle;
cmd.opcode = PT_INJECT_ERROR;
cmd.sub_opcode = SUBOP_ERROR_SW_TRIGGERS;
cmd.input_payload = &input;
cmd.input_payload_size = sizeof (input);
rc = ioctl_passthrough_cmd(&cmd);
if (rc != NVM_SUCCESS)
{
COMMON_LOG_ERROR_F("Failed to trigger dirty shutdown trip on dimm %u", cmd.device_handle);
}

COMMON_LOG_EXIT_RETURN_I(rc);
return rc;
}

int verify_dimm_lock_state(enum lock_state lock_state)
{
int rc = NVM_SUCCESS;
Expand Down Expand Up @@ -235,6 +267,9 @@ int nvm_inject_device_error(const NVM_UID device_uid,
case ERROR_TYPE_POISON:
rc = inject_poison_error(&discovery, p_error->dpa, p_error->memory_type, 1);
break;
case ERROR_TYPE_DIRTY_SHUTDOWN:
rc = inject_dirty_shutdown_trigger(&discovery, 1);
break;
case ERROR_TYPE_DIE_SPARING:
case ERROR_TYPE_SPARE_ALARM:
case ERROR_TYPE_MEDIA_FATAL_ERROR:
Expand Down Expand Up @@ -292,6 +327,9 @@ int nvm_clear_injected_device_error(const NVM_UID device_uid,
case ERROR_TYPE_POISON:
rc = inject_poison_error(&discovery, p_error->dpa, p_error->memory_type, 0);
break;
case ERROR_TYPE_DIRTY_SHUTDOWN:
rc = inject_dirty_shutdown_trigger(&discovery, 0);
break;
case ERROR_TYPE_DIE_SPARING:
rc = inject_software_trigger(&discovery, p_error->type, 0);
break;
Expand Down
22 changes: 20 additions & 2 deletions src/lib/fis_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -1390,7 +1390,9 @@ struct pt_payload_sw_triggers {
* Bit 0: Die Spare Trigger
* Bit 1: Used Spare Block Alarm Trip Trigger
* Bit 2: Fatal Error Trigger
* Bit 63-3: Reserved
* Bit 3: Spare Block Percentage Trigger
* Bit 4: Unsafe Shutdown Trigger
* Bit 63-5: Reserved
*/
unsigned long long triggers_to_modify;

Expand All @@ -1417,7 +1419,23 @@ struct pt_payload_sw_triggers {
*/
unsigned char fatal_error_trigger;

unsigned char reserved_1[116];
/*
* Spoofs spare block percentage within the DIMM.
* Bit 0 - Enable/Disable Trigger
* 0x0h - Do Not/Disable Trigger
* 0x1h - Enable Trigger
* Bits 7:1 - Spare Block Percentage (valid values are between 0 and 100)
*/
unsigned char spare_block_percentage_trigger;

/*
* Spoofs an unsafe shutdown on the next power cycle.
* 0x0h - Do Not/Disable Trigger
* 0x1h - Enable Trigger
*/
unsigned char unsafe_shutdown_trigger;

unsigned char reserved_1[114];
} __attribute__((packed));

/*
Expand Down
1 change: 1 addition & 0 deletions src/lib/nvm_management.h
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@ enum error_type
ERROR_TYPE_DIE_SPARING = 3, // Trigger or revert an artificial die sparing.
ERROR_TYPE_SPARE_ALARM = 4, // Trigger or clear a spare capacity threshold alarm.
ERROR_TYPE_MEDIA_FATAL_ERROR = 5, // Inject or clear a fake media fatal error.
ERROR_TYPE_DIRTY_SHUTDOWN = 6, // Inject or clear a dirty shutdown error.
};

/*
Expand Down

0 comments on commit 66fa361

Please sign in to comment.