qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] virtio-scsi spec, first public draft


From: Stefan Hajnoczi
Subject: Re: [Qemu-devel] virtio-scsi spec, first public draft
Date: Thu, 5 May 2011 10:43:23 +0100
User-agent: Mutt/1.5.21 (2010-09-15)

On Thu, May 05, 2011 at 12:28:31AM +0200, Paolo Bonzini wrote:
> Virtio SCSI Controller Device Spec
> ==================================
> 
> The virtio controller device groups together one or more simple virtual
> devices (ie. disk), and allows communicating to these devices using the
> SCSI protocol.  A controller device represents a SCSI host with many
> targets attached.
> 
> The virtio controller services two kinds of requests:
> 
> - command requests for a logical unit;
> 
> - task management functions related to a logical unit, target or
> command.
> 
> The controller is also able to send out notifications about added
> and removed devices.
> 
> v4:
>     First public version
> 
> Configuration
> -------------
> 
> Subsystem Device ID
>     TBD
> 
> Virtqueues
>     0..n-1:one requestq per target
>     n:control transmitq
>     n+1:control receiveq

1 requestq per target makes it harder to support large numbers or
dynamic targets.  You mention detaching targets so is there a way to add
a target?

The following would be simpler:
    0:requestq
    1:control transmitq
    2:control receiveq

Requests must include a target port identifier/name so that they can be
delivered to the correct target.  Adding or removing targets is easy
with a single requestq since the virtqueues don't change.

> Feature bits
>     VIRTIO_SCSI_F_INOUT - Whether a single request can include both
>         read-only and write-only data buffers.

Why make this an optional feature?

> Device configuration layout
>     struct virtio_scsi_config {
>         u32 num_targets;
>     }
> 
>     num_targets is the number of targets, and the id of the
>     virtqueue used for the control receiveq.
> 
> Device initialization
> ---------------------
> 
> The initialization routine should first of all discover the controller's
> control virtqueues.
> 
> The driver should then place at least a buffer in the control receiveq.
> Buffers returned by the device on the control receiveq may be referred
> to as "events" in the rest of the document.
> 
> The driver can immediately issue requests (for example, INQUIRY or
> REPORT LUNS) or task management functions (for example, I_T RESET).
> 
> Device operation: request queue
> -------------------------------
> 
> The driver queues requests to the virtqueue, and they are used by the device
> (not necessarily in order).
> 
> Requests have the following format:
> 
>     struct virtio_scsi_req
>     {
>         u32 type;
>         ...
>         u8 response;
>     }
> 
>     #define VIRTIO_SCSI_T_BARRIER         0x80000000
> 
>     The type identifies the remaining fields.  The value
>     VIRTIO_SCSI_T_BARRIER can be ORed in the type as well.  This bit
>     indicates that this request acts as a barrier and that all preceding
>     requests must be complete before this one, and all following requests
>     must not be started until this is complete.  Note that a barrier
>     does not flush caches in the underlying backend device in host,
>     and thus does not serve as data consistency guarantee.  The driver
>     must send a SYNCHRONIZE CACHE command to flush the host cache.

Why are these barrier semantics needed?

>     Valid response values are defined separately for each command.
> 
> - Task management function
> 
>     #define VIRTIO_SCSI_T_TMF                      0
> 
>     #define VIRTIO_SCSI_T_TMF_ABORT_TASK_SET       1
>     #define VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET      4
>     #define VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET   5
>     #define VIRTIO_SCSI_T_TMF_QUERY_TASK_SET       7
> 
>     #define VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_DETACH  (1 << 24)
> 
>     struct virtio_scsi_req_tmf
>     {
>         u32 subtype;
>         u8 lun[8];
>         u8 additional[];
>         u8 response;
>     }
> 
>     /* command-specific response values */
>     #define VIRTIO_SCSI_S_FUNCTION_COMPLETE        0
>     #define VIRTIO_SCSI_S_NO_TARGET                1
>     #define VIRTIO_SCSI_S_TARGET_FAILURE           2
>     #define VIRTIO_SCSI_S_FUNCTION_SUCCEEDED       3
>     #define VIRTIO_SCSI_S_FUNCTION_REJECTED        4
>     #define VIRTIO_SCSI_S_INCORRECT_LUN            5
> 
>     The type is VIRTIO_SCSI_T_LUN_INFO, possibly with the
>     VIRTIO_SCSI_T_BARRIER bit ORed in.

Did you mean "type is VIRTIO_SCSI_T_TMF"?

> 
>     The subtype and lun field are filled in by the driver, the additional
>     and response field is filled in by the device.  Unknown LUNs are
>     ignored; also, the lun field is ignored for the I_T NEXUS RESET
>     command.

In/out buffers must be separate in virtio so I think it makes sense to
split apart a struct virtio_scsi_tmf_req and struct
virtio_scsi_tmf_resp.

>     Task management functions accepting an I_T_L_Q nexus (ABORT TASK,
>     QUERY TASK) are only accessible through the control transmitq.
>     Task management functions not in the above list are not accessible
>     in this version of the specification.  Future versions may allow
>     access to them through additional features.
> 
>     VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_DETACH asks the device to make the
>     logical unit (and the target as well if this is the last logical
>     unit) disappear.  It takes an I_T_L nexus.  This non-standard TMF
>     should be used in response to a host request to shutdown a target
>     or LUN, after having placed the LUN in a clean state.

Do we need an initiator-driven detach?  If the initiator doesn't care
about a device anymore it simply doesn't communicate with it or allocate
resources for it.  I think the real detach should be performed on the
target side (e.g. QEMU monitor command removes the target from the SCSI
bus).  So I guess I'm asking what is the real use-case for this
function?

>     The outcome of the task management function is written by the device
>     in the response field.  A value of VIRTIO_SCSI_S_NO_TARGET means
>     that (even though the virtqueue exists) there is no target with this
>     number.  Other return values map 1-to-1 with those defined in SAM.
> 
> - SCSI command
> 
>     #define VIRTIO_SCSI_T_CMD                     1
> 
>     struct virtio_scsi_req_cmd {
>         u32 type;
>         u32 ioprio;
>         u8 lun[8];
>         u64 id;
>         u32 num_dataout, num_datain;
>         char cdb[];
>         char data[][num_dataout+num_datain];
>         u8 sense[];
>         u32 sense_len;
>         u32 residual;
>         u8 status;
>         u8 response;
>     };

We don't need explicit buffer size fields since virtqueue elements
include sizes.  For example:

size_t sense_len = elem->in_sg[sense_idx].iov_len;
memcpy(elem->in_sg[sense_idx].iov_buf, sense_buf,
       MIN(sense_len, sizeof(sense_buf)));

Stefan



reply via email to

[Prev in Thread] Current Thread [Next in Thread]