Page 1 of 1

ATA PIO C driver need some help

Posted: Thu Feb 24, 2011 12:34 am
by steven765
Thanks for the comments below. It now works on a vmware ide device reading and writing. My identify device parsing is, well, correct enough, i get the string and proper number of sectors which is all i need. I hope this helps others.

/////////////////////////assembly in and out ///////////////////////////////////////////

Code: Select all

static inline void insw(unsigned short port, void *addr, size_t cnt)
 {
	__asm volatile("rep; insw"
	    : "+D" (addr), "+c" (cnt)
	    : "d" (port)
	    : "memory");
 }

Code: Select all

static inline void outsw(unsigned short port, const void *addr, size_t cnt){
	__asm volatile("rep; outsw" : "+S" (addr), "+c" (cnt) : "d" (port));
}
////////////////////////////////////////////////////////////////////////////////

Code: Select all

int read_sector(int LBA) {
	int count = 1;		//number of sectors to read     
	char slavebit =0;	//0 for master device 1 for slave   sets bit 5 in 1f6 
	int stat;

	outb(0x3f6, 0x02);	//disable interrupts

	outb(0x1F6, (0xE0 | (slavebit <<  4) | (LBA >> 24 & 0x0F))); 

	//waste some time
	outb(0x1f1, 0x00);

	//set the sector count
	outb(0x1f2, (unsigned char)count);
	sleep(1);
	stat = ide_polling(0, 0);
		if(stat != 0)
			return stat;
	//send the low 8 bits of lbs to 1f3
	outb(0x1f3, (unsigned char)LBA); 
	sleep(1);
	stat = ide_polling(0, 0);
		if(stat != 0)
			return stat;
	//send the middle 8 bits to 1f4
	outb(0x1f4, (unsigned char)(LBA >> 8));
	sleep(1);
	stat = ide_polling(0, 0);
		if(stat != 0)
			return stat;
	//send the high 8 to 1f5
	outb(0x1f5, (unsigned char)(LBA >> 16));
	sleep(1);
	stat = ide_polling(0, 0);
	if(stat != 0)
		return stat;
	//issue a read sectors command
	outb(0x1f7, 0x20);
	sleep(1);
	stat = ide_polling(0, 0);
		if(stat != 0)
			return stat;

	//eat 256 words form the buffer
	insw(0x1f0, ide_buf, 256);
	
	ide_polling(0,0);
}

Code: Select all

int write_sector(int LBA)  {
	int i,count = 1;		//number of sectors to read     
	char slavebit =0;	//0 for master device 1 for slave   sets bit 5 in 1f6 
	int stat=0;

	outb(0x3f6, 0x02);	//disable interrupts

	outb(0x1F6, (0xE0 | (slavebit <<  4) | (LBA >> 24 & 0x0F))); 

	//waste some time
	outb(0x1f1, 0x00);

	//set the sector count
	outb(0x1f2, (unsigned char)count);
	sleep(1);
	stat = ide_polling(0, 1);
		if(stat == 1 || stat ==2)
			printf("error after 1f2  ");
	//send the low 8 bits of lbs to 1f3
	outb(0x1f3, (unsigned char)LBA); 
	sleep(1);
	stat = ide_polling(0,1);
		if(stat == 1 || stat ==2)
			printf("error after 1f3  ");
	//send the middle 8 bits to 1f4
	outb(0x1f4, (unsigned char)(LBA >> 8));
	sleep(1);
	stat = ide_polling(0, 1);
		if(stat == 1 || stat ==2)
			printf("error after 1f4  ");
	//send the high 8 to 1f5
	outb(0x1f5, (unsigned char)(LBA >> 16));
	sleep(1);
	stat = ide_polling(0, 1);
	if(stat == 1 || stat ==2)
			printf("error after 1f5  ");
	//issue a WRITE sectors command
	outb(0x1f7, 0x30);
	sleep(1);
	stat = ide_polling(0, 1);
		if(stat == 1 || stat ==2)
			printf("error after write command  ");

	//output 256 words form the buffer
	
	outsw(0x1f0,outarray, 256);

	stat = ide_polling(0, 1);
		if(stat == 1 || stat ==2)
			printf("error after write data  ");

	outb(0x1f7, 0xE7); //flush the cache after each write command

	ide_polling(0,1);
}

Re: ATA PIO C driver need some help

Posted: Thu Feb 24, 2011 2:30 pm
by bewing
A) You must read and write complete sectors. If you only write 10 words, the drive is left hanging, waiting for the rest of the sector.

B) You missed the line in the wiki article that says "do not use REP OUTSW to do writes" because the data comes too fast for some ATA controllers to handle.

Re: ATA PIO C driver need some help

Posted: Thu Feb 24, 2011 4:30 pm
by steven765
Thanks, so you just write zero's for the rest of the sector?

I didn't think that rep outsw would be as big of a deal on a virtual device (vmware). However, my question is using plain outsw, does the drive automatically cycle each word to the new location? Is that the reason it expects them in 256 word chunks?

Re: ATA PIO C driver need some help

Posted: Thu Feb 24, 2011 6:28 pm
by bewing
Yes, that is true, and yes.

Re: ATA PIO C driver need some help

Posted: Thu Feb 24, 2011 11:31 pm
by steven765
Thanks it's all working now. I'll probably have to use a insw in a loop with a pause when we go to try this on a actual physical disk. I also now need to look at interrupts, the fun continues. I should probably fix the IDE wiki because well that code doesn't work or compile in gcc. At least add this to the code at the bottom of ataPIO?

Re: ATA PIO C driver need some help

Posted: Fri Feb 25, 2011 1:38 pm
by bewing
As I wrote in the ATA PIO wiki article, REP INSW works just fine. It's just the OUTSW that can't be a REP on real hardware.

And I still say that the "IDE" article is merely a tutorial, and is wrong in lots of places, and should not be trusted.

(BTW: if you add stuff to the ATA PIO article, it will give you a warning message about exceeding 32K -- ignore it.)

Re: ATA PIO C driver need some help

Posted: Fri Feb 25, 2011 2:34 pm
by Dario
I think that you can combine both read and write functions to one function(same addressing and status checking)....and learn to use #define directives...it's so much easier to read outw(ATA_CMD, ATA_CMD_WRITE) then outw(0x1f7, 0x20). Abstraction is a good thing.

Re: ATA PIO C driver need some help

Posted: Tue Mar 01, 2011 5:31 pm
by steven765
Dario wrote:I think that you can combine both read and write functions to one function(same addressing and status checking)....and learn to use #define directives...it's so much easier to read outw(ATA_CMD, ATA_CMD_WRITE) then outw(0x1f7, 0x20). Abstraction is a good thing.
You can, but then you start making things more complex. The #def's are the way to do things in future. However as I just experienced, that is only easier once you know what they mean. Now that I have a working concept of how things operate in my mind I'm converting my code to use the #def's. When you're trying to understand how it works, I found myself constantly scrolling up to reference what each #def meant.. adding an extra layer of translation in my brain and slowing down the whole understanding process.

Re: ATA PIO C driver need some help

Posted: Wed Mar 02, 2011 12:14 am
by Chandra
steven765 wrote:
Dario wrote:I think that you can combine both read and write functions to one function(same addressing and status checking)....and learn to use #define directives...it's so much easier to read outw(ATA_CMD, ATA_CMD_WRITE) then outw(0x1f7, 0x20). Abstraction is a good thing.
You can, but then you start making things more complex. The #def's are the way to do things in future. However as I just experienced, that is only easier once you know what they mean. Now that I have a working concept of how things operate in my mind I'm converting my code to use the #def's. When you're trying to understand how it works, I found myself constantly scrolling up to reference what each #def meant.. adding an extra layer of translation in my brain and slowing down the whole understanding process.
Excellent! You just interpreted my heart. Nevertheless, there's a workaround.
Generally, the best idea is to use "#define" and then comment the value where it is used.Consider this:

Code: Select all

#define MASK_PORT 0x7f
#define MASK_VALUE 90


outportb(MASK_PORT,MASK_VALUE);     //send 90 to port 0x7f 
This way, it'll be easier to track what command is being sent and what value it carries. Cheers.

Re: ATA PIO C driver need some help

Posted: Thu Mar 03, 2011 6:35 pm
by steven765
So the file system i'm trying to marry this to is designed to input and output bytes not words. Since the function takes a void * is there any harm in just using it as is? I know it wastes space, but I can't seem to make read and write work with insb and outsb . The second sector is always coming back FF, so an error is occurring, but I can't find it.

Re: ATA PIO C driver need some help

Posted: Thu Mar 03, 2011 9:20 pm
by thepowersgang
@steven765: Your filesystem driver should be working with sectors (or blocks a multiple of the underlying sector size), not individual bytes when reading from the disk.

All the disk IO functions care about is a sector address, sector count, and a buffer to work from.

Re: ATA PIO C driver need some help

Posted: Thu Mar 03, 2011 9:56 pm
by steven765
thepowersgang wrote:@steven765: Your filesystem driver should be working with sectors (or blocks a multiple of the underlying sector size), not individual bytes when reading from the disk.

All the disk IO functions care about is a sector address, sector count, and a buffer to work from.

The buffer is defined in terms of bytes or words. To frame my question better. When writing/reading from the device. If I use rep; insw or outsw and run that 256 times (512 byte sector size) everything works great. However, when i try to use insb or outsb repped 512 types on multiple sectors it only writes one byte per word. And nothing past the first sector is written.

Re: ATA PIO C driver need some help

Posted: Thu Mar 03, 2011 10:23 pm
by Chandra
It would be useful to see your insb and outsb functions to check if they are actually configured to deal with 'words' and not 'bytes'.
You may want to use insw and outsw instead.

Re: ATA PIO C driver need some help

Posted: Thu Mar 03, 2011 10:52 pm
by gerryg400
The buffer is defined in terms of bytes or words. To frame my question better. When writing/reading from the device. If I use rep; insw or outsw and run that 256 times (512 byte sector size) everything works great. However, when i try to use insb or outsb repped 512 types on multiple sectors it only writes one byte per word. And nothing past the first sector is written.
You can't read or write the data byte at a time. It won't work. The ports are 16 bits wide. You must read or write it 16-bits at a time.

Re: ATA PIO C driver need some help

Posted: Sat Mar 05, 2011 11:01 pm
by steven765
gerryg400 wrote:
The buffer is defined in terms of bytes or words. To frame my question better. When writing/reading from the device. If I use rep; insw or outsw and run that 256 times (512 byte sector size) everything works great. However, when i try to use insb or outsb repped 512 types on multiple sectors it only writes one byte per word. And nothing past the first sector is written.
You can't read or write the data byte at a time. It won't work. The ports are 16 bits wide. You must read or write it 16-bits at a time.

Thanks, that makes sense!

@chandra I knew the functions were working properly, it's the same ones from bsd. Thanks for checking though

So I guess the task falls on me to detect the size of the incoming array (bytes) and stuff it into words. ugh.