Page 1 of 1
ATA DRIVE consecutive READ/WRITE of multi sectors -VR.URGENT
Posted: Fri Nov 02, 2007 6:55 am
by mahesh.vallamk
ATA DRIVE consecutive READ/WRITE of multi sectors ***VERY URGENT***
I got problem in consecutivly rading multiple sectors from hard disk and writing multiple sectors into hard disk.
After reading multiple sectors I am Recalibirating the drive using ATA command and then seeking to the particular sector using SEEK command .AFTER doing this I checked the status .(0x0000ff50) was value in status register.....
my problem is then i have called multiple sector write,the first sector is succusfully written into hard diak but for second sector DATA REQUEST (DRQ) bit in status reg. is not being set........ even for a long delay of (0x00FFFFFF) ...........
can any one please help me out ....its very urgent.......
Posted: Fri Nov 02, 2007 7:03 am
by JamesM
As it's so urgent, I shall help when your urgency means something to me.
Link 1
Link 2
Re: ATA DRIVE consecutive READ/WRITE of multi sectors -VR.UR
Posted: Mon Nov 05, 2007 7:02 am
by bewing
mahesh.vallamk wrote:
my problem is then i have called multiple sector write,the first sector is succusfully written into hard diak but for second sector DATA REQUEST (DRQ) bit in status reg. is not being set........ even for a long delay of (0x00FFFFFF)
This sounds similar to a problem I had recently. Writing to disk requires different timing than reading. Even if the first sector write is successful, the timing may have been bad enough to disrupt the function of the disk, and cause it to stop working.
In my case, I was using REP OUTSW to write the 256 words to the sector. This was too fast. I needed to put an io port delay between EACH WORD that I output.
Code: Select all
outlp:
outsw
call io_delay
loop outlp
...
io_delay:
ret
THANX for reply but.......
Posted: Mon Nov 05, 2007 7:30 am
by mahesh.vallamk
hi thank you for ur reply ...actually i tried giving a delay of 0xfffffff between both sector write.......but still i am getting error ...problem is the status register is not giving any write fault error also...........
Posted: Mon Nov 05, 2007 7:57 am
by exkor
dont know if thats related but 0x0000ff50 is dword while status reg is 1 byte 50h.
If you read status with dword maybe you are doing wrong size reads/writes somewhere else. By the way reading dword slower than reading byte.
Posted: Mon Nov 05, 2007 9:06 am
by XCHG
First make sure that the nIEN bit is cleared so that you will get IRQs from the IDE Controller. The nIEN bit is in the Device Control Register. When you issue the READ MULTIPLE command to an ATA drive, do these:
1) Check the Status Register, BSY should be 0 and DRQ should be 1.
2) Then sense the IRQ by waiting ( with a timeout) for the IRQ to be issued by the IDE Controller. The Primary IDE Controller fires IRQ14 while the secondary IDE Controller fires IRQ15.
3) Now read one BLOCK of data and not 1 SECTOR. You have to set the SECTORS PER BLOCK using the SET MULTIPLE command. So if each block is 4 sectors, then you have to read (4 * 512) / 2 WORDs from the IDE Controller. Note the / 2 because each WORD is 2 bytes.
4) Then if there are more blocks to read, go to the first step.
5) After you have read all the blocks, read the value in the Alternate Status Register and ignore it. This is to make sure that the INTRQ is negated by the IDE Controller.
6) Read the Status Register and ignore the value that is read. Again, this makes sure that the INTRQ is negated by the IDE Controller.
I Have coded a complete free ATA library (ATA1 Compliant) in NASM.
You can click here for more information.
Re: THANX for reply but.......
Posted: Fri Nov 09, 2007 3:28 pm
by bewing
mahesh.vallamk wrote: i tried giving a delay of 0xfffffff between both sector write
My point was that you may need a delay between EACH OUTPUT WORD.
Re: THANX for reply but.......
Posted: Fri Nov 09, 2007 4:58 pm
by XCHG
bewing wrote:mahesh.vallamk wrote: i tried giving a delay of 0xfffffff between both sector write
My point was that you may need a delay between EACH OUTPUT WORD.
ATA specifications don't state anything about that. I don't think he needs delays between a sector read/write operation
Re: THANX for reply but.......
Posted: Fri Nov 09, 2007 5:11 pm
by bewing
XCHG wrote:
ATA specifications don't state anything about that.
Well, they sorta do, but it's wrong. In my copy, it implies that it is intended that you use REP INSW and REP OUTSW to transmit data from/to the ATA bus. When I try it on real hardware, REP INSW works. REP OUTSW causes random disk lockups or other weirdness. Putting a tiny IO port delay between each OUTSW fixes the lockups.
XCHG wrote:
I don't think he needs delays between a sector read/write operation
Agreed.
XCHG wrote:
5) After you have read all the blocks, read the value in the Alternate Status Register and ignore it. This is to make sure that the INTRQ is negated by the IDE Controller.
6) Read the Status Register and ignore the value that is read. Again, this makes sure that the INTRQ is negated by the IDE Controller.
It's my understanding that you only need to do one or the other, not both.
The Status and Alternate Status registers connect to the same wires -- it's just that accessing Status will pre-empt interrupts, and Alternate Status won't.
INTRQ is NOT fired
Posted: Tue Nov 13, 2007 3:40 am
by mahesh.vallamk
I followed steps suggested by XCHEG .
But still I am getting problems..........
The INTRQ is not asserted after setting command for IDENTIFY DRIVE .
the steps i am following are
1.set drive to primary(0x0E0),
2.set nIEN=0,
3.set command IDENTIFY DRIVE(0xEC)
4.wait for BSY=0 & DRQ=1 (continues read of status register)
5.wait for INTRQ to be asserted(set a k=1 in ISR subroutine) and also read status
6.check for K=1 then read buffer.
but step 5 is not at all happening.
Posted: Tue Nov 13, 2007 7:27 pm
by bewing
There are 2 status registers. The regular one (at 0x1f7), and the Alternate Status Register (I forget the location right this minute). There is an important difference between them. If you read the regular status register, doing that will prevent the next disk IRQ from ever firing.
So, the point is, if you read the regular status register and wait for the BUSY bit to turn off, and the DRQ bit to turn on -- then do not wait for an IRQ after that, because it will never arrive. And you already know that the data is available, because the DRQ bit is on. Just go and read the data.
If, instead, you really want to receive an IRQ -- then you don't need to check the status registers at all. You send the command, wait for the IRQ, and when the IRQ fires, the data is ready. Just go read it.
If you really want to do BOTH, then do not ever read the regular status register (because it will prevent the IRQ from firing). Read the alternate status register instead. Once you read the alternate status register, you can still go and wait for the IRQ if you want to.
Posted: Tue Nov 13, 2007 11:18 pm
by mahesh.vallamk
****************So, the point is, if you read the regular status register and wait for the BUSY bit to turn off, and the DRQ bit to turn on -- then do not wait for an IRQ after that, because it will never arrive. And you already know that the data is available, because the DRQ bit is on. Just go and read the data. ****************************
First I tried this method without checking IRQ and reading regular status........
commands like identify params ,read (with multiple times using for loop),read buffer ,WRITE for one time .......were working fine.
but this steps are not working.......
WRITE MULTI command
READ MULTI command
WRITE command (called in loop for sect count times is not working)
Later.............
I tried the second method with out reading regular status and waiting for IRQ to fire.....
In this method IRQ was never fired.......
the same thing has happend for third method also ..............
Posted: Wed Nov 14, 2007 7:37 am
by mahesh.vallamk
This is code fragment for reading parameters
outportb(0x1f7,0xEC); /*identify drive*/
my_delay(10000);
outportb(0x1f7,0xE4); /*read buffer*/
L_temp=inportb(0x3f6); /*read alt status*/
my_delay(1000000);
while(G_temp !=1); /*setting in interrupt*/
G_temp=0;
for(L_ctrl_index=0;L_ctrl_index<65;L_ctrl_index++)
{
L_temp=inportb(0x1f0);
}
L_temp=inportb(0x1f7);
Sys_Hexprint(L_temp);
interrupt code:
L_temp=inportb(0x3f6);
my_delay(1000000);
L_status=L_status & 0x000000ff;
while(L_status !=0x00000058) /*DRQ set BSY clr*/
{
L_status=inportb(0x3f6);
}
G_temp=1;
Posted: Wed Nov 14, 2007 8:46 am
by exkor
Code: Select all
outportb(0x1f7,0xEC); /*identify drive*/
outportb(0x1f7,0xE4); /*read buffer*/
before issuing new command need to ensure that BSY=0 DRQ=0 & DRDY=1, DRDY is not required for ATAPI devices. Your status reg will have 50h most likely.
in your case 2nd command should fail because the status bits will not match with requirements (I dont know why it's here at all)
outportb(0x1f7,0xE4);
Code: Select all
outportb(0x1f7,0xEC); /*identify drive*/
my_delay(10000);
L_temp=inportb(0x3f6); /*read alt status*/
you dont need to read alt status, just wait for interrupt for half a second,
if no interrupt then no device present -> read status reg then -> ensure it is invalid and continue with device enumeration
Code: Select all
while(L_status !=0x00000058) /*DRQ set BSY clr*/
{
L_status=inportb(0x3f6);
}
no loops here just read status once, whatever is in the status reg is final, check that status reg has correct bits set
And no delays in the interrupt handler please.
Some IDE controllers require bus mastering status reg to be read otherwise you will only get 1 interrupt. But forget about that now
Code: Select all
outportb(0x1f7,0xE4); /*read buffer*/
the way you read 256 words after Ident Dev is using 'Data' port(page 51, section 5 in ATA7 Vol1 manual)
You better read all 256 words, then ensure that DRQ=0 & BSY=0 too
Code: Select all
G_temp=0;
outportb(0x1f7,0xEC); /*identify drive*/
my_delay(10000);
outportb(0x1f7,0xE4); /*read buffer*/
L_temp=inportb(0x3f6); /*read alt status*/
my_delay(1000000);
You must set G_temp variable before you issued a command
outportb(0x1f7,0xEC); /*identify drive*/
<--------------------- interrupt happens here
G_temp=0;
Pretty simple interrupt handler is located at
http://ata-atapi.com/atadrvr.zip
in file ATAIOINT.C
function static void far interrupt int_handler( void )
if I missed something then maybe others will find
Posted: Wed Nov 14, 2007 1:47 pm
by bewing
mahesh.vallamk wrote:
outportb(0x1f7,0xEC); /*identify drive*/
my_delay(10000);
outportb(0x1f7,0xE4); /*read buffer*/
As exkor said, the READ BUFFER command should not be there.
The IDENTIFY command returns the data to you all by itself.
Just issue IDENTIFY, wait for DRQ (if using method #1), and then inportw the 256 words.
Code: Select all
while(L_status !=0x00000058) /*DRQ set BSY clr*/
should say: