Tape device¶
Warning
Make sure you have the latest version of QEMU:
commit 0855a81f6f1c6f5700e30cc9c5a46ce1b096fc10
Published on May 09.
After pulling, make sure to recompile QEMU. Otherwise, read/write commands may not work correctly with some pagetable configurations.
The tape device is attached to a PCI card via a special, proprietary interface. The PCI card is connected to the computer. Your task is to write a driver for the PCI card.
The device contains up to 8 sections. Each section contains a number of tapes with a common size. Each section can read and write a single tape independently of other sections. You can imagine that each section is a shelf of tapes (think "cassettes"), a robot arm, and a tape player with play, rewind, fast forward, and a recording function.
Your task is to implement a block device driver for this device. Each section should be visible as a separate block device in the operating system.
You communicate with each section through a command register. Each section (and the device itself) sends an interrupt when a command is finished or when it fails.
The device is controlled using MMIO registers. It has only one BAR (BAR0, also used for all section registers) and uses a single PCI interrupt line.
All registers are 32-bit, little-endian. Access has to be aligned to a 4-byte boundary. Access of size other than 4 may fail.
Device registers¶
TAPEDEV_ENABLE- Write 1 to enable the device, 0 to disable it.TAPEDEV_IRQ_INIT_DONEis raised when setup is finished.TAPEDEV_STATUS- Status informationTAPEDEV_STATUS_DISABLED- Device is disabledTAPEDEV_STATUS_IDLE- Device is waiting for a commandTAPEDEV_STATUS_ERROR- Last command finished with an error
TAPEDEV_IRQ_STATUS- Interrupt status.TAPEDEV_IRQ_MASK- Interrupt mask. Interrupts won't be raised for enabled bits in this register.TAPEDEV_IRQ_CLEAR- Write to clear interrupts. Enabled bits in the written word will clear corresponding interrupts.TAPEDEV_SECTIONS- Number of sections (up to 8)
The following macros mean the number of a bit in TAPEDEV_IRQ_* word, starting from least significant:
TAPEDEV_IRQ_INIT_DONE- Init done.TAPEDEV_IRQ_HW_ERROR- Hardware error.TAPEDEV_IRQ_SECT_n_DONE- Section finished a command.TAPEDEV_IRQ_SECT_n_ERROR- Section error, check status.
Section registers¶
Each section has its own register space, starting under (section id, numbered from 1)*0x100.
TAPEDEV_SECT_CMD- Write to schedule a commandTAPEDEV_SECT_STATUS- Section statusTAPEDEV_SECT_STATUS_IDLE- Device is ready to accept commandsTAPEDEV_SECT_STATUS_WORKING- Command in progressTAPEDEV_SECT_STATUS_DONE- Command doneTAPEDEV_SECT_STATUS_ERR_INVALID_CMD- Invalid commandTAPEDEV_SECT_STATUS_ERR_TAPE_ACTIVE- Tape in driveTAPEDEV_SECT_STATUS_ERR_NO_TAPE- No tape in driveTAPEDEV_SECT_STATUS_ERR_RESET- Unrecoverable hypervisor error; please report on Slack.TAPEDEV_SECT_STATUS_ERR_INVALID_TAPE_NO- No tape with given IDTAPEDEV_SECT_STATUS_ERR_INVALID_FFWD_POS- Fast-forward past end of tapeTAPEDEV_SECT_STATUS_ERR_READ_PAST_END- Read past end of tapeTAPEDEV_SECT_STATUS_ERR_WRITE_PAST_END- Write past end of tapeTAPEDEV_SECT_STATUS_ERR_IO- Unrecoverable hypervisor error; please report on Slack.TAPEDEV_SECT_STATUS_ERR_PGTABLE- Failed to read from/write to the buffer, memory, or page table error
TAPEDEV_SECT_BUFFER_PTR- Bits 9-40 of the pointer to buffer/page table. Has to be aligned to a 512-byte boundary.TAPEDEV_SECT_TAPE_NO- Number of currently loaded tape, numbered from 1. If the tape drive is empty, 0.TAPEDEV_SECT_TAPES- Number of tapes in this sectionTAPEDEV_SECT_TAPE_SIZE- Type of tape, can be converted to size of a tape in bytes0 - 32 * 8192 bytes
1 - 64 * 8192 bytes
2 - 128 * 8192 bytes
3 - 256 * 8192 bytes
4 - 512 * 8192 bytes
TAPEDEV_SECT_TAPE_BLOCKSIZE- Configurable size of a single read or write.0 - 512
1 - 1024
2 - 2048
3 - 4096
4 - 8192
Commands¶
Each command is a 32-bit word. Bits 0-7 are the identifier of the command. Bits 8-31 are used to pass command-specific information.
TAPEDEV_CMD_TAKE_TAPE- Put tape in driveBits 8-31: number of the tape, starting from 1
Will raise an error if the drive is not empty
TAPEDEV_CMD_EJECT_TAPE- Eject tape from the driveTAPEDEV_CMD_REWIND- Rewind tape to beginningTAPEDEV_CMD_FAST_FWD- Fast-forward tape by n blocksBits 8-31: number of blocks to forward the tape by
TAPEDEV_CMD_READ- Read tapeBits 8-22: number of blocks to read
Bits 23-31: offset in page table counted in blocks
Will raise an error if the drive is empty
TAPEDEV_CMD_WRITE- Write tapeWill raise an error if the drive is empty
Bits 8-22: number of blocks to write
Bits 23-31: offset in page table counted in blocks
Buffer¶
The device supports scatter/gather - many blocks can be read from/written to a non-continuous buffer in a single command. The pointer passed to TAPEDEV_SECT_BUFFER_PTR is expected to point to a 4096-byte-large buffer containing a page table. Each of the 512 64-bit entries consists of two 32-bit words. The more significant word is bits 9-40 of the address of the buffer. The buffer has to be aligned to a 512-byte boundary. The less-significant 32-bit word is the size of the buffer in BLOCKSIZE blocks.
Starting the device¶
To start the device:
Clear all interrupts by writing to
TAPEDEV_IRQ_CLEAREnable at least the
TAPEDEV_IRQ_INIT_DONEandTAPEDEV_IRQ_HW_ERRORinterrupts.Write 1 to
TAPEDEV_ENABLE.The device has finished initializing when you receive the
TAPEDEV_IRQ_INIT_DONEinterrupt.