Murulidhar Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 1 | #include <array> |
Murulidhar Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 2 | #include <errno.h> |
| 3 | #include <fcntl.h> |
| 4 | #include <unistd.h> |
| 5 | #include <poll.h> |
| 6 | #include <endian.h> |
Murulidhar Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 7 | #include <sbe_chipOp_handler.hpp> |
Murulidhar Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 8 | #include <file.hpp> |
Murulidhar Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 9 | namespace openpower |
| 10 | { |
| 11 | namespace sbe |
| 12 | { |
| 13 | namespace internal |
| 14 | { |
Murulidhar Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 15 | |
| 16 | constexpr uint16_t MAGIC_CODE = 0xC0DE; |
| 17 | constexpr auto SBE_OPERATION_SUCCESSFUL = 0; |
| 18 | constexpr auto LENGTH_OF_DISTANCE_HEADER_IN_WORDS = 0x1; |
| 19 | constexpr auto LENGTH_OF_RESP_HEADER_IN_WORDS = 0x2; |
Murulidhar Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 20 | constexpr auto DISTANCE_TO_RESP_CODE = 0x1; |
Murulidhar Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 21 | constexpr auto MAX_FFDC_LEN_IN_WORDS = 5120; |
| 22 | constexpr auto WORD_SIZE = 4; |
| 23 | constexpr auto MAGIC_CODE_BITS = 16; |
| 24 | std::vector<sbe_word_t> writeToFifo(const char* devPath, |
| 25 | const sbe_word_t* cmdBuffer, |
| 26 | size_t cmdBufLen, |
| 27 | size_t respBufLen) |
Murulidhar Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 28 | { |
Benjamin Herrenschmidt | 0dc2932 | 2018-05-17 15:25:47 +1000 | [diff] [blame] | 29 | ssize_t len = 0; |
Murulidhar Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 30 | 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 Herrenschmidt | 0dc2932 | 2018-05-17 15:25:47 +1000 | [diff] [blame] | 87 | ssize_t bytesToRead = (totalReadLen * WORD_SIZE); |
Murulidhar Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 88 | 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 Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 96 | |
| 97 | //Extract the valid number of words read. |
Benjamin Herrenschmidt | f241156 | 2018-05-17 15:27:04 +1000 | [diff] [blame] | 98 | for (auto i = 0; i < (len / WORD_SIZE); ++i) |
Murulidhar Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 99 | { |
| 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 Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 105 | return response; |
| 106 | } |
| 107 | |
Murulidhar Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 108 | void parseResponse(std::vector<sbe_word_t>& sbeDataBuf) |
Murulidhar Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 109 | { |
Murulidhar Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 110 | //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 Mills | 12ef1d7 | 2018-04-08 15:01:59 -0500 | [diff] [blame] | 122 | distanceToStatusHeader << " is greater then total length of " |
Murulidhar Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 123 | "response buffer " << lengthObtained; |
| 124 | throw std::runtime_error(errMsg.str().c_str()); |
| 125 | } |
| 126 | |
| 127 | //Fetch the response header contents |
Murulidhar Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 128 | auto iter = sbeDataBuf.begin(); |
| 129 | std::advance(iter, (lengthObtained - distanceToStatusHeader)); |
Murulidhar Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 130 | |
| 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 Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 135 | |
| 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 Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 141 | if (l_magicCode != MAGIC_CODE) |
Murulidhar Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 142 | { |
| 143 | //TODO:use elog infrastructure |
| 144 | std::ostringstream errMsg; |
| 145 | errMsg << "Invalid MAGIC keyword in the response header (" << |
Murulidhar Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 146 | l_magicCode << "),expected keyword " << MAGIC_CODE; |
Murulidhar Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 147 | 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 Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 155 | LENGTH_OF_RESP_HEADER_IN_WORDS - |
Murulidhar Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 156 | 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 Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 174 | |
Murulidhar Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 175 | //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 Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 181 | } |
| 182 | |
| 183 | } |
| 184 | } |
| 185 | } |