Change default configuration to 2GB limit, no parity, no attention.

This commit is contained in:
Michael McMaster 2015-01-08 20:54:27 +10:00
parent 49c9b7d734
commit 64fed3d6b1
16 changed files with 346 additions and 94 deletions

View File

@ -1,4 +1,4 @@
20141223 4.0
20150108 4.0
- Fix handling requests for LUNs other than 0 from SCSI-2 hosts.
- Handle glitches of the scsi signals to improve stability and operate with
multiple devices on the SCSI bus.

View File

@ -20,21 +20,132 @@
#include "config.h"
#include "cdrom.h"
uint8_t SimpleTOC[] =
static const uint8_t SimpleTOC[] =
{
0x00, // toc length, MSB
0x0A, // toc length, LSB
0x12, // toc length, LSB
0x01, // First track number
0x01, // Last track number,
// TRACK 1 Descriptor
0x00, // reservied
0x06, // Q sub-channel not supplied, Digital track
0x00, // reserved
0x14, // Q sub-channel encodes current position, Digital track
0x01, // Track 1,
0x00, // Reserved
0x00,0x00,0x00,0x00 // Track start sector (LBA)
0x00,0x00,0x00,0x00, // Track start sector (LBA)
0x00, // reserved
0x14, // Q sub-channel encodes current position, Digital track
0xAA, // Leadout Track
0x00, // Reserved
0x00,0x00,0x00,0x00, // Track start sector (LBA)
};
void doReadTOC(int MSF, uint8_t track, uint16_t allocationLength)
static const uint8_t SessionTOC[] =
{
0x00, // toc length, MSB
0x0A, // toc length, LSB
0x01, // First session number
0x01, // Last session number,
// TRACK 1 Descriptor
0x00, // reserved
0x14, // Q sub-channel encodes current position, Digital track
0x01, // First track number in last complete session
0x00, // Reserved
0x00,0x00,0x00,0x00 // LBA of first track in last session
};
static const uint8_t FullTOC[] =
{
0x00, // toc length, MSB
0x44, // toc length, LSB
0x01, // First session number
0x01, // Last session number,
// A0 Descriptor
0x01, // session number
0x14, // ADR/Control
0x00, // TNO
0xA0, // POINT
0x00, // Min
0x00, // Sec
0x00, // Frame
0x00, // Zero
0x01, // First Track number.
0x00, // Disc type 00 = Mode 1
0x00, // PFRAME
// A1
0x01, // session number
0x14, // ADR/Control
0x00, // TNO
0xA1, // POINT
0x00, // Min
0x00, // Sec
0x00, // Frame
0x00, // Zero
0x01, // Last Track number
0x00, // PSEC
0x00, // PFRAME
// A2
0x01, // session number
0x14, // ADR/Control
0x00, // TNO
0xA2, // POINT
0x00, // Min
0x00, // Sec
0x00, // Frame
0x00, // Zero
0x79, // LEADOUT position BCD
0x59, // leadout PSEC BCD
0x74, // leadout PFRAME BCD
// TRACK 1 Descriptor
0x01, // session number
0x14, // ADR/Control
0x00, // TNO
0x01, // Point
0x00, // Min
0x00, // Sec
0x00, // Frame
0x00, // Zero
0x00, // PMIN
0x00, // PSEC
0x00, // PFRAME
// b0
0x01, // session number
0x54, // ADR/Control
0x00, // TNO
0xB1, // POINT
0x79, // Min BCD
0x59, // Sec BCD
0x74, // Frame BCD
0x00, // Zero
0x79, // PMIN BCD
0x59, // PSEC BCD
0x74, // PFRAME BCD
// c0
0x01, // session number
0x54, // ADR/Control
0x00, // TNO
0xC0, // POINT
0x00, // Min
0x00, // Sec
0x00, // Frame
0x00, // Zero
0x00, // PMIN
0x00, // PSEC
0x00 // PFRAME
};
static void LBA2MSF(uint32_t LBA, uint8_t* MSF)
{
MSF[0] = 0; // reserved.
MSF[3] = LBA % 75; // M
uint32_t rem = LBA / 75;
MSF[2] = rem % 60; // S
MSF[1] = rem / 60;
}
static void doReadTOC(int MSF, uint8_t track, uint16_t allocationLength)
{
// We only support track 1.
// track 0 means "return all tracks"
@ -45,18 +156,29 @@ void doReadTOC(int MSF, uint8_t track, uint16_t allocationLength)
scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;
scsiDev.phase = STATUS;
}
else if (MSF)
{
// MSF addressing not currently supported.
scsiDev.status = CHECK_CONDITION;
scsiDev.target->sense.code = ILLEGAL_REQUEST;
scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;
scsiDev.phase = STATUS;
}
else
{
uint32_t len = sizeof(SimpleTOC);
memcpy(scsiDev.data, SimpleTOC, len);
uint32_t capacity = getScsiCapacity(
scsiDev.target->cfg->sdSectorStart,
scsiDev.target->liveCfg.bytesPerSector,
scsiDev.target->cfg->scsiSectors);
// Replace start of leadout track
if (MSF)
{
LBA2MSF(capacity, scsiDev.data + 0x0E);
}
else
{
scsiDev.data[0x0E] = capacity >> 24;
scsiDev.data[0x0F] = capacity >> 16;
scsiDev.data[0x10] = capacity >> 8;
scsiDev.data[0x11] = capacity;
}
if (len > allocationLength)
{
len = allocationLength;
@ -66,20 +188,30 @@ void doReadTOC(int MSF, uint8_t track, uint16_t allocationLength)
}
}
uint8_t SimpleHeader[] =
static void doReadSessionInfo(uint8_t session, uint16_t allocationLength)
{
0x01, // 2048byte user data, L-EC in 288 byte aux field.
0x00, // reserved
0x00, // reserved
0x00, // reserved
0x00,0x00,0x00,0x00 // Track start sector (LBA)
};
uint32_t len = sizeof(SessionTOC);
memcpy(scsiDev.data, SessionTOC, len);
void doReadHeader(int MSF, uint32_t lba, uint16_t allocationLength)
{
if (MSF)
if (len > allocationLength)
{
len = allocationLength;
}
scsiDev.dataLen = len;
scsiDev.phase = DATA_IN;
}
static inline uint8_t
fromBCD(uint8_t val)
{
return ((val >> 4) * 10) + (val & 0xF);
}
static void doReadFullTOC(int convertBCD, uint8_t session, uint16_t allocationLength)
{
// We only support session 1.
if (session > 1)
{
// MSF addressing not currently supported.
scsiDev.status = CHECK_CONDITION;
scsiDev.target->sense.code = ILLEGAL_REQUEST;
scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;
@ -87,8 +219,25 @@ void doReadHeader(int MSF, uint32_t lba, uint16_t allocationLength)
}
else
{
uint32_t len = sizeof(SimpleHeader);
memcpy(scsiDev.data, SimpleHeader, len);
uint32_t len = sizeof(FullTOC);
memcpy(scsiDev.data, FullTOC, len);
if (convertBCD)
{
int descriptor = 4;
while (descriptor < len)
{
int i;
for (i = 0; i < 7; ++i)
{
scsiDev.data[descriptor + i] =
fromBCD(scsiDev.data[descriptor + 4 + i]);
}
descriptor += 11;
}
}
if (len > allocationLength)
{
len = allocationLength;
@ -98,6 +247,27 @@ void doReadHeader(int MSF, uint32_t lba, uint16_t allocationLength)
}
}
static uint8_t SimpleHeader[] =
{
0x01, // 2048byte user data, L-EC in 288 byte aux field.
0x00, // reserved
0x00, // reserved
0x00, // reserved
0x00,0x00,0x00,0x00 // Track start sector (LBA or MSF)
};
void doReadHeader(int MSF, uint32_t lba, uint16_t allocationLength)
{
uint32_t len = sizeof(SimpleHeader);
memcpy(scsiDev.data, SimpleHeader, len);
if (len > allocationLength)
{
len = allocationLength;
}
scsiDev.dataLen = len;
scsiDev.phase = DATA_IN;
}
// Handle direct-access scsi device commands
int scsiCDRomCommand()
@ -116,7 +286,24 @@ int scsiCDRomCommand()
(((uint32_t) scsiDev.cdb[7]) << 8) +
scsiDev.cdb[8];
doReadTOC(MSF, track, allocationLength);
// Reject MMC commands for now, otherwise the TOC data format
// won't be understood.
// The "format" field is reserved for SCSI-2
uint8_t format = scsiDev.cdb[2] & 0x0F;
switch (format)
{
case 0: doReadTOC(MSF, track, allocationLength); break; // SCSI-2
case 1: doReadSessionInfo(MSF, allocationLength); break; // MMC2
case 2: doReadFullTOC(0, track, allocationLength); break; // MMC2
case 3: doReadFullTOC(1, track, allocationLength); break; // MMC2
default:
{
scsiDev.status = CHECK_CONDITION;
scsiDev.target->sense.code = ILLEGAL_REQUEST;
scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;
scsiDev.phase = STATUS;
}
}
}
else if (command == 0x44)
{

View File

@ -29,7 +29,7 @@
#include <string.h>
static const uint16_t FIRMWARE_VERSION = 0x0401;
static const uint16_t FIRMWARE_VERSION = 0x0403;
enum USB_ENDPOINTS
{

View File

@ -165,7 +165,9 @@ static void doReadCapacity()
static void doWrite(uint32 lba, uint32 blocks)
{
if (blockDev.state & DISK_WP)
if ((blockDev.state & DISK_WP) ||
(scsiDev.target->cfg->deviceType == CONFIG_OPTICAL))
{
scsiDev.status = CHECK_CONDITION;
scsiDev.target->sense.code = ILLEGAL_REQUEST;

View File

@ -185,6 +185,8 @@ void scsiInquiry()
scsiDev.data[0] = 0x05; // device type
scsiDev.data[1] |= 0x80; // Removable bit.
break;
case CONFIG_FLOPPY_14MB:
case CONFIG_REMOVEABLE:
scsiDev.data[1] |= 0x80; // Removable bit.
break;

View File

@ -150,11 +150,37 @@ static void doModeSense(
int idx = 1;
if (!sixByteCmd) ++idx;
scsiDev.data[idx++] = 0; // Medium type. 0 = default
uint8_t mediumType = 0;
uint8_t deviceSpecificParam = 0;
uint8_t density = 0;
switch (scsiDev.target->cfg->deviceType == CONFIG_OPTICAL)
{
case CONFIG_FIXED:
case CONFIG_REMOVEABLE:
mediumType = 0; // We should support various floppy types here!
// Contains cache bits (0) and a Write-Protect bit.
deviceSpecificParam =
(blockDev.state & DISK_WP) ? 0x80 : 0;
density = 0; // reserved for direct access
break;
// Device-specific parameter. Contains cache bits (0) and
// a Write-Protect bit.
scsiDev.data[idx++] = (blockDev.state & DISK_WP) ? 0x80 : 0;
case CONFIG_FLOPPY_14MB:
mediumType = 0x1E; // 90mm/3.5"
deviceSpecificParam =
(blockDev.state & DISK_WP) ? 0x80 : 0;
density = 0; // reserved for direct access
break;
case CONFIG_OPTICAL:
mediumType = 0x02; // 120mm CDROM, data only.
deviceSpecificParam = 0;
density = 0x01; // User data only, 2048bytes per sector.
break;
};
scsiDev.data[idx++] = mediumType;
scsiDev.data[idx++] = deviceSpecificParam;
if (sixByteCmd)
{
@ -189,7 +215,7 @@ static void doModeSense(
////////////////////////////////////
if (!dbd)
{
scsiDev.data[idx++] = 0; // Density code. Reserved for direct-access
scsiDev.data[idx++] = density;
// Number of blocks
// Zero == all remaining blocks shall have the medium
// characteristics specified.

View File

@ -668,7 +668,7 @@ static void process_MessageOut()
}
scsiDev.lun = scsiDev.msgOut & 0x7;
scsiDev.discPriv =
scsiDev.discPriv =
((scsiDev.msgOut & 0x40) && (scsiDev.initiatorId >= 0))
? 1 : 0;
}

View File

@ -28,7 +28,7 @@ __attribute__ ((__section__(".cyloadablemeta"), used))
const uint8 cy_meta_loadable[] = {
0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
0x00u, 0x00u, 0x00u, 0x00u, 0x5Cu, 0xD1u, 0x01u, 0x04u,
0x00u, 0x00u, 0x00u, 0x00u, 0x5Cu, 0xD1u, 0x03u, 0x04u,
0x01u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,

View File

@ -91,7 +91,8 @@ typedef enum
{
CONFIG_FIXED,
CONFIG_REMOVEABLE,
CONFIG_OPTICAL
CONFIG_OPTICAL,
CONFIG_FLOPPY_14MB
} CONFIG_TYPE;
typedef struct __attribute__((packed))

View File

@ -90,10 +90,15 @@ ConfigUtil::Default(size_t targetIdx)
config.scsiId = config.scsiId | CONFIG_TARGET_ENABLED;
}
config.deviceType = CONFIG_FIXED;
config.flags = CONFIG_ENABLE_PARITY | CONFIG_ENABLE_UNIT_ATTENTION;
// Default to maximum fail-safe options.
config.flags = 0;// CONFIG_ENABLE_PARITY | CONFIG_ENABLE_UNIT_ATTENTION;
config.pad0 = 0;
config.sdSectorStart = 0;
config.scsiSectors = 2147483648; // 1TB
// Default to 2GB. Many systems have trouble with > 2GB disks, and
// a few start to complain at 1GB.
config.scsiSectors = 4194303; // 2GB - 1 sector
config.bytesPerSector = 512;
config.sectorsPerTrack = 63;
config.headsPerCylinder = 255;

View File

@ -8,7 +8,9 @@ LDFLAGS += -L$(BUILD)/libzipper/.libs -lzipper -L$(BUILD)/zlib -lz
LIBZIPPER_CONFIG = --disable-shared LDFLAGS="-L../zlib" CPPFLAGS="-I../zlib"
# wxWidgets 3.0.2 uses broken Webkit headers under OSX Yosemeti
# liblzma not available on OSX 10.7
WX_CONFIG=--disable-webkit --disable-webviewwebkit \
--without-libtiff --without-libjbig --without-liblzma --without-opengl \
--enable-monolithic --enable-stl --disable-shared
TARGET ?= $(shell uname -s)

View File

@ -102,7 +102,13 @@ TargetPanel::TargetPanel(wxWindow* parent, const TargetConfig& initialConfig) :
Bind(wxEVT_SPINCTRL, &TargetPanel::onInput<wxSpinEvent>, this, ID_scsiIdCtrl);
fgs->Add(new wxStaticText(this, wxID_ANY, wxT("Device Type")));
wxString deviceTypes[] = {wxT("Hard Drive"), wxT("Removable"), wxT("CDROM")};
wxString deviceTypes[] =
{
wxT("Hard Drive"),
wxT("Removable"),
wxT("CDROM"),
wxT("3.5\" Floppy")
};
myDeviceTypeCtrl =
new wxChoice(
this,
@ -304,6 +310,41 @@ TargetPanel::evaluate()
bool valid = true;
std::stringstream conv;
bool enabled = myEnableCtrl->IsChecked();
{
myScsiIdCtrl->Enable(enabled);
myDeviceTypeCtrl->Enable(enabled);
myParityCtrl->Enable(enabled);
myUnitAttCtrl->Enable(enabled);
myStartSDSectorCtrl->Enable(enabled && !myAutoStartSectorCtrl->IsChecked());
myAutoStartSectorCtrl->Enable(enabled);
mySectorSizeCtrl->Enable(enabled);
myNumSectorCtrl->Enable(enabled);
mySizeCtrl->Enable(enabled);
mySizeUnitCtrl->Enable(enabled);
myVendorCtrl->Enable(enabled);
myProductCtrl->Enable(enabled);
myRevisionCtrl->Enable(enabled);
mySerialCtrl->Enable(enabled);
}
switch (myDeviceTypeCtrl->GetSelection())
{
case CONFIG_OPTICAL:
mySectorSizeCtrl->ChangeValue("2048");
mySectorSizeCtrl->Enable(false);
break;
case CONFIG_FLOPPY_14MB:
mySectorSizeCtrl->ChangeValue("512");
mySectorSizeCtrl->Enable(false);
myNumSectorCtrl->ChangeValue("2880");
myNumSectorCtrl->Enable(false);
mySizeUnitCtrl->Enable(false);
mySizeCtrl->Enable(false);
break;
};
evaluateSize();
if (myAutoStartSectorCtrl->IsChecked())
{
std::stringstream ss; ss << myAutoStartSector;
@ -393,23 +434,6 @@ TargetPanel::evaluate()
mySerialMsg->SetLabelMarkup("");
}
bool enabled = myEnableCtrl->IsChecked();
{
myScsiIdCtrl->Enable(enabled);
myDeviceTypeCtrl->Enable(enabled);
myParityCtrl->Enable(enabled);
myUnitAttCtrl->Enable(enabled);
myStartSDSectorCtrl->Enable(enabled && !myAutoStartSectorCtrl->IsChecked());
myAutoStartSectorCtrl->Enable(enabled);
mySectorSizeCtrl->Enable(enabled);
myNumSectorCtrl->Enable(enabled);
mySizeCtrl->Enable(enabled);
mySizeUnitCtrl->Enable(enabled);
myVendorCtrl->Enable(enabled);
myProductCtrl->Enable(enabled);
myRevisionCtrl->Enable(enabled);
mySerialCtrl->Enable(enabled);
}
return valid || !enabled;
}
@ -423,49 +447,51 @@ TargetPanel::onInput(EvtType& event)
void
TargetPanel::onSizeInput(wxCommandEvent& event)
{
if (event.GetId() == ID_numSectorCtrl)
{
uint32_t numSectors;
std::stringstream conv;
conv << myNumSectorCtrl->GetValue();
conv >> numSectors;
conv.str(""); conv.clear();
if (conv)
{
uint64_t bytes =
uint64_t(numSectors) *
CtrlGetValue<uint16_t>(mySectorSizeCtrl).first;
if (bytes >= 1024 * 1024 * 1024)
{
conv << (bytes / (1024.0 * 1024 * 1024));
mySizeUnitCtrl->SetSelection(UNIT_GB);
}
else if (bytes >= 1024 * 1024)
{
conv << (bytes / (1024.0 * 1024));
mySizeUnitCtrl->SetSelection(UNIT_MB);
}
else
{
conv << (bytes / 1024.0);
mySizeUnitCtrl->SetSelection(UNIT_KB);
}
mySizeCtrl->ChangeValue(conv.str());
}
}
else
if (event.GetId() != ID_numSectorCtrl)
{
std::stringstream ss;
ss << convertUnitsToSectors().first;
myNumSectorCtrl->ChangeValue(ss.str());
}
evaluateSize();
onInput(event); // propagate
}
void
TargetPanel::evaluateSize()
{
uint32_t numSectors;
std::stringstream conv;
conv << myNumSectorCtrl->GetValue();
conv >> numSectors;
conv.str(""); conv.clear();
if (conv)
{
uint64_t bytes =
uint64_t(numSectors) *
CtrlGetValue<uint16_t>(mySectorSizeCtrl).first;
if (bytes >= 1024 * 1024 * 1024)
{
conv << (bytes / (1024.0 * 1024 * 1024));
mySizeUnitCtrl->SetSelection(UNIT_GB);
}
else if (bytes >= 1024 * 1024)
{
conv << (bytes / (1024.0 * 1024));
mySizeUnitCtrl->SetSelection(UNIT_MB);
}
else
{
conv << (bytes / 1024.0);
mySizeUnitCtrl->SetSelection(UNIT_KB);
}
mySizeCtrl->ChangeValue(conv.str());
}
}
std::pair<uint32_t, bool>
TargetPanel::convertUnitsToSectors() const
{

View File

@ -66,6 +66,7 @@ public:
private:
template<typename EvtType> void onInput(EvtType& event);
void onSizeInput(wxCommandEvent& event);
void evaluateSize();
std::pair<uint32_t, bool> convertUnitsToSectors() const;