An in-memory SSC-3 tape drive simulation library for Go.
Status: Standalone module with 46 unit tests under race detector. Used by uiscsi-tape mock target and the upcoming TCMU tape handler.
tapesim encapsulates all tape state -- position, filemarks, block size, EOM enforcement, density, compression, and error injection -- in a single Media type. It exposes operations matching SSC-3 semantics so that both the mock iSCSI target and the TCMU handler can delegate tape logic to a shared, independently tested implementation.
tapesim is stdlib-only and has no external dependencies.
- SSC-3 tape operations -- Read, Write, WriteFilemarks, Space, Rewind, ReadPosition
- Two-tier EOM -- early warning past configurable threshold, hard VOLUME OVERFLOW at media boundary
- Filemark handling -- SPACE positions at filemark (non-consuming per SSC-3), Read detects and consumes
- SPACE codes -- blocks, filemarks, end-of-data, with forward/backward and boundary clamping
- Fixed and variable block modes -- configurable via SetBlockSize
- Compression state -- DCE/DDE flags for MODE SENSE/SELECT support
- Sense data encoding -- SenseInfo with EncodeFixedSense (18-byte fixed-format, response code 0x70)
- Error injection -- per-opcode FIFO queues for deterministic fault testing (InjectError, InjectShortRead, InjectFilemark)
- Unit attention -- optional consume-once UA for TCMU handler use
- Functional options -- NewMedia constructor with WithEOMThreshold, WithBlockSize, WithDensityCode, WithUnitAttention
- No external dependencies -- stdlib only
import "github.com/uiscsi/tapesim"
// Create a 1 GB tape media with 90% EOM threshold (default).
m := tapesim.NewMedia(1<<30)
// Write data.
data := []byte("hello tape")
n, sense := m.Write(data, false) // variable mode
if sense != nil {
// Handle EOM warning or volume overflow.
}
// Rewind and read back.
m.Rewind()
buf := make([]byte, 1024)
n, sense = m.Read(buf, false)
// Write a filemark and space to it.
m.WriteFilemarks(1)
m.Rewind()
sense = m.Space(0x01, 1) // SPACE FILEMARKS forward 1
// Encode sense data for SCSI response.
si := &tapesim.SenseInfo{Key: 0x00, FM: true, ASC: 0x00, ASCQ: 0x01}
senseBytes := tapesim.EncodeFixedSense(si)| Type / Function | Description |
|---|---|
NewMedia(size, ...Option) |
Create tape media with functional options |
Media.Read(buf, fixed) |
Read from current position |
Media.Write(data, fixed) |
Write at current position |
Media.WriteFilemarks(count) |
Record filemarks |
Media.Space(code, count) |
Position by blocks, filemarks, or end-of-data |
Media.Rewind() |
Reset position to beginning |
Media.ReadPosition() |
Current position with BOP/EOP flags |
Media.BlockSize() / SetBlockSize() |
Fixed vs variable block mode |
Media.BlockLimits() |
Min/max block size |
Media.Compression() / SetCompression() |
DCE/DDE state |
Media.InjectError(op, key, asc, ascq) |
Queue a sense error for testing |
Media.InjectShortRead(op, len) |
Queue a short read for testing |
Media.InjectFilemark(pos) |
Insert a filemark at position |
DecodeSPACECount(cdb2, cdb3, cdb4) |
Sign-extend 24-bit SPACE count |
EncodeFixedSense(si) |
Encode SenseInfo to 18-byte fixed format |
go test -race ./...- Go 1.25+
GNU General Public License v3.0 -- see LICENSE.
- uiscsi -- pure-userspace iSCSI initiator library
- uiscsi-tape -- SSC tape driver over iSCSI
- tapeplayer -- TUI FLAC audio player for iSCSI tape drives
- go-tcmu -- Go bindings for Linux TCMU (target core user)