aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/block/virtio_blk.c64
-rw-r--r--include/linux/virtio_blk.h8
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)
74static bool do_req(struct request_queue *q, struct virtio_blk *vblk, 83static 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)
148static int virtblk_ioctl(struct block_device *bdev, fmode_t mode, 175static 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[] = {
356static unsigned int features[] = { 391static 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
361static struct virtio_driver virtio_blk = { 397static 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
19struct virtio_blk_config 20struct virtio_blk_config
20{ 21{
@@ -55,6 +56,13 @@ struct virtio_blk_outhdr
55 __u64 sector; 56 __u64 sector;
56}; 57};
57 58
59struct 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