This source file includes following definitions.
- getccdbuf
- putccdbuf
- ccdattach
- ccdinit
- ccdinterleave
- ccdopen
- ccdclose
- ccdstrategy
- ccdstart
- ccdbuffer
- ccdintr
- ccdiodone
- ccdread
- ccdwrite
- ccdioctl
- ccdsize
- ccddump
- ccdlookup
- ccdgetdisklabel
- printiinfo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
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/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
124
125 struct ccd_softc {
126 struct disk sc_dkdev;
127 struct ccdgeom sc_geom;
128 struct ccdcinfo *sc_cinfo;
129 struct ccdiinfo *sc_itable;
130 char sc_xname[8];
131 size_t sc_size;
132 int sc_flags;
133 int sc_cflags;
134 int sc_ileave;
135 u_int sc_nccdisks;
136 u_int sc_nccunits;
137 struct rwlock sc_rwlock;
138
139 };
140
141
142 #define CCDF_INITED 0x01
143 #define CCDF_WLABEL 0x02
144 #define CCDF_LABELLING 0x04
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)
157 #define CCD_DPRINTF(m,a)
158 #endif
159
160 struct ccdbuf {
161 struct buf cb_buf;
162 struct buf *cb_obp;
163 struct ccd_softc*cb_sc;
164 struct ccdbuf *cb_dep;
165 int cb_comp;
166 int cb_flags;
167 #define CBF_MIRROR 0x01
168 #define CBF_DONE 0x02
169 };
170
171
172 void ccdattach(int);
173
174
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
197 struct ccd_softc *ccd_softc;
198 struct ccddevice *ccddevs;
199 int numccd = 0;
200
201
202
203
204 struct pool ccdbufpl;
205
206
207
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
227
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
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
300
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
312
313 bzero(tmppath, sizeof(tmppath));
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
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
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
369
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
392
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
406
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
430
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;
444
445
446
447
448 ccdinterleave(cs);
449
450
451
452
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
479
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
487
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
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
511
512 size = 0;
513 bn = lbn = 0;
514 for (ii = cs->sc_itable; ; ii++) {
515
516 ii->ii_index = malloc((sizeof(int) * cs->sc_nccdisks),
517 M_DEVBUF, M_WAITOK);
518
519
520
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
532
533 if (smallci == NULL) {
534 ii->ii_ndisk = 0;
535 break;
536 }
537
538
539
540
541 ii->ii_startblk = bn / cs->sc_ileave;
542 ii->ii_startoff = lbn;
543
544
545
546
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
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
587
588
589
590 if ((cs->sc_flags & CCDF_INITED) && (cs->sc_dkdev.dk_openmask == 0))
591 ccdgetdisklabel(dev, cs, lp, 0);
592
593
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
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
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
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
676 if (bp->b_bcount == 0)
677 goto done;
678
679 lp = cs->sc_dkdev.dk_label;
680
681
682
683
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
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
718 disk_busy(&cs->sc_dkdev);
719
720
721
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
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
739
740
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
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
779
780 cbn = bn;
781 cboff = 0;
782
783 if (cs->sc_ileave == 0) {
784
785
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
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
813 ccdisk2 = ccdisk + ii->ii_ndisk;
814 ci2 = &cs->sc_cinfo[ccdisk2];
815
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
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
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;
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
854
855 cbp->cb_obp = bp;
856 cbp->cb_sc = cs;
857 cbp->cb_comp = ccdisk;
858
859
860
861
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;
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
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
905
906
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
962
963
964
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
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
991
992
993
994 return (physio(ccdstrategy, NULL, dev, B_READ, minphys, uio));
995 }
996
997
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
1015
1016
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
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
1065 ccd.ccd_unit = unit;
1066 ccd.ccd_interleave = ccio->ccio_ileave;
1067 ccd.ccd_flags = ccio->ccio_flags & CCDF_USERMASK;
1068
1069
1070
1071
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
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
1122
1123
1124
1125
1126
1127 bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1128 ccio->ccio_unit = unit;
1129 ccio->ccio_size = cs->sc_size;
1130
1131
1132 cs->sc_dkdev.dk_name = cs->sc_xname;
1133 disk_attach(&cs->sc_dkdev);
1134
1135
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
1147
1148
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
1161
1162
1163
1164 for (i = 0; i < cs->sc_nccdisks; ++i) {
1165
1166
1167
1168
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
1181 for (i = 0; cs->sc_itable[i].ii_ndisk; ++i)
1182 free(cs->sc_itable[i].ii_index, M_DEVBUF);
1183
1184
1185 free(cs->sc_cinfo, M_DEVBUF);
1186 free(cs->sc_itable, M_DEVBUF);
1187 cs->sc_flags &= ~CCDF_INITED;
1188
1189
1190
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
1197 disk_detach(&cs->sc_dkdev);
1198
1199
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
1297 return ENXIO;
1298 }
1299
1300
1301
1302
1303
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
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
1353
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
1385
1386 errstring = readdisklabel(DISKLABELDEV(dev), ccdstrategy,
1387 cs->sc_dkdev.dk_label, spoofonly);
1388
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