Adding Ensoniq ASR-10 support and improved FORMAT UNIT command.

- Read the data-phase bytes during a FORMAT UNIT command
- Return the exact number of bytes requested for the REQUEST SENSE command
This commit is contained in:
Michael McMaster
2014-04-29 17:40:22 +10:00
parent 3762d59973
commit 767f12e481
4 changed files with 92 additions and 23 deletions

View File

@@ -1,5 +1,7 @@
201404?? 3.4 201404?? 3.4
- Fix to ensure SCSI phase bits are set atomically. - Fix to ensure SCSI phase bits are set atomically.
- Always return the requested number of bytes for a REQUEST SENSE command
This is required to support the Ensoniq ASR-10.
- Decreased (unused) heap and stack sizes to prepare for a memory - Decreased (unused) heap and stack sizes to prepare for a memory
write cache write cache

View File

@@ -66,5 +66,5 @@ Users have reported success on these systems:
Roland JS-30 Sampler Roland JS-30 Sampler
Akai S1000, S3200, S3000XL, MPC 2000XL, DPS 12 Akai S1000, S3200, S3000XL, MPC 2000XL, DPS 12
EMU Emulator E4X with EOS 3.00b and E6400 (classic) with Eos 4.01 EMU Emulator E4X with EOS 3.00b and E6400 (classic) with Eos 4.01
Ensoniq ASR-X Ensoniq ASR-X, ASR-10 (from v3.4, 2GB size limit)
HP 16601A logic analyzer HP 16601A logic analyzer

View File

@@ -18,6 +18,7 @@
#include "device.h" #include "device.h"
#include "scsi.h" #include "scsi.h"
#include "scsiPhy.h"
#include "config.h" #include "config.h"
#include "disk.h" #include "disk.h"
#include "sd.h" #include "sd.h"
@@ -38,11 +39,69 @@ static int doSdInit()
return result; return result;
} }
// Callback once all data has been read in the data out phase.
static void doFormatUnit() static void doFormatUnitComplete(void)
{ {
// Low-level formatting is not required. // TODO start writing the initialisation pattern to the SD
// Nothing left to do. // card
scsiDev.phase = STATUS;
}
static void doFormatUnitSkipData(int bytes)
{
// We may not have enough memory to store the initialisation pattern and
// defect list data. Since we're not making use of it yet anyway, just
// discard the bytes.
scsiEnterPhase(DATA_OUT);
int i;
for (i = 0; i < bytes; ++i)
{
scsiReadByte();
}
}
// Callback from the data out phase.
static void doFormatUnitPatternHeader(void)
{
int defectLength =
((((uint16_t)scsiDev.data[2])) << 8) +
scsiDev.data[3];
int patternLength =
((((uint16_t)scsiDev.data[4 + 2])) << 8) +
scsiDev.data[4 + 3];
doFormatUnitSkipData(defectLength + patternLength);
doFormatUnitComplete();
}
// Callback from the data out phase.
static void doFormatUnitHeader(void)
{
int IP = (scsiDev.data[1] & 0x08) ? 1 : 0;
int DSP = (scsiDev.data[1] & 0x04) ? 1 : 0;
if (! DSP) // disable save parameters
{
configSave(); // Save the "MODE SELECT savable parameters"
}
if (IP)
{
// We need to read the initialisation pattern header first.
scsiDev.dataLen += 4;
scsiDev.phase = DATA_OUT;
scsiDev.postDataOutHook = doFormatUnitPatternHeader;
}
else
{
// Read the defect list data
int defectLength =
((((uint16_t)scsiDev.data[2])) << 8) +
scsiDev.data[3];
doFormatUnitSkipData(defectLength);
doFormatUnitComplete();
}
} }
static void doReadCapacity() static void doReadCapacity()
@@ -240,7 +299,22 @@ int scsiDiskCommand()
else if (command == 0x04) else if (command == 0x04)
{ {
// FORMAT UNIT // FORMAT UNIT
doFormatUnit(); // We don't really do any formatting, but we need to read the correct
// number of bytes in the DATA_OUT phase to make the SCSI host happy.
int fmtData = (scsiDev.cdb[1] & 0x10) ? 1 : 0;
if (fmtData)
{
// We need to read the parameter list, but we don't know how
// big it is yet. Start with the header.
scsiDev.dataLen = 4;
scsiDev.phase = DATA_OUT;
scsiDev.postDataOutHook = doFormatUnitHeader;
}
else
{
// No data to read, we're already finished!
}
} }
else if (command == 0x08) else if (command == 0x08)
{ {

View File

@@ -281,8 +281,12 @@ static void process_Command()
{ {
// REQUEST SENSE // REQUEST SENSE
uint32 allocLength = scsiDev.cdb[4]; uint32 allocLength = scsiDev.cdb[4];
if (allocLength == 0) allocLength = 256;
memset(scsiDev.data, 0, 18); // As specified by the SASI and SCSI1 standard.
// Newer initiators won't be specifying 0 anyway.
if (allocLength == 0) allocLength = 4;
memset(scsiDev.data, 0, 256); // Max possible alloc length
scsiDev.data[0] = 0xF0; scsiDev.data[0] = 0xF0;
scsiDev.data[2] = scsiDev.sense.code & 0x0F; scsiDev.data[2] = scsiDev.sense.code & 0x0F;
@@ -292,23 +296,12 @@ static void process_Command()
scsiDev.data[6] = transfer.lba; scsiDev.data[6] = transfer.lba;
// Additional bytes if there are errors to report // Additional bytes if there are errors to report
int responseLength;
if (scsiDev.sense.code == NO_SENSE)
{
responseLength = 8;
}
else
{
responseLength = 18;
scsiDev.data[7] = 10; // additional length scsiDev.data[7] = 10; // additional length
scsiDev.data[12] = scsiDev.sense.asc >> 8; scsiDev.data[12] = scsiDev.sense.asc >> 8;
scsiDev.data[13] = scsiDev.sense.asc; scsiDev.data[13] = scsiDev.sense.asc;
}
// Silently truncate results. SCSI-2 spec 8.2.14. // Silently truncate results. SCSI-2 spec 8.2.14.
enter_DataIn( enter_DataIn(allocLength);
(allocLength < responseLength) ? allocLength : responseLength
);
// This is a good time to clear out old sense information. // This is a good time to clear out old sense information.
scsiDev.sense.code = NO_SENSE; scsiDev.sense.code = NO_SENSE;