Module Name:    src
Committed By:   mlelstv
Date:           Tue Mar 19 16:56:29 UTC 2019

Modified Files:
        src/sys/dev/ata: wd.c

Log Message:
The NCQ support added a private request queue to the wd driver. This
makes the regular buffer queue ineffective, it also allowed to queue
an unlimited number of requests.

Fix this by limiting the number of requests queued to the driver to
the possible number of concurrent NCQ transactions.


To generate a diff of this commit:
cvs rdiff -u -r1.445 -r1.446 src/sys/dev/ata/wd.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/ata/wd.c
diff -u src/sys/dev/ata/wd.c:1.445 src/sys/dev/ata/wd.c:1.446
--- src/sys/dev/ata/wd.c:1.445	Tue Mar 19 06:51:05 2019
+++ src/sys/dev/ata/wd.c	Tue Mar 19 16:56:29 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: wd.c,v 1.445 2019/03/19 06:51:05 mlelstv Exp $ */
+/*	$NetBSD: wd.c,v 1.446 2019/03/19 16:56:29 mlelstv Exp $ */
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.  All rights reserved.
@@ -54,7 +54,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.445 2019/03/19 06:51:05 mlelstv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.446 2019/03/19 16:56:29 mlelstv Exp $");
 
 #include "opt_ata.h"
 #include "opt_wd.h"
@@ -321,6 +321,7 @@ wdattach(device_t parent, device_t self,
 	SLIST_INIT(&wd->sc_bslist);
 #endif
 	wd->atabus = adev->adev_bustype;
+	wd->inflight = 0;
 	wd->drvp = adev->adev_drv_data;
 
 	wd->drvp->drv_openings = 1;
@@ -729,6 +730,7 @@ wdstart1(struct wd_softc *wd, struct buf
 		xfer->c_bio.flags |= ATA_FUA;
 	}
 
+	wd->inflight++;
 	switch (wd->atabus->ata_bio(wd->drvp, xfer)) {
 	case ATACMD_TRY_AGAIN:
 		panic("wdstart1: try again");
@@ -749,10 +751,25 @@ wd_diskstart(device_t dev, struct buf *b
 	struct dk_softc *dksc = &wd->sc_dksc;
 #endif
 	struct ata_xfer *xfer;
+	struct ata_channel *chp;
+	unsigned openings;
 
 	mutex_enter(&wd->sc_lock);
 
-	xfer = ata_get_xfer(wd->drvp->chnl_softc, false);
+	chp = wd->drvp->chnl_softc;
+
+	ata_channel_lock(chp);
+	openings = ata_queue_openings(chp);
+	ata_channel_unlock(chp);
+
+	openings = uimin(openings, wd->drvp->drv_openings);
+
+	if (wd->inflight >= openings) {
+		mutex_exit(&wd->sc_lock);
+		return EAGAIN;
+	}
+
+	xfer = ata_get_xfer(chp, false);
 	if (xfer == NULL) {
 		ATADEBUG_PRINT(("wd_diskstart %s no xfer\n",
 		    dksc->sc_xname), DEBUG_XFERS);
@@ -952,7 +969,9 @@ noerror:	if ((xfer->c_bio.flags & ATA_CO
 
 	ata_free_xfer(wd->drvp->chnl_softc, xfer);
 
+	wd->inflight--;
 	dk_done(dksc, bp);
+	dk_start(dksc, NULL);
 }
 
 static void

Reply via email to