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