diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index 3719868..6991013 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -9,7 +9,7 @@ * Implementation of the CD-ROM drive with SCSI(-like) * commands, for both ATAPI and SCSI usage. * - * Version: @(#)cdrom.c 1.0.3 2018/03/07 + * Version: @(#)cdrom.c 1.0.4 2018/03/08 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -738,25 +738,53 @@ void cdrom_update_request_length(uint8_t id, int len, int block_len) static void cdrom_command_common(uint8_t id) { + double bytes_per_second, period; + double dusec; + cdrom[id].status = BUSY_STAT; cdrom[id].phase = 1; cdrom[id].pos = 0; if (cdrom[id].packet_status == CDROM_PHASE_COMPLETE) { - cdrom[id].callback = 20LL * CDROM_TIME; - cdrom_set_callback(id); - } else if (cdrom[id].packet_status == CDROM_PHASE_DATA_IN) { - if (cdrom[id].current_cdb[0] == 0x42) { - cdrom_log("CD-ROM %i: READ SUBCHANNEL\n", id); - cdrom[id].callback = 1000LL * CDROM_TIME; - cdrom_set_callback(id); - } else { - cdrom[id].callback = 60LL * CDROM_TIME; - cdrom_set_callback(id); - } + cdrom_phase_callback(id); + cdrom[id].callback = 0LL; } else { - cdrom[id].callback = 60LL * CDROM_TIME; - cdrom_set_callback(id); + switch(cdrom[id].current_cdb[0]) { + case 0x25: + case 0x42: + case 0x43: + case 0x44: + case 0x08: + case 0x28: + case 0x51: + case 0x52: + case 0xa8: + case 0xad: + case 0xb8: + case 0xb9: + case 0xbe: + bytes_per_second = 150.0 * 1024.0; + bytes_per_second *= (double) cdrom_drives[id].speed; + break; + default: + if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) { + cdrom[id].callback = -1LL; /* Speed depends on SCSI controller */ + return; + } else if (cdrom_drives[id].bus_type == CDROM_BUS_ATAPI_PIO_AND_DMA) { + if (cdrom_current_mode(id) == 2) + bytes_per_second = 66666666.666666666666666; /* 66 MB/s MDMA-2 speed */ + else + bytes_per_second = 8333333.333333333333333; /* 8.3 MB/s PIO-2 speed */ + } else + bytes_per_second = 3333333.333333333333333; /* 3.3 MB/s PIO-0 speed */ + break; + } + + period = 1000000.0 / bytes_per_second; + dusec = (double) TIMER_USEC; + dusec = dusec * period * (double) (cdrom[id].packet_len); + cdrom[id].callback = ((int64_t) dusec); } + cdrom_set_callback(id); } static void cdrom_command_complete(uint8_t id) diff --git a/src/cdrom/cdrom.h b/src/cdrom/cdrom.h index c6eb059..de8e7d4 100644 --- a/src/cdrom/cdrom.h +++ b/src/cdrom/cdrom.h @@ -8,7 +8,7 @@ * * Definitions for the CDROM module.. * - * Version: @(#)cdrom.h 1.0.3 2018/03/04 + * Version: @(#)cdrom.h 1.0.4 2018/03/08 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -193,6 +193,8 @@ typedef struct { unsigned int sound_on; unsigned int atapi_dma; + + uint8_t speed; } cdrom_drive_t; typedef struct { diff --git a/src/config.c b/src/config.c index 1c3fc2b..3d4ee41 100644 --- a/src/config.c +++ b/src/config.c @@ -12,7 +12,7 @@ * it on Windows XP, and possibly also Vista. Use the * -DANSI_CFG for use on these systems. * - * Version: @(#)config.c 1.0.2 2018/02/24 + * Version: @(#)config.c 1.0.3 2018/03/08 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -1246,6 +1246,9 @@ load_other_removable_devices(void) sscanf("0, none", "%01u, %s", &cdrom_drives[c].sound_on, s); cdrom_drives[c].bus_type = hdd_string_to_bus(s, 1); + sprintf(temp, "cdrom_%02i_speed", c+1); + cdrom_drives[c].speed = config_get_int(cat, temp, 8); + /* Default values, needed for proper operation of the Settings dialog. */ cdrom_drives[c].ide_channel = cdrom_drives[c].scsi_device_id = c + 2; @@ -2001,6 +2004,13 @@ save_other_removable_devices(void) config_set_int(cat, temp, cdrom_drives[c].host_drive); } + sprintf(temp, "cdrom_%02i_speed", c+1); + if ((cdrom_drives[c].bus_type == 0) || (cdrom_drives[c].speed == 8)) { + config_delete_var(cat, temp); + } else { + config_set_int(cat, temp, cdrom_drives[c].speed); + } + sprintf(temp, "cdrom_%02i_parameters", c+1); if (cdrom_drives[c].bus_type == 0) { config_delete_var(cat, temp); diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index 295fbea..a74668f 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -9,7 +9,7 @@ * Implementation of the IDE emulation for hard disks and ATAPI * CD-ROM devices. * - * Version: @(#)hdc_ide.c 1.0.5 2018/03/07 + * Version: @(#)hdc_ide.c 1.0.6 2018/03/08 * * Authors: Miran Grca, * Sarah Walker, @@ -504,7 +504,9 @@ static void ide_atapi_zip_identify(IDE *ide) zip_id = atapi_zip_drives[ide->channel]; - ide->buffer[0] = 0x8000 | (0<<8) | 0x80 | (2<<5); /* ATAPI device, direct-access device, removable media, accelerated DRQ */ + /* Using (2<<5) below makes the ASUS P/I-P54TP4XE misdentify the ZIP drive + as a LS-120. */ + ide->buffer[0] = 0x8000 | (0<<8) | 0x80 | (1<<5); /* ATAPI device, direct-access device, removable media, accelerated DRQ */ ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ if (zip_drives[zip_id].is_250) { ide_padstr((char *) (ide->buffer + 23), "42.S", 8); /* Firmware */ @@ -516,7 +518,6 @@ static void ide_atapi_zip_identify(IDE *ide) ide->buffer[49] = 0x200; /* LBA supported */ /* Note by Kotori: Look at this if this is supported by ZIP at all. */ - ide->buffer[48] = 1; /*Dword transfers supported*/ ide->buffer[51] = 2 << 8; /*PIO timing mode*/ ide->buffer[126] = 0xfffe; /* Interpret zero byte count limit as maximum length */ @@ -524,10 +525,9 @@ static void ide_atapi_zip_identify(IDE *ide) if (PCI && (ide->board < 2) && (zip_drives[zip_id].bus_type == ZIP_BUS_ATAPI_PIO_AND_DMA)) { ide->buffer[49] |= 0x100; /* DMA supported */ - ide->buffer[52] = 2 << 8; /*DMA timing mode*/ - ide->buffer[53] = 7; - ide->buffer[62] = 7; - ide->buffer[63] = 7; + ide->buffer[52] = 0 << 8; /*DMA timing mode*/ + ide->buffer[53] = 6; + ide->buffer[63] = 3; ide->buffer[88] = 7; if (ide->mdma_mode != -1) { @@ -535,18 +535,16 @@ static void ide_atapi_zip_identify(IDE *ide) d <<= 8; if ((ide->mdma_mode & 0x300) == 0x200) ide->buffer[88] |= d; - else if ((ide->mdma_mode & 0x300) == 0x100) - ide->buffer[63] |= d; else - ide->buffer[62] |= d; + ide->buffer[63] |= d; ide_log("PIDENTIFY DMA Mode: %04X, %04X\n", ide->buffer[62], ide->buffer[63]); } - ide->buffer[65] = 0xb4; - ide->buffer[66] = 0xb4; - ide->buffer[71] = 30; - ide->buffer[72] = 30; - ide->buffer[80] = 0x1e; /*ATA-1 to ATA-4 supported*/ - ide->buffer[81] = 0x18; /*ATA-4 revision 18 supported*/ + ide->buffer[65] = 0x96; + ide->buffer[66] = 0x96; + ide->buffer[67] = 0xb4; + ide->buffer[68] = 0xb4; + ide->buffer[80] = 0x30; /*Supported ATA versions : ATA/ATAPI-4 ATA/ATAPI-5*/ + ide->buffer[81] = 0x15; /*Maximum ATA revision supported : ATA/ATAPI-5 T13 1321D revision 1*/ } } @@ -644,6 +642,7 @@ static int ide_set_features(IDE *ide) uint8_t mode, submode; int bus, dma; + int max_pio = 2, max_mdma = 2; features = ide->cylprecomp; features_data = ide->secount; @@ -651,6 +650,8 @@ static int ide_set_features(IDE *ide) if (ide_drive_is_zip(ide)) { bus = zip_drives[atapi_zip_drives[ide->channel]].bus_type; dma = (bus == ZIP_BUS_ATAPI_PIO_AND_DMA); + max_pio = 0; + max_mdma = 1; } else if (ide_drive_is_cdrom(ide)) { bus = cdrom_drives[atapi_cdrom_drives[ide->channel]].bus_type; dma = (bus == CDROM_BUS_ATAPI_PIO_AND_DMA); @@ -683,7 +684,7 @@ static int ide_set_features(IDE *ide) break; case 0x01: /* PIO mode */ - if (submode > 2) + if (submode > max_pio) { return 0; } @@ -692,7 +693,7 @@ static int ide_set_features(IDE *ide) break; case 0x02: /* Singleword DMA mode */ - if (!PCI || !dma || (ide->board >= 2) || (submode > 2)) + if (!PCI || !dma || ide_drive_is_zip(ide) || (ide->board >= 2) || (submode > 2)) { return 0; } @@ -701,7 +702,7 @@ static int ide_set_features(IDE *ide) break; case 0x04: /* Multiword DMA mode */ - if (!PCI || !dma || (ide->board >= 2) || (submode > 2)) + if (!PCI || !dma || (ide->board >= 2) || (submode > max_mdma)) { return 0; } diff --git a/src/disk/zip.c b/src/disk/zip.c index ee493f0..33b1388 100644 --- a/src/disk/zip.c +++ b/src/disk/zip.c @@ -1,2579 +1,2590 @@ -/* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. - * - * This file is part of the VARCem Project. - * - * Implementation of the Iomega ZIP drive with SCSI(-like) - * commands, for both ATAPI and SCSI usage. - * - * Version: @(#)zip.c 1.0.3 2018/03/04 - * - * Authors: Fred N. van Kempen, - * Miran Grca, - * - * Copyright 2018 Miran Grca. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the: - * - * Free Software Foundation, Inc. - * 59 Temple Place - Suite 330 - * Boston, MA 02111-1307 - * USA. - */ -#include -#include -#include -#include -#include -#include -#define HAVE_STDARG_H -#include "../emu.h" -#include "../config.h" -#include "../timer.h" -#include "../device.h" -#include "../intel_piix.h" -#include "../scsi/scsi.h" -#include "../nvr.h" -#include "../disk/hdc.h" -#include "../disk/hdc_ide.h" -#include "../plat.h" -#include "../ui.h" -#include "zip.h" - - -/* Bits of 'status' */ -#define ERR_STAT 0x01 -#define DRQ_STAT 0x08 /* Data request */ -#define DSC_STAT 0x10 -#define SERVICE_STAT 0x10 -#define READY_STAT 0x40 -#define BUSY_STAT 0x80 - -/* Bits of 'error' */ -#define ABRT_ERR 0x04 /* Command aborted */ -#define MCR_ERR 0x08 /* Media change request */ - -zip_t zip[ZIP_NUM]; -zip_drive_t zip_drives[ZIP_NUM]; -uint8_t atapi_zip_drives[8] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; -uint8_t scsi_zip_drives[16][8] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } }; - - -/* Table of all SCSI commands and their flags, needed for the new disc change / not ready handler. */ -uint8_t zip_command_flags[0x100] = -{ - IMPLEMENTED | CHECK_READY | NONDATA, /* 0x00 */ - IMPLEMENTED | ALLOW_UA | NONDATA | SCSI_ONLY, /* 0x01 */ - 0, - IMPLEMENTED | ALLOW_UA, /* 0x03 */ - IMPLEMENTED | CHECK_READY | ALLOW_UA | NONDATA | SCSI_ONLY, /* 0x04 */ - 0, - IMPLEMENTED, /* 0x06 */ - 0, - IMPLEMENTED | CHECK_READY, /* 0x08 */ - 0, - IMPLEMENTED | CHECK_READY, /* 0x0A */ - 0, - IMPLEMENTED, /* 0x0C */ - IMPLEMENTED | ATAPI_ONLY, /* 0x0D */ - 0, 0, 0, 0, - IMPLEMENTED | ALLOW_UA, /* 0x12 */ - IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x13 */ - 0, - IMPLEMENTED, /* 0x15 */ - IMPLEMENTED | SCSI_ONLY, /* 0x16 */ - IMPLEMENTED | SCSI_ONLY, /* 0x17 */ - 0, 0, - IMPLEMENTED, - IMPLEMENTED | CHECK_READY, /* 0x1B */ - 0, - IMPLEMENTED, /* 0x1D */ - IMPLEMENTED | CHECK_READY, /* 0x1E */ - 0, 0, 0, 0, 0, 0, - IMPLEMENTED | CHECK_READY, /* 0x25 */ - 0, 0, - IMPLEMENTED | CHECK_READY, /* 0x28 */ - 0, - IMPLEMENTED | CHECK_READY, /* 0x2A */ - 0, 0, 0, - IMPLEMENTED | CHECK_READY, /* 0x2E */ - IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x2F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, - IMPLEMENTED | CHECK_READY, /* 0x41 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, - IMPLEMENTED, /* 0x55 */ - 0, 0, 0, 0, - IMPLEMENTED, /* 0x5A */ - 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - IMPLEMENTED | CHECK_READY, /* 0xA8 */ - 0, - IMPLEMENTED | CHECK_READY, /* 0xAA */ - 0, 0, 0, - IMPLEMENTED | CHECK_READY, /* 0xAE */ - IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0xAF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - IMPLEMENTED, /* 0xBD */ - 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -uint64_t zip_mode_sense_page_flags = (1LL << GPMODE_R_W_ERROR_PAGE) | (1LL << 0x02LL) | (1LL << 0x2FLL) | (1LL << GPMODE_ALL_PAGES); -uint64_t zip_250_mode_sense_page_flags = (1LL << GPMODE_R_W_ERROR_PAGE) | (1LL << 0x05LL) | (1LL << 0x08LL) | (1LL << 0x2FLL) | (1LL << GPMODE_ALL_PAGES); - - -static const mode_sense_pages_t zip_mode_sense_pages_default = -{ { - { 0, 0 }, - { GPMODE_R_W_ERROR_PAGE, 0x0a, 0xc8, 22, 0, 0, 0, 0, 90, 0, 0x50, 0x20 }, - { 0x02, 0x0e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0x2f, 0x04, 0x5c, 0x0f, 0xff, 0x0f } -} }; - -static const mode_sense_pages_t zip_250_mode_sense_pages_default = -{ { - { 0, 0 }, - { GPMODE_R_W_ERROR_PAGE, 0x06, 0xc8, 0x64, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0x05, 0x1e, 0x80, 0, 0x40, 0x20, 2, 0, 0, 0xef, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0b, 0x7d, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0x08, 0x0a, 4, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0x2f, 0x04, 0x5c, 0x0f, 0x3c, 0x0f } -} }; - -static const mode_sense_pages_t zip_mode_sense_pages_default_scsi = -{ { - { 0, 0 }, - { GPMODE_R_W_ERROR_PAGE, 0x0a, 0xc8, 22, 0, 0, 0, 0, 90, 0, 0x50, 0x20 }, - { 0x02, 0x0e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0x2f, 0x04, 0x5c, 0x0f, 0xff, 0x0f } -} }; - -static const mode_sense_pages_t zip_250_mode_sense_pages_default_scsi = -{ { - { 0, 0 }, - { GPMODE_R_W_ERROR_PAGE, 0x06, 0xc8, 0x64, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0x05, 0x1e, 0x80, 0, 0x40, 0x20, 2, 0, 0, 0xef, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0b, 0x7d, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0x08, 0x0a, 4, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0x2f, 0x04, 0x5c, 0x0f, 0x3c, 0x0f } -} }; - -static const mode_sense_pages_t zip_mode_sense_pages_changeable = -{ { - { 0, 0 }, - { GPMODE_R_W_ERROR_PAGE, 0x0a, 0xc8, 22, 0, 0, 0, 0, 90, 0, 0x50, 0x20 }, - { 0x02, 0x0e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0x2f, 0x04, 0x5c, 0x0f, 0xff, 0x0f } -} }; - -static const mode_sense_pages_t zip_250_mode_sense_pages_changeable = -{ { - { 0, 0 }, - { GPMODE_R_W_ERROR_PAGE, 0x06, 0xc8, 0x64, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0x05, 0x1e, 0x80, 0, 0x40, 0x20, 2, 0, 0, 0xef, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0b, 0x7d, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0x08, 0x0a, 4, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0x2f, 0x04, 0x5c, 0x0f, 0x3c, 0x0f } -} }; - -static mode_sense_pages_t zip_mode_sense_pages_saved[ZIP_NUM]; - - -#ifdef ENABLE_ZIP_LOG -int zip_do_log = ENABLE_ZIP_LOG; -#endif - - -static void -zip_log(const char *format, ...) -{ -#ifdef ENABLE_ZIP_LOG - va_list ap; - - if (zip_do_log) - { - va_start(ap, format); - pclog_ex(format, ap); - va_end(ap); - } -#endif -} - - -int find_zip_for_channel(uint8_t channel) -{ - uint8_t i = 0; - - for (i = 0; i < ZIP_NUM; i++) { - if (((zip_drives[i].bus_type == ZIP_BUS_ATAPI_PIO_ONLY) || (zip_drives[i].bus_type == ZIP_BUS_ATAPI_PIO_AND_DMA)) && (zip_drives[i].ide_channel == channel)) - return i; - } - return 0xff; -} - -void zip_init(int id, int cdb_len_setting); - -int zip_load(uint8_t id, wchar_t *fn) -{ - int read_only = zip_drives[id].ui_writeprot; - int size = 0; - - zip_drives[id].f = plat_fopen(fn, zip_drives[id].ui_writeprot ? L"rb" : L"rb+"); - if (!zip_drives[id].ui_writeprot && !zip_drives[id].f) { - zip_drives[id].f = plat_fopen(fn, L"rb"); - read_only = 1; - } - if (zip_drives[id].f) { - fseek(zip_drives[id].f, 0, SEEK_END); - size = ftell(zip_drives[id].f); - - if ((size == ((ZIP_250_SECTORS << 9) + 0x1000)) || (size == ((ZIP_SECTORS << 9) + 0x1000))) { - /* This is a ZDI image. */ - size -= 0x1000; - zip_drives[id].base = 0x1000; - } else - zip_drives[id].base = 0; - - if (zip_drives[id].is_250) { - if ((size != (ZIP_250_SECTORS << 9)) && (size != (ZIP_SECTORS << 9))) { - zip_log("File is incorrect size for a ZIP image\nMust be exactly %i or %i bytes\n", ZIP_250_SECTORS << 9, ZIP_SECTORS << 9); - fclose(zip_drives[id].f); - zip_drives[id].f = NULL; - zip_drives[id].medium_size = 0; - zip_eject(id); /* Make sure the host OS knows we've rejected (and ejected) the image. */ - return 0; - } - } else { - if (size != (ZIP_SECTORS << 9)) { - zip_log("File is incorrect size for a ZIP image\nMust be exactly %i bytes\n", ZIP_SECTORS << 9); - fclose(zip_drives[id].f); - zip_drives[id].f = NULL; - zip_drives[id].medium_size = 0; - zip_eject(id); /* Make sure the host OS knows we've rejected (and ejected) the image. */ - return 0; - } - } - - zip_drives[id].medium_size = size >> 9; - - fseek(zip_drives[id].f, zip_drives[id].base, SEEK_SET); - - memcpy(zip_drives[id].image_path, fn, sizeof(zip_drives[id].image_path)); - - zip_drives[id].read_only = read_only; - - return 1; - } - - return 0; -} - -void zip_disk_reload(uint8_t id) -{ - int ret = 0; - - if (wcslen(zip_drives[id].prev_image_path) == 0) - return; - else - ret = zip_load(id, zip_drives[id].prev_image_path); - - if (ret) - zip[id].unit_attention = 1; -} - -void zip_close(uint8_t id) -{ - if (zip_drives[id].f) { - fclose(zip_drives[id].f); - zip_drives[id].f = NULL; - - memcpy(zip_drives[id].prev_image_path, zip_drives[id].image_path, sizeof(zip_drives[id].prev_image_path)); - memset(zip_drives[id].image_path, 0, sizeof(zip_drives[id].image_path)); - - zip_drives[id].medium_size = 0; - } -} - -void build_atapi_zip_map() -{ - uint8_t i = 0; - - memset(atapi_zip_drives, 0xff, 8); - - for (i = 0; i < 8; i++) { - atapi_zip_drives[i] = find_zip_for_channel(i); - if (atapi_zip_drives[i] != 0xff) - zip_init(atapi_zip_drives[i], 12); - } -} - -int find_zip_for_scsi_id(uint8_t scsi_id, uint8_t scsi_lun) -{ - uint8_t i = 0; - - for (i = 0; i < ZIP_NUM; i++) { - if ((zip_drives[i].bus_type == ZIP_BUS_SCSI) && (zip_drives[i].scsi_device_id == scsi_id) && (zip_drives[i].scsi_device_lun == scsi_lun)) - return i; - } - return 0xff; -} - -void build_scsi_zip_map() -{ - uint8_t i = 0; - uint8_t j = 0; - - for (i = 0; i < 16; i++) - memset(scsi_zip_drives[i], 0xff, 8); - - for (i = 0; i < 16; i++) { - for (j = 0; j < 8; j++) { - scsi_zip_drives[i][j] = find_zip_for_scsi_id(i, j); - if (scsi_zip_drives[i][j] != 0xff) - zip_init(scsi_zip_drives[i][j], 12); - } - } -} - -void zip_set_callback(uint8_t id) -{ - if (zip_drives[id].bus_type != ZIP_BUS_SCSI) - ide_set_callback(zip_drives[id].ide_channel, zip[id].callback); -} - -void zip_set_cdb_len(int id, int cdb_len) -{ - zip[id].cdb_len = cdb_len; -} - -void zip_reset_cdb_len(int id) -{ - zip[id].cdb_len = zip[id].cdb_len_setting ? 16 : 12; -} - -void zip_set_signature(int id) -{ - if (id >= ZIP_NUM) - return; - zip[id].phase = 1; - zip[id].request_length = 0xEB14; -} - -void zip_init(int id, int cdb_len_setting) -{ - if (id >= ZIP_NUM) - return; - memset(&(zip[id]), 0, sizeof(zip_t)); - zip[id].requested_blocks = 1; - if (cdb_len_setting <= 1) - zip[id].cdb_len_setting = cdb_len_setting; - zip_reset_cdb_len(id); - zip[id].sense[0] = 0xf0; - zip[id].sense[7] = 10; - zip_drives[id].bus_mode = 0; - if (zip_drives[id].bus_type >= ZIP_BUS_ATAPI_PIO_AND_DMA) - zip_drives[id].bus_mode |= 2; - if (zip_drives[id].bus_type < ZIP_BUS_SCSI) - zip_drives[id].bus_mode |= 1; - zip_log("ZIP %i: Bus type %i, bus mode %i\n", id, zip_drives[id].bus_type, zip_drives[id].bus_mode); - if (zip_drives[id].bus_type < ZIP_BUS_SCSI) - zip_set_signature(id); - zip_drives[id].max_blocks_at_once = 85; - zip[id].status = READY_STAT | DSC_STAT; - zip[id].pos = 0; - zip[id].packet_status = 0xff; - zip_sense_key = zip_asc = zip_ascq = zip[id].unit_attention = 0; - zip[id].cdb_len_setting = 0; - zip[id].cdb_len = 12; -} - -int zip_supports_pio(int id) -{ - return (zip_drives[id].bus_mode & 1); -} - -int zip_supports_dma(int id) -{ - return (zip_drives[id].bus_mode & 2); -} - -/* Returns: 0 for none, 1 for PIO, 2 for DMA. */ -int zip_current_mode(int id) -{ - if (!zip_supports_pio(id) && !zip_supports_dma(id)) - return 0; - if (zip_supports_pio(id) && !zip_supports_dma(id)) { - zip_log("ZIP %i: Drive does not support DMA, setting to PIO\n", id); - return 1; - } - if (!zip_supports_pio(id) && zip_supports_dma(id)) - return 2; - if (zip_supports_pio(id) && zip_supports_dma(id)) { - zip_log("ZIP %i: Drive supports both, setting to %s\n", id, (zip[id].features & 1) ? "DMA" : "PIO", id); - return (zip[id].features & 1) ? 2 : 1; - } - - return 0; -} - -/* Translates ATAPI status (ERR_STAT flag) to SCSI status. */ -int zip_ZIP_PHASE_to_scsi(uint8_t id) -{ - if (zip[id].status & ERR_STAT) - return SCSI_STATUS_CHECK_CONDITION; - else - return SCSI_STATUS_OK; -} - -/* Translates ATAPI phase (DRQ, I/O, C/D) to SCSI phase (MSG, C/D, I/O). */ -int zip_atapi_phase_to_scsi(uint8_t id) -{ - if (zip[id].status & 8) { - switch (zip[id].phase & 3) { - case 0: - return 0; - case 1: - return 2; - case 2: - return 1; - case 3: - return 7; - } - } else { - if ((zip[id].phase & 3) == 3) - return 3; - else - return 4; - } - - return 0; -} - -int zip_lba_to_msf_accurate(int lba) -{ - int temp_pos; - int m, s, f; - - temp_pos = lba + 150; - f = temp_pos % 75; - temp_pos -= f; - temp_pos /= 75; - s = temp_pos % 60; - temp_pos -= s; - temp_pos /= 60; - m = temp_pos; - - return ((m << 16) | (s << 8) | f); -} - -void zip_mode_sense_load(uint8_t id) -{ - FILE *f; - wchar_t file_name[512]; - int i; - memset(&zip_mode_sense_pages_saved[id], 0, sizeof(mode_sense_pages_t)); - for (i = 0; i < 0x3f; i++) { - if (zip_drives[id].is_250) { - if (zip_250_mode_sense_pages_default.pages[i][1] != 0) { - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) - memcpy(zip_mode_sense_pages_saved[id].pages[i], zip_250_mode_sense_pages_default_scsi.pages[i], zip_250_mode_sense_pages_default_scsi.pages[i][1] + 2); - else - memcpy(zip_mode_sense_pages_saved[id].pages[i], zip_250_mode_sense_pages_default.pages[i], zip_250_mode_sense_pages_default.pages[i][1] + 2); - } - } else { - if (zip_mode_sense_pages_default.pages[i][1] != 0) { - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) - memcpy(zip_mode_sense_pages_saved[id].pages[i], zip_mode_sense_pages_default_scsi.pages[i], zip_mode_sense_pages_default_scsi.pages[i][1] + 2); - else - memcpy(zip_mode_sense_pages_saved[id].pages[i], zip_mode_sense_pages_default.pages[i], zip_mode_sense_pages_default.pages[i][1] + 2); - } - } - } - memset(file_name, 0, 512 * sizeof(wchar_t)); - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) - swprintf(file_name, 512, L"scsi_zip_%02i_mode_sense_bin", id); - else - swprintf(file_name, 512, L"zip_%02i_mode_sense_bin", id); - f = plat_fopen(nvr_path(file_name), L"rb"); - if (f) - fclose(f); -} - -void zip_mode_sense_save(uint8_t id) -{ - FILE *f; - wchar_t file_name[512]; - memset(file_name, 0, 512 * sizeof(wchar_t)); - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) - swprintf(file_name, 512, L"scsi_zip_%02i_mode_sense_bin", id); - else - swprintf(file_name, 512, L"zip_%02i_mode_sense_bin", id); - f = plat_fopen(nvr_path(file_name), L"wb"); - if (f) - fclose(f); -} - -static void zip_command_complete(uint8_t id); - -uint8_t zip_read_capacity_cdb[12] = {0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - -int zip_read_capacity(uint8_t id, uint8_t *cdb, uint8_t *buffer, uint32_t *len) -{ - int size = 0; - - if (zip_drives[id].is_250) - size = zip_drives[id].medium_size - 1; /* IMPORTANT: What's returned is the last LBA block. */ - else - size = ZIP_SECTORS - 1; /* IMPORTANT: What's returned is the last LBA block. */ - memset(buffer, 0, 8); - buffer[0] = (size >> 24) & 0xff; - buffer[1] = (size >> 16) & 0xff; - buffer[2] = (size >> 8) & 0xff; - buffer[3] = size & 0xff; - buffer[6] = 2; /* 512 = 0x0200 */ - *len = 8; - - return 1; -} - -/*SCSI Mode Sense 6/10*/ -uint8_t zip_mode_sense_read(uint8_t id, uint8_t page_control, uint8_t page, uint8_t pos) -{ - switch (page_control) { - case 0: - case 3: - if (zip_drives[id].is_250 && (page == 5) && (pos == 9) && (zip_drives[id].medium_size == ZIP_SECTORS)) - return 0x60; - return zip_mode_sense_pages_saved[id].pages[page][pos]; - break; - case 1: - if (zip_drives[id].is_250) - return zip_250_mode_sense_pages_changeable.pages[page][pos]; - else - return zip_mode_sense_pages_changeable.pages[page][pos]; - break; - case 2: - if (zip_drives[id].is_250) { - if ((page == 5) && (pos == 9) && (zip_drives[id].medium_size == ZIP_SECTORS)) - return 0x60; - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) - return zip_250_mode_sense_pages_default_scsi.pages[page][pos]; - else - return zip_250_mode_sense_pages_default.pages[page][pos]; - } else { - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) - return zip_mode_sense_pages_default_scsi.pages[page][pos]; - else - return zip_mode_sense_pages_default.pages[page][pos]; - } - break; - } - - return 0; -} - -uint32_t zip_mode_sense(uint8_t id, uint8_t *buf, uint32_t pos, uint8_t type, uint8_t block_descriptor_len) -{ - uint64_t page_flags; - uint8_t page_control = (type >> 6) & 3; - - if (zip_drives[id].is_250) - page_flags = zip_250_mode_sense_page_flags; - else - page_flags = zip_mode_sense_page_flags; - - int i = 0; - int j = 0; - - uint8_t msplen; - - type &= 0x3f; - - if (block_descriptor_len) { - if (zip_drives[id].is_250) { - buf[pos++] = ((zip_drives[id].medium_size >> 24) & 0xff); - buf[pos++] = ((zip_drives[id].medium_size >> 16) & 0xff); - buf[pos++] = ((zip_drives[id].medium_size >> 8) & 0xff); - buf[pos++] = ( zip_drives[id].medium_size & 0xff); - } else { - buf[pos++] = ((ZIP_SECTORS >> 24) & 0xff); - buf[pos++] = ((ZIP_SECTORS >> 16) & 0xff); - buf[pos++] = ((ZIP_SECTORS >> 8) & 0xff); - buf[pos++] = ( ZIP_SECTORS & 0xff); - } - buf[pos++] = 0; /* Reserved. */ - buf[pos++] = 0; /* Block length (0x200 = 512 bytes). */ - buf[pos++] = 2; - buf[pos++] = 0; - } - - for (i = 0; i < 0x40; i++) { - if ((type == GPMODE_ALL_PAGES) || (type == i)) { - if (page_flags & (1LL << zip[id].current_page_code)) { - buf[pos++] = zip_mode_sense_read(id, page_control, i, 0); - msplen = zip_mode_sense_read(id, page_control, i, 1); - buf[pos++] = msplen; - zip_log("ZIP %i: MODE SENSE: Page [%02X] length %i\n", id, i, msplen); - for (j = 0; j < msplen; j++) - buf[pos++] = zip_mode_sense_read(id, page_control, i, 2 + j); - } - } - } - - return pos; -} - -void zip_update_request_length(uint8_t id, int len, int block_len) -{ - uint32_t bt; - - if (!zip[id].request_length) - zip[id].max_transfer_len = 65534; - else - zip[id].max_transfer_len = zip[id].request_length; - - /* For media access commands, make sure the requested DRQ length matches the block length. */ - switch (zip[id].current_cdb[0]) { - case 0x08: - case 0x28: - case 0xa8: - if (zip[id].max_transfer_len < block_len) - zip[id].max_transfer_len = block_len; - bt = (zip[id].requested_blocks * block_len); - if (len > bt) - len = bt; - default: - zip[id].packet_len = len; - break; - } - /* If the DRQ length is odd, and the total remaining length is bigger, make sure it's even. */ - if ((zip[id].max_transfer_len & 1) && (zip[id].max_transfer_len < len)) - zip[id].max_transfer_len &= 0xfffe; - /* If the DRQ length is smaller or equal in size to the total remaining length, set it to that. */ - if (len <= zip[id].max_transfer_len) - zip[id].max_transfer_len = len; - return; -} - -static void zip_command_common(uint8_t id) -{ - zip[id].status = BUSY_STAT; - zip[id].phase = 1; - zip[id].pos = 0; - if (zip[id].packet_status == ZIP_PHASE_COMPLETE) { - zip[id].callback = 20LL * ZIP_TIME; - zip_set_callback(id); - } else if (zip[id].packet_status == ZIP_PHASE_DATA_IN) { - if (zip[id].current_cdb[0] == 0x42) { - zip_log("ZIP %i: READ SUBCHANNEL\n"); - zip[id].callback = 1000LL * ZIP_TIME; - zip_set_callback(id); - } else { - zip[id].callback = 60LL * ZIP_TIME; - zip_set_callback(id); - } - } else { - zip[id].callback = 60LL * ZIP_TIME; - zip_set_callback(id); - } -} - -static void zip_command_complete(uint8_t id) -{ - zip[id].packet_status = ZIP_PHASE_COMPLETE; - zip_command_common(id); -} - -static void zip_command_read(uint8_t id) -{ - zip[id].packet_status = ZIP_PHASE_DATA_IN; - zip_command_common(id); - zip[id].total_read = 0; -} - -static void zip_command_read_dma(uint8_t id) -{ - zip[id].packet_status = ZIP_PHASE_DATA_IN_DMA; - zip_command_common(id); - zip[id].total_read = 0; -} - -static void zip_command_write(uint8_t id) -{ - zip[id].packet_status = ZIP_PHASE_DATA_OUT; - zip_command_common(id); -} - -static void zip_command_write_dma(uint8_t id) -{ - zip[id].packet_status = ZIP_PHASE_DATA_OUT_DMA; - zip_command_common(id); -} - -/* 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 zip_data_command_finish(uint8_t id, int len, int block_len, int alloc_len, int direction) -{ - zip_log("ZIP %i: Finishing command (%02X): %i, %i, %i, %i, %i\n", id, zip[id].current_cdb[0], len, block_len, alloc_len, direction, zip[id].request_length); - zip[id].pos=0; - if (alloc_len >= 0) { - if (alloc_len < len) { - len = alloc_len; - } - } - - if ((len == 0) || (zip_current_mode(id) == 0)) { - if (zip_drives[id].bus_type != ZIP_BUS_SCSI) { - zip[id].packet_len = 0; - } - zip_command_complete(id); - } - else { - if (zip_current_mode(id) == 2) { - if (zip_drives[id].bus_type != ZIP_BUS_SCSI) { - zip[id].packet_len = alloc_len; - } - - if (direction == 0) - zip_command_read_dma(id); - else - zip_command_write_dma(id); - } - else { - zip_update_request_length(id, len, block_len); - if (direction == 0) - zip_command_read(id); - else - zip_command_write(id); - } - } - - zip_log("ZIP %i: Status: %i, cylinder %i, packet length: %i, position: %i, phase: %i\n", id, zip[id].packet_status, zip[id].request_length, zip[id].packet_len, zip[id].pos, zip[id].phase); -} - -static void zip_sense_clear(int id, int command) -{ - zip[id].previous_command = command; - zip_sense_key = zip_asc = zip_ascq = 0; -} - -static void zip_set_phase(uint8_t id, uint8_t phase) -{ - uint8_t scsi_id = zip_drives[id].scsi_device_id; - uint8_t scsi_lun = zip_drives[id].scsi_device_lun; - - if (zip_drives[id].bus_type != ZIP_BUS_SCSI) - return; - - SCSIDevices[scsi_id][scsi_lun].Phase = phase; -} - -static void zip_cmd_error(uint8_t id) -{ - zip_set_phase(id, SCSI_PHASE_STATUS); - zip[id].error = ((zip_sense_key & 0xf) << 4) | ABRT_ERR; - if (zip[id].unit_attention) - zip[id].error |= MCR_ERR; - zip[id].status = READY_STAT | ERR_STAT; - zip[id].phase = 3; - zip[id].pos = 0; - zip[id].packet_status = 0x80; - zip[id].callback = 50LL * ZIP_TIME; - zip_set_callback(id); - zip_log("ZIP %i: [%02X] ERROR: %02X/%02X/%02X\n", id, zip[id].current_cdb[0], zip_sense_key, zip_asc, zip_ascq); -} - -static void zip_unit_attention(uint8_t id) -{ - zip_set_phase(id, SCSI_PHASE_STATUS); - zip[id].error = (SENSE_UNIT_ATTENTION << 4) | ABRT_ERR; - if (zip[id].unit_attention) - zip[id].error |= MCR_ERR; - zip[id].status = READY_STAT | ERR_STAT; - zip[id].phase = 3; - zip[id].pos = 0; - zip[id].packet_status = 0x80; - zip[id].callback = 50LL * ZIP_TIME; - zip_set_callback(id); - zip_log("ZIP %i: UNIT ATTENTION\n", id); -} - -static void zip_bus_master_error(uint8_t id) -{ - zip_sense_key = zip_asc = zip_ascq = 0; - zip_cmd_error(id); -} - -static void zip_not_ready(uint8_t id) -{ - zip_sense_key = SENSE_NOT_READY; - zip_asc = ASC_MEDIUM_NOT_PRESENT; - zip_ascq = 0; - zip_cmd_error(id); -} - -static void zip_write_protected(uint8_t id) -{ - zip_sense_key = SENSE_UNIT_ATTENTION; - zip_asc = ASC_WRITE_PROTECTED; - zip_ascq = 0; - zip_cmd_error(id); -} - -static void zip_invalid_lun(uint8_t id) -{ - zip_sense_key = SENSE_ILLEGAL_REQUEST; - zip_asc = ASC_INV_LUN; - zip_ascq = 0; - zip_cmd_error(id); -} - -static void zip_illegal_opcode(uint8_t id) -{ - zip_sense_key = SENSE_ILLEGAL_REQUEST; - zip_asc = ASC_ILLEGAL_OPCODE; - zip_ascq = 0; - zip_cmd_error(id); -} - -static void zip_lba_out_of_range(uint8_t id) -{ - zip_sense_key = SENSE_ILLEGAL_REQUEST; - zip_asc = ASC_LBA_OUT_OF_RANGE; - zip_ascq = 0; - zip_cmd_error(id); -} - -static void zip_invalid_field(uint8_t id) -{ - zip_sense_key = SENSE_ILLEGAL_REQUEST; - zip_asc = ASC_INV_FIELD_IN_CMD_PACKET; - zip_ascq = 0; - zip_cmd_error(id); - zip[id].status = 0x53; -} - -static void zip_invalid_field_pl(uint8_t id) -{ - zip_sense_key = SENSE_ILLEGAL_REQUEST; - zip_asc = ASC_INV_FIELD_IN_PARAMETER_LIST; - zip_ascq = 0; - zip_cmd_error(id); - zip[id].status = 0x53; -} - -static void zip_data_phase_error(uint8_t id) -{ - zip_sense_key = SENSE_ILLEGAL_REQUEST; - zip_asc = ASC_DATA_PHASE_ERROR; - zip_ascq = 0; - zip_cmd_error(id); -} - -#define zipbufferb zip[id].buffer - -int zip_data(uint8_t id, uint32_t *len, int out) -{ - int i = 0; - - if (zip[id].sector_pos >= zip_drives[id].medium_size) { - zip_log("ZIP %i: Trying to %s beyond the end of disk\n", id, out ? "write" : "read"); - zip_lba_out_of_range(id); - return 0; - } - - *len = 0; - - for (i = 0; i < zip[id].requested_blocks; i++) { - fseek(zip_drives[id].f, zip_drives[id].base + (zip[id].sector_pos << 9) + *len, SEEK_SET); - if (out) - fwrite(zipbufferb + *len, 1, 512, zip_drives[id].f); - else - fread(zipbufferb + *len, 1, 512, zip_drives[id].f); - - *len += 512; - } - - return 1; -} - -int zip_blocks(uint8_t id, uint32_t *len, int first_batch, int out) -{ - int ret = 0; - - zip[id].data_pos = 0; - - if (!zip[id].sector_len) { - zip_command_complete(id); - return -1; - } - - zip_log("%sing %i blocks starting from %i...\n", out ? "Writ" : "Read", zip[id].requested_blocks, zip[id].sector_pos); - - ret = zip_data(id, len, out); - - zip_log("%s %i bytes of blocks...\n", out ? "Written" : "Read", *len); - - if (!ret) - return 0; - - zip[id].sector_pos += zip[id].requested_blocks; - zip[id].sector_len -= zip[id].requested_blocks; - - return 1; -} - -void zip_insert(uint8_t id) -{ - zip[id].unit_attention = 1; -} - -/*SCSI Sense Initialization*/ -void zip_sense_code_ok(uint8_t id) -{ - zip_sense_key = SENSE_NONE; - zip_asc = 0; - zip_ascq = 0; -} - -int zip_pre_execution_check(uint8_t id, uint8_t *cdb) -{ - int ready = 0; - - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { - if (((zip[id].request_length >> 5) & 7) != zip_drives[id].scsi_device_lun) { - zip_log("ZIP %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", id, ((zip[id].request_length >> 5) & 7)); - zip_invalid_lun(id); - return 0; - } - } - - if (!(zip_command_flags[cdb[0]] & IMPLEMENTED)) { - zip_log("ZIP %i: Attempting to execute unknown command %02X over %s\n", id, cdb[0], (zip_drives[id].bus_type == ZIP_BUS_SCSI) ? "SCSI" : ((zip_drives[id].bus_type == ZIP_BUS_ATAPI_PIO_AND_DMA) ? "ATAPI PIO/DMA" : "ATAPI PIO")); - - zip_illegal_opcode(id); - return 0; - } - - if ((zip_drives[id].bus_type < ZIP_BUS_SCSI) && (zip_command_flags[cdb[0]] & SCSI_ONLY)) { - zip_log("ZIP %i: Attempting to execute SCSI-only command %02X over ATAPI\n", id, cdb[0]); - zip_illegal_opcode(id); - return 0; - } - - if ((zip_drives[id].bus_type == ZIP_BUS_SCSI) && (zip_command_flags[cdb[0]] & ATAPI_ONLY)) { - zip_log("ZIP %i: Attempting to execute ATAPI-only command %02X over SCSI\n", id, cdb[0]); - zip_illegal_opcode(id); - return 0; - } - - ready = (zip_drives[id].f != NULL); - - /* If the drive is not ready, there is no reason to keep the - UNIT ATTENTION condition present, as we only use it to mark - disc changes. */ - if (!ready && zip[id].unit_attention) - zip[id].unit_attention = 0; - - /* If the UNIT ATTENTION condition is set and the command does not allow - execution under it, error out and report the condition. */ - if (zip[id].unit_attention == 1) { - /* Only increment the unit attention phase if the command can not pass through it. */ - if (!(zip_command_flags[cdb[0]] & ALLOW_UA)) { - /* zip_log("ZIP %i: Unit attention now 2\n", id); */ - zip[id].unit_attention = 2; - zip_log("ZIP %i: UNIT ATTENTION: Command %02X not allowed to pass through\n", id, cdb[0]); - zip_unit_attention(id); - return 0; - } - } - else if (zip[id].unit_attention == 2) { - if (cdb[0] != GPCMD_REQUEST_SENSE) { - /* zip_log("ZIP %i: Unit attention now 0\n", id); */ - zip[id].unit_attention = 0; - } - } - - /* Unless the command is REQUEST SENSE, clear the sense. This will *NOT* - the UNIT ATTENTION condition if it's set. */ - if (cdb[0] != GPCMD_REQUEST_SENSE) - zip_sense_clear(id, cdb[0]); - - /* Next it's time for NOT READY. */ - if (!ready) - zip[id].media_status = MEC_MEDIA_REMOVAL; - else - zip[id].media_status = (zip[id].unit_attention) ? MEC_NEW_MEDIA : MEC_NO_CHANGE; - - if ((zip_command_flags[cdb[0]] & CHECK_READY) && !ready) { - zip_log("ZIP %i: Not ready (%02X)\n", id, cdb[0]); - zip_not_ready(id); - return 0; - } - - zip_log("ZIP %i: Continuing with command %02X\n", id, cdb[0]); - - return 1; -} - -void zip_clear_callback(uint8_t channel) -{ - uint8_t id = atapi_zip_drives[channel]; - - if (id < ZIP_NUM) - { - zip[id].callback = 0LL; - zip_set_callback(id); - } -} - -static void zip_seek(uint8_t id, uint32_t pos) -{ - /* zip_log("ZIP %i: Seek %08X\n", id, pos); */ - zip[id].sector_pos = pos; -} - -static void zip_rezero(uint8_t id) -{ - zip[id].sector_pos = zip[id].sector_len = 0; - zip_seek(id, 0); -} - -void zip_reset(uint8_t id) -{ - zip_rezero(id); - zip[id].status = 0; - zip[id].callback = 0LL; - zip_set_callback(id); - zip[id].packet_status = 0xff; - zip[id].unit_attention = 0; -} - -void zip_request_sense(uint8_t id, uint8_t *buffer, uint8_t alloc_length, int desc) -{ - /*Will return 18 bytes of 0*/ - if (alloc_length != 0) { - memset(buffer, 0, alloc_length); - if (!desc) - memcpy(buffer, zip[id].sense, alloc_length); - else { - buffer[1] = zip_sense_key; - buffer[2] = zip_asc; - buffer[3] = zip_ascq; - } - } - - buffer[0] = desc ? 0x72 : 0x70; - - if (zip[id].unit_attention && (zip_sense_key == 0)) { - buffer[desc ? 1 : 2]=SENSE_UNIT_ATTENTION; - buffer[desc ? 2 : 12]=ASC_MEDIUM_MAY_HAVE_CHANGED; - buffer[desc ? 3 : 13]=0; - } - - zip_log("ZIP %i: Reporting sense: %02X %02X %02X\n", id, buffer[2], buffer[12], buffer[13]); - - if (buffer[desc ? 1 : 2] == SENSE_UNIT_ATTENTION) { - /* If the last remaining sense is unit attention, clear - that condition. */ - zip[id].unit_attention = 0; - } - - /* Clear the sense stuff as per the spec. */ - zip_sense_clear(id, GPCMD_REQUEST_SENSE); -} - -void zip_request_sense_for_scsi(uint8_t id, uint8_t *buffer, uint8_t alloc_length) -{ - int ready = 0; - - ready = (zip_drives[id].f != NULL); - - if (!ready && zip[id].unit_attention) { - /* If the drive is not ready, there is no reason to keep the - UNIT ATTENTION condition present, as we only use it to mark - disc changes. */ - zip[id].unit_attention = 0; - } - - /* Do *NOT* advance the unit attention phase. */ - - zip_request_sense(id, buffer, alloc_length, 0); -} - -void zip_set_buf_len(uint8_t id, int32_t *BufLen, uint32_t *src_len) -{ - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { - if (*BufLen == -1) - *BufLen = *src_len; - else { - *BufLen = MIN(*src_len, *BufLen); - *src_len = *BufLen; - } - zip_log("ZIP %i: Actual transfer length: %i\n", id, *BufLen); - } -} - -void zip_buf_alloc(uint8_t id, uint32_t len) -{ - zip_log("ZIP %i: Allocated buffer length: %i\n", id, len); - zipbufferb = (uint8_t *) malloc(len); -} - -void zip_buf_free(uint8_t id) -{ - if (zipbufferb) { - zip_log("ZIP %i: Freeing buffer...\n", id); - free(zipbufferb); - zipbufferb = NULL; - } -} - -void zip_command(uint8_t id, uint8_t *cdb) -{ - uint32_t len; - int pos=0; - uint32_t max_len; - unsigned idx = 0; - unsigned size_idx; - unsigned preamble_len; - uint32_t alloc_length; - int block_desc = 0; - int ret; - int32_t blen = 0; - int32_t *BufLen; - uint32_t i = 0; - - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { - BufLen = &SCSIDevices[zip_drives[id].scsi_device_id][zip_drives[id].scsi_device_lun].BufferLength; - zip[id].status &= ~ERR_STAT; - } else { - BufLen = &blen; - zip[id].error = 0; - } - - zip[id].packet_len = 0; - zip[id].request_pos = 0; - - zip[id].data_pos = 0; - - memcpy(zip[id].current_cdb, cdb, zip[id].cdb_len); - - if (cdb[0] != 0) { - zip_log("ZIP %i: Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X, Unit attention: %i\n", id, cdb[0], zip_sense_key, zip_asc, zip_ascq, zip[id].unit_attention); - zip_log("ZIP %i: Request length: %04X\n", id, zip[id].request_length); - - zip_log("ZIP %i: CDB: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", 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]); - } - - zip[id].sector_len = 0; - - zip_set_phase(id, SCSI_PHASE_STATUS); - - /* This handles the Not Ready/Unit Attention check if it has to be handled at this point. */ - if (zip_pre_execution_check(id, cdb) == 0) - return; - - switch (cdb[0]) { - case GPCMD_SEND_DIAGNOSTIC: - if (!(cdb[1] & (1 << 2))) { - zip_invalid_field(id); - return; - } - case GPCMD_SCSI_RESERVE: - case GPCMD_SCSI_RELEASE: - case GPCMD_TEST_UNIT_READY: - zip_set_phase(id, SCSI_PHASE_STATUS); - zip_command_complete(id); - break; - - case GPCMD_FORMAT_UNIT: - if ((zip_drives[id].bus_type == ZIP_BUS_SCSI) && zip_drives[id].read_only) - { - zip_write_protected(id); - return; - } - - zip_set_phase(id, SCSI_PHASE_STATUS); - zip_command_complete(id); - break; - - case GPCMD_IOMEGA_SENSE: - zip_set_phase(id, SCSI_PHASE_DATA_IN); - max_len = cdb[4]; - zip_buf_alloc(id, 256); - zip_set_buf_len(id, BufLen, &max_len); - memset(zipbufferb, 0, 256); - if (cdb[2] == 1) { - /* This page is related to disk health status - setting - this page to 0 makes disk health read as "marginal". */ - zipbufferb[0] = 0x58; - zipbufferb[1] = 0x00; - for (i = 0x00; i < 0x58; i++) - zipbufferb[i + 0x02] = 0xff; - } else if (cdb[2] == 2) { - zipbufferb[0] = 0x3d; - zipbufferb[1] = 0x00; - for (i = 0x00; i < 0x13; i++) - zipbufferb[i + 0x02] = 0x00; - zipbufferb[0x15] = 0x00; - if (zip_drives[id].read_only) - zipbufferb[0x15] |= 0x02; - for (i = 0x00; i < 0x27; i++) - zipbufferb[i + 0x16] = 0x00; - } else { - zip_invalid_field(id); - zip_buf_free(id); - return; - } - zip_data_command_finish(id, 18, 18, cdb[4], 0); - break; - - case GPCMD_REZERO_UNIT: - zip[id].sector_pos = zip[id].sector_len = 0; - zip_seek(id, 0); - zip_set_phase(id, SCSI_PHASE_STATUS); - 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. */ - zip_set_phase(id, SCSI_PHASE_DATA_IN); - max_len = cdb[4]; - zip_buf_alloc(id, 256); - zip_set_buf_len(id, BufLen, &max_len); - len = (cdb[1] & 1) ? 8 : 18; - zip_request_sense(id, zipbufferb, max_len, cdb[1] & 1); - zip_data_command_finish(id, len, len, cdb[4], 0); - break; - - case GPCMD_SET_SPEED: - case GPCMD_SET_SPEED_ALT: - zip_set_phase(id, SCSI_PHASE_STATUS); - zip_command_complete(id); - break; - - case GPCMD_MECHANISM_STATUS: - zip_set_phase(id, SCSI_PHASE_DATA_IN); - len = (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; - - zip_buf_alloc(id, 8); - - zip_set_buf_len(id, BufLen, &len); - - memset(zipbufferb, 0, 8); - zipbufferb[5] = 1; - - zip_data_command_finish(id, 8, 8, len, 0); - break; - - case GPCMD_READ_6: - case GPCMD_READ_10: - case GPCMD_READ_12: - zip_set_phase(id, SCSI_PHASE_DATA_IN); - alloc_length = 512; - - switch(cdb[0]) { - case GPCMD_READ_6: - zip[id].sector_len = cdb[4]; - zip[id].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", id, zip[id].sector_len, zip[id].sector_pos); - break; - case GPCMD_READ_10: - zip[id].sector_len = (cdb[7] << 8) | cdb[8]; - zip[id].sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - zip_log("ZIP %i: Length: %i, LBA: %i\n", id, zip[id].sector_len, zip[id].sector_pos); - break; - case GPCMD_READ_12: - zip[id].sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); - zip[id].sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); - break; - } - - if (!zip[id].sector_len) { - zip_set_phase(id, SCSI_PHASE_STATUS); - /* zip_log("ZIP %i: All done - callback set\n", id); */ - zip[id].packet_status = ZIP_PHASE_COMPLETE; - zip[id].callback = 20LL * ZIP_TIME; - zip_set_callback(id); - break; - } - - max_len = zip[id].sector_len; - zip[id].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. */ - - zip[id].packet_len = max_len * alloc_length; - zip_buf_alloc(id, zip[id].packet_len); - - ret = zip_blocks(id, &alloc_length, 1, 0); - if (ret <= 0) { - zip_buf_free(id); - return; - } - - zip[id].requested_blocks = max_len; - zip[id].packet_len = alloc_length; - - zip_set_buf_len(id, BufLen, &zip[id].packet_len); - - zip_data_command_finish(id, alloc_length, 512, alloc_length, 0); - - zip[id].all_blocks_total = zip[id].block_total; - if (zip[id].packet_status != ZIP_PHASE_COMPLETE) - ui_sb_update_icon(SB_ZIP | id, 1); - else - ui_sb_update_icon(SB_ZIP | id, 0); - return; - - case GPCMD_VERIFY_6: - case GPCMD_VERIFY_10: - case GPCMD_VERIFY_12: - if (!(cdb[1] & 2)) { - zip_set_phase(id, SCSI_PHASE_STATUS); - zip_command_complete(id); - break; - } - case GPCMD_WRITE_6: - case GPCMD_WRITE_10: - case GPCMD_WRITE_AND_VERIFY_10: - case GPCMD_WRITE_12: - case GPCMD_WRITE_AND_VERIFY_12: - zip_set_phase(id, SCSI_PHASE_DATA_OUT); - alloc_length = 512; - - if ((zip_drives[id].bus_type == ZIP_BUS_SCSI) && zip_drives[id].read_only) - { - zip_write_protected(id); - return; - } - - switch(cdb[0]) { - case GPCMD_VERIFY_6: - case GPCMD_WRITE_6: - zip[id].sector_len = cdb[4]; - zip[id].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: - case GPCMD_WRITE_AND_VERIFY_10: - zip[id].sector_len = (cdb[7] << 8) | cdb[8]; - zip[id].sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - zip_log("ZIP %i: Length: %i, LBA: %i\n", id, zip[id].sector_len, zip[id].sector_pos); - break; - case GPCMD_VERIFY_12: - case GPCMD_WRITE_12: - case GPCMD_WRITE_AND_VERIFY_12: - zip[id].sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); - zip[id].sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); - break; - } - - if (zip_drives[id].is_250) { - if ((zip[id].sector_pos >= zip_drives[id].medium_size) || ((zip[id].sector_pos + zip[id].sector_len - 1) >= zip_drives[id].medium_size)) - { - zip_lba_out_of_range(id); - return; - } - } else { - if ((zip[id].sector_pos >= ZIP_SECTORS) || ((zip[id].sector_pos + zip[id].sector_len - 1) >= ZIP_SECTORS)) - { - zip_lba_out_of_range(id); - return; - } - } - - if (!zip[id].sector_len) { - zip_set_phase(id, SCSI_PHASE_STATUS); - /* zip_log("ZIP %i: All done - callback set\n", id); */ - zip[id].packet_status = ZIP_PHASE_COMPLETE; - zip[id].callback = 20LL * ZIP_TIME; - zip_set_callback(id); - break; - } - - max_len = zip[id].sector_len; - zip[id].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. */ - - zip[id].packet_len = max_len * alloc_length; - zip_buf_alloc(id, zip[id].packet_len); - - zip[id].requested_blocks = max_len; - zip[id].packet_len = max_len << 9; - - zip_set_buf_len(id, BufLen, &zip[id].packet_len); - - zip_data_command_finish(id, zip[id].packet_len, 512, zip[id].packet_len, 1); - - zip[id].all_blocks_total = zip[id].block_total; - if (zip[id].packet_status != ZIP_PHASE_COMPLETE) - ui_sb_update_icon(SB_ZIP | id, 1); - else - ui_sb_update_icon(SB_ZIP | id, 0); - return; - - case GPCMD_WRITE_SAME_10: - zip_set_phase(id, SCSI_PHASE_DATA_OUT); - alloc_length = 512; - - if ((cdb[1] & 6) == 6) - { - zip_invalid_field(id); - return; - } - - if ((zip_drives[id].bus_type == ZIP_BUS_SCSI) && zip_drives[id].read_only) - { - zip_write_protected(id); - return; - } - - zip[id].sector_len = (cdb[7] << 8) | cdb[8]; - zip[id].sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - - if (zip_drives[id].is_250) { - if ((zip[id].sector_pos >= zip_drives[id].medium_size) || ((zip[id].sector_pos + zip[id].sector_len - 1) >= zip_drives[id].medium_size)) - { - zip_lba_out_of_range(id); - return; - } - } else { - if ((zip[id].sector_pos >= ZIP_SECTORS) || ((zip[id].sector_pos + zip[id].sector_len - 1) >= ZIP_SECTORS)) - { - zip_lba_out_of_range(id); - return; - } - } - - if (!zip[id].sector_len) { - zip_set_phase(id, SCSI_PHASE_STATUS); - /* zip_log("ZIP %i: All done - callback set\n", id); */ - zip[id].packet_status = ZIP_PHASE_COMPLETE; - zip[id].callback = 20LL * ZIP_TIME; - zip_set_callback(id); - break; - } - - max_len = zip[id].sector_len; - zip[id].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. */ - - zip[id].packet_len = max_len * alloc_length; - zip_buf_alloc(id, zip[id].packet_len); - - zip[id].requested_blocks = max_len; - zip[id].packet_len = alloc_length; - - zip_set_buf_len(id, BufLen, &zip[id].packet_len); - - zip_data_command_finish(id, zip[id].packet_len, 512, zip[id].packet_len, 1); - - zip[id].all_blocks_total = zip[id].block_total; - if (zip[id].packet_status != ZIP_PHASE_COMPLETE) - ui_sb_update_icon(SB_ZIP | id, 1); - else - ui_sb_update_icon(SB_ZIP | id, 0); - return; - - case GPCMD_MODE_SENSE_6: - case GPCMD_MODE_SENSE_10: - zip_set_phase(id, SCSI_PHASE_DATA_IN); - - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) - block_desc = ((cdb[1] >> 3) & 1) ? 0 : 1; - else - block_desc = 0; - - if (cdb[0] == GPCMD_MODE_SENSE_6) { - len = cdb[4]; - zip_buf_alloc(id, 256); - } else { - len = (cdb[8] | (cdb[7] << 8)); - zip_buf_alloc(id, 65536); - } - - zip[id].current_page_code = cdb[2] & 0x3F; - zip_log("Mode sense page: %02X\n", zip[id].current_page_code); - - if (!(zip_mode_sense_page_flags & (1LL << zip[id].current_page_code))) { - zip_invalid_field(id); - zip_buf_free(id); - return; - } - - memset(zipbufferb, 0, len); - alloc_length = len; - - if (cdb[0] == GPCMD_MODE_SENSE_6) { - len = zip_mode_sense(id, zipbufferb, 4, cdb[2], block_desc); - len = MIN(len, alloc_length); - zipbufferb[0] = len - 1; - zipbufferb[1] = 0; - if (block_desc) - zipbufferb[3] = 8; - } else { - len = zip_mode_sense(id, zipbufferb, 8, cdb[2], block_desc); - len = MIN(len, alloc_length); - zipbufferb[0]=(len - 2) >> 8; - zipbufferb[1]=(len - 2) & 255; - zipbufferb[2] = 0; - if (block_desc) { - zipbufferb[6] = 0; - zipbufferb[7] = 8; - } - } - - zip_set_buf_len(id, BufLen, &len); - - zip_log("ZIP %i: Reading mode page: %02X...\n", id, cdb[2]); - - zip_data_command_finish(id, len, len, alloc_length, 0); - return; - - case GPCMD_MODE_SELECT_6: - case GPCMD_MODE_SELECT_10: - zip_set_phase(id, SCSI_PHASE_DATA_OUT); - - if (cdb[0] == GPCMD_MODE_SELECT_6) { - len = cdb[4]; - zip_buf_alloc(id, 256); - } else { - len = (cdb[7] << 8) | cdb[8]; - zip_buf_alloc(id, 65536); - } - - zip_set_buf_len(id, BufLen, &len); - - zip[id].total_length = len; - zip[id].do_page_save = cdb[1] & 1; - - zip[id].current_page_pos = 0; - - zip_data_command_finish(id, len, len, len, 1); - return; - - case GPCMD_START_STOP_UNIT: - zip_set_phase(id, SCSI_PHASE_STATUS); - - switch(cdb[4] & 3) { - case 0: /* Stop the disc. */ - zip_eject(id); /* The Iomega Windows 9x drivers require this. */ - break; - case 1: /* Start the disc and read the TOC. */ - break; - case 2: /* Eject the disc if possible. */ - /* zip_eject(id); */ - break; - case 3: /* Load the disc (close tray). */ - zip_reload(id); - break; - } - - zip_command_complete(id); - break; - - case GPCMD_INQUIRY: - zip_set_phase(id, SCSI_PHASE_DATA_IN); - - max_len = cdb[3]; - max_len <<= 8; - max_len |= cdb[4]; - - zip_buf_alloc(id, 65536); - - if (cdb[1] & 1) { - preamble_len = 4; - size_idx = 3; - - zipbufferb[idx++] = 05; - zipbufferb[idx++] = cdb[2]; - zipbufferb[idx++] = 0; - - idx++; - - switch (cdb[2]) { - case 0x00: - zipbufferb[idx++] = 0x00; - zipbufferb[idx++] = 0x83; - break; - case 0x83: - if (idx + 24 > max_len) { - zip_data_phase_error(id); - zip_buf_free(id); - return; - } - - zipbufferb[idx++] = 0x02; - zipbufferb[idx++] = 0x00; - zipbufferb[idx++] = 0x00; - zipbufferb[idx++] = 20; - ide_padstr8(zipbufferb + idx, 20, "53R141"); /* Serial */ - idx += 20; - - if (idx + 72 > cdb[4]) - goto atapi_out; - zipbufferb[idx++] = 0x02; - zipbufferb[idx++] = 0x01; - zipbufferb[idx++] = 0x00; - zipbufferb[idx++] = 68; - ide_padstr8(zipbufferb + idx, 8, "IOMEGA "); /* Vendor */ - idx += 8; - if (zip_drives[id].is_250) - ide_padstr8(zipbufferb + idx, 40, "ZIP 250 "); /* Product */ - else - ide_padstr8(zipbufferb + idx, 40, "ZIP 100 "); /* Product */ - idx += 40; - ide_padstr8(zipbufferb + idx, 20, "53R141"); /* Product */ - idx += 20; - break; - default: - zip_log("INQUIRY: Invalid page: %02X\n", cdb[2]); - zip_invalid_field(id); - zip_buf_free(id); - return; - } - } else { - preamble_len = 5; - size_idx = 4; - - memset(zipbufferb, 0, 8); - if (cdb[1] & 0xe0) - zipbufferb[0] = 0x60; /*No physical device on this LUN*/ - else - zipbufferb[0] = 0x00; /*Hard disk*/ - zipbufferb[1] = 0x80; /*Removable*/ - if (zip_drives[id].is_250) { - zipbufferb[2] = (zip_drives[id].bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x00; /*SCSI-2 compliant*/ - zipbufferb[3] = (zip_drives[id].bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x21; - } else { - zipbufferb[2] = (zip_drives[id].bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x00; /*SCSI-2 compliant*/ - zipbufferb[3] = (zip_drives[id].bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x21; - } - zipbufferb[4] = 31; - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { - zipbufferb[6] = 1; /* 16-bit transfers supported */ - zipbufferb[7] = 0x20; /* Wide bus supported */ - } - - ide_padstr8(zipbufferb + 8, 8, "IOMEGA "); /* Vendor */ - if (zip_drives[id].is_250) { - ide_padstr8(zipbufferb + 16, 16, "ZIP 250 "); /* Product */ - ide_padstr8(zipbufferb + 32, 4, "42.S"); /* Revision */ - if (max_len >= 44) - ide_padstr8(zipbufferb + 36, 8, "08/08/01"); /* Date? */ - if (max_len >= 122) - ide_padstr8(zipbufferb + 96, 26, "(c) Copyright IOMEGA 2000 "); /* Copyright string */ - - } else { - ide_padstr8(zipbufferb + 16, 16, "ZIP 100 "); /* Product */ - ide_padstr8(zipbufferb + 32, 4, "E.08"); /* Revision */ - } - idx = 36; - - if (max_len == 96) { - zipbufferb[4] = 91; - idx = 96; - } else if (max_len == 128) { - zipbufferb[4] = 0x75; - idx = 128; - } - } - -atapi_out: - zipbufferb[size_idx] = idx - preamble_len; - len=idx; - - len = MIN(len, max_len); - zip_set_buf_len(id, BufLen, &len); - - zip_data_command_finish(id, len, len, max_len, 0); - break; - - case GPCMD_PREVENT_REMOVAL: - zip_set_phase(id, SCSI_PHASE_STATUS); - zip_command_complete(id); - break; - - case GPCMD_SEEK_6: - case GPCMD_SEEK_10: - zip_set_phase(id, SCSI_PHASE_STATUS); - - switch(cdb[0]) { - case GPCMD_SEEK_6: - pos = (cdb[2] << 8) | cdb[3]; - break; - case GPCMD_SEEK_10: - pos = (cdb[2] << 24) | (cdb[3]<<16) | (cdb[4]<<8) | cdb[5]; - break; - } - zip_seek(id, pos); - zip_command_complete(id); - break; - - case GPCMD_READ_CDROM_CAPACITY: - zip_set_phase(id, SCSI_PHASE_DATA_IN); - - zip_buf_alloc(id, 8); - - if (zip_read_capacity(id, zip[id].current_cdb, zipbufferb, &len) == 0) { - zip_buf_free(id); - return; - } - - zip_set_buf_len(id, BufLen, &len); - - zip_data_command_finish(id, len, len, len, 0); - break; - - case GPCMD_IOMEGA_EJECT: - zip_set_phase(id, SCSI_PHASE_STATUS); - zip_eject(id); - zip_command_complete(id); - break; - - default: - zip_illegal_opcode(id); - break; - } - - /* zip_log("ZIP %i: Phase: %02X, request length: %i\n", zip[id].phase, zip[id].request_length); */ - - if (zip_atapi_phase_to_scsi(id) == SCSI_PHASE_STATUS) - zip_buf_free(id); -} - -/* The command second phase function, needed for Mode Select. */ -uint8_t zip_phase_data_out(uint8_t id) -{ - uint16_t block_desc_len; - uint16_t pos; - - uint8_t error = 0; - uint8_t page, page_len; - - uint16_t i = 0; - - uint8_t hdr_len, val, old_val, ch; - - uint32_t last_to_write = 0, len = 0; - uint32_t c, h, s; - - switch(zip[id].current_cdb[0]) { - case GPCMD_VERIFY_6: - case GPCMD_VERIFY_10: - case GPCMD_VERIFY_12: - break; - case GPCMD_WRITE_6: - case GPCMD_WRITE_10: - case GPCMD_WRITE_AND_VERIFY_10: - case GPCMD_WRITE_12: - case GPCMD_WRITE_AND_VERIFY_12: - if (zip[id].requested_blocks > 0) - zip_blocks(id, &len, 1, 1); - break; - case GPCMD_WRITE_SAME_10: - if (!zip[id].current_cdb[7] && !zip[id].current_cdb[8]) { - if (zip_drives[id].is_250) - last_to_write = (zip_drives[id].medium_size - 1); - else - last_to_write = (ZIP_SECTORS - 1); - } else - last_to_write = zip[id].sector_pos + zip[id].sector_len - 1; - - for (i = zip[id].sector_pos; i <= last_to_write; i++) { - if (zip[id].current_cdb[1] & 2) { - zipbufferb[0] = (i >> 24) & 0xff; - zipbufferb[1] = (i >> 16) & 0xff; - zipbufferb[2] = (i >> 8) & 0xff; - zipbufferb[3] = i & 0xff; - } else if (zip[id].current_cdb[1] & 4) { - /* CHS are 96,1,2048 (ZIP 100) and 239,1,2048 (ZIP 250) */ - s = (i % 2048); - h = ((i - s) / 2048) % 1; - c = ((i - s) / 2048) / 1; - zipbufferb[0] = (c >> 16) & 0xff; - zipbufferb[1] = (c >> 8) & 0xff; - zipbufferb[2] = c & 0xff; - zipbufferb[3] = h & 0xff; - zipbufferb[4] = (s >> 24) & 0xff; - zipbufferb[5] = (s >> 16) & 0xff; - zipbufferb[6] = (s >> 8) & 0xff; - zipbufferb[7] = s & 0xff; - } - fseek(zip_drives[id].f, zip_drives[id].base + (i << 9), SEEK_SET); - fwrite(zipbufferb, 1, 512, zip_drives[id].f); - } - break; - case GPCMD_MODE_SELECT_6: - case GPCMD_MODE_SELECT_10: - if (zip[id].current_cdb[0] == GPCMD_MODE_SELECT_10) - hdr_len = 8; - else - hdr_len = 4; - - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { - if (zip[id].current_cdb[0] == GPCMD_MODE_SELECT_6) { - block_desc_len = zipbufferb[2]; - block_desc_len <<= 8; - block_desc_len |= zipbufferb[3]; - } else { - block_desc_len = zipbufferb[6]; - block_desc_len <<= 8; - block_desc_len |= zipbufferb[7]; - } - } else - block_desc_len = 0; - - pos = hdr_len + block_desc_len; - - while(1) { - page = zipbufferb[pos] & 0x3F; - page_len = zipbufferb[pos + 1]; - - pos += 2; - - if (!(zip_mode_sense_page_flags & (1LL << ((uint64_t) page)))) - error |= 1; - else { - for (i = 0; i < page_len; i++) { - ch = zip_mode_sense_pages_changeable.pages[page][i + 2]; - val = zipbufferb[pos + i]; - old_val = zip_mode_sense_pages_saved[id].pages[page][i + 2]; - if (val != old_val) { - if (ch) - zip_mode_sense_pages_saved[id].pages[page][i + 2] = val; - else - error |= 1; - } - } - } - - pos += page_len; - - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) - val = zip_mode_sense_pages_default_scsi.pages[page][0] & 0x80; - else - val = zip_mode_sense_pages_default.pages[page][0] & 0x80; - if (zip[id].do_page_save && val) - zip_mode_sense_save(id); - - if (pos >= zip[id].total_length) - break; - } - - if (error) { - zip_invalid_field_pl(id); - return 0; - } - break; - } - - return 1; -} - -/* This is the general ATAPI PIO request function. */ -void zip_pio_request(uint8_t id, uint8_t out) -{ - int old_pos = 0; - int ret = 0; - - if (zip_drives[id].bus_type < ZIP_BUS_SCSI) { - zip_log("ZIP %i: Lowering IDE IRQ\n", id); - ide_irq_lower(&(ide_drives[zip_drives[id].ide_channel])); - } - - zip[id].status = BUSY_STAT; - - if (zip[id].pos >= zip[id].packet_len) { - zip_log("ZIP %i: %i bytes %s, command done\n", id, zip[id].pos, out ? "written" : "read"); - - zip[id].pos = zip[id].request_pos = 0; - if (out) { - ret = zip_phase_data_out(id); - /* If ret = 0 (phase 1 error), then we do not do anything else other than - free the buffer, as the phase and callback have already been set by the - error function. */ - if (ret) - zip_command_complete(id); - } else - zip_command_complete(id); - ui_sb_update_icon(SB_ZIP | id, 0); - zip_buf_free(id); - } else { - zip_log("ZIP %i: %i bytes %s, %i bytes are still left\n", id, zip[id].pos, out ? "written" : "read", zip[id].packet_len - zip[id].pos); - - /* Make sure to keep pos, and reset request_pos to 0. */ - /* Also make sure to not reset total_read. */ - - /* If less than (packet length) bytes are remaining, update packet length - accordingly. */ - if ((zip[id].packet_len - zip[id].pos) < (zip[id].max_transfer_len)) - zip[id].max_transfer_len = zip[id].packet_len - zip[id].pos; - - old_pos = zip[id].pos; - zip[id].packet_status = out ? ZIP_PHASE_DATA_OUT : ZIP_PHASE_DATA_IN; - zip_command_common(id); - zip[id].pos = old_pos; - zip[id].request_pos = 0; - } -} - -void zip_phase_callback(uint8_t id); - -int zip_read_from_ide_dma(uint8_t channel) -{ - uint8_t id = atapi_zip_drives[channel]; - - if (id > ZIP_NUM) - return 0; - - if (ide_bus_master_write) { - if (ide_bus_master_write(channel >> 1, zipbufferb, zip[id].packet_len)) { - zip_bus_master_error(id); - zip_phase_callback(id); - return 0; - } else - return 1; - } else { - zip_bus_master_error(id); - zip_phase_callback(id); - return 0; - } - - return 0; -} - -int zip_read_from_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun) -{ - uint8_t id = scsi_zip_drives[scsi_id][scsi_lun]; - int32_t *BufLen = &SCSIDevices[scsi_id][scsi_lun].BufferLength; - - if (id > ZIP_NUM) - return 0; - - zip_log("Reading from SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, *BufLen); - memcpy(zipbufferb, SCSIDevices[scsi_id][scsi_lun].CmdBuffer, *BufLen); - return 1; -} - -int zip_read_from_dma(uint8_t id) -{ - int32_t *BufLen = &SCSIDevices[zip_drives[id].scsi_device_id][zip_drives[id].scsi_device_lun].BufferLength; - - int ret = 0; - - int in_data_length = 0; - - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) - ret = zip_read_from_scsi_dma(zip_drives[id].scsi_device_id, zip_drives[id].scsi_device_lun); - else - ret = zip_read_from_ide_dma(zip_drives[id].ide_channel); - - if (!ret) - return 0; - - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { - in_data_length = *BufLen; - zip_log("ZIP %i: SCSI Input data length: %i\n", id, in_data_length); - } else { - in_data_length = zip[id].max_transfer_len; - zip_log("ZIP %i: ATAPI Input data length: %i\n", id, in_data_length); - } - - ret = zip_phase_data_out(id); - if (!ret) { - zip_phase_callback(id); - return 0; - } else - return 1; - - return 0; -} - -int zip_write_to_ide_dma(uint8_t channel) -{ - uint8_t id = atapi_zip_drives[channel]; - - if (id > ZIP_NUM) { - zip_log("ZIP %i: Drive not found\n", id); - return 0; - } - - if (ide_bus_master_read) { - if (ide_bus_master_read(channel >> 1, zipbufferb, zip[id].packet_len)) { - zip_log("ZIP %i: ATAPI DMA error\n", id); - zip_bus_master_error(id); - zip_phase_callback(id); - return 0; - } - else { - zip_log("ZIP %i: ATAPI DMA success\n", id); - return 1; - } - } else { - zip_log("ZIP %i: No bus master\n", id); - zip_bus_master_error(id); - zip_phase_callback(id); - return 0; - } - - return 0; -} - -int zip_write_to_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun) -{ - uint8_t id = scsi_zip_drives[scsi_id][scsi_lun]; - int32_t *BufLen = &SCSIDevices[scsi_id][scsi_lun].BufferLength; - - if (id > ZIP_NUM) - return 0; - - zip_log("Writing to SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, *BufLen); - memcpy(SCSIDevices[scsi_id][scsi_lun].CmdBuffer, zipbufferb, *BufLen); - zip_log("ZIP %i: Data from CD buffer: %02X %02X %02X %02X %02X %02X %02X %02X\n", id, zipbufferb[0], zipbufferb[1], zipbufferb[2], zipbufferb[3], zipbufferb[4], zipbufferb[5], zipbufferb[6], zipbufferb[7]); - zip_log("ZIP %i: Data from SCSI DMA : %02X %02X %02X %02X %02X %02X %02X %02X\n", id, SCSIDevices[scsi_id][scsi_lun].CmdBuffer[0], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[1], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[2], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[3], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[4], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[5], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[6], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[7]); - return 1; -} - -int zip_write_to_dma(uint8_t id) -{ - int ret = 0; - - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { - zip_log("Write to SCSI DMA: (%02X:%02X)\n", zip_drives[id].scsi_device_id, zip_drives[id].scsi_device_lun); - ret = zip_write_to_scsi_dma(zip_drives[id].scsi_device_id, zip_drives[id].scsi_device_lun); - } else - ret = zip_write_to_ide_dma(zip_drives[id].ide_channel); - - if (!ret) - return 0; - - return 1; -} - -void zip_irq_raise(uint8_t id) -{ - if (zip_drives[id].bus_type < ZIP_BUS_SCSI) - ide_irq_raise(&(ide_drives[zip_drives[id].ide_channel])); -} - -/* If the result is 1, issue an IRQ, otherwise not. */ -void zip_phase_callback(uint8_t id) -{ - switch(zip[id].packet_status) { - case ZIP_PHASE_IDLE: - zip_log("ZIP %i: ZIP_PHASE_IDLE\n", id); - zip[id].pos=0; - zip[id].phase = 1; - zip[id].status = READY_STAT | DRQ_STAT | (zip[id].status & ERR_STAT); - return; - case ZIP_PHASE_COMMAND: - zip_log("ZIP %i: ZIP_PHASE_COMMAND\n", id); - zip[id].status = BUSY_STAT | (zip[id].status &ERR_STAT); - memcpy(zip[id].atapi_cdb, zipbufferb, zip[id].cdb_len); - zip_command(id, zip[id].atapi_cdb); - return; - case ZIP_PHASE_COMPLETE: - zip_log("ZIP %i: ZIP_PHASE_COMPLETE\n", id); - zip[id].status = READY_STAT; - zip[id].phase = 3; - zip[id].packet_status = 0xFF; - ui_sb_update_icon(SB_ZIP | id, 0); - zip_irq_raise(id); - return; - case ZIP_PHASE_DATA_OUT: - zip_log("ZIP %i: ZIP_PHASE_DATA_OUT\n", id); - zip[id].status = READY_STAT | DRQ_STAT | (zip[id].status & ERR_STAT); - zip[id].phase = 0; - zip_irq_raise(id); - return; - case ZIP_PHASE_DATA_OUT_DMA: - zip_log("ZIP %i: ZIP_PHASE_DATA_OUT_DMA\n", id); - zip_read_from_dma(id); - zip_buf_free(id); - zip[id].packet_status = ZIP_PHASE_COMPLETE; - zip[id].status = READY_STAT; - zip[id].phase = 3; - ui_sb_update_icon(SB_ZIP | id, 0); - zip_irq_raise(id); - return; - case ZIP_PHASE_DATA_IN: - zip_log("ZIP %i: ZIP_PHASE_DATA_IN\n", id); - zip[id].status = READY_STAT | DRQ_STAT | (zip[id].status & ERR_STAT); - zip[id].phase = 2; - zip_irq_raise(id); - return; - case ZIP_PHASE_DATA_IN_DMA: - zip_log("ZIP %i: ZIP_PHASE_DATA_IN_DMA\n", id); - zip_write_to_dma(id); - zip_buf_free(id); - zip[id].packet_status = ZIP_PHASE_COMPLETE; - zip[id].status = READY_STAT; - zip[id].phase = 3; - ui_sb_update_icon(SB_ZIP | id, 0); - zip_irq_raise(id); - return; - case ZIP_PHASE_ERROR: - zip_log("ZIP %i: ZIP_PHASE_ERROR\n", id); - zip[id].status = READY_STAT | ERR_STAT; - zip[id].phase = 3; - zip_irq_raise(id); - ui_sb_update_icon(SB_ZIP | id, 0); - return; - } -} - -/* Reimplement as 8-bit due to reimplementation of IDE data read and write. */ -uint32_t zip_read(uint8_t channel, int length) -{ - uint16_t *zipbufferw; - uint32_t *zipbufferl; - - uint8_t id = atapi_zip_drives[channel]; - - uint32_t temp = 0; - - if (id > ZIP_NUM) - return 0; - - zipbufferw = (uint16_t *) zipbufferb; - zipbufferl = (uint32_t *) zipbufferb; - - if (!zipbufferb) - return 0; - - /* 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 = 512 bytes). */ - switch(length) { - case 1: - temp = (zip[id].pos < zip[id].packet_len) ? zipbufferb[zip[id].pos] : 0; - zip[id].pos++; - zip[id].request_pos++; - break; - case 2: - temp = (zip[id].pos < zip[id].packet_len) ? zipbufferw[zip[id].pos >> 1] : 0; - zip[id].pos += 2; - zip[id].request_pos += 2; - break; - case 4: - temp = (zip[id].pos < zip[id].packet_len) ? zipbufferl[zip[id].pos >> 2] : 0; - zip[id].pos += 4; - zip[id].request_pos += 4; - break; - default: - return 0; - } - - if (zip[id].packet_status == ZIP_PHASE_DATA_IN) { - if ((zip[id].request_pos >= zip[id].max_transfer_len) || (zip[id].pos >= zip[id].packet_len)) { - /* Time for a DRQ. */ - // zip_log("ZIP %i: Issuing read callback\n", id); - zip_pio_request(id, 0); - } - // zip_log("ZIP %i: Returning: %02X (buffer position: %i, request position: %i)\n", id, temp, zip[id].pos, zip[id].request_pos); - return temp; - } else { - // zip_log("ZIP %i: Returning zero (buffer position: %i, request position: %i)\n", id, zip[id].pos, zip[id].request_pos); - return 0; - } -} - -/* Reimplement as 8-bit due to reimplementation of IDE data read and write. */ -void zip_write(uint8_t channel, uint32_t val, int length) -{ - uint16_t *zipbufferw; - uint32_t *zipbufferl; - - uint8_t id = atapi_zip_drives[channel]; - - if (id > ZIP_NUM) - return; - - if (zip[id].packet_status == ZIP_PHASE_IDLE) { - if (!zipbufferb) - zip_buf_alloc(id, zip[id].cdb_len); - } - - zipbufferw = (uint16_t *) zipbufferb; - zipbufferl = (uint32_t *) zipbufferb; - - if (!zipbufferb) - return; - - switch(length) { - case 1: - zipbufferb[zip[id].pos] = val & 0xff; - zip[id].pos++; - zip[id].request_pos++; - break; - case 2: - zipbufferw[zip[id].pos >> 1] = val & 0xffff; - zip[id].pos += 2; - zip[id].request_pos += 2; - break; - case 4: - zipbufferl[zip[id].pos >> 2] = val; - zip[id].pos += 4; - zip[id].request_pos += 4; - break; - default: - return; - } - - if (zip[id].packet_status == ZIP_PHASE_DATA_OUT) { - if ((zip[id].request_pos >= zip[id].max_transfer_len) || (zip[id].pos >= zip[id].packet_len)) { - /* Time for a DRQ. */ - zip_pio_request(id, 1); - } - return; - } else if (zip[id].packet_status == ZIP_PHASE_IDLE) { - if (zip[id].pos >= zip[id].cdb_len) { - zip[id].pos=0; - zip[id].status = BUSY_STAT; - zip[id].packet_status = ZIP_PHASE_COMMAND; - timer_process(); - zip_phase_callback(id); - timer_update_outstanding(); - } - return; - } -} - -void zip_hard_reset(void) -{ - int i = 0; - - for (i=0; i + * Miran Grca, + * + * Copyright 2018 Miran Grca. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../emu.h" +#include "../config.h" +#include "../timer.h" +#include "../device.h" +#include "../intel_piix.h" +#include "../scsi/scsi.h" +#include "../nvr.h" +#include "../disk/hdc.h" +#include "../disk/hdc_ide.h" +#include "../plat.h" +#include "../ui.h" +#include "zip.h" + + +/* Bits of 'status' */ +#define ERR_STAT 0x01 +#define DRQ_STAT 0x08 /* Data request */ +#define DSC_STAT 0x10 +#define SERVICE_STAT 0x10 +#define READY_STAT 0x40 +#define BUSY_STAT 0x80 + +/* Bits of 'error' */ +#define ABRT_ERR 0x04 /* Command aborted */ +#define MCR_ERR 0x08 /* Media change request */ + +zip_t zip[ZIP_NUM]; +zip_drive_t zip_drives[ZIP_NUM]; +uint8_t atapi_zip_drives[8] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; +uint8_t scsi_zip_drives[16][8] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } }; + + +/* Table of all SCSI commands and their flags, needed for the new disc change / not ready handler. */ +uint8_t zip_command_flags[0x100] = +{ + IMPLEMENTED | CHECK_READY | NONDATA, /* 0x00 */ + IMPLEMENTED | ALLOW_UA | NONDATA | SCSI_ONLY, /* 0x01 */ + 0, + IMPLEMENTED | ALLOW_UA, /* 0x03 */ + IMPLEMENTED | CHECK_READY | ALLOW_UA | NONDATA | SCSI_ONLY, /* 0x04 */ + 0, + IMPLEMENTED, /* 0x06 */ + 0, + IMPLEMENTED | CHECK_READY, /* 0x08 */ + 0, + IMPLEMENTED | CHECK_READY, /* 0x0A */ + 0, + IMPLEMENTED, /* 0x0C */ + IMPLEMENTED | ATAPI_ONLY, /* 0x0D */ + 0, 0, 0, 0, + IMPLEMENTED | ALLOW_UA, /* 0x12 */ + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x13 */ + 0, + IMPLEMENTED, /* 0x15 */ + IMPLEMENTED | SCSI_ONLY, /* 0x16 */ + IMPLEMENTED | SCSI_ONLY, /* 0x17 */ + 0, 0, + IMPLEMENTED, + IMPLEMENTED | CHECK_READY, /* 0x1B */ + 0, + IMPLEMENTED, /* 0x1D */ + IMPLEMENTED | CHECK_READY, /* 0x1E */ + 0, 0, 0, 0, 0, 0, + IMPLEMENTED | CHECK_READY, /* 0x25 */ + 0, 0, + IMPLEMENTED | CHECK_READY, /* 0x28 */ + 0, + IMPLEMENTED | CHECK_READY, /* 0x2A */ + 0, 0, 0, + IMPLEMENTED | CHECK_READY, /* 0x2E */ + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x2F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, + IMPLEMENTED | CHECK_READY, /* 0x41 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + IMPLEMENTED, /* 0x55 */ + 0, 0, 0, 0, + IMPLEMENTED, /* 0x5A */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + IMPLEMENTED | CHECK_READY, /* 0xA8 */ + 0, + IMPLEMENTED | CHECK_READY, /* 0xAA */ + 0, 0, 0, + IMPLEMENTED | CHECK_READY, /* 0xAE */ + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0xAF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + IMPLEMENTED, /* 0xBD */ + 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +uint64_t zip_mode_sense_page_flags = (1LL << GPMODE_R_W_ERROR_PAGE) | (1LL << 0x02LL) | (1LL << 0x2FLL) | (1LL << GPMODE_ALL_PAGES); +uint64_t zip_250_mode_sense_page_flags = (1LL << GPMODE_R_W_ERROR_PAGE) | (1LL << 0x05LL) | (1LL << 0x08LL) | (1LL << 0x2FLL) | (1LL << GPMODE_ALL_PAGES); + + +static const mode_sense_pages_t zip_mode_sense_pages_default = +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 0x0a, 0xc8, 22, 0, 0, 0, 0, 90, 0, 0x50, 0x20 }, + { 0x02, 0x0e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x2f, 0x04, 0x5c, 0x0f, 0xff, 0x0f } +} }; + +static const mode_sense_pages_t zip_250_mode_sense_pages_default = +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 0x06, 0xc8, 0x64, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x05, 0x1e, 0x80, 0, 0x40, 0x20, 2, 0, 0, 0xef, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0b, 0x7d, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x08, 0x0a, 4, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x2f, 0x04, 0x5c, 0x0f, 0x3c, 0x0f } +} }; + +static const mode_sense_pages_t zip_mode_sense_pages_default_scsi = +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 0x0a, 0xc8, 22, 0, 0, 0, 0, 90, 0, 0x50, 0x20 }, + { 0x02, 0x0e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x2f, 0x04, 0x5c, 0x0f, 0xff, 0x0f } +} }; + +static const mode_sense_pages_t zip_250_mode_sense_pages_default_scsi = +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 0x06, 0xc8, 0x64, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x05, 0x1e, 0x80, 0, 0x40, 0x20, 2, 0, 0, 0xef, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0b, 0x7d, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x08, 0x0a, 4, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x2f, 0x04, 0x5c, 0x0f, 0x3c, 0x0f } +} }; + +static const mode_sense_pages_t zip_mode_sense_pages_changeable = +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 0x0a, 0xc8, 22, 0, 0, 0, 0, 90, 0, 0x50, 0x20 }, + { 0x02, 0x0e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x2f, 0x04, 0x5c, 0x0f, 0xff, 0x0f } +} }; + +static const mode_sense_pages_t zip_250_mode_sense_pages_changeable = +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 0x06, 0xc8, 0x64, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x05, 0x1e, 0x80, 0, 0x40, 0x20, 2, 0, 0, 0xef, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0b, 0x7d, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x08, 0x0a, 4, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x2f, 0x04, 0x5c, 0x0f, 0x3c, 0x0f } +} }; + +static mode_sense_pages_t zip_mode_sense_pages_saved[ZIP_NUM]; + + +#ifdef ENABLE_ZIP_LOG +int zip_do_log = ENABLE_ZIP_LOG; +#endif + + +static void +zip_log(const char *format, ...) +{ +#ifdef ENABLE_ZIP_LOG + va_list ap; + + if (zip_do_log) + { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +int find_zip_for_channel(uint8_t channel) +{ + uint8_t i = 0; + + for (i = 0; i < ZIP_NUM; i++) { + if (((zip_drives[i].bus_type == ZIP_BUS_ATAPI_PIO_ONLY) || (zip_drives[i].bus_type == ZIP_BUS_ATAPI_PIO_AND_DMA)) && (zip_drives[i].ide_channel == channel)) + return i; + } + return 0xff; +} + +void zip_init(int id, int cdb_len_setting); + +int zip_load(uint8_t id, wchar_t *fn) +{ + int read_only = zip_drives[id].ui_writeprot; + int size = 0; + + zip_drives[id].f = plat_fopen(fn, zip_drives[id].ui_writeprot ? L"rb" : L"rb+"); + if (!zip_drives[id].ui_writeprot && !zip_drives[id].f) { + zip_drives[id].f = plat_fopen(fn, L"rb"); + read_only = 1; + } + if (zip_drives[id].f) { + fseek(zip_drives[id].f, 0, SEEK_END); + size = ftell(zip_drives[id].f); + + if ((size == ((ZIP_250_SECTORS << 9) + 0x1000)) || (size == ((ZIP_SECTORS << 9) + 0x1000))) { + /* This is a ZDI image. */ + size -= 0x1000; + zip_drives[id].base = 0x1000; + } else + zip_drives[id].base = 0; + + if (zip_drives[id].is_250) { + if ((size != (ZIP_250_SECTORS << 9)) && (size != (ZIP_SECTORS << 9))) { + zip_log("File is incorrect size for a ZIP image\nMust be exactly %i or %i bytes\n", ZIP_250_SECTORS << 9, ZIP_SECTORS << 9); + fclose(zip_drives[id].f); + zip_drives[id].f = NULL; + zip_drives[id].medium_size = 0; + zip_eject(id); /* Make sure the host OS knows we've rejected (and ejected) the image. */ + return 0; + } + } else { + if (size != (ZIP_SECTORS << 9)) { + zip_log("File is incorrect size for a ZIP image\nMust be exactly %i bytes\n", ZIP_SECTORS << 9); + fclose(zip_drives[id].f); + zip_drives[id].f = NULL; + zip_drives[id].medium_size = 0; + zip_eject(id); /* Make sure the host OS knows we've rejected (and ejected) the image. */ + return 0; + } + } + + zip_drives[id].medium_size = size >> 9; + + fseek(zip_drives[id].f, zip_drives[id].base, SEEK_SET); + + memcpy(zip_drives[id].image_path, fn, sizeof(zip_drives[id].image_path)); + + zip_drives[id].read_only = read_only; + + return 1; + } + + return 0; +} + +void zip_disk_reload(uint8_t id) +{ + int ret = 0; + + if (wcslen(zip_drives[id].prev_image_path) == 0) + return; + else + ret = zip_load(id, zip_drives[id].prev_image_path); + + if (ret) + zip[id].unit_attention = 1; +} + +void zip_close(uint8_t id) +{ + if (zip_drives[id].f) { + fclose(zip_drives[id].f); + zip_drives[id].f = NULL; + + memcpy(zip_drives[id].prev_image_path, zip_drives[id].image_path, sizeof(zip_drives[id].prev_image_path)); + memset(zip_drives[id].image_path, 0, sizeof(zip_drives[id].image_path)); + + zip_drives[id].medium_size = 0; + } +} + +void build_atapi_zip_map() +{ + uint8_t i = 0; + + memset(atapi_zip_drives, 0xff, 8); + + for (i = 0; i < 8; i++) { + atapi_zip_drives[i] = find_zip_for_channel(i); + if (atapi_zip_drives[i] != 0xff) + zip_init(atapi_zip_drives[i], 12); + } +} + +int find_zip_for_scsi_id(uint8_t scsi_id, uint8_t scsi_lun) +{ + uint8_t i = 0; + + for (i = 0; i < ZIP_NUM; i++) { + if ((zip_drives[i].bus_type == ZIP_BUS_SCSI) && (zip_drives[i].scsi_device_id == scsi_id) && (zip_drives[i].scsi_device_lun == scsi_lun)) + return i; + } + return 0xff; +} + +void build_scsi_zip_map() +{ + uint8_t i = 0; + uint8_t j = 0; + + for (i = 0; i < 16; i++) + memset(scsi_zip_drives[i], 0xff, 8); + + for (i = 0; i < 16; i++) { + for (j = 0; j < 8; j++) { + scsi_zip_drives[i][j] = find_zip_for_scsi_id(i, j); + if (scsi_zip_drives[i][j] != 0xff) + zip_init(scsi_zip_drives[i][j], 12); + } + } +} + +void zip_set_callback(uint8_t id) +{ + if (zip_drives[id].bus_type != ZIP_BUS_SCSI) + ide_set_callback(zip_drives[id].ide_channel, zip[id].callback); +} + +void zip_set_cdb_len(int id, int cdb_len) +{ + zip[id].cdb_len = cdb_len; +} + +void zip_reset_cdb_len(int id) +{ + zip[id].cdb_len = zip[id].cdb_len_setting ? 16 : 12; +} + +void zip_set_signature(int id) +{ + if (id >= ZIP_NUM) + return; + zip[id].phase = 1; + zip[id].request_length = 0xEB14; +} + +void zip_init(int id, int cdb_len_setting) +{ + if (id >= ZIP_NUM) + return; + memset(&(zip[id]), 0, sizeof(zip_t)); + zip[id].requested_blocks = 1; + if (cdb_len_setting <= 1) + zip[id].cdb_len_setting = cdb_len_setting; + zip_reset_cdb_len(id); + zip[id].sense[0] = 0xf0; + zip[id].sense[7] = 10; + zip_drives[id].bus_mode = 0; + if (zip_drives[id].bus_type >= ZIP_BUS_ATAPI_PIO_AND_DMA) + zip_drives[id].bus_mode |= 2; + if (zip_drives[id].bus_type < ZIP_BUS_SCSI) + zip_drives[id].bus_mode |= 1; + zip_log("ZIP %i: Bus type %i, bus mode %i\n", id, zip_drives[id].bus_type, zip_drives[id].bus_mode); + if (zip_drives[id].bus_type < ZIP_BUS_SCSI) + zip_set_signature(id); + zip_drives[id].max_blocks_at_once = 85; + zip[id].status = READY_STAT | DSC_STAT; + zip[id].pos = 0; + zip[id].packet_status = 0xff; + zip_sense_key = zip_asc = zip_ascq = zip[id].unit_attention = 0; + zip[id].cdb_len_setting = 0; + zip[id].cdb_len = 12; +} + +int zip_supports_pio(int id) +{ + return (zip_drives[id].bus_mode & 1); +} + +int zip_supports_dma(int id) +{ + return (zip_drives[id].bus_mode & 2); +} + +/* Returns: 0 for none, 1 for PIO, 2 for DMA. */ +int zip_current_mode(int id) +{ + if (!zip_supports_pio(id) && !zip_supports_dma(id)) + return 0; + if (zip_supports_pio(id) && !zip_supports_dma(id)) { + zip_log("ZIP %i: Drive does not support DMA, setting to PIO\n", id); + return 1; + } + if (!zip_supports_pio(id) && zip_supports_dma(id)) + return 2; + if (zip_supports_pio(id) && zip_supports_dma(id)) { + zip_log("ZIP %i: Drive supports both, setting to %s\n", id, (zip[id].features & 1) ? "DMA" : "PIO", id); + return (zip[id].features & 1) ? 2 : 1; + } + + return 0; +} + +/* Translates ATAPI status (ERR_STAT flag) to SCSI status. */ +int zip_ZIP_PHASE_to_scsi(uint8_t id) +{ + if (zip[id].status & ERR_STAT) + return SCSI_STATUS_CHECK_CONDITION; + else + return SCSI_STATUS_OK; +} + +/* Translates ATAPI phase (DRQ, I/O, C/D) to SCSI phase (MSG, C/D, I/O). */ +int zip_atapi_phase_to_scsi(uint8_t id) +{ + if (zip[id].status & 8) { + switch (zip[id].phase & 3) { + case 0: + return 0; + case 1: + return 2; + case 2: + return 1; + case 3: + return 7; + } + } else { + if ((zip[id].phase & 3) == 3) + return 3; + else + return 4; + } + + return 0; +} + +int zip_lba_to_msf_accurate(int lba) +{ + int temp_pos; + int m, s, f; + + temp_pos = lba + 150; + f = temp_pos % 75; + temp_pos -= f; + temp_pos /= 75; + s = temp_pos % 60; + temp_pos -= s; + temp_pos /= 60; + m = temp_pos; + + return ((m << 16) | (s << 8) | f); +} + +void zip_mode_sense_load(uint8_t id) +{ + FILE *f; + wchar_t file_name[512]; + int i; + memset(&zip_mode_sense_pages_saved[id], 0, sizeof(mode_sense_pages_t)); + for (i = 0; i < 0x3f; i++) { + if (zip_drives[id].is_250) { + if (zip_250_mode_sense_pages_default.pages[i][1] != 0) { + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) + memcpy(zip_mode_sense_pages_saved[id].pages[i], zip_250_mode_sense_pages_default_scsi.pages[i], zip_250_mode_sense_pages_default_scsi.pages[i][1] + 2); + else + memcpy(zip_mode_sense_pages_saved[id].pages[i], zip_250_mode_sense_pages_default.pages[i], zip_250_mode_sense_pages_default.pages[i][1] + 2); + } + } else { + if (zip_mode_sense_pages_default.pages[i][1] != 0) { + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) + memcpy(zip_mode_sense_pages_saved[id].pages[i], zip_mode_sense_pages_default_scsi.pages[i], zip_mode_sense_pages_default_scsi.pages[i][1] + 2); + else + memcpy(zip_mode_sense_pages_saved[id].pages[i], zip_mode_sense_pages_default.pages[i], zip_mode_sense_pages_default.pages[i][1] + 2); + } + } + } + memset(file_name, 0, 512 * sizeof(wchar_t)); + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) + swprintf(file_name, 512, L"scsi_zip_%02i_mode_sense_bin", id); + else + swprintf(file_name, 512, L"zip_%02i_mode_sense_bin", id); + f = plat_fopen(nvr_path(file_name), L"rb"); + if (f) + fclose(f); +} + +void zip_mode_sense_save(uint8_t id) +{ + FILE *f; + wchar_t file_name[512]; + memset(file_name, 0, 512 * sizeof(wchar_t)); + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) + swprintf(file_name, 512, L"scsi_zip_%02i_mode_sense_bin", id); + else + swprintf(file_name, 512, L"zip_%02i_mode_sense_bin", id); + f = plat_fopen(nvr_path(file_name), L"wb"); + if (f) + fclose(f); +} + +static void zip_command_complete(uint8_t id); + +uint8_t zip_read_capacity_cdb[12] = {0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +int zip_read_capacity(uint8_t id, uint8_t *cdb, uint8_t *buffer, uint32_t *len) +{ + int size = 0; + + if (zip_drives[id].is_250) + size = zip_drives[id].medium_size - 1; /* IMPORTANT: What's returned is the last LBA block. */ + else + size = ZIP_SECTORS - 1; /* IMPORTANT: What's returned is the last LBA block. */ + memset(buffer, 0, 8); + buffer[0] = (size >> 24) & 0xff; + buffer[1] = (size >> 16) & 0xff; + buffer[2] = (size >> 8) & 0xff; + buffer[3] = size & 0xff; + buffer[6] = 2; /* 512 = 0x0200 */ + *len = 8; + + return 1; +} + +/*SCSI Mode Sense 6/10*/ +uint8_t zip_mode_sense_read(uint8_t id, uint8_t page_control, uint8_t page, uint8_t pos) +{ + switch (page_control) { + case 0: + case 3: + if (zip_drives[id].is_250 && (page == 5) && (pos == 9) && (zip_drives[id].medium_size == ZIP_SECTORS)) + return 0x60; + return zip_mode_sense_pages_saved[id].pages[page][pos]; + break; + case 1: + if (zip_drives[id].is_250) + return zip_250_mode_sense_pages_changeable.pages[page][pos]; + else + return zip_mode_sense_pages_changeable.pages[page][pos]; + break; + case 2: + if (zip_drives[id].is_250) { + if ((page == 5) && (pos == 9) && (zip_drives[id].medium_size == ZIP_SECTORS)) + return 0x60; + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) + return zip_250_mode_sense_pages_default_scsi.pages[page][pos]; + else + return zip_250_mode_sense_pages_default.pages[page][pos]; + } else { + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) + return zip_mode_sense_pages_default_scsi.pages[page][pos]; + else + return zip_mode_sense_pages_default.pages[page][pos]; + } + break; + } + + return 0; +} + +uint32_t zip_mode_sense(uint8_t id, uint8_t *buf, uint32_t pos, uint8_t type, uint8_t block_descriptor_len) +{ + uint64_t page_flags; + uint8_t page_control = (type >> 6) & 3; + + if (zip_drives[id].is_250) + page_flags = zip_250_mode_sense_page_flags; + else + page_flags = zip_mode_sense_page_flags; + + int i = 0; + int j = 0; + + uint8_t msplen; + + type &= 0x3f; + + if (block_descriptor_len) { + if (zip_drives[id].is_250) { + buf[pos++] = ((zip_drives[id].medium_size >> 24) & 0xff); + buf[pos++] = ((zip_drives[id].medium_size >> 16) & 0xff); + buf[pos++] = ((zip_drives[id].medium_size >> 8) & 0xff); + buf[pos++] = ( zip_drives[id].medium_size & 0xff); + } else { + buf[pos++] = ((ZIP_SECTORS >> 24) & 0xff); + buf[pos++] = ((ZIP_SECTORS >> 16) & 0xff); + buf[pos++] = ((ZIP_SECTORS >> 8) & 0xff); + buf[pos++] = ( ZIP_SECTORS & 0xff); + } + buf[pos++] = 0; /* Reserved. */ + buf[pos++] = 0; /* Block length (0x200 = 512 bytes). */ + buf[pos++] = 2; + buf[pos++] = 0; + } + + for (i = 0; i < 0x40; i++) { + if ((type == GPMODE_ALL_PAGES) || (type == i)) { + if (page_flags & (1LL << zip[id].current_page_code)) { + buf[pos++] = zip_mode_sense_read(id, page_control, i, 0); + msplen = zip_mode_sense_read(id, page_control, i, 1); + buf[pos++] = msplen; + zip_log("ZIP %i: MODE SENSE: Page [%02X] length %i\n", id, i, msplen); + for (j = 0; j < msplen; j++) + buf[pos++] = zip_mode_sense_read(id, page_control, i, 2 + j); + } + } + } + + return pos; +} + +void zip_update_request_length(uint8_t id, int len, int block_len) +{ + uint32_t bt; + + if (!zip[id].request_length) + zip[id].max_transfer_len = 65534; + else + zip[id].max_transfer_len = zip[id].request_length; + + /* For media access commands, make sure the requested DRQ length matches the block length. */ + switch (zip[id].current_cdb[0]) { + case 0x08: + case 0x28: + case 0xa8: + if (zip[id].max_transfer_len < block_len) + zip[id].max_transfer_len = block_len; + bt = (zip[id].requested_blocks * block_len); + if (len > bt) + len = bt; + default: + zip[id].packet_len = len; + break; + } + /* If the DRQ length is odd, and the total remaining length is bigger, make sure it's even. */ + if ((zip[id].max_transfer_len & 1) && (zip[id].max_transfer_len < len)) + zip[id].max_transfer_len &= 0xfffe; + /* If the DRQ length is smaller or equal in size to the total remaining length, set it to that. */ + if (len <= zip[id].max_transfer_len) + zip[id].max_transfer_len = len; + return; +} + +static void zip_command_common(uint8_t id) +{ + double bytes_per_second, period; + double dusec; + + bytes_per_second = 0.0; + zip[id].status = BUSY_STAT; + zip[id].phase = 1; + zip[id].pos = 0; + if (zip[id].packet_status == ZIP_PHASE_COMPLETE) { + zip_phase_callback(id); + zip[id].callback = 0LL; + } else { + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { + zip[id].callback = -1LL; /* Speed depends on SCSI controller */ + return; + } else if (zip_drives[id].bus_type == ZIP_BUS_ATAPI_PIO_AND_DMA) { + if (zip_current_mode(id) == 2) + bytes_per_second = 66666666.666666666666666; /* 66 MB/s MDMA-2 speed */ + else + bytes_per_second = 8333333.333333333333333; /* 8.3 MB/s PIO-2 speed */ + } else + bytes_per_second = 3333333.333333333333333; /* 3.3 MB/s PIO-0 speed */ + + } + + period = 1000000.0 / bytes_per_second; + dusec = (double) TIMER_USEC; + dusec = dusec * period * (double) (zip[id].packet_len); + zip[id].callback = ((int64_t) dusec); + + zip_set_callback(id); +} + +static void zip_command_complete(uint8_t id) +{ + zip[id].packet_status = ZIP_PHASE_COMPLETE; + zip_command_common(id); +} + +static void zip_command_read(uint8_t id) +{ + zip[id].packet_status = ZIP_PHASE_DATA_IN; + zip_command_common(id); + zip[id].total_read = 0; +} + +static void zip_command_read_dma(uint8_t id) +{ + zip[id].packet_status = ZIP_PHASE_DATA_IN_DMA; + zip_command_common(id); + zip[id].total_read = 0; +} + +static void zip_command_write(uint8_t id) +{ + zip[id].packet_status = ZIP_PHASE_DATA_OUT; + zip_command_common(id); +} + +static void zip_command_write_dma(uint8_t id) +{ + zip[id].packet_status = ZIP_PHASE_DATA_OUT_DMA; + zip_command_common(id); +} + +/* 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 zip_data_command_finish(uint8_t id, int len, int block_len, int alloc_len, int direction) +{ + zip_log("ZIP %i: Finishing command (%02X): %i, %i, %i, %i, %i\n", id, zip[id].current_cdb[0], len, block_len, alloc_len, direction, zip[id].request_length); + zip[id].pos=0; + if (alloc_len >= 0) { + if (alloc_len < len) { + len = alloc_len; + } + } + + if ((len == 0) || (zip_current_mode(id) == 0)) { + if (zip_drives[id].bus_type != ZIP_BUS_SCSI) { + zip[id].packet_len = 0; + } + zip_command_complete(id); + } + else { + if (zip_current_mode(id) == 2) { + if (zip_drives[id].bus_type != ZIP_BUS_SCSI) { + zip[id].packet_len = alloc_len; + } + + if (direction == 0) + zip_command_read_dma(id); + else + zip_command_write_dma(id); + } + else { + zip_update_request_length(id, len, block_len); + if (direction == 0) + zip_command_read(id); + else + zip_command_write(id); + } + } + + zip_log("ZIP %i: Status: %i, cylinder %i, packet length: %i, position: %i, phase: %i\n", id, zip[id].packet_status, zip[id].request_length, zip[id].packet_len, zip[id].pos, zip[id].phase); +} + +static void zip_sense_clear(int id, int command) +{ + zip[id].previous_command = command; + zip_sense_key = zip_asc = zip_ascq = 0; +} + +static void zip_set_phase(uint8_t id, uint8_t phase) +{ + uint8_t scsi_id = zip_drives[id].scsi_device_id; + uint8_t scsi_lun = zip_drives[id].scsi_device_lun; + + if (zip_drives[id].bus_type != ZIP_BUS_SCSI) + return; + + SCSIDevices[scsi_id][scsi_lun].Phase = phase; +} + +static void zip_cmd_error(uint8_t id) +{ + zip_set_phase(id, SCSI_PHASE_STATUS); + zip[id].error = ((zip_sense_key & 0xf) << 4) | ABRT_ERR; + if (zip[id].unit_attention) + zip[id].error |= MCR_ERR; + zip[id].status = READY_STAT | ERR_STAT; + zip[id].phase = 3; + zip[id].pos = 0; + zip[id].packet_status = 0x80; + zip[id].callback = 50LL * ZIP_TIME; + zip_set_callback(id); + zip_log("ZIP %i: [%02X] ERROR: %02X/%02X/%02X\n", id, zip[id].current_cdb[0], zip_sense_key, zip_asc, zip_ascq); +} + +static void zip_unit_attention(uint8_t id) +{ + zip_set_phase(id, SCSI_PHASE_STATUS); + zip[id].error = (SENSE_UNIT_ATTENTION << 4) | ABRT_ERR; + if (zip[id].unit_attention) + zip[id].error |= MCR_ERR; + zip[id].status = READY_STAT | ERR_STAT; + zip[id].phase = 3; + zip[id].pos = 0; + zip[id].packet_status = 0x80; + zip[id].callback = 50LL * ZIP_TIME; + zip_set_callback(id); + zip_log("ZIP %i: UNIT ATTENTION\n", id); +} + +static void zip_bus_master_error(uint8_t id) +{ + zip_sense_key = zip_asc = zip_ascq = 0; + zip_cmd_error(id); +} + +static void zip_not_ready(uint8_t id) +{ + zip_sense_key = SENSE_NOT_READY; + zip_asc = ASC_MEDIUM_NOT_PRESENT; + zip_ascq = 0; + zip_cmd_error(id); +} + +static void zip_write_protected(uint8_t id) +{ + zip_sense_key = SENSE_UNIT_ATTENTION; + zip_asc = ASC_WRITE_PROTECTED; + zip_ascq = 0; + zip_cmd_error(id); +} + +static void zip_invalid_lun(uint8_t id) +{ + zip_sense_key = SENSE_ILLEGAL_REQUEST; + zip_asc = ASC_INV_LUN; + zip_ascq = 0; + zip_cmd_error(id); +} + +static void zip_illegal_opcode(uint8_t id) +{ + zip_sense_key = SENSE_ILLEGAL_REQUEST; + zip_asc = ASC_ILLEGAL_OPCODE; + zip_ascq = 0; + zip_cmd_error(id); +} + +static void zip_lba_out_of_range(uint8_t id) +{ + zip_sense_key = SENSE_ILLEGAL_REQUEST; + zip_asc = ASC_LBA_OUT_OF_RANGE; + zip_ascq = 0; + zip_cmd_error(id); +} + +static void zip_invalid_field(uint8_t id) +{ + zip_sense_key = SENSE_ILLEGAL_REQUEST; + zip_asc = ASC_INV_FIELD_IN_CMD_PACKET; + zip_ascq = 0; + zip_cmd_error(id); + zip[id].status = 0x53; +} + +static void zip_invalid_field_pl(uint8_t id) +{ + zip_sense_key = SENSE_ILLEGAL_REQUEST; + zip_asc = ASC_INV_FIELD_IN_PARAMETER_LIST; + zip_ascq = 0; + zip_cmd_error(id); + zip[id].status = 0x53; +} + +static void zip_data_phase_error(uint8_t id) +{ + zip_sense_key = SENSE_ILLEGAL_REQUEST; + zip_asc = ASC_DATA_PHASE_ERROR; + zip_ascq = 0; + zip_cmd_error(id); +} + +#define zipbufferb zip[id].buffer + +int zip_data(uint8_t id, uint32_t *len, int out) +{ + int i = 0; + + if (zip[id].sector_pos >= zip_drives[id].medium_size) { + zip_log("ZIP %i: Trying to %s beyond the end of disk\n", id, out ? "write" : "read"); + zip_lba_out_of_range(id); + return 0; + } + + *len = 0; + + for (i = 0; i < zip[id].requested_blocks; i++) { + fseek(zip_drives[id].f, zip_drives[id].base + (zip[id].sector_pos << 9) + *len, SEEK_SET); + if (out) + fwrite(zipbufferb + *len, 1, 512, zip_drives[id].f); + else + fread(zipbufferb + *len, 1, 512, zip_drives[id].f); + + *len += 512; + } + + return 1; +} + +int zip_blocks(uint8_t id, uint32_t *len, int first_batch, int out) +{ + int ret = 0; + + zip[id].data_pos = 0; + + if (!zip[id].sector_len) { + zip_command_complete(id); + return -1; + } + + zip_log("%sing %i blocks starting from %i...\n", out ? "Writ" : "Read", zip[id].requested_blocks, zip[id].sector_pos); + + ret = zip_data(id, len, out); + + zip_log("%s %i bytes of blocks...\n", out ? "Written" : "Read", *len); + + if (!ret) + return 0; + + zip[id].sector_pos += zip[id].requested_blocks; + zip[id].sector_len -= zip[id].requested_blocks; + + return 1; +} + +void zip_insert(uint8_t id) +{ + zip[id].unit_attention = 1; +} + +/*SCSI Sense Initialization*/ +void zip_sense_code_ok(uint8_t id) +{ + zip_sense_key = SENSE_NONE; + zip_asc = 0; + zip_ascq = 0; +} + +int zip_pre_execution_check(uint8_t id, uint8_t *cdb) +{ + int ready = 0; + + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { + if (((zip[id].request_length >> 5) & 7) != zip_drives[id].scsi_device_lun) { + zip_log("ZIP %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", id, ((zip[id].request_length >> 5) & 7)); + zip_invalid_lun(id); + return 0; + } + } + + if (!(zip_command_flags[cdb[0]] & IMPLEMENTED)) { + zip_log("ZIP %i: Attempting to execute unknown command %02X over %s\n", id, cdb[0], (zip_drives[id].bus_type == ZIP_BUS_SCSI) ? "SCSI" : ((zip_drives[id].bus_type == ZIP_BUS_ATAPI_PIO_AND_DMA) ? "ATAPI PIO/DMA" : "ATAPI PIO")); + + zip_illegal_opcode(id); + return 0; + } + + if ((zip_drives[id].bus_type < ZIP_BUS_SCSI) && (zip_command_flags[cdb[0]] & SCSI_ONLY)) { + zip_log("ZIP %i: Attempting to execute SCSI-only command %02X over ATAPI\n", id, cdb[0]); + zip_illegal_opcode(id); + return 0; + } + + if ((zip_drives[id].bus_type == ZIP_BUS_SCSI) && (zip_command_flags[cdb[0]] & ATAPI_ONLY)) { + zip_log("ZIP %i: Attempting to execute ATAPI-only command %02X over SCSI\n", id, cdb[0]); + zip_illegal_opcode(id); + return 0; + } + + ready = (zip_drives[id].f != NULL); + + /* If the drive is not ready, there is no reason to keep the + UNIT ATTENTION condition present, as we only use it to mark + disc changes. */ + if (!ready && zip[id].unit_attention) + zip[id].unit_attention = 0; + + /* If the UNIT ATTENTION condition is set and the command does not allow + execution under it, error out and report the condition. */ + if (zip[id].unit_attention == 1) { + /* Only increment the unit attention phase if the command can not pass through it. */ + if (!(zip_command_flags[cdb[0]] & ALLOW_UA)) { + /* zip_log("ZIP %i: Unit attention now 2\n", id); */ + zip[id].unit_attention = 2; + zip_log("ZIP %i: UNIT ATTENTION: Command %02X not allowed to pass through\n", id, cdb[0]); + zip_unit_attention(id); + return 0; + } + } + else if (zip[id].unit_attention == 2) { + if (cdb[0] != GPCMD_REQUEST_SENSE) { + /* zip_log("ZIP %i: Unit attention now 0\n", id); */ + zip[id].unit_attention = 0; + } + } + + /* Unless the command is REQUEST SENSE, clear the sense. This will *NOT* + the UNIT ATTENTION condition if it's set. */ + if (cdb[0] != GPCMD_REQUEST_SENSE) + zip_sense_clear(id, cdb[0]); + + /* Next it's time for NOT READY. */ + if (!ready) + zip[id].media_status = MEC_MEDIA_REMOVAL; + else + zip[id].media_status = (zip[id].unit_attention) ? MEC_NEW_MEDIA : MEC_NO_CHANGE; + + if ((zip_command_flags[cdb[0]] & CHECK_READY) && !ready) { + zip_log("ZIP %i: Not ready (%02X)\n", id, cdb[0]); + zip_not_ready(id); + return 0; + } + + zip_log("ZIP %i: Continuing with command %02X\n", id, cdb[0]); + + return 1; +} + +void zip_clear_callback(uint8_t channel) +{ + uint8_t id = atapi_zip_drives[channel]; + + if (id < ZIP_NUM) + { + zip[id].callback = 0LL; + zip_set_callback(id); + } +} + +static void zip_seek(uint8_t id, uint32_t pos) +{ + /* zip_log("ZIP %i: Seek %08X\n", id, pos); */ + zip[id].sector_pos = pos; +} + +static void zip_rezero(uint8_t id) +{ + zip[id].sector_pos = zip[id].sector_len = 0; + zip_seek(id, 0); +} + +void zip_reset(uint8_t id) +{ + zip_rezero(id); + zip[id].status = 0; + zip[id].callback = 0LL; + zip_set_callback(id); + zip[id].packet_status = 0xff; + zip[id].unit_attention = 0; +} + +void zip_request_sense(uint8_t id, uint8_t *buffer, uint8_t alloc_length, int desc) +{ + /*Will return 18 bytes of 0*/ + if (alloc_length != 0) { + memset(buffer, 0, alloc_length); + if (!desc) + memcpy(buffer, zip[id].sense, alloc_length); + else { + buffer[1] = zip_sense_key; + buffer[2] = zip_asc; + buffer[3] = zip_ascq; + } + } + + buffer[0] = desc ? 0x72 : 0x70; + + if (zip[id].unit_attention && (zip_sense_key == 0)) { + buffer[desc ? 1 : 2]=SENSE_UNIT_ATTENTION; + buffer[desc ? 2 : 12]=ASC_MEDIUM_MAY_HAVE_CHANGED; + buffer[desc ? 3 : 13]=0; + } + + zip_log("ZIP %i: Reporting sense: %02X %02X %02X\n", id, buffer[2], buffer[12], buffer[13]); + + if (buffer[desc ? 1 : 2] == SENSE_UNIT_ATTENTION) { + /* If the last remaining sense is unit attention, clear + that condition. */ + zip[id].unit_attention = 0; + } + + /* Clear the sense stuff as per the spec. */ + zip_sense_clear(id, GPCMD_REQUEST_SENSE); +} + +void zip_request_sense_for_scsi(uint8_t id, uint8_t *buffer, uint8_t alloc_length) +{ + int ready = 0; + + ready = (zip_drives[id].f != NULL); + + if (!ready && zip[id].unit_attention) { + /* If the drive is not ready, there is no reason to keep the + UNIT ATTENTION condition present, as we only use it to mark + disc changes. */ + zip[id].unit_attention = 0; + } + + /* Do *NOT* advance the unit attention phase. */ + + zip_request_sense(id, buffer, alloc_length, 0); +} + +void zip_set_buf_len(uint8_t id, int32_t *BufLen, uint32_t *src_len) +{ + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { + if (*BufLen == -1) + *BufLen = *src_len; + else { + *BufLen = MIN(*src_len, *BufLen); + *src_len = *BufLen; + } + zip_log("ZIP %i: Actual transfer length: %i\n", id, *BufLen); + } +} + +void zip_buf_alloc(uint8_t id, uint32_t len) +{ + zip_log("ZIP %i: Allocated buffer length: %i\n", id, len); + zipbufferb = (uint8_t *) malloc(len); +} + +void zip_buf_free(uint8_t id) +{ + if (zipbufferb) { + zip_log("ZIP %i: Freeing buffer...\n", id); + free(zipbufferb); + zipbufferb = NULL; + } +} + +void zip_command(uint8_t id, uint8_t *cdb) +{ + uint32_t len; + int pos=0; + uint32_t max_len; + unsigned idx = 0; + unsigned size_idx; + unsigned preamble_len; + uint32_t alloc_length; + int block_desc = 0; + int ret; + int32_t blen = 0; + int32_t *BufLen; + uint32_t i = 0; + + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { + BufLen = &SCSIDevices[zip_drives[id].scsi_device_id][zip_drives[id].scsi_device_lun].BufferLength; + zip[id].status &= ~ERR_STAT; + } else { + BufLen = &blen; + zip[id].error = 0; + } + + zip[id].packet_len = 0; + zip[id].request_pos = 0; + + zip[id].data_pos = 0; + + memcpy(zip[id].current_cdb, cdb, zip[id].cdb_len); + + if (cdb[0] != 0) { + zip_log("ZIP %i: Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X, Unit attention: %i\n", id, cdb[0], zip_sense_key, zip_asc, zip_ascq, zip[id].unit_attention); + zip_log("ZIP %i: Request length: %04X\n", id, zip[id].request_length); + + zip_log("ZIP %i: CDB: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", 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]); + } + + zip[id].sector_len = 0; + + zip_set_phase(id, SCSI_PHASE_STATUS); + + /* This handles the Not Ready/Unit Attention check if it has to be handled at this point. */ + if (zip_pre_execution_check(id, cdb) == 0) + return; + + switch (cdb[0]) { + case GPCMD_SEND_DIAGNOSTIC: + if (!(cdb[1] & (1 << 2))) { + zip_invalid_field(id); + return; + } + case GPCMD_SCSI_RESERVE: + case GPCMD_SCSI_RELEASE: + case GPCMD_TEST_UNIT_READY: + zip_set_phase(id, SCSI_PHASE_STATUS); + zip_command_complete(id); + break; + + case GPCMD_FORMAT_UNIT: + if ((zip_drives[id].bus_type == ZIP_BUS_SCSI) && zip_drives[id].read_only) + { + zip_write_protected(id); + return; + } + + zip_set_phase(id, SCSI_PHASE_STATUS); + zip_command_complete(id); + break; + + case GPCMD_IOMEGA_SENSE: + zip_set_phase(id, SCSI_PHASE_DATA_IN); + max_len = cdb[4]; + zip_buf_alloc(id, 256); + zip_set_buf_len(id, BufLen, &max_len); + memset(zipbufferb, 0, 256); + if (cdb[2] == 1) { + /* This page is related to disk health status - setting + this page to 0 makes disk health read as "marginal". */ + zipbufferb[0] = 0x58; + zipbufferb[1] = 0x00; + for (i = 0x00; i < 0x58; i++) + zipbufferb[i + 0x02] = 0xff; + } else if (cdb[2] == 2) { + zipbufferb[0] = 0x3d; + zipbufferb[1] = 0x00; + for (i = 0x00; i < 0x13; i++) + zipbufferb[i + 0x02] = 0x00; + zipbufferb[0x15] = 0x00; + if (zip_drives[id].read_only) + zipbufferb[0x15] |= 0x02; + for (i = 0x00; i < 0x27; i++) + zipbufferb[i + 0x16] = 0x00; + } else { + zip_invalid_field(id); + zip_buf_free(id); + return; + } + zip_data_command_finish(id, 18, 18, cdb[4], 0); + break; + + case GPCMD_REZERO_UNIT: + zip[id].sector_pos = zip[id].sector_len = 0; + zip_seek(id, 0); + zip_set_phase(id, SCSI_PHASE_STATUS); + 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. */ + zip_set_phase(id, SCSI_PHASE_DATA_IN); + max_len = cdb[4]; + zip_buf_alloc(id, 256); + zip_set_buf_len(id, BufLen, &max_len); + len = (cdb[1] & 1) ? 8 : 18; + zip_request_sense(id, zipbufferb, max_len, cdb[1] & 1); + zip_data_command_finish(id, len, len, cdb[4], 0); + break; + + case GPCMD_SET_SPEED: + case GPCMD_SET_SPEED_ALT: + zip_set_phase(id, SCSI_PHASE_STATUS); + zip_command_complete(id); + break; + + case GPCMD_MECHANISM_STATUS: + zip_set_phase(id, SCSI_PHASE_DATA_IN); + len = (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + + zip_buf_alloc(id, 8); + + zip_set_buf_len(id, BufLen, &len); + + memset(zipbufferb, 0, 8); + zipbufferb[5] = 1; + + zip_data_command_finish(id, 8, 8, len, 0); + break; + + case GPCMD_READ_6: + case GPCMD_READ_10: + case GPCMD_READ_12: + zip_set_phase(id, SCSI_PHASE_DATA_IN); + alloc_length = 512; + + switch(cdb[0]) { + case GPCMD_READ_6: + zip[id].sector_len = cdb[4]; + zip[id].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", id, zip[id].sector_len, zip[id].sector_pos); + break; + case GPCMD_READ_10: + zip[id].sector_len = (cdb[7] << 8) | cdb[8]; + zip[id].sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + zip_log("ZIP %i: Length: %i, LBA: %i\n", id, zip[id].sector_len, zip[id].sector_pos); + break; + case GPCMD_READ_12: + zip[id].sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + zip[id].sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); + break; + } + + if (!zip[id].sector_len) { + zip_set_phase(id, SCSI_PHASE_STATUS); + /* zip_log("ZIP %i: All done - callback set\n", id); */ + zip[id].packet_status = ZIP_PHASE_COMPLETE; + zip[id].callback = 20LL * ZIP_TIME; + zip_set_callback(id); + break; + } + + max_len = zip[id].sector_len; + zip[id].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. */ + + zip[id].packet_len = max_len * alloc_length; + zip_buf_alloc(id, zip[id].packet_len); + + ret = zip_blocks(id, &alloc_length, 1, 0); + if (ret <= 0) { + zip_buf_free(id); + return; + } + + zip[id].requested_blocks = max_len; + zip[id].packet_len = alloc_length; + + zip_set_buf_len(id, BufLen, &zip[id].packet_len); + + zip_data_command_finish(id, alloc_length, 512, alloc_length, 0); + + zip[id].all_blocks_total = zip[id].block_total; + if (zip[id].packet_status != ZIP_PHASE_COMPLETE) + ui_sb_update_icon(SB_ZIP | id, 1); + else + ui_sb_update_icon(SB_ZIP | id, 0); + return; + + case GPCMD_VERIFY_6: + case GPCMD_VERIFY_10: + case GPCMD_VERIFY_12: + if (!(cdb[1] & 2)) { + zip_set_phase(id, SCSI_PHASE_STATUS); + zip_command_complete(id); + break; + } + case GPCMD_WRITE_6: + case GPCMD_WRITE_10: + case GPCMD_WRITE_AND_VERIFY_10: + case GPCMD_WRITE_12: + case GPCMD_WRITE_AND_VERIFY_12: + zip_set_phase(id, SCSI_PHASE_DATA_OUT); + alloc_length = 512; + + if ((zip_drives[id].bus_type == ZIP_BUS_SCSI) && zip_drives[id].read_only) + { + zip_write_protected(id); + return; + } + + switch(cdb[0]) { + case GPCMD_VERIFY_6: + case GPCMD_WRITE_6: + zip[id].sector_len = cdb[4]; + zip[id].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: + case GPCMD_WRITE_AND_VERIFY_10: + zip[id].sector_len = (cdb[7] << 8) | cdb[8]; + zip[id].sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + zip_log("ZIP %i: Length: %i, LBA: %i\n", id, zip[id].sector_len, zip[id].sector_pos); + break; + case GPCMD_VERIFY_12: + case GPCMD_WRITE_12: + case GPCMD_WRITE_AND_VERIFY_12: + zip[id].sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + zip[id].sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); + break; + } + + if (zip_drives[id].is_250) { + if ((zip[id].sector_pos >= zip_drives[id].medium_size) || ((zip[id].sector_pos + zip[id].sector_len - 1) >= zip_drives[id].medium_size)) + { + zip_lba_out_of_range(id); + return; + } + } else { + if ((zip[id].sector_pos >= ZIP_SECTORS) || ((zip[id].sector_pos + zip[id].sector_len - 1) >= ZIP_SECTORS)) + { + zip_lba_out_of_range(id); + return; + } + } + + if (!zip[id].sector_len) { + zip_set_phase(id, SCSI_PHASE_STATUS); + /* zip_log("ZIP %i: All done - callback set\n", id); */ + zip[id].packet_status = ZIP_PHASE_COMPLETE; + zip[id].callback = 20LL * ZIP_TIME; + zip_set_callback(id); + break; + } + + max_len = zip[id].sector_len; + zip[id].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. */ + + zip[id].packet_len = max_len * alloc_length; + zip_buf_alloc(id, zip[id].packet_len); + + zip[id].requested_blocks = max_len; + zip[id].packet_len = max_len << 9; + + zip_set_buf_len(id, BufLen, &zip[id].packet_len); + + zip_data_command_finish(id, zip[id].packet_len, 512, zip[id].packet_len, 1); + + zip[id].all_blocks_total = zip[id].block_total; + if (zip[id].packet_status != ZIP_PHASE_COMPLETE) + ui_sb_update_icon(SB_ZIP | id, 1); + else + ui_sb_update_icon(SB_ZIP | id, 0); + return; + + case GPCMD_WRITE_SAME_10: + zip_set_phase(id, SCSI_PHASE_DATA_OUT); + alloc_length = 512; + + if ((cdb[1] & 6) == 6) + { + zip_invalid_field(id); + return; + } + + if ((zip_drives[id].bus_type == ZIP_BUS_SCSI) && zip_drives[id].read_only) + { + zip_write_protected(id); + return; + } + + zip[id].sector_len = (cdb[7] << 8) | cdb[8]; + zip[id].sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + + if (zip_drives[id].is_250) { + if ((zip[id].sector_pos >= zip_drives[id].medium_size) || ((zip[id].sector_pos + zip[id].sector_len - 1) >= zip_drives[id].medium_size)) + { + zip_lba_out_of_range(id); + return; + } + } else { + if ((zip[id].sector_pos >= ZIP_SECTORS) || ((zip[id].sector_pos + zip[id].sector_len - 1) >= ZIP_SECTORS)) + { + zip_lba_out_of_range(id); + return; + } + } + + if (!zip[id].sector_len) { + zip_set_phase(id, SCSI_PHASE_STATUS); + /* zip_log("ZIP %i: All done - callback set\n", id); */ + zip[id].packet_status = ZIP_PHASE_COMPLETE; + zip[id].callback = 20LL * ZIP_TIME; + zip_set_callback(id); + break; + } + + max_len = zip[id].sector_len; + zip[id].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. */ + + zip[id].packet_len = max_len * alloc_length; + zip_buf_alloc(id, zip[id].packet_len); + + zip[id].requested_blocks = max_len; + zip[id].packet_len = alloc_length; + + zip_set_buf_len(id, BufLen, &zip[id].packet_len); + + zip_data_command_finish(id, zip[id].packet_len, 512, zip[id].packet_len, 1); + + zip[id].all_blocks_total = zip[id].block_total; + if (zip[id].packet_status != ZIP_PHASE_COMPLETE) + ui_sb_update_icon(SB_ZIP | id, 1); + else + ui_sb_update_icon(SB_ZIP | id, 0); + return; + + case GPCMD_MODE_SENSE_6: + case GPCMD_MODE_SENSE_10: + zip_set_phase(id, SCSI_PHASE_DATA_IN); + + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) + block_desc = ((cdb[1] >> 3) & 1) ? 0 : 1; + else + block_desc = 0; + + if (cdb[0] == GPCMD_MODE_SENSE_6) { + len = cdb[4]; + zip_buf_alloc(id, 256); + } else { + len = (cdb[8] | (cdb[7] << 8)); + zip_buf_alloc(id, 65536); + } + + zip[id].current_page_code = cdb[2] & 0x3F; + zip_log("Mode sense page: %02X\n", zip[id].current_page_code); + + if (!(zip_mode_sense_page_flags & (1LL << zip[id].current_page_code))) { + zip_invalid_field(id); + zip_buf_free(id); + return; + } + + memset(zipbufferb, 0, len); + alloc_length = len; + + if (cdb[0] == GPCMD_MODE_SENSE_6) { + len = zip_mode_sense(id, zipbufferb, 4, cdb[2], block_desc); + len = MIN(len, alloc_length); + zipbufferb[0] = len - 1; + zipbufferb[1] = 0; + if (block_desc) + zipbufferb[3] = 8; + } else { + len = zip_mode_sense(id, zipbufferb, 8, cdb[2], block_desc); + len = MIN(len, alloc_length); + zipbufferb[0]=(len - 2) >> 8; + zipbufferb[1]=(len - 2) & 255; + zipbufferb[2] = 0; + if (block_desc) { + zipbufferb[6] = 0; + zipbufferb[7] = 8; + } + } + + zip_set_buf_len(id, BufLen, &len); + + zip_log("ZIP %i: Reading mode page: %02X...\n", id, cdb[2]); + + zip_data_command_finish(id, len, len, alloc_length, 0); + return; + + case GPCMD_MODE_SELECT_6: + case GPCMD_MODE_SELECT_10: + zip_set_phase(id, SCSI_PHASE_DATA_OUT); + + if (cdb[0] == GPCMD_MODE_SELECT_6) { + len = cdb[4]; + zip_buf_alloc(id, 256); + } else { + len = (cdb[7] << 8) | cdb[8]; + zip_buf_alloc(id, 65536); + } + + zip_set_buf_len(id, BufLen, &len); + + zip[id].total_length = len; + zip[id].do_page_save = cdb[1] & 1; + + zip[id].current_page_pos = 0; + + zip_data_command_finish(id, len, len, len, 1); + return; + + case GPCMD_START_STOP_UNIT: + zip_set_phase(id, SCSI_PHASE_STATUS); + + switch(cdb[4] & 3) { + case 0: /* Stop the disc. */ + zip_eject(id); /* The Iomega Windows 9x drivers require this. */ + break; + case 1: /* Start the disc and read the TOC. */ + break; + case 2: /* Eject the disc if possible. */ + /* zip_eject(id); */ + break; + case 3: /* Load the disc (close tray). */ + zip_reload(id); + break; + } + + zip_command_complete(id); + break; + + case GPCMD_INQUIRY: + zip_set_phase(id, SCSI_PHASE_DATA_IN); + + max_len = cdb[3]; + max_len <<= 8; + max_len |= cdb[4]; + + zip_buf_alloc(id, 65536); + + if (cdb[1] & 1) { + preamble_len = 4; + size_idx = 3; + + zipbufferb[idx++] = 05; + zipbufferb[idx++] = cdb[2]; + zipbufferb[idx++] = 0; + + idx++; + + switch (cdb[2]) { + case 0x00: + zipbufferb[idx++] = 0x00; + zipbufferb[idx++] = 0x83; + break; + case 0x83: + if (idx + 24 > max_len) { + zip_data_phase_error(id); + zip_buf_free(id); + return; + } + + zipbufferb[idx++] = 0x02; + zipbufferb[idx++] = 0x00; + zipbufferb[idx++] = 0x00; + zipbufferb[idx++] = 20; + ide_padstr8(zipbufferb + idx, 20, "53R141"); /* Serial */ + idx += 20; + + if (idx + 72 > cdb[4]) + goto atapi_out; + zipbufferb[idx++] = 0x02; + zipbufferb[idx++] = 0x01; + zipbufferb[idx++] = 0x00; + zipbufferb[idx++] = 68; + ide_padstr8(zipbufferb + idx, 8, "IOMEGA "); /* Vendor */ + idx += 8; + if (zip_drives[id].is_250) + ide_padstr8(zipbufferb + idx, 40, "ZIP 250 "); /* Product */ + else + ide_padstr8(zipbufferb + idx, 40, "ZIP 100 "); /* Product */ + idx += 40; + ide_padstr8(zipbufferb + idx, 20, "53R141"); /* Product */ + idx += 20; + break; + default: + zip_log("INQUIRY: Invalid page: %02X\n", cdb[2]); + zip_invalid_field(id); + zip_buf_free(id); + return; + } + } else { + preamble_len = 5; + size_idx = 4; + + memset(zipbufferb, 0, 8); + if (cdb[1] & 0xe0) + zipbufferb[0] = 0x60; /*No physical device on this LUN*/ + else + zipbufferb[0] = 0x00; /*Hard disk*/ + zipbufferb[1] = 0x80; /*Removable*/ + if (zip_drives[id].is_250) { + zipbufferb[2] = (zip_drives[id].bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x00; /*SCSI-2 compliant*/ + zipbufferb[3] = (zip_drives[id].bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x21; + } else { + zipbufferb[2] = (zip_drives[id].bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x00; /*SCSI-2 compliant*/ + zipbufferb[3] = (zip_drives[id].bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x21; + } + zipbufferb[4] = 31; + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { + zipbufferb[6] = 1; /* 16-bit transfers supported */ + zipbufferb[7] = 0x20; /* Wide bus supported */ + } + + ide_padstr8(zipbufferb + 8, 8, "IOMEGA "); /* Vendor */ + if (zip_drives[id].is_250) { + ide_padstr8(zipbufferb + 16, 16, "ZIP 250 "); /* Product */ + ide_padstr8(zipbufferb + 32, 4, "42.S"); /* Revision */ + if (max_len >= 44) + ide_padstr8(zipbufferb + 36, 8, "08/08/01"); /* Date? */ + if (max_len >= 122) + ide_padstr8(zipbufferb + 96, 26, "(c) Copyright IOMEGA 2000 "); /* Copyright string */ + + } else { + ide_padstr8(zipbufferb + 16, 16, "ZIP 100 "); /* Product */ + ide_padstr8(zipbufferb + 32, 4, "E.08"); /* Revision */ + } + idx = 36; + + if (max_len == 96) { + zipbufferb[4] = 91; + idx = 96; + } else if (max_len == 128) { + zipbufferb[4] = 0x75; + idx = 128; + } + } + +atapi_out: + zipbufferb[size_idx] = idx - preamble_len; + len=idx; + + len = MIN(len, max_len); + zip_set_buf_len(id, BufLen, &len); + + zip_data_command_finish(id, len, len, max_len, 0); + break; + + case GPCMD_PREVENT_REMOVAL: + zip_set_phase(id, SCSI_PHASE_STATUS); + zip_command_complete(id); + break; + + case GPCMD_SEEK_6: + case GPCMD_SEEK_10: + zip_set_phase(id, SCSI_PHASE_STATUS); + + switch(cdb[0]) { + case GPCMD_SEEK_6: + pos = (cdb[2] << 8) | cdb[3]; + break; + case GPCMD_SEEK_10: + pos = (cdb[2] << 24) | (cdb[3]<<16) | (cdb[4]<<8) | cdb[5]; + break; + } + zip_seek(id, pos); + zip_command_complete(id); + break; + + case GPCMD_READ_CDROM_CAPACITY: + zip_set_phase(id, SCSI_PHASE_DATA_IN); + + zip_buf_alloc(id, 8); + + if (zip_read_capacity(id, zip[id].current_cdb, zipbufferb, &len) == 0) { + zip_buf_free(id); + return; + } + + zip_set_buf_len(id, BufLen, &len); + + zip_data_command_finish(id, len, len, len, 0); + break; + + case GPCMD_IOMEGA_EJECT: + zip_set_phase(id, SCSI_PHASE_STATUS); + zip_eject(id); + zip_command_complete(id); + break; + + default: + zip_illegal_opcode(id); + break; + } + + /* zip_log("ZIP %i: Phase: %02X, request length: %i\n", zip[id].phase, zip[id].request_length); */ + + if (zip_atapi_phase_to_scsi(id) == SCSI_PHASE_STATUS) + zip_buf_free(id); +} + +/* The command second phase function, needed for Mode Select. */ +uint8_t zip_phase_data_out(uint8_t id) +{ + uint16_t block_desc_len; + uint16_t pos; + + uint8_t error = 0; + uint8_t page, page_len; + + uint16_t i = 0; + + uint8_t hdr_len, val, old_val, ch; + + uint32_t last_to_write = 0, len = 0; + uint32_t c, h, s; + + switch(zip[id].current_cdb[0]) { + case GPCMD_VERIFY_6: + case GPCMD_VERIFY_10: + case GPCMD_VERIFY_12: + break; + case GPCMD_WRITE_6: + case GPCMD_WRITE_10: + case GPCMD_WRITE_AND_VERIFY_10: + case GPCMD_WRITE_12: + case GPCMD_WRITE_AND_VERIFY_12: + if (zip[id].requested_blocks > 0) + zip_blocks(id, &len, 1, 1); + break; + case GPCMD_WRITE_SAME_10: + if (!zip[id].current_cdb[7] && !zip[id].current_cdb[8]) { + if (zip_drives[id].is_250) + last_to_write = (zip_drives[id].medium_size - 1); + else + last_to_write = (ZIP_SECTORS - 1); + } else + last_to_write = zip[id].sector_pos + zip[id].sector_len - 1; + + for (i = zip[id].sector_pos; i <= last_to_write; i++) { + if (zip[id].current_cdb[1] & 2) { + zipbufferb[0] = (i >> 24) & 0xff; + zipbufferb[1] = (i >> 16) & 0xff; + zipbufferb[2] = (i >> 8) & 0xff; + zipbufferb[3] = i & 0xff; + } else if (zip[id].current_cdb[1] & 4) { + /* CHS are 96,1,2048 (ZIP 100) and 239,1,2048 (ZIP 250) */ + s = (i % 2048); + h = ((i - s) / 2048) % 1; + c = ((i - s) / 2048) / 1; + zipbufferb[0] = (c >> 16) & 0xff; + zipbufferb[1] = (c >> 8) & 0xff; + zipbufferb[2] = c & 0xff; + zipbufferb[3] = h & 0xff; + zipbufferb[4] = (s >> 24) & 0xff; + zipbufferb[5] = (s >> 16) & 0xff; + zipbufferb[6] = (s >> 8) & 0xff; + zipbufferb[7] = s & 0xff; + } + fseek(zip_drives[id].f, zip_drives[id].base + (i << 9), SEEK_SET); + fwrite(zipbufferb, 1, 512, zip_drives[id].f); + } + break; + case GPCMD_MODE_SELECT_6: + case GPCMD_MODE_SELECT_10: + if (zip[id].current_cdb[0] == GPCMD_MODE_SELECT_10) + hdr_len = 8; + else + hdr_len = 4; + + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { + if (zip[id].current_cdb[0] == GPCMD_MODE_SELECT_6) { + block_desc_len = zipbufferb[2]; + block_desc_len <<= 8; + block_desc_len |= zipbufferb[3]; + } else { + block_desc_len = zipbufferb[6]; + block_desc_len <<= 8; + block_desc_len |= zipbufferb[7]; + } + } else + block_desc_len = 0; + + pos = hdr_len + block_desc_len; + + while(1) { + page = zipbufferb[pos] & 0x3F; + page_len = zipbufferb[pos + 1]; + + pos += 2; + + if (!(zip_mode_sense_page_flags & (1LL << ((uint64_t) page)))) + error |= 1; + else { + for (i = 0; i < page_len; i++) { + ch = zip_mode_sense_pages_changeable.pages[page][i + 2]; + val = zipbufferb[pos + i]; + old_val = zip_mode_sense_pages_saved[id].pages[page][i + 2]; + if (val != old_val) { + if (ch) + zip_mode_sense_pages_saved[id].pages[page][i + 2] = val; + else + error |= 1; + } + } + } + + pos += page_len; + + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) + val = zip_mode_sense_pages_default_scsi.pages[page][0] & 0x80; + else + val = zip_mode_sense_pages_default.pages[page][0] & 0x80; + if (zip[id].do_page_save && val) + zip_mode_sense_save(id); + + if (pos >= zip[id].total_length) + break; + } + + if (error) { + zip_invalid_field_pl(id); + return 0; + } + break; + } + + return 1; +} + +/* This is the general ATAPI PIO request function. */ +void zip_pio_request(uint8_t id, uint8_t out) +{ + int old_pos = 0; + int ret = 0; + + if (zip_drives[id].bus_type < ZIP_BUS_SCSI) { + zip_log("ZIP %i: Lowering IDE IRQ\n", id); + ide_irq_lower(&(ide_drives[zip_drives[id].ide_channel])); + } + + zip[id].status = BUSY_STAT; + + if (zip[id].pos >= zip[id].packet_len) { + zip_log("ZIP %i: %i bytes %s, command done\n", id, zip[id].pos, out ? "written" : "read"); + + zip[id].pos = zip[id].request_pos = 0; + if (out) { + ret = zip_phase_data_out(id); + /* If ret = 0 (phase 1 error), then we do not do anything else other than + free the buffer, as the phase and callback have already been set by the + error function. */ + if (ret) + zip_command_complete(id); + } else + zip_command_complete(id); + ui_sb_update_icon(SB_ZIP | id, 0); + zip_buf_free(id); + } else { + zip_log("ZIP %i: %i bytes %s, %i bytes are still left\n", id, zip[id].pos, out ? "written" : "read", zip[id].packet_len - zip[id].pos); + + /* Make sure to keep pos, and reset request_pos to 0. */ + /* Also make sure to not reset total_read. */ + + /* If less than (packet length) bytes are remaining, update packet length + accordingly. */ + if ((zip[id].packet_len - zip[id].pos) < (zip[id].max_transfer_len)) + zip[id].max_transfer_len = zip[id].packet_len - zip[id].pos; + + old_pos = zip[id].pos; + zip[id].packet_status = out ? ZIP_PHASE_DATA_OUT : ZIP_PHASE_DATA_IN; + zip_command_common(id); + zip[id].pos = old_pos; + zip[id].request_pos = 0; + } +} + +void zip_phase_callback(uint8_t id); + +int zip_read_from_ide_dma(uint8_t channel) +{ + uint8_t id = atapi_zip_drives[channel]; + + if (id > ZIP_NUM) + return 0; + + if (ide_bus_master_write) { + if (ide_bus_master_write(channel >> 1, zipbufferb, zip[id].packet_len)) { + zip_bus_master_error(id); + zip_phase_callback(id); + return 0; + } else + return 1; + } else { + zip_bus_master_error(id); + zip_phase_callback(id); + return 0; + } + + return 0; +} + +int zip_read_from_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun) +{ + uint8_t id = scsi_zip_drives[scsi_id][scsi_lun]; + int32_t *BufLen = &SCSIDevices[scsi_id][scsi_lun].BufferLength; + + if (id > ZIP_NUM) + return 0; + + zip_log("Reading from SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, *BufLen); + memcpy(zipbufferb, SCSIDevices[scsi_id][scsi_lun].CmdBuffer, *BufLen); + return 1; +} + +int zip_read_from_dma(uint8_t id) +{ + int32_t *BufLen = &SCSIDevices[zip_drives[id].scsi_device_id][zip_drives[id].scsi_device_lun].BufferLength; + + int ret = 0; + + int in_data_length = 0; + + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) + ret = zip_read_from_scsi_dma(zip_drives[id].scsi_device_id, zip_drives[id].scsi_device_lun); + else + ret = zip_read_from_ide_dma(zip_drives[id].ide_channel); + + if (!ret) + return 0; + + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { + in_data_length = *BufLen; + zip_log("ZIP %i: SCSI Input data length: %i\n", id, in_data_length); + } else { + in_data_length = zip[id].max_transfer_len; + zip_log("ZIP %i: ATAPI Input data length: %i\n", id, in_data_length); + } + + ret = zip_phase_data_out(id); + if (!ret) { + zip_phase_callback(id); + return 0; + } else + return 1; + + return 0; +} + +int zip_write_to_ide_dma(uint8_t channel) +{ + uint8_t id = atapi_zip_drives[channel]; + + if (id > ZIP_NUM) { + zip_log("ZIP %i: Drive not found\n", id); + return 0; + } + + if (ide_bus_master_read) { + if (ide_bus_master_read(channel >> 1, zipbufferb, zip[id].packet_len)) { + zip_log("ZIP %i: ATAPI DMA error\n", id); + zip_bus_master_error(id); + zip_phase_callback(id); + return 0; + } + else { + zip_log("ZIP %i: ATAPI DMA success\n", id); + return 1; + } + } else { + zip_log("ZIP %i: No bus master\n", id); + zip_bus_master_error(id); + zip_phase_callback(id); + return 0; + } + + return 0; +} + +int zip_write_to_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun) +{ + uint8_t id = scsi_zip_drives[scsi_id][scsi_lun]; + int32_t *BufLen = &SCSIDevices[scsi_id][scsi_lun].BufferLength; + + if (id > ZIP_NUM) + return 0; + + zip_log("Writing to SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, *BufLen); + memcpy(SCSIDevices[scsi_id][scsi_lun].CmdBuffer, zipbufferb, *BufLen); + zip_log("ZIP %i: Data from CD buffer: %02X %02X %02X %02X %02X %02X %02X %02X\n", id, zipbufferb[0], zipbufferb[1], zipbufferb[2], zipbufferb[3], zipbufferb[4], zipbufferb[5], zipbufferb[6], zipbufferb[7]); + zip_log("ZIP %i: Data from SCSI DMA : %02X %02X %02X %02X %02X %02X %02X %02X\n", id, SCSIDevices[scsi_id][scsi_lun].CmdBuffer[0], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[1], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[2], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[3], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[4], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[5], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[6], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[7]); + return 1; +} + +int zip_write_to_dma(uint8_t id) +{ + int ret = 0; + + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { + zip_log("Write to SCSI DMA: (%02X:%02X)\n", zip_drives[id].scsi_device_id, zip_drives[id].scsi_device_lun); + ret = zip_write_to_scsi_dma(zip_drives[id].scsi_device_id, zip_drives[id].scsi_device_lun); + } else + ret = zip_write_to_ide_dma(zip_drives[id].ide_channel); + + if (!ret) + return 0; + + return 1; +} + +void zip_irq_raise(uint8_t id) +{ + if (zip_drives[id].bus_type < ZIP_BUS_SCSI) + ide_irq_raise(&(ide_drives[zip_drives[id].ide_channel])); +} + +/* If the result is 1, issue an IRQ, otherwise not. */ +void zip_phase_callback(uint8_t id) +{ + switch(zip[id].packet_status) { + case ZIP_PHASE_IDLE: + zip_log("ZIP %i: ZIP_PHASE_IDLE\n", id); + zip[id].pos=0; + zip[id].phase = 1; + zip[id].status = READY_STAT | DRQ_STAT | (zip[id].status & ERR_STAT); + return; + case ZIP_PHASE_COMMAND: + zip_log("ZIP %i: ZIP_PHASE_COMMAND\n", id); + zip[id].status = BUSY_STAT | (zip[id].status &ERR_STAT); + memcpy(zip[id].atapi_cdb, zipbufferb, zip[id].cdb_len); + zip_command(id, zip[id].atapi_cdb); + return; + case ZIP_PHASE_COMPLETE: + zip_log("ZIP %i: ZIP_PHASE_COMPLETE\n", id); + zip[id].status = READY_STAT; + zip[id].phase = 3; + zip[id].packet_status = 0xFF; + ui_sb_update_icon(SB_ZIP | id, 0); + zip_irq_raise(id); + return; + case ZIP_PHASE_DATA_OUT: + zip_log("ZIP %i: ZIP_PHASE_DATA_OUT\n", id); + zip[id].status = READY_STAT | DRQ_STAT | (zip[id].status & ERR_STAT); + zip[id].phase = 0; + zip_irq_raise(id); + return; + case ZIP_PHASE_DATA_OUT_DMA: + zip_log("ZIP %i: ZIP_PHASE_DATA_OUT_DMA\n", id); + zip_read_from_dma(id); + zip_buf_free(id); + zip[id].packet_status = ZIP_PHASE_COMPLETE; + zip[id].status = READY_STAT; + zip[id].phase = 3; + ui_sb_update_icon(SB_ZIP | id, 0); + zip_irq_raise(id); + return; + case ZIP_PHASE_DATA_IN: + zip_log("ZIP %i: ZIP_PHASE_DATA_IN\n", id); + zip[id].status = READY_STAT | DRQ_STAT | (zip[id].status & ERR_STAT); + zip[id].phase = 2; + zip_irq_raise(id); + return; + case ZIP_PHASE_DATA_IN_DMA: + zip_log("ZIP %i: ZIP_PHASE_DATA_IN_DMA\n", id); + zip_write_to_dma(id); + zip_buf_free(id); + zip[id].packet_status = ZIP_PHASE_COMPLETE; + zip[id].status = READY_STAT; + zip[id].phase = 3; + ui_sb_update_icon(SB_ZIP | id, 0); + zip_irq_raise(id); + return; + case ZIP_PHASE_ERROR: + zip_log("ZIP %i: ZIP_PHASE_ERROR\n", id); + zip[id].status = READY_STAT | ERR_STAT; + zip[id].phase = 3; + zip_irq_raise(id); + ui_sb_update_icon(SB_ZIP | id, 0); + return; + } +} + +/* Reimplement as 8-bit due to reimplementation of IDE data read and write. */ +uint32_t zip_read(uint8_t channel, int length) +{ + uint16_t *zipbufferw; + uint32_t *zipbufferl; + + uint8_t id = atapi_zip_drives[channel]; + + uint32_t temp = 0; + + if (id > ZIP_NUM) + return 0; + + zipbufferw = (uint16_t *) zipbufferb; + zipbufferl = (uint32_t *) zipbufferb; + + if (!zipbufferb) + return 0; + + /* 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 = 512 bytes). */ + switch(length) { + case 1: + temp = (zip[id].pos < zip[id].packet_len) ? zipbufferb[zip[id].pos] : 0; + zip[id].pos++; + zip[id].request_pos++; + break; + case 2: + temp = (zip[id].pos < zip[id].packet_len) ? zipbufferw[zip[id].pos >> 1] : 0; + zip[id].pos += 2; + zip[id].request_pos += 2; + break; + case 4: + temp = (zip[id].pos < zip[id].packet_len) ? zipbufferl[zip[id].pos >> 2] : 0; + zip[id].pos += 4; + zip[id].request_pos += 4; + break; + default: + return 0; + } + + if (zip[id].packet_status == ZIP_PHASE_DATA_IN) { + if ((zip[id].request_pos >= zip[id].max_transfer_len) || (zip[id].pos >= zip[id].packet_len)) { + /* Time for a DRQ. */ + // zip_log("ZIP %i: Issuing read callback\n", id); + zip_pio_request(id, 0); + } + // zip_log("ZIP %i: Returning: %02X (buffer position: %i, request position: %i)\n", id, temp, zip[id].pos, zip[id].request_pos); + return temp; + } else { + // zip_log("ZIP %i: Returning zero (buffer position: %i, request position: %i)\n", id, zip[id].pos, zip[id].request_pos); + return 0; + } +} + +/* Reimplement as 8-bit due to reimplementation of IDE data read and write. */ +void zip_write(uint8_t channel, uint32_t val, int length) +{ + uint16_t *zipbufferw; + uint32_t *zipbufferl; + + uint8_t id = atapi_zip_drives[channel]; + + if (id > ZIP_NUM) + return; + + if (zip[id].packet_status == ZIP_PHASE_IDLE) { + if (!zipbufferb) + zip_buf_alloc(id, zip[id].cdb_len); + } + + zipbufferw = (uint16_t *) zipbufferb; + zipbufferl = (uint32_t *) zipbufferb; + + if (!zipbufferb) + return; + + switch(length) { + case 1: + zipbufferb[zip[id].pos] = val & 0xff; + zip[id].pos++; + zip[id].request_pos++; + break; + case 2: + zipbufferw[zip[id].pos >> 1] = val & 0xffff; + zip[id].pos += 2; + zip[id].request_pos += 2; + break; + case 4: + zipbufferl[zip[id].pos >> 2] = val; + zip[id].pos += 4; + zip[id].request_pos += 4; + break; + default: + return; + } + + if (zip[id].packet_status == ZIP_PHASE_DATA_OUT) { + if ((zip[id].request_pos >= zip[id].max_transfer_len) || (zip[id].pos >= zip[id].packet_len)) { + /* Time for a DRQ. */ + zip_pio_request(id, 1); + } + return; + } else if (zip[id].packet_status == ZIP_PHASE_IDLE) { + if (zip[id].pos >= zip[id].cdb_len) { + zip[id].pos=0; + zip[id].status = BUSY_STAT; + zip[id].packet_status = ZIP_PHASE_COMMAND; + timer_process(); + zip_phase_callback(id); + timer_update_outstanding(); + } + return; + } +} + +void zip_hard_reset(void) +{ + int i = 0; + + for (i=0; i * Sarah Walker, @@ -541,11 +541,13 @@ double fdd_real_period(int drive) return (32.0 * dusec); } +#if defined(DEV_BRANCH) && defined(USE_MRTHOR) if (romset == ROM_MRTHOR) { return (ddbp * dusec) / 4.0; } else +#endif { return (ddbp * dusec); } diff --git a/src/floppy/fdd_86f.c b/src/floppy/fdd_86f.c index 544b8bf..1644416 100644 --- a/src/floppy/fdd_86f.c +++ b/src/floppy/fdd_86f.c @@ -10,7 +10,7 @@ * data in the form of FM/MFM-encoded transitions) which also * forms the core of the emulator's floppy disk emulation. * - * Version: @(#)fdd_86f.c 1.0.1 2018/02/14 + * Version: @(#)fdd_86f.c 1.0.2 2018/03/08 * * Author: Miran Grca, * @@ -3408,6 +3408,7 @@ int d86f_export(int drive, wchar_t *fn) int tracks = 86; int i; + int inc = 1; uint32_t magic = 0x46423638; uint16_t version = 0x020B; @@ -3430,13 +3431,17 @@ int d86f_export(int drive, wchar_t *fn) fwrite(tt, 1, ((d86f_get_sides(drive) == 2) ? 2048 : 1024), f); - /* Do this do teremine how many tracks to actually output. */ - fdd_do_seek(drive, 2); - if (d86f[drive].cur_track == 1) - tracks >>= 1; + /* In the case of a thick track drive, always increment track + by two, since two tracks are going to get output at once. */ + if (!fdd_doublestep_40(drive)) + inc = 2; - for (i = 0; i < tracks; i++) { - fdd_do_seek(drive, i); + for (i = 0; i < tracks; i += inc) { + if (inc == 2) + fdd_do_seek(drive, i >> 1); + else + fdd_do_seek(drive, i); + d86f[drive].cur_track = i; d86f_write_tracks(drive, &f, tt); } diff --git a/src/lang/language.h b/src/lang/language.h index 3e6084e..5255fa2 100644 --- a/src/lang/language.h +++ b/src/lang/language.h @@ -10,7 +10,7 @@ * * NOTE: FIXME: Strings 2176 and 2193 are same. * - * Version: @(#)language.h 1.0.3 2018/03/01 + * Version: @(#)language.h 1.0.4 2018/03/08 * * Author: Fred N. van Kempen, * @@ -182,6 +182,7 @@ #define IDS_2176 2176 // "ZIP images (*.IM?)\0*.IM..." #define IDS_2177 2177 // "ZIP %i (%03i): %ls" #define IDS_2178 2178 // "Unable to initialize OpenAL.." +#define IDS_2179 2179 // "Speed" #define IDS_4096 4096 // "Hard disk (%s)" #define IDS_4097 4097 // "%01i:%01i" @@ -262,7 +263,7 @@ #define IDS_LANG_ENUS IDS_7168 -#define STR_NUM_2048 131 +#define STR_NUM_2048 132 #define STR_NUM_3072 11 #define STR_NUM_4096 20 #define STR_NUM_4352 7 diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 385d49d..a0fc2f3 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -11,7 +11,7 @@ * NOTES: OpenAT wip for 286-class machine with open BIOS. * PS2_M80-486 wip, pending receipt of TRM's for machine. * - * Version: @(#)machine_table.c 1.0.5 2018/03/05 + * Version: @(#)machine_table.c 1.0.6 2018/03/08 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -146,7 +146,9 @@ machine_t machines[] = { { "[Socket 5 FX] President Award 430FX PCI",ROM_PRESIDENT, "president", L"president/president", {{"Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_president_init, NULL, nvr_at_close }, { "[Socket 7 FX] Intel Advanced/ATX", ROM_THOR, "thor", L"intel/thor", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_thor_init, NULL, nvr_at_close }, +#if defined(DEV_BRANCH) && defined(USE_MRTHOR) { "[Socket 7 FX] MR Intel Advanced/ATX", ROM_MRTHOR, "mrthor", L"intel/mrthor", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_thor_init, NULL, nvr_at_close }, +#endif { "[Socket 7 HX] Acer M3a", ROM_ACERM3A, "acerm3a", L"acer/acerm3a", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_acerm3a_init, NULL, nvr_at_close }, { "[Socket 7 HX] Acer V35n", ROM_ACERV35N, "acerv35n", L"acer/acerv35n", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_acerv35n_init, NULL, nvr_at_close }, @@ -167,7 +169,9 @@ machine_t machines[] = { { "[Socket 5 FX] President Award 430FX PCI",ROM_PRESIDENT, "president", L"president/president", {{"Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_president_init, NULL, nvr_at_close }, { "[Socket 7 FX] Intel Advanced/ATX", ROM_THOR, "thor", L"intel/thor", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_thor_init, NULL, nvr_at_close }, +#if defined(DEV_BRANCH) && defined(USE_MRTHOR) { "[Socket 7 FX] MR Intel Advanced/ATX", ROM_MRTHOR, "mrthor", L"intel/mrthor", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_thor_init, NULL, nvr_at_close }, +#endif { "[Socket 7 HX] Acer M3a", ROM_ACERM3A, "acerm3a", L"acer/acerm3a", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_acerm3a_init, NULL, nvr_at_close }, { "[Socket 7 HX] Acer V35n", ROM_ACERV35N, "acerv35n", L"acer/acerv35n", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_acerv35n_init, NULL, nvr_at_close }, diff --git a/src/pc.c b/src/pc.c index d1d2d64..485d5f3 100644 --- a/src/pc.c +++ b/src/pc.c @@ -296,7 +296,9 @@ fatal(const char *fmt, ...) void pc_version(const char *platform) { +#if defined(BUILD) || defined(COMMIT) || defined(UPSTREAM) char temp[128]; +#endif sprintf(emu_title, "%s for %s", EMU_NAME, platform); diff --git a/src/rom.h b/src/rom.h index b7009df..733c729 100644 --- a/src/rom.h +++ b/src/rom.h @@ -8,7 +8,7 @@ * * Definitions for the ROM image handler. * - * Version: @(#)rom.h 1.0.4 2018/03/04 + * Version: @(#)rom.h 1.0.5 2018/03/08 * * Authors: Fred N. van Kempen, * @@ -181,7 +181,9 @@ enum { ROM_PRESIDENT, /* President Award 430FX PCI/430FX/Award/Unknown SIO */ ROM_THOR, /* Intel Advanced_ATX/430FX/AMI/NS PC87306 */ +#if defined(DEV_BRANCH) && defined(USE_MRTHOR) ROM_MRTHOR, /* Intel Advanced_ATX/430FX/MR.BIOS/NS PC87306 */ +#endif ROM_ACERM3A, /* Acer M3A/430HX/Acer/SMC FDC37C932FR */ ROM_ACERV35N, /* Acer V35N/430HX/Acer/SMC FDC37C932FR */ diff --git a/src/scsi/scsi_aha154x.c b/src/scsi/scsi_aha154x.c index 0fd82a7..56b6e10 100644 --- a/src/scsi/scsi_aha154x.c +++ b/src/scsi/scsi_aha154x.c @@ -10,7 +10,7 @@ * made by Adaptec, Inc. These controllers were designed for * the ISA bus. * - * Version: @(#)scsi_aha154x.c 1.0.3 2018/03/03 + * Version: @(#)scsi_aha154x.c 1.0.4 2018/03/08 * * Based on original code from TheCollector1995 and Miran Grca. * @@ -290,10 +290,7 @@ aha_fast_cmds(void *p, uint8_t cmd) x54x_t *dev = (x54x_t *)p; if (cmd == CMD_BIOS_SCSI) { - x54x_busy(1); dev->BIOSMailboxReq++; - x54x_set_wait_event(); - x54x_busy(0); return 1; } @@ -385,7 +382,6 @@ aha_cmds(void *p) case CMD_BIOS_MBINIT: /* BIOS Mailbox Initialization */ /* Sent by CF BIOS. */ - x54x_busy(1); dev->Mbx24bit = 1; mbi = (MailboxInit_t *)dev->CmdBuf; @@ -401,7 +397,6 @@ aha_cmds(void *p) dev->Status &= ~STAT_INIT; dev->DataReplyLeft = 0; - x54x_busy(0); break; case CMD_MEMORY_MAP_1: /* AHA memory mapper */ @@ -490,16 +485,12 @@ aha_do_bios_mail(x54x_t *dev) static void -aha_thread(void *p) +aha_callback(void *p) { x54x_t *dev = (x54x_t *)p; if (dev->BIOSMailboxInit && dev->BIOSMailboxReq) - { - x54x_wait_for_poll(); - aha_do_bios_mail(dev); - } } @@ -750,14 +741,11 @@ aha_setnvr(x54x_t *dev) memset(dev->nvr, 0x00, NVR_SIZE); f = nvr_fopen(dev->nvr_path, L"rb"); - if (f) - { + if (f != NULL) { fread(dev->nvr, 1, NVR_SIZE, f); fclose(f); f = NULL; - } - else - { + } else { aha_initnvr(dev); } } @@ -791,7 +779,7 @@ aha_init(device_t *info) dev->bit32 = 0; dev->lba_bios = 0; - dev->ven_thread = aha_thread; + dev->ven_callback = aha_callback; dev->ven_cmd_is_fast = aha_cmd_is_fast; dev->ven_fast_cmds = aha_fast_cmds; dev->get_ven_param_len = aha_param_len; @@ -819,6 +807,7 @@ aha_init(device_t *info) dev->HostID = device_get_config_int("hostid"); dev->rom_shram = 0x3F80; /* shadow RAM address base */ dev->rom_shramsz = 128; /* size of shadow RAM */ + dev->ha_bps = 5000000.0; /* normal SCSI */ break; case AHA_154xC: @@ -833,6 +822,7 @@ aha_init(device_t *info) dev->ven_get_host_id = aha_get_host_id; /* function to return host ID from EEPROM */ dev->ven_get_irq = aha_get_irq; /* function to return IRQ from EEPROM */ dev->ven_get_dma = aha_get_dma; /* function to return DMA channel from EEPROM */ + dev->ha_bps = 5000000.0; /* normal SCSI */ break; case AHA_154xCF: @@ -848,6 +838,7 @@ aha_init(device_t *info) dev->ven_get_host_id = aha_get_host_id; /* function to return host ID from EEPROM */ dev->ven_get_irq = aha_get_irq; /* function to return IRQ from EEPROM */ dev->ven_get_dma = aha_get_dma; /* function to return DMA channel from EEPROM */ + dev->ha_bps = 10000000.0; /* fast SCSI */ break; case AHA_154xCP: @@ -862,6 +853,7 @@ aha_init(device_t *info) dev->ven_get_host_id = aha_get_host_id; /* function to return host ID from EEPROM */ dev->ven_get_irq = aha_get_irq; /* function to return IRQ from EEPROM */ dev->ven_get_dma = aha_get_dma; /* function to return DMA channel from EEPROM */ + dev->ha_bps = 10000000.0; /* fast SCSI */ break; case AHA_1640: @@ -875,6 +867,7 @@ aha_init(device_t *info) dev->pos_regs[0] = 0x1F; /* MCA board ID */ dev->pos_regs[1] = 0x0F; mca_add(aha_mca_read, aha_mca_write, dev); + dev->ha_bps = 5000000.0; /* normal SCSI */ break; } diff --git a/src/scsi/scsi_buslogic.c b/src/scsi/scsi_buslogic.c index e083f04..e62c0d8 100644 --- a/src/scsi/scsi_buslogic.c +++ b/src/scsi/scsi_buslogic.c @@ -13,7 +13,7 @@ * 1 - BT-545S ISA; * 2 - BT-958D PCI * - * Version: @(#)scsi_buslogic.c 1.0.4 2018/02/26 + * Version: @(#)scsi_buslogic.c 1.0.5 2018/03/08 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -739,7 +739,6 @@ buslogic_cmds(void *p) dev->IrqEnabled = 1; return 1; case 0x81: - x54x_busy(1); dev->Mbx24bit = 0; MailboxInitE = (MailboxInitExtended_t *)dev->CmdBuf; @@ -756,7 +755,6 @@ buslogic_cmds(void *p) dev->Status &= ~STAT_INIT; dev->DataReplyLeft = 0; - x54x_busy(0); break; case 0x83: if (dev->CmdParam == 12) { @@ -1548,6 +1546,7 @@ buslogic_init(device_t *info) has_autoscsi_rom = 0; has_scam_rom = 0; dev->fw_rev = "AA335"; + dev->ha_bps = 5000000.0; /* normal SCSI */ break; case CHIP_BUSLOGIC_ISA: default: @@ -1560,6 +1559,7 @@ buslogic_init(device_t *info) autoscsi_rom_size = 0x4000; has_scam_rom = 0; dev->fw_rev = "AA421E"; + dev->ha_bps = 10000000.0; /* fast SCSI */ break; case CHIP_BUSLOGIC_MCA: strcpy(dev->name, "BT-640A"); @@ -1573,6 +1573,7 @@ buslogic_init(device_t *info) dev->pos_regs[0] = 0x08; /* MCA board ID */ dev->pos_regs[1] = 0x07; mca_add(buslogic_mca_read, buslogic_mca_write, dev); + dev->ha_bps = 5000000.0; /* normal SCSI */ break; case CHIP_BUSLOGIC_VLB: strcpy(dev->name, "BT-445S"); @@ -1585,6 +1586,7 @@ buslogic_init(device_t *info) has_scam_rom = 0; dev->fw_rev = "AA421E"; dev->bit32 = 1; + dev->ha_bps = 10000000.0; /* fast SCSI */ break; case CHIP_BUSLOGIC_PCI: strcpy(dev->name, "BT-958D"); @@ -1600,6 +1602,7 @@ buslogic_init(device_t *info) dev->fw_rev = "AA507B"; dev->cdrom_boot = 1; dev->bit32 = 1; + dev->ha_bps = 20000000.0; /* ultra SCSI */ break; } diff --git a/src/scsi/scsi_device.c b/src/scsi/scsi_device.c index 835f507..5a272c9 100644 --- a/src/scsi/scsi_device.c +++ b/src/scsi/scsi_device.c @@ -8,7 +8,7 @@ * * The generic SCSI device command handler. * - * Version: @(#)scsi_device.c 1.0.2 2018/02/24 + * Version: @(#)scsi_device.c 1.0.3 2018/03/08 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -47,131 +47,133 @@ #include "scsi_disk.h" -static uint8_t scsi_null_device_sense[14] = { 0x70,0,SENSE_ILLEGAL_REQUEST,0,0,0,0,0,0,0,0,0,ASC_INV_LUN,0 }; +static uint8_t scsi_null_device_sense[14] = { + 0x70,0,SENSE_ILLEGAL_REQUEST,0,0,0,0,0,0,0,0,0,ASC_INV_LUN,0 +}; -static uint8_t scsi_device_target_command(int lun_type, uint8_t id, uint8_t *cdb) +static uint8_t +scsi_device_target_command(int lun_type, uint8_t id, uint8_t *cdb) { - if (lun_type == SCSI_DISK) - { - scsi_hd_command(id, cdb); - return scsi_hd_err_stat_to_scsi(id); - } - else if (lun_type == SCSI_CDROM) - { - cdrom_command(id, cdb); - return cdrom_CDROM_PHASE_to_scsi(id); - } - else if (lun_type == SCSI_ZIP) - { - zip_command(id, cdb); - return zip_ZIP_PHASE_to_scsi(id); - } - else - { - return SCSI_STATUS_CHECK_CONDITION; - } + if (lun_type == SCSI_DISK) { + scsi_hd_command(id, cdb); + return scsi_hd_err_stat_to_scsi(id); + } + else if (lun_type == SCSI_CDROM) { + cdrom_command(id, cdb); + return cdrom_CDROM_PHASE_to_scsi(id); + } + else if (lun_type == SCSI_ZIP) { + zip_command(id, cdb); + return zip_ZIP_PHASE_to_scsi(id); + } + + return SCSI_STATUS_CHECK_CONDITION; } -static void scsi_device_target_phase_callback(int lun_type, uint8_t id) +static void +scsi_device_target_phase_callback(int lun_type, uint8_t id) { - if (lun_type == SCSI_DISK) - { - scsi_hd_callback(id); - } - else if (lun_type == SCSI_CDROM) - { - cdrom_phase_callback(id); - } - else if (lun_type == SCSI_ZIP) - { - zip_phase_callback(id); - } - else - { - return; - } -} - - -static int scsi_device_target_err_stat_to_scsi(int lun_type, uint8_t id) -{ - if (lun_type == SCSI_DISK) - { - return scsi_hd_err_stat_to_scsi(id); - } - else if (lun_type == SCSI_CDROM) - { - return cdrom_CDROM_PHASE_to_scsi(id); - } - else if (lun_type == SCSI_ZIP) - { - return zip_ZIP_PHASE_to_scsi(id); - } - else - { - return SCSI_STATUS_CHECK_CONDITION; - } -} - - -static void scsi_device_target_save_cdb_byte(int lun_type, uint8_t id, uint8_t cdb_byte) -{ - if (lun_type == SCSI_DISK) - { - shdc[id].request_length = cdb_byte; - } - else if (lun_type == SCSI_CDROM) - { - cdrom[id].request_length = cdb_byte; - } - else if (lun_type == SCSI_ZIP) - { - zip[id].request_length = cdb_byte; - } - else - { - return; - } -} - - -uint8_t *scsi_device_sense(uint8_t scsi_id, uint8_t scsi_lun) -{ - uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; - - uint8_t id = 0; - - switch (lun_type) - { - case SCSI_DISK: - id = scsi_hard_disks[scsi_id][scsi_lun]; - return shdc[id].sense; - break; - case SCSI_CDROM: - id = scsi_cdrom_drives[scsi_id][scsi_lun]; - return cdrom[id].sense; - break; - case SCSI_ZIP: - id = scsi_zip_drives[scsi_id][scsi_lun]; - return zip[id].sense; - break; - default: - return scsi_null_device_sense; - break; + if (lun_type == SCSI_DISK) { + scsi_hd_callback(id); + } + else if (lun_type == SCSI_CDROM) { + cdrom_phase_callback(id); + } + else if (lun_type == SCSI_ZIP) { + zip_phase_callback(id); } } -void scsi_device_request_sense(uint8_t scsi_id, uint8_t scsi_lun, uint8_t *buffer, uint8_t alloc_length) +static int +scsi_device_target_err_stat_to_scsi(int lun_type, uint8_t id) +{ + if (lun_type == SCSI_DISK) { + return scsi_hd_err_stat_to_scsi(id); + } + else if (lun_type == SCSI_CDROM) { + return cdrom_CDROM_PHASE_to_scsi(id); + } + else if (lun_type == SCSI_ZIP) { + return zip_ZIP_PHASE_to_scsi(id); + } + + return SCSI_STATUS_CHECK_CONDITION; +} + + +static void +scsi_device_target_save_cdb_byte(int lun_type, uint8_t id, uint8_t cdb_byte) +{ + if (lun_type == SCSI_DISK) { + shdc[id].request_length = cdb_byte; + } + else if (lun_type == SCSI_CDROM) { + cdrom[id].request_length = cdb_byte; + } + else if (lun_type == SCSI_ZIP) { + zip[id].request_length = cdb_byte; + } +} + + +int64_t +scsi_device_get_callback(uint8_t scsi_id, uint8_t scsi_lun) { uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; - uint8_t id = 0; - switch (lun_type) - { + switch (lun_type) { + case SCSI_DISK: + id = scsi_hard_disks[scsi_id][scsi_lun]; + return shdc[id].callback; + case SCSI_CDROM: + id = scsi_cdrom_drives[scsi_id][scsi_lun]; + return cdrom[id].callback; + case SCSI_ZIP: + id = scsi_zip_drives[scsi_id][scsi_lun]; + return zip[id].callback; + default: + break; + } + + return -1LL; +} + + +uint8_t * +scsi_device_sense(uint8_t scsi_id, uint8_t scsi_lun) +{ + uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; + uint8_t id = 0; + + switch (lun_type) { + case SCSI_DISK: + id = scsi_hard_disks[scsi_id][scsi_lun]; + return shdc[id].sense; + case SCSI_CDROM: + id = scsi_cdrom_drives[scsi_id][scsi_lun]; + return cdrom[id].sense; + case SCSI_ZIP: + id = scsi_zip_drives[scsi_id][scsi_lun]; + return zip[id].sense; + default: + break; + } + + return scsi_null_device_sense; +} + + +void +scsi_device_request_sense(uint8_t scsi_id, uint8_t scsi_lun, uint8_t *buffer, uint8_t alloc_length) +{ + uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; + uint8_t id = 0; + + switch (lun_type) { case SCSI_DISK: id = scsi_hard_disks[scsi_id][scsi_lun]; scsi_hd_request_sense_for_scsi(id, buffer, alloc_length); @@ -191,14 +193,13 @@ void scsi_device_request_sense(uint8_t scsi_id, uint8_t scsi_lun, uint8_t *buffe } -void scsi_device_type_data(uint8_t scsi_id, uint8_t scsi_lun, uint8_t *type, uint8_t *rmb) +void +scsi_device_type_data(uint8_t scsi_id, uint8_t scsi_lun, uint8_t *type, uint8_t *rmb) { uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; - uint8_t id = 0; - switch (lun_type) - { + switch (lun_type) { case SCSI_DISK: id = scsi_hard_disks[scsi_id][scsi_lun]; *type = 0x00; @@ -219,14 +220,13 @@ void scsi_device_type_data(uint8_t scsi_id, uint8_t scsi_lun, uint8_t *type, uin } -int scsi_device_read_capacity(uint8_t scsi_id, uint8_t scsi_lun, uint8_t *cdb, uint8_t *buffer, uint32_t *len) +int +scsi_device_read_capacity(uint8_t scsi_id, uint8_t scsi_lun, uint8_t *cdb, uint8_t *buffer, uint32_t *len) { uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; - uint8_t id = 0; - switch (lun_type) - { + switch (lun_type) { case SCSI_DISK: id = scsi_hard_disks[scsi_id][scsi_lun]; return scsi_hd_read_capacity(id, cdb, buffer, len); @@ -237,33 +237,36 @@ int scsi_device_read_capacity(uint8_t scsi_id, uint8_t scsi_lun, uint8_t *cdb, u id = scsi_zip_drives[scsi_id][scsi_lun]; return zip_read_capacity(id, cdb, buffer, len); default: - return 0; + break; } + + return 0; } -int scsi_device_present(uint8_t scsi_id, uint8_t scsi_lun) +int +scsi_device_present(uint8_t scsi_id, uint8_t scsi_lun) { uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; - switch (lun_type) - { + switch (lun_type) { case SCSI_NONE: return 0; default: - return 1; + break; } + + return 1; } -int scsi_device_valid(uint8_t scsi_id, uint8_t scsi_lun) +int +scsi_device_valid(uint8_t scsi_id, uint8_t scsi_lun) { uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; - uint8_t id = 0; - switch (lun_type) - { + switch (lun_type) { case SCSI_DISK: id = scsi_hard_disks[scsi_id][scsi_lun]; break; @@ -282,14 +285,13 @@ int scsi_device_valid(uint8_t scsi_id, uint8_t scsi_lun) } -int scsi_device_cdb_length(uint8_t scsi_id, uint8_t scsi_lun) +int +scsi_device_cdb_length(uint8_t scsi_id, uint8_t scsi_lun) { uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; - uint8_t id = 0; - switch (lun_type) - { + switch (lun_type) { case SCSI_CDROM: id = scsi_cdrom_drives[scsi_id][scsi_lun]; return cdrom[id].cdb_len; @@ -297,19 +299,20 @@ int scsi_device_cdb_length(uint8_t scsi_id, uint8_t scsi_lun) id = scsi_zip_drives[scsi_id][scsi_lun]; return zip[id].cdb_len; default: - return 12; + break; } + + return 12; } -void scsi_device_command_phase0(uint8_t scsi_id, uint8_t scsi_lun, int cdb_len, uint8_t *cdb) +void +scsi_device_command_phase0(uint8_t scsi_id, uint8_t scsi_lun, int cdb_len, uint8_t *cdb) { uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; - uint8_t id = 0; - switch (lun_type) - { + switch (lun_type) { case SCSI_DISK: id = scsi_hard_disks[scsi_id][scsi_lun]; break; @@ -352,36 +355,38 @@ void scsi_device_command_phase0(uint8_t scsi_id, uint8_t scsi_lun, int cdb_len, /* If the phase is DATA IN or DATA OUT, finish this here. */ } + void scsi_device_command_phase1(uint8_t scsi_id, uint8_t scsi_lun) { - uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; + uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; + uint8_t id = 0; - uint8_t id = 0; + switch (lun_type) { + case SCSI_DISK: + id = scsi_hard_disks[scsi_id][scsi_lun]; + break; + case SCSI_CDROM: + id = scsi_cdrom_drives[scsi_id][scsi_lun]; + break; + case SCSI_ZIP: + id = scsi_zip_drives[scsi_id][scsi_lun]; + break; + default: + id = 0; + return; + } - switch (lun_type) - { - case SCSI_DISK: - id = scsi_hard_disks[scsi_id][scsi_lun]; - break; - case SCSI_CDROM: - id = scsi_cdrom_drives[scsi_id][scsi_lun]; - break; - case SCSI_ZIP: - id = scsi_zip_drives[scsi_id][scsi_lun]; - break; - default: - id = 0; - return; - } + /* Call the second phase. */ + scsi_device_target_phase_callback(lun_type, id); + SCSIDevices[scsi_id][scsi_lun].Status = scsi_device_target_err_stat_to_scsi(lun_type, id); - /* Call the second phase. */ - scsi_device_target_phase_callback(lun_type, id); - SCSIDevices[scsi_id][scsi_lun].Status = scsi_device_target_err_stat_to_scsi(lun_type, id); - /* Command second phase complete - call the callback to complete the command. */ - scsi_device_target_phase_callback(lun_type, id); + /* Command second phase complete - call the callback to complete the command. */ + scsi_device_target_phase_callback(lun_type, id); } -int32_t *scsi_device_get_buf_len(uint8_t scsi_id, uint8_t scsi_lun) + +int32_t * +scsi_device_get_buf_len(uint8_t scsi_id, uint8_t scsi_lun) { - return &SCSIDevices[scsi_id][scsi_lun].BufferLength; + return &SCSIDevices[scsi_id][scsi_lun].BufferLength; } diff --git a/src/scsi/scsi_device.h b/src/scsi/scsi_device.h index ed122dd..15733d0 100644 --- a/src/scsi/scsi_device.h +++ b/src/scsi/scsi_device.h @@ -8,7 +8,7 @@ * * Definitions for the generic SCSI device command handler. * - * Version: @(#)scsi_device.h 1.0.1 2018/02/14 + * Version: @(#)scsi_device.h 1.0.2 2018/03/08 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -38,25 +38,26 @@ # define SCSI_DEVICE_H -typedef struct -{ - int state; - int new_state; - int clear_req; - uint32_t bus_in, bus_out; - int dev_id; +typedef struct { + int state; + int new_state; + int clear_req; + uint32_t bus_in, bus_out; + int dev_id; - int command_pos; - uint8_t command[20]; - int data_pos; - - int change_state_delay; - int new_req_delay; + int command_pos; + uint8_t command[20]; + int data_pos; + + int change_state_delay; + int new_req_delay; } scsi_bus_t; + extern uint8_t *scsi_device_sense(uint8_t id, uint8_t lun); extern void scsi_device_type_data(uint8_t id, uint8_t lun, uint8_t *type, uint8_t *rmb); +extern int64_t scsi_device_get_callback(uint8_t scsi_id, uint8_t scsi_lun); extern void scsi_device_request_sense(uint8_t scsi_id, uint8_t scsi_lun, uint8_t *buffer, uint8_t alloc_length); diff --git a/src/scsi/scsi_disk.c b/src/scsi/scsi_disk.c index 73dd512..41be788 100644 --- a/src/scsi/scsi_disk.c +++ b/src/scsi/scsi_disk.c @@ -8,7 +8,7 @@ * * Emulation of SCSI fixed and removable disks. * - * Version: @(#)scsi_disk.c 1.0.2 2018/03/07 + * Version: @(#)scsi_disk.c 1.0.3 2018/03/08 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -166,17 +166,26 @@ uint8_t scsi_hd_command_flags[0x100] = { uint64_t scsi_hd_mode_sense_page_flags = (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << 0x3F); /* This should be done in a better way but for time being, it's been done this way so it's not as huge and more readable. */ -static const mode_sense_pages_t scsi_hd_mode_sense_pages_default = -{ { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, - [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } -} }; +static const mode_sense_pages_t scsi_hd_mode_sense_pages_default = { + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 + }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' + } + } +}; + +static const mode_sense_pages_t scsi_hd_mode_sense_pages_changeable = { + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 + }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' + } + } +}; -static const mode_sense_pages_t scsi_hd_mode_sense_pages_changeable = -{ { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, - [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } -} }; static mode_sense_pages_t scsi_hd_mode_sense_pages_saved[HDD_NUM]; @@ -202,1526 +211,1421 @@ scsi_hd_log(const char *fmt, ...) /* Translates ATAPI status (ERR_STAT flag) to SCSI status. */ -int scsi_hd_err_stat_to_scsi(uint8_t id) +int +scsi_hd_err_stat_to_scsi(uint8_t id) { - if (shdc[id].status & ERR_STAT) - { - return SCSI_STATUS_CHECK_CONDITION; - } - else - { - return SCSI_STATUS_OK; - } + if (shdc[id].status & ERR_STAT) { + return SCSI_STATUS_CHECK_CONDITION; + } - return SCSI_STATUS_OK; + return SCSI_STATUS_OK; } -int find_hdd_for_scsi_id(uint8_t scsi_id, uint8_t scsi_lun) +int +find_hdd_for_scsi_id(uint8_t scsi_id, uint8_t scsi_lun) { - uint8_t i = 0; + uint8_t i = 0; - for (i = 0; i < HDD_NUM; i++) - { - if ((wcslen(hdd[i].fn) == 0) && (hdd[i].bus != HDD_BUS_SCSI_REMOVABLE)) - { - continue; - } - if (((hdd[i].spt == 0) || (hdd[i].hpc == 0) || (hdd[i].tracks == 0)) && (hdd[i].bus != HDD_BUS_SCSI_REMOVABLE)) - { - continue; - } - if (((hdd[i].bus == HDD_BUS_SCSI) || (hdd[i].bus == HDD_BUS_SCSI_REMOVABLE)) && (hdd[i].scsi_id == scsi_id) && (hdd[i].scsi_lun == scsi_lun)) - { - return i; - } + for (i=0; i 0) - { - scsi_loadhd(i, j, scsi_hard_disks[i][j]); - } + for (i=0; i<16; i++) { + for (j=0; j<8; j++) { + scsi_hard_disks[i][j] = find_hdd_for_scsi_id(i, j); + if (scsi_hard_disks[i][j] != 0xff) { + memset(&(shdc[scsi_hard_disks[i][j]]), 0, sizeof(shdc[scsi_hard_disks[i][j]])); + if (wcslen(hdd[scsi_hard_disks[i][j]].fn) > 0) { + scsi_loadhd(i, j, scsi_hard_disks[i][j]); } } } + } } -void scsi_hd_mode_sense_load(uint8_t id) + +void +scsi_hd_mode_sense_load(uint8_t id) { - FILE *f; - wchar_t file_name[512]; - int i; - memset(&scsi_hd_mode_sense_pages_saved[id], 0, sizeof(mode_sense_pages_t)); - for (i = 0; i < 0x3f; i++) { - if (scsi_hd_mode_sense_pages_default.pages[i][1] != 0) - memcpy(scsi_hd_mode_sense_pages_saved[id].pages[i], scsi_hd_mode_sense_pages_default.pages[i], scsi_hd_mode_sense_pages_default.pages[i][1] + 2); - } - swprintf(file_name, 512, L"scsi_hd_%02i_mode_sense.bin", id); - memset(file_name, 0, 512 * sizeof(wchar_t)); - f = plat_fopen(nvr_path(file_name), L"rb"); - if (f) { - fread(scsi_hd_mode_sense_pages_saved[id].pages[0x30], 1, 0x18, f); - fclose(f); - } + wchar_t file_name[512]; + FILE *f; + int i; + + memset(&scsi_hd_mode_sense_pages_saved[id], 0, sizeof(mode_sense_pages_t)); + for (i=0; i<0x3f; i++) { + if (scsi_hd_mode_sense_pages_default.pages[i][1] != 0) + memcpy(scsi_hd_mode_sense_pages_saved[id].pages[i], scsi_hd_mode_sense_pages_default.pages[i], scsi_hd_mode_sense_pages_default.pages[i][1] + 2); + } + swprintf(file_name, 512, L"scsi_hd_%02i_mode_sense.bin", id); + memset(file_name, 0, 512 * sizeof(wchar_t)); + f = plat_fopen(nvr_path(file_name), L"rb"); + if (f) { + fread(scsi_hd_mode_sense_pages_saved[id].pages[0x30], 1, 0x18, f); + fclose(f); + } } -void scsi_hd_mode_sense_save(uint8_t id) + +void +scsi_hd_mode_sense_save(uint8_t id) { - FILE *f; - wchar_t file_name[512]; - memset(file_name, 0, 512 * sizeof(wchar_t)); - swprintf(file_name, 512, L"scsi_hd_%02i_mode_sense.bin", id); - f = plat_fopen(nvr_path(file_name), L"wb"); - if (f) { - fwrite(scsi_hd_mode_sense_pages_saved[id].pages[0x30], 1, 0x18, f); - fclose(f); - } + wchar_t file_name[512]; + FILE *f; + + memset(file_name, 0, 512 * sizeof(wchar_t)); + swprintf(file_name, 512, L"scsi_hd_%02i_mode_sense.bin", id); + f = plat_fopen(nvr_path(file_name), L"wb"); + if (f) { + fwrite(scsi_hd_mode_sense_pages_saved[id].pages[0x30], 1, 0x18, f); + fclose(f); + } } -int scsi_hd_read_capacity(uint8_t id, uint8_t *cdb, uint8_t *buffer, uint32_t *len) + +int +scsi_hd_read_capacity(uint8_t id, uint8_t *cdb, uint8_t *buffer, uint32_t *len) { - int size = 0; + int size = 0; - size = hdd_image_get_last_sector(id); - memset(buffer, 0, 8); - buffer[0] = (size >> 24) & 0xff; - buffer[1] = (size >> 16) & 0xff; - buffer[2] = (size >> 8) & 0xff; - buffer[3] = size & 0xff; - buffer[6] = 2; /* 512 = 0x0200 */ - *len = 8; + size = hdd_image_get_last_sector(id); + memset(buffer, 0, 8); + buffer[0] = (size >> 24) & 0xff; + buffer[1] = (size >> 16) & 0xff; + buffer[2] = (size >> 8) & 0xff; + buffer[3] = size & 0xff; + buffer[6] = 2; /* 512 = 0x0200 */ + *len = 8; - return 1; + return 1; } /*SCSI Mode Sense 6/10*/ -uint8_t scsi_hd_mode_sense_read(uint8_t id, uint8_t page_control, uint8_t page, uint8_t pos) +uint8_t +scsi_hd_mode_sense_read(uint8_t id, uint8_t page_control, uint8_t page, uint8_t pos) { - switch (page_control) - { - case 0: - case 3: - return scsi_hd_mode_sense_pages_saved[id].pages[page][pos]; - break; - case 1: - return scsi_hd_mode_sense_pages_changeable.pages[page][pos]; - break; - case 2: - return scsi_hd_mode_sense_pages_default.pages[page][pos]; - break; - } + switch (page_control) { + case 0: + case 3: + return scsi_hd_mode_sense_pages_saved[id].pages[page][pos]; + break; + case 1: + return scsi_hd_mode_sense_pages_changeable.pages[page][pos]; + break; + case 2: + return scsi_hd_mode_sense_pages_default.pages[page][pos]; + break; + } - return 0; + return 0; } -uint32_t scsi_hd_mode_sense(uint8_t id, uint8_t *buf, uint32_t pos, uint8_t type, uint8_t block_descriptor_len) + +uint32_t +scsi_hd_mode_sense(uint8_t id, uint8_t *buf, uint32_t pos, uint8_t type, uint8_t block_descriptor_len) { - uint8_t page_control = (type >> 6) & 3; + uint8_t page_control = (type >> 6) & 3; + int i = 0; + int j = 0; + uint8_t msplen; + int size = 0; - int i = 0; - int j = 0; + type &= 0x3f; - uint8_t msplen; - int size = 0; + size = hdd_image_get_last_sector(id); - type &= 0x3f; + if (block_descriptor_len) { + buf[pos++] = 1; /* Density code. */ + buf[pos++] = (size >> 16) & 0xff; /* Number of blocks (0 = all). */ + buf[pos++] = (size >> 8) & 0xff; + buf[pos++] = size & 0xff; + buf[pos++] = 0; /* Reserved. */ + buf[pos++] = 0; /* Block length (0x200 = 512 bytes). */ + buf[pos++] = 2; + buf[pos++] = 0; + } - size = hdd_image_get_last_sector(id); - - if (block_descriptor_len) - { - buf[pos++] = 1; /* Density code. */ - buf[pos++] = (size >> 16) & 0xff; /* Number of blocks (0 = all). */ - buf[pos++] = (size >> 8) & 0xff; - buf[pos++] = size & 0xff; - buf[pos++] = 0; /* Reserved. */ - buf[pos++] = 0; /* Block length (0x200 = 512 bytes). */ - buf[pos++] = 2; - buf[pos++] = 0; - } - - for (i = 0; i < 0x40; i++) - { - if ((type == GPMODE_ALL_PAGES) || (type == i)) - { - if (scsi_hd_mode_sense_page_flags & (1LL << shdc[id].current_page_code)) - { - buf[pos++] = scsi_hd_mode_sense_read(id, page_control, i, 0); - msplen = scsi_hd_mode_sense_read(id, page_control, i, 1); - buf[pos++] = msplen; - scsi_hd_log("SCSI HDD %i: MODE SENSE: Page [%02X] length %i\n", id, i, msplen); - for (j = 0; j < msplen; j++) - { - buf[pos++] = scsi_hd_mode_sense_read(id, page_control, i, 2 + j); - } + for (i = 0; i < 0x40; i++) { + if ((type == GPMODE_ALL_PAGES) || (type == i)) { + if (scsi_hd_mode_sense_page_flags & (1LL << shdc[id].current_page_code)) { + buf[pos++] = scsi_hd_mode_sense_read(id, page_control, i, 0); + msplen = scsi_hd_mode_sense_read(id, page_control, i, 1); + buf[pos++] = msplen; + scsi_hd_log("SCSI HDD %i: MODE SENSE: Page [%02X] length %i\n", id, i, msplen); + for (j=0; j shdc[id].max_blocks_at_once) - { - shdc[id].requested_blocks = shdc[id].max_blocks_at_once; - } - shdc[id].block_total = (shdc[id].requested_blocks * block_len); - if (len > shdc[id].block_total) - { - len = shdc[id].block_total; - } - break; - default: - shdc[id].packet_len = len; - break; - } - /* If the DRQ length is odd, and the total remaining length is bigger, make sure it's even. */ - if ((shdc[id].request_length & 1) && (shdc[id].request_length < len)) - { - shdc[id].request_length &= 0xfffe; - } - /* If the DRQ length is smaller or equal in size to the total remaining length, set it to that. */ - if (len <= shdc[id].request_length) - { - shdc[id].request_length = len; - } - return; + return pos; } -static void scsi_hd_command_common(uint8_t id) +void +scsi_hd_update_request_length(uint8_t id, int len, int block_len) { - shdc[id].status = BUSY_STAT; - shdc[id].phase = 1; - shdc[id].pos = 0; - if (shdc[id].packet_status == CDROM_PHASE_COMPLETE) - { - shdc[id].callback = 20 * SCSI_TIME; - } - else - { - shdc[id].callback = 60 * SCSI_TIME; - } -} - - -void scsi_hd_command_complete(uint8_t id) -{ - shdc[id].packet_status = CDROM_PHASE_COMPLETE; - scsi_hd_command_common(id); -} - - -static void scsi_hd_command_read_dma(uint8_t id) -{ - shdc[id].packet_status = CDROM_PHASE_DATA_IN_DMA; - scsi_hd_command_common(id); - shdc[id].total_read = 0; -} - - -static void scsi_hd_command_write_dma(uint8_t id) -{ - shdc[id].packet_status = CDROM_PHASE_DATA_OUT_DMA; - scsi_hd_command_common(id); -} - - -void scsi_hd_data_command_finish(uint8_t id, int len, int block_len, int alloc_len, int direction) -{ - scsi_hd_log("SCSI HD %i: Finishing command (%02X): %i, %i, %i, %i, %i\n", id, shdc[id].current_cdb[0], len, block_len, alloc_len, direction, shdc[id].request_length); - shdc[id].pos=0; - if (alloc_len >= 0) - { - if (alloc_len < len) + /* For media access commands, make sure the requested + DRQ length matches the block length. */ + switch (shdc[id].current_cdb[0]) { + case 0x08: + case 0x0a: + case 0x28: + case 0x2a: + case 0xa8: + case 0xaa: + if (shdc[id].request_length < block_len) { - len = alloc_len; + shdc[id].request_length = block_len; } - } - if (len == 0) - { - scsi_hd_command_complete(id); - } - else - { - if (direction == 0) - { - scsi_hd_command_read_dma(id); + /* Make sure we respect the limit of how many blocks we can transfer at once. */ + if (shdc[id].requested_blocks > shdc[id].max_blocks_at_once) { + shdc[id].requested_blocks = shdc[id].max_blocks_at_once; } - else - { - scsi_hd_command_write_dma(id); + shdc[id].block_total = (shdc[id].requested_blocks * block_len); + if (len > shdc[id].block_total) { + len = shdc[id].block_total; } + break; + default: + shdc[id].packet_len = len; + break; + } + + /* If the DRQ length is odd, and the total remaining length + is bigger, make sure it's even. */ + if ((shdc[id].request_length & 1) && (shdc[id].request_length < len)) { + shdc[id].request_length &= 0xfffe; + } + + /* If the DRQ length is smaller or equal in size to the + total remaining length, set it to that. */ + if (len <= shdc[id].request_length) { + shdc[id].request_length = len; + } +} + + +static void +scsi_hd_command_common(uint8_t id) +{ + shdc[id].status = BUSY_STAT; + shdc[id].phase = 1; + shdc[id].pos = 0; + + if (shdc[id].packet_status == CDROM_PHASE_COMPLETE) { + scsi_hd_callback(id); + shdc[id].callback = 0LL; + } else + shdc[id].callback = -1LL; /* Speed depends on SCSI controller */ +} + + +void +scsi_hd_command_complete(uint8_t id) +{ + shdc[id].packet_status = CDROM_PHASE_COMPLETE; + scsi_hd_command_common(id); +} + + +static void +scsi_hd_command_read_dma(uint8_t id) +{ + shdc[id].packet_status = CDROM_PHASE_DATA_IN_DMA; + scsi_hd_command_common(id); + shdc[id].total_read = 0; +} + + +static void +scsi_hd_command_write_dma(uint8_t id) +{ + shdc[id].packet_status = CDROM_PHASE_DATA_OUT_DMA; + scsi_hd_command_common(id); +} + + +void +scsi_hd_data_command_finish(uint8_t id, int len, int block_len, int alloc_len, int direction) +{ + scsi_hd_log("SCSI HD %i: Finishing command (%02X): %i, %i, %i, %i, %i\n", id, shdc[id].current_cdb[0], len, block_len, alloc_len, direction, shdc[id].request_length); + shdc[id].pos=0; + if (alloc_len >= 0) { + if (alloc_len < len) { + len = alloc_len; } - - scsi_hd_log("SCSI HD %i: Status: %i, cylinder %i, packet length: %i, position: %i, phase: %i\n", id, shdc[id].packet_status, shdc[id].request_length, shdc[id].packet_len, shdc[id].pos, shdc[id].phase); -} - - -static void scsi_hd_sense_clear(int id, int command) -{ - shdc[id].previous_command = command; - scsi_hd_sense_key = scsi_hd_asc = scsi_hd_ascq = 0; -} - - -static void scsi_hd_set_phase(uint8_t id, uint8_t phase) -{ - uint8_t scsi_id = hdd[id].scsi_id; - uint8_t scsi_lun = hdd[id].scsi_lun; - - if ((hdd[id].bus != HDD_BUS_SCSI) && (hdd[id].bus != HDD_BUS_SCSI_REMOVABLE)) - return; - - SCSIDevices[scsi_id][scsi_lun].Phase = phase; -} - - -static void scsi_hd_cmd_error(uint8_t id) -{ - scsi_hd_set_phase(id, SCSI_PHASE_STATUS); - shdc[id].error = ((scsi_hd_sense_key & 0xf) << 4) | ABRT_ERR; - if (shdc[id].unit_attention & 3) - { - shdc[id].error |= MCR_ERR; + } + if (len == 0) { + scsi_hd_command_complete(id); + } else { + if (direction == 0) { + scsi_hd_command_read_dma(id); + } else { + scsi_hd_command_write_dma(id); } - shdc[id].status = READY_STAT | ERR_STAT; - shdc[id].phase = 3; - shdc[id].packet_status = 0x80; - shdc[id].callback = 50 * SCSI_TIME; - scsi_hd_log("SCSI HD %i: ERROR: %02X/%02X/%02X\n", id, scsi_hd_sense_key, scsi_hd_asc, scsi_hd_ascq); + } + + scsi_hd_log("SCSI HD %i: Status: %i, cylinder %i, packet length: %i, position: %i, phase: %i\n", id, shdc[id].packet_status, shdc[id].request_length, shdc[id].packet_len, shdc[id].pos, shdc[id].phase); } -static void scsi_hd_unit_attention(uint8_t id) +static void +scsi_hd_sense_clear(int id, int command) { - scsi_hd_set_phase(id, SCSI_PHASE_STATUS); - shdc[id].error = (SENSE_NOT_READY << 4) | ABRT_ERR; - if (shdc[id].unit_attention & 3) - { - shdc[id].error |= MCR_ERR; - } - shdc[id].status = READY_STAT | ERR_STAT; - shdc[id].phase = 3; - shdc[id].packet_status = 0x80; - shdc[id].callback = 50 * CDROM_TIME; - scsi_hd_log("SCSI HD %i: UNIT ATTENTION\n", id); + shdc[id].previous_command = command; + scsi_hd_sense_key = scsi_hd_asc = scsi_hd_ascq = 0; } -static void scsi_hd_not_ready(uint8_t id) +static void +scsi_hd_set_phase(uint8_t id, uint8_t phase) { - scsi_hd_sense_key = SENSE_NOT_READY; - scsi_hd_asc = ASC_MEDIUM_NOT_PRESENT; - scsi_hd_ascq = 0; - scsi_hd_cmd_error(id); + uint8_t scsi_id = hdd[id].scsi_id; + uint8_t scsi_lun = hdd[id].scsi_lun; + + if ((hdd[id].bus != HDD_BUS_SCSI) && + (hdd[id].bus != HDD_BUS_SCSI_REMOVABLE)) return; + + SCSIDevices[scsi_id][scsi_lun].Phase = phase; } -static void scsi_hd_write_protected(uint8_t id) +static void +scsi_hd_cmd_error(uint8_t id) { - scsi_hd_sense_key = SENSE_UNIT_ATTENTION; - scsi_hd_asc = ASC_WRITE_PROTECTED; - scsi_hd_ascq = 0; - scsi_hd_cmd_error(id); + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + shdc[id].error = ((scsi_hd_sense_key & 0xf) << 4) | ABRT_ERR; + if (shdc[id].unit_attention & 3) { + shdc[id].error |= MCR_ERR; + } + shdc[id].status = READY_STAT | ERR_STAT; + shdc[id].phase = 3; + shdc[id].packet_status = 0x80; + shdc[id].callback = 50 * SCSI_TIME; + + scsi_hd_log("SCSI HD %i: ERROR: %02X/%02X/%02X\n", id, scsi_hd_sense_key, scsi_hd_asc, scsi_hd_ascq); } -static void scsi_hd_invalid_lun(uint8_t id) +static void +scsi_hd_unit_attention(uint8_t id) { - scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; - scsi_hd_asc = ASC_INV_LUN; - scsi_hd_ascq = 0; - scsi_hd_set_phase(id, SCSI_PHASE_STATUS); - scsi_hd_cmd_error(id); + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + shdc[id].error = (SENSE_NOT_READY << 4) | ABRT_ERR; + if (shdc[id].unit_attention & 3) { + shdc[id].error |= MCR_ERR; + } + shdc[id].status = READY_STAT | ERR_STAT; + shdc[id].phase = 3; + shdc[id].packet_status = 0x80; + shdc[id].callback = 50 * CDROM_TIME; + + scsi_hd_log("SCSI HD %i: UNIT ATTENTION\n", id); } -static void scsi_hd_illegal_opcode(uint8_t id) +static void +scsi_hd_not_ready(uint8_t id) { - scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; - scsi_hd_asc = ASC_ILLEGAL_OPCODE; - scsi_hd_ascq = 0; - scsi_hd_cmd_error(id); + scsi_hd_sense_key = SENSE_NOT_READY; + scsi_hd_asc = ASC_MEDIUM_NOT_PRESENT; + scsi_hd_ascq = 0; + scsi_hd_cmd_error(id); } -void scsi_hd_lba_out_of_range(uint8_t id) +static void +scsi_hd_write_protected(uint8_t id) { - scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; - scsi_hd_asc = ASC_LBA_OUT_OF_RANGE; - scsi_hd_ascq = 0; - scsi_hd_cmd_error(id); + scsi_hd_sense_key = SENSE_UNIT_ATTENTION; + scsi_hd_asc = ASC_WRITE_PROTECTED; + scsi_hd_ascq = 0; + scsi_hd_cmd_error(id); } -static void scsi_hd_invalid_field(uint8_t id) +static void +scsi_hd_invalid_lun(uint8_t id) { - scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; - scsi_hd_asc = ASC_INV_FIELD_IN_CMD_PACKET; - scsi_hd_ascq = 0; - scsi_hd_cmd_error(id); - shdc[id].status = 0x53; + scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_hd_asc = ASC_INV_LUN; + scsi_hd_ascq = 0; + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + scsi_hd_cmd_error(id); } -static void scsi_hd_invalid_field_pl(uint8_t id) +static void +scsi_hd_illegal_opcode(uint8_t id) { - scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; - scsi_hd_asc = ASC_INV_FIELD_IN_PARAMETER_LIST; - scsi_hd_ascq = 0; - scsi_hd_cmd_error(id); - shdc[id].status = 0x53; + scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_hd_asc = ASC_ILLEGAL_OPCODE; + scsi_hd_ascq = 0; + scsi_hd_cmd_error(id); } -static void scsi_hd_data_phase_error(uint8_t id) +void +scsi_hd_lba_out_of_range(uint8_t id) { - scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; - scsi_hd_asc = ASC_DATA_PHASE_ERROR; - scsi_hd_ascq = 0; - scsi_hd_cmd_error(id); + scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_hd_asc = ASC_LBA_OUT_OF_RANGE; + scsi_hd_ascq = 0; + scsi_hd_cmd_error(id); +} + + +static void +scsi_hd_invalid_field(uint8_t id) +{ + scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_hd_asc = ASC_INV_FIELD_IN_CMD_PACKET; + scsi_hd_ascq = 0; + scsi_hd_cmd_error(id); + shdc[id].status = 0x53; +} + + +static void +scsi_hd_invalid_field_pl(uint8_t id) +{ + scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_hd_asc = ASC_INV_FIELD_IN_PARAMETER_LIST; + scsi_hd_ascq = 0; + scsi_hd_cmd_error(id); + shdc[id].status = 0x53; +} + + +static void +scsi_hd_data_phase_error(uint8_t id) +{ + scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_hd_asc = ASC_DATA_PHASE_ERROR; + scsi_hd_ascq = 0; + scsi_hd_cmd_error(id); } /*SCSI Sense Initialization*/ -void scsi_hd_sense_code_ok(uint8_t id) +void +scsi_hd_sense_code_ok(uint8_t id) { - scsi_hd_sense_key = SENSE_NONE; - scsi_hd_asc = 0; - scsi_hd_ascq = 0; + scsi_hd_sense_key = SENSE_NONE; + scsi_hd_asc = 0; + scsi_hd_ascq = 0; } -int scsi_hd_pre_execution_check(uint8_t id, uint8_t *cdb) +int +scsi_hd_pre_execution_check(uint8_t id, uint8_t *cdb) { - int ready = 1; + int ready = 1; - if (((shdc[id].request_length >> 5) & 7) != hdd[id].scsi_lun) - { - scsi_hd_log("SCSI HD %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", id, ((shdc[id].request_length >> 5) & 7)); - scsi_hd_invalid_lun(id); + if (((shdc[id].request_length >> 5) & 7) != hdd[id].scsi_lun) { + scsi_hd_log("SCSI HD %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", id, ((shdc[id].request_length >> 5) & 7)); + scsi_hd_invalid_lun(id); + return 0; + } + + if (!(scsi_hd_command_flags[cdb[0]] & IMPLEMENTED)) { + scsi_hd_log("SCSI HD %i: Attempting to execute unknown command %02X\n", id, cdb[0]); + scsi_hd_illegal_opcode(id); + return 0; + } + + if (hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) { + /* Removable disk, set ready state. */ + if (wcslen(hdd[id].fn) > 0) { + ready = 1; + } else { + ready = 0; + } + } else { + /* Fixed disk, clear UNIT ATTENTION, just in case it might have been set when the disk was removable). */ + shdc[id].unit_attention = 0; + } + + if (!ready && shdc[id].unit_attention) { + /* If the drive is not ready, there is no reason to keep the + UNIT ATTENTION condition present, as we only use it to mark + disc changes. */ + shdc[id].unit_attention = 0; + } + + /* If the UNIT ATTENTION condition is set and the command does not allow + execution under it, error out and report the condition. */ + if (shdc[id].unit_attention == 1) { + /* Only increment the unit attention phase if the command can not pass through it. */ + if (!(scsi_hd_command_flags[cdb[0]] & ALLOW_UA)) { + /* scsi_hd_log("SCSI HD %i: Unit attention now 2\n", id); */ + shdc[id].unit_attention = 2; + scsi_hd_log("SCSI HD %i: UNIT ATTENTION: Command %02X not allowed to pass through\n", id, cdb[0]); + scsi_hd_unit_attention(id); return 0; } - - if (!(scsi_hd_command_flags[cdb[0]] & IMPLEMENTED)) - { - scsi_hd_log("SCSI HD %i: Attempting to execute unknown command %02X\n", id, cdb[0]); - scsi_hd_illegal_opcode(id); - return 0; - } - - if (hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) - { - /* Removable disk, set ready state. */ - if (wcslen(hdd[id].fn) > 0) - { - ready = 1; - } - else - { - ready = 0; - } - } - else - { - /* Fixed disk, clear UNIT ATTENTION, just in case it might have been set when the disk was removable). */ + } else if (shdc[id].unit_attention == 2) { + if (cdb[0] != GPCMD_REQUEST_SENSE) { + /* scsi_hd_log("SCSI HD %i: Unit attention now 0\n", id); */ shdc[id].unit_attention = 0; } + } - if (!ready && shdc[id].unit_attention) - { - /* If the drive is not ready, there is no reason to keep the - UNIT ATTENTION condition present, as we only use it to mark - disc changes. */ - shdc[id].unit_attention = 0; - } + /* Unless the command is REQUEST SENSE, clear the sense. This will *NOT* + the UNIT ATTENTION condition if it's set. */ + if (cdb[0] != GPCMD_REQUEST_SENSE) { + scsi_hd_sense_clear(id, cdb[0]); + } - /* If the UNIT ATTENTION condition is set and the command does not allow - execution under it, error out and report the condition. */ - if (shdc[id].unit_attention == 1) - { - /* Only increment the unit attention phase if the command can not pass through it. */ - if (!(scsi_hd_command_flags[cdb[0]] & ALLOW_UA)) - { - /* scsi_hd_log("SCSI HD %i: Unit attention now 2\n", id); */ - shdc[id].unit_attention = 2; - scsi_hd_log("SCSI HD %i: UNIT ATTENTION: Command %02X not allowed to pass through\n", id, cdb[0]); - scsi_hd_unit_attention(id); - return 0; - } - } - else if (shdc[id].unit_attention == 2) - { - if (cdb[0] != GPCMD_REQUEST_SENSE) - { - /* scsi_hd_log("SCSI HD %i: Unit attention now 0\n", id); */ - shdc[id].unit_attention = 0; - } - } + /* Next it's time for NOT READY. */ + if ((scsi_hd_command_flags[cdb[0]] & CHECK_READY) && !ready) { + scsi_hd_log("SCSI HD %i: Not ready (%02X)\n", id, cdb[0]); + scsi_hd_not_ready(id); + return 0; + } - /* Unless the command is REQUEST SENSE, clear the sense. This will *NOT* - the UNIT ATTENTION condition if it's set. */ - if (cdb[0] != GPCMD_REQUEST_SENSE) - { - scsi_hd_sense_clear(id, cdb[0]); - } + scsi_hd_log("SCSI HD %i: Continuing with command\n", id); - /* Next it's time for NOT READY. */ - if ((scsi_hd_command_flags[cdb[0]] & CHECK_READY) && !ready) - { - scsi_hd_log("SCSI HD %i: Not ready (%02X)\n", id, cdb[0]); - scsi_hd_not_ready(id); - return 0; - } - - scsi_hd_log("SCSI HD %i: Continuing with command\n", id); - - return 1; + return 1; } -static void scsi_hd_seek(uint8_t id, uint32_t pos) +static void +scsi_hd_seek(uint8_t id, uint32_t pos) { - /* scsi_hd_log("SCSI HD %i: Seek %08X\n", id, pos); */ - hdd_image_seek(id, pos); + /* scsi_hd_log("SCSI HD %i: Seek %08X\n", id, pos); */ + hdd_image_seek(id, pos); } -static void scsi_hd_rezero(uint8_t id) +static void +scsi_hd_rezero(uint8_t id) { - if (id == 255) - { - return; - } + if (id == 255) return; - shdc[id].sector_pos = shdc[id].sector_len = 0; - scsi_hd_seek(id, 0); + shdc[id].sector_pos = shdc[id].sector_len = 0; + scsi_hd_seek(id, 0); } -void scsi_hd_reset(uint8_t id) +void +scsi_hd_reset(uint8_t id) { - scsi_hd_rezero(id); - shdc[id].status = 0; - shdc[id].callback = 0; - shdc[id].packet_status = 0xff; + scsi_hd_rezero(id); + shdc[id].status = 0; + shdc[id].callback = 0; + shdc[id].packet_status = 0xff; } -void scsi_hd_request_sense(uint8_t id, uint8_t *buffer, uint8_t alloc_length, int desc) -{ - /*Will return 18 bytes of 0*/ - if (alloc_length != 0) - { - memset(buffer, 0, alloc_length); - if (!desc) - memcpy(buffer, shdc[id].sense, alloc_length); - else { - buffer[1] = scsi_hd_sense_key; - buffer[2] = scsi_hd_asc; - buffer[3] = scsi_hd_ascq; - } - } - else - { - return; - } - - buffer[0] = 0x70; - - if (shdc[id].unit_attention && (scsi_hd_sense_key == 0)) - { - buffer[desc ? 1 : 2]=SENSE_UNIT_ATTENTION; - buffer[desc ? 2 : 12]=ASC_MEDIUM_MAY_HAVE_CHANGED; - buffer[desc ? 3 : 13]=0x00; - } - - scsi_hd_log("SCSI HD %i: Reporting sense: %02X %02X %02X\n", id, buffer[2], buffer[12], buffer[13]); - - if (buffer[desc ? 1: 2] == SENSE_UNIT_ATTENTION) - { - /* If the last remaining sense is unit attention, clear - that condition. */ - shdc[id].unit_attention = 0; - } - - /* Clear the sense stuff as per the spec. */ - scsi_hd_sense_clear(id, GPCMD_REQUEST_SENSE); -} - - -void scsi_hd_request_sense_for_scsi(uint8_t id, uint8_t *buffer, uint8_t alloc_length) +void +scsi_hd_request_sense(uint8_t id, uint8_t *buffer, uint8_t alloc_length, int desc) { - int ready = 1; - - if (hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) - { - /* Removable disk, set ready state. */ - if (wcslen(hdd[id].fn) > 0) - { - ready = 1; - } - else - { - ready = 0; - } - } - else - { - /* Fixed disk, clear UNIT ATTENTION, just in case it might have been set when the disk was removable). */ - shdc[id].unit_attention = 0; + /*Will return 18 bytes of 0*/ + if (alloc_length != 0) { + memset(buffer, 0x00, alloc_length); + if (! desc) + memcpy(buffer, shdc[id].sense, alloc_length); + else { + buffer[1] = scsi_hd_sense_key; + buffer[2] = scsi_hd_asc; + buffer[3] = scsi_hd_ascq; } + } else { + return; + } - if (!ready && shdc[id].unit_attention) - { - /* If the drive is not ready, there is no reason to keep the - UNIT ATTENTION condition present, as we only use it to mark - disc changes. */ - shdc[id].unit_attention = 0; - } + buffer[0] = 0x70; - /* Do *NOT* advance the unit attention phase. */ + if (shdc[id].unit_attention && (scsi_hd_sense_key == 0)) { + buffer[desc ? 1 : 2]=SENSE_UNIT_ATTENTION; + buffer[desc ? 2 : 12]=ASC_MEDIUM_MAY_HAVE_CHANGED; + buffer[desc ? 3 : 13]=0x00; + } - scsi_hd_request_sense(id, buffer, alloc_length, 0); + scsi_hd_log("SCSI HD %i: Reporting sense: %02X %02X %02X\n", id, buffer[2], buffer[12], buffer[13]); + + if (buffer[desc ? 1: 2] == SENSE_UNIT_ATTENTION) { + /* If the last remaining sense is unit attention, clear + that condition. */ + shdc[id].unit_attention = 0; + } + + /* Clear the sense stuff as per the spec. */ + scsi_hd_sense_clear(id, GPCMD_REQUEST_SENSE); } -void scsi_hd_command(uint8_t id, uint8_t *cdb) +void +scsi_hd_request_sense_for_scsi(uint8_t id, uint8_t *buffer, uint8_t alloc_length) { - /* uint8_t *hdbufferb = (uint8_t *) shdc[id].buffer; */ - uint8_t *hdbufferb = SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].CmdBuffer; - uint32_t len; - int pos=0; - int max_len; - unsigned idx = 0; - unsigned size_idx; - unsigned preamble_len; - uint32_t alloc_length; - char device_identify[9] = { 'E', 'M', 'U', '_', 'H', 'D', '0', '0', 0 }; - char device_identify_ex[15] = { 'E', 'M', 'U', '_', 'H', 'D', '0', '0', ' ', 'v', '1', '.', '0', '0', 0 }; - uint32_t last_sector = 0; - int block_desc = 0; - int32_t *BufLen = &SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].BufferLength; + int ready = 1; + + if (hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) { + /* Removable disk, set ready state. */ + if (wcslen(hdd[id].fn) > 0) { + ready = 1; + } else { + ready = 0; + } + } else { + /* Fixed disk, clear UNIT ATTENTION, just in case it might have been set when the disk was removable). */ + shdc[id].unit_attention = 0; + } + + if (!ready && shdc[id].unit_attention) { + /* If the drive is not ready, there is no reason to keep the + UNIT ATTENTION condition present, as we only use it to mark + disc changes. */ + shdc[id].unit_attention = 0; + } + + /* Do *NOT* advance the unit attention phase. */ + scsi_hd_request_sense(id, buffer, alloc_length, 0); +} + + +void +scsi_hd_command(uint8_t id, uint8_t *cdb) +{ + /* uint8_t *hdbufferb = (uint8_t *) shdc[id].buffer; */ + uint8_t *hdbufferb = SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].CmdBuffer; + uint32_t len; + int pos=0; + int max_len; + unsigned idx = 0; + unsigned size_idx; + unsigned preamble_len; + uint32_t alloc_length; + char device_identify[9] = { + 'E','M','U','_','H','D','0','0',0 }; + char device_identify_ex[15] = { + 'E','M','U','_','H','D','0','0',' ','v','1','.','0','0',0 }; + uint32_t last_sector = 0; + int block_desc = 0; + int32_t *BufLen = &SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].BufferLength; +#if 0 + int CdbLength; +#endif + + last_sector = hdd_image_get_last_sector(id); + + shdc[id].status &= ~ERR_STAT; + + shdc[id].packet_len = 0; + shdc[id].request_pos = 0; + + device_identify[6] = (id / 10) + 0x30; + device_identify[7] = (id % 10) + 0x30; + + device_identify_ex[6] = (id / 10) + 0x30; + device_identify_ex[7] = (id % 10) + 0x30; + device_identify_ex[10] = EMU_VERSION[0]; + device_identify_ex[12] = EMU_VERSION[2]; + device_identify_ex[13] = EMU_VERSION[3]; + + if (hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) { + device_identify[4] = 'R'; + device_identify_ex[4] = 'R'; + } + + shdc[id].data_pos = 0; + + memcpy(shdc[id].current_cdb, cdb, 12); + + if (cdb[0] != 0) { + scsi_hd_log("SCSI HD %i: Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X\n", id, cdb[0], scsi_hd_sense_key, scsi_hd_asc, scsi_hd_ascq); + scsi_hd_log("SCSI HD %i: Request length: %04X\n", id, shdc[id].request_length); #if 0 - int CdbLength; -#endif - last_sector = hdd_image_get_last_sector(id); - - shdc[id].status &= ~ERR_STAT; - - shdc[id].packet_len = 0; - shdc[id].request_pos = 0; - - device_identify[6] = (id / 10) + 0x30; - device_identify[7] = (id % 10) + 0x30; - - device_identify_ex[6] = (id / 10) + 0x30; - device_identify_ex[7] = (id % 10) + 0x30; - device_identify_ex[10] = EMU_VERSION[0]; - device_identify_ex[12] = EMU_VERSION[2]; - device_identify_ex[13] = EMU_VERSION[3]; - - if (hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) - { - device_identify[4] = 'R'; - - device_identify_ex[4] = 'R'; + for (CdbLength = 1; CdbLength < 12; CdbLength++) { + scsi_hd_log("SCSI HD %i: CDB[%d] = %d\n", id, CdbLength, cdb[CdbLength]); } - - shdc[id].data_pos = 0; - - memcpy(shdc[id].current_cdb, cdb, 12); - - if (cdb[0] != 0) - { - scsi_hd_log("SCSI HD %i: Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X\n", id, cdb[0], scsi_hd_sense_key, scsi_hd_asc, scsi_hd_ascq); - scsi_hd_log("SCSI HD %i: Request length: %04X\n", id, shdc[id].request_length); - -#if 0 - for (CdbLength = 1; CdbLength < 12; CdbLength++) - { - scsi_hd_log("SCSI HD %i: CDB[%d] = %d\n", id, CdbLength, cdb[CdbLength]); - } #endif - } + } - shdc[id].sector_len = 0; + shdc[id].sector_len = 0; - scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); - /* This handles the Not Ready/Unit Attention check if it has to be handled at this point. */ - if (scsi_hd_pre_execution_check(id, cdb) == 0) - { + /* This handles the Not Ready/Unit Attention check if it has to be handled at this point. */ + if (scsi_hd_pre_execution_check(id, cdb) == 0) return; + + switch (cdb[0]) { + case GPCMD_SEND_DIAGNOSTIC: + if (!(cdb[1] & (1 << 2))) { + scsi_hd_invalid_field(id); + return; + } + case GPCMD_SCSI_RESERVE: + case GPCMD_SCSI_RELEASE: + case GPCMD_TEST_UNIT_READY: + case GPCMD_FORMAT_UNIT: + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + scsi_hd_command_complete(id); + break; + + case GPCMD_REZERO_UNIT: + shdc[id].sector_pos = shdc[id].sector_len = 0; + scsi_hd_seek(id, 0); + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + 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 ((*BufLen == -1) || (cdb[4] < *BufLen)) + *BufLen = cdb[4]; + + if (*BufLen < cdb[4]) + cdb[4] = *BufLen; + + len = (cdb[1] & 1) ? 8 : 18; + + scsi_hd_set_phase(id, SCSI_PHASE_DATA_IN); + scsi_hd_data_command_finish(id, len, len, cdb[4], 0); + break; + + case GPCMD_MECHANISM_STATUS: + len = (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + + if ((*BufLen == -1) || (len < *BufLen)) + *BufLen = len; + + scsi_hd_set_phase(id, SCSI_PHASE_DATA_IN); + scsi_hd_data_command_finish(id, 8, 8, len, 0); + break; + + case GPCMD_READ_6: + case GPCMD_READ_10: + case GPCMD_READ_12: + switch(cdb[0]) { + case GPCMD_READ_6: + shdc[id].sector_len = cdb[4]; + shdc[id].sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); + break; + case GPCMD_READ_10: + shdc[id].sector_len = (cdb[7] << 8) | cdb[8]; + shdc[id].sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + break; + case GPCMD_READ_12: + shdc[id].sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + shdc[id].sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); + break; + } + + if ((shdc[id].sector_pos > last_sector) || ((shdc[id].sector_pos + shdc[id].sector_len - 1) > last_sector)) { + scsi_hd_lba_out_of_range(id); + return; + } + + if ((!shdc[id].sector_len) || (*BufLen == 0)) { + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); + scsi_hd_log("SCSI HD %i: All done - callback set\n", id); + shdc[id].packet_status = CDROM_PHASE_COMPLETE; + shdc[id].callback = 20 * SCSI_TIME; + break; + } + + max_len = shdc[id].sector_len; + shdc[id].requested_blocks = max_len; + + alloc_length = shdc[id].packet_len = max_len << 9; + + if ((*BufLen == -1) || (alloc_length < *BufLen)) + *BufLen = alloc_length; + + scsi_hd_set_phase(id, SCSI_PHASE_DATA_IN); + + if (shdc[id].requested_blocks > 1) { + scsi_hd_data_command_finish(id, alloc_length, alloc_length / shdc[id].requested_blocks, alloc_length, 0); + } else { + scsi_hd_data_command_finish(id, alloc_length, alloc_length, alloc_length, 0); + } + shdc[id].all_blocks_total = shdc[id].block_total; + ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 1); return; - } - switch (cdb[0]) - { - case GPCMD_SEND_DIAGNOSTIC: - if (!(cdb[1] & (1 << 2))) { - scsi_hd_invalid_field(id); - return; - } - case GPCMD_SCSI_RESERVE: - case GPCMD_SCSI_RELEASE: - case GPCMD_TEST_UNIT_READY: - case GPCMD_FORMAT_UNIT: + case GPCMD_VERIFY_6: + case GPCMD_VERIFY_10: + case GPCMD_VERIFY_12: + if (!(cdb[1] & 2)) { scsi_hd_set_phase(id, SCSI_PHASE_STATUS); scsi_hd_command_complete(id); break; + } + case GPCMD_WRITE_6: + case GPCMD_WRITE_10: + case GPCMD_WRITE_AND_VERIFY_10: + case GPCMD_WRITE_12: + case GPCMD_WRITE_AND_VERIFY_12: + if ((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) && hdd[id].wp) { + scsi_hd_write_protected(id); + return; + } - case GPCMD_REZERO_UNIT: - shdc[id].sector_pos = shdc[id].sector_len = 0; - scsi_hd_seek(id, 0); + switch(cdb[0]) { + case GPCMD_VERIFY_6: + case GPCMD_WRITE_6: + shdc[id].sector_len = cdb[4]; + shdc[id].sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); + scsi_hd_log("SCSI HD %i: Length: %i, LBA: %i\n", id, shdc[id].sector_len, shdc[id].sector_pos); + break; + case GPCMD_VERIFY_10: + case GPCMD_WRITE_10: + case GPCMD_WRITE_AND_VERIFY_10: + shdc[id].sector_len = (cdb[7] << 8) | cdb[8]; + shdc[id].sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + scsi_hd_log("SCSI HD %i: Length: %i, LBA: %i\n", id, shdc[id].sector_len, shdc[id].sector_pos); + break; + case GPCMD_VERIFY_12: + case GPCMD_WRITE_12: + case GPCMD_WRITE_AND_VERIFY_12: + shdc[id].sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + shdc[id].sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); + break; + } + + if ((shdc[id].sector_pos > last_sector) || ((shdc[id].sector_pos + shdc[id].sector_len - 1) > last_sector)) { + scsi_hd_lba_out_of_range(id); + return; + } + + if ((!shdc[id].sector_len) || (*BufLen == 0)) { scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); + scsi_hd_log("SCSI HD %i: All done - callback set\n", id); + shdc[id].packet_status = CDROM_PHASE_COMPLETE; + shdc[id].callback = 20 * SCSI_TIME; 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 ((*BufLen == -1) || (cdb[4] < *BufLen)) - { - *BufLen = cdb[4]; - } + max_len = shdc[id].sector_len; + shdc[id].requested_blocks = max_len; - if (*BufLen < cdb[4]) - { - cdb[4] = *BufLen; - } + alloc_length = shdc[id].packet_len = max_len << 9; - len = (cdb[1] & 1) ? 8 : 18; + if ((*BufLen == -1) || (alloc_length < *BufLen)) + *BufLen = alloc_length; - scsi_hd_set_phase(id, SCSI_PHASE_DATA_IN); - scsi_hd_data_command_finish(id, len, len, cdb[4], 0); + scsi_hd_set_phase(id, SCSI_PHASE_DATA_OUT); + + if (shdc[id].requested_blocks > 1) { + scsi_hd_data_command_finish(id, alloc_length, alloc_length / shdc[id].requested_blocks, alloc_length, 1); + } else { + scsi_hd_data_command_finish(id, alloc_length, alloc_length, alloc_length, 1); + } + shdc[id].all_blocks_total = shdc[id].block_total; + ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 1); + return; + + case GPCMD_WRITE_SAME_10: + if ((cdb[1] & 6) == 6) { + scsi_hd_invalid_field(id); + return; + } + + if ((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) && hdd[id].wp) { + scsi_hd_write_protected(id); + return; + } + + shdc[id].sector_len = (cdb[7] << 8) | cdb[8]; + shdc[id].sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + scsi_hd_log("SCSI HD %i: Length: %i, LBA: %i\n", id, shdc[id].sector_len, shdc[id].sector_pos); + + if ((shdc[id].sector_pos > last_sector) || ((shdc[id].sector_pos + shdc[id].sector_len - 1) > last_sector)) { + scsi_hd_lba_out_of_range(id); + return; + } + + if ((!shdc[id].sector_len) || (*BufLen == 0)) { + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); + scsi_hd_log("SCSI HD %i: All done - callback set\n", id); + shdc[id].packet_status = CDROM_PHASE_COMPLETE; + shdc[id].callback = 20 * SCSI_TIME; break; + } - case GPCMD_MECHANISM_STATUS: - len = (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + max_len = 1; + shdc[id].requested_blocks = max_len; - if ((*BufLen == -1) || (len < *BufLen)) - { - *BufLen = len; - } + alloc_length = shdc[id].packet_len = max_len << 9; - scsi_hd_set_phase(id, SCSI_PHASE_DATA_IN); - scsi_hd_data_command_finish(id, 8, 8, len, 0); - break; + if ((*BufLen == -1) || (alloc_length < *BufLen)) + *BufLen = alloc_length; - case GPCMD_READ_6: - case GPCMD_READ_10: - case GPCMD_READ_12: - switch(cdb[0]) - { - case GPCMD_READ_6: - shdc[id].sector_len = cdb[4]; - shdc[id].sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); - break; - case GPCMD_READ_10: - shdc[id].sector_len = (cdb[7] << 8) | cdb[8]; - shdc[id].sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - break; - case GPCMD_READ_12: - shdc[id].sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); - shdc[id].sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); - break; - } + scsi_hd_set_phase(id, SCSI_PHASE_DATA_OUT); - if ((shdc[id].sector_pos > last_sector) || ((shdc[id].sector_pos + shdc[id].sector_len - 1) > last_sector)) - { - scsi_hd_lba_out_of_range(id); - return; - } + if (shdc[id].requested_blocks > 1) { + scsi_hd_data_command_finish(id, alloc_length, alloc_length / shdc[id].requested_blocks, alloc_length, 1); + } else { + scsi_hd_data_command_finish(id, alloc_length, alloc_length, alloc_length, 1); + } + shdc[id].all_blocks_total = shdc[id].block_total; + ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 1); + return; - if ((!shdc[id].sector_len) || (*BufLen == 0)) - { - scsi_hd_set_phase(id, SCSI_PHASE_STATUS); - ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); - scsi_hd_log("SCSI HD %i: All done - callback set\n", id); - shdc[id].packet_status = CDROM_PHASE_COMPLETE; - shdc[id].callback = 20 * SCSI_TIME; - break; - } + case GPCMD_MODE_SENSE_6: + case GPCMD_MODE_SENSE_10: + scsi_hd_set_phase(id, SCSI_PHASE_DATA_IN); - max_len = shdc[id].sector_len; - shdc[id].requested_blocks = max_len; + block_desc = ((cdb[1] >> 3) & 1) ? 0 : 1; - alloc_length = shdc[id].packet_len = max_len << 9; + if (cdb[0] == GPCMD_MODE_SENSE_6) + len = cdb[4]; + else + len = (cdb[8] | (cdb[7] << 8)); - if ((*BufLen == -1) || (alloc_length < *BufLen)) - { - *BufLen = alloc_length; - } + shdc[id].current_page_code = cdb[2] & 0x3F; - scsi_hd_set_phase(id, SCSI_PHASE_DATA_IN); + alloc_length = len; - if (shdc[id].requested_blocks > 1) - { - scsi_hd_data_command_finish(id, alloc_length, alloc_length / shdc[id].requested_blocks, alloc_length, 0); - } - else - { - scsi_hd_data_command_finish(id, alloc_length, alloc_length, alloc_length, 0); - } - shdc[id].all_blocks_total = shdc[id].block_total; - ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 1); - return; - - case GPCMD_VERIFY_6: - case GPCMD_VERIFY_10: - case GPCMD_VERIFY_12: - if (!(cdb[1] & 2)) { - scsi_hd_set_phase(id, SCSI_PHASE_STATUS); - scsi_hd_command_complete(id); - break; - } - case GPCMD_WRITE_6: - case GPCMD_WRITE_10: - case GPCMD_WRITE_AND_VERIFY_10: - case GPCMD_WRITE_12: - case GPCMD_WRITE_AND_VERIFY_12: - if ((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) && hdd[id].wp) - { - scsi_hd_write_protected(id); - return; - } - - switch(cdb[0]) - { - case GPCMD_VERIFY_6: - case GPCMD_WRITE_6: - shdc[id].sector_len = cdb[4]; - shdc[id].sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); - scsi_hd_log("SCSI HD %i: Length: %i, LBA: %i\n", id, shdc[id].sector_len, shdc[id].sector_pos); - break; - case GPCMD_VERIFY_10: - case GPCMD_WRITE_10: - case GPCMD_WRITE_AND_VERIFY_10: - shdc[id].sector_len = (cdb[7] << 8) | cdb[8]; - shdc[id].sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - scsi_hd_log("SCSI HD %i: Length: %i, LBA: %i\n", id, shdc[id].sector_len, shdc[id].sector_pos); - break; - case GPCMD_VERIFY_12: - case GPCMD_WRITE_12: - case GPCMD_WRITE_AND_VERIFY_12: - shdc[id].sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); - shdc[id].sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); - break; - } - - if ((shdc[id].sector_pos > last_sector) || ((shdc[id].sector_pos + shdc[id].sector_len - 1) > last_sector)) - { - scsi_hd_lba_out_of_range(id); - return; - } - - if ((!shdc[id].sector_len) || (*BufLen == 0)) - { - scsi_hd_set_phase(id, SCSI_PHASE_STATUS); - ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); - scsi_hd_log("SCSI HD %i: All done - callback set\n", id); - shdc[id].packet_status = CDROM_PHASE_COMPLETE; - shdc[id].callback = 20 * SCSI_TIME; - break; - } - - max_len = shdc[id].sector_len; - shdc[id].requested_blocks = max_len; - - alloc_length = shdc[id].packet_len = max_len << 9; - - if ((*BufLen == -1) || (alloc_length < *BufLen)) - { - *BufLen = alloc_length; - } - - scsi_hd_set_phase(id, SCSI_PHASE_DATA_OUT); - - if (shdc[id].requested_blocks > 1) - { - scsi_hd_data_command_finish(id, alloc_length, alloc_length / shdc[id].requested_blocks, alloc_length, 1); - } - else - { - scsi_hd_data_command_finish(id, alloc_length, alloc_length, alloc_length, 1); - } - shdc[id].all_blocks_total = shdc[id].block_total; - ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 1); - return; - - case GPCMD_WRITE_SAME_10: - if ((cdb[1] & 6) == 6) - { - scsi_hd_invalid_field(id); - return; - } - - if ((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) && hdd[id].wp) - { - scsi_hd_write_protected(id); - return; - } - - shdc[id].sector_len = (cdb[7] << 8) | cdb[8]; - shdc[id].sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - scsi_hd_log("SCSI HD %i: Length: %i, LBA: %i\n", id, shdc[id].sector_len, shdc[id].sector_pos); - - if ((shdc[id].sector_pos > last_sector) || ((shdc[id].sector_pos + shdc[id].sector_len - 1) > last_sector)) - { - scsi_hd_lba_out_of_range(id); - return; - } - - if ((!shdc[id].sector_len) || (*BufLen == 0)) - { - scsi_hd_set_phase(id, SCSI_PHASE_STATUS); - ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); - scsi_hd_log("SCSI HD %i: All done - callback set\n", id); - shdc[id].packet_status = CDROM_PHASE_COMPLETE; - shdc[id].callback = 20 * SCSI_TIME; - break; - } - - max_len = 1; - shdc[id].requested_blocks = max_len; - - alloc_length = shdc[id].packet_len = max_len << 9; - - if ((*BufLen == -1) || (alloc_length < *BufLen)) - { - *BufLen = alloc_length; - } - - scsi_hd_set_phase(id, SCSI_PHASE_DATA_OUT); - - if (shdc[id].requested_blocks > 1) - { - scsi_hd_data_command_finish(id, alloc_length, alloc_length / shdc[id].requested_blocks, alloc_length, 1); - } - else - { - scsi_hd_data_command_finish(id, alloc_length, alloc_length, alloc_length, 1); - } - shdc[id].all_blocks_total = shdc[id].block_total; - ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 1); - return; - - case GPCMD_MODE_SENSE_6: - case GPCMD_MODE_SENSE_10: - scsi_hd_set_phase(id, SCSI_PHASE_DATA_IN); - - block_desc = ((cdb[1] >> 3) & 1) ? 0 : 1; - - if (cdb[0] == GPCMD_MODE_SENSE_6) - len = cdb[4]; - else - len = (cdb[8] | (cdb[7] << 8)); - - shdc[id].current_page_code = cdb[2] & 0x3F; - - alloc_length = len; - - shdc[id].temp_buffer = (uint8_t *) malloc(65536); - memset(shdc[id].temp_buffer, 0, 65536); - - if (cdb[0] == GPCMD_MODE_SENSE_6) { - len = scsi_hd_mode_sense(id, shdc[id].temp_buffer, 4, cdb[2], block_desc); - if (len > alloc_length) - len = alloc_length; - shdc[id].temp_buffer[0] = len - 1; - shdc[id].temp_buffer[1] = 0; - if (block_desc) - shdc[id].temp_buffer[3] = 8; - } - else - { - len = scsi_hd_mode_sense(id, shdc[id].temp_buffer, 8, cdb[2], block_desc); - if (len > alloc_length) - len = alloc_length; - shdc[id].temp_buffer[0]=(len - 2) >> 8; - shdc[id].temp_buffer[1]=(len - 2) & 255; - shdc[id].temp_buffer[2] = 0; - if (block_desc) { - shdc[id].temp_buffer[6] = 0; - shdc[id].temp_buffer[7] = 8; - } - } + shdc[id].temp_buffer = (uint8_t *) malloc(65536); + memset(shdc[id].temp_buffer, 0, 65536); + if (cdb[0] == GPCMD_MODE_SENSE_6) { + len = scsi_hd_mode_sense(id, shdc[id].temp_buffer, 4, cdb[2], block_desc); if (len > alloc_length) len = alloc_length; - else if (len < alloc_length) - alloc_length = len; - - if ((*BufLen == -1) || (alloc_length < *BufLen)) - *BufLen = alloc_length; - - scsi_hd_log("SCSI HDD %i: Reading mode page: %02X...\n", id, cdb[2]); - - scsi_hd_data_command_finish(id, len, len, alloc_length, 0); - return; - - case GPCMD_MODE_SELECT_6: - case GPCMD_MODE_SELECT_10: - scsi_hd_set_phase(id, SCSI_PHASE_DATA_OUT); - - if (cdb[0] == GPCMD_MODE_SELECT_6) - len = cdb[4]; - else - len = (cdb[7] << 8) | cdb[8]; - - if ((*BufLen == -1) || (len < *BufLen)) - *BufLen = len; - - shdc[id].total_length = len; - shdc[id].do_page_save = cdb[1] & 1; - - shdc[id].current_page_pos = 0; - - scsi_hd_data_command_finish(id, len, len, len, 1); - return; - - case GPCMD_START_STOP_UNIT: - if (hdd[id].bus != HDD_BUS_SCSI_REMOVABLE) - { - scsi_hd_illegal_opcode(id); - break; + shdc[id].temp_buffer[0] = len - 1; + shdc[id].temp_buffer[1] = 0; + if (block_desc) + shdc[id].temp_buffer[3] = 8; + } else { + len = scsi_hd_mode_sense(id, shdc[id].temp_buffer, 8, cdb[2], block_desc); + if (len > alloc_length) + len = alloc_length; + shdc[id].temp_buffer[0]=(len - 2) >> 8; + shdc[id].temp_buffer[1]=(len - 2) & 255; + shdc[id].temp_buffer[2] = 0; + if (block_desc) { + shdc[id].temp_buffer[6] = 0; + shdc[id].temp_buffer[7] = 8; } + } - switch(cdb[4] & 3) - { - case 0: /* Stop the disc. */ - case 1: /* Start the disc and read the TOC. */ - break; - case 2: /* Eject the disc if possible. */ - removable_disk_eject(id); - break; - case 3: /* Load the disc (close tray). */ - removable_disk_reload(id); - break; - } + if (len > alloc_length) + len = alloc_length; + else if (len < alloc_length) + alloc_length = len; - scsi_hd_set_phase(id, SCSI_PHASE_STATUS); - scsi_hd_command_complete(id); - break; + if ((*BufLen == -1) || (alloc_length < *BufLen)) + *BufLen = alloc_length; - case GPCMD_INQUIRY: - max_len = cdb[3]; - max_len <<= 8; - max_len |= cdb[4]; + scsi_hd_log("SCSI HDD %i: Reading mode page: %02X...\n", id, cdb[2]); - if ((!max_len) || (*BufLen == 0)) - { - scsi_hd_set_phase(id, SCSI_PHASE_STATUS); - /* scsi_hd_log("SCSI HD %i: All done - callback set\n", id); */ - shdc[id].packet_status = CDROM_PHASE_COMPLETE; - shdc[id].callback = 20 * SCSI_TIME; - break; - } - - shdc[id].temp_buffer = malloc(1024); + scsi_hd_data_command_finish(id, len, len, alloc_length, 0); + return; - if (cdb[1] & 1) - { - preamble_len = 4; - size_idx = 3; - - shdc[id].temp_buffer[idx++] = 05; - shdc[id].temp_buffer[idx++] = cdb[2]; - shdc[id].temp_buffer[idx++] = 0; + case GPCMD_MODE_SELECT_6: + case GPCMD_MODE_SELECT_10: + scsi_hd_set_phase(id, SCSI_PHASE_DATA_OUT); - idx++; + if (cdb[0] == GPCMD_MODE_SELECT_6) + len = cdb[4]; + else + len = (cdb[7] << 8) | cdb[8]; - switch (cdb[2]) - { - case 0x00: - shdc[id].temp_buffer[idx++] = 0x00; - shdc[id].temp_buffer[idx++] = 0x83; - break; - case 0x83: - if (idx + 24 > max_len) - { - free(shdc[id].temp_buffer); - shdc[id].temp_buffer = NULL; - scsi_hd_data_phase_error(id); - return; - } + if ((*BufLen == -1) || (len < *BufLen)) + *BufLen = len; - shdc[id].temp_buffer[idx++] = 0x02; - shdc[id].temp_buffer[idx++] = 0x00; - shdc[id].temp_buffer[idx++] = 0x00; - shdc[id].temp_buffer[idx++] = 20; - ide_padstr8(shdc[id].temp_buffer + idx, 20, "53R141"); /* Serial */ - idx += 20; + shdc[id].total_length = len; + shdc[id].do_page_save = cdb[1] & 1; - if (idx + 72 > cdb[4]) - { - goto atapi_out; - } - shdc[id].temp_buffer[idx++] = 0x02; - shdc[id].temp_buffer[idx++] = 0x01; - shdc[id].temp_buffer[idx++] = 0x00; - shdc[id].temp_buffer[idx++] = 68; - ide_padstr8(shdc[id].temp_buffer + idx, 8, EMU_NAME); /* Vendor */ - idx += 8; - ide_padstr8(shdc[id].temp_buffer + idx, 40, device_identify_ex); /* Product */ - idx += 40; - ide_padstr8(shdc[id].temp_buffer + idx, 20, "53R141"); /* Product */ - idx += 20; - break; - default: - scsi_hd_log("INQUIRY: Invalid page: %02X\n", cdb[2]); - free(shdc[id].temp_buffer); - shdc[id].temp_buffer = NULL; - scsi_hd_invalid_field(id); - return; - } - } - else - { - preamble_len = 5; - size_idx = 4; + shdc[id].current_page_pos = 0; - memset(shdc[id].temp_buffer, 0, 8); - shdc[id].temp_buffer[0] = 0; /*SCSI HD*/ - if (hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) - { - shdc[id].temp_buffer[1] = 0x80; /*Removable*/ - } - else - { - shdc[id].temp_buffer[1] = 0; /*Fixed*/ - } - shdc[id].temp_buffer[2] = 0x02; /*SCSI-2 compliant*/ - shdc[id].temp_buffer[3] = 0x02; - shdc[id].temp_buffer[4] = 31; - shdc[id].temp_buffer[6] = 1; /* 16-bit transfers supported */ - shdc[id].temp_buffer[7] = 0x20; /* Wide bus supported */ + scsi_hd_data_command_finish(id, len, len, len, 1); + return; - ide_padstr8(shdc[id].temp_buffer + 8, 8, EMU_NAME); /* Vendor */ - ide_padstr8(shdc[id].temp_buffer + 16, 16, device_identify); /* Product */ - ide_padstr8(shdc[id].temp_buffer + 32, 4, EMU_VERSION); /* Revision */ - idx = 36; - - if (max_len == 96) { - shdc[id].temp_buffer[4] = 91; - idx = 96; - } - } - -atapi_out: - shdc[id].temp_buffer[size_idx] = idx - preamble_len; - len=idx; - - scsi_hd_log("scsi_hd_command(): Inquiry (%08X, %08X)\n", hdbufferb, shdc[id].temp_buffer); - - if (len > max_len) - { - len = max_len; - } - - if ((*BufLen == -1) || (len < *BufLen)) - { - *BufLen = len; - } - - if (len > *BufLen) - { - len = *BufLen; - } - - scsi_hd_set_phase(id, SCSI_PHASE_DATA_IN); - scsi_hd_data_command_finish(id, len, len, max_len, 0); - break; - - case GPCMD_PREVENT_REMOVAL: - scsi_hd_set_phase(id, SCSI_PHASE_STATUS); - scsi_hd_command_complete(id); - break; - - case GPCMD_SEEK_6: - case GPCMD_SEEK_10: - switch(cdb[0]) - { - case GPCMD_SEEK_6: - pos = (cdb[2] << 8) | cdb[3]; - break; - case GPCMD_SEEK_10: - pos = (cdb[2] << 24) | (cdb[3]<<16) | (cdb[4]<<8) | cdb[5]; - break; - } - scsi_hd_seek(id, pos); - - scsi_hd_set_phase(id, SCSI_PHASE_STATUS); - scsi_hd_command_complete(id); - break; - - case GPCMD_READ_CDROM_CAPACITY: - shdc[id].temp_buffer = (uint8_t *) malloc(8); - - if (scsi_hd_read_capacity(id, shdc[id].current_cdb, shdc[id].temp_buffer, &len) == 0) - { - scsi_hd_set_phase(id, SCSI_PHASE_STATUS); - return; - } - - if ((*BufLen == -1) || (len < *BufLen)) - { - *BufLen = len; - } - - scsi_hd_set_phase(id, SCSI_PHASE_DATA_IN); - scsi_hd_data_command_finish(id, len, len, len, 0); - break; - - default: + case GPCMD_START_STOP_UNIT: + if (hdd[id].bus != HDD_BUS_SCSI_REMOVABLE) { scsi_hd_illegal_opcode(id); break; - } - - /* scsi_hd_log("SCSI HD %i: Phase: %02X, request length: %i\n", shdc[id].phase, shdc[id].request_length); */ + } + + switch(cdb[4] & 3) { + case 0: /* Stop the disc. */ + case 1: /* Start the disc and read the TOC. */ + break; + case 2: /* Eject the disc if possible. */ + removable_disk_eject(id); + break; + case 3: /* Load the disc (close tray). */ + removable_disk_reload(id); + break; + } + + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + scsi_hd_command_complete(id); + break; + + case GPCMD_INQUIRY: + max_len = cdb[3]; + max_len <<= 8; + max_len |= cdb[4]; + + if ((!max_len) || (*BufLen == 0)) { + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + /* scsi_hd_log("SCSI HD %i: All done - callback set\n", id); */ + shdc[id].packet_status = CDROM_PHASE_COMPLETE; + shdc[id].callback = 20 * SCSI_TIME; + break; + } + + shdc[id].temp_buffer = malloc(1024); + + if (cdb[1] & 1) { + preamble_len = 4; + size_idx = 3; + + shdc[id].temp_buffer[idx++] = 05; + shdc[id].temp_buffer[idx++] = cdb[2]; + shdc[id].temp_buffer[idx++] = 0; + + idx++; + + switch (cdb[2]) { + case 0x00: + shdc[id].temp_buffer[idx++] = 0x00; + shdc[id].temp_buffer[idx++] = 0x83; + break; + case 0x83: + if (idx + 24 > max_len) { + free(shdc[id].temp_buffer); + shdc[id].temp_buffer = NULL; + scsi_hd_data_phase_error(id); + return; + } + + shdc[id].temp_buffer[idx++] = 0x02; + shdc[id].temp_buffer[idx++] = 0x00; + shdc[id].temp_buffer[idx++] = 0x00; + shdc[id].temp_buffer[idx++] = 20; + ide_padstr8(shdc[id].temp_buffer + idx, 20, "53R141"); /* Serial */ + idx += 20; + + if (idx + 72 > cdb[4]) { + goto atapi_out; + } + shdc[id].temp_buffer[idx++] = 0x02; + shdc[id].temp_buffer[idx++] = 0x01; + shdc[id].temp_buffer[idx++] = 0x00; + shdc[id].temp_buffer[idx++] = 68; + ide_padstr8(shdc[id].temp_buffer + idx, 8, EMU_NAME); /* Vendor */ + idx += 8; + ide_padstr8(shdc[id].temp_buffer + idx, 40, device_identify_ex); /* Product */ + idx += 40; + ide_padstr8(shdc[id].temp_buffer + idx, 20, "53R141"); /* Product */ + idx += 20; + break; + default: + scsi_hd_log("INQUIRY: Invalid page: %02X\n", cdb[2]); + free(shdc[id].temp_buffer); + shdc[id].temp_buffer = NULL; + scsi_hd_invalid_field(id); + return; + } + } else { + preamble_len = 5; + size_idx = 4; + + memset(shdc[id].temp_buffer, 0, 8); + shdc[id].temp_buffer[0] = 0; /*SCSI HD*/ + if (hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) { + shdc[id].temp_buffer[1] = 0x80; /*Removable*/ + } else { + shdc[id].temp_buffer[1] = 0; /*Fixed*/ + } + shdc[id].temp_buffer[2] = 0x02; /*SCSI-2 compliant*/ + shdc[id].temp_buffer[3] = 0x02; + shdc[id].temp_buffer[4] = 31; + shdc[id].temp_buffer[6] = 1; /* 16-bit transfers supported */ + shdc[id].temp_buffer[7] = 0x20; /* Wide bus supported */ + + ide_padstr8(shdc[id].temp_buffer + 8, 8, EMU_NAME); /* Vendor */ + ide_padstr8(shdc[id].temp_buffer + 16, 16, device_identify); /* Product */ + ide_padstr8(shdc[id].temp_buffer + 32, 4, EMU_VERSION); /* Revision */ + idx = 36; + + if (max_len == 96) { + shdc[id].temp_buffer[4] = 91; + idx = 96; + } + } + +atapi_out: + shdc[id].temp_buffer[size_idx] = idx - preamble_len; + len=idx; + + scsi_hd_log("scsi_hd_command(): Inquiry (%08X, %08X)\n", hdbufferb, shdc[id].temp_buffer); + + if (len > max_len) + len = max_len; + + if ((*BufLen == -1) || (len < *BufLen)) + *BufLen = len; + + if (len > *BufLen) + len = *BufLen; + + scsi_hd_set_phase(id, SCSI_PHASE_DATA_IN); + scsi_hd_data_command_finish(id, len, len, max_len, 0); + break; + + case GPCMD_PREVENT_REMOVAL: + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + scsi_hd_command_complete(id); + break; + + case GPCMD_SEEK_6: + case GPCMD_SEEK_10: + switch(cdb[0]) { + case GPCMD_SEEK_6: + pos = (cdb[2] << 8) | cdb[3]; + break; + case GPCMD_SEEK_10: + pos = (cdb[2] << 24) | (cdb[3]<<16) | (cdb[4]<<8) | cdb[5]; + break; + } + scsi_hd_seek(id, pos); + + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + scsi_hd_command_complete(id); + break; + + case GPCMD_READ_CDROM_CAPACITY: + shdc[id].temp_buffer = (uint8_t *) malloc(8); + + if (scsi_hd_read_capacity(id, shdc[id].current_cdb, shdc[id].temp_buffer, &len) == 0) { + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + return; + } + + if ((*BufLen == -1) || (len < *BufLen)) + *BufLen = len; + + scsi_hd_set_phase(id, SCSI_PHASE_DATA_IN); + scsi_hd_data_command_finish(id, len, len, len, 0); + break; + + default: + scsi_hd_illegal_opcode(id); + break; + } + + /* scsi_hd_log("SCSI HD %i: Phase: %02X, request length: %i\n", shdc[id].phase, shdc[id].request_length); */ } -void scsi_hd_phase_data_in(uint8_t id) +void +scsi_hd_phase_data_in(uint8_t id) { - uint8_t *hdbufferb = SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].CmdBuffer; - int32_t *BufLen = &SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].BufferLength; - - if (!*BufLen) - { - scsi_hd_log("scsi_hd_phase_data_in(): Buffer length is 0\n"); - scsi_hd_set_phase(id, SCSI_PHASE_STATUS); - ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); - - return; - } - - switch (shdc[id].current_cdb[0]) - { - case GPCMD_REQUEST_SENSE: - scsi_hd_log("SCSI HDD %i: %08X, %08X\n", id, hdbufferb, *BufLen); - scsi_hd_request_sense(id, hdbufferb, *BufLen, shdc[id].current_cdb[1] & 1); - break; - case GPCMD_MECHANISM_STATUS: - memset(hdbufferb, 0, *BufLen); - hdbufferb[5] = 1; - break; - case GPCMD_READ_6: - case GPCMD_READ_10: - case GPCMD_READ_12: - if ((shdc[id].requested_blocks > 0) && (*BufLen > 0)) - { - if (shdc[id].packet_len > *BufLen) - { - hdd_image_read(id, shdc[id].sector_pos, *BufLen >> 9, hdbufferb); - } - else - { - hdd_image_read(id, shdc[id].sector_pos, shdc[id].requested_blocks, hdbufferb); - } - } - break; - case GPCMD_MODE_SENSE_6: - case GPCMD_MODE_SENSE_10: - case GPCMD_INQUIRY: - case GPCMD_READ_CDROM_CAPACITY: - scsi_hd_log("scsi_hd_phase_data_in(): Filling buffer (%08X, %08X)\n", hdbufferb, shdc[id].temp_buffer); - memcpy(hdbufferb, shdc[id].temp_buffer, *BufLen); - free(shdc[id].temp_buffer); - shdc[id].temp_buffer = NULL; - scsi_hd_log("%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", - hdbufferb[0], hdbufferb[1], hdbufferb[2], hdbufferb[3], hdbufferb[4], hdbufferb[5], hdbufferb[6], hdbufferb[7], - hdbufferb[8], hdbufferb[9], hdbufferb[10], hdbufferb[11], hdbufferb[12], hdbufferb[13], hdbufferb[14], hdbufferb[15]); - break; - default: - fatal("SCSI HDD %i: Bad Command for phase 2 (%02X)\n", shdc[id].current_cdb[0]); - break; - } + uint8_t *hdbufferb = SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].CmdBuffer; + int32_t *BufLen = &SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].BufferLength; + if (!*BufLen) { + scsi_hd_log("scsi_hd_phase_data_in(): Buffer length is 0\n"); scsi_hd_set_phase(id, SCSI_PHASE_STATUS); ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); + + return; + } + + switch (shdc[id].current_cdb[0]) { + case GPCMD_REQUEST_SENSE: + scsi_hd_log("SCSI HDD %i: %08X, %08X\n", id, hdbufferb, *BufLen); + scsi_hd_request_sense(id, hdbufferb, *BufLen, shdc[id].current_cdb[1] & 1); + break; + case GPCMD_MECHANISM_STATUS: + memset(hdbufferb, 0, *BufLen); + hdbufferb[5] = 1; + break; + case GPCMD_READ_6: + case GPCMD_READ_10: + case GPCMD_READ_12: + if ((shdc[id].requested_blocks > 0) && (*BufLen > 0)) { + if (shdc[id].packet_len > *BufLen) { + hdd_image_read(id, shdc[id].sector_pos, *BufLen >> 9, hdbufferb); + } else { + hdd_image_read(id, shdc[id].sector_pos, shdc[id].requested_blocks, hdbufferb); + } + } + break; + case GPCMD_MODE_SENSE_6: + case GPCMD_MODE_SENSE_10: + case GPCMD_INQUIRY: + case GPCMD_READ_CDROM_CAPACITY: + scsi_hd_log("scsi_hd_phase_data_in(): Filling buffer (%08X, %08X)\n", hdbufferb, shdc[id].temp_buffer); + memcpy(hdbufferb, shdc[id].temp_buffer, *BufLen); + free(shdc[id].temp_buffer); + shdc[id].temp_buffer = NULL; + scsi_hd_log("%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", + hdbufferb[0], hdbufferb[1], hdbufferb[2], hdbufferb[3], hdbufferb[4], hdbufferb[5], hdbufferb[6], hdbufferb[7], + hdbufferb[8], hdbufferb[9], hdbufferb[10], hdbufferb[11], hdbufferb[12], hdbufferb[13], hdbufferb[14], hdbufferb[15]); + break; + default: + fatal("SCSI HDD %i: Bad Command for phase 2 (%02X)\n", shdc[id].current_cdb[0]); + break; + } + + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); } -void scsi_hd_phase_data_out(uint8_t id) + +void +scsi_hd_phase_data_out(uint8_t id) { - uint8_t *hdbufferb = SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].CmdBuffer; + uint8_t *hdbufferb = SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].CmdBuffer; + int i; + int32_t *BufLen = &SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].BufferLength; + uint32_t last_sector = hdd_image_get_last_sector(id); + uint32_t last_to_write = 0; + uint32_t c, h, s; + uint16_t block_desc_len; + uint16_t pos; + uint8_t error = 0; + uint8_t page, page_len; + uint8_t hdr_len, val, old_val, ch; - int i; + if (!*BufLen) { + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); - int32_t *BufLen = &SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].BufferLength; + return; + } - uint32_t last_sector = hdd_image_get_last_sector(id); - uint32_t last_to_write = 0; - - uint32_t c, h, s; - - uint16_t block_desc_len; - uint16_t pos; - - uint8_t error = 0; - uint8_t page, page_len; - - uint8_t hdr_len, val, old_val, ch; - - if (!*BufLen) - { - scsi_hd_set_phase(id, SCSI_PHASE_STATUS); - ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); - - return; - } - - switch (shdc[id].current_cdb[0]) - { - case GPCMD_VERIFY_6: - case GPCMD_VERIFY_10: - case GPCMD_VERIFY_12: - break; - case GPCMD_WRITE_6: - case GPCMD_WRITE_10: - case GPCMD_WRITE_AND_VERIFY_10: - case GPCMD_WRITE_12: - case GPCMD_WRITE_AND_VERIFY_12: - if ((shdc[id].requested_blocks > 0) && (*BufLen > 0)) - { - if (shdc[id].packet_len > *BufLen) - { - hdd_image_write(id, shdc[id].sector_pos, *BufLen >> 9, hdbufferb); - } - else - { - hdd_image_write(id, shdc[id].sector_pos, shdc[id].requested_blocks, hdbufferb); - } - } - break; - case GPCMD_WRITE_SAME_10: - if (!shdc[id].current_cdb[7] && !shdc[id].current_cdb[8]) - last_to_write = last_sector; - else - last_to_write = shdc[id].sector_pos + shdc[id].sector_len - 1; - - for (i = shdc[id].sector_pos; i <= last_to_write; i++) { - if (shdc[id].current_cdb[1] & 2) { - hdbufferb[0] = (i >> 24) & 0xff; - hdbufferb[1] = (i >> 16) & 0xff; - hdbufferb[2] = (i >> 8) & 0xff; - hdbufferb[3] = i & 0xff; - } else if (shdc[id].current_cdb[1] & 4) { - s = (i % hdd[id].spt); - h = ((i - s) / hdd[id].spt) % hdd[id].hpc; - c = ((i - s) / hdd[id].spt) / hdd[id].hpc; - hdbufferb[0] = (c >> 16) & 0xff; - hdbufferb[1] = (c >> 8) & 0xff; - hdbufferb[2] = c & 0xff; - hdbufferb[3] = h & 0xff; - hdbufferb[4] = (s >> 24) & 0xff; - hdbufferb[5] = (s >> 16) & 0xff; - hdbufferb[6] = (s >> 8) & 0xff; - hdbufferb[7] = s & 0xff; - } - hdd_image_write(id, i, 1, hdbufferb); - } - break; - case GPCMD_MODE_SELECT_6: - case GPCMD_MODE_SELECT_10: - if (shdc[id].current_cdb[0] == GPCMD_MODE_SELECT_10) - hdr_len = 8; - else - hdr_len = 4; - - if (shdc[id].current_cdb[0] == GPCMD_MODE_SELECT_6) { - block_desc_len = hdbufferb[2]; - block_desc_len <<= 8; - block_desc_len |= hdbufferb[3]; + switch (shdc[id].current_cdb[0]) { + case GPCMD_VERIFY_6: + case GPCMD_VERIFY_10: + case GPCMD_VERIFY_12: + break; + case GPCMD_WRITE_6: + case GPCMD_WRITE_10: + case GPCMD_WRITE_AND_VERIFY_10: + case GPCMD_WRITE_12: + case GPCMD_WRITE_AND_VERIFY_12: + if ((shdc[id].requested_blocks > 0) && (*BufLen > 0)) { + if (shdc[id].packet_len > *BufLen) { + hdd_image_write(id, shdc[id].sector_pos, *BufLen >> 9, hdbufferb); } else { - block_desc_len = hdbufferb[6]; - block_desc_len <<= 8; - block_desc_len |= hdbufferb[7]; + hdd_image_write(id, shdc[id].sector_pos, shdc[id].requested_blocks, hdbufferb); } + } + break; + case GPCMD_WRITE_SAME_10: + if (!shdc[id].current_cdb[7] && !shdc[id].current_cdb[8]) + last_to_write = last_sector; + else + last_to_write = shdc[id].sector_pos + shdc[id].sector_len - 1; - pos = hdr_len + block_desc_len; + for (i = shdc[id].sector_pos; i <= last_to_write; i++) { + if (shdc[id].current_cdb[1] & 2) { + hdbufferb[0] = (i >> 24) & 0xff; + hdbufferb[1] = (i >> 16) & 0xff; + hdbufferb[2] = (i >> 8) & 0xff; + hdbufferb[3] = i & 0xff; + } else if (shdc[id].current_cdb[1] & 4) { + s = (i % hdd[id].spt); + h = ((i - s) / hdd[id].spt) % hdd[id].hpc; + c = ((i - s) / hdd[id].spt) / hdd[id].hpc; + hdbufferb[0] = (c >> 16) & 0xff; + hdbufferb[1] = (c >> 8) & 0xff; + hdbufferb[2] = c & 0xff; + hdbufferb[3] = h & 0xff; + hdbufferb[4] = (s >> 24) & 0xff; + hdbufferb[5] = (s >> 16) & 0xff; + hdbufferb[6] = (s >> 8) & 0xff; + hdbufferb[7] = s & 0xff; + } + hdd_image_write(id, i, 1, hdbufferb); + } + break; + case GPCMD_MODE_SELECT_6: + case GPCMD_MODE_SELECT_10: + if (shdc[id].current_cdb[0] == GPCMD_MODE_SELECT_10) + hdr_len = 8; + else + hdr_len = 4; - while(1) { - page = hdbufferb[pos] & 0x3F; - page_len = hdbufferb[pos + 1]; + if (shdc[id].current_cdb[0] == GPCMD_MODE_SELECT_6) { + block_desc_len = hdbufferb[2]; + block_desc_len <<= 8; + block_desc_len |= hdbufferb[3]; + } else { + block_desc_len = hdbufferb[6]; + block_desc_len <<= 8; + block_desc_len |= hdbufferb[7]; + } - pos += 2; + pos = hdr_len + block_desc_len; - if (!(scsi_hd_mode_sense_page_flags & (1LL << ((uint64_t) page)))) - error |= 1; - else { - for (i = 0; i < page_len; i++) { - ch = scsi_hd_mode_sense_pages_changeable.pages[page][i + 2]; - val = hdbufferb[pos + i]; - old_val = scsi_hd_mode_sense_pages_saved[id].pages[page][i + 2]; - if (val != old_val) { - if (ch) - scsi_hd_mode_sense_pages_saved[id].pages[page][i + 2] = val; - else - error |= 1; - } + while(1) { + page = hdbufferb[pos] & 0x3F; + page_len = hdbufferb[pos + 1]; + + pos += 2; + + if (!(scsi_hd_mode_sense_page_flags & (1LL << ((uint64_t) page)))) + error |= 1; + else { + for (i = 0; i < page_len; i++) { + ch = scsi_hd_mode_sense_pages_changeable.pages[page][i + 2]; + val = hdbufferb[pos + i]; + old_val = scsi_hd_mode_sense_pages_saved[id].pages[page][i + 2]; + if (val != old_val) { + if (ch) + scsi_hd_mode_sense_pages_saved[id].pages[page][i + 2] = val; + else + error |= 1; } } - - pos += page_len; - - val = scsi_hd_mode_sense_pages_default.pages[page][0] & 0x80; - if (shdc[id].do_page_save && val) - scsi_hd_mode_sense_save(id); - - if (pos >= shdc[id].total_length) - break; } - if (error) - scsi_hd_invalid_field_pl(id); - break; - default: - fatal("SCSI HDD %i: Bad Command for phase 2 (%02X)\n", shdc[id].current_cdb[0]); - break; - } + pos += page_len; - scsi_hd_set_phase(id, SCSI_PHASE_STATUS); - ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); + val = scsi_hd_mode_sense_pages_default.pages[page][0] & 0x80; + if (shdc[id].do_page_save && val) + scsi_hd_mode_sense_save(id); + + if (pos >= shdc[id].total_length) + break; + } + + if (error) + scsi_hd_invalid_field_pl(id); + break; + default: + fatal("SCSI HDD %i: Bad Command for phase 2 (%02X)\n", shdc[id].current_cdb[0]); + break; + } + + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); } + /* If the result is 1, issue an IRQ, otherwise not. */ -void scsi_hd_callback(uint8_t id) +void +scsi_hd_callback(uint8_t id) { - switch(shdc[id].packet_status) - { - case CDROM_PHASE_IDLE: - scsi_hd_log("SCSI HD %i: PHASE_IDLE\n", id); - shdc[id].pos=0; - shdc[id].phase = 1; - shdc[id].status = READY_STAT | DRQ_STAT | (shdc[id].status & ERR_STAT); - return; - case CDROM_PHASE_COMPLETE: - scsi_hd_log("SCSI HD %i: PHASE_COMPLETE\n", id); - shdc[id].status = READY_STAT; - shdc[id].phase = 3; - shdc[id].packet_status = 0xFF; - ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); - return; - case CDROM_PHASE_DATA_OUT: - scsi_hd_log("SCSI HD %i: PHASE_DATA_OUT\n", id); - shdc[id].status = READY_STAT | DRQ_STAT | (shdc[id].status & ERR_STAT); - shdc[id].phase = 0; - return; - case CDROM_PHASE_DATA_OUT_DMA: - scsi_hd_log("SCSI HD %i: PHASE_DATA_OUT_DMA\n", id); - scsi_hd_phase_data_out(id); - shdc[id].packet_status = CDROM_PHASE_COMPLETE; - shdc[id].status = READY_STAT; - shdc[id].phase = 3; - ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); - return; - case CDROM_PHASE_DATA_IN: - scsi_hd_log("SCSI HD %i: PHASE_DATA_IN\n", id); - shdc[id].status = READY_STAT | DRQ_STAT | (shdc[id].status & ERR_STAT); - shdc[id].phase = 2; - return; - case CDROM_PHASE_DATA_IN_DMA: - scsi_hd_log("SCSI HD %i: PHASE_DATA_IN_DMA\n", id); - scsi_hd_phase_data_in(id); - shdc[id].packet_status = CDROM_PHASE_COMPLETE; - shdc[id].status = READY_STAT; - shdc[id].phase = 3; - ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); - return; - case CDROM_PHASE_ERROR: - scsi_hd_log("SCSI HD %i: PHASE_ERROR\n", id); - shdc[id].status = READY_STAT | ERR_STAT; - shdc[id].phase = 3; - return; - } + switch(shdc[id].packet_status) { + case CDROM_PHASE_IDLE: + scsi_hd_log("SCSI HD %i: PHASE_IDLE\n", id); + shdc[id].pos=0; + shdc[id].phase = 1; + shdc[id].status = READY_STAT | DRQ_STAT | (shdc[id].status & ERR_STAT); + return; + case CDROM_PHASE_COMPLETE: + scsi_hd_log("SCSI HD %i: PHASE_COMPLETE\n", id); + shdc[id].status = READY_STAT; + shdc[id].phase = 3; + shdc[id].packet_status = 0xFF; + ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); + return; + case CDROM_PHASE_DATA_OUT: + scsi_hd_log("SCSI HD %i: PHASE_DATA_OUT\n", id); + shdc[id].status = READY_STAT | DRQ_STAT | (shdc[id].status & ERR_STAT); + shdc[id].phase = 0; + return; + case CDROM_PHASE_DATA_OUT_DMA: + scsi_hd_log("SCSI HD %i: PHASE_DATA_OUT_DMA\n", id); + scsi_hd_phase_data_out(id); + shdc[id].packet_status = CDROM_PHASE_COMPLETE; + shdc[id].status = READY_STAT; + shdc[id].phase = 3; + ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); + return; + case CDROM_PHASE_DATA_IN: + scsi_hd_log("SCSI HD %i: PHASE_DATA_IN\n", id); + shdc[id].status = READY_STAT | DRQ_STAT | (shdc[id].status & ERR_STAT); + shdc[id].phase = 2; + return; + case CDROM_PHASE_DATA_IN_DMA: + scsi_hd_log("SCSI HD %i: PHASE_DATA_IN_DMA\n", id); + scsi_hd_phase_data_in(id); + shdc[id].packet_status = CDROM_PHASE_COMPLETE; + shdc[id].status = READY_STAT; + shdc[id].phase = 3; + ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); + return; + case CDROM_PHASE_ERROR: + scsi_hd_log("SCSI HD %i: PHASE_ERROR\n", id); + shdc[id].status = READY_STAT | ERR_STAT; + shdc[id].phase = 3; + return; + } } diff --git a/src/scsi/scsi_ncr5380.c b/src/scsi/scsi_ncr5380.c index 026da40..24b8d4c 100644 --- a/src/scsi/scsi_ncr5380.c +++ b/src/scsi/scsi_ncr5380.c @@ -9,7 +9,7 @@ * Implementation of the NCR 5380 series of SCSI Host Adapters * made by NCR. These controllers were designed for the ISA bus. * - * Version: @(#)scsi_ncr5380.c 1.0.2 2018/02/22 + * Version: @(#)scsi_ncr5380.c 1.0.3 2018/03/08 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -409,7 +409,7 @@ dma_callback(void *priv) int bytes_transferred = 0; int c; - scsi->dma_timer += POLL_TIME_US; + scsi->dma_timer += POLL_TIME_US * TIMER_USEC; switch (scsi->ncr.dma_mode) { case DMA_SEND: diff --git a/src/scsi/scsi_ncr53c810.c b/src/scsi/scsi_ncr53c810.c index ab8bb6c..3a441f0 100644 --- a/src/scsi/scsi_ncr53c810.c +++ b/src/scsi/scsi_ncr53c810.c @@ -10,7 +10,7 @@ * NCR and later Symbios and LSI. This controller was designed * for the PCI bus. * - * Version: @(#)scsi_ncr53c810.c 1.0.2 2018/02/21 + * Version: @(#)scsi_ncr53c810.c 1.0.3 2018/03/08 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -289,6 +289,9 @@ typedef struct { uint8_t regop; uint32_t adder; + + int64_t timer_period; + int64_t timer_enabled; } ncr53c810_t; @@ -349,6 +352,8 @@ static void ncr53c810_soft_reset(ncr53c810_t *dev) { ncr53c810_log("LSI Reset\n"); + dev->timer_period = dev->timer_enabled = 0; + dev->carry = 0; dev->msg_action = 0; @@ -519,6 +524,7 @@ ncr53c810_script_scsi_interrupt(ncr53c810_t *dev, int stat0, int stat1) if ((dev->sist0 & mask0) || (dev->sist1 & mask1)) { ncr53c810_log("NCR 810: IRQ-mandated stop\n"); dev->sstop = 1; + dev->timer_period = dev->timer_enabled = 0; } ncr53c810_update_irq(dev); } @@ -532,6 +538,7 @@ ncr53c810_script_dma_interrupt(ncr53c810_t *dev, int stat) dev->dstat |= stat; ncr53c810_update_irq(dev); dev->sstop = 1; + dev->timer_period = dev->timer_enabled = 0; } @@ -549,6 +556,7 @@ ncr53c810_bad_phase(ncr53c810_t *dev, int out, int new_phase) ncr53c810_log("Phase mismatch interrupt\n"); ncr53c810_script_scsi_interrupt(dev, NCR_SIST0_MA, 0); dev->sstop = 1; + dev->timer_period = dev->timer_enabled = 0; ncr53c810_set_phase(dev, new_phase); } @@ -672,6 +680,7 @@ ncr53c810_do_command(ncr53c810_t *dev, uint8_t id) { scsi_device_t *sd; uint8_t buf[12]; + double period; memset(buf, 0, 12); DMAPageRead(dev->dnad, buf, MIN(12, dev->dbc)); @@ -713,9 +722,19 @@ ncr53c810_do_command(ncr53c810_t *dev, uint8_t id) if ((sd->Phase == SCSI_PHASE_DATA_IN) && (sd->BufferLength > 0)) { ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: PHASE_DI\n", id, dev->current_lun, buf[0]); ncr53c810_set_phase(dev, PHASE_DI); + dev->timer_period = scsi_device_get_callback(dev->current->tag, dev->current_lun); + if (dev->timer_period <= 0LL) { + period = ((double) sd->BufferLength) * 0.2 * ((double) TIMER_USEC); /* Fast SCSI: 10000000 bytes per second */ + dev->timer_period = (int64_t) period; + } } else if ((sd->Phase == SCSI_PHASE_DATA_OUT) && (sd->BufferLength > 0)) { ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: PHASE_DO\n", id, dev->current_lun, buf[0]); ncr53c810_set_phase(dev, PHASE_DO); + dev->timer_period = scsi_device_get_callback(dev->current->tag, dev->current_lun); + if (dev->timer_period <= 0LL) { + period = ((double) sd->BufferLength) * 0.2 * ((double) TIMER_USEC); /* Fast SCSI: 10000000 bytes per second */ + dev->timer_period = (int64_t) period; + } } else ncr53c810_command_complete(dev, sd->Status); } @@ -930,7 +949,7 @@ ncr53c810_memcpy(ncr53c810_t *dev, uint32_t dest, uint32_t src, int count) static void -ncr53c810_execute_script(ncr53c810_t *dev) +ncr53c810_process_script(ncr53c810_t *dev) { uint32_t insn, addr, id, buf[2], dest; int opcode, insn_processed = 0, reg, operator, cond, jmp, n, i; @@ -959,6 +978,7 @@ again: if (dev->sist1 & NCR_SIST1_STO) { ncr53c810_log("Delayed select timeout\n"); dev->sstop = 1; + dev->timer_period = dev->timer_enabled = 0; break; } ncr53c810_log("Block Move DBC=%d\n", dev->dbc); @@ -1004,7 +1024,9 @@ again: case PHASE_CMD: ncr53c810_log("Command Phase\n"); ncr53c810_do_command(dev, dev->sdid); - break; + dev->dfifo = dev->dbc & 0xff; + dev->ctest5 = (dev->ctest5 & 0xfc) | ((dev->dbc >> 8) & 3); + return; case PHASE_ST: ncr53c810_log("Status Phase\n"); ncr53c810_do_status(dev); @@ -1176,6 +1198,7 @@ again: if (dev->sist1 & NCR_SIST1_STO) { ncr53c810_log("Delayed select timeout\n"); dev->sstop = 1; + dev->timer_period = dev->timer_enabled = 0; break; } cond = jmp = (insn & (1 << 19)) != 0; @@ -1285,7 +1308,8 @@ again: ncr53c810_script_dma_interrupt(dev, NCR_DSTAT_SSI); } else { ncr53c810_log("NCR 810: SCRIPTS: Normal mode\n"); - goto again; + if (insn_processed < 100) + goto again; } } else { if (dev->sstop) @@ -1298,6 +1322,35 @@ again: } +static void +ncr53c810_execute_script(ncr53c810_t *dev) +{ + dev->timer_period = 10LL * TIMER_USEC; + dev->timer_enabled = 1; +} + + +static void +ncr53c810_callback(void *p) +{ + ncr53c810_t *dev = (ncr53c810_t *) p; + + dev->timer_period = 0; + if (!dev->waiting) + ncr53c810_process_script(dev); + + if (dev->sstop) { + dev->timer_period = 0; + dev->timer_enabled = 0; + return; + } else + dev->timer_enabled = 1; + + if (dev->timer_period == 0) + dev->timer_period = 50LL * TIMER_USEC; +} + + static void ncr53c810_reg_writeb(ncr53c810_t *dev, uint32_t offset, uint8_t val) { @@ -1400,7 +1453,9 @@ ncr53c810_reg_writeb(ncr53c810_t *dev, uint32_t offset, uint8_t val) ncr53c810_log("Woken by SIGP\n"); dev->waiting = 0; dev->dsp = dev->dnad; +#if 0 ncr53c810_execute_script(dev); +#endif } if ((val & NCR_ISTAT_SRST) && !(tmp & NCR_ISTAT_SRST)) { ncr53c810_soft_reset(dev); @@ -2099,6 +2154,9 @@ ncr53c810_init(device_t *info) ncr53c810_soft_reset(dev); + timer_add(ncr53c810_callback, + &dev->timer_period, &dev->timer_enabled, dev); + return(dev); } diff --git a/src/scsi/scsi_x54x.c b/src/scsi/scsi_x54x.c index c984d27..604f770 100644 --- a/src/scsi/scsi_x54x.c +++ b/src/scsi/scsi_x54x.c @@ -12,7 +12,7 @@ * * These controllers were designed for various buses. * - * Version: @(#)scsi_x54x.c 1.0.5 2018/03/04 + * Version: @(#)scsi_x54x.c 1.0.6 2018/03/08 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -39,6 +39,7 @@ * Boston, MA 02111-1307 * USA. */ +#include #include #include #include @@ -67,26 +68,9 @@ #define X54X_RESET_DURATION_US UINT64_C(50000) +static void x54x_cmd_callback(void *priv); -static void x54x_cmd_thread(void *priv); - -static volatile -thread_t *poll_tid; -static volatile -int busy; - -static volatile -event_t *evt; -static volatile -event_t *wait_evt; - -static volatile -event_t *wake_poll_thread; -static volatile -event_t *thread_started; - -static volatile -x54x_t *x54x_dev; +static x54x_t *x54x_dev; #ifdef ENABLE_X54X_LOG @@ -629,6 +613,13 @@ x54x_cmd_done(x54x_t *dev, int suppress) } +static void +x54x_add_to_period(int TransferLength) +{ + x54x_dev->temp_period += (int64_t)TransferLength; +} + + static void x54x_mbi_setup(x54x_t *dev, uint32_t CCBPointer, CCBU *CmdBlock, uint8_t HostStatus, uint8_t TargetStatus, uint8_t mbcc) @@ -656,6 +647,7 @@ x54x_ccb(x54x_t *dev) DMAPageWrite(req->CCBPointer + 0x000D, &(req->MailboxCompletionCode), 1); DMAPageWrite(req->CCBPointer + 0x000E, &(req->HostStatus), 1); DMAPageWrite(req->CCBPointer + 0x000F, &(req->TargetStatus), 1); + x54x_add_to_period(3); if (dev->MailboxOutInterrupts) dev->ToRaise = INTR_MBOA | INTR_ANY; @@ -668,7 +660,6 @@ static void x54x_mbi(x54x_t *dev) { Req_t *req = &dev->Req; -// uint32_t CCBPointer = req->CCBPointer; addr24 CCBPointer; CCBU *CmdBlock = &(req->CmdBlock); uint8_t HostStatus = req->HostStatus; @@ -686,6 +677,7 @@ x54x_mbi(x54x_t *dev) x54x_log("CCB statuses rewritten (pointer %08X)\n", req->CCBPointer); DMAPageWrite(req->CCBPointer + 0x000E, &(req->HostStatus), 1); DMAPageWrite(req->CCBPointer + 0x000F, &(req->TargetStatus), 1); + x54x_add_to_period(2); } else { x54x_log("Mailbox not found!\n"); } @@ -697,6 +689,7 @@ x54x_mbi(x54x_t *dev) x54x_log("Mailbox 24-bit: Status=0x%02X, CCB at 0x%04X\n", req->MailboxCompletionCode, CCBPointer); DMAPageWrite(Incoming, &(req->MailboxCompletionCode), 1); DMAPageWrite(Incoming + 1, (uint8_t *)&CCBPointer, 3); + x54x_add_to_period(4); x54x_log("%i bytes of 24-bit mailbox written to: %08X\n", sizeof(Mailbox_t), Incoming); } else { U32_TO_ADDR(CCBPointer, req->CCBPointer); @@ -705,6 +698,7 @@ x54x_mbi(x54x_t *dev) DMAPageWrite(Incoming + 4, &(req->HostStatus), 1); DMAPageWrite(Incoming + 5, &(req->TargetStatus), 1); DMAPageWrite(Incoming + 7, &(req->MailboxCompletionCode), 1); + x54x_add_to_period(7); x54x_log("%i bytes of 32-bit mailbox written to: %08X\n", sizeof(Mailbox32_t), Incoming); } @@ -725,13 +719,15 @@ x54x_rd_sge(int Is24bit, uint32_t Address, SGE32 *SG) if (Is24bit) { DMAPageRead(Address, (uint8_t *)&SGE24, sizeof(SGE)); + x54x_add_to_period(sizeof(SGE)); /* Convert the 24-bit entries into 32-bit entries. */ x54x_log("Read S/G block: %06X, %06X\n", SGE24.Segment, SGE24.SegmentPointer); SG->Segment = ADDR_TO_U32(SGE24.Segment); SG->SegmentPointer = ADDR_TO_U32(SGE24.SegmentPointer); } else { - DMAPageRead(Address, (uint8_t *)SG, sizeof(SGE32)); + DMAPageRead(Address, (uint8_t *)SG, sizeof(SGE32)); + x54x_add_to_period(sizeof(SGE32)); } } @@ -799,9 +795,11 @@ x54x_set_residue(Req_t *req, int32_t TransferLength) if (req->Is24bit) { U32_TO_ADDR(Residue24, Residue); DMAPageWrite(req->CCBPointer + 0x0004, (uint8_t *)&Residue24, 3); + x54x_add_to_period(3); x54x_log("24-bit Residual data length for reading: %d\n", Residue); } else { DMAPageWrite(req->CCBPointer + 0x0004, (uint8_t *)&Residue, 4); + x54x_add_to_period(4); x54x_log("32-bit Residual data length for reading: %d\n", Residue); } } @@ -853,9 +851,8 @@ x54x_buf_dma_transfer(Req_t *req, int Is24bit, int TransferLength, int dir) x54x_log("Writing S/G segment %i: length %i, pointer %08X\n", i, DataToTransfer, Address); DMAPageWrite(Address, &(SCSIDevices[req->TargetID][req->LUN].CmdBuffer[sg_pos]), DataToTransfer); } - else { + else x54x_log("No action on S/G segment %i: length %i, pointer %08X\n", i, DataToTransfer, Address); - } sg_pos += SGBuffer.Segment; @@ -871,11 +868,10 @@ x54x_buf_dma_transfer(Req_t *req, int Is24bit, int TransferLength, int dir) Address = DataPointer; if ((DataLength > 0) && (BufLen > 0) && (req->CmdBlock.common.ControlByte < 0x03)) { - if (read_from_host) { + if (read_from_host) DMAPageRead(Address, SCSIDevices[req->TargetID][req->LUN].CmdBuffer, MIN(BufLen, DataLength)); - } else if (write_to_host) { + else if (write_to_host) DMAPageWrite(Address, SCSIDevices[req->TargetID][req->LUN].CmdBuffer, MIN(BufLen, DataLength)); - } } } } @@ -959,6 +955,7 @@ SenseBufferFree(Req_t *req, int Copy) x54x_log("SenseBufferFree(): Writing %i bytes at %08X\n", SenseLength, SenseBufferAddress); DMAPageWrite(SenseBufferAddress, temp_sense, SenseLength); + x54x_add_to_period(SenseLength); x54x_log("Sense data written to buffer: %02X %02X %02X\n", temp_sense[2], temp_sense[12], temp_sense[13]); } @@ -978,6 +975,7 @@ x54x_scsi_cmd(x54x_t *dev) int32_t *BufLen; uint8_t phase; uint32_t SenseBufferAddress; + int64_t p; id = req->TargetID; lun = req->LUN; @@ -1000,8 +998,10 @@ x54x_scsi_cmd(x54x_t *dev) if (req->CmdBlock.common.CdbLength <= target_cdb_len) { memcpy(temp_cdb, req->CmdBlock.common.Cdb, req->CmdBlock.common.CdbLength); + x54x_add_to_period(req->CmdBlock.common.CdbLength); } else { memcpy(temp_cdb, req->CmdBlock.common.Cdb, target_cdb_len); + x54x_add_to_period(target_cdb_len); } dev->Residue = 0; @@ -1026,8 +1026,14 @@ x54x_scsi_cmd(x54x_t *dev) if ((SCSIDevices[id][lun].Status != SCSI_STATUS_OK) && (*BufLen > 0)) { SenseBufferAddress = SenseBufferPointer(req); DMAPageWrite(SenseBufferAddress, SCSIDevices[id][lun].CmdBuffer, *BufLen); + x54x_add_to_period(*BufLen); } } else { + p = scsi_device_get_callback(id, lun); + if (p <= 0LL) + x54x_add_to_period(*BufLen); + else + dev->media_period += p; x54x_buf_alloc(id, lun, MIN(target_data_len, *BufLen)); if (phase == SCSI_PHASE_DATA_OUT) x54x_buf_dma_transfer(req, bit24, target_data_len, 1); @@ -1055,10 +1061,6 @@ x54x_scsi_cmd(x54x_t *dev) } x54x_log("SCSIDevices[%02i][%02i].Status = %02X\n", id, lun, SCSIDevices[id][lun].Status); - - if (temp_cdb[0] == 0x42) { - thread_wait_event((event_t *) evt, 10); - } } @@ -1156,6 +1158,7 @@ x54x_req_abort(x54x_t *dev, uint32_t CCBPointer) /* Fetch data from the Command Control Block. */ DMAPageRead(CCBPointer, (uint8_t *)&CmdBlock, sizeof(CCB32)); + x54x_add_to_period(sizeof(CCB32)); x54x_mbi_setup(dev, CCBPointer, &CmdBlock, 0x26, SCSI_STATUS_OK, MBI_NOT_FOUND); @@ -1184,6 +1187,7 @@ x54x_mbo(x54x_t *dev, Mailbox32_t *Mailbox32) if (dev->Mbx24bit) { Outgoing = Addr + (Cur * sizeof(Mailbox_t)); DMAPageRead(Outgoing, (uint8_t *)&MailboxOut, sizeof(Mailbox_t)); + x54x_add_to_period(sizeof(Mailbox_t)); ccbp = *(uint32_t *) &MailboxOut; Mailbox32->CCBPointer = (ccbp >> 24) | ((ccbp >> 8) & 0xff00) | ((ccbp << 8) & 0xff0000); @@ -1192,6 +1196,7 @@ x54x_mbo(x54x_t *dev, Mailbox32_t *Mailbox32) Outgoing = Addr + (Cur * sizeof(Mailbox32_t)); DMAPageRead(Outgoing, (uint8_t *)Mailbox32, sizeof(Mailbox32_t)); + x54x_add_to_period(sizeof(Mailbox32_t)); } return(Outgoing); @@ -1224,14 +1229,11 @@ x54x_mbo_process(x54x_t *dev) /* We got the mailbox, mark it as free in the guest. */ x54x_log("x54x_do_mail(): Writing %i bytes at %08X\n", sizeof(CmdStatus), Outgoing + CodeOffset); DMAPageWrite(Outgoing + CodeOffset, &CmdStatus, 1); + x54x_add_to_period(1); - if (dev->ToRaise) { + if (dev->ToRaise) raise_irq(dev, 0, dev->ToRaise); - while (dev->Interrupt) - ; - } - if (dev->MailboxIsBIOS) dev->BIOSMailboxReq--; else @@ -1285,84 +1287,29 @@ static void x54x_cmd_done(x54x_t *dev, int suppress); -void -x54x_wait_for_poll(void) -{ - if (x54x_is_busy()) { - thread_wait_event((event_t *) wake_poll_thread, -1); - } - thread_reset_event((event_t *) wake_poll_thread); -} - - static void -x54x_cmd_thread(void *priv) +x54x_cmd_callback(void *priv) { x54x_t *dev = (x54x_t *) x54x_dev; + double period; - thread_set_event((event_t *) thread_started); - - x54x_log("Polling thread started\n"); - - while (x54x_dev) { - scsi_mutex_wait(1); - - if ((dev->Status & STAT_INIT) || (!dev->MailboxInit && !dev->BIOSMailboxInit) || (!dev->MailboxReq && !dev->BIOSMailboxReq)) { - /* If we did not get anything, wait a while. */ - thread_wait_event((event_t *)wait_evt, 10); - thread_reset_event((event_t *)wait_evt); - - scsi_mutex_wait(0); - continue; - } - - if (!(x54x_dev->Status & STAT_INIT) && x54x_dev->MailboxInit && dev->MailboxReq) { - x54x_wait_for_poll(); - - x54x_do_mail(dev); - } - - if (dev->ven_thread) { - dev->ven_thread(dev); - } - - scsi_mutex_wait(0); + if ((dev->Status & STAT_INIT) || (!dev->MailboxInit && !dev->BIOSMailboxInit) || (!dev->MailboxReq && !dev->BIOSMailboxReq)) { + /* If we did not get anything, do nothing and wait 10 us. */ + dev->timer_period = 10LL * TIMER_USEC; + return; } - x54x_log("%s: Callback: polling stopped.\n", dev->name); -} + dev->temp_period = dev->media_period = 0LL; + if (!(x54x_dev->Status & STAT_INIT) && x54x_dev->MailboxInit && dev->MailboxReq) + x54x_do_mail(dev); -void -x54x_busy(uint8_t set) -{ - busy = !!set; - if (!set) - thread_set_event((event_t *) wake_poll_thread); -} + if (dev->ven_callback) + dev->ven_callback(dev); - -void -x54x_thread_start(x54x_t *dev) -{ - if (!poll_tid) { - x54x_log("Starting thread...\n"); - poll_tid = thread_create(x54x_cmd_thread, dev); - } -} - - -uint8_t -x54x_is_busy(void) -{ - return(!!busy); -} - - -void -x54x_set_wait_event(void) -{ - thread_set_event((event_t *)wait_evt); + period = (1000000.0 / x54x_dev->ha_bps) * ((double) TIMER_USEC) * ((double) dev->temp_period); + dev->timer_period = dev->media_period + ((int64_t) period) + (40LL * TIMER_USEC); + x54x_log("Temporary period: %" PRId64 " us (%" PRIi64 " periods)\n", dev->timer_period, dev->temp_period); } @@ -1539,31 +1486,24 @@ x54x_out(uint16_t port, uint8_t val, void *priv) switch (port & 3) { case 0: if ((val & CTRL_HRST) || (val & CTRL_SRST)) { - x54x_busy(1); reset = (val & CTRL_HRST); x54x_log("Reset completed = %x\n", reset); x54x_reset_ctrl(dev, reset); x54x_log("Controller reset: "); - x54x_busy(0); break; } if (val & CTRL_IRST) { - x54x_busy(1); clear_irq(dev); x54x_log("Interrupt reset: "); - x54x_busy(0); } break; case 1: /* Fast path for the mailbox execution command. */ if ((val == CMD_START_SCSI) && (dev->Command == 0xff)) { - x54x_busy(1); dev->MailboxReq++; - x54x_set_wait_event(); x54x_log("Start SCSI command: "); - x54x_busy(0); return; } if (dev->ven_fast_cmds) { @@ -1630,7 +1570,6 @@ x54x_out(uint16_t port, uint8_t val, void *priv) break; case CMD_MBINIT: /* mailbox initialization */ - x54x_busy(1); dev->Mbx24bit = 1; mbi = (MailboxInit_t *)dev->CmdBuf; @@ -1649,7 +1588,6 @@ x54x_out(uint16_t port, uint8_t val, void *priv) dev->Status &= ~STAT_INIT; dev->DataReplyLeft = 0; x54x_log("Mailbox init: "); - x54x_busy(0); break; case CMD_BIOSCMD: /* execute BIOS */ @@ -1983,22 +1921,12 @@ x54x_init(device_t *info) dev->bus = info->flags; timer_add(x54x_reset_poll, &dev->ResetCB, &dev->ResetCB, dev); + dev->timer_period = 10LL * TIMER_USEC; + timer_add(x54x_cmd_callback, + &dev->timer_period, TIMER_ALWAYS_ENABLED, dev); x54x_dev = dev; - scsi_mutex(1); - - wake_poll_thread = thread_create_event(); - thread_started = thread_create_event(); - - /* Create a waitable event. */ - evt = thread_create_event(); - wait_evt = thread_create_event(); - - x54x_thread_start(dev); - thread_wait_event((event_t *)thread_started, -1); - thread_reset_event((event_t *)thread_started); - return(dev); } @@ -2011,17 +1939,8 @@ x54x_close(void *priv) if (dev) { x54x_dev = NULL; - /* Tell the thread to terminate. */ - if (poll_tid != NULL) { - x54x_busy(0); - - x54x_log("Waiting for SCSI thread to end...\n"); - /* Wait for the end event. */ - thread_wait((event_t *) poll_tid, -1); - x54x_log("SCSI thread ended\n"); - - poll_tid = NULL; - } + /* Tell the timer to terminate. */ + dev->timer_period = 0LL; dev->MailboxInit = dev->BIOSMailboxInit = 0; dev->MailboxCount = dev->BIOSMailboxCount = 0; @@ -2030,28 +1949,6 @@ x54x_close(void *priv) if (dev->ven_data) free(dev->ven_data); - if (wait_evt) { - thread_destroy_event((event_t *) evt); - evt = NULL; - } - - if (evt) { - thread_destroy_event((event_t *) evt); - evt = NULL; - } - - if (thread_started) { - thread_destroy_event((event_t *) thread_started); - thread_started = NULL; - } - - if (wake_poll_thread) { - thread_destroy_event((event_t *) wake_poll_thread); - wake_poll_thread = NULL; - } - - scsi_mutex(0); - if (dev->nvr != NULL) free(dev->nvr); diff --git a/src/scsi/scsi_x54x.h b/src/scsi/scsi_x54x.h index 7943c3a..10e0d7c 100644 --- a/src/scsi/scsi_x54x.h +++ b/src/scsi/scsi_x54x.h @@ -8,7 +8,7 @@ * * Definitions for the common AHA/BL code. * - * Version: @(#)scsi_x54x.h 1.0.1 2018/02/14 + * Version: @(#)scsi_x54x.h 1.0.2 2018/03/08 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -347,6 +347,10 @@ typedef struct { char vendor[16]; /* name of device vendor */ char name[16]; /* name of device */ + int64_t timer_period, temp_period; + int64_t media_period; + double ha_bps; /* bytes per second */ + int8_t Irq; uint8_t IrqEnabled; @@ -444,8 +448,8 @@ typedef struct { /* Pointer to a structure of vendor-specific data that only the vendor-specific code can understand */ void *ven_data; - /* Pointer to a function that performs vendor-specific operation during the thread */ - void (*ven_thread)(void *p); + /* Pointer to a function that performs vendor-specific operation during the timer callback */ + void (*ven_callback)(void *p); /* Pointer to a function that executes the second parameter phase of the vendor-specific command */ void (*ven_cmd_phase1)(void *p); /* Pointer to a function that gets the host adapter ID in case it has to be read from a non-standard location */ @@ -502,10 +506,6 @@ typedef struct extern void x54x_reset_ctrl(x54x_t *dev, uint8_t Reset); -extern void x54x_busy(uint8_t set); -extern void x54x_thread_start(x54x_t *dev); -extern void x54x_set_wait_event(void); -extern uint8_t x54x_is_busy(void); extern void x54x_buf_alloc(uint8_t id, uint8_t lun, int length); extern void x54x_buf_free(uint8_t id, uint8_t lun); extern uint8_t x54x_mbo_process(x54x_t *dev); diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 6b5d023..271365b 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -8,7 +8,7 @@ # # Makefile for Windows systems using the MinGW32 environment. # -# Version: @(#)Makefile.mingw 1.0.8 2018/03/07 +# Version: @(#)Makefile.mingw 1.0.9 2018/03/08 # # Author: Fred N. van Kempen, # @@ -98,21 +98,24 @@ endif ifndef DEV_BRANCH DEV_BRANCH := n endif -ifndef GREENB - GREENB := n +ifndef AMD_K + AMD_K := n endif ifndef LASERXT LASERXT := n endif -ifndef I686 - I686 := n -endif -ifndef AMD_K - AMD_K := n -endif ifndef PORTABLE3 PORTABLE3 := n endif +ifndef GREENB + GREENB := n +endif +ifndef MRTHOR + MRTHOR := y +endif +ifndef I686 + I686 := n +endif ifndef OPENAL OPENAL := y endif @@ -145,11 +148,12 @@ endif ifeq ($(DEV_BUILD), y) CRASHDUMP := y DEV_BRANCH := y - I686 := y AMD_K := y - GREENB := y - PORTABLE3 := y LASERXT := y + PORTABLE3 := y + GREENB := y + MRTHOR := y + I686 := y PAS16 := y STEALTH32 := y XL24 := y @@ -383,45 +387,49 @@ endif # Options for the DEV branch. ifeq ($(DEV_BRANCH), y) -OPTS += -DDEV_BRANCH -DEVBROBJ := + OPTS += -DDEV_BRANCH + DEVBROBJ := -ifeq ($(I686), y) -OPTS += -DUSE_I686 -DEVBROBJ += m_at_440fx.o -endif + ifeq ($(AMD_K), y) + OPTS += -DUSE_AMD_K + endif -ifeq ($(AMD_K), y) -OPTS += -DUSE_AMD_K -endif + ifeq ($(LASERXT), y) + OPTS += -DUSE_LASERXT + DEVBROBJ += m_xt_laserxt.o + endif -ifeq ($(GREENB), y) -OPTS += -DUSE_GREENB -DEVBROBJ += m_at_4gpv31.o -endif + ifeq ($(PORTABLE3), y) + OPTS += -DUSE_PORTABLE3 + endif -ifeq ($(PORTABLE3), y) -OPTS += -DUSE_PORTABLE3 -endif + ifeq ($(GREENB), y) + OPTS += -DUSE_GREENB + DEVBROBJ += m_at_4gpv31.o + endif -ifeq ($(LASERXT), y) -OPTS += -DUSE_LASERXT -DEVBROBJ += m_xt_laserxt.o -endif - -ifeq ($(STEALTH32), y) -OPTS += -DUSE_STEALTH32 -DEVBROBJ += vid_icd2061.o -endif + ifeq ($(MRTHOR), y) + OPTS += -DUSE_MRTHOR + endif -ifeq ($(XL24), y) -OPTS += -DUSE_XL24 -endif + ifeq ($(I686), y) + OPTS += -DUSE_I686 + DEVBROBJ += m_at_440fx.o + endif -ifeq ($(PAS16), y) -OPTS += -DUSE_PAS16 -DEVBROBJ += snd_pas16.o -endif + ifeq ($(STEALTH32), y) + OPTS += -DUSE_STEALTH32 + DEVBROBJ += vid_icd2061.o + endif + + ifeq ($(XL24), y) + OPTS += -DUSE_XL24 + endif + + ifeq ($(PAS16), y) + OPTS += -DUSE_PAS16 + DEVBROBJ += snd_pas16.o + endif endif diff --git a/src/win/VARCem.rc b/src/win/VARCem.rc index 6b169e4..4292074 100644 --- a/src/win/VARCem.rc +++ b/src/win/VARCem.rc @@ -8,7 +8,7 @@ * * Application resource script for Windows. * - * Version: @(#)VARCem.rc 1.0.5 2018/03/07 + * Version: @(#)VARCem.rc 1.0.6 2018/03/08 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -502,16 +502,16 @@ BEGIN PUSHBUTTON "&Remove",IDC_BUTTON_HDD_REMOVE,198,137,62,10 COMBOBOX IDC_COMBO_HD_BUS,33,117,90,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Bus:",IDT_1721,7,118,24,8 + LTEXT "Bus:",IDT_1721,7,119,24,8 COMBOBOX IDC_COMBO_HD_CHANNEL,170,117,90,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Channel:",IDT_1722,131,118,38,8 + LTEXT "Channel:",IDT_1722,131,119,38,8 COMBOBOX IDC_COMBO_HD_ID,170,117,22,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "ID:",IDT_1723,131,118,38,8 + LTEXT "ID:",IDT_1723,131,119,38,8 COMBOBOX IDC_COMBO_HD_LUN,239,117,22,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "LUN:",IDT_1724,200,118,38,8 + LTEXT "LUN:",IDT_1724,200,119,38,8 COMBOBOX IDC_COMBO_HD_CHANNEL_IDE,170,117,90,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP END @@ -539,16 +539,16 @@ BEGIN LTEXT "File name:",IDT_1731,7,7,204,9 COMBOBOX IDC_COMBO_HD_BUS,33,71,58,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Bus:",IDT_1721,7,72,24,8 + LTEXT "Bus:",IDT_1721,7,73,24,8 COMBOBOX IDC_COMBO_HD_CHANNEL,134,71,77,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Channel:",IDT_1722,99,72,34,8 + LTEXT "Channel:",IDT_1722,99,73,34,8 COMBOBOX IDC_COMBO_HD_ID,133,71,26,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "ID:",IDT_1723,117,72,15,8 + LTEXT "ID:",IDT_1723,117,73,15,8 COMBOBOX IDC_COMBO_HD_LUN,185,71,26,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "LUN:",IDT_1724,168,72,15,8 + LTEXT "LUN:",IDT_1724,168,73,15,8 COMBOBOX IDC_COMBO_HD_CHANNEL_IDE,134,71,77,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP LTEXT "Progress:",IDT_1752,7,7,204,9 @@ -566,7 +566,7 @@ BEGIN LTEXT "Floppy drives:",IDT_1737,7,7,43,8 COMBOBOX IDC_COMBO_FD_TYPE,33,85,90,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Type:",IDT_1738,7,86,24,8 + LTEXT "Type:",IDT_1738,7,87,24,8 CONTROL "Turbo timings",IDC_CHECKTURBO,"Button", BS_AUTOCHECKBOX | WS_TABSTOP,131,86,64,10 CONTROL "Check BPB",IDC_CHECKBPB,"Button", @@ -583,34 +583,37 @@ BEGIN LTEXT "CD-ROM drives:",IDT_1739,7,7,50,8 COMBOBOX IDC_COMBO_CD_BUS,33,85,90,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Bus:",IDT_1740,7,86,24,8 + LTEXT "Bus:",IDT_1740,7,87,24,8 COMBOBOX IDC_COMBO_CD_ID,170,85,22,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "ID:",IDT_1741,131,86,38,8 + LTEXT "ID:",IDT_1741,131,87,38,8 COMBOBOX IDC_COMBO_CD_LUN,239,85,22,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "LUN:",IDT_1742,200,86,38,8 + LTEXT "LUN:",IDT_1742,200,87,38,8 COMBOBOX IDC_COMBO_CD_CHANNEL_IDE,170,85,90,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Channel:",IDT_1743,131,86,38,8 + LTEXT "Channel:",IDT_1743,131,87,38,8 + COMBOBOX IDC_COMBO_CD_SPEED,33,105,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Speed:",IDT_1761,7,107,24,8 CONTROL "List1",IDC_LIST_ZIP_DRIVES,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | - WS_TABSTOP,7,117,253,60 - LTEXT "ZIP drives:",IDT_1758,7,107,50,8 - COMBOBOX IDC_COMBO_ZIP_BUS,33,184,90,12,CBS_DROPDOWNLIST | + WS_TABSTOP,7,137,253,60 + LTEXT "ZIP drives:",IDT_1739,7,127,50,8 + COMBOBOX IDC_COMBO_ZIP_BUS,73,204,90,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Bus:",IDT_1753,7,185,24,8 - COMBOBOX IDC_COMBO_ZIP_ID,170,184,22,12,CBS_DROPDOWNLIST | + LTEXT "Bus:",IDT_1753,57,206,14,8 + COMBOBOX IDC_COMBO_ZIP_ID,190,204,22,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "ID:",IDT_1754,131,185,38,8 - COMBOBOX IDC_COMBO_ZIP_LUN,239,184,22,12,CBS_DROPDOWNLIST | + LTEXT "ID:",IDT_1754,171,206,18,8 + COMBOBOX IDC_COMBO_ZIP_LUN,239,204,22,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "LUN:",IDT_1755,200,185,38,8 - COMBOBOX IDC_COMBO_ZIP_CHANNEL_IDE,170,184,90,12,CBS_DROPDOWNLIST | + LTEXT "LUN:",IDT_1755,220,206,18,8 + COMBOBOX IDC_COMBO_ZIP_CHANNEL_IDE,200,204,60,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Channel:",IDT_1756,131,185,38,8 + LTEXT "Channel:",IDT_1756,171,206,28,8 CONTROL "ZIP 250",IDC_CHECK250,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,204,64,10 + BS_AUTOCHECKBOX | WS_TABSTOP,7,204,44,10 END @@ -985,6 +988,7 @@ BEGIN IDS_2176 "ZIP images (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0" IDS_2177 "ZIP %i (%03i): %ls" IDS_2178 "Unable to initialize OpenAL, make sure you have the following library\nin your program folder:\n\nlibopenal-1.dll" + IDS_2179 "Speed:" IDS_4096 "Hard disk (%s)" IDS_4097 "%01i:%01i" diff --git a/src/win/resource.h b/src/win/resource.h index d5f8e48..46422ff 100644 --- a/src/win/resource.h +++ b/src/win/resource.h @@ -8,7 +8,7 @@ * * Windows resource defines. * - * Version: @(#)resource.h 1.0.4 2018/03/07 + * Version: @(#)resource.h 1.0.5 2018/03/08 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -112,6 +112,7 @@ #define IDT_1758 1758 /* ZIP drives: */ #define IDT_TITLE 1759 /* "VARCem for Plaform" */ #define IDT_VERSION 1760 /* "version.." */ +#define IDT_1761 1761 /* Speed: */ /* * To try to keep these organized, we now group the @@ -216,6 +217,7 @@ #define IDC_COMBO_ZIP_LUN 1163 #define IDC_COMBO_ZIP_CHANNEL_IDE 1164 #define IDC_CHECK250 1165 +#define IDC_COMBO_CD_SPEED 1166 #define IDC_SLIDER_GAIN 1180 /* sound gain dialog */ diff --git a/src/win/win_new_floppy.c b/src/win/win_new_floppy.c index 10982ff..562626d 100644 --- a/src/win/win_new_floppy.c +++ b/src/win/win_new_floppy.c @@ -8,7 +8,7 @@ * * Implementation of the New Floppy Image dialog. * - * Version: @(#)win_new_floppy.c 1.0.6 2018/03/08 + * Version: @(#)win_new_floppy.c 1.0.7 2018/03/08 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -100,6 +100,7 @@ create_86f(WCHAR *file_name, disk_size_t disk_size, uint8_t rpm_mode) uint32_t array_size, array_size2; uint32_t track_base, track_size; int i; + uint32_t shift = 0; dflags = 0; /* Has surface data? - Assume no for now. */ dflags |= (disk_size.hole << 1); /* Hole */ @@ -172,11 +173,15 @@ create_86f(WCHAR *file_name, disk_size_t disk_size, uint8_t rpm_mode) track_base = 8 + ((disk_size.sides == 2) ? 2048 : 1024); for (i = 0; i < disk_size.tracks * disk_size.sides; i++) + if (disk_size.tracks <= 43) + shift = 1; + + for (i = 0; i < (disk_size.tracks * disk_size.sides) << shift; i++) tarray[i] = track_base + (i * track_size); fwrite(tarray, 1, (disk_size.sides == 2) ? 2048 : 1024, f); - for (i = 0; i < disk_size.tracks * disk_size.sides; i++) { + for (i = 0; i < (disk_size.tracks * disk_size.sides) << shift; i++) { fwrite(&tflags, 2, 1, f); fwrite(&index_hole_pos, 4, 1, f); fwrite(empty, 1, array_size, f); diff --git a/src/win/win_settings.c b/src/win/win_settings.c index f04f242..e7e91bc 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -8,7 +8,7 @@ * * Implementation of the Settings dialog. * - * Version: @(#)win_settings.c 1.0.7 2018/03/08 + * Version: @(#)win_settings.c 1.0.8 2018/03/08 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -3955,6 +3955,7 @@ static BOOL win_settings_cdrom_drives_recalc_list(HWND hwndList) { fsid = combo_id_to_format_string_id(temp_cdrom_drives[i].bus_type); + lvI.iSubItem = 0; switch (temp_cdrom_drives[i].bus_type) { case CDROM_BUS_DISABLED: @@ -3983,6 +3984,21 @@ static BOOL win_settings_cdrom_drives_recalc_list(HWND hwndList) if (ListView_InsertItem(hwndList, &lvI) == -1) return FALSE; + + lvI.iSubItem = 1; + if (temp_cdrom_drives[i].bus_type == CDROM_BUS_DISABLED) + lvI.pszText = plat_get_string(IDS_2152); + else { + wsprintf(szText, L"%ix", temp_cdrom_drives[i].speed); + lvI.pszText = szText; + } + lvI.iItem = i; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + { + return FALSE; + } } return TRUE; @@ -4096,7 +4112,7 @@ static BOOL win_settings_cdrom_drives_init_columns(HWND hwndList) lvc.iSubItem = 0; lvc.pszText = plat_get_string(IDS_2082); - lvc.cx = 392; + lvc.cx = 342; lvc.fmt = LVCFMT_LEFT; if (ListView_InsertColumn(hwndList, 0, &lvc) == -1) @@ -4104,6 +4120,17 @@ static BOOL win_settings_cdrom_drives_init_columns(HWND hwndList) return FALSE; } + lvc.iSubItem = 1; + lvc.pszText = plat_get_string(IDS_2179); + + lvc.cx = 50; + lvc.fmt = LVCFMT_LEFT; + + if (ListView_InsertColumn(hwndList, 1, &lvc) == -1) + { + return FALSE; + } + return TRUE; } @@ -4124,7 +4151,6 @@ static BOOL win_settings_zip_drives_init_columns(HWND hwndList) return FALSE; } - lvc.iSubItem = 1; lvc.pszText = plat_get_string(IDS_2143); @@ -4288,6 +4314,21 @@ static void win_settings_cdrom_drives_update_item(HWND hwndList, int i) { return; } + + lvI.iSubItem = 1; + if (temp_cdrom_drives[i].bus_type == CDROM_BUS_DISABLED) + lvI.pszText = plat_get_string(IDS_2152); + else { + wsprintf(szText, L"%ix", temp_cdrom_drives[i].speed); + lvI.pszText = szText; + } + lvI.iItem = i; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + { + return; + } } static void win_settings_zip_drives_update_item(HWND hwndList, int i) @@ -4361,6 +4402,13 @@ static void cdrom_add_locations(HWND hdlg) } } + h = GetDlgItem(hdlg, IDC_COMBO_CD_SPEED); + for (i = 1; i <= 56; i++) + { + wsprintf(lptsTemp, L"%ix", i); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + h = GetDlgItem(hdlg, IDC_COMBO_CD_ID); for (i = 0; i < 16; i++) { @@ -4384,6 +4432,7 @@ static void cdrom_add_locations(HWND hdlg) free(lptsTemp); } + static void cdrom_recalc_location_controls(HWND hdlg, int assign_id) { int i = 0; @@ -4410,6 +4459,16 @@ static void cdrom_recalc_location_controls(HWND hdlg, int assign_id) EnableWindow(h, FALSE); ShowWindow(h, SW_HIDE); + h = GetDlgItem(hdlg, IDC_COMBO_CD_SPEED); + if (bus == CDROM_BUS_DISABLED) { + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + } else { + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, temp_cdrom_drives[cdlv_current_sel].speed - 1, 0); + } + switch(bus) { case CDROM_BUS_ATAPI_PIO_ONLY: /* ATAPI (PIO-only) */ @@ -4490,6 +4549,7 @@ static void zip_add_locations(HWND hdlg) free(lptsTemp); } + static void zip_recalc_location_controls(HWND hdlg, int assign_id) { int i = 0; @@ -4963,6 +5023,8 @@ other_removable_devices_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lPar } cdrom_untrack(cdlv_current_sel); assign = (temp_cdrom_drives[cdlv_current_sel].bus_type == b2) ? 0 : 1; + if (temp_cdrom_drives[cdlv_current_sel].bus_type == CDROM_BUS_DISABLED) + temp_cdrom_drives[cdlv_current_sel].speed = 8; if ((b2 == CDROM_BUS_ATAPI_PIO_ONLY) && (temp_cdrom_drives[cdlv_current_sel].bus_type == CDROM_BUS_ATAPI_PIO_AND_DMA)) assign = 0; else if ((b2 == CDROM_BUS_ATAPI_PIO_AND_DMA) && (temp_cdrom_drives[cdlv_current_sel].bus_type == CDROM_BUS_ATAPI_PIO_ONLY)) @@ -5024,6 +5086,20 @@ cdrom_bus_skip: rd_ignore_change = 0; return FALSE; + case IDC_COMBO_CD_SPEED: + if (rd_ignore_change) + { + return FALSE; + } + + rd_ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_CD_SPEED); + temp_cdrom_drives[cdlv_current_sel].speed = SendMessage(h, CB_GETCURSEL, 0, 0) + 1; + h = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); + win_settings_cdrom_drives_update_item(h, cdlv_current_sel); + rd_ignore_change = 0; + return FALSE; + case IDC_COMBO_ZIP_BUS: if (rd_ignore_change) {