diff --git a/src/disk/hdc_esdi_at.c b/src/disk/hdc_esdi_at.c index 042a6020a..e16d4d729 100644 --- a/src/disk/hdc_esdi_at.c +++ b/src/disk/hdc_esdi_at.c @@ -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); diff --git a/src/disk/hdc_esdi_mca.c b/src/disk/hdc_esdi_mca.c index 3714f93d4..c906c7ca1 100644 --- a/src/disk/hdc_esdi_mca.c +++ b/src/disk/hdc_esdi_mca.c @@ -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; diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index a14f54e7d..428804b5a 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -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 }; diff --git a/src/disk/hdc_st506_at.c b/src/disk/hdc_st506_at.c index c8c35d7d5..67bea6a8e 100644 --- a/src/disk/hdc_st506_at.c +++ b/src/disk/hdc_st506_at.c @@ -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); diff --git a/src/disk/hdc_st506_xt.c b/src/disk/hdc_st506_xt.c index fc20350b0..f3ac48a36 100644 --- a/src/disk/hdc_st506_xt.c +++ b/src/disk/hdc_st506_xt.c @@ -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); diff --git a/src/include/86box/hdc_ide.h b/src/include/86box/hdc_ide.h index 1f7a78c9f..4ee808d69 100644 --- a/src/include/86box/hdc_ide.h +++ b/src/include/86box/hdc_ide.h @@ -205,12 +205,14 @@ extern void win_cdrom_eject(uint8_t id); extern void win_cdrom_reload(uint8_t id); extern void ide_set_base_addr(int board, int base, uint16_t port); +extern void ide_set_irq(int board, int irq); extern void ide_handlers(uint8_t board, int set); extern void ide_board_set_force_ata3(int board, int force_ata3); #ifdef EMU_ISAPNP_H extern void ide_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv); +extern void ide_pnp_config_changed_1addr(uint8_t ld, isapnp_device_config_t *config, void *priv); #endif extern double ide_atapi_get_period(uint8_t channel);