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.cpp311
1 files changed, 255 insertions, 56 deletions
diff --git a/src/devices/machine/nscsi_bus.cpp b/src/devices/machine/nscsi_bus.cpp
index c2274f49c95..d1fa9a1265d 100644
--- a/src/devices/machine/nscsi_bus.cpp
+++ b/src/devices/machine/nscsi_bus.cpp
@@ -3,15 +3,19 @@
#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)
#define LOG_DATA (1U << 4)
#define LOG_DATA_SENT (1U << 5)
-//#define VERBOSE (LOG_GENERAL | LOG_STATE | LOG_CONTROL | LOG_DATA)
#define VERBOSE (LOG_UNSUPPORTED)
+//#define LOG_OUTPUT_FUNC osd_printf_info
#include "logmacro.h"
@@ -76,16 +80,16 @@ void nscsi_bus_device::regen_ctrl(int refid)
data);
for(int i=0; i<devcnt; i++)
if(dev[i].ctrl) {
- LOGMASKED(LOG_CONTROL, "%d=%s%s%s%s%s%s%s%s%s\n", i,
+ LOGMASKED(LOG_CONTROL, "dev%d=%s%s%s%s%s%s%s%s%s\n", i,
dev[i].ctrl & nscsi_device::S_RST ? "R" : "",
dev[i].ctrl & nscsi_device::S_ATN ? "A" : "",
dev[i].ctrl & nscsi_device::S_ACK ? "K" : "",
dev[i].ctrl & nscsi_device::S_REQ ? "Q" : "",
+ dev[i].ctrl & nscsi_device::S_SEL ? "S" : "",
+ dev[i].ctrl & nscsi_device::S_BSY ? "B" : "",
dev[i].ctrl & nscsi_device::S_MSG ? "M" : "",
- dev[i].ctrl & nscsi_device::S_INP ? "I" : "",
dev[i].ctrl & nscsi_device::S_CTL ? "C" : "",
- dev[i].ctrl & nscsi_device::S_SEL ? "S" : "",
- dev[i].ctrl & nscsi_device::S_BSY ? "B" : "");
+ dev[i].ctrl & nscsi_device::S_INP ? "I" : "");
}
}
@@ -128,7 +132,7 @@ void nscsi_bus_device::ctrl_wait(int refid, uint32_t lines, uint32_t mask)
void nscsi_bus_device::device_resolve_objects()
{
for(int i=0; i<16; i++) {
- device_t *subdev = subdevice(string_format("%d", i).c_str());
+ device_t *subdev = subdevice(string_format("%d", i));
nscsi_device *sdev = subdev ? downcast<nscsi_connector &>(*subdev).get_device() : nullptr;
if(sdev) {
int rid = devcnt++;
@@ -141,7 +145,7 @@ void nscsi_bus_device::device_resolve_objects()
nscsi_connector::nscsi_connector(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, NSCSI_CONNECTOR, tag, owner, clock),
- device_slot_interface(mconfig, *this)
+ device_single_card_slot_interface<nscsi_slot_card_interface>(mconfig, *this)
{
}
@@ -149,20 +153,13 @@ nscsi_connector::~nscsi_connector()
{
}
-void nscsi_connector::device_validity_check(validity_checker &valid) const
-{
- device_t *const carddev = get_card_device();
- if (carddev && !dynamic_cast<nscsi_slot_card_interface *>(carddev))
- osd_printf_error("Card device %s (%s) does not implement nscsi_slot_card_interface\n", carddev->tag(), carddev->name());
-}
-
void nscsi_connector::device_start()
{
}
nscsi_device *nscsi_connector::get_device()
{
- nscsi_slot_card_interface *connected = dynamic_cast<nscsi_slot_card_interface *>(get_card_device());
+ nscsi_slot_card_interface *const connected = get_card_device();
if (connected)
return connected->device().subdevice<nscsi_device>(connected->m_nscsi.finder_tag());
else
@@ -170,7 +167,7 @@ nscsi_device *nscsi_connector::get_device()
}
nscsi_slot_card_interface::nscsi_slot_card_interface(const machine_config &mconfig, device_t &device, const char *nscsi_tag) :
- device_slot_card_interface(mconfig, device),
+ device_interface(device, "nscsi"),
m_nscsi(device, nscsi_tag)
{
}
@@ -206,27 +203,27 @@ 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", "?", "?", "?",
- /* 88 */ "?", "?", "?", "?", "?", "?", "?", "?",
- /* 90 */ "?", "?", "?", "?", "?", "?", "?", "?",
- /* 98 */ "?", "?", "?", "?", "?", "?", "?", "?",
+ /* 88 */ "?", "?", "WRITE_16", "?", "?", "?", "?", "?",
+ /* 90 */ "?", "SYNCHRONIZE_CACHE_16", "?", "WRITE_SAME_16", "?", "?", "?", "?",
+ /* 98 */ "?", "?", "?", "?", "?", "?", "READ_CAPACITY_166/READ_LONG_16", "WRITE_LONG_16",
/* a0 */ "REPORT_LUNS", "BLANK", "SEND_EVENT", "REPORT_DEVICE_IDENTIFIER/SEND_KEY", "SET_DEVICE_IDENTIFIER/REPORT_KEY", "PLAY_AUDIO_12", "LOAD_UNLOAD_MEDIUM", "MOVE_MEDIUM_ATTACHED/SET_READ_AHEAD",
/* a8 */ "READ_12", "PLAY_RELATIVE_12", "WRITE_12", "?", "ERASE_12/GET_PERFORMANCE", "READ_DVD_STRUCTURE", "WRITE_AND_VERIFY_12", "VERIFY_12",
/* b0 */ "SEARCH_DATA_HIGH_12", "SEARCH_DATA_EQUAL_12", "SEARCH_DATA_LOW_12", "SET_LIMITS_12", "READ_ELEMENT_STATUS_ATTACHED", "?", "SET_STREAMING", "READ_DEFECT_DATA_12",
- /* b8 */ "?", "READ_CD_MSF", "SCAN_MMC", "SET_CD_SPEED", "PLAY_CD", "MECHANISM_STATUS", "READ_CD", "SEND_DVD_STRUCTURE",
+ /* b8 */ "?", "READ_CD_MSF", "SCAN_MMC", "SET_CD_SPEED", "PLAY_CD/SPARE_IN", "MECHANISM_STATUS/SPARE_OUT", "READ_CD", "SEND_DVD_STRUCTURE",
/* c0 */ "?", "?", "?", "?", "?", "?", "?", "?",
/* c8 */ "?", "?", "?", "?", "?", "?", "?", "?",
/* d0 */ "?", "?", "?", "?", "?", "?", "?", "?",
@@ -240,7 +237,7 @@ const char *const nscsi_full_device::command_names[256] = {
void nscsi_full_device::device_start()
{
nscsi_device::device_start();
- scsi_timer = timer_alloc(SCSI_TIMER);
+ scsi_timer = timer_alloc(FUNC(nscsi_full_device::update_tick), this);
save_item(NAME(scsi_cmdbuf));
save_item(NAME(scsi_sense_buffer));
save_item(NAME(scsi_cmdsize));
@@ -270,15 +267,12 @@ void nscsi_full_device::device_reset()
scsi_bus->data_w(scsi_refid, 0);
scsi_bus->ctrl_w(scsi_refid, 0, S_ALL);
scsi_bus->ctrl_wait(scsi_refid, S_SEL|S_BSY|S_RST, S_ALL);
+ sense(false, SK_NO_SENSE);
}
-void nscsi_full_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(nscsi_full_device::update_tick)
{
- if(id != SCSI_TIMER)
- return;
-
- step(true);
-
+ step(param);
}
void nscsi_full_device::scsi_ctrl_changed()
@@ -295,6 +289,11 @@ void nscsi_full_device::step(bool timeout)
scsi_bus->ctrl_w(scsi_refid, 0, S_ALL);
scsi_state = IDLE;
LOG("scsi bus reset\n");
+ scsi_state = scsi_substate = IDLE;
+ buf_control_rpos = buf_control_wpos = 0;
+ scsi_identify = 0;
+ data_buffer_size = 0;
+ data_buffer_pos = 0;
return;
}
@@ -309,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;
@@ -341,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;
@@ -357,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;
@@ -465,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;
@@ -518,7 +532,7 @@ void nscsi_full_device::scsi_put_data(int id, int pos, uint8_t data)
scsi_sense_buffer[pos] = data;
break;
default:
- fatalerror("nscsi_full_device::scsi_put_data - unknown id\n");
+ fatalerror("nscsi_full_device::scsi_put_data - unknown id %d\n", id);
}
}
@@ -539,14 +553,16 @@ bool nscsi_full_device::scsi_command_done(uint8_t command, uint8_t length)
case 4: return true;
case 5: return length == 12;
case 6: return true;
- case 7: return true;
+ case 7: return length == 32;
+ case 8: return length == 16;
+ case 9: return length == 16;
}
return true;
}
nscsi_full_device::control *nscsi_full_device::buf_control_push()
{
- if(buf_control_wpos == int(ARRAY_LENGTH(buf_control)))
+ if(buf_control_wpos == int(std::size(buf_control)))
throw emu_fatalerror("%s: buf_control overflow\n", tag());
control *c = buf_control + buf_control_wpos;
@@ -608,16 +624,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);
@@ -631,18 +802,34 @@ void nscsi_full_device::scsi_unknown_command()
void nscsi_full_device::scsi_command()
{
- switch(scsi_cmdbuf[0]) {
- 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);
+ 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:
+ handle_request_sense(lun);
+ break;
default:
scsi_unknown_command();
break;
}
}
+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) {
@@ -715,7 +902,7 @@ attotime nscsi_full_device::scsi_cable_skew_delay()
// Data release delay (400ns)
attotime nscsi_full_device::scsi_data_release_delay()
{
- return attotime::from_nsec(40);
+ return attotime::from_nsec(400);
}
// Deskew delay (45ns)
@@ -789,3 +976,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;
+}