Sun Dec 18 13:59:14 2016 UTC ()
The mutex passed to cv_wait must also be held when calling cv_broadcast.
Also optimizing mutex handling in completion thread.

From nick@.


(mlelstv)
diff -r1.170 -r1.171 src/sys/dev/scsipi/scsipi_base.c

cvs diff -r1.170 -r1.171 src/sys/dev/scsipi/scsipi_base.c (expand / switch to unified diff)

--- src/sys/dev/scsipi/scsipi_base.c 2016/12/16 15:00:52 1.170
+++ src/sys/dev/scsipi/scsipi_base.c 2016/12/18 13:59:14 1.171
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: scsipi_base.c,v 1.170 2016/12/16 15:00:52 mlelstv Exp $ */ 1/* $NetBSD: scsipi_base.c,v 1.171 2016/12/18 13:59:14 mlelstv Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 1998, 1999, 2000, 2002, 2003, 2004 The NetBSD Foundation, Inc. 4 * Copyright (c) 1998, 1999, 2000, 2002, 2003, 2004 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Charles M. Hannum; by Jason R. Thorpe of the Numerical Aerospace 8 * by Charles M. Hannum; by Jason R. Thorpe of the Numerical Aerospace
9 * Simulation Facility, NASA Ames Research Center. 9 * Simulation Facility, NASA Ames Research Center.
10 * 10 *
11 * Redistribution and use in source and binary forms, with or without 11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions 12 * modification, are permitted provided that the following conditions
13 * are met: 13 * are met:
14 * 1. Redistributions of source code must retain the above copyright 14 * 1. Redistributions of source code must retain the above copyright
@@ -21,27 +21,27 @@ @@ -21,27 +21,27 @@
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE. 30 * POSSIBILITY OF SUCH DAMAGE.
31 */ 31 */
32 32
33#include <sys/cdefs.h> 33#include <sys/cdefs.h>
34__KERNEL_RCSID(0, "$NetBSD: scsipi_base.c,v 1.170 2016/12/16 15:00:52 mlelstv Exp $"); 34__KERNEL_RCSID(0, "$NetBSD: scsipi_base.c,v 1.171 2016/12/18 13:59:14 mlelstv Exp $");
35 35
36#ifdef _KERNEL_OPT 36#ifdef _KERNEL_OPT
37#include "opt_scsi.h" 37#include "opt_scsi.h"
38#endif 38#endif
39 39
40#include <sys/param.h> 40#include <sys/param.h>
41#include <sys/systm.h> 41#include <sys/systm.h>
42#include <sys/kernel.h> 42#include <sys/kernel.h>
43#include <sys/buf.h> 43#include <sys/buf.h>
44#include <sys/uio.h> 44#include <sys/uio.h>
45#include <sys/malloc.h> 45#include <sys/malloc.h>
46#include <sys/pool.h> 46#include <sys/pool.h>
47#include <sys/errno.h> 47#include <sys/errno.h>
@@ -1452,28 +1452,28 @@ scsipi_done(struct scsipi_xfer *xs) @@ -1452,28 +1452,28 @@ scsipi_done(struct scsipi_xfer *xs)
1452 * if we can handle it in interrupt context. 1452 * if we can handle it in interrupt context.
1453 */ 1453 */
1454 if (xs->error == XS_NOERROR) { 1454 if (xs->error == XS_NOERROR) {
1455 mutex_exit(chan_mtx(chan)); 1455 mutex_exit(chan_mtx(chan));
1456 (void) scsipi_complete(xs); 1456 (void) scsipi_complete(xs);
1457 goto out; 1457 goto out;
1458 } 1458 }
1459 1459
1460 /* 1460 /*
1461 * There is an error on this xfer. Put it on the channel's 1461 * There is an error on this xfer. Put it on the channel's
1462 * completion queue, and wake up the completion thread. 1462 * completion queue, and wake up the completion thread.
1463 */ 1463 */
1464 TAILQ_INSERT_TAIL(&chan->chan_complete, xs, channel_q); 1464 TAILQ_INSERT_TAIL(&chan->chan_complete, xs, channel_q);
1465 mutex_exit(chan_mtx(chan)); 
1466 cv_broadcast(chan_cv_complete(chan)); 1465 cv_broadcast(chan_cv_complete(chan));
 1466 mutex_exit(chan_mtx(chan));
1467 1467
1468 out: 1468 out:
1469 /* 1469 /*
1470 * If there are more xfers on the channel's queue, attempt to 1470 * If there are more xfers on the channel's queue, attempt to
1471 * run them. 1471 * run them.
1472 */ 1472 */
1473 scsipi_run_queue(chan); 1473 scsipi_run_queue(chan);
1474} 1474}
1475 1475
1476/* 1476/*
1477 * scsipi_complete: 1477 * scsipi_complete:
1478 * 1478 *
1479 * Completion of a scsipi_xfer. This is the guts of scsipi_done(). 1479 * Completion of a scsipi_xfer. This is the guts of scsipi_done().
@@ -2128,88 +2128,84 @@ scsipi_execute_xs(struct scsipi_xfer *xs @@ -2128,88 +2128,84 @@ scsipi_execute_xs(struct scsipi_xfer *xs
2128 * function, restarting the command, if necessary. 2128 * function, restarting the command, if necessary.
2129 */ 2129 */
2130static void 2130static void
2131scsipi_completion_thread(void *arg) 2131scsipi_completion_thread(void *arg)
2132{ 2132{
2133 struct scsipi_channel *chan = arg; 2133 struct scsipi_channel *chan = arg;
2134 struct scsipi_xfer *xs; 2134 struct scsipi_xfer *xs;
2135 2135
2136 if (chan->chan_init_cb) 2136 if (chan->chan_init_cb)
2137 (*chan->chan_init_cb)(chan, chan->chan_init_cb_arg); 2137 (*chan->chan_init_cb)(chan, chan->chan_init_cb_arg);
2138 2138
2139 mutex_enter(chan_mtx(chan)); 2139 mutex_enter(chan_mtx(chan));
2140 chan->chan_flags |= SCSIPI_CHAN_TACTIVE; 2140 chan->chan_flags |= SCSIPI_CHAN_TACTIVE;
2141 mutex_exit(chan_mtx(chan)); 
2142 for (;;) { 2141 for (;;) {
2143 mutex_enter(chan_mtx(chan)); 
2144 xs = TAILQ_FIRST(&chan->chan_complete); 2142 xs = TAILQ_FIRST(&chan->chan_complete);
2145 if (xs == NULL && chan->chan_tflags == 0) { 2143 if (xs == NULL && chan->chan_tflags == 0) {
2146 /* nothing to do; wait */ 2144 /* nothing to do; wait */
2147 cv_wait(chan_cv_complete(chan), chan_mtx(chan)); 2145 cv_wait(chan_cv_complete(chan), chan_mtx(chan));
2148 mutex_exit(chan_mtx(chan)); 
2149 continue; 2146 continue;
2150 } 2147 }
2151 if (chan->chan_tflags & SCSIPI_CHANT_CALLBACK) { 2148 if (chan->chan_tflags & SCSIPI_CHANT_CALLBACK) {
2152 /* call chan_callback from thread context */ 2149 /* call chan_callback from thread context */
2153 chan->chan_tflags &= ~SCSIPI_CHANT_CALLBACK; 2150 chan->chan_tflags &= ~SCSIPI_CHANT_CALLBACK;
2154 chan->chan_callback(chan, chan->chan_callback_arg); 2151 chan->chan_callback(chan, chan->chan_callback_arg);
2155 mutex_exit(chan_mtx(chan)); 
2156 continue; 2152 continue;
2157 } 2153 }
2158 if (chan->chan_tflags & SCSIPI_CHANT_GROWRES) { 2154 if (chan->chan_tflags & SCSIPI_CHANT_GROWRES) {
2159 /* attempt to get more openings for this channel */ 2155 /* attempt to get more openings for this channel */
2160 chan->chan_tflags &= ~SCSIPI_CHANT_GROWRES; 2156 chan->chan_tflags &= ~SCSIPI_CHANT_GROWRES;
2161 mutex_exit(chan_mtx(chan)); 2157 mutex_exit(chan_mtx(chan));
2162 scsipi_adapter_request(chan, 2158 scsipi_adapter_request(chan,
2163 ADAPTER_REQ_GROW_RESOURCES, NULL); 2159 ADAPTER_REQ_GROW_RESOURCES, NULL);
2164 scsipi_channel_thaw(chan, 1); 2160 scsipi_channel_thaw(chan, 1);
2165 if (chan->chan_tflags & SCSIPI_CHANT_GROWRES) 2161 if (chan->chan_tflags & SCSIPI_CHANT_GROWRES)
2166 kpause("scsizzz", FALSE, hz/10, NULL); 2162 kpause("scsizzz", FALSE, hz/10, NULL);
 2163 mutex_enter(chan_mtx(chan));
2167 continue; 2164 continue;
2168 } 2165 }
2169 if (chan->chan_tflags & SCSIPI_CHANT_KICK) { 2166 if (chan->chan_tflags & SCSIPI_CHANT_KICK) {
2170 /* explicitly run the queues for this channel */ 2167 /* explicitly run the queues for this channel */
2171 chan->chan_tflags &= ~SCSIPI_CHANT_KICK; 2168 chan->chan_tflags &= ~SCSIPI_CHANT_KICK;
2172 mutex_exit(chan_mtx(chan)); 2169 mutex_exit(chan_mtx(chan));
2173 scsipi_run_queue(chan); 2170 scsipi_run_queue(chan);
 2171 mutex_enter(chan_mtx(chan));
2174 continue; 2172 continue;
2175 } 2173 }
2176 if (chan->chan_tflags & SCSIPI_CHANT_SHUTDOWN) { 2174 if (chan->chan_tflags & SCSIPI_CHANT_SHUTDOWN) {
2177 mutex_exit(chan_mtx(chan)); 
2178 break; 2175 break;
2179 } 2176 }
2180 if (xs) { 2177 if (xs) {
2181 TAILQ_REMOVE(&chan->chan_complete, xs, channel_q); 2178 TAILQ_REMOVE(&chan->chan_complete, xs, channel_q);
2182 mutex_exit(chan_mtx(chan)); 2179 mutex_exit(chan_mtx(chan));
2183 2180
2184 /* 2181 /*
2185 * Have an xfer with an error; process it. 2182 * Have an xfer with an error; process it.
2186 */ 2183 */
2187 (void) scsipi_complete(xs); 2184 (void) scsipi_complete(xs);
2188 2185
2189 /* 2186 /*
2190 * Kick the queue; keep it running if it was stopped 2187 * Kick the queue; keep it running if it was stopped
2191 * for some reason. 2188 * for some reason.
2192 */ 2189 */
2193 scsipi_run_queue(chan); 2190 scsipi_run_queue(chan);
2194 } else { 
2195 mutex_exit(chan_mtx(chan)); 
2196 } 2191 }
2197 } 2192 }
2198 2193
2199 chan->chan_thread = NULL; 2194 chan->chan_thread = NULL;
2200 2195
2201 /* In case parent is waiting for us to exit. */ 2196 /* In case parent is waiting for us to exit. */
2202 cv_broadcast(chan_cv_thread(chan)); 2197 cv_broadcast(chan_cv_thread(chan));
 2198 mutex_exit(chan_mtx(chan));
2203 2199
2204 kthread_exit(0); 2200 kthread_exit(0);
2205} 2201}
2206/* 2202/*
2207 * scsipi_thread_call_callback: 2203 * scsipi_thread_call_callback:
2208 * 2204 *
2209 * request to call a callback from the completion thread 2205 * request to call a callback from the completion thread
2210 */ 2206 */
2211int 2207int
2212scsipi_thread_call_callback(struct scsipi_channel *chan, 2208scsipi_thread_call_callback(struct scsipi_channel *chan,
2213 void (*callback)(struct scsipi_channel *, void *), void *arg) 2209 void (*callback)(struct scsipi_channel *, void *), void *arg)
2214{ 2210{
2215 2211