Module Name:    src
Committed By:   jdolecek
Date:           Sat Sep 22 17:50:09 UTC 2018

Modified Files:
        src/sys/dev/ata [jdolecek-ncqfixes]: TODO.ncq ata_subr.c atavar.h wd.c
            wdvar.h

Log Message:
remove explicit ata_channel_start() calls, it's no longer necessary
now that ata_xfer's are allocated via pool and not really limited;
replace by just a callout to restart the processing for rare cases
where system runs out of memory


To generate a diff of this commit:
cvs rdiff -u -r1.4.2.6 -r1.4.2.7 src/sys/dev/ata/TODO.ncq
cvs rdiff -u -r1.6.2.5 -r1.6.2.6 src/sys/dev/ata/ata_subr.c
cvs rdiff -u -r1.99.2.6 -r1.99.2.7 src/sys/dev/ata/atavar.h
cvs rdiff -u -r1.441.2.5 -r1.441.2.6 src/sys/dev/ata/wd.c
cvs rdiff -u -r1.46.6.3 -r1.46.6.4 src/sys/dev/ata/wdvar.h

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/TODO.ncq
diff -u src/sys/dev/ata/TODO.ncq:1.4.2.6 src/sys/dev/ata/TODO.ncq:1.4.2.7
--- src/sys/dev/ata/TODO.ncq:1.4.2.6	Sat Sep 22 16:14:25 2018
+++ src/sys/dev/ata/TODO.ncq	Sat Sep 22 17:50:09 2018
@@ -1,6 +1,4 @@
 jdolecek-ncqfixes goals:
-- add to wd(4) a callout to restart buf queue processing when ata_get_xfer()
-  call fails and remove ata_channel_start()
 - re-fix QEMU ahci(4) bug workaround (no READ LOG EXT support) - now it
   triggers KASSERT()
 - fix ahci(4) error handling under paralles - invalid bio via WD_CHAOS_MONKEY

Index: src/sys/dev/ata/ata_subr.c
diff -u src/sys/dev/ata/ata_subr.c:1.6.2.5 src/sys/dev/ata/ata_subr.c:1.6.2.6
--- src/sys/dev/ata/ata_subr.c:1.6.2.5	Sat Sep 22 09:22:59 2018
+++ src/sys/dev/ata/ata_subr.c	Sat Sep 22 17:50:09 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: ata_subr.c,v 1.6.2.5 2018/09/22 09:22:59 jdolecek Exp $	*/
+/*	$NetBSD: ata_subr.c,v 1.6.2.6 2018/09/22 17:50:09 jdolecek Exp $	*/
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.  All rights reserved.
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ata_subr.c,v 1.6.2.5 2018/09/22 09:22:59 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ata_subr.c,v 1.6.2.6 2018/09/22 17:50:09 jdolecek Exp $");
 
 #include "opt_ata.h"
 
@@ -257,54 +257,6 @@ ata_timeout(void *v)
 	splx(s);
 }
 
-/*
- * Must be called without any locks, i.e. with both drive and channel locks
- * released.
- */ 
-void
-ata_channel_start(struct ata_channel *chp, int drive, bool start_self)
-{
-	int i, s;
-	struct ata_drive_datas *drvp;
-
-	s = splbio();
-
-	KASSERT(chp->ch_ndrives > 0);
-
-#define ATA_DRIVE_START(chp, drive) \
-	do {							\
-		KASSERT(drive < chp->ch_ndrives);		\
-		drvp = &chp->ch_drive[drive];			\
-								\
-		if (drvp->drive_type != ATA_DRIVET_ATA &&	\
-		    drvp->drive_type != ATA_DRIVET_ATAPI &&	\
-		    drvp->drive_type != ATA_DRIVET_OLD)		\
-			continue;				\
-								\
-		if (drvp->drv_start != NULL)			\
-			(*drvp->drv_start)(drvp->drv_softc);	\
-	} while (0)
-
-	/*
-	 * Process drives in round robin fashion starting with next one after
-	 * the one which finished transfer. Thus no single drive would
-	 * completely starve other drives on same channel. 
-	 * This loop processes all but the current drive, so won't do anything
-	 * if there is only one drive in channel.
-	 */
-	for (i = (drive + 1) % chp->ch_ndrives; i != drive;
-	    i = (i + 1) % chp->ch_ndrives) {
-		ATA_DRIVE_START(chp, i);
-	}
-
-	/* Now try to kick off xfers on the current drive */
-	if (start_self)
-		ATA_DRIVE_START(chp, drive);
-
-	splx(s);
-#undef ATA_DRIVE_START
-}
-
 void
 ata_channel_lock(struct ata_channel *chp)
 {

Index: src/sys/dev/ata/atavar.h
diff -u src/sys/dev/ata/atavar.h:1.99.2.6 src/sys/dev/ata/atavar.h:1.99.2.7
--- src/sys/dev/ata/atavar.h:1.99.2.6	Sat Sep 22 16:14:25 2018
+++ src/sys/dev/ata/atavar.h	Sat Sep 22 17:50:09 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: atavar.h,v 1.99.2.6 2018/09/22 16:14:25 jdolecek Exp $	*/
+/*	$NetBSD: atavar.h,v 1.99.2.7 2018/09/22 17:50:09 jdolecek Exp $	*/
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.
@@ -327,7 +327,6 @@ struct ata_drive_datas {
 
 	/* Callbacks into the drive's driver. */
 	void	(*drv_done)(device_t, struct ata_xfer *); /* xfer is done */
-	void	(*drv_start)(device_t);			  /* start queue */
 
 	device_t drv_softc;		/* ATA drives softc, if any */
 	struct ata_channel *chnl_softc;	/* channel softc */
@@ -547,7 +546,6 @@ void	ata_kill_active(struct ata_channel 
 void	ata_reset_channel(struct ata_channel *, int);
 void	ata_channel_freeze(struct ata_channel *);
 void	ata_channel_thaw(struct ata_channel *);
-void	ata_channel_start(struct ata_channel *, int, bool);
 void	ata_channel_lock(struct ata_channel *);
 void	ata_channel_unlock(struct ata_channel *);
 void	ata_channel_lock_owned(struct ata_channel *);

Index: src/sys/dev/ata/wd.c
diff -u src/sys/dev/ata/wd.c:1.441.2.5 src/sys/dev/ata/wd.c:1.441.2.6
--- src/sys/dev/ata/wd.c:1.441.2.5	Sat Sep 22 16:14:25 2018
+++ src/sys/dev/ata/wd.c	Sat Sep 22 17:50:09 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: wd.c,v 1.441.2.5 2018/09/22 16:14:25 jdolecek Exp $ */
+/*	$NetBSD: wd.c,v 1.441.2.6 2018/09/22 17:50:09 jdolecek 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.441.2.5 2018/09/22 16:14:25 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.441.2.6 2018/09/22 17:50:09 jdolecek Exp $");
 
 #include "opt_ata.h"
 #include "opt_wd.h"
@@ -192,7 +192,7 @@ static void	wi_free(struct wd_ioctl *);
 static struct	wd_ioctl *wi_get(struct wd_softc *);
 static void	wdioctlstrategy(struct buf *);
 
-static void	wdstart(device_t);
+static void	wdrestart(void *);
 static void	wdstart1(struct wd_softc *, struct buf *, struct ata_xfer *);
 static int	wd_diskstart(device_t, struct buf *);
 static int	wd_dumpblocks(device_t, void *, daddr_t, int);
@@ -324,7 +324,6 @@ wdattach(device_t parent, device_t self,
 	wd->drvp = adev->adev_drv_data;
 
 	wd->drvp->drv_openings = 1;
-	wd->drvp->drv_start = wdstart;
 	wd->drvp->drv_done = wddone;
 	wd->drvp->drv_softc = dksc->sc_dev; /* done in atabusconfig_thread()
 					     but too late */
@@ -333,6 +332,7 @@ wdattach(device_t parent, device_t self,
 	SLIST_INIT(&wd->sc_requeue_list);
 	callout_init(&wd->sc_retry_callout, 0);		/* XXX MPSAFE */
 	callout_init(&wd->sc_requeue_callout, 0);	/* XXX MPSAFE */
+	callout_init(&wd->sc_restart_diskqueue, 0);	/* XXX MPSAFE */
 
 	aprint_naive("\n");
 	aprint_normal("\n");
@@ -527,6 +527,8 @@ wddetach(device_t self, int flags)
 	callout_destroy(&wd->sc_retry_callout);
 	callout_halt(&wd->sc_requeue_callout, &wd->sc_lock);
 	callout_destroy(&wd->sc_requeue_callout);
+	callout_halt(&wd->sc_restart_diskqueue, &wd->sc_lock);
+	callout_destroy(&wd->sc_restart_diskqueue);
 
 	mutex_exit(&wd->sc_lock);
 
@@ -749,6 +751,17 @@ wd_diskstart(device_t dev, struct buf *b
 	if (xfer == NULL) {
 		ATADEBUG_PRINT(("wd_diskstart %s no xfer\n",
 		    dksc->sc_xname), DEBUG_XFERS);
+
+		/*
+		 * No available memory, retry later. This happens very rarely
+		 * and only under memory pressure, so wait relatively long
+		 * before retry.
+		 */
+		if (!callout_pending(&wd->sc_restart_diskqueue)) {
+			callout_reset(&wd->sc_restart_diskqueue, hz / 2,
+			    wdrestart, dev);
+		}
+
 		mutex_exit(&wd->sc_lock);
 		return EAGAIN;
 	}
@@ -764,8 +777,9 @@ wd_diskstart(device_t dev, struct buf *b
  * Queue a drive for I/O.
  */
 static void
-wdstart(device_t self)
+wdrestart(void *x)
 {
+	device_t self = x;
 	struct wd_softc *wd = device_private(self);
 	struct dk_softc *dksc = &wd->sc_dksc;
 
@@ -919,7 +933,6 @@ noerror:	if ((xfer->c_bio.flags & ATA_CO
 	ata_free_xfer(wd->drvp->chnl_softc, xfer);
 
 	dk_done(dksc, bp);
-	ata_channel_start(wd->drvp->chnl_softc, wd->drvp->drive, true);
 }
 
 static void
@@ -1687,7 +1700,6 @@ wd_setcache(struct wd_softc *wd, int bit
 
 out:
 	ata_free_xfer(wd->drvp->chnl_softc, xfer);
-	ata_channel_start(wd->drvp->chnl_softc, wd->drvp->drive, true);
 	return error;
 }
 
@@ -1729,13 +1741,6 @@ wd_standby(struct wd_softc *wd, int flag
 
 out:
 	ata_free_xfer(wd->drvp->chnl_softc, xfer);
-
-	/*
-	 * Drive is supposed to go idle, start only other drives.
-	 * bufq might be actually already freed at this moment.
-	 */
-	ata_channel_start(wd->drvp->chnl_softc, wd->drvp->drive, false);
-
 	return error;
 }
 
@@ -1792,10 +1797,6 @@ wd_flushcache(struct wd_softc *wd, int f
 
 out_xfer:
 	ata_free_xfer(wd->drvp->chnl_softc, xfer);
-
-	/* start again I/O processing possibly stopped due to no xfer */
-	ata_channel_start(wd->drvp->chnl_softc, wd->drvp->drive, start_self);
-
 	return error;
 }
 
@@ -1855,7 +1856,6 @@ wd_trim(struct wd_softc *wd, daddr_t bno
 
 out:
 	ata_free_xfer(wd->drvp->chnl_softc, xfer);
-	ata_channel_start(wd->drvp->chnl_softc, wd->drvp->drive, true);
 	return error;
 }
 
@@ -2062,8 +2062,6 @@ wdioctlstrategy(struct buf *bp)
 
 out:
 	ata_free_xfer(wi->wi_softc->drvp->chnl_softc, xfer);
-	ata_channel_start(wi->wi_softc->drvp->chnl_softc,
-	    wi->wi_softc->drvp->drive, true);
 out2:
 	bp->b_error = error;
 	if (error)

Index: src/sys/dev/ata/wdvar.h
diff -u src/sys/dev/ata/wdvar.h:1.46.6.3 src/sys/dev/ata/wdvar.h:1.46.6.4
--- src/sys/dev/ata/wdvar.h:1.46.6.3	Sat Sep 22 16:14:25 2018
+++ src/sys/dev/ata/wdvar.h	Sat Sep 22 17:50:09 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: wdvar.h,v 1.46.6.3 2018/09/22 16:14:25 jdolecek Exp $	*/
+/*	$NetBSD: wdvar.h,v 1.46.6.4 2018/09/22 17:50:09 jdolecek Exp $	*/
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.
@@ -67,6 +67,7 @@ struct wd_softc {
 	/* Retry/requeue failed transfers */
 	SLIST_HEAD(, ata_xfer) sc_retry_list;
 	struct callout sc_retry_callout;	/* retry callout handle */
+	struct callout sc_restart_diskqueue;	/* restart queue processing */
 
 	SLIST_HEAD(, ata_xfer) sc_requeue_list;
 	struct callout sc_requeue_callout;	/* requeue callout handle */

Reply via email to