Index: firmware/target/arm/as3525/debug-as3525.c
===================================================================
--- firmware/target/arm/as3525/debug-as3525.c (revision 27164)
+++ firmware/target/arm/as3525/debug-as3525.c (working copy)
@@ -268,6 +268,30 @@
{
while(1)
{
+ int i;
+ extern int sd_cmds_submitted[NUM_VOLUMES];
+ extern int sd_cmds_errors[NUM_VOLUMES];
+ extern int sd_transfers[NUM_VOLUMES];
+ extern int sd_transfer_errors[NUM_VOLUMES];
+ lcd_clear_display();
+ line = 0;
+ lcd_puts(0, line++, "[SD error stats]");
+ for (i=0; i<NUM_VOLUMES; i++) {
+ lcd_putsf(0, line++, "Drive %d errors:", i);
+ lcd_putsf(0, line++, "cmd %d of %d",
+ sd_cmds_errors[i], sd_cmds_submitted[i]);
+ lcd_putsf(0, line++, "r/w %d of %d",
+ sd_transfer_errors[i], sd_transfers[i]);
+ }
+ lcd_update();
+ int btn = button_get_w_tmo(HZ/10);
+ if(btn == (DEBUG_CANCEL|BUTTON_REL))
+ goto end;
+ else if(btn == (BUTTON_DOWN|BUTTON_REL))
+ break;
+ }
+ while(1)
+ {
#ifdef SANSA_C200V2
lcd_clear_display();
line = 0;
Index: firmware/target/arm/as3525/sd-as3525.c
===================================================================
--- firmware/target/arm/as3525/sd-as3525.c (revision 27165)
+++ firmware/target/arm/as3525/sd-as3525.c (working copy)
@@ -45,12 +45,15 @@
#include "ata_idle_notify.h"
#include "sd.h"
#include "usb.h"
+#define LOGF_ENABLE
+#include "logf.h"

#ifdef HAVE_HOTSWAP
#include "disk.h"
#endif

#define VERIFY_WRITE 1
+#define VERIFY_READ 1

/* command flags */
#define MCI_NO_RESP (0<<0)
@@ -126,6 +129,11 @@
static struct event_queue sd_queue;
bool sd_enabled = false;

+int sd_cmds_submitted[NUM_VOLUMES];
+int sd_cmds_errors[NUM_VOLUMES];
+int sd_transfers[NUM_VOLUMES];
+int sd_transfer_errors[NUM_VOLUMES];
+
#if defined(HAVE_MULTIDRIVE)
static bool hs_card = false;
#define EXT_SD_BITS (1<<2)
@@ -138,6 +146,7 @@
#define UNALIGNED_NUM_SECTORS 10
static unsigned char aligned_buffer[UNALIGNED_NUM_SECTORS* SD_BLOCK_SIZE] __attribute__((aligned(32))); /* align on cache line size */
static unsigned char *uncached_buffer = AS3525_UNCACHED_ADDR(&aligned_buffer[0]);
+static unsigned char compare_buffer[UNALIGNED_NUM_SECTORS* SD_BLOCK_SIZE];


static inline void mci_delay(void) { udelay(1000) ; }
@@ -207,6 +216,8 @@
{
int status;

+ sd_cmds_submitted[drive]++;
+
unsigned cmd_retries = 6;
while(cmd_retries--)
{
@@ -236,8 +247,17 @@
{
response[0] = MCI_RESP0(drive); /* Always prepare short response */

- if(status & MCI_RESPONSE_ERROR) /* timeout or crc failure */
+ if(status & MCI_RESPONSE_ERROR) {/* timeout or crc failure */
+ long response = 0;
+ if (cmd != SD_SEND_STATUS) {
+ if (!send_cmd(drive, SD_SEND_STATUS, card_info[drive].rca,
+ MCI_RESP, &response))
+ status = -1;
+ }
+ logf("sd_cmd error: drive %d cmd %d arg %08x sd_status %08x card_status %08lx\n", drive, cmd, arg, status, response);
+ sd_cmds_errors[drive]++;
continue;
+ }

if(status & MCI_CMD_RESP_END) /* Response passed CRC check */
{
@@ -597,7 +617,7 @@
while (1)
{
if(!send_cmd(drive, SD_SEND_STATUS, card_info[drive].rca, MCI_RESP,
- &response))
+ &response))
return -1;

if (((response >> 9) & 0xf) == SD_TRAN)
@@ -689,7 +709,7 @@
unsigned long response;
bool aligned = !((uintptr_t)buf & (CACHEALIGN_SIZE - 1));

- mutex_lock(&sd_mtx);
+ sd_transfers[drive]++;
sd_enable(true);
led(true);

@@ -824,6 +844,7 @@
(9<<4) /* 2^9 = 512 */ ;

/* Wakeup signal from NAND/MCIO isr on MCI_DATA_ERROR | MCI_DATA_END */
+ //while (!(volatile int)transfer_completion_signal.signalled);
wakeup_wait(&transfer_completion_signal, TIMEOUT_BLOCK);

/* Wait for FIFO to empty, card may still be in PRG state for writes */
@@ -853,9 +874,12 @@
count -= transfer;
loops = 0; /* reset errors counter */
}
- else if(loops++ > PL180_MAX_TRANSFER_ERRORS)
+ else {
+ sd_transfer_errors[drive]++;
+ if(loops++ > PL180_MAX_TRANSFER_ERRORS)
panicf("SD Xfer %s err:0x%x Disk%d", (write? "write": "read"),
transfer_error[drive], drive);
+ }
}

sd_transfer_error:
@@ -870,14 +894,64 @@
if (ret) /* error */
card_info[drive].initialized = 0;

- mutex_unlock(&sd_mtx);
return ret;
}

+char panicbuf[500];
+
int sd_read_sectors(IF_MD2(int drive,) unsigned long start, int count,
void* buf)
{
- return sd_transfer_sectors(IF_MD2(drive,) start, count, buf, false);
+ int ret;
+
+ mutex_lock(&sd_mtx);
+
+ ret = sd_transfer_sectors(IF_MD2(drive,) start, count, buf, false);
+
+#ifdef VERIFY_READ
+ if (ret) /* read failed, no point in verifying? */
+ goto read_error;
+
+ while (count) {
+ char *buf2 = buf;
+ int transfer = count;
+ int i = 0;
+ if(transfer > UNALIGNED_NUM_SECTORS)
+ transfer = UNALIGNED_NUM_SECTORS;
+
+ ret = sd_transfer_sectors(IF_MD2(drive,) start, transfer, compare_buffer, false);
+ if (ret != 0)
+ panicf("sd%d: read verify failed: sec=%ld n=%d: retval %d", drive, start, transfer, ret);
+
+ for (i=0; i<transfer*512; i++) {
+ int n=sizeof(panicbuf);
+ int j=i;
+ char *s=panicbuf;
+
+ if (compare_buffer[i] == buf2[i])
+ continue;
+
+ while (n>=5 && j<transfer*512) { /* 4 characters + null */
+ snprintf(s, n, "%02x%02x",
+ (unsigned char)buf2[j],
+ (unsigned char)compare_buffer[j]);
+ s += 4;
+ n -= 4;
+ j++;
+ }
+
+ panicf("sd%d: read verify failed: sec=%ld n=%d %d: %s", drive, start, transfer, i, panicbuf);
+ }
+
+ buf += transfer * 512;
+ count -= transfer;
+ start += transfer;
+ }
+
+#endif
+read_error:
+ mutex_unlock(&sd_mtx);
+ return ret;
}

int sd_write_sectors(IF_MD2(int drive,) unsigned long start, int count,
@@ -890,11 +964,13 @@
#endif
int ret;

+ mutex_lock(&sd_mtx);
+
ret = sd_transfer_sectors(IF_MD2(drive,) start, count, (void*)buf, true);

#ifdef VERIFY_WRITE
if (ret) /* write failed, no point in verifying */
- return ret;
+ goto write_error;

count = saved_count;
buf = saved_buf;
@@ -904,11 +980,11 @@
if(transfer > UNALIGNED_NUM_SECTORS)
transfer = UNALIGNED_NUM_SECTORS;

- sd_transfer_sectors(IF_MD2(drive,) start, transfer, aligned_buffer, false);
- if (memcmp(buf, aligned_buffer, transfer * 512) != 0) {
+ sd_transfer_sectors(IF_MD2(drive,) start, transfer, compare_buffer, false);
+ if (memcmp(buf, compare_buffer, transfer * 512) != 0) {
/* try the write again in the hope to repair the damage */
sd_transfer_sectors(IF_MD2(drive,) saved_start, saved_count, saved_buf, true);
- panicf("sd: verify failed: sec=%ld n=%d!", start, transfer);
+ panicf("sd%d: write verify failed: sec=%ld n=%d!", drive, start, transfer);
}

buf += transfer * 512;
@@ -916,6 +992,8 @@
start += transfer;
}
#endif
+write_error:
+ mutex_unlock(&sd_mtx);
return ret;
}