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 | |
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.
-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); |