diff --git a/hw/sd.c b/hw/sd.c
index 07eb263..220562e 100644
--- a/hw/sd.c
+++ b/hw/sd.c
@@ -52,6 +52,7 @@ typedef enum {
     sd_r7,        /* Operating voltage */
     sd_r1b = -1,
     sd_illegal = -2,
+    sd_r1_long = -3, /* Two byte status in SPI mode.  */
 } sd_rsp_type_t;
 
 struct SDState {
@@ -342,24 +343,93 @@ static int sd_req_crc_validate(SDRequest *req)
     return sd_crc7(buffer, 5) != req->crc;	/* TODO */
 }
 
-static void sd_response_r1_make(SDState *sd, uint8_t *response)
+
+/* Make SPI status word from full card status.  Most commands only use
+   the high byte.  */
+static uint16_t sd_get_spi_status(SDState *sd, uint32_t cardstatus)
+{
+    uint16_t status = 0;
+
+    if (((cardstatus >> 9) & 0xf) < 4)
+        status |= SPI_SDR_IDLE;
+    if (cardstatus & ERASE_RESET)
+        status |= SPI_SDR_ERASE_RESET;
+    if (cardstatus & ILLEGAL_COMMAND)
+        status |= SPI_SDR_ILLEGAL_COMMAND;
+    if (cardstatus & COM_CRC_ERROR)
+        status |= SPI_SDR_COM_CRC_ERROR;
+    if (cardstatus & ERASE_SEQ_ERROR)
+        status |= SPI_SDR_ERASE_SEQ_ERROR;
+    if (cardstatus & ADDRESS_ERROR)
+        status |= SPI_SDR_ADDRESS_ERROR;
+    if (cardstatus & CARD_IS_LOCKED)
+        status |= SPI_SDR_LOCKED;
+    if (cardstatus & (LOCK_UNLOCK_FAILED | WP_ERASE_SKIP))
+        status |= SPI_SDR_WP_ERASE;
+    if (cardstatus & SD_ERROR)
+        status |= SPI_SDR_ERROR;
+    if (cardstatus & CC_ERROR)
+        status |= SPI_SDR_CC_ERROR;
+    if (cardstatus & CARD_ECC_FAILED)
+        status |= SPI_SDR_ECC_FAILED;
+    if (cardstatus & WP_VIOLATION)
+        status |= SPI_SDR_WP_VIOLATION;
+    if (cardstatus & ERASE_PARAM)
+        status |= SPI_SDR_ERASE_PARAM;
+    if (cardstatus & (OUT_OF_RANGE | CID_CSD_OVERWRITE))
+        status |= SPI_SDR_OUT_OF_RANGE;
+    /* ??? Don't know what Parameter Error really means, so
+       assume it's set if the second byte is nonzero.  */
+    if (status & 0xff)
+        status |= SPI_SDR_PARAMETER_ERROR;
+
+    return status;
+}
+
+static int sd_response_r1_make(SDState *sd, uint8_t *response)
 {
     uint32_t status = sd->card_status;
     /* Clear the "clear on read" status bits */
     sd->card_status &= ~CARD_STATUS_C;
 
-    response[0] = (status >> 24) & 0xff;
-    response[1] = (status >> 16) & 0xff;
-    response[2] = (status >> 8) & 0xff;
-    response[3] = (status >> 0) & 0xff;
+    if (sd->spi) {
+        response[0] = sd_get_spi_status(sd, status) >> 8;
+        return 1;
+    } else {
+        response[0] = (status >> 24) & 0xff;
+        response[1] = (status >> 16) & 0xff;
+        response[2] = (status >> 8) & 0xff;
+        response[3] = (status >> 0) & 0xff;
+        return 4;
+    }
+}
+
+/* Only used in SPI mode.  */
+static int sd_response_r1_long_make(SDState *sd, uint8_t *response)
+{
+    uint32_t status = sd->card_status;
+    /* Clear the "clear on read" status bits */
+    sd->card_status &= ~CARD_STATUS_C;
+    status = sd_get_spi_status(sd, status);
+    response[0] = status >> 8;
+    response[1] = status & 0xff;
+    return 2;
 }
 
-static void sd_response_r3_make(SDState *sd, uint8_t *response)
+static int sd_response_r3_make(SDState *sd, uint8_t *response)
 {
-    response[0] = (sd->ocr >> 24) & 0xff;
-    response[1] = (sd->ocr >> 16) & 0xff;
-    response[2] = (sd->ocr >> 8) & 0xff;
-    response[3] = (sd->ocr >> 0) & 0xff;
+    int len = 4;
+
+    if (sd->spi) {
+        len = 5;
+        *(response++) = sd_get_spi_status(sd, sd->card_status) >> 8;
+    }
+    *(response++) = (sd->ocr >> 24) & 0xff;
+    *(response++) = (sd->ocr >> 16) & 0xff;
+    *(response++) = (sd->ocr >> 8) & 0xff;
+    *(response++) = (sd->ocr >> 0) & 0xff;
+
+    return len;
 }
 
 static void sd_response_r6_make(SDState *sd, uint8_t *response)
@@ -379,12 +449,20 @@ static void sd_response_r6_make(SDState *sd, uint8_t *response)
     response[3] = status & 0xff;
 }
 
-static void sd_response_r7_make(SDState *sd, uint8_t *response)
+static int sd_response_r7_make(SDState *sd, uint8_t *response)
 {
-    response[0] = (sd->vhs >> 24) & 0xff;
-    response[1] = (sd->vhs >> 16) & 0xff;
-    response[2] = (sd->vhs >>  8) & 0xff;
-    response[3] = (sd->vhs >>  0) & 0xff;
+    int len = 4;
+
+    if (sd->spi) {
+        len = 5;
+        *(response++) = sd_get_spi_status(sd, sd->card_status) >> 8;
+    }
+    *(response++) = (sd->vhs >> 24) & 0xff;
+    *(response++) = (sd->vhs >> 16) & 0xff;
+    *(response++) = (sd->vhs >>  8) & 0xff;
+    *(response++) = (sd->vhs >>  0) & 0xff;
+
+    return len;
 }
 
 static void sd_reset(SDState *sd, BlockDriverState *bdrv)
@@ -441,7 +519,7 @@ static const BlockDevOps sd_block_ops = {
 };
 
 /* We do not model the chip select pin, so allow the board to select
-   whether card should be in SSI or MMC/SD mode.  It is also up to the
+   whether card should be in SPI or MMC/SD mode.  It is also up to the
    board to ensure that ssi transfers only occur when the chip select
    is asserted.  */
 SDState *sd_init(BlockDriverState *bs, int is_spi)
@@ -843,7 +921,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
             if (sd->rca != rca)
                 return sd_r0;
 
-            return sd_r1;
+            return sd->spi ? sd_r1_long : sd_r1;
 
         default:
             break;
@@ -1339,8 +1417,11 @@ send_response:
     switch (rtype) {
     case sd_r1:
     case sd_r1b:
-        sd_response_r1_make(sd, response);
-        rsplen = 4;
+        rsplen = sd_response_r1_make(sd, response);
+        break;
+
+    case sd_r1_long:
+        rsplen = sd_response_r1_long_make(sd, response);
         break;
 
     case sd_r2_i:
@@ -1354,8 +1435,7 @@ send_response:
         break;
 
     case sd_r3:
-        sd_response_r3_make(sd, response);
-        rsplen = 4;
+        rsplen = sd_response_r3_make(sd, response);
         break;
 
     case sd_r6:
@@ -1364,8 +1444,7 @@ send_response:
         break;
 
     case sd_r7:
-        sd_response_r7_make(sd, response);
-        rsplen = 4;
+        rsplen = sd_response_r7_make(sd, response);
         break;
 
     case sd_r0:
diff --git a/hw/sd.h b/hw/sd.h
index ac4b7c4..9b95df9 100644
--- a/hw/sd.h
+++ b/hw/sd.h
@@ -51,6 +51,23 @@
 #define APP_CMD			(1 << 5)
 #define AKE_SEQ_ERROR		(1 << 3)
 
+/* SPI State word bits.  */
+#define SPI_SDR_LOCKED          0x0001
+#define SPI_SDR_WP_ERASE        0x0002
+#define SPI_SDR_ERROR           0x0004
+#define SPI_SDR_CC_ERROR        0x0008
+#define SPI_SDR_ECC_FAILED      0x0010
+#define SPI_SDR_WP_VIOLATION    0x0020
+#define SPI_SDR_ERASE_PARAM     0x0040
+#define SPI_SDR_OUT_OF_RANGE    0x0080
+#define SPI_SDR_IDLE            0x0100
+#define SPI_SDR_ERASE_RESET     0x0200
+#define SPI_SDR_ILLEGAL_COMMAND 0x0400
+#define SPI_SDR_COM_CRC_ERROR   0x0800
+#define SPI_SDR_ERASE_SEQ_ERROR 0x1000
+#define SPI_SDR_ADDRESS_ERROR   0x2000
+#define SPI_SDR_PARAMETER_ERROR 0x4000
+
 typedef enum {
     sd_none = -1,
     sd_bc = 0,	/* broadcast -- no response */
diff --git a/hw/ssi-sd.c b/hw/ssi-sd.c
index b519bdb..08d1e78 100644
--- a/hw/ssi-sd.c
+++ b/hw/ssi-sd.c
@@ -40,30 +40,13 @@ typedef struct {
     ssi_sd_mode mode;
     int cmd;
     uint8_t cmdarg[4];
-    uint8_t response[5];
+    uint8_t response[16];
     int arglen;
     int response_pos;
     int stopping;
     SDState *sd;
 } ssi_sd_state;
 
-/* State word bits.  */
-#define SSI_SDR_LOCKED          0x0001
-#define SSI_SDR_WP_ERASE        0x0002
-#define SSI_SDR_ERROR           0x0004
-#define SSI_SDR_CC_ERROR        0x0008
-#define SSI_SDR_ECC_FAILED      0x0010
-#define SSI_SDR_WP_VIOLATION    0x0020
-#define SSI_SDR_ERASE_PARAM     0x0040
-#define SSI_SDR_OUT_OF_RANGE    0x0080
-#define SSI_SDR_IDLE            0x0100
-#define SSI_SDR_ERASE_RESET     0x0200
-#define SSI_SDR_ILLEGAL_COMMAND 0x0400
-#define SSI_SDR_COM_CRC_ERROR   0x0800
-#define SSI_SDR_ERASE_SEQ_ERROR 0x1000
-#define SSI_SDR_ADDRESS_ERROR   0x2000
-#define SSI_SDR_PARAMETER_ERROR 0x4000
-
 static uint32_t ssi_sd_transfer(SSISlave *dev, uint32_t val)
 {
     ssi_sd_state *s = FROM_SSI_SLAVE(ssi_sd_state, dev);
@@ -88,73 +71,17 @@ static uint32_t ssi_sd_transfer(SSISlave *dev, uint32_t val)
     case SSI_SD_CMDARG:
         if (s->arglen == 4) {
             SDRequest request;
-            uint8_t longresp[16];
-            /* FIXME: Check CRC.  */
+            /* CRC check only needed when enabled by CMD59, which we don't
+               implement yet.  */
             request.cmd = s->cmd;
             request.arg = (s->cmdarg[0] << 24) | (s->cmdarg[1] << 16)
                            | (s->cmdarg[2] << 8) | s->cmdarg[3];
             DPRINTF("CMD%d arg 0x%08x\n", s->cmd, request.arg);
-            s->arglen = sd_do_command(s->sd, &request, longresp);
+            s->arglen = sd_do_command(s->sd, &request, s->response);
             if (s->arglen <= 0) {
                 s->arglen = 1;
-                s->response[0] = 4;
+                s->response[0] = SPI_SDR_PARAMETER_ERROR >> 8;
                 DPRINTF("SD command failed\n");
-            } else if (s->cmd == 58) {
-                /* CMD58 returns R3 response (OCR)  */
-                DPRINTF("Returned OCR\n");
-                s->arglen = 5;
-                s->response[0] = 1;
-                memcpy(&s->response[1], longresp, 4);
-            } else if (s->arglen != 4) {
-                BADF("Unexpected response to cmd %d\n", s->cmd);
-                /* Illegal command is about as near as we can get.  */
-                s->arglen = 1;
-                s->response[0] = 4;
-            } else {
-                /* All other commands return status.  */
-                uint32_t cardstatus;
-                uint16_t status;
-                /* CMD13 returns a 2-byte statuse work. Other commands
-                   only return the first byte.  */
-                s->arglen = (s->cmd == 13) ? 2 : 1;
-                cardstatus = (longresp[0] << 24) | (longresp[1] << 16)
-                             | (longresp[2] << 8) | longresp[3];
-                status = 0;
-                if (((cardstatus >> 9) & 0xf) < 4)
-                    status |= SSI_SDR_IDLE;
-                if (cardstatus & ERASE_RESET)
-                    status |= SSI_SDR_ERASE_RESET;
-                if (cardstatus & ILLEGAL_COMMAND)
-                    status |= SSI_SDR_ILLEGAL_COMMAND;
-                if (cardstatus & COM_CRC_ERROR)
-                    status |= SSI_SDR_COM_CRC_ERROR;
-                if (cardstatus & ERASE_SEQ_ERROR)
-                    status |= SSI_SDR_ERASE_SEQ_ERROR;
-                if (cardstatus & ADDRESS_ERROR)
-                    status |= SSI_SDR_ADDRESS_ERROR;
-                if (cardstatus & CARD_IS_LOCKED)
-                    status |= SSI_SDR_LOCKED;
-                if (cardstatus & (LOCK_UNLOCK_FAILED | WP_ERASE_SKIP))
-                    status |= SSI_SDR_WP_ERASE;
-                if (cardstatus & SD_ERROR)
-                    status |= SSI_SDR_ERROR;
-                if (cardstatus & CC_ERROR)
-                    status |= SSI_SDR_CC_ERROR;
-                if (cardstatus & CARD_ECC_FAILED)
-                    status |= SSI_SDR_ECC_FAILED;
-                if (cardstatus & WP_VIOLATION)
-                    status |= SSI_SDR_WP_VIOLATION;
-                if (cardstatus & ERASE_PARAM)
-                    status |= SSI_SDR_ERASE_PARAM;
-                if (cardstatus & (OUT_OF_RANGE | CID_CSD_OVERWRITE))
-                    status |= SSI_SDR_OUT_OF_RANGE;
-                /* ??? Don't know what Parameter Error really means, so
-                   assume it's set if the second byte is nonzero.  */
-                if (status & 0xff)
-                    status |= SSI_SDR_PARAMETER_ERROR;
-                s->response[0] = status >> 8;
-                s->response[1] = status;
-                DPRINTF("Card status 0x%02x\n", status);
             }
             s->mode = SSI_SD_RESPONSE;
             s->response_pos = 0;
