Blame view

drivers/block/virtio_blk.c 25.9 KB
09c434b8a   Thomas Gleixner   treewide: Add SPD...
1
  // SPDX-License-Identifier: GPL-2.0-only
e467cde23   Rusty Russell   Block driver usin...
2
3
  //#define DEBUG
  #include <linux/spinlock.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
4
  #include <linux/slab.h>
e467cde23   Rusty Russell   Block driver usin...
5
6
  #include <linux/blkdev.h>
  #include <linux/hdreg.h>
0c8d44f23   Paul Gortmaker   block: Fix files ...
7
  #include <linux/module.h>
4678d6f97   Michael S. Tsirkin   virtio_blk: fix c...
8
  #include <linux/mutex.h>
ad71473d9   Christoph Hellwig   virtio_blk: use v...
9
  #include <linux/interrupt.h>
e467cde23   Rusty Russell   Block driver usin...
10
11
  #include <linux/virtio.h>
  #include <linux/virtio_blk.h>
3d1266c70   Jens Axboe   SG: audit of driv...
12
  #include <linux/scatterlist.h>
7a7c924cf   Christoph Hellwig   virtio_blk: allow...
13
  #include <linux/string_helpers.h>
5087a50e6   Michael S. Tsirkin   virtio-blk: use i...
14
  #include <linux/idr.h>
1cf7e9c68   Jens Axboe   virtio_blk: blk-m...
15
  #include <linux/blk-mq.h>
ad71473d9   Christoph Hellwig   virtio_blk: use v...
16
  #include <linux/blk-mq-virtio.h>
1cf7e9c68   Jens Axboe   virtio_blk: blk-m...
17
  #include <linux/numa.h>
55a2415be   Michael S. Tsirkin   virtio_blk: add a...
18
  #include <uapi/linux/virtio_ring.h>
3d1266c70   Jens Axboe   SG: audit of driv...
19

4f3bf19c6   Christian Borntraeger   virtio_blk: Dont ...
20
  #define PART_BITS 4
6a27b656f   Ming Lei   block: virtio-blk...
21
  #define VQ_NAME_LEN 16
1f23816b8   Changpeng Liu   virtio_blk: add d...
22
  #define MAX_DISCARD_SEGMENTS 256u
e467cde23   Rusty Russell   Block driver usin...
23

5087a50e6   Michael S. Tsirkin   virtio-blk: use i...
24
25
  static int major;
  static DEFINE_IDA(vd_index_ida);
2a647bfe1   Jonghwan Choi   virtio_blk: Add m...
26
  static struct workqueue_struct *virtblk_wq;
4f3bf19c6   Christian Borntraeger   virtio_blk: Dont ...
27

6a27b656f   Ming Lei   block: virtio-blk...
28
29
30
31
32
  struct virtio_blk_vq {
  	struct virtqueue *vq;
  	spinlock_t lock;
  	char name[VQ_NAME_LEN];
  } ____cacheline_aligned_in_smp;
bb6ec5760   Michael S. Tsirkin   virtio_blk: codin...
33
  struct virtio_blk {
90b5feb8c   Stefan Hajnoczi   virtio-blk: handl...
34
35
36
37
38
39
40
41
42
  	/*
  	 * This mutex must be held by anything that may run after
  	 * virtblk_remove() sets vblk->vdev to NULL.
  	 *
  	 * blk-mq, virtqueue processing, and sysfs attribute code paths are
  	 * shut down before vblk->vdev is set to NULL and therefore do not need
  	 * to hold this mutex.
  	 */
  	struct mutex vdev_mutex;
e467cde23   Rusty Russell   Block driver usin...
43
  	struct virtio_device *vdev;
e467cde23   Rusty Russell   Block driver usin...
44
45
46
  
  	/* The disk structure for the kernel. */
  	struct gendisk *disk;
24d2f9030   Christoph Hellwig   blk-mq: split out...
47
48
  	/* Block layer tags. */
  	struct blk_mq_tag_set tag_set;
7a7c924cf   Christoph Hellwig   virtio_blk: allow...
49
50
  	/* Process context for config space updates */
  	struct work_struct config_work;
90b5feb8c   Stefan Hajnoczi   virtio-blk: handl...
51
52
53
54
55
56
  	/*
  	 * Tracks references from block_device_operations open/release and
  	 * virtio_driver probe/remove so this object can be freed once no
  	 * longer in use.
  	 */
  	refcount_t refs;
0864b79a1   Rusty Russell   virtio: block: dy...
57
58
  	/* What host tells us, plus 2 for header & tailer. */
  	unsigned int sg_elems;
5087a50e6   Michael S. Tsirkin   virtio-blk: use i...
59
60
  	/* Ida index - used to track minor number allocations. */
  	int index;
6a27b656f   Ming Lei   block: virtio-blk...
61
62
63
64
  
  	/* num of vqs */
  	int num_vqs;
  	struct virtio_blk_vq *vqs;
e467cde23   Rusty Russell   Block driver usin...
65
  };
bb6ec5760   Michael S. Tsirkin   virtio_blk: codin...
66
  struct virtblk_req {
97b50a654   Christoph Hellwig   virtio_blk: make ...
67
  	struct virtio_blk_outhdr out_hdr;
cb38fa23c   Rusty Russell   virtio: de-struct...
68
  	u8 status;
a98755c55   Asias He   virtio-blk: Add b...
69
  	struct scatterlist sg[];
e467cde23   Rusty Russell   Block driver usin...
70
  };
2a842acab   Christoph Hellwig   block: introduce ...
71
  static inline blk_status_t virtblk_result(struct virtblk_req *vbr)
a98755c55   Asias He   virtio-blk: Add b...
72
73
74
  {
  	switch (vbr->status) {
  	case VIRTIO_BLK_S_OK:
2a842acab   Christoph Hellwig   block: introduce ...
75
  		return BLK_STS_OK;
a98755c55   Asias He   virtio-blk: Add b...
76
  	case VIRTIO_BLK_S_UNSUPP:
2a842acab   Christoph Hellwig   block: introduce ...
77
  		return BLK_STS_NOTSUPP;
a98755c55   Asias He   virtio-blk: Add b...
78
  	default:
2a842acab   Christoph Hellwig   block: introduce ...
79
  		return BLK_STS_IOERR;
a98755c55   Asias He   virtio-blk: Add b...
80
81
  	}
  }
97b50a654   Christoph Hellwig   virtio_blk: make ...
82
83
84
85
86
87
88
89
  static int virtblk_add_req(struct virtqueue *vq, struct virtblk_req *vbr,
  		struct scatterlist *data_sg, bool have_data)
  {
  	struct scatterlist hdr, status, *sgs[3];
  	unsigned int num_out = 0, num_in = 0;
  
  	sg_init_one(&hdr, &vbr->out_hdr, sizeof(vbr->out_hdr));
  	sgs[num_out++] = &hdr;
20af3cfd2   Paolo Bonzini   virtio-blk: use v...
90

0a11cc36f   Rusty Russell   virtio_blk: remov...
91
  	if (have_data) {
19c1c5a64   Michael S. Tsirkin   virtio_blk: v1.0 ...
92
  		if (vbr->out_hdr.type & cpu_to_virtio32(vq->vdev, VIRTIO_BLK_T_OUT))
20af3cfd2   Paolo Bonzini   virtio-blk: use v...
93
  			sgs[num_out++] = data_sg;
8f39db9d3   Paolo Bonzini   virtio-blk: use v...
94
  		else
20af3cfd2   Paolo Bonzini   virtio-blk: use v...
95
96
  			sgs[num_out + num_in++] = data_sg;
  	}
8f39db9d3   Paolo Bonzini   virtio-blk: use v...
97
98
99
100
  	sg_init_one(&status, &vbr->status, sizeof(vbr->status));
  	sgs[num_out + num_in++] = &status;
  
  	return virtqueue_add_sgs(vq, sgs, num_out, num_in, vbr, GFP_ATOMIC);
5ee21a52c   Paolo Bonzini   virtio-blk: reorg...
101
  }
1f23816b8   Changpeng Liu   virtio_blk: add d...
102
103
104
105
106
107
108
109
110
111
112
113
114
115
  static int virtblk_setup_discard_write_zeroes(struct request *req, bool unmap)
  {
  	unsigned short segments = blk_rq_nr_discard_segments(req);
  	unsigned short n = 0;
  	struct virtio_blk_discard_write_zeroes *range;
  	struct bio *bio;
  	u32 flags = 0;
  
  	if (unmap)
  		flags |= VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP;
  
  	range = kmalloc_array(segments, sizeof(*range), GFP_ATOMIC);
  	if (!range)
  		return -ENOMEM;
af822aa68   Ming Lei   block: virtio_blk...
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
  	/*
  	 * Single max discard segment means multi-range discard isn't
  	 * supported, and block layer only runs contiguity merge like
  	 * normal RW request. So we can't reply on bio for retrieving
  	 * each range info.
  	 */
  	if (queue_max_discard_segments(req->q) == 1) {
  		range[0].flags = cpu_to_le32(flags);
  		range[0].num_sectors = cpu_to_le32(blk_rq_sectors(req));
  		range[0].sector = cpu_to_le64(blk_rq_pos(req));
  		n = 1;
  	} else {
  		__rq_for_each_bio(bio, req) {
  			u64 sector = bio->bi_iter.bi_sector;
  			u32 num_sectors = bio->bi_iter.bi_size >> SECTOR_SHIFT;
  
  			range[n].flags = cpu_to_le32(flags);
  			range[n].num_sectors = cpu_to_le32(num_sectors);
  			range[n].sector = cpu_to_le64(sector);
  			n++;
  		}
1f23816b8   Changpeng Liu   virtio_blk: add d...
137
  	}
af822aa68   Ming Lei   block: virtio_blk...
138
  	WARN_ON_ONCE(n != segments);
1f23816b8   Changpeng Liu   virtio_blk: add d...
139
140
141
142
143
144
145
  	req->special_vec.bv_page = virt_to_page(range);
  	req->special_vec.bv_offset = offset_in_page(range);
  	req->special_vec.bv_len = sizeof(*range) * segments;
  	req->rq_flags |= RQF_SPECIAL_PAYLOAD;
  
  	return 0;
  }
5124c2857   Christoph Hellwig   virtio_blk: use b...
146
  static inline void virtblk_request_done(struct request *req)
a98755c55   Asias He   virtio-blk: Add b...
147
  {
9d74e2573   Christoph Hellwig   blk-mq: do not in...
148
  	struct virtblk_req *vbr = blk_mq_rq_to_pdu(req);
a98755c55   Asias He   virtio-blk: Add b...
149

1f23816b8   Changpeng Liu   virtio_blk: add d...
150
151
152
153
  	if (req->rq_flags & RQF_SPECIAL_PAYLOAD) {
  		kfree(page_address(req->special_vec.bv_page) +
  		      req->special_vec.bv_offset);
  	}
d19633d53   Christoph Hellwig   virtio_blk: don't...
154
  	blk_mq_end_request(req, virtblk_result(vbr));
a98755c55   Asias He   virtio-blk: Add b...
155
156
157
  }
  
  static void virtblk_done(struct virtqueue *vq)
e467cde23   Rusty Russell   Block driver usin...
158
159
  {
  	struct virtio_blk *vblk = vq->vdev->priv;
1cf7e9c68   Jens Axboe   virtio_blk: blk-m...
160
  	bool req_done = false;
6a27b656f   Ming Lei   block: virtio-blk...
161
  	int qid = vq->index;
e467cde23   Rusty Russell   Block driver usin...
162
  	struct virtblk_req *vbr;
e467cde23   Rusty Russell   Block driver usin...
163
  	unsigned long flags;
a98755c55   Asias He   virtio-blk: Add b...
164
  	unsigned int len;
e467cde23   Rusty Russell   Block driver usin...
165

6a27b656f   Ming Lei   block: virtio-blk...
166
  	spin_lock_irqsave(&vblk->vqs[qid].lock, flags);
bb8111086   Asias He   virtio-blk: Disab...
167
168
  	do {
  		virtqueue_disable_cb(vq);
6a27b656f   Ming Lei   block: virtio-blk...
169
  		while ((vbr = virtqueue_get_buf(vblk->vqs[qid].vq, &len)) != NULL) {
85dada09e   Christoph Hellwig   virtio_blk: remov...
170
  			struct request *req = blk_mq_rq_from_pdu(vbr);
15f73f5b3   Christoph Hellwig   blk-mq: move fail...
171
172
  			if (likely(!blk_should_fake_timeout(req->q)))
  				blk_mq_complete_request(req);
1cf7e9c68   Jens Axboe   virtio_blk: blk-m...
173
  			req_done = true;
33659ebba   Christoph Hellwig   block: remove wra...
174
  		}
7f03b17d5   Heinz Graalfs   virtio_blk: verif...
175
176
  		if (unlikely(virtqueue_is_broken(vq)))
  			break;
bb8111086   Asias He   virtio-blk: Disab...
177
  	} while (!virtqueue_enable_cb(vq));
1cf7e9c68   Jens Axboe   virtio_blk: blk-m...
178

e467cde23   Rusty Russell   Block driver usin...
179
  	/* In case queue is stopped waiting for more buffers. */
a98755c55   Asias He   virtio-blk: Add b...
180
  	if (req_done)
1b4a32585   Christoph Hellwig   blk-mq: add async...
181
  		blk_mq_start_stopped_hw_queues(vblk->disk->queue, true);
6a27b656f   Ming Lei   block: virtio-blk...
182
  	spin_unlock_irqrestore(&vblk->vqs[qid].lock, flags);
a98755c55   Asias He   virtio-blk: Add b...
183
  }
944e7c879   Jens Axboe   virtio_blk: imple...
184
185
186
187
188
189
190
191
192
193
194
195
196
  static void virtio_commit_rqs(struct blk_mq_hw_ctx *hctx)
  {
  	struct virtio_blk *vblk = hctx->queue->queuedata;
  	struct virtio_blk_vq *vq = &vblk->vqs[hctx->queue_num];
  	bool kick;
  
  	spin_lock_irq(&vq->lock);
  	kick = virtqueue_kick_prepare(vq->vq);
  	spin_unlock_irq(&vq->lock);
  
  	if (kick)
  		virtqueue_notify(vq->vq);
  }
fc17b6534   Christoph Hellwig   blk-mq: switch ->...
197
  static blk_status_t virtio_queue_rq(struct blk_mq_hw_ctx *hctx,
74c450521   Jens Axboe   blk-mq: add a 'li...
198
  			   const struct blk_mq_queue_data *bd)
e467cde23   Rusty Russell   Block driver usin...
199
  {
1cf7e9c68   Jens Axboe   virtio_blk: blk-m...
200
  	struct virtio_blk *vblk = hctx->queue->queuedata;
74c450521   Jens Axboe   blk-mq: add a 'li...
201
  	struct request *req = bd->rq;
9d74e2573   Christoph Hellwig   blk-mq: do not in...
202
  	struct virtblk_req *vbr = blk_mq_rq_to_pdu(req);
1cf7e9c68   Jens Axboe   virtio_blk: blk-m...
203
  	unsigned long flags;
20af3cfd2   Paolo Bonzini   virtio-blk: use v...
204
  	unsigned int num;
6a27b656f   Ming Lei   block: virtio-blk...
205
  	int qid = hctx->queue_num;
5261b85e5   Rusty Russell   virtio_blk: don't...
206
  	int err;
e8edca6f7   Ming Lei   block: virtio_blk...
207
  	bool notify = false;
1f23816b8   Changpeng Liu   virtio_blk: add d...
208
  	bool unmap = false;
aebf526b5   Christoph Hellwig   block: fold cmd_t...
209
  	u32 type;
e467cde23   Rusty Russell   Block driver usin...
210

aebf526b5   Christoph Hellwig   block: fold cmd_t...
211
212
213
214
215
216
217
218
  	switch (req_op(req)) {
  	case REQ_OP_READ:
  	case REQ_OP_WRITE:
  		type = 0;
  		break;
  	case REQ_OP_FLUSH:
  		type = VIRTIO_BLK_T_FLUSH;
  		break;
1f23816b8   Changpeng Liu   virtio_blk: add d...
219
220
221
222
223
224
225
  	case REQ_OP_DISCARD:
  		type = VIRTIO_BLK_T_DISCARD;
  		break;
  	case REQ_OP_WRITE_ZEROES:
  		type = VIRTIO_BLK_T_WRITE_ZEROES;
  		unmap = !(req->cmd_flags & REQ_NOUNMAP);
  		break;
aebf526b5   Christoph Hellwig   block: fold cmd_t...
226
227
228
229
230
  	case REQ_OP_DRV_IN:
  		type = VIRTIO_BLK_T_GET_ID;
  		break;
  	default:
  		WARN_ON_ONCE(1);
fc17b6534   Christoph Hellwig   blk-mq: switch ->...
231
  		return BLK_STS_IOERR;
e467cde23   Rusty Russell   Block driver usin...
232
  	}
187c49445   Alistair Delva   ANDROID: virtio_b...
233
234
235
  	BUG_ON(type != VIRTIO_BLK_T_DISCARD &&
  	       type != VIRTIO_BLK_T_WRITE_ZEROES &&
  	       (req->nr_phys_segments + 2 > vblk->sg_elems));
aebf526b5   Christoph Hellwig   block: fold cmd_t...
236
237
238
239
  	vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, type);
  	vbr->out_hdr.sector = type ?
  		0 : cpu_to_virtio64(vblk->vdev, blk_rq_pos(req));
  	vbr->out_hdr.ioprio = cpu_to_virtio32(vblk->vdev, req_get_ioprio(req));
e2490073c   Christoph Hellwig   blk-mq: call blk_...
240
  	blk_mq_start_request(req);
1f23816b8   Changpeng Liu   virtio_blk: add d...
241
242
243
244
245
  	if (type == VIRTIO_BLK_T_DISCARD || type == VIRTIO_BLK_T_WRITE_ZEROES) {
  		err = virtblk_setup_discard_write_zeroes(req, unmap);
  		if (err)
  			return BLK_STS_RESOURCE;
  	}
85dada09e   Christoph Hellwig   virtio_blk: remov...
246
  	num = blk_rq_map_sg(hctx->queue, req, vbr->sg);
1cde26f92   Hannes Reinecke   virtio_blk: SG_IO...
247
  	if (num) {
85dada09e   Christoph Hellwig   virtio_blk: remov...
248
  		if (rq_data_dir(req) == WRITE)
19c1c5a64   Michael S. Tsirkin   virtio_blk: v1.0 ...
249
  			vbr->out_hdr.type |= cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_OUT);
20af3cfd2   Paolo Bonzini   virtio-blk: use v...
250
  		else
19c1c5a64   Michael S. Tsirkin   virtio_blk: v1.0 ...
251
  			vbr->out_hdr.type |= cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_IN);
e467cde23   Rusty Russell   Block driver usin...
252
  	}
6a27b656f   Ming Lei   block: virtio-blk...
253
  	spin_lock_irqsave(&vblk->vqs[qid].lock, flags);
782e067db   Christoph Hellwig   virtio-blk: remov...
254
  	err = virtblk_add_req(vblk->vqs[qid].vq, vbr, vbr->sg, num);
5261b85e5   Rusty Russell   virtio_blk: don't...
255
  	if (err) {
6a27b656f   Ming Lei   block: virtio-blk...
256
  		virtqueue_kick(vblk->vqs[qid].vq);
f5f6b95c7   Halil Pasic   virtio-blk: fix h...
257
258
259
260
261
  		/* Don't stop the queue if -ENOMEM: we may have failed to
  		 * bounce the buffer due to global resource outage.
  		 */
  		if (err == -ENOSPC)
  			blk_mq_stop_hw_queue(hctx);
6a27b656f   Ming Lei   block: virtio-blk...
262
  		spin_unlock_irqrestore(&vblk->vqs[qid].lock, flags);
3d973b2e9   Halil Pasic   virtio-blk: impro...
263
264
  		switch (err) {
  		case -ENOSPC:
86ff7c2a8   Ming Lei   blk-mq: introduce...
265
  			return BLK_STS_DEV_RESOURCE;
3d973b2e9   Halil Pasic   virtio-blk: impro...
266
267
268
269
270
  		case -ENOMEM:
  			return BLK_STS_RESOURCE;
  		default:
  			return BLK_STS_IOERR;
  		}
a98755c55   Asias He   virtio-blk: Add b...
271
  	}
74c450521   Jens Axboe   blk-mq: add a 'li...
272
  	if (bd->last && virtqueue_kick_prepare(vblk->vqs[qid].vq))
e8edca6f7   Ming Lei   block: virtio_blk...
273
  		notify = true;
6a27b656f   Ming Lei   block: virtio-blk...
274
  	spin_unlock_irqrestore(&vblk->vqs[qid].lock, flags);
e8edca6f7   Ming Lei   block: virtio_blk...
275
276
  
  	if (notify)
6a27b656f   Ming Lei   block: virtio-blk...
277
  		virtqueue_notify(vblk->vqs[qid].vq);
fc17b6534   Christoph Hellwig   blk-mq: switch ->...
278
  	return BLK_STS_OK;
a98755c55   Asias He   virtio-blk: Add b...
279
  }
4cb2ea28c   john cooper   Add virtio disk i...
280
281
282
283
284
  /* return id (s/n) string for *disk to *id_str
   */
  static int virtblk_get_id(struct gendisk *disk, char *id_str)
  {
  	struct virtio_blk *vblk = disk->private_data;
f9596695b   Christoph Hellwig   virtio_blk: use b...
285
  	struct request_queue *q = vblk->disk->queue;
4cb2ea28c   john cooper   Add virtio disk i...
286
  	struct request *req;
e4c4776de   Mike Snitzer   virtio-blk: fix r...
287
  	int err;
4cb2ea28c   john cooper   Add virtio disk i...
288

ff005a066   Christoph Hellwig   block: sanitize b...
289
  	req = blk_get_request(q, REQ_OP_DRV_IN, 0);
f9596695b   Christoph Hellwig   virtio_blk: use b...
290
  	if (IS_ERR(req))
4cb2ea28c   john cooper   Add virtio disk i...
291
  		return PTR_ERR(req);
f9596695b   Christoph Hellwig   virtio_blk: use b...
292
293
294
295
  
  	err = blk_rq_map_kern(q, req, id_str, VIRTIO_BLK_ID_BYTES, GFP_KERNEL);
  	if (err)
  		goto out;
b7819b925   Christoph Hellwig   block: remove the...
296
  	blk_execute_rq(vblk->disk->queue, vblk->disk, req, false);
2a842acab   Christoph Hellwig   block: introduce ...
297
  	err = blk_status_to_errno(virtblk_result(blk_mq_rq_to_pdu(req)));
f9596695b   Christoph Hellwig   virtio_blk: use b...
298
  out:
e4c4776de   Mike Snitzer   virtio-blk: fix r...
299
  	blk_put_request(req);
e4c4776de   Mike Snitzer   virtio-blk: fix r...
300
  	return err;
4cb2ea28c   john cooper   Add virtio disk i...
301
  }
90b5feb8c   Stefan Hajnoczi   virtio-blk: handl...
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
  static void virtblk_get(struct virtio_blk *vblk)
  {
  	refcount_inc(&vblk->refs);
  }
  
  static void virtblk_put(struct virtio_blk *vblk)
  {
  	if (refcount_dec_and_test(&vblk->refs)) {
  		ida_simple_remove(&vd_index_ida, vblk->index);
  		mutex_destroy(&vblk->vdev_mutex);
  		kfree(vblk);
  	}
  }
  
  static int virtblk_open(struct block_device *bd, fmode_t mode)
  {
  	struct virtio_blk *vblk = bd->bd_disk->private_data;
  	int ret = 0;
  
  	mutex_lock(&vblk->vdev_mutex);
  
  	if (vblk->vdev)
  		virtblk_get(vblk);
  	else
  		ret = -ENXIO;
  
  	mutex_unlock(&vblk->vdev_mutex);
  	return ret;
  }
  
  static void virtblk_release(struct gendisk *disk, fmode_t mode)
  {
  	struct virtio_blk *vblk = disk->private_data;
  
  	virtblk_put(vblk);
  }
135da0b03   Christian Borntraeger   virtio_blk: provi...
338
339
340
  /* We provide getgeo only to please some old bootloader/partitioning tools */
  static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
  {
48e4043d4   Ryan Harper   virtio: add virti...
341
  	struct virtio_blk *vblk = bd->bd_disk->private_data;
90b5feb8c   Stefan Hajnoczi   virtio-blk: handl...
342
343
344
345
346
347
348
349
  	int ret = 0;
  
  	mutex_lock(&vblk->vdev_mutex);
  
  	if (!vblk->vdev) {
  		ret = -ENXIO;
  		goto out;
  	}
48e4043d4   Ryan Harper   virtio: add virti...
350
351
  
  	/* see if the host passed in geometry config */
855e0c528   Rusty Russell   virtio: use size-...
352
353
354
355
356
357
358
  	if (virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_GEOMETRY)) {
  		virtio_cread(vblk->vdev, struct virtio_blk_config,
  			     geometry.cylinders, &geo->cylinders);
  		virtio_cread(vblk->vdev, struct virtio_blk_config,
  			     geometry.heads, &geo->heads);
  		virtio_cread(vblk->vdev, struct virtio_blk_config,
  			     geometry.sectors, &geo->sectors);
48e4043d4   Ryan Harper   virtio: add virti...
359
360
361
362
363
364
  	} else {
  		/* some standard values, similar to sd */
  		geo->heads = 1 << 6;
  		geo->sectors = 1 << 5;
  		geo->cylinders = get_capacity(bd->bd_disk) >> 11;
  	}
90b5feb8c   Stefan Hajnoczi   virtio-blk: handl...
365
366
367
  out:
  	mutex_unlock(&vblk->vdev_mutex);
  	return ret;
135da0b03   Christian Borntraeger   virtio_blk: provi...
368
  }
83d5cde47   Alexey Dobriyan   const: make block...
369
  static const struct block_device_operations virtblk_fops = {
135da0b03   Christian Borntraeger   virtio_blk: provi...
370
  	.owner  = THIS_MODULE,
90b5feb8c   Stefan Hajnoczi   virtio-blk: handl...
371
372
  	.open = virtblk_open,
  	.release = virtblk_release,
135da0b03   Christian Borntraeger   virtio_blk: provi...
373
  	.getgeo = virtblk_getgeo,
e467cde23   Rusty Russell   Block driver usin...
374
  };
d50ed907d   Christian Borntraeger   virtio_blk: imple...
375
376
377
378
  static int index_to_minor(int index)
  {
  	return index << PART_BITS;
  }
5087a50e6   Michael S. Tsirkin   virtio-blk: use i...
379
380
381
382
  static int minor_to_index(int minor)
  {
  	return minor >> PART_BITS;
  }
e982c4d0a   Hannes Reinecke   virtio-blk: moder...
383
384
  static ssize_t serial_show(struct device *dev,
  			   struct device_attribute *attr, char *buf)
a5eb9e4ff   Ryan Harper   virtio_blk: Add '...
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
  {
  	struct gendisk *disk = dev_to_disk(dev);
  	int err;
  
  	/* sysfs gives us a PAGE_SIZE buffer */
  	BUILD_BUG_ON(PAGE_SIZE < VIRTIO_BLK_ID_BYTES);
  
  	buf[VIRTIO_BLK_ID_BYTES] = '\0';
  	err = virtblk_get_id(disk, buf);
  	if (!err)
  		return strlen(buf);
  
  	if (err == -EIO) /* Unsupported? Make it empty. */
  		return 0;
  
  	return err;
  }
393c525b5   Michael S. Tsirkin   virtio_blk: make ...
402

e982c4d0a   Hannes Reinecke   virtio-blk: moder...
403
  static DEVICE_ATTR_RO(serial);
a5eb9e4ff   Ryan Harper   virtio_blk: Add '...
404

daf2a5016   Stefan Hajnoczi   virtio_blk: print...
405
406
  /* The queue's logical block size must be set before calling this */
  static void virtblk_update_capacity(struct virtio_blk *vblk, bool resize)
7a7c924cf   Christoph Hellwig   virtio_blk: allow...
407
  {
7a7c924cf   Christoph Hellwig   virtio_blk: allow...
408
409
410
  	struct virtio_device *vdev = vblk->vdev;
  	struct request_queue *q = vblk->disk->queue;
  	char cap_str_2[10], cap_str_10[10];
1046d3049   Stefan Hajnoczi   virtio_blk: fix i...
411
  	unsigned long long nblocks;
b9f28d863   James Bottomley   sd, mmc, virtio_b...
412
  	u64 capacity;
7a7c924cf   Christoph Hellwig   virtio_blk: allow...
413
414
  
  	/* Host must always specify the capacity. */
855e0c528   Rusty Russell   virtio: use size-...
415
  	virtio_cread(vdev, struct virtio_blk_config, capacity, &capacity);
7a7c924cf   Christoph Hellwig   virtio_blk: allow...
416
417
418
419
420
421
422
423
  
  	/* If capacity is too big, truncate with warning. */
  	if ((sector_t)capacity != capacity) {
  		dev_warn(&vdev->dev, "Capacity %llu too large: truncating
  ",
  			 (unsigned long long)capacity);
  		capacity = (sector_t)-1;
  	}
1046d3049   Stefan Hajnoczi   virtio_blk: fix i...
424
425
426
  	nblocks = DIV_ROUND_UP_ULL(capacity, queue_logical_block_size(q) >> 9);
  
  	string_get_size(nblocks, queue_logical_block_size(q),
b9f28d863   James Bottomley   sd, mmc, virtio_b...
427
  			STRING_UNITS_2, cap_str_2, sizeof(cap_str_2));
1046d3049   Stefan Hajnoczi   virtio_blk: fix i...
428
  	string_get_size(nblocks, queue_logical_block_size(q),
b9f28d863   James Bottomley   sd, mmc, virtio_b...
429
  			STRING_UNITS_10, cap_str_10, sizeof(cap_str_10));
7a7c924cf   Christoph Hellwig   virtio_blk: allow...
430
431
  
  	dev_notice(&vdev->dev,
daf2a5016   Stefan Hajnoczi   virtio_blk: print...
432
433
434
435
  		   "[%s] %s%llu %d-byte logical blocks (%s/%s)
  ",
  		   vblk->disk->disk_name,
  		   resize ? "new size: " : "",
1046d3049   Stefan Hajnoczi   virtio_blk: fix i...
436
437
438
439
  		   nblocks,
  		   queue_logical_block_size(q),
  		   cap_str_10,
  		   cap_str_2);
7a7c924cf   Christoph Hellwig   virtio_blk: allow...
440

662155e28   Balbir Singh   virtio_blk.c: Con...
441
  	set_capacity_revalidate_and_notify(vblk->disk, capacity, true);
daf2a5016   Stefan Hajnoczi   virtio_blk: print...
442
443
444
445
446
447
  }
  
  static void virtblk_config_changed_work(struct work_struct *work)
  {
  	struct virtio_blk *vblk =
  		container_of(work, struct virtio_blk, config_work);
daf2a5016   Stefan Hajnoczi   virtio_blk: print...
448
449
  
  	virtblk_update_capacity(vblk, true);
7a7c924cf   Christoph Hellwig   virtio_blk: allow...
450
451
452
453
454
455
456
457
  }
  
  static void virtblk_config_changed(struct virtio_device *vdev)
  {
  	struct virtio_blk *vblk = vdev->priv;
  
  	queue_work(virtblk_wq, &vblk->config_work);
  }
6abd6e5a4   Amit Shah   virtio: blk: Move...
458
459
  static int init_vq(struct virtio_blk *vblk)
  {
2ff98449e   Markus Elfring   virtio_blk: Delet...
460
  	int err;
6a27b656f   Ming Lei   block: virtio-blk...
461
462
463
464
465
466
  	int i;
  	vq_callback_t **callbacks;
  	const char **names;
  	struct virtqueue **vqs;
  	unsigned short num_vqs;
  	struct virtio_device *vdev = vblk->vdev;
ad71473d9   Christoph Hellwig   virtio_blk: use v...
467
  	struct irq_affinity desc = { 0, };
6a27b656f   Ming Lei   block: virtio-blk...
468
469
470
471
472
473
  
  	err = virtio_cread_feature(vdev, VIRTIO_BLK_F_MQ,
  				   struct virtio_blk_config, num_queues,
  				   &num_vqs);
  	if (err)
  		num_vqs = 1;
bf348f9b7   Dongli Zhang   virtio-blk: limit...
474
  	num_vqs = min_t(unsigned int, nr_cpu_ids, num_vqs);
668866b6e   Markus Elfring   virtio_blk: Use k...
475
  	vblk->vqs = kmalloc_array(num_vqs, sizeof(*vblk->vqs), GFP_KERNEL);
347a52939   Minfei Huang   virtio_blk: Fix a...
476
477
  	if (!vblk->vqs)
  		return -ENOMEM;
6a27b656f   Ming Lei   block: virtio-blk...
478

668866b6e   Markus Elfring   virtio_blk: Use k...
479
480
481
  	names = kmalloc_array(num_vqs, sizeof(*names), GFP_KERNEL);
  	callbacks = kmalloc_array(num_vqs, sizeof(*callbacks), GFP_KERNEL);
  	vqs = kmalloc_array(num_vqs, sizeof(*vqs), GFP_KERNEL);
347a52939   Minfei Huang   virtio_blk: Fix a...
482
483
484
485
  	if (!names || !callbacks || !vqs) {
  		err = -ENOMEM;
  		goto out;
  	}
6abd6e5a4   Amit Shah   virtio: blk: Move...
486

6a27b656f   Ming Lei   block: virtio-blk...
487
488
489
490
491
492
493
  	for (i = 0; i < num_vqs; i++) {
  		callbacks[i] = virtblk_done;
  		snprintf(vblk->vqs[i].name, VQ_NAME_LEN, "req.%d", i);
  		names[i] = vblk->vqs[i].name;
  	}
  
  	/* Discover virtqueues and write information to configuration.  */
9b2bbdb22   Michael S. Tsirkin   virtio: wrap find...
494
  	err = virtio_find_vqs(vdev, num_vqs, vqs, callbacks, names, &desc);
6a27b656f   Ming Lei   block: virtio-blk...
495
  	if (err)
347a52939   Minfei Huang   virtio_blk: Fix a...
496
  		goto out;
6abd6e5a4   Amit Shah   virtio: blk: Move...
497

6a27b656f   Ming Lei   block: virtio-blk...
498
499
500
501
502
  	for (i = 0; i < num_vqs; i++) {
  		spin_lock_init(&vblk->vqs[i].lock);
  		vblk->vqs[i].vq = vqs[i];
  	}
  	vblk->num_vqs = num_vqs;
347a52939   Minfei Huang   virtio_blk: Fix a...
503
  out:
6a27b656f   Ming Lei   block: virtio-blk...
504
  	kfree(vqs);
6a27b656f   Ming Lei   block: virtio-blk...
505
  	kfree(callbacks);
6a27b656f   Ming Lei   block: virtio-blk...
506
  	kfree(names);
6a27b656f   Ming Lei   block: virtio-blk...
507
508
  	if (err)
  		kfree(vblk->vqs);
6abd6e5a4   Amit Shah   virtio: blk: Move...
509
510
  	return err;
  }
c0aa3e091   Ren Mingxin   virtio_blk: helpe...
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
  /*
   * Legacy naming scheme used for virtio devices.  We are stuck with it for
   * virtio blk but don't ever use it for any new driver.
   */
  static int virtblk_name_format(char *prefix, int index, char *buf, int buflen)
  {
  	const int base = 'z' - 'a' + 1;
  	char *begin = buf + strlen(prefix);
  	char *end = buf + buflen;
  	char *p;
  	int unit;
  
  	p = end - 1;
  	*p = '\0';
  	unit = base;
  	do {
  		if (p == begin)
  			return -EINVAL;
  		*--p = 'a' + (index % unit);
  		index = (index / unit) - 1;
  	} while (index >= 0);
  
  	memmove(begin, p, end - p);
  	memcpy(buf, prefix, strlen(prefix));
  
  	return 0;
  }
cd5d50386   Paolo Bonzini   virtio-blk: allow...
538
539
540
541
  static int virtblk_get_cache_mode(struct virtio_device *vdev)
  {
  	u8 writeback;
  	int err;
855e0c528   Rusty Russell   virtio: use size-...
542
543
544
  	err = virtio_cread_feature(vdev, VIRTIO_BLK_F_CONFIG_WCE,
  				   struct virtio_blk_config, wce,
  				   &writeback);
592002f55   Michael S. Tsirkin   virtio_blk: VIRTI...
545
546
547
548
549
  
  	/*
  	 * If WCE is not configurable and flush is not available,
  	 * assume no writeback cache is in use.
  	 */
cd5d50386   Paolo Bonzini   virtio-blk: allow...
550
  	if (err)
592002f55   Michael S. Tsirkin   virtio_blk: VIRTI...
551
  		writeback = virtio_has_feature(vdev, VIRTIO_BLK_F_FLUSH);
cd5d50386   Paolo Bonzini   virtio-blk: allow...
552
553
554
555
556
557
558
559
  
  	return writeback;
  }
  
  static void virtblk_update_cache_mode(struct virtio_device *vdev)
  {
  	u8 writeback = virtblk_get_cache_mode(vdev);
  	struct virtio_blk *vblk = vdev->priv;
ad9126ac7   Jens Axboe   virtio_blk: switc...
560
  	blk_queue_write_cache(vblk->disk->queue, writeback, false);
659e56ba8   Christoph Hellwig   block: add a new ...
561
  	revalidate_disk_size(vblk->disk, true);
cd5d50386   Paolo Bonzini   virtio-blk: allow...
562
563
564
565
566
567
568
  }
  
  static const char *const virtblk_cache_types[] = {
  	"write through", "write back"
  };
  
  static ssize_t
e982c4d0a   Hannes Reinecke   virtio-blk: moder...
569
570
  cache_type_store(struct device *dev, struct device_attribute *attr,
  		 const char *buf, size_t count)
cd5d50386   Paolo Bonzini   virtio-blk: allow...
571
572
573
574
575
  {
  	struct gendisk *disk = dev_to_disk(dev);
  	struct virtio_blk *vblk = disk->private_data;
  	struct virtio_device *vdev = vblk->vdev;
  	int i;
cd5d50386   Paolo Bonzini   virtio-blk: allow...
576
577
  
  	BUG_ON(!virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_CONFIG_WCE));
f53d5aa05   Andy Shevchenko   virtio_blk: Use s...
578
  	i = sysfs_match_string(virtblk_cache_types, buf);
cd5d50386   Paolo Bonzini   virtio-blk: allow...
579
  	if (i < 0)
f53d5aa05   Andy Shevchenko   virtio_blk: Use s...
580
  		return i;
cd5d50386   Paolo Bonzini   virtio-blk: allow...
581

855e0c528   Rusty Russell   virtio: use size-...
582
  	virtio_cwrite8(vdev, offsetof(struct virtio_blk_config, wce), i);
cd5d50386   Paolo Bonzini   virtio-blk: allow...
583
584
585
586
587
  	virtblk_update_cache_mode(vdev);
  	return count;
  }
  
  static ssize_t
e982c4d0a   Hannes Reinecke   virtio-blk: moder...
588
  cache_type_show(struct device *dev, struct device_attribute *attr, char *buf)
cd5d50386   Paolo Bonzini   virtio-blk: allow...
589
590
591
592
593
594
595
596
597
  {
  	struct gendisk *disk = dev_to_disk(dev);
  	struct virtio_blk *vblk = disk->private_data;
  	u8 writeback = virtblk_get_cache_mode(vblk->vdev);
  
  	BUG_ON(writeback >= ARRAY_SIZE(virtblk_cache_types));
  	return snprintf(buf, 40, "%s
  ", virtblk_cache_types[writeback]);
  }
e982c4d0a   Hannes Reinecke   virtio-blk: moder...
598
599
600
601
602
603
604
605
606
607
608
  static DEVICE_ATTR_RW(cache_type);
  
  static struct attribute *virtblk_attrs[] = {
  	&dev_attr_serial.attr,
  	&dev_attr_cache_type.attr,
  	NULL,
  };
  
  static umode_t virtblk_attrs_are_visible(struct kobject *kobj,
  		struct attribute *a, int n)
  {
4ce790632   Tian Tao   virtio-blk: Use k...
609
  	struct device *dev = kobj_to_dev(kobj);
e982c4d0a   Hannes Reinecke   virtio-blk: moder...
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
  	struct gendisk *disk = dev_to_disk(dev);
  	struct virtio_blk *vblk = disk->private_data;
  	struct virtio_device *vdev = vblk->vdev;
  
  	if (a == &dev_attr_cache_type.attr &&
  	    !virtio_has_feature(vdev, VIRTIO_BLK_F_CONFIG_WCE))
  		return S_IRUGO;
  
  	return a->mode;
  }
  
  static const struct attribute_group virtblk_attr_group = {
  	.attrs = virtblk_attrs,
  	.is_visible = virtblk_attrs_are_visible,
  };
  
  static const struct attribute_group *virtblk_attr_groups[] = {
  	&virtblk_attr_group,
  	NULL,
  };
cd5d50386   Paolo Bonzini   virtio-blk: allow...
630

d6296d39e   Christoph Hellwig   blk-mq: update ->...
631
632
  static int virtblk_init_request(struct blk_mq_tag_set *set, struct request *rq,
  		unsigned int hctx_idx, unsigned int numa_node)
e9b267d91   Christoph Hellwig   blk-mq: add ->ini...
633
  {
d6296d39e   Christoph Hellwig   blk-mq: update ->...
634
  	struct virtio_blk *vblk = set->driver_data;
e9b267d91   Christoph Hellwig   blk-mq: add ->ini...
635
636
637
638
639
  	struct virtblk_req *vbr = blk_mq_rq_to_pdu(rq);
  
  	sg_init_table(vbr->sg, vblk->sg_elems);
  	return 0;
  }
ad71473d9   Christoph Hellwig   virtio_blk: use v...
640
641
642
  static int virtblk_map_queues(struct blk_mq_tag_set *set)
  {
  	struct virtio_blk *vblk = set->driver_data;
9bc00750f   Dongli Zhang   virtio_blk: repla...
643
644
  	return blk_mq_virtio_map_queues(&set->map[HCTX_TYPE_DEFAULT],
  					vblk->vdev, 0);
ad71473d9   Christoph Hellwig   virtio_blk: use v...
645
  }
f363b089b   Eric Biggers   blk-mq: constify ...
646
  static const struct blk_mq_ops virtio_mq_ops = {
1cf7e9c68   Jens Axboe   virtio_blk: blk-m...
647
  	.queue_rq	= virtio_queue_rq,
944e7c879   Jens Axboe   virtio_blk: imple...
648
  	.commit_rqs	= virtio_commit_rqs,
5124c2857   Christoph Hellwig   virtio_blk: use b...
649
  	.complete	= virtblk_request_done,
24d2f9030   Christoph Hellwig   blk-mq: split out...
650
  	.init_request	= virtblk_init_request,
ad71473d9   Christoph Hellwig   virtio_blk: use v...
651
  	.map_queues	= virtblk_map_queues,
1cf7e9c68   Jens Axboe   virtio_blk: blk-m...
652
  };
24d2f9030   Christoph Hellwig   blk-mq: split out...
653
654
  static unsigned int virtblk_queue_depth;
  module_param_named(queue_depth, virtblk_queue_depth, uint, 0444);
1cf7e9c68   Jens Axboe   virtio_blk: blk-m...
655

8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
656
  static int virtblk_probe(struct virtio_device *vdev)
e467cde23   Rusty Russell   Block driver usin...
657
658
  {
  	struct virtio_blk *vblk;
69740c8ba   Christoph Hellwig   virtio_blk: add b...
659
  	struct request_queue *q;
5087a50e6   Michael S. Tsirkin   virtio-blk: use i...
660
  	int err, index;
a98755c55   Asias He   virtio-blk: Add b...
661

fd1068e18   Joerg Roedel   virtio-blk: Consi...
662
  	u32 v, blk_size, max_size, sg_elems, opt_io_size;
69740c8ba   Christoph Hellwig   virtio_blk: add b...
663
664
  	u16 min_io_size;
  	u8 physical_block_exp, alignment_offset;
e467cde23   Rusty Russell   Block driver usin...
665

a4379fd84   Michael S. Tsirkin   virtio/blk: verif...
666
667
668
669
670
671
  	if (!vdev->config->get) {
  		dev_err(&vdev->dev, "%s failure: config access disabled
  ",
  			__func__);
  		return -EINVAL;
  	}
5087a50e6   Michael S. Tsirkin   virtio-blk: use i...
672
673
674
675
676
  	err = ida_simple_get(&vd_index_ida, 0, minor_to_index(1 << MINORBITS),
  			     GFP_KERNEL);
  	if (err < 0)
  		goto out;
  	index = err;
4f3bf19c6   Christian Borntraeger   virtio_blk: Dont ...
677

0864b79a1   Rusty Russell   virtio: block: dy...
678
  	/* We need to know how many segments before we allocate. */
855e0c528   Rusty Russell   virtio: use size-...
679
680
681
  	err = virtio_cread_feature(vdev, VIRTIO_BLK_F_SEG_MAX,
  				   struct virtio_blk_config, seg_max,
  				   &sg_elems);
a5b365a65   Christoph Hellwig   virtio-blk: fix m...
682
683
684
  
  	/* We need at least one SG element, whatever they say. */
  	if (err || !sg_elems)
0864b79a1   Rusty Russell   virtio: block: dy...
685
686
687
688
  		sg_elems = 1;
  
  	/* We need an extra sg elements at head and tail. */
  	sg_elems += 2;
1cf7e9c68   Jens Axboe   virtio_blk: blk-m...
689
  	vdev->priv = vblk = kmalloc(sizeof(*vblk), GFP_KERNEL);
e467cde23   Rusty Russell   Block driver usin...
690
691
  	if (!vblk) {
  		err = -ENOMEM;
5087a50e6   Michael S. Tsirkin   virtio-blk: use i...
692
  		goto out_free_index;
e467cde23   Rusty Russell   Block driver usin...
693
  	}
90b5feb8c   Stefan Hajnoczi   virtio-blk: handl...
694
695
696
  	/* This reference is dropped in virtblk_remove(). */
  	refcount_set(&vblk->refs, 1);
  	mutex_init(&vblk->vdev_mutex);
e467cde23   Rusty Russell   Block driver usin...
697
  	vblk->vdev = vdev;
0864b79a1   Rusty Russell   virtio: block: dy...
698
  	vblk->sg_elems = sg_elems;
a98755c55   Asias He   virtio-blk: Add b...
699

7a7c924cf   Christoph Hellwig   virtio_blk: allow...
700
  	INIT_WORK(&vblk->config_work, virtblk_config_changed_work);
e467cde23   Rusty Russell   Block driver usin...
701

6abd6e5a4   Amit Shah   virtio: blk: Move...
702
703
  	err = init_vq(vblk);
  	if (err)
e467cde23   Rusty Russell   Block driver usin...
704
  		goto out_free_vblk;
e467cde23   Rusty Russell   Block driver usin...
705

e467cde23   Rusty Russell   Block driver usin...
706
  	/* FIXME: How many partitions?  How long is a piece of string? */
4f3bf19c6   Christian Borntraeger   virtio_blk: Dont ...
707
  	vblk->disk = alloc_disk(1 << PART_BITS);
e467cde23   Rusty Russell   Block driver usin...
708
709
  	if (!vblk->disk) {
  		err = -ENOMEM;
1cf7e9c68   Jens Axboe   virtio_blk: blk-m...
710
  		goto out_free_vq;
e467cde23   Rusty Russell   Block driver usin...
711
  	}
fc4324b45   Rusty Russell   virtio-blk: base ...
712
  	/* Default queue sizing is to fill the ring. */
24d2f9030   Christoph Hellwig   blk-mq: split out...
713
  	if (!virtblk_queue_depth) {
6a27b656f   Ming Lei   block: virtio-blk...
714
  		virtblk_queue_depth = vblk->vqs[0].vq->num_free;
fc4324b45   Rusty Russell   virtio-blk: base ...
715
716
  		/* ... but without indirect descs, we use 2 descs per req */
  		if (!virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC))
24d2f9030   Christoph Hellwig   blk-mq: split out...
717
  			virtblk_queue_depth /= 2;
fc4324b45   Rusty Russell   virtio-blk: base ...
718
  	}
24d2f9030   Christoph Hellwig   blk-mq: split out...
719
720
721
  
  	memset(&vblk->tag_set, 0, sizeof(vblk->tag_set));
  	vblk->tag_set.ops = &virtio_mq_ops;
24d2f9030   Christoph Hellwig   blk-mq: split out...
722
723
724
725
  	vblk->tag_set.queue_depth = virtblk_queue_depth;
  	vblk->tag_set.numa_node = NUMA_NO_NODE;
  	vblk->tag_set.flags = BLK_MQ_F_SHOULD_MERGE;
  	vblk->tag_set.cmd_size =
1cf7e9c68   Jens Axboe   virtio_blk: blk-m...
726
727
  		sizeof(struct virtblk_req) +
  		sizeof(struct scatterlist) * sg_elems;
24d2f9030   Christoph Hellwig   blk-mq: split out...
728
  	vblk->tag_set.driver_data = vblk;
6a27b656f   Ming Lei   block: virtio-blk...
729
  	vblk->tag_set.nr_hw_queues = vblk->num_vqs;
1cf7e9c68   Jens Axboe   virtio_blk: blk-m...
730

24d2f9030   Christoph Hellwig   blk-mq: split out...
731
732
733
  	err = blk_mq_alloc_tag_set(&vblk->tag_set);
  	if (err)
  		goto out_put_disk;
6bf6b0aa3   Omar Sandoval   virtio_blk: fix p...
734
  	q = blk_mq_init_queue(&vblk->tag_set);
35b489d32   Ming Lei   block: fix checki...
735
  	if (IS_ERR(q)) {
e467cde23   Rusty Russell   Block driver usin...
736
  		err = -ENOMEM;
24d2f9030   Christoph Hellwig   blk-mq: split out...
737
  		goto out_free_tags;
e467cde23   Rusty Russell   Block driver usin...
738
  	}
6bf6b0aa3   Omar Sandoval   virtio_blk: fix p...
739
  	vblk->disk->queue = q;
e467cde23   Rusty Russell   Block driver usin...
740

69740c8ba   Christoph Hellwig   virtio_blk: add b...
741
  	q->queuedata = vblk;
7d116b626   Fernando Luis Vázquez Cao   virtio_blk: set q...
742

c0aa3e091   Ren Mingxin   virtio_blk: helpe...
743
  	virtblk_name_format("vd", index, vblk->disk->disk_name, DISK_NAME_LEN);
d50ed907d   Christian Borntraeger   virtio_blk: imple...
744

e467cde23   Rusty Russell   Block driver usin...
745
  	vblk->disk->major = major;
d50ed907d   Christian Borntraeger   virtio_blk: imple...
746
  	vblk->disk->first_minor = index_to_minor(index);
e467cde23   Rusty Russell   Block driver usin...
747
748
  	vblk->disk->private_data = vblk;
  	vblk->disk->fops = &virtblk_fops;
5fa3142da   Fam Zheng   virtio-blk: Allow...
749
  	vblk->disk->flags |= GENHD_FL_EXT_DEVT;
5087a50e6   Michael S. Tsirkin   virtio-blk: use i...
750
  	vblk->index = index;
4f3bf19c6   Christian Borntraeger   virtio_blk: Dont ...
751

02c42b7a6   Tejun Heo   virtio_blk: drop ...
752
  	/* configure queue flush support */
cd5d50386   Paolo Bonzini   virtio-blk: allow...
753
  	virtblk_update_cache_mode(vdev);
e467cde23   Rusty Russell   Block driver usin...
754

3ef536095   Christian Borntraeger   virtio_blk: allow...
755
756
757
  	/* If disk is read-only in the host, the guest should obey */
  	if (virtio_has_feature(vdev, VIRTIO_BLK_F_RO))
  		set_disk_ro(vblk->disk, 1);
0864b79a1   Rusty Russell   virtio: block: dy...
758
  	/* We can handle whatever the host told us to handle. */
ee714f2dd   Martin K. Petersen   block: Finalize c...
759
  	blk_queue_max_segments(q, vblk->sg_elems-2);
0864b79a1   Rusty Russell   virtio: block: dy...
760

4b7f7e204   Rusty Russell   virtio: set max_s...
761
  	/* No real sector limit. */
ee714f2dd   Martin K. Petersen   block: Finalize c...
762
  	blk_queue_max_hw_sectors(q, -1U);
4b7f7e204   Rusty Russell   virtio: set max_s...
763

fd1068e18   Joerg Roedel   virtio-blk: Consi...
764
  	max_size = virtio_max_dma_size(vdev);
a586d4f60   Rusty Russell   virtio: simplify ...
765
766
  	/* Host can optionally specify maximum segment size and number of
  	 * segments. */
855e0c528   Rusty Russell   virtio: use size-...
767
768
  	err = virtio_cread_feature(vdev, VIRTIO_BLK_F_SIZE_MAX,
  				   struct virtio_blk_config, size_max, &v);
e467cde23   Rusty Russell   Block driver usin...
769
  	if (!err)
fd1068e18   Joerg Roedel   virtio-blk: Consi...
770
771
772
  		max_size = min(max_size, v);
  
  	blk_queue_max_segment_size(q, max_size);
e467cde23   Rusty Russell   Block driver usin...
773

066f4d82a   Christian Borntraeger   virtio_blk: check...
774
  	/* Host can optionally specify the block size of the device */
855e0c528   Rusty Russell   virtio: use size-...
775
776
777
  	err = virtio_cread_feature(vdev, VIRTIO_BLK_F_BLK_SIZE,
  				   struct virtio_blk_config, blk_size,
  				   &blk_size);
066f4d82a   Christian Borntraeger   virtio_blk: check...
778
  	if (!err)
69740c8ba   Christoph Hellwig   virtio_blk: add b...
779
780
781
782
783
  		blk_queue_logical_block_size(q, blk_size);
  	else
  		blk_size = queue_logical_block_size(q);
  
  	/* Use topology information if available */
855e0c528   Rusty Russell   virtio: use size-...
784
785
786
  	err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY,
  				   struct virtio_blk_config, physical_block_exp,
  				   &physical_block_exp);
69740c8ba   Christoph Hellwig   virtio_blk: add b...
787
788
789
  	if (!err && physical_block_exp)
  		blk_queue_physical_block_size(q,
  				blk_size * (1 << physical_block_exp));
855e0c528   Rusty Russell   virtio: use size-...
790
791
792
  	err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY,
  				   struct virtio_blk_config, alignment_offset,
  				   &alignment_offset);
69740c8ba   Christoph Hellwig   virtio_blk: add b...
793
794
  	if (!err && alignment_offset)
  		blk_queue_alignment_offset(q, blk_size * alignment_offset);
855e0c528   Rusty Russell   virtio: use size-...
795
796
797
  	err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY,
  				   struct virtio_blk_config, min_io_size,
  				   &min_io_size);
69740c8ba   Christoph Hellwig   virtio_blk: add b...
798
799
  	if (!err && min_io_size)
  		blk_queue_io_min(q, blk_size * min_io_size);
855e0c528   Rusty Russell   virtio: use size-...
800
801
802
  	err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY,
  				   struct virtio_blk_config, opt_io_size,
  				   &opt_io_size);
69740c8ba   Christoph Hellwig   virtio_blk: add b...
803
804
  	if (!err && opt_io_size)
  		blk_queue_io_opt(q, blk_size * opt_io_size);
1f23816b8   Changpeng Liu   virtio_blk: add d...
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
  	if (virtio_has_feature(vdev, VIRTIO_BLK_F_DISCARD)) {
  		q->limits.discard_granularity = blk_size;
  
  		virtio_cread(vdev, struct virtio_blk_config,
  			     discard_sector_alignment, &v);
  		q->limits.discard_alignment = v ? v << SECTOR_SHIFT : 0;
  
  		virtio_cread(vdev, struct virtio_blk_config,
  			     max_discard_sectors, &v);
  		blk_queue_max_discard_sectors(q, v ? v : UINT_MAX);
  
  		virtio_cread(vdev, struct virtio_blk_config, max_discard_seg,
  			     &v);
  		blk_queue_max_discard_segments(q,
  					       min_not_zero(v,
  							    MAX_DISCARD_SEGMENTS));
  
  		blk_queue_flag_set(QUEUE_FLAG_DISCARD, q);
  	}
  
  	if (virtio_has_feature(vdev, VIRTIO_BLK_F_WRITE_ZEROES)) {
  		virtio_cread(vdev, struct virtio_blk_config,
  			     max_write_zeroes_sectors, &v);
  		blk_queue_max_write_zeroes_sectors(q, v ? v : UINT_MAX);
  	}
daf2a5016   Stefan Hajnoczi   virtio_blk: print...
830
  	virtblk_update_capacity(vblk, false);
7a11370e5   Michael S. Tsirkin   virtio_blk: enabl...
831
  	virtio_device_ready(vdev);
e982c4d0a   Hannes Reinecke   virtio-blk: moder...
832
  	device_add_disk(&vdev->dev, vblk->disk, virtblk_attr_groups);
e467cde23   Rusty Russell   Block driver usin...
833
  	return 0;
24d2f9030   Christoph Hellwig   blk-mq: split out...
834
835
  out_free_tags:
  	blk_mq_free_tag_set(&vblk->tag_set);
e467cde23   Rusty Russell   Block driver usin...
836
837
  out_put_disk:
  	put_disk(vblk->disk);
e467cde23   Rusty Russell   Block driver usin...
838
  out_free_vq:
d2a7ddda9   Michael S. Tsirkin   virtio: find_vqs/...
839
  	vdev->config->del_vqs(vdev);
e7eea44ee   Hou Tao   virtio-blk: free ...
840
  	kfree(vblk->vqs);
e467cde23   Rusty Russell   Block driver usin...
841
842
  out_free_vblk:
  	kfree(vblk);
5087a50e6   Michael S. Tsirkin   virtio-blk: use i...
843
844
  out_free_index:
  	ida_simple_remove(&vd_index_ida, index);
e467cde23   Rusty Russell   Block driver usin...
845
846
847
  out:
  	return err;
  }
8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
848
  static void virtblk_remove(struct virtio_device *vdev)
e467cde23   Rusty Russell   Block driver usin...
849
850
  {
  	struct virtio_blk *vblk = vdev->priv;
e467cde23   Rusty Russell   Block driver usin...
851

cc74f7193   Michael S. Tsirkin   virtio_blk: drop ...
852
853
  	/* Make sure no work handler is accessing the device. */
  	flush_work(&vblk->config_work);
7a7c924cf   Christoph Hellwig   virtio_blk: allow...
854

02e2b1249   Asias He   virtio-blk: Call ...
855
  	del_gendisk(vblk->disk);
483001c76   Asias He   virtio-blk: Reset...
856
  	blk_cleanup_queue(vblk->disk->queue);
02e2b1249   Asias He   virtio-blk: Call ...
857

24d2f9030   Christoph Hellwig   blk-mq: split out...
858
  	blk_mq_free_tag_set(&vblk->tag_set);
90b5feb8c   Stefan Hajnoczi   virtio-blk: handl...
859
  	mutex_lock(&vblk->vdev_mutex);
6e5aa7efb   Rusty Russell   virtio: reset fun...
860
861
  	/* Stop all the virtqueues. */
  	vdev->config->reset(vdev);
90b5feb8c   Stefan Hajnoczi   virtio-blk: handl...
862
863
  	/* Virtqueues are stopped, nothing can use vblk->vdev anymore. */
  	vblk->vdev = NULL;
e467cde23   Rusty Russell   Block driver usin...
864
  	put_disk(vblk->disk);
d2a7ddda9   Michael S. Tsirkin   virtio: find_vqs/...
865
  	vdev->config->del_vqs(vdev);
6a27b656f   Ming Lei   block: virtio-blk...
866
  	kfree(vblk->vqs);
f4953fe6c   Alexander Graf   virtio-blk: Don't...
867

90b5feb8c   Stefan Hajnoczi   virtio-blk: handl...
868
869
870
  	mutex_unlock(&vblk->vdev_mutex);
  
  	virtblk_put(vblk);
e467cde23   Rusty Russell   Block driver usin...
871
  }
891070003   Aaron Lu   virtio: pm: use C...
872
  #ifdef CONFIG_PM_SLEEP
f8fb5bc23   Amit Shah   virtio: blk: Add ...
873
874
875
876
877
878
  static int virtblk_freeze(struct virtio_device *vdev)
  {
  	struct virtio_blk *vblk = vdev->priv;
  
  	/* Ensure we don't receive any more interrupts */
  	vdev->config->reset(vdev);
cc74f7193   Michael S. Tsirkin   virtio_blk: drop ...
879
  	/* Make sure no work handler is accessing the device. */
f8fb5bc23   Amit Shah   virtio: blk: Add ...
880
  	flush_work(&vblk->config_work);
9b3e99058   Sagi Grimberg   virtio_blk: quies...
881
  	blk_mq_quiesce_queue(vblk->disk->queue);
f8fb5bc23   Amit Shah   virtio: blk: Add ...
882
883
884
885
886
887
888
889
890
  
  	vdev->config->del_vqs(vdev);
  	return 0;
  }
  
  static int virtblk_restore(struct virtio_device *vdev)
  {
  	struct virtio_blk *vblk = vdev->priv;
  	int ret;
f8fb5bc23   Amit Shah   virtio: blk: Add ...
891
  	ret = init_vq(vdev->priv);
6d62c37f1   Michael S. Tsirkin   virtio_blk: enabl...
892
893
894
895
  	if (ret)
  		return ret;
  
  	virtio_device_ready(vdev);
1cf7e9c68   Jens Axboe   virtio_blk: blk-m...
896

9b3e99058   Sagi Grimberg   virtio_blk: quies...
897
  	blk_mq_unquiesce_queue(vblk->disk->queue);
6d62c37f1   Michael S. Tsirkin   virtio_blk: enabl...
898
  	return 0;
f8fb5bc23   Amit Shah   virtio: blk: Add ...
899
900
  }
  #endif
47483e252   Márton Németh   block: make virti...
901
  static const struct virtio_device_id id_table[] = {
e467cde23   Rusty Russell   Block driver usin...
902
903
904
  	{ VIRTIO_ID_BLOCK, VIRTIO_DEV_ANY_ID },
  	{ 0 },
  };
19c1c5a64   Michael S. Tsirkin   virtio_blk: v1.0 ...
905
  static unsigned int features_legacy[] = {
02c42b7a6   Tejun Heo   virtio_blk: drop ...
906
  	VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, VIRTIO_BLK_F_GEOMETRY,
97b50a654   Christoph Hellwig   virtio_blk: make ...
907
  	VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE,
592002f55   Michael S. Tsirkin   virtio_blk: VIRTI...
908
  	VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_CONFIG_WCE,
1f23816b8   Changpeng Liu   virtio_blk: add d...
909
  	VIRTIO_BLK_F_MQ, VIRTIO_BLK_F_DISCARD, VIRTIO_BLK_F_WRITE_ZEROES,
19c1c5a64   Michael S. Tsirkin   virtio_blk: v1.0 ...
910
911
912
913
914
  }
  ;
  static unsigned int features[] = {
  	VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, VIRTIO_BLK_F_GEOMETRY,
  	VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE,
592002f55   Michael S. Tsirkin   virtio_blk: VIRTI...
915
  	VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_CONFIG_WCE,
1f23816b8   Changpeng Liu   virtio_blk: add d...
916
  	VIRTIO_BLK_F_MQ, VIRTIO_BLK_F_DISCARD, VIRTIO_BLK_F_WRITE_ZEROES,
c45a6816c   Rusty Russell   virtio: explicit ...
917
  };
8d85fce77   Greg Kroah-Hartman   Drivers: block: r...
918
  static struct virtio_driver virtio_blk = {
19c1c5a64   Michael S. Tsirkin   virtio_blk: v1.0 ...
919
920
921
922
923
924
925
926
927
928
  	.feature_table			= features,
  	.feature_table_size		= ARRAY_SIZE(features),
  	.feature_table_legacy		= features_legacy,
  	.feature_table_size_legacy	= ARRAY_SIZE(features_legacy),
  	.driver.name			= KBUILD_MODNAME,
  	.driver.owner			= THIS_MODULE,
  	.id_table			= id_table,
  	.probe				= virtblk_probe,
  	.remove				= virtblk_remove,
  	.config_changed			= virtblk_config_changed,
891070003   Aaron Lu   virtio: pm: use C...
929
  #ifdef CONFIG_PM_SLEEP
19c1c5a64   Michael S. Tsirkin   virtio_blk: v1.0 ...
930
931
  	.freeze				= virtblk_freeze,
  	.restore			= virtblk_restore,
f8fb5bc23   Amit Shah   virtio: blk: Add ...
932
  #endif
e467cde23   Rusty Russell   Block driver usin...
933
934
935
936
  };
  
  static int __init init(void)
  {
7a7c924cf   Christoph Hellwig   virtio_blk: allow...
937
938
939
940
941
  	int error;
  
  	virtblk_wq = alloc_workqueue("virtio-blk", 0, 0);
  	if (!virtblk_wq)
  		return -ENOMEM;
4f3bf19c6   Christian Borntraeger   virtio_blk: Dont ...
942
  	major = register_blkdev(0, "virtblk");
7a7c924cf   Christoph Hellwig   virtio_blk: allow...
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
  	if (major < 0) {
  		error = major;
  		goto out_destroy_workqueue;
  	}
  
  	error = register_virtio_driver(&virtio_blk);
  	if (error)
  		goto out_unregister_blkdev;
  	return 0;
  
  out_unregister_blkdev:
  	unregister_blkdev(major, "virtblk");
  out_destroy_workqueue:
  	destroy_workqueue(virtblk_wq);
  	return error;
e467cde23   Rusty Russell   Block driver usin...
958
959
960
961
962
  }
  
  static void __exit fini(void)
  {
  	unregister_virtio_driver(&virtio_blk);
38f37b578   Michael S. Tsirkin   virtio_blk: fix r...
963
  	unregister_blkdev(major, "virtblk");
7a7c924cf   Christoph Hellwig   virtio_blk: allow...
964
  	destroy_workqueue(virtblk_wq);
e467cde23   Rusty Russell   Block driver usin...
965
966
967
968
969
970
971
  }
  module_init(init);
  module_exit(fini);
  
  MODULE_DEVICE_TABLE(virtio, id_table);
  MODULE_DESCRIPTION("Virtio block driver");
  MODULE_LICENSE("GPL");