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
{