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 // Amester packs data in 4 bytes 81 ssize_t size = command.size() * sizeof(int32_t); 82 auto rc = write((fd)(), command.data(), size); 83 if (rc < 0 || (rc != size)) 84 { 85 // This would log and terminate since its not handled. 86 elog<WriteFailure>( 87 phosphor::logging::org::open_power::OCC::PassThrough:: 88 WriteFailure::CALLOUT_ERRNO(errno), 89 phosphor::logging::org::open_power::OCC::PassThrough:: 90 WriteFailure::CALLOUT_DEVICE_PATH(devicePath.c_str())); 91 } 92 93 // Now read the response. This would be the content of occ-sram 94 while(1) 95 { 96 int32_t data {}; 97 auto len = read((fd)(), &data, sizeof(data)); 98 if (len > 0) 99 { 100 response.emplace_back(data); 101 } 102 else if (len < 0 && errno == EAGAIN) 103 { 104 // We may have data coming still. 105 // This driver does not need a sleep for a retry. 106 continue; 107 } 108 else if (len == 0) 109 { 110 // We have read all that we can. 111 break; 112 } 113 else 114 { 115 // This would log and terminate since its not handled. 116 elog<ReadFailure>( 117 phosphor::logging::org::open_power::OCC::PassThrough:: 118 ReadFailure::CALLOUT_ERRNO(errno), 119 phosphor::logging::org::open_power::OCC::PassThrough:: 120 ReadFailure::CALLOUT_DEVICE_PATH(devicePath.c_str())); 121 } 122 } 123 124 return response; 125 } 126 127 } // namespace pass_through 128 } // namespace occ 129 } // namespace open_power 130