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