blob: 95fb9857aa3caa7f9f6b57edac855ddcb724233c [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 {
Brandon Kimfdffe5c2021-03-30 15:07:59 -0700119 if (getLEDGroupState(faultLedGroupPath) != request)
120 {
121 util::SDBusPlus::setProperty(bus, LED_GROUP_BUSNAME,
122 faultLedGroupPath, LED_GROUP_IFACE,
123 "Asserted", request);
124 }
Tony Lee89659212019-06-21 17:34:14 +0800125 }
126}
127
128void Nvme::setLocateLED(const std::string& locateLedGroupPath,
129 const std::string& locateLedBusName,
130 const std::string& locateLedPath, bool isPresent)
131{
132 if (locateLedGroupPath.empty() || locateLedBusName.empty() ||
133 locateLedPath.empty())
134 {
135 return;
136 }
137
138 namespace server = sdbusplus::xyz::openbmc_project::Led::server;
139
140 if (!getLEDGroupState(locateLedGroupPath))
141 {
142 if (isPresent)
143 util::SDBusPlus::setProperty(
144 bus, locateLedBusName, locateLedPath, LED_CONTROLLER_IFACE,
145 "State",
146 server::convertForMessage(server::Physical::Action::On));
147 else
148 util::SDBusPlus::setProperty(
149 bus, locateLedBusName, locateLedPath, LED_CONTROLLER_IFACE,
150 "State",
151 server::convertForMessage(server::Physical::Action::Off));
152 }
153}
154
155bool Nvme::getLEDGroupState(const std::string& ledPath)
156{
157 auto asserted = util::SDBusPlus::getProperty<bool>(
158 bus, LED_GROUP_BUSNAME, ledPath, LED_GROUP_IFACE, "Asserted");
159
160 return asserted;
161}
162
163void Nvme::setLEDsStatus(const phosphor::nvme::Nvme::NVMeConfig& config,
164 bool success,
165 const phosphor::nvme::Nvme::NVMeData& nvmeData)
166{
Tony Lee89659212019-06-21 17:34:14 +0800167
168 if (success)
169 {
170 if (!nvmeData.smartWarnings.empty())
171 {
172 auto request =
173 (strcmp(nvmeData.smartWarnings.c_str(), NOWARNING_STRING) == 0)
174 ? false
175 : true;
176
177 setFaultLED(config.locateLedGroupPath, config.faultLedGroupPath,
178 request);
179 setLocateLED(config.locateLedGroupPath,
180 config.locateLedControllerBusName,
181 config.locateLedControllerPath, !request);
182 }
183 isError[config.index] = false;
184 }
185 else
186 {
187 if (isError[config.index] != true)
188 {
189 // Drive is present but can not get data, turn on fault LED.
190 log<level::ERR>("Drive status is good but can not get data.",
Brandon Kim9b771e22020-10-05 12:02:01 -0700191 entry("OBJ_PATH=%s", config.index.c_str()));
Tony Lee89659212019-06-21 17:34:14 +0800192 isError[config.index] = true;
193 }
194
195 setFaultLED(config.locateLedGroupPath, config.faultLedGroupPath, true);
196 setLocateLED(config.locateLedGroupPath,
197 config.locateLedControllerBusName,
198 config.locateLedControllerPath, false);
199 }
200}
201
Tony Lee6c595012019-06-19 10:54:59 +0800202std::string intToHex(int input)
203{
204 std::stringstream tmp;
205 tmp << std::hex << input;
206
207 return tmp.str();
208}
209
210/** @brief Get NVMe info over smbus */
George Hung5e23bcd2021-07-01 12:16:11 +0800211bool Nvme::getNVMeInfobyBusID(int busID,
212 phosphor::nvme::Nvme::NVMeData& nvmeData)
Tony Lee6c595012019-06-19 10:54:59 +0800213{
214 nvmeData.present = true;
215 nvmeData.vendor = "";
216 nvmeData.serialNumber = "";
George Hung831f2042021-05-19 17:02:29 +0800217 nvmeData.modelNumber = "";
Tony Lee6c595012019-06-19 10:54:59 +0800218 nvmeData.smartWarnings = "";
219 nvmeData.statusFlags = "";
220 nvmeData.driveLifeUsed = "";
Brandon Kimd5838d12021-05-19 12:51:55 -0700221 nvmeData.sensorValue = static_cast<int8_t>(TEMPERATURE_SENSOR_FAILURE);
George Hung831f2042021-05-19 17:02:29 +0800222 nvmeData.wcTemp = 0;
Tony Lee6c595012019-06-19 10:54:59 +0800223
224 phosphor::smbus::Smbus smbus;
225
226 unsigned char rsp_data_command_0[I2C_DATA_MAX] = {0};
227 unsigned char rsp_data_command_8[I2C_DATA_MAX] = {0};
228
229 uint8_t tx_data = COMMAND_CODE_0;
230
231 auto init = smbus.smbusInit(busID);
232
Tony Lee6c595012019-06-19 10:54:59 +0800233 if (init == -1)
234 {
235 if (isErrorSmbus[busID] != true)
236 {
237 log<level::ERR>("smbusInit fail!");
238 isErrorSmbus[busID] = true;
239 }
240
241 nvmeData.present = false;
242
243 return nvmeData.present;
244 }
245
George Hung92a15ba2020-09-14 17:14:52 +0800246 auto res_int = smbus.SendSmbusRWCmdRAW(busID, NVME_SSD_SLAVE_ADDRESS,
247 &tx_data, sizeof(tx_data),
248 rsp_data_command_0, CODE_0_LENGTH);
Tony Lee6c595012019-06-19 10:54:59 +0800249
250 if (res_int < 0)
251 {
252 if (isErrorSmbus[busID] != true)
253 {
254 log<level::ERR>("Send command code 0 fail!");
255 isErrorSmbus[busID] = true;
256 }
257
258 smbus.smbusClose(busID);
259 nvmeData.present = false;
260 return nvmeData.present;
261 }
262
George Hung92a15ba2020-09-14 17:14:52 +0800263 nvmeData.statusFlags = intToHex(rsp_data_command_0[1]);
264 nvmeData.smartWarnings = intToHex(rsp_data_command_0[2]);
265 nvmeData.driveLifeUsed = intToHex(rsp_data_command_0[4]);
George Hung93455332021-01-06 20:57:04 +0800266 nvmeData.sensorValue = static_cast<int8_t>(rsp_data_command_0[3]);
267 nvmeData.wcTemp = static_cast<int8_t>(rsp_data_command_0[5]);
George Hung92a15ba2020-09-14 17:14:52 +0800268
Tony Lee6c595012019-06-19 10:54:59 +0800269 tx_data = COMMAND_CODE_8;
270
George Hung92a15ba2020-09-14 17:14:52 +0800271 res_int = smbus.SendSmbusRWCmdRAW(busID, NVME_SSD_SLAVE_ADDRESS, &tx_data,
272 sizeof(tx_data), rsp_data_command_8,
273 CODE_8_LENGTH);
Tony Lee6c595012019-06-19 10:54:59 +0800274
275 if (res_int < 0)
276 {
277 if (isErrorSmbus[busID] != true)
278 {
279 log<level::ERR>("Send command code 8 fail!");
280 isErrorSmbus[busID] = true;
281 }
282
283 smbus.smbusClose(busID);
284 nvmeData.present = false;
285 return nvmeData.present;
286 }
287
288 nvmeData.vendor =
289 intToHex(rsp_data_command_8[1]) + " " + intToHex(rsp_data_command_8[2]);
290
George Hung69b96182020-08-20 17:19:56 +0800291 for (auto iter = map_vendor.begin(); iter != map_vendor.end(); iter++)
292 {
293 if (iter->first == nvmeData.vendor)
294 {
295 nvmeData.vendor = iter->second;
296 break;
297 }
298 }
299
Tony Lee6c595012019-06-19 10:54:59 +0800300 for (int offset = SERIALNUMBER_START_INDEX; offset < SERIALNUMBER_END_INDEX;
301 offset++)
302 {
George Hung31c3a2f2021-07-29 19:15:14 +0800303 // Only accept digits/letters/punctuation characters.
304 if (rsp_data_command_8[offset] >= '!' &&
305 rsp_data_command_8[offset] <= '~')
George Hung69b96182020-08-20 17:19:56 +0800306 nvmeData.serialNumber +=
307 static_cast<char>(rsp_data_command_8[offset]);
Tony Lee6c595012019-06-19 10:54:59 +0800308 }
309
George Hung92a15ba2020-09-14 17:14:52 +0800310 if (nvmeData.vendor == "Samsung")
311 {
312 unsigned char rsp_data_vpd[I2C_DATA_MAX] = {0};
313 const int rx_len = (MODELNUMBER_END_INDEX - MODELNUMBER_START_INDEX);
314 tx_data = MODELNUMBER_START_INDEX;
315
316 auto res_int =
317 smbus.SendSmbusRWCmdRAW(busID, NVME_SSD_VPD_SLAVE_ADDRESS, &tx_data,
318 sizeof(tx_data), rsp_data_vpd, rx_len);
319
320 if (res_int < 0)
321 {
322 if (isErrorSmbus[busID] != true)
323 {
324 log<level::ERR>("Send command read VPD fail!");
325 isErrorSmbus[busID] = true;
326 }
327
328 smbus.smbusClose(busID);
329 nvmeData.present = false;
330 return nvmeData.present;
331 }
332
333 for (int i = 0; i < rx_len; i++)
334 {
George Hung31c3a2f2021-07-29 19:15:14 +0800335 // Only accept digits/letters/punctuation characters.
336 if ((rsp_data_vpd[i] >= '!' && rsp_data_vpd[i] <= '~'))
George Hung92a15ba2020-09-14 17:14:52 +0800337 nvmeData.modelNumber += static_cast<char>(rsp_data_vpd[i]);
338 }
339
340 if (nvmeData.modelNumber.substr(0, nvmeData.vendor.size()) == "SAMSUNG")
341 nvmeData.modelNumber.erase(0, nvmeData.vendor.size());
342 }
Tony Lee6c595012019-06-19 10:54:59 +0800343
344 smbus.smbusClose(busID);
345
346 isErrorSmbus[busID] = false;
347
348 return nvmeData.present;
349}
350
Tony Lee84d430c2019-06-13 15:26:15 +0800351void Nvme::run()
352{
Tony Lee89659212019-06-21 17:34:14 +0800353 init();
354
Tony Lee84d430c2019-06-13 15:26:15 +0800355 std::function<void()> callback(std::bind(&Nvme::read, this));
356 try
357 {
358 u_int64_t interval = MONITOR_INTERVAL_SECONDS * 1000000;
359 _timer.restart(std::chrono::microseconds(interval));
360 }
361 catch (const std::exception& e)
362 {
Brandon Kim9b771e22020-10-05 12:02:01 -0700363 log<level::ERR>("Error in polling loop. "), entry("ERROR=%s", e.what());
Tony Lee84d430c2019-06-13 15:26:15 +0800364 }
365}
366
Tony Lee6c595012019-06-19 10:54:59 +0800367/** @brief Parsing NVMe config JSON file */
368Json parseSensorConfig()
Tony Lee84d430c2019-06-13 15:26:15 +0800369{
Tony Lee6c595012019-06-19 10:54:59 +0800370 std::ifstream jsonFile(configFile);
371 if (!jsonFile.is_open())
372 {
373 log<level::ERR>("NVMe config JSON file not found");
374 }
375
376 auto data = Json::parse(jsonFile, nullptr, false);
377 if (data.is_discarded())
378 {
379 log<level::ERR>("NVMe config readings JSON parser failure");
380 }
381
382 return data;
Tony Lee84d430c2019-06-13 15:26:15 +0800383}
384
Tony Lee6c595012019-06-19 10:54:59 +0800385/** @brief Obtain the initial configuration value of NVMe */
386std::vector<phosphor::nvme::Nvme::NVMeConfig> Nvme::getNvmeConfig()
387{
388
389 phosphor::nvme::Nvme::NVMeConfig nvmeConfig;
390 std::vector<phosphor::nvme::Nvme::NVMeConfig> nvmeConfigs;
391 int8_t criticalHigh = 0;
392 int8_t criticalLow = 0;
393 int8_t maxValue = 0;
394 int8_t minValue = 0;
395 int8_t warningHigh = 0;
396 int8_t warningLow = 0;
397
398 try
399 {
400 auto data = parseSensorConfig();
401 static const std::vector<Json> empty{};
402 std::vector<Json> readings = data.value("config", empty);
403 std::vector<Json> thresholds = data.value("threshold", empty);
404 if (!thresholds.empty())
405 {
406 for (const auto& instance : thresholds)
407 {
408 criticalHigh = instance.value("criticalHigh", 0);
409 criticalLow = instance.value("criticalLow", 0);
410 maxValue = instance.value("maxValue", 0);
411 minValue = instance.value("minValue", 0);
412 warningHigh = instance.value("warningHigh", 0);
413 warningLow = instance.value("warningLow", 0);
414 }
415 }
416 else
417 {
418 log<level::ERR>(
419 "Invalid NVMe config file, thresholds dosen't exist");
420 }
421
422 if (!readings.empty())
423 {
424 for (const auto& instance : readings)
425 {
426 uint8_t index = instance.value("NVMeDriveIndex", 0);
427 uint8_t busID = instance.value("NVMeDriveBusID", 0);
Tony Lee89659212019-06-21 17:34:14 +0800428 std::string faultLedGroupPath =
429 instance.value("NVMeDriveFaultLEDGroupPath", "");
430 std::string locateLedGroupPath =
431 instance.value("NVMeDriveLocateLEDGroupPath", "");
George Hung873b5b32020-06-20 14:56:15 +0800432 uint16_t presentPin = instance.value("NVMeDrivePresentPin", 0);
433 uint16_t pwrGoodPin = instance.value("NVMeDrivePwrGoodPin", 0);
Tony Lee89659212019-06-21 17:34:14 +0800434 std::string locateLedControllerBusName =
435 instance.value("NVMeDriveLocateLEDControllerBusName", "");
436 std::string locateLedControllerPath =
437 instance.value("NVMeDriveLocateLEDControllerPath", "");
Tony Lee6c595012019-06-19 10:54:59 +0800438
439 nvmeConfig.index = std::to_string(index);
440 nvmeConfig.busID = busID;
Tony Lee89659212019-06-21 17:34:14 +0800441 nvmeConfig.faultLedGroupPath = faultLedGroupPath;
Tony Lee6c595012019-06-19 10:54:59 +0800442 nvmeConfig.presentPin = presentPin;
443 nvmeConfig.pwrGoodPin = pwrGoodPin;
Tony Lee89659212019-06-21 17:34:14 +0800444 nvmeConfig.locateLedControllerBusName =
445 locateLedControllerBusName;
446 nvmeConfig.locateLedControllerPath = locateLedControllerPath;
447 nvmeConfig.locateLedGroupPath = locateLedGroupPath;
Tony Lee6c595012019-06-19 10:54:59 +0800448 nvmeConfig.criticalHigh = criticalHigh;
449 nvmeConfig.criticalLow = criticalLow;
450 nvmeConfig.warningHigh = warningHigh;
451 nvmeConfig.warningLow = warningLow;
452 nvmeConfig.maxValue = maxValue;
453 nvmeConfig.minValue = minValue;
454 nvmeConfigs.push_back(nvmeConfig);
455 }
456 }
457 else
458 {
459 log<level::ERR>("Invalid NVMe config file, config dosen't exist");
460 }
461 }
462 catch (const Json::exception& e)
463 {
Brandon Kim9b771e22020-10-05 12:02:01 -0700464 log<level::ERR>("Json Exception caught."), entry("MSG=%s", e.what());
Tony Lee6c595012019-06-19 10:54:59 +0800465 }
466
467 return nvmeConfigs;
468}
469
470std::string Nvme::getGPIOValueOfNvme(const std::string& fullPath)
471{
472 std::string val;
473 std::ifstream ifs;
474 auto retries = 3;
475
476 while (retries != 0)
477 {
478 try
479 {
480 if (!ifs.is_open())
481 ifs.open(fullPath);
482 ifs.clear();
483 ifs.seekg(0);
484 ifs >> val;
485 }
486 catch (const std::exception& e)
487 {
488 --retries;
489 std::this_thread::sleep_for(delay);
490 log<level::ERR>("Can not open gpio path.",
Brandon Kim9b771e22020-10-05 12:02:01 -0700491 entry("MSG=%s", e.what()));
Tony Lee6c595012019-06-19 10:54:59 +0800492 continue;
493 }
494 break;
495 }
496
497 ifs.close();
498 return val;
499}
500
Tony Lee89659212019-06-21 17:34:14 +0800501void Nvme::createNVMeInventory()
502{
Patrick Williams05eedaa2020-05-13 17:58:42 -0500503 using Properties = std::map<std::string, std::variant<std::string, bool>>;
Tony Lee89659212019-06-21 17:34:14 +0800504 using Interfaces = std::map<std::string, Properties>;
505
506 std::string inventoryPath;
507 std::map<sdbusplus::message::object_path, Interfaces> obj;
508
George Hung831f2042021-05-19 17:02:29 +0800509 for (const auto& config : configs)
Tony Lee89659212019-06-21 17:34:14 +0800510 {
511 inventoryPath = "/system/chassis/motherboard/nvme" + config.index;
512
513 obj = {{
514 inventoryPath,
515 {{ITEM_IFACE, {}}, {NVME_STATUS_IFACE, {}}, {ASSET_IFACE, {}}},
516 }};
517 util::SDBusPlus::CallMethod(bus, INVENTORY_BUSNAME, INVENTORY_NAMESPACE,
518 INVENTORY_MANAGER_IFACE, "Notify", obj);
519 }
520}
521
522void Nvme::init()
523{
524 createNVMeInventory();
525}
526
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700527void Nvme::readNvmeData(NVMeConfig& config)
528{
529 std::string inventoryPath = NVME_INVENTORY_PATH + config.index;
530 NVMeData nvmeData;
531
532 // get NVMe information through i2c by busID.
533 auto success = getNVMeInfobyBusID(config.busID, nvmeData);
534 auto iter = nvmes.find(config.index);
535
536 // can not find. create dbus
537 if (iter == nvmes.end())
538 {
Brandon Kim9b771e22020-10-05 12:02:01 -0700539 log<level::INFO>("SSD plug.", entry("INDEX=%s", config.index.c_str()));
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700540
541 std::string objPath = NVME_OBJ_PATH + config.index;
542 auto nvmeSSD =
543 std::make_shared<phosphor::nvme::NvmeSSD>(bus, objPath.c_str());
544 nvmes.emplace(config.index, nvmeSSD);
545
546 setNvmeInventoryProperties(true, nvmeData, inventoryPath);
547 nvmeSSD->setSensorValueToDbus(nvmeData.sensorValue);
George Hung93455332021-01-06 20:57:04 +0800548 if (nvmeData.wcTemp != 0)
549 {
550 config.criticalHigh = nvmeData.wcTemp;
551 config.warningHigh = nvmeData.wcTemp;
552 }
George Hung831f2042021-05-19 17:02:29 +0800553 nvmeSSD->setSensorMaxMin(config.maxValue, config.minValue);
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700554 nvmeSSD->setSensorThreshold(config.criticalHigh, config.criticalLow,
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700555 config.warningHigh, config.warningLow);
556
557 nvmeSSD->checkSensorThreshold();
558 setLEDsStatus(config, success, nvmeData);
559 }
560 else
561 {
562 setNvmeInventoryProperties(true, nvmeData, inventoryPath);
563 iter->second->setSensorValueToDbus(nvmeData.sensorValue);
George Hung831f2042021-05-19 17:02:29 +0800564 if (nvmeData.wcTemp != 0)
565 {
George Hungbe343992021-07-02 09:15:54 +0800566 config.criticalHigh = nvmeData.wcTemp;
567 config.warningHigh = nvmeData.wcTemp;
568
George Hung831f2042021-05-19 17:02:29 +0800569 iter->second->setSensorThreshold(
570 config.criticalHigh, config.criticalLow, config.warningHigh,
571 config.warningLow);
572 }
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700573 iter->second->checkSensorThreshold();
574 setLEDsStatus(config, success, nvmeData);
575 }
576}
577
Tony Lee6c595012019-06-19 10:54:59 +0800578/** @brief Monitor NVMe drives every one second */
Tony Lee84d430c2019-06-13 15:26:15 +0800579void Nvme::read()
580{
Tony Lee6c595012019-06-19 10:54:59 +0800581 std::string devPresentPath;
582 std::string devPwrGoodPath;
Tony Lee89659212019-06-21 17:34:14 +0800583 std::string inventoryPath;
Tony Lee6c595012019-06-19 10:54:59 +0800584
Tony Lee6c595012019-06-19 10:54:59 +0800585 for (auto config : configs)
586 {
587 NVMeData nvmeData;
Tony Lee6c595012019-06-19 10:54:59 +0800588
Tony Lee89659212019-06-21 17:34:14 +0800589 inventoryPath = NVME_INVENTORY_PATH + config.index;
590
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700591 if (config.presentPin)
Tony Lee6c595012019-06-19 10:54:59 +0800592 {
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700593 devPresentPath =
594 GPIO_BASE_PATH + std::to_string(config.presentPin) + "/value";
595
596 if (getGPIOValueOfNvme(devPresentPath) != IS_PRESENT)
Tony Lee6c595012019-06-19 10:54:59 +0800597 {
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700598 // Drive not present, remove nvme d-bus path ,
599 // clean all properties in inventory
600 // and turn off fault and locate LED
Tony Lee89659212019-06-21 17:34:14 +0800601
602 setFaultLED(config.locateLedGroupPath, config.faultLedGroupPath,
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700603 false);
Tony Lee89659212019-06-21 17:34:14 +0800604 setLocateLED(config.locateLedGroupPath,
605 config.locateLedControllerBusName,
606 config.locateLedControllerPath, false);
607
Tony Lee6c595012019-06-19 10:54:59 +0800608 nvmeData = NVMeData();
Tony Lee89659212019-06-21 17:34:14 +0800609 setNvmeInventoryProperties(false, nvmeData, inventoryPath);
Tony Lee6c595012019-06-19 10:54:59 +0800610 nvmes.erase(config.index);
George Hung188ad952020-06-20 16:28:06 +0800611 continue;
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700612 }
613 else if (config.pwrGoodPin)
614 {
615 devPwrGoodPath = GPIO_BASE_PATH +
616 std::to_string(config.pwrGoodPin) + "/value";
Tony Lee6c595012019-06-19 10:54:59 +0800617
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700618 if (getGPIOValueOfNvme(devPwrGoodPath) != POWERGD)
Tony Lee6c595012019-06-19 10:54:59 +0800619 {
George Hung95b90f42021-01-11 21:18:59 +0800620 // IFDET should be used to provide the final say
621 // in SSD's presence - IFDET showing SSD is present
622 // but the power is off (if the drive is plugged in)
623 // is a valid state.
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700624
625 setFaultLED(config.locateLedGroupPath,
626 config.faultLedGroupPath, true);
627 setLocateLED(config.locateLedGroupPath,
628 config.locateLedControllerBusName,
629 config.locateLedControllerPath, false);
630
631 nvmeData = NVMeData();
George Hung95b90f42021-01-11 21:18:59 +0800632 setNvmeInventoryProperties(true, nvmeData, inventoryPath);
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700633
634 if (isErrorPower[config.index] != true)
635 {
636 log<level::ERR>(
637 "Present pin is true but power good pin is false.",
Brandon Kim9b771e22020-10-05 12:02:01 -0700638 entry("INDEX=%s", config.index.c_str()));
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700639 log<level::ERR>(
640 "Erase SSD from map and d-bus.",
Brandon Kim9b771e22020-10-05 12:02:01 -0700641 entry("INDEX=%s", config.index.c_str()));
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700642
643 isErrorPower[config.index] = true;
644 }
George Hung95b90f42021-01-11 21:18:59 +0800645
646 // Keep reading to report the invalid temperature
647 // (To make thermal loop know that the sensor reading
648 // is invalid).
649 readNvmeData(config);
George Hung188ad952020-06-20 16:28:06 +0800650 continue;
Tony Lee6c595012019-06-19 10:54:59 +0800651 }
652 }
653 }
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700654 // Drive status is good, update value or create d-bus and update
655 // value.
656 readNvmeData(config);
Tony Lee89659212019-06-21 17:34:14 +0800657
Vijay Khemkae41b2e42020-04-21 09:23:10 -0700658 isErrorPower[config.index] = false;
Tony Lee6c595012019-06-19 10:54:59 +0800659 }
Tony Lee84d430c2019-06-13 15:26:15 +0800660}
661} // namespace nvme
662} // namespace phosphor