From 6602368cc4243fa6c9d43c288b0326a76ac1c87f Mon Sep 17 00:00:00 2001 From: SarahW Date: Thu, 15 Mar 2018 19:36:30 +0000 Subject: [PATCH] Implemented ATAPI DMA transfer modes. --- src/ide.c | 35 +++++++++----- src/ide.h | 14 +++++- src/ide_atapi.c | 120 +++++++++++++++++++++++++++++++++++++++++------- src/ide_atapi.h | 4 +- src/piix.c | 44 +++++++++--------- src/scsi.h | 1 + src/scsi_cd.c | 62 ++++++++++++++++++++++++- src/scsi_hd.c | 1 + src/scsi_zip.c | 62 ++++++++++++++++++++++++- 9 files changed, 289 insertions(+), 54 deletions(-) diff --git a/src/ide.c b/src/ide.c index 3f8a6a7..09933f4 100644 --- a/src/ide.c +++ b/src/ide.c @@ -45,6 +45,7 @@ #define WIN_SETIDLE1 0xE3 #define WIN_CHECK_POWER_MODE 0xE5 #define WIN_IDENTIFY 0xEC /* Ask drive to identify itself */ +#define WIN_SET_FEATURES 0xEF /** Evaluate to non-zero if the currently selected drive is an ATAPI device */ #define IDE_DRIVE_IS_CDROM(ide) (ide->type == IDE_CDROM) @@ -93,8 +94,8 @@ IDE *ext_ide; char ide_fn[7][512]; -int (*ide_bus_master_read_sector)(int channel, uint8_t *data); -int (*ide_bus_master_write_sector)(int channel, uint8_t *data); +int (*ide_bus_master_read_data)(int channel, uint8_t *data, int size); +int (*ide_bus_master_write_data)(int channel, uint8_t *data, int size); void (*ide_bus_master_set_irq)(int channel); int idecallback[2] = {0, 0}; @@ -582,7 +583,7 @@ void writeide(int ide_board, uint16_t addr, uint8_t val) return; case WIN_IDENTIFY: /* Identify Device */ - case 0xEF: + case WIN_SET_FEATURES: // output=3; // timetolive=500; ide->atastat = BUSY_STAT; @@ -593,7 +594,7 @@ void writeide(int ide_board, uint16_t addr, uint8_t val) case WIN_PACKETCMD: /* ATAPI Packet */ if (ide->type == IDE_CDROM) - atapi_command_start(&ide->atapi); + atapi_command_start(&ide->atapi, ide->cylprecomp); ide->atastat = BUSY_STAT; timer_process(); @@ -932,9 +933,9 @@ void callbackide(int ide_board) } ide->pos=0; - if (ide_bus_master_read_sector) + if (ide_bus_master_read_data) { - if (ide_bus_master_read_sector(ide_board, &ide->sector_buffer[ide->sector_pos*512])) + if (ide_bus_master_read_data(ide_board, &ide->sector_buffer[ide->sector_pos*512], 512)) idecallback[ide_board]=6*IDE_TIME; /*DMA not performed, try again later*/ else { @@ -1010,9 +1011,9 @@ void callbackide(int ide_board) goto abort_cmd; } - if (ide_bus_master_write_sector) + if (ide_bus_master_write_data) { - if (ide_bus_master_write_sector(ide_board, (uint8_t *)ide->buffer)) + if (ide_bus_master_write_data(ide_board, (uint8_t *)ide->buffer, 512)) idecallback[ide_board]=6*IDE_TIME; /*DMA not performed, try again later*/ else { @@ -1138,7 +1139,6 @@ void callbackide(int ide_board) return; case WIN_SETIDLE1: /* Idle */ - case 0xEF: goto abort_cmd; case WIN_IDENTIFY: /* Identify Device */ @@ -1161,7 +1161,18 @@ void callbackide(int ide_board) } return; + case WIN_SET_FEATURES: + if (ide->type == IDE_NONE) + goto abort_cmd; + if (!IDE_DRIVE_IS_CDROM(ide)) + goto abort_cmd; + if (!atapi_dev->bus.devices[0]->atapi_set_feature(ide->cylprecomp, ide->secount, atapi_dev->bus.device_data[0])) + goto abort_cmd; + ide->atastat = READY_STAT | DSC_STAT; + ide_irq_raise(ide); + return; + case WIN_CHECK_POWER_MODE: if (ide->type == IDE_NONE) { @@ -1291,10 +1302,10 @@ static void ide_close(void *p) { } -void ide_set_bus_master(int (*read_sector)(int channel, uint8_t *data), int (*write_sector)(int channel, uint8_t *data), void (*set_irq)(int channel)) +void ide_set_bus_master(int (*read_data)(int channel, uint8_t *data, int size), int (*write_data)(int channel, uint8_t *data, int size), void (*set_irq)(int channel)) { - ide_bus_master_read_sector = read_sector; - ide_bus_master_write_sector = write_sector; + ide_bus_master_read_data = read_data; + ide_bus_master_write_data = write_data; ide_bus_master_set_irq = set_irq; } diff --git a/src/ide.h b/src/ide.h index 3389c4d..cb497ea 100644 --- a/src/ide.h +++ b/src/ide.h @@ -15,9 +15,13 @@ extern void ide_pri_enable(); extern void ide_sec_enable(); extern void ide_pri_disable(); extern void ide_sec_disable(); -extern void ide_set_bus_master(int (*read_sector)(int channel, uint8_t *data), int (*write_sector)(int channel, uint8_t *data), void (*set_irq)(int channel)); +extern void ide_set_bus_master(int (*read_data)(int channel, uint8_t *data, int size), int (*write_data)(int channel, uint8_t *data, int size), void (*set_irq)(int channel)); void ide_irq_raise(struct IDE *ide); +extern int (*ide_bus_master_read_data)(int channel, uint8_t *data, int size); +extern int (*ide_bus_master_write_data)(int channel, uint8_t *data, int size); +extern void (*ide_bus_master_set_irq)(int channel); + #include "ide_atapi.h" extern int ideboard; @@ -47,4 +51,12 @@ extern device_t ide_device; #define ABRT_ERR 0x04 /* Command aborted */ #define MCR_ERR 0x08 /* Media change request */ +#define FEATURE_SET_TRANSFER_MODE 0x03 +#define FEATURE_ENABLE_IRQ_OVERLAPPED 0x5d +#define FEATURE_ENABLE_IRQ_SERVICE 0x5e +#define FEATURE_DISABLE_REVERT 0x66 +#define FEATURE_ENABLE_REVERT 0xcc +#define FEATURE_DISABLE_IRQ_OVERLAPPED 0xdd +#define FEATURE_DISABLE_IRQ_SERVICE 0xde + #endif //__IDE__ diff --git a/src/ide_atapi.c b/src/ide_atapi.c index 0570eba..ccd7136 100644 --- a/src/ide_atapi.c +++ b/src/ide_atapi.c @@ -17,6 +17,11 @@ #define ATAPI_STATE_READ_DATA_WAIT 8 #define ATAPI_STATE_WRITE_DATA 9 #define ATAPI_STATE_WRITE_DATA_WAIT 10 +#define ATAPI_STATE_RETRY_READ_DMA 11 +#define ATAPI_STATE_RETRY_WRITE_DMA 12 + +#define FEATURES_DMA 0x01 +#define FEATURES_OVERLAP 0x02 ATAPI *atapi; @@ -94,9 +99,11 @@ static int wait_for_bus(scsi_bus_t *bus, int state, int req_needed) return 0; } -void atapi_command_start(atapi_device_t *atapi) +void atapi_command_start(atapi_device_t *atapi, uint8_t features) { scsi_bus_t *bus = &atapi->bus; + + atapi->use_dma = features & 1; scsi_bus_update(bus, BUS_SEL | BUS_SETDATA(1 << 0)); if (!(scsi_bus_read(bus) & BUS_BSY)) @@ -243,19 +250,47 @@ void atapi_process_packet(atapi_device_t *atapi_dev) switch (bus_state & (BUS_IO | BUS_CD | BUS_MSG)) { case 0: - atapi_dev->state = ATAPI_STATE_WRITE_DATA_WAIT; - atapi_dev->data_read_pos = scsi_dev->get_bytes_required(scsi_data); - if (atapi_dev->data_read_pos > atapi_dev->max_transfer_len) - atapi_dev->data_read_pos = atapi_dev->max_transfer_len; atapi_dev->data_write_pos = 0; - *atapi_dev->cylinder = atapi_dev->data_read_pos; + + if (atapi_dev->use_dma) + { + if (ide_bus_master_write_data) + { + if (ide_bus_master_write_data(atapi_dev->board, atapi_dev->data, atapi_dev->data_read_pos)) + { + atapi_dev->state = ATAPI_STATE_RETRY_WRITE_DMA; + idecallback[atapi_dev->board] = 1*IDE_TIME; + } + else + + atapi_dev->data_write_pos = atapi_dev->data_read_pos; { + atapi_dev->bus_state = 0; + atapi_dev->state = ATAPI_STATE_WRITE_DATA; + idecallback[atapi_dev->board] = 6 * IDE_TIME; + } + } + else + { + atapi_dev->state = ATAPI_STATE_RETRY_WRITE_DMA; + idecallback[atapi_dev->board] = 1*IDE_TIME; + } + } + else + { + if (atapi_dev->data_read_pos > atapi_dev->max_transfer_len) + atapi_dev->data_read_pos = atapi_dev->max_transfer_len; + + atapi_dev->state = ATAPI_STATE_WRITE_DATA_WAIT; -// pclog("WRITE_DATA: bytes=%i\n", *atapi_dev->cylinder); - *atapi_dev->atastat = READY_STAT | DRQ_STAT | (*atapi_dev->atastat & ERR_STAT); - atapi_dev->bus_state = BUS_REQ; - ide_irq_raise(atapi_dev->ide); + *atapi_dev->cylinder = atapi_dev->data_read_pos; + +// pclog("WRITE_DATA: bytes=%i\n", *atapi_dev->cylinder); + *atapi_dev->atastat = READY_STAT | DRQ_STAT | (*atapi_dev->atastat & ERR_STAT); + atapi_dev->bus_state = BUS_REQ; + ide_irq_raise(atapi_dev->ide); + } break; case BUS_IO: @@ -391,12 +426,36 @@ void atapi_process_packet(atapi_device_t *atapi_dev) if ((scsi_bus_read(&atapi_dev->bus) & (BUS_IO | BUS_CD | BUS_MSG)) != BUS_IO) break; } - atapi_dev->state = ATAPI_STATE_READ_DATA_WAIT; - *atapi_dev->atastat = READY_STAT | DRQ_STAT | (*atapi_dev->atastat & ERR_STAT); - *atapi_dev->cylinder = atapi_dev->data_write_pos; -// pclog("READ_DATA: bytes=%i\n", *atapi_dev->cylinder); - atapi_dev->bus_state = BUS_IO | BUS_REQ; - ide_irq_raise(atapi_dev->ide); + if (atapi_dev->use_dma) + { + if (ide_bus_master_read_data) + { + if (ide_bus_master_read_data(atapi_dev->board, atapi_dev->data, atapi_dev->data_write_pos)) + { + atapi_dev->state = ATAPI_STATE_RETRY_READ_DMA; + idecallback[atapi_dev->board] = 1*IDE_TIME; + } + else + { + atapi_dev->state = ATAPI_STATE_NEXT_PHASE; + idecallback[atapi_dev->board] = 6*IDE_TIME; + } + } + else + { + atapi_dev->state = ATAPI_STATE_RETRY_READ_DMA; + idecallback[atapi_dev->board] = 1*IDE_TIME; + } + } + else + { + atapi_dev->state = ATAPI_STATE_READ_DATA_WAIT; + *atapi_dev->atastat = READY_STAT | DRQ_STAT | (*atapi_dev->atastat & ERR_STAT); + *atapi_dev->cylinder = atapi_dev->data_write_pos; +// pclog("READ_DATA: bytes=%i\n", *atapi_dev->cylinder); + atapi_dev->bus_state = BUS_IO | BUS_REQ; + ide_irq_raise(atapi_dev->ide); + } } break; @@ -473,5 +532,34 @@ void atapi_process_packet(atapi_device_t *atapi_dev) idecallback[atapi_dev->board] = 6 * IDE_TIME; } break; + + case ATAPI_STATE_RETRY_READ_DMA: + { + if (ide_bus_master_read_data(atapi_dev->board, atapi_dev->data, atapi_dev->data_write_pos)) + { + idecallback[atapi_dev->board] = 1*IDE_TIME; + } + else + { + atapi_dev->state = ATAPI_STATE_NEXT_PHASE; + idecallback[atapi_dev->board] = 6*IDE_TIME; + } + } + break; + + case ATAPI_STATE_RETRY_WRITE_DMA: + { + if (ide_bus_master_write_data(atapi_dev->board, atapi_dev->data, atapi_dev->data_read_pos)) + { + idecallback[atapi_dev->board] = 1*IDE_TIME; + } + else + { + atapi_dev->bus_state = 0; + atapi_dev->state = ATAPI_STATE_WRITE_DATA; + idecallback[atapi_dev->board] = 6 * IDE_TIME; + } + } + break; } } diff --git a/src/ide_atapi.h b/src/ide_atapi.h index c46511c..f737090 100644 --- a/src/ide_atapi.h +++ b/src/ide_atapi.h @@ -53,11 +53,13 @@ typedef struct atapi_device_t uint8_t *atastat; uint8_t *error; int *cylinder; + + int use_dma; } atapi_device_t; void atapi_data_write(atapi_device_t *atapi_dev, uint16_t val); uint16_t atapi_data_read(atapi_device_t *atapi_dev); -void atapi_command_start(atapi_device_t *atapi); +void atapi_command_start(atapi_device_t *atapi, uint8_t features); uint8_t atapi_read_iir(atapi_device_t *atapi_dev); uint8_t atapi_read_drq(atapi_device_t *atapi_dev); void atapi_process_packet(atapi_device_t *atapi_dev); diff --git a/src/piix.c b/src/piix.c index 7538a66..b902419 100644 --- a/src/piix.c +++ b/src/piix.c @@ -216,21 +216,21 @@ uint8_t piix_bus_master_read(uint16_t port, void *priv) return 0xff; } -int piix_bus_master_sector_read(int channel, uint8_t *data) +int piix_bus_master_data_read(int channel, uint8_t *data, int size) { int transferred = 0; if (!(piix_busmaster[channel].status & 1)) return 1; /*DMA disabled*/ - while (transferred < 512) + while (transferred < size) { - if (piix_busmaster[channel].count < (512 - transferred) && piix_busmaster[channel].eot) - fatal("DMA on channel %i - Read count less than 512! Addr %08X Count %04X EOT %i\n", channel, piix_busmaster[channel].addr, piix_busmaster[channel].count, piix_busmaster[channel].eot); + if (piix_busmaster[channel].count < (size - transferred) && piix_busmaster[channel].eot) + fatal("DMA on channel %i - Read count less than size! Addr %08X Count %04X EOT %i size %i\n", channel, piix_busmaster[channel].addr, piix_busmaster[channel].count, piix_busmaster[channel].eot, size); - mem_invalidate_range(piix_busmaster[channel].addr, piix_busmaster[channel].addr+511); + mem_invalidate_range(piix_busmaster[channel].addr, piix_busmaster[channel].addr+(size-1)); - if (piix_busmaster[channel].count < (512 - transferred)) + if (piix_busmaster[channel].count < (size - transferred)) { // pclog("Transferring smaller - %i bytes\n", piix_busmaster[channel].count); if (piix_busmaster[channel].addr < (mem_size * 1024)) @@ -246,17 +246,17 @@ int piix_bus_master_sector_read(int channel, uint8_t *data) } else { -// pclog("Transferring larger - %i bytes\n", 512 - transferred); +// pclog("Transferring larger - %i bytes\n", size - transferred); if (piix_busmaster[channel].addr < (mem_size * 1024)) { - int count = 512 - transferred; + int count = size - transferred; if ((piix_busmaster[channel].addr + count) > (mem_size * 1024)) count = (mem_size * 1024) - piix_busmaster[channel].addr; memcpy(&ram[piix_busmaster[channel].addr], data + transferred, count); } - piix_busmaster[channel].addr += (512 - transferred); - piix_busmaster[channel].count -= (512 - transferred); - transferred += (512 - transferred); + piix_busmaster[channel].addr += (size - transferred); + piix_busmaster[channel].count -= (size - transferred); + transferred += (size - transferred); } // pclog("DMA on channel %i - Addr %08X Count %04X EOT %i\n", channel, piix_busmaster[channel].addr, piix_busmaster[channel].count, piix_busmaster[channel].eot); @@ -275,19 +275,19 @@ int piix_bus_master_sector_read(int channel, uint8_t *data) } return 0; } -int piix_bus_master_sector_write(int channel, uint8_t *data) +int piix_bus_master_data_write(int channel, uint8_t *data, int size) { int transferred = 0; if (!(piix_busmaster[channel].status & 1)) return 1; /*DMA disabled*/ - while (transferred < 512) + while (transferred < size) { - if (piix_busmaster[channel].count < (512 - transferred) && piix_busmaster[channel].eot) - fatal("DMA on channel %i - Write count less than 512! Addr %08X Count %04X EOT %i\n", channel, piix_busmaster[channel].addr, piix_busmaster[channel].count, piix_busmaster[channel].eot); + if (piix_busmaster[channel].count < (size - transferred) && piix_busmaster[channel].eot) + fatal("DMA on channel %i - Write count less than size! Addr %08X Count %04X EOT %i size %i\n", channel, piix_busmaster[channel].addr, piix_busmaster[channel].count, piix_busmaster[channel].eot, size); - if (piix_busmaster[channel].count < (512 - transferred)) + if (piix_busmaster[channel].count < (size - transferred)) { // pclog("Transferring smaller - %i bytes\n", piix_busmaster[channel].count); if (piix_busmaster[channel].addr < (mem_size * 1024)) @@ -303,17 +303,17 @@ int piix_bus_master_sector_write(int channel, uint8_t *data) } else { -// pclog("Transferring larger - %i bytes\n", 512 - transferred); +// pclog("Transferring larger - %i bytes\n", size - transferred); if (piix_busmaster[channel].addr < (mem_size * 1024)) { - int count = 512 - transferred; + int count = size - transferred; if ((piix_busmaster[channel].addr + count) > (mem_size * 1024)) count = (mem_size * 1024) - piix_busmaster[channel].addr; memcpy(data + transferred, &ram[piix_busmaster[channel].addr], count); } - piix_busmaster[channel].addr += (512 - transferred); - piix_busmaster[channel].count -= (512 - transferred); - transferred += (512 - transferred); + piix_busmaster[channel].addr += (size - transferred); + piix_busmaster[channel].count -= (size - transferred); + transferred += (size - transferred); } // pclog("DMA on channel %i - Addr %08X Count %04X EOT %i\n", channel, piix_busmaster[channel].addr, piix_busmaster[channel].count, piix_busmaster[channel].eot); @@ -377,7 +377,7 @@ void piix_init(int card, int pci_a, int pci_b, int pci_c, int pci_d) card_piix_ide[0x40] = card_piix_ide[0x41] = 0x00; card_piix_ide[0x42] = card_piix_ide[0x43] = 0x00; - ide_set_bus_master(piix_bus_master_sector_read, piix_bus_master_sector_write, piix_bus_master_set_irq); + ide_set_bus_master(piix_bus_master_data_read, piix_bus_master_data_write, piix_bus_master_set_irq); pci_set_card_routing(pci_a, PCI_INTA); pci_set_card_routing(pci_b, PCI_INTB); diff --git a/src/scsi.h b/src/scsi.h index a89010c..8791011 100644 --- a/src/scsi.h +++ b/src/scsi.h @@ -18,6 +18,7 @@ typedef struct scsi_device_t int (*get_bytes_required)(void *p); void (*atapi_identify)(uint16_t *buffer, void *p); + int (*atapi_set_feature)(uint8_t feature, uint8_t val, void *p); uint8_t (*read)(void *p); void (*write)(uint8_t val, void *p); diff --git a/src/scsi_cd.c b/src/scsi_cd.c index f7721f5..d782d78 100644 --- a/src/scsi_cd.c +++ b/src/scsi_cd.c @@ -3,6 +3,7 @@ #include #include #include "ibm.h" +#include "ide.h" #include "ide_atapi.h" #include "scsi.h" #include "scsi_cd.h" @@ -194,6 +195,8 @@ typedef struct scsi_cd_data_t int is_atapi; atapi_device_t *atapi_dev; + + int pio_mode, mdma_mode; } scsi_cd_data_t; static void scsi_add_data(scsi_cd_data_t *data, uint8_t val) @@ -1171,16 +1174,72 @@ static int scsi_cd_get_bytes_required(void *p) static void scsi_cd_atapi_identify(uint16_t *buffer, void *p) { + scsi_cd_data_t *data = p; + memset(buffer, 0, 512); buffer[0] = 0x8000 | (5<<8) | 0x80 | (2<<5); /* ATAPI device, CD-ROM drive, removable media, accelerated DRQ */ ide_padstr((char *)(buffer + 10), "", 20); /* Serial Number */ ide_padstr((char *)(buffer + 23), "v1.0", 8); /* Firmware */ ide_padstr((char *)(buffer + 27), "PCemCD", 40); /* Model */ - buffer[49] = 0x200; /* LBA supported */ + buffer[49] = 0x300; /*DMA and LBA supported*/ + buffer[51] = 120; + buffer[52] = 120; + buffer[53] = 2; /*Words 64-70 are valid*/ + buffer[62] = 0x0000; + buffer[63] = 0x0007 | (0x100 << data->mdma_mode); /*Multi-word DMA 0, 1 & 2*/ + buffer[64] = 0x0003; /*PIO Modes 3 & 4*/ + if (data->pio_mode >= 3) + buffer[64] |= (0x100 << (data->pio_mode - 3)); + buffer[65] = 120; /*Minimum multi-word cycle time*/ + buffer[66] = 120; /*Recommended multi-word cycle time*/ + buffer[67] = 120; /*Minimum PIO cycle time*/ buffer[126] = 0xfffe; /* Interpret zero byte count limit as maximum length */ } +static int scsi_cd_atapi_set_feature(uint8_t feature, uint8_t val, void *p) +{ + scsi_cd_data_t *data = p; + + switch (feature) + { + case FEATURE_SET_TRANSFER_MODE: + if (!(val & 0xfe)) + { + /*Default transfer mode*/ + data->pio_mode = 0; + return 1; + } + else if ((val & 0xf8) == 0x08) + { + /*PIO transfer mode*/ + if ((val & 7) > 4) + return 0; + data->pio_mode = (val & 7); + return 1; + } + else if ((val & 0xf8) == 0x20) + { + /*Multi-word DMA transfer mode*/ + if ((val & 7) > 2) + return 0; + data->mdma_mode = (val & 7); + return 1; + } + return 0; /*Invalid data*/ + + case FEATURE_ENABLE_IRQ_OVERLAPPED: + case FEATURE_ENABLE_IRQ_SERVICE: + case FEATURE_DISABLE_REVERT: + case FEATURE_DISABLE_IRQ_OVERLAPPED: + case FEATURE_DISABLE_IRQ_SERVICE: + case FEATURE_ENABLE_REVERT: + return 1; + } + + return 0; /*Feature not supported*/ +} + scsi_device_t scsi_cd = { scsi_cd_init, @@ -1195,6 +1254,7 @@ scsi_device_t scsi_cd = scsi_cd_get_bytes_required, scsi_cd_atapi_identify, + scsi_cd_atapi_set_feature, scsi_cd_read, scsi_cd_write, diff --git a/src/scsi_hd.c b/src/scsi_hd.c index 9cd60ba..f314ebf 100644 --- a/src/scsi_hd.c +++ b/src/scsi_hd.c @@ -826,6 +826,7 @@ scsi_device_t scsi_hd = scsi_hd_get_sense_key, scsi_hd_get_bytes_required, + NULL, NULL, scsi_hd_read, diff --git a/src/scsi_zip.c b/src/scsi_zip.c index e6bb291..18421c5 100644 --- a/src/scsi_zip.c +++ b/src/scsi_zip.c @@ -4,6 +4,7 @@ #include #include "ibm.h" #include "hdd_file.h" +#include "ide.h" #include "ide_atapi.h" #include "scsi.h" #include "scsi_zip.h" @@ -73,6 +74,8 @@ typedef struct scsi_zip_data atapi_device_t *atapi_dev; int read_only; + + int pio_mode, mdma_mode; } scsi_zip_data; static scsi_zip_data *zip_data; @@ -1077,16 +1080,72 @@ static int scsi_zip_get_bytes_required(void *p) static void scsi_zip_atapi_identify(uint16_t *buffer, void *p) { + scsi_zip_data *data = p; + memset(buffer, 0, 512); buffer[0] = 0x8000 | (0<<8) | 0x80 | (2<<5); /* ATAPI device, direct-access device, removable media, accelerated DRQ */ ide_padstr((char *)(buffer + 10), "", 20); /* Serial Number */ ide_padstr((char *)(buffer + 23), "E.08", 8); /* Firmware */ ide_padstr((char *)(buffer + 27), "IOMEGA ZIP 100 ATAPI", 40); /* Model */ - buffer[49] = 0x200; /* LBA supported */ + buffer[49] = 0x300; /*DMA and LBA supported*/ + buffer[51] = 120; + buffer[52] = 120; + buffer[53] = 2; /*Words 64-70 are valid*/ + buffer[62] = 0x0000; + buffer[63] = 0x0003 | (0x100 << data->mdma_mode); /*Multi-word DMA 0 & 1*/ + buffer[64] = 0x0001; /*PIO Mode 3*/ + if (data->pio_mode >= 3) + buffer[64] |= (0x100 << (data->pio_mode - 3)); + buffer[65] = 120; /*Minimum multi-word cycle time*/ + buffer[66] = 120; /*Recommended multi-word cycle time*/ + buffer[67] = 120; /*Minimum PIO cycle time*/ buffer[126] = 0xfffe; /* Interpret zero byte count limit as maximum length */ } +static int scsi_zip_atapi_set_feature(uint8_t feature, uint8_t val, void *p) +{ + scsi_zip_data *data = p; + + switch (feature) + { + case FEATURE_SET_TRANSFER_MODE: + if (!(val & 0xfe)) + { + /*Default transfer mode*/ + data->pio_mode = 0; + return 1; + } + else if ((val & 0xf8) == 0x08) + { + /*PIO transfer mode*/ + if ((val & 7) > 3) + return 0; + data->pio_mode = (val & 7); + return 1; + } + else if ((val & 0xf8) == 0x20) + { + /*Multi-word DMA transfer mode*/ + if ((val & 7) > 1) + return 0; + data->mdma_mode = (val & 7); + return 1; + } + return 0; /*Invalid data*/ + + case FEATURE_ENABLE_IRQ_OVERLAPPED: + case FEATURE_ENABLE_IRQ_SERVICE: + case FEATURE_DISABLE_REVERT: + case FEATURE_DISABLE_IRQ_OVERLAPPED: + case FEATURE_DISABLE_IRQ_SERVICE: + case FEATURE_ENABLE_REVERT: + return 1; + } + + return 0; /*Feature not supported*/ +} + scsi_device_t scsi_zip = { scsi_zip_init, @@ -1101,6 +1160,7 @@ scsi_device_t scsi_zip = scsi_zip_get_bytes_required, scsi_zip_atapi_identify, + scsi_zip_atapi_set_feature, scsi_zip_read, scsi_zip_write,