Skip to content

SCSI Driver

opencode-agent[bot] edited this page May 10, 2026 · 1 revision

SCSI Driver

JNode's SCSI driver subsystem for disk and CD-ROM devices with command descriptor blocks and sense data handling.

Overview

The SCSI driver subsystem in JNode provides block device drivers for SCSI-based storage. The architecture is layered: a SCSI bus layer (org.jnode.driver.bus.scsi) containing core device classes and protocol utilities, a command layer with command descriptor block (CDB) implementations organized by command set (SPC for primary commands, MMC for multimedia), and a block driver layer (org.jnode.driver.block.scsi) that maps SCSI devices to block device APIs for use by the filesystem layer.

The subsystem bridges hardware SCSI devices (accessed via host controller bus drivers) to the block device layer, making disks and CD-ROMs accessible to filesystems through FSBlockDeviceAPI. The SCSI bus is abstract — concrete implementations like USB mass storage wrap SCSI-over-USB protocols.

Key Components

Class/File Purpose
SCSIDevice.java Abstract base for all SCSI devices, extends Device, declares executeCommand and getDescriptor
SCSIDeviceAPI.java Device API interface exposing executeCommand(CDB, ...) and getDescriptor() to upper layers
CDB.java Abstract base class for all command descriptor blocks; extends SCSIBuffer, stores opcode
SCSIBuffer.java Big-endian byte buffer for all SCSI data structures; provides getUInt8/16/32, getASCII, setInt8/16/32
SCSIConstants.java Timeout constants: GROUP_NOTIMEOUT (500ms), GROUP1_TIMEOUT (10s), GROUP2_TIMEOUT (5s)
SCSIException.java Exception thrown by executeCommand on SCSI errors
InquiryData.java Wrapper for INQUIRY response; exposes getPeripheralDeviceType, getVendorIdentification, getProductIdentification
SenseData.java Wrapper for sense data; exposes getSenseKey(), getASC(), getASCQ()
SenseKey.java Enum for SCSI sense keys (NO_SENSE, RECOVERED_ERROR, NOT_READY, etc.)
SCSICDROMDriver.java Block driver for CD/DVD; implements FSBlockDeviceAPI and RemovableDeviceAPI; 2048-byte alignment
CDROMDeviceToDriverMapper.java Maps SCSI devices with peripheral device type 0x05 to SCSICDROMDriver; match level MATCH_DEVCLASS

SPC (SCSI Primary Commands) CDBs

Class Opcode Purpose
CDBInquiry 0x12 Retrieve device identification and capabilities
CDBRequestSense 0x03 Request sense data after check condition
CDBReportLuns 0xA0 Report configured logical units
CDBTestUnitReady 0x00 Check if device is ready

MMC (Multimedia Commands) CDBs

Class Opcode Purpose
CDBRead10 0x28 Read data from optical media
CDBReadCapacity 0x25 Retrieve medium capacity
CDBReadTOC 0x43 Read table of contents
CDBMediaRemoval 0x1E Lock/unlock removable media
CDBStartStopUnit 0x1B Start/stop/load/eject medium
CDBGetConfiguration 0x46 Get current device configuration
MMCUtils.java Static utility methods for MMC operations (readCapacity, readData, setMediaRemoval, startStopUnit)
CapacityData.java Wrapper for READ CAPACITY response; exposes getLogicalBlockAddress(), getBlockLength()

How It Works

Device hierarchy

SCSIDevice extends Device and sits below the driver framework. It is subclassed by hardware-specific bus drivers (e.g., USB mass storage wraps SCSI commands over USB). The device exposes SCSIDeviceAPI to the driver layer:

public abstract class SCSIDevice extends Device {
    public abstract InquiryData getDescriptor();
    public abstract int executeCommand(CDB cdb, byte[] data, int dataOffset, long timeout)
        throws SCSIException, TimeoutException, InterruptedException;
    public final SenseData requestSense() { ... }
}

The SCSIDeviceAPIImpl inner class wraps a SCSIDevice and implements SCSIDeviceAPI, registering it on the device during startDevice() in drivers like SCSICDROMDriver.

Command execution flow

  1. A driver (e.g., SCSICDROMDriver.read()) creates a CDB subclass (e.g., CDBRead10) with parameters encoded into the byte buffer.
  2. The driver calls SCSIDevice.executeCommand(cdb, data, offset, timeout).
  3. The host controller implementation (e.g., USB) translates the CDB to the transport protocol, sends it, and receives data/status.
  4. On check condition, the driver calls requestSense() to retrieve SenseData and determine the error.
  5. SCSIException wraps the error for the block layer.

CDB structure

CDB extends SCSIBuffer and assigns the opcode at byte 0:

public abstract class CDB extends SCSIBuffer {
    public CDB(int cdbLength, int opcode) {
        super(cdbLength);
        setInt8(0, opcode);
    }
    public abstract int getDataTransfertCount();
}

CDBs are grouped: Group 0 (6-byte CDB) for basic commands, Group 1 (10-byte CDB) for block devices. MMCUtils uses Group 1 timeouts for all CDB operations.

CD-ROM driver

SCSICDROMDriver extends Driver and implements FSBlockDeviceAPI and RemovableDeviceAPI. On startDevice() it registers three APIs on the underlying SCSIDevice: SCSIDeviceAPI, RemovableDeviceAPI, and FSBlockDeviceAPI backed by FSBlockAlignmentSupport with 2048-byte alignment (standard CD-ROM sector size).

Read operations (read(long devOffset, ByteBuffer destBuf)) compute the LBA from devOffset / blockLength, construct a CDBRead10, call MMCUtils.readData(), and refresh the ByteBuffer. Write throws IOException("Readonly device").

The driver handles media changes via a changed flag. On getLength(), getSectorSize(), or read(), processChanged() re-reads the capacity if the flag is set.

Device-to-driver mapping

CDROMDeviceToDriverMapper implements DeviceToDriverMapper with match level MATCH_DEVCLASS. It checks device instanceof SCSIDevice and getDescriptor().getPeripheralDeviceType() == 0x05 (CD/DVD device per SPC). Returns a new SCSICDROMDriver instance on match.

SCSI buffer utilities

SCSIBuffer extends BigEndian to handle multi-byte values as MSB-first (big-endian), matching SCSI protocol requirements. Subclasses (InquiryData, CapacityData, SenseData) use typed getter/setter methods rather than raw offsets.

InquiryData masks peripheral device type with & 0x1F per SPC section 4.4.4. Vendor/product/revision fields are read as 8/16/4-byte ASCII strings with trailing space trimming.

SenseData extracts response code, sense key (masked to 4 bits), ASC, and ASCQ from the fixed-format sense buffer per SPC section 4.5.

Gotchas

  • No write support on CD-ROM: SCSICDROMDriver.write() throws "Readonly device". This is correct for read-only optical media but must not be assumed for all SCSI devices.
  • Media change detection: The driver uses a changed boolean flag to trigger capacity re-reads. Applications relying on media change notifications should check RemovableDeviceAPI state or implement polling.
  • SCSIDiskDriver not present: The issue mentions SCSIDiskDriver.java but it does not exist in the current codebase. SCSI disk support may be unimplemented or handled via other mechanisms (e.g., SCSI-over-USB in USBStorageSCSIDriver).
  • Host controller abstraction: SCSIDevice.executeCommand() is abstract — actual command transport depends on the host controller implementation (USB mass storage, hardware SCSI adapter). Drivers must handle transport-specific errors.
  • Request sense on every error: The requestSense() helper simplifies error diagnosis but adds an extra command on error paths. Some transports may not support it.
  • Peripheral device type checks: Device type 0x05 is CD/DVD per SPC. Other values (0x00=disk, 0x01=tape, 0x07=optical) require different block drivers.

Related Pages

Clone this wiki locally