DF-3691 / mkmeta.py
#!/usr/bin/env python3 """Build crafted nata RAID metadata disk images for the DF-369x PoCs. Disks are sized to a multiple of 1008 sectors (16 heads * 63 spt as reported by QEMU ide-hd) so that: PROMISE_LBA = total_secs - 63 ADP_LBA = total_secs - 17 """ import struct, sys SECS = 1008 * 260 # 262080 sectors = 128.0625 MB IMG_SECTORS = SECS def promise_native(path, *, rtype, array_width, total_disks, total_sectors, disk_sectors, stripe_shift=0, gen=1, diskflags=(0x06, 0x00)): b = bytearray(2048) b[0:24] = b"FreeBSD ATA driver RAID " # ATA_MAGIC (23 bytes + NUL from bzero) struct.pack_into("<Q", b, 28, 0x1122334455667788) # meta->magic_0 # struct promise_raid_conf.raid @512 struct.pack_into("<I", b, 512, 0x00000080) # integrity = PR_I_VALID struct.pack_into("<B", b, 517, 0) # raid.disk_number struct.pack_into("<I", b, 532, disk_sectors) # raid.disk_sectors struct.pack_into("<H", b, 540, gen) # raid.generation struct.pack_into("<B", b, 542, 0x0f) # status VALID|ONLINE|INITED|READY struct.pack_into("<B", b, 543, rtype) struct.pack_into("<B", b, 544, total_disks) struct.pack_into("<B", b, 545, stripe_shift) struct.pack_into("<B", b, 546, array_width) struct.pack_into("<B", b, 547, 0) # array_number struct.pack_into("<I", b, 548, total_sectors) struct.pack_into("<H", b, 552, 3) # cylinders struct.pack_into("<B", b, 554, 254) # heads struct.pack_into("<B", b, 555, 63) # sectors # raid.disk[8] @564, 12 bytes each for i in range(2): off = 564 + 12 * i struct.pack_into("<B", b, off, diskflags[i]) # PR_F_ONLINE|PR_F_ASSIGNED etc struct.pack_into("<Q", b, off + 4, 0x1122334455667788) # checksum: sum of first 511 LE u32 words stored at word 511 words = struct.unpack_from("<511I", b, 0) struct.pack_into("<I", b, 2044, sum(words) & 0xffffffff) wr(path, b, SECS - 63) def adaptec(path, *, total_disks, gen=1, stripe_shift=0): b = bytearray(8704) struct.pack_into("<I", b, 0, 0xc4650790) # magic_0 (raw native compare) struct.pack_into(">I", b, 4, gen) # generation (be32toh) struct.pack_into(">H", b, 8, 1) # total_configs # configs[0] @64 (all big endian per header comment) struct.pack_into(">H", b, 64 + 0, total_disks) # total_disks @64 struct.pack_into(">H", b, 64 + 2, gen) # generation struct.pack_into("<I", b, 64 + 4, 0xAAAABBBB) # magic_0 (raw) struct.pack_into("<B", b, 64 + 9, 0x00) # type = ADP_T_RAID0 (raw byte) @73 struct.pack_into(">I", b, 64 + 24, 100000) # sectors @88 (be32) struct.pack_into("<H", b, 64 + 28, stripe_shift) # stripe_shift @92 (native use) struct.pack_into("<I", b, 8448, 0x4d545044) # magic_3 @8448 (raw native compare) wr(path, b, SECS - 17) def wr(path, meta, lba): with open(path, "wb") as f: f.truncate(0) f.truncate(SECS * 512) f.seek(lba * 512) f.write(bytes(meta)) print("%s: %d sectors, metadata at LBA %d (%d bytes)" % (path, SECS, lba, len(meta))) if __name__ == "__main__": d = "/tmp/opencode/araid/" # F2/DF-3691: RAID0, width=64 (>MAX_DISKS=16), total_disks=1 -> array READY, # strategy drv = blkno % 64 picks disks[32]/disks[63] OOB. promise_native(d + "f2_width.img", rtype=0x00, array_width=64, total_disks=1, total_sectors=100000, disk_sectors=100000) # F7/DF-3696: RAID5 width=2, total_disks=2, disk1 offline -> DEGRADED -> # strategy leaks request and never completes the bio. promise_native(d + "f7_r5deg.img", rtype=0x04, array_width=2, total_disks=2, total_sectors=100000, disk_sectors=100000, diskflags=(0x06, 0x00)) # F1/DF-3690: Adaptec RAID0 total_disks=60000 -> zero-loop disks[0..59999]. adaptec(d + "f1_adaptec.img", total_disks=60000) |