From 1f2256ec81ace90396002fe965d9eea6462f3bcf Mon Sep 17 00:00:00 2001 From: dingusdev <52434309+dingusdev@users.noreply.github.com> Date: Thu, 22 Aug 2024 20:42:43 -0700 Subject: [PATCH] Additional ATA commands Mostly from Wack0's NT4 fork. Co-Authored-By: Rairii <2650838+Wack0@users.noreply.github.com> --- devices/common/ata/atahd.cpp | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/devices/common/ata/atahd.cpp b/devices/common/ata/atahd.cpp index 95f226f..ffc7896 100644 --- a/devices/common/ata/atahd.cpp +++ b/devices/common/ata/atahd.cpp @@ -85,6 +85,9 @@ int AtaHardDisk::perform_command() { switch (this->r_command) { case NOP: break; + case ATAPI_SOFT_RESET: // for ATA devices, is a no-op + this->r_status &= ~BSY; + break; case RECALIBRATE: // is optional in ATA-3; disappeared in >= ATA-4 // OF 3.1.1 won't boot off the drive that reports error for this command this->r_cylinder_hi = 0; @@ -94,25 +97,48 @@ int AtaHardDisk::perform_command() { this->r_status &= ~BSY; this->update_intrq(1); break; + case READ_MULTIPLE: case READ_SECTOR: case READ_SECTOR_NR: { uint16_t sec_count = this->r_sect_count ? this->r_sect_count : 256; int xfer_size = sec_count * ATA_HD_SEC_SIZE; uint64_t offset = this->get_lba() * ATA_HD_SEC_SIZE; + uint32_t ints_size = ATA_HD_SEC_SIZE; + if (this->r_command == READ_MULTIPLE) { + if (this->multiple_sector_count == 0) { + LOG_F(ERROR, "%s: READ MULTIPLE with SET MULTIPLE==0", this->name.c_str()); + this->r_status |= ERR; + this->r_status &= ~BSY; + break; + } + ints_size *= this->multiple_sector_count; + } hdd_img.read(buffer, offset, xfer_size); this->data_ptr = (uint16_t *)this->buffer; // those commands should generate IRQ for each sector - this->prepare_xfer(xfer_size, ATA_HD_SEC_SIZE); + this->prepare_xfer(xfer_size, ints_size); this->signal_data_ready(); } break; + case WRITE_MULTIPLE: case WRITE_SECTOR: case WRITE_SECTOR_NR: { uint16_t sec_count = this->r_sect_count ? this->r_sect_count : 256; this->cur_fpos = this->get_lba() * ATA_HD_SEC_SIZE; this->data_ptr = (uint16_t *)this->buffer; this->cur_data_ptr = this->data_ptr; - this->prepare_xfer(sec_count * ATA_HD_SEC_SIZE, ATA_HD_SEC_SIZE); + uint32_t xfer_size = sec_count * ATA_HD_SEC_SIZE; + uint32_t ints_size = ATA_HD_SEC_SIZE; + if (this->r_command == WRITE_MULTIPLE) { + if (this->multiple_sector_count == 0) { + LOG_F(ERROR, "%s: WRITE MULTIPLE with SET MULTIPLE==0", this->name.c_str()); + this->r_status |= ERR; + this->r_status &= ~BSY; + break; + } + ints_size *= this->multiple_sector_count; + } + this->prepare_xfer(xfer_size, ints_size); this->post_xfer_action = [this]() { this->hdd_img.write(this->data_ptr, this->cur_fpos, this->chunk_size); this->cur_fpos += this->chunk_size; @@ -127,6 +153,11 @@ int AtaHardDisk::perform_command() { this->r_status &= ~BSY; this->update_intrq(1); break; + case READ_VERIFY: + // verify sectors are readable, just no-op + this->r_status &= ~BSY; + this->update_intrq(1); + break; case INIT_DEV_PARAM: // update fictive disk geometry with parameters from host this->sectors = this->r_sect_count;