ccd.c revision 1.143.6.1 1 /* $NetBSD: ccd.c,v 1.143.6.1 2014/08/27 14:39:19 msaitoh Exp $ */
2
3 /*-
4 * Copyright (c) 1996, 1997, 1998, 1999, 2007, 2009 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe, and by Andrew Doran.
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 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 /*
33 * Copyright (c) 1988 University of Utah.
34 * Copyright (c) 1990, 1993
35 * The Regents of the University of California. All rights reserved.
36 *
37 * This code is derived from software contributed to Berkeley by
38 * the Systems Programming Group of the University of Utah Computer
39 * Science Department.
40 *
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
43 * are met:
44 * 1. Redistributions of source code must retain the above copyright
45 * notice, this list of conditions and the following disclaimer.
46 * 2. Redistributions in binary form must reproduce the above copyright
47 * notice, this list of conditions and the following disclaimer in the
48 * documentation and/or other materials provided with the distribution.
49 * 3. Neither the name of the University nor the names of its contributors
50 * may be used to endorse or promote products derived from this software
51 * without specific prior written permission.
52 *
53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * SUCH DAMAGE.
64 *
65 * from: Utah $Hdr: cd.c 1.6 90/11/28$
66 *
67 * @(#)cd.c 8.2 (Berkeley) 11/16/93
68 */
69
70 /*
71 * "Concatenated" disk driver.
72 *
73 * Notes on concurrency:
74 *
75 * => sc_dvlock serializes access to the device nodes, excluding block I/O.
76 *
77 * => sc_iolock serializes access to (sc_flags & CCDF_INITED), disk stats,
78 * sc_stop, sc_bufq and b_resid from master buffers.
79 *
80 * => a combination of CCDF_INITED, sc_inflight, and sc_iolock is used to
81 * serialize I/O and configuration changes.
82 *
83 * => the in-core disk label does not change while the device is open.
84 *
85 * On memory consumption: ccd fans out I/O requests and so needs to
86 * allocate memory. If the system is desperately low on memory, we
87 * single thread I/O.
88 */
89
90 #include <sys/cdefs.h>
91 __KERNEL_RCSID(0, "$NetBSD: ccd.c,v 1.143.6.1 2014/08/27 14:39:19 msaitoh Exp $");
92
93 #if defined(_KERNEL_OPT)
94 #include "opt_compat_netbsd.h"
95 #endif
96
97 #include <sys/param.h>
98 #include <sys/systm.h>
99 #include <sys/kernel.h>
100 #include <sys/proc.h>
101 #include <sys/errno.h>
102 #include <sys/buf.h>
103 #include <sys/kmem.h>
104 #include <sys/pool.h>
105 #include <sys/module.h>
106 #include <sys/namei.h>
107 #include <sys/stat.h>
108 #include <sys/ioctl.h>
109 #include <sys/disklabel.h>
110 #include <sys/device.h>
111 #include <sys/disk.h>
112 #include <sys/syslog.h>
113 #include <sys/fcntl.h>
114 #include <sys/vnode.h>
115 #include <sys/conf.h>
116 #include <sys/mutex.h>
117 #include <sys/queue.h>
118 #include <sys/kauth.h>
119 #include <sys/kthread.h>
120 #include <sys/bufq.h>
121
122 #include <uvm/uvm_extern.h>
123
124 #include <dev/ccdvar.h>
125 #include <dev/dkvar.h>
126
127 #if defined(CCDDEBUG) && !defined(DEBUG)
128 #define DEBUG
129 #endif
130
131 #ifdef DEBUG
132 #define CCDB_FOLLOW 0x01
133 #define CCDB_INIT 0x02
134 #define CCDB_IO 0x04
135 #define CCDB_LABEL 0x08
136 #define CCDB_VNODE 0x10
137 int ccddebug = 0x00;
138 #endif
139
140 #define ccdunit(x) DISKUNIT(x)
141
142 struct ccdbuf {
143 struct buf cb_buf; /* new I/O buf */
144 struct buf *cb_obp; /* ptr. to original I/O buf */
145 struct ccd_softc *cb_sc; /* pointer to ccd softc */
146 int cb_comp; /* target component */
147 SIMPLEQ_ENTRY(ccdbuf) cb_q; /* fifo of component buffers */
148 };
149
150 /* component buffer pool */
151 static pool_cache_t ccd_cache;
152
153 #define CCD_GETBUF() pool_cache_get(ccd_cache, PR_WAITOK)
154 #define CCD_PUTBUF(cbp) pool_cache_put(ccd_cache, cbp)
155
156 #define CCDLABELDEV(dev) \
157 (MAKEDISKDEV(major((dev)), ccdunit((dev)), RAW_PART))
158
159 /* called by main() at boot time */
160 void ccdattach(int);
161
162 /* called by biodone() at interrupt time */
163 static void ccdiodone(struct buf *);
164
165 static void ccdinterleave(struct ccd_softc *);
166 static int ccdinit(struct ccd_softc *, char **, struct vnode **,
167 struct lwp *);
168 static struct ccdbuf *ccdbuffer(struct ccd_softc *, struct buf *,
169 daddr_t, void *, long);
170 static void ccdgetdefaultlabel(struct ccd_softc *, struct disklabel *);
171 static void ccdgetdisklabel(dev_t);
172 static void ccdmakedisklabel(struct ccd_softc *);
173 static void ccdstart(struct ccd_softc *);
174 static void ccdthread(void *);
175
176 static dev_type_open(ccdopen);
177 static dev_type_close(ccdclose);
178 static dev_type_read(ccdread);
179 static dev_type_write(ccdwrite);
180 static dev_type_ioctl(ccdioctl);
181 static dev_type_strategy(ccdstrategy);
182 static dev_type_size(ccdsize);
183
184 const struct bdevsw ccd_bdevsw = {
185 .d_open = ccdopen,
186 .d_close = ccdclose,
187 .d_strategy = ccdstrategy,
188 .d_ioctl = ccdioctl,
189 .d_dump = nodump,
190 .d_psize = ccdsize,
191 .d_flag = D_DISK | D_MPSAFE
192 };
193
194 const struct cdevsw ccd_cdevsw = {
195 .d_open = ccdopen,
196 .d_close = ccdclose,
197 .d_read = ccdread,
198 .d_write = ccdwrite,
199 .d_ioctl = ccdioctl,
200 .d_stop = nostop,
201 .d_tty = notty,
202 .d_poll = nopoll,
203 .d_mmap = nommap,
204 .d_kqfilter = nokqfilter,
205 .d_flag = D_DISK | D_MPSAFE
206 };
207
208 #ifdef DEBUG
209 static void printiinfo(struct ccdiinfo *);
210 #endif
211
212 /* Publically visible for the benefit of libkvm and ccdconfig(8). */
213 struct ccd_softc *ccd_softc;
214 const int ccd_softc_elemsize = sizeof(struct ccd_softc);
215 int numccd = 0;
216
217 /*
218 * Called by main() during pseudo-device attachment. All we need
219 * to do is allocate enough space for devices to be configured later.
220 */
221 void
222 ccdattach(int num)
223 {
224 struct ccd_softc *cs;
225 int i;
226
227 if (num <= 0) {
228 #ifdef DIAGNOSTIC
229 panic("ccdattach: count <= 0");
230 #endif
231 return;
232 }
233
234 ccd_softc = kmem_zalloc(num * ccd_softc_elemsize, KM_SLEEP);
235 if (ccd_softc == NULL) {
236 printf("WARNING: no memory for concatenated disks\n");
237 return;
238 }
239 numccd = num;
240
241 /* Initialize the component buffer pool. */
242 ccd_cache = pool_cache_init(sizeof(struct ccdbuf), 0,
243 0, 0, "ccdbuf", NULL, IPL_BIO, NULL, NULL, NULL);
244
245 /* Initialize per-softc structures. */
246 for (i = 0; i < num; i++) {
247 cs = &ccd_softc[i];
248 snprintf(cs->sc_xname, sizeof(cs->sc_xname), "ccd%d", i);
249 mutex_init(&cs->sc_dvlock, MUTEX_DEFAULT, IPL_NONE);
250 cs->sc_iolock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE);
251 cv_init(&cs->sc_stop, "ccdstop");
252 cv_init(&cs->sc_push, "ccdthr");
253 disk_init(&cs->sc_dkdev, cs->sc_xname, NULL); /* XXX */
254 }
255 }
256
257 static int
258 ccdinit(struct ccd_softc *cs, char **cpaths, struct vnode **vpp,
259 struct lwp *l)
260 {
261 struct ccdcinfo *ci = NULL;
262 int ix;
263 struct vattr va;
264 struct ccdgeom *ccg = &cs->sc_geom;
265 char *tmppath;
266 int error, path_alloced;
267 uint64_t psize, minsize;
268 unsigned secsize, maxsecsize;
269
270 #ifdef DEBUG
271 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
272 printf("%s: ccdinit\n", cs->sc_xname);
273 #endif
274
275 /* Allocate space for the component info. */
276 cs->sc_cinfo = kmem_alloc(cs->sc_nccdisks * sizeof(*cs->sc_cinfo),
277 KM_SLEEP);
278 tmppath = kmem_alloc(MAXPATHLEN, KM_SLEEP);
279
280 cs->sc_size = 0;
281
282 /*
283 * Verify that each component piece exists and record
284 * relevant information about it.
285 */
286 maxsecsize = 0;
287 minsize = 0;
288 for (ix = 0, path_alloced = 0; ix < cs->sc_nccdisks; ix++) {
289 ci = &cs->sc_cinfo[ix];
290 ci->ci_vp = vpp[ix];
291
292 /*
293 * Copy in the pathname of the component.
294 */
295 memset(tmppath, 0, MAXPATHLEN); /* sanity */
296 error = copyinstr(cpaths[ix], tmppath,
297 MAXPATHLEN, &ci->ci_pathlen);
298 if (ci->ci_pathlen == 0)
299 error = EINVAL;
300 if (error) {
301 #ifdef DEBUG
302 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
303 printf("%s: can't copy path, error = %d\n",
304 cs->sc_xname, error);
305 #endif
306 goto out;
307 }
308 ci->ci_path = kmem_alloc(ci->ci_pathlen, KM_SLEEP);
309 memcpy(ci->ci_path, tmppath, ci->ci_pathlen);
310 path_alloced++;
311
312 /*
313 * XXX: Cache the component's dev_t.
314 */
315 vn_lock(vpp[ix], LK_SHARED | LK_RETRY);
316 error = VOP_GETATTR(vpp[ix], &va, l->l_cred);
317 VOP_UNLOCK(vpp[ix]);
318 if (error != 0) {
319 #ifdef DEBUG
320 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
321 printf("%s: %s: getattr failed %s = %d\n",
322 cs->sc_xname, ci->ci_path,
323 "error", error);
324 #endif
325 goto out;
326 }
327 ci->ci_dev = va.va_rdev;
328
329 /*
330 * Get partition information for the component.
331 */
332 error = getdisksize(vpp[ix], &psize, &secsize);
333 if (error) {
334 #ifdef DEBUG
335 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
336 printf("%s: %s: disksize failed, error = %d\n",
337 cs->sc_xname, ci->ci_path, error);
338 #endif
339 goto out;
340 }
341
342 /*
343 * Calculate the size, truncating to an interleave
344 * boundary if necessary.
345 */
346 maxsecsize = secsize > maxsecsize ? secsize : maxsecsize;
347 if (cs->sc_ileave > 1)
348 psize -= psize % cs->sc_ileave;
349
350 if (psize == 0) {
351 #ifdef DEBUG
352 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
353 printf("%s: %s: size == 0\n",
354 cs->sc_xname, ci->ci_path);
355 #endif
356 error = ENODEV;
357 goto out;
358 }
359
360 if (minsize == 0 || psize < minsize)
361 minsize = psize;
362 ci->ci_size = psize;
363 cs->sc_size += psize;
364 }
365
366 /*
367 * Don't allow the interleave to be smaller than
368 * the biggest component sector.
369 */
370 if ((cs->sc_ileave > 0) &&
371 (cs->sc_ileave < (maxsecsize / DEV_BSIZE))) {
372 #ifdef DEBUG
373 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
374 printf("%s: interleave must be at least %d\n",
375 cs->sc_xname, (maxsecsize / DEV_BSIZE));
376 #endif
377 error = EINVAL;
378 goto out;
379 }
380
381 /*
382 * If uniform interleave is desired set all sizes to that of
383 * the smallest component.
384 */
385 if (cs->sc_flags & CCDF_UNIFORM) {
386 for (ci = cs->sc_cinfo;
387 ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
388 ci->ci_size = minsize;
389
390 cs->sc_size = cs->sc_nccdisks * minsize;
391 }
392
393 /*
394 * Construct the interleave table.
395 */
396 ccdinterleave(cs);
397
398 /*
399 * Create pseudo-geometry based on 1MB cylinders. It's
400 * pretty close.
401 */
402 ccg->ccg_secsize = DEV_BSIZE;
403 ccg->ccg_ntracks = 1;
404 ccg->ccg_nsectors = 1024 * (1024 / ccg->ccg_secsize);
405 ccg->ccg_ncylinders = cs->sc_size / ccg->ccg_nsectors;
406
407 if (cs->sc_ileave > 0)
408 aprint_normal("%s: Interleaving %d component%s "
409 "(%d block interleave)\n", cs->sc_xname,
410 cs->sc_nccdisks, (cs->sc_nccdisks != 0 ? "s" : ""),
411 cs->sc_ileave);
412 else
413 aprint_normal("%s: Concatenating %d component%s\n",
414 cs->sc_xname,
415 cs->sc_nccdisks, (cs->sc_nccdisks != 0 ? "s" : ""));
416 for (ix = 0; ix < cs->sc_nccdisks; ix++) {
417 ci = &cs->sc_cinfo[ix];
418 aprint_normal("%s: %s (%ju blocks)\n", cs->sc_xname,
419 ci->ci_path, (uintmax_t)ci->ci_size);
420 }
421 aprint_normal("%s: total %ju blocks\n", cs->sc_xname, cs->sc_size);
422
423 /*
424 * Create thread to handle deferred I/O.
425 */
426 cs->sc_zap = false;
427 error = kthread_create(PRI_BIO, KTHREAD_MPSAFE, NULL, ccdthread,
428 cs, &cs->sc_thread, "%s", cs->sc_xname);
429 if (error) {
430 printf("ccdinit: can't create thread: %d\n", error);
431 goto out;
432 }
433
434 /*
435 * Only now that everything is set up can we enable the device.
436 */
437 mutex_enter(cs->sc_iolock);
438 cs->sc_flags |= CCDF_INITED;
439 mutex_exit(cs->sc_iolock);
440 kmem_free(tmppath, MAXPATHLEN);
441 return (0);
442
443 out:
444 for (ix = 0; ix < path_alloced; ix++) {
445 kmem_free(cs->sc_cinfo[ix].ci_path,
446 cs->sc_cinfo[ix].ci_pathlen);
447 }
448 kmem_free(cs->sc_cinfo, cs->sc_nccdisks * sizeof(struct ccdcinfo));
449 kmem_free(tmppath, MAXPATHLEN);
450 return (error);
451 }
452
453 static void
454 ccdinterleave(struct ccd_softc *cs)
455 {
456 struct ccdcinfo *ci, *smallci;
457 struct ccdiinfo *ii;
458 daddr_t bn, lbn;
459 int ix;
460 u_long size;
461
462 #ifdef DEBUG
463 if (ccddebug & CCDB_INIT)
464 printf("ccdinterleave(%p): ileave %d\n", cs, cs->sc_ileave);
465 #endif
466 /*
467 * Allocate an interleave table.
468 * Chances are this is too big, but we don't care.
469 */
470 size = (cs->sc_nccdisks + 1) * sizeof(struct ccdiinfo);
471 cs->sc_itable = kmem_zalloc(size, KM_SLEEP);
472
473 /*
474 * Trivial case: no interleave (actually interleave of disk size).
475 * Each table entry represents a single component in its entirety.
476 */
477 if (cs->sc_ileave == 0) {
478 bn = 0;
479 ii = cs->sc_itable;
480
481 for (ix = 0; ix < cs->sc_nccdisks; ix++) {
482 /* Allocate space for ii_index. */
483 ii->ii_indexsz = sizeof(int);
484 ii->ii_index = kmem_alloc(ii->ii_indexsz, KM_SLEEP);
485 ii->ii_ndisk = 1;
486 ii->ii_startblk = bn;
487 ii->ii_startoff = 0;
488 ii->ii_index[0] = ix;
489 bn += cs->sc_cinfo[ix].ci_size;
490 ii++;
491 }
492 ii->ii_ndisk = 0;
493 #ifdef DEBUG
494 if (ccddebug & CCDB_INIT)
495 printiinfo(cs->sc_itable);
496 #endif
497 return;
498 }
499
500 /*
501 * The following isn't fast or pretty; it doesn't have to be.
502 */
503 size = 0;
504 bn = lbn = 0;
505 for (ii = cs->sc_itable; ; ii++) {
506 /* Allocate space for ii_index. */
507 ii->ii_indexsz = sizeof(int) * cs->sc_nccdisks;
508 ii->ii_index = kmem_alloc(ii->ii_indexsz, KM_SLEEP);
509
510 /*
511 * Locate the smallest of the remaining components
512 */
513 smallci = NULL;
514 for (ci = cs->sc_cinfo;
515 ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
516 if (ci->ci_size > size &&
517 (smallci == NULL ||
518 ci->ci_size < smallci->ci_size))
519 smallci = ci;
520
521 /*
522 * Nobody left, all done
523 */
524 if (smallci == NULL) {
525 ii->ii_ndisk = 0;
526 break;
527 }
528
529 /*
530 * Record starting logical block and component offset
531 */
532 ii->ii_startblk = bn / cs->sc_ileave;
533 ii->ii_startoff = lbn;
534
535 /*
536 * Determine how many disks take part in this interleave
537 * and record their indices.
538 */
539 ix = 0;
540 for (ci = cs->sc_cinfo;
541 ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
542 if (ci->ci_size >= smallci->ci_size)
543 ii->ii_index[ix++] = ci - cs->sc_cinfo;
544 ii->ii_ndisk = ix;
545 bn += ix * (smallci->ci_size - size);
546 lbn = smallci->ci_size / cs->sc_ileave;
547 size = smallci->ci_size;
548 }
549 #ifdef DEBUG
550 if (ccddebug & CCDB_INIT)
551 printiinfo(cs->sc_itable);
552 #endif
553 }
554
555 /* ARGSUSED */
556 static int
557 ccdopen(dev_t dev, int flags, int fmt, struct lwp *l)
558 {
559 int unit = ccdunit(dev);
560 struct ccd_softc *cs;
561 struct disklabel *lp;
562 int error = 0, part, pmask;
563
564 #ifdef DEBUG
565 if (ccddebug & CCDB_FOLLOW)
566 printf("ccdopen(0x%"PRIx64", 0x%x)\n", dev, flags);
567 #endif
568 if (unit >= numccd)
569 return (ENXIO);
570 cs = &ccd_softc[unit];
571
572 mutex_enter(&cs->sc_dvlock);
573
574 lp = cs->sc_dkdev.dk_label;
575
576 part = DISKPART(dev);
577 pmask = (1 << part);
578
579 /*
580 * If we're initialized, check to see if there are any other
581 * open partitions. If not, then it's safe to update
582 * the in-core disklabel. Only read the disklabel if it is
583 * not already valid.
584 */
585 if ((cs->sc_flags & (CCDF_INITED|CCDF_VLABEL)) == CCDF_INITED &&
586 cs->sc_dkdev.dk_openmask == 0)
587 ccdgetdisklabel(dev);
588
589 /* Check that the partition exists. */
590 if (part != RAW_PART) {
591 if (((cs->sc_flags & CCDF_INITED) == 0) ||
592 ((part >= lp->d_npartitions) ||
593 (lp->d_partitions[part].p_fstype == FS_UNUSED))) {
594 error = ENXIO;
595 goto done;
596 }
597 }
598
599 /* Prevent our unit from being unconfigured while open. */
600 switch (fmt) {
601 case S_IFCHR:
602 cs->sc_dkdev.dk_copenmask |= pmask;
603 break;
604
605 case S_IFBLK:
606 cs->sc_dkdev.dk_bopenmask |= pmask;
607 break;
608 }
609 cs->sc_dkdev.dk_openmask =
610 cs->sc_dkdev.dk_copenmask | cs->sc_dkdev.dk_bopenmask;
611
612 done:
613 mutex_exit(&cs->sc_dvlock);
614 return (error);
615 }
616
617 /* ARGSUSED */
618 static int
619 ccdclose(dev_t dev, int flags, int fmt, struct lwp *l)
620 {
621 int unit = ccdunit(dev);
622 struct ccd_softc *cs;
623 int part;
624
625 #ifdef DEBUG
626 if (ccddebug & CCDB_FOLLOW)
627 printf("ccdclose(0x%"PRIx64", 0x%x)\n", dev, flags);
628 #endif
629
630 if (unit >= numccd)
631 return (ENXIO);
632 cs = &ccd_softc[unit];
633
634 mutex_enter(&cs->sc_dvlock);
635
636 part = DISKPART(dev);
637
638 /* ...that much closer to allowing unconfiguration... */
639 switch (fmt) {
640 case S_IFCHR:
641 cs->sc_dkdev.dk_copenmask &= ~(1 << part);
642 break;
643
644 case S_IFBLK:
645 cs->sc_dkdev.dk_bopenmask &= ~(1 << part);
646 break;
647 }
648 cs->sc_dkdev.dk_openmask =
649 cs->sc_dkdev.dk_copenmask | cs->sc_dkdev.dk_bopenmask;
650
651 if (cs->sc_dkdev.dk_openmask == 0) {
652 if ((cs->sc_flags & CCDF_KLABEL) == 0)
653 cs->sc_flags &= ~CCDF_VLABEL;
654 }
655
656 mutex_exit(&cs->sc_dvlock);
657 return (0);
658 }
659
660 static bool
661 ccdbackoff(struct ccd_softc *cs)
662 {
663
664 /* XXX Arbitrary, should be a uvm call. */
665 return uvmexp.free < (uvmexp.freemin >> 1) &&
666 disk_isbusy(&cs->sc_dkdev);
667 }
668
669 static void
670 ccdthread(void *cookie)
671 {
672 struct ccd_softc *cs;
673
674 cs = cookie;
675
676 #ifdef DEBUG
677 if (ccddebug & CCDB_FOLLOW)
678 printf("ccdthread: hello\n");
679 #endif
680
681 mutex_enter(cs->sc_iolock);
682 while (__predict_true(!cs->sc_zap)) {
683 if (bufq_peek(cs->sc_bufq) == NULL) {
684 /* Nothing to do. */
685 cv_wait(&cs->sc_push, cs->sc_iolock);
686 continue;
687 }
688 if (ccdbackoff(cs)) {
689 /* Wait for memory to become available. */
690 (void)cv_timedwait(&cs->sc_push, cs->sc_iolock, 1);
691 continue;
692 }
693 #ifdef DEBUG
694 if (ccddebug & CCDB_FOLLOW)
695 printf("ccdthread: dispatching I/O\n");
696 #endif
697 ccdstart(cs);
698 mutex_enter(cs->sc_iolock);
699 }
700 cs->sc_thread = NULL;
701 mutex_exit(cs->sc_iolock);
702 #ifdef DEBUG
703 if (ccddebug & CCDB_FOLLOW)
704 printf("ccdthread: goodbye\n");
705 #endif
706 kthread_exit(0);
707 }
708
709 static void
710 ccdstrategy(struct buf *bp)
711 {
712 int unit = ccdunit(bp->b_dev);
713 struct ccd_softc *cs = &ccd_softc[unit];
714
715 /* Must be open or reading label. */
716 KASSERT(cs->sc_dkdev.dk_openmask != 0 ||
717 (cs->sc_flags & CCDF_RLABEL) != 0);
718
719 mutex_enter(cs->sc_iolock);
720 /* Synchronize with device init/uninit. */
721 if (__predict_false((cs->sc_flags & CCDF_INITED) == 0)) {
722 mutex_exit(cs->sc_iolock);
723 #ifdef DEBUG
724 if (ccddebug & CCDB_FOLLOW)
725 printf("ccdstrategy: unit %d: not inited\n", unit);
726 #endif
727 bp->b_error = ENXIO;
728 bp->b_resid = bp->b_bcount;
729 biodone(bp);
730 return;
731 }
732
733 /* Defer to thread if system is low on memory. */
734 bufq_put(cs->sc_bufq, bp);
735 if (__predict_false(ccdbackoff(cs))) {
736 mutex_exit(cs->sc_iolock);
737 #ifdef DEBUG
738 if (ccddebug & CCDB_FOLLOW)
739 printf("ccdstrategy: holding off on I/O\n");
740 #endif
741 return;
742 }
743 ccdstart(cs);
744 }
745
746 static void
747 ccdstart(struct ccd_softc *cs)
748 {
749 daddr_t blkno;
750 int wlabel;
751 struct disklabel *lp;
752 long bcount, rcount;
753 struct ccdbuf *cbp;
754 char *addr;
755 daddr_t bn;
756 vnode_t *vp;
757 buf_t *bp;
758
759 KASSERT(mutex_owned(cs->sc_iolock));
760
761 disk_busy(&cs->sc_dkdev);
762 bp = bufq_get(cs->sc_bufq);
763 KASSERT(bp != NULL);
764
765 #ifdef DEBUG
766 if (ccddebug & CCDB_FOLLOW)
767 printf("ccdstart(%s, %p)\n", cs->sc_xname, bp);
768 #endif
769
770 /* If it's a nil transfer, wake up the top half now. */
771 if (bp->b_bcount == 0)
772 goto done;
773
774 lp = cs->sc_dkdev.dk_label;
775
776 /*
777 * Do bounds checking and adjust transfer. If there's an
778 * error, the bounds check will flag that for us. Convert
779 * the partition relative block number to an absolute.
780 */
781 blkno = bp->b_blkno;
782 wlabel = cs->sc_flags & (CCDF_WLABEL|CCDF_LABELLING);
783 if (DISKPART(bp->b_dev) != RAW_PART) {
784 if (bounds_check_with_label(&cs->sc_dkdev, bp, wlabel) <= 0)
785 goto done;
786 blkno += lp->d_partitions[DISKPART(bp->b_dev)].p_offset;
787 }
788 mutex_exit(cs->sc_iolock);
789 bp->b_rawblkno = blkno;
790
791 /* Allocate the component buffers and start I/O! */
792 bp->b_resid = bp->b_bcount;
793 bn = bp->b_rawblkno;
794 addr = bp->b_data;
795 for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) {
796 cbp = ccdbuffer(cs, bp, bn, addr, bcount);
797 rcount = cbp->cb_buf.b_bcount;
798 bn += btodb(rcount);
799 addr += rcount;
800 vp = cbp->cb_buf.b_vp;
801 if ((cbp->cb_buf.b_flags & B_READ) == 0) {
802 mutex_enter(vp->v_interlock);
803 vp->v_numoutput++;
804 mutex_exit(vp->v_interlock);
805 }
806 (void)VOP_STRATEGY(vp, &cbp->cb_buf);
807 }
808 return;
809
810 done:
811 disk_unbusy(&cs->sc_dkdev, 0, 0);
812 cv_broadcast(&cs->sc_stop);
813 cv_broadcast(&cs->sc_push);
814 mutex_exit(cs->sc_iolock);
815 bp->b_resid = bp->b_bcount;
816 biodone(bp);
817 }
818
819 /*
820 * Build a component buffer header.
821 */
822 static struct ccdbuf *
823 ccdbuffer(struct ccd_softc *cs, struct buf *bp, daddr_t bn, void *addr,
824 long bcount)
825 {
826 struct ccdcinfo *ci;
827 struct ccdbuf *cbp;
828 daddr_t cbn, cboff;
829 u_int64_t cbc;
830 int ccdisk;
831
832 #ifdef DEBUG
833 if (ccddebug & CCDB_IO)
834 printf("ccdbuffer(%p, %p, %" PRId64 ", %p, %ld)\n",
835 cs, bp, bn, addr, bcount);
836 #endif
837 /*
838 * Determine which component bn falls in.
839 */
840 cbn = bn;
841 cboff = 0;
842
843 /*
844 * Serially concatenated
845 */
846 if (cs->sc_ileave == 0) {
847 daddr_t sblk;
848
849 sblk = 0;
850 for (ccdisk = 0, ci = &cs->sc_cinfo[ccdisk];
851 cbn >= sblk + ci->ci_size;
852 ccdisk++, ci = &cs->sc_cinfo[ccdisk])
853 sblk += ci->ci_size;
854 cbn -= sblk;
855 }
856 /*
857 * Interleaved
858 */
859 else {
860 struct ccdiinfo *ii;
861 int off;
862
863 cboff = cbn % cs->sc_ileave;
864 cbn /= cs->sc_ileave;
865 for (ii = cs->sc_itable; ii->ii_ndisk; ii++)
866 if (ii->ii_startblk > cbn)
867 break;
868 ii--;
869 off = cbn - ii->ii_startblk;
870 if (ii->ii_ndisk == 1) {
871 ccdisk = ii->ii_index[0];
872 cbn = ii->ii_startoff + off;
873 } else {
874 ccdisk = ii->ii_index[off % ii->ii_ndisk];
875 cbn = ii->ii_startoff + off / ii->ii_ndisk;
876 }
877 cbn *= cs->sc_ileave;
878 ci = &cs->sc_cinfo[ccdisk];
879 }
880
881 /*
882 * Fill in the component buf structure.
883 */
884 cbp = CCD_GETBUF();
885 KASSERT(cbp != NULL);
886 buf_init(&cbp->cb_buf);
887 cbp->cb_buf.b_flags = bp->b_flags;
888 cbp->cb_buf.b_oflags = bp->b_oflags;
889 cbp->cb_buf.b_cflags = bp->b_cflags;
890 cbp->cb_buf.b_iodone = ccdiodone;
891 cbp->cb_buf.b_proc = bp->b_proc;
892 cbp->cb_buf.b_dev = ci->ci_dev;
893 cbp->cb_buf.b_blkno = cbn + cboff;
894 cbp->cb_buf.b_data = addr;
895 cbp->cb_buf.b_vp = ci->ci_vp;
896 cbp->cb_buf.b_objlock = ci->ci_vp->v_interlock;
897 if (cs->sc_ileave == 0)
898 cbc = dbtob((u_int64_t)(ci->ci_size - cbn));
899 else
900 cbc = dbtob((u_int64_t)(cs->sc_ileave - cboff));
901 cbp->cb_buf.b_bcount = cbc < bcount ? cbc : bcount;
902
903 /*
904 * context for ccdiodone
905 */
906 cbp->cb_obp = bp;
907 cbp->cb_sc = cs;
908 cbp->cb_comp = ccdisk;
909
910 BIO_COPYPRIO(&cbp->cb_buf, bp);
911
912 #ifdef DEBUG
913 if (ccddebug & CCDB_IO)
914 printf(" dev 0x%"PRIx64"(u%lu): cbp %p bn %" PRId64 " addr %p"
915 " bcnt %d\n",
916 ci->ci_dev, (unsigned long) (ci-cs->sc_cinfo), cbp,
917 cbp->cb_buf.b_blkno, cbp->cb_buf.b_data,
918 cbp->cb_buf.b_bcount);
919 #endif
920
921 return (cbp);
922 }
923
924 /*
925 * Called at interrupt time.
926 * Mark the component as done and if all components are done,
927 * take a ccd interrupt.
928 */
929 static void
930 ccdiodone(struct buf *vbp)
931 {
932 struct ccdbuf *cbp = (struct ccdbuf *) vbp;
933 struct buf *bp = cbp->cb_obp;
934 struct ccd_softc *cs = cbp->cb_sc;
935 int count;
936
937 #ifdef DEBUG
938 if (ccddebug & CCDB_FOLLOW)
939 printf("ccdiodone(%p)\n", cbp);
940 if (ccddebug & CCDB_IO) {
941 printf("ccdiodone: bp %p bcount %d resid %d\n",
942 bp, bp->b_bcount, bp->b_resid);
943 printf(" dev 0x%"PRIx64"(u%d), cbp %p bn %" PRId64 " addr %p"
944 " bcnt %d\n",
945 cbp->cb_buf.b_dev, cbp->cb_comp, cbp,
946 cbp->cb_buf.b_blkno, cbp->cb_buf.b_data,
947 cbp->cb_buf.b_bcount);
948 }
949 #endif
950
951 if (cbp->cb_buf.b_error != 0) {
952 bp->b_error = cbp->cb_buf.b_error;
953 printf("%s: error %d on component %d\n",
954 cs->sc_xname, bp->b_error, cbp->cb_comp);
955 }
956 count = cbp->cb_buf.b_bcount;
957 buf_destroy(&cbp->cb_buf);
958 CCD_PUTBUF(cbp);
959
960 /*
961 * If all done, "interrupt".
962 */
963 mutex_enter(cs->sc_iolock);
964 bp->b_resid -= count;
965 if (bp->b_resid < 0)
966 panic("ccdiodone: count");
967 if (bp->b_resid == 0) {
968 /*
969 * Request is done for better or worse, wakeup the top half.
970 */
971 if (bp->b_error != 0)
972 bp->b_resid = bp->b_bcount;
973 disk_unbusy(&cs->sc_dkdev, (bp->b_bcount - bp->b_resid),
974 (bp->b_flags & B_READ));
975 if (!disk_isbusy(&cs->sc_dkdev)) {
976 if (bufq_peek(cs->sc_bufq) != NULL) {
977 cv_broadcast(&cs->sc_push);
978 }
979 cv_broadcast(&cs->sc_stop);
980 }
981 mutex_exit(cs->sc_iolock);
982 biodone(bp);
983 } else
984 mutex_exit(cs->sc_iolock);
985 }
986
987 /* ARGSUSED */
988 static int
989 ccdread(dev_t dev, struct uio *uio, int flags)
990 {
991 int unit = ccdunit(dev);
992 struct ccd_softc *cs;
993
994 #ifdef DEBUG
995 if (ccddebug & CCDB_FOLLOW)
996 printf("ccdread(0x%"PRIx64", %p)\n", dev, uio);
997 #endif
998 if (unit >= numccd)
999 return (ENXIO);
1000 cs = &ccd_softc[unit];
1001
1002 /* Unlocked advisory check, ccdstrategy check is synchronous. */
1003 if ((cs->sc_flags & CCDF_INITED) == 0)
1004 return (ENXIO);
1005
1006 return (physio(ccdstrategy, NULL, dev, B_READ, minphys, uio));
1007 }
1008
1009 /* ARGSUSED */
1010 static int
1011 ccdwrite(dev_t dev, struct uio *uio, int flags)
1012 {
1013 int unit = ccdunit(dev);
1014 struct ccd_softc *cs;
1015
1016 #ifdef DEBUG
1017 if (ccddebug & CCDB_FOLLOW)
1018 printf("ccdwrite(0x%"PRIx64", %p)\n", dev, uio);
1019 #endif
1020 if (unit >= numccd)
1021 return (ENXIO);
1022 cs = &ccd_softc[unit];
1023
1024 /* Unlocked advisory check, ccdstrategy check is synchronous. */
1025 if ((cs->sc_flags & CCDF_INITED) == 0)
1026 return (ENXIO);
1027
1028 return (physio(ccdstrategy, NULL, dev, B_WRITE, minphys, uio));
1029 }
1030
1031 static int
1032 ccdioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
1033 {
1034 int unit = ccdunit(dev);
1035 int i, j, lookedup = 0, error = 0;
1036 int part, pmask;
1037 struct ccd_softc *cs;
1038 struct ccd_ioctl *ccio = (struct ccd_ioctl *)data;
1039 kauth_cred_t uc;
1040 char **cpp;
1041 struct pathbuf *pb;
1042 struct vnode **vpp;
1043 #ifdef __HAVE_OLD_DISKLABEL
1044 struct disklabel newlabel;
1045 #endif
1046
1047 if (unit >= numccd)
1048 return (ENXIO);
1049 cs = &ccd_softc[unit];
1050 uc = kauth_cred_get();
1051
1052 /*
1053 * Compat code must not be called if on a platform where
1054 * sizeof (size_t) == sizeof (uint64_t) as CCDIOCSET will
1055 * be the same as CCDIOCSET_60
1056 */
1057 #ifndef _LP64
1058 switch (cmd) {
1059 case CCDIOCSET_60: {
1060 struct ccd_ioctl ccionew;
1061 struct ccd_ioctl_60 *ccio60 =
1062 (struct ccd_ioctl_60 *)data;
1063 ccionew.ccio_disks = ccio->ccio_disks;
1064 ccionew.ccio_ndisks = ccio->ccio_ndisks;
1065 ccionew.ccio_ileave = ccio->ccio_ileave;
1066 ccionew.ccio_flags = ccio->ccio_flags;
1067 ccionew.ccio_unit = ccio->ccio_unit;
1068 error = ccdioctl(dev, CCDIOCSET, &ccionew, flag, l);
1069 if (!error) {
1070 /* Copy data back, adjust types if necessary */
1071 ccio60->ccio_disks = ccionew.ccio_disks;
1072 ccio60->ccio_ndisks = ccionew.ccio_ndisks;
1073 ccio60->ccio_ileave = ccionew.ccio_ileave;
1074 ccio60->ccio_flags = ccionew.ccio_flags;
1075 ccio60->ccio_unit = ccionew.ccio_unit;
1076 ccio60->ccio_size = (size_t)ccionew.ccio_size;
1077 }
1078 return error;
1079 }
1080 break;
1081
1082 case CCDIOCCLR_60:
1083 /*
1084 * ccio_size member not used, so existing struct OK
1085 * drop through to existing non-compat version
1086 */
1087 cmd = CCDIOCCLR;
1088 break;
1089 }
1090 #endif /* !_LP64*/
1091
1092 /* Must be open for writes for these commands... */
1093 switch (cmd) {
1094 case CCDIOCSET:
1095 case CCDIOCCLR:
1096 case DIOCSDINFO:
1097 case DIOCWDINFO:
1098 #ifdef __HAVE_OLD_DISKLABEL
1099 case ODIOCSDINFO:
1100 case ODIOCWDINFO:
1101 #endif
1102 case DIOCKLABEL:
1103 case DIOCWLABEL:
1104 if ((flag & FWRITE) == 0)
1105 return (EBADF);
1106 }
1107
1108 mutex_enter(&cs->sc_dvlock);
1109
1110 /* Must be initialized for these... */
1111 switch (cmd) {
1112 case CCDIOCCLR:
1113 case DIOCGDINFO:
1114 case DIOCCACHESYNC:
1115 case DIOCSDINFO:
1116 case DIOCWDINFO:
1117 case DIOCGPART:
1118 case DIOCWLABEL:
1119 case DIOCKLABEL:
1120 case DIOCGDEFLABEL:
1121 #ifdef __HAVE_OLD_DISKLABEL
1122 case ODIOCGDINFO:
1123 case ODIOCSDINFO:
1124 case ODIOCWDINFO:
1125 case ODIOCGDEFLABEL:
1126 #endif
1127 if ((cs->sc_flags & CCDF_INITED) == 0) {
1128 error = ENXIO;
1129 goto out;
1130 }
1131 }
1132
1133 switch (cmd) {
1134 case CCDIOCSET:
1135 if (cs->sc_flags & CCDF_INITED) {
1136 error = EBUSY;
1137 goto out;
1138 }
1139
1140 /* Validate the flags. */
1141 if ((ccio->ccio_flags & CCDF_USERMASK) != ccio->ccio_flags) {
1142 error = EINVAL;
1143 goto out;
1144 }
1145
1146 if (ccio->ccio_ndisks > CCD_MAXNDISKS ||
1147 ccio->ccio_ndisks == 0) {
1148 error = EINVAL;
1149 goto out;
1150 }
1151
1152 /* Fill in some important bits. */
1153 cs->sc_ileave = ccio->ccio_ileave;
1154 cs->sc_nccdisks = ccio->ccio_ndisks;
1155 cs->sc_flags = ccio->ccio_flags & CCDF_USERMASK;
1156
1157 /*
1158 * Allocate space for and copy in the array of
1159 * component pathnames and device numbers.
1160 */
1161 cpp = kmem_alloc(ccio->ccio_ndisks * sizeof(*cpp), KM_SLEEP);
1162 vpp = kmem_alloc(ccio->ccio_ndisks * sizeof(*vpp), KM_SLEEP);
1163 error = copyin(ccio->ccio_disks, cpp,
1164 ccio->ccio_ndisks * sizeof(*cpp));
1165 if (error) {
1166 kmem_free(vpp, ccio->ccio_ndisks * sizeof(*vpp));
1167 kmem_free(cpp, ccio->ccio_ndisks * sizeof(*cpp));
1168 goto out;
1169 }
1170
1171 #ifdef DEBUG
1172 if (ccddebug & CCDB_INIT)
1173 for (i = 0; i < ccio->ccio_ndisks; ++i)
1174 printf("ccdioctl: component %d: %p\n",
1175 i, cpp[i]);
1176 #endif
1177
1178 for (i = 0; i < ccio->ccio_ndisks; ++i) {
1179 #ifdef DEBUG
1180 if (ccddebug & CCDB_INIT)
1181 printf("ccdioctl: lookedup = %d\n", lookedup);
1182 #endif
1183 error = pathbuf_copyin(cpp[i], &pb);
1184 if (error == 0) {
1185 error = dk_lookup(pb, l, &vpp[i]);
1186 }
1187 pathbuf_destroy(pb);
1188 if (error != 0) {
1189 for (j = 0; j < lookedup; ++j)
1190 (void)vn_close(vpp[j], FREAD|FWRITE,
1191 uc);
1192 kmem_free(vpp, ccio->ccio_ndisks *
1193 sizeof(*vpp));
1194 kmem_free(cpp, ccio->ccio_ndisks *
1195 sizeof(*cpp));
1196 goto out;
1197 }
1198 ++lookedup;
1199 }
1200
1201 /* Attach the disk. */
1202 disk_attach(&cs->sc_dkdev);
1203 bufq_alloc(&cs->sc_bufq, "fcfs", 0);
1204
1205 /*
1206 * Initialize the ccd. Fills in the softc for us.
1207 */
1208 if ((error = ccdinit(cs, cpp, vpp, l)) != 0) {
1209 for (j = 0; j < lookedup; ++j)
1210 (void)vn_close(vpp[j], FREAD|FWRITE,
1211 uc);
1212 kmem_free(vpp, ccio->ccio_ndisks * sizeof(*vpp));
1213 kmem_free(cpp, ccio->ccio_ndisks * sizeof(*cpp));
1214 disk_detach(&cs->sc_dkdev);
1215 bufq_free(cs->sc_bufq);
1216 goto out;
1217 }
1218
1219 /* We can free the temporary variables now. */
1220 kmem_free(vpp, ccio->ccio_ndisks * sizeof(*vpp));
1221 kmem_free(cpp, ccio->ccio_ndisks * sizeof(*cpp));
1222
1223 /*
1224 * The ccd has been successfully initialized, so
1225 * we can place it into the array. Don't try to
1226 * read the disklabel until the disk has been attached,
1227 * because space for the disklabel is allocated
1228 * in disk_attach();
1229 */
1230 ccio->ccio_unit = unit;
1231 ccio->ccio_size = cs->sc_size;
1232
1233 /* Try and read the disklabel. */
1234 ccdgetdisklabel(dev);
1235 break;
1236
1237 case CCDIOCCLR:
1238 /*
1239 * Don't unconfigure if any other partitions are open
1240 * or if both the character and block flavors of this
1241 * partition are open.
1242 */
1243 part = DISKPART(dev);
1244 pmask = (1 << part);
1245 if ((cs->sc_dkdev.dk_openmask & ~pmask) ||
1246 ((cs->sc_dkdev.dk_bopenmask & pmask) &&
1247 (cs->sc_dkdev.dk_copenmask & pmask))) {
1248 error = EBUSY;
1249 goto out;
1250 }
1251
1252 /* Stop new I/O, wait for in-flight I/O to complete. */
1253 mutex_enter(cs->sc_iolock);
1254 cs->sc_flags &= ~(CCDF_INITED|CCDF_VLABEL);
1255 cs->sc_zap = true;
1256 while (disk_isbusy(&cs->sc_dkdev) ||
1257 bufq_peek(cs->sc_bufq) != NULL ||
1258 cs->sc_thread != NULL) {
1259 cv_broadcast(&cs->sc_push);
1260 (void)cv_timedwait(&cs->sc_stop, cs->sc_iolock, hz);
1261 }
1262 mutex_exit(cs->sc_iolock);
1263
1264 /*
1265 * Free ccd_softc information and clear entry.
1266 */
1267
1268 /* Close the components and free their pathnames. */
1269 for (i = 0; i < cs->sc_nccdisks; ++i) {
1270 /*
1271 * XXX: this close could potentially fail and
1272 * cause Bad Things. Maybe we need to force
1273 * the close to happen?
1274 */
1275 #ifdef DEBUG
1276 if (ccddebug & CCDB_VNODE)
1277 vprint("CCDIOCCLR: vnode info",
1278 cs->sc_cinfo[i].ci_vp);
1279 #endif
1280 (void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE,
1281 uc);
1282 kmem_free(cs->sc_cinfo[i].ci_path,
1283 cs->sc_cinfo[i].ci_pathlen);
1284 }
1285
1286 /* Free interleave index. */
1287 for (i = 0; cs->sc_itable[i].ii_ndisk; ++i) {
1288 kmem_free(cs->sc_itable[i].ii_index,
1289 cs->sc_itable[i].ii_indexsz);
1290 }
1291
1292 /* Free component info and interleave table. */
1293 kmem_free(cs->sc_cinfo, cs->sc_nccdisks *
1294 sizeof(struct ccdcinfo));
1295 kmem_free(cs->sc_itable, (cs->sc_nccdisks + 1) *
1296 sizeof(struct ccdiinfo));
1297
1298 aprint_normal("%s: detached\n", cs->sc_xname);
1299
1300 /* Detach the disk. */
1301 disk_detach(&cs->sc_dkdev);
1302 bufq_free(cs->sc_bufq);
1303 break;
1304
1305 case DIOCGDINFO:
1306 *(struct disklabel *)data = *(cs->sc_dkdev.dk_label);
1307 break;
1308
1309 #ifdef __HAVE_OLD_DISKLABEL
1310 case ODIOCGDINFO:
1311 newlabel = *(cs->sc_dkdev.dk_label);
1312 if (newlabel.d_npartitions > OLDMAXPARTITIONS)
1313 return ENOTTY;
1314 memcpy(data, &newlabel, sizeof (struct olddisklabel));
1315 break;
1316 #endif
1317
1318 case DIOCGPART:
1319 ((struct partinfo *)data)->disklab = cs->sc_dkdev.dk_label;
1320 ((struct partinfo *)data)->part =
1321 &cs->sc_dkdev.dk_label->d_partitions[DISKPART(dev)];
1322 break;
1323
1324 case DIOCCACHESYNC:
1325 /*
1326 * XXX Do we really need to care about having a writable
1327 * file descriptor here?
1328 */
1329 if ((flag & FWRITE) == 0)
1330 return (EBADF);
1331
1332 /*
1333 * We pass this call down to all components and report
1334 * the first error we encounter.
1335 */
1336 for (error = 0, i = 0; i < cs->sc_nccdisks; i++) {
1337 j = VOP_IOCTL(cs->sc_cinfo[i].ci_vp, cmd, data,
1338 flag, uc);
1339 if (j != 0 && error == 0)
1340 error = j;
1341 }
1342 break;
1343
1344 case DIOCWDINFO:
1345 case DIOCSDINFO:
1346 #ifdef __HAVE_OLD_DISKLABEL
1347 case ODIOCWDINFO:
1348 case ODIOCSDINFO:
1349 #endif
1350 {
1351 struct disklabel *lp;
1352 #ifdef __HAVE_OLD_DISKLABEL
1353 if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) {
1354 memset(&newlabel, 0, sizeof newlabel);
1355 memcpy(&newlabel, data, sizeof (struct olddisklabel));
1356 lp = &newlabel;
1357 } else
1358 #endif
1359 lp = (struct disklabel *)data;
1360
1361 cs->sc_flags |= CCDF_LABELLING;
1362
1363 error = setdisklabel(cs->sc_dkdev.dk_label,
1364 lp, 0, cs->sc_dkdev.dk_cpulabel);
1365 if (error == 0) {
1366 if (cmd == DIOCWDINFO
1367 #ifdef __HAVE_OLD_DISKLABEL
1368 || cmd == ODIOCWDINFO
1369 #endif
1370 )
1371 error = writedisklabel(CCDLABELDEV(dev),
1372 ccdstrategy, cs->sc_dkdev.dk_label,
1373 cs->sc_dkdev.dk_cpulabel);
1374 }
1375
1376 cs->sc_flags &= ~CCDF_LABELLING;
1377 break;
1378 }
1379
1380 case DIOCKLABEL:
1381 if (*(int *)data != 0)
1382 cs->sc_flags |= CCDF_KLABEL;
1383 else
1384 cs->sc_flags &= ~CCDF_KLABEL;
1385 break;
1386
1387 case DIOCWLABEL:
1388 if (*(int *)data != 0)
1389 cs->sc_flags |= CCDF_WLABEL;
1390 else
1391 cs->sc_flags &= ~CCDF_WLABEL;
1392 break;
1393
1394 case DIOCGDEFLABEL:
1395 ccdgetdefaultlabel(cs, (struct disklabel *)data);
1396 break;
1397
1398 #ifdef __HAVE_OLD_DISKLABEL
1399 case ODIOCGDEFLABEL:
1400 ccdgetdefaultlabel(cs, &newlabel);
1401 if (newlabel.d_npartitions > OLDMAXPARTITIONS)
1402 return ENOTTY;
1403 memcpy(data, &newlabel, sizeof (struct olddisklabel));
1404 break;
1405 #endif
1406
1407 default:
1408 error = ENOTTY;
1409 }
1410
1411 out:
1412 mutex_exit(&cs->sc_dvlock);
1413 return (error);
1414 }
1415
1416 static int
1417 ccdsize(dev_t dev)
1418 {
1419 struct ccd_softc *cs;
1420 struct disklabel *lp;
1421 int part, unit, omask, size;
1422
1423 unit = ccdunit(dev);
1424 if (unit >= numccd)
1425 return (-1);
1426 cs = &ccd_softc[unit];
1427
1428 if ((cs->sc_flags & CCDF_INITED) == 0)
1429 return (-1);
1430
1431 part = DISKPART(dev);
1432 omask = cs->sc_dkdev.dk_openmask & (1 << part);
1433 lp = cs->sc_dkdev.dk_label;
1434
1435 if (omask == 0 && ccdopen(dev, 0, S_IFBLK, curlwp))
1436 return (-1);
1437
1438 if (lp->d_partitions[part].p_fstype != FS_SWAP)
1439 size = -1;
1440 else
1441 size = lp->d_partitions[part].p_size *
1442 (lp->d_secsize / DEV_BSIZE);
1443
1444 if (omask == 0 && ccdclose(dev, 0, S_IFBLK, curlwp))
1445 return (-1);
1446
1447 return (size);
1448 }
1449
1450 static void
1451 ccdgetdefaultlabel(struct ccd_softc *cs, struct disklabel *lp)
1452 {
1453 struct ccdgeom *ccg = &cs->sc_geom;
1454
1455 memset(lp, 0, sizeof(*lp));
1456
1457 lp->d_secperunit = cs->sc_size;
1458 lp->d_secsize = ccg->ccg_secsize;
1459 lp->d_nsectors = ccg->ccg_nsectors;
1460 lp->d_ntracks = ccg->ccg_ntracks;
1461 lp->d_ncylinders = ccg->ccg_ncylinders;
1462 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1463
1464 strncpy(lp->d_typename, "ccd", sizeof(lp->d_typename));
1465 lp->d_type = DTYPE_CCD;
1466 strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
1467 lp->d_rpm = 3600;
1468 lp->d_interleave = 1;
1469 lp->d_flags = 0;
1470
1471 lp->d_partitions[RAW_PART].p_offset = 0;
1472 lp->d_partitions[RAW_PART].p_size = cs->sc_size;
1473 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
1474 lp->d_npartitions = RAW_PART + 1;
1475
1476 lp->d_magic = DISKMAGIC;
1477 lp->d_magic2 = DISKMAGIC;
1478 lp->d_checksum = dkcksum(cs->sc_dkdev.dk_label);
1479 }
1480
1481 /*
1482 * Read the disklabel from the ccd. If one is not present, fake one
1483 * up.
1484 */
1485 static void
1486 ccdgetdisklabel(dev_t dev)
1487 {
1488 int unit = ccdunit(dev);
1489 struct ccd_softc *cs = &ccd_softc[unit];
1490 const char *errstring;
1491 struct disklabel *lp = cs->sc_dkdev.dk_label;
1492 struct cpu_disklabel *clp = cs->sc_dkdev.dk_cpulabel;
1493
1494 KASSERT(mutex_owned(&cs->sc_dvlock));
1495
1496 memset(clp, 0, sizeof(*clp));
1497
1498 ccdgetdefaultlabel(cs, lp);
1499
1500 /*
1501 * Call the generic disklabel extraction routine.
1502 */
1503 cs->sc_flags |= CCDF_RLABEL;
1504 if ((cs->sc_flags & CCDF_NOLABEL) != 0)
1505 errstring = "CCDF_NOLABEL set; ignoring on-disk label";
1506 else
1507 errstring = readdisklabel(CCDLABELDEV(dev), ccdstrategy,
1508 cs->sc_dkdev.dk_label, cs->sc_dkdev.dk_cpulabel);
1509 if (errstring)
1510 ccdmakedisklabel(cs);
1511 else {
1512 int i;
1513 struct partition *pp;
1514
1515 /*
1516 * Sanity check whether the found disklabel is valid.
1517 *
1518 * This is necessary since total size of ccd may vary
1519 * when an interleave is changed even though exactly
1520 * same componets are used, and old disklabel may used
1521 * if that is found.
1522 */
1523 if (lp->d_secperunit != cs->sc_size)
1524 printf("WARNING: %s: "
1525 "total sector size in disklabel (%ju) != "
1526 "the size of ccd (%ju)\n", cs->sc_xname,
1527 (uintmax_t)lp->d_secperunit,
1528 (uintmax_t)cs->sc_size);
1529 for (i = 0; i < lp->d_npartitions; i++) {
1530 pp = &lp->d_partitions[i];
1531 if (pp->p_offset + pp->p_size > cs->sc_size)
1532 printf("WARNING: %s: end of partition `%c' "
1533 "exceeds the size of ccd (%ju)\n",
1534 cs->sc_xname, 'a' + i, (uintmax_t)cs->sc_size);
1535 }
1536 }
1537
1538 #ifdef DEBUG
1539 /* It's actually extremely common to have unlabeled ccds. */
1540 if (ccddebug & CCDB_LABEL)
1541 if (errstring != NULL)
1542 printf("%s: %s\n", cs->sc_xname, errstring);
1543 #endif
1544
1545 /* In-core label now valid. */
1546 cs->sc_flags = (cs->sc_flags | CCDF_VLABEL) & ~CCDF_RLABEL;
1547 }
1548
1549 /*
1550 * Take care of things one might want to take care of in the event
1551 * that a disklabel isn't present.
1552 */
1553 static void
1554 ccdmakedisklabel(struct ccd_softc *cs)
1555 {
1556 struct disklabel *lp = cs->sc_dkdev.dk_label;
1557
1558 /*
1559 * For historical reasons, if there's no disklabel present
1560 * the raw partition must be marked FS_BSDFFS.
1561 */
1562 lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS;
1563
1564 strncpy(lp->d_packname, "default label", sizeof(lp->d_packname));
1565
1566 lp->d_checksum = dkcksum(lp);
1567 }
1568
1569 #ifdef DEBUG
1570 static void
1571 printiinfo(struct ccdiinfo *ii)
1572 {
1573 int ix, i;
1574
1575 for (ix = 0; ii->ii_ndisk; ix++, ii++) {
1576 printf(" itab[%d]: #dk %d sblk %" PRId64 " soff %" PRId64,
1577 ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff);
1578 for (i = 0; i < ii->ii_ndisk; i++)
1579 printf(" %d", ii->ii_index[i]);
1580 printf("\n");
1581 }
1582 }
1583 #endif
1584
1585 MODULE(MODULE_CLASS_DRIVER, ccd, NULL);
1586
1587 static int
1588 ccd_modcmd(modcmd_t cmd, void *arg)
1589 {
1590 int bmajor, cmajor, error = 0;
1591
1592 bmajor = cmajor = -1;
1593
1594 switch (cmd) {
1595 case MODULE_CMD_INIT:
1596 #ifdef _MODULE
1597 ccdattach(4);
1598
1599 return devsw_attach("ccd", &ccd_bdevsw, &bmajor,
1600 &ccd_cdevsw, &cmajor);
1601 #endif
1602 break;
1603
1604 case MODULE_CMD_FINI:
1605 #ifdef _MODULE
1606 return devsw_detach(&ccd_bdevsw, &ccd_cdevsw);
1607 #endif
1608 break;
1609
1610 case MODULE_CMD_STAT:
1611 return ENOTTY;
1612
1613 default:
1614 return ENOTTY;
1615 }
1616
1617 return error;
1618 }
1619