-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.
#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)
+};
+
+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
};
-void doReadTOC(int MSF, uint8_t track, uint16_t allocationLength)
+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"
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;
}
}
-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 (len > allocationLength)
+ {
+ len = allocationLength;
+ }
+ scsiDev.dataLen = len;
+ scsiDev.phase = DATA_IN;
+}
+
+static inline uint8_t
+fromBCD(uint8_t val)
{
- if (MSF)
+ 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;
}
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;
}
}
+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()
(((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)
{
\r
#include <string.h>\r
\r
-static const uint16_t FIRMWARE_VERSION = 0x0401;\r
+static const uint16_t FIRMWARE_VERSION = 0x0403;\r
\r
enum USB_ENDPOINTS\r
{\r
\r
static void doWrite(uint32 lba, uint32 blocks)\r
{\r
- if (blockDev.state & DISK_WP)\r
+ if ((blockDev.state & DISK_WP) ||\r
+ (scsiDev.target->cfg->deviceType == CONFIG_OPTICAL))\r
+\r
{\r
scsiDev.status = CHECK_CONDITION;\r
scsiDev.target->sense.code = ILLEGAL_REQUEST;\r
scsiDev.data[0] = 0x05; // device type\r
scsiDev.data[1] |= 0x80; // Removable bit.\r
break;\r
+\r
+ case CONFIG_FLOPPY_14MB:\r
case CONFIG_REMOVEABLE:\r
scsiDev.data[1] |= 0x80; // Removable bit.\r
break;\r
int idx = 1;\r
if (!sixByteCmd) ++idx;\r
\r
- scsiDev.data[idx++] = 0; // Medium type. 0 = default\r
+ uint8_t mediumType = 0;\r
+ uint8_t deviceSpecificParam = 0;\r
+ uint8_t density = 0;\r
+ switch (scsiDev.target->cfg->deviceType == CONFIG_OPTICAL)\r
+ {\r
+ case CONFIG_FIXED:\r
+ case CONFIG_REMOVEABLE:\r
+ mediumType = 0; // We should support various floppy types here!\r
+ // Contains cache bits (0) and a Write-Protect bit.\r
+ deviceSpecificParam =\r
+ (blockDev.state & DISK_WP) ? 0x80 : 0;\r
+ density = 0; // reserved for direct access\r
+ break;\r
+\r
+ case CONFIG_FLOPPY_14MB:\r
+ mediumType = 0x1E; // 90mm/3.5"\r
+ deviceSpecificParam =\r
+ (blockDev.state & DISK_WP) ? 0x80 : 0;\r
+ density = 0; // reserved for direct access\r
+ break;\r
+\r
+ case CONFIG_OPTICAL:\r
+ mediumType = 0x02; // 120mm CDROM, data only.\r
+ deviceSpecificParam = 0;\r
+ density = 0x01; // User data only, 2048bytes per sector.\r
+ break;\r
+\r
+ };\r
\r
- // Device-specific parameter. Contains cache bits (0) and\r
- // a Write-Protect bit.\r
- scsiDev.data[idx++] = (blockDev.state & DISK_WP) ? 0x80 : 0;\r
+ scsiDev.data[idx++] = mediumType;\r
+ scsiDev.data[idx++] = deviceSpecificParam;\r
\r
if (sixByteCmd)\r
{\r
////////////////////////////////////\r
if (!dbd)\r
{\r
- scsiDev.data[idx++] = 0; // Density code. Reserved for direct-access\r
+ scsiDev.data[idx++] = density;\r
// Number of blocks\r
// Zero == all remaining blocks shall have the medium\r
// characteristics specified.\r
}\r
\r
scsiDev.lun = scsiDev.msgOut & 0x7;\r
- scsiDev.discPriv =\r
+ scsiDev.discPriv = \r
((scsiDev.msgOut & 0x40) && (scsiDev.initiatorId >= 0))\r
? 1 : 0;\r
}\r
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,
{
CONFIG_FIXED,
CONFIG_REMOVEABLE,
- CONFIG_OPTICAL
+ CONFIG_OPTICAL,
+ CONFIG_FLOPPY_14MB
} CONFIG_TYPE;
typedef struct __attribute__((packed))
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;
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)
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,
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;
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;
}
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
{
private:
template<typename EvtType> void onInput(EvtType& event);
void onSizeInput(wxCommandEvent& event);
+ void evaluateSize();
std::pair<uint32_t, bool> convertUnitsToSectors() const;