From 04ab950e5cb48406fbaffc3a7c564af5b9ba4aba Mon Sep 17 00:00:00 2001 From: Petteri Aimonen Date: Wed, 24 Aug 2022 10:29:19 +0300 Subject: [PATCH 1/5] Disable raw fallback when image is specified through .ini (ZuluSCSI/ZuluSCSI-firmware#39) Changed so that code properly checks for image specified through any means, not just through filename lookup. --- src/ZuluSCSI.cpp | 14 ++++++-------- src/ZuluSCSI_disk.cpp | 13 +++++++++++++ src/ZuluSCSI_disk.h | 3 +++ 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/ZuluSCSI.cpp b/src/ZuluSCSI.cpp index d53ed953..de126438 100644 --- a/src/ZuluSCSI.cpp +++ b/src/ZuluSCSI.cpp @@ -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++) { @@ -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); @@ -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(); diff --git a/src/ZuluSCSI_disk.cpp b/src/ZuluSCSI_disk.cpp index 8e8b66d8..e1333ac2 100644 --- a/src/ZuluSCSI_disk.cpp +++ b/src/ZuluSCSI_disk.cpp @@ -521,6 +521,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 */ /*******************************/ diff --git a/src/ZuluSCSI_disk.h b/src/ZuluSCSI_disk.h index fa095373..c03f68e0 100644 --- a/src/ZuluSCSI_disk.h +++ b/src/ZuluSCSI_disk.h @@ -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(); \ No newline at end of file From 2a0f42a2d99c536283decd40dfc01c132376a3d1 Mon Sep 17 00:00:00 2001 From: Petteri Aimonen Date: Wed, 24 Aug 2022 10:59:31 +0300 Subject: [PATCH 2/5] Show warning about undivisible image size only when host queries disk geometry (#35) --- src/ZuluSCSI_disk.cpp | 45 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/src/ZuluSCSI_disk.cpp b/src/ZuluSCSI_disk.cpp index e1333ac2..ea803047 100644 --- a/src/ZuluSCSI_disk.cpp +++ b/src/ZuluSCSI_disk.cpp @@ -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]; @@ -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"); @@ -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) { @@ -1603,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" From bf78bfd39d6f3bfebe7e0c491bf1324fb8f2e05b Mon Sep 17 00:00:00 2001 From: Petteri Aimonen Date: Wed, 24 Aug 2022 11:55:52 +0300 Subject: [PATCH 3/5] Fix pauses during transfer in PIO mode (#70) Some SCSI hosts expect that a whole sector is transferred without any gaps. This was previously fixed for DMA modes, but the PIO mode still had some pauses. --- lib/ZuluSCSI_platform_GD32F205/ZuluSCSI_platform.h | 4 ++++ lib/ZuluSCSI_platform_GD32F205/scsiPhy.cpp | 14 +++++++++++--- lib/ZuluSCSI_platform_GD32F205/sd_card_sdio.cpp | 7 +++++++ lib/ZuluSCSI_platform_GD32F205/sd_card_spi.cpp | 8 ++++++++ 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/lib/ZuluSCSI_platform_GD32F205/ZuluSCSI_platform.h b/lib/ZuluSCSI_platform_GD32F205/ZuluSCSI_platform.h index 7e34d7dc..fd5b20fe 100644 --- a/lib/ZuluSCSI_platform_GD32F205/ZuluSCSI_platform.h +++ b/lib/ZuluSCSI_platform_GD32F205/ZuluSCSI_platform.h @@ -145,4 +145,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 diff --git a/lib/ZuluSCSI_platform_GD32F205/scsiPhy.cpp b/lib/ZuluSCSI_platform_GD32F205/scsiPhy.cpp index ee7f4409..0fded4b7 100644 --- a/lib/ZuluSCSI_platform_GD32F205/scsiPhy.cpp +++ b/lib/ZuluSCSI_platform_GD32F205/scsiPhy.cpp @@ -418,13 +418,21 @@ 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; + processPollingWrite(max_count); return isPollingWriteFinished(data); } diff --git a/lib/ZuluSCSI_platform_GD32F205/sd_card_sdio.cpp b/lib/ZuluSCSI_platform_GD32F205/sd_card_sdio.cpp index df8022e5..e2bcc604 100644 --- a/lib/ZuluSCSI_platform_GD32F205/sd_card_sdio.cpp +++ b/lib/ZuluSCSI_platform_GD32F205/sd_card_sdio.cpp @@ -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) {} diff --git a/lib/ZuluSCSI_platform_GD32F205/sd_card_spi.cpp b/lib/ZuluSCSI_platform_GD32F205/sd_card_spi.cpp index 4116bf69..3322c43f 100644 --- a/lib/ZuluSCSI_platform_GD32F205/sd_card_spi.cpp +++ b/lib/ZuluSCSI_platform_GD32F205/sd_card_spi.cpp @@ -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 \ No newline at end of file From d2ec6209249d059693305213a86402afa7826999 Mon Sep 17 00:00:00 2001 From: Petteri Aimonen Date: Wed, 24 Aug 2022 12:09:46 +0300 Subject: [PATCH 4/5] Avoid SysTick interrupts during transfers (#70) SysTick interrupts caused short 0.7 us pauses during PIO reads and all writes. The pauses are probably short enough not to disturb most hosts. This commit avoids the pauses by executing the SysTick interrupt before the sector transfer if needed. If host transfer rate is below 500kB/s, the SysTick interrupt will still happen every 1 ms during the sector. But in that case the SCSI cycle time is more than 2 us anyway, so the pause is insignificant. --- .../ZuluSCSI_platform.cpp | 24 +++++++++++++++++++ .../ZuluSCSI_platform.h | 5 ++++ lib/ZuluSCSI_platform_GD32F205/scsiPhy.cpp | 5 ++++ 3 files changed, 34 insertions(+) diff --git a/lib/ZuluSCSI_platform_GD32F205/ZuluSCSI_platform.cpp b/lib/ZuluSCSI_platform_GD32F205/ZuluSCSI_platform.cpp index 70d6e8f7..a8059f14 100644 --- a/lib/ZuluSCSI_platform_GD32F205/ZuluSCSI_platform.cpp +++ b/lib/ZuluSCSI_platform_GD32F205/ZuluSCSI_platform.cpp @@ -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 */ /***************/ diff --git a/lib/ZuluSCSI_platform_GD32F205/ZuluSCSI_platform.h b/lib/ZuluSCSI_platform_GD32F205/ZuluSCSI_platform.h index fd5b20fe..3594fb22 100644 --- a/lib/ZuluSCSI_platform_GD32F205/ZuluSCSI_platform.h +++ b/lib/ZuluSCSI_platform_GD32F205/ZuluSCSI_platform.h @@ -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) diff --git a/lib/ZuluSCSI_platform_GD32F205/scsiPhy.cpp b/lib/ZuluSCSI_platform_GD32F205/scsiPhy.cpp index 0fded4b7..f3530702 100644 --- a/lib/ZuluSCSI_platform_GD32F205/scsiPhy.cpp +++ b/lib/ZuluSCSI_platform_GD32F205/scsiPhy.cpp @@ -433,6 +433,9 @@ extern "C" bool scsiIsWriteFinished(const uint8_t *data) 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); } @@ -491,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 From c7380b6fe4493072fe912326e0b79f1a8610e099 Mon Sep 17 00:00:00 2001 From: Alex Perez Date: Wed, 24 Aug 2022 17:38:20 -0700 Subject: [PATCH 5/5] bump rev --- src/ZuluSCSI_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ZuluSCSI_config.h b/src/ZuluSCSI_config.h index c37533ea..8f0e1822 100644 --- a/src/ZuluSCSI_config.h +++ b/src/ZuluSCSI_config.h @@ -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