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