[Top][All Lists]
[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
- [Qemu-devel] virtio-scsi spec, first public draft, Paolo Bonzini, 2011/05/04
- Re: [Qemu-devel] virtio-scsi spec, first public draft,
Stefan Hajnoczi <=
- Re: [Qemu-devel] virtio-scsi spec, first public draft, Paolo Bonzini, 2011/05/05
- Re: [Qemu-devel] virtio-scsi spec, first public draft, Hannes Reinecke, 2011/05/05
- Re: [Qemu-devel] virtio-scsi spec, first public draft, Paolo Bonzini, 2011/05/05
- Re: [Qemu-devel] virtio-scsi spec, first public draft, Stefan Hajnoczi, 2011/05/06
- Re: [Qemu-devel] virtio-scsi spec, first public draft, Paolo Bonzini, 2011/05/06
Re: [Qemu-devel] virtio-scsi spec, first public draft, Christoph Hellwig, 2011/05/05