1 /* $NetBSD: disksubr.c,v 1.34 2023/01/15 05:08:33 tsutsui Exp $ */
2
3 /*
4 * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 * Credits:
32 * This file was based mostly on the i386/disksubr.c file:
33 * @(#)ufs_disksubr.c 7.16 (Berkeley) 5/4/91
34 * The functions: disklabel_sun_to_bsd, disklabel_bsd_to_sun
35 * were originally taken from arch/sparc/scsi/sun_disklabel.c
36 * (which was written by Theo de Raadt) and then substantially
37 * rewritten by Gordon W. Ross.
38 */
39
40 /*
41 * Copyright (c) 1994 Theo de Raadt. All rights reserved.
42 *
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
45 * are met:
46 * 1. Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright
49 * notice, this list of conditions and the following disclaimer in the
50 * documentation and/or other materials provided with the distribution.
51 *
52 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
53 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
54 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
55 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
56 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
57 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
58 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
59 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
60 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
61 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
62 *
63 */
64
65 /*
66 * Copyright (c) 1994, 1995 Gordon W. Ross
67 *
68 * Redistribution and use in source and binary forms, with or without
69 * modification, are permitted provided that the following conditions
70 * are met:
71 * 1. Redistributions of source code must retain the above copyright
72 * notice, this list of conditions and the following disclaimer.
73 * 2. Redistributions in binary form must reproduce the above copyright
74 * notice, this list of conditions and the following disclaimer in the
75 * documentation and/or other materials provided with the distribution.
76 * 3. All advertising materials mentioning features or use of this software
77 * must display the following acknowledgement:
78 * This product includes software developed by the University of
79 * California, Berkeley and its contributors.
80 * 4. Neither the name of the University nor the names of its contributors
81 * may be used to endorse or promote products derived from this software
82 * without specific prior written permission.
83 *
84 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
85 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
86 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
87 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
88 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
89 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
90 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
91 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
92 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
93 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
94 * SUCH DAMAGE.
95 *
96 * Credits:
97 * This file was based mostly on the i386/disksubr.c file:
98 * @(#)ufs_disksubr.c 7.16 (Berkeley) 5/4/91
99 * The functions: disklabel_sun_to_bsd, disklabel_bsd_to_sun
100 * were originally taken from arch/sparc/scsi/sun_disklabel.c
101 * (which was written by Theo de Raadt) and then substantially
102 * rewritten by Gordon W. Ross.
103 */
104
105 #include <sys/cdefs.h>
106 __KERNEL_RCSID(0, "$NetBSD: disksubr.c,v 1.34 2023/01/15 05:08:33 tsutsui Exp $");
107
108 #include <sys/param.h>
109 #include <sys/systm.h>
110 #include <sys/buf.h>
111 #include <sys/device.h>
112 #include <sys/disklabel.h>
113 #include <sys/disk.h>
114 #include <sys/dkbad.h>
115
116 #include <dev/sun/disklabel.h>
117
118 /*
119 * UniOS disklabel (== ISI disklabel) is very similar to SunOS.
120 * SunOS UniOS/ISI
121 * text 128 128
122 * (pad) 292 294
123 * rpm 2 -
124 * pcyl 2 badchk 2
125 * sparecyl 2 maxblk 4
126 * (pad) 4 dtype 2
127 * interleave 2 ndisk 2
128 * ncyl 2 2
129 * acyl 2 2
130 * ntrack 2 2
131 * nsect 2 2
132 * (pad) 4 bhead 2
133 * - ppart 2
134 * dkpart[8] 64 64
135 * magic 2 2
136 * cksum 2 2
137 *
138 * Magic number value and checksum calculation are identical. Subtle
139 * difference is partition start address; UniOS/ISI maintains sector
140 * numbers while SunOS label has cylinder number.
141 *
142 * It is found that LUNA Mach2.5 has BSD label embedded at offset 64
143 * retaining UniOS/ISI label at the end of label block. LUNA Mach
144 * manipulates BSD disklabel in the same manner as 4.4BSD. It's
145 * uncertain LUNA Mach can create a disklabel on fresh disks since
146 * Mach writedisklabel logic seems to fail when no BSD label is found.
147 *
148 * Kernel handles disklabel in this way;
149 * - searches BSD label at offset 64
150 * - if not found, searches UniOS/ISI label at the end of block
151 * - kernel can distinguish whether it was SunOS label or UniOS/ISI
152 * label and understand both
153 * - kernel writes UniOS/ISI label combined with BSD label to update
154 * the label block
155 */
156
157 #if LABELSECTOR != 0
158 #error "Default value of LABELSECTOR no longer zero?"
159 #endif
160
161 static const char *disklabel_om_to_bsd(char *, struct disklabel *);
162 static int disklabel_bsd_to_om(struct disklabel *, char *);
163
164 /*
165 * Attempt to read a disk label from a device
166 * using the indicated strategy routine.
167 * The label must be partly set up before this:
168 * secpercyl, secsize and anything required for a block i/o read
169 * operation in the driver's strategy/start routines
170 * must be filled in before calling us.
171 *
172 * Return buffer for use in signalling errors if requested.
173 *
174 * Returns null on success and an error string on failure.
175 */
176 const char *
readdisklabel(dev_t dev,void (* strat)(struct buf *),struct disklabel * lp,struct cpu_disklabel * clp)177 readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, struct cpu_disklabel *clp)
178 {
179 struct buf *bp;
180 struct disklabel *dlp;
181 struct sun_disklabel *slp;
182 int error;
183 int i;
184
185 /* minimal requirements for archtypal disk label */
186 if (lp->d_secperunit == 0)
187 lp->d_secperunit = 0x1fffffff;
188 if (lp->d_npartitions < RAW_PART + 1)
189 lp->d_npartitions = RAW_PART + 1;
190 for (i = 0; i < RAW_PART; i++) {
191 lp->d_partitions[i].p_size = 0;
192 lp->d_partitions[i].p_offset = 0;
193 }
194 if (lp->d_partitions[RAW_PART].p_size == 0)
195 lp->d_partitions[RAW_PART].p_size = lp->d_secperunit;
196 lp->d_partitions[RAW_PART].p_offset = 0;
197
198 /* obtain buffer to probe drive with */
199 bp = geteblk((int)lp->d_secsize);
200
201 /* next, dig out disk label */
202 bp->b_dev = dev;
203 bp->b_blkno = LABELSECTOR;
204 bp->b_cylinder = 0;
205 bp->b_bcount = lp->d_secsize;
206 bp->b_flags |= B_READ;
207 (*strat)(bp);
208
209 /* if successful, locate disk label within block and validate */
210 error = biowait(bp);
211 if (!error) {
212 /* Save the whole block in case it has info we need. */
213 memcpy(clp->cd_block, bp->b_data, sizeof(clp->cd_block));
214 }
215 brelse(bp, 0);
216 if (error)
217 return ("disk label read error");
218
219 /* Check for a NetBSD disk label first. */
220 dlp = (struct disklabel *)(clp->cd_block + LABELOFFSET);
221 if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC) {
222 if (dkcksum(dlp) == 0) {
223 *lp = *dlp; /* struct assignment */
224 return (NULL);
225 }
226 printf("NetBSD disk label corrupted");
227 }
228
229 /* Check for a UniOS/ISI disk label. */
230 slp = (struct sun_disklabel *)clp->cd_block;
231 if (slp->sl_magic == SUN_DKMAGIC) {
232 return (disklabel_om_to_bsd(clp->cd_block, lp));
233 }
234
235 memset(clp->cd_block, 0, sizeof(clp->cd_block));
236 return ("no disk label");
237 }
238
239 /*
240 * Write disk label back to device after modification.
241 * Current label is already in clp->cd_block[]
242 */
243 int
writedisklabel(dev_t dev,void (* strat)(struct buf *),struct disklabel * lp,struct cpu_disklabel * clp)244 writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, struct cpu_disklabel *clp)
245 {
246 struct buf *bp;
247 struct disklabel *dlp;
248 int error;
249
250 /* implant NetBSD disklabel at LABELOFFSET. */
251 dlp = (struct disklabel *)(clp->cd_block + LABELOFFSET);
252 *dlp = *lp; /* struct assignment */
253
254 error = disklabel_bsd_to_om(lp, clp->cd_block);
255 if (error)
256 return (error);
257
258 /* Get a buffer and copy the new label into it. */
259 bp = geteblk((int)lp->d_secsize);
260 memcpy(bp->b_data, clp->cd_block, sizeof(clp->cd_block));
261
262 /* Write out the updated label. */
263 bp->b_dev = dev;
264 bp->b_blkno = LABELSECTOR;
265 bp->b_cylinder = 0;
266 bp->b_bcount = lp->d_secsize;
267 bp->b_flags |= B_WRITE;
268 (*strat)(bp);
269 error = biowait(bp);
270 brelse(bp, 0);
271
272 return (error);
273 }
274
275 /************************************************************************
276 *
277 * The rest of this was taken from arch/sparc/scsi/sun_disklabel.c
278 * and then substantially rewritten by Gordon W. Ross
279 *
280 ************************************************************************/
281
282 /* What partition types to assume for Sun disklabels: */
283 static u_char
284 sun_fstypes[8] = {
285 FS_BSDFFS, /* a */
286 FS_SWAP, /* b */
287 FS_OTHER, /* c - whole disk */
288 FS_BSDFFS, /* d */
289 FS_BSDFFS, /* e */
290 FS_BSDFFS, /* f */
291 FS_BSDFFS, /* g */
292 FS_BSDFFS, /* h */
293 };
294
295 /*
296 * Given a UniOS/ISI disk label, set lp to a BSD disk label.
297 * Returns NULL on success, else an error string.
298 *
299 * The BSD label is cleared out before this is called.
300 */
301 static const char *
disklabel_om_to_bsd(char * cp,struct disklabel * lp)302 disklabel_om_to_bsd(char *cp, struct disklabel *lp)
303 {
304 struct sun_disklabel *sl;
305 struct partition *npp;
306 struct sun_dkpart *spp;
307 int i, secpercyl;
308 u_short cksum, *sp1, *sp2;
309
310 sl = (struct sun_disklabel *)cp;
311
312 /* Verify the XOR check. */
313 sp1 = (u_short *)sl;
314 sp2 = (u_short *)(sl + 1);
315 cksum = 0;
316 while (sp1 < sp2)
317 cksum ^= *sp1++;
318 if (cksum != 0)
319 return ("UniOS disk label, bad checksum");
320
321 memset((void *)lp, 0, sizeof(struct disklabel));
322 /* Format conversion. */
323 lp->d_magic = DISKMAGIC;
324 lp->d_magic2 = DISKMAGIC;
325 memcpy(lp->d_packname, sl->sl_text, sizeof(lp->d_packname));
326
327 lp->d_type = DKTYPE_SCSI;
328 lp->d_secsize = 512;
329 lp->d_nsectors = sl->sl_nsectors;
330 lp->d_ntracks = sl->sl_ntracks;
331 lp->d_ncylinders = sl->sl_ncylinders;
332
333 secpercyl = sl->sl_nsectors * sl->sl_ntracks;
334 lp->d_secpercyl = secpercyl;
335 lp->d_secperunit = secpercyl * sl->sl_ncylinders;
336
337 lp->d_sparespercyl = 0; /* no way to know */
338 lp->d_acylinders = sl->sl_acylinders;
339 lp->d_rpm = sl->sl_rpm; /* UniOS - (empty) */
340 lp->d_interleave = sl->sl_interleave; /* UniOS - ndisk */
341
342 if (sl->sl_rpm == 0) {
343 /* UniOS label has blkoffset, not cyloffset */
344 secpercyl = 1;
345 }
346
347 lp->d_npartitions = 8;
348 /* These are as defined in <ufs/ffs/fs.h> */
349 lp->d_bbsize = 8192; /* XXX */
350 lp->d_sbsize = 8192; /* XXX */
351 for (i = 0; i < 8; i++) {
352 spp = &sl->sl_part[i];
353 npp = &lp->d_partitions[i];
354 npp->p_offset = spp->sdkp_cyloffset * secpercyl;
355 npp->p_size = spp->sdkp_nsectors;
356 if (npp->p_size == 0)
357 npp->p_fstype = FS_UNUSED;
358 else {
359 /* Partition has non-zero size. Set type, etc. */
360 npp->p_fstype = sun_fstypes[i];
361
362 /*
363 * The sun label does not store the FFS fields,
364 * so just set them with default values here.
365 * XXX: This keeps newfs from trying to rewrite
366 * XXX: the disk label in the most common case.
367 * XXX: (Should remove that code from newfs...)
368 */
369 if (npp->p_fstype == FS_BSDFFS) {
370 npp->p_fsize = 1024;
371 npp->p_frag = 8;
372 npp->p_cpg = 16;
373 }
374 }
375 }
376
377 /*
378 * XXX BandAid XXX
379 * UniOS rootfs sits on part c which don't begin at sect 0,
380 * and impossible to mount. Thus, make it usable as part b.
381 */
382 if (sl->sl_rpm == 0 && lp->d_partitions[2].p_offset != 0) {
383 lp->d_partitions[1] = lp->d_partitions[2];
384 lp->d_partitions[1].p_fstype = FS_BSDFFS;
385 }
386
387 lp->d_checksum = dkcksum(lp);
388
389 return (NULL);
390 }
391
392 /*
393 * Given a BSD disk label, update the UniOS disklabel
394 * pointed to by cp with the new info. Note that the
395 * UniOS disklabel may have other info we need to keep.
396 * Returns zero or error code.
397 */
398 static int
disklabel_bsd_to_om(struct disklabel * lp,char * cp)399 disklabel_bsd_to_om(struct disklabel *lp, char *cp)
400 {
401 struct sun_disklabel *sl;
402 struct partition *npp;
403 struct sun_dkpart *spp;
404 int i;
405 u_short cksum, *sp1, *sp2;
406
407 if (lp->d_secsize != 512)
408 return (EINVAL);
409
410 sl = (struct sun_disklabel *)cp;
411
412 /* Format conversion. */
413 memcpy(sl->sl_text, lp->d_packname, sizeof(lp->d_packname));
414 sl->sl_rpm = 0; /* UniOS */
415 #if 0 /* leave as was */
416 sl->sl_pcyl = lp->d_ncylinders + lp->d_acylinders; /* XXX */
417 sl->sl_sparespercyl = lp->d_sparespercyl;
418 #endif
419 sl->sl_interleave = lp->d_interleave;
420 sl->sl_ncylinders = lp->d_ncylinders;
421 sl->sl_acylinders = lp->d_acylinders;
422 sl->sl_ntracks = lp->d_ntracks;
423 sl->sl_nsectors = lp->d_nsectors;
424
425 for (i = 0; i < 8; i++) {
426 spp = &sl->sl_part[i];
427 npp = &lp->d_partitions[i];
428
429 spp->sdkp_cyloffset = npp->p_offset; /* UniOS */
430 spp->sdkp_nsectors = npp->p_size;
431 }
432 sl->sl_magic = SUN_DKMAGIC;
433
434 /* Correct the XOR check. */
435 sp1 = (u_short *)sl;
436 sp2 = (u_short *)(sl + 1);
437 sl->sl_cksum = cksum = 0;
438 while (sp1 < sp2)
439 cksum ^= *sp1++;
440 sl->sl_cksum = cksum;
441
442 return (0);
443 }
444