2017-05-30 03:38:38 +02:00
|
|
|
/*
|
2022-11-13 16:37:58 -05:00
|
|
|
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
|
|
|
|
* running old operating systems and software designed for IBM
|
|
|
|
|
* PC systems and compatibles from 1981 through fairly recent
|
|
|
|
|
* system designs based on the PCI bus.
|
2017-05-30 03:38:38 +02:00
|
|
|
*
|
2022-11-13 16:37:58 -05:00
|
|
|
* Emulation of SCSI fixed disks.
|
2017-05-30 03:38:38 +02:00
|
|
|
*
|
2020-03-25 00:46:02 +02:00
|
|
|
*
|
2017-05-30 03:38:38 +02:00
|
|
|
*
|
2022-11-13 16:37:58 -05:00
|
|
|
* Authors: Miran Grca, <mgrca8@gmail.com>
|
2017-10-17 01:59:09 -04:00
|
|
|
*
|
2022-11-13 16:37:58 -05:00
|
|
|
* Copyright 2017-2018 Miran Grca.
|
2017-05-30 03:38:38 +02:00
|
|
|
*/
|
2017-06-16 03:18:59 +02:00
|
|
|
#include <stdio.h>
|
2017-09-25 04:31:20 -04:00
|
|
|
#include <stdint.h>
|
|
|
|
|
#include <string.h>
|
2017-09-04 01:52:29 -04:00
|
|
|
#include <stdlib.h>
|
2017-08-15 19:49:25 +02:00
|
|
|
#include <stdarg.h>
|
2017-09-25 04:31:20 -04:00
|
|
|
#include <wchar.h>
|
2017-12-10 02:53:10 -05:00
|
|
|
#define HAVE_STDARG_H
|
2020-03-29 14:24:42 +02:00
|
|
|
#include <86box/86box.h>
|
|
|
|
|
#include <86box/timer.h>
|
|
|
|
|
#include <86box/device.h>
|
|
|
|
|
#include <86box/nvr.h>
|
|
|
|
|
#include <86box/hdd.h>
|
|
|
|
|
#include <86box/hdc.h>
|
2022-08-02 20:11:23 -04:00
|
|
|
#include <86box/scsi.h>
|
2020-03-29 14:24:42 +02:00
|
|
|
#include <86box/scsi_device.h>
|
|
|
|
|
#include <86box/hdc_ide.h>
|
|
|
|
|
#include <86box/plat.h>
|
|
|
|
|
#include <86box/ui.h>
|
|
|
|
|
#include <86box/scsi_disk.h>
|
2020-06-26 13:26:42 +02:00
|
|
|
#include <86box/version.h>
|
2017-08-24 01:14:39 -04:00
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
#define scsi_disk_sense_error dev->sense[0]
|
2022-09-18 17:17:15 -04:00
|
|
|
#define scsi_disk_sense_key dev->sense[2]
|
|
|
|
|
#define scsi_disk_asc dev->sense[12]
|
|
|
|
|
#define scsi_disk_ascq dev->sense[13]
|
2018-07-15 01:41:53 +02:00
|
|
|
|
2017-05-05 01:49:42 +02:00
|
|
|
/* Table of all SCSI commands and their flags, needed for the new disc change / not ready handler. */
|
2018-07-15 01:41:53 +02:00
|
|
|
const uint8_t scsi_disk_command_flags[0x100] = {
|
2022-09-18 17:17:15 -04:00
|
|
|
IMPLEMENTED | CHECK_READY | NONDATA, /* 0x00 */
|
|
|
|
|
IMPLEMENTED | ALLOW_UA | NONDATA | SCSI_ONLY, /* 0x01 */
|
2017-08-24 01:14:39 -04:00
|
|
|
0,
|
2022-09-18 17:17:15 -04:00
|
|
|
IMPLEMENTED | ALLOW_UA, /* 0x03 */
|
|
|
|
|
IMPLEMENTED | CHECK_READY | ALLOW_UA | NONDATA | SCSI_ONLY, /* 0x04 */
|
2017-08-24 01:14:39 -04:00
|
|
|
0, 0, 0,
|
2022-09-18 17:17:15 -04:00
|
|
|
IMPLEMENTED | CHECK_READY, /* 0x08 */
|
2017-08-24 01:14:39 -04:00
|
|
|
0,
|
2022-09-18 17:17:15 -04:00
|
|
|
IMPLEMENTED | CHECK_READY, /* 0x0A */
|
|
|
|
|
IMPLEMENTED | CHECK_READY | NONDATA, /* 0x0B */
|
2018-07-15 01:41:53 +02:00
|
|
|
0, 0, 0, 0, 0, 0,
|
2022-09-18 17:17:15 -04:00
|
|
|
IMPLEMENTED | ALLOW_UA, /* 0x12 */
|
|
|
|
|
IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x13 */
|
2017-10-16 06:19:18 +02:00
|
|
|
0,
|
2022-09-18 17:17:15 -04:00
|
|
|
IMPLEMENTED, /* 0x15 */
|
|
|
|
|
IMPLEMENTED | SCSI_ONLY, /* 0x16 */
|
|
|
|
|
IMPLEMENTED | SCSI_ONLY, /* 0x17 */
|
2018-01-24 18:38:43 +01:00
|
|
|
0, 0,
|
2022-09-18 17:17:15 -04:00
|
|
|
IMPLEMENTED, /* 0x1A */
|
2018-04-25 23:51:13 +02:00
|
|
|
0, 0,
|
2022-09-18 17:17:15 -04:00
|
|
|
IMPLEMENTED, /* 0x1D */
|
|
|
|
|
IMPLEMENTED | CHECK_READY, /* 0x1E */
|
2017-08-24 01:14:39 -04:00
|
|
|
0, 0, 0, 0, 0, 0,
|
2022-09-18 17:17:15 -04:00
|
|
|
IMPLEMENTED | CHECK_READY, /* 0x25 */
|
2017-08-24 01:14:39 -04:00
|
|
|
0, 0,
|
2022-09-18 17:17:15 -04:00
|
|
|
IMPLEMENTED | CHECK_READY, /* 0x28 */
|
2017-08-24 01:14:39 -04:00
|
|
|
0,
|
2022-09-18 17:17:15 -04:00
|
|
|
IMPLEMENTED | CHECK_READY, /* 0x2A */
|
|
|
|
|
IMPLEMENTED | CHECK_READY | NONDATA, /* 0x2B */
|
2018-07-15 01:41:53 +02:00
|
|
|
0, 0,
|
2022-09-18 17:17:15 -04:00
|
|
|
IMPLEMENTED | CHECK_READY, /* 0x2E */
|
|
|
|
|
IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x2F */
|
2017-08-24 01:14:39 -04:00
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
2017-11-23 21:32:21 +01:00
|
|
|
0,
|
2022-09-18 17:17:15 -04:00
|
|
|
IMPLEMENTED | CHECK_READY, /* 0x41 */
|
2017-11-23 21:32:21 +01:00
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
2017-10-16 06:19:18 +02:00
|
|
|
0, 0, 0, 0, 0,
|
2022-09-18 17:17:15 -04:00
|
|
|
IMPLEMENTED, /* 0x55 */
|
2017-10-16 06:19:18 +02:00
|
|
|
0, 0, 0, 0,
|
2022-09-18 17:17:15 -04:00
|
|
|
IMPLEMENTED, /* 0x5A */
|
2017-10-16 06:19:18 +02:00
|
|
|
0, 0, 0, 0, 0,
|
2017-08-24 01:14:39 -04:00
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
2022-09-18 17:17:15 -04:00
|
|
|
IMPLEMENTED | CHECK_READY, /* 0xA8 */
|
2017-08-24 01:14:39 -04:00
|
|
|
0,
|
2022-09-18 17:17:15 -04:00
|
|
|
IMPLEMENTED | CHECK_READY, /* 0xAA */
|
2017-11-23 21:32:21 +01:00
|
|
|
0, 0, 0,
|
2022-09-18 17:17:15 -04:00
|
|
|
IMPLEMENTED | CHECK_READY, /* 0xAE */
|
|
|
|
|
IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0xAF */
|
2017-08-24 01:14:39 -04:00
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
2022-09-18 17:17:15 -04:00
|
|
|
IMPLEMENTED, /* 0xBD */
|
2017-08-24 01:14:39 -04:00
|
|
|
0, 0,
|
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
2017-05-05 01:49:42 +02:00
|
|
|
};
|
|
|
|
|
|
2022-09-18 17:17:15 -04:00
|
|
|
uint64_t scsi_disk_mode_sense_page_flags = (GPMODEP_FORMAT_DEVICE_PAGE | GPMODEP_RIGID_DISK_PAGE | GPMODEP_UNK_VENDOR_PAGE | GPMODEP_ALL_PAGES);
|
2017-10-08 05:04:38 +02:00
|
|
|
|
|
|
|
|
/* 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. */
|
2022-09-18 17:17:15 -04:00
|
|
|
static const mode_sense_pages_t scsi_disk_mode_sense_pages_default = {
|
|
|
|
|
{[GPMODE_FORMAT_DEVICE_PAGE] = { GPMODE_FORMAT_DEVICE_PAGE, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
|
|
|
|
[GPMODE_RIGID_DISK_PAGE] = { GPMODE_RIGID_DISK_PAGE, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 200, 0xff, 0xff, 0xff, 0, 0, 0, 0x15, 0x18, 0, 0 },
|
|
|
|
|
[GPMODE_UNK_VENDOR_PAGE] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' }}
|
|
|
|
|
};
|
2017-10-08 05:04:38 +02:00
|
|
|
|
2022-09-18 17:17:15 -04:00
|
|
|
static const mode_sense_pages_t scsi_disk_mode_sense_pages_changeable = {
|
|
|
|
|
{[GPMODE_FORMAT_DEVICE_PAGE] = { GPMODE_FORMAT_DEVICE_PAGE, 0x16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
|
|
|
|
[GPMODE_RIGID_DISK_PAGE] = { GPMODE_RIGID_DISK_PAGE, 0x16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
|
|
|
|
[GPMODE_UNK_VENDOR_PAGE] = { 0xB0, 0x16, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }}
|
|
|
|
|
};
|
2017-11-24 02:23:00 -05:00
|
|
|
|
2017-10-19 21:08:34 -04:00
|
|
|
#ifdef ENABLE_SCSI_DISK_LOG
|
2018-07-15 01:41:53 +02:00
|
|
|
int scsi_disk_do_log = ENABLE_SCSI_DISK_LOG;
|
2017-08-24 01:14:39 -04:00
|
|
|
|
2017-11-24 02:23:00 -05:00
|
|
|
static void
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_log(const char *fmt, ...)
|
2017-05-05 01:49:42 +02:00
|
|
|
{
|
2017-12-05 23:35:35 +01:00
|
|
|
va_list ap;
|
|
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
if (scsi_disk_do_log) {
|
2022-09-18 17:17:15 -04:00
|
|
|
va_start(ap, fmt);
|
|
|
|
|
pclog_ex(fmt, ap);
|
|
|
|
|
va_end(ap);
|
2017-11-24 02:23:00 -05:00
|
|
|
}
|
2017-05-05 01:49:42 +02:00
|
|
|
}
|
2018-10-19 00:39:32 +02:00
|
|
|
#else
|
2022-09-18 17:17:15 -04:00
|
|
|
# define scsi_disk_log(fmt, ...)
|
2018-10-19 00:39:32 +02:00
|
|
|
#endif
|
2017-05-05 01:49:42 +02:00
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
void
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_mode_sense_load(scsi_disk_t *dev)
|
2017-05-27 03:53:32 +02:00
|
|
|
{
|
2018-04-25 23:51:13 +02:00
|
|
|
FILE *f;
|
2022-09-18 17:17:15 -04:00
|
|
|
char file_name[512];
|
2018-10-27 22:19:39 +02:00
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
memset(&dev->ms_pages_saved, 0, sizeof(mode_sense_pages_t));
|
2018-10-27 22:19:39 +02:00
|
|
|
memcpy(&dev->ms_pages_saved, &scsi_disk_mode_sense_pages_default, sizeof(mode_sense_pages_t));
|
|
|
|
|
|
2021-03-14 20:35:01 +01:00
|
|
|
memset(file_name, 0, 512);
|
|
|
|
|
sprintf(file_name, "scsi_disk_%02i_mode_sense.bin", dev->id);
|
|
|
|
|
f = plat_fopen(nvr_path(file_name), "rb");
|
2018-04-25 23:51:13 +02:00
|
|
|
if (f) {
|
2022-09-18 17:17:15 -04:00
|
|
|
if (fread(dev->ms_pages_saved.pages[0x30], 1, 0x18, f) != 0x18)
|
|
|
|
|
fatal("scsi_disk_mode_sense_load(): Error reading data\n");
|
|
|
|
|
fclose(f);
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
2017-05-05 01:49:42 +02:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
void
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_mode_sense_save(scsi_disk_t *dev)
|
2017-05-05 01:49:42 +02:00
|
|
|
{
|
2018-04-25 23:51:13 +02:00
|
|
|
FILE *f;
|
2022-09-18 17:17:15 -04:00
|
|
|
char file_name[512];
|
Added the IBM 5161 ISA expansion for PC and XT;
Cleaned up the parallel port emulation, added IRQ support, and made enabling/disabling per port;
Added the Award 430NX and the Intel Classic/PCI (Alfredo, 420TX);
Finished the 586MC1;
Added 8087 emulation;
Moved Cyrix 6x86'es to the Dev branch;
Sanitized/cleaned up memregs.c/h and intel.c/h;
Split the chipsets from machines and sanitized Port 92 emulation;
Added support for the 15bpp mode to the Compaq ATI 28800;
Moved the MR 386DX and 486 machines to the Dev branch;
Ported the new dynamic recompiler from PCem, but it remains in Dev branch until after v2.00;
Ported the new timer code from PCem;
Cleaned up the CPU table of unused stuff and better optimized its structure;
Ported the Open-XT and Open-AT from VARCem, the Open-AT is in the Dev branch;
Ported the XT MFM controller rewrite and adding of more controllers (incl. two RLL ones), from VARCem;
Added the AHA-1540A and the BusTek BT-542B;
Moved the Sumo SCSI-AT to the Dev branch;
Minor IDE, FDC, and floppy drive code clean-ups;
Made NCR 5380/53C400-based cards' BIOS address configurable;
Got rid of the legacy romset variable;
Unified (video) buffer and buffer32 into one and make the unified buffer 32-bit;
Added the Amstead PPC512 per PCem patch by John Elliott;
Switched memory mapping granularity from 16k to 4k (less than 1k not possible due to internal pages);
Rewrote the CL-GD 54xx blitter, fixes Win-OS/2 on the 54x6 among other thing;
Added the Image Manager 1024 and Professional Graphics Controller per PCem patch by John Elliott and work done on VARCem;
Added Headland HT-216, GC-205 and Video 7 VGA 1024i emulation based on PCem commit;
Implemented the fuction keys for the Toshiba T1000/T1200/T3100 enhancement;
Amstrad MegaPC does now works correctly with non-internal graphics card;
The SLiRP code no longer casts a packed struct type to a non-packed struct type;
The Xi8088 and PB410a no longer hang on 86Box when PS/2 mouse is not present;
The S3 Virge on BeOS is no longer broken (was broken by build #1591);
OS/2 2.0 build 6.167 now sees key presses again;
Xi8088 now work on CGA again;
86F images converted from either the old or new variants of the HxC MFM format now work correctly;
Hardware interrupts with a vector of 0xFF are now handled correctly;
OPTi 495SX boards no longer incorrectly have 64 MB maximum RAM when 32 MB is correct;
Fixed VNC keyboard input bugs;
Fixed AT RTC periodic interrupt - Chicago 58s / 73f / 73g / 81 MIDI play no longer hangs with the build's own VTD driver;
Fixed mouse polling with internal mice - Amstrad and Olivetti mice now work correctly;
Triones ATAPI DMA driver now correctly reads a file at the end of a CD image with a sectors number not divisible by 4;
Compaq Portable now works with all graphics cards;
Fixed various MDSI Genius bugs;
Added segment limit checks and improved page fault checks for several CPU instructions - Memphis 15xx WINSETUP and Chicago 58s WINDISK.CPL no longer issue a GPF, and some S3 drivers that used to have glitches, now work correctly;
Further improved the 808x emulation, also fixes the noticably choppy sound when using 808x CPU's, also fixes #355;
OS/2 installer no logner locks up on splash screen on PS/2 Model 70 and 80, fixes #400.
Fixed several Amstead bugs, GEM no longer crashes on the Amstrad 1640, fixes #391.
Ported John Elliott's Amstrad fixes and improvement from PCem, and fixed the default language so it's correctly Engliish, fixes #278, fixes #389.
Fixed a minor IDE timing bug, fixes #388.
Fixed Toshiba T1000 RAM issues, fixes #379.
Fixed EGA/(S)VGA overscan border handling, fixes #378;
Got rid of the now long useless IDE channel 2 auto-removal, fixes #370;
Fixed the BIOS files used by the AMSTRAD PC1512, fixes #366;
Ported the Unicode CD image file name fix from VARCem, fixes #365;
Fixed high density floppy disks on the Xi8088, fixes #359;
Fixed some bugs in the Hercules emulation, fixes #346, fixes #358;
Fixed the SCSI hard disk mode sense pages, fixes #356;
Removed the AMI Unknown 386SX because of impossibility to identify the chipset, closes #349;
Fixed bugs in the serial mouse emulation, fixes #344;
Compiled 86Box binaries now include all the required .DLL's, fixes #341;
Made some combo boxes in the Settings dialog slightly wider, fixes #276.
2019-09-20 14:02:30 +02:00
|
|
|
|
2021-03-14 20:35:01 +01:00
|
|
|
memset(file_name, 0, 512);
|
|
|
|
|
sprintf(file_name, "scsi_disk_%02i_mode_sense.bin", dev->id);
|
|
|
|
|
f = plat_fopen(nvr_path(file_name), "wb");
|
2018-04-25 23:51:13 +02:00
|
|
|
if (f) {
|
2022-09-18 17:17:15 -04:00
|
|
|
fwrite(dev->ms_pages_saved.pages[0x30], 1, 0x18, f);
|
|
|
|
|
fclose(f);
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
2017-05-05 01:49:42 +02:00
|
|
|
}
|
|
|
|
|
|
2017-10-08 05:04:38 +02:00
|
|
|
/*SCSI Mode Sense 6/10*/
|
2018-04-25 23:51:13 +02:00
|
|
|
uint8_t
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_mode_sense_read(scsi_disk_t *dev, uint8_t page_control, uint8_t page, uint8_t pos)
|
2017-10-08 05:04:38 +02:00
|
|
|
{
|
Added the IBM 5161 ISA expansion for PC and XT;
Cleaned up the parallel port emulation, added IRQ support, and made enabling/disabling per port;
Added the Award 430NX and the Intel Classic/PCI (Alfredo, 420TX);
Finished the 586MC1;
Added 8087 emulation;
Moved Cyrix 6x86'es to the Dev branch;
Sanitized/cleaned up memregs.c/h and intel.c/h;
Split the chipsets from machines and sanitized Port 92 emulation;
Added support for the 15bpp mode to the Compaq ATI 28800;
Moved the MR 386DX and 486 machines to the Dev branch;
Ported the new dynamic recompiler from PCem, but it remains in Dev branch until after v2.00;
Ported the new timer code from PCem;
Cleaned up the CPU table of unused stuff and better optimized its structure;
Ported the Open-XT and Open-AT from VARCem, the Open-AT is in the Dev branch;
Ported the XT MFM controller rewrite and adding of more controllers (incl. two RLL ones), from VARCem;
Added the AHA-1540A and the BusTek BT-542B;
Moved the Sumo SCSI-AT to the Dev branch;
Minor IDE, FDC, and floppy drive code clean-ups;
Made NCR 5380/53C400-based cards' BIOS address configurable;
Got rid of the legacy romset variable;
Unified (video) buffer and buffer32 into one and make the unified buffer 32-bit;
Added the Amstead PPC512 per PCem patch by John Elliott;
Switched memory mapping granularity from 16k to 4k (less than 1k not possible due to internal pages);
Rewrote the CL-GD 54xx blitter, fixes Win-OS/2 on the 54x6 among other thing;
Added the Image Manager 1024 and Professional Graphics Controller per PCem patch by John Elliott and work done on VARCem;
Added Headland HT-216, GC-205 and Video 7 VGA 1024i emulation based on PCem commit;
Implemented the fuction keys for the Toshiba T1000/T1200/T3100 enhancement;
Amstrad MegaPC does now works correctly with non-internal graphics card;
The SLiRP code no longer casts a packed struct type to a non-packed struct type;
The Xi8088 and PB410a no longer hang on 86Box when PS/2 mouse is not present;
The S3 Virge on BeOS is no longer broken (was broken by build #1591);
OS/2 2.0 build 6.167 now sees key presses again;
Xi8088 now work on CGA again;
86F images converted from either the old or new variants of the HxC MFM format now work correctly;
Hardware interrupts with a vector of 0xFF are now handled correctly;
OPTi 495SX boards no longer incorrectly have 64 MB maximum RAM when 32 MB is correct;
Fixed VNC keyboard input bugs;
Fixed AT RTC periodic interrupt - Chicago 58s / 73f / 73g / 81 MIDI play no longer hangs with the build's own VTD driver;
Fixed mouse polling with internal mice - Amstrad and Olivetti mice now work correctly;
Triones ATAPI DMA driver now correctly reads a file at the end of a CD image with a sectors number not divisible by 4;
Compaq Portable now works with all graphics cards;
Fixed various MDSI Genius bugs;
Added segment limit checks and improved page fault checks for several CPU instructions - Memphis 15xx WINSETUP and Chicago 58s WINDISK.CPL no longer issue a GPF, and some S3 drivers that used to have glitches, now work correctly;
Further improved the 808x emulation, also fixes the noticably choppy sound when using 808x CPU's, also fixes #355;
OS/2 installer no logner locks up on splash screen on PS/2 Model 70 and 80, fixes #400.
Fixed several Amstead bugs, GEM no longer crashes on the Amstrad 1640, fixes #391.
Ported John Elliott's Amstrad fixes and improvement from PCem, and fixed the default language so it's correctly Engliish, fixes #278, fixes #389.
Fixed a minor IDE timing bug, fixes #388.
Fixed Toshiba T1000 RAM issues, fixes #379.
Fixed EGA/(S)VGA overscan border handling, fixes #378;
Got rid of the now long useless IDE channel 2 auto-removal, fixes #370;
Fixed the BIOS files used by the AMSTRAD PC1512, fixes #366;
Ported the Unicode CD image file name fix from VARCem, fixes #365;
Fixed high density floppy disks on the Xi8088, fixes #359;
Fixed some bugs in the Hercules emulation, fixes #346, fixes #358;
Fixed the SCSI hard disk mode sense pages, fixes #356;
Removed the AMI Unknown 386SX because of impossibility to identify the chipset, closes #349;
Fixed bugs in the serial mouse emulation, fixes #344;
Compiled 86Box binaries now include all the required .DLL's, fixes #341;
Made some combo boxes in the Settings dialog slightly wider, fixes #276.
2019-09-20 14:02:30 +02:00
|
|
|
if (page_control == 1)
|
2022-09-18 17:17:15 -04:00
|
|
|
return scsi_disk_mode_sense_pages_changeable.pages[page][pos];
|
|
|
|
|
|
|
|
|
|
if (page == GPMODE_RIGID_DISK_PAGE)
|
|
|
|
|
switch (page_control) {
|
|
|
|
|
/* Rigid disk geometry page. */
|
|
|
|
|
case 0:
|
|
|
|
|
case 2:
|
|
|
|
|
case 3:
|
|
|
|
|
switch (pos) {
|
2023-06-09 23:46:54 -04:00
|
|
|
default:
|
2022-09-18 17:17:15 -04:00
|
|
|
case 0:
|
|
|
|
|
case 1:
|
|
|
|
|
return scsi_disk_mode_sense_pages_default.pages[page][pos];
|
|
|
|
|
case 2:
|
|
|
|
|
case 6:
|
|
|
|
|
case 9:
|
|
|
|
|
return (dev->drv->tracks >> 16) & 0xff;
|
|
|
|
|
case 3:
|
|
|
|
|
case 7:
|
|
|
|
|
case 10:
|
|
|
|
|
return (dev->drv->tracks >> 8) & 0xff;
|
|
|
|
|
case 4:
|
|
|
|
|
case 8:
|
|
|
|
|
case 11:
|
|
|
|
|
return dev->drv->tracks & 0xff;
|
|
|
|
|
case 5:
|
|
|
|
|
return dev->drv->hpc & 0xff;
|
|
|
|
|
}
|
2023-06-09 23:46:54 -04:00
|
|
|
|
|
|
|
|
default:
|
2022-09-18 17:17:15 -04:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else if (page == GPMODE_FORMAT_DEVICE_PAGE)
|
|
|
|
|
switch (page_control) {
|
|
|
|
|
/* Format device page. */
|
|
|
|
|
case 0:
|
|
|
|
|
case 2:
|
|
|
|
|
case 3:
|
|
|
|
|
switch (pos) {
|
2023-06-09 23:46:54 -04:00
|
|
|
default:
|
2022-09-18 17:17:15 -04:00
|
|
|
case 0:
|
|
|
|
|
case 1:
|
|
|
|
|
return scsi_disk_mode_sense_pages_default.pages[page][pos];
|
|
|
|
|
/* Actual sectors + the 1 "alternate sector" we report. */
|
|
|
|
|
case 10:
|
|
|
|
|
return ((dev->drv->spt + 1) >> 8) & 0xff;
|
|
|
|
|
case 11:
|
|
|
|
|
return (dev->drv->spt + 1) & 0xff;
|
|
|
|
|
}
|
2023-06-09 23:46:54 -04:00
|
|
|
|
|
|
|
|
default:
|
2022-09-18 17:17:15 -04:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
switch (page_control) {
|
|
|
|
|
case 0:
|
|
|
|
|
case 3:
|
|
|
|
|
return dev->ms_pages_saved.pages[page][pos];
|
|
|
|
|
case 2:
|
|
|
|
|
return scsi_disk_mode_sense_pages_default.pages[page][pos];
|
2023-06-09 23:46:54 -04:00
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
2022-09-18 17:17:15 -04:00
|
|
|
}
|
2017-10-08 05:04:38 +02:00
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
return 0;
|
2017-10-08 05:04:38 +02:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
uint32_t
|
2018-10-10 22:33:24 +02:00
|
|
|
scsi_disk_mode_sense(scsi_disk_t *dev, uint8_t *buf, uint32_t pos, uint8_t page, uint8_t block_descriptor_len)
|
2018-04-25 23:51:13 +02:00
|
|
|
{
|
2023-05-29 01:30:51 -04:00
|
|
|
uint8_t msplen;
|
|
|
|
|
uint8_t page_control = (page >> 6) & 3;
|
|
|
|
|
int size = 0;
|
2017-10-08 05:04:38 +02:00
|
|
|
|
2018-10-10 22:33:24 +02:00
|
|
|
page &= 0x3f;
|
2017-10-08 05:04:38 +02:00
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
size = hdd_image_get_last_sector(dev->id);
|
2017-10-16 06:19:18 +02:00
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
if (block_descriptor_len) {
|
2022-09-18 17:17:15 -04:00
|
|
|
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;
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
2017-10-08 05:04:38 +02:00
|
|
|
|
2023-05-29 01:30:51 -04:00
|
|
|
for (uint8_t i = 0; i < 0x40; i++) {
|
2018-10-10 22:33:24 +02:00
|
|
|
if ((page == GPMODE_ALL_PAGES) || (page == i)) {
|
2022-09-18 17:17:15 -04:00
|
|
|
if (scsi_disk_mode_sense_page_flags & (1LL << (uint64_t) page)) {
|
|
|
|
|
buf[pos++] = scsi_disk_mode_sense_read(dev, page_control, i, 0);
|
|
|
|
|
msplen = scsi_disk_mode_sense_read(dev, page_control, i, 1);
|
|
|
|
|
buf[pos++] = msplen;
|
|
|
|
|
scsi_disk_log("SCSI HDD %i: MODE SENSE: Page [%02X] length %i\n", dev->id, i, msplen);
|
2023-05-29 01:30:51 -04:00
|
|
|
for (uint8_t j = 0; j < msplen; j++)
|
2022-09-18 17:17:15 -04:00
|
|
|
buf[pos++] = scsi_disk_mode_sense_read(dev, page_control, i, 2 + j);
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
2017-10-08 05:04:38 +02:00
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
return pos;
|
2017-10-08 05:04:38 +02:00
|
|
|
}
|
2017-08-26 04:38:12 +02:00
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_command_common(scsi_disk_t *dev)
|
2017-05-05 01:49:42 +02:00
|
|
|
{
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->status = BUSY_STAT;
|
2022-09-18 17:17:15 -04:00
|
|
|
dev->phase = 1;
|
2018-10-31 12:23:49 +01:00
|
|
|
if (dev->packet_status == PHASE_COMPLETE)
|
2022-09-18 17:17:15 -04:00
|
|
|
dev->callback = 0.0;
|
2018-10-31 12:23:49 +01:00
|
|
|
else
|
2022-09-18 17:17:15 -04:00
|
|
|
dev->callback = -1.0; /* Speed depends on SCSI controller */
|
2017-05-05 01:49:42 +02:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_command_complete(scsi_disk_t *dev)
|
2017-05-05 01:49:42 +02:00
|
|
|
{
|
2019-09-21 19:15:38 +02:00
|
|
|
ui_sb_update_icon(SB_HDD | dev->drv->bus, 0);
|
2018-10-10 22:33:24 +02:00
|
|
|
dev->packet_status = PHASE_COMPLETE;
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_command_common(dev);
|
2017-05-05 01:49:42 +02:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_command_read_dma(scsi_disk_t *dev)
|
2017-05-05 01:49:42 +02:00
|
|
|
{
|
2018-10-10 22:33:24 +02:00
|
|
|
dev->packet_status = PHASE_DATA_IN_DMA;
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_command_common(dev);
|
2017-05-05 01:49:42 +02:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_command_write_dma(scsi_disk_t *dev)
|
2017-05-05 01:49:42 +02:00
|
|
|
{
|
2018-10-10 22:33:24 +02:00
|
|
|
dev->packet_status = PHASE_DATA_OUT_DMA;
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_command_common(dev);
|
2017-05-05 01:49:42 +02:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2023-06-09 23:46:54 -04:00
|
|
|
scsi_disk_data_command_finish(scsi_disk_t *dev, int len, UNUSED(int block_len), int alloc_len, int direction)
|
2017-05-05 01:49:42 +02:00
|
|
|
{
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_log("SCSI HD %i: Finishing command (%02X): %i, %i, %i, %i, %i\n", dev->id,
|
2022-09-18 17:17:15 -04:00
|
|
|
dev->current_cdb[0], len, block_len, alloc_len, direction, dev->request_length);
|
2018-04-25 23:51:13 +02:00
|
|
|
if (alloc_len >= 0) {
|
2022-09-18 17:17:15 -04:00
|
|
|
if (alloc_len < len)
|
|
|
|
|
len = alloc_len;
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
|
|
|
|
if (len == 0)
|
2022-09-18 17:17:15 -04:00
|
|
|
scsi_disk_command_complete(dev);
|
2018-04-25 23:51:13 +02:00
|
|
|
else {
|
2022-09-18 17:17:15 -04:00
|
|
|
if (direction == 0)
|
|
|
|
|
scsi_disk_command_read_dma(dev);
|
|
|
|
|
else
|
|
|
|
|
scsi_disk_command_write_dma(dev);
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
2018-01-06 22:47:41 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2023-06-09 23:46:54 -04:00
|
|
|
scsi_disk_sense_clear(scsi_disk_t *dev, UNUSED(int command))
|
2017-05-05 01:49:42 +02:00
|
|
|
{
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_sense_key = scsi_disk_asc = scsi_disk_ascq = 0;
|
2017-05-05 01:49:42 +02:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_set_phase(scsi_disk_t *dev, uint8_t phase)
|
2017-05-19 01:16:04 +02:00
|
|
|
{
|
2021-07-22 20:13:44 +02:00
|
|
|
uint8_t scsi_bus = (dev->drv->scsi_id >> 4) & 0x0f;
|
2022-09-18 17:17:15 -04:00
|
|
|
uint8_t scsi_id = dev->drv->scsi_id & 0x0f;
|
2017-05-19 01:16:04 +02:00
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
if (dev->drv->bus != HDD_BUS_SCSI)
|
2022-09-18 17:17:15 -04:00
|
|
|
return;
|
2017-08-24 01:14:39 -04:00
|
|
|
|
2021-07-22 20:13:44 +02:00
|
|
|
scsi_devices[scsi_bus][scsi_id].phase = phase;
|
2017-05-19 01:16:04 +02:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_cmd_error(scsi_disk_t *dev)
|
2017-05-27 03:53:32 +02:00
|
|
|
{
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_set_phase(dev, SCSI_PHASE_STATUS);
|
2022-09-18 17:17:15 -04:00
|
|
|
dev->error = ((scsi_disk_sense_key & 0xf) << 4) | ABRT_ERR;
|
|
|
|
|
dev->status = READY_STAT | ERR_STAT;
|
|
|
|
|
dev->phase = 3;
|
2018-10-31 12:23:49 +01:00
|
|
|
dev->packet_status = PHASE_ERROR;
|
2022-09-18 17:17:15 -04:00
|
|
|
dev->callback = 50.0 * SCSI_TIME;
|
2019-09-21 19:15:38 +02:00
|
|
|
ui_sb_update_icon(SB_HDD | dev->drv->bus, 0);
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_log("SCSI HD %i: ERROR: %02X/%02X/%02X\n", dev->id, scsi_disk_sense_key, scsi_disk_asc, scsi_disk_ascq);
|
2017-05-27 03:53:32 +02:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_invalid_lun(scsi_disk_t *dev)
|
2017-05-05 01:49:42 +02:00
|
|
|
{
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_sense_key = SENSE_ILLEGAL_REQUEST;
|
2022-09-18 17:17:15 -04:00
|
|
|
scsi_disk_asc = ASC_INV_LUN;
|
|
|
|
|
scsi_disk_ascq = 0;
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_set_phase(dev, SCSI_PHASE_STATUS);
|
|
|
|
|
scsi_disk_cmd_error(dev);
|
2017-05-05 01:49:42 +02:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_illegal_opcode(scsi_disk_t *dev)
|
2017-05-05 01:49:42 +02:00
|
|
|
{
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_sense_key = SENSE_ILLEGAL_REQUEST;
|
2022-09-18 17:17:15 -04:00
|
|
|
scsi_disk_asc = ASC_ILLEGAL_OPCODE;
|
|
|
|
|
scsi_disk_ascq = 0;
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_cmd_error(dev);
|
2017-05-05 01:49:42 +02:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_lba_out_of_range(scsi_disk_t *dev)
|
2017-05-05 01:49:42 +02:00
|
|
|
{
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_sense_key = SENSE_ILLEGAL_REQUEST;
|
2022-09-18 17:17:15 -04:00
|
|
|
scsi_disk_asc = ASC_LBA_OUT_OF_RANGE;
|
|
|
|
|
scsi_disk_ascq = 0;
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_cmd_error(dev);
|
2017-05-05 01:49:42 +02:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_invalid_field(scsi_disk_t *dev)
|
2017-05-05 01:49:42 +02:00
|
|
|
{
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_sense_key = SENSE_ILLEGAL_REQUEST;
|
2022-09-18 17:17:15 -04:00
|
|
|
scsi_disk_asc = ASC_INV_FIELD_IN_CMD_PACKET;
|
|
|
|
|
scsi_disk_ascq = 0;
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_cmd_error(dev);
|
|
|
|
|
dev->status = 0x53;
|
2017-05-05 01:49:42 +02:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_invalid_field_pl(scsi_disk_t *dev)
|
2017-10-08 05:04:38 +02:00
|
|
|
{
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_sense_key = SENSE_ILLEGAL_REQUEST;
|
2022-09-18 17:17:15 -04:00
|
|
|
scsi_disk_asc = ASC_INV_FIELD_IN_PARAMETER_LIST;
|
|
|
|
|
scsi_disk_ascq = 0;
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_cmd_error(dev);
|
|
|
|
|
dev->status = 0x53;
|
2017-10-08 05:04:38 +02:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_data_phase_error(scsi_disk_t *dev)
|
2017-05-05 01:49:42 +02:00
|
|
|
{
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_sense_key = SENSE_ILLEGAL_REQUEST;
|
2022-09-18 17:17:15 -04:00
|
|
|
scsi_disk_asc = ASC_DATA_PHASE_ERROR;
|
|
|
|
|
scsi_disk_ascq = 0;
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_cmd_error(dev);
|
2017-05-05 01:49:42 +02:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static int
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_pre_execution_check(scsi_disk_t *dev, uint8_t *cdb)
|
2017-05-05 01:49:42 +02:00
|
|
|
{
|
2021-03-23 06:32:18 +01:00
|
|
|
if ((cdb[0] != GPCMD_REQUEST_SENSE) && (dev->cur_lun == SCSI_LUN_USE_CDB) && (cdb[1] & 0xe0)) {
|
2022-09-18 17:17:15 -04:00
|
|
|
scsi_disk_log("SCSI HD %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n",
|
|
|
|
|
dev->id, ((dev->request_length >> 5) & 7));
|
|
|
|
|
scsi_disk_invalid_lun(dev);
|
|
|
|
|
return 0;
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
2017-05-19 01:16:04 +02:00
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
if (!(scsi_disk_command_flags[cdb[0]] & IMPLEMENTED)) {
|
2022-09-18 17:17:15 -04:00
|
|
|
scsi_disk_log("SCSI HD %i: Attempting to execute unknown command %02X\n", dev->id, cdb[0]);
|
|
|
|
|
scsi_disk_illegal_opcode(dev);
|
|
|
|
|
return 0;
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
2017-05-19 01:16:04 +02:00
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
/* 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)
|
2022-09-18 17:17:15 -04:00
|
|
|
scsi_disk_sense_clear(dev, cdb[0]);
|
2017-05-05 01:49:42 +02:00
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_log("SCSI HD %i: Continuing with command\n", dev->id);
|
2017-05-19 01:16:04 +02:00
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
return 1;
|
2017-05-05 01:49:42 +02:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_seek(scsi_disk_t *dev, uint32_t pos)
|
2017-05-05 01:49:42 +02:00
|
|
|
{
|
2018-07-15 01:41:53 +02:00
|
|
|
/* scsi_disk_log("SCSI HD %i: Seek %08X\n", dev->id, pos); */
|
|
|
|
|
hdd_image_seek(dev->id, pos);
|
2017-05-05 01:49:42 +02:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_rezero(scsi_disk_t *dev)
|
2017-05-05 01:49:42 +02:00
|
|
|
{
|
2018-07-15 01:41:53 +02:00
|
|
|
if (dev->id == 0xff)
|
2022-09-18 17:17:15 -04:00
|
|
|
return;
|
2017-05-27 03:53:32 +02:00
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->sector_pos = dev->sector_len = 0;
|
|
|
|
|
scsi_disk_seek(dev, 0);
|
2017-05-05 01:49:42 +02:00
|
|
|
}
|
|
|
|
|
|
2018-10-10 22:33:24 +02:00
|
|
|
static void
|
2018-10-30 13:32:25 +01:00
|
|
|
scsi_disk_reset(scsi_common_t *sc)
|
2017-05-05 01:49:42 +02:00
|
|
|
{
|
2018-10-30 13:32:25 +01:00
|
|
|
scsi_disk_t *dev = (scsi_disk_t *) sc;
|
2018-10-10 22:33:24 +02:00
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_rezero(dev);
|
2022-09-18 17:17:15 -04:00
|
|
|
dev->status = 0;
|
|
|
|
|
dev->callback = 0.0;
|
2018-10-31 12:23:49 +01:00
|
|
|
dev->packet_status = PHASE_NONE;
|
2022-09-18 17:17:15 -04:00
|
|
|
dev->cur_lun = SCSI_LUN_USE_CDB;
|
2017-05-05 01:49:42 +02:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
void
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_request_sense(scsi_disk_t *dev, uint8_t *buffer, uint8_t alloc_length, int desc)
|
2022-02-20 02:26:27 -05:00
|
|
|
{
|
2018-04-25 23:51:13 +02:00
|
|
|
/*Will return 18 bytes of 0*/
|
|
|
|
|
if (alloc_length != 0) {
|
2022-09-18 17:17:15 -04:00
|
|
|
memset(buffer, 0, alloc_length);
|
|
|
|
|
if (!desc)
|
|
|
|
|
memcpy(buffer, dev->sense, alloc_length);
|
|
|
|
|
else {
|
|
|
|
|
buffer[1] = scsi_disk_sense_key;
|
|
|
|
|
buffer[2] = scsi_disk_asc;
|
|
|
|
|
buffer[3] = scsi_disk_ascq;
|
|
|
|
|
}
|
2018-04-25 23:51:13 +02:00
|
|
|
} else
|
2022-09-18 17:17:15 -04:00
|
|
|
return;
|
2017-05-19 01:16:04 +02:00
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
buffer[0] = 0x70;
|
2017-05-05 01:49:42 +02:00
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_log("SCSI HD %i: Reporting sense: %02X %02X %02X\n", dev->id, buffer[2], buffer[12], buffer[13]);
|
2017-05-19 01:16:04 +02:00
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
/* Clear the sense stuff as per the spec. */
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_sense_clear(dev, GPCMD_REQUEST_SENSE);
|
2017-05-05 01:49:42 +02:00
|
|
|
}
|
|
|
|
|
|
2018-10-10 22:33:24 +02:00
|
|
|
static void
|
2018-10-30 13:32:25 +01:00
|
|
|
scsi_disk_request_sense_for_scsi(scsi_common_t *sc, uint8_t *buffer, uint8_t alloc_length)
|
2017-05-05 01:49:42 +02:00
|
|
|
{
|
2018-10-30 13:32:25 +01:00
|
|
|
scsi_disk_t *dev = (scsi_disk_t *) sc;
|
2018-10-10 22:33:24 +02:00
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_request_sense(dev, buffer, alloc_length, 0);
|
2017-05-05 01:49:42 +02:00
|
|
|
}
|
|
|
|
|
|
2018-09-12 19:46:26 +02:00
|
|
|
static void
|
2023-06-09 23:46:54 -04:00
|
|
|
scsi_disk_set_buf_len(UNUSED(scsi_disk_t *dev), int32_t *BufLen, int32_t *src_len)
|
2018-09-12 19:46:26 +02:00
|
|
|
{
|
|
|
|
|
if (*BufLen == -1)
|
2022-09-18 17:17:15 -04:00
|
|
|
*BufLen = *src_len;
|
2018-09-12 19:46:26 +02:00
|
|
|
else {
|
2022-09-18 17:17:15 -04:00
|
|
|
*BufLen = MIN(*src_len, *BufLen);
|
|
|
|
|
*src_len = *BufLen;
|
2018-09-12 19:46:26 +02:00
|
|
|
}
|
|
|
|
|
scsi_disk_log("SCSI HD %i: Actual transfer length: %i\n", dev->id, *BufLen);
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-10 22:33:24 +02:00
|
|
|
static void
|
2018-10-30 13:32:25 +01:00
|
|
|
scsi_disk_buf_alloc(scsi_disk_t *dev, uint32_t len)
|
|
|
|
|
{
|
|
|
|
|
scsi_disk_log("SCSI HD %i: Allocated buffer length: %i\n", dev->id, len);
|
|
|
|
|
if (!dev->temp_buffer)
|
2022-09-18 17:17:15 -04:00
|
|
|
dev->temp_buffer = (uint8_t *) malloc(len);
|
2018-10-30 13:32:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
scsi_disk_buf_free(scsi_disk_t *dev)
|
2017-05-05 01:49:42 +02:00
|
|
|
{
|
2018-10-30 13:32:25 +01:00
|
|
|
if (dev->temp_buffer) {
|
2022-09-18 17:17:15 -04:00
|
|
|
scsi_disk_log("SCSI HD %i: Freeing buffer...\n", dev->id);
|
|
|
|
|
free(dev->temp_buffer);
|
|
|
|
|
dev->temp_buffer = NULL;
|
2018-10-30 13:32:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
scsi_disk_command(scsi_common_t *sc, uint8_t *cdb)
|
|
|
|
|
{
|
|
|
|
|
scsi_disk_t *dev = (scsi_disk_t *) sc;
|
2022-09-18 17:17:15 -04:00
|
|
|
int32_t *BufLen;
|
2023-05-29 01:30:51 -04:00
|
|
|
int32_t len;
|
|
|
|
|
int32_t max_len;
|
|
|
|
|
int32_t alloc_length;
|
2022-09-18 17:17:15 -04:00
|
|
|
int pos = 0;
|
|
|
|
|
int idx = 0;
|
2023-05-29 01:30:51 -04:00
|
|
|
unsigned size_idx;
|
|
|
|
|
unsigned preamble_len;
|
2022-09-18 17:17:15 -04:00
|
|
|
uint32_t last_sector = 0;
|
|
|
|
|
char device_identify[9] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', 0 };
|
|
|
|
|
char device_identify_ex[15] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', ' ', 'v', '1', '.', '0', '0', 0 };
|
|
|
|
|
int block_desc = 0;
|
|
|
|
|
uint8_t scsi_bus = (dev->drv->scsi_id >> 4) & 0x0f;
|
|
|
|
|
uint8_t scsi_id = dev->drv->scsi_id & 0x0f;
|
2018-04-25 23:51:13 +02:00
|
|
|
|
2021-07-22 20:13:44 +02:00
|
|
|
BufLen = &scsi_devices[scsi_bus][scsi_id].buffer_length;
|
2018-04-25 23:51:13 +02:00
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
last_sector = hdd_image_get_last_sector(dev->id);
|
2018-04-25 23:51:13 +02:00
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->status &= ~ERR_STAT;
|
|
|
|
|
dev->packet_len = 0;
|
2018-04-25 23:51:13 +02:00
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
device_identify[6] = (dev->id / 10) + 0x30;
|
|
|
|
|
device_identify[7] = (dev->id % 10) + 0x30;
|
|
|
|
|
|
2022-09-18 17:17:15 -04:00
|
|
|
device_identify_ex[6] = (dev->id / 10) + 0x30;
|
|
|
|
|
device_identify_ex[7] = (dev->id % 10) + 0x30;
|
PIC rewrite, proper SMRAM API, complete SiS 471 rewrite and addition of 40x, 460, and 461, changes to mem.c/h, disabled Voodoo memory dumping on exit, bumped SDL Hardware scale quality to 2, bumped IDE/ATAPI drives to ATA-6, finally bumped emulator version to 3.0, redid the bus type ID's to allow for planned ATAPI hard disks, made SST flash set its high mappings to the correct address if the CPU is 16-bit, and added the SiS 401 AMI 486 Clone, AOpen Vi15G, and the Soyo 4SA2 (486 with SiS 496/497 that can boot from CD-ROM), assorted 286+ protected mode fixes (for slightly more accuracy), and fixes to 808x emulation (MS Word 1.0 and 1.10 for DOS now work correctly from floppy).
2020-10-14 23:15:01 +02:00
|
|
|
device_identify_ex[10] = EMU_VERSION_EX[0];
|
|
|
|
|
device_identify_ex[12] = EMU_VERSION_EX[2];
|
|
|
|
|
device_identify_ex[13] = EMU_VERSION_EX[3];
|
2018-04-25 23:51:13 +02:00
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
memcpy(dev->current_cdb, cdb, 12);
|
2018-04-25 23:51:13 +02:00
|
|
|
|
|
|
|
|
if (cdb[0] != 0) {
|
2022-09-18 17:17:15 -04:00
|
|
|
scsi_disk_log("SCSI HD %i: Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X\n",
|
|
|
|
|
dev->id, cdb[0], scsi_disk_sense_key, scsi_disk_asc, scsi_disk_ascq);
|
|
|
|
|
scsi_disk_log("SCSI HD %i: Request length: %04X\n", dev->id, dev->request_length);
|
2018-04-25 23:51:13 +02:00
|
|
|
|
2022-09-18 17:17:15 -04:00
|
|
|
scsi_disk_log("SCSI HD %i: CDB: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", dev->id,
|
|
|
|
|
cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7],
|
|
|
|
|
cdb[8], cdb[9], cdb[10], cdb[11]);
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
2017-06-16 03:18:59 +02:00
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->sector_len = 0;
|
2017-05-05 01:49:42 +02:00
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_set_phase(dev, SCSI_PHASE_STATUS);
|
2017-05-05 01:49:42 +02:00
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
/* This handles the Not Ready/Unit Attention check if it has to be handled at this point. */
|
2018-07-15 01:41:53 +02:00
|
|
|
if (scsi_disk_pre_execution_check(dev, cdb) == 0)
|
2022-09-18 17:17:15 -04:00
|
|
|
return;
|
2018-04-25 23:51:13 +02:00
|
|
|
|
|
|
|
|
switch (cdb[0]) {
|
2022-09-18 17:17:15 -04:00
|
|
|
case GPCMD_SEND_DIAGNOSTIC:
|
|
|
|
|
if (!(cdb[1] & (1 << 2))) {
|
|
|
|
|
scsi_disk_invalid_field(dev);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2023-07-26 10:57:01 -04:00
|
|
|
#ifdef FALLTHROUGH_ANNOTATION
|
2023-06-09 23:46:54 -04:00
|
|
|
[[fallthrough]];
|
2023-07-20 15:59:54 -04:00
|
|
|
#endif
|
2022-09-18 17:17:15 -04:00
|
|
|
case GPCMD_SCSI_RESERVE:
|
|
|
|
|
case GPCMD_SCSI_RELEASE:
|
|
|
|
|
case GPCMD_TEST_UNIT_READY:
|
|
|
|
|
case GPCMD_FORMAT_UNIT:
|
|
|
|
|
scsi_disk_set_phase(dev, SCSI_PHASE_STATUS);
|
|
|
|
|
scsi_disk_command_complete(dev);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPCMD_REZERO_UNIT:
|
|
|
|
|
dev->sector_pos = dev->sector_len = 0;
|
|
|
|
|
scsi_disk_seek(dev, 0);
|
|
|
|
|
scsi_disk_set_phase(dev, 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. */
|
|
|
|
|
len = cdb[4];
|
|
|
|
|
|
|
|
|
|
if (!len) {
|
|
|
|
|
scsi_disk_set_phase(dev, SCSI_PHASE_STATUS);
|
|
|
|
|
dev->packet_status = PHASE_COMPLETE;
|
|
|
|
|
dev->callback = 20.0 * SCSI_TIME;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
scsi_disk_buf_alloc(dev, 256);
|
|
|
|
|
scsi_disk_set_buf_len(dev, BufLen, &len);
|
|
|
|
|
|
|
|
|
|
if (*BufLen < cdb[4])
|
|
|
|
|
cdb[4] = *BufLen;
|
|
|
|
|
|
|
|
|
|
len = (cdb[1] & 1) ? 8 : 18;
|
|
|
|
|
|
|
|
|
|
scsi_disk_request_sense(dev, dev->temp_buffer, *BufLen, cdb[1] & 1);
|
|
|
|
|
scsi_disk_set_phase(dev, SCSI_PHASE_DATA_IN);
|
|
|
|
|
scsi_disk_data_command_finish(dev, len, len, cdb[4], 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPCMD_MECHANISM_STATUS:
|
|
|
|
|
scsi_disk_set_phase(dev, SCSI_PHASE_DATA_IN);
|
|
|
|
|
len = (cdb[8] << 8) | cdb[9];
|
|
|
|
|
|
|
|
|
|
scsi_disk_buf_alloc(dev, 8);
|
|
|
|
|
scsi_disk_set_buf_len(dev, BufLen, &len);
|
|
|
|
|
|
|
|
|
|
memset(dev->temp_buffer, 0, 8);
|
|
|
|
|
dev->temp_buffer[5] = 1;
|
|
|
|
|
|
|
|
|
|
scsi_disk_data_command_finish(dev, 8, 8, len, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPCMD_READ_6:
|
|
|
|
|
case GPCMD_READ_10:
|
|
|
|
|
case GPCMD_READ_12:
|
|
|
|
|
switch (cdb[0]) {
|
|
|
|
|
case GPCMD_READ_6:
|
|
|
|
|
dev->sector_len = cdb[4];
|
|
|
|
|
if (dev->sector_len == 0)
|
|
|
|
|
dev->sector_len = 256; /* For READ (6) and WRITE (6), a length of 0 indicates a transfer of 256 sector. */
|
|
|
|
|
dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]);
|
|
|
|
|
break;
|
|
|
|
|
case GPCMD_READ_10:
|
|
|
|
|
dev->sector_len = (cdb[7] << 8) | cdb[8];
|
|
|
|
|
dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5];
|
|
|
|
|
break;
|
|
|
|
|
case GPCMD_READ_12:
|
|
|
|
|
dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]);
|
|
|
|
|
dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]);
|
|
|
|
|
break;
|
2023-06-09 23:46:54 -04:00
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
2022-09-18 17:17:15 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((dev->sector_pos > last_sector) /* || ((dev->sector_pos + dev->sector_len - 1) > last_sector)*/) {
|
|
|
|
|
scsi_disk_lba_out_of_range(dev);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((!dev->sector_len) || (*BufLen == 0)) {
|
|
|
|
|
scsi_disk_set_phase(dev, SCSI_PHASE_STATUS);
|
|
|
|
|
scsi_disk_log("SCSI HD %i: All done - callback set\n", dev);
|
|
|
|
|
dev->packet_status = PHASE_COMPLETE;
|
|
|
|
|
dev->callback = 20.0 * SCSI_TIME;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
max_len = dev->sector_len;
|
|
|
|
|
dev->requested_blocks = max_len;
|
|
|
|
|
|
|
|
|
|
alloc_length = dev->packet_len = max_len << 9;
|
|
|
|
|
scsi_disk_buf_alloc(dev, dev->packet_len);
|
|
|
|
|
scsi_disk_set_buf_len(dev, BufLen, &alloc_length);
|
|
|
|
|
scsi_disk_set_phase(dev, SCSI_PHASE_DATA_IN);
|
|
|
|
|
|
|
|
|
|
if ((dev->requested_blocks > 0) && (*BufLen > 0)) {
|
|
|
|
|
if (dev->packet_len > (uint32_t) *BufLen)
|
|
|
|
|
hdd_image_read(dev->id, dev->sector_pos, *BufLen >> 9, dev->temp_buffer);
|
|
|
|
|
else
|
|
|
|
|
hdd_image_read(dev->id, dev->sector_pos, dev->requested_blocks, dev->temp_buffer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dev->requested_blocks > 1)
|
|
|
|
|
scsi_disk_data_command_finish(dev, alloc_length, alloc_length / dev->requested_blocks, alloc_length, 0);
|
|
|
|
|
else
|
|
|
|
|
scsi_disk_data_command_finish(dev, alloc_length, alloc_length, alloc_length, 0);
|
|
|
|
|
|
|
|
|
|
if (dev->packet_status != PHASE_COMPLETE)
|
|
|
|
|
ui_sb_update_icon(SB_HDD | dev->drv->bus, 1);
|
|
|
|
|
else
|
|
|
|
|
ui_sb_update_icon(SB_HDD | dev->drv->bus, 0);
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case GPCMD_VERIFY_6:
|
|
|
|
|
case GPCMD_VERIFY_10:
|
|
|
|
|
case GPCMD_VERIFY_12:
|
|
|
|
|
if (!(cdb[1] & 2)) {
|
|
|
|
|
scsi_disk_set_phase(dev, SCSI_PHASE_STATUS);
|
|
|
|
|
scsi_disk_command_complete(dev);
|
|
|
|
|
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:
|
|
|
|
|
switch (cdb[0]) {
|
|
|
|
|
case GPCMD_VERIFY_6:
|
|
|
|
|
case GPCMD_WRITE_6:
|
|
|
|
|
dev->sector_len = cdb[4];
|
|
|
|
|
if (dev->sector_len == 0)
|
|
|
|
|
dev->sector_len = 256; /* For READ (6) and WRITE (6), a length of 0 indicates a transfer of 256 sector. */
|
|
|
|
|
dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]);
|
|
|
|
|
scsi_disk_log("SCSI HD %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, dev->sector_pos);
|
|
|
|
|
break;
|
|
|
|
|
case GPCMD_VERIFY_10:
|
|
|
|
|
case GPCMD_WRITE_10:
|
|
|
|
|
case GPCMD_WRITE_AND_VERIFY_10:
|
|
|
|
|
dev->sector_len = (cdb[7] << 8) | cdb[8];
|
|
|
|
|
dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5];
|
|
|
|
|
scsi_disk_log("SCSI HD %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, dev->sector_pos);
|
|
|
|
|
break;
|
|
|
|
|
case GPCMD_VERIFY_12:
|
|
|
|
|
case GPCMD_WRITE_12:
|
|
|
|
|
case GPCMD_WRITE_AND_VERIFY_12:
|
|
|
|
|
dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]);
|
|
|
|
|
dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]);
|
|
|
|
|
break;
|
2023-06-09 23:46:54 -04:00
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
2022-09-18 17:17:15 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((dev->sector_pos > last_sector) /* ||
|
|
|
|
|
((dev->sector_pos + dev->sector_len - 1) > last_sector)*/
|
|
|
|
|
) {
|
|
|
|
|
scsi_disk_lba_out_of_range(dev);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((!dev->sector_len) || (*BufLen == 0)) {
|
|
|
|
|
scsi_disk_set_phase(dev, SCSI_PHASE_STATUS);
|
|
|
|
|
scsi_disk_log("SCSI HD %i: All done - callback set\n", dev->id);
|
|
|
|
|
dev->packet_status = PHASE_COMPLETE;
|
|
|
|
|
dev->callback = 20.0 * SCSI_TIME;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
max_len = dev->sector_len;
|
|
|
|
|
dev->requested_blocks = max_len;
|
|
|
|
|
|
|
|
|
|
alloc_length = dev->packet_len = max_len << 9;
|
|
|
|
|
scsi_disk_buf_alloc(dev, dev->packet_len);
|
|
|
|
|
|
|
|
|
|
scsi_disk_set_buf_len(dev, BufLen, &alloc_length);
|
|
|
|
|
scsi_disk_set_phase(dev, SCSI_PHASE_DATA_OUT);
|
|
|
|
|
|
|
|
|
|
if (dev->requested_blocks > 1)
|
|
|
|
|
scsi_disk_data_command_finish(dev, alloc_length, alloc_length / dev->requested_blocks, alloc_length, 1);
|
|
|
|
|
else
|
|
|
|
|
scsi_disk_data_command_finish(dev, alloc_length, alloc_length, alloc_length, 1);
|
|
|
|
|
|
|
|
|
|
if (dev->packet_status != PHASE_COMPLETE)
|
|
|
|
|
ui_sb_update_icon(SB_HDD | dev->drv->bus, 1);
|
|
|
|
|
else
|
|
|
|
|
ui_sb_update_icon(SB_HDD | dev->drv->bus, 0);
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case GPCMD_WRITE_SAME_10:
|
|
|
|
|
scsi_disk_set_phase(dev, SCSI_PHASE_DATA_OUT);
|
|
|
|
|
alloc_length = 512;
|
|
|
|
|
|
|
|
|
|
if ((cdb[1] & 6) == 6) {
|
|
|
|
|
scsi_disk_invalid_field(dev);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dev->sector_len = (cdb[7] << 8) | cdb[8];
|
|
|
|
|
dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5];
|
|
|
|
|
|
|
|
|
|
if ((dev->sector_pos > last_sector) /* ||
|
|
|
|
|
((dev->sector_pos + dev->sector_len - 1) > last_sector)*/
|
|
|
|
|
) {
|
|
|
|
|
scsi_disk_lba_out_of_range(dev);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((!dev->sector_len) || (*BufLen == 0)) {
|
|
|
|
|
scsi_disk_set_phase(dev, SCSI_PHASE_STATUS);
|
|
|
|
|
scsi_disk_log("SCSI HD %i: All done - callback set\n", dev->id);
|
|
|
|
|
dev->packet_status = PHASE_COMPLETE;
|
|
|
|
|
dev->callback = 20.0 * SCSI_TIME;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
scsi_disk_buf_alloc(dev, alloc_length);
|
|
|
|
|
scsi_disk_set_buf_len(dev, BufLen, &alloc_length);
|
|
|
|
|
|
|
|
|
|
max_len = 1;
|
|
|
|
|
dev->requested_blocks = 1;
|
|
|
|
|
|
|
|
|
|
scsi_disk_set_phase(dev, SCSI_PHASE_DATA_OUT);
|
|
|
|
|
|
|
|
|
|
scsi_disk_data_command_finish(dev, 512, 512, alloc_length, 1);
|
|
|
|
|
|
|
|
|
|
if (dev->packet_status != PHASE_COMPLETE)
|
|
|
|
|
ui_sb_update_icon(SB_HDD | dev->drv->bus, 1);
|
|
|
|
|
else
|
|
|
|
|
ui_sb_update_icon(SB_HDD | dev->drv->bus, 0);
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case GPCMD_MODE_SENSE_6:
|
|
|
|
|
case GPCMD_MODE_SENSE_10:
|
|
|
|
|
scsi_disk_set_phase(dev, SCSI_PHASE_DATA_IN);
|
|
|
|
|
|
|
|
|
|
block_desc = ((cdb[1] >> 3) & 1) ? 0 : 1;
|
|
|
|
|
|
|
|
|
|
if (cdb[0] == GPCMD_MODE_SENSE_6) {
|
|
|
|
|
len = cdb[4];
|
|
|
|
|
scsi_disk_buf_alloc(dev, 256);
|
|
|
|
|
} else {
|
|
|
|
|
len = (cdb[8] | (cdb[7] << 8));
|
|
|
|
|
scsi_disk_buf_alloc(dev, 65536);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memset(dev->temp_buffer, 0, len);
|
|
|
|
|
alloc_length = len;
|
|
|
|
|
|
|
|
|
|
if (cdb[0] == GPCMD_MODE_SENSE_6) {
|
|
|
|
|
len = scsi_disk_mode_sense(dev, dev->temp_buffer, 4, cdb[2], block_desc);
|
|
|
|
|
if (len > alloc_length)
|
|
|
|
|
len = alloc_length;
|
|
|
|
|
dev->temp_buffer[0] = len - 1;
|
|
|
|
|
dev->temp_buffer[1] = 0;
|
|
|
|
|
if (block_desc)
|
|
|
|
|
dev->temp_buffer[3] = 8;
|
|
|
|
|
} else {
|
|
|
|
|
len = scsi_disk_mode_sense(dev, dev->temp_buffer, 8, cdb[2], block_desc);
|
|
|
|
|
if (len > alloc_length)
|
|
|
|
|
len = alloc_length;
|
|
|
|
|
dev->temp_buffer[0] = (len - 2) >> 8;
|
|
|
|
|
dev->temp_buffer[1] = (len - 2) & 255;
|
|
|
|
|
dev->temp_buffer[2] = 0;
|
|
|
|
|
if (block_desc) {
|
|
|
|
|
dev->temp_buffer[6] = 0;
|
|
|
|
|
dev->temp_buffer[7] = 8;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (len > alloc_length)
|
|
|
|
|
len = alloc_length;
|
|
|
|
|
else if (len < alloc_length)
|
|
|
|
|
alloc_length = len;
|
|
|
|
|
|
|
|
|
|
scsi_disk_set_buf_len(dev, BufLen, &alloc_length);
|
|
|
|
|
scsi_disk_log("SCSI HDD %i: Reading mode page: %02X...\n", dev->id, cdb[2]);
|
|
|
|
|
|
|
|
|
|
scsi_disk_data_command_finish(dev, len, len, alloc_length, 0);
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case GPCMD_MODE_SELECT_6:
|
|
|
|
|
case GPCMD_MODE_SELECT_10:
|
|
|
|
|
scsi_disk_set_phase(dev, SCSI_PHASE_DATA_OUT);
|
|
|
|
|
|
|
|
|
|
if (cdb[0] == GPCMD_MODE_SELECT_6) {
|
|
|
|
|
len = cdb[4];
|
|
|
|
|
scsi_disk_buf_alloc(dev, 256);
|
|
|
|
|
} else {
|
|
|
|
|
len = (cdb[7] << 8) | cdb[8];
|
|
|
|
|
scsi_disk_buf_alloc(dev, 65536);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
scsi_disk_set_buf_len(dev, BufLen, &len);
|
|
|
|
|
dev->total_length = len;
|
|
|
|
|
dev->do_page_save = cdb[1] & 1;
|
|
|
|
|
scsi_disk_data_command_finish(dev, len, len, len, 1);
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case GPCMD_INQUIRY:
|
|
|
|
|
max_len = cdb[3];
|
|
|
|
|
max_len <<= 8;
|
|
|
|
|
max_len |= cdb[4];
|
|
|
|
|
|
|
|
|
|
if ((!max_len) || (*BufLen == 0)) {
|
|
|
|
|
scsi_disk_set_phase(dev, SCSI_PHASE_STATUS);
|
|
|
|
|
/* scsi_disk_log("SCSI HD %i: All done - callback set\n", dev->id); */
|
|
|
|
|
dev->packet_status = PHASE_COMPLETE;
|
|
|
|
|
dev->callback = 20.0 * SCSI_TIME;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
scsi_disk_buf_alloc(dev, 65536);
|
|
|
|
|
|
|
|
|
|
if (cdb[1] & 1) {
|
|
|
|
|
preamble_len = 4;
|
|
|
|
|
size_idx = 3;
|
|
|
|
|
|
|
|
|
|
dev->temp_buffer[idx++] = 05;
|
|
|
|
|
dev->temp_buffer[idx++] = cdb[2];
|
|
|
|
|
dev->temp_buffer[idx++] = 0;
|
|
|
|
|
|
|
|
|
|
idx++;
|
|
|
|
|
|
|
|
|
|
switch (cdb[2]) {
|
|
|
|
|
case 0x00:
|
|
|
|
|
dev->temp_buffer[idx++] = 0x00;
|
|
|
|
|
dev->temp_buffer[idx++] = 0x83;
|
|
|
|
|
break;
|
|
|
|
|
case 0x83:
|
|
|
|
|
if (idx + 24 > max_len) {
|
|
|
|
|
scsi_disk_buf_free(dev);
|
|
|
|
|
scsi_disk_data_phase_error(dev);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dev->temp_buffer[idx++] = 0x02;
|
|
|
|
|
dev->temp_buffer[idx++] = 0x00;
|
|
|
|
|
dev->temp_buffer[idx++] = 0x00;
|
|
|
|
|
dev->temp_buffer[idx++] = 20;
|
|
|
|
|
ide_padstr8(dev->temp_buffer + idx, 20, "53R141"); /* Serial */
|
|
|
|
|
idx += 20;
|
|
|
|
|
|
|
|
|
|
if (idx + 72 > cdb[4])
|
|
|
|
|
goto atapi_out;
|
|
|
|
|
dev->temp_buffer[idx++] = 0x02;
|
|
|
|
|
dev->temp_buffer[idx++] = 0x01;
|
|
|
|
|
dev->temp_buffer[idx++] = 0x00;
|
|
|
|
|
dev->temp_buffer[idx++] = 68;
|
|
|
|
|
ide_padstr8(dev->temp_buffer + idx, 8, EMU_NAME); /* Vendor */
|
|
|
|
|
idx += 8;
|
|
|
|
|
ide_padstr8(dev->temp_buffer + idx, 40, device_identify_ex); /* Product */
|
|
|
|
|
idx += 40;
|
|
|
|
|
ide_padstr8(dev->temp_buffer + idx, 20, "53R141"); /* Product */
|
|
|
|
|
idx += 20;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
scsi_disk_log("INQUIRY: Invalid page: %02X\n", cdb[2]);
|
|
|
|
|
scsi_disk_invalid_field(dev);
|
|
|
|
|
scsi_disk_buf_free(dev);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
preamble_len = 5;
|
|
|
|
|
size_idx = 4;
|
|
|
|
|
|
|
|
|
|
memset(dev->temp_buffer, 0, 8);
|
|
|
|
|
dev->temp_buffer[0] = 0; /*SCSI HD*/
|
|
|
|
|
dev->temp_buffer[1] = 0; /*Fixed*/
|
|
|
|
|
dev->temp_buffer[2] = 0x02; /*SCSI-2 compliant*/
|
|
|
|
|
dev->temp_buffer[3] = 0x02;
|
|
|
|
|
dev->temp_buffer[4] = 31;
|
|
|
|
|
dev->temp_buffer[6] = 1; /* 16-bit transfers supported */
|
|
|
|
|
dev->temp_buffer[7] = 0x20; /* Wide bus supported */
|
|
|
|
|
|
|
|
|
|
ide_padstr8(dev->temp_buffer + 8, 8, EMU_NAME); /* Vendor */
|
|
|
|
|
ide_padstr8(dev->temp_buffer + 16, 16, device_identify); /* Product */
|
|
|
|
|
ide_padstr8(dev->temp_buffer + 32, 4, EMU_VERSION_EX); /* Revision */
|
|
|
|
|
idx = 36;
|
|
|
|
|
|
|
|
|
|
if (max_len == 96) {
|
|
|
|
|
dev->temp_buffer[4] = 91;
|
|
|
|
|
idx = 96;
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-05-29 06:17:13 +02:00
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
atapi_out:
|
2022-09-18 17:17:15 -04:00
|
|
|
dev->temp_buffer[size_idx] = idx - preamble_len;
|
|
|
|
|
len = idx;
|
|
|
|
|
|
|
|
|
|
if (len > max_len)
|
|
|
|
|
len = max_len;
|
|
|
|
|
|
|
|
|
|
scsi_disk_set_buf_len(dev, BufLen, &len);
|
|
|
|
|
|
|
|
|
|
if (len > *BufLen)
|
|
|
|
|
len = *BufLen;
|
|
|
|
|
|
|
|
|
|
scsi_disk_set_phase(dev, SCSI_PHASE_DATA_IN);
|
|
|
|
|
scsi_disk_data_command_finish(dev, len, len, max_len, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPCMD_PREVENT_REMOVAL:
|
|
|
|
|
scsi_disk_set_phase(dev, SCSI_PHASE_STATUS);
|
|
|
|
|
scsi_disk_command_complete(dev);
|
|
|
|
|
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;
|
2023-06-09 23:46:54 -04:00
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
2022-09-18 17:17:15 -04:00
|
|
|
}
|
|
|
|
|
scsi_disk_seek(dev, pos);
|
|
|
|
|
|
|
|
|
|
scsi_disk_set_phase(dev, SCSI_PHASE_STATUS);
|
|
|
|
|
scsi_disk_command_complete(dev);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPCMD_READ_CDROM_CAPACITY:
|
|
|
|
|
scsi_disk_buf_alloc(dev, 8);
|
|
|
|
|
|
|
|
|
|
max_len = hdd_image_get_last_sector(dev->id);
|
|
|
|
|
memset(dev->temp_buffer, 0, 8);
|
|
|
|
|
dev->temp_buffer[0] = (max_len >> 24) & 0xff;
|
|
|
|
|
dev->temp_buffer[1] = (max_len >> 16) & 0xff;
|
|
|
|
|
dev->temp_buffer[2] = (max_len >> 8) & 0xff;
|
|
|
|
|
dev->temp_buffer[3] = max_len & 0xff;
|
|
|
|
|
dev->temp_buffer[6] = 2;
|
|
|
|
|
len = 8;
|
|
|
|
|
|
|
|
|
|
scsi_disk_set_buf_len(dev, BufLen, &len);
|
|
|
|
|
|
|
|
|
|
scsi_disk_set_phase(dev, SCSI_PHASE_DATA_IN);
|
|
|
|
|
scsi_disk_data_command_finish(dev, len, len, len, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
scsi_disk_illegal_opcode(dev);
|
|
|
|
|
break;
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
2017-10-14 07:03:19 +02:00
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
/* scsi_disk_log("SCSI HD %i: Phase: %02X, request length: %i\n", dev->id, dev->phase, dev->request_length); */
|
2017-10-14 07:03:19 +02:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2018-10-30 13:32:25 +01:00
|
|
|
scsi_disk_command_stop(scsi_common_t *sc)
|
2018-04-25 23:51:13 +02:00
|
|
|
{
|
2018-10-30 13:32:25 +01:00
|
|
|
scsi_disk_t *dev = (scsi_disk_t *) sc;
|
2018-01-13 22:56:13 +01:00
|
|
|
|
2018-10-30 13:32:25 +01:00
|
|
|
scsi_disk_command_complete(dev);
|
|
|
|
|
scsi_disk_buf_free(dev);
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
2018-01-13 22:56:13 +01:00
|
|
|
|
2018-10-31 12:23:49 +01:00
|
|
|
static uint8_t
|
2018-10-30 13:32:25 +01:00
|
|
|
scsi_disk_phase_data_out(scsi_common_t *sc)
|
2018-04-25 23:51:13 +02:00
|
|
|
{
|
2023-06-09 23:46:54 -04:00
|
|
|
scsi_disk_t *dev = (scsi_disk_t *) sc;
|
|
|
|
|
uint8_t scsi_bus = (dev->drv->scsi_id >> 4) & 0x0f;
|
|
|
|
|
uint8_t scsi_id = dev->drv->scsi_id & 0x0f;
|
|
|
|
|
int i;
|
|
|
|
|
const int32_t *BufLen = &scsi_devices[scsi_bus][scsi_id].buffer_length;
|
|
|
|
|
uint32_t last_sector = hdd_image_get_last_sector(dev->id);
|
|
|
|
|
uint32_t c;
|
|
|
|
|
uint32_t h;
|
|
|
|
|
uint32_t s;
|
|
|
|
|
uint32_t last_to_write = 0;
|
|
|
|
|
uint16_t block_desc_len;
|
|
|
|
|
uint16_t pos;
|
|
|
|
|
uint16_t param_list_len;
|
|
|
|
|
uint8_t hdr_len;
|
|
|
|
|
uint8_t val;
|
|
|
|
|
uint8_t old_val;
|
|
|
|
|
uint8_t ch;
|
|
|
|
|
uint8_t error = 0;
|
|
|
|
|
uint8_t page;
|
|
|
|
|
uint8_t page_len;
|
2018-04-25 23:51:13 +02:00
|
|
|
|
|
|
|
|
if (!*BufLen) {
|
2022-09-18 17:17:15 -04:00
|
|
|
scsi_disk_set_phase(dev, SCSI_PHASE_STATUS);
|
2017-10-14 07:03:19 +02:00
|
|
|
|
2022-09-18 17:17:15 -04:00
|
|
|
return 1;
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
2017-10-14 07:03:19 +02:00
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
switch (dev->current_cdb[0]) {
|
2022-09-18 17:17:15 -04:00
|
|
|
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 ((dev->requested_blocks > 0) && (*BufLen > 0)) {
|
|
|
|
|
if (dev->packet_len > (uint32_t) *BufLen)
|
|
|
|
|
hdd_image_write(dev->id, dev->sector_pos, *BufLen >> 9, dev->temp_buffer);
|
|
|
|
|
else
|
|
|
|
|
hdd_image_write(dev->id, dev->sector_pos, dev->requested_blocks, dev->temp_buffer);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case GPCMD_WRITE_SAME_10:
|
|
|
|
|
if (!dev->current_cdb[7] && !dev->current_cdb[8])
|
|
|
|
|
last_to_write = last_sector;
|
|
|
|
|
else
|
|
|
|
|
last_to_write = dev->sector_pos + dev->sector_len - 1;
|
|
|
|
|
|
|
|
|
|
for (i = dev->sector_pos; i <= (int) last_to_write; i++) {
|
|
|
|
|
if (dev->current_cdb[1] & 2) {
|
|
|
|
|
dev->temp_buffer[0] = (i >> 24) & 0xff;
|
|
|
|
|
dev->temp_buffer[1] = (i >> 16) & 0xff;
|
|
|
|
|
dev->temp_buffer[2] = (i >> 8) & 0xff;
|
|
|
|
|
dev->temp_buffer[3] = i & 0xff;
|
|
|
|
|
} else if (dev->current_cdb[1] & 4) {
|
|
|
|
|
s = (i % dev->drv->spt);
|
|
|
|
|
h = ((i - s) / dev->drv->spt) % dev->drv->hpc;
|
|
|
|
|
c = ((i - s) / dev->drv->spt) / dev->drv->hpc;
|
|
|
|
|
dev->temp_buffer[0] = (c >> 16) & 0xff;
|
|
|
|
|
dev->temp_buffer[1] = (c >> 8) & 0xff;
|
|
|
|
|
dev->temp_buffer[2] = c & 0xff;
|
|
|
|
|
dev->temp_buffer[3] = h & 0xff;
|
|
|
|
|
dev->temp_buffer[4] = (s >> 24) & 0xff;
|
|
|
|
|
dev->temp_buffer[5] = (s >> 16) & 0xff;
|
|
|
|
|
dev->temp_buffer[6] = (s >> 8) & 0xff;
|
|
|
|
|
dev->temp_buffer[7] = s & 0xff;
|
|
|
|
|
}
|
|
|
|
|
hdd_image_write(dev->id, i, 1, dev->temp_buffer);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case GPCMD_MODE_SELECT_6:
|
|
|
|
|
case GPCMD_MODE_SELECT_10:
|
|
|
|
|
if (dev->current_cdb[0] == GPCMD_MODE_SELECT_10) {
|
|
|
|
|
hdr_len = 8;
|
|
|
|
|
param_list_len = dev->current_cdb[7];
|
|
|
|
|
param_list_len <<= 8;
|
|
|
|
|
param_list_len |= dev->current_cdb[8];
|
|
|
|
|
} else {
|
|
|
|
|
hdr_len = 4;
|
|
|
|
|
param_list_len = dev->current_cdb[4];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dev->current_cdb[0] == GPCMD_MODE_SELECT_6) {
|
|
|
|
|
block_desc_len = dev->temp_buffer[2];
|
|
|
|
|
block_desc_len <<= 8;
|
|
|
|
|
block_desc_len |= dev->temp_buffer[3];
|
|
|
|
|
} else {
|
|
|
|
|
block_desc_len = dev->temp_buffer[6];
|
|
|
|
|
block_desc_len <<= 8;
|
|
|
|
|
block_desc_len |= dev->temp_buffer[7];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pos = hdr_len + block_desc_len;
|
|
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
|
if (pos >= param_list_len) {
|
|
|
|
|
scsi_disk_log("SCSI HD %i: Buffer has only block descriptor\n", dev->id);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
page = dev->temp_buffer[pos] & 0x3F;
|
|
|
|
|
page_len = dev->temp_buffer[pos + 1];
|
|
|
|
|
|
|
|
|
|
pos += 2;
|
|
|
|
|
|
|
|
|
|
if (!(scsi_disk_mode_sense_page_flags & (1LL << ((uint64_t) page))))
|
|
|
|
|
error |= 1;
|
|
|
|
|
else {
|
|
|
|
|
for (i = 0; i < page_len; i++) {
|
|
|
|
|
ch = scsi_disk_mode_sense_pages_changeable.pages[page][i + 2];
|
|
|
|
|
val = dev->temp_buffer[pos + i];
|
|
|
|
|
old_val = dev->ms_pages_saved.pages[page][i + 2];
|
|
|
|
|
if (val != old_val) {
|
|
|
|
|
if (ch)
|
|
|
|
|
dev->ms_pages_saved.pages[page][i + 2] = val;
|
|
|
|
|
else
|
|
|
|
|
error |= 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pos += page_len;
|
|
|
|
|
|
|
|
|
|
val = scsi_disk_mode_sense_pages_default.pages[page][0] & 0x80;
|
|
|
|
|
if (dev->do_page_save && val)
|
|
|
|
|
scsi_disk_mode_sense_save(dev);
|
|
|
|
|
|
|
|
|
|
if (pos >= dev->total_length)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
|
scsi_disk_buf_free(dev);
|
|
|
|
|
scsi_disk_invalid_field_pl(dev);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
fatal("SCSI HDD %i: Bad Command for phase 2 (%02X)\n", dev->id, dev->current_cdb[0]);
|
|
|
|
|
break;
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
2017-10-14 07:03:19 +02:00
|
|
|
|
2018-10-30 13:32:25 +01:00
|
|
|
scsi_disk_command_stop((scsi_common_t *) dev);
|
2018-10-31 12:23:49 +01:00
|
|
|
return 1;
|
2017-05-05 01:49:42 +02:00
|
|
|
}
|
2018-07-15 01:41:53 +02:00
|
|
|
|
|
|
|
|
void
|
|
|
|
|
scsi_disk_hard_reset(void)
|
|
|
|
|
{
|
2022-09-18 17:17:15 -04:00
|
|
|
scsi_disk_t *dev;
|
2018-10-10 22:33:24 +02:00
|
|
|
scsi_device_t *sd;
|
2023-05-29 01:30:51 -04:00
|
|
|
uint8_t scsi_bus;
|
|
|
|
|
uint8_t scsi_id;
|
2018-07-15 01:41:53 +02:00
|
|
|
|
2023-05-29 01:30:51 -04:00
|
|
|
for (uint8_t c = 0; c < HDD_NUM; c++) {
|
2022-09-18 17:17:15 -04:00
|
|
|
if (hdd[c].bus == HDD_BUS_SCSI) {
|
|
|
|
|
scsi_disk_log("SCSI disk hard_reset drive=%d\n", c);
|
2018-07-15 01:41:53 +02:00
|
|
|
|
2022-09-18 17:17:15 -04:00
|
|
|
scsi_bus = (hdd[c].scsi_id >> 4) & 0x0f;
|
|
|
|
|
scsi_id = hdd[c].scsi_id & 0x0f;
|
2021-07-22 20:13:44 +02:00
|
|
|
|
2022-09-18 17:17:15 -04:00
|
|
|
/* Make sure to ignore any SCSI disk that has an out of range SCSI bus. */
|
|
|
|
|
if (scsi_bus >= SCSI_BUS_MAX)
|
|
|
|
|
continue;
|
2021-07-22 20:13:44 +02:00
|
|
|
|
2022-09-18 17:17:15 -04:00
|
|
|
/* Make sure to ignore any SCSI disk that has an out of range ID. */
|
|
|
|
|
if (scsi_id >= SCSI_ID_MAX)
|
|
|
|
|
continue;
|
2018-10-10 22:33:24 +02:00
|
|
|
|
2022-09-18 17:17:15 -04:00
|
|
|
/* Make sure to ignore any SCSI disk whose image file name is empty. */
|
|
|
|
|
if (strlen(hdd[c].fn) == 0)
|
|
|
|
|
continue;
|
2018-10-10 22:33:24 +02:00
|
|
|
|
2022-09-18 17:17:15 -04:00
|
|
|
/* Make sure to ignore any SCSI disk whose image fails to load. */
|
|
|
|
|
if (!hdd_image_load(c))
|
|
|
|
|
continue;
|
2018-10-10 22:33:24 +02:00
|
|
|
|
2022-09-18 17:17:15 -04:00
|
|
|
if (!hdd[c].priv) {
|
|
|
|
|
hdd[c].priv = (scsi_disk_t *) malloc(sizeof(scsi_disk_t));
|
|
|
|
|
memset(hdd[c].priv, 0, sizeof(scsi_disk_t));
|
|
|
|
|
}
|
2018-07-15 01:41:53 +02:00
|
|
|
|
2022-09-18 17:17:15 -04:00
|
|
|
dev = (scsi_disk_t *) hdd[c].priv;
|
2018-10-26 04:47:21 +02:00
|
|
|
|
2022-09-18 17:17:15 -04:00
|
|
|
/* SCSI disk, attach to the SCSI bus. */
|
|
|
|
|
sd = &scsi_devices[scsi_bus][scsi_id];
|
2018-10-10 22:33:24 +02:00
|
|
|
|
2022-09-18 17:17:15 -04:00
|
|
|
sd->sc = (scsi_common_t *) dev;
|
|
|
|
|
sd->command = scsi_disk_command;
|
|
|
|
|
sd->request_sense = scsi_disk_request_sense_for_scsi;
|
|
|
|
|
sd->reset = scsi_disk_reset;
|
|
|
|
|
sd->phase_data_out = scsi_disk_phase_data_out;
|
|
|
|
|
sd->command_stop = scsi_disk_command_stop;
|
|
|
|
|
sd->type = SCSI_FIXED_DISK;
|
2018-10-10 22:33:24 +02:00
|
|
|
|
2022-09-18 17:17:15 -04:00
|
|
|
dev->id = c;
|
|
|
|
|
dev->drv = &hdd[c];
|
2018-07-15 01:41:53 +02:00
|
|
|
|
2022-09-18 17:17:15 -04:00
|
|
|
dev->cur_lun = SCSI_LUN_USE_CDB;
|
2021-03-23 06:32:18 +01:00
|
|
|
|
2022-09-18 17:17:15 -04:00
|
|
|
scsi_disk_mode_sense_load(dev);
|
2018-10-10 22:33:24 +02:00
|
|
|
|
2022-09-18 17:17:15 -04:00
|
|
|
scsi_disk_log("SCSI disk %i attached to SCSI ID %i\n", c, hdd[c].scsi_id);
|
|
|
|
|
}
|
2018-07-15 01:41:53 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
scsi_disk_close(void)
|
|
|
|
|
{
|
|
|
|
|
scsi_disk_t *dev;
|
2023-05-29 01:30:51 -04:00
|
|
|
uint8_t scsi_bus;
|
|
|
|
|
uint8_t scsi_id;
|
2018-07-15 01:41:53 +02:00
|
|
|
|
2023-05-29 01:30:51 -04:00
|
|
|
for (uint8_t c = 0; c < HDD_NUM; c++) {
|
2022-09-18 17:17:15 -04:00
|
|
|
if (hdd[c].bus == HDD_BUS_SCSI) {
|
|
|
|
|
scsi_bus = (hdd[c].scsi_id >> 4) & 0x0f;
|
|
|
|
|
scsi_id = hdd[c].scsi_id & 0x0f;
|
2021-07-22 20:13:44 +02:00
|
|
|
|
2022-09-18 17:17:15 -04:00
|
|
|
memset(&scsi_devices[scsi_bus][scsi_id], 0x00, sizeof(scsi_device_t));
|
2020-06-14 21:59:45 +02:00
|
|
|
|
2022-09-18 17:17:15 -04:00
|
|
|
hdd_image_close(c);
|
2018-07-15 01:41:53 +02:00
|
|
|
|
2022-09-18 17:17:15 -04:00
|
|
|
dev = hdd[c].priv;
|
2018-10-30 13:32:25 +01:00
|
|
|
|
2022-09-18 17:17:15 -04:00
|
|
|
if (dev) {
|
|
|
|
|
free(dev);
|
|
|
|
|
hdd[c].priv = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-07-15 01:41:53 +02:00
|
|
|
}
|
|
|
|
|
}
|