Author: blueswirl Date: Sat Aug 20 14:10:07 2011 New Revision: 1047 URL: http://tracker.coreboot.org/trac/openbios/changeset/1047
Log: ESP: clear Unit Attention condition after reset
In recent QEMU, SCSI devices are in Unit Attention condition after reset and this made Read Capacity command fail.
Fix by sending a Test Unit Ready command to the devices first.
Also avoid division by zero if block size is 0 when Read Capacity fails.
Thanks to Paolo Bonzini for analysis.
Signed-off-by: Blue Swirl blauwirbel@gmail.com
Modified: trunk/openbios-devel/drivers/esp.c
Modified: trunk/openbios-devel/drivers/esp.c ============================================================================== --- trunk/openbios-devel/drivers/esp.c Mon Aug 8 14:33:10 2011 (r1046) +++ trunk/openbios-devel/drivers/esp.c Sat Aug 20 14:10:07 2011 (r1047) @@ -108,11 +108,17 @@
DPRINTF("do_command: id %d, cmd[0] 0x%x, status 0x%x\n", sd->id, esp->buffer[0], status);
- // Target didn't want all command data or went to status phase - // instead of data phase? - if ((status & ESP_STAT_TCNT) != ESP_STAT_TCNT - || (status & ESP_STAT_PMASK) == ESP_STATP) + /* Target didn't want all command data? */ + if ((status & ESP_STAT_TCNT) != ESP_STAT_TCNT) { return status; + } + if (replylen == 0) { + return 0; + } + /* Target went to status phase instead of data phase? */ + if ((status & ESP_STAT_PMASK) == ESP_STATP) { + return status; + }
// Get reply // Set DMA address @@ -176,12 +182,31 @@ if (do_command(esp, sd, 11, 8)) { sd->sectors = 0; sd->bs = 0; - + DPRINTF("read_capacity id %d failed\n", sd->id); return 0; } sd->bs = (esp->buffer[4] << 24) | (esp->buffer[5] << 16) | (esp->buffer[6] << 8) | esp->buffer[7]; sd->sectors = ((esp->buffer[0] << 24) | (esp->buffer[1] << 16) | (esp->buffer[2] << 8) | esp->buffer[3]) * (sd->bs / 512);
+ DPRINTF("read_capacity id %d bs %d sectors %d\n", sd->id, sd->bs, + sd->sectors); + return 1; +} + +static unsigned int +test_unit_ready(esp_private_t *esp, sd_private_t *sd) +{ + /* Setup command = Test Unit Ready */ + memset(esp->buffer, 0, 6); + esp->buffer[0] = 0x80; + esp->buffer[1] = TEST_UNIT_READY; + + if (do_command(esp, sd, 6, 0)) { + DPRINTF("test_unit_ready id %d failed\n", sd->id); + return 0; + } + + DPRINTF("test_unit_ready id %d success\n", sd->id); return 1; }
@@ -234,6 +259,10 @@
DPRINTF("ob_sd_read_blocks id %d %lx block=%d n=%d\n", (*sd)->id, (unsigned long)dest, blk, n );
+ if ((*sd)->bs == 0) { + PUSH(0); + return; + } spb = (*sd)->bs / 512; while (n) { sect_offset = blk / spb; @@ -438,6 +467,7 @@ int id, diskcount = 0, cdcount = 0, *counter_ptr; char nodebuff[256], aliasbuff[256]; esp_private_t *esp; + unsigned int i;
DPRINTF("Initializing SCSI...");
@@ -476,8 +506,21 @@
for (id = 0; id < 8; id++) { esp->sd[id].id = id; - if (!inquiry(esp, &esp->sd[id])) + if (!inquiry(esp, &esp->sd[id])) { + DPRINTF("Unit %d not present\n", id); continue; + } + /* Clear Unit Attention condition from reset */ + for (i = 0; i < 5; i++) { + if (test_unit_ready(esp, &esp->sd[id])) { + break; + } + } + if (i == 5) { + DPRINTF("Unit %d present but won't become ready\n", id); + continue; + } + DPRINTF("Unit %d present\n", id); read_capacity(esp, &esp->sd[id]);
#ifdef CONFIG_DEBUG_ESP