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;