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;
 }