|  | @@ -548,6 +548,29 @@ int scsiDiskCommand()
 | 
	
		
			
				|  |  |  	return commandHandled;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +static uint32_t
 | 
	
		
			
				|  |  | +calcReadahead(uint32_t totalBytes, uint32_t sdSpeedKBs, uint32_t scsiSpeedKBs)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	if (scsiSpeedKBs == 0 || scsiDev.hostSpeedMeasured == 0)
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		return totalBytes;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	// uint32_t readAheadBytes = totalBytes * (1 - scsiSpeedKBs / sdSpeedKBs);
 | 
	
		
			
				|  |  | +	// Won't overflow with 65536 max bytes, 20000 max scsi speed.
 | 
	
		
			
				|  |  | +	uint32_t readAheadBytes = totalBytes - totalBytes * scsiSpeedKBs / sdSpeedKBs;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	// Round up to nearest FIFO size (* 4 for safety)
 | 
	
		
			
				|  |  | +	readAheadBytes = ((readAheadBytes / SCSI_FIFO_DEPTH) + 4) * SCSI_FIFO_DEPTH;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (readAheadBytes > totalBytes)
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		readAheadBytes = totalBytes;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return readAheadBytes;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  void scsiDiskPoll()
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |  	uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;
 | 
	
	
		
			
				|  | @@ -704,18 +727,16 @@ void scsiDiskPoll()
 | 
	
		
			
				|  |  |  				transfer.lba);
 | 
	
		
			
				|  |  |  		int i = 0;
 | 
	
		
			
				|  |  |  		int clearBSY = 0;
 | 
	
		
			
				|  |  | -		int extraSectors = 0;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  		int parityError = 0;
 | 
	
		
			
				|  |  |  		int enableParity = scsiDev.boardCfg.flags & S2S_CFG_ENABLE_PARITY;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -		uint32_t scsiSpeed = s2s_getScsiRateMBs();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  		uint32_t maxSectors = sizeof(scsiDev.data) / SD_SECTOR_SIZE;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  		static_assert(SCSI_XFER_MAX >= sizeof(scsiDev.data), "Assumes SCSI_XFER_MAX >= sizeof(scsiDev.data)");
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  		// Start reading and filling fifos as soon as possible.
 | 
	
		
			
				|  |  | +		DWT->CYCCNT = 0; // Start counting cycles
 | 
	
		
			
				|  |  |  		scsiSetDataCount(transfer.blocks * bytesPerSector);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  		while ((i < totalSDSectors) &&
 | 
	
	
		
			
				|  | @@ -733,31 +754,15 @@ void scsiDiskPoll()
 | 
	
		
			
				|  |  |  				// no flow control. This can be handled if a) the scsi interface
 | 
	
		
			
				|  |  |  				// doesn't block and b) we read enough SCSI sectors first so that
 | 
	
		
			
				|  |  |  				// the SD interface cannot catch up.
 | 
	
		
			
				|  |  | -				int prevExtraSectors = extraSectors;
 | 
	
		
			
				|  |  |  				uint32_t totalBytes = sectors * SD_SECTOR_SIZE;
 | 
	
		
			
				|  |  | -				extraSectors = 0;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -				int32_t readAheadBytes = totalBytes;
 | 
	
		
			
				|  |  | -				uint32_t sdSpeed = s2s_getSdRateMBs() + (scsiDev.sdUnderrunCount / 2);
 | 
	
		
			
				|  |  | -				// if (have blind writes)
 | 
	
		
			
				|  |  | -				if (scsiSpeed > 0 && scsiDev.sdUnderrunCount < 16)
 | 
	
		
			
				|  |  | -				{
 | 
	
		
			
				|  |  | -					// readAhead = sectors * (sd / scsi - 1 + 0.1);
 | 
	
		
			
				|  |  | -					readAheadBytes = totalBytes * sdSpeed / scsiSpeed - totalBytes;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -					// Round up to nearest FIFO size.
 | 
	
		
			
				|  |  | -					readAheadBytes = ((readAheadBytes / SCSI_FIFO_DEPTH) + 1) * SCSI_FIFO_DEPTH;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -					if (readAheadBytes > totalBytes)
 | 
	
		
			
				|  |  | -					{
 | 
	
		
			
				|  |  | -						readAheadBytes = totalBytes;
 | 
	
		
			
				|  |  | -					}
 | 
	
		
			
				|  |  | -				}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -				uint32_t prevExtraBytes = prevExtraSectors * SD_SECTOR_SIZE;
 | 
	
		
			
				|  |  | -				uint32_t scsiBytesRead = prevExtraBytes;
 | 
	
		
			
				|  |  | -				readAheadBytes -= prevExtraBytes; // Must be signed!
 | 
	
		
			
				|  |  | +				uint32_t sdSpeedKBs = s2s_getSdRateKBs() + (scsiDev.sdUnderrunCount * 256);
 | 
	
		
			
				|  |  | +				uint32_t readAheadBytes = calcReadahead(
 | 
	
		
			
				|  |  | +					totalBytes,
 | 
	
		
			
				|  |  | +					sdSpeedKBs,
 | 
	
		
			
				|  |  | +					scsiDev.hostSpeedKBs);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +				uint32_t scsiBytesRead = 0;
 | 
	
		
			
				|  |  |  				if (readAheadBytes > 0)
 | 
	
		
			
				|  |  |  				{
 | 
	
		
			
				|  |  |  					scsiReadPIO(
 | 
	
	
		
			
				|  | @@ -765,6 +770,42 @@ void scsiDiskPoll()
 | 
	
		
			
				|  |  |  						readAheadBytes,
 | 
	
		
			
				|  |  |  						&parityError);
 | 
	
		
			
				|  |  |  					scsiBytesRead += readAheadBytes;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +					if (i == 0)
 | 
	
		
			
				|  |  | +					{
 | 
	
		
			
				|  |  | +						uint32_t elapsedCycles = DWT->CYCCNT;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +						// uint32_t rateKBs = (readAheadBytes / 1000) / (elapsedCycles / HAL_RCC_GetHCLKFreq());
 | 
	
		
			
				|  |  | +						// Scaled by 4 to avoid overflow w/ max 65536 at 108MHz.
 | 
	
		
			
				|  |  | +						uint32_t rateKBs = ((readAheadBytes / 4) * (HAL_RCC_GetHCLKFreq() / 1000) / elapsedCycles) * 4;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +						scsiDev.hostSpeedKBs = (scsiDev.hostSpeedKBs + rateKBs) / 2;
 | 
	
		
			
				|  |  | +						scsiDev.hostSpeedMeasured = 1;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +						if (rateKBs < scsiDev.hostSpeedKBs)
 | 
	
		
			
				|  |  | +						{
 | 
	
		
			
				|  |  | +							// Our readahead was too slow; assume remaining bytes
 | 
	
		
			
				|  |  | +							// will be as well.
 | 
	
		
			
				|  |  | +							if (readAheadBytes < totalBytes)
 | 
	
		
			
				|  |  | +							{
 | 
	
		
			
				|  |  | +								uint32_t properReadahead = calcReadahead(
 | 
	
		
			
				|  |  | +									totalBytes,
 | 
	
		
			
				|  |  | +									sdSpeedKBs,
 | 
	
		
			
				|  |  | +									rateKBs);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +								if (properReadahead > readAheadBytes)
 | 
	
		
			
				|  |  | +								{
 | 
	
		
			
				|  |  | +									uint32_t diff = properReadahead - readAheadBytes;
 | 
	
		
			
				|  |  | +									readAheadBytes = properReadahead;
 | 
	
		
			
				|  |  | +									scsiReadPIO(
 | 
	
		
			
				|  |  | +										&scsiDev.data[scsiBytesRead],
 | 
	
		
			
				|  |  | +										diff,
 | 
	
		
			
				|  |  | +										&parityError);
 | 
	
		
			
				|  |  | +									scsiBytesRead += diff;
 | 
	
		
			
				|  |  | +								}
 | 
	
		
			
				|  |  | +							}
 | 
	
		
			
				|  |  | +						}
 | 
	
		
			
				|  |  | +					}
 | 
	
		
			
				|  |  |  				}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  				HAL_SD_WriteBlocks_DMA(&hsd, (uint32_t*) (&scsiDev.data[0]), (i + sdLBA) * 512ll, SD_SECTOR_SIZE, sectors);
 | 
	
	
		
			
				|  | @@ -783,22 +824,6 @@ void scsiDiskPoll()
 | 
	
		
			
				|  |  |  					scsiBytesRead += (totalBytes - readAheadBytes);
 | 
	
		
			
				|  |  |  				}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -				if (!underrun && rem > sectors)
 | 
	
		
			
				|  |  | -				{
 | 
	
		
			
				|  |  | -					// We probably have some time to waste reading more here.
 | 
	
		
			
				|  |  | -					// While noting this is going to drop us down into
 | 
	
		
			
				|  |  | -					// half-duplex operation (hence why we read max / 4 only)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -					extraSectors = rem - sectors > (maxSectors / 4)
 | 
	
		
			
				|  |  | -						? (maxSectors / 4)
 | 
	
		
			
				|  |  | -						: rem - sectors;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -					scsiReadPIO(
 | 
	
		
			
				|  |  | -						&scsiDev.data[0],
 | 
	
		
			
				|  |  | -						extraSectors * SD_SECTOR_SIZE,
 | 
	
		
			
				|  |  | -						&parityError);
 | 
	
		
			
				|  |  | -				}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  				uint32_t dmaFinishTime = s2s_getTime_ms();
 | 
	
		
			
				|  |  |  				while ((!hsd.SdTransferCplt ||
 | 
	
		
			
				|  |  |  						__HAL_SD_SDIO_GET_FLAG(&hsd, SDIO_FLAG_TXACT)) &&
 |