Subject: Some more fd.c patches
To: None <amiga-dev@sun-lamp.cs.berkeley.edu>
From: Michael L. Hitch <osymh@gemini.oscs.montana.edu>
List: amiga-dev
Date: 04/21/1994 16:20:24
Here are some more fd.c patches for anyone playing with the floppy driver.
These include the patches previously posted by Ty Sarna.
Also included are changes to autoconf.c and swapgeneric.c that should
allow booting using the floppy drive as the root file system. [The diffs
for autoconf.c doesn't have the correct line numbers, so you may have to
make these changes manually.]
The patches to fd.c provides the following:
- Working support for HD drives.
- The delay() routine uses the DELAY() function instead of a counted
loop, so delay timing should be CPU-independent. It works on my
25Mhz 68040 and 33Mhz 68040 systems. [The DELAY() routine seems to
be quite a bit off for large delays, so I have a "fudge-factor"
multiplier that may need to be tweaked a bit.]
- Writes seem to work reliably now. I finally tracked down the problem
I was having that resulted in bad tracks. The Fdopen() routine called
fd_probe every time, and fd_probe called get_drive_id(). Get_drive_id()
deselects the drive - at times during the middle of the DMA write! The
crude fix I've got just skips calling fd_probe() if a drive is currently
selected.
- The drive type values are now "inverted" so they match the definitions
in the AmigaDOS disk resource includes.
- The driver will retry the track read if an error is detected.
- When writing to the floppy, if the write begins on the first sector
of the track and will be writing the entire track, the old data isn't
read off the disk since it is just going to be overwritten anyway. This
allows a "poor man's format" to be done using dd:
dd if=/dev/zero of=/dev/rfd0 bs=22b count=80
[for DD disks; bs=44b for HD disks].
- The side-delay and settle-delay value appear to have been reversed, so
the entries in the drive_types table have been swapped.
- The ADKF_MFMPREC flag wasn't being set, which I think is supposed
to be set for MFM recorded disks. [hackdisk.device and trackdisk.device
also set this.]
- The disk label should report 300rpm for DD drives and 150RPM for HD drives.
Michael
diff -cr /mnt/src/sys/arch/amiga/amiga/autoconf.c /opt/sys/arch/amiga/amiga/autoconf.c
*** /mnt/src/sys/arch/amiga/amiga/autoconf.c Mon Apr 11 09:52:56 1994
--- /opt/sys/arch/amiga/amiga/autoconf.c Sun Apr 10 19:10:55 1994
***************
*** 971,977 ****
static char devname[][2] = {
0,0, /* 0 = ct */
0,0, /* 1 = xx */
! 'r','d', /* 2 = rd */
0,0, /* 3 = sw */
's','d', /* 4 = sd */
};
--- 1008,1014 ----
static char devname[][2] = {
0,0, /* 0 = ct */
0,0, /* 1 = xx */
! 'f','d', /* 2 = fd */
0,0, /* 3 = sw */
's','d', /* 4 = sd */
};
diff -cr /mnt/src/sys/arch/amiga/amiga/swapgeneric.c /opt/sys/arch/amiga/amiga/swapgeneric.c
*** /mnt/src/sys/arch/amiga/amiga/swapgeneric.c Mon Feb 28 10:55:35 1994
--- /opt/sys/arch/amiga/amiga/swapgeneric.c Sun Apr 10 19:07:36 1994
***************
*** 58,64 ****
};
int dmmin, dmmax, dmtext;
! /*extern struct driver rddriver;*/
extern struct driver sddriver;
extern struct amiga_ctlr amiga_cinit[];
extern struct amiga_device amiga_dinit[];
--- 58,64 ----
};
int dmmin, dmmax, dmtext;
! extern struct driver fddriver;
extern struct driver sddriver;
extern struct amiga_ctlr amiga_cinit[];
extern struct amiga_device amiga_dinit[];
***************
*** 68,74 ****
char *gc_name;
dev_t gc_root;
} genericconf[] = {
! /* { (caddr_t)&rddriver, "rd", makedev(2, 0), },*/
{ (caddr_t)&sddriver, "sd", makedev(4, 0), },
{ 0 },
};
--- 68,74 ----
char *gc_name;
dev_t gc_root;
} genericconf[] = {
! { (caddr_t)&fddriver, "fd", makedev(2, 0), },
{ (caddr_t)&sddriver, "sd", makedev(4, 0), },
{ 0 },
};
diff -cr /mnt/src/sys/arch/amiga/dev/fd.c /opt/sys/arch/amiga/dev/fd.c
*** /mnt/src/sys/arch/amiga/dev/fd.c Fri Apr 8 10:12:49 1994
--- /opt/sys/arch/amiga/dev/fd.c Wed Apr 20 22:45:56 1994
***************
*** 109,117 ****
#define DSKLEN_WRITE (1<<14)
/* drive type values */
! #define FD_NONE 0x00000000
! #define FD_DD_3 0xffffffff /* double-density 3.5" (880K) */
! #define FD_HD_3 0x55555555 /* high-density 3.5" (1760K) */
struct fd_type {
int id;
--- 109,118 ----
#define DSKLEN_WRITE (1<<14)
/* drive type values */
! #define FD_NONE 0xffffffff
! #define FD_DD_3 0x00000000 /* double-density 3.5" (880K) */
! #define FD_HD_3 0xaaaaaaaa /* high-density 3.5" (1760K) */
! #define FD_DD_5 0x55555555 /* double-density 5.25" (440K) */
struct fd_type {
int id;
***************
*** 120,125 ****
--- 121,127 ----
int heads;
int read_size;
int write_size;
+ int gap_size;
int sect_mult;
int precomp1;
int precomp2;
***************
*** 129,137 ****
};
struct fd_type drive_types[] = {
! /* id name tr he rdsz wrsz sm pc1 pc2 sd st st */
! { FD_DD_3, "DD 3.5", 80, 2, 14716, 13630, 1, 80, 161, 3, 18, 1 },
! { FD_HD_3, "HD 3.5", 80, 2, 29432, 27260, 2, 80, 161, 3, 18, 1 },
{ FD_NONE, "No Drive", 0, }
};
int num_dr_types = sizeof(drive_types) / sizeof(drive_types[0]);
--- 131,140 ----
};
struct fd_type drive_types[] = {
! /* id name tr he rdsz wrsz gap sm pc1 pc2 sd st st */
! { FD_DD_3, "DD 3.5\"", 80, 2, 14716, 13630, 414, 1, 80, 161, 3, 2, 18 },
! { FD_HD_3, "HD 3.5\"", 80, 2, 29432, 27260, 828, 2, 80, 161, 3, 2, 18 },
! { FD_DD_5, "DD 5.25\"",40, 2, 14716, 13630, 414, 1, 40, 80, 3, 2, 18 },
{ FD_NONE, "No Drive", 0, }
};
int num_dr_types = sizeof(drive_types) / sizeof(drive_types[0]);
***************
*** 313,321 ****
long cnt, inner;
int val;
! for (cnt = 0; cnt < delay_ms; cnt++)
! for (inner = 0; inner < 500; inner++)
! val += inner * cnt;
return(val);
}
--- 316,322 ----
long cnt, inner;
int val;
! DELAY (delay_ms * 1000 * 25); /* NOTE: DELAY seems to run too fast */
return(val);
}
***************
*** 336,345 ****
fdu_t fdu;
{
int i;
- int cnt; /* XXXX not used? */
- cnt = 0; /* XXXX not used? */
-
/* deselect all drives */
for (i = 0; i < DRVS_PER_CTLR; i++)
DESELECT(SELMASK(i));
--- 337,343 ----
***************
*** 459,464 ****
--- 457,464 ----
/* set known values */
fd->cyl = 0;
+
+ delay (fd->ft->settle_time);
}
/*
***************
*** 472,478 ****
{
int cyl, side;
int dir, cnt;
- int delay_time;
cyl = track >> 1;
side = (track % 2) ^ 1;
--- 472,477 ----
***************
*** 494,504 ****
if (cnt) {
while (cnt) {
- delay_time = fd->ft->step_delay;
- if (dir != fd->dir)
- delay_time += fd->ft->settle_time;
fd_step();
! delay(delay_time);
--cnt;
}
delay(fd->ft->settle_time);
--- 493,500 ----
if (cnt) {
while (cnt) {
fd_step();
! delay(fd->ft->step_delay);
--cnt;
}
delay(fd->ft->settle_time);
***************
*** 605,615 ****
track = fd->buf_track;
/* gap space */
! for (cnt = 0; cnt < 414; cnt++)
*raw++ = 0xaaaaaaaa;
/* sectors */
! for (cnt = 0; cnt < 11; cnt++) {
*raw = 0xaaaaaaaa;
correct(raw);
++raw;
--- 601,611 ----
track = fd->buf_track;
/* gap space */
! for (cnt = fd->ft->gap_size; cnt; cnt--)
*raw++ = 0xaaaaaaaa;
/* sectors */
! for (cnt = 0; cnt < fd->sects; cnt++) {
*raw = 0xaaaaaaaa;
correct(raw);
++raw;
***************
*** 616,622 ****
*raw++ = 0x44894489;
! format = 0xff000000 | (track << 16) | (cnt << 8) | (11 - cnt);
csum = encode_long(format,raw);
raw += 2;
--- 612,618 ----
*raw++ = 0x44894489;
! format = 0xff000000 | (track << 16) | (cnt << 8) | (fd->sects - cnt);
csum = encode_long(format,raw);
raw += 2;
***************
*** 628,635 ****
--- 624,635 ----
csum = 0;
encode_block(raw+2, data + cnt * 512, 512, &csum);
csum = encode_long(csum, raw);
+ correct (raw+2);
raw += 256 + 2;
}
+ *raw = 0xaaa80000;
+ correct(raw);
+
}
#define get_word(raw) (*(u_short *)(raw))
***************
*** 646,652 ****
/*
* scan_sync - looks for the next start of sector marked by a sync. When
! * sector = 10, can't be certain of a starting sync.
*/
u_long
scan_sync(raw, end, sect)
--- 646,652 ----
/*
* scan_sync - looks for the next start of sector marked by a sync. When
! * sect != 0, can't be certain of a starting sync.
*/
u_long
scan_sync(raw, end, sect)
***************
*** 655,661 ****
{
u_short data;
! if (sect != 10) {
while (raw < end) {
data = get_word(raw);
if (data == 0x4489)
--- 655,661 ----
{
u_short data;
! if (sect == 0) {
while (raw < end) {
data = get_word(raw);
if (data == 0x4489)
***************
*** 696,702 ****
end = raw + fd->ft->read_size;
for (scnt = fd->sects-1; scnt >= 0; scnt--) {
! if ((raw = scan_sync(raw, end, scnt)) == 0) {
/* XXXX */
printf("can't find sync for sector %d\n", scnt);
return(1);
--- 696,702 ----
end = raw + fd->ft->read_size;
for (scnt = fd->sects-1; scnt >= 0; scnt--) {
! if ((raw = scan_sync(raw, end, scnt == fd->sects-1)) == 0) {
/* XXXX */
printf("can't find sync for sector %d\n", scnt);
return(1);
***************
*** 774,780 ****
if (data_csum != csum) {
printf(
! "MFM_DATA: f=%d t=%d s=%d sn=%d sc=%d %ld, %ld\n",
format, tnum, sect, snext, scnt, data_csum, csum);
return(MFM_DATA);
}
--- 774,780 ----
if (data_csum != csum) {
printf(
! "MFM_DATA: f=%d t=%d s=%d sn=%d sc=%d %lx, %lx\n",
format, tnum, sect, snext, scnt, data_csum, csum);
return(MFM_DATA);
}
***************
*** 791,807 ****
int unit;
{
u_long id;
! int i;
id = 0;
/* loop and read disk ID */
! for (i = 0; i < 32; i++) {
SELECT(SELMASK(unit));
/* read and store value of DSKRDY */
! id <<= 1; /* XXXX 0 << 1? */
! id |= (ciaa.pra & CIAA_PRA_RDY) ? 0 : 1;
DESELECT(SELMASK(unit));
}
--- 791,807 ----
int unit;
{
u_long id;
! u_long id_bit;
id = 0;
/* loop and read disk ID */
! for (id_bit = 0x80000000; id_bit; id_bit >>= 1) {
SELECT(SELMASK(unit));
/* read and store value of DSKRDY */
! if (ciaa.pra & CIAA_PRA_RDY)
! id |= id_bit;
DESELECT(SELMASK(unit));
}
***************
*** 811,818 ****
get_drive_id(unit)
int unit;
{
! int i, t;
! u_long id;
u_char mask1, mask2;
volatile u_char *a_ptr;
volatile u_char *b_ptr;
--- 811,818 ----
get_drive_id(unit)
int unit;
{
! int t;
! u_long id, id_bit;
u_char mask1, mask2;
volatile u_char *a_ptr;
volatile u_char *b_ptr;
***************
*** 830,839 ****
*b_ptr &= mask1;
*b_ptr |= mask2;
! for (i = 0; i < 32; i++) {
*b_ptr &= mask1;
! t = (*a_ptr) & CIAA_PRA_RDY;
! id = (id << 1) | (t ? 0 : 1);
*b_ptr |= mask2;
}
--- 830,839 ----
*b_ptr &= mask1;
*b_ptr |= mask2;
! for (id_bit = 0x80000000; id_bit; id_bit >>= 1) {
*b_ptr &= mask1;
! if ((*a_ptr) & CIAA_PRA_RDY)
! id |= id_bit;
*b_ptr |= mask2;
}
***************
*** 877,882 ****
--- 877,887 ----
id = get_drive_id(fd->fdu);
type = get_drive_type(id);
+ /* get_drive_id shuts off the motor */
+ /* XXXX fdc_data[0] only as long as there is one controller */
+ if (fd->fdu == fdc_data[0].motor_fdu)
+ fdc_data[0].motor_fdu = -1;
+
if (type == -1) {
/* XXXX */
printf("fd_probe: unsupported drive type %08x found\n", id);
***************
*** 910,916 ****
fd->buf_track = track;
fdc->state = WAIT_READ;
- timeout((timeout_t)fd_timeout, (caddr_t)fdc, 2 * hz);
fd_seek(fd, track);
--- 915,920 ----
***************
*** 924,929 ****
--- 928,934 ----
custom.dsklen = 0;
delay(fd->ft->side_time);
+ timeout((timeout_t)fd_timeout, (caddr_t)fdc, 2 * hz);
custom.dskpt = (u_char *)kvtop(raw_buf);
custom.dsklen = len | DSKLEN_DMAEN;
***************
*** 946,952 ****
fdc->saved = fdc->state;
fdc->state = WAIT_WRITE;
- timeout((timeout_t)fd_timeout, (caddr_t)fdc, 2 * hz);
fd_seek(fd, track);
--- 951,956 ----
***************
*** 960,966 ****
ADKF_MSBSYNC;
/* set appropriate adkcon bits */
! adk = ADKF_SETCLR | ADKF_FAST;
if (track >= fd->ft->precomp2)
adk |= ADKF_PRECOMP1;
else if (track >= fd->ft->precomp1)
--- 964,970 ----
ADKF_MSBSYNC;
/* set appropriate adkcon bits */
! adk = ADKF_SETCLR | ADKF_FAST | ADKF_MFMPREC;
if (track >= fd->ft->precomp2)
adk |= ADKF_PRECOMP1;
else if (track >= fd->ft->precomp1)
***************
*** 969,974 ****
--- 973,979 ----
custom.dsklen = DSKLEN_WRITE;
delay(fd->ft->side_time);
+ timeout((timeout_t)fd_timeout, (caddr_t)fdc, 2 * hz);
custom.dskpt = (u_char *)kvtop(raw_buf); /* XXXX again raw */
custom.dsklen = len | DSKLEN_DMAEN | DSKLEN_WRITE;
***************
*** 1057,1063 ****
if (fdu >= DRVS_PER_CTLR)
return(ENXIO);
! fd_probe(fd);
if (fd->ft == NULL || fd->ft->tracks == 0)
return(ENXIO);
--- 1062,1080 ----
if (fdu >= DRVS_PER_CTLR)
return(ENXIO);
! /*
! * XXXX don't probe if device is currently selected
! * it may be in the middle of a DMA transfer and fd_probe
! * will deselect all drives
! */
! if (fdc->motor_fdu < 0)
! fd_probe(fd);
! #if 0
! else
! printf ("fd: Fdopen called with a drive selected\n");
! #endif
!
!
if (fd->ft == NULL || fd->ft->tracks == 0)
return(ENXIO);
***************
*** 1130,1141 ****
fd_label->d_magic = DISKMAGIC;
fd_label->d_type = DTYPE_FLOPPY;
strncpy(fd_label->d_typename, "fd", sizeof(fd_label->d_typename) - 1);
! strcpy(fd_label->d_packname, "some pack");
fd_label->d_secsize = 512;
! fd_label->d_nsectors = 11;
! fd_label->d_ntracks = 2;
! fd_label->d_ncylinders = 80;
fd_label->d_secpercyl = fd_label->d_nsectors * fd_label->d_ntracks;
fd_label->d_secperunit= fd_label->d_ncylinders * fd_label->d_secpercyl;
--- 1147,1159 ----
fd_label->d_magic = DISKMAGIC;
fd_label->d_type = DTYPE_FLOPPY;
strncpy(fd_label->d_typename, "fd", sizeof(fd_label->d_typename) - 1);
! strcpy(fd_label->d_packname, fd->ft->name);
+ fd_label->d_rpm = 300 / fd->ft->sect_mult;
fd_label->d_secsize = 512;
! fd_label->d_nsectors = fd->sects;
! fd_label->d_ntracks = fd->ft->heads;
! fd_label->d_ncylinders = fd->ft->tracks;
fd_label->d_secpercyl = fd_label->d_nsectors * fd_label->d_ntracks;
fd_label->d_secperunit= fd_label->d_ncylinders * fd_label->d_secpercyl;
***************
*** 1192,1203 ****
blknum = (unsigned long) bp->b_blkno * DEV_BSIZE / FDBLK;
nblocks = fd->sects * fd->ft->tracks * fd->ft->heads;
if (blknum + (bp->b_bcount / FDBLK) > nblocks) {
! /* XXXX */
! printf("at end of disk\n");
! bp->b_error = ENOSPC;
! bp->b_flags |= B_ERROR;
! biodone(bp);
! return;
}
bp->b_cylin = blknum; /* set here for disksort */
--- 1210,1228 ----
blknum = (unsigned long) bp->b_blkno * DEV_BSIZE / FDBLK;
nblocks = fd->sects * fd->ft->tracks * fd->ft->heads;
if (blknum + (bp->b_bcount / FDBLK) > nblocks) {
! nblocks -= blknum;
! if (nblocks == 0) {
! bp->b_resid = bp->b_bcount;
! goto done;
! }
! if (nblocks < 0) {
! bp->b_error = EINVAL;
! bp->b_flags |= B_ERROR;
! done:
! biodone(bp);
! return;
! }
! bp->b_bcount = dbtob(nblocks);
}
bp->b_cylin = blknum; /* set here for disksort */
***************
*** 1255,1265 ****
dp = &fd->head;
bp = dp->b_actf;
/* XXXX */
! printf("fd%d: Operation timeout\n", fd->fdu);
if (bp) {
retrier(fdc);
fdc->state = DONE_IO;
if (fdc->retry < 6)
fdc->retry = 6;
} else {
--- 1280,1297 ----
dp = &fd->head;
bp = dp->b_actf;
+ if (fd == NULL) {
+ printf ("fd_timeout called with no active drive?\n");
+ return;
+ }
+
/* XXXX */
! printf("fd%d: Operation timeout; state %d\n", fd->fdu, fdc->state);
if (bp) {
retrier(fdc);
+ #if 0 /* XXX retrier already set fdc->state? */
fdc->state = DONE_IO;
+ #endif
if (fdc->retry < 6)
fdc->retry = 6;
} else {
***************
*** 1368,1378 ****
if (fd->buf_track != track) {
TRACE1("do track %d\n", track);
! if (fd->buf_dirty)
track_write(fdc, fd);
! else
! track_read(fdc, fd, track);
! return(0);
}
fdc->state = DO_IO;
--- 1400,1424 ----
if (fd->buf_track != track) {
TRACE1("do track %d\n", track);
! if (fd->buf_dirty) {
track_write(fdc, fd);
! return (0);
! } else {
! if (read || sec != 0 ||
! ((bp->b_bcount - fd->skip)/FDBLK) % fd->sects) {
! track_read(fdc, fd, track);
! return(0);
! }
! /*
! * if writing a full track, don't bother reading
! * in the old track - we're just going to overwrite
! * it all anyway.
! */
! fd_seek (fd, track);
! fd->buf_track = track;
! /* clear sector labels */
! bzero(fd->buf_labels, MAX_SECTS * 16);
! }
}
fdc->state = DO_IO;
***************
*** 1397,1405 ****
fdc->state = DOSEEK;
else {
fd->skip = 0;
! bp->b_resid = 0;
! dp->b_actf = bp->b_actf;
! biodone(bp);
fdc->state = FINDWORK;
}
return(1);
--- 1443,1455 ----
fdc->state = DOSEEK;
else {
fd->skip = 0;
! if (bp == NULL)
! printf ("fd: fdstate DONE_IO bp == NULL\n");
! else {
! bp->b_resid = 0;
! dp->b_actf = bp->b_actf;
! biodone(bp);
! }
fdc->state = FINDWORK;
}
return(1);
***************
*** 1406,1419 ****
case WAIT_READ:
untimeout((timeout_t)fd_timeout, (caddr_t)fdc);
custom.dsklen = 0;
! amiga_read(fd);
! fdc->state = DO_IO;
! return(1);
case WAIT_WRITE:
untimeout((timeout_t)fd_timeout, (caddr_t)fdc);
custom.dsklen = 0;
fdc->state = fdc->saved;
fd->buf_dirty = 0;
return(1);
default:
/* XXXX */
--- 1456,1490 ----
case WAIT_READ:
untimeout((timeout_t)fd_timeout, (caddr_t)fdc);
custom.dsklen = 0;
! if (amiga_read(fd) == 0) {
! fdc->retry = 0;
! fdc->state = DO_IO;
! return(1);
! }
! if (fdc->retry++ < 6) {
! track_read(fdc, fd, track);
! return(0);
! }
! if (bp) {
! bp->b_flags |= B_ERROR;
! bp->b_error = EIO;
! bp->b_resid = bp->b_bcount - fd->skip;
! dp->b_actf = bp->b_actf;
! fd->skip = 0;
! biodone(bp);
! }
! fdc->state = FINDWORK;
! return (1);
case WAIT_WRITE:
untimeout((timeout_t)fd_timeout, (caddr_t)fdc);
custom.dsklen = 0;
fdc->state = fdc->saved;
fd->buf_dirty = 0;
+ /*
+ * post-write delay - should delay only if changing sides
+ * after a write?
+ */
+ delay (4);
return(1);
default:
/* XXXX */
***************
*** 1458,1469 ****
/* XXXX */
printf("fd%d: hard error\n", fd->fdu);
! bp->b_flags |= B_ERROR;
! bp->b_error = EIO;
! bp->b_resid = bp->b_bcount - fd->skip;
! dp->b_actf = bp->b_actf;
! fd->skip = 0;
! biodone(bp);
fdc->state = FINDWORK;
return(1);
#if 0
--- 1529,1544 ----
/* XXXX */
printf("fd%d: hard error\n", fd->fdu);
! if (bp == NULL)
! printf ("fd: retrier bp == NULL\n");
! else {
! bp->b_flags |= B_ERROR;
! bp->b_error = EIO;
! bp->b_resid = bp->b_bcount - fd->skip;
! dp->b_actf = bp->b_actf;
! fd->skip = 0;
! biodone(bp);
! }
fdc->state = FINDWORK;
return(1);
#if 0
--
Michael L. Hitch INTERNET: osymh@montana.edu
Computer Consultant BITNET: OSYMH@MTSUNIX1.BITNET
Office of Systems and Computing Services
Montana State University Bozeman, MT USA
------------------------------------------------------------------------------