#include <DriverSupport/disk/Types.h>

/*
 * RPC interface exposed by disk drivers for a particular disk. 
 */
interface DiskDriver {
    /// Gets the capacity of the disk
    GetCapacity(diskId: UInt64) => (status: Int32, sectorSize: UInt32, numSectors: UInt64)

    /**
     * Opens a session to the disk driver, which includes a shared memory region in which read and
     * write commands are submitted by the client side of the connection. It consists of an array
     * of command descriptors.
     *
     * Note that the client is in charge of marking a command descriptor as allocated; but the
     * remote end is responsible for marking them as free, as this also requires some management
     * of the associated read/write physical memory buffers.
     *
     * The caller should map the shared memory region into its address space. It may use normal
     * cacheability as it is not accessed by the hardware for data transfers. The returned session
     * token should be included with all subsequent command calls to uniquely identify the buffers.
     *
     * We do not require that tokens are any particular value or format, other than that a valid
     * token MAY NOT be 0.
     */
    OpenSession() => (status: Int32, sessionToken: UInt64, regionHandle: UInt64, regionSize: UInt64, numCommands: UInt64)

    /**
     * Releases all shared memory regions, including read/write buffers, associated with the
     * provided session. Any commands that are currently in flight will be canceled.
     */
    CloseSession(session: UInt64) => (status: Int32)

    /**
     * Creates the read buffer allocation, with the requested minimum size of memory preallocated.
     *
     * Note that the given size is treated as a hint. The driver is free to completely ignore it,
     * so the caller should be able to deal with getting much less memory.
     *
     * This region is able to grow as needed. Returned is a maximum size that the caller should
     * reserve for the read buffer in its virtual memory map.
     */
    CreateReadBuffer(session: UInt64, requestedSize: UInt64) => (status: Int32, readBufHandle: UInt64, readBufMaxSize: UInt64)

    /**
     * Creates the write buffer allocation, with the requested minimum size of memory preallocated.
     *
     * Note that the given size is treated as a hint. The driver is free to completely ignore it,
     * so the caller should be able to deal with getting much less memory.
     *
     * This region is able to grow as needed. Returned is a maximum size that the caller should
     * reserve for the write buffer in its virtual memory map.
     */
    CreateWriteBuffer(session: UInt64, requestedSize: UInt64) => (status: Int32, writeBufHandle: UInt64, writeBufMaxSize: UInt64)

    /**
     * Notifies the remote end that the command in the given slot is ready to be executed.
     *
     * For write commands, you should no longer access the write buffer region after this point.
     * In the case of both read and write commands, access to the command slot after issuing this
     * call is prohibited until the command completion notification has been received.
     */
    ExecuteCommand(session: UInt64, slot: UInt32) =|

    /**
     * Indicates that a command slot, which was used for a read, is no longer needed and both the
     * command slot and its associated read buffer region may be reused.
     *
     * The client should call this after it's finished using the read data or copied it to another
     * buffer for later use.
     */
    ReleaseReadCommand(session: UInt64, slot: UInt32) =|

    /**
     * Requests an allocation of memory in the write buffer region, which may then be used as part
     * of a write command when sent to the device.
     *
     * The size may also be adjusted upwards to account for any minimum sector sizes, and the
     * caller should use the returned `bytesAllocated` value as the size it requests for the write.
     *
     * Note that this allocation is automatically released when the write completes. This means you
     * MUST use an allocation for a write, even if it is one with an invalid parameter, so that it
     * gets correctly released or you will eventually run out of write buffer space.
     */
    AllocWriteMemory(session: UInt64, bytesRequested: UInt64) => (status: Int32, offset: UInt64, bytesAllocated: UInt64)
}
