2 * Copyright (c) 2012 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@dragonflybsd.org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * This module allows disk devices to be created and associated with a
36 * communications pipe or socket. You open the device and issue an
37 * ioctl() to install a new disk along with its communications descriptor.
39 * All further communication occurs via the descriptor using the DMSG
40 * LNK_CONN, LNK_SPAN, and BLOCK protocols. The descriptor can be a
41 * direct connection to a remote machine's disk (in-kernenl), to a remote
42 * cluster controller, to the local cluster controller, etc.
44 * /dev/xdisk is the control device, issue ioctl()s to create the /dev/xa%d
45 * devices. These devices look like raw disks to the system.
47 #include <sys/param.h>
48 #include <sys/systm.h>
51 #include <sys/device.h>
52 #include <sys/devicestat.h>
54 #include <sys/kernel.h>
55 #include <sys/malloc.h>
56 #include <sys/sysctl.h>
58 #include <sys/queue.h>
61 #include <sys/kern_syscall.h>
64 #include <sys/xdiskioctl.h>
67 #include <sys/thread2.h>
72 TAILQ_ENTRY(xa_tag) entry;
74 dmsg_blk_error_t status;
78 int running; /* transaction running */
79 int waitseq; /* streaming reply */
80 int done; /* final (transaction closed) */
83 typedef struct xa_tag xa_tag_t;
86 TAILQ_ENTRY(xa_softc) entry;
89 struct xdisk_attach_ioctl xaioc;
90 struct disk_info info;
99 TAILQ_HEAD(, bio) bioq;
100 TAILQ_HEAD(, xa_tag) tag_freeq;
101 TAILQ_HEAD(, xa_tag) tag_pendq;
102 TAILQ_HEAD(, kdmsg_circuit) circq;
103 struct lwkt_token tok;
106 typedef struct xa_softc xa_softc_t;
108 #define MAXTAGS 64 /* no real limit */
110 static int xdisk_attach(struct xdisk_attach_ioctl *xaioc);
111 static int xdisk_detach(struct xdisk_attach_ioctl *xaioc);
112 static void xa_exit(kdmsg_iocom_t *iocom);
113 static void xa_terminate_check(struct xa_softc *xa);
114 static int xa_rcvdmsg(kdmsg_msg_t *msg);
115 static void xa_autodmsg(kdmsg_msg_t *msg);
117 static xa_tag_t *xa_setup_cmd(xa_softc_t *xa, struct bio *bio);
118 static void xa_start(xa_tag_t *tag, kdmsg_msg_t *msg);
119 static uint32_t xa_wait(xa_tag_t *tag, int seq);
120 static void xa_done(xa_tag_t *tag, int wasbio);
121 static int xa_sync_completion(kdmsg_state_t *state, kdmsg_msg_t *msg);
122 static int xa_bio_completion(kdmsg_state_t *state, kdmsg_msg_t *msg);
124 MALLOC_DEFINE(M_XDISK, "Networked disk client", "Network Disks");
127 * Control device, issue ioctls to create xa devices.
129 static d_open_t xdisk_open;
130 static d_close_t xdisk_close;
131 static d_ioctl_t xdisk_ioctl;
133 static struct dev_ops xdisk_ops = {
134 { "xdisk", 0, D_MPSAFE | D_TRACKCLOSE },
135 .d_open = xdisk_open,
136 .d_close = xdisk_close,
137 .d_ioctl = xdisk_ioctl
143 static d_open_t xa_open;
144 static d_close_t xa_close;
145 static d_ioctl_t xa_ioctl;
146 static d_strategy_t xa_strategy;
147 static d_psize_t xa_size;
149 static struct dev_ops xa_ops = {
150 { "xa", 0, D_DISK | D_CANFREE | D_MPSAFE | D_TRACKCLOSE },
155 .d_write = physwrite,
156 .d_strategy = xa_strategy,
160 static struct lwkt_token xdisk_token = LWKT_TOKEN_INITIALIZER(xdisk_token);
161 static int xdisk_opencount;
162 static cdev_t xdisk_dev;
163 static TAILQ_HEAD(, xa_softc) xa_queue;
166 * Module initialization
169 xdisk_modevent(module_t mod, int type, void *data)
173 TAILQ_INIT(&xa_queue);
174 xdisk_dev = make_dev(&xdisk_ops, 0,
175 UID_ROOT, GID_WHEEL, 0600, "xdisk");
179 if (xdisk_opencount || TAILQ_FIRST(&xa_queue))
182 destroy_dev(xdisk_dev);
185 dev_ops_remove_all(&xdisk_ops);
186 dev_ops_remove_all(&xa_ops);
194 DEV_MODULE(xdisk, xdisk_modevent, 0);
200 xdisk_open(struct dev_open_args *ap)
202 kprintf("XDISK_OPEN\n");
203 lwkt_gettoken(&xdisk_token);
205 lwkt_reltoken(&xdisk_token);
210 xdisk_close(struct dev_close_args *ap)
212 kprintf("XDISK_CLOSE\n");
213 lwkt_gettoken(&xdisk_token);
215 lwkt_reltoken(&xdisk_token);
220 xdisk_ioctl(struct dev_ioctl_args *ap)
226 error = xdisk_attach((void *)ap->a_data);
229 error = xdisk_detach((void *)ap->a_data);
238 /************************************************************************
240 ************************************************************************/
243 xdisk_attach(struct xdisk_attach_ioctl *xaioc)
253 kprintf("xdisk attach %d %jd/%d %s %s\n",
254 xaioc->fd, (intmax_t)xaioc->bytes, xaioc->blksize,
255 xaioc->cl_label, xaioc->fs_label);
258 * Normalize ioctl params
260 fp = holdfp(curproc->p_fd, xaioc->fd, -1);
263 if (xaioc->cl_label[sizeof(xaioc->cl_label) - 1] != 0)
265 if (xaioc->fs_label[sizeof(xaioc->fs_label) - 1] != 0)
267 if (xaioc->blksize < DEV_BSIZE || xaioc->blksize > MAXBSIZE)
271 * See if the serial number is already present. If we are
272 * racing a termination the disk subsystem may still have
273 * duplicate entries not yet removed so we wait a bit and
276 lwkt_gettoken(&xdisk_token);
278 TAILQ_FOREACH(xa, &xa_queue, entry) {
279 if (strcmp(xa->iocom.auto_lnk_conn.fs_label,
280 xaioc->fs_label) == 0) {
281 if (xa->serializing) {
282 tsleep(xa, 0, "xadelay", hz / 10);
286 kdmsg_iocom_uninit(&xa->iocom);
292 * Create a new xa if not already present
297 TAILQ_FOREACH(xa, &xa_queue, entry) {
298 if (xa->unit == unit)
305 xa = kmalloc(sizeof(*xa), M_XDISK, M_WAITOK|M_ZERO);
306 kprintf("ALLOCATE XA %p\n", xa);
309 lwkt_token_init(&xa->tok, "xa");
310 TAILQ_INIT(&xa->circq);
311 TAILQ_INIT(&xa->bioq);
312 TAILQ_INIT(&xa->tag_freeq);
313 TAILQ_INIT(&xa->tag_pendq);
314 for (n = 0; n < MAXTAGS; ++n) {
315 tag = kmalloc(sizeof(*tag), M_XDISK, M_WAITOK|M_ZERO);
317 TAILQ_INSERT_TAIL(&xa->tag_freeq, tag, entry);
319 TAILQ_INSERT_TAIL(&xa_queue, xa, entry);
323 lwkt_reltoken(&xdisk_token);
328 if (xa->dev == NULL) {
329 dev = disk_create(unit, &xa->disk, &xa_ops);
334 xa->info.d_media_blksize = xaioc->blksize;
335 xa->info.d_media_blocks = xaioc->bytes / xaioc->blksize;
336 xa->info.d_dsflags = DSO_MBRQUIET | DSO_RAWPSIZE;
337 xa->info.d_secpertrack = 32;
338 xa->info.d_nheads = 64;
339 xa->info.d_secpercyl = xa->info.d_secpertrack * xa->info.d_nheads;
340 xa->info.d_ncylinders = 0;
341 if (xa->xaioc.fs_label[0])
342 xa->info.d_serialno = xa->xaioc.fs_label;
345 * Set up messaging connection
347 ksnprintf(devname, sizeof(devname), "xa%d", unit);
348 kdmsg_iocom_init(&xa->iocom, xa,
349 KDMSG_IOCOMF_AUTOCONN |
350 KDMSG_IOCOMF_AUTOSPAN |
351 KDMSG_IOCOMF_AUTOCIRC |
352 KDMSG_IOCOMF_AUTOFORGE,
353 M_XDISK, xa_rcvdmsg);
354 xa->iocom.exit_func = xa_exit;
356 kdmsg_iocom_reconnect(&xa->iocom, fp, devname);
359 * Setup our LNK_CONN advertisement for autoinitiate.
361 * Our filter is setup to only accept PEER_BLOCK/SERVER
364 xa->iocom.auto_lnk_conn.pfs_type = DMSG_PFSTYPE_CLIENT;
365 xa->iocom.auto_lnk_conn.proto_version = DMSG_SPAN_PROTO_1;
366 xa->iocom.auto_lnk_conn.peer_type = DMSG_PEER_BLOCK;
367 xa->iocom.auto_lnk_conn.peer_mask = 1LLU << DMSG_PEER_BLOCK;
368 xa->iocom.auto_lnk_conn.pfs_mask = 1LLU << DMSG_PFSTYPE_SERVER;
369 ksnprintf(xa->iocom.auto_lnk_conn.cl_label,
370 sizeof(xa->iocom.auto_lnk_conn.cl_label),
371 "%s", xaioc->cl_label);
374 * We need a unique pfs_fsid to avoid confusion.
375 * We supply a rendezvous fs_label using the serial number.
377 kern_uuidgen(&xa->pfs_fsid, 1);
378 xa->iocom.auto_lnk_conn.pfs_fsid = xa->pfs_fsid;
379 ksnprintf(xa->iocom.auto_lnk_conn.fs_label,
380 sizeof(xa->iocom.auto_lnk_conn.fs_label),
381 "%s", xaioc->fs_label);
384 * Setup our LNK_SPAN advertisement for autoinitiate
386 xa->iocom.auto_lnk_span.pfs_type = DMSG_PFSTYPE_CLIENT;
387 xa->iocom.auto_lnk_span.proto_version = DMSG_SPAN_PROTO_1;
388 xa->iocom.auto_lnk_span.peer_type = DMSG_PEER_BLOCK;
389 ksnprintf(xa->iocom.auto_lnk_span.cl_label,
390 sizeof(xa->iocom.auto_lnk_span.cl_label),
391 "%s", xa->xaioc.cl_label);
393 kdmsg_iocom_autoinitiate(&xa->iocom, xa_autodmsg);
394 disk_setdiskinfo_sync(&xa->disk, &xa->info);
396 lwkt_gettoken(&xdisk_token);
398 xa_terminate_check(xa);
399 lwkt_reltoken(&xdisk_token);
405 xdisk_detach(struct xdisk_attach_ioctl *xaioc)
409 lwkt_gettoken(&xdisk_token);
411 TAILQ_FOREACH(xa, &xa_queue, entry) {
412 if (strcmp(xa->iocom.auto_lnk_conn.fs_label,
413 xaioc->fs_label) == 0) {
417 if (xa == NULL || xa->serializing == 0) {
421 tsleep(xa, 0, "xadet", hz / 10);
424 kprintf("DETACHING XA\n");
425 kdmsg_iocom_uninit(&xa->iocom);
428 lwkt_reltoken(&xdisk_token);
433 * Called from iocom core transmit thread upon disconnect.
437 xa_exit(kdmsg_iocom_t *iocom)
439 struct xa_softc *xa = iocom->handle;
441 kprintf("XA_EXIT UNIT %d\n", xa->unit);
443 if (xa->serializing == 0)
444 kdmsg_iocom_uninit(iocom);
447 * If the drive is not in use and no longer attach it can be
450 lwkt_gettoken(&xdisk_token);
452 xa_terminate_check(xa);
453 lwkt_reltoken(&xdisk_token);
457 * Determine if we can destroy the xa_softc.
459 * Called with xdisk_token held.
463 xa_terminate_check(struct xa_softc *xa)
467 if (xa->opencnt || xa->attached || xa->serializing)
470 kprintf("TERMINATE XA %p %d\n", xa, xa->unit);
471 kdmsg_iocom_uninit(&xa->iocom);
473 disk_destroy(&xa->disk);
474 xa->dev->si_drv1 = NULL;
477 kprintf("REMOVEQ XA %p %d\n", xa, xa->unit);
478 KKASSERT(xa->opencnt == 0 && xa->attached == 0);
479 kprintf("IOCOMUN XA %p %d\n", xa, xa->unit);
480 while ((tag = TAILQ_FIRST(&xa->tag_freeq)) != NULL) {
481 TAILQ_REMOVE(&xa->tag_freeq, tag, entry);
485 KKASSERT(TAILQ_EMPTY(&xa->tag_pendq));
486 TAILQ_REMOVE(&xa_queue, xa, entry); /* XXX */
488 kprintf("xa_close: destroy unreferenced disk\n");
492 * Shim to catch and record virtual circuit events.
495 xa_autodmsg(kdmsg_msg_t *msg)
497 struct xa_softc *xa = msg->iocom->handle;
498 kdmsg_circuit_t *circ;
499 kdmsg_circuit_t *cscan;
503 * Because this is just a shim we don't have a state callback for
504 * the transactions we are sniffing, so make things easier by
505 * calculating the original command along with the current message's
506 * flags. This is because transactions are made up of numerous
507 * messages and only the first typically specifies the actual command.
510 xcmd = msg->state->icmd |
511 (msg->any.head.cmd & (DMSGF_CREATE |
515 xcmd = msg->any.head.cmd;
519 * Add or remove a circuit, sorted by weight (lower numbers are
523 case DMSG_LNK_CIRC | DMSGF_CREATE | DMSGF_REPLY:
524 kprintf("XA: Received autodmsg: CREATE+REPLY\n");
525 circ = msg->state->any.circ;
526 lwkt_gettoken(&xa->tok);
527 if (circ->recorded == 0) {
528 TAILQ_FOREACH(cscan, &xa->circq, entry) {
529 if (circ->weight < cscan->weight)
533 TAILQ_INSERT_BEFORE(cscan, circ, entry);
535 TAILQ_INSERT_TAIL(&xa->circq, circ, entry);
538 lwkt_reltoken(&xa->tok);
540 case DMSG_LNK_CIRC | DMSGF_DELETE | DMSGF_REPLY:
541 kprintf("XA: Received autodmsg: DELETE+REPLY\n");
542 circ = msg->state->any.circ;
543 lwkt_gettoken(&xa->tok);
544 if (circ->recorded) {
545 TAILQ_REMOVE(&xa->circq, circ, entry);
548 lwkt_reltoken(&xa->tok);
556 xa_rcvdmsg(kdmsg_msg_t *msg)
558 switch(msg->any.head.cmd & DMSGF_TRANSMASK) {
561 * Execute shell command (not supported atm).
563 * This is a one-way packet but if not (e.g. if part of
564 * a streaming transaction), we will have already closed
567 kdmsg_msg_reply(msg, DMSG_ERR_NOSUPP);
569 case DMSG_DBG_SHELL | DMSGF_REPLY:
571 * Receive one or more replies to a shell command that we
574 * This is a one-way packet but if not (e.g. if part of
575 * a streaming transaction), we will have already closed
579 msg->aux_data[msg->aux_size - 1] = 0;
580 kprintf("DEBUGMSG: %s\n", msg->aux_data);
585 * Unsupported LNK message received. We only need to
586 * reply if it's a transaction in order to close our end.
587 * Ignore any one-way messages are any further messages
588 * associated with the transaction.
590 * NOTE: This case also includes DMSG_LNK_ERROR messages
591 * which might be one-way, replying to those would
592 * cause an infinite ping-pong.
594 if (msg->any.head.cmd & DMSGF_CREATE)
595 kdmsg_msg_reply(msg, DMSG_ERR_NOSUPP);
602 /************************************************************************
603 * XA DEVICE INTERFACE *
604 ************************************************************************/
607 xa_open(struct dev_open_args *ap)
609 cdev_t dev = ap->a_head.a_dev;
615 dev->si_bsize_phys = 512;
616 dev->si_bsize_best = 32768;
619 * Interlock open with opencnt, wait for attachment operations
622 lwkt_gettoken(&xdisk_token);
626 lwkt_reltoken(&xdisk_token);
627 return ENXIO; /* raced destruction */
629 if (xa->serializing) {
630 tsleep(xa, 0, "xarace", hz / 10);
635 * Serialize initial open
637 if (xa->opencnt++ > 0) {
638 lwkt_reltoken(&xdisk_token);
642 lwkt_reltoken(&xdisk_token);
644 kprintf("XA OPEN COMMAND\n");
646 tag = xa_setup_cmd(xa, NULL);
648 lwkt_gettoken(&xdisk_token);
649 KKASSERT(xa->opencnt > 0);
652 xa_terminate_check(xa);
653 lwkt_reltoken(&xdisk_token);
656 msg = kdmsg_msg_alloc(&xa->iocom, tag->circuit,
657 DMSG_BLK_OPEN | DMSGF_CREATE,
658 xa_sync_completion, tag);
659 msg->any.blk_open.modes = DMSG_BLKOPEN_RD | DMSG_BLKOPEN_WR;
661 if (xa_wait(tag, 0) == 0) {
662 kprintf("XA OPEN GOOD\n");
663 xa->keyid = tag->status.keyid;
664 xa->opentag = tag; /* leave tag open */
668 kprintf("XA OPEN BAD\n");
670 lwkt_gettoken(&xdisk_token);
671 KKASSERT(xa->opencnt > 0);
674 xa_terminate_check(xa);
675 lwkt_reltoken(&xdisk_token);
682 xa_close(struct dev_close_args *ap)
684 cdev_t dev = ap->a_head.a_dev;
690 return ENXIO; /* raced destruction */
692 lwkt_gettoken(&xa->tok);
693 if ((tag = xa->opentag) != NULL) {
695 kdmsg_state_reply(tag->state, DMSG_ERR_NOSUPP);
696 while (tag->done == 0)
697 xa_wait(tag, tag->waitseq);
700 lwkt_reltoken(&xa->tok);
702 lwkt_gettoken(&xdisk_token);
703 KKASSERT(xa->opencnt > 0);
705 xa_terminate_check(xa);
706 lwkt_reltoken(&xdisk_token);
712 xa_strategy(struct dev_strategy_args *ap)
714 xa_softc_t *xa = ap->a_head.a_dev->si_drv1;
716 struct bio *bio = ap->a_bio;
718 bio->bio_buf->b_error = ENXIO;
719 bio->bio_buf->b_flags |= B_ERROR;
723 tag = xa_setup_cmd(xa, bio);
730 xa_ioctl(struct dev_ioctl_args *ap)
736 xa_size(struct dev_psize_args *ap)
740 if ((xa = ap->a_head.a_dev->si_drv1) == NULL)
742 ap->a_result = xa->info.d_media_blocks;
746 /************************************************************************
747 * XA BLOCK PROTOCOL STATE MACHINE *
748 ************************************************************************
750 * Implement tag/msg setup and related functions.
753 xa_setup_cmd(xa_softc_t *xa, struct bio *bio)
755 kdmsg_circuit_t *circ;
759 * Only get a tag if we have a valid virtual circuit to the server.
761 lwkt_gettoken(&xa->tok);
762 if ((circ = TAILQ_FIRST(&xa->circq)) == NULL) {
764 } else if ((tag = TAILQ_FIRST(&xa->tag_freeq)) != NULL) {
765 TAILQ_REMOVE(&xa->tag_freeq, tag, entry);
766 TAILQ_INSERT_TAIL(&xa->tag_pendq, tag, entry);
768 tag->circuit = circ->circ_state->msgid;
772 * If we can't dispatch now and this is a bio, queue it for later.
774 if (tag == NULL && bio) {
775 TAILQ_INSERT_TAIL(&xa->bioq, bio, bio_act);
777 lwkt_reltoken(&xa->tok);
783 xa_start(xa_tag_t *tag, kdmsg_msg_t *msg)
785 xa_softc_t *xa = tag->xa;
797 msg = kdmsg_msg_alloc(&xa->iocom, tag->circuit,
799 DMSGF_CREATE | DMSGF_DELETE,
800 xa_bio_completion, tag);
801 msg->any.blk_read.keyid = xa->keyid;
802 msg->any.blk_read.offset = bio->bio_offset;
803 msg->any.blk_read.bytes = bp->b_bcount;
806 msg = kdmsg_msg_alloc(&xa->iocom, tag->circuit,
808 DMSGF_CREATE | DMSGF_DELETE,
809 xa_bio_completion, tag);
810 msg->any.blk_write.keyid = xa->keyid;
811 msg->any.blk_write.offset = bio->bio_offset;
812 msg->any.blk_write.bytes = bp->b_bcount;
813 msg->aux_data = bp->b_data;
814 msg->aux_size = bp->b_bcount;
817 msg = kdmsg_msg_alloc(&xa->iocom, tag->circuit,
819 DMSGF_CREATE | DMSGF_DELETE,
820 xa_bio_completion, tag);
821 msg->any.blk_flush.keyid = xa->keyid;
822 msg->any.blk_flush.offset = bio->bio_offset;
823 msg->any.blk_flush.bytes = bp->b_bcount;
825 case BUF_CMD_FREEBLKS:
826 msg = kdmsg_msg_alloc(&xa->iocom, tag->circuit,
828 DMSGF_CREATE | DMSGF_DELETE,
829 xa_bio_completion, tag);
830 msg->any.blk_freeblks.keyid = xa->keyid;
831 msg->any.blk_freeblks.offset = bio->bio_offset;
832 msg->any.blk_freeblks.bytes = bp->b_bcount;
835 bp->b_flags |= B_ERROR;
846 tag->state = msg->state;
847 kdmsg_msg_write(msg);
854 xa_wait(xa_tag_t *tag, int seq)
856 xa_softc_t *xa = tag->xa;
858 lwkt_gettoken(&xa->tok);
859 while (tag->waitseq == seq)
860 tsleep(tag, 0, "xawait", 0);
861 lwkt_reltoken(&xa->tok);
862 return (tag->status.head.error);
866 xa_done(xa_tag_t *tag, int wasbio)
868 xa_softc_t *xa = tag->xa;
871 KKASSERT(tag->msg == NULL);
872 KKASSERT(tag->bio == NULL);
875 lwkt_gettoken(&xa->tok);
876 if ((bio = TAILQ_FIRST(&xa->bioq)) != NULL) {
877 TAILQ_REMOVE(&xa->bioq, bio, bio_act);
879 lwkt_reltoken(&xa->tok);
882 TAILQ_INSERT_TAIL(&xa->tag_freeq, tag, entry);
883 lwkt_reltoken(&xa->tok);
888 xa_sync_completion(kdmsg_state_t *state, kdmsg_msg_t *msg)
890 xa_tag_t *tag = state->any.any;
891 xa_softc_t *xa = tag->xa;
893 switch(msg->any.head.cmd & DMSGF_CMDSWMASK) {
894 case DMSG_LNK_ERROR | DMSGF_REPLY:
895 bzero(&tag->status, sizeof(tag->status));
896 tag->status.head = msg->any.head;
898 case DMSG_BLK_ERROR | DMSGF_REPLY:
899 tag->status = msg->any.blk_error;
902 kprintf("XA_SYNC_COMPLETION ERROR %u RESID %u\n",
903 tag->status.head.error, tag->status.resid);
904 if (msg->any.head.cmd & DMSGF_DELETE) { /* receive termination */
905 kdmsg_msg_reply(msg, 0); /* terminate our side */
908 lwkt_gettoken(&xa->tok);
910 lwkt_reltoken(&xa->tok);
918 xa_bio_completion(kdmsg_state_t *state, kdmsg_msg_t *msg)
920 xa_tag_t *tag = state->any.any;
921 /*xa_softc_t *xa = tag->xa;*/
926 * Get the bio from the tag. If no bio is present we just do
929 if ((bio = tag->bio) == NULL)
934 * Process return status
936 switch(msg->any.head.cmd & DMSGF_CMDSWMASK) {
937 case DMSG_LNK_ERROR | DMSGF_REPLY:
938 bzero(&tag->status, sizeof(tag->status));
939 tag->status.head = msg->any.head;
940 if (tag->status.head.error)
941 tag->status.resid = bp->b_bcount;
943 tag->status.resid = 0;
945 case DMSG_BLK_ERROR | DMSGF_REPLY:
946 tag->status = msg->any.blk_error;
949 kprintf("XA_BIO_COMPLETION ERROR %u RESID %u\n",
950 tag->status.head.error, tag->status.resid);
953 * Process bio completion
955 * For reads any returned data is zero-extended if necessary, so
956 * the server can short-cut any all-zeros reads if it desires.
960 if (msg->aux_data && msg->aux_size) {
961 if (msg->aux_size < bp->b_bcount) {
962 bcopy(msg->aux_data, bp->b_data, msg->aux_size);
963 bzero(bp->b_data + msg->aux_size,
964 bp->b_bcount - msg->aux_size);
966 bcopy(msg->aux_data, bp->b_data, bp->b_bcount);
969 bzero(bp->b_data, bp->b_bcount);
974 case BUF_CMD_FREEBLKS:
976 if (tag->status.resid > bp->b_bcount)
977 tag->status.resid = bp->b_bcount;
978 bp->b_resid = tag->status.resid;
979 if ((bp->b_error = tag->status.head.error) != 0) {
980 bp->b_flags |= B_ERROR;
990 * Handle completion of the transaction. If the bioq is not empty
991 * we can initiate another bio on the same tag.
994 if (msg->any.head.cmd & DMSGF_DELETE)