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