ATA PIO C driver need some help

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
steven765
Posts: 21
Joined: Tue Feb 22, 2011 3:28 pm

ATA PIO C driver need some help

Post 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);
}
Last edited by steven765 on Thu Feb 24, 2011 11:28 pm, edited 1 time in total.
User avatar
bewing
Member
Member
Posts: 1401
Joined: Wed Feb 07, 2007 1:45 pm
Location: Eugene, OR, US

Re: ATA PIO C driver need some help

Post 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.
steven765
Posts: 21
Joined: Tue Feb 22, 2011 3:28 pm

Re: ATA PIO C driver need some help

Post 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?
User avatar
bewing
Member
Member
Posts: 1401
Joined: Wed Feb 07, 2007 1:45 pm
Location: Eugene, OR, US

Re: ATA PIO C driver need some help

Post by bewing »

Yes, that is true, and yes.
steven765
Posts: 21
Joined: Tue Feb 22, 2011 3:28 pm

Re: ATA PIO C driver need some help

Post 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?
User avatar
bewing
Member
Member
Posts: 1401
Joined: Wed Feb 07, 2007 1:45 pm
Location: Eugene, OR, US

Re: ATA PIO C driver need some help

Post 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.)
Dario
Member
Member
Posts: 117
Joined: Sun Aug 31, 2008 12:39 pm

Re: ATA PIO C driver need some help

Post 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.
____
Dario
steven765
Posts: 21
Joined: Tue Feb 22, 2011 3:28 pm

Re: ATA PIO C driver need some help

Post 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.
User avatar
Chandra
Member
Member
Posts: 487
Joined: Sat Jul 17, 2010 12:45 am

Re: ATA PIO C driver need some help

Post 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.
Programming is not about using a language to solve a problem, it's about using logic to find a solution !
steven765
Posts: 21
Joined: Tue Feb 22, 2011 3:28 pm

Re: ATA PIO C driver need some help

Post 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.
User avatar
thepowersgang
Member
Member
Posts: 734
Joined: Tue Dec 25, 2007 6:03 am
Libera.chat IRC: thePowersGang
Location: Perth, Western Australia
Contact:

Re: ATA PIO C driver need some help

Post 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.
Kernel Development, It's the brain surgery of programming.
Acess2 OS (c) | Tifflin OS (rust) | mrustc - Rust compiler
Currently Working on: mrustc
steven765
Posts: 21
Joined: Tue Feb 22, 2011 3:28 pm

Re: ATA PIO C driver need some help

Post 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.
User avatar
Chandra
Member
Member
Posts: 487
Joined: Sat Jul 17, 2010 12:45 am

Re: ATA PIO C driver need some help

Post 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.
Programming is not about using a language to solve a problem, it's about using logic to find a solution !
gerryg400
Member
Member
Posts: 1801
Joined: Thu Mar 25, 2010 11:26 pm
Location: Melbourne, Australia

Re: ATA PIO C driver need some help

Post 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.
If a trainstation is where trains stop, what is a workstation ?
steven765
Posts: 21
Joined: Tue Feb 22, 2011 3:28 pm

Re: ATA PIO C driver need some help

Post 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.
Post Reply