diff options
author | Kevin O'Connor <kevin@koconnor.net> | 2008-03-11 19:42:41 -0400 |
---|---|---|
committer | Kevin O'Connor <kevin@koconnor.net> | 2008-03-11 19:42:41 -0400 |
commit | 1fcf1448561c07ffa47f05d3c492c78d2bfbbb3b (patch) | |
tree | c256fe79a56bf08d5bf6312263a602a3dc3c6f9c /src | |
parent | a69bc3a94fd28edd957e0d201432b566b700ca2b (diff) | |
download | seabios-hppa-1fcf1448561c07ffa47f05d3c492c78d2bfbbb3b.zip seabios-hppa-1fcf1448561c07ffa47f05d3c492c78d2bfbbb3b.tar.gz seabios-hppa-1fcf1448561c07ffa47f05d3c492c78d2bfbbb3b.tar.bz2 |
Reorganize ata code; reduce stack usage.
This fixes an issue with freedos lbacache - the bios was overrunning
the stack on disk requests.
The code has been simplified by extracting common code.
Some handlers moved to inline code to reduce overall stack usage.
Diffstat (limited to 'src')
-rw-r--r-- | src/ata.c | 375 | ||||
-rw-r--r-- | src/ata.h | 217 | ||||
-rw-r--r-- | src/atabits.h | 136 | ||||
-rw-r--r-- | src/disk.c | 32 |
4 files changed, 405 insertions, 355 deletions
@@ -28,7 +28,7 @@ static int await_ide(u8 when_done, u16 base, u16 timeout) { - u32 time=0,last=0; + u32 time=0, last=0; // for the times you're supposed to throw one away u16 status = inb(base + ATA_CB_STAT); for (;;) { @@ -138,90 +138,97 @@ ata_reset(u16 device) // 5 : more sectors to read/verify // 6 : no sectors left to write // 7 : more sectors to write -u16 -ata_cmd_data(u16 device, u16 command, u16 count, u16 cylinder - , u16 head, u16 sector, u32 lba, u16 segment, u16 offset) -{ - DEBUGF("ata_cmd_data d=%d cmd=%d count=%d c=%d h=%d s=%d" - " lba=%d seg=%x off=%x\n" - , device, command, count, cylinder, head, sector - , lba, segment, offset); - - u8 channel = device / 2; - u8 slave = device % 2; +static int +send_cmd(struct ata_pio_command *cmd) +{ + u16 biosid = cmd->biosid; + u8 channel = biosid / 2; u16 iobase1 = GET_EBDA(ata.channels[channel].iobase1); u16 iobase2 = GET_EBDA(ata.channels[channel].iobase2); - u8 mode = GET_EBDA(ata.devices[device].mode); - - // Reset count of transferred data - SET_EBDA(ata.trsfsectors,0); - SET_EBDA(ata.trsfbytes,0L); u8 status = inb(iobase1 + ATA_CB_STAT); if (status & ATA_CB_STAT_BSY) return 1; outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN, iobase2 + ATA_CB_DC); - - // sector will be 0 only on lba access. Convert to lba-chs - if (sector == 0) { - if ((count >= 1 << 8) || (lba + count >= 1UL << 28)) { - outb(0x00, iobase1 + ATA_CB_FR); - outb((count >> 8) & 0xff, iobase1 + ATA_CB_SC); - outb(lba >> 24, iobase1 + ATA_CB_SN); - outb(0, iobase1 + ATA_CB_CL); - outb(0, iobase1 + ATA_CB_CH); - command |= 0x04; - count &= (1UL << 8) - 1; - lba &= (1UL << 24) - 1; - } - sector = (u16) (lba & 0x000000ffL); - cylinder = (u16) ((lba>>8) & 0x0000ffffL); - head = ((u16) ((lba>>24) & 0x0000000fL)) | ATA_CB_DH_LBA; + if (cmd->command & 0x04) { + outb(0x00, iobase1 + ATA_CB_FR); + outb(cmd->sector_count2, iobase1 + ATA_CB_SC); + outb(cmd->lba_low2, iobase1 + ATA_CB_SN); + outb(cmd->lba_mid2, iobase1 + ATA_CB_CL); + outb(cmd->lba_high2, iobase1 + ATA_CB_CH); } - - outb(0x00, iobase1 + ATA_CB_FR); - outb(count, iobase1 + ATA_CB_SC); - outb(sector, iobase1 + ATA_CB_SN); - outb(cylinder & 0x00ff, iobase1 + ATA_CB_CL); - outb(cylinder >> 8, iobase1 + ATA_CB_CH); - outb((slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (u8) head - , iobase1 + ATA_CB_DH); - outb(command, iobase1 + ATA_CB_CMD); + outb(cmd->feature, iobase1 + ATA_CB_FR); + outb(cmd->sector_count, iobase1 + ATA_CB_SC); + outb(cmd->lba_low, iobase1 + ATA_CB_SN); + outb(cmd->lba_mid, iobase1 + ATA_CB_CL); + outb(cmd->lba_high, iobase1 + ATA_CB_CH); + outb(cmd->device, iobase1 + ATA_CB_DH); + outb(cmd->command, iobase1 + ATA_CB_CMD); await_ide(NOT_BSY_DRQ, iobase1, IDE_TIMEOUT); - status = inb(iobase1 + ATA_CB_STAT); + status = inb(iobase1 + ATA_CB_STAT); if (status & ATA_CB_STAT_ERR) { - DEBUGF("ata_cmd_data : read error\n"); + DEBUGF("send_cmd : read error\n"); return 2; } if (!(status & ATA_CB_STAT_DRQ)) { - DEBUGF("ata_cmd_data : DRQ not set (status %02x)\n" + DEBUGF("send_cmd : DRQ not set (status %02x)\n" , (unsigned) status); return 3; } - // FIXME : move seg/off translation here + return 0; +} + +int +ata_transfer(struct ata_pio_command *cmd) +{ + DEBUGF("ata_transfer id=%d cmd=%d lba=%d count=%d seg=%x off=%x\n" + , cmd->biosid, cmd->command + , (cmd->lba_high << 16) | (cmd->lba_mid << 8) | cmd->lba_low + , cmd->sector_count, cmd->segment, cmd->offset); + + // Reset count of transferred data + SET_EBDA(ata.trsfsectors,0); + SET_EBDA(ata.trsfbytes,0L); + + int ret = send_cmd(cmd); + if (ret) + return ret; + + u16 biosid = cmd->biosid; + u8 channel = biosid / 2; + u16 iobase1 = GET_EBDA(ata.channels[channel].iobase1); + u16 iobase2 = GET_EBDA(ata.channels[channel].iobase2); + u8 mode = GET_EBDA(ata.devices[biosid].mode); + int iswrite = (cmd->command & ~0x40) == ATA_CMD_WRITE_SECTORS; irq_enable(); + u16 segment = cmd->segment; + u16 offset = cmd->offset; u8 current = 0; - while (1) { - if (offset > 0xf800) { + u16 count = cmd->sector_count; + u8 status; + for (;;) { + if (offset >= 0xf800) { offset -= 0x800; segment += 0x80; } - if (command == ATA_CMD_WRITE_SECTORS) { + if (iswrite) { // Write data to controller + DEBUGF("Write sector id=%d dest=%x:%x\n", biosid, segment, offset); if (mode == ATA_MODE_PIO32) outsl_seg(iobase1, segment, offset, 512 / 4); else outsw_seg(iobase1, segment, offset, 512 / 2); } else { // Read data from controller + DEBUGF("Read sector id=%d dest=%x:%x\n", biosid, segment, offset); if (mode == ATA_MODE_PIO32) insl_seg(iobase1, segment, offset, 512 / 4); else @@ -239,7 +246,7 @@ ata_cmd_data(u16 device, u16 command, u16 count, u16 cylinder status &= (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR); if (status != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ)) { - DEBUGF("ata_cmd_data : more sectors left (status %02x)\n" + DEBUGF("ata_transfer : more sectors left (status %02x)\n" , (unsigned) status); return 5; } @@ -247,17 +254,18 @@ ata_cmd_data(u16 device, u16 command, u16 count, u16 cylinder status &= (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR); - if (command != ATA_CMD_WRITE_SECTORS) + if (!iswrite) status &= ~ATA_CB_STAT_DF; if (status != ATA_CB_STAT_RDY ) { - DEBUGF("ata_cmd_data : no sectors left (status %02x)\n" + DEBUGF("ata_transfer : no sectors left (status %02x)\n" , (unsigned) status); return 4; } + irq_disable(); + // Enable interrupts outb(ATA_CB_DC_HD15, iobase2+ATA_CB_DC); - irq_disable(); return 0; } @@ -270,23 +278,17 @@ ata_cmd_data(u16 device, u16 command, u16 count, u16 cylinder // 2 : BUSY bit set // 3 : error // 4 : not ready -u16 -ata_cmd_packet(u16 device, u8 *cmdbuf, u8 cmdlen, u16 header - , u32 length, u8 inout, u16 bufseg, u16 bufoff) +int +ata_cmd_packet(u16 biosid, u8 *cmdbuf, u8 cmdlen + , u16 header, u32 length, u16 bufseg, u16 bufoff) { - DEBUGF("ata_cmd_packet d=%d cmdlen=%d h=%d l=%d inout=%d" + DEBUGF("ata_cmd_packet d=%d cmdlen=%d h=%d l=%d" " seg=%x off=%x\n" - , device, cmdlen, header, length, inout + , biosid, cmdlen, header, length , bufseg, bufoff); - u8 channel = device / 2; - u8 slave = device % 2; - - // Data out is not supported yet - if (inout == ATA_DATA_OUT) { - BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n"); - return 1; - } + u8 channel = biosid / 2; + u8 slave = biosid % 2; // The header length must be even if (header & 1) { @@ -296,155 +298,133 @@ ata_cmd_packet(u16 device, u8 *cmdbuf, u8 cmdlen, u16 header u16 iobase1 = GET_EBDA(ata.channels[channel].iobase1); u16 iobase2 = GET_EBDA(ata.channels[channel].iobase2); - u8 mode = GET_EBDA(ata.devices[device].mode); - - if (cmdlen < 12) - cmdlen=12; - if (cmdlen > 12) - cmdlen=16; - cmdlen>>=1; + u8 mode = GET_EBDA(ata.devices[biosid].mode); + + struct ata_pio_command cmd; + cmd.sector_count = 0; + cmd.feature = 0; + cmd.lba_low = 0; + cmd.lba_mid = 0xf0; + cmd.lba_high = 0xff; + cmd.device = slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0; + cmd.command = ATA_CMD_PACKET; + + cmd.biosid = biosid; + int ret = send_cmd(&cmd); + if (ret) + return ret; // Reset count of transferred data SET_EBDA(ata.trsfsectors,0); SET_EBDA(ata.trsfbytes,0L); - u8 status = inb(iobase1 + ATA_CB_STAT); - if (status & ATA_CB_STAT_BSY) - return 2; - - outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN, iobase2 + ATA_CB_DC); - outb(0x00, iobase1 + ATA_CB_FR); - outb(0x00, iobase1 + ATA_CB_SC); - outb(0x00, iobase1 + ATA_CB_SN); - outb(0xfff0 & 0x00ff, iobase1 + ATA_CB_CL); - outb(0xfff0 >> 8, iobase1 + ATA_CB_CH); - outb(slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0, iobase1 + ATA_CB_DH); - outb(ATA_CMD_PACKET, iobase1 + ATA_CB_CMD); - - // Device should ok to receive command - await_ide(NOT_BSY_DRQ, iobase1, IDE_TIMEOUT); - status = inb(iobase1 + ATA_CB_STAT); - - if (status & ATA_CB_STAT_ERR) { - DEBUGF("ata_cmd_packet : error, status is %02x\n", status); - return 3; - } else if ( !(status & ATA_CB_STAT_DRQ) ) { - DEBUGF("ata_cmd_packet : DRQ not set (status %02x)\n" - , (unsigned) status); - return 4; - } + irq_enable(); // Send command to device - irq_enable(); + outsw_seg(iobase1, GET_SEG(SS), (u32)cmdbuf, cmdlen / 2); - outsw_seg(iobase1, GET_SEG(SS), (u32)cmdbuf, cmdlen); + u8 status; + u16 loops = 0; + for (;;) { + if (loops == 0) {//first time through + status = inb(iobase2 + ATA_CB_ASTAT); + await_ide(NOT_BSY_DRQ, iobase1, IDE_TIMEOUT); + } else + await_ide(NOT_BSY, iobase1, IDE_TIMEOUT); + loops++; - if (inout == ATA_DATA_NO) { - await_ide(NOT_BSY, iobase1, IDE_TIMEOUT); status = inb(iobase1 + ATA_CB_STAT); - } else { - u16 loops = 0; - while (1) { - if (loops == 0) {//first time through - status = inb(iobase2 + ATA_CB_ASTAT); - await_ide(NOT_BSY_DRQ, iobase1, IDE_TIMEOUT); - } else - await_ide(NOT_BSY, iobase1, IDE_TIMEOUT); - loops++; + inb(iobase1 + ATA_CB_SC); - status = inb(iobase1 + ATA_CB_STAT); - inb(iobase1 + ATA_CB_SC); + // Check if command completed + if(((inb(iobase1 + ATA_CB_SC)&0x7)==0x3) && + ((status & (ATA_CB_STAT_RDY | ATA_CB_STAT_ERR)) == ATA_CB_STAT_RDY)) + break; - // Check if command completed - if(((inb(iobase1 + ATA_CB_SC)&0x7)==0x3) && - ((status & (ATA_CB_STAT_RDY | ATA_CB_STAT_ERR)) == ATA_CB_STAT_RDY)) - break; + if (status & ATA_CB_STAT_ERR) { + DEBUGF("ata_cmd_packet : error (status %02x)\n", status); + return 3; + } - if (status & ATA_CB_STAT_ERR) { - DEBUGF("ata_cmd_packet : error (status %02x)\n", status); - return 3; - } + // Normalize address + bufseg += (bufoff / 16); + bufoff %= 16; - // Normalize address - bufseg += (bufoff / 16); - bufoff %= 16; - - // Get the byte count - u16 lcount = (((u16)(inb(iobase1 + ATA_CB_CH))<<8) - + inb(iobase1 + ATA_CB_CL)); - - // adjust to read what we want - u16 lbefore, lafter; - if (header > lcount) { - lbefore=lcount; - header-=lcount; - lcount=0; - } else { - lbefore=header; - header=0; - lcount-=lbefore; - } + // Get the byte count + u16 lcount = (((u16)(inb(iobase1 + ATA_CB_CH))<<8) + + inb(iobase1 + ATA_CB_CL)); - if (lcount > length) { - lafter=lcount-length; - lcount=length; - length=0; - } else { - lafter=0; - length-=lcount; - } + // adjust to read what we want + u16 lbefore, lafter; + if (header > lcount) { + lbefore=lcount; + header-=lcount; + lcount=0; + } else { + lbefore=header; + header=0; + lcount-=lbefore; + } - // Save byte count - u16 count = lcount; + if (lcount > length) { + lafter=lcount-length; + lcount=length; + length=0; + } else { + lafter=0; + length-=lcount; + } - DEBUGF("Trying to read %04x bytes (%04x %04x %04x) " - , lbefore+lcount+lafter, lbefore, lcount, lafter); - DEBUGF("to 0x%04x:0x%04x\n", bufseg, bufoff); + // Save byte count + u16 count = lcount; - // If counts not dividable by 4, use 16bits mode - u8 lmode = mode; - if (lbefore & 0x03) lmode=ATA_MODE_PIO16; - if (lcount & 0x03) lmode=ATA_MODE_PIO16; - if (lafter & 0x03) lmode=ATA_MODE_PIO16; + DEBUGF("Trying to read %04x bytes (%04x %04x %04x) " + , lbefore+lcount+lafter, lbefore, lcount, lafter); + DEBUGF("to 0x%04x:0x%04x\n", bufseg, bufoff); - // adds an extra byte if count are odd. before is always even - if (lcount & 0x01) { - lcount+=1; - if ((lafter > 0) && (lafter & 0x01)) { - lafter-=1; - } - } + // If counts not dividable by 4, use 16bits mode + u8 lmode = mode; + if (lbefore & 0x03) lmode=ATA_MODE_PIO16; + if (lcount & 0x03) lmode=ATA_MODE_PIO16; + if (lafter & 0x03) lmode=ATA_MODE_PIO16; - if (lmode == ATA_MODE_PIO32) { - lcount>>=2; lbefore>>=2; lafter>>=2; - } else { - lcount>>=1; lbefore>>=1; lafter>>=1; + // adds an extra byte if count are odd. before is always even + if (lcount & 0x01) { + lcount+=1; + if ((lafter > 0) && (lafter & 0x01)) { + lafter-=1; } + } - int i; - for (i=0; i<lbefore; i++) - if (lmode == ATA_MODE_PIO32) - inl(iobase1); - else - inw(iobase1); + if (lmode == ATA_MODE_PIO32) { + lcount>>=2; lbefore>>=2; lafter>>=2; + } else { + lcount>>=1; lbefore>>=1; lafter>>=1; + } + int i; + for (i=0; i<lbefore; i++) if (lmode == ATA_MODE_PIO32) - insl_seg(iobase1, bufseg, bufoff, lcount); + inl(iobase1); else - insw_seg(iobase1, bufseg, bufoff, lcount); + inw(iobase1); - for (i=0; i<lafter; i++) - if (lmode == ATA_MODE_PIO32) - inl(iobase1); - else - inw(iobase1); + if (lmode == ATA_MODE_PIO32) + insl_seg(iobase1, bufseg, bufoff, lcount); + else + insw_seg(iobase1, bufseg, bufoff, lcount); - // Compute new buffer address - bufoff += count; + for (i=0; i<lafter; i++) + if (lmode == ATA_MODE_PIO32) + inl(iobase1); + else + inw(iobase1); - // Save transferred bytes count - SET_EBDA(ata.trsfsectors, loops); - } + // Compute new buffer address + bufoff += count; + + // Save transferred bytes count + SET_EBDA(ata.trsfsectors, loops); } // Final check, device must be ready @@ -461,8 +441,8 @@ ata_cmd_packet(u16 device, u8 *cmdbuf, u8 cmdlen, u16 header return 0; } -u16 -cdrom_read(u16 device, u32 lba, u32 count, u16 segment, u16 offset, u16 skip) +int +cdrom_read(u16 biosid, u32 lba, u32 count, u16 segment, u16 offset, u16 skip) { u16 sectors = (count + 2048 - 1) / 2048; @@ -476,9 +456,8 @@ cdrom_read(u16 device, u32 lba, u32 count, u16 segment, u16 offset, u16 skip) atacmd[4]=(lba & 0x0000ff00) >> 8; atacmd[5]=(lba & 0x000000ff); - return ata_cmd_packet(device, atacmd, sizeof(atacmd) - , skip, count, ATA_DATA_IN - , segment, offset); + return ata_cmd_packet(biosid, atacmd, sizeof(atacmd) + , skip, count, segment, offset); } // --------------------------------------------------------------------------- @@ -587,9 +566,9 @@ ata_detect() SET_EBDA(ata.devices[device].device,ATA_DEVICE_HD); SET_EBDA(ata.devices[device].mode, ATA_MODE_PIO16); - u16 ret = ata_cmd_data(device,ATA_CMD_IDENTIFY_DEVICE - , 1, 0, 0, 0, 0L - , GET_SEG(SS), (u32)buffer); + u16 ret = ata_cmd_data_chs(device, ATA_CMD_IDENTIFY_DEVICE + , 0, 0, 1, 1 + , GET_SEG(SS), (u32)buffer); if (ret) BX_PANIC("ata-detect: Failed to detect ATA device\n"); @@ -691,9 +670,9 @@ ata_detect() SET_EBDA(ata.devices[device].device,ATA_DEVICE_CDROM); SET_EBDA(ata.devices[device].mode, ATA_MODE_PIO16); - u16 ret = ata_cmd_data(device,ATA_CMD_IDENTIFY_DEVICE_PACKET - , 1, 0, 0, 0, 0L - , GET_SEG(SS), (u32)buffer); + u16 ret = ata_cmd_data_chs(device, ATA_CMD_IDENTIFY_DEVICE_PACKET + , 0, 0, 1, 1 + , GET_SEG(SS), (u32)buffer); if (ret != 0) BX_PANIC("ata-detect: Failed to detect ATAPI device\n"); @@ -9,152 +9,87 @@ #define __ATA_H #include "types.h" // u16 +#include "atabits.h" + +struct ata_pio_command { + u16 segment; + u16 offset; + u8 biosid; + + u8 feature; + u8 sector_count; + u8 lba_low; + u8 lba_mid; + u8 lba_high; + u8 device; + u8 command; + + u8 sector_count2; + u8 lba_low2; + u8 lba_mid2; + u8 lba_high2; +}; // Function definitions void ata_reset(u16 device); -u16 ata_cmd_data(u16 device, u16 command, u16 count, u16 cylinder - , u16 head, u16 sector, u32 lba, u16 segment, u16 offset); -u16 ata_cmd_packet(u16 device, u8 *cmdbuf, u8 cmdlen, u16 header - , u32 length, u8 inout, u16 bufseg, u16 bufoff); -u16 cdrom_read(u16 device, u32 lba, u32 count +int ata_transfer(struct ata_pio_command *cmd); +int ata_cmd_packet(u16 device, u8 *cmdbuf, u8 cmdlen + , u16 header, u32 length, u16 bufseg, u16 bufoff); +int cdrom_read(u16 device, u32 lba, u32 count , u16 segment, u16 offset, u16 skip); void ata_detect(); -// Global defines -- ATA register and register bits. -// command block & control block regs -#define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0 -#define ATA_CB_ERR 1 // error in pio_base_addr1+1 -#define ATA_CB_FR 1 // feature reg out pio_base_addr1+1 -#define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2 -#define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3 -#define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4 -#define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5 -#define ATA_CB_DH 6 // device head in/out pio_base_addr1+6 -#define ATA_CB_STAT 7 // primary status in pio_base_addr1+7 -#define ATA_CB_CMD 7 // command out pio_base_addr1+7 -#define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6 -#define ATA_CB_DC 6 // device control out pio_base_addr2+6 -#define ATA_CB_DA 7 // device address in pio_base_addr2+7 - -#define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC -#define ATA_CB_ER_BBK 0x80 // ATA bad block -#define ATA_CB_ER_UNC 0x40 // ATA uncorrected error -#define ATA_CB_ER_MC 0x20 // ATA media change -#define ATA_CB_ER_IDNF 0x10 // ATA id not found -#define ATA_CB_ER_MCR 0x08 // ATA media change request -#define ATA_CB_ER_ABRT 0x04 // ATA command aborted -#define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found -#define ATA_CB_ER_NDAM 0x01 // ATA address mark not found - -#define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask) -#define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request -#define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort -#define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media -#define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication - -// ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC) -#define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask) -#define ATA_CB_SC_P_REL 0x04 // ATAPI release -#define ATA_CB_SC_P_IO 0x02 // ATAPI I/O -#define ATA_CB_SC_P_CD 0x01 // ATAPI C/D - -// bits 7-4 of the device/head (CB_DH) reg -#define ATA_CB_DH_DEV0 0xa0 // select device 0 -#define ATA_CB_DH_DEV1 0xb0 // select device 1 -#define ATA_CB_DH_LBA 0x40 // use LBA - -// status reg (CB_STAT and CB_ASTAT) bits -#define ATA_CB_STAT_BSY 0x80 // busy -#define ATA_CB_STAT_RDY 0x40 // ready -#define ATA_CB_STAT_DF 0x20 // device fault -#define ATA_CB_STAT_WFT 0x20 // write fault (old name) -#define ATA_CB_STAT_SKC 0x10 // seek complete -#define ATA_CB_STAT_SERV 0x10 // service -#define ATA_CB_STAT_DRQ 0x08 // data request -#define ATA_CB_STAT_CORR 0x04 // corrected -#define ATA_CB_STAT_IDX 0x02 // index -#define ATA_CB_STAT_ERR 0x01 // error (ATA) -#define ATA_CB_STAT_CHK 0x01 // check (ATAPI) - -// device control reg (CB_DC) bits -#define ATA_CB_DC_HD15 0x08 // bit should always be set to one -#define ATA_CB_DC_SRST 0x04 // soft reset -#define ATA_CB_DC_NIEN 0x02 // disable interrupts - -// Most mandtory and optional ATA commands (from ATA-3), -#define ATA_CMD_CFA_ERASE_SECTORS 0xC0 -#define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03 -#define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87 -#define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD -#define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38 -#define ATA_CMD_CHECK_POWER_MODE1 0xE5 -#define ATA_CMD_CHECK_POWER_MODE2 0x98 -#define ATA_CMD_DEVICE_RESET 0x08 -#define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90 -#define ATA_CMD_FLUSH_CACHE 0xE7 -#define ATA_CMD_FORMAT_TRACK 0x50 -#define ATA_CMD_IDENTIFY_DEVICE 0xEC -#define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1 -#define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1 -#define ATA_CMD_IDLE1 0xE3 -#define ATA_CMD_IDLE2 0x97 -#define ATA_CMD_IDLE_IMMEDIATE1 0xE1 -#define ATA_CMD_IDLE_IMMEDIATE2 0x95 -#define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91 -#define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91 -#define ATA_CMD_NOP 0x00 -#define ATA_CMD_PACKET 0xA0 -#define ATA_CMD_READ_BUFFER 0xE4 -#define ATA_CMD_READ_DMA 0xC8 -#define ATA_CMD_READ_DMA_QUEUED 0xC7 -#define ATA_CMD_READ_MULTIPLE 0xC4 -#define ATA_CMD_READ_SECTORS 0x20 -#define ATA_CMD_READ_VERIFY_SECTORS 0x40 -#define ATA_CMD_RECALIBRATE 0x10 -#define ATA_CMD_REQUEST_SENSE 0x03 -#define ATA_CMD_SEEK 0x70 -#define ATA_CMD_SET_FEATURES 0xEF -#define ATA_CMD_SET_MULTIPLE_MODE 0xC6 -#define ATA_CMD_SLEEP1 0xE6 -#define ATA_CMD_SLEEP2 0x99 -#define ATA_CMD_STANDBY1 0xE2 -#define ATA_CMD_STANDBY2 0x96 -#define ATA_CMD_STANDBY_IMMEDIATE1 0xE0 -#define ATA_CMD_STANDBY_IMMEDIATE2 0x94 -#define ATA_CMD_WRITE_BUFFER 0xE8 -#define ATA_CMD_WRITE_DMA 0xCA -#define ATA_CMD_WRITE_DMA_QUEUED 0xCC -#define ATA_CMD_WRITE_MULTIPLE 0xC5 -#define ATA_CMD_WRITE_SECTORS 0x30 -#define ATA_CMD_WRITE_VERIFY 0x3C - -#define ATA_IFACE_NONE 0x00 -#define ATA_IFACE_ISA 0x00 -#define ATA_IFACE_PCI 0x01 - -#define ATA_TYPE_NONE 0x00 -#define ATA_TYPE_UNKNOWN 0x01 -#define ATA_TYPE_ATA 0x02 -#define ATA_TYPE_ATAPI 0x03 - -#define ATA_DEVICE_NONE 0x00 -#define ATA_DEVICE_HD 0xFF -#define ATA_DEVICE_CDROM 0x05 - -#define ATA_MODE_NONE 0x00 -#define ATA_MODE_PIO16 0x00 -#define ATA_MODE_PIO32 0x01 -#define ATA_MODE_ISADMA 0x02 -#define ATA_MODE_PCIDMA 0x03 -#define ATA_MODE_USEIRQ 0x10 - -#define ATA_TRANSLATION_NONE 0 -#define ATA_TRANSLATION_LBA 1 -#define ATA_TRANSLATION_LARGE 2 -#define ATA_TRANSLATION_RECHS 3 - -#define ATA_DATA_NO 0x00 -#define ATA_DATA_IN 0x01 -#define ATA_DATA_OUT 0x02 +static inline int +ata_cmd_data(u16 biosid, u16 command, u32 lba, u16 count + , u16 segment, u16 offset) +{ + u8 slave = biosid % 2; + + struct ata_pio_command cmd; + cmd.biosid = biosid; + cmd.segment = segment; + cmd.offset = offset; + + if (count >= (1<<8) || lba + count >= (1<<28)) { + cmd.sector_count2 = count >> 8; + cmd.lba_low2 = lba >> 24; + cmd.lba_mid2 = 0; + cmd.lba_high2 = 0; + + command |= 0x04; + lba &= 0xffffff; + } + + cmd.feature = 0; + cmd.sector_count = count; + cmd.lba_low = lba; + cmd.lba_mid = lba >> 8; + cmd.lba_high = lba >> 16; + cmd.device = ((slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) + | ((lba >> 24) & 0xf) | ATA_CB_DH_LBA); + cmd.command = command; + return ata_transfer(&cmd); +} + +static inline int +ata_cmd_data_chs(u16 biosid, u16 command, u16 cyl, u16 head, u16 sect, u16 count + , u16 segment, u16 offset) +{ + u8 slave = biosid % 2; + + struct ata_pio_command cmd; + cmd.biosid = biosid; + cmd.segment = segment; + cmd.offset = offset; + + cmd.sector_count = count & 0xff; + cmd.feature = 0; + cmd.lba_low = sect; + cmd.lba_mid = cyl; + cmd.lba_high = cyl >> 8; + cmd.device = (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (head & 0xff); + cmd.command = command; + return ata_transfer(&cmd); +} #endif /* __ATA_H */ diff --git a/src/atabits.h b/src/atabits.h new file mode 100644 index 0000000..d4ddc15 --- /dev/null +++ b/src/atabits.h @@ -0,0 +1,136 @@ +// Global defines -- ATA register and register bits. +// command block & control block regs +#define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0 +#define ATA_CB_ERR 1 // error in pio_base_addr1+1 +#define ATA_CB_FR 1 // feature reg out pio_base_addr1+1 +#define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2 +#define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3 +#define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4 +#define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5 +#define ATA_CB_DH 6 // device head in/out pio_base_addr1+6 +#define ATA_CB_STAT 7 // primary status in pio_base_addr1+7 +#define ATA_CB_CMD 7 // command out pio_base_addr1+7 +#define ATA_CB_ASTAT 6 // alternate status in pio_base_addr2+6 +#define ATA_CB_DC 6 // device control out pio_base_addr2+6 +#define ATA_CB_DA 7 // device address in pio_base_addr2+7 + +#define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC +#define ATA_CB_ER_BBK 0x80 // ATA bad block +#define ATA_CB_ER_UNC 0x40 // ATA uncorrected error +#define ATA_CB_ER_MC 0x20 // ATA media change +#define ATA_CB_ER_IDNF 0x10 // ATA id not found +#define ATA_CB_ER_MCR 0x08 // ATA media change request +#define ATA_CB_ER_ABRT 0x04 // ATA command aborted +#define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found +#define ATA_CB_ER_NDAM 0x01 // ATA address mark not found + +#define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask) +#define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request +#define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort +#define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media +#define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication + +// ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC) +#define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask) +#define ATA_CB_SC_P_REL 0x04 // ATAPI release +#define ATA_CB_SC_P_IO 0x02 // ATAPI I/O +#define ATA_CB_SC_P_CD 0x01 // ATAPI C/D + +// bits 7-4 of the device/head (CB_DH) reg +#define ATA_CB_DH_DEV0 0xa0 // select device 0 +#define ATA_CB_DH_DEV1 0xb0 // select device 1 +#define ATA_CB_DH_LBA 0x40 // use LBA + +// status reg (CB_STAT and CB_ASTAT) bits +#define ATA_CB_STAT_BSY 0x80 // busy +#define ATA_CB_STAT_RDY 0x40 // ready +#define ATA_CB_STAT_DF 0x20 // device fault +#define ATA_CB_STAT_WFT 0x20 // write fault (old name) +#define ATA_CB_STAT_SKC 0x10 // seek complete +#define ATA_CB_STAT_SERV 0x10 // service +#define ATA_CB_STAT_DRQ 0x08 // data request +#define ATA_CB_STAT_CORR 0x04 // corrected +#define ATA_CB_STAT_IDX 0x02 // index +#define ATA_CB_STAT_ERR 0x01 // error (ATA) +#define ATA_CB_STAT_CHK 0x01 // check (ATAPI) + +// device control reg (CB_DC) bits +#define ATA_CB_DC_HD15 0x08 // bit should always be set to one +#define ATA_CB_DC_SRST 0x04 // soft reset +#define ATA_CB_DC_NIEN 0x02 // disable interrupts + +// Most mandtory and optional ATA commands (from ATA-3), +#define ATA_CMD_CFA_ERASE_SECTORS 0xC0 +#define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03 +#define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87 +#define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD +#define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38 +#define ATA_CMD_CHECK_POWER_MODE1 0xE5 +#define ATA_CMD_CHECK_POWER_MODE2 0x98 +#define ATA_CMD_DEVICE_RESET 0x08 +#define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90 +#define ATA_CMD_FLUSH_CACHE 0xE7 +#define ATA_CMD_FORMAT_TRACK 0x50 +#define ATA_CMD_IDENTIFY_DEVICE 0xEC +#define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1 +#define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1 +#define ATA_CMD_IDLE1 0xE3 +#define ATA_CMD_IDLE2 0x97 +#define ATA_CMD_IDLE_IMMEDIATE1 0xE1 +#define ATA_CMD_IDLE_IMMEDIATE2 0x95 +#define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91 +#define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91 +#define ATA_CMD_NOP 0x00 +#define ATA_CMD_PACKET 0xA0 +#define ATA_CMD_READ_BUFFER 0xE4 +#define ATA_CMD_READ_DMA 0xC8 +#define ATA_CMD_READ_DMA_QUEUED 0xC7 +#define ATA_CMD_READ_MULTIPLE 0xC4 +#define ATA_CMD_READ_SECTORS 0x20 +#define ATA_CMD_READ_VERIFY_SECTORS 0x40 +#define ATA_CMD_RECALIBRATE 0x10 +#define ATA_CMD_REQUEST_SENSE 0x03 +#define ATA_CMD_SEEK 0x70 +#define ATA_CMD_SET_FEATURES 0xEF +#define ATA_CMD_SET_MULTIPLE_MODE 0xC6 +#define ATA_CMD_SLEEP1 0xE6 +#define ATA_CMD_SLEEP2 0x99 +#define ATA_CMD_STANDBY1 0xE2 +#define ATA_CMD_STANDBY2 0x96 +#define ATA_CMD_STANDBY_IMMEDIATE1 0xE0 +#define ATA_CMD_STANDBY_IMMEDIATE2 0x94 +#define ATA_CMD_WRITE_BUFFER 0xE8 +#define ATA_CMD_WRITE_DMA 0xCA +#define ATA_CMD_WRITE_DMA_QUEUED 0xCC +#define ATA_CMD_WRITE_MULTIPLE 0xC5 +#define ATA_CMD_WRITE_SECTORS 0x30 +#define ATA_CMD_WRITE_VERIFY 0x3C + +#define ATA_IFACE_NONE 0x00 +#define ATA_IFACE_ISA 0x00 +#define ATA_IFACE_PCI 0x01 + +#define ATA_TYPE_NONE 0x00 +#define ATA_TYPE_UNKNOWN 0x01 +#define ATA_TYPE_ATA 0x02 +#define ATA_TYPE_ATAPI 0x03 + +#define ATA_DEVICE_NONE 0x00 +#define ATA_DEVICE_HD 0xFF +#define ATA_DEVICE_CDROM 0x05 + +#define ATA_MODE_NONE 0x00 +#define ATA_MODE_PIO16 0x00 +#define ATA_MODE_PIO32 0x01 +#define ATA_MODE_ISADMA 0x02 +#define ATA_MODE_PCIDMA 0x03 +#define ATA_MODE_USEIRQ 0x10 + +#define ATA_TRANSLATION_NONE 0 +#define ATA_TRANSLATION_LBA 1 +#define ATA_TRANSLATION_LARGE 2 +#define ATA_TRANSLATION_RECHS 3 + +#define ATA_DATA_NO 0x00 +#define ATA_DATA_IN 0x01 +#define ATA_DATA_OUT 0x02 @@ -44,7 +44,7 @@ basic_access(struct bregs *regs, u8 device, u16 command) u16 sector = regs->cl & 0x3f; u16 head = regs->dh; - if ((count > 128) || (count == 0) || (sector == 0)) { + if (count > 128 || count == 0 || sector == 0) { BX_INFO("int13_harddisk: function %02x, parameter out of range!\n" , regs->ah); disk_ret(regs, DISK_RET_EPARAM); @@ -58,7 +58,7 @@ basic_access(struct bregs *regs, u8 device, u16 command) u16 npspt = GET_EBDA(ata.devices[device].pchs.spt); // sanity check on cyl heads, sec - if ( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) { + if (cylinder >= nlc || head >= nlh || sector > nlspt) { BX_INFO("int13_harddisk: function %02x, parameters out of" " range %04x/%04x/%04x!\n" , regs->ah, cylinder, head, sector); @@ -66,14 +66,6 @@ basic_access(struct bregs *regs, u8 device, u16 command) return; } - u32 lba = 0; - // if needed, translate lchs to lba, and execute command - if ( (nph != nlh) || (npspt != nlspt)) { - lba = (((((u32)cylinder * (u32)nlh) + (u32)head) * (u32)nlspt) - + (u32)sector - 1); - sector = 0; // this forces the command to be lba - } - if (!command) { // If verify or seek disk_ret(regs, DISK_RET_SUCCESS); @@ -83,9 +75,19 @@ basic_access(struct bregs *regs, u8 device, u16 command) u16 segment = regs->es; u16 offset = regs->bx; - u8 status = ata_cmd_data(device, command - , count, cylinder, head, sector - , lba, segment, offset); + u8 status; + u32 lba; + if (nph != nlh || npspt != nlspt) { + // translate lchs to lba + lba = (((((u32)cylinder * (u32)nlh) + (u32)head) * (u32)nlspt) + + (u32)sector - 1); + status = ata_cmd_data(device, command, lba, count, segment, offset); + } else { + // XXX - see if lba access can always be used. + status = ata_cmd_data_chs(device, command + , cylinder, head, sector + , count, segment, offset); + } // Set nb of sector transferred regs->al = GET_EBDA(ata.trsfsectors); @@ -188,9 +190,7 @@ extended_access(struct bregs *regs, u8 device, u16 command) u8 status; if (type == ATA_TYPE_ATA) - status = ata_cmd_data(device, command - , count, 0, 0, 0 - , lba, segment, offset); + status = ata_cmd_data(device, command, lba, count, segment, offset); else status = cdrom_read(device, lba, count*2048, segment, offset, 0); |