From: Kyle Hale Date: Tue, 7 Jan 2014 23:31:45 +0000 (-0600) Subject: Added ATA PIO write, other ide cleanup X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=commitdiff_plain;h=a71d971190b236cdd56f7a4003d78d4839466077 Added ATA PIO write, other ide cleanup --- diff --git a/palacios/src/devices/ata.h b/palacios/src/devices/ata.h index 49637c1..0f9c8df 100644 --- a/palacios/src/devices/ata.h +++ b/palacios/src/devices/ata.h @@ -17,6 +17,9 @@ * redistribute, and modify it as specified in the file "V3VEE_LICENSE". */ +#ifndef _DEVICES_ATA_H_ +#define _DEVICES_ATA_H_ + #define MAX_MULT_SECTORS 255 @@ -127,6 +130,7 @@ static int ata_read(struct ide_internal * ide, struct ide_channel * channel, uin } + static int ata_write(struct ide_internal * ide, struct ide_channel * channel, uint8_t * src, uint_t sect_cnt) { struct ide_drive * drive = get_selected_drive(channel); @@ -182,6 +186,34 @@ static int ata_get_lba(struct ide_internal * ide, struct ide_channel * channel, // 28 bit LBA +static int ata_write_sectors(struct ide_internal * ide, struct ide_channel * channel) { + struct ide_drive * drive = get_selected_drive(channel); + uint32_t sect_cnt = (drive->sector_count == 0) ? 256 : drive->sector_count; + + if (ata_get_lba(ide, channel, &(drive->current_lba)) == -1) { + ide_abort_command(ide, channel); + return 0; + } + + drive->transfer_length = sect_cnt * HD_SECTOR_SIZE; + drive->transfer_index = 0; + channel->status.busy = 0; + channel->status.ready = 0; + channel->status.write_fault = 0; + channel->status.data_req = 1; + channel->status.error = 0; + + drive->irq_flags.io_dir = 1; + drive->irq_flags.c_d = 0; + drive->irq_flags.rel = 0; + + PrintDebug(VM_NONE, VCORE_NONE, "IDE: Returning from write sectors\n"); + + return 0; +} + + +// 28 bit LBA static int ata_read_sectors(struct ide_internal * ide, struct ide_channel * channel) { struct ide_drive * drive = get_selected_drive(channel); // The if the sector count == 0 then read 256 sectors (cast up to handle that value) @@ -230,3 +262,5 @@ static int ata_read_sectors_ext(struct ide_internal * ide, struct ide_channel * return -1; } + +#endif diff --git a/palacios/src/devices/atapi.h b/palacios/src/devices/atapi.h index f202d6d..7667e97 100644 --- a/palacios/src/devices/atapi.h +++ b/palacios/src/devices/atapi.h @@ -17,11 +17,91 @@ * redistribute, and modify it as specified in the file "V3VEE_LICENSE". */ +#ifndef __DEVICES_ATAPI_H__ +#define __DEVICES_ATAPI_H__ + #define ATAPI_PACKET_SIZE 12 #include "atapi-types.h" +/* ACS-2 T13/2015-D Table B.2 Command codes */ +#define ATAPI_NOP 0x00 +#define CFA_REQ_EXT_ERROR_CODE 0x03 +#define ATAPI_DSM 0x06 +#define ATAPI_DEVICE_RESET 0x08 +#define ATAPI_RECAL 0x10 +#define ATAPI_READ 0x20 +#define ATAPI_READ_ONCE 0x21 +#define ATAPI_READ_EXT 0x24 +#define ATAPI_READDMA_EXT 0x25 +#define ATAPI_READDMA_QUEUED_EXT 0x26 +#define ATAPI_READ_NATIVE_MAX_EXT 0x27 +#define ATAPI_MULTREAD_EXT 0x29 +#define ATAPI_WRITE 0x30 +#define ATAPI_WRITE_ONCE 0x31 +#define ATAPI_WRITE_EXT 0x34 +#define ATAPI_WRITEDMA_EXT 0x35 +#define ATAPI_WRITEDMA_QUEUED_EXT 0x36 +#define ATAPI_SET_MAX_EXT 0x37 +#define ATAPI_SET_MAX_EXT 0x37 +#define CFA_WRITE_SECT_WO_ERASE 0x38 +#define ATAPI_MULTWRITE_EXT 0x39 +#define ATAPI_WRITE_VERIFY 0x3C +#define ATAPI_VERIFY 0x40 +#define ATAPI_VERIFY_ONCE 0x41 +#define ATAPI_VERIFY_EXT 0x42 +#define ATAPI_SEEK 0x70 +#define CFA_TRANSLATE_SECTOR 0x87 +#define ATAPI_DIAGNOSE 0x90 +#define ATAPI_SPECIFY 0x91 +#define ATAPI_DOWNLOAD_MICROCODE 0x92 +#define ATAPI_STANDBYNOW2 0x94 +#define ATAPI_IDLEIMMEDIATE2 0x95 +#define ATAPI_STANDBY2 0x96 +#define ATAPI_SETIDLE2 0x97 +#define ATAPI_CHECKPOWERMODE2 0x98 +#define ATAPI_SLEEPNOW2 0x99 +#define ATAPI_PACKETCMD 0xA0 +#define ATAPI_PIDENTIFY 0xA1 +#define ATAPI_QUEUED_SERVICE 0xA2 +#define ATAPI_SMART 0xB0 +#define CFA_ACCESS_METADATA_STORAGE 0xB8 +#define CFA_ERASE_SECTORS 0xC0 +#define ATAPI_MULTREAD 0xC4 +#define ATAPI_MULTWRITE 0xC5 +#define ATAPI_SETMULT 0xC6 +#define ATAPI_READDMA 0xC8 +#define ATAPI_READDMA_ONCE 0xC9 +#define ATAPI_WRITEDMA 0xCA +#define ATAPI_WRITEDMA_ONCE 0xCB +#define ATAPI_WRITEDMA_QUEUED 0xCC +#define CFA_WRITE_MULTI_WO_ERASE 0xCD +#define ATAPI_GETMEDIASTATUS 0xDA +#define ATAPI_DOORLOCK 0xDE +#define ATAPI_DOORUNLOCK 0xDF +#define ATAPI_STANDBYNOW1 0xE0 +#define ATAPI_IDLEIMMEDIATE 0xE1 +#define ATAPI_STANDBY 0xE2 +#define ATAPI_SETIDLE1 0xE3 +#define ATAPI_READ_BUFFER 0xE4 +#define ATAPI_CHECKPOWERMODE1 0xE5 +#define ATAPI_SLEEPNOW1 0xE6 +#define ATAPI_FLUSH_CACHE 0xE7 +#define ATAPI_WRITE_BUFFER 0xE8 +#define ATAPI_FLUSH_CACHE_EXT 0xEA +#define ATAPI_IDENTIFY 0xEC +#define ATAPI_MEDIAEJECT 0xED +#define ATAPI_SETFEATURES 0xEF +#define IBM_SENSE_CONDITION 0xF0 +#define ATAPI_SECURITY_SET_PASS 0xF1 +#define ATAPI_SECURITY_UNLOCK 0xF2 +#define ATAPI_SECURITY_ERASE_PREPARE 0xF3 +#define ATAPI_SECURITY_ERASE_UNIT 0xF4 +#define ATAPI_SECURITY_FREEZE_LOCK 0xF5 +#define CFA_WEAR_LEVEL 0xF5 +#define ATAPI_SECURITY_DISABLE 0xF6 + /* ATAPI sucks... * The OS will write to the cylinder register the number of bytes it wants to read * however the device can change that value @@ -723,3 +803,5 @@ static void atapi_identify_device(struct ide_drive * drive) { /* Disabled until command packet DMA is fixed */ drive_id->dma_ultra = 0x2020; // Ultra_DMA_Mode_5_Selected | Ultra_DMA_Mode_5_Supported; } + +#endif diff --git a/palacios/src/devices/ide.c b/palacios/src/devices/ide.c index e0da650..855549f 100644 --- a/palacios/src/devices/ide.c +++ b/palacios/src/devices/ide.c @@ -808,7 +808,7 @@ static int write_cmd_port(struct guest_info * core, ushort_t port, void * src, u switch (channel->cmd_reg) { - case 0xa1: // ATAPI Identify Device Packet + case ATAPI_PIDENTIFY: // ATAPI Identify Device Packet if (drive->drive_type != BLOCK_CDROM) { drive_reset(drive); @@ -824,7 +824,7 @@ static int write_cmd_port(struct guest_info * core, ushort_t port, void * src, u ide_raise_irq(ide, channel); } break; - case 0xec: // Identify Device + case ATAPI_IDENTIFY: // Identify Device if (drive->drive_type != BLOCK_DISK) { drive_reset(drive); @@ -840,7 +840,7 @@ static int write_cmd_port(struct guest_info * core, ushort_t port, void * src, u } break; - case 0xa0: // ATAPI Command Packet + case ATAPI_PACKETCMD: // ATAPI Command Packet if (drive->drive_type != BLOCK_CDROM) { ide_abort_command(ide, channel); } @@ -852,14 +852,14 @@ static int write_cmd_port(struct guest_info * core, ushort_t port, void * src, u channel->status.data_req = 1; channel->status.error = 0; - // reset the data buffer... + // reset the datxgoto-la buffer... drive->transfer_length = ATAPI_PACKET_SIZE; drive->transfer_index = 0; break; - case 0x20: // Read Sectors with Retry - case 0x21: // Read Sectors without Retry + case ATAPI_READ: // Read Sectors with Retry + case ATAPI_READ_ONCE: // Read Sectors without Retry drive->hd_state.cur_sector_num = 1; if (ata_read_sectors(ide, channel) == -1) { @@ -868,7 +868,7 @@ static int write_cmd_port(struct guest_info * core, ushort_t port, void * src, u } break; - case 0x24: // Read Sectors Extended + case ATAPI_READ_EXT: // Read Sectors Extended drive->hd_state.cur_sector_num = 1; if (ata_read_sectors_ext(ide, channel) == -1) { @@ -877,8 +877,20 @@ static int write_cmd_port(struct guest_info * core, ushort_t port, void * src, u } break; - case 0xc8: // Read DMA with retry - case 0xc9: { // Read DMA + case ATAPI_WRITE: {// Write Sector + drive->hd_state.cur_sector_num = 1; + + if (ata_write_sectors(ide, channel) == -1) { + PrintError(core->vm_info, core, "Error writing sectors\n"); + return -1; + } + break; + } + + + + case ATAPI_READDMA: // Read DMA with retry + case ATAPI_READDMA_ONCE: { // Read DMA uint32_t sect_cnt = (drive->sector_count == 0) ? 256 : drive->sector_count; if (ata_get_lba(ide, channel, &(drive->current_lba)) == -1) { @@ -901,7 +913,7 @@ static int write_cmd_port(struct guest_info * core, ushort_t port, void * src, u break; } - case 0xca: { // Write DMA + case ATAPI_WRITEDMA: { // Write DMA uint32_t sect_cnt = (drive->sector_count == 0) ? 256 : drive->sector_count; if (ata_get_lba(ide, channel, &(drive->current_lba)) == -1) { @@ -923,22 +935,22 @@ static int write_cmd_port(struct guest_info * core, ushort_t port, void * src, u } break; } - case 0xe0: // Standby Now 1 - case 0xe1: // Set Idle Immediate - case 0xe2: // Standby - case 0xe3: // Set Idle 1 - case 0xe6: // Sleep Now 1 - case 0x94: // Standby Now 2 - case 0x95: // Idle Immediate (CFA) - case 0x96: // Standby 2 - case 0x97: // Set idle 2 - case 0x99: // Sleep Now 2 + case ATAPI_STANDBYNOW1: // Standby Now 1 + case ATAPI_IDLEIMMEDIATE: // Set Idle Immediate + case ATAPI_STANDBY: // Standby + case ATAPI_SETIDLE1: // Set Idle 1 + case ATAPI_SLEEPNOW1: // Sleep Now 1 + case ATAPI_STANDBYNOW2: // Standby Now 2 + case ATAPI_IDLEIMMEDIATE2: // Idle Immediate (CFA) + case ATAPI_STANDBY2: // Standby 2 + case ATAPI_SETIDLE2: // Set idle 2 + case ATAPI_SLEEPNOW2: // Sleep Now 2 channel->status.val = 0; channel->status.ready = 1; ide_raise_irq(ide, channel); break; - case 0xef: // Set Features + case ATAPI_SETFEATURES: // Set Features // Prior to this the features register has been written to. // This command tells the drive to check if the new value is supported (the value is drive specific) // Common is that bit0=DMA enable @@ -955,14 +967,14 @@ static int write_cmd_port(struct guest_info * core, ushort_t port, void * src, u ide_raise_irq(ide, channel); break; - case 0x91: // Initialize Drive Parameters - case 0x10: // recalibrate? + case ATAPI_SPECIFY: // Initialize Drive Parameters + case ATAPI_RECAL: // recalibrate? channel->status.error = 0; channel->status.ready = 1; channel->status.seek_complete = 1; ide_raise_irq(ide, channel); break; - case 0xc6: { // Set multiple mode (IDE Block mode) + case ATAPI_SETMULT: { // Set multiple mode (IDE Block mode) // This makes the drive transfer multiple sectors before generating an interrupt uint32_t tmp_sect_num = drive->sector_num; // GCC SUCKS @@ -985,7 +997,7 @@ static int write_cmd_port(struct guest_info * core, ushort_t port, void * src, u break; } - case 0x08: // Reset Device + case ATAPI_DEVICE_RESET: // Reset Device drive_reset(drive); channel->error_reg.val = 0x01; channel->status.busy = 0; @@ -995,7 +1007,7 @@ static int write_cmd_port(struct guest_info * core, ushort_t port, void * src, u channel->status.error = 0; break; - case 0xe5: // Check power mode + case ATAPI_CHECKPOWERMODE1: // Check power mode drive->sector_count = 0xff; /* 0x00=standby, 0x80=idle, 0xff=active or idle */ channel->status.busy = 0; channel->status.ready = 1; @@ -1004,7 +1016,7 @@ static int write_cmd_port(struct guest_info * core, ushort_t port, void * src, u channel->status.error = 0; break; - case 0xc4: // read multiple sectors + case ATAPI_MULTREAD: // read multiple sectors drive->hd_state.cur_sector_num = drive->hd_state.mult_sector_num; default: PrintError(core->vm_info, core, "Unimplemented IDE command (%x)\n", channel->cmd_reg); @@ -1020,29 +1032,44 @@ static int write_data_port(struct guest_info * core, ushort_t port, void * src, struct ide_channel * channel = get_selected_channel(ide, port); struct ide_drive * drive = get_selected_drive(channel); - // PrintDebug(core->vm_info, core, "IDE: Writing Data Port %x (val=%x, len=%d)\n", - // port, *(uint32_t *)src, length); - + PrintDebug(core->vm_info, core, "IDE: Writing Data Port %x (val=%x, len=%d)\n", + port, *(uint32_t *)src, length); + memcpy(drive->data_buf + drive->transfer_index, src, length); drive->transfer_index += length; // Transfer is complete, dispatch the command if (drive->transfer_index >= drive->transfer_length) { - switch (channel->cmd_reg) { - case 0x30: // Write Sectors - PrintError(core->vm_info, core, "Writing Data not yet implemented\n"); - return -1; - - case 0xa0: // ATAPI packet command - if (atapi_handle_packet(core, ide, channel) == -1) { - PrintError(core->vm_info, core, "Error handling ATAPI packet\n"); - return -1; - } - break; - default: - PrintError(core->vm_info, core, "Unhandld IDE Command %x\n", channel->cmd_reg); - return -1; - } + switch (channel->cmd_reg) { + + case ATAPI_WRITE: // Write Sectors + + channel->status.busy = 1; + channel->status.data_req = 0; + + if (ata_write(ide, channel, drive->data_buf, drive->transfer_length/HD_SECTOR_SIZE) == -1) { + PrintError(core->vm_info, core, "Error writing to disk\n"); + return -1; + } + + PrintDebug(core->vm_info, core, "IDE: Write sectors complete\n"); + + channel->status.error = 0; + channel->status.busy = 0; + + ide_raise_irq(ide, channel); + break; + + case ATAPI_PACKETCMD: // ATAPI packet command + if (atapi_handle_packet(core, ide, channel) == -1) { + PrintError(core->vm_info, core, "Error handling ATAPI packet\n"); + return -1; + } + break; + default: + PrintError(core->vm_info, core, "Unhandld IDE Command %x\n", channel->cmd_reg); + return -1; + } } return length;