ATA DRIVE consecutive READ/WRITE of multi sectors -VR.URGENT
-
- Posts: 6
- Joined: Fri Nov 02, 2007 6:36 am
ATA DRIVE consecutive READ/WRITE of multi sectors -VR.URGENT
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.......
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.......
Re: ATA DRIVE consecutive READ/WRITE of multi sectors -VR.UR
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.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)
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
-
- Posts: 6
- Joined: Fri Nov 02, 2007 6:36 am
THANX for reply but.......
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...........
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.
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.
On the field with sword and shield amidst the din of dying of men's wails. War is waged and the battle will rage until only the righteous prevails.
Re: THANX for reply but.......
My point was that you may need a delay between EACH OUTPUT WORD.mahesh.vallamk wrote: i tried giving a delay of 0xfffffff between both sector write
Re: THANX for reply but.......
ATA specifications don't state anything about that. I don't think he needs delays between a sector read/write operationbewing wrote:My point was that you may need a delay between EACH OUTPUT WORD.mahesh.vallamk wrote: i tried giving a delay of 0xfffffff between both sector write
On the field with sword and shield amidst the din of dying of men's wails. War is waged and the battle will rage until only the righteous prevails.
Re: THANX for reply but.......
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: ATA specifications don't state anything about that.
Agreed.XCHG wrote: I don't think he needs delays between a sector read/write operation
It's my understanding that you only need to do one or the other, not both.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.
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.
-
- Posts: 6
- Joined: Fri Nov 02, 2007 6:36 am
INTRQ is NOT fired
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.
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.
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.
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.
-
- Posts: 6
- Joined: Fri Nov 02, 2007 6:36 am
****************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 ..............
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 ..............
-
- Posts: 6
- Joined: Fri Nov 02, 2007 6:36 am
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;
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;
Code: Select all
outportb(0x1f7,0xEC); /*identify drive*/
outportb(0x1f7,0xE4); /*read buffer*/
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*/
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);
}
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*/
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);
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
As exkor said, the READ BUFFER command should not be there.mahesh.vallamk wrote: outportb(0x1f7,0xEC); /*identify drive*/
my_delay(10000);
outportb(0x1f7,0xE4); /*read buffer*/
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*/
Code: Select all
while ((L_status & 0x88) != 8)