Bus master bug...
Posted: Tue Feb 03, 2004 7:33 am
I've tried to do reading/writing on my hdd's with bus master operation for weeks now, and it just doesn't work. I really hope you guys can give me some help here...
The problem is simply that no interrupt is generated after I started the bus master operation, if I use for example read sectors instead of read dma an interrupt is generated and it seems to work fine. A strange thing is that if I try to read from status/alt. status or any other ATA register more then a very short time after bus master operation is started the computer totally locks! I have followed every step in the ATA-4 documentation and in my chip set documentation (Intel 440BX) but nothing works. My hdd's are a Seagate ST34321A (ATA-3) and a IBM-DTLA-307030 (ATA-4) both connected to primary channel. Identify device command shows that ultra-dma mode 2 is selected for both of them and UDMACTL register in chipset says ultra-dma is selected. BUT - the Drive 0/1 DMA Capable bits in bus master ide status register are both 0.
I've checked all the values in my variables carefully and I've tried to change around a lot but with no success. So what have I forgotten?
==========================================================================
/* set prd pointer... */
outl(io_base+4,(unsigned)(channel->prd));
/* set read or write bit */
outb(io_base,((char)(read_or_write<<3))|(inb(io_base)&0xF7));
/* clear IDE interrupt status and IDE DMA error */
outb(io_base+2,0x6);
/* device select with delay (temporary solution...), add 4 highest lba bits */
while(inb(command_block+7)&0x88);
outb(command_block+6,(char)((channel->dev_select<<4)|0x40|(lba>>24)));
while(test++ > 10000)
while(inb(command_block+7)&0x88);
/* rest of lba address... */
outb(command_block+5,(char)(lba>>16));
outb(command_block+4,(char)(lba>>8));
outb(command_block+3,(char)(lba));
/* sector count, 128 or 256 sectors */
outb(command_block+2,(char)(blocks_to_read<<7));
/* the command... */
outb(command_block+7,read_or_write?WRITE_DMA:READ_DMA);
/* start bus master */
outb(io_base,((char)(read_or_write<<3))|0x01|(inb(io_base)&0xF7));
==========================================================================
io_base for primary channel is 0x1020, command_block 0x01F0 and control_block 0x03F4. PRD table is aligned on 64KB boundary and the memory regions for reading/writing also.
The problem is simply that no interrupt is generated after I started the bus master operation, if I use for example read sectors instead of read dma an interrupt is generated and it seems to work fine. A strange thing is that if I try to read from status/alt. status or any other ATA register more then a very short time after bus master operation is started the computer totally locks! I have followed every step in the ATA-4 documentation and in my chip set documentation (Intel 440BX) but nothing works. My hdd's are a Seagate ST34321A (ATA-3) and a IBM-DTLA-307030 (ATA-4) both connected to primary channel. Identify device command shows that ultra-dma mode 2 is selected for both of them and UDMACTL register in chipset says ultra-dma is selected. BUT - the Drive 0/1 DMA Capable bits in bus master ide status register are both 0.
I've checked all the values in my variables carefully and I've tried to change around a lot but with no success. So what have I forgotten?
==========================================================================
/* set prd pointer... */
outl(io_base+4,(unsigned)(channel->prd));
/* set read or write bit */
outb(io_base,((char)(read_or_write<<3))|(inb(io_base)&0xF7));
/* clear IDE interrupt status and IDE DMA error */
outb(io_base+2,0x6);
/* device select with delay (temporary solution...), add 4 highest lba bits */
while(inb(command_block+7)&0x88);
outb(command_block+6,(char)((channel->dev_select<<4)|0x40|(lba>>24)));
while(test++ > 10000)
while(inb(command_block+7)&0x88);
/* rest of lba address... */
outb(command_block+5,(char)(lba>>16));
outb(command_block+4,(char)(lba>>8));
outb(command_block+3,(char)(lba));
/* sector count, 128 or 256 sectors */
outb(command_block+2,(char)(blocks_to_read<<7));
/* the command... */
outb(command_block+7,read_or_write?WRITE_DMA:READ_DMA);
/* start bus master */
outb(io_base,((char)(read_or_write<<3))|0x01|(inb(io_base)&0xF7));
==========================================================================
io_base for primary channel is 0x1020, command_block 0x01F0 and control_block 0x03F4. PRD table is aligned on 64KB boundary and the memory regions for reading/writing also.