1 /* $NetBSD: disksubr.c,v 1.8 2009/08/02 12:04:28 uch Exp $ */
2
3 /*-
4 * Copyright (c) 2004 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by UCHIYAMA Yasushi.
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 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: disksubr.c,v 1.8 2009/08/02 12:04:28 uch Exp $");
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/disk.h>
38 #include <sys/buf.h>
39 #include <sys/disklabel.h>
40
41 #include <machine/sector.h>
42
43 #define DISKLABEL_DEBUG
44
45 #ifdef DISKLABEL_DEBUG
46 #define DPRINTF(fmt, args...) printf(fmt, ##args)
47 #else
48 #define DPRINTF(arg...) ((void)0)
49 #endif
50
51 const char *
readdisklabel(dev_t dev,void (* strategy)(struct buf *),struct disklabel * d,struct cpu_disklabel * ux)52 readdisklabel(dev_t dev, void (*strategy)(struct buf *), struct disklabel *d,
53 struct cpu_disklabel *ux)
54 {
55 uint8_t buf[DEV_BSIZE];
56 struct pdinfo_sector *pdinfo = &ux->pdinfo;
57 struct vtoc_sector *vtoc = &ux->vtoc;
58 bool disklabel_available = false;
59 bool vtoc_available = false;
60 void *rwops;
61
62 if ((rwops = sector_init(dev, strategy)) == 0)
63 return "can't read/write disk";
64
65 /* Read VTOC */
66 if (!pdinfo_sector(rwops, pdinfo) || !pdinfo_sanity(pdinfo)) {
67 DPRINTF("%s: PDINFO not found.\n", __func__);
68 } else if (vtoc_sector(rwops, vtoc, pdinfo->logical_sector) &&
69 vtoc_sanity(vtoc)) {
70 vtoc_available = true;
71
72 /* Read BSD DISKLABEL (if any) */
73 sector_read(rwops, buf, LABELSECTOR);
74 if (disklabel_sanity((struct disklabel *)buf)) {
75 disklabel_available = true;
76 memcpy(d, buf, sizeof(struct disklabel));
77 } else {
78 DPRINTF("%s: no BSD disklabel.\n", __func__);
79 }
80 } else {
81 DPRINTF("%s: PDINFO found, but VTOC not found.\n", __func__);
82 }
83 sector_fini(rwops);
84
85 /* If there is no BSD disklabel, convert from VTOC */
86 if (!disklabel_available) {
87 if (vtoc_available) {
88 DPRINTF("%s: creating disklabel from VTOC.\n",
89 __func__);
90 } else {
91 DPRINTF("%s: no VTOC. creating default disklabel.\n",
92 __func__);
93 vtoc_set_default(ux, d);
94 }
95 disklabel_set_default(d);
96 vtoc_to_disklabel(ux, d);
97 }
98
99 return 0;
100 }
101
102 int
setdisklabel(struct disklabel * od,struct disklabel * nd,u_long openmask,struct cpu_disklabel * ux)103 setdisklabel(struct disklabel *od, struct disklabel *nd, u_long openmask,
104 struct cpu_disklabel *ux)
105 {
106
107 KDASSERT(openmask == 0); /* openmask is obsolete. -uch */
108
109 if (!disklabel_sanity(nd))
110 return EINVAL;
111
112 *od = *nd;
113
114 return 0;
115 }
116
117 int
writedisklabel(dev_t dev,void (* strategy)(struct buf *),struct disklabel * d,struct cpu_disklabel * ux)118 writedisklabel(dev_t dev, void (*strategy)(struct buf *), struct disklabel *d,
119 struct cpu_disklabel *ux)
120 {
121 uint8_t buf[DEV_BSIZE];
122 int err = 0;
123 void *rwops;
124
125 if (!disklabel_sanity(d))
126 return EINVAL;
127
128 /* 1. Update VTOC */
129 disklabel_to_vtoc(ux, d);
130 DPRINTF("%s: logical_sector=%d\n", __func__, ux->pdinfo.logical_sector);
131
132 if ((rwops = sector_init(dev, strategy)) == 0)
133 return ENOMEM;
134 pdinfo_sanity(&ux->pdinfo);
135 vtoc_sanity(&ux->vtoc);
136
137 /* 2. Write VTOC to bootblock */
138 sector_write(rwops, (void *)&ux->pdinfo, PDINFO_SECTOR);
139 sector_write(rwops, (void *)&ux->vtoc,
140 ux->pdinfo.logical_sector + VTOC_SECTOR);
141
142 /* 3. Write disklabel to LABELSECTOR */
143 memset(buf, 0, sizeof buf);
144 memcpy(buf, d, sizeof *d);
145 if (!sector_write(rwops, buf, LABELSECTOR)) {
146 DPRINTF("%s: failed to write disklabel.\n", __func__);
147 err = EIO;
148 }
149 sector_fini(rwops);
150
151 return err;
152 }
153