blob: bdbacd013b6f92340c6fe3ecb58e77117c8cfa72 [file] [log] [blame]
Tony Lee84d430c2019-06-13 15:26:15 +08001#include "nvme_manager.hpp"
2
Tony Lee6c595012019-06-19 10:54:59 +08003#include "smbus.hpp"
4
5#include <filesystem>
6#include <map>
7#include <nlohmann/json.hpp>
Tony Lee84d430c2019-06-13 15:26:15 +08008#include <phosphor-logging/elog-errors.hpp>
9#include <phosphor-logging/log.hpp>
Tony Lee89659212019-06-21 17:34:14 +080010#include <sdbusplus/message.hpp>
Tony Lee6c595012019-06-19 10:54:59 +080011#include <sstream>
12#include <string>
Tony Lee89659212019-06-21 17:34:14 +080013#include <xyz/openbmc_project/Led/Physical/server.hpp>
Tony Lee84d430c2019-06-13 15:26:15 +080014
Tony Lee6c595012019-06-19 10:54:59 +080015#include "i2c.h"
Tony Lee84d430c2019-06-13 15:26:15 +080016#define MONITOR_INTERVAL_SECONDS 1
Tony Lee6c595012019-06-19 10:54:59 +080017#define NVME_SSD_SLAVE_ADDRESS 0x6a
George Hung92a15ba2020-09-14 17:14:52 +080018#define NVME_SSD_VPD_SLAVE_ADDRESS 0x53
Tony Lee6c595012019-06-19 10:54:59 +080019#define GPIO_BASE_PATH "/sys/class/gpio/gpio"
20#define IS_PRESENT "0"
21#define POWERGD "1"
Tony Lee89659212019-06-21 17:34:14 +080022#define NOWARNING_STRING "ff"
Tony Lee6c595012019-06-19 10:54:59 +080023
24static constexpr auto configFile = "/etc/nvme/nvme_config.json";
25static constexpr auto delay = std::chrono::milliseconds{100};
26using Json = nlohmann::json;
27
28static constexpr const uint8_t COMMAND_CODE_0 = 0;
29static constexpr const uint8_t COMMAND_CODE_8 = 8;
George Hung92a15ba2020-09-14 17:14:52 +080030static constexpr const uint8_t CODE_0_LENGTH = 8;
31static constexpr const uint8_t CODE_8_LENGTH = 23;
Tony Lee6c595012019-06-19 10:54:59 +080032
Tony Lee89659212019-06-21 17:34:14 +080033static constexpr int CapacityFaultMask = 1;
34static constexpr int temperatureFaultMask = 1 << 1;
35static constexpr int DegradesFaultMask = 1 << 2;
36static constexpr int MediaFaultMask = 1 << 3;
37static constexpr int BackupDeviceFaultMask = 1 << 4;
38static constexpr int NOWARNING = 255;
39
Tony Lee6c595012019-06-19 10:54:59 +080040static constexpr int SERIALNUMBER_START_INDEX = 3;
41static constexpr int SERIALNUMBER_END_INDEX = 23;
George Hung92a15ba2020-09-14 17:14:52 +080042static constexpr int MODELNUMBER_START_INDEX = 46;
43static constexpr int MODELNUMBER_END_INDEX = 85;
Tony Lee6c595012019-06-19 10:54:59 +080044
45static constexpr const int TEMPERATURE_SENSOR_FAILURE = 0x81;
46
Brandon Kim8353c5f2022-07-08 17:09:23 -070047static std::map<std::string, std::string> map_vendor = {
48 {"80 86", "Intel"}, {"1e f", "Kioxia"}, {"14 4d", "Samsung"}};
George Hung69b96182020-08-20 17:19:56 +080049
Tony Lee6c595012019-06-19 10:54:59 +080050namespace fs = std::filesystem;
51
Tony Lee84d430c2019-06-13 15:26:15 +080052namespace phosphor
53{
54namespace nvme
55{
56
57using namespace std;
58using namespace phosphor::logging;
59
Tony Lee89659212019-06-21 17:34:14 +080060void Nvme::setNvmeInventoryProperties(
Chanh Nguyene528b0a2021-07-14 16:57:57 +070061 NVMeConfig& config, bool present,
62 const phosphor::nvme::Nvme::NVMeData& nvmeData,
Tony Lee89659212019-06-21 17:34:14 +080063 const std::string& inventoryPath)
64{
Chanh Nguyene528b0a2021-07-14 16:57:57 +070065 static std::unordered_map<int, std::string> preSerial;
66 static std::unordered_map<int, std::string> preSmartWarning;
67 static std::unordered_map<int, std::string> preStatusFlags;
Tony Lee89659212019-06-21 17:34:14 +080068
Chanh Nguyene528b0a2021-07-14 16:57:57 +070069 if (preSerial[config.busID].compare(nvmeData.serialNumber) != 0)
70 {
71 util::SDBusPlus::setProperty(bus, INVENTORY_BUSNAME, inventoryPath,
72 ITEM_IFACE, "Present", present);
73 util::SDBusPlus::setProperty(bus, INVENTORY_BUSNAME, inventoryPath,
74 ASSET_IFACE, "Manufacturer",
75 nvmeData.vendor);
76 util::SDBusPlus::setProperty(bus, INVENTORY_BUSNAME, inventoryPath,
77 ASSET_IFACE, "SerialNumber",
78 nvmeData.serialNumber);
79 util::SDBusPlus::setProperty(bus, INVENTORY_BUSNAME, inventoryPath,
80 ASSET_IFACE, "Model",
81 nvmeData.modelNumber);
82 util::SDBusPlus::setProperty(bus, INVENTORY_BUSNAME, inventoryPath,
83 NVME_STATUS_IFACE, "DriveLifeUsed",
84 nvmeData.driveLifeUsed);
85 preSerial[config.busID] = nvmeData.serialNumber;
86 }
Tony Lee89659212019-06-21 17:34:14 +080087
Chanh Nguyene528b0a2021-07-14 16:57:57 +070088 if (preStatusFlags[config.busID].compare(nvmeData.statusFlags) != 0)
89 {
90 util::SDBusPlus::setProperty(bus, INVENTORY_BUSNAME, inventoryPath,
91 NVME_STATUS_IFACE, "StatusFlags",
92 nvmeData.statusFlags);
93 preStatusFlags[config.busID] = nvmeData.statusFlags;
94 }
Tony Lee89659212019-06-21 17:34:14 +080095
Chanh Nguyene528b0a2021-07-14 16:57:57 +070096 if (preSmartWarning[config.busID].compare(nvmeData.smartWarnings) != 0)
97 {
98 util::SDBusPlus::setProperty(bus, INVENTORY_BUSNAME, inventoryPath,
99 NVME_STATUS_IFACE, "SmartWarnings",
100 nvmeData.smartWarnings);
101 auto smartWarning = (!nvmeData.smartWarnings.empty())
102 ? std::stoi(nvmeData.smartWarnings, 0, 16)
103 : NOWARNING;
Tony Lee89659212019-06-21 17:34:14 +0800104
Chanh Nguyene528b0a2021-07-14 16:57:57 +0700105 util::SDBusPlus::setProperty(bus, INVENTORY_BUSNAME, inventoryPath,
106 NVME_STATUS_IFACE, "CapacityFault",
107 !(smartWarning & CapacityFaultMask));
Tony Lee89659212019-06-21 17:34:14 +0800108
Chanh Nguyene528b0a2021-07-14 16:57:57 +0700109 util::SDBusPlus::setProperty(bus, INVENTORY_BUSNAME, inventoryPath,
110 NVME_STATUS_IFACE, "TemperatureFault",
111 !(smartWarning & temperatureFaultMask));
Tony Lee89659212019-06-21 17:34:14 +0800112
Chanh Nguyene528b0a2021-07-14 16:57:57 +0700113 util::SDBusPlus::setProperty(bus, INVENTORY_BUSNAME, inventoryPath,
114 NVME_STATUS_IFACE, "DegradesFault",
115 !(smartWarning & DegradesFaultMask));
116
117 util::SDBusPlus::setProperty(bus, INVENTORY_BUSNAME, inventoryPath,
118 NVME_STATUS_IFACE, "MediaFault",
119 !(smartWarning & MediaFaultMask));
120
121 util::SDBusPlus::setProperty(bus, INVENTORY_BUSNAME, inventoryPath,
122 NVME_STATUS_IFACE, "BackupDeviceFault",
123 !(smartWarning & BackupDeviceFaultMask));
124 preSmartWarning[config.busID] = nvmeData.smartWarnings;
125 }
Tony Lee89659212019-06-21 17:34:14 +0800126}
127
128void Nvme::setFaultLED(const std::string& locateLedGroupPath,
129 const std::string& faultLedGroupPath, bool request)
130{
131 if (locateLedGroupPath.empty() || faultLedGroupPath.empty())
132 {
133 return;
134 }
135
136 // Before toggle LED, check whether is Identify or not.
137 if (!getLEDGroupState(locateLedGroupPath))
138 {
Brandon Kimfdffe5c2021-03-30 15:07:59 -0700139 if (getLEDGroupState(faultLedGroupPath) != request)
140 {
141 util::SDBusPlus::setProperty(bus, LED_GROUP_BUSNAME,
142 faultLedGroupPath, LED_GROUP_IFACE,
143 "Asserted", request);
144 }
Tony Lee89659212019-06-21 17:34:14 +0800145 }
146}
147
148void Nvme::setLocateLED(const std::string& locateLedGroupPath,
149 const std::string& locateLedBusName,
150 const std::string& locateLedPath, bool isPresent)
151{
152 if (locateLedGroupPath.empty() || locateLedBusName.empty() ||
153 locateLedPath.empty())
154 {
155 return;
156 }
157
158 namespace server = sdbusplus::xyz::openbmc_project::Led::server;
159
160 if (!getLEDGroupState(locateLedGroupPath))
161 {
162 if (isPresent)
163 util::SDBusPlus::setProperty(
164 bus, locateLedBusName, locateLedPath, LED_CONTROLLER_IFACE,
165 "State",
166 server::convertForMessage(server::Physical::Action::On));
167 else
168 util::SDBusPlus::setProperty(
169 bus, locateLedBusName, locateLedPath, LED_CONTROLLER_IFACE,
170 "State",
171 server::convertForMessage(server::Physical::Action::Off));
172 }
173}
174
175bool Nvme::getLEDGroupState(const std::string& ledPath)
176{
177 auto asserted = util::SDBusPlus::getProperty<bool>(
178 bus, LED_GROUP_BUSNAME, ledPath, LED_GROUP_IFACE, "Asserted");
179
180 return asserted;
181}
182
183void Nvme::setLEDsStatus(const phosphor::nvme::Nvme::NVMeConfig& config,
184 bool success,
185 const phosphor::nvme::Nvme::NVMeData& nvmeData)
186{
Tony Lee89659212019-06-21 17:34:14 +0800187
188 if (success)
189 {
190 if (!nvmeData.smartWarnings.empty())
191 {
192 auto request =
193 (strcmp(nvmeData.smartWarnings.c_str(), NOWARNING_STRING) == 0)
194 ? false
195 : true;
196
197 setFaultLED(config.locateLedGroupPath, config.faultLedGroupPath,
198 request);
199 setLocateLED(config.locateLedGroupPath,
200 config.locateLedControllerBusName,
201 config.locateLedControllerPath, !request);
202 }
203 isError[config.index] = false;
204 }
205 else
206 {
207 if (isError[config.index] != true)
208 {
209 // Drive is present but can not get data, turn on fault LED.
210 log<level::ERR>("Drive status is good but can not get data.",
Brandon Kim9b771e22020-10-05 12:02:01 -0700211 entry("OBJ_PATH=%s", config.index.c_str()));
Tony Lee89659212019-06-21 17:34:14 +0800212 isError[config.index] = true;
213 }
214
215 setFaultLED(config.locateLedGroupPath, config.faultLedGroupPath, true);
216 setLocateLED(config.locateLedGroupPath,
217 config.locateLedControllerBusName,
218 config.locateLedControllerPath, false);
219 }
220}
221
Tony Lee6c595012019-06-19 10:54:59 +0800222std::string intToHex(int input)
223{
224 std::stringstream tmp;
225 tmp << std::hex << input;
226
227 return tmp.str();
228}
229
230/** @brief Get NVMe info over smbus */
George Hung5e23bcd2021-07-01 12:16:11 +0800231bool Nvme::getNVMeInfobyBusID(int busID,
232 phosphor::nvme::Nvme::NVMeData& nvmeData)
Tony Lee6c595012019-06-19 10:54:59 +0800233{
234 nvmeData.present = true;
235 nvmeData.vendor = "";
236 nvmeData.serialNumber = "";
George Hung831f2042021-05-19 17:02:29 +0800237 nvmeData.modelNumber = "";
Tony Lee6c595012019-06-19 10:54:59 +0800238 nvmeData.smartWarnings = "";
239 nvmeData.statusFlags = "";
240 nvmeData.driveLifeUsed = "";
Brandon Kimd5838d12021-05-19 12:51:55 -0700241 nvmeData.sensorValue = static_cast<int8_t>(TEMPERATURE_SENSOR_FAILURE);
George Hung831f2042021-05-19 17:02:29 +0800242 nvmeData.wcTemp = 0;
Tony Lee6c595012019-06-19 10:54:59 +0800243
244 phosphor::smbus::Smbus smbus;
245
246 unsigned char rsp_data_command_0[I2C_DATA_MAX] = {0};
247 unsigned char rsp_data_command_8[I2C_DATA_MAX] = {0};
248
249 uint8_t tx_data = COMMAND_CODE_0;
250
251 auto init = smbus.smbusInit(busID);
252
Tony Lee6c595012019-06-19 10:54:59 +0800253 if (init == -1)
254 {
255 if (isErrorSmbus[busID] != true)
256 {
257 log<level::ERR>("smbusInit fail!");
258 isErrorSmbus[busID] = true;
259 }
260
261 nvmeData.present = false;
262
263 return nvmeData.present;
264 }
265
George Hung92a15ba2020-09-14 17:14:52 +0800266 auto res_int = smbus.SendSmbusRWCmdRAW(busID, NVME_SSD_SLAVE_ADDRESS,
267 &tx_data, sizeof(tx_data),
268 rsp_data_command_0, CODE_0_LENGTH);
Tony Lee6c595012019-06-19 10:54:59 +0800269
270 if (res_int < 0)
271 {
272 if (isErrorSmbus[busID] != true)
273 {
274 log<level::ERR>("Send command code 0 fail!");
275 isErrorSmbus[busID] = true;
276 }
277
278 smbus.smbusClose(busID);
279 nvmeData.present = false;
280 return nvmeData.present;
281 }
282
George Hung92a15ba2020-09-14 17:14:52 +0800283 nvmeData.statusFlags = intToHex(rsp_data_command_0[1]);
284 nvmeData.smartWarnings = intToHex(rsp_data_command_0[2]);
285 nvmeData.driveLifeUsed = intToHex(rsp_data_command_0[4]);
George Hung93455332021-01-06 20:57:04 +0800286 nvmeData.sensorValue = static_cast<int8_t>(rsp_data_command_0[3]);
287 nvmeData.wcTemp = static_cast<int8_t>(rsp_data_command_0[5]);
George Hung92a15ba2020-09-14 17:14:52 +0800288
Tony Lee6c595012019-06-19 10:54:59 +0800289 tx_data = COMMAND_CODE_8;
290
George Hung92a15ba2020-09-14 17:14:52 +0800291 res_int = smbus.SendSmbusRWCmdRAW(busID, NVME_SSD_SLAVE_ADDRESS, &tx_data,
292 sizeof(tx_data), rsp_data_command_8,
293 CODE_8_LENGTH);
Tony Lee6c595012019-06-19 10:54:59 +0800294
295 if (res_int < 0)
296 {
297 if (isErrorSmbus[busID] != true)
298 {
299 log<level::ERR>("Send command code 8 fail!");
300 isErrorSmbus[busID] = true;
301 }
302
303 smbus.smbusClose(busID);
304 nvmeData.present = false;
305 return nvmeData.present;
306 }
307
308 nvmeData.vendor =
309 intToHex(rsp_data_command_8[1]) + " " + intToHex(rsp_data_command_8[2]);
310
George Hung69b96182020-08-20 17:19:56 +0800311 for (auto iter = map_vendor.begin(); iter != map_vendor.end(); iter++)
312 {
313 if (iter->first == nvmeData.vendor)
314 {
315 nvmeData.vendor = iter->second;
316 break;
317 }
318 }
319
Tony Lee6c595012019-06-19 10:54:59 +0800320 for (int offset = SERIALNUMBER_START_INDEX; offset < SERIALNUMBER_END_INDEX;
321 offset++)
322 {
George Hung31c3a2f2021-07-29 19:15:14 +0800323 // Only accept digits/letters/punctuation characters.
324 if (rsp_data_command_8[offset] >= '!' &&
325 rsp_data_command_8[offset] <= '~')
George Hung69b96182020-08-20 17:19:56 +0800326 nvmeData.serialNumber +=
327 static_cast<char>(rsp_data_command_8[offset]);
Tony Lee6c595012019-06-19 10:54:59 +0800328 }
329
George Hung92a15ba2020-09-14 17:14:52 +0800330 if (nvmeData.vendor == "Samsung")
331 {
332 unsigned char rsp_data_vpd[I2C_DATA_MAX] = {0};
333 const int rx_len = (MODELNUMBER_END_INDEX - MODELNUMBER_START_INDEX);
334 tx_data = MODELNUMBER_START_INDEX;
335
336 auto res_int =
337 smbus.SendSmbusRWCmdRAW(busID, NVME_SSD_VPD_SLAVE_ADDRESS, &tx_data,
338 sizeof(tx_data), rsp_data_vpd, rx_len);
339
340 if (res_int < 0)
341 {
342 if (isErrorSmbus[busID] != true)
343 {
344 log<level::ERR>("Send command read VPD fail!");
345 isErrorSmbus[busID] = true;
346 }
347
348 smbus.smbusClose(busID);
349 nvmeData.present = false;
350 return nvmeData.present;
351 }
352
353 for (int i = 0; i < rx_len; i++)
354 {
George Hung31c3a2f2021-07-29 19:15:14 +0800355 // Only accept digits/letters/punctuation characters.
356 if ((rsp_data_vpd[i] >= '!' && rsp_data_vpd[i] <= '~'))
George Hung92a15ba2020-09-14 17:14:52 +0800357 nvmeData.modelNumber += static_cast<char>(rsp_data_vpd[i]);
358 }
359
360 if (nvmeData.modelNumber.substr(0, nvmeData.vendor.size()) == "SAMSUNG")
361 nvmeData.modelNumber.erase(0, nvmeData.vendor.size());
362 }
Tony Lee6c595012019-06-19 10:54:59 +0800363
364 smbus.smbusClose(busID);
365
366 isErrorSmbus[busID] = false;
367
368 return nvmeData.present;
369}
370
Tony Lee84d430c2019-06-13 15:26:15 +0800371void Nvme::run()
372{
Tony Lee89659212019-06-21 17:34:14 +0800373 init();
374
Tony Lee84d430c2019-06-13 15:26:15 +0800375 std::function<void()> callback(std::bind(&Nvme::read, this));
376 try
377 {
378 u_int64_t interval = MONITOR_INTERVAL_SECONDS * 1000000;
379 _timer.restart(std::chrono::microseconds(interval));
380 }
381 catch (const std::exception& e)
382 {
Brandon Kim9b771e22020-10-05 12:02:01 -0700383 log<level::ERR>("Error in polling loop. "), entry("ERROR=%s", e.what());
Tony Lee84d430c2019-06-13 15:26:15 +0800384 }
385}
386
Tony Lee6c595012019-06-19 10:54:59 +0800387/** @brief Parsing NVMe config JSON file */
388Json parseSensorConfig()
Tony Lee84d430c2019-06-13 15:26:15 +0800389{
Tony Lee6c595012019-06-19 10:54:59 +0800390 std::ifstream jsonFile(configFile);
391 if (!jsonFile.is_open())
392 {
393 log<level::ERR>("NVMe config JSON file not found");
394 }
395
396 auto data = Json::parse(jsonFile, nullptr, false);
397 if (data.is_discarded())
398 {
399 log<level::ERR>("NVMe config readings JSON parser failure");
400 }
401
402 return data;
Tony Lee84d430c2019-06-13 15:26:15 +0800403}
404
Tony Lee6c595012019-06-19 10:54:59 +0800405/** @brief Obtain the initial configuration value of NVMe */
406std::vector<phosphor::nvme::Nvme::NVMeConfig> Nvme::getNvmeConfig()
407{
408
409 phosphor::nvme::Nvme::NVMeConfig nvmeConfig;
410 std::vector<phosphor::nvme::Nvme::NVMeConfig> nvmeConfigs;
411 int8_t criticalHigh = 0;
412 int8_t criticalLow = 0;
413 int8_t maxValue = 0;
414 int8_t minValue = 0;
415 int8_t warningHigh = 0;
416 int8_t warningLow = 0;
417
418 try
419 {
420 auto data = parseSensorConfig();
421 static const std::vector<Json> empty{};
422 std::vector<Json> readings = data.value("config", empty);
423 std::vector<Json> thresholds = data.value("threshold", empty);
424 if (!thresholds.empty())
425 {
426 for (const auto& instance : thresholds)
427 {
428 criticalHigh = instance.value("criticalHigh", 0);
429 criticalLow = instance.value("criticalLow", 0);
430 maxValue = instance.value("maxValue", 0);
431 minValue = instance.value("minValue", 0);
432 warningHigh = instance.value("warningHigh", 0);
433 warningLow = instance.value("warningLow", 0);
434 }
435 }
436 else
437 {
438 log<level::ERR>(
439 "Invalid NVMe config file, thresholds dosen't exist");
440 }
441
442 if (!readings.empty())
443 {
444 for (const auto& instance : readings)
445 {
446 uint8_t index = instance.value("NVMeDriveIndex", 0);
447 uint8_t busID = instance.value("NVMeDriveBusID", 0);
Tony Lee89659212019-06-21 17:34:14 +0800448 std::string faultLedGroupPath =
449 instance.value("NVMeDriveFaultLEDGroupPath", "");
450 std::string locateLedGroupPath =
451 instance.value("NVMeDriveLocateLEDGroupPath", "");
George Hung873b5b32020-06-20 14:56:15 +0800452 uint16_t presentPin = instance.value("NVMeDrivePresentPin", 0);
453 uint16_t pwrGoodPin = instance.value("NVMeDrivePwrGoodPin", 0);
Tony Lee89659212019-06-21 17:34:14 +0800454 std::string locateLedControllerBusName =
455 instance.value("NVMeDriveLocateLEDControllerBusName", "");
456 std::string locateLedControllerPath =
457 instance.value("NVMeDriveLocateLEDControllerPath", "");
Tony Lee6c595012019-06-19 10:54:59 +0800458
459 nvmeConfig.index = std::to_string(index);
460 nvmeConfig.busID = busID;
Tony Lee89659212019-06-21 17:34:14 +0800461 nvmeConfig.faultLedGroupPath = faultLedGroupPath;
Tony Lee6c595012019-06-19 10:54:59 +0800462 nvmeConfig.presentPin = presentPin;
463 nvmeConfig.pwrGoodPin = pwrGoodPin;
Tony Lee89659212019-06-21 17:34:14 +0800464 nvmeConfig.locateLedControllerBusName =
465 locateLedControllerBusName;
466 nvmeConfig.locateLedControllerPath = locateLedControllerPath;
467 nvmeConfig.locateLedGroupPath = locateLedGroupPath;
Tony Lee6c595012019-06-19 10:54:59 +0800468 nvmeConfig.criticalHigh = criticalHigh;
469 nvmeConfig.criticalLow = criticalLow;
470 nvmeConfig.warningHigh = warningHigh;
471 nvmeConfig.warningLow = warningLow;
472 nvmeConfig.maxValue = maxValue;
473 nvmeConfig.minValue = minValue;
474 nvmeConfigs.push_back(nvmeConfig);
475 }
476 }
477 else
478 {
479 log<level::ERR>("Invalid NVMe config file, config dosen't exist");
480 }
481 }
482 catch (const Json::exception& e)
483 {
Brandon Kim9b771e22020-10-05 12:02:01 -0700484 log<level::ERR>("Json Exception caught."), entry("MSG=%s", e.what());
Tony Lee6c595012019-06-19 10:54:59 +0800485 }
486
487 return nvmeConfigs;
488}
489
490std::string Nvme::getGPIOValueOfNvme(const std::string& fullPath)
491{
492 std::string val;
493 std::ifstream ifs;
494 auto retries = 3;
495
496 while (retries != 0)
497 {
498 try
499 {
500 if (!ifs.is_open())
501 ifs.open(fullPath);
502 ifs.clear();
503 ifs.seekg(0);
504 ifs >> val;
505 }
506 catch (const std::exception& e)
507 {
508 --retries;
509 std::this_thread::sleep_for(delay);
510 log<level::ERR>("Can not open gpio path.",
Brandon Kim9b771e22020-10-05 12:02:01 -0700511 entry("MSG=%s", e.what()));
Tony Lee6c595012019-06-19 10:54:59 +0800512 continue;
513 }
514 break;
515 }
516
517 ifs.close();
518 return val;
519}
520
Tony Lee89659212019-06-21 17:34:14 +0800521void Nvme::createNVMeInventory()
522{
Patrick Williams05eedaa2020-05-13 17:58:42 -0500523 using Properties = std::map<std::string, std::variant<std::string, bool>>;
Tony Lee89659212019-06-21 17:34:14 +0800524 using Interfaces = std::map<std::string, Properties>;
525
526 std::string inventoryPath;
527 std::map<sdbusplus::message::object_path, Interfaces> obj;
528
George Hung831f2042021-05-19 17:02:29 +0800529 for (const auto& config : configs)
Tony Lee89659212019-06-21 17:34:14 +0800530 {
531 inventoryPath = "/system/chassis/motherboard/nvme" + config.index;
532
533 obj = {{
534 inventoryPath,
535 {{ITEM_IFACE, {}}, {NVME_STATUS_IFACE, {}}, {ASSET_IFACE, {}}},
536 }};
537 util::SDBusPlus::CallMethod(bus, INVENTORY_BUSNAME, INVENTORY_NAMESPACE,
538 INVENTORY_MANAGER_IFACE, "Notify", obj);
539 }
540}
541
542void Nvme::init()
543{
544 createNVMeInventory();
545}
546
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700547void Nvme::readNvmeData(NVMeConfig& config)
548{
549 std::string inventoryPath = NVME_INVENTORY_PATH + config.index;
550 NVMeData nvmeData;
551
552 // get NVMe information through i2c by busID.
553 auto success = getNVMeInfobyBusID(config.busID, nvmeData);
554 auto iter = nvmes.find(config.index);
555
556 // can not find. create dbus
557 if (iter == nvmes.end())
558 {
Brandon Kim9b771e22020-10-05 12:02:01 -0700559 log<level::INFO>("SSD plug.", entry("INDEX=%s", config.index.c_str()));
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700560
561 std::string objPath = NVME_OBJ_PATH + config.index;
562 auto nvmeSSD =
563 std::make_shared<phosphor::nvme::NvmeSSD>(bus, objPath.c_str());
564 nvmes.emplace(config.index, nvmeSSD);
565
Chanh Nguyene528b0a2021-07-14 16:57:57 +0700566 setNvmeInventoryProperties(config, true, nvmeData, inventoryPath);
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700567 nvmeSSD->setSensorValueToDbus(nvmeData.sensorValue);
George Hung93455332021-01-06 20:57:04 +0800568 if (nvmeData.wcTemp != 0)
569 {
570 config.criticalHigh = nvmeData.wcTemp;
571 config.warningHigh = nvmeData.wcTemp;
572 }
George Hung831f2042021-05-19 17:02:29 +0800573 nvmeSSD->setSensorMaxMin(config.maxValue, config.minValue);
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700574 nvmeSSD->setSensorThreshold(config.criticalHigh, config.criticalLow,
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700575 config.warningHigh, config.warningLow);
576
577 nvmeSSD->checkSensorThreshold();
578 setLEDsStatus(config, success, nvmeData);
579 }
580 else
581 {
Chanh Nguyene528b0a2021-07-14 16:57:57 +0700582 setNvmeInventoryProperties(config, true, nvmeData, inventoryPath);
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700583 iter->second->setSensorValueToDbus(nvmeData.sensorValue);
George Hung831f2042021-05-19 17:02:29 +0800584 if (nvmeData.wcTemp != 0)
585 {
George Hungbe343992021-07-02 09:15:54 +0800586 config.criticalHigh = nvmeData.wcTemp;
587 config.warningHigh = nvmeData.wcTemp;
588
George Hung831f2042021-05-19 17:02:29 +0800589 iter->second->setSensorThreshold(
590 config.criticalHigh, config.criticalLow, config.warningHigh,
591 config.warningLow);
592 }
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700593 iter->second->checkSensorThreshold();
594 setLEDsStatus(config, success, nvmeData);
595 }
596}
597
Tony Lee6c595012019-06-19 10:54:59 +0800598/** @brief Monitor NVMe drives every one second */
Tony Lee84d430c2019-06-13 15:26:15 +0800599void Nvme::read()
600{
Tony Lee6c595012019-06-19 10:54:59 +0800601 std::string devPresentPath;
602 std::string devPwrGoodPath;
Tony Lee89659212019-06-21 17:34:14 +0800603 std::string inventoryPath;
Tony Lee6c595012019-06-19 10:54:59 +0800604
Tony Lee6c595012019-06-19 10:54:59 +0800605 for (auto config : configs)
606 {
607 NVMeData nvmeData;
Tony Lee6c595012019-06-19 10:54:59 +0800608
Tony Lee89659212019-06-21 17:34:14 +0800609 inventoryPath = NVME_INVENTORY_PATH + config.index;
610
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700611 if (config.presentPin)
Tony Lee6c595012019-06-19 10:54:59 +0800612 {
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700613 devPresentPath =
614 GPIO_BASE_PATH + std::to_string(config.presentPin) + "/value";
615
616 if (getGPIOValueOfNvme(devPresentPath) != IS_PRESENT)
Tony Lee6c595012019-06-19 10:54:59 +0800617 {
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700618 // Drive not present, remove nvme d-bus path ,
619 // clean all properties in inventory
620 // and turn off fault and locate LED
Tony Lee89659212019-06-21 17:34:14 +0800621
622 setFaultLED(config.locateLedGroupPath, config.faultLedGroupPath,
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700623 false);
Tony Lee89659212019-06-21 17:34:14 +0800624 setLocateLED(config.locateLedGroupPath,
625 config.locateLedControllerBusName,
626 config.locateLedControllerPath, false);
627
Tony Lee6c595012019-06-19 10:54:59 +0800628 nvmeData = NVMeData();
Chanh Nguyene528b0a2021-07-14 16:57:57 +0700629 setNvmeInventoryProperties(config, false, nvmeData,
630 inventoryPath);
Tony Lee6c595012019-06-19 10:54:59 +0800631 nvmes.erase(config.index);
George Hung188ad952020-06-20 16:28:06 +0800632 continue;
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700633 }
634 else if (config.pwrGoodPin)
635 {
636 devPwrGoodPath = GPIO_BASE_PATH +
637 std::to_string(config.pwrGoodPin) + "/value";
Tony Lee6c595012019-06-19 10:54:59 +0800638
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700639 if (getGPIOValueOfNvme(devPwrGoodPath) != POWERGD)
Tony Lee6c595012019-06-19 10:54:59 +0800640 {
George Hung95b90f42021-01-11 21:18:59 +0800641 // IFDET should be used to provide the final say
642 // in SSD's presence - IFDET showing SSD is present
643 // but the power is off (if the drive is plugged in)
644 // is a valid state.
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700645
646 setFaultLED(config.locateLedGroupPath,
647 config.faultLedGroupPath, true);
648 setLocateLED(config.locateLedGroupPath,
649 config.locateLedControllerBusName,
650 config.locateLedControllerPath, false);
651
652 nvmeData = NVMeData();
Chanh Nguyene528b0a2021-07-14 16:57:57 +0700653 setNvmeInventoryProperties(config, true, nvmeData,
654 inventoryPath);
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700655
656 if (isErrorPower[config.index] != true)
657 {
658 log<level::ERR>(
659 "Present pin is true but power good pin is false.",
Brandon Kim9b771e22020-10-05 12:02:01 -0700660 entry("INDEX=%s", config.index.c_str()));
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700661 log<level::ERR>(
662 "Erase SSD from map and d-bus.",
Brandon Kim9b771e22020-10-05 12:02:01 -0700663 entry("INDEX=%s", config.index.c_str()));
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700664
665 isErrorPower[config.index] = true;
666 }
George Hung95b90f42021-01-11 21:18:59 +0800667
668 // Keep reading to report the invalid temperature
669 // (To make thermal loop know that the sensor reading
670 // is invalid).
671 readNvmeData(config);
George Hung188ad952020-06-20 16:28:06 +0800672 continue;
Tony Lee6c595012019-06-19 10:54:59 +0800673 }
674 }
675 }
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700676 // Drive status is good, update value or create d-bus and update
677 // value.
678 readNvmeData(config);
Tony Lee89659212019-06-21 17:34:14 +0800679
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700680 isErrorPower[config.index] = false;
Tony Lee6c595012019-06-19 10:54:59 +0800681 }
Tony Lee84d430c2019-06-13 15:26:15 +0800682}
683} // namespace nvme
684} // namespace phosphor