mirror of
https://github.com/dingusdev/dingusppc.git
synced 2025-01-13 18:30:44 +00:00
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.
This commit is contained in:
parent
96dc02b249
commit
155b8cdad9
@ -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 = {
|
||||
|
@ -30,7 +30,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#include <string>
|
||||
|
||||
#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
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user