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