/** @file

  Virtio Block Device specific type and macro definitions corresponding to the
  virtio-0.9.5 specification.

  Copyright (C) 2012, Red Hat, Inc.

  SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#ifndef _VIRTIO_BLK_H_
#define _VIRTIO_BLK_H_

#include <IndustryStandard/Virtio.h>

//
// virtio-0.9.5, Appendix D: Block Device
//
#pragma pack(1)
typedef struct {
  UINT8     PhysicalBlockExp; // # of logical blocks per physical block (log2)
  UINT8     AlignmentOffset;  // offset of first aligned logical block
  UINT16    MinIoSize;        // suggested minimum I/O size in blocks
  UINT32    OptIoSize;        // optimal (suggested maximum) I/O size in blocks
} VIRTIO_BLK_TOPOLOGY;

typedef struct {
  UINT64                 Capacity;
  UINT32                 SizeMax;
  UINT32                 SegMax;
  UINT16                 Cylinders;
  UINT8                  Heads;
  UINT8                  Sectors;
  UINT32                 BlkSize;
  VIRTIO_BLK_TOPOLOGY    Topology;
} VIRTIO_BLK_CONFIG;
#pragma pack()

#define OFFSET_OF_VBLK(Field)  OFFSET_OF (VIRTIO_BLK_CONFIG, Field)
#define SIZE_OF_VBLK(Field)    (sizeof ((VIRTIO_BLK_CONFIG *) 0)->Field)

#define VIRTIO_BLK_F_BARRIER   BIT0
#define VIRTIO_BLK_F_SIZE_MAX  BIT1
#define VIRTIO_BLK_F_SEG_MAX   BIT2
#define VIRTIO_BLK_F_GEOMETRY  BIT4
#define VIRTIO_BLK_F_RO        BIT5
#define VIRTIO_BLK_F_BLK_SIZE  BIT6 // treated as "logical block size" in
                                    // practice; actual host side
                                    // implementation negotiates "optimal"
                                    // block size separately, via
                                    // VIRTIO_BLK_F_TOPOLOGY
#define VIRTIO_BLK_F_SCSI      BIT7
#define VIRTIO_BLK_F_FLUSH     BIT9  // identical to "write cache enabled"
#define VIRTIO_BLK_F_TOPOLOGY  BIT10 // information on optimal I/O alignment

//
// We keep the status byte separate from the rest of the virtio-blk request
// header. See description of historical scattering at the end of Appendix D:
// we're going to put the status byte in a separate VRING_DESC.
//
#pragma pack(1)
typedef struct {
  UINT32    Type;
  UINT32    IoPrio;
  UINT64    Sector;
} VIRTIO_BLK_REQ;
#pragma pack()

#define VIRTIO_BLK_T_IN            0x00000000
#define VIRTIO_BLK_T_OUT           0x00000001
#define VIRTIO_BLK_T_SCSI_CMD      0x00000002
#define VIRTIO_BLK_T_SCSI_CMD_OUT  0x00000003
#define VIRTIO_BLK_T_FLUSH         0x00000004
#define VIRTIO_BLK_T_FLUSH_OUT     0x00000005
#define VIRTIO_BLK_T_BARRIER       BIT31

#define VIRTIO_BLK_S_OK      0x00
#define VIRTIO_BLK_S_IOERR   0x01
#define VIRTIO_BLK_S_UNSUPP  0x02

#endif // _VIRTIO_BLK_H_
