diff -cr pl13/linux/Makefile pl13.new/linux/Makefile
*** pl13/linux/Makefile	Sun Oct 31 15:43:52 1993
--- pl13.new/linux/Makefile	Sun Oct 31 15:44:02 1993
***************
*** 35,40 ****
--- 35,53 ----
  ROOT_DEV = CURRENT
  
  #
+ # As we cannot detect the number of tracks within reasonable time,
+ # this define tells the autodetect-routine how much tracks it should
+ # assume for nonstandard formats. If the "normal" number of sectors
+ # is detected, still 80 (or 40) tracks are assumed.
+ #     FD_detect_83  assume 83 tracks (42 on DD-disks)
+ #     FD_detect_82  assume 82 tracks (41 on DD-disks)
+ #     (none)        assume 80 tracks (40 on DD-disks)
+ #
+ 
+ FD_DETECT=-DFD_detect_83
+ 
+ 
+ #
  # If you want to preset the SVGA mode, uncomment the next line and
  # set SVGA_MODE to whatever number you want.
  # Set it to -DSVGA_MODE=NORMAL_VGA if you just want the EGA/VGA mode.
***************
*** 50,56 ****
  # standard CFLAGS
  #
  
! CFLAGS = -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer # -x c++
  
  ifdef CONFIG_M486
  CFLAGS := $(CFLAGS) -m486
--- 63,69 ----
  # standard CFLAGS
  #
  
! CFLAGS = -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer $(FD_DETECT) # -x c++
  
  ifdef CONFIG_M486
  CFLAGS := $(CFLAGS) -m486
diff -cr pl13/linux/boot/head.S pl13.new/linux/boot/head.S
*** pl13/linux/boot/head.S	Sun Aug  1 17:07:07 1993
--- pl13.new/linux/boot/head.S	Sat Oct 23 12:59:25 1993
***************
*** 268,277 ****
   * floppy_track_buffer is used to buffer one track of floppy data: it
   * has to be separate from the tmp_floppy area, as otherwise a single-
   * sector read/write can mess it up. It can contain one full track of
!  * data (18*2*512 bytes).
   */
  _floppy_track_buffer:
! 	.fill 512*2*18,1,0
  
  /* This is the default interrupt "handler" :-) */
  int_msg:
--- 268,277 ----
   * floppy_track_buffer is used to buffer one track of floppy data: it
   * has to be separate from the tmp_floppy area, as otherwise a single-
   * sector read/write can mess it up. It can contain one full track of
!  * data (21*2*512 bytes).
   */
  _floppy_track_buffer:
! 	.fill 512*2*21,1,0
  
  /* This is the default interrupt "handler" :-) */
  int_msg:
diff -cr pl13/linux/include/linux/fd.h pl13.new/linux/include/linux/fd.h
*** pl13/linux/include/linux/fd.h	Sat Feb 13 13:44:54 1993
--- pl13.new/linux/include/linux/fd.h	Sun Oct 31 21:34:45 1993
***************
*** 14,19 ****
--- 14,23 ----
  #define FDFLUSH  11 /* flush buffers for media; either for verifying media, or for
                         handling a media change without closing the file
  		       descriptor */
+ #define FDSETMAXERRS 12 /* set abortion and read_track treshold */
+ #define FDGETMAXERRS 14 /* get abortion and read_track treshold */
+ #define FDGETEMSGTRESH	15	/* get fdc error reporting treshold */
+ #define FDGETDRVTYP 16          /* get drive type: 5 1/4 or 3 1/2 */
  
  #define FD_FILL_BYTE 0xF6 /* format fill byte */
  
***************
*** 31,36 ****
--- 35,41 ----
  			stretch;	/* !=0 means double track steps */
  	unsigned char	gap,		/* gap1 size */
  			rate,		/* data rate. |= 0x40 for perpendicular */
+ 	                                /*            |= 0x20 for sector interleaving */
  			spec1,		/* stepping rate, head unload time */
  			fmt_gap;	/* gap2 size */
  	char 	      * name; /* used only for predefined formats */
***************
*** 38,43 ****
--- 43,54 ----
  
  struct format_descr {
  	unsigned int device,head,track;
+ };
+ 
+ struct floppy_max_errors {
+   unsigned int abort,  	   /* number of errors to be reached before aborting */
+                read_track; /* maximal number of errors permitted to read an
+ 			    * entire track at once */
  };
  
  #endif
diff -cr pl13/linux/kernel/blk_drv/floppy.c pl13.new/linux/kernel/blk_drv/floppy.c
*** pl13/linux/kernel/blk_drv/floppy.c	Sun Aug 15 13:24:36 1993
--- pl13.new/linux/kernel/blk_drv/floppy.c	Sun Oct 31 21:39:17 1993
***************
*** 104,122 ****
   * max X times - some types of errors increase the errorcount by 2 or
   * even 3, so we might actually retry only X/2 times before giving up.
   */
! #define MAX_ERRORS 12
  
  /*
   * Maximum disk size (in kilobytes). This default is used whenever the
   * current disk size is unknown.
   */
! #define MAX_DISK_SIZE 1440
  
  /*
   * Maximum number of sectors in a track buffer. Track buffering is disabled
   * if tracks are bigger.
   */
! #define MAX_BUFFER_SECTORS 18
  
  /*
   * The DMA channel used by the floppy controller cannot access data at
--- 104,122 ----
   * max X times - some types of errors increase the errorcount by 2 or
   * even 3, so we might actually retry only X/2 times before giving up.
   */
! static struct floppy_max_errors max_errors[]={ {12, 4},{12, 4},{12 ,4},{12, 4}};
  
  /*
   * Maximum disk size (in kilobytes). This default is used whenever the
   * current disk size is unknown.
   */
! #define MAX_DISK_SIZE 1743
  
  /*
   * Maximum number of sectors in a track buffer. Track buffering is disabled
   * if tracks are bigger.
   */
! #define MAX_BUFFER_SECTORS 21
  
  /*
   * The DMA channel used by the floppy controller cannot access data at
***************
*** 146,182 ****
   * be self-explanatory.
   */
  static struct floppy_struct floppy_type[] = {
! 	{    0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL },	/* no testing */
! 	{  720, 9,2,40,0,0x2A,0x02,0xDF,0x50,NULL },	/* 360kB PC diskettes */
! 	{ 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,NULL },	/* 1.2 MB AT-diskettes */
! 	{  720, 9,2,40,1,0x2A,0x02,0xDF,0x50,NULL },	/* 360kB in 720kB drive */
! 	{ 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,NULL },	/* 3.5" 720kB diskette */
! 	{  720, 9,2,40,1,0x23,0x01,0xDF,0x50,NULL },	/* 360kB in 1.2MB drive */
! 	{ 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,NULL },	/* 720kB in 1.2MB drive */
! 	{ 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,NULL },	/* 1.44MB diskette */
  };
  
  /*
!  * Auto-detection. Each drive type has a pair of formats which are
   * used in succession to try to read the disk. If the FDC cannot lock onto
   * the disk, the next format is tried. This uses the variable 'probing'.
   */
! static struct floppy_struct floppy_types[] = {
! 	{  720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"360k/PC" }, /* 360kB PC diskettes */
! 	{  720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"360k/PC" }, /* 360kB PC diskettes */
! 	{ 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,"1.2M" },	  /* 1.2 MB AT-diskettes */
! 	{  720, 9,2,40,1,0x23,0x01,0xDF,0x50,"360k/AT" }, /* 360kB in 1.2MB drive */
! 	{ 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"720k" },	  /* 3.5" 720kB diskette */
! 	{ 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"720k" },	  /* 3.5" 720kB diskette */
! 	{ 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"1.44M" },	  /* 1.44MB diskette */
! 	{ 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"720k/AT" }, /* 3.5" 720kB diskette */
! };
  
  /* Auto-detection: Disk type used until the next media change occurs. */
  struct floppy_struct *current_type[4] = { NULL, NULL, NULL, NULL };
  
  /* This type is tried first. */
! struct floppy_struct *base_type[4];
  
  /*
   * User-provided type information. current_type points to
--- 146,204 ----
   * be self-explanatory.
   */
  static struct floppy_struct floppy_type[] = {
! 	{    0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL },	/*  0 no testing */
! 	{  720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"360k PC" },	/*  1 360kB PC diskettes */
! 	{ 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,"1.2M" },	/*  2 1.2 MB AT-diskettes */
! 	{  720, 9,2,40,1,0x2A,0x02,0xDF,0x50,"D360" },	/*  3 360kB in 720kB drive */
! 	{ 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"720k"},	/*  4 3.5" 720kB diskette */
! 	{  720, 9,2,40,1,0x23,0x01,0xDF,0x50,"h360" },	/*  5 360kB in 1.2MB drive */
! 	{ 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,"h720" },	/*  6 720kB in 1.2MB drive */
! 	{ 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"1.44M" },	/*  7 1.44MB diskette */
! 	{  800,10,2,40,1,0x25,0x02,0xDF,0x2E,"h400" },	/*  8 400k 5.25" */
! 	{ 1600,10,2,80,0,0x25,0x01,0xDF,0x2E,"H800" },	/*  9 800k 3.5" */
! 	{ 2880,18,2,80,0,0x25,0x00,0xDF,0x02,"h1440" }, /* 10 1.44MB 5.25" */
! 	{ 3360,21,2,80,0,0x25,0x00,0xDF,0x0C,"H1680" }, /* 11 1.68MB 3.5" */
! 	{  820,10,2,41,1,0x25,0x02,0xDF,0x2E,"h410" },	/* 12 410k 5.25" */
! 	{ 1640,10,2,82,0,0x25,0x01,0xDF,0x2E,"H820" },	/* 13 820k 3.5" */
! 	{ 2952,18,2,82,0,0x25,0x00,0xDF,0x02,"h1476" },	/* 14 1.48MB 5.25" */
! 	{ 3444,21,2,82,0,0x25,0x00,0xDF,0x0C,"H1722" },	/* 15 1.72MB 3.5" */
! 	{  840,10,2,42,1,0x25,0x02,0xDF,0x2E,"h420" },	/* 16 420k 5.25" */
! 	{ 1660,10,2,83,0,0x25,0x01,0xDF,0x2E,"H830" },	/* 17 830k 3.5" */
! 	{ 2988,18,2,83,0,0x25,0x00,0xDF,0x02,"h1494" },	/* 18 1.49MB 5.25" */
! 	{ 3486,21,2,83,0,0x25,0x00,0xDF,0x0C,"H1743" },	/* 19 1.74MB 3.5" */
  };
  
  /*
!  * Auto-detection. Each drive type has four formats which are
   * used in succession to try to read the disk. If the FDC cannot lock onto
   * the disk, the next format is tried. This uses the variable 'probing'.
   */
! static int floppy_types[] = {
! #ifdef FD_detect_82
! 	 1,  1,  1,  1,  /* 5.25" DD drive */
! 	14,  2, 12,  5,  /* 5.25" HD drive */
! 	13,  4, 13,  4,  /* 3.5" DD drive */
! 	15,  7, 13,  4   /* 3.5" HD drive */
! #else
! #ifdef FD_detect_83
! 	 1,  1,  1,  1,
! 	18,  2, 16,  5,
! 	17,  4, 17,  4,
! 	19,  7, 17,  4
! #else   /* 80 tracks */
! 	 1,  1,  1,  1,
! 	10,  2,  8,  5,
! 	 9,  4,  9,  4,
! 	11,  7,  9,  4
! #endif
! #endif
! 	};
  
  /* Auto-detection: Disk type used until the next media change occurs. */
  struct floppy_struct *current_type[4] = { NULL, NULL, NULL, NULL };
  
  /* This type is tried first. */
! int *base_type[4];
  
  /*
   * User-provided type information. current_type points to
***************
*** 192,198 ****
  	 720, 720, 720, 720,
  	 360, 360, 360, 360,
  	 720, 720, 720, 720,
! 	1440,1440,1440,1440
  };
  
  /*
--- 214,232 ----
  	 720, 720, 720, 720,
  	 360, 360, 360, 360,
  	 720, 720, 720, 720,
! 	1440,1440,1440,1440,
! 	 400, 400, 400, 400,
! 	 800, 800, 800, 800,
! 	1440,1440,1440,1440,
! 	1680,1680,1680,1680,
! 	 410, 410, 410, 410,
! 	 820, 820, 820, 820,
! 	1476,1476,1476,1476,
! 	1722,1722,1722,1722,
! 	 420, 420, 420, 420,
! 	 830, 830, 830, 830,
! 	1494,1494,1494,1494,
! 	1743,1743,1743,1743
  };
  
  /*
***************
*** 398,403 ****
--- 432,439 ----
  		return 0;
  	}
  	if (fake_change & mask) {
+ /* don't forget to invalidate the buffered track ... */
+ 		buffer_track = -1;
  		fake_change &= ~mask;
  /* omitting the next line breaks formatting in a horrible way ... */
  		changed_floppies &= ~mask;
***************
*** 404,409 ****
--- 440,446 ----
  		return 1;
  	}
  	if (changed_floppies & mask) {
+ 		buffer_track = -1;
  		changed_floppies &= ~mask;
  		recalibrate = 1;
  		return 1;
***************
*** 453,459 ****
  	if (read_track) {
  /* mark buffer-track bad, in case all this fails.. */
  		buffer_drive = buffer_track = -1;
! 		count = floppy->sect*2*512;
  		addr = (long) floppy_track_buffer;
  	} else if (addr >= LAST_DMA_ADDR) {
  		addr = (long) tmp_floppy_area;
--- 490,496 ----
  	if (read_track) {
  /* mark buffer-track bad, in case all this fails.. */
  		buffer_drive = buffer_track = -1;
! 		count = floppy->sect*floppy->head*512;
  		addr = (long) floppy_track_buffer;
  	} else if (addr >= LAST_DMA_ADDR) {
  		addr = (long) tmp_floppy_area;
***************
*** 517,522 ****
--- 554,560 ----
  static void bad_flp_intr(void)
  {
  	int errors;
+ 	int maximum;
  
  	current_track = NO_TRACK;
  	if (format_status == FORMAT_BUSY)
***************
*** 527,536 ****
  		return;
  	} else
  		errors = ++CURRENT->errors;
! 	if (errors > MAX_ERRORS) {
  		request_done(0);
  	}
! 	if (errors > MAX_ERRORS/2)
  		reset = 1;
  	else
  		recalibrate = 1;
--- 565,580 ----
  		return;
  	} else
  		errors = ++CURRENT->errors;
! 
! 	if ( !CURRENT )
! 		maximum = 12; /* formatting */
! 	else
! 		maximum = max_errors[ CURRENT_DEVICE & 0x3 ].abort;
! 
! 	if (errors > maximum) {
  		request_done(0);
  	}
! 	if (errors > maximum/2)
  		reset = 1;
  	else
  		recalibrate = 1;
***************
*** 766,773 ****
   */
  static void transfer(void)
  {
! 	read_track = (command == FD_READ) && (CURRENT_ERRORS < 4) &&
! 	    (floppy->sect <= MAX_BUFFER_SECTORS);
  
  	configure_fdc_mode();
  
--- 810,818 ----
   */
  static void transfer(void)
  {
! 	read_track = (command == FD_READ) &&
! 	  (CURRENT_ERRORS < max_errors[CURRENT_DEVICE & 0x3].read_track ) &&
! 	  (floppy->sect <= MAX_BUFFER_SECTORS);
  
  	configure_fdc_mode();
  
***************
*** 969,991 ****
  
  static void setup_format_params(void)
  {
!     unsigned char *here = (unsigned char *) tmp_floppy_area;
!     int count,head_shift,track_shift,total_shift;
  
      /* allow for about 30ms for data transport per track */
      head_shift  = floppy->sect / 6;
      /* a ``cylinder'' is two tracks plus a little stepping time */
      track_shift = 2 * head_shift + 1; 
!     /* count backwards */
!     total_shift = floppy->sect - 
! 	((track_shift * track + head_shift * head) % floppy->sect);
! 
!     /* XXX: should do a check to see this fits in tmp_floppy_area!! */
!     for (count = 0; count < floppy->sect; count++) {
! 	*here++ = track;
! 	*here++ = head;
! 	*here++ = 1 + (( count + total_shift ) % floppy->sect);
! 	*here++ = 2; /* 512 bytes */
      }
  }
  
--- 1014,1054 ----
  
  static void setup_format_params(void)
  {
!     struct fparm {
!         unsigned char track,head,sect,size;
!         } *here = (void *)tmp_floppy_area;
!     int il,n,count,head_shift,track_shift;
  
      /* allow for about 30ms for data transport per track */
      head_shift  = floppy->sect / 6;
      /* a ``cylinder'' is two tracks plus a little stepping time */
      track_shift = 2 * head_shift + 1; 
!     /* position of logical sector 1 on this track */
!     n = (track_shift * track + head_shift * head) % floppy->sect;
!     /* determine interleave */
!     il = 1;
!     if (base_type[format_req.device & 3] && 
! 	floppy->sect - floppy_type[base_type[format_req.device & 3][1]].sect >2)
!       il = 2;
! 
!     /* initialize field */ 
!     for (count = 0; count < floppy->sect; ++count) {
!        here[count].track = track;
!        here[count].head = head;
!        here[count].sect = 0;
!        here[count].size = 2;
!        }
!     /* place logical sectors */
!     for (count = 1; count <= floppy->sect; ++count) {
!         here[n].sect = count;
!         n = (n+il) % floppy->sect;
!         if (here[n].sect) { /* sector busy, find next free sector */
!            ++n;
!            if (n>=floppy->sect) {
!              n-=floppy->sect;
!              while (here[n].sect) ++n;
!              }
!         }
      }
  }
  
***************
*** 1025,1037 ****
  		floppy = current_type[device & 3];
  		if (!floppy) {
  			probing = 1;
! 			floppy = base_type[device & 3];
! 			if (!floppy) {
  				request_done(0);
  				goto repeat;
  			}
! 			if (CURRENT_ERRORS & 1)
! 				floppy++;
  		}
  	}
  	if (format_status != FORMAT_BUSY) {
--- 1088,1099 ----
  		floppy = current_type[device & 3];
  		if (!floppy) {
  			probing = 1;
! 			if (base_type[ device & 3] == NULL){
! 				floppy = NULL;
  				request_done(0);
  				goto repeat;
  			}
! 			floppy = &floppy_type[base_type[device & 3][CURRENT_ERRORS & 3]];
  		}
  	}
  	if (format_status != FORMAT_BUSY) {
***************
*** 1114,1119 ****
--- 1176,1224 ----
  	}
  	drive = MINOR(inode->i_rdev);
  	switch (cmd) {
+ 		case FDGETEMSGTRESH:
+ 			i = verify_area(VERIFY_WRITE,(void *) param,
+ 					sizeof(struct floppy_struct));
+ 			if (i)
+ 				return i;
+ 			for ( cnt = 0; cnt < sizeof(short) ; cnt++)
+ 				put_fs_byte(((char *) 
+ 				      (min_report_error_cnt+DRIVE(drive)))[cnt],
+ 				      (char *) param+cnt);
+ 			return 0;
+ 		case FDGETDRVTYP:
+ 			i=verify_area(VERIFY_WRITE,(void *) param,16);
+ 			if (i)
+ 				return i;
+ 			if ( drive < 4 ){
+ 			  if ( !base_type[drive & 3] )
+ 			    return -ENXIO;
+ 			  drive = base_type[ drive & 3][1];
+ 			}
+ 			else
+ 			  drive >>=2;
+ 	 		memcpy_tofs( (char *)param, floppy_type[drive].name,16);
+ 			return 0;			
+ 		case FDSETMAXERRS:
+ 			if ( !suser() )
+ 				return -EPERM;
+ 			for (cnt = 0; 
+ 			     cnt < sizeof(struct floppy_max_errors); 
+ 			     cnt++)
+ 				((char *)( &(max_errors[drive & 0x3])))[cnt]=
+ 				  get_fs_byte((char *) param+cnt);
+ 			return 0;
+ 		case FDGETMAXERRS:
+ 			i=verify_area(VERIFY_WRITE,(void *) param,sizeof(long));
+ 			if (i)
+ 				return i;
+ 			for (cnt = 0; 
+ 			     cnt < sizeof(struct floppy_max_errors); 
+ 			     cnt++)
+ 				put_fs_byte(((char *)
+ 					    (& (max_errors[drive & 0x3])))[cnt],
+ 					    (char *) param+cnt);
+ 			return 0;
  		case FDFMTBEG:
  			if (!suser())
  				return -EPERM;
***************
*** 1166,1171 ****
--- 1271,1282 ----
  			sti();
  			okay = format_status == FORMAT_OKAY;
  			format_status = FORMAT_NONE;
+ 
+ /*
+  * omitting the following line keeps the drive spinning 'forever' after the end
+  * of the formatting.
+  */
+ 			floppy_off( drive & 3);
  			wake_up(&format_done);
  			return okay ? 0 : -EIO;
  		case FDFLUSH:
***************
*** 1189,1199 ****
--- 1300,1334 ----
  			break;
  		case FDSETPRM:
  		case FDDEFPRM:
+ 
+ 			/*
+ 			 * invalidate buffer cache and track buffer before
+ 			 * changing the geometry.
+ 			 */
+ 			buffer_track = -1;
+ 			cli();
+ 			fake_change |= 1 << (drive & 3);
+ 			sti();
+ 			check_disk_change(inode->i_rdev);
+ 			buffer_track = -1;
+ 
  			memcpy_fromfs(user_params+drive,
  				(void *) param,
  				sizeof(struct floppy_struct));
  			current_type[drive] = &user_params[drive];
  			floppy_sizes[drive] = user_params[drive].size >> 1;
+ 
+ 			/* 
+ 			 * if the user specifies zero sectors per track, 
+ 			 * this could cause divide errors in kernel space.
+ 			 * Force the number of sectors to be at least 1.
+ 			 */
+ 			if ( user_params[drive].sect <= 0 )
+ 				user_params[drive].sect = 1;
+ 			/* same goes for heads */
+ 			if ( user_params[drive].head <= 0 )
+ 				user_params[drive].head = 1;
+ 
  			if (cmd == FDDEFPRM)
  				keep_data[drive] = -1;
  			else {
***************
*** 1233,1245 ****
  inb_p(0x71); \
  })
  
! static struct floppy_struct *find_base(int drive,int code)
  {
! 	struct floppy_struct *base;
  
  	if (code > 0 && code < 5) {
! 		base = &floppy_types[(code-1)*2];
! 		printk("fd%d is %s",drive,base->name);
  		return base;
  	}
  	printk("fd%d is unknown type %d",drive,code);
--- 1368,1380 ----
  inb_p(0x71); \
  })
  
! static int *find_base(int drive,int code)
  {
! 	int *base;
  
  	if (code > 0 && code < 5) {
! 		base = &floppy_types[(code-1)*4];
! 		printk("fd%d is %s",drive,floppy_type[base[1]].name);
  		return base;
  	}
  	printk("fd%d is unknown type %d",drive,code);
***************
*** 1271,1276 ****
--- 1406,1416 ----
  	int old_dev;
  
  	drive = inode->i_rdev & 3;
+ 
+ 	if (MINOR(inode->i_rdev) >> 2  >=
+ 	    sizeof(floppy_type) / sizeof(floppy_type[0]))
+ 	  return -ENXIO;
+ 
  	old_dev = fd_device[drive];
  	if (fd_ref[drive])
  		if (old_dev != inode->i_rdev)
