mt1959: separate A/B firmware upload paths

A (): single WRITE_BUFFER → verify 0x45 → unlock×2
B (): WRITE handshake → READ 0x3000 → WRITE 16B → verify → unlock×5

9/10 handlers are identical A/B. Only load_firmware has different logic.
Both paths end with do_unlock() — firmware upload is a prerequisite for
unlock, not a substitute. init() tries unlock first, falls back to
load_firmware only on failure (cold boot).
This commit is contained in:
MattJackson
2026-04-08 20:35:43 -07:00
parent 760bab0893
commit 4153d23652
+103 -23
View File
@@ -158,10 +158,18 @@ impl Platform for Mt1959 {
} }
/// ///
/// 1. WRITE_BUFFER mode=6 with ld_microcode (size = payload.len()) /// Two variants with different upload sequences:
/// 2. Check all bytes transferred ///
/// 3. READ_BUFFER buf=0x45 verify (4 bytes, expect response == 2) /// 1. WRITE_BUFFER mode=6 with ld_microcode
/// 4. do_unlock() × 2 /// 2. READ_BUFFER buf=0x45 verify (expect response == 2)
/// 3. do_unlock() × 2
///
/// 1. WRITE_BUFFER with mode=2 buf=0x77 initial handshake (0x9C0 bytes)
/// 2. Check response == 2
/// 3. READ_BUFFER at offset 0x3000 (16 bytes, firmware metadata check)
/// 4. WRITE_BUFFER mode=6 with ld_microcode (16 bytes from payload+16)
/// 5. READ verify
/// 6. do_unlock() × 5 retries
fn load_firmware(&mut self, scsi: &mut dyn ScsiTransport) -> Result<()> { fn load_firmware(&mut self, scsi: &mut dyn ScsiTransport) -> Result<()> {
let microcode = &self.profile.ld_microcode; let microcode = &self.profile.ld_microcode;
if microcode.is_empty() { if microcode.is_empty() {
@@ -170,25 +178,13 @@ impl Platform for Mt1959 {
}); });
} }
// scsi_send(TO_DEVICE, ld_microcode, len) if self.mode == 0x01 {
let len = microcode.len(); // ── MT1959-A path ──────────────────────────────────────────
let cdb = [ self.load_firmware_a(scsi)?;
0x3B, 0x06, 0x00, } else {
0x00, 0x00, 0x00, // ── MT1959-B path ──────────────────────────────────────────
(len >> 16) as u8, (len >> 8) as u8, len as u8, self.load_firmware_b(scsi)?;
0x00, }
];
let mut data = microcode.clone();
scsi.execute(&cdb, DataDirection::ToDevice, &mut data, 30_000)?;
let verify_cdb = [0x3C, 0x01, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00];
let mut verify_resp = [0u8; 4];
let _ = scsi.execute(
&verify_cdb, DataDirection::FromDevice, &mut verify_resp, 5_000,
);
self.do_unlock(scsi)?;
self.do_unlock(scsi)?;
Ok(()) Ok(())
} }
@@ -519,3 +515,87 @@ impl Platform for Mt1959 {
self.unlocked self.unlocked
} }
} }
// ── Private firmware upload variants ───────────────────────────────────
impl Mt1959 {
///
/// Simple: WRITE all microcode → verify buf=0x45 → unlock × 2.
fn load_firmware_a(&mut self, scsi: &mut dyn ScsiTransport) -> Result<()> {
let microcode = &self.profile.ld_microcode;
let len = microcode.len();
// WRITE_BUFFER mode=6: send entire microcode payload
let cdb = [
0x3B, 0x06, 0x00,
0x00, 0x00, 0x00,
(len >> 16) as u8, (len >> 8) as u8, len as u8,
0x00,
];
let mut data = microcode.clone();
scsi.execute(&cdb, DataDirection::ToDevice, &mut data, 30_000)?;
let verify_cdb = [0x3C, 0x01, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00];
let mut verify_resp = [0u8; 4];
let _ = scsi.execute(
&verify_cdb, DataDirection::FromDevice, &mut verify_resp, 5_000,
);
// Unlock × 2
self.do_unlock(scsi)?;
self.do_unlock(scsi)?;
Ok(())
}
///
/// Multi-step handshake:
/// 1. WRITE initial block via mode/buf (0x9C0 bytes from microcode)
/// 2. READ firmware metadata at offset 0x3000 (16 bytes)
/// 3. WRITE 16 bytes from microcode+16 via mode=6
/// 4. READ verify
/// 5. do_unlock() × 5 retries
fn load_firmware_b(&mut self, scsi: &mut dyn ScsiTransport) -> Result<()> {
let microcode = &self.profile.ld_microcode;
// Step 1: Initial handshake write via mode/buf_id
let handshake_len = 0x9C0usize.min(microcode.len());
let cdb = [
0x3B, self.mode, self.buffer_id,
0x00, 0x00, 0x00,
(handshake_len >> 16) as u8, (handshake_len >> 8) as u8, handshake_len as u8,
0x00,
];
let mut data = microcode[..handshake_len].to_vec();
scsi.execute(&cdb, DataDirection::ToDevice, &mut data, 30_000)?;
// Step 2: READ firmware metadata at offset 0x3000 (16 bytes)
let meta_cdb = [0x3C, 0x06, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x10, 0x00];
let mut meta_resp = [0u8; 16];
let _ = scsi.execute(&meta_cdb, DataDirection::FromDevice, &mut meta_resp, 5_000);
// Step 3: WRITE 16 bytes from microcode offset 16 via mode=6
if microcode.len() > 32 {
let write2_cdb = [
0x3B, 0x06, 0x00,
0x00, 0x00, 0x00,
0x00, 0x00, 0x10, 0x00,
];
let mut data2 = microcode[16..32].to_vec();
let _ = scsi.execute(&write2_cdb, DataDirection::ToDevice, &mut data2, 5_000);
}
// Step 4: READ verify
let verify_cdb = [0x3C, self.mode, self.buffer_id, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00];
let mut verify_resp = [0u8; 4];
let _ = scsi.execute(&verify_cdb, DataDirection::FromDevice, &mut verify_resp, 5_000);
// Step 5: do_unlock() × 5 retries
for _attempt in 0..5 {
if self.do_unlock(scsi).is_ok() {
return Ok(());
}
}
self.do_unlock(scsi)?;
Ok(())
}
}