From cc6d9ed8117d257b4d3c77aa20e7476ab912d4ba Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:09:44 -0500 Subject: [PATCH] Import 1.1.66 --- Makefile | 2 +- arch/i386/config.in | 11 +- drivers/block/blk.h | 7 + drivers/block/cdu31a.c | 4 +- drivers/block/floppy.c | 900 ++++++++++++++++++++++--------------- drivers/block/hd.c | 47 +- drivers/block/ll_rw_blk.c | 7 +- drivers/char/console.c | 5 +- drivers/net/8390.h | 2 +- drivers/net/apricot.c | 16 +- drivers/net/ewrk3.c | 4 +- drivers/net/hp.c | 2 +- drivers/net/ne.c | 2 +- drivers/net/plip.c | 4 +- drivers/net/ppp.c | 4 +- drivers/net/sk_g16.c | 8 +- drivers/net/slip.c | 4 +- drivers/scsi/53c7,8xx.c | 2 +- drivers/scsi/Makefile | 5 + drivers/scsi/NCR5380.c | 4 +- drivers/scsi/NCR5380.h | 2 +- drivers/scsi/README.qlogic | 65 +++ drivers/scsi/aha152x.c | 525 +++++++++++++--------- drivers/scsi/aha152x.h | 28 +- drivers/scsi/eata.c | 2 +- drivers/scsi/fdomain.c | 2 +- drivers/scsi/hosts.c | 7 + drivers/scsi/in2000.c | 678 ++++++++++++++++++++++++++++ drivers/scsi/in2000.h | 124 +++++ drivers/scsi/qlogic.c | 564 +++++++++++++++++++++++ drivers/scsi/qlogic.h | 37 ++ drivers/scsi/scsi.c | 11 +- drivers/scsi/scsi.h | 10 +- drivers/scsi/sr.c | 122 +++++ drivers/scsi/sr.h | 1 + drivers/scsi/u14-34f.c | 2 +- fs/isofs/file.c | 13 +- fs/super.c | 2 + ibcs/binfmt_coff.c | 2 +- include/asm-alpha/delay.h | 38 ++ include/linux/fd.h | 53 ++- include/linux/netdevice.h | 2 +- init/main.c | 118 +++-- kernel/ksyms.c | 15 + net/inet/af_inet.c | 11 +- net/inet/dev.c | 27 +- net/inet/devinet.c | 2 +- net/inet/ip.c | 2 +- net/inet/packet.c | 2 +- net/inet/route.c | 2 +- net/inet/sock.c | 19 +- net/inet/tcp.c | 100 ++++- 52 files changed, 2900 insertions(+), 728 deletions(-) create mode 100644 drivers/scsi/README.qlogic create mode 100644 drivers/scsi/in2000.c create mode 100644 drivers/scsi/in2000.h create mode 100644 drivers/scsi/qlogic.c create mode 100644 drivers/scsi/qlogic.h create mode 100644 include/asm-alpha/delay.h diff --git a/Makefile b/Makefile index 1adbf9b5b559..5b890719bf93 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 1 -SUBLEVEL = 65 +SUBLEVEL = 66 ARCH = i386 diff --git a/arch/i386/config.in b/arch/i386/config.in index e4020af0f98b..e0691e3ac1d3 100644 --- a/arch/i386/config.in +++ b/arch/i386/config.in @@ -6,6 +6,7 @@ comment 'General setup' bool 'Kernel math emulation' CONFIG_MATH_EMULATION n +bool 'Normal floppy disk support' CONFIG_BLK_DEV_FD y bool 'Normal harddisk support' CONFIG_BLK_DEV_HD y bool 'XT harddisk support' CONFIG_BLK_DEV_XD n bool 'Networking support' CONFIG_NET y @@ -57,8 +58,9 @@ bool 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F n bool 'Future Domain 16xx SCSI support' CONFIG_SCSI_FUTURE_DOMAIN n bool 'Generic NCR5380 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 n bool 'NCR53c7,8xx SCSI support' CONFIG_SCSI_NCR53C7xx n -#bool 'Always IN2000 SCSI support' CONFIG_SCSI_IN2000 n +bool 'Always IN2000 SCSI support' CONFIG_SCSI_IN2000 n bool 'PAS16 SCSI support' CONFIG_SCSI_PAS16 n +bool 'QLOGIC SCSI support' CONFIG_SCSI_QLOGIC n bool 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE n bool 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 n bool 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR n @@ -116,6 +118,7 @@ if [ "$CONFIG_NET_ISA" = "y" ]; then bool 'NI6510 support' CONFIG_NI65 n fi bool 'HP PCLAN support' CONFIG_HPLAN n + bool 'HP PCLAN PLUS support' CONFIG_HPLAN_PLUS n bool 'NE2000/NE1000 support' CONFIG_NE2000 y bool 'SK_G16 support' CONFIG_SK_G16 n fi @@ -163,7 +166,11 @@ bool '/proc filesystem support' CONFIG_PROC_FS y if [ "$CONFIG_INET" = "y" ]; then bool 'NFS filesystem support' CONFIG_NFS_FS y fi -bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS n +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 + bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS y +else + bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS n +fi bool 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS n bool 'System V and Coherent filesystem support' CONFIG_SYSV_FS n diff --git a/drivers/block/blk.h b/drivers/block/blk.h index 95a8fb2068d8..53d55b17d9be 100644 --- a/drivers/block/blk.h +++ b/drivers/block/blk.h @@ -45,6 +45,13 @@ extern unsigned long sbpcd_init(unsigned long, unsigned long); #endif CONFIG_SBPCD extern void set_device_ro(int dev,int flag); +extern void floppy_init(void); +#ifdef FD_MODULE +static +#else +extern +#endif +int new_floppy_init(void); extern void rd_load(void); extern long rd_init(long mem_start, int length); extern int ramdisk_size; diff --git a/drivers/block/cdu31a.c b/drivers/block/cdu31a.c index fd2794a84ee7..b7825abf9265 100644 --- a/drivers/block/cdu31a.c +++ b/drivers/block/cdu31a.c @@ -673,7 +673,7 @@ get_result(unsigned char *result_buffer, *result_size = 2; /* - * 0x20 means an error occured. Byte 2 will have the error code. + * 0x20 means an error occurred. Byte 2 will have the error code. * Otherwise, the command succeeded, byte 2 will have the count of * how many more status bytes are coming. * @@ -2781,7 +2781,7 @@ cdu31a_setup(char *strings, } else { - printk("CDU31A: Unknown interface type: %s\n", strings[3]); + printk("CDU31A: Unknown interface type: %s\n", strings); } } } diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index b5f6c91d0634..7dc0ba4e1ba1 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -4,34 +4,6 @@ * Copyright (C) 1991, 1992 Linus Torvalds * Copyright (C) 1993, 1994 Alain Knaff */ - -/* Configuration */ -/* The following does some extra sanity checks */ -#define SANITY - -/* the following is the mask of allowed drives. By default units 2 and - * 3 of both floppy controllers are disabled, because switching on the - * motor of these drives causes system hangs on some PCI computers. drive - * 0 is the low bit (0x1), and drive 7 is the high bit (0x80). Bits are on if - * a drive is allowed. */ - -#define ALLOWED_DRIVE_MASK 0x33 - - -/* Undefine the following if you have to floppy disk controllers: - * This works at least for me; if you get two controllers working, with - * drives attached to both, please mail me: Alain.Knaff@imag.fr */ -/* #define HAVE_2_CONTROLLERS */ - - -/* Define the following if you don't like that your drives seek audibly - * after a disk change (but it may not work correctly for everybody) - */ -/* #define SILENT_DC_CLEAR */ - - -/* End of configuration */ - /* * 02.12.91 - Changed to static variables to indicate need for reset * and recalibrate. This makes some things easier (output_byte reset @@ -109,13 +81,39 @@ * errors to allow safe writing by specialized programs. */ +#define CONFIG_FLOPPY_SANITY +#undef CONFIG_FLOPPY_23 +#undef CONFIG_FLOPPY_2_FDC +#undef CONFIG_FLOPPY_SILENT_DCL_CLEAR + #define REALLY_SLOW_IO -#define FLOPPY_IRQ 6 -#define FLOPPY_DMA 2 #define DEBUGT 2 +#define DCL_DEBUG /* debug disk change line */ #include + +#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 + * motor of these drives causes system hangs on some PCI computers. drive + * 0 is the low bit (0x1), and drive 7 is the high bit (0x80). Bits are on if + * a drive is allowed. */ +#ifdef CONFIG_FLOPPY_23 +#define ALLOWED_DRIVE_MASK 0xff +#else +#define ALLOWED_DRIVE_MASK 0x33 +#endif + +#define FLOPPY_IRQ 6 +#define FLOPPY_DMA 2 +#define FDC1 0x3f0 +#define FDC2 0x370 +#endif + +#define MODULE_AWARE_DRIVER + +#ifdef CONFIG_BLK_DEV_FD #include #include #include @@ -139,11 +137,11 @@ #define MAJOR_NR FLOPPY_MAJOR #include "blk.h" -static unsigned int changed_floppies = 0xff, fake_change = 0; +static unsigned int fake_change = 0; static int initialising=1; -#ifdef HAVE_2_CONTROLLERS +#ifdef CONFIG_FLOPPY_2_FDC #define N_FDC 2 #define N_DRIVE 8 #else @@ -161,11 +159,17 @@ static int initialising=1; #define DRS (&drive_state[current_drive]) #define DRWE (&write_errors[current_drive]) #define FDCS (&fdc_state[fdc]) +#define CLEARF(x) (clear_bit(x##_BIT, &DRS->flags)) +#define SETF(x) (set_bit(x##_BIT, &DRS->flags)) +#define TESTF(x) (test_bit(x##_BIT, &DRS->flags)) #define UDP (&drive_params[drive]) #define UDRS (&drive_state[drive]) #define UDRWE (&write_errors[drive]) #define UFDCS (&fdc_state[FDC(drive)]) +#define UCLEARF(x) (clear_bit(x##_BIT, &UDRS->flags)) +#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); @@ -200,8 +204,9 @@ printk(DEVICE_NAME "%d: " x,current_drive,(x1),(x2),(x3)); /* * Maximum disk size (in kilobytes). This default is used whenever the * current disk size is unknown. + * [Now it is rather a minimum] */ -#define MAX_DISK_SIZE 3984 +#define MAX_DISK_SIZE 2 /* 3984*/ @@ -280,8 +285,8 @@ static struct { }; static struct floppy_drive_params drive_params[N_DRIVE]; -static struct floppy_drive_struct volatile drive_state[N_DRIVE]; -static struct floppy_write_errors volatile write_errors[N_DRIVE]; +static struct floppy_drive_struct drive_state[N_DRIVE]; +static struct floppy_write_errors write_errors[N_DRIVE]; static struct floppy_raw_cmd raw_cmd; /* @@ -335,7 +340,7 @@ 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 -#ifdef HAVE_2_CONTROLLERS +#ifdef CONFIG_FLOPPY_2_FDC , NULL, NULL, NULL, NULL #endif @@ -367,6 +372,9 @@ static volatile int command_status = FD_COMMAND_NONE, fdc_busy = 0; static struct wait_queue *fdc_wait = NULL, *command_done = NULL; #define NO_SIGNAL (!(current->signal & ~current->blocked) || !interruptible) #define CALL(x) if( (x) == -EINTR) return -EINTR; +#define _WAIT(x,i) CALL(ret=wait_til_done((x),i)) +#define WAIT(x) _WAIT((x),interruptible) +#define IWAIT(x) _WAIT((x),1) /* Errors during formatting are counted here. */ static int format_errors; @@ -400,10 +408,10 @@ void (*error)(void); /* this is called to tally an error */ done_f done; /* this is called to say if the operation has succeeded/failed */ } *cont; +static void floppy_ready(void); static void floppy_start(void); -static void redo_fd_request(void); +static void process_fd_request(void); static void recalibrate_floppy(void); -static void seek_floppy(void); static void floppy_shutdown(void); static int floppy_grab_irq_and_dma(void); @@ -427,7 +435,10 @@ static void reset_fdc(void); #define NO_TRACK -1 #define NEED_1_RECAL -2 #define NEED_2_RECAL -3 -#define PROVEN_ABSENT -4 + +/* */ +static int usage_count = 0; + /* buffer related variables */ static int buffer_track = -1; @@ -437,10 +448,10 @@ static int buffer_max = -1; /* fdc related variables, should end up in a struct */ static struct floppy_fdc_state fdc_state[N_FDC]; -int fdc; /* current fdc */ +static int fdc; /* current fdc */ static struct floppy_struct * floppy = floppy_type; -static unsigned char current_drive = 255; +static unsigned char current_drive = 0; static long current_count_sectors = 0; static char *current_addr = 0; static unsigned char sector_t; /* sector in track */ @@ -478,14 +489,17 @@ static inline void debugt(char *message) /* * disk change. - * This routine is responsible for maintaining the changed_floppies flag, + * This routine is responsible for maintaining the FD_DISK_CHANGE flag, * and the last_checked date. * * last_checked is the date of the last check which showed 'no disk change' - * changed_floppies is set under two conditions: + * FD_DISK_CHANGE is set under two conditions: * 1. The floppy has been changed after some i/o to that floppy already * took place. - * 2. No floppy disk is in the drive. + * 2. No floppy disk is in the drive. This is done in order to ensure that + * requests are quickly flushed in case there is no disk in the drive. It + * follows that FD_DISK_CHANGE can only be cleared if there is a disk in + * the drive. * * For 1., maxblock is observed. Maxblock is 0 if no i/o has taken place yet. * For 2., FD_DISK_NEWCHANGE is watched. FD_DISK_NEWCHANGE is cleared on @@ -500,62 +514,102 @@ static inline void debugt(char *message) static int disk_change(int drive) { - if(jiffies < DP->select_delay + DRS->select_date) - udelay(20000); + int fdc=FDC(drive); +#ifdef CONFIG_FLOPPY_SANITY + if(jiffies < UDP->select_delay + UDRS->select_date) + DPRINT("WARNING disk change called early\n"); + if(! (FDCS->dor & (0x10 << UNIT(drive))) || + (FDCS->dor & 3) != UNIT(drive) || + fdc != FDC(drive)){ + DPRINT("probing disk change on unselected drive\n"); + DPRINT3("drive=%d fdc=%d dor=%x\n",drive, FDC(drive), + FDCS->dor); + } +#endif - if(inb_p(FD_DIR) & 0x80){ - UDRS->flags |= FD_VERIFY; /* verify write protection */ - - if(UDRS->maxblock || /* disk change check */ - !(UDRS->flags & FD_DISK_NEWCHANGE)){/* disk presence check */ - /* mark it changed or absent */ - set_bit(drive,&changed_floppies); +#ifdef DCL_DEBUG + if (UDP->flags & FD_DEBUG){ + DPRINT1("checking disk change line for drive %d\n",drive); + DPRINT1("jiffies=%ld\n", jiffies); + DPRINT1("disk change line=%x\n",inb_p(FD_DIR)&0x80); + DPRINT1("flags=%x\n",UDRS->flags); + } +#endif + if (UDP->flags & FD_BROKEN_DCL) + return UTESTF(FD_DISK_CHANGED); + if( (inb_p(FD_DIR) ^ UDP->flags) & 0x80){ + USETF(FD_VERIFY); /* verify write protection */ + if(UDRS->maxblock){ + /* mark it changed */ + USETF(FD_DISK_CHANGED); /* invalidate its geometry */ if (UDRS->keep_data >= 0) { - if ((DP->flags & FTD_MSG) && + if ((UDP->flags & FTD_MSG) && current_type[drive] != NULL) DPRINT("Disk type is undefined after " "disk change\n"); current_type[drive] = NULL; - floppy_sizes[drive] = MAX_DISK_SIZE; + floppy_sizes[DRIVE(current_drive) + (FDC(current_drive) << 7)] = MAX_DISK_SIZE; } } - UDRS->flags |= FD_DISK_NEWCHANGE; + /*USETF(FD_DISK_NEWCHANGE);*/ return 1; - } else { + } else if(jiffies >= DRS->select_date+DP->select_delay){ UDRS->last_checked=jiffies; - UDRS->flags &= ~FD_DISK_NEWCHANGE; - return 0; + UCLEARF(FD_DISK_NEWCHANGE); } + return 0; +} + +static inline int is_selected(int dor, int unit) +{ + return ( (dor & (0x10 << unit)) && (dor &3) == unit); } -static int locked=0; static int set_dor(int fdc, char mask, char data) { register unsigned char drive, unit, newdor,olddor; - locked=1; + if(FDCS->address == -1) + return -1; + olddor = FDCS->dor; newdor = (olddor & mask) | data; if ( newdor != olddor ){ unit = olddor & 0x3; - drive = REVDRIVE(fdc,unit); - if ( olddor & ( 0x10 << unit )) + if(is_selected(olddor, unit) && !is_selected(newdor,unit)){ + drive = REVDRIVE(fdc,unit); +#ifdef DCL_DEBUG + if (UDP->flags & FD_DEBUG){ + DPRINT("calling disk change from set_dor\n"); + } +#endif disk_change(drive); + } FDCS->dor = newdor; - outb_p( newdor, FD_DOR); + outb_p(newdor, FD_DOR); + + unit = newdor & 0x3; + if(!is_selected(olddor, unit) && is_selected(newdor,unit)){ + drive = REVDRIVE(fdc,unit); + UDRS->select_date = jiffies; + } } - locked=0; + if ( newdor & 0xf0 ) + floppy_grab_irq_and_dma(); + if( olddor & 0xf0 ) + floppy_release_irq_and_dma(); return olddor; } static void twaddle(void) { - cli(); + if (DP->select_delay) + return; outb_p(FDCS->dor & ~(0x10<dor, FD_DOR); - sti(); + DRS->select_date = jiffies; } /* reset all driver information about the current fdc. This is needed after @@ -570,7 +624,6 @@ static void reset_fdc_info(int mode) FDCS->rawcmd = 0; for ( drive = 0; drive < N_DRIVE; drive++) if (FDC(drive) == fdc && - UDRS->track != PROVEN_ABSENT && ( mode || UDRS->track != NEED_1_RECAL)) UDRS->track = NEED_2_RECAL; } @@ -578,12 +631,12 @@ static void reset_fdc_info(int mode) /* selects the fdc and drive, and enables the fdc's input/dma. */ static void set_fdc(int drive) { - if ( drive >= 0 ){ + if (drive >= 0 && drive < N_DRIVE){ fdc = FDC(drive); current_drive = drive; } set_dor(fdc,~0,8); -#ifdef HAVE_2_CONTROLLERS +#ifdef CONFIG_FLOPPY_2_FDC set_dor(1-fdc, ~8, 0); #endif if ( FDCS->rawcmd == 2 ) @@ -592,16 +645,16 @@ static void set_fdc(int drive) FDCS->reset = 1; } -static int usage_count = 0; /* locks the driver */ static int lock_fdc(int drive, int interruptible) { - if(!usage_count){ printk("trying to lock fdc while usage count=0\n"); return -1; } floppy_grab_irq_and_dma(); + if (!current->pid) + run_task_queue(&tq_timer); cli(); while (fdc_busy && NO_SIGNAL) interruptible_sleep_on(&fdc_wait); @@ -619,6 +672,10 @@ static int lock_fdc(int drive, int interruptible) #define LOCK_FDC(drive,interruptible) \ if(lock_fdc(drive,interruptible)) return -EINTR; +typedef void (*timeout_fn)(unsigned long); +static struct timer_list fd_timeout ={ NULL, NULL, 0, 0, + (timeout_fn) floppy_shutdown }; + /* unlocks the driver */ static inline void unlock_fdc(void) { @@ -629,7 +686,7 @@ static inline void unlock_fdc(void) DPRINT1("device interrupt still active at FDC release: %p!\n", DEVICE_INTR); command_status = FD_COMMAND_NONE; - timer_active &= ~(1 << FLOPPY_TIMER); + del_timer(&fd_timeout); fdc_busy = 0; floppy_release_irq_and_dma(); wake_up(&fdc_wait); @@ -640,10 +697,7 @@ static void motor_off_callback(unsigned long nr) { unsigned char mask = ~(0x10 << UNIT(nr)); - if(locked) - floppy_off(nr); - else - set_dor( FDC(nr), mask, 0 ); + set_dor( FDC(nr), mask, 0 ); } static struct timer_list motor_off_timer[N_DRIVE] = { @@ -651,7 +705,7 @@ static struct timer_list motor_off_timer[N_DRIVE] = { { NULL, NULL, 0, 1, motor_off_callback }, { NULL, NULL, 0, 2, motor_off_callback }, { NULL, NULL, 0, 3, motor_off_callback } -#ifdef HAVE_2_CONTROLLERS +#ifdef CONFIG_FLOPPY_2_FDC , { NULL, NULL, 0, 4, motor_off_callback }, { NULL, NULL, 0, 5, motor_off_callback }, @@ -661,26 +715,25 @@ static struct timer_list motor_off_timer[N_DRIVE] = { }; /* schedules motor off */ -static void floppy_off(unsigned int nr) +static void floppy_off(unsigned int drive) { unsigned long volatile delta; - register int fdc=FDC(nr); + register int fdc=FDC(drive); - if( !(FDCS->dor & ( 0x10 << UNIT(nr)))) + if( !(FDCS->dor & ( 0x10 << UNIT(drive)))) return; - del_timer(motor_off_timer+nr); + del_timer(motor_off_timer+drive); /* make spindle stop in a position which minimizes spinup time * next time */ - if ( drive_params[nr].rps ){ - delta = jiffies - drive_state[nr].first_read_date + HZ - - drive_params[nr].spindown_offset; - delta = (( delta * drive_params[nr].rps) % HZ ) / - drive_params[nr].rps; - motor_off_timer[nr].expires = drive_params[nr].spindown - delta; + if (UDP->rps ){ + delta = jiffies - UDRS->first_read_date + HZ - + UDP->spindown_offset; + delta = (( delta * UDP->rps) % HZ ) / UDP->rps; + motor_off_timer[drive].expires = UDP->spindown - delta; } - add_timer(motor_off_timer+nr); + add_timer(motor_off_timer+drive); } /* @@ -691,32 +744,37 @@ static void floppy_off(unsigned int nr) static void scandrives(void) { int i, drive, saved_drive; + + if (DP->select_delay) + return; - saved_drive = current_drive % N_DRIVE; + saved_drive = current_drive; for(i=0; i< N_DRIVE; i++){ drive = (saved_drive + i + 1 ) % N_DRIVE; - if ( UDRS->fd_ref == 0 ) + if ( UDRS->fd_ref == 0 || UDP->select_delay != 0) continue; /* skip closed drives */ set_fdc(drive); - if (!(FDCS->dor & (0x10 << UNIT(drive))) || - ((FDCS->dor & 0x3) != UNIT(drive))) - UDRS->select_date = jiffies; if(! (set_dor( fdc, ~3, UNIT(drive) | ( 0x10 << UNIT(drive))) & (0x10 << UNIT(drive)))) /* switch the motor off again, if it was off to * begin with */ set_dor( fdc, ~( 0x10 << UNIT(drive) ), 0 ); } - current_drive = saved_drive; + set_fdc(saved_drive); } -typedef void (*timeout_fn)(unsigned long); static struct timer_list fd_timer ={ NULL, NULL, 0, 0, 0 }; /* this function makes sure that the disk stays in the drive during the * transfer */ static void fd_watchdog(void) { +#ifdef DCL_DEBUG + if (DP->flags & FD_DEBUG){ + DPRINT("calling disk change from watchdog\n"); + } +#endif + if ( disk_change(current_drive) ){ DPRINT("disk removed during i/o\n"); floppy_shutdown(); @@ -735,7 +793,7 @@ static void main_command_interrupt(void) } /* waits for a delay (spinup or select) to pass */ -static int wait_for_completion(int nr, int delay, timeout_fn function) +static int wait_for_completion(int delay, timeout_fn function) { if ( FDCS->reset ){ reset_fdc(); /* do the reset during sleep to win time @@ -756,7 +814,7 @@ static int wait_for_completion(int nr, int delay, timeout_fn function) static void setup_DMA(void) { -#ifdef SANITY +#ifdef CONFIG_FLOPPY_SANITY if ((!CURRENT || CURRENT->buffer != current_addr || raw_cmd.length > 512 * CURRENT->nr_sectors) && @@ -998,11 +1056,11 @@ static void fdc_specify(void) * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue * of the specify command (i.e. using the fdc_specify function). */ -static void fdc_dtr(void) +static int fdc_dtr(void) { /* If data rate not already set to desired value, set it. */ if ( raw_cmd.rate == FDCS->dtr) - return; + return 0; /* Set dtr */ outb_p(raw_cmd.rate, FD_DCR); @@ -1010,10 +1068,11 @@ static void fdc_dtr(void) /* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB) * need a stabilization period of several milliseconds to be * enforced after data rate changes before R/W operations. - * Pause 5 msec to avoid trouble. + * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies) */ - udelay(5000); FDCS->dtr = raw_cmd.rate; + return(wait_for_completion(jiffies+2, + (timeout_fn) floppy_ready)); } /* fdc_dtr */ static void tell_sector(void) @@ -1042,15 +1101,15 @@ static int interpret_errors(void) /* check IC to find cause of interrupt */ switch ((ST0 & ST0_INTR)>>6) { - case 1: /* error occured during command execution */ + case 1: /* error occurred during command execution */ bad = 1; if (ST1 & ST1_WP) { DPRINT("Drive is write protected\n"); - DRS->flags &= ~FD_DISK_WRITABLE; + CLEARF(FD_DISK_WRITABLE); cont->done(0); bad = 2; } else if (ST1 & ST1_ND) { - DRS->flags |= FD_NEED_TWADDLE; + SETF(FD_NEED_TWADDLE); } else if (ST1 & ST1_OR) { if (DP->flags & FTD_MSG ) DPRINT("Over/Underrun - retrying\n"); @@ -1126,7 +1185,7 @@ static void setup_rw_floppy(void) function = (timeout_fn) setup_rw_floppy; /* wait until the floppy is spinning fast enough */ - if (wait_for_completion(current_drive,ready_date,function)) + if (wait_for_completion(ready_date,function)) return; } dflags = DRS->flags; @@ -1156,9 +1215,7 @@ static void setup_rw_floppy(void) fd_watchdog(); } -#ifdef SILENT_DC_CLEAR static int blind_seek; -#endif /* * This is the routine called after every seek (or recalibrate) interrupt @@ -1168,9 +1225,6 @@ static void seek_interrupt(void) { #ifdef DEBUGT debugt("seek interrupt:"); -#endif -#ifdef SILENT_DC_CLEAR - set_dor(fdc, ~0, (0x10 << UNIT(current_drive))); #endif if (inr != 2 || (ST0 & 0xF8) != 0x20 ) { DPRINT("seek failed\n"); @@ -1179,20 +1233,23 @@ static void seek_interrupt(void) cont->redo(); return; } - if (DRS->track >= 0 && DRS->track != ST1 -#ifdef SILENT_DC_CLEAR - && !blind_seek + if (DRS->track >= 0 && DRS->track != ST1 && !blind_seek){ +#ifdef DCL_DEBUG + if (DP->flags & FD_DEBUG){ + DPRINT("clearing NEWCHANGE flag because of effective seek\n"); + DPRINT1("jiffies=%ld\n", jiffies); + } #endif - ) - DRS->flags &= ~FD_DISK_NEWCHANGE; /* effective seek */ + CLEARF(FD_DISK_NEWCHANGE); /* effective seek */ + DRS->select_date = jiffies; + } DRS->track = ST1; - DRS->select_date = jiffies; - seek_floppy(); + floppy_ready(); } static void check_wp(void) { - if (DRS->flags & FD_VERIFY) { + if (TESTF(FD_VERIFY)) { /* check write protection */ output_byte( FD_GETSTATUS ); output_byte( UNIT(current_drive) ); @@ -1200,10 +1257,18 @@ static void check_wp(void) FDCS->reset = 1; return; } - DRS->flags &= ~(FD_VERIFY | FD_DISK_WRITABLE | FD_NEED_TWADDLE); - + CLEARF(FD_VERIFY); + CLEARF(FD_NEED_TWADDLE); +#ifdef DCL_DEBUG + if (DP->flags & FD_DEBUG){ + DPRINT("checking whether disk is write protected\n"); + DPRINT1("wp=%x\n",ST3 & 0x40); + } +#endif if (!( ST3 & 0x40)) - DRS->flags |= FD_DISK_WRITABLE; + SETF(FD_DISK_WRITABLE); + else + CLEARF(FD_DISK_WRITABLE); } } @@ -1211,16 +1276,22 @@ static void seek_floppy(void) { int track; -#ifdef SILENT_DC_CLEAR blind_seek=0; + +#ifdef DCL_DEBUG + if (DP->flags & FD_DEBUG){ + DPRINT("calling disk change from seek\n"); + } #endif - disk_change(current_drive); - if ((raw_cmd.flags & FD_RAW_NEED_DISK) && - test_bit(current_drive,&changed_floppies)){ + + if (!TESTF(FD_DISK_NEWCHANGE) && + disk_change(current_drive) && + (raw_cmd.flags & FD_RAW_NEED_DISK)){ /* the media changed flag should be cleared after the seek. * If it isn't, this means that there is really no disk in * the drive. */ + SETF(FD_DISK_CHANGED); cont->done(0); cont->redo(); return; @@ -1228,7 +1299,7 @@ static void seek_floppy(void) if ( DRS->track <= NEED_1_RECAL ){ recalibrate_floppy(); return; - } else if ((DRS->flags & FD_DISK_NEWCHANGE) && + } else if (TESTF(FD_DISK_NEWCHANGE) && (raw_cmd.flags & FD_RAW_NEED_DISK) && (DRS->track <= NO_TRACK || DRS->track == raw_cmd.track)) { /* we seek to clear the media-changed condition. Does anybody @@ -1236,15 +1307,17 @@ static void seek_floppy(void) if ( raw_cmd.track ) track = raw_cmd.track - 1; else { -#ifdef SILENT_DC_CLEAR - set_dor(fdc, ~ (0x10 << UNIT(current_drive)), 0); - blind_seek = 1; -#endif + if(DP->flags & FD_SILENT_DCL_CLEAR){ + set_dor(fdc, ~(0x10 << UNIT(current_drive)), 0); + blind_seek = 1; + raw_cmd.flags |= FD_RAW_NEED_SEEK; + } track = 1; } } else { check_wp(); - if (raw_cmd.track != DRS->track) + if (raw_cmd.track != DRS->track && + (raw_cmd.flags & FD_RAW_NEED_SEEK)) track = raw_cmd.track; else { setup_rw_floppy(); @@ -1252,23 +1325,13 @@ static void seek_floppy(void) } } -#ifndef SILENT_DC_CLEAR - if ( !track && DRS->track >= 0 && DRS->track < 80 ){ - DRS->flags &= ~FD_DISK_NEWCHANGE; - /* if we go to track 0 anyways, we can just as well use - * recalibrate */ - recalibrate_floppy(); - } else -#endif - { - SET_INTR(seek_interrupt); - output_byte(FD_SEEK); - output_byte(UNIT(current_drive)); - LAST_OUT(track); + SET_INTR(seek_interrupt); + output_byte(FD_SEEK); + output_byte(UNIT(current_drive)); + LAST_OUT(track); #ifdef DEBUGT - debugt("seek command:"); + debugt("seek command:"); #endif - } } static void recal_interrupt(void) @@ -1280,11 +1343,6 @@ static void recal_interrupt(void) FDCS->reset = 1; else if (ST0 & ST0_ECE) { switch(DRS->track){ - case PROVEN_ABSENT: -#ifdef DEBUGT - debugt("recal interrupt proven absent:"); -#endif - /* fall through */ case NEED_1_RECAL: #ifdef DEBUGT debugt("recal interrupt need 1 recal:"); @@ -1305,7 +1363,14 @@ static void recal_interrupt(void) * not to move at recalibration is to be already at * track 0.) Clear the new change flag */ - DRS->flags &= ~FD_DISK_NEWCHANGE; +#ifdef DCL_DEBUG + if (DP->flags & FD_DEBUG){ + DPRINT("clearing NEWCHANGE flag because of second recalibrate\n"); + } +#endif + + CLEARF(FD_DISK_NEWCHANGE); + DRS->select_date = jiffies; /* fall through */ default: #ifdef DEBUGT @@ -1321,7 +1386,7 @@ static void recal_interrupt(void) } } else DRS->track = ST1; - seek_floppy(); + floppy_ready(); } /* @@ -1358,8 +1423,11 @@ static void floppy_interrupt(int unused) void (*handler)(void) = DEVICE_INTR; CLEAR_INTR; - if ( fdc >= N_FDC ){ /* we don't even know which FDC is the culprit */ - printk("floppy interrupt on bizarre fdc\n"); + if ( fdc >= N_FDC || FDCS->address == -1){ + /* we don't even know which FDC is the culprit */ + printk("DOR0=%x\n", fdc_state[0].dor); + printk("floppy interrupt on bizarre fdc %d\n",fdc); + printk("handler=%p\n", handler); return; } inr = result(); @@ -1444,9 +1512,9 @@ void show_floppy(void) printk("floppy_tq.routine=%p\n", floppy_tq.routine); if(fd_timer.prev) printk("fd_timer.function=%p\n", fd_timer.function); - if( timer_active & (1 << FLOPPY_TIMER)){ - printk("timer_table=%p\n",timer_table[FLOPPY_TIMER].fn); - printk("expires=%ld\n",timer_table[FLOPPY_TIMER].expires); + if(fd_timeout.prev){ + printk("timer_table=%p\n",fd_timeout.function); + printk("expires=%ld\n",fd_timeout.expires); printk("now=%ld\n",jiffies); } printk("cont=%p\n", cont); @@ -1470,19 +1538,15 @@ static void floppy_shutdown(void) cont->done(0); cont->redo(); /* this will recall reset when needed */ } +/*typedef void (*timeout_fn)(unsigned long);*/ /* start motor, check media-changed condition and write protection */ -static void start_motor(void) +static int start_motor( void (*function)(void) ) { int mask, data; mask = 0xfc; data = UNIT(current_drive); - if ( (FDCS->dor & 0x03) != UNIT(current_drive) || - !(FDCS->dor & ( 0x10 << UNIT(current_drive) ) )) - /* notes select time if floppy is not yet selected */ - DRS->select_date = jiffies; - if (!(raw_cmd.flags & FD_RAW_NO_MOTOR)){ if(!(FDCS->dor & ( 0x10 << UNIT(current_drive) ) )){ set_debugt(); @@ -1499,26 +1563,31 @@ static void start_motor(void) /* starts motor and selects floppy */ del_timer(motor_off_timer + current_drive); set_dor( fdc, mask, data); - if( raw_cmd.flags & FD_RAW_NO_MOTOR) - return; - disk_change(current_drive); - - return; + /* wait_for_completion also schedules reset if needed. */ + return(wait_for_completion(DRS->select_date+DP->select_delay, + (timeout_fn) function)); } static void floppy_ready(void) { CHECK_RESET; - start_motor(); + if(start_motor(floppy_ready)) return; + if(fdc_dtr()) return; - /* wait_for_completion also schedules reset if needed. */ - if(wait_for_completion(current_drive, - DRS->select_date+DP->select_delay, - (timeout_fn) floppy_ready)) - return; - fdc_dtr(); - if ( raw_cmd.flags & FD_RAW_NEED_SEEK ){ +#ifdef DCL_DEBUG + if (DP->flags & FD_DEBUG){ + DPRINT("calling disk change from floppy_ready\n"); + } +#endif + + if(!(raw_cmd.flags & FD_RAW_NO_MOTOR) && + disk_change(current_drive) && + !DP->select_delay) + twaddle(); /* this clears the dcl on certain drive/controller + * combinations */ + + if ( raw_cmd.flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)){ perpendicular_mode(); fdc_specify(); /* must be done here because of hut, hlt ... */ seek_floppy(); @@ -1528,9 +1597,17 @@ static void floppy_ready(void) static void floppy_start(void) { - timer_table[FLOPPY_TIMER].expires = jiffies + DP->timeout; - timer_active |= 1 << FLOPPY_TIMER; + del_timer(&fd_timeout); + fd_timeout.expires = DP->timeout; + add_timer(&fd_timeout); + scandrives(); +#ifdef DCL_DEBUG + if (DP->flags & FD_DEBUG){ + DPRINT("setting NEWCHANGE in floppy_start\n"); + } +#endif + SETF(FD_DISK_NEWCHANGE); floppy_ready(); } @@ -1550,7 +1627,7 @@ static void floppy_start(void) static void do_wakeup(void) { - timer_active &= ~(1 << FLOPPY_TIMER); + del_timer(&fd_timeout); cont = 0; command_status += 2; wake_up(&command_done); @@ -1582,7 +1659,7 @@ static int wait_til_done( void (*handler)(void ), int interruptible ) if(command_status < 2){ sti(); floppy_shutdown(); - redo_fd_request(); + process_fd_request(); return -EINTR; } sti(); @@ -1757,7 +1834,6 @@ static void redo_format(void) raw_cmd.track = format_req.track << floppy->stretch; buffer_track = -1; setup_format_params(); - clear_bit(current_drive, &changed_floppies); floppy_start(); #ifdef DEBUGT debugt("queue format request"); @@ -1772,23 +1848,27 @@ static struct cont_t format_cont={ static int do_format(int device, struct format_descr *tmp_format_req) { - int okay; + int ret; + int drive=DRIVE(device); - LOCK_FDC(DRIVE(device),1); + LOCK_FDC(drive,1); set_floppy(device); if (!floppy || + floppy->track > DP->tracks || tmp_format_req->track >= floppy->track || - tmp_format_req->head >= floppy->head){ - redo_fd_request(); + tmp_format_req->head >= floppy->head || + (floppy->sect << 2) % (1 << FD_SIZECODE(floppy)) || + !floppy->fmt_gap) { + process_fd_request(); return -EINVAL; } format_req = *tmp_format_req; format_errors = 0; cont = &format_cont; errors = &format_errors; - CALL(okay=wait_til_done(redo_format,1)); - redo_fd_request(); - return okay; + IWAIT(redo_format); + process_fd_request(); + return ret; } /* @@ -1803,7 +1883,7 @@ static void request_done(int uptodate) int block; probing = 0; - timer_active &= ~(1 << FLOPPY_TIMER); + del_timer(&fd_timeout); if (!CURRENT){ DPRINT("request list destroyed in floppy request done\n"); @@ -1867,7 +1947,7 @@ static void rw_interrupt(void) floppy->sect + ((R_SECTOR-SECTOR) << SIZECODE >> 2) - (sector_t % floppy->sect) % ssize; -#ifdef SANITY +#ifdef CONFIG_FLOPPY_SANITY if ( nr_sectors > current_count_sectors + ssize - (current_count_sectors + sector_t) % ssize + sector_t % ssize){ @@ -1940,7 +2020,7 @@ static int buffer_chain_size(void) size = CURRENT->current_nr_sectors << 9; bh = CURRENT->bh; - if(bh){ + if (bh){ bh = bh->b_reqnext; while ( bh && bh->b_data == base + size ){ size += bh->b_size; @@ -1987,7 +2067,7 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2) current_count_sectors = CURRENT->nr_sectors; } remaining = current_count_sectors << 9; -#ifdef SANITY +#ifdef CONFIG_FLOPPY_SANITY if ((remaining >> 9) > CURRENT->nr_sectors && CT(COMMAND) == FD_WRITE ){ DPRINT("in copy buffer\n"); @@ -2013,7 +2093,7 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2) while ( remaining > 0){ if ( size > remaining ) size = remaining; -#ifdef SANITY +#ifdef CONFIG_FLOPPY_SANITY if (dma_buffer + size > floppy_track_buffer + (max_buffer_sectors << 10) || dma_buffer < floppy_track_buffer ){ @@ -2042,7 +2122,7 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2) dma_buffer += size; bh = bh->b_reqnext; -#ifdef SANITY +#ifdef CONFIG_FLOPPY_SANITY if ( !bh){ DPRINT("bh=null in copy buffer after copy\n"); break; @@ -2051,7 +2131,7 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2) size = bh->b_size; buffer = bh->b_data; } -#ifdef SANITY +#ifdef CONFIG_FLOPPY_SANITY if ( remaining ){ if ( remaining > 0 ) max_sector -= remaining >> 9; @@ -2075,7 +2155,7 @@ static int make_raw_rw_request(void) int aligned_sector_t; int max_sector, max_size, tracksize, ssize; - current_drive = DRIVE(CURRENT->dev); + set_fdc(DRIVE(CURRENT->dev)); raw_cmd.flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK; @@ -2098,7 +2178,7 @@ static int make_raw_rw_request(void) return 0; HEAD = sector_t / floppy->sect; - if ( (DRS->flags & FD_NEED_TWADDLE) && sector_t < floppy->sect ) + if ( TESTF( FD_NEED_TWADDLE) && sector_t < floppy->sect ) max_sector = floppy->sect; /* 2M disks have phantom sectors on the first track */ @@ -2189,7 +2269,7 @@ static int make_raw_rw_request(void) */ if ((indirect - sector_t) * 2 > (direct - sector_t) * 3 && *errors < DP->max_errors.read_track && - /*!(DRS->flags & FD_NEED_TWADDLE) &&*/ + /*!TESTF( FD_NEED_TWADDLE) &&*/ ( ( !probing || (DP->read_track & (1 <probed_format))))){ max_size = CURRENT->nr_sectors; @@ -2223,7 +2303,7 @@ static int make_raw_rw_request(void) * if we get here, we know that the write * is either aligned or the data already in the buffer * (buffer will be overwritten) */ -#ifdef SANITY +#ifdef CONFIG_FLOPPY_SANITY if (sector_t != aligned_sector_t && buffer_track == -1 ) DPRINT("internal error offset !=0 on write\n"); #endif @@ -2238,7 +2318,7 @@ static int make_raw_rw_request(void) raw_cmd.length = sector_t+current_count_sectors-aligned_sector_t; raw_cmd.length = ((raw_cmd.length -1)|(ssize-1))+1; raw_cmd.length <<= 9; -#ifdef SANITY +#ifdef CONFIG_FLOPPY_SANITY if ((raw_cmd.length < current_count_sectors << 9) || (current_addr != CURRENT->buffer && CT(COMMAND) == FD_WRITE && @@ -2295,24 +2375,19 @@ static int make_raw_rw_request(void) return 2; } -static struct cont_t rw_cont={ - rw_interrupt, - redo_fd_request, - bad_flp_intr, - request_done }; - static void redo_fd_request(void) { #define REPEAT {request_done(0); continue; } int device; int tmp; + int error; + error = -1; if (current_drive < N_DRIVE) floppy_off(current_drive); if (CURRENT && CURRENT->dev < 0) return; - cont = &rw_cont; while(1){ if (!CURRENT) { CLEAR_INTR; @@ -2323,20 +2398,29 @@ static void redo_fd_request(void) panic(DEVICE_NAME ": request list destroyed"); if (CURRENT->bh && !CURRENT->bh->b_lock) panic(DEVICE_NAME ": block not locked"); - +#if 0 + if (!CURRENT->bh->b_count && + (CURRENT->errors || error == CURRENT->dev)){ + error=CURRENT->dev; + DPRINT("skipping read ahead buffer\n"); + REPEAT; + } +#endif + error=-1; device = CURRENT->dev; set_fdc( DRIVE(device)); - timer_table[FLOPPY_TIMER].expires = jiffies + DP->timeout; - timer_active |= 1 << FLOPPY_TIMER; - raw_cmd.flags=0; - start_motor(); - if(test_bit( DRIVE(device), &fake_change) || - test_bit( DRIVE(device), &changed_floppies)){ + del_timer(&fd_timeout); + fd_timeout.expires = DP->timeout; + add_timer(&fd_timeout); + + set_floppy(device); + if(start_motor(redo_fd_request)) return; + if(test_bit(current_drive, &fake_change) || + TESTF(FD_DISK_CHANGED)){ DPRINT("disk absent or changed during operation\n"); REPEAT; } - set_floppy(device); if (!floppy) { /* Autodetection */ if (!probing){ DRS->probed_format = 0; @@ -2357,6 +2441,8 @@ static void redo_fd_request(void) continue; } + if (TESTF(FD_NEED_TWADDLE)) + twaddle(); floppy_tq.routine = (void *)(void *) floppy_start; queue_task(&floppy_tq, &tq_timer); #ifdef DEBUGT @@ -2367,7 +2453,22 @@ static void redo_fd_request(void) #undef REPEAT } -void do_fd_request(void) +static struct cont_t rw_cont={ + rw_interrupt, + redo_fd_request, + bad_flp_intr, + request_done }; + +struct tq_struct request_tq = +{ 0, 0, (void *) (void *) redo_fd_request, 0 }; + +static void process_fd_request(void) +{ + cont = &rw_cont; + queue_task(&request_tq, &tq_timer); +} + +static void do_fd_request(void) { if (fdc_busy) /* fdc busy, this new request will be treated when the @@ -2376,7 +2477,30 @@ void do_fd_request(void) /* fdc_busy cannot be set by an interrupt or a bh */ floppy_grab_irq_and_dma(); fdc_busy=1; - redo_fd_request(); + process_fd_request(); +} + +static struct cont_t poll_cont={ + success_and_wakeup, + floppy_ready, + generic_failure, + generic_done }; + +static int poll_drive(int interruptible, int flag){ + int ret; + /* no auto-sense, just clear dcl */ + raw_cmd.flags= flag; + raw_cmd.track=0; + raw_cmd.cmd_count=0; + cont = &poll_cont; +#ifdef DCL_DEBUG + if (DP->flags & FD_DEBUG){ + DPRINT("setting NEWCHANGE in poll_drive\n"); + } +#endif + SETF(FD_DISK_NEWCHANGE); + WAIT(floppy_ready); + return ret; } /* @@ -2397,29 +2521,23 @@ static struct cont_t reset_cont={ static int user_reset_fdc(int drive, int arg, int interruptible) { - int result; + int ret; - result=0; + ret=0; + if(arg == FD_RESET_IF_NEEDED && !FDCS->reset) + return 0; LOCK_FDC(drive,interruptible); - switch(arg){ - case FD_RESET_ALWAYS: + if(arg == FD_RESET_ALWAYS) FDCS->reset=1; - break; - case FD_RESET_IF_RAWCMD: - if(FDCS->rawcmd == 2 ) - reset_fdc_info(1); - break; - } if ( FDCS->reset ){ cont = &reset_cont; - timer_table[FLOPPY_TIMER].expires = jiffies + 5; - timer_active |= 1 << FLOPPY_TIMER; - CALL(result=wait_til_done(reset_fdc,interruptible)); + del_timer(&fd_timeout); + fd_timeout.expires = DP->timeout; + add_timer(&fd_timeout); + WAIT(reset_fdc); } - if ( UDRS->track == PROVEN_ABSENT ) - UDRS->track = NEED_2_RECAL; - redo_fd_request(); - return result; + process_fd_request(); + return ret; } /* @@ -2465,21 +2583,21 @@ static struct cont_t raw_cmd_cont={ generic_failure, generic_done }; -static int raw_cmd_ioctl(int drive, void *param) +static int raw_cmd_ioctl(void *param) { - int i, count, ret; + int i, drive, count, ret; if ( FDCS->rawcmd <= 1 ) FDCS->rawcmd = 1; - for ( i= 0; i < N_DRIVE; i++){ - if ( FDC(i) != fdc) + for ( drive= 0; drive < N_DRIVE; drive++){ + if ( FDC(drive) != fdc) continue; - if ( i == drive ){ - if ( drive_state[i].fd_ref > 1 ){ + if ( drive == current_drive ){ + if ( UDRS->fd_ref > 1 ){ FDCS->rawcmd = 2; break; } - } else if ( drive_state[i].fd_ref ){ + } else if ( UDRS->fd_ref ){ FDCS->rawcmd = 2; break; } @@ -2505,13 +2623,18 @@ static int raw_cmd_ioctl(int drive, void *param) current_addr = floppy_track_buffer; cont = &raw_cmd_cont; - CALL(ret=wait_til_done(floppy_start,1)); + IWAIT(floppy_start); +#ifdef DCL_DEBUG + if (DP->flags & FD_DEBUG){ + DPRINT("calling disk change from raw_cmd ioctl\n"); + } +#endif if( disk_change(current_drive) ) raw_cmd.flags |= FD_RAW_DISK_CHANGE; else raw_cmd.flags &= ~FD_RAW_DISK_CHANGE; if(raw_cmd.flags & FD_RAW_NO_MOTOR_AFTER) - motor_off_callback(drive); + motor_off_callback(current_drive); if ( !ret && !FDCS->reset ){ raw_cmd.reply_count = inr; @@ -2538,7 +2661,7 @@ static int invalidate_drive(int rdev) { /* invalidate the buffer track to force a reread */ set_bit( DRIVE(rdev), &fake_change); - redo_fd_request(); + process_fd_request(); check_disk_change(rdev); return 0; } @@ -2547,6 +2670,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long param) { #define IOCTL_MODE_BIT 8 +#define OPEN_WRITE_BIT 16 #define IOCTL_ALLOWED (filp && (filp->f_mode & IOCTL_MODE_BIT)) struct floppy_struct newparams; @@ -2584,7 +2708,9 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, return -ENODEV; return COPYOUT(this_floppy[0]); case FDPOLLDRVSTAT: - check_disk_change(device); + LOCK_FDC(drive,1); + CALL(poll_drive(1, FD_RAW_NEED_DISK)); + process_fd_request(); /* fall through */ case FDGETDRVSTAT: return COPYOUT(*UDRS); @@ -2611,14 +2737,12 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, return -EINVAL; LOCK_FDC(drive,1); set_floppy(device); - CALL(i = raw_cmd_ioctl(drive, (void *) param)); - redo_fd_request(); + CALL(i = raw_cmd_ioctl((void *) param)); + process_fd_request(); return i; case FDFMTTRK: if (UDRS->fd_ref != 1) return -EBUSY; - if (UDRS->track == PROVEN_ABSENT) - return -ENXIO; COPYIN(tmp_format_req); return do_format(device, &tmp_format_req); case FDSETMAXERRS: @@ -2648,7 +2772,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, if ( type){ if ( !suser() ) return -EPERM; - LOCK_FDC(-1,1); + LOCK_FDC(drive,1); for ( cnt = 0; cnt < N_DRIVE; cnt++){ if (TYPE(drive_state[cnt].fd_device) == type && drive_state[cnt].fd_ref) @@ -2660,11 +2784,11 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, cnt < (type << 2 ) + 4 ; cnt++) floppy_sizes[cnt]= -#ifdef HAVE_2_CONTROLLERS +#ifdef CONFIG_FLOPPY_2_FDC floppy_sizes[cnt+0x80]= #endif floppy_type[type].size>>1; - redo_fd_request(); + process_fd_request(); for ( cnt = 0; cnt < N_DRIVE; cnt++){ if (TYPE(drive_state[cnt].fd_device) == type && drive_state[cnt].fd_ref) @@ -2675,12 +2799,10 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, } LOCK_FDC(drive,1); - if ( cmd != FDDEFPRM ){ + if ( cmd != FDDEFPRM ) /* notice a disk change immediately, else * we loose our settings immediately*/ - raw_cmd.flags = 0; - start_motor(); - } + CALL(poll_drive(1,0)); user_params[drive] = newparams; if (buffer_drive == drive && buffer_max > user_params[drive].sect) @@ -2701,7 +2823,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, DRS->maxtrack ) invalidate_drive(device); else - redo_fd_request(); + process_fd_request(); return 0; case FDRESET: return user_reset_fdc( drive, (int)param, 1); @@ -2718,7 +2840,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, case FDTWADDLE: LOCK_FDC(drive,1); twaddle(); - redo_fd_request(); + process_fd_request(); } if ( ! suser() ) return -EPERM; @@ -2769,35 +2891,48 @@ static void config_types(void) printk("\n"); } -int floppy_is_wp( int minor) +static int floppy_read(struct inode * inode, struct file * filp, + char * buf, int count) { - check_disk_change(minor + (MAJOR_NR << 8)); - return ! ( drive_state[ DRIVE(minor) ].flags & FD_DISK_WRITABLE ); + int drive = DRIVE(inode->i_rdev); + + check_disk_change(inode->i_rdev); + if (UTESTF(FD_DISK_CHANGED)) + return -ENXIO; + return block_read(inode, filp, buf, count); } +static int floppy_write(struct inode * inode, struct file * filp, + char * buf, int count) +{ + int block; + int ret; + int drive = DRIVE(inode->i_rdev); -#define WRAPPER(op) \ -static int floppy_##op(struct inode * inode, struct file * filp, \ - char * buf, int count) \ -{ \ - check_disk_change(inode->i_rdev); \ - if ( drive_state[DRIVE(inode->i_rdev)].track == PROVEN_ABSENT ) \ - return -ENXIO; \ - if ( test_bit(DRIVE(inode->i_rdev),&changed_floppies)) \ - return -ENXIO; \ - return block_##op(inode, filp, buf, count); \ + if(!UDRS->maxblock) + UDRS->maxblock=1;/* make change detectable */ + check_disk_change(inode->i_rdev); + if (UTESTF(FD_DISK_CHANGED)) + return -ENXIO; + if(!UTESTF(FD_DISK_WRITABLE)) + return -EROFS; + block = (filp->f_pos + count) >> 9; + if(block > UDRS->maxblock) + UDRS->maxblock = block; + ret= block_write(inode, filp, buf, count); + return ret; } -WRAPPER(read) -WRAPPER(write) - static void floppy_release(struct inode * inode, struct file * filp) { int drive; drive = DRIVE(inode->i_rdev); - fsync_dev(inode->i_rdev); + if( !filp || (filp->f_mode & (2 | OPEN_WRITE_BIT))) + /* if the file is mounted OR (writable now AND writable at + * open time) Linus: Does this cover all cases? */ + block_fsync(inode,filp); if (UDRS->fd_ref < 0) UDRS->fd_ref=0; @@ -2828,20 +2963,22 @@ static int floppy_open(struct inode * inode, struct file * filp) } drive = DRIVE(inode->i_rdev); - if ( drive >= N_DRIVE || !( ALLOWED_DRIVE_MASK & ( 1 << drive)) ) + if (drive >= N_DRIVE || + !( ALLOWED_DRIVE_MASK & ( 1 << drive)) || + fdc_state[FDC(drive)].version == FDC_NONE) return -ENXIO; if (TYPE(inode->i_rdev) >= NUMBER(floppy_type)) return -ENXIO; - - if ((filp->f_mode & 3) && - UDRS->track == PROVEN_ABSENT ) - return -ENXIO; - old_dev = UDRS->fd_device; if (UDRS->fd_ref && old_dev != inode->i_rdev) return -EBUSY; + if(!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)){ + USETF(FD_DISK_CHANGED); + USETF(FD_VERIFY); + } + if(UDRS->fd_ref == -1 || (UDRS->fd_ref && (filp->f_flags & O_EXCL))) return -EBUSY; @@ -2865,30 +3002,21 @@ static int floppy_open(struct inode * inode, struct file * filp) /* Allow ioctls if we have write-permissions even if read-only open */ if ((filp->f_mode & 2) || permission(inode,2)) filp->f_mode |= IOCTL_MODE_BIT; + if (filp->f_mode & 2) + filp->f_mode |= OPEN_WRITE_BIT; if (UFDCS->rawcmd == 1) UFDCS->rawcmd = 2; if (filp->f_flags & O_NDELAY) return 0; - - if (filp->f_mode && UDRS->track == PROVEN_ABSENT ) - RETERR(ENXIO); - - if (user_reset_fdc(drive, FD_RESET_IF_NEEDED,0)) - RETERR(EIO); - if (filp->f_mode & 3) { UDRS->last_checked = 0; check_disk_change(inode->i_rdev); - if (test_bit(drive,&changed_floppies)) + if (UTESTF(FD_DISK_CHANGED)) RETERR(ENXIO); } - - if (filp->f_mode && UDRS->track == PROVEN_ABSENT ) - RETERR(ENXIO); - - if ((filp->f_mode & 2) && !(UDRS->flags & FD_DISK_WRITABLE)) + if ((filp->f_mode & 2) && !(UTESTF(FD_DISK_WRITABLE))) RETERR(EROFS); return 0; #undef RETERR @@ -2906,45 +3034,38 @@ static int check_floppy_change(dev_t dev) return 0; } - if(test_bit(drive, &changed_floppies)) + if (UTESTF(FD_DISK_CHANGED)) return 1; if(UDRS->last_checked + UDP->checkfreq < jiffies){ lock_fdc(drive,0); - start_motor(); - redo_fd_request(); + poll_drive(0,0); + process_fd_request(); } - if(test_bit(drive, &changed_floppies)) - return 1; - if(test_bit(drive, &fake_change)) + if(UTESTF(FD_DISK_CHANGED) || + test_bit(drive, &fake_change) || + (!TYPE(dev) && !current_type[drive])) return 1; return 0; } -static struct cont_t poll_cont={ - success_and_wakeup, - floppy_ready, - generic_failure, - generic_done }; - - /* revalidate the floppy disk, i.e. trigger format autodetection by reading * the bootblock (block 0). "Autodetection" is also needed to check whether * there is a disk in the drive at all... Thus we also do it for fixed * geometry formats */ static int floppy_revalidate(dev_t dev) { +#define NO_GEOM (!current_type[drive] && !TYPE(dev)) struct buffer_head * bh; int drive=DRIVE(dev); int cf; - cf = test_bit(drive, &changed_floppies); - if(cf || test_bit(drive, &fake_change)){ + if(UTESTF(FD_DISK_CHANGED) || test_bit(drive, &fake_change) || NO_GEOM){ lock_fdc(drive,0); - cf = test_bit(drive, &changed_floppies); - if(! (cf || test_bit(drive, &fake_change))){ - redo_fd_request(); /* already done by another thread */ + cf = UTESTF(FD_DISK_CHANGED); + if(! (cf || test_bit(drive, &fake_change) || NO_GEOM)){ + process_fd_request(); /*already done by another thread*/ return 0; } UDRS->maxblock = 0; @@ -2952,34 +3073,28 @@ static int floppy_revalidate(dev_t dev) if ( buffer_drive == drive) buffer_track = -1; clear_bit(drive, &fake_change); - clear_bit(drive, &changed_floppies); - if(cf){ + UCLEARF(FD_DISK_CHANGED); + if(cf) UDRS->generation++; - if(!current_type[drive] && !TYPE(dev)){ - /* auto-sensing */ - int size = floppy_blocksizes[MINOR(dev)]; - if (!size) - size = 1024; - if (!(bh = getblk(dev,0,size))){ - redo_fd_request(); - return 1; - } - if ( bh && ! bh->b_uptodate) - ll_rw_block(READ, 1, &bh); - redo_fd_request(); - wait_on_buffer(bh); - brelse(bh); - return 0; - } else { - /* no auto-sense, just clear dcl */ - raw_cmd.flags=FD_RAW_NEED_SEEK|FD_RAW_NEED_DISK; - raw_cmd.track=0; - raw_cmd.cmd_count=0; - cont = &poll_cont; - wait_til_done(floppy_ready,0); + if(NO_GEOM){ + /* auto-sensing */ + int size = floppy_blocksizes[MINOR(dev)]; + if (!size) + size = 1024; + if (!(bh = getblk(dev,0,size))){ + process_fd_request(); + return 1; } - } - redo_fd_request(); + if ( bh && ! bh->b_uptodate) + ll_rw_block(READ, 1, &bh); + process_fd_request(); + wait_on_buffer(bh); + brelse(bh); + return 0; + } + if(cf) + poll_drive(0, FD_RAW_NEED_DISK); + process_fd_request(); } return 0; } @@ -3046,17 +3161,21 @@ static char get_fdc_version(void) } printk("FDC %d is a post-1991 82077\n",fdc); return FDC_82077; /* Revised 82077AA passes all the tests */ -} /* fdc_init */ +} /* get_fdc_version */ -void floppy_init(void) +#ifdef FD_MODULE +static +#endif +int new_floppy_init(void) { - int i; + int i,drive; + int have_no_fdc=0; sti(); if (register_blkdev(MAJOR_NR,"fd",&floppy_fops)) { printk("Unable to get major %d for floppy\n",MAJOR_NR); - return; + return -EBUSY; } for(i=0; i<256; i++) @@ -3068,42 +3187,48 @@ void floppy_init(void) blk_size[MAJOR_NR] = floppy_sizes; blksize_size[MAJOR_NR] = floppy_blocksizes; blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; - timer_table[FLOPPY_TIMER].fn = floppy_shutdown; - timer_active &= ~(1 << FLOPPY_TIMER); + del_timer(&fd_timeout); config_types(); - fdc_state[0].address = 0x3f0; + fdc_state[0].address = FDC1; + fdc_state[0].dor = 0; #if N_FDC > 1 - fdc_state[1].address = 0x370; + fdc_state[1].address = FDC2; + fdc_state[1].dor = 0; #endif + for (i = 0 ; i < N_FDC ; i++) { fdc = i; FDCS->dtr = -1; - FDCS->dor = 0; + FDCS->dor = 0x4; FDCS->reset = 0; FDCS->version = FDC_NONE; - set_dor(fdc, ~0, 0xc ); + } + + if(floppy_grab_irq_and_dma()){ + unregister_blkdev(MAJOR_NR,"fd"); + return -EBUSY; } /* initialise drive state */ - for (i = 0; i < N_DRIVE ; i++) { - current_drive = i; - DRS->flags = FD_VERIFY | FD_DISK_NEWCHANGE; - DRS->generation = 0; - DRS->keep_data = 0; - DRS->fd_ref = 0; - DRS->fd_device = 0; - DRWE->write_errors = 0; - DRWE->first_error_sector = 0; - DRWE->first_error_generation = 0; - DRWE->last_error_sector = 0; - DRWE->last_error_generation = 0; - DRWE->badness = 0; + for (drive = 0; drive < N_DRIVE ; drive++) { + UDRS->flags = FD_VERIFY | FD_DISK_NEWCHANGE | FD_DISK_CHANGED; + UDRS->generation = 0; + UDRS->keep_data = 0; + UDRS->fd_ref = 0; + UDRS->fd_device = 0; + UDRWE->write_errors = 0; + UDRWE->first_error_sector = 0; + UDRWE->first_error_generation = 0; + UDRWE->last_error_sector = 0; + UDRWE->last_error_generation = 0; + UDRWE->badness = 0; } - floppy_grab_irq_and_dma(); for (i = 0 ; i < N_FDC ; i++) { fdc = i; + if (FDCS->address == -1 ) + continue; FDCS->rawcmd = 2; if(user_reset_fdc(-1,FD_RESET_IF_NEEDED,0)) continue; @@ -3112,6 +3237,7 @@ void floppy_init(void) if (FDCS->version == FDC_NONE) continue; + have_no_fdc = 0; /* Not all FDCs seem to be able to handle the version command * properly, so force a reset for the standard FDC clones, * to avoid interrupt garbage. @@ -3123,6 +3249,15 @@ void floppy_init(void) current_drive = 0; floppy_release_irq_and_dma(); initialising=0; + if(have_no_fdc) + unregister_blkdev(MAJOR_NR,"fd"); + return have_no_fdc; +} + +/* stupid compatibility hack... */ +void floppy_init(void) +{ + new_floppy_init(); } static int floppy_grab_irq_and_dma(void) @@ -3134,13 +3269,15 @@ static int floppy_grab_irq_and_dma(void) return 0; } sti(); - +#ifdef FD_MODULE + MOD_INC_USE_COUNT; +#endif for(i=0; i< N_FDC; i++){ fdc = i; reset_fdc_info(1); - outb_p( FDCS->dor, FD_DOR); + outb_p(FDCS->dor, FD_DOR); } - set_dor(0, ~0, 8); /* avoid immediate interrupt */ + set_dor(0, ~0, 8); /* avoid immediate interrupt */ if (request_irq(FLOPPY_IRQ, floppy_interrupt, SA_INTERRUPT, "floppy")) { DPRINT1("Unable to grab IRQ%d for the floppy driver\n", @@ -3153,25 +3290,50 @@ static int floppy_grab_irq_and_dma(void) free_irq(FLOPPY_IRQ); return -1; } + for(fdc = 0; fdc < N_FDC ; fdc++) + if(FDCS->address != -1) + outb_p(FDCS->dor, FD_DOR); + fdc = 0; enable_irq(FLOPPY_IRQ); return 0; } static void floppy_release_irq_and_dma(void) { +#ifdef CONFIG_FLOPPY_SANITY + int drive; +#endif cli(); if (--usage_count){ sti(); return; } sti(); +#ifdef FD_MODULE + MOD_DEC_USE_COUNT; +#endif disable_dma(FLOPPY_DMA); free_dma(FLOPPY_DMA); disable_irq(FLOPPY_IRQ); free_irq(FLOPPY_IRQ); + set_dor(0, ~0, 8); #if N_FDC > 1 - if(fdc.address != -1) - set_dor(1, ~8, 0); + set_dor(1, ~8, 0); +#endif + +#ifdef CONFIG_FLOPPY_SANITY + for(drive=0; drive < N_FDC * 4; drive++) + if( motor_off_timer[drive].next ) + printk("motor off timer %d still active\n", drive); + + if(fd_timeout.next) + printk("floppy timer still active\n"); + if (fd_timer.next) + printk("auxiliary floppy timer still active\n"); + if(floppy_tq.sync) + printk("task queue still active\n"); #endif } + +#endif diff --git a/drivers/block/hd.c b/drivers/block/hd.c index a0347961b431..f6af9eaa4ec2 100644 --- a/drivers/block/hd.c +++ b/drivers/block/hd.c @@ -260,40 +260,29 @@ static unsigned int mult_req [MAX_HD] = {0,}; /* requested MultMode count static unsigned int mult_count [MAX_HD] = {0,}; /* currently enabled MultMode count */ static struct request WCURRENT; -static void fixstring(unsigned char *s, int n) +static void fixstring (unsigned char *s, int bytecount) { - int i; - unsigned short *ss = (unsigned short *) s; + unsigned char *p, *end = &s[bytecount &= ~1]; /* bytecount must be even */ /* convert from big-endian to little-endian */ - for (i = n ; (i -= 2) >= 0 ; ss++) - *ss = (*ss >> 8) | (*ss << 8); - - /* "strnlen()" */ - for (i = 0 ; i < n ; i++) { - if (!s[i]) { - n = i; - break; - } + for (p = end ; p != s;) { + unsigned short *pp = (unsigned short *) (p -= 2); + *pp = (*pp >> 8) | (*pp << 8); } - /* wipe out trailing spaces */ - while (n > 0) { - if (s[n-1] != ' ') - break; - n--; - s[n] = '\0'; - } + /* strip leading blanks */ + while (s != end && *s == ' ') + ++s; - /* wipe out leading spaces */ - if (*s == ' ') { - unsigned char *t = s; - while (n-- && *++s == ' '); - while (n-- >= 0) { - *t++ = *s; - *s++ = '\0'; - } + /* compress internal blanks and strip trailing blanks */ + while (s != end && *s) { + if (*s++ != ' ' || (s != end && *s && *s != ' ')) + *p++ = *(s-1); } + + /* wipe out trailing garbage */ + while (p != end) + *p++ = '\0'; } static void identify_intr(void) @@ -332,8 +321,8 @@ static void identify_intr(void) fixstring (id->model, sizeof(id->model)); printk (" hd%c: %.40s, %dMB w/%dKB Cache, CHS=%d/%d/%d, MaxMult=%d\n", dev+'a', id->model, id->cyls*id->heads*id->sectors/2048, - id->buf_size/2, hd_info[dev].cyl, hd_info[dev].head, - hd_info[dev].sect, id->max_multsect); + id->buf_size/2, bios_info[dev].cyl, bios_info[dev].head, + bios_info[dev].sect, id->max_multsect); /* * Early model Quantum drives go weird at this point, * but doing a recalibrate seems to "fix" them. diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 37888c37efdc..05fcf157dbdc 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -17,7 +17,7 @@ #include #include - +#include #include "blk.h" /* @@ -507,6 +507,11 @@ long blk_dev_init(long mem_start, long mem_end) #ifdef CONFIG_MCD mem_start = mcd_init(mem_start,mem_end); #endif +#ifdef CONFIG_BLK_DEV_FD + floppy_init(); +#else + outb_p(0xc, 0x3f2); +#endif #ifdef CONFIG_SBPCD mem_start = sbpcd_init(mem_start, mem_end); #endif CONFIG_SBPCD diff --git a/drivers/char/console.c b/drivers/char/console.c index d619fab63764..e21a457b8320 100644 --- a/drivers/char/console.c +++ b/drivers/char/console.c @@ -46,7 +46,8 @@ * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics * Chars, and VT100 enhancements by Peter MacDonald. * - * Copy and paste function by Andrew Haylett. + * Copy and paste function by Andrew Haylett, + * some enhancements by Alessandro Rubini. * * User definable mapping table and font loading by Eugene G. Crosser, * @@ -2337,6 +2338,8 @@ int set_selection(const int arg, struct tty_struct *tty) default: return -EINVAL; } + /* remove the pointer */ + highlight_pointer(sel_cons,-1); /* select to end of line if on trailing space */ if (new_sel_end > new_sel_start && !atedge(new_sel_end) && isspace(*(off + new_sel_end))) diff --git a/drivers/net/8390.h b/drivers/net/8390.h index f9b5ea1284e3..80f42ec63cd7 100644 --- a/drivers/net/8390.h +++ b/drivers/net/8390.h @@ -146,7 +146,7 @@ struct ei_device { #define ENTSR_COL 0x04 /* The transmit collided at least once. */ #define ENTSR_ABT 0x08 /* The transmit collided 16 times, and was deferred. */ #define ENTSR_CRS 0x10 /* The carrier sense was lost. */ -#define ENTSR_FU 0x20 /* A "FIFO underrun" occured during transmit. */ +#define ENTSR_FU 0x20 /* A "FIFO underrun" occurred during transmit. */ #define ENTSR_CDH 0x40 /* The collision detect "heartbeat" signal was lost. */ #define ENTSR_OWC 0x80 /* There was an out-of-window collision. */ diff --git a/drivers/net/apricot.c b/drivers/net/apricot.c index de840783d0c2..772649795c79 100644 --- a/drivers/net/apricot.c +++ b/drivers/net/apricot.c @@ -652,7 +652,8 @@ unsigned long apricot_init(unsigned long mem_start, unsigned long mem_end) int i; int checksum = 0; int ioaddr = 0x300; - + char eth_addr[6]; + /* this is easy the ethernet interface can only be at 0x300 */ /* first check nothing is already registered here */ @@ -668,12 +669,21 @@ unsigned long apricot_init(unsigned long mem_start, unsigned long mem_end) if (checksum % 0x100) return mem_start; - dev = init_etherdev(0, (sizeof (struct i596_private) + 0xf), &mem_start); + for(i = 0; i < 6 ; i++) + eth_addr[i] = inb(ioaddr +8 +i)); + + /* Some other boards trip the checksum.. but then appear as ether + address 0. Trap these - AC */ + + if(memcmp(eth_addr,"\x00\x00\x00\x00\x00\x00",6)==0) + return mem_addr; + + dev = init_etherdev(0, (sizeof (struct i596_private) + 0xf), &mem_start); printk("%s: Apricot 82596 at %#3x,", dev->name, ioaddr); for (i = 0; i < 6; i++) - printk(" %2.2X", dev->dev_addr[i] = inb(ioaddr +8 + i)); + printk(" %2.2X", dev->dev_addr[i] = eth_addr[i]); dev->base_addr = ioaddr; dev->irq = 10; diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c index f1ab8e5d2239..0442249d586d 100644 --- a/drivers/net/ewrk3.c +++ b/drivers/net/ewrk3.c @@ -291,7 +291,7 @@ static void ewrk3_interrupt(int reg_ptr); static int ewrk3_close(struct device *dev); static struct enet_statistics *ewrk3_get_stats(struct device *dev); static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); -static int ewrk3_ioctl(struct device *dev, struct ifreq *rq); +static int ewrk3_ioctl(struct device *dev, struct ifreq *rq, int cmd); /* ** Private functions @@ -1580,7 +1580,7 @@ static unsigned char aprom_crc(struct device *dev, unsigned char *eeprom_image, ** Perform IOCTL call functions here. Some are privileged operations and the ** effective uid is checked in those cases. */ -static int ewrk3_ioctl(struct device *dev, struct ifreq *rq) +static int ewrk3_ioctl(struct device *dev, struct ifreq *rq, int cmd) { struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv; struct ewrk3_ioctl *ioc = (struct ewrk3_ioctl *) &rq->ifr_data; diff --git a/drivers/net/hp.c b/drivers/net/hp.c index b76f590f4691..76f33f4b6f4f 100644 --- a/drivers/net/hp.c +++ b/drivers/net/hp.c @@ -275,7 +275,7 @@ hp_block_output(struct device *dev, int count, outb_p(0xff, nic_base + EN0_RSARLO); outb_p(0x00, nic_base + EN0_RSARHI); outb_p(E8390_RREAD+E8390_START, EN_CMD); - /* Make certain that the dummy read has occured. */ + /* Make certain that the dummy read has occurred. */ inb_p(0x61); inb_p(0x61); #endif diff --git a/drivers/net/ne.c b/drivers/net/ne.c index 425d00f12737..588d80915ff1 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -402,7 +402,7 @@ ne_block_output(struct device *dev, int count, outb_p(0x42, nic_base + EN0_RSARLO); outb_p(0x00, nic_base + EN0_RSARHI); outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD); - /* Make certain that the dummy read has occured. */ + /* Make certain that the dummy read has occurred. */ SLOW_DOWN_IO; SLOW_DOWN_IO; SLOW_DOWN_IO; diff --git a/drivers/net/plip.c b/drivers/net/plip.c index 183d49a2f6d2..43863e110c6a 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -186,7 +186,7 @@ static void plip_interrupt(int reg_ptr); static int plip_send(struct device *dev, enum plip_nibble_state *ns_p, unsigned char data); static void plip_send_packet(struct device *dev); -static int plip_ioctl(struct device *dev, struct ifreq *ifr); +static int plip_ioctl(struct device *dev, struct ifreq *ifr, int cmd); static int plip_config(struct device *dev, struct ifmap *map); @@ -942,7 +942,7 @@ static int plip_config(struct device *dev, struct ifmap *map) return 0; } -static int plip_ioctl(struct device *dev, struct ifreq *rq) +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; diff --git a/drivers/net/ppp.c b/drivers/net/ppp.c index 7e57d304e831..a93be1e183b2 100644 --- a/drivers/net/ppp.c +++ b/drivers/net/ppp.c @@ -94,7 +94,7 @@ static char ppp_warning[] = KERN_WARNING "PPP: ALERT! not INUSE! %d\n"; int ppp_init(struct device *); static void ppp_init_ctrl_blk(struct ppp *); static int ppp_dev_open(struct device *); -static int ppp_dev_ioctl(struct device *dev, struct ifreq *ifr); +static int ppp_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd); static int ppp_dev_close(struct device *); static void ppp_kick_tty(struct ppp *); @@ -607,7 +607,7 @@ ppp_dev_close(struct device *dev) } #ifndef NET02D -static int ppp_dev_ioctl(struct device *dev, struct ifreq *ifr) +static int ppp_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd) { struct ppp *ppp = &ppp_ctrl[dev->base_addr]; int error; diff --git a/drivers/net/sk_g16.c b/drivers/net/sk_g16.c index 550b2c0a8b1f..8f501c14d456 100644 --- a/drivers/net/sk_g16.c +++ b/drivers/net/sk_g16.c @@ -232,8 +232,8 @@ static char *rcsid = "$Id: sk_g16.c,v 1.1 1994/06/30 16:25:15 root Exp $"; #define SK_IORUN 0x20 /* - * LANCE interrupt: 0 = LANCE interrupt occured - * 1 = no LANCE interrupt occured + * LANCE interrupt: 0 = LANCE interrupt occurred + * 1 = no LANCE interrupt occurred */ #define SK_IRQ 0x10 @@ -1408,7 +1408,7 @@ static void SK_txintr(struct device *dev) * We check status of transmitted packet. * see LANCE data-sheet for error explanation */ - if (tmdstat & TX_ERR) /* Error occured */ + if (tmdstat & TX_ERR) /* Error occurred */ { printk("%s: TX error: %04x %04x\n", dev->name, (int) tmdstat, (int) tmdp->status2); @@ -1440,7 +1440,7 @@ static void SK_txintr(struct device *dev) tmdp->status2 = 0; /* Clear error flags */ } - else if (tmdstat & TX_MORE) /* Collisions occured ? */ + else if (tmdstat & TX_MORE) /* Collisions occurred ? */ { /* * Here I have a problem. diff --git a/drivers/net/slip.c b/drivers/net/slip.c index 61bc7f35b685..6d80df49a74f 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -166,7 +166,7 @@ static void sl_changedmtu(struct slip *sl) int omtu=sl->mtu; #ifdef CONFIG_AX25 - sl->mtu=dev->mtu+73 + sl->mtu=dev->mtu+73; #else sl->mtu=dev->mtu; #endif @@ -572,7 +572,7 @@ sl_open(struct device *dev) } #ifdef CONFIG_AX25 - sl->mtu = dev->mtu+73 + sl->mtu = dev->mtu+73; #else sl->mtu = dev->mtu; #endif diff --git a/drivers/scsi/53c7,8xx.c b/drivers/scsi/53c7,8xx.c index 32079646b297..24d679201c56 100644 --- a/drivers/scsi/53c7,8xx.c +++ b/drivers/scsi/53c7,8xx.c @@ -3466,7 +3466,7 @@ static void intr_dma (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) { if (dstat & DSTAT_OPC) { /* - * Ascertain if this IID interrupts occured before or after a STO + * Ascertain if this IID interrupts occurred before or after a STO * interrupt. Since the interrupt handling code now leaves * DSP unmodified until _after_ all stacked interrupts have been * processed, reading the DSP returns the original DSP register. diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 6f8765f85fee..d4500bee3de2 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -47,6 +47,11 @@ SCSI_OBJS := $(SCSI_OBJS) sg.o SCSI_SRCS := $(SCSI_SRCS) sg.c endif +ifdef CONFIG_SCSI_QLOGIC +SCSI_OBJS := $(SCSI_OBJS) qlogic.o +SCSI_SRCS := $(SCSI_SRCS) qlogic.c +endif + ifdef CONFIG_SCSI_AHA152X SCSI_OBJS := $(SCSI_OBJS) aha152x.o SCSI_SRCS := $(SCSI_SRCS) aha152x.c diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index 925a61630719..19d13b3ddea3 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -1647,7 +1647,7 @@ static int NCR5380_transfer_dma (struct Scsi_Host *instance, NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE); #else /* - * Note : on my sample board, watch-dog timeouts occured when interrupts + * Note : on my sample board, watch-dog timeouts occurred when interrupts * were not disabled for the duration of a single DMA transfer, from * before the setting of DMA mode to after transfer of the last byte. */ @@ -1971,7 +1971,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) { } /* - * The prefered transfer method is going to be + * The preferred transfer method is going to be * PSEUDO-DMA for systems that are strictly PIO, * since we can let the hardware do the handshaking. * diff --git a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h index 400c49a87095..e0a21dc33097 100644 --- a/drivers/scsi/NCR5380.h +++ b/drivers/scsi/NCR5380.h @@ -56,7 +56,7 @@ /* * The contents of the OUTPUT DATA register are asserted on the bus when - * either arbitration is occuring or the phase-indicating signals ( + * either arbitration is occurring or the phase-indicating signals ( * IO, CD, MSG) in the TARGET COMMAND register and the ASSERT DATA * bit in the INITIATOR COMMAND register is set. */ diff --git a/drivers/scsi/README.qlogic b/drivers/scsi/README.qlogic new file mode 100644 index 000000000000..62d38ad3ea1a --- /dev/null +++ b/drivers/scsi/README.qlogic @@ -0,0 +1,65 @@ + +RANDOM NOTES ON THE QLOGIC SCSI DRIVER + +This driver does NOT support the PCI version. It is a different chip. + +It DOES support the ISA, VLB, and PCMCIA versions of the Qlogic FastSCSI! +cards as well as any other card based on the chip (including the Control +Concepts SCSI/IDE/SIO/PIO/FDC cards). + +PCMCIA SUPPORT + +This currently only works if the card is enabled first from DOS. This means +you will have to load your socket and card services, and QL41DOS.SYS and +QL40ENBL.SYS. These are a minimum, but loading the rest of the modules +won't interfere with the operation. The next thing to do is load the kernel +without resetting the hardware, which can be a simple ctrl-alt-delete with +a boot floppy, or by using loadlin with the kernel image accessable from +DOS. If you are using the Linux PCMCIA driver, you will have to adjust +it or otherwise stop it from configuring the card. + +I am working with the PCMCIA group to make it more flexible, but that may +take a while. + +ALL CARDS + +The top of the qlogic.c file has a number of defines that controls +configuration. As shipped, it provides a balance between speed and +function. If there are any problems, try setting SLOW_CABLE to 1, and +then try changing USE_IRQ and TURBO_PDMA to zero. If you are familiar +with SCSI, there are other settings which can tune the bus. + +It may be a good idea to enable RESET_AT_START, especially if the devices +may not have been just powered up, or if you are restarting after a crash, +since they may be busy trying to complete the last command or something. +It comes up faster if this is set to zero, and if you have reliable +hardware and connections it may be more useful to not reset things. + +SOME TROUBLESHOOTING TIPS + +Make sure it works properly under DOS. You should also do an inital FDISK +on a new drive if you want partitions. + +Don't enable all the speedups first. If anything is wrong, they will make +any problem worse. + +IMPORTANT + +The best way to test if your cables, termination, etc. are good is to copy +a very big file (e.g. a doublespace container file, or a very large executable +or archive). It should be at least 5 megabytes, but you can do multiple tests +on smaller files. Then do a COMP to verify that the file copied properly. +(Turn off all caching when doing these tests, otherwise you will test your +RAM and not the files). Then do 10 COMPs, comparing the same file on the +SCSI hard drive, i.e. "COMP realbig.doc realbig.doc". Then do it after the +computer gets warm. + +I noticed my system which seems to work 100% would fail this test if the +computer was left on for a few hours. It was worse with longer cables, and +more devices on the SCSI bus. What seems to happen is that it gets a false +ACK causing an extra byte to be inserted into the stream (and this is not +detected). This can be caused by bad termination (the ACK can be reflected), +or by noise when the chips work less well because of the heat, or when cables +get too long for the speed. + +If it doesn't work under DOS, it won't work under Linux. diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index b1d0c8cd9eb7..4107006c5379 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -20,10 +20,17 @@ * General Public License for more details. * - * $Id: aha152x.c,v 1.4 1994/09/12 11:33:01 root Exp $ + * $Id: aha152x.c,v 1.6 1994/11/24 20:35:27 root Exp $ * * $Log: aha152x.c,v $ + * Revision 1.6 1994/11/24 20:35:27 root + * - problem with odd number of bytes in fifo fixed + * + * Revision 1.5 1994/10/30 14:39:56 root + * - abort code fixed + * - debugging improved + * * Revision 1.4 1994/09/12 11:33:01 root * - irqaction to request_irq * - abortion updated @@ -243,15 +250,18 @@ /* recently used for debugging */ #if 0 -#define DEBUG_PHASES -#define DEBUG_DATAI #endif +#define DEBUG_QUEUE +#define DEBUG_PHASES + #endif #define DEBUG_RESET /* resets should be rare */ #define DEBUG_ABORT /* aborts too */ +#define DEBUG_DEFAULT (debug_reset|debug_abort) + /* END OF DEFINES */ /* some additional "phases" for getphase() */ @@ -266,6 +276,10 @@ static int can_disconnect = 0; static int can_doparity = 0; static int commands = 0; +#ifdef DEBUG_AHA152X +unsigned int aha152x_debug = DEBUG_DEFAULT; +#endif + /* set by aha152x_setup according to the command line */ static int setup_called = 0; static int setup_portbase = 0; @@ -274,6 +288,10 @@ static int setup_scsiid = 0; static int setup_reconnect = 0; static int setup_doparity = 0; +#ifdef DEBUG_AHA152X +static int setup_debug = 0; +#endif + static char *setup_str = (char *)NULL; enum { @@ -295,8 +313,7 @@ static Scsi_Cmnd *issue_SC = NULL; static Scsi_Cmnd *current_SC = NULL; static Scsi_Cmnd *disconnected_SC = NULL; -static struct wait_queue *abortion_complete; -static int abort_result; +static int aborting=0, abortion_complete=0, abort_result; void aha152x_intr( int irqno ); void aha152x_done( int error ); @@ -328,7 +345,7 @@ static void *addresses[] = (void *) 0xf0000, (void *) 0xeb800, /* VTech Platinum SMP */ }; -#define ADDRESS_COUNT (sizeof( addresses ) / sizeof( unsigned )) +#define ADDRESS_COUNT (sizeof( addresses ) / sizeof( void * )) /* possible i/o addresses for the AIC-6260 */ static unsigned short ports[] = @@ -494,6 +511,9 @@ void aha152x_setup( char *str, int *ints) setup_scsiid = ints[0] >= 3 ? ints[3] : 7; setup_reconnect = ints[0] >= 4 ? ints[4] : 1; setup_doparity = ints[0] >= 5 ? ints[5] : 1; +#ifdef DEBUG_AHA152X + setup_debug = ints[0] >= 6 ? ints[6] : DEBUG_DEFAULT; +#endif } /* @@ -527,10 +547,18 @@ int aha152x_detect(Scsi_Host_Template * tpnt) { printk("aha152x: processing commandline: "); +#ifdef DEBUG_AHA152X + if(setup_called>6) +#else if(setup_called>5) +#endif { printk("\naha152x: %s\n", setup_str ); +#ifdef DEBUG_AHA152X + printk("aha152x: usage: aha152x=[,[,[,[,[,]]]]]\n"); +#else printk("aha152x: usage: aha152x=[,[,[,[,]]]]\n"); +#endif panic("aha152x panics in line %d", __LINE__); } @@ -539,6 +567,9 @@ int aha152x_detect(Scsi_Host_Template * tpnt) this_host = setup_scsiid; can_disconnect = setup_reconnect; can_doparity = setup_doparity; +#ifdef DEBUG_AHA152X + aha152x_debug = setup_debug; +#endif for( i=0; itarget, - SCpnt->lun, - *(unsigned char *)SCpnt->cmnd, - SCpnt->use_sg, - SCpnt->request_bufflen ); - disp_ports(); + if(aha152x_debug & debug_queue) + { + printk( "SCpnt (target = %d lun = %d cmnd = ", + SCpnt->target, + SCpnt->lun); + print_command(SCpnt->cmnd); + printk( ", pieces = %d size = %u), ", + SCpnt->use_sg, + SCpnt->request_bufflen ); + disp_ports(); + } #endif SCpnt->scsi_done = done; @@ -771,7 +806,8 @@ int aha152x_queue( Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *)) SETPORT( PORTA, 1 ); #if defined(DEBUG_QUEUES) - printk("i+ (%d), ", commands ); + if(aha152x_debug & debug_queues) + printk("i+ (%d), ", commands ); #endif append_SC( &issue_SC, SCpnt); @@ -810,11 +846,12 @@ int aha152x_abort( Scsi_Cmnd *SCpnt) cli(); #if defined(DEBUG_ABORT) - printk("aha152x: abort(), SCpnt=0x%08x, ", (unsigned int) SCpnt ); -#endif + if(aha152x_debug & debug_abort) + { + printk("aha152x: abort(), SCpnt=0x%08x, ", (unsigned int) SCpnt ); -#if defined(DEBUG_ABORT) - show_queues(); + show_queues(); + } #endif /* look for command in issue queue */ @@ -838,24 +875,30 @@ int aha152x_abort( Scsi_Cmnd *SCpnt) return SCSI_ABORT_SUCCESS; } - if (!current_SC && TESTLO(SSTAT1, BUSFREE)) - printk("bus busy w/o current command, "); + /* if the bus is busy or a command is currently processed, + we can't do anything more */ + if ( TESTLO(SSTAT1, BUSFREE) || (current_SC && current_SC!=SCpnt)) + { + /* fail abortion, if bus is busy */ - if (current_SC==SCpnt) - if( TESTLO(SSTAT1, BUSFREE) ) { - /* fail abortion, if current command is on the bus */ + if(!current_SC) + printk("bus busy w/o current command, "); + sti(); return SCSI_ABORT_BUSY; } - else - { - /* target entered bus free before COMMAND COMPLETE, nothing to abort */ - sti(); - current_SC->result = DID_ERROR << 16; - current_SC->done(current_SC); - current_SC = (Scsi_Cmnd *) NULL; - return SCSI_ABORT_SUCCESS; - } + + /* bus is free */ + + if(current_SC) + { + /* target entered bus free before COMMAND COMPLETE, nothing to abort */ + sti(); + current_SC->result = DID_ERROR << 16; + current_SC->done(current_SC); + current_SC = (Scsi_Cmnd *) NULL; + return SCSI_ABORT_SUCCESS; + } /* look for command in disconnected queue */ for( ptr=disconnected_SC, prev=NULL; @@ -864,40 +907,45 @@ int aha152x_abort( Scsi_Cmnd *SCpnt) ; if(ptr) - if( TESTHI(SSTAT1, BUSFREE) ) - { - /* dequeue */ - if(prev) - prev->host_scribble = ptr->host_scribble; - else - disconnected_SC = (Scsi_Cmnd *) ptr->host_scribble; - - /* set command current and initiate selection, - let the interrupt routine take care of the abortion */ - current_SC = ptr; - ptr->SCp.phase = in_selection|aborted; - SETPORT( SCSIID, (this_host << OID_) | current_SC->target ); - - /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */ - SETPORT( SIMODE0, ENSELDO | (disconnected_SC ? ENSELDI : 0) ); - SETPORT( SIMODE1, ENSELTIMO ); - - /* Enable SELECTION OUT sequence */ - SETBITS(SCSISEQ, ENSELO | ENAUTOATNO ); - - SETBITS( DMACNTRL0, INTEN ); - abort_result=SCSI_ABORT_SUCCESS; - sti(); - - /* sleep until the abortion is complete */ - sleep_on( &abortion_complete ); - return abort_result; - } - else { - /* fail abortion, if we can't abort the disconnected command */ - sti(); - return SCSI_ABORT_BUSY; - } + if(!aborting) + { + /* dequeue */ + if(prev) + prev->host_scribble = ptr->host_scribble; + else + disconnected_SC = (Scsi_Cmnd *) ptr->host_scribble; + + /* set command current and initiate selection, + let the interrupt routine take care of the abortion */ + current_SC = ptr; + ptr->SCp.phase = in_selection|aborted; + SETPORT( SCSIID, (this_host << OID_) | current_SC->target ); + + /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */ + SETPORT( SIMODE0, ENSELDO | (disconnected_SC ? ENSELDI : 0) ); + SETPORT( SIMODE1, ENSELTIMO ); + + /* Enable SELECTION OUT sequence */ + SETBITS(SCSISEQ, ENSELO | ENAUTOATNO ); + + SETBITS( DMACNTRL0, INTEN ); + abort_result=SCSI_ABORT_SUCCESS; + aborting++; + abortion_complete=0; + sti(); + + /* sleep until the abortion is complete */ + while(!abortion_complete) + ; + aborting=0; + return abort_result; + } + else + { + /* we're already aborting a command */ + sti(); + return( SCSI_ABORT_BUSY ); + } /* command wasn't found */ printk("command not found\n"); @@ -954,12 +1002,12 @@ int aha152x_reset(Scsi_Cmnd * __unused) { CLRBITS( DMACNTRL0, INTEN ); -#if defined( DEBUG_RESET ) +#if defined(DEBUG_RESET) + if(aha152x_debug & debug_reset) + { printk("aha152x: reset(), bus not free: SCSI RESET OUT\n"); -#endif - -#if defined( DEBUG_RESET ) show_queues(); + } #endif if(current_SC && !current_SC->device->soft_reset) @@ -998,8 +1046,11 @@ int aha152x_reset(Scsi_Cmnd * __unused) sti(); #if defined( DEBUG_RESET ) - printk("commands on targets w/ soft-resets:\n"); - show_queues(); + if(aha152x_debug & debug_reset) + { + printk("commands on targets w/ soft-resets:\n"); + show_queues(); + } #endif /* RESET OUT */ @@ -1023,8 +1074,10 @@ int aha152x_reset(Scsi_Cmnd * __unused) int aha152x_biosparam(Scsi_Disk * disk, int dev, int *info_array ) { int size = disk->capacity; + #if defined(DEBUG_BIOSPARAM) - printk("aha152x_biosparam: dev=%x, size=%d, ", dev, size); + if(aha152x_debug & debug_biosparam) + printk("aha152x_biosparam: dev=%x, size=%d, ", dev, size); #endif /* I took this from other SCSI drivers, since it provides @@ -1034,9 +1087,12 @@ int aha152x_biosparam(Scsi_Disk * disk, int dev, int *info_array ) info_array[2]=size>>11; #if defined(DEBUG_BIOSPARAM) - printk("bios geometry: head=%d, sec=%d, cyl=%d\n", - info_array[0], info_array[1], info_array[2]); - printk("WARNING: check, if the bios geometry is correct.\n"); + if(aha152x_debug & debug_biosparam) + { + printk("bios geometry: head=%d, sec=%d, cyl=%d\n", + info_array[0], info_array[1], info_array[2]); + printk("WARNING: check, if the bios geometry is correct.\n"); + } #endif return 0; @@ -1050,14 +1106,18 @@ void aha152x_done( int error ) Scsi_Cmnd *done_SC; #if defined(DEBUG_DONE) - printk("\naha152x: done(), "); - disp_ports(); + if(aha152x_debug & debug_done) + { + printk("\naha152x: done(), "); + disp_ports(); + } #endif if (current_SC) { #if defined(DEBUG_DONE) - printk("done(%x), ", error); + if(aha152x_debug & debug_done) + printk("done(%x), ", error); #endif cli(); @@ -1071,7 +1131,8 @@ void aha152x_done( int error ) SETPORT( PORTA, 0 ); /* turn led off */ #if defined(DEBUG_QUEUES) - printk("ok (%d), ", commands); + if(aha152x_debug & debug_queues) + printk("ok (%d), ", commands); #endif sti(); @@ -1079,23 +1140,27 @@ void aha152x_done( int error ) SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0); #if defined(DEBUG_PHASES) - printk("BUS FREE loop, "); + if(aha152x_debug & debug_phases) + printk("BUS FREE loop, "); #endif while( TESTLO( SSTAT1, BUSFREE ) ) ; #if defined(DEBUG_PHASES) - printk("BUS FREE\n"); + if(aha152x_debug & debug_phases) + printk("BUS FREE\n"); #endif done_SC->result = error; if(done_SC->scsi_done) { #if defined(DEBUG_DONE) - printk("calling scsi_done, "); + if(aha152x_debug & debug_done) + printk("calling scsi_done, "); #endif done_SC->scsi_done( done_SC ); #if defined(DEBUG_DONE) - printk("done returned, "); + if(aha152x_debug & debug_done) + printk("done returned, "); #endif } else @@ -1116,7 +1181,8 @@ void aha152x_intr( int irqno ) enter_driver("intr"); #else #if defined(DEBUG_INTR) - printk("\naha152x: intr(), "); + if(aha152x_debug & debug_intr) + printk("\naha152x: intr(), "); #endif #endif @@ -1143,6 +1209,7 @@ void aha152x_intr( int irqno ) if(current_SC) { #if defined(DEBUG_QUEUES) + if(aha152x_debug & debug_queues) printk("i+, "); #endif cli(); @@ -1157,7 +1224,8 @@ void aha152x_intr( int irqno ) SETPORT( SSTAT1, CLRBUSFREE ); #if defined(DEBUG_QUEUES) || defined(DEBUG_PHASES) - printk("reselected, "); + if(aha152x_debug & (debug_queues|debug_phases)) + printk("reselected, "); #endif i = GETPORT(SELID) & ~(1 << this_host); @@ -1169,7 +1237,8 @@ void aha152x_intr( int irqno ) aha152x_panic("reconnecting target unknown"); #if defined(DEBUG_QUEUES) - printk("SELID=%02x, target=%d, ", GETPORT(SELID), target ); + if(aha152x_debug & debug_queues) + printk("SELID=%02x, target=%d, ", GETPORT(SELID), target ); #endif SETPORT( SCSIID, (this_host << OID_) | target ); SETPORT( SCSISEQ, ENRESELI ); @@ -1202,12 +1271,14 @@ void aha152x_intr( int irqno ) getphase(); #if defined(DEBUG_QUEUES) - printk("identify=%02x, lun=%d, ", identify_msg, identify_msg & 0x3f ); + if(aha152x_debug & debug_queues) + printk("identify=%02x, lun=%d, ", identify_msg, identify_msg & 0x3f ); #endif cli(); #if defined(DEBUG_QUEUES) - printk("d-, "); + if(aha152x_debug & debug_queues) + printk("d-, "); #endif current_SC = remove_SC( &disconnected_SC, target, @@ -1239,18 +1310,21 @@ void aha152x_intr( int irqno ) { cli(); #if defined(DEBUG_QUEUES) - printk("i-, "); + if(aha152x_debug & debug_queues) + printk("i-, "); #endif current_SC = remove_first_SC( &issue_SC ); sti(); #if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES) - printk("issuing command, "); + if(aha152x_debug & (debug_intr|debug_selection|debug_phases)) + printk("issuing command, "); #endif current_SC->SCp.phase = in_selection; #if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES) - printk("selecting %d, ", current_SC->target); + if(aha152x_debug & (debug_intr|debug_selection|debug_phases)) + printk("selecting %d, ", current_SC->target); #endif SETPORT( SCSIID, (this_host << OID_) | current_SC->target ); @@ -1279,7 +1353,8 @@ void aha152x_intr( int irqno ) /* the bus is busy with something */ #if defined(DEBUG_INTR) - disp_ports(); + if(aha152x_debug & debug_intr) + disp_ports(); #endif /* we are waiting for the result of a selection attempt */ @@ -1311,21 +1386,22 @@ void aha152x_intr( int irqno ) if(current_SC->SCp.phase & aborted) { abort_result=SCSI_ABORT_ERROR; - wake_up( &abortion_complete ); + abortion_complete++; } aha152x_done( DID_NO_CONNECT << 16 ); return; } #if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES) - printk("SELDO (SELID=%x), ", GETPORT(SELID)); + if(aha152x_debug & (debug_selection|debug_phases)) + printk("SELDO (SELID=%x), ", GETPORT(SELID)); #endif /* selection was done */ SETPORT( SSTAT0, CLRSELDO ); #if defined(DEBUG_ABORT) - if(current_SC->SCp.phase & aborted) + if((aha152x_debug & debug_abort) && (current_SC->SCp.phase & aborted)) printk("(ABORT) target selected, "); #endif @@ -1348,6 +1424,7 @@ void aha152x_intr( int irqno ) else { #if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES) + if(aha152x_debug & (debug_selection|debug_phases)) printk("SELTO, "); #endif /* end selection attempt */ @@ -1366,10 +1443,11 @@ void aha152x_intr( int irqno ) if(current_SC->SCp.phase & aborted) { #if defined(DEBUG_ABORT) - printk("(ABORT) selection timeout, "); + if(aha152x_debug & debug_abort) + printk("(ABORT) selection timeout, "); #endif abort_result=SCSI_ABORT_ERROR; - wake_up( &abortion_complete ); + abortion_complete++; } if( TESTLO( SSTAT0, SELINGO ) ) @@ -1398,13 +1476,15 @@ void aha152x_intr( int irqno ) unsigned char message; #if defined(DEBUG_INTR) || defined(DEBUG_MSGO) || defined(DEBUG_PHASES) - printk("MESSAGE OUT, "); + if(aha152x_debug & (debug_intr|debug_msgo|debug_phases)) + printk("MESSAGE OUT, "); #endif if( current_SC->SCp.phase & aborted ) { #if defined(DEBUG_MSGO) || defined(DEBUG_ABORT) - printk("ABORT, "); + if(aha152x_debug & (debug_msgo|debug_abort)) + printk("ABORT, "); #endif message=ABORT; } @@ -1416,15 +1496,17 @@ void aha152x_intr( int irqno ) { message=IDENTIFY(can_disconnect,current_SC->lun); #if defined(DEBUG_MSGO) - printk("IDENTIFY (reconnect=%s;lun=%d), ", - can_disconnect ? "enabled" : "disabled", current_SC->lun); + if(aha152x_debug & debug_msgo) + printk("IDENTIFY (reconnect=%s;lun=%d), ", + can_disconnect ? "enabled" : "disabled", current_SC->lun); #endif } else { message=MESSAGE_REJECT; #if defined(DEBUG_MSGO) - printk("REJECT, "); + if(aha152x_debug & debug_msgo) + printk("REJECT, "); #endif } @@ -1455,7 +1537,7 @@ void aha152x_intr( int irqno ) { /* revive abort(); abort() enables interrupts */ abort_result=SCSI_ABORT_SUCCESS; - wake_up( &abortion_complete ); + abortion_complete++; current_SC->SCp.phase = (current_SC->SCp.phase & ~(P_MASK<<16)); @@ -1472,7 +1554,8 @@ void aha152x_intr( int irqno ) case P_CMD: /* COMMAND phase */ #if defined(DEBUG_INTR) || defined(DEBUG_CMD) || defined(DEBUG_PHASES) - printk("COMMAND, "); + if(aha152x_debug & (debug_intr|debug_cmd|debug_phases)) + printk("COMMAND, "); #endif if( !(current_SC->SCp.sent_command) ) { @@ -1493,7 +1576,8 @@ void aha152x_intr( int irqno ) SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE ); #if defined(DEBUG_CMD) - printk("waiting, "); + if(aha152x_debug & debug_cmd) + printk("waiting, "); #endif /* wait for FIFO to get empty */ while( TESTLO ( DMASTAT, DFIFOEMP|INTSTAT ) ) @@ -1503,9 +1587,12 @@ void aha152x_intr( int irqno ) aha152x_panic("target left COMMAND phase"); #if defined(DEBUG_CMD) - printk("DFIFOEMP, outsw (%d words), ", - COMMAND_SIZE(current_SC->cmnd[0])>>1); - disp_ports(); + if(aha152x_debug & debug_cmd) + { + printk("DFIFOEMP, outsw (%d words), ", + COMMAND_SIZE(current_SC->cmnd[0])>>1); + disp_ports(); + } #endif outsw( DATAPORT, @@ -1513,8 +1600,11 @@ void aha152x_intr( int irqno ) COMMAND_SIZE(current_SC->cmnd[0])>>1 ); #if defined(DEBUG_CMD) - printk("FCNT=%d, STCNT=%d, ", GETPORT(FIFOSTAT), GETSTCNT() ); - disp_ports(); + if(aha152x_debug & debug_cmd) + { + printk("FCNT=%d, STCNT=%d, ", GETPORT(FIFOSTAT), GETSTCNT() ); + disp_ports(); + } #endif /* wait for SCSI FIFO to get empty. @@ -1530,8 +1620,9 @@ void aha152x_intr( int irqno ) CLRBITS(DMACNTRL0, ENDMA); #if defined(DEBUG_CMD) || defined(DEBUG_INTR) - printk("sent %d/%d command bytes, ", GETSTCNT(), - COMMAND_SIZE(current_SC->cmnd[0])); + if(debug_cmd & debug_intr) + printk("sent %d/%d command bytes, ", GETSTCNT(), + COMMAND_SIZE(current_SC->cmnd[0])); #endif } @@ -1541,7 +1632,8 @@ void aha152x_intr( int irqno ) case P_MSGI: /* MESSAGE IN phase */ #if defined(DEBUG_INTR) || defined(DEBUG_MSGI) || defined(DEBUG_PHASES) - printk("MESSAGE IN, "); + if(aha152x_debug & (debug_intr|debug_msgi|debug_phases)) + printk("MESSAGE IN, "); #endif SETPORT( SXFRCTL0, CH1); @@ -1555,7 +1647,8 @@ void aha152x_intr( int irqno ) { case DISCONNECT: #if defined(DEBUG_MSGI) || defined(DEBUG_PHASES) - printk("target disconnected, "); + if(aha152x_debug & (debug_msgi|debug_phases)) + printk("target disconnected, "); #endif current_SC->SCp.Message = 0; current_SC->SCp.phase |= disconnected; @@ -1565,20 +1658,23 @@ void aha152x_intr( int irqno ) case COMMAND_COMPLETE: #if defined(DEBUG_MSGI) || defined(DEBUG_PHASES) - printk("inbound message ( COMMAND COMPLETE ), "); + if(aha152x_debug & (debug_msgi|debug_phases)) + printk("inbound message ( COMMAND COMPLETE ), "); #endif done++; break; case MESSAGE_REJECT: -#if defined(DEBUG_MSGI) || defined(DEBUG_TIMING) - printk("inbound message ( MESSAGE REJECT ), "); +#if defined(DEBUG_MSGI) + if(aha152x_debug & debug_msgi) + printk("inbound message ( MESSAGE REJECT ), "); #endif break; case SAVE_POINTERS: #if defined(DEBUG_MSGI) - printk("inbound message ( SAVE DATA POINTERS ), "); + if(aha152x_debug & debug_msgi) + printk("inbound message ( SAVE DATA POINTERS ), "); #endif break; @@ -1587,7 +1683,8 @@ void aha152x_intr( int irqno ) int i, code; #if defined(DEBUG_MSGI) - printk("inbound message ( EXTENDED MESSAGE ), "); + if(aha152x_debug & debug_msgi) + printk("inbound message ( EXTENDED MESSAGE ), "); #endif make_acklow(); if(getphase()!=P_MSGI) @@ -1596,11 +1693,8 @@ void aha152x_intr( int irqno ) i=GETPORT(SCSIBUS); #if defined(DEBUG_MSGI) - printk("length (%d), ", i); -#endif - -#if defined(DEBUG_MSGI) - printk("code ( "); + if(aha152x_debug & debug_msgi) + printk("length (%d), code ( ", i); #endif make_acklow(); @@ -1613,50 +1707,58 @@ void aha152x_intr( int irqno ) { case 0x00: #if defined(DEBUG_MSGI) - printk("MODIFY DATA POINTER "); + if(aha152x_debug & debug_msgi) + printk("MODIFY DATA POINTER "); #endif SETPORT(SCSISIG, P_MSGI|ATNO); break; case 0x01: #if defined(DEBUG_MSGI) - printk("SYNCHRONOUS DATA TRANSFER REQUEST "); + if(aha152x_debug & debug_msgi) + printk("SYNCHRONOUS DATA TRANSFER REQUEST "); #endif SETPORT(SCSISIG, P_MSGI|ATNO); break; case 0x02: #if defined(DEBUG_MSGI) - printk("EXTENDED IDENTIFY "); + if(aha152x_debug & debug_msgi) + printk("EXTENDED IDENTIFY "); #endif break; case 0x03: #if defined(DEBUG_MSGI) - printk("WIDE DATA TRANSFER REQUEST "); + if(aha152x_debug & debug_msgi) + printk("WIDE DATA TRANSFER REQUEST "); #endif SETPORT(SCSISIG, P_MSGI|ATNO); break; default: #if defined(DEBUG_MSGI) - if( code & 0x80 ) - printk("reserved (%d) ", code ); - else - printk("vendor specific (%d) ", code); + if(aha152x_debug & debug_msgi) + if( code & 0x80 ) + printk("reserved (%d) ", code ); + else + printk("vendor specific (%d) ", code); #endif SETPORT(SCSISIG, P_MSGI|ATNO); break; } #if defined(DEBUG_MSGI) - printk(" ), data ( "); + if(aha152x_debug & debug_msgi) + printk(" ), data ( "); #endif while( --i && (make_acklow(), getphase()==P_MSGI)) { #if defined(DEBUG_MSGI) - printk("%x ", GETPORT(SCSIBUS) ); + if(aha152x_debug & debug_msgi) + printk("%x ", GETPORT(SCSIBUS) ); #else GETPORT(SCSIBUS); #endif } #if defined(DEBUG_MSGI) - printk(" ), "); + if(aha152x_debug & debug_msgi) + printk(" ), "); #endif /* We reject all extended messages. To do this we just enter MSGO by asserting ATN. Since @@ -1684,7 +1786,8 @@ void aha152x_intr( int irqno ) { cli(); #if defined(DEBUG_QUEUES) - printk("d+, "); + if(aha152x_debug & debug_queues) + printk("d+, "); #endif append_SC( &disconnected_SC, current_SC); current_SC = NULL; @@ -1702,7 +1805,8 @@ void aha152x_intr( int irqno ) case P_STATUS: /* STATUS IN phase */ #if defined(DEBUG_STATUS) || defined(DEBUG_INTR) || defined(DEBUG_PHASES) - printk("STATUS, "); + if(aha152x_debug & (debug_status|debug_intr|debug_phases)) + printk("STATUS, "); #endif SETPORT( SXFRCTL0, CH1); @@ -1717,9 +1821,12 @@ void aha152x_intr( int irqno ) getphase(); #if defined(DEBUG_STATUS) - printk("inbound status "); - print_status( current_SC->SCp.Status ); - printk(", "); + if(aha152x_debug & debug_status) + { + printk("inbound status "); + print_status( current_SC->SCp.Status ); + printk(", "); + } #endif break; @@ -1728,7 +1835,8 @@ void aha152x_intr( int irqno ) int fifodata, data_count, done; #if defined(DEBUG_DATAI) || defined(DEBUG_INTR) || defined(DEBUG_PHASES) - printk("DATA IN, "); + if(aha152x_debug & (debug_datai|debug_intr|debug_phases)) + printk("DATA IN, "); #endif if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT)) @@ -1751,7 +1859,8 @@ void aha152x_intr( int irqno ) while ( !done ) { #if defined(DEBUG_DATAI) - printk("expecting data, "); + if(aha152x_debug & debug_datai) + printk("expecting data, "); #endif /* wait for PHASEMIS or full FIFO */ while( TESTLO ( DMASTAT, DFIFOFULL|INTSTAT ) ) @@ -1768,13 +1877,15 @@ void aha152x_intr( int irqno ) /* rest of data in FIFO */ fifodata=GETPORT(FIFOSTAT); #if defined(DEBUG_DATAI) - printk("last transfer, "); + if(aha152x_debug & debug_datai) + printk("last transfer, "); #endif done=1; } #if defined(DEBUG_DATAI) - printk("fifodata=%d, ", fifodata); + if(aha152x_debug & debug_datai) + printk("fifodata=%d, ", fifodata); #endif while( fifodata && current_SC->SCp.this_residual ) @@ -1788,35 +1899,37 @@ void aha152x_intr( int irqno ) fifodata -= data_count; #if defined(DEBUG_DATAI) - printk("data_count=%d, ", data_count); + if(aha152x_debug & debug_datai) + printk("data_count=%d, ", data_count); #endif - if(data_count == 1) + if(data_count&1) { /* get a single byte in byte mode */ SETBITS(DMACNTRL0, _8BIT ); *current_SC->SCp.ptr++ = GETPORT( DATAPORT ); current_SC->SCp.this_residual--; } - else + if(data_count>1) { CLRBITS(DMACNTRL0, _8BIT ); data_count >>= 1; /* Number of words */ insw( DATAPORT, current_SC->SCp.ptr, data_count ); #if defined(DEBUG_DATAI) + if(aha152x_debug & debug_datai) /* show what comes with the last transfer */ - if(done) - { - int i; - unsigned char *data; - - printk("data on last transfer (%d bytes: ", - 2*data_count); - data = (unsigned char *) current_SC->SCp.ptr; - for( i=0; i<2*data_count; i++) - printk("%2x ", *data++); - printk("), "); - } + if(done) + { + int i; + unsigned char *data; + + printk("data on last transfer (%d bytes: ", + 2*data_count); + data = (unsigned char *) current_SC->SCp.ptr; + for( i=0; i<2*data_count; i++) + printk("%2x ", *data++); + printk("), "); + } #endif current_SC->SCp.ptr += 2 * data_count; current_SC->SCp.this_residual -= 2 * data_count; @@ -1851,15 +1964,16 @@ void aha152x_intr( int irqno ) } #if defined(DEBUG_DATAI) - if(!fifodata) - printk("fifo empty, "); - else - printk("something left in fifo, "); + if(aha152x_debug & debug_datai) + if(!fifodata) + printk("fifo empty, "); + else + printk("something left in fifo, "); #endif } #if defined(DEBUG_DATAI) - if(current_SC->SCp.buffers_residual || current_SC->SCp.this_residual) + if((aha152x_debug & debug_datai) && (current_SC->SCp.buffers_residual || current_SC->SCp.this_residual)) printk("left buffers (buffers=%d, bytes=%d), ", current_SC->SCp.buffers_residual, current_SC->SCp.this_residual); @@ -1871,7 +1985,8 @@ void aha152x_intr( int irqno ) CLRBITS(DMACNTRL0, ENDMA ); #if defined(DEBUG_DATAI) || defined(DEBUG_INTR) - printk("got %d bytes, ", GETSTCNT()); + if(aha152x_debug & (debug_datai|debug_intr)) + printk("got %d bytes, ", GETSTCNT()); #endif current_SC->SCp.have_data_in++; @@ -1883,12 +1998,14 @@ void aha152x_intr( int irqno ) int data_count; #if defined(DEBUG_DATAO) || defined(DEBUG_INTR) || defined(DEBUG_PHASES) - printk("DATA OUT, "); + if(aha152x_debug & (debug_datao|debug_intr|debug_phases)) + printk("DATA OUT, "); #endif #if defined(DEBUG_DATAO) - printk("got data to send (bytes=%d, buffers=%d), ", - current_SC->SCp.this_residual, - current_SC->SCp.buffers_residual ); + if(aha152x_debug & debug_datao) + printk("got data to send (bytes=%d, buffers=%d), ", + current_SC->SCp.this_residual, + current_SC->SCp.buffers_residual ); #endif if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT) ) @@ -1913,26 +2030,28 @@ void aha152x_intr( int irqno ) current_SC->SCp.buffers_residual) ) { #if defined(DEBUG_DATAO) - printk("sending data (left: bytes=%d, buffers=%d), waiting, ", - current_SC->SCp.this_residual, - current_SC->SCp.buffers_residual); + if(aha152x_debug & debug_datao) + printk("sending data (left: bytes=%d, buffers=%d), waiting, ", + current_SC->SCp.this_residual, + current_SC->SCp.buffers_residual); #endif /* transfer rest of buffer, but max. 128 byte */ data_count = current_SC->SCp.this_residual > 128 ? 128 : current_SC->SCp.this_residual ; #if defined(DEBUG_DATAO) - printk("data_count=%d, ", data_count); + if(aha152x_debug & debug_datao) + printk("data_count=%d, ", data_count); #endif - if(data_count == 1) + if(data_count&1) { /* put a single byte in byte mode */ SETBITS(DMACNTRL0, _8BIT ); SETPORT(DATAPORT, *current_SC->SCp.ptr++); current_SC->SCp.this_residual--; } - else + if(data_count>1) { CLRBITS(DMACNTRL0, _8BIT ); data_count >>= 1; /* Number of words */ @@ -1946,8 +2065,9 @@ void aha152x_intr( int irqno ) ; #if defined(DEBUG_DATAO) - printk("fifo (%d bytes), transfered (%d bytes), ", - GETPORT(FIFOSTAT), GETSTCNT() ); + if(aha152x_debug & debug_datao) + printk("fifo (%d bytes), transfered (%d bytes), ", + GETPORT(FIFOSTAT), GETSTCNT() ); #endif /* if this buffer is empty and there are more buffers left */ @@ -1978,10 +2098,11 @@ void aha152x_intr( int irqno ) current_SC->SCp.ptr -= data_count; current_SC->SCp.this_residual += data_count; #if defined(DEBUG_DATAO) - printk("left data (bytes=%d, buffers=%d), fifos (bytes=%d), transfer incomplete, resetting fifo, ", - current_SC->SCp.this_residual, - current_SC->SCp.buffers_residual, - data_count ); + if(aha152x_debug & debug_datao) + printk("left data (bytes=%d, buffers=%d), fifos (bytes=%d), transfer incomplete, resetting fifo, ", + current_SC->SCp.this_residual, + current_SC->SCp.buffers_residual, + data_count ); #endif SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO); CLRBITS(SXFRCTL0, SCSIEN|DMAEN ); @@ -1990,19 +2111,17 @@ void aha152x_intr( int irqno ) else { #if defined(DEBUG_DATAO) - printk("waiting for SCSI fifo to get empty, "); + if(aha152x_debug & debug_datao) + printk("waiting for SCSI fifo to get empty, "); #endif /* wait for SCSI fifo to get empty */ while( TESTLO( SSTAT2, SEMPTY ) ) ; #if defined(DEBUG_DATAO) - printk("ok, "); -#endif - -#if defined(DEBUG_DATAO) - printk("left data (bytes=%d, buffers=%d) ", - current_SC->SCp.this_residual, - current_SC->SCp.buffers_residual); + if(aha152x_debug & debug_datao) + printk("ok, left data (bytes=%d, buffers=%d) ", + current_SC->SCp.this_residual, + current_SC->SCp.buffers_residual); #endif CLRBITS(SXFRCTL0, SCSIEN|DMAEN); @@ -2014,7 +2133,8 @@ void aha152x_intr( int irqno ) } #if defined(DEBUG_DATAO) || defined(DEBUG_INTR) - printk("sent %d data bytes, ", GETSTCNT() ); + if(aha152x_debug & (debug_datao|debug_intr)) + printk("sent %d data bytes, ", GETSTCNT() ); #endif } break; @@ -2024,7 +2144,8 @@ void aha152x_intr( int irqno ) leave_driver("(BUSFREE) intr"); #endif #if defined(DEBUG_PHASES) - printk("unexpected BUS FREE, "); + if(aha152x_debug & debug_phases) + printk("unexpected BUS FREE, "); #endif current_SC->SCp.phase = (current_SC->SCp.phase & ~(P_MASK<<16)); @@ -2053,7 +2174,8 @@ void aha152x_intr( int irqno ) if(done) { #if defined(DEBUG_INTR) - printk("command done.\n"); + if(aha152x_debug & debug_intr) + printk("command done.\n"); #endif #if defined(DEBUG_RACE) leave_driver("(done) intr"); @@ -2082,7 +2204,8 @@ void aha152x_intr( int irqno ) SETPORT( SIMODE0, 0 ); SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE ); #if defined(DEBUG_INTR) - disp_enintr(); + if(aha152x_debug & debug_intr) + disp_enintr(); #endif #if defined(DEBUG_RACE) leave_driver("(PHASEEND) intr"); @@ -2107,9 +2230,12 @@ static void aha152x_panic(char *msg) */ static void disp_ports(void) { -#if !defined(SKIP_PORTS) +#ifdef DEBUG_AHA152X int s; + if(aha152x_debug & debug_skipports) + return; + printk("\n%s: ", current_SC ? "on bus" : "waiting"); s=GETPORT(SCSISEQ); @@ -2354,13 +2480,10 @@ static void leave_driver(const char *func) */ static void show_command(Scsi_Cmnd *ptr) { - int i; - printk("0x%08x: target=%d; lun=%d; cmnd=( ", (unsigned int) ptr, ptr->target, ptr->lun); - for(i=0; icmnd[0]); i++) - printk("%02x ", ptr->cmnd[i]); + print_command(ptr->cmnd); printk("); residual=%d; buffers=%d; phase |", ptr->SCp.this_residual, ptr->SCp.buffers_residual); diff --git a/drivers/scsi/aha152x.h b/drivers/scsi/aha152x.h index 4a045918bf56..09cf73b2ea7d 100644 --- a/drivers/scsi/aha152x.h +++ b/drivers/scsi/aha152x.h @@ -2,12 +2,13 @@ #define _AHA152X_H /* - * $Id: aha152x.h,v 1.4 1994/09/12 11:32:41 root Exp $ + * $Id: aha152x.h,v 1.6 1994/11/24 21:35:38 root Exp root $ */ +#if defined(__KERNEL__) + #include "../block/blk.h" #include "scsi.h" -#if defined(__KERNEL__) #include int aha152x_detect(Scsi_Host_Template *); @@ -22,7 +23,7 @@ int aha152x_biosparam(Disk *, int, int*); (unless we support more than 1 cmd_per_lun this should do) */ #define AHA152X_MAXQUEUE 7 -#define AHA152X_REVID "Adaptec 152x SCSI driver; $Revision: 1.4 $" +#define AHA152X_REVID "Adaptec 152x SCSI driver; $Revision: 1.6 $" /* Initial value of Scsi_Host entry */ #define AHA152X { /* next */ NULL, \ @@ -336,4 +337,25 @@ typedef union { #define TESTLO(PORT, BITS) \ ((inb(PORT) & (BITS)) == 0) +#ifdef DEBUG_AHA152X +enum { + debug_skipports =0x0001, + debug_queue =0x0002, + debug_intr =0x0004, + debug_selection =0x0008, + debug_msgo =0x0010, + debug_msgi =0x0020, + debug_status =0x0040, + debug_cmd =0x0080, + debug_datai =0x0100, + debug_datao =0x0200, + debug_abort =0x0400, + debug_done =0x0800, + debug_biosparam =0x1000, + debug_phases =0x2000, + debug_queues =0x4000, + debug_reset =0x8000, +}; +#endif + #endif /* _AHA152X_H */ diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c index 95ed18a446a3..d7d89d16d4f7 100644 --- a/drivers/scsi/eata.c +++ b/drivers/scsi/eata.c @@ -413,7 +413,7 @@ int eata_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) { } if (k == sh[j]->can_queue) { - printk("%s: qcomm, no free mailbox, reseting.\n", BN(j)); + printk("%s: qcomm, no free mailbox, resetting.\n", BN(j)); if (HD(j)->in_reset) printk("%s: qcomm, already in reset.\n", BN(j)); diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c index e1636b093b20..9caa24ecb83e 100644 --- a/drivers/scsi/fdomain.c +++ b/drivers/scsi/fdomain.c @@ -150,7 +150,7 @@ 18C30 chip have a 2k cache). When this many 512 byte blocks are filled by the SCSI device, an interrupt will be raised. Therefore, this could be as low as 0, or as high as 16. Note, however, that values which are too high - or too low seem to prevent any interrupts from occuring, and thereby lock + or too low seem to prevent any interrupts from occurring, and thereby lock up the machine. I have found that 2 is a good number, but throughput may be increased by changing this value to values which are close to 2. Please let me know if you try any different values. diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 93c9d07dc103..64c4de82adba 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -67,6 +67,10 @@ #include "pas16.h" #endif +#ifdef CONFIG_SCSI_QLOGIC +#include "qlogic.h" +#endif + #ifdef CONFIG_SCSI_SEAGATE #include "seagate.h" #endif @@ -159,6 +163,9 @@ static Scsi_Host_Template builtin_scsi_hosts[] = #ifdef CONFIG_SCSI_GENERIC_NCR5380 GENERIC_NCR5380, #endif +#ifdef CONFIG_SCSI_QLOGIC + QLOGIC, +#endif #ifdef CONFIG_SCSI_PAS16 MV_PAS16, #endif diff --git a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c new file mode 100644 index 000000000000..2878d9618c8e --- /dev/null +++ b/drivers/scsi/in2000.c @@ -0,0 +1,678 @@ +/* + * This file is in2000.c, written and + * Copyright (C) 1993 Brad McLean + * Last edit 07/19/94 WDE + * Disclaimer: + * Note: This is ugly. I know it, I wrote it, but my whole + * focus was on getting the damn thing up and out quickly. + * Future stuff that would be nice: Command chaining, and + * a local queue of commands would speed stuff up considerably. + * Disconnection needs some supporting code. All of this + * is beyond the scope of what I wanted to address, but if you + * have time and patience, more power to you. + * Also, there are some constants scattered throughout that + * should have defines, and I should have built functions to + * address the registers on the WD chip. + * Oh well, I'm out of time for this project. + * The one good thing to be said is that you can use the card. + */ + +/* + * This module was updated by Shaun Savage first on 5-13-93 + * At that time the write was fixed, irq detection, and some + * timing stuff. since that time other problems were fixed. + * On 7-20-93 this file was updated for patch level 11 + * There are still problems with it but it work on 95% of + * the machines. There are still problems with it working with + * IDE drives, as swap drive and HD that support reselection. + * But for most people it will work. + */ +/* More changes by Bill Earnest, wde@aluxpo.att.com + * through 4/07/94. Includes rewrites of FIFO routines, + * length-limited commands to make swap partitions work. + * Merged the changes released by Larry Doolittle, based on input + * from Jon Luckey, Roger Sunshine, John Shifflett. The FAST_FIFO + * doesn't work for me. Scatter-gather code from Eric. The change to + * an IF stmt. in the interrupt routine finally made it stable. + * Limiting swap request size patch to ll_rw_blk.c not needed now. + * Please ignore the clutter of debug stmts., pretty can come later. + */ +/* Merged code from Matt Postiff improving the auto-sense validation + * for all I/O addresses. Some reports of problems still come in, but + * have been unable to reproduce or localize the cause. Some are from + * LUN > 0 problems, but that is not host specific. Now 6/6/94. + */ +/* Changes for 1.1.28 kernel made 7/19/94, code not affected. (WDE) + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include "../block/blk.h" +#include "scsi.h" +#include "hosts.h" +#include "sd.h" + +#include "in2000.h" + +/*#define FAST_FIFO_IO*/ + +/*#define DEBUG*/ +#ifdef DEBUG +#define DEB(x) x +#else +#define DEB(x) +#endif + +/* These functions are based on include/asm/io.h */ +#ifndef inw +inline static unsigned short inw( unsigned short port ) +{ + unsigned short _v; + + __asm__ volatile ("inw %1,%0" + :"=a" (_v):"d" ((unsigned short) port)); + return _v; +} +#endif + +#ifndef outw +inline static void outw( unsigned short value, unsigned short port ) +{ + __asm__ volatile ("outw %0,%1" + : /* no outputs */ + :"a" ((unsigned short) value), + "d" ((unsigned short) port)); +} +#endif + +/* These functions are lifted from drivers/block/hd.c */ + +#define port_read(port,buf,nr) \ +__asm__("cld;rep;insw": :"d" (port),"D" (buf),"c" (nr):"cx","di") + +#define port_write(port,buf,nr) \ +__asm__("cld;rep;outsw": :"d" (port),"S" (buf),"c" (nr):"cx","si") + +static unsigned int base; +static unsigned int ficmsk; +static unsigned char irq_level; +static int in2000_datalen; +static unsigned int in2000_nsegment; +static unsigned int in2000_current_segment; +static unsigned short *in2000_dataptr; +static char in2000_datawrite; +static struct scatterlist * in2000_scatter; +static Scsi_Cmnd *in2000_SCptr = 0; + +static void (*in2000_done)(Scsi_Cmnd *); + +static int in2000_test_port(int index) +{ + static const int *bios_tab[] = { + (int *) 0xc8000, (int *) 0xd0000, (int *) 0xd8000 }; + int i; + char tmp; + + tmp = inb(INFLED); + /* First, see if the DIP switch values are valid */ + /* The test of B7 may fail on some early boards, mine works. */ + if (((~tmp & 0x3) != index ) || (tmp & 0x80) || !(tmp & 0x4) ) + return 0; + printk("IN-2000 probe got dip setting of %02X\n", tmp); + tmp = inb(INVERS); +/* Add some extra sanity checks here */ + for(i=0; i < 3; i++) + if(*(bios_tab[i]+0x04) == 0x41564f4e) { + printk("IN-2000 probe found hdw. vers. %02x, BIOS at %06x\n", + tmp, (unsigned int)bios_tab[i]); + return 1; + } + printk("in2000 BIOS not found.\n"); + return 0; +} + + +/* + * retreive the current transaction counter from the WD + */ + +static unsigned in2000_txcnt(void) +{ + unsigned total=0; + + if(inb(INSTAT) & 0x20) return 0xffffff; /* not readable now */ + outb(TXCNTH,INSTAT); /* then autoincrement */ + total = (inb(INDATA) & 0xff) << 16; + outb(TXCNTM,INSTAT); + total += (inb(INDATA) & 0xff) << 8; + outb(TXCNTL,INSTAT); + total += (inb(INDATA) & 0xff); + return total; +} + +/* + * Note: the FIFO is screwy, and has a counter granularity of 16 bytes, so + * we have to reconcile the FIFO counter, the transaction byte count from the + * WD chip, and of course, our desired transaction size. It may look strange, + * and could probably use improvement, but it works, for now. + */ + +static void in2000_fifo_out(void) /* uses FIFOCNTR */ +{ + unsigned count, infcnt, txcnt; + + infcnt = inb(INFCNT)& 0xfe; /* FIFO counter */ + do { + txcnt = in2000_txcnt(); +/*DEB(printk("FIw:%d %02x %d\n", in2000_datalen, infcnt, txcnt));*/ + count = (infcnt << 3) - 32; /* dont fill completely */ + if ( count > in2000_datalen ) + count = in2000_datalen; /* limit to actual data on hand */ + count >>= 1; /* Words, not bytes */ +#ifdef FAST_FIFO_IO + if ( count ) { + port_write(INFIFO, in2000_dataptr, count); + in2000_datalen -= (count<<1); + } +#else + while ( count-- ) + { + outw(*in2000_dataptr++, INFIFO); + in2000_datalen -= 2; + } +#endif + } while((in2000_datalen > 0) && ((infcnt = (inb(INFCNT)) & 0xfe) >= 0x20) ); + /* If scatter-gather, go on to next segment */ + if( !in2000_datalen && in2000_current_segment < in2000_nsegment) + { + in2000_scatter++; + in2000_current_segment++; + in2000_datalen = in2000_scatter->length; + in2000_dataptr = (unsigned short*)in2000_scatter->address; + } + if ( in2000_datalen <= 0 ) + { + ficmsk = 0; + count = 32; /* Always says to use this much flush */ + while ( count-- ) + outw(0, INFIFO); + outb(2, ININTR); /* Mask FIFO Interrupts when done */ + } +} + +static void in2000_fifo_in(void) /* uses FIFOCNTR */ +{ + unsigned fic, count, count2; + + count = inb(INFCNT) & 0xe1; + do{ + count2 = count; + count = (fic = inb(INFCNT)) & 0xe1; + } while ( count != count2 ); +DEB(printk("FIir:%d %02x %08x\n", in2000_datalen,fic,(unsigned int )in2000_dataptr)); + do { + count2 = in2000_txcnt(); /* bytes yet to come over SCSI bus */ +DEB(printk("FIr:%d %02x %08x %08x\n", in2000_datalen,fic,count2,(unsigned int)in2000_dataptr)); + if(count2 > 65536) count2 = 0; + if(fic > 128) count = 1024; + else if(fic > 64) count = 512; + else if (fic > 32) count = 256; + else if ( count2 < in2000_datalen ) /* if drive has < what we want */ + count = in2000_datalen - count2; /* FIFO has the rest */ + if ( count > in2000_datalen ) /* count2 is lesser of FIFO & rqst */ + count2 = in2000_datalen >> 1; /* converted to word count */ + else + count2 = count >> 1; + count >>= 1; /* also to words */ + count -= count2; /* extra left over in FIFO */ +#ifdef FAST_FIFO_IO + if ( count2 ) { + port_read(INFIFO, in2000_dataptr, count2); + in2000_datalen -= (count2<<1); + } +#else + while ( count2-- ) + { + *in2000_dataptr++ = inw(INFIFO); + in2000_datalen -=2; + } +#endif + } while((in2000_datalen > 0) && (fic = inb(INFCNT)) ); +DEB(printk("FIer:%d %02x %08x\n", in2000_datalen,fic,(unsigned int )in2000_dataptr)); +/* while ( count-- ) + inw(INFIFO);*/ /* Throw away some extra stuff */ + if( !in2000_datalen && in2000_current_segment < in2000_nsegment) + { + in2000_scatter++; + in2000_current_segment++; + in2000_datalen = in2000_scatter->length; + in2000_dataptr = (unsigned short*)in2000_scatter->address; + } + if ( ! in2000_datalen ){ + outb(2, ININTR); /* Mask FIFO Interrupts when done */ + ficmsk = 0;} +} + +static void in2000_intr_handle(int foo) +{ + int result=0; + unsigned int count,auxstatus,scsistatus,cmdphase,scsibyte; + int action=0; + Scsi_Cmnd *SCptr; + + DEB(printk("INT:%d %02x %08x\n", in2000_datalen, inb(INFCNT),(unsigned int)in2000_dataptr)); + + if (( (ficmsk & (count = inb(INFCNT))) == 0xfe ) || + ( (inb(INSTAT) & 0x8c) == 0x80)) + { /* FIFO interrupt or WD interrupt */ + auxstatus = inb(INSTAT); /* need to save now */ + outb(SCSIST,INSTAT); + scsistatus = inb(INDATA); /* This clears the WD intrpt bit */ + outb(TARGETU,INSTAT); /* then autoincrement */ + scsibyte = inb(INDATA); /* Get the scsi status byte */ + outb(CMDPHAS,INSTAT); + cmdphase = inb(INDATA); + DEB(printk("(int2000:%02x %02x %02x %02x %02x)\n",count,auxstatus, + scsistatus,cmdphase,scsibyte)); + + /* Why do we assume that we need to send more data here??? ERY */ + if ( in2000_datalen && in2000_dataptr ) /* data xfer pending */ + { + if ( in2000_datawrite ) + in2000_fifo_out(); + else + in2000_fifo_in(); + } else ficmsk = 0; + if ( (auxstatus & 0x8c) == 0x80 ) + { /* There is a WD Chip interrupt & register read good */ + outb(2,ININTR); /* Disable fifo interrupts */ + ficmsk = 0; + result = DID_OK << 16; + /* 16=Select & transfer complete, 85=got disconnect */ + if ((scsistatus != 0x16) && (scsistatus != 0x85) + && (scsistatus != 0x42)){ +/* printk("(WDi2000:%02x %02x %02x %02x %02x)\n",count,auxstatus, + scsistatus,cmdphase,scsibyte);*/ +/* printk("QDAT:%d %08x %02x\n", + in2000_datalen,(unsigned int)in2000_dataptr,ficmsk);*/ + ; + } + switch ( scsistatus & 0xf0 ) + { + case 0x00: /* Card Reset Completed */ + action = 3; + break; + case 0x10: /* Successful Command Completion */ + if ( scsistatus & 0x8 ) + action = 1; + break; + case 0x20: /* Command Paused or Aborted */ + if ( (scsistatus & 0x8) ) + action = 1; + else if ( (scsistatus & 7) < 2 ) + action = 2; + else + result = DID_ABORT << 16; + break; + case 0x40: /* Terminated early */ + if ( scsistatus & 0x8 ) + action = 1; + else if ( (scsistatus & 7) > 2 ) + action = 2; + else + result = DID_TIME_OUT << 16; + break; + case 0x80: /* Service Required from SCSI bus */ + if ( scsistatus & 0x8 ) + action = 1; + else + action = 2; + break; + } /* end switch(scsistatus) */ + outb(0,INFLED); + switch ( action ) + { + case 0x02: /* Issue an abort */ + outb(COMMAND,INSTAT); + outb(1,INDATA); /* ABORT COMMAND */ + result = DID_ABORT << 16; + case 0x00: /* Basically all done */ + if ( ! in2000_SCptr ) + return; + in2000_SCptr->result = result | scsibyte; + SCptr = in2000_SCptr; + in2000_SCptr = 0; + if ( in2000_done ) + (*in2000_done)(SCptr); + break; + case 0x01: /* We need to reissue a command */ + outb(CMDPHAS,INSTAT); + switch ( scsistatus & 7 ) + { + case 0: /* Data out phase */ + case 1: /* Data in phase */ + case 4: /* Unspec info out phase */ + case 5: /* Unspec info in phase */ + case 6: /* Message in phase */ + case 7: /* Message in phase */ + outb(0x41,INDATA); /* rdy to disconn */ + break; + case 2: /* command phase */ + outb(0x30,INDATA); /* rdy to send cmd bytes */ + break; + case 3: /* status phase */ + outb(0x45,INDATA); /* To go to status phase,*/ + outb(TXCNTH,INSTAT); /* elim. data, autoinc */ + outb(0,INDATA); + outb(0,INDATA); + outb(0,INDATA); + in2000_datalen = 0; + in2000_dataptr = 0; + break; + } /* end switch(scsistatus) */ + outb(COMMAND,INSTAT); + outb(8,INDATA); /* RESTART THE COMMAND */ + break; + case 0x03: /* Finish up a Card Reset */ + outb(TIMEOUT,INSTAT); /* I got these values */ + /* by reverse Engineering */ + outb(IN2000_TMOUT,INDATA); /* the Always' bios. */ + outb(CONTROL,INSTAT); + outb(0,INDATA); + outb(SYNCTXR,INSTAT); + outb(0x40,INDATA); /* async, 4 cyc xfer per. */ + break; + } /* end switch(action) */ + } /* end if auxstatus for WD int */ + } /* end while intrpt active */ +} + +static int in2000_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *)) +{ + unchar direction; + unchar *cmd = (unchar *) SCpnt->cmnd; + unchar target = SCpnt->target; + void *buff = SCpnt->request_buffer; + int bufflen = SCpnt->request_bufflen; + int timeout, size, loop; + int i; + + /* + * This SCSI command has no data phase, but unfortunately the mid-level + * SCSI drivers ask for 256 bytes of data xfer. Our card hangs if you + * do this, so we protect against it here. It would be nice if the mid- + * level could be changed, but who knows if that would break other host + * adapter drivers. + */ + if ( *cmd == TEST_UNIT_READY ) + bufflen = 0; + + /* + * What it looks like. Boy did I get tired of reading it's output. + */ + if (*cmd == READ_10 || *cmd == WRITE_10) { + i = xscsi2int((cmd+1)); + } else if (*cmd == READ_6 || *cmd == WRITE_6) { + i = scsi2int((cmd+1)); + } else { + i = -1; + } +#ifdef DEBUG + printk("in2000qcmd: pos %d len %d ", i, bufflen); + printk("scsi cmd:"); + for (i = 0; i < SCpnt->cmd_len; i++) printk("%02x ", cmd[i]); + printk("\n"); +#endif + direction = 1; /* assume for most commands */ + if (*cmd == WRITE_10 || *cmd == WRITE_6) + direction = 0; + size = SCpnt->cmd_len; /* CDB length */ + /* + * Setup our current pointers + * This is where you would allocate a control structure in a queue, + * If you were going to upgrade this to do multiple issue. + * Note that datalen and dataptr exist because we can change the + * values during the course of the operation, while managing the + * FIFO. + * Note the nasty little first clause. In theory, the mid-level + * drivers should never hand us more than one command at a time, + * but just in case someone gets cute in configuring the driver, + * we'll protect them, although not very politely. + */ + if ( in2000_SCptr ) + { + printk("in2000_queue_command waiting for free command block!\n"); + while ( in2000_SCptr ); + } + for ( timeout = jiffies + 5; timeout > jiffies; ) + { + if ( ! ( inb(INSTAT) & 0xb0 ) ) + { + timeout = 0; + break; + } + else + { + inb(INSTAT); + outb(SCSIST,INSTAT); + inb(INDATA); + outb(TARGETU,INSTAT); /* then autoinc */ + inb(INDATA); + inb(INDATA); + } + } + if ( timeout ) + { + printk("in2000_queue_command timeout!\n"); + SCpnt->result = DID_TIME_OUT << 16; + (*done)(SCpnt); + return 1; + } + /* Added for scatter-gather support */ + in2000_nsegment = SCpnt->use_sg; + in2000_current_segment = 0; + if(SCpnt->use_sg){ + in2000_scatter = (struct scatterlist *) buff; + in2000_datalen = in2000_scatter->length; + in2000_dataptr = (unsigned short*)in2000_scatter->address; + } else { + in2000_scatter = NULL; + in2000_datalen = bufflen; + in2000_dataptr = (unsigned short*) buff; + }; + in2000_done = done; + in2000_SCptr = SCpnt; + /* + * Write the CDB to the card, then the LUN, the length, and the target. + */ + outb(TOTSECT, INSTAT); /* start here then autoincrement */ + for ( loop=0; loop < size; loop++ ) + outb(cmd[loop],INDATA); + outb(TARGETU,INSTAT); + outb(SCpnt->lun & 7,INDATA); + SCpnt->host_scribble = NULL; + outb(TXCNTH,INSTAT); /* then autoincrement */ + outb(bufflen>>16,INDATA); + outb(bufflen>>8,INDATA); + outb(bufflen,INDATA); + outb(target&7,INDATA); + /* + * Set up the FIFO + */ + cli(); /* so FIFO init waits till WD set */ + outb(0,INFRST); + if ( direction == 1 ) + { + in2000_datawrite = 0; + outb(0,INFWRT); + } + else + { + in2000_datawrite = 1; + for ( loop=16; --loop; ) /* preload the outgoing fifo */ + { + outw(*in2000_dataptr++,INFIFO); + if(in2000_datalen > 0) in2000_datalen-=2; + } + } + ficmsk = 0xff; + /* + * Start it up + */ + outb(CONTROL,INSTAT); /* WD BUS Mode */ + outb(0x4C,INDATA); + if ( in2000_datalen ) /* if data xfer cmd */ + outb(0,ININTR); /* Enable FIFO intrpt some boards? */ + outb(COMMAND,INSTAT); + outb(0,INNLED); + outb(8,INDATA); /* Select w/ATN & Transfer */ + sti(); /* let the intrpt rip */ + return 0; +} + +static volatile int internal_done_flag = 0; +static volatile int internal_done_errcode = 0; + +static void internal_done(Scsi_Cmnd * SCpnt) +{ + internal_done_errcode = SCpnt->result; + ++internal_done_flag; +} + +static int in2000_command(Scsi_Cmnd * SCpnt) +{ + in2000_queuecommand(SCpnt, internal_done); + + while (!internal_done_flag); + internal_done_flag = 0; + return internal_done_errcode; +} + +static int in2000_detect(Scsi_Host_Template * tpnt) +{ +/* Order chosen to reduce conflicts with some multi-port serial boards */ + int base_tab[] = { 0x220,0x200,0x110,0x100 }; + int int_tab[] = { 15,14,11,10 }; + struct Scsi_Host * shpnt; + int loop, tmp; + + DEB(printk("in2000_detect: \n")); + + for ( loop=0; loop < 4; loop++ ) + { + base = base_tab[loop]; + if ( in2000_test_port(loop)) break; + } + if ( loop == 4 ) + return 0; + + /* Read the dip switch values again for miscellaneous checking and + informative messages */ + tmp = inb(INFLED); + + /* Bit 2 tells us if interrupts are disabled */ + if ( (tmp & 0x4) == 0 ) { + printk("The IN-2000 is not configured for interrupt operation\n"); + printk("Change the DIP switch settings to enable interrupt operation\n"); + } + + /* Bit 6 tells us about floppy controller */ + printk("IN-2000 probe found floppy controller on IN-2000 "); + if ( (tmp & 0x40) == 0) + printk("enabled\n"); + else + printk("disabled\n"); + + /* Bit 5 tells us about synch/asynch mode */ + printk("IN-2000 probe found IN-2000 in "); + if ( (tmp & 0x20) == 0) + printk("synchronous mode\n"); + else + printk("asynchronous mode\n"); + + irq_level = int_tab [ ((~inb(INFLED)>>3)&0x3) ]; + + printk("Configuring IN2000 at IO:%x, IRQ %d" +#ifdef FAST_FIFO_IO + " (using fast FIFO I/O code)" +#endif + "\n",base, irq_level); + + outb(2,ININTR); /* Shut off the FIFO first, so it won't ask for data.*/ + if (request_irq(irq_level,in2000_intr_handle, 0, "in2000")) + { + printk("in2000_detect: Unable to allocate IRQ.\n"); + return 0; + } + outb(0,INFWRT); /* read mode so WD can intrpt */ + outb(SCSIST,INSTAT); + inb(INDATA); /* free status reg, clear WD intrpt */ + outb(OWNID,INSTAT); + outb(0x7,INDATA); /* we use addr 7 */ + outb(COMMAND,INSTAT); + outb(0,INDATA); /* do chip reset */ + shpnt = scsi_register(tpnt, 0); + /* Set these up so that we can unload the driver properly. */ + shpnt->io_port = base; + shpnt->n_io_port = 12; + shpnt->irq = irq_level; + snarf_region(base, 12); /* Prevent other drivers from using this space */ + return 1; +} + +static int in2000_abort(Scsi_Cmnd * SCpnt) +{ + DEB(printk("in2000_abort\n")); + /* + * Ask no stupid questions, just order the abort. + */ + outb(COMMAND,INSTAT); + outb(1,INDATA); /* Abort Command */ + return 0; +} + +static inline void delay( unsigned how_long ) +{ + unsigned long time = jiffies + how_long; + while (jiffies < time) ; +} + +static int in2000_reset(Scsi_Cmnd * SCpnt) +{ + DEB(printk("in2000_reset called\n")); + /* + * Note: this is finished off by an incoming interrupt + */ + outb(0,INFWRT); /* read mode so WD can intrpt */ + outb(SCSIST,INSTAT); + inb(INDATA); + outb(OWNID,INSTAT); + outb(0x7,INDATA); /* ID=7,noadv, no parity, clk div=2 (8-10Mhz clk) */ + outb(COMMAND,INSTAT); + outb(0,INDATA); /* reset WD chip */ + delay(2); +#ifdef SCSI_RESET_PENDING + return SCSI_RESET_PENDING; +#else + if(SCpnt) SCpnt->flags |= NEEDS_JUMPSTART; + return 0; +#endif +} + +static int in2000_biosparam(Disk * disk, int dev, int* iinfo) + { + int size = disk->capacity; + DEB(printk("in2000_biosparam\n")); + iinfo[0] = 64; + iinfo[1] = 32; + iinfo[2] = size >> 11; + return 0; + } diff --git a/drivers/scsi/in2000.h b/drivers/scsi/in2000.h new file mode 100644 index 000000000000..4507cdc6aa46 --- /dev/null +++ b/drivers/scsi/in2000.h @@ -0,0 +1,124 @@ +#ifndef _IN2000_H + +/* $Id: in2000.h,v 1.1 1994/03/14 06:27:38 root Exp root $ + * + * Header file for the Always IN 2000 driver for Linux + * + */ + +#include +#include + +/* The IN-2000 is based on a WD33C93 */ + +#define INSTAT (base + 0x0) /* R: Auxiliary Status; W: register select */ +#define INDATA (base + 0x1) /* R/W: Data port */ +#define INFIFO (base + 0x2) /* R/W FIFO, Word access only */ +#define INREST (base + 0x3) /* W: Reset everything */ +#define INFCNT (base + 0x4) /* R: FIFO byte count */ +#define INFRST (base + 0x5) /* W: Reset Fifo count and to write */ +#define INFWRT (base + 0x7) /* W: Set FIFO to read */ +#define INFLED (base + 0x8) /* W: Set LED; R: Dip Switch settings */ +#define INNLED (base + 0x9) /* W: reset LED */ +#define INVERS (base + 0xa) /* R: Read hw version, end-reset */ +#define ININTR (base + 0xc) /* W: Interrupt Mask Port */ +#define G2CNTRL_HRDY 0x20 /* Sets HOST ready */ + +/* WD33C93 defines */ +#define OWNID 0 +#define CONTROL 1 +#define TIMEOUT 2 +#define TOTSECT 3 +#define TOTHEAD 4 +#define TOTCYLH 5 +#define TOTCYLL 6 +#define LADRSHH 7 +#define LADRSHL 8 +#define LADRSLH 9 +#define LADRSLL 10 +#define SECTNUM 11 +#define HEADNUM 12 +#define CYLNUMH 13 +#define CYLNUML 14 +#define TARGETU 15 +#define CMDPHAS 16 +#define SYNCTXR 17 +#define TXCNTH 18 +#define TXCNTM 19 +#define TXCNTL 20 +#define DESTID 21 +#define SRCID 22 +#define SCSIST 23 +#define COMMAND 24 +#define WDDATA 25 +#define AUXSTAT 31 + +/* OWNID Register Bits */ +#define OWN_EAF 0x08 +#define OWN_EHP 0x10 +#define OWN_FS0 0x40 +#define OWN_FS1 0x80 +/* AUX Register Bits */ +#define AUX_DBR 0 +#define AUX_PE 1 +#define AUX_CIP 0x10 +#define AUX_BSY 0x20 +#define AUX_LCI 0x40 +#define AUX_INT 0x80 + +/* Select timeout const, 1 count = 8ms */ +#define IN2000_TMOUT 0x1f + +#if 0 +/* This is used with scatter-gather */ +struct in2000_chain { + ulong dataptr; /* Location of data */ + ulong datalen; /* Size of this part of chain */ +}; +#endif + +/* These belong in scsi.h also */ +#define any2scsi(up, p) \ +(up)[0] = (((unsigned long)(p)) >> 16); \ +(up)[1] = (((unsigned long)(p)) >> 8); \ +(up)[2] = ((unsigned long)(p)); + +#define scsi2int(up) ( ((((long)*(up))&0x1f) << 16) + (((long)(up)[1]) << 8) + ((long)(up)[2]) ) + +#define xany2scsi(up, p) \ +(up)[0] = ((long)(p)) >> 24; \ +(up)[1] = ((long)(p)) >> 16; \ +(up)[2] = ((long)(p)) >> 8; \ +(up)[3] = ((long)(p)); + +#define xscsi2int(up) ( (((long)(up)[0]) << 24) + (((long)(up)[1]) << 16) \ + + (((long)(up)[2]) << 8) + ((long)(up)[3]) ) + +#define MAX_CDB 12 +#define MAX_SENSE 14 +#define MAX_STATUS 32 + +static int in2000_detect(Scsi_Host_Template *); +static int in2000_command(Scsi_Cmnd *); +static int in2000_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +static int in2000_abort(Scsi_Cmnd *); +static int in2000_reset(Scsi_Cmnd *); +static int in2000_biosparam(Disk *, int, int*); + + +#ifndef NULL + #define NULL 0 +#endif + +/* next may be "SG_NONE" or "SG_ALL" or nr. of (1k) blocks per R/W Cmd. */ +#define IN2000_SG SG_ALL +#define IN2000 {NULL, "Always IN2000", in2000_detect, NULL, \ + NULL, in2000_command, \ + in2000_queuecommand, \ + in2000_abort, \ + in2000_reset, \ + NULL, \ + in2000_biosparam, \ + 1, 7, IN2000_SG, 1, 0, 0} + +#endif diff --git a/drivers/scsi/qlogic.c b/drivers/scsi/qlogic.c new file mode 100644 index 000000000000..2aec0c946658 --- /dev/null +++ b/drivers/scsi/qlogic.c @@ -0,0 +1,564 @@ +/*----------------------------------------------------------------*/ +/* + Qlogic linux driver - work in progress. No Warranty express or implied. + Use at your own risk. Support Tort Reform so you won't have to read all + these silly disclaimers. + + Copyright 1994, Tom Zerucha. + zerucha@shell.portal.com + + Additional Code, and much appreciated help by + Michael A. Griffith + grif@cs.ucr.edu + + Reference Qlogic FAS408 Technical Manual, 53408-510-00A, May 10, 1994 + (you can reference it, but it is incomplete and inaccurate in places) + + Version 0.37 + Redistributable under terms of the GNU Public License + +*/ +/*----------------------------------------------------------------*/ +/* Configuration */ + +/* Set the following to 1 to enable the use of interrupts. Note that 0 tends + to be more stable, but slower (or ties up the system more) */ +#define QL_USE_IRQ 1 + +/* Set the following to max out the speed of the PIO PseudoDMA transfers, + again, 0 tends to be slower, but more stable */ +#define QL_TURBO_PDMA 1 + +/* This will reset all devices when the driver is initialized (during bootup). + The other linux drivers don't do this, but the DOS drivers do, and after + using DOS or some kind of crash or lockup this will bring things back */ +#define QL_RESET_AT_START 1 + +/* This will set fast (10Mhz) synchronous timing, FASTCLK must also be 1*/ +#define FASTSCSI 0 + +/* This will set a faster sync transfer rate */ +#define FASTCLK 0 + +/* This bit needs to be set to 1 if your cabling is long or noisy */ +#define SLOWCABLE 0 + +/* This is the sync transfer divisor, 40Mhz/X will be the data rate + The power on default is 5, the maximum normal value is 5 */ +#define SYNCXFRPD 4 + +/* This is the count of how many synchronous transfers can take place + i.e. how many reqs can occur before an ack is given. + The maximum value for this is 15, the upper bits can modify + REQ/ACK assertion and deassertion during synchronous transfers + If this is 0, the bus will only transfer asynchronously */ +#define SYNCOFFST 0 +/* for the curious, bits 7&6 control the deassertion delay in 1/2 cycles + of the 40Mhz clock. If FASTCLK is 1, specifying 01 (1/2) will + cause the deassertion to be early by 1/2 clock. Bits 5&4 control + the assertion delay, also in 1/2 clocks (FASTCLK is ignored here). */ + +/*----------------------------------------------------------------*/ + +#include +#include "../block/blk.h" /* to get disk capacity */ +#include +#include +#include +#include +#include +#include "sd.h" +#include "hosts.h" +#include "qlogic.h" + +/*----------------------------------------------------------------*/ +/* driver state info, local to driver */ +static int qbase; /* Port */ +static int qinitid; /* initiator ID */ +static int qabort; /* Flag to cause an abort */ +static int qlirq; /* IRQ being used */ +static char qinfo[80]; /* description */ +static Scsi_Cmnd *qlcmd; /* current command being processed */ + +/*----------------------------------------------------------------*/ + +#define REG0 ( outb( inb( qbase + 0xd ) & 0x7f , qbase + 0xd ), outb( 4 , qbase + 0xd )) +#define REG1 ( outb( inb( qbase + 0xd ) | 0x80 , qbase + 0xd ), outb( 0xb6 , qbase + 0xd )) + +/* following is watchdog timeout - 0 is longest possible */ +#define WATCHDOG 5000000 + +/*----------------------------------------------------------------*/ +/* the following will set the monitor border color (useful to find + where something crashed or gets stuck at and as a simple profiler) */ + +#if 0 +#define rtrc(i) {inb(0x3da);outb(0x31,0x3c0);outb((i),0x3c0);} +#else +#define rtrc(i) {} +#endif + +/*----------------------------------------------------------------*/ +/* local functions */ +/*----------------------------------------------------------------*/ +static void ql_zap(void); +/* error recovery - reset everything */ +void ql_zap() +{ +int x; + cli(); + x = inb(qbase + 0xd); + REG0; + outb(3, qbase + 3); /* reset SCSI */ + outb(2, qbase + 3); /* reset chip */ + if (x & 0x80) + REG1; + sti(); +} + +/*----------------------------------------------------------------*/ +/* do pseudo-dma */ +static int ql_pdma(int phase, char *request, int reqlen) +{ +int j; + j = 0; + if (phase & 1) { /* in */ +#if QL_TURBO_PDMA + /* empty fifo in large chunks */ + if( reqlen >= 128 && (inb( qbase + 8 ) & 2) ) { /* full */ + insl( qbase + 4, request, 32 ); + reqlen -= 128; + request += 128; + } + while( reqlen >= 84 && !( j & 0xc0 ) ) /* 2/3 */ + if( (j=inb( qbase + 8 )) & 4 ) { + insl( qbase + 4, request, 21 ); + reqlen -= 84; + request += 84; + } + if( reqlen >= 44 && (inb( qbase + 8 ) & 8) ) { /* 1/3 */ + insl( qbase + 4, request, 11 ); + reqlen -= 44; + request += 44; + } +#endif + /* until both empty and int (or until reclen is 0) */ + j = 0; + while( reqlen && !( (j & 0x10) && (j & 0xc0) ) ) { + /* while bytes to receive and not empty */ + j &= 0xc0; + while ( reqlen && !( (j=inb(qbase + 8)) & 0x10 ) ) { + *request++ = inb(qbase + 4); + reqlen--; + } + if( j & 0x10 ) + j = inb(qbase+8); + + } + } + else { /* out */ +#if QL_TURBO_PDMA + if( reqlen >= 128 && inb( qbase + 8 ) & 0x10 ) { /* empty */ + outsl(qbase + 4, request, 32 ); + reqlen -= 128; + request += 128; + } + while( reqlen >= 84 && !( j & 0xc0 ) ) /* 1/3 */ + if( !((j=inb( qbase + 8 )) & 8) ) { + outsl( qbase + 4, request, 21 ); + reqlen -= 84; + request += 84; + } + if( reqlen >= 40 && !(inb( qbase + 8 ) & 4 ) ) { /* 2/3 */ + outsl( qbase + 4, request, 10 ); + reqlen -= 40; + request += 40; + } +#endif + /* until full and int (or until reclen is 0) */ + j = 0; + while( reqlen && !( (j & 2) && (j & 0xc0) ) ) { + /* while bytes to send and not full */ + while ( reqlen && !( (j=inb(qbase + 8)) & 2 ) ) { + outb(*request++, qbase + 4); + reqlen--; + } + if( j & 2 ) + j = inb(qbase+8); + } + } +/* maybe return reqlen */ + return inb( qbase + 8 ) & 0xc0; +} + +/*----------------------------------------------------------------*/ +/* wait for interrupt flag (polled - not real hardware interrupt) */ +static int ql_wai(void) +{ +int i,k; + i = WATCHDOG; + while (--i && !qabort && !((k = inb(qbase + 4)) & 0xe0)); + if (!i) + return (DID_TIME_OUT); + if (qabort) + return (qabort == 1 ? DID_ABORT : DID_RESET); + if (k & 0x60) + ql_zap(); + if (k & 0x20) + return (DID_PARITY); + if (k & 0x40) + return (DID_ERROR); + return 0; +} + +/*----------------------------------------------------------------*/ +/* initate scsi command - queueing handler */ +static void ql_icmd(Scsi_Cmnd * cmd) +{ +unsigned int i; + qabort = 0; + + cli(); + REG0; +/* clearing of interrupts and the fifo is needed */ + inb(qbase + 5); /* clear interrupts */ + if (inb(qbase + 5)) /* if still interrupting */ + outb(2, qbase + 3); /* reset chip */ + else if (inb(qbase + 7) & 0x1f) + outb(1, qbase + 3); /* clear fifo */ + while (inb(qbase + 5)); /* clear ints */ + REG1; + outb(1, qbase + 8); /* set for PIO pseudo DMA */ + outb(0, qbase + 0xb); /* disable ints */ + inb(qbase + 8); /* clear int bits */ + REG0; + outb(0x40, qbase + 0xb); /* enable features */ + +/* configurables */ +#if FASTSCSI +#if FASTCLK + outb(0x18, qbase + 0xc); +#else + outb(0x10, qbase + 0xc); +#endif +#else +#if FASTCLK + outb(8, qbase + 0xc); +#endif +#endif + +#if SLOWCABLE + outb(0xd0 | qinitid, qbase + 8); /* (initiator) bus id */ +#else + outb(0x50 | qinitid, qbase + 8); /* (initiator) bus id */ +#endif + outb( SYNCOFFST , qbase + 7 ); + outb( SYNCXFRPD , qbase + 6 ); +/**/ + outb(0x99, qbase + 5); /* timer */ + outb(cmd->target, qbase + 4); + + for (i = 0; i < COMMAND_SIZE(cmd->cmnd[0]); i++) + outb(cmd->cmnd[i], qbase + 2); + qlcmd = cmd; + outb(0x41, qbase + 3); /* select and send command */ + sti(); +} +/*----------------------------------------------------------------*/ +/* process scsi command - usually after interrupt */ +static unsigned int ql_pcmd(Scsi_Cmnd * cmd) +{ +unsigned int i, j, k; +unsigned int result; /* ultimate return result */ +unsigned int status; /* scsi returned status */ +unsigned int message; /* scsi returned message */ +unsigned int phase; /* recorded scsi phase */ +unsigned int reqlen; /* total length of transfer */ +struct scatterlist *sglist; /* scatter-gather list pointer */ +unsigned int sgcount; /* sg counter */ + + j = inb(qbase + 6); + i = inb(qbase + 5); + if (i == 0x20) { + return (DID_NO_CONNECT << 16); + } + i |= inb(qbase + 5); /* the 0x10 bit can be set after the 0x08 */ + if (i != 0x18) { + printk("Ql:Bad Interrupt status:%02x\n", i); + ql_zap(); + return (DID_BAD_INTR << 16); + } + j &= 7; /* j = inb( qbase + 7 ) >> 5; */ +/* correct status is supposed to be step 4 */ +/* it sometimes returns step 3 but with 0 bytes left to send */ + if (j != 4 && (j != 3 || inb(qbase + 7) & 0x1f)) { + printk("Ql:Bad sequence for command %d, int %02X, cmdleft = %d\n", j, i, inb( qbase+7 ) & 0x1f ); + ql_zap(); + return (DID_ERROR << 16); + } + result = DID_OK; + if (inb(qbase + 7) & 0x1f) /* if some bytes in fifo */ + outb(1, qbase + 3); /* clear fifo */ +/* note that request_bufflen is the total xfer size when sg is used */ + reqlen = cmd->request_bufflen; +/* note that it won't work if transfers > 16M are requested */ + if (reqlen && !((phase = inb(qbase + 4)) & 6)) { /* data phase */ +rtrc(1) + outb(reqlen, qbase); /* low-mid xfer cnt */ + outb(reqlen >> 8, qbase+1); /* low-mid xfer cnt */ + outb(reqlen >> 16, qbase + 0xe); /* high xfer cnt */ + outb(0x90, qbase + 3); /* command do xfer */ +/* PIO pseudo DMA to buffer or sglist */ + REG1; + if (!cmd->use_sg) + ql_pdma(phase, cmd->request_buffer, cmd->request_bufflen); + else { + sgcount = cmd->use_sg; + sglist = cmd->request_buffer; + while (sgcount--) { + if (qabort) { + REG0; + return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16); + } + if (ql_pdma(phase, sglist->address, sglist->length)) + break; + sglist++; + } + } + REG0; +rtrc(2) +/* wait for irq (split into second state of irq handler if this can take time) */ + if ((k = ql_wai())) + return (k << 16); + k = inb(qbase + 5); /* should be 0x10, bus service */ + } +/*** Enter Status (and Message In) Phase ***/ + k = WATCHDOG; +rtrc(4) + while (--k && !qabort && !(inb(qbase + 4) & 6)); /* wait for status phase */ + if (!k) { + ql_zap(); + return (DID_TIME_OUT << 16); + } + while (inb(qbase + 5)); /* clear pending ints */ + if (qabort) + return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16); + outb(0x11, qbase + 3); /* get status and message */ + if ((k = ql_wai())) + return (k << 16); + i = inb(qbase + 5); /* get chip irq stat */ + j = inb(qbase + 7) & 0x1f; /* and bytes rec'd */ + status = inb(qbase + 2); + message = inb(qbase + 2); +/* should get function complete int if Status and message, else bus serv if only status */ + if (!((i == 8 && j == 2) || (i == 0x10 && j == 1))) { + printk("Ql:Error during status phase, int=%02X, %d bytes recd\n", i, j); + result = DID_ERROR; + } + outb(0x12, qbase + 3); /* done, disconnect */ +rtrc(3) + if ((k = ql_wai())) + return (k << 16); +/* should get bus service interrupt and disconnect interrupt */ + i = inb(qbase + 5); /* should be bus service */ + while (!qabort && ((i & 0x20) != 0x20)) + i |= inb(qbase + 5); +rtrc(0) + if (qabort) + return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16); + return (result << 16) | (message << 8) | (status & STATUS_MASK); +} + +#if QL_USE_IRQ +/*----------------------------------------------------------------*/ +/* interrupt handler */ +static void ql_ihandl(int irq) +{ +Scsi_Cmnd *icmd; + REG0; + if (!(inb(qbase + 4) & 0x80)) /* false alarm? */ + return; + if (qlcmd == NULL) { /* no command to process? */ + while (inb(qbase + 5)); /* maybe also ql_zap() */ + return; + } + icmd = qlcmd; + icmd->result = ql_pcmd(icmd); + qlcmd = NULL; +/* if result is CHECK CONDITION done calls qcommand to request sense */ + (icmd->scsi_done) (icmd); +} +#endif + +/*----------------------------------------------------------------*/ +/* global functions */ +/*----------------------------------------------------------------*/ +/* non queued command */ +#if QL_USE_IRQ +static void qlidone(Scsi_Cmnd * cmd) {}; /* null function */ +#endif + +/* command process */ +int qlogic_command(Scsi_Cmnd * cmd) +{ +int k; +#if QL_USE_IRQ + if (qlirq >= 0) { + qlogic_queuecommand(cmd, qlidone); + while (qlcmd != NULL); + return cmd->result; + } +#endif +/* non-irq version */ + if (cmd->target == qinitid) + return (DID_BAD_TARGET << 16); + ql_icmd(cmd); + if ((k = ql_wai())) + return (k << 16); + return ql_pcmd(cmd); + +} + +#if QL_USE_IRQ +/*----------------------------------------------------------------*/ +/* queued command */ +int qlogic_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) +{ + if(cmd->target == qinitid) { + cmd->result = DID_BAD_TARGET << 16; + done(cmd); + return 0; + } + + cmd->scsi_done = done; +/* wait for the last command's interrupt to finish */ + while (qlcmd != NULL); + ql_icmd(cmd); + return 0; +} +#else +int qlogic_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) +{ + return 1; +} +#endif + +/*----------------------------------------------------------------*/ +/* look for qlogic card and init if found */ +int qlogic_detect(Scsi_Host_Template * host) +{ +int i, j; /* these are only used by IRQ detect */ +int qltyp; /* type of chip */ +struct Scsi_Host *hreg; /* registered host structure */ + +/* Qlogic Cards only exist at 0x230 or 0x330 (the chip itself decodes the + address - I check 230 first since MIDI cards are typically at 330 + Note that this will not work for 2 Qlogic cards in 1 system. The + easiest way to do that is to create 2 versions of this file, one for + 230 and one for 330. + + Alternately, the Scsi_Host structure now stores the i/o port and can + be used to set the port (go through and replace qbase with + (struct Scsi_Cmnd *) cmd->host->io_port, or for efficiency, set a local + copy of qbase. There will also need to be something similar within the + IRQ handlers to sort out which board it came from and thus which port. +*/ + + for (qbase = 0x230; qbase < 0x430; qbase += 0x100) { + REG1; + if ( ( (inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7 ) + && ( (inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7 ) ) + break; + } + if (qbase == 0x430) + return 0; + + qltyp = inb(qbase + 0xe) & 0xf8; + qinitid = host->this_id; + if (qinitid < 0) + qinitid = 7; /* if no ID, use 7 */ + outb(1, qbase + 8); /* set for PIO pseudo DMA */ + REG0; + outb(0xd0 | qinitid, qbase + 8); /* (ini) bus id, disable scsi rst */ + outb(0x99, qbase + 5); /* select timer */ + qlirq = -1; +#if QL_RESET_AT_START + outb( 3 , qbase + 3 ); + REG1; + while( inb( qbase + 0xf ) & 4 ); + REG0; +#endif +#if QL_USE_IRQ +/* IRQ probe - toggle pin and check request pending */ + cli(); + i = 0xffff; + j = 3; + outb(0x90, qbase + 3); /* illegal command - cause interrupt */ + REG1; + outb(10, 0x20); /* access pending interrupt map */ + outb(10, 0xa0); + while (j--) { + outb(0xb2, qbase + 0xd); /* int pin off */ + i &= ~(inb(0x20) | (inb(0xa0) << 8)); /* find IRQ off */ + outb(0xb6, qbase + 0xd); /* int pin on */ + i &= inb(0x20) | (inb(0xa0) << 8); /* find IRQ on */ + } + REG0; + while (inb(qbase + 5)); /* purge int */ + while (i) /* find on bit */ + i >>= 1, qlirq++; /* should check for exactly 1 on */ + if (qlirq >= 0 && !request_irq(qlirq, ql_ihandl, 0, "qlogic")) + host->can_queue = 1; + sti(); +#endif + hreg = scsi_register( host , 0 ); /* no host data */ + hreg->io_port = qbase; + hreg->irq = qlirq; + + sprintf(qinfo, "Qlogic Driver version 0.36, chip %02X at %03X, IRQ %d", qltyp, qbase, qlirq); + host->name = qinfo; + return 1; +} + +/*----------------------------------------------------------------*/ +/* return bios parameters */ +int qlogic_biosparam(Disk * disk, int dev, int ip[]) +{ +/* This should mimmic the DOS Qlogic driver's behavior exactly */ + ip[0] = 0x40; + ip[1] = 0x20; + ip[2] = disk->capacity / (ip[0] * ip[1]); + if (ip[2] > 1024) { + ip[0] = 0xff; + ip[1] = 0x3f; + ip[2] = disk->capacity / (ip[0] * ip[1]); + if (ip[2] > 1023) + ip[2] = 1023; + } + return 0; +} + +/*----------------------------------------------------------------*/ +/* abort command in progress */ +int qlogic_abort(Scsi_Cmnd * cmd) +{ + qabort = 1; + ql_zap(); + return 0; +} + +/*----------------------------------------------------------------*/ +/* reset SCSI bus */ +int qlogic_reset(Scsi_Cmnd * cmd) +{ + qabort = 2; + ql_zap(); + return 1; +} + +/*----------------------------------------------------------------*/ +/* return info string */ +const char *qlogic_info() +{ + return qinfo; +} diff --git a/drivers/scsi/qlogic.h b/drivers/scsi/qlogic.h new file mode 100644 index 000000000000..aecb64ff3f0f --- /dev/null +++ b/drivers/scsi/qlogic.h @@ -0,0 +1,37 @@ +#ifndef _QLOGIC_H +#define _QLOGIC_H + +int qlogic_detect(Scsi_Host_Template * ); +const char * qlogic_info(void); +int qlogic_command(Scsi_Cmnd *); +int qlogic_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); +int qlogic_abort(Scsi_Cmnd *); +int qlogic_reset(Scsi_Cmnd *); +int qlogic_biosparam(Disk *,int,int[]); + +#ifndef NULL +#define NULL (0) +#endif + +#define QLOGIC { \ + NULL, \ + NULL, \ + qlogic_detect, \ + NULL, \ + qlogic_info, \ + qlogic_command, \ + qlogic_queuecommand, \ + qlogic_abort, \ + qlogic_reset, \ + NULL, \ + qlogic_biosparam, \ + 0, \ + -1, \ + SG_ALL, \ + 1, \ + 0, \ + 0, \ + DISABLE_CLUSTERING \ +} + +#endif /* _QLOGIC_H */ diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 0f95321cb45b..ad37178cc65f 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -346,6 +346,13 @@ static void scan_scsis (struct Scsi_Host * shpnt) scsi_result[0] = TYPE_ROM; scsi_result[1] |= 0x80; /* removable */ } + + SDpnt->manufactor = SCSI_MAN_UNKNOWN; + if (!strncmp(scsi_result+8,"NEC",3)) + SDpnt->manufactor = SCSI_MAN_NEC; + if (!strncmp(scsi_result+8,"TOSHIBA",7)) + SDpnt->manufactor = SCSI_MAN_TOSHIBA; + SDpnt->removable = (0x80 & scsi_result[1]) >> 7; SDpnt->lockable = SDpnt->removable; @@ -532,7 +539,7 @@ static void scsi_times_out (Scsi_Cmnd * SCpnt) if (!scsi_abort (SCpnt, DID_TIME_OUT)) return; case IN_ABORT: - printk("SCSI host %d abort() timed out - reseting\n", + printk("SCSI host %d abort() timed out - resetting\n", SCpnt->host->host_no); if (!scsi_reset (SCpnt)) return; @@ -1297,7 +1304,7 @@ static void scsi_done (Scsi_Cmnd * SCpnt) if ((SCpnt->retries >= (SCpnt->allowed >> 1)) && !(SCpnt->flags & WAS_RESET)) { - printk("scsi%d : reseting for second half of retries.\n", + printk("scsi%d : resetting for second half of retries.\n", SCpnt->host->host_no); reset(SCpnt); break; diff --git a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h index 5a62c959a424..347f97b77286 100644 --- a/drivers/scsi/scsi.h +++ b/drivers/scsi/scsi.h @@ -183,7 +183,7 @@ extern const unsigned char scsi_command_size[8]; #define DRIVER_OK 0x00 /* - These indicate the error that occured, and what is available. + These indicate the error that occurred, and what is available. */ #define DRIVER_BUSY 0x01 @@ -259,6 +259,13 @@ extern const unsigned char scsi_command_size[8]; as the LUN. */ +/* + Manufactors list +*/ + +#define SCSI_MAN_UNKNOWN 0 +#define SCSI_MAN_NEC 1 +#define SCSI_MAN_TOSHIBA 2 /* The scsi_device struct contains what we know about each given scsi @@ -268,6 +275,7 @@ extern const unsigned char scsi_command_size[8]; typedef struct scsi_device { struct scsi_device * next; /* Used for linked list */ unsigned char id, lun; + unsigned int manufactor; /* Manufactor of device, for using vendor-specific cmd's */ int attached; /* # of high level drivers attached to this */ int access_count; /* Count of open channels/mounts */ struct wait_queue * device_wait; /* Used to wait if device is busy */ diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 14ccb0f19f90..5fda0fc942f0 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -271,6 +271,122 @@ static void rw_intr (Scsi_Cmnd * SCpnt) } } +/* + * Here I tried to implement better support for PhotoCD's. + * + * Much of this has do be done with vendor-specific SCSI-commands. + * So I have to complete it step by step. Useful information is welcome. + * + * Actually works: (should work ;-) + * - NEC: Detection and support of multisession CD's. Special handling + * for XA-disks is not nessesary. + * + * - TOSHIBA: setting density is done here now, mounting PhotoCD's should + * work now without running the program "set_density" + * multisession-CD's are supported too. + * + * Gerd Knorr (mailto:kraxel@cs.tu-berlin.de, + * http://www.cs.tu-berlin.de/~kraxel/) + */ + +static void sr_photocd_done(Scsi_Cmnd *SCpnt) +{ + SCpnt->request.dev = 0xfffe; +} + +static void sr_photocd(struct inode *inode) +{ + unsigned long sector,min,sec,frame; + Scsi_Cmnd *SCpnt; + unsigned char scsi_cmd[10]; + unsigned char *buffer; + int rc; + + switch(scsi_CDs[MINOR(inode->i_rdev)].device->manufactor) { + + case SCSI_MAN_NEC: + printk("sr_photocd: use NEC code\n"); + SCpnt = allocate_device(NULL, scsi_CDs[MINOR(inode->i_rdev)].device,1); + memset(scsi_cmd,0,10); + scsi_cmd[0] = 0xde; + scsi_cmd[1] = ((scsi_CDs[MINOR(inode->i_rdev)].device->lun) << 5) | 0x03; + scsi_cmd[2] = 0xb0; + buffer = (unsigned char*) scsi_malloc(512); + scsi_do_cmd(SCpnt, scsi_cmd, buffer, 0x16, + sr_photocd_done, SR_TIMEOUT, MAX_RETRIES); + while (SCpnt->request.dev != 0xfffe); + rc = SCpnt->result; + if (driver_byte(rc) != 0) { + printk("sr_photocd: oops, CD-ROM reports an error.\n"); + sector = 0; } + else { + min = (unsigned long)buffer[15]/16*10 + (unsigned long)buffer[15]%16; + sec = (unsigned long)buffer[16]/16*10 + (unsigned long)buffer[16]%16; + frame = (unsigned long)buffer[17]/16*10 + (unsigned long)buffer[17]%16; + sector = min*60*75 + sec*75 + frame; + if (sector) { + printk("sr_photocd: multisession PhotoCD detected\n"); }} + scsi_free(buffer,512); + SCpnt->request.dev = -1; + break; + + case SCSI_MAN_TOSHIBA: + printk("sr_photocd: use TOSHIBA code\n"); + + /* first I do a set_density-call (for reading XA-sectors) ... */ + SCpnt = allocate_device(NULL, scsi_CDs[MINOR(inode->i_rdev)].device,1); + memset(scsi_cmd,0,10); + scsi_cmd[0] = 0x15; + scsi_cmd[1] = ((scsi_CDs[MINOR(inode->i_rdev)].device->lun) << 5)|(1 << 4); + scsi_cmd[4] = 12; + buffer = (unsigned char*) scsi_malloc(512); + memset(buffer,0,512); + buffer[ 3] = 0x08; + buffer[ 4] = 0x83; + buffer[10] = 0x08; + scsi_do_cmd(SCpnt, scsi_cmd, buffer, 12, + sr_photocd_done, SR_TIMEOUT, MAX_RETRIES); + while (SCpnt->request.dev != 0xfffe); + rc = SCpnt->result; + if (driver_byte(rc) != 0) { + printk("sr_photocd: oops, CD-ROM reports an error.\n"); } + scsi_free(buffer,512); + SCpnt->request.dev = -1; + + /* ... and then I ask, if there is a multisession-Disk */ + SCpnt = allocate_device(NULL, scsi_CDs[MINOR(inode->i_rdev)].device,1); + memset(scsi_cmd,0,10); + scsi_cmd[0] = 0xc7; + scsi_cmd[1] = ((scsi_CDs[MINOR(inode->i_rdev)].device->lun) << 5) | 3; + buffer = (unsigned char*) scsi_malloc(512); + memset(buffer,0,512); + scsi_do_cmd(SCpnt, scsi_cmd, buffer, 4, + sr_photocd_done, SR_TIMEOUT, MAX_RETRIES); + while (SCpnt->request.dev != 0xfffe); + rc = SCpnt->result; + if (driver_byte(rc) != 0) { + printk("sr_photocd: oops, CD-ROM reports an error.\n"); + sector = 0; } + else { + min = (unsigned long)buffer[1]/16*10 + (unsigned long)buffer[1]%16; + sec = (unsigned long)buffer[2]/16*10 + (unsigned long)buffer[2]%16; + frame = (unsigned long)buffer[3]/16*10 + (unsigned long)buffer[3]%16; + sector = min*60*75 + sec*75 + frame; + if (sector) { + printk("sr_photocd: multisession PhotoCD detected: %lu\n",sector); }} + scsi_free(buffer,512); + SCpnt->request.dev = -1; + break; + case SCSI_MAN_UNKNOWN: + default: + printk("sr_photocd: there is no special photocd-code for this drive\n"); + sector = 0; + break; } + + scsi_CDs[MINOR(inode->i_rdev)].mpcd_sector = sector; + return; +} + static int sr_open(struct inode * inode, struct file * filp) { if(MINOR(inode->i_rdev) >= sr_template.nr_dev || @@ -292,6 +408,8 @@ static int sr_open(struct inode * inode, struct file * filp) if(scsi_CDs[MINOR(inode->i_rdev)].needs_sector_size) get_sectorsize(MINOR(inode->i_rdev)); + sr_photocd(inode); + return 0; } @@ -437,6 +555,10 @@ work around the fact that the buffer cache has a block size of 1024, and we have 2048 byte sectors. This code should work for buffers that are any multiple of 512 bytes long. */ + /* this is for support of multisession-CD's */ + if (block >= 64 && block < 68) { + block += scsi_CDs[dev].mpcd_sector*4; } + SCpnt->use_sg = 0; if (SCpnt->host->sg_tablesize > 0 && diff --git a/drivers/scsi/sr.h b/drivers/scsi/sr.h index c02356759937..e549551ba9e2 100644 --- a/drivers/scsi/sr.h +++ b/drivers/scsi/sr.h @@ -24,6 +24,7 @@ typedef struct unsigned capacity; /* size in blocks */ unsigned sector_size; /* size in bytes */ Scsi_Device *device; + unsigned long mpcd_sector; /* for reading multisession-CD's */ 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 */ diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c index 61da7dbe3ef4..61d336978166 100644 --- a/drivers/scsi/u14-34f.c +++ b/drivers/scsi/u14-34f.c @@ -463,7 +463,7 @@ int u14_34f_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) { } if (k == sh[j]->can_queue) { - printk("%s: qcomm, no free mailbox, reseting.\n", BN(j)); + printk("%s: qcomm, no free mailbox, resetting.\n", BN(j)); if (HD(j)->in_reset) printk("%s: qcomm, already in reset.\n", BN(j)); diff --git a/fs/isofs/file.c b/fs/isofs/file.c index ab0c739e4f4c..b2f487bbf084 100644 --- a/fs/isofs/file.c +++ b/fs/isofs/file.c @@ -119,7 +119,7 @@ static void isofs_determine_filetype(struct inode * inode) static int isofs_file_read(struct inode * inode, struct file * filp, char * buf, int count) { int read,left,chars; - int block, blocks, offset; + int block, blocks, offset, total_blocks; int bhrequest; int ra_blocks, max_block, nextblock; struct buffer_head ** bhb, ** bhe; @@ -154,6 +154,17 @@ static int isofs_file_read(struct inode * inode, struct file * filp, char * buf, ra_blocks = read_ahead[MAJOR(inode->i_dev)] / (BLOCK_SIZE >> 9); if(ra_blocks > blocks) blocks = ra_blocks; + /* + * this is for stopping read ahead at EOF. It's important for + * reading PhotoCD's, becauce they have many small data tracks instead + * of one big. And between two data-tracks are some unreadable sectors. + * A read ahead after a EOF may try to read such an unreadable sector. + * kraxel@cs.tu-berlin.de (Gerd Knorr) + */ + total_blocks = inode->i_size >> ISOFS_BUFFER_BITS(inode); + if (inode->i_size & (ISOFS_BUFFER_BITS(inode)-1)) total_blocks++; + while (block + blocks > total_blocks) blocks--; + max_block = (inode->i_size + BLOCK_SIZE - 1)/BLOCK_SIZE; nextblock = -1; diff --git a/fs/super.c b/fs/super.c index 35c58e06755a..8f9636a9d8a0 100644 --- a/fs/super.c +++ b/fs/super.c @@ -641,10 +641,12 @@ void mount_root(void) memset(super_blocks, 0, sizeof(super_blocks)); fcntl_init_locks(); +#ifdef CONFIG_BLK_DEV_FD if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) { printk(KERN_NOTICE "VFS: Insert root floppy and press ENTER\n"); wait_for_keypress(); } +#endif memset(&filp, 0, sizeof(filp)); memset(&d_inode, 0, sizeof(d_inode)); diff --git a/ibcs/binfmt_coff.c b/ibcs/binfmt_coff.c index 37ad3fc856a1..1a7c760cd08e 100644 --- a/ibcs/binfmt_coff.c +++ b/ibcs/binfmt_coff.c @@ -546,7 +546,7 @@ load_object (struct linux_binprm * bprm, struct pt_regs *regs, int lib_ok) } } /* - * Generate any needed trap for this process. If an error occured then + * Generate any needed trap for this process. If an error occurred then * generate a segmentation violation. If the process is being debugged * then generate the load trap. (Note: If this is a library load then * do not generate the trap here. Pass the error to the caller who diff --git a/include/asm-alpha/delay.h b/include/asm-alpha/delay.h new file mode 100644 index 000000000000..87e69f657bcb --- /dev/null +++ b/include/asm-alpha/delay.h @@ -0,0 +1,38 @@ +#ifndef __ALPHA_DELAY_H +#define __ALPHA_DELAY_H + +extern unsigned long loops_per_sec; + +/* + * Copyright (C) 1993 Linus Torvalds + * + * Delay routines, using a pre-computed "loops_per_second" value. + */ + +extern __inline__ void __delay(unsigned long loops) +{ + __asm__ __volatile__(".align 3\n" + "1:\tsubq %0,1,%0\n\t" + "bge %0,1b": "=r" (loops) : "0" (loops)); +} + +/* + * division by multiplication: you don't have to worry about + * loss of precision. + * + * Use only for very small delays ( < 1 msec). Should probably use a + * lookup table, really, as the multiplications take much too long with + * short delays. This is a "reasonable" implementation, though (and the + * first constant multiplications gets optimized away if the delay is + * a constant) + */ +extern __inline__ void udelay(unsigned long usecs) +{ + usecs *= 0x000010c6f7a0b5edUL; /* 2**64 / 1000000 */ + __asm__("umulh %1,%2,%0" + :"=r" (usecs) + :"r" (usecs),"r" (loops_per_sec)); + __delay(usecs); +} + +#endif /* defined(__ALPHA_DELAY_H) */ diff --git a/include/linux/fd.h b/include/linux/fd.h index 76b9c64796df..43991f3f1b9f 100644 --- a/include/linux/fd.h +++ b/include/linux/fd.h @@ -25,19 +25,15 @@ #define FDGETDRVPRM 21 /* get drive parameters */ #define FDGETDRVSTAT 22 /* get drive state */ #define FDPOLLDRVSTAT 23 /* get drive state */ -#define FDGETFDCSTAT 25 /* get fdc state */ -#define FDWERRORCLR 27 /* clear write error and badness information */ -#define FDWERRORGET 28 /* get write error and badness information */ - #define FDRESET 24 /* reset FDC */ + #define FD_RESET_IF_NEEDED 0 #define FD_RESET_IF_RAWCMD 1 #define FD_RESET_ALWAYS 2 -#define FDBAILOUT 26 /* release all fdc locks */ -#define FD_CLEAR_RESET 0 -#define FD_COMPLETE_FORMAT 1 -#define FD_UNLOCK_FDC 2 +#define FDGETFDCSTAT 25 /* get fdc state */ +#define FDWERRORCLR 27 /* clear write error and badness information */ +#define FDWERRORGET 28 /* get write error and badness information */ #define FDRAWCMD 30 /* send a raw command to the fdc */ @@ -59,6 +55,7 @@ #define FD_PERP 0x40 #ifndef ASSEMBLER +/* the following structure is used by FDSETPRM, FDDEFPRM and FDGETPRM */ struct floppy_struct { unsigned int size, /* nr of sectors total */ sect, /* sectors per track */ @@ -94,6 +91,7 @@ struct floppy_max_errors { }; +/* the following structure is used by FDSETDRVPRM and FDGETDRVPRM */ struct floppy_drive_params { char cmos; /* cmos type */ @@ -124,7 +122,11 @@ struct floppy_drive_params { * disk changes. * Also used to enable/disable printing of overrun warnings. */ + #define FTD_MSG 0x10 +#define FD_BROKEN_DCL 0x20 +#define FD_DEBUG 0x02 +#define FD_SILENT_DCL_CLEAR 0x4 char read_track; /* use readtrack during probing? */ @@ -139,21 +141,30 @@ struct floppy_drive_params { int native_format; /* native format of this drive */ }; -struct floppy_drive_struct { - signed char flags; +enum { +FD_NEED_TWADDLE_BIT, /* more magic */ +FD_VERIFY_BIT, /* inquire for write protection */ +FD_DISK_NEWCHANGE_BIT, /* change detected, and no action undertaken yet to + clear media change status */ +FD_UNUSED_BIT, +FD_DISK_CHANGED_BIT, /* disk has been changed since last i/o */ +FD_DISK_WRITABLE_BIT /* disk is writable */ +}; /* values for these flags */ -#define FD_NEED_TWADDLE 1 /* more magic */ -#define FD_VERIFY 2 /* this is set at bootup to force an initial drive status - inquiry*/ -#define FD_DISK_NEWCHANGE 4 /* change detected, and no action undertaken yet to - clear media change status */ -#define FD_DRIVE_PRESENT 8 -#define FD_DISK_WRITABLE 32 - - unsigned long volatile spinup_date; - unsigned long volatile select_date; - unsigned long volatile first_read_date; +#define FD_NEED_TWADDLE (1 << FD_NEED_TWADDLE_BIT) +#define FD_VERIFY (1 << FD_VERIFY_BIT) +#define FD_DISK_NEWCHANGE (1 << FD_DISK_NEWCHANGE_BIT) +#define FD_DISK_CHANGED (1 << FD_DISK_CHANGED_BIT) +#define FD_DISK_WRITABLE (1 << FD_DISK_WRITABLE_BIT) + +#define FD_DRIVE_PRESENT 0 /* keep fdpatch utils compiling */ + +struct floppy_drive_struct { + signed char flags; + unsigned long spinup_date; + unsigned long select_date; + unsigned long first_read_date; short probed_format; short track; /* current track */ short maxblock; /* id of highest block read */ diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index f0473be80963..0c66a3e5efff 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -139,7 +139,7 @@ struct device #define HAVE_SET_MAC_ADDR int (*set_mac_address)(struct device *dev, void *addr); #define HAVE_PRIVATE_IOCTL - int (*do_ioctl)(struct device *dev, struct ifreq *ifr); + int (*do_ioctl)(struct device *dev, struct ifreq *ifr, int cmd); #define HAVE_SET_CONFIG int (*set_config)(struct device *dev, struct ifmap *map); diff --git a/init/main.c b/init/main.c index a13414748c31..5c83edcef9f7 100644 --- a/init/main.c +++ b/init/main.c @@ -75,7 +75,6 @@ extern long console_init(long, long); extern long kmalloc_init(long,long); extern long blk_dev_init(long,long); extern long chr_dev_init(long,long); -extern void floppy_init(void); extern void sock_init(void); extern long rd_init(long mem_start, int length); unsigned long net_dev_init(unsigned long, unsigned long); @@ -406,6 +405,82 @@ static void copro_timeout(void) outb_p(0,0xf0); } +static void check_fpu(void) +{ + static double x = 4195835.0; + static double y = 3145727.0; + unsigned short control_word; + int i; + + if (!hard_math) { +#ifndef CONFIG_MATH_EMULATION + printk("No coprocessor found and no math emulation present.\n"); + printk("Giving up.\n"); + for (;;) ; +#endif + return; + } + /* + * check if exception 16 works correctly.. This is truly evil + * code: it disables the high 8 interrupts to make sure that + * the irq13 doesn't happen. But as this will lead to a lockup + * if no exception16 arrives, it depends on the fact that the + * high 8 interrupts will be re-enabled by the next timer tick. + * So the irq13 will happen eventually, but the exception 16 + * should get there first.. + */ + printk("Checking 386/387 coupling... "); + timer_table[COPRO_TIMER].expires = jiffies+50; + timer_table[COPRO_TIMER].fn = copro_timeout; + timer_active |= 1< +extern char floppy_track_buffer[]; +extern void set_device_ro(int dev,int flag); +#include +#include extern void *sys_call_table; @@ -91,6 +95,10 @@ struct symbol_table symbol_table = { 0, 0, 0, /* for stacked module support */ X(namei), X(lnamei), X(open_namei), + X(check_disk_change), + X(invalidate_buffers), + X(fsync_dev), + X(permission), X(inode_setattr), X(inode_change_ok), X(generic_mmap), @@ -116,7 +124,10 @@ struct symbol_table symbol_table = { 0, 0, 0, /* for stacked module support */ X(block_fsync), X(wait_for_request), X(blksize_size), + X(blk_size), X(blk_dev), + X(is_read_only), + X(set_device_ro), /* Module creation of serial units */ X(register_serial), @@ -144,7 +155,11 @@ struct symbol_table symbol_table = { 0, 0, 0, /* for stacked module support */ X(bh_mask), X(add_timer), X(del_timer), + X(tq_timer), X(tq_immediate), + X(tq_last), + X(timer_active), + X(timer_table), /* dma handling */ X(request_dma), diff --git a/net/inet/af_inet.c b/net/inet/af_inet.c index 9cfefd1525f8..dd79ed69d124 100644 --- a/net/inet/af_inet.c +++ b/net/inet/af_inet.c @@ -1245,12 +1245,15 @@ static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) case OLD_SIOCGIFHWADDR: case SIOCSIFMAP: case SIOCGIFMAP: - case SIOCDEVPRIVATE: case SIOCSIFSLAVE: case SIOCGIFSLAVE: return(dev_ioctl(cmd,(void *) arg)); default: + if ((cmd >= SIOCDEVPRIVATE) && + (cmd <= (SIOCDEVPRIVATE + 15))) + return(dev_ioctl(cmd,(void *) arg)); + if (sk->prot->ioctl==NULL) return(-EINVAL); return(sk->prot->ioctl(sk, cmd, arg)); @@ -1304,6 +1307,12 @@ struct sock *get_sock(struct proto *prot, unsigned short num, continue; score++; } + /* + * strange but true: udp sockets don't care that much + * about the remote address. + */ + if (prot == &udp_prot) + return s; /* remote address matches? */ if (s->daddr) { if (s->daddr != raddr) diff --git a/net/inet/dev.c b/net/inet/dev.c index 4175e866fdde..97307038889a 100644 --- a/net/inet/dev.c +++ b/net/inet/dev.c @@ -1268,13 +1268,6 @@ static int dev_ifsioc(void *arg, unsigned int getset) return -EINVAL; ret=dev->set_mac_address(dev,ifr.ifr_hwaddr.sa_data); break; - - case SIOCDEVPRIVATE: - if(dev->do_ioctl==NULL) - return -EOPNOTSUPP; - ret=dev->do_ioctl(dev, &ifr); - memcpy_tofs(arg,&ifr,sizeof(struct ifreq)); - break; case SIOCGIFMAP: ifr.ifr_map.mem_start=dev->mem_start; @@ -1348,10 +1341,19 @@ static int dev_ifsioc(void *arg, unsigned int getset) break; #endif /* - * Unknown ioctl + * Unknown or private ioctl */ default: + if((getset >= SIOCDEVPRIVATE) && + (getset <= (SIOCDEVPRIVATE + 15))) { + if(dev->do_ioctl==NULL) + return -EOPNOTSUPP; + ret=dev->do_ioctl(dev, &ifr, getset); + memcpy_tofs(arg,&ifr,sizeof(struct ifreq)); + break; + } + ret = -EINVAL; } return(ret); @@ -1404,7 +1406,6 @@ int dev_ioctl(unsigned int cmd, void *arg) case SIOCSIFMEM: case SIOCSIFMAP: case SIOCSIFSLAVE: - case SIOCDEVPRIVATE: if (!suser()) return -EPERM; return dev_ifsioc(arg, cmd); @@ -1413,10 +1414,16 @@ int dev_ioctl(unsigned int cmd, void *arg) return -EINVAL; /* - * Unknown ioctl. + * Unknown or private ioctl. */ default: + if((cmd >= SIOCDEVPRIVATE) && + (cmd <= (SIOCDEVPRIVATE + 15))) { + if (!suser()) + return -EPERM; + return dev_ifsioc(arg, cmd); + } return -EINVAL; } } diff --git a/net/inet/devinet.c b/net/inet/devinet.c index ff830956042b..a0ed0b5c388e 100644 --- a/net/inet/devinet.c +++ b/net/inet/devinet.c @@ -151,7 +151,7 @@ int ip_chk_addr(unsigned long addr) return IS_BROADCAST; } } - if(IN_MULTICAST(addr)) + if(IN_MULTICAST(ntohl(addr))) return IS_MULTICAST; return 0; /* no match at all */ } diff --git a/net/inet/ip.c b/net/inet/ip.c index bb1bee640b6e..fe48ca8eb7e5 100644 --- a/net/inet/ip.c +++ b/net/inet/ip.c @@ -1851,7 +1851,7 @@ void ip_do_retransmit(struct sock *sk, int all) * If the packet is still being sent by the device/protocol * below then don't retransmit. This is both needed, and good - * especially with connected mode AX.25 where it stops resends - * occuring of an as yet unsent anyway frame! + * occurring of an as yet unsent anyway frame! * We still add up the counts as the round trip time wants * adjusting. */ diff --git a/net/inet/packet.c b/net/inet/packet.c index c1311b343902..0f6c3698d9ca 100644 --- a/net/inet/packet.c +++ b/net/inet/packet.c @@ -295,7 +295,7 @@ int packet_recvfrom(struct sock *sk, unsigned char *to, int len, skb=skb_recv_datagram(sk,flags,noblock,&err); /* - * An error occured so return it. Because skb_recv_datagram() + * An error occurred so return it. Because skb_recv_datagram() * handles the blocking we don't see and worry about blocking * retries. */ diff --git a/net/inet/route.c b/net/inet/route.c index dbf7f769dde4..58401d742c30 100644 --- a/net/inet/route.c +++ b/net/inet/route.c @@ -113,8 +113,8 @@ void ip_rt_flush(struct device *dev) unsigned long flags; rp = &rt_base; - cli(); save_flags(flags); + cli(); while ((r = *rp) != NULL) { if (r->rt_dev != dev) { rp = &r->rt_next; diff --git a/net/inet/sock.c b/net/inet/sock.c index e406aa671561..319376aa15ff 100644 --- a/net/inet/sock.c +++ b/net/inet/sock.c @@ -43,7 +43,7 @@ * Alan Cox : for new sk_buff allocations wmalloc/rmalloc now call alloc_skb * Alan Cox : kfree_s calls now are kfree_skbmem so we can track skb resources * Alan Cox : Supports socket option broadcast now as does udp. Packet and raw need fixing. - * Alan Cox : Added RCVBUF,SNDBUF size setting. It suddenly occured to me how easy it was so... + * Alan Cox : Added RCVBUF,SNDBUF size setting. It suddenly occurred to me how easy it was so... * Rick Sladkey : Relaxed UDP rules for matching packets. * C.E.Hawkins : IFF_PROMISC/SIOCGHWADDR support * Pauline Middelink : Pidentd support @@ -497,14 +497,29 @@ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) void release_sock(struct sock *sk) { struct sk_buff *skb; + unsigned long flags; if (!sk->prot) return; + /* + * Make the backlog atomic. If we don't do this there is a tiny + * window where a packet may arrive between the sk->blog being + * tested and then set with sk->inuse stil 0 causing an extra + * unwanted re-entry into release_sock(). + */ + + save_flags(flags); + cli(); if (sk->blog) + { + restore_flags(flags); return; + } + sk->blog=1; + sk->inuse = 1; + restore_flags(flags); #ifdef CONFIG_INET /* See if we have any packets built up. */ - sk->inuse = 1; while((skb = skb_dequeue(&sk->back_log)) != NULL) { sk->blog = 1; diff --git a/net/inet/tcp.c b/net/inet/tcp.c index 432c4c8ddc0d..6accbe968917 100644 --- a/net/inet/tcp.c +++ b/net/inet/tcp.c @@ -101,6 +101,10 @@ * a sensible code size. * Alan Cox : Self connect lockup fix. * Alan Cox : No connect to multicast. + * Ross Biro : Close unaccepted children on master + * socket close. + * Alan Cox : Reset tracing code. + * Alan Cox : Spurious resets on shutdown. * * * To Fix: @@ -178,6 +182,8 @@ unsigned long seq_offset; struct tcp_mib tcp_statistics; +static void tcp_close(struct sock *sk, int timeout); + #ifdef TCP_FASTPATH unsigned long tcp_rx_miss=0, tcp_rx_hit1=0, tcp_rx_hit2=0; #endif @@ -260,6 +266,42 @@ static struct sk_buff *tcp_find_established(struct sock *s) return NULL; } + +/* + * This routine closes sockets which have been at least partially + * opened, but not yet accepted. Currently it is only called by + * tcp_close, and timeout mirrors the value there. + */ + +static void tcp_close_pending (struct sock *sk, int timeout) +{ + unsigned long flags; + struct sk_buff *p, *old_p; + + save_flags(flags); + cli(); + p=skb_peek(&sk->receive_queue); + + if(p==NULL) + { + restore_flags(flags); + return; + } + + do + { + tcp_close (p->sk, timeout); + skb_unlink (p); + old_p = p; + p=p->next; + kfree_skb(old_p, FREE_READ); + } + while(p!=skb_peek(&sk->receive_queue)); + + restore_flags(flags); + return; +} + static struct sk_buff *tcp_dequeue_established(struct sock *s) { struct sk_buff *skb; @@ -1979,6 +2021,8 @@ static void tcp_conn_request(struct sock *sk, struct sk_buff *skb, } else { + if(sk->debug) + printk("Reset on %p: Connect on dead socket.\n",sk); tcp_reset(daddr, saddr, th, sk->prot, opt, dev, sk->ip_tos,sk->ip_ttl); tcp_statistics.TcpAttemptFails++; kfree_skb(skb, FREE_READ); @@ -2309,6 +2353,9 @@ static void tcp_close(struct sock *sk, int timeout) release_sock(sk); return; case TCP_LISTEN: + /* we need to drop any sockets which have been connected, + but have not yet been accepted. */ + tcp_close_pending(sk, timeout); tcp_set_state(sk,TCP_CLOSE); release_sock(sk); return; @@ -2918,7 +2965,7 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int if (sk->rcv_ack_seq == sk->write_seq && sk->acked_seq == sk->fin_seq) { flag |= 1; - tcp_set_state(sk,TCP_CLOSE); + tcp_time_wait(sk); sk->shutdown = SHUTDOWN_MASK; } } @@ -2939,7 +2986,7 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int { flag |= 1; sk->shutdown |= SEND_SHUTDOWN; - tcp_set_state(sk,TCP_FIN_WAIT2); + tcp_set_state(sk, TCP_FIN_WAIT2); } } @@ -3015,6 +3062,8 @@ static int tcp_data(struct sk_buff *skb, struct sock *sk, struct tcphdr *th; int dup_dumped=0; unsigned long new_seq; + struct sk_buff *tail; + unsigned long shut_seq; th = skb->h.th; skb->len = len -(th->doff*4); @@ -3044,11 +3093,37 @@ static int tcp_data(struct sk_buff *skb, struct sock *sk, { new_seq= th->seq + skb->len + th->syn; /* Right edge of _data_ part of frame */ - if(after(new_seq,sk->acked_seq+1)) /* If the right edge of this frame is after the last copied byte - then it contains data we will never touch. We send an RST to - ensure the far end knows it never got to the application */ + /* + * This is subtle and not nice. When we shut down we can + * have data in the queue and acked_seq therefore not + * pointing to the last byte that will be read. Thus + * the naive implementation: + * after(new_seq,sk->acked_seq+1) + * will cause bogus resets IFF a resend of a frame that has + * been queued but not yet read after a shutdown has been done + * occured.What we do now is a bit more complex but works as + * follows. If the queue is empty copied_seq+1 is right (+1 for FIN) + * if the queue has data the shutdown occurs at the right edge of + * the last packet queued +1 + * + * We can't simply ack data beyond this point as it has + * and will never be received by an application. + */ + tail=skb_peek(&sk->receive_queue); + if(tail!=NULL) + { + tail=sk->receive_queue.prev; + shut_seq=tail->h.th->seq+tail->len+1; + } + else + shut_seq=sk->copied_seq+1; + + if(after(new_seq,shut_seq)) { sk->acked_seq = new_seq + th->fin; + if(sk->debug) + printk("Data arrived on %p after close [Data right edge %lX, Socket shut on %lX] %d\n", + sk, new_seq, shut_seq, sk->blog); tcp_reset(sk->saddr, sk->daddr, skb->h.th, sk->prot, NULL, skb->dev, sk->ip_tos, sk->ip_ttl); tcp_statistics.TcpEstabResets++; @@ -3802,7 +3877,7 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, cli(); if (sk->inuse) { - skb_queue_head(&sk->back_log, skb); + skb_queue_tail(&sk->back_log, skb); sti(); return(0); } @@ -3998,7 +4073,8 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, sk->err = ECONNRESET; tcp_set_state(sk,TCP_CLOSE); sk->shutdown = SHUTDOWN_MASK; - tcp_reset(daddr, saddr, th, sk->prot, opt,dev, sk->ip_tos,sk->ip_ttl); + if(sk->debug) + printk("Socket %p reset by SYN while established.\n", sk); if (!sk->dead) { sk->state_change(sk); } @@ -4012,9 +4088,10 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, * old connection. * */ + if(st==TCP_TIME_WAIT && th->seq > sk->acked_seq && sk->dead) { - release_sock(sk); + struct sock *psk=sk; /* * Find the listening socket. */ @@ -4023,19 +4100,22 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, { sk->inuse=1; tcp_conn_request(sk, skb, daddr, saddr,opt, dev,seq+128000); - release_sock(sk); + release_sock(psk); /* Fall through in case people are also using the piggy backed SYN + data protocol violation */ } else { + tcp_reset(daddr, saddr, th, psk->prot, opt,dev, psk->ip_tos,psk->ip_ttl); + release_sock(psk); kfree_skb(skb, FREE_READ); return 0; } } else { + tcp_reset(daddr, saddr, th, sk->prot, opt,dev, sk->ip_tos,sk->ip_ttl); kfree_skb(skb, FREE_READ); release_sock(sk); return(0); @@ -4080,6 +4160,7 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, if (!th->rst) { if (!th->ack) th->ack_seq = 0; + if(sk->debug) printk("Reset on closed socket %s.\n",sk->blog); tcp_reset(daddr, saddr, th, sk->prot, opt,dev,sk->ip_tos,sk->ip_ttl); } kfree_skb(skb, FREE_READ); @@ -4093,6 +4174,7 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, return(0); } if (th->ack) { + printk("Reset on listening socket %d.\n",sk->blog); tcp_reset(daddr, saddr, th, sk->prot, opt,dev,sk->ip_tos,sk->ip_ttl); kfree_skb(skb, FREE_READ); release_sock(sk); -- 2.39.5