]> git.neil.brown.name Git - history.git/commitdiff
Import 1.1.90 1.1.90
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:09:54 +0000 (15:09 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:09:54 +0000 (15:09 -0500)
50 files changed:
CREDITS
Makefile
arch/i386/config.in
arch/i386/kernel/ldt.c
arch/i386/kernel/signal.c
arch/i386/kernel/traps.c
arch/sparc/kernel/ioport.c
arch/sparc/mm/init.c
drivers/block/README.fd
drivers/block/aztcd.c
drivers/block/floppy.c
drivers/char/ChangeLog
drivers/char/cyclades.c
drivers/char/keyboard.c
drivers/char/n_tty.c
drivers/char/serial.c
drivers/char/tty_ioctl.c
drivers/net/3c501.c
drivers/net/Space.c
drivers/net/de600.c
drivers/net/de620.c
drivers/net/ni52.c
drivers/net/plip.c
drivers/scsi/eata.c
drivers/scsi/eata.h
drivers/scsi/eata_dma.h
drivers/scsi/hosts.c
drivers/scsi/script_asm.pl
drivers/scsi/scsi.c
drivers/scsi/scsi.h
drivers/scsi/sr.c
drivers/scsi/sr.h
drivers/scsi/sr_ioctl.c
drivers/scsi/u14-34f.c
drivers/scsi/u14-34f.h
drivers/sound/Readme
fs/isofs/inode.c
fs/nfs/sock.c
include/asm-i386/bugs.h
include/asm-sparc/cprefix.h
include/linux/pci.h
include/linux/serial.h
include/linux/serial_reg.h
include/linux/tty.h
ipc/sem.c
kernel/ksyms.c
mm/memory.c
net/inet/icmp.c
net/inet/ip_fw.c
net/inet/tcp.c

diff --git a/CREDITS b/CREDITS
index ec535721c5dd0e731e68bc671587c2028304b4a3..29e73a33f61c67c32829cf843d3c12b3f2fa77cf 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -719,8 +719,8 @@ D: Dosemu
 N: Hannu Savolainen
 E: hannu@voxware.pp.fi
 D: Kernel sound drivers
-S: Pallaksentie 4 A 2
-S: 00970 Helsinki
+S: Hiekkalaiturintie 3 A 8
+S: 00980 Helsinki
 S: Finland
 
 N: Peter De Schrijver
index cbe50c984cd2461ef6b0a470fb64c6ea4010149d..11c170d0e342dba1c990137b44ddfa81db360260 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 1
-SUBLEVEL = 89
+SUBLEVEL = 90
 
 ARCH = i386
 
@@ -217,7 +217,7 @@ modules_install:
        \
        ls *.o > .allmods; \
        echo $$MODULES | tr ' ' '\n' | sort | comm -23 .allmods - > .misc; \
-       inst_mod .misc misc; \
+       if [ -s .misc ]; then inst_mod .misc misc; fi; \
        rm -f .misc .allmods; \
        )
 
index 86bac97fb6dfc2e04e7d538216aea1d966238dbc..4d0daf1e179b63b857a29b64f714dc7f7f05d67b 100644 (file)
@@ -210,7 +210,7 @@ bool '/proc filesystem support' CONFIG_PROC_FS y
 if [ "$CONFIG_INET" = "y" ]; then
 bool 'NFS filesystem support' CONFIG_NFS_FS y
 fi
-if [ "$CONFIG_BLK_DEV_SR" = "y" -o "$CONFIG_CDU31A" = "y" -o "$CONFIG_MCD" = "y" -o "$CONFIG_SBPCD" = "y" -o "$CONFIG_BLK_DEV_IDECD" = "y" ]; then
+if [ "$CONFIG_BLK_DEV_SR" = "y" -o "$CONFIG_CDU31A" = "y" -o "$CONFIG_MCD" = "y" -o "$CONFIG_SBPCD" = "y" -o "$CONFIG_BLK_DEV_IDECD" = "y" -o "$CONFIG_AZTCD" = "y" ]; then
        bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS y
 else
        bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS n
index f3adcb021cad674d328dd92398c8c3e77919d48c..bace95f4e393c0aa7723f8b8364cf0305d442473 100644 (file)
@@ -66,6 +66,7 @@ static int write_ldt(void * ptr, unsigned long bytecount)
                        if (task[i] == current) {
                                if (!(current->ldt = (struct desc_struct*) vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE)))
                                        return -ENOMEM;
+                               memset(current->ldt, 0, LDT_ENTRIES*LDT_ENTRY_SIZE);
                                set_ldt_desc(gdt+(i<<1)+FIRST_LDT_ENTRY, current->ldt, LDT_ENTRIES);
                                load_ldt(i);
                        }
index 95ebdbddb99c582a2324fc81b8013a0b80312d7f..0dbe2715b64c24527c15616d91f9cf705b0f0371 100644 (file)
@@ -254,6 +254,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
        }
        regs->esp = (unsigned long) frame;
        regs->eip = eip;                /* "return" to the first handler */
+       regs->eflags &= ~TF_MASK;
        current->tss.trap_no = current->tss.error_code = 0;
        return 1;
 }
index cd2d25ff0517212b0838742f6fad23988f6dff9d..6dd7fc65b637b1a86eefc8f4d083396e62f960f9 100644 (file)
@@ -178,23 +178,14 @@ DO_ERROR(17, SIGSEGV, "alignment check", alignment_check, current)
 
 asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
 {
-       int signr = SIGSEGV;
-
        if (regs->eflags & VM_MASK) {
                handle_vm86_fault((struct vm86_regs *) regs, error_code);
                return;
        }
        die_if_kernel("general protection",regs,error_code);
-       switch (get_seg_byte(regs->cs, (char *)regs->eip)) {
-               case 0xCD: /* INT */
-               case 0xF4: /* HLT */
-               case 0xFA: /* CLI */
-               case 0xFB: /* STI */
-                       signr = SIGILL;
-       }
        current->tss.error_code = error_code;
        current->tss.trap_no = 13;
-       send_sig(signr, current, 1);    
+       send_sig(SIGSEGV, current, 1);  
 }
 
 asmlinkage void do_nmi(struct pt_regs * regs, long error_code)
index b70a256ce4c7468aa6f9d7c9d5e60038be942079..1a927deeeeb003fdfa996ac231d727b44107dadd 100644 (file)
@@ -1,6 +1,6 @@
 /* ioport.c:  I/O access on the Sparc. Work in progress.. Most of the things
  *            in this file are for the sole purpose of getting the kernel
- *           throught the compiler. :-)
+ *           through the compiler. :-)
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  */
index 23a9afe6feed16b8b17e6d7697a366aef30c9ce7..5b831edb095017fbab72a5d53213b4745cb01c56 100644 (file)
@@ -97,7 +97,7 @@ extern unsigned long free_area_init(unsigned long, unsigned long);
  * unmaps the bootup page table (as we're now in KSEG, so we don't need it).
  *
  * The bootup sequence put the virtual page table into high memory: that
- * means that we cah change the L1 page table by just using VL1p below.
+ * means that we can change the L1 page table by just using VL1p below.
  */
 
 unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
index 0d494770930053ef646586d6edba2099f316cf96..514fd3dbeb8022bb7234ece218cb38767d6d431e 100644 (file)
@@ -35,16 +35,70 @@ restore the default behaviour.
        Sets the bitmask of allowed drives to <mask>. By default, only units
        0 and 1 of each floppy controller are allowed. This is done because
        certain non-standard hardware (ASUS PCI motherboards) mess up the
-       keyboard when accessing units 2 or 3.
+       keyboard when accessing units 2 or 3. This option is somewhat
+       obsoleted by the cmos option.
+
+ floppy=all_drives
+       Sets the bitmask of allowed drives to all drives. Use this if you have
+       more than two drives connected to a floppy controller.
+
+ floppy=asus_pci
+       Sets the bitmask to allow only units 0 and 1. (The default)
+
+ floppy=daring
+       Tells the floppy driver that you have a well behaved floppy controller.
+       This allows more efficient and smoother operation, but may fail on
+       certain controllers. This may speed up certain operations.
+
+ floppy=0,daring
+       Tells the floppy driver that your floppy controller should be used
+       with caution.
+
+ floppy=one_fdc
+       Tells the floppy driver that you have only floppy controller (default)
 
  floppy=two_fdc
+ floppy=<address>,two_fdc
        Tells the floppy driver that you have two floppy controllers. The
-       second floppy controller is assumed to be at io address 0x370.
+       second floppy controller is assumed to be at <address>. If <address>
+       is not given, 0x370 is assumed.
 
  floppy=thinkpad
        Tells the floppy driver that you have a Thinkpad. Thinkpads use an
        inverted convention for the disk change line.
 
+ floppy=0,thinkpad
+       Tells the floppy driver that you don't have a Thinkpad.
+
+ floppy=<drive>,<type>,cmos
+       Sets the cmos type of <drive> to <type>. Additionnaly, this drive is
+       allowed in the bitmask. This is useful if you have more than two
+       floppy drives (only two can be described in the physical cmos), or if
+       your BIOS uses non-standard CMOS types. The CMOS types are:
+               0 - unknown or not installed
+               1 - 5 1/4 DD
+               2 - 5 1/4 HD
+               3 - 3 1/2 DD
+               4 - 3 1/2 HD
+               5 - 3 1/2 ED
+               6 - 3 1/2 ED
+       (Note: there are two valid types for ED drives. This is because 5 was
+       initially chosen to represent floppy *tapes*, and 6 for ED drives.
+       AMI ignored this, and used 5 for ED drives. That's why the floppy
+       driver handles both)
+       Setting the CMOS to 0 for the first two drives (default) makes the
+       floppy driver read the physical cmos for those drives.
+
+ floppy=unexpected_interrupts
+       Print a warning message when an unexpected interrupt is received 
+       (default behaviour)
+
+ floppy=no_unexpected_interrupts
+ floppy=L40SX
+       Don't print a message when an unexpected interrupt is received. This
+       is needed on IBM L40SX laptops in certain video modes. (There seems
+       to be an interaction between video and floppy. The unexpected interrupts
+       only affect performance, and can safely be ignored.)
 
 
 Supporting utilities and additional documentation:
index 47f767c70993c61e4dafc2ec931b5abaffb561d8..624d407618cf0a2658be2dbde7d18f431601ef0e 100644 (file)
@@ -638,7 +638,7 @@ azt_Play.end.min, azt_Play.end.sec, azt_Play.end.frame);
                break;
        case CDROMVOLCTRL:   /* Volume control 
         * With my Aztech CD268-01A volume control does not work, I can only
-          turn the cannels on (any value !=0) or off (value==0). Maybe it
+          turn the channels on (any value !=0) or off (value==0). Maybe it
            works better with your drive */
                 st=verify_area(VERIFY_READ,(void *) arg, sizeof(volctrl));
                 if (st) return (st);
index 5be8a9030c133ae747eeda4c722aeaf82a1f3dc8..81faa1240b9251a539aa9c0c082a9468646a58bf 100644 (file)
@@ -82,7 +82,6 @@
  */
 
 #define CONFIG_FLOPPY_SANITY
-#define  CONFIG_FLOPPY_2_FDC
 #undef  CONFIG_FLOPPY_SILENT_DCL_CLEAR
 
 #define REALLY_SLOW_IO
@@ -92,6 +91,9 @@
 
 #include <linux/config.h>
 
+/* do print messages for unexpected interupts */
+static int print_unex=1;
+
 #ifndef FD_MODULE
 /* the following is the mask of allowed drives. By default units 2 and
  * 3 of both floppy controllers are disabled, because switching on the
@@ -148,14 +150,8 @@ static int initialising=1;
 #define FLOPPY1_TYPE 0
 #endif
 
-
-#ifdef CONFIG_FLOPPY_2_FDC
 #define N_FDC 2
 #define N_DRIVE 8
-#else
-#define N_FDC 1
-#define N_DRIVE 4
-#endif
 
 #define TYPE(x) ( ((x)>>2) & 0x1f )
 #define DRIVE(x) ( ((x)&0x03) | (((x)&0x80 ) >> 5))
@@ -179,16 +175,16 @@ static int initialising=1;
 #define USETF(x) (set_bit(x##_BIT, &UDRS->flags))
 #define UTESTF(x) (test_bit(x##_BIT, &UDRS->flags))
 
-#define DPRINT(x) printk(DEVICE_NAME "%d: " x,current_drive);
+#define DPRINT(x) printk(DEVICE_NAME "%d: " x,current_drive)
 
 #define DPRINT1(x,x1) \
-printk(DEVICE_NAME "%d: " x,current_drive,(x1));
+printk(DEVICE_NAME "%d: " x,current_drive,(x1))
 
 #define DPRINT2(x,x1,x2) \
-printk(DEVICE_NAME "%d: " x,current_drive,(x1),(x2));
+printk(DEVICE_NAME "%d: " x,current_drive,(x1),(x2))
 
 #define DPRINT3(x,x1,x2,x3) \
-printk(DEVICE_NAME "%d: " x,current_drive,(x1),(x2),(x3));
+printk(DEVICE_NAME "%d: " x,current_drive,(x1),(x2),(x3))
 
 /* read/write */
 #define COMMAND raw_cmd.cmd[0]
@@ -348,11 +344,8 @@ static struct floppy_struct floppy_type[32] = {
 
 /* Auto-detection: Disk type used until the next media change occurs. */
 struct floppy_struct *current_type[N_DRIVE] = {
+       NULL, NULL, NULL, NULL,
        NULL, NULL, NULL, NULL
-#ifdef CONFIG_FLOPPY_2_FDC
-       ,
-       NULL, NULL, NULL, NULL
-#endif
 };
 
 /*
@@ -645,9 +638,7 @@ static void set_fdc(int drive)
                current_drive = drive;
        }
        set_dor(fdc,~0,8);
-#ifdef CONFIG_FLOPPY_2_FDC
        set_dor(1-fdc, ~8, 0);
-#endif
        if ( FDCS->rawcmd == 2 )
                reset_fdc_info(1);
        if( inb_p(FD_STATUS) != STATUS_READY )
@@ -713,14 +704,11 @@ static struct timer_list motor_off_timer[N_DRIVE] = {
        { NULL, NULL, 0, 0, motor_off_callback },
        { NULL, NULL, 0, 1, motor_off_callback },
        { NULL, NULL, 0, 2, motor_off_callback },
-       { NULL, NULL, 0, 3, motor_off_callback }
-#ifdef CONFIG_FLOPPY_2_FDC
-       ,
+       { NULL, NULL, 0, 3, motor_off_callback },
        { NULL, NULL, 0, 4, motor_off_callback },
        { NULL, NULL, 0, 5, motor_off_callback },
        { NULL, NULL, 0, 6, motor_off_callback },
        { NULL, NULL, 0, 7, motor_off_callback }
-#endif
 };
 
 /* schedules motor off */
@@ -1438,18 +1426,22 @@ static void unexpected_floppy_interrupt(void)
        int i;
        if ( initialising )
                return;
-       DPRINT("unexpected interrupt\n");
-       if ( inr >= 0 )
-               for(i=0; i<inr; i++)
-                       printk("%d %x\n", i, reply_buffer[i] );
+       if(print_unex){
+               DPRINT("unexpected interrupt\n");
+               if ( inr >= 0 )
+                       for(i=0; i<inr; i++)
+                               printk("%d %x\n", i, reply_buffer[i] );
+       }
        while(1){
                output_byte(FD_SENSEI);
                inr=result();
                if ( inr != 2 )
                        break;
-               printk("sensei\n");
-               for(i=0; i<inr; i++)
-                       printk("%d %x\n", i, reply_buffer[i] );
+               if(print_unex){
+                       printk("sensei\n");
+                       for(i=0; i<inr; i++)
+                               printk("%d %x\n", i, reply_buffer[i] );
+               }
        }
        FDCS->reset = 1;
 }
@@ -2829,9 +2821,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
                             cnt < (type << 2 ) + 4 ;
                             cnt++)
                                floppy_sizes[cnt]=
-#ifdef CONFIG_FLOPPY_2_FDC
                                        floppy_sizes[cnt+0x80]=
-#endif
                                                floppy_type[type].size>>1;
                        process_fd_request();
                        for ( cnt = 0; cnt < N_DRIVE; cnt++){
@@ -2899,36 +2889,44 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
 #undef IOCTL_ALLOWED
 }
 
-static void set_base_type(int drive,int code)
-{
-       if (code > 0 && code <= NUMBER(default_drive_params)) {
-               memcpy((char *) UDP,
-                      (char *) (&default_drive_params[code].params),
-                      sizeof( struct floppy_drive_params ));
-               printk("fd%d is %s", drive, default_drive_params[code].name);
-               return;
-       } else if (!code)
-               printk("fd%d is not installed", drive);
-       else
-               printk("fd%d is unknown type %d",drive,code);
-}
-
 static void config_types(void)
 {
+       int first=1;
        int drive;
 
-       for (drive=0; drive<N_DRIVE ; drive++){
-               /* default type for unidentifiable drives */
-               memcpy((char *) UDP, (char *) (&default_drive_params->params),
-                      sizeof( struct floppy_drive_params ));
-       }
-       printk("Floppy drive(s): ");
-       set_base_type(0, FLOPPY0_TYPE);
-       if (FLOPPY1_TYPE) {
-               printk(", ");
-               set_base_type(1, FLOPPY1_TYPE);
+       /* read drive info out of physical cmos */
+       drive=0;
+       if (!UDP->cmos )
+               UDP->cmos= FLOPPY0_TYPE;
+       drive=1;
+       if (!UDP->cmos && FLOPPY1_TYPE)
+               UDP->cmos = FLOPPY1_TYPE;
+
+       /* XXX */
+       /* additional physical CMOS drive detection should go here */
+
+       for (drive=0; drive < N_DRIVE; drive++){
+               if (UDP->cmos >= 0 && UDP->cmos <= NUMBER(default_drive_params))
+                       memcpy((char *) UDP,
+                              (char *) (&default_drive_params[(int)UDP->cmos].params),
+                              sizeof(struct floppy_drive_params));
+               if (UDP->cmos){
+                       if (first)
+                               printk("Floppy drive(s): ");
+                       else
+                               printk(", ");
+                       first=0;
+                       if (UDP->cmos > 0 ){
+                               ALLOWED_DRIVE_MASK |= 1 << drive;
+                               printk("fd%d is %s", drive,
+                                      default_drive_params[(int)UDP->cmos].name);
+                       } else
+                               printk("fd%d is unknown type %d",drive,
+                                      UDP->cmos);
+               }
        }
-       printk("\n");
+       if(!first)
+               printk("\n");
 }
 
 static int floppy_read(struct inode * inode, struct file * filp,
@@ -3204,56 +3202,128 @@ static char get_fdc_version(void)
 } /* get_fdc_version */
 
 /* lilo configuration */
-static void invert_dcl(int *ints)
+
+/* we make the invert_dcl function global. One day, somebody might
+want to centralize all thinkpad related options into one lilo option,
+there are just so many thinpad related quirks! */
+void floppy_invert_dcl(int *ints,int param)
 {
        int i;
        
-       for (i=0; i < ARRAY_SIZE(default_drive_params); i++)
-               default_drive_params[i].params.flags |= 0x80;
+       for (i=0; i < ARRAY_SIZE(default_drive_params); i++){
+               if (param)
+                       default_drive_params[i].params.flags |= 0x80;
+               else
+                       default_drive_params[i].params.flags &= ~0x80;
+       }
        DPRINT("Configuring drives for inverted dcl\n");
 }
 
-static void allow_drives(int *ints)
+static void daring(int *ints,int param)
 {
-       if (ints[1] >= 1 ){
-               ALLOWED_DRIVE_MASK=ints[1];
-               DPRINT1("setting allowed_drive_mask to 0x%x\n", ints[1]);
-       } else
-               DPRINT("allowed_drive_mask needs a parameter\n");
+       int i;
+
+       for (i=0; i < ARRAY_SIZE(default_drive_params); i++){
+               if (param){
+                       default_drive_params[i].params.select_delay = 0;
+                       default_drive_params[i].params.flags |= FD_SILENT_DCL_CLEAR;
+               } else {
+                       default_drive_params[i].params.select_delay = 2;
+                       default_drive_params[i].params.flags &= ~FD_SILENT_DCL_CLEAR;
+               }
+       }
+       DPRINT1("Assuming %s floppy hardware\n", param ? "standard" : "broken");
 }
 
-#ifdef  CONFIG_FLOPPY_2_FDC
-static void twofdc(int *ints)
+static void allow_drives(int *ints, int param)
 {
-       FDC2 = 0x370;
-       DPRINT("enabling second fdc at address 0x370\n");
+       ALLOWED_DRIVE_MASK=param;
+       DPRINT1("setting allowed_drive_mask to 0x%x\n", param);
 }
-#endif
 
+static void fdc2_adr(int *ints, int param)
+{
+       FDC2 = param;
+       if(param)
+               DPRINT1("enabling second fdc at address 0x%3x\n", FDC2);
+       else
+               DPRINT("disabling second fdc\n");
+}
+
+static void unex(int *ints,int param)
+{
+       print_unex = param;
+       DPRINT1("%sprinting messages for unexpected interrupts\n",
+               param ? "" : "not ");
+}
+
+static void set_cmos(int *ints, int dummy)
+{
+       int current_drive=0;
+
+       if ( ints[0] != 2 ){
+               DPRINT("wrong number of parameter for cmos\n");
+               return;
+       }
+       current_drive = ints[1];
+       if (current_drive < 0 || current_drive >= 8 ){
+               DPRINT("bad drive for set_cmos\n");
+               return;
+       }
+       if(ints[2] <= 0 || ints[2] >= NUMBER(default_drive_params)){
+               DPRINT1("bad cmos code %d\n", ints[2]);
+               return;
+       }
+       DP->cmos = ints[2];
+       DPRINT1("setting cmos code to %d\n", ints[2]);
+}
+               
 static struct param_table {
        char *name;
-       void (*fn)(int *ints);
+       void (*fn)(int *ints, int param);
+       int def_param;
 } config_params[]={
-{ "allowed_drive_mask", allow_drives },
-#ifdef  CONFIG_FLOPPY_2_FDC
-{ "two_fdc", twofdc },
-#endif
-{ "thinkpad", invert_dcl } };
+{ "allowed_drive_mask", allow_drives, 0xff },
+{ "all_drives", allow_drives, 0xff },
+{ "asus_pci", allow_drives, 0x33 },
+
+{ "daring", daring, 1},
+
+{ "two_fdc", fdc2_adr, 0x370 },
+{ "one_fdc", fdc2_adr, 0 },
 
+{ "thinkpad", floppy_invert_dcl, 1 },
+
+{ "cmos", set_cmos, 0 },
+
+{ "unexpected_interrupts", unex, 1 },
+{ "no_unexpected_interrupts", unex, 0 },
+{ "L40SX", unex, 0 } };
+
+#define FLOPPY_SETUP
 void floppy_setup(char *str, int *ints)
 {
        int i;
+       int param;
        if(!str)
                return;
        for(i=0; i< ARRAY_SIZE(config_params); i++){
                if (strcmp(str,config_params[i].name) == 0 ){
-                       config_params[i].fn(ints);
+                       if (ints[0] )
+                               param = ints[1];
+                       else
+                               param = config_params[i].def_param;
+                       config_params[i].fn(ints,param);
                        return;
                }
        }
-       printk("unknown floppy parameter %s\n", str);
+       DPRINT1("unknown floppy option %s\n", str);
+       DPRINT("allowed options are:");
+       for(i=0; i< ARRAY_SIZE(config_params); i++)
+               printk(" %s",config_params[i].name);
+       printk("\n");
+       DPRINT("Read linux/drivers/block/README.fd\n");
 }
-#define FLOPPY_SETUP
 
 #ifdef FD_MODULE
 static
index a746968e3d0c95babdc09e565fa378a544cea3ba..980d3c851b3bbcc75b7ee643cb389b00eb563261 100644 (file)
@@ -1,31 +1,3 @@
-Thu Jan 26 09:02:49 1995  Theodore Y. Ts'o  (tytso@rt-11)
-
-       * serial.c (rs_init, set_serial_info, get_serial_info, rs_close):
-               Support close_wait and close_wait2 in the serial driver.
-               This is helpful for slow devices (like serial plotters) so
-               that their outputs don't get flushed upon device close.
-               This has to be configurable because normally we don't want
-               ports to be hung up for long periods of time during a
-               close when they are not connected to a device, or the
-               device is powered off.
-
-               The default is to wait 30 seconds after shutting down the
-               receiver (to prevent echo wars).  This is done by setting
-               close_wait=ASYNC_CLOSE_WAIT_NONE, close_wait2 = 3000.  If
-               XON/XOFF handshaking is used, then the 30 second timeout
-               should happen before the receiver is shutdown; this is
-               done by reversing the values of close_wait and
-               close_wait2.  In the case of a very slow device, the
-               timeouts for close_wait or close_wait2 should be lengthened.
-               If either value is set to 0, the kernel will wait forever
-               for all of the data to be transmitted.  
-
-Thu Jan 17 01:17:20 1995  Theodore Y. Ts'o  (tytso@rt-11)
-
-       * serial.c (startup, change_speed, rs_init): Add support to detect
-               the StarTech 16650 chip.  Treat it as a 16450 for now,
-               because of its FIFO bugs.
-
 Thu Jan  5 21:21:57 1995  <dhinds@allegro.stanford.edu>
 
        * serial.c: (receive_char): Added counter to prevent infinite loop
index db9f36685fb06d1d59f3d9907599522b0cf6b671..2a8fa35ff157fe22b600e79bb185d32eac4739d1 100644 (file)
@@ -1909,7 +1909,7 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
            ret_val = tty_check_change(tty);
            if (ret_val)
                return ret_val;
-            wait_until_sent(tty,0);
+            tty_wait_until_sent(tty,0);
             if (!arg)
                 send_break(info, HZ/4); /* 1/4 second */
             break;
@@ -1917,7 +1917,7 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
            ret_val = tty_check_change(tty);
            if (ret_val)
                return ret_val;
-            wait_until_sent(tty,0);
+            tty_wait_until_sent(tty,0);
             send_break(info, arg ? arg*(HZ/10) : HZ/4);
             break;
         case TIOCMBIS:
@@ -2060,7 +2060,7 @@ cy_close(struct tty_struct * tty, struct file * filp)
     if (info->flags & ASYNC_CALLOUT_ACTIVE)
        info->callout_termios = *tty->termios;
     if (info->flags & ASYNC_INITIALIZED)
-       wait_until_sent(tty, 3000); /* 30 seconds timeout */
+       tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
     shutdown(info);
     if (tty->driver.flush_buffer)
        tty->driver.flush_buffer(tty);
index 0a80d7f4dd85c9b64122e1982c3094efb458a019..960bb0d23657539fd46b89a837f73e4e7d0cf074 100644 (file)
@@ -164,9 +164,10 @@ static inline void kb_wait(void)
 {
        int i;
 
-       for (i=0; i<0x10000; i++)
+       for (i=0; i<0x100000; i++)
                if ((inb_p(0x64) & 0x02) == 0)
-                       break;
+                       return;
+       printk("Keyboard timed out\n");
 }
 
 static inline void send_cmd(unsigned char c)
@@ -1164,15 +1165,14 @@ unsigned long kbd_init(unsigned long kmem_start)
        bh_base[KEYBOARD_BH].routine = kbd_bh;
        request_irq(KEYBOARD_IRQ, keyboard_interrupt, 0, "keyboard");
 #ifdef __alpha__
-       /* enable keyboard interrupts */
-       outb(0x60,0x64);
-       while (inb(0x64) & 2)
-               /* nothing */;
-       outb(0x1,0x60);
-       while (inb(0x64) & 2)
-               /* nothing */;
-       if (!send_data(0xf0) || !send_data(0x01))
-               printk("Scanmode 1 change failed\n");
+       /* enable keyboard interrupts, PC/AT mode */
+       kb_wait();
+       outb(0x60,0x64);        /* write PS/2 Mode Register */
+       kb_wait();
+       outb(0x41,0x60);        /* KCC | EKI */
+       kb_wait();
+       if (!send_data(0xf0) || !send_data(0x02))
+               printk("Scanmode 2 change failed\n");
 #endif
        mark_bh(KEYBOARD_BH);
        enable_bh(KEYBOARD_BH);
index f8111121fe7e7b0cf6ac3ca7ae4e4c67f012b8eb..9e6b44ad348803f76fff4ccaafda276f2c3cc609 100644 (file)
@@ -666,7 +666,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct termios * old)
 
 static void n_tty_close(struct tty_struct *tty)
 {
-       wait_until_sent(tty, 0);
+       tty_wait_until_sent(tty, 0);
        n_tty_flush_buffer(tty);
        if (tty->read_buf) {
                free_page((unsigned long) tty->read_buf);
index 468fac11e8e7887c10f166e494906f72a92bd5fd..76816b17293680556d875424052f12985a3deb5b 100644 (file)
@@ -877,15 +877,7 @@ static int startup(struct async_struct * info)
         * Clear the FIFO buffers and disable them
         * (they will be reenabled in change_speed())
         */
-       if (info->type == PORT_16650) {
-               serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
-                                            UART_FCR_CLEAR_XMIT));
-#if 0
-               info->xmit_fifo_size = 32;
-#else
-               info->xmit_fifo_size = 1;
-#endif
-       } else if (info->type == PORT_16550A) {
+       if (info->type == PORT_16550A) {
                serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
                                             UART_FCR_CLEAR_XMIT));
                info->xmit_fifo_size = 16;
@@ -1156,18 +1148,6 @@ static void change_speed(struct async_struct *info)
                        fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
                else
                        fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
-       } else if (info->type == PORT_16650) {
-               /*
-                * On the 16650, we disable the FIFOs altogether
-                * because of a design bug in how the implement
-                * things.  We could support it by completely changing
-                * how we handle the interrupt driver, but not today....
-                *
-                * N.B.  Because there's no way to set a FIFO trigger
-                * at 1 char, we'd probably disable at speed below
-                * 2400 baud anyway...
-                */
-               fcr = 0;
        } else
                fcr = 0;
        
@@ -1424,8 +1404,6 @@ static int get_serial_info(struct async_struct * info,
        tmp.flags = info->flags;
        tmp.baud_base = info->baud_base;
        tmp.close_delay = info->close_delay;
-       tmp.closing_wait = info->closing_wait;
-       tmp.closing_wait2 = info->closing_wait2;
        tmp.custom_divisor = info->custom_divisor;
        tmp.hub6 = info->hub6;
        memcpy_tofs(retinfo,&tmp,sizeof(*retinfo));
@@ -1493,8 +1471,6 @@ static int set_serial_info(struct async_struct * info,
        info->custom_divisor = new_serial.custom_divisor;
        info->type = new_serial.type;
        info->close_delay = new_serial.close_delay;
-       info->closing_wait = new_serial.closing_wait;
-       info->closing_wait2 = new_serial.closing_wait2;
 
        release_region(info->port,8);
        if (change_port || change_irq) {
@@ -1722,7 +1698,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
                        retval = tty_check_change(tty);
                        if (retval)
                                return retval;
-                       wait_until_sent(tty, 0);
+                       tty_wait_until_sent(tty, 0);
                        if (!arg)
                                send_break(info, HZ/4); /* 1/4 second */
                        return 0;
@@ -1730,7 +1706,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
                        retval = tty_check_change(tty);
                        if (retval)
                                return retval;
-                       wait_until_sent(tty, 0);
+                       tty_wait_until_sent(tty, 0);
                        send_break(info, arg ? arg*(HZ/10) : HZ/4);
                        return 0;
                case TIOCGSOFTCAR:
@@ -1895,8 +1871,6 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
                info->normal_termios = *tty->termios;
        if (info->flags & ASYNC_CALLOUT_ACTIVE)
                info->callout_termios = *tty->termios;
-       if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-               wait_until_sent(tty, info->closing_wait);
        /*
         * At this point we stop accepting input.  To do this, we
         * disable the receive line status interrupts, and tell the
@@ -1907,7 +1881,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
        info->read_status_mask &= ~UART_LSR_DR;
        if (info->flags & ASYNC_INITIALIZED) {
                serial_out(info, UART_IER, info->IER);
-               wait_until_sent(tty, info->closing_wait2);
+               tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
                /*
                 * Before we drop DTR, make sure the UART transmitter
                 * has completely drained; this is especially
@@ -2355,10 +2329,6 @@ static void autoconfig(struct async_struct * info)
        if (info->flags & ASYNC_AUTO_IRQ)
                info->irq = do_auto_irq(info);
                
-       scratch2 = serial_in(info, UART_LCR);
-       serial_outp(info, UART_LCR, scratch2 | UART_LCR_DLAB);
-       serial_outp(info, UART_EFR, 0); /* EFR is the same as FCR */
-       serial_outp(info, UART_LCR, scratch2);
        serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
        scratch = serial_in(info, UART_IIR) >> 6;
        info->xmit_fifo_size = 1;
@@ -2373,15 +2343,8 @@ static void autoconfig(struct async_struct * info)
                        info->type = PORT_16550;
                        break;
                case 3:
-                       serial_outp(info, UART_LCR, scratch2 | UART_LCR_DLAB);
-                       if (serial_in(info, UART_EFR) == 0) {
-                               info->type = PORT_16650;
-                               info->xmit_fifo_size = 32;
-                       } else {
-                               info->type = PORT_16550A;
-                               info->xmit_fifo_size = 16;
-                       }
-                       serial_outp(info, UART_LCR, scratch2);
+                       info->type = PORT_16550A;
+                       info->xmit_fifo_size = 16;
                        break;
        }
        if (info->type == PORT_16450) {
@@ -2495,8 +2458,6 @@ long rs_init(long kmem_start)
                info->type = PORT_UNKNOWN;
                info->custom_divisor = 0;
                info->close_delay = 50;
-               info->closing_wait = ASYNC_CLOSING_WAIT_NONE;
-               info->closing_wait2 = 3000;
                info->x_char = 0;
                info->event = 0;
                info->count = 0;
@@ -2532,9 +2493,6 @@ long rs_init(long kmem_start)
                        case PORT_16550A:
                                printk(" is a 16550A\n");
                                break;
-                       case PORT_16650:
-                               printk(" is a 16650\n");
-                               break;
                        default:
                                printk("\n");
                                break;
index 9e4d1ce6657c51849d76fa2c6892735c3c5c88c8..7e006628b52b26a452da2e69014801813b6d379e 100644 (file)
@@ -40,7 +40,7 @@
 #define TERMIOS_WAIT   2
 #define TERMIOS_TERMIO 4
 
-void wait_until_sent(struct tty_struct * tty, int timeout)
+void tty_wait_until_sent(struct tty_struct * tty, int timeout)
 {
        struct wait_queue wait = { current, NULL };
 
@@ -132,7 +132,7 @@ static int set_termios(struct tty_struct * tty, unsigned long arg, int opt)
                tty->ldisc.flush_buffer(tty);
 
        if (opt & TERMIOS_WAIT)
-               wait_until_sent(tty, 0);
+               tty_wait_until_sent(tty, 0);
 
        cli();
        *tty->termios = tmp_termios;
@@ -363,7 +363,7 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file,
                        retval = tty_check_change(tty);
                        if (retval)
                                return retval;
-                       wait_until_sent(tty, 0);
+                       tty_wait_until_sent(tty, 0);
                        if (!tty->driver.ioctl)
                                return 0;
                        tty->driver.ioctl(tty, file, cmd, arg);
index b15c5f48330fe51015d73b9b2561efe4885e26a2..cfde63f106cd2c4d76256ed32b42e79c748f456e 100644 (file)
     in group 224.0.0.1 and you will therefore be listening to all multicasts.
     One nv conference running over that ethernet and you can give up.
     
+    2/8/95 (invid@msen.com)
+
+    Removed calls to init_etherdev since they are no longer needed, and
+    cleaned up modularization just a bit. The driver still allows only
+    the default address for cards when loaded as a module, but that's
+    really less braindead than anyone using a 3c501 board. :)
 */
 
 static char *version =
@@ -75,6 +81,9 @@ static char *version =
 #ifdef MODULE
 #include <linux/module.h>
 #include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
 #endif
 
 #include <linux/kernel.h>
@@ -95,9 +104,6 @@ static char *version =
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 
-extern struct device *init_etherdev(struct device *dev, int sizeof_private,
-                                   unsigned long *mem_startp);
-
 /* A zero-terminated list of I/O addresses to be probed.
    The 3c501 can be at many locations, but here are the popular ones. */
 static unsigned int netcard_portlist[] =
@@ -208,6 +214,8 @@ el1_probe(struct device *dev)
 static int
 el1_probe1(struct device *dev, int ioaddr)
 {
+    #ifndef MODULE
+
     char *mname;               /* Vendor name */
     unsigned char station_addr[6];
     int autoirq = 0;
@@ -232,9 +240,6 @@ el1_probe1(struct device *dev, int ioaddr)
     /* Grab the region so we can find the another board if autoIRQ fails. */
     request_region(ioaddr, EL1_IO_EXTENT,"3c501");
 
-    if (dev == NULL)
-       dev = init_etherdev(0, sizeof(struct net_local), 0);
-
     /* We auto-IRQ by shutting off the interrupt line and letting it float
        high. */
     if (dev->irq < 2) {
@@ -290,6 +295,7 @@ el1_probe1(struct device *dev, int ioaddr)
     /* Setup the generic properties */
     ether_setup(dev);
 
+#endif /* !MODULE */
     return 0;
 }
 
@@ -312,9 +318,7 @@ el_open(struct device *dev)
     dev->start = 1;
 
     outb(AX_RX, AX_CMD);       /* Aux control, irq and receive enabled */
-#ifdef MODULE
     MOD_INC_USE_COUNT;
-#endif       
     return 0;
 }
 
@@ -618,9 +622,7 @@ el1_close(struct device *dev)
     outb(AX_RESET, AX_CMD);    /* Reset the chip */
     irq2dev_map[dev->irq] = 0;
 
-#ifdef MODULE
     MOD_DEC_USE_COUNT;
-#endif    
     return 0;
 }
 
index e95beae6cddd3b1a6d17253ca92595e0d87cda22..ab1a3c3f76a029ff27f5ee885d3b8759a7854826 100644 (file)
@@ -115,7 +115,7 @@ ethif_probe(struct device *dev)
 #ifdef CONFIG_EWRK3             /* DEC EtherWORKS 3 */
         && ewrk3_probe(dev)
 #endif
-#ifdef CONFIG_DE4X5             /* DEC DE425, DE434, DE435 adapters */
+#ifdef CONFIG_DE4x5             /* DEC DE425, DE434, DE435 adapters */
         && de4x5_probe(dev)
 #endif
 #ifdef CONFIG_APRICOT          /* Apricot I82596 */
index 2ef5c136ad90821f5966fbbdd77232def7d03109..5ac4e07a1ff4823da75cee628fa578ee3b68f5c0 100644 (file)
@@ -686,10 +686,12 @@ de600_probe(struct device *dev)
                return ENODEV;
        }
 
+#if 0 /* Not yet */
        if (check_region(DE600_IO, 3)) {
                printk(", port 0x%x busy\n", DE600_IO);
                return EBUSY;
        }
+#endif
        request_region(DE600_IO, 3, "de600");
 
        printk(", Ethernet Address: %02X", dev->dev_addr[0]);
@@ -840,10 +842,7 @@ init_module(void)
 void
 cleanup_module(void)
 {
-       if (MOD_IN_USE)
-               printk("de600: device busy, remove delayed\n");
-       else
-               unregister_netdev(&de600_dev);
+       unregister_netdev(&de600_dev);
        release_region(DE600_IO, 3);
 }
 #endif /* MODULE */
index 1ca83c34714fe84168dd2d51e5fea6f1c5569117..17da44f0533b3356f9db5461283e476ffc3e4efc 100644 (file)
@@ -824,10 +824,12 @@ de620_probe(struct device *dev)
                return ENODEV;
        }
 
+#if 0 /* Not yet */
        if (check_region(DE620_IO, 3)) {
                printk(", port 0x%x busy\n", DE620_IO);
                return EBUSY;
        }
+#endif
        request_region(DE620_IO, 3, "de620");
 
        /* else, got it! */
@@ -987,10 +989,7 @@ init_module(void)
 void
 cleanup_module(void)
 {
-       if (MOD_IN_USE)
-               printk("de620: device busy, remove delayed\n");
-       else
-               unregister_netdev(&de620_dev);
+       unregister_netdev(&de620_dev);
        release_region(DE620_IO, 3);
 }
 #endif /* MODULE */
index ae233bc2bc8d96ac33e383dbf8e6a1e840d92e95..84350f056aca8037d051ea55f714c1374523c5d0 100644 (file)
@@ -11,7 +11,7 @@
  * CAN YOU PLEASE REPORT ME YOUR PERFORMANCE EXPERIENCES !!.
  * 
  * If you find a bug, please report me:
- *   The kernelpanic output and any kmsg from the ni52 driver
+ *   The kernel panic output and any kmsg from the ni52 driver
  *   the ni5210-driver-version and the linux-kernel version 
  *   how many shared memory (memsize) on the netcard, 
  *   bootprom: yes/no, base_addr, mem_start
  *
  * 19.Sep.94: Added Multicast support (not tested yet) (MH)
  * 
- * 18.Sep.94: Workarround for 'EL-Bug'. Removed flexible RBD-handling. 
+ * 18.Sep.94: Workaround for 'EL-Bug'. Removed flexible RBD-handling. 
  *            Now, every RFD has exact one RBD. (MH)
  *
- * 14.Sep.94: added promiscous mode, a few cleanups (MH)
+ * 14.Sep.94: added promiscuous mode, a few cleanups (MH)
  *
  * 19.Aug.94: changed request_irq() parameter (MH)
  * 
 
   * IMPORTANT NOTE: if you configure only one NUM_XMIT_BUFFS, the driver works
   * --------------- in a different (more stable?) mode. Only in this mode it's
-  *                 possbile to configure the driver with 'NO_NOPCOMMANDS'
+  *                 possible to configure the driver with 'NO_NOPCOMMANDS'
 
 sizeof(scp)=12; sizeof(scb)=16; sizeof(iscp)=8;
 sizeof(scp)+sizeof(iscp)+sizeof(scb) = 36 = INIT
@@ -272,7 +272,7 @@ static int check586(struct device *dev,char *where,unsigned size)
     ni_attn586();
     DELAY(2);  /* wait a while... */
 
-    if(p->iscp->busy) /* i82586 clears 'busy' after succesful init */
+    if(p->iscp->busy) /* i82586 clears 'busy' after successful init */
       return 0;
   }
   return 1;
@@ -611,7 +611,7 @@ static int init586(struct device *dev,int num_addrs,void *addrs)
       if(len < num_addrs)
       {
         num_addrs = len;
-        printk("%s: Sorry, can only apply %d MC-Addresse(s).\n",dev->name,num_addrs);
+        printk("%s: Sorry, can only apply %d MC-Address(es).\n",dev->name,num_addrs);
       }
       mc_cmd = (struct mcsetup_cmd_struct *) ptr;
       mc_cmd->cmd_status = 0;
@@ -845,7 +845,7 @@ static void ni52_rnr_int(struct device *dev)
   p->stats.rx_errors++;
 
   WAIT_4_SCB_CMD();    /* wait for the last cmd */
-  p->scb->cmd = RUC_ABORT; /* usually the RU is in the 'no ressource'-state .. abort it now. */
+  p->scb->cmd = RUC_ABORT; /* usually the RU is in the 'no resource'-state .. abort it now. */
   ni_attn586(); 
   WAIT_4_SCB_CMD();    /* wait for accept cmd. */
 
@@ -1081,7 +1081,7 @@ static void set_multicast_list(struct device *dev, int num_addrs, void *addrs)
 {
   if(!dev->start && !num_addrs)
   {
-    printk("%s: Can't apply promiscous/multicastmode to a not running interface.\n",dev->name);
+    printk("%s: Can't apply promiscuous/multicastmode to a not running interface.\n",dev->name);
     return;
   }
 
index efc0ee37eb37a81222c31cda7fb84b70fa3db592..a951af543a72a07668bd3fcb38765d6d46e16e74 100644 (file)
@@ -1,5 +1,5 @@
-/* $Id: plip.c,v 1.7 1994/12/16 06:20:02 gniibe Exp $ */
-/* plip.c: A parallel port "network" driver for linux. */
+/* $Id: plip.c,v 1.10 1995/02/08 05:47:12 gniibe Exp $ */
+/* PLIP: A parallel port "network" driver for Linux. */
 /* This driver is for parallel port with 5-bit cable (LapLink (R) cable). */
 /*
  * Authors:    Donald Becker,  <becker@super.org>
@@ -9,12 +9,8 @@
  *             Peter Bauer, <100136.3530@compuserve.com>
  *             Niibe Yutaka, <gniibe@mri.co.jp>
  *
- *             This is the all improved state based PLIP that Niibe Yutaka has contributed.
- *
- *             Modularization by Alan Cox. I also added the plipconfig program to tune the timeouts
- *             and ifmap support for funny serial port settings or setting odd values using the 
- *             modular plip. I also took the panic() calls out. I don't like panic - especially when
- *             it can be avoided.
+ *             Modularization and ifreq/ifmap support by Alan Cox.
+ *             Rewritten by Niibe Yutaka.
  *
  *             This program is free software; you can redistribute it and/or
  *             modify it under the terms of the GNU General Public License
 /*
  * Original version and the name 'PLIP' from Donald Becker <becker@super.org>
  * inspired by Russ Nelson's parallel port packet driver.
+ *
+ * NOTE:
+ *     Tanabe Hiroyasu had changed the protocol, and it was in Linux v1.0.
+ *     Because of the necessity to communicate to DOS machines with the
+ *     Crynwr packet driver, Peter Bauer changed the protocol again
+ *     back to original protocol.
+ *
+ *     This version follows original PLIP protocol. 
+ *     So, this PLIP can't communicate the PLIP of Linux v1.0.
  */
 
-static char *version =
-    "NET3 "
-#ifdef MODULE
-    "MODULAR "    
-#endif    
-    "PLIP $Revision: 1.7 $ gniibe@mri.co.jp\n";
+static char *version = "NET3 PLIP version 2.0 gniibe@mri.co.jp\n";
 
 /*
   Sources:
@@ -40,17 +40,19 @@ static char *version =
        "parallel.asm" parallel port packet driver.
 
   The "Crynwr" parallel port standard specifies the following protocol:
-   send header nibble '8'
-   count-low octet
-   count-high octet
-   ... data octets
-   checksum octet
+    Trigger by sending '0x08' (this cause interrupt on other end)
+    count-low octet
+    count-high octet
+    ... data octets
+    checksum octet
   Each octet is sent as <wait for rx. '0x1?'> <send 0x10+(octet&0x0F)>
                        <wait for rx. '0x0?'> <send 0x00+((octet>>4)&0x0F)>
 
-The cable used is a de facto standard parallel null cable -- sold as
-a "LapLink" cable by various places.  You'll need a 10-conductor cable to
-make one yourself.  The wiring is:
+  The packet is encapsulated as if it were ethernet.
+
+  The cable used is a de facto standard parallel null cable -- sold as
+  a "LapLink" cable by various places.  You'll need a 12-conductor cable to
+  make one yourself.  The wiring is:
     SLCTIN     17 - 17
     GROUND     25 - 25
     D0->ERROR  2 - 15          15 - 2
@@ -67,6 +69,9 @@ make one yourself.  The wiring is:
 #ifdef MODULE
 #include <linux/module.h>
 #include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
 #endif
 
 #include <linux/kernel.h>
@@ -94,9 +99,9 @@ make one yourself.  The wiring is:
 #include <asm/bitops.h>
 #include <asm/irq.h>
 
-/* use 0 for production, 1 for verification, >2 for debug */
+/* Use 0 for production, 1 for verification, >2 for debug */
 #ifndef NET_DEBUG
-#define NET_DEBUG 3
+#define NET_DEBUG 1
 #endif
 static unsigned int net_debug = NET_DEBUG;
 
@@ -107,807 +112,903 @@ static unsigned int net_debug = NET_DEBUG;
 #define PLIP_TRIGGER_WAIT       500
 
 /* Nibble time out = PLIP_NIBBLE_WAIT * PLIP_DELAY_UNIT usec */
-#define PLIP_NIBBLE_WAIT        5000
+#define PLIP_NIBBLE_WAIT        3000
 
+#define PAR_INTR_ON            (LP_PINITP|LP_PSELECP|LP_PINTEN)
+#define PAR_INTR_OFF           (LP_PINITP|LP_PSELECP)
 #define PAR_DATA(dev)          ((dev)->base_addr+0)
 #define PAR_STATUS(dev)                ((dev)->base_addr+1)
 #define PAR_CONTROL(dev)       ((dev)->base_addr+2)
 
-/* Index to functions, as function prototypes. */
+/* Bottom halfs */
+static void plip_kick_bh(struct device *dev);
+static void plip_bh(struct device *dev);
+
+/* Interrupt handler */
+static void plip_interrupt(int irq, struct pt_regs *regs);
+
+/* Functions for DEV methods */
+static int plip_rebuild_header(void *buff, struct device *dev,
+                              unsigned long raddr, struct sk_buff *skb);
 static int plip_tx_packet(struct sk_buff *skb, struct device *dev);
 static int plip_open(struct device *dev);
 static int plip_close(struct device *dev);
 static struct enet_statistics *plip_get_stats(struct device *dev);
-static int plip_rebuild_header(void *buff, struct device *dev,
-                              unsigned long raddr, struct sk_buff *skb);
-static void plip_kick_bh(struct device *dev);
-static void plip_bh(struct device *dev);
+static int plip_config(struct device *dev, struct ifmap *map);
+static int plip_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
 \f
 enum plip_connection_state {
-    PLIP_CN_NONE=0,
-    PLIP_CN_RECEIVE,
-    PLIP_CN_SEND,
-    PLIP_CN_CLOSING,
-    PLIP_CN_ERROR
+       PLIP_CN_NONE=0,
+       PLIP_CN_RECEIVE,
+       PLIP_CN_SEND,
+       PLIP_CN_CLOSING,
+       PLIP_CN_ERROR
 };
 
 enum plip_packet_state {
-    PLIP_PK_DONE=0,
-    PLIP_PK_TRIGGER,
-    PLIP_PK_LENGTH_LSB,
-    PLIP_PK_LENGTH_MSB,
-    PLIP_PK_DATA,
-    PLIP_PK_CHECKSUM
+       PLIP_PK_DONE=0,
+       PLIP_PK_TRIGGER,
+       PLIP_PK_LENGTH_LSB,
+       PLIP_PK_LENGTH_MSB,
+       PLIP_PK_DATA,
+       PLIP_PK_CHECKSUM
 };
 
 enum plip_nibble_state {
-    PLIP_NB_BEGIN,
-    PLIP_NB_1,
-    PLIP_NB_2,
+       PLIP_NB_BEGIN,
+       PLIP_NB_1,
+       PLIP_NB_2,
 };
 
-#define PLIP_STATE_STRING(x) \
-    (((x) == PLIP_PK_DONE)?"0":\
-     ((x) == PLIP_PK_TRIGGER)?"t":\
-     ((x) == PLIP_PK_LENGTH_LSB)?"l":\
-     ((x) == PLIP_PK_LENGTH_MSB)?"m":\
-     ((x) == PLIP_PK_DATA)?"d":\
-     ((x) == PLIP_PK_CHECKSUM)?"s":"B")
-
 struct plip_local {
-    enum plip_packet_state state;
-    enum plip_nibble_state nibble;
-    unsigned short length;
-    unsigned short byte;
-    unsigned char  checksum;
-    unsigned char  data;
-    struct sk_buff *skb;
+       enum plip_packet_state state;
+       enum plip_nibble_state nibble;
+       unsigned short length;
+       unsigned short byte;
+       unsigned char  checksum;
+       unsigned char  data;
+       struct sk_buff *skb;
 };
 
 struct net_local {
-    struct enet_statistics e;
-    struct tq_struct immediate;
-    struct tq_struct deferred;
-    struct plip_local snd_data;
-    struct plip_local rcv_data;
-    unsigned long  trigger_us;
-    unsigned long  nibble_us;
-    unsigned long  unit_us;
-    enum plip_connection_state connection;
-    unsigned short timeout_count;
+       struct enet_statistics enet_stats;
+       struct tq_struct immediate;
+       struct tq_struct deferred;
+       struct plip_local snd_data;
+       struct plip_local rcv_data;
+       unsigned long  trigger;
+       unsigned long  nibble;
+       unsigned long  unit;
+       enum plip_connection_state connection;
+       unsigned short timeout_count;
+       char is_deferred;
 };
-
-/* Routines used internally. */
-static void plip_device_clear(struct device *dev);
-static void plip_interrupt(int irq, struct pt_regs *regs);
-
-static int plip_error(struct device *dev);
-static int plip_receive_packet(struct device *dev);
-static int plip_send_packet(struct device *dev);
-static int plip_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
-static int plip_config(struct device *dev, struct ifmap *map);
 \f
+/* Entry point of PLIP driver.
+   Probe the hardware, and register/initialize the driver. */
 int
 plip_init(struct device *dev)
 {
-    struct net_local *nl;
+       struct net_local *nl;
 
-    /* Check that there is something at base_addr. */
-    outb(LP_PINITP, PAR_CONTROL(dev));
-    outb(0x00, PAR_DATA(dev));
-    if (inb(PAR_DATA(dev)) != 0x00)
-       return -ENODEV;
+       /* Check region before the probe */
+       if (check_region(PAR_DATA(dev), 3) < 0)
+               return -ENODEV;
 
-    /* Alpha testers must have the version number to report bugs. */
-    if (net_debug)
-       printk(version);
+       /* Check that there is something at base_addr. */
+       outb(0, PAR_DATA(dev));
+       udelay(1000);
+       if (inb(PAR_DATA(dev)) != 0)
+               return -ENODEV;
 
-    if (dev->irq) {
-       printk("%s: configured for parallel port at %#3x, IRQ %d.\n",
-              dev->name, dev->base_addr, dev->irq);
-    } else {
-       printk("%s: configured for parallel port at %#3x",
-              dev->name, dev->base_addr);
+       printk(version);
+       printk("%s: Parallel port at %#3lx, ", dev->name, dev->base_addr);
+       if (dev->irq) {
+               printk("using assigned IRQ %d.\n", dev->irq);
+       } else {
+               int irq = 0;
 #ifdef MODULE
-       /* autoirq doesn't work :(, but we can set it by ifconfig */
+               /* dev->irq==0 means autoprobe, but we don't try to do so
+                  with module.  We can change it by ifconfig */
 #else
-       autoirq_setup(0);
-       outb(LP_PINITP|LP_PSELECP, PAR_CONTROL(dev));
-       outb(LP_PINITP|LP_PSELECP|LP_PINTEN, PAR_CONTROL(dev));
-       outb(LP_PINITP|LP_PSELECP, PAR_CONTROL(dev));
-       dev->irq = autoirq_report(1);
+               unsigned int irqs = probe_irq_on();
+
+               outb(0x00, PAR_CONTROL(dev));
+               udelay(1000);
+               outb(PAR_INTR_OFF, PAR_CONTROL(dev));
+               outb(PAR_INTR_ON, PAR_CONTROL(dev));
+               outb(PAR_INTR_OFF, PAR_CONTROL(dev));
+               udelay(1000);
+               irq = probe_irq_off(irqs);
 #endif
-       if (dev->irq)
-           printk(", probed IRQ %d.\n", dev->irq);
-       else {
-           printk(", failed to detect IRQ line.\n");
-           return -ENODEV;
+               if (irq > 0) {
+                       dev->irq = irq;
+                       printk("using probed IRQ %d.\n", dev->irq);
+               } else
+                       printk("failed to detect IRQ(%d) --"
+                              " Please set IRQ by ifconfig.\n", irq);
        }
-    }
-
-    request_region(PAR_DATA(dev), 3,"plip");
-
-    /* Fill in the generic fields of the device structure. */
-    ether_setup(dev);
-
-    /* And, override parts of it */
-    dev->rebuild_header        = plip_rebuild_header;
-    dev->hard_start_xmit       = plip_tx_packet;
-    dev->open                  = plip_open;
-    dev->stop                  = plip_close;
-    dev->get_stats             = plip_get_stats;
-    dev->set_config            = plip_config;
-    dev->do_ioctl              = plip_ioctl;
-    dev->flags                 = IFF_POINTOPOINT;
-
-    /* Set private structure */
-    dev->priv = kmalloc(sizeof (struct net_local), GFP_KERNEL);
-    memset(dev->priv, 0, sizeof(struct net_local));
-    nl = (struct net_local *) dev->priv;
-    
-    /* initialize constants */
-    nl->trigger_us     = PLIP_TRIGGER_WAIT;
-    nl->nibble_us      = PLIP_NIBBLE_WAIT;
-    nl->unit_us                = PLIP_DELAY_UNIT;
-
-    /* initialize task queue structures */
-    nl->immediate.next = &tq_last;
-    nl->immediate.sync = 0;
-    nl->immediate.routine = (void *)(void *)plip_bh;
-    nl->immediate.data = dev;
-
-    nl->deferred.next = &tq_last;
-    nl->deferred.sync = 0;
-    nl->deferred.routine = (void *)(void *)plip_kick_bh;
-    nl->deferred.data = dev;
-
-    return 0;
+
+       request_region(PAR_DATA(dev), 3, dev->name);
+
+       /* Fill in the generic fields of the device structure. */
+       ether_setup(dev);
+
+       /* Then, override parts of it */
+       dev->rebuild_header     = plip_rebuild_header;
+       dev->hard_start_xmit    = plip_tx_packet;
+       dev->open               = plip_open;
+       dev->stop               = plip_close;
+       dev->get_stats          = plip_get_stats;
+       dev->set_config         = plip_config;
+       dev->do_ioctl           = plip_ioctl;
+       dev->flags              = IFF_POINTOPOINT;
+
+       /* Set the private structure */
+       dev->priv = kmalloc(sizeof (struct net_local), GFP_KERNEL);
+       memset(dev->priv, 0, sizeof(struct net_local));
+       nl = (struct net_local *) dev->priv;
+
+       /* Initialize constants */
+       nl->trigger     = PLIP_TRIGGER_WAIT;
+       nl->nibble      = PLIP_NIBBLE_WAIT;
+       nl->unit        = PLIP_DELAY_UNIT;
+
+       /* Initialize task queue structures */
+       nl->immediate.next = &tq_last;
+       nl->immediate.sync = 0;
+       nl->immediate.routine = (void *)(void *)plip_bh;
+       nl->immediate.data = dev;
+
+       nl->deferred.next = &tq_last;
+       nl->deferred.sync = 0;
+       nl->deferred.routine = (void *)(void *)plip_kick_bh;
+       nl->deferred.data = dev;
+
+       return 0;
 }
 \f
+/* Bottom half handler for the delayed request.
+   This routine is kicked by do_timer().
+   Request `plip_bh' to be invoked. */
 static void
 plip_kick_bh(struct device *dev)
 {
-    struct net_local *nl = (struct net_local *)dev->priv;
+       struct net_local *nl = (struct net_local *)dev->priv;
 
-    if (nl->connection == PLIP_CN_NONE)
-       return;
-    queue_task(&nl->immediate, &tq_immediate);
-    mark_bh(IMMEDIATE_BH);
-    return;
+       if (nl->is_deferred) {
+               queue_task(&nl->immediate, &tq_immediate);
+               mark_bh(IMMEDIATE_BH);
+       }
 }
 
+/* Forward declarations of internal routines */
+static int plip_none(struct device *, struct net_local *,
+                    struct plip_local *, struct plip_local *);
+static int plip_receive_packet(struct device *, struct net_local *,
+                              struct plip_local *, struct plip_local *);
+static int plip_send_packet(struct device *, struct net_local *,
+                           struct plip_local *, struct plip_local *);
+static int plip_connection_close(struct device *, struct net_local *,
+                                struct plip_local *, struct plip_local *);
+static int plip_error(struct device *, struct net_local *,
+                     struct plip_local *, struct plip_local *);
+static int plip_bh_timeout_error(struct device *dev, struct net_local *nl,
+                                struct plip_local *snd,
+                                struct plip_local *rcv,
+                                int error);
+
+#define OK        0
+#define TIMEOUT   1
+#define ERROR     2
+
+typedef int (*plip_func)(struct device *dev, struct net_local *nl,
+                        struct plip_local *snd, struct plip_local *rcv);
+
+static plip_func connection_state_table[] =
+{
+       plip_none,
+       plip_receive_packet,
+       plip_send_packet,
+       plip_connection_close,
+       plip_error
+};
+
+/* Bottom half handler of PLIP. */
 static void
 plip_bh(struct device *dev)
 {
-    struct net_local *nl = (struct net_local *)dev->priv;
-    struct enet_statistics *stats = (struct enet_statistics *) dev->priv;
-    struct plip_local *rcv = &nl->rcv_data;
-    struct plip_local *snd = &nl->snd_data;
-    int result, timeout=0;
-    unsigned char *s;
-    unsigned char c0;
-    struct sk_buff *skb;
-
-    while (!timeout) {
-       cli();
-       switch (nl->connection) {
-       case PLIP_CN_NONE:
-           sti();
-           return;
-
-       case PLIP_CN_RECEIVE:
-           sti();
-           disable_irq(dev->irq);
-           outb(LP_PINITP|LP_PSELECP, PAR_CONTROL(dev));
-           outb(0x01, PAR_DATA(dev));   /* send ACK */
-           dev->interrupt = 0;
-           result = plip_receive_packet(dev);
-           if (result == 0) { /* success */
-               outb (0x00, PAR_DATA(dev));
-               skb = rcv->skb;
-               rcv->skb = NULL;
-               stats->rx_packets++;
-               netif_rx(skb);
-               if (snd->state != PLIP_PK_DONE) {
-                   nl->connection = PLIP_CN_SEND;
-                   outb(LP_PINITP|LP_PSELECP|LP_PINTEN, PAR_CONTROL(dev));
-                   enable_irq(dev->irq);
-               } else {
-                   nl->connection = PLIP_CN_NONE;
-                   outb(LP_PINITP|LP_PSELECP|LP_PINTEN, PAR_CONTROL(dev));
-                   enable_irq(dev->irq);
-                   return;
-               }
-           } else if (result == -1) { /* failure */
-               outb(0x00, PAR_DATA(dev));
-               if (rcv->skb)
-                   dev_kfree_skb(rcv->skb, FREE_WRITE);
-               rcv->state = PLIP_PK_DONE;
-               rcv->skb = NULL;
-               if (snd->skb)
-                   dev_kfree_skb(snd->skb, FREE_WRITE);
-               snd->state = PLIP_PK_DONE;
-               snd->skb = NULL;
-               dev->tbusy = 1;
-               nl->connection = PLIP_CN_ERROR;
-           } else
-               timeout = 1;
-           break;
-
-       case PLIP_CN_SEND:
-           sti();
-           result = plip_send_packet(dev);
-           if (result == -1) /* interrupted */
-               break;
-           if (result == 0) { /* success */
-               outb (0x00, PAR_DATA(dev));
-               snd->state = PLIP_PK_DONE;
-               snd->skb = NULL;
-               nl->connection = PLIP_CN_CLOSING;
-               queue_task(&nl->deferred, &tq_timer);
-               outb(LP_PINITP|LP_PSELECP|LP_PINTEN, PAR_CONTROL(dev));
-               enable_irq(dev->irq);
-               return;
-           } else
-               timeout = 1;
-           break;
-
-       case PLIP_CN_CLOSING:
-           sti();
-           nl->connection = PLIP_CN_NONE;
-           mark_bh(NET_BH);
-           dev->tbusy = 0;
-           return;
-
-       case PLIP_CN_ERROR:
-           sti();
-           result = plip_error(dev);
-           if (result == 0) {
-               nl->connection = PLIP_CN_NONE;
-               dev->tbusy = 0;
-               outb(LP_PINITP|LP_PSELECP|LP_PINTEN, PAR_CONTROL(dev));
-               enable_irq(dev->irq);
-               return;
-           } else {
+       struct net_local *nl = (struct net_local *)dev->priv;
+       struct plip_local *snd = &nl->snd_data;
+       struct plip_local *rcv = &nl->rcv_data;
+       plip_func f;
+       int r;
+
+       nl->is_deferred = 0;
+       f = connection_state_table[nl->connection];
+       if ((r = (*f)(dev, nl, snd, rcv)) != OK
+           && (r = plip_bh_timeout_error(dev, nl, snd, rcv, r)) != OK) {
+               nl->is_deferred = 1;
                queue_task(&nl->deferred, &tq_timer);
-               return;
-           }
-           break;
        }
-    }
+}
 
-    /* timeout */
-    if (++nl->timeout_count > 3) { /* cable problem? */
-       c0 = inb(PAR_STATUS(dev));
+static int
+plip_bh_timeout_error(struct device *dev, struct net_local *nl,
+                     struct plip_local *snd, struct plip_local *rcv,
+                     int error)
+{
+       unsigned char c0;
 
+       cli();
        if (nl->connection == PLIP_CN_SEND) {
-           stats->tx_errors++;
-           stats->tx_aborted_errors++;
-           s =  PLIP_STATE_STRING(snd->state);
-           if (net_debug > 1)
-               printk("%s: transmit timeout(%s,%02x)... reset interface.\n",
-                      dev->name, s, (unsigned int)c0);
-           if (snd->skb)
-               dev_kfree_skb(snd->skb, FREE_WRITE);
+
+               if (error != ERROR) { /* Timeout */
+                       nl->timeout_count++;
+                       if ((snd->state == PLIP_PK_TRIGGER
+                            && nl->timeout_count <= 10)
+                           || nl->timeout_count <= 3) {
+                               sti();
+                               /* Try again later */
+                               return TIMEOUT;
+                       }
+                       c0 = inb(PAR_STATUS(dev));
+                       printk("%s: transmit timeout(%d,%02x)\n",
+                              dev->name, snd->state, c0);
+               }
+               nl->enet_stats.tx_errors++;
+               nl->enet_stats.tx_aborted_errors++;
        } else if (nl->connection == PLIP_CN_RECEIVE) {
-           stats->rx_dropped++;
-           s =  PLIP_STATE_STRING(rcv->state);
-           if (net_debug > 1)
-               printk("%s: receive timeout(%s,%02x)... reset interface.\n",
-                      dev->name, s, (unsigned int)c0);
-           if (rcv->skb)
-               dev_kfree_skb(rcv->skb, FREE_WRITE);
+               if (rcv->state == PLIP_PK_TRIGGER) {
+                       /* Transmission was interrupted. */
+                       sti();
+                       return OK;
+               }
+               if (error != ERROR) { /* Timeout */
+                       if (++nl->timeout_count <= 3) {
+                               sti();
+                               /* Try again later */
+                               return TIMEOUT;
+                       }
+                       c0 = inb(PAR_STATUS(dev));
+                       printk("%s: receive timeout(%d,%02x)\n",
+                              dev->name, rcv->state, c0);
+               }
+               nl->enet_stats.rx_dropped++;
+       }
+       rcv->state = PLIP_PK_DONE;
+       if (rcv->skb) {
+               rcv->skb->free = 1;
+               kfree_skb(rcv->skb, FREE_READ);
+               rcv->skb = NULL;
+       }
+       snd->state = PLIP_PK_DONE;
+       if (snd->skb) {
+               dev_kfree_skb(snd->skb, FREE_WRITE);
+               snd->skb = NULL;
        }
        disable_irq(dev->irq);
-       outb(LP_PINITP|LP_PSELECP, PAR_CONTROL(dev));
+       outb(PAR_INTR_OFF, PAR_CONTROL(dev));
        dev->tbusy = 1;
        nl->connection = PLIP_CN_ERROR;
        outb(0x00, PAR_DATA(dev));
-    }
+       sti();
 
-    queue_task(&nl->deferred, &tq_timer);
-    return;
+       return TIMEOUT;
 }
 \f
 static int
-plip_tx_packet(struct sk_buff *skb, struct device *dev)
+plip_none(struct device *dev, struct net_local *nl,
+         struct plip_local *snd, struct plip_local *rcv)
 {
-    struct net_local *nl = (struct net_local *)dev->priv;
-    struct plip_local *snd = &nl->snd_data;
-
-    if (dev->tbusy)
-       return 1;
-
-    /* If some higher layer thinks we've missed an tx-done interrupt
-       we are passed NULL. Caution: dev_tint() handles the cli()/sti()
-       itself. */
-    if (skb == NULL) {
-       dev_tint(dev);
-       return 0;
-    }
+       return OK;
+}
 
-    if (set_bit(0, (void*)&dev->tbusy) != 0) {
-       printk("%s: Transmitter access conflict.\n", dev->name);
-       return 1;
-    }
+/* PLIP_RECEIVE --- receive a byte(two nibbles)
+   Returns OK on success, TIMEOUT on timeout */
+inline static int
+plip_receive(unsigned short nibble_timeout, unsigned short unit,
+            unsigned short status_addr, unsigned short data_addr,
+            enum plip_nibble_state *ns_p, unsigned char *data_p)
+{
+       unsigned char c0, c1;
+       unsigned int cx;
+
+       switch (*ns_p) {
+       case PLIP_NB_BEGIN:
+               cx = nibble_timeout;
+               while (1) {
+                       c0 = inb(status_addr);
+                       udelay(unit);
+                       if ((c0 & 0x80) == 0) {
+                               c1 = inb(status_addr);
+                               if (c0 == c1)
+                                       break;
+                       }
+                       if (--cx == 0)
+                               return TIMEOUT;
+               }
+               *data_p = (c0 >> 3) & 0x0f;
+               outb(0x10, data_addr); /* send ACK */
+               *ns_p = PLIP_NB_1;
+
+       case PLIP_NB_1:
+               cx = nibble_timeout;
+               while (1) {
+                       c0 = inb(status_addr);
+                       udelay(unit);
+                       if (c0 & 0x80) {
+                               c1 = inb(status_addr);
+                               if (c0 == c1)
+                                       break;
+                       }
+                       if (--cx == 0)
+                               return TIMEOUT;
+               }
+               *data_p |= (c0 << 1) & 0xf0;
+               outb(0x00, data_addr); /* send ACK */
+               *ns_p = PLIP_NB_BEGIN;
+               return OK;
 
-    if (skb->len > dev->mtu) {
-       printk("%s: packet too big, %d.\n", dev->name, (int)skb->len);
-       dev->tbusy = 0;
-       return 0;
-    }
+       case PLIP_NB_2:
+       }
+}
 
-    snd->state = PLIP_PK_TRIGGER;
-    dev->trans_start = jiffies;
+/* PLIP_RECEIVE_PACKET --- receive a packet */
+static int
+plip_receive_packet(struct device *dev, struct net_local *nl,
+                   struct plip_local *snd, struct plip_local *rcv)
+{
+       unsigned short data_addr = PAR_DATA(dev),
+                      status_addr = PAR_STATUS(dev);
+       unsigned short nibble_timeout = nl->nibble, unit = nl->unit;
+       unsigned char *lbuf;
 
-    snd->skb = skb;
-    snd->length = skb->len;
+       switch (rcv->state) {
+       case PLIP_PK_TRIGGER:
+               disable_irq(dev->irq);
+               outb(PAR_INTR_OFF, PAR_CONTROL(dev));
+               dev->interrupt = 0;
+               outb(0x01, PAR_DATA(dev)); /* send ACK */
+               if (net_debug > 2)
+                       printk("%s: receive start\n", dev->name);
+               rcv->state = PLIP_PK_LENGTH_LSB;
+               rcv->nibble = PLIP_NB_BEGIN;
+
+       case PLIP_PK_LENGTH_LSB:
+               if (snd->state != PLIP_PK_DONE) {
+                       if (plip_receive(nl->trigger, unit,
+                                        status_addr, data_addr, &rcv->nibble,
+                                        (unsigned char *)&rcv->length)) {
+                               /* collision, here dev->tbusy == 1 */
+                               rcv->state = PLIP_PK_DONE;
+                               nl->is_deferred = 1;
+                               nl->connection = PLIP_CN_SEND;
+                               queue_task(&nl->deferred, &tq_timer);
+                               outb(PAR_INTR_ON, PAR_CONTROL(dev));
+                               enable_irq(dev->irq);
+                               return OK;
+                       }
+               } else {
+                       if (plip_receive(nibble_timeout, unit,
+                                        status_addr, data_addr, &rcv->nibble,
+                                        (unsigned char *)&rcv->length))
+                               return TIMEOUT;
+               }
+               rcv->state = PLIP_PK_LENGTH_MSB;
+
+       case PLIP_PK_LENGTH_MSB:
+               if (plip_receive(nibble_timeout, unit,
+                                status_addr, data_addr, &rcv->nibble,
+                                (unsigned char *)&rcv->length+1))
+                       return TIMEOUT;
+               if (rcv->length > dev->mtu || rcv->length < 8) {
+                       printk("%s: bogus packet size %d.\n", dev->name, rcv->length);
+                       return ERROR;
+               }
+               /* Malloc up new buffer. */
+               rcv->skb = alloc_skb(rcv->length, GFP_ATOMIC);
+               if (rcv->skb == NULL) {
+                       printk("%s: Memory squeeze.\n", dev->name);
+                       return ERROR;
+               }
+               rcv->skb->len = rcv->length;
+               rcv->skb->dev = dev;
+               rcv->state = PLIP_PK_DATA;
+               rcv->byte = 0;
+               rcv->checksum = 0;
+
+       case PLIP_PK_DATA:
+               lbuf = rcv->skb->data;
+               do {
+                       if (plip_receive(nibble_timeout, unit,
+                                        status_addr, data_addr,
+                                        &rcv->nibble, &lbuf[rcv->byte]))
+                               return TIMEOUT;
+                       rcv->checksum += lbuf[rcv->byte];
+               } while (++rcv->byte < rcv->length);
+               rcv->state = PLIP_PK_CHECKSUM;
+
+       case PLIP_PK_CHECKSUM:
+               if (plip_receive(nibble_timeout, unit, status_addr,
+                                data_addr, &rcv->nibble, &rcv->data))
+                       return TIMEOUT;
+               if (rcv->data != rcv->checksum) {
+                       nl->enet_stats.rx_crc_errors++;
+                       if (net_debug)
+                               printk("%s: checksum error\n", dev->name);
+                       return ERROR;
+               }
+               rcv->state = PLIP_PK_DONE;
 
-    cli();
-    if (nl->connection == PLIP_CN_NONE) {
-       nl->connection = PLIP_CN_SEND;
-       nl->timeout_count = 0;
-    }
-    sti();
-    queue_task(&nl->immediate, &tq_immediate);
-    mark_bh(IMMEDIATE_BH);
+       case PLIP_PK_DONE:
+               /* Inform the upper layer for the arrival of a packet. */
+               netif_rx(rcv->skb);
+               nl->enet_stats.rx_packets++;
+               rcv->skb = NULL;
+               if (net_debug > 2)
+                       printk("%s: receive end\n", dev->name);
 
-    return 0;
+               /* Close the connection. */
+               outb (0x00, PAR_DATA(dev));
+               cli();
+               if (snd->state != PLIP_PK_DONE) {
+                       nl->connection = PLIP_CN_SEND;
+                       sti();
+                       queue_task(&nl->immediate, &tq_immediate);
+                       outb(PAR_INTR_ON, PAR_CONTROL(dev));
+                       enable_irq(dev->irq);
+                       return OK;
+               } else {
+                       nl->connection = PLIP_CN_NONE;
+                       sti();
+                       outb(PAR_INTR_ON, PAR_CONTROL(dev));
+                       enable_irq(dev->irq);
+                       return OK;
+               }
+       }
+       return OK;
 }
 
-/* Open/initialize the board.  This is called (in the current kernel)
-   sometime after booting when the 'ifconfig' program is run.
-
-   This routine gets exclusive access to the parallel port by allocating
-   its IRQ line.
- */
-static int
-plip_open(struct device *dev)
+/* PLIP_SEND --- send a byte (two nibbles) 
+   Returns OK on success, TIMEOUT when timeout    */
+inline static int
+plip_send(unsigned short nibble_timeout, unsigned short unit,
+         unsigned short status_addr, unsigned short data_addr,
+         enum plip_nibble_state *ns_p, unsigned char data)
 {
-    int i;
-
-    cli();
-    if (request_irq(dev->irq , plip_interrupt, 0, "plip") != 0) {
-       sti();
-       printk("%s: couldn't get IRQ %d.\n", dev->name, dev->irq);
-       return -EAGAIN;
-    }
-    irq2dev_map[dev->irq] = dev;
-    sti();
-    /* enable rx interrupt. */
-    outb(LP_PINITP|LP_PSELECP|LP_PINTEN, PAR_CONTROL(dev));
-    plip_device_clear(dev);
-
-    /* Fill in the MAC-level header. */
-    for (i=0; i < ETH_ALEN - sizeof(unsigned long); i++)
-       dev->dev_addr[i] = 0xfc;
-    memcpy(&(dev->dev_addr[i]), &dev->pa_addr, sizeof(unsigned long));
-
-    dev->start = 1;
-#ifdef MODULE
-    MOD_INC_USE_COUNT;
-#endif        
-    return 0;
+       unsigned char c0;
+       unsigned int cx;
+
+       switch (*ns_p) {
+       case PLIP_NB_BEGIN:
+               outb((data & 0x0f), data_addr);
+               *ns_p = PLIP_NB_1;
+
+       case PLIP_NB_1:
+               outb(0x10 | (data & 0x0f), data_addr);
+               cx = nibble_timeout;
+               while (1) {
+                       c0 = inb(status_addr);
+                       if ((c0 & 0x80) == 0) 
+                               break;
+                       if (--cx == 0)
+                               return TIMEOUT;
+                       udelay(unit);
+               }
+               outb(0x10 | (data >> 4), data_addr);
+               *ns_p = PLIP_NB_2;
+
+       case PLIP_NB_2:
+               outb((data >> 4), data_addr);
+               cx = nibble_timeout;
+               while (1) {
+                       c0 = inb(status_addr);
+                       if (c0 & 0x80)
+                               break;
+                       if (--cx == 0)
+                               return TIMEOUT;
+                       udelay(unit);
+               }
+               *ns_p = PLIP_NB_BEGIN;
+               return OK;
+       }
 }
 
-/* The inverse routine to plip_open (). */
+/* PLIP_SEND_PACKET --- send a packet */
 static int
-plip_close(struct device *dev)
+plip_send_packet(struct device *dev, struct net_local *nl,
+                struct plip_local *snd, struct plip_local *rcv)
 {
-    dev->tbusy = 1;
-    dev->start = 0;
-    cli();
-    free_irq(dev->irq);
-    irq2dev_map[dev->irq] = NULL;
-    sti();
-    outb(0x00, PAR_DATA(dev));
-    /* release the interrupt. */
-    outb(LP_PINITP|LP_PSELECP, PAR_CONTROL(dev));
-#ifdef MODULE
-    MOD_DEC_USE_COUNT;
-#endif        
-    return 0;
+       unsigned short data_addr = PAR_DATA(dev),
+                      status_addr = PAR_STATUS(dev);
+       unsigned short nibble_timeout = nl->nibble, unit = nl->unit;
+       unsigned char *lbuf;
+       unsigned char c0;
+       unsigned int cx;
+
+       if (snd->skb == NULL || (lbuf = snd->skb->data) == NULL) {
+               printk("%s: send skb lost\n", dev->name);
+               snd->state = PLIP_PK_DONE;
+               snd->skb = NULL;
+               return ERROR;
+       }
+
+       switch (snd->state) {
+       case PLIP_PK_TRIGGER:
+               /* Trigger remote rx interrupt. */
+               outb(0x08, PAR_DATA(dev));
+               cx = nl->trigger;
+               while (1) {
+                       udelay(nl->unit);
+                       cli();
+                       if (nl->connection == PLIP_CN_RECEIVE) {
+                               sti();
+                               /* interrupted */
+                               nl->enet_stats.collisions++;
+                               if (net_debug > 1)
+                                       printk("%s: collision.\n", dev->name);
+                               return OK;
+                       }
+                       c0 = inb(PAR_STATUS(dev));
+                       if (c0 & 0x08) {
+                               disable_irq(dev->irq);
+                               outb(PAR_INTR_OFF, PAR_CONTROL(dev));
+                               if (net_debug > 2)
+                                       printk("%s: send start\n", dev->name);
+                               snd->state = PLIP_PK_LENGTH_LSB;
+                               snd->nibble = PLIP_NB_BEGIN;
+                               nl->timeout_count = 0;
+                               sti();
+                               break;
+                       }
+                       sti();
+                       if (--cx == 0) {
+                               outb(0x00, PAR_DATA(dev));
+                               return TIMEOUT;
+                       }
+               }
+
+       case PLIP_PK_LENGTH_LSB:
+               if (plip_send(nibble_timeout, unit, status_addr, data_addr,
+                             &snd->nibble, snd->length & 0xff))
+                       return TIMEOUT;
+               snd->state = PLIP_PK_LENGTH_MSB;
+
+       case PLIP_PK_LENGTH_MSB:
+               if (plip_send(nibble_timeout, unit, status_addr, data_addr,
+                             &snd->nibble, snd->length >> 8))
+                       return TIMEOUT;
+               snd->state = PLIP_PK_DATA;
+               snd->byte = 0;
+               snd->checksum = 0;
+
+       case PLIP_PK_DATA:
+               do {
+                       if (plip_send(nibble_timeout, unit,
+                                     status_addr, data_addr,
+                                     &snd->nibble, lbuf[snd->byte]))
+                               return TIMEOUT;
+                       snd->checksum += lbuf[snd->byte];
+               } while (++snd->byte < snd->length);
+               snd->state = PLIP_PK_CHECKSUM;
+
+       case PLIP_PK_CHECKSUM:
+               if (plip_send(nibble_timeout, unit, status_addr, data_addr,
+                             &snd->nibble, snd->checksum))
+                       return TIMEOUT;
+
+               dev_kfree_skb(snd->skb, FREE_WRITE);
+               nl->enet_stats.tx_packets++;
+               snd->state = PLIP_PK_DONE;
+
+       case PLIP_PK_DONE:
+               /* Close the connection */
+               outb (0x00, PAR_DATA(dev));
+               snd->skb = NULL;
+               if (net_debug > 2)
+                       printk("%s: send end\n", dev->name);
+               nl->connection = PLIP_CN_CLOSING;
+               nl->is_deferred = 1;
+               queue_task(&nl->deferred, &tq_timer);
+               outb(PAR_INTR_ON, PAR_CONTROL(dev));
+               enable_irq(dev->irq);
+               return OK;
+       }
+       return OK;
 }
 
-static struct enet_statistics *
-plip_get_stats(struct device *dev)
+static int
+plip_connection_close(struct device *dev, struct net_local *nl,
+                     struct plip_local *snd, struct plip_local *rcv)
 {
-    struct enet_statistics *localstats = (struct enet_statistics*)dev->priv;
-    return localstats;
+       cli();
+       if (nl->connection == PLIP_CN_CLOSING) {
+               nl->connection = PLIP_CN_NONE;
+               dev->tbusy = 0;
+               mark_bh(NET_BH);
+       }
+       sti();
+       return OK;
 }
 
-/* We don't need to send arp, for plip is point-to-point. */
+/* PLIP_ERROR --- wait till other end settled */
 static int
-plip_rebuild_header(void *buff, struct device *dev, unsigned long dst,
-                   struct sk_buff *skb)
+plip_error(struct device *dev, struct net_local *nl,
+          struct plip_local *snd, struct plip_local *rcv)
 {
-    struct ethhdr *eth = (struct ethhdr *)buff;
-    int i;
+       unsigned char status;
 
-    if (eth->h_proto != htons(ETH_P_IP)) {
-       printk("plip_rebuild_header: Don't know how to resolve type %d addresses?\n", (int)eth->h_proto);
-       memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
-       return 0;
-    }
+       status = inb(PAR_STATUS(dev));
+       if ((status & 0xf8) == 0x80) {
+               if (net_debug > 2)
+                       printk("%s: reset interface.\n", dev->name);
+               nl->connection = PLIP_CN_NONE;
+               dev->tbusy = 0;
+               dev->interrupt = 0;
+               outb(PAR_INTR_ON, PAR_CONTROL(dev));
+               enable_irq(dev->irq);
+               mark_bh(NET_BH);
+       } else {
+               nl->is_deferred = 1;
+               queue_task(&nl->deferred, &tq_timer);
+       }
 
-    for (i=0; i < ETH_ALEN - sizeof(unsigned long); i++)
-       eth->h_dest[i] = 0xfc;
-    memcpy(&(eth->h_dest[i]), &dst, sizeof(unsigned long));
-    return 0;
+       return OK;
 }
 \f
+/* Handle the parallel port interrupts. */
 static void
-plip_device_clear(struct device *dev)
+plip_interrupt(int irq, struct pt_regs * regs)
 {
-    struct net_local *nl = (struct net_local *)dev->priv;
-
-    outb (0x00, PAR_DATA(dev));
-    nl->rcv_data.state = PLIP_PK_DONE;
-    nl->snd_data.state = PLIP_PK_DONE;
-    nl->rcv_data.skb = NULL;
-    nl->snd_data.skb = NULL;
-    nl->connection = PLIP_CN_NONE;
-    cli();
-    dev->tbusy = 0;
-    sti();
-    outb(LP_PINITP|LP_PSELECP|LP_PINTEN, PAR_CONTROL(dev));
-    enable_irq(dev->irq);
-}
+       struct device *dev = (struct device *) irq2dev_map[irq];
+       struct net_local *nl = (struct net_local *)dev->priv;
+       struct plip_local *rcv = &nl->rcv_data;
+       unsigned char c0;
 
-/* PLIP_ERROR --- wait till other end settled */
-static int
-plip_error(struct device *dev)
-{
-    unsigned char status;
+       if (dev == NULL) {
+               printk ("plip_interrupt: irq %d for unknown device.\n", irq);
+               return;
+       }
 
-    status = inb(PAR_STATUS(dev));
-    if ((status & 0xf8) == 0x80)
-       return 0;
-    return 1;
+       if (dev->interrupt)
+               return;
+
+       c0 = inb(PAR_STATUS(dev));
+       if ((c0 & 0xf8) != 0xc0) {
+               if (net_debug > 1)
+                       printk("%s: spurious interrupt\n", dev->name);
+               return;
+       }
+       dev->interrupt = 1;
+       if (net_debug > 3)
+               printk("%s: interrupt.\n", dev->name);
+
+       cli();
+       switch (nl->connection) {
+       case PLIP_CN_CLOSING:
+               dev->tbusy = 0;
+       case PLIP_CN_NONE:
+       case PLIP_CN_SEND:
+               dev->last_rx = jiffies;
+               rcv->state = PLIP_PK_TRIGGER;
+               nl->connection = PLIP_CN_RECEIVE;
+               nl->timeout_count = 0;
+               queue_task(&nl->immediate, &tq_immediate);
+               mark_bh(IMMEDIATE_BH);
+               sti();
+               break;
+
+       case PLIP_CN_RECEIVE:
+               sti();
+               printk("%s: receive interrupt when receiving packet\n", dev->name);
+               break;
+
+       case PLIP_CN_ERROR:
+               sti();
+               printk("%s: receive interrupt in error state\n", dev->name);
+               break;
+       }
 }
 \f
-/* PLIP_RECEIVE --- receive a byte(two nibbles)
-   Returns 0 on success, 1 on failure          */
-inline static int
-plip_receive(unsigned short nibble_timeout, unsigned short unit_us,
-            unsigned short status_addr, unsigned short data_addr,
-            enum plip_nibble_state *ns_p, unsigned char *data_p)
+/* We don't need to send arp, for plip is point-to-point. */
+static int
+plip_rebuild_header(void *buff, struct device *dev, unsigned long dst,
+                   struct sk_buff *skb)
 {
-    unsigned char c0, c1;
-    unsigned int cx;
-
-    switch (*ns_p) {
-    case PLIP_NB_BEGIN:
-       cx = nibble_timeout;
-       while (1) {
-           c0 = inb(status_addr);
-           udelay(unit_us);
-           if ((c0 & 0x80) == 0) {
-               c1 = inb(status_addr);
-               if (c0 == c1)
-                   break;
-           }
-           if (--cx == 0)
-               return 1;
-       }
-       *data_p = (c0 >> 3) & 0x0f;
-       outb(0x10, data_addr); /* send ACK */
-       *ns_p = PLIP_NB_1;
-
-    case PLIP_NB_1:
-       cx = nibble_timeout;
-       while (1) {
-           c0 = inb(status_addr);
-           udelay(unit_us);
-           if (c0 & 0x80) {
-               c1 = inb(status_addr);
-               if (c0 == c1)
-                   break;
-           }
-           if (--cx == 0)
-               return 1;
+       struct ethhdr *eth = (struct ethhdr *)buff;
+       int i;
+
+       if (eth->h_proto != htons(ETH_P_IP)) {
+               printk("plip_rebuild_header: Don't know how to resolve type %d addresses?\n", (int)eth->h_proto);
+               memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
+               return 0;
        }
-       *data_p |= (c0 << 1) & 0xf0;
-       outb(0x00, data_addr); /* send ACK */
-       *ns_p = PLIP_NB_BEGIN;
-       return 0;
 
-    case PLIP_NB_2:
-    }
+       for (i=0; i < ETH_ALEN - sizeof(unsigned long); i++)
+               eth->h_dest[i] = 0xfc;
+       memcpy(&(eth->h_dest[i]), &dst, sizeof(unsigned long));
+       return 0;
 }
 
-/* PLIP_RECEIVE_PACKET --- receive a packet
-   Returns 0 on success, 1 when timeout, -1 on failure */
 static int
-plip_receive_packet(struct device *dev)
+plip_tx_packet(struct sk_buff *skb, struct device *dev)
 {
-    unsigned short data_addr = PAR_DATA(dev), status_addr = PAR_STATUS(dev);
-    struct net_local *nl = (struct net_local *)dev->priv;
-    unsigned short nibble_timeout = nl->nibble_us, unit_us = nl->unit_us;
-    struct plip_local *rcv = &nl->rcv_data;
-    unsigned char *lbuf;
-    struct enet_statistics *stats = (struct enet_statistics *) dev->priv;
-
-    switch (rcv->state) {
-    case PLIP_PK_TRIGGER:
-       rcv->state = PLIP_PK_LENGTH_LSB;
-       rcv->nibble = PLIP_NB_BEGIN;
-
-    case PLIP_PK_LENGTH_LSB:
-       if (plip_receive(nibble_timeout, unit_us, status_addr, data_addr,
-                        &rcv->nibble, (unsigned char *)&rcv->length))
-           return 1;
-       rcv->state = PLIP_PK_LENGTH_MSB;
-
-    case PLIP_PK_LENGTH_MSB:
-       if (plip_receive(nibble_timeout, unit_us, status_addr, data_addr,
-                        &rcv->nibble, (unsigned char *)&rcv->length+1))
-           return 1;
-       if (rcv->length > dev->mtu || rcv->length < 8) {
-           printk("%s: bogus packet size %d.\n", dev->name, rcv->length);
-           return -1;
-       }
-       /* Malloc up new buffer. */
-       rcv->skb = alloc_skb(rcv->length, GFP_ATOMIC);
-       if (rcv->skb == NULL) {
-           printk("%s: Memory squeeze.\n", dev->name);
-           return -1;
+       struct net_local *nl = (struct net_local *)dev->priv;
+       struct plip_local *snd = &nl->snd_data;
+
+       if (dev->tbusy)
+               return 1;
+
+       /* If some higher layer thinks we've missed an tx-done interrupt
+          we are passed NULL. Caution: dev_tint() handles the cli()/sti()
+          itself. */
+       if (skb == NULL) {
+               dev_tint(dev);
+               return 0;
        }
-       rcv->skb->len = rcv->length;
-       rcv->skb->dev = dev;
-       rcv->state = PLIP_PK_DATA;
-       rcv->byte = 0;
-       rcv->checksum = 0;
-
-    case PLIP_PK_DATA:
-       lbuf = rcv->skb->data;
-       do {
-           if (plip_receive(nibble_timeout, unit_us, status_addr, data_addr,
-                            &rcv->nibble, &lbuf[rcv->byte]))
+
+       if (set_bit(0, (void*)&dev->tbusy) != 0) {
+               printk("%s: Transmitter access conflict.\n", dev->name);
                return 1;
-           rcv->checksum += lbuf[rcv->byte];
-       } while (++rcv->byte < rcv->length);
-       rcv->state = PLIP_PK_CHECKSUM;
-
-    case PLIP_PK_CHECKSUM:
-       if (plip_receive(nibble_timeout, unit_us, status_addr, data_addr,
-                        &rcv->nibble, &rcv->data))
-           return 1;
-       if (rcv->data != rcv->checksum) {
-           stats->rx_crc_errors++;
-           if (net_debug)
-               printk("%s: checksum error\n", dev->name);
-           return -1;
        }
-       rcv->state = PLIP_PK_DONE;
 
-    case PLIP_PK_DONE:
-    }
-    return 0;
-}
+       if (skb->len > dev->mtu) {
+               printk("%s: packet too big, %d.\n", dev->name, (int)skb->len);
+               dev->tbusy = 0;
+               return 0;
+       }
 
-/* Handle the parallel port interrupts. */
-static void
-plip_interrupt(int irq, struct pt_regs * regs)
-{
-    struct device *dev = (struct device *) irq2dev_map[irq];
-    struct net_local *nl = (struct net_local *)dev->priv;
-    struct plip_local *rcv = &nl->rcv_data;
-    unsigned char c0;
-
-    if (dev == NULL) {
-       if (net_debug)
-           printk ("plip_interrupt: irq %d for unknown device.\n", irq);
-       return;
-    }
-
-    if (dev->interrupt)
-       return;
-
-    c0 = inb(PAR_STATUS(dev));
-    if ((c0 & 0xf8) != 0xc0) {
-       if (net_debug > 3)
-           printk("plip: spurious interrupt\n");
-       return;
-    }
-    dev->interrupt = 1;
-    if (net_debug > 3)
-       printk("%s: interrupt.\n", dev->name);
-
-    cli();
-    switch (nl->connection) {
-    case PLIP_CN_CLOSING:
-       dev->tbusy = 0;
-    case PLIP_CN_NONE:
-    case PLIP_CN_SEND:
-       sti();
-       dev->last_rx = jiffies;
-       rcv->state = PLIP_PK_TRIGGER;
-       nl->connection = PLIP_CN_RECEIVE;
-       nl->timeout_count = 0;
+       if (net_debug > 2)
+               printk("%s: send request\n", dev->name);
+
+       cli();
+       dev->trans_start = jiffies;
+       snd->skb = skb;
+       snd->length = skb->len;
+       snd->state = PLIP_PK_TRIGGER;
+       if (nl->connection == PLIP_CN_NONE) {
+               nl->connection = PLIP_CN_SEND;
+               nl->timeout_count = 0;
+       }
        queue_task(&nl->immediate, &tq_immediate);
        mark_bh(IMMEDIATE_BH);
-       break;
-
-    case PLIP_CN_RECEIVE:
        sti();
-       printk("%s: receive interrupt when receiving packet\n", dev->name);
-       break;
 
-    case PLIP_CN_ERROR:
-       sti();
-       printk("%s: receive interrupt in error state\n", dev->name);
-       break;
-    }
+       return 0;
 }
-\f
-/* PLIP_SEND --- send a byte (two nibbles) 
-   Returns 0 on success, 1 on failure        */
-inline static int
-plip_send(unsigned short nibble_timeout, unsigned short unit_us,
-         unsigned short status_addr, unsigned short data_addr,
-         enum plip_nibble_state *ns_p, unsigned char data)
+
+/* Open/initialize the board.  This is called (in the current kernel)
+   sometime after booting when the 'ifconfig' program is run.
+
+   This routine gets exclusive access to the parallel port by allocating
+   its IRQ line.
+ */
+static int
+plip_open(struct device *dev)
 {
-    unsigned char c0;
-    unsigned int cx;
-
-    switch (*ns_p) {
-    case PLIP_NB_BEGIN:
-       outb((data & 0x0f), data_addr);
-       *ns_p = PLIP_NB_1;
-
-    case PLIP_NB_1:
-       outb(0x10 | (data & 0x0f), data_addr);
-       cx = nibble_timeout;
-       while (1) {
-           c0 = inb(status_addr);
-           if ((c0 & 0x80) == 0) 
-               break;
-           if (--cx == 0) /* time out */
-               return 1;
-           udelay(unit_us);
+       struct net_local *nl = (struct net_local *)dev->priv;
+       int i;
+
+       if (dev->irq == 0) {
+               printk("%s: IRQ is not set.  Please set it by ifconfig.\n", dev->name);
+               return -EAGAIN;
        }
-       outb(0x10 | (data >> 4), data_addr);
-       *ns_p = PLIP_NB_2;
-
-    case PLIP_NB_2:
-       outb((data >> 4), data_addr);
-       cx = nibble_timeout;
-       while (1) {
-           c0 = inb(status_addr);
-           if (c0 & 0x80)
-               break;
-           if (--cx == 0) /* time out */
-               return 1;
-           udelay(unit_us);
+       cli();
+       if (request_irq(dev->irq , plip_interrupt, 0, dev->name) != 0) {
+               sti();
+               printk("%s: couldn't get IRQ %d.\n", dev->name, dev->irq);
+               return -EAGAIN;
        }
-       *ns_p = PLIP_NB_BEGIN;
+       irq2dev_map[dev->irq] = dev;
+       sti();
+
+       /* Clear the data port. */
+       outb (0x00, PAR_DATA(dev));
+
+       /* Enable rx interrupt. */
+       outb(PAR_INTR_ON, PAR_CONTROL(dev));
+
+       /* Initialize the state machine. */
+       nl->rcv_data.state = nl->snd_data.state = PLIP_PK_DONE;
+       nl->rcv_data.skb = nl->snd_data.skb = NULL;
+       nl->connection = PLIP_CN_NONE;
+       nl->is_deferred = 0;
+
+       /* Fill in the MAC-level header. */
+       for (i=0; i < ETH_ALEN - sizeof(unsigned long); i++)
+               dev->dev_addr[i] = 0xfc;
+       memcpy(&(dev->dev_addr[i]), &dev->pa_addr, sizeof(unsigned long));
+
+       dev->interrupt = 0;
+       dev->start = 1;
+       dev->tbusy = 0;
+       MOD_INC_USE_COUNT;
        return 0;
-    }
 }
 
-/* PLIP_SEND_PACKET --- send a packet
-   Returns 0 on success, 1 when timeout, -1 when interrupted  */
+/* The inverse routine to plip_open (). */
 static int
-plip_send_packet(struct device *dev)
+plip_close(struct device *dev)
 {
-    unsigned short data_addr = PAR_DATA(dev), status_addr = PAR_STATUS(dev);
-    struct net_local *nl = (struct net_local *)dev->priv;
-    unsigned short nibble_timeout = nl->nibble_us, unit_us = nl->unit_us;
-    struct plip_local *snd = &nl->snd_data;
-    unsigned char *lbuf = snd->skb->data;
-    unsigned char c0;
-    unsigned int cx;
-    struct enet_statistics *stats = (struct enet_statistics *) dev->priv;
-
-    switch (snd->state) {
-    case PLIP_PK_TRIGGER:
-       /* Trigger remote rx interrupt. */
-       outb(0x08, PAR_DATA(dev));
-       cx = nl->trigger_us;
-       while (1) {
-           if (nl->connection == PLIP_CN_RECEIVE) { /* interrupted */
-               stats->collisions++;
-               if (net_debug > 3)
-                   printk("%s: collision.\n", dev->name);
-               return -1;
-           }
-           cli();
-           c0 = inb(PAR_STATUS(dev));
-           if (c0 & 0x08) {
-               disable_irq(dev->irq);
-               outb(LP_PINITP|LP_PSELECP, PAR_CONTROL(dev));
-               if (net_debug > 3)
-                   printk("+");
-               /* OK, connection established! */
-               snd->state = PLIP_PK_LENGTH_LSB;
-               snd->nibble = PLIP_NB_BEGIN;
-               nl->timeout_count = 0;
-               sti();
-               break;
-           }
-           sti();
-           udelay(nl->unit_us);
-           if (--cx == 0) {
-               outb(0x00, PAR_DATA(dev));
-               return 1;
-           }
-       }
+       struct net_local *nl = (struct net_local *)dev->priv;
+       struct plip_local *snd = &nl->snd_data;
+       struct plip_local *rcv = &nl->rcv_data;
 
-    case PLIP_PK_LENGTH_LSB:
-       if (plip_send(nibble_timeout, unit_us, status_addr, data_addr,
-                     &snd->nibble, snd->length & 0xff)) /* timeout */
-           return 1;
-       snd->state = PLIP_PK_LENGTH_MSB;
-
-    case PLIP_PK_LENGTH_MSB:
-       if (plip_send(nibble_timeout, unit_us, status_addr, data_addr,
-                     &snd->nibble, snd->length >> 8)) /* timeout */
-           return 1;
-       snd->state = PLIP_PK_DATA;
-       snd->byte = 0;
-       snd->checksum = 0;
-
-    case PLIP_PK_DATA:
-       do {
-           if (plip_send(nibble_timeout, unit_us, status_addr, data_addr,
-                         &snd->nibble, lbuf[snd->byte])) /* timeout */
-               return 1;
-           snd->checksum += lbuf[snd->byte];
-       } while (++snd->byte < snd->length);
-       snd->state = PLIP_PK_CHECKSUM;
+       dev->tbusy = 1;
+       dev->start = 0;
+       cli();
+       free_irq(dev->irq);
+       irq2dev_map[dev->irq] = NULL;
+       nl->is_deferred = 0;
+       nl->connection = PLIP_CN_NONE;
+       sti();
+       outb(0x00, PAR_DATA(dev));
+
+       snd->state = PLIP_PK_DONE;
+       if (snd->skb) {
+               dev_kfree_skb(snd->skb, FREE_WRITE);
+               snd->skb = NULL;
+       }
+       rcv->state = PLIP_PK_DONE;
+       if (rcv->skb) {
+               rcv->skb->free = 1;
+               kfree_skb(rcv->skb, FREE_READ);
+               rcv->skb = NULL;
+       }
 
-    case PLIP_PK_CHECKSUM:
-       if (plip_send(nibble_timeout, unit_us, status_addr, data_addr,
-                     &snd->nibble, snd->checksum)) /* timeout */
-           return 1;
+       /* Reset. */
+       outb(0x00, PAR_CONTROL(dev));
+       MOD_DEC_USE_COUNT;
+       return 0;
+}
 
-       dev_kfree_skb(snd->skb, FREE_WRITE);
-       stats->tx_packets++;
+static struct enet_statistics *
+plip_get_stats(struct device *dev)
+{
+       struct net_local *nl = (struct net_local *)dev->priv;
+       struct enet_statistics *r = &nl->enet_stats;
 
-    case PLIP_PK_DONE:
-    }
-    return 0;
+       return r;
 }
-\f
-static int plip_config(struct device *dev, struct ifmap *map)
+
+static int
+plip_config(struct device *dev, struct ifmap *map)
 {
-       if(dev->flags&IFF_UP)
+       if (dev->flags & IFF_UP)
                return -EBUSY;
-/*
- *     We could probe this for verification, but since they told us
- *     to do it then they can suffer.
- */
-       if(map->base_addr!= (unsigned short)-1)
-               dev->base_addr=map->base_addr;
-       if(map->irq!= (unsigned char)-1)
-               dev->irq= map->irq;
+
+       if (map->base_addr != (unsigned long)-1
+           && map->base_addr != dev->base_addr)
+               printk("%s: You cannot change base_addr of this interface (ignored).\n", dev->name);
+
+       if (map->irq != (unsigned char)-1)
+               dev->irq = map->irq;
        return 0;
 }
 
-static int plip_ioctl(struct device *dev, struct ifreq *rq, int cmd)
+static int
+plip_ioctl(struct device *dev, struct ifreq *rq, int cmd)
 {
        struct net_local *nl = (struct net_local *) dev->priv;
        struct plipconf *pc = (struct plipconf *) &rq->ifr_data;
        
-       switch(pc->pcmd)
-       {
-               case PLIP_GET_TIMEOUT:
-                       pc->trigger=nl->trigger_us;
-                       pc->nibble=nl->nibble_us;
-                       pc->unit=nl->unit_us;
-                       break;
-               case PLIP_SET_TIMEOUT:
-                       nl->trigger_us=pc->trigger;
-                       nl->nibble_us=pc->nibble;
-                       nl->unit_us=pc->unit;
-                       break;
-               default:
-                       return -EOPNOTSUPP;
+       switch(pc->pcmd) {
+       case PLIP_GET_TIMEOUT:
+               pc->trigger = nl->trigger;
+               pc->nibble  = nl->nibble;
+               pc->unit    = nl->unit;
+               break;
+       case PLIP_SET_TIMEOUT:
+               nl->trigger = pc->trigger;
+               nl->nibble  = pc->nibble;
+               nl->unit    = pc->unit;
+               break;
+       default:
+               return -EOPNOTSUPP;
        }
        return 0;
 }
-
 \f
 #ifdef MODULE
 char kernel_version[] = UTS_RELEASE;
@@ -939,56 +1040,45 @@ static struct device dev_plip2 =
 int
 init_module(void)
 {
-    int devices=0;
-
-    if (register_netdev(&dev_plip0) != 0)
-       devices++;
-    if (register_netdev(&dev_plip1) != 0)
-       devices++;
-    if (register_netdev(&dev_plip2) != 0)
-       devices++;
-    if (devices == 0)
-       return -EIO;
-    return 0;
+       int devices=0;
+
+       if (register_netdev(&dev_plip0) != 0)
+               devices++;
+       if (register_netdev(&dev_plip1) != 0)
+               devices++;
+       if (register_netdev(&dev_plip2) != 0)
+               devices++;
+       if (devices == 0)
+               return -EIO;
+       return 0;
 }
 
 void
 cleanup_module(void)
 {
-    if (MOD_IN_USE)
-       printk("plip: device busy, remove delayed\n");
-    else {
        if (dev_plip0.priv) {
-           unregister_netdev(&dev_plip0);
-           release_region(PAR_DATA(&dev_plip0), 3);
-           kfree_s(dev_plip0.priv, sizeof(struct net_local));
-           dev_plip0.priv = NULL;
+               unregister_netdev(&dev_plip0);
+               release_region(PAR_DATA(&dev_plip0), 3);
+               kfree_s(dev_plip0.priv, sizeof(struct net_local));
+               dev_plip0.priv = NULL;
        }
        if (dev_plip1.priv) {
-           unregister_netdev(&dev_plip1);
-           release_region(PAR_DATA(&dev_plip1), 3);
-           kfree_s(dev_plip1.priv, sizeof(struct net_local));
-           dev_plip1.priv = NULL;
+               unregister_netdev(&dev_plip1);
+               release_region(PAR_DATA(&dev_plip1), 3);
+               kfree_s(dev_plip1.priv, sizeof(struct net_local));
+               dev_plip1.priv = NULL;
        }
        if (dev_plip2.priv) {
-           unregister_netdev(&dev_plip2);
-           release_region(PAR_DATA(&dev_plip2), 3);
-           kfree_s(dev_plip2.priv, sizeof(struct net_local));
-           dev_plip2.priv = NULL;
+               unregister_netdev(&dev_plip2);
+               release_region(PAR_DATA(&dev_plip2), 3);
+               kfree_s(dev_plip2.priv, sizeof(struct net_local));
+               dev_plip2.priv = NULL;
        }
-    }
 }
 #endif /* MODULE */
 \f
 /*
  * Local variables:
- * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -m486 -I../../net/inet -c plip.c"
- * c-indent-level: 4
- * c-continued-statement-offset: 4
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * version-control: t
- * kept-new-versions: 10
+ * compile-command: "gcc -DMODULE -DCONFIG_MODVERSIONS -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -g -fomit-frame-pointer -pipe -m486 -c plip.c"
  * End:
  */
index d33f396e80e9472381966d04ee136f3dc025da3e..61ea3f91ea9277ddefae637d4a8ffdcb74711c23 100644 (file)
@@ -1,6 +1,10 @@
 /*
  *      eata.c - Low-level driver for EATA/DMA SCSI host adapters.
  *
+ *       8 Feb 1995 rev. 1.15 for linux 1.1.89
+ *          Cleared target_time_out counter while preforming a reset.
+ *          All external symbols renamed to avoid possible name conflicts.
+ *
  *      28 Jan 1995 rev. 1.14 for linux 1.1.86
  *          Added module support.
  *          Log and do a retry when a disk drive returns a target status 
@@ -41,7 +45,7 @@
  *          This driver is based on the CAM (Common Access Method Committee)
  *          EATA (Enhanced AT Bus Attachment) rev. 2.0A, using DMA protocol.
  *
- *      Released by Dario Ballabio (Dario_Ballabio@milano.europe.dg.com)
+ *      Copyright (C) 1994, 1995 Dario Ballabio (dario@milano.europe.dg.com)
  *
  */
 
@@ -89,6 +93,7 @@
 
 #if defined(MODULE)
 #include <linux/module.h>
+#include <linux/version.h>
 #endif
 
 #include <linux/string.h>
@@ -288,7 +293,7 @@ static unsigned int irqlist[MAX_IRQ], calls[MAX_IRQ];
 #define HD(board) ((struct hostdata *) &sh[board]->hostdata)
 #define BN(board) (HD(board)->board_name)
 
-static void eata_interrupt_handler(int, struct pt_regs *);
+static void eata2x_interrupt_handler(int, struct pt_regs *);
 static int do_trace = FALSE;
 
 static inline unchar wait_on_busy(ushort iobase) {
@@ -411,7 +416,7 @@ static inline int port_detect(ushort *port_base, unsigned int j,
 
    /* Board detected, allocate its IRQ if not already done */
    if ((irq >= MAX_IRQ) || ((irqlist[irq] == NO_IRQ) && request_irq
-       (irq, eata_interrupt_handler, SA_INTERRUPT, driver_name))) {
+       (irq, eata2x_interrupt_handler, SA_INTERRUPT, driver_name))) {
       printk("%s: unable to allocate IRQ %u, detaching.\n", name, irq);
       return FALSE;
       }
@@ -461,12 +466,7 @@ static inline int port_detect(ushort *port_base, unsigned int j,
    if (HD(j)->subversion == ESA)
       sh[j]->unchecked_isa_dma = FALSE;
    else {
-
-#if !defined(MODULE)
-      /* The module code does not checkin/checkout in the blocking list yet */
       sh[j]->block = sh[j];
-#endif
-
       sh[j]->unchecked_isa_dma = TRUE;
       disable_dma(dma_channel);
       clear_dma_ff(dma_channel);
@@ -507,7 +507,7 @@ static inline int port_detect(ushort *port_base, unsigned int j,
    return TRUE;
 }
 
-int eata_detect (Scsi_Host_Template * tpnt) {
+int eata2x_detect (Scsi_Host_Template * tpnt) {
    unsigned int j = 0, k, flags;
 
    ushort io_port[] = { 
@@ -535,6 +535,9 @@ int eata_detect (Scsi_Host_Template * tpnt) {
       port_base++;
       }
 
+   if (j > 0) 
+      printk("EATA/DMA 2.0x: Copyright (C) 1994, 1995 Dario Ballabio.\n");
+
    restore_flags(flags);
    return j;
 }
@@ -554,7 +557,7 @@ static inline void build_sg_list(struct mscp *cpp, Scsi_Cmnd *SCpnt) {
    cpp->data_len = htonl((SCpnt->use_sg * sizeof(struct sg_list)));
 }
 
-int eata_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
+int eata2x_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
    unsigned int i, j, k, flags;
    struct mscp *cpp;
    struct mssp *spp;
@@ -585,7 +588,7 @@ int eata_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
 
       if (HD(j)->in_reset) 
          printk("%s: qcomm, already in reset.\n", BN(j));
-      else if (eata_reset(SCpnt) == SCSI_RESET_SUCCESS) 
+      else if (eata2x_reset(SCpnt) == SCSI_RESET_SUCCESS) 
          panic("%s: qcomm, SCSI_RESET_SUCCESS.\n", BN(j));
 
       SCpnt->result = DID_BUS_BUSY << 16; 
@@ -657,7 +660,7 @@ int eata_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
    return 0;
 }
 
-int eata_abort (Scsi_Cmnd *SCarg) {
+int eata2x_abort (Scsi_Cmnd *SCarg) {
    unsigned int i, j, flags;
 
    save_flags(flags);
@@ -715,7 +718,7 @@ int eata_abort (Scsi_Cmnd *SCarg) {
       panic("%s: abort, mbox %d, invalid cp_stat.\n", BN(j), i);
 }
 
-int eata_reset (Scsi_Cmnd *SCarg) {
+int eata2x_reset (Scsi_Cmnd *SCarg) {
    unsigned int i, j, flags, time, k, limit = 0;
    int arg_done = FALSE;
    Scsi_Cmnd *SCpnt;
@@ -743,6 +746,8 @@ int eata_reset (Scsi_Cmnd *SCarg) {
 
    for (k = 0; k < MAX_TARGET; k++) HD(j)->target_reset[k] = TRUE;
 
+   for (k = 0; k < MAX_TARGET; k++) HD(j)->target_time_out[k] = 0;
+
    for (i = 0; i < sh[j]->can_queue; i++) {
 
       if (HD(j)->cp_stat[i] == FREE) continue;
@@ -784,7 +789,7 @@ int eata_reset (Scsi_Cmnd *SCarg) {
    HD(j)->in_reset = TRUE;
    sti();
    time = jiffies;
-   while (jiffies < (time + 200) && limit++ < 100000000) sti();
+   while (jiffies < (time + 100) && limit++ < 100000000);
    cli();
    printk("%s: reset, interrupts disabled, loops %d.\n", BN(j), limit);
 
@@ -821,7 +826,7 @@ int eata_reset (Scsi_Cmnd *SCarg) {
       }
 }
 
-static void eata_interrupt_handler(int irq, struct pt_regs * regs) {
+static void eata2x_interrupt_handler(int irq, struct pt_regs * regs) {
    Scsi_Cmnd *SCpnt;
    unsigned int i, j, k, flags, status, tstatus, loops, total_loops = 0;
    struct mssp *spp;
@@ -928,8 +933,7 @@ static void eata_interrupt_handler(int irq, struct pt_regs * regs) {
                      status = DID_BUS_BUSY << 16;
 
                   else if (tstatus == CHECK_CONDITION
-                           && (SCpnt->device->type == TYPE_DISK
-                            || SCpnt->device->type == TYPE_ROM)
+                           && SCpnt->device->type == TYPE_DISK
                            && (SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION)
                      status = DID_ERROR << 16;
    
@@ -939,8 +943,7 @@ static void eata_interrupt_handler(int irq, struct pt_regs * regs) {
                   if (tstatus == GOOD)
                      HD(j)->target_reset[SCpnt->target] = FALSE;
    
-                  if (spp->target_status && (SCpnt->device->type == TYPE_DISK
-                                          || SCpnt->device->type == TYPE_ROM))
+                  if (spp->target_status && SCpnt->device->type == TYPE_DISK)
                      printk("%s: ihdlr, target %d:%d, pid %ld, target_status "\
                             "0x%x, sense key 0x%x.\n", BN(j), 
                             SCpnt->target, SCpnt->lun, SCpnt->pid,
index 518e9f2c68067bfc6f1f1ab0bf70a1f8552e0613..02ebc7809219fbe934bf60e96f09658e04d04424 100644 (file)
@@ -7,24 +7,24 @@
 
 #include <linux/scsicam.h>
 
-#define EATA_VERSION "1.14.03"
+#define EATA_VERSION "1.15.00"
 
-int eata_detect(Scsi_Host_Template *);
-int eata_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int eata_abort(Scsi_Cmnd *);
-int eata_reset(Scsi_Cmnd *);
+int eata2x_detect(Scsi_Host_Template *);
+int eata2x_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int eata2x_abort(Scsi_Cmnd *);
+int eata2x_reset(Scsi_Cmnd *);
 
-#define EATA {  NULL, /* Ptr for modules */                    \
+#define EATA {                                                 \
+                NULL, /* Ptr for modules */                    \
                 NULL, /* usage count for modules */           \
-                "EATA/DMA 2.0 rev. " EATA_VERSION " by "       \
-                "Dario_Ballabio@milano.europe.dg.com.",        \
-                eata_detect,                                  \
+                "EATA/DMA 2.0x rev. " EATA_VERSION " ",        \
+                eata2x_detect,                                \
                 NULL, /* Release */                           \
                NULL,                                          \
                NULL,                                          \
-               eata_queuecommand,                             \
-               eata_abort,                                    \
-               eata_reset,                                    \
+               eata2x_queuecommand,                           \
+               eata2x_abort,                                  \
+               eata2x_reset,                                  \
                NULL,                                          \
                scsicam_bios_param,                            \
                0,   /* can_queue, reset by detect */          \
index 367672cc7aca3f1ed6913968b8ba9f53b14511a9..dd746620523ea02bc901a854c66c83ab31e7177a 100644 (file)
@@ -137,7 +137,7 @@ int eata_release(struct Scsi_Host *);
 #define C_P_L_DIV          4  /* 1 <= C_P_L_DIV <= 8            
                               * You can use this parameter to fine-tune
                               * the driver. Depending on the number of 
-                              * devices and their ablilty to queue commands
+                              * devices and their ability to queue commands
                               * you will get the best results with a value
                               * ~= numdevices-(devices_unable_to_queue_commands/2)
                               * The reason for this is that the disk driver tents 
index 93b470894f973e0e7db866e3d9f159cc97061b50..da1b7c57f8e3c7a7f2c26496f3c71c9c4cb60d81 100644 (file)
@@ -221,7 +221,7 @@ scsi_unregister(struct Scsi_Host * sh){
        j = sh->extra_bytes;
 
        if(scsi_hostlist == sh)
-               scsi_hostlist = NULL;
+               scsi_hostlist = sh->next;
        else {
                shpnt = scsi_hostlist;
                while(shpnt->next != sh) shpnt = shpnt->next;
@@ -244,7 +244,8 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j){
        if(j > 0xffff) panic("Too many extra bytes requested\n");
        retval->extra_bytes = j;
        retval->loaded_as_module = scsi_loadable_module_flag;
-       retval->host_no = next_scsi_host++;
+       retval->host_no = max_scsi_hosts++; /* never reuse host_no (DB) */
+       next_scsi_host++;
        retval->host_queue = NULL;
        retval->host_wait = NULL;
        retval->last_reset = 0;
@@ -339,29 +340,7 @@ unsigned int scsi_init()
        printk ("scsi : %d host%s.\n", next_scsi_host,
                (next_scsi_host == 1) ? "" : "s");
 
-      {
-      int block_count = 0, index;
-      struct Scsi_Host * sh[128], * shpnt;
-
-         for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
-            if (shpnt->block) sh[block_count++] = shpnt;
-      
-         if (block_count == 1) sh[0]->block = NULL;
-
-         else if (block_count > 1) {
-
-            for(index = 0; index < block_count - 1; index++) {
-               sh[index]->block = sh[index + 1];
-               printk("scsi%d : added to blocked host list.\n", 
-                      sh[index]->host_no);
-               }
-           
-            sh[block_count - 1]->block = sh[0];
-            printk("scsi%d : added to blocked host list.\n", 
-                   sh[index]->host_no);
-            }
-
-      }
+       scsi_make_blocked_list();
 
        /* Now attach the high level drivers */
 #ifdef CONFIG_BLK_DEV_SD
@@ -377,7 +356,9 @@ unsigned int scsi_init()
        scsi_register_device(&sg_template);
 #endif
 
+#if 0      
        max_scsi_hosts = next_scsi_host;
+#endif
        return 0;
 }
 
index 37c120a555e8b04baf727fb412f5d8acd8468afe..f1e739d98d57e0880e4a1a3739d69a9380d50090 100644 (file)
@@ -280,11 +280,11 @@ sub parse_conditional {
        $conditional = $1;
        print STDERR "$0 : parsed ATN\n" if ($debug);
     } elsif ($conditional =~ /^($phase)\s*(.*)/i) {
-       $1 = "\U$1\E";
-       $p = $scsi_phases{$1};
+       $phase_index = "\U$1\E";
+       $p = $scsi_phases{$phase_index};
        $code[$address] |= $p | 0x00_02_00_00;
        $conditional = $2;
-       print STDERR "$0 : parsed phase $1\n" if ($debug);
+       print STDERR "$0 : parsed phase $phase_index\n" if ($debug);
     } else {
        $other = '';
        $need_data = 1;
@@ -378,16 +378,17 @@ while (<STDIN>) {
        $rest = $2;
        foreach $rest (split (/\s*,\s*/, $rest)) {
            if ($rest =~ /^($identifier)\s*=\s*($constant)\s*$/) {
-               if ($symbol_values{$1} eq undef) {
-                   $symbol_values{$1} = eval $2;
-                   delete $forward{$1};
+               local ($id, $cnst) = ($1, $2);
+               if ($symbol_values{$id} eq undef) {
+                   $symbol_values{$id} = eval $cnst;
+                   delete $forward{$id};
                    if ($is_absolute =~ /ABSOLUTE/i) {
-                       push (@absolute , $1);
+                       push (@absolute , $id);
                    } else {
-                       push (@relative, $1);
+                       push (@relative, $id);
                    }
                } else {
-                   die "$0 : redefinition of symbol $1 in line $lineno : $_\n";
+                   die "$0 : redefinition of symbol $id in line $lineno : $_\n";
                }
            } else {
                die 
index c1cdfd0b4227b7877c1af7c6d2613dbd164a07d6..bfd3c170f233c5ae711fe7dbc9b7df6aaa035ced 100644 (file)
@@ -1,18 +1,18 @@
 /*
- *     scsi.c Copyright (C) 1992 Drew Eckhardt 
+ *     scsi.c Copyright (C) 1992 Drew Eckhardt
  *            Copyright (C) 1993, 1994, 1995 Eric Youngdale
  *
  *     generic mid-level SCSI driver
- *             Initial versions: Drew Eckhardt 
+ *             Initial versions: Drew Eckhardt
  *             Subsequent revisions: Eric Youngdale
  *
  *     <drew@colorado.edu>
  *
- *     Bug correction thanks go to : 
+ *     Bug correction thanks go to :
  *             Rik Faith <faith@cs.unc.edu>
  *             Tommy Thorn <tthorn>
  *             Thomas Wuensche <tw@fgb1.fgb.mw.tu-muenchen.de>
- * 
+ *
  *       Modified by Eric Youngdale ericy@cais.com to
  *       add scatter-gather, multiple outstanding request, and other
  *       enhancements.
@@ -48,10 +48,9 @@ static void scsi_times_out (Scsi_Cmnd * SCpnt, int pid);
 
 static int time_start;
 static int time_elapsed;
-static int scsi_maybe_deadlocked = 0;
-static int max_active = 0;
-static struct Scsi_Host * host_active = NULL;
-static struct Scsi_Host * host_next = NULL;
+static volatile struct Scsi_Host * host_active = NULL;
+#define SCSI_BLOCK(HOST) ((HOST->block && host_active && HOST != host_active) \
+                  || (HOST->can_queue && HOST->host_busy >= HOST->can_queue))
 
 #define MAX_SCSI_DEVICE_CODE 10
 const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] =
@@ -70,8 +69,8 @@ const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] =
 
 
 /*
-       global variables : 
-       scsi_devices an array of these specifying the address for each 
+       global variables :
+       scsi_devices an array of these specifying the address for each
        (host, id, LUN)
 */
 
@@ -86,21 +85,21 @@ static unsigned char generic_sense[6] = {REQUEST_SENSE, 0,0,0, 255, 0};
 Scsi_Cmnd * last_cmnd = NULL;
 
 /*
- *     As the scsi do command functions are intelligent, and may need to 
- *     redo a command, we need to keep track of the last command 
+ *     As the scsi do command functions are intelligent, and may need to
+ *     redo a command, we need to keep track of the last command
  *     executed on each one.
  */
 
-#define WAS_RESET      0x01
-#define WAS_TIMEDOUT   0x02
+#define WAS_RESET      0x01
+#define WAS_TIMEDOUT   0x02
 #define WAS_SENSE      0x04
 #define IS_RESETTING   0x08
 #define IS_ABORTING    0x10
 #define ASKED_FOR_SENSE 0x20
 
 /*
- *     This is the number  of clock ticks we should wait before we time out 
- *     and abort the command.  This is for  where the scsi.c module generates 
+ *     This is the number  of clock ticks we should wait before we time out
+ *     and abort the command.  This is for  where the scsi.c module generates
  *     the command, not where it originates from a higher level, in which
  *     case the timeout is specified there.
  *
@@ -127,9 +126,13 @@ static void scsi_dump_status(void);
        #define SENSE_TIMEOUT 50
        #define RESET_TIMEOUT 50
        #define ABORT_TIMEOUT 50
-       #define MIN_RESET_DELAY 100
 #endif
 
+#define MIN_RESET_DELAY 100
+
+/* Do not call reset on error if we just did a reset within 10 sec. */
+#define MIN_RESET_PERIOD 1000
+
 /* The following devices are known not to tolerate a lun != 0 scan for
    one reason or another.  Some will respond to all luns, others will
    lock up. */
@@ -140,7 +143,7 @@ static void scsi_dump_status(void);
        char * revision; /* Latest revision known to be bad.  Not used yet */
      };
 
-static struct blist blacklist[] = 
+static struct blist blacklist[] =
 {
    {"CHINON","CD-ROM CDS-431","H42"},  /* Locks up if polled for lun != 0 */
    {"CHINON","CD-ROM CDS-535","Q14"}, /* Lockup if polled for lun != 0 */
@@ -171,7 +174,7 @@ static struct blist blacklist[] =
    {"HP", "C1750A", "3226"},    /* scanjet iic */
    {"HP", "C1790A", ""},       /* scanjet iip */
    {"HP", "C2500A", ""},       /* scanjet iicx */
-   {NULL, NULL, NULL}};        
+   {NULL, NULL, NULL}};
 
 static int blacklisted(unsigned char * response_data){
   int i = 0;
@@ -187,41 +190,89 @@ static int blacklisted(unsigned char * response_data){
     if(memcmp(blacklist[i].model, pnt,
               strlen(blacklist[i].model))) continue;
     return 1;
-  };   
+  };
 };
 
 /*
- *     As the actual SCSI command runs in the background, we must set up a 
- *     flag that tells scan_scsis() when the result it has is valid.  
- *     scan_scsis can set the_result to -1, and watch for it to become the 
- *     actual return code for that call.  the scan_scsis_done function() is 
- *     our user specified completion function that is passed on to the  
+ *     As the actual SCSI command runs in the background, we must set up a
+ *     flag that tells scan_scsis() when the result it has is valid.
+ *     scan_scsis can set the_result to -1, and watch for it to become the
+ *     actual return code for that call.  the scan_scsis_done function() is
+ *     our user specified completion function that is passed on to the
  *     scsi_do_cmd() function.
  */
 
 volatile int in_scan_scsis = 0;
 static int the_result;
 
-static void restart_all(void) {
- /*
-  * If we might have deadlocked, get things started again. Only
-  * for block devices. Character devices should never deadlock.
-  */
-  struct Scsi_Device_Template * sdtpnt;
+void scsi_make_blocked_list(void)  {
+  int block_count = 0, index;
+  unsigned int flags;
+  struct Scsi_Host * sh[128], * shpnt;
+
+  /*
+   * Create a circular linked list from the scsi hosts which have
+   * the "block" field in the Scsi_Host structure set to any value
+   * different from NULL.
+   * If there is only one host such that host->block != NULL, the list is
+   * empty and host->block is reset to NULL.
+   * The blocked list should include all the scsi hosts using ISA DMA.
+   * In some systems, using two dma channels simultaneously causes
+   * unpredictable results.
+   * Among the scsi hosts in the blocked list, only one host at a time
+   * is allowed to have active commands queued. The transition from
+   * one active host to the next one is allowed only when host_busy == 0
+   * for the active host (which implies host_busy == 0 for all the hosts
+   * in the list). Moreover for block devices the transition to a new
+   * active host is allowed only when a request is completed, since a
+   * block device request can be divided into multiple scsi commands
+   * (when there are few sg lists or clustering is disabled).
+   *
+   * (DB, 4 Feb 1995)
+   */
 
-  for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+  save_flags(flags);
+  cli();
+  host_active = NULL;
+
+  for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next) {
+
+#if 0
+     /*
+      * Is this is a candidate for the blocked list?
+      * Useful to put into the blocked list all the hosts whose driver
+      * does not know about the host->block feature.
+      */
+     if (shpnt->unchecked_isa_dma) shpnt->block = shpnt;
+#endif
 
-     if (sdtpnt->blk && blk_dev[sdtpnt->major].request_fn)
-        (*blk_dev[sdtpnt->major].request_fn)();
+     if (shpnt->block) sh[block_count++] = shpnt;
+     }
 
+  if (block_count == 1) sh[0]->block = NULL;
+
+  else if (block_count > 1) {
+
+     for(index = 0; index < block_count - 1; index++) {
+       sh[index]->block = sh[index + 1];
+       printk("scsi%d : added to blocked host list.\n",
+              sh[index]->host_no);
+       }
+
+     sh[block_count - 1]->block = sh[0];
+     printk("scsi%d : added to blocked host list.\n",
+           sh[index]->host_no);
+     }
+
+  restore_flags(flags);
   }
 
 static void scan_scsis_done (Scsi_Cmnd * SCpnt)
        {
-       
+
 #ifdef DEBUG
        printk ("scan_scsis_done(%d, %06x)\n", SCpnt->host, SCpnt->result);
-#endif 
+#endif
        SCpnt->request.dev = 0xfffe;
 
        if (SCpnt->request.sem != NULL)
@@ -235,17 +286,17 @@ static int max_scsi_luns = 1;
 #endif
 
 void scsi_luns_setup(char *str, int *ints) {
-    if (ints[0] != 1) 
+    if (ints[0] != 1)
        printk("scsi_luns_setup : usage max_scsi_luns=n (n should be between 1 and 8)\n");
     else
-        max_scsi_luns = ints[1];
+       max_scsi_luns = ints[1];
 }
 
 /*
- *     Detecting SCSI devices :        
- *     We scan all present host adapter's busses,  from ID 0 to ID 6.  
- *     We use the INQUIRY command, determine device type, and pass the ID / 
- *     lun address of all sequential devices to the tape driver, all random 
+ *     Detecting SCSI devices :
+ *     We scan all present host adapter's busses,  from ID 0 to ID 6.
+ *     We use the INQUIRY command, determine device type, and pass the ID /
+ *     lun address of all sequential devices to the tape driver, all random
  *     devices to the disk driver.
  */
 
@@ -258,7 +309,7 @@ void scan_scsis (struct Scsi_Host * shpnt)
   Scsi_Device * SDpnt, *SDtail;
   struct Scsi_Device_Template * sdtpnt;
   Scsi_Cmnd  SCmd;
-  
+
   ++in_scan_scsis;
   lun = 0;
   type = -1;
@@ -271,9 +322,9 @@ void scan_scsis (struct Scsi_Host * shpnt)
   }
 
   /* Make sure we have something that is valid for DMA purposes */
-  scsi_result = ((current == task[0]  || !shpnt->unchecked_isa_dma) 
+  scsi_result = ((current == task[0]  || !shpnt->unchecked_isa_dma)
                 ?  &scsi_result0[0] : scsi_malloc(512));
-           
+
 
   shpnt->host_queue = &SCmd;  /* We need this so that
                                         commands can time out */
@@ -292,16 +343,16 @@ void scan_scsis (struct Scsi_Host * shpnt)
          SDpnt->next = NULL;
          SDpnt->attached = 0;
 /*
- * Assume that the device will have handshaking problems, and then 
+ * Assume that the device will have handshaking problems, and then
  * fix this field later if it turns out it doesn't.
  */
          SDpnt->borken = 1;
-         
+
          scsi_cmd[0] = TEST_UNIT_READY;
          scsi_cmd[1] = lun << 5;
          scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
          scsi_cmd[4] = 0;
-         
+
          SCmd.host = shpnt;
          SCmd.target = dev;
          SCmd.lun = lun;
@@ -313,12 +364,12 @@ void scan_scsis (struct Scsi_Host * shpnt)
          SCmd.old_use_sg  = 0;
          SCmd.transfersize = 0;
          SCmd.underflow = 0;
-         
+
          scsi_do_cmd (&SCmd,
-                      (void *)  scsi_cmd, (void *) 
-                      scsi_result, 256,  scan_scsis_done, 
+                      (void *)  scsi_cmd, (void *)
+                      scsi_result, 256,  scan_scsis_done,
                       SCSI_TIMEOUT + 400, 5);
-         
+
          /* Wait for command to finish.  Use simple wait if we are booting, else
             do it right and use a mutex */
 
@@ -338,8 +389,8 @@ void scan_scsis (struct Scsi_Host * shpnt)
          printk("scsi: scan SCSIS id %d lun %d\n", dev, lun);
          printk("scsi: return code %08x\n", SCmd.result);
 #endif
-         
-         
+
+
          if(SCmd.result) {
            if ((driver_byte(SCmd.result)  & DRIVER_SENSE) &&
                ((SCmd.sense_buffer[0] & 0x70) >> 4) == 7) {
@@ -352,30 +403,30 @@ void scan_scsis (struct Scsi_Host * shpnt)
            else
              break;
          };
-         
+
 #if defined (DEBUG) || defined(DEBUG_INIT)
          printk("scsi: performing INQUIRY\n");
 #endif
-         
+
          /*
-          * Build an INQUIRY command block.  
+          * Build an INQUIRY command block.
           */
-         
+
          scsi_cmd[0] = INQUIRY;
          scsi_cmd[1] = (lun << 5) & 0xe0;
          scsi_cmd[2] = 0;
          scsi_cmd[3] = 0;
          scsi_cmd[4] = 255;
          scsi_cmd[5] = 0;
-         
+
          SCmd.request.dev = 0xffff; /* Mark not busy */
          SCmd.cmd_len = 0;
-         
+
          scsi_do_cmd (&SCmd,
-                      (void *)  scsi_cmd, (void *) 
-                      scsi_result, 256,  scan_scsis_done, 
+                      (void *)  scsi_cmd, (void *)
+                      scsi_result, 256,  scan_scsis_done,
                       SCSI_TIMEOUT, 3);
-         
+
          if (current == task[0]){
            while (SCmd.request.dev != 0xfffe);
          } else {
@@ -389,18 +440,18 @@ void scan_scsis (struct Scsi_Host * shpnt)
          }
 
          the_result = SCmd.result;
-         
+
 #if defined(DEBUG) || defined(DEBUG_INIT)
          if (!the_result)
            printk("scsi: INQUIRY successful\n");
          else
            printk("scsi: INQUIRY failed with code %08x\n", the_result);
 #endif
-         
-         if(the_result) break; 
-         
+
+         if(the_result) break;
+
          /* skip other luns on this device */
-         
+
          if (!the_result)
            {
                /* It would seem some TOSHIBA CD-ROM gets things wrong */
@@ -411,32 +462,23 @@ void scan_scsis (struct Scsi_Host * shpnt)
                        scsi_result[1] |= 0x80;  /* removable */
                }
 
-/*
- *     Unfortunately the Toshiba CD-ROM XM-3401TA doesn't
- *     understand the vendor specific mode select/sense
- *     commands which are used by the photo cd routines in 
- *     sr.c.
- */
-
              SDpnt->manufacturer = SCSI_MAN_UNKNOWN;
              if (!strncmp(scsi_result+8,"NEC",3))
                SDpnt->manufacturer = SCSI_MAN_NEC;
-             if (!strncmp(scsi_result+8,"TOSHIBA",7) &&
-                 strncmp(scsi_result+16,"CD-ROM XM-3401TA",16) &&
-                 strncmp(scsi_result+32,"3593",4))
+             if (!strncmp(scsi_result+8,"TOSHIBA",7))
                SDpnt->manufacturer = SCSI_MAN_TOSHIBA;
 
-             SDpnt->removable = (0x80 & 
+             SDpnt->removable = (0x80 &
                                  scsi_result[1]) >> 7;
              SDpnt->lockable = SDpnt->removable;
              SDpnt->changed = 0;
              SDpnt->access_count = 0;
              SDpnt->busy = 0;
-/* 
+/*
  *     Currently, all sequential devices are assumed to be tapes,
- *     all random devices disk, with the appropriate read only 
+ *     all random devices disk, with the appropriate read only
  *     flags set for ROM / WORM treated as RO.
- */ 
+ */
 
              switch (type = (scsi_result[0] & 0x1f))
                {
@@ -460,12 +502,12 @@ void scan_scsis (struct Scsi_Host * shpnt)
                  type = -1;
 #endif
                }
-             
-             SDpnt->soft_reset = 
+
+             SDpnt->soft_reset =
                (scsi_result[7] & 1) && ((scsi_result[3] & 7) == 2);
              SDpnt->random = (type == TYPE_TAPE) ? 0 : 1;
              SDpnt->type = (type & 0x1f);
-             
+
              if (type != -1)
                {
                  print_inquiry(scsi_result);
@@ -479,19 +521,19 @@ void scan_scsis (struct Scsi_Host * shpnt)
                      (SDpnt->scsi_level == 1 &&
                       (scsi_result[3] & 0x0f) == 1))
                    SDpnt->scsi_level++;
-/* 
+/*
  * Set the tagged_queue flag for SCSI-II devices that purport to support
  * tagged queuing in the INQUIRY data.
  */
-                 
+
                  SDpnt->tagged_queue = 0;
-                 
+
                  if ((SDpnt->scsi_level >= SCSI_2) &&
                      (scsi_result[7] & 2)) {
                    SDpnt->tagged_supported = 1;
                    SDpnt->current_tag = 0;
                  }
-                 
+
 /*
  * Accommodate drivers that want to sleep when they should be in a polling
  * loop.
@@ -502,14 +544,14 @@ void scan_scsis (struct Scsi_Host * shpnt)
 /*
  * Some revisions of the Texel CD ROM drives have handshaking
  * problems when used with the Seagate controllers.  Before we
- * know what type of device we're talking to, we assume it's 
+ * know what type of device we're talking to, we assume it's
  * borken and then change it here if it turns out that it isn't
  * a TEXEL drive.
  */
 
                  if(strncmp("TEXEL", (char *) &scsi_result[8], 5) != 0 ||
-                    strncmp("CD-ROM", (char *) &scsi_result[16], 6) != 0 
-/* 
+                    strncmp("CD-ROM", (char *) &scsi_result[16], 6) != 0
+/*
  * XXX 1.06 has problems, some one should figure out the others too so
  * ALL TEXEL drives don't suffer in performance, especially when I finish
  * integrating my seagate patches which do multiple I_T_L nexuses.
@@ -520,8 +562,8 @@ void scan_scsis (struct Scsi_Host * shpnt)
 #endif
                                 )
                    SDpnt->borken = 0;
-                 
-                 
+
+
                  /* These devices need this "key" to unlock the device
                     so we can use it */
                  if(memcmp("INSITE", &scsi_result[8], 6) == 0 &&
@@ -535,15 +577,15 @@ void scan_scsis (struct Scsi_Host * shpnt)
                    scsi_cmd[3] = 0;
                    scsi_cmd[4] = 0x2a;
                    scsi_cmd[5] = 0;
-                   
+
                    SCmd.request.dev = 0xffff; /* Mark not busy */
                    SCmd.cmd_len = 0;
-                   
+
                    scsi_do_cmd (&SCmd,
-                                (void *)  scsi_cmd, (void *) 
-                                scsi_result, 0x2a,  scan_scsis_done, 
+                                (void *)  scsi_cmd, (void *)
+                                scsi_result, 0x2a,  scan_scsis_done,
                                 SCSI_TIMEOUT, 3);
-                   
+
                    if (current == task[0]){
                      while (SCmd.request.dev != 0xfffe);
                    } else {
@@ -572,16 +614,16 @@ void scan_scsis (struct Scsi_Host * shpnt)
                    break;
                  /* Some scsi-1 peripherals do not handle lun != 0.
                     I am assuming that scsi-2 peripherals do better */
-                 if((scsi_result[2] & 0x07) == 1 && 
+                 if((scsi_result[2] & 0x07) == 1 &&
                     (scsi_result[3] & 0x0f) == 0) break;
                }
            }       /* if result == DID_OK ends */
        }       /* for lun ends */
   shpnt->host_queue = NULL;  /* No longer needed here */
-  
+
   /* Last device block does not exist.  Free memory. */
   scsi_init_free((char *) SDpnt, sizeof(Scsi_Device));
-  
+
 
   /* If we allocated a buffer so we could do DMA, free it now */
   if (scsi_result != &scsi_result0[0]) scsi_free(scsi_result, 512);
@@ -590,22 +632,22 @@ void scan_scsis (struct Scsi_Host * shpnt)
 }       /* scan_scsis  ends */
 
 /*
- *     Flag bits for the internal_timeout array 
+ *     Flag bits for the internal_timeout array
  */
 
 #define NORMAL_TIMEOUT 0
 #define IN_ABORT 1
 #define IN_RESET 2
 /*
-       This is our time out function, called when the timer expires for a 
-       given host adapter.  It will attempt to abort the currently executing 
+       This is our time out function, called when the timer expires for a
+       given host adapter.  It will attempt to abort the currently executing
        command, that failing perform a kernel panic.
-*/ 
+*/
 
 static void scsi_times_out (Scsi_Cmnd * SCpnt, int pid)
        {
-       
-       switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET))
+
+       switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET))
                {
                case NORMAL_TIMEOUT:
                        if (!in_scan_scsis) {
@@ -613,13 +655,13 @@ static void scsi_times_out (Scsi_Cmnd * SCpnt, int pid)
                          scsi_dump_status();
 #endif
                        }
-                       
+
                        if (!scsi_abort (SCpnt, DID_TIME_OUT, pid))
-                               return;                         
+                               return;
                case IN_ABORT:
                        printk("SCSI host %d abort() timed out - resetting\n",
                                SCpnt->host->host_no);
-                       if (!scsi_reset (SCpnt)) 
+                       if (!scsi_reset (SCpnt))
                                return;
                case IN_RESET:
                case (IN_ABORT | IN_RESET):
@@ -633,7 +675,7 @@ static void scsi_times_out (Scsi_Cmnd * SCpnt, int pid)
                default:
                        INTERNAL_ERROR;
                }
-                                       
+
        }
 
 
@@ -651,10 +693,10 @@ Scsi_Cmnd * request_queueable (struct request * req, Scsi_Device * device)
 
   if (!device)
     panic ("No device passed to request_queueable().\n");
-  
+
   if (req && req->dev <= 0)
     panic("Invalid device in request_queueable");
-  
+
   SCpnt =  device->host->host_queue;
     while(SCpnt){
       if(SCpnt->target == device->id &&
@@ -665,17 +707,7 @@ Scsi_Cmnd * request_queueable (struct request * req, Scsi_Device * device)
 
   if (!SCpnt) return NULL;
 
-  if (device->host->can_queue &&
-       ((device->host->block && host_active && device->host != host_active) || 
-        (device->host->block && host_next && device->host != host_next) ||
-        device->host->host_busy >= device->host->can_queue)) {
-
-     if (device->host->block && !host_next && host_active 
-                             && device->host != host_active) 
-        host_next = device->host;
-
-     return NULL;
-     }
+  if (SCSI_BLOCK(device->host)) return NULL;
 
   if (req) {
     memcpy(&SCpnt->request, req, sizeof(struct request));
@@ -706,7 +738,7 @@ Scsi_Cmnd * request_queueable (struct request * req, Scsi_Device * device)
     } else {
       req->dev = -1;
       wake_up(&wait_for_request);
-    };      
+    };
   } else {
     SCpnt->request.dev = 0xffff; /* Busy, but no request */
     SCpnt->request.sem = NULL;  /* And no one is waiting for the device either */
@@ -743,26 +775,15 @@ Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device,
 
   if (!device)
     panic ("No device passed to allocate_device().\n");
-  
+
   if (reqp) req = *reqp;
 
     /* See if this request has already been queued by an interrupt routine */
   if (req && (dev = req->dev) <= 0) return NULL;
-  
-  host = device->host;
-  
-  if (intr_count && host->can_queue &&
-                      ((host->block && host_active && host != host_active) ||
-                       (host->block && host_next && host != host_next) ||
-                       host->host_busy >= host->can_queue)) {
 
-     scsi_maybe_deadlocked = 1;
-
-     if (host->block && !host_next && host_active && host != host_active) 
-        host_next = host;
+  host = device->host;
 
-     return NULL;
-     }
+  if (intr_count && SCSI_BLOCK(host)) return NULL;
 
   while (1==1){
     SCpnt = host->host_queue;
@@ -790,7 +811,7 @@ Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device,
                 device->id ,device->lun);
          panic("No device found in allocate_device\n");
        };
-       SCSI_SLEEP(&device->device_wait, 
+       SCSI_SLEEP(&device->device_wait,
                   (SCwait->request.dev > 0));
       } else {
        if (req) {
@@ -819,7 +840,7 @@ Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device,
            req->buffer = bh->b_data;
            SCpnt->request.sem = NULL; /* Wait until whole thing done */
          }
-         else 
+         else
            {
              req->dev = -1;
              *reqp = req->next;
@@ -845,12 +866,13 @@ Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device,
 /*
        This is inline because we have stack problemes if we recurse to deeply.
 */
-                        
+
 inline void internal_cmnd (Scsi_Cmnd * SCpnt)
        {
        int temp;
        struct Scsi_Host * host;
-#ifdef DEBUG_DELAY     
+       unsigned int flags;
+#ifdef DEBUG_DELAY
        int clock;
 #endif
 
@@ -860,27 +882,30 @@ inline void internal_cmnd (Scsi_Cmnd * SCpnt)
        host = SCpnt->host;
 
 /*
-       We will wait MIN_RESET_DELAY clock ticks after the last reset so 
+       We will wait MIN_RESET_DELAY clock ticks after the last reset so
        we can avoid the drive not being ready.
-*/ 
-temp = host->last_reset;
+*/
+save_flags(flags);
+sti();
+temp = host->last_reset + MIN_RESET_DELAY;
 while (jiffies < temp);
+restore_flags(flags);
 
 update_timeout(SCpnt, SCpnt->timeout_per_command);
 
 /*
        We will use a queued command if possible, otherwise we will emulate the
-       queuing and calling of completion function ourselves. 
+       queuing and calling of completion function ourselves.
 */
 #ifdef DEBUG
        printk("internal_cmnd (host = %d, target = %d, command = %08x, buffer =  %08x, \n"
                "bufflen = %d, done = %08x)\n", SCpnt->host->host_no, SCpnt->target, SCpnt->cmnd, SCpnt->buffer, SCpnt->bufflen, SCpnt->done);
 #endif
 
-        if (host->can_queue)
+       if (host->can_queue)
                {
 #ifdef DEBUG
-       printk("queuecommand : routine at %08x\n", 
+       printk("queuecommand : routine at %08x\n",
                host->hostt->queuecommand);
 #endif
                  /* This locking tries to prevent all sorts of races between
@@ -894,7 +919,7 @@ update_timeout(SCpnt, SCpnt->timeout_per_command);
                if(!intr_count && SCpnt->host->irq)
                  disable_irq(SCpnt->host->irq);
 
-                host->hostt->queuecommand (SCpnt, scsi_done);
+               host->hostt->queuecommand (SCpnt, scsi_done);
 
                if(!intr_count && SCpnt->host->irq)
                  enable_irq(SCpnt->host->irq);
@@ -906,34 +931,34 @@ update_timeout(SCpnt, SCpnt->timeout_per_command);
        printk("command() :  routine at %08x\n", host->hostt->command);
 #endif
                temp=host->hostt->command (SCpnt);
-               SCpnt->result = temp;
+               SCpnt->result = temp;
 #ifdef DEBUG_DELAY
        clock = jiffies + 400;
        while (jiffies < clock);
        printk("done(host = %d, result = %04x) : routine at %08x\n", host->host_no, temp, done);
 #endif
-               scsi_done(SCpnt);
-               }       
+               scsi_done(SCpnt);
+               }
 #ifdef DEBUG
        printk("leaving internal_cmnd()\n");
 #endif
-       }       
+       }
 
 static void scsi_request_sense (Scsi_Cmnd * SCpnt)
        {
        unsigned int flags;
-       
+
        save_flags(flags);
        cli();
        SCpnt->flags |= WAS_SENSE | ASKED_FOR_SENSE;
        update_timeout(SCpnt, SENSE_TIMEOUT);
        restore_flags(flags);
-       
+
 
        memcpy ((void *) SCpnt->cmnd , (void *) generic_sense,
                sizeof(generic_sense));
 
-       SCpnt->cmnd[1] = SCpnt->lun << 5;       
+       SCpnt->cmnd[1] = SCpnt->lun << 5;
        SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer);
 
        SCpnt->request_buffer = &SCpnt->sense_buffer;
@@ -946,96 +971,65 @@ static void scsi_request_sense (Scsi_Cmnd * SCpnt)
 
 
 /*
-       scsi_do_cmd sends all the commands out to the low-level driver.  It 
-       handles the specifics required for each low level driver - ie queued 
-       or non queued.  It also prevents conflicts when different high level 
+       scsi_do_cmd sends all the commands out to the low-level driver.  It
+       handles the specifics required for each low level driver - ie queued
+       or non queued.  It also prevents conflicts when different high level
        drivers go for the same host at the same time.
 */
 
-void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd , 
+void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
                  void *buffer, unsigned bufflen, void (*done)(Scsi_Cmnd *),
-                 int timeout, int retries 
+                 int timeout, int retries
                   )
-        {
+       {
        unsigned long flags;
        struct Scsi_Host * host = SCpnt->host;
 
 #ifdef DEBUG
        {
-       int i;  
+       int i;
        int target = SCpnt->target;
        printk ("scsi_do_cmd (host = %d, target = %d, buffer =%08x, "
                "bufflen = %d, done = %08x, timeout = %d, retries = %d)\n"
                "command : " , host->host_no, target, buffer, bufflen, done, timeout, retries);
        for (i = 0; i < 10; ++i)
-               printk ("%02x  ", ((unsigned char *) cmnd)[i]); 
+               printk ("%02x  ", ((unsigned char *) cmnd)[i]);
        printk("\n");
       };
 #endif
-       
+
        if (!host)
                {
                panic ("Invalid or not present host.\n");
                }
 
-       
+
 /*
-       We must prevent reentrancy to the lowlevel host driver.  This prevents 
-       it - we enter a loop until the host we want to talk to is not busy.   
+       We must prevent reentrancy to the lowlevel host driver.  This prevents
+       it - we enter a loop until the host we want to talk to is not busy.
        Race conditions are prevented, as interrupts are disabled in between the
        time we check for the host being not busy, and the time we mark it busy
        ourselves.
 */
 
-       SCpnt->pid = scsi_pid++; 
+       save_flags(flags);
+       cli();
+       SCpnt->pid = scsi_pid++;
+
+       while (SCSI_BLOCK(host)) {
+          restore_flags(flags);
+          SCSI_SLEEP(&host->host_wait, SCSI_BLOCK(host));
+          cli();
+          }
 
-        for(;;) {
+       if (host->block) host_active = host;
+
+       host->host_busy++;
+       restore_flags(flags);
 
-         save_flags(flags);
-          cli();
-
-         if (host->can_queue &&
-                ((host->block && host_active && host != host_active) ||
-                (host->block && host_next && host != host_next) ||
-                host->host_busy >= host->can_queue)) {
-
-             if (intr_count) 
-                panic("scsi: queueing to inactive host while in interrupt.\n");
-
-             if (host->block && !host_next && host_active 
-                                           && host != host_active) 
-                host_next = host;
-
-            restore_flags(flags);
-            SCSI_SLEEP(&host->host_wait, 
-                       ((host->block && host_active && host != host_active) ||
-                        (host->block && host_next && host != host_next) ||
-                       host->host_busy >= host->can_queue));
-            } 
-
-          else {
-            host->host_busy++;
-
-            if (host->block) {
-
-               if (!host_active) {
-                   max_active = 0;
-                   host_active = host;
-                   host_next = NULL;
-                   }
-                else if (max_active > 7 && !host_next) 
-                   host_next = host->block;
-
-                max_active++;
-                }
-
-            restore_flags(flags);
-            break;
-            }
-          }
 /*
-       Our own function scsi_done (which marks the host as not busy, disables 
-       the timeout counter, etc) will be called by us or by the 
+       Our own function scsi_done (which marks the host as not busy, disables
+       the timeout counter, etc) will be called by us or by the
        scsi_hosts[host].queuecommand() function needs to also call
        the completion function for the high level driver.
 
@@ -1054,7 +1048,7 @@ void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
        SCpnt->allowed=retries;
        SCpnt->done = done;
        SCpnt->timeout_per_command = timeout;
-                               
+
        memcpy ((void *) SCpnt->cmnd , (void *) cmnd, 12);
        /* Zero the sense buffer.  Some host adapters automatically request
           sense on error.  0 is not a valid sense code.  */
@@ -1075,13 +1069,13 @@ void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
 #ifdef DEBUG
        printk ("Leaving scsi_do_cmd()\n");
 #endif
-        }
+       }
 
 
 
 /*
-       The scsi_done() function disables the timeout timer for the scsi host, 
-       marks the host as not busy, and calls the user specified completion 
+       The scsi_done() function disables the timeout timer for the scsi host,
+       marks the host as not busy, and calls the user specified completion
        function for that host's current command.
 */
 
@@ -1090,14 +1084,14 @@ static void reset (Scsi_Cmnd * SCpnt)
 #ifdef DEBUG
        printk("scsi: reset(%d)\n", SCpnt->host->host_no);
 #endif
-       
+
        SCpnt->flags |= (WAS_RESET | IS_RESETTING);
        scsi_reset(SCpnt);
-       
+
 #ifdef DEBUG
        printk("performing request sense\n");
 #endif
-       
+
 #if 0  /* FIXME - remove this when done */
        if(SCpnt->flags & NEEDS_JUMPSTART) {
          SCpnt->flags &= ~NEEDS_JUMPSTART;
@@ -1105,8 +1099,8 @@ static void reset (Scsi_Cmnd * SCpnt)
        };
 #endif
 }
-       
-       
+
+
 
 static int check_sense (Scsi_Cmnd * SCpnt)
        {
@@ -1119,7 +1113,7 @@ static int check_sense (Scsi_Cmnd * SCpnt)
     else
       return SUGGEST_RETRY;
       }
-  
+
   SCpnt->flags &= ~ASKED_FOR_SENSE;
 
 #ifdef DEBUG_INIT
@@ -1127,7 +1121,7 @@ static int check_sense (Scsi_Cmnd * SCpnt)
        print_sense("", SCpnt);
        printk("\n");
 #endif
-               if (SCpnt->sense_buffer[2] &0xe0)
+               if (SCpnt->sense_buffer[2] &0xe0)
                  return SUGGEST_ABORT;
 
                switch (SCpnt->sense_buffer[2] & 0xf)
@@ -1138,16 +1132,16 @@ static int check_sense (Scsi_Cmnd * SCpnt)
                        return SUGGEST_IS_OK;
 
                case ABORTED_COMMAND:
-                       return SUGGEST_RETRY;   
+                       return SUGGEST_RETRY;
                case NOT_READY:
                case UNIT_ATTENTION:
                        return SUGGEST_ABORT;
 
-               /* these three are not supported */     
+               /* these three are not supported */
                case COPY_ABORTED:
                case VOLUME_OVERFLOW:
                case MISCOMPARE:
-       
+
                case MEDIUM_ERROR:
                        return SUGGEST_REMAP;
                case BLANK_CHECK:
@@ -1198,7 +1192,7 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
        /* If we requested an abort, (and we got it) then fix up the return
           status to say why */
        if(host_byte(result) == DID_ABORT && SCpnt->abort_reason)
-         SCpnt->result = result = (result & 0xff00ffff) | 
+         SCpnt->result = result = (result & 0xff00ffff) |
            (SCpnt->abort_reason << 16);
 
 
@@ -1217,7 +1211,7 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
                SCpnt->cmd_len = SCpnt->old_cmd_len;
        }
 
-       switch (host_byte(result))      
+       switch (host_byte(result))
        {
        case DID_OK:
                if (status_byte(result) && (SCpnt->flags & WAS_SENSE))
@@ -1228,7 +1222,7 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
 
                        if (!(SCpnt->flags & WAS_RESET))
                                {
-                               printk("scsi%d : target %d lun %d request sense failed, performing reset.\n", 
+                               printk("scsi%d : target %d lun %d request sense failed, performing reset.\n",
                                        SCpnt->host->host_no, SCpnt->target, SCpnt->lun);
                                reset(SCpnt);
                                return;
@@ -1253,11 +1247,11 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
 
                                        SCpnt->flags &= ~WAS_SENSE;
                                        SCpnt->internal_timeout &= ~SENSE_TIMEOUT;
-       
+
                                        switch (checked = check_sense(SCpnt))
                                        {
                                        case SUGGEST_SENSE:
-                                       case 0: 
+                                       case 0:
 #ifdef DEBUG
        printk("NO SENSE.  status = REDO\n");
 #endif
@@ -1265,10 +1259,10 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
                                                update_timeout(SCpnt, oldto);
                                                status = REDO;
                                                break;
-                                       case SUGGEST_IS_OK:
+                                       case SUGGEST_IS_OK:
                                                break;
-                                       case SUGGEST_REMAP:                     
-                                       case SUGGEST_RETRY: 
+                                       case SUGGEST_REMAP:
+                                       case SUGGEST_RETRY:
 #ifdef DEBUG
        printk("SENSE SUGGEST REMAP or SUGGEST RETRY - status = MAYREDO\n");
 #endif
@@ -1285,10 +1279,10 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
                                                exit =  DRIVER_SENSE | SUGGEST_ABORT;
                                                break;
                                        default:
-                                               printk ("Internal error %s %d \n", __FILE__, 
+                                               printk ("Internal error %s %d \n", __FILE__,
                                                        __LINE__);
-                                       }                          
-                                       }       
+                                       }
+                                       }
                                else
                                        {
 #ifdef DEBUG
@@ -1298,16 +1292,16 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
                                        exit =  DRIVER_OK;
                                        status = FINISHED;
                                        }
-                               break;  
+                               break;
 
                        case CHECK_CONDITION:
                                switch (check_sense(SCpnt))
                                  {
-                                 case 0: 
+                                 case 0:
                                    update_timeout(SCpnt, oldto);
                                    status = REDO;
                                    break;
-                                 case SUGGEST_REMAP:                   
+                                 case SUGGEST_REMAP:
                                  case SUGGEST_RETRY:
                                    status = MAYREDO;
                                    exit = DRIVER_SENSE | SUGGEST_RETRY;
@@ -1319,22 +1313,22 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
                                  case SUGGEST_SENSE:
                                scsi_request_sense (SCpnt);
                                status = PENDING;
-                               break;          
+                               break;
                                  }
-                               break;          
-                       
+                               break;
+
                        case CONDITION_GOOD:
                        case INTERMEDIATE_GOOD:
                        case INTERMEDIATE_C_GOOD:
                                break;
-                               
+
                        case BUSY:
                                update_timeout(SCpnt, oldto);
                                status = REDO;
                                break;
 
                        case RESERVATION_CONFLICT:
-                               printk("scsi%d : RESERVATION CONFLICT performing reset.\n", 
+                               printk("scsi%d : RESERVATION CONFLICT performing reset.\n",
                                        SCpnt->host->host_no);
                                reset(SCpnt);
                                return;
@@ -1345,16 +1339,16 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
 #endif
                        default:
                                printk ("Internal error %s %d \n"
-                                       "status byte = %d \n", __FILE__, 
+                                       "status byte = %d \n", __FILE__,
                                        __LINE__, status_byte(result));
-                               
+
                        }
                        break;
                        default:
-                               panic("scsi: unsupported message byte %d received\n", msg_byte(result)); 
+                               panic("scsi: unsupported message byte %d received\n", msg_byte(result));
                        }
                        break;
-       case DID_TIME_OUT:      
+       case DID_TIME_OUT:
 #ifdef DEBUG
        printk("Host returned DID_TIME_OUT - ");
 #endif
@@ -1363,10 +1357,10 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
                        {
 #ifdef DEBUG
        printk("Aborting\n");
-#endif 
+#endif
                        exit = (DRIVER_TIMEOUT | SUGGEST_ABORT);
-                       }               
-               else 
+                       }
+               else
                        {
 #ifdef DEBUG
                        printk ("Retrying.\n");
@@ -1386,15 +1380,15 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
 #endif
                exit  = (DRIVER_HARD | SUGGEST_ABORT);
                break;
-       case DID_ERROR: 
+       case DID_ERROR:
                status = MAYREDO;
                exit = (DRIVER_HARD | SUGGEST_ABORT);
                break;
        case DID_BAD_TARGET:
        case DID_ABORT:
                exit = (DRIVER_INVALID | SUGGEST_ABORT);
-               break;  
-        case DID_RESET:
+               break;
+       case DID_RESET:
                if (SCpnt->flags & IS_RESETTING)
                        {
                        SCpnt->flags &= ~IS_RESETTING;
@@ -1402,14 +1396,14 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
                        break;
                        }
 
-                if(msg_byte(result) == GOOD &&
-                      status_byte(result) == CHECK_CONDITION) {
+               if(msg_byte(result) == GOOD &&
+                     status_byte(result) == CHECK_CONDITION) {
                        switch (check_sense(SCpnt)) {
-                       case 0: 
+                       case 0:
                            update_timeout(SCpnt, oldto);
                            status = REDO;
                            break;
-                       case SUGGEST_REMAP:                     
+                       case SUGGEST_REMAP:
                        case SUGGEST_RETRY:
                            status = MAYREDO;
                            exit = DRIVER_SENSE | SUGGEST_RETRY;
@@ -1419,20 +1413,20 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
                            exit =  DRIVER_SENSE | SUGGEST_ABORT;
                            break;
                        case SUGGEST_SENSE:
-                              scsi_request_sense (SCpnt);
-                              status = PENDING;
-                              break;
+                             scsi_request_sense (SCpnt);
+                             status = PENDING;
+                             break;
                        }
                } else {
-                status=REDO;
-                exit = SUGGEST_RETRY;
+               status=REDO;
+               exit = SUGGEST_RETRY;
                }
-                break;
-       default :               
+               break;
+       default :
                exit = (DRIVER_ERROR | SUGGEST_DIE);
        }
 
-       switch (status) 
+       switch (status)
                {
                case FINISHED:
                case PENDING:
@@ -1447,13 +1441,14 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
                        if ((++SCpnt->retries) < SCpnt->allowed)
                        {
                        if ((SCpnt->retries >= (SCpnt->allowed >> 1))
+                           && !(jiffies < SCpnt->host->last_reset + MIN_RESET_PERIOD)
                            && !(SCpnt->flags & WAS_RESET))
-                               {
+                               {
                                        printk("scsi%d : resetting for second half of retries.\n",
                                                SCpnt->host->host_no);
                                        reset(SCpnt);
                                        break;
-                               }
+                               }
 
                        }
                        else
@@ -1465,14 +1460,12 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
 
                case REDO:
 
-                        if (host->block) scsi_maybe_deadlocked = 1;
-
-                       if (SCpnt->flags & WAS_SENSE)                   
-                               scsi_request_sense(SCpnt);      
-                       else    
+                       if (SCpnt->flags & WAS_SENSE)
+                               scsi_request_sense(SCpnt);
+                       else
                          {
                            memcpy ((void *) SCpnt->cmnd,
-                                   (void*) SCpnt->data_cmnd, 
+                                   (void*) SCpnt->data_cmnd,
                                    sizeof(SCpnt->data_cmnd));
                            SCpnt->request_buffer = SCpnt->buffer;
                            SCpnt->request_bufflen = SCpnt->bufflen;
@@ -1480,8 +1473,8 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
                            SCpnt->cmd_len = SCpnt->old_cmd_len;
                            internal_cmnd (SCpnt);
                          };
-                       break;  
-               default: 
+                       break;
+               default:
                        INTERNAL_ERROR;
                }
 
@@ -1493,30 +1486,24 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
           host->host_busy--; /* Indicate that we are free */
 
           if (host->block && host->host_busy == 0) {
-              struct Scsi_Host * block;
-
-              block = host_next;
-              host_active = NULL;
+             host_active = NULL;
 
-              if (block) wake_up(&block->host_wait);
+             /* For block devices "wake_up" is done in end_scsi_request */
+             if (MAJOR(SCpnt->request.dev) != SCSI_DISK_MAJOR &&
+                       MAJOR(SCpnt->request.dev) != SCSI_CDROM_MAJOR) {
+                struct Scsi_Host * next;
 
-              for (block = host->block; block != host; block = block->block)
-                 wake_up(&block->host_wait);
+                for (next = host->block; next != host; next = next->block)
+                   wake_up(&next->host_wait);
+                }
 
-              host_next = NULL;
-
-              if (scsi_maybe_deadlocked) {
-                 scsi_maybe_deadlocked = 0;
-                 restart_all();
-                 }
-
-              }
+             }
 
-           wake_up(&host->host_wait);
+          wake_up(&host->host_wait);
           SCpnt->result = result | ((exit & 0xff) << 24);
           SCpnt->use_sg = SCpnt->old_use_sg;
           SCpnt->cmd_len = SCpnt->old_cmd_len;
-          SCpnt->done (SCpnt);
+          SCpnt->done (SCpnt);
           }
 
 #undef FINISHED
@@ -1527,13 +1514,13 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
 
 /*
        The scsi_abort function interfaces with the abort() function of the host
-       we are aborting, and causes the current command to not complete.  The 
-       caller should deal with any error messages or status returned on the 
+       we are aborting, and causes the current command to not complete.  The
+       caller should deal with any error messages or status returned on the
        next call.
-       
+
        This will not be called reentrantly for a given host.
 */
-       
+
 /*
        Since we're nice guys and specified that abort() and reset()
        can be non-reentrant.  The internal_timeout flags are used for
@@ -1546,8 +1533,8 @@ int scsi_abort (Scsi_Cmnd * SCpnt, int why, int pid)
        int oldto;
        unsigned long flags;
        struct Scsi_Host * host = SCpnt->host;
-       
-       while(1)        
+
+       while(1)
                {
                save_flags(flags);
                cli();
@@ -1561,24 +1548,24 @@ int scsi_abort (Scsi_Cmnd * SCpnt, int why, int pid)
                  return 0;
                }
 
-               if (SCpnt->internal_timeout & IN_ABORT) 
+               if (SCpnt->internal_timeout & IN_ABORT)
                        {
                        restore_flags(flags);
                        while (SCpnt->internal_timeout & IN_ABORT);
                        }
                else
-                       {       
+                       {
                        SCpnt->internal_timeout |= IN_ABORT;
                        oldto = update_timeout(SCpnt, ABORT_TIMEOUT);
 
-                       if ((SCpnt->flags & IS_RESETTING) && 
+                       if ((SCpnt->flags & IS_RESETTING) &&
                            SCpnt->device->soft_reset) {
                          /* OK, this command must have died when we did the
                             reset.  The device itself must have lied. */
                          printk("Stale command on %d:%d appears to have died when"
                                 " the bus was reset\n", SCpnt->target, SCpnt->lun);
                        }
-                       
+
                        restore_flags(flags);
                        if (!host->host_busy) {
                          SCpnt->internal_timeout &= ~IN_ABORT;
@@ -1586,7 +1573,7 @@ int scsi_abort (Scsi_Cmnd * SCpnt, int why, int pid)
                          return 0;
                        }
                        printk("scsi : aborting command due to timeout : pid %lu, scsi%d, id %d, lun %d ",
-                              SCpnt->pid, SCpnt->host->host_no, (int) SCpnt->target, (int) 
+                              SCpnt->pid, SCpnt->host->host_no, (int) SCpnt->target, (int)
                               SCpnt->lun);
                        print_command (SCpnt->cmnd);
                        if (SCpnt->request.dev == -1 || pid != SCpnt->pid)
@@ -1638,16 +1625,16 @@ int scsi_abort (Scsi_Cmnd * SCpnt, int why, int pid)
                          return 1;
                        }
                      }
-             } 
+             }
       }
-     
+
 int scsi_reset (Scsi_Cmnd * SCpnt)
        {
        int temp, oldto;
        unsigned long flags;
        Scsi_Cmnd * SCpnt1;
        struct Scsi_Host * host = SCpnt->host;
-       
+
 #ifdef DEBUG
        printk("Danger Will Robinson! - SCSI bus for host %d is being reset.\n",host->host_no);
 #endif
@@ -1662,16 +1649,16 @@ int scsi_reset (Scsi_Cmnd * SCpnt)
                else
                        {
                        SCpnt->internal_timeout |= IN_RESET;
-                       oldto = update_timeout(SCpnt, RESET_TIMEOUT);   
-                                       
+                       oldto = update_timeout(SCpnt, RESET_TIMEOUT);
+
                        if (host->host_busy)
-                               {       
+                               {
                                restore_flags(flags);
                                SCpnt1 = host->host_queue;
                                while(SCpnt1) {
                                  if (SCpnt1->request.dev > 0) {
-#if 0                            
-                                   if (!(SCpnt1->flags & IS_RESETTING) && 
+#if 0
+                                   if (!(SCpnt1->flags & IS_RESETTING) &&
                                      !(SCpnt1->internal_timeout & IN_ABORT))
                                    scsi_abort(SCpnt1, DID_RESET, SCpnt->pid);
 #endif
@@ -1680,31 +1667,20 @@ int scsi_reset (Scsi_Cmnd * SCpnt)
                                  SCpnt1 = SCpnt1->next;
                                };
 
-                               temp = host->hostt->reset(SCpnt);       
-                               }                               
+                               host->last_reset = jiffies;
+                               temp = host->hostt->reset(SCpnt);
+                               host->last_reset = jiffies;
+                               }
                        else
                                {
-                               host->host_busy++;
-
-                                if (host->block) {
-                                   host_active = host;
-                                   host_next = NULL;
-                                   }
-       
+                               if (!host->block) host->host_busy++;
                                restore_flags(flags);
+                               host->last_reset = jiffies;
                                temp = host->hostt->reset(SCpnt);
                                host->last_reset = jiffies;
-                               host->host_busy--;
-
+                               if (!host->block) host->host_busy--;
                                }
 
-                        if (host->block && host->host_busy == 0) {
-                           host_active = NULL;
-                           host_next = NULL;
-                           restart_all();
-                           }
-
-
 #ifdef DEBUG
                        printk("scsi reset function returned %d\n", temp);
 #endif
@@ -1723,7 +1699,7 @@ int scsi_reset (Scsi_Cmnd * SCpnt)
                          SCpnt->internal_timeout &= ~IN_RESET;
                          scsi_request_sense (SCpnt);
                          return 0;
-                       case SCSI_RESET_SNOOZE:                   
+                       case SCSI_RESET_SNOOZE:
                          /* In this case, we set the timeout field to 0
                             so that this command does not time out any more,
                             and we return 1 so that we get a message on the
@@ -1738,12 +1714,12 @@ int scsi_reset (Scsi_Cmnd * SCpnt)
                        default:
                          return 1;
                        }
-       
-                       return temp;    
+
+                       return temp;
                        }
                }
        }
-                        
+
 
 static void scsi_main_timeout(void)
        {
@@ -1756,7 +1732,7 @@ static void scsi_main_timeout(void)
        struct Scsi_Host * host;
        Scsi_Cmnd * SCpnt = NULL;
 
-       do      {       
+       do {
                save_flags(flags);
                cli();
 
@@ -1765,7 +1741,7 @@ static void scsi_main_timeout(void)
                Find all timers such that they have 0 or negative (shouldn't happen)
                time remaining on them.
        */
-                       
+
                timed_out = 0;
                for(host = scsi_hostlist; host; host = host->next) {
                  for(SCpnt = host->host_queue; SCpnt; SCpnt = SCpnt->next)
@@ -1775,23 +1751,23 @@ static void scsi_main_timeout(void)
                        pid = SCpnt->pid;
                        restore_flags(flags);
                        scsi_times_out(SCpnt, pid);
-                       ++timed_out; 
+                       ++timed_out;
                        save_flags(flags);
                        cli();
                      }
                };
-             } while (timed_out);      
+             } while (timed_out);
        restore_flags(flags);
       }
 
 /*
        The strategy is to cause the timer code to call scsi_times_out()
-       when the soonest timeout is pending.  
+       when the soonest timeout is pending.
        The arguments are used when we are queueing a new command, because
        we do not want to subtract the time used from this time, but when we
        set the timer, we want to take this value into account.
 */
-       
+
 static int update_timeout(Scsi_Cmnd * SCset, int timeout)
        {
        unsigned int least, used;
@@ -1803,18 +1779,18 @@ static int update_timeout(Scsi_Cmnd * SCset, int timeout)
        save_flags(flags);
        cli();
 
-/* 
-       Figure out how much time has passed since the last time the timeouts 
-       were updated 
+/*
+       Figure out how much time has passed since the last time the timeouts
+       were updated
 */
        used = (time_start) ? (jiffies - time_start) : 0;
 
 /*
        Find out what is due to timeout soonest, and adjust all timeouts for
-       the amount of time that has passed since the last time we called 
-       update_timeout. 
+       the amount of time that has passed since the last time we called
+       update_timeout.
 */
-       
+
        oldto = 0;
 
        if(SCset){
@@ -1834,24 +1810,24 @@ static int update_timeout(Scsi_Cmnd * SCset, int timeout)
            };
 
 /*
-       If something is due to timeout again, then we will set the next timeout 
+       If something is due to timeout again, then we will set the next timeout
        interrupt to occur.  Otherwise, timeouts are disabled.
 */
-       
+
        if (least != 0xffffffff)
                {
-               time_start = jiffies;   
-               timer_table[SCSI_TIMER].expires = (time_elapsed = least) + jiffies;     
+               time_start = jiffies;
+               timer_table[SCSI_TIMER].expires = (time_elapsed = least) + jiffies;
                timer_active |= 1 << SCSI_TIMER;
                }
        else
                {
                timer_table[SCSI_TIMER].expires = time_start = time_elapsed = 0;
                timer_active &= ~(1 << SCSI_TIMER);
-               }       
+               }
        restore_flags(flags);
        return oldto;
-       }               
+       }
 
 
 static unsigned char * dma_malloc_freelist = NULL;
@@ -1872,12 +1848,12 @@ void *scsi_malloc(unsigned int len)
   int i, j;
   if((len & 0x1ff) || len > (1<<MALLOC_PAGEBITS))
     return NULL;
-  
+
   save_flags(flags);
   cli();
   nbits = len >> 9;
   mask = (1 << nbits) - 1;
-  
+
   for(i=0;i < (dma_sectors >> (MALLOC_PAGEBITS - 9)); i++)
     for(j=0; j<=(sizeof(*dma_malloc_freelist) * 8) - nbits; j++){
       if ((dma_malloc_freelist[i] & (mask << j)) == 0){
@@ -1906,13 +1882,13 @@ int scsi_free(void *obj, unsigned int len)
 
    offset = -1;
   for (page = 0; page < (dma_sectors >> 3); page++)
-       if ((unsigned long) obj >= (unsigned long) dma_malloc_pages[page] &&
-               (unsigned long) obj < (unsigned long) dma_malloc_pages[page] + (1 << MALLOC_PAGEBITS))
-               {
-                       offset = ((unsigned long) obj) - ((unsigned long)dma_malloc_pages[page]);
-                       break;
-               }
-                
+       if ((unsigned long) obj >= (unsigned long) dma_malloc_pages[page] &&
+               (unsigned long) obj < (unsigned long) dma_malloc_pages[page] + (1 << MALLOC_PAGEBITS))
+               {
+                       offset = ((unsigned long) obj) - ((unsigned long)dma_malloc_pages[page]);
+                       break;
+               }
+
   if (page == (dma_sectors >> 3)) panic("Bad offset");
   sector = offset >> 9;
   if(sector >= dma_sectors) panic ("Bad page");
@@ -1973,8 +1949,8 @@ void scsi_init_free(char * ptr, unsigned int size)
 }
 
 /*
-       scsi_dev_init() is our initialization routine, which in turn calls host 
-       initialization, bus scanning, and sd/st initialization routines.  It 
+       scsi_dev_init() is our initialization routine, which in turn calls host
+       initialization, bus scanning, and sd/st initialization routines.  It
        should be called from main().
 */
 
@@ -1988,7 +1964,7 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end
        int i;
 #ifdef FOO_ON_YOU
        return;
-#endif 
+#endif
 
        /* Init a few things so we can "malloc" memory. */
        scsi_loadable_module_flag = 0;
@@ -1999,8 +1975,8 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end
        timer_table[SCSI_TIMER].expires = 0;
 
        /* initialize all hosts */
-       scsi_init(); 
-                               
+       scsi_init();
+
        scsi_devices = (Scsi_Device *) NULL;
 
        for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
@@ -2012,7 +1988,7 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end
            printk("%d SCSI %s%s ", sdtpnt->dev_noticed, sdtpnt->name,
            (sdtpnt->dev_noticed != 1) ? "s" : "");
        printk("total.\n");
-  
+
        for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
          if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)();
 
@@ -2034,8 +2010,8 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end
              SCpnt->old_use_sg = 0;
              SCpnt->old_cmd_len = 0;
              SCpnt->timeout = 0;
-              SCpnt->underflow = 0;
-              SCpnt->transfersize = 0;
+             SCpnt->underflow = 0;
+             SCpnt->transfersize = 0;
              SCpnt->host_scribble = NULL;
              host = SDpnt->host;
              if(host->host_queue)
@@ -2057,12 +2033,12 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end
 
        for (SDpnt=scsi_devices; SDpnt; SDpnt = SDpnt->next) {
          host = SDpnt->host;
-         
+
          if(SDpnt->type != TYPE_TAPE)
-           dma_sectors += ((host->sg_tablesize * 
-                            sizeof(struct scatterlist) + 511) >> 9) * 
+           dma_sectors += ((host->sg_tablesize *
+                            sizeof(struct scatterlist) + 511) >> 9) *
                               host->cmd_per_lun;
-         
+
          if(host->unchecked_isa_dma &&
             memory_end - 1 > ISA_DMA_THRESHOLD &&
             SDpnt->type != TYPE_TAPE) {
@@ -2075,17 +2051,17 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end
        dma_sectors = (dma_sectors + 15) & 0xfff0;
        dma_free_sectors = dma_sectors;  /* This must be a multiple of 16 */
 
-       dma_malloc_freelist = (unsigned char *) 
+       dma_malloc_freelist = (unsigned char *)
          scsi_init_malloc(dma_sectors >> 3, GFP_ATOMIC);
        memset(dma_malloc_freelist, 0, dma_sectors >> 3);
 
-       dma_malloc_pages = (unsigned char **) 
-         scsi_init_malloc(dma_sectors >> 1, GFP_ATOMIC);
-       memset(dma_malloc_pages, 0, dma_sectors >> 1);
-       for(i=0; i< dma_sectors >> 3; i++)
-         dma_malloc_pages[i] = (unsigned char *) 
-           scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
+       dma_malloc_pages = (unsigned char **)
+         scsi_init_malloc(dma_sectors >> 1, GFP_ATOMIC);
+       memset(dma_malloc_pages, 0, dma_sectors >> 1);
+
+       for(i=0; i< dma_sectors >> 3; i++)
+         dma_malloc_pages[i] = (unsigned char *)
+           scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
 
 
        /* OK, now we finish the initialization by doing spin-up, read
@@ -2093,41 +2069,41 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end
        for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
          if(sdtpnt->finish && sdtpnt->nr_dev)
            (*sdtpnt->finish)();
-       
+
        scsi_loadable_module_flag = 1;
        return scsi_init_memory_start;
        }
 
 static void print_inquiry(unsigned char *data)
 {
-        int i;
+       int i;
 
        printk("  Vendor: ");
        for (i = 8; i < 16; i++)
-               {
-               if (data[i] >= 0x20 && i < data[4] + 5)
-                       printk("%c", data[i]);
-               else
-                       printk(" ");
-               }
+               {
+               if (data[i] >= 0x20 && i < data[4] + 5)
+                       printk("%c", data[i]);
+               else
+                       printk(" ");
+               }
 
        printk("  Model: ");
        for (i = 16; i < 32; i++)
-               {
-               if (data[i] >= 0x20 && i < data[4] + 5)
-                       printk("%c", data[i]);
-               else
-                       printk(" ");
-               }
+               {
+               if (data[i] >= 0x20 && i < data[4] + 5)
+                       printk("%c", data[i]);
+               else
+                       printk(" ");
+               }
 
        printk("  Rev: ");
        for (i = 32; i < 36; i++)
-               {
-               if (data[i] >= 0x20 && i < data[4] + 5)
-                       printk("%c", data[i]);
-               else
-                       printk(" ");
-               }
+               {
+               if (data[i] >= 0x20 && i < data[4] + 5)
+                       printk("%c", data[i]);
+               else
+                       printk(" ");
+               }
 
        printk("\n");
 
@@ -2186,8 +2162,14 @@ static int scsi_register_host(Scsi_Host_Template * tpnt)
            printk ("scsi%d : %s\n", /* And print a little message */
                    shpnt->host_no, name);
          }
+
+      printk ("scsi : %d host%s.\n", next_scsi_host,
+               (next_scsi_host == 1) ? "" : "s");
+
+      scsi_make_blocked_list();
+
       /* The next step is to call scan_scsis here.  This generates the
-         Scsi_Devices entries */
+        Scsi_Devices entries */
 
       for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
        if(shpnt->hostt == tpnt) scan_scsis(shpnt);
@@ -2232,18 +2214,18 @@ static int scsi_register_host(Scsi_Host_Template * tpnt)
          unsigned int new_dma_sectors = 0;
          unsigned int new_need_isa_buffer = 0;
          unsigned char ** new_dma_malloc_pages = NULL;
-         
+
          if (scsi_devicelist)
            new_dma_sectors = 16;  /* Base value we use */
-         
+
          for (SDpnt=scsi_devices; SDpnt; SDpnt = SDpnt->next) {
            host = SDpnt->host;
-           
+
            if(SDpnt->type != TYPE_TAPE)
-             new_dma_sectors += ((host->sg_tablesize * 
-                                  sizeof(struct scatterlist) + 511) >> 9) * 
+             new_dma_sectors += ((host->sg_tablesize *
+                                  sizeof(struct scatterlist) + 511) >> 9) *
                                     host->cmd_per_lun;
-           
+
            if(host->unchecked_isa_dma &&
               scsi_need_isa_bounce_buffers &&
               SDpnt->type != TYPE_TAPE) {
@@ -2252,21 +2234,21 @@ static int scsi_register_host(Scsi_Host_Template * tpnt)
              new_need_isa_buffer++;
            };
          };
-         
+
          new_dma_sectors = (new_dma_sectors + 15) & 0xfff0;
 
-         new_dma_malloc_freelist = (unsigned char *) 
+         new_dma_malloc_freelist = (unsigned char *)
            scsi_init_malloc(new_dma_sectors >> 3, GFP_ATOMIC);
          memset(new_dma_malloc_freelist, 0, new_dma_sectors >> 3);
-         
-         new_dma_malloc_pages = (unsigned char **) 
+
+         new_dma_malloc_pages = (unsigned char **)
            scsi_init_malloc(new_dma_sectors >> 1, GFP_ATOMIC);
          memset(new_dma_malloc_pages, 0, new_dma_sectors >> 1);
-         
+
          for(i=dma_sectors >> 3; i< new_dma_sectors >> 3; i++)
-           new_dma_malloc_pages[i] = (unsigned char *) 
+           new_dma_malloc_pages[i] = (unsigned char *)
              scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
-         
+
 
          /* When we dick with the actual DMA list, we need to protect things */
 
@@ -2275,21 +2257,22 @@ static int scsi_register_host(Scsi_Host_Template * tpnt)
          memcpy(new_dma_malloc_freelist, dma_malloc_freelist, dma_sectors >> 3);
          scsi_init_free(dma_malloc_freelist, dma_sectors>>3);
          dma_malloc_freelist = new_dma_malloc_freelist;
-         
+
          memcpy(new_dma_malloc_pages, dma_malloc_pages, dma_sectors >> 1);
          scsi_init_free((char *) dma_malloc_pages, dma_sectors>>1);
-         
+
          dma_free_sectors += new_dma_sectors - dma_sectors;
          dma_malloc_pages = new_dma_malloc_pages;
          dma_sectors = new_dma_sectors;
          need_isa_buffer = new_need_isa_buffer;
          restore_flags(flags);
 
-         
+
        }
       /* This does any final handling that is required. */
       for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
-       if(sdtpnt->finish) (*sdtpnt->finish)();
+       if(sdtpnt->finish && sdtpnt->nr_dev)
+         (*sdtpnt->finish)();
     }
   return 0;
 }
@@ -2299,7 +2282,7 @@ static int scsi_register_host(Scsi_Host_Template * tpnt)
  * is trying to remove a low level scsi driver from the system.
  */
 static void scsi_unregister_host(Scsi_Host_Template * tpnt)
-{  
+{
   Scsi_Host_Template * SHT, *SHTp;
   Scsi_Device *sdpnt, * sdppnt, * sdpnt1;
   Scsi_Cmnd * SCpnt;
@@ -2344,7 +2327,7 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt)
          return;
        }
       }
-  
+
   /* Next we free up the Scsi_Cmnd structures for this host */
 
   for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next)
@@ -2355,7 +2338,7 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt)
        sdpnt->host->host_queue = SCpnt;
        if (SCpnt) SCpnt->prev = NULL;
       }
-  
+
   /* Next free up the Scsi_Device structures for this host */
 
   sdppnt = NULL;
@@ -2376,7 +2359,7 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt)
      that were detected */
 
   shpnt = scsi_hostlist;
-  while(shpnt) { 
+  while(shpnt) {
    sh1 = shpnt->next;
     if(shpnt->hostt == tpnt) {
       if(shpnt->loaded_as_module) {
@@ -2388,7 +2371,7 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt)
             thing for most correctly written host adapters. */
          if (shpnt->irq) free_irq(shpnt->irq);
          if (shpnt->dma_channel != 0xff) free_dma(shpnt->dma_channel);
-         if (shpnt->io_port && shpnt->n_io_port) 
+         if (shpnt->io_port && shpnt->n_io_port)
            release_region(shpnt->io_port, shpnt->n_io_port);
        }
        if(pcount == next_scsi_host) scsi_unregister(shpnt);
@@ -2398,6 +2381,11 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt)
     shpnt = sh1;
   }
 
+  printk ("scsi : %d host%s.\n", next_scsi_host,
+         (next_scsi_host == 1) ? "" : "s");
+
+  scsi_make_blocked_list();
+
   /* There were some hosts that were loaded at boot time, so we cannot
      do any more than this */
   if (tpnt->present) return;
@@ -2452,7 +2440,7 @@ void scsi_unregister_module(int module_type, void * ptr)
 }
 
 #ifdef DEBUG_TIMEOUT
-static void 
+static void
 scsi_dump_status(void)
 {
   int i;
index e47383ec0b7bf13f1fa41cabd87b45b58d4b83cb..e66df3ee4706eef473c1e0a87c0c2ad1a3fc7568 100644 (file)
@@ -76,6 +76,7 @@
 #define MODE_SELECT_10         0x55
 #define MODE_SENSE_10          0x5a
 
+extern void scsi_make_blocked_list(void);
 extern volatile int in_scan_scsis;
 extern const unsigned char scsi_command_size[8];
 #define COMMAND_SIZE(opcode) scsi_command_size[((opcode) >> 5) & 7]
@@ -528,6 +529,7 @@ extern int scsi_reset (Scsi_Cmnd *);
 extern int max_scsi_hosts;
 
 #if defined(MAJOR_NR) && (MAJOR_NR != SCSI_TAPE_MAJOR)
+#include "hosts.h"
 static Scsi_Cmnd * end_scsi_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors)
 {
        struct request * req;
@@ -566,6 +568,15 @@ static Scsi_Cmnd * end_scsi_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors
        if (req->sem != NULL) {
                up(req->sem);
        }
+
+        if (SCpnt->host->block) {
+           struct Scsi_Host * next;
+
+           for (next = SCpnt->host->block; next != SCpnt->host;
+                                                   next = next->block)
+              wake_up(&next->host_wait);
+           }
+
        req->dev = -1;
        wake_up(&wait_for_request);
        wake_up(&SCpnt->device->device_wait);
@@ -595,11 +606,16 @@ static Scsi_Cmnd * end_scsi_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors
        if (CONDITION) {                                        \
                struct wait_queue wait = { current, NULL};      \
                add_wait_queue(QUEUE, &wait);                   \
-sleep_repeat:                                                  \
+        for(;;) {                                              \
                current->state = TASK_UNINTERRUPTIBLE;          \
                if (CONDITION) {                                \
-                       schedule();                             \
-                       goto sleep_repeat;                      \
+                   if (intr_count)                              \
+                      panic("scsi: trying to call schedule() in interrupt" \
+                            ", file %s, line %d.\n", __FILE__, __LINE__);  \
+                  schedule();                                  \
+                  }                                            \
+               else                                            \
+                   break;                                      \
                }                                               \
                remove_wait_queue(QUEUE, &wait);                \
                current->state = TASK_RUNNING;                  \
index 4f84e0c5f6e2efc3405651edc64152daebf91709..ab0f8e3dbd93d36841d2e5f18501196255a11ca0 100644 (file)
@@ -293,19 +293,11 @@ static void rw_intr (Scsi_Cmnd * SCpnt)
  *     
  *   - TOSHIBA: setting density is done here now, mounting PhotoCD's should
  *              work now without running the program "set_density"
- *              People reported that it is necessary to eject and reinsert
- *              the CD after the set-density call to get this working for
- *              old drives.
- *              And some very new drives don't need this call any more...
  *              Multisession CD's are supported too.
  *
- * Dec 1994: completely rewritten, uses kernel_scsi_ioctl() now
- *
  *   kraxel@cs.tu-berlin.de (Gerd Knorr)
  */
 
-#define DEBUG
-
 static void sr_photocd(struct inode *inode)
 {
   unsigned long   sector,min,sec,frame;
@@ -345,12 +337,14 @@ static void sr_photocd(struct inode *inode)
     if (rc != 0) {
       printk("sr_photocd: ioctl error (NEC): 0x%x\n",rc);
       sector = 0;
+      is_xa = 0;
     } else {
       min   = (unsigned long) rec[15]/16*10 + (unsigned long) rec[15]%16;
       sec   = (unsigned long) rec[16]/16*10 + (unsigned long) rec[16]%16;
       frame = (unsigned long) rec[17]/16*10 + (unsigned long) rec[17]%16;
       /* if rec[14] isn't 0xb0, the drive does not support multisession CD's, use zero */
       sector = (0xb0 == rec[14]) ? min*CD_SECS*CD_FRAMES + sec*CD_FRAMES + frame : 0;
+      is_xa = (rec[14] == 0xb0);
 #ifdef DEBUG
       printk("NEC: (%2x) %2li:%02li:%02li = %li\n",buf[8+14],min,sec,frame,sector);
       if (sector) {
@@ -377,6 +371,7 @@ static void sr_photocd(struct inode *inode)
     if (rc != 0) {
       printk("sr_photocd: ioctl error (TOSHIBA #1): 0x%x\n",rc);
       sector = 0;
+      is_xa = 0;
       break; /* if the first ioctl fails, we don't call the second one */
     }
     is_xa  = (rec[0] == 0x20);
@@ -431,6 +426,8 @@ static void sr_photocd(struct inode *inode)
       if (rc != 0) {
        printk("sr_photocd: ioctl error (TOSHIBA #3): 0x%x\n",rc);
       }
+      /* The set_density command may have changed the sector size or capacity. */
+      scsi_CDs[MINOR(inode->i_rdev)].needs_sector_size = 1;
     }
     break;
 
@@ -440,16 +437,14 @@ static void sr_photocd(struct inode *inode)
     printk("sr_photocd: unknown drive, no special multisession code\n");
 #endif
     sector = 0;
+    is_xa = 0;
     break; }
 
   scsi_CDs[MINOR(inode->i_rdev)].mpcd_sector = sector;
-  /* The code above may have changed the sector size or capacity. */
-  scsi_CDs[MINOR(inode->i_rdev)].needs_sector_size = 1;
+  scsi_CDs[MINOR(inode->i_rdev)].is_xa = is_xa;
   return;
 }
 
-#undef DEBUG
-
 static int sr_open(struct inode * inode, struct file * filp)
 {
        if(MINOR(inode->i_rdev) >= sr_template.nr_dev || 
index e549551ba9e21926be37ebe97f25b3c91336a4e3..6200e0fb1a85859d9cc11c5f2a3bf6848080d5fb 100644 (file)
@@ -25,6 +25,7 @@ typedef struct
        unsigned        sector_size;            /* size in bytes                        */
        Scsi_Device     *device;                
        unsigned long   mpcd_sector;            /* for reading multisession-CD's        */
+       char            is_xa;                  /* is it an XA-CD ?                     */
        unsigned char   sector_bit_size;        /* sector size = 2^sector_bit_size      */
        unsigned char   sector_bit_shift;       /* sectors/FS block = 2^sector_bit_shift*/
        unsigned        needs_sector_size:1;    /* needs to get sector size */
index 4e317c5556f85193a6a8b0c0ccaddf7532fe7e14..f1ec868eca36de6296acf307bcdc1267751ab269 100644 (file)
@@ -408,11 +408,8 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne
                            ms_info.addr.lba=scsi_CDs[target].mpcd_sector;
                          else return (-EINVAL);
                        
-                         if (scsi_CDs[target].mpcd_sector)
-                           ms_info.xa_flag=1; /* valid redirection address */
-                         else
-                           ms_info.xa_flag=0; /* invalid redirection address */
-                         
+                         ms_info.xa_flag=scsi_CDs[target].is_xa;
+                                                 
                          err=verify_area(VERIFY_WRITE,(void *) arg,
                                          sizeof(struct cdrom_multisession));
                          if (err) return (err);
index c5f1ae7a77e64a1f069c9d24e93a123635a598ab..7b902ea74a8decff3e17473c3b68e59a1b981c18 100644 (file)
@@ -1,6 +1,9 @@
 /*
  *      u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters.
  *
+ *       8 Feb 1995 rev. 1.15 for linux 1.1.89
+ *          Cleared target_time_out counter while preforming a reset.
+ *
  *      28 Jan 1995 rev. 1.14 for linux 1.1.86
  *          Added module support.
  *          Log and do a retry when a disk drive returns a target status
@@ -34,7 +37,7 @@
  * 
  *          Multiple U14F and/or U34F host adapters are supported.
  *
- *      Released by Dario Ballabio (Dario_Ballabio@milano.europe.dg.com)
+ *      Copyright (C) 1994, 1995 Dario Ballabio (dario@milano.europe.dg.com)
  *
  *      WARNING: if your 14F board has an old firmware revision (see below)
  *               you must change "#undef" into "#define" in the following
 
 #if defined(MODULE)
 #include <linux/module.h>
+#include <linux/version.h>
 #endif
 
 #include <linux/string.h>
@@ -295,7 +299,7 @@ static int board_inquiry(unsigned int j) {
 
    sti();
    time = jiffies;
-   while (jiffies < (time + 100) && limit++ < 100000000) sti();
+   while (jiffies < (time + 100) && limit++ < 100000000);
    cli();
 
    if (cpp->adapter_status || HD(j)->cp_stat[0] != FREE) {
@@ -424,11 +428,7 @@ static inline int port_detect(ushort *port_base, unsigned int j,
       sprintf(BN(j), "U34F%d", j);
       }
    else {
-
-#if !defined(MODULE)
-      /* The module code does not checkin/checkout in the blocking list yet */
       sh[j]->block = sh[j];
-#endif
 
 #if defined (HAVE_OLD_U14F_FIRMWARE)
       sh[j]->hostt->use_clustering = DISABLE_CLUSTERING;
@@ -491,6 +491,9 @@ int u14_34f_detect (Scsi_Host_Template * tpnt) {
       port_base++;
       }
 
+   if (j > 0) 
+      printk("UltraStor 14F/34F: Copyright (C) 1994, 1995 Dario Ballabio.\n");
+
    restore_flags(flags);
    return j;
 }
@@ -691,6 +694,8 @@ int u14_34f_reset(Scsi_Cmnd * SCarg) {
 
    for (k = 0; k < MAX_TARGET; k++) HD(j)->target_reset[k] = TRUE;
 
+   for (k = 0; k < MAX_TARGET; k++) HD(j)->target_time_out[k] = 0;
+
    for (i = 0; i < sh[j]->can_queue; i++) {
 
       if (HD(j)->cp_stat[i] == FREE) continue;
@@ -733,7 +738,7 @@ int u14_34f_reset(Scsi_Cmnd * SCarg) {
    HD(j)->in_reset = TRUE;
    sti();
    time = jiffies;
-   while (jiffies < (time + 200) && limit++ < 100000000) sti();
+   while (jiffies < (time + 100) && limit++ < 100000000);
    cli();
    printk("%s: reset, interrupts disabled, loops %d.\n", BN(j), limit);
 
@@ -879,8 +884,7 @@ static void u14_34f_interrupt_handler(int irq, struct pt_regs * regs) {
                   status = DID_BUS_BUSY << 16;
 
                else if (tstatus == CHECK_CONDITION
-                        && (SCpnt->device->type == TYPE_DISK
-                         || SCpnt->device->type == TYPE_ROM)
+                        && SCpnt->device->type == TYPE_DISK
                         && (SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION)
                   status = DID_ERROR << 16;
    
@@ -890,8 +894,7 @@ static void u14_34f_interrupt_handler(int irq, struct pt_regs * regs) {
                if (tstatus == GOOD)
                   HD(j)->target_reset[SCpnt->target] = FALSE;
 
-               if (spp->target_status && (SCpnt->device->type == TYPE_DISK
-                                       || SCpnt->device->type == TYPE_ROM))
+               if (spp->target_status && SCpnt->device->type == TYPE_DISK)
                   printk("%s: ihdlr, target %d:%d, pid %ld, target_status "\
                          "0x%x, sense key 0x%x.\n", BN(j), 
                          SCpnt->target, SCpnt->lun, SCpnt->pid,
index 041d1f81f6bdc61fde8f8c4bd2b3a794908d825b..1080869dcbe6398bbfef0efd74513da4ae0b49a5 100644 (file)
@@ -10,15 +10,14 @@ int u14_34f_abort(Scsi_Cmnd *);
 int u14_34f_reset(Scsi_Cmnd *);
 int u14_34f_biosparam(Disk *, int, int *);
 
-#define U14_34F_VERSION "1.14.05"
+#define U14_34F_VERSION "1.15.00"
 
 #define ULTRASTOR_14_34F {                                            \
-                NULL,                                                 \
-                NULL,                                                 \
-                "UltraStor 14F/34F rev. " U14_34F_VERSION " by "      \
-                "Dario_Ballabio@milano.europe.dg.com.",               \
+                NULL, /* Ptr for modules */                           \
+                NULL, /* usage count for modules */                  \
+                "UltraStor 14F/34F rev. " U14_34F_VERSION " ",        \
                 u14_34f_detect,                                       \
-                NULL,                                                 \
+                NULL, /* Release */                                   \
                 NULL,                                                \
                 NULL,                                                 \
                 u14_34f_queuecommand,                                 \
index 60d18cbe8327ef06ecec5eb9209537116f9d12fe..37f45380030b79e2874f83a717c8d2e2a7b063d0 100644 (file)
@@ -74,7 +74,13 @@ Hannu Savolainen
 hannu@voxware.pp.fi
 
 Snail mail:    Hannu Savolainen
-               Pallaksentie 4 A 2
-               00970 Helsinki
+               Hiekkalaiturintie 3 A 8
+               00980 Helsinki
                Finland
-FAX:           +358 0 395 1968 (usually not connected)
+FAX:           +358 0 341 6272 (answers if I have my machine (mgetty) on).
+
+NOTE!  I propably don't answer to Snail mail or FAX messages. Sending answer
+       to each of them is simply too expensive and time consuming. However I
+       try to reply every email message I get (within a week). If you don't
+       get response, please check how your address is written in the message
+       header. I can't answer if I don't have a valid reply address.
index d0dfa718d0e7658c60931d58f6919e9ea4d89c63..d7376ccddf499d09106c7abe60872d2c65bfcf34 100644 (file)
@@ -145,6 +145,43 @@ static int parse_options(char *options, struct iso9660_options * popt)
        return 1;
 }
 
+
+static unsigned int isofs_get_last_session(int dev)
+{
+  struct cdrom_multisession ms_info;
+  unsigned int vol_desc_start;
+  struct inode inode_fake;
+  extern struct file_operations * get_blkfops(unsigned int);
+  int i;
+
+  /*
+   * look if the driver can tell the multi session redirection value
+   * <emoenke@gwdg.de>
+   */
+  vol_desc_start=0;
+  if (get_blkfops(MAJOR(dev))->ioctl!=NULL)
+    {
+      inode_fake.i_rdev=dev;
+      ms_info.addr_format=CDROM_LBA;
+      set_fs(KERNEL_DS);
+      i=get_blkfops(MAJOR(dev))->ioctl(&inode_fake,
+                                      NULL,
+                                      CDROMMULTISESSION,
+                                      (unsigned long) &ms_info);
+      set_fs(USER_DS);
+#if 0 
+      printk("isofs.inode: CDROMMULTISESSION: rc=%d\n",i);
+      if (i==0)
+       {
+         printk("isofs.inode: XA disk: %s\n", ms_info.xa_flag ? "yes":"no");
+         printk("isofs.inode: vol_desc_start = %d\n", ms_info.addr.lba);
+       }
+#endif 0
+      if ((i==0)&&(ms_info.xa_flag)) vol_desc_start=ms_info.addr.lba;
+    }
+  return vol_desc_start;
+}
+
 struct super_block *isofs_read_super(struct super_block *s,void *data,
                                     int silent)
 {
@@ -153,11 +190,8 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
        unsigned int blocksize_bits;
        int high_sierra;
        int dev=s->s_dev;
-       int i;
-       struct cdrom_multisession ms_info;
        unsigned int vol_desc_start;
-       struct inode inode_fake;
-       extern struct file_operations * get_blkfops(unsigned int);
+
        struct iso_volume_descriptor *vdp;
        struct hs_volume_descriptor *hdp;
 
@@ -200,34 +234,11 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
 
        s->u.isofs_sb.s_high_sierra = high_sierra = 0; /* default is iso9660 */
 
-       /*
-        * look if the driver can tell the multi session redirection value
-        * <emoenke@gwdg.de>
-        */
-       vol_desc_start=0;
-       if (get_blkfops(MAJOR(dev))->ioctl!=NULL)
-         {
-           inode_fake.i_rdev=dev;
-           ms_info.addr_format=CDROM_LBA;
-           set_fs(KERNEL_DS);
-           i=get_blkfops(MAJOR(dev))->ioctl(&inode_fake,
-                                            NULL,
-                                            CDROMMULTISESSION,
-                                            (unsigned long) &ms_info);
-           set_fs(USER_DS);
-#if 0
-           printk("isofs.inode: CDROMMULTISESSION: rc=%d\n",i);
-           if (i==0)
-             {
-               printk("isofs.inode: XA disk: %s\n", ms_info.xa_flag ? "yes":"no");
-               printk("isofs.inode: vol_desc_start = %d\n", ms_info.addr.lba);
-             }
-#endif 0
-           if ((i==0)&&(ms_info.xa_flag)) vol_desc_start=ms_info.addr.lba;
-         }
+       vol_desc_start = isofs_get_last_session(dev);
+       
        for (iso_blknum = vol_desc_start+16; iso_blknum < vol_desc_start+100; iso_blknum++) {
 #if 0
-       printk("isofs.inode: iso_blknum=%d\n", iso_blknum);
+               printk("isofs.inode: iso_blknum=%d\n", iso_blknum);
 #endif 0
                if (!(bh = bread(dev, iso_blknum << (ISOFS_BLOCK_BITS-blocksize_bits), opt.blocksize))) {
                        s->s_dev=0;
index 45e027cbb7f1d7b1ad8ea7c05ea2df1f3ade99c6..ea81f55afa8f5e9f69b82c9416967e521555a8f2 100644 (file)
@@ -37,9 +37,6 @@
  * ***FIXME*** should probably put this in nfs_fs.h */
 #define NFS_SLACK_SPACE 1024
 
-
-extern struct socket *socki_lookup(struct inode *inode);
-
 #define _S(nr) (1<<((nr)-1))
 
 /*
@@ -81,7 +78,7 @@ static int do_nfs_rpc_call(struct nfs_server *server, int *start, int *end, int
        file = server->file;
        inode = file->f_inode;
        select = file->f_op->select;
-       sock = socki_lookup(inode);
+       sock = &inode->u.socket_i;
        if (!sock) {
                printk("nfs_rpc_call: socki_lookup failed\n");
                return -EBADF;
index f0382690dcc36089057162bc9721572e608ea4b1..2d40c0d9b9ac0434d9ff47c187a4aa2b9cd59960 100644 (file)
@@ -94,7 +94,7 @@ static void check_fpu(void)
                return;
 
        }
-       printk("Ok, FDIV bug i%c86 system\n", '0'+x86);
+       printk("Hmm, FDIV bug i%c86 system\n", '0'+x86);
 }
 
 static void check_hlt(void)
index 20fbbf531c3841aa560f063ec0c4c594a9271fc6..439c7c67124a53db90da8d29c9e984bdf8102efc 100644 (file)
@@ -1,7 +1,7 @@
 /* cprefix.h:  This file is included by assembly source which needs
  *             to know what the c-label prefixes are. The newer versions
  *            of cpp that come with gcc predefine such things to help
- *            us out. The reason this stuff is neaded is to make
+ *            us out. The reason this stuff is needed is to make
  *            solaris compiles of the kernel work.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
index 2b2c84f6287c6ea906796a5c2253c47f7f637eee..c15903a81ba328e04b02133dd949e272dba10d88 100644 (file)
@@ -226,8 +226,10 @@ struct pci_class_type {
 #define PCI_DEVICE_ID_DEC_TULIP                0x0002
 #define PCI_DEVICE_ID_DEC_TULIP_FAST   0x0009
 #define PCI_DEVICE_ID_DEC_FDDI         0x000F
+#define PCI_DEVICE_ID_DEC_BRD          0x0001
 
 #define PCI_VENDOR_ID_MATROX           0x102B
+#define PCI_DEVICE_ID_MATROX_2plus     0x0518
 
 #define PCI_VENDOR_ID_INTEL            0x8086
 #define PCI_DEVICE_ID_INTEL_82378      0x0484
@@ -262,13 +264,13 @@ struct pci_class_type {
 #define PCI_DEVICE_ID_AI_M1435         0x1435
 
 #define PCI_VENDOR_ID_AL               0x10b9
-#define PCI_DEVICE_ID_AL_M1449         0x4449
+#define PCI_DEVICE_ID_AL_M1449         0x1449
 #define PCI_DEVICE_ID_AL_M1451         0x1451
 
 #define PCI_VENDOR_ID_TSENG            0x100c
 #define PCI_DEVICE_ID_TSENG_W32P_2     0x3202
 #define PCI_DEVICE_ID_TSENG_W32P_b     0x3205
-#define PCI_DEVICE_ID_TSENG_W32P_a     0x3207
+#define PCI_DEVICE_ID_TSENG_W32P_c     0x3207
 
 #define PCI_VENDOR_ID_CMD              0x1095
 #define PCI_DEVICE_ID_CMD_640          0x0640
@@ -290,6 +292,7 @@ struct pci_class_type {
 
 #define PCI_VENDOR_ID_TRIDENT          0x1023
 #define PCI_DEVICE_ID_TRIDENT_9420     0x9420
+#define PCI_DEVICE_ID_TRIDENT_9440     0x9440
 
 #define PCI_VENDOR_ID_CONTAQ           0x1080
 #define PCI_DEVICE_ID_CONTAQ_82C599    0x0600
@@ -300,19 +303,30 @@ struct pci_class_type {
 #define PCI_DEVICE_ID_VIA_82C505       0x0505
 
 #define PCI_VENDOR_ID_SI               0x1039
-#define PCI_DEVICE_ID_SI_MG1936                0x0406
-#define PCI_DEVICE_ID_SI_MG1938                0x0008
+#define PCI_DEVICE_ID_SI_496           0x0496
+#define PCI_DEVICE_ID_SI_501           0x0406
+#define PCI_DEVICE_ID_SI_503           0x0008
 
 #define PCI_VENDOR_ID_LEADTEK          0x107d
 #define PCI_DEVICE_ID_LEADTEK_805      0x0000
 
+#define PCI_VENDOR_ID_IMS              0x10e0
+#define PCI_DEVICE_ID_IMS_8849         0x8849
+
+#define PCI_VENDOR_ID_ZEINET           0x1193
+#define PCI_DEVICE_ID_ZEINET_1221      0x0001
+
+#define PCI_VENDOR_ID_EF               0x111a
+#define PCI_DEVICE_ID_EF_ATM           0x0000
+
+
 struct pci_vendor_type {
        unsigned short vendor_id;
        char *vendor_name;
 };
 
 
-#define PCI_VENDOR_NUM 30
+#define PCI_VENDOR_NUM 33
 #define PCI_VENDOR_TYPE { \
        {PCI_VENDOR_ID_NCR,             "NCR"}, \
        {PCI_VENDOR_ID_ADAPTEC,         "Adaptec"}, \
@@ -343,7 +357,10 @@ struct pci_vendor_type {
        {PCI_VENDOR_ID_NS,              "NS"}, \
        {PCI_VENDOR_ID_VIA,             "VIA Technologies"}, \
        {PCI_VENDOR_ID_SI,              "Silicon Integrated"}, \
-       {PCI_VENDOR_ID_LEADTEK,         "Leadtek Research"} \
+       {PCI_VENDOR_ID_LEADTEK,         "Leadtek Research"}, \
+       {PCI_VENDOR_ID_IMS,             "IMS"}, \
+       {PCI_VENDOR_ID_ZEINET,          "ZeiNet"}, \
+       {PCI_VENDOR_ID_EF,              "Efficient Networks"} \
 }
 
 
@@ -362,7 +379,7 @@ struct pci_device_type {
        char *device_name;
 };
 
-#define PCI_DEVICE_NUM 54
+#define PCI_DEVICE_NUM 61
 #define PCI_DEVICE_TYPE { \
        {0xff,  PCI_VENDOR_ID_NCR,      PCI_DEVICE_ID_NCR_53C810,       "53c810"}, \
        {0xff,  PCI_VENDOR_ID_NCR,      PCI_DEVICE_ID_NCR_53C815,       "53c815"}, \
@@ -385,6 +402,8 @@ struct pci_device_type {
        {0xff,  PCI_VENDOR_ID_DEC,      PCI_DEVICE_ID_DEC_TULIP,        "DC21040"}, \
        {0xff,  PCI_VENDOR_ID_DEC,      PCI_DEVICE_ID_DEC_TULIP_FAST,   "DC21040"}, \
        {0xff,  PCI_VENDOR_ID_DEC,      PCI_DEVICE_ID_DEC_FDDI,         "DEFPA"}, \
+       {0xff,  PCI_VENDOR_ID_DEC,      PCI_DEVICE_ID_DEC_BRD,          "DC21050"}, \
+       {0xff,  PCI_VENDOR_ID_MATROX,   PCI_DEVICE_ID_MATROX_2plus,     "MGA/2+"}, \
        {0xff,  PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82378,      "82378IB"}, \
        {0x00,  PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82424,      "82424ZX Saturn"}, \
        {0xff,  PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82375,      "82375EB"}, \
@@ -405,7 +424,7 @@ struct pci_device_type {
        {0xff,  PCI_VENDOR_ID_AL,       PCI_DEVICE_ID_AL_M1451,         "M1451"}, \
        {0xff,  PCI_VENDOR_ID_TSENG,    PCI_DEVICE_ID_TSENG_W32P_2,     "ET4000W32P"}, \
        {0xff,  PCI_VENDOR_ID_TSENG,    PCI_DEVICE_ID_TSENG_W32P_b,     "ET4000W32P rev B"}, \
-       {0xff,  PCI_VENDOR_ID_TSENG,    PCI_DEVICE_ID_TSENG_W32P_a,     "ET4000W32P rev A"}, \
+       {0xff,  PCI_VENDOR_ID_TSENG,    PCI_DEVICE_ID_TSENG_W32P_c,     "ET4000W32P rev C"}, \
        {0xff,  PCI_VENDOR_ID_CMD,      PCI_DEVICE_ID_CMD_640,          "640A"}, \
        {0xff,  PCI_VENDOR_ID_VISION,   PCI_DEVICE_ID_VISION_QD8500,    "QD-8500PCI"}, \
        {0xff,  PCI_VENDOR_ID_AMD,      PCI_DEVICE_ID_AMD_LANCE,        "79C970"}, \
@@ -413,11 +432,16 @@ struct pci_device_type {
        {0xff,  PCI_VENDOR_ID_ADL,      PCI_DEVICE_ID_ADL_2301,         "2301"}, \
        {0xff,  PCI_VENDOR_ID_SYMPHONY, PCI_DEVICE_ID_SYMPHONY_101,     "82C101"}, \
        {0xff,  PCI_VENDOR_ID_TRIDENT,  PCI_DEVICE_ID_TRIDENT_9420,     "TG 9420"}, \
+       {0xff,  PCI_VENDOR_ID_TRIDENT,  PCI_DEVICE_ID_TRIDENT_9440,     "TG 9440"}, \
        {0xff,  PCI_VENDOR_ID_CONTAQ,   PCI_DEVICE_ID_CONTAQ_82C599,    "82C599"}, \
        {0xff,  PCI_VENDOR_ID_VIA,      PCI_DEVICE_ID_VIA_82C505,       "VT 82C505"}, \
-       {0xff,  PCI_VENDOR_ID_SI,       PCI_DEVICE_ID_SI_MG1936,        "MG1936 ??"}, \
-       {0xff,  PCI_VENDOR_ID_SI,       PCI_DEVICE_ID_SI_MG1938,        "MG1938 ??"}, \
-       {0xff,  PCI_VENDOR_ID_LEADTEK,  PCI_DEVICE_ID_LEADTEK_805,      "S3 805"} \
+       {0xff,  PCI_VENDOR_ID_SI,       PCI_DEVICE_ID_SI_496,           "85C496"}, \
+       {0xff,  PCI_VENDOR_ID_SI,       PCI_DEVICE_ID_SI_501,           "85C501"}, \
+       {0xff,  PCI_VENDOR_ID_SI,       PCI_DEVICE_ID_SI_503,           "85C503"}, \
+       {0xff,  PCI_VENDOR_ID_LEADTEK,  PCI_DEVICE_ID_LEADTEK_805,      "S3 805"}, \
+       {0xff,  PCI_VENDOR_ID_IMS,      PCI_DEVICE_ID_IMS_8849,         "8849"}, \
+       {0xff,  PCI_VENDOR_ID_ZEINET,   PCI_DEVICE_ID_ZEINET_1221,      "1221"}, \
+       {0xff,  PCI_VENDOR_ID_EF,       PCI_DEVICE_ID_EF_ATM,           "155P-MF1"} \
 }
 
 /* An item of this structure has the following meaning */
index ab0185d91002e8445c7a2ab06903aee7b799387b..aff70148b9432582cbdece27a90e5c80426c3b77 100644 (file)
@@ -22,18 +22,9 @@ struct serial_struct {
        unsigned short  close_delay;
        char    reserved_char[2];
        int     hub6;
-       unsigned short  closing_wait; /* time to wait before rcvr shutdown */
-       unsigned short  closing_wait2; /* time to wait after rcvr shutdown */
-       int     reserved[4];
+       int     reserved[5];
 };
 
-/*
- * For the close wait times, 0 means wait forever for serial port to
- * flush its output.  65535 means don't wait at all.
- */
-#define ASYNC_CLOSING_WAIT_INF 0
-#define ASYNC_CLOSING_WAIT_NONE        65535
-
 /*
  * These are the supported serial types.
  */
@@ -42,9 +33,8 @@ struct serial_struct {
 #define PORT_16450     2
 #define PORT_16550     3
 #define PORT_16550A    4
-#define PORT_CIRRUS     5      /* Hey!  Who put this there? */
-#define PORT_16650     6
-#define PORT_MAX       6
+#define PORT_CIRRUS     5
+#define PORT_MAX       5
 
 /*
  * Definitions for async_struct (and serial_struct) flags field
@@ -106,8 +96,6 @@ struct async_struct {
        int                     custom_divisor;
        int                     x_char; /* xon/xoff character */
        int                     close_delay;
-       unsigned short          closing_wait;
-       unsigned short          closing_wait2;
        int                     IER;    /* Interrupt Enable Register */
        int                     MCR;    /* Modem control register */
        int                     MCR_noint; /* MCR with interrupts off */
index 19d7c0ba7a74e5635ed2f2798a71151b55af93ee..5e983fc1c3c63ddfe01fbba0b510c06e031e356d 100644 (file)
@@ -21,8 +21,6 @@
 #define UART_IER       1       /* Out: Interrupt Enable Register */
 #define UART_IIR       2       /* In:  Interrupt ID Register */
 #define UART_FCR       2       /* Out: FIFO Control Register */
-#define UART_EFR       2       /* I/O: Extended Features Register */
-                               /* (DLAB=1, 16C660 only) */
 #define UART_LCR       3       /* Out: Line Control Register */
 #define UART_MCR       4       /* Out: Modem Control Register */
 #define UART_LSR       5       /* In:  Line Status Register */
@@ -31,7 +29,6 @@
 
 /*
  * These are the definitions for the FIFO Control Register
- * (16650 only)
  */
 #define UART_FCR_ENABLE_FIFO   0x01 /* Enable the FIFO */
 #define UART_FCR_CLEAR_RCVR    0x02 /* Clear the RCVR FIFO */
 #define UART_FCR_TRIGGER_4     0x40 /* Mask for trigger set at 4 */
 #define UART_FCR_TRIGGER_8     0x80 /* Mask for trigger set at 8 */
 #define UART_FCR_TRIGGER_14    0xC0 /* Mask for trigger set at 14 */
-/* 16650 redefinitions */
-#define UART_FCR6_R_TRIGGER_8  0x00 /* Mask for receive trigger set at 1 */
-#define UART_FCR6_R_TRIGGER_16 0x40 /* Mask for receive trigger set at 4 */
-#define UART_FCR6_R_TRIGGER_24  0x80 /* Mask for receive trigger set at 8 */
-#define UART_FCR6_R_TRIGGER_28 0xC0 /* Mask for receive trigger set at 14 */
-#define UART_FCR6_T_TRIGGER_16 0x00 /* Mask for transmit trigger set at 16 */
-#define UART_FCR6_T_TRIGGER_8  0x10 /* Mask for transmit trigger set at 8 */
-#define UART_FCR6_T_TRIGGER_24  0x20 /* Mask for transmit trigger set at 24 */
-#define UART_FCR6_T_TRIGGER_30 0x30 /* Mask for transmit trigger set at 30 */
 
 /*
  * These are the definitions for the Line Control Register
 #define UART_MSR_DCTS  0x01    /* Delta CTS */
 #define UART_MSR_ANY_DELTA 0x0F        /* Any of the delta bits! */
 
-/*
- * These are the definitions for the Extended Features Register
- * (StarTech 16C660 only, when DLAB=1)
- */
-#define UART_EFR_CTS   0x80    /* CTS flow control */
-#define UART_EFR_RTS   0x40    /* RTS flow control */
-#define UART_EFR_SCD   0x20    /* Special character detect */
-#define UART_EFR_ENI   0x10    /* Enhanced Interrupt */
-/*
- * the low four bits control software flow control
- */
-
 #endif /* _LINUX_SERIAL_REG_H */
 
index 4c24bb5906f4259b8b89da7eca6181f38f116250..5dec5968383275f1fc2c904b0c6fb571af5df834 100644 (file)
@@ -283,7 +283,7 @@ extern int tty_paranoia_check(struct tty_struct *tty, dev_t device,
                              const char *routine);
 extern char *_tty_name(struct tty_struct *tty, char *buf);
 extern char *tty_name(struct tty_struct *tty);
-extern void wait_until_sent(struct tty_struct * tty, int timeout);
+extern void tty_wait_until_sent(struct tty_struct * tty, int timeout);
 extern int tty_check_change(struct tty_struct * tty);
 extern void stop_tty(struct tty_struct * tty);
 extern void start_tty(struct tty_struct * tty);
index fa3700824509f3fb96065a15177671df47dc3f30..6dbe8e4fe243f0bbceafc72f99d5cdcb5c0232d5 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -9,7 +9,7 @@
  * wake up processes that were waiting for semval to go to 0 if the
  * value went to 0 and was then incremented rapidly enough. In solving
  * this problem I have also modified the implementation so that it
- * processes pending operations in a FIFO manner, thus give a guarentee
+ * processes pending operations in a FIFO manner, thus give a guarantee
  * that processes waiting for a lock on the semaphore won't starve
  * unless another locking process fails to unlock.
  * In addition the following two changes in behavior have been introduced:
@@ -20,7 +20,7 @@
  *   have read permissions. The implementation now returns 0
  *   on success as stated in the manual page.
  * - There is some confusion over whether the set of undo adjustments
- *   to be peformed at exit should be done in an atomic manner.
+ *   to be performed at exit should be done in an atomic manner.
  *   That is, if we are attempting to decrement the semval should we queue
  *   up and wait until we can do so legally?
  *   The original implementation attempted to do this.
index a01a982b8c2ceab42d2c2b0c499da09664c89f2c..1c2604503f776ef2721b43106e8b4c3c9daedba3 100644 (file)
@@ -173,6 +173,12 @@ struct symbol_table symbol_table = {
        X(register_serial),
        X(unregister_serial),
 
+       /* tty routines */
+       X(tty_hangup),
+       X(tty_wait_until_sent),
+       X(tty_check_change),
+       X(tty_hung_up_p),
+
        /* filesystem registration */
        X(register_filesystem),
        X(unregister_filesystem),
index 5329d32ba15286ccb288307ccb2a9b8db87b94dc..eaada2d15c6b57484189e3683fd76b24355b1d15 100644 (file)
@@ -268,116 +268,149 @@ int copy_page_tables(struct task_struct * tsk)
        return 0;
 }
 
+static inline void forget_pte(pte_t page)
+{
+       if (pte_none(page))
+               return;
+       if (pte_present(page)) {
+               free_page(pte_page(page));
+               if (mem_map[MAP_NR(pte_page(page))] & MAP_PAGE_RESERVED)
+                       return;
+               if (current->mm->rss <= 0)
+                       return;
+               current->mm->rss--;
+               return;
+       }
+       swap_free(pte_val(page));
+}
+
+static inline void unmap_pte_range(pmd_t * pmd, unsigned long address, unsigned long size)
+{
+       pte_t * pte;
+       unsigned long end;
+
+       if (pmd_none(*pmd))
+               return;
+       if (pmd_bad(*pmd)) {
+               printk("unmap_pte_range: bad pmd (%08lx)\n", pmd_val(*pmd));
+               pmd_clear(pmd);
+               return;
+       }
+       pte = pte_offset(pmd, address);
+       address &= ~PMD_MASK;
+       end = address + size;
+       if (end >= PMD_SIZE)
+               end = PMD_SIZE;
+       do {
+               pte_t page = *pte;
+               pte_clear(pte);
+               forget_pte(page);
+               address += PAGE_SIZE;
+               pte++;
+       } while (address < end);
+}
+
+static inline void unmap_pmd_range(pgd_t * dir, unsigned long address, unsigned long size)
+{
+       pmd_t * pmd;
+       unsigned long end;
+
+       if (pgd_none(*dir))
+               return;
+       if (pgd_bad(*dir)) {
+               printk("unmap_pmd_range: bad pgd (%08lx)\n", pgd_val(*dir));
+               pgd_clear(dir);
+               return;
+       }
+       pmd = pmd_offset(dir, address);
+       address &= ~PGDIR_MASK;
+       end = address + size;
+       if (end > PGDIR_SIZE)
+               end = PGDIR_SIZE;
+       do {
+               unmap_pte_range(pmd, address, end - address);
+               address = (address + PMD_SIZE) & PMD_MASK; 
+               pmd++;
+       } while (address < end);
+}
+
 /*
  * a more complete version of free_page_tables which performs with page
  * granularity.
  */
-int unmap_page_range(unsigned long from, unsigned long size)
+int unmap_page_range(unsigned long address, unsigned long size)
 {
-       pgd_t page_dir, * dir;
-       pte_t page, * page_table;
-       unsigned long poff, pcnt, pc;
-
-       if (from & ~PAGE_MASK) {
-               printk("unmap_page_range called with wrong alignment\n");
-               return -EINVAL;
-       }
-       size = (size + ~PAGE_MASK) >> PAGE_SHIFT;
-       dir = PAGE_DIR_OFFSET(current,from);
-       poff = (from >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
-       if ((pcnt = PTRS_PER_PAGE - poff) > size)
-               pcnt = size;
+       pgd_t * dir;
+       unsigned long end = address + size;
 
-       for ( ; size > 0; ++dir, size -= pcnt,
-            pcnt = (size > PTRS_PER_PAGE ? PTRS_PER_PAGE : size)) {
-               page_dir = *dir;
-               if (pgd_none(page_dir)) {
-                       poff = 0;
-                       continue;
-               }
-               if (pgd_bad(page_dir)) {
-                       printk("unmap_page_range: bad page directory.");
-                       continue;
-               }
-               page_table = (pte_t *) pgd_page(page_dir);
-               if (poff) {
-                       page_table += poff;
-                       poff = 0;
-               }
-               for (pc = pcnt; pc--; page_table++) {
-                       page = *page_table;
-                       if (!pte_none(page)) {
-                               pte_clear(page_table);
-                               if (pte_present(page)) {
-                                       if (!(mem_map[MAP_NR(pte_page(page))] & MAP_PAGE_RESERVED))
-                                               if (current->mm->rss > 0)
-                                                       --current->mm->rss;
-                                       free_page(pte_page(page));
-                               } else
-                                       swap_free(pte_val(page));
-                       }
-               }
-               if (pcnt == PTRS_PER_PAGE) {
-                       pgd_clear(dir);
-                       free_page(pgd_page(page_dir));
-               }
+       dir = pgd_offset(current, address);
+       while (address < end) {
+               unmap_pmd_range(dir, address, end - address);
+               address = (address + PGDIR_SIZE) & PGDIR_MASK;
+               dir++;
        }
        invalidate();
        return 0;
 }
 
-int zeromap_page_range(unsigned long from, unsigned long size, pgprot_t prot)
+static inline void zeromap_pte_range(pte_t * pte, unsigned long address, unsigned long size, pte_t zero_pte)
+{
+       unsigned long end;
+
+       address &= ~PMD_MASK;
+       end = address + size;
+       if (end > PMD_SIZE)
+               end = PMD_SIZE;
+       do {
+               pte_t oldpage = *pte;
+               *pte = zero_pte;
+               forget_pte(oldpage);
+               address += PAGE_SIZE;
+               pte++;
+       } while (address < end);
+}
+
+static inline int zeromap_pmd_range(pmd_t * pmd, unsigned long address, unsigned long size, pte_t zero_pte)
 {
+       unsigned long end;
+
+       address &= ~PGDIR_MASK;
+       end = address + size;
+       if (end > PGDIR_SIZE)
+               end = PGDIR_SIZE;
+       do {
+               pte_t * pte = pte_alloc(pmd, address);
+               if (!pte)
+                       return -ENOMEM;
+               zeromap_pte_range(pte, address, end - address, zero_pte);
+               address = (address + PMD_SIZE) & PMD_MASK;
+               pmd++;
+       } while (address < end);
+       return 0;
+}
+
+int zeromap_page_range(unsigned long address, unsigned long size, pgprot_t prot)
+{
+       int error = 0;
        pgd_t * dir;
-       pte_t * page_table;
-       unsigned long poff, pcnt;
+       unsigned long end = address + size;
        pte_t zero_pte;
 
-       if (from & ~PAGE_MASK) {
-               printk("zeromap_page_range: from = %08lx\n",from);
-               return -EINVAL;
-       }
        zero_pte = pte_wrprotect(mk_pte(ZERO_PAGE, prot));
-       dir = PAGE_DIR_OFFSET(current,from);
-       size = (size + ~PAGE_MASK) >> PAGE_SHIFT;
-       poff = (from >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
-       if ((pcnt = PTRS_PER_PAGE - poff) > size)
-               pcnt = size;
-
-       while (size > 0) {
-               if (!pgd_present(*dir)) {
-                       if (!(page_table = (pte_t *) get_free_page(GFP_KERNEL))) {
-                               invalidate();
-                               return -ENOMEM;
-                       }
-                       if (pgd_present(*dir)) {
-                               free_page((unsigned long) page_table);
-                               page_table = (pte_t *) pgd_page(*dir);
-                       } else
-                               pgd_set(dir, page_table);
-               } else
-                       page_table = (pte_t *) pgd_page(*dir);
+       dir = pgd_offset(current, address);
+       while (address < end) {
+               pmd_t *pmd = pmd_alloc(dir, address);
+               error = -ENOMEM;
+               if (!pmd)
+                       break;
+               error = zeromap_pmd_range(pmd, address, end - address, zero_pte);
+               if (error)
+                       break;
+               address = (address + PGDIR_SIZE) & PGDIR_MASK;
                dir++;
-               page_table += poff;
-               poff = 0;
-               for (size -= pcnt; pcnt-- ;) {
-                       pte_t page = *page_table;
-                       if (!pte_none(page)) {
-                               pte_clear(page_table);
-                               if (pte_present(page)) {
-                                       if (!(mem_map[MAP_NR(pte_page(page))] & MAP_PAGE_RESERVED))
-                                               if (current->mm->rss > 0)
-                                                       --current->mm->rss;
-                                       free_page(pte_page(page));
-                               } else
-                                       swap_free(pte_val(page));
-                       }
-                       *page_table++ = zero_pte;
-               }
-               pcnt = (size > PTRS_PER_PAGE ? PTRS_PER_PAGE : size);
        }
        invalidate();
-       return 0;
+       return error;
 }
 
 /*
index c9d9f0da992c5bc2333521a65eadbcf55821d277..5ce7f88d75779eab66aebf0a7eb87616e675e6fa 100644 (file)
@@ -372,11 +372,14 @@ static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb,
                         *      Add better route to host.
                         *      But first check that the redirect
                         *      comes from the old gateway..
+                        *      And make sure it's an ok host address
+                        *      (not some confused thing sending our
+                        *      address)
                         */
                        rt = ip_rt_route(ip, NULL, NULL);
                        if (!rt)
                                break;
-                       if (rt->rt_gateway != source)
+                       if (rt->rt_gateway != source || ip_chk_addr(icmph->un.gateway))
                                break;
                        printk("redirect from %s\n", in_ntoa(source));
                        ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_HOST | RTF_GATEWAY),
index fbbdb6da7e438e0a69bab10600a520eab5066585..aa7526ab31fc3259052f97fe4e46037eb72c5a69 100644 (file)
@@ -424,7 +424,7 @@ addr_match:
 } /* End of whole function */
 #endif /* CONFIG_IP_ACCT */
 
-#ifdef CONFIG_IP_ACCT
+#if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL)
 
 static void zero_fw_chain(struct ip_fw *chainptr)
 {
@@ -437,10 +437,6 @@ static void zero_fw_chain(struct ip_fw *chainptr)
        }
 }
 
-#endif
-
-#if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL)
-
 static void free_fw_chain(struct ip_fw *volatile* chainptr)
 {
        unsigned long flags;
index 4ae85af0a25670996f5f78bccf4ac4eaa206d78a..c60cdd22dc57cf571d2d8d27fed665f9186710e5 100644 (file)
@@ -371,7 +371,9 @@ static void tcp_close_pending (struct sock *sk)
 {
        struct sk_buff *skb;
 
-       while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
+       while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) 
+       {
+               skb->sk->dead=1;
                tcp_close(skb->sk, 0);
                kfree_skb(skb, FREE_READ);
        }
@@ -607,10 +609,11 @@ static int tcp_write_timeout(struct sock *sk)
        {
                sk->err = ETIMEDOUT;
                sk->error_report(sk);
+               del_timer(&sk->retransmit_timer);
                /*
                 *      Time wait the socket 
                 */
-               if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2 || sk->state == TCP_CLOSING) 
+               if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2 || sk->state == TCP_CLOSING 
                {
                        tcp_set_state(sk,TCP_TIME_WAIT);
                        reset_msl_timer (sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
@@ -2850,6 +2853,8 @@ static void tcp_conn_request(struct sock *sk, struct sk_buff *skb,
        {
                sk->err = -ENOMEM;
                newsk->dead = 1;
+               newsk->state = TCP_CLOSE;
+               /* And this will destroy it */
                release_sock(newsk);
                kfree_skb(skb, FREE_READ);
                tcp_statistics.TcpAttemptFails++;
@@ -2879,6 +2884,7 @@ static void tcp_conn_request(struct sock *sk, struct sk_buff *skb,
                buff->free = 1;
                kfree_skb(buff,FREE_WRITE);
                newsk->dead = 1;
+               newsk->state = TCP_CLOSE;
                release_sock(newsk);
                skb->sk = sk;
                kfree_skb(skb, FREE_READ);
@@ -2917,8 +2923,6 @@ static void tcp_conn_request(struct sock *sk, struct sk_buff *skb,
 
        tcp_send_check(t1, daddr, saddr, sizeof(*t1)+4, newsk);
        newsk->prot->queue_xmit(newsk, ndev, buff, 0);
-       reset_xmit_timer(newsk, TIME_WRITE, newsk->rto);
-
        reset_xmit_timer(newsk, TIME_WRITE , TCP_TIMEOUT_INIT);
        skb->sk = newsk;