xref: /dflybsd-src/sys/dev/disk/xdisk/xdisk.c (revision 42e46aee3886bf921057b9d73ba56cb52657e469)
1ddfbb283SMatthew Dillon /*
2d30cab67SMatthew Dillon  * Copyright (c) 2012-2014 The DragonFly Project.  All rights reserved.
3ddfbb283SMatthew Dillon  *
4ddfbb283SMatthew Dillon  * This code is derived from software contributed to The DragonFly Project
5ddfbb283SMatthew Dillon  * by Matthew Dillon <dillon@dragonflybsd.org>
6ddfbb283SMatthew Dillon  *
7ddfbb283SMatthew Dillon  * Redistribution and use in source and binary forms, with or without
8ddfbb283SMatthew Dillon  * modification, are permitted provided that the following conditions
9ddfbb283SMatthew Dillon  * are met:
10ddfbb283SMatthew Dillon  *
11ddfbb283SMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
12ddfbb283SMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
13ddfbb283SMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
14ddfbb283SMatthew Dillon  *    notice, this list of conditions and the following disclaimer in
15ddfbb283SMatthew Dillon  *    the documentation and/or other materials provided with the
16ddfbb283SMatthew Dillon  *    distribution.
17ddfbb283SMatthew Dillon  * 3. Neither the name of The DragonFly Project nor the names of its
18ddfbb283SMatthew Dillon  *    contributors may be used to endorse or promote products derived
19ddfbb283SMatthew Dillon  *    from this software without specific, prior written permission.
20ddfbb283SMatthew Dillon  *
21ddfbb283SMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22ddfbb283SMatthew Dillon  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23ddfbb283SMatthew Dillon  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24ddfbb283SMatthew Dillon  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25ddfbb283SMatthew Dillon  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26ddfbb283SMatthew Dillon  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27ddfbb283SMatthew Dillon  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28ddfbb283SMatthew Dillon  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29ddfbb283SMatthew Dillon  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30ddfbb283SMatthew Dillon  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31ddfbb283SMatthew Dillon  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32ddfbb283SMatthew Dillon  * SUCH DAMAGE.
33ddfbb283SMatthew Dillon  */
34ddfbb283SMatthew Dillon /*
35ddfbb283SMatthew Dillon  * This module allows disk devices to be created and associated with a
36ddfbb283SMatthew Dillon  * communications pipe or socket.  You open the device and issue an
37ddfbb283SMatthew Dillon  * ioctl() to install a new disk along with its communications descriptor.
38ddfbb283SMatthew Dillon  *
39ddfbb283SMatthew Dillon  * All further communication occurs via the descriptor using the DMSG
40ddfbb283SMatthew Dillon  * LNK_CONN, LNK_SPAN, and BLOCK protocols.  The descriptor can be a
41ddfbb283SMatthew Dillon  * direct connection to a remote machine's disk (in-kernenl), to a remote
42ddfbb283SMatthew Dillon  * cluster controller, to the local cluster controller, etc.
43ddfbb283SMatthew Dillon  *
44ddfbb283SMatthew Dillon  * /dev/xdisk is the control device, issue ioctl()s to create the /dev/xa%d
45ddfbb283SMatthew Dillon  * devices.  These devices look like raw disks to the system.
46ddfbb283SMatthew Dillon  */
47ddfbb283SMatthew Dillon #include <sys/param.h>
48ddfbb283SMatthew Dillon #include <sys/systm.h>
49ddfbb283SMatthew Dillon #include <sys/buf.h>
50ddfbb283SMatthew Dillon #include <sys/conf.h>
51ddfbb283SMatthew Dillon #include <sys/device.h>
52ddfbb283SMatthew Dillon #include <sys/devicestat.h>
53ddfbb283SMatthew Dillon #include <sys/disk.h>
54ddfbb283SMatthew Dillon #include <sys/kernel.h>
55ddfbb283SMatthew Dillon #include <sys/malloc.h>
56ddfbb283SMatthew Dillon #include <sys/sysctl.h>
57ddfbb283SMatthew Dillon #include <sys/proc.h>
58ddfbb283SMatthew Dillon #include <sys/queue.h>
59d30cab67SMatthew Dillon #include <sys/tree.h>
60ddfbb283SMatthew Dillon #include <sys/udev.h>
61ddfbb283SMatthew Dillon #include <sys/uuid.h>
62ddfbb283SMatthew Dillon #include <sys/kern_syscall.h>
63ddfbb283SMatthew Dillon 
64ddfbb283SMatthew Dillon #include <sys/dmsg.h>
65ddfbb283SMatthew Dillon #include <sys/xdiskioctl.h>
66ddfbb283SMatthew Dillon 
67ddfbb283SMatthew Dillon #include <sys/buf2.h>
68ddfbb283SMatthew Dillon 
690f50fb46SMatthew Dillon struct xa_softc;
70d30cab67SMatthew Dillon struct xa_softc_tree;
71d30cab67SMatthew Dillon RB_HEAD(xa_softc_tree, xa_softc);
72d30cab67SMatthew Dillon RB_PROTOTYPE(xa_softc_tree, xa_softc, rbnode, xa_softc_cmp);
730f50fb46SMatthew Dillon 
74bab1d4ffSMatthew Dillon static int xa_active;
75bab1d4ffSMatthew Dillon SYSCTL_INT(_debug, OID_AUTO, xa_active, CTLFLAG_RW, &xa_active, 0,
76bab1d4ffSMatthew Dillon 	   "Number of active xdisk IOs");
77bab1d4ffSMatthew Dillon static uint64_t xa_last;
78bab1d4ffSMatthew Dillon SYSCTL_ULONG(_debug, OID_AUTO, xa_last, CTLFLAG_RW, &xa_last, 0,
79bab1d4ffSMatthew Dillon 	   "Offset of last xdisk IO");
805ab1caedSMatthew Dillon static int xa_debug = 1;
815ab1caedSMatthew Dillon SYSCTL_INT(_debug, OID_AUTO, xa_debug, CTLFLAG_RW, &xa_debug, 0,
825ab1caedSMatthew Dillon 	   "xdisk debugging");
83bab1d4ffSMatthew Dillon 
84d30cab67SMatthew Dillon /*
85d30cab67SMatthew Dillon  * Track a BIO tag
86d30cab67SMatthew Dillon  */
870f50fb46SMatthew Dillon struct xa_tag {
880f50fb46SMatthew Dillon 	TAILQ_ENTRY(xa_tag) entry;
89d30cab67SMatthew Dillon 	struct xa_softc	*sc;
900f50fb46SMatthew Dillon 	dmsg_blk_error_t status;
910f50fb46SMatthew Dillon 	kdmsg_state_t	*state;
920f50fb46SMatthew Dillon 	struct bio	*bio;
93d30cab67SMatthew Dillon 	int		waiting;
94d30cab67SMatthew Dillon 	int		async;
95d30cab67SMatthew Dillon 	int		done;
960f50fb46SMatthew Dillon };
970f50fb46SMatthew Dillon 
980f50fb46SMatthew Dillon typedef struct xa_tag	xa_tag_t;
990f50fb46SMatthew Dillon 
100d30cab67SMatthew Dillon /*
101d30cab67SMatthew Dillon  * Track devices.
102d30cab67SMatthew Dillon  */
1030f50fb46SMatthew Dillon struct xa_softc {
104d30cab67SMatthew Dillon 	struct kdmsg_state_list spanq;
105d30cab67SMatthew Dillon 	RB_ENTRY(xa_softc) rbnode;
1060f50fb46SMatthew Dillon 	cdev_t		dev;
107bab1d4ffSMatthew Dillon 	struct devstat	stats;
1080f50fb46SMatthew Dillon 	struct disk_info info;
1090f50fb46SMatthew Dillon 	struct disk	disk;
1107750fd72SMatthew Dillon 	uuid_t		peer_id;
1110f50fb46SMatthew Dillon 	int		unit;
1120f50fb46SMatthew Dillon 	int		opencnt;
113d30cab67SMatthew Dillon 	int		spancnt;
1140f50fb46SMatthew Dillon 	uint64_t	keyid;
115d30cab67SMatthew Dillon 	int		serializing;
116d30cab67SMatthew Dillon 	int		last_error;
1175ab1caedSMatthew Dillon 	int		terminating;
1187750fd72SMatthew Dillon 	char		peer_label[64];	/* from LNK_SPAN host/dev */
1197750fd72SMatthew Dillon 	char		pfs_label[64];	/* from LNK_SPAN serno */
120d30cab67SMatthew Dillon 	xa_tag_t	*open_tag;
121d30cab67SMatthew Dillon 	TAILQ_HEAD(, bio) bioq;		/* pending BIOs */
122d30cab67SMatthew Dillon 	TAILQ_HEAD(, xa_tag) tag_freeq;	/* available I/O tags */
123d30cab67SMatthew Dillon 	TAILQ_HEAD(, xa_tag) tag_pendq;	/* running I/O tags */
124a06d536bSMatthew Dillon 	struct lock	lk;
1250f50fb46SMatthew Dillon };
1260f50fb46SMatthew Dillon 
1270f50fb46SMatthew Dillon typedef struct xa_softc	xa_softc_t;
1280f50fb46SMatthew Dillon 
129d30cab67SMatthew Dillon struct xa_iocom {
130d30cab67SMatthew Dillon 	TAILQ_ENTRY(xa_iocom) entry;
131d30cab67SMatthew Dillon 	kdmsg_iocom_t	iocom;
132d30cab67SMatthew Dillon 	xa_softc_t	dummysc;
133d30cab67SMatthew Dillon };
134d30cab67SMatthew Dillon 
135d30cab67SMatthew Dillon typedef struct xa_iocom xa_iocom_t;
136d30cab67SMatthew Dillon 
137d30cab67SMatthew Dillon static int xa_softc_cmp(xa_softc_t *sc1, xa_softc_t *sc2);
138d30cab67SMatthew Dillon RB_GENERATE(xa_softc_tree, xa_softc, rbnode, xa_softc_cmp);
139d30cab67SMatthew Dillon static struct xa_softc_tree xa_device_tree;
140d30cab67SMatthew Dillon 
1410f50fb46SMatthew Dillon #define MAXTAGS		64	/* no real limit */
1420f50fb46SMatthew Dillon 
143ddfbb283SMatthew Dillon static int xdisk_attach(struct xdisk_attach_ioctl *xaioc);
1440f50fb46SMatthew Dillon static int xdisk_detach(struct xdisk_attach_ioctl *xaioc);
145d30cab67SMatthew Dillon static void xaio_exit(kdmsg_iocom_t *iocom);
146d30cab67SMatthew Dillon static int xaio_rcvdmsg(kdmsg_msg_t *msg);
1470f50fb46SMatthew Dillon 
148d30cab67SMatthew Dillon static void xa_terminate_check(struct xa_softc *sc);
149d30cab67SMatthew Dillon 
150d30cab67SMatthew Dillon static xa_tag_t *xa_setup_cmd(xa_softc_t *sc, struct bio *bio);
151d30cab67SMatthew Dillon static void xa_start(xa_tag_t *tag, kdmsg_msg_t *msg, int async);
1520f50fb46SMatthew Dillon static void xa_done(xa_tag_t *tag, int wasbio);
153d30cab67SMatthew Dillon static void xa_release(xa_tag_t *tag, int wasbio);
154d30cab67SMatthew Dillon static uint32_t xa_wait(xa_tag_t *tag);
1550f50fb46SMatthew Dillon static int xa_sync_completion(kdmsg_state_t *state, kdmsg_msg_t *msg);
1560f50fb46SMatthew Dillon static int xa_bio_completion(kdmsg_state_t *state, kdmsg_msg_t *msg);
157d30cab67SMatthew Dillon static void xa_restart_deferred(xa_softc_t *sc);
158ddfbb283SMatthew Dillon 
1595ab1caedSMatthew Dillon #define xa_printf(level, ctl, ...)	\
1605ab1caedSMatthew Dillon 	if (xa_debug >= (level)) kprintf("xdisk: " ctl, __VA_ARGS__)
1615ab1caedSMatthew Dillon 
162ddfbb283SMatthew Dillon MALLOC_DEFINE(M_XDISK, "Networked disk client", "Network Disks");
163ddfbb283SMatthew Dillon 
164ddfbb283SMatthew Dillon /*
165ddfbb283SMatthew Dillon  * Control device, issue ioctls to create xa devices.
166ddfbb283SMatthew Dillon  */
167ddfbb283SMatthew Dillon static d_open_t xdisk_open;
168ddfbb283SMatthew Dillon static d_close_t xdisk_close;
169ddfbb283SMatthew Dillon static d_ioctl_t xdisk_ioctl;
170ddfbb283SMatthew Dillon 
171ddfbb283SMatthew Dillon static struct dev_ops xdisk_ops = {
1720f50fb46SMatthew Dillon 	{ "xdisk", 0, D_MPSAFE | D_TRACKCLOSE },
173ddfbb283SMatthew Dillon         .d_open =	xdisk_open,
174ddfbb283SMatthew Dillon         .d_close =	xdisk_close,
175ddfbb283SMatthew Dillon         .d_ioctl =	xdisk_ioctl
176ddfbb283SMatthew Dillon };
177ddfbb283SMatthew Dillon 
178ddfbb283SMatthew Dillon /*
179ddfbb283SMatthew Dillon  * XA disk devices
180ddfbb283SMatthew Dillon  */
181ddfbb283SMatthew Dillon static d_open_t xa_open;
182ddfbb283SMatthew Dillon static d_close_t xa_close;
183ddfbb283SMatthew Dillon static d_ioctl_t xa_ioctl;
184ddfbb283SMatthew Dillon static d_strategy_t xa_strategy;
185ddfbb283SMatthew Dillon static d_psize_t xa_size;
186ddfbb283SMatthew Dillon 
187ddfbb283SMatthew Dillon static struct dev_ops xa_ops = {
1880f50fb46SMatthew Dillon 	{ "xa", 0, D_DISK | D_CANFREE | D_MPSAFE | D_TRACKCLOSE },
189ddfbb283SMatthew Dillon         .d_open =	xa_open,
190ddfbb283SMatthew Dillon         .d_close =	xa_close,
191ddfbb283SMatthew Dillon         .d_ioctl =	xa_ioctl,
192ddfbb283SMatthew Dillon         .d_read =	physread,
193ddfbb283SMatthew Dillon         .d_write =	physwrite,
194ddfbb283SMatthew Dillon         .d_strategy =	xa_strategy,
195ddfbb283SMatthew Dillon 	.d_psize =	xa_size
196ddfbb283SMatthew Dillon };
197ddfbb283SMatthew Dillon 
198ddfbb283SMatthew Dillon static int xdisk_opencount;
199ddfbb283SMatthew Dillon static cdev_t xdisk_dev;
200a06d536bSMatthew Dillon struct lock xdisk_lk;
201d30cab67SMatthew Dillon static TAILQ_HEAD(, xa_iocom) xaiocomq;
202ddfbb283SMatthew Dillon 
203ddfbb283SMatthew Dillon /*
204ddfbb283SMatthew Dillon  * Module initialization
205ddfbb283SMatthew Dillon  */
206ddfbb283SMatthew Dillon static int
xdisk_modevent(module_t mod,int type,void * data)207ddfbb283SMatthew Dillon xdisk_modevent(module_t mod, int type, void *data)
208ddfbb283SMatthew Dillon {
209ddfbb283SMatthew Dillon 	switch (type) {
210ddfbb283SMatthew Dillon 	case MOD_LOAD:
211d30cab67SMatthew Dillon 		TAILQ_INIT(&xaiocomq);
212d30cab67SMatthew Dillon 		RB_INIT(&xa_device_tree);
213a06d536bSMatthew Dillon 		lockinit(&xdisk_lk, "xdisk", 0, 0);
214ddfbb283SMatthew Dillon 		xdisk_dev = make_dev(&xdisk_ops, 0,
215ddfbb283SMatthew Dillon 				     UID_ROOT, GID_WHEEL, 0600, "xdisk");
216ddfbb283SMatthew Dillon 		break;
217ddfbb283SMatthew Dillon 	case MOD_UNLOAD:
218ddfbb283SMatthew Dillon 	case MOD_SHUTDOWN:
2195ab1caedSMatthew Dillon 		if (!RB_EMPTY(&xa_device_tree))
2205ab1caedSMatthew Dillon 			return (EBUSY);
221d30cab67SMatthew Dillon 		if (xdisk_opencount || TAILQ_FIRST(&xaiocomq))
222ddfbb283SMatthew Dillon 			return (EBUSY);
223ddfbb283SMatthew Dillon 		if (xdisk_dev) {
224ddfbb283SMatthew Dillon 			destroy_dev(xdisk_dev);
225ddfbb283SMatthew Dillon 			xdisk_dev = NULL;
226ddfbb283SMatthew Dillon 		}
227ddfbb283SMatthew Dillon 		dev_ops_remove_all(&xdisk_ops);
228ddfbb283SMatthew Dillon 		dev_ops_remove_all(&xa_ops);
229ddfbb283SMatthew Dillon 		break;
230ddfbb283SMatthew Dillon 	default:
231ddfbb283SMatthew Dillon 		break;
232ddfbb283SMatthew Dillon 	}
233ddfbb283SMatthew Dillon 	return 0;
234ddfbb283SMatthew Dillon }
235ddfbb283SMatthew Dillon 
236ddfbb283SMatthew Dillon DEV_MODULE(xdisk, xdisk_modevent, 0);
237ddfbb283SMatthew Dillon 
238d30cab67SMatthew Dillon static int
xa_softc_cmp(xa_softc_t * sc1,xa_softc_t * sc2)239d30cab67SMatthew Dillon xa_softc_cmp(xa_softc_t *sc1, xa_softc_t *sc2)
240d30cab67SMatthew Dillon {
2417750fd72SMatthew Dillon 	return(strcmp(sc1->pfs_label, sc2->pfs_label));
242d30cab67SMatthew Dillon }
243d30cab67SMatthew Dillon 
244ddfbb283SMatthew Dillon /*
245ddfbb283SMatthew Dillon  * Control device
246ddfbb283SMatthew Dillon  */
247ddfbb283SMatthew Dillon static int
xdisk_open(struct dev_open_args * ap)248ddfbb283SMatthew Dillon xdisk_open(struct dev_open_args *ap)
249ddfbb283SMatthew Dillon {
250a06d536bSMatthew Dillon 	lockmgr(&xdisk_lk, LK_EXCLUSIVE);
251ddfbb283SMatthew Dillon 	++xdisk_opencount;
252a06d536bSMatthew Dillon 	lockmgr(&xdisk_lk, LK_RELEASE);
253ddfbb283SMatthew Dillon 	return(0);
254ddfbb283SMatthew Dillon }
255ddfbb283SMatthew Dillon 
256ddfbb283SMatthew Dillon static int
xdisk_close(struct dev_close_args * ap)257ddfbb283SMatthew Dillon xdisk_close(struct dev_close_args *ap)
258ddfbb283SMatthew Dillon {
259a06d536bSMatthew Dillon 	lockmgr(&xdisk_lk, LK_EXCLUSIVE);
260ddfbb283SMatthew Dillon 	--xdisk_opencount;
261a06d536bSMatthew Dillon 	lockmgr(&xdisk_lk, LK_RELEASE);
262ddfbb283SMatthew Dillon 	return(0);
263ddfbb283SMatthew Dillon }
264ddfbb283SMatthew Dillon 
265ddfbb283SMatthew Dillon static int
xdisk_ioctl(struct dev_ioctl_args * ap)266ddfbb283SMatthew Dillon xdisk_ioctl(struct dev_ioctl_args *ap)
267ddfbb283SMatthew Dillon {
268ddfbb283SMatthew Dillon 	int error;
269ddfbb283SMatthew Dillon 
270ddfbb283SMatthew Dillon 	switch(ap->a_cmd) {
271ddfbb283SMatthew Dillon 	case XDISKIOCATTACH:
272ddfbb283SMatthew Dillon 		error = xdisk_attach((void *)ap->a_data);
273ddfbb283SMatthew Dillon 		break;
2740f50fb46SMatthew Dillon 	case XDISKIOCDETACH:
2750f50fb46SMatthew Dillon 		error = xdisk_detach((void *)ap->a_data);
2760f50fb46SMatthew Dillon 		break;
277ddfbb283SMatthew Dillon 	default:
278ddfbb283SMatthew Dillon 		error = ENOTTY;
279ddfbb283SMatthew Dillon 		break;
280ddfbb283SMatthew Dillon 	}
281ddfbb283SMatthew Dillon 	return error;
282ddfbb283SMatthew Dillon }
283ddfbb283SMatthew Dillon 
284ddfbb283SMatthew Dillon /************************************************************************
285ddfbb283SMatthew Dillon  *				DMSG INTERFACE				*
286ddfbb283SMatthew Dillon  ************************************************************************/
287ddfbb283SMatthew Dillon 
288ddfbb283SMatthew Dillon static int
xdisk_attach(struct xdisk_attach_ioctl * xaioc)289ddfbb283SMatthew Dillon xdisk_attach(struct xdisk_attach_ioctl *xaioc)
290ddfbb283SMatthew Dillon {
291d30cab67SMatthew Dillon 	xa_iocom_t *xaio;
292ddfbb283SMatthew Dillon 	struct file *fp;
293ddfbb283SMatthew Dillon 
2940f50fb46SMatthew Dillon 	/*
2950f50fb46SMatthew Dillon 	 * Normalize ioctl params
2960f50fb46SMatthew Dillon 	 */
29735949930SMatthew Dillon 	fp = holdfp(curthread, xaioc->fd, -1);
298ddfbb283SMatthew Dillon 	if (fp == NULL)
299ddfbb283SMatthew Dillon 		return EINVAL;
3005ab1caedSMatthew Dillon 	xa_printf(1, "xdisk_attach fp=%p\n", fp);
301ddfbb283SMatthew Dillon 
302ddfbb283SMatthew Dillon 	/*
3030f50fb46SMatthew Dillon 	 * See if the serial number is already present.  If we are
3040f50fb46SMatthew Dillon 	 * racing a termination the disk subsystem may still have
3050f50fb46SMatthew Dillon 	 * duplicate entries not yet removed so we wait a bit and
3060f50fb46SMatthew Dillon 	 * retry.
307ddfbb283SMatthew Dillon 	 */
308a06d536bSMatthew Dillon 	lockmgr(&xdisk_lk, LK_EXCLUSIVE);
3090f50fb46SMatthew Dillon 
310d30cab67SMatthew Dillon 	xaio = kmalloc(sizeof(*xaio), M_XDISK, M_WAITOK | M_ZERO);
311d30cab67SMatthew Dillon 	kdmsg_iocom_init(&xaio->iocom, xaio,
312d30cab67SMatthew Dillon 			 KDMSG_IOCOMF_AUTOCONN,
313d30cab67SMatthew Dillon 			 M_XDISK, xaio_rcvdmsg);
314d30cab67SMatthew Dillon 	xaio->iocom.exit_func = xaio_exit;
3158d6d37b8SMatthew Dillon 
316d30cab67SMatthew Dillon 	kdmsg_iocom_reconnect(&xaio->iocom, fp, "xdisk");
317ddfbb283SMatthew Dillon 
318ddfbb283SMatthew Dillon 	/*
3190f50fb46SMatthew Dillon 	 * Setup our LNK_CONN advertisement for autoinitiate.
3200f50fb46SMatthew Dillon 	 *
3217750fd72SMatthew Dillon 	 * Our filter is setup to only accept PEER_BLOCK advertisements.
3227750fd72SMatthew Dillon 	 * XXX no peer_id filter.
323d30cab67SMatthew Dillon 	 *
3240f50fb46SMatthew Dillon 	 * We need a unique pfs_fsid to avoid confusion.
325ddfbb283SMatthew Dillon 	 */
3267750fd72SMatthew Dillon 	xaio->iocom.auto_lnk_conn.peer_type = DMSG_PEER_CLIENT;
327d30cab67SMatthew Dillon 	xaio->iocom.auto_lnk_conn.proto_version = DMSG_SPAN_PROTO_1;
328d30cab67SMatthew Dillon 	xaio->iocom.auto_lnk_conn.peer_mask = 1LLU << DMSG_PEER_BLOCK;
3297750fd72SMatthew Dillon 	ksnprintf(xaio->iocom.auto_lnk_conn.peer_label,
3307750fd72SMatthew Dillon 		  sizeof(xaio->iocom.auto_lnk_conn.peer_label),
3317750fd72SMatthew Dillon 		  "%s/xdisk",
3327750fd72SMatthew Dillon 		  hostname);
3337750fd72SMatthew Dillon 	/* kern_uuidgen(&xaio->iocom.auto_lnk_conn.pfs_fsid, 1); */
334ddfbb283SMatthew Dillon 
3350f50fb46SMatthew Dillon 	/*
3360f50fb46SMatthew Dillon 	 * Setup our LNK_SPAN advertisement for autoinitiate
3370f50fb46SMatthew Dillon 	 */
338d30cab67SMatthew Dillon 	TAILQ_INSERT_TAIL(&xaiocomq, xaio, entry);
339d30cab67SMatthew Dillon 	kdmsg_iocom_autoinitiate(&xaio->iocom, NULL);
340a06d536bSMatthew Dillon 
341a06d536bSMatthew Dillon 	lockmgr(&xdisk_lk, LK_RELEASE);
3420f50fb46SMatthew Dillon 
343d30cab67SMatthew Dillon 	return 0;
344ddfbb283SMatthew Dillon }
345ddfbb283SMatthew Dillon 
346ddfbb283SMatthew Dillon static int
xdisk_detach(struct xdisk_attach_ioctl * xaioc)3470f50fb46SMatthew Dillon xdisk_detach(struct xdisk_attach_ioctl *xaioc)
348ddfbb283SMatthew Dillon {
349d30cab67SMatthew Dillon 	return EINVAL;
350ddfbb283SMatthew Dillon }
351ddfbb283SMatthew Dillon 
352ddfbb283SMatthew Dillon /*
353ddfbb283SMatthew Dillon  * Called from iocom core transmit thread upon disconnect.
354ddfbb283SMatthew Dillon  */
355ddfbb283SMatthew Dillon static
356ddfbb283SMatthew Dillon void
xaio_exit(kdmsg_iocom_t * iocom)357d30cab67SMatthew Dillon xaio_exit(kdmsg_iocom_t *iocom)
358ddfbb283SMatthew Dillon {
359d30cab67SMatthew Dillon 	xa_iocom_t *xaio = iocom->handle;
360ddfbb283SMatthew Dillon 
361a06d536bSMatthew Dillon 	lockmgr(&xdisk_lk, LK_EXCLUSIVE);
3625ab1caedSMatthew Dillon 	xa_printf(1, "%s", "xdisk_detach [xaio_exit()]\n");
363d30cab67SMatthew Dillon 	TAILQ_REMOVE(&xaiocomq, xaio, entry);
364a06d536bSMatthew Dillon 	lockmgr(&xdisk_lk, LK_RELEASE);
365d30cab67SMatthew Dillon 
366bab1d4ffSMatthew Dillon 	kdmsg_iocom_uninit(&xaio->iocom);
367bab1d4ffSMatthew Dillon 
368d30cab67SMatthew Dillon 	kfree(xaio, M_XDISK);
369d30cab67SMatthew Dillon }
370d30cab67SMatthew Dillon 
371d30cab67SMatthew Dillon /*
372d30cab67SMatthew Dillon  * Called from iocom core to handle messages that the iocom core does not
373d30cab67SMatthew Dillon  * handle itself and for which a state function callback has not yet been
374d30cab67SMatthew Dillon  * established.
375d30cab67SMatthew Dillon  *
376d30cab67SMatthew Dillon  * We primarily care about LNK_SPAN transactions here.
377d30cab67SMatthew Dillon  */
378d30cab67SMatthew Dillon static int
xaio_rcvdmsg(kdmsg_msg_t * msg)379d30cab67SMatthew Dillon xaio_rcvdmsg(kdmsg_msg_t *msg)
380d30cab67SMatthew Dillon {
381d30cab67SMatthew Dillon 	kdmsg_state_t	*state = msg->state;
382d30cab67SMatthew Dillon 	xa_iocom_t	*xaio = state->iocom->handle;
383d30cab67SMatthew Dillon 	xa_softc_t	*sc;
384d30cab67SMatthew Dillon 
385a06d536bSMatthew Dillon 	if (state) {
3865ab1caedSMatthew Dillon 		xa_printf(4,
3875ab1caedSMatthew Dillon 			"xdisk - rcvmsg state=%p rx=%08x tx=%08x msgcmd=%08x\n",
388a06d536bSMatthew Dillon 			state, state->rxcmd, state->txcmd,
389a06d536bSMatthew Dillon 			msg->any.head.cmd);
390a06d536bSMatthew Dillon 	}
391a06d536bSMatthew Dillon 	lockmgr(&xdisk_lk, LK_EXCLUSIVE);
392ddfbb283SMatthew Dillon 
393d30cab67SMatthew Dillon 	switch(msg->tcmd) {
394d30cab67SMatthew Dillon 	case DMSG_LNK_SPAN | DMSGF_CREATE | DMSGF_DELETE:
3958d6d37b8SMatthew Dillon 		/*
396d30cab67SMatthew Dillon 		 * A LNK_SPAN transaction which is opened and closed
397d30cab67SMatthew Dillon 		 * degenerately is not useful to us, just ignore it.
3988d6d37b8SMatthew Dillon 		 */
399d30cab67SMatthew Dillon 		kdmsg_msg_reply(msg, 0);
400d30cab67SMatthew Dillon 		break;
401d30cab67SMatthew Dillon 	case DMSG_LNK_SPAN | DMSGF_CREATE:
4028d6d37b8SMatthew Dillon 		/*
403d30cab67SMatthew Dillon 		 * Manage the tracking node for the remote LNK_SPAN.
4040f50fb46SMatthew Dillon 		 *
405d30cab67SMatthew Dillon 		 * Return a streaming result, leaving the transaction open
406d30cab67SMatthew Dillon 		 * in both directions to allow sub-transactions.
4070f50fb46SMatthew Dillon 		 */
4087750fd72SMatthew Dillon 		bcopy(msg->any.lnk_span.peer_label, xaio->dummysc.peer_label,
4097750fd72SMatthew Dillon 		      sizeof(xaio->dummysc.peer_label));
4107750fd72SMatthew Dillon 		xaio->dummysc.peer_label[
4117750fd72SMatthew Dillon 			sizeof(xaio->dummysc.peer_label) - 1] = 0;
412d30cab67SMatthew Dillon 
4137750fd72SMatthew Dillon 		bcopy(msg->any.lnk_span.pfs_label, xaio->dummysc.pfs_label,
4147750fd72SMatthew Dillon 		      sizeof(xaio->dummysc.pfs_label));
4157750fd72SMatthew Dillon 		xaio->dummysc.pfs_label[
4167750fd72SMatthew Dillon 			sizeof(xaio->dummysc.pfs_label) - 1] = 0;
417d30cab67SMatthew Dillon 
4185ab1caedSMatthew Dillon 		xa_printf(3, "LINK_SPAN state %p create for %s\n",
4197750fd72SMatthew Dillon 			  msg->state, msg->any.lnk_span.pfs_label);
420d30cab67SMatthew Dillon 
421d30cab67SMatthew Dillon 		sc = RB_FIND(xa_softc_tree, &xa_device_tree, &xaio->dummysc);
422d30cab67SMatthew Dillon 		if (sc == NULL) {
423d30cab67SMatthew Dillon 			xa_softc_t *sctmp;
4240f50fb46SMatthew Dillon 			xa_tag_t *tag;
425d30cab67SMatthew Dillon 			cdev_t dev;
426d30cab67SMatthew Dillon 			int unit;
427d30cab67SMatthew Dillon 			int n;
4280f50fb46SMatthew Dillon 
429d30cab67SMatthew Dillon 			sc = kmalloc(sizeof(*sc), M_XDISK, M_WAITOK | M_ZERO);
4307750fd72SMatthew Dillon 			bcopy(msg->any.lnk_span.peer_label, sc->peer_label,
4317750fd72SMatthew Dillon 			      sizeof(sc->peer_label));
4327750fd72SMatthew Dillon 			sc->peer_label[sizeof(sc->peer_label) - 1] = 0;
4337750fd72SMatthew Dillon 			bcopy(msg->any.lnk_span.pfs_label, sc->pfs_label,
4347750fd72SMatthew Dillon 			      sizeof(sc->pfs_label));
4357750fd72SMatthew Dillon 			sc->pfs_label[sizeof(sc->pfs_label) - 1] = 0;
436d30cab67SMatthew Dillon 
437d30cab67SMatthew Dillon 			/* XXX FIXME O(N^2) */
438d30cab67SMatthew Dillon 			unit = -1;
439d30cab67SMatthew Dillon 			do {
440d30cab67SMatthew Dillon 				++unit;
441d30cab67SMatthew Dillon 				RB_FOREACH(sctmp, xa_softc_tree,
442d30cab67SMatthew Dillon 					   &xa_device_tree) {
443d30cab67SMatthew Dillon 					if (sctmp->unit == unit)
444d30cab67SMatthew Dillon 						break;
445d30cab67SMatthew Dillon 				}
446d30cab67SMatthew Dillon 			} while (sctmp);
447d30cab67SMatthew Dillon 
448d30cab67SMatthew Dillon 			sc->unit = unit;
449d30cab67SMatthew Dillon 			sc->serializing = 1;
450d30cab67SMatthew Dillon 			sc->spancnt = 1;
451a06d536bSMatthew Dillon 			lockinit(&sc->lk, "xalk", 0, 0);
452d30cab67SMatthew Dillon 			TAILQ_INIT(&sc->spanq);
453d30cab67SMatthew Dillon 			TAILQ_INIT(&sc->bioq);
454d30cab67SMatthew Dillon 			TAILQ_INIT(&sc->tag_freeq);
455d30cab67SMatthew Dillon 			TAILQ_INIT(&sc->tag_pendq);
456a06d536bSMatthew Dillon 
457a06d536bSMatthew Dillon 			lockmgr(&sc->lk, LK_EXCLUSIVE);
458d30cab67SMatthew Dillon 			RB_INSERT(xa_softc_tree, &xa_device_tree, sc);
459d30cab67SMatthew Dillon 			TAILQ_INSERT_TAIL(&sc->spanq, msg->state, user_entry);
460d30cab67SMatthew Dillon 			msg->state->any.xa_sc = sc;
4618d6d37b8SMatthew Dillon 
4628d6d37b8SMatthew Dillon 			/*
463d30cab67SMatthew Dillon 			 * Setup block device
4648d6d37b8SMatthew Dillon 			 */
465d30cab67SMatthew Dillon 			for (n = 0; n < MAXTAGS; ++n) {
466d30cab67SMatthew Dillon 				tag = kmalloc(sizeof(*tag),
467d30cab67SMatthew Dillon 					      M_XDISK, M_WAITOK|M_ZERO);
468d30cab67SMatthew Dillon 				tag->sc = sc;
469d30cab67SMatthew Dillon 				TAILQ_INSERT_TAIL(&sc->tag_freeq, tag, entry);
4700f50fb46SMatthew Dillon 			}
4710f50fb46SMatthew Dillon 
472d30cab67SMatthew Dillon 			if (sc->dev == NULL) {
473d30cab67SMatthew Dillon 				dev = disk_create(unit, &sc->disk, &xa_ops);
474d30cab67SMatthew Dillon 				dev->si_drv1 = sc;
475d30cab67SMatthew Dillon 				sc->dev = dev;
476bab1d4ffSMatthew Dillon 				devstat_add_entry(&sc->stats, "xa", unit,
477bab1d4ffSMatthew Dillon 						  DEV_BSIZE,
478bab1d4ffSMatthew Dillon 						  DEVSTAT_NO_ORDERED_TAGS,
479bab1d4ffSMatthew Dillon 						  DEVSTAT_TYPE_DIRECT |
480bab1d4ffSMatthew Dillon 						  DEVSTAT_TYPE_IF_OTHER,
481bab1d4ffSMatthew Dillon 						  DEVSTAT_PRIORITY_OTHER);
482d30cab67SMatthew Dillon 			}
4838d6d37b8SMatthew Dillon 
484d30cab67SMatthew Dillon 			sc->info.d_media_blksize =
485d30cab67SMatthew Dillon 				msg->any.lnk_span.media.block.blksize;
486d30cab67SMatthew Dillon 			if (sc->info.d_media_blksize <= 0)
487d30cab67SMatthew Dillon 				sc->info.d_media_blksize = 1;
488d30cab67SMatthew Dillon 			sc->info.d_media_blocks =
489d30cab67SMatthew Dillon 				msg->any.lnk_span.media.block.bytes /
490d30cab67SMatthew Dillon 				sc->info.d_media_blksize;
491d30cab67SMatthew Dillon 			sc->info.d_dsflags = DSO_MBRQUIET | DSO_RAWPSIZE;
492d30cab67SMatthew Dillon 			sc->info.d_secpertrack = 32;
493d30cab67SMatthew Dillon 			sc->info.d_nheads = 64;
494d30cab67SMatthew Dillon 			sc->info.d_secpercyl = sc->info.d_secpertrack *
495d30cab67SMatthew Dillon 					       sc->info.d_nheads;
496d30cab67SMatthew Dillon 			sc->info.d_ncylinders = 0;
4977750fd72SMatthew Dillon 			if (sc->pfs_label[0])
4987750fd72SMatthew Dillon 				sc->info.d_serialno = sc->pfs_label;
499d34b92afSMatthew Dillon 			/*
500d34b92afSMatthew Dillon 			 * WARNING! disk_setdiskinfo() must be asynchronous
501d34b92afSMatthew Dillon 			 *	    because we are in the rxmsg thread.  If
502d34b92afSMatthew Dillon 			 *	    it is synchronous and issues more disk
503d34b92afSMatthew Dillon 			 *	    I/Os, we will deadlock.
504d34b92afSMatthew Dillon 			 */
505d34b92afSMatthew Dillon 			disk_setdiskinfo(&sc->disk, &sc->info);
506d30cab67SMatthew Dillon 			xa_restart_deferred(sc);	/* eats serializing */
507a06d536bSMatthew Dillon 			lockmgr(&sc->lk, LK_RELEASE);
5080f50fb46SMatthew Dillon 		} else {
509a06d536bSMatthew Dillon 			lockmgr(&sc->lk, LK_EXCLUSIVE);
510d30cab67SMatthew Dillon 			++sc->spancnt;
511d30cab67SMatthew Dillon 			TAILQ_INSERT_TAIL(&sc->spanq, msg->state, user_entry);
512d30cab67SMatthew Dillon 			msg->state->any.xa_sc = sc;
513d30cab67SMatthew Dillon 			if (sc->serializing == 0 && sc->open_tag == NULL) {
514d30cab67SMatthew Dillon 				sc->serializing = 1;
515d30cab67SMatthew Dillon 				xa_restart_deferred(sc); /* eats serializing */
5160f50fb46SMatthew Dillon 			}
517a06d536bSMatthew Dillon 			lockmgr(&sc->lk, LK_RELEASE);
5187924b8f1SMatthew Dillon 			if (sc->dev && sc->dev->si_disk) {
5195ab1caedSMatthew Dillon 				xa_printf(1, "reprobe disk: %s\n",
5207750fd72SMatthew Dillon 					  sc->pfs_label);
5217924b8f1SMatthew Dillon 				disk_msg_send(DISK_DISK_REPROBE,
5227924b8f1SMatthew Dillon 					      sc->dev->si_disk,
5237924b8f1SMatthew Dillon 					      NULL);
5247924b8f1SMatthew Dillon 			}
525d30cab67SMatthew Dillon 		}
5265ab1caedSMatthew Dillon 		xa_printf(2, "sc %p spancnt %d\n", sc, sc->spancnt);
527d30cab67SMatthew Dillon 		kdmsg_msg_result(msg, 0);
528ddfbb283SMatthew Dillon 		break;
529d30cab67SMatthew Dillon 	case DMSG_LNK_SPAN | DMSGF_DELETE:
5300c98b966SMatthew Dillon 		/*
531d30cab67SMatthew Dillon 		 * Manage the tracking node for the remote LNK_SPAN.
532d30cab67SMatthew Dillon 		 *
533d30cab67SMatthew Dillon 		 * Return a final result, closing our end of the transaction.
5340c98b966SMatthew Dillon 		 */
535d30cab67SMatthew Dillon 		sc = msg->state->any.xa_sc;
5365ab1caedSMatthew Dillon 		xa_printf(3, "LINK_SPAN state %p delete for %s (sc=%p)\n",
5377750fd72SMatthew Dillon 			  msg->state, (sc ? sc->pfs_label : "(null)"), sc);
538a06d536bSMatthew Dillon 		lockmgr(&sc->lk, LK_EXCLUSIVE);
539d30cab67SMatthew Dillon 		msg->state->any.xa_sc = NULL;
540d30cab67SMatthew Dillon 		TAILQ_REMOVE(&sc->spanq, msg->state, user_entry);
541d30cab67SMatthew Dillon 		--sc->spancnt;
542a06d536bSMatthew Dillon 
5435ab1caedSMatthew Dillon 		xa_printf(2, "sc %p spancnt %d\n", sc, sc->spancnt);
544a06d536bSMatthew Dillon 
545a06d536bSMatthew Dillon 		/*
546a06d536bSMatthew Dillon 		 * Spans can come and go as the graph stabilizes, so if
547a06d536bSMatthew Dillon 		 * we lose a span along with sc->open_tag we may be able
548a06d536bSMatthew Dillon 		 * to restart the I/Os on a different span.
549a06d536bSMatthew Dillon 		 */
550a06d536bSMatthew Dillon 		if (sc->spancnt &&
551a06d536bSMatthew Dillon 		    sc->serializing == 0 && sc->open_tag == NULL) {
552a06d536bSMatthew Dillon 			sc->serializing = 1;
553a06d536bSMatthew Dillon 			xa_restart_deferred(sc);
554a06d536bSMatthew Dillon 		}
555a06d536bSMatthew Dillon 		lockmgr(&sc->lk, LK_RELEASE);
556d30cab67SMatthew Dillon 		kdmsg_msg_reply(msg, 0);
557a06d536bSMatthew Dillon 
558a06d536bSMatthew Dillon #if 0
559a06d536bSMatthew Dillon 		/*
560a06d536bSMatthew Dillon 		 * Termination
561a06d536bSMatthew Dillon 		 */
562a06d536bSMatthew Dillon 		if (sc->spancnt == 0)
563a06d536bSMatthew Dillon 			xa_terminate_check(sc);
564a06d536bSMatthew Dillon #endif
565ddfbb283SMatthew Dillon 		break;
566bab1d4ffSMatthew Dillon 	case DMSG_LNK_SPAN | DMSGF_DELETE | DMSGF_REPLY:
567a06d536bSMatthew Dillon 		/*
568a06d536bSMatthew Dillon 		 * Ignore unimplemented streaming replies on our LNK_SPAN
569a06d536bSMatthew Dillon 		 * transaction.
570a06d536bSMatthew Dillon 		 */
5715ab1caedSMatthew Dillon 		xa_printf(3, "LINK_SPAN state %p delete+reply\n",
572a06d536bSMatthew Dillon 			  msg->state);
573a06d536bSMatthew Dillon 		break;
574d30cab67SMatthew Dillon 	case DMSG_LNK_SPAN | DMSGF_REPLY:
5758d6d37b8SMatthew Dillon 		/*
576d30cab67SMatthew Dillon 		 * Ignore unimplemented streaming replies on our LNK_SPAN
577d30cab67SMatthew Dillon 		 * transaction.
5788d6d37b8SMatthew Dillon 		 */
5795ab1caedSMatthew Dillon 		xa_printf(3, "LINK_SPAN state %p reply\n",
580a06d536bSMatthew Dillon 			  msg->state);
581ddfbb283SMatthew Dillon 		break;
582ddfbb283SMatthew Dillon 	case DMSG_DBG_SHELL:
583ddfbb283SMatthew Dillon 		/*
5843b76886bSMatthew Dillon 		 * Execute shell command (not supported atm).
5853b76886bSMatthew Dillon 		 *
5863b76886bSMatthew Dillon 		 * This is a one-way packet but if not (e.g. if part of
5873b76886bSMatthew Dillon 		 * a streaming transaction), we will have already closed
5883b76886bSMatthew Dillon 		 * our end.
589ddfbb283SMatthew Dillon 		 */
590ddfbb283SMatthew Dillon 		kdmsg_msg_reply(msg, DMSG_ERR_NOSUPP);
591ddfbb283SMatthew Dillon 		break;
592ddfbb283SMatthew Dillon 	case DMSG_DBG_SHELL | DMSGF_REPLY:
5933b76886bSMatthew Dillon 		/*
594d30cab67SMatthew Dillon 		 * Receive one or more replies to a shell command
595d30cab67SMatthew Dillon 		 * that we sent.  Just dump it to the console.
5963b76886bSMatthew Dillon 		 *
597d30cab67SMatthew Dillon 		 * This is a one-way packet but if not (e.g. if
598d30cab67SMatthew Dillon 		 * part of a streaming transaction), we will have
599d30cab67SMatthew Dillon 		 * already closed our end.
6003b76886bSMatthew Dillon 		 */
601ddfbb283SMatthew Dillon 		if (msg->aux_data) {
602ddfbb283SMatthew Dillon 			msg->aux_data[msg->aux_size - 1] = 0;
6035ab1caedSMatthew Dillon 			xa_printf(0, "DEBUGMSG: %s\n", msg->aux_data);
604ddfbb283SMatthew Dillon 		}
605ddfbb283SMatthew Dillon 		break;
606ddfbb283SMatthew Dillon 	default:
6073b76886bSMatthew Dillon 		/*
608d30cab67SMatthew Dillon 		 * Unsupported one-way message, streaming message, or
609d30cab67SMatthew Dillon 		 * transaction.
610d30cab67SMatthew Dillon 		 *
611d30cab67SMatthew Dillon 		 * Terminate any unsupported transactions with an error
612d30cab67SMatthew Dillon 		 * and ignore any unsupported streaming messages.
6130f50fb46SMatthew Dillon 		 *
6140f50fb46SMatthew Dillon 		 * NOTE: This case also includes DMSG_LNK_ERROR messages
6150f50fb46SMatthew Dillon 		 *	 which might be one-way, replying to those would
6160f50fb46SMatthew Dillon 		 *	 cause an infinite ping-pong.
6173b76886bSMatthew Dillon 		 */
6180f50fb46SMatthew Dillon 		if (msg->any.head.cmd & DMSGF_CREATE)
619ddfbb283SMatthew Dillon 			kdmsg_msg_reply(msg, DMSG_ERR_NOSUPP);
620ddfbb283SMatthew Dillon 		break;
621ddfbb283SMatthew Dillon 	}
622a06d536bSMatthew Dillon 	lockmgr(&xdisk_lk, LK_RELEASE);
623d30cab67SMatthew Dillon 
624d30cab67SMatthew Dillon 	return 0;
625ddfbb283SMatthew Dillon }
626ddfbb283SMatthew Dillon 
627d30cab67SMatthew Dillon /*
628d30cab67SMatthew Dillon  * Determine if we can destroy the xa_softc.
629d30cab67SMatthew Dillon  *
630a06d536bSMatthew Dillon  * Called with xdisk_lk held.
631d30cab67SMatthew Dillon  */
632d30cab67SMatthew Dillon static
633d30cab67SMatthew Dillon void
xa_terminate_check(struct xa_softc * sc)634d30cab67SMatthew Dillon xa_terminate_check(struct xa_softc *sc)
635d30cab67SMatthew Dillon {
636d30cab67SMatthew Dillon 	xa_tag_t *tag;
637d30cab67SMatthew Dillon 
638d30cab67SMatthew Dillon 	/*
639d30cab67SMatthew Dillon 	 * Determine if we can destroy the softc.
640d30cab67SMatthew Dillon 	 */
6415ab1caedSMatthew Dillon 	xa_printf(1, "Terminate check xa%d (%d,%d,%d) sc=%p ",
642d30cab67SMatthew Dillon 		sc->unit,
643323c0947SMatthew Dillon 		sc->opencnt, sc->serializing, sc->spancnt,
644323c0947SMatthew Dillon 		sc);
645d30cab67SMatthew Dillon 
6465ab1caedSMatthew Dillon 	if (sc->opencnt || sc->serializing || sc->spancnt ||
6475ab1caedSMatthew Dillon 	    TAILQ_FIRST(&sc->bioq) || TAILQ_FIRST(&sc->tag_pendq)) {
6485ab1caedSMatthew Dillon 		xa_printf(1, "%s", "(leave intact)\n");
649d30cab67SMatthew Dillon 		return;
650323c0947SMatthew Dillon 	}
651d30cab67SMatthew Dillon 
652a06d536bSMatthew Dillon 	/*
653a06d536bSMatthew Dillon 	 * Remove from device tree, a race with a new incoming span
654a06d536bSMatthew Dillon 	 * will create a new softc and disk.
655a06d536bSMatthew Dillon 	 */
656d30cab67SMatthew Dillon 	RB_REMOVE(xa_softc_tree, &xa_device_tree, sc);
6575ab1caedSMatthew Dillon 	sc->terminating = 1;
658d30cab67SMatthew Dillon 
659a06d536bSMatthew Dillon 	/*
660a06d536bSMatthew Dillon 	 * Device has to go first to prevent device ops races.
661a06d536bSMatthew Dillon 	 */
662d30cab67SMatthew Dillon 	if (sc->dev) {
663d30cab67SMatthew Dillon 		disk_destroy(&sc->disk);
664bab1d4ffSMatthew Dillon 		devstat_remove_entry(&sc->stats);
665d30cab67SMatthew Dillon 		sc->dev->si_drv1 = NULL;
666d30cab67SMatthew Dillon 		sc->dev = NULL;
667d30cab67SMatthew Dillon 	}
668a06d536bSMatthew Dillon 
6695ab1caedSMatthew Dillon 	xa_printf(1, "%s", "(remove from tree)\n");
670a06d536bSMatthew Dillon 	sc->serializing = 1;
671d30cab67SMatthew Dillon 	KKASSERT(sc->opencnt == 0);
672d30cab67SMatthew Dillon 	KKASSERT(TAILQ_EMPTY(&sc->tag_pendq));
673d30cab67SMatthew Dillon 
674d30cab67SMatthew Dillon 	while ((tag = TAILQ_FIRST(&sc->tag_freeq)) != NULL) {
675d30cab67SMatthew Dillon 		TAILQ_REMOVE(&sc->tag_freeq, tag, entry);
676d30cab67SMatthew Dillon 		tag->sc = NULL;
677d30cab67SMatthew Dillon 		kfree(tag, M_XDISK);
678d30cab67SMatthew Dillon 	}
679bab1d4ffSMatthew Dillon 
680d30cab67SMatthew Dillon 	kfree(sc, M_XDISK);
681d30cab67SMatthew Dillon }
682ddfbb283SMatthew Dillon 
683ddfbb283SMatthew Dillon /************************************************************************
684ddfbb283SMatthew Dillon  *			   XA DEVICE INTERFACE				*
685ddfbb283SMatthew Dillon  ************************************************************************/
686ddfbb283SMatthew Dillon 
687ddfbb283SMatthew Dillon static int
xa_open(struct dev_open_args * ap)688ddfbb283SMatthew Dillon xa_open(struct dev_open_args *ap)
689ddfbb283SMatthew Dillon {
690ddfbb283SMatthew Dillon 	cdev_t dev = ap->a_head.a_dev;
691d30cab67SMatthew Dillon 	xa_softc_t *sc;
6920f50fb46SMatthew Dillon 	int error;
693ddfbb283SMatthew Dillon 
694ddfbb283SMatthew Dillon 	dev->si_bsize_phys = 512;
695ddfbb283SMatthew Dillon 	dev->si_bsize_best = 32768;
696ddfbb283SMatthew Dillon 
697ddfbb283SMatthew Dillon 	/*
6980f50fb46SMatthew Dillon 	 * Interlock open with opencnt, wait for attachment operations
6990f50fb46SMatthew Dillon 	 * to finish.
700ddfbb283SMatthew Dillon 	 */
701a06d536bSMatthew Dillon 	lockmgr(&xdisk_lk, LK_EXCLUSIVE);
7020f50fb46SMatthew Dillon again:
703d30cab67SMatthew Dillon 	sc = dev->si_drv1;
704d30cab67SMatthew Dillon 	if (sc == NULL) {
705a06d536bSMatthew Dillon 		lockmgr(&xdisk_lk, LK_RELEASE);
7060f50fb46SMatthew Dillon 		return ENXIO;	/* raced destruction */
7070f50fb46SMatthew Dillon 	}
708d30cab67SMatthew Dillon 	if (sc->serializing) {
709d30cab67SMatthew Dillon 		tsleep(sc, 0, "xarace", hz / 10);
7100f50fb46SMatthew Dillon 		goto again;
7110f50fb46SMatthew Dillon 	}
7125ab1caedSMatthew Dillon 	if (sc->terminating) {
7135ab1caedSMatthew Dillon 		lockmgr(&xdisk_lk, LK_RELEASE);
7145ab1caedSMatthew Dillon 		return ENXIO;	/* raced destruction */
7155ab1caedSMatthew Dillon 	}
716d30cab67SMatthew Dillon 	sc->serializing = 1;
717ddfbb283SMatthew Dillon 
7180f50fb46SMatthew Dillon 	/*
7190f50fb46SMatthew Dillon 	 * Serialize initial open
7200f50fb46SMatthew Dillon 	 */
721d30cab67SMatthew Dillon 	if (sc->opencnt++ > 0) {
722bab1d4ffSMatthew Dillon 		sc->serializing = 0;
723bab1d4ffSMatthew Dillon 		wakeup(sc);
724a06d536bSMatthew Dillon 		lockmgr(&xdisk_lk, LK_RELEASE);
725ddfbb283SMatthew Dillon 		return(0);
726ddfbb283SMatthew Dillon 	}
7270f50fb46SMatthew Dillon 
728d30cab67SMatthew Dillon 	/*
729d30cab67SMatthew Dillon 	 * Issue BLK_OPEN if necessary.  ENXIO is returned if we have trouble.
730d30cab67SMatthew Dillon 	 */
731d30cab67SMatthew Dillon 	if (sc->open_tag == NULL) {
7325dafdfbaSMatthew Dillon 		lockmgr(&sc->lk, LK_EXCLUSIVE);
733d30cab67SMatthew Dillon 		xa_restart_deferred(sc); /* eats serializing */
7345dafdfbaSMatthew Dillon 		lockmgr(&sc->lk, LK_RELEASE);
7350f50fb46SMatthew Dillon 	} else {
736d30cab67SMatthew Dillon 		sc->serializing = 0;
737d30cab67SMatthew Dillon 		wakeup(sc);
7380f50fb46SMatthew Dillon 	}
739a06d536bSMatthew Dillon 	lockmgr(&xdisk_lk, LK_RELEASE);
740d30cab67SMatthew Dillon 
741d30cab67SMatthew Dillon 	/*
742d30cab67SMatthew Dillon 	 * Wait for completion of the BLK_OPEN
743d30cab67SMatthew Dillon 	 */
744a06d536bSMatthew Dillon 	lockmgr(&xdisk_lk, LK_EXCLUSIVE);
745d30cab67SMatthew Dillon 	while (sc->serializing)
746a06d536bSMatthew Dillon 		lksleep(sc, &xdisk_lk, 0, "xaopen", hz);
747d30cab67SMatthew Dillon 
748d30cab67SMatthew Dillon 	error = sc->last_error;
749d30cab67SMatthew Dillon 	if (error) {
750d30cab67SMatthew Dillon 		KKASSERT(sc->opencnt > 0);
751d30cab67SMatthew Dillon 		--sc->opencnt;
752d30cab67SMatthew Dillon 		xa_terminate_check(sc);
753d30cab67SMatthew Dillon 		sc = NULL;	/* sc may be invalid now */
754d30cab67SMatthew Dillon 	}
755a06d536bSMatthew Dillon 	lockmgr(&xdisk_lk, LK_RELEASE);
756d30cab67SMatthew Dillon 
7570f50fb46SMatthew Dillon 	return (error);
7580f50fb46SMatthew Dillon }
759ddfbb283SMatthew Dillon 
760ddfbb283SMatthew Dillon static int
xa_close(struct dev_close_args * ap)761ddfbb283SMatthew Dillon xa_close(struct dev_close_args *ap)
762ddfbb283SMatthew Dillon {
763ddfbb283SMatthew Dillon 	cdev_t dev = ap->a_head.a_dev;
764d30cab67SMatthew Dillon 	xa_softc_t *sc;
7650f50fb46SMatthew Dillon 	xa_tag_t *tag;
7660f50fb46SMatthew Dillon 
767a06d536bSMatthew Dillon 	lockmgr(&xdisk_lk, LK_EXCLUSIVE);
7685ab1caedSMatthew Dillon 	sc = dev->si_drv1;
769*42e46aeeSSascha Wildner 	if (sc == NULL)
7705ab1caedSMatthew Dillon 		return ENXIO;	/* raced destruction */
7715ab1caedSMatthew Dillon 	if (sc->terminating) {
7725ab1caedSMatthew Dillon 		lockmgr(&sc->lk, LK_RELEASE);
7735ab1caedSMatthew Dillon 		return ENXIO;	/* raced destruction */
7745ab1caedSMatthew Dillon 	}
775a06d536bSMatthew Dillon 	lockmgr(&sc->lk, LK_EXCLUSIVE);
776d30cab67SMatthew Dillon 
777d30cab67SMatthew Dillon 	/*
778d30cab67SMatthew Dillon 	 * NOTE: Clearing open_tag allows a concurrent open to re-open
779d30cab67SMatthew Dillon 	 *	 the device and prevents autonomous completion of the tag.
780d30cab67SMatthew Dillon 	 */
781d30cab67SMatthew Dillon 	if (sc->opencnt == 1 && sc->open_tag) {
782d30cab67SMatthew Dillon 		tag = sc->open_tag;
783d30cab67SMatthew Dillon 		sc->open_tag = NULL;
784a06d536bSMatthew Dillon 		lockmgr(&sc->lk, LK_RELEASE);
785d30cab67SMatthew Dillon 		kdmsg_state_reply(tag->state, 0);	/* close our side */
786d30cab67SMatthew Dillon 		xa_wait(tag);				/* wait on remote */
787a06d536bSMatthew Dillon 	} else {
788a06d536bSMatthew Dillon 		lockmgr(&sc->lk, LK_RELEASE);
789d30cab67SMatthew Dillon 	}
790d30cab67SMatthew Dillon 	KKASSERT(sc->opencnt > 0);
791d30cab67SMatthew Dillon 	--sc->opencnt;
792d30cab67SMatthew Dillon 	xa_terminate_check(sc);
793a06d536bSMatthew Dillon 	lockmgr(&xdisk_lk, LK_RELEASE);
7940f50fb46SMatthew Dillon 
7950f50fb46SMatthew Dillon 	return(0);
796ddfbb283SMatthew Dillon }
797ddfbb283SMatthew Dillon 
798ddfbb283SMatthew Dillon static int
xa_strategy(struct dev_strategy_args * ap)799ddfbb283SMatthew Dillon xa_strategy(struct dev_strategy_args *ap)
800ddfbb283SMatthew Dillon {
801d30cab67SMatthew Dillon 	xa_softc_t *sc = ap->a_head.a_dev->si_drv1;
8020f50fb46SMatthew Dillon 	xa_tag_t *tag;
8030f50fb46SMatthew Dillon 	struct bio *bio = ap->a_bio;
8040f50fb46SMatthew Dillon 
805bab1d4ffSMatthew Dillon 	devstat_start_transaction(&sc->stats);
806bab1d4ffSMatthew Dillon 	atomic_add_int(&xa_active, 1);
807bab1d4ffSMatthew Dillon 	xa_last = bio->bio_offset;
8080f50fb46SMatthew Dillon 
8095dafdfbaSMatthew Dillon 	/*
8105dafdfbaSMatthew Dillon 	 * If no tags are available NULL is returned and the bio is
8115dafdfbaSMatthew Dillon 	 * placed on sc->bioq.
8125dafdfbaSMatthew Dillon 	 */
813a06d536bSMatthew Dillon 	lockmgr(&sc->lk, LK_EXCLUSIVE);
814d30cab67SMatthew Dillon 	tag = xa_setup_cmd(sc, bio);
8155a78b06aSMatthew Dillon 	if (tag)
816d30cab67SMatthew Dillon 		xa_start(tag, NULL, 1);
817a06d536bSMatthew Dillon 	lockmgr(&sc->lk, LK_RELEASE);
818a06d536bSMatthew Dillon 
8190f50fb46SMatthew Dillon 	return(0);
820ddfbb283SMatthew Dillon }
821ddfbb283SMatthew Dillon 
822ddfbb283SMatthew Dillon static int
xa_ioctl(struct dev_ioctl_args * ap)823ddfbb283SMatthew Dillon xa_ioctl(struct dev_ioctl_args *ap)
824ddfbb283SMatthew Dillon {
825ddfbb283SMatthew Dillon 	return(ENOTTY);
826ddfbb283SMatthew Dillon }
827ddfbb283SMatthew Dillon 
828ddfbb283SMatthew Dillon static int
xa_size(struct dev_psize_args * ap)829ddfbb283SMatthew Dillon xa_size(struct dev_psize_args *ap)
830ddfbb283SMatthew Dillon {
831d30cab67SMatthew Dillon 	struct xa_softc *sc;
832ddfbb283SMatthew Dillon 
833d30cab67SMatthew Dillon 	if ((sc = ap->a_head.a_dev->si_drv1) == NULL)
834ddfbb283SMatthew Dillon 		return (ENXIO);
835d30cab67SMatthew Dillon 	ap->a_result = sc->info.d_media_blocks;
836ddfbb283SMatthew Dillon 	return (0);
837ddfbb283SMatthew Dillon }
8380f50fb46SMatthew Dillon 
8390f50fb46SMatthew Dillon /************************************************************************
8400f50fb46SMatthew Dillon  *		    XA BLOCK PROTOCOL STATE MACHINE			*
8410f50fb46SMatthew Dillon  ************************************************************************
8420f50fb46SMatthew Dillon  *
8430f50fb46SMatthew Dillon  * Implement tag/msg setup and related functions.
844a06d536bSMatthew Dillon  * Called with sc->lk held.
8450f50fb46SMatthew Dillon  */
8460f50fb46SMatthew Dillon static xa_tag_t *
xa_setup_cmd(xa_softc_t * sc,struct bio * bio)847d30cab67SMatthew Dillon xa_setup_cmd(xa_softc_t *sc, struct bio *bio)
8480f50fb46SMatthew Dillon {
8490f50fb46SMatthew Dillon 	xa_tag_t *tag;
8500f50fb46SMatthew Dillon 
8510f50fb46SMatthew Dillon 	/*
8520f50fb46SMatthew Dillon 	 * Only get a tag if we have a valid virtual circuit to the server.
8530f50fb46SMatthew Dillon 	 */
854d30cab67SMatthew Dillon 	if ((tag = TAILQ_FIRST(&sc->tag_freeq)) != NULL) {
855d30cab67SMatthew Dillon 		TAILQ_REMOVE(&sc->tag_freeq, tag, entry);
8560f50fb46SMatthew Dillon 		tag->bio = bio;
857d30cab67SMatthew Dillon 		TAILQ_INSERT_TAIL(&sc->tag_pendq, tag, entry);
8580f50fb46SMatthew Dillon 	}
8590f50fb46SMatthew Dillon 
8600f50fb46SMatthew Dillon 	/*
8610f50fb46SMatthew Dillon 	 * If we can't dispatch now and this is a bio, queue it for later.
8620f50fb46SMatthew Dillon 	 */
8630f50fb46SMatthew Dillon 	if (tag == NULL && bio) {
864d30cab67SMatthew Dillon 		TAILQ_INSERT_TAIL(&sc->bioq, bio, bio_act);
8650f50fb46SMatthew Dillon 	}
8660f50fb46SMatthew Dillon 
8670f50fb46SMatthew Dillon 	return (tag);
8680f50fb46SMatthew Dillon }
8690f50fb46SMatthew Dillon 
870a06d536bSMatthew Dillon /*
871a06d536bSMatthew Dillon  * Called with sc->lk held
872a06d536bSMatthew Dillon  */
8730f50fb46SMatthew Dillon static void
xa_start(xa_tag_t * tag,kdmsg_msg_t * msg,int async)874d30cab67SMatthew Dillon xa_start(xa_tag_t *tag, kdmsg_msg_t *msg, int async)
8750f50fb46SMatthew Dillon {
876d30cab67SMatthew Dillon 	xa_softc_t *sc = tag->sc;
877d30cab67SMatthew Dillon 
878d30cab67SMatthew Dillon 	tag->done = 0;
879d30cab67SMatthew Dillon 	tag->async = async;
8805dafdfbaSMatthew Dillon 	tag->status.head.error = DMSG_ERR_IO;	/* fallback error */
8810f50fb46SMatthew Dillon 
8820f50fb46SMatthew Dillon 	if (msg == NULL) {
8830f50fb46SMatthew Dillon 		struct bio *bio;
8840f50fb46SMatthew Dillon 		struct buf *bp;
885a06d536bSMatthew Dillon 		kdmsg_state_t *trans;
886a06d536bSMatthew Dillon 
887a06d536bSMatthew Dillon 		if (sc->opencnt == 0 || sc->open_tag == NULL) {
888a06d536bSMatthew Dillon 			TAILQ_FOREACH(trans, &sc->spanq, user_entry) {
889a06d536bSMatthew Dillon 				if ((trans->rxcmd & DMSGF_DELETE) == 0)
890a06d536bSMatthew Dillon 					break;
891a06d536bSMatthew Dillon 			}
892a06d536bSMatthew Dillon 		} else {
893a06d536bSMatthew Dillon 			trans = sc->open_tag->state;
894a06d536bSMatthew Dillon 		}
895a06d536bSMatthew Dillon 		if (trans == NULL)
896a06d536bSMatthew Dillon 			goto skip;
8970f50fb46SMatthew Dillon 
8980f50fb46SMatthew Dillon 		KKASSERT(tag->bio);
8990f50fb46SMatthew Dillon 		bio = tag->bio;
9000f50fb46SMatthew Dillon 		bp = bio->bio_buf;
9010f50fb46SMatthew Dillon 
9020f50fb46SMatthew Dillon 		switch(bp->b_cmd) {
9030f50fb46SMatthew Dillon 		case BUF_CMD_READ:
904a06d536bSMatthew Dillon 			msg = kdmsg_msg_alloc(trans,
905d34b92afSMatthew Dillon 					      DMSG_BLK_READ |
906d34b92afSMatthew Dillon 					      DMSGF_CREATE |
907d34b92afSMatthew Dillon 					      DMSGF_DELETE,
908d34b92afSMatthew Dillon 					      xa_bio_completion, tag);
909d30cab67SMatthew Dillon 			msg->any.blk_read.keyid = sc->keyid;
9100f50fb46SMatthew Dillon 			msg->any.blk_read.offset = bio->bio_offset;
9110f50fb46SMatthew Dillon 			msg->any.blk_read.bytes = bp->b_bcount;
9120f50fb46SMatthew Dillon 			break;
9130f50fb46SMatthew Dillon 		case BUF_CMD_WRITE:
914a06d536bSMatthew Dillon 			msg = kdmsg_msg_alloc(trans,
9150f50fb46SMatthew Dillon 					      DMSG_BLK_WRITE |
9160f50fb46SMatthew Dillon 					      DMSGF_CREATE | DMSGF_DELETE,
9170f50fb46SMatthew Dillon 					      xa_bio_completion, tag);
918d30cab67SMatthew Dillon 			msg->any.blk_write.keyid = sc->keyid;
9190f50fb46SMatthew Dillon 			msg->any.blk_write.offset = bio->bio_offset;
9200f50fb46SMatthew Dillon 			msg->any.blk_write.bytes = bp->b_bcount;
9210f50fb46SMatthew Dillon 			msg->aux_data = bp->b_data;
9220f50fb46SMatthew Dillon 			msg->aux_size = bp->b_bcount;
9230f50fb46SMatthew Dillon 			break;
9240f50fb46SMatthew Dillon 		case BUF_CMD_FLUSH:
925a06d536bSMatthew Dillon 			msg = kdmsg_msg_alloc(trans,
9260f50fb46SMatthew Dillon 					      DMSG_BLK_FLUSH |
9270f50fb46SMatthew Dillon 					      DMSGF_CREATE | DMSGF_DELETE,
9280f50fb46SMatthew Dillon 					      xa_bio_completion, tag);
929d30cab67SMatthew Dillon 			msg->any.blk_flush.keyid = sc->keyid;
9300f50fb46SMatthew Dillon 			msg->any.blk_flush.offset = bio->bio_offset;
9310f50fb46SMatthew Dillon 			msg->any.blk_flush.bytes = bp->b_bcount;
9320f50fb46SMatthew Dillon 			break;
9330f50fb46SMatthew Dillon 		case BUF_CMD_FREEBLKS:
934a06d536bSMatthew Dillon 			msg = kdmsg_msg_alloc(trans,
9350f50fb46SMatthew Dillon 					      DMSG_BLK_FREEBLKS |
9360f50fb46SMatthew Dillon 					      DMSGF_CREATE | DMSGF_DELETE,
9370f50fb46SMatthew Dillon 					      xa_bio_completion, tag);
938d30cab67SMatthew Dillon 			msg->any.blk_freeblks.keyid = sc->keyid;
9390f50fb46SMatthew Dillon 			msg->any.blk_freeblks.offset = bio->bio_offset;
9400f50fb46SMatthew Dillon 			msg->any.blk_freeblks.bytes = bp->b_bcount;
9410f50fb46SMatthew Dillon 			break;
9420f50fb46SMatthew Dillon 		default:
9430f50fb46SMatthew Dillon 			bp->b_flags |= B_ERROR;
9440f50fb46SMatthew Dillon 			bp->b_error = EIO;
945bab1d4ffSMatthew Dillon 			devstat_end_transaction_buf(&sc->stats, bp);
946bab1d4ffSMatthew Dillon 			atomic_add_int(&xa_active, -1);
9470f50fb46SMatthew Dillon 			biodone(bio);
9480f50fb46SMatthew Dillon 			tag->bio = NULL;
9490f50fb46SMatthew Dillon 			break;
9500f50fb46SMatthew Dillon 		}
9510f50fb46SMatthew Dillon 	}
9520f50fb46SMatthew Dillon 
953a06d536bSMatthew Dillon 	/*
9545dafdfbaSMatthew Dillon 	 * If no msg was allocated we likely could not find a good span.
955a06d536bSMatthew Dillon 	 */
956a06d536bSMatthew Dillon skip:
9570f50fb46SMatthew Dillon 	if (msg) {
9585dafdfbaSMatthew Dillon 		/*
9595dafdfbaSMatthew Dillon 		 * Message was passed in or constructed.
9605dafdfbaSMatthew Dillon 		 */
9610f50fb46SMatthew Dillon 		tag->state = msg->state;
9625dafdfbaSMatthew Dillon 		lockmgr(&sc->lk, LK_RELEASE);
9630f50fb46SMatthew Dillon 		kdmsg_msg_write(msg);
9645dafdfbaSMatthew Dillon 		lockmgr(&sc->lk, LK_EXCLUSIVE);
9655dafdfbaSMatthew Dillon 	} else if (tag->bio &&
9665dafdfbaSMatthew Dillon 		   (tag->bio->bio_buf->b_flags & B_FAILONDIS) == 0) {
9675dafdfbaSMatthew Dillon 		/*
9685dafdfbaSMatthew Dillon 		 * No spans available but BIO is not allowed to fail
9695dafdfbaSMatthew Dillon 		 * on connectivity problems.  Requeue the BIO.
9705dafdfbaSMatthew Dillon 		 */
9715dafdfbaSMatthew Dillon 		TAILQ_INSERT_TAIL(&sc->bioq, tag->bio, bio_act);
9725dafdfbaSMatthew Dillon 		tag->bio = NULL;
9735dafdfbaSMatthew Dillon 		lockmgr(&sc->lk, LK_RELEASE);
9745dafdfbaSMatthew Dillon 		xa_done(tag, 1);
9755dafdfbaSMatthew Dillon 		lockmgr(&sc->lk, LK_EXCLUSIVE);
9760f50fb46SMatthew Dillon 	} else {
9775dafdfbaSMatthew Dillon 		/*
9785dafdfbaSMatthew Dillon 		 * No spans available, bio is allowed to fail.
9795dafdfbaSMatthew Dillon 		 */
980a06d536bSMatthew Dillon 		lockmgr(&sc->lk, LK_RELEASE);
981d30cab67SMatthew Dillon 		tag->status.head.error = DMSG_ERR_IO;
9820f50fb46SMatthew Dillon 		xa_done(tag, 1);
983a06d536bSMatthew Dillon 		lockmgr(&sc->lk, LK_EXCLUSIVE);
9840f50fb46SMatthew Dillon 	}
9850f50fb46SMatthew Dillon }
9860f50fb46SMatthew Dillon 
9870f50fb46SMatthew Dillon static uint32_t
xa_wait(xa_tag_t * tag)988d30cab67SMatthew Dillon xa_wait(xa_tag_t *tag)
9890f50fb46SMatthew Dillon {
990d30cab67SMatthew Dillon 	xa_softc_t *sc = tag->sc;
991d30cab67SMatthew Dillon 	uint32_t error;
9920f50fb46SMatthew Dillon 
993a06d536bSMatthew Dillon 	lockmgr(&sc->lk, LK_EXCLUSIVE);
994d30cab67SMatthew Dillon 	tag->waiting = 1;
995d30cab67SMatthew Dillon 	while (tag->done == 0)
996a06d536bSMatthew Dillon 		lksleep(tag, &sc->lk, 0, "xawait", 0);
997a06d536bSMatthew Dillon 	lockmgr(&sc->lk, LK_RELEASE);
998a06d536bSMatthew Dillon 
999d30cab67SMatthew Dillon 	error = tag->status.head.error;
1000d30cab67SMatthew Dillon 	tag->waiting = 0;
1001d30cab67SMatthew Dillon 	xa_release(tag, 0);
1002d30cab67SMatthew Dillon 
1003d30cab67SMatthew Dillon 	return error;
10040f50fb46SMatthew Dillon }
10050f50fb46SMatthew Dillon 
10060f50fb46SMatthew Dillon static void
xa_done(xa_tag_t * tag,int wasbio)10070f50fb46SMatthew Dillon xa_done(xa_tag_t *tag, int wasbio)
10080f50fb46SMatthew Dillon {
1009d30cab67SMatthew Dillon 	KKASSERT(tag->bio == NULL);
1010d30cab67SMatthew Dillon 
1011d30cab67SMatthew Dillon 	tag->state = NULL;
1012d30cab67SMatthew Dillon 	tag->done = 1;
1013d30cab67SMatthew Dillon 	if (tag->waiting)
1014d30cab67SMatthew Dillon 		wakeup(tag);
1015d30cab67SMatthew Dillon 	if (tag->async)
1016d30cab67SMatthew Dillon 		xa_release(tag, wasbio);
1017d30cab67SMatthew Dillon }
1018d30cab67SMatthew Dillon 
1019bab1d4ffSMatthew Dillon /*
1020bab1d4ffSMatthew Dillon  * Release a tag.  If everything looks ok and there are pending BIOs
1021bab1d4ffSMatthew Dillon  * (due to all tags in-use), we can use the tag to start the next BIO.
1022bab1d4ffSMatthew Dillon  * Do not try to restart if the connection is currently failed.
1023bab1d4ffSMatthew Dillon  */
1024d30cab67SMatthew Dillon static
1025d30cab67SMatthew Dillon void
xa_release(xa_tag_t * tag,int wasbio)1026d30cab67SMatthew Dillon xa_release(xa_tag_t *tag, int wasbio)
1027d30cab67SMatthew Dillon {
1028d30cab67SMatthew Dillon 	xa_softc_t *sc = tag->sc;
10290f50fb46SMatthew Dillon 	struct bio *bio;
10300f50fb46SMatthew Dillon 
1031a06d536bSMatthew Dillon 	if ((bio = tag->bio) != NULL) {
1032a06d536bSMatthew Dillon 		struct buf *bp = bio->bio_buf;
1033a06d536bSMatthew Dillon 
1034a06d536bSMatthew Dillon 		bp->b_error = EIO;
1035a06d536bSMatthew Dillon 		bp->b_flags |= B_ERROR;
1036a06d536bSMatthew Dillon 		devstat_end_transaction_buf(&sc->stats, bp);
1037a06d536bSMatthew Dillon 		atomic_add_int(&xa_active, -1);
1038a06d536bSMatthew Dillon 		biodone(bio);
1039a06d536bSMatthew Dillon 		tag->bio = NULL;
1040a06d536bSMatthew Dillon 	}
1041a06d536bSMatthew Dillon 
1042a06d536bSMatthew Dillon 	lockmgr(&sc->lk, LK_EXCLUSIVE);
1043a06d536bSMatthew Dillon 
1044bab1d4ffSMatthew Dillon 	if (wasbio && sc->open_tag &&
1045bab1d4ffSMatthew Dillon 	    (bio = TAILQ_FIRST(&sc->bioq)) != NULL) {
1046d30cab67SMatthew Dillon 		TAILQ_REMOVE(&sc->bioq, bio, bio_act);
10470f50fb46SMatthew Dillon 		tag->bio = bio;
1048d30cab67SMatthew Dillon 		xa_start(tag, NULL, 1);
10490f50fb46SMatthew Dillon 	} else {
1050d30cab67SMatthew Dillon 		TAILQ_REMOVE(&sc->tag_pendq, tag, entry);
1051d30cab67SMatthew Dillon 		TAILQ_INSERT_TAIL(&sc->tag_freeq, tag, entry);
10520f50fb46SMatthew Dillon 	}
1053a06d536bSMatthew Dillon 	lockmgr(&sc->lk, LK_RELEASE);
10540f50fb46SMatthew Dillon }
10550f50fb46SMatthew Dillon 
1056d30cab67SMatthew Dillon /*
1057d30cab67SMatthew Dillon  * Handle messages under the BLKOPEN transaction.
1058d30cab67SMatthew Dillon  */
10590f50fb46SMatthew Dillon static int
xa_sync_completion(kdmsg_state_t * state,kdmsg_msg_t * msg)10600f50fb46SMatthew Dillon xa_sync_completion(kdmsg_state_t *state, kdmsg_msg_t *msg)
10610f50fb46SMatthew Dillon {
10620f50fb46SMatthew Dillon 	xa_tag_t *tag = state->any.any;
1063b11f41cdSSascha Wildner 	xa_softc_t *sc;
1064d30cab67SMatthew Dillon 	struct bio *bio;
10650f50fb46SMatthew Dillon 
1066d30cab67SMatthew Dillon 	/*
1067d30cab67SMatthew Dillon 	 * If the tag has been cleaned out we already closed our side
1068d30cab67SMatthew Dillon 	 * of the transaction and we are waiting for the other side to
1069d30cab67SMatthew Dillon 	 * close.
1070d30cab67SMatthew Dillon 	 */
10715ab1caedSMatthew Dillon 	xa_printf(1, "xa_sync_completion: tag %p msg %08x state %p\n",
1072a06d536bSMatthew Dillon 		  tag, msg->any.head.cmd, msg->state);
1073a06d536bSMatthew Dillon 
1074d30cab67SMatthew Dillon 	if (tag == NULL) {
1075d30cab67SMatthew Dillon 		if (msg->any.head.cmd & DMSGF_CREATE)
1076d30cab67SMatthew Dillon 			kdmsg_state_reply(state, DMSG_ERR_LOSTLINK);
1077d30cab67SMatthew Dillon 		return 0;
1078d30cab67SMatthew Dillon 	}
1079b11f41cdSSascha Wildner 	sc = tag->sc;
1080d30cab67SMatthew Dillon 
1081d30cab67SMatthew Dillon 	/*
1082d30cab67SMatthew Dillon 	 * Validate the tag
1083d30cab67SMatthew Dillon 	 */
1084a06d536bSMatthew Dillon 	lockmgr(&sc->lk, LK_EXCLUSIVE);
1085d30cab67SMatthew Dillon 
1086d30cab67SMatthew Dillon 	/*
1087d30cab67SMatthew Dillon 	 * Handle initial response to our open and restart any deferred
1088d30cab67SMatthew Dillon 	 * BIOs on success.
1089d30cab67SMatthew Dillon 	 *
1090d30cab67SMatthew Dillon 	 * NOTE: DELETE may also be set.
1091d30cab67SMatthew Dillon 	 */
1092d30cab67SMatthew Dillon 	if (msg->any.head.cmd & DMSGF_CREATE) {
10930f50fb46SMatthew Dillon 		switch(msg->any.head.cmd & DMSGF_CMDSWMASK) {
10940f50fb46SMatthew Dillon 		case DMSG_LNK_ERROR | DMSGF_REPLY:
10950f50fb46SMatthew Dillon 			bzero(&tag->status, sizeof(tag->status));
10960f50fb46SMatthew Dillon 			tag->status.head = msg->any.head;
10970f50fb46SMatthew Dillon 			break;
10980f50fb46SMatthew Dillon 		case DMSG_BLK_ERROR | DMSGF_REPLY:
10990f50fb46SMatthew Dillon 			tag->status = msg->any.blk_error;
11000f50fb46SMatthew Dillon 			break;
11010f50fb46SMatthew Dillon 		}
1102d30cab67SMatthew Dillon 		sc->last_error = tag->status.head.error;
11035ab1caedSMatthew Dillon 		xa_printf(1, "blk_open completion status %d\n",
1104d30cab67SMatthew Dillon 			  sc->last_error);
1105d30cab67SMatthew Dillon 		if (sc->last_error == 0) {
1106d30cab67SMatthew Dillon 			while ((bio = TAILQ_FIRST(&sc->bioq)) != NULL) {
1107d30cab67SMatthew Dillon 				tag = xa_setup_cmd(sc, NULL);
1108d30cab67SMatthew Dillon 				if (tag == NULL)
1109d30cab67SMatthew Dillon 					break;
1110d30cab67SMatthew Dillon 				TAILQ_REMOVE(&sc->bioq, bio, bio_act);
1111d30cab67SMatthew Dillon 				tag->bio = bio;
1112d30cab67SMatthew Dillon 				xa_start(tag, NULL, 1);
1113d30cab67SMatthew Dillon 			}
1114d30cab67SMatthew Dillon 		}
1115d30cab67SMatthew Dillon 		sc->serializing = 0;
1116d30cab67SMatthew Dillon 		wakeup(sc);
1117d30cab67SMatthew Dillon 	}
1118d30cab67SMatthew Dillon 
1119d30cab67SMatthew Dillon 	/*
1120d30cab67SMatthew Dillon 	 * Handle unexpected termination (or lost comm channel) from other
1121d30cab67SMatthew Dillon 	 * side.  Autonomous completion only if open_tag matches,
1122d30cab67SMatthew Dillon 	 * otherwise another thread is probably waiting on the tag.
1123d30cab67SMatthew Dillon 	 *
1124d30cab67SMatthew Dillon 	 * (see xa_close() for other interactions)
1125d30cab67SMatthew Dillon 	 */
1126d30cab67SMatthew Dillon 	if (msg->any.head.cmd & DMSGF_DELETE) {
11271f4b0713SMatthew Dillon 		kdmsg_state_reply(tag->state, 0);
1128d30cab67SMatthew Dillon 		if (sc->open_tag == tag) {
1129d30cab67SMatthew Dillon 			sc->open_tag = NULL;
11301f4b0713SMatthew Dillon 			xa_done(tag, 0);
11311f4b0713SMatthew Dillon 		} else {
1132d30cab67SMatthew Dillon 			tag->async = 0;
1133d30cab67SMatthew Dillon 			xa_done(tag, 0);
11340f50fb46SMatthew Dillon 		}
11351f4b0713SMatthew Dillon 	}
1136a06d536bSMatthew Dillon 	lockmgr(&sc->lk, LK_RELEASE);
1137a06d536bSMatthew Dillon 
11380f50fb46SMatthew Dillon 	return (0);
11390f50fb46SMatthew Dillon }
11400f50fb46SMatthew Dillon 
11410f50fb46SMatthew Dillon static int
xa_bio_completion(kdmsg_state_t * state,kdmsg_msg_t * msg)11420f50fb46SMatthew Dillon xa_bio_completion(kdmsg_state_t *state, kdmsg_msg_t *msg)
11430f50fb46SMatthew Dillon {
11440f50fb46SMatthew Dillon 	xa_tag_t *tag = state->any.any;
1145d30cab67SMatthew Dillon 	xa_softc_t *sc = tag->sc;
11460f50fb46SMatthew Dillon 	struct bio *bio;
11470f50fb46SMatthew Dillon 	struct buf *bp;
11480f50fb46SMatthew Dillon 
11490f50fb46SMatthew Dillon 	/*
11500f50fb46SMatthew Dillon 	 * Get the bio from the tag.  If no bio is present we just do
11510f50fb46SMatthew Dillon 	 * 'done' handling.
11520f50fb46SMatthew Dillon 	 */
11530f50fb46SMatthew Dillon 	if ((bio = tag->bio) == NULL)
11540f50fb46SMatthew Dillon 		goto handle_done;
11550f50fb46SMatthew Dillon 	bp = bio->bio_buf;
11560f50fb46SMatthew Dillon 
11570f50fb46SMatthew Dillon 	/*
11580f50fb46SMatthew Dillon 	 * Process return status
11590f50fb46SMatthew Dillon 	 */
11600f50fb46SMatthew Dillon 	switch(msg->any.head.cmd & DMSGF_CMDSWMASK) {
11610f50fb46SMatthew Dillon 	case DMSG_LNK_ERROR | DMSGF_REPLY:
11620f50fb46SMatthew Dillon 		bzero(&tag->status, sizeof(tag->status));
11630f50fb46SMatthew Dillon 		tag->status.head = msg->any.head;
11640f50fb46SMatthew Dillon 		if (tag->status.head.error)
11650f50fb46SMatthew Dillon 			tag->status.resid = bp->b_bcount;
11660f50fb46SMatthew Dillon 		else
11670f50fb46SMatthew Dillon 			tag->status.resid = 0;
11680f50fb46SMatthew Dillon 		break;
11690f50fb46SMatthew Dillon 	case DMSG_BLK_ERROR | DMSGF_REPLY:
11700f50fb46SMatthew Dillon 		tag->status = msg->any.blk_error;
11710f50fb46SMatthew Dillon 		break;
11720f50fb46SMatthew Dillon 	}
11730f50fb46SMatthew Dillon 
11740f50fb46SMatthew Dillon 	/*
1175323c0947SMatthew Dillon 	 * If the device is open stall the bio on DMSG errors.  If an
1176323c0947SMatthew Dillon 	 * actual I/O error occured on the remote device, DMSG_ERR_IO
1177323c0947SMatthew Dillon 	 * will be returned.
11785a78b06aSMatthew Dillon 	 */
11795a78b06aSMatthew Dillon 	if (tag->status.head.error &&
1180d30cab67SMatthew Dillon 	    (msg->any.head.cmd & DMSGF_DELETE) && sc->opencnt) {
1181323c0947SMatthew Dillon 		if (tag->status.head.error != DMSG_ERR_IO)
11825a78b06aSMatthew Dillon 			goto handle_repend;
11835a78b06aSMatthew Dillon 	}
11845a78b06aSMatthew Dillon 
11855a78b06aSMatthew Dillon 	/*
11860f50fb46SMatthew Dillon 	 * Process bio completion
11870f50fb46SMatthew Dillon 	 *
11880f50fb46SMatthew Dillon 	 * For reads any returned data is zero-extended if necessary, so
11890f50fb46SMatthew Dillon 	 * the server can short-cut any all-zeros reads if it desires.
11900f50fb46SMatthew Dillon 	 */
11910f50fb46SMatthew Dillon 	switch(bp->b_cmd) {
11920f50fb46SMatthew Dillon 	case BUF_CMD_READ:
11930f50fb46SMatthew Dillon 		if (msg->aux_data && msg->aux_size) {
11940f50fb46SMatthew Dillon 			if (msg->aux_size < bp->b_bcount) {
11950f50fb46SMatthew Dillon 				bcopy(msg->aux_data, bp->b_data, msg->aux_size);
11960f50fb46SMatthew Dillon 				bzero(bp->b_data + msg->aux_size,
11970f50fb46SMatthew Dillon 				      bp->b_bcount - msg->aux_size);
11980f50fb46SMatthew Dillon 			} else {
11990f50fb46SMatthew Dillon 				bcopy(msg->aux_data, bp->b_data, bp->b_bcount);
12000f50fb46SMatthew Dillon 			}
12010f50fb46SMatthew Dillon 		} else {
12020f50fb46SMatthew Dillon 			bzero(bp->b_data, bp->b_bcount);
12030f50fb46SMatthew Dillon 		}
12040f50fb46SMatthew Dillon 		/* fall through */
12050f50fb46SMatthew Dillon 	case BUF_CMD_WRITE:
12060f50fb46SMatthew Dillon 	case BUF_CMD_FLUSH:
12070f50fb46SMatthew Dillon 	case BUF_CMD_FREEBLKS:
12080f50fb46SMatthew Dillon 	default:
12090f50fb46SMatthew Dillon 		if (tag->status.resid > bp->b_bcount)
12100f50fb46SMatthew Dillon 			tag->status.resid = bp->b_bcount;
12110f50fb46SMatthew Dillon 		bp->b_resid = tag->status.resid;
1212323c0947SMatthew Dillon 		if (tag->status.head.error != 0) {
1213323c0947SMatthew Dillon 			bp->b_error = EIO;
12140f50fb46SMatthew Dillon 			bp->b_flags |= B_ERROR;
12150f50fb46SMatthew Dillon 		} else {
12160f50fb46SMatthew Dillon 			bp->b_resid = 0;
12170f50fb46SMatthew Dillon 		}
1218bab1d4ffSMatthew Dillon 		devstat_end_transaction_buf(&sc->stats, bp);
1219bab1d4ffSMatthew Dillon 		atomic_add_int(&xa_active, -1);
12200f50fb46SMatthew Dillon 		biodone(bio);
12210f50fb46SMatthew Dillon 		tag->bio = NULL;
12220f50fb46SMatthew Dillon 		break;
12230f50fb46SMatthew Dillon 	}
12240f50fb46SMatthew Dillon 
12250f50fb46SMatthew Dillon 	/*
12260f50fb46SMatthew Dillon 	 * Handle completion of the transaction.  If the bioq is not empty
12270f50fb46SMatthew Dillon 	 * we can initiate another bio on the same tag.
12288d6d37b8SMatthew Dillon 	 *
12298d6d37b8SMatthew Dillon 	 * NOTE: Most of our transactions will be single-message
12308d6d37b8SMatthew Dillon 	 *	 CREATE+DELETEs, so we won't have to terminate the
12318d6d37b8SMatthew Dillon 	 *	 transaction separately, here.  But just in case they
12328d6d37b8SMatthew Dillon 	 *	 aren't be sure to terminate the transaction.
12330f50fb46SMatthew Dillon 	 */
12340f50fb46SMatthew Dillon handle_done:
12358d6d37b8SMatthew Dillon 	if (msg->any.head.cmd & DMSGF_DELETE) {
12360f50fb46SMatthew Dillon 		xa_done(tag, 1);
12375a78b06aSMatthew Dillon 		if ((state->txcmd & DMSGF_DELETE) == 0)
12388d6d37b8SMatthew Dillon 			kdmsg_msg_reply(msg, 0);
12398d6d37b8SMatthew Dillon 	}
12405a78b06aSMatthew Dillon 	return (0);
12415a78b06aSMatthew Dillon 
12425a78b06aSMatthew Dillon 	/*
12435a78b06aSMatthew Dillon 	 * Handle the case where the transaction failed due to a
12445a78b06aSMatthew Dillon 	 * connectivity issue.  The tag is put away with wasbio=0
1245d30cab67SMatthew Dillon 	 * and we put the BIO back onto the bioq for a later restart.
1246a06d536bSMatthew Dillon 	 *
1247a06d536bSMatthew Dillon 	 * probe I/Os (where the device is not open) will be failed
1248a06d536bSMatthew Dillon 	 * instead of requeued.
12495a78b06aSMatthew Dillon 	 */
12505a78b06aSMatthew Dillon handle_repend:
12515a78b06aSMatthew Dillon 	tag->bio = NULL;
1252a06d536bSMatthew Dillon 	if (bio->bio_buf->b_flags & B_FAILONDIS) {
12535ab1caedSMatthew Dillon 		xa_printf(1, "xa_strategy: lost link, fail probe bp %p\n",
1254a06d536bSMatthew Dillon 			  bio->bio_buf);
1255a06d536bSMatthew Dillon 		bio->bio_buf->b_error = ENXIO;
1256a06d536bSMatthew Dillon 		bio->bio_buf->b_flags |= B_ERROR;
1257a06d536bSMatthew Dillon 		biodone(bio);
1258a06d536bSMatthew Dillon 		bio = NULL;
1259a06d536bSMatthew Dillon 	} else {
12605ab1caedSMatthew Dillon 		xa_printf(1, "xa_strategy: lost link, requeue bp %p\n",
12615ab1caedSMatthew Dillon 			  bio->bio_buf);
1262a06d536bSMatthew Dillon 	}
12635a78b06aSMatthew Dillon 	xa_done(tag, 0);
12645a78b06aSMatthew Dillon 	if ((state->txcmd & DMSGF_DELETE) == 0)
12655a78b06aSMatthew Dillon 		kdmsg_msg_reply(msg, 0);
12665a78b06aSMatthew Dillon 
12675a78b06aSMatthew Dillon 	/*
1268d30cab67SMatthew Dillon 	 * Requeue the bio
12695a78b06aSMatthew Dillon 	 */
1270a06d536bSMatthew Dillon 	if (bio) {
1271a06d536bSMatthew Dillon 		lockmgr(&sc->lk, LK_EXCLUSIVE);
1272d30cab67SMatthew Dillon 		TAILQ_INSERT_TAIL(&sc->bioq, bio, bio_act);
1273a06d536bSMatthew Dillon 		lockmgr(&sc->lk, LK_RELEASE);
1274a06d536bSMatthew Dillon 	}
12750f50fb46SMatthew Dillon 	return (0);
12760f50fb46SMatthew Dillon }
12770c98b966SMatthew Dillon 
12780c98b966SMatthew Dillon /*
1279d30cab67SMatthew Dillon  * Restart as much deferred I/O as we can.  The serializer is set and we
1280d30cab67SMatthew Dillon  * eat it (clear it) when done.
12810c98b966SMatthew Dillon  *
1282a06d536bSMatthew Dillon  * Called with sc->lk held
12830c98b966SMatthew Dillon  */
12840c98b966SMatthew Dillon static
12850c98b966SMatthew Dillon void
xa_restart_deferred(xa_softc_t * sc)1286d30cab67SMatthew Dillon xa_restart_deferred(xa_softc_t *sc)
12870c98b966SMatthew Dillon {
1288d30cab67SMatthew Dillon 	kdmsg_state_t *span;
1289d30cab67SMatthew Dillon 	kdmsg_msg_t *msg;
12900c98b966SMatthew Dillon 	xa_tag_t *tag;
1291d30cab67SMatthew Dillon 	int error;
12920c98b966SMatthew Dillon 
1293d30cab67SMatthew Dillon 	KKASSERT(sc->serializing);
1294d30cab67SMatthew Dillon 
1295d30cab67SMatthew Dillon 	/*
1296d30cab67SMatthew Dillon 	 * Determine if a restart is needed.
1297d30cab67SMatthew Dillon 	 */
1298d30cab67SMatthew Dillon 	if (sc->opencnt == 0) {
1299d30cab67SMatthew Dillon 		/*
1300d30cab67SMatthew Dillon 		 * Device is not open, nothing to do, eat serializing.
1301d30cab67SMatthew Dillon 		 */
1302d30cab67SMatthew Dillon 		sc->serializing = 0;
1303d30cab67SMatthew Dillon 		wakeup(sc);
1304d30cab67SMatthew Dillon 	} else if (sc->open_tag == NULL) {
1305d30cab67SMatthew Dillon 		/*
1306d30cab67SMatthew Dillon 		 * BLK_OPEN required before we can restart any BIOs.
1307d30cab67SMatthew Dillon 		 * Select the best LNK_SPAN to issue the BLK_OPEN under.
1308d30cab67SMatthew Dillon 		 *
1309d30cab67SMatthew Dillon 		 * serializing interlocks waiting open()s.
1310d30cab67SMatthew Dillon 		 */
1311d30cab67SMatthew Dillon 		error = 0;
1312d30cab67SMatthew Dillon 		TAILQ_FOREACH(span, &sc->spanq, user_entry) {
1313d30cab67SMatthew Dillon 			if ((span->rxcmd & DMSGF_DELETE) == 0)
13140c98b966SMatthew Dillon 				break;
1315d30cab67SMatthew Dillon 		}
1316d30cab67SMatthew Dillon 		if (span == NULL)
1317d30cab67SMatthew Dillon 			error = ENXIO;
1318d30cab67SMatthew Dillon 
1319d30cab67SMatthew Dillon 		if (error == 0) {
1320d30cab67SMatthew Dillon 			tag = xa_setup_cmd(sc, NULL);
1321d30cab67SMatthew Dillon 			if (tag == NULL)
1322d30cab67SMatthew Dillon 				error = ENXIO;
1323d30cab67SMatthew Dillon 		}
1324d30cab67SMatthew Dillon 		if (error == 0) {
1325d30cab67SMatthew Dillon 			sc->open_tag = tag;
1326d30cab67SMatthew Dillon 			msg = kdmsg_msg_alloc(span,
1327d30cab67SMatthew Dillon 					      DMSG_BLK_OPEN |
1328d30cab67SMatthew Dillon 					      DMSGF_CREATE,
1329d30cab67SMatthew Dillon 					      xa_sync_completion, tag);
1330d30cab67SMatthew Dillon 			msg->any.blk_open.modes = DMSG_BLKOPEN_RD;
13315ab1caedSMatthew Dillon 			xa_printf(1,
13325ab1caedSMatthew Dillon 				  "BLK_OPEN tag %p state %p "
13337924b8f1SMatthew Dillon 				  "span-state %p\n",
1334a06d536bSMatthew Dillon 				  tag, msg->state, span);
1335d30cab67SMatthew Dillon 			xa_start(tag, msg, 0);
1336d30cab67SMatthew Dillon 		}
1337d30cab67SMatthew Dillon 		if (error) {
1338d30cab67SMatthew Dillon 			sc->serializing = 0;
1339d30cab67SMatthew Dillon 			wakeup(sc);
1340d30cab67SMatthew Dillon 		}
1341d30cab67SMatthew Dillon 		/* else leave serializing set until BLK_OPEN response */
1342d30cab67SMatthew Dillon 	} else {
1343d30cab67SMatthew Dillon 		/* nothing to do */
1344d30cab67SMatthew Dillon 		sc->serializing = 0;
1345d30cab67SMatthew Dillon 		wakeup(sc);
13460c98b966SMatthew Dillon 	}
13470c98b966SMatthew Dillon }
1348