#include "byteorder.h"
#include "disc.h"
#include "dvd_drive.h"
+#include "nintendo_disc_header.h"
+#include "xbox_ref/xbox_ref_log.h"
static void hlds_e7_visible_probe_log (const char *fmt, ...) {
static bool started = false;
/* Read cache */
u_int32_t cache_size; //!< The number of blocks that will be cached when read.
bool hlds_e7_read_schedule_logged; //!< True once the selected HLDS 0xE7 read schedule has been logged for this run.
+ bool seed_diagnostic_active; //!< True while the initial 20 Nintendo seed blocks are being acquired.
+ unsigned int seed_diagnostic_block; //!< Zero-based seed-block index currently being acquired.
+ disc_seed_diagnostic seed_diagnostic; //!< Last actionable seed/cache failure evidence.
u_int8_t **raw_cache; //!< Memory area for raw sectors cache.
u_int8_t **cache; //!< Memory area for unscrambled sectors cache.
u_int32_t *cache_map; //!< Data structure used by the caching system to know which blocks are in memory.
};
+
+static void disc_seed_diag_clear (disc *d) {
+ if (!d)
+ return;
+ memset (&d -> seed_diagnostic, 0, sizeof (d -> seed_diagnostic));
+}
+
+static void disc_seed_diag_log (disc *d, const char *fmt, ...) {
+ va_list ap;
+ if (!d || !d -> seed_diagnostic_active || !fmt)
+ return;
+ xbox_ref_log_fprintf (stderr, "[SEED-DIAG] ");
+ va_start (ap, fmt);
+ /* xbox_ref_log_fprintf is variadic rather than vfprintf-based, so format
+ * into a bounded buffer before sending the line to both console and log. */
+ {
+ char line[768];
+ vsnprintf (line, sizeof (line), fmt, ap);
+ xbox_ref_log_fprintf (stderr, "%s\n", line);
+ }
+ va_end (ap);
+}
+
+static void disc_seed_diag_fail (
+ disc *d,
+ u_int32_t sector_start,
+ u_int32_t sector_end,
+ int retry,
+ const char *stage,
+ const char *detail,
+ int transport_result,
+ bool capture_command
+) {
+ dvd_command_diagnostic command;
+ char cdb_text[3 * 12 + 1];
+ int i;
+ int used;
+
+ if (!d || !d -> seed_diagnostic_active)
+ return;
+ disc_seed_diag_clear (d);
+ d -> seed_diagnostic.valid = true;
+ d -> seed_diagnostic.seed_block_index = d -> seed_diagnostic_block;
+ d -> seed_diagnostic.sector_start = sector_start;
+ d -> seed_diagnostic.sector_end = sector_end;
+ d -> seed_diagnostic.retry = retry;
+ snprintf (d -> seed_diagnostic.stage, sizeof (d -> seed_diagnostic.stage), "%s", stage ? stage : "unknown");
+ snprintf (d -> seed_diagnostic.detail, sizeof (d -> seed_diagnostic.detail), "%s", detail ? detail : "");
+ d -> seed_diagnostic.transport_result = transport_result;
+
+ memset (&command, 0, sizeof (command));
+ if (capture_command && dvd_get_last_command_diagnostic (d -> dvd, &command)) {
+ d -> seed_diagnostic.transport_result = command.transport_result;
+ d -> seed_diagnostic.os_error = command.os_error;
+ d -> seed_diagnostic.scsi_status = command.scsi_status;
+ d -> seed_diagnostic.sense_key = command.sense_key;
+ d -> seed_diagnostic.asc = command.asc;
+ d -> seed_diagnostic.ascq = command.ascq;
+ d -> seed_diagnostic.cdb_length = command.cdb_length;
+ memcpy (d -> seed_diagnostic.cdb, command.cdb, sizeof (d -> seed_diagnostic.cdb));
+ }
+
+ cdb_text[0] = '\0';
+ used = 0;
+ for (i = 0; i < d -> seed_diagnostic.cdb_length && i < 12; i++) {
+ int wrote = snprintf (cdb_text + used, sizeof (cdb_text) - (size_t) used,
+ "%s%02X", i ? " " : "", d -> seed_diagnostic.cdb[i]);
+ if (wrote < 0 || wrote >= (int) (sizeof (cdb_text) - (size_t) used))
+ break;
+ used += wrote;
+ }
+
+ disc_seed_diag_log (d,
+ "block=%u/20 sectors=%u..%u retry=%d stage=%s result=FAIL rc=%d os=%d scsi=0x%02X sense=%02X/%02X/%02X cdb=[%s] detail=%s",
+ d -> seed_diagnostic.seed_block_index + 1,
+ sector_start, sector_end, retry,
+ d -> seed_diagnostic.stage,
+ d -> seed_diagnostic.transport_result,
+ d -> seed_diagnostic.os_error,
+ d -> seed_diagnostic.scsi_status & 0xff,
+ d -> seed_diagnostic.sense_key & 0xff,
+ d -> seed_diagnostic.asc & 0xff,
+ d -> seed_diagnostic.ascq & 0xff,
+ cdb_text[0] ? cdb_text : "none",
+ d -> seed_diagnostic.detail[0] ? d -> seed_diagnostic.detail : "none");
+}
+
+bool disc_get_seed_diagnostic (disc *d, disc_seed_diagnostic *out) {
+ if (!d || !out || !d -> seed_diagnostic.valid)
+ return false;
+ *out = d -> seed_diagnostic;
+ return true;
+}
+
static void disc_cache_init (disc *d, u_int32_t size) {
u_int32_t i;
u_int8_t raw_block[RAW_BLOCK_SIZE];
u_int8_t iso_block[BLOCK_SIZE];
u_int8_t readbuf[BLOCK_SIZE];
+ char detail[160];
+ req_sense sense;
block_no = block_sector / SECTORS_PER_BLOCK;
memset (raw_block, 0, sizeof (raw_block));
memset (iso_block, 0, sizeof (iso_block));
out = true;
+ disc_seed_diag_clear (d);
warning ("Method 8 split recovery: trying %d-sector chunks for sectors %u..%u", chunk_len, block_sector, block_sector + SECTORS_PER_BLOCK - 1);
+ disc_seed_diag_log (d,
+ "block=%u/20 sectors=%u..%u retry=%d stage=split-profile result=BEGIN detail=chunk-sectors-%d",
+ d -> seed_diagnostic_block + 1, block_sector,
+ block_sector + SECTORS_PER_BLOCK - 1, c, chunk_len);
for (chunk_start = 0; chunk_start < SECTORS_PER_BLOCK && out; chunk_start += chunk_len) {
u_int32_t chunk_sector = block_sector + (u_int32_t) chunk_start;
memset (readbuf, 0, sizeof (readbuf));
+ memset (&sense, 0, sizeof (sense));
if (chunk_sector + 992 + 16 <= d -> sectors_no)
- dvd_read_sector_dummy (d -> dvd, chunk_sector + 992, 16, NULL, NULL, 0);
+ ret = dvd_read_sector_dummy (d -> dvd, chunk_sector + 992, 16, &sense, NULL, 0);
else if (chunk_sector >= 992)
- dvd_read_sector_dummy (d -> dvd, chunk_sector - 992, 16, NULL, NULL, 0);
+ ret = dvd_read_sector_dummy (d -> dvd, chunk_sector - 992, 16, &sense, NULL, 0);
else
- dvd_flush_cache_READ12 (d -> dvd, chunk_sector, NULL);
+ ret = dvd_flush_cache_READ12 (d -> dvd, chunk_sector, &sense);
+ if (ret < 0) {
+ disc_seed_diag_log (d,
+ "block=%u/20 sectors=%u..%u retry=%d stage=split-prefetch result=NONFATAL-FAIL rc=%d sense=%02X/%02X/%02X detail=chunk-sectors-%d",
+ d -> seed_diagnostic_block + 1, chunk_sector,
+ chunk_sector + (u_int32_t) chunk_len - 1, c, ret,
+ sense.sense_key & 0xff, sense.asc & 0xff, sense.ascq & 0xff, chunk_len);
+ }
- ret = dvd_read_streaming (d -> dvd, chunk_sector, (u_int32_t) chunk_len, NULL, readbuf, (size_t) chunk_len * SECTOR_SIZE);
+ memset (&sense, 0, sizeof (sense));
+ ret = dvd_read_streaming (d -> dvd, chunk_sector, (u_int32_t) chunk_len,
+ &sense, readbuf, (size_t) chunk_len * SECTOR_SIZE);
if (ret < 0) {
+ snprintf (detail, sizeof (detail), "chunk-sectors=%d sense=%02X/%02X/%02X",
+ chunk_len, sense.sense_key & 0xff, sense.asc & 0xff, sense.ascq & 0xff);
+ disc_seed_diag_fail (d, chunk_sector,
+ chunk_sector + (u_int32_t) chunk_len - 1, c,
+ "split-streaming-read", detail, ret, true);
warning ("Method 8 split recovery: READ12 streaming failed for sectors %u..%u with %d", chunk_sector, chunk_sector + (u_int32_t) chunk_len - 1, ret);
out = false;
break;
sect = &raw_block[(chunk_start + k) * RAW_SECTOR_SIZE];
ram_offset = (u_int32_t) k * RAW_SECTOR_SIZE;
- if (dvd_memdump (d -> dvd, ram_offset, 1, 12, sect) < 0) {
+ ret = dvd_memdump (d -> dvd, ram_offset, 1, 12, sect);
+ if (ret < 0) {
+ snprintf (detail, sizeof (detail), "chunk-sectors=%d raw-offset=%u sector-index=%d",
+ chunk_len, ram_offset, k);
+ disc_seed_diag_fail (d, chunk_sector + (u_int32_t) k,
+ chunk_sector + (u_int32_t) k, c,
+ "split-header-memdump", detail, ret, true);
warning ("Method 8 split recovery: header memdump failed at sector %u", chunk_sector + (u_int32_t) k);
out = false;
break;
}
- if (dvd_memdump (d -> dvd, ram_offset + 2060, 1, 4, sect + 2060) < 0) {
+ ret = dvd_memdump (d -> dvd, ram_offset + 2060, 1, 4, sect + 2060);
+ if (ret < 0) {
+ snprintf (detail, sizeof (detail), "chunk-sectors=%d raw-offset=%u sector-index=%d",
+ chunk_len, ram_offset + 2060, k);
+ disc_seed_diag_fail (d, chunk_sector + (u_int32_t) k,
+ chunk_sector + (u_int32_t) k, c,
+ "split-edc-memdump", detail, ret, true);
warning ("Method 8 split recovery: EDC memdump failed at sector %u", chunk_sector + (u_int32_t) k);
out = false;
break;
}
if (out && !unscrambler_unscramble_16sectors (d -> u, block_sector, raw_block, iso_block)) {
+ snprintf (detail, sizeof (detail), "chunk-sectors=%d", chunk_len);
+ disc_seed_diag_fail (d, block_sector,
+ block_sector + SECTORS_PER_BLOCK - 1, c,
+ "split-edc-unscramble-validation", detail, -1, false);
warning ("Method 8 split recovery: EDC/unscramble validation failed for %d-sector chunks at sectors %u..%u", chunk_len, block_sector, block_sector + SECTORS_PER_BLOCK - 1);
out = false;
}
if (out) {
disc_cache_add_block (d, block_no, iso_block, raw_block);
warning ("Method 8 split recovery: recovered sectors %u..%u using %d-sector chunks", block_sector, block_sector + SECTORS_PER_BLOCK - 1, chunk_len);
+ disc_seed_diag_log (d,
+ "block=%u/20 sectors=%u..%u retry=%d stage=split-profile result=PASS detail=chunk-sectors-%d",
+ d -> seed_diagnostic_block + 1, block_sector,
+ block_sector + SECTORS_PER_BLOCK - 1, c, chunk_len);
return true;
}
}
}
static int disc_read_sector_8 (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata) {
- if (disc_hlds_type_is_gdr8081n_search_guided (dvd_get_hlds_e7_type (d -> dvd)))
- return disc_read_sector_8_gdr8081n_search_guided (d, sector_no, data, rawdata);
-
bool out;
u_int32_t ram_offset;
+ u_int32_t start_block;
+ u_int32_t profile_blocks;
+ u_int32_t prefetch_sector;
int j, k, ret, retry;
+ int prefetch_ret;
u_int8_t *sect, buf[5][RAW_BLOCK_SIZE];
u_int8_t readbuf[BLOCK_SIZE];
u_int8_t buf_unscrambled[5][BLOCK_SIZE];
- u_int32_t start_block;
- u_int32_t profile_blocks;
-//fprintf (stdout,"disc_read_sector_8");
+ req_sense sense;
+ char detail[160];
+
+ if (disc_hlds_type_is_gdr8081n_search_guided (dvd_get_hlds_e7_type (d -> dvd)))
+ return disc_read_sector_8_gdr8081n_search_guided (d, sector_no, data, rawdata);
+
start_block = sector_no / SECTORS_PER_BLOCK;
profile_blocks = dvd_get_hlds_e7_mem_blocks (d -> dvd);
if (profile_blocks < 1 || profile_blocks > 5)
out = false;
for (retry = 0; !out && retry < MAX_READ_RETRIES; retry++) {
- /* Assume everything will turn out well */
out = true;
+ disc_seed_diag_clear (d);
+ disc_seed_diag_log (d,
+ "block=%u/20 sectors=%u..%u retry=%d stage=normal-profile result=BEGIN detail=windows-%u",
+ d -> seed_diagnostic_block + 1, sector_no,
+ sector_no + SECTORS_PER_BLOCK - 1, retry, profile_blocks);
if (retry > 0) {
warning ("Read retry %d for sector %u", retry, sector_no);
-
- /* Try to reset in-memory data by seeking to a distant sector */
-// if (sector_no > 1000)
-// dvd_read_sector_streaming (d -> dvd, 0, NULL, NULL, 0);
-// else
-// dvd_read_sector_streaming (d -> dvd, 1500, NULL, NULL, 0);
- if (sector_no +992 +16 <= d -> sectors_no) //smaller than last sector
- dvd_read_sector_dummy (d -> dvd, sector_no +992, 16, NULL, NULL, 0);
- else if (sector_no -992 >= 0) //larger than first sector
- dvd_read_sector_dummy (d -> dvd, sector_no -992, 16, NULL, NULL, 0);
- else dvd_flush_cache_READ12 (d -> dvd, sector_no, NULL);
+ memset (&sense, 0, sizeof (sense));
+ if (sector_no + 992 + 16 <= d -> sectors_no)
+ ret = dvd_read_sector_dummy (d -> dvd, sector_no + 992, 16, &sense, NULL, 0);
+ else if (sector_no >= 992)
+ ret = dvd_read_sector_dummy (d -> dvd, sector_no - 992, 16, &sense, NULL, 0);
+ else
+ ret = dvd_flush_cache_READ12 (d -> dvd, sector_no, &sense);
+ if (ret < 0) {
+ disc_seed_diag_log (d,
+ "block=%u/20 sectors=%u..%u retry=%d stage=retry-cache-reset result=NONFATAL-FAIL rc=%d sense=%02X/%02X/%02X",
+ d -> seed_diagnostic_block + 1, sector_no,
+ sector_no + SECTORS_PER_BLOCK - 1, retry, ret,
+ sense.sense_key & 0xff, sense.asc & 0xff, sense.ascq & 0xff);
+ }
}
- /* First READ command. Type3/Type4 drives can expose several 16-sector
- * cache windows after a nearby READ. The modified GDR-8050L test firmware
- * proved seed retrieval and the first data runs, but failed when we drove it
- * with the normal five-window prefetch schedule. For that profile, avoid
- * the distant prefetch and consume only the current 16-sector window. */
+ /* Prime the volatile cache, then immediately consume it. */
+ memset (&sense, 0, sizeof (sense));
if (disc_hlds_type_is_gdr8050l_no_prefetch (dvd_get_hlds_e7_type (d -> dvd))) {
- /* GDR-8050L modified-firmware no-prefetch scheduling is selected/logged
- * by the profile probe, not from this hot per-read path. Keeping
- * logging here spams one line for every 16-sector read/cache probe. */
- dvd_flush_cache_READ12 (d -> dvd, sector_no, NULL);
+ prefetch_sector = sector_no;
+ prefetch_ret = dvd_flush_cache_READ12 (d -> dvd, sector_no, &sense);
} else {
if (sector_no > d -> sectors_no - 1000)
- dvd_read_sector_streaming (d -> dvd, sector_no - 16 * 5 * 2, NULL, NULL, 0);
+ prefetch_sector = sector_no - 16 * 5 * 2;
else
- dvd_read_sector_streaming (d -> dvd, sector_no + 16 * 5, NULL, NULL, 0);
+ prefetch_sector = sector_no + 16 * 5;
+ prefetch_ret = dvd_read_sector_streaming (d -> dvd, prefetch_sector, &sense, NULL, 0);
+ }
+ if (prefetch_ret < 0) {
+ disc_seed_diag_log (d,
+ "block=%u/20 sectors=%u..%u retry=%d stage=prefetch result=NONFATAL-FAIL rc=%d sense=%02X/%02X/%02X detail=prefetch-lba-%u",
+ d -> seed_diagnostic_block + 1, sector_no,
+ sector_no + SECTORS_PER_BLOCK - 1, retry, prefetch_ret,
+ sense.sense_key & 0xff, sense.asc & 0xff, sense.ascq & 0xff,
+ prefetch_sector);
}
- if ((ret = dvd_read_sector_streaming (d -> dvd, sector_no, NULL, readbuf, sizeof (readbuf))) >= 0) {
+
+ memset (&sense, 0, sizeof (sense));
+ ret = dvd_read_sector_streaming (d -> dvd, sector_no, &sense, readbuf, sizeof (readbuf));
+ if (ret >= 0) {
for (j = 0; j < (int) profile_blocks && sector_no + j * 16 < d -> sectors_no && out; j++) {
- /* Reconstruct raw sectors */
for (k = 0; k < 16; k++) {
sect = &buf[j][k * RAW_SECTOR_SIZE];
ram_offset = (j * RAW_BLOCK_SIZE) + k * RAW_SECTOR_SIZE;
- /* Get first 12 bytes (ID. IED and CPR_MAI fields) and last 4 bytes (EDC field) with memdump */
- if (dvd_memdump (d -> dvd, ram_offset, 1, 12, sect) < 0) {
+ ret = dvd_memdump (d -> dvd, ram_offset, 1, 12, sect);
+ if (ret < 0) {
+ snprintf (detail, sizeof (detail),
+ "window=%d sector-index=%d raw-offset=%u", j, k, ram_offset);
+ disc_seed_diag_fail (d, sector_no + (u_int32_t) (j * 16 + k),
+ sector_no + (u_int32_t) (j * 16 + k), retry,
+ "header-memdump", detail, ret, true);
error ("Memdump (1) failed");
out = false;
- retry = MAX_READ_RETRIES; /* Well, if this fails going on is useless */
- } else if (dvd_memdump (d -> dvd, ram_offset + 2060, 1, 4, sect + 2060) < 0) { /* Dumping in a single block is faster */
- error ("Memdump (2) failed");
- out = false;
+ retry = MAX_READ_RETRIES;
+ } else {
+ ret = dvd_memdump (d -> dvd, ram_offset + 2060, 1, 4, sect + 2060);
+ if (ret < 0) {
+ snprintf (detail, sizeof (detail),
+ "window=%d sector-index=%d raw-offset=%u", j, k, ram_offset + 2060);
+ disc_seed_diag_fail (d, sector_no + (u_int32_t) (j * 16 + k),
+ sector_no + (u_int32_t) (j * 16 + k), retry,
+ "edc-memdump", detail, ret, true);
+ error ("Memdump (2) failed");
+ out = false;
+ }
}
}
}
- /* Now the same for remaining cached 16-sector blocks. Type1 drives only
- * expose one validated cache window at their DIC-derived base address. */
for (j = 0; j < (int) profile_blocks && sector_no + j * 16 < d -> sectors_no && out; j++) {
- if (j == 0 || (ret = dvd_read_sector_streaming (d -> dvd, sector_no + j * 16, NULL, readbuf, sizeof (readbuf))) >= 0) {
- /* Copy "user data" field which has been incorrectly unscrambled by the DVD drive firmware */
- for (k = 0; k < 16; k++) {
- sect = &buf[j][k * RAW_SECTOR_SIZE];
- memcpy (sect + 12, readbuf + k * SECTOR_SIZE, SECTOR_SIZE);
+ if (j != 0) {
+ memset (&sense, 0, sizeof (sense));
+ ret = dvd_read_sector_streaming (d -> dvd, sector_no + (u_int32_t) j * 16,
+ &sense, readbuf, sizeof (readbuf));
+ if (ret < 0) {
+ snprintf (detail, sizeof (detail),
+ "window=%d sense=%02X/%02X/%02X", j,
+ sense.sense_key & 0xff, sense.asc & 0xff, sense.ascq & 0xff);
+ disc_seed_diag_fail (d, sector_no + (u_int32_t) j * 16,
+ sector_no + (u_int32_t) j * 16 + SECTORS_PER_BLOCK - 1,
+ retry, "cached-window-streaming-read", detail, ret, true);
+ error ("dvd_read_sector_streaming() failed with %d", ret);
+ out = false;
+ break;
}
+ }
+
+ for (k = 0; k < 16; k++) {
+ sect = &buf[j][k * RAW_SECTOR_SIZE];
+ memcpy (sect + 12, readbuf + k * SECTOR_SIZE, SECTOR_SIZE);
+ }
#ifdef DEBUG
- if (d -> unscrambling) {
+ if (d -> unscrambling) {
#endif
- /* Try to unscramble all data to see if EDC fails */
- if (!unscrambler_unscramble_16sectors (d -> u, sector_no + (j * 16), buf[j], buf_unscrambled[j]))
- out = false;
-#ifdef DEBUG
+ if (!unscrambler_unscramble_16sectors (d -> u,
+ sector_no + (u_int32_t) (j * 16), buf[j], buf_unscrambled[j])) {
+ snprintf (detail, sizeof (detail), "window=%d", j);
+ disc_seed_diag_fail (d,
+ sector_no + (u_int32_t) j * 16,
+ sector_no + (u_int32_t) j * 16 + SECTORS_PER_BLOCK - 1,
+ retry, "edc-unscramble-validation", detail, -1, false);
+ out = false;
}
-#endif
- } else {
- error ("dvd_read_sector_streaming() failed with %d", ret);
- out = false;
+#ifdef DEBUG
}
+#endif
}
if (out) {
- /* It seems all data were unscrambled correctly, so cache them out */
for (j = 0; j < (int) profile_blocks && sector_no + j * SECTORS_PER_BLOCK < d -> sectors_no; j++)
disc_cache_add_block (d, start_block + j, buf_unscrambled[j], buf[j]);
+ disc_seed_diag_clear (d);
+ disc_seed_diag_log (d,
+ "block=%u/20 sectors=%u..%u retry=%d stage=normal-profile result=PASS detail=windows-%u",
+ d -> seed_diagnostic_block + 1, sector_no,
+ sector_no + SECTORS_PER_BLOCK - 1, retry, profile_blocks);
}
} else {
+ snprintf (detail, sizeof (detail), "sense=%02X/%02X/%02X",
+ sense.sense_key & 0xff, sense.asc & 0xff, sense.ascq & 0xff);
+ disc_seed_diag_fail (d, sector_no,
+ sector_no + SECTORS_PER_BLOCK - 1, retry,
+ "streaming-read", detail, ret, true);
error ("dvd_read_sector_streaming() failed with %d", ret);
out = false;
}
if (!out) {
u_int32_t block_sector = start_block * SECTORS_PER_BLOCK;
warning ("Method 8 normal profile read failed at sectors %u..%u; entering split recovery", block_sector, block_sector + SECTORS_PER_BLOCK - 1);
+ disc_seed_diag_log (d,
+ "block=%u/20 sectors=%u..%u retry=%d stage=normal-profile result=EXHAUSTED detail=entering-split-recovery",
+ d -> seed_diagnostic_block + 1, block_sector,
+ block_sector + SECTORS_PER_BLOCK - 1, MAX_READ_RETRIES - 1);
out = disc_read_sector_8_split_recover_block (d, block_sector);
}
if (!out)
error ("Too many retries, giving up");
- return (out);
+ return out;
}
}
-static bool disc_analyze (disc *d) {
+static const char *disc_detected_type_name (disc_type type) {
+ switch (type) {
+ case DISC_TYPE_GAMECUBE:
+ return "GameCube";
+ case DISC_TYPE_WII:
+ return "Wii";
+ case DISC_TYPE_WII_DL:
+ return "Wii_DL";
+ case DISC_TYPE_DVD:
+ return "DVD";
+ case DISC_TYPE_XBOX:
+ return "Xbox";
+ default:
+ return "Unknown";
+ }
+}
+
+
+static bool disc_analyze (disc *d, bool allow_type_correction, bool allow_size_correction) {
u_int8_t *buf;
char tmp[0x03E0 + 1];
bool unscramble_old, out;
+ nintendo_disc_header_type header_type;
+ disc_type previous_type;
/* Force unscrambling for this read */
unscramble_old = d -> unscrambling;
if (disc_read_sector (d, 0, &buf, NULL)) {
/* System ID */
d -> system_id = buf[0];
-// if (d -> system_id == 'G') {
-// d -> type = DISC_TYPE_GAMECUBE;
-// d -> sectors_no = DISC_GAMECUBE_SECTORS_NO;
-// } else if (d -> system_id == 'R') {
-// d -> type = DISC_TYPE_WII;
-// d -> sectors_no = DISC_WII_SECTORS_NO;
-// } else {
-// error ("Unknown system ID: '%c'", d -> system_id);
-// MY_ASSERT (false);
-// }
+
+ /*
+ * The legacy capacity probe can misclassify GameCube media on some
+ * HLDS drives because an out-of-range dummy read does not always
+ * return the expected ILLEGAL REQUEST / LBA OUT OF RANGE sense data.
+ * Once sector 0 has been unscrambled, its platform magic is the
+ * authoritative discriminator.
+ *
+ * Explicit -T selections remain authoritative and are not changed.
+ * Explicit -S geometry also remains authoritative.
+ */
+ header_type = nintendo_disc_header_detect (buf, SECTOR_SIZE);
+ previous_type = d -> type;
+
+ if (allow_type_correction &&
+ header_type == NINTENDO_DISC_HEADER_GAMECUBE) {
+ d -> type = DISC_TYPE_GAMECUBE;
+ if (allow_size_correction)
+ d -> sectors_no = DISC_GAMECUBE_SECTORS_NO;
+ } else if (allow_type_correction &&
+ header_type == NINTENDO_DISC_HEADER_WII &&
+ d -> type != DISC_TYPE_WII &&
+ d -> type != DISC_TYPE_WII_DL) {
+ d -> type = DISC_TYPE_WII;
+ if (allow_size_correction)
+ d -> sectors_no = DISC_WII_SECTORS_NO_SL;
+ }
+
+ if (allow_type_correction &&
+ header_type != NINTENDO_DISC_HEADER_UNKNOWN &&
+ previous_type != d -> type) {
+ warning ("Disc type corrected from %s to %s using sector-0 platform magic",
+ disc_detected_type_name (previous_type),
+ disc_detected_type_name (d -> type));
+ }
/* Game ID */
strncpy (d -> game_id, (char *) buf + 1, 2);
static bool disc_crack_seeds (disc *d) {
int i;
- /* As a Nintendo GameCube/Wii disc should not have too many keys, 20 should be enough */
+ /* As a Nintendo GameCube/Wii disc should not have too many keys, 20 should be enough. */
debug ("Retrieving all DVD seeds");
- if (!disc_probe_gdr8050l_e7_speed_profile (d))
+ disc_seed_diag_clear (d);
+ d -> seed_diagnostic_active = true;
+ d -> seed_diagnostic_block = 0;
+ xbox_ref_log_fprintf (stderr, "\n");
+ disc_seed_diag_log (d,
+ "campaign=begin blocks=20 method=%d profile=%s cache-base=0x%08X windows=%u",
+ d -> read_method,
+ dvd_get_hlds_e7_profile_name (d -> dvd),
+ dvd_get_hlds_e7_cache_base (d -> dvd),
+ dvd_get_hlds_e7_mem_blocks (d -> dvd));
+
+ if (!disc_probe_gdr8050l_e7_speed_profile (d)) {
+ disc_seed_diag_fail (d, 0, 15, 0, "profile-probe",
+ "GDR-8050L runtime profile probe failed", -1, false);
+ d -> seed_diagnostic_active = false;
return false;
- if (!disc_probe_gdr8081n_e7_profile (d))
+ }
+ if (!disc_probe_gdr8081n_e7_profile (d)) {
+ disc_seed_diag_fail (d, 0, 15, 0, "profile-probe",
+ "GDR-8081N runtime profile probe failed", -1, false);
+ d -> seed_diagnostic_active = false;
return false;
+ }
+
for (i = 0; i < 20 * 16; i += 16) {
- if (!disc_read_sector (d, i, NULL, NULL))
+ d -> seed_diagnostic_block = (unsigned int) (i / 16);
+ disc_seed_diag_clear (d);
+ disc_seed_diag_log (d,
+ "block=%u/20 sectors=%d..%d stage=seed-block result=BEGIN",
+ d -> seed_diagnostic_block + 1, i, i + 15);
+ if (!disc_read_sector (d, (u_int32_t) i, NULL, NULL)) {
+ if (!d -> seed_diagnostic.valid)
+ disc_seed_diag_fail (d, (u_int32_t) i, (u_int32_t) i + 15,
+ 0, "seed-block-read", "disc_read_sector returned failure without a classified sub-stage", -1, false);
+ disc_seed_diag_log (d,
+ "campaign=fail block=%u/20 sectors=%d..%d",
+ d -> seed_diagnostic_block + 1, i, i + 15);
+ d -> seed_diagnostic_active = false;
return false;
+ }
+ disc_seed_diag_log (d,
+ "block=%u/20 sectors=%d..%d stage=seed-block result=PASS",
+ d -> seed_diagnostic_block + 1, i, i + 15);
}
+ disc_seed_diag_clear (d);
+ disc_seed_diag_log (d, "campaign=pass blocks=20");
+ d -> seed_diagnostic_active = false;
return true;
}
disc_set_unscrambling (d, false);
out = true;
}
- else if (disc_analyze (d)) {
+ else if (disc_analyze (
+ d,
+ disctype > 4,
+ sectors_no == (u_int32_t) -1
+ )) {
disc_check_update (d);
out = true;
} else {
-int disc_xbox_recovery_kick (disc *d, bool auth_recovery) {
+int disc_xbox_prepare_game_view (disc *d, u_int32_t *sectors, u_int32_t *sector_size) {
+ int out;
if (!d || d -> type != DISC_TYPE_XBOX)
return -1;
- return dvd_xbox_recovery_kick (d -> dvd, auth_recovery);
+ out = dvd_xbox_prepare_game_view (d -> dvd, sectors, sector_size);
+ if (out == 0 && sectors)
+ d -> sectors_no = *sectors;
+ return out;
}
int disc_refresh_volume (disc *d) {
return dvd_wait_ready (d -> dvd, timeout_ms);
}
+char *disc_get_drive_vendor (disc *d) {
+ return d ? dvd_get_vendor (d -> dvd) : NULL;
+}
+
+char *disc_get_drive_product_id (disc *d) {
+ return d ? dvd_get_product_id (d -> dvd) : NULL;
+}
+
+char *disc_get_drive_firmware_revision (disc *d) {
+ return d ? dvd_get_product_revision (d -> dvd) : NULL;
+}
+
char *disc_get_drive_model_string (disc *d) {
- return (dvd_get_model_string (d -> dvd));
+ return d ? dvd_get_model_string (d -> dvd) : NULL;
}