meta-facebook/meta-fby2/recipes-fby2/plat-utils/files/enclosure-util/enclosure-util.c (548 lines of code) (raw):

/* * enclosure-util * Copyright 2015-present Facebook. All Rights Reserved. * * This program 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; either version 2 of the License, or * (at your option) any later version. * * This program 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 have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <stdio.h> #include <stdint.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <signal.h> #include <syslog.h> #include <string.h> #include <openbmc/nvme-mi.h> #include <openbmc/pal.h> #define MAX_DRIVE_NUM 2 #define MAX_GP_DRIVE_NUM 6 #define MAX_GPV2_DRIVE_NUM 12 #define CMD_DRIVE_STATUS 0 #define CMD_DRIVE_HEALTH 1 #define MAX_SERIAL_NUM 20 #define MAX_PART_NUM 40 #define I2C_DEV_GP_1 "/dev/i2c-1" #define I2C_DEV_GP_3 "/dev/i2c-5" #define I2C_GP_MUX_ADDR 0x71 /* NVMe-MI SSD Status Flag bit mask */ #define NVME_SFLGS_MASK_BIT 0x28 // check bit 5,3 /* NVMe-MI SSD SMART Critical Warning */ #define NVME_SMART_WARNING_MASK_BIT 0x1F // check bit 0~4 #define SPRINGHILL_M2_OFFSET_BASE 1 // one byte for FBID #define NVME_BAD_HEALTH 1 static uint8_t m_slot_id = 0; static uint8_t m_slot_type = 0xFF; static void print_usage_help(void) { printf("Usage: enclosure-util <slot1|slot2|slot3|slot4> --drive-status <number, all>\n"); printf(" enclosure-util <slot1|slot2|slot3|slot4> --drive-health\n"); } static int drive_status(ssd_data *ssd) { t_status_flags status_flag_decoding; t_smart_warning smart_warning_decoding; t_key_value_pair temp_decoding; t_key_value_pair pdlu_decoding; t_key_value_pair vendor_decoding; t_key_value_pair sn_decoding; t_key_value_pair pn_decoding; t_key_value_pair meff_decoding; t_key_value_pair ffi_0_decoding; t_key_value_pair sinfo_0_decoding; t_key_value_pair module_helath_decoding; t_key_value_pair lower_thermal_temp_decoding; t_key_value_pair upper_thermal_temp_decoding; t_key_value_pair power_state_decoding; t_key_value_pair i2c_freq_decoding; t_key_value_pair tdp_level_decoding; t_key_value_pair asic_version_decoding; t_key_value_pair fw_version_decoding; t_key_value_pair asic_core_vol1_decoding; t_key_value_pair asic_core_vol2_decoding; t_key_value_pair power_rail_vol1_decoding; t_key_value_pair power_rail_vol2_decoding; t_key_value_pair asic_error_type_decoding; t_key_value_pair module_error_type_decoding; t_key_value_pair warning_flag_decoding; t_key_value_pair interrupt_flag_decoding; t_key_value_pair max_asic_temp_decoding; t_key_value_pair total_int_mem_err_count_decoding; t_key_value_pair total_ext_mem_err_count_decoding; t_key_value_pair smbus_err_decoding; nvme_vendor_decode(ssd->vendor, &vendor_decoding); printf("%s: %s\n", vendor_decoding.key, vendor_decoding.value); nvme_serial_num_decode(ssd->serial_num, &sn_decoding); printf("%s: %s\n", sn_decoding.key, sn_decoding.value); nvme_temp_decode(ssd->temp, &temp_decoding); printf("%s: %s\n", temp_decoding.key, temp_decoding.value); nvme_pdlu_decode(ssd->pdlu, &pdlu_decoding); printf("%s: %s\n", pdlu_decoding.key, pdlu_decoding.value); nvme_sflgs_decode(ssd->sflgs, &status_flag_decoding); #if defined(CONFIG_FBY2_GPV2) if (ssd->vendor == VENDOR_ID_INTEL) { sprintf(status_flag_decoding.read_complete.value, "NA"); sprintf(status_flag_decoding.functional.value, "NA"); sprintf(status_flag_decoding.reset_required.value, "NA"); sprintf(status_flag_decoding.port0_link.value, "NA"); sprintf(status_flag_decoding.port1_link.value, "NA"); } #endif printf("%s: %s\n", status_flag_decoding.self.key, status_flag_decoding.self.value); printf(" %s: %s\n", status_flag_decoding.read_complete.key, status_flag_decoding.read_complete.value); printf(" %s: %s\n", status_flag_decoding.ready.key, status_flag_decoding.ready.value); printf(" %s: %s\n", status_flag_decoding.functional.key, status_flag_decoding.functional.value); printf(" %s: %s\n", status_flag_decoding.reset_required.key, status_flag_decoding.reset_required.value); printf(" %s: %s\n", status_flag_decoding.port0_link.key, status_flag_decoding.port0_link.value); printf(" %s: %s\n", status_flag_decoding.port1_link.key, status_flag_decoding.port1_link.value); nvme_smart_warning_decode(ssd->warning, &smart_warning_decoding); printf("%s: %s\n", smart_warning_decoding.self.key, smart_warning_decoding.self.value); printf(" %s: %s\n", smart_warning_decoding.spare_space.key, smart_warning_decoding.spare_space.value); printf(" %s: %s\n", smart_warning_decoding.temp_warning.key, smart_warning_decoding.temp_warning.value); printf(" %s: %s\n", smart_warning_decoding.reliability.key, smart_warning_decoding.reliability.value); printf(" %s: %s\n", smart_warning_decoding.media_status.key, smart_warning_decoding.media_status.value); printf(" %s: %s\n", smart_warning_decoding.backup_device.key, smart_warning_decoding.backup_device.value); if (ssd->fb_defined == 0x01) { nvme_part_num_decode(ssd->block_len_module_id_area, ssd->part_num, &pn_decoding); printf("%s: %s\n", pn_decoding.key, pn_decoding.value); nvme_meff_decode(ssd->block_len_module_id_area, ssd->meff, &meff_decoding); printf("%s: %s\n", meff_decoding.key, meff_decoding.value); nvme_ffi_0_decode(ssd->block_len_module_id_area, ssd->ffi_0, &ffi_0_decoding); printf("%s: %s\n", ffi_0_decoding.key, ffi_0_decoding.value); if (ssd->ffi_0 == FFI_0_ACCELERATOR) { nvme_raw_data_prase("Module health", ssd->block_len_module_stat_area, ssd->module_helath, &module_helath_decoding); printf("%s: %s\n", module_helath_decoding.key, module_helath_decoding.value); nvme_lower_threshold_temp_decode(ssd->block_len_module_stat_area, ssd->lower_theshold, &lower_thermal_temp_decoding); printf("%s: %s\n", lower_thermal_temp_decoding.key, lower_thermal_temp_decoding.value); nvme_upper_threshold_temp_decode(ssd->block_len_module_stat_area, ssd->upper_threshold, &upper_thermal_temp_decoding); printf("%s: %s\n", upper_thermal_temp_decoding.key, upper_thermal_temp_decoding.value); nvme_power_state_decode(ssd->block_len_module_stat_area, ssd->power_state, &power_state_decoding); printf("%s: %s\n", power_state_decoding.key, power_state_decoding.value); nvme_i2c_freq_decode (ssd->block_len_module_stat_area, ssd->i2c_freq, &i2c_freq_decoding); printf("%s: %s\n", i2c_freq_decoding.key, i2c_freq_decoding.value); nvme_tdp_level_decode (ssd->block_len_module_stat_area, ssd->tdp_level, &tdp_level_decoding); printf("%s: %s\n", tdp_level_decoding.key, tdp_level_decoding.value); nvme_raw_data_prase("ASIC version", ssd->block_len_ver_area, ssd->asic_version, &asic_version_decoding); printf("%s: %s\n", asic_version_decoding.key, asic_version_decoding.value); nvme_fw_version_decode(ssd->block_len_ver_area, ssd->fw_major_ver, ssd->fw_minor_ver, &fw_version_decoding); printf("%s: %s\n", fw_version_decoding.key, fw_version_decoding.value); nvme_monitor_area_decode("ASIC Core1 Voltage", ssd->block_len_mon_area, ssd->asic_core_vol1, ASIC_CORE_VOL_UNIT, &asic_core_vol1_decoding); printf("%s: %s\n", asic_core_vol1_decoding.key, asic_core_vol1_decoding.value); nvme_monitor_area_decode("ASIC Core2 Voltage", ssd->block_len_mon_area, ssd->asic_core_vol2, ASIC_CORE_VOL_UNIT, &asic_core_vol2_decoding); printf("%s: %s\n", asic_core_vol2_decoding.key, asic_core_vol2_decoding.value); nvme_monitor_area_decode("Module Power Rail1 Voltage", ssd->block_len_mon_area, ssd->power_rail_vol1, POWER_RAIL_VOL_UNIT, &power_rail_vol1_decoding); printf("%s: %s\n", power_rail_vol1_decoding.key, power_rail_vol1_decoding.value); nvme_monitor_area_decode("Module Power Rail2 Voltage", ssd->block_len_mon_area, ssd->power_rail_vol2, POWER_RAIL_VOL_UNIT, &power_rail_vol2_decoding); printf("%s: %s\n", power_rail_vol2_decoding.key, power_rail_vol2_decoding.value); nvme_raw_data_prase("ASIC Error Type Report", ssd->block_len_err_ret_area, ssd->asic_error_type, &asic_error_type_decoding); printf("%s: %s\n", asic_error_type_decoding.key, asic_error_type_decoding.value); nvme_raw_data_prase("Module Error Type Report", ssd->block_len_err_ret_area, ssd->module_error_type, &module_error_type_decoding); printf("%s: %s\n", module_error_type_decoding.key, module_error_type_decoding.value); nvme_raw_data_prase("Warning Flag", ssd->block_len_err_ret_area, ssd->warning_flag, &warning_flag_decoding); printf("%s: %s\n", warning_flag_decoding.key, warning_flag_decoding.value); nvme_raw_data_prase("Interrupt Flag", ssd->block_len_err_ret_area, ssd->interrupt_flag, &interrupt_flag_decoding); printf("%s: %s\n", interrupt_flag_decoding.key, interrupt_flag_decoding.value); nvme_max_asic_temp_decode(ssd->block_len_err_ret_area, ssd->max_asic_temp, &max_asic_temp_decoding); printf("%s: %s\n", max_asic_temp_decoding.key, max_asic_temp_decoding.value); nvme_total_int_mem_err_count_decode(ssd->block_len_err_ret_area, ssd->total_int_mem_err_count, &total_int_mem_err_count_decoding); printf("%s: %s\n", total_int_mem_err_count_decoding.key, total_int_mem_err_count_decoding.value); nvme_total_ext_mem_err_count_decode(ssd->block_len_err_ret_area, ssd->total_ext_mem_err_count, &total_ext_mem_err_count_decoding); printf("%s: %s\n", total_ext_mem_err_count_decoding.key, total_ext_mem_err_count_decoding.value); nvme_smbus_err_decode(ssd->block_len_err_ret_area, ssd->smbus_err, &smbus_err_decoding); printf("%s: %s\n", smbus_err_decoding.key, smbus_err_decoding.value); } else if (ssd->ffi_0 == FFI_0_STORAGE) { printf("%s: 0x%02X\n", "Storage version", ssd->ssd_ver); printf("%s: %d GB\n", "Storage Capacity", ssd->ssd_capacity); printf("%s: %d W\n", "Storage Power", ssd->ssd_pwr); nvme_sinfo_0_decode (ssd->ssd_sinfo_0,&sinfo_0_decoding); printf("%s: %s\n", sinfo_0_decoding.key, sinfo_0_decoding.value); } } return 0; } static int drive_health(ssd_data *ssd) { if (ssd->fb_defined != 0x01 || ssd->ffi_0 != FFI_0_ACCELERATOR) { // since accelerator doesn't implement SMART WARNING, do not check it. if ((ssd->warning & NVME_SMART_WARNING_MASK_BIT) != NVME_SMART_WARNING_MASK_BIT) return NVME_BAD_HEALTH; } if ((ssd->sflgs & NVME_SFLGS_MASK_BIT) != NVME_SFLGS_MASK_BIT) return NVME_BAD_HEALTH; return 0; } static int read_bic_nvme_data(uint8_t slot_id, uint8_t drv_num, uint8_t cmd) { int ret = 0, offset_base = 0; int rlen = 0; float tdp_val = 0; uint8_t bus, wbuf[8], rbuf[64]; char stype_str[32] = {0}; ssd_data ssd; if (m_slot_type == SLOT_TYPE_SERVER) { bus = 0x3; wbuf[0] = 1 << (drv_num - 1); sprintf(stype_str, "Server Board"); } else { // SLOT_TYPE_GPV2 bus = (2 + drv_num/2) * 2 + 1; wbuf[0] = 1 << (drv_num%2); sprintf(stype_str, "Glacier Point V2"); } // MUX ret = bic_master_write_read(slot_id, bus, 0xe2, wbuf, 1, rbuf, 0); if (ret != 0) { syslog(LOG_DEBUG, "%s(): bic_master_write_read failed", __func__); return ret; } if (cmd == CMD_DRIVE_STATUS) { memset(&ssd, 0x00, sizeof(ssd_data)); printf("%s %u Drive%d\n", stype_str, slot_id, drv_num); do { wbuf[0] = 0x00; // offset 00 rlen = 8; ret = bic_master_write_read(slot_id, bus, 0xd4, wbuf, 1, rbuf, rlen); if (ret != 0) { syslog(LOG_DEBUG, "%s(): bic_master_write_read offset=%d read length=%d failed", __func__,wbuf[0],rlen); break; } // Judge whether this device is SpringHill M.2. via FBID. // TODO: If SpringHill M.2. can follow NVMe-MI I2C transaction, we will remove this judgement. if (rbuf[0] == wbuf[0]) { offset_base = SPRINGHILL_M2_OFFSET_BASE; } ssd.sflgs = rbuf[offset_base + 1]; ssd.warning = rbuf[offset_base + 2]; ssd.temp = rbuf[offset_base + 3]; ssd.pdlu = rbuf[offset_base + 4]; wbuf[0] = 0x08; // offset 08 rlen = 24 + offset_base; ret = bic_master_write_read(slot_id, bus, 0xd4, wbuf, 1, rbuf, rlen); if (ret != 0) { syslog(LOG_DEBUG, "%s(): bic_master_write_read offset=%d read length=%d failed", __func__,wbuf[0],rlen); break; } ssd.vendor = (rbuf[offset_base + 1] << 8) | rbuf[offset_base + 2]; memcpy(ssd.serial_num, &rbuf[offset_base + 3], MAX_SERIAL_NUM); if (m_slot_type == SLOT_TYPE_GPV2) { wbuf[0] = 0x20; // offset 32 rlen = 55 + offset_base; ret = bic_master_write_read(slot_id, bus, 0xd4, wbuf, 1, rbuf, rlen); if (ret != 0) { syslog(LOG_DEBUG, "%s(): bic_master_write_read offset=%d read length=%d failed", __func__,wbuf[0],rlen); break; } ssd.block_len_module_id_area = rbuf[offset_base + 0]; ssd.fb_defined = rbuf[offset_base + 1]; memcpy(ssd.part_num, &rbuf[offset_base + 2], MAX_PART_NUM); ssd.meff = rbuf[offset_base + 42]; ssd.ffi_0 = rbuf[offset_base + 43]; if (ssd.fb_defined == 1) { if (ssd.ffi_0 == FFI_0_ACCELERATOR) { wbuf[0] = 0x60; // offset 96 rlen = 8 + offset_base; ret = bic_master_write_read(slot_id, bus, 0xd4, wbuf, 1, rbuf, rlen); if (ret != 0) { syslog(LOG_DEBUG, "%s(): bic_master_write_read offset=%d read length=%d failed", __func__,wbuf[0],rlen); break; } ssd.block_len_module_stat_area = rbuf[offset_base + 0]; ssd.module_helath = rbuf[offset_base + 1]; ssd.lower_theshold = rbuf[offset_base + 2]; ssd.upper_threshold = rbuf[offset_base + 3]; ssd.power_state = rbuf[offset_base + 4]; ssd.i2c_freq = rbuf[offset_base + 5]; // Formula provided by SPH if (ssd.vendor == VENDOR_ID_INTEL) { tdp_val = rbuf[offset_base + 7] + rbuf[offset_base + 6] / 250; if (tdp_val > 13) { ssd.tdp_level = TDP_LEVEL3; } else if (tdp_val >= 10.5) { ssd.tdp_level = TDP_LEVEL2; } else { ssd.tdp_level = TDP_LEVEL1; } } else { ssd.tdp_level = rbuf[offset_base + 6]; } wbuf[0] = 0x68; // offset 104 rlen = 8 + offset_base; ret = bic_master_write_read(slot_id, bus, 0xd4, wbuf, 1, rbuf, rlen); if (ret != 0) { syslog(LOG_DEBUG, "%s(): bic_master_write_read offset=%d read length=%d failed", __func__,wbuf[0],rlen); break; } ssd.block_len_ver_area = rbuf[offset_base + 0]; ssd.asic_version = rbuf[offset_base + 1]; ssd.fw_major_ver = rbuf[offset_base + 2]; ssd.fw_minor_ver = rbuf[offset_base + 3]; wbuf[0] = 0x70; // offset 112 rlen = 10 + offset_base; ret = bic_master_write_read(slot_id, bus, 0xd4, wbuf, 1, rbuf, rlen); if (ret != 0) { syslog(LOG_DEBUG, "%s(): bic_master_write_read offset=%d read length=%d failed", __func__,wbuf[0],rlen); break; } ssd.block_len_mon_area = rbuf[offset_base + 0]; ssd.asic_core_vol1 = (rbuf[offset_base + 1] << 8) | rbuf[offset_base + 2]; ssd.asic_core_vol2 = (rbuf[offset_base + 3] << 8) | rbuf[offset_base + 4]; ssd.power_rail_vol1 = (rbuf[offset_base + 5] << 8) | rbuf[offset_base + 6]; ssd.power_rail_vol2 = (rbuf[offset_base + 7] << 8) | rbuf[offset_base + 8]; wbuf[0] = 0x7A; // offset 122 rlen = 10 + offset_base; ret = bic_master_write_read(slot_id, bus, 0xd4, wbuf, 1, rbuf, rlen); if (ret != 0) { syslog(LOG_DEBUG, "%s(): bic_master_write_read offset=%d read length=%d failed", __func__,wbuf[0],rlen); break; } ssd.block_len_err_ret_area = rbuf[offset_base + 0]; ssd.asic_error_type = rbuf[offset_base + 1]; ssd.module_error_type = rbuf[offset_base + 2]; ssd.warning_flag = rbuf[offset_base + 3]; ssd.interrupt_flag = rbuf[offset_base + 4]; ssd.max_asic_temp = rbuf[offset_base + 5]; ssd.total_int_mem_err_count = rbuf[offset_base + 6]; ssd.total_ext_mem_err_count = rbuf[offset_base + 7]; ssd.smbus_err = rbuf[offset_base + 8]; } else if (ssd.ffi_0 == FFI_0_STORAGE) { wbuf[0] = 0x57; // offset 87 rlen = 9; ret = bic_master_write_read(slot_id, bus, 0xd4, wbuf, 1, rbuf, rlen); if (ret != 0) { syslog(LOG_DEBUG, "%s(): bic_master_write_read offset=%d read length=%d failed", __func__,wbuf[0],rlen); break; } ssd.ssd_ver = rbuf[1]; ssd.ssd_capacity = (rbuf[2] << 8) | rbuf[3]; ssd.ssd_pwr = rbuf[4]; ssd.ssd_sinfo_0 = rbuf[5]; } } } drive_status(&ssd); } while (0); printf("\n"); return ret; } else if (cmd == CMD_DRIVE_HEALTH) { memset(&ssd, 0x00, sizeof(ssd_data)); wbuf[0] = 0x00; // offset 00 ret = bic_master_write_read(slot_id, bus, 0xd4, wbuf, 1, rbuf, 8); if (ret != 0) { syslog(LOG_DEBUG, "%s(): bic_master_write_read failed", __func__); return ret; } // Judge whether this device is SpringHill M.2. via FBID. // TODO: If SpringHill M.2. can follow NVMe-MI I2C transaction, we will remove this judgement. if (rbuf[1] == wbuf[0]) { offset_base = SPRINGHILL_M2_OFFSET_BASE; } ssd.sflgs = rbuf[offset_base + 1]; ssd.warning = rbuf[offset_base + 2]; if (m_slot_type == SLOT_TYPE_GPV2) { wbuf[0] = 0x20; // offset 32 rlen = 55 + offset_base; ret = bic_master_write_read(slot_id, bus, 0xd4, wbuf, 1, rbuf, rlen); if (ret != 0) { syslog(LOG_DEBUG, "%s(): bic_master_write_read offset=%d read length=%d failed", __func__,wbuf[0],rlen); return ret; } ssd.fb_defined = rbuf[offset_base + 1]; ssd.ffi_0 = rbuf[offset_base + 43]; } else { ssd.fb_defined = 0; ssd.ffi_0 = 0; } ret = drive_health(&ssd); return ret; } else { syslog(LOG_DEBUG, "%s(): unknown cmd", __func__); return -1; } return 0; } static int read_gp_nvme_data(uint8_t slot_id, uint8_t drv_num, uint8_t cmd) { int ret = 0; uint8_t channel = 0; char *device; ssd_data ssd; // MUX switch (drv_num) { case 0: channel = MUX_CH_1; break; case 1: channel = MUX_CH_0; break; case 2: channel = MUX_CH_4; break; case 3: channel = MUX_CH_3; break; case 4: channel = MUX_CH_2; break; case 5: channel = MUX_CH_5; break; default: return -1; } device = (slot_id == 1) ? I2C_DEV_GP_1 : I2C_DEV_GP_3; ret = fby2_mux_control(device, I2C_GP_MUX_ADDR, channel); if (ret != 0) { syslog(LOG_DEBUG, "%s: fby2_mux_control failed", __func__); return ret; } if (cmd == CMD_DRIVE_STATUS) { memset(&ssd, 0x00, sizeof(ssd_data)); printf("Glacier Point %u Drive%d\n", slot_id, drv_num); do { ret = nvme_sflgs_read(device, &ssd.sflgs); if (ret != 0) { syslog(LOG_DEBUG, "%s(): nvme_sflgs_read failed", __func__); break; } ret = nvme_smart_warning_read(device, &ssd.warning); if (ret != 0) { syslog(LOG_DEBUG, "%s(): nvme_smart_warning_read failed", __func__); break; } ret = nvme_temp_read(device, &ssd.temp); if (ret != 0) { syslog(LOG_DEBUG, "%s(): nvme_temp_read failed", __func__); break; } ret = nvme_pdlu_read(device, &ssd.pdlu); if (ret != 0) { syslog(LOG_DEBUG, "%s(): nvme_pdlu_read failed", __func__); break; } ret = nvme_vendor_read(device, &ssd.vendor); if (ret != 0) { syslog(LOG_DEBUG, "%s(): nvme_vendor_read failed", __func__); break; } ret = nvme_serial_num_read(device, ssd.serial_num, MAX_SERIAL_NUM); if (ret != 0) { syslog(LOG_DEBUG, "%s(): nvme_serial_num_read failed", __func__); break; } drive_status(&ssd); } while (0); printf("\n"); return ret; } else if (cmd == CMD_DRIVE_HEALTH) { memset(&ssd, 0x00, sizeof(ssd_data)); if (nvme_sflgs_read(device, &ssd.sflgs)) { syslog(LOG_DEBUG, "%s(): nvme_sflgs_read failed", __func__); return -1; } if (nvme_smart_warning_read(device, &ssd.warning)) { syslog(LOG_DEBUG, "%s(): nvme_smart_warning_read failed", __func__); return -1; } ret = drive_health(&ssd); return ret; } else { syslog(LOG_DEBUG, "%s(): unknown cmd", __func__); return -1; } return 0; } static void ssd_monitor_enable(uint8_t slot_id, uint8_t slot_type, uint8_t en) { if ((slot_type == SLOT_TYPE_SERVER) || (slot_type == SLOT_TYPE_GPV2)) { if (en) { // enable sensor monitor bic_disable_sensor_monitor(slot_id, 0); } else { // disable sensor monitor bic_disable_sensor_monitor(slot_id, 1); msleep(100); } } else if (slot_type == SLOT_TYPE_GP) { if (en) { // enable sensor monitor fby2_disable_gp_m2_monior(slot_id, 0); } else { // disable sensor monitor fby2_disable_gp_m2_monior(slot_id, 1); msleep(100); } } } static void enclosure_sig_handler(int sig) { if (m_slot_id) { ssd_monitor_enable(m_slot_id, m_slot_type, 1); } } int main(int argc, char **argv) { int ret; uint8_t slot_id, slot_type = 0xFF; uint8_t i, drv_start = 1, drv_end = MAX_DRIVE_NUM; char *end = NULL; int (*read_nvme_data)(uint8_t,uint8_t,uint8_t); struct sigaction sa; if (argc < 3) { print_usage_help(); return -1; } if (!strcmp(argv[1], "slot1")) { slot_id = 1; } else if (!strcmp(argv[1] , "slot2")) { slot_id = 2; } else if (!strcmp(argv[1] , "slot3")) { slot_id = 3; } else if (!strcmp(argv[1] , "slot4")) { slot_id = 4; } else { print_usage_help(); return -1; } slot_type = fby2_get_slot_type(slot_id); if (slot_type == SLOT_TYPE_SERVER) { drv_start = 1; // 1-based drv_end = MAX_DRIVE_NUM; read_nvme_data = read_bic_nvme_data; } else if (slot_type == SLOT_TYPE_GP) { drv_start = 0; // 0-based drv_end = MAX_GP_DRIVE_NUM - 1; read_nvme_data = read_gp_nvme_data; } else if (slot_type == SLOT_TYPE_GPV2) { drv_start = 0; // 0-based drv_end = MAX_GPV2_DRIVE_NUM - 1; read_nvme_data = read_bic_nvme_data; } else { return -1; } m_slot_type = slot_type; m_slot_id = slot_id; sa.sa_handler = enclosure_sig_handler; sa.sa_flags = 0; sigemptyset(&sa.sa_mask); sigaction(SIGHUP, &sa, NULL); sigaction(SIGINT, &sa, NULL); sigaction(SIGQUIT, &sa, NULL); sigaction(SIGSEGV, &sa, NULL); sigaction(SIGTERM, &sa, NULL); if ((argc == 4) && !strcmp(argv[2], "--drive-status")) { if (!strcmp(argv[3], "all")) { ssd_monitor_enable(slot_id, slot_type, 0); for (i = drv_start; i <= drv_end; i++) { read_nvme_data(slot_id, i, CMD_DRIVE_STATUS); } ssd_monitor_enable(slot_id, slot_type, 1); } else { errno = 0; ret = strtol(argv[3], &end, 0); if (errno || *end || (ret < drv_start) || (ret > drv_end)) { print_usage_help(); return -1; } ssd_monitor_enable(slot_id, slot_type, 0); read_nvme_data(slot_id, (uint8_t)ret, CMD_DRIVE_STATUS); ssd_monitor_enable(slot_id, slot_type, 1); } } else if ((argc == 3) && !strcmp(argv[2], "--drive-health")) { ssd_monitor_enable(slot_id, slot_type, 0); for (i = drv_start; i <= drv_end; i++) { ret = read_nvme_data(slot_id, i, CMD_DRIVE_HEALTH); printf("M.2-%u: %s\n", i, (ret == 0)?"Normal":((ret == NVME_BAD_HEALTH)?"Abnormal":"NA")); } ssd_monitor_enable(slot_id, slot_type, 1); } else { print_usage_help(); return -1; } return 0; }