summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/nscsi_bus.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/nscsi_bus.cpp')
-rw-r--r--src/devices/machine/nscsi_bus.cpp254
1 files changed, 226 insertions, 28 deletions
diff --git a/src/devices/machine/nscsi_bus.cpp b/src/devices/machine/nscsi_bus.cpp
index eeaf2c2722a..1f95b670c44 100644
--- a/src/devices/machine/nscsi_bus.cpp
+++ b/src/devices/machine/nscsi_bus.cpp
@@ -3,7 +3,11 @@
#include "emu.h"
#include "nscsi_bus.h"
-#define LOG_GENERAL (1U << 0)
+#include "util/multibyte.h"
+
+#include <cassert>
+#include <cstring>
+
#define LOG_UNSUPPORTED (1U << 1)
#define LOG_STATE (1U << 2)
#define LOG_CONTROL (1U << 3)
@@ -199,17 +203,17 @@ nscsi_full_device::nscsi_full_device(const machine_config &mconfig, device_type
}
const char *const nscsi_full_device::command_names[256] = {
- /* 00 */ "TEST_UNIT_READY", "REZERO", "?", "REQUEST_SENSE", "FORMAT_UNIT", "?", "?", "REASSIGN_BLOCKS",
- /* 08 */ "READ_6/RECIEVE", "?", "WRITE_6/SEND", "SEEK", "?", "?", "?", "?",
- /* 10 */ "?", "?", "INQUIRY", "?", "?", "MODE_SELECT_6", "RESERVE_6", "RELEASE_6",
- /* 18 */ "?", "?", "MODE_SENSE_6", "START_STOP_UNIT", "RECIEVE_DIAG_RES", "SEND_DIAGNOSTICS", "PREVENT_ALLOW_MEDIUM_REMOVAL", "?",
- /* 20 */ "?", "?", "?", "READ_FORMAT_CAPACITIES", "?", "READ_CAPACITY", "?", "?",
-
- /* 28 */ "READ_10", "READ_GENERATION", "WRITE_10", "SEEK_10", "ERASE_10", "READ_UPDATED_BLOCK_10", "WRITE_VERIFY", "VERIFY",
- /* 30 */ "SEARCH_DATA_HIGH_10", "SEARCH_DATA_EQUAL_10", "SEARCH_DATA_LOW_10", "SET_LIMITS_10", "PREFETCH", "SYNC_CACHE", "LOCK_UNLOCK_CACHE", "READ_DEFECT_DATA",
- /* 38 */ "MEDIUM_SCAN", "COMPARE", "COPY_AND_VERIFY", "WRITE_BUFFER", "READ_DATA_BUFFER", "UPDATE_BLOCK", "READ_LONG", "WRITE_LONG",
+ /* 00 */ "TEST_UNIT_READY", "REWIND/REZERO_UNIT", "REQUEST_BLOCK_ADDRESS", "REQUEST_SENSE", "FORMAT/FORMAT_UNIT", "READ_BLOCK_LIMITS", "?", "INITIALIZE_ELEMENT_STATUS/REASSIGN_BLOCKS",
+ /* 08 */ "GET_MESSAGE_6/READ_6/RECEIVE", "?", "PRINT/SEND_MESSAGE_6/SEND_6/WRITE_6", "SEEK_6/SLEW_AND_PRINT", "SEEK_BLOCK", "?", "?", "READ_REVERSE",
+ /* 10 */ "SYNCHRONIZE_BUFFER/WRITE_FILEMARKS", "SPACE", "INQUIRY", "VERIFY_6", "RECOVER_BUFFERED_DATA", "MODE_SELECT_6", "RESERVE_6/RESERVE_UNIT", "RELEASE_6/RELEASE_UNIT",
+ /* 18 */ "COPY", "ERASE", "MODE_SENSE_6", "LOAD_UNLOAD/SCAN/STOP_PRINT/START_STOP_UNIT", "RECEIVE_DIAGNOSTIC_RESULTS", "SEND_DIAGNOSTIC", "PREVENT_ALLOW_MEDIUM_REMOVAL", "?",
+ /* 20 */ "?", "?", "?", "READ_FORMAT_CAPACITIES", "SET_WINDOW", "GET_WINDOW/READ_CAPACITY/READ_CD_RECORDED_CAPACITY", "?", "?",
+
+ /* 28 */ "GET_MESSAGE_10/READ_10", "READ_GENERATION", "SEND_MESSAGE_10/SEND_10/WRITE_10", "LOCATE/POSITION_TO_ELEMENT/SEEK_10", "ERASE_10", "READ_UPDATED_BLOCK", "WRITE_AND_VERIFY_10", "VERIFY_10",
+ /* 30 */ "SEARCH_DATA_HIGH_10", "OBJECT_POSITION/SEARCH_DATA_EQUAL_10", "SEARCH_DATA_LOW_10", "SET_LIMITS_10", "PREFETCH/READ_POSITION", "SYNCHRONIZE_CACHE", "LOCK_UNLOCK_CACHE", "READ_DEFECT_DATA_10",
+ /* 38 */ "MEDIUM_SCAN", "COMPARE", "COPY_AND_VERIFY", "WRITE_BUFFER", "READ_BUFFER", "UPDATE_BLOCK", "READ_LONG", "WRITE_LONG",
/* 40 */ "CHANGE_DEFINITION", "WRITE_SAME", "READ_SUB_CHANNEL", "READ_TOC_PMA_ATIP", "READ_HEADER", "PLAY_AUDIO_10", "GET_CONFIGURATION", "PLAY_AUDIO_MSF",
- /* 48 */ "PLAY_AUDIO_TRACK_INDEX", "PLAY_RELATIVE_10", "GET_EVENT_STATUS_NOTIFICATION", "PAUSE_RESUME", "LOG_SELECT", "LOG_SENSE", "STOP_PLAY_SCAN", "?",
+ /* 48 */ "PLAY_AUDIO_TRACK_INDEX", "PLAY_TRACK_RELATIVE_10", "GET_EVENT_STATUS_NOTIFICATION", "PAUSE_RESUME", "LOG_SELECT", "LOG_SENSE", "STOP_PLAY_SCAN", "?",
/* 50 */ "XDWRITE", "READ_DISC_INFORMATION/XPWRITE", "READ_TRACK_INFORMATION/XDREAD", "RESERVE_TRACK", "SEND_OPC_INFORMATION", "MODE_SELECT_10", "RESERVE_10", "RELEASE_10",
/* 58 */ "REPAIR_TRACK", "READ_MASTER_CUE", "MODE_SENSE_10", "CLOSE_TRACK_SESSION", "READ_BUFFER_CAPACITY", "SEND_CUE_SHEET", "PERSISTENT_RESERVE_IN", "PERSISTENT_RESERVE_OUT",
/* 80 */ "XDWRITE_EXTENDED", "REBUILD", "REGENERATE", "EXTENDED_COPY", "RECEIVE_COPY_RESULTS", "?", "?", "?",
@@ -268,7 +272,7 @@ void nscsi_full_device::device_reset()
TIMER_CALLBACK_MEMBER(nscsi_full_device::update_tick)
{
- step(true);
+ step(param);
}
void nscsi_full_device::scsi_ctrl_changed()
@@ -304,7 +308,7 @@ void nscsi_full_device::step(bool timeout)
if(scsi_initiator_id == 16)
scsi_initiator_id = -1;
scsi_state = TARGET_SELECT_WAIT_BUS_SETTLE;
- scsi_timer->adjust(scsi_bus_settle_delay());
+ scsi_timer->adjust(scsi_bus_settle_delay(), true);
}
break;
@@ -336,7 +340,12 @@ void nscsi_full_device::step(bool timeout)
if(!(ctrl & S_ACK)) {
scsi_state &= STATE_MASK;
scsi_bus->ctrl_wait(scsi_refid, 0, S_ACK);
- step(false);
+ attotime delay = scsi_data_byte_period();
+ if (delay == attotime::zero) {
+ step(false);
+ } else {
+ scsi_timer->adjust(delay, false);
+ }
}
break;
@@ -352,7 +361,12 @@ void nscsi_full_device::step(bool timeout)
if(!(ctrl & S_ACK)) {
scsi_state &= STATE_MASK;
scsi_bus->ctrl_wait(scsi_refid, 0, S_ACK);
- step(false);
+ attotime delay = scsi_data_byte_period();
+ if (delay == attotime::zero) {
+ step(false);
+ } else {
+ scsi_timer->adjust(delay, false);
+ }
}
break;
@@ -460,7 +474,12 @@ void nscsi_full_device::step(bool timeout)
scsi_bus->ctrl_wait(scsi_refid, 0, S_ACK);
scsi_command();
scsi_state = TARGET_NEXT_CONTROL;
- step(false);
+ attotime delay = scsi_data_command_delay();
+ if (delay == attotime::zero) {
+ step(false);
+ } else {
+ scsi_timer->adjust(delay, false);
+ }
} else
target_recv_byte();
break;
@@ -603,16 +622,171 @@ void nscsi_full_device::scsi_data_out(int buf, int size)
c->param2 = size;
}
+//////////////////////////////////////////////////////////////////////////////
+
+void nscsi_full_device::set_sense_data(const u8 sense_key, const u16 sense_key_code, const sense_data *data)
+{
+ assert(sizeof(scsi_sense_buffer) >= 18);
+ assert(sense_key <= 0x0f);
+ memset(scsi_sense_buffer, 0, 18);
+ if (data) {
+ scsi_sense_buffer[0] = (data->invalid ? 0 : 0x80) // even though SCSI-2 section 8.2.14 implies valid bit should always be set, other sections such as 10.2.12 disagree!
+ | (data->deferred ? 0x71 : 0x70);
+ scsi_sense_buffer[2] = (data->filemark ? 0x80 : 0)
+ | (data->eom ? 0x40 : 0)
+ | (data->bad_len ? 0x20 : 0); // "incorrect length indicator"
+ put_s32be(&scsi_sense_buffer[3], data->info);
+ }
+ else
+ scsi_sense_buffer[0] = 0xf0;
+ scsi_sense_buffer[2] |= sense_key;
+ scsi_sense_buffer[7] = 10; // additional sense length
+ put_u16be(&scsi_sense_buffer[12], sense_key_code);
+}
+
void nscsi_full_device::sense(bool deferred, uint8_t key, uint8_t asc, uint8_t ascq)
{
- memset(scsi_sense_buffer, 0, sizeof(scsi_sense_buffer));
- scsi_sense_buffer[0] = deferred ? 0x71 : 0x70;
- scsi_sense_buffer[2] = key;
- scsi_sense_buffer[7] = sizeof(scsi_sense_buffer) - 8;
- scsi_sense_buffer[12] = asc;
- scsi_sense_buffer[13] = ascq;
+ sense_data s;
+ s.deferred = deferred;
+ set_sense_data(key, (asc << 8) | ascq, &s);
+}
+
+void nscsi_full_device::report_condition(const u8 sense_key, const u16 sense_key_code, const sense_data *data)
+{
+ set_sense_data(sense_key, sense_key_code, data);
+ scsi_status_complete(SS_CHECK_CONDITION);
+}
+
+void nscsi_full_device::report_bad_lun(const u8 cmd, const u8 lun)
+{
+ LOG("%s (0x%02x) lun=%d\n *** BAD LUN\n", command_names[cmd], cmd, lun);
+ report_condition(SK_ILLEGAL_REQUEST, SKC_LOGICAL_UNIT_NOT_SUPPORTED);
+}
+
+void nscsi_full_device::report_bad_cmd(const u8 cmd)
+{
+ LOG("%s (0x%02x)\n *** BAD COMMAND\n", command_names[cmd], cmd);
+ report_condition(SK_ILLEGAL_REQUEST, SKC_INVALID_COMMAND_OPERATION_CODE);
+}
+
+void nscsi_full_device::report_filemark(const s32 info, const bool eom)
+{
+ LOG(" *** FILEMARK info=%d\n", info);
+ sense_data s;
+ s.filemark = true;
+ s.eom = eom;
+ s.info = info;
+ report_condition(SK_NO_SENSE, SKC_FILEMARK_DETECTED, &s);
+}
+
+void nscsi_full_device::report_bom(const s32 info)
+{
+ LOG(" *** BOM info=%d\n", info);
+ sense_data s;
+ s.eom = true;
+ s.info = info;
+ report_condition(SK_NO_SENSE, SKC_BEGINNING_OF_PARTITION_MEDIUM_DETECTED, &s);
}
+void nscsi_full_device::report_ew(const s32 info)
+{
+ LOG(" EW info=%d\n", info);
+ sense_data s;
+ s.eom = true;
+ s.info = info;
+ report_condition(SK_NO_SENSE, SKC_END_OF_PARTITION_MEDIUM_DETECTED, &s);
+}
+
+void nscsi_full_device::report_eod(const s32 info, const bool eom)
+{
+ LOG(" *** EOD info=%d\n", info);
+ sense_data s;
+ s.eom = eom;
+ s.info = info;
+ report_condition(SK_BLANK_CHECK, SKC_END_OF_DATA_DETECTED, &s);
+}
+
+void nscsi_full_device::report_eom(const bool write, const s32 info, const bool invalid)
+{
+ LOG(" *** EOM info=%d invalid=%d\n", info, invalid);
+ sense_data s;
+ s.invalid = invalid;
+ s.eom = true;
+ s.info = info;
+ report_condition(write ? SK_VOLUME_OVERFLOW : SK_MEDIUM_ERROR, SKC_END_OF_PARTITION_MEDIUM_DETECTED, &s);
+}
+
+void nscsi_full_device::report_bad_len(const bool over, const s32 info)
+{
+ LOG(" *** %sLENGTH BLOCK info=%d\n", over ? "OVER" : "UNDER", info);
+ sense_data s;
+ s.bad_len = true;
+ s.info = info;
+ report_condition(SK_ILLEGAL_REQUEST, SKC_NO_ADDITIONAL_SENSE_INFORMATION, &s);
+}
+
+void nscsi_full_device::report_bad_cdb_field()
+{
+ LOG(" *** BAD CDB FIELD\n");
+ report_condition(SK_ILLEGAL_REQUEST, SKC_INVALID_FIELD_IN_CDB);
+}
+
+void nscsi_full_device::report_bad_pl_field()
+{
+ LOG(" *** BAD PARAMETER LIST FIELD\n");
+ report_condition(SK_ILLEGAL_REQUEST, SKC_INVALID_FIELD_IN_PARAMETER_LIST);
+}
+
+void nscsi_full_device::report_bad_pl_len()
+{
+ LOG(" *** BAD PARAMETER LIST LENGTH\n");
+ report_condition(SK_ILLEGAL_REQUEST, SKC_PARAMETER_LIST_LENGTH_ERROR);
+}
+
+void nscsi_full_device::report_no_saving_params()
+{
+ LOG(" *** NO SAVING PARAMETERS\n");
+ report_condition(SK_ILLEGAL_REQUEST, SKC_SAVING_PARAMETERS_NOT_SUPPORTED);
+}
+
+void nscsi_full_device::report_no_medium()
+{
+ LOG(" *** NO MEDIUM\n");
+ report_condition(SK_NOT_READY, SKC_MEDIUM_NOT_PRESENT);
+}
+
+void nscsi_full_device::report_medium_changed()
+{
+ LOG(" MEDIUM CHANGED\n");
+ report_condition(SK_UNIT_ATTENTION, SKC_NOT_READY_TO_READY_TRANSITION_MEDIUM_MAY_HAVE_CHANGED);
+}
+
+void nscsi_full_device::report_read_only()
+{
+ LOG(" *** READ ONLY\n");
+ report_condition(SK_DATA_PROTECT, SKC_WRITE_PROTECTED);
+}
+
+void nscsi_full_device::report_read_failure()
+{
+ LOG(" *** READ FAILURE\n");
+ report_condition(SK_MEDIUM_ERROR, SKC_UNRECOVERED_READ_ERROR);
+}
+
+void nscsi_full_device::report_write_failure()
+{
+ LOG(" *** WRITE FAILURE\n");
+ report_condition(SK_MEDIUM_ERROR, SKC_WRITE_ERROR);
+}
+
+void nscsi_full_device::report_erase_failure()
+{
+ LOG(" *** ERASE FAILURE\n");
+ report_condition(SK_MEDIUM_ERROR, SKC_ERASE_FAILURE);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
void nscsi_full_device::scsi_unknown_command()
{
std::string txt = util::string_format("Unhandled command %s (%d):", command_names[scsi_cmdbuf[0]], scsi_cmdsize);
@@ -626,15 +800,15 @@ void nscsi_full_device::scsi_unknown_command()
void nscsi_full_device::scsi_command()
{
- switch(scsi_cmdbuf[0]) {
- case SC_REZERO:
- LOG("command REZERO\n");
+ const u8 cmd = scsi_cmdbuf[0];
+ const u8 lun = get_lun(scsi_cmdbuf[1] >> 5); // LUN may be overridden by IDENTIFY, per SCSI-2 section 7.2.2
+ switch(cmd) {
+ case SC_REZERO_UNIT:
+ LOG("command REZERO UNIT\n");
scsi_status_complete(SS_GOOD);
break;
case SC_REQUEST_SENSE:
- LOG("command REQUEST SENSE alloc=%d\n", scsi_cmdbuf[4]);
- scsi_data_in(SBUF_SENSE, scsi_cmdbuf[4] ? std::min(scsi_cmdbuf[4], u8(sizeof(scsi_sense_buffer))) : 4);
- scsi_status_complete(SS_GOOD);
+ handle_request_sense(lun);
break;
default:
scsi_unknown_command();
@@ -642,6 +816,18 @@ void nscsi_full_device::scsi_command()
}
}
+void nscsi_full_device::handle_request_sense(const u8 lun) // mandatory; SCSI-2 section 8.2.14
+{
+ const u8 alloc_len = scsi_cmdbuf[4]; // allocation length
+ LOG("command REQUEST SENSE lun=%d alloc_len=%d\n", lun, alloc_len);
+ if ((scsi_cmdbuf[1] & 0x1f) || scsi_cmdbuf[2] || scsi_cmdbuf[3]) // error: reserved bits set
+ return report_bad_cdb_field();
+
+ assert(sizeof(scsi_sense_buffer) >= 18);
+ scsi_data_in(SBUF_SENSE, std::min(18, (const int)alloc_len));
+ scsi_status_complete(SS_GOOD);
+}
+
void nscsi_full_device::scsi_message()
{
if(scsi_cmdbuf[0] & 0x80) {
@@ -788,3 +974,15 @@ attotime nscsi_full_device::scsi_fast_negation_period()
{
return attotime::from_nsec(30);
}
+
+// Byte transfer rate (immediate)
+attotime nscsi_full_device::scsi_data_byte_period()
+{
+ return attotime::zero;
+}
+
+// Command execution delay (immediate)
+attotime nscsi_full_device::scsi_data_command_delay()
+{
+ return attotime::zero;
+}