blob: 361e9f42c68dafeb0d27c67ba728fefcc19bab56 [file] [log] [blame]
Murulidhar Nataraju1adec022017-04-20 12:05:51 -05001#include <array>
Murulidhar Nataraju06a0c2c2017-07-11 08:55:33 -05002#include <errno.h>
3#include <fcntl.h>
4#include <unistd.h>
5#include <poll.h>
6#include <endian.h>
Murulidhar Nataraju1adec022017-04-20 12:05:51 -05007#include <sbe_chipOp_handler.hpp>
Murulidhar Nataraju06a0c2c2017-07-11 08:55:33 -05008#include <file.hpp>
Murulidhar Nataraju1adec022017-04-20 12:05:51 -05009namespace openpower
10{
11namespace sbe
12{
13namespace internal
14{
Murulidhar Nataraju1adec022017-04-20 12:05:51 -050015
16constexpr uint16_t MAGIC_CODE = 0xC0DE;
17constexpr auto SBE_OPERATION_SUCCESSFUL = 0;
18constexpr auto LENGTH_OF_DISTANCE_HEADER_IN_WORDS = 0x1;
19constexpr auto LENGTH_OF_RESP_HEADER_IN_WORDS = 0x2;
Murulidhar Nataraju1adec022017-04-20 12:05:51 -050020constexpr auto DISTANCE_TO_RESP_CODE = 0x1;
Murulidhar Nataraju06a0c2c2017-07-11 08:55:33 -050021constexpr auto MAX_FFDC_LEN_IN_WORDS = 5120;
22constexpr auto WORD_SIZE = 4;
23constexpr auto MAGIC_CODE_BITS = 16;
24std::vector<sbe_word_t> writeToFifo(const char* devPath,
25 const sbe_word_t* cmdBuffer,
26 size_t cmdBufLen,
27 size_t respBufLen)
Murulidhar Nataraju1adec022017-04-20 12:05:51 -050028{
Benjamin Herrenschmidt0dc29322018-05-17 15:25:47 +100029 ssize_t len = 0;
Murulidhar Nataraju06a0c2c2017-07-11 08:55:33 -050030 std::vector<sbe_word_t> response;
31 std::ostringstream errMsg;
32
33 //Open the device and obtain the file descriptor associated with it.
34 FileDescriptor fileFd(devPath, (O_RDWR | O_NONBLOCK));
35
36 //Wait for FIFO device and perform write operation
37 struct pollfd poll_fd = {};
38 poll_fd.fd = fileFd();
39 poll_fd.events = POLLOUT | POLLERR;
40
41 int rc = 0;
42 if ((rc = poll(&poll_fd, 1, -1)) < 0)
43 {
44 //TODO:use elog infrastructure
45 errMsg << "Waiting for FIFO device:" << devPath << "to write failed"
46 << "rc=" << rc << "errno=" << errno;
47 throw std::runtime_error(errMsg.str().c_str());
48 }
49 if (poll_fd.revents & POLLERR)
50 {
51 //TODO:use elog infrastructure
52 errMsg << "POLLERR while waiting for writeable FIFO,errno:" << errno;
53 throw std::runtime_error(errMsg.str().c_str());
54 }
55 auto bytesToWrite = (cmdBufLen * WORD_SIZE);
56 //Perform the write operation
57 len = write(fileFd(), cmdBuffer, bytesToWrite);
58 if (len < 0)
59 {
60 //TODO:use elog infrastructure
61 errMsg << "Failed to write to FIFO device:" << devPath << " Length "
62 "returned= " << len << " errno=" << errno;
63 throw std::runtime_error(errMsg.str().c_str());
64 }
65 //Wait for FIFO device and perform read operation
66 poll_fd.fd = fileFd();
67 poll_fd.events = POLLIN | POLLERR;
68 if ((rc = poll(&poll_fd, 1, -1) < 0))
69 {
70 //TODO:use elog infrastructure
71 errMsg << "Waiting for FIFO device:" << devPath << "to read failed"
72 << " rc=" << rc << " and errno=" << errno;
73 throw std::runtime_error(errMsg.str().c_str());
74 }
75 if (poll_fd.revents & POLLERR)
76 {
77 //TODO:use elog infrastructure
78 errMsg << "POLLERR while waiting for readable FIFO,errno:" << errno;
79 throw std::runtime_error(errMsg.str().c_str());
80 }
81 //Derive the total read length which should include the FFDC, which SBE
82 //returns in case of failure.
83 size_t totalReadLen = respBufLen + MAX_FFDC_LEN_IN_WORDS;
84 //Create a temporary buffer
85 std::vector<sbe_word_t> buffer(totalReadLen);
86
Benjamin Herrenschmidt0dc29322018-05-17 15:25:47 +100087 ssize_t bytesToRead = (totalReadLen * WORD_SIZE);
Murulidhar Nataraju06a0c2c2017-07-11 08:55:33 -050088 len = read(fileFd(), buffer.data(), bytesToRead);
89 if (len < 0)
90 {
91 //TODO:use elog infrastructure
92 errMsg << "Failed to read the FIFO device:" << devPath << "bytes read ="
93 << len << " errno=" << errno;
94 throw std::runtime_error(errMsg.str().c_str());
95 }
Murulidhar Nataraju06a0c2c2017-07-11 08:55:33 -050096
97 //Extract the valid number of words read.
Benjamin Herrenschmidtf2411562018-05-17 15:27:04 +100098 for (auto i = 0; i < (len / WORD_SIZE); ++i)
Murulidhar Nataraju06a0c2c2017-07-11 08:55:33 -050099 {
100 response.push_back(be32toh(buffer[i]));
101 }
102
103 //Closing of the file descriptor will be handled when the FileDescriptor
104 //object will go out of scope.
Murulidhar Nataraju1adec022017-04-20 12:05:51 -0500105 return response;
106}
107
Murulidhar Nataraju06a0c2c2017-07-11 08:55:33 -0500108void parseResponse(std::vector<sbe_word_t>& sbeDataBuf)
Murulidhar Nataraju1adec022017-04-20 12:05:51 -0500109{
Murulidhar Nataraju1adec022017-04-20 12:05:51 -0500110 //Number of 32-bit words obtained from the SBE
111 size_t lengthObtained = sbeDataBuf.size();
112
113 //Fetch the SBE header and SBE chiop primary and secondary status
114 //Last value in the buffer will have the offset for the SBE header
115 size_t distanceToStatusHeader = sbeDataBuf[sbeDataBuf.size() - 1];
116
117 if (lengthObtained < distanceToStatusHeader)
118 {
119 //TODO:use elog infrastructure
120 std::ostringstream errMsg;
121 errMsg << "Distance to SBE status header value " <<
Gunnar Mills12ef1d72018-04-08 15:01:59 -0500122 distanceToStatusHeader << " is greater then total length of "
Murulidhar Nataraju1adec022017-04-20 12:05:51 -0500123 "response buffer " << lengthObtained;
124 throw std::runtime_error(errMsg.str().c_str());
125 }
126
127 //Fetch the response header contents
Murulidhar Nataraju1adec022017-04-20 12:05:51 -0500128 auto iter = sbeDataBuf.begin();
129 std::advance(iter, (lengthObtained - distanceToStatusHeader));
Murulidhar Nataraju06a0c2c2017-07-11 08:55:33 -0500130
131 //First header word will have 2 bytes of MAGIC CODE followed by
132 //Command class and command type
133 //| MAGIC BYTES:0xCODE | COMMAND-CLASS | COMMAND-TYPE|
134 sbe_word_t l_magicCode = (*iter >> MAGIC_CODE_BITS);
Murulidhar Nataraju1adec022017-04-20 12:05:51 -0500135
136 //Fetch the primary and secondary response code
137 std::advance(iter, DISTANCE_TO_RESP_CODE);
138 auto l_priSecResp = *iter;
139
140 //Validate the magic code obtained in the response
Murulidhar Nataraju06a0c2c2017-07-11 08:55:33 -0500141 if (l_magicCode != MAGIC_CODE)
Murulidhar Nataraju1adec022017-04-20 12:05:51 -0500142 {
143 //TODO:use elog infrastructure
144 std::ostringstream errMsg;
145 errMsg << "Invalid MAGIC keyword in the response header (" <<
Murulidhar Nataraju06a0c2c2017-07-11 08:55:33 -0500146 l_magicCode << "),expected keyword " << MAGIC_CODE;
Murulidhar Nataraju1adec022017-04-20 12:05:51 -0500147 throw std::runtime_error(errMsg.str().c_str());
148 }
149
150 //Validate the Primary and Secondary response value
151 if (l_priSecResp != SBE_OPERATION_SUCCESSFUL)
152 {
153 //Extract the SBE FFDC and throw it to the caller
154 size_t ffdcLen = (distanceToStatusHeader -
Murulidhar Nataraju06a0c2c2017-07-11 08:55:33 -0500155 LENGTH_OF_RESP_HEADER_IN_WORDS -
Murulidhar Nataraju1adec022017-04-20 12:05:51 -0500156 LENGTH_OF_DISTANCE_HEADER_IN_WORDS);
157 if (ffdcLen)
158 {
159 std::vector<sbe_word_t> ffdcData(ffdcLen);
160 //Fetch the offset of FFDC data
161 auto ffdcOffset = (lengthObtained - distanceToStatusHeader) +
162 LENGTH_OF_RESP_HEADER_IN_WORDS;
163 std::copy_n((sbeDataBuf.begin() + ffdcOffset), ffdcLen,
164 ffdcData.begin());
165 }
166
167 //TODO:use elog infrastructure to return the SBE and Hardware procedure
168 //FFDC container back to the caller.
169 std::ostringstream errMsg;
170 errMsg << "Chip operation failed with SBE response code:" << l_priSecResp
171 << ".Length of FFDC data of obtained:" << ffdcLen;
172 throw std::runtime_error(errMsg.str().c_str());
173 }
Murulidhar Nataraju1adec022017-04-20 12:05:51 -0500174
Murulidhar Nataraju06a0c2c2017-07-11 08:55:33 -0500175 //In case of success, remove the response header content and send only the
176 //data.Response header will be towards the end of the buffer.
177 auto respLen = (lengthObtained - distanceToStatusHeader);
178 iter = sbeDataBuf.begin();
179 std::advance(iter,respLen);
180 sbeDataBuf.erase(iter, sbeDataBuf.end());
Murulidhar Nataraju1adec022017-04-20 12:05:51 -0500181}
182
183}
184}
185}