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_DONE is raised when setup is finished.

  • TAPEDEV_STATUS - Status information
    • TAPEDEV_STATUS_DISABLED - Device is disabled

    • TAPEDEV_STATUS_IDLE - Device is waiting for a command

    • TAPEDEV_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 command

  • TAPEDEV_SECT_STATUS - Section status
    • TAPEDEV_SECT_STATUS_IDLE - Device is ready to accept commands

    • TAPEDEV_SECT_STATUS_WORKING - Command in progress

    • TAPEDEV_SECT_STATUS_DONE - Command done

    • TAPEDEV_SECT_STATUS_ERR_INVALID_CMD - Invalid command

    • TAPEDEV_SECT_STATUS_ERR_TAPE_ACTIVE - Tape in drive

    • TAPEDEV_SECT_STATUS_ERR_NO_TAPE - No tape in drive

    • TAPEDEV_SECT_STATUS_ERR_RESET - Unrecoverable hypervisor error; please report on Slack.

    • TAPEDEV_SECT_STATUS_ERR_INVALID_TAPE_NO - No tape with given ID

    • TAPEDEV_SECT_STATUS_ERR_INVALID_FFWD_POS - Fast-forward past end of tape

    • TAPEDEV_SECT_STATUS_ERR_READ_PAST_END - Read past end of tape

    • TAPEDEV_SECT_STATUS_ERR_WRITE_PAST_END - Write past end of tape

    • TAPEDEV_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 section

  • TAPEDEV_SECT_TAPE_SIZE - Type of tape, can be converted to size of a tape in bytes
    • 0 - 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 drive
    • Bits 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 drive

  • TAPEDEV_CMD_REWIND - Rewind tape to beginning

  • TAPEDEV_CMD_FAST_FWD - Fast-forward tape by n blocks
    • Bits 8-31: number of blocks to forward the tape by

  • TAPEDEV_CMD_READ - Read tape
    • Bits 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 tape
    • Will 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:

  1. Clear all interrupts by writing to TAPEDEV_IRQ_CLEAR

  2. Enable at least the TAPEDEV_IRQ_INIT_DONE and TAPEDEV_IRQ_HW_ERROR interrupts.

  3. Write 1 to TAPEDEV_ENABLE.

  4. The device has finished initializing when you receive the TAPEDEV_IRQ_INIT_DONE interrupt.