1212#include <stdlib.h>
1313#include <unistd.h>
1414
15+ #include <sys/poll.h>
1516#include <sys/socket.h>
1617#include <sys/types.h>
1718#include <sys/uio.h>
@@ -94,6 +95,7 @@ static struct __mi_mctp_socket_ops ops = {
9495 socket ,
9596 sendmsg ,
9697 recvmsg ,
98+ poll ,
9799 ioctl_tag ,
98100};
99101
@@ -166,16 +168,27 @@ static void nvme_mi_mctp_tag_drop(struct nvme_mi_ep *ep, __u8 tag)
166168
167169#endif /* !defined SIOMCTPTAGALLOC */
168170
169- static bool nvme_mi_mctp_resp_is_mpr (struct nvme_mi_resp * resp , size_t len )
171+ struct nvme_mi_msg_resp_mpr {
172+ struct nvme_mi_msg_hdr hdr ;
173+ __u8 status ;
174+ __u8 rsvd0 ;
175+ __u16 mprt ;
176+ };
177+
178+ /* Check if this response was a More Processing Required response; if so,
179+ * populate the worst-case expected processing time, given in milliseconds.
180+ */
181+ static bool nvme_mi_mctp_resp_is_mpr (struct nvme_mi_resp * resp , size_t len ,
182+ unsigned int * mpr_time )
170183{
171- struct nvme_mi_msg_resp * msg ;
184+ struct nvme_mi_msg_resp_mpr * msg ;
172185 __le32 mic ;
173186 __u32 crc ;
174187
175188 if (len != sizeof (* msg ) + sizeof (mic ))
176189 return false;
177190
178- msg = (struct nvme_mi_msg_resp * )resp -> hdr ;
191+ msg = (struct nvme_mi_msg_resp_mpr * )resp -> hdr ;
179192
180193 if (msg -> status != NVME_MI_RESP_MPR )
181194 return false;
@@ -199,6 +212,9 @@ static bool nvme_mi_mctp_resp_is_mpr(struct nvme_mi_resp *resp, size_t len)
199212 if (le32_to_cpu (mic ) != crc )
200213 return false;
201214
215+ if (mpr_time )
216+ * mpr_time = cpu_to_le16 (msg -> mprt ) * 100 ;
217+
202218 return true;
203219}
204220
@@ -209,8 +225,10 @@ static int nvme_mi_mctp_submit(struct nvme_mi_ep *ep,
209225 struct nvme_mi_transport_mctp * mctp ;
210226 struct iovec req_iov [3 ], resp_iov [3 ];
211227 struct msghdr req_msg , resp_msg ;
228+ int i , rc , errno_save , timeout ;
212229 struct sockaddr_mctp addr ;
213- int i , rc , errno_save ;
230+ struct pollfd pollfds [1 ];
231+ unsigned int mpr_time ;
214232 ssize_t len ;
215233 __le32 mic ;
216234 __u8 tag ;
@@ -283,9 +301,29 @@ static int nvme_mi_mctp_submit(struct nvme_mi_ep *ep,
283301 resp_msg .msg_iov = resp_iov ;
284302 resp_msg .msg_iovlen = 3 ;
285303
304+ pollfds [0 ].fd = mctp -> sd ;
305+ pollfds [0 ].events = POLLIN ;
306+ timeout = ep -> timeout ?: -1 ;
286307retry :
308+ rc = ops .poll (pollfds , 1 , timeout );
309+ if (rc < 0 ) {
310+ if (errno == EINTR )
311+ goto retry ;
312+ errno_save = errno ;
313+ nvme_msg (ep -> root , LOG_ERR ,
314+ "Failed polling on MCTP socket: %m" );
315+ errno = errno_save ;
316+ return -1 ;
317+ }
318+
319+ if (rc == 0 ) {
320+ nvme_msg (ep -> root , LOG_DEBUG , "Timeout on MCTP socket" );
321+ errno = ETIMEDOUT ;
322+ return -1 ;
323+ }
324+
287325 rc = -1 ;
288- len = ops .recvmsg (mctp -> sd , & resp_msg , 0 );
326+ len = ops .recvmsg (mctp -> sd , & resp_msg , MSG_DONTWAIT );
289327
290328 if (len < 0 ) {
291329 errno_save = errno ;
@@ -331,11 +369,20 @@ static int nvme_mi_mctp_submit(struct nvme_mi_ep *ep,
331369 * header fields. However, we need to do this in the transport in order
332370 * to keep the tag allocated and retry the recvmsg
333371 */
334- if (nvme_mi_mctp_resp_is_mpr (resp , len )) {
372+ if (nvme_mi_mctp_resp_is_mpr (resp , len , & mpr_time )) {
335373 nvme_msg (ep -> root , LOG_DEBUG ,
336374 "Received More Processing Required, waiting for response\n" );
337- /* TODO: when we implement timeouts, inspect the MPR response
338- * for the estimated completion time. */
375+
376+ /* if the controller hasn't set MPRT, fall back to our command/
377+ * response timeout, or the largest possible MPRT if none set */
378+ if (!mpr_time )
379+ mpr_time = ep -> timeout ?: 0xffff ;
380+
381+ /* clamp to the endpoint max */
382+ if (ep -> mprt_max && mpr_time > ep -> mprt_max )
383+ mpr_time = ep -> mprt_max ;
384+
385+ timeout = mpr_time ;
339386 goto retry ;
340387 }
341388
@@ -434,6 +481,13 @@ nvme_mi_ep_t nvme_mi_open_mctp(nvme_root_t root, unsigned int netid, __u8 eid)
434481 ep -> transport = & nvme_mi_transport_mctp ;
435482 ep -> transport_data = mctp ;
436483
484+ /* Assuming an i2c transport at 100kHz, smallest MTU (64+4). Given
485+ * a worst-case clock stretch, and largest-sized packets, we can
486+ * expect up to 1.6s per command/response pair. Allowing for a
487+ * retry or two (handled by lower layers), 5s is a reasonable timeout.
488+ */
489+ ep -> timeout = 5000 ;
490+
437491 return ep ;
438492
439493err_free_ep :
0 commit comments