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