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