From KVM

STORPORT miniport driver for VIRTIO based SCSI controller

Scope

VirtIO miniport driver works together with the Storport driver. Storport miniport driver is a vendor-supplied driver used to access hardware. The following document describes VirtIO Storport miniport driver design goals and implementation. Detailed description of VirtIO itself is out of the scope and will not be covered in this document.

Code tour

File Description
virtio_store.c Main source module for the miniport.
virtio_store.h Main include file for the miniport.
virtio_store.rc Resource definitions.
virtio_store_utils.c Source file for print to COM port routine.
virtio_store_utils.h Include file containing debugging and debugging print related definitions.
virtio_store_hw_helper.c Source file containing some "HW" related routines.
virtio_store_hw_helper.h Include file containing definitions for some "HW" related routines.
osdep.h Include OS dependent definitions.
VirtIO.h Include file containing VirtIO queue related definitions.
virtio_pci.c Source file for VirtIO PCI device routines.
virtio_pci.h Include file for VirtIO PCI device.
virtio_ring.c Source file for VirtIO ring routines.
virtio_ring.h Include file for VirtIO ring definitions.
txtsetup.oem Windows Server 2003 text-mode setup file.
wlh.inf Windows Server 2008 INF file.
wnet.inf Windows Server 2003 INF file.

Main Declarations and Data Structures

VirtIO block device configuration descriptor

typedef struct virtio_blk_config {

   u64 capacity;                      /* The capacity (in 512-byte sectors). */
   u32 size_max;                      /* The maximum segment size (if VIRTIO_BLK_F_SIZE_MAX) */
   u32 seg_max;                       /* The maximum number of segments (if VIRTIO_BLK_F_SEG_MAX) */
   struct virtio_blk_geometry {       /* geometry the device (if VIRTIO_BLK_F_GEOMETRY) */
       u16 cylinders;
       u8 heads;
       u8 sectors;
   } geometry;
   u32 blk_size;                      /* block size of device (if VIRTIO_BLK_F_BLK_SIZE) */

}blk_config, *pblk_config;

Miniport driver's per-HBA extension

typedef struct _ADAPTER_EXTENSION {

   ULONG_PTR             device_base; /* device base address */
   virtio_pci_vq_info    pci_vq_info; /* pci virtual queue information block*/
   vring_virtqueue*      virtqueue;   /* virtual queue pointer*/
   INQUIRYDATA           inquiry_data;/* inquiry data block */
   blk_config            info;        /* block device configutation block */
   ULONG                 breaks_number;/* number of phisical breaks to adjust the PORT_CONFIGURATION_INFORMATION */
   ULONG                 transfer_size;/* maximum transfer size to adjust the PORT_CONFIGURATION_INFORMATION */
   ULONG                 queue_depth; /* maximum depth of the device queue */
   BOOLEAN               dump_mode;   /* runningin crash-dump mode*/

}ADAPTER_EXTENSION, *PADAPTER_EXTENSION;

VirtIO request header

typedef struct virtio_blk_outhdr {

   u32 type;                          /* VIRTIO_BLK_T* */
   u32 ioprio;                        /* io priority. Always 0*/
   u64 sector;                        /* Sector (ie. 512 byte offset) */

}blk_outhdr, *pblk_outhdr;

VirtIO request descriptor

typedef struct virtio_blk_req {

   struct list_head list;             /* currently not in use*/
   struct request *req;               /* pointer to SRB*/
   blk_outhdr out_hdr;                /* runningin crash-dump mode*/
   u8     status;                     /* request completion status */
   VIO_SG sg[VIRTIO_MAX_SG];          /* buffer that holdes scatter-gather list*/

}blk_req, *pblk_req;

Miniport driver's per-SRB extension

typedef struct _RHEL_SRB_EXTENSION {

   blk_req               vbr;         /* request descriptor block */
   ULONG                 out;         /* number of OUT elements */
   ULONG                 in;          /* number of IN elements */

}RHEL_SRB_EXTENSION, *PRHEL_SRB_EXTENSION;

Functions

VirtIO Storport miniport driver routines

VirtIoFindAdapter

The VirtIoFindAdapter routine uses the supplied configuration to determine whether a VirtIO HBA is supported and, if it is, to return configuration information about that adapter

ULONG VirtIoFindAdapter(

   IN PVOID DeviceExtension,
   IN PVOID HwContext,
   IN PVOID BusInformation,
   IN PCHAR ArgumentString,
   IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
   OUT PBOOLEAN Again
   );

VirtIoHwInitialize

The VirtIoHwInitialize routine initializes the miniport driver after system reboot or power failure occurs. It is called by StorPort after VirtIoFindAdapter successfully returns. VirtIoHwInitialize initializes the VirtIO HBA.

BOOLEAN VirtIoHwInitialize(

   IN PVOID DeviceExtension
   );

VirtIoBuildIo

The VirtIoBuildIo routine processes the SRB with unsynchronized access to shared system data structures before passing it to VirtIoStartIo.

BOOLEAN VirtIoBuildIo(

   IN PVOID DeviceExtension,
   IN PSCSI_REQUEST_BLOCK Srb
   );

VirtIoStartIo

The Storport driver calls the VirtIoStartIo routine one time for each incoming I/O request.

BOOLEAN VirtIoStartIo(

   IN PVOID DeviceExtension,
   IN PSCSI_REQUEST_BLOCK Srb
   );

VirtIoInterrupt

The Storport driver calls the VirtIoInterrupt routine after the VirtIO HBA generates an interrupt request.

BOOLEAN VirtIoInterrupt(

   IN PVOID DeviceExtension
   );

VirtIoResetBus

The VirtIoResetBus routine is called by the port driver to clear error conditions.

BOOLEAN VirtIoResetBus(

   IN PVOID DeviceExtension,
   IN ULONG PathId
   );

VirtIoAdapterControl

The VirtIoAdapterControl routine is called to perform synchronous operations to control the state or behavior of an adapter, such as stopping or restarting the VirtIO HBA for power management.

SCSI_ADAPTER_CONTROL_STATUS VirtIoAdapterControl(

   IN PVOID DeviceExtension,
   IN SCSI_ADAPTER_CONTROL_TYPE ControlType,
   IN PVOID Parameters
   );

VirtIO support routines

VirtIODeviceReset

The VirtIODeviceReset routine is called from RhelShutDown routine to perform the VirtIO device reset.

VOID VirtIODeviceReset(

   IN PVOID DeviceExtension);

VirtIODeviceGetHostFeature

The VirtIODeviceGetHostFeature routine is called from VirtIoHwInitialize routine to obtain the VirtIO device feature.

bool VirtIODeviceGetHostFeature(

   IN PVOID DeviceExtension,
   IN unsigned uFeature);

VirtIODeviceGet

The VirtIODeviceGet routine is called from VirtIoHwInitialize routine to obtain a block of unformatted data by reading the VirtIO device PCI configuration space.

void VirtIODeviceGet(

   IN PVOID DeviceExtension,
   unsigned offset,
   PVOID buf,
   unsigned len);

VirtIODeviceISR

The VirtIODeviceISR routine is called from VirtIoInterrupt routine to obtain an interrupt status.

UCHAR VirtIODeviceISR(

   IN PVOID DeviceExtension);

VirtIODeviceFindVirtualQueue

The VirtIODeviceFindVirtualQueue routine is called from VirtIoFindAdapter and VirtIoAdapterControl routines to create or re-create a virtual queue.

struct virtqueue* VirtIODeviceFindVirtualQueue(

   IN PVOID DeviceExtension,
   IN unsigned index);

Miscellaneous routines

RhelDoReadWrite

The RhelDoReadWrite routine is called from VirtIoStartIo routine. It passes an array of scatter gather elements to VirtIO queue by calling the add_buf and, if the above operation was ok, calls kick routines.

BOOLEAN RhelDoReadWrite(

   IN PVOID DeviceExtension,
   PSCSI_REQUEST_BLOCK Srb
   );

RhelShutDown

The RhelShutDown routine is called from VirtIoAdapterControl routine in response to ScsiStopAdapter request to delete a virtual queue and reset the underlying VirtIO device.

VOID RhelShutDown(

   IN PVOID DeviceExtension
   );

RhelDbgPrintToComPort

The RhelDbgPrintToComPort routine is called from everywhere to output debug print to COM1 port.

ULONG _cdecl RhelDbgPrintToComPort(

   __in LPTSTR Format,
   ...
   );

How to build

Run the appropriated WDK build environment. Go to the viostor project directory and run "build –cegZ" command.

Debugging

Even though live debugging is possible and sometimes highly desirable, in most cases debugging by printing is good enough to find a problem. Debug printing verbosity can be changed by adjusting RhelDbgLevel variable defined in virtio_stor.c file. Different levels of verbosity are defined in virtio_store_utilities.h file

  1. define TRACE_LEVEL_NONE 0 // Tracing is not on
  2. define TRACE_LEVEL_FATAL 1 // Abnormal exit or termination
  3. define TRACE_LEVEL_ERROR 2 // Severe errors that need logging
  4. define TRACE_LEVEL_WARNING 3 // Warnings such as allocation failure
  5. define TRACE_LEVEL_INFORMATION 4 // Includes non-error cases(e.g.,Entry-Exit)
  6. define TRACE_LEVEL_VERBOSE 5 // Detailed traces from intermediate steps

Debug output to COM1 port can be turned on by uncommiting the following string in SOURCES file:

  1. C_DEFINES = -DRHEL_COM_DEBUG=1 $(C_DEFINES)

Useful information

Find everything you need here: Storport Miniport Drivers

VirtIO block for XP

An old style, SCSIPort driver, can be created by building the code in XP environment. However, due to the lack of resources SCSIPort driver has never been fully tested and currently is unsupported.