Page 1 of 1

PEBKAC floppy driver

Posted: Tue Feb 13, 2007 11:08 am
by uglyoldbob
I must be retarded. So I am programming a simple floppy driver. Kernel boots using GRUB, PIC is mapped out, paging is used.
The command for read_sector works great on BOCHS, but fails on a real computer (specifically an 80386SX with 2MB RAM). After the command on the real pc, st0 is 0x40 (command could not be terminated properly) and st1 is 0x4 (no data).
My outportb has the value first, then the port number

Here is the flowchart for my driver.

RESET_
outportb(0, DOR)
wait 100 MS
outportb (0xC, DOR)
wait for interrupt
(command 0x08, checky interrupt status) X 4
...sendFloppyCommand(data_register, CHECK_INTERRUPT_STATUS);
......wait until MSR says it is ready to recieve
......outportb(command, DATA_REGISTER)
...wait until MSR says it is ready
...*st0 = inportb(data_register);
...wait until MSR says it is ready
...*cylinder = inportb(data_register);
outportb(0, CONFIG_CONTROL_REG)
configure_drive_command
...sends the three bytes of the command with sendFloppyCommand
calibrate_drive_command
...enable motor for disk drive
...send two bytes for calibrate drive command
...wait for interrupt
...check interrupt status
...if st0 != 0x20 (success) print error
...send command again if cylinder != 0

DMA is programmed
seek command is issued
...send three bytes of command
...wait for interrupt
...check interrupt status
...repeat if cylinder is not in the right place

wait the proper amount of time
wait 10,000 milliseconds (timer at IRQ 0 is at 1KHz)

send all bytes of read sector commands
wait for interrupt
//the guide says to check interrupt status, but complains about controller having data to send me
get all results bytes and print them to the screen


I must be missing something here. Bochs doesn't complain about DMA, although it still might be the problem. I used the excessively long delay becuase the floppy drive is very slow on the 80386 (several seconds delay for each interrupt it expects to get)
I have tried 0x44, 0x45, and 0x46 for the DMA codes but they all do the same. Not sure what to try now. I've tried everything listed in all the other floppy drive posts.

EDITED: Had to use '.' to align it so it would look right.

Posted: Tue Feb 13, 2007 12:43 pm
by Jim
Make sure you delay enough after a seek, I had the same probloms see http://www.osdev.org/phpBB2/viewtopic.php?t=12731

Posted: Tue Feb 13, 2007 1:19 pm
by uglyoldbob
keller wrote:Make sure you delay enough after a seek, I had the same probloms see http://www.osdev.org/phpBB2/viewtopic.php?t=12731
Is 10 seconds long enough?

Posted: Tue Feb 13, 2007 8:08 pm
by uglyoldbob
Figured out the problem. I didn't have enough of a delay, but the delay I needed was in a different place.
I had to place a longer delay after writing the reset controller command. YAY. Now I just have to figure out what is an acceptable delay time (I used an extremely long delay to make sure the delay would fix it).

Here is what works for my old 80386. The appropriate delay after the head seek is still there, but this (below) has to be there as well (and it's not really that much of a delay)

outportb(0, base + DIGITAL_OUTPUT_REG);
while (inportb(base + CHECK_DRIVE_STATUS) != 0);
//should delay long enough for the reset to finish course
outportb(0x0C, base + DIGITAL_OUTPUT_REG);

I tried doing a 100 msec delay between the two and it didn't work. 2000 milliseconds did work, but I think it is quite excessive. I didn't bother trying to "calibrate" the delay to work on my computer, because then it might not work on another computer. Apparently reading from the MSR worked. The floppy datasheet says that the reset clears all registers to 0, which is why I wait until the register reads 0, which is practically instantly (well it's fast).

Posted: Tue Feb 13, 2007 10:11 pm
by Happy Egghead
Hi,
According to The Indispensable Hardware Book the BIOS has a head settle time after seek of 512ms @250k per second, 426ms @300k per second and 256ms @500k per second. 1Mbit per second transfer rate isn't used.
This is passed with the fix drive data command 03 and if your floppy controller supports extdended commands you can get a dump with command 0x0f to see the current results.

Still writing my driver, but these *should* be accurate considering that with most floppy disk drives a full movement of the r/w arm takes about 300ms. Older disk drives will be slower since they spin slower.
Andrew Tanenbaum mentions in Opsys Design and Implementation that floppy drives whilst simple from the outside are very fussy creatures.
In contrast USB keys are 'simpler' in hardware, but make it all up for their simplicity in software complications!

Posted: Tue Feb 13, 2007 11:58 pm
by uglyoldbob
Has anybody noticed that the read_track function is broken in their bochs? I copied my code for read_sector, and changed it for read_track (the commands are the same except for the first byte).
Bochs x86 Emulator 2.3
Build from CVS snapshot on August 27, 2006

On bochs, my code says the controller wants to give me data when I try to write the command bytes.

On a real 386 PC, it works, but I'm not sure how much data it transfered. Any ideas?

Posted: Wed Feb 14, 2007 12:28 am
by Happy Egghead
Hi,
I believe the amount to transfer depends on size of floppy so
18 sectors * 512 bytes = 9kbytes of info for a 3 1/2" 1.44 mbyte floppy?

Don't try multi-track reading though. From everything I've read most floppy drives do wierd things when crossing from one track to the next.
I think this holds for multi-sector as well ie You can't start a 6 sector read from sector 17.
The read track always transfers a full track, and ignores the sector number and data length fields.

Posted: Wed Feb 14, 2007 8:53 am
by uglyoldbob
Why would read_track not work on BOCHS though and still work on a real computer?

Posted: Fri Feb 16, 2007 5:50 pm
by Happy Egghead
Hi,
In short - Bochs isn't a real computer!

In Long - Sometimes things work in Bochs and they don't work on real computers because Bochs makes optimisations.
Example - Bochs zeroes all it's memory - real computers don't.
Sometimes you can write things for a real computer and it won't run in Bochs.
A good example of this is the floppy system. A 'real' floppy system has reasonably strict timing and the hardware (controller / drive) is guaranteed to work a certain way - that's the ISA/PCI/standard. otherwise nothing would ever work. Even though the chips from an original AT don't exist in your 'real' computer, I'd make a bet that the design of the little curcuit buried in the chips is a direct copy (minus any never used features) from those 30 year old chips. They don't take up much space!
Example - the DMA chip and interrupt chip have lots of fancy features such and 'memory to memory move' and 'Auto EOI' and 'rotating interrupt priority'. These things are ignored by both real hardware and emulated hardware because they CANNOT under any circumstances be used by the hardware. Check out the DMA info in the wiki for a real good run down on 99% of the DMA chips features being unusable.
These things directly affect the way an OS can be written - they HAVE to be written a certain way. Bochs while being a great convenience to testing code unfortunatley suffers from the fact that it is software. A floppy controller can never be emulated as good as a real silicon chip. Some emulators can get really, really close (MAME for example) but it will never be the same as having a real box blinking it's lights in front of you.

My advice is to ignore the data sheets and find tutorials by people who have used the hardware. (This forum's a great place for example.)
The data sheets show what a piece of hardware could do in a perfect world. How it was actually used however.........blame IBM!!!! :?