2017-09-30 16:56:38 -04:00
|
|
|
/*
|
|
|
|
|
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
|
|
|
|
* running old operating systems and software designed for IBM
|
|
|
|
|
* PC systems and compatibles from 1981 through fairly recent
|
|
|
|
|
* system designs based on the PCI bus.
|
|
|
|
|
*
|
|
|
|
|
* This file is part of the 86Box distribution.
|
|
|
|
|
*
|
|
|
|
|
* Common code to handle all sorts of hard disk images.
|
|
|
|
|
*
|
2020-03-25 00:46:02 +02:00
|
|
|
*
|
2017-09-30 16:56:38 -04:00
|
|
|
*
|
|
|
|
|
* Authors: Miran Grca, <mgrca8@gmail.com>
|
|
|
|
|
* Fred N. van Kempen, <decwiz@yahoo.com>
|
2017-10-08 19:14:46 -04:00
|
|
|
*
|
2019-09-26 10:02:43 +02:00
|
|
|
* Copyright 2016-2019 Miran Grca.
|
|
|
|
|
* Copyright 2017-2019 Fred N. van Kempen.
|
2017-09-30 16:56:38 -04:00
|
|
|
*/
|
2017-09-25 04:31:20 -04:00
|
|
|
#include <stdio.h>
|
2022-07-07 23:35:34 +02:00
|
|
|
#include <inttypes.h>
|
2017-09-25 04:31:20 -04:00
|
|
|
#include <string.h>
|
2022-07-07 23:35:34 +02:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <stdbool.h>
|
|
|
|
|
#include <math.h>
|
2017-09-25 04:31:20 -04:00
|
|
|
#include <wchar.h>
|
2020-03-29 14:24:42 +02:00
|
|
|
#include <86box/86box.h>
|
|
|
|
|
#include <86box/plat.h>
|
|
|
|
|
#include <86box/ui.h>
|
|
|
|
|
#include <86box/hdd.h>
|
|
|
|
|
#include <86box/cdrom.h>
|
2022-07-07 23:35:34 +02:00
|
|
|
#include <86box/video.h>
|
|
|
|
|
#include "cpu.h"
|
2017-08-24 01:14:39 -04:00
|
|
|
|
2022-07-19 11:31:06 +02:00
|
|
|
#define HDD_OVERHEAD_TIME 50.0
|
2017-10-01 16:29:15 -04:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
hard_disk_t hdd[HDD_NUM];
|
2022-07-19 23:52:18 +02:00
|
|
|
|
2017-10-01 16:29:15 -04:00
|
|
|
int
|
|
|
|
|
hdd_init(void)
|
|
|
|
|
{
|
|
|
|
|
/* Clear all global data. */
|
|
|
|
|
memset(hdd, 0x00, sizeof(hdd));
|
|
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
return (0);
|
2017-10-01 16:29:15 -04:00
|
|
|
}
|
2017-10-07 00:46:54 -04:00
|
|
|
|
|
|
|
|
int
|
|
|
|
|
hdd_string_to_bus(char *str, int cdrom)
|
|
|
|
|
{
|
2022-09-18 17:13:50 -04:00
|
|
|
if (!strcmp(str, "none"))
|
|
|
|
|
return (HDD_BUS_DISABLED);
|
2017-10-07 00:46:54 -04:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
if (!strcmp(str, "mfm") || !strcmp(str, "rll")) {
|
|
|
|
|
if (cdrom) {
|
2017-10-07 00:46:54 -04:00
|
|
|
no_cdrom:
|
2022-09-18 17:13:50 -04:00
|
|
|
ui_msgbox_header(MBX_ERROR, (wchar_t *) IDS_2130, (wchar_t *) IDS_4099);
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
2017-10-07 00:46:54 -04:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
return (HDD_BUS_MFM);
|
2017-10-07 00:46:54 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* FIXME: delete 'rll' in a year or so.. --FvK */
|
|
|
|
|
if (!strcmp(str, "esdi") || !strcmp(str, "rll")) {
|
2022-09-18 17:13:50 -04:00
|
|
|
if (cdrom)
|
|
|
|
|
goto no_cdrom;
|
2017-10-07 00:46:54 -04:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
return (HDD_BUS_ESDI);
|
2017-10-07 00:46:54 -04:00
|
|
|
}
|
|
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
if (!strcmp(str, "ide_pio_only"))
|
|
|
|
|
return (HDD_BUS_IDE);
|
2017-10-07 00:46:54 -04:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
if (!strcmp(str, "ide"))
|
|
|
|
|
return (HDD_BUS_IDE);
|
2017-10-07 00:46:54 -04:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
if (!strcmp(str, "atapi_pio_only"))
|
|
|
|
|
return (HDD_BUS_ATAPI);
|
2017-10-07 00:46:54 -04:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
if (!strcmp(str, "atapi"))
|
|
|
|
|
return (HDD_BUS_ATAPI);
|
2017-10-07 00:46:54 -04:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
if (!strcmp(str, "eide"))
|
|
|
|
|
return (HDD_BUS_IDE);
|
2017-10-07 00:46:54 -04:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
if (!strcmp(str, "xta"))
|
|
|
|
|
return (HDD_BUS_XTA);
|
2017-10-07 00:46:54 -04:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
if (!strcmp(str, "atide"))
|
|
|
|
|
return (HDD_BUS_IDE);
|
2017-10-07 00:46:54 -04:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
if (!strcmp(str, "ide_pio_and_dma"))
|
|
|
|
|
return (HDD_BUS_IDE);
|
2017-10-07 00:46:54 -04:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
if (!strcmp(str, "atapi_pio_and_dma"))
|
|
|
|
|
return (HDD_BUS_ATAPI);
|
2017-10-07 00:46:54 -04:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
if (!strcmp(str, "scsi"))
|
|
|
|
|
return (HDD_BUS_SCSI);
|
2017-10-07 00:46:54 -04:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
return (0);
|
2017-10-07 00:46:54 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
hdd_bus_to_string(int bus, int cdrom)
|
|
|
|
|
{
|
|
|
|
|
char *s = "none";
|
|
|
|
|
|
|
|
|
|
switch (bus) {
|
2022-09-18 17:13:50 -04:00
|
|
|
case HDD_BUS_DISABLED:
|
|
|
|
|
default:
|
|
|
|
|
break;
|
2017-10-07 00:46:54 -04:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
case HDD_BUS_MFM:
|
|
|
|
|
s = "mfm";
|
|
|
|
|
break;
|
2017-10-07 00:46:54 -04:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
case HDD_BUS_XTA:
|
|
|
|
|
s = "xta";
|
|
|
|
|
break;
|
2017-10-07 00:46:54 -04:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
case HDD_BUS_ESDI:
|
|
|
|
|
s = "esdi";
|
|
|
|
|
break;
|
2017-10-07 00:46:54 -04:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
case HDD_BUS_IDE:
|
|
|
|
|
s = "ide";
|
|
|
|
|
break;
|
PIC rewrite, proper SMRAM API, complete SiS 471 rewrite and addition of 40x, 460, and 461, changes to mem.c/h, disabled Voodoo memory dumping on exit, bumped SDL Hardware scale quality to 2, bumped IDE/ATAPI drives to ATA-6, finally bumped emulator version to 3.0, redid the bus type ID's to allow for planned ATAPI hard disks, made SST flash set its high mappings to the correct address if the CPU is 16-bit, and added the SiS 401 AMI 486 Clone, AOpen Vi15G, and the Soyo 4SA2 (486 with SiS 496/497 that can boot from CD-ROM), assorted 286+ protected mode fixes (for slightly more accuracy), and fixes to 808x emulation (MS Word 1.0 and 1.10 for DOS now work correctly from floppy).
2020-10-14 23:15:01 +02:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
case HDD_BUS_ATAPI:
|
|
|
|
|
s = "atapi";
|
|
|
|
|
break;
|
2017-10-07 00:46:54 -04:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
case HDD_BUS_SCSI:
|
|
|
|
|
s = "scsi";
|
|
|
|
|
break;
|
2017-10-07 00:46:54 -04:00
|
|
|
}
|
|
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
return (s);
|
2017-10-07 00:46:54 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
hdd_is_valid(int c)
|
|
|
|
|
{
|
2018-04-25 23:51:13 +02:00
|
|
|
if (hdd[c].bus == HDD_BUS_DISABLED)
|
2022-09-18 17:13:50 -04:00
|
|
|
return (0);
|
2017-10-07 00:46:54 -04:00
|
|
|
|
2021-03-14 20:35:01 +01:00
|
|
|
if (strlen(hdd[c].fn) == 0)
|
2022-09-18 17:13:50 -04:00
|
|
|
return (0);
|
2017-10-07 00:46:54 -04:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
if ((hdd[c].tracks == 0) || (hdd[c].hpc == 0) || (hdd[c].spt == 0))
|
|
|
|
|
return (0);
|
2017-10-07 00:46:54 -04:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
return (1);
|
2017-10-07 00:46:54 -04:00
|
|
|
}
|
2022-07-07 23:35:34 +02:00
|
|
|
|
|
|
|
|
double
|
|
|
|
|
hdd_seek_get_time(hard_disk_t *hdd, uint32_t dst_addr, uint8_t operation, uint8_t continuous, double max_seek_time)
|
|
|
|
|
{
|
2022-07-19 11:31:06 +02:00
|
|
|
if (!hdd->speed_preset)
|
|
|
|
|
return HDD_OVERHEAD_TIME;
|
|
|
|
|
|
2022-07-19 23:52:18 +02:00
|
|
|
hdd_zone_t *zone = NULL;
|
|
|
|
|
for (int i = 0; i < hdd->num_zones; i++) {
|
2022-09-18 17:13:50 -04:00
|
|
|
zone = &hdd->zones[i];
|
|
|
|
|
if (zone->end_sector >= dst_addr)
|
|
|
|
|
break;
|
2022-07-19 23:52:18 +02:00
|
|
|
}
|
2022-07-07 23:35:34 +02:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
double continuous_times[2][2] = {
|
|
|
|
|
{hdd->head_switch_usec, hdd->cyl_switch_usec },
|
|
|
|
|
{ zone->sector_time_usec, zone->sector_time_usec}
|
|
|
|
|
};
|
2022-07-19 23:52:18 +02:00
|
|
|
double times[2] = { HDD_OVERHEAD_TIME, hdd->avg_rotation_lat_usec };
|
|
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
uint32_t new_track = zone->start_track + ((dst_addr - zone->start_sector) / zone->sectors_per_track);
|
|
|
|
|
uint32_t new_cylinder = new_track / hdd->phy_heads;
|
|
|
|
|
uint32_t cylinder_diff = abs((int) hdd->cur_cylinder - (int) new_cylinder);
|
2022-07-19 23:52:18 +02:00
|
|
|
|
|
|
|
|
bool sequential = dst_addr == hdd->cur_addr + 1;
|
2022-09-18 17:13:50 -04:00
|
|
|
continuous = continuous && sequential;
|
2022-07-19 23:52:18 +02:00
|
|
|
|
|
|
|
|
double seek_time = 0.0;
|
|
|
|
|
if (continuous)
|
2022-09-18 17:13:50 -04:00
|
|
|
seek_time = continuous_times[new_track == hdd->cur_track][!!cylinder_diff];
|
2022-07-19 23:52:18 +02:00
|
|
|
else {
|
2022-09-18 17:13:50 -04:00
|
|
|
if (!cylinder_diff)
|
|
|
|
|
seek_time = times[operation != HDD_OP_SEEK];
|
|
|
|
|
else {
|
|
|
|
|
seek_time = hdd->cyl_switch_usec + (hdd->full_stroke_usec * (double) cylinder_diff / (double) hdd->phy_cyl) + ((operation != HDD_OP_SEEK) * hdd->avg_rotation_lat_usec);
|
|
|
|
|
}
|
2022-07-19 23:52:18 +02:00
|
|
|
}
|
2022-07-07 23:35:34 +02:00
|
|
|
|
2022-07-19 23:52:18 +02:00
|
|
|
if (!max_seek_time || seek_time <= max_seek_time) {
|
2022-09-18 17:13:50 -04:00
|
|
|
hdd->cur_addr = dst_addr;
|
|
|
|
|
hdd->cur_track = new_track;
|
|
|
|
|
hdd->cur_cylinder = new_cylinder;
|
2022-07-19 23:52:18 +02:00
|
|
|
}
|
2022-07-07 23:35:34 +02:00
|
|
|
|
2022-07-19 23:52:18 +02:00
|
|
|
return seek_time;
|
2022-07-07 23:35:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
hdd_readahead_update(hard_disk_t *hdd)
|
|
|
|
|
{
|
2022-07-19 23:52:18 +02:00
|
|
|
uint64_t elapsed_cycles;
|
2022-09-18 17:13:50 -04:00
|
|
|
double elapsed_us, seek_time;
|
2022-07-19 23:52:18 +02:00
|
|
|
uint32_t max_read_ahead, i;
|
|
|
|
|
uint32_t space_needed;
|
2022-07-07 23:35:34 +02:00
|
|
|
|
2022-07-19 23:52:18 +02:00
|
|
|
hdd_cache_t *cache = &hdd->cache;
|
|
|
|
|
if (cache->ra_ongoing) {
|
2022-09-18 17:13:50 -04:00
|
|
|
hdd_cache_seg_t *segment = &cache->segments[cache->ra_segment];
|
2022-07-07 23:35:34 +02:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
elapsed_cycles = tsc - cache->ra_start_time;
|
|
|
|
|
elapsed_us = (double) elapsed_cycles / cpuclock * 1000000.0;
|
|
|
|
|
/* Do not overwrite data not yet read by host */
|
|
|
|
|
max_read_ahead = (segment->host_addr + cache->segment_size) - segment->ra_addr;
|
2022-07-07 23:35:34 +02:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
seek_time = 0.0;
|
2022-07-07 23:35:34 +02:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
for (i = 0; i < max_read_ahead; i++) {
|
|
|
|
|
seek_time += hdd_seek_get_time(hdd, segment->ra_addr, HDD_OP_READ, 1, elapsed_us - seek_time);
|
|
|
|
|
if (seek_time > elapsed_us)
|
|
|
|
|
break;
|
2022-07-07 23:35:34 +02:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
segment->ra_addr++;
|
|
|
|
|
}
|
2022-07-19 23:52:18 +02:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
if (segment->ra_addr > segment->lba_addr + cache->segment_size) {
|
|
|
|
|
space_needed = segment->ra_addr - (segment->lba_addr + cache->segment_size);
|
|
|
|
|
segment->lba_addr += space_needed;
|
|
|
|
|
}
|
2022-07-19 23:52:18 +02:00
|
|
|
}
|
2022-07-07 23:35:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static double
|
|
|
|
|
hdd_writecache_flush(hard_disk_t *hdd)
|
|
|
|
|
{
|
2022-07-19 23:52:18 +02:00
|
|
|
double seek_time = 0.0;
|
2022-07-07 23:35:34 +02:00
|
|
|
|
2022-07-19 23:52:18 +02:00
|
|
|
while (hdd->cache.write_pending) {
|
2022-09-18 17:13:50 -04:00
|
|
|
seek_time += hdd_seek_get_time(hdd, hdd->cache.write_addr, HDD_OP_WRITE, 1, 0);
|
|
|
|
|
hdd->cache.write_addr++;
|
|
|
|
|
hdd->cache.write_pending--;
|
2022-07-19 23:52:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return seek_time;
|
2022-07-07 23:35:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
hdd_writecache_update(hard_disk_t *hdd)
|
|
|
|
|
{
|
2022-07-19 23:52:18 +02:00
|
|
|
uint64_t elapsed_cycles;
|
2022-09-18 17:13:50 -04:00
|
|
|
double elapsed_us, seek_time;
|
2022-07-19 23:52:18 +02:00
|
|
|
|
|
|
|
|
if (hdd->cache.write_pending) {
|
2022-09-18 17:13:50 -04:00
|
|
|
elapsed_cycles = tsc - hdd->cache.write_start_time;
|
|
|
|
|
elapsed_us = (double) elapsed_cycles / cpuclock * 1000000.0;
|
|
|
|
|
seek_time = 0.0;
|
|
|
|
|
|
|
|
|
|
while (hdd->cache.write_pending) {
|
|
|
|
|
seek_time += hdd_seek_get_time(hdd, hdd->cache.write_addr, HDD_OP_WRITE, 1, elapsed_us - seek_time);
|
|
|
|
|
if (seek_time > elapsed_us)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
hdd->cache.write_addr++;
|
|
|
|
|
hdd->cache.write_pending--;
|
|
|
|
|
}
|
2022-07-19 23:52:18 +02:00
|
|
|
}
|
2022-07-07 23:35:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double
|
|
|
|
|
hdd_timing_write(hard_disk_t *hdd, uint32_t addr, uint32_t len)
|
|
|
|
|
{
|
2022-09-18 17:13:50 -04:00
|
|
|
double seek_time = 0.0;
|
2022-07-19 23:52:18 +02:00
|
|
|
uint32_t flush_needed;
|
|
|
|
|
|
2022-07-19 11:31:06 +02:00
|
|
|
if (!hdd->speed_preset)
|
|
|
|
|
return HDD_OVERHEAD_TIME;
|
|
|
|
|
|
2022-07-19 23:52:18 +02:00
|
|
|
hdd_readahead_update(hdd);
|
|
|
|
|
hdd_writecache_update(hdd);
|
2022-07-07 23:35:34 +02:00
|
|
|
|
2022-07-19 23:52:18 +02:00
|
|
|
hdd->cache.ra_ongoing = 0;
|
2022-07-07 23:35:34 +02:00
|
|
|
|
2022-07-19 23:52:18 +02:00
|
|
|
if (hdd->cache.write_pending && (addr != (hdd->cache.write_addr + hdd->cache.write_pending))) {
|
2022-09-18 17:13:50 -04:00
|
|
|
/* New request is not sequential to existing cache, need to flush it */
|
|
|
|
|
seek_time += hdd_writecache_flush(hdd);
|
2022-07-19 23:52:18 +02:00
|
|
|
}
|
2022-07-07 23:35:34 +02:00
|
|
|
|
2022-07-19 23:52:18 +02:00
|
|
|
if (!hdd->cache.write_pending) {
|
2022-09-18 17:13:50 -04:00
|
|
|
/* Cache is empty */
|
|
|
|
|
hdd->cache.write_addr = addr;
|
2022-07-19 23:52:18 +02:00
|
|
|
}
|
2022-07-07 23:35:34 +02:00
|
|
|
|
2022-07-19 23:52:18 +02:00
|
|
|
hdd->cache.write_pending += len;
|
|
|
|
|
if (hdd->cache.write_pending > hdd->cache.write_size) {
|
2022-09-18 17:13:50 -04:00
|
|
|
/* If request is bigger than free cache, flush some data first */
|
|
|
|
|
flush_needed = hdd->cache.write_pending - hdd->cache.write_size;
|
|
|
|
|
for (uint32_t i = 0; i < flush_needed; i++) {
|
|
|
|
|
seek_time += hdd_seek_get_time(hdd, hdd->cache.write_addr, HDD_OP_WRITE, 1, 0);
|
|
|
|
|
hdd->cache.write_addr++;
|
|
|
|
|
}
|
2022-07-19 23:52:18 +02:00
|
|
|
}
|
2022-07-07 23:35:34 +02:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
hdd->cache.write_start_time = tsc + (uint32_t) (seek_time * cpuclock / 1000000.0);
|
2022-07-07 23:35:34 +02:00
|
|
|
|
2022-07-19 23:52:18 +02:00
|
|
|
return seek_time;
|
2022-07-07 23:35:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double
|
|
|
|
|
hdd_timing_read(hard_disk_t *hdd, uint32_t addr, uint32_t len)
|
|
|
|
|
{
|
2022-07-19 23:52:18 +02:00
|
|
|
double seek_time = 0.0;
|
|
|
|
|
|
2022-07-19 11:31:06 +02:00
|
|
|
if (!hdd->speed_preset)
|
|
|
|
|
return HDD_OVERHEAD_TIME;
|
|
|
|
|
|
2022-07-19 23:52:18 +02:00
|
|
|
hdd_readahead_update(hdd);
|
|
|
|
|
hdd_writecache_update(hdd);
|
2022-07-07 23:35:34 +02:00
|
|
|
|
2022-07-19 23:52:18 +02:00
|
|
|
seek_time += hdd_writecache_flush(hdd);
|
2022-07-07 23:35:34 +02:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
hdd_cache_t *cache = &hdd->cache;
|
2022-07-19 23:52:18 +02:00
|
|
|
hdd_cache_seg_t *active_seg = &cache->segments[0];
|
2022-07-07 23:35:34 +02:00
|
|
|
|
2022-07-19 23:52:18 +02:00
|
|
|
for (uint32_t i = 0; i < cache->num_segments; i++) {
|
2022-09-18 17:13:50 -04:00
|
|
|
hdd_cache_seg_t *segment = &cache->segments[i];
|
|
|
|
|
if (!segment->valid) {
|
|
|
|
|
active_seg = segment;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (segment->lba_addr <= addr && (segment->lba_addr + cache->segment_size) >= addr) {
|
|
|
|
|
/* Cache HIT */
|
|
|
|
|
segment->host_addr = addr;
|
|
|
|
|
active_seg = segment;
|
|
|
|
|
if (addr + len > segment->ra_addr) {
|
|
|
|
|
uint32_t need_read = (addr + len) - segment->ra_addr;
|
|
|
|
|
for (uint32_t j = 0; j < need_read; j++) {
|
|
|
|
|
seek_time += hdd_seek_get_time(hdd, segment->ra_addr, HDD_OP_READ, 1, 0.0);
|
|
|
|
|
segment->ra_addr++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (addr + len > segment->lba_addr + cache->segment_size) {
|
|
|
|
|
/* Need to erase some previously cached data */
|
|
|
|
|
uint32_t space_needed = (addr + len) - (segment->lba_addr + cache->segment_size);
|
|
|
|
|
segment->lba_addr += space_needed;
|
|
|
|
|
}
|
|
|
|
|
goto update_lru;
|
|
|
|
|
} else {
|
|
|
|
|
if (segment->lru > active_seg->lru)
|
|
|
|
|
active_seg = segment;
|
|
|
|
|
}
|
2022-07-19 23:52:18 +02:00
|
|
|
}
|
2022-07-07 23:35:34 +02:00
|
|
|
|
2022-07-19 23:52:18 +02:00
|
|
|
/* Cache MISS */
|
2022-09-18 17:13:50 -04:00
|
|
|
active_seg->lba_addr = addr;
|
|
|
|
|
active_seg->valid = 1;
|
2022-07-19 23:52:18 +02:00
|
|
|
active_seg->host_addr = addr;
|
2022-09-18 17:13:50 -04:00
|
|
|
active_seg->ra_addr = addr;
|
2022-07-07 23:35:34 +02:00
|
|
|
|
2022-07-19 23:52:18 +02:00
|
|
|
for (uint32_t i = 0; i < len; i++) {
|
2022-09-18 17:13:50 -04:00
|
|
|
seek_time += hdd_seek_get_time(hdd, active_seg->ra_addr, HDD_OP_READ, i != 0, 0.0);
|
|
|
|
|
active_seg->ra_addr++;
|
2022-07-19 23:52:18 +02:00
|
|
|
}
|
2022-07-07 23:35:34 +02:00
|
|
|
|
|
|
|
|
update_lru:
|
2022-07-19 23:52:18 +02:00
|
|
|
for (uint32_t i = 0; i < cache->num_segments; i++)
|
2022-09-18 17:13:50 -04:00
|
|
|
cache->segments[i].lru++;
|
2022-07-07 23:35:34 +02:00
|
|
|
|
2022-07-19 23:52:18 +02:00
|
|
|
active_seg->lru = 0;
|
2022-07-07 23:35:34 +02:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
cache->ra_ongoing = 1;
|
|
|
|
|
cache->ra_segment = active_seg->id;
|
|
|
|
|
cache->ra_start_time = tsc + (uint32_t) (seek_time * cpuclock / 1000000.0);
|
2022-07-19 11:31:06 +02:00
|
|
|
|
2022-07-19 23:52:18 +02:00
|
|
|
return seek_time;
|
2022-07-07 23:35:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
hdd_cache_init(hard_disk_t *hdd)
|
|
|
|
|
{
|
2022-07-19 23:52:18 +02:00
|
|
|
hdd_cache_t *cache = &hdd->cache;
|
2022-09-18 17:13:50 -04:00
|
|
|
uint32_t i;
|
2022-07-19 23:52:18 +02:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
cache->ra_segment = 0;
|
|
|
|
|
cache->ra_ongoing = 0;
|
2022-07-19 23:52:18 +02:00
|
|
|
cache->ra_start_time = 0;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < cache->num_segments; i++) {
|
2022-09-18 17:13:50 -04:00
|
|
|
cache->segments[i].valid = 0;
|
|
|
|
|
cache->segments[i].lru = 0;
|
|
|
|
|
cache->segments[i].id = i;
|
|
|
|
|
cache->segments[i].ra_addr = 0;
|
|
|
|
|
cache->segments[i].host_addr = 0;
|
2022-07-19 23:52:18 +02:00
|
|
|
}
|
2022-07-07 23:35:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
hdd_zones_init(hard_disk_t *hdd)
|
|
|
|
|
{
|
2022-09-18 17:13:50 -04:00
|
|
|
uint32_t lba = 0, track = 0;
|
|
|
|
|
uint32_t i, tracks;
|
|
|
|
|
double revolution_usec = 60.0 / (double) hdd->rpm * 1000000.0;
|
2022-07-19 23:52:18 +02:00
|
|
|
hdd_zone_t *zone;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < hdd->num_zones; i++) {
|
2022-09-18 17:13:50 -04:00
|
|
|
zone = &hdd->zones[i];
|
|
|
|
|
zone->start_sector = lba;
|
|
|
|
|
zone->start_track = track;
|
|
|
|
|
zone->sector_time_usec = revolution_usec / (double) zone->sectors_per_track;
|
|
|
|
|
tracks = zone->cylinders * hdd->phy_heads;
|
|
|
|
|
lba += tracks * zone->sectors_per_track;
|
|
|
|
|
zone->end_sector = lba - 1;
|
|
|
|
|
track += tracks - 1;
|
2022-07-19 23:52:18 +02:00
|
|
|
}
|
2022-07-07 23:35:34 +02:00
|
|
|
}
|
|
|
|
|
|
2022-07-19 11:31:06 +02:00
|
|
|
static hdd_preset_t hdd_speed_presets[] = {
|
2022-09-18 17:13:50 -04:00
|
|
|
{.name = "RAM Disk (max. speed)", .internal_name = "ramdisk", .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 32},
|
2022-07-19 11:31:06 +02:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
{ .name = "[1989] 3500 RPM", .internal_name = "1989_3500rpm", .zones = 1, .avg_spt = 35, .heads = 2, .rpm = 3500, .full_stroke_ms = 40, .track_seek_ms = 8, .rcache_num_seg = 1, .rcache_seg_size = 16, .max_multiple = 8 },
|
2022-07-07 23:35:34 +02:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
{ .name = "[1992] 3600 RPM", .internal_name = "1992_3600rpm", .zones = 1, .avg_spt = 45, .heads = 2, .rpm = 3600, .full_stroke_ms = 30, .track_seek_ms = 6, .rcache_num_seg = 4, .rcache_seg_size = 16, .max_multiple = 8 },
|
2022-07-07 23:35:34 +02:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
{ .name = "[1994] 4500 RPM", .internal_name = "1994_4500rpm", .zones = 8, .avg_spt = 80, .heads = 4, .rpm = 4500, .full_stroke_ms = 26, .track_seek_ms = 5, .rcache_num_seg = 4, .rcache_seg_size = 32, .max_multiple = 16 },
|
2022-07-07 23:35:34 +02:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
{ .name = "[1996] 5400 RPM", .internal_name = "1996_5400rpm", .zones = 16, .avg_spt = 135, .heads = 4, .rpm = 5400, .full_stroke_ms = 24, .track_seek_ms = 3, .rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 16 },
|
2022-07-07 23:35:34 +02:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
{ .name = "[1997] 5400 RPM", .internal_name = "1997_5400rpm", .zones = 16, .avg_spt = 185, .heads = 6, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2.5, .rcache_num_seg = 8, .rcache_seg_size = 64, .max_multiple = 32 },
|
2022-07-07 23:35:34 +02:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
{ .name = "[1998] 5400 RPM", .internal_name = "1998_5400rpm", .zones = 16, .avg_spt = 300, .heads = 8, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 32 },
|
2022-07-07 23:35:34 +02:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
{ .name = "[2000] 7200 RPM", .internal_name = "2000_7200rpm", .zones = 16, .avg_spt = 350, .heads = 6, .rpm = 7200, .full_stroke_ms = 15, .track_seek_ms = 2, .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 32 },
|
2022-07-07 23:35:34 +02:00
|
|
|
};
|
|
|
|
|
|
2022-07-19 11:31:06 +02:00
|
|
|
int
|
|
|
|
|
hdd_preset_get_num()
|
|
|
|
|
{
|
|
|
|
|
return sizeof(hdd_speed_presets) / sizeof(hdd_preset_t);
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-14 14:44:36 +03:00
|
|
|
const char *
|
2022-07-19 11:31:06 +02:00
|
|
|
hdd_preset_getname(int preset)
|
|
|
|
|
{
|
2022-10-14 14:44:36 +03:00
|
|
|
return hdd_speed_presets[preset].name;
|
2022-07-19 11:31:06 +02:00
|
|
|
}
|
|
|
|
|
|
2022-10-14 14:44:36 +03:00
|
|
|
const char *
|
2022-07-19 11:31:06 +02:00
|
|
|
hdd_preset_get_internal_name(int preset)
|
|
|
|
|
{
|
2022-10-14 14:44:36 +03:00
|
|
|
return hdd_speed_presets[preset].internal_name;
|
2022-07-19 11:31:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
hdd_preset_get_from_internal_name(char *s)
|
|
|
|
|
{
|
|
|
|
|
int c = 0;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < (sizeof(hdd_speed_presets) / sizeof(hdd_preset_t)); i++) {
|
2022-09-18 17:13:50 -04:00
|
|
|
if (!strcmp((char *) hdd_speed_presets[c].internal_name, s))
|
2022-07-19 11:31:06 +02:00
|
|
|
return c;
|
|
|
|
|
c++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-07 23:35:34 +02:00
|
|
|
void
|
2022-07-19 11:31:06 +02:00
|
|
|
hdd_preset_apply(int hdd_id)
|
2022-07-07 23:35:34 +02:00
|
|
|
{
|
2022-07-19 23:52:18 +02:00
|
|
|
hard_disk_t *hd = &hdd[hdd_id];
|
2022-09-18 17:13:50 -04:00
|
|
|
double revolution_usec, zone_percent;
|
|
|
|
|
uint32_t disk_sectors, sectors_per_surface, cylinders, cylinders_per_zone;
|
|
|
|
|
uint32_t total_sectors = 0, i;
|
|
|
|
|
uint32_t spt, zone_sectors;
|
2022-07-07 23:35:34 +02:00
|
|
|
|
2022-07-19 23:52:18 +02:00
|
|
|
if (hd->speed_preset >= hdd_preset_get_num())
|
2022-09-18 17:13:50 -04:00
|
|
|
hd->speed_preset = 0;
|
2022-07-19 11:31:06 +02:00
|
|
|
|
2022-07-19 23:52:18 +02:00
|
|
|
hdd_preset_t *preset = &hdd_speed_presets[hd->speed_preset];
|
2022-07-19 11:31:06 +02:00
|
|
|
|
2022-07-19 23:52:18 +02:00
|
|
|
hd->cache.num_segments = preset->rcache_num_seg;
|
|
|
|
|
hd->cache.segment_size = preset->rcache_seg_size;
|
|
|
|
|
hd->max_multiple_block = preset->max_multiple;
|
2022-07-07 23:35:34 +02:00
|
|
|
|
2022-07-19 23:52:18 +02:00
|
|
|
if (!hd->speed_preset)
|
2022-09-18 17:13:50 -04:00
|
|
|
return;
|
2022-07-07 23:35:34 +02:00
|
|
|
|
2022-07-19 23:52:18 +02:00
|
|
|
hd->phy_heads = preset->heads;
|
2022-09-18 17:13:50 -04:00
|
|
|
hd->rpm = preset->rpm;
|
2022-07-07 23:35:34 +02:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
revolution_usec = 60.0 / (double) hd->rpm * 1000000.0;
|
2022-07-19 23:52:18 +02:00
|
|
|
hd->avg_rotation_lat_usec = revolution_usec / 2;
|
2022-09-18 17:13:50 -04:00
|
|
|
hd->full_stroke_usec = preset->full_stroke_ms * 1000;
|
|
|
|
|
hd->head_switch_usec = preset->track_seek_ms * 1000;
|
|
|
|
|
hd->cyl_switch_usec = preset->track_seek_ms * 1000;
|
2022-07-07 23:35:34 +02:00
|
|
|
|
2022-07-19 23:52:18 +02:00
|
|
|
hd->cache.write_size = 64;
|
2022-07-19 11:31:06 +02:00
|
|
|
|
2022-07-19 23:52:18 +02:00
|
|
|
hd->num_zones = preset->zones;
|
2022-07-19 11:31:06 +02:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
disk_sectors = hd->tracks * hd->hpc * hd->spt;
|
|
|
|
|
sectors_per_surface = (uint32_t) ceil((double) disk_sectors / (double) hd->phy_heads);
|
|
|
|
|
cylinders = (uint32_t) ceil((double) sectors_per_surface / (double) preset->avg_spt);
|
|
|
|
|
hd->phy_cyl = cylinders;
|
|
|
|
|
cylinders_per_zone = cylinders / preset->zones;
|
2022-07-07 23:35:34 +02:00
|
|
|
|
2022-07-19 23:52:18 +02:00
|
|
|
for (i = 0; i < preset->zones; i++) {
|
2022-09-18 17:13:50 -04:00
|
|
|
zone_percent = i * 100 / (double) preset->zones;
|
2022-07-07 23:35:34 +02:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
if (i < preset->zones - 1) {
|
|
|
|
|
/* Function for realistic zone sector density */
|
|
|
|
|
double spt_percent = -0.00341684 * pow(zone_percent, 2) - 0.175811 * zone_percent + 118.48;
|
|
|
|
|
spt = (uint32_t) ceil((double) preset->avg_spt * spt_percent / 100);
|
|
|
|
|
} else
|
|
|
|
|
spt = (uint32_t) ceil((double) (disk_sectors - total_sectors) / (double) (cylinders_per_zone * preset->heads));
|
2022-07-07 23:35:34 +02:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
zone_sectors = spt * cylinders_per_zone * preset->heads;
|
|
|
|
|
total_sectors += zone_sectors;
|
2022-07-07 23:35:34 +02:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
hd->zones[i].cylinders = cylinders_per_zone;
|
|
|
|
|
hd->zones[i].sectors_per_track = spt;
|
2022-07-19 23:52:18 +02:00
|
|
|
}
|
2022-07-07 23:35:34 +02:00
|
|
|
|
2022-07-19 23:52:18 +02:00
|
|
|
hdd_zones_init(hd);
|
|
|
|
|
hdd_cache_init(hd);
|
|
|
|
|
}
|