ccd.c revision 1.51 1 /* $NetBSD: ccd.c,v 1.51 1998/07/31 01:23:56 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * Copyright (c) 1988 University of Utah.
41 * Copyright (c) 1990, 1993
42 * The Regents of the University of California. All rights reserved.
43 *
44 * This code is derived from software contributed to Berkeley by
45 * the Systems Programming Group of the University of Utah Computer
46 * Science Department.
47 *
48 * Redistribution and use in source and binary forms, with or without
49 * modification, are permitted provided that the following conditions
50 * are met:
51 * 1. Redistributions of source code must retain the above copyright
52 * notice, this list of conditions and the following disclaimer.
53 * 2. Redistributions in binary form must reproduce the above copyright
54 * notice, this list of conditions and the following disclaimer in the
55 * documentation and/or other materials provided with the distribution.
56 * 3. All advertising materials mentioning features or use of this software
57 * must display the following acknowledgement:
58 * This product includes software developed by the University of
59 * California, Berkeley and its contributors.
60 * 4. Neither the name of the University nor the names of its contributors
61 * may be used to endorse or promote products derived from this software
62 * without specific prior written permission.
63 *
64 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
65 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
66 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
67 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
68 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
69 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
70 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
71 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
72 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
73 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
74 * SUCH DAMAGE.
75 *
76 * from: Utah $Hdr: cd.c 1.6 90/11/28$
77 *
78 * @(#)cd.c 8.2 (Berkeley) 11/16/93
79 */
80
81 /*
82 * "Concatenated" disk driver.
83 *
84 * Dynamic configuration and disklabel support by:
85 * Jason R. Thorpe <thorpej (at) nas.nasa.gov>
86 * Numerical Aerodynamic Simulation Facility
87 * Mail Stop 258-6
88 * NASA Ames Research Center
89 * Moffett Field, CA 94035
90 *
91 * Mirroring support based on code written by Satoshi Asami
92 * and Nisha Talagala.
93 */
94
95 #include <sys/param.h>
96 #include <sys/systm.h>
97 #include <sys/proc.h>
98 #include <sys/errno.h>
99 #include <sys/buf.h>
100 #include <sys/malloc.h>
101 #include <sys/namei.h>
102 #include <sys/stat.h>
103 #include <sys/ioctl.h>
104 #include <sys/disklabel.h>
105 #include <sys/device.h>
106 #include <sys/disk.h>
107 #include <sys/syslog.h>
108 #include <sys/fcntl.h>
109 #include <sys/vnode.h>
110 #include <sys/conf.h>
111
112 #include <dev/ccdvar.h>
113
114 #if defined(CCDDEBUG) && !defined(DEBUG)
115 #define DEBUG
116 #endif
117
118 #ifdef DEBUG
119 #define CCDB_FOLLOW 0x01
120 #define CCDB_INIT 0x02
121 #define CCDB_IO 0x04
122 #define CCDB_LABEL 0x08
123 #define CCDB_VNODE 0x10
124 int ccddebug = 0x00;
125 #endif
126
127 #define ccdunit(x) DISKUNIT(x)
128
129 struct ccdbuf {
130 struct buf cb_buf; /* new I/O buf */
131 struct buf *cb_obp; /* ptr. to original I/O buf */
132 int cb_unit; /* target unit */
133 int cb_comp; /* target component */
134 int cb_flags; /* misc. flags */
135 };
136
137 /* cb_flags */
138 #define CBF_MIRROR 0x01 /* we're for a mirror component */
139
140 /* XXX Safe to wait? */
141 #define CCD_GETBUF(cs) pool_get(&(cs)->sc_cbufpool, PR_WAITOK)
142 #define CCD_PUTBUF(cs, cbp) pool_put(&(cs)->sc_cbufpool, cbp)
143
144 #define CCDLABELDEV(dev) \
145 (MAKEDISKDEV(major((dev)), ccdunit((dev)), RAW_PART))
146
147 /* called by main() at boot time */
148 void ccdattach __P((int));
149
150 /* called by biodone() at interrupt time */
151 void ccdiodone __P((struct buf *));
152 int ccdsize __P((dev_t));
153
154 static void ccdstart __P((struct ccd_softc *, struct buf *));
155 static void ccdinterleave __P((struct ccd_softc *, int));
156 static void ccdintr __P((struct ccd_softc *, struct buf *));
157 static int ccdinit __P((struct ccddevice *, char **, struct proc *));
158 static int ccdlookup __P((char *, struct proc *p, struct vnode **));
159 static void ccdbuffer __P((struct ccd_softc *, struct buf *,
160 daddr_t, caddr_t, long, struct ccdbuf **));
161 static void ccdgetdefaultlabel __P((struct ccd_softc *, struct disklabel *));
162 static void ccdgetdisklabel __P((dev_t));
163 static void ccdmakedisklabel __P((struct ccd_softc *));
164 static int ccdlock __P((struct ccd_softc *));
165 static void ccdunlock __P((struct ccd_softc *));
166
167 #ifdef DEBUG
168 static void printiinfo __P((struct ccdiinfo *));
169 #endif
170
171 /* Non-private for the benefit of libkvm. */
172 struct ccd_softc *ccd_softc;
173 struct ccddevice *ccddevs;
174 int numccd = 0;
175
176 /*
177 * Called by main() during pseudo-device attachment. All we need
178 * to do is allocate enough space for devices to be configured later.
179 */
180 void
181 ccdattach(num)
182 int num;
183 {
184 if (num <= 0) {
185 #ifdef DIAGNOSTIC
186 panic("ccdattach: count <= 0");
187 #endif
188 return;
189 }
190
191 ccd_softc = (struct ccd_softc *)malloc(num * sizeof(struct ccd_softc),
192 M_DEVBUF, M_NOWAIT);
193 ccddevs = (struct ccddevice *)malloc(num * sizeof(struct ccddevice),
194 M_DEVBUF, M_NOWAIT);
195 if ((ccd_softc == NULL) || (ccddevs == NULL)) {
196 printf("WARNING: no memory for concatenated disks\n");
197 if (ccd_softc != NULL)
198 free(ccd_softc, M_DEVBUF);
199 if (ccddevs != NULL)
200 free(ccddevs, M_DEVBUF);
201 return;
202 }
203 numccd = num;
204 bzero(ccd_softc, num * sizeof(struct ccd_softc));
205 bzero(ccddevs, num * sizeof(struct ccddevice));
206 }
207
208 static int
209 ccdinit(ccd, cpaths, p)
210 struct ccddevice *ccd;
211 char **cpaths;
212 struct proc *p;
213 {
214 register struct ccd_softc *cs = &ccd_softc[ccd->ccd_unit];
215 register struct ccdcinfo *ci = NULL;
216 register size_t size;
217 register int ix;
218 struct vnode *vp;
219 struct vattr va;
220 size_t minsize;
221 int maxsecsize;
222 struct partinfo dpart;
223 struct ccdgeom *ccg = &cs->sc_geom;
224 char tmppath[MAXPATHLEN];
225 int error;
226
227 #ifdef DEBUG
228 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
229 printf("ccdinit: unit %d\n", ccd->ccd_unit);
230 #endif
231
232 cs->sc_size = 0;
233 cs->sc_ileave = ccd->ccd_interleave;
234 cs->sc_nccdisks = ccd->ccd_ndev;
235 sprintf(cs->sc_xname, "ccd%d", ccd->ccd_unit); /* XXX */
236
237 /* Allocate space for the component info. */
238 cs->sc_cinfo = malloc(cs->sc_nccdisks * sizeof(struct ccdcinfo),
239 M_DEVBUF, M_WAITOK);
240
241 /*
242 * Verify that each component piece exists and record
243 * relevant information about it.
244 */
245 maxsecsize = 0;
246 minsize = 0;
247 for (ix = 0; ix < cs->sc_nccdisks; ix++) {
248 vp = ccd->ccd_vpp[ix];
249 ci = &cs->sc_cinfo[ix];
250 ci->ci_vp = vp;
251
252 /*
253 * Copy in the pathname of the component.
254 */
255 bzero(tmppath, sizeof(tmppath)); /* sanity */
256 error = copyinstr(cpaths[ix], tmppath,
257 MAXPATHLEN, &ci->ci_pathlen);
258 if (error) {
259 #ifdef DEBUG
260 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
261 printf("%s: can't copy path, error = %d\n",
262 cs->sc_xname, error);
263 #endif
264 free(cs->sc_cinfo, M_DEVBUF);
265 return (error);
266 }
267 ci->ci_path = malloc(ci->ci_pathlen, M_DEVBUF, M_WAITOK);
268 bcopy(tmppath, ci->ci_path, ci->ci_pathlen);
269
270 /*
271 * XXX: Cache the component's dev_t.
272 */
273 if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) != 0) {
274 #ifdef DEBUG
275 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
276 printf("%s: %s: getattr failed %s = %d\n",
277 cs->sc_xname, ci->ci_path,
278 "error", error);
279 #endif
280 free(ci->ci_path, M_DEVBUF);
281 free(cs->sc_cinfo, M_DEVBUF);
282 return (error);
283 }
284 ci->ci_dev = va.va_rdev;
285
286 /*
287 * Get partition information for the component.
288 */
289 error = VOP_IOCTL(vp, DIOCGPART, (caddr_t)&dpart,
290 FREAD, p->p_ucred, p);
291 if (error) {
292 #ifdef DEBUG
293 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
294 printf("%s: %s: ioctl failed, error = %d\n",
295 cs->sc_xname, ci->ci_path, error);
296 #endif
297 free(ci->ci_path, M_DEVBUF);
298 free(cs->sc_cinfo, M_DEVBUF);
299 return (error);
300 }
301
302 /*
303 * Calculate the size, truncating to an interleave
304 * boundary if necessary.
305 */
306 maxsecsize =
307 ((dpart.disklab->d_secsize > maxsecsize) ?
308 dpart.disklab->d_secsize : maxsecsize);
309 size = dpart.part->p_size;
310 if (cs->sc_ileave > 1)
311 size -= size % cs->sc_ileave;
312
313 if (size == 0) {
314 #ifdef DEBUG
315 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
316 printf("%s: %s: size == 0\n",
317 cs->sc_xname, ci->ci_path);
318 #endif
319 free(ci->ci_path, M_DEVBUF);
320 free(cs->sc_cinfo, M_DEVBUF);
321 return (ENODEV);
322 }
323
324 if (minsize == 0 || size < minsize)
325 minsize = size;
326 ci->ci_size = size;
327 cs->sc_size += size;
328 }
329
330 /*
331 * Don't allow the interleave to be smaller than
332 * the biggest component sector.
333 */
334 if ((cs->sc_ileave > 0) &&
335 (cs->sc_ileave < (maxsecsize / DEV_BSIZE))) {
336 #ifdef DEBUG
337 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
338 printf("%s: interleave must be at least %d\n",
339 cs->sc_xname, (maxsecsize / DEV_BSIZE));
340 #endif
341 free(ci->ci_path, M_DEVBUF);
342 free(cs->sc_cinfo, M_DEVBUF);
343 return (EINVAL);
344 }
345
346 /*
347 * Mirroring support requires uniform interleave and
348 * and even number of components.
349 */
350 if (ccd->ccd_flags & CCDF_MIRROR) {
351 ccd->ccd_flags |= CCDF_UNIFORM;
352 if (cs->sc_ileave == 0) {
353 #ifdef DEBUG
354 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
355 printf("%s: mirroring requires interleave\n",
356 cs->sc_xname);
357 #endif
358 free(ci->ci_path, M_DEVBUF);
359 free(cs->sc_cinfo, M_DEVBUF);
360 return (EINVAL);
361 }
362 if (cs->sc_nccdisks % 2) {
363 #ifdef DEBUG
364 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
365 printf("%s: mirroring requires even # of components\n",
366 cs->sc_xname);
367 #endif
368 free(ci->ci_path, M_DEVBUF);
369 free(cs->sc_cinfo, M_DEVBUF);
370 return (EINVAL);
371 }
372 }
373
374 /*
375 * If uniform interleave is desired set all sizes to that of
376 * the smallest component.
377 */
378 if (ccd->ccd_flags & CCDF_UNIFORM) {
379 for (ci = cs->sc_cinfo;
380 ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
381 ci->ci_size = minsize;
382
383 if (ccd->ccd_flags & CCDF_MIRROR)
384 cs->sc_size = (cs->sc_nccdisks / 2) * minsize;
385 else
386 cs->sc_size = cs->sc_nccdisks * minsize;
387 }
388
389 /*
390 * Construct the interleave table.
391 */
392 ccdinterleave(cs, ccd->ccd_unit);
393
394 /*
395 * Create pseudo-geometry based on 1MB cylinders. It's
396 * pretty close.
397 */
398 ccg->ccg_secsize = DEV_BSIZE;
399 ccg->ccg_ntracks = 1;
400 ccg->ccg_nsectors = 1024 * (1024 / ccg->ccg_secsize);
401 ccg->ccg_ncylinders = cs->sc_size / ccg->ccg_nsectors;
402
403 cs->sc_flags |= CCDF_INITED;
404 cs->sc_cflags = ccd->ccd_flags; /* So we can find out later... */
405 cs->sc_unit = ccd->ccd_unit;
406
407 return (0);
408 }
409
410 static void
411 ccdinterleave(cs, unit)
412 register struct ccd_softc *cs;
413 int unit;
414 {
415 register struct ccdcinfo *ci, *smallci;
416 register struct ccdiinfo *ii;
417 register daddr_t bn, lbn;
418 register int ix;
419 u_long size;
420
421 #ifdef DEBUG
422 if (ccddebug & CCDB_INIT)
423 printf("ccdinterleave(%p): ileave %d\n", cs, cs->sc_ileave);
424 #endif
425 /*
426 * Allocate an interleave table.
427 * Chances are this is too big, but we don't care.
428 */
429 size = (cs->sc_nccdisks + 1) * sizeof(struct ccdiinfo);
430 cs->sc_itable = (struct ccdiinfo *)malloc(size, M_DEVBUF, M_WAITOK);
431 bzero((caddr_t)cs->sc_itable, size);
432
433 /*
434 * Trivial case: no interleave (actually interleave of disk size).
435 * Each table entry represents a single component in its entirety.
436 */
437 if (cs->sc_ileave == 0) {
438 bn = 0;
439 ii = cs->sc_itable;
440
441 for (ix = 0; ix < cs->sc_nccdisks; ix++) {
442 /* Allocate space for ii_index. */
443 ii->ii_index = malloc(sizeof(int), M_DEVBUF, M_WAITOK);
444 ii->ii_ndisk = 1;
445 ii->ii_startblk = bn;
446 ii->ii_startoff = 0;
447 ii->ii_index[0] = ix;
448 bn += cs->sc_cinfo[ix].ci_size;
449 ii++;
450 }
451 ii->ii_ndisk = 0;
452 #ifdef DEBUG
453 if (ccddebug & CCDB_INIT)
454 printiinfo(cs->sc_itable);
455 #endif
456 return;
457 }
458
459 /*
460 * The following isn't fast or pretty; it doesn't have to be.
461 */
462 size = 0;
463 bn = lbn = 0;
464 for (ii = cs->sc_itable; ; ii++) {
465 /* Allocate space for ii_index. */
466 ii->ii_index = malloc((sizeof(int) * cs->sc_nccdisks),
467 M_DEVBUF, M_WAITOK);
468
469 /*
470 * Locate the smallest of the remaining components
471 */
472 smallci = NULL;
473 for (ci = cs->sc_cinfo;
474 ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
475 if (ci->ci_size > size &&
476 (smallci == NULL ||
477 ci->ci_size < smallci->ci_size))
478 smallci = ci;
479
480 /*
481 * Nobody left, all done
482 */
483 if (smallci == NULL) {
484 ii->ii_ndisk = 0;
485 break;
486 }
487
488 /*
489 * Record starting logical block and component offset
490 */
491 ii->ii_startblk = bn / cs->sc_ileave;
492 ii->ii_startoff = lbn;
493
494 /*
495 * Determine how many disks take part in this interleave
496 * and record their indices.
497 */
498 ix = 0;
499 for (ci = cs->sc_cinfo;
500 ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
501 if (ci->ci_size >= smallci->ci_size)
502 ii->ii_index[ix++] = ci - cs->sc_cinfo;
503 ii->ii_ndisk = ix;
504 bn += ix * (smallci->ci_size - size);
505 lbn = smallci->ci_size / cs->sc_ileave;
506 size = smallci->ci_size;
507 }
508 #ifdef DEBUG
509 if (ccddebug & CCDB_INIT)
510 printiinfo(cs->sc_itable);
511 #endif
512 }
513
514 /* ARGSUSED */
515 int
516 ccdopen(dev, flags, fmt, p)
517 dev_t dev;
518 int flags, fmt;
519 struct proc *p;
520 {
521 int unit = ccdunit(dev);
522 struct ccd_softc *cs;
523 struct disklabel *lp;
524 int error = 0, part, pmask;
525
526 #ifdef DEBUG
527 if (ccddebug & CCDB_FOLLOW)
528 printf("ccdopen(0x%x, 0x%x)\n", dev, flags);
529 #endif
530 if (unit >= numccd)
531 return (ENXIO);
532 cs = &ccd_softc[unit];
533
534 if ((error = ccdlock(cs)) != 0)
535 return (error);
536
537 lp = cs->sc_dkdev.dk_label;
538
539 part = DISKPART(dev);
540 pmask = (1 << part);
541
542 /*
543 * If we're initialized, check to see if there are any other
544 * open partitions. If not, then it's safe to update
545 * the in-core disklabel.
546 */
547 if ((cs->sc_flags & CCDF_INITED) && (cs->sc_dkdev.dk_openmask == 0))
548 ccdgetdisklabel(dev);
549
550 /* Check that the partition exists. */
551 if (part != RAW_PART) {
552 if (((cs->sc_flags & CCDF_INITED) == 0) ||
553 ((part >= lp->d_npartitions) ||
554 (lp->d_partitions[part].p_fstype == FS_UNUSED))) {
555 error = ENXIO;
556 goto done;
557 }
558 }
559
560 /* Prevent our unit from being unconfigured while open. */
561 switch (fmt) {
562 case S_IFCHR:
563 cs->sc_dkdev.dk_copenmask |= pmask;
564 break;
565
566 case S_IFBLK:
567 cs->sc_dkdev.dk_bopenmask |= pmask;
568 break;
569 }
570 cs->sc_dkdev.dk_openmask =
571 cs->sc_dkdev.dk_copenmask | cs->sc_dkdev.dk_bopenmask;
572
573 done:
574 ccdunlock(cs);
575 return (error);
576 }
577
578 /* ARGSUSED */
579 int
580 ccdclose(dev, flags, fmt, p)
581 dev_t dev;
582 int flags, fmt;
583 struct proc *p;
584 {
585 int unit = ccdunit(dev);
586 struct ccd_softc *cs;
587 int error = 0, part;
588
589 #ifdef DEBUG
590 if (ccddebug & CCDB_FOLLOW)
591 printf("ccdclose(0x%x, 0x%x)\n", dev, flags);
592 #endif
593
594 if (unit >= numccd)
595 return (ENXIO);
596 cs = &ccd_softc[unit];
597
598 if ((error = ccdlock(cs)) != 0)
599 return (error);
600
601 part = DISKPART(dev);
602
603 /* ...that much closer to allowing unconfiguration... */
604 switch (fmt) {
605 case S_IFCHR:
606 cs->sc_dkdev.dk_copenmask &= ~(1 << part);
607 break;
608
609 case S_IFBLK:
610 cs->sc_dkdev.dk_bopenmask &= ~(1 << part);
611 break;
612 }
613 cs->sc_dkdev.dk_openmask =
614 cs->sc_dkdev.dk_copenmask | cs->sc_dkdev.dk_bopenmask;
615
616 ccdunlock(cs);
617 return (0);
618 }
619
620 void
621 ccdstrategy(bp)
622 register struct buf *bp;
623 {
624 register int unit = ccdunit(bp->b_dev);
625 register struct ccd_softc *cs = &ccd_softc[unit];
626 register int s;
627 int wlabel;
628 struct disklabel *lp;
629
630 #ifdef DEBUG
631 if (ccddebug & CCDB_FOLLOW)
632 printf("ccdstrategy(%p): unit %d\n", bp, unit);
633 #endif
634 if ((cs->sc_flags & CCDF_INITED) == 0) {
635 bp->b_error = ENXIO;
636 bp->b_flags |= B_ERROR;
637 goto done;
638 }
639
640 /* If it's a nil transfer, wake up the top half now. */
641 if (bp->b_bcount == 0)
642 goto done;
643
644 lp = cs->sc_dkdev.dk_label;
645
646 /*
647 * Do bounds checking and adjust transfer. If there's an
648 * error, the bounds check will flag that for us.
649 */
650 wlabel = cs->sc_flags & (CCDF_WLABEL|CCDF_LABELLING);
651 if (DISKPART(bp->b_dev) != RAW_PART)
652 if (bounds_check_with_label(bp, lp, wlabel) <= 0)
653 goto done;
654
655 bp->b_resid = bp->b_bcount;
656
657 /*
658 * "Start" the unit.
659 */
660 s = splbio();
661 ccdstart(cs, bp);
662 splx(s);
663 return;
664 done:
665 biodone(bp);
666 }
667
668 static void
669 ccdstart(cs, bp)
670 register struct ccd_softc *cs;
671 register struct buf *bp;
672 {
673 register long bcount, rcount;
674 struct ccdbuf *cbp[4];
675 caddr_t addr;
676 daddr_t bn;
677 struct partition *pp;
678
679 #ifdef DEBUG
680 if (ccddebug & CCDB_FOLLOW)
681 printf("ccdstart(%p, %p)\n", cs, bp);
682 #endif
683
684 /* Instrumentation. */
685 disk_busy(&cs->sc_dkdev);
686
687 /*
688 * Translate the partition-relative block number to an absolute.
689 */
690 bn = bp->b_blkno;
691 if (DISKPART(bp->b_dev) != RAW_PART) {
692 pp = &cs->sc_dkdev.dk_label->d_partitions[DISKPART(bp->b_dev)];
693 bn += pp->p_offset;
694 }
695
696 /*
697 * Allocate component buffers and fire off the requests
698 */
699 addr = bp->b_data;
700 for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) {
701 ccdbuffer(cs, bp, bn, addr, bcount, cbp);
702 rcount = cbp[0]->cb_buf.b_bcount;
703 if ((cbp[0]->cb_buf.b_flags & B_READ) == 0)
704 cbp[0]->cb_buf.b_vp->v_numoutput++;
705 VOP_STRATEGY(&cbp[0]->cb_buf);
706
707 /*
708 * Mirror requires additional write.
709 */
710 if ((cs->sc_cflags & CCDF_MIRROR) &&
711 ((cbp[0]->cb_buf.b_flags & B_READ) == 0)) {
712 cbp[1]->cb_buf.b_vp->v_numoutput++;
713 VOP_STRATEGY(&cbp[1]->cb_buf);
714 }
715
716 bn += btodb(rcount);
717 addr += rcount;
718 }
719 }
720
721 /*
722 * Build a component buffer header.
723 */
724 static void
725 ccdbuffer(cs, bp, bn, addr, bcount, cbpp)
726 register struct ccd_softc *cs;
727 struct buf *bp;
728 daddr_t bn;
729 caddr_t addr;
730 long bcount;
731 struct ccdbuf **cbpp;
732 {
733 register struct ccdcinfo *ci, *ci2 = NULL;
734 register struct ccdbuf *cbp;
735 register daddr_t cbn, cboff;
736 register u_int64_t cbc;
737 int ccdisk;
738
739 #ifdef DEBUG
740 if (ccddebug & CCDB_IO)
741 printf("ccdbuffer(%p, %p, %d, %p, %ld)\n",
742 cs, bp, bn, addr, bcount);
743 #endif
744 /*
745 * Determine which component bn falls in.
746 */
747 cbn = bn;
748 cboff = 0;
749
750 /*
751 * Serially concatenated
752 */
753 if (cs->sc_ileave == 0) {
754 register daddr_t sblk;
755
756 sblk = 0;
757 for (ccdisk = 0, ci = &cs->sc_cinfo[ccdisk];
758 cbn >= sblk + ci->ci_size;
759 ccdisk++, ci = &cs->sc_cinfo[ccdisk])
760 sblk += ci->ci_size;
761 cbn -= sblk;
762 }
763 /*
764 * Interleaved
765 */
766 else {
767 register struct ccdiinfo *ii;
768 int off;
769
770 cboff = cbn % cs->sc_ileave;
771 cbn /= cs->sc_ileave;
772 for (ii = cs->sc_itable; ii->ii_ndisk; ii++)
773 if (ii->ii_startblk > cbn)
774 break;
775 ii--;
776 off = cbn - ii->ii_startblk;
777 if (ii->ii_ndisk == 1) {
778 ccdisk = ii->ii_index[0];
779 cbn = ii->ii_startoff + off;
780 } else {
781 if (cs->sc_cflags & CCDF_MIRROR) {
782 ccdisk =
783 ii->ii_index[off % (ii->ii_ndisk / 2)];
784 cbn = ii->ii_startoff +
785 (off / (ii->ii_ndisk / 2));
786 /* Mirrored data */
787 ci2 =
788 &cs->sc_cinfo[ccdisk + (ii->ii_ndisk / 2)];
789 } else {
790 /* Normal case. */
791 ccdisk = ii->ii_index[off % ii->ii_ndisk];
792 cbn = ii->ii_startoff + off / ii->ii_ndisk;
793 }
794 }
795 cbn *= cs->sc_ileave;
796 ci = &cs->sc_cinfo[ccdisk];
797 }
798
799 /*
800 * Fill in the component buf structure.
801 */
802 cbp = CCD_GETBUF(cs);
803 cbp->cb_flags = 0;
804 cbp->cb_buf.b_flags = bp->b_flags | B_CALL;
805 cbp->cb_buf.b_iodone = ccdiodone;
806 cbp->cb_buf.b_proc = bp->b_proc;
807 cbp->cb_buf.b_dev = ci->ci_dev; /* XXX */
808 cbp->cb_buf.b_blkno = cbn + cboff;
809 cbp->cb_buf.b_data = addr;
810 cbp->cb_buf.b_vp = ci->ci_vp;
811 if (cs->sc_ileave == 0)
812 cbc = dbtob((u_int64_t)(ci->ci_size - cbn));
813 else
814 cbc = dbtob((u_int64_t)(cs->sc_ileave - cboff));
815 cbp->cb_buf.b_bcount = cbc < bcount ? cbc : bcount;
816
817 /*
818 * context for ccdiodone
819 */
820 cbp->cb_obp = bp;
821 cbp->cb_unit = cs->sc_unit;
822 cbp->cb_comp = ccdisk;
823
824 /* First buffer is dealt with. */
825 cbpp[0] = cbp;
826
827 #ifdef DEBUG
828 if (ccddebug & CCDB_IO)
829 printf(" dev 0x%x(u%d): cbp %p bn %d addr %p bcnt %ld\n",
830 ci->ci_dev, ci-cs->sc_cinfo, cbp, cbp->cb_buf.b_blkno,
831 cbp->cb_buf.b_data, cbp->cb_buf.b_bcount);
832 #endif
833
834 /*
835 * Mirrors have an additional write operation that is nearly
836 * identical to the first.
837 */
838 if ((cs->sc_cflags & CCDF_MIRROR) &&
839 ((cbp->cb_buf.b_flags & B_READ) == 0)) {
840 cbp = CCD_GETBUF(cs);
841 *cbp = *cbpp[0];
842 cbp->cb_flags = CBF_MIRROR;
843 cbp->cb_buf.b_dev = ci2->ci_dev; /* XXX */
844 cbp->cb_buf.b_vp = ci2->ci_vp;
845 cbp->cb_comp = ci2 - cs->sc_cinfo;
846 cbpp[1] = cbp;
847 }
848 }
849
850 static void
851 ccdintr(cs, bp)
852 register struct ccd_softc *cs;
853 register struct buf *bp;
854 {
855
856 #ifdef DEBUG
857 if (ccddebug & CCDB_FOLLOW)
858 printf("ccdintr(%p, %p)\n", cs, bp);
859 #endif
860 /*
861 * Request is done for better or worse, wakeup the top half.
862 */
863 if (bp->b_flags & B_ERROR)
864 bp->b_resid = bp->b_bcount;
865 disk_unbusy(&cs->sc_dkdev, (bp->b_bcount - bp->b_resid));
866 biodone(bp);
867 }
868
869 /*
870 * Called at interrupt time.
871 * Mark the component as done and if all components are done,
872 * take a ccd interrupt.
873 */
874 void
875 ccdiodone(vbp)
876 struct buf *vbp;
877 {
878 struct ccdbuf *cbp = (struct ccdbuf *) vbp;
879 register struct buf *bp = cbp->cb_obp;
880 register int unit = cbp->cb_unit;
881 struct ccd_softc *cs = &ccd_softc[unit];
882 int count, cbflags, s;
883 char *comptype;
884
885 s = splbio();
886 #ifdef DEBUG
887 if (ccddebug & CCDB_FOLLOW)
888 printf("ccdiodone(%p)\n", cbp);
889 if (ccddebug & CCDB_IO) {
890 if (cbp->cb_flags & CBF_MIRROR)
891 printf("ccdiodone: mirror component\n");
892 else
893 printf("ccdiodone: bp %p bcount %ld resid %ld\n",
894 bp, bp->b_bcount, bp->b_resid);
895 printf(" dev 0x%x(u%d), cbp %p bn %d addr %p bcnt %ld\n",
896 cbp->cb_buf.b_dev, cbp->cb_comp, cbp,
897 cbp->cb_buf.b_blkno, cbp->cb_buf.b_data,
898 cbp->cb_buf.b_bcount);
899 }
900 #endif
901
902 if (cbp->cb_buf.b_flags & B_ERROR) {
903 if (cbp->cb_flags & CBF_MIRROR)
904 comptype = " (mirror)";
905 else {
906 bp->b_flags |= B_ERROR;
907 bp->b_error = cbp->cb_buf.b_error ?
908 cbp->cb_buf.b_error : EIO;
909 comptype = "";
910 }
911
912 printf("%s: error %d on component %d%s\n",
913 cs->sc_xname, bp->b_error, cbp->cb_comp, comptype);
914 }
915 count = cbp->cb_buf.b_bcount;
916 cbflags = cbp->cb_flags;
917 CCD_PUTBUF(cs, cbp);
918
919 /*
920 * If all done, "interrupt".
921 *
922 * Note that mirror component buffers aren't counted against
923 * the original I/O buffer.
924 */
925 if ((cbflags & CBF_MIRROR) == 0) {
926 bp->b_resid -= count;
927 if (bp->b_resid < 0)
928 panic("ccdiodone: count");
929 if (bp->b_resid == 0)
930 ccdintr(&ccd_softc[unit], bp);
931 }
932 splx(s);
933 }
934
935 /* ARGSUSED */
936 int
937 ccdread(dev, uio, flags)
938 dev_t dev;
939 struct uio *uio;
940 int flags;
941 {
942 int unit = ccdunit(dev);
943 struct ccd_softc *cs;
944
945 #ifdef DEBUG
946 if (ccddebug & CCDB_FOLLOW)
947 printf("ccdread(0x%x, %p)\n", dev, uio);
948 #endif
949 if (unit >= numccd)
950 return (ENXIO);
951 cs = &ccd_softc[unit];
952
953 if ((cs->sc_flags & CCDF_INITED) == 0)
954 return (ENXIO);
955
956 /*
957 * XXX: It's not clear that using minphys() is completely safe,
958 * in particular, for raw I/O. Underlying devices might have some
959 * non-obvious limits, because of the copy to user-space.
960 */
961 return (physio(ccdstrategy, NULL, dev, B_READ, minphys, uio));
962 }
963
964 /* ARGSUSED */
965 int
966 ccdwrite(dev, uio, flags)
967 dev_t dev;
968 struct uio *uio;
969 int flags;
970 {
971 int unit = ccdunit(dev);
972 struct ccd_softc *cs;
973
974 #ifdef DEBUG
975 if (ccddebug & CCDB_FOLLOW)
976 printf("ccdwrite(0x%x, %p)\n", dev, uio);
977 #endif
978 if (unit >= numccd)
979 return (ENXIO);
980 cs = &ccd_softc[unit];
981
982 if ((cs->sc_flags & CCDF_INITED) == 0)
983 return (ENXIO);
984
985 /*
986 * XXX: It's not clear that using minphys() is completely safe,
987 * in particular, for raw I/O. Underlying devices might have some
988 * non-obvious limits, because of the copy to user-space.
989 */
990 return (physio(ccdstrategy, NULL, dev, B_WRITE, minphys, uio));
991 }
992
993 int
994 ccdioctl(dev, cmd, data, flag, p)
995 dev_t dev;
996 u_long cmd;
997 caddr_t data;
998 int flag;
999 struct proc *p;
1000 {
1001 int unit = ccdunit(dev);
1002 int i, j, lookedup = 0, error = 0;
1003 int part, pmask;
1004 struct ccd_softc *cs;
1005 struct ccd_ioctl *ccio = (struct ccd_ioctl *)data;
1006 struct ccddevice ccd;
1007 char **cpp;
1008 struct vnode **vpp;
1009
1010 if (unit >= numccd)
1011 return (ENXIO);
1012 cs = &ccd_softc[unit];
1013
1014 bzero(&ccd, sizeof(ccd));
1015
1016 /* Must be open for writes for these commands... */
1017 switch (cmd) {
1018 case CCDIOCSET:
1019 case CCDIOCCLR:
1020 case DIOCSDINFO:
1021 case DIOCWDINFO:
1022 case DIOCWLABEL:
1023 if ((flag & FWRITE) == 0)
1024 return (EBADF);
1025 }
1026
1027 /* Must be initialized for these... */
1028 switch (cmd) {
1029 case CCDIOCCLR:
1030 case DIOCGDINFO:
1031 case DIOCSDINFO:
1032 case DIOCWDINFO:
1033 case DIOCGPART:
1034 case DIOCWLABEL:
1035 case DIOCGDEFLABEL:
1036 if ((cs->sc_flags & CCDF_INITED) == 0)
1037 return (ENXIO);
1038 }
1039
1040 switch (cmd) {
1041 case CCDIOCSET:
1042 if (cs->sc_flags & CCDF_INITED)
1043 return (EBUSY);
1044
1045 if ((error = ccdlock(cs)) != 0)
1046 return (error);
1047
1048 /* Fill in some important bits. */
1049 ccd.ccd_unit = unit;
1050 ccd.ccd_interleave = ccio->ccio_ileave;
1051 ccd.ccd_flags = ccio->ccio_flags & CCDF_USERMASK;
1052
1053 /*
1054 * Allocate space for and copy in the array of
1055 * componet pathnames and device numbers.
1056 */
1057 cpp = malloc(ccio->ccio_ndisks * sizeof(char *),
1058 M_DEVBUF, M_WAITOK);
1059 vpp = malloc(ccio->ccio_ndisks * sizeof(struct vnode *),
1060 M_DEVBUF, M_WAITOK);
1061
1062 error = copyin((caddr_t)ccio->ccio_disks, (caddr_t)cpp,
1063 ccio->ccio_ndisks * sizeof(char **));
1064 if (error) {
1065 free(vpp, M_DEVBUF);
1066 free(cpp, M_DEVBUF);
1067 ccdunlock(cs);
1068 return (error);
1069 }
1070
1071 #ifdef DEBUG
1072 if (ccddebug & CCDB_INIT)
1073 for (i = 0; i < ccio->ccio_ndisks; ++i)
1074 printf("ccdioctl: component %d: 0x%p\n",
1075 i, cpp[i]);
1076 #endif
1077
1078 for (i = 0; i < ccio->ccio_ndisks; ++i) {
1079 #ifdef DEBUG
1080 if (ccddebug & CCDB_INIT)
1081 printf("ccdioctl: lookedup = %d\n", lookedup);
1082 #endif
1083 if ((error = ccdlookup(cpp[i], p, &vpp[i])) != 0) {
1084 for (j = 0; j < lookedup; ++j)
1085 (void)vn_close(vpp[j], FREAD|FWRITE,
1086 p->p_ucred, p);
1087 free(vpp, M_DEVBUF);
1088 free(cpp, M_DEVBUF);
1089 ccdunlock(cs);
1090 return (error);
1091 }
1092 ++lookedup;
1093 }
1094 ccd.ccd_cpp = cpp;
1095 ccd.ccd_vpp = vpp;
1096 ccd.ccd_ndev = ccio->ccio_ndisks;
1097
1098 /*
1099 * Initialize the ccd. Fills in the softc for us.
1100 */
1101 if ((error = ccdinit(&ccd, cpp, p)) != 0) {
1102 for (j = 0; j < lookedup; ++j)
1103 (void)vn_close(vpp[j], FREAD|FWRITE,
1104 p->p_ucred, p);
1105 bzero(&ccd_softc[unit], sizeof(struct ccd_softc));
1106 free(vpp, M_DEVBUF);
1107 free(cpp, M_DEVBUF);
1108 ccdunlock(cs);
1109 return (error);
1110 }
1111
1112 /*
1113 * The ccd has been successfully initialized, so
1114 * we can place it into the array. Don't try to
1115 * read the disklabel until the disk has been attached,
1116 * because space for the disklabel is allocated
1117 * in disk_attach();
1118 */
1119 bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1120 ccio->ccio_unit = unit;
1121 ccio->ccio_size = cs->sc_size;
1122
1123 /* Attach the disk. */
1124 cs->sc_dkdev.dk_name = cs->sc_xname;
1125 disk_attach(&cs->sc_dkdev);
1126
1127 /* Initialize the component buffer pool. */
1128 pool_init(&cs->sc_cbufpool, sizeof(struct ccdbuf), 0,
1129 0, 0, "ccdpl", 0, NULL, NULL, M_DEVBUF);
1130
1131 /* Try and read the disklabel. */
1132 ccdgetdisklabel(dev);
1133
1134 ccdunlock(cs);
1135
1136 break;
1137
1138 case CCDIOCCLR:
1139 if ((error = ccdlock(cs)) != 0)
1140 return (error);
1141
1142 /*
1143 * Don't unconfigure if any other partitions are open
1144 * or if both the character and block flavors of this
1145 * partition are open.
1146 */
1147 part = DISKPART(dev);
1148 pmask = (1 << part);
1149 if ((cs->sc_dkdev.dk_openmask & ~pmask) ||
1150 ((cs->sc_dkdev.dk_bopenmask & pmask) &&
1151 (cs->sc_dkdev.dk_copenmask & pmask))) {
1152 ccdunlock(cs);
1153 return (EBUSY);
1154 }
1155
1156 /*
1157 * Free ccd_softc information and clear entry.
1158 */
1159
1160 /* Close the components and free their pathnames. */
1161 for (i = 0; i < cs->sc_nccdisks; ++i) {
1162 /*
1163 * XXX: this close could potentially fail and
1164 * cause Bad Things. Maybe we need to force
1165 * the close to happen?
1166 */
1167 #ifdef DEBUG
1168 if (ccddebug & CCDB_VNODE)
1169 vprint("CCDIOCCLR: vnode info",
1170 cs->sc_cinfo[i].ci_vp);
1171 #endif
1172 (void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE,
1173 p->p_ucred, p);
1174 free(cs->sc_cinfo[i].ci_path, M_DEVBUF);
1175 }
1176
1177 /* Free interleave index. */
1178 for (i = 0; cs->sc_itable[i].ii_ndisk; ++i)
1179 free(cs->sc_itable[i].ii_index, M_DEVBUF);
1180
1181 /* Free component info and interleave table. */
1182 free(cs->sc_cinfo, M_DEVBUF);
1183 free(cs->sc_itable, M_DEVBUF);
1184 cs->sc_flags &= ~CCDF_INITED;
1185
1186 /*
1187 * Free ccddevice information and clear entry.
1188 */
1189 free(ccddevs[unit].ccd_cpp, M_DEVBUF);
1190 free(ccddevs[unit].ccd_vpp, M_DEVBUF);
1191 bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1192
1193 /* Free the component buffer pool. */
1194 pool_destroy(&cs->sc_cbufpool);
1195
1196 /* Detatch the disk. */
1197 disk_detach(&cs->sc_dkdev);
1198
1199 ccdunlock(cs);
1200
1201 break;
1202
1203 case DIOCGDINFO:
1204 *(struct disklabel *)data = *(cs->sc_dkdev.dk_label);
1205 break;
1206
1207 case DIOCGPART:
1208 ((struct partinfo *)data)->disklab = cs->sc_dkdev.dk_label;
1209 ((struct partinfo *)data)->part =
1210 &cs->sc_dkdev.dk_label->d_partitions[DISKPART(dev)];
1211 break;
1212
1213 case DIOCWDINFO:
1214 case DIOCSDINFO:
1215 if ((error = ccdlock(cs)) != 0)
1216 return (error);
1217
1218 cs->sc_flags |= CCDF_LABELLING;
1219
1220 error = setdisklabel(cs->sc_dkdev.dk_label,
1221 (struct disklabel *)data, 0, cs->sc_dkdev.dk_cpulabel);
1222 if (error == 0) {
1223 if (cmd == DIOCWDINFO)
1224 error = writedisklabel(CCDLABELDEV(dev),
1225 ccdstrategy, cs->sc_dkdev.dk_label,
1226 cs->sc_dkdev.dk_cpulabel);
1227 }
1228
1229 cs->sc_flags &= ~CCDF_LABELLING;
1230
1231 ccdunlock(cs);
1232
1233 if (error)
1234 return (error);
1235 break;
1236
1237 case DIOCWLABEL:
1238 if (*(int *)data != 0)
1239 cs->sc_flags |= CCDF_WLABEL;
1240 else
1241 cs->sc_flags &= ~CCDF_WLABEL;
1242 break;
1243
1244 case DIOCGDEFLABEL:
1245 ccdgetdefaultlabel(cs, (struct disklabel *)data);
1246 break;
1247
1248 default:
1249 return (ENOTTY);
1250 }
1251
1252 return (0);
1253 }
1254
1255 int
1256 ccdsize(dev)
1257 dev_t dev;
1258 {
1259 struct ccd_softc *cs;
1260 struct disklabel *lp;
1261 int part, unit, omask, size;
1262
1263 unit = ccdunit(dev);
1264 if (unit >= numccd)
1265 return (-1);
1266 cs = &ccd_softc[unit];
1267
1268 if ((cs->sc_flags & CCDF_INITED) == 0)
1269 return (-1);
1270
1271 part = DISKPART(dev);
1272 omask = cs->sc_dkdev.dk_openmask & (1 << part);
1273 lp = cs->sc_dkdev.dk_label;
1274
1275 if (omask == 0 && ccdopen(dev, 0, S_IFBLK, curproc))
1276 return (-1);
1277
1278 if (lp->d_partitions[part].p_fstype != FS_SWAP)
1279 size = -1;
1280 else
1281 size = lp->d_partitions[part].p_size *
1282 (lp->d_secsize / DEV_BSIZE);
1283
1284 if (omask == 0 && ccdclose(dev, 0, S_IFBLK, curproc))
1285 return (-1);
1286
1287 return (size);
1288 }
1289
1290 int
1291 ccddump(dev, blkno, va, size)
1292 dev_t dev;
1293 daddr_t blkno;
1294 caddr_t va;
1295 size_t size;
1296 {
1297
1298 /* Not implemented. */
1299 return ENXIO;
1300 }
1301
1302 /*
1303 * Lookup the provided name in the filesystem. If the file exists,
1304 * is a valid block device, and isn't being used by anyone else,
1305 * set *vpp to the file's vnode.
1306 */
1307 static int
1308 ccdlookup(path, p, vpp)
1309 char *path;
1310 struct proc *p;
1311 struct vnode **vpp; /* result */
1312 {
1313 struct nameidata nd;
1314 struct vnode *vp;
1315 struct vattr va;
1316 int error;
1317
1318 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, path, p);
1319 if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) {
1320 #ifdef DEBUG
1321 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
1322 printf("ccdlookup: vn_open error = %d\n", error);
1323 #endif
1324 return (error);
1325 }
1326 vp = nd.ni_vp;
1327
1328 if (vp->v_usecount > 1) {
1329 VOP_UNLOCK(vp, 0);
1330 (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1331 return (EBUSY);
1332 }
1333
1334 if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) != 0) {
1335 #ifdef DEBUG
1336 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
1337 printf("ccdlookup: getattr error = %d\n", error);
1338 #endif
1339 VOP_UNLOCK(vp, 0);
1340 (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1341 return (error);
1342 }
1343
1344 /* XXX: eventually we should handle VREG, too. */
1345 if (va.va_type != VBLK) {
1346 VOP_UNLOCK(vp, 0);
1347 (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1348 return (ENOTBLK);
1349 }
1350
1351 #ifdef DEBUG
1352 if (ccddebug & CCDB_VNODE)
1353 vprint("ccdlookup: vnode info", vp);
1354 #endif
1355
1356 VOP_UNLOCK(vp, 0);
1357 *vpp = vp;
1358 return (0);
1359 }
1360
1361 static void
1362 ccdgetdefaultlabel(cs, lp)
1363 struct ccd_softc *cs;
1364 struct disklabel *lp;
1365 {
1366 struct ccdgeom *ccg = &cs->sc_geom;
1367
1368 bzero(lp, sizeof(*lp));
1369
1370 lp->d_secperunit = cs->sc_size;
1371 lp->d_secsize = ccg->ccg_secsize;
1372 lp->d_nsectors = ccg->ccg_nsectors;
1373 lp->d_ntracks = ccg->ccg_ntracks;
1374 lp->d_ncylinders = ccg->ccg_ncylinders;
1375 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1376
1377 strncpy(lp->d_typename, "ccd", sizeof(lp->d_typename));
1378 lp->d_type = DTYPE_CCD;
1379 strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
1380 lp->d_rpm = 3600;
1381 lp->d_interleave = 1;
1382 lp->d_flags = 0;
1383
1384 lp->d_partitions[RAW_PART].p_offset = 0;
1385 lp->d_partitions[RAW_PART].p_size = cs->sc_size;
1386 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
1387 lp->d_npartitions = RAW_PART + 1;
1388
1389 lp->d_magic = DISKMAGIC;
1390 lp->d_magic2 = DISKMAGIC;
1391 lp->d_checksum = dkcksum(cs->sc_dkdev.dk_label);
1392 }
1393
1394 /*
1395 * Read the disklabel from the ccd. If one is not present, fake one
1396 * up.
1397 */
1398 static void
1399 ccdgetdisklabel(dev)
1400 dev_t dev;
1401 {
1402 int unit = ccdunit(dev);
1403 struct ccd_softc *cs = &ccd_softc[unit];
1404 char *errstring;
1405 struct disklabel *lp = cs->sc_dkdev.dk_label;
1406 struct cpu_disklabel *clp = cs->sc_dkdev.dk_cpulabel;
1407
1408 bzero(clp, sizeof(*clp));
1409
1410 ccdgetdefaultlabel(cs, lp);
1411
1412 /*
1413 * Call the generic disklabel extraction routine.
1414 */
1415 errstring = readdisklabel(CCDLABELDEV(dev), ccdstrategy,
1416 cs->sc_dkdev.dk_label, cs->sc_dkdev.dk_cpulabel);
1417 if (errstring)
1418 ccdmakedisklabel(cs);
1419 else {
1420 int i;
1421 struct partition *pp;
1422
1423 /*
1424 * Sanity check whether the found disklabel is valid.
1425 *
1426 * This is necessary since total size of ccd may vary
1427 * when an interleave is changed even though exactly
1428 * same componets are used, and old disklabel may used
1429 * if that is found.
1430 */
1431 if (lp->d_secperunit != cs->sc_size)
1432 printf("WARNING: %s: "
1433 "total sector size in disklabel (%d) != "
1434 "the size of ccd (%d)\n", cs->sc_xname,
1435 lp->d_secperunit, cs->sc_size);
1436 for (i = 0; i < lp->d_npartitions; i++) {
1437 pp = &lp->d_partitions[i];
1438 if (pp->p_offset + pp->p_size > cs->sc_size)
1439 printf("WARNING: %s: end of partition `%c' "
1440 "exceeds the size of ccd (%d)\n",
1441 cs->sc_xname, 'a' + i, cs->sc_size);
1442 }
1443 }
1444
1445 #ifdef DEBUG
1446 /* It's actually extremely common to have unlabeled ccds. */
1447 if (ccddebug & CCDB_LABEL)
1448 if (errstring != NULL)
1449 printf("%s: %s\n", cs->sc_xname, errstring);
1450 #endif
1451 }
1452
1453 /*
1454 * Take care of things one might want to take care of in the event
1455 * that a disklabel isn't present.
1456 */
1457 static void
1458 ccdmakedisklabel(cs)
1459 struct ccd_softc *cs;
1460 {
1461 struct disklabel *lp = cs->sc_dkdev.dk_label;
1462
1463 /*
1464 * For historical reasons, if there's no disklabel present
1465 * the raw partition must be marked FS_BSDFFS.
1466 */
1467 lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS;
1468
1469 strncpy(lp->d_packname, "default label", sizeof(lp->d_packname));
1470
1471 lp->d_checksum = dkcksum(lp);
1472 }
1473
1474 /*
1475 * Wait interruptibly for an exclusive lock.
1476 *
1477 * XXX
1478 * Several drivers do this; it should be abstracted and made MP-safe.
1479 */
1480 static int
1481 ccdlock(cs)
1482 struct ccd_softc *cs;
1483 {
1484 int error;
1485
1486 while ((cs->sc_flags & CCDF_LOCKED) != 0) {
1487 cs->sc_flags |= CCDF_WANTED;
1488 if ((error = tsleep(cs, PRIBIO | PCATCH, "ccdlck", 0)) != 0)
1489 return (error);
1490 }
1491 cs->sc_flags |= CCDF_LOCKED;
1492 return (0);
1493 }
1494
1495 /*
1496 * Unlock and wake up any waiters.
1497 */
1498 static void
1499 ccdunlock(cs)
1500 struct ccd_softc *cs;
1501 {
1502
1503 cs->sc_flags &= ~CCDF_LOCKED;
1504 if ((cs->sc_flags & CCDF_WANTED) != 0) {
1505 cs->sc_flags &= ~CCDF_WANTED;
1506 wakeup(cs);
1507 }
1508 }
1509
1510 #ifdef DEBUG
1511 static void
1512 printiinfo(ii)
1513 struct ccdiinfo *ii;
1514 {
1515 register int ix, i;
1516
1517 for (ix = 0; ii->ii_ndisk; ix++, ii++) {
1518 printf(" itab[%d]: #dk %d sblk %d soff %d",
1519 ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff);
1520 for (i = 0; i < ii->ii_ndisk; i++)
1521 printf(" %d", ii->ii_index[i]);
1522 printf("\n");
1523 }
1524 }
1525 #endif
1526