Ping?

Ashton Fagg <ash...@fagg.id.au> writes:

> I noticed this when looking through the nvme.c code the other day.
>
> Currently, nvme_poll() has a loop like this:
>
>       while (!ISSET(state.c.flags, htole16(NVME_CQE_PHASE))) {
>               if (nvme_q_complete(sc, q) == 0)
>                       delay(10);
>
>                 /* XXX no timeout? */ 
>       }
>
> The comment is indicative - there probably should be a timeout here in
> case things are terribly wrong and the queue never gets fully processed.
>
> NetBSD appears to have a similar construct in their version of the
> driver:
>
> https://github.com/NetBSD/src/blob/trunk/sys/dev/ic/nvme.c
>
> The following diff adds a counter to fail the poll after 10 seconds of
> spinning. I've been torturing my test machine (which has an nvme boot
> drive) with this applied - no issues so far.
>
> AFAICT, returning anything non-zero should be ok as it looks like
> nothing specifically checks the return code for anything other being
> zero. But, I may be wrong and perhaps one of the various NVME_CQE_*
> masks is more suitable.
>
> Thanks.

diff --git a/sys/dev/ic/nvme.c b/sys/dev/ic/nvme.c
index 9a79c8b1bfe..4e112f482ee 100644
--- a/sys/dev/ic/nvme.c
+++ b/sys/dev/ic/nvme.c
@@ -117,6 +117,11 @@ void	nvme_scsi_inquiry(struct scsi_xfer *);
 void	nvme_scsi_capacity16(struct scsi_xfer *);
 void	nvme_scsi_capacity(struct scsi_xfer *);
 
+/* Here, we define a delay of 10 microseconds between poll attempts.
+ * And, we allow 1e6 attempts. This corresponds to a ~10 second wait. */
+#define NVME_POLL_DELAY_USECS 10
+#define NVME_POLL_MAX_ATTEMPTS 1E6
+
 #define nvme_read4(_s, _r) \
 	bus_space_read_4((_s)->sc_iot, (_s)->sc_ioh, (_r))
 #define nvme_write4(_s, _r, _v) \
@@ -918,6 +923,7 @@ nvme_poll(struct nvme_softc *sc, struct nvme_queue *q, struct nvme_ccb *ccb,
 	void (*done)(struct nvme_softc *, struct nvme_ccb *, struct nvme_cqe *);
 	void *cookie;
 	u_int16_t flags;
+	int tries = 0;
 
 	memset(&state, 0, sizeof(state));
 	(*fill)(sc, ccb, &state.s);
@@ -931,9 +937,13 @@ nvme_poll(struct nvme_softc *sc, struct nvme_queue *q, struct nvme_ccb *ccb,
 	nvme_q_submit(sc, q, ccb, nvme_poll_fill);
 	while (!ISSET(state.c.flags, htole16(NVME_CQE_PHASE))) {
 		if (nvme_q_complete(sc, q) == 0)
-			delay(10);
+			delay(NVME_POLL_DELAY_USECS);
 
-		/* XXX no timeout? */
+		if (++tries >= NVME_POLL_MAX_ATTEMPTS) {
+			/* Something appears to be quite wrong... */
+			printf("%s: poll timeout.\n", DEVNAME(sc));
+			return (1);
+		}
 	}
 
 	ccb->ccb_cookie = cookie;

Reply via email to