virtio_blk: SG_IO passthru support
Subsystems (4)
PATCH 1/1 virtio_blk: SG_IO passthru support
From: Hannes Reinecke <[email protected]>
Add support for SG_IO passthru to virtio_blk. We add the scsi command block after the normal outhdr, and the scsi inhdr with full status information aswell as the sense buffer before the regular inhdr.
[hch: forward ported, added the VIRTIO_BLK_F_SCSI flags, some comments
and tested the whole beast]
drivers/block/virtio_blk.c +54 -16
@@ -37,6 +37,7 @@ struct virtblk_reqstruct list_head list;struct request *req;struct virtio_blk_outhdr out_hdr; +struct virtio_scsi_inhdr in_hdr;u8 status; };
@@ -49,7 +50,9 @@ static void blk_done(struct virtqueue *vspin_lock_irqsave (&vblk->lock, flags);while ((vbr = vblk->vq->vq_ops->get_buf (vblk->vq, &len)) !=NULL ) { +unsigned int nr_bytes;int error; +switch (vbr->status) {case VIRTIO_BLK_S_OK : error =0 ;
@@ -62,7 +65,15 @@ static void blk_done(struct virtqueue *vbreak ; } -__blk_end_request (vbr->req, error,blk_rq_bytes (vbr->req)); +if (blk_pc_request (vbr->req)) { + vbr->req->data_len = vbr->in_hdr.residual; + nr_bytes = vbr->in_hdr.data_len; + vbr->req->sense_len = vbr->in_hdr.sense_len; + vbr->req->errors = vbr->in_hdr.errors; + }else + nr_bytes =blk_rq_bytes (vbr->req); + +__blk_end_request (vbr->req, error, nr_bytes);list_del (&vbr->list);mempool_free (vbr, vblk->pool); }
@@ -74,7 +85,7 @@ static void blk_done(struct virtqueue *vstatic bool do_req (struct request_queue *q,struct virtio_blk *vblk,struct request *req) { -unsigned long num, out, in; +unsigned long num, out =0 , in =0 ;struct virtblk_req *vbr; vbr =mempool_alloc (vblk->pool,GFP_ATOMIC );
@@ -99,18 +110,36 @@ static bool do_req(struct request_queueif (blk_barrier_rq (vbr->req)) vbr->out_hdr.type |=VIRTIO_BLK_T_BARRIER ; -sg_set_buf (&vblk->sg[0 ], &vbr->out_hdr,sizeof (vbr->out_hdr)); - num =blk_rq_map_sg (q, vbr->req, vblk->sg+1 ); -sg_set_buf (&vblk->sg[num+1 ], &vbr->status,sizeof (vbr->status)); - -if (rq_data_dir (vbr->req) ==WRITE ) { - vbr->out_hdr.type |=VIRTIO_BLK_T_OUT ; - out =1 + num; - in =1 ; - }else { - vbr->out_hdr.type |=VIRTIO_BLK_T_IN ; - out =1 ; - in =1 + num; +sg_set_buf (&vblk->sg[out++], &vbr->out_hdr,sizeof (vbr->out_hdr)); + +/* +* If this is a packet command we need a couple of additional headers. +* Behind the normal outhdr we put a segment with the scsi command +* block, and before the normal inhdr we put the sense data and the +* inhdr with additional status information before the normal inhdr. +*/ +if (blk_pc_request (vbr->req)) +sg_set_buf (&vblk->sg[out++], vbr->req->cmd, vbr->req->cmd_len); + + num =blk_rq_map_sg (q, vbr->req, vblk->sg + out); + +if (blk_pc_request (vbr->req)) { +sg_set_buf (&vblk->sg[num + out + in++], vbr->req->sense,96 ); +sg_set_buf (&vblk->sg[num + out + in++], &vbr->in_hdr, +sizeof (vbr->in_hdr)); + } + +sg_set_buf (&vblk->sg[num + out + in++], &vbr->status, +sizeof (vbr->status)); + +if (num) { +if (rq_data_dir (vbr->req) ==WRITE ) { + vbr->out_hdr.type |=VIRTIO_BLK_T_OUT ; + out += num; + }else { + vbr->out_hdr.type |=VIRTIO_BLK_T_IN ; + in += num; + } }if (vblk->vq->vq_ops->add_buf (vblk->vq, vblk->sg, out, in, vbr)) {
@@ -149,8 +178,16 @@ static void do_virtblk_request(struct restatic int virtblk_ioctl (struct block_device *bdev,fmode_t mode,unsigned cmd,unsigned long data) { -return scsi_cmd_ioctl (bdev->bd_disk->queue, - bdev->bd_disk, mode, cmd, +struct gendisk *disk = bdev->bd_disk; +struct virtio_blk *vblk = disk->private_data; + +/* +* Only allow the generic SCSI ioctls if the host can support it. +*/ +if (!virtio_has_feature (vblk->vdev,VIRTIO_BLK_F_SCSI )) +return -ENOIOCTLCMD ; + +return scsi_cmd_ioctl (disk->queue, disk, mode, cmd, (void __user *)data); }
@@ -356,6 +393,7 @@ static struct virtio_device_id id_table[static unsigned int features[] = {VIRTIO_BLK_F_BARRIER ,VIRTIO_BLK_F_SEG_MAX ,VIRTIO_BLK_F_SIZE_MAX ,VIRTIO_BLK_F_GEOMETRY ,VIRTIO_BLK_F_RO ,VIRTIO_BLK_F_BLK_SIZE , +VIRTIO_BLK_F_SCSI , };static struct virtio_driver virtio_blk = {
include/linux/virtio_blk.h +9 -0
@@ -15,6 +15,7 @@#define VIRTIO_BLK_F_GEOMETRY 4/* Legacy geometry available */ #define VIRTIO_BLK_F_RO 5/* Disk is read-only */ #define VIRTIO_BLK_F_BLK_SIZE 6/* Block size of disk is available*/ +#define VIRTIO_BLK_F_SCSI 7/* Supports scsi command passthru */ struct virtio_blk_config {
@@ -55,6 +56,14 @@ struct virtio_blk_outhdr__u64 sector; }; +struct virtio_scsi_inhdr +{ +__u32 errors; +__u32 data_len; +__u32 sense_len; +__u32 residual; +}; +/* And this is the final byte of the write scatter-gather list. */ #define VIRTIO_BLK_S_OK 0#define VIRTIO_BLK_S_IOERR 1
Am Monday 27 April 2009 10:21:21 schrieben Sie:
Quoted 8 lines
From: Hannes Reinecke <[email protected]>
Add support for
SG_IOpassthru tovirtio_blk. We add the scsi command block after the normal outhdr, and the scsi inhdr with full status information aswell as the sense buffer before the regular inhdr.[hch: forward ported, added the
VIRTIO_BLK_F_SCSIflags, some comments
and tested the whole beast]
I like the VIRTIO_BLK_F_SCSI flag - it avoids some problems we had with an earlier version. (I believe we found a solution, but this explicit check looks much more reliable)
I gave this patch a short test with the kuli loader (s390 userspace). You can consider the "VIRTIO_BLK_F_SCSI not available" case
Christian
Rusty Russell
AppliedQuoted 8 lines · Christoph Hellwig
From: Hannes Reinecke <[email protected]>
Add support for
SG_IOpassthru tovirtio_blk. We add the scsi command block after the normal outhdr, and the scsi inhdr with full status information aswell as the sense buffer before the regular inhdr.[hch: forward ported, added the
VIRTIO_BLK_F_SCSIflags, some comments
and tested the whole beast]
Thanks Christoph, it's really nice to get a patch which is well thought-out, thorough and intuitive.
Oh, and if you're bored, it'd be nice to have lguest support for at least ejecting a CDROM.
Applied,
Rusty.