Page 1 of 1

HDD - PIO Driver [SOLVED]

Posted: Tue Jun 03, 2008 5:17 pm
by 01000101
hey,
I just started fiddling around with harddisk driver writing (using PIO), and I've been going through the specs in The Indespincable PC Hardware Book r3 and it looks all pretty clear-cut and easy to implement, but I'm running into an issue with my read command.

Everything is ZEROs! :twisted:

im sure it's a stupid mistake, but its annoying the crap out of me.

Code: Select all

void Read_Sector(char Type)
{
    outportb(0x1F6, Type);  // Drive/Head
    outportb(0x1F5, 0x00);  // Cylinder MSB
    outportb(0x1F4, 0x00);  // Cylinder LSB
    outportb(0x1F3, 0x00);  // Sector Number
    outportb(0x1F2, 0x01);  // Sector Count
    outportb(0x1F1, 0x20);  // Command

    while(inportb(0x1F7) & 0x80){} // wait for BSY bit to go low
    if(inportb(0x1F7) & 0x01){printf("HDD - ERR ERROR 4. \n",0);}

    int i = 0;
    for(i = 0; i < 256; i++)
    {
        if(inportw(0x1F0) != 0xD0C4)  // I wrote 0xD0C4 256 times and now im trying to read it. 
        {
            printf("ERROR %x \nStatus %x \nSectors Left %u \n", inportb(0x1F1), inportb(0x1F7), inportb(0x1F2)); 
            break;
        }
        else{printf("YAY \n",0);}
    }
    printf("HDD - Read Completed \n",0);
}
this returns 0's.

I havent got to putting in dynamic addressing, but I'm not too concerned with it yet, at least until i can read sectors properly.

BTW, this is just part of an experimental kernel I have going, so no DiNS work with this one. =)

not looking for someone to fix it for me, but to push me in the right direction if this is completely wrong lol.

Posted: Tue Jun 03, 2008 5:47 pm
by Pyrofan1
I thought hard drives fire irq 14 when they have data to be read. So have you tried adding an irq 14 handler?

Posted: Tue Jun 03, 2008 6:11 pm
by 01000101
yesss indeed. i just read that. It says that once the IRQ14 has been fired, the interrupt handler transfers sector data into main memory. Is that done through the 0x1F0 port?

Posted: Tue Jun 03, 2008 7:34 pm
by Dex
Maybe you should take a look at your command reg

Code: Select all

;  Technical Information on the ports:
;      Port    Read/Write   Misc
;     ------  ------------ -------------------------------------------------
;       1f0       r/w       data register, the bytes are written/read here
;       1f1       r         error register  (look these values up yourself)
;       1f2       r/w       sector count, how many sectors to read/write
;       1f3       r/w       sector number, the actual sector wanted
;       1f4       r/w       cylinder low, cylinders is 0-1024
;       1f5       r/w       cylinder high, this makes up the rest of the 1024
;       1f6       r/w       drive/head
;                              bit 7 = 1
;                              bit 6 = 0
;                              bit 5 = 1
;                              bit 4 = 0  drive 0 select
;                                    = 1  drive 1 select
;                              bit 3-0    head select bits
;       1f7       r         status register
;                              bit 7 = 1  controller is executing a command
;                              bit 6 = 1  drive is ready
;                              bit 5 = 1  write fault
;                              bit 4 = 1  seek complete
;                              bit 3 = 1  sector buffer requires servicing
;                              bit 2 = 1  disk data read corrected
;                              bit 1 = 1  index - set to 1 each revolution
;                              bit 0 = 1  previous command ended in an error
;       1f7       w         command register
;                            commands:
;                              50h format track
;                              20h read sectors with retry
;                              21h read sectors without retry
;                              22h read long with retry
;                              23h read long without retry
;                              30h write sectors with retry
;                              31h write sectors without retry
;                              32h write long with retry
;                              33h write long without retry
;
;  Most of these should work on even non-IDE hard disks.
;  This code is for reading, the code for writing is the next article.



	mov     dx,1f6h         ;Drive and head port
	mov     al,0a0h         ;Drive 0, head 0
	out     dx,al

	mov     dx,1f2h         ;Sector count port
	mov     al,1            ;Read one sector
	out     dx,al

	mov     dx,1f3h         ;Sector number port
	mov     al,1            ;Read sector one
	out     dx,al

	mov     dx,1f4h         ;Cylinder low port
	mov     al,0            ;Cylinder 0
	out     dx,al

	mov     dx,1f5h         ;Cylinder high port
	mov     al,0            ;The rest of the cylinder 0
	out     dx,al

	mov     dx,1f7h         ;Command port
	mov     al,20h          ;Read with retry.
	out     dx,al
still_going:
	in      al,dx
	test    al,8            ;This means the sector buffer requires
				;servicing.
	jz      still_going     ;Don't continue until the sector buffer
				;is ready.

	mov     cx,512/2        ;One sector /2
	mov     di,offset buffer
	mov     dx,1f0h         ;Data port - data comes in and out of here.
	rep     insw

;   ------

	mov     ax,201h         ;Read using int13h then compare buffers.
	mov     dx,80h
	mov     cx,1
	mov     bx,offset buffer2
	int     13h

	mov     cx,512
	mov     si,offset buffer
	mov     di,offset buffer2
	repe    cmpsb
	jne     failure
	mov     ah,9
	mov     dx,offset readmsg
	int     21h
	jmp     good_exit
failure:
	mov     ah,9
	mov     dx,offset failmsg
	int     21h
good_exit:
	mov     ax,4c00h        ;Exit the program
	int     21h


Posted: Tue Jun 03, 2008 7:43 pm
by 01000101
lol great.
fixed. =)

Thanks.

Posted: Tue Jun 03, 2008 9:49 pm
by bewing
I assume that the two problems were that you never sent the "read" command to port 1f7, and that you were requesting "sector 0" which is always illegal?

You'd probably still be well off to check the wiki article -- I put a whole bunch of things in there that are not to be found anywhere else. :wink:
http://www.osdev.org/wiki/ATA_PIO_Mode

Posted: Wed Jun 04, 2008 7:36 am
by 01000101
yes & yes.

It's odd not 'starting' at zero. But all is well now, I can read and write fine and without the use of a IRQ14 handler. And I was able to use the IDENTIFY command successfully and parse the useful words.

I'll head over to that site later (once i have more time online) and check out what they have.

Posted: Wed Jun 04, 2008 2:40 pm
by 01000101
out of curiousity (since I will eventually need a logging method for DiNS), is PIO a viable method of parse logging or is the latency to great? All I will need to do is fill up a sector of logs, and then write it and then wait until another sector is filled and write that.. and so on. It doesnt seem like it would take that much time out of the actual network operations being done.

Posted: Wed Jun 04, 2008 4:54 pm
by pcmattman
I would personally suggest using DMA, simply because while you're waiting for the logs to be written your OS will be able to continue receiving packets without any noticeable drop in performance.

If you consider that a sector is 512 bytes, and you send words down the line, that's 256 outw calls (unless you write bytes, in which case it's the full 512). Per sector. :D

It really is up to you, but the easiest thing to do would be to put together a benchmark, with some flag that makes your system use PIO or DMA. That way you can test with either PIO or DMA and figure out whether the latency of PIO is too much.

EDIT: Additional advantage to writing both a DMA and a PIO based driver is that you'll already have both ready to be used, which might be helpful later on in your project.

Posted: Wed Jun 04, 2008 7:19 pm
by bewing
I'm not so sure. The disk DMA would go through your PCI memory busmastering -- as I'm sure your network packets do too. Writing using PIO uses the IO bus, as we all know. One would assume that the log is going to end up in L1 cache.

So to write through DMA, you'd have to flush the cache to main memory through the Northbridge, then read it over the Southbridge, while fighting the network card for PCI Busmastering time/packets.

But to write it using PIO, the CPU would just have to read it from L1 cache, and pipe it over the IO Port bus ... the main problem with that is that all 512 writes are to the same IO port ... and there are automatic delays built into the IO port bus if you write multiple times to the same port, AFAIK.

It seems like it would depend on just how much support the networking cards need from the IO port bus. If they don't need much, maybe PIO would be better.

Posted: Wed Jun 04, 2008 7:44 pm
by 01000101
Network Card I/O is minimal unless there is a packet/nic error (which there 99.9% of the time isnt). For a normal operation there is one OUT to acknowledge the interrupt and one IN to see if the buffer is empty.