1 /* $NetBSD: disksubr.c,v 1.29 2022/05/24 06:28:00 andvar 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 * @(#)ufs_disksubr.c 7.16 (Berkeley) 5/4/91
32 */
33
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: disksubr.c,v 1.29 2022/05/24 06:28:00 andvar Exp $");
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/buf.h>
40 #include <sys/device.h>
41 #include <sys/disk.h>
42 #include <sys/disklabel.h>
43 #include <sys/syslog.h>
44 #include <ufs/ufs/dinode.h> /* XXX for fs.h */
45 #include <ufs/ffs/fs.h> /* XXX for BBSIZE & SBSIZE */
46
47 #define b_cylin b_resid
48
49 static const char *disklabel_mips_to_bsd(struct mips_volheader *,
50 struct disklabel *);
51 static int disklabel_bsd_to_mips(struct disklabel *,
52 struct mips_volheader *);
53 static int mipsvh_cksum(struct mips_volheader *);
54
55 #define LABELSIZE(lp) ((char *)&lp->d_partitions[lp->d_npartitions] - \
56 (char *)lp)
57
58 /*
59 * Attempt to read a disk label from a device
60 * using the indicated strategy routine.
61 * The label must be partly set up before this:
62 * secpercyl and anything required in the strategy routine
63 * (e.g., sector size) must be filled in before calling us.
64 * Returns null on success and an error string on failure.
65 */
66 const char *
readdisklabel(dev_t dev,void (* strat)(struct buf * bp),register struct disklabel * lp,struct cpu_disklabel * clp)67 readdisklabel(dev_t dev, void (*strat)(struct buf *bp), register struct disklabel *lp, struct cpu_disklabel *clp)
68 {
69 register struct buf *bp;
70 struct disklabel *dlp;
71 struct mips_volheader *mvp;
72 int i, err;
73
74 /* minimum requirements for disk label */
75 if (lp->d_secperunit == 0)
76 lp->d_secperunit = 0x1fffffff;
77 if (lp->d_npartitions == 0) {
78 lp->d_npartitions = RAW_PART + 1;
79 if (lp->d_partitions[RAW_PART].p_size == 0)
80 lp->d_partitions[RAW_PART].p_size = 0x1fffffff;
81 lp->d_partitions[RAW_PART].p_offset = 0;
82 }
83
84 bp = geteblk((int)lp->d_secsize);
85
86 bp->b_dev = dev;
87 bp->b_blkno = LABELSECTOR;
88 bp->b_bcount = lp->d_secsize;
89 bp->b_flags |= B_READ;
90 bp->b_cylinder = bp->b_blkno / lp->d_secpercyl;
91 (*strat)(bp);
92 err = biowait(bp);
93 brelse(bp, 0);
94
95 if (err)
96 return "error reading disklabel";
97
98 /* Check for NetBSD label in second sector */
99 dlp = (struct disklabel *)((char *)bp->b_data + LABELOFFSET);
100 if (dlp->d_magic == DISKMAGIC)
101 if (!dkcksum(dlp)) {
102 memcpy(lp, dlp, LABELSIZE(dlp));
103 return NULL; /* NetBSD label found */
104 }
105
106 bp = geteblk((int)lp->d_secsize);
107 bp->b_dev = dev;
108 bp->b_blkno = MIPS_VHSECTOR;
109 bp->b_bcount = lp->d_secsize;
110 bp->b_flags |= B_READ;
111 bp->b_cylinder = bp->b_blkno / lp->d_secpercyl;
112 (*strat)(bp);
113 err = biowait(bp);
114 brelse(bp, 0);
115
116 if (err)
117 return "error reading volume header";
118
119 mvp = (struct mips_volheader *)bp->b_data;
120 /* Check for MIPS RISC/os volume header */
121 if (mvp->vh_magic == MIPS_VHMAGIC)
122 return disklabel_mips_to_bsd(mvp, lp);
123
124 /* Search for NetBSD label in first sector */
125 for (i=0; i <= lp->d_secsize - sizeof(*dlp); i += sizeof(long)) {
126 dlp = (struct disklabel *) ((char *)mvp + i);
127 if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC) {
128 if (dlp->d_npartitions > MAXPARTITIONS ||
129 dkcksum(dlp) != 0)
130 return "disk label corrupted";
131 else {
132 memcpy(lp, dlp, sizeof *lp);
133 return NULL; /* Found */
134 }
135 }
136 }
137 return "no disk label";
138 }
139
140 /* encoding of disk minor numbers, should be elsewhere... */
141 #define dkunit(dev) (minor(dev) >> 3)
142 #define dkpart(dev) (minor(dev) & 07)
143 #define dkminor(unit, part) (((unit) << 3) | (part))
144
145 /*
146 * Write disk label back to device after modification.
147 */
148 int
writedisklabel(dev_t dev,void (* strat)(struct buf * bp),register struct disklabel * lp,struct cpu_disklabel * clp)149 writedisklabel(dev_t dev, void (*strat)(struct buf *bp), register struct disklabel *lp, struct cpu_disklabel *clp)
150 {
151 struct buf *bp;
152 int labelpart;
153 int error;
154
155 labelpart = dkpart(dev);
156 if (lp->d_partitions[labelpart].p_offset != 0) {
157 if (lp->d_partitions[0].p_offset != 0)
158 return (EXDEV); /* not quite right */
159 labelpart = 0;
160 }
161
162 /* Read RISC/os volume header before merging NetBSD partition info*/
163 bp = geteblk((int)lp->d_secsize);
164
165 bp->b_dev = dev;
166 bp->b_blkno = MIPS_VHSECTOR;
167 bp->b_bcount = lp->d_secsize;
168 bp->b_flags |= B_READ;
169 bp->b_cylinder = bp->b_blkno / lp->d_secpercyl;
170 (*strat)(bp);
171
172 if((error = biowait(bp)) != 0)
173 goto ioerror;
174
175 if ((error = disklabel_bsd_to_mips(lp, (void *)bp->b_data)) != 0)
176 goto ioerror;
177
178 /* Write MIPS RISC/os label to first sector */
179 bp->b_flags &= ~(B_READ);
180 bp->b_oflags &= ~(BO_DONE);
181 bp->b_flags |= B_WRITE;
182 (*strat)(bp);
183 if ((error = biowait(bp)) != 0)
184 goto ioerror;
185
186 /* Write NetBSD disk label to second sector */
187 memset(bp->b_data, 0, lp->d_secsize);
188 memcpy(bp->b_data, lp, sizeof(*lp));
189 bp->b_blkno = LABELSECTOR;
190 bp->b_bcount = lp->d_secsize;
191 bp->b_cylinder = bp->b_blkno / lp->d_secpercyl;
192 bp->b_flags &= ~(B_READ);
193 bp->b_oflags &= ~(BO_DONE);
194 bp->b_flags |= B_WRITE;
195 (*strat)(bp);
196 error = biowait(bp);
197
198 ioerror:
199 brelse(bp, 0);
200 return error;
201 }
202
203 /*
204 * Conversion table for mapping partition numbers and types between
205 * a MIPS volume header and a BSD partition table.
206 *
207 * Mips volume header compatibility is required in order to boot
208 * NetBSD from the Mips stand alone shell, but due to the differences
209 * in the partition numbers used along with different methods for
210 * determining partition types we must use a table for mapping the
211 * differences.
212 */
213
214 struct partitionmap {
215 int mips_part; /* Mips partition number */
216 int mips_type; /* Mips partition type */
217 int bsd_part; /* BSD partition number */
218 int bsd_type; /* BSD partition type */
219 };
220
221 struct partitionmap partition_map[] = {
222 /* Mips Mips Type BSD BSD Type */
223 {0, MIPS_FS_BSD42, 0, FS_BSDFFS},
224 {1, MIPS_FS_BSD42, 1, FS_SWAP},
225 {10, MIPS_FS_VOLUME, RAW_PART, FS_OTHER},
226 {3, MIPS_FS_BSD42, 3, FS_BSDFFS},
227 {4, MIPS_FS_BSD42, 4, FS_BSDFFS},
228 {5, MIPS_FS_BSD42, 5, FS_BSDFFS},
229 {6, MIPS_FS_BSD42, 6, FS_BSDFFS},
230 {7, MIPS_FS_BSD42, 7, FS_BSDFFS}
231 };
232 #define NPARTMAP (sizeof(partition_map)/sizeof(struct partitionmap))
233
234 /*
235 * Convert a RISC/os disk label into a NetBSD disk label.
236 *
237 * Returns NULL on success, otherwise an error string
238 */
239 static const char *
disklabel_mips_to_bsd(struct mips_volheader * vh,struct disklabel * lp)240 disklabel_mips_to_bsd(struct mips_volheader *vh, struct disklabel *lp)
241 {
242 int i, bp, mp;
243 struct partition *lpp;
244 if (mipsvh_cksum(vh))
245 return ("MIPS disk label corrupted");
246
247 lp->d_secsize = vh->vh_dp.dp_secbytes;
248 lp->d_nsectors = vh->vh_dp.dp_secs;
249 lp->d_ntracks = vh->vh_dp.dp_trks0;
250 lp->d_ncylinders = vh->vh_dp.dp_cyls;
251 lp->d_interleave = vh->vh_dp.dp_interleave;
252
253 lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
254 lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
255
256 lp->d_bbsize = BBSIZE;
257 lp->d_sbsize = SBLOCKSIZE;
258 lp->d_npartitions = MAXPARTITIONS;
259
260 for (i = 0; i < NPARTMAP; i++) {
261 mp = partition_map[i].mips_part;
262 bp = partition_map[i].bsd_part;
263
264 lpp = &lp->d_partitions[bp];
265 lpp->p_offset = vh->vh_part[mp].pt_offset;
266 lpp->p_size = vh->vh_part[mp].pt_size;
267 lpp->p_fstype = partition_map[i].bsd_type;
268 if (lpp->p_fstype == FS_BSDFFS) {
269 lpp->p_fsize = 1024;
270 lpp->p_frag = 8;
271 lpp->p_cpg = 16;
272 }
273 }
274 #if DIAGNOSTIC
275 printf("Warning: using MIPS disk label\n");
276 #endif
277 return NULL;
278 }
279
280 /*
281 * Convert a NetBSD disk label into a RISC/os disk label.
282 *
283 * Returns NULL on success, otherwise an error string
284 */
285 static int
disklabel_bsd_to_mips(struct disklabel * lp,struct mips_volheader * vh)286 disklabel_bsd_to_mips(struct disklabel *lp, struct mips_volheader *vh)
287 {
288 int i, bp, mp;
289 struct partition *lpp;
290
291 if (vh->vh_magic != MIPS_VHMAGIC || mipsvh_cksum(vh) != 0) {
292 #if DIAGNOSTIC
293 printf("Warning: writing MIPS compatible label\n");
294 #endif
295 memset((void *)vh, 0, sizeof *vh);
296 vh->vh_magic = MIPS_VHMAGIC;
297 vh->vh_root = 0; /* a*/
298 vh->vh_swap = 1; /* b*/
299 }
300 strcpy(vh->bootfile, "/netbsd");
301 vh->vh_dp.dp_skew = lp->d_trackskew;
302 vh->vh_dp.dp_gap1 = 1; /* XXX */
303 vh->vh_dp.dp_gap2 = 1; /* XXX */
304 vh->vh_dp.dp_cyls = lp->d_ncylinders;
305 vh->vh_dp.dp_shd0 = 0;
306 vh->vh_dp.dp_trks0 = lp->d_ntracks;
307 vh->vh_dp.dp_secs = lp->d_nsectors;
308 vh->vh_dp.dp_secbytes = lp->d_secsize;
309 vh->vh_dp.dp_interleave = lp->d_interleave;
310 vh->vh_dp.dp_nretries = 22;
311
312 for (i = 0; i < NPARTMAP; i++) {
313 mp = partition_map[i].mips_part;
314 bp = partition_map[i].bsd_part;
315
316 lpp = &lp->d_partitions[bp];
317 vh->vh_part[mp].pt_offset = lpp->p_offset;
318 vh->vh_part[mp].pt_size = lpp->p_size;
319 vh->vh_part[mp].pt_fstype = partition_map[i].mips_type;
320 }
321 /*
322 * Create a fake partition for bootstrap code (or SASH)
323 */
324 vh->vh_part[8].pt_offset = 0;
325 vh->vh_part[8].pt_size = vh->vh_part[vh->vh_root].pt_offset +
326 BBSIZE / vh->vh_dp.dp_secbytes;
327 vh->vh_part[8].pt_fstype = MIPS_FS_VOLHDR;
328
329 vh->vh_cksum = 0;
330 vh->vh_cksum = -mipsvh_cksum(vh);
331 return 0;
332 }
333
334 /*
335 * Compute checksum for MIPS disk volume header
336 *
337 * Mips volume header checksum is the 32bit 2's complement sum
338 * of the entire volume header structure
339 */
340 int
mipsvh_cksum(struct mips_volheader * vhp)341 mipsvh_cksum(struct mips_volheader *vhp)
342 {
343 int i, *ptr;
344 int cksum = 0;
345
346 ptr = (int *)vhp;
347 i = sizeof(*vhp) / sizeof(*ptr);
348 while (i--)
349 cksum += *ptr++;
350 return cksum;
351 }
352