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