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