summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2006-09-22 00:33:42 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2006-09-22 00:33:42 +0000
commitb4ea7bd984c9980a330d3349443cf2b0b38607c7 (patch)
tree783008c927807444c221ce9cbb8e810e55fef493 /sys
parente179f1096195bb76ee73ef371e695dfcf698be3b (diff)
implement a kernel thread that can be used by the midlayer or scsi drivers
when they need a process context to do something. the most obvious task that springs to mind is attaches and detaches of devices on scsibus. ok krw@ marco@ deraadt@
Diffstat (limited to 'sys')
-rw-r--r--sys/scsi/scsi_base.c99
-rw-r--r--sys/scsi/scsiconf.c5
-rw-r--r--sys/scsi/scsiconf.h4
3 files changed, 100 insertions, 8 deletions
diff --git a/sys/scsi/scsi_base.c b/sys/scsi/scsi_base.c
index 730216ebd11..a9965fb8f2d 100644
--- a/sys/scsi/scsi_base.c
+++ b/sys/scsi/scsi_base.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: scsi_base.c,v 1.112 2006/08/04 21:35:51 beck Exp $ */
+/* $OpenBSD: scsi_base.c,v 1.113 2006/09/22 00:33:41 dlg Exp $ */
/* $NetBSD: scsi_base.c,v 1.43 1997/04/02 02:29:36 mycroft Exp $ */
/*
@@ -46,11 +46,25 @@
#include <sys/device.h>
#include <sys/proc.h>
#include <sys/pool.h>
+#include <sys/kthread.h>
+#include <sys/queue.h>
#include <scsi/scsi_all.h>
#include <scsi/scsi_disk.h>
#include <scsi/scsiconf.h>
+struct scsi_task {
+ void (*func)(void *, void *);
+ void *sc;
+ void *arg;
+
+ TAILQ_ENTRY(scsi_task) entry;
+};
+
+void scsi_create_task_thread(void *);
+void scsi_create_task(void *);
+void scsi_task_thread(void *);
+
static __inline struct scsi_xfer *scsi_make_xs(struct scsi_link *,
struct scsi_generic *, int cmdlen, u_char *data_addr,
int datalen, int retries, int timeout, struct buf *, int flags);
@@ -65,7 +79,10 @@ char *scsi_decode_sense(struct scsi_sense_data *, int);
#define DECODE_ASC_ASCQ 2
#define DECODE_SKSV 3
-struct pool scsi_xfer_pool;
+struct pool scsi_xfer_pool;
+struct pool scsi_task_pool;
+TAILQ_HEAD(, scsi_task) scsi_task_list;
+volatile int scsi_running = 0;
/*
* Called when a scsibus is attached to initialize global data.
@@ -73,11 +90,8 @@ struct pool scsi_xfer_pool;
void
scsi_init()
{
- static int scsi_init_done;
-
- if (scsi_init_done)
+ if (scsi_running++)
return;
- scsi_init_done = 1;
#if defined(SCSI_DELAY) && SCSI_DELAY > 0
/* Historical. Older buses may need a moment to stabilize. */
@@ -87,6 +101,79 @@ scsi_init()
/* Initialize the scsi_xfer pool. */
pool_init(&scsi_xfer_pool, sizeof(struct scsi_xfer), 0,
0, 0, "scxspl", NULL);
+
+ /* Initialize the scsi_task pool. */
+ pool_init(&scsi_task_pool, sizeof(struct scsi_task), 0,
+ 0, 0, "sctkpl", NULL);
+
+ /* Get the creation of the task thread underway. */
+ TAILQ_INIT(&scsi_task_list);
+ kthread_create_deferred(scsi_create_task_thread, NULL);
+}
+
+void
+scsi_deinit()
+{
+ if (--scsi_running)
+ return;
+
+ wakeup(&scsi_task_list);
+}
+
+void
+scsi_create_task_thread(void *arg)
+{
+ if (kthread_create(scsi_task_thread, NULL, NULL, "scsi") != NULL)
+ panic("unable to create scsi task thread");
+}
+
+void
+scsi_task_thread(void *arg)
+{
+ struct scsi_task *task;
+ int s;
+
+ s = splbio();
+ while (scsi_running) {
+ while ((task = TAILQ_FIRST(&scsi_task_list)) != NULL) {
+ TAILQ_REMOVE(&scsi_task_list, task, entry);
+ splx(s);
+
+ task->func(task->sc, task->arg);
+
+ s = splbio();
+ pool_put(&scsi_task_pool, task);
+ }
+ tsleep(&scsi_task_list, PWAIT, "slacking", 10 * hz);
+ }
+
+ if (!TAILQ_EMPTY(&scsi_task_list))
+ panic("outstanding scsi tasks");
+ splx(s);
+
+ kthread_exit(0);
+}
+
+/*
+ * Must be called at splbio.
+ */
+int
+scsi_task(void (*func)(void *, void *), void *sc, void *arg, int nosleep)
+{
+ struct scsi_task *task;
+
+ task = pool_get(&scsi_task_pool, nosleep ? PR_NOWAIT : PR_WAITOK);
+ if (task == NULL)
+ return (ENOMEM);
+
+ task->func = func;
+ task->sc = sc;
+ task->arg = arg;
+
+ TAILQ_INSERT_TAIL(&scsi_task_list, task, entry);
+ wakeup(&scsi_task_list);
+
+ return (0);
}
/*
diff --git a/sys/scsi/scsiconf.c b/sys/scsi/scsiconf.c
index 3bc11fe542c..19ab86b3198 100644
--- a/sys/scsi/scsiconf.c
+++ b/sys/scsi/scsiconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: scsiconf.c,v 1.112 2006/09/21 08:42:11 dlg Exp $ */
+/* $OpenBSD: scsiconf.c,v 1.113 2006/09/22 00:33:41 dlg Exp $ */
/* $NetBSD: scsiconf.c,v 1.57 1996/05/02 01:09:01 neil Exp $ */
/*
@@ -190,6 +190,9 @@ scsibusdetach(struct device *dev, int type)
free(sb->sc_link, M_DEVBUF);
+ /* Free shared data. */
+ scsi_deinit();
+
return (0);
}
diff --git a/sys/scsi/scsiconf.h b/sys/scsi/scsiconf.h
index 823eb9fda25..de5c5125f27 100644
--- a/sys/scsi/scsiconf.h
+++ b/sys/scsi/scsiconf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: scsiconf.h,v 1.72 2006/07/29 02:40:45 krw Exp $ */
+/* $OpenBSD: scsiconf.h,v 1.73 2006/09/22 00:33:41 dlg Exp $ */
/* $NetBSD: scsiconf.h,v 1.35 1997/04/02 02:29:38 mycroft Exp $ */
/*
@@ -308,6 +308,8 @@ const void *scsi_inqmatch(struct scsi_inquiry_data *, const void *, int,
int, int *);
void scsi_init(void);
+void scsi_deinit(void);
+int scsi_task(void (*func)(void *, void *), void *, void *, int);
struct scsi_xfer *
scsi_get_xs(struct scsi_link *, int);
void scsi_free_xs(struct scsi_xfer *);