Path: news.funet.fi!fuug!mcsun!uunet!milo!grebyn!escom!al From: al@escom.com (Al Donaldson) Newsgroups: comp.os.minix Subject: floppy.c handles 1.2 and 1.44 meg disks Keywords: patch for IBM systems, revised approach Message-ID: <1991Oct22.064948.24645@escom.com> Date: 22 Oct 91 06:49:48 GMT Organization: ESCOM Corporation Lines: 144 In automatic mode (minor devices 0 or 1), the 1.5 kernel/floppy.c can't tell the difference between 5.25" 1.2 meg and 3.5" 1.44 meg floppies, unless you build the kernel with a DEFAULT_CLASS (include/minix/config.h) that allows only 3.5" disks or only 5.25" disks. This is my third attempt to fix this. My first approach was to test every individual I/O operation for type d=1 (5.25", 1.2 meg) to see if it could read sector 18 (i.e., 1.44 meg, d=6 disk) or, if not, sector 15 (i.e., 1.2 meg disk). This involved way too much disk activity. My second approach (which I mailed to beta-minix a few weeks ago) checked sector 18, then 15, until it found a match, then saved that type in a new field in the floppy struct and used it thereafter. This worked great for reads but, alas, Bruce Evans pointed out that it wouldn't work right if the first access was a write, e.g., "dd if=foo of=/dev/fd0". The following patch fixes this problem using a different method. It reads sector IDs using the existing read_id() function to determine the number of sectors per track. If there are 18 sectors, then it must be a 3.5" 1.44 meg disk; if 15 sectors, then it must be a 5.25" 1.2 meg floppy. Assume we find a type d=6 1.44 meg floppy (18 sectors). Although the user may change floppies from 1.44 meg to 720K to 1.44 meg, etc., it is safe to say that those are the only types worth checking, so I just detect the max number of sectors and then squeeze the drive_class[] bits down to either THREE_INCH or FIVE_INCH based on the number of sectors. The code was compiled with a DEFAULT_CLASS of 0 (config.h). Performance penalties, if any, appear to be negligible. I've run quite a lot of tests this time, but it is still possible that there are bugs. The floppy driver is fairly complicated (about 1000 lines), particularly the code that does auto type checking. I added about 25 lines of code and ran the following tests: On each system (Zenith 386 with 1.44 meg and IBM AT with 1.2 meg): - booted and did a read "dd if=/dev/fd0 of=foo"; - rebooted and did a write "dd if=foo of=/dev/fd0"; - switched disks from high to low density and back to high density; - mixed in various reads and writes of non-automatic types, e.g., /dev/PS0 on the Zenith and /dev/at0 on the AT. Some caveats and warnings: 1. This has not been tested this to see if it conflicts with formatting. You probably shouldn't try to format /dev/fd0. 2. I have no idea how this might work with non-IBM systems. 3. This should work with kernels compiled with DEFAULT_CLASS=3 or DEFAULT_CLASS=5, but I haven't tested it. 4. This should work with machines having one 1.2 meg drive and one 1.44 meg drive, or some other combination (because there are separate floppy structures for each physical drive). But I haven't tested that either. 5. I'm not a C expert. There are quite likely cleaner ways of doing this. You won't hurt my feelings if you clean it up. 6. Your mileage may vary. This might cause a file system crash or your computer might even burst into flames. Please practice safe computing and check the code before you run it. This will probably not do you much good if you have only one system with a single type of diskette drive. If so, just use the proper DEFAULT_CLASS or, better yet, specify the device as /dev/PS0 or /dev/at0, as appropriate. But if you have multiple systems with different types of diskettes or a mixed system with both 1.2 and 1.44 floppies, this should help. Please let me know what you find. Unshar the following and "patch < flop.cdiff". Patches are with respect to Prentice Hall 1.5 IBM distribution. Build the system with DEFAULT_CLASS = 0. If you want to see what the floppy driver is doing, compile the driver with -DDEBUG. Al ============ *** floppy.c Mon Oct 21 23:34:53 1991 --- floppy.NEW Tue Oct 22 00:20:33 1991 *************** *** 124,132 **** #define DIVISOR 128 /* used for sector size encoding */ #define MAX_FDC_RETRY 100 /* max # times to try to output to FDC */ #define NT 7 /* number of diskette/drive combinations */ ! #define AUTOMATIC 0x3F /* bit map allowing both 3.5 and 5.25 disks */ ! /* except for drive type 6, because that is */ ! /* hard to distinguish from drive type 1 */ #define THREE_INCH 0x48 /* bit map allowing only 3.5 inch diskettes */ #define FIVE_INCH 0x37 /* bit map allowing only 5.25 inch diskettes */ --- 124,130 ---- #define DIVISOR 128 /* used for sector size encoding */ #define MAX_FDC_RETRY 100 /* max # times to try to output to FDC */ #define NT 7 /* number of diskette/drive combinations */ ! #define AUTOMATIC 0x7F /* bit map allowing both 3.5 and 5.25 disks */ #define THREE_INCH 0x48 /* bit map allowing only 3.5 inch diskettes */ #define FIVE_INCH 0x37 /* bit map allowing only 5.25 inch diskettes */ *************** *** 290,295 **** --- 288,294 ---- unsigned dtype; phys_bytes param_phys; phys_bytes user_param_phys; + int i, maxsec; /* Decode the message parameters. */ drive = m_ptr->DEVICE & ~(DEV_TYPE_BITS | FORMAT_DEV_BIT); *************** *** 369,374 **** --- 368,398 ---- /* Check bit map to skip illegal densities. */ while ((drive_class[drive] & (1 << d)) == 0) d = (d + 1) % NT; fp->fl_density = d; + + /* Read sector IDs and set drive_class based on nr_sectors. + * Once we read a hi-density disk, restrict search to either + * THREE_INCH or FIVE_INCH for that drive. + */ + if (drive_class[drive] == AUTOMATIC) { + need_reset = TRUE; + fp->fl_calibration = UNCALIBRATED; + f_reset(); + if (pc_at) out_byte(FDC_RATE, rate[d]); + recalibrate(fp); + maxsec = 0; + + for ( i = 0 ; i < nr_sectors[d] ; i++ ) { + fp->fl_sector = i; + r = read_id(fp); + if (fp->fl_results[ST_SEC] > maxsec) + maxsec = fp->fl_results[ST_SEC]; + } + if (maxsec == 18) drive_class[drive] = THREE_INCH; + if (maxsec == 15) drive_class[drive] = FIVE_INCH; + } + #if DEBUG + printf("\nd=%x, errors=%x, drive=%x\n", d, errors, drive_class[drive]); + #endif sectors = nr_sectors[d]; fp->fl_cylinder = (int) (block / (NR_HEADS * sectors)); ============ end of patch ============