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