SINTRAN III SCSI Optical Disk Commands - Addendum¶
Document Created: 2025-10-13 Source File: IP-P2-SCSI-OPDI.NPL Purpose: Document optical disk-specific SCSI commands and write recovery mechanism
Overview¶
The optical disk driver (IP-P2-SCSI-OPDI.NPL) extends the standard SCSI disk driver with special handling for write-once and rewritable optical media (WORM and MO disks). The key difference is the CCRWO (Compare-Compare-Rewrite-Optical) recovery mechanism.
Optical-Specific SCSI Commands¶
1. VERIFY(10) with BYTCHK - Used as COMPARE¶
Command: 0x2F with BYTCHK bit set Source: Line 303-304
Command Block (10-byte CDB):
Byte 0: 0x2F % VERIFY(10) opcode
Byte 1: 0x02 % BYTCHK bit (bit 1) set = compare mode
Bytes 2-5: Logical Block Address % Start block (big-endian)
Bytes 6-7: Reserved
Bytes 8-9: Verification Length % Number of blocks
Purpose: - Compares data on optical media with data in host memory - Used in CCRWO write recovery to detect blank or corrupted blocks
Data Phase: - OUT (Host → Device) - Device reads media and compares byte-by-byte with host data
Expected Status: - GOOD (0x00): Data matches perfectly - CHECK CONDITION: Mismatch detected
CHECK CONDITION Sense Keys: - 0x05 (ILLEGAL REQUEST): Block out of range - 0x03 (MEDIUM ERROR): Media defect prevents comparison - 0x08 (BLANK CHECK): Block contains blank/unwritten data ← CRITICAL for optical
SINTRAN Processing (Lines 315-327):
IF A=100010 THEN % BLANK CHECK (0x08 << 13 = 0100010 octal)
% Block is blank - rewrite it
% Switch from VERIFY to WRITE command
FI
Decoding the Status Check:
- A=100010 means sense key = 8 (BLANK CHECK)
- Bit 15 is set (extended sense indicator)
- This is the optical disk's way of saying "this block was never written"
2. WRITE(10) - Extended Write Command¶
Command: 0x2A Source: Line 317
Command Block (10-byte CDB):
Byte 0: 0x2A % WRITE(10) opcode
Byte 1: Flags
Bit 3: FUA (Force Unit Access) - bypass cache
Bit 4: DPO (Disable Page Out) - don't cache
Bytes 2-5: Logical Block Address % Start block (big-endian)
Byte 6: Group Number (reserved)
Bytes 7-8: Transfer Length % Number of blocks (big-endian)
Byte 9: Control
Why WRITE(10) instead of WRITE(6)?
WRITE(10) is used for optical disks because: 1. Larger address space - Optical disks can be > 2GB (21-bit limit of WRITE(6)) 2. Better error detection - More status bits available 3. FUA/DPO control - Important for write-once media
SINTRAN Usage (Lines 317-326):
25000; *STATX 00; LDATX 20 % WRITE(10) command, load next word
A=:L; ABPA3; *STDTX 10; LDDTX 30 % Store failing address
AD SHZ -10; ABP32-L=:L:=:D-D % Calculate new amount (partial write)
Partial Write Support: If COMPARE finds a blank block in the middle of a write: - Calculates remaining blocks after the blank block - Adjusts memory address to skip already-written blocks - Issues WRITE(10) for remaining data only
CCRWO: Compare-Compare-Rewrite-Optical Recovery¶
Purpose¶
The CCRWO routine (lines 299-329) implements write recovery for optical disks. It handles the case where a write operation fails due to media defects or partial writes.
When CCRWO is Triggered¶
Trigger Conditions (Lines 248-252):
IF PFAIL=T OR SBRST=T OR LIRST=T THEN
D:=X; 77/\X.SLINK.ABFUN; D=:X:=A
IF 1=D OR 61=D THEN % Function 1 or 61 = WRITE
X.OPSTA BONE 4SRWO=:X.OPSTA % Set write recovery flag
FI
FI
Trigger Reasons: - PFAIL: Power failure detected during write - SBRST: SCSI bus reset occurred - LIRST: LUN reset occurred - Functions 1 or 61: Only for WRITE operations
CCRWO Algorithm Flow¶
Step 1: Compare Written Data (Lines 301-314)
┌─────────────────────────────────────────────┐
│ Build VERIFY(10) with BYTCHK command │
│ - Opcode: 0x2F │
│ - BYTCHK bit set (0x02 in byte 1) │
│ - Address: Original write start address │
│ - Length: Original write length │
│ - Data: Original write data buffer │
└─────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ Send VERIFY command to device │
│ Device compares media with host data │
└─────────────────────────────────────────────┘
Step 2: Analyze VERIFY Result (Line 315)
┌─────────────────────────┐
│ VERIFY Status? │
└────────────┬────────────┘
│
┌─────────────┴──────────────┐
│ │
▼ ▼
┌─────────┐ ┌──────────┐
│ GOOD │ │ CHECK │
│ Status │ │CONDITION │
└────┬────┘ └─────┬────┘
│ │
▼ ▼
All data ┌──────────────────────────────┐
verified │ Check Sense Key │
correctly └────────────┬─────────────────┘
│
┌────────────┴────────────┐
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ Sense Key 8 │ │ Other │
│ BLANK CHECK │ │ Error │
└──────┬───────┘ └──────┬───────┘
│ │
▼ ▼
Rewrite blank Report error
blocks (Step 3) and exit
Step 3: Rewrite Blank Blocks (Lines 316-327)
If BLANK CHECK detected:
% Get failing block address from sense data
A=:L; ABPA3; *STDTX 10; LDDTX 30 % Load address of first blank block
% Calculate how many blocks remain after blank block
ABP32-L=:L:=:D-D % Remaining blocks
% Adjust memory buffer pointer to skip good blocks
A:=0; D:=L; *EXR ST
AD SHZ -1; A:=:D+X.MEMA2=:X.MEMA2 % New memory address
A:=D+C+X.MEMA1=:X.MEMA1
% Issue WRITE(10) command for remaining blocks
25000; *STATX 00 % WRITE(10) opcode
% ... (setup CDB with new address and length)
CALL SCSID % Execute write
Why This Works:
For optical media with defects: 1. Initial WRITE command partially succeeds, writes good blocks 2. Encounters bad/blank block, returns CHECK CONDITION 3. CCRWO runs VERIFY with BYTCHK to check what was written 4. Device compares media with buffer, finds first mismatch 5. Returns BLANK CHECK with exact address of failed block 6. SINTRAN rewrites only the failed and subsequent blocks 7. Good blocks that were already written are skipped
Optical Disk Device Types¶
INQUIRY Device Type Values¶
Device Type 0x04: Write-Once (WORM)
// INQUIRY response byte 0
device_type = 0x04;
Characteristics: - Can write to each block only once - Cannot erase or rewrite blocks - Used for archival storage - Example: OSI LD 1200 SCSI
SINTRAN Behavior (Lines 214-216):
IF SUTYP SHZ -10><3 AND ><4 THEN
T:=TYPER; GO FAR ERREX % ILLEGAL DEVICE TYPE
FI
Accepted Types: - Type 3: Processor device (rare) - Type 4: Write-once device
Device Type 0x07: Optical Memory (Rewritable MO)
Although not explicitly shown in the code, SCSI-2 defines:
device_type = 0x07; // Optical memory (Magneto-Optical)
Characteristics: - Can rewrite blocks multiple times - Uses magnetic field + laser for writing - More reliable than magnetic disks - Example: Sony, Fujitsu MO drives
SINTRAN may accept type 7 through type 4 handling.
Write Recovery Example Scenario¶
Scenario: Write to Defective Optical Disk¶
Initial Write Request:
Function: 1 (WRITE)
Address: Block 1000
Length: 100 blocks (1000-1099)
Data: Buffer at memory address 0x10000
What Happens:
Attempt 1: Normal WRITE
1. SINTRAN issues WRITE(10) command
- Start: Block 1000
- Length: 100 blocks
2. Optical drive writes:
- Blocks 1000-1019 ✓ (20 blocks succeed)
- Block 1020 ✗ (media defect)
- Write aborts with CHECK CONDITION
3. REQUEST SENSE returns:
- Sense Key: 0x03 (MEDIUM ERROR)
- Information: 0x000003EC (1020 in decimal)
4. SINTRAN detects write failure on Function 1
- Sets OPSTA bit 4SRWO (write recovery needed)
Attempt 2: CCRWO Recovery
5. CCRWO routine activates (line 226)
6. Issues VERIFY(10) with BYTCHK:
- Start: Block 1000
- Length: 100 blocks
- Data: Original buffer at 0x10000
7. Optical drive compares:
- Blocks 1000-1019: Match ✓
- Block 1020: BLANK (not written) ✗
- Returns CHECK CONDITION
8. REQUEST SENSE returns:
- Sense Key: 0x08 (BLANK CHECK)
- Information: 0x000003EC (block 1020)
- Valid bit set, Information field contains first blank block
Attempt 3: Rewrite Remaining Blocks
9. CCRWO calculates:
- Blocks written successfully: 20 (1000-1019)
- First failed block: 1020
- Remaining blocks: 100 - 20 = 80 blocks
- New memory address: 0x10000 + (20 × 2048) = 0x1A000
10. Issues new WRITE(10):
- Start: Block 1020
- Length: 80 blocks (1020-1099)
- Data: Buffer at 0x1A000
11. Optical drive writes:
- Blocks 1020-1099 ✓ (80 blocks succeed)
- Returns GOOD status
12. Operation completes successfully
- Total blocks written: 20 + 80 = 100 ✓
Final Result: - All 100 blocks written despite media defect at block 1020 - SINTRAN automatically recovered without user intervention - Blocks 1000-1019 not rewritten (already good)
BLANK CHECK Sense Key (0x08)¶
Special Meaning for Optical Disks¶
Standard SCSI-2 Definition:
Sense Key 0x08: BLANK CHECK
- Indicates attempt to read blank medium
- Used for sequential access devices (tape)
- Optical: Indicates unwritten or erased block
SINTRAN Interpretation (Line 315):
IF A=100010 THEN % Sense key 8, bit 15 set
% This block is blank - needs to be written
When BLANK CHECK Occurs:
-
Reading unwritten blocks on WORM
- Application reads block that was never written
- Drive returns BLANK CHECK
- Data returned is zeros or undefined
-
VERIFY after partial write
- Write operation was interrupted
- VERIFY with BYTCHK finds first unwritten block
- Drive returns BLANK CHECK with block address
-
Format verification
- Checking if disk is formatted
- Unformatted areas return BLANK CHECK
ASC/ASCQ Values:
ASC 0x00, ASCQ 0x05: End of data detected
ASC 0x14, ASCQ 0x05: Record not found (blank)
Handling in C# Emulator¶
public class OpticalDiskEmulator
{
// Track which blocks have been written
private BitArray writtenBlocks;
public ScsiStatus HandleVerifyCommand(byte[] cdb, byte[] dataBuffer)
{
uint startBlock = GetLBA(cdb);
uint numBlocks = GetTransferLength(cdb);
bool byteCheck = (cdb[1] & 0x02) != 0;
if (byteCheck)
{
// Compare mode - check each block
for (uint i = 0; i < numBlocks; i++)
{
uint blockNum = startBlock + i;
// Check if block was ever written
if (!writtenBlocks[blockNum])
{
// Generate BLANK CHECK sense
SetSense(
senseKey: 0x08, // BLANK CHECK
asc: 0x14,
ascq: 0x05,
information: blockNum // Which block is blank
);
return ScsiStatus.CheckCondition;
}
// Compare block data with buffer
if (!CompareBlockData(blockNum, dataBuffer, i * blockSize))
{
// Data mismatch
SetSense(
senseKey: 0x03, // MEDIUM ERROR
asc: 0x11,
ascq: 0x00,
information: blockNum
);
return ScsiStatus.CheckCondition;
}
}
}
return ScsiStatus.Good;
}
public ScsiStatus HandleWriteCommand(byte[] cdb, byte[] dataBuffer)
{
uint startBlock = GetLBA(cdb);
uint numBlocks = GetTransferLength(cdb);
for (uint i = 0; i < numBlocks; i++)
{
uint blockNum = startBlock + i;
// For WORM media, check if already written
if (isWORM && writtenBlocks[blockNum])
{
// Cannot overwrite on WORM
SetSense(
senseKey: 0x05, // ILLEGAL REQUEST
asc: 0x21,
ascq: 0x00,
information: blockNum
);
return ScsiStatus.CheckCondition;
}
// Write the block
WriteBlock(blockNum, dataBuffer, i * blockSize);
writtenBlocks[blockNum] = true;
}
return ScsiStatus.Good;
}
}
MODE SELECT for Optical Disks¶
Optical-Specific Mode Parameters¶
Source: Lines 111-124
Command Flow:
MDSEL: IF SUTYP SHZ -10=3 THEN % Device type 3 (processor)
1 % Mode page 1
ELSE
"0" % Mode page 0
FI
X=:MSXRG; T:=X.CMAD1; X:=X.CMAD2
A SHZ 10; *STZTX 00; STATX 10 % Sense data header
Mode Parameter Header:
Byte 0-1: Reserved (0x0000)
Byte 2-3: Block descriptor length = 4
Block Descriptor:
Byte 0: Density code (for optical: media type)
- 0x01: CD-ROM
- 0x02: DVD-ROM
- 0x10: Rewritable MO
- 0x11: Write-once
Bytes 1-3: Reserved
Why This Matters:
Optical drives need MODE SELECT to: 1. Set write power level 2. Configure error correction mode 3. Set defect management on/off 4. Configure write verification
Optical Disk Functions¶
Supported Functions (Lines 10-28)¶
| Function | Octal | Description | Notes |
|---|---|---|---|
| 0 | 00 | READ | Same as magnetic disk |
| 1 | 01 | WRITE | With CCRWO recovery |
| 2 | 02 | READ PARITY | Verify read |
| 3 | 03 | COMPARE | Not implemented (line 85) |
| 4 | 04 | SEEK | Pre-positioning |
| 34 | 42 | RESERVE DEVICE | Multi-host support |
| 35 | 43 | RELEASE DEVICE | Multi-host support |
| 37 | 45 | READ EXTENDED STATUS | Get sense data |
| 42 | 52 | READ FORMAT | Get disk geometry |
| 60 | 74 | READ (Double address) | Large disks > 4GB |
| 61 | 75 | WRITE (Double address) | With CCRWO recovery |
| 62 | 76 | READ PARITY (Double) | Large disk verify |
| 63 | 77 | COMPARE (Double) | Not implemented |
| 73 | 111 | TEST UNIT READY | Status check |
| 74 | 112 | USER SPECIFIED CDB | Custom commands |
| 75 | 113 | INQUIRY | Device identification |
COMPARE Not Implemented¶
Line 84-86:
IF A/\17=5 AND 77/\X.ABFUN=3 OR=63 THEN
0=:X.HSTAT % COMPARE NOT IMPLEMENTED
FI
Reason: - Sense key 5 = ILLEGAL REQUEST - Functions 3 and 63 are COMPARE functions - SINTRAN clears error status (pretends success) - COMPARE would use VERIFY with BYTCHK, but SINTRAN doesn't fully implement it for explicit COMPARE function calls - CCRWO uses VERIFY internally, but user applications cannot call COMPARE directly
Implementation Checklist for C# Optical Emulator¶
Required Features¶
- [ ] VERIFY(10) with BYTCHK support
- [ ] Compare media data with host buffer
- [ ] Return GOOD if all blocks match
- [ ] Return BLANK CHECK (0x08) for unwritten blocks
- [ ] Set Information field to first mismatched block address
- [ ] WRITE(10) support
- [ ] Accept 10-byte CDB format
- [ ] Support large LBAs (32-bit addresses)
- [ ] Track which blocks have been written
- [ ] BLANK CHECK sense generation
- [ ] Sense Key = 0x08
- [ ] Information field = block address
- [ ] ASC/ASCQ appropriate values
- [ ] WORM write protection
- [ ] For WORM media (type 4), prevent overwriting written blocks
- [ ] Return ILLEGAL REQUEST if attempting to overwrite
- [ ] MODE SELECT parsing
- [ ] Accept mode page 0 or 1
- [ ] Parse block descriptor
- [ ] Store density/media type
- [ ] CCRWO compatibility
- [ ] Support VERIFY → BLANK CHECK → WRITE sequence
- [ ] Return accurate block numbers in sense data
- [ ] Handle partial writes correctly
Testing Scenarios¶
Test 1: Normal Write¶
1. WRITE(10) blocks 1000-1099
2. All blocks succeed
3. Return GOOD status
4. writtenBlocks[1000-1099] all set
Test 2: Write with Defect¶
1. WRITE(10) blocks 1000-1099
2. Blocks 1000-1019 succeed
3. Block 1020 fails (simulated defect)
4. Return CHECK CONDITION, sense key 0x03, info=1020
5. writtenBlocks[1000-1019] set, [1020+] clear
Test 3: CCRWO Recovery¶
1. After Test 2 failure
2. Receive VERIFY(10) with BYTCHK, blocks 1000-1099
3. Compare blocks 1000-1019: Match ✓
4. Check block 1020: Not written (blank) ✗
5. Return CHECK CONDITION, sense key 0x08, info=1020
6. Receive WRITE(10), blocks 1020-1099
7. Write all blocks successfully
8. Return GOOD status
9. writtenBlocks[1000-1099] all set
Test 4: WORM Protection¶
1. WRITE(10) block 1000 (first time)
2. Return GOOD, writtenBlocks[1000] set
3. WRITE(10) block 1000 (second time)
4. Return CHECK CONDITION, sense key 0x05 (ILLEGAL REQUEST)
5. ASC = 0x21 (Logical block address out of range or write protected)
Test 5: INQUIRY¶
1. Receive INQUIRY command
2. Return device type 0x04 (Write-once)
3. Vendor: "OSI " (space padded)
4. Product: "LD 1200 SCSI "
5. Followed by READ CAPACITY
Summary¶
Key Differences: Optical vs Magnetic¶
| Aspect | Magnetic Disk | Optical Disk |
|---|---|---|
| Write Command | WRITE(6) 0x0A | WRITE(10) 0x2A |
| Addressing | 21-bit (2MB limit) | 32-bit (2TB limit) |
| Error Recovery | Retry on error | CCRWO (Compare-Rewrite) |
| Overwrite | Unlimited | WORM: once only; MO: limited |
| BLANK CHECK | Rare | Critical for recovery |
| VERIFY | Optional | Required for CCRWO |
| Device Type | 0x00 | 0x04 (WORM), 0x07 (MO) |
CCRWO Advantages¶
- Automatic Recovery - No user intervention needed
- Selective Rewrite - Only rewrites failed blocks
- Media Defect Tolerance - Works around bad sectors
- Data Integrity - Verifies all data written correctly
C# Implementation Key Points¶
- Track written blocks with BitArray or similar
- VERIFY with BYTCHK must compare and return BLANK CHECK
- Information field in sense data must contain exact block number
- Partial writes supported - can write subset of requested blocks
- WORM enforcement - prevent overwriting once-written blocks
Document Path: Source Code\Sintran L\NPL\SCSI-Optical-Commands-Addendum.md
Related Documents: - SCSI-Commands-Analysis.md - General SCSI commands - IP-P2-SCSI-OPDI.md - Full optical driver documentation - SCSI-C#-Implementation-Guide.md - C# emulator implementation guide