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 <fstream> 23 #include <phosphor-logging/log.hpp> 24 #include <sdbusplus/bus.hpp> 25 26 namespace google 27 { 28 namespace ipmi 29 { 30 31 using namespace phosphor::logging; 32 33 struct PsuResetRequest 34 { 35 uint8_t subcommand; 36 // Delay in seconds. 37 uint32_t delay; 38 } __attribute__((packed)); 39 40 static constexpr auto TIME_DELAY_FILENAME = "/run/psu_timedelay"; 41 static constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1"; 42 static constexpr auto SYSTEMD_ROOT = "/org/freedesktop/systemd1"; 43 static constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager"; 44 static constexpr auto PSU_HARDRESET_TARGET = "gbmc-psu-hardreset.target"; 45 46 ipmi_ret_t PsuHardReset(const uint8_t* reqBuf, uint8_t* replyBuf, 47 size_t* dataLen) 48 { 49 if ((*dataLen) < sizeof(struct PsuResetRequest)) 50 { 51 fprintf(stderr, "Invalid command length: %u\n", 52 static_cast<uint32_t>(*dataLen)); 53 return IPMI_CC_INVALID; 54 } 55 56 struct PsuResetRequest request; 57 memcpy(&request, &reqBuf[0], sizeof(struct PsuResetRequest)); 58 59 std::ofstream ofs; 60 ofs.open(TIME_DELAY_FILENAME, std::ofstream::out); 61 if (!ofs.good()) 62 { 63 fprintf(stderr, "Unable to open file for output.\n"); 64 return IPMI_CC_INVALID; 65 } 66 67 ofs << "PSU_HARDRESET_DELAY=" << request.delay << std::endl; 68 if (ofs.fail()) 69 { 70 fprintf(stderr, "Write failed\n"); 71 ofs.close(); 72 return IPMI_CC_INVALID; 73 } 74 75 // Write succeeded, please continue. 76 ofs.flush(); 77 ofs.close(); 78 79 auto bus = sdbusplus::bus::new_default(); 80 auto method = bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_ROOT, 81 SYSTEMD_INTERFACE, "StartUnit"); 82 83 method.append(PSU_HARDRESET_TARGET); 84 method.append("replace"); 85 86 try 87 { 88 bus.call_noreply(method); 89 } 90 catch (const sdbusplus::exception::SdBusError& ex) 91 { 92 log<level::ERR>("Failed to call PSU hard reset"); 93 return IPMI_CC_INVALID; 94 } 95 96 replyBuf[0] = SysPsuHardReset; 97 (*dataLen) = sizeof(uint8_t); 98 99 return IPMI_CC_OK; 100 } 101 102 } // namespace ipmi 103 } // namespace google 104