1 #include <array> 2 #include <errno.h> 3 #include <fcntl.h> 4 #include <unistd.h> 5 #include <poll.h> 6 #include <endian.h> 7 #include <sbe_chipOp_handler.hpp> 8 #include <file.hpp> 9 namespace openpower 10 { 11 namespace sbe 12 { 13 namespace internal 14 { 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; 20 constexpr auto DISTANCE_TO_RESP_CODE = 0x1; 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) 28 { 29 ssize_t len = 0; 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 87 ssize_t bytesToRead = (totalReadLen * WORD_SIZE); 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 } 96 97 //Extract the valid number of words read. 98 for (auto i = 0; i < (len / WORD_SIZE); ++i) 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. 105 return response; 106 } 107 108 void parseResponse(std::vector<sbe_word_t>& sbeDataBuf) 109 { 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 " << 122 distanceToStatusHeader << " is greater then total length of " 123 "response buffer " << lengthObtained; 124 throw std::runtime_error(errMsg.str().c_str()); 125 } 126 127 //Fetch the response header contents 128 auto iter = sbeDataBuf.begin(); 129 std::advance(iter, (lengthObtained - distanceToStatusHeader)); 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); 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 141 if (l_magicCode != MAGIC_CODE) 142 { 143 //TODO:use elog infrastructure 144 std::ostringstream errMsg; 145 errMsg << "Invalid MAGIC keyword in the response header (" << 146 l_magicCode << "),expected keyword " << MAGIC_CODE; 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 - 155 LENGTH_OF_RESP_HEADER_IN_WORDS - 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 } 174 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()); 181 } 182 183 } 184 } 185 } 186