From 155b8cdad94f3cf2da68fa4d863f0dd7d6f4d413 Mon Sep 17 00:00:00 2001 From: joevt Date: Thu, 28 Mar 2024 04:54:49 -0700 Subject: [PATCH] atahd: Support inexact CHS. The total size needs to have 3 factors cylinders, heads, & sectors. Imagine a disk having a total size with 3 prime factors 3 x 5 x 11. 15 cannot be assigned to heads because that would only leave 11 for sectors and cylinders. Therefore, test all heads and sectors combinations. If the third factor for cylinders is not found, then choose 16 heads, then the minimum number of sectors, and finally the maximum number of cylinders. The loop could be changed to skip values of heads that are not a factor, but it doesn't take any time to try them all. --- devices/common/ata/atahd.cpp | 63 ++++++++++++++++++------------------ devices/common/ata/atahd.h | 4 ++- 2 files changed, 35 insertions(+), 32 deletions(-) diff --git a/devices/common/ata/atahd.cpp b/devices/common/ata/atahd.cpp index 131c6d8..b5f462d 100644 --- a/devices/common/ata/atahd.cpp +++ b/devices/common/ata/atahd.cpp @@ -209,50 +209,51 @@ uint64_t AtaHardDisk::get_lba() { } void AtaHardDisk::calc_chs_params() { - unsigned num_blocks, heads, sectors, max_sectors; + unsigned num_blocks, heads, sectors, max_sectors, cylinders, max_cylinders; LOG_F(INFO, "%s: total sectors %d", this->name.c_str(), this->total_sectors); + if (this->total_sectors >= REAL_CHS_LIMIT) { + heads = 16; + sectors = 255; + cylinders = 65535; + LOG_F(WARNING, "%s: exceeds max CHS translation", + this->name.c_str()); + goto done; + } + // use PC BIOS limit to keep number of sectors small for smaller disks - if (this->total_sectors >= ATA_BIOS_LIMIT) + if (this->total_sectors >= ATA_BIOS_LIMIT) { max_sectors = 255; - else + max_cylinders = 65535; + } else { max_sectors = 63; + max_cylinders = 16383; + } num_blocks = this->total_sectors; for (heads = 16; heads > 0; heads--) - if (!(num_blocks % heads)) - break; + for (sectors = max_sectors; sectors > 0; sectors--) + if (!(num_blocks % (heads * sectors))) + if (heads * sectors * max_cylinders >= num_blocks) { + cylinders = num_blocks / (heads * sectors); + goto done; + } + heads = 16; + sectors = (num_blocks + heads * max_cylinders - 1) / (heads * max_cylinders); + cylinders = (num_blocks + heads * sectors - 1) / (heads * sectors); + + LOG_F(WARNING, "%s: could not find a suitable CHS translation; increased sectors to %d", + this->name.c_str(), heads * sectors * cylinders); + +done: this->heads = heads; - - if (!heads) { - LOG_F(WARNING, "%s: could not find a suitable number of heads", - this->name.c_str()); - return; - } - - num_blocks /= heads; - - for (sectors = max_sectors; sectors > 0; sectors--) { - if (!(num_blocks % sectors)) { - if (num_blocks / sectors < 65536) - break; - } - } - this->sectors = sectors; - - if (!sectors) { - LOG_F(WARNING, "%s: could not find a suitable CHS translation", - this->name.c_str()); - return; - } - - this->cylinders = num_blocks / sectors; - LOG_F(INFO, "%s: C=%d, H=%d, S=%d", this->name.c_str(), this->cylinders, - this->heads, this->sectors); + this->cylinders = cylinders; + LOG_F(INFO, "%s: C=%d, H=%d, S=%d", this->name.c_str(), cylinders, + heads, sectors); } static const PropMap AtaHardDiskProperties = { diff --git a/devices/common/ata/atahd.h b/devices/common/ata/atahd.h index fc48b9d..8c7fb34 100644 --- a/devices/common/ata/atahd.h +++ b/devices/common/ata/atahd.h @@ -30,7 +30,9 @@ along with this program. If not, see . #include #define ATA_HD_SEC_SIZE 512 -#define ATA_BIOS_LIMIT 16514064 +#define ATA_BIOS_LIMIT 16514064 // C:16383 x H:16 x S:63 = C:1032 x H:254 x S:63 = 8063.5078125 MiB = 8.46 GB +#define REAL_CHS_LIMIT 267382800 // C:65535 x H:16 x S:255 = 127.498 GiB = 136.900 GB = largest identify +#define CHS_LIMIT 267386880 // C:65536 x H:16 x S:255 = 127.500 GiB = 136.902 GB = largest address class AtaHardDisk : public AtaBaseDevice {