2018-01-26 22:17:09 +01: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.
|
2018-01-26 22:17:09 +01:00
|
|
|
*
|
2022-11-13 16:37:58 -05:00
|
|
|
* This file is part of the 86Box distribution.
|
2018-01-26 22:17:09 +01:00
|
|
|
*
|
2022-11-13 16:37:58 -05:00
|
|
|
* Implementation of the Iomega ZIP drive with SCSI(-like)
|
|
|
|
|
* commands, for both ATAPI and SCSI usage.
|
2018-01-26 22:17:09 +01:00
|
|
|
*
|
2022-11-13 16:37:58 -05:00
|
|
|
* Authors: Miran Grca, <mgrca8@gmail.com>
|
2018-01-26 22:17:09 +01:00
|
|
|
*
|
2025-01-28 16:26:28 +01:00
|
|
|
* Copyright 2018-2025 Miran Grca.
|
2018-01-26 22:17:09 +01:00
|
|
|
*/
|
2025-07-25 16:30:40 +02:00
|
|
|
#ifdef ENABLE_RDISK_LOG
|
2025-01-28 16:26:28 +01:00
|
|
|
#include <stdarg.h>
|
|
|
|
|
#endif
|
2018-01-26 22:17:09 +01:00
|
|
|
#include <stdint.h>
|
2025-01-28 16:26:28 +01:00
|
|
|
#include <stdio.h>
|
2018-01-26 22:17:09 +01:00
|
|
|
#include <stdlib.h>
|
2025-01-28 16:26:28 +01:00
|
|
|
#include <string.h>
|
2020-03-29 14:24:42 +02:00
|
|
|
#include <86box/86box.h>
|
|
|
|
|
#include <86box/timer.h>
|
|
|
|
|
#include <86box/device.h>
|
2025-01-28 16:26:28 +01:00
|
|
|
#include <86box/log.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/nvr.h>
|
2025-01-28 16:26:28 +01:00
|
|
|
#include <86box/path.h>
|
2020-03-29 14:24:42 +02:00
|
|
|
#include <86box/plat.h>
|
|
|
|
|
#include <86box/ui.h>
|
|
|
|
|
#include <86box/hdc_ide.h>
|
2025-07-25 16:30:40 +02:00
|
|
|
#include <86box/rdisk.h>
|
|
|
|
|
#include <86box/version.h>
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2023-10-28 22:00:23 +02:00
|
|
|
#define IDE_ATAPI_IS_EARLY id->sc->pad0
|
|
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_drive_t rdisk_drives[RDISK_NUM];
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
// clang-format off
|
|
|
|
|
/*
|
|
|
|
|
Table of all SCSI commands and their flags, needed for the new disc change /
|
|
|
|
|
not ready handler.
|
|
|
|
|
*/
|
2025-07-25 16:30:40 +02:00
|
|
|
const uint8_t rdisk_command_flags[0x100] = {
|
2025-01-28 16:26:28 +01:00
|
|
|
[0x00] = IMPLEMENTED | CHECK_READY,
|
|
|
|
|
[0x01] = IMPLEMENTED | ALLOW_UA | SCSI_ONLY,
|
|
|
|
|
[0x03] = IMPLEMENTED | ALLOW_UA,
|
|
|
|
|
[0x04] = IMPLEMENTED | CHECK_READY | ALLOW_UA | SCSI_ONLY,
|
|
|
|
|
[0x06] = IMPLEMENTED,
|
|
|
|
|
[0x08] = IMPLEMENTED | CHECK_READY,
|
|
|
|
|
[0x0a ... 0x0b] = IMPLEMENTED | CHECK_READY,
|
|
|
|
|
[0x0c] = IMPLEMENTED,
|
|
|
|
|
[0x0d] = IMPLEMENTED | ATAPI_ONLY,
|
|
|
|
|
[0x12] = IMPLEMENTED | ALLOW_UA,
|
2025-03-18 00:43:49 +01:00
|
|
|
[0x13] = IMPLEMENTED | CHECK_READY,
|
2025-01-28 16:26:28 +01:00
|
|
|
[0x15] = IMPLEMENTED,
|
|
|
|
|
[0x16 ... 0x17] = IMPLEMENTED | SCSI_ONLY,
|
|
|
|
|
[0x1a] = IMPLEMENTED,
|
|
|
|
|
[0x1b] = IMPLEMENTED | CHECK_READY,
|
|
|
|
|
[0x1d] = IMPLEMENTED,
|
|
|
|
|
[0x1e] = IMPLEMENTED | CHECK_READY,
|
|
|
|
|
[0x23] = IMPLEMENTED | ATAPI_ONLY,
|
|
|
|
|
[0x25] = IMPLEMENTED | CHECK_READY,
|
|
|
|
|
[0x28] = IMPLEMENTED | CHECK_READY,
|
|
|
|
|
[0x2a ... 0x2b] = IMPLEMENTED | CHECK_READY,
|
2025-03-18 00:43:49 +01:00
|
|
|
[0x2e ... 0x2f] = IMPLEMENTED | CHECK_READY,
|
2025-01-28 16:26:28 +01:00
|
|
|
[0x41] = IMPLEMENTED | CHECK_READY,
|
|
|
|
|
[0x55] = IMPLEMENTED,
|
|
|
|
|
[0x5a] = IMPLEMENTED,
|
|
|
|
|
[0xa8] = IMPLEMENTED | CHECK_READY,
|
|
|
|
|
[0xaa] = IMPLEMENTED | CHECK_READY,
|
|
|
|
|
[0xae] = IMPLEMENTED | CHECK_READY,
|
|
|
|
|
[0xaf] = IMPLEMENTED | CHECK_READY | SCSI_ONLY,
|
|
|
|
|
[0xbd] = IMPLEMENTED
|
2018-01-26 22:17:09 +01:00
|
|
|
};
|
|
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
static uint64_t zip_mode_sense_page_flags = (GPMODEP_R_W_ERROR_PAGE | GPMODEP_DISCONNECT_PAGE |
|
|
|
|
|
GPMODEP_IOMEGA_PAGE | GPMODEP_ALL_PAGES);
|
|
|
|
|
static uint64_t zip_250_mode_sense_page_flags = (GPMODEP_R_W_ERROR_PAGE | GPMODEP_FLEXIBLE_DISK_PAGE |
|
|
|
|
|
GPMODEP_CACHING_PAGE | GPMODEP_IOMEGA_PAGE |
|
|
|
|
|
GPMODEP_ALL_PAGES);
|
|
|
|
|
|
|
|
|
|
static const mode_sense_pages_t zip_mode_sense_pages_default = {
|
|
|
|
|
{ [0x01] = { GPMODE_R_W_ERROR_PAGE, 0x0a, 0xc8, 0x16, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x5a, 0x00, 0x50, 0x20 },
|
|
|
|
|
[0x02] = { GPMODE_DISCONNECT_PAGE, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
|
|
|
|
[0x2f] = { GPMODE_IOMEGA_PAGE, 0x04, 0x5c, 0x0f, 0xff, 0x0f } }
|
|
|
|
|
};
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
static const mode_sense_pages_t zip_250_mode_sense_pages_default = {
|
|
|
|
|
{ [0x01] = { GPMODE_R_W_ERROR_PAGE, 0x06, 0xc8, 0x64, 0x00, 0x00, 0x00, 0x00 },
|
|
|
|
|
[0x05] = { GPMODE_FLEXIBLE_DISK_PAGE, 0x1e, 0x80, 0x00, 0x40, 0x20, 0x02, 0x00,
|
|
|
|
|
0x00, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x0b, 0x7d, 0x00, 0x00 },
|
|
|
|
|
[0x08] = { GPMODE_CACHING_PAGE, 0x0a, 0x04, 0x00, 0xff, 0xff, 0x00, 0x00,
|
|
|
|
|
0xff, 0xff, 0xff, 0xff },
|
|
|
|
|
[0x2f] = { GPMODE_IOMEGA_PAGE, 0x04, 0x5c, 0x0f, 0x3c, 0x0f } }
|
|
|
|
|
};
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
static const mode_sense_pages_t zip_mode_sense_pages_default_scsi = {
|
|
|
|
|
{ [0x01] = { GPMODE_R_W_ERROR_PAGE, 0x0a, 0xc8, 0x16, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x5a, 0x00, 0x50, 0x20 },
|
|
|
|
|
[0x02] = { GPMODE_DISCONNECT_PAGE, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
|
|
|
|
[0x2f] = { GPMODE_IOMEGA_PAGE, 0x04, 0x5c, 0x0f, 0xff, 0x0f } }
|
|
|
|
|
};
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
static const mode_sense_pages_t zip_250_mode_sense_pages_default_scsi = {
|
|
|
|
|
{ [0x01] = { GPMODE_R_W_ERROR_PAGE, 0x06, 0xc8, 0x64, 0x00, 0x00, 0x00, 0x00 },
|
|
|
|
|
[0x05] = { GPMODE_FLEXIBLE_DISK_PAGE, 0x1e, 0x80, 0x00, 0x40, 0x20, 0x02, 0x00,
|
|
|
|
|
0x00, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x0b, 0x7d, 0x00, 0x00 },
|
|
|
|
|
[0x08] = { GPMODE_CACHING_PAGE, 0x0a, 0x04, 0x00, 0xff, 0xff, 0x00, 0x00,
|
|
|
|
|
0xff, 0xff, 0xff, 0xff },
|
|
|
|
|
[0x2f] = { GPMODE_IOMEGA_PAGE, 0x04, 0x5c, 0x0f, 0x3c, 0x0f } }
|
|
|
|
|
};
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
static const mode_sense_pages_t zip_mode_sense_pages_changeable = {
|
|
|
|
|
{ [0x01] = { GPMODE_R_W_ERROR_PAGE, 0x0a, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff,
|
|
|
|
|
0x5a, 0xff, 0xff, 0xff },
|
|
|
|
|
[0x02] = { GPMODE_DISCONNECT_PAGE, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
|
|
|
|
[0x2f] = { GPMODE_IOMEGA_PAGE, 0x04, 0xff, 0xff, 0xff, 0xff } }
|
|
|
|
|
};
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
static const mode_sense_pages_t zip_250_mode_sense_pages_changeable = {
|
|
|
|
|
{ [0x01] = { GPMODE_R_W_ERROR_PAGE, 0x06, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 },
|
|
|
|
|
[0x05] = { GPMODE_FLEXIBLE_DISK_PAGE, 0x1e, 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, 0x00, 0x00 },
|
|
|
|
|
[0x08] = { GPMODE_CACHING_PAGE, 0x0a, 0x04, 0x00, 0xff, 0xff, 0x00, 0x00,
|
|
|
|
|
0xff, 0xff, 0xff, 0xff },
|
|
|
|
|
[0x2f] = { GPMODE_IOMEGA_PAGE, 0x04, 0xff, 0xff, 0xff, 0xff } }
|
|
|
|
|
};
|
2022-09-18 17:13:50 -04:00
|
|
|
// clang-format on
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
static void rdisk_command_complete(rdisk_t *dev);
|
|
|
|
|
static void rdisk_init(rdisk_t *dev);
|
2018-04-25 23:51:13 +02:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
#ifdef ENABLE_RDISK_LOG
|
|
|
|
|
int rdisk_do_log = ENABLE_RDISK_LOG;
|
2018-01-26 22:17:09 +01:00
|
|
|
|
|
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_log(void *priv, const char *fmt, ...)
|
2018-01-26 22:17:09 +01:00
|
|
|
{
|
2018-04-25 23:51:13 +02:00
|
|
|
va_list ap;
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
if (rdisk_do_log) {
|
2022-09-18 17:13:50 -04:00
|
|
|
va_start(ap, fmt);
|
2025-01-28 16:26:28 +01:00
|
|
|
log_out(priv, fmt, ap);
|
2022-09-18 17:13:50 -04:00
|
|
|
va_end(ap);
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
2018-10-19 00:39:32 +02:00
|
|
|
#else
|
2025-07-25 16:30:40 +02:00
|
|
|
# define rdisk_log(priv, fmt, ...)
|
2018-10-19 00:39:32 +02:00
|
|
|
#endif
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2018-10-30 13:32:25 +01:00
|
|
|
static int
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_load_abort(const rdisk_t *dev)
|
2018-10-30 13:32:25 +01:00
|
|
|
{
|
2023-08-21 20:22:55 -04:00
|
|
|
if (dev->drv->fp)
|
|
|
|
|
fclose(dev->drv->fp);
|
|
|
|
|
dev->drv->fp = NULL;
|
2018-10-30 13:32:25 +01:00
|
|
|
dev->drv->medium_size = 0;
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_eject(dev->id); /* Make sure the host OS knows we've rejected (and ejected) the image. */
|
2018-10-30 13:32:25 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
int
|
2025-01-28 16:26:28 +01:00
|
|
|
image_is_zdi(const char *s)
|
|
|
|
|
{
|
|
|
|
|
return !strcasecmp(path_get_extension((char *) s), "ZDI");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_is_empty(const uint8_t id)
|
2025-01-28 16:26:28 +01:00
|
|
|
{
|
2025-07-25 16:30:40 +02:00
|
|
|
const rdisk_t *dev = (const rdisk_t *) rdisk_drives[id].priv;
|
2025-01-28 16:26:28 +01:00
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
|
|
if ((dev->drv == NULL) || (dev->drv->fp == NULL))
|
|
|
|
|
ret = 1;
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_load(const rdisk_t *dev, const char *fn, const int skip_insert)
|
2018-04-25 23:51:13 +02:00
|
|
|
{
|
2025-07-25 16:30:40 +02:00
|
|
|
const int was_empty = rdisk_is_empty(dev->id);
|
2025-01-28 16:26:28 +01:00
|
|
|
int ret = 0;
|
2025-07-23 15:53:34 +02:00
|
|
|
int offs = 0;
|
|
|
|
|
|
|
|
|
|
if (strstr(fn, "wp://") == fn) {
|
|
|
|
|
offs = 5;
|
|
|
|
|
dev->drv->read_only = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn += offs;
|
2018-04-25 23:51:13 +02:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
if (dev->drv == NULL)
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_eject(dev->id);
|
2025-01-28 16:26:28 +01:00
|
|
|
else {
|
|
|
|
|
const int is_zdi = image_is_zdi(fn);
|
2023-11-25 22:54:07 -03:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
dev->drv->fp = plat_fopen(fn, dev->drv->read_only ? "rb" : "rb+");
|
|
|
|
|
ret = 1;
|
2018-04-25 23:51:13 +02:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
if (dev->drv->fp == NULL) {
|
|
|
|
|
if (!dev->drv->read_only) {
|
|
|
|
|
dev->drv->fp = plat_fopen(fn, "rb");
|
|
|
|
|
if (dev->drv->fp == NULL)
|
2025-07-25 16:30:40 +02:00
|
|
|
ret = rdisk_load_abort(dev);
|
2025-01-28 16:26:28 +01:00
|
|
|
else
|
|
|
|
|
dev->drv->read_only = 1;
|
|
|
|
|
} else
|
2025-07-25 16:30:40 +02:00
|
|
|
ret = rdisk_load_abort(dev);
|
2025-01-28 16:26:28 +01:00
|
|
|
}
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
if (ret) {
|
|
|
|
|
fseek(dev->drv->fp, 0, SEEK_END);
|
|
|
|
|
int size = ftell(dev->drv->fp);
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
if (is_zdi) {
|
|
|
|
|
/* This is a ZDI image. */
|
|
|
|
|
size -= 0x1000;
|
|
|
|
|
dev->drv->base = 0x1000;
|
|
|
|
|
} else
|
|
|
|
|
dev->drv->base = 0;
|
|
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
if (dev->drv->type != RDISK_TYPE_ZIP_100) {
|
2025-01-28 16:26:28 +01:00
|
|
|
if ((size != (ZIP_250_SECTORS << 9)) && (size != (ZIP_SECTORS << 9))) {
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_log(dev->log, "File is incorrect size for a RDISK image\n");
|
|
|
|
|
rdisk_log(dev->log, "Must be exactly %i or %i bytes\n",
|
2025-01-28 16:26:28 +01:00
|
|
|
ZIP_250_SECTORS << 9, ZIP_SECTORS << 9);
|
2025-07-25 16:30:40 +02:00
|
|
|
ret = rdisk_load_abort(dev);
|
2025-01-28 16:26:28 +01:00
|
|
|
}
|
|
|
|
|
} else if (size != (ZIP_SECTORS << 9)) {
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_log(dev->log, "File is incorrect size for a RDISK image\n");
|
|
|
|
|
rdisk_log(dev->log, "Must be exactly %i bytes\n", ZIP_SECTORS << 9);
|
|
|
|
|
ret = rdisk_load_abort(dev);
|
2025-01-28 16:26:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ret)
|
|
|
|
|
dev->drv->medium_size = size >> 9;
|
2022-09-18 17:13:50 -04:00
|
|
|
}
|
2025-01-28 16:26:28 +01:00
|
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
|
if (fseek(dev->drv->fp, dev->drv->base, SEEK_SET) == -1)
|
2025-07-25 16:30:40 +02:00
|
|
|
log_fatal(dev->log, "rdisk_load(): Error seeking to the beginning of "
|
2025-01-28 16:26:28 +01:00
|
|
|
"the file\n");
|
|
|
|
|
|
2025-07-23 15:53:34 +02:00
|
|
|
strncpy(dev->drv->image_path, fn - offs, sizeof(dev->drv->image_path) - 1);
|
2025-01-28 16:26:28 +01:00
|
|
|
/*
|
|
|
|
|
After using strncpy, dev->drv->image_path needs to be explicitly null
|
|
|
|
|
terminated to make gcc happy.
|
|
|
|
|
In the event strlen(dev->drv->image_path) == sizeof(dev->drv->image_path)
|
|
|
|
|
(no null terminator) it is placed at the very end. Otherwise, it is placed
|
|
|
|
|
right after the string.
|
|
|
|
|
*/
|
|
|
|
|
const size_t term = strlen(dev->drv->image_path) ==
|
|
|
|
|
sizeof(dev->drv->image_path) ? sizeof(dev->drv->image_path) - 1 :
|
|
|
|
|
strlen(dev->drv->image_path);
|
|
|
|
|
dev->drv->image_path[term] = '\0';
|
2022-09-18 17:13:50 -04:00
|
|
|
}
|
2018-10-30 13:32:25 +01:00
|
|
|
}
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
if (ret && !skip_insert) {
|
|
|
|
|
/* Signal media change to the emulated machine. */
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_insert((rdisk_t *) dev);
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
/* The drive was previously empty, transition directly to UNIT ATTENTION. */
|
|
|
|
|
if (was_empty)
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_insert((rdisk_t *) dev);
|
2025-01-28 16:26:28 +01:00
|
|
|
}
|
2025-07-23 15:53:34 +02:00
|
|
|
|
|
|
|
|
if (ret)
|
2025-07-25 16:30:40 +02:00
|
|
|
ui_sb_update_icon_wp(SB_RDISK | dev->id, dev->drv->read_only);
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_disk_reload(const rdisk_t *dev)
|
2018-01-26 22:17:09 +01:00
|
|
|
{
|
2025-01-28 16:26:28 +01:00
|
|
|
if (strlen(dev->drv->prev_image_path) != 0)
|
2025-07-25 16:30:40 +02:00
|
|
|
(void) rdisk_load(dev, dev->drv->prev_image_path, 0);
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_disk_unload(const rdisk_t *dev)
|
2018-01-26 22:17:09 +01:00
|
|
|
{
|
2025-01-28 16:26:28 +01:00
|
|
|
if ((dev->drv != NULL) && (dev->drv->fp != NULL)) {
|
2023-08-21 20:22:55 -04:00
|
|
|
fclose(dev->drv->fp);
|
|
|
|
|
dev->drv->fp = NULL;
|
2018-10-27 22:19:39 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_disk_close(const rdisk_t *dev)
|
2018-10-27 22:19:39 +02:00
|
|
|
{
|
2025-01-28 16:26:28 +01:00
|
|
|
if ((dev->drv != NULL) && (dev->drv->fp != NULL)) {
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_disk_unload(dev);
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
memcpy(dev->drv->prev_image_path, dev->drv->image_path,
|
|
|
|
|
sizeof(dev->drv->prev_image_path));
|
2022-09-18 17:13:50 -04:00
|
|
|
memset(dev->drv->image_path, 0, sizeof(dev->drv->image_path));
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
dev->drv->medium_size = 0;
|
2025-01-28 16:26:28 +01:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_insert((rdisk_t *) dev);
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_set_callback(const rdisk_t *dev)
|
2018-01-26 22:17:09 +01:00
|
|
|
{
|
2025-07-25 16:30:40 +02:00
|
|
|
if (dev->drv->bus_type != RDISK_BUS_SCSI)
|
2022-09-18 17:13:50 -04:00
|
|
|
ide_set_callback(ide_drives[dev->drv->ide_channel], dev->callback);
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_init(rdisk_t *dev)
|
2018-01-26 22:17:09 +01:00
|
|
|
{
|
2025-07-25 16:30:40 +02:00
|
|
|
if (dev->id < RDISK_NUM) {
|
2025-01-28 16:26:28 +01:00
|
|
|
dev->requested_blocks = 1;
|
|
|
|
|
dev->sense[0] = 0xf0;
|
|
|
|
|
dev->sense[7] = 10;
|
|
|
|
|
dev->drv->bus_mode = 0;
|
2025-07-25 16:30:40 +02:00
|
|
|
if (dev->drv->bus_type >= RDISK_BUS_ATAPI)
|
2025-01-28 16:26:28 +01:00
|
|
|
dev->drv->bus_mode |= 2;
|
2025-07-25 16:30:40 +02:00
|
|
|
if (dev->drv->bus_type < RDISK_BUS_SCSI)
|
2025-01-28 16:26:28 +01:00
|
|
|
dev->drv->bus_mode |= 1;
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_log(dev->log, "Bus type %i, bus mode %i\n", dev->drv->bus_type, dev->drv->bus_mode);
|
|
|
|
|
if (dev->drv->bus_type < RDISK_BUS_SCSI) {
|
2025-01-28 16:26:28 +01:00
|
|
|
dev->tf->phase = 1;
|
|
|
|
|
dev->tf->request_length = 0xEB14;
|
|
|
|
|
}
|
|
|
|
|
dev->tf->status = READY_STAT | DSC_STAT;
|
|
|
|
|
dev->tf->pos = 0;
|
|
|
|
|
dev->packet_status = PHASE_NONE;
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_sense_key = rdisk_asc = rdisk_ascq = dev->unit_attention = dev->transition = 0;
|
|
|
|
|
rdisk_info = 0x00000000;
|
2018-10-30 13:32:25 +01:00
|
|
|
}
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static int
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_supports_pio(const rdisk_t *dev)
|
2018-01-26 22:17:09 +01:00
|
|
|
{
|
2018-07-15 01:41:53 +02:00
|
|
|
return (dev->drv->bus_mode & 1);
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static int
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_supports_dma(const rdisk_t *dev)
|
2018-01-26 22:17:09 +01:00
|
|
|
{
|
2018-07-15 01:41:53 +02:00
|
|
|
return (dev->drv->bus_mode & 2);
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Returns: 0 for none, 1 for PIO, 2 for DMA. */
|
2018-04-25 23:51:13 +02:00
|
|
|
static int
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_current_mode(const rdisk_t *dev)
|
2018-01-26 22:17:09 +01:00
|
|
|
{
|
2025-07-25 16:30:40 +02:00
|
|
|
if (!rdisk_supports_pio(dev) && !rdisk_supports_dma(dev))
|
2022-09-18 17:13:50 -04:00
|
|
|
return 0;
|
2025-07-25 16:30:40 +02:00
|
|
|
if (rdisk_supports_pio(dev) && !rdisk_supports_dma(dev)) {
|
|
|
|
|
rdisk_log(dev->log, "Drive does not support DMA, setting to PIO\n");
|
2022-09-18 17:13:50 -04:00
|
|
|
return 1;
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
2025-07-25 16:30:40 +02:00
|
|
|
if (!rdisk_supports_pio(dev) && rdisk_supports_dma(dev))
|
2022-09-18 17:13:50 -04:00
|
|
|
return 2;
|
2025-07-25 16:30:40 +02:00
|
|
|
if (rdisk_supports_pio(dev) && rdisk_supports_dma(dev)) {
|
|
|
|
|
rdisk_log(dev->log, "Drive supports both, setting to %s\n",
|
2023-10-28 22:00:23 +02:00
|
|
|
(dev->tf->features & 1) ? "DMA" : "PIO");
|
|
|
|
|
return (dev->tf->features & 1) ? 2 : 1;
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
return 0;
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_mode_sense_load(rdisk_t *dev)
|
2018-01-26 22:17:09 +01:00
|
|
|
{
|
2025-01-28 16:26:28 +01:00
|
|
|
char fn[512] = { 0 };
|
2018-04-25 23:51:13 +02:00
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
memset(&dev->ms_pages_saved, 0, sizeof(mode_sense_pages_t));
|
2025-07-25 16:30:40 +02:00
|
|
|
|
|
|
|
|
if (dev->drv->type == RDISK_TYPE_ZIP_100) {
|
|
|
|
|
if (rdisk_drives[dev->id].bus_type == RDISK_BUS_SCSI)
|
2022-09-18 17:13:50 -04:00
|
|
|
memcpy(&dev->ms_pages_saved, &zip_mode_sense_pages_default_scsi, sizeof(mode_sense_pages_t));
|
|
|
|
|
else
|
|
|
|
|
memcpy(&dev->ms_pages_saved, &zip_mode_sense_pages_default, sizeof(mode_sense_pages_t));
|
2025-07-25 16:30:40 +02:00
|
|
|
} else {
|
|
|
|
|
if (rdisk_drives[dev->id].bus_type == RDISK_BUS_SCSI)
|
|
|
|
|
memcpy(&dev->ms_pages_saved, &zip_250_mode_sense_pages_default_scsi, sizeof(mode_sense_pages_t));
|
|
|
|
|
else
|
|
|
|
|
memcpy(&dev->ms_pages_saved, &zip_250_mode_sense_pages_default, sizeof(mode_sense_pages_t));
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
2018-10-27 22:19:39 +02:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
if (dev->drv->bus_type == RDISK_BUS_SCSI)
|
|
|
|
|
sprintf(fn, "scsi_rdisk_%02i_mode_sense_bin", dev->id);
|
2018-04-25 23:51:13 +02:00
|
|
|
else
|
2025-07-25 16:30:40 +02:00
|
|
|
sprintf(fn, "rdisk_%02i_mode_sense_bin", dev->id);
|
2025-01-28 16:26:28 +01:00
|
|
|
FILE *fp = plat_fopen(nvr_path(fn), "rb");
|
2023-08-21 20:22:55 -04:00
|
|
|
if (fp) {
|
2025-07-25 16:30:40 +02:00
|
|
|
/* Nothing to read, not used by RDISK. */
|
2023-08-21 20:22:55 -04:00
|
|
|
fclose(fp);
|
2018-10-27 03:43:25 +02:00
|
|
|
}
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_mode_sense_save(const rdisk_t *dev)
|
2018-01-26 22:17:09 +01:00
|
|
|
{
|
2025-01-28 16:26:28 +01:00
|
|
|
char fn[512] = { 0 };
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
if (dev->drv->bus_type == RDISK_BUS_SCSI)
|
|
|
|
|
sprintf(fn, "scsi_rdisk_%02i_mode_sense_bin", dev->id);
|
2018-04-25 23:51:13 +02:00
|
|
|
else
|
2025-07-25 16:30:40 +02:00
|
|
|
sprintf(fn, "rdisk_%02i_mode_sense_bin", dev->id);
|
2025-01-28 16:26:28 +01:00
|
|
|
FILE *fp = plat_fopen(nvr_path(fn), "wb");
|
2023-08-21 20:22:55 -04:00
|
|
|
if (fp) {
|
2025-07-25 16:30:40 +02:00
|
|
|
/* Nothing to write, not used by RDISK. */
|
2023-08-21 20:22:55 -04:00
|
|
|
fclose(fp);
|
2018-10-27 03:43:25 +02:00
|
|
|
}
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
/* SCSI Mode Sense 6/10. */
|
2018-04-25 23:51:13 +02:00
|
|
|
static uint8_t
|
2025-07-25 16:30:40 +02:00
|
|
|
zip_mode_sense_read(const rdisk_t *dev, const uint8_t pgctl,
|
2025-01-28 16:26:28 +01:00
|
|
|
const uint8_t page, const uint8_t pos)
|
2018-04-25 23:51:13 +02:00
|
|
|
{
|
2025-01-28 16:26:28 +01:00
|
|
|
switch (pgctl) {
|
2022-09-18 17:13:50 -04:00
|
|
|
case 0:
|
|
|
|
|
case 3:
|
2025-07-25 16:30:40 +02:00
|
|
|
if ((dev->drv->type != RDISK_TYPE_ZIP_100) && (page == 5) && (pos == 9) &&
|
2025-01-28 16:26:28 +01:00
|
|
|
(dev->drv->medium_size == ZIP_SECTORS))
|
2022-09-18 17:13:50 -04:00
|
|
|
return 0x60;
|
|
|
|
|
return dev->ms_pages_saved.pages[page][pos];
|
|
|
|
|
case 1:
|
2025-07-25 16:30:40 +02:00
|
|
|
if (dev->drv->type == RDISK_TYPE_ZIP_100)
|
2022-09-18 17:13:50 -04:00
|
|
|
return zip_mode_sense_pages_changeable.pages[page][pos];
|
2025-07-25 16:30:40 +02:00
|
|
|
else
|
|
|
|
|
return zip_250_mode_sense_pages_changeable.pages[page][pos];
|
2022-09-18 17:13:50 -04:00
|
|
|
case 2:
|
2025-07-25 16:30:40 +02:00
|
|
|
if (dev->drv->type == RDISK_TYPE_ZIP_100) {
|
|
|
|
|
if (dev->drv->bus_type == RDISK_BUS_SCSI)
|
|
|
|
|
return zip_mode_sense_pages_default_scsi.pages[page][pos];
|
|
|
|
|
else
|
|
|
|
|
return zip_mode_sense_pages_default.pages[page][pos];
|
|
|
|
|
} else {
|
2022-09-18 17:13:50 -04:00
|
|
|
if ((page == 5) && (pos == 9) && (dev->drv->medium_size == ZIP_SECTORS))
|
|
|
|
|
return 0x60;
|
2025-07-25 16:30:40 +02:00
|
|
|
if (dev->drv->bus_type == RDISK_BUS_SCSI)
|
2022-09-18 17:13:50 -04:00
|
|
|
return zip_250_mode_sense_pages_default_scsi.pages[page][pos];
|
|
|
|
|
else
|
|
|
|
|
return zip_250_mode_sense_pages_default.pages[page][pos];
|
|
|
|
|
}
|
2023-06-28 13:46:28 -04:00
|
|
|
|
|
|
|
|
default:
|
2022-09-18 17:13:50 -04:00
|
|
|
break;
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
return 0;
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static uint32_t
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_mode_sense(const rdisk_t *dev, uint8_t *buf, uint32_t pos,
|
2025-01-28 16:26:28 +01:00
|
|
|
uint8_t page, const uint8_t block_descriptor_len)
|
2018-01-26 22:17:09 +01:00
|
|
|
{
|
2025-01-28 16:26:28 +01:00
|
|
|
uint64_t pf;
|
|
|
|
|
const uint8_t pgctl = (page >> 6) & 3;
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
if (dev->drv->type == RDISK_TYPE_ZIP_100)
|
2022-09-18 17:13:50 -04:00
|
|
|
pf = zip_mode_sense_page_flags;
|
2025-07-25 16:30:40 +02:00
|
|
|
else
|
|
|
|
|
pf = zip_250_mode_sense_page_flags;
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2018-10-10 22:33:24 +02:00
|
|
|
page &= 0x3f;
|
2018-04-25 23:51:13 +02:00
|
|
|
|
|
|
|
|
if (block_descriptor_len) {
|
2022-09-18 17:13:50 -04:00
|
|
|
buf[pos++] = ((dev->drv->medium_size >> 24) & 0xff);
|
|
|
|
|
buf[pos++] = ((dev->drv->medium_size >> 16) & 0xff);
|
|
|
|
|
buf[pos++] = ((dev->drv->medium_size >> 8) & 0xff);
|
|
|
|
|
buf[pos++] = (dev->drv->medium_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
|
|
|
}
|
|
|
|
|
|
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:13:50 -04:00
|
|
|
if (pf & (1LL << ((uint64_t) page))) {
|
2025-01-28 16:26:28 +01:00
|
|
|
const uint8_t msplen = zip_mode_sense_read(dev, pgctl, i, 1);
|
|
|
|
|
buf[pos++] = zip_mode_sense_read(dev, pgctl, i, 0);
|
|
|
|
|
buf[pos++] = msplen;
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_log(dev->log, "MODE SENSE: Page [%02X] length %i\n", i, msplen);
|
2023-05-29 01:30:51 -04:00
|
|
|
for (uint8_t j = 0; j < msplen; j++)
|
2025-01-28 16:26:28 +01:00
|
|
|
buf[pos++] = zip_mode_sense_read(dev, pgctl, i, 2 + j);
|
2022-09-18 17:13:50 -04:00
|
|
|
}
|
|
|
|
|
}
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return pos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_update_request_length(rdisk_t *dev, int len, int block_len)
|
2018-04-25 23:51:13 +02:00
|
|
|
{
|
2023-05-29 01:30:51 -04:00
|
|
|
int bt;
|
|
|
|
|
int min_len = 0;
|
2018-04-25 23:51:13 +02:00
|
|
|
|
2023-10-28 22:00:23 +02:00
|
|
|
dev->max_transfer_len = dev->tf->request_length;
|
2018-04-25 23:51:13 +02:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
/*
|
|
|
|
|
For media access commands, make sure the requested DRQ length matches the
|
|
|
|
|
block length.
|
|
|
|
|
*/
|
2018-04-25 23:51:13 +02:00
|
|
|
switch (dev->current_cdb[0]) {
|
2022-09-18 17:13:50 -04:00
|
|
|
case 0x08:
|
|
|
|
|
case 0x0a:
|
|
|
|
|
case 0x28:
|
|
|
|
|
case 0x2a:
|
|
|
|
|
case 0xa8:
|
|
|
|
|
case 0xaa:
|
|
|
|
|
/* Round it to the nearest 2048 bytes. */
|
|
|
|
|
dev->max_transfer_len = (dev->max_transfer_len >> 9) << 9;
|
|
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
/*
|
|
|
|
|
Make sure total length is not bigger than sum of the lengths of
|
|
|
|
|
all the requested blocks.
|
|
|
|
|
*/
|
2022-09-18 17:13:50 -04:00
|
|
|
bt = (dev->requested_blocks * block_len);
|
|
|
|
|
if (len > bt)
|
|
|
|
|
len = bt;
|
|
|
|
|
|
|
|
|
|
min_len = block_len;
|
|
|
|
|
|
|
|
|
|
if (len <= block_len) {
|
|
|
|
|
/* Total length is less or equal to block length. */
|
|
|
|
|
if (dev->max_transfer_len < block_len) {
|
|
|
|
|
/* Transfer a minimum of (block size) bytes. */
|
|
|
|
|
dev->max_transfer_len = block_len;
|
|
|
|
|
dev->packet_len = block_len;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-08-09 19:44:56 -04:00
|
|
|
fallthrough;
|
2023-06-09 23:46:54 -04:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
default:
|
|
|
|
|
dev->packet_len = len;
|
|
|
|
|
break;
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
2025-01-28 16:26:28 +01:00
|
|
|
/*
|
|
|
|
|
If the DRQ length is odd, and the total remaining length is bigger,
|
|
|
|
|
make sure it's even.
|
|
|
|
|
*/
|
2018-04-25 23:51:13 +02:00
|
|
|
if ((dev->max_transfer_len & 1) && (dev->max_transfer_len < len))
|
2022-09-18 17:13:50 -04:00
|
|
|
dev->max_transfer_len &= 0xfffe;
|
2025-01-28 16:26:28 +01:00
|
|
|
/*
|
|
|
|
|
If the DRQ length is smaller or equal in size to the total remaining length,
|
|
|
|
|
set it to that.
|
|
|
|
|
*/
|
2018-04-25 23:51:13 +02:00
|
|
|
if (!dev->max_transfer_len)
|
2022-09-18 17:13:50 -04:00
|
|
|
dev->max_transfer_len = 65534;
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
if ((len <= dev->max_transfer_len) && (len >= min_len))
|
2023-10-28 22:00:23 +02:00
|
|
|
dev->tf->request_length = dev->max_transfer_len = len;
|
2018-07-15 01:41:53 +02:00
|
|
|
else if (len > dev->max_transfer_len)
|
2023-10-28 22:00:23 +02:00
|
|
|
dev->tf->request_length = dev->max_transfer_len;
|
2018-04-25 23:51:13 +02:00
|
|
|
|
|
|
|
|
return;
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
2019-11-19 04:35:54 +01:00
|
|
|
static double
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_bus_speed(rdisk_t *dev)
|
2019-11-19 04:35:54 +01:00
|
|
|
{
|
|
|
|
|
double ret = -1.0;
|
|
|
|
|
|
2025-03-21 03:29:46 +01:00
|
|
|
if (dev && dev->drv)
|
|
|
|
|
ret = ide_atapi_get_period(dev->drv->ide_channel);
|
|
|
|
|
|
|
|
|
|
if (ret == -1.0) {
|
|
|
|
|
if (dev)
|
|
|
|
|
dev->callback = -1.0;
|
|
|
|
|
ret = 0.0;
|
2019-11-19 04:35:54 +01:00
|
|
|
}
|
2025-03-21 03:29:46 +01:00
|
|
|
|
|
|
|
|
return ret;
|
2019-11-19 04:35:54 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_command_common(rdisk_t *dev)
|
2018-01-26 22:17:09 +01:00
|
|
|
{
|
2023-10-28 22:00:23 +02:00
|
|
|
dev->tf->status = BUSY_STAT;
|
|
|
|
|
dev->tf->phase = 1;
|
|
|
|
|
dev->tf->pos = 0;
|
2018-10-31 12:23:49 +01:00
|
|
|
if (dev->packet_status == PHASE_COMPLETE)
|
2022-09-18 17:13:50 -04:00
|
|
|
dev->callback = 0.0;
|
2025-07-25 16:30:40 +02:00
|
|
|
else if (dev->drv->bus_type == RDISK_BUS_SCSI)
|
2025-03-21 03:29:46 +01:00
|
|
|
dev->callback = -1.0; /* Speed depends on SCSI controller */
|
|
|
|
|
else
|
2025-07-25 16:30:40 +02:00
|
|
|
dev->callback = rdisk_bus_speed(dev) * (double) (dev->packet_len);
|
2018-04-25 23:51:13 +02:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_set_callback(dev);
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_command_complete(rdisk_t *dev)
|
2018-01-26 22:17:09 +01:00
|
|
|
{
|
2018-10-10 22:33:24 +02:00
|
|
|
dev->packet_status = PHASE_COMPLETE;
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_command_common(dev);
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_command_read(rdisk_t *dev)
|
2018-01-26 22:17:09 +01:00
|
|
|
{
|
2018-10-10 22:33:24 +02:00
|
|
|
dev->packet_status = PHASE_DATA_IN;
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_command_common(dev);
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_command_read_dma(rdisk_t *dev)
|
2018-01-26 22:17:09 +01:00
|
|
|
{
|
2018-10-10 22:33:24 +02:00
|
|
|
dev->packet_status = PHASE_DATA_IN_DMA;
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_command_common(dev);
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_command_write(rdisk_t *dev)
|
2018-01-26 22:17:09 +01:00
|
|
|
{
|
2018-10-10 22:33:24 +02:00
|
|
|
dev->packet_status = PHASE_DATA_OUT;
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_command_common(dev);
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_command_write_dma(rdisk_t *dev)
|
2018-01-26 22:17:09 +01:00
|
|
|
{
|
2018-10-10 22:33:24 +02:00
|
|
|
dev->packet_status = PHASE_DATA_OUT_DMA;
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_command_common(dev);
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
/*
|
2025-07-25 16:30:40 +02:00
|
|
|
dev = Pointer to current RDISK device;
|
2018-01-26 22:17:09 +01:00
|
|
|
len = Total transfer length;
|
|
|
|
|
block_len = Length of a single block (why does it matter?!);
|
|
|
|
|
alloc_len = Allocated transfer length;
|
2025-01-28 16:26:28 +01:00
|
|
|
direction = Transfer direction (0 = read from host, 1 = write to host).
|
|
|
|
|
*/
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_data_command_finish(rdisk_t *dev, int len, const int block_len,
|
2025-01-28 16:26:28 +01:00
|
|
|
const int alloc_len, const int direction)
|
2018-01-26 22:17:09 +01:00
|
|
|
{
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_log(dev->log, "Finishing command (%02X): %i, %i, %i, %i, %i\n",
|
2025-01-28 16:26:28 +01:00
|
|
|
dev->current_cdb[0], len, block_len, alloc_len,
|
|
|
|
|
direction, dev->tf->request_length);
|
2023-10-28 22:00:23 +02:00
|
|
|
dev->tf->pos = 0;
|
2018-04-25 23:51:13 +02:00
|
|
|
if (alloc_len >= 0) {
|
2022-09-18 17:13:50 -04:00
|
|
|
if (alloc_len < len)
|
|
|
|
|
len = alloc_len;
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
2025-07-25 16:30:40 +02:00
|
|
|
if ((len == 0) || (rdisk_current_mode(dev) == 0)) {
|
|
|
|
|
if (dev->drv->bus_type != RDISK_BUS_SCSI)
|
2022-09-18 17:13:50 -04:00
|
|
|
dev->packet_len = 0;
|
2018-04-25 23:51:13 +02:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_command_complete(dev);
|
2018-04-25 23:51:13 +02:00
|
|
|
} else {
|
2025-07-25 16:30:40 +02:00
|
|
|
if (rdisk_current_mode(dev) == 2) {
|
|
|
|
|
if (dev->drv->bus_type != RDISK_BUS_SCSI)
|
2022-09-18 17:13:50 -04:00
|
|
|
dev->packet_len = alloc_len;
|
|
|
|
|
|
|
|
|
|
if (direction == 0)
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_command_read_dma(dev);
|
2022-09-18 17:13:50 -04:00
|
|
|
else
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_command_write_dma(dev);
|
2022-09-18 17:13:50 -04:00
|
|
|
} else {
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_update_request_length(dev, len, block_len);
|
|
|
|
|
if ((dev->drv->bus_type != RDISK_BUS_SCSI) &&
|
2025-04-07 01:44:12 +02:00
|
|
|
(dev->tf->request_length == 0))
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_command_complete(dev);
|
2025-04-07 01:44:12 +02:00
|
|
|
else if (direction == 0)
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_command_read(dev);
|
2022-09-18 17:13:50 -04:00
|
|
|
else
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_command_write(dev);
|
2022-09-18 17:13:50 -04:00
|
|
|
}
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
|
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_log(dev->log, "Status: %i, cylinder %i, packet length: %i, position: %i, phase: %i\n",
|
2025-01-28 16:26:28 +01:00
|
|
|
dev->packet_status, dev->tf->request_length, dev->packet_len,
|
|
|
|
|
dev->tf->pos, dev->tf->phase);
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_sense_clear(rdisk_t *dev, UNUSED(int command))
|
2018-01-26 22:17:09 +01:00
|
|
|
{
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_sense_key = rdisk_asc = rdisk_ascq = 0;
|
|
|
|
|
rdisk_info = 0x00000000;
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_set_phase(const rdisk_t *dev, const uint8_t phase)
|
2018-01-26 22:17:09 +01:00
|
|
|
{
|
2025-01-28 16:26:28 +01:00
|
|
|
const uint8_t scsi_bus = (dev->drv->scsi_device_id >> 4) & 0x0f;
|
|
|
|
|
const uint8_t scsi_id = dev->drv->scsi_device_id & 0x0f;
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
if (dev->drv->bus_type == RDISK_BUS_SCSI)
|
2025-01-28 16:26:28 +01:00
|
|
|
scsi_devices[scsi_bus][scsi_id].phase = phase;
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_cmd_error(rdisk_t *dev)
|
2018-01-26 22:17:09 +01:00
|
|
|
{
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_set_phase(dev, SCSI_PHASE_STATUS);
|
|
|
|
|
dev->tf->error = ((rdisk_sense_key & 0xf) << 4) | ABRT_ERR;
|
2023-10-28 22:00:23 +02:00
|
|
|
dev->tf->status = READY_STAT | ERR_STAT;
|
|
|
|
|
dev->tf->phase = 3;
|
|
|
|
|
dev->tf->pos = 0;
|
2018-10-31 12:23:49 +01:00
|
|
|
dev->packet_status = PHASE_ERROR;
|
2025-07-25 16:30:40 +02:00
|
|
|
dev->callback = 50.0 * RDISK_TIME;
|
|
|
|
|
rdisk_set_callback(dev);
|
|
|
|
|
ui_sb_update_icon(SB_RDISK | dev->id, 0);
|
|
|
|
|
ui_sb_update_icon_write(SB_RDISK | dev->id, 0);
|
|
|
|
|
rdisk_log(dev->log, "[%02X] ERROR: %02X/%02X/%02X\n", dev->current_cdb[0], rdisk_sense_key,
|
|
|
|
|
rdisk_asc, rdisk_ascq);
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_unit_attention(rdisk_t *dev)
|
2018-01-26 22:17:09 +01:00
|
|
|
{
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_set_phase(dev, SCSI_PHASE_STATUS);
|
2023-10-28 22:00:23 +02:00
|
|
|
dev->tf->error = (SENSE_UNIT_ATTENTION << 4) | ABRT_ERR;
|
|
|
|
|
dev->tf->status = READY_STAT | ERR_STAT;
|
|
|
|
|
dev->tf->phase = 3;
|
|
|
|
|
dev->tf->pos = 0;
|
2018-10-31 12:23:49 +01:00
|
|
|
dev->packet_status = PHASE_ERROR;
|
2025-07-25 16:30:40 +02:00
|
|
|
dev->callback = 50.0 * RDISK_TIME;
|
|
|
|
|
rdisk_set_callback(dev);
|
|
|
|
|
ui_sb_update_icon(SB_RDISK | dev->id, 0);
|
|
|
|
|
ui_sb_update_icon_write(SB_RDISK | dev->id, 0);
|
|
|
|
|
rdisk_log(dev->log, "UNIT ATTENTION\n", dev->id);
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_buf_alloc(rdisk_t *dev, const uint32_t len)
|
2018-10-31 12:23:49 +01:00
|
|
|
{
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_log(dev->log, "Allocated buffer length: %i\n", len);
|
2025-09-07 01:12:30 +02:00
|
|
|
|
|
|
|
|
if (dev->buffer == NULL) {
|
2022-09-18 17:13:50 -04:00
|
|
|
dev->buffer = (uint8_t *) malloc(len);
|
2025-09-07 01:12:30 +02:00
|
|
|
dev->buffer_sz = len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (len > dev->buffer_sz) {
|
|
|
|
|
uint8_t *buf = (uint8_t *) realloc(dev->buffer, len);
|
|
|
|
|
dev->buffer = buf;
|
|
|
|
|
dev->buffer_sz = len;
|
|
|
|
|
}
|
2018-10-31 12:23:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_buf_free(rdisk_t *dev)
|
2018-01-26 22:17:09 +01:00
|
|
|
{
|
2025-01-28 16:26:28 +01:00
|
|
|
if (dev->buffer != NULL) {
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_log(dev->log, "Removable Disk %i: Freeing buffer...\n");
|
2022-09-18 17:13:50 -04:00
|
|
|
free(dev->buffer);
|
|
|
|
|
dev->buffer = NULL;
|
2018-10-31 12:23:49 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_bus_master_error(scsi_common_t *sc)
|
2018-10-31 12:23:49 +01:00
|
|
|
{
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_t *dev = (rdisk_t *) sc;
|
2018-10-31 12:23:49 +01:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_buf_free(dev);
|
|
|
|
|
rdisk_sense_key = rdisk_asc = rdisk_ascq = 0;
|
|
|
|
|
rdisk_info = (dev->sector_pos >> 24) |
|
2025-01-28 16:26:28 +01:00
|
|
|
((dev->sector_pos >> 16) << 8) |
|
|
|
|
|
((dev->sector_pos >> 8) << 16) |
|
|
|
|
|
( dev->sector_pos << 24);
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_cmd_error(dev);
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_not_ready(rdisk_t *dev)
|
2018-01-26 22:17:09 +01:00
|
|
|
{
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_sense_key = SENSE_NOT_READY;
|
|
|
|
|
rdisk_asc = ASC_MEDIUM_NOT_PRESENT;
|
|
|
|
|
rdisk_ascq = 0;
|
|
|
|
|
rdisk_info = 0x00000000;
|
|
|
|
|
rdisk_cmd_error(dev);
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_write_protected(rdisk_t *dev)
|
2018-01-26 22:17:09 +01:00
|
|
|
{
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_sense_key = SENSE_UNIT_ATTENTION;
|
|
|
|
|
rdisk_asc = ASC_WRITE_PROTECTED;
|
|
|
|
|
rdisk_ascq = 0;
|
|
|
|
|
rdisk_info = (dev->sector_pos >> 24) |
|
2025-01-28 16:26:28 +01:00
|
|
|
((dev->sector_pos >> 16) << 8) |
|
|
|
|
|
((dev->sector_pos >> 8) << 16) |
|
|
|
|
|
( dev->sector_pos << 24);
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_cmd_error(dev);
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
2024-10-29 13:57:21 -03:00
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_write_error(rdisk_t *dev)
|
2024-10-29 13:57:21 -03:00
|
|
|
{
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_sense_key = SENSE_MEDIUM_ERROR;
|
|
|
|
|
rdisk_asc = ASC_WRITE_ERROR;
|
|
|
|
|
rdisk_ascq = 0;
|
|
|
|
|
rdisk_info = (dev->sector_pos >> 24) |
|
2025-01-28 16:26:28 +01:00
|
|
|
((dev->sector_pos >> 16) << 8) |
|
|
|
|
|
((dev->sector_pos >> 8) << 16) |
|
|
|
|
|
( dev->sector_pos << 24);
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_cmd_error(dev);
|
2024-10-29 13:57:21 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_read_error(rdisk_t *dev)
|
2024-10-29 13:57:21 -03:00
|
|
|
{
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_sense_key = SENSE_MEDIUM_ERROR;
|
|
|
|
|
rdisk_asc = ASC_UNRECOVERED_READ_ERROR;
|
|
|
|
|
rdisk_ascq = 0;
|
|
|
|
|
rdisk_info = (dev->sector_pos >> 24) |
|
2025-01-28 16:26:28 +01:00
|
|
|
((dev->sector_pos >> 16) << 8) |
|
|
|
|
|
((dev->sector_pos >> 8) << 16) |
|
|
|
|
|
( dev->sector_pos << 24);
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_cmd_error(dev);
|
2024-10-29 13:57:21 -03:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_invalid_lun(rdisk_t *dev, const uint8_t lun)
|
2018-01-26 22:17:09 +01:00
|
|
|
{
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_sense_key = SENSE_ILLEGAL_REQUEST;
|
|
|
|
|
rdisk_asc = ASC_INV_LUN;
|
|
|
|
|
rdisk_ascq = 0;
|
|
|
|
|
rdisk_info = lun << 24;
|
|
|
|
|
rdisk_cmd_error(dev);
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_illegal_opcode(rdisk_t *dev, const uint8_t opcode)
|
2018-01-26 22:17:09 +01:00
|
|
|
{
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_sense_key = SENSE_ILLEGAL_REQUEST;
|
|
|
|
|
rdisk_asc = ASC_ILLEGAL_OPCODE;
|
|
|
|
|
rdisk_ascq = 0;
|
|
|
|
|
rdisk_info = opcode << 24;
|
|
|
|
|
rdisk_cmd_error(dev);
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_lba_out_of_range(rdisk_t *dev)
|
2018-01-26 22:17:09 +01:00
|
|
|
{
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_sense_key = SENSE_ILLEGAL_REQUEST;
|
|
|
|
|
rdisk_asc = ASC_LBA_OUT_OF_RANGE;
|
|
|
|
|
rdisk_ascq = 0;
|
|
|
|
|
rdisk_info = (dev->sector_pos >> 24) |
|
2025-01-28 16:26:28 +01:00
|
|
|
((dev->sector_pos >> 16) << 8) |
|
|
|
|
|
((dev->sector_pos >> 8) << 16) |
|
|
|
|
|
( dev->sector_pos << 24);
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_cmd_error(dev);
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_invalid_field(rdisk_t *dev, const uint32_t field)
|
2018-01-26 22:17:09 +01:00
|
|
|
{
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_sense_key = SENSE_ILLEGAL_REQUEST;
|
|
|
|
|
rdisk_asc = ASC_INV_FIELD_IN_CMD_PACKET;
|
|
|
|
|
rdisk_ascq = 0;
|
|
|
|
|
rdisk_info = (field >> 24) |
|
2025-01-28 16:26:28 +01:00
|
|
|
((field >> 16) << 8) |
|
|
|
|
|
((field >> 8) << 16) |
|
|
|
|
|
( field << 24);
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_cmd_error(dev);
|
2023-10-28 22:00:23 +02:00
|
|
|
dev->tf->status = 0x53;
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_invalid_field_pl(rdisk_t *dev, const uint32_t field)
|
2018-04-25 23:51:13 +02:00
|
|
|
{
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_sense_key = SENSE_ILLEGAL_REQUEST;
|
|
|
|
|
rdisk_asc = ASC_INV_FIELD_IN_PARAMETER_LIST;
|
|
|
|
|
rdisk_ascq = 0;
|
|
|
|
|
rdisk_info = (field >> 24) |
|
2025-01-28 16:26:28 +01:00
|
|
|
((field >> 16) << 8) |
|
|
|
|
|
((field >> 8) << 16) |
|
|
|
|
|
( field << 24);
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_cmd_error(dev);
|
2023-10-28 22:00:23 +02:00
|
|
|
dev->tf->status = 0x53;
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_data_phase_error(rdisk_t *dev, const uint32_t info)
|
2018-04-25 23:51:13 +02:00
|
|
|
{
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_sense_key = SENSE_ILLEGAL_REQUEST;
|
|
|
|
|
rdisk_asc = ASC_DATA_PHASE_ERROR;
|
|
|
|
|
rdisk_ascq = 0;
|
|
|
|
|
rdisk_info = (info >> 24) |
|
2025-01-28 16:26:28 +01:00
|
|
|
((info >> 16) << 8) |
|
|
|
|
|
((info >> 8) << 16) |
|
|
|
|
|
( info << 24);
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_cmd_error(dev);
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_blocks(rdisk_t *dev, int32_t *len, const int out)
|
2018-04-25 23:51:13 +02:00
|
|
|
{
|
2025-01-28 16:26:28 +01:00
|
|
|
int ret = 1;
|
|
|
|
|
*len = 0;
|
2018-04-25 23:51:13 +02:00
|
|
|
|
2025-03-18 00:43:49 +01:00
|
|
|
if (dev->sector_len > 0) {
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_log(dev->log, "%sing %i blocks starting from %i...\n", out ? "Writ" : "Read",
|
2025-01-28 16:26:28 +01:00
|
|
|
dev->requested_blocks, dev->sector_pos);
|
2018-04-25 23:51:13 +02:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
if (dev->sector_pos >= dev->drv->medium_size) {
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_log(dev->log, "Trying to %s beyond the end of disk\n",
|
2025-01-28 16:26:28 +01:00
|
|
|
out ? "write" : "read");
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_lba_out_of_range(dev);
|
2025-03-18 00:43:49 +01:00
|
|
|
ret = 0;
|
2025-01-28 16:26:28 +01:00
|
|
|
} else {
|
|
|
|
|
*len = dev->requested_blocks << 9;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < dev->requested_blocks; i++) {
|
2025-03-18 00:43:49 +01:00
|
|
|
if (fseek(dev->drv->fp, dev->drv->base + (dev->sector_pos << 9),
|
|
|
|
|
SEEK_SET) == -1) {
|
2025-01-28 16:26:28 +01:00
|
|
|
if (out)
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_write_error(dev);
|
2025-01-28 16:26:28 +01:00
|
|
|
else
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_read_error(dev);
|
2025-01-28 16:26:28 +01:00
|
|
|
ret = -1;
|
|
|
|
|
} else {
|
|
|
|
|
if (feof(dev->drv->fp))
|
|
|
|
|
break;
|
2018-04-25 23:51:13 +02:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
if (out) {
|
|
|
|
|
if (fwrite(dev->buffer + (i << 9), 1,
|
|
|
|
|
512, dev->drv->fp) != 512) {
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_log(dev->log, "rdisk_blocks(): Error writing data\n");
|
|
|
|
|
rdisk_write_error(dev);
|
2025-01-28 16:26:28 +01:00
|
|
|
ret = -1;
|
|
|
|
|
} else
|
|
|
|
|
fflush(dev->drv->fp);
|
|
|
|
|
} else if (fread(dev->buffer + (i << 9), 1,
|
|
|
|
|
512, dev->drv->fp) != 512) {
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_log(dev->log, "rdisk_blocks(): Error reading data\n");
|
|
|
|
|
rdisk_read_error(dev);
|
2025-01-28 16:26:28 +01:00
|
|
|
ret = -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-09-18 17:13:50 -04:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
if (ret == -1)
|
|
|
|
|
break;
|
2022-09-18 17:13:50 -04:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
dev->sector_pos++;
|
2024-10-29 13:57:21 -03:00
|
|
|
}
|
2024-09-24 04:37:26 +02:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
if (ret == 1) {
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_log(dev->log, "%s %i bytes of blocks...\n", out ? "Written" :
|
2025-01-28 16:26:28 +01:00
|
|
|
"Read", *len);
|
|
|
|
|
|
|
|
|
|
dev->sector_len -= dev->requested_blocks;
|
2024-10-29 13:57:21 -03:00
|
|
|
}
|
2022-09-18 17:13:50 -04:00
|
|
|
}
|
2025-03-18 00:43:49 +01:00
|
|
|
} else {
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_command_complete(dev);
|
2025-03-18 00:43:49 +01:00
|
|
|
ret = 0;
|
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
|
|
|
}
|
2018-04-25 23:51:13 +02:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
return ret;
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_insert(rdisk_t *dev)
|
2018-01-26 22:17:09 +01:00
|
|
|
{
|
2025-01-28 16:26:28 +01:00
|
|
|
if ((dev != NULL) && (dev->drv != NULL)) {
|
|
|
|
|
if (dev->drv->fp == NULL) {
|
|
|
|
|
dev->unit_attention = 0;
|
|
|
|
|
dev->transition = 0;
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_log(dev->log, "Media removal\n");
|
2025-01-28 16:26:28 +01:00
|
|
|
} else if (dev->transition) {
|
|
|
|
|
dev->unit_attention = 1;
|
|
|
|
|
/* Turn off the medium changed status. */
|
|
|
|
|
dev->transition = 0;
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_log(dev->log, "Media insert\n");
|
2025-01-28 16:26:28 +01:00
|
|
|
} else {
|
|
|
|
|
dev->unit_attention = 0;
|
|
|
|
|
dev->transition = 1;
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_log(dev->log, "Media transition\n");
|
2025-01-28 16:26:28 +01:00
|
|
|
}
|
|
|
|
|
}
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static int
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_pre_execution_check(rdisk_t *dev, const uint8_t *cdb)
|
2018-04-25 23:51:13 +02:00
|
|
|
{
|
2025-01-28 16:26:28 +01:00
|
|
|
int ready;
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
if ((cdb[0] != GPCMD_REQUEST_SENSE) && (dev->cur_lun == SCSI_LUN_USE_CDB) &&
|
|
|
|
|
(cdb[1] & 0xe0)) {
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_log(dev->log, "Attempting to execute a unknown command targeted at SCSI LUN %i\n",
|
2023-10-28 22:00:23 +02:00
|
|
|
((dev->tf->request_length >> 5) & 7));
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_invalid_lun(dev, cdb[1] >> 5);
|
2022-09-28 04:01:19 +02:00
|
|
|
return 0;
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
if (!(rdisk_command_flags[cdb[0]] & IMPLEMENTED)) {
|
|
|
|
|
rdisk_log(dev->log, "Attempting to execute unknown command %02X over %s\n",
|
|
|
|
|
cdb[0], (dev->drv->bus_type == RDISK_BUS_SCSI) ?
|
2025-01-28 16:26:28 +01:00
|
|
|
"SCSI" : "ATAPI");
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_illegal_opcode(dev, cdb[0]);
|
2022-09-18 17:13:50 -04:00
|
|
|
return 0;
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
|
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
if ((dev->drv->bus_type < RDISK_BUS_SCSI) &&
|
|
|
|
|
(rdisk_command_flags[cdb[0]] & SCSI_ONLY)) {
|
|
|
|
|
rdisk_log(dev->log, "Attempting to execute SCSI-only command %02X "
|
2025-01-28 16:26:28 +01:00
|
|
|
"over ATAPI\n", cdb[0]);
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_illegal_opcode(dev, cdb[0]);
|
2022-09-18 17:13:50 -04:00
|
|
|
return 0;
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
if ((dev->drv->bus_type == RDISK_BUS_SCSI) &&
|
|
|
|
|
(rdisk_command_flags[cdb[0]] & ATAPI_ONLY)) {
|
|
|
|
|
rdisk_log(dev->log, "Attempting to execute ATAPI-only command %02X "
|
2025-01-28 16:26:28 +01:00
|
|
|
"over SCSI\n", cdb[0]);
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_illegal_opcode(dev, cdb[0]);
|
2022-09-18 17:13:50 -04:00
|
|
|
return 0;
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
if (dev->transition) {
|
|
|
|
|
if ((cdb[0] == GPCMD_TEST_UNIT_READY) || (cdb[0] == GPCMD_REQUEST_SENSE))
|
|
|
|
|
ready = 0;
|
|
|
|
|
else {
|
2025-07-25 16:30:40 +02:00
|
|
|
if (!(rdisk_command_flags[cdb[0]] & ALLOW_UA)) {
|
|
|
|
|
rdisk_log(dev->log, "(ext_medium_changed != 0): rdisk_insert()\n");
|
|
|
|
|
rdisk_insert((void *) dev);
|
2025-01-28 16:26:28 +01:00
|
|
|
}
|
2018-04-25 23:51:13 +02:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
ready = (dev->drv->fp != NULL);
|
|
|
|
|
}
|
|
|
|
|
} else
|
|
|
|
|
ready = (dev->drv->fp != NULL);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
If the drive is not ready, there is no reason to keep the
|
2018-04-25 23:51:13 +02:00
|
|
|
UNIT ATTENTION condition present, as we only use it to mark
|
2025-01-28 16:26:28 +01:00
|
|
|
disc changes.
|
|
|
|
|
*/
|
|
|
|
|
if (!ready && (dev->unit_attention > 0))
|
2022-09-18 17:13:50 -04:00
|
|
|
dev->unit_attention = 0;
|
2018-04-25 23:51:13 +02:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
/*
|
|
|
|
|
If the UNIT ATTENTION condition is set and the command does not allow
|
|
|
|
|
execution under it, error out and report the condition.
|
|
|
|
|
*/
|
2018-04-25 23:51:13 +02:00
|
|
|
if (dev->unit_attention == 1) {
|
2025-01-28 16:26:28 +01:00
|
|
|
/*
|
|
|
|
|
Only increment the unit attention phase if the command can
|
|
|
|
|
not pass through it.
|
|
|
|
|
*/
|
2025-07-25 16:30:40 +02:00
|
|
|
if (!(rdisk_command_flags[cdb[0]] & ALLOW_UA)) {
|
|
|
|
|
rdisk_log(dev->log, "Unit attention now 2\n");
|
2025-01-28 16:26:28 +01:00
|
|
|
dev->unit_attention++;
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_log(dev->log, "UNIT ATTENTION: Command %02X not allowed to pass through\n",
|
2025-01-28 16:26:28 +01:00
|
|
|
cdb[0]);
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_unit_attention(dev);
|
2022-09-18 17:13:50 -04:00
|
|
|
return 0;
|
|
|
|
|
}
|
2018-04-25 23:51:13 +02:00
|
|
|
} else if (dev->unit_attention == 2) {
|
2022-09-18 17:13:50 -04:00
|
|
|
if (cdb[0] != GPCMD_REQUEST_SENSE) {
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_log(dev->log, "Unit attention now 0\n");
|
2022-09-18 17:13:50 -04:00
|
|
|
dev->unit_attention = 0;
|
|
|
|
|
}
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
/*
|
|
|
|
|
Unless the command is REQUEST SENSE, clear the sense. This will *NOT* clear
|
|
|
|
|
the UNIT ATTENTION condition if it's set.
|
|
|
|
|
*/
|
2018-04-25 23:51:13 +02:00
|
|
|
if (cdb[0] != GPCMD_REQUEST_SENSE)
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_sense_clear(dev, cdb[0]);
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
if (!ready && (rdisk_command_flags[cdb[0]] & CHECK_READY)) {
|
|
|
|
|
rdisk_log(dev->log, "Not ready (%02X)\n", cdb[0]);
|
|
|
|
|
rdisk_not_ready(dev);
|
2022-09-18 17:13:50 -04:00
|
|
|
return 0;
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_log(dev->log, "Continuing with command %02X\n", cdb[0]);
|
2018-04-25 23:51:13 +02:00
|
|
|
return 1;
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_seek(rdisk_t *dev, const uint32_t pos)
|
2018-01-26 22:17:09 +01:00
|
|
|
{
|
2022-09-18 17:13:50 -04:00
|
|
|
dev->sector_pos = pos;
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_rezero(rdisk_t *dev)
|
2018-01-26 22:17:09 +01:00
|
|
|
{
|
2018-04-25 23:51:13 +02:00
|
|
|
dev->sector_pos = dev->sector_len = 0;
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_seek(dev, 0);
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_reset(scsi_common_t *sc)
|
2018-01-26 22:17:09 +01:00
|
|
|
{
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_t *dev = (rdisk_t *) sc;
|
2018-10-10 22:33:24 +02:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_rezero(dev);
|
2023-10-28 22:00:23 +02:00
|
|
|
dev->tf->status = 0;
|
|
|
|
|
dev->callback = 0.0;
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_set_callback(dev);
|
2023-10-28 22:00:23 +02:00
|
|
|
dev->tf->phase = 1;
|
|
|
|
|
dev->tf->request_length = 0xEB14;
|
|
|
|
|
dev->packet_status = PHASE_NONE;
|
|
|
|
|
dev->unit_attention = 0;
|
|
|
|
|
dev->cur_lun = SCSI_LUN_USE_CDB;
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_sense_key = rdisk_asc = rdisk_ascq = dev->unit_attention = dev->transition = 0;
|
|
|
|
|
rdisk_info = 0x00000000;
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_request_sense(rdisk_t *dev, uint8_t *buffer, const uint8_t alloc_length, const 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:13:50 -04:00
|
|
|
memset(buffer, 0, alloc_length);
|
|
|
|
|
if (!desc)
|
|
|
|
|
memcpy(buffer, dev->sense, alloc_length);
|
|
|
|
|
else {
|
2025-07-25 16:30:40 +02:00
|
|
|
buffer[1] = rdisk_sense_key;
|
|
|
|
|
buffer[2] = rdisk_asc;
|
|
|
|
|
buffer[3] = rdisk_ascq;
|
2022-09-18 17:13:50 -04:00
|
|
|
}
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
buffer[0] = desc ? 0x72 : 0xf0;
|
|
|
|
|
if (!desc)
|
|
|
|
|
buffer[7] = 10;
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
if (dev->unit_attention && (rdisk_sense_key == 0)) {
|
2022-09-18 17:13:50 -04:00
|
|
|
buffer[desc ? 1 : 2] = SENSE_UNIT_ATTENTION;
|
|
|
|
|
buffer[desc ? 2 : 12] = ASC_MEDIUM_MAY_HAVE_CHANGED;
|
|
|
|
|
buffer[desc ? 3 : 13] = 0;
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_log(dev->log, "Reporting sense: %02X %02X %02X\n", buffer[2],
|
2025-01-28 16:26:28 +01:00
|
|
|
buffer[12], buffer[13]);
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
if (buffer[desc ? 1 : 2] == SENSE_UNIT_ATTENTION) {
|
2022-09-18 17:13:50 -04:00
|
|
|
/* If the last remaining sense is unit attention, clear
|
|
|
|
|
that condition. */
|
|
|
|
|
dev->unit_attention = 0;
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
/* Clear the sense stuff as per the spec. */
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_sense_clear(dev, GPCMD_REQUEST_SENSE);
|
2025-01-28 16:26:28 +01:00
|
|
|
|
|
|
|
|
if (dev->transition) {
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_log(dev->log, "Removable Disk_TRANSITION: rdisk_insert()\n");
|
|
|
|
|
rdisk_insert((void *) dev);
|
2025-01-28 16:26:28 +01:00
|
|
|
}
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
2018-10-10 22:33:24 +02:00
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_request_sense_for_scsi(scsi_common_t *sc, uint8_t *buffer, const uint8_t alloc_length)
|
2018-01-26 22:17:09 +01:00
|
|
|
{
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_t *dev = (rdisk_t *) sc;
|
2025-01-28 16:26:28 +01:00
|
|
|
const int ready = (dev->drv->fp != NULL);
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
if (!ready && dev->unit_attention) {
|
2025-01-28 16:26:28 +01:00
|
|
|
/*
|
|
|
|
|
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.
|
|
|
|
|
*/
|
2022-09-18 17:13:50 -04:00
|
|
|
dev->unit_attention = 0;
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
/* Do *NOT* advance the unit attention phase. */
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_request_sense(dev, buffer, alloc_length, 0);
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_set_buf_len(const rdisk_t *dev, int32_t *BufLen, int32_t *src_len)
|
2018-01-26 22:17:09 +01:00
|
|
|
{
|
2025-07-25 16:30:40 +02:00
|
|
|
if (dev->drv->bus_type == RDISK_BUS_SCSI) {
|
2022-09-18 17:13:50 -04:00
|
|
|
if (*BufLen == -1)
|
|
|
|
|
*BufLen = *src_len;
|
|
|
|
|
else {
|
|
|
|
|
*BufLen = MIN(*src_len, *BufLen);
|
|
|
|
|
*src_len = *BufLen;
|
|
|
|
|
}
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_log(dev->log, "Actual transfer length: %i\n", *BufLen);
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
2018-10-10 22:33:24 +02:00
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_command(scsi_common_t *sc, const uint8_t *cdb)
|
|
|
|
|
{
|
|
|
|
|
rdisk_t *dev = (rdisk_t *) sc;
|
|
|
|
|
char device_identify[9] = { '8', '6', 'B', '_', 'R', 'D', '0', '0', 0 };
|
|
|
|
|
const uint8_t scsi_bus = (dev->drv->scsi_device_id >> 4) & 0x0f;
|
|
|
|
|
const uint8_t scsi_id = dev->drv->scsi_device_id & 0x0f;
|
|
|
|
|
int pos = 0;
|
|
|
|
|
int idx = 0;
|
|
|
|
|
int32_t blen = 0;
|
2025-01-28 16:26:28 +01:00
|
|
|
uint32_t i;
|
|
|
|
|
unsigned preamble_len;
|
|
|
|
|
int32_t len;
|
|
|
|
|
int32_t max_len;
|
|
|
|
|
int32_t alloc_length;
|
|
|
|
|
int block_desc;
|
|
|
|
|
int size_idx;
|
|
|
|
|
int32_t * BufLen;
|
2018-04-25 23:51:13 +02:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
if (dev->drv->bus_type == RDISK_BUS_SCSI) {
|
2023-10-28 22:00:23 +02:00
|
|
|
BufLen = &scsi_devices[scsi_bus][scsi_id].buffer_length;
|
|
|
|
|
dev->tf->status &= ~ERR_STAT;
|
2018-04-25 23:51:13 +02:00
|
|
|
} else {
|
2023-10-28 22:00:23 +02:00
|
|
|
BufLen = &blen;
|
|
|
|
|
dev->tf->error = 0;
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
dev->packet_len = 0;
|
2018-04-25 23:51:13 +02:00
|
|
|
dev->request_pos = 0;
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
device_identify[7] = dev->id + 0x30;
|
|
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
memcpy(dev->current_cdb, cdb, 12);
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
if (cdb[0] != 0) {
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_log(dev->log, "Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X, "
|
2025-01-28 16:26:28 +01:00
|
|
|
"Unit attention: %i\n",
|
2025-07-25 16:30:40 +02:00
|
|
|
cdb[0], rdisk_sense_key, rdisk_asc, rdisk_ascq, dev->unit_attention);
|
|
|
|
|
rdisk_log(dev->log, "Request length: %04X\n", dev->tf->request_length);
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_log(dev->log, "CDB: %02X %02X %02X %02X %02X %02X %02X %02X "
|
2025-01-28 16:26:28 +01:00
|
|
|
"%02X %02X %02X %02X\n",
|
2022-09-18 17:13:50 -04:00
|
|
|
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
|
|
|
}
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
dev->sector_len = 0;
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_set_phase(dev, SCSI_PHASE_STATUS);
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
/*
|
|
|
|
|
This handles the Not Ready/Unit Attention check if it has to be handled at
|
|
|
|
|
this point.
|
|
|
|
|
*/
|
2025-07-25 16:30:40 +02:00
|
|
|
if (rdisk_pre_execution_check(dev, cdb) == 0)
|
2022-09-18 17:13:50 -04:00
|
|
|
return;
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
switch (cdb[0]) {
|
2022-09-18 17:13:50 -04:00
|
|
|
case GPCMD_SEND_DIAGNOSTIC:
|
|
|
|
|
if (!(cdb[1] & (1 << 2))) {
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_invalid_field(dev, cdb[1]);
|
2022-09-18 17:13:50 -04:00
|
|
|
return;
|
|
|
|
|
}
|
2023-08-09 19:44:56 -04:00
|
|
|
fallthrough;
|
2022-09-18 17:13:50 -04:00
|
|
|
case GPCMD_SCSI_RESERVE:
|
|
|
|
|
case GPCMD_SCSI_RELEASE:
|
|
|
|
|
case GPCMD_TEST_UNIT_READY:
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_set_phase(dev, SCSI_PHASE_STATUS);
|
|
|
|
|
rdisk_command_complete(dev);
|
2022-09-18 17:13:50 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPCMD_FORMAT_UNIT:
|
2025-01-28 16:26:28 +01:00
|
|
|
if (dev->drv->read_only)
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_write_protected(dev);
|
2025-01-28 16:26:28 +01:00
|
|
|
else {
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_set_phase(dev, SCSI_PHASE_STATUS);
|
|
|
|
|
rdisk_command_complete(dev);
|
2022-09-18 17:13:50 -04:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPCMD_IOMEGA_SENSE:
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_set_phase(dev, SCSI_PHASE_DATA_IN);
|
2022-09-18 17:13:50 -04:00
|
|
|
max_len = cdb[4];
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_buf_alloc(dev, 256);
|
|
|
|
|
rdisk_set_buf_len(dev, BufLen, &max_len);
|
2022-09-18 17:13:50 -04:00
|
|
|
memset(dev->buffer, 0, 256);
|
|
|
|
|
if (cdb[2] == 1) {
|
2025-01-28 16:26:28 +01:00
|
|
|
/*
|
|
|
|
|
This page is related to disk health status - setting
|
|
|
|
|
this page to 0 makes disk health read as "marginal".
|
|
|
|
|
*/
|
2022-09-18 17:13:50 -04:00
|
|
|
dev->buffer[0] = 0x58;
|
|
|
|
|
dev->buffer[1] = 0x00;
|
|
|
|
|
for (i = 0x00; i < 0x58; i++)
|
|
|
|
|
dev->buffer[i + 0x02] = 0xff;
|
|
|
|
|
} else if (cdb[2] == 2) {
|
|
|
|
|
dev->buffer[0] = 0x3d;
|
|
|
|
|
dev->buffer[1] = 0x00;
|
|
|
|
|
for (i = 0x00; i < 0x13; i++)
|
|
|
|
|
dev->buffer[i + 0x02] = 0x00;
|
|
|
|
|
dev->buffer[0x15] = 0x00;
|
|
|
|
|
if (dev->drv->read_only)
|
|
|
|
|
dev->buffer[0x15] |= 0x02;
|
|
|
|
|
for (i = 0x00; i < 0x27; i++)
|
|
|
|
|
dev->buffer[i + 0x16] = 0x00;
|
|
|
|
|
} else {
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_invalid_field(dev, cdb[2]);
|
|
|
|
|
rdisk_buf_free(dev);
|
2022-09-18 17:13:50 -04:00
|
|
|
return;
|
|
|
|
|
}
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_data_command_finish(dev, 18, 18, cdb[4], 0);
|
2022-09-18 17:13:50 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPCMD_REZERO_UNIT:
|
|
|
|
|
dev->sector_pos = dev->sector_len = 0;
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_seek(dev, 0);
|
|
|
|
|
rdisk_set_phase(dev, SCSI_PHASE_STATUS);
|
2022-09-18 17:13:50 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPCMD_REQUEST_SENSE:
|
2025-01-28 16:26:28 +01:00
|
|
|
/*
|
|
|
|
|
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.
|
|
|
|
|
*/
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_set_phase(dev, SCSI_PHASE_DATA_IN);
|
2022-09-18 17:13:50 -04:00
|
|
|
max_len = cdb[4];
|
|
|
|
|
|
|
|
|
|
if (!max_len) {
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_set_phase(dev, SCSI_PHASE_STATUS);
|
2022-09-18 17:13:50 -04:00
|
|
|
dev->packet_status = PHASE_COMPLETE;
|
2025-07-25 16:30:40 +02:00
|
|
|
dev->callback = 20.0 * RDISK_TIME;
|
|
|
|
|
rdisk_set_callback(dev);
|
2022-09-18 17:13:50 -04:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_buf_alloc(dev, 256);
|
|
|
|
|
rdisk_set_buf_len(dev, BufLen, &max_len);
|
2022-09-18 17:13:50 -04:00
|
|
|
len = (cdb[1] & 1) ? 8 : 18;
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_request_sense(dev, dev->buffer, max_len, cdb[1] & 1);
|
|
|
|
|
rdisk_data_command_finish(dev, len, len, cdb[4], 0);
|
2022-09-18 17:13:50 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPCMD_MECHANISM_STATUS:
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_set_phase(dev, SCSI_PHASE_DATA_IN);
|
2022-09-18 17:13:50 -04:00
|
|
|
len = (cdb[8] << 8) | cdb[9];
|
|
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_buf_alloc(dev, 8);
|
|
|
|
|
rdisk_set_buf_len(dev, BufLen, &len);
|
2022-09-18 17:13:50 -04:00
|
|
|
|
|
|
|
|
memset(dev->buffer, 0, 8);
|
|
|
|
|
dev->buffer[5] = 1;
|
|
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_data_command_finish(dev, 8, 8, len, 0);
|
2022-09-18 17:13:50 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPCMD_READ_6:
|
|
|
|
|
case GPCMD_READ_10:
|
|
|
|
|
case GPCMD_READ_12:
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_set_phase(dev, SCSI_PHASE_DATA_IN);
|
2022-09-18 17:13:50 -04:00
|
|
|
alloc_length = 512;
|
|
|
|
|
|
|
|
|
|
switch (cdb[0]) {
|
|
|
|
|
case GPCMD_READ_6:
|
|
|
|
|
dev->sector_len = cdb[4];
|
2023-10-28 22:00:23 +02:00
|
|
|
/*
|
|
|
|
|
For READ (6) and WRITE (6), a length of 0 indicates a
|
|
|
|
|
transfer of 256 sectors.
|
|
|
|
|
*/
|
|
|
|
|
if (dev->sector_len == 0)
|
|
|
|
|
dev->sector_len = 256;
|
|
|
|
|
dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) |
|
|
|
|
|
(((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]);
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_log(dev->log, "Length: %i, LBA: %i\n", dev->sector_len, dev->sector_pos);
|
2022-09-18 17:13:50 -04:00
|
|
|
break;
|
|
|
|
|
case GPCMD_READ_10:
|
|
|
|
|
dev->sector_len = (cdb[7] << 8) | cdb[8];
|
2025-01-28 16:26:28 +01:00
|
|
|
dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) |
|
|
|
|
|
(cdb[4] << 8) | cdb[5];
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_log(dev->log, "Length: %i, LBA: %i\n", dev->sector_len, dev->sector_pos);
|
2022-09-18 17:13:50 -04:00
|
|
|
break;
|
|
|
|
|
case GPCMD_READ_12:
|
2025-01-28 16:26:28 +01:00
|
|
|
dev->sector_len = (((uint32_t) cdb[6]) << 24) |
|
|
|
|
|
(((uint32_t) cdb[7]) << 16) |
|
2023-10-28 22:00:23 +02:00
|
|
|
(((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]);
|
2025-01-28 16:26:28 +01:00
|
|
|
dev->sector_pos = (((uint32_t) cdb[2]) << 24) |
|
|
|
|
|
(((uint32_t) cdb[3]) << 16) |
|
2023-10-28 22:00:23 +02:00
|
|
|
(((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]);
|
2022-09-18 17:13:50 -04:00
|
|
|
break;
|
2023-06-28 13:46:28 -04:00
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
2022-09-18 17:13:50 -04:00
|
|
|
}
|
|
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
if (dev->sector_pos >= dev->drv->medium_size)
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_lba_out_of_range(dev);
|
2025-01-28 16:26:28 +01:00
|
|
|
else if (dev->sector_len) {
|
|
|
|
|
max_len = dev->sector_len;
|
|
|
|
|
dev->requested_blocks = max_len;
|
2023-10-28 22:00:23 +02:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
dev->packet_len = max_len * alloc_length;
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_buf_alloc(dev, dev->packet_len);
|
2022-09-18 17:13:50 -04:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
const int ret = rdisk_blocks(dev, &alloc_length, 0);
|
2025-03-20 06:20:22 +01:00
|
|
|
alloc_length = dev->requested_blocks * 512;
|
2025-01-28 16:26:28 +01:00
|
|
|
|
|
|
|
|
if (ret > 0) {
|
|
|
|
|
dev->requested_blocks = max_len;
|
|
|
|
|
dev->packet_len = alloc_length;
|
|
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len);
|
2022-09-18 17:13:50 -04:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_data_command_finish(dev, alloc_length, 512,
|
2025-01-28 16:26:28 +01:00
|
|
|
alloc_length, 0);
|
2022-09-18 17:13:50 -04:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
ui_sb_update_icon(SB_RDISK | dev->id,
|
2025-01-28 16:26:28 +01:00
|
|
|
dev->packet_status != PHASE_COMPLETE);
|
|
|
|
|
} else {
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_set_phase(dev, SCSI_PHASE_STATUS);
|
2025-01-28 16:26:28 +01:00
|
|
|
dev->packet_status = (ret < 0) ? PHASE_ERROR : PHASE_COMPLETE;
|
2025-07-25 16:30:40 +02:00
|
|
|
dev->callback = 20.0 * RDISK_TIME;
|
|
|
|
|
rdisk_set_callback(dev);
|
|
|
|
|
rdisk_buf_free(dev);
|
2025-01-28 16:26:28 +01:00
|
|
|
}
|
|
|
|
|
} else {
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_set_phase(dev, SCSI_PHASE_STATUS);
|
|
|
|
|
/* rdisk_log(dev->log, "All done - callback set\n"); */
|
2025-01-28 16:26:28 +01:00
|
|
|
dev->packet_status = PHASE_COMPLETE;
|
2025-07-25 16:30:40 +02:00
|
|
|
dev->callback = 20.0 * RDISK_TIME;
|
|
|
|
|
rdisk_set_callback(dev);
|
2025-01-28 16:26:28 +01:00
|
|
|
break;
|
2022-09-18 17:13:50 -04:00
|
|
|
}
|
2025-01-28 16:26:28 +01:00
|
|
|
break;
|
2022-09-18 17:13:50 -04:00
|
|
|
|
|
|
|
|
case GPCMD_VERIFY_6:
|
|
|
|
|
case GPCMD_VERIFY_10:
|
|
|
|
|
case GPCMD_VERIFY_12:
|
|
|
|
|
if (!(cdb[1] & 2)) {
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_set_phase(dev, SCSI_PHASE_STATUS);
|
|
|
|
|
rdisk_command_complete(dev);
|
2022-09-18 17:13:50 -04:00
|
|
|
break;
|
|
|
|
|
}
|
2023-08-09 19:44:56 -04:00
|
|
|
fallthrough;
|
2022-09-18 17:13:50 -04:00
|
|
|
case GPCMD_WRITE_6:
|
|
|
|
|
case GPCMD_WRITE_10:
|
|
|
|
|
case GPCMD_WRITE_AND_VERIFY_10:
|
|
|
|
|
case GPCMD_WRITE_12:
|
|
|
|
|
case GPCMD_WRITE_AND_VERIFY_12:
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_set_phase(dev, SCSI_PHASE_DATA_OUT);
|
2022-09-18 17:13:50 -04:00
|
|
|
alloc_length = 512;
|
|
|
|
|
|
|
|
|
|
if (dev->drv->read_only) {
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_write_protected(dev);
|
2025-01-28 16:26:28 +01:00
|
|
|
break;
|
2022-09-18 17:13:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (cdb[0]) {
|
|
|
|
|
case GPCMD_VERIFY_6:
|
|
|
|
|
case GPCMD_WRITE_6:
|
|
|
|
|
dev->sector_len = cdb[4];
|
2023-10-28 22:00:23 +02:00
|
|
|
/*
|
|
|
|
|
For READ (6) and WRITE (6), a length of 0 indicates a
|
|
|
|
|
transfer of 256 sectors.
|
|
|
|
|
*/
|
2022-09-18 17:13:50 -04:00
|
|
|
if (dev->sector_len == 0)
|
2023-10-28 22:00:23 +02:00
|
|
|
dev->sector_len = 256;
|
|
|
|
|
dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) |
|
|
|
|
|
(((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]);
|
2022-09-18 17:13:50 -04:00
|
|
|
break;
|
|
|
|
|
case GPCMD_VERIFY_10:
|
|
|
|
|
case GPCMD_WRITE_10:
|
|
|
|
|
case GPCMD_WRITE_AND_VERIFY_10:
|
|
|
|
|
dev->sector_len = (cdb[7] << 8) | cdb[8];
|
2025-01-28 16:26:28 +01:00
|
|
|
dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) |
|
|
|
|
|
(cdb[4] << 8) | cdb[5];
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_log(dev->log, "Length: %i, LBA: %i\n",
|
2025-01-28 16:26:28 +01:00
|
|
|
dev->sector_len, dev->sector_pos);
|
2022-09-18 17:13:50 -04:00
|
|
|
break;
|
|
|
|
|
case GPCMD_VERIFY_12:
|
|
|
|
|
case GPCMD_WRITE_12:
|
|
|
|
|
case GPCMD_WRITE_AND_VERIFY_12:
|
2025-01-28 16:26:28 +01:00
|
|
|
dev->sector_len = (((uint32_t) cdb[6]) << 24) |
|
|
|
|
|
(((uint32_t) cdb[7]) << 16) |
|
2023-10-28 22:00:23 +02:00
|
|
|
(((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]);
|
2025-01-28 16:26:28 +01:00
|
|
|
dev->sector_pos = (((uint32_t) cdb[2]) << 24) |
|
|
|
|
|
(((uint32_t) cdb[3]) << 16) |
|
2023-10-28 22:00:23 +02:00
|
|
|
(((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]);
|
2022-09-18 17:13:50 -04:00
|
|
|
break;
|
2023-06-28 13:46:28 -04:00
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
2022-09-18 17:13:50 -04:00
|
|
|
}
|
|
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
if (dev->sector_pos >= dev->drv->medium_size)
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_lba_out_of_range(dev);
|
2025-01-28 16:26:28 +01:00
|
|
|
if (dev->sector_len) {
|
|
|
|
|
max_len = dev->sector_len;
|
|
|
|
|
dev->requested_blocks = max_len;
|
2022-09-18 17:13:50 -04:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
dev->packet_len = max_len * alloc_length;
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_buf_alloc(dev, dev->packet_len);
|
2022-09-18 17:13:50 -04:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
dev->requested_blocks = max_len;
|
|
|
|
|
dev->packet_len = max_len << 9;
|
2022-09-18 17:13:50 -04:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len);
|
2022-09-18 17:13:50 -04:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_data_command_finish(dev, dev->packet_len, 512,
|
2025-01-28 16:26:28 +01:00
|
|
|
dev->packet_len, 1);
|
2022-09-18 17:13:50 -04:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
ui_sb_update_icon_write(SB_RDISK | dev->id,
|
2025-01-28 16:26:28 +01:00
|
|
|
dev->packet_status != PHASE_COMPLETE);
|
|
|
|
|
} else {
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_set_phase(dev, SCSI_PHASE_STATUS);
|
|
|
|
|
/* rdisk_log(dev->log, "All done - callback set\n"); */
|
2022-09-18 17:13:50 -04:00
|
|
|
dev->packet_status = PHASE_COMPLETE;
|
2025-07-25 16:30:40 +02:00
|
|
|
dev->callback = 20.0 * RDISK_TIME;
|
|
|
|
|
rdisk_set_callback(dev);
|
2022-09-18 17:13:50 -04:00
|
|
|
}
|
2025-01-28 16:26:28 +01:00
|
|
|
break;
|
2022-09-18 17:13:50 -04:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
case GPCMD_WRITE_SAME_10:
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_set_phase(dev, SCSI_PHASE_DATA_OUT);
|
2025-01-28 16:26:28 +01:00
|
|
|
alloc_length = 512;
|
2022-09-18 17:13:50 -04:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
if ((cdb[1] & 6) == 6)
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_invalid_field(dev, cdb[1]);
|
2025-01-28 16:26:28 +01:00
|
|
|
else {
|
|
|
|
|
if (dev->drv->read_only)
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_write_protected(dev);
|
2025-01-28 16:26:28 +01:00
|
|
|
else {
|
|
|
|
|
dev->sector_len = (cdb[7] << 8) | cdb[8];
|
|
|
|
|
dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) |
|
|
|
|
|
(cdb[4] << 8) | cdb[5];
|
2022-09-18 17:13:50 -04:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
if (dev->sector_pos >= dev->drv->medium_size)
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_lba_out_of_range(dev);
|
2025-01-28 16:26:28 +01:00
|
|
|
else if (dev->sector_len) {
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_buf_alloc(dev, alloc_length);
|
|
|
|
|
rdisk_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len);
|
2022-09-18 17:13:50 -04:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
max_len = 1;
|
|
|
|
|
dev->requested_blocks = 1;
|
2022-09-18 17:13:50 -04:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
dev->packet_len = alloc_length;
|
2022-09-18 17:13:50 -04:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_set_phase(dev, SCSI_PHASE_DATA_OUT);
|
2025-01-28 16:26:28 +01:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_data_command_finish(dev, 512, 512,
|
2025-01-28 16:26:28 +01:00
|
|
|
alloc_length, 1);
|
|
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
ui_sb_update_icon_write(SB_RDISK | dev->id,
|
2025-01-28 16:26:28 +01:00
|
|
|
dev->packet_status != PHASE_COMPLETE);
|
|
|
|
|
} else {
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_set_phase(dev, SCSI_PHASE_STATUS);
|
|
|
|
|
/* rdisk_log(dev->log, "All done - callback set\n"); */
|
2025-01-28 16:26:28 +01:00
|
|
|
dev->packet_status = PHASE_COMPLETE;
|
2025-07-25 16:30:40 +02:00
|
|
|
dev->callback = 20.0 * RDISK_TIME;
|
|
|
|
|
rdisk_set_callback(dev);
|
2025-01-28 16:26:28 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
2022-09-18 17:13:50 -04:00
|
|
|
|
|
|
|
|
case GPCMD_MODE_SENSE_6:
|
|
|
|
|
case GPCMD_MODE_SENSE_10:
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_set_phase(dev, SCSI_PHASE_DATA_IN);
|
2022-09-18 17:13:50 -04:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
if (dev->drv->bus_type == RDISK_BUS_SCSI)
|
2022-09-18 17:13:50 -04:00
|
|
|
block_desc = ((cdb[1] >> 3) & 1) ? 0 : 1;
|
|
|
|
|
else
|
|
|
|
|
block_desc = 0;
|
|
|
|
|
|
|
|
|
|
if (cdb[0] == GPCMD_MODE_SENSE_6) {
|
|
|
|
|
len = cdb[4];
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_buf_alloc(dev, 256);
|
2022-09-18 17:13:50 -04:00
|
|
|
} else {
|
|
|
|
|
len = (cdb[8] | (cdb[7] << 8));
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_buf_alloc(dev, 65536);
|
2022-09-18 17:13:50 -04:00
|
|
|
}
|
|
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
if (zip_mode_sense_page_flags & (1LL << (uint64_t) (cdb[2] & 0x3f))) {
|
|
|
|
|
memset(dev->buffer, 0, len);
|
|
|
|
|
alloc_length = len;
|
|
|
|
|
|
|
|
|
|
if (cdb[0] == GPCMD_MODE_SENSE_6) {
|
2025-07-25 16:30:40 +02:00
|
|
|
len = rdisk_mode_sense(dev, dev->buffer, 4, cdb[2],
|
|
|
|
|
block_desc);
|
2025-01-28 16:26:28 +01:00
|
|
|
len = MIN(len, alloc_length);
|
|
|
|
|
dev->buffer[0] = len - 1;
|
|
|
|
|
dev->buffer[1] = 0;
|
|
|
|
|
if (block_desc)
|
|
|
|
|
dev->buffer[3] = 8;
|
|
|
|
|
} else {
|
2025-07-25 16:30:40 +02:00
|
|
|
len = rdisk_mode_sense(dev, dev->buffer, 8, cdb[2],
|
|
|
|
|
block_desc);
|
2025-01-28 16:26:28 +01:00
|
|
|
len = MIN(len, alloc_length);
|
|
|
|
|
dev->buffer[0] = (len - 2) >> 8;
|
|
|
|
|
dev->buffer[1] = (len - 2) & 255;
|
|
|
|
|
dev->buffer[2] = 0;
|
|
|
|
|
if (block_desc) {
|
|
|
|
|
dev->buffer[6] = 0;
|
|
|
|
|
dev->buffer[7] = 8;
|
|
|
|
|
}
|
2022-09-18 17:13:50 -04:00
|
|
|
}
|
|
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_set_buf_len(dev, BufLen, &len);
|
2022-09-18 17:13:50 -04:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_log(dev->log, "Reading mode page: %02X...\n", cdb[2]);
|
2022-09-18 17:13:50 -04:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_data_command_finish(dev, len, len, alloc_length, 0);
|
2025-01-28 16:26:28 +01:00
|
|
|
} else {
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_invalid_field(dev, cdb[2]);
|
|
|
|
|
rdisk_buf_free(dev);
|
2025-01-28 16:26:28 +01:00
|
|
|
}
|
|
|
|
|
break;
|
2022-09-18 17:13:50 -04:00
|
|
|
|
|
|
|
|
case GPCMD_MODE_SELECT_6:
|
|
|
|
|
case GPCMD_MODE_SELECT_10:
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_set_phase(dev, SCSI_PHASE_DATA_OUT);
|
2022-09-18 17:13:50 -04:00
|
|
|
|
|
|
|
|
if (cdb[0] == GPCMD_MODE_SELECT_6) {
|
|
|
|
|
len = cdb[4];
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_buf_alloc(dev, 256);
|
2022-09-18 17:13:50 -04:00
|
|
|
} else {
|
|
|
|
|
len = (cdb[7] << 8) | cdb[8];
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_buf_alloc(dev, 65536);
|
2022-09-18 17:13:50 -04:00
|
|
|
}
|
|
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_set_buf_len(dev, BufLen, &len);
|
2022-09-18 17:13:50 -04:00
|
|
|
|
|
|
|
|
dev->total_length = len;
|
|
|
|
|
dev->do_page_save = cdb[1] & 1;
|
|
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_data_command_finish(dev, len, len, len, 1);
|
2022-09-18 17:13:50 -04:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case GPCMD_START_STOP_UNIT:
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_set_phase(dev, SCSI_PHASE_STATUS);
|
2022-09-18 17:13:50 -04:00
|
|
|
|
|
|
|
|
switch (cdb[4] & 3) {
|
|
|
|
|
case 0: /* Stop the disc. */
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_eject(dev->id); /* The Iomega Windows 9x drivers require this. */
|
2022-09-18 17:13:50 -04:00
|
|
|
break;
|
|
|
|
|
case 1: /* Start the disc and read the TOC. */
|
|
|
|
|
break;
|
|
|
|
|
case 2: /* Eject the disc if possible. */
|
2023-06-26 12:47:04 -04:00
|
|
|
#if 0
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_eject(dev->id);
|
2023-06-26 12:47:04 -04:00
|
|
|
#endif
|
2022-09-18 17:13:50 -04:00
|
|
|
break;
|
|
|
|
|
case 3: /* Load the disc (close tray). */
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_reload(dev->id);
|
2022-09-18 17:13:50 -04:00
|
|
|
break;
|
2023-06-28 13:46:28 -04:00
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
2022-09-18 17:13:50 -04:00
|
|
|
}
|
|
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_command_complete(dev);
|
2022-09-18 17:13:50 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPCMD_INQUIRY:
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_set_phase(dev, SCSI_PHASE_DATA_IN);
|
2022-09-18 17:13:50 -04:00
|
|
|
|
|
|
|
|
max_len = cdb[3];
|
|
|
|
|
max_len <<= 8;
|
|
|
|
|
max_len |= cdb[4];
|
|
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_buf_alloc(dev, 65536);
|
2022-09-18 17:13:50 -04:00
|
|
|
|
|
|
|
|
if (cdb[1] & 1) {
|
|
|
|
|
preamble_len = 4;
|
|
|
|
|
size_idx = 3;
|
|
|
|
|
|
|
|
|
|
dev->buffer[idx++] = 0;
|
|
|
|
|
dev->buffer[idx++] = cdb[2];
|
|
|
|
|
dev->buffer[idx++] = 0;
|
|
|
|
|
|
|
|
|
|
idx++;
|
|
|
|
|
|
|
|
|
|
switch (cdb[2]) {
|
|
|
|
|
case 0x00:
|
|
|
|
|
dev->buffer[idx++] = 0x00;
|
|
|
|
|
dev->buffer[idx++] = 0x83;
|
|
|
|
|
break;
|
|
|
|
|
case 0x83:
|
|
|
|
|
if (idx + 24 > max_len) {
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_data_phase_error(dev, cdb[2]);
|
|
|
|
|
rdisk_buf_free(dev);
|
2022-09-18 17:13:50 -04:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dev->buffer[idx++] = 0x02;
|
|
|
|
|
dev->buffer[idx++] = 0x00;
|
|
|
|
|
dev->buffer[idx++] = 0x00;
|
|
|
|
|
dev->buffer[idx++] = 20;
|
|
|
|
|
ide_padstr8(dev->buffer + idx, 20, "53R141"); /* Serial */
|
|
|
|
|
idx += 20;
|
|
|
|
|
|
|
|
|
|
if (idx + 72 > cdb[4])
|
|
|
|
|
goto atapi_out;
|
|
|
|
|
dev->buffer[idx++] = 0x02;
|
|
|
|
|
dev->buffer[idx++] = 0x01;
|
|
|
|
|
dev->buffer[idx++] = 0x00;
|
|
|
|
|
dev->buffer[idx++] = 68;
|
2025-01-28 16:26:28 +01:00
|
|
|
/* Vendor */
|
2025-07-25 16:30:40 +02:00
|
|
|
if (dev->drv->type >= RDISK_TYPE_ZIP_100)
|
|
|
|
|
ide_padstr8(dev->buffer + idx, 8, "IOMEGA ");
|
|
|
|
|
else
|
|
|
|
|
ide_padstr8(dev->buffer + 8, 8, EMU_NAME); /* Vendor */
|
2022-09-18 17:13:50 -04:00
|
|
|
idx += 8;
|
2025-01-28 16:26:28 +01:00
|
|
|
/* Product */
|
2025-07-25 16:30:40 +02:00
|
|
|
if (dev->drv->type == RDISK_TYPE_ZIP_250)
|
2025-01-28 16:26:28 +01:00
|
|
|
ide_padstr8(dev->buffer + idx, 40, "ZIP 250 ");
|
2025-07-25 16:30:40 +02:00
|
|
|
else if (dev->drv->type == RDISK_TYPE_ZIP_100)
|
2025-01-28 16:26:28 +01:00
|
|
|
ide_padstr8(dev->buffer + idx, 40, "ZIP 100 ");
|
2025-07-25 16:30:40 +02:00
|
|
|
else
|
|
|
|
|
ide_padstr8(dev->buffer + 16, 40, device_identify); /* Product */
|
2022-09-18 17:13:50 -04:00
|
|
|
idx += 40;
|
2025-01-28 16:26:28 +01:00
|
|
|
ide_padstr8(dev->buffer + idx, 20, "53R141");
|
2022-09-18 17:13:50 -04:00
|
|
|
idx += 20;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_log(dev->log, "INQUIRY: Invalid page: %02X\n", cdb[2]);
|
|
|
|
|
rdisk_invalid_field(dev, cdb[2]);
|
|
|
|
|
rdisk_buf_free(dev);
|
2022-09-18 17:13:50 -04:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
preamble_len = 5;
|
|
|
|
|
size_idx = 4;
|
|
|
|
|
|
|
|
|
|
memset(dev->buffer, 0, 8);
|
2024-05-06 13:09:08 +02:00
|
|
|
if ((cdb[1] & 0xe0) || ((dev->cur_lun > 0x00) && (dev->cur_lun < 0xff)))
|
2025-01-28 16:26:28 +01:00
|
|
|
dev->buffer[0] = 0x7f; /* No physical device on this LUN */
|
2022-09-18 17:13:50 -04:00
|
|
|
else
|
2025-01-28 16:26:28 +01:00
|
|
|
dev->buffer[0] = 0x00; /* Hard disk */
|
|
|
|
|
dev->buffer[1] = 0x80; /* Removable */
|
|
|
|
|
/* SCSI-2 compliant */
|
2025-07-25 16:30:40 +02:00
|
|
|
dev->buffer[2] = (dev->drv->bus_type == RDISK_BUS_SCSI) ? 0x02 : 0x00;
|
|
|
|
|
dev->buffer[3] = (dev->drv->bus_type == RDISK_BUS_SCSI) ? 0x02 : 0x21;
|
2023-06-26 12:47:04 -04:00
|
|
|
#if 0
|
|
|
|
|
dev->buffer[4] = 31;
|
|
|
|
|
#endif
|
2022-09-18 17:13:50 -04:00
|
|
|
dev->buffer[4] = 0;
|
2025-07-25 16:30:40 +02:00
|
|
|
if (dev->drv->bus_type == RDISK_BUS_SCSI) {
|
2025-01-28 16:26:28 +01:00
|
|
|
dev->buffer[6] = 1; /* 16-bit transfers supported */
|
|
|
|
|
dev->buffer[7] = 0x20; /* Wide bus supported */
|
2022-09-18 17:13:50 -04:00
|
|
|
}
|
|
|
|
|
dev->buffer[7] |= 0x02;
|
|
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
ide_padstr8(dev->buffer + 8, 8, "IOMEGA "); /* Vendor */
|
2025-07-25 16:30:40 +02:00
|
|
|
if (dev->drv->type == RDISK_TYPE_ZIP_250) {
|
2025-01-28 16:26:28 +01:00
|
|
|
/* Product */
|
|
|
|
|
ide_padstr8(dev->buffer + 16, 16, "ZIP 250 ");
|
|
|
|
|
/* Revision */
|
|
|
|
|
ide_padstr8(dev->buffer + 32, 4, "42.S");
|
|
|
|
|
/* Date? */
|
2022-09-18 17:13:50 -04:00
|
|
|
if (max_len >= 44)
|
2025-01-28 16:26:28 +01:00
|
|
|
ide_padstr8(dev->buffer + 36, 8, "08/08/01");
|
2022-09-18 17:13:50 -04:00
|
|
|
if (max_len >= 122)
|
|
|
|
|
ide_padstr8(dev->buffer + 96, 26, "(c) Copyright IOMEGA 2000 "); /* Copyright string */
|
2025-07-25 16:30:40 +02:00
|
|
|
} else if (dev->drv->type == RDISK_TYPE_ZIP_100) {
|
2025-01-28 16:26:28 +01:00
|
|
|
/* Product */
|
|
|
|
|
ide_padstr8(dev->buffer + 16, 16, "ZIP 100 ");
|
|
|
|
|
/* Revision */
|
|
|
|
|
ide_padstr8(dev->buffer + 32, 4, "E.08");
|
2025-07-25 16:30:40 +02:00
|
|
|
} else {
|
|
|
|
|
ide_padstr8(dev->buffer + 8, 8,
|
|
|
|
|
EMU_NAME); /* Vendor */
|
|
|
|
|
ide_padstr8(dev->buffer + 16, 16,
|
|
|
|
|
device_identify); /* Product */
|
|
|
|
|
ide_padstr8(dev->buffer + 32, 4,
|
|
|
|
|
EMU_VERSION_EX); /* Revision */
|
2022-09-18 17:13:50 -04:00
|
|
|
}
|
|
|
|
|
idx = 36;
|
|
|
|
|
|
|
|
|
|
if (max_len == 96) {
|
|
|
|
|
dev->buffer[4] = 91;
|
|
|
|
|
idx = 96;
|
|
|
|
|
} else if (max_len == 128) {
|
|
|
|
|
dev->buffer[4] = 0x75;
|
|
|
|
|
idx = 128;
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-01-26 22:17:09 +01:00
|
|
|
|
|
|
|
|
atapi_out:
|
2022-09-18 17:13:50 -04:00
|
|
|
dev->buffer[size_idx] = idx - preamble_len;
|
|
|
|
|
len = idx;
|
|
|
|
|
|
|
|
|
|
len = MIN(len, max_len);
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_set_buf_len(dev, BufLen, &len);
|
2022-09-18 17:13:50 -04:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_data_command_finish(dev, len, len, max_len, 0);
|
2022-09-18 17:13:50 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPCMD_PREVENT_REMOVAL:
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_set_phase(dev, SCSI_PHASE_STATUS);
|
|
|
|
|
rdisk_command_complete(dev);
|
2022-09-18 17:13:50 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPCMD_SEEK_6:
|
|
|
|
|
case GPCMD_SEEK_10:
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_set_phase(dev, SCSI_PHASE_STATUS);
|
2022-09-18 17:13:50 -04:00
|
|
|
|
|
|
|
|
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-28 13:46:28 -04:00
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
2022-09-18 17:13:50 -04:00
|
|
|
}
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_seek(dev, pos);
|
|
|
|
|
rdisk_command_complete(dev);
|
2022-09-18 17:13:50 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPCMD_READ_CDROM_CAPACITY:
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_set_phase(dev, SCSI_PHASE_DATA_IN);
|
2022-09-18 17:13:50 -04:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_buf_alloc(dev, 8);
|
2022-09-18 17:13:50 -04:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
/* IMPORTANT: What's returned is the last LBA block. */
|
|
|
|
|
max_len = dev->drv->medium_size - 1;
|
2022-09-18 17:13:50 -04:00
|
|
|
memset(dev->buffer, 0, 8);
|
|
|
|
|
dev->buffer[0] = (max_len >> 24) & 0xff;
|
|
|
|
|
dev->buffer[1] = (max_len >> 16) & 0xff;
|
|
|
|
|
dev->buffer[2] = (max_len >> 8) & 0xff;
|
|
|
|
|
dev->buffer[3] = max_len & 0xff;
|
|
|
|
|
dev->buffer[6] = 2; /* 512 = 0x0200 */
|
|
|
|
|
len = 8;
|
|
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_set_buf_len(dev, BufLen, &len);
|
2022-09-18 17:13:50 -04:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_data_command_finish(dev, len, len, len, 0);
|
2022-09-18 17:13:50 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPCMD_IOMEGA_EJECT:
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_set_phase(dev, SCSI_PHASE_STATUS);
|
|
|
|
|
rdisk_eject(dev->id);
|
|
|
|
|
rdisk_command_complete(dev);
|
2022-09-18 17:13:50 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPCMD_READ_FORMAT_CAPACITIES:
|
|
|
|
|
len = (cdb[7] << 8) | cdb[8];
|
|
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_buf_alloc(dev, len);
|
2022-09-18 17:13:50 -04:00
|
|
|
memset(dev->buffer, 0, len);
|
|
|
|
|
|
|
|
|
|
pos = 0;
|
|
|
|
|
|
|
|
|
|
/* List header */
|
|
|
|
|
dev->buffer[pos++] = 0;
|
|
|
|
|
dev->buffer[pos++] = 0;
|
|
|
|
|
dev->buffer[pos++] = 0;
|
2023-08-21 20:22:55 -04:00
|
|
|
if (dev->drv->fp != NULL)
|
2022-09-18 17:13:50 -04:00
|
|
|
dev->buffer[pos++] = 16;
|
|
|
|
|
else
|
|
|
|
|
dev->buffer[pos++] = 8;
|
|
|
|
|
|
|
|
|
|
/* Current/Maximum capacity header */
|
2025-07-25 16:30:40 +02:00
|
|
|
if (dev->drv->type == RDISK_TYPE_ZIP_100) {
|
|
|
|
|
/* ZIP 100 only supports ZIP 100 media as well, so we always return
|
|
|
|
|
the ZIP 100 size. */
|
|
|
|
|
dev->buffer[pos++] = (ZIP_SECTORS >> 24) & 0xff;
|
|
|
|
|
dev->buffer[pos++] = (ZIP_SECTORS >> 16) & 0xff;
|
|
|
|
|
dev->buffer[pos++] = (ZIP_SECTORS >> 8) & 0xff;
|
|
|
|
|
dev->buffer[pos++] = ZIP_SECTORS & 0xff;
|
|
|
|
|
if (dev->drv->fp != NULL)
|
|
|
|
|
dev->buffer[pos++] = 2;
|
|
|
|
|
else
|
|
|
|
|
dev->buffer[pos++] = 3;
|
|
|
|
|
} else {
|
2022-09-18 17:13:50 -04:00
|
|
|
/* ZIP 250 also supports ZIP 100 media, so if the medium is inserted,
|
|
|
|
|
we return the inserted medium's size, otherwise, the ZIP 250 size. */
|
2023-08-21 20:22:55 -04:00
|
|
|
if (dev->drv->fp != NULL) {
|
2022-09-18 17:13:50 -04:00
|
|
|
dev->buffer[pos++] = (dev->drv->medium_size >> 24) & 0xff;
|
|
|
|
|
dev->buffer[pos++] = (dev->drv->medium_size >> 16) & 0xff;
|
|
|
|
|
dev->buffer[pos++] = (dev->drv->medium_size >> 8) & 0xff;
|
|
|
|
|
dev->buffer[pos++] = dev->drv->medium_size & 0xff;
|
|
|
|
|
dev->buffer[pos++] = 2; /* Current medium capacity */
|
|
|
|
|
} else {
|
|
|
|
|
dev->buffer[pos++] = (ZIP_250_SECTORS >> 24) & 0xff;
|
|
|
|
|
dev->buffer[pos++] = (ZIP_250_SECTORS >> 16) & 0xff;
|
|
|
|
|
dev->buffer[pos++] = (ZIP_250_SECTORS >> 8) & 0xff;
|
|
|
|
|
dev->buffer[pos++] = ZIP_250_SECTORS & 0xff;
|
|
|
|
|
dev->buffer[pos++] = 3; /* Maximum medium capacity */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dev->buffer[pos++] = 512 >> 16;
|
|
|
|
|
dev->buffer[pos++] = 512 >> 8;
|
|
|
|
|
dev->buffer[pos++] = 512 & 0xff;
|
|
|
|
|
|
2023-08-21 20:22:55 -04:00
|
|
|
if (dev->drv->fp != NULL) {
|
2022-09-18 17:13:50 -04:00
|
|
|
/* Formattable capacity descriptor */
|
|
|
|
|
dev->buffer[pos++] = (dev->drv->medium_size >> 24) & 0xff;
|
|
|
|
|
dev->buffer[pos++] = (dev->drv->medium_size >> 16) & 0xff;
|
|
|
|
|
dev->buffer[pos++] = (dev->drv->medium_size >> 8) & 0xff;
|
|
|
|
|
dev->buffer[pos++] = dev->drv->medium_size & 0xff;
|
|
|
|
|
dev->buffer[pos++] = 0;
|
|
|
|
|
dev->buffer[pos++] = 512 >> 16;
|
|
|
|
|
dev->buffer[pos++] = 512 >> 8;
|
|
|
|
|
dev->buffer[pos++] = 512 & 0xff;
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_set_buf_len(dev, BufLen, &len);
|
2022-09-18 17:13:50 -04:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_data_command_finish(dev, len, len, len, 0);
|
2022-09-18 17:13:50 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_illegal_opcode(dev, cdb[0]);
|
2022-09-18 17:13:50 -04:00
|
|
|
break;
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2023-06-26 12:47:04 -04:00
|
|
|
#if 0
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_log(dev->log, "Phase: %02X, request length: %i\n",
|
2025-01-28 16:26:28 +01:00
|
|
|
dev->tf->phase, dev->tf->request_length);
|
2023-06-26 12:47:04 -04:00
|
|
|
#endif
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2023-10-28 22:00:23 +02:00
|
|
|
if ((dev->packet_status == PHASE_COMPLETE) || (dev->packet_status == PHASE_ERROR))
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_buf_free(dev);
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2018-10-30 13:32:25 +01:00
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_command_stop(scsi_common_t *sc)
|
2018-10-30 13:32:25 +01:00
|
|
|
{
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_t *dev = (rdisk_t *) sc;
|
2018-10-30 13:32:25 +01:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_command_complete(dev);
|
|
|
|
|
rdisk_buf_free(dev);
|
2018-10-30 13:32:25 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
/* The command second phase function, needed for Mode Select. */
|
|
|
|
|
static uint8_t
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_phase_data_out(scsi_common_t *sc)
|
2018-04-25 23:51:13 +02:00
|
|
|
{
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_t *dev = (rdisk_t *) sc;
|
2025-01-28 16:26:28 +01:00
|
|
|
int len = 0;
|
|
|
|
|
uint8_t error = 0;
|
|
|
|
|
uint32_t last_to_write;
|
|
|
|
|
uint32_t i;
|
2023-05-29 01:30:51 -04:00
|
|
|
uint16_t block_desc_len;
|
|
|
|
|
uint16_t pos;
|
2020-12-26 02:26:45 +01:00
|
|
|
uint16_t param_list_len;
|
2025-01-28 16:26:28 +01:00
|
|
|
uint8_t hdr_len;
|
|
|
|
|
uint8_t val;
|
2018-09-12 19:46:26 +02:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
switch (dev->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 (dev->requested_blocks > 0)
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_blocks(dev, &len, 1);
|
2022-09-18 17:13:50 -04:00
|
|
|
break;
|
|
|
|
|
case GPCMD_WRITE_SAME_10:
|
|
|
|
|
if (!dev->current_cdb[7] && !dev->current_cdb[8]) {
|
|
|
|
|
last_to_write = (dev->drv->medium_size - 1);
|
|
|
|
|
} else
|
|
|
|
|
last_to_write = dev->sector_pos + dev->sector_len - 1;
|
|
|
|
|
|
|
|
|
|
for (i = dev->sector_pos; i <= last_to_write; i++) {
|
|
|
|
|
if (dev->current_cdb[1] & 2) {
|
|
|
|
|
dev->buffer[0] = (i >> 24) & 0xff;
|
|
|
|
|
dev->buffer[1] = (i >> 16) & 0xff;
|
|
|
|
|
dev->buffer[2] = (i >> 8) & 0xff;
|
|
|
|
|
dev->buffer[3] = i & 0xff;
|
|
|
|
|
} else if (dev->current_cdb[1] & 4) {
|
2025-07-25 16:30:40 +02:00
|
|
|
/* CHS are 96, 1, 2048 (RDISK 100) and 239, 1, 2048 (RDISK 250) */
|
2025-01-28 16:26:28 +01:00
|
|
|
const uint32_t s = (i % 2048);
|
|
|
|
|
const uint32_t h = ((i - s) / 2048) % 1;
|
|
|
|
|
const uint32_t c = ((i - s) / 2048) / 1;
|
|
|
|
|
dev->buffer[0] = (c >> 16) & 0xff;
|
|
|
|
|
dev->buffer[1] = (c >> 8) & 0xff;
|
|
|
|
|
dev->buffer[2] = c & 0xff;
|
|
|
|
|
dev->buffer[3] = h & 0xff;
|
|
|
|
|
dev->buffer[4] = (s >> 24) & 0xff;
|
|
|
|
|
dev->buffer[5] = (s >> 16) & 0xff;
|
|
|
|
|
dev->buffer[6] = (s >> 8) & 0xff;
|
|
|
|
|
dev->buffer[7] = s & 0xff;
|
2022-09-18 17:13:50 -04:00
|
|
|
}
|
2025-01-28 16:26:28 +01:00
|
|
|
if (fseek(dev->drv->fp, dev->drv->base + (i << 9),
|
|
|
|
|
SEEK_SET) == -1)
|
2025-07-25 16:30:40 +02:00
|
|
|
log_fatal(dev->log, "rdisk_phase_data_out(): Error seeking\n");
|
2023-08-21 20:22:55 -04:00
|
|
|
if (fwrite(dev->buffer, 1, 512, dev->drv->fp) != 512)
|
2025-07-25 16:30:40 +02:00
|
|
|
log_fatal(dev->log, "rdisk_phase_data_out(): Error writing data\n");
|
2022-09-18 17:13:50 -04:00
|
|
|
}
|
2024-09-24 04:37:26 +02:00
|
|
|
|
|
|
|
|
fflush(dev->drv->fp);
|
2022-09-18 17:13:50 -04:00
|
|
|
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];
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
if (dev->drv->bus_type == RDISK_BUS_SCSI) {
|
2022-09-18 17:13:50 -04:00
|
|
|
if (dev->current_cdb[0] == GPCMD_MODE_SELECT_6) {
|
|
|
|
|
block_desc_len = dev->buffer[2];
|
|
|
|
|
block_desc_len <<= 8;
|
|
|
|
|
block_desc_len |= dev->buffer[3];
|
|
|
|
|
} else {
|
|
|
|
|
block_desc_len = dev->buffer[6];
|
|
|
|
|
block_desc_len <<= 8;
|
|
|
|
|
block_desc_len |= dev->buffer[7];
|
|
|
|
|
}
|
|
|
|
|
} else
|
|
|
|
|
block_desc_len = 0;
|
|
|
|
|
|
|
|
|
|
pos = hdr_len + block_desc_len;
|
|
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
|
if (pos >= param_list_len) {
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_log(dev->log, "Buffer has only block descriptor\n");
|
2022-09-18 17:13:50 -04:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
const uint8_t page = dev->buffer[pos] & 0x3f;
|
|
|
|
|
const uint8_t page_len = dev->buffer[pos + 1];
|
2022-09-18 17:13:50 -04:00
|
|
|
|
|
|
|
|
pos += 2;
|
|
|
|
|
|
|
|
|
|
if (!(zip_mode_sense_page_flags & (1LL << ((uint64_t) page))))
|
|
|
|
|
error |= 1;
|
2025-01-28 16:26:28 +01:00
|
|
|
else for (i = 0; i < page_len; i++) {
|
|
|
|
|
const uint8_t old_val = dev->ms_pages_saved.pages[page][i + 2];
|
|
|
|
|
const uint8_t ch = zip_mode_sense_pages_changeable.pages[page][i + 2];
|
|
|
|
|
val = dev->buffer[pos + i];
|
|
|
|
|
if (val != old_val) {
|
|
|
|
|
if (ch)
|
|
|
|
|
dev->ms_pages_saved.pages[page][i + 2] = val;
|
|
|
|
|
else {
|
|
|
|
|
error |= 1;
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_invalid_field_pl(dev, val);
|
2022-09-18 17:13:50 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pos += page_len;
|
|
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
if (dev->drv->bus_type == RDISK_BUS_SCSI)
|
2022-09-18 17:13:50 -04:00
|
|
|
val = zip_mode_sense_pages_default_scsi.pages[page][0] & 0x80;
|
|
|
|
|
else
|
|
|
|
|
val = zip_mode_sense_pages_default.pages[page][0] & 0x80;
|
|
|
|
|
if (dev->do_page_save && val)
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_mode_sense_save(dev);
|
2022-09-18 17:13:50 -04:00
|
|
|
|
|
|
|
|
if (pos >= dev->total_length)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (error) {
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_buf_free(dev);
|
2022-09-18 17:13:50 -04:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2023-06-28 13:46:28 -04:00
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
2018-04-25 23:51:13 +02:00
|
|
|
}
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_command_stop((scsi_common_t *) dev);
|
2018-04-25 23:51:13 +02:00
|
|
|
return 1;
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Peform a master init on the entire module. */
|
|
|
|
|
void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_global_init(void)
|
2018-01-26 22:17:09 +01:00
|
|
|
{
|
|
|
|
|
/* Clear the global data. */
|
2025-07-25 16:30:40 +02:00
|
|
|
memset(rdisk_drives, 0x00, sizeof(rdisk_drives));
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
2018-10-10 22:33:24 +02:00
|
|
|
static int
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_get_max(UNUSED(const ide_t *ide), const int ide_has_dma, const int type)
|
2018-10-10 22:33:24 +02:00
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
switch (type) {
|
|
|
|
|
case TYPE_PIO:
|
2025-08-15 20:59:07 +02:00
|
|
|
ret = 3;
|
2022-09-18 17:13:50 -04:00
|
|
|
break;
|
|
|
|
|
case TYPE_SDMA:
|
|
|
|
|
default:
|
|
|
|
|
ret = -1;
|
|
|
|
|
break;
|
|
|
|
|
case TYPE_MDMA:
|
|
|
|
|
ret = ide_has_dma ? 1 : -1;
|
|
|
|
|
break;
|
|
|
|
|
case TYPE_UDMA:
|
|
|
|
|
ret = ide_has_dma ? 5 : -1;
|
|
|
|
|
break;
|
2018-10-10 22:33:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_get_timings(UNUSED(const ide_t *ide), const int ide_has_dma, const int type)
|
2018-10-10 22:33:24 +02:00
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
switch (type) {
|
|
|
|
|
case TIMINGS_DMA:
|
|
|
|
|
ret = ide_has_dma ? 0x96 : 0;
|
|
|
|
|
break;
|
|
|
|
|
case TIMINGS_PIO:
|
2025-08-15 20:59:07 +02:00
|
|
|
ret = 0xf0;
|
2022-09-18 17:13:50 -04:00
|
|
|
break;
|
|
|
|
|
case TIMINGS_PIO_FC:
|
2025-08-15 20:59:07 +02:00
|
|
|
ret = 0xb4;
|
2022-09-18 17:13:50 -04:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
ret = 0;
|
|
|
|
|
break;
|
2018-10-10 22:33:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_zip_100_identify(const ide_t *ide)
|
2018-10-30 13:32:25 +01:00
|
|
|
{
|
2022-09-18 17:13:50 -04:00
|
|
|
ide_padstr((char *) (ide->buffer + 23), "E.08", 8); /* Firmware */
|
2018-10-30 13:32:25 +01:00
|
|
|
ide_padstr((char *) (ide->buffer + 27), "IOMEGA ZIP 100 ATAPI", 40); /* Model */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_zip_250_identify(const ide_t *ide, const int ide_has_dma)
|
2018-10-30 13:32:25 +01:00
|
|
|
{
|
2025-01-28 16:26:28 +01:00
|
|
|
/* Firmware */
|
|
|
|
|
ide_padstr((char *) (ide->buffer + 23), "42.S", 8);
|
|
|
|
|
/* Model */
|
|
|
|
|
ide_padstr((char *) (ide->buffer + 27), "IOMEGA ZIP 250 ATAPI", 40);
|
2018-10-30 13:32:25 +01:00
|
|
|
|
|
|
|
|
if (ide_has_dma) {
|
2025-01-28 16:26:28 +01:00
|
|
|
ide->buffer[80] = 0x70; /* Supported ATA versions : ATA/ATAPI-4 ATA/ATAPI-6 */
|
|
|
|
|
/* Maximum ATA revision supported : ATA/ATAPI-6 T13 1410D revision 3a */
|
|
|
|
|
ide->buffer[81] = 0x19;
|
2018-10-30 13:32:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_generic_identify(const ide_t *ide, const int ide_has_dma, const rdisk_t *rdisk)
|
|
|
|
|
{
|
|
|
|
|
char model[40];
|
|
|
|
|
|
|
|
|
|
memset(model, 0, 40);
|
|
|
|
|
snprintf(model, 40, "%s %s%02i", EMU_NAME, "86B_RD", rdisk->id);
|
|
|
|
|
ide_padstr((char *) (ide->buffer + 23), EMU_VERSION_EX, 8); /* Firmware */
|
|
|
|
|
ide_padstr((char *) (ide->buffer + 27), model, 40); /* Model */
|
|
|
|
|
|
|
|
|
|
if (ide_has_dma) {
|
|
|
|
|
ide->buffer[80] = 0x70; /* Supported ATA versions : ATA/ATAPI-4 ATA/ATAPI-6 */
|
|
|
|
|
/* Maximum ATA revision supported : ATA/ATAPI-6 T13 1410D revision 3a */
|
|
|
|
|
ide->buffer[81] = 0x19;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
rdisk_identify(const ide_t *ide, const int ide_has_dma)
|
2018-10-10 22:33:24 +02:00
|
|
|
{
|
2025-07-25 16:30:40 +02:00
|
|
|
const rdisk_t *rdisk = (rdisk_t *) ide->sc;
|
2018-10-10 22:33:24 +02:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
/*
|
|
|
|
|
ATAPI device, direct-access device, removable media, interrupt DRQ:
|
2018-10-10 22:33:24 +02:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
Using (2 << 5) below makes the ASUS P/I-P54TP4XE misdentify the RDISK drive
|
2025-01-28 16:26:28 +01:00
|
|
|
as a LS-120.
|
|
|
|
|
*/
|
2018-10-30 13:32:25 +01:00
|
|
|
ide->buffer[0] = 0x8000 | (0 << 8) | 0x80 | (1 << 5);
|
2025-01-28 16:26:28 +01:00
|
|
|
ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */
|
|
|
|
|
ide->buffer[49] = 0x200; /* LBA supported */
|
|
|
|
|
/* Interpret zero byte count limit as maximum length */
|
|
|
|
|
ide->buffer[126] = 0xfffe;
|
2018-10-10 22:33:24 +02:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
if (rdisk_drives[rdisk->id].type == RDISK_TYPE_ZIP_250)
|
|
|
|
|
rdisk_zip_250_identify(ide, ide_has_dma);
|
|
|
|
|
else if (rdisk_drives[rdisk->id].type == RDISK_TYPE_ZIP_100)
|
|
|
|
|
rdisk_zip_100_identify(ide);
|
2018-10-10 22:33:24 +02:00
|
|
|
else
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_generic_identify(ide, ide_has_dma, rdisk);
|
2018-10-10 22:33:24 +02:00
|
|
|
}
|
|
|
|
|
|
2018-10-19 19:10:12 +02:00
|
|
|
static void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_drive_reset(const int c)
|
2018-10-10 22:33:24 +02:00
|
|
|
{
|
2025-07-25 16:30:40 +02:00
|
|
|
const uint8_t scsi_bus = (rdisk_drives[c].scsi_device_id >> 4) & 0x0f;
|
|
|
|
|
const uint8_t scsi_id = rdisk_drives[c].scsi_device_id & 0x0f;
|
2025-01-28 16:26:28 +01:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
if (rdisk_drives[c].priv == NULL) {
|
|
|
|
|
rdisk_drives[c].priv = (rdisk_t *) calloc(1, sizeof(rdisk_t));
|
|
|
|
|
rdisk_t *dev = (rdisk_t *) rdisk_drives[c].priv;
|
2018-10-10 22:33:24 +02:00
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
char n[1024] = { 0 };
|
|
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
sprintf(n, "Removable Disk %i", c + 1);
|
2025-01-28 16:26:28 +01:00
|
|
|
dev->log = log_open(n);
|
2018-10-10 22:33:24 +02:00
|
|
|
}
|
|
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_t *dev = (rdisk_t *) rdisk_drives[c].priv;
|
2018-10-26 04:47:21 +02:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
dev->id = c;
|
2021-03-23 06:32:18 +01:00
|
|
|
dev->cur_lun = SCSI_LUN_USE_CDB;
|
2018-10-10 22:33:24 +02:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
if (rdisk_drives[c].bus_type == RDISK_BUS_SCSI) {
|
2025-01-28 16:26:28 +01:00
|
|
|
if (dev->tf == NULL)
|
2023-10-28 22:00:23 +02:00
|
|
|
dev->tf = (ide_tf_t *) calloc(1, sizeof(ide_tf_t));
|
|
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
/* SCSI RDISK, attach to the SCSI bus. */
|
2025-01-28 16:26:28 +01:00
|
|
|
scsi_device_t *sd = &scsi_devices[scsi_bus][scsi_id];
|
2022-09-18 17:13:50 -04:00
|
|
|
|
|
|
|
|
sd->sc = (scsi_common_t *) dev;
|
2025-07-25 16:30:40 +02:00
|
|
|
sd->command = rdisk_command;
|
|
|
|
|
sd->request_sense = rdisk_request_sense_for_scsi;
|
|
|
|
|
sd->reset = rdisk_reset;
|
|
|
|
|
sd->phase_data_out = rdisk_phase_data_out;
|
|
|
|
|
sd->command_stop = rdisk_command_stop;
|
2022-09-18 17:13:50 -04:00
|
|
|
sd->type = SCSI_REMOVABLE_DISK;
|
2025-07-25 16:30:40 +02:00
|
|
|
} else if (rdisk_drives[c].bus_type == RDISK_BUS_ATAPI) {
|
2022-09-18 17:13:50 -04:00
|
|
|
/* ATAPI CD-ROM, attach to the IDE bus. */
|
2025-07-25 16:30:40 +02:00
|
|
|
ide_t *id = ide_get_drive(rdisk_drives[c].ide_channel);
|
2022-09-18 17:13:50 -04:00
|
|
|
/* If the IDE channel is initialized, we attach to it,
|
|
|
|
|
otherwise, we do nothing - it's going to be a drive
|
|
|
|
|
that's not attached to anything. */
|
|
|
|
|
if (id) {
|
|
|
|
|
id->sc = (scsi_common_t *) dev;
|
2023-10-28 22:00:23 +02:00
|
|
|
dev->tf = id->tf;
|
|
|
|
|
IDE_ATAPI_IS_EARLY = 0;
|
2025-07-25 16:30:40 +02:00
|
|
|
id->get_max = rdisk_get_max;
|
|
|
|
|
id->get_timings = rdisk_get_timings;
|
|
|
|
|
id->identify = rdisk_identify;
|
2022-09-18 17:13:50 -04:00
|
|
|
id->stop = NULL;
|
2025-07-25 16:30:40 +02:00
|
|
|
id->packet_command = rdisk_command;
|
|
|
|
|
id->device_reset = rdisk_reset;
|
|
|
|
|
id->phase_data_out = rdisk_phase_data_out;
|
|
|
|
|
id->command_stop = rdisk_command_stop;
|
|
|
|
|
id->bus_master_error = rdisk_bus_master_error;
|
2022-09-18 17:13:50 -04:00
|
|
|
id->interrupt_drq = 1;
|
|
|
|
|
|
|
|
|
|
ide_atapi_attach(id);
|
|
|
|
|
}
|
2018-10-10 22:33:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-26 22:17:09 +01:00
|
|
|
void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_hard_reset(void)
|
2018-01-26 22:17:09 +01:00
|
|
|
{
|
2025-07-25 16:30:40 +02:00
|
|
|
for (uint8_t c = 0; c < RDISK_NUM; c++) {
|
|
|
|
|
if ((rdisk_drives[c].bus_type == RDISK_BUS_ATAPI) || (rdisk_drives[c].bus_type == RDISK_BUS_SCSI)) {
|
2018-04-25 23:51:13 +02:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
if (rdisk_drives[c].bus_type == RDISK_BUS_SCSI) {
|
|
|
|
|
const uint8_t scsi_bus = (rdisk_drives[c].scsi_device_id >> 4) & 0x0f;
|
|
|
|
|
const uint8_t scsi_id = rdisk_drives[c].scsi_device_id & 0x0f;
|
2021-07-22 20:13:44 +02:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
/* Make sure to ignore any SCSI RDISK drive that has an out of range SCSI bus. */
|
2022-09-18 17:13:50 -04:00
|
|
|
if (scsi_bus >= SCSI_BUS_MAX)
|
|
|
|
|
continue;
|
2021-07-22 20:13:44 +02:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
/* Make sure to ignore any SCSI RDISK drive that has an out of range ID. */
|
2022-09-18 17:13:50 -04:00
|
|
|
if (scsi_id >= SCSI_ID_MAX)
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2018-10-10 22:33:24 +02:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
/* Make sure to ignore any ATAPI RDISK drive that has an out of range IDE channel. */
|
|
|
|
|
if ((rdisk_drives[c].bus_type == RDISK_BUS_ATAPI) && (rdisk_drives[c].ide_channel > 7))
|
2022-09-18 17:13:50 -04:00
|
|
|
continue;
|
2018-10-10 22:33:24 +02:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_drive_reset(c);
|
2018-04-25 23:51:13 +02:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_t *dev = (rdisk_t *) rdisk_drives[c].priv;
|
2025-01-28 16:26:28 +01:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_log(dev->log, "Removable Disk hard_reset drive=%d\n", c);
|
2018-10-26 04:47:21 +02:00
|
|
|
|
2023-11-10 22:53:56 +01:00
|
|
|
if (dev->tf == NULL)
|
|
|
|
|
continue;
|
|
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
dev->id = c;
|
2025-07-25 16:30:40 +02:00
|
|
|
dev->drv = &rdisk_drives[c];
|
2018-07-15 01:41:53 +02:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_init(dev);
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
if (strlen(rdisk_drives[c].image_path))
|
|
|
|
|
rdisk_load(dev, rdisk_drives[c].image_path, 0);
|
2018-03-17 20:32:20 +01:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_mode_sense_load(dev);
|
2018-10-10 22:33:24 +02:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
if (rdisk_drives[c].bus_type == RDISK_BUS_SCSI)
|
|
|
|
|
rdisk_log(dev->log, "SCSI RDISK drive %i attached to SCSI ID %i\n",
|
|
|
|
|
c, rdisk_drives[c].scsi_device_id);
|
|
|
|
|
else if (rdisk_drives[c].bus_type == RDISK_BUS_ATAPI)
|
|
|
|
|
rdisk_log(dev->log, "ATAPI RDISK drive %i attached to IDE channel %i\n",
|
|
|
|
|
c, rdisk_drives[c].ide_channel);
|
2022-09-18 17:13:50 -04:00
|
|
|
}
|
2018-01-26 22:17:09 +01:00
|
|
|
}
|
|
|
|
|
}
|
2018-07-15 01:41:53 +02:00
|
|
|
|
|
|
|
|
void
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_close(void)
|
2018-07-15 01:41:53 +02:00
|
|
|
{
|
2025-07-25 16:30:40 +02:00
|
|
|
for (uint8_t c = 0; c < RDISK_NUM; c++) {
|
|
|
|
|
if (rdisk_drives[c].bus_type == RDISK_BUS_SCSI) {
|
|
|
|
|
const uint8_t scsi_bus = (rdisk_drives[c].scsi_device_id >> 4) & 0x0f;
|
|
|
|
|
const uint8_t scsi_id = rdisk_drives[c].scsi_device_id & 0x0f;
|
2021-07-22 20:13:44 +02:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
memset(&scsi_devices[scsi_bus][scsi_id], 0x00, sizeof(scsi_device_t));
|
|
|
|
|
}
|
2020-06-14 21:59:45 +02:00
|
|
|
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_t *dev = (rdisk_t *) rdisk_drives[c].priv;
|
2018-07-15 01:41:53 +02:00
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
if (dev) {
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_disk_unload(dev);
|
2018-07-15 01:41:53 +02:00
|
|
|
|
2023-10-28 22:00:23 +02:00
|
|
|
if (dev->tf)
|
|
|
|
|
free(dev->tf);
|
|
|
|
|
|
2025-01-28 16:26:28 +01:00
|
|
|
if (dev->log != NULL) {
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_log(dev->log, "Log closed\n");
|
2025-01-28 16:26:28 +01:00
|
|
|
|
|
|
|
|
log_close(dev->log);
|
|
|
|
|
dev->log = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-18 17:13:50 -04:00
|
|
|
free(dev);
|
2025-07-25 16:30:40 +02:00
|
|
|
rdisk_drives[c].priv = NULL;
|
2022-09-18 17:13:50 -04:00
|
|
|
}
|
2018-07-15 01:41:53 +02:00
|
|
|
}
|
|
|
|
|
}
|