diff options
author | David Gwynne <dlg@cvs.openbsd.org> | 2006-09-22 00:33:42 +0000 |
---|---|---|
committer | David Gwynne <dlg@cvs.openbsd.org> | 2006-09-22 00:33:42 +0000 |
commit | b4ea7bd984c9980a330d3349443cf2b0b38607c7 (patch) | |
tree | 783008c927807444c221ce9cbb8e810e55fef493 | |
parent | e179f1096195bb76ee73ef371e695dfcf698be3b (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@
-rw-r--r-- | sys/scsi/scsi_base.c | 99 | ||||
-rw-r--r-- | sys/scsi/scsiconf.c | 5 | ||||
-rw-r--r-- | sys/scsi/scsiconf.h | 4 |
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 *); |