1 /* $NetBSD: disksubr.c,v 1.4 2019/04/17 20:46:38 skrll Exp $ */
2
3 /* $OpenBSD: disksubr.c,v 1.6 2000/10/18 21:00:34 mickey Exp $ */
4
5 /*
6 * Copyright (c) 1999 Michael Shalayeff
7 * Copyright (c) 1997 Niklas Hallqvist
8 * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * @(#)ufs_disksubr.c 7.16 (Berkeley) 5/4/91
36 */
37
38 /*
39 * Copyright (c) 1996 Theo de Raadt. All rights reserved.
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 *
50 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
51 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
52 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
53 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
54 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
55 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
56 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
57 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
58 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
59 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
60 */
61
62 /*
63 * This disksubr.c module started to take its present form on OpenBSD/alpha
64 * but it was always thought it should be made completely MI and not need to
65 * be in that alpha-specific tree at all.
66 *
67 * XXX HPUX disklabel is not understood yet.
68 */
69
70 #include <sys/cdefs.h>
71 __KERNEL_RCSID(0, "$NetBSD: disksubr.c,v 1.4 2019/04/17 20:46:38 skrll Exp $");
72
73 #include <sys/param.h>
74 #include <sys/systm.h>
75 #include <sys/buf.h>
76 #include <sys/device.h>
77 #include <sys/disklabel.h>
78 #include <sys/syslog.h>
79 #include <sys/disk.h>
80
81 const char *readliflabel(struct buf *, void (*)(struct buf *),
82 struct disklabel *, struct cpu_disklabel *, int *, int *, int);
83 const char *readbsdlabel(struct buf *, void (*)(struct buf *), int,
84 int, int, struct disklabel *, int);
85
86 /*
87 * Try to read a standard BSD disklabel at a certain sector.
88 */
89 const char *
readbsdlabel(struct buf * bp,void (* strat)(struct buf *),int cyl,int sec,int off,struct disklabel * lp,int spoofonly)90 readbsdlabel(struct buf *bp, void (*strat)(struct buf *), int cyl, int sec,
91 int off, struct disklabel *lp, int spoofonly)
92 {
93 struct disklabel *dlp;
94 const char *msg = NULL;
95 uint16_t cksum;
96
97 /* don't read the on-disk label if we are in spoofed-only mode */
98 if (spoofonly)
99 return (NULL);
100
101 bp->b_blkno = sec;
102 bp->b_cylinder = cyl;
103 bp->b_bcount = lp->d_secsize;
104 bp->b_cflags = BC_BUSY;
105 bp->b_flags = B_READ;
106 bp->b_oflags = 0;
107 (*strat)(bp);
108
109 /* if successful, locate disk label within block and validate */
110 if (biowait(bp)) {
111 /* XXX we return the faked label built so far */
112 msg = "disk label I/O error";
113 return (msg);
114 }
115
116 /*
117 * If off is negative, search until the end of the sector for
118 * the label, otherwise, just look at the specific location
119 * we're given.
120 */
121 dlp = (struct disklabel *)((char *)bp->b_data + (off >= 0 ? off : 0));
122 do {
123 if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) {
124 if (msg == NULL)
125 msg = "no disk label";
126 } else {
127 cksum = dkcksum(dlp);
128 if (dlp->d_npartitions > MAXPARTITIONS || cksum != 0) {
129 msg = "disk label corrupted";
130 } else {
131 *lp = *dlp;
132 msg = NULL;
133 break;
134 }
135 }
136 if (off >= 0)
137 break;
138 dlp = (struct disklabel *)((char *)dlp + sizeof(int32_t));
139 } while (dlp <= (struct disklabel *)((char *)bp->b_data +
140 lp->d_secsize - sizeof(*dlp)));
141 return (msg);
142 }
143
144 /*
145 * Attempt to read a disk label from a device
146 * using the indicated strategy routine.
147 * The label must be partly set up before this:
148 * secpercyl, secsize and anything required for a block i/o read
149 * operation in the driver's strategy/start routines
150 * must be filled in before calling us.
151 *
152 * Returns null on success and an error string on failure.
153 */
154 const char *
readdisklabel(dev_t dev,void (* strat)(struct buf *),struct disklabel * lp,struct cpu_disklabel * osdep)155 readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
156 struct cpu_disklabel *osdep)
157 {
158 int spoofonly = 0;
159 struct buf *bp = NULL;
160 const char *msg = "no disk label";
161 int i;
162 struct disklabel fallbacklabel;
163
164 /* minimal requirements for archetypal disk label */
165 if (lp->d_secsize == 0)
166 lp->d_secsize = DEV_BSIZE;
167 if (lp->d_secperunit == 0)
168 lp->d_secperunit = 0x1fffffff;
169 if (lp->d_secpercyl == 0)
170 return "invalid geometry";
171
172 lp->d_npartitions = RAW_PART + 1;
173 for (i = 0; i < RAW_PART; i++) {
174 lp->d_partitions[i].p_size = 0;
175 lp->d_partitions[i].p_offset = 0;
176 }
177 if (lp->d_partitions[i].p_size == 0)
178 lp->d_partitions[i].p_size = 0x1fffffff;
179 lp->d_partitions[i].p_offset = 0;
180 fallbacklabel = *lp;
181
182 /* get a buffer and initialize it */
183 bp = geteblk((int)lp->d_secsize);
184 bp->b_dev = dev;
185
186 msg = readliflabel(bp, strat, lp, osdep, 0, 0, spoofonly);
187
188 #if defined(CD9660)
189 if (msg && iso_disklabelspoof(dev, strat, lp) == 0)
190 msg = NULL;
191 #endif
192
193 /* If there was an error, still provide a decent fake one. */
194 if (msg)
195 *lp = fallbacklabel;
196
197 if (bp) {
198 brelse(bp, BC_INVAL);
199 }
200 return (msg);
201 }
202
203
204 const char *
readliflabel(struct buf * bp,void (* strat)(struct buf *),struct disklabel * lp,struct cpu_disklabel * osdep,int * partoffp,int * cylp,int spoofonly)205 readliflabel(struct buf *bp, void (*strat)(struct buf *), struct disklabel *lp,
206 struct cpu_disklabel *osdep, int *partoffp, int *cylp, int spoofonly)
207 {
208 int fsoff;
209
210 /* read LIF volume header */
211 bp->b_blkno = btodb(HPPA_LIF_VOLSTART);
212 bp->b_bcount = lp->d_secsize;
213 bp->b_cflags = BC_BUSY;
214 bp->b_flags = B_READ;
215 bp->b_cylinder = btodb(HPPA_LIF_VOLSTART) / lp->d_secpercyl;
216 (*strat)(bp);
217
218 if (biowait(bp)) {
219 if (partoffp)
220 *partoffp = -1;
221 return "LIF volume header I/O error";
222 }
223
224 memcpy(&osdep->lifvol, bp->b_data, sizeof(struct hppa_lifvol));
225 if (osdep->lifvol.vol_id != HPPA_LIF_VOL_ID) {
226 fsoff = 0;
227 } else {
228 struct buf *dbp;
229 struct hppa_lifdir *p;
230
231 dbp = geteblk(lp->d_secsize);
232 dbp->b_dev = bp->b_dev;
233
234 /* read LIF directory */
235 dbp->b_blkno = btodb(HPPA_LIF_DIRSTART);
236 dbp->b_bcount = lp->d_secsize;
237 dbp->b_cflags = BC_BUSY;
238 dbp->b_flags = B_READ;
239 dbp->b_cylinder = (HPPA_LIF_DIRSTART) / lp->d_secpercyl;
240
241 (*strat)(dbp);
242
243 if (biowait(dbp)) {
244 if (partoffp)
245 *partoffp = -1;
246 brelse(dbp, BC_INVAL);
247
248 return "LIF directory I/O error";
249 }
250
251 memcpy(osdep->lifdir, dbp->b_data, HPPA_LIF_DIRSIZE);
252 brelse(dbp, BC_INVAL);
253 /* scan for LIF_DIR_FS dir entry */
254 for (fsoff = -1, p = &osdep->lifdir[0];
255 fsoff < 0 && p < &osdep->lifdir[HPPA_LIF_NUMDIR]; p++)
256 if (p->dir_type == HPPA_LIF_DIR_FS)
257 fsoff = hppa_lifstodb(p->dir_addr);
258
259 /* if no suitable lifdir entry found assume 0 */
260 if (fsoff < 0)
261 fsoff = 0;
262 }
263
264 if (partoffp)
265 *partoffp = fsoff;
266
267 return readbsdlabel(bp, strat, 0, fsoff + LABELSECTOR, LABELOFFSET,
268 lp, spoofonly);
269 }
270
271 /*
272 * Write disk label back to device after modification.
273 */
274 int
writedisklabel(dev_t dev,void (* strat)(struct buf *),struct disklabel * lp,struct cpu_disklabel * osdep)275 writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
276 struct cpu_disklabel *osdep)
277 {
278 const char *msg = "no disk label";
279 struct buf *bp;
280 struct disklabel dl;
281 struct cpu_disklabel cdl;
282 int labeloffset, error, partoff = 0, cyl = 0;
283
284 /* get a buffer and initialize it */
285 bp = geteblk((int)lp->d_secsize);
286 bp->b_dev = dev;
287
288 /*
289 * I once played with the thought of using osdep->label{tag,sector}
290 * as a cache for knowing where (and what) to write. However, now I
291 * think it might be useful to reprobe if someone has written
292 * a newer disklabel of another type with disklabel(8) and -r.
293 */
294 dl = *lp;
295 msg = readliflabel(bp, strat, &dl, &cdl, &partoff, &cyl, 0);
296 labeloffset = LABELOFFSET;
297
298 if (msg) {
299 if (partoff == -1)
300 return EIO;
301
302 /* Write it in the regular place with native byte order. */
303 labeloffset = LABELOFFSET;
304 bp->b_blkno = partoff + LABELSECTOR;
305 bp->b_cylinder = cyl;
306 bp->b_bcount = lp->d_secsize;
307 }
308
309 *(struct disklabel *)((char *)bp->b_data + labeloffset) = *lp;
310
311 bp->b_cflags = BC_BUSY;
312 bp->b_flags = B_WRITE;
313 (*strat)(bp);
314 error = biowait(bp);
315
316 brelse(bp, BC_INVAL);
317 return (error);
318 }
319