Skip to content

Commit

Permalink
Merge pull request #43 from ZuluSCSI/v1.0.7-release
Browse files Browse the repository at this point in the history
Disable raw fallback when image is specified through .ini
Show warning about undivisible image size only when host queries disk
Fix pauses during transfer in PIO mode
Avoid SysTick interrupts during transfers
  • Loading branch information
aperezbios authored Aug 25, 2022
2 parents 0f79605 + c7380b6 commit dc30e55
Show file tree
Hide file tree
Showing 9 changed files with 123 additions and 21 deletions.
24 changes: 24 additions & 0 deletions lib/ZuluSCSI_platform_GD32F205/ZuluSCSI_platform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,30 @@ void SysTick_Handler(void)
"b SysTick_Handler_inner": : : "r0");
}

// This function is called by scsiPhy.cpp.
// It resets the systick counter to give 1 millisecond of uninterrupted transfer time.
// The total number of skips is kept track of to keep the correct time on average.
void SysTick_Handle_PreEmptively()
{
static int skipped_clocks = 0;

__disable_irq();
uint32_t loadval = SysTick->LOAD;
skipped_clocks += loadval - SysTick->VAL;
SysTick->VAL = 0;

if (skipped_clocks > loadval)
{
// We have skipped enough ticks that it is time to fake a call
// to SysTick interrupt handler.
skipped_clocks -= loadval;
uint32_t stack_frame[8] = {0};
stack_frame[6] = (uint32_t)__builtin_return_address(0);
SysTick_Handler_inner(stack_frame);
}
__enable_irq();
}

/***************/
/* GPIO init */
/***************/
Expand Down
9 changes: 9 additions & 0 deletions lib/ZuluSCSI_platform_GD32F205/ZuluSCSI_platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ void azplatform_emergency_log_save();
typedef void (*sd_callback_t)(uint32_t bytes_complete);
void azplatform_set_sd_callback(sd_callback_t func, const uint8_t *buffer);

// This function is called by scsiPhy.cpp.
// It resets the systick counter to give 1 millisecond of uninterrupted transfer time.
// The total number of skips is kept track of to keep the correct time on average.
void SysTick_Handle_PreEmptively();

// Reprogram firmware in main program area.
#define AZPLATFORM_BOOTLOADER_SIZE 32768
#define AZPLATFORM_FLASH_TOTAL_SIZE (256 * 1024)
Expand Down Expand Up @@ -145,4 +150,8 @@ extern SdioConfig g_sd_sdio_config_crash;

#endif

// Check if a DMA request for SD card read has completed.
// This is used to optimize the timing of data transfers on SCSI bus.
bool check_sd_read_done();

#endif
19 changes: 16 additions & 3 deletions lib/ZuluSCSI_platform_GD32F205/scsiPhy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -418,13 +418,24 @@ static bool isPollingWriteFinished(const uint8_t *data)
extern "C" bool scsiIsWriteFinished(const uint8_t *data)
{
// Check if there is still a polling transfer in progress
if (!isPollingWriteFinished(data))
if (!isPollingWriteFinished(data) && !check_sd_read_done())
{
// Process the transfer piece-by-piece while waiting
// for SD card to react.
int max_count = g_scsi_writereq.count / 8;
max_count &= ~255;
if (max_count < 256) max_count = 256;

// Always transfer whole sectors without pause to avoid problems with some SCSI hosts.
int bytesPerSector = 512;
if (scsiDev.target)
{
bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;
}
if (max_count % bytesPerSector != 0) max_count -= (max_count % bytesPerSector);
if (max_count < bytesPerSector) max_count = bytesPerSector;

// Avoid SysTick interrupt pauses during the transfer
SysTick_Handle_PreEmptively();

processPollingWrite(max_count);
return isPollingWriteFinished(data);
}
Expand Down Expand Up @@ -483,6 +494,8 @@ extern "C" void scsiRead(uint8_t* data, uint32_t count, int* parityError)
uint32_t count_words = count / 4;
bool use_greenpak = (g_scsi_phy_mode == PHY_MODE_GREENPAK_DMA || g_scsi_phy_mode == PHY_MODE_GREENPAK_PIO);

SysTick_Handle_PreEmptively();

if (g_scsi_phase == DATA_OUT && scsiDev.target->syncOffset > 0)
{
// Synchronous data transfer
Expand Down
7 changes: 7 additions & 0 deletions lib/ZuluSCSI_platform_GD32F205/sd_card_sdio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,13 @@ bool SdioCard::readSectors(uint32_t sector, uint8_t* dst, size_t n)
get_stream_callback(dst, n * 512)));
}

// Check if a DMA request for SD card read has completed.
// This is used to optimize the timing of data transfers on SCSI bus.
bool check_sd_read_done()
{
return (DMA_CHCTL(DMA1, DMA_CH3) & DMA_CHXCTL_CHEN)
&& (DMA_INTF(DMA1) & DMA_FLAG_ADD(DMA_FLAG_FTF, DMA_CH3));
}

// These functions are not used for SDIO mode but are needed to avoid build error.
void sdCsInit(SdCsPin_t pin) {}
Expand Down
8 changes: 8 additions & 0 deletions lib/ZuluSCSI_platform_GD32F205/sd_card_spi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,4 +263,12 @@ void azplatform_set_sd_callback(sd_callback_t func, const uint8_t *buffer)
g_sd_spi_port.set_sd_callback(func, buffer);
}

// Check if a DMA request for SD card read has completed.
// This is used to optimize the timing of data transfers on SCSI bus.
bool check_sd_read_done()
{
return (DMA_CHCTL(DMA0, SD_SPI_RX_DMA_CHANNEL) & DMA_CHXCTL_CHEN)
&& (DMA_INTF(DMA0) & DMA_FLAG_ADD(DMA_FLAG_FTF, SD_SPI_RX_DMA_CHANNEL));
}

#endif
14 changes: 6 additions & 8 deletions src/ZuluSCSI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,12 +329,6 @@ bool findHDDImages()
}
root.close();

// Error if there are 0 image files
if(!foundImage) {
azlog("ERROR: No valid images found!");
blinkStatus(BLINK_ERROR_NO_IMAGES);
}

// Print SCSI drive map
for (int i = 0; i < NUM_SCSIID; i++)
{
Expand Down Expand Up @@ -381,9 +375,10 @@ static void reinitSCSI()
{
scsiDiskResetImages();
readSCSIDeviceConfig();
bool foundImage = findHDDImages();
findHDDImages();

if (foundImage)
// Error if there are 0 image files
if (scsiDiskCheckAnyImagesConfigured())
{
// Ok, there is an image
blinkStatus(BLINK_STATUS_OK);
Expand All @@ -394,7 +389,10 @@ static void reinitSCSI()
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, false);
#else
azlog("No valid image files found!");
#endif
blinkStatus(BLINK_ERROR_NO_IMAGES);
}

scsiPhyReset();
Expand Down
2 changes: 1 addition & 1 deletion src/ZuluSCSI_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#pragma once

// Use variables for version number
#define FW_VER_NUM "1.0.6"
#define FW_VER_NUM "1.0.7"
#define FW_VER_SUFFIX "release"
#define ZULU_FW_VERSION FW_VER_NUM "-" FW_VER_SUFFIX

Expand Down
58 changes: 49 additions & 9 deletions src/ZuluSCSI_disk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,9 @@ struct image_config_t: public S2S_TargetCfg

// Maximum amount of bytes to prefetch
int prefetchbytes;

// Warning about geometry settings
bool geometrywarningprinted;
};

static image_config_t g_DiskImages[S2S_MAX_TARGETS];
Expand Down Expand Up @@ -393,15 +396,6 @@ bool scsiDiskOpenHDDImage(int target_idx, const char *filename, int scsi_id, int
azlog("---- WARNING: file ", filename, " is not contiguous. This will increase read latency.");
}

uint32_t sectorsPerHeadTrack = img.sectorsPerTrack * img.headsPerCylinder;
if (img.scsiSectors % sectorsPerHeadTrack != 0)
{
azlog("---- NOTE: Drive geometry is ",
(int)img.sectorsPerTrack, "x", (int)img.headsPerCylinder, "=",
(int)sectorsPerHeadTrack, " but image size of ", (int)img.scsiSectors,
" is not divisible.");
}

if (is_cd)
{
azlog("---- Configuring as CD-ROM drive based on image name");
Expand Down Expand Up @@ -434,6 +428,23 @@ bool scsiDiskOpenHDDImage(int target_idx, const char *filename, int scsi_id, int
return false;
}

static void checkDiskGeometryDivisible(image_config_t &img)
{
if (!img.geometrywarningprinted)
{
uint32_t sectorsPerHeadTrack = img.sectorsPerTrack * img.headsPerCylinder;
if (img.scsiSectors % sectorsPerHeadTrack != 0)
{
azlog("WARNING: Host used command ", scsiDev.cdb[0],
" which is affected by drive geometry. Current settings are ",
(int)img.sectorsPerTrack, " sectors x ", (int)img.headsPerCylinder, " heads = ",
(int)sectorsPerHeadTrack, " but image size of ", (int)img.scsiSectors,
" sectors is not divisible. This can cause error messages in diagnostics tools.");
img.geometrywarningprinted = true;
}
}
}

// Set target configuration to default values
static void scsiDiskConfigDefaults(int target_idx)
{
Expand Down Expand Up @@ -521,6 +532,19 @@ void scsiDiskLoadConfig(int target_idx)
}
}

bool scsiDiskCheckAnyImagesConfigured()
{
for (int i = 0; i < S2S_MAX_TARGETS; i++)
{
if (g_DiskImages[i].file.isOpen() && (g_DiskImages[i].scsiId & S2S_CFG_TARGET_ENABLED))
{
return true;
}
}

return false;
}

/*******************************/
/* Config handling for SCSI2SD */
/*******************************/
Expand Down Expand Up @@ -1590,6 +1614,22 @@ void scsiDiskPoll()
{
diskDataOut();
}

if (scsiDev.phase == STATUS && scsiDev.target)
{
// Check if the command is affected by drive geometry.
// Affected commands are:
// 0x1A MODE SENSE command of pages 0x03 (device format), 0x04 (disk geometry) or 0x3F (all pages)
// 0x1C RECEIVE DIAGNOSTICS RESULTS
uint8_t command = scsiDev.cdb[0];
uint8_t pageCode = scsiDev.cdb[2] & 0x3F;
if ((command == 0x1A && (pageCode == 0x03 || pageCode == 0x04 || pageCode == 0x3F)) ||
command == 0x1C)
{
image_config_t &img = *(image_config_t*)scsiDev.target->cfg;
checkDiskGeometryDivisible(img);
}
}
}

extern "C"
Expand Down
3 changes: 3 additions & 0 deletions src/ZuluSCSI_disk.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@ extern "C" {
void scsiDiskResetImages();
bool scsiDiskOpenHDDImage(int target_idx, const char *filename, int scsi_id, int scsi_lun, int blocksize, bool is_cd, bool is_fd);
void scsiDiskLoadConfig(int target_idx);

// Returns true if there is at least one image active
bool scsiDiskCheckAnyImagesConfigured();

0 comments on commit dc30e55

Please sign in to comment.