X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=palacios%2Fsrc%2Fdevices%2Fata.h;h=c6ad4b433c9db90ab6ad3a1ff927c464f4ac4bc5;hb=198151f1d58834ff7889389007232a3d250f51f1;hp=49637c14981b6ff06b839155d87e29e88606775f;hpb=acaadd79c597c8d5180fbfbec79c01fef3dff003;p=palacios.git diff --git a/palacios/src/devices/ata.h b/palacios/src/devices/ata.h index 49637c1..c6ad4b4 100644 --- a/palacios/src/devices/ata.h +++ b/palacios/src/devices/ata.h @@ -17,9 +17,15 @@ * redistribute, and modify it as specified in the file "V3VEE_LICENSE". */ +#ifndef _DEVICES_ATA_H_ +#define _DEVICES_ATA_H_ + #define MAX_MULT_SECTORS 255 + + + static void ata_identify_device(struct ide_drive * drive) { struct ide_drive_id * drive_id = (struct ide_drive_id *)(drive->data_buf); const char* serial_number = " VT00001\0\0\0\0\0\0\0\0\0\0\0\0"; @@ -40,7 +46,6 @@ static void ata_identify_device(struct ide_drive * drive) { drive_id->cdrom_flag = 0; - // Make it the simplest drive possible (1 head, 1 cyl, 1 sect/track) drive_id->num_cylinders = drive->num_cylinders; drive_id->num_heads = drive->num_heads; drive_id->bytes_per_track = drive->num_sectors * HD_SECTOR_SIZE; @@ -53,12 +58,14 @@ static void ata_identify_device(struct ide_drive * drive) { memcpy(drive_id->firmware_rev, firmware, strlen(firmware)); memcpy(drive_id->model_num, drive->model, 40); - // 32 bits access + // 32 bits access for PIO supported drive_id->dword_io = 1; // enable DMA access - drive_id->dma_enable = 1; + // We want guest to assume UDMA5 + // but any DMA model looks the same to the guest + drive_id->dma_enable = 1; // enable LBA access drive_id->lba_enable = 1; @@ -74,7 +81,6 @@ static void ata_identify_device(struct ide_drive * drive) { drive_id->rw_multiples = 0x8000 | MAX_MULT_SECTORS; - // words 64-70, 54-58 valid drive_id->field_valid = 0x0007; // DMA + pkg cmd valid @@ -82,25 +88,39 @@ static void ata_identify_device(struct ide_drive * drive) { // copied from CFA540A // drive_id->buf[63] = 0x0103; // variable (DMA stuff) //drive_id->buf[63] = 0x0000; // variable (DMA stuff) + // 0x0007 => MWDMA modes 0..2 supported - none selected drive_id->buf[63] = 0x0007; - // drive_id->buf[64] = 0x0001; // PIO + // We wll support PIO mode 0 + // Maybe revisit this later to allow advanced modes + // We really want the guest to use DMA + drive_id->buf[64] = 0x0001; // PIO + + // MWDMA transfer min cycle time drive_id->buf[65] = 0x00b4; + // MWDMA transfer time recommended drive_id->buf[66] = 0x00b4; + // minimum pio transfer time without flow control drive_id->buf[67] = 0x012c; + // minimum pio transfer time with IORDY flow control drive_id->buf[68] = 0x00b4; drive_id->buf[71] = 30; // faked drive_id->buf[72] = 30; // faked + // queue depth set to one + // We should not expect queued DMAs + // drive_id->buf[80] = 0x1e; // supports up to ATA/ATAPI-4 drive_id->major_rev_num = 0x0040; // supports up to ATA/ATAPI-6 drive_id->buf[83] |= 0x0400; // supports 48 bit LBA + // No special features supported + // Pretend drive is already autoconfed to UDMA5 drive_id->dma_ultra = 0x2020; // Ultra_DMA_Mode_5_Selected | Ultra_DMA_Mode_5_Supported; } @@ -127,9 +147,16 @@ 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); + if (drive->hd_state.accessed == 0) { + PrintError(VM_NONE,VCORE_NONE,"Reseting lba...\n"); + drive->current_lba = 0; + drive->hd_state.accessed = 1; + } + PrintDebug(VM_NONE, VCORE_NONE,"Writing Drive LBA=%d (count=%d)\n", (uint32_t)(drive->current_lba), sect_cnt); int ret = drive->ops->write(src, drive->current_lba * HD_SECTOR_SIZE, sect_cnt * HD_SECTOR_SIZE, drive->private_data); @@ -143,51 +170,109 @@ static int ata_write(struct ide_internal * ide, struct ide_channel * channel, ui } - -static int ata_get_lba(struct ide_internal * ide, struct ide_channel * channel, uint64_t * lba) { +// +// Grand unified conversion for various addressing modes: +// +// CHS => 64 bit LBA (8 bit sector count) +// LBA28 => 64 bit LBA (8 bit sector count) +// LBA48 => 64 bit LBA (16 bit sector count) +static int ata_get_lba_and_size(struct ide_internal * ide, struct ide_channel * channel, uint64_t * lba, uint64_t *num_sects) { struct ide_drive * drive = get_selected_drive(channel); - // The if the sector count == 0 then read 256 sectors (cast up to handle that value) - uint32_t sect_cnt = (drive->sector_count == 0) ? 256 : drive->sector_count; - - union { - uint32_t addr; - uint8_t buf[4]; - } __attribute__((packed)) lba_addr; - /* LBA addr bits: - 0-8: sector number reg (drive->lba0) - 8-16: low cylinder reg (drive->lba1) - 16-24: high cylinder reg (drive->lba2) - 24-28: low 4 bits of drive_head reg (channel->drive_head.head_num) - */ + if (is_lba48(channel)) { + *num_sects = drive->lba48.sector_count; + *lba = drive->lba48.lba; + PrintDebug(VM_NONE,VCORE_NONE,"get_lba: lba48: lba=%llu, num_sects=%llu\n",*lba,*num_sects); + } else { + // LBA48 or CHS + // The if the sector count == 0 then read 256 sectors (cast up to handle that value) + *num_sects = (drive->sector_count == 0) ? 256 : drive->sector_count; + + if (is_lba28(channel)) { + union { + uint32_t addr; + uint8_t buf[4]; + } __attribute__((packed)) lba_addr; + + /* LBA addr bits: + 0-8: sector number reg (drive->lba0) + 8-16: low cylinder reg (drive->lba1) + 16-24: high cylinder reg (drive->lba2) + 24-28: low 4 bits of drive_head reg (channel->drive_head.head_num) + */ + + + lba_addr.buf[0] = drive->lba0; + lba_addr.buf[1] = drive->lba1; + lba_addr.buf[2] = drive->lba2; + lba_addr.buf[3] = channel->drive_head.lba3; + + *lba = lba_addr.addr; + + PrintDebug(VM_NONE,VCORE_NONE,"get_lba: lba28: lba0=%u (sect), lba1=%u (cyllow), lba2=%u (cylhigh), lba3=%d (head) => lba=%llu numsects=%llu\n", drive->lba0, drive->lba1, drive->lba2, channel->drive_head.lba3, *lba, *num_sects); + + } else { + // we are in CHS mode.... + + *lba = + ((uint64_t)drive->cylinder * drive->num_heads + + channel->drive_head.head_num) * drive->num_sectors + + // sector number is 1 based + (drive->sector_num - 1); + + + PrintDebug(VM_NONE,VCORE_NONE,"get_lba: Huh, 1995 has returned - CHS (%u,%u,%u) addressing on drive of (%u,%u,%u) translated as lba=%llu num_sects=%llu....\n", + drive->cylinder, channel->drive_head.head_num, drive->sector_num, + drive->num_cylinders, drive->num_heads, drive->num_sectors, *lba,*num_sects ); + } + } + + if ((*lba + *num_sects) > + drive->ops->get_capacity(drive->private_data) / HD_SECTOR_SIZE) { + PrintError(VM_NONE, VCORE_NONE,"IDE: request size exceeds disk capacity (lba=%llu) (num_sects=%llu) (ReadEnd=%llu) (capacity=%llu)\n", + *lba, *num_sects, + *lba + (*num_sects * HD_SECTOR_SIZE), + drive->ops->get_capacity(drive->private_data)); + return -1; + } + + return 0; +} - lba_addr.buf[0] = drive->lba0; - lba_addr.buf[1] = drive->lba1; - lba_addr.buf[2] = drive->lba2; - lba_addr.buf[3] = channel->drive_head.lba3; +static int ata_write_sectors(struct ide_internal * ide, struct ide_channel * channel) { + uint64_t sect_cnt; + struct ide_drive * drive = get_selected_drive(channel); - if ((lba_addr.addr + sect_cnt) > - drive->ops->get_capacity(drive->private_data) / HD_SECTOR_SIZE) { - PrintError(VM_NONE, VCORE_NONE,"IDE: request size exceeds disk capacity (lba=%d) (sect_cnt=%d) (ReadEnd=%d) (capacity=%p)\n", - lba_addr.addr, sect_cnt, - lba_addr.addr + (sect_cnt * HD_SECTOR_SIZE), - (void *)(addr_t)(drive->ops->get_capacity(drive->private_data))); - return -1; + if (ata_get_lba_and_size(ide, channel, &(drive->current_lba), §_cnt ) == -1) { + PrintError(VM_NONE,VCORE_NONE,"Cannot get lba+size\n"); + ide_abort_command(ide, channel); + return 0; } - *lba = lba_addr.addr; + PrintDebug(VM_NONE,VCORE_NONE,"ata write sectors: lba=%llu sect_cnt=%llu\n", drive->current_lba, sect_cnt); + + 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; + + PrintDebug(VM_NONE, VCORE_NONE, "IDE: Returning from write sectors\n"); + return 0; } -// 28 bit LBA +// 28 bit LBA or CHS static int ata_read_sectors(struct ide_internal * ide, struct ide_channel * channel) { + uint64_t sect_cnt; struct ide_drive * drive = get_selected_drive(channel); - // The if the sector count == 0 then read 256 sectors (cast up to handle that value) - uint32_t sect_cnt = (drive->sector_count == 0) ? 256 : drive->sector_count; - if (ata_get_lba(ide, channel, &(drive->current_lba)) == -1) { + if (ata_get_lba_and_size(ide, channel, &(drive->current_lba),§_cnt) == -1) { + PrintError(VM_NONE,VCORE_NONE,"Cannot get lba+size\n"); ide_abort_command(ide, channel); return 0; } @@ -207,11 +292,6 @@ static int ata_read_sectors(struct ide_internal * ide, struct ide_channel * cha 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; - - ide_raise_irq(ide, channel); PrintDebug(VM_NONE, VCORE_NONE,"Returning from read sectors\n"); @@ -220,13 +300,82 @@ static int ata_read_sectors(struct ide_internal * ide, struct ide_channel * cha } -// 48 bit LBA -static int ata_read_sectors_ext(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) - //uint32_t sector_count = (drive->sector_count == 0) ? 256 : drive->sector_count; - - PrintError(VM_NONE, VCORE_NONE, "Extended Sector read not implemented\n"); - - return -1; -} +/* ATA COMMANDS as per */ +/* ACS-2 T13/2015-D Table B.2 Command codes */ +#define ATA_NOP 0x00 +#define CFA_REQ_EXT_ERROR_CODE 0x03 +#define ATA_DSM 0x06 +#define ATA_DEVICE_RESET 0x08 +#define ATA_RECAL 0x10 +#define ATA_READ 0x20 +#define ATA_READ_ONCE 0x21 +#define ATA_READ_EXT 0x24 +#define ATA_READDMA_EXT 0x25 +#define ATA_READDMA_QUEUED_EXT 0x26 +#define ATA_READ_NATIVE_MAX_EXT 0x27 +#define ATA_MULTREAD_EXT 0x29 +#define ATA_WRITE 0x30 +#define ATA_WRITE_ONCE 0x31 +#define ATA_WRITE_EXT 0x34 +#define ATA_WRITEDMA_EXT 0x35 +#define ATA_WRITEDMA_QUEUED_EXT 0x36 +#define ATA_SET_MAX_EXT 0x37 +#define ATA_SET_MAX_EXT 0x37 +#define CFA_WRITE_SECT_WO_ERASE 0x38 +#define ATA_MULTWRITE_EXT 0x39 +#define ATA_WRITE_VERIFY 0x3C +#define ATA_VERIFY 0x40 +#define ATA_VERIFY_ONCE 0x41 +#define ATA_VERIFY_EXT 0x42 +#define ATA_SEEK 0x70 +#define CFA_TRANSLATE_SECTOR 0x87 +#define ATA_DIAGNOSE 0x90 +#define ATA_SPECIFY 0x91 +#define ATA_DOWNLOAD_MICROCODE 0x92 +#define ATA_STANDBYNOW2 0x94 +#define ATA_IDLEIMMEDIATE2 0x95 +#define ATA_STANDBY2 0x96 +#define ATA_SETIDLE2 0x97 +#define ATA_CHECKPOWERMODE2 0x98 +#define ATA_SLEEPNOW2 0x99 +#define ATA_PACKETCMD 0xA0 +#define ATA_PIDENTIFY 0xA1 +#define ATA_QUEUED_SERVICE 0xA2 +#define ATA_SMART 0xB0 +#define CFA_ACCESS_METADATA_STORAGE 0xB8 +#define CFA_ERASE_SECTORS 0xC0 +#define ATA_MULTREAD 0xC4 +#define ATA_MULTWRITE 0xC5 +#define ATA_SETMULT 0xC6 +#define ATA_READDMA 0xC8 +#define ATA_READDMA_ONCE 0xC9 +#define ATA_WRITEDMA 0xCA +#define ATA_WRITEDMA_ONCE 0xCB +#define ATA_WRITEDMA_QUEUED 0xCC +#define CFA_WRITE_MULTI_WO_ERASE 0xCD +#define ATA_GETMEDIASTATUS 0xDA +#define ATA_DOORLOCK 0xDE +#define ATA_DOORUNLOCK 0xDF +#define ATA_STANDBYNOW1 0xE0 +#define ATA_IDLEIMMEDIATE 0xE1 +#define ATA_STANDBY 0xE2 +#define ATA_SETIDLE1 0xE3 +#define ATA_READ_BUFFER 0xE4 +#define ATA_CHECKPOWERMODE1 0xE5 +#define ATA_SLEEPNOW1 0xE6 +#define ATA_FLUSH_CACHE 0xE7 +#define ATA_WRITE_BUFFER 0xE8 +#define ATA_FLUSH_CACHE_EXT 0xEA +#define ATA_IDENTIFY 0xEC +#define ATA_MEDIAEJECT 0xED +#define ATA_SETFEATURES 0xEF +#define IBM_SENSE_CONDITION 0xF0 +#define ATA_SECURITY_SET_PASS 0xF1 +#define ATA_SECURITY_UNLOCK 0xF2 +#define ATA_SECURITY_ERASE_PREPARE 0xF3 +#define ATA_SECURITY_ERASE_UNIT 0xF4 +#define ATA_SECURITY_FREEZE_LOCK 0xF5 +#define CFA_WEAR_LEVEL 0xF5 +#define ATA_SECURITY_DISABLE 0xF6 + +#endif