diff --git a/src/86box.c b/src/86box.c index b42a15656..0c1d0f0ae 100644 --- a/src/86box.c +++ b/src/86box.c @@ -1055,7 +1055,8 @@ pc_send_cad(void) void pc_send_cae(void) { - pc_send_ca(1); + // pc_send_ca(1); + picint(1 << 14); } void diff --git a/src/chipset/intel_piix.c b/src/chipset/intel_piix.c index 53ed617d2..e5b90d861 100644 --- a/src/chipset/intel_piix.c +++ b/src/chipset/intel_piix.c @@ -1600,7 +1600,10 @@ piix_init(const device_t *info) dev->port_92 = device_add(&port_92_pci_device); - cpu_set_isa_pci_div(4); + if (cpu_busspeed > 50000000) + cpu_set_isa_pci_div(4); + else + cpu_set_isa_pci_div(3); dma_alias_set(); diff --git a/src/chipset/via_vt82c49x.c b/src/chipset/via_vt82c49x.c index e25fdbfa0..de55f7060 100644 --- a/src/chipset/via_vt82c49x.c +++ b/src/chipset/via_vt82c49x.c @@ -30,6 +30,7 @@ #include <86box/mem.h> #include <86box/smram.h> #include <86box/pic.h> +#include <86box/timer.h> #include <86box/hdc.h> #include <86box/hdc_ide.h> #include <86box/port_92.h> diff --git a/src/config.c b/src/config.c index db9fcb31b..30f96b24f 100644 --- a/src/config.c +++ b/src/config.c @@ -876,6 +876,7 @@ load_hard_disks(void) break; case HDD_BUS_SCSI: + case HDD_BUS_ATAPI: max_spt = 255; max_hpc = 255; max_tracks = 266305; @@ -893,6 +894,8 @@ load_hard_disks(void) switch (hdd[c].bus) { case HDD_BUS_IDE: case HDD_BUS_ESDI: + case HDD_BUS_ATAPI: + case HDD_BUS_SCSI: sprintf(tmp2, "1997_5400rpm"); break; default: @@ -925,7 +928,7 @@ load_hard_disks(void) /* IDE */ sprintf(temp, "hdd_%02i_ide_channel", c + 1); - if (hdd[c].bus == HDD_BUS_IDE) { + if ((hdd[c].bus == HDD_BUS_IDE) || (hdd[c].bus == HDD_BUS_ATAPI)) { sprintf(tmp2, "%01u:%01u", c >> 1, c & 1); p = ini_section_get_string(cat, temp, tmp2); sscanf(p, "%01u:%01u", &board, &dev); @@ -2396,7 +2399,7 @@ save_hard_disks(void) ini_section_delete_var(cat, temp); sprintf(temp, "hdd_%02i_ide_channel", c + 1); - if (!hdd_is_valid(c) || (hdd[c].bus != HDD_BUS_IDE)) + if (!hdd_is_valid(c) || ((hdd[c].bus != HDD_BUS_IDE) && (hdd[c].bus != HDD_BUS_ATAPI))) ini_section_delete_var(cat, temp); else { sprintf(tmp2, "%01u:%01u", hdd[c].ide_channel >> 1, hdd[c].ide_channel & 1); diff --git a/src/disk/hdc.c b/src/disk/hdc.c index 8df617187..07df9d0e6 100644 --- a/src/disk/hdc.c +++ b/src/disk/hdc.c @@ -24,6 +24,7 @@ #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/machine.h> +#include <86box/timer.h> #include <86box/device.h> #include <86box/hdc.h> #include <86box/hdc_ide.h> diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index 8cd0d9885..8410955ae 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -110,18 +110,7 @@ #define IDE_TIME 10.0 -typedef struct ide_board_t { - int bit32; - int cur_dev; - int irq; - int inited; - int diag; - int force_ata3; - uint16_t base_main; - uint16_t side_main; - pc_timer_t timer; - ide_t *ide[2]; -} ide_board_t; +#define IDE_ATAPI_IS_EARLY ide->sc->pad0 typedef struct ide_bm_t { int (*dma)(uint8_t *data, int transfer_length, int out, void *priv); @@ -129,8 +118,24 @@ typedef struct ide_bm_t { void *priv; } ide_bm_t; -static ide_board_t *ide_boards[4] = { NULL, NULL, NULL, NULL }; -static ide_bm_t *ide_bm[4] = { NULL, NULL, NULL, NULL }; +typedef struct ide_board_t { + uint8_t devctl; + uint8_t pad; + uint16_t base[2]; + int bit32; + int cur_dev; + int irq; + int inited; + int diag; + int force_ata3; + + pc_timer_t timer; + + ide_t *ide[2]; + ide_bm_t *bm; +} ide_board_t; + +ide_board_t *ide_boards[IDE_BUS_MAX]; static uint8_t ide_ter_pnp_rom[] = { 0x09, 0xf8, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, /* BOX0001, serial 0, dummy checksum (filled in by isapnp_add_card) */ @@ -186,6 +191,7 @@ int ide_qua_enabled = 0; static void ide_atapi_callback(ide_t *ide); static void ide_callback(void *priv); +// #define ENABLE_IDE_LOG 1 #ifdef ENABLE_IDE_LOG int ide_do_log = ENABLE_IDE_LOG; @@ -207,7 +213,7 @@ ide_log(const char *fmt, ...) uint8_t getstat(ide_t *ide) { - return ide->atastat; + return ide->tf->atastat; } ide_t * @@ -330,6 +336,24 @@ ide_atapi_get_period(uint8_t channel) return ide_get_xfer_time(ide, 1); } +static void +ide_irq_update(ide_board_t *dev) +{ + ide_t *ide; + uint8_t set; + + if (dev == NULL) + return; + + ide = ide_drives[dev->cur_dev]; + set = !(ide_boards[ide->board]->devctl & 2) && ide->irqstat; + + if (!dev->force_ata3 && dev->bm && dev->bm->set_irq) + dev->bm->set_irq(set << 2, dev->bm->priv); + else if (ide_boards[ide->board]->irq != -1) + picint_common(dev->irq, PIC_IRQ_EDGE, set, NULL); +} + void ide_irq_raise(ide_t *ide) { @@ -340,15 +364,11 @@ ide_irq_raise(ide_t *ide) ide_log("IDE %i: IRQ raise\n", ide->board); - if (!(ide->fdisk & 2) && ide->selected) { - if (!ide_boards[ide->board]->force_ata3 && ide_bm[ide->board] && ide_bm[ide->board]->set_irq) - ide_bm[ide->board]->set_irq(0x04, ide_bm[ide->board]->priv); - else if (ide_boards[ide->board]->irq != -1) - picint(1 << ide_boards[ide->board]->irq); - } - ide->irqstat = 1; ide->service = 1; + + if (ide->selected) + ide_irq_update(ide_boards[ide->board]); } void @@ -361,40 +381,10 @@ ide_irq_lower(ide_t *ide) // ide_log("IDE %i: IRQ lower\n", ide->board); - if (ide->irqstat && ide->selected) { - if (!ide_boards[ide->board]->force_ata3 && ide_bm[ide->board] && ide_bm[ide->board]->set_irq) - ide_bm[ide->board]->set_irq(0x00, ide_bm[ide->board]->priv); - else if (ide_boards[ide->board]->irq != -1) - picintc(1 << ide_boards[ide->board]->irq); - } - ide->irqstat = 0; -} -static void -ide_irq_update(ide_t *ide) -{ - if (!ide_boards[ide->board]) - return; - - /* ide_log("Raising IRQ %i (board %i)\n", ide_boards[ide->board]->irq, ide->board); */ - - if (!(ide->fdisk & 2) && ide->irqstat) { - ide_log("IDE %i: IRQ update raise\n", ide->board); - if (!ide_boards[ide->board]->force_ata3 && ide_bm[ide->board] && ide_bm[ide->board]->set_irq) { - ide_bm[ide->board]->set_irq(0x00, ide_bm[ide->board]->priv); - ide_bm[ide->board]->set_irq(0x04, ide_bm[ide->board]->priv); - } else if (ide_boards[ide->board]->irq != -1) { - picintc(1 << ide_boards[ide->board]->irq); - picint(1 << ide_boards[ide->board]->irq); - } - } else if ((ide->fdisk & 2) || !ide->irqstat) { - ide_log("IDE %i: IRQ update lower\n", ide->board); - if (!ide_boards[ide->board]->force_ata3 && ide_bm[ide->board] && ide_bm[ide->board]->set_irq) - ide_bm[ide->board]->set_irq(0x00, ide_bm[ide->board]->priv); - else if (ide_boards[ide->board]->irq != -1) - picintc(1 << ide_boards[ide->board]->irq); - } + if (ide->selected) + ide_irq_update(ide_boards[ide->board]); } /** @@ -443,59 +433,37 @@ ide_padstr8(uint8_t *buf, int buf_size, const char *src) static int ide_get_max(ide_t *ide, int type) { + int ret = -1; + ide_bm_t *bm = ide_boards[ide->board]->bm; + int ata_4 = (!ide_boards[ide->board]->force_ata3 && (bm != NULL)); + int max[2][4] = { { 0, -1, -1, -1 }, { 4, 2, 2, 5 } }; + if (ide->type == IDE_ATAPI) - return ide->get_max(!ide->sc->pad0 && !ide_boards[ide->board]->force_ata3 && (ide_bm[ide->board] != NULL), type); + ret = ide->get_max(!IDE_ATAPI_IS_EARLY && ata_4, type); + else if (type <= TYPE_UDMA) + ret = max[ata_4][type]; + else + fatal("Unknown transfer type: %i\n", type); - switch (type) { - case TYPE_PIO: /* PIO */ - if (!ide_boards[ide->board]->force_ata3 && (ide_bm[ide->board] != NULL)) - return 4; - - return 0; /* Maximum PIO 0 for legacy PIO-only drive. */ - case TYPE_SDMA: /* SDMA */ - if (!ide_boards[ide->board]->force_ata3 && (ide_bm[ide->board] != NULL)) - return 2; - - return -1; - case TYPE_MDMA: /* MDMA */ - if (!ide_boards[ide->board]->force_ata3 && (ide_bm[ide->board] != NULL)) - return 2; - - return -1; - case TYPE_UDMA: /* UDMA */ - if (!ide_boards[ide->board]->force_ata3 && (ide_bm[ide->board] != NULL)) - return 5; - - return -1; - default: - fatal("Unknown transfer type: %i\n", type); - return -1; - } + return ret; } static int ide_get_timings(ide_t *ide, int type) { + int ret = 0; + ide_bm_t *bm = ide_boards[ide->board]->bm; + int ata_4 = (!ide_boards[ide->board]->force_ata3 && (bm != NULL)); + int timings[2][3] = { { 0, 0, 0 }, { 120, 120, 0 } }; + if (ide->type == IDE_ATAPI) - return ide->get_timings(!ide->sc->pad0 && !ide_boards[ide->board]->force_ata3 && (ide_bm[ide->board] != NULL), type); + ret = ide->get_timings(!IDE_ATAPI_IS_EARLY && ata_4, type); + else if (type <= TIMINGS_PIO_FC) + ret = timings[ata_4][type]; + else + fatal("Unknown transfer type: %i\n", type); - switch (type) { - case TIMINGS_DMA: - if (!ide_boards[ide->board]->force_ata3 && (ide_bm[ide->board] != NULL)) - return 120; - - return 0; - case TIMINGS_PIO: - if (!ide_boards[ide->board]->force_ata3 && (ide_bm[ide->board] != NULL)) - return 120; - - return 0; - case TIMINGS_PIO_FC: - return 0; - default: - fatal("Unknown transfer type: %i\n", type); - return 0; - } + return ret; } /** @@ -505,11 +473,13 @@ static void ide_hd_identify(ide_t *ide) { char device_identify[9] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', 0 }; + ide_bm_t *bm = ide_boards[ide->board]->bm; uint32_t d_hpc; uint32_t d_spt; uint32_t d_tracks; - uint64_t full_size = (((uint64_t) hdd[ide->hdd_num].tracks) * hdd[ide->hdd_num].hpc * hdd[ide->hdd_num].spt); + uint64_t full_size = (((uint64_t) hdd[ide->hdd_num].tracks) * + hdd[ide->hdd_num].hpc * hdd[ide->hdd_num].spt); device_identify[6] = (ide->hdd_num / 10) + 0x30; device_identify[7] = (ide->hdd_num % 10) + 0x30; @@ -538,13 +508,20 @@ ide_hd_identify(ide_t *ide) } ide_log("Default CHS translation: %i, %i, %i\n", ide->buffer[1], ide->buffer[3], ide->buffer[6]); - ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ - ide_padstr((char *) (ide->buffer + 23), EMU_VERSION_EX, 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), device_identify, 40); /* Model */ - ide->buffer[0] = (1 << 6); /*Fixed drive*/ - ide->buffer[20] = 3; /*Buffer type*/ - ide->buffer[21] = hdd[ide->hdd_num].cache.num_segments * hdd[ide->hdd_num].cache.segment_size; /*Buffer size*/ - ide->buffer[50] = 0x4000; /* Capabilities */ + /* Serial Number */ + ide_padstr((char *) (ide->buffer + 10), "", 20); + /* Firmware */ + ide_padstr((char *) (ide->buffer + 23), EMU_VERSION_EX, 8); + /* Model */ + ide_padstr((char *) (ide->buffer + 27), device_identify, 40); + /* Fixed drive */ + ide->buffer[0] = (1 << 6); + /* Buffer type */ + ide->buffer[20] = 3; + /* Buffer size */ + ide->buffer[21] = hdd[ide->hdd_num].cache.num_segments * hdd[ide->hdd_num].cache.segment_size; + /* Capabilities */ + ide->buffer[50] = 0x4000; ide->buffer[59] = ide->blocksize ? (ide->blocksize | 0x100) : 0; if ((ide->tracks >= 1024) || (ide->hpc > 16) || (ide->spt > 63)) { @@ -556,9 +533,10 @@ ide_hd_identify(ide_t *ide) ide_log("Full size: %" PRIu64 "\n", full_size); /* - Bit 0 = The fields reported in words 54-58 are valid; - Bit 1 = The fields reported in words 64-70 are valid; - Bit 2 = The fields reported in word 88 are valid. */ + Bit 0 = The fields reported in words 54-58 are valid; + Bit 1 = The fields reported in words 64-70 are valid; + Bit 2 = The fields reported in word 88 are valid. + */ ide->buffer[53] = 1; if (ide->cfg_spt != 0) { @@ -577,16 +555,19 @@ ide_hd_identify(ide_t *ide) } } - full_size = ((uint64_t) ide->buffer[54]) * ((uint64_t) ide->buffer[55]) * ((uint64_t) ide->buffer[56]); + full_size = ((uint64_t) ide->buffer[54]) * ((uint64_t) ide->buffer[55]) * + ((uint64_t) ide->buffer[56]); - ide->buffer[57] = full_size & 0xFFFF; /* Total addressable sectors (LBA) */ + /* Total addressable sectors (LBA) */ + ide->buffer[57] = full_size & 0xFFFF; ide->buffer[58] = (full_size >> 16) & 0x0FFF; ide_log("Current CHS translation: %i, %i, %i\n", ide->buffer[54], ide->buffer[55], ide->buffer[56]); } - ide->buffer[47] = hdd[ide->hdd_num].max_multiple_block | 0x8000; /*Max sectors on multiple transfer command*/ - if (!ide_boards[ide->board]->force_ata3 && ide_bm[ide->board]) { + /* Max sectors on multiple transfer command */ + ide->buffer[47] = hdd[ide->hdd_num].max_multiple_block | 0x8000; + if (!ide_boards[ide->board]->force_ata3 && (bm != NULL)) { ide->buffer[80] = 0x7e; /*ATA-1 to ATA-6 supported*/ ide->buffer[81] = 0x19; /*ATA-6 revision 3a supported*/ } else { @@ -604,13 +585,14 @@ ide_identify(ide_t *ide) int max_mdma; int max_udma; const ide_t *ide_other = ide_drives[ide->channel ^ 1]; + ide_bm_t *bm = ide_boards[ide->board]->bm; ide_log("IDE IDENTIFY or IDENTIFY PACKET DEVICE on board %i (channel %i)\n", ide->board, ide->channel); memset(ide->buffer, 0, 512); if (ide->type == IDE_ATAPI) - ide->identify(ide, !ide->sc->pad0 && !ide_boards[ide->board]->force_ata3 && (ide_bm[ide->board] != NULL)); + ide->identify(ide, !IDE_ATAPI_IS_EARLY && !ide_boards[ide->board]->force_ata3 && (bm != NULL)); else if (ide->type != IDE_NONE) ide_hd_identify(ide); else { @@ -668,7 +650,8 @@ ide_identify(ide_t *ide) } if ((max_sdma != -1) || (max_mdma != -1) || (max_udma != -1)) { - ide->buffer[49] |= 0x100; /* DMA supported */ + /* DMA supported */ + ide->buffer[49] |= 0x100; ide->buffer[52] = ide_get_timings(ide, TIMINGS_DMA); } @@ -708,9 +691,10 @@ ide_get_sector(ide_t *ide) heads = ide->cfg_hpc; sectors = ide->cfg_spt; - uint8_t sector = ide->sector ? ide->sector : 1; + uint8_t sector = ide->sector ? (ide->sector - 1) : 0; - return ((((off64_t) ide->cylinder * heads) + ide->head) * sectors) + (sector - 1); + return ((((off64_t) ide->tf->cylinder * heads) + (off64_t) ide->head) * sectors) + + (off64_t) sector; } } @@ -724,12 +708,12 @@ ide_next_sector(ide_t *ide) ide->lba_addr++; else { ide->sector++; - if (ide->sector == (ide->cfg_spt + 1)) { + if ((ide->sector == 0) || (ide->sector == (ide->cfg_spt + 1))) { ide->sector = 1; ide->head++; - if (ide->head == ide->cfg_hpc) { + if ((ide->head == 0) || (ide->head == ide->cfg_hpc)) { ide->head = 0; - ide->cylinder++; + ide->tf->cylinder++; } } } @@ -755,23 +739,16 @@ loadhd(ide_t *ide, int d, UNUSED(const char *fn)) void ide_set_signature(ide_t *ide) { + uint16_t ide_signatures[3] = { /* 0xffff */ 0x7f7f, 0x0000, 0xeb14 }; + ide->sector = 1; ide->head = 0; - if (ide->type == IDE_ATAPI) { - ide->sc->phase = 1; - ide->sc->request_length = 0xEB14; - ide->secount = ide->sc->phase; - ide->cylinder = ide->sc->request_length; - } else { - ide->secount = 1; -#if 0 - ide->cylinder = ((ide->type == IDE_HDD) ? 0 : 0xFFFF); -#endif - ide->cylinder = ((ide->type == IDE_HDD) ? 0 : 0x7F7F); - if (ide->type == IDE_HDD) - ide->drive = 0; - } + ide->tf->secount = 1; + ide->tf->cylinder = ide_signatures[ide->type]; + + if (ide->type == IDE_HDD) + ide->drive = 0; } static int @@ -783,10 +760,8 @@ ide_set_features(ide_t *ide) int submode; int max; - features = ide->cylprecomp; - features_data = ide->secount; - - ide_log("Features code %02X\n", features); + features = ide->tf->cylprecomp; + features_data = ide->tf->secount; ide_log("IDE %02X: Set features: %02X, %02X\n", ide->channel, features, features_data); @@ -803,7 +778,8 @@ ide_set_features(ide_t *ide) return 0; max = ide_get_max(ide, TYPE_PIO); ide->mdma_mode = (1 << max); - ide_log("IDE %02X: Setting DPIO mode: %02X, %08X\n", ide->channel, submode, ide->mdma_mode); + ide_log("IDE %02X: Setting DPIO mode: %02X, %08X\n", ide->channel, + submode, ide->mdma_mode); break; case 0x01: /* PIO mode */ @@ -811,7 +787,8 @@ ide_set_features(ide_t *ide) if (submode > max) return 0; ide->mdma_mode = (1 << submode); - ide_log("IDE %02X: Setting PIO mode: %02X, %08X\n", ide->channel, submode, ide->mdma_mode); + ide_log("IDE %02X: Setting PIO mode: %02X, %08X\n", ide->channel, + submode, ide->mdma_mode); break; case 0x02: /* Singleword DMA mode */ @@ -819,7 +796,8 @@ ide_set_features(ide_t *ide) if (submode > max) return 0; ide->mdma_mode = (1 << submode) | 0x100; - ide_log("IDE %02X: Setting SDMA mode: %02X, %08X\n", ide->channel, submode, ide->mdma_mode); + ide_log("IDE %02X: Setting SDMA mode: %02X, %08X\n", ide->channel, + submode, ide->mdma_mode); break; case 0x04: /* Multiword DMA mode */ @@ -827,7 +805,8 @@ ide_set_features(ide_t *ide) if (submode > max) return 0; ide->mdma_mode = (1 << submode) | 0x200; - ide_log("IDE %02X: Setting MDMA mode: %02X, %08X\n", ide->channel, submode, ide->mdma_mode); + ide_log("IDE %02X: Setting MDMA mode: %02X, %08X\n", ide->channel, + submode, ide->mdma_mode); break; case 0x08: /* Ultra DMA mode */ @@ -835,7 +814,8 @@ ide_set_features(ide_t *ide) if (submode > max) return 0; ide->mdma_mode = (1 << submode) | 0x300; - ide_log("IDE %02X: Setting UDMA mode: %02X, %08X\n", ide->channel, submode, ide->mdma_mode); + ide_log("IDE %02X: Setting UDMA mode: %02X, %08X\n", ide->channel, + submode, ide->mdma_mode); break; default: @@ -870,15 +850,15 @@ ide_set_sector(ide_t *ide, int64_t sector_num) unsigned int cyl; unsigned int r; if (ide->lba) { - ide->head = (sector_num >> 24); - ide->cylinder = (sector_num >> 8); - ide->sector = sector_num; + ide->head = (sector_num >> 24) & 0xff; + ide->tf->cylinder = (sector_num >> 8) & 0xffff; + ide->sector = sector_num & 0xff; } else { - cyl = sector_num / (hdd[ide->hdd_num].hpc * hdd[ide->hdd_num].spt); - r = sector_num % (hdd[ide->hdd_num].hpc * hdd[ide->hdd_num].spt); - ide->cylinder = cyl; - ide->head = ((r / hdd[ide->hdd_num].spt) & 0x0f); - ide->sector = (r % hdd[ide->hdd_num].spt) + 1; + cyl = sector_num / (hdd[ide->hdd_num].hpc * hdd[ide->hdd_num].spt); + r = sector_num % (hdd[ide->hdd_num].hpc * hdd[ide->hdd_num].spt); + ide->tf->cylinder = cyl & 0xffff; + ide->head = ((r / hdd[ide->hdd_num].spt) & 0x0f) & 0xff; + ide->sector = ((r % hdd[ide->hdd_num].spt) + 1) & 0xff; } } @@ -886,14 +866,16 @@ static void ide_zero(int d) { ide_t *dev; + if (ide_drives[d] == NULL) - ide_drives[d] = (ide_t *) malloc(sizeof(ide_t)); - memset(ide_drives[d], 0, sizeof(ide_t)); + ide_drives[d] = (ide_t *) calloc(1, sizeof(ide_t)); + dev = ide_drives[d]; + dev->tf = (ide_tf_t *) calloc(1, sizeof(ide_tf_t)); dev->channel = d; dev->type = IDE_NONE; dev->hdd_num = -1; - dev->atastat = DRDY_STAT | DSC_STAT; + dev->tf->atastat = DRDY_STAT | DSC_STAT; dev->service = 0; dev->board = d >> 1; dev->selected = !(d & 1); @@ -905,31 +887,31 @@ void ide_allocate_buffer(ide_t *dev) { if (dev->buffer == NULL) - dev->buffer = (uint16_t *) malloc(65536 * sizeof(uint16_t)); - memset(dev->buffer, 0, 65536 * sizeof(uint16_t)); + dev->buffer = (uint16_t *) calloc(1, 65536 * sizeof(uint16_t)); } void ide_atapi_attach(ide_t *ide) { + ide_bm_t *bm = ide_boards[ide->board]->bm; + if (ide->type != IDE_NONE) return; ide->type = IDE_ATAPI; ide_allocate_buffer(ide); ide_set_signature(ide); - ide->mdma_mode = (1 << ide->get_max(!ide->sc->pad0 && !ide_boards[ide->board]->force_ata3 && (ide_bm[ide->board] != NULL), TYPE_PIO)); - ide->error = 1; + ide->mdma_mode = (1 << ide->get_max(!IDE_ATAPI_IS_EARLY && + !ide_boards[ide->board]->force_ata3 && (bm != NULL), TYPE_PIO)); + ide->tf->error = 1; ide->cfg_spt = ide->cfg_hpc = 0; -#ifndef EARLY_ATAPI - ide->sc->status = 0; -#endif + if (!IDE_ATAPI_IS_EARLY) + ide->tf->atastat = 0; } void ide_set_callback(ide_t *ide, double callback) { - if (!ide) { ide_log("ide_set_callback(NULL): Set callback failed\n"); return; @@ -964,9 +946,9 @@ ide_set_board_callback(uint8_t board, double callback) static void ide_atapi_command_bus(ide_t *ide) { - ide->sc->status = BUSY_STAT; - ide->sc->phase = 1; - ide->sc->pos = 0; + ide->tf->atastat = BUSY_STAT; + ide->tf->phase = 1; + ide->tf->pos = 0; ide->sc->callback = 1.0 * IDE_TIME; ide_set_callback(ide, ide->sc->callback); } @@ -976,90 +958,85 @@ ide_atapi_callback(ide_t *ide) { int out; int ret = 0; + ide_bm_t *bm = ide_boards[ide->board]->bm; +#ifdef ENABLE_IDE_LOG + char *phases[7] = { "Idle", "Command", "Data in", "Data out", "Data in DMA", "Data out DMA", + "Complete" }; + char *phase; + + if (ide->sc->packet_status <= PHASE_COMPLETE) + phase = phases[ide->sc->packet_status]; + else if (ide->sc->packet_status == PHASE_ERROR) + phase = "Error"; + else if (ide->sc->packet_status == PHASE_NONE) + phase = "None"; + else + phase = "Unknown"; + + ide_log("Phase: %02X (%s)\n", ide->sc->packet_status, phase); +#endif switch (ide->sc->packet_status) { + default: + break; + case PHASE_IDLE: -#ifdef ENABLE_IDE_LOG - ide_log("PHASE_IDLE\n"); -#endif - ide->sc->pos = 0; - ide->sc->phase = 1; - ide->sc->status = READY_STAT | DRQ_STAT | (ide->sc->status & ERR_STAT); - return; + ide->tf->pos = 0; + ide->tf->phase = 1; + ide->tf->atastat = READY_STAT | DRQ_STAT | (ide->tf->atastat & ERR_STAT); + break; case PHASE_COMMAND: -#ifdef ENABLE_IDE_LOG - ide_log("PHASE_COMMAND\n"); -#endif - ide->sc->status = BUSY_STAT | (ide->sc->status & ERR_STAT); + ide->tf->atastat = BUSY_STAT | (ide->tf->atastat & ERR_STAT); if (ide->packet_command) { ide->packet_command(ide->sc, ide->sc->atapi_cdb); if ((ide->sc->packet_status == PHASE_COMPLETE) && (ide->sc->callback == 0.0)) ide_atapi_callback(ide); } - return; + break; case PHASE_COMPLETE: -#ifdef ENABLE_IDE_LOG - ide_log("PHASE_COMPLETE\n"); -#endif - ide->sc->status = READY_STAT; - ide->sc->phase = 3; + case PHASE_ERROR: + ide->tf->atastat = READY_STAT; + if (ide->sc->packet_status == PHASE_ERROR) + ide->tf->atastat |= ERR_STAT; + ide->tf->phase = 3; ide->sc->packet_status = PHASE_NONE; ide_irq_raise(ide); - return; + break; case PHASE_DATA_IN: case PHASE_DATA_OUT: -#ifdef ENABLE_IDE_LOG - ide_log("PHASE_DATA_IN or PHASE_DATA_OUT\n"); -#endif - ide->sc->status = READY_STAT | DRQ_STAT | (ide->sc->status & ERR_STAT); - ide->sc->phase = !(ide->sc->packet_status & 0x01) << 1; + ide->tf->atastat = READY_STAT | DRQ_STAT | (ide->tf->atastat & ERR_STAT); + ide->tf->phase = !(ide->sc->packet_status & 0x01) << 1; ide_irq_raise(ide); - return; + break; case PHASE_DATA_IN_DMA: case PHASE_DATA_OUT_DMA: -#ifdef ENABLE_IDE_LOG - ide_log("PHASE_DATA_IN_DMA or PHASE_DATA_OUT_DMA\n"); -#endif out = (ide->sc->packet_status & 0x01); - if (!ide->sc->pad0 && !ide_boards[ide->board]->force_ata3 && - ide_bm[ide->board] && ide_bm[ide->board]->dma) { - ret = ide_bm[ide->board]->dma(ide->sc->temp_buffer, ide->sc->packet_len, - out, ide_bm[ide->board]->priv); - } else { - /* DMA command without a bus master. */ - if (ide->bus_master_error) - ide->bus_master_error(ide->sc); - return; + if (!IDE_ATAPI_IS_EARLY && !ide_boards[ide->board]->force_ata3 && + (bm != NULL) && bm->dma) { + ret = bm->dma(ide->sc->temp_buffer, ide->sc->packet_len, out, bm->priv); } + /* Else, DMA command without a bus master, ret = 0 (default). */ - if (ret == 0) { - if (ide->bus_master_error) - ide->bus_master_error(ide->sc); - } else if (ret == 1) { - if (out && ide->phase_data_out) - ret = ide->phase_data_out(ide->sc); - else if (!out && ide->command_stop) - ide->command_stop(ide->sc); + switch (ret) { + case 0: + if (ide->bus_master_error) + ide->bus_master_error(ide->sc); + break; + case 1: + if (out && ide->phase_data_out) + ret = ide->phase_data_out(ide->sc); + else if (!out && ide->command_stop) + ide->command_stop(ide->sc); - if ((ide->sc->packet_status == PHASE_COMPLETE) && (ide->sc->callback == 0.0)) - ide_atapi_callback(ide); - } else if (ret == 2) - ide_atapi_command_bus(ide); - - return; - case PHASE_ERROR: -#ifdef ENABLE_IDE_LOG - ide_log("PHASE_ERROR\n"); -#endif - ide->sc->status = READY_STAT | ERR_STAT; - ide->sc->phase = 3; - ide->sc->packet_status = PHASE_NONE; - ide_irq_raise(ide); - return; - default: - ide_log("PHASE_UNKNOWN %02X\n", ide->sc->packet_status); - return; + if ((ide->sc->packet_status == PHASE_COMPLETE) && (ide->sc->callback == 0.0)) + ide_atapi_callback(ide); + break; + case 2: + ide_atapi_command_bus(ide); + break; + } + break; } } @@ -1071,12 +1048,12 @@ ide_atapi_pio_request(ide_t *ide, uint8_t out) ide_irq_lower(ide); - dev->status = BSY_STAT; + ide->tf->atastat = BSY_STAT; - if (dev->pos >= dev->packet_len) { - ide_log("%i bytes %s, command done\n", dev->pos, out ? "written" : "read"); + if (ide->tf->pos >= dev->packet_len) { + ide_log("%i bytes %s, command done\n", ide->tf->pos, out ? "written" : "read"); - dev->pos = dev->request_pos = 0; + ide->tf->pos = dev->request_pos = 0; if (out && ide->phase_data_out) ide->phase_data_out(dev); else if (!out && ide->command_stop) @@ -1085,23 +1062,23 @@ ide_atapi_pio_request(ide_t *ide, uint8_t out) if ((ide->sc->packet_status == PHASE_COMPLETE) && (ide->sc->callback == 0.0)) ide_atapi_callback(ide); } else { - ide_log("%i bytes %s, %i bytes are still left\n", dev->pos, - out ? "written" : "read", dev->packet_len - dev->pos); + ide_log("%i bytes %s, %i bytes are still left\n", ide->tf->pos, + out ? "written" : "read", dev->packet_len - ide->tf->pos); /* If less than (packet length) bytes are remaining, update packet length accordingly. */ - if ((dev->packet_len - dev->pos) < (dev->max_transfer_len)) { - dev->max_transfer_len = dev->packet_len - dev->pos; + if ((dev->packet_len - ide->tf->pos) < (dev->max_transfer_len)) { + dev->max_transfer_len = dev->packet_len - ide->tf->pos; /* Also update the request length so the host knows how many bytes to transfer. */ - dev->request_length = dev->max_transfer_len; + ide->tf->request_length = dev->max_transfer_len; } ide_log("CD-ROM %i: Packet length %i, request length %i\n", dev->id, dev->packet_len, dev->max_transfer_len); dev->packet_status = PHASE_DATA_IN | out; - dev->status = BSY_STAT; - dev->phase = 1; + ide->tf->atastat = BSY_STAT; + ide->tf->phase = 1; ide_atapi_callback(ide); ide_set_callback(ide, 0.0); @@ -1109,169 +1086,122 @@ ide_atapi_pio_request(ide_t *ide, uint8_t out) } } -static uint32_t +static uint16_t ide_atapi_packet_read(ide_t *ide, int length) { scsi_common_t *dev = ide->sc; - const uint16_t *bufferw; - const uint32_t *bufferl; + uint16_t ret = 0; - uint32_t temp = 0; + if (dev && dev->temp_buffer && (dev->packet_status == PHASE_DATA_IN)) { + ide_log("PHASE_DATA_IN read: %i, %i, %i, %i\n", + dev->request_pos, dev->max_transfer_len, ide->tf->pos, dev->packet_len); - if (!dev || !dev->temp_buffer || (dev->packet_status != PHASE_DATA_IN)) - return 0; + bufferw = (uint16_t *) dev->temp_buffer; - if (dev->packet_status == PHASE_DATA_IN) - ide_log("PHASE_DATA_IN read: %i, %i, %i, %i\n", dev->request_pos, dev->max_transfer_len, dev->pos, dev->packet_len); - - bufferw = (uint16_t *) dev->temp_buffer; - bufferl = (uint32_t *) dev->temp_buffer; - - /* Make sure we return a 0 and don't attempt to read from the buffer if we're transferring bytes beyond it, - which can happen when issuing media access commands with an allocated length below minimum request length - (which is 1 sector = 2048 bytes). */ - switch (length) { - case 1: - temp = (dev->pos < dev->packet_len) ? dev->temp_buffer[dev->pos] : 0; - dev->pos++; - dev->request_pos++; - break; - case 2: - temp = (dev->pos < dev->packet_len) ? bufferw[dev->pos >> 1] : 0; - dev->pos += 2; + /* Make sure we return a 0 and don't attempt to read from the buffer if + we're transferring bytes beyond it, which can happen when issuing media + access commands with an allocated length below minimum request length + (which is 1 sector = 2048 bytes). */ + if (length == 2) { + ret = (ide->tf->pos < dev->packet_len) ? bufferw[ide->tf->pos >> 1] : 0; + ide->tf->pos += 2; dev->request_pos += 2; - break; - case 4: - temp = (dev->pos < dev->packet_len) ? bufferl[dev->pos >> 2] : 0; - dev->pos += 4; - dev->request_pos += 4; - break; - default: - return 0; - } + } else { + ret = (ide->tf->pos < dev->packet_len) ? dev->temp_buffer[ide->tf->pos] : 0; + ide->tf->pos++; + dev->request_pos++; + } - if (dev->packet_status == PHASE_DATA_IN) { - if ((dev->request_pos >= dev->max_transfer_len) || (dev->pos >= dev->packet_len)) { + if ((dev->request_pos >= dev->max_transfer_len) || (ide->tf->pos >= dev->packet_len)) { /* Time for a DRQ. */ ide_atapi_pio_request(ide, 0); } - return temp; - } else - return 0; + } + + return ret; } static void -ide_atapi_packet_write(ide_t *ide, uint32_t val, int length) +ide_atapi_packet_write(ide_t *ide, uint16_t val, int length) { scsi_common_t *dev = ide->sc; - uint8_t *bufferb; - uint16_t *bufferw; - uint32_t *bufferl; + uint8_t *bufferb = NULL; + uint16_t *bufferw = NULL; - if (!dev) - return; - - if (dev->packet_status == PHASE_IDLE) - bufferb = dev->atapi_cdb; - else { - if (dev->temp_buffer) + if (dev) { + if (dev->packet_status == PHASE_IDLE) + bufferb = dev->atapi_cdb; + else if (dev->temp_buffer) bufferb = dev->temp_buffer; - else - return; + + bufferw = (uint16_t *) bufferb; } - bufferw = (uint16_t *) bufferb; - bufferl = (uint32_t *) bufferb; - - if (dev->packet_status == PHASE_DATA_IN) - return; - - switch (length) { - case 1: - bufferb[dev->pos] = val & 0xff; - dev->pos++; - dev->request_pos++; - break; - case 2: - bufferw[dev->pos >> 1] = val & 0xffff; - dev->pos += 2; + if ((bufferb != NULL) && (dev->packet_status != PHASE_DATA_IN)) { + if (length == 2) { + bufferw[ide->tf->pos >> 1] = val & 0xffff; + ide->tf->pos += 2; dev->request_pos += 2; - break; - case 4: - bufferl[dev->pos >> 2] = val; - dev->pos += 4; - dev->request_pos += 4; - break; - default: - return; - } + } else { + bufferb[ide->tf->pos] = val & 0xff; + ide->tf->pos++; + dev->request_pos++; + } - if (dev->packet_status == PHASE_DATA_OUT) { - if ((dev->request_pos >= dev->max_transfer_len) || (dev->pos >= dev->packet_len)) { - /* Time for a DRQ. */ - ide_atapi_pio_request(ide, 1); + if (dev->packet_status == PHASE_DATA_OUT) { + if ((dev->request_pos >= dev->max_transfer_len) || (ide->tf->pos >= dev->packet_len)) { + /* Time for a DRQ. */ + ide_atapi_pio_request(ide, 1); + } + } else if (dev->packet_status == PHASE_IDLE) { + if (ide->tf->pos >= 12) { + ide->tf->pos = 0; + ide->tf->atastat = BSY_STAT; + dev->packet_status = PHASE_COMMAND; + ide_atapi_callback(ide); + } } - return; - } else if (dev->packet_status == PHASE_IDLE) { - if (dev->pos >= 12) { - dev->pos = 0; - dev->status = BSY_STAT; - dev->packet_status = PHASE_COMMAND; - ide_atapi_callback(ide); - } - return; } } -void -ide_write_data(ide_t *ide, uint32_t val, int length) +static void +ide_write_data(ide_t *ide, uint16_t val, int length) { uint8_t *idebufferb = (uint8_t *) ide->buffer; uint16_t *idebufferw = ide->buffer; - uint32_t *idebufferl = (uint32_t *) ide->buffer; if (ide->command == WIN_PACKETCMD) { - ide->pos = 0; - if (ide->type == IDE_ATAPI) ide_atapi_packet_write(ide, val, length); + else + ide->tf->pos = 0; } else { - switch (length) { - case 1: - idebufferb[ide->pos] = val & 0xff; - ide->pos++; - break; - case 2: - idebufferw[ide->pos >> 1] = val & 0xffff; - ide->pos += 2; - break; - case 4: - idebufferl[ide->pos >> 2] = val; - ide->pos += 4; - break; - default: - return; + if (length == 2) { + idebufferw[ide->tf->pos >> 1] = val & 0xffff; + ide->tf->pos += 2; + } else { + idebufferb[ide->tf->pos] = val & 0xff; + ide->tf->pos++; } - if (ide->pos >= 512) { - ide->pos = 0; - ide->atastat = BSY_STAT; + if (ide->tf->pos >= 512) { + ide->tf->pos = 0; + ide->tf->atastat = BSY_STAT; double seek_time = hdd_timing_write(&hdd[ide->hdd_num], ide_get_sector(ide), 1); double xfer_time = ide_get_xfer_time(ide, 512); double wait_time = seek_time + xfer_time; if (ide->command == WIN_WRITE_MULTIPLE) { - if ((ide->blockcount + 1) >= ide->blocksize || ide->secount == 1) { + if ((ide->blockcount + 1) >= ide->blocksize || ide->tf->secount == 1) { ide_set_callback(ide, seek_time + xfer_time + ide->pending_delay); ide->pending_delay = 0; } else { ide->pending_delay += wait_time; ide_callback(ide); } - } else { + } else ide_set_callback(ide, wait_time); - } } } } @@ -1287,7 +1217,7 @@ ide_writew(uint16_t addr, uint16_t val, void *priv) ch = dev->cur_dev; ide = ide_drives[ch]; - ide_log("ide_writew %04X %04X from %04X(%08X):%08X\n", addr, val, CS, cs, cpu_state.pc); + ide_log("ide_writew(%04X, %04X, %08X)\n", addr, val, priv); addr &= 0x7; @@ -1319,7 +1249,7 @@ ide_writel(uint16_t addr, uint32_t val, void *priv) ch = dev->cur_dev; ide = ide_drives[ch]; - ide_log("ide_writel %04X %08X from %04X(%08X):%08X\n", addr, val, CS, cs, cpu_state.pc); + ide_log("ide_writel(%04X, %08X, %08X)\n", addr, val, priv); addr &= 0x7; @@ -1368,14 +1298,14 @@ ide_write_devctl(UNUSED(uint16_t addr), uint8_t val, void *priv) ide = ide_drives[ch]; ide_other = ide_drives[ch ^ 1]; - ide_log("ide_write_devctl %04X %02X from %04X(%08X):%08X\n", addr, val, CS, cs, cpu_state.pc); + ide_log("ide_write_devctl(%04X, %02X, %08X)\n", addr, val, priv); if ((ide->type == IDE_NONE) && (ide_other->type == IDE_NONE)) return; dev->diag = 0; - if ((val & 4) && !(ide->fdisk & 4)) { + if ((val & 4) && !(dev->devctl & 4)) { /* Reset toggled from 0 to 1, initiate reset procedure. */ if (ide->type == IDE_ATAPI) ide->sc->callback = 0.0; @@ -1386,44 +1316,28 @@ ide_write_devctl(UNUSED(uint16_t addr), uint8_t val, void *priv) some 286 and 386 machines error out. */ if (!(ch & 1)) { if (ide->type != IDE_NONE) { - ide->atastat = BSY_STAT; - ide->error = 1; - if (ide->type == IDE_ATAPI) { - ide->sc->status = BSY_STAT; - ide->sc->error = 1; - } + ide->tf->atastat = BSY_STAT; + ide->tf->error = 1; } if (ide_other->type != IDE_NONE) { - ide_other->atastat = BSY_STAT; - ide_other->error = 1; - if (ide_other->type == IDE_ATAPI) { - ide_other->sc->status = BSY_STAT; - ide_other->sc->error = 1; - } + ide_other->tf->atastat = BSY_STAT; + ide_other->tf->error = 1; } } - } else if (!(val & 4) && (ide->fdisk & 4)) { + } else if (!(val & 4) && (dev->devctl & 4)) { /* Reset toggled from 1 to 0. */ if (!(ch & 1)) { /* Currently active device is 0, use the device 0 reset protocol. */ /* Device 0. */ dev_reset(ide); - ide->atastat = BSY_STAT; - ide->error = 1; - if (ide->type == IDE_ATAPI) { - ide->sc->status = BSY_STAT; - ide->sc->error = 1; - } + ide->tf->atastat = BSY_STAT; + ide->tf->error = 1; /* Device 1. */ dev_reset(ide_other); - ide_other->atastat = BSY_STAT; - ide_other->error = 1; - if (ide_other->type == IDE_ATAPI) { - ide_other->sc->status = BSY_STAT; - ide_other->sc->error = 1; - } + ide_other->tf->atastat = BSY_STAT; + ide_other->tf->error = 1; /* Fire the timer. */ dev->diag = 0; @@ -1434,12 +1348,8 @@ ide_write_devctl(UNUSED(uint16_t addr), uint8_t val, void *priv) } else { /* Currently active device is 1, simply reset the status and the active device. */ dev_reset(ide); - ide->atastat = DRDY_STAT | DSC_STAT; - ide->error = 1; - if (ide->type == IDE_ATAPI) { - ide->sc->status = DRDY_STAT | DSC_STAT; - ide->sc->error = 1; - } + ide->tf->atastat = DRDY_STAT | DSC_STAT; + ide->tf->error = 1; dev->cur_dev &= ~1; ch = dev->cur_dev; @@ -1451,111 +1361,114 @@ ide_write_devctl(UNUSED(uint16_t addr), uint8_t val, void *priv) } } - old = ide->fdisk; - ide->fdisk = ide_other->fdisk = val; - if (!(val & 0x02) && (old & 0x02) && ide->irqstat) - ide_irq_update(ide); + old = dev->devctl; + dev->devctl = val; + if (!(val & 0x02) && (old & 0x02)) + ide_irq_update(ide_boards[ide->board]); +} + +static void +ide_reset_registers(ide_t *ide) +{ + uint16_t ide_signatures[3] = { /* 0xffff */ 0x7f7f, 0x0000, 0xeb14 }; + + ide->tf->atastat = DRDY_STAT | DSC_STAT; + ide->tf->error = 1; + ide->tf->secount = 1; + ide->tf->cylinder = ide_signatures[ide->type]; + + ide->sector = 1; + ide->head = 0; + ide->reset = 0; + + if (ide->type == IDE_ATAPI) + ide->sc->callback = 0.0; + + ide_set_callback(ide, 0.0); } void ide_writeb(uint16_t addr, uint8_t val, void *priv) { ide_board_t *dev = (ide_board_t *) priv; - ide_t *ide; ide_t *ide_other; int ch; + int absent = 0; + int bad = 0; + int reset = 0; ch = dev->cur_dev; ide = ide_drives[ch]; ide_other = ide_drives[ch ^ 1]; - ide_log("ide_write %04X %02X from %04X(%08X):%08X\n", addr, val, CS, cs, cpu_state.pc); + /* Absent and is master or both are absent. */ + if ((ide->type == IDE_NONE) && ((ide_drives[ch ^ 1]->type == IDE_NONE) || !(ch & 1))) + absent = 1; + /* Absent and is slave and master is present. */ + else if ((ide->type == IDE_NONE) && (ch & 1)) + absent = 2; + + ide_log("ide_writeb(%04X, %02X, %08X)\n", addr, val, priv); addr &= 0x7; - if ((ide->type == IDE_NONE) && ((addr == 0x0) || (addr == 0x7))) - return; - - switch (addr) { + if ((absent != 1) || ((addr != 0x0) && (addr != 0x7))) switch (addr) { case 0x0: /* Data */ - ide_write_data(ide, val | (val << 8), 2); - return; + if (absent == 0) + ide_write_data(ide, val | (val << 8), 2); + break; /* Note to self: for ATAPI, bit 0 of this is DMA if set, PIO if clear. */ case 0x1: /* Features */ - if (ide->type == IDE_ATAPI) { + ide->tf->cylprecomp = val; + if (ide->type == IDE_ATAPI) ide_log("ATAPI transfer mode: %s\n", (val & 1) ? "DMA" : "PIO"); - ide->sc->features = val; - } - ide->cylprecomp = val; /* The ATA-3 specification says this register is the parameter for the command and is unclear as to whether or not it's written to both devices at once. Writing it to both devices at once breaks CD boot on the AMI Apollo. */ #ifdef WRITE_PARAM_TO_BOTH_DEVICES - if (ide_other->type == IDE_ATAPI) - ide_other->sc->features = val; - ide_other->cylprecomp = val; + ide_other->tf->cylprecomp = val; #endif return; case 0x2: /* Sector count */ - if (ide->type == IDE_ATAPI) { - ide_log("Sector count write: %i\n", val); - ide->sc->phase = val; - } - ide->secount = val; - - if (ide_other->type == IDE_ATAPI) { - ide_log("Other sector count write: %i\n", val); - ide_other->sc->phase = val; - } - ide_other->secount = val; - return; + ide->tf->secount = val; + ide_other->tf->secount = val; + break; case 0x3: /* Sector */ ide->sector = val; - ide->lba_addr = (ide->lba_addr & 0xFFFFF00) | val; + ide->lba_addr = (ide->lba_addr & 0xfffff00) | val; ide_other->sector = val; - ide_other->lba_addr = (ide_other->lba_addr & 0xFFFFF00) | val; - return; + ide_other->lba_addr = (ide_other->lba_addr & 0xfffff00) | val; + break; case 0x4: /* Cylinder low */ - if (ide->type == IDE_ATAPI) { - ide->sc->request_length &= 0xFF00; - ide->sc->request_length |= val; - } - ide->cylinder = (ide->cylinder & 0xFF00) | val; - ide->lba_addr = (ide->lba_addr & 0xFFF00FF) | (val << 8); + ide->tf->cylinder = (ide->tf->cylinder & 0xff00) | val; + ide->lba_addr = (ide->lba_addr & 0xfff00ff) | (val << 8); - if (ide_other->type == IDE_ATAPI) { - ide_other->sc->request_length &= 0xFF00; - ide_other->sc->request_length |= val; - } - ide_other->cylinder = (ide_other->cylinder & 0xFF00) | val; - ide_other->lba_addr = (ide_other->lba_addr & 0xFFF00FF) | (val << 8); - return; + ide_other->tf->cylinder = (ide_other->tf->cylinder & 0xff00) | val; + ide_other->lba_addr = (ide_other->lba_addr & 0xfff00ff) | (val << 8); + break; case 0x5: /* Cylinder high */ - if (ide->type == IDE_ATAPI) { - ide->sc->request_length &= 0xFF; - ide->sc->request_length |= (val << 8); - } - ide->cylinder = (ide->cylinder & 0xFF) | (val << 8); - ide->lba_addr = (ide->lba_addr & 0xF00FFFF) | (val << 16); + ide->tf->cylinder = (ide->tf->cylinder & 0xff) | (val << 8); + ide->lba_addr = (ide->lba_addr & 0xf00ffff) | (val << 16); - if (ide_other->type == IDE_ATAPI) { - ide_other->sc->request_length &= 0xFF; - ide_other->sc->request_length |= (val << 8); - } - ide_other->cylinder = (ide_other->cylinder & 0xFF) | (val << 8); - ide_other->lba_addr = (ide_other->lba_addr & 0xF00FFFF) | (val << 16); - return; + ide_other->tf->cylinder = (ide_other->tf->cylinder & 0xff) | (val << 8); + ide_other->lba_addr = (ide_other->lba_addr & 0xf00ffff) | (val << 16); + break; case 0x6: /* Drive/Head */ if (ch != ((val >> 4) & 1) + (ide->board << 1)) { + if (!ide->reset && !ide_other->reset && ide->irqstat) { + ide_irq_lower(ide); + ide->irqstat = 1; + } + ide_boards[ide->board]->cur_dev = ((val >> 4) & 1) + (ide->board << 1); ch = ide_boards[ide->board]->cur_dev; @@ -1566,87 +1479,60 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) ide_other->selected = 0; if (ide->reset || ide_other->reset) { - ide->atastat = ide_other->atastat = DRDY_STAT | DSC_STAT; - ide->error = ide_other->error = 1; - ide->secount = ide_other->secount = 1; - ide->sector = ide_other->sector = 1; - ide->head = ide_other->head = 0; - ide->cylinder = ide_other->cylinder = 0; - ide->reset = ide_other->reset = 0; + ide_reset_registers(ide); + ide_reset_registers(ide_other); - if (ide->type == IDE_ATAPI) { - ide->sc->status = DRDY_STAT | DSC_STAT; - ide->sc->error = 1; - ide->sc->phase = 1; - ide->sc->request_length = 0xEB14; - ide->sc->callback = 0.0; - ide->cylinder = 0xEB14; - } - - if (ide_other->type == IDE_ATAPI) { - ide_other->sc->status = DRDY_STAT | DSC_STAT; - ide_other->sc->error = 1; - ide_other->sc->phase = 1; - ide_other->sc->request_length = 0xEB14; - ide_other->sc->callback = 0.0; - ide_other->cylinder = 0xEB14; - } - - ide_set_callback(ide, 0.0); - ide_set_callback(ide_other, 0.0); ide_set_board_callback(ide->board, 0.0); - return; - } + reset = 1; + } else + ide_irq_update(ide_boards[ide->board]); } - ide->head = val & 0xF; - ide->lba = val & 0x40; - ide_other->head = val & 0xF; - ide_other->lba = val & 0x40; + if (!reset) { + ide->head = ide_other->head = val & 0xF; + ide->lba = ide_other->lba = val & 0x40; - ide->lba_addr = (ide->lba_addr & 0x0FFFFFF) | ((val & 0xF) << 24); - ide_other->lba_addr = (ide_other->lba_addr & 0x0FFFFFF) | ((val & 0xF) << 24); - - ide_irq_update(ide); - return; + ide->lba_addr = (ide->lba_addr & 0x0FFFFFF) | ((val & 0xF) << 24); + ide_other->lba_addr = (ide_other->lba_addr & 0x0FFFFFF) | ((val & 0xF) << 24); + } + break; case 0x7: /* Command register */ - if (ide->type == IDE_NONE) - return; + if (absent == 2) + break; ide_irq_lower(ide); ide->command = val; - ide->error = 0; - if (ide->type == IDE_ATAPI) - ide->sc->error = 0; - - if (((val >= WIN_RECAL) && (val <= 0x1F)) || ((val >= WIN_SEEK) && (val <= 0x7F))) { - if (ide->type == IDE_ATAPI) - ide->sc->status = DRDY_STAT; - else - ide->atastat = READY_STAT | BSY_STAT; - - if (ide->type == IDE_ATAPI) { - ide->sc->callback = 100.0 * IDE_TIME; - ide_set_callback(ide, 100.0 * IDE_TIME); - } else { - double seek_time = hdd_seek_get_time(&hdd[ide->hdd_num], ide_get_sector(ide), HDD_OP_SEEK, 0, 0.0); - ide_set_callback(ide, seek_time); - } - return; - } + ide->tf->error = 0; switch (val) { + case WIN_RECAL ... 0x1F: + case WIN_SEEK ... 0x7F: + if (ide->type == IDE_ATAPI) + ide->tf->atastat = DRDY_STAT; + else + ide->tf->atastat = READY_STAT | BSY_STAT; + + if (ide->type == IDE_ATAPI) { + ide->sc->callback = 100.0 * IDE_TIME; + ide_set_callback(ide, 100.0 * IDE_TIME); + } else { + double seek_time = hdd_seek_get_time(&hdd[ide->hdd_num], + ide_get_sector(ide), HDD_OP_SEEK, 0, 0.0); + ide_set_callback(ide, seek_time); + } + break; + case WIN_SRST: /* ATAPI Device Reset */ if (ide->type == IDE_ATAPI) { - ide->sc->status = BSY_STAT; + ide->tf->atastat = BSY_STAT; ide->sc->callback = 100.0 * IDE_TIME; } else - ide->atastat = DRDY_STAT; + ide->tf->atastat = DRDY_STAT; ide_set_callback(ide, 100.0 * IDE_TIME); - return; + break; case WIN_READ_MULTIPLE: /* Fatal removed in accordance with the official ATAPI reference: @@ -1661,34 +1547,36 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) case WIN_READ_NORETRY: case WIN_READ_DMA: case WIN_READ_DMA_ALT: - if (ide->type == IDE_ATAPI) { - ide->sc->status = BSY_STAT; + ide->tf->atastat = BSY_STAT; + + if (ide->type == IDE_ATAPI) ide->sc->callback = 200.0 * IDE_TIME; - } else - ide->atastat = BSY_STAT; if (ide->type == IDE_HDD) { ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); uint32_t sec_count; double wait_time; if ((val == WIN_READ_DMA) || (val == WIN_READ_DMA_ALT)) { - // TODO make DMA timing more accurate - sec_count = ide->secount ? ide->secount : 256; - double seek_time = hdd_timing_read(&hdd[ide->hdd_num], ide_get_sector(ide), sec_count); + /* TODO make DMA timing more accurate */ + sec_count = ide->tf->secount ? ide->tf->secount : 256; + double seek_time = hdd_timing_read(&hdd[ide->hdd_num], + ide_get_sector(ide), sec_count); double xfer_time = ide_get_xfer_time(ide, 512 * sec_count); wait_time = seek_time > xfer_time ? seek_time : xfer_time; } else if ((val == WIN_READ_MULTIPLE) && (ide->blocksize > 0)) { - sec_count = ide->secount ? ide->secount : 256; + sec_count = ide->tf->secount ? ide->tf->secount : 256; if (sec_count > ide->blocksize) sec_count = ide->blocksize; - double seek_time = hdd_timing_read(&hdd[ide->hdd_num], ide_get_sector(ide), sec_count); + double seek_time = hdd_timing_read(&hdd[ide->hdd_num], + ide_get_sector(ide), sec_count); double xfer_time = ide_get_xfer_time(ide, 512 * sec_count); wait_time = seek_time + xfer_time; } else if ((val == WIN_READ_MULTIPLE) && (ide->blocksize == 0)) wait_time = 200.0; else { sec_count = 1; - double seek_time = hdd_timing_read(&hdd[ide->hdd_num], ide_get_sector(ide), sec_count); + double seek_time = hdd_timing_read(&hdd[ide->hdd_num], + ide_get_sector(ide), sec_count); double xfer_time = ide_get_xfer_time(ide, 512 * sec_count); wait_time = seek_time + xfer_time; } @@ -1696,7 +1584,7 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) } else ide_set_callback(ide, 200.0 * IDE_TIME); ide->do_initial_read = 1; - return; + break; case WIN_WRITE_MULTIPLE: /* Fatal removed for the same reason as for WIN_READ_MULTIPLE. */ @@ -1708,14 +1596,9 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) case WIN_WRITE: case WIN_WRITE_NORETRY: - if (ide->type == IDE_ATAPI) { - ide->sc->status = DRQ_STAT | DSC_STAT | DRDY_STAT; - ide->sc->pos = 0; - } else { - ide->atastat = DRQ_STAT | DSC_STAT | DRDY_STAT; - ide->pos = 0; - } - return; + ide->tf->atastat = DRQ_STAT | DSC_STAT | DRDY_STAT; + ide->tf->pos = 0; + break; case WIN_WRITE_DMA: case WIN_WRITE_DMA_ALT: @@ -1724,46 +1607,47 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) case WIN_IDENTIFY: /* Identify Device */ case WIN_SET_FEATURES: /* Set Features */ case WIN_READ_NATIVE_MAX: - if (ide->type == IDE_ATAPI) { - ide->sc->status = BSY_STAT; + ide->tf->atastat = BSY_STAT; + + if (ide->type == IDE_ATAPI) ide->sc->callback = 200.0 * IDE_TIME; - } else - ide->atastat = BSY_STAT; if ((ide->type == IDE_HDD) && ((val == WIN_WRITE_DMA) || (val == WIN_WRITE_DMA_ALT))) { - uint32_t sec_count = ide->secount ? ide->secount : 256; - double seek_time = hdd_timing_read(&hdd[ide->hdd_num], ide_get_sector(ide), sec_count); + uint32_t sec_count = ide->tf->secount ? ide->tf->secount : 256; + double seek_time = hdd_timing_read(&hdd[ide->hdd_num], + ide_get_sector(ide), sec_count); double xfer_time = ide_get_xfer_time(ide, 512 * sec_count); double wait_time = seek_time > xfer_time ? seek_time : xfer_time; ide_set_callback(ide, wait_time); - } else if ((ide->type == IDE_HDD) && ((val == WIN_VERIFY) || (val == WIN_VERIFY_ONCE))) { - uint32_t sec_count = ide->secount ? ide->secount : 256; - double seek_time = hdd_timing_read(&hdd[ide->hdd_num], ide_get_sector(ide), sec_count); + } else if ((ide->type == IDE_HDD) && ((val == WIN_VERIFY) || + (val == WIN_VERIFY_ONCE))) { + uint32_t sec_count = ide->tf->secount ? ide->tf->secount : 256; + double seek_time = hdd_timing_read(&hdd[ide->hdd_num], + ide_get_sector(ide), sec_count); ide_set_callback(ide, seek_time + ide_get_xfer_time(ide, 2)); } else if ((val == WIN_IDENTIFY) || (val == WIN_SET_FEATURES)) ide_callback(ide); else ide_set_callback(ide, 200.0 * IDE_TIME); - return; + break; case WIN_FORMAT: if (ide->type == IDE_ATAPI) - goto ide_bad_command; + bad = 1; else { - ide->atastat = DRQ_STAT; - ide->pos = 0; + ide->tf->atastat = DRQ_STAT; + ide->tf->pos = 0; } - return; + break; case WIN_SPECIFY: /* Initialize Drive Parameters */ - if (ide->type == IDE_ATAPI) { - ide->sc->status = BSY_STAT; + ide->tf->atastat = BSY_STAT; + + if (ide->type == IDE_ATAPI) ide->sc->callback = 30.0 * IDE_TIME; - } else - ide->atastat = BSY_STAT; ide_set_callback(ide, 30.0 * IDE_TIME); - return; + break; case WIN_DRIVE_DIAGNOSTICS: /* Execute Drive Diagnostics */ dev->cur_dev &= ~1; @@ -1774,21 +1658,13 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) /* Device 0. */ dev_reset(ide); - ide->atastat = BSY_STAT; - ide->error = 1; - if (ide->type == IDE_ATAPI) { - ide->sc->status = BSY_STAT; - ide->sc->error = 1; - } + ide->tf->atastat = BSY_STAT; + ide->tf->error = 1; /* Device 1. */ dev_reset(ide_other); - ide_other->atastat = BSY_STAT; - ide_other->error = 1; - if (ide_other->type == IDE_ATAPI) { - ide_other->sc->status = BSY_STAT; - ide_other->sc->error = 1; - } + ide_other->tf->atastat = BSY_STAT; + ide_other->tf->error = 1; /* Fire the timer. */ dev->diag = 1; @@ -1796,51 +1672,45 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) ide_set_callback(ide, 0.0); ide_set_callback(ide_other, 0.0); ide_set_board_callback(ide->board, 200.0 * IDE_TIME); - return; + break; case WIN_PIDENTIFY: /* Identify Packet Device */ case WIN_SET_MULTIPLE_MODE: /* Set Multiple Mode */ case WIN_NOP: case WIN_STANDBYNOW1: case WIN_IDLENOW1: - case WIN_SETIDLE1: /* Idle */ + case WIN_SETIDLE1: /* Idle */ case WIN_CHECKPOWERMODE1: case WIN_SLEEP1: - if (ide->type == IDE_ATAPI) - ide->sc->status = BSY_STAT; - else - ide->atastat = BSY_STAT; + ide->tf->atastat = BSY_STAT; ide_callback(ide); - return; + break; case WIN_PACKETCMD: /* ATAPI Packet */ /* Skip the command callback wait, and process immediately. */ + ide->tf->pos = 0; if (ide->type == IDE_ATAPI) { ide->sc->packet_status = PHASE_IDLE; - ide->sc->pos = 0; - ide->sc->phase = 1; - ide->sc->status = DRDY_STAT | DRQ_STAT; + ide->tf->secount = 1; + ide->tf->atastat = DRDY_STAT | DRQ_STAT; if (ide->interrupt_drq) ide_irq_raise(ide); /* Interrupt DRQ, requires IRQ on any DRQ. */ } else { - ide->atastat = BSY_STAT; + ide->tf->atastat = BSY_STAT; ide_set_callback(ide, 200.0 * IDE_TIME); - ide->pos = 0; } - return; + break; - case 0xF0: + case 0xf0: default: -ide_bad_command: - if (ide->type == IDE_ATAPI) { - ide->sc->status = DRDY_STAT | ERR_STAT | DSC_STAT; - ide->sc->error = ABRT_ERR; - } else { - ide->atastat = DRDY_STAT | ERR_STAT | DSC_STAT; - ide->error = ABRT_ERR; - } - ide_irq_raise(ide); - return; + bad = 1; + break; + } + + if (bad) { + ide->tf->atastat = DRDY_STAT | ERR_STAT | DSC_STAT; + ide->tf->error = ABRT_ERR; + ide_irq_raise(ide); } return; @@ -1849,136 +1719,130 @@ ide_bad_command: } } -static uint32_t +static uint16_t ide_read_data(ide_t *ide, int length) { - uint32_t temp = 0; - - if (!ide->buffer) { - switch (length) { - case 1: - return 0xff; - case 2: - return 0xffff; - case 4: - return 0xffffffff; - default: - return 0; - } - } - const uint8_t *idebufferb = (uint8_t *) ide->buffer; const uint16_t *idebufferw = ide->buffer; - const uint32_t *idebufferl = (uint32_t *) ide->buffer; + int ch = ide->channel; + uint16_t ret = 0; - if (ide->command == WIN_PACKETCMD) { - ide->pos = 0; - if (ide->type == IDE_ATAPI) - temp = ide_atapi_packet_read(ide, length); - else { - ide_log("Drive not ATAPI (position: %i)\n", ide->pos); - return 0; - } - } else { - switch (length) { - case 1: - temp = idebufferb[ide->pos]; - ide->pos++; - break; - case 2: - temp = idebufferw[ide->pos >> 1]; - ide->pos += 2; - break; - case 4: - temp = idebufferl[ide->pos >> 2]; - ide->pos += 4; - break; - default: - return 0; - } - } - if ((ide->pos >= 512) && (ide->command != WIN_PACKETCMD)) { - ide->pos = 0; - ide->atastat = DRDY_STAT | DSC_STAT; - if (ide->type == IDE_ATAPI) { - ide->sc->status = DRDY_STAT | DSC_STAT; - ide->sc->packet_status = PHASE_IDLE; - } - if ((ide->command == WIN_READ) || (ide->command == WIN_READ_NORETRY) || (ide->command == WIN_READ_MULTIPLE)) { - ide->secount = (ide->secount - 1) & 0xff; - if (ide->secount) { - ide_next_sector(ide); - ide->atastat = BSY_STAT | READY_STAT | DSC_STAT; - if (ide->command == WIN_READ_MULTIPLE) { - if (!ide->blockcount) { - uint32_t sec_count = ide->secount ? ide->secount : 256; - if (sec_count > ide->blocksize) - sec_count = ide->blocksize; - double seek_time = hdd_timing_read(&hdd[ide->hdd_num], ide_get_sector(ide), sec_count); - double xfer_time = ide_get_xfer_time(ide, 512 * sec_count); - ide_set_callback(ide, seek_time + xfer_time); - } else { - ide_callback(ide); - } - } else { - double seek_time = hdd_timing_read(&hdd[ide->hdd_num], ide_get_sector(ide), 1); - double xfer_time = ide_get_xfer_time(ide, 512); - ide_set_callback(ide, seek_time + xfer_time); + /* Absent and is master or both are absent. */ + if ((ide->type == IDE_NONE) && ((ide_drives[ch ^ 1]->type == IDE_NONE) || !(ch & 1))) { + if (length == 2) + ret = 0xff7f; + else + ret = 0x7f; + /* Absent and is slave and master is present. */ + } else if ((ide->type != IDE_NONE) || !(ch & 1)) { + if (!ide->buffer) { + if (length == 2) + ret = 0xffff; + else + ret = 0xff; + } else if (ide->command == WIN_PACKETCMD) { + if (ide->type == IDE_ATAPI) + ret = ide_atapi_packet_read(ide, length); + else { + ide_log("Drive not ATAPI (position: %i)\n", ide->tf->pos); + ide->tf->pos = 0; + } + } else { + if (length == 2) { + ret = idebufferw[ide->tf->pos >> 1]; + ide->tf->pos += 2; + } else { + ret = idebufferb[ide->tf->pos]; + ide->tf->pos++; + } + + if (ide->tf->pos >= 512) { + ide->tf->pos = 0; + ide->tf->atastat = DRDY_STAT | DSC_STAT; + if (ide->type == IDE_ATAPI) + ide->sc->packet_status = PHASE_IDLE; + + if ((ide->command == WIN_READ) || (ide->command == WIN_READ_NORETRY) || + (ide->command == WIN_READ_MULTIPLE)) { + ide->tf->secount--; + + if (ide->tf->secount) { + ide_next_sector(ide); + ide->tf->atastat = BSY_STAT | READY_STAT | DSC_STAT; + if (ide->command == WIN_READ_MULTIPLE) { + if (!ide->blockcount) { + uint32_t sec_count = ide->tf->secount ? ide->tf->secount : 256; + if (sec_count > ide->blocksize) + sec_count = ide->blocksize; + double seek_time = hdd_timing_read(&hdd[ide->hdd_num], + ide_get_sector(ide), sec_count); + double xfer_time = ide_get_xfer_time(ide, 512 * sec_count); + ide_set_callback(ide, seek_time + xfer_time); + } else + ide_callback(ide); + } else { + double seek_time = hdd_timing_read(&hdd[ide->hdd_num], ide_get_sector(ide), 1); + double xfer_time = ide_get_xfer_time(ide, 512); + ide_set_callback(ide, seek_time + xfer_time); + } + } else + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); } - } else - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); + } } } - return temp; + return ret; } static uint8_t ide_status(ide_t *ide, ide_t *ide_other, int ch) { - if ((ide->type == IDE_NONE) && ((ide_other->type == IDE_NONE) || !(ch & 1))) - return 0x7f; /* Bit 7 pulled down, all other bits pulled up, per the spec. */ - else if ((ide->type == IDE_NONE) && (ch & 1)) - return 0x7f /*0x00*/; /* On real hardware, a slave with a present master always returns a status of 0x00. */ - else if (ide->type == IDE_ATAPI) - return (ide->sc->status & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0); - else - return ide->atastat; + uint8_t ret; + + /* Absent and is master or both are absent. */ + if ((ide->type == IDE_NONE) && ((ide_drives[ch ^ 1]->type == IDE_NONE) || !(ch & 1))) { + /* Bit 7 pulled down, all other bits pulled up, per the spec. */ + ret = 0x7f; + /* Absent and is slave and master is present. */ + } else if ((ide->type == IDE_NONE) && (ch & 1)) { + /* On real hardware, a slave with a present master always + returns a status of 0x00. + Confirmed by the ATA-3 and ATA-4 specifications. */ + ret = 0x00; + } else { + ret = ide->tf->atastat; + if (ide->type == IDE_ATAPI) + ret = (ret & ~DSC_STAT) | (ide->service << 4); + } + + return ret; } uint8_t ide_readb(uint16_t addr, void *priv) { const ide_board_t *dev = (ide_board_t *) priv; - int ch; int absent = 0; ide_t *ide; + ide_t *ide_other; + uint8_t ret = 0xff; ch = dev->cur_dev; ide = ide_drives[ch]; + ide_other = ide_drives[ch ^ 1]; - uint8_t temp = 0xff; - uint16_t tempw; - - addr |= 0x90; - addr &= 0xFFF7; - + /* Absent and is master or both are absent. */ if ((ide->type == IDE_NONE) && ((ide_drives[ch ^ 1]->type == IDE_NONE) || !(ch & 1))) - absent = 1; /* Absent and is master or both are absent. */ + absent = 1; + /* Absent and is slave and master is present. */ else if ((ide->type == IDE_NONE) && (ch & 1)) - absent = 2; /* Absent and is slave and master is present. */ + absent = 2; switch (addr & 0x7) { case 0x0: /* Data */ - if (absent == 1) - temp = 0x7f; - else if (absent == 2) - temp = 0x00; - else { - tempw = ide_read_data(ide, 2); - temp = tempw & 0xff; - } + ret = ide_read_data(ide, 2) & 0xff; break; /* For ATAPI: Bits 7-4 = sense key, bit 3 = MCR (media change requested), @@ -1986,13 +1850,9 @@ ide_readb(uint16_t addr, void *priv) and Bit 0 = ILI (illegal length indication). */ case 0x1: /* Error */ if (absent == 1) - temp = 0x7f; - else if (absent == 2) - temp = 0x01; - else if (ide->type == IDE_ATAPI) - temp = ide->sc->error; + ret = 0x7f; else - temp = ide->error; + ret = ide->tf->error; break; /* For ATAPI: @@ -2010,74 +1870,66 @@ ide_readb(uint16_t addr, void *priv) 1 0 1 Status. */ case 0x2: /* Sector count */ if (absent == 1) - temp = 0x7f; + ret = 0x7f; else if (absent == 2) - temp = 0x01; - else if (ide->type == IDE_ATAPI) - temp = ide->sc->phase; + ret = ide_other->tf->secount; else - temp = ide->secount; + ret = ide->tf->secount; break; case 0x3: /* Sector */ if (absent == 1) - temp = 0x7f; + ret = 0x7f; else if (absent == 2) - temp = 0x01; + ret = (uint8_t) ide_other->sector; else - temp = (uint8_t) ide->sector; + ret = (uint8_t) ide->sector; break; case 0x4: /* Cylinder low */ if (absent == 1) - temp = 0x7f; + ret = 0x7f; else if (absent == 2) - temp = 0x00; - else if (ide->type == IDE_ATAPI) - temp = ide->sc->request_length & 0xff; + ret = ide_other->tf->cylinder & 0xff; else - temp = ide->cylinder & 0xff; + ret = ide->tf->cylinder & 0xff; break; case 0x5: /* Cylinder high */ if (absent == 1) - temp = 0x7f; + ret = 0x7f; else if (absent == 2) - temp = 0x00; - else if (ide->type == IDE_ATAPI) - temp = ide->sc->request_length >> 8; + ret = ide_other->tf->cylinder >> 8; else - temp = ide->cylinder >> 8; + ret = ide->tf->cylinder >> 8; break; case 0x6: /* Drive/Head */ if (absent == 1) - temp = 0x7f; - else if (absent == 2) - temp = 0xb0; + ret = 0x7f; else - temp = (uint8_t) (ide->head | ((ch & 1) ? 0x10 : 0) | (ide->lba ? 0x40 : 0) | 0xa0); + ret = (uint8_t) (ide->head | ((ch & 1) ? 0x10 : 0) | (ide->lba ? 0x40 : 0) | 0xa0); break; /* For ATAPI: Bit 5 is DMA ready, but without overlapped or interlaved DMA, it is DF (drive fault). */ case 0x7: /* Status */ ide_irq_lower(ide); - temp = ide_status(ide, ide_drives[ch ^ 1], ch); + ret = ide_status(ide, ide_drives[ch ^ 1], ch); break; default: break; } - ide_log("ide_readb(%04X, %08X) = %02X\n", addr, priv, temp); - return temp; + ide_log("ide_readb(%04X, %08X) = %02X\n", addr, priv, ret); + return ret; } uint8_t ide_read_alt_status(UNUSED(uint16_t addr), void *priv) { - uint8_t temp = 0xff; + uint8_t ret = 0xff; const ide_board_t *dev = (ide_board_t *) priv; @@ -2089,16 +1941,16 @@ ide_read_alt_status(UNUSED(uint16_t addr), void *priv) /* Per the Seagate ATA-3 specification: Reading the alternate status does *NOT* clear the IRQ. */ - temp = ide_status(ide, ide_drives[ch ^ 1], ch); + ret = ide_status(ide, ide_drives[ch ^ 1], ch); - ide_log("ide_read_alt_status(%04X, %08X) = %02X\n", addr, priv, temp); - return temp; + ide_log("ide_read_alt_status(%04X, %08X) = %02X\n", addr, priv, ret); + return ret; } uint16_t ide_readw(uint16_t addr, void *priv) { - uint16_t temp = 0xffff; + uint16_t ret = 0xffff; const ide_board_t *dev = (ide_board_t *) priv; @@ -2110,86 +1962,80 @@ ide_readw(uint16_t addr, void *priv) switch (addr & 0x7) { case 0x0: /* Data */ - temp = ide_read_data(ide, 2); + ret = ide_read_data(ide, 2); break; case 0x7: - temp = ide_readb(addr, priv) | 0xff00; + ret = ide_readb(addr, priv) | 0xff00; break; default: - temp = ide_readb(addr, priv) | (ide_readb(addr + 1, priv) << 8); + ret = ide_readb(addr, priv) | (ide_readb(addr + 1, priv) << 8); break; } - ide_log("ide_readw(%04X, %08X) = %04X\n", addr, priv, temp); - return temp; + ide_log("ide_readw(%04X, %08X) = %04X\n", addr, priv, ret); + return ret; } static uint32_t ide_readl(uint16_t addr, void *priv) { - uint16_t temp2; - uint32_t temp = 0xffffffff; - - const ide_board_t *dev = (ide_board_t *) priv; - ide_t *ide; int ch; + uint32_t ret = 0xffffffff; + + const ide_board_t *dev = (ide_board_t *) priv; ch = dev->cur_dev; ide = ide_drives[ch]; switch (addr & 0x7) { case 0x0: /* Data */ - temp2 = ide_read_data(ide, 2); + ret = ide_read_data(ide, 2); if (dev->bit32) - temp = temp2 | (ide_read_data(ide, 2) << 16); + ret |= (ide_read_data(ide, 2) << 16); else - temp = temp2 | (ide_readw(addr + 2, priv) << 16); + ret |= (ide_readw(addr + 2, priv) << 16); break; case 0x6: case 0x7: - temp = ide_readw(addr, priv) | 0xffff0000; + ret = ide_readw(addr, priv) | 0xffff0000; break; default: - temp = ide_readw(addr, priv) | (ide_readw(addr + 2, priv) << 16); + ret = ide_readw(addr, priv) | (ide_readw(addr + 2, priv) << 16); break; } - ide_log("ide_readl(%04X, %08X) = %04X\n", addr, priv, temp); - return temp; + ide_log("ide_readl(%04X, %08X) = %04X\n", addr, priv, ret); + return ret; } static void ide_board_callback(void *priv) { ide_board_t *dev = (ide_board_t *) priv; + ide_t *ide; #ifdef ENABLE_IDE_LOG - ide_log("CALLBACK RESET\n"); + ide_log("ide_board_callback(%i)\n", dev->cur_dev >> 1); #endif - dev->ide[0]->atastat = DRDY_STAT | DSC_STAT; - if (dev->ide[0]->type == IDE_ATAPI) { - if (dev->ide[0]->sc->pad0) - dev->ide[0]->sc->status = DRDY_STAT | DSC_STAT; - else - dev->ide[0]->sc->status = 0; - } - - dev->ide[1]->atastat = DRDY_STAT | DSC_STAT; - if (dev->ide[1]->type == IDE_ATAPI) { - if (dev->ide[1]->sc->pad0) - dev->ide[1]->sc->status = DRDY_STAT | DSC_STAT; - else - dev->ide[1]->sc->status = 0; + for (uint8_t i = 0; i < 2; i++) { + ide = dev->ide[i]; + if (ide->type == IDE_ATAPI) { + ide->tf->atastat = 0; + if (IDE_ATAPI_IS_EARLY) + ide->tf->atastat |= DRDY_STAT | DSC_STAT; + } else + ide->tf->atastat = DRDY_STAT | DSC_STAT; } dev->cur_dev &= ~1; + ide = dev->ide[0]; if (dev->diag) { dev->diag = 0; - if ((dev->ide[0]->type != IDE_ATAPI) || dev->ide[0]->sc->pad0) - ide_irq_raise(dev->ide[0]); + if ((ide->type != IDE_ATAPI) || IDE_ATAPI_IS_EARLY) + ide_irq_raise(ide); } } @@ -2197,15 +2043,10 @@ static void atapi_error_no_ready(ide_t *ide) { ide->command = 0; - if (ide->type == IDE_ATAPI) { - ide->sc->status = ERR_STAT | DSC_STAT; - ide->sc->error = ABRT_ERR; - ide->sc->pos = 0; - } else { - ide->atastat = ERR_STAT | DSC_STAT; - ide->error = ABRT_ERR; - ide->pos = 0; - } + ide->tf->atastat = ERR_STAT | DSC_STAT; + ide->tf->error = ABRT_ERR; + ide->tf->pos = 0; + ide_irq_raise(ide); } @@ -2214,150 +2055,144 @@ ide_callback(void *priv) { int snum; int ret = 0; - + uint8_t err = 0x00; + int chk_chs = 0; ide_t *ide = (ide_t *) priv; + ide_bm_t *bm = ide_boards[ide->board]->bm; - ide_log("CALLBACK %02X %i %i\n", ide->command, ide->reset, ide->channel); - - if (((ide->command >= WIN_RECAL) && (ide->command <= 0x1F)) || ((ide->command >= WIN_SEEK) && (ide->command <= 0x7F))) { - if (ide->type != IDE_HDD) { - atapi_error_no_ready(ide); - return; - } - if ((ide->command >= WIN_SEEK) && (ide->command <= 0x7F) && !ide->lba) { - if ((ide->cylinder >= ide->tracks) || (ide->head >= ide->hpc) || !ide->sector || (ide->sector > ide->spt)) - goto id_not_found; - } - ide->atastat = DRDY_STAT | DSC_STAT; - ide_irq_raise(ide); - return; - } + ide_log("ide_callback(%i): %02X\n", ide->channel, ide->command); switch (ide->command) { - /* Initialize the Task File Registers as follows: Status = 00h, Error = 01h, Sector Count = 01h, Sector Number = 01h, - Cylinder Low = 14h, Cylinder High =EBh and Drive/Head = 00h. */ - case WIN_SRST: /*ATAPI Device Reset */ + case WIN_SEEK ... 0x7F: + chk_chs = !ide->lba; + fallthrough; + case WIN_RECAL ... 0x1F: + if (ide->type == IDE_ATAPI) + atapi_error_no_ready(ide); + else { + if (chk_chs && ((ide->tf->cylinder >= ide->tracks) || (ide->head >= ide->hpc) || + !ide->sector || (ide->sector > ide->spt))) + err = IDNF_ERR; + else { + ide->tf->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + } + } + break; - ide->atastat = DRDY_STAT | DSC_STAT; - ide->error = 1; /*Device passed*/ - ide->secount = 1; - ide->sector = 1; + /* Initialize the Task File Registers as follows: + Status = 00h, Error = 01h, Sector Count = 01h, Sector Number = 01h, + Cylinder Low = 14h, Cylinder High = EBh and Drive/Head = 00h. */ + case WIN_SRST: /*ATAPI Device Reset */ + ide->tf->error = 1; /*Device passed*/ + + ide->tf->secount = 1; + ide->sector = 1; ide_set_signature(ide); + ide->tf->atastat = DRDY_STAT | DSC_STAT; if (ide->type == IDE_ATAPI) { - ide->sc->error = 1; if (ide->device_reset) ide->device_reset(ide->sc); - if (ide->sc->pad0) /* pad0 = early */ - ide->sc->status = DRDY_STAT | DSC_STAT; - else - ide->sc->status = 0; + if (!IDE_ATAPI_IS_EARLY) + ide->tf->atastat = 0; } + ide_irq_raise(ide); - if ((ide->type == IDE_ATAPI) && !ide->sc->pad0) + + if ((ide->type == IDE_ATAPI) && !IDE_ATAPI_IS_EARLY) ide->service = 0; - return; + break; case WIN_NOP: case WIN_STANDBYNOW1: case WIN_IDLENOW1: case WIN_SETIDLE1: - if (ide->type == IDE_ATAPI) - ide->sc->status = DRDY_STAT | DSC_STAT; - else - ide->atastat = DRDY_STAT | DSC_STAT; + ide->tf->atastat = DRDY_STAT | DSC_STAT; ide_irq_raise(ide); - return; + break; case WIN_CHECKPOWERMODE1: case WIN_SLEEP1: - if (ide->type == IDE_ATAPI) { - ide->sc->phase = 0xFF; - ide->sc->status = DRDY_STAT | DSC_STAT; - } - ide->secount = 0xFF; - ide->atastat = DRDY_STAT | DSC_STAT; + ide->tf->secount = 0xff; + ide->tf->atastat = DRDY_STAT | DSC_STAT; ide_irq_raise(ide); - return; + break; case WIN_READ: case WIN_READ_NORETRY: if (ide->type == IDE_ATAPI) { ide_set_signature(ide); - goto abort_cmd; + err = ABRT_ERR; + } else if (!ide->lba && (ide->cfg_spt == 0)) + err = IDNF_ERR; + else { + if (ide->do_initial_read) { + ide->do_initial_read = 0; + ide->sector_pos = 0; + hdd_image_read(ide->hdd_num, ide_get_sector(ide), + ide->tf->secount ? ide->tf->secount : 256, ide->sector_buffer); + } + + memcpy(ide->buffer, &ide->sector_buffer[ide->sector_pos * 512], 512); + + ide->sector_pos++; + + ide->tf->pos = 0; + ide->tf->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; + + ide_irq_raise(ide); + + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); } - if (!ide->lba && (ide->cfg_spt == 0)) - goto id_not_found; - - if (ide->do_initial_read) { - ide->do_initial_read = 0; - ide->sector_pos = 0; - if (ide->secount) - hdd_image_read(ide->hdd_num, ide_get_sector(ide), ide->secount, ide->sector_buffer); - else - hdd_image_read(ide->hdd_num, ide_get_sector(ide), 256, ide->sector_buffer); - } - - memcpy(ide->buffer, &ide->sector_buffer[ide->sector_pos * 512], 512); - - ide->sector_pos++; - ide->pos = 0; - - ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; - - ide_irq_raise(ide); - - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); - return; + break; case WIN_READ_DMA: case WIN_READ_DMA_ALT: - if ((ide->type == IDE_ATAPI) || ide_boards[ide->board]->force_ata3 || !ide_bm[ide->board]) { + if ((ide->type == IDE_ATAPI) || ide_boards[ide->board]->force_ata3 || (bm == NULL)) { ide_log("IDE %i: DMA read aborted (bad device or board)\n", ide->channel); - goto abort_cmd; - } - if (!ide->lba && (ide->cfg_spt == 0)) { + err = ABRT_ERR; + } else if (!ide->lba && (ide->cfg_spt == 0)) { ide_log("IDE %i: DMA read aborted (SPECIFY failed)\n", ide->channel); - goto id_not_found; - } - - ide->sector_pos = 0; - if (ide->secount) - ide->sector_pos = ide->secount; - else - ide->sector_pos = 256; - hdd_image_read(ide->hdd_num, ide_get_sector(ide), ide->sector_pos, ide->sector_buffer); - - ide->pos = 0; - - if (!ide_boards[ide->board]->force_ata3 && ide_bm[ide->board] && ide_bm[ide->board]->dma) { - /* We should not abort - we should simply wait for the host to start DMA. */ - ret = ide_bm[ide->board]->dma(ide->sector_buffer, ide->sector_pos * 512, - 0, ide_bm[ide->board]->priv); - if (ret == 2) { - /* Bus master DMA disabled, simply wait for the host to enable DMA. */ - ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; - ide_set_callback(ide, 6.0 * IDE_TIME); - return; - } else if (ret == 1) { - /*DMA successful*/ - ide_log("IDE %i: DMA read successful\n", ide->channel); - - ide->atastat = DRDY_STAT | DSC_STAT; - - ide_irq_raise(ide); - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); - } else { - /* Bus master DMAS error, abort the command. */ - ide_log("IDE %i: DMA read aborted (failed)\n", ide->channel); - goto abort_cmd; - } + err = IDNF_ERR; } else { - ide_log("IDE %i: DMA read aborted (no bus master)\n", ide->channel); - goto abort_cmd; + ide->sector_pos = 0; + if (ide->tf->secount) + ide->sector_pos = ide->tf->secount; + else + ide->sector_pos = 256; + hdd_image_read(ide->hdd_num, ide_get_sector(ide), ide->sector_pos, ide->sector_buffer); + + ide->tf->pos = 0; + + if (!ide_boards[ide->board]->force_ata3 && (bm != NULL) && bm->dma) { + /* We should not abort - we should simply wait for the host to start DMA. */ + ret = bm->dma(ide->sector_buffer, ide->sector_pos * 512, 0, bm->priv); + if (ret == 2) { + /* Bus master DMA disabled, simply wait for the host to enable DMA. */ + ide->tf->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; + ide_set_callback(ide, 6.0 * IDE_TIME); + return; + } else if (ret == 1) { + /* DMA successful */ + ide_log("IDE %i: DMA read successful\n", ide->channel); + + ide->tf->atastat = DRDY_STAT | DSC_STAT; + + ide_irq_raise(ide); + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); + } else { + /* Bus master DMAS error, abort the command. */ + ide_log("IDE %i: DMA read aborted (failed)\n", ide->channel); + err = ABRT_ERR; + } + } else { + ide_log("IDE %i: DMA read aborted (no bus master)\n", ide->channel); + err = ABRT_ERR; + } } - return; + break; case WIN_READ_MULTIPLE: /* According to the official ATA reference: @@ -2367,98 +2202,97 @@ ide_callback(void *priv) disabled, the Read Multiple operation is rejected with an Aborted Com- mand error. */ if ((ide->type == IDE_ATAPI) || !ide->blocksize) - goto abort_cmd; - if (!ide->lba && (ide->cfg_spt == 0)) - goto id_not_found; + err = ABRT_ERR; + else if (!ide->lba && (ide->cfg_spt == 0)) + err = IDNF_ERR; + else { + if (ide->do_initial_read) { + ide->do_initial_read = 0; + ide->sector_pos = 0; + hdd_image_read(ide->hdd_num, ide_get_sector(ide), + ide->tf->secount ? ide->tf->secount : 256, ide->sector_buffer); + } - if (ide->do_initial_read) { - ide->do_initial_read = 0; - ide->sector_pos = 0; - if (ide->secount) - hdd_image_read(ide->hdd_num, ide_get_sector(ide), ide->secount, ide->sector_buffer); - else - hdd_image_read(ide->hdd_num, ide_get_sector(ide), 256, ide->sector_buffer); + memcpy(ide->buffer, &ide->sector_buffer[ide->sector_pos * 512], 512); + + ide->sector_pos++; + ide->tf->pos = 0; + + ide->tf->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; + if (!ide->blockcount) + ide_irq_raise(ide); + ide->blockcount++; + if (ide->blockcount >= ide->blocksize) + ide->blockcount = 0; } - - memcpy(ide->buffer, &ide->sector_buffer[ide->sector_pos * 512], 512); - - ide->sector_pos++; - ide->pos = 0; - - ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; - if (!ide->blockcount) - ide_irq_raise(ide); - ide->blockcount++; - if (ide->blockcount >= ide->blocksize) - ide->blockcount = 0; - return; + break; case WIN_WRITE: case WIN_WRITE_NORETRY: if (ide->type == IDE_ATAPI) - goto abort_cmd; - if (!ide->lba && (ide->cfg_spt == 0)) - goto id_not_found; - hdd_image_write(ide->hdd_num, ide_get_sector(ide), 1, (uint8_t *) ide->buffer); - ide_irq_raise(ide); - ide->secount = (ide->secount - 1) & 0xff; - if (ide->secount) { - ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; - ide->pos = 0; - ide_next_sector(ide); - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); - } else { - ide->atastat = DRDY_STAT | DSC_STAT; - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); + err = ABRT_ERR; + else if (!ide->lba && (ide->cfg_spt == 0)) + err = IDNF_ERR; + else { + hdd_image_write(ide->hdd_num, ide_get_sector(ide), 1, (uint8_t *) ide->buffer); + ide_irq_raise(ide); + ide->tf->secount--; + if (ide->tf->secount) { + ide->tf->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; + ide->tf->pos = 0; + ide_next_sector(ide); + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); + } else { + ide->tf->atastat = DRDY_STAT | DSC_STAT; + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); + } } - return; + break; case WIN_WRITE_DMA: case WIN_WRITE_DMA_ALT: - if ((ide->type == IDE_ATAPI) || ide_boards[ide->board]->force_ata3 || !ide_bm[ide->board]) { + if ((ide->type == IDE_ATAPI) || ide_boards[ide->board]->force_ata3 || (bm == NULL)) { ide_log("IDE %i: DMA write aborted (bad device type or board)\n", ide->channel); - goto abort_cmd; - } - if (!ide->lba && (ide->cfg_spt == 0)) { + err = ABRT_ERR; + } else if (!ide->lba && (ide->cfg_spt == 0)) { ide_log("IDE %i: DMA write aborted (SPECIFY failed)\n", ide->channel); - goto id_not_found; - } - - if (!ide_boards[ide->board]->force_ata3 && ide_bm[ide->board] && ide_bm[ide->board]->dma) { - if (ide->secount) - ide->sector_pos = ide->secount; - else - ide->sector_pos = 256; - - ret = ide_bm[ide->board]->dma(ide->sector_buffer, ide->sector_pos * 512, - 1, ide_bm[ide->board]->priv); - - if (ret == 2) { - /* Bus master DMA disabled, simply wait for the host to enable DMA. */ - ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; - ide_set_callback(ide, 6.0 * IDE_TIME); - return; - } else if (ret == 1) { - /*DMA successful*/ - ide_log("IDE %i: DMA write successful\n", ide->channel); - - hdd_image_write(ide->hdd_num, ide_get_sector(ide), ide->sector_pos, ide->sector_buffer); - - ide->atastat = DRDY_STAT | DSC_STAT; - - ide_irq_raise(ide); - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); - } else { - /* Bus master DMA error, abort the command. */ - ide_log("IDE %i: DMA read aborted (failed)\n", ide->channel); - goto abort_cmd; - } + err = IDNF_ERR; } else { - ide_log("IDE %i: DMA write aborted (no bus master)\n", ide->channel); - goto abort_cmd; - } + if (!ide_boards[ide->board]->force_ata3 && (bm != NULL) && bm->dma) { + if (ide->tf->secount) + ide->sector_pos = ide->tf->secount; + else + ide->sector_pos = 256; - return; + ret = bm->dma(ide->sector_buffer, ide->sector_pos * 512, 1, bm->priv); + + if (ret == 2) { + /* Bus master DMA disabled, simply wait for the host to enable DMA. */ + ide->tf->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; + ide_set_callback(ide, 6.0 * IDE_TIME); + return; + } else if (ret == 1) { + /* DMA successful */ + ide_log("IDE %i: DMA write successful\n", ide->channel); + + hdd_image_write(ide->hdd_num, ide_get_sector(ide), + ide->sector_pos, ide->sector_buffer); + + ide->tf->atastat = DRDY_STAT | DSC_STAT; + + ide_irq_raise(ide); + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); + } else { + /* Bus master DMA error, abort the command. */ + ide_log("IDE %i: DMA read aborted (failed)\n", ide->channel); + err = ABRT_ERR; + } + } else { + ide_log("IDE %i: DMA write aborted (no bus master)\n", ide->channel); + err = ABRT_ERR; + } + } + break; case WIN_WRITE_MULTIPLE: /* According to the official ATA reference: @@ -2468,157 +2302,154 @@ ide_callback(void *priv) disabled, the Read Multiple operation is rejected with an Aborted Com- mand error. */ if ((ide->type == IDE_ATAPI) || !ide->blocksize) - goto abort_cmd; - if (!ide->lba && (ide->cfg_spt == 0)) - goto id_not_found; - hdd_image_write(ide->hdd_num, ide_get_sector(ide), 1, (uint8_t *) ide->buffer); - ide->blockcount++; - if (ide->blockcount >= ide->blocksize || ide->secount == 1) { - ide->blockcount = 0; - ide_irq_raise(ide); + err = ABRT_ERR; + else if (!ide->lba && (ide->cfg_spt == 0)) + err = IDNF_ERR; + else { + hdd_image_write(ide->hdd_num, ide_get_sector(ide), 1, (uint8_t *) ide->buffer); + ide->blockcount++; + if (ide->blockcount >= ide->blocksize || ide->tf->secount == 1) { + ide->blockcount = 0; + ide_irq_raise(ide); + } + ide->tf->secount--; + if (ide->tf->secount) { + ide->tf->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; + ide->tf->pos = 0; + ide_next_sector(ide); + } else { + ide->tf->atastat = DRDY_STAT | DSC_STAT; + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); + } } - ide->secount = (ide->secount - 1) & 0xff; - if (ide->secount) { - ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; - ide->pos = 0; - ide_next_sector(ide); - } else { - ide->atastat = DRDY_STAT | DSC_STAT; - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); - } - return; + break; case WIN_VERIFY: case WIN_VERIFY_ONCE: if (ide->type == IDE_ATAPI) - goto abort_cmd; - if (!ide->lba && (ide->cfg_spt == 0)) - goto id_not_found; - ide->pos = 0; - ide->atastat = DRDY_STAT | DSC_STAT; - ide_irq_raise(ide); - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); - return; + err = ABRT_ERR; + else if (!ide->lba && (ide->cfg_spt == 0)) + err = IDNF_ERR; + else { + ide->tf->pos = 0; + ide->tf->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); + } + break; case WIN_FORMAT: if (ide->type == IDE_ATAPI) - goto abort_cmd; - if (!ide->lba && (ide->cfg_spt == 0)) - goto id_not_found; - hdd_image_zero(ide->hdd_num, ide_get_sector(ide), ide->secount); + err = ABRT_ERR; + else if (!ide->lba && (ide->cfg_spt == 0)) + err = IDNF_ERR; + else { + hdd_image_zero(ide->hdd_num, ide_get_sector(ide), ide->tf->secount); - ide->atastat = DRDY_STAT | DSC_STAT; - ide_irq_raise(ide); + ide->tf->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); - return; + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); + } + break; case WIN_SPECIFY: /* Initialize Drive Parameters */ if (ide->type == IDE_ATAPI) - goto abort_cmd; - if (ide->cfg_spt == 0) { - /* Only accept after RESET or DIAG. */ - ide->cfg_spt = ide->secount; - ide->cfg_hpc = ide->head + 1; + err = ABRT_ERR; + else { + if (ide->cfg_spt == 0) { + /* Only accept after RESET or DIAG. */ + ide->cfg_spt = ide->tf->secount; + ide->cfg_hpc = ide->head + 1; + } + ide->command = 0x00; + ide->tf->atastat = DRDY_STAT | DSC_STAT; + ide->tf->error = 1; + ide_irq_raise(ide); } - ide->command = 0x00; - ide->atastat = DRDY_STAT | DSC_STAT; - ide->error = 1; - ide_irq_raise(ide); - return; + break; case WIN_PIDENTIFY: /* Identify Packet Device */ if (ide->type == IDE_ATAPI) { ide_identify(ide); - ide->pos = 0; - ide->sc->phase = 2; - ide->sc->pos = 0; - ide->sc->error = 0; - ide->sc->status = DRQ_STAT | DRDY_STAT | DSC_STAT; + ide->tf->pos = 0; + ide->tf->phase = 2; + ide->tf->error = 0; + ide->tf->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; ide_irq_raise(ide); - return; - } - goto abort_cmd; + } else + err = ABRT_ERR; + break; case WIN_SET_MULTIPLE_MODE: - if (ide->type == IDE_ATAPI) - goto abort_cmd; - if ((ide->secount < 2) || (ide->secount > hdd[ide->hdd_num].max_multiple_block)) - goto abort_cmd; - ide->blocksize = ide->secount; - ide->atastat = DRDY_STAT | DSC_STAT; - ide_irq_raise(ide); - return; + if ((ide->type == IDE_ATAPI) || (ide->tf->secount < 2) || + (ide->tf->secount > hdd[ide->hdd_num].max_multiple_block)) + err = ABRT_ERR; + else { + ide->blocksize = ide->tf->secount; + ide->tf->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + } + break; case WIN_SET_FEATURES: if ((ide->type == IDE_NONE) || !ide_set_features(ide)) - goto abort_cmd; + err = ABRT_ERR; + else { + ide->tf->atastat = DRDY_STAT | DSC_STAT; - if (ide->type == IDE_ATAPI) { - ide->sc->status = DRDY_STAT | DSC_STAT; - ide->sc->pos = 0; - } + if (ide->type == IDE_ATAPI) + ide->tf->pos = 0; - ide->atastat = DRDY_STAT | DSC_STAT; - ide_irq_raise(ide); - return; - - case WIN_READ_NATIVE_MAX: - if (ide->type != IDE_HDD) - goto abort_cmd; - snum = hdd[ide->hdd_num].spt; - snum *= hdd[ide->hdd_num].hpc; - snum *= hdd[ide->hdd_num].tracks; - ide_set_sector(ide, snum - 1); - ide->atastat = DRDY_STAT | DSC_STAT; - ide_irq_raise(ide); - return; - - case WIN_IDENTIFY: /* Identify Device */ - if (ide->type != IDE_HDD) { - ide_set_signature(ide); - goto abort_cmd; - } else { - ide_identify(ide); - ide->pos = 0; - ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; ide_irq_raise(ide); } - return; + break; + + case WIN_READ_NATIVE_MAX: + if (ide->type == IDE_HDD) { + snum = hdd[ide->hdd_num].spt; + snum *= hdd[ide->hdd_num].hpc; + snum *= hdd[ide->hdd_num].tracks; + ide_set_sector(ide, snum - 1); + ide->tf->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + } else + err = ABRT_ERR; + break; + + case WIN_IDENTIFY: /* Identify Device */ + if (ide->type == IDE_HDD) { + ide_identify(ide); + ide->tf->pos = 0; + ide->tf->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + } else { + ide_set_signature(ide); + err = ABRT_ERR; + } + break; case WIN_PACKETCMD: /* ATAPI Packet */ - if (ide->type != IDE_ATAPI) - goto abort_cmd; - - ide_atapi_callback(ide); - return; - - case 0xFF: - goto abort_cmd; + if (ide->type == IDE_ATAPI) + ide_atapi_callback(ide); + else + err = ABRT_ERR; + break; default: + case 0xff: + err = ABRT_ERR; break; } -abort_cmd: - ide->command = 0; - if (ide->type == IDE_ATAPI) { - ide->sc->status = DRDY_STAT | ERR_STAT | DSC_STAT; - ide->sc->error = ABRT_ERR; - ide->sc->pos = 0; - } else { - ide->atastat = DRDY_STAT | ERR_STAT | DSC_STAT; - ide->error = ABRT_ERR; - ide->pos = 0; - } - ide_irq_raise(ide); - return; + if (err != 0x00) { + ide->tf->atastat = DRDY_STAT | ERR_STAT | DSC_STAT; + ide->tf->error = err; -id_not_found: - ide->atastat = DRDY_STAT | ERR_STAT | DSC_STAT; - ide->error = IDNF_ERR; - ide->pos = 0; - ide_irq_raise(ide); + ide->tf->pos = 0; + + ide_irq_raise(ide); + } } uint8_t @@ -2661,130 +2492,74 @@ ide_read_ali_76(void) ide0 = ide_drives[ch0]; ide1 = ide_drives[ch1]; - if (ide1->atastat & BSY_STAT) + if (ide1->tf->atastat & BSY_STAT) ret |= 0x40; - if (ide1->atastat & DRQ_STAT) + if (ide1->tf->atastat & DRQ_STAT) ret |= 0x20; - if (ide1->atastat & ERR_STAT) + if (ide1->tf->atastat & ERR_STAT) ret |= 0x10; - if (ide0->atastat & BSY_STAT) + if (ide0->tf->atastat & BSY_STAT) ret |= 0x04; - if (ide0->atastat & DRQ_STAT) + if (ide0->tf->atastat & DRQ_STAT) ret |= 0x02; - if (ide0->atastat & ERR_STAT) + if (ide0->tf->atastat & ERR_STAT) ret |= 0x01; return ret; } void -ide_set_handlers(uint8_t board) +ide_handlers(uint8_t board, int set) { - if (ide_boards[board] == NULL) - return; + if (ide_boards[board] != NULL) { + if (ide_boards[board]->base[0]) { + io_handler(set, ide_boards[board]->base[0], 8, + ide_readb, ide_readw, ide_readl, + ide_writeb, ide_writew, ide_writel, + ide_boards[board]); + } - if (ide_boards[board]->base_main) { - io_sethandler(ide_boards[board]->base_main, 8, - ide_readb, ide_readw, ide_readl, - ide_writeb, ide_writew, ide_writel, - ide_boards[board]); - } - - if (ide_boards[board]->side_main) { - io_sethandler(ide_boards[board]->side_main, 1, - ide_read_alt_status, NULL, NULL, - ide_write_devctl, NULL, NULL, - ide_boards[board]); + if (ide_boards[board]->base[1]) { + io_handler(set, ide_boards[board]->base[1], 1, + ide_read_alt_status, NULL, NULL, + ide_write_devctl, NULL, NULL, + ide_boards[board]); + } } } void -ide_remove_handlers(uint8_t board) +ide_set_base_addr(int board, int base, uint16_t port) { - if (ide_boards[board] == NULL) - return; + ide_log("ide_set_base_addr(%i, %i, %04X)\n", board, base, port); - if (ide_boards[board]->base_main) { - io_removehandler(ide_boards[board]->base_main, 8, - ide_readb, ide_readw, ide_readl, - ide_writeb, ide_writew, ide_writel, - ide_boards[board]); - } - - if (ide_boards[board]->side_main) { - io_removehandler(ide_boards[board]->side_main, 1, - ide_read_alt_status, NULL, NULL, - ide_write_devctl, NULL, NULL, - ide_boards[board]); - } -} - -void -ide_pri_enable(void) -{ - ide_set_handlers(0); -} - -void -ide_pri_disable(void) -{ - ide_remove_handlers(0); -} - -void -ide_sec_enable(void) -{ - ide_set_handlers(1); -} - -void -ide_sec_disable(void) -{ - ide_remove_handlers(1); -} - -void -ide_set_base(int board, uint16_t port) -{ - ide_log("ide_set_base(%i, %04X)\n", board, port); - - if (ide_boards[board] == NULL) - return; - - ide_boards[board]->base_main = port; -} - -void -ide_set_side(int board, uint16_t port) -{ - ide_log("ide_set_side(%i, %04X)\n", board, port); - - if (ide_boards[board] == NULL) - return; - - ide_boards[board]->side_main = port; + if (ide_boards[board] != NULL) + ide_boards[board]->base[base] = port; } static void ide_clear_bus_master(int board) { - if (ide_bm[board]) { - free(ide_bm[board]); - ide_bm[board] = NULL; + ide_bm_t *bm = ide_boards[board]->bm; + + if (bm != NULL) { + free(bm); + ide_boards[board]->bm = NULL; } } -/* This so drives can be forced to ATA-3 (no DMA) for machines that hide the on-board PCI IDE controller - (eg. Packard Bell PB640 and ASUS P/I-P54TP4XE), breaking DMA drivers unless this is done. */ +/* + This so drives can be forced to ATA-3 (no DMA) for machines that hide the + on-board PCI IDE controller (eg. Packard Bell PB640 and ASUS P/I-P54TP4XE), + breaking DMA drivers unless this is done. + */ extern void ide_board_set_force_ata3(int board, int force_ata3) { ide_log("ide_board_set_force_ata3(%i, %i)\n", board, force_ata3); - if ((ide_boards[board] == NULL) || !ide_boards[board]->inited) - return; - - ide_boards[board]->force_ata3 = force_ata3; + if ((ide_boards[board] != NULL) && ide_boards[board]->inited) + ide_boards[board]->force_ata3 = force_ata3; } static void @@ -2812,28 +2587,31 @@ ide_board_close(int board) dev = ide_drives[c]; - if (dev == NULL) - continue; + if (dev != NULL) { + if ((dev->type == IDE_HDD) && (dev->hdd_num != -1)) + hdd_image_close(dev->hdd_num); - if ((dev->type == IDE_HDD) && (dev->hdd_num != -1)) - hdd_image_close(dev->hdd_num); + if (dev->type == IDE_ATAPI) + dev->tf->atastat = DRDY_STAT | DSC_STAT; + else if (dev->tf != NULL) { + free(dev->tf); + dev->tf = NULL; + } - if (dev->type == IDE_ATAPI) - dev->sc->status = DRDY_STAT | DSC_STAT; + if (dev->buffer) { + free(dev->buffer); + dev->buffer = NULL; + } - if (dev->buffer) { - free(dev->buffer); - dev->buffer = NULL; - } + if (dev->sector_buffer) { + free(dev->sector_buffer); + dev->buffer = NULL; + } - if (dev->sector_buffer) { - free(dev->sector_buffer); - dev->buffer = NULL; - } - - if (dev) { - free(dev); - ide_drives[c] = NULL; + if (dev) { + free(dev); + ide_drives[c] = NULL; + } } } @@ -2877,8 +2655,7 @@ ide_board_setup(int board) ide_log("Found IDE hard disk on channel %i\n", ch); loadhd(ide_drives[ch], d, hdd[d].fn); if (ide_drives[ch]->sector_buffer == NULL) - ide_drives[ch]->sector_buffer = (uint8_t *) malloc(256 * 512); - memset(ide_drives[ch]->sector_buffer, 0, 256 * 512); + ide_drives[ch]->sector_buffer = (uint8_t *) calloc(1, 256 * 512); if (++c >= 2) break; } @@ -2897,7 +2674,7 @@ ide_board_setup(int board) ide_set_signature(dev); dev->mdma_mode = (1 << ide_get_max(dev, TYPE_PIO)); - dev->error = 1; + dev->tf->error = 1; if (dev->type != IDE_HDD) dev->cfg_spt = dev->cfg_hpc = 0; if (dev->type == IDE_HDD) @@ -2916,15 +2693,14 @@ ide_board_init(int board, int irq, int base_main, int side_main, int type) ide_log("IDE: Initializing board %i...\n", board); if (ide_boards[board] == NULL) - ide_boards[board] = (ide_board_t *) malloc(sizeof(ide_board_t)); + ide_boards[board] = (ide_board_t *) calloc(1, sizeof(ide_board_t)); - memset(ide_boards[board], 0, sizeof(ide_board_t)); ide_boards[board]->irq = irq; ide_boards[board]->cur_dev = board << 1; if (type & 6) ide_boards[board]->bit32 = 1; - ide_boards[board]->base_main = base_main; - ide_boards[board]->side_main = side_main; + ide_boards[board]->base[0] = base_main; + ide_boards[board]->base[1] = side_main; ide_set_handlers(board); timer_add(&ide_boards[board]->timer, ide_board_callback, ide_boards[board], 0); @@ -2942,18 +2718,20 @@ ide_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) if (ld) return; - if (ide_boards[board]->base_main || ide_boards[board]->side_main) { + if (ide_boards[board]->base[0] || ide_boards[board]->base[1]) { ide_remove_handlers(board); - ide_boards[board]->base_main = ide_boards[board]->side_main = 0; + ide_boards[board]->base[0] = ide_boards[board]->base[1] = 0; } ide_boards[board]->irq = -1; if (config->activate) { - ide_boards[board]->base_main = (config->io[0].base != ISAPNP_IO_DISABLED) ? config->io[0].base : 0x0000; - ide_boards[board]->side_main = (config->io[1].base != ISAPNP_IO_DISABLED) ? config->io[1].base : 0x0000; + ide_boards[board]->base[0] = (config->io[0].base != ISAPNP_IO_DISABLED) ? + config->io[0].base : 0x0000; + ide_boards[board]->base[1] = (config->io[1].base != ISAPNP_IO_DISABLED) ? + config->io[1].base : 0x0000; - if (ide_boards[board]->base_main && ide_boards[board]->side_main) + if (ide_boards[board]->base[0] && ide_boards[board]->base[1]) ide_set_handlers(board); if (config->irq[0].irq != ISAPNP_IRQ_DISABLED) @@ -2977,7 +2755,8 @@ ide_ter_init(const device_t *info) if (irq < 0) { ide_board_init(2, -1, 0, 0, 0); if (irq == -1) - isapnp_add_card(ide_ter_pnp_rom, sizeof(ide_ter_pnp_rom), ide_pnp_config_changed, NULL, NULL, NULL, (void *) 2); + isapnp_add_card(ide_ter_pnp_rom, sizeof(ide_ter_pnp_rom), + ide_pnp_config_changed, NULL, NULL, NULL, (void *) 2); } else { ide_board_init(2, irq, HDC_TERTIARY_BASE, HDC_TERTIARY_SIDE, 0); } @@ -3008,10 +2787,10 @@ ide_qua_init(const device_t *info) if (irq < 0) { ide_board_init(3, -1, 0, 0, 0); if (irq == -1) - isapnp_add_card(ide_qua_pnp_rom, sizeof(ide_qua_pnp_rom), ide_pnp_config_changed, NULL, NULL, NULL, (void *) 3); - } else { + isapnp_add_card(ide_qua_pnp_rom, sizeof(ide_qua_pnp_rom), + ide_pnp_config_changed, NULL, NULL, NULL, (void *) 3); + } else ide_board_init(3, irq, HDC_QUATERNARY_BASE, HDC_QUATERNARY_SIDE, 0); - } return (ide_boards[3]); } @@ -3042,12 +2821,17 @@ ide_set_bus_master(int board, int (*dma)(uint8_t *data, int transfer_length, int out, void *priv), void (*set_irq)(uint8_t status, void *priv), void *priv) { - if (ide_bm[board] == NULL) - ide_bm[board] = (ide_bm_t *) malloc(sizeof(ide_bm_t)); + ide_bm_t *bm; - ide_bm[board]->dma = dma; - ide_bm[board]->set_irq = set_irq; - ide_bm[board]->priv = priv; + if (ide_boards[board]->bm == NULL) { + bm = (ide_bm_t *) calloc(1, sizeof(ide_bm_t)); + ide_boards[board]->bm = bm; + } else + bm = ide_boards[board]->bm; + + bm->dma = dma; + bm->set_irq = set_irq; + bm->priv = priv; } static void * @@ -3056,12 +2840,7 @@ ide_init(const device_t *info) ide_log("Initializing IDE...\n"); switch (info->local) { - case 0: /* ISA, single-channel */ - case 1: /* ISA, dual-channel */ - case 2: /* VLB, single-channel */ - case 3: /* VLB, dual-channel */ - case 4: /* PCI, single-channel */ - case 5: /* PCI, dual-channel */ + case 0 ... 5: ide_board_init(0, 14, 0x1f0, 0x3f6, info->local); if (info->local & 1) @@ -3072,7 +2851,6 @@ ide_init(const device_t *info) break; } - // return ide_drives; return (void *) (intptr_t) -1; } @@ -3081,11 +2859,11 @@ ide_drive_reset(int d) { ide_log("Resetting IDE drive %i...\n", d); - ide_drives[d]->channel = d; - ide_drives[d]->atastat = DRDY_STAT | DSC_STAT; - ide_drives[d]->service = 0; - ide_drives[d]->board = d >> 1; - ide_drives[d]->selected = !(d & 1); + ide_drives[d]->channel = d; + ide_drives[d]->tf->atastat = DRDY_STAT | DSC_STAT; + ide_drives[d]->service = 0; + ide_drives[d]->board = d >> 1; + ide_drives[d]->selected = !(d & 1); timer_stop(&ide_drives[d]->timer); if (ide_boards[d >> 1]) { @@ -3125,11 +2903,10 @@ ide_reset(UNUSED(void *priv)) { ide_log("Resetting IDE...\n"); - if (ide_boards[0] != NULL) - ide_board_reset(0); - - if (ide_boards[1] != NULL) - ide_board_reset(1); + for (uint8_t i = 0; i < 2; i++) { + if (ide_boards[i] != NULL) + ide_board_reset(i); + } } /* Close a standalone IDE unit. */ @@ -3138,14 +2915,11 @@ ide_close(UNUSED(void *priv)) { ide_log("Closing IDE...\n"); - if (ide_boards[0] != NULL) { - ide_board_close(0); - ide_boards[0] = NULL; - } - - if (ide_boards[1] != NULL) { - ide_board_close(1); - ide_boards[1] = NULL; + for (uint8_t i = 0; i < 2; i++) { + if (ide_boards[i] != NULL) { + ide_board_close(i); + ide_boards[i] = NULL; + } } } diff --git a/src/disk/hdc_xtide.c b/src/disk/hdc_xtide.c index 91bf5a2e3..dfe5931f1 100644 --- a/src/disk/hdc_xtide.c +++ b/src/disk/hdc_xtide.c @@ -40,6 +40,7 @@ #include <86box/io.h> #include <86box/mem.h> #include <86box/rom.h> +#include <86box/timer.h> #include <86box/device.h> #include <86box/hdc.h> #include <86box/hdc_ide.h> diff --git a/src/disk/mo.c b/src/disk/mo.c index 7d2a5c9e0..ad781a8ac 100644 --- a/src/disk/mo.c +++ b/src/disk/mo.c @@ -49,6 +49,8 @@ # include #endif +#define IDE_ATAPI_IS_EARLY id->sc->pad0 + mo_drive_t mo_drives[MO_NUM]; /* Table of all SCSI commands and their flags, needed for the new disc change / not ready handler. */ @@ -443,11 +445,11 @@ mo_init(mo_t *dev) dev->drv->bus_mode |= 1; mo_log("MO %i: Bus type %i, bus mode %i\n", dev->id, dev->drv->bus_type, dev->drv->bus_mode); if (dev->drv->bus_type < MO_BUS_SCSI) { - dev->phase = 1; - dev->request_length = 0xEB14; + dev->tf->phase = 1; + dev->tf->request_length = 0xEB14; } - dev->status = READY_STAT | DSC_STAT; - dev->pos = 0; + dev->tf->status = READY_STAT | DSC_STAT; + dev->tf->pos = 0; dev->packet_status = PHASE_NONE; mo_sense_key = mo_asc = mo_ascq = dev->unit_attention = 0; } @@ -477,36 +479,9 @@ mo_current_mode(mo_t *dev) if (!mo_supports_pio(dev) && mo_supports_dma(dev)) return 2; if (mo_supports_pio(dev) && mo_supports_dma(dev)) { - mo_log("MO %i: Drive supports both, setting to %s\n", dev->id, (dev->features & 1) ? "DMA" : "PIO"); - return (dev->features & 1) ? 2 : 1; - } - - return 0; -} - -/* Translates ATAPI phase (DRQ, I/O, C/D) to SCSI phase (MSG, C/D, I/O). */ -int -mo_atapi_phase_to_scsi(mo_t *dev) -{ - if (dev->status & 8) { - switch (dev->phase & 3) { - case 0: - return 0; - case 1: - return 2; - case 2: - return 1; - case 3: - return 7; - - default: - break; - } - } else { - if ((dev->phase & 3) == 3) - return 3; - else - return 4; + mo_log("MO %i: Drive supports both, setting to %s\n", dev->id, + (dev->tf->features & 1) ? "DMA" : "PIO"); + return (dev->tf->features & 1) ? 2 : 1; } return 0; @@ -622,7 +597,7 @@ mo_update_request_length(mo_t *dev, int len, int block_len) int bt; int min_len = 0; - dev->max_transfer_len = dev->request_length; + dev->max_transfer_len = dev->tf->request_length; /* For media access commands, make sure the requested DRQ length matches the block length. */ switch (dev->current_cdb[0]) { @@ -666,9 +641,9 @@ mo_update_request_length(mo_t *dev, int len, int block_len) dev->max_transfer_len = 65534; if ((len <= dev->max_transfer_len) && (len >= min_len)) - dev->request_length = dev->max_transfer_len = len; + dev->tf->request_length = dev->max_transfer_len = len; else if (len > dev->max_transfer_len) - dev->request_length = dev->max_transfer_len; + dev->tf->request_length = dev->max_transfer_len; return; } @@ -699,9 +674,9 @@ mo_command_common(mo_t *dev) double bytes_per_second; double period; - dev->status = BUSY_STAT; - dev->phase = 1; - dev->pos = 0; + dev->tf->status = BUSY_STAT; + dev->tf->phase = 1; + dev->tf->pos = 0; if (dev->packet_status == PHASE_COMPLETE) dev->callback = 0.0; else { @@ -763,8 +738,8 @@ static void mo_data_command_finish(mo_t *dev, int len, int block_len, int alloc_len, int direction) { mo_log("MO %i: Finishing command (%02X): %i, %i, %i, %i, %i\n", - dev->id, dev->current_cdb[0], len, block_len, alloc_len, direction, dev->request_length); - dev->pos = 0; + dev->id, dev->current_cdb[0], len, block_len, alloc_len, direction, dev->tf->request_length); + dev->tf->pos = 0; if (alloc_len >= 0) { if (alloc_len < len) len = alloc_len; @@ -793,7 +768,8 @@ mo_data_command_finish(mo_t *dev, int len, int block_len, int alloc_len, int dir } mo_log("MO %i: Status: %i, cylinder %i, packet length: %i, position: %i, phase: %i\n", - dev->id, dev->packet_status, dev->request_length, dev->packet_len, dev->pos, dev->phase); + dev->id, dev->packet_status, dev->tf->request_length, dev->packet_len, dev->tf->pos, + dev->tf->phase); } static void @@ -818,14 +794,14 @@ static void mo_cmd_error(mo_t *dev) { mo_set_phase(dev, SCSI_PHASE_STATUS); - dev->error = ((mo_sense_key & 0xf) << 4) | ABRT_ERR; + dev->tf->error = ((mo_sense_key & 0xf) << 4) | ABRT_ERR; if (dev->unit_attention) - dev->error |= MCR_ERR; - dev->status = READY_STAT | ERR_STAT; - dev->phase = 3; - dev->pos = 0; - dev->packet_status = PHASE_ERROR; - dev->callback = 50.0 * MO_TIME; + dev->tf->error |= MCR_ERR; + dev->tf->status = READY_STAT | ERR_STAT; + dev->tf->phase = 3; + dev->tf->pos = 0; + dev->packet_status = PHASE_ERROR; + dev->callback = 50.0 * MO_TIME; mo_set_callback(dev); ui_sb_update_icon(SB_MO | dev->id, 0); mo_log("MO %i: [%02X] ERROR: %02X/%02X/%02X\n", dev->id, dev->current_cdb[0], mo_sense_key, mo_asc, mo_ascq); @@ -835,14 +811,14 @@ static void mo_unit_attention(mo_t *dev) { mo_set_phase(dev, SCSI_PHASE_STATUS); - dev->error = (SENSE_UNIT_ATTENTION << 4) | ABRT_ERR; + dev->tf->error = (SENSE_UNIT_ATTENTION << 4) | ABRT_ERR; if (dev->unit_attention) - dev->error |= MCR_ERR; - dev->status = READY_STAT | ERR_STAT; - dev->phase = 3; - dev->pos = 0; - dev->packet_status = PHASE_ERROR; - dev->callback = 50.0 * MO_TIME; + dev->tf->error |= MCR_ERR; + dev->tf->status = READY_STAT | ERR_STAT; + dev->tf->phase = 3; + dev->tf->pos = 0; + dev->packet_status = PHASE_ERROR; + dev->callback = 50.0 * MO_TIME; mo_set_callback(dev); ui_sb_update_icon(SB_MO | dev->id, 0); mo_log("MO %i: UNIT ATTENTION\n", dev->id); @@ -928,7 +904,7 @@ mo_invalid_field(mo_t *dev) mo_asc = ASC_INV_FIELD_IN_CMD_PACKET; mo_ascq = 0; mo_cmd_error(dev); - dev->status = 0x53; + dev->tf->status = 0x53; } static void @@ -938,7 +914,7 @@ mo_invalid_field_pl(mo_t *dev) mo_asc = ASC_INV_FIELD_IN_PARAMETER_LIST; mo_ascq = 0; mo_cmd_error(dev); - dev->status = 0x53; + dev->tf->status = 0x53; } static int @@ -1112,7 +1088,8 @@ mo_pre_execution_check(mo_t *dev, uint8_t *cdb) int ready = 0; if ((cdb[0] != GPCMD_REQUEST_SENSE) && (dev->cur_lun == SCSI_LUN_USE_CDB) && (cdb[1] & 0xe0)) { - mo_log("MO %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", dev->id, ((dev->request_length >> 5) & 7)); + mo_log("MO %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", dev->id, + ((dev->tf->request_length >> 5) & 7)); mo_invalid_lun(dev); return 0; } @@ -1202,14 +1179,14 @@ mo_reset(scsi_common_t *sc) mo_t *dev = (mo_t *) sc; mo_rezero(dev); - dev->status = 0; - dev->callback = 0.0; + dev->tf->status = 0; + dev->callback = 0.0; mo_set_callback(dev); - dev->phase = 1; - dev->request_length = 0xEB14; - dev->packet_status = PHASE_NONE; - dev->unit_attention = 0; - dev->cur_lun = SCSI_LUN_USE_CDB; + dev->tf->phase = 1; + dev->tf->request_length = 0xEB14; + dev->packet_status = PHASE_NONE; + dev->unit_attention = 0; + dev->cur_lun = SCSI_LUN_USE_CDB; } static void @@ -1302,11 +1279,11 @@ mo_command(scsi_common_t *sc, uint8_t *cdb) uint8_t scsi_id = dev->drv->scsi_device_id & 0x0f; if (dev->drv->bus_type == MO_BUS_SCSI) { - BufLen = &scsi_devices[scsi_bus][scsi_id].buffer_length; - dev->status &= ~ERR_STAT; + BufLen = &scsi_devices[scsi_bus][scsi_id].buffer_length; + dev->tf->status &= ~ERR_STAT; } else { - BufLen = &blen; - dev->error = 0; + BufLen = &blen; + dev->tf->error = 0; } dev->packet_len = 0; @@ -1319,7 +1296,7 @@ mo_command(scsi_common_t *sc, uint8_t *cdb) if (cdb[0] != 0) { mo_log("MO %i: Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X, Unit attention: %i\n", dev->id, cdb[0], mo_sense_key, mo_asc, mo_ascq, dev->unit_attention); - mo_log("MO %i: Request length: %04X\n", dev->id, dev->request_length); + mo_log("MO %i: Request length: %04X\n", dev->id, dev->tf->request_length); mo_log("MO %i: CDB: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", dev->id, cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], @@ -1857,10 +1834,10 @@ mo_command(scsi_common_t *sc, uint8_t *cdb) } #if 0 - mo_log("MO %i: Phase: %02X, request length: %i\n", dev->id, dev->phase, dev->request_length); + mo_log("MO %i: Phase: %02X, request length: %i\n", dev->id, dev->tf->phase, dev->tf->request_length); #endif - if (mo_atapi_phase_to_scsi(dev) == SCSI_PHASE_STATUS) + if ((dev->packet_status == PHASE_COMPLETE) || (dev->packet_status == PHASE_ERROR)) mo_buf_free(dev); } @@ -2099,6 +2076,9 @@ mo_drive_reset(int c) dev->cur_lun = SCSI_LUN_USE_CDB; if (mo_drives[c].bus_type == MO_BUS_SCSI) { + if (!dev->tf) + dev->tf = (ide_tf_t *) calloc(1, sizeof(ide_tf_t)); + /* SCSI MO, attach to the SCSI bus. */ sd = &scsi_devices[scsi_bus][scsi_id]; @@ -2117,6 +2097,8 @@ mo_drive_reset(int c) that's not attached to anything. */ if (id) { id->sc = (scsi_common_t *) dev; + dev->tf = id->tf; + IDE_ATAPI_IS_EARLY = 0; id->get_max = mo_get_max; id->get_timings = mo_get_timings; id->identify = mo_identify; @@ -2203,6 +2185,9 @@ mo_close(void) if (dev) { mo_disk_unload(dev); + if (dev->tf) + free(dev->tf); + free(dev); mo_drives[c].priv = NULL; } diff --git a/src/disk/zip.c b/src/disk/zip.c index c9a4fce18..c498383e8 100644 --- a/src/disk/zip.c +++ b/src/disk/zip.c @@ -36,6 +36,8 @@ #include <86box/hdc_ide.h> #include <86box/zip.h> +#define IDE_ATAPI_IS_EARLY id->sc->pad0 + zip_drive_t zip_drives[ZIP_NUM]; /* Table of all SCSI commands and their flags, needed for the new disc change / not ready handler. */ @@ -588,11 +590,11 @@ zip_init(zip_t *dev) dev->drv->bus_mode |= 1; zip_log("ZIP %i: Bus type %i, bus mode %i\n", dev->id, dev->drv->bus_type, dev->drv->bus_mode); if (dev->drv->bus_type < ZIP_BUS_SCSI) { - dev->phase = 1; - dev->request_length = 0xEB14; + dev->tf->phase = 1; + dev->tf->request_length = 0xEB14; } - dev->status = READY_STAT | DSC_STAT; - dev->pos = 0; + dev->tf->status = READY_STAT | DSC_STAT; + dev->tf->pos = 0; dev->packet_status = PHASE_NONE; zip_sense_key = zip_asc = zip_ascq = dev->unit_attention = 0; } @@ -622,36 +624,9 @@ zip_current_mode(zip_t *dev) if (!zip_supports_pio(dev) && zip_supports_dma(dev)) return 2; if (zip_supports_pio(dev) && zip_supports_dma(dev)) { - zip_log("ZIP %i: Drive supports both, setting to %s\n", dev->id, (dev->features & 1) ? "DMA" : "PIO"); - return (dev->features & 1) ? 2 : 1; - } - - return 0; -} - -/* Translates ATAPI phase (DRQ, I/O, C/D) to SCSI phase (MSG, C/D, I/O). */ -int -zip_atapi_phase_to_scsi(zip_t *dev) -{ - if (dev->status & 8) { - switch (dev->phase & 3) { - case 0: - return 0; - case 1: - return 2; - case 2: - return 1; - case 3: - return 7; - - default: - break; - } - } else { - if ((dev->phase & 3) == 3) - return 3; - else - return 4; + zip_log("ZIP %i: Drive supports both, setting to %s\n", dev->id, + (dev->tf->features & 1) ? "DMA" : "PIO"); + return (dev->tf->features & 1) ? 2 : 1; } return 0; @@ -791,7 +766,7 @@ zip_update_request_length(zip_t *dev, int len, int block_len) int bt; int min_len = 0; - dev->max_transfer_len = dev->request_length; + dev->max_transfer_len = dev->tf->request_length; /* For media access commands, make sure the requested DRQ length matches the block length. */ switch (dev->current_cdb[0]) { @@ -835,9 +810,9 @@ zip_update_request_length(zip_t *dev, int len, int block_len) dev->max_transfer_len = 65534; if ((len <= dev->max_transfer_len) && (len >= min_len)) - dev->request_length = dev->max_transfer_len = len; + dev->tf->request_length = dev->max_transfer_len = len; else if (len > dev->max_transfer_len) - dev->request_length = dev->max_transfer_len; + dev->tf->request_length = dev->max_transfer_len; return; } @@ -868,9 +843,9 @@ zip_command_common(zip_t *dev) double bytes_per_second; double period; - dev->status = BUSY_STAT; - dev->phase = 1; - dev->pos = 0; + dev->tf->status = BUSY_STAT; + dev->tf->phase = 1; + dev->tf->pos = 0; if (dev->packet_status == PHASE_COMPLETE) dev->callback = 0.0; else { @@ -932,8 +907,8 @@ static void zip_data_command_finish(zip_t *dev, int len, int block_len, int alloc_len, int direction) { zip_log("ZIP %i: Finishing command (%02X): %i, %i, %i, %i, %i\n", - dev->id, dev->current_cdb[0], len, block_len, alloc_len, direction, dev->request_length); - dev->pos = 0; + dev->id, dev->current_cdb[0], len, block_len, alloc_len, direction, dev->tf->request_length); + dev->tf->pos = 0; if (alloc_len >= 0) { if (alloc_len < len) len = alloc_len; @@ -962,7 +937,8 @@ zip_data_command_finish(zip_t *dev, int len, int block_len, int alloc_len, int d } zip_log("ZIP %i: Status: %i, cylinder %i, packet length: %i, position: %i, phase: %i\n", - dev->id, dev->packet_status, dev->request_length, dev->packet_len, dev->pos, dev->phase); + dev->id, dev->packet_status, dev->tf->request_length, dev->packet_len, dev->tf->pos, + dev->tf->phase); } static void @@ -987,12 +963,12 @@ static void zip_cmd_error(zip_t *dev) { zip_set_phase(dev, SCSI_PHASE_STATUS); - dev->error = ((zip_sense_key & 0xf) << 4) | ABRT_ERR; + dev->tf->error = ((zip_sense_key & 0xf) << 4) | ABRT_ERR; if (dev->unit_attention) - dev->error |= MCR_ERR; - dev->status = READY_STAT | ERR_STAT; - dev->phase = 3; - dev->pos = 0; + dev->tf->error |= MCR_ERR; + dev->tf->status = READY_STAT | ERR_STAT; + dev->tf->phase = 3; + dev->tf->pos = 0; dev->packet_status = PHASE_ERROR; dev->callback = 50.0 * ZIP_TIME; zip_set_callback(dev); @@ -1004,12 +980,12 @@ static void zip_unit_attention(zip_t *dev) { zip_set_phase(dev, SCSI_PHASE_STATUS); - dev->error = (SENSE_UNIT_ATTENTION << 4) | ABRT_ERR; + dev->tf->error = (SENSE_UNIT_ATTENTION << 4) | ABRT_ERR; if (dev->unit_attention) - dev->error |= MCR_ERR; - dev->status = READY_STAT | ERR_STAT; - dev->phase = 3; - dev->pos = 0; + dev->tf->error |= MCR_ERR; + dev->tf->status = READY_STAT | ERR_STAT; + dev->tf->phase = 3; + dev->tf->pos = 0; dev->packet_status = PHASE_ERROR; dev->callback = 50.0 * ZIP_TIME; zip_set_callback(dev); @@ -1097,7 +1073,7 @@ zip_invalid_field(zip_t *dev) zip_asc = ASC_INV_FIELD_IN_CMD_PACKET; zip_ascq = 0; zip_cmd_error(dev); - dev->status = 0x53; + dev->tf->status = 0x53; } static void @@ -1107,7 +1083,7 @@ zip_invalid_field_pl(zip_t *dev) zip_asc = ASC_INV_FIELD_IN_PARAMETER_LIST; zip_ascq = 0; zip_cmd_error(dev); - dev->status = 0x53; + dev->tf->status = 0x53; } static void @@ -1184,7 +1160,8 @@ zip_pre_execution_check(zip_t *dev, uint8_t *cdb) int ready = 0; if ((cdb[0] != GPCMD_REQUEST_SENSE) && (dev->cur_lun == SCSI_LUN_USE_CDB) && (cdb[1] & 0xe0)) { - zip_log("ZIP %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", dev->id, ((dev->request_length >> 5) & 7)); + zip_log("ZIP %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", dev->id, + ((dev->tf->request_length >> 5) & 7)); zip_invalid_lun(dev); return 0; } @@ -1274,14 +1251,14 @@ zip_reset(scsi_common_t *sc) zip_t *dev = (zip_t *) sc; zip_rezero(dev); - dev->status = 0; - dev->callback = 0.0; + dev->tf->status = 0; + dev->callback = 0.0; zip_set_callback(dev); - dev->phase = 1; - dev->request_length = 0xEB14; - dev->packet_status = PHASE_NONE; - dev->unit_attention = 0; - dev->cur_lun = SCSI_LUN_USE_CDB; + dev->tf->phase = 1; + dev->tf->request_length = 0xEB14; + dev->packet_status = PHASE_NONE; + dev->unit_attention = 0; + dev->cur_lun = SCSI_LUN_USE_CDB; } static void @@ -1373,11 +1350,11 @@ zip_command(scsi_common_t *sc, uint8_t *cdb) uint8_t scsi_id = dev->drv->scsi_device_id & 0x0f; if (dev->drv->bus_type == ZIP_BUS_SCSI) { - BufLen = &scsi_devices[scsi_bus][scsi_id].buffer_length; - dev->status &= ~ERR_STAT; + BufLen = &scsi_devices[scsi_bus][scsi_id].buffer_length; + dev->tf->status &= ~ERR_STAT; } else { - BufLen = &blen; - dev->error = 0; + BufLen = &blen; + dev->tf->error = 0; } dev->packet_len = 0; @@ -1388,7 +1365,7 @@ zip_command(scsi_common_t *sc, uint8_t *cdb) if (cdb[0] != 0) { zip_log("ZIP %i: Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X, Unit attention: %i\n", dev->id, cdb[0], zip_sense_key, zip_asc, zip_ascq, dev->unit_attention); - zip_log("ZIP %i: Request length: %04X\n", dev->id, dev->request_length); + zip_log("ZIP %i: Request length: %04X\n", dev->id, dev->tf->request_length); zip_log("ZIP %i: CDB: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", dev->id, cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], @@ -1465,8 +1442,9 @@ zip_command(scsi_common_t *sc, uint8_t *cdb) break; case GPCMD_REQUEST_SENSE: - /* If there's a unit attention condition and there's a buffered not ready, a standalone REQUEST SENSE - should forget about the not ready, and report unit attention straight away. */ + /* If there's a unit attention condition and there's a buffered not + ready, a standalone REQUEST SENSE should forget about the not + ready, and report unit attention straight away. */ zip_set_phase(dev, SCSI_PHASE_DATA_IN); max_len = cdb[4]; @@ -1507,7 +1485,14 @@ zip_command(scsi_common_t *sc, uint8_t *cdb) switch (cdb[0]) { case GPCMD_READ_6: dev->sector_len = cdb[4]; - dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); + /* + For READ (6) and WRITE (6), a length of 0 indicates a + transfer of 256 sectors. + */ + if (dev->sector_len == 0) + dev->sector_len = 256; + dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | + (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); zip_log("ZIP %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, dev->sector_pos); break; case GPCMD_READ_10: @@ -1516,14 +1501,21 @@ zip_command(scsi_common_t *sc, uint8_t *cdb) zip_log("ZIP %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, dev->sector_pos); break; case GPCMD_READ_12: - dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); - dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); + dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | + (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | + (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); break; default: break; } + if (dev->sector_pos >= dev->drv->medium_size) { + zip_lba_out_of_range(dev); + return; + } + if (!dev->sector_len) { zip_set_phase(dev, SCSI_PHASE_STATUS); /* zip_log("ZIP %i: All done - callback set\n", dev->id); */ @@ -1534,9 +1526,13 @@ zip_command(scsi_common_t *sc, uint8_t *cdb) } max_len = dev->sector_len; - dev->requested_blocks = max_len; /* If we're reading all blocks in one go for DMA, why not also for PIO, it should NOT - matter anyway, this step should be identical and only the way the read dat is - transferred to the host should be different. */ + /* + If we're reading all blocks in one go for DMA, why not also for + PIO, it should NOT matter anyway, this step should be identical + and only the way the read dat is transferred to the host should + be different. + */ + dev->requested_blocks = max_len; dev->packet_len = max_len * alloc_length; zip_buf_alloc(dev, dev->packet_len); @@ -1558,10 +1554,7 @@ zip_command(scsi_common_t *sc, uint8_t *cdb) zip_data_command_finish(dev, alloc_length, 512, alloc_length, 0); - if (dev->packet_status != PHASE_COMPLETE) - ui_sb_update_icon(SB_ZIP | dev->id, 1); - else - ui_sb_update_icon(SB_ZIP | dev->id, 0); + ui_sb_update_icon(SB_ZIP | dev->id, dev->packet_status != PHASE_COMPLETE); return; case GPCMD_VERIFY_6: @@ -1590,9 +1583,14 @@ zip_command(scsi_common_t *sc, uint8_t *cdb) case GPCMD_VERIFY_6: case GPCMD_WRITE_6: dev->sector_len = cdb[4]; + /* + For READ (6) and WRITE (6), a length of 0 indicates a + transfer of 256 sectors. + */ if (dev->sector_len == 0) - dev->sector_len = 256; /* For READ (6) and WRITE (6), a length of 0 indicates a transfer of 256 sector. */ - dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); + dev->sector_len = 256; + dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | + (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); break; case GPCMD_VERIFY_10: case GPCMD_WRITE_10: @@ -1604,17 +1602,17 @@ zip_command(scsi_common_t *sc, uint8_t *cdb) case GPCMD_VERIFY_12: case GPCMD_WRITE_12: case GPCMD_WRITE_AND_VERIFY_12: - dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); - dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); + dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | + (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | + (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); break; default: break; } - if ((dev->sector_pos >= dev->drv->medium_size) /* || - ((dev->sector_pos + dev->sector_len - 1) >= dev->drv->medium_size)*/ - ) { + if (dev->sector_pos >= dev->drv->medium_size) { zip_lba_out_of_range(dev); return; } @@ -1629,9 +1627,13 @@ zip_command(scsi_common_t *sc, uint8_t *cdb) } max_len = dev->sector_len; - dev->requested_blocks = max_len; /* If we're writing all blocks in one go for DMA, why not also for PIO, it should NOT - matter anyway, this step should be identical and only the way the read dat is - transferred to the host should be different. */ + /* + If we're writing all blocks in one go for DMA, why not also for + PIO, it should NOT matter anyway, this step should be identical + and only the way the read dat is transferred to the host should + be different. + */ + dev->requested_blocks = max_len; dev->packet_len = max_len * alloc_length; zip_buf_alloc(dev, dev->packet_len); @@ -1643,10 +1645,7 @@ zip_command(scsi_common_t *sc, uint8_t *cdb) zip_data_command_finish(dev, dev->packet_len, 512, dev->packet_len, 1); - if (dev->packet_status != PHASE_COMPLETE) - ui_sb_update_icon(SB_ZIP | dev->id, 1); - else - ui_sb_update_icon(SB_ZIP | dev->id, 0); + ui_sb_update_icon(SB_ZIP | dev->id, dev->packet_status != PHASE_COMPLETE); return; case GPCMD_WRITE_SAME_10: @@ -1665,9 +1664,7 @@ zip_command(scsi_common_t *sc, uint8_t *cdb) dev->sector_len = (cdb[7] << 8) | cdb[8]; dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - if ((dev->sector_pos >= dev->drv->medium_size) /* || - ((dev->sector_pos + dev->sector_len - 1) >= dev->drv->medium_size)*/ - ) { + if (dev->sector_pos >= dev->drv->medium_size) { zip_lba_out_of_range(dev); return; } @@ -1693,10 +1690,7 @@ zip_command(scsi_common_t *sc, uint8_t *cdb) zip_data_command_finish(dev, 512, 512, alloc_length, 1); - if (dev->packet_status != PHASE_COMPLETE) - ui_sb_update_icon(SB_ZIP | dev->id, 1); - else - ui_sb_update_icon(SB_ZIP | dev->id, 0); + ui_sb_update_icon(SB_ZIP | dev->id, dev->packet_status != PHASE_COMPLETE); return; case GPCMD_MODE_SENSE_6: @@ -2034,10 +2028,10 @@ atapi_out: } #if 0 - zip_log("ZIP %i: Phase: %02X, request length: %i\n", dev->id, dev->phase, dev->request_length); + zip_log("ZIP %i: Phase: %02X, request length: %i\n", dev->id, dev->tf->phase, dev->tf->request_length); #endif - if (zip_atapi_phase_to_scsi(dev) == SCSI_PHASE_STATUS) + if ((dev->packet_status == PHASE_COMPLETE) || (dev->packet_status == PHASE_ERROR)) zip_buf_free(dev); } @@ -2321,6 +2315,9 @@ zip_drive_reset(int c) dev->cur_lun = SCSI_LUN_USE_CDB; if (zip_drives[c].bus_type == ZIP_BUS_SCSI) { + if (!dev->tf) + dev->tf = (ide_tf_t *) calloc(1, sizeof(ide_tf_t)); + /* SCSI ZIP, attach to the SCSI bus. */ sd = &scsi_devices[scsi_bus][scsi_id]; @@ -2339,6 +2336,8 @@ zip_drive_reset(int c) that's not attached to anything. */ if (id) { id->sc = (scsi_common_t *) dev; + dev->tf = id->tf; + IDE_ATAPI_IS_EARLY = 0; id->get_max = zip_get_max; id->get_timings = zip_get_timings; id->identify = zip_identify; @@ -2425,6 +2424,9 @@ zip_close(void) if (dev) { zip_disk_unload(dev); + if (dev->tf) + free(dev->tf); + free(dev); zip_drives[c].priv = NULL; } diff --git a/src/include/86box/hdc_ide.h b/src/include/86box/hdc_ide.h index 37b11da85..b1bff13b3 100644 --- a/src/include/86box/hdc_ide.h +++ b/src/include/86box/hdc_ide.h @@ -41,13 +41,46 @@ enum { IDE_ATAPI }; -#ifdef SCSI_DEVICE_H +typedef struct ide_tf_s { + union { + uint8_t cylprecomp; + uint8_t features; + }; + union { + uint8_t secount; + uint8_t phase; + }; + union { + uint16_t cylinder; + uint16_t request_length; + }; + union { + uint8_t atastat; + uint8_t status; + }; + uint8_t error; + uint16_t pad; + uint32_t pos; +} ide_tf_t; + +#ifdef _TIMER_H_ typedef struct ide_s { - uint8_t selected; +#ifdef ANCIENT_CODE + /* Task file. */ + uint8_t cylprecomp; + uint8_t secount; + uint16_t cylinder; uint8_t atastat; uint8_t error; + uint16_t pad; + uint32_t pos; +#endif + + /* The rest. */ + uint8_t selected; uint8_t command; - uint8_t fdisk; + uint8_t head; + uint8_t sector; int type; int board; int irqstat; @@ -56,18 +89,12 @@ typedef struct ide_s { int blockcount; int hdd_num; int channel; - int pos; int sector_pos; int lba; int reset; int mdma_mode; int do_initial_read; - uint32_t secount; - uint32_t sector; - uint32_t cylinder; - uint32_t head; uint32_t drive; - uint32_t cylprecomp; uint32_t cfg_spt; uint32_t cfg_hpc; uint32_t lba_addr; @@ -80,11 +107,19 @@ typedef struct ide_s { pc_timer_t timer; + /* Task file. */ + ide_tf_t * tf; + /* Stuff mostly used by ATAPI */ +#ifdef SCSI_DEVICE_H scsi_common_t *sc; +#else + void * sc; +#endif int interrupt_drq; double pending_delay; +#ifdef SCSI_DEVICE_H int (*get_max)(int ide_has_dma, int type); int (*get_timings)(int ide_has_dma, int type); void (*identify)(struct ide_s *ide, int ide_has_dma); @@ -94,10 +129,22 @@ typedef struct ide_s { uint8_t (*phase_data_out)(scsi_common_t *sc); void (*command_stop)(scsi_common_t *sc); void (*bus_master_error)(scsi_common_t *sc); +#else + void * get_max; + void * get_timings; + void * identify; + void * stop; + void * device_reset; + void * phase_data_out; + void * command_stop; + void * bus_master_error; +#endif } ide_t; +#ifdef EMU_HDC_H extern ide_t *ide_drives[IDE_NUM]; #endif +#endif /* Type: 0 = PIO, @@ -155,16 +202,9 @@ extern void ide_set_bus_master(int board, extern void win_cdrom_eject(uint8_t id); extern void win_cdrom_reload(uint8_t id); -extern void ide_set_base(int board, uint16_t port); -extern void ide_set_side(int board, uint16_t port); +extern void ide_set_base_addr(int board, int base, uint16_t port); -extern void ide_set_handlers(uint8_t board); -extern void ide_remove_handlers(uint8_t board); - -extern void ide_pri_enable(void); -extern void ide_pri_disable(void); -extern void ide_sec_enable(void); -extern void ide_sec_disable(void); +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 @@ -183,4 +223,16 @@ extern void ide_padstr8(uint8_t *buf, int buf_size, const char *src); extern uint8_t ide_read_ali_75(void); extern uint8_t ide_read_ali_76(void); +/* Legacy #define's. */ +#define ide_set_base(board, port) ide_set_base_addr(board, 0, port) +#define ide_set_side(board, port) ide_set_base_addr(board, 1, port) + +#define ide_pri_enable() ide_handlers(0, 1) +#define ide_pri_disable() ide_handlers(0, 0) +#define ide_sec_enable() ide_handlers(1, 1) +#define ide_sec_disable() ide_handlers(1, 0) + +#define ide_set_handlers(board) ide_handlers(board, 1) +#define ide_remove_handlers(board) ide_handlers(board, 0) + #endif /*EMU_IDE_H*/ diff --git a/src/include/86box/hdd.h b/src/include/86box/hdd.h index 9874fb4aa..8c82209c7 100644 --- a/src/include/86box/hdd.h +++ b/src/include/86box/hdd.h @@ -148,7 +148,8 @@ typedef struct hard_disk_t { uint8_t scsi_id; }; uint8_t bus; - uint8_t res; /* Reserved for bus mode */ + uint8_t bus_mode; /* Bit 0 = PIO suported; + Bit 1 = DMA supportd. */ uint8_t wp; /* Disk has been mounted READ-ONLY */ uint8_t pad; uint8_t pad0; diff --git a/src/include/86box/mo.h b/src/include/86box/mo.h index 8071b80b5..5d4b723f3 100644 --- a/src/include/86box/mo.h +++ b/src/include/86box/mo.h @@ -128,23 +128,35 @@ typedef struct mo_t { mode_sense_pages_t ms_pages_saved; mo_drive_t *drv; +#ifdef EMU_IDE_H + ide_tf_t * tf; +#else + void * tf; +#endif uint8_t *buffer; uint8_t atapi_cdb[16]; uint8_t current_cdb[16]; uint8_t sense[256]; - uint8_t status; - uint8_t phase; - uint8_t error; - uint8_t id; +#ifdef ANCIENT_CODE + /* Task file. */ uint8_t features; + uint8_t phase; + uint16_t request_length; + uint8_t status; + uint8_t error; + uint16_t pad; + uint32_t pos; +#endif + + uint8_t id; uint8_t cur_lun; uint8_t pad0; uint8_t pad1; - uint16_t request_length; uint16_t max_transfer_len; + uint16_t pad2; int requested_blocks; int packet_status; @@ -158,7 +170,6 @@ typedef struct mo_t { uint32_t sector_pos; uint32_t sector_len; uint32_t packet_len; - uint32_t pos; double callback; } mo_t; diff --git a/src/include/86box/scsi_cdrom.h b/src/include/86box/scsi_cdrom.h index 35a4676e7..dec537429 100644 --- a/src/include/86box/scsi_cdrom.h +++ b/src/include/86box/scsi_cdrom.h @@ -26,24 +26,36 @@ typedef struct scsi_cdrom_t { /* Common block. */ mode_sense_pages_t ms_pages_saved; - cdrom_t *drv; + cdrom_t * drv; +#ifdef EMU_IDE_H + ide_tf_t *tf; +#else + void * tf; +#endif uint8_t *buffer; uint8_t atapi_cdb[16]; uint8_t current_cdb[16]; uint8_t sense[256]; - uint8_t status; - uint8_t phase; - uint8_t error; - uint8_t id; +#ifdef ANCIENT_CODE + /* Task file. */ uint8_t features; + uint8_t phase; + uint16_t request_length; + uint8_t status; + uint8_t error; + uint16_t pad; + uint32_t pos; +#endif + + uint8_t id; uint8_t cur_lun; uint8_t early; uint8_t pad1; - uint16_t request_length; uint16_t max_transfer_len; + uint16_t pad2; int requested_blocks; int packet_status; @@ -57,7 +69,6 @@ typedef struct scsi_cdrom_t { uint32_t sector_pos; uint32_t sector_len; uint32_t packet_len; - uint32_t pos; double callback; diff --git a/src/include/86box/scsi_device.h b/src/include/86box/scsi_device.h index e04cc058f..cb7e1ad03 100644 --- a/src/include/86box/scsi_device.h +++ b/src/include/86box/scsi_device.h @@ -347,7 +347,12 @@ typedef struct mode_sense_pages_t { typedef struct scsi_common_s { mode_sense_pages_t ms_pages_saved; - void *priv; + void * priv; +#ifdef EMU_IDE_H + ide_tf_t *tf; +#else + void * tf; +#endif uint8_t *temp_buffer; uint8_t atapi_cdb[16]; /* This is atapi_cdb in ATAPI-supporting devices, @@ -355,17 +360,24 @@ typedef struct scsi_common_s { uint8_t current_cdb[16]; uint8_t sense[256]; - uint8_t status; - uint8_t phase; - uint8_t error; - uint8_t id; +#ifdef ANCIENT_CODE + /* Task file. */ uint8_t features; + uint8_t phase; + uint16_t request_length; + uint8_t status; + uint8_t error; + uint16_t pad; + uint32_t pos; +#endif + + uint8_t id; uint8_t cur_lun; uint8_t pad0; uint8_t pad1; - uint16_t request_length; uint16_t max_transfer_len; + uint16_t pad2; int requested_blocks; int packet_status; @@ -379,7 +391,6 @@ typedef struct scsi_common_s { uint32_t sector_pos; uint32_t sector_len; uint32_t packet_len; - uint32_t pos; double callback; } scsi_common_t; diff --git a/src/include/86box/scsi_disk.h b/src/include/86box/scsi_disk.h index 280899ade..a62bc9e20 100644 --- a/src/include/86box/scsi_disk.h +++ b/src/include/86box/scsi_disk.h @@ -20,38 +20,48 @@ typedef struct scsi_disk_t { mode_sense_pages_t ms_pages_saved; hard_disk_t *drv; +#ifdef EMU_IDE_H + ide_tf_t * tf; +#else + void * tf; +#endif uint8_t *temp_buffer; - uint8_t pad[16]; /* This is atapi_cdb in ATAPI-supporting devices, - and pad in SCSI-only devices. */ + uint8_t atapi_cdb[16]; uint8_t current_cdb[16]; uint8_t sense[256]; - uint8_t status; +#ifdef ANCIENT_CODE + /* Task file. */ + uint8_t features; uint8_t phase; - uint8_t error; - uint8_t id; - uint8_t pad0; - uint8_t cur_lun; - uint8_t pad1; - uint8_t pad2; - uint16_t request_length; - uint16_t pad4; + uint8_t status; + uint8_t error; + uint16_t pad; + uint32_t pos; +#endif + + uint8_t id; + uint8_t cur_lun; + uint8_t pad0; + uint8_t pad1; + + uint16_t max_transfer_len; + uint16_t pad2; int requested_blocks; int packet_status; int total_length; int do_page_save; int unit_attention; - int pad5; + int request_pos; int pad6; int pad7; uint32_t sector_pos; uint32_t sector_len; uint32_t packet_len; - uint32_t pos; double callback; } scsi_disk_t; diff --git a/src/include/86box/zip.h b/src/include/86box/zip.h index 2cadb2ff2..a4a4c341f 100644 --- a/src/include/86box/zip.h +++ b/src/include/86box/zip.h @@ -74,23 +74,35 @@ typedef struct zip_t { mode_sense_pages_t ms_pages_saved; zip_drive_t *drv; +#ifdef EMU_IDE_H + ide_tf_t * tf; +#else + void * tf; +#endif uint8_t *buffer; uint8_t atapi_cdb[16]; uint8_t current_cdb[16]; uint8_t sense[256]; - uint8_t status; - uint8_t phase; - uint8_t error; - uint8_t id; +#ifdef ANCIENT_CODE + /* Task file. */ uint8_t features; + uint8_t phase; + uint16_t request_length; + uint8_t status; + uint8_t error; + uint16_t pad; + uint32_t pos; +#endif + + uint8_t id; uint8_t cur_lun; uint8_t pad0; uint8_t pad1; - uint16_t request_length; uint16_t max_transfer_len; + uint16_t pad2; int requested_blocks; int packet_status; @@ -104,7 +116,6 @@ typedef struct zip_t { uint32_t sector_pos; uint32_t sector_len; uint32_t packet_len; - uint32_t pos; double callback; } zip_t; diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index df19f185a..30415c10b 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -41,6 +41,8 @@ #include <86box/scsi_cdrom.h> #include <86box/version.h> +#define IDE_ATAPI_IS_EARLY id->sc->pad0 + #pragma pack(push, 1) typedef struct gesn_cdb_t { uint8_t opcode; @@ -516,15 +518,17 @@ scsi_cdrom_init(scsi_cdrom_t *dev) dev->drv->bus_mode |= 2; if (dev->drv->bus_type < CDROM_BUS_SCSI) dev->drv->bus_mode |= 1; - scsi_cdrom_log("CD-ROM %i: Bus type %i, bus mode %i\n", dev->id, dev->drv->bus_type, dev->drv->bus_mode); + scsi_cdrom_log("CD-ROM %i: Bus type %i, bus mode %i\n", + dev->id, dev->drv->bus_type, dev->drv->bus_mode); dev->sense[0] = 0xf0; dev->sense[7] = 10; - if ((dev->drv->type == CDROM_TYPE_NEC_260_100) || (dev->drv->type == CDROM_TYPE_NEC_260_101)) /*NEC only*/ - dev->status = READY_STAT | DSC_STAT; + /* NEC only */ + if ((dev->drv->type == CDROM_TYPE_NEC_260_100) || (dev->drv->type == CDROM_TYPE_NEC_260_101)) + dev->tf->status = READY_STAT | DSC_STAT; else - dev->status = 0; - dev->pos = 0; + dev->tf->status = 0; + dev->tf->pos = 0; dev->packet_status = PHASE_NONE; scsi_cdrom_sense_key = scsi_cdrom_asc = scsi_cdrom_ascq = dev->unit_attention = 0; dev->drv->cur_speed = dev->drv->speed; @@ -541,37 +545,9 @@ scsi_cdrom_current_mode(scsi_cdrom_t *dev) return 2; else if (dev->drv->bus_type == CDROM_BUS_ATAPI) { scsi_cdrom_log("CD-ROM %i: ATAPI drive, setting to %s\n", dev->id, - (dev->features & 1) ? "DMA" : "PIO", + (dev->tf->features & 1) ? "DMA" : "PIO", dev->id); - return (dev->features & 1) ? 2 : 1; - } - - return 0; -} - -/* Translates ATAPI phase (DRQ, I/O, C/D) to SCSI phase (MSG, C/D, I/O). */ -int -scsi_cdrom_atapi_phase_to_scsi(scsi_cdrom_t *dev) -{ - if (dev->status & 8) { - switch (dev->phase & 3) { - case 0: - return 0; - case 1: - return 2; - case 2: - return 1; - case 3: - return 7; - - default: - break; - } - } else { - if ((dev->phase & 3) == 3) - return 3; - else - return 4; + return (dev->tf->features & 1) ? 2 : 1; } return 0; @@ -617,7 +593,8 @@ scsi_cdrom_get_volume(void *priv, int channel) case CDROM_TYPE_SONY_CDU561_18k: case CDROM_TYPE_SONY_CDU76S_100: case CDROM_TYPE_TEXEL_DMXX24_100: - ret = dev->ms_pages_saved_sony.pages[dev->sony_vendor ? GPMODE_CDROM_AUDIO_PAGE_SONY : GPMODE_CDROM_AUDIO_PAGE][channel ? 11 : 9]; + ret = dev->ms_pages_saved_sony.pages[dev->sony_vendor ? GPMODE_CDROM_AUDIO_PAGE_SONY : + GPMODE_CDROM_AUDIO_PAGE][channel ? 11 : 9]; break; default: ret = dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE][channel ? 11 : 9]; @@ -640,13 +617,15 @@ scsi_cdrom_mode_sense_load(scsi_cdrom_t *dev) case CDROM_TYPE_SONY_CDU76S_100: case CDROM_TYPE_TEXEL_DMXX24_100: memset(&dev->ms_pages_saved_sony, 0, sizeof(mode_sense_pages_t)); - memcpy(&dev->ms_pages_saved_sony, &scsi_cdrom_mode_sense_pages_default_sony_scsi, sizeof(mode_sense_pages_t)); + memcpy(&dev->ms_pages_saved_sony, &scsi_cdrom_mode_sense_pages_default_sony_scsi, + sizeof(mode_sense_pages_t)); memset(file_name, 0, 512); sprintf(file_name, "scsi_cdrom_%02i_mode_sense_sony_bin", dev->id); fp = plat_fopen(nvr_path(file_name), "rb"); if (fp) { - if (fread(dev->ms_pages_saved_sony.pages[GPMODE_CDROM_AUDIO_PAGE_SONY], 1, 0x10, fp) != 0x10) + if (fread(dev->ms_pages_saved_sony.pages[GPMODE_CDROM_AUDIO_PAGE_SONY], 1, + 0x10, fp) != 0x10) fatal("scsi_cdrom_mode_sense_load(): Error reading data\n"); fclose(fp); } @@ -654,9 +633,11 @@ scsi_cdrom_mode_sense_load(scsi_cdrom_t *dev) default: memset(&dev->ms_pages_saved, 0, sizeof(mode_sense_pages_t)); if (dev->drv->bus_type == CDROM_BUS_SCSI) - memcpy(&dev->ms_pages_saved, &scsi_cdrom_mode_sense_pages_default_scsi, sizeof(mode_sense_pages_t)); + memcpy(&dev->ms_pages_saved, &scsi_cdrom_mode_sense_pages_default_scsi, + sizeof(mode_sense_pages_t)); else - memcpy(&dev->ms_pages_saved, &scsi_cdrom_mode_sense_pages_default, sizeof(mode_sense_pages_t)); + memcpy(&dev->ms_pages_saved, &scsi_cdrom_mode_sense_pages_default, + sizeof(mode_sense_pages_t)); memset(file_name, 0, 512); if (dev->drv->bus_type == CDROM_BUS_SCSI) @@ -839,14 +820,14 @@ scsi_cdrom_mode_sense(scsi_cdrom_t *dev, uint8_t *buf, uint32_t pos, uint8_t pag else { if ((i == GPMODE_CAPABILITIES_PAGE) && (j == 4)) { buf[pos] = scsi_cdrom_mode_sense_read(dev, page_control, i, 2 + j) & 0x1f; - /* The early CD-ROM drives we emulate (NEC CDR-260 for ATAPI and early vendor SCSI CD-ROM models) are - caddy drives, the later ones are tray drives. */ - if (dev->drv->bus_type == CDROM_BUS_SCSI) { + /* The early CD-ROM drives we emulate (NEC CDR-260 for ATAPI and + early vendor SCSI CD-ROM models) are caddy drives, the later + ones are tray drives. */ + if (dev->drv->bus_type == CDROM_BUS_SCSI) buf[pos++] |= ((dev->drv->type == CDROM_TYPE_86BOX_100) ? 0x20 : 0x00); - } else { + else buf[pos++] |= ((dev->drv->type == CDROM_TYPE_NEC_260_100) || ((dev->drv->type == CDROM_TYPE_NEC_260_101)) ? 0x00 : 0x20); - } } else if ((i == GPMODE_CAPABILITIES_PAGE) && (j >= 6) && (j <= 7)) { if (j & 1) buf[pos++] = ((dev->drv->speed * 176) & 0xff); @@ -881,7 +862,7 @@ scsi_cdrom_update_request_length(scsi_cdrom_t *dev, int len, int block_len) int32_t min_len = 0; double dlen; - dev->max_transfer_len = dev->request_length; + dev->max_transfer_len = dev->tf->request_length; /* For media access commands, make sure the requested DRQ length matches the block length. */ switch (dev->current_cdb[0]) { @@ -936,9 +917,9 @@ scsi_cdrom_update_request_length(scsi_cdrom_t *dev, int len, int block_len) dev->max_transfer_len = 65534; if ((len <= dev->max_transfer_len) && (len >= min_len)) - dev->request_length = dev->max_transfer_len = len; + dev->tf->request_length = dev->max_transfer_len = len; else if (len > dev->max_transfer_len) - dev->request_length = dev->max_transfer_len; + dev->tf->request_length = dev->max_transfer_len; return; } @@ -969,10 +950,11 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) double bytes_per_second = 0.0; double period; - dev->status = BUSY_STAT; - dev->phase = 1; - dev->pos = 0; - dev->callback = 0; + /* MAP: BUSY_STAT, no DRQ, phase 1. */ + dev->tf->status = BUSY_STAT; + dev->tf->phase = 1; + dev->tf->pos = 0; + dev->callback = 0; scsi_cdrom_log("CD-ROM %i: Current speed: %ix\n", dev->id, dev->drv->cur_speed); @@ -1000,14 +982,10 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) dev->callback += period; fallthrough; case 0x25: - case 0x42: - case 0x43: - case 0x44: - case 0x51: - case 0x52: + case 0x42 ... 0x44: + case 0x51 ... 0x52: case 0xad: - case 0xb8: - case 0xb9: + case 0xb8 ... 0xb9: case 0xbe: if (dev->current_cdb[0] == 0x42) dev->callback += 40.0; @@ -1015,8 +993,7 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) bytes_per_second = 176.0 * 1024.0; bytes_per_second *= (double) dev->drv->cur_speed; break; - case 0xc6: - case 0xc7: + case 0xc6 ... 0xc7: switch (dev->drv->type) { case CDROM_TYPE_TOSHIBA_XM_3433: case CDROM_TYPE_TOSHIBA_XM3201B_3232: @@ -1050,8 +1027,7 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) bytes_per_second *= (double) dev->drv->cur_speed; break; } - case 0xc2: - case 0xc3: + case 0xc2 ... 0xc3: switch (dev->drv->type) { case CDROM_TYPE_DEC_RRD45_0436: case CDROM_TYPE_SONY_CDU541_10i: @@ -1065,8 +1041,7 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) bytes_per_second *= (double) dev->drv->cur_speed; break; } - case 0xdd: - case 0xde: + case 0xdd ... 0xde: switch (dev->drv->type) { case CDROM_TYPE_NEC_38_103: case CDROM_TYPE_NEC_211_100: @@ -1100,7 +1075,7 @@ scsi_cdrom_command_complete(scsi_cdrom_t *dev) ui_sb_update_icon(SB_CDROM | dev->id, 0); dev->packet_status = PHASE_COMPLETE; scsi_cdrom_command_common(dev); - dev->phase = 3; + dev->tf->phase = 3; } static void @@ -1108,7 +1083,7 @@ scsi_cdrom_command_read(scsi_cdrom_t *dev) { dev->packet_status = PHASE_DATA_IN; scsi_cdrom_command_common(dev); - dev->phase = !(dev->packet_status & 0x01) << 1; + dev->tf->phase = !(dev->packet_status & 0x01) << 1; } static void @@ -1123,7 +1098,7 @@ scsi_cdrom_command_write(scsi_cdrom_t *dev) { dev->packet_status = PHASE_DATA_OUT; scsi_cdrom_command_common(dev); - dev->phase = !(dev->packet_status & 0x01) << 1; + dev->tf->phase = !(dev->packet_status & 0x01) << 1; } static void @@ -1142,8 +1117,9 @@ static void scsi_cdrom_data_command_finish(scsi_cdrom_t *dev, int len, int block_len, int alloc_len, int direction) { scsi_cdrom_log("CD-ROM %i: Finishing command (%02X): %i, %i, %i, %i, %i\n", - dev->id, dev->current_cdb[0], len, block_len, alloc_len, direction, dev->request_length); - dev->pos = 0; + dev->id, dev->current_cdb[0], len, block_len, alloc_len, direction, + dev->tf->request_length); + dev->tf->pos = 0; if (alloc_len >= 0) { if (alloc_len < len) len = alloc_len; @@ -1172,7 +1148,8 @@ scsi_cdrom_data_command_finish(scsi_cdrom_t *dev, int len, int block_len, int al } scsi_cdrom_log("CD-ROM %i: Status: %i, cylinder %i, packet length: %i, position: %i, phase: %i\n", - dev->id, dev->packet_status, dev->request_length, dev->packet_len, dev->pos, dev->phase); + dev->id, dev->packet_status, dev->tf->request_length, dev->packet_len, dev->tf->pos, + dev->tf->phase); } static void @@ -1197,14 +1174,14 @@ static void scsi_cdrom_cmd_error(scsi_cdrom_t *dev) { scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - dev->error = ((scsi_cdrom_sense_key & 0xf) << 4) | ABRT_ERR; + dev->tf->error = ((scsi_cdrom_sense_key & 0xf) << 4) | ABRT_ERR; if (dev->unit_attention) - dev->error |= MCR_ERR; - dev->status = READY_STAT | ERR_STAT; - dev->phase = 3; - dev->pos = 0; - dev->packet_status = PHASE_ERROR; - dev->callback = 50.0 * CDROM_TIME; + dev->tf->error |= MCR_ERR; + dev->tf->status = READY_STAT | ERR_STAT; + dev->tf->phase = 3; + dev->tf->pos = 0; + dev->packet_status = PHASE_ERROR; + dev->callback = 50.0 * CDROM_TIME; scsi_cdrom_set_callback(dev); ui_sb_update_icon(SB_CDROM | dev->id, 0); scsi_cdrom_log("CD-ROM %i: ERROR: %02X/%02X/%02X\n", dev->id, scsi_cdrom_sense_key, scsi_cdrom_asc, scsi_cdrom_ascq); @@ -1214,12 +1191,12 @@ static void scsi_cdrom_unit_attention(scsi_cdrom_t *dev) { scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - dev->error = (SENSE_UNIT_ATTENTION << 4) | ABRT_ERR; + dev->tf->error = (SENSE_UNIT_ATTENTION << 4) | ABRT_ERR; if (dev->unit_attention) - dev->error |= MCR_ERR; - dev->status = READY_STAT | ERR_STAT; - dev->phase = 3; - dev->pos = 0; + dev->tf->error |= MCR_ERR; + dev->tf->status = READY_STAT | ERR_STAT; + dev->tf->phase = 3; + dev->tf->pos = 0; dev->packet_status = PHASE_ERROR; dev->callback = 50.0 * CDROM_TIME; scsi_cdrom_set_callback(dev); @@ -1298,7 +1275,7 @@ scsi_cdrom_invalid_field(scsi_cdrom_t *dev) scsi_cdrom_asc = ASC_INV_FIELD_IN_CMD_PACKET; scsi_cdrom_ascq = 0; scsi_cdrom_cmd_error(dev); - dev->status = 0x53; + dev->tf->status = 0x53; } static void @@ -1308,7 +1285,7 @@ scsi_cdrom_invalid_field_pl(scsi_cdrom_t *dev) scsi_cdrom_asc = ASC_INV_FIELD_IN_PARAMETER_LIST; scsi_cdrom_ascq = 0; scsi_cdrom_cmd_error(dev); - dev->status = 0x53; + dev->tf->status = 0x53; } static void @@ -1575,7 +1552,7 @@ scsi_cdrom_pre_execution_check(scsi_cdrom_t *dev, uint8_t *cdb) if ((cdb[0] != GPCMD_REQUEST_SENSE) && (dev->cur_lun == SCSI_LUN_USE_CDB) && (cdb[1] & 0xe0)) { scsi_cdrom_log("CD-ROM %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", - dev->id, ((dev->request_length >> 5) & 7)); + dev->id, ((dev->tf->request_length >> 5) & 7)); scsi_cdrom_invalid_lun(dev); return 0; } @@ -1674,14 +1651,14 @@ scsi_cdrom_reset(scsi_common_t *sc) return; scsi_cdrom_rezero(dev); - dev->status = 0; - dev->callback = 0.0; + dev->tf->status = 0; + dev->callback = 0.0; scsi_cdrom_set_callback(dev); - dev->phase = 1; - dev->request_length = 0xEB14; - dev->packet_status = PHASE_NONE; - dev->unit_attention = 0xff; - dev->cur_lun = SCSI_LUN_USE_CDB; + dev->tf->phase = 1; + dev->tf->request_length = 0xeb14; + dev->packet_status = PHASE_NONE; + dev->unit_attention = 0xff; + dev->cur_lun = SCSI_LUN_USE_CDB; } static void @@ -1793,10 +1770,10 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) if (dev->drv->bus_type == CDROM_BUS_SCSI) { BufLen = &scsi_devices[scsi_bus][scsi_id].buffer_length; - dev->status &= ~ERR_STAT; + dev->tf->status &= ~ERR_STAT; } else { BufLen = &blen; - dev->error = 0; + dev->tf->error = 0; } dev->packet_len = 0; @@ -1814,11 +1791,12 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) if (cdb[0] != 0) { scsi_cdrom_log("CD-ROM %i: Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X, Unit attention: %i\n", - dev->id, cdb[0], scsi_cdrom_sense_key, scsi_cdrom_asc, scsi_cdrom_ascq, dev->unit_attention); - scsi_cdrom_log("CD-ROM %i: Request length: %04X\n", dev->id, dev->request_length); + dev->id, cdb[0], scsi_cdrom_sense_key, scsi_cdrom_asc, scsi_cdrom_ascq, + dev->unit_attention); + scsi_cdrom_log("CD-ROM %i: Request length: %04X\n", dev->id, dev->tf->request_length); - scsi_cdrom_log("CD-ROM %i: CDB: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", dev->id, - cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], + scsi_cdrom_log("CD-ROM %i: CDB: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", + dev->id, cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8], cdb[9], cdb[10], cdb[11]); } @@ -3727,9 +3705,10 @@ atapi_out: break; } - /* scsi_cdrom_log("CD-ROM %i: Phase: %02X, request length: %i\n", dev->phase, dev->request_length); */ + /* scsi_cdrom_log("CD-ROM %i: Phase: %02X, request length: %i\n", dev->tf->phase, + dev->tf->request_length); */ - if (scsi_cdrom_atapi_phase_to_scsi(dev) == SCSI_PHASE_STATUS) + if ((dev->packet_status == PHASE_COMPLETE) || (dev->packet_status == PHASE_ERROR)) scsi_cdrom_buf_free(dev); } @@ -3905,6 +3884,9 @@ scsi_cdrom_close(void *priv) { scsi_cdrom_t *dev = (scsi_cdrom_t *) priv; + if (dev->tf) + free(dev->tf); + if (dev) free(dev); } @@ -4086,6 +4068,7 @@ scsi_cdrom_drive_reset(int c) ide_t *id; uint8_t scsi_bus = (drv->scsi_device_id >> 4) & 0x0f; uint8_t scsi_id = drv->scsi_device_id & 0x0f; + uint8_t valid = 0; if (drv->bus_type == CDROM_BUS_SCSI) { /* Make sure to ignore any SCSI CD-ROM drive that has an out of range SCSI bus. */ @@ -4118,9 +4101,12 @@ scsi_cdrom_drive_reset(int c) drv->get_channel = scsi_cdrom_get_channel; drv->close = scsi_cdrom_close; - scsi_cdrom_init(dev); - if (drv->bus_type == CDROM_BUS_SCSI) { + valid = 1; + + if (!dev->tf) + dev->tf = (ide_tf_t *) calloc(1, sizeof(ide_tf_t)); + /* SCSI CD-ROM, attach to the SCSI bus. */ sd = &scsi_devices[scsi_bus][scsi_id]; @@ -4140,7 +4126,12 @@ scsi_cdrom_drive_reset(int c) otherwise, we do nothing - it's going to be a drive that's not attached to anything. */ if (id) { + valid = 1; + id->sc = (scsi_common_t *) dev; + dev->tf = id->tf; + if ((dev->drv->type == CDROM_TYPE_NEC_260_100) || (dev->drv->type == CDROM_TYPE_NEC_260_101)) + IDE_ATAPI_IS_EARLY = 1; id->get_max = scsi_cdrom_get_max; id->get_timings = scsi_cdrom_get_timings; id->identify = scsi_cdrom_identify; @@ -4158,4 +4149,7 @@ scsi_cdrom_drive_reset(int c) scsi_cdrom_log("ATAPI CD-ROM drive %i attached to IDE channel %i\n", c, cdrom[c].ide_channel); } + + if (valid) + scsi_cdrom_init(dev); } diff --git a/src/scsi/scsi_device.c b/src/scsi/scsi_device.c index 4fce9f989..4442b2680 100644 --- a/src/scsi/scsi_device.c +++ b/src/scsi/scsi_device.c @@ -23,6 +23,7 @@ #include <86box/86box.h> #include <86box/device.h> #include <86box/hdd.h> +#include <86box/hdc_ide.h> #include <86box/scsi.h> #include <86box/scsi_device.h> #include <86box/plat_unused.h> @@ -37,7 +38,7 @@ scsi_device_target_command(scsi_device_t *dev, uint8_t *cdb) if (dev->command) { dev->command(dev->sc, cdb); - if (dev->sc->status & ERR_STAT) + if (dev->sc->tf->status & ERR_STAT) return SCSI_STATUS_CHECK_CONDITION; else return SCSI_STATUS_OK; @@ -140,7 +141,7 @@ scsi_device_command_phase1(scsi_device_t *dev) } else scsi_device_command_stop(dev); - if (dev->sc->status & ERR_STAT) + if (dev->sc->tf->status & ERR_STAT) dev->status = SCSI_STATUS_CHECK_CONDITION; else dev->status = SCSI_STATUS_OK; diff --git a/src/scsi/scsi_disk.c b/src/scsi/scsi_disk.c index 3db3b729f..ade235b8c 100644 --- a/src/scsi/scsi_disk.c +++ b/src/scsi/scsi_disk.c @@ -20,19 +20,24 @@ #include #define HAVE_STDARG_H #include <86box/86box.h> +#include <86box/config.h> #include <86box/timer.h> #include <86box/device.h> -#include <86box/nvr.h> -#include <86box/hdd.h> -#include <86box/hdc.h> #include <86box/scsi.h> #include <86box/scsi_device.h> +#include <86box/machine.h> +#include <86box/nvr.h> +#include <86box/hdc.h> #include <86box/hdc_ide.h> +#include <86box/sound.h> #include <86box/plat.h> #include <86box/ui.h> +#include <86box/hdd.h> #include <86box/scsi_disk.h> #include <86box/version.h> +#define IDE_ATAPI_IS_EARLY id->sc->pad0 + #define scsi_disk_sense_error dev->sense[0] #define scsi_disk_sense_key dev->sense[2] #define scsi_disk_asc dev->sense[12] @@ -116,6 +121,13 @@ static const mode_sense_pages_t scsi_disk_mode_sense_pages_changeable = { [GPMODE_UNK_VENDOR_PAGE] = { 0xB0, 0x16, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }} }; +static void scsi_disk_command_complete(scsi_disk_t *dev); + +static void scsi_disk_mode_sense_load(scsi_disk_t *dev); + +static void scsi_disk_init(scsi_disk_t *dev); +static void scsi_disk_reset(scsi_common_t *sc); + #ifdef ENABLE_SCSI_DISK_LOG int scsi_disk_do_log = ENABLE_SCSI_DISK_LOG; @@ -134,6 +146,59 @@ scsi_disk_log(const char *fmt, ...) # define scsi_disk_log(fmt, ...) #endif +static void +scsi_disk_set_callback(scsi_disk_t *dev) +{ + if (dev->drv->bus != HDD_BUS_SCSI) + ide_set_callback(ide_drives[dev->drv->ide_channel], dev->callback); +} + +static void +scsi_disk_init(scsi_disk_t *dev) +{ + if (!dev) + return; + + /* Do a reset (which will also rezero it). */ + scsi_disk_reset((scsi_common_t *) dev); + + /* Configure the drive. */ + dev->requested_blocks = 1; + + dev->drv->bus_mode = 0; + if (dev->drv->bus >= HDD_BUS_ATAPI) + dev->drv->bus_mode |= 2; + if (dev->drv->bus < HDD_BUS_SCSI) + dev->drv->bus_mode |= 1; + scsi_disk_log("SCSI HDD %i: Bus type %i, bus mode %i\n", + dev->id, dev->drv->bus, dev->drv->bus_mode); + + dev->sense[0] = 0xf0; + dev->sense[7] = 10; + /* NEC only */ + dev->tf->status = 0; + dev->tf->pos = 0; + dev->packet_status = PHASE_NONE; + scsi_disk_sense_key = scsi_disk_asc = scsi_disk_ascq = dev->unit_attention = 0; + scsi_disk_mode_sense_load(dev); +} + +/* Returns: 0 for none, 1 for PIO, 2 for DMA. */ +static int +scsi_disk_current_mode(scsi_disk_t *dev) +{ + if (dev->drv->bus == HDD_BUS_SCSI) + return 2; + else if (dev->drv->bus == HDD_BUS_ATAPI) { + scsi_disk_log("SCSI DISK %i: ATAPI drive, setting to %s\n", dev->id, + (dev->tf->features & 1) ? "DMA" : "PIO", + dev->id); + return (dev->tf->features & 1) ? 2 : 1; + } + + return 0; +} + void scsi_disk_mode_sense_load(scsi_disk_t *dev) { @@ -279,15 +344,106 @@ scsi_disk_mode_sense(scsi_disk_t *dev, uint8_t *buf, uint32_t pos, uint8_t page, return pos; } +static void +scsi_disk_update_request_length(scsi_disk_t *dev, int len, int block_len) +{ + int bt; + int min_len = 0; + + dev->max_transfer_len = dev->tf->request_length; + + /* For media access commands, make sure the requested DRQ length matches the block length. */ + switch (dev->current_cdb[0]) { + case 0x08: + case 0x0a: + case 0x28: + case 0x2a: + case 0xa8: + case 0xaa: + /* Round it to the nearest 2048 bytes. */ + dev->max_transfer_len = (dev->max_transfer_len >> 9) << 9; + + /* Make sure total length is not bigger than sum of the lengths of + all the requested blocks. */ + bt = (dev->requested_blocks * block_len); + if (len > bt) + len = bt; + + min_len = block_len; + + if (len <= block_len) { + /* Total length is less or equal to block length. */ + if (dev->max_transfer_len < block_len) { + /* Transfer a minimum of (block size) bytes. */ + dev->max_transfer_len = block_len; + dev->packet_len = block_len; + break; + } + } + fallthrough; + + default: + dev->packet_len = len; + break; + } + /* If the DRQ length is odd, and the total remaining length is bigger, make sure it's even. */ + if ((dev->max_transfer_len & 1) && (dev->max_transfer_len < len)) + dev->max_transfer_len &= 0xfffe; + /* If the DRQ length is smaller or equal in size to the total remaining length, set it to that. */ + if (!dev->max_transfer_len) + dev->max_transfer_len = 65534; + + if ((len <= dev->max_transfer_len) && (len >= min_len)) + dev->tf->request_length = dev->max_transfer_len = len; + else if (len > dev->max_transfer_len) + dev->tf->request_length = dev->max_transfer_len; + + return; +} + +static double +scsi_disk_bus_speed(scsi_disk_t *dev) +{ + double ret = -1.0; + + if (dev && dev->drv && (dev->drv->bus == HDD_BUS_SCSI)) { + dev->callback = -1.0; /* Speed depends on SCSI controller */ + return 0.0; + } else { + if (dev && dev->drv) + ret = ide_atapi_get_period(dev->drv->ide_channel); + if (ret == -1.0) { + if (dev) + dev->callback = -1.0; + return 0.0; + } else + return ret * 1000000.0; + } +} + static void scsi_disk_command_common(scsi_disk_t *dev) { - dev->status = BUSY_STAT; - dev->phase = 1; + double bytes_per_second; + double period; + + dev->tf->status = BUSY_STAT; + dev->tf->phase = 1; + dev->tf->pos = 0; if (dev->packet_status == PHASE_COMPLETE) dev->callback = 0.0; - else - dev->callback = -1.0; /* Speed depends on SCSI controller */ + else { + if (dev->drv->bus == HDD_BUS_SCSI) { + dev->callback = -1.0; /* Speed depends on SCSI controller */ + return; + } else + bytes_per_second = scsi_disk_bus_speed(dev); + + period = 1000000.0 / bytes_per_second; + dev->callback = period * (double) (dev->packet_len); + } + + scsi_disk_set_callback(dev); } static void @@ -298,6 +454,13 @@ scsi_disk_command_complete(scsi_disk_t *dev) scsi_disk_command_common(dev); } +static void +scsi_disk_command_read(scsi_disk_t *dev) +{ + dev->packet_status = PHASE_DATA_IN; + scsi_disk_command_common(dev); +} + static void scsi_disk_command_read_dma(scsi_disk_t *dev) { @@ -305,6 +468,13 @@ scsi_disk_command_read_dma(scsi_disk_t *dev) scsi_disk_command_common(dev); } +static void +scsi_disk_command_write(scsi_disk_t *dev) +{ + dev->packet_status = PHASE_DATA_OUT; + scsi_disk_command_common(dev); +} + static void scsi_disk_command_write_dma(scsi_disk_t *dev) { @@ -312,23 +482,48 @@ scsi_disk_command_write_dma(scsi_disk_t *dev) scsi_disk_command_common(dev); } +/* id = Current ZIP device ID; + len = Total transfer length; + block_len = Length of a single block (why does it matter?!); + alloc_len = Allocated transfer length; + direction = Transfer direction (0 = read from host, 1 = write to host). */ static void -scsi_disk_data_command_finish(scsi_disk_t *dev, int len, UNUSED(int block_len), int alloc_len, int direction) +scsi_disk_data_command_finish(scsi_disk_t *dev, int len, int block_len, int alloc_len, int direction) { - scsi_disk_log("SCSI HD %i: Finishing command (%02X): %i, %i, %i, %i, %i\n", dev->id, - dev->current_cdb[0], len, block_len, alloc_len, direction, dev->request_length); + scsi_disk_log("SCSI HD %i: Finishing command (%02X): %i, %i, %i, %i, %i\n", + dev->id, dev->current_cdb[0], len, block_len, alloc_len, direction, + dev->tf->request_length); + dev->tf->pos = 0; if (alloc_len >= 0) { if (alloc_len < len) len = alloc_len; } - if (len == 0) + if ((len == 0) || (scsi_disk_current_mode(dev) == 0)) { + if (dev->drv->bus != HDD_BUS_SCSI) + dev->packet_len = 0; + scsi_disk_command_complete(dev); - else { - if (direction == 0) - scsi_disk_command_read_dma(dev); - else - scsi_disk_command_write_dma(dev); + } else { + if (scsi_disk_current_mode(dev) == 2) { + if (dev->drv->bus != HDD_BUS_SCSI) + dev->packet_len = alloc_len; + + if (direction == 0) + scsi_disk_command_read_dma(dev); + else + scsi_disk_command_write_dma(dev); + } else { + scsi_disk_update_request_length(dev, len, block_len); + if (direction == 0) + scsi_disk_command_read(dev); + else + scsi_disk_command_write(dev); + } } + + scsi_disk_log("SCSI HD %i: Status: %i, cylinder %i, packet length: %i, position: %i, phase: %i\n", + dev->id, dev->packet_status, dev->tf->request_length, dev->packet_len, dev->tf->pos, + dev->tf->phase); } static void @@ -353,15 +548,44 @@ static void scsi_disk_cmd_error(scsi_disk_t *dev) { scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); - dev->error = ((scsi_disk_sense_key & 0xf) << 4) | ABRT_ERR; - dev->status = READY_STAT | ERR_STAT; - dev->phase = 3; + dev->tf->error = ((scsi_disk_sense_key & 0xf) << 4) | ABRT_ERR; + dev->tf->status = READY_STAT | ERR_STAT; + dev->tf->phase = 3; dev->packet_status = PHASE_ERROR; dev->callback = 50.0 * SCSI_TIME; + scsi_disk_set_callback(dev); ui_sb_update_icon(SB_HDD | dev->drv->bus, 0); scsi_disk_log("SCSI HD %i: ERROR: %02X/%02X/%02X\n", dev->id, scsi_disk_sense_key, scsi_disk_asc, scsi_disk_ascq); } +static void +scsi_disk_buf_alloc(scsi_disk_t *dev, uint32_t len) +{ + scsi_disk_log("SCSI HD %i: Allocated buffer length: %i\n", dev->id, len); + if (!dev->temp_buffer) + dev->temp_buffer = (uint8_t *) malloc(len); +} + +static void +scsi_disk_buf_free(scsi_disk_t *dev) +{ + if (dev->temp_buffer) { + scsi_disk_log("SCSI HD %i: Freeing buffer...\n", dev->id); + free(dev->temp_buffer); + dev->temp_buffer = NULL; + } +} + +static void +scsi_disk_bus_master_error(scsi_common_t *sc) +{ + scsi_disk_t *dev = (scsi_disk_t *) sc; + + scsi_disk_buf_free(dev); + scsi_disk_sense_key = scsi_disk_asc = scsi_disk_ascq = 0; + scsi_disk_cmd_error(dev); +} + static void scsi_disk_invalid_lun(scsi_disk_t *dev) { @@ -397,7 +621,7 @@ scsi_disk_invalid_field(scsi_disk_t *dev) scsi_disk_asc = ASC_INV_FIELD_IN_CMD_PACKET; scsi_disk_ascq = 0; scsi_disk_cmd_error(dev); - dev->status = 0x53; + dev->tf->status = 0x53; } static void @@ -407,7 +631,7 @@ scsi_disk_invalid_field_pl(scsi_disk_t *dev) scsi_disk_asc = ASC_INV_FIELD_IN_PARAMETER_LIST; scsi_disk_ascq = 0; scsi_disk_cmd_error(dev); - dev->status = 0x53; + dev->tf->status = 0x53; } static void @@ -419,18 +643,56 @@ scsi_disk_data_phase_error(scsi_disk_t *dev) scsi_disk_cmd_error(dev); } +static int +scsi_disk_blocks(scsi_disk_t *dev, int32_t *len, UNUSED(int first_batch), int out) +{ + *len = 0; + uint32_t medium_size = hdd_image_get_last_sector(dev->id); + + if (!dev->sector_len) { + scsi_disk_command_complete(dev); + return -1; + } + + scsi_disk_log("%sing %i blocks starting from %i...\n", out ? "Writ" : "Read", + dev->requested_blocks, dev->sector_pos); + + if (dev->sector_pos >= medium_size) { + scsi_disk_log("SCSI HD %i: Trying to %s beyond the end of disk\n", dev->id, out ? "write" : "read"); + scsi_disk_lba_out_of_range(dev); + return 0; + } + + *len = dev->requested_blocks << 9; + + for (int i = 0; i < dev->requested_blocks; i++) { + if (out) + hdd_image_write(dev->id, dev->sector_pos + i, 1, dev->temp_buffer + (i << 9)); + else + hdd_image_read(dev->id, dev->sector_pos + i, 1, dev->temp_buffer + (i << 9)); + } + + scsi_disk_log("%s %i bytes of blocks...\n", out ? "Written" : "Read", *len); + + dev->sector_pos += dev->requested_blocks; + dev->sector_len -= dev->requested_blocks; + + return 1; +} + static int scsi_disk_pre_execution_check(scsi_disk_t *dev, uint8_t *cdb) { if ((cdb[0] != GPCMD_REQUEST_SENSE) && (dev->cur_lun == SCSI_LUN_USE_CDB) && (cdb[1] & 0xe0)) { scsi_disk_log("SCSI HD %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", - dev->id, ((dev->request_length >> 5) & 7)); + dev->id, ((dev->tf->request_length >> 5) & 7)); scsi_disk_invalid_lun(dev); return 0; } if (!(scsi_disk_command_flags[cdb[0]] & IMPLEMENTED)) { - scsi_disk_log("SCSI HD %i: Attempting to execute unknown command %02X\n", dev->id, cdb[0]); + scsi_disk_log("SCSI HD %i: Attempting to execute unknown command %02X over %s\n", dev->id, cdb[0], + (dev->drv->bus == HDD_BUS_SCSI) ? "SCSI" : "ATAPI"); scsi_disk_illegal_opcode(dev); return 0; } @@ -468,10 +730,14 @@ scsi_disk_reset(scsi_common_t *sc) scsi_disk_t *dev = (scsi_disk_t *) sc; scsi_disk_rezero(dev); - dev->status = 0; - dev->callback = 0.0; - dev->packet_status = PHASE_NONE; - dev->cur_lun = SCSI_LUN_USE_CDB; + dev->tf->status = 0; + dev->callback = 0.0; + scsi_disk_set_callback(dev); + dev->tf->phase = 1; + dev->tf->request_length = 0xEB14; + dev->packet_status = PHASE_NONE; + dev->unit_attention = 0; + dev->cur_lun = SCSI_LUN_USE_CDB; } void @@ -507,32 +773,16 @@ scsi_disk_request_sense_for_scsi(scsi_common_t *sc, uint8_t *buffer, uint8_t all } static void -scsi_disk_set_buf_len(UNUSED(scsi_disk_t *dev), int32_t *BufLen, int32_t *src_len) +scsi_disk_set_buf_len(scsi_disk_t *dev, int32_t *BufLen, int32_t *src_len) { - if (*BufLen == -1) - *BufLen = *src_len; - else { - *BufLen = MIN(*src_len, *BufLen); - *src_len = *BufLen; - } - scsi_disk_log("SCSI HD %i: Actual transfer length: %i\n", dev->id, *BufLen); -} - -static void -scsi_disk_buf_alloc(scsi_disk_t *dev, uint32_t len) -{ - scsi_disk_log("SCSI HD %i: Allocated buffer length: %i\n", dev->id, len); - if (!dev->temp_buffer) - dev->temp_buffer = (uint8_t *) malloc(len); -} - -static void -scsi_disk_buf_free(scsi_disk_t *dev) -{ - if (dev->temp_buffer) { - scsi_disk_log("SCSI HD %i: Freeing buffer...\n", dev->id); - free(dev->temp_buffer); - dev->temp_buffer = NULL; + if (dev->drv->bus == HDD_BUS_SCSI) { + if (*BufLen == -1) + *BufLen = *src_len; + else { + *BufLen = MIN(*src_len, *BufLen); + *src_len = *BufLen; + } + scsi_disk_log("SCSI HD %i: Actual transfer length: %i\n", dev->id, *BufLen); } } @@ -540,6 +790,8 @@ static void scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) { scsi_disk_t *dev = (scsi_disk_t *) sc; + int ret; + int32_t blen = 0; int32_t *BufLen; int32_t len; int32_t max_len; @@ -555,12 +807,18 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) uint8_t scsi_bus = (dev->drv->scsi_id >> 4) & 0x0f; uint8_t scsi_id = dev->drv->scsi_id & 0x0f; - BufLen = &scsi_devices[scsi_bus][scsi_id].buffer_length; + if (dev->drv->bus == HDD_BUS_SCSI) { + BufLen = &scsi_devices[scsi_bus][scsi_id].buffer_length; + dev->tf->status &= ~ERR_STAT; + } else { + BufLen = &blen; + dev->tf->error = 0; + } last_sector = hdd_image_get_last_sector(dev->id); - dev->status &= ~ERR_STAT; dev->packet_len = 0; + dev->request_pos = 0; device_identify[6] = (dev->id / 10) + 0x30; device_identify[7] = (dev->id % 10) + 0x30; @@ -576,7 +834,7 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) if (cdb[0] != 0) { scsi_disk_log("SCSI HD %i: Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X\n", dev->id, cdb[0], scsi_disk_sense_key, scsi_disk_asc, scsi_disk_ascq); - scsi_disk_log("SCSI HD %i: Request length: %04X\n", dev->id, dev->request_length); + scsi_disk_log("SCSI HD %i: Request length: %04X\n", dev->id, dev->tf->request_length); scsi_disk_log("SCSI HD %i: CDB: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", dev->id, cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], @@ -613,14 +871,16 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) break; case GPCMD_REQUEST_SENSE: - /* If there's a unit attention condition and there's a buffered not ready, a standalone REQUEST SENSE - should forget about the not ready, and report unit attention straight away. */ + /* If there's a unit attention condition and there's a buffered not + ready, a standalone REQUEST SENSE should forget about the not + ready, and report unit attention straight away. */ len = cdb[4]; if (!len) { scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); dev->packet_status = PHASE_COMPLETE; dev->callback = 20.0 * SCSI_TIME; + scsi_disk_set_callback(dev); break; } @@ -653,63 +913,80 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) case GPCMD_READ_6: case GPCMD_READ_10: case GPCMD_READ_12: + scsi_disk_set_phase(dev, SCSI_PHASE_DATA_IN); + alloc_length = 512; + switch (cdb[0]) { case GPCMD_READ_6: dev->sector_len = cdb[4]; + /* + For READ (6) and WRITE (6), a length of 0 indicates a + transfer of 256 sectors. + */ if (dev->sector_len == 0) - dev->sector_len = 256; /* For READ (6) and WRITE (6), a length of 0 indicates a transfer of 256 sector. */ - dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); + dev->sector_len = 256; + dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | + (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); break; case GPCMD_READ_10: dev->sector_len = (cdb[7] << 8) | cdb[8]; dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; break; case GPCMD_READ_12: - dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); - dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); + dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | + (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | + (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); break; default: break; } - if ((dev->sector_pos > last_sector) /* || ((dev->sector_pos + dev->sector_len - 1) > last_sector)*/) { + if (dev->sector_pos > last_sector) { scsi_disk_lba_out_of_range(dev); return; } - if ((!dev->sector_len) || (*BufLen == 0)) { + if (!dev->sector_len) { scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); - scsi_disk_log("SCSI HD %i: All done - callback set\n", dev); + scsi_disk_log("SCSI HD %i: All done - callback set\n", dev->id); dev->packet_status = PHASE_COMPLETE; dev->callback = 20.0 * SCSI_TIME; + scsi_disk_set_callback(dev); break; } max_len = dev->sector_len; + /* + If we're reading all blocks in one go for DMA, why not also for + PIO, it should NOT matter anyway, this step should be identical + and only the way the read dat is transferred to the host should + be different. + */ dev->requested_blocks = max_len; - alloc_length = dev->packet_len = max_len << 9; + dev->packet_len = max_len * alloc_length; scsi_disk_buf_alloc(dev, dev->packet_len); - scsi_disk_set_buf_len(dev, BufLen, &alloc_length); - scsi_disk_set_phase(dev, SCSI_PHASE_DATA_IN); - if ((dev->requested_blocks > 0) && (*BufLen > 0)) { - if (dev->packet_len > (uint32_t) *BufLen) - hdd_image_read(dev->id, dev->sector_pos, *BufLen >> 9, dev->temp_buffer); - else - hdd_image_read(dev->id, dev->sector_pos, dev->requested_blocks, dev->temp_buffer); + ret = scsi_disk_blocks(dev, &alloc_length, 1, 0); + if (ret <= 0) { + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + dev->packet_status = PHASE_COMPLETE; + dev->callback = 20.0 * SCSI_TIME; + scsi_disk_set_callback(dev); + scsi_disk_buf_free(dev); + return; } - if (dev->requested_blocks > 1) - scsi_disk_data_command_finish(dev, alloc_length, alloc_length / dev->requested_blocks, alloc_length, 0); - else - scsi_disk_data_command_finish(dev, alloc_length, alloc_length, alloc_length, 0); + dev->requested_blocks = max_len; + dev->packet_len = alloc_length; - if (dev->packet_status != PHASE_COMPLETE) - ui_sb_update_icon(SB_HDD | dev->drv->bus, 1); - else - ui_sb_update_icon(SB_HDD | dev->drv->bus, 0); + scsi_disk_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len); + + scsi_disk_data_command_finish(dev, alloc_length, 512, alloc_length, 0); + + ui_sb_update_icon(SB_HDD | dev->drv->bus, dev->packet_status != PHASE_COMPLETE); return; case GPCMD_VERIFY_6: @@ -726,70 +1003,82 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) case GPCMD_WRITE_AND_VERIFY_10: case GPCMD_WRITE_12: case GPCMD_WRITE_AND_VERIFY_12: + scsi_disk_set_phase(dev, SCSI_PHASE_DATA_OUT); + alloc_length = 512; + switch (cdb[0]) { case GPCMD_VERIFY_6: case GPCMD_WRITE_6: dev->sector_len = cdb[4]; + /* + For READ (6) and WRITE (6), a length of 0 indicates a + transfer of 256 sectors. + */ if (dev->sector_len == 0) - dev->sector_len = 256; /* For READ (6) and WRITE (6), a length of 0 indicates a transfer of 256 sector. */ - dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); - scsi_disk_log("SCSI HD %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, dev->sector_pos); + dev->sector_len = 256; + dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | + (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); + scsi_disk_log("SCSI HD %i: Length: %i, LBA: %i\n", dev->id, + dev->sector_len, dev->sector_pos); break; case GPCMD_VERIFY_10: case GPCMD_WRITE_10: case GPCMD_WRITE_AND_VERIFY_10: dev->sector_len = (cdb[7] << 8) | cdb[8]; dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - scsi_disk_log("SCSI HD %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, dev->sector_pos); + scsi_disk_log("SCSI HD %i: Length: %i, LBA: %i\n", dev->id, + dev->sector_len, dev->sector_pos); break; case GPCMD_VERIFY_12: case GPCMD_WRITE_12: case GPCMD_WRITE_AND_VERIFY_12: - dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); - dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); + dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | + (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | + (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); break; default: break; } - if ((dev->sector_pos > last_sector) /* || - ((dev->sector_pos + dev->sector_len - 1) > last_sector)*/ - ) { + if (dev->sector_pos > last_sector) { scsi_disk_lba_out_of_range(dev); return; } - if ((!dev->sector_len) || (*BufLen == 0)) { + if (!dev->sector_len) { scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); scsi_disk_log("SCSI HD %i: All done - callback set\n", dev->id); dev->packet_status = PHASE_COMPLETE; dev->callback = 20.0 * SCSI_TIME; + scsi_disk_set_callback(dev); break; } max_len = dev->sector_len; + /* + If we're writing all blocks in one go for DMA, why not also for + PIO, it should NOT matter anyway, this step should be identical + and only the way the read dat is transferred to the host should + be different. + */ dev->requested_blocks = max_len; - alloc_length = dev->packet_len = max_len << 9; + dev->packet_len = max_len * alloc_length; scsi_disk_buf_alloc(dev, dev->packet_len); - scsi_disk_set_buf_len(dev, BufLen, &alloc_length); - scsi_disk_set_phase(dev, SCSI_PHASE_DATA_OUT); + dev->requested_blocks = max_len; + dev->packet_len = max_len << 9; - if (dev->requested_blocks > 1) - scsi_disk_data_command_finish(dev, alloc_length, alloc_length / dev->requested_blocks, alloc_length, 1); - else - scsi_disk_data_command_finish(dev, alloc_length, alloc_length, alloc_length, 1); + scsi_disk_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len); - if (dev->packet_status != PHASE_COMPLETE) - ui_sb_update_icon(SB_HDD | dev->drv->bus, 1); - else - ui_sb_update_icon(SB_HDD | dev->drv->bus, 0); + scsi_disk_data_command_finish(dev, dev->packet_len, 512, dev->packet_len, 1); + + ui_sb_update_icon(SB_HDD | dev->drv->bus, dev->packet_status != PHASE_COMPLETE); return; case GPCMD_WRITE_SAME_10: - scsi_disk_set_phase(dev, SCSI_PHASE_DATA_OUT); alloc_length = 512; if ((cdb[1] & 6) == 6) { @@ -800,42 +1089,43 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) dev->sector_len = (cdb[7] << 8) | cdb[8]; dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - if ((dev->sector_pos > last_sector) /* || - ((dev->sector_pos + dev->sector_len - 1) > last_sector)*/ - ) { + if (dev->sector_pos > last_sector) { scsi_disk_lba_out_of_range(dev); return; } - if ((!dev->sector_len) || (*BufLen == 0)) { + if (!dev->sector_len) { scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); scsi_disk_log("SCSI HD %i: All done - callback set\n", dev->id); dev->packet_status = PHASE_COMPLETE; dev->callback = 20.0 * SCSI_TIME; + scsi_disk_set_callback(dev); break; } scsi_disk_buf_alloc(dev, alloc_length); - scsi_disk_set_buf_len(dev, BufLen, &alloc_length); + scsi_disk_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len); max_len = 1; dev->requested_blocks = 1; + dev->packet_len = alloc_length; + scsi_disk_set_phase(dev, SCSI_PHASE_DATA_OUT); scsi_disk_data_command_finish(dev, 512, 512, alloc_length, 1); - if (dev->packet_status != PHASE_COMPLETE) - ui_sb_update_icon(SB_HDD | dev->drv->bus, 1); - else - ui_sb_update_icon(SB_HDD | dev->drv->bus, 0); + ui_sb_update_icon(SB_HDD | dev->drv->bus, dev->packet_status != PHASE_COMPLETE); return; case GPCMD_MODE_SENSE_6: case GPCMD_MODE_SENSE_10: scsi_disk_set_phase(dev, SCSI_PHASE_DATA_IN); - block_desc = ((cdb[1] >> 3) & 1) ? 0 : 1; + if (dev->drv->bus == HDD_BUS_SCSI) + block_desc = ((cdb[1] >> 3) & 1) ? 0 : 1; + else + block_desc = 0; if (cdb[0] == GPCMD_MODE_SENSE_6) { len = cdb[4]; @@ -968,8 +1258,8 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) memset(dev->temp_buffer, 0, 8); dev->temp_buffer[0] = 0; /*SCSI HD*/ dev->temp_buffer[1] = 0; /*Fixed*/ - dev->temp_buffer[2] = 0x02; /*SCSI-2 compliant*/ - dev->temp_buffer[3] = 0x02; + dev->temp_buffer[2] = (dev->drv->bus == HDD_BUS_SCSI) ? 0x02 : 0x00; /*SCSI-2 compliant*/ + dev->temp_buffer[3] = (dev->drv->bus == HDD_BUS_SCSI) ? 0x02 : 0x21; dev->temp_buffer[4] = 31; dev->temp_buffer[6] = 1; /* 16-bit transfers supported */ dev->temp_buffer[7] = 0x20; /* Wide bus supported */ @@ -1048,7 +1338,11 @@ atapi_out: break; } - /* scsi_disk_log("SCSI HD %i: Phase: %02X, request length: %i\n", dev->id, dev->phase, dev->request_length); */ + /* scsi_disk_log("SCSI HD %i: Phase: %02X, request length: %i\n", dev->id, dev->tf->phase, + dev->tf->request_length); */ + + if ((dev->packet_status == PHASE_COMPLETE) || (dev->packet_status == PHASE_ERROR)) + scsi_disk_buf_free(dev); } static void @@ -1072,6 +1366,7 @@ scsi_disk_phase_data_out(scsi_common_t *sc) uint32_t c; uint32_t h; uint32_t s; + int len = 0; uint32_t last_to_write = 0; uint16_t block_desc_len; uint16_t pos; @@ -1100,12 +1395,8 @@ scsi_disk_phase_data_out(scsi_common_t *sc) case GPCMD_WRITE_AND_VERIFY_10: case GPCMD_WRITE_12: case GPCMD_WRITE_AND_VERIFY_12: - if ((dev->requested_blocks > 0) && (*BufLen > 0)) { - if (dev->packet_len > (uint32_t) *BufLen) - hdd_image_write(dev->id, dev->sector_pos, *BufLen >> 9, dev->temp_buffer); - else - hdd_image_write(dev->id, dev->sector_pos, dev->requested_blocks, dev->temp_buffer); - } + if (dev->requested_blocks > 0) + scsi_disk_blocks(dev, &len, 1, 1); break; case GPCMD_WRITE_SAME_10: if (!dev->current_cdb[7] && !dev->current_cdb[8]) @@ -1147,15 +1438,18 @@ scsi_disk_phase_data_out(scsi_common_t *sc) param_list_len = dev->current_cdb[4]; } - if (dev->current_cdb[0] == GPCMD_MODE_SELECT_6) { - block_desc_len = dev->temp_buffer[2]; - block_desc_len <<= 8; - block_desc_len |= dev->temp_buffer[3]; - } else { - block_desc_len = dev->temp_buffer[6]; - block_desc_len <<= 8; - block_desc_len |= dev->temp_buffer[7]; - } + if (dev->drv->bus == HDD_BUS_SCSI) { + if (dev->current_cdb[0] == GPCMD_MODE_SELECT_6) { + block_desc_len = dev->temp_buffer[2]; + block_desc_len <<= 8; + block_desc_len |= dev->temp_buffer[3]; + } else { + block_desc_len = dev->temp_buffer[6]; + block_desc_len <<= 8; + block_desc_len |= dev->temp_buffer[7]; + } + } else + block_desc_len = 0; pos = hdr_len + block_desc_len; @@ -1210,15 +1504,99 @@ scsi_disk_phase_data_out(scsi_common_t *sc) return 1; } +static int +scsi_disk_get_max(int ide_has_dma, int type) +{ + int ret; + + switch (type) { + case TYPE_PIO: + ret = ide_has_dma ? 4 : 0; + break; + case TYPE_SDMA: + ret = ide_has_dma ? 2 : -1; + break; + case TYPE_MDMA: + ret = ide_has_dma ? 2 : -1; + break; + case TYPE_UDMA: + ret = ide_has_dma ? 5 : -1; + break; + default: + ret = -1; + break; + } + + return ret; +} + +static int +scsi_disk_get_timings(int ide_has_dma, int type) +{ + int ret; + + switch (type) { + case TIMINGS_DMA: + ret = ide_has_dma ? 120 : 0; + break; + case TIMINGS_PIO: + ret = ide_has_dma ? 120 : 0; + break; + case TIMINGS_PIO_FC: + ret = 0; + break; + default: + ret = 0; + break; + } + + return ret; +} + +/** + * Fill in ide->buffer with the output of the "IDENTIFY PACKET DEVICE" command + */ +static void +scsi_disk_identify(ide_t *ide, int ide_has_dma) +{ + const scsi_disk_t *dev; + char device_identify[9] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', 0 }; + + dev = (scsi_disk_t *) ide->sc; + + device_identify[7] = dev->id + 0x30; + scsi_disk_log("ATAPI Identify: %s\n", device_identify); + + /* ATAPI device, direct-access device, non-removable media, accelerated DRQ */ + ide->buffer[0] = 0x8000 | (0 << 8) | 0x00 | (2 << 5); + ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ + + ide_padstr((char *) (ide->buffer + 23), EMU_VERSION_EX, 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), device_identify, 40); /* Model */ + + ide->buffer[49] = 0x200; /* LBA supported */ + ide->buffer[126] = 0xfffe; /* Interpret zero byte count limit as maximum length */ + + if (ide_has_dma) { + ide->buffer[71] = 30; + ide->buffer[72] = 30; + ide->buffer[80] = 0x7e; /*ATA-1 to ATA-6 supported*/ + ide->buffer[81] = 0x19; /*ATA-6 revision 3a supported*/ + } +} + void scsi_disk_hard_reset(void) { scsi_disk_t *dev; scsi_device_t *sd; + ide_t *id; uint8_t scsi_bus; uint8_t scsi_id; + uint8_t valid = 0; for (uint8_t c = 0; c < HDD_NUM; c++) { + valid = 0; if (hdd[c].bus == HDD_BUS_SCSI) { scsi_disk_log("SCSI disk hard_reset drive=%d\n", c); @@ -1241,13 +1619,16 @@ scsi_disk_hard_reset(void) if (!hdd_image_load(c)) continue; - if (!hdd[c].priv) { - hdd[c].priv = (scsi_disk_t *) malloc(sizeof(scsi_disk_t)); - memset(hdd[c].priv, 0, sizeof(scsi_disk_t)); - } + valid = 1; + + if (!hdd[c].priv) + hdd[c].priv = (scsi_disk_t *) calloc(1, sizeof(scsi_disk_t)); dev = (scsi_disk_t *) hdd[c].priv; + if (!dev->tf) + dev->tf = (ide_tf_t *) calloc(1, sizeof(ide_tf_t)); + /* SCSI disk, attach to the SCSI bus. */ sd = &scsi_devices[scsi_bus][scsi_id]; @@ -1259,14 +1640,58 @@ scsi_disk_hard_reset(void) sd->command_stop = scsi_disk_command_stop; sd->type = SCSI_FIXED_DISK; - dev->id = c; - dev->drv = &hdd[c]; + scsi_disk_log("SCSI disk %i attached to SCSI ID %i\n", c, hdd[c].scsi_id); + } else if (hdd[c].bus == HDD_BUS_ATAPI) { + /* Make sure to ignore any SCSI disk whose image file name is empty. */ + if (strlen(hdd[c].fn) == 0) + continue; + + /* Make sure to ignore any SCSI disk whose image fails to load. */ + if (!hdd_image_load(c)) + continue; + + /* ATAPI hard disk, attach to the IDE bus. */ + id = ide_get_drive(hdd[c].ide_channel); + /* If the IDE channel is initialized, we attach to it, + otherwise, we do nothing - it's going to be a drive + that's not attached to anything. */ + if (id) { + valid = 1; + + if (!hdd[c].priv) + hdd[c].priv = (scsi_disk_t *) calloc(1, sizeof(scsi_disk_t)); + + dev = (scsi_disk_t *) hdd[c].priv; + + id->sc = (scsi_common_t *) dev; + dev->tf = id->tf; + IDE_ATAPI_IS_EARLY = 0; + id->get_max = scsi_disk_get_max; + id->get_timings = scsi_disk_get_timings; + id->identify = scsi_disk_identify; + id->stop = NULL; + id->packet_command = scsi_disk_command; + id->device_reset = scsi_disk_reset; + id->phase_data_out = scsi_disk_phase_data_out; + id->command_stop = scsi_disk_command_stop; + id->bus_master_error = scsi_disk_bus_master_error; + id->interrupt_drq = 0; + + ide_atapi_attach(id); + } + + scsi_disk_log("ATAPI hard disk drive %i attached to IDE channel %i\n", c, hdd[c].ide_channel); + } + + if (valid) { + dev->id = c; + dev->drv = &hdd[c]; dev->cur_lun = SCSI_LUN_USE_CDB; - scsi_disk_mode_sense_load(dev); + scsi_disk_init(dev); - scsi_disk_log("SCSI disk %i attached to SCSI ID %i\n", c, hdd[c].scsi_id); + scsi_disk_mode_sense_load(dev); } } } @@ -1279,17 +1704,22 @@ scsi_disk_close(void) uint8_t scsi_id; for (uint8_t c = 0; c < HDD_NUM; c++) { - if (hdd[c].bus == HDD_BUS_SCSI) { - scsi_bus = (hdd[c].scsi_id >> 4) & 0x0f; - scsi_id = hdd[c].scsi_id & 0x0f; + if ((hdd[c].bus == HDD_BUS_SCSI) || (hdd[c].bus == HDD_BUS_ATAPI)) { + if (hdd[c].bus == HDD_BUS_SCSI) { + scsi_bus = (hdd[c].scsi_id >> 4) & 0x0f; + scsi_id = hdd[c].scsi_id & 0x0f; - memset(&scsi_devices[scsi_bus][scsi_id], 0x00, sizeof(scsi_device_t)); + memset(&scsi_devices[scsi_bus][scsi_id], 0x00, sizeof(scsi_device_t)); + } hdd_image_close(c); dev = hdd[c].priv; if (dev) { + if (dev->tf) + free(dev->tf); + free(dev); hdd[c].priv = NULL; }