|
|
@@ -30,6 +30,8 @@
|
|
|
#include "ZuluSCSI_log.h"
|
|
|
#include "ZuluSCSI_config.h"
|
|
|
#include "ZuluSCSI_presets.h"
|
|
|
+#include "ImageBackingStore.h"
|
|
|
+#include "ROMDrive.h"
|
|
|
#include <minIni.h>
|
|
|
#include <string.h>
|
|
|
#include <strings.h>
|
|
|
@@ -76,14 +78,6 @@ extern "C" {
|
|
|
#endif
|
|
|
#endif
|
|
|
|
|
|
-#ifndef PLATFORM_HAS_ROM_DRIVE
|
|
|
-// Dummy defines for platforms without ROM drive support
|
|
|
-#define PLATFORM_ROMDRIVE_PAGE_SIZE 1024
|
|
|
-uint32_t platform_get_romdrive_maxsize() { return 0; }
|
|
|
-bool platform_read_romdrive(uint8_t *dest, uint32_t start, uint32_t count) { return false; }
|
|
|
-bool platform_write_romdrive(const uint8_t *data, uint32_t start, uint32_t count) { return false; }
|
|
|
-#endif
|
|
|
-
|
|
|
#ifndef PLATFORM_SCSIPHY_HAS_NONBLOCKING_READ
|
|
|
// For platforms that do not have non-blocking read from SCSI bus
|
|
|
void scsiStartRead(uint8_t* data, uint32_t count, int *parityError)
|
|
|
@@ -100,157 +94,22 @@ bool scsiIsReadFinished(const uint8_t *data)
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
-// SD card sector size is always 512 bytes
|
|
|
-extern SdFs SD;
|
|
|
-#define SD_SECTOR_SIZE 512
|
|
|
-
|
|
|
/************************************************/
|
|
|
/* ROM drive support (in microcontroller flash) */
|
|
|
/************************************************/
|
|
|
|
|
|
-struct romdrive_hdr_t {
|
|
|
- char magic[8]; // "ROMDRIVE"
|
|
|
- int scsi_id;
|
|
|
- uint32_t imagesize;
|
|
|
- uint32_t blocksize;
|
|
|
- S2S_CFG_TYPE drivetype;
|
|
|
- uint32_t reserved[32];
|
|
|
-};
|
|
|
-
|
|
|
-// Check if the romdrive is present
|
|
|
-static bool check_romdrive(romdrive_hdr_t *hdr)
|
|
|
-{
|
|
|
- if (!platform_read_romdrive((uint8_t*)hdr, 0, sizeof(romdrive_hdr_t)))
|
|
|
- {
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- if (memcmp(hdr->magic, "ROMDRIVE", 8) != 0)
|
|
|
- {
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- if (hdr->imagesize <= 0 || hdr->scsi_id < 0 || hdr->scsi_id > 8)
|
|
|
- {
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
-// Clear the drive metadata header
|
|
|
-bool scsiDiskClearRomDrive()
|
|
|
-{
|
|
|
-#ifndef PLATFORM_HAS_ROM_DRIVE
|
|
|
- logmsg("---- Platform does not support ROM drive");
|
|
|
- return false;
|
|
|
-#else
|
|
|
- romdrive_hdr_t hdr = {0x0};
|
|
|
-
|
|
|
- if (!platform_write_romdrive((const uint8_t*)&hdr, 0, PLATFORM_ROMDRIVE_PAGE_SIZE))
|
|
|
- {
|
|
|
- logmsg("-- Failed to clear ROM drive");
|
|
|
- return false;
|
|
|
- }
|
|
|
- logmsg("-- Cleared ROM drive");
|
|
|
- SD.remove("CLEAR_ROM");
|
|
|
- return true;
|
|
|
-#endif
|
|
|
-}
|
|
|
-
|
|
|
-// Load an image file to romdrive
|
|
|
-bool scsiDiskProgramRomDrive(const char *filename, int scsi_id, int blocksize, S2S_CFG_TYPE type)
|
|
|
-{
|
|
|
-#ifndef PLATFORM_HAS_ROM_DRIVE
|
|
|
- logmsg("---- Platform does not support ROM drive");
|
|
|
- return false;
|
|
|
-#endif
|
|
|
-
|
|
|
- FsFile file = SD.open(filename, O_RDONLY);
|
|
|
- if (!file.isOpen())
|
|
|
- {
|
|
|
- logmsg("---- Failed to open: ", filename);
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- uint64_t filesize = file.size();
|
|
|
- uint32_t maxsize = platform_get_romdrive_maxsize() - PLATFORM_ROMDRIVE_PAGE_SIZE;
|
|
|
-
|
|
|
- logmsg("---- SCSI ID: ", scsi_id, " blocksize ", blocksize, " type ", (int)type);
|
|
|
- logmsg("---- ROM drive maximum size is ", (int)maxsize,
|
|
|
- " bytes, image file is ", (int)filesize, " bytes");
|
|
|
-
|
|
|
- if (filesize > maxsize)
|
|
|
- {
|
|
|
- logmsg("---- Image size exceeds ROM space, not loading");
|
|
|
- file.close();
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- romdrive_hdr_t hdr = {};
|
|
|
- memcpy(hdr.magic, "ROMDRIVE", 8);
|
|
|
- hdr.scsi_id = scsi_id;
|
|
|
- hdr.imagesize = filesize;
|
|
|
- hdr.blocksize = blocksize;
|
|
|
- hdr.drivetype = type;
|
|
|
-
|
|
|
- // Program the drive metadata header
|
|
|
- if (!platform_write_romdrive((const uint8_t*)&hdr, 0, PLATFORM_ROMDRIVE_PAGE_SIZE))
|
|
|
- {
|
|
|
- logmsg("---- Failed to program ROM drive header");
|
|
|
- file.close();
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- // Program the drive contents
|
|
|
- uint32_t pages = (filesize + PLATFORM_ROMDRIVE_PAGE_SIZE - 1) / PLATFORM_ROMDRIVE_PAGE_SIZE;
|
|
|
- for (uint32_t i = 0; i < pages; i++)
|
|
|
- {
|
|
|
- if (i % 2)
|
|
|
- LED_ON();
|
|
|
- else
|
|
|
- LED_OFF();
|
|
|
-
|
|
|
- if (file.read(scsiDev.data, PLATFORM_ROMDRIVE_PAGE_SIZE) <= 0 ||
|
|
|
- !platform_write_romdrive(scsiDev.data, (i + 1) * PLATFORM_ROMDRIVE_PAGE_SIZE, PLATFORM_ROMDRIVE_PAGE_SIZE))
|
|
|
- {
|
|
|
- logmsg("---- Failed to program ROM drive page ", (int)i);
|
|
|
- file.close();
|
|
|
- return false;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- LED_OFF();
|
|
|
-
|
|
|
- file.close();
|
|
|
-
|
|
|
- char newname[MAX_FILE_PATH * 2] = "";
|
|
|
- strlcat(newname, filename, sizeof(newname));
|
|
|
- strlcat(newname, "_loaded", sizeof(newname));
|
|
|
- SD.rename(filename, newname);
|
|
|
- logmsg("---- ROM drive programming successful, image file renamed to ", newname);
|
|
|
-
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
-bool scsiDiskCheckRomDrive()
|
|
|
-{
|
|
|
- romdrive_hdr_t hdr = {};
|
|
|
- return check_romdrive(&hdr);
|
|
|
-}
|
|
|
-
|
|
|
// Check if rom drive exists and activate it
|
|
|
bool scsiDiskActivateRomDrive()
|
|
|
{
|
|
|
#ifndef PLATFORM_HAS_ROM_DRIVE
|
|
|
return false;
|
|
|
-#endif
|
|
|
+#else
|
|
|
|
|
|
uint32_t maxsize = platform_get_romdrive_maxsize() - PLATFORM_ROMDRIVE_PAGE_SIZE;
|
|
|
logmsg("-- Platform supports ROM drive up to ", (int)(maxsize / 1024), " kB");
|
|
|
|
|
|
romdrive_hdr_t hdr = {};
|
|
|
- if (!check_romdrive(&hdr))
|
|
|
+ if (!romDriveCheckPresent(&hdr))
|
|
|
{
|
|
|
logmsg("---- ROM drive image not detected");
|
|
|
return false;
|
|
|
@@ -275,8 +134,6 @@ bool scsiDiskActivateRomDrive()
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-
|
|
|
logmsg("---- Activating ROM drive, SCSI id ", (int)hdr.scsi_id, " size ", (int)(hdr.imagesize / 1024), " kB");
|
|
|
bool status = scsiDiskOpenHDDImage(hdr.scsi_id, "ROM:", hdr.scsi_id, 0, hdr.blocksize, hdr.drivetype);
|
|
|
|
|
|
@@ -289,305 +146,18 @@ bool scsiDiskActivateRomDrive()
|
|
|
{
|
|
|
return true;
|
|
|
}
|
|
|
+
|
|
|
+#endif
|
|
|
}
|
|
|
|
|
|
|
|
|
/***********************/
|
|
|
-/* Backing image files */
|
|
|
+/* Image configuration */
|
|
|
/***********************/
|
|
|
|
|
|
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.
|
|
|
-//
|
|
|
-// If the platform supports a ROM drive, it is activated by using
|
|
|
-// filename "ROM:".
|
|
|
-class ImageBackingStore
|
|
|
-{
|
|
|
-public:
|
|
|
- ImageBackingStore()
|
|
|
- {
|
|
|
- m_israw = false;
|
|
|
- m_isrom = false;
|
|
|
- m_isreadonly_attr = false;
|
|
|
- m_blockdev = nullptr;
|
|
|
- m_bgnsector = m_endsector = m_cursector = 0;
|
|
|
- }
|
|
|
-
|
|
|
- ImageBackingStore(const char *filename, uint32_t scsi_block_size): 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')
|
|
|
- {
|
|
|
- logmsg("Invalid format for raw filename: ", filename);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if ((scsi_block_size % SD_SECTOR_SIZE) != 0)
|
|
|
- {
|
|
|
- logmsg("SCSI block size ", (int)scsi_block_size, " is not supported for RAW partitions (must be divisible by 512 bytes)");
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- m_israw = true;
|
|
|
- m_blockdev = SD.card();
|
|
|
-
|
|
|
- uint32_t sectorCount = SD.card()->sectorCount();
|
|
|
- if (m_endsector >= sectorCount)
|
|
|
- {
|
|
|
- logmsg("Limiting RAW image mapping to SD card sector count: ", (int)sectorCount);
|
|
|
- m_endsector = sectorCount - 1;
|
|
|
- }
|
|
|
- }
|
|
|
- else if (strncasecmp(filename, "ROM:", 4) == 0)
|
|
|
- {
|
|
|
- if (!check_romdrive(&m_romhdr))
|
|
|
- {
|
|
|
- m_romhdr.imagesize = 0;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- m_isrom = true;
|
|
|
- }
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- m_isreadonly_attr = !!(FS_ATTRIB_READ_ONLY & SD.attrib(filename));
|
|
|
- if (m_isreadonly_attr)
|
|
|
- {
|
|
|
- m_fsfile = SD.open(filename, O_RDONLY);
|
|
|
- logmsg("---- Image file is read-only, writes disabled");
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- m_fsfile = SD.open(filename, O_RDWR);
|
|
|
- }
|
|
|
-
|
|
|
- uint32_t sectorcount = m_fsfile.size() / SD_SECTOR_SIZE;
|
|
|
- uint32_t begin = 0, end = 0;
|
|
|
- if (m_fsfile.contiguousRange(&begin, &end) && end >= begin + sectorcount
|
|
|
- && (scsi_block_size % SD_SECTOR_SIZE) == 0)
|
|
|
- {
|
|
|
- // Convert to raw mapping, this avoids some unnecessary
|
|
|
- // access overhead in SdFat library.
|
|
|
- m_israw = true;
|
|
|
- m_blockdev = SD.card();
|
|
|
- m_bgnsector = begin;
|
|
|
-
|
|
|
- if (end != begin + sectorcount)
|
|
|
- {
|
|
|
- uint32_t allocsize = end - begin + 1;
|
|
|
- // Due to issue #80 in ZuluSCSI version 1.0.8 and 1.0.9 the allocated size was mistakenly reported to SCSI controller.
|
|
|
- // If the drive was formatted using those versions, you may have problems accessing it with newer firmware.
|
|
|
- // The old behavior can be restored with setting [SCSI] UseFATAllocSize = 1 in config file.
|
|
|
-
|
|
|
- if (ini_getbool("SCSI", "UseFATAllocSize", 0, CONFIGFILE))
|
|
|
- {
|
|
|
- sectorcount = allocsize;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- m_endsector = begin + sectorcount - 1;
|
|
|
- m_fsfile.close();
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- bool isWritable()
|
|
|
- {
|
|
|
- return !m_isrom && !m_isreadonly_attr;
|
|
|
- }
|
|
|
-
|
|
|
- bool isRom()
|
|
|
- {
|
|
|
- return m_isrom;
|
|
|
- }
|
|
|
-
|
|
|
- bool isOpen()
|
|
|
- {
|
|
|
- if (m_israw)
|
|
|
- return (m_blockdev != NULL);
|
|
|
- else if (m_isrom)
|
|
|
- return (m_romhdr.imagesize > 0);
|
|
|
- else
|
|
|
- return m_fsfile.isOpen();
|
|
|
- }
|
|
|
-
|
|
|
- bool close()
|
|
|
- {
|
|
|
- if (m_israw)
|
|
|
- {
|
|
|
- m_blockdev = nullptr;
|
|
|
- return true;
|
|
|
- }
|
|
|
- else if (m_isrom)
|
|
|
- {
|
|
|
- m_romhdr.imagesize = 0;
|
|
|
- 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 if (m_isrom)
|
|
|
- {
|
|
|
- return m_romhdr.imagesize;
|
|
|
- }
|
|
|
- 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 if (m_isrom)
|
|
|
- {
|
|
|
- *bgnSector = 0;
|
|
|
- *endSector = 0;
|
|
|
- return true;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- return m_fsfile.contiguousRange(bgnSector, endSector);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- bool seek(uint64_t pos)
|
|
|
- {
|
|
|
- if (m_israw)
|
|
|
- {
|
|
|
- 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 if (m_isrom)
|
|
|
- {
|
|
|
- uint32_t sectornum = pos / SD_SECTOR_SIZE;
|
|
|
- assert((uint64_t)sectornum * SD_SECTOR_SIZE == pos);
|
|
|
- m_cursector = sectornum;
|
|
|
- return m_cursector * SD_SECTOR_SIZE < m_romhdr.imagesize;
|
|
|
- }
|
|
|
- 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 if (m_isrom)
|
|
|
- {
|
|
|
- uint32_t sectorcount = count / SD_SECTOR_SIZE;
|
|
|
- assert((uint64_t)sectorcount * SD_SECTOR_SIZE == count);
|
|
|
- uint32_t start = m_cursector * SD_SECTOR_SIZE + PLATFORM_ROMDRIVE_PAGE_SIZE;
|
|
|
- if (platform_read_romdrive((uint8_t*)buf, start, count))
|
|
|
- {
|
|
|
- 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 if (m_isrom)
|
|
|
- {
|
|
|
- logmsg("ERROR: attempted to write to ROM drive");
|
|
|
- return 0;
|
|
|
- }
|
|
|
- else if (m_isreadonly_attr)
|
|
|
- {
|
|
|
- logmsg("ERROR: attempted to write to a read only image");
|
|
|
- return 0;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- return m_fsfile.write(buf, count);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- void flush()
|
|
|
- {
|
|
|
- if (!m_israw && !m_isrom && !m_isreadonly_attr)
|
|
|
- {
|
|
|
- m_fsfile.flush();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-private:
|
|
|
- bool m_israw;
|
|
|
- bool m_isrom;
|
|
|
- bool m_isreadonly_attr;
|
|
|
- romdrive_hdr_t m_romhdr;
|
|
|
- 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
|
|
|
{
|
|
|
ImageBackingStore file;
|