ccd.c revision 1.19 1 /* $NetBSD: ccd.c,v 1.19 1995/10/12 21:28:32 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
665 #ifdef DEBUG
666 if (ccddebug & CCDB_FOLLOW)
667 printf("ccdstart(%x, %x)\n", cs, bp);
668 #endif
669
670 #ifdef WORKING_DISK_STATISTICS /* XXX !! */
671 /*
672 * Instrumentation (not very meaningful)
673 */
674 cs->sc_nactive++;
675 if (cs->sc_dk >= 0) {
676 dk_busy |= 1 << cs->sc_dk;
677 dk_xfer[cs->sc_dk]++;
678 dk_wds[cs->sc_dk] += bp->b_bcount >> 6;
679 }
680 #endif
681
682 /*
683 * Translate the partition-relative block number to an absolute.
684 */
685 bn = (bp->b_blkno +
686 cs->sc_dkdev.dk_label.d_partitions[DISKPART(bp->b_dev)].p_offset);
687
688 /*
689 * Allocate component buffers and fire off the requests
690 */
691 addr = bp->b_data;
692 for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) {
693 cbp = ccdbuffer(cs, bp, bn, addr, bcount);
694 rcount = cbp->cb_buf.b_bcount;
695 if ((cbp->cb_buf.b_flags & B_READ) == 0)
696 cbp->cb_buf.b_vp->v_numoutput++;
697 VOP_STRATEGY(&cbp->cb_buf);
698 bn += btodb(rcount);
699 addr += rcount;
700 }
701 }
702
703 /*
704 * Build a component buffer header.
705 */
706 static struct ccdbuf *
707 ccdbuffer(cs, bp, bn, addr, bcount)
708 register struct ccd_softc *cs;
709 struct buf *bp;
710 daddr_t bn;
711 caddr_t addr;
712 long bcount;
713 {
714 register struct ccdcinfo *ci;
715 register struct ccdbuf *cbp;
716 register daddr_t cbn, cboff;
717
718 #ifdef DEBUG
719 if (ccddebug & CCDB_IO)
720 printf("ccdbuffer(%x, %x, %d, %x, %d)\n",
721 cs, bp, bn, addr, bcount);
722 #endif
723 /*
724 * Determine which component bn falls in.
725 */
726 cbn = bn;
727 cboff = 0;
728
729 /*
730 * Serially concatenated
731 */
732 if (cs->sc_ileave == 0) {
733 register daddr_t sblk;
734
735 sblk = 0;
736 for (ci = cs->sc_cinfo; cbn >= sblk + ci->ci_size; ci++)
737 sblk += ci->ci_size;
738 cbn -= sblk;
739 }
740 /*
741 * Interleaved
742 */
743 else {
744 register struct ccdiinfo *ii;
745 int ccdisk, off;
746
747 cboff = cbn % cs->sc_ileave;
748 cbn /= cs->sc_ileave;
749 for (ii = cs->sc_itable; ii->ii_ndisk; ii++)
750 if (ii->ii_startblk > cbn)
751 break;
752 ii--;
753 off = cbn - ii->ii_startblk;
754 if (ii->ii_ndisk == 1) {
755 ccdisk = ii->ii_index[0];
756 cbn = ii->ii_startoff + off;
757 } else {
758 ccdisk = ii->ii_index[off % ii->ii_ndisk];
759 cbn = ii->ii_startoff + off / ii->ii_ndisk;
760 }
761 cbn *= cs->sc_ileave;
762 ci = &cs->sc_cinfo[ccdisk];
763 }
764
765 /*
766 * Fill in the component buf structure.
767 */
768 cbp = getccdbuf();
769 cbp->cb_buf.b_flags = bp->b_flags | B_CALL;
770 cbp->cb_buf.b_iodone = (void (*)())ccdiodone;
771 cbp->cb_buf.b_proc = bp->b_proc;
772 cbp->cb_buf.b_dev = ci->ci_dev; /* XXX */
773 cbp->cb_buf.b_blkno = cbn + cboff;
774 cbp->cb_buf.b_data = addr;
775 cbp->cb_buf.b_vp = ci->ci_vp;
776 if (cs->sc_ileave == 0)
777 cbp->cb_buf.b_bcount = dbtob(ci->ci_size - cbn);
778 else
779 cbp->cb_buf.b_bcount = dbtob(cs->sc_ileave - cboff);
780 if (cbp->cb_buf.b_bcount > bcount)
781 cbp->cb_buf.b_bcount = bcount;
782
783 /*
784 * context for ccdiodone
785 */
786 cbp->cb_obp = bp;
787 cbp->cb_unit = cs - ccd_softc;
788 cbp->cb_comp = ci - cs->sc_cinfo;
789
790 #ifdef DEBUG
791 if (ccddebug & CCDB_IO)
792 printf(" dev %x(u%d): cbp %x bn %d addr %x bcnt %d\n",
793 ci->ci_dev, ci-cs->sc_cinfo, cbp, cbp->cb_buf.b_blkno,
794 cbp->cb_buf.b_data, cbp->cb_buf.b_bcount);
795 #endif
796 return (cbp);
797 }
798
799 static void
800 ccdintr(cs, bp)
801 register struct ccd_softc *cs;
802 register struct buf *bp;
803 {
804
805 #ifdef DEBUG
806 if (ccddebug & CCDB_FOLLOW)
807 printf("ccdintr(%x, %x)\n", cs, bp);
808 #endif
809 /*
810 * Request is done for better or worse, wakeup the top half.
811 */
812 #ifdef WORKING_DISK_STATISTICS /* XXX !! */
813 --cs->sc_nactive;
814 #ifdef DIAGNOSTIC
815 if (cs->sc_nactive < 0)
816 panic("ccdintr: ccd%d: sc_nactive < 0", cs->sc_unit);
817 #endif
818
819 if (cs->sc_nactive == 0 && cs->sc_dk >= 0)
820 dk_busy &= ~(1 << cs->sc_dk);
821 #endif
822 if (bp->b_flags & B_ERROR)
823 bp->b_resid = bp->b_bcount;
824 biodone(bp);
825 }
826
827 /*
828 * Called at interrupt time.
829 * Mark the component as done and if all components are done,
830 * take a ccd interrupt.
831 */
832 void
833 ccdiodone(cbp)
834 struct ccdbuf *cbp;
835 {
836 register struct buf *bp = cbp->cb_obp;
837 register int unit = cbp->cb_unit;
838 int count, s;
839
840 s = splbio();
841 #ifdef DEBUG
842 if (ccddebug & CCDB_FOLLOW)
843 printf("ccdiodone(%x)\n", cbp);
844 if (ccddebug & CCDB_IO) {
845 printf("ccdiodone: bp %x bcount %d resid %d\n",
846 bp, bp->b_bcount, bp->b_resid);
847 printf(" dev %x(u%d), cbp %x bn %d addr %x bcnt %d\n",
848 cbp->cb_buf.b_dev, cbp->cb_comp, cbp,
849 cbp->cb_buf.b_blkno, cbp->cb_buf.b_data,
850 cbp->cb_buf.b_bcount);
851 }
852 #endif
853
854 if (cbp->cb_buf.b_flags & B_ERROR) {
855 bp->b_flags |= B_ERROR;
856 bp->b_error = cbp->cb_buf.b_error ? cbp->cb_buf.b_error : EIO;
857 #ifdef DEBUG
858 printf("ccd%d: error %d on component %d\n",
859 unit, bp->b_error, cbp->cb_comp);
860 #endif
861 }
862 count = cbp->cb_buf.b_bcount;
863 putccdbuf(cbp);
864
865 /*
866 * If all done, "interrupt".
867 */
868 bp->b_resid -= count;
869 if (bp->b_resid < 0)
870 panic("ccdiodone: count");
871 if (bp->b_resid == 0)
872 ccdintr(&ccd_softc[unit], bp);
873 splx(s);
874 }
875
876 /* ARGSUSED */
877 int
878 ccdread(dev, uio, flags)
879 dev_t dev;
880 struct uio *uio;
881 int flags;
882 {
883 int unit = ccdunit(dev);
884 struct ccd_softc *cs;
885
886 #ifdef DEBUG
887 if (ccddebug & CCDB_FOLLOW)
888 printf("ccdread(%x, %x)\n", dev, uio);
889 #endif
890 if (unit >= numccd)
891 return (ENXIO);
892 cs = &ccd_softc[unit];
893
894 if ((cs->sc_flags & CCDF_INITED) == 0)
895 return (ENXIO);
896
897 /*
898 * XXX: It's not clear that using minphys() is completely safe,
899 * in particular, for raw I/O. Underlying devices might have some
900 * non-obvious limits, because of the copy to user-space.
901 */
902 return (physio(ccdstrategy, NULL, dev, B_READ, minphys, uio));
903 }
904
905 /* ARGSUSED */
906 int
907 ccdwrite(dev, uio, flags)
908 dev_t dev;
909 struct uio *uio;
910 int flags;
911 {
912 int unit = ccdunit(dev);
913 struct ccd_softc *cs;
914
915 #ifdef DEBUG
916 if (ccddebug & CCDB_FOLLOW)
917 printf("ccdwrite(%x, %x)\n", dev, uio);
918 #endif
919 if (unit >= numccd)
920 return (ENXIO);
921 cs = &ccd_softc[unit];
922
923 if ((cs->sc_flags & CCDF_INITED) == 0)
924 return (ENXIO);
925
926 /*
927 * XXX: It's not clear that using minphys() is completely safe,
928 * in particular, for raw I/O. Underlying devices might have some
929 * non-obvious limits, because of the copy to user-space.
930 */
931 return (physio(ccdstrategy, NULL, dev, B_WRITE, minphys, uio));
932 }
933
934 int
935 ccdioctl(dev, cmd, data, flag, p)
936 dev_t dev;
937 u_long cmd;
938 caddr_t data;
939 int flag;
940 struct proc *p;
941 {
942 int unit = ccdunit(dev);
943 int i, j, lookedup = 0, error = 0;
944 int part, pmask;
945 struct ccd_softc *cs;
946 struct ccd_ioctl *ccio = (struct ccd_ioctl *)data;
947 struct ccddevice ccd;
948 char **cpp;
949 struct vnode **vpp;
950 #ifdef WORKING_DISK_STATISTICS /* XXX !! */
951 extern int dkn;
952 #endif
953
954 if (unit >= numccd)
955 return (ENXIO);
956 cs = &ccd_softc[unit];
957
958 bzero(&ccd, sizeof(ccd));
959
960 switch (cmd) {
961 case CCDIOCSET:
962 if (cs->sc_flags & CCDF_INITED)
963 return (EBUSY);
964
965 if ((flag & FWRITE) == 0)
966 return (EBADF);
967
968 if (error = ccdlock(cs))
969 return (error);
970
971 /* Fill in some important bits. */
972 ccd.ccd_unit = unit;
973 ccd.ccd_interleave = ccio->ccio_ileave;
974 ccd.ccd_flags = ccio->ccio_flags & CCDF_USERMASK;
975
976 /*
977 * Allocate space for and copy in the array of
978 * componet pathnames and device numbers.
979 */
980 cpp = malloc(ccio->ccio_ndisks * sizeof(char *),
981 M_DEVBUF, M_WAITOK);
982 vpp = malloc(ccio->ccio_ndisks * sizeof(struct vnode *),
983 M_DEVBUF, M_WAITOK);
984
985 error = copyin((caddr_t)ccio->ccio_disks, (caddr_t)cpp,
986 ccio->ccio_ndisks * sizeof(char **));
987 if (error) {
988 free(vpp, M_DEVBUF);
989 free(cpp, M_DEVBUF);
990 ccdunlock(cs);
991 return (error);
992 }
993
994 #ifdef DEBUG
995 if (ccddebug & CCDB_INIT)
996 for (i = 0; i < ccio->ccio_ndisks; ++i)
997 printf("ccdioctl: component %d: 0x%x\n",
998 i, cpp[i]);
999 #endif
1000
1001 for (i = 0; i < ccio->ccio_ndisks; ++i) {
1002 #ifdef DEBUG
1003 if (ccddebug & CCDB_INIT)
1004 printf("ccdioctl: lookedup = %d\n", lookedup);
1005 #endif
1006 if (error = ccdlookup(cpp[i], p, &vpp[i])) {
1007 for (j = 0; j < lookedup; ++j)
1008 (void)vn_close(vpp[j], FREAD|FWRITE,
1009 p->p_ucred, p);
1010 free(vpp, M_DEVBUF);
1011 free(cpp, M_DEVBUF);
1012 ccdunlock(cs);
1013 return (error);
1014 }
1015 ++lookedup;
1016 }
1017 ccd.ccd_cpp = cpp;
1018 ccd.ccd_vpp = vpp;
1019 ccd.ccd_ndev = ccio->ccio_ndisks;
1020
1021 #ifdef WORKING_DISK_STATISTICS /* XXX !! */
1022 /*
1023 * Assign disk index first so that init routine
1024 * can use it (saves having the driver drag around
1025 * the ccddevice pointer just to set up the dk_*
1026 * info in the open routine).
1027 */
1028 if (dkn < DK_NDRIVE)
1029 ccd.ccd_dk = dkn++;
1030 else
1031 ccd.ccd_dk = -1;
1032 #endif
1033
1034 /*
1035 * Initialize the ccd. Fills in the softc for us.
1036 */
1037 if (error = ccdinit(&ccd, cpp, p)) {
1038 #ifdef WORKING_DISK_STATISTICS /* XXX !! */
1039 if (ccd.ccd_dk >= 0)
1040 --dkn;
1041 #endif
1042 for (j = 0; j < lookedup; ++j)
1043 (void)vn_close(vpp[j], FREAD|FWRITE,
1044 p->p_ucred, p);
1045 bzero(&ccd_softc[unit], sizeof(struct ccd_softc));
1046 free(vpp, M_DEVBUF);
1047 free(cpp, M_DEVBUF);
1048 ccdunlock(cs);
1049 return (error);
1050 }
1051
1052 /*
1053 * The ccd has been successfully initialized, so
1054 * we can place it into the array and read the disklabel.
1055 */
1056 bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1057 ccio->ccio_unit = unit;
1058 ccio->ccio_size = cs->sc_size;
1059 ccdgetdisklabel(dev);
1060
1061 ccdunlock(cs);
1062
1063 break;
1064
1065 case CCDIOCCLR:
1066 if ((cs->sc_flags & CCDF_INITED) == 0)
1067 return (ENXIO);
1068
1069 if ((flag & FWRITE) == 0)
1070 return (EBADF);
1071
1072 if (error = ccdlock(cs))
1073 return (error);
1074
1075 /*
1076 * Don't unconfigure if any other partitions are open
1077 * or if both the character and block flavors of this
1078 * partition are open.
1079 */
1080 part = DISKPART(dev);
1081 pmask = (1 << part);
1082 if ((cs->sc_dkdev.dk_openmask & ~pmask) ||
1083 ((cs->sc_dkdev.dk_bopenmask & pmask) &&
1084 (cs->sc_dkdev.dk_copenmask & pmask))) {
1085 ccdunlock(cs);
1086 return (EBUSY);
1087 }
1088
1089 /*
1090 * Free ccd_softc information and clear entry.
1091 */
1092 for (i = 0; i < cs->sc_nccdisks; ++i) {
1093 /*
1094 * XXX: this close could potentially fail and
1095 * cause Bad Things. Maybe we need to force
1096 * the close to happen?
1097 */
1098 #ifdef DEBUG
1099 if (ccddebug & CCDB_VNODE)
1100 vprint("CCDIOCCLR: vnode info",
1101 cs->sc_cinfo[i].ci_vp);
1102 #endif
1103 (void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE,
1104 p->p_ucred, p);
1105 free(cs->sc_cinfo[i].ci_path, M_DEVBUF);
1106 free(cs->sc_itable[i].ii_index, M_DEVBUF);
1107 }
1108 free(cs->sc_cinfo, M_DEVBUF);
1109 free(cs->sc_itable, M_DEVBUF);
1110 bzero(cs, sizeof(struct ccd_softc));
1111
1112 /*
1113 * Free ccddevice information and clear entry.
1114 */
1115 free(ccddevs[unit].ccd_cpp, M_DEVBUF);
1116 free(ccddevs[unit].ccd_vpp, M_DEVBUF);
1117 ccd.ccd_dk = -1;
1118 bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1119
1120 ccdunlock(cs);
1121
1122 break;
1123
1124 case DIOCGDINFO:
1125 if ((cs->sc_flags & CCDF_INITED) == 0)
1126 return (ENXIO);
1127
1128 *(struct disklabel *)data = cs->sc_dkdev.dk_label;
1129 break;
1130
1131 case DIOCGPART:
1132 if ((cs->sc_flags & CCDF_INITED) == 0)
1133 return (ENXIO);
1134
1135 ((struct partinfo *)data)->disklab = &cs->sc_dkdev.dk_label;
1136 ((struct partinfo *)data)->part =
1137 &cs->sc_dkdev.dk_label.d_partitions[DISKPART(dev)];
1138 break;
1139
1140 case DIOCWDINFO:
1141 case DIOCSDINFO:
1142 if ((cs->sc_flags & CCDF_INITED) == 0)
1143 return (ENXIO);
1144
1145 if ((flag & FWRITE) == 0)
1146 return (EBADF);
1147
1148 if (error = ccdlock(cs))
1149 return (error);
1150
1151 cs->sc_flags |= CCDF_LABELLING;
1152
1153 error = setdisklabel(&cs->sc_dkdev.dk_label,
1154 (struct disklabel *)data, 0, &cs->sc_dkdev.dk_cpulabel);
1155 if (error == 0) {
1156 if (cmd == DIOCWDINFO)
1157 error = writedisklabel(CCDLABELDEV(dev),
1158 ccdstrategy, &cs->sc_dkdev.dk_label,
1159 &cs->sc_dkdev.dk_cpulabel);
1160 }
1161
1162 cs->sc_flags &= ~CCDF_LABELLING;
1163
1164 ccdunlock(cs);
1165
1166 if (error)
1167 return (error);
1168 break;
1169
1170 case DIOCWLABEL:
1171 if ((cs->sc_flags & CCDF_INITED) == 0)
1172 return (ENXIO);
1173
1174 if ((flag & FWRITE) == 0)
1175 return (EBADF);
1176 if (*(int *)data != 0)
1177 cs->sc_flags |= CCDF_WLABEL;
1178 else
1179 cs->sc_flags &= ~CCDF_WLABEL;
1180 break;
1181
1182 default:
1183 return (ENOTTY);
1184 }
1185
1186 return (0);
1187 }
1188
1189 int
1190 ccdsize(dev)
1191 dev_t dev;
1192 {
1193 struct ccd_softc *cs;
1194 int part, size;
1195
1196 if (ccdopen(dev, 0, S_IFBLK, curproc))
1197 return (-1);
1198
1199 cs = &ccd_softc[ccdunit(dev)];
1200 part = DISKPART(dev);
1201
1202 if ((cs->sc_flags & CCDF_INITED) == 0)
1203 return (-1);
1204
1205 if (cs->sc_dkdev.dk_label.d_partitions[part].p_fstype != FS_SWAP)
1206 size = -1;
1207 else
1208 size = cs->sc_dkdev.dk_label.d_partitions[part].p_size;
1209
1210 if (ccdclose(dev, 0, S_IFBLK, curproc))
1211 return (-1);
1212
1213 return (size);
1214 }
1215
1216 int
1217 ccddump(dev, blkno, va, size)
1218 dev_t dev;
1219 daddr_t blkno;
1220 caddr_t va;
1221 size_t size;
1222 {
1223
1224 /* Not implemented. */
1225 return ENXIO;
1226 }
1227
1228 /*
1229 * Lookup the provided name in the filesystem. If the file exists,
1230 * is a valid block device, and isn't being used by anyone else,
1231 * set *vpp to the file's vnode.
1232 */
1233 static int
1234 ccdlookup(path, p, vpp)
1235 char *path;
1236 struct proc *p;
1237 struct vnode **vpp; /* result */
1238 {
1239 struct nameidata nd;
1240 struct vnode *vp;
1241 struct vattr va;
1242 int error;
1243
1244 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, path, p);
1245 if (error = vn_open(&nd, FREAD|FWRITE, 0)) {
1246 #ifdef DEBUG
1247 if (ccddebug & CCDB_FOLLOW|CCDB_INIT)
1248 printf("ccdlookup: vn_open error = %d\n", error);
1249 #endif
1250 return (error);
1251 }
1252 vp = nd.ni_vp;
1253
1254 if (vp->v_usecount > 1) {
1255 VOP_UNLOCK(vp);
1256 (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1257 return (EBUSY);
1258 }
1259
1260 if (error = VOP_GETATTR(vp, &va, p->p_ucred, p)) {
1261 #ifdef DEBUG
1262 if (ccddebug & CCDB_FOLLOW|CCDB_INIT)
1263 printf("ccdlookup: getattr error = %d\n", error);
1264 #endif
1265 VOP_UNLOCK(vp);
1266 (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1267 return (error);
1268 }
1269
1270 /* XXX: eventually we should handle VREG, too. */
1271 if (va.va_type != VBLK) {
1272 VOP_UNLOCK(vp);
1273 (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1274 return (ENOTBLK);
1275 }
1276
1277 #ifdef DEBUG
1278 if (ccddebug & CCDB_VNODE)
1279 vprint("ccdlookup: vnode info", vp);
1280 #endif
1281
1282 VOP_UNLOCK(vp);
1283 *vpp = vp;
1284 return (0);
1285 }
1286
1287 /*
1288 * Read the disklabel from the ccd. If one is not present, fake one
1289 * up.
1290 */
1291 static void
1292 ccdgetdisklabel(dev)
1293 dev_t dev;
1294 {
1295 int unit = ccdunit(dev);
1296 struct ccd_softc *cs = &ccd_softc[unit];
1297 char *errstring;
1298 struct disklabel *lp = &cs->sc_dkdev.dk_label;
1299 struct cpu_disklabel *clp = &cs->sc_dkdev.dk_cpulabel;
1300 struct ccdgeom *ccg = &cs->sc_geom;
1301
1302 bzero(lp, sizeof(*lp));
1303 bzero(clp, sizeof(*clp));
1304
1305 lp->d_secperunit = cs->sc_size;
1306 lp->d_secsize = ccg->ccg_secsize;
1307 lp->d_nsectors = ccg->ccg_nsectors;
1308 lp->d_ntracks = ccg->ccg_ntracks;
1309 lp->d_ncylinders = ccg->ccg_ncylinders;
1310 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1311
1312 strncpy(lp->d_typename, "ccd", sizeof(lp->d_typename));
1313 lp->d_type = DTYPE_CCD;
1314 strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
1315 lp->d_rpm = 3600;
1316 lp->d_interleave = 1;
1317 lp->d_flags = 0;
1318
1319 lp->d_partitions[RAW_PART].p_offset = 0;
1320 lp->d_partitions[RAW_PART].p_size = cs->sc_size;
1321 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
1322 lp->d_npartitions = RAW_PART + 1;
1323
1324 lp->d_magic = DISKMAGIC;
1325 lp->d_magic2 = DISKMAGIC;
1326 lp->d_checksum = dkcksum(&cs->sc_dkdev.dk_label);
1327
1328 /*
1329 * Call the generic disklabel extraction routine.
1330 */
1331 if (errstring = readdisklabel(CCDLABELDEV(dev), ccdstrategy,
1332 &cs->sc_dkdev.dk_label, &cs->sc_dkdev.dk_cpulabel))
1333 ccdmakedisklabel(cs);
1334
1335 #ifdef DEBUG
1336 /* It's actually extremely common to have unlabeled ccds. */
1337 if (ccddebug & CCDB_LABEL)
1338 if (errstring != NULL)
1339 printf("ccd%d: %s\n", unit, errstring);
1340 #endif
1341 }
1342
1343 /*
1344 * Take care of things one might want to take care of in the event
1345 * that a disklabel isn't present.
1346 */
1347 static void
1348 ccdmakedisklabel(cs)
1349 struct ccd_softc *cs;
1350 {
1351 struct disklabel *lp = &cs->sc_dkdev.dk_label;
1352
1353 /*
1354 * For historical reasons, if there's no disklabel present
1355 * the raw partition must be marked FS_BSDFFS.
1356 */
1357 lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS;
1358
1359 strncpy(lp->d_packname, "default label", sizeof(lp->d_packname));
1360 }
1361
1362 /*
1363 * Wait interruptibly for an exclusive lock.
1364 *
1365 * XXX
1366 * Several drivers do this; it should be abstracted and made MP-safe.
1367 */
1368 static int
1369 ccdlock(cs)
1370 struct ccd_softc *cs;
1371 {
1372 int error;
1373
1374 while ((cs->sc_flags & CCDF_LOCKED) != 0) {
1375 cs->sc_flags |= CCDF_WANTED;
1376 if ((error = tsleep(cs, PRIBIO | PCATCH, "ccdlck", 0)) != 0)
1377 return (error);
1378 }
1379 cs->sc_flags |= CCDF_LOCKED;
1380 return (0);
1381 }
1382
1383 /*
1384 * Unlock and wake up any waiters.
1385 */
1386 static void
1387 ccdunlock(cs)
1388 struct ccd_softc *cs;
1389 {
1390
1391 cs->sc_flags &= ~CCDF_LOCKED;
1392 if ((cs->sc_flags & CCDF_WANTED) != 0) {
1393 cs->sc_flags &= ~CCDF_WANTED;
1394 wakeup(cs);
1395 }
1396 }
1397
1398 #ifdef DEBUG
1399 static void
1400 printiinfo(ii)
1401 struct ccdiinfo *ii;
1402 {
1403 register int ix, i;
1404
1405 for (ix = 0; ii->ii_ndisk; ix++, ii++) {
1406 printf(" itab[%d]: #dk %d sblk %d soff %d",
1407 ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff);
1408 for (i = 0; i < ii->ii_ndisk; i++)
1409 printf(" %d", ii->ii_index[i]);
1410 printf("\n");
1411 }
1412 }
1413 #endif
1414