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