diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-03-17 22:05:47 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-03-17 22:05:47 +0000 |
commit | 27cfca1ec98e91261b1a5355d10a8996464b63af (patch) | |
tree | 8e895a53e372fa682b4c0a585b9377d67ed70d0e /drivers/scsi/hosts.c | |
parent | 6a76fb7214c477ccf6582bd79c5b4ccc4f9c41b1 (diff) |
Look Ma' what I found on my harddisk ...
o New faster syscalls for 2.1.x, too
o Upgrade to 2.1.89.
Don't try to run this. It's flaky as hell. But feel free to debug ...
Diffstat (limited to 'drivers/scsi/hosts.c')
-rw-r--r-- | drivers/scsi/hosts.c | 55 |
1 files changed, 50 insertions, 5 deletions
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 4c62c2df4..e9ea1be59 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -16,11 +16,6 @@ * hosts currently present in the system. */ -/* - * Don't import our own symbols, as this would severely mess up our - * symbol tables. - */ -#define _SCSI_SYMS_VER_ #define __NO_VERSION__ #include <linux/module.h> @@ -32,6 +27,10 @@ #include <linux/proc_fs.h> #include <linux/init.h> +#define __KERNEL_SYSCALLS__ + +#include <linux/unistd.h> + #include "scsi.h" #ifndef NULL @@ -447,7 +446,9 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j){ struct Scsi_Host * retval, *shpnt; retval = (struct Scsi_Host *)scsi_init_malloc(sizeof(struct Scsi_Host) + j, (tpnt->unchecked_isa_dma && j ? GFP_DMA : 0) | GFP_ATOMIC); + atomic_set(&retval->host_active,0); retval->host_busy = 0; + retval->host_failed = 0; retval->block = NULL; retval->wish_block = 0; if(j > 0xffff) panic("Too many extra bytes requested\n"); @@ -470,6 +471,16 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j){ retval->io_port = 0; retval->hostt = tpnt; retval->next = NULL; + retval->in_recovery = 0; + retval->ehandler = NULL; /* Initial value until the thing starts up. */ + retval->eh_notify = NULL; /* Who we notify when we exit. */ + + /* + * Initialize the fields used for mid-level queueing. + */ + retval->pending_commands = NULL; + retval->host_busy = FALSE; + #ifdef DEBUG printk("Register %x %x: %d\n", (int)retval, (int)retval->hostt, j); #endif @@ -506,6 +517,32 @@ scsi_register_device(struct Scsi_Device_Template * sdpnt) return 0; } +/* + * Why is this a seperate function? Because the kernel_thread code + * effectively does a fork, and there is a builtin exit() call when + * the child returns. The difficulty is that scsi_init() is + * marked __initfunc(), which means the memory is unmapped after bootup + * is complete, which means that the thread's exit() call gets wiped. + * + * The lesson is to *NEVER*, *NEVER* call kernel_thread() from an + * __initfunc() function, if that function could ever return. + */ +static void launch_error_handler_thread(struct Scsi_Host * shpnt) +{ + struct semaphore sem = MUTEX_LOCKED; + + shpnt->eh_notify = &sem; + + kernel_thread((int (*)(void *))scsi_error_handler, + (void *) shpnt, 0); + /* + * Now wait for the kernel error thread to initialize itself + * as it might be needed when we scan the bus. + */ + down (&sem); + shpnt->eh_notify = NULL; +} + __initfunc(unsigned int scsi_init(void)) { static int called = 0; @@ -556,6 +593,14 @@ __initfunc(unsigned int scsi_init(void)) name = shpnt->hostt->name; printk ("scsi%d : %s\n", /* And print a little message */ shpnt->host_no, name); + + /* + * Now start the error recovery thread for the host. + */ + if( shpnt->hostt->use_new_eh_code ) + { + launch_error_handler_thread(shpnt); + } } printk ("scsi : %d host%s.\n", next_scsi_host, |