1*f603807bSTomohiro Kusumi /*
2*f603807bSTomohiro Kusumi  * Copyright (c) 2010 The DragonFly Project.  All rights reserved.
3*f603807bSTomohiro Kusumi  *
4*f603807bSTomohiro Kusumi  * This code is derived from software contributed to The DragonFly Project
5*f603807bSTomohiro Kusumi  * by Alex Hornung <ahornung@gmail.com>
6*f603807bSTomohiro Kusumi  *
7*f603807bSTomohiro Kusumi  * Redistribution and use in source and binary forms, with or without
8*f603807bSTomohiro Kusumi  * modification, are permitted provided that the following conditions
9*f603807bSTomohiro Kusumi  * are met:
10*f603807bSTomohiro Kusumi  *
11*f603807bSTomohiro Kusumi  * 1. Redistributions of source code must retain the above copyright
12*f603807bSTomohiro Kusumi  *    notice, this list of conditions and the following disclaimer.
13*f603807bSTomohiro Kusumi  * 2. Redistributions in binary form must reproduce the above copyright
14*f603807bSTomohiro Kusumi  *    notice, this list of conditions and the following disclaimer in
15*f603807bSTomohiro Kusumi  *    the documentation and/or other materials provided with the
16*f603807bSTomohiro Kusumi  *    distribution.
17*f603807bSTomohiro Kusumi  * 3. Neither the name of The DragonFly Project nor the names of its
18*f603807bSTomohiro Kusumi  *    contributors may be used to endorse or promote products derived
19*f603807bSTomohiro Kusumi  *    from this software without specific, prior written permission.
20*f603807bSTomohiro Kusumi  *
21*f603807bSTomohiro Kusumi  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22*f603807bSTomohiro Kusumi  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23*f603807bSTomohiro Kusumi  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24*f603807bSTomohiro Kusumi  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25*f603807bSTomohiro Kusumi  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26*f603807bSTomohiro Kusumi  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27*f603807bSTomohiro Kusumi  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28*f603807bSTomohiro Kusumi  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29*f603807bSTomohiro Kusumi  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30*f603807bSTomohiro Kusumi  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31*f603807bSTomohiro Kusumi  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32*f603807bSTomohiro Kusumi  * SUCH DAMAGE.
33*f603807bSTomohiro Kusumi  */
34*f603807bSTomohiro Kusumi 
35*f603807bSTomohiro Kusumi /*
36*f603807bSTomohiro Kusumi  * This file implements initial version of a mirror target
37*f603807bSTomohiro Kusumi  */
38*f603807bSTomohiro Kusumi #include <sys/bio.h>
39*f603807bSTomohiro Kusumi #include <sys/malloc.h>
40*f603807bSTomohiro Kusumi #include <sys/uuid.h>
41*f603807bSTomohiro Kusumi 
42*f603807bSTomohiro Kusumi #include <dev/disk/dm/dm.h>
43*f603807bSTomohiro Kusumi MALLOC_DEFINE(M_DMDMIRROR, "dm_dmirror", "Device Mapper Target DMIRROR");
44*f603807bSTomohiro Kusumi 
45*f603807bSTomohiro Kusumi /* segdesc flags */
46*f603807bSTomohiro Kusumi #define MEDIA_UNSTABLE		0x0001
47*f603807bSTomohiro Kusumi #define	MEDIA_READ_DEGRADED	0x0002
48*f603807bSTomohiro Kusumi #define MEDIA_WRITE_DEGRADED	0x0004
49*f603807bSTomohiro Kusumi #define MEDIA_MASTER		0x0008
50*f603807bSTomohiro Kusumi #define UNINITIALIZED		0x0010
51*f603807bSTomohiro Kusumi #define OLD_UNSTABLE		0x0020
52*f603807bSTomohiro Kusumi #define OLD_MSATER		0x0040
53*f603807bSTomohiro Kusumi 
54*f603807bSTomohiro Kusumi /* dmirror disk flags */
55*f603807bSTomohiro Kusumi #define DISK_ONLINE		0x0001
56*f603807bSTomohiro Kusumi 
57*f603807bSTomohiro Kusumi 
58*f603807bSTomohiro Kusumi #define	dmirror_set_bio_disk(bio, x)	((bio)->bio_caller_info1.ptr = (x))
59*f603807bSTomohiro Kusumi #define	dmirror_get_bio_disk(bio)	((bio)?((bio)->bio_caller_info1.ptr):NULL)
60*f603807bSTomohiro Kusumi #define	dmirror_set_bio_seg(bio, x)	((bio)->bio_caller_info2.offset = (x))
61*f603807bSTomohiro Kusumi #define	dmirror_get_bio_segno(bio)	((bio)?((bio)->bio_caller_info2.offset):0)
62*f603807bSTomohiro Kusumi 
63*f603807bSTomohiro Kusumi #define	dmirror_set_bio_retries(bio, x)	((bio)->bio_caller_info3.value = (x))
64*f603807bSTomohiro Kusumi #define	dmirror_get_bio_retries(bio)	((bio)?((bio)->bio_caller_info3.value):0)
65*f603807bSTomohiro Kusumi 
66*f603807bSTomohiro Kusumi #define dmirror_set_bio_mbuf(bio, x)	((bio)->bio_caller_info3.ptr = (x))
67*f603807bSTomohiro Kusumi #define dmirror_get_bio_mbuf(bio)	((bio)?((bio)->bio_caller_info3.ptr):NULL)
68*f603807bSTomohiro Kusumi 
69*f603807bSTomohiro Kusumi 
70*f603807bSTomohiro Kusumi 
71*f603807bSTomohiro Kusumi /* Segment descriptor for each logical segment */
72*f603807bSTomohiro Kusumi typedef struct segdesc {
73*f603807bSTomohiro Kusumi 	uint32_t	flags;		/* Flags, including state */
74*f603807bSTomohiro Kusumi 	uint32_t	zf_bitmap;	/* Zero-fill bitmap */
75*f603807bSTomohiro Kusumi 	uint8_t		disk_no;
76*f603807bSTomohiro Kusumi 	uint8_t		spare1;
77*f603807bSTomohiro Kusumi 	uint16_t	spare2;
78*f603807bSTomohiro Kusumi 	uint32_t	spare3;
79*f603807bSTomohiro Kusumi 	/* XXX: some timestamp/serial */
80*f603807bSTomohiro Kusumi } segdesc_t;
81*f603807bSTomohiro Kusumi 
82*f603807bSTomohiro Kusumi typedef struct dmirror_disk {
83*f603807bSTomohiro Kusumi 	uint32_t	flags;
84*f603807bSTomohiro Kusumi 	dm_pdev_t 	*pdev;
85*f603807bSTomohiro Kusumi } dmirror_disk_t;
86*f603807bSTomohiro Kusumi 
87*f603807bSTomohiro Kusumi typedef struct target_dmirror_config {
88*f603807bSTomohiro Kusumi 	size_t	params_len;
89*f603807bSTomohiro Kusumi 	dmirror_disk_t	disks[4];
90*f603807bSTomohiro Kusumi 	uint8_t	ndisks;
91*f603807bSTomohiro Kusumi 	/* XXX: uuid stuff */
92*f603807bSTomohiro Kusumi 
93*f603807bSTomohiro Kusumi } dm_target_dmirror_config_t;
94*f603807bSTomohiro Kusumi 
95*f603807bSTomohiro Kusumi static
96*f603807bSTomohiro Kusumi struct bio*
dmirror_clone_bio(struct bio * obio)97*f603807bSTomohiro Kusumi dmirror_clone_bio(struct bio *obio)
98*f603807bSTomohiro Kusumi {
99*f603807bSTomohiro Kusumi 	struct bio *bio;
100*f603807bSTomohiro Kusumi 	struct buf *mbp;
101*f603807bSTomohiro Kusumi 	struct buf *bp;
102*f603807bSTomohiro Kusumi 
103*f603807bSTomohiro Kusumi 	mbp = obio->bio_buf;
104*f603807bSTomohiro Kusumi 	bp = getpbuf(NULL);
105*f603807bSTomohiro Kusumi 
106*f603807bSTomohiro Kusumi 	BUF_KERNPROC(bp);
107*f603807bSTomohiro Kusumi 	bp->b_vp = mbp->b_vp;
108*f603807bSTomohiro Kusumi 	bp->b_cmd = mbp->b_cmd;
109*f603807bSTomohiro Kusumi 	bp->b_data = (char *)mbp->b_data;
110*f603807bSTomohiro Kusumi 	bp->b_resid = bp->b_bcount = mbp->b_bcount;
111*f603807bSTomohiro Kusumi 	bp->b_bufsize = bp->b_bcount;
112*f603807bSTomohiro Kusumi 
113*f603807bSTomohiro Kusumi 	bio = &bp->b_bio1;
114*f603807bSTomohiro Kusumi 	bio->bio_offset = obio->bio_offset;
115*f603807bSTomohiro Kusumi 
116*f603807bSTomohiro Kusumi 	return (bio);
117*f603807bSTomohiro Kusumi }
118*f603807bSTomohiro Kusumi 
119*f603807bSTomohiro Kusumi static void
dmirror_write_done(struct bio * bio)120*f603807bSTomohiro Kusumi dmirror_write_done(struct bio *bio)
121*f603807bSTomohiro Kusumi {
122*f603807bSTomohiro Kusumi 	dmirror_disk_t disk;
123*f603807bSTomohiro Kusumi 	off_t segno;
124*f603807bSTomohiro Kusumi 	struct bio *obio, *mbio;
125*f603807bSTomohiro Kusumi 	int retries;
126*f603807bSTomohiro Kusumi 
127*f603807bSTomohiro Kusumi 	disk = dmirror_get_bio_disk(bio);
128*f603807bSTomohiro Kusumi 	segno = dmirror_get_bio_segno(bio);
129*f603807bSTomohiro Kusumi 	mbio = dmirror_get_bio_mbuf(bio);
130*f603807bSTomohiro Kusumi 
131*f603807bSTomohiro Kusumi 	if (bio->bio_buf->b_flags & B_ERROR) {
132*f603807bSTomohiro Kusumi 		/* write failed */
133*f603807bSTomohiro Kusumi 	}
134*f603807bSTomohiro Kusumi 
135*f603807bSTomohiro Kusumi 	obio = pop_bio(bio);
136*f603807bSTomohiro Kusumi 	biodone(obio);
137*f603807bSTomohiro Kusumi }
138*f603807bSTomohiro Kusumi 
139*f603807bSTomohiro Kusumi void
dmirror_issue_write(dmirror_disk_t disk,struct bio * bio)140*f603807bSTomohiro Kusumi dmirror_issue_write(dmirror_disk_t disk, struct bio *bio)
141*f603807bSTomohiro Kusumi {
142*f603807bSTomohiro Kusumi 	dmirror_set_bio_disk(bio, disk);
143*f603807bSTomohiro Kusumi 	dmirror_set_bio_segno(bio, SEGNO_FROM_OFFSET(bio->bio_offset));
144*f603807bSTomohiro Kusumi 
145*f603807bSTomohiro Kusumi 	bio->bio_done = dmirror_write_done;
146*f603807bSTomohiro Kusumi 	vn_strategy(disk->pdev, bio);
147*f603807bSTomohiro Kusumi }
148*f603807bSTomohiro Kusumi 
149*f603807bSTomohiro Kusumi void
dmirror_write(dm_target_crypt_config_t config,struct bio * bio)150*f603807bSTomohiro Kusumi dmirror_write(dm_target_crypt_config_t config, struct bio *bio)
151*f603807bSTomohiro Kusumi {
152*f603807bSTomohiro Kusumi 	dmirror_disk_t disk, m_disk;
153*f603807bSTomohiro Kusumi 	struct bio *wbio1, *wbio2;
154*f603807bSTomohiro Kusumi 	segdesc_t segdesc;
155*f603807bSTomohiro Kusumi 	int i, masters = 0;
156*f603807bSTomohiro Kusumi 
157*f603807bSTomohiro Kusumi 	for(i = 0; i < XXX config->ndisks; i++) {
158*f603807bSTomohiro Kusumi 		disk = &config->disks[i];
159*f603807bSTomohiro Kusumi 		segdesc = SEGDESC_FROM_OFFSET(disk, bio->bio_offset);
160*f603807bSTomohiro Kusumi 		if (segdesc->flags & MEDIA_MASTER) {
161*f603807bSTomohiro Kusumi 			if (++masters == 1)
162*f603807bSTomohiro Kusumi 				m_disk = disk;
163*f603807bSTomohiro Kusumi 		}
164*f603807bSTomohiro Kusumi 	}
165*f603807bSTomohiro Kusumi 
166*f603807bSTomohiro Kusumi 	if (masters == 1) {
167*f603807bSTomohiro Kusumi 		dmirror_set_bio_mbuf(bio, NULL);
168*f603807bSTomohiro Kusumi 		dmirror_issue_write(m_disk, bio);
169*f603807bSTomohiro Kusumi 	} else {
170*f603807bSTomohiro Kusumi 		wbio1 = dmirror_clone_bio(bio);
171*f603807bSTomohiro Kusumi 		wbio2 = dmirror_clone_bio(bio);
172*f603807bSTomohiro Kusumi 		dmirror_set_bio_mbuf(wbio1, bio);
173*f603807bSTomohiro Kusumi 		dmirror_set_bio_mbuf(wbio2, bio);
174*f603807bSTomohiro Kusumi 		dmirror_issue_write(XXX disk1, wbio1);
175*f603807bSTomohiro Kusumi 		dmirror_issue_write(XXX disk2, wbio2);
176*f603807bSTomohiro Kusumi 	}
177*f603807bSTomohiro Kusumi 
178*f603807bSTomohiro Kusumi }
179*f603807bSTomohiro Kusumi 
180*f603807bSTomohiro Kusumi static void
segdesc_set_flag(dmirror_disk_t disk,off_t segno,int flag)181*f603807bSTomohiro Kusumi segdesc_set_flag(dmirror_disk_t disk, off_t segno, int flag)
182*f603807bSTomohiro Kusumi {
183*f603807bSTomohiro Kusumi 	/*
184*f603807bSTomohiro Kusumi 	 * XXX: set the flag on the in-memory descriptor and write back to disks.
185*f603807bSTomohiro Kusumi 	 */
186*f603807bSTomohiro Kusumi 	foo |= flag;
187*f603807bSTomohiro Kusumi }
188*f603807bSTomohiro Kusumi 
189*f603807bSTomohiro Kusumi 
190*f603807bSTomohiro Kusumi static void
segdesc_clear_flag(dmirror_disk_t disk,off_t segno,int flag)191*f603807bSTomohiro Kusumi segdesc_clear_flag(dmirror_disk_t disk, off_t segno, int flag)
192*f603807bSTomohiro Kusumi {
193*f603807bSTomohiro Kusumi 	/*
194*f603807bSTomohiro Kusumi 	 * XXX: set the flag on the in-memory descriptor and write back to disks.
195*f603807bSTomohiro Kusumi 	 */
196*f603807bSTomohiro Kusumi 	foo &= ~flag;
197*f603807bSTomohiro Kusumi }
198*f603807bSTomohiro Kusumi 
199*f603807bSTomohiro Kusumi static void
dmirror_read_done(struct bio * bio)200*f603807bSTomohiro Kusumi dmirror_read_done(struct bio *bio)
201*f603807bSTomohiro Kusumi {
202*f603807bSTomohiro Kusumi 	dmirror_disk_t disk;
203*f603807bSTomohiro Kusumi 	off_t segno;
204*f603807bSTomohiro Kusumi 	struct bio *obio;
205*f603807bSTomohiro Kusumi 	int retries;
206*f603807bSTomohiro Kusumi 
207*f603807bSTomohiro Kusumi 	disk = dmirror_get_bio_disk(bio);
208*f603807bSTomohiro Kusumi 	segno = dmirror_get_bio_segno(bio);
209*f603807bSTomohiro Kusumi 	retries = dmirror_get_bio_retries(bio);
210*f603807bSTomohiro Kusumi 
211*f603807bSTomohiro Kusumi 	if (bio->bio_buf->b_flags & B_ERROR) {
212*f603807bSTomohiro Kusumi 		/* read failed, so redispatch to a different disk */
213*f603807bSTomohiro Kusumi 		segdesc_set_flag(disk, segno, MEDIA_READ_DEGRADED);
214*f603807bSTomohiro Kusumi 		/* XXX: set other disk to master, if possible */
215*f603807bSTomohiro Kusumi 		if (retries < disk->config->max_retries) {
216*f603807bSTomohiro Kusumi 			dmirror_set_bio_retries(bio, retries + 1);
217*f603807bSTomohiro Kusumi 			/*
218*f603807bSTomohiro Kusumi 			 * XXX: how do we restore the bio to health? Like this?
219*f603807bSTomohiro Kusumi 			 */
220*f603807bSTomohiro Kusumi 			bio->bio_buf->b_flags &= ~(B_ERROR | B_INVAL);
221*f603807bSTomohiro Kusumi 			/*
222*f603807bSTomohiro Kusumi 			 * XXX: something tells me that dispatching stuff from a
223*f603807bSTomohiro Kusumi 			 *	biodone routine is not the greatest idea
224*f603807bSTomohiro Kusumi 			 */
225*f603807bSTomohiro Kusumi 			dmirror_issue_read(next_disk, bio);
226*f603807bSTomohiro Kusumi 			return;
227*f603807bSTomohiro Kusumi 		}
228*f603807bSTomohiro Kusumi 	}
229*f603807bSTomohiro Kusumi 
230*f603807bSTomohiro Kusumi 	obio = pop_bio(bio);
231*f603807bSTomohiro Kusumi 	biodone(obio);
232*f603807bSTomohiro Kusumi }
233*f603807bSTomohiro Kusumi 
234*f603807bSTomohiro Kusumi void
dmirror_issue_read(dmirror_disk_t disk,struct bio * bio)235*f603807bSTomohiro Kusumi dmirror_issue_read(dmirror_disk_t disk, struct bio *bio)
236*f603807bSTomohiro Kusumi {
237*f603807bSTomohiro Kusumi 	dmirror_set_bio_disk(bio, disk);
238*f603807bSTomohiro Kusumi 	dmirror_set_bio_segno(bio, SEGNO_FROM_OFFSET(bio->bio_offset));
239*f603807bSTomohiro Kusumi 
240*f603807bSTomohiro Kusumi 	bio->bio_done = dmirror_read_done;
241*f603807bSTomohiro Kusumi 	vn_strategy(disk->pdev, bio);
242*f603807bSTomohiro Kusumi }
243*f603807bSTomohiro Kusumi 
244*f603807bSTomohiro Kusumi void
dmirror_read(dm_target_crypt_config_t config,struct bio * bio)245*f603807bSTomohiro Kusumi dmirror_read(dm_target_crypt_config_t config, struct bio *bio)
246*f603807bSTomohiro Kusumi {
247*f603807bSTomohiro Kusumi 	dmirror_disk_t disk, m_disk;
248*f603807bSTomohiro Kusumi 	segdesc_t segdesc;
249*f603807bSTomohiro Kusumi 	int i, masters = 0;
250*f603807bSTomohiro Kusumi 
251*f603807bSTomohiro Kusumi 	for(i = 0; i < XXX config->ndisks; i++) {
252*f603807bSTomohiro Kusumi 		disk = &config->disks[i];
253*f603807bSTomohiro Kusumi 		segdesc = SEGDESC_FROM_OFFSET(disk, bio->bio_offset);
254*f603807bSTomohiro Kusumi 		if (segdesc->flags & MEDIA_MASTER) {
255*f603807bSTomohiro Kusumi 			if (++masters == 1)
256*f603807bSTomohiro Kusumi 				m_disk = disk;
257*f603807bSTomohiro Kusumi 		}
258*f603807bSTomohiro Kusumi 	}
259*f603807bSTomohiro Kusumi 
260*f603807bSTomohiro Kusumi 	if (masters > 1) {
261*f603807bSTomohiro Kusumi 		/* XXX: fail. */
262*f603807bSTomohiro Kusumi 		biodone(foo);
263*f603807bSTomohiro Kusumi 		return;
264*f603807bSTomohiro Kusumi 	}
265*f603807bSTomohiro Kusumi 
266*f603807bSTomohiro Kusumi 	if (masters == 1) {
267*f603807bSTomohiro Kusumi 		segdesc = SEGDESC_FROM_OFFSET(m_disk, bio->bio_offset);
268*f603807bSTomohiro Kusumi 		if (segdesc->flags & UNINITIALIZED) {
269*f603807bSTomohiro Kusumi 			/* XXX: ... */
270*f603807bSTomohiro Kusumi 		}
271*f603807bSTomohiro Kusumi 		dmirror_issue_read(m_disk, bio);
272*f603807bSTomohiro Kusumi 	} else {
273*f603807bSTomohiro Kusumi 		/* dispatch read to any disk */
274*f603807bSTomohiro Kusumi 		/* but try not to send to a READ_DEGRADED drive */
275*f603807bSTomohiro Kusumi 		m_disk = NULL;
276*f603807bSTomohiro Kusumi 		for (i = 0; i < config->ndisks; i++) {
277*f603807bSTomohiro Kusumi 			disk = &config->disks[i];
278*f603807bSTomohiro Kusumi 			segdesc = SEGDESC_FROM_OFFSET(disk, bio->bio_offset);
279*f603807bSTomohiro Kusumi 			if (!(segdesc->flags & MEDIA_READ_DEGRADED)) {
280*f603807bSTomohiro Kusumi 				m_disk = disk;
281*f603807bSTomohiro Kusumi 				break;
282*f603807bSTomohiro Kusumi 			}
283*f603807bSTomohiro Kusumi 		}
284*f603807bSTomohiro Kusumi 		/* XXX: do the uninitialized magic here, too */
285*f603807bSTomohiro Kusumi 		if (m_disk) {
286*f603807bSTomohiro Kusumi 			/*
287*f603807bSTomohiro Kusumi 			 * XXX: we found some non-degraded disk. We might want to
288*f603807bSTomohiro Kusumi 			 * optimize performance by sending reads to different disks,
289*f603807bSTomohiro Kusumi 			 * not just the first one.
290*f603807bSTomohiro Kusumi 			 */
291*f603807bSTomohiro Kusumi 			dmirror_set_bio_retries(bio, 0);
292*f603807bSTomohiro Kusumi 			dmirror_issue_read(m_disk, bio);
293*f603807bSTomohiro Kusumi 		} else {
294*f603807bSTomohiro Kusumi 			/* XXX: all disks are read degraded, just sent to any */
295*f603807bSTomohiro Kusumi 			m_disk = &config->disks[i];
296*f603807bSTomohiro Kusumi 			dmirror_set_bio_retries(bio, 0);
297*f603807bSTomohiro Kusumi 			dmirror_issue_read(m_disk, bio);
298*f603807bSTomohiro Kusumi 		}
299*f603807bSTomohiro Kusumi 	}
300*f603807bSTomohiro Kusumi }
301*f603807bSTomohiro Kusumi 
302*f603807bSTomohiro Kusumi /* Strategy routine called from dm_strategy. */
303*f603807bSTomohiro Kusumi /*
304*f603807bSTomohiro Kusumi  * Do IO operation, called from dmstrategy routine.
305*f603807bSTomohiro Kusumi  */
306*f603807bSTomohiro Kusumi int
dm_target_dmirror_strategy(dm_table_entry_t * table_en,struct buf * bp)307*f603807bSTomohiro Kusumi dm_target_dmirror_strategy(dm_table_entry_t *table_en, struct buf *bp)
308*f603807bSTomohiro Kusumi {
309*f603807bSTomohiro Kusumi 	struct bio *bio, *split_bio1, *split_bio2;
310*f603807bSTomohiro Kusumi 	struct buf *bp;
311*f603807bSTomohiro Kusumi 	off_t bseg, eseg, seg_end;
312*f603807bSTomohiro Kusumi 	size_t fsb;
313*f603807bSTomohiro Kusumi 	int split_transaction = 0;
314*f603807bSTomohiro Kusumi 
315*f603807bSTomohiro Kusumi 	dm_target_crypt_config_t *priv;
316*f603807bSTomohiro Kusumi 	priv = table_en->target_config;
317*f603807bSTomohiro Kusumi 
318*f603807bSTomohiro Kusumi 	if ((bp->b_cmd == BUF_CMD_READ) || (bp->b_cmd == BUF_CMD_WRITE)) {
319*f603807bSTomohiro Kusumi 		/* Get rid of stuff we can't really handle */
320*f603807bSTomohiro Kusumi 		if (((bp->b_bcount % DEV_BSIZE) != 0) || (bp->b_bcount == 0)) {
321*f603807bSTomohiro Kusumi 			kprintf("dm_target_dmirror_strategy: can't really handle bp->b_bcount = %d\n", bp->b_bcount);
322*f603807bSTomohiro Kusumi 			bp->b_error = EINVAL;
323*f603807bSTomohiro Kusumi 			bp->b_flags |= B_ERROR | B_INVAL;
324*f603807bSTomohiro Kusumi 			biodone(&bp->b_bio1);
325*f603807bSTomohiro Kusumi 			return 0;
326*f603807bSTomohiro Kusumi 		}
327*f603807bSTomohiro Kusumi 
328*f603807bSTomohiro Kusumi 		bseg = SEGNO_FROM_OFFSET(bp->b_bio1.bio_offset);
329*f603807bSTomohiro Kusumi 		eseg = SEGNO_FROM_OFFSET(bp->b_bio1.bio_offset + bp->b_resid);
330*f603807bSTomohiro Kusumi 		seg_end = OFFSET_FROM_SEGNO(eseg);
331*f603807bSTomohiro Kusumi 
332*f603807bSTomohiro Kusumi 		if (bseg != eseg) {
333*f603807bSTomohiro Kusumi 			split_transaction = 1;
334*f603807bSTomohiro Kusumi 			/* fsb = first segment bytes (bytes in the first segment) */
335*f603807bSTomohiro Kusumi 			fsb = seg_end - bp->b_bio1.bio_offset;
336*f603807bSTomohiro Kusumi 
337*f603807bSTomohiro Kusumi 			nestbuf = getpbuf(NULL);
338*f603807bSTomohiro Kusumi 			nestiobuf_setup(&bp->b_bio1, nestbuf, 0, fsb);
339*f603807bSTomohiro Kusumi 			split_bio1 = push_bio(&nestbuf->b_bio1);
340*f603807bSTomohiro Kusumi 			split_bio1->bio_offset = bp->b_bio1.bio_offset +
341*f603807bSTomohiro Kusumi 			    priv->block_offset*DEV_BSIZE;
342*f603807bSTomohiro Kusumi 
343*f603807bSTomohiro Kusumi 			nestbuf = getpbuf(NULL);
344*f603807bSTomohiro Kusumi 			nestiobuf_setup(&bp->b_bio1, nestbuf, fsb, bp->b_resid - fsb);
345*f603807bSTomohiro Kusumi 			split_bio2 = push_bio(&nestbuf->b_bio1);
346*f603807bSTomohiro Kusumi 			split_bio2->bio_offset = bp->b_bio1.bio_offset + fsb +
347*f603807bSTomohiro Kusumi 			    priv->block_offset*DEV_BSIZE;
348*f603807bSTomohiro Kusumi 		}
349*f603807bSTomohiro Kusumi 	}
350*f603807bSTomohiro Kusumi 
351*f603807bSTomohiro Kusumi 	switch (bp->b_cmd) {
352*f603807bSTomohiro Kusumi 	case BUF_CMD_READ:
353*f603807bSTomohiro Kusumi 		if (split_transaction) {
354*f603807bSTomohiro Kusumi 			dmirror_read(priv, split_bio1);
355*f603807bSTomohiro Kusumi 			dmirror_read(priv, split_bio2);
356*f603807bSTomohiro Kusumi 		} else {
357*f603807bSTomohiro Kusumi 			bio = push_bio(&bp->b_bio1);
358*f603807bSTomohiro Kusumi 			bio->bio_offset = bp->b_bio1.bio_offset + priv->block_offset*DEV_BSIZE;
359*f603807bSTomohiro Kusumi 			dmirror_read(priv, bio);
360*f603807bSTomohiro Kusumi 		}
361*f603807bSTomohiro Kusumi 		break;
362*f603807bSTomohiro Kusumi 
363*f603807bSTomohiro Kusumi 	case BUF_CMD_WRITE:
364*f603807bSTomohiro Kusumi 		if (split_transaction) {
365*f603807bSTomohiro Kusumi 			dmirror_write(priv, split_bio1);
366*f603807bSTomohiro Kusumi 			dmirror_write(priv, split_bio2);
367*f603807bSTomohiro Kusumi 		} else {
368*f603807bSTomohiro Kusumi 			bio = push_bio(&bp->b_bio1);
369*f603807bSTomohiro Kusumi 			bio->bio_offset = bp->b_bio1.bio_offset + priv->block_offset*DEV_BSIZE;
370*f603807bSTomohiro Kusumi 			dmirror_write(priv, bio);
371*f603807bSTomohiro Kusumi 		}
372*f603807bSTomohiro Kusumi 		break;
373*f603807bSTomohiro Kusumi 
374*f603807bSTomohiro Kusumi 	default:
375*f603807bSTomohiro Kusumi 		/* XXX: clone... */
376*f603807bSTomohiro Kusumi 		vn_strategy(priv->pdev[0]->pdev_vnode, &bp->b_bio1);
377*f603807bSTomohiro Kusumi 		vn_strategy(priv->pdev[1]->pdev_vnode, &bp->b_bio1);
378*f603807bSTomohiro Kusumi 	}
379*f603807bSTomohiro Kusumi 
380*f603807bSTomohiro Kusumi 	return 0;
381*f603807bSTomohiro Kusumi 
382*f603807bSTomohiro Kusumi }
383*f603807bSTomohiro Kusumi 
384*f603807bSTomohiro Kusumi /* XXX: add missing dm functions */
385