11 KiB
scsi.device — Hard Disk, CD-ROM, and Mass Storage I/O
Overview
SCSI and IDE hard disks on the Amiga are accessed through scsi.device or compatible device drivers. The API is consistent across implementations — the same IORequest structure and commands work regardless of whether the underlying hardware is Commodore's native Gayle IDE, a Zorro SCSI card, or an accelerator-integrated controller.
Disk Interfaces by Amiga Model
| Model | Interface | Controller | Device Name | Bandwidth Limit |
|---|---|---|---|---|
| A500 | None (stock) | — | — | Requires external SCSI card |
| A500+ | None (stock) | — | — | Requires external SCSI card |
| A600 | IDE (44-pin) | Gayle | scsi.device |
~1.5 MB/s (PIO, 16-bit CIA) |
| A1000 | None (stock) | — | — | Requires SCSI sidecar |
| A1200 | IDE (44-pin) | Gayle | scsi.device |
~1.5 MB/s (PIO) |
| A2000 | None (stock) | — | — | Zorro II SCSI cards |
| A3000 | SCSI (50-pin) | WD33C93 | scsi.device |
~3 MB/s (DMA) |
| A4000 | IDE (40-pin) | A4000 IDE | scsi.device |
~2 MB/s (PIO) |
| A4000T | SCSI (50-pin) + IDE | NCR 53C710 + IDE | 2nd.scsi.device / scsi.device |
~10 MB/s (SCSI DMA) |
| CD32 | IDE (internal CD) | Akiko | scsi.device |
~1.5 MB/s |
| CDTV | SCSI (internal CD) | DMAC + WD33C93 | scsi.device |
~150 KB/s (1× CD) |
Why Native Bandwidth Is Limited
The A600/A1200 Gayle IDE interface is the most common and the most constrained:
flowchart LR
CPU["68020/68030<br/>(fast bus)"] -->|"PIO transfer<br/>WORD at a time"| GAYLE["Gayle IDE<br/>(no DMA!)"]
GAYLE -->|"16-bit ATA"| DRIVE["IDE Drive"]
style GAYLE fill:#ffcdd2,stroke:#c62828,color:#333
| Bottleneck | Explanation |
|---|---|
| No DMA | Gayle has no DMA engine — every word must be moved by the CPU (MOVE.W loop) |
| 16-bit bus | Gayle connects via 16-bit data path even on 32-bit CPUs |
| PIO mode 0 | Stock Gayle supports only PIO mode 0 (~3.3 MB/s theoretical, ~1.5 MB/s actual) |
| CIA timing | CIA chip access introduces wait states |
| CPU overhead | 100% CPU utilization during transfers — no multitasking during disk I/O |
Community Solutions — Fast IDE
| Solution | Method | Improvement |
|---|---|---|
| FastATA (E-Matrix/Elbox) | Zorro SCSI/IDE card with DMA | Up to ~10 MB/s, frees CPU |
| Buddha/Catweasel | Clock port / Zorro IDE with optimized driver | ~2–3 MB/s, multiple IDE channels |
| Blizzard SCSI | Accelerator-integrated SCSI | Up to ~5 MB/s with DMA |
| GVP Series II | Zorro II SCSI with custom DMA ASIC | ~3 MB/s, DMA frees CPU |
| A4091 | Zorro III SCSI (NCR 53C710) | ~10 MB/s — fastest stock Amiga SCSI |
| CF adapters | CompactFlash in IDE socket | Same speed, but no mechanical seek latency |
| SD/microSD | Adapter on clock port | Varies, typically slow but no noise |
Native vs. Vendor Drivers — Software Differences
All drivers expose the same CMD_READ/CMD_WRITE/HD_SCSICMD API, but internal differences matter:
| Aspect | Commodore scsi.device |
Vendor Drivers (GVP, A4091, etc.) |
|---|---|---|
| Source | Commodore ROM or Devs: | Third-party (ships with hardware) |
| DMA support | None (Gayle PIO) | Often DMA-capable |
| Interrupt handling | Level 2 interrupt (CIA) | Card-specific interrupt level |
| TD64 / NSD | Added via patches | Often built-in from factory |
| Multi-LUN | Usually ignored | Proper LUN scanning on SCSI |
| Disconnect/reselect | Not supported (Gayle) | SCSI disconnect on good controllers |
| Tagged queuing | No | Some advanced SCSI controllers |
| CD-ROM support | Basic (atapi.device) | Full ATAPI/SCSI CD support |
| Removable media | Basic change detection | Proper unit attention handling |
Important
When writing software that accesses disks, always use the device name from the mountlist — don't hardcode
scsi.device. Different systems use different device names for the same physical drive.
Opening
struct MsgPort *diskPort = CreateMsgPort();
struct IOStdReq *diskReq = (struct IOStdReq *)
CreateIORequest(diskPort, sizeof(struct IOStdReq));
/* Unit 0 = first device on the bus (master/ID 0): */
if (OpenDevice("scsi.device", 0, (struct IORequest *)diskReq, 0))
{
Printf("Cannot open scsi.device unit 0\n");
}
Units
| Unit | SCSI Meaning | IDE Meaning |
|---|---|---|
| 0 | SCSI ID 0 | Master |
| 1 | SCSI ID 1 | Slave |
| 2–6 | SCSI ID 2–6 | N/A |
| 7 | Host adapter (reserved) | N/A |
Standard Commands
/* Read 512 bytes from byte offset on disk: */
diskReq->io_Command = CMD_READ;
diskReq->io_Data = buffer;
diskReq->io_Length = 512;
diskReq->io_Offset = 0; /* byte offset */
DoIO((struct IORequest *)diskReq);
/* Write: */
diskReq->io_Command = CMD_WRITE;
diskReq->io_Data = buffer;
diskReq->io_Length = 512;
diskReq->io_Offset = 512;
DoIO((struct IORequest *)diskReq);
/* Flush write cache: */
diskReq->io_Command = CMD_UPDATE;
DoIO((struct IORequest *)diskReq);
Important
The
io_Offsetfield is aULONG(32-bit), limiting addressable space to 4 GB. For larger drives, use TD64/NSD 64-bit commands.
Direct SCSI Commands (HD_SCSICMD)
For operations beyond read/write — device identification, mode pages, CD-ROM commands:
#include <devices/scsidisk.h>
struct SCSICmd scsicmd;
UBYTE cdb[10], sense[20], data[512];
/* READ(10) — read 1 sector at LBA 0: */
memset(cdb, 0, sizeof(cdb));
cdb[0] = 0x28; /* READ(10) opcode */
cdb[7] = 0; cdb[8] = 1; /* transfer length = 1 sector */
scsicmd.scsi_Data = (UWORD *)data;
scsicmd.scsi_Length = 512;
scsicmd.scsi_Command = cdb;
scsicmd.scsi_CmdLength = 10;
scsicmd.scsi_Flags = SCSIF_READ | SCSIF_AUTOSENSE;
scsicmd.scsi_SenseData = sense;
scsicmd.scsi_SenseLength = sizeof(sense);
diskReq->io_Command = HD_SCSICMD;
diskReq->io_Data = &scsicmd;
diskReq->io_Length = sizeof(scsicmd);
DoIO((struct IORequest *)diskReq);
if (scsicmd.scsi_Status != 0)
Printf("SCSI error: status=%ld, sense key=%ld\n",
scsicmd.scsi_Status, sense[2] & 0x0F);
Common SCSI Commands
| Opcode | Name | CDB | Description |
|---|---|---|---|
0x00 |
TEST UNIT READY | 6 | Check device readiness |
0x03 |
REQUEST SENSE | 6 | Get error details |
0x12 |
INQUIRY | 6 | Device identification |
0x1A |
MODE SENSE(6) | 6 | Read device parameters |
0x25 |
READ CAPACITY | 10 | Get total sectors and sector size |
0x28 |
READ(10) | 10 | Read sectors (32-bit LBA) |
0x2A |
WRITE(10) | 10 | Write sectors |
0x35 |
SYNCHRONIZE CACHE | 10 | Flush write cache |
0x43 |
READ TOC | 10 | Read CD table of contents |
0xBE |
READ CD | 12 | Read CD sector (any format) |
CD-ROM Specifics
CD-ROM drives require special handling — they use ATAPI (IDE) or SCSI commands but with CD-specific extensions:
Opening a CD-ROM
/* CD-ROM is typically on a different device or unit: */
/* A1200 + ATAPI CD: */
OpenDevice("scsi.device", 2, req, 0); /* unit 2 = slave on second channel */
/* External SCSI CD: */
OpenDevice("2nd.scsi.device", 3, req, 0); /* SCSI ID 3 */
/* AmiCDFS or CacheCDFS handles mounting automatically via:
DEVS:DOSDrivers/CD0 mountlist entry */
Reading the Table of Contents
UBYTE tocData[804]; /* max TOC size */
memset(cdb, 0, 10);
cdb[0] = 0x43; /* READ TOC */
cdb[6] = 1; /* starting track */
cdb[7] = (sizeof(tocData) >> 8) & 0xFF;
cdb[8] = sizeof(tocData) & 0xFF;
scsicmd.scsi_Data = (UWORD *)tocData;
scsicmd.scsi_Length = sizeof(tocData);
scsicmd.scsi_Command = cdb;
scsicmd.scsi_CmdLength = 10;
scsicmd.scsi_Flags = SCSIF_READ | SCSIF_AUTOSENSE;
DoIO((struct IORequest *)diskReq);
Audio CD Playback
/* PLAY AUDIO MSF — play from start to end: */
memset(cdb, 0, 10);
cdb[0] = 0x47; /* PLAY AUDIO MSF */
cdb[3] = 0; /* start minute */
cdb[4] = 2; /* start second */
cdb[5] = 0; /* start frame */
cdb[6] = 60; /* end minute */
cdb[7] = 0; /* end second */
cdb[8] = 0; /* end frame */
scsicmd.scsi_Flags = SCSIF_READ;
DoIO((struct IORequest *)diskReq);
CD Filesystem Drivers
| Driver | Type | Features |
|---|---|---|
| AmiCDFS | Free (Aminet) | ISO 9660, Rock Ridge, HFS, circular cache |
| CacheCDFS | OS 3.5+ / IDE-fix | ISO 9660, Rock Ridge, Joliet, HFS, LRU cache — de facto standard |
| AsimCDFS | Commercial | ISO 9660, High Sierra, Rock Ridge, HFS, CD-DA ripping, CDTV/CD32 emulation |
| AllegroCDFS | Elbox-bundled | ISO 9660 L1–3, Rock Ridge, Joliet, UDF, fastest benchmarks |
| ODFileSystem | Open source | ISO 9660, Rock Ridge, Joliet, UDF, HFS, HFS+ — modern replacement |
See CD-ROM Filesystems for the full deep-dive: format coverage matrix, handler architecture, mount configuration, and decision guide.
64-Bit Addressing (TD64 / NSD)
For drives larger than 4 GB:
/* TD64 — uses io_Actual for high 32 bits: */
diskReq->io_Command = NSCMD_TD_READ64;
diskReq->io_Data = buffer;
diskReq->io_Length = 512;
diskReq->io_Offset = lowOffset; /* low 32 bits */
diskReq->io_Actual = highOffset; /* high 32 bits */
DoIO((struct IORequest *)diskReq);
Tip
New Style Device (NSD) provides a standard way to query 64-bit support: send
NSCMD_DEVICEQUERYand check the returned command list.
MiSTer / FPGA Notes
| Aspect | Implementation |
|---|---|
| IDE emulation | MiSTer emulates Gayle IDE — presents virtual ATA backed by SD card .hdf |
| SCSI emulation | A2091/A3000 SCSI cores map targets to .hdf files |
| Sector size | Must be 512 bytes — all Amiga drivers assume this |
| RDB | Rigid Disk Block at sectors 0–15 — must be present for HDToolBox |
| Performance | Virtual IDE is faster than real Gayle (no PIO bottleneck) |
References
- NDK39:
devices/scsidisk.h,devices/trackdisk.h - ADCD 2.1: scsi.device autodocs
- SCSI-2 standard: ANSI X3.131-1994
- See also: trackdisk.md — floppy I/O (shares the same API model)
- See also: CDTV Hardware — DMAC/WD33C93 SCSI CD-ROM controller
- See also: Akiko — CD32 — CD32 CD-ROM controller (Akiko PIO, not SCSI)
- See also: Gayle IDE & PCMCIA — A600/A1200 IDE controller
- See also: Gary — A3000 — A3000 SDMAC/WD33C93 SCSI integration
- See also: CD-ROM Filesystems — CDFS handler deep-dive: ISO 9660, Rock Ridge, Joliet, UDF, handler comparison
- See also: ATA/ATAPI Protocol — ATA task file registers, ATAPI packet commands, driver ecosystem (IDE-fix, Buddha, FastATA), CompactFlash, removable media