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