]> FriiDump Source - friidump.git/blobdiff - libfriidump/dvd_drive.c
Record A102 and B101 live profile evidence
[friidump.git] / libfriidump / dvd_drive.c
index 036d38b861ae02684ffa0dad88af6828db9d54d1..88aa2c0e91e24024818673deb086cd348fc9b74d 100644 (file)
 #include "dvd_drive.h"
 #include "disc.h"
 #include "sha1.h"
 #include "dvd_drive.h"
 #include "disc.h"
 #include "sha1.h"
+#include "xbox_ref/xbox_ref_log.h"
 
 #ifdef WIN32
 #include <windows.h>
 #include <ntddscsi.h>
 #else
 #include <linux/cdrom.h>
 
 #ifdef WIN32
 #include <windows.h>
 #include <ntddscsi.h>
 #else
 #include <linux/cdrom.h>
+#include <scsi/sg.h>
 #include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <fcntl.h>
@@ -99,6 +101,9 @@ struct dvd_drive_s {
        const char *hlds_e7_record_id;
        const char *hlds_e7_notes;
 
        const char *hlds_e7_record_id;
        const char *hlds_e7_notes;
 
+       /* Last transport command evidence for release-build diagnostics. */
+       dvd_command_diagnostic last_command;
+
        /* Device-dependent internal memory dump function */
        /*! The intended area should start where sector data is stored upon a READ command. Here we assume that sectors are
         *  stored one after the other, as heuristics showed it is the case for the Hitachi MN103-based drives, but this model
        /* Device-dependent internal memory dump function */
        /*! The intended area should start where sector data is stored upon a READ command. Here we assume that sectors are
         *  stored one after the other, as heuristics showed it is the case for the Hitachi MN103-based drives, but this model
@@ -195,6 +200,23 @@ static bool dvd_prod_has_any (dvd_drive *dvd, const char **needles, size_t count
        return false;
 }
 
        return false;
 }
 
+static bool hlds_product_has (const char *product_id, const char *needle) {
+       return product_id && needle && strstr (product_id, needle) != NULL;
+}
+
+static bool hlds_product_has_any (
+       const char *product_id,
+       const char **needles,
+       size_t count
+) {
+       size_t i;
+       for (i = 0; i < count; i++) {
+               if (hlds_product_has (product_id, needles[i]))
+                       return true;
+       }
+       return false;
+}
+
 static bool dvd_is_hlds_gcc4243_4244_drive (dvd_drive *dvd) {
        static const char *names[] = {
                "GCC-4243N", "GCC4243N", "GCC4243",
 static bool dvd_is_hlds_gcc4243_4244_drive (dvd_drive *dvd) {
        static const char *names[] = {
                "GCC-4243N", "GCC4243N", "GCC4243",
@@ -233,13 +255,17 @@ static const hlds_e7_profile_desc hlds_e7_profiles[] = {
        { "GCC-4242N", "0J06", 22, 0x80000000U, 1, 8, "GCC-4242N 0J06 promoted E7 parser profile", "error_prone_supported_profile_hardening", "GCC_424x", "HL;IT;RPC;RPC_JCS3;RPC_SUFFIX", "stage5b_0066", 0x824U, 0x90038621U, "capable but error-prone; conservative Method 8 one-window validation profile" },
        { "GCC-4243N", "0000", 3, 0x80000000U, 5, 8, "GCC-4243N 0000 promoted E7 parser profile", "known_supported_profile_hardening", "GCC_424x", "HL;IT;RPC;RPC_JCS3;RPC_SUFFIX", "stage5b_0069", 0x884U, 0x90037929U, "known-supported GCC_424x profile hardening target" },
        { "GCC-4243N", "1.08", 3, 0x80000000U, 5, 8, "GCC-4243N 1.08 promoted E7 parser profile", "known_supported_profile_hardening", "GCC_424x", "HL;IT;RPC;RPC_JCS3;RPC_SUFFIX", "stage5b_0071", 0x880U, 0x90036813U, "known-supported GCC_424x profile hardening target" },
        { "GCC-4242N", "0J06", 22, 0x80000000U, 1, 8, "GCC-4242N 0J06 promoted E7 parser profile", "error_prone_supported_profile_hardening", "GCC_424x", "HL;IT;RPC;RPC_JCS3;RPC_SUFFIX", "stage5b_0066", 0x824U, 0x90038621U, "capable but error-prone; conservative Method 8 one-window validation profile" },
        { "GCC-4243N", "0000", 3, 0x80000000U, 5, 8, "GCC-4243N 0000 promoted E7 parser profile", "known_supported_profile_hardening", "GCC_424x", "HL;IT;RPC;RPC_JCS3;RPC_SUFFIX", "stage5b_0069", 0x884U, 0x90037929U, "known-supported GCC_424x profile hardening target" },
        { "GCC-4243N", "1.08", 3, 0x80000000U, 5, 8, "GCC-4243N 1.08 promoted E7 parser profile", "known_supported_profile_hardening", "GCC_424x", "HL;IT;RPC;RPC_JCS3;RPC_SUFFIX", "stage5b_0071", 0x880U, 0x90036813U, "known-supported GCC_424x profile hardening target" },
+       { "GCC4243", "A102", 3, 0x80000000U, 5, 8, "GCC-4243N A102 promoted E7 parser profile", "known_supported_profile_hardening_live_validated", "GCC_424x", "HL;IT;RPC;RPC_JCS3;RPC_SUFFIX", "hybrid_identity_v3:stage5b_0439", 0x880U, 0x9003731dU, "Live INQUIRY alias for GCC4243/A102; exact profile selection, 20-block seed retrieval, full GameCube dump, STOP UNIT, and exact Redump match validated with Sonic Mega Collection (US)" },
+       { "GCC-4243N", "A102", 3, 0x80000000U, 5, 8, "GCC-4243N A102 promoted E7 parser profile", "known_supported_profile_hardening_live_validated", "GCC_424x", "HL;IT;RPC;RPC_JCS3;RPC_SUFFIX", "hybrid_identity_v3:stage5b_0439", 0x880U, 0x9003731dU, "Canonical model alias for GCC-4243N A102; exact profile selection, 20-block seed retrieval, full GameCube dump, STOP UNIT, and exact Redump match validated with Sonic Mega Collection (US)" },
        { "GCC-4244N", "1.03", 3, 0x80000000U, 5, 8, "GCC-4244N 1.03 promoted E7 parser profile", "known_supported_profile_hardening", "GCC_424x", "HL;IT;RPC;RPC_JCS3;RPC_SUFFIX", "stage5b_0073", 0x88cU, 0x90037d06U, "P1 owned GCC_424x profile hardening target" },
        { "GCC-4244N", "103", 3, 0x80000000U, 5, 8, "GCC-4244N 103 promoted E7 parser profile", "known_supported_profile_hardening", "GCC_424x", "HL;IT;RPC;RPC_JCS3;RPC_SUFFIX", "stage5b_0076", 0x894U, 0x900386fbU, "P1 owned GCC_424x profile hardening target" },
        { "GCC-4244N", "1.03", 3, 0x80000000U, 5, 8, "GCC-4244N 1.03 promoted E7 parser profile", "known_supported_profile_hardening", "GCC_424x", "HL;IT;RPC;RPC_JCS3;RPC_SUFFIX", "stage5b_0073", 0x88cU, 0x90037d06U, "P1 owned GCC_424x profile hardening target" },
        { "GCC-4244N", "103", 3, 0x80000000U, 5, 8, "GCC-4244N 103 promoted E7 parser profile", "known_supported_profile_hardening", "GCC_424x", "HL;IT;RPC;RPC_JCS3;RPC_SUFFIX", "stage5b_0076", 0x894U, 0x900386fbU, "P1 owned GCC_424x profile hardening target" },
+       { "GCC4244", "B101", 3, 0x80000000U, 5, 8, "GCC-4244N B101 promoted E7 parser profile", "known_supported_profile_hardening_live_validated", "GCC_424x", "HL;IT;RPC;RPC_JCS3;RPC_SUFFIX", "hybrid_identity_v3:stage5b_0426", 0x894U, 0x900386d2U, "Live INQUIRY alias for GCC4244/B101; exact profile selection, 20-block GameCube seed retrieval, and STOP UNIT validated; the earlier legacy Type3 fallback full dump matched Redump" },
+       { "GCC-4244N", "B101", 3, 0x80000000U, 5, 8, "GCC-4244N B101 promoted E7 parser profile", "known_supported_profile_hardening_live_validated", "GCC_424x", "HL;IT;RPC;RPC_JCS3;RPC_SUFFIX", "hybrid_identity_v3:stage5b_0426", 0x894U, 0x900386d2U, "Canonical model alias for GCC-4244N B101; exact profile selection, 20-block GameCube seed retrieval, and STOP UNIT validated; the earlier legacy Type3 fallback full dump matched Redump" },
        { "GCC4244", "B103", 3, 0x80000000U, 5, 8, "GCC-4244N B103 promoted E7 parser profile", "known_supported_profile_hardening_live_validated", "GCC_424x", "HL;IT;RPC;RPC_JCS3;RPC_SUFFIX", "promoted_parser_signature_v23", 0x894U, 0x900386fbU, "Live INQUIRY alias for HL-DT-ST CDRW/DVD GCC4244 B103; case label B101; exact Stage5B parser signature recovered; media preflight, seed retrieval, full GameCube dump, STOP UNIT, and Redump hash match validated" },
        { "GCC-4244N", "B103", 3, 0x80000000U, 5, 8, "GCC-4244N B103 promoted E7 parser profile", "known_supported_profile_hardening_live_validated", "GCC_424x", "HL;IT;RPC;RPC_JCS3;RPC_SUFFIX", "promoted_parser_signature_v23", 0x894U, 0x900386fbU, "B103 shares the promoted parser signature gate/CDB with 103/104; live GCC4244/B103 hardware completed a Redump-matching GameCube dump" },
        { "GCC-4244N", "104", 3, 0x80000000U, 5, 8, "GCC-4244N 104 promoted E7 parser profile", "known_supported_profile_hardening", "GCC_424x", "HL;IT;RPC;RPC_JCS3;RPC_SUFFIX", "stage5b_0078", 0x894U, 0x900386fbU, "P1 owned GCC_424x profile hardening target" },
        { "GDR-3120L", "0046", 4, 0x80000000U, 5, 8, "GDR-3120L 0046 experimental GC/Wii E7 parser profile", "experimental_gc_wii_candidate", "GDR_3120x", "HL;IT;RPC;RPC_JD4_SPACE;RPC_SUFFIX", "stage5b_0355", 0x5b8U, 0x90025bceU, "historically Xbox/reference; allow read-only GC/Wii Method 8 experiment, not proven support until dump validates" },
        { "GCC4244", "B103", 3, 0x80000000U, 5, 8, "GCC-4244N B103 promoted E7 parser profile", "known_supported_profile_hardening_live_validated", "GCC_424x", "HL;IT;RPC;RPC_JCS3;RPC_SUFFIX", "promoted_parser_signature_v23", 0x894U, 0x900386fbU, "Live INQUIRY alias for HL-DT-ST CDRW/DVD GCC4244 B103; case label B101; exact Stage5B parser signature recovered; media preflight, seed retrieval, full GameCube dump, STOP UNIT, and Redump hash match validated" },
        { "GCC-4244N", "B103", 3, 0x80000000U, 5, 8, "GCC-4244N B103 promoted E7 parser profile", "known_supported_profile_hardening_live_validated", "GCC_424x", "HL;IT;RPC;RPC_JCS3;RPC_SUFFIX", "promoted_parser_signature_v23", 0x894U, 0x900386fbU, "B103 shares the promoted parser signature gate/CDB with 103/104; live GCC4244/B103 hardware completed a Redump-matching GameCube dump" },
        { "GCC-4244N", "104", 3, 0x80000000U, 5, 8, "GCC-4244N 104 promoted E7 parser profile", "known_supported_profile_hardening", "GCC_424x", "HL;IT;RPC;RPC_JCS3;RPC_SUFFIX", "stage5b_0078", 0x894U, 0x900386fbU, "P1 owned GCC_424x profile hardening target" },
        { "GDR-3120L", "0046", 4, 0x80000000U, 5, 8, "GDR-3120L 0046 experimental GC/Wii E7 parser profile", "experimental_gc_wii_candidate", "GDR_3120x", "HL;IT;RPC;RPC_JD4_SPACE;RPC_SUFFIX", "stage5b_0355", 0x5b8U, 0x90025bceU, "historically Xbox/reference; allow read-only GC/Wii Method 8 experiment, not proven support until dump validates" },
-       { "GDR-8050L", "0L23", 44, 0x80000000U, 1, 8, "GDR-8050L 0L23 donor/modified-firmware E7 parser profile", "donor_reference_modified_firmware_only", "GDR_8050x", "HL;IT;RPC;RPC_JD4_SPACE;RPC_SUFFIX", "stage5b_0099", 0x5d0U, 0x90026160U, "stock firmware is Xbox-only here; GC/Wii 0xE7 path requires modified firmware with memdump support" },
+       { "GDR-8050L", "0012", 44, 0x80000000U, 1, 8, "GDR-8050L 0012 hybrid cross-flash E7 parser profile", "hybrid_crossflash_modified_firmware_only", "GDR_8050x", "HL;IT;RPC;RPC_JD4_SPACE;RPC_SUFFIX", "hybrid_identity_v3:gdr8050l_0012", 0x5d0U, 0x90026160U, "Operating identity is GDR-8050L 0012 on GDR-8163B physical hardware; package compatibility identity is GDR-8163B 0L23; GC/Wii 0xE7 access requires modified firmware; native GDR-8050L hardware is not owned" },
        { "GDR-8082N", "0120", 4, 0x80000000U, 5, 9, "GDR-8082N 0120 promoted E7 parser profile", "known_supported_profile_hardening", "GDR_808x", "HL;IT;RPC;RPC_SUFFIX", "stage5b_0103", 0x638U, 0x900282daU, "known-supported reference profile" },
        { "GDR-8083N", "0K04", 4, 0x80000000U, 5, 9, "GDR-8083N 0K04 promoted E7 parser profile", "known_supported_profile_hardening", "GDR_808x", "HL;IT;RPC;RPC_SUFFIX", "stage5b_0104", 0x638U, 0x900291fcU, "known-supported reference profile" },
        { "GDR-8161B", "0102", 4, 0x80000000U, 5, 9, "GDR-8161B 0102 promoted E7 parser profile", "known_supported_profile_hardening", "GDR_816x", "IT;RPC;RPC_SUFFIX", "stage5b_0109", 0x5a8U, 0x90025010U, "known-supported reference profile" },
        { "GDR-8082N", "0120", 4, 0x80000000U, 5, 9, "GDR-8082N 0120 promoted E7 parser profile", "known_supported_profile_hardening", "GDR_808x", "HL;IT;RPC;RPC_SUFFIX", "stage5b_0103", 0x638U, 0x900282daU, "known-supported reference profile" },
        { "GDR-8083N", "0K04", 4, 0x80000000U, 5, 9, "GDR-8083N 0K04 promoted E7 parser profile", "known_supported_profile_hardening", "GDR_808x", "HL;IT;RPC;RPC_SUFFIX", "stage5b_0104", 0x638U, 0x900291fcU, "known-supported reference profile" },
        { "GDR-8161B", "0102", 4, 0x80000000U, 5, 9, "GDR-8161B 0102 promoted E7 parser profile", "known_supported_profile_hardening", "GDR_816x", "IT;RPC;RPC_SUFFIX", "stage5b_0109", 0x5a8U, 0x90025010U, "known-supported reference profile" },
@@ -269,25 +295,25 @@ static void hlds_normalize_model (const char *src, char *dst, size_t dst_size) {
        dst[j] = 0;
 }
 
        dst[j] = 0;
 }
 
-static bool hlds_model_matches (dvd_drive *dvd, const char *model) {
+static bool hlds_model_matches_value (const char *product_id, const char *model) {
        char prod_norm[64];
        char model_norm[64];
        char prod_norm[64];
        char model_norm[64];
-       if (!dvd || !dvd -> prod_id || !model)
+       if (!product_id || !model)
                return false;
                return false;
-       hlds_normalize_model (dvd -> prod_id, prod_norm, sizeof (prod_norm));
+       hlds_normalize_model (product_id, prod_norm, sizeof (prod_norm));
        hlds_normalize_model (model, model_norm, sizeof (model_norm));
        return prod_norm[0] && model_norm[0] && strstr (prod_norm, model_norm) != NULL;
 }
 
        hlds_normalize_model (model, model_norm, sizeof (model_norm));
        return prod_norm[0] && model_norm[0] && strstr (prod_norm, model_norm) != NULL;
 }
 
-static bool hlds_revision_matches (dvd_drive *dvd, const char *revision) {
+static bool hlds_revision_matches_value (const char *actual, const char *expected) {
        const unsigned char *a;
        const unsigned char *b;
        const unsigned char *a;
        const unsigned char *b;
-       if (!revision || !revision[0])
+       if (!expected || !expected[0])
                return true;
                return true;
-       if (!dvd || !dvd -> prod_rev)
+       if (!actual)
                return false;
                return false;
-       a = (const unsigned char *) dvd -> prod_rev;
-       b = (const unsigned char *) revision;
+       a = (const unsigned char *) actual;
+       b = (const unsigned char *) expected;
        while (*a && *b) {
                if (toupper (*a) != toupper (*b))
                        return false;
        while (*a && *b) {
                if (toupper (*a) != toupper (*b))
                        return false;
@@ -297,19 +323,70 @@ static bool hlds_revision_matches (dvd_drive *dvd, const char *revision) {
        return *a == 0 && *b == 0;
 }
 
        return *a == 0 && *b == 0;
 }
 
-static const hlds_e7_profile_desc *dvd_find_hlds_e7_profile (dvd_drive *dvd) {
+static const hlds_e7_profile_desc *hlds_find_e7_profile_for_identity (
+       const char *vendor,
+       const char *product_id,
+       const char *revision
+) {
        const hlds_e7_profile_desc *p;
        const hlds_e7_profile_desc *p;
-       if (!dvd_is_hlds_drive (dvd))
+       if (!vendor || strcmp (vendor, "HL-DT-ST") != 0)
                return NULL;
        for (p = hlds_e7_profiles; p -> model; p++) {
                return NULL;
        for (p = hlds_e7_profiles; p -> model; p++) {
-               if (hlds_model_matches (dvd, p -> model) && hlds_revision_matches (dvd, p -> firmware))
+               if (
+                       hlds_model_matches_value (product_id, p -> model) &&
+                       hlds_revision_matches_value (revision, p -> firmware)
+               )
                        return p;
        }
        return NULL;
 }
 
                        return p;
        }
        return NULL;
 }
 
-static u_int32_t dvd_hlds_e7_detect_type (dvd_drive *dvd) {
-       const hlds_e7_profile_desc *profile = dvd_find_hlds_e7_profile (dvd);
+static const hlds_e7_profile_desc *dvd_find_hlds_e7_profile (dvd_drive *dvd) {
+       if (!dvd)
+               return NULL;
+       return hlds_find_e7_profile_for_identity (
+               dvd -> vendor,
+               dvd -> prod_id,
+               dvd -> prod_rev
+       );
+}
+
+bool dvd_lookup_hlds_e7_profile (
+       const char *vendor,
+       const char *product_id,
+       const char *revision,
+       dvd_hlds_e7_profile_info *out
+) {
+       const hlds_e7_profile_desc *p;
+       if (out)
+               memset (out, 0, sizeof (*out));
+       p = hlds_find_e7_profile_for_identity (vendor, product_id, revision);
+       if (!p)
+               return false;
+       if (out) {
+               out -> type = p -> type;
+               out -> cache_base = p -> cache_base;
+               out -> mem_blocks = p -> mem_blocks;
+               out -> preferred_method = p -> preferred_method;
+               out -> label = p -> label;
+               out -> support_tier = p -> support_tier;
+               out -> family = p -> family;
+               out -> tokens = p -> tokens;
+               out -> record_id = p -> record_id;
+               out -> static_cdb_base = p -> static_cdb_base;
+               out -> static_gate = p -> static_gate;
+               out -> notes = p -> notes;
+       }
+       return true;
+}
+
+u_int32_t dvd_detect_hlds_e7_type_for_identity (
+       const char *vendor,
+       const char *product_id,
+       const char *revision
+) {
+       const hlds_e7_profile_desc *profile =
+               hlds_find_e7_profile_for_identity (vendor, product_id, revision);
        static const char *type1[] = {
                "GCC-4160N", "GCC4160N", "GCC4160",
                "GCC-4240N", "GCC4240N", "GCC4240"
        static const char *type1[] = {
                "GCC-4160N", "GCC4160N", "GCC4160",
                "GCC-4240N", "GCC4240N", "GCC4240"
@@ -339,29 +416,39 @@ static u_int32_t dvd_hlds_e7_detect_type (dvd_drive *dvd) {
                "GDR3120L", "GDR-3120L"
        };
 
                "GDR3120L", "GDR-3120L"
        };
 
-       if (!dvd_is_hlds_drive (dvd))
+       if (!vendor || strcmp (vendor, "HL-DT-ST") != 0)
                return 0;
        if (profile)
                return profile -> type;
                return 0;
        if (profile)
                return profile -> type;
-       if (dvd_prod_has_any (dvd, type1, sizeof (type1) / sizeof (type1[0])))
+       if (hlds_product_has_any (product_id, type1, sizeof (type1) / sizeof (type1[0])))
                return 1;
                return 1;
-       if (dvd_prod_has_any (dvd, type2_1, sizeof (type2_1) / sizeof (type2_1[0])))
+       if (hlds_product_has_any (product_id, type2_1, sizeof (type2_1) / sizeof (type2_1[0])))
                return 21;
                return 21;
-       if (dvd_prod_has_any (dvd, type2_2, sizeof (type2_2) / sizeof (type2_2[0])))
+       if (hlds_product_has_any (product_id, type2_2, sizeof (type2_2) / sizeof (type2_2[0])))
                return 22;
                return 22;
-       if (dvd_prod_has_any (dvd, gdr8081n, sizeof (gdr8081n) / sizeof (gdr8081n[0])))
+       if (hlds_product_has_any (product_id, gdr8081n, sizeof (gdr8081n) / sizeof (gdr8081n[0])))
                return 81;
                return 81;
-       if (dvd_prod_has_any (dvd, type3, sizeof (type3) / sizeof (type3[0])))
+       if (hlds_product_has_any (product_id, type3, sizeof (type3) / sizeof (type3[0])))
                return 3;
                return 3;
-       if (dvd_is_hlds_gdr8050l_drive (dvd))
+       if (hlds_product_has (product_id, "GDR8050L") || hlds_product_has (product_id, "GDR-8050L"))
                return 44;
                return 44;
-       if (dvd_prod_has_any (dvd, type4, sizeof (type4) / sizeof (type4[0])))
+       if (hlds_product_has_any (product_id, type4, sizeof (type4) / sizeof (type4[0])))
                return 4;
        /* DIC labels GSA-4163B as an Xbox swap candidate, not a normal 0xE7
         * Nintendo-disc cache dump profile, so keep it out of the profile layer. */
        return 0;
 }
 
                return 4;
        /* DIC labels GSA-4163B as an Xbox swap candidate, not a normal 0xE7
         * Nintendo-disc cache dump profile, so keep it out of the profile layer. */
        return 0;
 }
 
+static u_int32_t dvd_hlds_e7_detect_type (dvd_drive *dvd) {
+       if (!dvd)
+               return 0;
+       return dvd_detect_hlds_e7_type_for_identity (
+               dvd -> vendor,
+               dvd -> prod_id,
+               dvd -> prod_rev
+       );
+}
+
 static bool dvd_is_hlds_gc_wii_drive (dvd_drive *dvd) {
        return dvd_hlds_e7_detect_type (dvd) != 0;
 }
 static bool dvd_is_hlds_gc_wii_drive (dvd_drive *dvd) {
        return dvd_hlds_e7_detect_type (dvd) != 0;
 }
@@ -509,6 +596,41 @@ void dvd_init_command (mmc_command *mmc, u_int8_t *buf, int len, req_sense *sens
 }
 
 
 }
 
 
+static void dvd_record_command_diagnostic (
+       dvd_drive *dvd,
+       mmc_command *mmc,
+       int transport_result,
+       int os_error,
+       int scsi_status,
+       int sense_key,
+       int asc,
+       int ascq
+) {
+       if (!dvd || !mmc)
+               return;
+       memset (&dvd -> last_command, 0, sizeof (dvd -> last_command));
+       dvd -> last_command.valid = true;
+       dvd -> last_command.transport_result = transport_result;
+       dvd -> last_command.os_error = os_error;
+       dvd -> last_command.scsi_status = scsi_status;
+       dvd -> last_command.sense_key = sense_key & 0x0f;
+       dvd -> last_command.asc = asc & 0xff;
+       dvd -> last_command.ascq = ascq & 0xff;
+       dvd -> last_command.cdb_length = mmc -> cmdlen;
+       if (dvd -> last_command.cdb_length < 0)
+               dvd -> last_command.cdb_length = 0;
+       if (dvd -> last_command.cdb_length > (int) sizeof (dvd -> last_command.cdb))
+               dvd -> last_command.cdb_length = (int) sizeof (dvd -> last_command.cdb);
+       memcpy (dvd -> last_command.cdb, mmc -> cmd, sizeof (dvd -> last_command.cdb));
+}
+
+bool dvd_get_last_command_diagnostic (dvd_drive *dvd, dvd_command_diagnostic *out) {
+       if (!dvd || !out || !dvd -> last_command.valid)
+               return false;
+       *out = dvd -> last_command;
+       return true;
+}
+
 #ifdef WIN32
 
 /* Doc is under the UNIX function */
 #ifdef WIN32
 
 /* Doc is under the UNIX function */
@@ -516,6 +638,8 @@ int dvd_execute_cmd (dvd_drive *dvd, mmc_command *mmc, bool ignore_errors) {
        SCSI_PASS_THROUGH_DIRECT *sptd;
        unsigned char sptd_sense[sizeof (*sptd) + 18], *sense;
        DWORD bytes;
        SCSI_PASS_THROUGH_DIRECT *sptd;
        unsigned char sptd_sense[sizeof (*sptd) + 18], *sense;
        DWORD bytes;
+       DWORD win_error;
+       BOOL ioctl_ok;
        int out;
 
        sptd = (SCSI_PASS_THROUGH_DIRECT *) sptd_sense;
        int out;
 
        sptd = (SCSI_PASS_THROUGH_DIRECT *) sptd_sense;
@@ -533,39 +657,34 @@ int dvd_execute_cmd (dvd_drive *dvd, mmc_command *mmc, bool ignore_errors) {
        else
                sptd -> DataIn = SCSI_IOCTL_DATA_IN;
        sptd -> DataBuffer = mmc -> buffer;
        else
                sptd -> DataIn = SCSI_IOCTL_DATA_IN;
        sptd -> DataBuffer = mmc -> buffer;
-       // Quick hack: Windows hates sptd->DataTransferLength = 1, so we set it to 2 and ignore the second byte.
-       if (mmc -> buflen == 1)         // TODO
+       /* Quick hack: Windows hates DataTransferLength = 1. */
+       if (mmc -> buflen == 1)
                sptd -> DataTransferLength = 2;
        else
                sptd -> DataTransferLength = mmc -> buflen;
        sptd -> TimeOutValue = MMC_CMD_TIMEOUT;
        sptd -> SenseInfoOffset = sizeof (*sptd);
 
                sptd -> DataTransferLength = 2;
        else
                sptd -> DataTransferLength = mmc -> buflen;
        sptd -> TimeOutValue = MMC_CMD_TIMEOUT;
        sptd -> SenseInfoOffset = sizeof (*sptd);
 
-       //fprintf (stdout,"mmc->cmd[00] = %d \n",mmc->cmd[00]);
-       //Set streaming hack
-       if (mmc->cmd[00]==0xB6) {
+       if (mmc -> cmd[0] == 0xB6) {
                sptd -> DataIn = SCSI_IOCTL_DATA_OUT;
                sptd -> DataTransferLength = 28;
        }
 
                sptd -> DataIn = SCSI_IOCTL_DATA_OUT;
                sptd -> DataTransferLength = 28;
        }
 
-       {
-               BOOL ioctl_ok = DeviceIoControl (dvd -> fd, IOCTL_SCSI_PASS_THROUGH_DIRECT,
-                       sptd, sizeof (*sptd) + 18, sptd, sizeof (*sptd) + 18, &bytes, NULL);
-               /* DeviceIoControl may succeed while the drive returns CHECK CONDITION.
-                * Treat any non-GOOD SCSI status as command failure.  ignore_errors only
-                * suppresses diagnostics; it must not turn failed commands into success. */
-               if (!ioctl_ok || sptd -> ScsiStatus != 0) {
-                       out = -1;       /* Failure */
-                       if (!ignore_errors) {
-                               error ("Execution of MMC command failed: Win32=%lu SCSI=0x%02X",
-                               (unsigned long) GetLastError (), sptd -> ScsiStatus);
-                               debug ("Command was: ");
-                               hex_and_ascii_print ("", mmc -> cmd, sizeof (mmc -> cmd));
-                               debug ("Sense data: %02X/%02X/%02X\n", sense[2] & 0x0F, sense[12], sense[13]);
-                       }
-               } else {
-                       out = 0;
+       ioctl_ok = DeviceIoControl (dvd -> fd, IOCTL_SCSI_PASS_THROUGH_DIRECT,
+               sptd, sizeof (*sptd) + 18, sptd, sizeof (*sptd) + 18, &bytes, NULL);
+       win_error = ioctl_ok ? ERROR_SUCCESS : GetLastError ();
+       /* DeviceIoControl may succeed while the drive returns CHECK CONDITION. */
+       if (!ioctl_ok || sptd -> ScsiStatus != 0) {
+               out = -1;
+               if (!ignore_errors) {
+                       error ("Execution of MMC command failed: Win32=%lu SCSI=0x%02X",
+                               (unsigned long) win_error, sptd -> ScsiStatus);
+                       debug ("Command was: ");
+                       hex_and_ascii_print ("", mmc -> cmd, sizeof (mmc -> cmd));
+                       debug ("Sense data: %02X/%02X/%02X\n", sense[2] & 0x0F, sense[12], sense[13]);
                }
                }
+       } else {
+               out = 0;
        }
        
        if (mmc -> sense) {
        }
        
        if (mmc -> sense) {
@@ -573,8 +692,10 @@ int dvd_execute_cmd (dvd_drive *dvd, mmc_command *mmc, bool ignore_errors) {
                mmc -> sense -> asc = sense[12];
                mmc -> sense -> ascq = sense[13];
        }
                mmc -> sense -> asc = sense[12];
                mmc -> sense -> ascq = sense[13];
        }
+       dvd_record_command_diagnostic (dvd, mmc, out, (int) win_error,
+               (int) sptd -> ScsiStatus, sense[2], sense[12], sense[13]);
        
        
-       return (out);
+       return out;
 }
 
 #else
 }
 
 #else
@@ -588,6 +709,7 @@ int dvd_execute_cmd (dvd_drive *dvd, mmc_command *mmc, bool ignore_errors) {
  */
 int dvd_execute_cmd (dvd_drive *dvd, mmc_command *mmc, bool ignore_errors) {
        int out;
  */
 int dvd_execute_cmd (dvd_drive *dvd, mmc_command *mmc, bool ignore_errors) {
        int out;
+       int saved_errno;
        struct cdrom_generic_command cgc;
        struct request_sense sense;
        
        struct cdrom_generic_command cgc;
        struct request_sense sense;
        
@@ -596,8 +718,8 @@ int dvd_execute_cmd (dvd_drive *dvd, mmc_command *mmc, bool ignore_errors) {
        hex_and_ascii_print ("", mmc -> cmd, sizeof (mmc -> cmd));
 #endif
 
        hex_and_ascii_print ("", mmc -> cmd, sizeof (mmc -> cmd));
 #endif
 
-       /* Init Linux-format MMC command */
-       memset (&cgc, 0, sizeof (struct cdrom_generic_command));
+       memset (&sense, 0, sizeof (sense));
+       memset (&cgc, 0, sizeof (cgc));
        memcpy (cgc.cmd, mmc -> cmd, sizeof (mmc -> cmd));
        cgc.buffer = (unsigned char *) mmc -> buffer;
        cgc.buflen = mmc -> buflen;
        memcpy (cgc.cmd, mmc -> cmd, sizeof (mmc -> cmd));
        cgc.buffer = (unsigned char *) mmc -> buffer;
        cgc.buflen = mmc -> buflen;
@@ -607,17 +729,19 @@ int dvd_execute_cmd (dvd_drive *dvd, mmc_command *mmc, bool ignore_errors) {
                cgc.data_direction = CGC_DATA_NONE;
        else
                cgc.data_direction = CGC_DATA_READ;
                cgc.data_direction = CGC_DATA_NONE;
        else
                cgc.data_direction = CGC_DATA_READ;
-       cgc.timeout = MMC_CMD_TIMEOUT * 1000;   /* Linux uses milliseconds */
+       cgc.timeout = MMC_CMD_TIMEOUT * 1000;
        cgc.sense = &sense;
        if (ioctl (dvd -> fd, CDROM_SEND_PACKET, &cgc) < 0) {
        cgc.sense = &sense;
        if (ioctl (dvd -> fd, CDROM_SEND_PACKET, &cgc) < 0) {
-               out = -1;       /* Failure */
+               saved_errno = errno;
+               out = -1;
                if (!ignore_errors) {
                if (!ignore_errors) {
-                       error ("Execution of MMC command failed: %s", strerror (errno));
+                       error ("Execution of MMC command failed: %s", strerror (saved_errno));
                        debug ("Command was:");
                        hex_and_ascii_print ("", cgc.cmd, sizeof (cgc.cmd));
                        debug ("Sense data: %02X/%02X/%02X", sense.sense_key, sense.asc, sense.ascq);
                }
        } else {
                        debug ("Command was:");
                        hex_and_ascii_print ("", cgc.cmd, sizeof (cgc.cmd));
                        debug ("Sense data: %02X/%02X/%02X", sense.sense_key, sense.asc, sense.ascq);
                }
        } else {
+               saved_errno = 0;
                out = 0;
        }
        
                out = 0;
        }
        
@@ -626,8 +750,220 @@ int dvd_execute_cmd (dvd_drive *dvd, mmc_command *mmc, bool ignore_errors) {
                mmc -> sense -> asc = sense.asc;
                mmc -> sense -> ascq = sense.ascq;
        }
                mmc -> sense -> asc = sense.asc;
                mmc -> sense -> ascq = sense.ascq;
        }
+       dvd_record_command_diagnostic (dvd, mmc, out, saved_errno,
+               (int) cgc.stat, sense.sense_key, sense.asc, sense.ascq);
        
        
-       return (out);
+       return out;
+}
+#endif
+
+#ifndef WIN32
+/*
+ * Linux equivalent of the copied Windows SCSI_PASS_THROUGH_DIRECT transport
+ * used by UnlockDrive().  CDROM_SEND_PACKET does not expose an explicit CDB
+ * length and applies a single generic timeout.  The GDR-8050L handshake uses
+ * 6-, 10-, and 12-byte CDBs plus 120-second command timeouts (10 seconds only
+ * for sticky descrambling).  SG_IO preserves those boundaries exactly.
+ */
+static int dvd_xbox_sgio_exact (dvd_drive *dvd,
+               const char *step,
+               const u_int8_t *cdb,
+               int cdb_len,
+               u_int8_t *buf,
+               u_int32_t buf_len,
+               dvd_data_direction direction,
+               unsigned int timeout_ms) {
+       sg_io_hdr_t io;
+       u_int8_t sense[32];
+       mmc_command diagnostic;
+       int rc;
+       int saved_errno = 0;
+       int transport_result;
+       int i;
+
+       if (!dvd || !cdb || cdb_len < 1 || cdb_len > 12)
+               return -1;
+
+       memset (&io, 0, sizeof (io));
+       memset (sense, 0, sizeof (sense));
+       memset (&diagnostic, 0, sizeof (diagnostic));
+
+       io.interface_id = 'S';
+       io.cmdp = (unsigned char *) cdb;
+       io.cmd_len = (unsigned char) cdb_len;
+       io.sbp = sense;
+       io.mx_sb_len = sizeof (sense);
+       io.timeout = timeout_ms;
+       io.dxferp = buf;
+       io.dxfer_len = buf_len;
+
+       switch (direction) {
+       case DVD_DATA_OUT:
+               io.dxfer_direction = SG_DXFER_TO_DEV;
+               break;
+       case DVD_DATA_NONE:
+               io.dxfer_direction = SG_DXFER_NONE;
+               io.dxferp = NULL;
+               io.dxfer_len = 0;
+               break;
+       case DVD_DATA_IN:
+       default:
+               io.dxfer_direction = SG_DXFER_FROM_DEV;
+               break;
+       }
+
+       errno = 0;
+       rc = ioctl (dvd -> fd, SG_IO, &io);
+       if (rc < 0)
+               saved_errno = errno;
+
+       transport_result =
+               (rc == 0 &&
+                io.status == 0 &&
+                io.host_status == 0 &&
+                io.driver_status == 0) ? 0 : -1;
+
+       diagnostic.cmdlen = cdb_len;
+       diagnostic.direction = direction;
+       diagnostic.buffer = buf;
+       diagnostic.buflen = (int) buf_len;
+       memcpy (diagnostic.cmd, cdb, (size_t) cdb_len);
+       dvd_record_command_diagnostic (
+               dvd,
+               &diagnostic,
+               transport_result,
+               saved_errno,
+               (int) io.status,
+               sense[2],
+               sense[12],
+               sense[13]);
+
+       xbox_ref_log_fprintf (
+               stderr,
+               "[XBOX-SGIO] step=%s rc=%d errno=%d status=0x%02X host=0x%04X driver=0x%04X sense=%02X/%02X/%02X resid=%d timeout_ms=%u cdb=[",
+               step ? step : "unnamed",
+               rc,
+               saved_errno,
+               (unsigned int) io.status,
+               (unsigned int) io.host_status,
+               (unsigned int) io.driver_status,
+               (unsigned int) (sense[2] & 0x0F),
+               (unsigned int) sense[12],
+               (unsigned int) sense[13],
+               io.resid,
+               timeout_ms);
+       for (i = 0; i < cdb_len; i++)
+               xbox_ref_log_fprintf (
+                       stderr,
+                       "%s%02X",
+                       i ? " " : "",
+                       (unsigned int) cdb[i]);
+       xbox_ref_log_fprintf (
+               stderr,
+               "] xfer=%u direction=%s result=%s\n",
+               buf_len,
+               direction == DVD_DATA_OUT ? "out" :
+               direction == DVD_DATA_NONE ? "none" : "in",
+               transport_result == 0 ? "PASS" : "FAIL");
+
+       return transport_result;
+}
+
+static int dvd_xbox_exact_read_capacity (dvd_drive *dvd,
+               const char *step,
+               u_int32_t *sectors,
+               u_int32_t *sector_size) {
+       u_int8_t cdb[10];
+       u_int8_t buf[8];
+       u_int32_t max_lba;
+
+       memset (cdb, 0, sizeof (cdb));
+       memset (buf, 0, sizeof (buf));
+       cdb[0] = 0x25;
+
+       if (dvd_xbox_sgio_exact (
+                       dvd, step, cdb, sizeof (cdb), buf, sizeof (buf),
+                       DVD_DATA_IN, 120000) < 0)
+               return -1;
+
+       max_lba =
+               ((u_int32_t) buf[0] << 24) |
+               ((u_int32_t) buf[1] << 16) |
+               ((u_int32_t) buf[2] << 8) |
+               (u_int32_t) buf[3];
+
+       if (sectors)
+               *sectors = max_lba + 1;
+       if (sector_size)
+               *sector_size =
+                       ((u_int32_t) buf[4] << 24) |
+                       ((u_int32_t) buf[5] << 16) |
+                       ((u_int32_t) buf[6] << 8) |
+                       (u_int32_t) buf[7];
+       return 0;
+}
+
+static int dvd_xbox_exact_mode_sense_10 (dvd_drive *dvd,
+               const char *step,
+               u_int8_t page,
+               u_int8_t *buf,
+               size_t buf_len) {
+       u_int8_t cdb[10];
+
+       if (!buf || buf_len > 0xFFFF)
+               return -1;
+       memset (cdb, 0, sizeof (cdb));
+       memset (buf, 0, buf_len);
+       cdb[0] = 0x5A;
+       cdb[2] = page;
+       cdb[7] = (u_int8_t) ((buf_len >> 8) & 0xFF);
+       cdb[8] = (u_int8_t) (buf_len & 0xFF);
+
+       return dvd_xbox_sgio_exact (
+               dvd, step, cdb, sizeof (cdb), buf, (u_int32_t) buf_len,
+               DVD_DATA_IN, 120000);
+}
+
+static int dvd_xbox_exact_mode_select_10 (dvd_drive *dvd,
+               const char *step,
+               const u_int8_t *buf,
+               size_t buf_len) {
+       u_int8_t cdb[10];
+       u_int8_t tmp[256];
+
+       if (!buf || buf_len > sizeof (tmp) || buf_len > 0xFFFF)
+               return -1;
+       memset (cdb, 0, sizeof (cdb));
+       memset (tmp, 0, sizeof (tmp));
+       memcpy (tmp, buf, buf_len);
+       cdb[0] = 0x55;
+       cdb[7] = (u_int8_t) ((buf_len >> 8) & 0xFF);
+       cdb[8] = (u_int8_t) (buf_len & 0xFF);
+
+       return dvd_xbox_sgio_exact (
+               dvd, step, cdb, sizeof (cdb), tmp, (u_int32_t) buf_len,
+               DVD_DATA_OUT, 120000);
+}
+
+static int dvd_xbox_exact_mode_select_6 (dvd_drive *dvd,
+               const char *step,
+               const u_int8_t *buf,
+               size_t buf_len) {
+       u_int8_t cdb[6];
+       u_int8_t tmp[64];
+
+       if (!buf || buf_len > sizeof (tmp) || buf_len > 0xFF)
+               return -1;
+       memset (cdb, 0, sizeof (cdb));
+       memset (tmp, 0, sizeof (tmp));
+       memcpy (tmp, buf, buf_len);
+       cdb[0] = 0x15;
+       cdb[1] = 0x11;
+       cdb[4] = (u_int8_t) buf_len;
+
+       return dvd_xbox_sgio_exact (
+               dvd, step, cdb, sizeof (cdb), tmp, (u_int32_t) buf_len,
+               DVD_DATA_OUT, 10000);
 }
 #endif
 
 }
 #endif
 
@@ -1012,6 +1348,20 @@ int dvd_stop_unit (dvd_drive *dvd, bool start, req_sense *sense) {
        return dvd_start_stop_unit (dvd, start, false, sense);
 }
 
        return dvd_start_stop_unit (dvd, start, false, sense);
 }
 
+int dvd_set_door_lock (dvd_drive *dvd, bool locked) {
+#ifdef WIN32
+       (void) dvd;
+       (void) locked;
+       return 0;
+#else
+       if (!dvd)
+               return -EINVAL;
+       if (ioctl (dvd -> fd, CDROM_LOCKDOOR, locked ? 1 : 0) < 0)
+               return -errno;
+       return 0;
+#endif
+}
+
 int dvd_wait_ready (dvd_drive *dvd, unsigned int timeout_ms) {
        unsigned int waited = 0;
        if (!dvd)
 int dvd_wait_ready (dvd_drive *dvd, unsigned int timeout_ms) {
        unsigned int waited = 0;
        if (!dvd)
@@ -1031,28 +1381,59 @@ int dvd_media_cycle (dvd_drive *dvd, req_sense *sense) {
        int i;
        int out;
 
        int i;
        int out;
 
+#ifndef WIN32
+       /* Linux commonly applies CDO_LOCK while an optical device is open.  A raw
+        * START STOP UNIT eject then fails immediately even though the process owns
+        * the only intentional handle.  Release that kernel/drive door lock before
+        * the GDR-8050L software tray cycle, then restore it after the tray is loaded
+        * and ready.  CDROM_LOCKDOOR is the documented Linux optical-door API. */
+       out = dvd_set_door_lock (dvd, false);
+       if (out < 0) {
+               xbox_ref_log_fprintf (stderr,
+                       "[XBOX][FATAL] Linux media-cycle could not release the optical door lock: %s (errno=%d).\n",
+                       strerror (-out), -out);
+               return out;
+       }
+       xbox_ref_log_fprintf (stderr, "[XBOX] Linux media-cycle released the optical door lock before software eject.\n");
+#endif
+
        /* Match the original GDR-8050L dumper's AutomateTrayCycle(): eject, wait
         * long enough for the tray to extend, close, poll readiness, then settle. */
        out = dvd_start_stop_unit (dvd, false, true, sense); /* LoEj=1, Start=0: eject */
        /* Match the original GDR-8050L dumper's AutomateTrayCycle(): eject, wait
         * long enough for the tray to extend, close, poll readiness, then settle. */
        out = dvd_start_stop_unit (dvd, false, true, sense); /* LoEj=1, Start=0: eject */
-       if (out < 0)
+       if (out < 0) {
+               xbox_ref_log_fprintf (stderr, "[XBOX][FATAL] Media-cycle software eject command failed.\n");
                return out;
                return out;
+       }
        dvd_sleep_ms (3000);
 
        out = dvd_start_stop_unit (dvd, true, true, sense);  /* LoEj=1, Start=1: load */
        dvd_sleep_ms (3000);
 
        out = dvd_start_stop_unit (dvd, true, true, sense);  /* LoEj=1, Start=1: load */
-       if (out < 0)
+       if (out < 0) {
+               xbox_ref_log_fprintf (stderr, "[XBOX][FATAL] Media-cycle software load command failed; the door remains unlocked for recovery.\n");
                return out;
                return out;
+       }
 
        for (i = 0; i < 90; i++) {
                dvd_sleep_ms (500);
                if (dvd_test_unit_ready (dvd, NULL) == 0) {
                        dvd_sleep_ms (1500);
 
        for (i = 0; i < 90; i++) {
                dvd_sleep_ms (500);
                if (dvd_test_unit_ready (dvd, NULL) == 0) {
                        dvd_sleep_ms (1500);
+#ifndef WIN32
+                       out = dvd_set_door_lock (dvd, true);
+                       if (out < 0)
+                               xbox_ref_log_fprintf (stderr,
+                                       "[XBOX][WARN] Linux media-cycle completed, but the optical door could not be re-locked: %s (errno=%d).\n",
+                                       strerror (-out), -out);
+                       else
+                               xbox_ref_log_fprintf (stderr, "[XBOX] Linux media-cycle restored the optical door lock after load.\n");
+#endif
                        return 0;
                }
        }
 
        /* Original dumper falls back to a fixed 10s settle delay if TUR never
                        return 0;
                }
        }
 
        /* Original dumper falls back to a fixed 10s settle delay if TUR never
-        * reports ready after tray close. */
+        * reports ready after tray close.  Keep the door unlocked on failure so the
+        * user can recover the media without power-cycling the external drive. */
        dvd_sleep_ms (10000);
        dvd_sleep_ms (10000);
+       fprintf (stderr, "[XBOX][FATAL] Media-cycle tray closed, but the drive never became ready; the door remains unlocked for recovery.\n");
        return -1;
 }
 
        return -1;
 }
 
@@ -1324,10 +1705,13 @@ int dvd_read_dvd_structure (dvd_drive *dvd, u_int8_t format, u_int8_t layer, u_i
 
        dvd_init_command (&mmc, extbuf, (int) extbufsize, sense);
        mmc.cmd[0] = MMC_READ_DVD_STRUCTURE;
 
        dvd_init_command (&mmc, extbuf, (int) extbufsize, sense);
        mmc.cmd[0] = MMC_READ_DVD_STRUCTURE;
+       /* MMC READ DVD STRUCTURE places Format in CDB byte 7. Byte 11 is
+        * Control and must remain zero. The copied Windows GetMediaID() path
+        * uses the same byte-7 boundary for DMI format 0x04. */
        mmc.cmd[6] = layer;
        mmc.cmd[6] = layer;
+       mmc.cmd[7] = format;
        mmc.cmd[8] = (u_int8_t) ((extbufsize & 0xFF00) >> 8);
        mmc.cmd[9] = (u_int8_t)  (extbufsize & 0x00FF);
        mmc.cmd[8] = (u_int8_t) ((extbufsize & 0xFF00) >> 8);
        mmc.cmd[9] = (u_int8_t)  (extbufsize & 0x00FF);
-       mmc.cmd[11] = format;
        mmc.cmdlen = 12;
 
        return dvd_execute_cmd (dvd, &mmc, false);
        mmc.cmdlen = 12;
 
        return dvd_execute_cmd (dvd, &mmc, false);
@@ -1430,47 +1814,109 @@ int dvd_xbox_vendor_unlock_wxripper (dvd_drive *dvd, u_int32_t *unlocked_sectors
 }
 
 
 }
 
 
-int dvd_xbox_recovery_kick (dvd_drive *dvd, bool auth_recovery) {
-       mmc_command mmc;
-       u_int8_t dummy[2048];
-       u_int8_t auth_probe_buf[8];
-       int i;
+#define XBOX_LOCKED_VIDEO_VIEW_MAX_SECTORS 200000U
+
+static int dvd_xbox_refresh_ready_capacity (dvd_drive *dvd,
+               u_int32_t *sectors,
+               u_int32_t *sector_size) {
+       u_int32_t observed_sectors = 0;
+       u_int32_t observed_sector_size = 0;
 
        if (!dvd)
                return -1;
 
 
        if (!dvd)
                return -1;
 
-       /* Mirrors the proven dumper recovery cadence: after the GDR-8050L
-        * authentication/view switch, re-trigger the Xbox media auth command, set
-        * maximum speed, then issue a few harmless READ(10) probes.  All commands
-        * deliberately ignore errors because the point is to wake/re-prime firmware
-        * state, not to make any one probe authoritative.
-        */
-       if (auth_recovery) {
-               /* GDR-8050L / HLDS auth kick: READ DVD STRUCTURE C0 magic trigger. */
-               dvd_init_command (&mmc, auth_probe_buf, sizeof (auth_probe_buf), NULL);
-               mmc.cmd[0] = MMC_READ_DVD_STRUCTURE;
-               mmc.cmd[2] = 0xFF;
-               mmc.cmd[3] = 0x02;
-               mmc.cmd[4] = 0xFD;
-               mmc.cmd[11] = 0xC0;
-               mmc.cmdlen = 12;
-               dvd_execute_cmd (dvd, &mmc, true);
-
-               /* Hitachi/Kreon-style fallback auth kick: FF 08 01. */
-               dvd_init_command (&mmc, NULL, 0, NULL);
-               mmc.cmd[0] = 0xFF;
-               mmc.cmd[1] = 0x08;
-               mmc.cmd[2] = 0x01;
-               mmc.cmdlen = 10;
-               mmc.direction = DVD_DATA_NONE;
-               dvd_execute_cmd (dvd, &mmc, true);
+       /* Exact portable equivalent of xbox_ref_refresh_ready_capacity():
+        * RefreshVolume(); Sleep(2000); EnsureDriveReady(30000); GetTotalSectors(). */
+       dvd_refresh_volume (dvd);
+       dvd_sleep_ms (2000);
+       if (dvd_wait_ready (dvd, 30000) < 0)
+               return -1;
+       if (dvd_read_capacity_10 (dvd, &observed_sectors, &observed_sector_size, NULL) < 0)
+               return -1;
+
+       if (sectors)
+               *sectors = observed_sectors;
+       if (sector_size)
+               *sector_size = observed_sector_size;
+       return 0;
+}
+
+int dvd_xbox_prepare_game_view (dvd_drive *dvd,
+               u_int32_t *sectors,
+               u_int32_t *sector_size) {
+       u_int32_t entry_sectors = 0;
+       u_int32_t observed_sectors = 0;
+       u_int32_t observed_sector_size = 0;
+
+       if (!dvd || !dvd_is_xbox_challenge_drive (dvd))
+               return -1;
+
+       /* Port xbox_ref_gdr8050l_dump_core() state preparation exactly, replacing
+        * Win32 handle/volume calls with FriiDump's portable Linux equivalents.
+        * No RecoveryKick, media-auth kick, or synthetic LBA-zero read cadence is
+        * part of this stock/cross-flashed GDR-8050L sequence. */
+       if (dvd_wait_ready (dvd, 30000) < 0) {
+               xbox_ref_log_fprintf (stderr,
+                       "[XBOX-WINSEQ][FATAL] Drive did not become ready before Xbox state preparation.\n");
+               return -1;
+       }
+       if (dvd_read_capacity_10 (dvd, &entry_sectors, &observed_sector_size, NULL) < 0) {
+               xbox_ref_log_fprintf (stderr,
+                       "[XBOX-WINSEQ][FATAL] Entry READ CAPACITY failed.\n");
+               return -1;
+       }
+       xbox_ref_log_fprintf (stderr,
+               "[XBOX-WINSEQ] Entry READ CAPACITY: %u sectors.\n",
+               entry_sectors);
+
+       if (entry_sectors > XBOX_LOCKED_VIDEO_VIEW_MAX_SECTORS) {
+               xbox_ref_log_fprintf (stderr,
+                       "[XBOX-WINSEQ] Entry state already exposes the Xbox game view; skipping the redundant initial handshake and tray cycle.\n");
+               if (dvd_xbox_refresh_ready_capacity (dvd, &observed_sectors, &observed_sector_size) < 0)
+                       return -1;
+       } else {
+               xbox_ref_log_fprintf (stderr,
+                       "[XBOX-WINSEQ] Entry state appears locked/video; attempting the full handshake directly without a media transition.\n");
+               if (dvd_xbox_gdr8050l_unlock (dvd, NULL) < 0)
+                       xbox_ref_log_fprintf (stderr,
+                               "[XBOX-WINSEQ][WARN] Direct UnlockDrive transport returned failure; READ CAPACITY remains authoritative.\n");
+               if (dvd_xbox_refresh_ready_capacity (dvd, &observed_sectors, &observed_sector_size) < 0)
+                       return -1;
+               xbox_ref_log_fprintf (stderr,
+                       "[XBOX-WINSEQ] Direct-handshake READ CAPACITY: %u sectors.\n",
+                       observed_sectors);
+
+               if (observed_sectors <= XBOX_LOCKED_VIDEO_VIEW_MAX_SECTORS) {
+                       xbox_ref_log_fprintf (stderr,
+                               "[XBOX-WINSEQ][WARN] Direct handshake did not expose the Xbox game view; performing one tray-cycle recovery and retry.\n");
+                       if (dvd_media_cycle (dvd, NULL) < 0)
+                               return -1;
+                       xbox_ref_log_fprintf (stderr,
+                               "[XBOX-WINSEQ] Re-applying the full handshake after recovery media change.\n");
+                       if (dvd_xbox_gdr8050l_unlock (dvd, NULL) < 0)
+                               xbox_ref_log_fprintf (stderr,
+                                       "[XBOX-WINSEQ][WARN] Recovery UnlockDrive transport returned failure; READ CAPACITY remains authoritative.\n");
+                       if (dvd_xbox_refresh_ready_capacity (dvd, &observed_sectors, &observed_sector_size) < 0)
+                               return -1;
+                       xbox_ref_log_fprintf (stderr,
+                               "[XBOX-WINSEQ] Recovery-handshake READ CAPACITY: %u sectors.\n",
+                               observed_sectors);
+
+                       if (observed_sectors <= XBOX_LOCKED_VIDEO_VIEW_MAX_SECTORS) {
+                               xbox_ref_log_fprintf (stderr,
+                                       "[XBOX-WINSEQ][FATAL] Xbox game view was not established after direct and recovery handshakes.\n");
+                               return -1;
+                       }
+               }
        }
 
        }
 
+       /* Exact next Windows step after state preparation. */
        dvd_set_speed (dvd, 0xFFFF, NULL);
 
        dvd_set_speed (dvd, 0xFFFF, NULL);
 
-       for (i = 0; i < 10; i++)
-               dvd_read_10 (dvd, 0, 1, NULL, dummy, sizeof (dummy));
-
+       if (sectors)
+               *sectors = observed_sectors;
+       if (sector_size)
+               *sector_size = observed_sector_size;
        return 0;
 }
 
        return 0;
 }
 
@@ -1496,11 +1942,16 @@ int dvd_lock_volume (dvd_drive *dvd) {
 #ifdef WIN32
        DWORD bytesReturned = 0;
        if (!dvd)
 #ifdef WIN32
        DWORD bytesReturned = 0;
        if (!dvd)
-               return -1;
-       return DeviceIoControl (dvd -> fd, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &bytesReturned, NULL) ? 0 : -1;
+               return DVD_VOLUME_LOCK_FAILED;
+       return DeviceIoControl (dvd -> fd, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &bytesReturned, NULL)
+               ? DVD_VOLUME_LOCK_OK
+               : DVD_VOLUME_LOCK_FAILED;
 #else
 #else
+       /* Linux CDROM_SEND_PACKET has no FSCTL_LOCK_VOLUME equivalent here.
+        * Return a distinct result instead of falsely reporting an exclusive lock.
+        * The caller may continue after warning about automount/media polling. */
        (void) dvd;
        (void) dvd;
-       return 0;
+       return DVD_VOLUME_LOCK_UNAVAILABLE;
 #endif
 }
 
 #endif
 }
 
@@ -1519,6 +1970,7 @@ static int dvd_xbox_read_host_challenge_table (dvd_drive *dvd, u_int8_t *table,
        if (!table || table_len < 0x664)
                return -1;
 
        if (!table || table_len < 0x664)
                return -1;
 
+#ifdef WIN32
        /* GDR-8050L / Xbox READ DVD STRUCTURE format C0. */
        dvd_init_command (&mmc, table, 0x664, NULL);
        mmc.cmd[0] = MMC_READ_DVD_STRUCTURE;
        /* GDR-8050L / Xbox READ DVD STRUCTURE format C0. */
        dvd_init_command (&mmc, table, 0x664, NULL);
        mmc.cmd[0] = MMC_READ_DVD_STRUCTURE;
@@ -1543,14 +1995,65 @@ static int dvd_xbox_read_host_challenge_table (dvd_drive *dvd, u_int8_t *table,
                mmc.cmdlen = 12;
                out = dvd_execute_cmd (dvd, &mmc, true);
        }
                mmc.cmdlen = 12;
                out = dvd_execute_cmd (dvd, &mmc, true);
        }
+#else
+       {
+               u_int8_t cdb[12];
+
+               memset (cdb, 0, sizeof (cdb));
+               memset (table, 0, table_len);
+               cdb[0] = 0xAD;
+               cdb[2] = 0xFF;
+               cdb[3] = 0x02;
+               cdb[4] = 0xFD;
+               cdb[5] = 0xFF;
+               cdb[6] = 0xFE;
+               cdb[8] = 0x06;
+               cdb[9] = 0x64;
+               cdb[11] = 0xC0;
+               out = dvd_xbox_sgio_exact (
+                       dvd,
+                       "3-read-dvd-structure-c0",
+                       cdb,
+                       sizeof (cdb),
+                       table,
+                       0x664,
+                       DVD_DATA_IN,
+                       120000);
+
+               if (out < 0 || table[772] != 1 || table[773] == 0) {
+                       memset (cdb, 0, sizeof (cdb));
+                       memset (table, 0, table_len);
+                       cdb[0] = 0xFD;
+                       cdb[1] = 0x01;
+                       cdb[8] = 0x06;
+                       cdb[9] = 0x64;
+                       out = dvd_xbox_sgio_exact (
+                               dvd,
+                               "3-read-host-table-fallback-fd",
+                               cdb,
+                               sizeof (cdb),
+                               table,
+                               0x664,
+                               DVD_DATA_IN,
+                               120000);
+               }
+       }
+#endif
 
        if (out < 0 || table[772] != 1)
                return -1;
 
        if (out < 0 || table[772] != 1)
                return -1;
+
+       xbox_ref_log_fprintf (
+               stderr,
+               "[XBOX-SGIO] challenge-table marker=%u entries-byte=%u result=PASS\n",
+               (unsigned int) table[772],
+               (unsigned int) table[773]);
        return 0;
 }
 
 int dvd_xbox_gdr8050l_unlock (dvd_drive *dvd, u_int32_t *unlocked_sectors) {
        int i, k, l;
        return 0;
 }
 
 int dvd_xbox_gdr8050l_unlock (dvd_drive *dvd, u_int32_t *unlocked_sectors) {
        int i, k, l;
+       int out;
        int chalpos[24];
        u_int8_t table[0x664];
        u_int8_t restable[261];
        int chalpos[24];
        u_int8_t table[0x664];
        u_int8_t restable[261];
@@ -1567,8 +2070,15 @@ int dvd_xbox_gdr8050l_unlock (dvd_drive *dvd, u_int32_t *unlocked_sectors) {
        /* Step 1/2: read current capacity and the Xbox mode page. If the drive is
         * already unlocked, this is harmless; the final capacity check below becomes
         * the authority. */
        /* Step 1/2: read current capacity and the Xbox mode page. If the drive is
         * already unlocked, this is harmless; the final capacity check below becomes
         * the authority. */
+#ifdef WIN32
        dvd_read_capacity_10 (dvd, &sectors, &sector_size, NULL);
        dvd_mode_sense_10 (dvd, 0x3E, page, sizeof (page), NULL);
        dvd_read_capacity_10 (dvd, &sectors, &sector_size, NULL);
        dvd_mode_sense_10 (dvd, 0x3E, page, sizeof (page), NULL);
+#else
+       dvd_xbox_exact_read_capacity (
+               dvd, "1-initial-read-capacity", &sectors, &sector_size);
+       dvd_xbox_exact_mode_sense_10 (
+               dvd, "2-mode-sense-3e", 0x3E, page, sizeof (page));
+#endif
 
        /* Step 3: retrieve and decode the host challenge table. */
        if (dvd_xbox_read_host_challenge_table (dvd, table, sizeof (table)) < 0) {
 
        /* Step 3: retrieve and decode the host challenge table. */
        if (dvd_xbox_read_host_challenge_table (dvd, table, sizeof (table)) < 0) {
@@ -1610,8 +2120,15 @@ int dvd_xbox_gdr8050l_unlock (dvd_drive *dvd, u_int32_t *unlocked_sectors) {
        /* Match the original dumper: send the challenge and continue even if
         * Windows reports a transport failure.  The later XDVDFS probe is the
         * authority for whether the drive actually entered the game view. */
        /* Match the original dumper: send the challenge and continue even if
         * Windows reports a transport failure.  The later XDVDFS probe is the
         * authority for whether the drive actually entered the game view. */
+#ifdef WIN32
        dvd_mode_select_10 (dvd, page, sizeof (page), NULL);
        dvd_mode_sense_10 (dvd, 0x3E, page, sizeof (page), NULL);
        dvd_mode_select_10 (dvd, page, sizeof (page), NULL);
        dvd_mode_sense_10 (dvd, 0x3E, page, sizeof (page), NULL);
+#else
+       dvd_xbox_exact_mode_select_10 (
+               dvd, "4-mode-select-challenge-1", page, sizeof (page));
+       dvd_xbox_exact_mode_sense_10 (
+               dvd, "5-mode-sense-verify-1", 0x3E, page, sizeof (page));
+#endif
 
        /* Step 6: second host challenge. */
        memset (page, 0, sizeof (page));
 
        /* Step 6: second host challenge. */
        memset (page, 0, sizeof (page));
@@ -1620,8 +2137,15 @@ int dvd_xbox_gdr8050l_unlock (dvd_drive *dvd, u_int32_t *unlocked_sectors) {
        page[9] = 0x12;
        page[12] = 0x01;
        memcpy (&page[15], &restable[1 + chalpos[k - 1] * 11], 5);
        page[9] = 0x12;
        page[12] = 0x01;
        memcpy (&page[15], &restable[1 + chalpos[k - 1] * 11], 5);
+#ifdef WIN32
        dvd_mode_select_10 (dvd, page, sizeof (page), NULL);
        dvd_mode_sense_10 (dvd, 0x3E, page, sizeof (page), NULL);
        dvd_mode_select_10 (dvd, page, sizeof (page), NULL);
        dvd_mode_sense_10 (dvd, 0x3E, page, sizeof (page), NULL);
+#else
+       dvd_xbox_exact_mode_select_10 (
+               dvd, "6-mode-select-challenge-2", page, sizeof (page));
+       dvd_xbox_exact_mode_sense_10 (
+               dvd, "7-mode-sense-verify-2", 0x3E, page, sizeof (page));
+#endif
 
        /* Step 8: unlock partition 1. */
        memset (page, 0, sizeof (page));
 
        /* Step 8: unlock partition 1. */
        memset (page, 0, sizeof (page));
@@ -1634,14 +2158,24 @@ int dvd_xbox_gdr8050l_unlock (dvd_drive *dvd, u_int32_t *unlocked_sectors) {
        page[13] = 0xD1;
        page[14] = 0x01;
        memcpy (&page[15], &restable[1 + chalpos[k - 1] * 11], 5);
        page[13] = 0xD1;
        page[14] = 0x01;
        memcpy (&page[15], &restable[1 + chalpos[k - 1] * 11], 5);
+#ifdef WIN32
        dvd_mode_select_10 (dvd, page, sizeof (page), NULL);
        dvd_mode_select_10 (dvd, page, sizeof (page), NULL);
+#else
+       dvd_xbox_exact_mode_select_10 (
+               dvd, "8-mode-select-partition-1-unlock", page, sizeof (page));
+#endif
 
        /* Step 9: sticky descrambling, mode page 0x31. */
        memset (sticky, 0, sizeof (sticky));
        sticky[4] = 0x31;
        sticky[5] = 0x06;
        sticky[6] = 0x01;
 
        /* Step 9: sticky descrambling, mode page 0x31. */
        memset (sticky, 0, sizeof (sticky));
        sticky[4] = 0x31;
        sticky[5] = 0x06;
        sticky[6] = 0x01;
+#ifdef WIN32
        dvd_mode_select_6 (dvd, sticky, sizeof (sticky), NULL);
        dvd_mode_select_6 (dvd, sticky, sizeof (sticky), NULL);
+#else
+       dvd_xbox_exact_mode_select_6 (
+               dvd, "9-mode-select-sticky-descrambling", sticky, sizeof (sticky));
+#endif
 
        /* Step 10: final capacity observation.  The original UnlockDrive() only
         * prints this verification and does not fail if the capacity has not changed
 
        /* Step 10: final capacity observation.  The original UnlockDrive() only
         * prints this verification and does not fail if the capacity has not changed
@@ -1649,12 +2183,24 @@ int dvd_xbox_gdr8050l_unlock (dvd_drive *dvd, u_int32_t *unlocked_sectors) {
         * prime the drive before the required media-change event. */
        sectors = 0;
        sector_size = 0;
         * prime the drive before the required media-change event. */
        sectors = 0;
        sector_size = 0;
-       if (dvd_read_capacity_10 (dvd, &sectors, &sector_size, NULL) == 0) {
+#ifdef WIN32
+       out = dvd_read_capacity_10 (dvd, &sectors, &sector_size, NULL);
+#else
+       out = dvd_xbox_exact_read_capacity (
+               dvd, "10-final-read-capacity", &sectors, &sector_size);
+#endif
+       if (out == 0) {
                if (unlocked_sectors)
                        *unlocked_sectors = sectors;
                if (unlocked_sectors)
                        *unlocked_sectors = sectors;
-               fprintf (stderr, "[XBOX] GDR-8050L handshake complete; READ CAPACITY reports %u sectors of %u bytes.\n", sectors, sector_size);
+               xbox_ref_log_fprintf (
+                       stderr,
+                       "[XBOX] GDR-8050L handshake complete; READ CAPACITY reports %u sectors of %u bytes.\n",
+                       sectors,
+                       sector_size);
        } else {
        } else {
-               fprintf (stderr, "[XBOX] GDR-8050L handshake sent; final READ CAPACITY verify failed, continuing like original dumper.\n");
+               xbox_ref_log_fprintf (
+                       stderr,
+                       "[XBOX] GDR-8050L handshake sent; final READ CAPACITY verify failed, continuing like original dumper.\n");
        }
 
        return 0;
        }
 
        return 0;