SINTRAN III SCSI Commands Analysis¶
Document Created: 2025-10-13 Source Files: IP-P2-SCSI-DISK.NPL, IP-P2-SCSI-DRIV.NPL Purpose: Document all SCSI commands used, their response requirements, and custom command support
Table of Contents¶
- SCSI Commands Used by SINTRAN
- Command Details and Response Requirements
- Custom SCSI Command Support
- INQUIRY Command Support
- Implementation Requirements
SCSI Commands Used by SINTRAN¶
Overview¶
SINTRAN III uses two command mapping arrays (SCSF1 and SCSF2) that map SINTRAN function codes (0-77 octal) to SCSI opcodes. The choice of array depends on the SCSI device type:
- SCSF1: Used for Direct Access Devices (Type 0, 4, 5)
- SCSF2: Used for Sequential Access Devices (Type 1, 2, 3 - Tape devices)
Command Mapping Tables¶
SCSF1 - Direct Access Devices (Disks)¶
| Function | Octal | SCSI Opcode | Command Name | Notes |
|---|---|---|---|---|
| 0 | 00 | 0x08 | READ(6) | Read sectors |
| 1 | 01 | 0x0A | WRITE(6) | Write sectors |
| 2 | 02 | 0x2F | VERIFY(6) | Verify data |
| 3 | 03 | 0x2F | VERIFY(6) | Verify with compare |
| 4 | 04 | 0x0B | SEEK(6) | Seek to address |
| 16 | 20 | 0x00 | TEST UNIT READY | Check device status |
| 19 | 23 | 0x15 | MODE SELECT(6) | Set device parameters |
| 21 | 25 | 0x1A | MODE SENSE(6) | Query device parameters |
| 28 | 34 | 0x16 | RESERVE DEVICE | Reserve for exclusive use |
| 29 | 35 | 0x17 | RELEASE DEVICE | Release reservation |
| 33 | 41 | 0x04 | FORMAT UNIT | Format disk |
| 34 | 42 | Special | READ CAPACITY(10) | Get disk size (auto-inquiry) |
| 36 | 44 | 0x08 | READ(6) | Read control area |
| 37 | 45 | 0x0A | WRITE(6) | Write control area |
| 48 | 60 | 0x08 | READ(6) | Read (double address) |
| 49 | 61 | 0x0A | WRITE(6) | Write (double address) |
| 50 | 62 | 0x2F | VERIFY(6) | Verify (double address) |
| 51 | 63 | 0x2F | VERIFY(6) | Verify compare (double addr) |
| 54 | 66 | 0x08 | READ(6) | Read with special handling |
| 57 | 71 | 0x2E | WRITE AND VERIFY | Write with verify |
| 59 | 73 | 0x00 | TEST UNIT READY | Device ready check |
| 60 | 74 | User | USER COMMAND | Execute user-specified CDB |
| 61 | 75 | 0x12 | INQUIRY | Device identification |
SCSF2 - Sequential Access Devices (Tapes/Streamers)¶
| Function | Octal | SCSI Opcode | Command Name | Notes |
|---|---|---|---|---|
| 0 | 00 | 0x08 | READ(6) | Read tape blocks |
| 1 | 01 | 0x0A | WRITE(6) | Write tape blocks |
| 2 | 02 | 0x13 | VERIFY(6) | Verify tape data |
| 3 | 03 | 0x13 | VERIFY(6) | Verify with compare |
| 7 | 07 | 0x19 | ERASE | Erase tape |
| 8 | 10 | 0x11 | SPACE BLOCKS | Space forward/backward |
| 9 | 11 | 0x11 | SPACE FILEMARKS | Space over filemarks |
| 10 | 12 | 0x10 | WRITE FILEMARKS | Write end-of-file marks |
| 11 | 13 | 0x01 | REWIND | Rewind to beginning |
| 12 | 14 | 0x19 | ERASE | Erase (gap) |
| 13 | 15 | 0x11 | SPACE BLOCKS | Space reverse |
| 14 | 16 | 0x11 | SPACE BLOCKS | Space forward |
| 15 | 17 | 0x1B | START/STOP UNIT | Unload tape |
| 16 | 20 | 0x00 | TEST UNIT READY | Device status |
| 17 | 21 | 0x01 | REWIND | Rewind |
| 18 | 22 | 0x01 | REWIND | Rewind |
| 19 | 23 | 0x15 | MODE SELECT(6) | Set tape parameters |
| 21 | 25 | 0x1A | MODE SENSE(6) | Query tape parameters |
| 22 | 26 | 0x08 | READ(6) | Read variable blocks |
| 23 | 27 | 0x0A | WRITE(6) | Write variable blocks |
| 24 | 30 | 0x1B | START/STOP UNIT | Load tape |
| 28 | 34 | 0x16 | RESERVE DEVICE | Reserve device |
| 29 | 35 | 0x17 | RELEASE DEVICE | Release device |
| 34 | 42 | 0x05 | READ BLOCK LIMITS | Query block size limits |
| 48 | 60 | 0x08 | READ(6) | Read (special mode) |
| 49 | 61 | 0x0A | WRITE(6) | Write (special mode) |
| 50 | 62 | 0x13 | VERIFY(6) | Verify (special mode) |
| 51 | 63 | 0x13 | VERIFY(6) | Verify compare |
| 54 | 66 | 0x08 | READ(6) | Read with handling |
| 56 | 70 | 0x1B | START/STOP UNIT | Retension tape |
| 59 | 73 | 0x00 | TEST UNIT READY | Device ready |
| 60 | 74 | User | USER COMMAND | Execute user-specified CDB |
| 61 | 75 | 0x12 | INQUIRY | Device identification |
| 62 | 76 | 0x11 | SPACE BLOCKS | Space to end of data |
Automatic Commands¶
These commands are issued automatically by the driver:
| SCSI Opcode | Command | When Issued | Source Line |
|---|---|---|---|
| 0x03 | REQUEST SENSE | After CHECK CONDITION status | 1359-1364 |
| 0x12 | INQUIRY | Device initialization | 1223-1227 |
| 0x25 | READ CAPACITY(10) | After INQUIRY for disks | 1234 |
| 0x05 | READ BLOCK LIMITS | After INQUIRY for tapes | 1237 |
| 0x1A | MODE SENSE(6) | Tape initialization | Line 544 |
| 0x15 | MODE SELECT(6) | After MODE SENSE for tapes | Line 558 |
Command Details and Response Requirements¶
1. TEST UNIT READY (0x00)¶
Function Codes: 16 (20 octal), 59 (73 octal)
Command Block:
Byte 0: 0x00 | (LUN << 5)
Byte 1-4: 0x00
Byte 5: Control byte
Expected Response: - GOOD status (0x00): Device is ready - CHECK CONDITION: Device not ready, REQUEST SENSE will provide details
SINTRAN Behavior: - No data phase - Used to check if device is operational - Retries with wait on BUSY status
2. REQUEST SENSE (0x03)¶
Automatically issued after CHECK CONDITION status
Command Block:
Byte 0: 0x03 | (LUN << 5)
Byte 1-2: 0x0000
Byte 3: Reserved
Byte 4: Allocation length (sense buffer size)
Byte 5: Control byte
Expected Response: Must return extended sense data (minimum 8 bytes):
Byte 0: Error code (0x70 = current error, 0x71 = deferred error)
Byte 1: Reserved
Byte 2: Sense Key (bits 0-3)
- 0x00: NO SENSE
- 0x01: RECOVERED ERROR
- 0x02: NOT READY
- 0x03: MEDIUM ERROR
- 0x04: HARDWARE ERROR
- 0x05: ILLEGAL REQUEST
- 0x06: UNIT ATTENTION
- 0x0B: ABORTED COMMAND
- 0x0C: COPY ABORTED (for COPY command)
Byte 3-6: Information bytes
Byte 7: Additional sense length
Byte 8+: Additional sense data
Critical Bits (Line 1200-1209):
Bit 15: Must be 1 for extended sense
Bits 5-7: ILI (Illegal Length), EOM (End of Media), EOF flags
Bits 0-3: Sense key
SINTRAN Special Handling: - Sense Key = 6 (UNIT ATTENTION): Forces re-initialization (INQUIRY) at line 1210-1212 - Sense Key = 1 or 3: Logged as corrected/medium error - Sense Key = 12: Interpreted as COPY ABORTED - Sense Key = 13: ABORTED COMMAND - triggers retry
Source: Lines 1186-1214
3. INQUIRY (0x12)¶
Function Code: 61 (75 octal) Also automatically issued during initialization
Command Block (Line 1224-1227):
Byte 0: 0x12 | (LUN << 5)
Byte 1: 0x00
Byte 2: 0x00 (Page code)
Byte 3: Reserved
Byte 4: Allocation length (usually 36+ bytes)
Byte 5: Control
Expected Response (Standard INQUIRY Data):
Byte 0: Peripheral Device Type
- 0x00: Direct Access (disk)
- 0x01: Sequential Access (tape)
- 0x02: Printer
- 0x03: Processor
- 0x04: Write-once
- 0x05: CD-ROM
- 0x7F: Logical unit not present
Byte 1: RMB (bit 7 = removable)
Byte 2: Version
Byte 3: Response Data Format (must be 2)
Byte 4: Additional length (n-4)
Byte 5-6: Reserved
Byte 7: Flags
Byte 8-15: Vendor ID (8 bytes ASCII)
Byte 16-31: Product ID (16 bytes ASCII)
Byte 32-35: Product Revision (4 bytes ASCII)
SINTRAN Processing (Lines 1230-1265):
-
Device Type Check (Line 1232-1242):
- Type 0, 3, 4 → Direct Access, issues READ CAPACITY(10) next
- Type 1 → Sequential Access, issues READ BLOCK LIMITS next
- Type 0x7F → Returns "NO SUCH LUN" error
-
For Disks - READ CAPACITY(10) follows (Line 1234):
READ CAPACITY Command:
Byte 0: 0x25
Byte 1-8: Reserved
Byte 9: Control
READ CAPACITY Response:
Bytes 0-3: Last Logical Block Address (big-endian)
Bytes 4-7: Block Length in bytes (big-endian)
Stored at: Line 1252-1254 → SURSZ (device record size)
- For Tapes - READ BLOCK LIMITS follows (Line 1237):
READ BLOCK LIMITS Command:
Byte 0: 0x05
Byte 1-4: Reserved
Byte 5: Control
READ BLOCK LIMITS Response:
Byte 0: Reserved
Bytes 1-3: Maximum block length
Bytes 4-5: Minimum block length
Processing (Lines 1257-1264): - Fixed block mode if min = max - Variable block mode if different - Block size stored in SURSZ
Required Flags Set: - Bit 5SCIN: Initialization complete - Bit 5SCDA: Direct access device (if applicable) - Bit 5SFBM: Fixed block mode (tapes) - Bit 5SVBS: Variable block size (tapes)
Source: Lines 1216-1314
4. READ(6) (0x08)¶
Function Codes: 0, 36, 48, 54, 60, 66
Command Block (Lines 1533-1539):
6-byte format:
Byte 0: 0x08 | (LUN << 5) | (MSB 3 bits of address)
Byte 1: Middle byte of address
Byte 2: LSB of address
Byte 3: Transfer length (0 = 256 blocks)
Byte 4: Control
10-byte format (for large addresses):
Byte 0: 0x28 (READ(10))
Byte 1: Flags
Bytes 2-5: Logical Block Address (big-endian)
Bytes 6-7: Reserved
Bytes 7-8: Transfer Length
Byte 9: Control
SINTRAN uses 10-byte format when: - Address > 0x1FFFFF (21 bits) - Line 1531
Data Phase: - IN (Device → Host) - Transfer size = Block size × Transfer length - Block size obtained from INQUIRY/READ CAPACITY
Expected Status: - GOOD (0x00): Data transferred successfully - CHECK CONDITION: Error occurred, REQUEST SENSE provides details
Error Handling: - Retries on UNIT ATTENTION (sense key 6) - Retries on ABORTED COMMAND (sense key 13) - Fails on MEDIUM ERROR (sense key 3)
Source: Lines 1476-1545, CACOB routine
5. WRITE(6) (0x0A)¶
Function Codes: 1, 37, 49, 55, 61
Command Block: Same format as READ(6)
Data Phase: - OUT (Host → Device) - Transfer size = Block size × Transfer length
Expected Status: Same as READ
Optical Disk Special Handling: - Function 71 (WRITE AND VERIFY) uses opcode 0x2E - See IP-P2-SCSI-OPDI.NPL for write recovery mechanism
Source: Same as READ
6. MODE SENSE(6) (0x1A)¶
Function Code: 21 (25 octal) Also automatic for tape initialization
Command Block (Line 544):
Byte 0: 0x1A | (LUN << 5)
Byte 1: DBD flag (Disable Block Descriptors)
Byte 2: Page Control (bits 6-7) | Page Code (bits 0-5)
Byte 3: Reserved
Byte 4: Allocation Length
Byte 5: Control
Expected Response:
Mode Parameter Header:
Byte 0: Mode Data Length
Byte 1: Medium Type
Byte 2: Device-Specific Parameter
- Bit 7: Write Protect (1 = protected)
Byte 3: Block Descriptor Length
Block Descriptor (if present):
Bytes 0-3: Number of blocks (or density code in byte 0)
Byte 4: Reserved
Bytes 5-7: Block length
SINTRAN Processing (Lines 992-1004): - Extracts write-protect flag from byte 2, bit 7 - Extracts density code from byte 4 of block descriptor - Stores in CFORM field
Used For: - Determining tape density - Checking write protection - Querying block size
Source: Lines 542-564, 989-1004
7. MODE SELECT(6) (0x15)¶
Function Code: 19 (23 octal) Also automatic after MODE SENSE for tapes
Command Block (Line 558):
Byte 0: 0x15 | (LUN << 5)
Byte 1: PF (Page Format, bit 4) | SP (Save Pages, bit 0)
Byte 2: Reserved
Byte 3: Reserved
Byte 4: Parameter List Length
Byte 5: Control
Data Phase OUT - Mode Parameter List:
Header:
Byte 0: Reserved
Byte 1: Reserved
Byte 2: Reserved
Byte 3: Block Descriptor Length
Block Descriptor (Lines 553-557):
Byte 0: Density Code
Bytes 1-3: Reserved
Byte 4: Reserved
Bytes 5-7: Block Length (0 for variable blocks)
SINTRAN Sets: - Density code from previous MODE SENSE or user parameter - Block size: 1024 (0x400) for fixed block mode, 0 for variable
Used For: - Setting tape density - Setting block size mode (fixed vs variable)
Source: Lines 546-577, MODE SELECT logic
8. VERIFY(6) (0x2F)¶
Function Codes: 2, 3, 50, 51, 62, 63
Command Block:
Byte 0: 0x2F | (LUN << 5) | (Address MSB)
Byte 1: Address middle
Byte 2: Address LSB
Byte 3: Verification Length
Byte 4: Control
- Bit 1: BYTCHK (Byte Check) - compare with host data
Two Modes:
- BYTCHK = 0: Verify media only (no data transfer)
- BYTCHK = 1: Compare with host data (Data OUT phase)
Expected Status: - GOOD: Verification passed - CHECK CONDITION: Verification failed or media error
SINTRAN Note: Line 198: "COMPARE NOT IMPLEMENTED" - SINTRAN may not fully support BYTCHK=1 mode
Source: SCSF1/SCSF2 arrays, lines 1452-1469
9. WRITE AND VERIFY (0x2E)¶
Function Code: 57 (71 octal)
Command Block:
Byte 0: 0x2E | (LUN << 5)
Byte 1: Flags
Bytes 2-5: Logical Block Address
Bytes 6-7: Reserved
Bytes 7-8: Transfer Length
Byte 9: Control
Behavior: - Writes data to medium - Immediately verifies written data - Single operation from host perspective
Used By: - Optical disk driver for critical writes - See CCRWO (Compare-Compare-Rewrite-Optical) in IP-P2-SCSI-OPDI.NPL
Source: SCSF1 array index 69
10. SEEK(6) (0x0B)¶
Function Code: 4
Command Block:
Byte 0: 0x0B | (LUN << 5) | (Address MSB)
Byte 1: Address middle
Byte 2: Address LSB
Byte 3: Reserved
Byte 4: Control
Purpose: - Pre-position disk head to reduce latency on next READ/WRITE - Used by elevator algorithm (DSORT) for optimization
Expected Status: - GOOD: Seek complete - CHECK CONDITION: Seek error
Source: SCSF1 array index 4
11. FORMAT UNIT (0x04)¶
Function Code: 33 (41 octal)
Command Block:
Byte 0: 0x04 | (LUN << 5)
Byte 1: Format Options
Byte 2: Vendor Specific
Byte 3: Interleave (MSB)
Byte 4: Interleave (LSB)
Byte 5: Control
Optional Data Phase: - OUT phase if defect list provided - No data phase for simple format
Expected Status: - GOOD: Format complete - CHECK CONDITION: Format failed
SINTRAN Note: - Used for disk formatting - May take significant time (several minutes to hours)
Source: SCSF1 array index 34
12. RESERVE/RELEASE DEVICE (0x16/0x17)¶
Function Codes: 28 (34 octal), 29 (35 octal)
RESERVE Command:
Byte 0: 0x16 | (LUN << 5)
Byte 1-4: Reserved
Byte 5: Control
RELEASE Command:
Byte 0: 0x17 | (LUN << 5)
Byte 1-4: Reserved
Byte 5: Control
Purpose: - RESERVE: Lock device for exclusive use by this initiator - RELEASE: Unlock device
Expected Status: - GOOD: Reservation accepted/released - RESERVATION CONFLICT (0x18): Device already reserved by another initiator
SINTRAN Handling (Lines 649-651, 1144-1146): - Tracks reservation state in OPSTA bit 4SRES - Returns error code 3210 (RESERVATION CONFLICT) to application
Source: SCSF1/SCSF2 arrays index 28-29
13. Tape-Specific Commands¶
REWIND (0x01)¶
Function Codes: 11 (13 octal), 17, 21
Command Block:
Byte 0: 0x01 | (LUN << 5)
Byte 1: Immediate bit (bit 0)
Byte 2-4: Reserved
Byte 5: Control
Immediate Mode: - Bit 0 = 1: Command returns immediately, rewind continues in background - Bit 0 = 0: Command waits for rewind to complete
WRITE FILEMARKS (0x10)¶
Function Code: 10 (12 octal)
Command Block:
Byte 0: 0x10 | (LUN << 5)
Byte 1: Reserved
Bytes 2-4: Number of filemarks (3 bytes, big-endian)
Byte 5: Control
SPACE (0x11)¶
Function Codes: 8-10, 13-14, 62
Command Block:
Byte 0: 0x11 | (LUN << 5)
Byte 1: Code (bits 0-1)
- 0x00: Space blocks
- 0x01: Space filemarks
- 0x03: Space to end of data
Bytes 2-4: Count (signed 3-byte value, can be negative for reverse)
Byte 5: Control
ERASE (0x19)¶
Function Code: 7
Command Block:
Byte 0: 0x19 | (LUN << 5)
Byte 1: Long bit (bit 0)
Byte 2-4: Reserved
Byte 5: Control
START/STOP UNIT (0x1B)¶
Function Codes: 15 (17 octal - unload), 24 (30 octal - load), 56 (70 octal - retension)
Command Block:
Byte 0: 0x1B | (LUN << 5)
Byte 1: Immediate bit (bit 0)
Byte 2-3: Reserved
Byte 4: Power/LoEj/Start
- Bit 0: Start (1 = start, 0 = stop)
- Bit 1: LoEj (Load/Eject)
Byte 5: Control
Operations: - Load: LoEj=1, Start=1 - Unload: LoEj=1, Start=0 - Retension: Special vendor-specific mode
Source: SCSF2 array, tape functions
Custom SCSI Command Support¶
Function 74: Execute User-Specified SCSI Command Block¶
✅ YES - Applications CAN send custom SCSI commands including INQUIRY
Function Code: 60 (74 octal)
API Entry Point (Line 1100-1127):
SCSID: A=:X.HSTAT:=L=:X."FINISH":=B=:X.SCUDF
T=:X.SCTRG:=:X; 77/\X.ABFUN; X:=T
...
IF A=74 THEN
CALL GUSCB % USER SPECIFIED COMMAND
...
GUSCB Routine (Lines 1385-1392):
GUSCB: ABPA3=:SUIBC; A:=L=:SAVA:=6=:L % NUMBER OF WORDS (6 = 12 bytes)
ABPA2; X:=SMBP1; T:=SMBP2; *MOVPP % MOVE COMMAND BLOCK FROM USER MEMORY
IF ABFUN SHZ -14=0 THEN 377/\SUICO FI
T:=SAVA=:P
How It Works¶
- User builds SCSI Command Descriptor Block (CDB) in memory
-
Calls SCSID with:
- ABFUN = 74 (octal) with LUN in bits 6-8
- MEMAD = Data buffer address (for data-in/data-out phases)
- ABPA2 = Pointer to CDB (Command Descriptor Block)
- ABPA3 = Byte count for data transfer
- A register = Driver control flags
-
Driver copies 12-byte CDB from user memory (line 1389)
- Driver executes SCSI command through normal protocol (EXCOM routine)
- Results returned in user's data buffer
Parameters¶
ABSTR Parameter Block:
struct ABSTR {
uint16_t ABFUN; // Function code = 74 (octal)
// Bits 0-5: Function (74)
// Bits 6-8: LUN (0-7)
uint16_t MEMAD_HI; // Data buffer address (high word)
uint16_t MEMAD_LO; // Data buffer address (low word)
uint16_t ABPA2_HI; // CDB address (high word)
uint16_t ABPA2_LO; // CDB address (low word)
// Points to 12-byte command block
uint16_t ABPA3_HI; // Byte count (high word)
uint16_t ABPA3_LO; // Byte count (low word)
// Data transfer length in bytes
};
A Register Control Flags:
Bit 0-3: Log₂ of timeout (seconds = 2^n)
Bit 4: Use SELECT without ATN
Bit 5: Don't use disconnect/reconnect
Bit 6: Return on command accepted (before data transfer complete)
Example: Sending INQUIRY Command¶
Step 1: Build INQUIRY CDB in memory:
uint8_t inquiry_cdb[12] = {
0x12, // INQUIRY opcode
0x00, // LUN=0, no EVPD
0x00, // Page code
0x00, // Reserved
0x24, // Allocation length = 36 bytes
0x00, // Control
0x00, 0x00, // Reserved
0x00, 0x00, // Reserved
0x00, 0x00 // Reserved
};
Step 2: Allocate data buffer:
uint8_t inquiry_data[36]; // Buffer for INQUIRY response
Step 3: Set up ABSTR parameters:
struct ABSTR params;
params.ABFUN = 074; // Function 74 (octal), LUN 0
params.MEMAD = (uint32_t)inquiry_data; // Response buffer address
params.ABPA2 = (uint32_t)inquiry_cdb; // CDB address
params.ABPA3 = 36; // Expect 36 bytes response
Step 4: Call SCSID:
; ND-100 Assembly example
T = ¶ms
X = device_datafield
B = lun_datafield
A = 4 ; Timeout = 2^4 = 16 seconds
JPL I (SCSID)
JMP ERROR_EXIT
JMP BUSY_EXIT
JMP SUCCESS_EXIT
SUCCESS_EXIT:
; inquiry_data now contains device information
; Parse bytes 0-35 for device type, vendor, product, etc.
Step 5: Parse results:
// After successful return:
uint8_t device_type = inquiry_data[0] & 0x1F;
bool removable = (inquiry_data[1] & 0x80) != 0;
char vendor[9];
memcpy(vendor, &inquiry_data[8], 8);
vendor[8] = '\0';
char product[17];
memcpy(product, &inquiry_data[16], 16);
product[16] = '\0';
char revision[5];
memcpy(revision, &inquiry_data[32], 4);
revision[4] = '\0';
INQUIRY Command Support¶
Built-in INQUIRY Support¶
Function Code: 61 (75 octal)
Applications can also use the built-in INQUIRY support instead of Function 74:
Automatic Processing: - Sends INQUIRY command - For disks: Automatically follows with READ CAPACITY(10) - For tapes: Automatically follows with READ BLOCK LIMITS - Parses device type - Stores block size in device data structure - Sets initialization flags
Usage:
struct ABSTR params;
params.ABFUN = 075; // Function 75 (octal) = INQUIRY
params.MEMAD = buffer_addr; // Buffer for extended information
params.ABPA2 = 0; // Not used
params.ABPA3 = 100; // Buffer size for format info
// Call SCSID
// After return, device is fully initialized and ready
What's Returned:
For Function 42 (Inquiry + Read Capacity), returned in MEMAD buffer:
struct FormatInfo {
uint32_t disk_size; // Total blocks on disk
uint32_t block_size; // Bytes per block
// ... other fields depend on device type
};
Advantages of Function 75 vs Function 74:
| Aspect | Function 75 (Built-in) | Function 74 (Custom) |
|---|---|---|
| Setup | Simple - just call with buffer | Must build CDB manually |
| Parsing | Automatic | Must parse response manually |
| Follow-up | Auto READ CAPACITY/BLOCK LIMITS | Must send separately if needed |
| Initialization | Sets device flags automatically | Must track device state manually |
| Use Case | Device initialization | Advanced diagnostics, custom commands |
Implementation Requirements¶
For C# SCSI Emulator¶
To properly support SINTRAN's SCSI expectations, the C# emulator must:
1. Implement All Commands¶
Support all commands in SCSF1/SCSF2 tables, particularly:
- ✅ Must Have:
- TEST UNIT READY
- REQUEST SENSE (with proper extended sense format)
- INQUIRY (with proper device type response)
- READ CAPACITY(10) or READ BLOCK LIMITS
- READ(6) and WRITE(6)
- MODE SENSE(6) and MODE SELECT(6)
- ⚠️ Should Have:
- SEEK(6) for performance
- VERIFY(6) for data integrity
- RESERVE/RELEASE for multi-host
- START/STOP UNIT for removable media
- 🔧 Optional:
- FORMAT UNIT
- WRITE AND VERIFY
- Tape commands (if emulating tape)
2. Status Handling¶
Return proper SCSI status:
public enum ScsiStatus : byte
{
Good = 0x00,
CheckCondition = 0x02,
ConditionMet = 0x04,
Busy = 0x08,
Intermediate = 0x10,
IntermediateConditionMet = 0x14,
ReservationConflict = 0x18,
CommandTerminated = 0x22,
QueueFull = 0x28
}
For CHECK CONDITION, prepare valid extended sense data.
3. REQUEST SENSE Response¶
Must return valid extended sense data:
public class ExtendedSenseData
{
public byte ErrorCode = 0x70; // Current error
public byte SenseKey; // 0x00-0x0F
public byte[] Information = new byte[4];
public byte AdditionalSenseLength = 10;
public byte[] CommandSpecificInfo = new byte[4];
public byte AdditionalSenseCode; // ASC
public byte AdditionalSenseCodeQualifier; // ASCQ
public byte FieldReplaceableUnitCode;
public byte[] SenseKeySpecific = new byte[3];
}
Critical Sense Keys for SINTRAN:
- 0x00 (NO SENSE): Operation succeeded
- 0x01 (RECOVERED ERROR): Error but data is valid
- 0x02 (NOT READY): Device not ready
- 0x03 (MEDIUM ERROR): Unrecoverable read/write error
- 0x05 (ILLEGAL REQUEST): Invalid command or parameter
- 0x06 (UNIT ATTENTION): Device reset or media changed - triggers re-initialization
- 0x0B (ABORTED COMMAND): Command aborted - triggers retry
- 0x0C (COPY ABORTED): COPY command failed
4. INQUIRY Response¶
Must return proper INQUIRY data:
public class InquiryData
{
public byte PeripheralDeviceType; // 0=disk, 1=tape, 5=CD-ROM
public bool Removable;
public byte Version = 0x02; // SCSI-2 compliance
public byte ResponseDataFormat = 0x02;
public byte AdditionalLength = 31; // n-4 where n=36
public byte[] Vendor = new byte[8]; // ASCII, space-padded
public byte[] Product = new byte[16]; // ASCII, space-padded
public byte[] Revision = new byte[4]; // ASCII
// Followed by READ CAPACITY or READ BLOCK LIMITS
}
5. Function 74 Support¶
Must support user-specified CDB execution:
public void ExecuteUserCommand(byte[] cdb, byte[] dataBuffer,
int dataLength, bool dataIn)
{
// 1. Validate CDB (6, 10, or 12 bytes)
// 2. Parse opcode from cdb[0]
// 3. Execute command
// 4. Transfer data if dataLength > 0
// 5. Return status
}
Security Considerations: - Consider limiting dangerous commands (FORMAT UNIT, WRITE BUFFER, etc.) - Or require special permissions for raw SCSI access - Log all Function 74 commands for audit
6. Interrupt Handling¶
As documented in SCSI-C#-Implementation-Guide.md:
- Generate interrupts on phase changes
- Set RSTAU bit 11 (NCR interrupt)
- Trigger Level 11 CPU interrupt
- Wait for WCONT=5 (resume) before continuing
Reference: See previous analysis in SCSI-C#-Implementation-Guide.md
7. Response Timing¶
SINTRAN expects responses within timeout period: - Default: 2^4 = 16 seconds - Can be specified in A register bits 0-3 - Return BUSY status if operation will take longer - After BUSY, SINTRAN will retry with delays
8. Block Size Handling¶
Critical for proper operation:
// After INQUIRY, device must report:
// - For disks: Use READ CAPACITY(10) to return:
// * Last block address (total blocks - 1)
// * Block size in bytes (typically 512 or 1024)
//
// - For tapes: Use READ BLOCK LIMITS to return:
// * Maximum block length
// * Minimum block length
// * If max == min: Fixed block mode
// * If different: Variable block mode
public class DeviceGeometry
{
public uint TotalBlocks;
public uint BlockSize;
public bool FixedBlockMode;
}
SINTRAN uses block size for: - Calculating DMA transfer lengths - Converting between logical records and physical blocks - Validating transfer requests
Testing Checklist¶
Basic Commands¶
- [ ] TEST UNIT READY returns GOOD status
- [ ] INQUIRY returns valid device type
- [ ] READ CAPACITY returns correct disk size
- [ ] REQUEST SENSE returns extended sense data
- [ ] READ(6) transfers data correctly
- [ ] WRITE(6) accepts data correctly
Status Handling¶
- [ ] GOOD status allows operation to complete
- [ ] CHECK CONDITION triggers REQUEST SENSE
- [ ] BUSY status causes retry with delay
- [ ] RESERVATION CONFLICT returns proper error
Sense Keys¶
- [ ] NO SENSE (0x00) = success
- [ ] RECOVERED ERROR (0x01) = warning logged
- [ ] NOT READY (0x02) = device not ready
- [ ] MEDIUM ERROR (0x03) = data error
- [ ] ILLEGAL REQUEST (0x05) = bad parameter
- [ ] UNIT ATTENTION (0x06) = triggers re-INQUIRY
- [ ] ABORTED COMMAND (0x0B) = triggers retry
Function 74 (Custom Commands)¶
- [ ] Can send INQUIRY via Function 74
- [ ] Can send TEST UNIT READY via Function 74
- [ ] Can read INQUIRY response data
- [ ] Invalid CDB returns ILLEGAL REQUEST
- [ ] Works for both data-in and data-out commands
Interrupt Mode¶
- [ ] Interrupts generated on phase changes
- [ ] RSTAU bit 11 set on NCR interrupt
- [ ] Level 11 interrupt triggered
- [ ] Operation pauses on WCONT=0
- [ ] Operation resumes on WCONT=5
Advanced¶
- [ ] MODE SENSE returns device parameters
- [ ] MODE SELECT changes device parameters
- [ ] VERIFY command works
- [ ] SEEK improves performance (optional)
- [ ] RESERVE/RELEASE work for multi-host (optional)
Conclusion¶
SINTRAN III has comprehensive SCSI support including:
- ✅ All essential SCSI-2 commands for disks and tapes
- ✅ Automatic command sequences (INQUIRY→READ CAPACITY)
- ✅ Full error handling with proper sense key interpretation
- ✅ User-accessible custom commands via Function 74
- ✅ INQUIRY command support both built-in (Function 75) and custom (Function 74)
Applications CAN: - Send INQUIRY commands using Function 74 (custom CDB) - Send INQUIRY commands using Function 75 (automatic parsing) - Send ANY valid SCSI command via Function 74 - Read complete response data - Parse device information
For C# Emulator: - Implement all commands in SCSF1/SCSF2 arrays - Return proper extended sense data on CHECK CONDITION - Support Function 74 for custom CDB execution - Handle UNIT ATTENTION (sense key 6) correctly - triggers re-initialization - Generate interrupts on all SCSI phase changes (see previous guide)
Document Path: Source Code\Sintran L\NPL\SCSI-Commands-Analysis.md