tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: Interrupt storm mitigation needed



Joerg Sonnenberger <joerg%britannica.bec.de@localhost> writes:

> Just in case others run into it, you can put the patch you are running
> into GNATS?

Yes, of course.  Should I submit it as a bug report with a known
workaround, and then you (or someone) close it as a "won't fix",
thus leaving it saved and searchable?

I've already shared it with one other person who needed it, btw.

Oh, and as a side effect of all this, I'm also running a version of the
amr driver that I've updated to use mutexes and condvars instead of
spl...() calls, and to add a couple of bugfixes from FreeBSD.  (It's not
in synch with FreeBSD; I just picked the easily understood changes.)

In addition to the mutexes and condvars, it adds a simple watchdog
thread for the newer versions of the hardware, makes it tickle the
controller at task submission time if it seems not ready (from FreeBSD),
adds a buffer allocation size hack to the ioctl handler, to work around
a firmware bug in some versions of the controller (also from FreeBSD),
and rearranges the bus_dmamap_sync() calls to make the use match the
documentation.

Diff appended below, if someone wants to take a look at it.

-tih

Index: sys/dev/pci/amr.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/amr.c,v
retrieving revision 1.58
diff -u -r1.58 amr.c
--- sys/dev/pci/amr.c	25 Jul 2014 08:10:38 -0000	1.58
+++ sys/dev/pci/amr.c	2 Mar 2015 12:47:22 -0000
@@ -77,6 +77,8 @@
 #include <sys/conf.h>
 #include <sys/kthread.h>
 #include <sys/kauth.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
 
 #include <machine/endian.h>
 #include <sys/bus.h>
@@ -100,7 +102,8 @@
 static int	amr_print(void *, const char *);
 static void	amr_shutdown(void *);
 static void	amr_teardown(struct amr_softc *);
-static void	amr_thread(void *);
+static void	amr_quartz_thread(void *);
+static void	amr_std_thread(void *);
 
 static int	amr_quartz_get_work(struct amr_softc *,
 				    struct amr_mailbox_resp *);
@@ -186,13 +189,15 @@
 
 static void	*amr_sdh;
 
+static kcondvar_t thread_cv;
+static kmutex_t	thread_mutex;
+
 static int	amr_max_segs;
 int		amr_max_xfer;
 
 static inline u_int8_t
 amr_inb(struct amr_softc *amr, int off)
 {
-
 	bus_space_barrier(amr->amr_iot, amr->amr_ioh, off, 1,
 	    BUS_SPACE_BARRIER_WRITE | BUS_SPACE_BARRIER_READ);
 	return (bus_space_read_1(amr->amr_iot, amr->amr_ioh, off));
@@ -201,7 +206,6 @@
 static inline u_int32_t
 amr_inl(struct amr_softc *amr, int off)
 {
-
 	bus_space_barrier(amr->amr_iot, amr->amr_ioh, off, 4,
 	    BUS_SPACE_BARRIER_WRITE | BUS_SPACE_BARRIER_READ);
 	return (bus_space_read_4(amr->amr_iot, amr->amr_ioh, off));
@@ -210,7 +214,6 @@
 static inline void
 amr_outb(struct amr_softc *amr, int off, u_int8_t val)
 {
-
 	bus_space_write_1(amr->amr_iot, amr->amr_ioh, off, val);
 	bus_space_barrier(amr->amr_iot, amr->amr_ioh, off, 1,
 	    BUS_SPACE_BARRIER_WRITE);
@@ -219,7 +222,6 @@
 static inline void
 amr_outl(struct amr_softc *amr, int off, u_int32_t val)
 {
-
 	bus_space_write_4(amr->amr_iot, amr->amr_ioh, off, val);
 	bus_space_barrier(amr->amr_iot, amr->amr_ioh, off, 4,
 	    BUS_SPACE_BARRIER_WRITE);
@@ -282,6 +284,9 @@
 
 	amr = device_private(self);
 	amr->amr_dv = self;
+
+	mutex_init(&amr->amr_mutex, MUTEX_DEFAULT, IPL_BIO);
+
 	pa = (struct pci_attach_args *)aux;
 	pc = pa->pa_pc;
 
@@ -303,7 +308,6 @@
 			if (PCI_MAPREG_IO_SIZE(reg) != 0)
 				ioreg = i;
 			break;
-
 		}
 	}
 
@@ -424,6 +428,8 @@
 			break;
 
 		ac->ac_ident = i;
+		cv_init(&ac->ac_cv, "amr1ccb");
+		mutex_init(&ac->ac_mutex, MUTEX_DEFAULT, IPL_NONE);
 		amr_ccb_free(amr, ac);
 	}
 	if (i != AMR_MAX_CMDS) {
@@ -491,16 +497,23 @@
 
 	SIMPLEQ_INIT(&amr->amr_ccb_queue);
 
-	/* XXX This doesn't work for newer boards yet. */
+	cv_init(&thread_cv, "amrwdog");
+	mutex_init(&thread_mutex, MUTEX_DEFAULT, IPL_NONE);
+
 	if ((apt->apt_flags & AT_QUARTZ) == 0) {
-		rv = kthread_create(PRI_NONE, 0, NULL, amr_thread, amr,
-		    &amr->amr_thread, "%s", device_xname(amr->amr_dv));
- 		if (rv != 0)
-			aprint_error_dev(amr->amr_dv, "unable to create thread (%d)",
- 			    rv);
- 		else
- 			amr->amr_flags |= AMRF_THREAD;
+		rv = kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL,
+				    amr_std_thread, amr, &amr->amr_thread,
+				    "%s", device_xname(amr->amr_dv));
+	} else {
+		rv = kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL,
+				    amr_quartz_thread, amr, &amr->amr_thread,
+				    "%s", device_xname(amr->amr_dv));
 	}
+	if (rv != 0)
+		aprint_error_dev(amr->amr_dv, "unable to create thread (%d)",
+ 		    rv);
+ 	else
+ 		amr->amr_flags |= AMRF_THREAD;
 }
 
 /*
@@ -516,9 +529,14 @@
 
 	if ((fl & AMRF_THREAD) != 0) {
 		amr->amr_flags |= AMRF_THREAD_EXIT;
-		wakeup(amr_thread);
-		while ((amr->amr_flags & AMRF_THREAD_EXIT) != 0)
-			tsleep(&amr->amr_flags, PWAIT, "amrexit", 0);
+		mutex_enter(&thread_mutex);
+		cv_broadcast(&thread_cv);
+		mutex_exit(&thread_mutex);
+		while ((amr->amr_flags & AMRF_THREAD_EXIT) != 0) {
+			mutex_enter(&thread_mutex);
+			cv_wait(&thread_cv, &thread_mutex);
+			mutex_exit(&thread_mutex);
+		}
 	}
 	if ((fl & AMRF_CCBS) != 0) {
 		SLIST_FOREACH(ac, &amr->amr_ccb_freelist, ac_chain.slist) {
@@ -743,7 +761,7 @@
 	extern struct cfdriver amr_cd;
 	struct amr_softc *amr;
 	struct amr_ccb *ac;
-	int i, rv, s;
+	int i, rv;
 
 	for (i = 0; i < amr_cd.cd_ndevs; i++) {
 		if ((amr = device_lookup_private(&amr_cd, i)) == NULL)
@@ -751,9 +769,7 @@
 
 		if ((rv = amr_ccb_alloc(amr, &ac)) == 0) {
 			ac->ac_cmd.mb_command = AMR_CMD_FLUSH;
-			s = splbio();
 			rv = amr_ccb_poll(amr, ac, 30000);
-			splx(s);
 			amr_ccb_free(amr, ac);
 		}
 		if (rv != 0)
@@ -775,6 +791,8 @@
 	amr = cookie;
 	forus = 0;
 
+	mutex_spin_enter(&amr->amr_mutex);
+
 	while ((*amr->amr_get_work)(amr, &mbox) == 0) {
 		/* Iterate over completed commands in this result. */
 		for (i = 0; i < mbox.mb_nstatus; i++) {
@@ -803,14 +821,21 @@
 				    device_xname(amr->amr_dv), ac->ac_ident);
 
 			/* Pass notification to upper layers. */
-			if (ac->ac_handler != NULL)
+			mutex_spin_exit(&amr->amr_mutex);
+			if (ac->ac_handler != NULL) {
 				(*ac->ac_handler)(ac);
-			else
-				wakeup(ac);
+			} else {
+				mutex_enter(&ac->ac_mutex);
+				cv_signal(&ac->ac_cv);
+				mutex_exit(&ac->ac_mutex);
+			}
+			mutex_spin_enter(&amr->amr_mutex);
 		}
 		forus = 1;
 	}
 
+	mutex_spin_exit(&amr->amr_mutex);
+
 	if (forus)
 		amr_ccb_enqueue(amr, NULL);
 
@@ -821,28 +846,75 @@
  * Watchdog thread.
  */
 static void
-amr_thread(void *cookie)
+amr_quartz_thread(void *cookie)
+{
+	struct amr_softc *amr;
+	struct amr_ccb *ac;
+
+	amr = cookie;
+
+	for (;;) {
+		mutex_enter(&thread_mutex);
+		cv_timedwait(&thread_cv, &thread_mutex, AMR_WDOG_TICKS);
+		mutex_exit(&thread_mutex);
+
+		if ((amr->amr_flags & AMRF_THREAD_EXIT) != 0) {
+			amr->amr_flags ^= AMRF_THREAD_EXIT;
+			mutex_enter(&thread_mutex);
+			cv_signal(&thread_cv);
+			mutex_exit(&thread_mutex);
+			kthread_exit(0);
+		}
+
+		if (amr_intr(amr) == 0)
+			amr_ccb_enqueue(amr, NULL);
+
+		mutex_spin_enter(&amr->amr_mutex);
+		ac = TAILQ_FIRST(&amr->amr_ccb_active);
+		while (ac != NULL) {
+			if (ac->ac_start_time + AMR_TIMEOUT > time_uptime)
+				break;
+			if ((ac->ac_flags & AC_MOAN) == 0) {
+				printf("%s: ccb %d timed out; mailbox:\n",
+				    device_xname(amr->amr_dv), ac->ac_ident);
+				amr_ccb_dump(amr, ac);
+				ac->ac_flags |= AC_MOAN;
+			}
+			ac = TAILQ_NEXT(ac, ac_chain.tailq);
+		}
+		mutex_spin_exit(&amr->amr_mutex);
+	}
+}
+
+static void
+amr_std_thread(void *cookie)
 {
 	struct amr_softc *amr;
 	struct amr_ccb *ac;
 	struct amr_logdrive *al;
 	struct amr_enquiry *ae;
-	int rv, i, s;
+	int rv, i;
 
 	amr = cookie;
 	ae = amr->amr_enqbuf;
 
 	for (;;) {
-		tsleep(amr_thread, PWAIT, "amrwdog", AMR_WDOG_TICKS);
+		mutex_enter(&thread_mutex);
+		cv_timedwait(&thread_cv, &thread_mutex, AMR_WDOG_TICKS);
+		mutex_exit(&thread_mutex);
 
 		if ((amr->amr_flags & AMRF_THREAD_EXIT) != 0) {
 			amr->amr_flags ^= AMRF_THREAD_EXIT;
-			wakeup(&amr->amr_flags);
+			mutex_enter(&thread_mutex);
+			cv_signal(&thread_cv);
+			mutex_exit(&thread_mutex);
 			kthread_exit(0);
 		}
 
-		s = splbio();
-		amr_intr(cookie);
+		if (amr_intr(amr) == 0)
+			amr_ccb_enqueue(amr, NULL);
+
+		mutex_spin_enter(&amr->amr_mutex);
 		ac = TAILQ_FIRST(&amr->amr_ccb_active);
 		while (ac != NULL) {
 			if (ac->ac_start_time + AMR_TIMEOUT > time_uptime)
@@ -855,7 +927,7 @@
 			}
 			ac = TAILQ_NEXT(ac, ac_chain.tailq);
 		}
-		splx(s);
+		mutex_spin_exit(&amr->amr_mutex);
 
 		if ((rv = amr_ccb_alloc(amr, &ac)) != 0) {
 			printf("%s: ccb_alloc failed (%d)\n",
@@ -958,15 +1030,13 @@
 int
 amr_ccb_alloc(struct amr_softc *amr, struct amr_ccb **acp)
 {
-	int s;
-
-	s = splbio();
+	mutex_spin_enter(&amr->amr_mutex);
 	if ((*acp = SLIST_FIRST(&amr->amr_ccb_freelist)) == NULL) {
-		splx(s);
+		mutex_spin_exit(&amr->amr_mutex);
 		return (EAGAIN);
 	}
 	SLIST_REMOVE_HEAD(&amr->amr_ccb_freelist, ac_chain.slist);
-	splx(s);
+	mutex_spin_exit(&amr->amr_mutex);
 
 	return (0);
 }
@@ -977,17 +1047,15 @@
 void
 amr_ccb_free(struct amr_softc *amr, struct amr_ccb *ac)
 {
-	int s;
-
 	memset(&ac->ac_cmd, 0, sizeof(ac->ac_cmd));
 	ac->ac_cmd.mb_ident = ac->ac_ident + 1;
 	ac->ac_cmd.mb_busy = 1;
 	ac->ac_handler = NULL;
 	ac->ac_flags = 0;
 
-	s = splbio();
+	mutex_spin_enter(&amr->amr_mutex);
 	SLIST_INSERT_HEAD(&amr->amr_ccb_freelist, ac, ac_chain.slist);
-	splx(s);
+	mutex_spin_exit(&amr->amr_mutex);
 }
 
 /*
@@ -998,21 +1066,24 @@
 void
 amr_ccb_enqueue(struct amr_softc *amr, struct amr_ccb *ac)
 {
-	int s;
-
-	s = splbio();
-
-	if (ac != NULL)
+	if (ac != NULL) {
+		mutex_spin_enter(&amr->amr_mutex);
 		SIMPLEQ_INSERT_TAIL(&amr->amr_ccb_queue, ac, ac_chain.simpleq);
-
-	while ((ac = SIMPLEQ_FIRST(&amr->amr_ccb_queue)) != NULL) {
-		if ((*amr->amr_submit)(amr, ac) != 0)
-			break;
-		SIMPLEQ_REMOVE_HEAD(&amr->amr_ccb_queue, ac_chain.simpleq);
-		TAILQ_INSERT_TAIL(&amr->amr_ccb_active, ac, ac_chain.tailq);
+		mutex_spin_exit(&amr->amr_mutex);
 	}
 
-	splx(s);
+	while (SIMPLEQ_FIRST(&amr->amr_ccb_queue) != NULL) {
+		mutex_spin_enter(&amr->amr_mutex);
+		if ((ac = SIMPLEQ_FIRST(&amr->amr_ccb_queue)) != NULL) {
+			if ((*amr->amr_submit)(amr, ac) != 0) {
+				mutex_spin_exit(&amr->amr_mutex);
+				break;
+			}
+			SIMPLEQ_REMOVE_HEAD(&amr->amr_ccb_queue, ac_chain.simpleq);
+			TAILQ_INSERT_TAIL(&amr->amr_ccb_active, ac, ac_chain.tailq);
+		}
+		mutex_spin_exit(&amr->amr_mutex);
+	}
 }
 
 /*
@@ -1096,25 +1167,33 @@
 
 /*
  * Submit a command to the controller and poll on completion.  Return
- * non-zero on timeout or error.  Must be called with interrupts blocked.
+ * non-zero on timeout or error.
  */
 int
 amr_ccb_poll(struct amr_softc *amr, struct amr_ccb *ac, int timo)
 {
-	int rv;
+	int rv, i;
 
-	if ((rv = (*amr->amr_submit)(amr, ac)) != 0)
+	mutex_spin_enter(&amr->amr_mutex);
+	if ((rv = (*amr->amr_submit)(amr, ac)) != 0) {
+		mutex_spin_exit(&amr->amr_mutex);
 		return (rv);
+	}
 	TAILQ_INSERT_TAIL(&amr->amr_ccb_active, ac, ac_chain.tailq);
+	mutex_spin_exit(&amr->amr_mutex);
 
-	for (timo *= 10; timo != 0; timo--) {
+	for (i = timo * 10; i > 0; i--) {
 		amr_intr(amr);
 		if ((ac->ac_flags & AC_COMPLETE) != 0)
 			break;
 		DELAY(100);
 	}
 
-	return (timo == 0 || ac->ac_status != 0 ? EIO : 0);
+	if (i == 0)
+		printf("%s: polled operation timed out after %d ms\n",
+		       device_xname(amr->amr_dv), timo);
+
+	return ((i == 0 || ac->ac_status != 0) ? EIO : 0);
 }
 
 /*
@@ -1124,12 +1203,10 @@
 int
 amr_ccb_wait(struct amr_softc *amr, struct amr_ccb *ac)
 {
-	int s;
-
-	s = splbio();
 	amr_ccb_enqueue(amr, ac);
-	tsleep(ac, PRIBIO, "amrcmd", 0);
-	splx(s);
+	mutex_enter(&ac->ac_mutex);
+	cv_wait(&ac->ac_cv, &ac->ac_mutex);
+	mutex_exit(&ac->ac_mutex);
 
 	return (ac->ac_status != 0 ? EIO : 0);
 }
@@ -1165,14 +1242,29 @@
 static int
 amr_quartz_submit(struct amr_softc *amr, struct amr_ccb *ac)
 {
+	int i = 0;
 	u_int32_t v;
 
 	amr->amr_mbox->mb_poll = 0;
 	amr->amr_mbox->mb_ack = 0;
+
 	bus_dmamap_sync(amr->amr_dmat, amr->amr_dmamap, 0,
-	    sizeof(struct amr_mailbox), BUS_DMASYNC_PREWRITE);
+	    sizeof(struct amr_mailbox),
+	    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
+
+	v = amr_inl(amr, AMR_QREG_ODB);
 	bus_dmamap_sync(amr->amr_dmat, amr->amr_dmamap, 0,
 	    sizeof(struct amr_mailbox), BUS_DMASYNC_POSTREAD);
+	while ((amr->amr_mbox->mb_cmd.mb_busy != 0) && (i++ < 10)) {
+		bus_dmamap_sync(amr->amr_dmat, amr->amr_dmamap, 0,
+		    sizeof(struct amr_mailbox), BUS_DMASYNC_PREREAD);
+		/* This is a no-op read that flushes pending mailbox updates */
+		v = amr_inl(amr, AMR_QREG_ODB);
+		DELAY(1);
+		bus_dmamap_sync(amr->amr_dmat, amr->amr_dmamap, 0,
+		    sizeof(struct amr_mailbox), BUS_DMASYNC_POSTREAD);
+	}
+
 	if (amr->amr_mbox->mb_cmd.mb_busy != 0)
 		return (EAGAIN);
 
@@ -1181,8 +1273,7 @@
 		amr->amr_mbox->mb_cmd.mb_busy = 0;
 		bus_dmamap_sync(amr->amr_dmat, amr->amr_dmamap, 0,
 		    sizeof(struct amr_mailbox), BUS_DMASYNC_PREWRITE);
-		bus_dmamap_sync(amr->amr_dmat, amr->amr_dmamap, 0,
-		    sizeof(struct amr_mailbox), BUS_DMASYNC_PREREAD);
+		printf("%s: submit failed\n", device_xname(amr->amr_dv));
 		return (EAGAIN);
 	}
 
@@ -1193,8 +1284,12 @@
 
 	ac->ac_start_time = time_uptime;
 	ac->ac_flags |= AC_ACTIVE;
+
 	amr_outl(amr, AMR_QREG_IDB,
 	    (amr->amr_mbox_paddr + 16) | AMR_QIDB_SUBMIT);
+	bus_dmamap_sync(amr->amr_dmat, amr->amr_dmamap, 0,
+	    sizeof(struct amr_mailbox), BUS_DMASYNC_POSTWRITE);
+
 	return (0);
 }
 
@@ -1204,10 +1299,10 @@
 
 	amr->amr_mbox->mb_poll = 0;
 	amr->amr_mbox->mb_ack = 0;
-	bus_dmamap_sync(amr->amr_dmat, amr->amr_dmamap, 0,
-	    sizeof(struct amr_mailbox), BUS_DMASYNC_PREWRITE);
+
 	bus_dmamap_sync(amr->amr_dmat, amr->amr_dmamap, 0,
 	    sizeof(struct amr_mailbox), BUS_DMASYNC_POSTREAD);
+
 	if (amr->amr_mbox->mb_cmd.mb_busy != 0)
 		return (EAGAIN);
 
@@ -1215,19 +1310,22 @@
 		amr->amr_mbox->mb_cmd.mb_busy = 0;
 		bus_dmamap_sync(amr->amr_dmat, amr->amr_dmamap, 0,
 		    sizeof(struct amr_mailbox), BUS_DMASYNC_PREWRITE);
-		bus_dmamap_sync(amr->amr_dmat, amr->amr_dmamap, 0,
-		    sizeof(struct amr_mailbox), BUS_DMASYNC_PREREAD);
 		return (EAGAIN);
 	}
 
 	amr->amr_mbox->mb_segment = 0;
 	memcpy(&amr->amr_mbox->mb_cmd, &ac->ac_cmd, sizeof(ac->ac_cmd));
+
 	bus_dmamap_sync(amr->amr_dmat, amr->amr_dmamap, 0,
 	    sizeof(struct amr_mailbox), BUS_DMASYNC_PREWRITE);
 
 	ac->ac_start_time = time_uptime;
 	ac->ac_flags |= AC_ACTIVE;
 	amr_outb(amr, AMR_SREG_CMD, AMR_SCMD_POST);
+
+	bus_dmamap_sync(amr->amr_dmat, amr->amr_dmamap, 0,
+	    sizeof(struct amr_mailbox), BUS_DMASYNC_POSTWRITE);
+
 	return (0);
 }
 
@@ -1239,6 +1337,8 @@
 static int
 amr_quartz_get_work(struct amr_softc *amr, struct amr_mailbox_resp *mbsave)
 {
+	bus_dmamap_sync(amr->amr_dmat, amr->amr_dmamap, 0,
+	    sizeof(struct amr_mailbox), BUS_DMASYNC_PREREAD);
 
 	/* Work waiting for us? */
 	if (amr_inl(amr, AMR_QREG_ODB) != AMR_QODB_READY)
@@ -1250,9 +1350,6 @@
 	/* Save the mailbox, which contains a list of completed commands. */
 	memcpy(mbsave, &amr->amr_mbox->mb_resp, sizeof(*mbsave));
 
-	bus_dmamap_sync(amr->amr_dmat, amr->amr_dmamap, 0,
-	    sizeof(struct amr_mailbox), BUS_DMASYNC_PREREAD);
-
 	/* Ack the interrupt and mailbox transfer. */
 	amr_outl(amr, AMR_QREG_ODB, AMR_QODB_READY);
 	amr_outl(amr, AMR_QREG_IDB, (amr->amr_mbox_paddr+16) | AMR_QIDB_ACK);
@@ -1277,6 +1374,9 @@
 {
 	u_int8_t istat;
 
+	bus_dmamap_sync(amr->amr_dmat, amr->amr_dmamap, 0,
+	    sizeof(struct amr_mailbox), BUS_DMASYNC_PREREAD);
+
 	/* Check for valid interrupt status. */
 	if (((istat = amr_inb(amr, AMR_SREG_INTR)) & AMR_SINTR_VALID) == 0)
 		return (-1);
@@ -1290,9 +1390,6 @@
 	/* Save mailbox, which contains a list of completed commands. */
 	memcpy(mbsave, &amr->amr_mbox->mb_resp, sizeof(*mbsave));
 
-	bus_dmamap_sync(amr->amr_dmat, amr->amr_dmamap, 0,
-	    sizeof(struct amr_mailbox), BUS_DMASYNC_PREREAD);
-
 	/* Ack mailbox transfer. */
 	amr_outb(amr, AMR_SREG_CMD, AMR_SCMD_ACKINTR);
 
@@ -1334,6 +1431,21 @@
 	return (0);
 }
 
+/* used below to correct for a firmware bug */
+static unsigned long
+amrioctl_buflen(unsigned long len)
+{
+	if (len <= 4 * 1024)
+		return (4 * 1024);
+	if (len <= 8 * 1024)
+		return (8 * 1024);
+	if (len <= 32 * 1024)
+		return (32 * 1024);
+	if (len <= 64 * 1024)
+		return (64 * 1024);
+	return (len);
+}
+
 static int
 amrioctl(dev_t dev, u_long cmd, void *data, int flag,
     struct lwp *l)
@@ -1380,9 +1492,11 @@
 
 	/*
 	 * allocate kernel memory for data, doing I/O directly to user
-	 * buffer isn't that easy.
+	 * buffer isn't that easy.  Correct allocation size for a bug
+	 * in at least some versions of the device firmware, by using
+	 * the amrioctl_buflen() function, defined above.
 	 */
-	dp = malloc(au_length, M_DEVBUF, M_WAITOK|M_ZERO);
+	dp = malloc(amrioctl_buflen(au_length), M_DEVBUF, M_WAITOK|M_ZERO);
 	if (dp == NULL)
 		return ENOMEM;
 	if ((error = copyin(au_buffer, dp, au_length)) != 0)
@@ -1390,7 +1504,9 @@
 
 	/* direct command to controller */
 	while (amr_ccb_alloc(amr, &ac) != 0) {
-		error = tsleep(NULL, PRIBIO | PCATCH, "armmbx", hz);
+		mutex_enter(&thread_mutex);
+		error = cv_timedwait_sig(&thread_cv, &thread_mutex, hz);
+		mutex_exit(&thread_mutex);
 		if (error == EINTR)
 			goto out;
 	}
Index: sys/dev/pci/amrvar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/amrvar.h,v
retrieving revision 1.9
diff -u -r1.9 amrvar.h
--- sys/dev/pci/amrvar.h	27 Jul 2012 16:25:11 -0000	1.9
+++ sys/dev/pci/amrvar.h	2 Mar 2015 12:47:22 -0000
@@ -82,6 +82,8 @@
 	int	(*amr_get_work)(struct amr_softc *, struct amr_mailbox_resp *);
 	int	(*amr_submit)(struct amr_softc *sc, struct amr_ccb *);
 
+	kmutex_t		amr_mutex;
+
 	int			amr_numdrives;
 	struct amr_logdrive	amr_drive[AMR_MAX_UNITS];
 };
@@ -122,6 +124,8 @@
 	void 		*ac_context;
 	device_t	ac_dv;
 	struct amr_mailbox_cmd	ac_cmd;
+	kmutex_t	ac_mutex;
+	kcondvar_t	ac_cv;
 };
 #define	AC_XFER_IN	0x01	/* Map describes inbound xfer */
 #define	AC_XFER_OUT	0x02	/* Map describes outbound xfer */
Index: sys/dev/pci/ld_amr.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/ld_amr.c,v
retrieving revision 1.21
diff -u -r1.21 ld_amr.c
--- sys/dev/pci/ld_amr.c	2 Feb 2012 19:43:06 -0000	1.21
+++ sys/dev/pci/ld_amr.c	2 Mar 2015 12:47:22 -0000
@@ -70,7 +70,6 @@
 static int
 ld_amr_match(device_t parent, cfdata_t match, void *aux)
 {
-
 	return (1);
 }
 
@@ -122,7 +121,7 @@
 	struct amr_ccb *ac;
 	struct amr_softc *amr;
 	struct amr_mailbox_cmd *mb;
-	int s, rv;
+	int rv;
 
 	amr = device_private(device_parent(sc->sc_ld.sc_dv));
 
@@ -147,9 +146,7 @@
 		 * Polled commands must not sit on the software queue.  Wait
 		 * up to 30 seconds for the command to complete.
 		 */
-		s = splbio();
 		rv = amr_ccb_poll(amr, ac, 30000);
-		splx(s);
 		amr_ccb_unmap(amr, ac);
 		amr_ccb_free(amr, ac);
 	} else {
@@ -166,7 +163,6 @@
 static int
 ld_amr_start(struct ld_softc *ld, struct buf *bp)
 {
-
 	return (ld_amr_dobio((struct ld_amr_softc *)ld, bp->b_data,
 	    bp->b_bcount, bp->b_rawblkno, (bp->b_flags & B_READ) == 0, bp));
 }

-- 
Popularity is the hallmark of mediocrity.  --Niles Crane, "Frasier"


Home | Main Index | Thread Index | Old Index