Skip to content

Commit

Permalink
Add raw passthrough mode (without FAT filesystem).
Browse files Browse the repository at this point in the history
If no images are found, the whole SD card is presented as SCSI drive.
Raw passthrough can also be manually specified in config file.
  • Loading branch information
PetteriAimonen authored and morio committed Aug 12, 2022
1 parent 30e5ee5 commit 8a47a01
Show file tree
Hide file tree
Showing 4 changed files with 196 additions and 6 deletions.
20 changes: 17 additions & 3 deletions src/ZuluSCSI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ FsFile g_logfile;
/* Status reporting by blinking led */
/************************************/

#define BLINK_STATUS_OK 1
#define BLINK_ERROR_NO_IMAGES 3
#define BLINK_ERROR_NO_SD_CARD 5

Expand Down Expand Up @@ -384,7 +385,15 @@ static void reinitSCSI()
if (foundImage)
{
// Ok, there is an image
blinkStatus(1);
blinkStatus(BLINK_STATUS_OK);
}
else
{
#if RAW_FALLBACK_ENABLE
azlog("No images found, enabling RAW fallback partition");
scsiDiskOpenHDDImage(RAW_FALLBACK_SCSI_ID, "RAW:0:0xFFFFFFFF", RAW_FALLBACK_SCSI_ID, 0,
RAW_FALLBACK_BLOCKSIZE, false);
#endif
}

scsiPhyReset();
Expand All @@ -398,7 +407,7 @@ extern "C" int zuluscsi_main(void)
azplatform_init();
azplatform_late_init();

if(!SD.begin(SD_CONFIG))
if(!SD.begin(SD_CONFIG) && (!SD.card() || SD.sdErrorCode() != 0))
{
azlog("SD card init failed, sdErrorCode: ", (int)SD.sdErrorCode(),
" sdErrorData: ", (int)SD.sdErrorData());
Expand All @@ -408,10 +417,15 @@ extern "C" int zuluscsi_main(void)
blinkStatus(BLINK_ERROR_NO_SD_CARD);
delay(1000);
azplatform_reset_watchdog();
} while (!SD.begin(SD_CONFIG));
} while (!SD.begin(SD_CONFIG) && (!SD.card() || SD.sdErrorCode() != 0));
azlog("SD card init succeeded after retry");
}

if (SD.clusterCount() == 0)
{
azlog("SD card without filesystem!");
}

print_sd_info();

reinitSCSI();
Expand Down
6 changes: 6 additions & 0 deletions src/ZuluSCSI_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@
#define NUM_SCSILUN 1 // Maximum number of LUNs supported (Currently has to be 1)
#define READ_PARITY_CHECK 0 // Perform read parity check (unverified)

// SCSI raw fallback configuration when no image files are detected
// Presents the whole SD card as an SCSI drive
#define RAW_FALLBACK_ENABLE 1
#define RAW_FALLBACK_SCSI_ID 1
#define RAW_FALLBACK_BLOCKSIZE 512

// Default SCSI drive information (can be overridden in INI file)
// Selected based on device type (fixed, removable, optical, floppy, mag-optical, tape)
// Each entry has {vendor, product, version, serial}
Expand Down
167 changes: 165 additions & 2 deletions src/ZuluSCSI_disk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include "ZuluSCSI_config.h"
#include <minIni.h>
#include <string.h>
#include <strings.h>
#include <assert.h>
#include <SdFat.h>

extern "C" {
Expand Down Expand Up @@ -41,6 +43,8 @@ extern "C" {
#define PLATFORM_OPTIMAL_LAST_SD_WRITE_SIZE 512
#endif

// SD card sector size is always 512 bytes
#define SD_SECTOR_SIZE 512

/***********************/
/* Backing image files */
Expand All @@ -49,9 +53,168 @@ extern "C" {
extern SdFs SD;
SdDevice sdDev = {2, 256 * 1024 * 1024 * 2}; /* For SCSI2SD */

// This class wraps SdFat library FsFile to allow access
// through either FAT filesystem or as a raw sector range.
//
// Raw access is activated by using filename like "RAW:0:12345"
// where the numbers are the first and last sector.
class ImageBackingStore
{
public:
ImageBackingStore()
{
m_israw = false;
m_blockdev = nullptr;
m_bgnsector = m_endsector = m_cursector = 0;
}

ImageBackingStore(const char *filename): ImageBackingStore()
{
if (strncasecmp(filename, "RAW:", 4) == 0)
{
char *endptr, *endptr2;
m_bgnsector = strtoul(filename + 4, &endptr, 0);
m_endsector = strtoul(endptr + 1, &endptr2, 0);

if (*endptr != ':' || *endptr2 != '\0')
{
azlog("Invalid format for raw filename: ", filename);
return;
}

m_israw = true;
m_blockdev = SD.card();

if (m_endsector >= SD.card()->sectorCount())
{
m_endsector = SD.card()->sectorCount() - 1;
}
}
else
{
m_fsfile = SD.open(filename, O_RDWR);
}
}

bool isOpen() { return m_israw ? !!m_blockdev : m_fsfile.isOpen(); }
bool close()
{
if (m_israw)
{
m_blockdev = nullptr;
return true;
}
else
{
return m_fsfile.close();
}
}

uint64_t size()
{
if (m_israw && m_blockdev)
{
return (uint64_t)(m_endsector - m_bgnsector + 1) * SD_SECTOR_SIZE;
}
else
{
return m_fsfile.size();
}
}

bool contiguousRange(uint32_t* bgnSector, uint32_t* endSector)
{
if (m_israw && m_blockdev)
{
*bgnSector = m_bgnsector;
*endSector = m_endsector;
return true;
}
else
{
return m_fsfile.contiguousRange(bgnSector, endSector);
}
}

bool seek(uint64_t pos)
{
if (m_israw && m_blockdev)
{
uint32_t sectornum = pos / SD_SECTOR_SIZE;
assert((uint64_t)sectornum * SD_SECTOR_SIZE == pos);
m_cursector = m_bgnsector + sectornum;
return (m_cursector <= m_endsector);
}
else
{
return m_fsfile.seek(pos);
}
}

int read(void* buf, size_t count)
{
if (m_israw && m_blockdev)
{
uint32_t sectorcount = count / SD_SECTOR_SIZE;
assert((uint64_t)sectorcount * SD_SECTOR_SIZE == count);
if (m_blockdev->readSectors(m_cursector, (uint8_t*)buf, sectorcount))
{
m_cursector += sectorcount;
return count;
}
else
{
return -1;
}
}
else
{
return m_fsfile.read(buf, count);
}
}

size_t write(const void* buf, size_t count)
{
if (m_israw && m_blockdev)
{
uint32_t sectorcount = count / SD_SECTOR_SIZE;
assert((uint64_t)sectorcount * SD_SECTOR_SIZE == count);
if (m_blockdev->writeSectors(m_cursector, (const uint8_t*)buf, sectorcount))
{
m_cursector += sectorcount;
return count;
}
else
{
return 0;
}
}
else
{
return m_fsfile.write(buf, count);
}
}

void flush()
{
if (!m_israw)
{
m_fsfile.flush();
}
}

private:
bool m_israw;
FsFile m_fsfile;
SdCard *m_blockdev;
uint32_t m_bgnsector;
uint32_t m_endsector;
uint32_t m_cursector;
};

struct image_config_t: public S2S_TargetCfg
{
FsFile file;
ImageBackingStore file;

// For CD-ROM drive ejection
bool ejected;
Expand Down Expand Up @@ -204,7 +367,7 @@ static void setDefaultDriveInfo(int target_idx)
bool scsiDiskOpenHDDImage(int target_idx, const char *filename, int scsi_id, int scsi_lun, int blocksize, bool is_cd)
{
image_config_t &img = g_DiskImages[target_idx];
img.file = SD.open(filename, O_RDWR);
img.file = ImageBackingStore(filename);

if (img.file.isOpen())
{
Expand Down
9 changes: 8 additions & 1 deletion zuluscsi.ini
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,11 @@ Product = "CD-ROM Drive"
Type = 2
# If IMG0..IMG9 are specified, they are cycled after each CD eject command.
#IMG0 = FirstCD.iso
#IMG1 = SecondCD.iso
#IMG1 = SecondCD.iso


# Raw sector range from SD card can be passed through
# Format is RAW:first_sector:last_sector where sector numbers can be decimal or hex.
# If end sector is beyond end of SD card, it will be adjusted automatically.
# [SCSI4]
# IMG0 = RAW:0x00000000:0xFFFFFFFF # Whole SD card

0 comments on commit 8a47a01

Please sign in to comment.