blob: dbed8747ced531dbf3c9eb5beb900690a7b62f33 [file] [log] [blame]
Patrick Ventureda79c9c2018-11-01 15:35:52 -07001#include <endian.h>
Murulidhar Nataraju06a0c2c2017-07-11 08:55:33 -05002#include <errno.h>
3#include <fcntl.h>
Murulidhar Nataraju06a0c2c2017-07-11 08:55:33 -05004#include <poll.h>
Patrick Ventureda79c9c2018-11-01 15:35:52 -07005#include <unistd.h>
6
7#include <array>
Murulidhar Nataraju06a0c2c2017-07-11 08:55:33 -05008#include <file.hpp>
Patrick Ventureda79c9c2018-11-01 15:35:52 -07009#include <sbe_chipOp_handler.hpp>
Murulidhar Nataraju1adec022017-04-20 12:05:51 -050010namespace openpower
11{
12namespace sbe
13{
14namespace internal
15{
Murulidhar Nataraju1adec022017-04-20 12:05:51 -050016
17constexpr uint16_t MAGIC_CODE = 0xC0DE;
18constexpr auto SBE_OPERATION_SUCCESSFUL = 0;
19constexpr auto LENGTH_OF_DISTANCE_HEADER_IN_WORDS = 0x1;
20constexpr auto LENGTH_OF_RESP_HEADER_IN_WORDS = 0x2;
Murulidhar Nataraju1adec022017-04-20 12:05:51 -050021constexpr auto DISTANCE_TO_RESP_CODE = 0x1;
Murulidhar Nataraju06a0c2c2017-07-11 08:55:33 -050022constexpr auto MAX_FFDC_LEN_IN_WORDS = 5120;
23constexpr auto WORD_SIZE = 4;
24constexpr auto MAGIC_CODE_BITS = 16;
25std::vector<sbe_word_t> writeToFifo(const char* devPath,
26 const sbe_word_t* cmdBuffer,
Patrick Ventureda79c9c2018-11-01 15:35:52 -070027 size_t cmdBufLen, 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
Patrick Ventureda79c9c2018-11-01 15:35:52 -070033 // Open the device and obtain the file descriptor associated with it.
Murulidhar Nataraju06a0c2c2017-07-11 08:55:33 -050034 FileDescriptor fileFd(devPath, (O_RDWR | O_NONBLOCK));
35
Patrick Ventureda79c9c2018-11-01 15:35:52 -070036 // Wait for FIFO device and perform write operation
Murulidhar Nataraju06a0c2c2017-07-11 08:55:33 -050037 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 {
Patrick Ventureda79c9c2018-11-01 15:35:52 -070044 // TODO:use elog infrastructure
Murulidhar Nataraju06a0c2c2017-07-11 08:55:33 -050045 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 {
Patrick Ventureda79c9c2018-11-01 15:35:52 -070051 // TODO:use elog infrastructure
Murulidhar Nataraju06a0c2c2017-07-11 08:55:33 -050052 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);
Patrick Ventureda79c9c2018-11-01 15:35:52 -070056 // Perform the write operation
Murulidhar Nataraju06a0c2c2017-07-11 08:55:33 -050057 len = write(fileFd(), cmdBuffer, bytesToWrite);
58 if (len < 0)
59 {
Patrick Ventureda79c9c2018-11-01 15:35:52 -070060 // TODO:use elog infrastructure
61 errMsg << "Failed to write to FIFO device:" << devPath
62 << " Length "
63 "returned= "
64 << len << " errno=" << errno;
Murulidhar Nataraju06a0c2c2017-07-11 08:55:33 -050065 throw std::runtime_error(errMsg.str().c_str());
66 }
Patrick Ventureda79c9c2018-11-01 15:35:52 -070067 // Wait for FIFO device and perform read operation
Murulidhar Nataraju06a0c2c2017-07-11 08:55:33 -050068 poll_fd.fd = fileFd();
69 poll_fd.events = POLLIN | POLLERR;
70 if ((rc = poll(&poll_fd, 1, -1) < 0))
71 {
Patrick Ventureda79c9c2018-11-01 15:35:52 -070072 // TODO:use elog infrastructure
Murulidhar Nataraju06a0c2c2017-07-11 08:55:33 -050073 errMsg << "Waiting for FIFO device:" << devPath << "to read failed"
74 << " rc=" << rc << " and errno=" << errno;
75 throw std::runtime_error(errMsg.str().c_str());
76 }
77 if (poll_fd.revents & POLLERR)
78 {
Patrick Ventureda79c9c2018-11-01 15:35:52 -070079 // TODO:use elog infrastructure
Murulidhar Nataraju06a0c2c2017-07-11 08:55:33 -050080 errMsg << "POLLERR while waiting for readable FIFO,errno:" << errno;
81 throw std::runtime_error(errMsg.str().c_str());
82 }
Patrick Ventureda79c9c2018-11-01 15:35:52 -070083 // Derive the total read length which should include the FFDC, which SBE
84 // returns in case of failure.
Murulidhar Nataraju06a0c2c2017-07-11 08:55:33 -050085 size_t totalReadLen = respBufLen + MAX_FFDC_LEN_IN_WORDS;
Patrick Ventureda79c9c2018-11-01 15:35:52 -070086 // Create a temporary buffer
Murulidhar Nataraju06a0c2c2017-07-11 08:55:33 -050087 std::vector<sbe_word_t> buffer(totalReadLen);
88
Benjamin Herrenschmidt0dc29322018-05-17 15:25:47 +100089 ssize_t bytesToRead = (totalReadLen * WORD_SIZE);
Murulidhar Nataraju06a0c2c2017-07-11 08:55:33 -050090 len = read(fileFd(), buffer.data(), bytesToRead);
91 if (len < 0)
92 {
Patrick Ventureda79c9c2018-11-01 15:35:52 -070093 // TODO:use elog infrastructure
94 errMsg << "Failed to read the FIFO device:" << devPath
95 << "bytes read =" << len << " errno=" << errno;
Murulidhar Nataraju06a0c2c2017-07-11 08:55:33 -050096 throw std::runtime_error(errMsg.str().c_str());
97 }
Murulidhar Nataraju06a0c2c2017-07-11 08:55:33 -050098
Patrick Ventureda79c9c2018-11-01 15:35:52 -070099 // Extract the valid number of words read.
Benjamin Herrenschmidtf2411562018-05-17 15:27:04 +1000100 for (auto i = 0; i < (len / WORD_SIZE); ++i)
Murulidhar Nataraju06a0c2c2017-07-11 08:55:33 -0500101 {
102 response.push_back(be32toh(buffer[i]));
103 }
104
Patrick Ventureda79c9c2018-11-01 15:35:52 -0700105 // Closing of the file descriptor will be handled when the FileDescriptor
106 // object will go out of scope.
Murulidhar Nataraju1adec022017-04-20 12:05:51 -0500107 return response;
108}
109
Murulidhar Nataraju06a0c2c2017-07-11 08:55:33 -0500110void parseResponse(std::vector<sbe_word_t>& sbeDataBuf)
Murulidhar Nataraju1adec022017-04-20 12:05:51 -0500111{
Patrick Ventureda79c9c2018-11-01 15:35:52 -0700112 // Number of 32-bit words obtained from the SBE
Murulidhar Nataraju1adec022017-04-20 12:05:51 -0500113 size_t lengthObtained = sbeDataBuf.size();
114
Patrick Ventureda79c9c2018-11-01 15:35:52 -0700115 // Fetch the SBE header and SBE chiop primary and secondary status
116 // Last value in the buffer will have the offset for the SBE header
117 size_t distanceToStatusHeader = sbeDataBuf[sbeDataBuf.size() - 1];
Murulidhar Nataraju1adec022017-04-20 12:05:51 -0500118
119 if (lengthObtained < distanceToStatusHeader)
120 {
Patrick Ventureda79c9c2018-11-01 15:35:52 -0700121 // TODO:use elog infrastructure
Murulidhar Nataraju1adec022017-04-20 12:05:51 -0500122 std::ostringstream errMsg;
Patrick Ventureda79c9c2018-11-01 15:35:52 -0700123 errMsg << "Distance to SBE status header value "
124 << distanceToStatusHeader
125 << " is greater then total length of "
126 "response buffer "
127 << lengthObtained;
Murulidhar Nataraju1adec022017-04-20 12:05:51 -0500128 throw std::runtime_error(errMsg.str().c_str());
129 }
130
Patrick Ventureda79c9c2018-11-01 15:35:52 -0700131 // Fetch the response header contents
Murulidhar Nataraju1adec022017-04-20 12:05:51 -0500132 auto iter = sbeDataBuf.begin();
133 std::advance(iter, (lengthObtained - distanceToStatusHeader));
Murulidhar Nataraju06a0c2c2017-07-11 08:55:33 -0500134
Patrick Ventureda79c9c2018-11-01 15:35:52 -0700135 // First header word will have 2 bytes of MAGIC CODE followed by
136 // Command class and command type
Murulidhar Nataraju06a0c2c2017-07-11 08:55:33 -0500137 //| MAGIC BYTES:0xCODE | COMMAND-CLASS | COMMAND-TYPE|
138 sbe_word_t l_magicCode = (*iter >> MAGIC_CODE_BITS);
Murulidhar Nataraju1adec022017-04-20 12:05:51 -0500139
Patrick Ventureda79c9c2018-11-01 15:35:52 -0700140 // Fetch the primary and secondary response code
Murulidhar Nataraju1adec022017-04-20 12:05:51 -0500141 std::advance(iter, DISTANCE_TO_RESP_CODE);
142 auto l_priSecResp = *iter;
143
Patrick Ventureda79c9c2018-11-01 15:35:52 -0700144 // Validate the magic code obtained in the response
Murulidhar Nataraju06a0c2c2017-07-11 08:55:33 -0500145 if (l_magicCode != MAGIC_CODE)
Murulidhar Nataraju1adec022017-04-20 12:05:51 -0500146 {
Patrick Ventureda79c9c2018-11-01 15:35:52 -0700147 // TODO:use elog infrastructure
Murulidhar Nataraju1adec022017-04-20 12:05:51 -0500148 std::ostringstream errMsg;
Patrick Ventureda79c9c2018-11-01 15:35:52 -0700149 errMsg << "Invalid MAGIC keyword in the response header ("
150 << l_magicCode << "),expected keyword " << MAGIC_CODE;
Murulidhar Nataraju1adec022017-04-20 12:05:51 -0500151 throw std::runtime_error(errMsg.str().c_str());
152 }
153
Patrick Ventureda79c9c2018-11-01 15:35:52 -0700154 // Validate the Primary and Secondary response value
Murulidhar Nataraju1adec022017-04-20 12:05:51 -0500155 if (l_priSecResp != SBE_OPERATION_SUCCESSFUL)
156 {
Patrick Ventureda79c9c2018-11-01 15:35:52 -0700157 // Extract the SBE FFDC and throw it to the caller
158 size_t ffdcLen =
159 (distanceToStatusHeader - LENGTH_OF_RESP_HEADER_IN_WORDS -
160 LENGTH_OF_DISTANCE_HEADER_IN_WORDS);
Murulidhar Nataraju1adec022017-04-20 12:05:51 -0500161 if (ffdcLen)
162 {
163 std::vector<sbe_word_t> ffdcData(ffdcLen);
Patrick Ventureda79c9c2018-11-01 15:35:52 -0700164 // Fetch the offset of FFDC data
Murulidhar Nataraju1adec022017-04-20 12:05:51 -0500165 auto ffdcOffset = (lengthObtained - distanceToStatusHeader) +
166 LENGTH_OF_RESP_HEADER_IN_WORDS;
167 std::copy_n((sbeDataBuf.begin() + ffdcOffset), ffdcLen,
168 ffdcData.begin());
169 }
170
Patrick Ventureda79c9c2018-11-01 15:35:52 -0700171 // TODO:use elog infrastructure to return the SBE and Hardware procedure
172 // FFDC container back to the caller.
Murulidhar Nataraju1adec022017-04-20 12:05:51 -0500173 std::ostringstream errMsg;
Patrick Ventureda79c9c2018-11-01 15:35:52 -0700174 errMsg << "Chip operation failed with SBE response code:"
175 << l_priSecResp
Murulidhar Nataraju1adec022017-04-20 12:05:51 -0500176 << ".Length of FFDC data of obtained:" << ffdcLen;
177 throw std::runtime_error(errMsg.str().c_str());
178 }
Murulidhar Nataraju1adec022017-04-20 12:05:51 -0500179
Patrick Ventureda79c9c2018-11-01 15:35:52 -0700180 // In case of success, remove the response header content and send only the
181 // data.Response header will be towards the end of the buffer.
Murulidhar Nataraju06a0c2c2017-07-11 08:55:33 -0500182 auto respLen = (lengthObtained - distanceToStatusHeader);
183 iter = sbeDataBuf.begin();
Patrick Ventureda79c9c2018-11-01 15:35:52 -0700184 std::advance(iter, respLen);
Murulidhar Nataraju06a0c2c2017-07-11 08:55:33 -0500185 sbeDataBuf.erase(iter, sbeDataBuf.end());
Murulidhar Nataraju1adec022017-04-20 12:05:51 -0500186}
187
Patrick Ventureda79c9c2018-11-01 15:35:52 -0700188} // namespace internal
189} // namespace sbe
190} // namespace openpower