1 #include <memory>
2 #include <algorithm>
3 #include <fcntl.h>
4 #include <errno.h>
5 #include <phosphor-logging/log.hpp>
6 #include "occ_pass_through.hpp"
7 #include "occ_finder.hpp"
8 namespace open_power
9 {
10 namespace occ
11 {
12 namespace pass_through
13 {
14 
15 void run()
16 {
17     auto bus = sdbusplus::bus::new_default();
18     sdbusplus::server::manager::manager objManager(bus,
19                                                    OCC_PASS_THROUGH_ROOT);
20 
21     std::vector<std::unique_ptr<PassThrough>> objects;
22     auto occs = open_power::occ::finder::get();
23 
24     for (const auto& occ : occs)
25     {
26         auto occPassThrough = object(occ);
27         objects.emplace_back(
28             std::make_unique<PassThrough>(bus, occPassThrough.c_str()));
29     }
30     bus.request_name(OCC_PASS_THROUGH_BUSNAME);
31 
32     while (true)
33     {
34         bus.process_discard();
35         bus.wait();
36     }
37 }
38 
39 PassThrough::PassThrough(
40     sdbusplus::bus::bus& bus,
41     const char* path) :
42     Iface(bus, path),
43     path(path),
44     fd(openDevice())
45 {
46     // Nothing to do.
47 }
48 
49 int PassThrough::openDevice()
50 {
51     // Device instance number starts from 1.
52     devicePath.append(std::to_string((this->path.back() - '0') + 1));
53 
54     int fd = open(devicePath.c_str(), O_RDWR | O_NONBLOCK);
55     if (fd < 0)
56     {
57         // This is for completion. This is getting replaced by elog
58         // in the next commit
59         throw std::runtime_error("Error opening " + devicePath);
60     }
61     return fd;
62 }
63 
64 std::vector<int32_t> PassThrough::send(std::vector<int32_t> command)
65 {
66     using namespace phosphor::logging;
67 
68     std::vector<int32_t> response {};
69 
70     // Amester packs data in 4 bytes
71     ssize_t size = command.size() * sizeof(int32_t);
72     auto rc = write((fd)(), command.data(), size);
73     if (rc < 0 || (rc != size))
74     {
75         log<level::ERR>("Error writing to OCC");
76 
77         // In the next commit, it will have exceptions.
78         return response;
79     }
80 
81     // Now read the response. This would be the content of occ-sram
82     while(1)
83     {
84         errno = 0;
85         int32_t data {};
86         auto len = read((fd)(), &data, sizeof(data));
87         if (len > 0)
88         {
89             response.emplace_back(data);
90         }
91         else if (len < 0 && errno == EAGAIN)
92         {
93             // We may have data coming still
94             continue;
95         }
96         else if (len == 0)
97         {
98             // We have read all that we can.
99             break;
100         }
101         else
102         {
103             // Will have exception in the next commit.
104             log<level::ERR>("Error reading from OCC");
105             break;
106         }
107     }
108 
109     return response;
110 }
111 
112 
113 } // namespace pass_through
114 } // namespace occ
115 } // namespace open_power
116