From c33470541c95c6df7137b50235d7a8030cab8370 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:09:40 -0500 Subject: [PATCH] Import 1.1.51 --- Makefile | 2 +- drivers/block/floppy.c | 320 +++++++++++++++++++++----------------- drivers/block/hd.c | 26 ++-- drivers/net/apricot.c | 188 ++++++++++++---------- drivers/net/lance.c | 12 +- drivers/scsi/aha152x.c | 104 ++++++++----- drivers/scsi/aha152x.h | 4 +- drivers/scsi/seagate.c | 4 +- fs/block_dev.c | 35 ++++- fs/locks.c | 45 +++++- include/asm-i386/string.h | 2 +- include/linux/fd.h | 25 ++- mm/mmap.c | 7 + mm/mprotect.c | 46 ++++-- net/inet/rarp.c | 22 --- net/inet/tcp.c | 2 +- 16 files changed, 513 insertions(+), 331 deletions(-) diff --git a/Makefile b/Makefile index be6c40521e62..43d3c82325e5 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 1 -SUBLEVEL = 50 +SUBLEVEL = 51 ARCH = i386 diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index a4a30615f545..0e20a44f0b98 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -9,6 +9,15 @@ /* 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 */ @@ -89,6 +98,9 @@ * disk types. */ +/* 1994/9/17 -- Koen Holtman -- added logging of physical floppy write + * errors to allow safe writing by specialized programs. + */ #define REALLY_SLOW_IO #define FLOPPY_IRQ 6 @@ -100,6 +112,7 @@ #include #include #include +#include #define FDPATCHES #include #include @@ -127,7 +140,7 @@ static int initialising=1; #define N_DRIVE 8 #else #define N_FDC 1 -#define N_DRIVE 2 +#define N_DRIVE 4 #endif #define TYPE(x) ( ((x)>>2) & 0x1f ) @@ -138,10 +151,12 @@ static int initialising=1; /* reverse mapping from unit and fdc to drive */ #define DP (&drive_params[current_drive]) #define DRS (&drive_state[current_drive]) +#define DRWE (&write_errors[current_drive]) #define FDCS (&fdc_state[fdc]) #define UDP (&drive_params[drive]) #define UDRS (&drive_state[drive]) +#define UDRWE (&write_errors[drive]) #define UFDCS (&fdc_state[FDC(drive)]) /* read/write */ @@ -247,6 +262,7 @@ 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_raw_cmd raw_cmd; /* @@ -299,9 +315,10 @@ static struct floppy_struct floppy_type[32] = { /* Auto-detection: Disk type used until the next media change occurs. */ struct floppy_struct *current_type[N_DRIVE] = { - NULL, NULL + NULL, NULL, NULL, NULL #ifdef HAVE_2_CONTROLLERS - ,NULL, NULL, NULL, NULL, NULL, NULL + , + NULL, NULL, NULL, NULL #endif }; @@ -386,6 +403,7 @@ static void reset_fdc(void); #define NO_TRACK -1 #define NEED_1_RECAL -2 #define NEED_2_RECAL -3 +#define PROVEN_ABSENT -4 /* buffer related variables */ static int buffer_track = -1; @@ -441,7 +459,6 @@ static int set_dor(int fdc, char mask, char data) { register unsigned char drive, unit, newdor,olddor; - cli(); olddor = FDCS->dor; newdor = (olddor & mask) | data; if ( newdor != olddor ){ @@ -456,16 +473,13 @@ static int set_dor(int fdc, char mask, char data) FDCS->dor = newdor; outb_p( newdor, FD_DOR); } - sti(); return olddor; } static void twaddle(void) { - cli(); outb_p(FDCS->dor & ~(0x10<dor, FD_DOR); - sti(); } /* reset all driver information about the current fdc. This is needed after @@ -480,6 +494,7 @@ 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; } @@ -510,10 +525,6 @@ static void lock_fdc(int drive) sti(); command_status = FD_COMMAND_NONE; set_fdc(drive); - if ( drive >= 0 ){ - timer_table[FLOPPY_TIMER].expires = jiffies + DP->timeout; - timer_active |= 1 << FLOPPY_TIMER; - } } /* unlocks the driver */ @@ -545,11 +556,12 @@ static void motor_off_callback(unsigned long nr) static struct timer_list motor_off_timer[N_DRIVE] = { { NULL, NULL, 0, 0, motor_off_callback }, - { NULL, NULL, 0, 1, motor_off_callback } -#ifdef HAVE_2_CONTROLLERS - ,{ NULL, NULL, 0, 2, motor_off_callback }, + { NULL, NULL, 0, 1, motor_off_callback }, + { NULL, NULL, 0, 2, motor_off_callback }, { NULL, NULL, 0, 3, motor_off_callback } - ,{ NULL, NULL, 0, 4, motor_off_callback }, +#ifdef HAVE_2_CONTROLLERS + , + { NULL, NULL, 0, 4, motor_off_callback }, { NULL, NULL, 0, 5, motor_off_callback }, { NULL, NULL, 0, 6, motor_off_callback }, { NULL, NULL, 0, 7, motor_off_callback } @@ -561,7 +573,6 @@ static void floppy_off(unsigned int nr) { unsigned long volatile delta; - cli(); del_timer(motor_off_timer+nr); /* make spindle stop in a position which minimizes spinup time @@ -574,7 +585,6 @@ static void floppy_off(unsigned int nr) motor_off_timer[nr].expires = drive_params[nr].spindown - delta; } add_timer(motor_off_timer+nr); - sti(); } /* @@ -592,7 +602,9 @@ static void scandrives(void) if ( UDRS->fd_ref == 0 ) continue; /* skip closed drives */ set_fdc(drive); - UDRS->select_date = jiffies; + 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 @@ -610,14 +622,13 @@ static struct timer_list fd_timer ={ NULL, NULL, 0, 0, 0 }; static void fd_watchdog(void) { if ( inb_p( FD_DIR ) & 0x80 ){ + changed_floppies |= ( 1 << current_drive); floppy_shutdown(); } else { - cli(); del_timer(&fd_timer); fd_timer.function = (timeout_fn) fd_watchdog; fd_timer.expires = 10; add_timer(&fd_timer); - sti(); } } @@ -986,7 +997,8 @@ static int interpret_errors(void) } else if (ST2 & ST2_BC) { /* cylinder marked as bad */ printk("bad cylinder"); } else { - printk("unknown error. ST[0..3] are: 0x%x 0x%x 0x%x 0x%x\n", ST0, ST1, ST2, ST3); + printk("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x", ST0, ST1, ST2); + tell_sector(); } printk("\n"); @@ -1101,6 +1113,7 @@ static void seek_floppy(void) * If it isn't, this means that there is really no disk in * the drive. */ + changed_floppies |= ( 1 << current_drive); cont->done(0); cont->redo(); return; @@ -1148,13 +1161,25 @@ 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:"); +#endif /* after a second recalibrate, we still haven't * reached track 0. Probably no drive */ - cont->error(); + DRS->track = PROVEN_ABSENT; + cont->done(0); cont->redo(); return; case NEED_2_RECAL: +#ifdef DEBUGT + debugt("recal interrupt need 2 recal:"); +#endif /* If we already did a recalibrate, and we are not at * track 0, this means we have moved. (The only way * not to move at recalibration is to be already at @@ -1163,6 +1188,9 @@ static void recal_interrupt(void) DRS->flags &= ~FD_DISK_NEWCHANGE; /* fall through */ default: +#ifdef DEBUGT + debugt("recal interrupt default:"); +#endif /* Recalibrate moves the head by at most 80 steps. If * after one recalibrate we don't have reached track * 0, this might mean that we started beyond track 80. @@ -1186,6 +1214,7 @@ static void unexpected_floppy_interrupt(void) if ( initialising ) return; printk(DEVICE_NAME ": unexpected interrupt\n"); + inr = result(); if ( inr >= 0 ) for(i=0; ireset = 1; } -/* interrupt handler */ -static void floppy_interrupt(int unused) +static void floppy_bh(void (*handler)(void)) { - void (*handler)(void) = DEVICE_INTR; - - CLEAR_INTR; - if ( fdc >= N_FDC ) /* we don't even know which FDC is the culprit */ - return; inr = result(); - if (!handler){ - unexpected_floppy_interrupt(); - return; - } if ( inr == 0 ){ do { output_byte(FD_SENSEI); inr = result(); } while ( (ST0 & 0x83) != UNIT(current_drive) && inr == 2); } - sti(); /* this should help improve interrupt latency. */ handler(); } +struct tq_struct floppy_tq = +{ 0, 0, (void *) (void *) floppy_bh, 0 }; + +/* interrupt handler */ +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"); + return; + } + if (!handler) + unexpected_floppy_interrupt(); + else { + floppy_tq.data = (void *) handler; + queue_task_irq(&floppy_tq, &tq_timer); + } +} + static void recalibrate_floppy(void) { +#ifdef DEBUGT + debugt("recalibrate floppy:"); +#endif SET_INTR(recal_interrupt); output_byte(FD_RECALIBRATE); LAST_OUT(UNIT(current_drive)); @@ -1258,24 +1300,21 @@ static void reset_fdc(void) if ( FDCS->version >= FDC_82077 ) outb_p(0x80 | ( FDCS->dtr &3), FD_STATUS); else { - cli(); outb_p(FDCS->dor & ~0x04, FD_DOR); udelay(FD_RESET_DELAY); outb(FDCS->dor, FD_DOR); - sti(); } } +static void empty(void) +{ +} + static void floppy_shutdown(void) { - cli(); - if ( !DEVICE_INTR ){ /* no interrupt pending. Probably has just been - * served */ - sti(); - return; - } + del_timer( &fd_timer); CLEAR_INTR; - sti(); + floppy_tq.data = (void *) empty; if ( !initialising ) printk(DEVICE_NAME ": timeout\n"); FDCS->reset = 1; @@ -1393,16 +1432,13 @@ static void floppy_on(unsigned int drive) * General purpose continuations. * ============================== */ -static void empty(void) -{ -} static void do_wakeup(void) { timer_active &= ~(1 << FLOPPY_TIMER); + cont = 0; command_status += 2; wake_up(&command_done); - cont = 0; } static struct cont_t wakeup_cont={ @@ -1415,9 +1451,12 @@ static struct cont_t wakeup_cont={ static int wait_til_done(void) { int ret; + while(command_status < 2) if (current->pid) sleep_on( & command_done ); + else + run_task_queue(&tq_timer); if ( FDCS->reset ) command_status = FD_COMMAND_ERROR; if ( command_status == FD_COMMAND_OKAY ) @@ -1487,6 +1526,8 @@ static void bad_flp_intr(void) return; } (*errors)++; + if (*errors > DRWE->badness) + DRWE->badness = *errors; if (*errors > DP->max_errors.abort) cont->done(0); if (*errors > DP->max_errors.reset) @@ -1520,23 +1561,25 @@ static void format_interrupt(void) cont->redo(); } +#define CODE2SIZE (ssize = ( ( 1 << SIZECODE ) + 3 ) >> 2) +#define FM_MODE(x,y) ((y) & ~(((x)->rate & 0x80 ) >>1)) +#define CT(x) ( (x) | 0x40 ) static void setup_format_params(void) { struct fparm { unsigned char track,head,sect,size; } *here = (struct fparm *)floppy_track_buffer; - int ssize,il,n; + int il,n; int count,head_shift,track_shift; raw_cmd.flags = FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK; raw_cmd.rate = floppy->rate & 0x3; raw_cmd.cmd_count = NR_F; - COMMAND = FD_FORMAT; + COMMAND = FM_MODE(floppy,FD_FORMAT); DR_SELECT = UNIT(current_drive) + ( format_req.head << 2 ); F_SIZECODE = FD_SIZECODE(floppy); - ssize = 1 << ( F_SIZECODE - 2 ); - F_SECT_PER_TRACK = floppy->sect / ssize; + F_SECT_PER_TRACK = floppy->sect << 2 >> F_SIZECODE; F_GAP = floppy->fmt_gap; F_FILL = FD_FILL_BYTE; @@ -1555,7 +1598,7 @@ static void setup_format_params(void) /* determine interleave */ il = 1; - if (floppy->sect > DP->interleave_sect && ssize==1) + if (floppy->sect > DP->interleave_sect && F_SIZECODE == 2) il++; /* initialize field */ @@ -1667,11 +1710,16 @@ static void request_done(int uptodate) printk(DEVICE_NAME "request list destroyed in floppy request done\n"); } else { -#ifdef NO_WEIRD_UNLOCKED - if ( CURRENT->bh ) - /* avoid those pesky "Weird unlocked ... errors" */ - CURRENT->bh->b_req = 0; -#endif + if(CURRENT->cmd == WRITE) { + /* record write error information */ + DRWE->write_errors++; + if(DRWE->write_errors == 1) { + DRWE->first_error_sector = CURRENT->sector; + DRWE->first_error_generation = DRS->generation; + } + DRWE->last_error_sector = CURRENT->sector; + DRWE->last_error_generation = DRS->generation; + } end_request(0); } } @@ -1689,9 +1737,9 @@ static void rw_interrupt(void) DRS->first_read_date = jiffies; nr_sectors = 0; - ssize = 1 << (SIZECODE - 2); + CODE2SIZE; nr_sectors = ((R_TRACK-TRACK)*floppy->head+R_HEAD-HEAD) * - floppy->sect + (R_SECTOR-SECTOR) * ssize - + floppy->sect + ((R_SECTOR-SECTOR) << SIZECODE >> 2) - (sector_t % floppy->sect) % ssize; #ifdef SANITY @@ -1767,10 +1815,10 @@ static void rw_interrupt(void) probing = 0; } - if ( COMMAND != FD_READ || current_addr == CURRENT->buffer ){ + if ( CT(COMMAND) != FD_READ || current_addr == CURRENT->buffer ){ /* transfer directly from buffer */ cont->done(1); - } else if ( COMMAND == FD_READ){ + } else if ( CT(COMMAND) == FD_READ){ buffer_track = raw_cmd.track; buffer_drive = current_drive; if ( nr_sectors + sector_t > buffer_max ) @@ -1835,7 +1883,7 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2) max_sector = transfer_size(ssize, max_sector, CURRENT->nr_sectors); - if (current_count_sectors <= 0 && COMMAND == FD_WRITE && + if (current_count_sectors <= 0 && CT(COMMAND) == FD_WRITE && buffer_max > sector_t + CURRENT->nr_sectors){ current_count_sectors = buffer_max - sector_t; if ( current_count_sectors > CURRENT->nr_sectors ) @@ -1843,7 +1891,8 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2) } remaining = current_count_sectors << 9; #ifdef SANITY - if ((remaining >> 9) > CURRENT->nr_sectors && COMMAND == 0xc5 ){ + if ((remaining >> 9) > CURRENT->nr_sectors && + CT(COMMAND) == FD_WRITE ){ printk(DEVICE_NAME ": in copy buffer\n"); printk("current_count_sectors=%ld\n", current_count_sectors); printk("remaining=%d\n", remaining >> 9); @@ -1883,16 +1932,16 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2) sector_t, buffer_min); printk("current_count_sectors=%ld\n", current_count_sectors); - if ( COMMAND == FD_READ ) + if ( CT(COMMAND) == FD_READ ) printk("read\n"); - if ( COMMAND == FD_READ ) + if ( CT(COMMAND) == FD_READ ) printk("write\n"); break; } if ( ((int)buffer) % 512 ) printk(DEVICE_NAME ": %p buffer not aligned\n", buffer); #endif - if ( COMMAND == FD_READ ) + if ( CT(COMMAND) == FD_READ ) memcpy( buffer, dma_buffer, size); else memcpy( dma_buffer, buffer, size); @@ -1944,10 +1993,10 @@ static int make_raw_rw_request(void) raw_cmd.cmd_count = NR_RW; if (CURRENT->cmd == READ){ raw_cmd.flags |= FD_RAW_READ; - COMMAND = FD_READ; + COMMAND = FM_MODE(floppy,FD_READ); } else if (CURRENT->cmd == WRITE){ raw_cmd.flags |= FD_RAW_WRITE; - COMMAND = FD_WRITE; + COMMAND = FM_MODE(floppy,FD_WRITE); } else { printk(DEVICE_NAME ": make_raw_rw_request: unknown command\n"); @@ -1982,13 +2031,16 @@ static int make_raw_rw_request(void) raw_cmd.rate == 2) raw_cmd.rate = 1; - SIZECODE2 = 0xff; + if ( SIZECODE ) + SIZECODE2 = 0xff; + else + SIZECODE2 = 0x80; raw_cmd.track = TRACK << floppy->stretch; DR_SELECT = UNIT(current_drive) + ( HEAD << 2 ); GAP = floppy->gap; - ssize = 1 << (SIZECODE - 2 ); - SECT_PER_TRACK = floppy->sect / ssize; - SECTOR = (sector_t % floppy->sect) / ssize + 1; + CODE2SIZE; + SECT_PER_TRACK = floppy->sect << 2 >> SIZECODE; + SECTOR = ((sector_t % floppy->sect) << 2 >> SIZECODE) + 1; tracksize = floppy->sect - floppy->sect % ssize; if ( tracksize < floppy->sect ){ SECT_PER_TRACK ++; @@ -2011,12 +2063,12 @@ static int make_raw_rw_request(void) if ((raw_cmd.track == buffer_track) && (current_drive == buffer_drive) && (sector_t >= buffer_min) && (sector_t < buffer_max)) { /* data already in track buffer */ - if (COMMAND == FD_READ) { + if (CT(COMMAND) == FD_READ) { copy_buffer(1, max_sector, buffer_max); return 1; } } else if (aligned_sector_t != sector_t || CURRENT->nr_sectors < ssize){ - if (COMMAND == FD_WRITE){ + if (CT(COMMAND) == FD_WRITE){ if(sector_t + CURRENT->nr_sectors > ssize && sector_t + CURRENT->nr_sectors < ssize + ssize) max_size = ssize + ssize; @@ -2025,7 +2077,7 @@ static int make_raw_rw_request(void) } raw_cmd.flags &= ~FD_RAW_WRITE; raw_cmd.flags |= FD_RAW_READ; - COMMAND = FD_READ; + COMMAND = FM_MODE(floppy,FD_READ); } else if ((long)CURRENT->buffer <= LAST_DMA_ADDR ) { int direct, indirect; @@ -2060,14 +2112,14 @@ static int make_raw_rw_request(void) } } - if ( COMMAND == FD_READ ) + if ( CT(COMMAND) == FD_READ ) max_size = max_sector; /* unbounded */ /* claim buffer track if needed */ if (buffer_track != raw_cmd.track || /* bad track */ buffer_drive !=current_drive || /* bad drive */ sector_t < buffer_min || - ((COMMAND == FD_READ || + ((CT(COMMAND) == FD_READ || (aligned_sector_t == sector_t && CURRENT->nr_sectors >= ssize ))&& max_sector > 2 * MAX_BUFFER_SECTORS + buffer_min && max_size + sector_t > 2 * MAX_BUFFER_SECTORS + buffer_min) @@ -2078,7 +2130,7 @@ static int make_raw_rw_request(void) } current_addr = floppy_track_buffer +((aligned_sector_t-buffer_min )<<9); - if ( COMMAND == FD_WRITE ){ + if ( CT(COMMAND) == FD_WRITE ){ /* copy write buffer to track buffer. * if we get here, we know that the write * is either aligned or the data already in the buffer @@ -2101,10 +2153,11 @@ static int make_raw_rw_request(void) raw_cmd.length <<= 9; #ifdef SANITY if ((raw_cmd.length < current_count_sectors << 9) || - (current_addr != CURRENT->buffer && COMMAND == FD_WRITE && + (current_addr != CURRENT->buffer && + CT(COMMAND) == FD_WRITE && (aligned_sector_t + (raw_cmd.length >> 9) > buffer_max || aligned_sector_t < buffer_min )) || - raw_cmd.length % ( 512 << ( SIZECODE -2 )) || + raw_cmd.length % ( 128 << SIZECODE ) || raw_cmd.length <= 0 || current_count_sectors <= 0){ printk(DEVICE_NAME ": fractionary current count b=%lx s=%lx\n", raw_cmd.length, current_count_sectors); @@ -2137,9 +2190,9 @@ static int make_raw_rw_request(void) raw_cmd.length >> 9 ); printk("current_count_sectors=%ld\n", current_count_sectors); - if ( COMMAND == FD_READ ) + if ( CT(COMMAND) == FD_READ ) printk("read\n"); - if ( COMMAND == FD_READ ) + if ( CT(COMMAND) == FD_READ ) printk("write\n"); return 0; } @@ -2206,8 +2259,10 @@ static void redo_fd_request(void) request_done(tmp); continue; } + if ( DRS->flags & FD_NEED_TWADDLE ) twaddle(); + floppy_on(current_drive); #ifdef DEBUGT debugt("queue fd request"); @@ -2225,6 +2280,8 @@ static struct cont_t rw_cont={ void do_fd_request(void) { + if ( fdc_busy) + printk("do fd request\n"); lock_fdc(-1); cont = &rw_cont; redo_fd_request(); @@ -2268,6 +2325,8 @@ static int user_reset_fdc(int drive, int arg) reset_fdc(); result=wait_til_done(); } + if ( UDRS->track == PROVEN_ABSENT ) + UDRS->track = NEED_2_RECAL; unlock_fdc(); return result; } @@ -2357,7 +2416,7 @@ static int raw_cmd_ioctl(int drive, void *param) current_addr = floppy_track_buffer; raw_cmd.flags |= FD_RAW_USER_SUPPLIED; - cont = &raw_cmd_cont; + cont = &raw_cmd_cont; floppy_on(current_drive); ret=wait_til_done(); @@ -2385,11 +2444,9 @@ static int raw_cmd_ioctl(int drive, void *param) static int invalidate_drive(int rdev) { /* invalidate the buffer track to force a reread */ - cli(); fake_change |= 1 << DRIVE(rdev); - sti(); - unlock_fdc(); check_disk_change(rdev); + unlock_fdc(); return 0; } @@ -2442,10 +2499,20 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, return COPYOUT(*UFDCS); case FDGETDRVPRM: return COPYOUT(*UDP); + case FDWERRORGET: + return COPYOUT(*UDRWE); } if (!IOCTL_ALLOWED) return -EPERM; switch (cmd) { + case FDWERRORCLR: + 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; + return 0; case FDRAWCMD: if (type) return -EINVAL; @@ -2457,7 +2524,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, case FDFMTTRK: if (UDRS->fd_ref != 1) return -EBUSY; - if (! (UDRS->flags & FD_DRIVE_PRESENT )) + if (UDRS->track == PROVEN_ABSENT) return -ENXIO; COPYIN(tmp_format_req); return do_format(device, &tmp_format_req); @@ -2492,7 +2559,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, for ( cnt = 0; cnt < N_DRIVE; cnt++){ if (TYPE(drive_state[cnt].fd_device) == type && drive_state[cnt].fd_ref){ - cli(); fake_change |= 1 << cnt; sti(); + fake_change |= 1 << cnt; } } floppy_type[type] = newparams; @@ -2631,6 +2698,8 @@ static int floppy_##op(struct inode * inode, struct file * filp, \ char * buf, int count) \ { \ maybe_check_change(inode->i_rdev); \ + if ( drive_state[DRIVE(inode->i_rdev)].track == PROVEN_ABSENT ) \ + return -ENXIO; \ if ( changed_floppies & ( 1 << DRIVE(inode->i_rdev) )) \ return -ENXIO; \ return block_##op(inode, filp, buf, count); \ @@ -2644,7 +2713,8 @@ static void floppy_release(struct inode * inode, struct file * filp) { int drive= DRIVE(inode->i_rdev); - fsync_dev(inode->i_rdev); + if(filp->f_mode & 2) + fsync_dev(inode->i_rdev); if ( UDRS->fd_ref < 0) UDRS->fd_ref=0; else if (!UDRS->fd_ref--) { @@ -2678,7 +2748,7 @@ static int floppy_open(struct inode * inode, struct file * filp) } drive = DRIVE(inode->i_rdev); - if ( drive >= N_DRIVE ) + if ( drive >= N_DRIVE || !( ALLOWED_DRIVE_MASK & ( 1 << drive)) ) return -ENXIO; if (command_status == FD_COMMAND_DETECT && drive >= current_drive) { @@ -2689,10 +2759,9 @@ static int floppy_open(struct inode * inode, struct file * filp) if (TYPE(inode->i_rdev) >= NUMBER(floppy_type)) return -ENXIO; - if (filp->f_mode & 3) { - if ( !(UDRS->flags & FD_DRIVE_PRESENT)) - 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) @@ -2727,7 +2796,7 @@ static int floppy_open(struct inode * inode, struct file * filp) if (filp->f_flags & O_NDELAY) return 0; - if (filp->f_mode && !(UDRS->flags & FD_DRIVE_PRESENT)) + if (filp->f_mode && UDRS->track == PROVEN_ABSENT ) RETERR(ENXIO); if (user_reset_fdc(drive, FD_RESET_IF_NEEDED)) @@ -2738,6 +2807,10 @@ static int floppy_open(struct inode * inode, struct file * filp) if (changed_floppies & ( 1 << drive )) RETERR(ENXIO); } + + if (filp->f_mode && UDRS->track == PROVEN_ABSENT ) + RETERR(ENXIO); + if ((filp->f_mode & 2) && !(UDRS->flags & FD_DISK_WRITABLE)) RETERR(EROFS); return 0; @@ -2789,17 +2862,18 @@ static int check_floppy_change(dev_t dev) } /* revalidate the floppy disk, i.e. trigger format autodetection by reading - * the bootblock (block 0) */ + * the bootblock (block 0). "Autodetection" is also needed to check wether + * 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) { struct buffer_head * bh; - if ( TYPE(dev) || current_type[DRIVE(dev)] ) - return 0; if (!(bh = getblk(dev,0,1024))) return 1; if ( bh && ! bh->b_uptodate) ll_rw_block(READ, 1, &bh); + wait_on_buffer(bh); brelse(bh); return 0; } @@ -2808,7 +2882,7 @@ static struct file_operations floppy_fops = { NULL, /* lseek - default */ floppy_read, /* read - general block-dev read */ floppy_write, /* write - general block-dev write */ - NULL, /* readdir - bad */ + NULL, /* readdir - bad */ NULL, /* select */ fd_ioctl, /* ioctl */ NULL, /* mmap */ @@ -2868,37 +2942,6 @@ static char get_fdc_version(void) return FDC_82077; /* Revised 82077AA passes all the tests */ } /* fdc_init */ -/* - * Drive detection routine. This runs in the background while the kernel - * does other (non floppy related) initialisation work. - */ -static void detect_interrupt(void) -{ - if ( DRS->track == 0 ) - DRS->flags |= FD_DRIVE_PRESENT | FD_VERIFY; - else if ( DRS->track != NEED_1_RECAL ){ - floppy_ready(); - return; - } - floppy_off(current_drive); - current_drive++; - if (current_drive == N_DRIVE || - fdc_state[FDC(current_drive)].version == FDC_NONE){ - set_fdc(0); - unlock_fdc(); - floppy_release_irq_and_dma(); - return; - } - set_fdc(current_drive); - floppy_ready(); /* next */ -} - -static struct cont_t detect_cont={ - detect_interrupt, - detect_interrupt, - empty, - (done_f) empty }; - void floppy_init(void) { int i; @@ -2941,6 +2984,12 @@ void floppy_init(void) 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; } floppy_grab_irq_and_dma(); @@ -2963,15 +3012,8 @@ void floppy_init(void) } fdc=0; current_drive = 0; - lock_fdc(-1); - initialising =0; - command_status = FD_COMMAND_DETECT; - cont = &detect_cont; - raw_cmd.cmd_count = 0; - raw_cmd.flags = FD_RAW_NEED_SEEK; - raw_cmd.track = 0; - floppy_ready(); - cli(); + floppy_release_irq_and_dma(); + initialising=0; } int floppy_grab_irq_and_dma(void) diff --git a/drivers/block/hd.c b/drivers/block/hd.c index b0f39069ee2b..08a77c0848d7 100644 --- a/drivers/block/hd.c +++ b/drivers/block/hd.c @@ -212,7 +212,7 @@ static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect, if (reset) return; if (!controller_ready(drive, head)) { - special_op[drive] += reset = 1; + reset = 1; return; } SET_INTR(intr_addr); @@ -311,7 +311,7 @@ static void identify_intr(void) /* In fact, we should probably do a reset in any case in */ /* case we changed the geometry */ if (!strncmp(id.model, "QUANTUM", 7)) - special_op[dev] += reset = 1; + reset = 1; /* flush remaining 384 (reserved/undefined) ID bytes: */ insw(HD_DATA,(char *)&id,sizeof(id)/2); @@ -439,7 +439,7 @@ static void bad_rw_intr(void) end_request(0); special_op[dev] += recalibrate[dev] = 1; } else if (CURRENT->errors % RESET_FREQ == 0) - special_op[dev] += reset = 1; + reset = 1; else if ((hd_error & TRK0_ERR) || CURRENT->errors % RECAL_FREQ == 0) special_op[dev] += recalibrate[dev] = 1; /* Otherwise just retry */ @@ -644,7 +644,7 @@ static void hd_times_out(void) sti(); if (!CURRENT) return; - special_op [DEVICE_NR(CURRENT->dev)] += reset = 1; + reset = 1; printk(KERN_DEBUG "HD timeout\n"); cli(); if (++CURRENT->errors >= MAX_ERRORS) { @@ -701,16 +701,16 @@ repeat: #endif if (!unmask_intr[dev]) cli(); + if (reset) { + int i; + + for (i=0; i < NR_HD; i++) + special_op[i] = recalibrate[i] = 1; + cli(); /* better play it safe, as resets are the last resort */ + reset_hd(); + return; + } if (special_op[dev]) { /* we use "special_op" to reduce overhead on r/w */ - if (reset) { - int i; - - for (i=0; i < NR_HD; i++) - special_op[i] = recalibrate[i] = 1; - cli(); /* better play it safe, as resets are the last resort */ - reset_hd(); - return; - } if (recalibrate[dev]) { recalibrate[dev] = 0; hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr); diff --git a/drivers/net/apricot.c b/drivers/net/apricot.c index 15609dc42354..de840783d0c2 100644 --- a/drivers/net/apricot.c +++ b/drivers/net/apricot.c @@ -188,20 +188,18 @@ static void i596_interrupt(int reg_ptr); static int i596_close(struct device *dev); static struct enet_statistics *i596_get_stats(struct device *dev); static void i596_add_cmd(struct device *dev, struct i596_cmd *cmd); -static void i596_cleanup_cmd(struct i596_private *lp); static void print_eth(char *); #ifdef HAVE_MULTICAST static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); #endif - static inline void init_rx_bufs(struct device *dev) { struct i596_private *lp = (struct i596_private *)dev->priv; int i; - int boguscnt = 50; + int boguscnt = 100; short ioaddr = dev->base_addr; if (i596_debug > 1) printk ("%s: init_rx_bufs.\n", dev->name); @@ -249,7 +247,7 @@ init_i596_mem(struct device *dev) { struct i596_private *lp = (struct i596_private *)dev->priv; short ioaddr = dev->base_addr; - int boguscnt = 50; + int boguscnt = 100; /* change the scp address */ outw(0, ioaddr); @@ -295,8 +293,16 @@ init_i596_mem(struct device *dev) init_rx_bufs(dev); - return; + boguscnt=200; + while (lp->scb.status, lp->scb.command) + if (--boguscnt == 0) + { + printk("i82596 init timed out with status %4.4x, cmd %4.4x.\n", + lp->scb.status, lp->scb.command); + break; + } + return; } static inline int @@ -361,77 +367,11 @@ i596_rx(struct device *dev) return 0; } - -static void i596_add_cmd(struct device *dev, struct i596_cmd *cmd) -{ - struct i596_private *lp = (struct i596_private *)dev->priv; - int ioaddr = dev->base_addr; - unsigned long flags; - int boguscnt = 50; - - if (i596_debug > 4) printk ("i596_add_cmd\n"); - - cmd->status = 0; - cmd->command |= (CMD_EOL|CMD_INTR); - cmd->next = (struct i596_cmd *) -1; - - save_flags(flags); - cli(); - if (lp->cmd_head != (struct i596_cmd *) -1) - lp->cmd_tail->next = cmd; - else - { - lp->cmd_head=cmd; - while (lp->scb.status, lp->scb.command) - if (--boguscnt == 0) - { - printk("i596_add_cmd timed out with status %4.4x, cmd %4.4x.\n", - lp->scb.status, lp->scb.command); - break; - } - - lp->scb.cmd = cmd; - lp->scb.command = CUC_START; - outw (0, ioaddr+4); - } - lp->cmd_tail=cmd; - lp->cmd_backlog++; - - lp->cmd_head=lp->scb.cmd; - restore_flags(flags); - - if (lp->cmd_backlog > 8) - { - int tickssofar = jiffies - lp->last_cmd; - if (tickssofar < 10) - return; - printk("%s: command unit timed out, status resetting.\n", - dev->name); - - boguscnt = 50; - while (lp->scb.status, lp->scb.command) - if (--boguscnt == 0) - { - printk("i596_add_cmd timed out with status %4.4x, cmd %4.4x.\n", - lp->scb.status, lp->scb.command); - break; - } - lp->scb.command=CUC_ABORT|RX_ABORT; - outw(0, ioaddr+4); - - i596_cleanup_cmd(lp); - i596_rx(dev); - init_i596_mem(dev); - } - -} - - - -static void i596_cleanup_cmd(struct i596_private *lp) +static inline void +i596_cleanup_cmd(struct i596_private *lp) { struct i596_cmd *ptr; - int boguscnt = 50; + int boguscnt = 100; if (i596_debug > 4) printk ("i596_cleanup_cmd\n"); @@ -482,8 +422,96 @@ static void i596_cleanup_cmd(struct i596_private *lp) lp->scb.cmd = lp->cmd_head; } +static inline void +i596_reset(struct device *dev, struct i596_private *lp, int ioaddr) +{ + int boguscnt = 100; + if (i596_debug > 4) printk ("i596_reset\n"); + while (lp->scb.status, lp->scb.command) + if (--boguscnt == 0) + { + printk("i596_reset timed out with status %4.4x, cmd %4.4x.\n", + lp->scb.status, lp->scb.command); + break; + } + + dev->start=0; + dev->tbusy=1; + + lp->scb.command=CUC_ABORT|RX_ABORT; + outw(0, ioaddr+4); + + /* wait for shutdown */ + boguscnt = 400; + + while ((lp->scb.status, lp->scb.command) || lp->scb.command) + if (--boguscnt == 0) + { + printk("i596_reset 2 timed out with status %4.4x, cmd %4.4x.\n", + lp->scb.status, lp->scb.command); + break; + } + + i596_cleanup_cmd(lp); + i596_rx(dev); + + dev->start=1; + dev->tbusy=0; + dev->interrupt=0; + init_i596_mem(dev); +} + +static void i596_add_cmd(struct device *dev, struct i596_cmd *cmd) +{ + struct i596_private *lp = (struct i596_private *)dev->priv; + int ioaddr = dev->base_addr; + unsigned long flags; + int boguscnt = 100; + + if (i596_debug > 4) printk ("i596_add_cmd\n"); + + cmd->status = 0; + cmd->command |= (CMD_EOL|CMD_INTR); + cmd->next = (struct i596_cmd *) -1; + + save_flags(flags); + cli(); + if (lp->cmd_head != (struct i596_cmd *) -1) + lp->cmd_tail->next = cmd; + else + { + lp->cmd_head=cmd; + while (lp->scb.status, lp->scb.command) + if (--boguscnt == 0) + { + printk("i596_add_cmd timed out with status %4.4x, cmd %4.4x.\n", + lp->scb.status, lp->scb.command); + break; + } + + lp->scb.cmd = cmd; + lp->scb.command = CUC_START; + outw (0, ioaddr+4); + } + lp->cmd_tail=cmd; + lp->cmd_backlog++; + + lp->cmd_head=lp->scb.cmd; + restore_flags(flags); + + if (lp->cmd_backlog > 16) + { + int tickssofar = jiffies - lp->last_cmd; + + if (tickssofar < 25) return; + + printk("%s: command unit timed out, status resetting.\n", dev->name); + + i596_reset(dev, lp, ioaddr); + } +} static int i596_open(struct device *dev) @@ -528,13 +556,9 @@ i596_start_xmit(struct sk_buff *skb, struct device *dev) /* Try to restart the adaptor */ if (lp->last_restart == lp->stats.tx_packets) { if (i596_debug > 1) printk ("Resetting board.\n"); - /* Shutdown and restart */ - - lp->scb.command=CUC_ABORT|RX_ABORT; - outw(0, ioaddr+4); - i596_cleanup_cmd(lp); - init_i596_mem(dev); + /* Shutdown and restart */ + i596_reset(dev,lp, ioaddr); } else { /* Issue a channel attention signal */ if (i596_debug > 1) printk ("Kicking board.\n"); @@ -605,7 +629,6 @@ i596_start_xmit(struct sk_buff *skb, struct device *dev) return 0; } - static void print_eth(char *add) { @@ -676,7 +699,6 @@ unsigned long apricot_init(unsigned long mem_start, unsigned long mem_end) return mem_start; } - static void i596_interrupt(int reg_ptr) { @@ -684,7 +706,7 @@ i596_interrupt(int reg_ptr) struct device *dev = (struct device *)(irq2dev_map[irq]); struct i596_private *lp; short ioaddr; - int boguscnt = 100; + int boguscnt = 200; unsigned short status, ack_cmd=0; if (dev == NULL) { diff --git a/drivers/net/lance.c b/drivers/net/lance.c index b4f861cb5618..ff69b4247152 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -72,7 +72,7 @@ have on-board buffer memory needed to support the slower shared memory mode.) Most ISA boards have jumpered settings for the I/O base, IRQ line, and DMA channel. This driver probes the likely base addresses: {0x300, 0x320, 0x340, 0x360}. -After the board is found it generates an DMA-timeout interrupt and uses +After the board is found it generates a DMA-timeout interrupt and uses autoIRQ to find the IRQ line. The DMA channel can be set with the low bits of the otherwise-unused dev->mem_start value (aka PARAM1). If unset it is probed for by enabling each free DMA channel in turn and checking if @@ -102,14 +102,14 @@ statically allocates full-sized (slightly oversized -- PKT_BUF_SZ) buffers to avoid the administrative overhead. For the Rx side this avoids dynamically allocating full-sized buffers "just in case", at the expense of a memory-to-memory data copy for each packet received. For most systems this -is an good tradeoff: the Rx buffer will always be in low memory, the copy +is a good tradeoff: the Rx buffer will always be in low memory, the copy is inexpensive, and it primes the cache for later packet processing. For Tx the buffers are only used when needed as low-memory bounce buffers. IIIB. 16M memory limitations. For the ISA bus master mode all structures used directly by the LANCE, the initialization block, Rx and Tx rings, and data buffers, must be -accessable from the ISA bus, i.e. in the lower 16M of real memory. +accessible from the ISA bus, i.e. in the lower 16M of real memory. This is a problem for current Linux kernels on >16M machines. The network devices are initialized after memory initialization, and the kernel doles out memory from the top of memory downward. The current solution is to have a @@ -237,7 +237,7 @@ static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); /* This lance probe is unlike the other board probes in 1.0.*. The LANCE may have to allocate a contiguous low-memory region for bounce buffers. - This requirement is satified by having the lance initialization occur before the + This requirement is satisfied by having the lance initialization occur before the memory management system is started, and thus well before the other probes. */ unsigned long lance_init(unsigned long mem_start, unsigned long mem_end) { @@ -737,7 +737,7 @@ lance_interrupt(int reg_ptr) lp->tx_ring[entry].base = 0; - if (status & 0x40000000) { /* There was an major error, log it. */ + if (status & 0x40000000) { /* There was a major error, log it. */ int err_status = lp->tx_ring[entry].misc; lp->stats.tx_errors++; if (err_status & 0x0400) lp->stats.tx_aborted_errors++; @@ -808,7 +808,7 @@ lance_rx(struct device *dev) int status = lp->rx_ring[entry].base >> 24; if (status != 0x03) { /* There was an error. */ - /* There is an tricky error noted by John Murphy, + /* There is a tricky error noted by John Murphy, to Russ Nelson: Even with full-sized buffers it's possible for a jabber packet to use two buffers, with only the last correctly noting the error. */ diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index 1a2dfc575425..b1d0c8cd9eb7 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -20,10 +20,19 @@ * General Public License for more details. * - * $Id: aha152x.c,v 1.2 1994/07/03 12:56:36 root Exp $ + * $Id: aha152x.c,v 1.4 1994/09/12 11:33:01 root Exp $ * * $Log: aha152x.c,v $ + * Revision 1.4 1994/09/12 11:33:01 root + * - irqaction to request_irq + * - abortion updated + * + * Revision 1.3 1994/08/04 13:53:05 root + * - updates for mid-level-driver changes + * - accept unexpected BUSFREE phase as error condition + * - parity check now configurable + * * Revision 1.2 1994/07/03 12:56:36 root * - cleaned up debugging code * - more tweaking on reset delays @@ -133,19 +142,20 @@ AUTOCONF : use configuration the controller reports (only 152x) IRQ : override interrupt channel (9,10,11 or 12) (default 11) SCSI_ID : override scsiid of AIC-6260 (0-7) (default 7) - RECONNECT : override target dis-/reconnection/multiple outstanding commands + RECONNECT : override target dis-/reconnection/multiple outstanding commands (default on) + PARITY : override parity check (default on) SKIP_BIOSTEST : Don't test for BIOS signature (AHA-1510 or disabled BIOS) PORTBASE : Force port base. Don't try to probe LILO COMMAND LINE OPTIONS: - aha152x=,,, + aha152x=[,[,[,[,]]]] The normal configuration can be overridden by specifying a command line. When you do this, the BIOS test is skipped. Entered values have to be valid (known). Don't use values that aren't support under normal operation. - If you think that you need other value: contact me. + If you think that you need other values: contact me. REFERENCES USED: @@ -175,7 +185,7 @@ #include #include "../block/blk.h" #include "scsi.h" -#include "sd.h" /* Reqd for biosparam definition */ +#include "sd.h" #include "hosts.h" #include "constants.h" #include @@ -201,6 +211,9 @@ #if !defined(RECONNECT) #error undefined RECONNECT; define AUTOCONF or RECONNECT #endif +#if !defined(PARITY) +#error undefined PARITY; define AUTOCONF or PARITY +#endif #endif /* I use this when I'm looking for weird bugs */ @@ -250,6 +263,7 @@ static char *aha152x_id = AHA152X_REVID; static int port_base = 0; static int this_host = 0; static int can_disconnect = 0; +static int can_doparity = 0; static int commands = 0; /* set by aha152x_setup according to the command line */ @@ -258,6 +272,7 @@ static int setup_portbase = 0; static int setup_irq = 0; static int setup_scsiid = 0; static int setup_reconnect = 0; +static int setup_doparity = 0; static char *setup_str = (char *)NULL; @@ -474,13 +489,11 @@ void aha152x_setup( char *str, int *ints) setup_called=ints[0]; setup_str=str; - if(ints[0] != 4) - return; - - setup_portbase = ints[1]; - setup_irq = ints[2]; - setup_scsiid = ints[3]; - setup_reconnect = ints[4]; + setup_portbase = ints[0] >= 1 ? ints[1] : 0x340; + setup_irq = ints[0] >= 2 ? ints[2] : 11; + setup_scsiid = ints[0] >= 3 ? ints[3] : 7; + setup_reconnect = ints[0] >= 4 ? ints[4] : 1; + setup_doparity = ints[0] >= 5 ? ints[5] : 1; } /* @@ -514,10 +527,10 @@ int aha152x_detect(Scsi_Host_Template * tpnt) { printk("aha152x: processing commandline: "); - if(setup_called!=4) + if(setup_called>5) { printk("\naha152x: %s\n", setup_str ); - printk("aha152x: usage: aha152x=,,,\n"); + printk("aha152x: usage: aha152x=[,[,[,[,]]]]\n"); panic("aha152x panics in line %d", __LINE__); } @@ -525,6 +538,7 @@ int aha152x_detect(Scsi_Host_Template * tpnt) interrupt_level = setup_irq; this_host = setup_scsiid; can_disconnect = setup_reconnect; + can_doparity = setup_doparity; for( i=0; i 1) ) + { + printk("parity %d should be 0 or 1\n", can_doparity); + panic("aha152x panics in line %d", __LINE__); + } printk("ok\n"); } else @@ -605,6 +625,7 @@ int aha152x_detect(Scsi_Host_Template * tpnt) interrupt_level = ints[conf.cf_irq]; this_host = conf.cf_id; can_disconnect = conf.cf_tardisc; + can_doparity = !conf.cf_parity; printk("auto configuration: ok, "); @@ -621,6 +642,10 @@ int aha152x_detect(Scsi_Host_Template * tpnt) #if defined(RECONNECT) can_disconnect=RECONNECT; #endif + +#if defined(PARITY) + can_doparity=PARITY; +#endif } printk("detection complete\n"); @@ -661,8 +686,12 @@ int aha152x_detect(Scsi_Host_Template * tpnt) aha152x_reset(NULL); - printk("aha152x: vital data: PORTBASE=0x%03x, IRQ=%d, SCSI ID=%d, reconnect=%s, parity=enabled\n", - port_base, interrupt_level, this_host, can_disconnect ? "enabled" : "disabled" ); + printk("aha152x: vital data: PORTBASE=0x%03x, IRQ=%d, SCSI ID=%d, reconnect=%s, parity=%s\n", + port_base, + interrupt_level, + this_host, + can_disconnect ? "enabled" : "disabled", + can_doparity ? "enabled" : "disabled"); snarf_region(port_base, TEST-SCSISEQ); /* Register */ @@ -809,11 +838,14 @@ int aha152x_abort( Scsi_Cmnd *SCpnt) return SCSI_ABORT_SUCCESS; } - if (current_SC) + if (!current_SC && TESTLO(SSTAT1, BUSFREE)) + printk("bus busy w/o current command, "); + + if (current_SC==SCpnt) if( TESTLO(SSTAT1, BUSFREE) ) { - /* fail abortion, if current command is on the bus */ - sti(); - return SCSI_ABORT_BUSY; + /* fail abortion, if current command is on the bus */ + sti(); + return SCSI_ABORT_BUSY; } else { @@ -831,10 +863,8 @@ int aha152x_abort( Scsi_Cmnd *SCpnt) prev=ptr, ptr=(Scsi_Cmnd *) ptr->host_scribble) ; - if(ptr && TESTLO(SSTAT1, BUSFREE) ) - printk("bus busy but no current command, "); - - if(ptr && TESTHI(SSTAT1, BUSFREE) ) + if(ptr) + if( TESTHI(SSTAT1, BUSFREE) ) { /* dequeue */ if(prev) @@ -863,10 +893,14 @@ int aha152x_abort( Scsi_Cmnd *SCpnt) sleep_on( &abortion_complete ); return abort_result; } - else - printk("aha152x: bus busy but no current command\n"); + else { + /* fail abortion, if we can't abort the disconnected command */ + sti(); + return SCSI_ABORT_BUSY; + } /* command wasn't found */ + printk("command not found\n"); sti(); return SCSI_ABORT_NOT_RUNNING; } @@ -1189,7 +1223,7 @@ void aha152x_intr( int irqno ) sti(); SETPORT( SIMODE0, 0 ); - SETPORT( SIMODE1, ENPHASEMIS ); + SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE ); #if defined(DEBUG_RACE) leave_driver("(reselected) intr"); #endif @@ -1221,7 +1255,7 @@ void aha152x_intr( int irqno ) SETPORT( SCSIID, (this_host << OID_) | current_SC->target ); /* Enable interrupts for SELECTION OUT DONE and SELECTION OUT INITIATED */ - SETPORT( SXFRCTL1, ENSPCHK|ENSTIMER); + SETPORT( SXFRCTL1, can_doparity ? (ENSPCHK|ENSTIMER) : ENSTIMER); /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */ SETPORT( SIMODE0, ENSELDO | (disconnected_SC ? ENSELDI : 0) ); @@ -1305,7 +1339,7 @@ void aha152x_intr( int irqno ) SETPORT( SCSISIG, P_MSGO ); SETPORT( SIMODE0, 0 ); - SETPORT( SIMODE1, ENREQINIT ); + SETPORT( SIMODE1, ENREQINIT|ENBUSFREE ); SETBITS( DMACNTRL0, INTEN); return; } @@ -1397,7 +1431,7 @@ void aha152x_intr( int irqno ) CLRBITS( SXFRCTL0, ENDMA); SETPORT( SIMODE0, 0 ); - SETPORT( SIMODE1, ENPHASEMIS|ENREQINIT ); + SETPORT( SIMODE1, ENPHASEMIS|ENREQINIT|ENBUSFREE ); /* wait for data latch to become ready or a phase change */ while( TESTLO( DMASTAT, INTSTAT ) ) @@ -1456,7 +1490,7 @@ void aha152x_intr( int irqno ) /* missing phase raises INTSTAT */ SETPORT( SIMODE0, 0 ); - SETPORT( SIMODE1, ENPHASEMIS ); + SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE ); #if defined(DEBUG_CMD) printk("waiting, "); @@ -1673,7 +1707,7 @@ void aha152x_intr( int irqno ) SETPORT( SXFRCTL0, CH1); SETPORT( SIMODE0, 0 ); - SETPORT( SIMODE1, ENREQINIT ); + SETPORT( SIMODE1, ENREQINIT|ENBUSFREE ); if( TESTHI( SSTAT1, PHASEMIS ) ) printk("aha152x: passing STATUS phase"); @@ -1870,7 +1904,7 @@ void aha152x_intr( int irqno ) SETPORT(SXFRCTL0, SCSIEN|DMAEN|CH1); SETPORT( SIMODE0, 0 ); - SETPORT( SIMODE1, ENPHASEMIS ); + SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE ); /* while current buffer is not empty or there are more buffers to transfer */ @@ -2027,7 +2061,7 @@ void aha152x_intr( int irqno ) SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 ); SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0); - SETPORT( SCSISEQ, disconnected_SC ? ENRESELI : 0 ); + SETPORT(SCSISEQ, disconnected_SC ? ENRESELI : 0 ); SETBITS( DMACNTRL0, INTEN ); @@ -2046,7 +2080,7 @@ void aha152x_intr( int irqno ) current_SC->SCp.phase |= 1<<16 ; SETPORT( SIMODE0, 0 ); - SETPORT( SIMODE1, ENPHASEMIS ); + SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE ); #if defined(DEBUG_INTR) disp_enintr(); #endif diff --git a/drivers/scsi/aha152x.h b/drivers/scsi/aha152x.h index eea476732ed4..4a045918bf56 100644 --- a/drivers/scsi/aha152x.h +++ b/drivers/scsi/aha152x.h @@ -2,7 +2,7 @@ #define _AHA152X_H /* - * $Id: aha152x.h,v 1.2 1994/07/03 13:01:47 root Exp $ + * $Id: aha152x.h,v 1.4 1994/09/12 11:32:41 root Exp $ */ #include "../block/blk.h" @@ -22,7 +22,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.2 $" +#define AHA152X_REVID "Adaptec 152x SCSI driver; $Revision: 1.4 $" /* Initial value of Scsi_Host entry */ #define AHA152X { /* next */ NULL, \ diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c index 42b2b6b84689..5eb721bb5cd9 100644 --- a/drivers/scsi/seagate.c +++ b/drivers/scsi/seagate.c @@ -260,11 +260,9 @@ static inline void borken_wait(void) { register int count; for (count = borken_calibration; count && (STATUS & STAT_REQ); --count); - if (count) #if (DEBUG & DEBUG_BORKEN) + if (count) printk("scsi%d : borken timeout\n", hostno); -#else - ; #endif } diff --git a/fs/block_dev.c b/fs/block_dev.c index 727e713a7110..387d65cc81f3 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -19,7 +19,7 @@ extern int *blksize_size[]; int block_write(struct inode * inode, struct file * filp, char * buf, int count) { - int blocksize, blocksize_bits, i, j; + int blocksize, blocksize_bits, i, j, buffercount,write_error; int block, blocks; loff_t offset; int chars; @@ -29,9 +29,10 @@ int block_write(struct inode * inode, struct file * filp, char * buf, int count) int blocks_per_cluster; unsigned int size; unsigned int dev; - struct buffer_head * bh; + struct buffer_head * bh, *bufferlist[NBUF]; register char * p; + write_error = buffercount = 0; dev = inode->i_rdev; if ( is_read_only( inode->i_rdev )) return -EPERM; @@ -118,13 +119,35 @@ int block_write(struct inode * inode, struct file * filp, char * buf, int count) buf += chars; bh->b_uptodate = 1; mark_buffer_dirty(bh, 0); - if (filp->f_flags & O_SYNC) { - ll_rw_block(WRITE, 1, &bh); - wait_on_buffer(bh); + if (filp->f_flags & O_SYNC) + bufferlist[buffercount++] = bh; + else + brelse(bh); + if (buffercount == NBUF){ + ll_rw_block(WRITE, buffercount, bufferlist); + for(i=0; ib_uptodate) + write_error=1; + brelse(bufferlist[i]); + } + buffercount=0; } - brelse(bh); + if(write_error) + break; } + if ( buffercount ){ + ll_rw_block(WRITE, buffercount, bufferlist); + for(i=0; ib_uptodate) + write_error=1; + brelse(bufferlist[i]); + } + } filp->f_reada = 1; + if(write_error) + return -EIO; return written; } diff --git a/fs/locks.c b/fs/locks.c index 7b7ba61decb4..7b1c318f461e 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -4,13 +4,15 @@ * Provide support for fcntl()'s F_GETLK, F_SETLK, and F_SETLKW calls. * Doug Evans, 92Aug07, dje@sspiff.uucp. * - * FIXME: two things aren't handled yet: - * - deadlock detection/avoidance (of dubious merit, but since it's in - * the definition, I guess it should be provided eventually) + * Deadlock Detection added by Kelly Carmichael, kelly@[142.24.8.65] + * September 17, 1994. + * + * FIXME: one thing isn't handled yet: * - mandatory locks (requires lots of changes elsewhere) * * Edited by Kai Petzke, wpp@marie.physik.tu-berlin.de */ +#define DEADLOCK_DETECTION #include @@ -30,6 +32,9 @@ static int lock_it(struct file *filp, struct file_lock *caller, unsigned int fd) static struct file_lock *alloc_lock(struct file_lock **pos, struct file_lock *fl, unsigned int fd); static void free_lock(struct file_lock **fl); +#ifdef DEADLOCK_DETECTION +int locks_deadlocked(int my_pid,int blocked_pid); +#endif static struct file_lock file_lock_table[NR_FILE_LOCKS]; static struct file_lock *file_lock_free_list; @@ -145,11 +150,13 @@ repeat: /* * File is locked by another process. If this is * F_SETLKW wait for the lock to be released. - * FIXME: We need to check for deadlocks here. */ if (cmd == F_SETLKW) { if (current->signal & ~current->blocked) return -ERESTARTSYS; +#ifdef DEADLOCK_DETECTION + if (locks_deadlocked(file_lock.fl_owner->pid,fl->fl_owner->pid)) return -EDEADLOCK; +#endif interruptible_sleep_on(&fl->fl_wait); if (current->signal & ~current->blocked) return -ERESTARTSYS; @@ -166,6 +173,36 @@ repeat: return lock_it(filp, &file_lock, fd); } +#ifdef DEADLOCK_DETECTION +/* + * This function tests for deadlock condition before putting a process to sleep + * this detection scheme is recursive... we may need some test as to make it + * exit if the function gets stuck due to bad lock data. + */ + +int locks_deadlocked(int my_pid,int blocked_pid) +{ + int ret_val; + struct wait_queue *dlock_wait; + struct file_lock *fl; + for (fl = &file_lock_table[0]; fl < file_lock_table + NR_FILE_LOCKS - 1; fl++) { + if (fl->fl_owner == NULL) continue; /* not a used lock */ + if (fl->fl_owner->pid != my_pid) continue; + if (fl->fl_wait == NULL) continue; /* no queues */ + dlock_wait = fl->fl_wait; + do { + if (dlock_wait->task != NULL) { + if (dlock_wait->task->pid == blocked_pid) return -EDEADLOCK; + ret_val = locks_deadlocked(dlock_wait->task->pid,blocked_pid); + if (ret_val) return -EDEADLOCK; + } + dlock_wait = dlock_wait->next; + } while (dlock_wait != fl->fl_wait); + } + return 0; +} +#endif + /* * This function is called when the file is closed. */ diff --git a/include/asm-i386/string.h b/include/asm-i386/string.h index e5832df57e4b..3c4c598c1814 100644 --- a/include/asm-i386/string.h +++ b/include/asm-i386/string.h @@ -482,7 +482,7 @@ __asm__("cld\n\t" \ #define memset(s, c, count) \ (__builtin_constant_p(c) ? \ - __constant_c_x_memset((s),(0x01010101*(unsigned char)c),(count)) : \ + __constant_c_x_memset((s),(0x01010101UL*(unsigned char)c),(count)) : \ __memset((s),(c),(count))) /* diff --git a/include/linux/fd.h b/include/linux/fd.h index 11d52cf55172..7248805e0c34 100644 --- a/include/linux/fd.h +++ b/include/linux/fd.h @@ -26,6 +26,8 @@ #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 @@ -51,7 +53,7 @@ #define FD_2M 0x4 #define FD_SIZECODEMASK 0x38 -#define FD_SIZECODE(floppy) (((( (floppy)->rate ) & FD_SIZECODEMASK) >> 3)+ 2) +#define FD_SIZECODE(floppy) (((((floppy)->rate&FD_SIZECODEMASK)>> 3)+ 2) %8) #define FD_SECTSIZE(floppy) ( (floppy)->rate & FD_2M ? \ 512 : 128 << FD_SIZECODE(floppy) ) #define FD_PERP 0x40 @@ -170,6 +172,27 @@ struct floppy_drive_struct { int fd_device; int last_checked; /* when was the drive last checked for a disk change? */ + +}; + +struct floppy_write_errors { + /* Write error logging. + * + * These fields can be cleared with the FDWERRORCLR ioctl. + * Only writes that were attempted but failed due to a physical media + * error are logged. write(2) calls that fail and return an error code + * to the user process are not counted. + */ + + unsigned int write_errors; /* number of physical write errors encountered */ + + /* position of first and last write errors */ + unsigned long first_error_sector; + int first_error_generation; + unsigned long last_error_sector; + int last_error_generation; + + unsigned int badness; /* highest retry count for a read or write operation */ }; struct floppy_fdc_state { diff --git a/mm/mmap.c b/mm/mmap.c index 174c67b9be81..7b5657a64f38 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -428,6 +428,13 @@ void merge_segments(struct vm_area_struct *mpnt) */ prev->vm_end = mpnt->vm_end; prev->vm_next = mpnt->vm_next; + if (mpnt->vm_ops && mpnt->vm_ops->close) { + mpnt->vm_offset += mpnt->vm_end - mpnt->vm_start; + mpnt->vm_start = mpnt->vm_end; + mpnt->vm_ops->close(mpnt); + } + if (mpnt->vm_inode) + mpnt->vm_inode->i_count--; kfree_s(mpnt, sizeof(*mpnt)); mpnt = prev; } diff --git a/mm/mprotect.c b/mm/mprotect.c index b539c41f0610..528854d0047c 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c @@ -107,17 +107,32 @@ static inline int mprotect_fixup_middle(struct vm_area_struct * vma, unsigned long start, unsigned long end, int newflags, int prot) { - int error; - unsigned long tmpflags, tmpprot; + struct vm_area_struct * left, * right; - tmpflags = vma->vm_flags; - tmpprot = vma->vm_page_prot; + left = (struct vm_area_struct *) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL); + if (!left) + return -ENOMEM; + right = (struct vm_area_struct *) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL); + if (!right) { + kfree(left); + return -ENOMEM; + } + *left = *vma; + *right = *vma; + left->vm_end = start; + vma->vm_start = start; + vma->vm_end = end; + right->vm_start = end; + vma->vm_offset += vma->vm_start - left->vm_start; + right->vm_offset += right->vm_start - left->vm_start; vma->vm_flags = newflags; vma->vm_page_prot = prot; - error = mprotect_fixup_end(vma, end, tmpflags, tmpprot); - if (!error) - error = mprotect_fixup_start(vma, start, tmpflags, tmpprot); - return error; + if (vma->vm_inode) + vma->vm_inode->i_count += 2; + insert_vm_struct(current, left); + insert_vm_struct(current, right); + merge_segments(current->mm->mmap); + return 0; } static int mprotect_fixup(struct vm_area_struct * vma, @@ -155,7 +170,7 @@ static int mprotect_fixup(struct vm_area_struct * vma, asmlinkage int sys_mprotect(unsigned long start, size_t len, unsigned long prot) { - unsigned long end; + unsigned long end, tmp; struct vm_area_struct * vma; if (start & ~PAGE_MASK) @@ -188,12 +203,15 @@ asmlinkage int sys_mprotect(unsigned long start, size_t len, unsigned long prot) if (vma->vm_end >= end) return mprotect_fixup(vma, start, end, newflags); - error = mprotect_fixup(vma, start, vma->vm_end, newflags); + tmp = vma->vm_end; + error = mprotect_fixup(vma, start, tmp, newflags); if (error) return error; - start = vma->vm_end; - vma = vma->vm_next; - if (!vma || vma->vm_start != start) - return -EFAULT; + start = tmp; + if (vma->vm_end <= start) { + vma = vma->vm_next; + if (!vma || vma->vm_start != start) + return -EFAULT; + } } } diff --git a/net/inet/rarp.c b/net/inet/rarp.c index 5badcbe825cb..94db10cf89e5 100644 --- a/net/inet/rarp.c +++ b/net/inet/rarp.c @@ -74,28 +74,6 @@ struct rarp_table struct rarp_table *rarp_tables = NULL; -/* - * This structure defines an ethernet arp header, which is the same header - * that is used for rarp. - */ - -struct arphdr -{ - unsigned short ar_hrd; /* format of hardware address */ - unsigned short ar_pro; /* format of protocol address */ - unsigned char ar_hln; /* length of hardware address */ - unsigned char ar_pln; /* length of protocol address */ - unsigned short ar_op; /* ARP opcode (command) */ -#if 0 - /* - * Ethernet looks like this : This bit is variable sized however... - */ - unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */ - unsigned char ar_sip[4]; /* sender IP address */ - unsigned char ar_tha[ETH_ALEN]; /* target hardware address */ - unsigned char ar_tip[4]; /* target IP address */ -#endif -}; static struct packet_type rarp_packet_type = { diff --git a/net/inet/tcp.c b/net/inet/tcp.c index f11d7361c65e..f018fc39ebbd 100644 --- a/net/inet/tcp.c +++ b/net/inet/tcp.c @@ -82,7 +82,7 @@ * Matt Dillon : More TCP improvements and RST bug fixes * Matt Dillon : Yet more small nasties remove from the TCP code * (Be very nice to this man if tcp finally works 100%) 8) - * Alan Cox : BSD accept sematics. + * Alan Cox : BSD accept semantics. * * * To Fix: -- 2.39.5