1 #include <memory> 2 #include <algorithm> 3 #include <fcntl.h> 4 #include <errno.h> 5 #include <phosphor-logging/log.hpp> 6 #include <phosphor-logging/elog.hpp> 7 #include <org/open_power/OCC/PassThrough/error.hpp> 8 #include "occ_pass_through.hpp" 9 #include "elog-errors.hpp" 10 namespace open_power 11 { 12 namespace occ 13 { 14 namespace pass_through 15 { 16 17 PassThrough::PassThrough( 18 sdbusplus::bus::bus& bus, 19 const char* path) : 20 Iface(bus, path), 21 path(path), 22 fd(openDevice()) 23 { 24 // Nothing to do. 25 } 26 27 int PassThrough::openDevice() 28 { 29 using namespace phosphor::logging; 30 using namespace sdbusplus::org::open_power::OCC::PassThrough::Error; 31 32 // Device instance number starts from 1. 33 devicePath.append(std::to_string((this->path.back() - '0') + 1)); 34 35 int fd = open(devicePath.c_str(), O_RDWR | O_NONBLOCK); 36 if (fd < 0) 37 { 38 // This would log and terminate since its not handled. 39 elog<OpenFailure>( 40 phosphor::logging::org::open_power::OCC::PassThrough:: 41 OpenFailure::CALLOUT_ERRNO(errno), 42 phosphor::logging::org::open_power::OCC::PassThrough:: 43 OpenFailure::CALLOUT_DEVICE_PATH(devicePath.c_str())); 44 } 45 return fd; 46 } 47 48 std::vector<int32_t> PassThrough::send(std::vector<int32_t> command) 49 { 50 using namespace phosphor::logging; 51 using namespace sdbusplus::org::open_power::OCC::PassThrough::Error; 52 53 std::vector<int32_t> response {}; 54 55 // OCC only understands [bytes] so need array of bytes. Doing this 56 // because rest-server currently treats all int* as 32 bit integer. 57 std::vector<uint8_t> cmdInBytes; 58 cmdInBytes.resize(command.size()); 59 60 // Populate uint8_t version of vector. 61 std::transform(command.begin(), command.end(), cmdInBytes.begin(), 62 [](decltype(cmdInBytes)::value_type x){return x;}); 63 64 ssize_t size = cmdInBytes.size() * sizeof(decltype(cmdInBytes)::value_type); 65 auto rc = write((fd)(), cmdInBytes.data(), size); 66 if (rc < 0 || (rc != size)) 67 { 68 // This would log and terminate since its not handled. 69 elog<WriteFailure>( 70 phosphor::logging::org::open_power::OCC::PassThrough:: 71 WriteFailure::CALLOUT_ERRNO(errno), 72 phosphor::logging::org::open_power::OCC::PassThrough:: 73 WriteFailure::CALLOUT_DEVICE_PATH(devicePath.c_str())); 74 } 75 76 // Now read the response. This would be the content of occ-sram 77 while(1) 78 { 79 uint8_t data {}; 80 auto len = read((fd)(), &data, sizeof(data)); 81 if (len > 0) 82 { 83 response.emplace_back(data); 84 } 85 else if (len < 0 && errno == EAGAIN) 86 { 87 // We may have data coming still. 88 // This driver does not need a sleep for a retry. 89 continue; 90 } 91 else if (len == 0) 92 { 93 // We have read all that we can. 94 break; 95 } 96 else 97 { 98 // This would log and terminate since its not handled. 99 elog<ReadFailure>( 100 phosphor::logging::org::open_power::OCC::PassThrough:: 101 ReadFailure::CALLOUT_ERRNO(errno), 102 phosphor::logging::org::open_power::OCC::PassThrough:: 103 ReadFailure::CALLOUT_DEVICE_PATH(devicePath.c_str())); 104 } 105 } 106 107 return response; 108 } 109 110 } // namespace pass_through 111 } // namespace occ 112 } // namespace open_power 113