// ---------------------------------------------------------------------------
-// ATA/ATAPI driver : execute a data-in command
+// ATA/ATAPI driver : execute a data command
// ---------------------------------------------------------------------------
// returns
// 0 : no error
// 6 : no sectors left to write
// 7 : more sectors to write
u16
-ata_cmd_data_in(u16 device, u16 command, u16 count, u16 cylinder
- , u16 head, u16 sector, u32 lba, u16 segment, u16 offset)
+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_in d=%d cmd=%d count=%d c=%d h=%d s=%d"
+ 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);
status = inb(iobase1 + ATA_CB_STAT);
if (status & ATA_CB_STAT_ERR) {
- DEBUGF("ata_cmd_data_in : read error\n");
+ DEBUGF("ata_cmd_data : read error\n");
return 2;
- } else if ( !(status & ATA_CB_STAT_DRQ) ) {
- DEBUGF("ata_cmd_data_in : DRQ not set (status %02x)\n"
+ }
+ if (!(status & ATA_CB_STAT_DRQ)) {
+ DEBUGF("ata_cmd_data : DRQ not set (status %02x)\n"
, (unsigned) status);
return 3;
}
segment += 0x80;
}
- if (mode == ATA_MODE_PIO32)
- insl_seg(iobase1, segment, offset, 512 / 4);
- else
- insw_seg(iobase1, segment, offset, 512 / 2);
+ if (command == ATA_CMD_WRITE_SECTORS) {
+ // Write data to controller
+ 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
+ if (mode == ATA_MODE_PIO32)
+ insl_seg(iobase1, segment, offset, 512 / 4);
+ else
+ insw_seg(iobase1, segment, offset, 512 / 2);
+ await_ide(NOT_BSY, iobase1, IDE_TIMEOUT);
+ }
offset += 512;
current++;
SET_EBDA(ata.trsfsectors,current);
count--;
- await_ide(NOT_BSY, iobase1, IDE_TIMEOUT);
status = inb(iobase1 + ATA_CB_STAT);
- if (count == 0) {
- if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ
- | ATA_CB_STAT_ERR) )
- != ATA_CB_STAT_RDY ) {
- DEBUGF("ata_cmd_data_in : no sectors left (status %02x)\n"
- , (unsigned) status);
- return 4;
- }
+ if (count == 0)
break;
- }
- else {
- if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ
- | ATA_CB_STAT_ERR) )
- != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
- DEBUGF("ata_cmd_data_in : more sectors left (status %02x)\n"
- , (unsigned) status);
- return 5;
- }
- continue;
+ 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"
+ , (unsigned) status);
+ return 5;
}
}
- // Enable interrupts
- outb(ATA_CB_DC_HD15, iobase2+ATA_CB_DC);
- return 0;
-}
-// ---------------------------------------------------------------------------
-// ATA/ATAPI driver : execute a data-out command
-// ---------------------------------------------------------------------------
- // returns
- // 0 : no error
- // 1 : BUSY bit set
- // 2 : read error
- // 3 : expected DRQ=1
- // 4 : no sectors left to read/verify
- // 5 : more sectors to read/verify
- // 6 : no sectors left to write
- // 7 : more sectors to write
-u16
-ata_cmd_data_out(u16 device, u16 command, u16 count, u16 cylinder
- , u16 head, u16 sector, u32 lba, u16 segment, u16 offset)
-{
- DEBUGF("ata_cmd_data_out 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;
-
- 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;
- }
-
- 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);
-
- await_ide(NOT_BSY_DRQ, iobase1, IDE_TIMEOUT);
- status = inb(iobase1 + ATA_CB_STAT);
-
- if (status & ATA_CB_STAT_ERR) {
- DEBUGF("ata_cmd_data_out : read error\n");
- return 2;
- } else if ( !(status & ATA_CB_STAT_DRQ) ) {
- DEBUGF("ata_cmd_data_out : DRQ not set (status %02x)\n"
+ 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)
+ status &= ~ATA_CB_STAT_DF;
+ if (status != ATA_CB_STAT_RDY ) {
+ DEBUGF("ata_cmd_data : no sectors left (status %02x)\n"
, (unsigned) status);
- return 3;
+ return 4;
}
- // FIXME : move seg/off translation here
-
- irq_enable();
-
- u8 current = 0;
- while (1) {
- if (offset > 0xf800) {
- offset -= 0x800;
- segment += 0x80;
- }
-
- if (mode == ATA_MODE_PIO32)
- outsl_seg(iobase1, segment, offset, 512 / 4);
- else
- outsw_seg(iobase1, segment, offset, 512 / 2);
- offset += 512;
-
- current++;
- SET_EBDA(ata.trsfsectors,current);
- count--;
- status = inb(iobase1 + ATA_CB_STAT);
- if (count == 0) {
- if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF
- | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
- != ATA_CB_STAT_RDY ) {
- DEBUGF("ata_cmd_data_out : no sectors left (status %02x)\n"
- , (unsigned) status);
- return 6;
- }
- break;
- } else {
- if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ
- | ATA_CB_STAT_ERR) )
- != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
- DEBUGF("ata_cmd_data_out : more sectors left (status %02x)\n"
- , (unsigned) status);
- return 7;
- }
- continue;
- }
- }
// Enable interrupts
outb(ATA_CB_DC_HD15, iobase2+ATA_CB_DC);
+ irq_disable();
return 0;
}
SET_EBDA(ata.devices[device].device,ATA_DEVICE_HD);
SET_EBDA(ata.devices[device].mode, ATA_MODE_PIO16);
- u16 ret = ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE
- , 1, 0, 0, 0, 0L
- , GET_SEG(SS), (u32)buffer);
+ u16 ret = ata_cmd_data(device,ATA_CMD_IDENTIFY_DEVICE
+ , 1, 0, 0, 0, 0L
+ , GET_SEG(SS), (u32)buffer);
if (ret)
BX_PANIC("ata-detect: Failed to detect ATA device\n");
SET_EBDA(ata.devices[device].pchs.cylinders, cylinders);
SET_EBDA(ata.devices[device].pchs.spt, spt);
SET_EBDA(ata.devices[device].sectors, sectors);
- BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt);
+ BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation="
+ , channel, slave,cylinders, heads, spt);
translation = inb_cmos(CMOS_BIOS_DISKTRANSFLAG + channel/2);
for (shift=device%4; shift>0; shift--)
SET_EBDA(ata.devices[device].device,ATA_DEVICE_CDROM);
SET_EBDA(ata.devices[device].mode, ATA_MODE_PIO16);
- u16 ret = ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET
- , 1, 0, 0, 0, 0L
- , GET_SEG(SS), (u32)buffer);
+ u16 ret = ata_cmd_data(device,ATA_CMD_IDENTIFY_DEVICE_PACKET
+ , 1, 0, 0, 0, 0L
+ , GET_SEG(SS), (u32)buffer);
if (ret != 0)
BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
sector = 0; // this forces the command to be lba
}
- u16 segment = regs->es;
- u16 offset = regs->bx;
-
- u8 status;
- switch (command) {
- case ATA_CMD_READ_SECTORS:
- status = ata_cmd_data_in(device, ATA_CMD_READ_SECTORS
- , count, cylinder, head, sector
- , lba, segment, offset);
- break;
- case ATA_CMD_WRITE_SECTORS:
- status = ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS
- , count, cylinder, head, sector
- , lba, segment, offset);
- break;
- default:
+ if (!command) {
+ // If verify or seek
disk_ret(regs, DISK_RET_SUCCESS);
return;
}
+ u16 segment = regs->es;
+ u16 offset = regs->bx;
+
+ u8 status = ata_cmd_data(device, command
+ , count, cylinder, head, sector
+ , lba, segment, offset);
+
// Set nb of sector transferred
regs->al = GET_EBDA(ata.trsfsectors);
return;
}
- u8 status;
- switch (command) {
- case ATA_CMD_READ_SECTORS:
- if (type == ATA_TYPE_ATA)
- status = ata_cmd_data_in(device, ATA_CMD_READ_SECTORS
- , count, 0, 0, 0
- , lba, segment, offset);
- else
- status = cdrom_read(device, lba, count*2048, segment, offset, 0);
- break;
- case ATA_CMD_WRITE_SECTORS:
- status = ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS
- , count, 0, 0, 0
- , lba, segment, offset);
- break;
- default:
+ if (!command) {
// If verify or seek
disk_ret(regs, DISK_RET_SUCCESS);
return;
}
+ u8 status;
+ if (type == ATA_TYPE_ATA)
+ status = ata_cmd_data(device, command
+ , count, 0, 0, 0
+ , lba, segment, offset);
+ else
+ status = cdrom_read(device, lba, count*2048, segment, offset, 0);
+
SET_INT13EXT(regs, count, GET_EBDA(ata.trsfsectors));
if (status != 0) {