File:
[DragonFly] /
src /
sys /
dev /
disk /
ccd /
ccd.c
Revision
1.15:
download - view:
text,
annotated -
select for diffs
Thu May 13 23:49:15 2004 UTC (9 years ago) by
dillon
Branches:
MAIN
CVS tags:
HEAD
device switch 1/many: Remove d_autoq, add d_clone (where d_autoq was).
d_autoq was used to allow the device port dispatch to mix old-style synchronous
calls with new style messaging calls within a particular device. It was never
used for that purpose.
d_clone will be more fully implemented as work continues. We are going to
install d_port in the dev_t (struct specinfo) structure itself and d_clone
will be needed to allow devices to 'revector' the port on a minor-number
by minor-number basis, in particular allowing minor numbers to be directly
dispatched to distinct threads. This is something we will be needing later
on.
1: /* $FreeBSD: src/sys/dev/ccd/ccd.c,v 1.73.2.1 2001/09/11 09:49:52 kris Exp $ */
2: /* $DragonFly: src/sys/dev/disk/ccd/ccd.c,v 1.15 2004/05/13 23:49:15 dillon Exp $ */
3:
4: /* $NetBSD: ccd.c,v 1.22 1995/12/08 19:13:26 thorpej Exp $ */
5:
6: /*
7: * Copyright (c) 1995 Jason R. Thorpe.
8: * All rights reserved.
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 for the NetBSD Project
21: * by Jason R. Thorpe.
22: * 4. The name of the author may not be used to endorse or promote products
23: * derived from this software without specific prior written permission.
24: *
25: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
29: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30: * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
32: * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35: * SUCH DAMAGE.
36: */
37:
38: /*
39: * Copyright (c) 1988 University of Utah.
40: * Copyright (c) 1990, 1993
41: * The Regents of the University of California. All rights reserved.
42: *
43: * This code is derived from software contributed to Berkeley by
44: * the Systems Programming Group of the University of Utah Computer
45: * Science Department.
46: *
47: * Redistribution and use in source and binary forms, with or without
48: * modification, are permitted provided that the following conditions
49: * are met:
50: * 1. Redistributions of source code must retain the above copyright
51: * notice, this list of conditions and the following disclaimer.
52: * 2. Redistributions in binary form must reproduce the above copyright
53: * notice, this list of conditions and the following disclaimer in the
54: * documentation and/or other materials provided with the distribution.
55: * 3. All advertising materials mentioning features or use of this software
56: * must display the following acknowledgement:
57: * This product includes software developed by the University of
58: * California, Berkeley and its contributors.
59: * 4. 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:
91: #include "use_ccd.h"
92:
93: #include <sys/param.h>
94: #include <sys/systm.h>
95: #include <sys/kernel.h>
96: #include <sys/module.h>
97: #include <sys/proc.h>
98: #include <sys/buf.h>
99: #include <sys/malloc.h>
100: #include <sys/namei.h>
101: #include <sys/conf.h>
102: #include <sys/stat.h>
103: #include <sys/sysctl.h>
104: #include <sys/disklabel.h>
105: #include <vfs/ufs/fs.h>
106: #include <sys/devicestat.h>
107: #include <sys/fcntl.h>
108: #include <sys/vnode.h>
109: #include <sys/buf2.h>
110:
111: #include <sys/ccdvar.h>
112:
113: #include <vm/vm_zone.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: static int ccddebug = CCDB_FOLLOW | CCDB_INIT | CCDB_IO | CCDB_LABEL |
126: CCDB_VNODE;
127: SYSCTL_INT(_debug, OID_AUTO, ccddebug, CTLFLAG_RW, &ccddebug, 0, "");
128: #undef DEBUG
129: #endif
130:
131: #define ccdunit(x) dkunit(x)
132: #define ccdpart(x) dkpart(x)
133:
134: /*
135: This is how mirroring works (only writes are special):
136:
137: When initiating a write, ccdbuffer() returns two "struct ccdbuf *"s
138: linked together by the cb_mirror field. "cb_pflags &
139: CCDPF_MIRROR_DONE" is set to 0 on both of them.
140:
141: When a component returns to ccdiodone(), it checks if "cb_pflags &
142: CCDPF_MIRROR_DONE" is set or not. If not, it sets the partner's
143: flag and returns. If it is, it means its partner has already
144: returned, so it will go to the regular cleanup.
145:
146: */
147:
148: struct ccdbuf {
149: struct buf cb_buf; /* new I/O buf */
150: struct buf *cb_obp; /* ptr. to original I/O buf */
151: struct ccdbuf *cb_freenext; /* free list link */
152: int cb_unit; /* target unit */
153: int cb_comp; /* target component */
154: int cb_pflags; /* mirror/parity status flag */
155: struct ccdbuf *cb_mirror; /* mirror counterpart */
156: };
157:
158: /* bits in cb_pflags */
159: #define CCDPF_MIRROR_DONE 1 /* if set, mirror counterpart is done */
160:
161: #define CCDLABELDEV(dev) \
162: (makedev(major((dev)), dkmakeminor(ccdunit((dev)), 0, RAW_PART)))
163:
164: static d_open_t ccdopen;
165: static d_close_t ccdclose;
166: static d_strategy_t ccdstrategy;
167: static d_ioctl_t ccdioctl;
168: static d_dump_t ccddump;
169: static d_psize_t ccdsize;
170:
171: #define NCCDFREEHIWAT 16
172:
173: #define CDEV_MAJOR 74
174:
175: static struct cdevsw ccd_cdevsw = {
176: /* name */ "ccd",
177: /* maj */ CDEV_MAJOR,
178: /* flags */ D_DISK,
179: /* port */ NULL,
180: /* clone */ NULL,
181:
182: /* open */ ccdopen,
183: /* close */ ccdclose,
184: /* read */ physread,
185: /* write */ physwrite,
186: /* ioctl */ ccdioctl,
187: /* poll */ nopoll,
188: /* mmap */ nommap,
189: /* strategy */ ccdstrategy,
190: /* dump */ ccddump,
191: /* psize */ ccdsize
192: };
193:
194: /* called during module initialization */
195: static void ccdattach (void);
196: static int ccd_modevent (module_t, int, void *);
197:
198: /* called by biodone() at interrupt time */
199: static void ccdiodone (struct ccdbuf *cbp);
200:
201: static void ccdstart (struct ccd_softc *, struct buf *);
202: static void ccdinterleave (struct ccd_softc *, int);
203: static void ccdintr (struct ccd_softc *, struct buf *);
204: static int ccdinit (struct ccddevice *, char **, struct thread *);
205: static int ccdlookup (char *, struct thread *td, struct vnode **);
206: static void ccdbuffer (struct ccdbuf **ret, struct ccd_softc *,
207: struct buf *, daddr_t, caddr_t, long);
208: static void ccdgetdisklabel (dev_t);
209: static void ccdmakedisklabel (struct ccd_softc *);
210: static int ccdlock (struct ccd_softc *);
211: static void ccdunlock (struct ccd_softc *);
212:
213: #ifdef DEBUG
214: static void printiinfo (struct ccdiinfo *);
215: #endif
216:
217: /* Non-private for the benefit of libkvm. */
218: struct ccd_softc *ccd_softc;
219: struct ccddevice *ccddevs;
220: struct ccdbuf *ccdfreebufs;
221: static int numccdfreebufs;
222: static int numccd = 0;
223:
224: /*
225: * getccdbuf() - Allocate and zero a ccd buffer.
226: *
227: * This routine is called at splbio().
228: */
229:
230: static __inline
231: struct ccdbuf *
232: getccdbuf(struct ccdbuf *cpy)
233: {
234: struct ccdbuf *cbp;
235:
236: /*
237: * Allocate from freelist or malloc as necessary
238: */
239: if ((cbp = ccdfreebufs) != NULL) {
240: ccdfreebufs = cbp->cb_freenext;
241: --numccdfreebufs;
242: } else {
243: cbp = malloc(sizeof(struct ccdbuf), M_DEVBUF, M_WAITOK);
244: }
245:
246: /*
247: * Used by mirroring code
248: */
249: if (cpy)
250: bcopy(cpy, cbp, sizeof(struct ccdbuf));
251: else
252: bzero(cbp, sizeof(struct ccdbuf));
253:
254: /*
255: * independant struct buf initialization
256: */
257: LIST_INIT(&cbp->cb_buf.b_dep);
258: BUF_LOCKINIT(&cbp->cb_buf);
259: BUF_LOCK(&cbp->cb_buf, LK_EXCLUSIVE);
260: BUF_KERNPROC(&cbp->cb_buf);
261:
262: return(cbp);
263: }
264:
265: /*
266: * putccdbuf() - Free a ccd buffer.
267: *
268: * This routine is called at splbio().
269: */
270:
271: static __inline
272: void
273: putccdbuf(struct ccdbuf *cbp)
274: {
275: BUF_UNLOCK(&cbp->cb_buf);
276: BUF_LOCKFREE(&cbp->cb_buf);
277:
278: if (numccdfreebufs < NCCDFREEHIWAT) {
279: cbp->cb_freenext = ccdfreebufs;
280: ccdfreebufs = cbp;
281: ++numccdfreebufs;
282: } else {
283: free((caddr_t)cbp, M_DEVBUF);
284: }
285: }
286:
287:
288: /*
289: * Number of blocks to untouched in front of a component partition.
290: * This is to avoid violating its disklabel area when it starts at the
291: * beginning of the slice.
292: */
293: #if !defined(CCD_OFFSET)
294: #define CCD_OFFSET 16
295: #endif
296:
297: /*
298: * Called by main() during pseudo-device attachment. All we need
299: * to do is allocate enough space for devices to be configured later, and
300: * add devsw entries.
301: */
302: static void
303: ccdattach()
304: {
305: int i;
306: int num = NCCD;
307:
308: if (num > 1)
309: printf("ccd0-%d: Concatenated disk drivers\n", num-1);
310: else
311: printf("ccd0: Concatenated disk driver\n");
312:
313: ccd_softc = malloc(num * sizeof(struct ccd_softc), M_DEVBUF,
314: M_WAITOK | M_ZERO);
315: ccddevs = malloc(num * sizeof(struct ccddevice), M_DEVBUF,
316: M_WAITOK | M_ZERO);
317: numccd = num;
318:
319: cdevsw_add(&ccd_cdevsw);
320: /* XXX: is this necessary? */
321: for (i = 0; i < numccd; ++i)
322: ccddevs[i].ccd_dk = -1;
323: }
324:
325: static int
326: ccd_modevent(mod, type, data)
327: module_t mod;
328: int type;
329: void *data;
330: {
331: int error = 0;
332:
333: switch (type) {
334: case MOD_LOAD:
335: ccdattach();
336: break;
337:
338: case MOD_UNLOAD:
339: printf("ccd0: Unload not supported!\n");
340: error = EOPNOTSUPP;
341: break;
342:
343: default: /* MOD_SHUTDOWN etc */
344: break;
345: }
346: return (error);
347: }
348:
349: DEV_MODULE(ccd, ccd_modevent, NULL);
350:
351: static int
352: ccdinit(struct ccddevice *ccd, char **cpaths, struct thread *td)
353: {
354: struct ccd_softc *cs = &ccd_softc[ccd->ccd_unit];
355: struct ccdcinfo *ci = NULL; /* XXX */
356: size_t size;
357: int ix;
358: struct vnode *vp;
359: size_t minsize;
360: int maxsecsize;
361: struct partinfo dpart;
362: struct ccdgeom *ccg = &cs->sc_geom;
363: char tmppath[MAXPATHLEN];
364: int error = 0;
365: struct ucred *cred;
366:
367: KKASSERT(td->td_proc);
368: cred = td->td_proc->p_ucred;
369:
370: #ifdef DEBUG
371: if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
372: printf("ccdinit: unit %d\n", ccd->ccd_unit);
373: #endif
374:
375: cs->sc_size = 0;
376: cs->sc_ileave = ccd->ccd_interleave;
377: cs->sc_nccdisks = ccd->ccd_ndev;
378:
379: /* Allocate space for the component info. */
380: cs->sc_cinfo = malloc(cs->sc_nccdisks * sizeof(struct ccdcinfo),
381: M_DEVBUF, M_WAITOK);
382:
383: /*
384: * Verify that each component piece exists and record
385: * relevant information about it.
386: */
387: maxsecsize = 0;
388: minsize = 0;
389: for (ix = 0; ix < cs->sc_nccdisks; ix++) {
390: vp = ccd->ccd_vpp[ix];
391: ci = &cs->sc_cinfo[ix];
392: ci->ci_vp = vp;
393:
394: /*
395: * Copy in the pathname of the component.
396: */
397: bzero(tmppath, sizeof(tmppath)); /* sanity */
398: if ((error = copyinstr(cpaths[ix], tmppath,
399: MAXPATHLEN, &ci->ci_pathlen)) != 0) {
400: #ifdef DEBUG
401: if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
402: printf("ccd%d: can't copy path, error = %d\n",
403: ccd->ccd_unit, error);
404: #endif
405: goto fail;
406: }
407: ci->ci_path = malloc(ci->ci_pathlen, M_DEVBUF, M_WAITOK);
408: bcopy(tmppath, ci->ci_path, ci->ci_pathlen);
409:
410: ci->ci_dev = vn_todev(vp);
411:
412: /*
413: * Get partition information for the component.
414: */
415: if ((error = VOP_IOCTL(vp, DIOCGPART, (caddr_t)&dpart,
416: FREAD, cred, td)) != 0) {
417: #ifdef DEBUG
418: if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
419: printf("ccd%d: %s: ioctl failed, error = %d\n",
420: ccd->ccd_unit, ci->ci_path, error);
421: #endif
422: goto fail;
423: }
424: if (dpart.part->p_fstype == FS_BSDFFS) {
425: maxsecsize =
426: ((dpart.disklab->d_secsize > maxsecsize) ?
427: dpart.disklab->d_secsize : maxsecsize);
428: size = dpart.part->p_size - CCD_OFFSET;
429: } else {
430: #ifdef DEBUG
431: if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
432: printf("ccd%d: %s: incorrect partition type\n",
433: ccd->ccd_unit, ci->ci_path);
434: #endif
435: error = EFTYPE;
436: goto fail;
437: }
438:
439: /*
440: * Calculate the size, truncating to an interleave
441: * boundary if necessary.
442: */
443:
444: if (cs->sc_ileave > 1)
445: size -= size % cs->sc_ileave;
446:
447: if (size == 0) {
448: #ifdef DEBUG
449: if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
450: printf("ccd%d: %s: size == 0\n",
451: ccd->ccd_unit, ci->ci_path);
452: #endif
453: error = ENODEV;
454: goto fail;
455: }
456:
457: if (minsize == 0 || size < minsize)
458: minsize = size;
459: ci->ci_size = size;
460: cs->sc_size += size;
461: }
462:
463: /*
464: * Don't allow the interleave to be smaller than
465: * the biggest component sector.
466: */
467: if ((cs->sc_ileave > 0) &&
468: (cs->sc_ileave < (maxsecsize / DEV_BSIZE))) {
469: #ifdef DEBUG
470: if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
471: printf("ccd%d: interleave must be at least %d\n",
472: ccd->ccd_unit, (maxsecsize / DEV_BSIZE));
473: #endif
474: error = EINVAL;
475: goto fail;
476: }
477:
478: /*
479: * If uniform interleave is desired set all sizes to that of
480: * the smallest component. This will guarentee that a single
481: * interleave table is generated.
482: *
483: * Lost space must be taken into account when calculating the
484: * overall size. Half the space is lost when CCDF_MIRROR is
485: * specified. One disk is lost when CCDF_PARITY is specified.
486: */
487: if (ccd->ccd_flags & CCDF_UNIFORM) {
488: for (ci = cs->sc_cinfo;
489: ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) {
490: ci->ci_size = minsize;
491: }
492: if (ccd->ccd_flags & CCDF_MIRROR) {
493: /*
494: * Check to see if an even number of components
495: * have been specified. The interleave must also
496: * be non-zero in order for us to be able to
497: * guarentee the topology.
498: */
499: if (cs->sc_nccdisks % 2) {
500: printf("ccd%d: mirroring requires an even number of disks\n", ccd->ccd_unit );
501: error = EINVAL;
502: goto fail;
503: }
504: if (cs->sc_ileave == 0) {
505: printf("ccd%d: an interleave must be specified when mirroring\n", ccd->ccd_unit);
506: error = EINVAL;
507: goto fail;
508: }
509: cs->sc_size = (cs->sc_nccdisks/2) * minsize;
510: } else if (ccd->ccd_flags & CCDF_PARITY) {
511: cs->sc_size = (cs->sc_nccdisks-1) * minsize;
512: } else {
513: if (cs->sc_ileave == 0) {
514: printf("ccd%d: an interleave must be specified when using parity\n", ccd->ccd_unit);
515: error = EINVAL;
516: goto fail;
517: }
518: cs->sc_size = cs->sc_nccdisks * minsize;
519: }
520: }
521:
522: /*
523: * Construct the interleave table.
524: */
525: ccdinterleave(cs, ccd->ccd_unit);
526:
527: /*
528: * Create pseudo-geometry based on 1MB cylinders. It's
529: * pretty close.
530: */
531: ccg->ccg_secsize = maxsecsize;
532: ccg->ccg_ntracks = 1;
533: ccg->ccg_nsectors = 1024 * 1024 / ccg->ccg_secsize;
534: ccg->ccg_ncylinders = cs->sc_size / ccg->ccg_nsectors;
535:
536: /*
537: * Add an devstat entry for this device.
538: */
539: devstat_add_entry(&cs->device_stats, "ccd", ccd->ccd_unit,
540: ccg->ccg_secsize, DEVSTAT_ALL_SUPPORTED,
541: DEVSTAT_TYPE_STORARRAY |DEVSTAT_TYPE_IF_OTHER,
542: DEVSTAT_PRIORITY_ARRAY);
543:
544: cs->sc_flags |= CCDF_INITED;
545: cs->sc_cflags = ccd->ccd_flags; /* So we can find out later... */
546: cs->sc_unit = ccd->ccd_unit;
547: return (0);
548: fail:
549: while (ci > cs->sc_cinfo) {
550: ci--;
551: free(ci->ci_path, M_DEVBUF);
552: }
553: free(cs->sc_cinfo, M_DEVBUF);
554: return (error);
555: }
556:
557: static void
558: ccdinterleave(cs, unit)
559: struct ccd_softc *cs;
560: int unit;
561: {
562: struct ccdcinfo *ci, *smallci;
563: struct ccdiinfo *ii;
564: daddr_t bn, lbn;
565: int ix;
566: u_long size;
567:
568: #ifdef DEBUG
569: if (ccddebug & CCDB_INIT)
570: printf("ccdinterleave(%x): ileave %d\n", cs, cs->sc_ileave);
571: #endif
572:
573: /*
574: * Allocate an interleave table. The worst case occurs when each
575: * of N disks is of a different size, resulting in N interleave
576: * tables.
577: *
578: * Chances are this is too big, but we don't care.
579: */
580: size = (cs->sc_nccdisks + 1) * sizeof(struct ccdiinfo);
581: cs->sc_itable = (struct ccdiinfo *)malloc(size, M_DEVBUF, M_WAITOK);
582: bzero((caddr_t)cs->sc_itable, size);
583:
584: /*
585: * Trivial case: no interleave (actually interleave of disk size).
586: * Each table entry represents a single component in its entirety.
587: *
588: * An interleave of 0 may not be used with a mirror or parity setup.
589: */
590: if (cs->sc_ileave == 0) {
591: bn = 0;
592: ii = cs->sc_itable;
593:
594: for (ix = 0; ix < cs->sc_nccdisks; ix++) {
595: /* Allocate space for ii_index. */
596: ii->ii_index = malloc(sizeof(int), M_DEVBUF, M_WAITOK);
597: ii->ii_ndisk = 1;
598: ii->ii_startblk = bn;
599: ii->ii_startoff = 0;
600: ii->ii_index[0] = ix;
601: bn += cs->sc_cinfo[ix].ci_size;
602: ii++;
603: }
604: ii->ii_ndisk = 0;
605: #ifdef DEBUG
606: if (ccddebug & CCDB_INIT)
607: printiinfo(cs->sc_itable);
608: #endif
609: return;
610: }
611:
612: /*
613: * The following isn't fast or pretty; it doesn't have to be.
614: */
615: size = 0;
616: bn = lbn = 0;
617: for (ii = cs->sc_itable; ; ii++) {
618: /*
619: * Allocate space for ii_index. We might allocate more then
620: * we use.
621: */
622: ii->ii_index = malloc((sizeof(int) * cs->sc_nccdisks),
623: M_DEVBUF, M_WAITOK);
624:
625: /*
626: * Locate the smallest of the remaining components
627: */
628: smallci = NULL;
629: for (ci = cs->sc_cinfo; ci < &cs->sc_cinfo[cs->sc_nccdisks];
630: ci++) {
631: if (ci->ci_size > size &&
632: (smallci == NULL ||
633: ci->ci_size < smallci->ci_size)) {
634: smallci = ci;
635: }
636: }
637:
638: /*
639: * Nobody left, all done
640: */
641: if (smallci == NULL) {
642: ii->ii_ndisk = 0;
643: break;
644: }
645:
646: /*
647: * Record starting logical block using an sc_ileave blocksize.
648: */
649: ii->ii_startblk = bn / cs->sc_ileave;
650:
651: /*
652: * Record starting comopnent block using an sc_ileave
653: * blocksize. This value is relative to the beginning of
654: * a component disk.
655: */
656: ii->ii_startoff = lbn;
657:
658: /*
659: * Determine how many disks take part in this interleave
660: * and record their indices.
661: */
662: ix = 0;
663: for (ci = cs->sc_cinfo;
664: ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) {
665: if (ci->ci_size >= smallci->ci_size) {
666: ii->ii_index[ix++] = ci - cs->sc_cinfo;
667: }
668: }
669: ii->ii_ndisk = ix;
670: bn += ix * (smallci->ci_size - size);
671: lbn = smallci->ci_size / cs->sc_ileave;
672: size = smallci->ci_size;
673: }
674: #ifdef DEBUG
675: if (ccddebug & CCDB_INIT)
676: printiinfo(cs->sc_itable);
677: #endif
678: }
679:
680: /* ARGSUSED */
681: static int
682: ccdopen(dev_t dev, int flags, int fmt, d_thread_t *td)
683: {
684: int unit = ccdunit(dev);
685: struct ccd_softc *cs;
686: struct disklabel *lp;
687: int error = 0, part, pmask;
688:
689: #ifdef DEBUG
690: if (ccddebug & CCDB_FOLLOW)
691: printf("ccdopen(%x, %x)\n", dev, flags);
692: #endif
693: if (unit >= numccd)
694: return (ENXIO);
695: cs = &ccd_softc[unit];
696:
697: if ((error = ccdlock(cs)) != 0)
698: return (error);
699:
700: lp = &cs->sc_label;
701:
702: part = ccdpart(dev);
703: pmask = (1 << part);
704:
705: /*
706: * If we're initialized, check to see if there are any other
707: * open partitions. If not, then it's safe to update
708: * the in-core disklabel.
709: */
710: if ((cs->sc_flags & CCDF_INITED) && (cs->sc_openmask == 0))
711: ccdgetdisklabel(dev);
712:
713: /* Check that the partition exists. */
714: if (part != RAW_PART && ((part >= lp->d_npartitions) ||
715: (lp->d_partitions[part].p_fstype == FS_UNUSED))) {
716: error = ENXIO;
717: goto done;
718: }
719:
720: cs->sc_openmask |= pmask;
721: done:
722: ccdunlock(cs);
723: return (0);
724: }
725:
726: /* ARGSUSED */
727: static int
728: ccdclose(dev_t dev, int flags, int fmt, d_thread_t *td)
729: {
730: int unit = ccdunit(dev);
731: struct ccd_softc *cs;
732: int error = 0, part;
733:
734: #ifdef DEBUG
735: if (ccddebug & CCDB_FOLLOW)
736: printf("ccdclose(%x, %x)\n", dev, flags);
737: #endif
738:
739: if (unit >= numccd)
740: return (ENXIO);
741: cs = &ccd_softc[unit];
742:
743: if ((error = ccdlock(cs)) != 0)
744: return (error);
745:
746: part = ccdpart(dev);
747:
748: /* ...that much closer to allowing unconfiguration... */
749: cs->sc_openmask &= ~(1 << part);
750: ccdunlock(cs);
751: return (0);
752: }
753:
754: static void
755: ccdstrategy(bp)
756: struct buf *bp;
757: {
758: int unit = ccdunit(bp->b_dev);
759: struct ccd_softc *cs = &ccd_softc[unit];
760: int s;
761: int wlabel;
762: struct disklabel *lp;
763:
764: #ifdef DEBUG
765: if (ccddebug & CCDB_FOLLOW)
766: printf("ccdstrategy(%x): unit %d\n", bp, unit);
767: #endif
768: if ((cs->sc_flags & CCDF_INITED) == 0) {
769: bp->b_error = ENXIO;
770: bp->b_flags |= B_ERROR;
771: goto done;
772: }
773:
774: /* If it's a nil transfer, wake up the top half now. */
775: if (bp->b_bcount == 0)
776: goto done;
777:
778: lp = &cs->sc_label;
779:
780: /*
781: * Do bounds checking and adjust transfer. If there's an
782: * error, the bounds check will flag that for us.
783: */
784: wlabel = cs->sc_flags & (CCDF_WLABEL|CCDF_LABELLING);
785: if (ccdpart(bp->b_dev) != RAW_PART) {
786: if (bounds_check_with_label(bp, lp, wlabel) <= 0)
787: goto done;
788: } else {
789: int pbn; /* in sc_secsize chunks */
790: long sz; /* in sc_secsize chunks */
791:
792: pbn = bp->b_blkno / (cs->sc_geom.ccg_secsize / DEV_BSIZE);
793: sz = howmany(bp->b_bcount, cs->sc_geom.ccg_secsize);
794:
795: /*
796: * If out of bounds return an error. If at the EOF point,
797: * simply read or write less.
798: */
799:
800: if (pbn < 0 || pbn >= cs->sc_size) {
801: bp->b_resid = bp->b_bcount;
802: if (pbn != cs->sc_size) {
803: bp->b_error = EINVAL;
804: bp->b_flags |= B_ERROR | B_INVAL;
805: }
806: goto done;
807: }
808:
809: /*
810: * If the request crosses EOF, truncate the request.
811: */
812: if (pbn + sz > cs->sc_size) {
813: bp->b_bcount = (cs->sc_size - pbn) *
814: cs->sc_geom.ccg_secsize;
815: }
816: }
817:
818: bp->b_resid = bp->b_bcount;
819:
820: /*
821: * "Start" the unit.
822: */
823: s = splbio();
824: ccdstart(cs, bp);
825: splx(s);
826: return;
827: done:
828: biodone(bp);
829: }
830:
831: static void
832: ccdstart(cs, bp)
833: struct ccd_softc *cs;
834: struct buf *bp;
835: {
836: long bcount, rcount;
837: struct ccdbuf *cbp[4];
838: /* XXX! : 2 reads and 2 writes for RAID 4/5 */
839: caddr_t addr;
840: daddr_t bn;
841: struct partition *pp;
842:
843: #ifdef DEBUG
844: if (ccddebug & CCDB_FOLLOW)
845: printf("ccdstart(%x, %x)\n", cs, bp);
846: #endif
847:
848: /* Record the transaction start */
849: devstat_start_transaction(&cs->device_stats);
850:
851: /*
852: * Translate the partition-relative block number to an absolute.
853: */
854: bn = bp->b_blkno;
855: if (ccdpart(bp->b_dev) != RAW_PART) {
856: pp = &cs->sc_label.d_partitions[ccdpart(bp->b_dev)];
857: bn += pp->p_offset;
858: }
859:
860: /*
861: * Allocate component buffers and fire off the requests
862: */
863: addr = bp->b_data;
864: for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) {
865: ccdbuffer(cbp, cs, bp, bn, addr, bcount);
866: rcount = cbp[0]->cb_buf.b_bcount;
867:
868: if (cs->sc_cflags & CCDF_MIRROR) {
869: /*
870: * Mirroring. Writes go to both disks, reads are
871: * taken from whichever disk seems most appropriate.
872: *
873: * We attempt to localize reads to the disk whos arm
874: * is nearest the read request. We ignore seeks due
875: * to writes when making this determination and we
876: * also try to avoid hogging.
877: */
878: if ((cbp[0]->cb_buf.b_flags & B_READ) == 0) {
879: cbp[0]->cb_buf.b_vp->v_numoutput++;
880: cbp[1]->cb_buf.b_vp->v_numoutput++;
881: VOP_STRATEGY(cbp[0]->cb_buf.b_vp,
882: &cbp[0]->cb_buf);
883: VOP_STRATEGY(cbp[1]->cb_buf.b_vp,
884: &cbp[1]->cb_buf);
885: } else {
886: int pick = cs->sc_pick;
887: daddr_t range = cs->sc_size / 16;
888:
889: if (bn < cs->sc_blk[pick] - range ||
890: bn > cs->sc_blk[pick] + range
891: ) {
892: cs->sc_pick = pick = 1 - pick;
893: }
894: cs->sc_blk[pick] = bn + btodb(rcount);
895: VOP_STRATEGY(cbp[pick]->cb_buf.b_vp,
896: &cbp[pick]->cb_buf);
897: }
898: } else {
899: /*
900: * Not mirroring
901: */
902: if ((cbp[0]->cb_buf.b_flags & B_READ) == 0)
903: cbp[0]->cb_buf.b_vp->v_numoutput++;
904: VOP_STRATEGY(cbp[0]->cb_buf.b_vp, &cbp[0]->cb_buf);
905: }
906: bn += btodb(rcount);
907: addr += rcount;
908: }
909: }
910:
911: /*
912: * Build a component buffer header.
913: */
914: static void
915: ccdbuffer(cb, cs, bp, bn, addr, bcount)
916: struct ccdbuf **cb;
917: struct ccd_softc *cs;
918: struct buf *bp;
919: daddr_t bn;
920: caddr_t addr;
921: long bcount;
922: {
923: struct ccdcinfo *ci, *ci2 = NULL; /* XXX */
924: struct ccdbuf *cbp;
925: daddr_t cbn, cboff;
926: off_t cbc;
927:
928: #ifdef DEBUG
929: if (ccddebug & CCDB_IO)
930: printf("ccdbuffer(%x, %x, %d, %x, %d)\n",
931: cs, bp, bn, addr, bcount);
932: #endif
933: /*
934: * Determine which component bn falls in.
935: */
936: cbn = bn;
937: cboff = 0;
938:
939: if (cs->sc_ileave == 0) {
940: /*
941: * Serially concatenated and neither a mirror nor a parity
942: * config. This is a special case.
943: */
944: daddr_t sblk;
945:
946: sblk = 0;
947: for (ci = cs->sc_cinfo; cbn >= sblk + ci->ci_size; ci++)
948: sblk += ci->ci_size;
949: cbn -= sblk;
950: } else {
951: struct ccdiinfo *ii;
952: int ccdisk, off;
953:
954: /*
955: * Calculate cbn, the logical superblock (sc_ileave chunks),
956: * and cboff, a normal block offset (DEV_BSIZE chunks) relative
957: * to cbn.
958: */
959: cboff = cbn % cs->sc_ileave; /* DEV_BSIZE gran */
960: cbn = cbn / cs->sc_ileave; /* DEV_BSIZE * ileave gran */
961:
962: /*
963: * Figure out which interleave table to use.
964: */
965: for (ii = cs->sc_itable; ii->ii_ndisk; ii++) {
966: if (ii->ii_startblk > cbn)
967: break;
968: }
969: ii--;
970:
971: /*
972: * off is the logical superblock relative to the beginning
973: * of this interleave block.
974: */
975: off = cbn - ii->ii_startblk;
976:
977: /*
978: * We must calculate which disk component to use (ccdisk),
979: * and recalculate cbn to be the superblock relative to
980: * the beginning of the component. This is typically done by
981: * adding 'off' and ii->ii_startoff together. However, 'off'
982: * must typically be divided by the number of components in
983: * this interleave array to be properly convert it from a
984: * CCD-relative logical superblock number to a
985: * component-relative superblock number.
986: */
987: if (ii->ii_ndisk == 1) {
988: /*
989: * When we have just one disk, it can't be a mirror
990: * or a parity config.
991: */
992: ccdisk = ii->ii_index[0];
993: cbn = ii->ii_startoff + off;
994: } else {
995: if (cs->sc_cflags & CCDF_MIRROR) {
996: /*
997: * We have forced a uniform mapping, resulting
998: * in a single interleave array. We double
999: * up on the first half of the available
1000: * components and our mirror is in the second
1001: * half. This only works with a single
1002: * interleave array because doubling up
1003: * doubles the number of sectors, so there
1004: * cannot be another interleave array because
1005: * the next interleave array's calculations
1006: * would be off.
1007: */
1008: int ndisk2 = ii->ii_ndisk / 2;
1009: ccdisk = ii->ii_index[off % ndisk2];
1010: cbn = ii->ii_startoff + off / ndisk2;
1011: ci2 = &cs->sc_cinfo[ccdisk + ndisk2];
1012: } else if (cs->sc_cflags & CCDF_PARITY) {
1013: /*
1014: * XXX not implemented yet
1015: */
1016: int ndisk2 = ii->ii_ndisk - 1;
1017: ccdisk = ii->ii_index[off % ndisk2];
1018: cbn = ii->ii_startoff + off / ndisk2;
1019: if (cbn % ii->ii_ndisk <= ccdisk)
1020: ccdisk++;
1021: } else {
1022: ccdisk = ii->ii_index[off % ii->ii_ndisk];
1023: cbn = ii->ii_startoff + off / ii->ii_ndisk;
1024: }
1025: }
1026:
1027: ci = &cs->sc_cinfo[ccdisk];
1028:
1029: /*
1030: * Convert cbn from a superblock to a normal block so it
1031: * can be used to calculate (along with cboff) the normal
1032: * block index into this particular disk.
1033: */
1034: cbn *= cs->sc_ileave;
1035: }
1036:
1037: /*
1038: * Fill in the component buf structure.
1039: */
1040: cbp = getccdbuf(NULL);
1041: cbp->cb_buf.b_flags = bp->b_flags | B_CALL;
1042: cbp->cb_buf.b_iodone = (void (*)(struct buf *))ccdiodone;
1043: cbp->cb_buf.b_dev = ci->ci_dev; /* XXX */
1044: cbp->cb_buf.b_blkno = cbn + cboff + CCD_OFFSET;
1045: cbp->cb_buf.b_offset = dbtob(cbn + cboff + CCD_OFFSET);
1046: cbp->cb_buf.b_data = addr;
1047: cbp->cb_buf.b_vp = ci->ci_vp;
1048: if (cs->sc_ileave == 0)
1049: cbc = dbtob((off_t)(ci->ci_size - cbn));
1050: else
1051: cbc = dbtob((off_t)(cs->sc_ileave - cboff));
1052: cbp->cb_buf.b_bcount = (cbc < bcount) ? cbc : bcount;
1053: cbp->cb_buf.b_bufsize = cbp->cb_buf.b_bcount;
1054:
1055: /*
1056: * context for ccdiodone
1057: */
1058: cbp->cb_obp = bp;
1059: cbp->cb_unit = cs - ccd_softc;
1060: cbp->cb_comp = ci - cs->sc_cinfo;
1061:
1062: #ifdef DEBUG
1063: if (ccddebug & CCDB_IO)
1064: printf(" dev %x(u%d): cbp %x bn %d addr %x bcnt %d\n",
1065: ci->ci_dev, ci-cs->sc_cinfo, cbp, cbp->cb_buf.b_blkno,
1066: cbp->cb_buf.b_data, cbp->cb_buf.b_bcount);
1067: #endif
1068: cb[0] = cbp;
1069:
1070: /*
1071: * Note: both I/O's setup when reading from mirror, but only one
1072: * will be executed.
1073: */
1074: if (cs->sc_cflags & CCDF_MIRROR) {
1075: /* mirror, setup second I/O */
1076: cbp = getccdbuf(cb[0]);
1077: cbp->cb_buf.b_dev = ci2->ci_dev;
1078: cbp->cb_buf.b_vp = ci2->ci_vp;
1079: cbp->cb_comp = ci2 - cs->sc_cinfo;
1080: cb[1] = cbp;
1081: /* link together the ccdbuf's and clear "mirror done" flag */
1082: cb[0]->cb_mirror = cb[1];
1083: cb[1]->cb_mirror = cb[0];
1084: cb[0]->cb_pflags &= ~CCDPF_MIRROR_DONE;
1085: cb[1]->cb_pflags &= ~CCDPF_MIRROR_DONE;
1086: }
1087: }
1088:
1089: static void
1090: ccdintr(cs, bp)
1091: struct ccd_softc *cs;
1092: struct buf *bp;
1093: {
1094: #ifdef DEBUG
1095: if (ccddebug & CCDB_FOLLOW)
1096: printf("ccdintr(%x, %x)\n", cs, bp);
1097: #endif
1098: /*
1099: * Request is done for better or worse, wakeup the top half.
1100: */
1101: if (bp->b_flags & B_ERROR)
1102: bp->b_resid = bp->b_bcount;
1103: devstat_end_transaction_buf(&cs->device_stats, bp);
1104: biodone(bp);
1105: }
1106:
1107: /*
1108: * Called at interrupt time.
1109: * Mark the component as done and if all components are done,
1110: * take a ccd interrupt.
1111: */
1112: static void
1113: ccdiodone(cbp)
1114: struct ccdbuf *cbp;
1115: {
1116: struct buf *bp = cbp->cb_obp;
1117: int unit = cbp->cb_unit;
1118: int count, s;
1119:
1120: s = splbio();
1121: #ifdef DEBUG
1122: if (ccddebug & CCDB_FOLLOW)
1123: printf("ccdiodone(%x)\n", cbp);
1124: if (ccddebug & CCDB_IO) {
1125: printf("ccdiodone: bp %x bcount %d resid %d\n",
1126: bp, bp->b_bcount, bp->b_resid);
1127: printf(" dev %x(u%d), cbp %x bn %d addr %x bcnt %d\n",
1128: cbp->cb_buf.b_dev, cbp->cb_comp, cbp,
1129: cbp->cb_buf.b_blkno, cbp->cb_buf.b_data,
1130: cbp->cb_buf.b_bcount);
1131: }
1132: #endif
1133: /*
1134: * If an error occured, report it. If this is a mirrored
1135: * configuration and the first of two possible reads, do not
1136: * set the error in the bp yet because the second read may
1137: * succeed.
1138: */
1139:
1140: if (cbp->cb_buf.b_flags & B_ERROR) {
1141: const char *msg = "";
1142:
1143: if ((ccd_softc[unit].sc_cflags & CCDF_MIRROR) &&
1144: (cbp->cb_buf.b_flags & B_READ) &&
1145: (cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) {
1146: /*
1147: * We will try our read on the other disk down
1148: * below, also reverse the default pick so if we
1149: * are doing a scan we do not keep hitting the
1150: * bad disk first.
1151: */
1152: struct ccd_softc *cs = &ccd_softc[unit];
1153:
1154: msg = ", trying other disk";
1155: cs->sc_pick = 1 - cs->sc_pick;
1156: cs->sc_blk[cs->sc_pick] = bp->b_blkno;
1157: } else {
1158: bp->b_flags |= B_ERROR;
1159: bp->b_error = cbp->cb_buf.b_error ?
1160: cbp->cb_buf.b_error : EIO;
1161: }
1162: printf("ccd%d: error %d on component %d block %d (ccd block %d)%s\n",
1163: unit, bp->b_error, cbp->cb_comp,
1164: (int)cbp->cb_buf.b_blkno, bp->b_blkno, msg);
1165: }
1166:
1167: /*
1168: * Process mirror. If we are writing, I/O has been initiated on both
1169: * buffers and we fall through only after both are finished.
1170: *
1171: * If we are reading only one I/O is initiated at a time. If an
1172: * error occurs we initiate the second I/O and return, otherwise
1173: * we free the second I/O without initiating it.
1174: */
1175:
1176: if (ccd_softc[unit].sc_cflags & CCDF_MIRROR) {
1177: if ((cbp->cb_buf.b_flags & B_READ) == 0) {
1178: /*
1179: * When writing, handshake with the second buffer
1180: * to determine when both are done. If both are not
1181: * done, return here.
1182: */
1183: if ((cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) {
1184: cbp->cb_mirror->cb_pflags |= CCDPF_MIRROR_DONE;
1185: putccdbuf(cbp);
1186: splx(s);
1187: return;
1188: }
1189: } else {
1190: /*
1191: * When reading, either dispose of the second buffer
1192: * or initiate I/O on the second buffer if an error
1193: * occured with this one.
1194: */
1195: if ((cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) {
1196: if (cbp->cb_buf.b_flags & B_ERROR) {
1197: cbp->cb_mirror->cb_pflags |=
1198: CCDPF_MIRROR_DONE;
1199: VOP_STRATEGY(
1200: cbp->cb_mirror->cb_buf.b_vp,
1201: &cbp->cb_mirror->cb_buf
1202: );
1203: putccdbuf(cbp);
1204: splx(s);
1205: return;
1206: } else {
1207: putccdbuf(cbp->cb_mirror);
1208: /* fall through */
1209: }
1210: }
1211: }
1212: }
1213:
1214: /*
1215: * use b_bufsize to determine how big the original request was rather
1216: * then b_bcount, because b_bcount may have been truncated for EOF.
1217: *
1218: * XXX We check for an error, but we do not test the resid for an
1219: * aligned EOF condition. This may result in character & block
1220: * device access not recognizing EOF properly when read or written
1221: * sequentially, but will not effect filesystems.
1222: */
1223: count = cbp->cb_buf.b_bufsize;
1224: putccdbuf(cbp);
1225:
1226: /*
1227: * If all done, "interrupt".
1228: */
1229: bp->b_resid -= count;
1230: if (bp->b_resid < 0)
1231: panic("ccdiodone: count");
1232: if (bp->b_resid == 0)
1233: ccdintr(&ccd_softc[unit], bp);
1234: splx(s);
1235: }
1236:
1237: static int
1238: ccdioctl(dev_t dev, u_long cmd, caddr_t data, int flag, d_thread_t *td)
1239: {
1240: int unit = ccdunit(dev);
1241: int i, j, lookedup = 0, error = 0;
1242: int part, pmask, s;
1243: struct ccd_softc *cs;
1244: struct ccd_ioctl *ccio = (struct ccd_ioctl *)data;
1245: struct ccddevice ccd;
1246: char **cpp;
1247: struct vnode **vpp;
1248: struct ucred *cred;
1249:
1250: KKASSERT(td->td_proc != NULL);
1251: cred = td->td_proc->p_ucred;
1252:
1253: if (unit >= numccd)
1254: return (ENXIO);
1255: cs = &ccd_softc[unit];
1256:
1257: bzero(&ccd, sizeof(ccd));
1258:
1259: switch (cmd) {
1260: case CCDIOCSET:
1261: if (cs->sc_flags & CCDF_INITED)
1262: return (EBUSY);
1263:
1264: if ((flag & FWRITE) == 0)
1265: return (EBADF);
1266:
1267: if ((error = ccdlock(cs)) != 0)
1268: return (error);
1269:
1270: if (ccio->ccio_ndisks > CCD_MAXNDISKS)
1271: return (EINVAL);
1272:
1273: /* Fill in some important bits. */
1274: ccd.ccd_unit = unit;
1275: ccd.ccd_interleave = ccio->ccio_ileave;
1276: if (ccd.ccd_interleave == 0 &&
1277: ((ccio->ccio_flags & CCDF_MIRROR) ||
1278: (ccio->ccio_flags & CCDF_PARITY))) {
1279: printf("ccd%d: disabling mirror/parity, interleave is 0\n", unit);
1280: ccio->ccio_flags &= ~(CCDF_MIRROR | CCDF_PARITY);
1281: }
1282: if ((ccio->ccio_flags & CCDF_MIRROR) &&
1283: (ccio->ccio_flags & CCDF_PARITY)) {
1284: printf("ccd%d: can't specify both mirror and parity, using mirror\n", unit);
1285: ccio->ccio_flags &= ~CCDF_PARITY;
1286: }
1287: if ((ccio->ccio_flags & (CCDF_MIRROR | CCDF_PARITY)) &&
1288: !(ccio->ccio_flags & CCDF_UNIFORM)) {
1289: printf("ccd%d: mirror/parity forces uniform flag\n",
1290: unit);
1291: ccio->ccio_flags |= CCDF_UNIFORM;
1292: }
1293: ccd.ccd_flags = ccio->ccio_flags & CCDF_USERMASK;
1294:
1295: /*
1296: * Allocate space for and copy in the array of
1297: * componet pathnames and device numbers.
1298: */
1299: cpp = malloc(ccio->ccio_ndisks * sizeof(char *),
1300: M_DEVBUF, M_WAITOK);
1301: vpp = malloc(ccio->ccio_ndisks * sizeof(struct vnode *),
1302: M_DEVBUF, M_WAITOK);
1303:
1304: error = copyin((caddr_t)ccio->ccio_disks, (caddr_t)cpp,
1305: ccio->ccio_ndisks * sizeof(char **));
1306: if (error) {
1307: free(vpp, M_DEVBUF);
1308: free(cpp, M_DEVBUF);
1309: ccdunlock(cs);
1310: return (error);
1311: }
1312:
1313: #ifdef DEBUG
1314: if (ccddebug & CCDB_INIT)
1315: for (i = 0; i < ccio->ccio_ndisks; ++i)
1316: printf("ccdioctl: component %d: 0x%x\n",
1317: i, cpp[i]);
1318: #endif
1319:
1320: for (i = 0; i < ccio->ccio_ndisks; ++i) {
1321: #ifdef DEBUG
1322: if (ccddebug & CCDB_INIT)
1323: printf("ccdioctl: lookedup = %d\n", lookedup);
1324: #endif
1325: if ((error = ccdlookup(cpp[i], td, &vpp[i])) != 0) {
1326: for (j = 0; j < lookedup; ++j)
1327: (void)vn_close(vpp[j], FREAD|FWRITE, td);
1328: free(vpp, M_DEVBUF);
1329: free(cpp, M_DEVBUF);
1330: ccdunlock(cs);
1331: return (error);
1332: }
1333: ++lookedup;
1334: }
1335: ccd.ccd_cpp = cpp;
1336: ccd.ccd_vpp = vpp;
1337: ccd.ccd_ndev = ccio->ccio_ndisks;
1338:
1339: /*
1340: * Initialize the ccd. Fills in the softc for us.
1341: */
1342: if ((error = ccdinit(&ccd, cpp, td)) != 0) {
1343: for (j = 0; j < lookedup; ++j)
1344: (void)vn_close(vpp[j], FREAD|FWRITE, td);
1345: bzero(&ccd_softc[unit], sizeof(struct ccd_softc));
1346: free(vpp, M_DEVBUF);
1347: free(cpp, M_DEVBUF);
1348: ccdunlock(cs);
1349: return (error);
1350: }
1351:
1352: /*
1353: * The ccd has been successfully initialized, so
1354: * we can place it into the array and read the disklabel.
1355: */
1356: bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1357: ccio->ccio_unit = unit;
1358: ccio->ccio_size = cs->sc_size;
1359: ccdgetdisklabel(dev);
1360:
1361: ccdunlock(cs);
1362:
1363: break;
1364:
1365: case CCDIOCCLR:
1366: if ((cs->sc_flags & CCDF_INITED) == 0)
1367: return (ENXIO);
1368:
1369: if ((flag & FWRITE) == 0)
1370: return (EBADF);
1371:
1372: if ((error = ccdlock(cs)) != 0)
1373: return (error);
1374:
1375: /* Don't unconfigure if any other partitions are open */
1376: part = ccdpart(dev);
1377: pmask = (1 << part);
1378: if ((cs->sc_openmask & ~pmask)) {
1379: ccdunlock(cs);
1380: return (EBUSY);
1381: }
1382:
1383: /*
1384: * Free ccd_softc information and clear entry.
1385: */
1386:
1387: /* Close the components and free their pathnames. */
1388: for (i = 0; i < cs->sc_nccdisks; ++i) {
1389: /*
1390: * XXX: this close could potentially fail and
1391: * cause Bad Things. Maybe we need to force
1392: * the close to happen?
1393: */
1394: #ifdef DEBUG
1395: if (ccddebug & CCDB_VNODE)
1396: vprint("CCDIOCCLR: vnode info",
1397: cs->sc_cinfo[i].ci_vp);
1398: #endif
1399: (void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE, td);
1400: free(cs->sc_cinfo[i].ci_path, M_DEVBUF);
1401: }
1402:
1403: /* Free interleave index. */
1404: for (i = 0; cs->sc_itable[i].ii_ndisk; ++i)
1405: free(cs->sc_itable[i].ii_index, M_DEVBUF);
1406:
1407: /* Free component info and interleave table. */
1408: free(cs->sc_cinfo, M_DEVBUF);
1409: free(cs->sc_itable, M_DEVBUF);
1410: cs->sc_flags &= ~CCDF_INITED;
1411:
1412: /*
1413: * Free ccddevice information and clear entry.
1414: */
1415: free(ccddevs[unit].ccd_cpp, M_DEVBUF);
1416: free(ccddevs[unit].ccd_vpp, M_DEVBUF);
1417: ccd.ccd_dk = -1;
1418: bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1419:
1420: /*
1421: * And remove the devstat entry.
1422: */
1423: devstat_remove_entry(&cs->device_stats);
1424:
1425: /* This must be atomic. */
1426: s = splhigh();
1427: ccdunlock(cs);
1428: bzero(cs, sizeof(struct ccd_softc));
1429: splx(s);
1430:
1431: break;
1432:
1433: case DIOCGDINFO:
1434: if ((cs->sc_flags & CCDF_INITED) == 0)
1435: return (ENXIO);
1436:
1437: *(struct disklabel *)data = cs->sc_label;
1438: break;
1439:
1440: case DIOCGPART:
1441: if ((cs->sc_flags & CCDF_INITED) == 0)
1442: return (ENXIO);
1443:
1444: ((struct partinfo *)data)->disklab = &cs->sc_label;
1445: ((struct partinfo *)data)->part =
1446: &cs->sc_label.d_partitions[ccdpart(dev)];
1447: break;
1448:
1449: case DIOCWDINFO:
1450: case DIOCSDINFO:
1451: if ((cs->sc_flags & CCDF_INITED) == 0)
1452: return (ENXIO);
1453:
1454: if ((flag & FWRITE) == 0)
1455: return (EBADF);
1456:
1457: if ((error = ccdlock(cs)) != 0)
1458: return (error);
1459:
1460: cs->sc_flags |= CCDF_LABELLING;
1461:
1462: error = setdisklabel(&cs->sc_label,
1463: (struct disklabel *)data, 0);
1464: if (error == 0) {
1465: if (cmd == DIOCWDINFO)
1466: error = writedisklabel(CCDLABELDEV(dev),
1467: &cs->sc_label);
1468: }
1469:
1470: cs->sc_flags &= ~CCDF_LABELLING;
1471:
1472: ccdunlock(cs);
1473:
1474: if (error)
1475: return (error);
1476: break;
1477:
1478: case DIOCWLABEL:
1479: if ((cs->sc_flags & CCDF_INITED) == 0)
1480: return (ENXIO);
1481:
1482: if ((flag & FWRITE) == 0)
1483: return (EBADF);
1484: if (*(int *)data != 0)
1485: cs->sc_flags |= CCDF_WLABEL;
1486: else
1487: cs->sc_flags &= ~CCDF_WLABEL;
1488: break;
1489:
1490: default:
1491: return (ENOTTY);
1492: }
1493:
1494: return (0);
1495: }
1496:
1497: static int
1498: ccdsize(dev_t dev)
1499: {
1500: struct ccd_softc *cs;
1501: int part, size;
1502:
1503: if (ccdopen(dev, 0, S_IFCHR, curthread))
1504: return (-1);
1505:
1506: cs = &ccd_softc[ccdunit(dev)];
1507: part = ccdpart(dev);
1508:
1509: if ((cs->sc_flags & CCDF_INITED) == 0)
1510: return (-1);
1511:
1512: if (cs->sc_label.d_partitions[part].p_fstype != FS_SWAP)
1513: size = -1;
1514: else
1515: size = cs->sc_label.d_partitions[part].p_size;
1516:
1517: if (ccdclose(dev, 0, S_IFCHR, curthread))
1518: return (-1);
1519:
1520: return (size);
1521: }
1522:
1523: static int
1524: ccddump(dev)
1525: dev_t dev;
1526: {
1527:
1528: /* Not implemented. */
1529: return ENXIO;
1530: }
1531:
1532: /*
1533: * Lookup the provided name in the filesystem. If the file exists,
1534: * is a valid block device, and isn't being used by anyone else,
1535: * set *vpp to the file's vnode.
1536: */
1537: static int
1538: ccdlookup(char *path, struct thread *td, struct vnode **vpp)
1539: {
1540: struct nameidata nd;
1541: struct vnode *vp;
1542: int error;
1543: struct ucred *cred;
1544:
1545: KKASSERT(td->td_proc);
1546: cred = td->td_proc->p_ucred;
1547:
1548: NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, path, td);
1549: if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) {
1550: #ifdef DEBUG
1551: if (ccddebug & CCDB_FOLLOW|CCDB_INIT)
1552: printf("ccdlookup: vn_open error = %d\n", error);
1553: #endif
1554: return (error);
1555: }
1556: vp = nd.ni_vp;
1557:
1558: if (vp->v_usecount > 1) {
1559: error = EBUSY;
1560: goto bad;
1561: }
1562:
1563: if (!vn_isdisk(vp, &error))
1564: goto bad;
1565:
1566: #ifdef DEBUG
1567: if (ccddebug & CCDB_VNODE)
1568: vprint("ccdlookup: vnode info", vp);
1569: #endif
1570:
1571: VOP_UNLOCK(vp, NULL, 0, td);
1572: NDFREE(&nd, NDF_ONLY_PNBUF);
1573: *vpp = vp;
1574: return (0);
1575: bad:
1576: VOP_UNLOCK(vp, NULL, 0, td);
1577: NDFREE(&nd, NDF_ONLY_PNBUF);
1578: /* vn_close does vrele() for vp */
1579: (void)vn_close(vp, FREAD|FWRITE, td);
1580: return (error);
1581: }
1582:
1583: /*
1584: * Read the disklabel from the ccd. If one is not present, fake one
1585: * up.
1586: */
1587: static void
1588: ccdgetdisklabel(dev)
1589: dev_t dev;
1590: {
1591: int unit = ccdunit(dev);
1592: struct ccd_softc *cs = &ccd_softc[unit];
1593: char *errstring;
1594: struct disklabel *lp = &cs->sc_label;
1595: struct ccdgeom *ccg = &cs->sc_geom;
1596:
1597: bzero(lp, sizeof(*lp));
1598:
1599: lp->d_secperunit = cs->sc_size;
1600: lp->d_secsize = ccg->ccg_secsize;
1601: lp->d_nsectors = ccg->ccg_nsectors;
1602: lp->d_ntracks = ccg->ccg_ntracks;
1603: lp->d_ncylinders = ccg->ccg_ncylinders;
1604: lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1605:
1606: strncpy(lp->d_typename, "ccd", sizeof(lp->d_typename));
1607: lp->d_type = DTYPE_CCD;
1608: strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
1609: lp->d_rpm = 3600;
1610: lp->d_interleave = 1;
1611: lp->d_flags = 0;
1612:
1613: lp->d_partitions[RAW_PART].p_offset = 0;
1614: lp->d_partitions[RAW_PART].p_size = cs->sc_size;
1615: lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
1616: lp->d_npartitions = RAW_PART + 1;
1617:
1618: lp->d_bbsize = BBSIZE; /* XXX */
1619: lp->d_sbsize = SBSIZE; /* XXX */
1620:
1621: lp->d_magic = DISKMAGIC;
1622: lp->d_magic2 = DISKMAGIC;
1623: lp->d_checksum = dkcksum(&cs->sc_label);
1624:
1625: /*
1626: * Call the generic disklabel extraction routine.
1627: */
1628: errstring = readdisklabel(CCDLABELDEV(dev), &cs->sc_label);
1629: if (errstring != NULL)
1630: ccdmakedisklabel(cs);
1631:
1632: #ifdef DEBUG
1633: /* It's actually extremely common to have unlabeled ccds. */
1634: if (ccddebug & CCDB_LABEL)
1635: if (errstring != NULL)
1636: printf("ccd%d: %s\n", unit, errstring);
1637: #endif
1638: }
1639:
1640: /*
1641: * Take care of things one might want to take care of in the event
1642: * that a disklabel isn't present.
1643: */
1644: static void
1645: ccdmakedisklabel(cs)
1646: struct ccd_softc *cs;
1647: {
1648: struct disklabel *lp = &cs->sc_label;
1649:
1650: /*
1651: * For historical reasons, if there's no disklabel present
1652: * the raw partition must be marked FS_BSDFFS.
1653: */
1654: lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS;
1655:
1656: strncpy(lp->d_packname, "default label", sizeof(lp->d_packname));
1657: }
1658:
1659: /*
1660: * Wait interruptibly for an exclusive lock.
1661: *
1662: * XXX
1663: * Several drivers do this; it should be abstracted and made MP-safe.
1664: */
1665: static int
1666: ccdlock(cs)
1667: struct ccd_softc *cs;
1668: {
1669: int error;
1670:
1671: while ((cs->sc_flags & CCDF_LOCKED) != 0) {
1672: cs->sc_flags |= CCDF_WANTED;
1673: if ((error = tsleep(cs, PCATCH, "ccdlck", 0)) != 0)
1674: return (error);
1675: }
1676: cs->sc_flags |= CCDF_LOCKED;
1677: return (0);
1678: }
1679:
1680: /*
1681: * Unlock and wake up any waiters.
1682: */
1683: static void
1684: ccdunlock(cs)
1685: struct ccd_softc *cs;
1686: {
1687:
1688: cs->sc_flags &= ~CCDF_LOCKED;
1689: if ((cs->sc_flags & CCDF_WANTED) != 0) {
1690: cs->sc_flags &= ~CCDF_WANTED;
1691: wakeup(cs);
1692: }
1693: }
1694:
1695: #ifdef DEBUG
1696: static void
1697: printiinfo(ii)
1698: struct ccdiinfo *ii;
1699: {
1700: int ix, i;
1701:
1702: for (ix = 0; ii->ii_ndisk; ix++, ii++) {
1703: printf(" itab[%d]: #dk %d sblk %d soff %d",
1704: ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff);
1705: for (i = 0; i < ii->ii_ndisk; i++)
1706: printf(" %d", ii->ii_index[i]);
1707: printf("\n");
1708: }
1709: }
1710: #endif
1711:
1712:
1713: /* Local Variables: */
1714: /* c-argdecl-indent: 8 */
1715: /* c-continued-statement-offset: 8 */
1716: /* c-indent-level: 8 */
1717: /* End: */