1 /* 2 * Copyright 2018 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "psu.hpp" 18 19 #include "main.hpp" 20 21 #include <cstdint> 22 #include <cstring> 23 #include <fstream> 24 #include <phosphor-logging/log.hpp> 25 #include <sdbusplus/bus.hpp> 26 27 namespace google 28 { 29 namespace ipmi 30 { 31 32 using namespace phosphor::logging; 33 34 struct PsuResetRequest 35 { 36 uint8_t subcommand; 37 // Delay in seconds. 38 uint32_t delay; 39 } __attribute__((packed)); 40 41 static constexpr auto TIME_DELAY_FILENAME = "/run/psu_timedelay"; 42 static constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1"; 43 static constexpr auto SYSTEMD_ROOT = "/org/freedesktop/systemd1"; 44 static constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager"; 45 static constexpr auto PSU_HARDRESET_TARGET = "gbmc-psu-hardreset.target"; 46 47 ipmi_ret_t PsuHardReset(const uint8_t* reqBuf, uint8_t* replyBuf, 48 size_t* dataLen) 49 { 50 if ((*dataLen) < sizeof(struct PsuResetRequest)) 51 { 52 std::fprintf(stderr, "Invalid command length: %u\n", 53 static_cast<uint32_t>(*dataLen)); 54 return IPMI_CC_INVALID; 55 } 56 57 struct PsuResetRequest request; 58 std::memcpy(&request, &reqBuf[0], sizeof(struct PsuResetRequest)); 59 60 std::ofstream ofs; 61 ofs.open(TIME_DELAY_FILENAME, std::ofstream::out); 62 if (!ofs.good()) 63 { 64 std::fprintf(stderr, "Unable to open file for output.\n"); 65 return IPMI_CC_INVALID; 66 } 67 68 ofs << "PSU_HARDRESET_DELAY=" << request.delay << std::endl; 69 if (ofs.fail()) 70 { 71 std::fprintf(stderr, "Write failed\n"); 72 ofs.close(); 73 return IPMI_CC_INVALID; 74 } 75 76 // Write succeeded, please continue. 77 ofs.flush(); 78 ofs.close(); 79 80 auto bus = sdbusplus::bus::new_default(); 81 auto method = bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_ROOT, 82 SYSTEMD_INTERFACE, "StartUnit"); 83 84 method.append(PSU_HARDRESET_TARGET); 85 method.append("replace"); 86 87 try 88 { 89 bus.call_noreply(method); 90 } 91 catch (const sdbusplus::exception::SdBusError& ex) 92 { 93 log<level::ERR>("Failed to call PSU hard reset"); 94 return IPMI_CC_INVALID; 95 } 96 97 replyBuf[0] = SysPsuHardReset; 98 (*dataLen) = sizeof(uint8_t); 99 100 return IPMI_CC_OK; 101 } 102 103 } // namespace ipmi 104 } // namespace google 105