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