1181643Skmacy/*
2196661Skmacy * XenBSD block device driver
3196661Skmacy *
4251195Sgibbs * Copyright (c) 2010-2013 Spectra Logic Corporation
5199960Skmacy * Copyright (c) 2009 Scott Long, Yahoo!
6196661Skmacy * Copyright (c) 2009 Frank Suchomel, Citrix
7199959Skmacy * Copyright (c) 2009 Doug F. Rabson, Citrix
8199959Skmacy * Copyright (c) 2005 Kip Macy
9199959Skmacy * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
10199959Skmacy * Modifications by Mark A. Williamson are (c) Intel Research Cambridge
11199959Skmacy *
12199959Skmacy *
13199959Skmacy * Permission is hereby granted, free of charge, to any person obtaining a copy
14199959Skmacy * of this software and associated documentation files (the "Software"), to
15199959Skmacy * deal in the Software without restriction, including without limitation the
16199959Skmacy * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
17199959Skmacy * sell copies of the Software, and to permit persons to whom the Software is
18199959Skmacy * furnished to do so, subject to the following conditions:
19199959Skmacy *
20199959Skmacy * The above copyright notice and this permission notice shall be included in
21199959Skmacy * all copies or substantial portions of the Software.
22199959Skmacy * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23199959Skmacy * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24199959Skmacy * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25199959Skmacy * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26199959Skmacy * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27199959Skmacy * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28199959Skmacy * DEALINGS IN THE SOFTWARE.
29181643Skmacy */
30181643Skmacy
31181643Skmacy#include <sys/cdefs.h>
32181643Skmacy__FBSDID("$FreeBSD: releng/10.2/sys/dev/xen/blkfront/blkfront.c 285738 2015-07-21 07:22:18Z royger $");
33181643Skmacy
34181643Skmacy#include <sys/param.h>
35181643Skmacy#include <sys/systm.h>
36181643Skmacy#include <sys/malloc.h>
37181643Skmacy#include <sys/kernel.h>
38181643Skmacy#include <vm/vm.h>
39181643Skmacy#include <vm/pmap.h>
40181643Skmacy
41181643Skmacy#include <sys/bio.h>
42181643Skmacy#include <sys/bus.h>
43181643Skmacy#include <sys/conf.h>
44181643Skmacy#include <sys/module.h>
45231743Sgibbs#include <sys/sysctl.h>
46181643Skmacy
47181643Skmacy#include <machine/bus.h>
48181643Skmacy#include <sys/rman.h>
49181643Skmacy#include <machine/resource.h>
50181643Skmacy#include <machine/intr_machdep.h>
51181643Skmacy#include <machine/vmparam.h>
52199960Skmacy#include <sys/bus_dma.h>
53181643Skmacy
54255040Sgibbs#include <xen/xen-os.h>
55186557Skmacy#include <xen/hypervisor.h>
56186557Skmacy#include <xen/xen_intr.h>
57189699Sdfr#include <xen/gnttab.h>
58181643Skmacy#include <xen/interface/grant_table.h>
59185605Skmacy#include <xen/interface/io/protocols.h>
60185605Skmacy#include <xen/xenbus/xenbusvar.h>
61181643Skmacy
62255040Sgibbs#include <machine/_inttypes.h>
63255040Sgibbs#include <machine/xen/xenvar.h>
64255040Sgibbs
65181643Skmacy#include <geom/geom_disk.h>
66181643Skmacy
67181643Skmacy#include <dev/xen/blkfront/block.h>
68181643Skmacy
69185605Skmacy#include "xenbus_if.h"
70185605Skmacy
71251204Sgibbs/*--------------------------- Forward Declarations ---------------------------*/
72251204Sgibbsstatic void xbd_closing(device_t);
73251195Sgibbsstatic void xbd_startio(struct xbd_softc *sc);
74181643Skmacy
75251204Sgibbs/*---------------------------------- Macros ----------------------------------*/
76251204Sgibbs#if 0
77251204Sgibbs#define DPRINTK(fmt, args...) printf("[XEN] %s:%d: " fmt ".\n", __func__, __LINE__, ##args)
78251204Sgibbs#else
79251204Sgibbs#define DPRINTK(fmt, args...)
80251204Sgibbs#endif
81214077Sgibbs
82251204Sgibbs#define XBD_SECTOR_SHFT		9
83251204Sgibbs
84251204Sgibbs/*---------------------------- Global Static Data ----------------------------*/
85251204Sgibbsstatic MALLOC_DEFINE(M_XENBLOCKFRONT, "xbd", "Xen Block Front driver data");
86181643Skmacy
87251204Sgibbs/*---------------------------- Command Processing ----------------------------*/
88251772Sgibbsstatic void
89251772Sgibbsxbd_freeze(struct xbd_softc *sc, xbd_flag_t xbd_flag)
90251772Sgibbs{
91251772Sgibbs	if (xbd_flag != XBDF_NONE && (sc->xbd_flags & xbd_flag) != 0)
92251772Sgibbs		return;
93251772Sgibbs
94251772Sgibbs	sc->xbd_flags |= xbd_flag;
95251772Sgibbs	sc->xbd_qfrozen_cnt++;
96251772Sgibbs}
97251772Sgibbs
98251772Sgibbsstatic void
99251772Sgibbsxbd_thaw(struct xbd_softc *sc, xbd_flag_t xbd_flag)
100251772Sgibbs{
101251772Sgibbs	if (xbd_flag != XBDF_NONE && (sc->xbd_flags & xbd_flag) == 0)
102251772Sgibbs		return;
103251772Sgibbs
104251807Sgibbs	if (sc->xbd_qfrozen_cnt == 0)
105251772Sgibbs		panic("%s: Thaw with flag 0x%x while not frozen.",
106251772Sgibbs		    __func__, xbd_flag);
107251772Sgibbs
108251772Sgibbs	sc->xbd_flags &= ~xbd_flag;
109251772Sgibbs	sc->xbd_qfrozen_cnt--;
110251772Sgibbs}
111251772Sgibbs
112252260Sgibbsstatic void
113252260Sgibbsxbd_cm_freeze(struct xbd_softc *sc, struct xbd_command *cm, xbdc_flag_t cm_flag)
114252260Sgibbs{
115252260Sgibbs	if ((cm->cm_flags & XBDCF_FROZEN) != 0)
116252260Sgibbs		return;
117252260Sgibbs
118252260Sgibbs	cm->cm_flags |= XBDCF_FROZEN|cm_flag;
119252260Sgibbs	xbd_freeze(sc, XBDF_NONE);
120252260Sgibbs}
121252260Sgibbs
122252260Sgibbsstatic void
123252260Sgibbsxbd_cm_thaw(struct xbd_softc *sc, struct xbd_command *cm)
124252260Sgibbs{
125252260Sgibbs	if ((cm->cm_flags & XBDCF_FROZEN) == 0)
126252260Sgibbs		return;
127252260Sgibbs
128252260Sgibbs	cm->cm_flags &= ~XBDCF_FROZEN;
129252260Sgibbs	xbd_thaw(sc, XBDF_NONE);
130252260Sgibbs}
131252260Sgibbs
132251204Sgibbsstatic inline void
133251206Sgibbsxbd_flush_requests(struct xbd_softc *sc)
134251204Sgibbs{
135251204Sgibbs	int notify;
136199960Skmacy
137251204Sgibbs	RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&sc->xbd_ring, notify);
138181643Skmacy
139251204Sgibbs	if (notify)
140255040Sgibbs		xen_intr_signal(sc->xen_intr_handle);
141251204Sgibbs}
142181643Skmacy
143251204Sgibbsstatic void
144251204Sgibbsxbd_free_command(struct xbd_command *cm)
145251204Sgibbs{
146181643Skmacy
147251751Sgibbs	KASSERT((cm->cm_flags & XBDCF_Q_MASK) == XBD_Q_NONE,
148251751Sgibbs	    ("Freeing command that is still on queue %d.",
149251751Sgibbs	    cm->cm_flags & XBDCF_Q_MASK));
150181643Skmacy
151251751Sgibbs	cm->cm_flags = XBDCF_INITIALIZER;
152251204Sgibbs	cm->cm_bp = NULL;
153251204Sgibbs	cm->cm_complete = NULL;
154251751Sgibbs	xbd_enqueue_cm(cm, XBD_Q_FREE);
155251772Sgibbs	xbd_thaw(cm->cm_sc, XBDF_CM_SHORTAGE);
156251204Sgibbs}
157181643Skmacy
158185605Skmacystatic void
159251204Sgibbsxbd_queue_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
160185605Skmacy{
161251204Sgibbs	struct xbd_softc *sc;
162251204Sgibbs	struct xbd_command *cm;
163251204Sgibbs	blkif_request_t	*ring_req;
164251204Sgibbs	struct blkif_request_segment *sg;
165251204Sgibbs	struct blkif_request_segment *last_block_sg;
166251204Sgibbs	grant_ref_t *sg_ref;
167251204Sgibbs	vm_paddr_t buffer_ma;
168251204Sgibbs	uint64_t fsect, lsect;
169251204Sgibbs	int ref;
170251204Sgibbs	int op;
171251204Sgibbs	int block_segs;
172185605Skmacy
173251204Sgibbs	cm = arg;
174251204Sgibbs	sc = cm->cm_sc;
175185605Skmacy
176251204Sgibbs	if (error) {
177251204Sgibbs		cm->cm_bp->bio_error = EIO;
178251204Sgibbs		biodone(cm->cm_bp);
179251204Sgibbs		xbd_free_command(cm);
180231743Sgibbs		return;
181185605Skmacy	}
182185605Skmacy
183251204Sgibbs	/* Fill out a communications ring structure. */
184251204Sgibbs	ring_req = RING_GET_REQUEST(&sc->xbd_ring, sc->xbd_ring.req_prod_pvt);
185251204Sgibbs	sc->xbd_ring.req_prod_pvt++;
186251204Sgibbs	ring_req->id = cm->cm_id;
187251204Sgibbs	ring_req->operation = cm->cm_operation;
188251204Sgibbs	ring_req->sector_number = cm->cm_sector_number;
189251204Sgibbs	ring_req->handle = (blkif_vdev_t)(uintptr_t)sc->xbd_disk;
190251204Sgibbs	ring_req->nr_segments = nsegs;
191251204Sgibbs	cm->cm_nseg = nsegs;
192251204Sgibbs
193285738Sroyger	block_segs    = MIN(nsegs, BLKIF_MAX_SEGMENTS_PER_REQUEST);
194251204Sgibbs	sg            = ring_req->seg;
195251204Sgibbs	last_block_sg = sg + block_segs;
196251204Sgibbs	sg_ref        = cm->cm_sg_refs;
197251204Sgibbs
198285738Sroyger	while (sg < last_block_sg) {
199285738Sroyger		buffer_ma = segs->ds_addr;
200285738Sroyger		fsect = (buffer_ma & PAGE_MASK) >> XBD_SECTOR_SHFT;
201285738Sroyger		lsect = fsect + (segs->ds_len  >> XBD_SECTOR_SHFT) - 1;
202251204Sgibbs
203285738Sroyger		KASSERT(lsect <= 7, ("XEN disk driver data cannot "
204285738Sroyger		    "cross a page boundary"));
205251204Sgibbs
206285738Sroyger		/* install a grant reference. */
207285738Sroyger		ref = gnttab_claim_grant_reference(&cm->cm_gref_head);
208251204Sgibbs
209285738Sroyger		/*
210285738Sroyger		 * GNTTAB_LIST_END == 0xffffffff, but it is private
211285738Sroyger		 * to gnttab.c.
212285738Sroyger		 */
213285738Sroyger		KASSERT(ref != ~0, ("grant_reference failed"));
214251204Sgibbs
215285738Sroyger		gnttab_grant_foreign_access_ref(
216285738Sroyger		    ref,
217285738Sroyger		    xenbus_get_otherend_id(sc->xbd_dev),
218285738Sroyger		    buffer_ma >> PAGE_SHIFT,
219285738Sroyger		    ring_req->operation == BLKIF_OP_WRITE);
220251204Sgibbs
221285738Sroyger		*sg_ref = ref;
222285738Sroyger		*sg = (struct blkif_request_segment) {
223285738Sroyger			.gref       = ref,
224285738Sroyger			.first_sect = fsect,
225285738Sroyger			.last_sect  = lsect
226285738Sroyger		};
227285738Sroyger		sg++;
228285738Sroyger		sg_ref++;
229285738Sroyger		segs++;
230285738Sroyger		nsegs--;
231185605Skmacy	}
232185605Skmacy
233251204Sgibbs	if (cm->cm_operation == BLKIF_OP_READ)
234251204Sgibbs		op = BUS_DMASYNC_PREREAD;
235251204Sgibbs	else if (cm->cm_operation == BLKIF_OP_WRITE)
236251204Sgibbs		op = BUS_DMASYNC_PREWRITE;
237251204Sgibbs	else
238251204Sgibbs		op = 0;
239251204Sgibbs	bus_dmamap_sync(sc->xbd_io_dmat, cm->cm_map, op);
240251204Sgibbs
241251204Sgibbs	gnttab_free_grant_references(cm->cm_gref_head);
242251204Sgibbs
243251751Sgibbs	xbd_enqueue_cm(cm, XBD_Q_BUSY);
244251204Sgibbs
245251204Sgibbs	/*
246251772Sgibbs	 * If bus dma had to asynchronously call us back to dispatch
247251772Sgibbs	 * this command, we are no longer executing in the context of
248251772Sgibbs	 * xbd_startio().  Thus we cannot rely on xbd_startio()'s call to
249251772Sgibbs	 * xbd_flush_requests() to publish this command to the backend
250251772Sgibbs	 * along with any other commands that it could batch.
251251204Sgibbs	 */
252251772Sgibbs	if ((cm->cm_flags & XBDCF_ASYNC_MAPPING) != 0)
253251206Sgibbs		xbd_flush_requests(sc);
254251204Sgibbs
255251204Sgibbs	return;
256185605Skmacy}
257185605Skmacy
258251204Sgibbsstatic int
259251204Sgibbsxbd_queue_request(struct xbd_softc *sc, struct xbd_command *cm)
260181643Skmacy{
261251204Sgibbs	int error;
262186557Skmacy
263271611Sroyger	error = bus_dmamap_load(sc->xbd_io_dmat, cm->cm_map, cm->cm_data,
264271611Sroyger	    cm->cm_datalen, xbd_queue_cb, cm, 0);
265251204Sgibbs	if (error == EINPROGRESS) {
266251772Sgibbs		/*
267251772Sgibbs		 * Maintain queuing order by freezing the queue.  The next
268251772Sgibbs		 * command may not require as many resources as the command
269251772Sgibbs		 * we just attempted to map, so we can't rely on bus dma
270251772Sgibbs		 * blocking for it too.
271251772Sgibbs		 */
272252260Sgibbs		xbd_cm_freeze(sc, cm, XBDCF_ASYNC_MAPPING);
273251204Sgibbs		return (0);
274251204Sgibbs	}
275182082Skmacy
276251204Sgibbs	return (error);
277251204Sgibbs}
278181643Skmacy
279251204Sgibbsstatic void
280251204Sgibbsxbd_restart_queue_callback(void *arg)
281251204Sgibbs{
282251204Sgibbs	struct xbd_softc *sc = arg;
283185605Skmacy
284251204Sgibbs	mtx_lock(&sc->xbd_io_lock);
285181643Skmacy
286251772Sgibbs	xbd_thaw(sc, XBDF_GNT_SHORTAGE);
287251772Sgibbs
288251204Sgibbs	xbd_startio(sc);
289181643Skmacy
290251204Sgibbs	mtx_unlock(&sc->xbd_io_lock);
291181643Skmacy}
292181643Skmacy
293251204Sgibbsstatic struct xbd_command *
294251204Sgibbsxbd_bio_command(struct xbd_softc *sc)
295251204Sgibbs{
296251204Sgibbs	struct xbd_command *cm;
297251204Sgibbs	struct bio *bp;
298181643Skmacy
299255040Sgibbs	if (__predict_false(sc->xbd_state != XBD_STATE_CONNECTED))
300251204Sgibbs		return (NULL);
301251204Sgibbs
302251204Sgibbs	bp = xbd_dequeue_bio(sc);
303251204Sgibbs	if (bp == NULL)
304251204Sgibbs		return (NULL);
305251204Sgibbs
306251751Sgibbs	if ((cm = xbd_dequeue_cm(sc, XBD_Q_FREE)) == NULL) {
307251772Sgibbs		xbd_freeze(sc, XBDF_CM_SHORTAGE);
308251204Sgibbs		xbd_requeue_bio(sc, bp);
309251204Sgibbs		return (NULL);
310251204Sgibbs	}
311251204Sgibbs
312251204Sgibbs	if (gnttab_alloc_grant_references(sc->xbd_max_request_segments,
313251204Sgibbs	    &cm->cm_gref_head) != 0) {
314251204Sgibbs		gnttab_request_free_callback(&sc->xbd_callback,
315251204Sgibbs		    xbd_restart_queue_callback, sc,
316251204Sgibbs		    sc->xbd_max_request_segments);
317251772Sgibbs		xbd_freeze(sc, XBDF_GNT_SHORTAGE);
318251204Sgibbs		xbd_requeue_bio(sc, bp);
319251751Sgibbs		xbd_enqueue_cm(cm, XBD_Q_FREE);
320251204Sgibbs		return (NULL);
321251204Sgibbs	}
322251204Sgibbs
323251204Sgibbs	cm->cm_bp = bp;
324271611Sroyger	cm->cm_data = bp->bio_data;
325271611Sroyger	cm->cm_datalen = bp->bio_bcount;
326251204Sgibbs	cm->cm_sector_number = (blkif_sector_t)bp->bio_pblkno;
327251204Sgibbs
328252260Sgibbs	switch (bp->bio_cmd) {
329252260Sgibbs	case BIO_READ:
330252260Sgibbs		cm->cm_operation = BLKIF_OP_READ;
331252260Sgibbs		break;
332252260Sgibbs	case BIO_WRITE:
333252260Sgibbs		cm->cm_operation = BLKIF_OP_WRITE;
334252260Sgibbs		if ((bp->bio_flags & BIO_ORDERED) != 0) {
335252260Sgibbs			if ((sc->xbd_flags & XBDF_BARRIER) != 0) {
336252260Sgibbs				cm->cm_operation = BLKIF_OP_WRITE_BARRIER;
337252260Sgibbs			} else {
338252260Sgibbs				/*
339252260Sgibbs				 * Single step this command.
340252260Sgibbs				 */
341252260Sgibbs				cm->cm_flags |= XBDCF_Q_FREEZE;
342252260Sgibbs				if (xbd_queue_length(sc, XBD_Q_BUSY) != 0) {
343252260Sgibbs					/*
344252260Sgibbs					 * Wait for in-flight requests to
345252260Sgibbs					 * finish.
346252260Sgibbs					 */
347252260Sgibbs					xbd_freeze(sc, XBDF_WAIT_IDLE);
348252260Sgibbs					xbd_requeue_cm(cm, XBD_Q_READY);
349252260Sgibbs					return (NULL);
350252260Sgibbs				}
351252260Sgibbs			}
352252260Sgibbs		}
353252260Sgibbs		break;
354252260Sgibbs	case BIO_FLUSH:
355252260Sgibbs		if ((sc->xbd_flags & XBDF_FLUSH) != 0)
356252260Sgibbs			cm->cm_operation = BLKIF_OP_FLUSH_DISKCACHE;
357252260Sgibbs		else if ((sc->xbd_flags & XBDF_BARRIER) != 0)
358252260Sgibbs			cm->cm_operation = BLKIF_OP_WRITE_BARRIER;
359252260Sgibbs		else
360252260Sgibbs			panic("flush request, but no flush support available");
361252260Sgibbs		break;
362252260Sgibbs	default:
363252260Sgibbs		panic("unknown bio command %d", bp->bio_cmd);
364252260Sgibbs	}
365252260Sgibbs
366251204Sgibbs	return (cm);
367251204Sgibbs}
368251204Sgibbs
369181643Skmacy/*
370251204Sgibbs * Dequeue buffers and place them in the shared communication ring.
371251204Sgibbs * Return when no more requests can be accepted or all buffers have
372251204Sgibbs * been queued.
373251204Sgibbs *
374251204Sgibbs * Signal XEN once the ring has been filled out.
375181643Skmacy */
376181643Skmacystatic void
377251204Sgibbsxbd_startio(struct xbd_softc *sc)
378181643Skmacy{
379251204Sgibbs	struct xbd_command *cm;
380251204Sgibbs	int error, queued = 0;
381181643Skmacy
382251204Sgibbs	mtx_assert(&sc->xbd_io_lock, MA_OWNED);
383251204Sgibbs
384251751Sgibbs	if (sc->xbd_state != XBD_STATE_CONNECTED)
385199960Skmacy		return;
386181643Skmacy
387285738Sroyger	while (!RING_FULL(&sc->xbd_ring)) {
388285738Sroyger
389251772Sgibbs		if (sc->xbd_qfrozen_cnt != 0)
390251204Sgibbs			break;
391196661Skmacy
392251751Sgibbs		cm = xbd_dequeue_cm(sc, XBD_Q_READY);
393181643Skmacy
394251204Sgibbs		if (cm == NULL)
395251204Sgibbs		    cm = xbd_bio_command(sc);
396251204Sgibbs
397251204Sgibbs		if (cm == NULL)
398251204Sgibbs			break;
399251204Sgibbs
400252260Sgibbs		if ((cm->cm_flags & XBDCF_Q_FREEZE) != 0) {
401252260Sgibbs			/*
402252260Sgibbs			 * Single step command.  Future work is
403252260Sgibbs			 * held off until this command completes.
404252260Sgibbs			 */
405252260Sgibbs			xbd_cm_freeze(sc, cm, XBDCF_Q_FREEZE);
406252260Sgibbs		}
407252260Sgibbs
408251204Sgibbs		if ((error = xbd_queue_request(sc, cm)) != 0) {
409251204Sgibbs			printf("xbd_queue_request returned %d\n", error);
410251204Sgibbs			break;
411251204Sgibbs		}
412251204Sgibbs		queued++;
413251204Sgibbs	}
414251204Sgibbs
415251204Sgibbs	if (queued != 0)
416251206Sgibbs		xbd_flush_requests(sc);
417199960Skmacy}
418181643Skmacy
419199960Skmacystatic void
420251195Sgibbsxbd_bio_complete(struct xbd_softc *sc, struct xbd_command *cm)
421199960Skmacy{
422199960Skmacy	struct bio *bp;
423199960Skmacy
424251195Sgibbs	bp = cm->cm_bp;
425199960Skmacy
426255040Sgibbs	if (__predict_false(cm->cm_status != BLKIF_RSP_OKAY)) {
427199960Skmacy		disk_err(bp, "disk error" , -1, 0);
428251195Sgibbs		printf(" status: %x\n", cm->cm_status);
429199960Skmacy		bp->bio_flags |= BIO_ERROR;
430199960Skmacy	}
431199960Skmacy
432199960Skmacy	if (bp->bio_flags & BIO_ERROR)
433199960Skmacy		bp->bio_error = EIO;
434199960Skmacy	else
435199960Skmacy		bp->bio_resid = 0;
436199960Skmacy
437251195Sgibbs	xbd_free_command(cm);
438181643Skmacy	biodone(bp);
439181643Skmacy}
440181643Skmacy
441196661Skmacystatic void
442251204Sgibbsxbd_int(void *xsc)
443251204Sgibbs{
444251204Sgibbs	struct xbd_softc *sc = xsc;
445251204Sgibbs	struct xbd_command *cm;
446251204Sgibbs	blkif_response_t *bret;
447251204Sgibbs	RING_IDX i, rp;
448251204Sgibbs	int op;
449251204Sgibbs
450251204Sgibbs	mtx_lock(&sc->xbd_io_lock);
451251204Sgibbs
452255040Sgibbs	if (__predict_false(sc->xbd_state == XBD_STATE_DISCONNECTED)) {
453251204Sgibbs		mtx_unlock(&sc->xbd_io_lock);
454251204Sgibbs		return;
455251204Sgibbs	}
456251204Sgibbs
457251204Sgibbs again:
458251204Sgibbs	rp = sc->xbd_ring.sring->rsp_prod;
459251204Sgibbs	rmb(); /* Ensure we see queued responses up to 'rp'. */
460251204Sgibbs
461251204Sgibbs	for (i = sc->xbd_ring.rsp_cons; i != rp;) {
462251204Sgibbs		bret = RING_GET_RESPONSE(&sc->xbd_ring, i);
463251204Sgibbs		cm   = &sc->xbd_shadow[bret->id];
464251204Sgibbs
465251751Sgibbs		xbd_remove_cm(cm, XBD_Q_BUSY);
466285738Sroyger		gnttab_end_foreign_access_references(cm->cm_nseg,
467285738Sroyger		    cm->cm_sg_refs);
468285738Sroyger		i++;
469251204Sgibbs
470251204Sgibbs		if (cm->cm_operation == BLKIF_OP_READ)
471251204Sgibbs			op = BUS_DMASYNC_POSTREAD;
472252260Sgibbs		else if (cm->cm_operation == BLKIF_OP_WRITE ||
473252260Sgibbs		    cm->cm_operation == BLKIF_OP_WRITE_BARRIER)
474251204Sgibbs			op = BUS_DMASYNC_POSTWRITE;
475251204Sgibbs		else
476251204Sgibbs			op = 0;
477251204Sgibbs		bus_dmamap_sync(sc->xbd_io_dmat, cm->cm_map, op);
478251204Sgibbs		bus_dmamap_unload(sc->xbd_io_dmat, cm->cm_map);
479251204Sgibbs
480251204Sgibbs		/*
481251772Sgibbs		 * Release any hold this command has on future command
482251772Sgibbs		 * dispatch.
483251204Sgibbs		 */
484252260Sgibbs		xbd_cm_thaw(sc, cm);
485251204Sgibbs
486251204Sgibbs		/*
487251204Sgibbs		 * Directly call the i/o complete routine to save an
488251204Sgibbs		 * an indirection in the common case.
489251204Sgibbs		 */
490251204Sgibbs		cm->cm_status = bret->status;
491251204Sgibbs		if (cm->cm_bp)
492251204Sgibbs			xbd_bio_complete(sc, cm);
493251204Sgibbs		else if (cm->cm_complete != NULL)
494251204Sgibbs			cm->cm_complete(cm);
495251204Sgibbs		else
496251204Sgibbs			xbd_free_command(cm);
497251204Sgibbs	}
498251204Sgibbs
499251204Sgibbs	sc->xbd_ring.rsp_cons = i;
500251204Sgibbs
501251204Sgibbs	if (i != sc->xbd_ring.req_prod_pvt) {
502251204Sgibbs		int more_to_do;
503251204Sgibbs		RING_FINAL_CHECK_FOR_RESPONSES(&sc->xbd_ring, more_to_do);
504251204Sgibbs		if (more_to_do)
505251204Sgibbs			goto again;
506251204Sgibbs	} else {
507251204Sgibbs		sc->xbd_ring.sring->rsp_event = i + 1;
508251204Sgibbs	}
509251204Sgibbs
510252260Sgibbs	if (xbd_queue_length(sc, XBD_Q_BUSY) == 0)
511252260Sgibbs		xbd_thaw(sc, XBDF_WAIT_IDLE);
512252260Sgibbs
513251204Sgibbs	xbd_startio(sc);
514251204Sgibbs
515255040Sgibbs	if (__predict_false(sc->xbd_state == XBD_STATE_SUSPENDED))
516251751Sgibbs		wakeup(&sc->xbd_cm_q[XBD_Q_BUSY]);
517251204Sgibbs
518251204Sgibbs	mtx_unlock(&sc->xbd_io_lock);
519251204Sgibbs}
520251204Sgibbs
521251204Sgibbs/*------------------------------- Dump Support -------------------------------*/
522251204Sgibbs/**
523251204Sgibbs * Quiesce the disk writes for a dump file before allowing the next buffer.
524251204Sgibbs */
525251204Sgibbsstatic void
526251195Sgibbsxbd_quiesce(struct xbd_softc *sc)
527196661Skmacy{
528251195Sgibbs	int mtd;
529196661Skmacy
530196661Skmacy	// While there are outstanding requests
531252260Sgibbs	while (xbd_queue_length(sc, XBD_Q_BUSY) != 0) {
532251195Sgibbs		RING_FINAL_CHECK_FOR_RESPONSES(&sc->xbd_ring, mtd);
533196661Skmacy		if (mtd) {
534199960Skmacy			/* Recieved request completions, update queue. */
535251195Sgibbs			xbd_int(sc);
536196661Skmacy		}
537252260Sgibbs		if (xbd_queue_length(sc, XBD_Q_BUSY) != 0) {
538199960Skmacy			/*
539199960Skmacy			 * Still pending requests, wait for the disk i/o
540199960Skmacy			 * to complete.
541199960Skmacy			 */
542199734Skmacy			HYPERVISOR_yield();
543196661Skmacy		}
544196661Skmacy	}
545196661Skmacy}
546196661Skmacy
547199960Skmacy/* Kernel dump function for a paravirtualized disk device */
548199960Skmacystatic void
549251195Sgibbsxbd_dump_complete(struct xbd_command *cm)
550199960Skmacy{
551196661Skmacy
552251751Sgibbs	xbd_enqueue_cm(cm, XBD_Q_COMPLETE);
553199960Skmacy}
554199960Skmacy
555185605Skmacystatic int
556251195Sgibbsxbd_dump(void *arg, void *virtual, vm_offset_t physical, off_t offset,
557251195Sgibbs    size_t length)
558196661Skmacy{
559251195Sgibbs	struct disk *dp = arg;
560251195Sgibbs	struct xbd_softc *sc = dp->d_drv1;
561251195Sgibbs	struct xbd_command *cm;
562251195Sgibbs	size_t chunk;
563251195Sgibbs	int sbp;
564251195Sgibbs	int rc = 0;
565196661Skmacy
566199960Skmacy	if (length <= 0)
567199960Skmacy		return (rc);
568196661Skmacy
569251195Sgibbs	xbd_quiesce(sc);	/* All quiet on the western front. */
570196661Skmacy
571199960Skmacy	/*
572199960Skmacy	 * If this lock is held, then this module is failing, and a
573199960Skmacy	 * successful kernel dump is highly unlikely anyway.
574199960Skmacy	 */
575251195Sgibbs	mtx_lock(&sc->xbd_io_lock);
576199960Skmacy
577199960Skmacy	/* Split the 64KB block as needed */
578199960Skmacy	for (sbp=0; length > 0; sbp++) {
579251751Sgibbs		cm = xbd_dequeue_cm(sc, XBD_Q_FREE);
580199960Skmacy		if (cm == NULL) {
581251195Sgibbs			mtx_unlock(&sc->xbd_io_lock);
582251195Sgibbs			device_printf(sc->xbd_dev, "dump: no more commands?\n");
583199960Skmacy			return (EBUSY);
584196661Skmacy		}
585196661Skmacy
586251195Sgibbs		if (gnttab_alloc_grant_references(sc->xbd_max_request_segments,
587251195Sgibbs		    &cm->cm_gref_head) != 0) {
588251195Sgibbs			xbd_free_command(cm);
589251195Sgibbs			mtx_unlock(&sc->xbd_io_lock);
590251195Sgibbs			device_printf(sc->xbd_dev, "no more grant allocs?\n");
591199960Skmacy			return (EBUSY);
592196661Skmacy		}
593199960Skmacy
594251195Sgibbs		chunk = length > sc->xbd_max_request_size ?
595251195Sgibbs		    sc->xbd_max_request_size : length;
596251195Sgibbs		cm->cm_data = virtual;
597251195Sgibbs		cm->cm_datalen = chunk;
598251195Sgibbs		cm->cm_operation = BLKIF_OP_WRITE;
599251195Sgibbs		cm->cm_sector_number = offset / dp->d_sectorsize;
600251195Sgibbs		cm->cm_complete = xbd_dump_complete;
601199960Skmacy
602251751Sgibbs		xbd_enqueue_cm(cm, XBD_Q_READY);
603199960Skmacy
604199960Skmacy		length -= chunk;
605199960Skmacy		offset += chunk;
606199960Skmacy		virtual = (char *) virtual + chunk;
607196661Skmacy	}
608199960Skmacy
609199960Skmacy	/* Tell DOM0 to do the I/O */
610251195Sgibbs	xbd_startio(sc);
611251195Sgibbs	mtx_unlock(&sc->xbd_io_lock);
612199960Skmacy
613199960Skmacy	/* Poll for the completion. */
614251195Sgibbs	xbd_quiesce(sc);	/* All quite on the eastern front */
615199960Skmacy
616199960Skmacy	/* If there were any errors, bail out... */
617251751Sgibbs	while ((cm = xbd_dequeue_cm(sc, XBD_Q_COMPLETE)) != NULL) {
618251195Sgibbs		if (cm->cm_status != BLKIF_RSP_OKAY) {
619251195Sgibbs			device_printf(sc->xbd_dev,
620199960Skmacy			    "Dump I/O failed at sector %jd\n",
621251195Sgibbs			    cm->cm_sector_number);
622199960Skmacy			rc = EIO;
623199960Skmacy		}
624251195Sgibbs		xbd_free_command(cm);
625199960Skmacy	}
626199960Skmacy
627196661Skmacy	return (rc);
628196661Skmacy}
629196661Skmacy
630251204Sgibbs/*----------------------------- Disk Entrypoints -----------------------------*/
631251204Sgibbsstatic int
632251204Sgibbsxbd_open(struct disk *dp)
633251204Sgibbs{
634251204Sgibbs	struct xbd_softc *sc = dp->d_drv1;
635196661Skmacy
636251204Sgibbs	if (sc == NULL) {
637251204Sgibbs		printf("xb%d: not found", sc->xbd_unit);
638251204Sgibbs		return (ENXIO);
639251204Sgibbs	}
640251204Sgibbs
641251751Sgibbs	sc->xbd_flags |= XBDF_OPEN;
642251204Sgibbs	sc->xbd_users++;
643251204Sgibbs	return (0);
644251204Sgibbs}
645251204Sgibbs
646196661Skmacystatic int
647251204Sgibbsxbd_close(struct disk *dp)
648185605Skmacy{
649251204Sgibbs	struct xbd_softc *sc = dp->d_drv1;
650181643Skmacy
651251204Sgibbs	if (sc == NULL)
652251204Sgibbs		return (ENXIO);
653251751Sgibbs	sc->xbd_flags &= ~XBDF_OPEN;
654251204Sgibbs	if (--(sc->xbd_users) == 0) {
655251204Sgibbs		/*
656251204Sgibbs		 * Check whether we have been instructed to close.  We will
657251204Sgibbs		 * have ignored this request initially, as the device was
658251204Sgibbs		 * still mounted.
659251204Sgibbs		 */
660251204Sgibbs		if (xenbus_get_otherend_state(sc->xbd_dev) ==
661251204Sgibbs		    XenbusStateClosing)
662251204Sgibbs			xbd_closing(sc->xbd_dev);
663185605Skmacy	}
664251204Sgibbs	return (0);
665251204Sgibbs}
666181643Skmacy
667251204Sgibbsstatic int
668251204Sgibbsxbd_ioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
669251204Sgibbs{
670251204Sgibbs	struct xbd_softc *sc = dp->d_drv1;
671251204Sgibbs
672251204Sgibbs	if (sc == NULL)
673251204Sgibbs		return (ENXIO);
674251204Sgibbs
675251204Sgibbs	return (ENOTTY);
676185605Skmacy}
677185605Skmacy
678251204Sgibbs/*
679251204Sgibbs * Read/write routine for a buffer.  Finds the proper unit, place it on
680251204Sgibbs * the sortq and kick the controller.
681251204Sgibbs */
682231743Sgibbsstatic void
683251204Sgibbsxbd_strategy(struct bio *bp)
684251204Sgibbs{
685251204Sgibbs	struct xbd_softc *sc = bp->bio_disk->d_drv1;
686251204Sgibbs
687251204Sgibbs	/* bogus disk? */
688251204Sgibbs	if (sc == NULL) {
689251204Sgibbs		bp->bio_error = EINVAL;
690251204Sgibbs		bp->bio_flags |= BIO_ERROR;
691251204Sgibbs		bp->bio_resid = bp->bio_bcount;
692251204Sgibbs		biodone(bp);
693251204Sgibbs		return;
694251204Sgibbs	}
695251204Sgibbs
696251204Sgibbs	/*
697251204Sgibbs	 * Place it in the queue of disk activities for this disk
698251204Sgibbs	 */
699251204Sgibbs	mtx_lock(&sc->xbd_io_lock);
700251204Sgibbs
701251204Sgibbs	xbd_enqueue_bio(sc, bp);
702251204Sgibbs	xbd_startio(sc);
703251204Sgibbs
704251204Sgibbs	mtx_unlock(&sc->xbd_io_lock);
705251204Sgibbs	return;
706251204Sgibbs}
707251204Sgibbs
708251204Sgibbs/*------------------------------ Ring Management -----------------------------*/
709251204Sgibbsstatic int
710251206Sgibbsxbd_alloc_ring(struct xbd_softc *sc)
711251204Sgibbs{
712251204Sgibbs	blkif_sring_t *sring;
713251204Sgibbs	uintptr_t sring_page_addr;
714251204Sgibbs	int error;
715251204Sgibbs	int i;
716251204Sgibbs
717251204Sgibbs	sring = malloc(sc->xbd_ring_pages * PAGE_SIZE, M_XENBLOCKFRONT,
718251204Sgibbs	    M_NOWAIT|M_ZERO);
719251204Sgibbs	if (sring == NULL) {
720251204Sgibbs		xenbus_dev_fatal(sc->xbd_dev, ENOMEM, "allocating shared ring");
721251204Sgibbs		return (ENOMEM);
722251204Sgibbs	}
723251204Sgibbs	SHARED_RING_INIT(sring);
724251204Sgibbs	FRONT_RING_INIT(&sc->xbd_ring, sring, sc->xbd_ring_pages * PAGE_SIZE);
725251204Sgibbs
726251204Sgibbs	for (i = 0, sring_page_addr = (uintptr_t)sring;
727251204Sgibbs	     i < sc->xbd_ring_pages;
728251204Sgibbs	     i++, sring_page_addr += PAGE_SIZE) {
729251204Sgibbs
730251204Sgibbs		error = xenbus_grant_ring(sc->xbd_dev,
731251204Sgibbs		    (vtomach(sring_page_addr) >> PAGE_SHIFT),
732251204Sgibbs		    &sc->xbd_ring_ref[i]);
733251204Sgibbs		if (error) {
734251204Sgibbs			xenbus_dev_fatal(sc->xbd_dev, error,
735251204Sgibbs			    "granting ring_ref(%d)", i);
736251204Sgibbs			return (error);
737251204Sgibbs		}
738251204Sgibbs	}
739251204Sgibbs	if (sc->xbd_ring_pages == 1) {
740251204Sgibbs		error = xs_printf(XST_NIL, xenbus_get_node(sc->xbd_dev),
741251204Sgibbs		    "ring-ref", "%u", sc->xbd_ring_ref[0]);
742251204Sgibbs		if (error) {
743251204Sgibbs			xenbus_dev_fatal(sc->xbd_dev, error,
744251204Sgibbs			    "writing %s/ring-ref",
745251204Sgibbs			    xenbus_get_node(sc->xbd_dev));
746251204Sgibbs			return (error);
747251204Sgibbs		}
748251204Sgibbs	} else {
749251204Sgibbs		for (i = 0; i < sc->xbd_ring_pages; i++) {
750251204Sgibbs			char ring_ref_name[]= "ring_refXX";
751251204Sgibbs
752251204Sgibbs			snprintf(ring_ref_name, sizeof(ring_ref_name),
753251204Sgibbs			    "ring-ref%u", i);
754251204Sgibbs			error = xs_printf(XST_NIL, xenbus_get_node(sc->xbd_dev),
755251204Sgibbs			     ring_ref_name, "%u", sc->xbd_ring_ref[i]);
756251204Sgibbs			if (error) {
757251204Sgibbs				xenbus_dev_fatal(sc->xbd_dev, error,
758251204Sgibbs				    "writing %s/%s",
759251204Sgibbs				    xenbus_get_node(sc->xbd_dev),
760251204Sgibbs				    ring_ref_name);
761251204Sgibbs				return (error);
762251204Sgibbs			}
763251204Sgibbs		}
764251204Sgibbs	}
765251204Sgibbs
766255040Sgibbs	error = xen_intr_alloc_and_bind_local_port(sc->xbd_dev,
767255040Sgibbs	    xenbus_get_otherend_id(sc->xbd_dev), NULL, xbd_int, sc,
768255040Sgibbs	    INTR_TYPE_BIO | INTR_MPSAFE, &sc->xen_intr_handle);
769251204Sgibbs	if (error) {
770251204Sgibbs		xenbus_dev_fatal(sc->xbd_dev, error,
771255040Sgibbs		    "xen_intr_alloc_and_bind_local_port failed");
772251204Sgibbs		return (error);
773251204Sgibbs	}
774251204Sgibbs
775251204Sgibbs	return (0);
776251204Sgibbs}
777251204Sgibbs
778251214Sgibbsstatic void
779251214Sgibbsxbd_free_ring(struct xbd_softc *sc)
780251214Sgibbs{
781251214Sgibbs	int i;
782251214Sgibbs
783251214Sgibbs	if (sc->xbd_ring.sring == NULL)
784251214Sgibbs		return;
785251214Sgibbs
786251214Sgibbs	for (i = 0; i < sc->xbd_ring_pages; i++) {
787251214Sgibbs		if (sc->xbd_ring_ref[i] != GRANT_REF_INVALID) {
788251214Sgibbs			gnttab_end_foreign_access_ref(sc->xbd_ring_ref[i]);
789251214Sgibbs			sc->xbd_ring_ref[i] = GRANT_REF_INVALID;
790251214Sgibbs		}
791251214Sgibbs	}
792251214Sgibbs	free(sc->xbd_ring.sring, M_XENBLOCKFRONT);
793251214Sgibbs	sc->xbd_ring.sring = NULL;
794251214Sgibbs}
795251214Sgibbs
796251204Sgibbs/*-------------------------- Initialization/Teardown -------------------------*/
797252260Sgibbsstatic int
798252260Sgibbsxbd_feature_string(struct xbd_softc *sc, char *features, size_t len)
799252260Sgibbs{
800252260Sgibbs	struct sbuf sb;
801252260Sgibbs	int feature_cnt;
802252260Sgibbs
803252260Sgibbs	sbuf_new(&sb, features, len, SBUF_FIXEDLEN);
804252260Sgibbs
805252260Sgibbs	feature_cnt = 0;
806252260Sgibbs	if ((sc->xbd_flags & XBDF_FLUSH) != 0) {
807252260Sgibbs		sbuf_printf(&sb, "flush");
808252260Sgibbs		feature_cnt++;
809252260Sgibbs	}
810252260Sgibbs
811252260Sgibbs	if ((sc->xbd_flags & XBDF_BARRIER) != 0) {
812252260Sgibbs		if (feature_cnt != 0)
813252260Sgibbs			sbuf_printf(&sb, ", ");
814252260Sgibbs		sbuf_printf(&sb, "write_barrier");
815252260Sgibbs		feature_cnt++;
816252260Sgibbs	}
817252260Sgibbs
818252260Sgibbs	(void) sbuf_finish(&sb);
819252260Sgibbs	return (sbuf_len(&sb));
820252260Sgibbs}
821252260Sgibbs
822252260Sgibbsstatic int
823252260Sgibbsxbd_sysctl_features(SYSCTL_HANDLER_ARGS)
824252260Sgibbs{
825252260Sgibbs	char features[80];
826252260Sgibbs	struct xbd_softc *sc = arg1;
827252260Sgibbs	int error;
828252260Sgibbs	int len;
829252260Sgibbs
830252260Sgibbs	error = sysctl_wire_old_buffer(req, 0);
831252260Sgibbs	if (error != 0)
832252260Sgibbs		return (error);
833252260Sgibbs
834252260Sgibbs	len = xbd_feature_string(sc, features, sizeof(features));
835252260Sgibbs
836252260Sgibbs	/* len is -1 on error, which will make the SYSCTL_OUT a no-op. */
837252260Sgibbs	return (SYSCTL_OUT(req, features, len + 1/*NUL*/));
838252260Sgibbs}
839252260Sgibbs
840251204Sgibbsstatic void
841251195Sgibbsxbd_setup_sysctl(struct xbd_softc *xbd)
842231743Sgibbs{
843231743Sgibbs	struct sysctl_ctx_list *sysctl_ctx = NULL;
844251195Sgibbs	struct sysctl_oid *sysctl_tree = NULL;
845252260Sgibbs	struct sysctl_oid_list *children;
846231743Sgibbs
847251195Sgibbs	sysctl_ctx = device_get_sysctl_ctx(xbd->xbd_dev);
848231743Sgibbs	if (sysctl_ctx == NULL)
849231743Sgibbs		return;
850231743Sgibbs
851251195Sgibbs	sysctl_tree = device_get_sysctl_tree(xbd->xbd_dev);
852231743Sgibbs	if (sysctl_tree == NULL)
853231743Sgibbs		return;
854231743Sgibbs
855252260Sgibbs	children = SYSCTL_CHILDREN(sysctl_tree);
856252260Sgibbs	SYSCTL_ADD_UINT(sysctl_ctx, children, OID_AUTO,
857251195Sgibbs	    "max_requests", CTLFLAG_RD, &xbd->xbd_max_requests, -1,
858251195Sgibbs	    "maximum outstanding requests (negotiated)");
859231743Sgibbs
860252260Sgibbs	SYSCTL_ADD_UINT(sysctl_ctx, children, OID_AUTO,
861251195Sgibbs	    "max_request_segments", CTLFLAG_RD,
862251195Sgibbs	    &xbd->xbd_max_request_segments, 0,
863251195Sgibbs	    "maximum number of pages per requests (negotiated)");
864231743Sgibbs
865252260Sgibbs	SYSCTL_ADD_UINT(sysctl_ctx, children, OID_AUTO,
866251195Sgibbs	    "max_request_size", CTLFLAG_RD, &xbd->xbd_max_request_size, 0,
867251195Sgibbs	    "maximum size in bytes of a request (negotiated)");
868231743Sgibbs
869252260Sgibbs	SYSCTL_ADD_UINT(sysctl_ctx, children, OID_AUTO,
870251195Sgibbs	    "ring_pages", CTLFLAG_RD, &xbd->xbd_ring_pages, 0,
871251195Sgibbs	    "communication channel pages (negotiated)");
872252260Sgibbs
873252260Sgibbs	SYSCTL_ADD_PROC(sysctl_ctx, children, OID_AUTO,
874252260Sgibbs	    "features", CTLTYPE_STRING|CTLFLAG_RD, xbd, 0,
875252260Sgibbs	    xbd_sysctl_features, "A", "protocol features (negotiated)");
876231743Sgibbs}
877231743Sgibbs
878185605Skmacy/*
879251204Sgibbs * Translate Linux major/minor to an appropriate name and unit
880251204Sgibbs * number. For HVM guests, this allows us to use the same drive names
881251204Sgibbs * with blkfront as the emulated drives, easing transition slightly.
882185605Skmacy */
883251204Sgibbsstatic void
884251204Sgibbsxbd_vdevice_to_unit(uint32_t vdevice, int *unit, const char **name)
885181643Skmacy{
886251204Sgibbs	static struct vdev_info {
887251204Sgibbs		int major;
888251204Sgibbs		int shift;
889251204Sgibbs		int base;
890251204Sgibbs		const char *name;
891251204Sgibbs	} info[] = {
892251204Sgibbs		{3,	6,	0,	"ada"},	/* ide0 */
893251204Sgibbs		{22,	6,	2,	"ada"},	/* ide1 */
894251204Sgibbs		{33,	6,	4,	"ada"},	/* ide2 */
895251204Sgibbs		{34,	6,	6,	"ada"},	/* ide3 */
896251204Sgibbs		{56,	6,	8,	"ada"},	/* ide4 */
897251204Sgibbs		{57,	6,	10,	"ada"},	/* ide5 */
898251204Sgibbs		{88,	6,	12,	"ada"},	/* ide6 */
899251204Sgibbs		{89,	6,	14,	"ada"},	/* ide7 */
900251204Sgibbs		{90,	6,	16,	"ada"},	/* ide8 */
901251204Sgibbs		{91,	6,	18,	"ada"},	/* ide9 */
902251204Sgibbs
903251204Sgibbs		{8,	4,	0,	"da"},	/* scsi disk0 */
904251204Sgibbs		{65,	4,	16,	"da"},	/* scsi disk1 */
905251204Sgibbs		{66,	4,	32,	"da"},	/* scsi disk2 */
906251204Sgibbs		{67,	4,	48,	"da"},	/* scsi disk3 */
907251204Sgibbs		{68,	4,	64,	"da"},	/* scsi disk4 */
908251204Sgibbs		{69,	4,	80,	"da"},	/* scsi disk5 */
909251204Sgibbs		{70,	4,	96,	"da"},	/* scsi disk6 */
910251204Sgibbs		{71,	4,	112,	"da"},	/* scsi disk7 */
911251204Sgibbs		{128,	4,	128,	"da"},	/* scsi disk8 */
912251204Sgibbs		{129,	4,	144,	"da"},	/* scsi disk9 */
913251204Sgibbs		{130,	4,	160,	"da"},	/* scsi disk10 */
914251204Sgibbs		{131,	4,	176,	"da"},	/* scsi disk11 */
915251204Sgibbs		{132,	4,	192,	"da"},	/* scsi disk12 */
916251204Sgibbs		{133,	4,	208,	"da"},	/* scsi disk13 */
917251204Sgibbs		{134,	4,	224,	"da"},	/* scsi disk14 */
918251204Sgibbs		{135,	4,	240,	"da"},	/* scsi disk15 */
919251204Sgibbs
920251204Sgibbs		{202,	4,	0,	"xbd"},	/* xbd */
921251204Sgibbs
922251204Sgibbs		{0,	0,	0,	NULL},
923251204Sgibbs	};
924251204Sgibbs	int major = vdevice >> 8;
925251204Sgibbs	int minor = vdevice & 0xff;
926214077Sgibbs	int i;
927181643Skmacy
928251204Sgibbs	if (vdevice & (1 << 28)) {
929251204Sgibbs		*unit = (vdevice & ((1 << 28) - 1)) >> 8;
930251204Sgibbs		*name = "xbd";
931251204Sgibbs		return;
932181643Skmacy	}
933181643Skmacy
934251204Sgibbs	for (i = 0; info[i].major; i++) {
935251204Sgibbs		if (info[i].major == major) {
936251204Sgibbs			*unit = info[i].base + (minor >> info[i].shift);
937251204Sgibbs			*name = info[i].name;
938251204Sgibbs			return;
939251204Sgibbs		}
940251204Sgibbs	}
941251204Sgibbs
942251204Sgibbs	*unit = minor >> 4;
943251204Sgibbs	*name = "xbd";
944251204Sgibbs}
945251204Sgibbs
946251204Sgibbsint
947251204Sgibbsxbd_instance_create(struct xbd_softc *sc, blkif_sector_t sectors,
948251204Sgibbs    int vdevice, uint16_t vdisk_info, unsigned long sector_size)
949251204Sgibbs{
950252260Sgibbs	char features[80];
951251204Sgibbs	int unit, error = 0;
952251204Sgibbs	const char *name;
953251204Sgibbs
954251195Sgibbs	xbd_vdevice_to_unit(vdevice, &unit, &name);
955185605Skmacy
956251204Sgibbs	sc->xbd_unit = unit;
957181643Skmacy
958252260Sgibbs	if (strcmp(name, "xbd") != 0)
959251204Sgibbs		device_printf(sc->xbd_dev, "attaching as %s%d\n", name, unit);
960199960Skmacy
961252260Sgibbs	if (xbd_feature_string(sc, features, sizeof(features)) > 0) {
962252260Sgibbs		device_printf(sc->xbd_dev, "features: %s\n",
963252260Sgibbs		    features);
964252260Sgibbs	}
965252260Sgibbs
966251204Sgibbs	sc->xbd_disk = disk_alloc();
967251204Sgibbs	sc->xbd_disk->d_unit = sc->xbd_unit;
968251204Sgibbs	sc->xbd_disk->d_open = xbd_open;
969251204Sgibbs	sc->xbd_disk->d_close = xbd_close;
970251204Sgibbs	sc->xbd_disk->d_ioctl = xbd_ioctl;
971251204Sgibbs	sc->xbd_disk->d_strategy = xbd_strategy;
972251204Sgibbs	sc->xbd_disk->d_dump = xbd_dump;
973251204Sgibbs	sc->xbd_disk->d_name = name;
974251204Sgibbs	sc->xbd_disk->d_drv1 = sc;
975251204Sgibbs	sc->xbd_disk->d_sectorsize = sector_size;
976231743Sgibbs
977251204Sgibbs	sc->xbd_disk->d_mediasize = sectors * sector_size;
978251204Sgibbs	sc->xbd_disk->d_maxsize = sc->xbd_max_request_size;
979271611Sroyger	sc->xbd_disk->d_flags = 0;
980252260Sgibbs	if ((sc->xbd_flags & (XBDF_FLUSH|XBDF_BARRIER)) != 0) {
981252260Sgibbs		sc->xbd_disk->d_flags |= DISKFLAG_CANFLUSHCACHE;
982252260Sgibbs		device_printf(sc->xbd_dev,
983252260Sgibbs		    "synchronize cache commands enabled.\n");
984252260Sgibbs	}
985251204Sgibbs	disk_create(sc->xbd_disk, DISK_VERSION);
986181643Skmacy
987251204Sgibbs	return error;
988181643Skmacy}
989181643Skmacy
990251204Sgibbsstatic void
991251204Sgibbsxbd_free(struct xbd_softc *sc)
992189699Sdfr{
993251204Sgibbs	int i;
994251204Sgibbs
995189699Sdfr	/* Prevent new requests being issued until we fix things up. */
996251195Sgibbs	mtx_lock(&sc->xbd_io_lock);
997251751Sgibbs	sc->xbd_state = XBD_STATE_DISCONNECTED;
998251204Sgibbs	mtx_unlock(&sc->xbd_io_lock);
999225705Sgibbs
1000251204Sgibbs	/* Free resources associated with old device channel. */
1001251214Sgibbs	xbd_free_ring(sc);
1002251204Sgibbs	if (sc->xbd_shadow) {
1003225705Sgibbs
1004251204Sgibbs		for (i = 0; i < sc->xbd_max_requests; i++) {
1005251204Sgibbs			struct xbd_command *cm;
1006189699Sdfr
1007251204Sgibbs			cm = &sc->xbd_shadow[i];
1008251204Sgibbs			if (cm->cm_sg_refs != NULL) {
1009251204Sgibbs				free(cm->cm_sg_refs, M_XENBLOCKFRONT);
1010251204Sgibbs				cm->cm_sg_refs = NULL;
1011251204Sgibbs			}
1012181643Skmacy
1013251204Sgibbs			bus_dmamap_destroy(sc->xbd_io_dmat, cm->cm_map);
1014251204Sgibbs		}
1015251204Sgibbs		free(sc->xbd_shadow, M_XENBLOCKFRONT);
1016251204Sgibbs		sc->xbd_shadow = NULL;
1017181643Skmacy
1018251204Sgibbs		bus_dma_tag_destroy(sc->xbd_io_dmat);
1019251204Sgibbs
1020251751Sgibbs		xbd_initq_cm(sc, XBD_Q_FREE);
1021251751Sgibbs		xbd_initq_cm(sc, XBD_Q_READY);
1022251751Sgibbs		xbd_initq_cm(sc, XBD_Q_COMPLETE);
1023251204Sgibbs	}
1024251204Sgibbs
1025255040Sgibbs	xen_intr_unbind(&sc->xen_intr_handle);
1026255040Sgibbs
1027181643Skmacy}
1028181643Skmacy
1029251204Sgibbs/*--------------------------- State Change Handlers --------------------------*/
1030214077Sgibbsstatic void
1031251195Sgibbsxbd_initialize(struct xbd_softc *sc)
1032181643Skmacy{
1033214077Sgibbs	const char *otherend_path;
1034214077Sgibbs	const char *node_path;
1035231743Sgibbs	uint32_t max_ring_page_order;
1036214077Sgibbs	int error;
1037214077Sgibbs	int i;
1038181643Skmacy
1039251195Sgibbs	if (xenbus_get_state(sc->xbd_dev) != XenbusStateInitialising) {
1040225705Sgibbs		/* Initialization has already been performed. */
1041225705Sgibbs		return;
1042225705Sgibbs	}
1043181643Skmacy
1044214077Sgibbs	/*
1045214077Sgibbs	 * Protocol defaults valid even if negotiation for a
1046214077Sgibbs	 * setting fails.
1047214077Sgibbs	 */
1048231743Sgibbs	max_ring_page_order = 0;
1049251195Sgibbs	sc->xbd_ring_pages = 1;
1050285738Sroyger	sc->xbd_max_request_segments = BLKIF_MAX_SEGMENTS_PER_REQUEST;
1051251195Sgibbs	sc->xbd_max_request_size =
1052251195Sgibbs	    XBD_SEGS_TO_SIZE(sc->xbd_max_request_segments);
1053214077Sgibbs
1054214077Sgibbs	/*
1055214077Sgibbs	 * Protocol negotiation.
1056214077Sgibbs	 *
1057214077Sgibbs	 * \note xs_gather() returns on the first encountered error, so
1058214077Sgibbs	 *       we must use independant calls in order to guarantee
1059214077Sgibbs	 *       we don't miss information in a sparsly populated back-end
1060214077Sgibbs	 *       tree.
1061231743Sgibbs	 *
1062231743Sgibbs	 * \note xs_scanf() does not update variables for unmatched
1063231743Sgibbs	 *	 fields.
1064214077Sgibbs	 */
1065251195Sgibbs	otherend_path = xenbus_get_otherend_path(sc->xbd_dev);
1066251195Sgibbs	node_path = xenbus_get_node(sc->xbd_dev);
1067231743Sgibbs
1068231743Sgibbs	/* Support both backend schemes for relaying ring page limits. */
1069214077Sgibbs	(void)xs_scanf(XST_NIL, otherend_path,
1070251195Sgibbs	    "max-ring-page-order", NULL, "%" PRIu32,
1071251195Sgibbs	    &max_ring_page_order);
1072251195Sgibbs	sc->xbd_ring_pages = 1 << max_ring_page_order;
1073231743Sgibbs	(void)xs_scanf(XST_NIL, otherend_path,
1074251195Sgibbs	    "max-ring-pages", NULL, "%" PRIu32,
1075251195Sgibbs	    &sc->xbd_ring_pages);
1076251195Sgibbs	if (sc->xbd_ring_pages < 1)
1077251195Sgibbs		sc->xbd_ring_pages = 1;
1078214077Sgibbs
1079251195Sgibbs	if (sc->xbd_ring_pages > XBD_MAX_RING_PAGES) {
1080251195Sgibbs		device_printf(sc->xbd_dev,
1081251195Sgibbs		    "Back-end specified ring-pages of %u "
1082285738Sroyger		    "limited to front-end limit of %u.\n",
1083251195Sgibbs		    sc->xbd_ring_pages, XBD_MAX_RING_PAGES);
1084251195Sgibbs		sc->xbd_ring_pages = XBD_MAX_RING_PAGES;
1085181643Skmacy	}
1086181643Skmacy
1087251195Sgibbs	if (powerof2(sc->xbd_ring_pages) == 0) {
1088231743Sgibbs		uint32_t new_page_limit;
1089231743Sgibbs
1090251195Sgibbs		new_page_limit = 0x01 << (fls(sc->xbd_ring_pages) - 1);
1091251195Sgibbs		device_printf(sc->xbd_dev,
1092251195Sgibbs		    "Back-end specified ring-pages of %u "
1093251195Sgibbs		    "is not a power of 2. Limited to %u.\n",
1094251195Sgibbs		    sc->xbd_ring_pages, new_page_limit);
1095251195Sgibbs		sc->xbd_ring_pages = new_page_limit;
1096231743Sgibbs	}
1097231743Sgibbs
1098285738Sroyger	sc->xbd_max_requests =
1099285738Sroyger	    BLKIF_MAX_RING_REQUESTS(sc->xbd_ring_pages * PAGE_SIZE);
1100251195Sgibbs	if (sc->xbd_max_requests > XBD_MAX_REQUESTS) {
1101251195Sgibbs		device_printf(sc->xbd_dev,
1102251195Sgibbs		    "Back-end specified max_requests of %u "
1103285738Sroyger		    "limited to front-end limit of %zu.\n",
1104251195Sgibbs		    sc->xbd_max_requests, XBD_MAX_REQUESTS);
1105251195Sgibbs		sc->xbd_max_requests = XBD_MAX_REQUESTS;
1106181643Skmacy	}
1107214077Sgibbs
1108214077Sgibbs	/* Allocate datastructures based on negotiated values. */
1109251195Sgibbs	error = bus_dma_tag_create(
1110251195Sgibbs	    bus_get_dma_tag(sc->xbd_dev),	/* parent */
1111251195Sgibbs	    512, PAGE_SIZE,			/* algnmnt, boundary */
1112251195Sgibbs	    BUS_SPACE_MAXADDR,			/* lowaddr */
1113251195Sgibbs	    BUS_SPACE_MAXADDR,			/* highaddr */
1114251195Sgibbs	    NULL, NULL,				/* filter, filterarg */
1115251195Sgibbs	    sc->xbd_max_request_size,
1116251195Sgibbs	    sc->xbd_max_request_segments,
1117251195Sgibbs	    PAGE_SIZE,				/* maxsegsize */
1118251195Sgibbs	    BUS_DMA_ALLOCNOW,			/* flags */
1119251195Sgibbs	    busdma_lock_mutex,			/* lockfunc */
1120251195Sgibbs	    &sc->xbd_io_lock,			/* lockarg */
1121251195Sgibbs	    &sc->xbd_io_dmat);
1122214077Sgibbs	if (error != 0) {
1123251195Sgibbs		xenbus_dev_fatal(sc->xbd_dev, error,
1124251195Sgibbs		    "Cannot allocate parent DMA tag\n");
1125214077Sgibbs		return;
1126181643Skmacy	}
1127181643Skmacy
1128214077Sgibbs	/* Per-transaction data allocation. */
1129251195Sgibbs	sc->xbd_shadow = malloc(sizeof(*sc->xbd_shadow) * sc->xbd_max_requests,
1130251195Sgibbs	    M_XENBLOCKFRONT, M_NOWAIT|M_ZERO);
1131251195Sgibbs	if (sc->xbd_shadow == NULL) {
1132251195Sgibbs		bus_dma_tag_destroy(sc->xbd_io_dmat);
1133251195Sgibbs		xenbus_dev_fatal(sc->xbd_dev, error,
1134251195Sgibbs		    "Cannot allocate request structures\n");
1135225705Sgibbs		return;
1136214077Sgibbs	}
1137214077Sgibbs
1138251195Sgibbs	for (i = 0; i < sc->xbd_max_requests; i++) {
1139251195Sgibbs		struct xbd_command *cm;
1140214077Sgibbs
1141251195Sgibbs		cm = &sc->xbd_shadow[i];
1142251195Sgibbs		cm->cm_sg_refs = malloc(
1143251195Sgibbs		    sizeof(grant_ref_t) * sc->xbd_max_request_segments,
1144251195Sgibbs		    M_XENBLOCKFRONT, M_NOWAIT);
1145251195Sgibbs		if (cm->cm_sg_refs == NULL)
1146214077Sgibbs			break;
1147251195Sgibbs		cm->cm_id = i;
1148251751Sgibbs		cm->cm_flags = XBDCF_INITIALIZER;
1149214077Sgibbs		cm->cm_sc = sc;
1150251195Sgibbs		if (bus_dmamap_create(sc->xbd_io_dmat, 0, &cm->cm_map) != 0)
1151214077Sgibbs			break;
1152251195Sgibbs		xbd_free_command(cm);
1153214077Sgibbs	}
1154214077Sgibbs
1155251206Sgibbs	if (xbd_alloc_ring(sc) != 0)
1156214077Sgibbs		return;
1157214077Sgibbs
1158231743Sgibbs	/* Support both backend schemes for relaying ring page limits. */
1159251195Sgibbs	if (sc->xbd_ring_pages > 1) {
1160233465Sgibbs		error = xs_printf(XST_NIL, node_path,
1161251195Sgibbs		    "num-ring-pages","%u",
1162251195Sgibbs		    sc->xbd_ring_pages);
1163233465Sgibbs		if (error) {
1164251195Sgibbs			xenbus_dev_fatal(sc->xbd_dev, error,
1165251195Sgibbs			    "writing %s/num-ring-pages",
1166251195Sgibbs			    node_path);
1167233465Sgibbs			return;
1168233465Sgibbs		}
1169233465Sgibbs
1170233465Sgibbs		error = xs_printf(XST_NIL, node_path,
1171251195Sgibbs		    "ring-page-order", "%u",
1172251195Sgibbs		    fls(sc->xbd_ring_pages) - 1);
1173233465Sgibbs		if (error) {
1174251195Sgibbs			xenbus_dev_fatal(sc->xbd_dev, error,
1175251195Sgibbs			    "writing %s/ring-page-order",
1176251195Sgibbs			    node_path);
1177233465Sgibbs			return;
1178233465Sgibbs		}
1179214077Sgibbs	}
1180214077Sgibbs
1181214077Sgibbs	error = xs_printf(XST_NIL, node_path, "event-channel",
1182255040Sgibbs	    "%u", xen_intr_port(sc->xen_intr_handle));
1183214077Sgibbs	if (error) {
1184251195Sgibbs		xenbus_dev_fatal(sc->xbd_dev, error,
1185251195Sgibbs		    "writing %s/event-channel",
1186251195Sgibbs		    node_path);
1187214077Sgibbs		return;
1188214077Sgibbs	}
1189214077Sgibbs
1190251195Sgibbs	error = xs_printf(XST_NIL, node_path, "protocol",
1191251195Sgibbs	    "%s", XEN_IO_PROTO_ABI_NATIVE);
1192214077Sgibbs	if (error) {
1193251195Sgibbs		xenbus_dev_fatal(sc->xbd_dev, error,
1194251195Sgibbs		    "writing %s/protocol",
1195251195Sgibbs		    node_path);
1196214077Sgibbs		return;
1197214077Sgibbs	}
1198214077Sgibbs
1199251195Sgibbs	xenbus_set_state(sc->xbd_dev, XenbusStateInitialised);
1200181643Skmacy}
1201181643Skmacy
1202181643Skmacy/*
1203251195Sgibbs * Invoked when the backend is finally 'ready' (and has published
1204251195Sgibbs * the details about the physical device - #sectors, size, etc).
1205251195Sgibbs */
1206181643Skmacystatic void
1207251195Sgibbsxbd_connect(struct xbd_softc *sc)
1208181643Skmacy{
1209251195Sgibbs	device_t dev = sc->xbd_dev;
1210181643Skmacy	unsigned long sectors, sector_size;
1211181643Skmacy	unsigned int binfo;
1212252260Sgibbs	int err, feature_barrier, feature_flush;
1213181643Skmacy
1214251751Sgibbs	if (sc->xbd_state == XBD_STATE_CONNECTED ||
1215251751Sgibbs	    sc->xbd_state == XBD_STATE_SUSPENDED)
1216181643Skmacy		return;
1217181643Skmacy
1218185605Skmacy	DPRINTK("blkfront.c:connect:%s.\n", xenbus_get_otherend_path(dev));
1219181643Skmacy
1220214077Sgibbs	err = xs_gather(XST_NIL, xenbus_get_otherend_path(dev),
1221251195Sgibbs	    "sectors", "%lu", &sectors,
1222251195Sgibbs	    "info", "%u", &binfo,
1223251195Sgibbs	    "sector-size", "%lu", &sector_size,
1224251195Sgibbs	    NULL);
1225181643Skmacy	if (err) {
1226185605Skmacy		xenbus_dev_fatal(dev, err,
1227185605Skmacy		    "reading backend fields at %s",
1228185605Skmacy		    xenbus_get_otherend_path(dev));
1229181643Skmacy		return;
1230181643Skmacy	}
1231214077Sgibbs	err = xs_gather(XST_NIL, xenbus_get_otherend_path(dev),
1232251195Sgibbs	     "feature-barrier", "%lu", &feature_barrier,
1233251195Sgibbs	     NULL);
1234252260Sgibbs	if (err == 0 && feature_barrier != 0)
1235251751Sgibbs		sc->xbd_flags |= XBDF_BARRIER;
1236181643Skmacy
1237252260Sgibbs	err = xs_gather(XST_NIL, xenbus_get_otherend_path(dev),
1238252260Sgibbs	     "feature-flush-cache", "%lu", &feature_flush,
1239252260Sgibbs	     NULL);
1240252260Sgibbs	if (err == 0 && feature_flush != 0)
1241252260Sgibbs		sc->xbd_flags |= XBDF_FLUSH;
1242252260Sgibbs
1243251195Sgibbs	if (sc->xbd_disk == NULL) {
1244225705Sgibbs		device_printf(dev, "%juMB <%s> at %s",
1245225705Sgibbs		    (uintmax_t) sectors / (1048576 / sector_size),
1246225705Sgibbs		    device_get_desc(dev),
1247225705Sgibbs		    xenbus_get_node(dev));
1248225705Sgibbs		bus_print_child_footer(device_get_parent(dev), dev);
1249181643Skmacy
1250251195Sgibbs		xbd_instance_create(sc, sectors, sc->xbd_vdevice, binfo,
1251251195Sgibbs		    sector_size);
1252225705Sgibbs	}
1253181643Skmacy
1254185605Skmacy	(void)xenbus_set_state(dev, XenbusStateConnected);
1255185605Skmacy
1256181643Skmacy	/* Kick pending requests. */
1257251195Sgibbs	mtx_lock(&sc->xbd_io_lock);
1258251751Sgibbs	sc->xbd_state = XBD_STATE_CONNECTED;
1259251195Sgibbs	xbd_startio(sc);
1260251751Sgibbs	sc->xbd_flags |= XBDF_READY;
1261251195Sgibbs	mtx_unlock(&sc->xbd_io_lock);
1262181643Skmacy}
1263181643Skmacy
1264181643Skmacy/**
1265181643Skmacy * Handle the change of state of the backend to Closing.  We must delete our
1266181643Skmacy * device-layer structures now, to ensure that writes are flushed through to
1267201138Sgibbs * the backend.  Once this is done, we can switch to Closed in
1268181643Skmacy * acknowledgement.
1269181643Skmacy */
1270185605Skmacystatic void
1271251195Sgibbsxbd_closing(device_t dev)
1272181643Skmacy{
1273251195Sgibbs	struct xbd_softc *sc = device_get_softc(dev);
1274181643Skmacy
1275214077Sgibbs	xenbus_set_state(dev, XenbusStateClosing);
1276214077Sgibbs
1277251195Sgibbs	DPRINTK("xbd_closing: %s removed\n", xenbus_get_node(dev));
1278181643Skmacy
1279251195Sgibbs	if (sc->xbd_disk != NULL) {
1280251195Sgibbs		disk_destroy(sc->xbd_disk);
1281251195Sgibbs		sc->xbd_disk = NULL;
1282181643Skmacy	}
1283181643Skmacy
1284214077Sgibbs	xenbus_set_state(dev, XenbusStateClosed);
1285181643Skmacy}
1286181643Skmacy
1287251204Sgibbs/*---------------------------- NewBus Entrypoints ----------------------------*/
1288185605Skmacystatic int
1289251204Sgibbsxbd_probe(device_t dev)
1290181643Skmacy{
1291256757Sgibbs	if (strcmp(xenbus_get_type(dev), "vbd") != 0)
1292256757Sgibbs		return (ENXIO);
1293181643Skmacy
1294256757Sgibbs	if (xen_hvm_domain()) {
1295256757Sgibbs		int error;
1296256757Sgibbs		char *type;
1297256757Sgibbs
1298256757Sgibbs		/*
1299256757Sgibbs		 * When running in an HVM domain, IDE disk emulation is
1300256757Sgibbs		 * disabled early in boot so that native drivers will
1301256757Sgibbs		 * not see emulated hardware.  However, CDROM device
1302256757Sgibbs		 * emulation cannot be disabled.
1303256757Sgibbs		 *
1304256757Sgibbs		 * Through use of FreeBSD's vm_guest and xen_hvm_domain()
1305256757Sgibbs		 * APIs, we could modify the native CDROM driver to fail its
1306256757Sgibbs		 * probe when running under Xen.  Unfortunatlely, the PV
1307256757Sgibbs		 * CDROM support in XenServer (up through at least version
1308256757Sgibbs		 * 6.2) isn't functional, so we instead rely on the emulated
1309256757Sgibbs		 * CDROM instance, and fail to attach the PV one here in
1310256757Sgibbs		 * the blkfront driver.
1311256757Sgibbs		 */
1312256757Sgibbs		error = xs_read(XST_NIL, xenbus_get_node(dev),
1313256757Sgibbs		    "device-type", NULL, (void **) &type);
1314256757Sgibbs		if (error)
1315256757Sgibbs			return (ENXIO);
1316256757Sgibbs
1317256757Sgibbs		if (strncmp(type, "cdrom", 5) == 0) {
1318256757Sgibbs			free(type, M_XENSTORE);
1319256757Sgibbs			return (ENXIO);
1320256757Sgibbs		}
1321256757Sgibbs		free(type, M_XENSTORE);
1322181643Skmacy	}
1323181643Skmacy
1324256757Sgibbs	device_set_desc(dev, "Virtual Block Device");
1325256757Sgibbs	device_quiet(dev);
1326256757Sgibbs	return (0);
1327181643Skmacy}
1328181643Skmacy
1329251204Sgibbs/*
1330251204Sgibbs * Setup supplies the backend dir, virtual device.  We place an event
1331251204Sgibbs * channel and shared frame entries.  We watch backend to wait if it's
1332251204Sgibbs * ok.
1333251204Sgibbs */
1334181643Skmacystatic int
1335251204Sgibbsxbd_attach(device_t dev)
1336181643Skmacy{
1337251204Sgibbs	struct xbd_softc *sc;
1338251204Sgibbs	const char *name;
1339251204Sgibbs	uint32_t vdevice;
1340251204Sgibbs	int error;
1341251204Sgibbs	int i;
1342251204Sgibbs	int unit;
1343181643Skmacy
1344251204Sgibbs	/* FIXME: Use dynamic device id if this is not set. */
1345251204Sgibbs	error = xs_scanf(XST_NIL, xenbus_get_node(dev),
1346251204Sgibbs	    "virtual-device", NULL, "%" PRIu32, &vdevice);
1347255051Scperciva	if (error)
1348255051Scperciva		error = xs_scanf(XST_NIL, xenbus_get_node(dev),
1349255051Scperciva		    "virtual-device-ext", NULL, "%" PRIu32, &vdevice);
1350251204Sgibbs	if (error) {
1351251204Sgibbs		xenbus_dev_fatal(dev, error, "reading virtual-device");
1352251204Sgibbs		device_printf(dev, "Couldn't determine virtual device.\n");
1353251204Sgibbs		return (error);
1354181643Skmacy	}
1355181643Skmacy
1356251204Sgibbs	xbd_vdevice_to_unit(vdevice, &unit, &name);
1357251204Sgibbs	if (!strcmp(name, "xbd"))
1358251204Sgibbs		device_set_unit(dev, unit);
1359181643Skmacy
1360251204Sgibbs	sc = device_get_softc(dev);
1361251204Sgibbs	mtx_init(&sc->xbd_io_lock, "blkfront i/o lock", NULL, MTX_DEF);
1362251751Sgibbs	xbd_initqs(sc);
1363251204Sgibbs	for (i = 0; i < XBD_MAX_RING_PAGES; i++)
1364251214Sgibbs		sc->xbd_ring_ref[i] = GRANT_REF_INVALID;
1365181643Skmacy
1366251204Sgibbs	sc->xbd_dev = dev;
1367251204Sgibbs	sc->xbd_vdevice = vdevice;
1368251751Sgibbs	sc->xbd_state = XBD_STATE_DISCONNECTED;
1369181643Skmacy
1370251204Sgibbs	xbd_setup_sysctl(sc);
1371181643Skmacy
1372251204Sgibbs	/* Wait for backend device to publish its protocol capabilities. */
1373251204Sgibbs	xenbus_set_state(dev, XenbusStateInitialising);
1374199960Skmacy
1375251204Sgibbs	return (0);
1376199960Skmacy}
1377199960Skmacy
1378251204Sgibbsstatic int
1379251204Sgibbsxbd_detach(device_t dev)
1380181643Skmacy{
1381251204Sgibbs	struct xbd_softc *sc = device_get_softc(dev);
1382181643Skmacy
1383251751Sgibbs	DPRINTK("%s: %s removed\n", __func__, xenbus_get_node(dev));
1384181643Skmacy
1385251204Sgibbs	xbd_free(sc);
1386251204Sgibbs	mtx_destroy(&sc->xbd_io_lock);
1387199960Skmacy
1388251204Sgibbs	return 0;
1389199960Skmacy}
1390181643Skmacy
1391199960Skmacystatic int
1392251204Sgibbsxbd_suspend(device_t dev)
1393199960Skmacy{
1394251204Sgibbs	struct xbd_softc *sc = device_get_softc(dev);
1395251204Sgibbs	int retval;
1396251204Sgibbs	int saved_state;
1397181643Skmacy
1398251204Sgibbs	/* Prevent new requests being issued until we fix things up. */
1399251204Sgibbs	mtx_lock(&sc->xbd_io_lock);
1400251751Sgibbs	saved_state = sc->xbd_state;
1401251751Sgibbs	sc->xbd_state = XBD_STATE_SUSPENDED;
1402199960Skmacy
1403251204Sgibbs	/* Wait for outstanding I/O to drain. */
1404251204Sgibbs	retval = 0;
1405252260Sgibbs	while (xbd_queue_length(sc, XBD_Q_BUSY) != 0) {
1406251751Sgibbs		if (msleep(&sc->xbd_cm_q[XBD_Q_BUSY], &sc->xbd_io_lock,
1407251204Sgibbs		    PRIBIO, "blkf_susp", 30 * hz) == EWOULDBLOCK) {
1408251204Sgibbs			retval = EBUSY;
1409251204Sgibbs			break;
1410214077Sgibbs		}
1411199960Skmacy	}
1412251204Sgibbs	mtx_unlock(&sc->xbd_io_lock);
1413181643Skmacy
1414251204Sgibbs	if (retval != 0)
1415251751Sgibbs		sc->xbd_state = saved_state;
1416199960Skmacy
1417251204Sgibbs	return (retval);
1418199960Skmacy}
1419181643Skmacy
1420251204Sgibbsstatic int
1421251204Sgibbsxbd_resume(device_t dev)
1422181643Skmacy{
1423251204Sgibbs	struct xbd_softc *sc = device_get_softc(dev);
1424181643Skmacy
1425251204Sgibbs	DPRINTK("xbd_resume: %s\n", xenbus_get_node(dev));
1426181643Skmacy
1427251204Sgibbs	xbd_free(sc);
1428251204Sgibbs	xbd_initialize(sc);
1429251204Sgibbs	return (0);
1430181643Skmacy}
1431181643Skmacy
1432251204Sgibbs/**
1433251204Sgibbs * Callback received when the backend's state changes.
1434251204Sgibbs */
1435181643Skmacystatic void
1436251204Sgibbsxbd_backend_changed(device_t dev, XenbusState backend_state)
1437181643Skmacy{
1438251204Sgibbs	struct xbd_softc *sc = device_get_softc(dev);
1439181643Skmacy
1440251204Sgibbs	DPRINTK("backend_state=%d\n", backend_state);
1441181643Skmacy
1442251204Sgibbs	switch (backend_state) {
1443251204Sgibbs	case XenbusStateUnknown:
1444251204Sgibbs	case XenbusStateInitialising:
1445251204Sgibbs	case XenbusStateReconfigured:
1446251204Sgibbs	case XenbusStateReconfiguring:
1447251204Sgibbs	case XenbusStateClosed:
1448251204Sgibbs		break;
1449181643Skmacy
1450251204Sgibbs	case XenbusStateInitWait:
1451251204Sgibbs	case XenbusStateInitialised:
1452251204Sgibbs		xbd_initialize(sc);
1453251204Sgibbs		break;
1454181643Skmacy
1455251204Sgibbs	case XenbusStateConnected:
1456251204Sgibbs		xbd_initialize(sc);
1457251204Sgibbs		xbd_connect(sc);
1458251204Sgibbs		break;
1459181643Skmacy
1460251204Sgibbs	case XenbusStateClosing:
1461251204Sgibbs		if (sc->xbd_users > 0)
1462251204Sgibbs			xenbus_dev_error(dev, -EBUSY,
1463251204Sgibbs			    "Device in use; refusing to close");
1464199960Skmacy		else
1465251204Sgibbs			xbd_closing(dev);
1466251204Sgibbs		break;
1467181643Skmacy	}
1468181643Skmacy}
1469181643Skmacy
1470251204Sgibbs/*---------------------------- NewBus Registration ---------------------------*/
1471251195Sgibbsstatic device_method_t xbd_methods[] = {
1472185605Skmacy	/* Device interface */
1473251195Sgibbs	DEVMETHOD(device_probe,         xbd_probe),
1474251195Sgibbs	DEVMETHOD(device_attach,        xbd_attach),
1475251195Sgibbs	DEVMETHOD(device_detach,        xbd_detach),
1476185605Skmacy	DEVMETHOD(device_shutdown,      bus_generic_shutdown),
1477251195Sgibbs	DEVMETHOD(device_suspend,       xbd_suspend),
1478251195Sgibbs	DEVMETHOD(device_resume,        xbd_resume),
1479185605Skmacy
1480185605Skmacy	/* Xenbus interface */
1481251195Sgibbs	DEVMETHOD(xenbus_otherend_changed, xbd_backend_changed),
1482181643Skmacy
1483185605Skmacy	{ 0, 0 }
1484185605Skmacy};
1485181643Skmacy
1486251195Sgibbsstatic driver_t xbd_driver = {
1487185605Skmacy	"xbd",
1488251195Sgibbs	xbd_methods,
1489251195Sgibbs	sizeof(struct xbd_softc),
1490185605Skmacy};
1491251195Sgibbsdevclass_t xbd_devclass;
1492185605Skmacy
1493251195SgibbsDRIVER_MODULE(xbd, xenbusb_front, xbd_driver, xbd_devclass, 0, 0);
1494