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 struct PsuResetRequest request; 51 52 if ((*dataLen) < sizeof(request)) 53 { 54 std::fprintf(stderr, "Invalid command length: %u\n", 55 static_cast<uint32_t>(*dataLen)); 56 return IPMI_CC_REQ_DATA_LEN_INVALID; 57 } 58 59 std::memcpy(&request, &reqBuf[0], sizeof(struct PsuResetRequest)); 60 61 std::ofstream ofs; 62 ofs.open(TIME_DELAY_FILENAME, std::ofstream::out); 63 if (!ofs.good()) 64 { 65 std::fprintf(stderr, "Unable to open file for output.\n"); 66 return IPMI_CC_UNSPECIFIED_ERROR; 67 } 68 69 ofs << "PSU_HARDRESET_DELAY=" << request.delay << std::endl; 70 if (ofs.fail()) 71 { 72 std::fprintf(stderr, "Write failed\n"); 73 ofs.close(); 74 return IPMI_CC_UNSPECIFIED_ERROR; 75 } 76 77 // Write succeeded, please continue. 78 ofs.flush(); 79 ofs.close(); 80 81 auto bus = sdbusplus::bus::new_default(); 82 auto method = bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_ROOT, 83 SYSTEMD_INTERFACE, "StartUnit"); 84 85 method.append(PSU_HARDRESET_TARGET); 86 method.append("replace"); 87 88 try 89 { 90 bus.call_noreply(method); 91 } 92 catch (const sdbusplus::exception::SdBusError& ex) 93 { 94 log<level::ERR>("Failed to call PSU hard reset"); 95 return IPMI_CC_UNSPECIFIED_ERROR; 96 } 97 98 replyBuf[0] = SysPsuHardReset; 99 (*dataLen) = sizeof(uint8_t); 100 101 return IPMI_CC_OK; 102 } 103 104 } // namespace ipmi 105 } // namespace google 106