diff options
-rw-r--r-- | drivers/block/virtio_blk.c | 64 | ||||
-rw-r--r-- | include/linux/virtio_blk.h | 8 |
2 files changed, 58 insertions, 14 deletions
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index dfe9ee5f1696..62275dbdf2eb 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c | |||
@@ -37,6 +37,7 @@ struct virtblk_req | |||
37 | struct list_head list; | 37 | struct list_head list; |
38 | struct request *req; | 38 | struct request *req; |
39 | struct virtio_blk_outhdr out_hdr; | 39 | struct virtio_blk_outhdr out_hdr; |
40 | struct virtio_scsi_inhdr in_hdr; | ||
40 | u8 status; | 41 | u8 status; |
41 | }; | 42 | }; |
42 | 43 | ||
@@ -49,7 +50,9 @@ static void blk_done(struct virtqueue *vq) | |||
49 | 50 | ||
50 | spin_lock_irqsave(&vblk->lock, flags); | 51 | spin_lock_irqsave(&vblk->lock, flags); |
51 | while ((vbr = vblk->vq->vq_ops->get_buf(vblk->vq, &len)) != NULL) { | 52 | while ((vbr = vblk->vq->vq_ops->get_buf(vblk->vq, &len)) != NULL) { |
53 | unsigned int nr_bytes; | ||
52 | int error; | 54 | int error; |
55 | |||
53 | switch (vbr->status) { | 56 | switch (vbr->status) { |
54 | case VIRTIO_BLK_S_OK: | 57 | case VIRTIO_BLK_S_OK: |
55 | error = 0; | 58 | error = 0; |
@@ -62,6 +65,12 @@ static void blk_done(struct virtqueue *vq) | |||
62 | break; | 65 | break; |
63 | } | 66 | } |
64 | 67 | ||
68 | if (blk_pc_request(vbr->req)) { | ||
69 | vbr->req->resid_len = vbr->in_hdr.residual; | ||
70 | vbr->req->sense_len = vbr->in_hdr.sense_len; | ||
71 | vbr->req->errors = vbr->in_hdr.errors; | ||
72 | } | ||
73 | |||
65 | __blk_end_request_all(vbr->req, error); | 74 | __blk_end_request_all(vbr->req, error); |
66 | list_del(&vbr->list); | 75 | list_del(&vbr->list); |
67 | mempool_free(vbr, vblk->pool); | 76 | mempool_free(vbr, vblk->pool); |
@@ -74,7 +83,7 @@ static void blk_done(struct virtqueue *vq) | |||
74 | static bool do_req(struct request_queue *q, struct virtio_blk *vblk, | 83 | static bool do_req(struct request_queue *q, struct virtio_blk *vblk, |
75 | struct request *req) | 84 | struct request *req) |
76 | { | 85 | { |
77 | unsigned long num, out, in; | 86 | unsigned long num, out = 0, in = 0; |
78 | struct virtblk_req *vbr; | 87 | struct virtblk_req *vbr; |
79 | 88 | ||
80 | vbr = mempool_alloc(vblk->pool, GFP_ATOMIC); | 89 | vbr = mempool_alloc(vblk->pool, GFP_ATOMIC); |
@@ -99,18 +108,36 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk, | |||
99 | if (blk_barrier_rq(vbr->req)) | 108 | if (blk_barrier_rq(vbr->req)) |
100 | vbr->out_hdr.type |= VIRTIO_BLK_T_BARRIER; | 109 | vbr->out_hdr.type |= VIRTIO_BLK_T_BARRIER; |
101 | 110 | ||
102 | sg_set_buf(&vblk->sg[0], &vbr->out_hdr, sizeof(vbr->out_hdr)); | 111 | sg_set_buf(&vblk->sg[out++], &vbr->out_hdr, sizeof(vbr->out_hdr)); |
103 | num = blk_rq_map_sg(q, vbr->req, vblk->sg+1); | ||
104 | sg_set_buf(&vblk->sg[num+1], &vbr->status, sizeof(vbr->status)); | ||
105 | 112 | ||
106 | if (rq_data_dir(vbr->req) == WRITE) { | 113 | /* |
107 | vbr->out_hdr.type |= VIRTIO_BLK_T_OUT; | 114 | * If this is a packet command we need a couple of additional headers. |
108 | out = 1 + num; | 115 | * Behind the normal outhdr we put a segment with the scsi command |
109 | in = 1; | 116 | * block, and before the normal inhdr we put the sense data and the |
110 | } else { | 117 | * inhdr with additional status information before the normal inhdr. |
111 | vbr->out_hdr.type |= VIRTIO_BLK_T_IN; | 118 | */ |
112 | out = 1; | 119 | if (blk_pc_request(vbr->req)) |
113 | in = 1 + num; | 120 | sg_set_buf(&vblk->sg[out++], vbr->req->cmd, vbr->req->cmd_len); |
121 | |||
122 | num = blk_rq_map_sg(q, vbr->req, vblk->sg + out); | ||
123 | |||
124 | if (blk_pc_request(vbr->req)) { | ||
125 | sg_set_buf(&vblk->sg[num + out + in++], vbr->req->sense, 96); | ||
126 | sg_set_buf(&vblk->sg[num + out + in++], &vbr->in_hdr, | ||
127 | sizeof(vbr->in_hdr)); | ||
128 | } | ||
129 | |||
130 | sg_set_buf(&vblk->sg[num + out + in++], &vbr->status, | ||
131 | sizeof(vbr->status)); | ||
132 | |||
133 | if (num) { | ||
134 | if (rq_data_dir(vbr->req) == WRITE) { | ||
135 | vbr->out_hdr.type |= VIRTIO_BLK_T_OUT; | ||
136 | out += num; | ||
137 | } else { | ||
138 | vbr->out_hdr.type |= VIRTIO_BLK_T_IN; | ||
139 | in += num; | ||
140 | } | ||
114 | } | 141 | } |
115 | 142 | ||
116 | if (vblk->vq->vq_ops->add_buf(vblk->vq, vblk->sg, out, in, vbr)) { | 143 | if (vblk->vq->vq_ops->add_buf(vblk->vq, vblk->sg, out, in, vbr)) { |
@@ -148,8 +175,16 @@ static void do_virtblk_request(struct request_queue *q) | |||
148 | static int virtblk_ioctl(struct block_device *bdev, fmode_t mode, | 175 | static int virtblk_ioctl(struct block_device *bdev, fmode_t mode, |
149 | unsigned cmd, unsigned long data) | 176 | unsigned cmd, unsigned long data) |
150 | { | 177 | { |
151 | return scsi_cmd_ioctl(bdev->bd_disk->queue, | 178 | struct gendisk *disk = bdev->bd_disk; |
152 | bdev->bd_disk, mode, cmd, | 179 | struct virtio_blk *vblk = disk->private_data; |
180 | |||
181 | /* | ||
182 | * Only allow the generic SCSI ioctls if the host can support it. | ||
183 | */ | ||
184 | if (!virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_SCSI)) | ||
185 | return -ENOIOCTLCMD; | ||
186 | |||
187 | return scsi_cmd_ioctl(disk->queue, disk, mode, cmd, | ||
153 | (void __user *)data); | 188 | (void __user *)data); |
154 | } | 189 | } |
155 | 190 | ||
@@ -356,6 +391,7 @@ static struct virtio_device_id id_table[] = { | |||
356 | static unsigned int features[] = { | 391 | static unsigned int features[] = { |
357 | VIRTIO_BLK_F_BARRIER, VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, | 392 | VIRTIO_BLK_F_BARRIER, VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, |
358 | VIRTIO_BLK_F_GEOMETRY, VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE, | 393 | VIRTIO_BLK_F_GEOMETRY, VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE, |
394 | VIRTIO_BLK_F_SCSI, | ||
359 | }; | 395 | }; |
360 | 396 | ||
361 | static struct virtio_driver virtio_blk = { | 397 | static struct virtio_driver virtio_blk = { |
diff --git a/include/linux/virtio_blk.h b/include/linux/virtio_blk.h index 94c56d29869d..4dbcbc1c3481 100644 --- a/include/linux/virtio_blk.h +++ b/include/linux/virtio_blk.h | |||
@@ -15,6 +15,7 @@ | |||
15 | #define VIRTIO_BLK_F_GEOMETRY 4 /* Legacy geometry available */ | 15 | #define VIRTIO_BLK_F_GEOMETRY 4 /* Legacy geometry available */ |
16 | #define VIRTIO_BLK_F_RO 5 /* Disk is read-only */ | 16 | #define VIRTIO_BLK_F_RO 5 /* Disk is read-only */ |
17 | #define VIRTIO_BLK_F_BLK_SIZE 6 /* Block size of disk is available*/ | 17 | #define VIRTIO_BLK_F_BLK_SIZE 6 /* Block size of disk is available*/ |
18 | #define VIRTIO_BLK_F_SCSI 7 /* Supports scsi command passthru */ | ||
18 | 19 | ||
19 | struct virtio_blk_config | 20 | struct virtio_blk_config |
20 | { | 21 | { |
@@ -55,6 +56,13 @@ struct virtio_blk_outhdr | |||
55 | __u64 sector; | 56 | __u64 sector; |
56 | }; | 57 | }; |
57 | 58 | ||
59 | struct virtio_scsi_inhdr { | ||
60 | __u32 errors; | ||
61 | __u32 data_len; | ||
62 | __u32 sense_len; | ||
63 | __u32 residual; | ||
64 | }; | ||
65 | |||
58 | /* And this is the final byte of the write scatter-gather list. */ | 66 | /* And this is the final byte of the write scatter-gather list. */ |
59 | #define VIRTIO_BLK_S_OK 0 | 67 | #define VIRTIO_BLK_S_OK 0 |
60 | #define VIRTIO_BLK_S_IOERR 1 | 68 | #define VIRTIO_BLK_S_IOERR 1 |