.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | //#define DEBUG |
---|
2 | 3 | #include <linux/spinlock.h> |
---|
3 | 4 | #include <linux/slab.h> |
---|
.. | .. |
---|
10 | 11 | #include <linux/virtio_blk.h> |
---|
11 | 12 | #include <linux/scatterlist.h> |
---|
12 | 13 | #include <linux/string_helpers.h> |
---|
13 | | -#include <scsi/scsi_cmnd.h> |
---|
14 | 14 | #include <linux/idr.h> |
---|
15 | 15 | #include <linux/blk-mq.h> |
---|
16 | 16 | #include <linux/blk-mq-virtio.h> |
---|
17 | 17 | #include <linux/numa.h> |
---|
| 18 | +#include <uapi/linux/virtio_ring.h> |
---|
18 | 19 | |
---|
19 | 20 | #define PART_BITS 4 |
---|
20 | 21 | #define VQ_NAME_LEN 16 |
---|
| 22 | +#define MAX_DISCARD_SEGMENTS 256u |
---|
21 | 23 | |
---|
22 | 24 | static int major; |
---|
23 | 25 | static DEFINE_IDA(vd_index_ida); |
---|
.. | .. |
---|
70 | 72 | }; |
---|
71 | 73 | |
---|
72 | 74 | struct virtblk_req { |
---|
73 | | -#ifdef CONFIG_VIRTIO_BLK_SCSI |
---|
74 | | - struct scsi_request sreq; /* for SCSI passthrough, must be first */ |
---|
75 | | - u8 sense[SCSI_SENSE_BUFFERSIZE]; |
---|
76 | | - struct virtio_scsi_inhdr in_hdr; |
---|
77 | | -#endif |
---|
78 | 75 | struct virtio_blk_outhdr out_hdr; |
---|
79 | 76 | u8 status; |
---|
80 | 77 | struct scatterlist sg[]; |
---|
.. | .. |
---|
91 | 88 | return BLK_STS_IOERR; |
---|
92 | 89 | } |
---|
93 | 90 | } |
---|
94 | | - |
---|
95 | | -/* |
---|
96 | | - * If this is a packet command we need a couple of additional headers. Behind |
---|
97 | | - * the normal outhdr we put a segment with the scsi command block, and before |
---|
98 | | - * the normal inhdr we put the sense data and the inhdr with additional status |
---|
99 | | - * information. |
---|
100 | | - */ |
---|
101 | | -#ifdef CONFIG_VIRTIO_BLK_SCSI |
---|
102 | | -static int virtblk_add_req_scsi(struct virtqueue *vq, struct virtblk_req *vbr, |
---|
103 | | - struct scatterlist *data_sg, bool have_data) |
---|
104 | | -{ |
---|
105 | | - struct scatterlist hdr, status, cmd, sense, inhdr, *sgs[6]; |
---|
106 | | - unsigned int num_out = 0, num_in = 0; |
---|
107 | | - |
---|
108 | | - sg_init_one(&hdr, &vbr->out_hdr, sizeof(vbr->out_hdr)); |
---|
109 | | - sgs[num_out++] = &hdr; |
---|
110 | | - sg_init_one(&cmd, vbr->sreq.cmd, vbr->sreq.cmd_len); |
---|
111 | | - sgs[num_out++] = &cmd; |
---|
112 | | - |
---|
113 | | - if (have_data) { |
---|
114 | | - if (vbr->out_hdr.type & cpu_to_virtio32(vq->vdev, VIRTIO_BLK_T_OUT)) |
---|
115 | | - sgs[num_out++] = data_sg; |
---|
116 | | - else |
---|
117 | | - sgs[num_out + num_in++] = data_sg; |
---|
118 | | - } |
---|
119 | | - |
---|
120 | | - sg_init_one(&sense, vbr->sense, SCSI_SENSE_BUFFERSIZE); |
---|
121 | | - sgs[num_out + num_in++] = &sense; |
---|
122 | | - sg_init_one(&inhdr, &vbr->in_hdr, sizeof(vbr->in_hdr)); |
---|
123 | | - sgs[num_out + num_in++] = &inhdr; |
---|
124 | | - sg_init_one(&status, &vbr->status, sizeof(vbr->status)); |
---|
125 | | - sgs[num_out + num_in++] = &status; |
---|
126 | | - |
---|
127 | | - return virtqueue_add_sgs(vq, sgs, num_out, num_in, vbr, GFP_ATOMIC); |
---|
128 | | -} |
---|
129 | | - |
---|
130 | | -static inline void virtblk_scsi_request_done(struct request *req) |
---|
131 | | -{ |
---|
132 | | - struct virtblk_req *vbr = blk_mq_rq_to_pdu(req); |
---|
133 | | - struct virtio_blk *vblk = req->q->queuedata; |
---|
134 | | - struct scsi_request *sreq = &vbr->sreq; |
---|
135 | | - |
---|
136 | | - sreq->resid_len = virtio32_to_cpu(vblk->vdev, vbr->in_hdr.residual); |
---|
137 | | - sreq->sense_len = virtio32_to_cpu(vblk->vdev, vbr->in_hdr.sense_len); |
---|
138 | | - sreq->result = virtio32_to_cpu(vblk->vdev, vbr->in_hdr.errors); |
---|
139 | | -} |
---|
140 | | - |
---|
141 | | -static int virtblk_ioctl(struct block_device *bdev, fmode_t mode, |
---|
142 | | - unsigned int cmd, unsigned long data) |
---|
143 | | -{ |
---|
144 | | - struct gendisk *disk = bdev->bd_disk; |
---|
145 | | - struct virtio_blk *vblk = disk->private_data; |
---|
146 | | - |
---|
147 | | - /* |
---|
148 | | - * Only allow the generic SCSI ioctls if the host can support it. |
---|
149 | | - */ |
---|
150 | | - if (!virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_SCSI)) |
---|
151 | | - return -ENOTTY; |
---|
152 | | - |
---|
153 | | - return scsi_cmd_blk_ioctl(bdev, mode, cmd, |
---|
154 | | - (void __user *)data); |
---|
155 | | -} |
---|
156 | | -#else |
---|
157 | | -static inline int virtblk_add_req_scsi(struct virtqueue *vq, |
---|
158 | | - struct virtblk_req *vbr, struct scatterlist *data_sg, |
---|
159 | | - bool have_data) |
---|
160 | | -{ |
---|
161 | | - return -EIO; |
---|
162 | | -} |
---|
163 | | -static inline void virtblk_scsi_request_done(struct request *req) |
---|
164 | | -{ |
---|
165 | | -} |
---|
166 | | -#define virtblk_ioctl NULL |
---|
167 | | -#endif /* CONFIG_VIRTIO_BLK_SCSI */ |
---|
168 | 91 | |
---|
169 | 92 | static int virtblk_add_req(struct virtqueue *vq, struct virtblk_req *vbr, |
---|
170 | 93 | struct scatterlist *data_sg, bool have_data) |
---|
.. | .. |
---|
188 | 111 | return virtqueue_add_sgs(vq, sgs, num_out, num_in, vbr, GFP_ATOMIC); |
---|
189 | 112 | } |
---|
190 | 113 | |
---|
| 114 | +static int virtblk_setup_discard_write_zeroes(struct request *req, bool unmap) |
---|
| 115 | +{ |
---|
| 116 | + unsigned short segments = blk_rq_nr_discard_segments(req); |
---|
| 117 | + unsigned short n = 0; |
---|
| 118 | + struct virtio_blk_discard_write_zeroes *range; |
---|
| 119 | + struct bio *bio; |
---|
| 120 | + u32 flags = 0; |
---|
| 121 | + |
---|
| 122 | + if (unmap) |
---|
| 123 | + flags |= VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP; |
---|
| 124 | + |
---|
| 125 | + range = kmalloc_array(segments, sizeof(*range), GFP_ATOMIC); |
---|
| 126 | + if (!range) |
---|
| 127 | + return -ENOMEM; |
---|
| 128 | + |
---|
| 129 | + /* |
---|
| 130 | + * Single max discard segment means multi-range discard isn't |
---|
| 131 | + * supported, and block layer only runs contiguity merge like |
---|
| 132 | + * normal RW request. So we can't reply on bio for retrieving |
---|
| 133 | + * each range info. |
---|
| 134 | + */ |
---|
| 135 | + if (queue_max_discard_segments(req->q) == 1) { |
---|
| 136 | + range[0].flags = cpu_to_le32(flags); |
---|
| 137 | + range[0].num_sectors = cpu_to_le32(blk_rq_sectors(req)); |
---|
| 138 | + range[0].sector = cpu_to_le64(blk_rq_pos(req)); |
---|
| 139 | + n = 1; |
---|
| 140 | + } else { |
---|
| 141 | + __rq_for_each_bio(bio, req) { |
---|
| 142 | + u64 sector = bio->bi_iter.bi_sector; |
---|
| 143 | + u32 num_sectors = bio->bi_iter.bi_size >> SECTOR_SHIFT; |
---|
| 144 | + |
---|
| 145 | + range[n].flags = cpu_to_le32(flags); |
---|
| 146 | + range[n].num_sectors = cpu_to_le32(num_sectors); |
---|
| 147 | + range[n].sector = cpu_to_le64(sector); |
---|
| 148 | + n++; |
---|
| 149 | + } |
---|
| 150 | + } |
---|
| 151 | + |
---|
| 152 | + WARN_ON_ONCE(n != segments); |
---|
| 153 | + |
---|
| 154 | + req->special_vec.bv_page = virt_to_page(range); |
---|
| 155 | + req->special_vec.bv_offset = offset_in_page(range); |
---|
| 156 | + req->special_vec.bv_len = sizeof(*range) * segments; |
---|
| 157 | + req->rq_flags |= RQF_SPECIAL_PAYLOAD; |
---|
| 158 | + |
---|
| 159 | + return 0; |
---|
| 160 | +} |
---|
| 161 | + |
---|
191 | 162 | static inline void virtblk_request_done(struct request *req) |
---|
192 | 163 | { |
---|
193 | 164 | struct virtblk_req *vbr = blk_mq_rq_to_pdu(req); |
---|
194 | 165 | |
---|
195 | | - switch (req_op(req)) { |
---|
196 | | - case REQ_OP_SCSI_IN: |
---|
197 | | - case REQ_OP_SCSI_OUT: |
---|
198 | | - virtblk_scsi_request_done(req); |
---|
199 | | - break; |
---|
| 166 | + if (req->rq_flags & RQF_SPECIAL_PAYLOAD) { |
---|
| 167 | + kfree(page_address(req->special_vec.bv_page) + |
---|
| 168 | + req->special_vec.bv_offset); |
---|
200 | 169 | } |
---|
201 | 170 | |
---|
202 | 171 | blk_mq_end_request(req, virtblk_result(vbr)); |
---|
.. | .. |
---|
217 | 186 | while ((vbr = virtqueue_get_buf(vblk->vqs[qid].vq, &len)) != NULL) { |
---|
218 | 187 | struct request *req = blk_mq_rq_from_pdu(vbr); |
---|
219 | 188 | |
---|
220 | | - blk_mq_complete_request(req); |
---|
| 189 | + if (likely(!blk_should_fake_timeout(req->q))) |
---|
| 190 | + blk_mq_complete_request(req); |
---|
221 | 191 | req_done = true; |
---|
222 | 192 | } |
---|
223 | 193 | if (unlikely(virtqueue_is_broken(vq))) |
---|
.. | .. |
---|
228 | 198 | if (req_done) |
---|
229 | 199 | blk_mq_start_stopped_hw_queues(vblk->disk->queue, true); |
---|
230 | 200 | spin_unlock_irqrestore(&vblk->vqs[qid].lock, flags); |
---|
| 201 | +} |
---|
| 202 | + |
---|
| 203 | +static void virtio_commit_rqs(struct blk_mq_hw_ctx *hctx) |
---|
| 204 | +{ |
---|
| 205 | + struct virtio_blk *vblk = hctx->queue->queuedata; |
---|
| 206 | + struct virtio_blk_vq *vq = &vblk->vqs[hctx->queue_num]; |
---|
| 207 | + bool kick; |
---|
| 208 | + |
---|
| 209 | + spin_lock_irq(&vq->lock); |
---|
| 210 | + kick = virtqueue_kick_prepare(vq->vq); |
---|
| 211 | + spin_unlock_irq(&vq->lock); |
---|
| 212 | + |
---|
| 213 | + if (kick) |
---|
| 214 | + virtqueue_notify(vq->vq); |
---|
231 | 215 | } |
---|
232 | 216 | |
---|
233 | 217 | static blk_status_t virtio_queue_rq(struct blk_mq_hw_ctx *hctx, |
---|
.. | .. |
---|
241 | 225 | int qid = hctx->queue_num; |
---|
242 | 226 | int err; |
---|
243 | 227 | bool notify = false; |
---|
| 228 | + bool unmap = false; |
---|
244 | 229 | u32 type; |
---|
245 | | - |
---|
246 | | - BUG_ON(req->nr_phys_segments + 2 > vblk->sg_elems); |
---|
247 | 230 | |
---|
248 | 231 | switch (req_op(req)) { |
---|
249 | 232 | case REQ_OP_READ: |
---|
.. | .. |
---|
253 | 236 | case REQ_OP_FLUSH: |
---|
254 | 237 | type = VIRTIO_BLK_T_FLUSH; |
---|
255 | 238 | break; |
---|
256 | | - case REQ_OP_SCSI_IN: |
---|
257 | | - case REQ_OP_SCSI_OUT: |
---|
258 | | - type = VIRTIO_BLK_T_SCSI_CMD; |
---|
| 239 | + case REQ_OP_DISCARD: |
---|
| 240 | + type = VIRTIO_BLK_T_DISCARD; |
---|
| 241 | + break; |
---|
| 242 | + case REQ_OP_WRITE_ZEROES: |
---|
| 243 | + type = VIRTIO_BLK_T_WRITE_ZEROES; |
---|
| 244 | + unmap = !(req->cmd_flags & REQ_NOUNMAP); |
---|
259 | 245 | break; |
---|
260 | 246 | case REQ_OP_DRV_IN: |
---|
261 | 247 | type = VIRTIO_BLK_T_GET_ID; |
---|
.. | .. |
---|
265 | 251 | return BLK_STS_IOERR; |
---|
266 | 252 | } |
---|
267 | 253 | |
---|
| 254 | + BUG_ON(type != VIRTIO_BLK_T_DISCARD && |
---|
| 255 | + type != VIRTIO_BLK_T_WRITE_ZEROES && |
---|
| 256 | + (req->nr_phys_segments + 2 > vblk->sg_elems)); |
---|
| 257 | + |
---|
268 | 258 | vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, type); |
---|
269 | 259 | vbr->out_hdr.sector = type ? |
---|
270 | 260 | 0 : cpu_to_virtio64(vblk->vdev, blk_rq_pos(req)); |
---|
271 | 261 | vbr->out_hdr.ioprio = cpu_to_virtio32(vblk->vdev, req_get_ioprio(req)); |
---|
272 | 262 | |
---|
273 | 263 | blk_mq_start_request(req); |
---|
| 264 | + |
---|
| 265 | + if (type == VIRTIO_BLK_T_DISCARD || type == VIRTIO_BLK_T_WRITE_ZEROES) { |
---|
| 266 | + err = virtblk_setup_discard_write_zeroes(req, unmap); |
---|
| 267 | + if (err) |
---|
| 268 | + return BLK_STS_RESOURCE; |
---|
| 269 | + } |
---|
274 | 270 | |
---|
275 | 271 | num = blk_rq_map_sg(hctx->queue, req, vbr->sg); |
---|
276 | 272 | if (num) { |
---|
.. | .. |
---|
281 | 277 | } |
---|
282 | 278 | |
---|
283 | 279 | spin_lock_irqsave(&vblk->vqs[qid].lock, flags); |
---|
284 | | - if (blk_rq_is_scsi(req)) |
---|
285 | | - err = virtblk_add_req_scsi(vblk->vqs[qid].vq, vbr, vbr->sg, num); |
---|
286 | | - else |
---|
287 | | - err = virtblk_add_req(vblk->vqs[qid].vq, vbr, vbr->sg, num); |
---|
| 280 | + err = virtblk_add_req(vblk->vqs[qid].vq, vbr, vbr->sg, num); |
---|
288 | 281 | if (err) { |
---|
289 | 282 | virtqueue_kick(vblk->vqs[qid].vq); |
---|
290 | 283 | /* Don't stop the queue if -ENOMEM: we may have failed to |
---|
.. | .. |
---|
406 | 399 | } |
---|
407 | 400 | |
---|
408 | 401 | static const struct block_device_operations virtblk_fops = { |
---|
409 | | - .ioctl = virtblk_ioctl, |
---|
410 | 402 | .owner = THIS_MODULE, |
---|
411 | 403 | .open = virtblk_open, |
---|
412 | 404 | .release = virtblk_release, |
---|
.. | .. |
---|
423 | 415 | return minor >> PART_BITS; |
---|
424 | 416 | } |
---|
425 | 417 | |
---|
426 | | -static ssize_t virtblk_serial_show(struct device *dev, |
---|
427 | | - struct device_attribute *attr, char *buf) |
---|
| 418 | +static ssize_t serial_show(struct device *dev, |
---|
| 419 | + struct device_attribute *attr, char *buf) |
---|
428 | 420 | { |
---|
429 | 421 | struct gendisk *disk = dev_to_disk(dev); |
---|
430 | 422 | int err; |
---|
.. | .. |
---|
443 | 435 | return err; |
---|
444 | 436 | } |
---|
445 | 437 | |
---|
446 | | -static DEVICE_ATTR(serial, 0444, virtblk_serial_show, NULL); |
---|
| 438 | +static DEVICE_ATTR_RO(serial); |
---|
447 | 439 | |
---|
448 | 440 | /* The queue's logical block size must be set before calling this */ |
---|
449 | 441 | static void virtblk_update_capacity(struct virtio_blk *vblk, bool resize) |
---|
.. | .. |
---|
480 | 472 | cap_str_10, |
---|
481 | 473 | cap_str_2); |
---|
482 | 474 | |
---|
483 | | - set_capacity(vblk->disk, capacity); |
---|
| 475 | + set_capacity_revalidate_and_notify(vblk->disk, capacity, true); |
---|
484 | 476 | } |
---|
485 | 477 | |
---|
486 | 478 | static void virtblk_config_changed_work(struct work_struct *work) |
---|
487 | 479 | { |
---|
488 | 480 | struct virtio_blk *vblk = |
---|
489 | 481 | container_of(work, struct virtio_blk, config_work); |
---|
490 | | - char *envp[] = { "RESIZE=1", NULL }; |
---|
491 | 482 | |
---|
492 | 483 | virtblk_update_capacity(vblk, true); |
---|
493 | | - revalidate_disk(vblk->disk); |
---|
494 | | - kobject_uevent_env(&disk_to_dev(vblk->disk)->kobj, KOBJ_CHANGE, envp); |
---|
495 | 484 | } |
---|
496 | 485 | |
---|
497 | 486 | static void virtblk_config_changed(struct virtio_device *vdev) |
---|
.. | .. |
---|
611 | 600 | struct virtio_blk *vblk = vdev->priv; |
---|
612 | 601 | |
---|
613 | 602 | blk_queue_write_cache(vblk->disk->queue, writeback, false); |
---|
614 | | - revalidate_disk(vblk->disk); |
---|
| 603 | + revalidate_disk_size(vblk->disk, true); |
---|
615 | 604 | } |
---|
616 | 605 | |
---|
617 | 606 | static const char *const virtblk_cache_types[] = { |
---|
.. | .. |
---|
619 | 608 | }; |
---|
620 | 609 | |
---|
621 | 610 | static ssize_t |
---|
622 | | -virtblk_cache_type_store(struct device *dev, struct device_attribute *attr, |
---|
623 | | - const char *buf, size_t count) |
---|
| 611 | +cache_type_store(struct device *dev, struct device_attribute *attr, |
---|
| 612 | + const char *buf, size_t count) |
---|
624 | 613 | { |
---|
625 | 614 | struct gendisk *disk = dev_to_disk(dev); |
---|
626 | 615 | struct virtio_blk *vblk = disk->private_data; |
---|
.. | .. |
---|
638 | 627 | } |
---|
639 | 628 | |
---|
640 | 629 | static ssize_t |
---|
641 | | -virtblk_cache_type_show(struct device *dev, struct device_attribute *attr, |
---|
642 | | - char *buf) |
---|
| 630 | +cache_type_show(struct device *dev, struct device_attribute *attr, char *buf) |
---|
643 | 631 | { |
---|
644 | 632 | struct gendisk *disk = dev_to_disk(dev); |
---|
645 | 633 | struct virtio_blk *vblk = disk->private_data; |
---|
.. | .. |
---|
649 | 637 | return snprintf(buf, 40, "%s\n", virtblk_cache_types[writeback]); |
---|
650 | 638 | } |
---|
651 | 639 | |
---|
652 | | -static const struct device_attribute dev_attr_cache_type_ro = |
---|
653 | | - __ATTR(cache_type, 0444, |
---|
654 | | - virtblk_cache_type_show, NULL); |
---|
655 | | -static const struct device_attribute dev_attr_cache_type_rw = |
---|
656 | | - __ATTR(cache_type, 0644, |
---|
657 | | - virtblk_cache_type_show, virtblk_cache_type_store); |
---|
| 640 | +static DEVICE_ATTR_RW(cache_type); |
---|
| 641 | + |
---|
| 642 | +static struct attribute *virtblk_attrs[] = { |
---|
| 643 | + &dev_attr_serial.attr, |
---|
| 644 | + &dev_attr_cache_type.attr, |
---|
| 645 | + NULL, |
---|
| 646 | +}; |
---|
| 647 | + |
---|
| 648 | +static umode_t virtblk_attrs_are_visible(struct kobject *kobj, |
---|
| 649 | + struct attribute *a, int n) |
---|
| 650 | +{ |
---|
| 651 | + struct device *dev = kobj_to_dev(kobj); |
---|
| 652 | + struct gendisk *disk = dev_to_disk(dev); |
---|
| 653 | + struct virtio_blk *vblk = disk->private_data; |
---|
| 654 | + struct virtio_device *vdev = vblk->vdev; |
---|
| 655 | + |
---|
| 656 | + if (a == &dev_attr_cache_type.attr && |
---|
| 657 | + !virtio_has_feature(vdev, VIRTIO_BLK_F_CONFIG_WCE)) |
---|
| 658 | + return S_IRUGO; |
---|
| 659 | + |
---|
| 660 | + return a->mode; |
---|
| 661 | +} |
---|
| 662 | + |
---|
| 663 | +static const struct attribute_group virtblk_attr_group = { |
---|
| 664 | + .attrs = virtblk_attrs, |
---|
| 665 | + .is_visible = virtblk_attrs_are_visible, |
---|
| 666 | +}; |
---|
| 667 | + |
---|
| 668 | +static const struct attribute_group *virtblk_attr_groups[] = { |
---|
| 669 | + &virtblk_attr_group, |
---|
| 670 | + NULL, |
---|
| 671 | +}; |
---|
658 | 672 | |
---|
659 | 673 | static int virtblk_init_request(struct blk_mq_tag_set *set, struct request *rq, |
---|
660 | 674 | unsigned int hctx_idx, unsigned int numa_node) |
---|
.. | .. |
---|
662 | 676 | struct virtio_blk *vblk = set->driver_data; |
---|
663 | 677 | struct virtblk_req *vbr = blk_mq_rq_to_pdu(rq); |
---|
664 | 678 | |
---|
665 | | -#ifdef CONFIG_VIRTIO_BLK_SCSI |
---|
666 | | - vbr->sreq.sense = vbr->sense; |
---|
667 | | -#endif |
---|
668 | 679 | sg_init_table(vbr->sg, vblk->sg_elems); |
---|
669 | 680 | return 0; |
---|
670 | 681 | } |
---|
.. | .. |
---|
673 | 684 | { |
---|
674 | 685 | struct virtio_blk *vblk = set->driver_data; |
---|
675 | 686 | |
---|
676 | | - return blk_mq_virtio_map_queues(set, vblk->vdev, 0); |
---|
| 687 | + return blk_mq_virtio_map_queues(&set->map[HCTX_TYPE_DEFAULT], |
---|
| 688 | + vblk->vdev, 0); |
---|
677 | 689 | } |
---|
678 | | - |
---|
679 | | -#ifdef CONFIG_VIRTIO_BLK_SCSI |
---|
680 | | -static void virtblk_initialize_rq(struct request *req) |
---|
681 | | -{ |
---|
682 | | - struct virtblk_req *vbr = blk_mq_rq_to_pdu(req); |
---|
683 | | - |
---|
684 | | - scsi_req_init(&vbr->sreq); |
---|
685 | | -} |
---|
686 | | -#endif |
---|
687 | 690 | |
---|
688 | 691 | static const struct blk_mq_ops virtio_mq_ops = { |
---|
689 | 692 | .queue_rq = virtio_queue_rq, |
---|
| 693 | + .commit_rqs = virtio_commit_rqs, |
---|
690 | 694 | .complete = virtblk_request_done, |
---|
691 | 695 | .init_request = virtblk_init_request, |
---|
692 | | -#ifdef CONFIG_VIRTIO_BLK_SCSI |
---|
693 | | - .initialize_rq_fn = virtblk_initialize_rq, |
---|
694 | | -#endif |
---|
695 | 696 | .map_queues = virtblk_map_queues, |
---|
696 | 697 | }; |
---|
697 | 698 | |
---|
.. | .. |
---|
704 | 705 | struct request_queue *q; |
---|
705 | 706 | int err, index; |
---|
706 | 707 | |
---|
707 | | - u32 v, blk_size, sg_elems, opt_io_size; |
---|
| 708 | + u32 v, blk_size, max_size, sg_elems, opt_io_size; |
---|
708 | 709 | u16 min_io_size; |
---|
709 | 710 | u8 physical_block_exp, alignment_offset; |
---|
710 | 711 | |
---|
.. | .. |
---|
811 | 812 | /* No real sector limit. */ |
---|
812 | 813 | blk_queue_max_hw_sectors(q, -1U); |
---|
813 | 814 | |
---|
| 815 | + max_size = virtio_max_dma_size(vdev); |
---|
| 816 | + |
---|
814 | 817 | /* Host can optionally specify maximum segment size and number of |
---|
815 | 818 | * segments. */ |
---|
816 | 819 | err = virtio_cread_feature(vdev, VIRTIO_BLK_F_SIZE_MAX, |
---|
817 | 820 | struct virtio_blk_config, size_max, &v); |
---|
818 | 821 | if (!err) |
---|
819 | | - blk_queue_max_segment_size(q, v); |
---|
820 | | - else |
---|
821 | | - blk_queue_max_segment_size(q, -1U); |
---|
| 822 | + max_size = min(max_size, v); |
---|
| 823 | + |
---|
| 824 | + blk_queue_max_segment_size(q, max_size); |
---|
822 | 825 | |
---|
823 | 826 | /* Host can optionally specify the block size of the device */ |
---|
824 | 827 | err = virtio_cread_feature(vdev, VIRTIO_BLK_F_BLK_SIZE, |
---|
825 | 828 | struct virtio_blk_config, blk_size, |
---|
826 | 829 | &blk_size); |
---|
827 | | - if (!err) |
---|
| 830 | + if (!err) { |
---|
| 831 | + err = blk_validate_block_size(blk_size); |
---|
| 832 | + if (err) { |
---|
| 833 | + dev_err(&vdev->dev, |
---|
| 834 | + "virtio_blk: invalid block size: 0x%x\n", |
---|
| 835 | + blk_size); |
---|
| 836 | + goto out_cleanup_disk; |
---|
| 837 | + } |
---|
| 838 | + |
---|
828 | 839 | blk_queue_logical_block_size(q, blk_size); |
---|
829 | | - else |
---|
| 840 | + } else |
---|
830 | 841 | blk_size = queue_logical_block_size(q); |
---|
831 | 842 | |
---|
832 | 843 | /* Use topology information if available */ |
---|
.. | .. |
---|
855 | 866 | if (!err && opt_io_size) |
---|
856 | 867 | blk_queue_io_opt(q, blk_size * opt_io_size); |
---|
857 | 868 | |
---|
| 869 | + if (virtio_has_feature(vdev, VIRTIO_BLK_F_DISCARD)) { |
---|
| 870 | + virtio_cread(vdev, struct virtio_blk_config, |
---|
| 871 | + discard_sector_alignment, &v); |
---|
| 872 | + if (v) |
---|
| 873 | + q->limits.discard_granularity = v << SECTOR_SHIFT; |
---|
| 874 | + else |
---|
| 875 | + q->limits.discard_granularity = blk_size; |
---|
| 876 | + |
---|
| 877 | + virtio_cread(vdev, struct virtio_blk_config, |
---|
| 878 | + max_discard_sectors, &v); |
---|
| 879 | + blk_queue_max_discard_sectors(q, v ? v : UINT_MAX); |
---|
| 880 | + |
---|
| 881 | + virtio_cread(vdev, struct virtio_blk_config, max_discard_seg, |
---|
| 882 | + &v); |
---|
| 883 | + |
---|
| 884 | + /* |
---|
| 885 | + * max_discard_seg == 0 is out of spec but we always |
---|
| 886 | + * handled it. |
---|
| 887 | + */ |
---|
| 888 | + if (!v) |
---|
| 889 | + v = sg_elems - 2; |
---|
| 890 | + blk_queue_max_discard_segments(q, |
---|
| 891 | + min(v, MAX_DISCARD_SEGMENTS)); |
---|
| 892 | + |
---|
| 893 | + blk_queue_flag_set(QUEUE_FLAG_DISCARD, q); |
---|
| 894 | + } |
---|
| 895 | + |
---|
| 896 | + if (virtio_has_feature(vdev, VIRTIO_BLK_F_WRITE_ZEROES)) { |
---|
| 897 | + virtio_cread(vdev, struct virtio_blk_config, |
---|
| 898 | + max_write_zeroes_sectors, &v); |
---|
| 899 | + blk_queue_max_write_zeroes_sectors(q, v ? v : UINT_MAX); |
---|
| 900 | + } |
---|
| 901 | + |
---|
858 | 902 | virtblk_update_capacity(vblk, false); |
---|
859 | 903 | virtio_device_ready(vdev); |
---|
860 | 904 | |
---|
861 | | - device_add_disk(&vdev->dev, vblk->disk); |
---|
862 | | - err = device_create_file(disk_to_dev(vblk->disk), &dev_attr_serial); |
---|
863 | | - if (err) |
---|
864 | | - goto out_del_disk; |
---|
865 | | - |
---|
866 | | - if (virtio_has_feature(vdev, VIRTIO_BLK_F_CONFIG_WCE)) |
---|
867 | | - err = device_create_file(disk_to_dev(vblk->disk), |
---|
868 | | - &dev_attr_cache_type_rw); |
---|
869 | | - else |
---|
870 | | - err = device_create_file(disk_to_dev(vblk->disk), |
---|
871 | | - &dev_attr_cache_type_ro); |
---|
872 | | - if (err) |
---|
873 | | - goto out_del_disk; |
---|
| 905 | + device_add_disk(&vdev->dev, vblk->disk, virtblk_attr_groups); |
---|
874 | 906 | return 0; |
---|
875 | 907 | |
---|
876 | | -out_del_disk: |
---|
877 | | - del_gendisk(vblk->disk); |
---|
| 908 | +out_cleanup_disk: |
---|
878 | 909 | blk_cleanup_queue(vblk->disk->queue); |
---|
879 | 910 | out_free_tags: |
---|
880 | 911 | blk_mq_free_tag_set(&vblk->tag_set); |
---|
.. | .. |
---|
963 | 994 | static unsigned int features_legacy[] = { |
---|
964 | 995 | VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, VIRTIO_BLK_F_GEOMETRY, |
---|
965 | 996 | VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE, |
---|
966 | | -#ifdef CONFIG_VIRTIO_BLK_SCSI |
---|
967 | | - VIRTIO_BLK_F_SCSI, |
---|
968 | | -#endif |
---|
969 | 997 | VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_CONFIG_WCE, |
---|
970 | | - VIRTIO_BLK_F_MQ, |
---|
| 998 | + VIRTIO_BLK_F_MQ, VIRTIO_BLK_F_DISCARD, VIRTIO_BLK_F_WRITE_ZEROES, |
---|
971 | 999 | } |
---|
972 | 1000 | ; |
---|
973 | 1001 | static unsigned int features[] = { |
---|
974 | 1002 | VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, VIRTIO_BLK_F_GEOMETRY, |
---|
975 | 1003 | VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE, |
---|
976 | 1004 | VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_CONFIG_WCE, |
---|
977 | | - VIRTIO_BLK_F_MQ, |
---|
| 1005 | + VIRTIO_BLK_F_MQ, VIRTIO_BLK_F_DISCARD, VIRTIO_BLK_F_WRITE_ZEROES, |
---|
978 | 1006 | }; |
---|
979 | 1007 | |
---|
980 | 1008 | static struct virtio_driver virtio_blk = { |
---|