1 #include "config.h" 2 3 #include "occ_pass_through.hpp" 4 5 #include "elog-errors.hpp" 6 7 #include <errno.h> 8 #include <fcntl.h> 9 #include <unistd.h> 10 11 #include <algorithm> 12 #include <memory> 13 #include <org/open_power/OCC/Device/error.hpp> 14 #include <phosphor-logging/elog.hpp> 15 #include <phosphor-logging/log.hpp> 16 #include <string> 17 namespace open_power 18 { 19 namespace occ 20 { 21 22 PassThrough::PassThrough(sdbusplus::bus::bus& bus, const char* path) : 23 Iface(bus, path), path(path), 24 devicePath(OCC_DEV_PATH + std::to_string((this->path.back() - '0') + 1)), 25 activeStatusSignal( 26 bus, sdbusRule::propertiesChanged(path, "org.open_power.OCC.Status"), 27 std::bind(std::mem_fn(&PassThrough::activeStatusEvent), this, 28 std::placeholders::_1)) 29 { 30 // Nothing to do. 31 } 32 33 void PassThrough::openDevice() 34 { 35 using namespace phosphor::logging; 36 using namespace sdbusplus::org::open_power::OCC::Device::Error; 37 38 if (!occActive) 39 { 40 log<level::INFO>("OCC is inactive; cannot perform pass-through"); 41 return; 42 } 43 44 fd = open(devicePath.c_str(), O_RDWR | O_NONBLOCK); 45 if (fd < 0) 46 { 47 // This would log and terminate since its not handled. 48 elog<OpenFailure>( 49 phosphor::logging::org::open_power::OCC::Device::OpenFailure:: 50 CALLOUT_ERRNO(errno), 51 phosphor::logging::org::open_power::OCC::Device::OpenFailure:: 52 CALLOUT_DEVICE_PATH(devicePath.c_str())); 53 } 54 return; 55 } 56 57 void PassThrough::closeDevice() 58 { 59 if (fd >= 0) 60 { 61 close(fd); 62 fd = -1; 63 } 64 } 65 66 std::vector<int32_t> PassThrough::send(std::vector<int32_t> command) 67 { 68 using namespace phosphor::logging; 69 using namespace sdbusplus::org::open_power::OCC::Device::Error; 70 71 std::vector<int32_t> response{}; 72 73 openDevice(); 74 75 if (fd < 0) 76 { 77 // OCC is inactive; empty response 78 return response; 79 } 80 81 // OCC only understands [bytes] so need array of bytes. Doing this 82 // because rest-server currently treats all int* as 32 bit integer. 83 std::vector<uint8_t> cmdInBytes; 84 cmdInBytes.resize(command.size()); 85 86 // Populate uint8_t version of vector. 87 std::transform(command.begin(), command.end(), cmdInBytes.begin(), 88 [](decltype(cmdInBytes)::value_type x) { return x; }); 89 90 ssize_t size = cmdInBytes.size() * sizeof(decltype(cmdInBytes)::value_type); 91 auto rc = write(fd, cmdInBytes.data(), size); 92 if (rc < 0 || (rc != size)) 93 { 94 // This would log and terminate since its not handled. 95 elog<WriteFailure>( 96 phosphor::logging::org::open_power::OCC::Device::WriteFailure:: 97 CALLOUT_ERRNO(errno), 98 phosphor::logging::org::open_power::OCC::Device::WriteFailure:: 99 CALLOUT_DEVICE_PATH(devicePath.c_str())); 100 } 101 102 // Now read the response. This would be the content of occ-sram 103 while (1) 104 { 105 uint8_t data{}; 106 auto len = read(fd, &data, sizeof(data)); 107 if (len > 0) 108 { 109 response.emplace_back(data); 110 } 111 else if (len < 0 && errno == EAGAIN) 112 { 113 // We may have data coming still. 114 // This driver does not need a sleep for a retry. 115 continue; 116 } 117 else if (len == 0) 118 { 119 // We have read all that we can. 120 break; 121 } 122 else 123 { 124 // This would log and terminate since its not handled. 125 elog<ReadFailure>( 126 phosphor::logging::org::open_power::OCC::Device::ReadFailure:: 127 CALLOUT_ERRNO(errno), 128 phosphor::logging::org::open_power::OCC::Device::ReadFailure:: 129 CALLOUT_DEVICE_PATH(devicePath.c_str())); 130 } 131 } 132 133 closeDevice(); 134 135 return response; 136 } 137 138 // Called at OCC Status change signal 139 void PassThrough::activeStatusEvent(sdbusplus::message::message& msg) 140 { 141 std::string statusInterface; 142 std::map<std::string, std::variant<bool>> msgData; 143 msg.read(statusInterface, msgData); 144 145 auto propertyMap = msgData.find("OccActive"); 146 if (propertyMap != msgData.end()) 147 { 148 // Extract the OccActive property 149 if (std::get<bool>(propertyMap->second)) 150 { 151 occActive = true; 152 } 153 else 154 { 155 occActive = false; 156 this->closeDevice(); 157 } 158 } 159 return; 160 } 161 162 } // namespace occ 163 } // namespace open_power 164