xref: /illumos-gate/usr/src/uts/common/xen/io/xdb.c (revision 002c70ff32f5df6f93c15f88d351ce26443e6ee7)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * Note: This is the backend part of the split PV disk driver. This driver
29  * is not a nexus driver, nor is it a leaf driver(block/char/stream driver).
30  * Currently, it does not create any minor node. So, although, it runs in
31  * backend domain, it will not be used directly from within dom0.
32  * It simply gets block I/O requests issued by frontend from a shared page
33  * (blkif ring buffer - defined by Xen) between backend and frontend domain,
34  * generates a buf, and push it down to underlying disk target driver via
35  * ldi interface. When buf is done, this driver will generate a response
36  * and put it into ring buffer to inform frontend of the status of the I/O
37  * request issued by it. When a new virtual device entry is added in xenstore,
38  * there will be an watch event sent from Xen to xvdi framework, who will,
39  * in turn, create the devinfo node and try to attach this driver
40  * (see xvdi_create_dev). When frontend peer changes its state to
41  * XenbusStateClose, an event will also be sent from Xen to xvdi framework,
42  * who will detach and remove this devinfo node (see i_xvdi_oestate_handler).
43  * I/O requests get from ring buffer and event coming from xenstore cannot be
44  * trusted. We verify them in xdb_get_buf() and xdb_check_state_transition().
45  *
46  * Virtual device configuration is read/written from/to the database via
47  * xenbus_* interfaces. Driver also use xvdi_* to interact with hypervisor.
48  * There is an on-going effort to make xvdi_* cover all xenbus_*.
49  */
50 
51 #pragma ident	"%Z%%M%	%I%	%E% SMI"
52 
53 #include "xdb.h"
54 #include <sys/lofi.h>
55 #include <vm/hat_i86.h>
56 
57 static xdb_t *xdb_statep;
58 static int xdb_debug = 0;
59 
60 #ifdef DEBUG
61 /*
62  * debug aid functions
63  */
64 
65 static void
66 logva(xdb_t *vdp, uint64_t va)
67 {
68 	uint64_t *page_addrs;
69 	int i;
70 
71 	page_addrs = vdp->page_addrs;
72 	for (i = 0; i < XDB_MAX_IO_PAGES; i++) {
73 		if (page_addrs[i] == va)
74 			debug_enter("VA remapping found!");
75 	}
76 
77 	for (i = 0; i < XDB_MAX_IO_PAGES; i++) {
78 		if (page_addrs[i] == 0) {
79 			page_addrs[i] = va;
80 			break;
81 		}
82 	}
83 	ASSERT(i < XDB_MAX_IO_PAGES);
84 }
85 
86 static void
87 unlogva(xdb_t *vdp, uint64_t va)
88 {
89 	uint64_t *page_addrs;
90 	int i;
91 
92 	page_addrs = vdp->page_addrs;
93 	for (i = 0; i < XDB_MAX_IO_PAGES; i++) {
94 		if (page_addrs[i] == va) {
95 			page_addrs[i] = 0;
96 			break;
97 		}
98 	}
99 	ASSERT(i < XDB_MAX_IO_PAGES);
100 }
101 
102 static void
103 xdb_dump_request_oe(blkif_request_t *req)
104 {
105 	int i;
106 
107 	/*
108 	 * Exploit the public interface definitions for BLKIF_OP_READ
109 	 * etc..
110 	 */
111 	char *op_name[] = { "read", "write", "barrier", "flush" };
112 
113 	XDB_DBPRINT(XDB_DBG_IO, (CE_NOTE, "op=%s", op_name[req->operation]));
114 	XDB_DBPRINT(XDB_DBG_IO, (CE_NOTE, "num of segments=%d",
115 	    req->nr_segments));
116 	XDB_DBPRINT(XDB_DBG_IO, (CE_NOTE, "handle=%d", req->handle));
117 	XDB_DBPRINT(XDB_DBG_IO, (CE_NOTE, "id=%llu",
118 	    (unsigned long long)req->id));
119 	XDB_DBPRINT(XDB_DBG_IO, (CE_NOTE, "start sector=%llu",
120 	    (unsigned long long)req->sector_number));
121 	for (i = 0; i < req->nr_segments; i++) {
122 		XDB_DBPRINT(XDB_DBG_IO, (CE_NOTE, "gref=%d, first sec=%d,"
123 		    "last sec=%d", req->seg[i].gref, req->seg[i].first_sect,
124 		    req->seg[i].last_sect));
125 	}
126 }
127 #endif /* DEBUG */
128 
129 /*
130  * Statistics.
131  */
132 static char *xdb_stats[] = {
133 	"rd_reqs",
134 	"wr_reqs",
135 	"br_reqs",
136 	"fl_reqs",
137 	"oo_reqs"
138 };
139 
140 static int
141 xdb_kstat_update(kstat_t *ksp, int flag)
142 {
143 	xdb_t *vdp;
144 	kstat_named_t *knp;
145 
146 	if (flag != KSTAT_READ)
147 		return (EACCES);
148 
149 	vdp = ksp->ks_private;
150 	knp = ksp->ks_data;
151 
152 	/*
153 	 * Assignment order should match that of the names in
154 	 * xdb_stats.
155 	 */
156 	(knp++)->value.ui64 = vdp->xs_stat_req_reads;
157 	(knp++)->value.ui64 = vdp->xs_stat_req_writes;
158 	(knp++)->value.ui64 = vdp->xs_stat_req_barriers;
159 	(knp++)->value.ui64 = vdp->xs_stat_req_flushes;
160 	(knp++)->value.ui64 = 0; /* oo_req */
161 
162 	return (0);
163 }
164 
165 static boolean_t
166 xdb_kstat_init(xdb_t *vdp)
167 {
168 	int nstat = sizeof (xdb_stats) / sizeof (xdb_stats[0]);
169 	char **cp = xdb_stats;
170 	kstat_named_t *knp;
171 
172 	if ((vdp->xs_kstats = kstat_create("xdb",
173 	    ddi_get_instance(vdp->xs_dip),
174 	    "req_statistics", "block", KSTAT_TYPE_NAMED,
175 	    nstat, 0)) == NULL)
176 		return (B_FALSE);
177 
178 	vdp->xs_kstats->ks_private = vdp;
179 	vdp->xs_kstats->ks_update = xdb_kstat_update;
180 
181 	knp = vdp->xs_kstats->ks_data;
182 	while (nstat > 0) {
183 		kstat_named_init(knp, *cp, KSTAT_DATA_UINT64);
184 		knp++;
185 		cp++;
186 		nstat--;
187 	}
188 
189 	kstat_install(vdp->xs_kstats);
190 
191 	return (B_TRUE);
192 }
193 
194 static int xdb_biodone(buf_t *);
195 
196 static buf_t *
197 xdb_get_buf(xdb_t *vdp, blkif_request_t *req, xdb_request_t *xreq)
198 {
199 	buf_t *bp;
200 	uint8_t segs, curseg;
201 	int sectors;
202 	int i, err;
203 	gnttab_map_grant_ref_t mapops[BLKIF_MAX_SEGMENTS_PER_REQUEST];
204 	ddi_acc_handle_t acchdl;
205 
206 	acchdl = vdp->xs_ring_hdl;
207 	bp = XDB_XREQ2BP(xreq);
208 	curseg = xreq->xr_curseg;
209 	/* init a new xdb request */
210 	if (req != NULL) {
211 		ASSERT(MUTEX_HELD(&vdp->xs_iomutex));
212 		boolean_t pagemapok = B_TRUE;
213 		uint8_t op = ddi_get8(acchdl, &req->operation);
214 
215 		xreq->xr_vdp = vdp;
216 		xreq->xr_op = op;
217 		xreq->xr_id = ddi_get64(acchdl, &req->id);
218 		segs = xreq->xr_buf_pages = ddi_get8(acchdl, &req->nr_segments);
219 		if (segs == 0) {
220 			if (op != BLKIF_OP_FLUSH_DISKCACHE)
221 				cmn_err(CE_WARN, "!non-BLKIF_OP_FLUSH_DISKCACHE"
222 				    " is seen from domain %d with zero "
223 				    "length data buffer!", vdp->xs_peer);
224 			bioinit(bp);
225 			bp->b_bcount = 0;
226 			bp->b_lblkno = 0;
227 			bp->b_un.b_addr = NULL;
228 			return (bp);
229 		} else if (op == BLKIF_OP_FLUSH_DISKCACHE) {
230 			cmn_err(CE_WARN, "!BLKIF_OP_FLUSH_DISKCACHE"
231 			    " is seen from domain %d with non-zero "
232 			    "length data buffer!", vdp->xs_peer);
233 		}
234 
235 		/*
236 		 * segs should be no bigger than BLKIF_MAX_SEGMENTS_PER_REQUEST
237 		 * according to the definition of blk interface by Xen
238 		 * we do sanity check here
239 		 */
240 		if (segs > BLKIF_MAX_SEGMENTS_PER_REQUEST)
241 			segs = xreq->xr_buf_pages =
242 			    BLKIF_MAX_SEGMENTS_PER_REQUEST;
243 
244 		for (i = 0; i < segs; i++) {
245 			uint8_t fs, ls;
246 
247 			mapops[i].host_addr =
248 			    (uint64_t)(uintptr_t)XDB_IOPAGE_VA(
249 			    vdp->xs_iopage_va, xreq->xr_idx, i);
250 			mapops[i].dom = vdp->xs_peer;
251 			mapops[i].ref = ddi_get32(acchdl, &req->seg[i].gref);
252 			mapops[i].flags = GNTMAP_host_map;
253 			if (op != BLKIF_OP_READ)
254 				mapops[i].flags |= GNTMAP_readonly;
255 
256 			fs = ddi_get8(acchdl, &req->seg[i].first_sect);
257 			ls = ddi_get8(acchdl, &req->seg[i].last_sect);
258 
259 			/*
260 			 * first_sect should be no bigger than last_sect and
261 			 * both of them should be no bigger than
262 			 * (PAGESIZE / XB_BSIZE - 1) according to definition
263 			 * of blk interface by Xen, so sanity check again
264 			 */
265 			if (fs > (PAGESIZE / XB_BSIZE - 1))
266 				fs = PAGESIZE / XB_BSIZE - 1;
267 			if (ls > (PAGESIZE / XB_BSIZE - 1))
268 				ls = PAGESIZE / XB_BSIZE - 1;
269 			if (fs > ls)
270 				fs = ls;
271 
272 			xreq->xr_segs[i].fs = fs;
273 			xreq->xr_segs[i].ls = ls;
274 		}
275 
276 		/* map in io pages */
277 		err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref,
278 		    mapops, i);
279 		if (err != 0)
280 			return (NULL);
281 		for (i = 0; i < segs; i++) {
282 			/*
283 			 * Although HYPERVISOR_grant_table_op() returned no
284 			 * error, mapping of each single page can fail. So,
285 			 * we have to do the check here and handle the error
286 			 * if needed
287 			 */
288 			if (mapops[i].status != GNTST_okay) {
289 				int j;
290 				for (j = 0; j < i; j++) {
291 #ifdef DEBUG
292 					unlogva(vdp, mapops[j].host_addr);
293 #endif
294 					xen_release_pfn(
295 					    xreq->xr_plist[j].p_pagenum);
296 				}
297 				pagemapok = B_FALSE;
298 				break;
299 			}
300 			/* record page mapping handle for unmapping later */
301 			xreq->xr_page_hdls[i] = mapops[i].handle;
302 #ifdef DEBUG
303 			logva(vdp, mapops[i].host_addr);
304 #endif
305 			/*
306 			 * Pass the MFNs down using the shadow list (xr_pplist)
307 			 *
308 			 * This is pretty ugly since we have implict knowledge
309 			 * of how the rootnex binds buffers.
310 			 * The GNTTABOP_map_grant_ref op makes us do some ugly
311 			 * stuff since we're not allowed to touch these PTEs
312 			 * from the VM.
313 			 *
314 			 * Obviously, these aren't real page_t's. The rootnex
315 			 * only needs p_pagenum.
316 			 * Also, don't use btop() here or 32 bit PAE breaks.
317 			 */
318 			xreq->xr_pplist[i] = &xreq->xr_plist[i];
319 			xreq->xr_plist[i].p_pagenum =
320 			    xen_assign_pfn(mapops[i].dev_bus_addr >> PAGESHIFT);
321 		}
322 
323 		/*
324 		 * not all pages mapped in successfully, unmap those mapped-in
325 		 * page and return failure
326 		 */
327 		if (!pagemapok) {
328 			gnttab_unmap_grant_ref_t unmapop;
329 
330 			for (i = 0; i < segs; i++) {
331 				if (mapops[i].status != GNTST_okay)
332 					continue;
333 				unmapop.host_addr =
334 				    (uint64_t)(uintptr_t)XDB_IOPAGE_VA(
335 				    vdp->xs_iopage_va, xreq->xr_idx, i);
336 				unmapop.dev_bus_addr = NULL;
337 				unmapop.handle = mapops[i].handle;
338 				(void) HYPERVISOR_grant_table_op(
339 				    GNTTABOP_unmap_grant_ref, &unmapop, 1);
340 			}
341 
342 			return (NULL);
343 		}
344 		bioinit(bp);
345 		bp->b_lblkno = ddi_get64(acchdl, &req->sector_number);
346 		bp->b_flags = B_BUSY | B_SHADOW | B_PHYS;
347 		bp->b_flags |= (ddi_get8(acchdl, &req->operation) ==
348 		    BLKIF_OP_READ) ? B_READ : (B_WRITE | B_ASYNC);
349 	} else {
350 		uint64_t blkst;
351 		int isread;
352 
353 		/* reuse this buf */
354 		blkst = bp->b_lblkno + bp->b_bcount / DEV_BSIZE;
355 		isread = bp->b_flags & B_READ;
356 		bioreset(bp);
357 		bp->b_lblkno = blkst;
358 		bp->b_flags = B_BUSY | B_SHADOW | B_PHYS;
359 		bp->b_flags |= isread ? B_READ : (B_WRITE | B_ASYNC);
360 		XDB_DBPRINT(XDB_DBG_IO, (CE_NOTE, "reuse buf, xreq is %d!!",
361 		    xreq->xr_idx));
362 	}
363 
364 	/* form a buf */
365 	bp->b_un.b_addr = XDB_IOPAGE_VA(vdp->xs_iopage_va, xreq->xr_idx,
366 	    curseg) + xreq->xr_segs[curseg].fs * DEV_BSIZE;
367 	bp->b_shadow = &xreq->xr_pplist[curseg];
368 	bp->b_iodone = xdb_biodone;
369 	sectors = 0;
370 	for (i = curseg; i < xreq->xr_buf_pages; i++) {
371 		/*
372 		 * The xreq->xr_segs[i].fs of the first seg can be non-zero
373 		 * otherwise, we'll break it into multiple bufs
374 		 */
375 		if ((i != curseg) && (xreq->xr_segs[i].fs != 0)) {
376 			break;
377 		}
378 		sectors += (xreq->xr_segs[i].ls - xreq->xr_segs[i].fs + 1);
379 	}
380 	xreq->xr_curseg = i;
381 	bp->b_bcount = sectors * DEV_BSIZE;
382 	bp->b_bufsize = bp->b_bcount;
383 
384 	return (bp);
385 }
386 
387 static xdb_request_t *
388 xdb_get_req(xdb_t *vdp)
389 {
390 	xdb_request_t *req;
391 	int idx;
392 
393 	ASSERT(MUTEX_HELD(&vdp->xs_iomutex));
394 	ASSERT(vdp->xs_free_req != -1);
395 	req = &vdp->xs_req[vdp->xs_free_req];
396 	vdp->xs_free_req = req->xr_next;
397 	idx = req->xr_idx;
398 	bzero(req, sizeof (xdb_request_t));
399 	req->xr_idx = idx;
400 	return (req);
401 }
402 
403 static void
404 xdb_free_req(xdb_request_t *req)
405 {
406 	xdb_t *vdp = req->xr_vdp;
407 
408 	ASSERT(MUTEX_HELD(&vdp->xs_iomutex));
409 	req->xr_next = vdp->xs_free_req;
410 	vdp->xs_free_req = req->xr_idx;
411 }
412 
413 static void
414 xdb_response(xdb_t *vdp, blkif_request_t *req, boolean_t ok)
415 {
416 	xendev_ring_t *ringp = vdp->xs_ring;
417 	ddi_acc_handle_t acchdl = vdp->xs_ring_hdl;
418 	blkif_response_t *resp;
419 
420 	resp = xvdi_ring_get_response(ringp);
421 	ASSERT(resp);
422 
423 	ddi_put64(acchdl, &resp->id, ddi_get64(acchdl, &req->id));
424 	ddi_put8(acchdl, &resp->operation, ddi_get8(acchdl, &req->operation));
425 	ddi_put16(acchdl, (uint16_t *)&resp->status,
426 	    ok ? BLKIF_RSP_OKAY : BLKIF_RSP_ERROR);
427 	if (xvdi_ring_push_response(ringp))
428 		xvdi_notify_oe(vdp->xs_dip);
429 }
430 
431 static void
432 xdb_init_ioreqs(xdb_t *vdp)
433 {
434 	int i;
435 
436 	for (i = 0; i < BLKIF_RING_SIZE; i++) {
437 		vdp->xs_req[i].xr_idx = i;
438 		vdp->xs_req[i].xr_next = i + 1;
439 	}
440 	vdp->xs_req[BLKIF_RING_SIZE - 1].xr_next = -1;
441 	vdp->xs_free_req = 0;
442 
443 	/* alloc va in host dom for io page mapping */
444 	vdp->xs_iopage_va = vmem_xalloc(heap_arena,
445 	    XDB_MAX_IO_PAGES * PAGESIZE, PAGESIZE, 0, 0, 0, 0,
446 	    VM_SLEEP);
447 	for (i = 0; i < XDB_MAX_IO_PAGES; i++)
448 		hat_prepare_mapping(kas.a_hat,
449 		    vdp->xs_iopage_va + i * PAGESIZE);
450 }
451 
452 static void
453 xdb_uninit_ioreqs(xdb_t *vdp)
454 {
455 	int i;
456 
457 	for (i = 0; i < XDB_MAX_IO_PAGES; i++)
458 		hat_release_mapping(kas.a_hat,
459 		    vdp->xs_iopage_va + i * PAGESIZE);
460 	vmem_xfree(heap_arena, vdp->xs_iopage_va,
461 	    XDB_MAX_IO_PAGES * PAGESIZE);
462 }
463 
464 static uint_t
465 xdb_intr(caddr_t arg)
466 {
467 	xendev_ring_t *ringp;
468 	blkif_request_t *req;
469 	xdb_request_t *xreq;
470 	buf_t *bp;
471 	uint8_t op;
472 	xdb_t *vdp = (xdb_t *)arg;
473 	int ret = DDI_INTR_UNCLAIMED;
474 	dev_info_t *dip = vdp->xs_dip;
475 
476 	XDB_DBPRINT(XDB_DBG_IO, (CE_NOTE,
477 	    "xdb@%s: I/O request received from dom %d",
478 	    ddi_get_name_addr(dip), vdp->xs_peer));
479 
480 	mutex_enter(&vdp->xs_iomutex);
481 
482 	/* shouldn't touch ring buffer if not in connected state */
483 	if (vdp->xs_if_status != XDB_CONNECTED) {
484 		mutex_exit(&vdp->xs_iomutex);
485 		return (DDI_INTR_UNCLAIMED);
486 	}
487 
488 	ringp = vdp->xs_ring;
489 
490 	/*
491 	 * We'll loop till there is no more request in the ring
492 	 * We won't stuck in this loop for ever since the size of ring buffer
493 	 * is limited, and frontend will stop pushing requests into it when
494 	 * the ring buffer is full
495 	 */
496 
497 	/* req_event will be increased in xvdi_ring_get_request() */
498 	while ((req = xvdi_ring_get_request(ringp)) != NULL) {
499 		ret = DDI_INTR_CLAIMED;
500 
501 		op = ddi_get8(vdp->xs_ring_hdl, &req->operation);
502 		if (op == BLKIF_OP_READ			||
503 		    op == BLKIF_OP_WRITE		||
504 		    op == BLKIF_OP_WRITE_BARRIER	||
505 		    op == BLKIF_OP_FLUSH_DISKCACHE) {
506 #ifdef DEBUG
507 			xdb_dump_request_oe(req);
508 #endif
509 			xreq = xdb_get_req(vdp);
510 			ASSERT(xreq);
511 			switch (op) {
512 			case BLKIF_OP_READ:
513 				vdp->xs_stat_req_reads++;
514 				break;
515 			case BLKIF_OP_WRITE_BARRIER:
516 				vdp->xs_stat_req_barriers++;
517 				/* FALLTHRU */
518 			case BLKIF_OP_WRITE:
519 				vdp->xs_stat_req_writes++;
520 				break;
521 			case BLKIF_OP_FLUSH_DISKCACHE:
522 				vdp->xs_stat_req_flushes++;
523 				break;
524 			}
525 
526 			xreq->xr_curseg = 0; /* start from first segment */
527 			bp = xdb_get_buf(vdp, req, xreq);
528 			if (bp == NULL) {
529 				/* failed to form a buf */
530 				xdb_free_req(xreq);
531 				xdb_response(vdp, req, B_FALSE);
532 				continue;
533 			}
534 			bp->av_forw = NULL;
535 
536 			XDB_DBPRINT(XDB_DBG_IO, (CE_NOTE,
537 			    " buf %p, blkno %lld, size %lu, addr %p",
538 			    (void *)bp, (longlong_t)bp->b_blkno,
539 			    (ulong_t)bp->b_bcount, (void *)bp->b_un.b_addr));
540 
541 			/* send bp to underlying blk driver */
542 			if (vdp->xs_f_iobuf == NULL) {
543 				vdp->xs_f_iobuf = vdp->xs_l_iobuf = bp;
544 			} else {
545 				vdp->xs_l_iobuf->av_forw = bp;
546 				vdp->xs_l_iobuf = bp;
547 			}
548 			vdp->xs_ionum++;
549 		} else {
550 			xdb_response(vdp, req, B_FALSE);
551 			XDB_DBPRINT(XDB_DBG_IO, (CE_WARN, "xdb@%s: "
552 			    "Unsupported cmd received from dom %d",
553 			    ddi_get_name_addr(dip), vdp->xs_peer));
554 		}
555 	}
556 	/* notify our taskq to push buf to underlying blk driver */
557 	if (ret == DDI_INTR_CLAIMED)
558 		cv_broadcast(&vdp->xs_iocv);
559 
560 	mutex_exit(&vdp->xs_iomutex);
561 
562 	return (ret);
563 }
564 
565 static int
566 xdb_biodone(buf_t *bp)
567 {
568 	blkif_response_t *resp;
569 	int i, err, bioerr;
570 	uint8_t segs;
571 	gnttab_unmap_grant_ref_t unmapops[BLKIF_MAX_SEGMENTS_PER_REQUEST];
572 	xdb_request_t *xreq = XDB_BP2XREQ(bp);
573 	xdb_t *vdp = xreq->xr_vdp;
574 	xendev_ring_t *ringp = vdp->xs_ring;
575 	ddi_acc_handle_t acchdl = vdp->xs_ring_hdl;
576 	buf_t *nbp;
577 
578 	bioerr = geterror(bp);
579 	if (bioerr)
580 		XDB_DBPRINT(XDB_DBG_IO, (CE_WARN, "xdb@%s: I/O error %d",
581 		    ddi_get_name_addr(vdp->xs_dip), bioerr));
582 
583 	/* check if we are done w/ this I/O request */
584 	if ((bioerr == 0) && (xreq->xr_curseg < xreq->xr_buf_pages)) {
585 		nbp = xdb_get_buf(vdp, NULL, xreq);
586 		if (nbp) {
587 			err = ldi_strategy(vdp->xs_ldi_hdl, nbp);
588 			if (err == 0) {
589 				XDB_DBPRINT(XDB_DBG_IO, (CE_NOTE,
590 				    "sent buf to backend ok"));
591 				return (DDI_SUCCESS);
592 			}
593 			bioerr = EIO;
594 			XDB_DBPRINT(XDB_DBG_IO, (CE_WARN, "xdb@%s: "
595 			    "sent buf to backend dev failed, err=%d",
596 			    ddi_get_name_addr(vdp->xs_dip), err));
597 		} else {
598 			bioerr = EIO;
599 		}
600 	}
601 
602 	/* unmap io pages */
603 	segs = xreq->xr_buf_pages;
604 	/*
605 	 * segs should be no bigger than BLKIF_MAX_SEGMENTS_PER_REQUEST
606 	 * according to the definition of blk interface by Xen
607 	 */
608 	ASSERT(segs <= BLKIF_MAX_SEGMENTS_PER_REQUEST);
609 	for (i = 0; i < segs; i++) {
610 		unmapops[i].host_addr = (uint64_t)(uintptr_t)XDB_IOPAGE_VA(
611 		    vdp->xs_iopage_va, xreq->xr_idx, i);
612 #ifdef DEBUG
613 		mutex_enter(&vdp->xs_iomutex);
614 		unlogva(vdp, unmapops[i].host_addr);
615 		mutex_exit(&vdp->xs_iomutex);
616 #endif
617 		unmapops[i].dev_bus_addr = NULL;
618 		unmapops[i].handle = xreq->xr_page_hdls[i];
619 	}
620 	err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref,
621 	    unmapops, segs);
622 	ASSERT(!err);
623 
624 	/*
625 	 * If we have reached a barrier write or a cache flush , then we must
626 	 * flush all our I/Os.
627 	 */
628 	if (xreq->xr_op == BLKIF_OP_WRITE_BARRIER ||
629 	    xreq->xr_op == BLKIF_OP_FLUSH_DISKCACHE) {
630 		/*
631 		 * XXX At this point the write did succeed, so I don't
632 		 * believe we should report an error because the flush
633 		 * failed. However, this is a debatable point, so
634 		 * maybe we need to think more carefully about this.
635 		 * For now, just cast to void.
636 		 */
637 		(void) ldi_ioctl(vdp->xs_ldi_hdl,
638 		    DKIOCFLUSHWRITECACHE, NULL, FKIOCTL, kcred, NULL);
639 	}
640 
641 	mutex_enter(&vdp->xs_iomutex);
642 
643 	/* send response back to frontend */
644 	if (vdp->xs_if_status == XDB_CONNECTED) {
645 		resp = xvdi_ring_get_response(ringp);
646 		ASSERT(resp);
647 		ddi_put64(acchdl, &resp->id, xreq->xr_id);
648 		ddi_put8(acchdl, &resp->operation, xreq->xr_op);
649 		ddi_put16(acchdl, (uint16_t *)&resp->status,
650 		    bioerr ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY);
651 		if (xvdi_ring_push_response(ringp))
652 			xvdi_notify_oe(vdp->xs_dip);
653 		XDB_DBPRINT(XDB_DBG_IO, (CE_NOTE,
654 		    "sent resp back to frontend, id=%llu",
655 		    (unsigned long long)xreq->xr_id));
656 	}
657 	/* free io resources */
658 	biofini(bp);
659 	xdb_free_req(xreq);
660 
661 	vdp->xs_ionum--;
662 	if ((vdp->xs_if_status != XDB_CONNECTED) && (vdp->xs_ionum == 0))
663 		/* we're closing, someone is waiting for I/O clean-up */
664 		cv_signal(&vdp->xs_ionumcv);
665 
666 	mutex_exit(&vdp->xs_iomutex);
667 
668 	return (DDI_SUCCESS);
669 }
670 
671 static int
672 xdb_bindto_frontend(xdb_t *vdp)
673 {
674 	int err;
675 	char *oename;
676 	grant_ref_t gref;
677 	evtchn_port_t evtchn;
678 	dev_info_t *dip = vdp->xs_dip;
679 
680 	/*
681 	 * Gather info from frontend
682 	 */
683 	oename = xvdi_get_oename(dip);
684 	if (oename == NULL)
685 		return (DDI_FAILURE);
686 
687 	err = xenbus_gather(XBT_NULL, oename,
688 	    "ring-ref", "%lu", &gref, "event-channel", "%u", &evtchn, NULL);
689 	if (err != 0) {
690 		xvdi_fatal_error(dip, err,
691 		    "Getting ring-ref and evtchn from frontend");
692 		return (DDI_FAILURE);
693 	}
694 
695 	/*
696 	 * map and init ring
697 	 */
698 	err = xvdi_map_ring(dip, BLKIF_RING_SIZE,
699 	    sizeof (union blkif_sring_entry), gref, &vdp->xs_ring);
700 	if (err != DDI_SUCCESS)
701 		return (DDI_FAILURE);
702 	/*
703 	 * This will be removed after we use shadow I/O ring request since
704 	 * we don't need to access the ring itself directly, thus the access
705 	 * handle is not needed
706 	 */
707 	vdp->xs_ring_hdl = vdp->xs_ring->xr_acc_hdl;
708 
709 	/*
710 	 * bind event channel
711 	 */
712 	err = xvdi_bind_evtchn(dip, evtchn);
713 	if (err != DDI_SUCCESS) {
714 		xvdi_unmap_ring(vdp->xs_ring);
715 		return (DDI_FAILURE);
716 	}
717 
718 	return (DDI_SUCCESS);
719 }
720 
721 static void
722 xdb_unbindfrom_frontend(xdb_t *vdp)
723 {
724 	xvdi_free_evtchn(vdp->xs_dip);
725 	xvdi_unmap_ring(vdp->xs_ring);
726 }
727 
728 #define	LOFI_CTRL_NODE	"/dev/lofictl"
729 #define	LOFI_DEV_NODE	"/devices/pseudo/lofi@0:"
730 #define	LOFI_MODE	FREAD | FWRITE | FEXCL
731 
732 static int
733 xdb_setup_node(xdb_t *vdp, char *path)
734 {
735 	dev_info_t *dip;
736 	char *xsnode, *node;
737 	ldi_handle_t ldi_hdl;
738 	struct lofi_ioctl *li;
739 	int minor;
740 	int err;
741 	unsigned int len;
742 
743 	dip = vdp->xs_dip;
744 	xsnode = xvdi_get_xsname(dip);
745 	if (xsnode == NULL)
746 		return (DDI_FAILURE);
747 
748 	err = xenbus_read(XBT_NULL, xsnode, "params", (void **)&node, &len);
749 	if (err != 0) {
750 		xvdi_fatal_error(vdp->xs_dip, err, "reading 'params'");
751 		return (DDI_FAILURE);
752 	}
753 
754 	if (!XDB_IS_LOFI(vdp)) {
755 		(void) strlcpy(path, node, MAXPATHLEN + 1);
756 		kmem_free(node, len);
757 		return (DDI_SUCCESS);
758 	}
759 
760 	do {
761 		err = ldi_open_by_name(LOFI_CTRL_NODE, LOFI_MODE, kcred,
762 		    &ldi_hdl, vdp->xs_ldi_li);
763 	} while (err == EBUSY);
764 	if (err != 0) {
765 		kmem_free(node, len);
766 		return (DDI_FAILURE);
767 	}
768 
769 	li = kmem_zalloc(sizeof (*li), KM_SLEEP);
770 	(void) strlcpy(li->li_filename, node, MAXPATHLEN + 1);
771 	kmem_free(node, len);
772 	if (ldi_ioctl(ldi_hdl, LOFI_MAP_FILE, (intptr_t)li,
773 	    LOFI_MODE | FKIOCTL, kcred, &minor) != 0) {
774 		cmn_err(CE_WARN, "xdb@%s: Failed to create lofi dev for %s",
775 		    ddi_get_name_addr(dip), li->li_filename);
776 		(void) ldi_close(ldi_hdl, LOFI_MODE, kcred);
777 		kmem_free(li, sizeof (*li));
778 		return (DDI_FAILURE);
779 	}
780 	/*
781 	 * return '/devices/...' instead of '/dev/lofi/...' since the
782 	 * former is available immediately after calling ldi_ioctl
783 	 */
784 	(void) snprintf(path, MAXPATHLEN + 1, LOFI_DEV_NODE "%d", minor);
785 	(void) xenbus_printf(XBT_NULL, xsnode, "node", "%s", path);
786 	(void) ldi_close(ldi_hdl, LOFI_MODE, kcred);
787 	kmem_free(li, sizeof (*li));
788 	return (DDI_SUCCESS);
789 }
790 
791 static void
792 xdb_teardown_node(xdb_t *vdp)
793 {
794 	dev_info_t *dip;
795 	char *xsnode, *node;
796 	ldi_handle_t ldi_hdl;
797 	struct lofi_ioctl *li;
798 	int err;
799 	unsigned int len;
800 
801 	if (!XDB_IS_LOFI(vdp))
802 		return;
803 
804 	dip = vdp->xs_dip;
805 	xsnode = xvdi_get_xsname(dip);
806 	if (xsnode == NULL)
807 		return;
808 
809 	err = xenbus_read(XBT_NULL, xsnode, "params", (void **)&node, &len);
810 	if (err != 0) {
811 		xvdi_fatal_error(vdp->xs_dip, err, "reading 'params'");
812 		return;
813 	}
814 
815 	li = kmem_zalloc(sizeof (*li), KM_SLEEP);
816 	(void) strlcpy(li->li_filename, node, MAXPATHLEN + 1);
817 	kmem_free(node, len);
818 
819 	do {
820 		err = ldi_open_by_name(LOFI_CTRL_NODE, LOFI_MODE, kcred,
821 		    &ldi_hdl, vdp->xs_ldi_li);
822 	} while (err == EBUSY);
823 
824 	if (err != 0) {
825 		kmem_free(li, sizeof (*li));
826 		return;
827 	}
828 
829 	if (ldi_ioctl(ldi_hdl, LOFI_UNMAP_FILE, (intptr_t)li,
830 	    LOFI_MODE | FKIOCTL, kcred, NULL) != 0) {
831 		cmn_err(CE_WARN, "xdb@%s: Failed to delete lofi dev for %s",
832 		    ddi_get_name_addr(dip), li->li_filename);
833 	}
834 
835 	(void) ldi_close(ldi_hdl, LOFI_MODE, kcred);
836 	kmem_free(li, sizeof (*li));
837 }
838 
839 static int
840 xdb_open_device(xdb_t *vdp)
841 {
842 	uint64_t devsize;
843 	dev_info_t *dip;
844 	char *xsnode;
845 	char *nodepath;
846 	char *mode = NULL;
847 	char *type = NULL;
848 	int err;
849 
850 	dip = vdp->xs_dip;
851 	xsnode = xvdi_get_xsname(dip);
852 	if (xsnode == NULL)
853 		return (DDI_FAILURE);
854 
855 	err = xenbus_gather(XBT_NULL, xsnode,
856 	    "mode", NULL, &mode, "type", NULL, &type, NULL);
857 	if (err != 0) {
858 		if (mode)
859 			kmem_free(mode, strlen(mode) + 1);
860 		if (type)
861 			kmem_free(type, strlen(type) + 1);
862 		xvdi_fatal_error(dip, err,
863 		    "Getting mode and type from backend device");
864 		return (DDI_FAILURE);
865 	}
866 	if (strcmp(type, "file") == 0) {
867 		vdp->xs_type |= XDB_DEV_LOFI;
868 	}
869 	kmem_free(type, strlen(type) + 1);
870 	if ((strcmp(mode, "r") == NULL) || (strcmp(mode, "ro") == NULL)) {
871 		vdp->xs_type |= XDB_DEV_RO;
872 	}
873 	kmem_free(mode, strlen(mode) + 1);
874 
875 	/*
876 	 * try to open backend device
877 	 */
878 	if (ldi_ident_from_dip(dip, &vdp->xs_ldi_li) != 0)
879 		return (DDI_FAILURE);
880 
881 	nodepath = kmem_zalloc(MAXPATHLEN + 1, KM_SLEEP);
882 	err = xdb_setup_node(vdp, nodepath);
883 	if (err != DDI_SUCCESS) {
884 		xvdi_fatal_error(dip, err,
885 		    "Getting device path of backend device");
886 		ldi_ident_release(vdp->xs_ldi_li);
887 		kmem_free(nodepath, MAXPATHLEN + 1);
888 		return (DDI_FAILURE);
889 	}
890 
891 	if (ldi_open_by_name(nodepath,
892 	    FREAD | (XDB_IS_RO(vdp) ? 0 : FWRITE),
893 	    kcred, &vdp->xs_ldi_hdl, vdp->xs_ldi_li) != 0) {
894 		xdb_teardown_node(vdp);
895 		ldi_ident_release(vdp->xs_ldi_li);
896 		cmn_err(CE_WARN, "xdb@%s: Failed to open: %s",
897 		    ddi_get_name_addr(dip), nodepath);
898 		kmem_free(nodepath, MAXPATHLEN + 1);
899 		return (DDI_FAILURE);
900 	}
901 
902 	/* check if it's a CD/DVD disc */
903 	if (ldi_prop_get_int(vdp->xs_ldi_hdl, LDI_DEV_T_ANY | DDI_PROP_DONTPASS,
904 	    "inquiry-device-type", DTYPE_DIRECT) == DTYPE_RODIRECT)
905 		vdp->xs_type |= XDB_DEV_CD;
906 	/* check if it's a removable disk */
907 	if (ldi_prop_exists(vdp->xs_ldi_hdl,
908 	    LDI_DEV_T_ANY | DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
909 	    "removable-media"))
910 		vdp->xs_type |= XDB_DEV_RMB;
911 
912 	if (ldi_get_size(vdp->xs_ldi_hdl, &devsize) != DDI_SUCCESS) {
913 		(void) ldi_close(vdp->xs_ldi_hdl,
914 		    FREAD | (XDB_IS_RO(vdp) ? 0 : FWRITE), kcred);
915 		xdb_teardown_node(vdp);
916 		ldi_ident_release(vdp->xs_ldi_li);
917 		kmem_free(nodepath, MAXPATHLEN + 1);
918 		return (DDI_FAILURE);
919 	}
920 	vdp->xs_sectors = devsize / XB_BSIZE;
921 
922 	kmem_free(nodepath, MAXPATHLEN + 1);
923 	return (DDI_SUCCESS);
924 }
925 
926 static void
927 xdb_close_device(xdb_t *vdp)
928 {
929 	(void) ldi_close(vdp->xs_ldi_hdl,
930 	    FREAD | (XDB_IS_RO(vdp) ? 0 : FWRITE), kcred);
931 	xdb_teardown_node(vdp);
932 	ldi_ident_release(vdp->xs_ldi_li);
933 	vdp->xs_ldi_li = NULL;
934 	vdp->xs_ldi_hdl = NULL;
935 }
936 
937 /*
938  * Kick-off connect process
939  * If xs_fe_status == XDB_FE_READY and xs_dev_status == XDB_DEV_READY
940  * the xs_if_status will be changed to XDB_CONNECTED on success,
941  * otherwise, xs_if_status will not be changed
942  */
943 static int
944 xdb_start_connect(xdb_t *vdp)
945 {
946 	uint32_t dinfo;
947 	xenbus_transaction_t xbt;
948 	int err, svdst;
949 	char *xsnode;
950 	dev_info_t *dip = vdp->xs_dip;
951 	char *barrier;
952 	uint_t len;
953 
954 	/*
955 	 * Start connect to frontend only when backend device are ready
956 	 * and frontend has moved to XenbusStateInitialised, which means
957 	 * ready to connect
958 	 */
959 	ASSERT((vdp->xs_fe_status == XDB_FE_READY) &&
960 	    (vdp->xs_dev_status == XDB_DEV_READY));
961 
962 	if (((xsnode = xvdi_get_xsname(dip)) == NULL)		 ||
963 	    ((vdp->xs_peer = xvdi_get_oeid(dip)) == (domid_t)-1) ||
964 	    (xdb_open_device(vdp) != DDI_SUCCESS))
965 		return (DDI_FAILURE);
966 
967 	(void) xvdi_switch_state(dip, XBT_NULL, XenbusStateInitialised);
968 
969 	if (xdb_bindto_frontend(vdp) != DDI_SUCCESS)
970 		goto errout1;
971 
972 	/* init i/o requests */
973 	xdb_init_ioreqs(vdp);
974 
975 	if (ddi_add_intr(dip, 0, NULL, NULL, xdb_intr, (caddr_t)vdp)
976 	    != DDI_SUCCESS)
977 		goto errout2;
978 
979 	/*
980 	 * we can recieve intr any time from now on
981 	 * mark that we're ready to take intr
982 	 */
983 	mutex_enter(&vdp->xs_iomutex);
984 	/*
985 	 * save it in case we need to restore when we
986 	 * fail to write xenstore later
987 	 */
988 	svdst = vdp->xs_if_status;
989 	vdp->xs_if_status = XDB_CONNECTED;
990 	mutex_exit(&vdp->xs_iomutex);
991 
992 	/* write into xenstore the info needed by frontend */
993 trans_retry:
994 	if (xenbus_transaction_start(&xbt)) {
995 		xvdi_fatal_error(dip, EIO, "transaction start");
996 		goto errout3;
997 	}
998 
999 	/*
1000 	 * If feature-barrier isn't present in xenstore, add it.
1001 	 */
1002 	if (xenbus_read(xbt, xsnode, "feature-barrier",
1003 	    (void **)&barrier, &len) != 0) {
1004 		if ((err = xenbus_printf(xbt, xsnode, "feature-barrier",
1005 		    "%d", 1)) != 0) {
1006 			cmn_err(CE_WARN, "xdb@%s: failed to write "
1007 			    "'feature-barrier'", ddi_get_name_addr(dip));
1008 			xvdi_fatal_error(dip, err, "writing 'feature-barrier'");
1009 			goto abort_trans;
1010 		}
1011 	} else
1012 		kmem_free(barrier, len);
1013 
1014 	dinfo = 0;
1015 	if (XDB_IS_RO(vdp))
1016 		dinfo |= VDISK_READONLY;
1017 	if (XDB_IS_CD(vdp))
1018 		dinfo |= VDISK_CDROM;
1019 	if (XDB_IS_RMB(vdp))
1020 		dinfo |= VDISK_REMOVABLE;
1021 	if (err = xenbus_printf(xbt, xsnode, "info", "%u", dinfo)) {
1022 		xvdi_fatal_error(dip, err, "writing 'info'");
1023 		goto abort_trans;
1024 	}
1025 
1026 	/* hard-coded 512-byte sector size */
1027 	if (err = xenbus_printf(xbt, xsnode, "sector-size", "%u", DEV_BSIZE)) {
1028 		xvdi_fatal_error(dip, err, "writing 'sector-size'");
1029 		goto abort_trans;
1030 	}
1031 
1032 	if (err = xenbus_printf(xbt, xsnode, "sectors", "%"PRIu64,
1033 	    vdp->xs_sectors)) {
1034 		xvdi_fatal_error(dip, err, "writing 'sectors'");
1035 		goto abort_trans;
1036 	}
1037 
1038 	if (err = xenbus_printf(xbt, xsnode, "instance", "%d",
1039 	    ddi_get_instance(dip))) {
1040 		xvdi_fatal_error(dip, err, "writing 'instance'");
1041 		goto abort_trans;
1042 	}
1043 
1044 	if ((err = xvdi_switch_state(dip, xbt, XenbusStateConnected)) > 0) {
1045 		xvdi_fatal_error(dip, err, "writing 'state'");
1046 		goto abort_trans;
1047 	}
1048 
1049 	if (err = xenbus_transaction_end(xbt, 0)) {
1050 		if (err == EAGAIN)
1051 			/* transaction is ended, don't need to abort it */
1052 			goto trans_retry;
1053 		xvdi_fatal_error(dip, err, "completing transaction");
1054 		goto errout3;
1055 	}
1056 
1057 	return (DDI_SUCCESS);
1058 
1059 abort_trans:
1060 	(void) xenbus_transaction_end(xbt, 1);
1061 errout3:
1062 	mutex_enter(&vdp->xs_iomutex);
1063 	vdp->xs_if_status = svdst;
1064 	mutex_exit(&vdp->xs_iomutex);
1065 	ddi_remove_intr(dip, 0, NULL);
1066 errout2:
1067 	xdb_uninit_ioreqs(vdp);
1068 	xdb_unbindfrom_frontend(vdp);
1069 errout1:
1070 	xdb_close_device(vdp);
1071 	return (DDI_FAILURE);
1072 }
1073 
1074 /*
1075  * Kick-off disconnect process
1076  * xs_if_status will not be changed
1077  */
1078 static int
1079 xdb_start_disconnect(xdb_t *vdp)
1080 {
1081 	/*
1082 	 * Kick-off disconnect process
1083 	 */
1084 	if (xvdi_switch_state(vdp->xs_dip, XBT_NULL, XenbusStateClosing) > 0)
1085 		return (DDI_FAILURE);
1086 
1087 	return (DDI_SUCCESS);
1088 }
1089 
1090 /*
1091  * Disconnect from frontend and close backend device
1092  * ifstatus will be changed to XDB_DISCONNECTED
1093  * Xenbus state will be changed to XenbusStateClosed
1094  */
1095 static void
1096 xdb_close(dev_info_t *dip)
1097 {
1098 	xdb_t *vdp = (xdb_t *)ddi_get_driver_private(dip);
1099 
1100 	ASSERT(MUTEX_HELD(&vdp->xs_cbmutex));
1101 
1102 	mutex_enter(&vdp->xs_iomutex);
1103 
1104 	if (vdp->xs_if_status != XDB_CONNECTED) {
1105 		vdp->xs_if_status = XDB_DISCONNECTED;
1106 		cv_broadcast(&vdp->xs_iocv);
1107 		mutex_exit(&vdp->xs_iomutex);
1108 		(void) xvdi_switch_state(dip, XBT_NULL, XenbusStateClosed);
1109 		return;
1110 	}
1111 	vdp->xs_if_status = XDB_DISCONNECTED;
1112 	cv_broadcast(&vdp->xs_iocv);
1113 
1114 	mutex_exit(&vdp->xs_iomutex);
1115 
1116 	/* stop accepting I/O request from frontend */
1117 	ddi_remove_intr(dip, 0, NULL);
1118 	/* clear all on-going I/Os, if any */
1119 	mutex_enter(&vdp->xs_iomutex);
1120 	while (vdp->xs_ionum > 0)
1121 		cv_wait(&vdp->xs_ionumcv, &vdp->xs_iomutex);
1122 	mutex_exit(&vdp->xs_iomutex);
1123 
1124 	/* clean up resources and close this interface */
1125 	xdb_uninit_ioreqs(vdp);
1126 	xdb_unbindfrom_frontend(vdp);
1127 	xdb_close_device(vdp);
1128 	vdp->xs_peer = (domid_t)-1;
1129 	(void) xvdi_switch_state(dip, XBT_NULL, XenbusStateClosed);
1130 }
1131 
1132 /*
1133  * Xdb_check_state_transition will check the XenbusState change to see
1134  * if the change is a valid transition or not.
1135  * The new state is written by frontend domain, or by running xenstore-write
1136  * to change it manually in dom0
1137  */
1138 static int
1139 xdb_check_state_transition(xdb_t *vdp, XenbusState oestate)
1140 {
1141 	enum xdb_state status;
1142 	int stcheck;
1143 #define	STOK	0 /* need further process */
1144 #define	STNOP	1 /* no action need taking */
1145 #define	STBUG	2 /* unexpected state change, could be a bug */
1146 
1147 	status = vdp->xs_if_status;
1148 	stcheck = STOK;
1149 
1150 	switch (status) {
1151 	case XDB_UNKNOWN:
1152 		if (vdp->xs_fe_status == XDB_FE_UNKNOWN) {
1153 			if ((oestate == XenbusStateUnknown)		||
1154 			    (oestate == XenbusStateConnected))
1155 				stcheck = STBUG;
1156 			else if ((oestate == XenbusStateInitialising)	||
1157 			    (oestate == XenbusStateInitWait))
1158 				stcheck = STNOP;
1159 		} else {
1160 			if ((oestate == XenbusStateUnknown)		||
1161 			    (oestate == XenbusStateInitialising)	||
1162 			    (oestate == XenbusStateInitWait)		||
1163 			    (oestate == XenbusStateConnected))
1164 				stcheck = STBUG;
1165 			else if (oestate == XenbusStateInitialised)
1166 				stcheck = STNOP;
1167 		}
1168 		break;
1169 	case XDB_CONNECTED:
1170 		if ((oestate == XenbusStateUnknown)		||
1171 		    (oestate == XenbusStateInitialising)	||
1172 		    (oestate == XenbusStateInitWait)		||
1173 		    (oestate == XenbusStateInitialised))
1174 			stcheck = STBUG;
1175 		else if (oestate == XenbusStateConnected)
1176 			stcheck = STNOP;
1177 		break;
1178 	case XDB_DISCONNECTED:
1179 	default:
1180 			stcheck = STBUG;
1181 	}
1182 
1183 	if (stcheck == STOK)
1184 		return (DDI_SUCCESS);
1185 
1186 	if (stcheck == STBUG)
1187 		cmn_err(CE_NOTE, "xdb@%s: unexpected otherend "
1188 		    "state change to %d!, when status is %d",
1189 		    ddi_get_name_addr(vdp->xs_dip), oestate, status);
1190 
1191 	return (DDI_FAILURE);
1192 }
1193 
1194 static void
1195 xdb_send_buf(void *arg)
1196 {
1197 	buf_t *bp;
1198 	xdb_t *vdp = (xdb_t *)arg;
1199 
1200 	mutex_enter(&vdp->xs_iomutex);
1201 
1202 	while (vdp->xs_if_status != XDB_DISCONNECTED) {
1203 		while ((bp = vdp->xs_f_iobuf) != NULL) {
1204 			vdp->xs_f_iobuf = bp->av_forw;
1205 			bp->av_forw = NULL;
1206 			mutex_exit(&vdp->xs_iomutex);
1207 			if (bp->b_bcount != 0) {
1208 				int err = ldi_strategy(vdp->xs_ldi_hdl, bp);
1209 				if (err != 0) {
1210 					bp->b_flags |= B_ERROR;
1211 					(void) xdb_biodone(bp);
1212 					XDB_DBPRINT(XDB_DBG_IO, (CE_WARN,
1213 					    "xdb@%s: sent buf to backend dev"
1214 					    "failed, err=%d",
1215 					    ddi_get_name_addr(vdp->xs_dip),
1216 					    err));
1217 				} else {
1218 					XDB_DBPRINT(XDB_DBG_IO, (CE_NOTE,
1219 					    "sent buf to backend ok"));
1220 				}
1221 			} else /* no I/O need to be done */
1222 				(void) xdb_biodone(bp);
1223 
1224 			mutex_enter(&vdp->xs_iomutex);
1225 		}
1226 
1227 		if (vdp->xs_if_status != XDB_DISCONNECTED)
1228 			cv_wait(&vdp->xs_iocv, &vdp->xs_iomutex);
1229 	}
1230 
1231 	mutex_exit(&vdp->xs_iomutex);
1232 }
1233 
1234 /*ARGSUSED*/
1235 static void
1236 xdb_hp_state_change(dev_info_t *dip, ddi_eventcookie_t id, void *arg,
1237     void *impl_data)
1238 {
1239 	xendev_hotplug_state_t state = *(xendev_hotplug_state_t *)impl_data;
1240 	xdb_t *vdp = (xdb_t *)ddi_get_driver_private(dip);
1241 
1242 	XDB_DBPRINT(XDB_DBG_INFO, (CE_NOTE, "xdb@%s: "
1243 	    "hotplug status change to %d!", ddi_get_name_addr(dip), state));
1244 
1245 	mutex_enter(&vdp->xs_cbmutex);
1246 	if (state == Connected) {
1247 		/* Hotplug script has completed successfully */
1248 		if (vdp->xs_dev_status == XDB_DEV_UNKNOWN) {
1249 			vdp->xs_dev_status = XDB_DEV_READY;
1250 			if (vdp->xs_fe_status == XDB_FE_READY)
1251 				/* try to connect to frontend */
1252 				if (xdb_start_connect(vdp) != DDI_SUCCESS)
1253 					(void) xdb_start_disconnect(vdp);
1254 		}
1255 	}
1256 	mutex_exit(&vdp->xs_cbmutex);
1257 }
1258 
1259 /*ARGSUSED*/
1260 static void
1261 xdb_oe_state_change(dev_info_t *dip, ddi_eventcookie_t id, void *arg,
1262     void *impl_data)
1263 {
1264 	XenbusState new_state = *(XenbusState *)impl_data;
1265 	xdb_t *vdp = (xdb_t *)ddi_get_driver_private(dip);
1266 
1267 	XDB_DBPRINT(XDB_DBG_INFO, (CE_NOTE, "xdb@%s: "
1268 	    "otherend state change to %d!", ddi_get_name_addr(dip), new_state));
1269 
1270 	mutex_enter(&vdp->xs_cbmutex);
1271 
1272 	if (xdb_check_state_transition(vdp, new_state) == DDI_FAILURE) {
1273 		mutex_exit(&vdp->xs_cbmutex);
1274 		return;
1275 	}
1276 
1277 	switch (new_state) {
1278 	case XenbusStateInitialised:
1279 		ASSERT(vdp->xs_if_status == XDB_UNKNOWN);
1280 
1281 		/* frontend is ready for connecting */
1282 		vdp->xs_fe_status = XDB_FE_READY;
1283 
1284 		if (vdp->xs_dev_status == XDB_DEV_READY)
1285 			if (xdb_start_connect(vdp) != DDI_SUCCESS)
1286 				(void) xdb_start_disconnect(vdp);
1287 		break;
1288 	case XenbusStateClosing:
1289 		(void) xvdi_switch_state(dip, XBT_NULL, XenbusStateClosing);
1290 		break;
1291 	case XenbusStateClosed:
1292 		/* clean up */
1293 		xdb_close(dip);
1294 	}
1295 
1296 	mutex_exit(&vdp->xs_cbmutex);
1297 }
1298 
1299 static int
1300 xdb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
1301 {
1302 	xdb_t *vdp;
1303 	ddi_iblock_cookie_t ibc;
1304 	int instance;
1305 
1306 	switch (cmd) {
1307 	case DDI_RESUME:
1308 		return (DDI_FAILURE);
1309 	case DDI_ATTACH:
1310 		break;
1311 	default:
1312 		return (DDI_FAILURE);
1313 	}
1314 
1315 	/* DDI_ATTACH */
1316 	instance = ddi_get_instance(dip);
1317 	if (ddi_soft_state_zalloc(xdb_statep, instance) != DDI_SUCCESS)
1318 		return (DDI_FAILURE);
1319 
1320 	vdp = ddi_get_soft_state(xdb_statep, instance);
1321 	vdp->xs_dip = dip;
1322 	if (ddi_get_iblock_cookie(dip, 0, &ibc) != DDI_SUCCESS)
1323 		goto errout1;
1324 
1325 	if (!xdb_kstat_init(vdp))
1326 		goto errout1;
1327 
1328 	mutex_init(&vdp->xs_iomutex, NULL, MUTEX_DRIVER, (void *)ibc);
1329 	mutex_init(&vdp->xs_cbmutex, NULL, MUTEX_DRIVER, (void *)ibc);
1330 	cv_init(&vdp->xs_iocv, NULL, CV_DRIVER, NULL);
1331 	cv_init(&vdp->xs_ionumcv, NULL, CV_DRIVER, NULL);
1332 
1333 	ddi_set_driver_private(dip, vdp);
1334 
1335 	vdp->xs_iotaskq = ddi_taskq_create(dip, "xdb_iotask", 1,
1336 	    TASKQ_DEFAULTPRI, 0);
1337 	if (vdp->xs_iotaskq == NULL)
1338 		goto errout2;
1339 	(void) ddi_taskq_dispatch(vdp->xs_iotaskq, xdb_send_buf, vdp,
1340 	    DDI_SLEEP);
1341 
1342 	/* Watch frontend and hotplug state change */
1343 	if (xvdi_add_event_handler(dip, XS_OE_STATE, xdb_oe_state_change) !=
1344 	    DDI_SUCCESS)
1345 		goto errout3;
1346 	if (xvdi_add_event_handler(dip, XS_HP_STATE, xdb_hp_state_change) !=
1347 	    DDI_SUCCESS) {
1348 		goto errout4;
1349 	}
1350 
1351 	/*
1352 	 * Kick-off hotplug script
1353 	 */
1354 	if (xvdi_post_event(dip, XEN_HP_ADD) != DDI_SUCCESS) {
1355 		cmn_err(CE_WARN, "xdb@%s: failed to start hotplug script",
1356 		    ddi_get_name_addr(dip));
1357 		goto errout4;
1358 	}
1359 
1360 	/*
1361 	 * start waiting for hotplug event and otherend state event
1362 	 * mainly for debugging, frontend will not take any op seeing this
1363 	 */
1364 	(void) xvdi_switch_state(dip, XBT_NULL, XenbusStateInitWait);
1365 
1366 	XDB_DBPRINT(XDB_DBG_INFO, (CE_NOTE, "xdb@%s: attached!",
1367 	    ddi_get_name_addr(dip)));
1368 	return (DDI_SUCCESS);
1369 
1370 errout4:
1371 	xvdi_remove_event_handler(dip, NULL);
1372 errout3:
1373 	mutex_enter(&vdp->xs_cbmutex);
1374 	mutex_enter(&vdp->xs_iomutex);
1375 	vdp->xs_if_status = XDB_DISCONNECTED;
1376 	cv_broadcast(&vdp->xs_iocv);
1377 	mutex_exit(&vdp->xs_iomutex);
1378 	mutex_exit(&vdp->xs_cbmutex);
1379 	ddi_taskq_destroy(vdp->xs_iotaskq);
1380 errout2:
1381 	ddi_set_driver_private(dip, NULL);
1382 	cv_destroy(&vdp->xs_iocv);
1383 	cv_destroy(&vdp->xs_ionumcv);
1384 	mutex_destroy(&vdp->xs_cbmutex);
1385 	mutex_destroy(&vdp->xs_iomutex);
1386 	kstat_delete(vdp->xs_kstats);
1387 errout1:
1388 	ddi_soft_state_free(xdb_statep, instance);
1389 	return (DDI_FAILURE);
1390 }
1391 
1392 /*ARGSUSED*/
1393 static int
1394 xdb_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
1395 {
1396 	int instance = ddi_get_instance(dip);
1397 	xdb_t *vdp = XDB_INST2SOFTS(instance);
1398 
1399 	switch (cmd) {
1400 	case DDI_SUSPEND:
1401 		return (DDI_FAILURE);
1402 	case DDI_DETACH:
1403 		break;
1404 	default:
1405 		return (DDI_FAILURE);
1406 	}
1407 
1408 	/* DDI_DETACH handling */
1409 
1410 	/* shouldn't detach, if still used by frontend */
1411 	mutex_enter(&vdp->xs_iomutex);
1412 	if (vdp->xs_if_status != XDB_DISCONNECTED) {
1413 		mutex_exit(&vdp->xs_iomutex);
1414 		return (DDI_FAILURE);
1415 	}
1416 	mutex_exit(&vdp->xs_iomutex);
1417 
1418 	xvdi_remove_event_handler(dip, NULL);
1419 	/* can do nothing about it, if it fails */
1420 	(void) xvdi_post_event(dip, XEN_HP_REMOVE);
1421 
1422 	ddi_taskq_destroy(vdp->xs_iotaskq);
1423 	cv_destroy(&vdp->xs_iocv);
1424 	cv_destroy(&vdp->xs_ionumcv);
1425 	mutex_destroy(&vdp->xs_cbmutex);
1426 	mutex_destroy(&vdp->xs_iomutex);
1427 	kstat_delete(vdp->xs_kstats);
1428 	ddi_set_driver_private(dip, NULL);
1429 	ddi_soft_state_free(xdb_statep, instance);
1430 
1431 	XDB_DBPRINT(XDB_DBG_INFO, (CE_NOTE, "xdb@%s: detached!",
1432 	    ddi_get_name_addr(dip)));
1433 	return (DDI_SUCCESS);
1434 }
1435 
1436 static struct dev_ops xdb_dev_ops = {
1437 	DEVO_REV,	/* devo_rev */
1438 	0,		/* devo_refcnt */
1439 	ddi_getinfo_1to1, /* devo_getinfo */
1440 	nulldev,	/* devo_identify */
1441 	nulldev,	/* devo_probe */
1442 	xdb_attach,	/* devo_attach */
1443 	xdb_detach,	/* devo_detach */
1444 	nodev,		/* devo_reset */
1445 	NULL,		/* devo_cb_ops */
1446 	NULL,		/* devo_bus_ops */
1447 	NULL		/* power */
1448 };
1449 
1450 /*
1451  * Module linkage information for the kernel.
1452  */
1453 static struct modldrv modldrv = {
1454 	&mod_driverops,			/* Type of module. */
1455 	"vbd backend driver %I%",	/* Name of the module */
1456 	&xdb_dev_ops			/* driver ops */
1457 };
1458 
1459 static struct modlinkage xdb_modlinkage = {
1460 	MODREV_1,
1461 	&modldrv,
1462 	NULL
1463 };
1464 
1465 int
1466 _init(void)
1467 {
1468 	int rv;
1469 
1470 	if ((rv = ddi_soft_state_init((void **)&xdb_statep,
1471 	    sizeof (xdb_t), 0)) == 0)
1472 		if ((rv = mod_install(&xdb_modlinkage)) != 0)
1473 			ddi_soft_state_fini((void **)&xdb_statep);
1474 	return (rv);
1475 }
1476 
1477 int
1478 _fini(void)
1479 {
1480 	int rv;
1481 
1482 	if ((rv = mod_remove(&xdb_modlinkage)) != 0)
1483 		return (rv);
1484 	ddi_soft_state_fini((void **)&xdb_statep);
1485 	return (rv);
1486 }
1487 
1488 int
1489 _info(struct modinfo *modinfop)
1490 {
1491 	return (mod_info(&xdb_modlinkage, modinfop));
1492 }
1493