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
- 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
write cache

View File

@ -66,5 +66,5 @@ Users have reported success on these systems:
Roland JS-30 Sampler
Akai S1000, S3200, S3000XL, MPC 2000XL, DPS 12
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

View File

@ -18,6 +18,7 @@
#include "device.h"
#include "scsi.h"
#include "scsiPhy.h"
#include "config.h"
#include "disk.h"
#include "sd.h"
@ -38,11 +39,69 @@ static int doSdInit()
return result;
}
static void doFormatUnit()
// Callback once all data has been read in the data out phase.
static void doFormatUnitComplete(void)
{
// Low-level formatting is not required.
// Nothing left to do.
// TODO start writing the initialisation pattern to the SD
// 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()
@ -240,7 +299,22 @@ int scsiDiskCommand()
else if (command == 0x04)
{
// 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)
{

View File

@ -281,8 +281,12 @@ static void process_Command()
{
// REQUEST SENSE
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[2] = scsiDev.sense.code & 0x0F;
@ -292,23 +296,12 @@ static void process_Command()
scsiDev.data[6] = transfer.lba;
// 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[12] = scsiDev.sense.asc >> 8;
scsiDev.data[13] = scsiDev.sense.asc;
}
scsiDev.data[7] = 10; // additional length
scsiDev.data[12] = scsiDev.sense.asc >> 8;
scsiDev.data[13] = scsiDev.sense.asc;
// Silently truncate results. SCSI-2 spec 8.2.14.
enter_DataIn(
(allocLength < responseLength) ? allocLength : responseLength
);
enter_DataIn(allocLength);
// This is a good time to clear out old sense information.
scsiDev.sense.code = NO_SENSE;