Fixed the FORMAT command on almost every emulated hard disk controller.
This commit is contained in:
@@ -214,6 +214,41 @@ get_sector(esdi_t *esdi, off64_t *addr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
get_sector_format(esdi_t *esdi, off64_t *addr)
|
||||
{
|
||||
const drive_t *drive = &esdi->drives[esdi->drive_sel];
|
||||
int heads = drive->cfg_hpc;
|
||||
int sectors = drive->cfg_spt;
|
||||
int c;
|
||||
int h;
|
||||
int s;
|
||||
|
||||
if (esdi->head > heads) {
|
||||
esdi_at_log("esdi_get_sector: past end of configured heads\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (drive->cfg_spt == drive->real_spt && drive->cfg_hpc == drive->real_hpc) {
|
||||
*addr = ((((off64_t) esdi->cylinder * heads) + esdi->head) * sectors);
|
||||
} else {
|
||||
/*
|
||||
* When performing translation, the firmware seems to leave 1
|
||||
* sector per track inaccessible (spare sector)
|
||||
*/
|
||||
|
||||
*addr = ((((off64_t) esdi->cylinder * heads) + esdi->head) * sectors);
|
||||
|
||||
s = *addr % (drive->real_spt - 1);
|
||||
h = (*addr / (drive->real_spt - 1)) % drive->real_hpc;
|
||||
c = (*addr / (drive->real_spt - 1)) / drive->real_hpc;
|
||||
|
||||
*addr = ((((off64_t) c * drive->real_hpc) + h) * drive->real_spt) + s;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Move to the next sector using CHS addressing. */
|
||||
static void
|
||||
next_sector(esdi_t *esdi)
|
||||
@@ -655,7 +690,7 @@ esdi_callback(void *priv)
|
||||
irq_raise(esdi);
|
||||
break;
|
||||
} else {
|
||||
if (get_sector(esdi, &addr)) {
|
||||
if (get_sector_format(esdi, &addr)) {
|
||||
esdi->error = ERR_ID_NOT_FOUND;
|
||||
esdi->status = STAT_READY | STAT_DSC | STAT_ERR;
|
||||
irq_raise(esdi);
|
||||
|
||||
@@ -831,14 +831,12 @@ esdi_callback(void *priv)
|
||||
|
||||
switch (dev->cmd_state) {
|
||||
case 0:
|
||||
dev->rba = (dev->cmd_data[2] | (dev->cmd_data[3] << 16)) & 0x0fffffff;
|
||||
dev->rba = hdd_image_get_last_sector(drive->hdd_num);
|
||||
|
||||
dev->sector_count = dev->cmd_data[1];
|
||||
|
||||
if ((dev->rba + dev->sector_count) > hdd_image_get_last_sector(drive->hdd_num)) {
|
||||
rba_out_of_range(dev);
|
||||
return;
|
||||
}
|
||||
if (dev->command == CMD_FORMAT_UNIT)
|
||||
dev->sector_count = dev->cmd_data[1];
|
||||
else
|
||||
dev->sector_count = 0;
|
||||
|
||||
dev->status = STATUS_IRQ | STATUS_CMD_IN_PROGRESS | STATUS_TRANSFER_REQ;
|
||||
dev->irq_status = dev->cmd_dev | IRQ_DATA_TRANSFER_READY;
|
||||
@@ -855,7 +853,8 @@ esdi_callback(void *priv)
|
||||
return;
|
||||
}
|
||||
|
||||
hdd_image_zero(drive->hdd_num, dev->rba, dev->sector_count);
|
||||
if (dev->command == CMD_FORMAT_UNIT)
|
||||
hdd_image_zero(drive->hdd_num, 0, hdd_image_get_last_sector(drive->hdd_num) + 1);
|
||||
|
||||
dev->status = STATUS_CMD_IN_PROGRESS;
|
||||
dev->cmd_state = 2;
|
||||
|
||||
@@ -738,6 +738,22 @@ ide_get_sector(ide_t *ide)
|
||||
}
|
||||
}
|
||||
|
||||
static off64_t
|
||||
ide_get_sector_format(ide_t *ide)
|
||||
{
|
||||
uint32_t heads;
|
||||
uint32_t sectors;
|
||||
|
||||
if (ide->tf->lba)
|
||||
return (off64_t) ide->lba_addr;
|
||||
else {
|
||||
heads = ide->cfg_hpc;
|
||||
sectors = ide->cfg_spt;
|
||||
|
||||
return ((((off64_t) ide->tf->cylinder * heads) + (off64_t) ide->tf->head) * sectors);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Move to the next sector using CHS addressing
|
||||
*/
|
||||
@@ -2147,8 +2163,9 @@ ide_callback(void *priv)
|
||||
if (ide->type == IDE_ATAPI)
|
||||
atapi_error_no_ready(ide);
|
||||
else {
|
||||
if (chk_chs && ((ide->tf->cylinder >= ide->tracks) || (ide->tf->head >= ide->hpc) ||
|
||||
!ide->tf->sector || (ide->tf->sector > ide->spt)))
|
||||
/* The J-Bond PCI400C-A Phoenix BIOS implies that this command is supposed to
|
||||
ignore the sector number. */
|
||||
if (chk_chs && ((ide->tf->cylinder >= ide->tracks) || (ide->tf->head >= ide->hpc)))
|
||||
err = IDNF_ERR;
|
||||
else {
|
||||
ide->tf->atastat = DRDY_STAT | DSC_STAT;
|
||||
@@ -2434,7 +2451,7 @@ ide_callback(void *priv)
|
||||
else if (!ide->tf->lba && (ide->cfg_spt == 0))
|
||||
err = IDNF_ERR;
|
||||
else {
|
||||
hdd_image_zero(ide->hdd_num, ide_get_sector(ide), ide->tf->secount);
|
||||
hdd_image_zero(ide->hdd_num, ide_get_sector_format(ide), ide->tf->secount);
|
||||
|
||||
ide->tf->atastat = DRDY_STAT | DSC_STAT;
|
||||
ide_irq_raise(ide);
|
||||
@@ -2628,6 +2645,15 @@ ide_set_base_addr(int board, int base, uint16_t port)
|
||||
ide_boards[board]->base[base] = port;
|
||||
}
|
||||
|
||||
void
|
||||
ide_set_irq(int board, int irq)
|
||||
{
|
||||
ide_log("ide_set_irq(%i, %i)\n", board, irq);
|
||||
|
||||
if (ide_boards[board] != NULL)
|
||||
ide_boards[board]->irq = irq;
|
||||
}
|
||||
|
||||
static void
|
||||
ide_clear_bus_master(int board)
|
||||
{
|
||||
@@ -2803,6 +2829,36 @@ ide_board_init(int board, int irq, int base_main, int side_main, int type, int b
|
||||
ide_boards[board]->inited = 1;
|
||||
}
|
||||
|
||||
/* Needed for ESS ES1688/968 PnP. */
|
||||
void
|
||||
ide_pnp_config_changed_1addr(uint8_t ld, isapnp_device_config_t *config, void *priv)
|
||||
{
|
||||
intptr_t board = (intptr_t) priv;
|
||||
|
||||
if (ld)
|
||||
return;
|
||||
|
||||
if (ide_boards[board]->base[0] || ide_boards[board]->base[1]) {
|
||||
ide_remove_handlers(board);
|
||||
ide_boards[board]->base[0] = ide_boards[board]->base[1] = 0;
|
||||
}
|
||||
|
||||
ide_boards[board]->irq = -1;
|
||||
|
||||
if (config->activate) {
|
||||
ide_boards[board]->base[0] = (config->io[0].base != ISAPNP_IO_DISABLED) ?
|
||||
config->io[0].base : 0x0000;
|
||||
ide_boards[board]->base[1] = (config->io[0].base != ISAPNP_IO_DISABLED) ?
|
||||
(config->io[0].base + 0x0206) : 0x0000;
|
||||
|
||||
if (ide_boards[board]->base[0] && ide_boards[board]->base[1])
|
||||
ide_set_handlers(board);
|
||||
|
||||
if (config->irq[0].irq != ISAPNP_IRQ_DISABLED)
|
||||
ide_boards[board]->irq = config->irq[0].irq;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ide_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv)
|
||||
{
|
||||
@@ -3526,5 +3582,5 @@ const device_t ide_qua_pnp_device = {
|
||||
{ .available = NULL },
|
||||
.speed_changed = NULL,
|
||||
.force_redraw = NULL,
|
||||
.config = ide_qua_config
|
||||
.config = NULL
|
||||
};
|
||||
|
||||
@@ -187,7 +187,7 @@ get_sector(mfm_t *mfm, off64_t *addr)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (mfm->sector >= drive->cfg_spt + 1) {
|
||||
if (mfm->sector >= (drive->cfg_spt + 1)) {
|
||||
st506_at_log("WD1003(%d) get_sector: past end of configured sectors\n",
|
||||
mfm->drvsel);
|
||||
return 1;
|
||||
@@ -199,7 +199,7 @@ get_sector(mfm_t *mfm, off64_t *addr)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (mfm->sector >= drive->spt + 1) {
|
||||
if (mfm->sector >= (drive->spt + 1)) {
|
||||
st506_at_log("WD1003(%d) get_sector: past end of sectors\n", mfm->drvsel);
|
||||
return 1;
|
||||
}
|
||||
@@ -209,6 +209,35 @@ get_sector(mfm_t *mfm, off64_t *addr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
get_sector_format(mfm_t *mfm, off64_t *addr)
|
||||
{
|
||||
const drive_t *drive = &mfm->drives[mfm->drvsel];
|
||||
|
||||
/* FIXME: See if this is even needed - if the code is present, IBM AT
|
||||
diagnostics v2.07 will error with: ERROR 152 - SYSTEM BOARD. */
|
||||
if (drive->curcyl != mfm->cylinder) {
|
||||
st506_at_log("WD1003(%d) sector: wrong cylinder\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (mfm->head > drive->cfg_hpc) {
|
||||
st506_at_log("WD1003(%d) get_sector: past end of configured heads\n",
|
||||
mfm->drvsel);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* We should check this in the SET_DRIVE_PARAMETERS command! --FvK */
|
||||
if (mfm->head > drive->hpc) {
|
||||
st506_at_log("WD1003(%d) get_sector: past end of heads\n", mfm->drvsel);
|
||||
return 1;
|
||||
}
|
||||
|
||||
*addr = ((((off64_t) mfm->cylinder * drive->cfg_hpc) + mfm->head) * drive->cfg_spt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Move to the next sector using CHS addressing. */
|
||||
static void
|
||||
next_sector(mfm_t *mfm)
|
||||
@@ -634,7 +663,7 @@ do_callback(void *priv)
|
||||
st506_at_log("WD1003(%d) format(%d,%d)\n",
|
||||
mfm->drvsel, mfm->cylinder, mfm->head);
|
||||
do_seek(mfm);
|
||||
if (get_sector(mfm, &addr)) {
|
||||
if (get_sector_format(mfm, &addr)) {
|
||||
mfm->error = ERR_ID_NOT_FOUND;
|
||||
mfm->status = STAT_READY | STAT_DSC | STAT_ERR;
|
||||
irq_raise(mfm);
|
||||
|
||||
@@ -457,6 +457,37 @@ get_chs(hdc_t *dev, drive_t *drive)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
get_chs_format(hdc_t *dev, drive_t *drive)
|
||||
{
|
||||
dev->err_bv = 0x80;
|
||||
|
||||
dev->head = dev->command[1] & 0x1f;
|
||||
/* 6 bits are used for the sector number even on the IBM PC controller. */
|
||||
dev->sector = 1;
|
||||
dev->count = dev->command[4];
|
||||
if (((dev->type == ST506_XT_TYPE_ST11M) || (dev->type == ST506_XT_TYPE_ST11R)) && (dev->command[0] >= 0xf0))
|
||||
dev->cylinder = 0;
|
||||
else {
|
||||
dev->cylinder = dev->command[3] | ((dev->command[2] & 0xc0) << 2);
|
||||
dev->cylinder += dev->cyl_off; /* for ST-11 */
|
||||
}
|
||||
|
||||
if (dev->cylinder >= drive->cfg_cyl) {
|
||||
/*
|
||||
* This really is an error, we cannot move
|
||||
* past the end of the drive, which should
|
||||
* result in an ERR_ILLEGAL_ADDR. --FvK
|
||||
*/
|
||||
drive->cylinder = drive->cfg_cyl - 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
drive->cylinder = dev->cylinder;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
st506_callback(void *priv)
|
||||
{
|
||||
@@ -628,7 +659,7 @@ st506_callback(void *priv)
|
||||
case CMD_FORMAT_BAD_TRACK:
|
||||
switch (dev->state) {
|
||||
case STATE_START_COMMAND:
|
||||
(void) get_chs(dev, drive);
|
||||
(void) get_chs_format(dev, drive);
|
||||
st506_xt_log("ST506: FORMAT_%sTRACK(%i, %i/%i)\n",
|
||||
(dev->command[0] == CMD_FORMAT_BAD_TRACK) ? "BAD_" : "",
|
||||
dev->drive_sel, dev->cylinder, dev->head);
|
||||
|
||||
Reference in New Issue
Block a user