blob: 07ce839210835480f739113984db657757cccc3b [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
George Hung69b96182020-08-20 17:19:56 +080047static std::map<std::string, std::string> map_vendor = {{"80 86", "Intel"},
48 {"14 4d", "Samsung"}};
49
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(
61 bool present, const phosphor::nvme::Nvme::NVMeData& nvmeData,
62 const std::string& inventoryPath)
63{
64 util::SDBusPlus::setProperty(bus, INVENTORY_BUSNAME, inventoryPath,
65 ITEM_IFACE, "Present", present);
66 util::SDBusPlus::setProperty(bus, INVENTORY_BUSNAME, inventoryPath,
67 ASSET_IFACE, "Manufacturer", nvmeData.vendor);
68 util::SDBusPlus::setProperty(bus, INVENTORY_BUSNAME, inventoryPath,
69 ASSET_IFACE, "SerialNumber",
70 nvmeData.serialNumber);
71 util::SDBusPlus::setProperty(bus, INVENTORY_BUSNAME, inventoryPath,
George Hung92a15ba2020-09-14 17:14:52 +080072 ASSET_IFACE, "Model", nvmeData.modelNumber);
73 util::SDBusPlus::setProperty(bus, INVENTORY_BUSNAME, inventoryPath,
Tony Lee89659212019-06-21 17:34:14 +080074 NVME_STATUS_IFACE, "SmartWarnings",
75 nvmeData.smartWarnings);
76 util::SDBusPlus::setProperty(bus, INVENTORY_BUSNAME, inventoryPath,
77 NVME_STATUS_IFACE, "StatusFlags",
78 nvmeData.statusFlags);
79 util::SDBusPlus::setProperty(bus, INVENTORY_BUSNAME, inventoryPath,
80 NVME_STATUS_IFACE, "DriveLifeUsed",
81 nvmeData.driveLifeUsed);
82
83 auto smartWarning = (!nvmeData.smartWarnings.empty())
84 ? std::stoi(nvmeData.smartWarnings, 0, 16)
85 : NOWARNING;
86
87 util::SDBusPlus::setProperty(bus, INVENTORY_BUSNAME, inventoryPath,
88 NVME_STATUS_IFACE, "CapacityFault",
89 !(smartWarning & CapacityFaultMask));
90
91 util::SDBusPlus::setProperty(bus, INVENTORY_BUSNAME, inventoryPath,
92 NVME_STATUS_IFACE, "TemperatureFault",
93 !(smartWarning & temperatureFaultMask));
94
95 util::SDBusPlus::setProperty(bus, INVENTORY_BUSNAME, inventoryPath,
96 NVME_STATUS_IFACE, "DegradesFault",
97 !(smartWarning & DegradesFaultMask));
98
99 util::SDBusPlus::setProperty(bus, INVENTORY_BUSNAME, inventoryPath,
100 NVME_STATUS_IFACE, "MediaFault",
101 !(smartWarning & MediaFaultMask));
102
103 util::SDBusPlus::setProperty(bus, INVENTORY_BUSNAME, inventoryPath,
104 NVME_STATUS_IFACE, "BackupDeviceFault",
105 !(smartWarning & BackupDeviceFaultMask));
106}
107
108void Nvme::setFaultLED(const std::string& locateLedGroupPath,
109 const std::string& faultLedGroupPath, bool request)
110{
111 if (locateLedGroupPath.empty() || faultLedGroupPath.empty())
112 {
113 return;
114 }
115
116 // Before toggle LED, check whether is Identify or not.
117 if (!getLEDGroupState(locateLedGroupPath))
118 {
119 util::SDBusPlus::setProperty(bus, LED_GROUP_BUSNAME, faultLedGroupPath,
120 LED_GROUP_IFACE, "Asserted", request);
121 }
122}
123
124void Nvme::setLocateLED(const std::string& locateLedGroupPath,
125 const std::string& locateLedBusName,
126 const std::string& locateLedPath, bool isPresent)
127{
128 if (locateLedGroupPath.empty() || locateLedBusName.empty() ||
129 locateLedPath.empty())
130 {
131 return;
132 }
133
134 namespace server = sdbusplus::xyz::openbmc_project::Led::server;
135
136 if (!getLEDGroupState(locateLedGroupPath))
137 {
138 if (isPresent)
139 util::SDBusPlus::setProperty(
140 bus, locateLedBusName, locateLedPath, LED_CONTROLLER_IFACE,
141 "State",
142 server::convertForMessage(server::Physical::Action::On));
143 else
144 util::SDBusPlus::setProperty(
145 bus, locateLedBusName, locateLedPath, LED_CONTROLLER_IFACE,
146 "State",
147 server::convertForMessage(server::Physical::Action::Off));
148 }
149}
150
151bool Nvme::getLEDGroupState(const std::string& ledPath)
152{
153 auto asserted = util::SDBusPlus::getProperty<bool>(
154 bus, LED_GROUP_BUSNAME, ledPath, LED_GROUP_IFACE, "Asserted");
155
156 return asserted;
157}
158
159void Nvme::setLEDsStatus(const phosphor::nvme::Nvme::NVMeConfig& config,
160 bool success,
161 const phosphor::nvme::Nvme::NVMeData& nvmeData)
162{
163 static std::unordered_map<std::string, bool> isError;
164
165 if (success)
166 {
167 if (!nvmeData.smartWarnings.empty())
168 {
169 auto request =
170 (strcmp(nvmeData.smartWarnings.c_str(), NOWARNING_STRING) == 0)
171 ? false
172 : true;
173
174 setFaultLED(config.locateLedGroupPath, config.faultLedGroupPath,
175 request);
176 setLocateLED(config.locateLedGroupPath,
177 config.locateLedControllerBusName,
178 config.locateLedControllerPath, !request);
179 }
180 isError[config.index] = false;
181 }
182 else
183 {
184 if (isError[config.index] != true)
185 {
186 // Drive is present but can not get data, turn on fault LED.
187 log<level::ERR>("Drive status is good but can not get data.",
Brandon Kim9b771e22020-10-05 12:02:01 -0700188 entry("OBJ_PATH=%s", config.index.c_str()));
Tony Lee89659212019-06-21 17:34:14 +0800189 isError[config.index] = true;
190 }
191
192 setFaultLED(config.locateLedGroupPath, config.faultLedGroupPath, true);
193 setLocateLED(config.locateLedGroupPath,
194 config.locateLedControllerBusName,
195 config.locateLedControllerPath, false);
196 }
197}
198
Tony Lee6c595012019-06-19 10:54:59 +0800199std::string intToHex(int input)
200{
201 std::stringstream tmp;
202 tmp << std::hex << input;
203
204 return tmp.str();
205}
206
207/** @brief Get NVMe info over smbus */
208bool getNVMeInfobyBusID(int busID, phosphor::nvme::Nvme::NVMeData& nvmeData)
209{
210 nvmeData.present = true;
211 nvmeData.vendor = "";
212 nvmeData.serialNumber = "";
213 nvmeData.smartWarnings = "";
214 nvmeData.statusFlags = "";
215 nvmeData.driveLifeUsed = "";
216 nvmeData.sensorValue = (int8_t)TEMPERATURE_SENSOR_FAILURE;
217
218 phosphor::smbus::Smbus smbus;
219
220 unsigned char rsp_data_command_0[I2C_DATA_MAX] = {0};
221 unsigned char rsp_data_command_8[I2C_DATA_MAX] = {0};
222
223 uint8_t tx_data = COMMAND_CODE_0;
224
225 auto init = smbus.smbusInit(busID);
226
227 static std::unordered_map<int, bool> isErrorSmbus;
228
229 if (init == -1)
230 {
231 if (isErrorSmbus[busID] != true)
232 {
233 log<level::ERR>("smbusInit fail!");
234 isErrorSmbus[busID] = true;
235 }
236
237 nvmeData.present = false;
238
239 return nvmeData.present;
240 }
241
George Hung92a15ba2020-09-14 17:14:52 +0800242 auto res_int = smbus.SendSmbusRWCmdRAW(busID, NVME_SSD_SLAVE_ADDRESS,
243 &tx_data, sizeof(tx_data),
244 rsp_data_command_0, CODE_0_LENGTH);
Tony Lee6c595012019-06-19 10:54:59 +0800245
246 if (res_int < 0)
247 {
248 if (isErrorSmbus[busID] != true)
249 {
250 log<level::ERR>("Send command code 0 fail!");
251 isErrorSmbus[busID] = true;
252 }
253
254 smbus.smbusClose(busID);
255 nvmeData.present = false;
256 return nvmeData.present;
257 }
258
George Hung92a15ba2020-09-14 17:14:52 +0800259 nvmeData.statusFlags = intToHex(rsp_data_command_0[1]);
260 nvmeData.smartWarnings = intToHex(rsp_data_command_0[2]);
261 nvmeData.driveLifeUsed = intToHex(rsp_data_command_0[4]);
262 nvmeData.sensorValue = (int8_t)rsp_data_command_0[3];
263
Tony Lee6c595012019-06-19 10:54:59 +0800264 tx_data = COMMAND_CODE_8;
265
George Hung92a15ba2020-09-14 17:14:52 +0800266 res_int = smbus.SendSmbusRWCmdRAW(busID, NVME_SSD_SLAVE_ADDRESS, &tx_data,
267 sizeof(tx_data), rsp_data_command_8,
268 CODE_8_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 8 fail!");
275 isErrorSmbus[busID] = true;
276 }
277
278 smbus.smbusClose(busID);
279 nvmeData.present = false;
280 return nvmeData.present;
281 }
282
283 nvmeData.vendor =
284 intToHex(rsp_data_command_8[1]) + " " + intToHex(rsp_data_command_8[2]);
285
George Hung69b96182020-08-20 17:19:56 +0800286 for (auto iter = map_vendor.begin(); iter != map_vendor.end(); iter++)
287 {
288 if (iter->first == nvmeData.vendor)
289 {
290 nvmeData.vendor = iter->second;
291 break;
292 }
293 }
294
Tony Lee6c595012019-06-19 10:54:59 +0800295 for (int offset = SERIALNUMBER_START_INDEX; offset < SERIALNUMBER_END_INDEX;
296 offset++)
297 {
George Hung69b96182020-08-20 17:19:56 +0800298 if (rsp_data_command_8[offset] != ' ')
299 nvmeData.serialNumber +=
300 static_cast<char>(rsp_data_command_8[offset]);
Tony Lee6c595012019-06-19 10:54:59 +0800301 }
302
George Hung92a15ba2020-09-14 17:14:52 +0800303 if (nvmeData.vendor == "Samsung")
304 {
305 unsigned char rsp_data_vpd[I2C_DATA_MAX] = {0};
306 const int rx_len = (MODELNUMBER_END_INDEX - MODELNUMBER_START_INDEX);
307 tx_data = MODELNUMBER_START_INDEX;
308
309 auto res_int =
310 smbus.SendSmbusRWCmdRAW(busID, NVME_SSD_VPD_SLAVE_ADDRESS, &tx_data,
311 sizeof(tx_data), rsp_data_vpd, rx_len);
312
313 if (res_int < 0)
314 {
315 if (isErrorSmbus[busID] != true)
316 {
317 log<level::ERR>("Send command read VPD fail!");
318 isErrorSmbus[busID] = true;
319 }
320
321 smbus.smbusClose(busID);
322 nvmeData.present = false;
323 return nvmeData.present;
324 }
325
326 for (int i = 0; i < rx_len; i++)
327 {
328 if (rsp_data_vpd[i] != ' ')
329 nvmeData.modelNumber += static_cast<char>(rsp_data_vpd[i]);
330 }
331
332 if (nvmeData.modelNumber.substr(0, nvmeData.vendor.size()) == "SAMSUNG")
333 nvmeData.modelNumber.erase(0, nvmeData.vendor.size());
334 }
Tony Lee6c595012019-06-19 10:54:59 +0800335
336 smbus.smbusClose(busID);
337
338 isErrorSmbus[busID] = false;
339
340 return nvmeData.present;
341}
342
Tony Lee84d430c2019-06-13 15:26:15 +0800343void Nvme::run()
344{
Tony Lee89659212019-06-21 17:34:14 +0800345 init();
346
Tony Lee84d430c2019-06-13 15:26:15 +0800347 std::function<void()> callback(std::bind(&Nvme::read, this));
348 try
349 {
350 u_int64_t interval = MONITOR_INTERVAL_SECONDS * 1000000;
351 _timer.restart(std::chrono::microseconds(interval));
352 }
353 catch (const std::exception& e)
354 {
Brandon Kim9b771e22020-10-05 12:02:01 -0700355 log<level::ERR>("Error in polling loop. "), entry("ERROR=%s", e.what());
Tony Lee84d430c2019-06-13 15:26:15 +0800356 }
357}
358
Tony Lee6c595012019-06-19 10:54:59 +0800359/** @brief Parsing NVMe config JSON file */
360Json parseSensorConfig()
Tony Lee84d430c2019-06-13 15:26:15 +0800361{
Tony Lee6c595012019-06-19 10:54:59 +0800362 std::ifstream jsonFile(configFile);
363 if (!jsonFile.is_open())
364 {
365 log<level::ERR>("NVMe config JSON file not found");
366 }
367
368 auto data = Json::parse(jsonFile, nullptr, false);
369 if (data.is_discarded())
370 {
371 log<level::ERR>("NVMe config readings JSON parser failure");
372 }
373
374 return data;
Tony Lee84d430c2019-06-13 15:26:15 +0800375}
376
Tony Lee6c595012019-06-19 10:54:59 +0800377/** @brief Obtain the initial configuration value of NVMe */
378std::vector<phosphor::nvme::Nvme::NVMeConfig> Nvme::getNvmeConfig()
379{
380
381 phosphor::nvme::Nvme::NVMeConfig nvmeConfig;
382 std::vector<phosphor::nvme::Nvme::NVMeConfig> nvmeConfigs;
383 int8_t criticalHigh = 0;
384 int8_t criticalLow = 0;
385 int8_t maxValue = 0;
386 int8_t minValue = 0;
387 int8_t warningHigh = 0;
388 int8_t warningLow = 0;
389
390 try
391 {
392 auto data = parseSensorConfig();
393 static const std::vector<Json> empty{};
394 std::vector<Json> readings = data.value("config", empty);
395 std::vector<Json> thresholds = data.value("threshold", empty);
396 if (!thresholds.empty())
397 {
398 for (const auto& instance : thresholds)
399 {
400 criticalHigh = instance.value("criticalHigh", 0);
401 criticalLow = instance.value("criticalLow", 0);
402 maxValue = instance.value("maxValue", 0);
403 minValue = instance.value("minValue", 0);
404 warningHigh = instance.value("warningHigh", 0);
405 warningLow = instance.value("warningLow", 0);
406 }
407 }
408 else
409 {
410 log<level::ERR>(
411 "Invalid NVMe config file, thresholds dosen't exist");
412 }
413
414 if (!readings.empty())
415 {
416 for (const auto& instance : readings)
417 {
418 uint8_t index = instance.value("NVMeDriveIndex", 0);
419 uint8_t busID = instance.value("NVMeDriveBusID", 0);
Tony Lee89659212019-06-21 17:34:14 +0800420 std::string faultLedGroupPath =
421 instance.value("NVMeDriveFaultLEDGroupPath", "");
422 std::string locateLedGroupPath =
423 instance.value("NVMeDriveLocateLEDGroupPath", "");
George Hung873b5b32020-06-20 14:56:15 +0800424 uint16_t presentPin = instance.value("NVMeDrivePresentPin", 0);
425 uint16_t pwrGoodPin = instance.value("NVMeDrivePwrGoodPin", 0);
Tony Lee89659212019-06-21 17:34:14 +0800426 std::string locateLedControllerBusName =
427 instance.value("NVMeDriveLocateLEDControllerBusName", "");
428 std::string locateLedControllerPath =
429 instance.value("NVMeDriveLocateLEDControllerPath", "");
Tony Lee6c595012019-06-19 10:54:59 +0800430
431 nvmeConfig.index = std::to_string(index);
432 nvmeConfig.busID = busID;
Tony Lee89659212019-06-21 17:34:14 +0800433 nvmeConfig.faultLedGroupPath = faultLedGroupPath;
Tony Lee6c595012019-06-19 10:54:59 +0800434 nvmeConfig.presentPin = presentPin;
435 nvmeConfig.pwrGoodPin = pwrGoodPin;
Tony Lee89659212019-06-21 17:34:14 +0800436 nvmeConfig.locateLedControllerBusName =
437 locateLedControllerBusName;
438 nvmeConfig.locateLedControllerPath = locateLedControllerPath;
439 nvmeConfig.locateLedGroupPath = locateLedGroupPath;
Tony Lee6c595012019-06-19 10:54:59 +0800440 nvmeConfig.criticalHigh = criticalHigh;
441 nvmeConfig.criticalLow = criticalLow;
442 nvmeConfig.warningHigh = warningHigh;
443 nvmeConfig.warningLow = warningLow;
444 nvmeConfig.maxValue = maxValue;
445 nvmeConfig.minValue = minValue;
446 nvmeConfigs.push_back(nvmeConfig);
447 }
448 }
449 else
450 {
451 log<level::ERR>("Invalid NVMe config file, config dosen't exist");
452 }
453 }
454 catch (const Json::exception& e)
455 {
Brandon Kim9b771e22020-10-05 12:02:01 -0700456 log<level::ERR>("Json Exception caught."), entry("MSG=%s", e.what());
Tony Lee6c595012019-06-19 10:54:59 +0800457 }
458
459 return nvmeConfigs;
460}
461
462std::string Nvme::getGPIOValueOfNvme(const std::string& fullPath)
463{
464 std::string val;
465 std::ifstream ifs;
466 auto retries = 3;
467
468 while (retries != 0)
469 {
470 try
471 {
472 if (!ifs.is_open())
473 ifs.open(fullPath);
474 ifs.clear();
475 ifs.seekg(0);
476 ifs >> val;
477 }
478 catch (const std::exception& e)
479 {
480 --retries;
481 std::this_thread::sleep_for(delay);
482 log<level::ERR>("Can not open gpio path.",
Brandon Kim9b771e22020-10-05 12:02:01 -0700483 entry("MSG=%s", e.what()));
Tony Lee6c595012019-06-19 10:54:59 +0800484 continue;
485 }
486 break;
487 }
488
489 ifs.close();
490 return val;
491}
492
Tony Lee89659212019-06-21 17:34:14 +0800493void Nvme::createNVMeInventory()
494{
Patrick Williams05eedaa2020-05-13 17:58:42 -0500495 using Properties = std::map<std::string, std::variant<std::string, bool>>;
Tony Lee89659212019-06-21 17:34:14 +0800496 using Interfaces = std::map<std::string, Properties>;
497
498 std::string inventoryPath;
499 std::map<sdbusplus::message::object_path, Interfaces> obj;
500
501 for (const auto config : configs)
502 {
503 inventoryPath = "/system/chassis/motherboard/nvme" + config.index;
504
505 obj = {{
506 inventoryPath,
507 {{ITEM_IFACE, {}}, {NVME_STATUS_IFACE, {}}, {ASSET_IFACE, {}}},
508 }};
509 util::SDBusPlus::CallMethod(bus, INVENTORY_BUSNAME, INVENTORY_NAMESPACE,
510 INVENTORY_MANAGER_IFACE, "Notify", obj);
511 }
512}
513
514void Nvme::init()
515{
516 createNVMeInventory();
517}
518
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700519void Nvme::readNvmeData(NVMeConfig& config)
520{
521 std::string inventoryPath = NVME_INVENTORY_PATH + config.index;
522 NVMeData nvmeData;
523
524 // get NVMe information through i2c by busID.
525 auto success = getNVMeInfobyBusID(config.busID, nvmeData);
526 auto iter = nvmes.find(config.index);
527
528 // can not find. create dbus
529 if (iter == nvmes.end())
530 {
Brandon Kim9b771e22020-10-05 12:02:01 -0700531 log<level::INFO>("SSD plug.", entry("INDEX=%s", config.index.c_str()));
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700532
533 std::string objPath = NVME_OBJ_PATH + config.index;
534 auto nvmeSSD =
535 std::make_shared<phosphor::nvme::NvmeSSD>(bus, objPath.c_str());
536 nvmes.emplace(config.index, nvmeSSD);
537
538 setNvmeInventoryProperties(true, nvmeData, inventoryPath);
539 nvmeSSD->setSensorValueToDbus(nvmeData.sensorValue);
540 nvmeSSD->setSensorThreshold(config.criticalHigh, config.criticalLow,
541 config.maxValue, config.minValue,
542 config.warningHigh, config.warningLow);
543
544 nvmeSSD->checkSensorThreshold();
545 setLEDsStatus(config, success, nvmeData);
546 }
547 else
548 {
549 setNvmeInventoryProperties(true, nvmeData, inventoryPath);
550 iter->second->setSensorValueToDbus(nvmeData.sensorValue);
551 iter->second->checkSensorThreshold();
552 setLEDsStatus(config, success, nvmeData);
553 }
554}
555
Tony Lee6c595012019-06-19 10:54:59 +0800556/** @brief Monitor NVMe drives every one second */
Tony Lee84d430c2019-06-13 15:26:15 +0800557void Nvme::read()
558{
Tony Lee6c595012019-06-19 10:54:59 +0800559 std::string devPresentPath;
560 std::string devPwrGoodPath;
Tony Lee89659212019-06-21 17:34:14 +0800561 std::string inventoryPath;
Tony Lee6c595012019-06-19 10:54:59 +0800562
563 static std::unordered_map<std::string, bool> isErrorPower;
564
565 for (auto config : configs)
566 {
567 NVMeData nvmeData;
Tony Lee6c595012019-06-19 10:54:59 +0800568
Tony Lee89659212019-06-21 17:34:14 +0800569 inventoryPath = NVME_INVENTORY_PATH + config.index;
570
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700571 if (config.presentPin)
Tony Lee6c595012019-06-19 10:54:59 +0800572 {
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700573 devPresentPath =
574 GPIO_BASE_PATH + std::to_string(config.presentPin) + "/value";
575
576 if (getGPIOValueOfNvme(devPresentPath) != IS_PRESENT)
Tony Lee6c595012019-06-19 10:54:59 +0800577 {
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700578 // Drive not present, remove nvme d-bus path ,
579 // clean all properties in inventory
580 // and turn off fault and locate LED
Tony Lee89659212019-06-21 17:34:14 +0800581
582 setFaultLED(config.locateLedGroupPath, config.faultLedGroupPath,
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700583 false);
Tony Lee89659212019-06-21 17:34:14 +0800584 setLocateLED(config.locateLedGroupPath,
585 config.locateLedControllerBusName,
586 config.locateLedControllerPath, false);
587
Tony Lee6c595012019-06-19 10:54:59 +0800588 nvmeData = NVMeData();
Tony Lee89659212019-06-21 17:34:14 +0800589 setNvmeInventoryProperties(false, nvmeData, inventoryPath);
Tony Lee6c595012019-06-19 10:54:59 +0800590 nvmes.erase(config.index);
George Hung188ad952020-06-20 16:28:06 +0800591 continue;
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700592 }
593 else if (config.pwrGoodPin)
594 {
595 devPwrGoodPath = GPIO_BASE_PATH +
596 std::to_string(config.pwrGoodPin) + "/value";
Tony Lee6c595012019-06-19 10:54:59 +0800597
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700598 if (getGPIOValueOfNvme(devPwrGoodPath) != POWERGD)
Tony Lee6c595012019-06-19 10:54:59 +0800599 {
Tony Lee6c595012019-06-19 10:54:59 +0800600
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700601 // Present pin is true but power good pin is false
602 // remove nvme d-bus path, clean all properties in inventory
603 // and turn on fault LED
604
605 setFaultLED(config.locateLedGroupPath,
606 config.faultLedGroupPath, true);
607 setLocateLED(config.locateLedGroupPath,
608 config.locateLedControllerBusName,
609 config.locateLedControllerPath, false);
610
611 nvmeData = NVMeData();
612 setNvmeInventoryProperties(false, nvmeData, inventoryPath);
613 nvmes.erase(config.index);
614
615 if (isErrorPower[config.index] != true)
616 {
617 log<level::ERR>(
618 "Present pin is true but power good pin is false.",
Brandon Kim9b771e22020-10-05 12:02:01 -0700619 entry("INDEX=%s", config.index.c_str()));
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700620 log<level::ERR>(
621 "Erase SSD from map and d-bus.",
Brandon Kim9b771e22020-10-05 12:02:01 -0700622 entry("INDEX=%s", config.index.c_str()));
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700623
624 isErrorPower[config.index] = true;
625 }
George Hung188ad952020-06-20 16:28:06 +0800626 continue;
Tony Lee6c595012019-06-19 10:54:59 +0800627 }
628 }
629 }
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700630 // Drive status is good, update value or create d-bus and update
631 // value.
632 readNvmeData(config);
Tony Lee89659212019-06-21 17:34:14 +0800633
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700634 isErrorPower[config.index] = false;
Tony Lee6c595012019-06-19 10:54:59 +0800635 }
Tony Lee84d430c2019-06-13 15:26:15 +0800636}
637} // namespace nvme
638} // namespace phosphor