1 /* $NetBSD: disksubr.c,v 1.24 2019/04/03 22:10:51 christos Exp $ */
2
3 /*
4 * Copyright (c) 2001 Christopher Sekiya
5 * Copyright (c) 2001 Wayne Knowles
6 * Copyright (c) 2000 Soren S. Jorvang
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed for the
20 * NetBSD Project. See http://www.NetBSD.org/ for
21 * information about NetBSD.
22 * 4. The name of the author may not be used to endorse or promote products
23 * derived from this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 */
36
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: disksubr.c,v 1.24 2019/04/03 22:10:51 christos Exp $");
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/buf.h>
43 #include <sys/disklabel.h>
44 #include <sys/disk.h>
45 #include <ufs/ufs/dinode.h>
46 #include <ufs/ffs/fs.h>
47
48 #include <machine/disklabel.h>
49
50 static int disklabel_bsd_to_sgimips(struct disklabel *lp,
51 struct sgi_boot_block *vh);
52 static const char *disklabel_sgimips_to_bsd(struct sgi_boot_block *vh,
53 struct disklabel *lp);
54
55 int mipsvh_cksum(struct sgi_boot_block *vhp);
56
57 #define LABELSIZE(lp) ((char *)&lp->d_partitions[lp->d_npartitions] - \
58 (char *)lp)
59
60
61 /*
62 * Attempt to read a disk label from a device using the indicated
63 * strategy routine. The label must be partly set up before this:
64 * secpercyl, secsize and anything required for a block i/o read
65 * operation in the driver's strategy/start routines must be
66 * filled in before calling us.
67 *
68 * Return buffer for use in signalling errors if requested.
69 *
70 * Returns null on success and an error string on failure.
71 */
72
73 const char *
readdisklabel(dev_t dev,void (* strat)(struct buf *),struct disklabel * lp,struct cpu_disklabel * clp)74 readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, struct cpu_disklabel *clp)
75 {
76 struct buf *bp;
77 struct disklabel *dlp;
78 struct sgi_boot_block *slp;
79 int err;
80
81 /* Minimal requirements for archetypal disk label. */
82 if (lp->d_secsize == 0)
83 lp->d_secsize = DEV_BSIZE;
84 if (lp->d_secperunit == 0)
85 lp->d_secperunit = 0x1fffffff;
86
87 /* Obtain buffer to probe drive with. */
88 bp = geteblk((int)lp->d_secsize);
89
90 bp->b_dev = dev;
91 bp->b_blkno = LABELSECTOR;
92 bp->b_bcount = lp->d_secsize;
93 bp->b_flags |= B_READ;
94 bp->b_cylinder = bp->b_blkno / lp->d_secpercyl;
95 (*strat)(bp);
96 err = biowait(bp);
97 brelse(bp, 0);
98
99 if (err)
100 return "error reading disklabel";
101
102 /* Check for NetBSD label in second sector */
103 dlp = (struct disklabel *)((char *)bp->b_data + LABELOFFSET);
104 if (dlp->d_magic == DISKMAGIC)
105 if (!dkcksum(dlp)) {
106 memcpy(lp, dlp, LABELSIZE(dlp));
107 return NULL; /* NetBSD label found */
108 }
109
110 bp = geteblk((int)lp->d_secsize);
111 bp->b_dev = dev;
112 bp->b_blkno = 0;
113 bp->b_bcount = lp->d_secsize;
114 bp->b_flags |= B_READ;
115 bp->b_cylinder = bp->b_blkno / lp->d_secpercyl;
116 (*strat)(bp);
117 err = biowait(bp);
118 brelse(bp, 0);
119
120 if (err)
121 return "error reading volume header";
122
123 /* Check for a SGI label. */
124 slp = (struct sgi_boot_block *)bp->b_data;
125 if (be32toh(slp->magic) != SGI_BOOT_BLOCK_MAGIC)
126 return "no disk label";
127
128 return disklabel_sgimips_to_bsd(slp, lp);
129 }
130
131 #define dkpart(dev) (minor(dev) & 07)
132 #define dkminor(unit, part) (((unit) << 3) | (part))
133
134 int
writedisklabel(dev_t dev,void (* strat)(struct buf *),struct disklabel * lp,struct cpu_disklabel * clp)135 writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, struct cpu_disklabel *clp)
136 {
137 struct buf *bp;
138 int labelpart;
139 int error;
140
141 labelpart = dkpart(dev);
142 if (lp->d_partitions[labelpart].p_offset != 0) {
143 if (lp->d_partitions[0].p_offset != 0)
144 return (EXDEV); /* not quite right */
145 labelpart = 0;
146 }
147
148 /* Read sgimips volume header before merging NetBSD partition info */
149 bp = geteblk((int)lp->d_secsize);
150
151 bp->b_dev = dev;
152 bp->b_blkno = 0;
153 bp->b_bcount = lp->d_secsize;
154 bp->b_flags |= B_READ;
155 bp->b_cylinder = bp->b_blkno / lp->d_secpercyl;
156 (*strat)(bp);
157
158 if((error = biowait(bp)) != 0)
159 goto ioerror;
160
161 if ((error = disklabel_bsd_to_sgimips(lp, (void *)bp->b_data)) != 0)
162 goto ioerror;
163
164 /* Write sgimips label to first sector */
165 bp->b_oflags &= ~(BO_DONE);
166 bp->b_flags &= ~(B_READ);
167 bp->b_flags |= B_WRITE;
168 (*strat)(bp);
169 if ((error = biowait(bp)) != 0)
170 goto ioerror;
171
172 /* Write NetBSD disk label to second sector */
173 memset(bp->b_data, 0, lp->d_secsize);
174 memcpy(bp->b_data, lp, sizeof(*lp));
175 bp->b_blkno = LABELSECTOR;
176 bp->b_bcount = lp->d_secsize;
177 bp->b_cylinder = bp->b_blkno / lp->d_secpercyl;
178 bp->b_oflags &= ~(BO_DONE);
179 bp->b_flags &= ~(B_READ);
180 bp->b_flags |= B_WRITE;
181 (*strat)(bp);
182 error = biowait(bp);
183
184 ioerror:
185 brelse(bp, 0);
186 return error;
187 }
188
189 struct partitionmap {
190 int mips_part; /* sgimips partition number */
191 int mips_type; /* sgimips partition type */
192 int bsd_part; /* BSD partition number */
193 int bsd_type; /* BSD partition type */
194 };
195
196 struct partitionmap partition_map[] = {
197 /* slice sgimips type BSD BSD Type */
198 {0, SGI_PTYPE_BSD, 0, FS_BSDFFS},
199 {1, SGI_PTYPE_RAW, 1, FS_SWAP},
200 {2, SGI_PTYPE_BSD, 10, FS_BSDFFS},
201 {3, SGI_PTYPE_BSD, 3, FS_BSDFFS},
202 {4, SGI_PTYPE_BSD, 4, FS_BSDFFS},
203 {5, SGI_PTYPE_BSD, 5, FS_BSDFFS},
204 {6, SGI_PTYPE_BSD, 6, FS_BSDFFS},
205 {7, SGI_PTYPE_BSD, 7, FS_BSDFFS},
206 {8, SGI_PTYPE_VOLHDR, 8, FS_OTHER},
207 {9, SGI_PTYPE_BSD, 9, FS_BSDFFS},
208 {10, SGI_PTYPE_VOLUME, 2, FS_OTHER},
209 {11, SGI_PTYPE_BSD, 11, FS_BSDFFS},
210 {12, SGI_PTYPE_BSD, 12, FS_BSDFFS},
211 {13, SGI_PTYPE_BSD, 13, FS_BSDFFS},
212 {14, SGI_PTYPE_BSD, 14, FS_BSDFFS},
213 {15, SGI_PTYPE_BSD, 15, FS_BSDFFS}
214 };
215
216 #define NPARTMAP (sizeof(partition_map)/sizeof(struct partitionmap))
217
218 /*
219 * Convert a sgimips disk label into a NetBSD disk label.
220 *
221 * Returns NULL on success, otherwise an error string
222 */
223 static const char *
disklabel_sgimips_to_bsd(struct sgi_boot_block * vh,struct disklabel * lp)224 disklabel_sgimips_to_bsd(struct sgi_boot_block *vh, struct disklabel *lp)
225 {
226 int i, bp, mp;
227 struct partition *lpp;
228 if (mipsvh_cksum(vh))
229 return ("sgimips disk label corrupted");
230
231 #if 0 /* ARCS ignores dp_secbytes and it may be wrong; use default instead */
232 lp->d_secsize = vh->dp.dp_secbytes;
233 #endif
234 lp->d_nsectors = vh->dp.dp_secs;
235 lp->d_ntracks = vh->dp.dp_trks0;
236 lp->d_ncylinders = vh->dp.dp_cyls;
237 lp->d_interleave = vh->dp.dp_interleave;
238
239
240 lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
241 lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
242
243 lp->d_bbsize = BBSIZE;
244 lp->d_sbsize = SBLOCKSIZE;
245 lp->d_npartitions = MAXPARTITIONS;
246
247 for (i = 0; i < 16; i++) {
248 mp = partition_map[i].mips_part;
249 bp = partition_map[i].bsd_part;
250
251 lpp = &lp->d_partitions[bp];
252 lpp->p_offset = vh->partitions[mp].first;
253 /* XXX ARCS ignores dp_secbytes on calculating offsets */
254 if (lp->d_secsize > DEV_BSIZE)
255 lpp->p_offset /= lp->d_secsize / DEV_BSIZE;
256 lpp->p_size = vh->partitions[mp].blocks;
257 lpp->p_fstype = partition_map[i].bsd_type;
258 if (lpp->p_fstype == FS_BSDFFS) {
259 lpp->p_fsize = 1024;
260 lpp->p_frag = 8;
261 lpp->p_cpg = 16;
262 }
263 }
264 return NULL;
265 }
266
267
268 /*
269 * Convert a NetBSD disk label into a sgimips disk label.
270 *
271 * Returns NULL on success, otherwise an error string
272 */
273 static int
disklabel_bsd_to_sgimips(struct disklabel * lp,struct sgi_boot_block * vh)274 disklabel_bsd_to_sgimips(struct disklabel *lp, struct sgi_boot_block *vh)
275 {
276 int i, bp, mp;
277 struct partition *lpp;
278
279 if (vh->magic != SGI_BOOT_BLOCK_MAGIC || mipsvh_cksum(vh) != 0) {
280 memset((void *)vh, 0, sizeof *vh);
281 vh->magic = SGI_BOOT_BLOCK_MAGIC;
282 vh->root = 0; /* a*/
283 vh->swap = 1; /* b*/
284 }
285
286 strcpy(vh->bootfile, "/netbsd");
287 vh->dp.dp_skew = lp->d_trackskew;
288 vh->dp.dp_gap1 = 1; /* XXX */
289 vh->dp.dp_gap2 = 1; /* XXX */
290 vh->dp.dp_cyls = lp->d_ncylinders;
291 vh->dp.dp_shd0 = 0;
292 vh->dp.dp_trks0 = lp->d_ntracks;
293 vh->dp.dp_secs = lp->d_nsectors;
294 #if 0 /* ARCS ignores dp_secbytes; leave it default */
295 vh->dp.dp_secbytes = lp->d_secsize;
296 #else
297 vh->dp.dp_secbytes = SGI_BOOT_BLOCK_BLOCKSIZE;
298 #endif
299 vh->dp.dp_interleave = lp->d_interleave;
300 vh->dp.dp_nretries = 22;
301
302 for (i = 0; i < 16; i++) {
303 mp = partition_map[i].mips_part;
304 bp = partition_map[i].bsd_part;
305
306 lpp = &lp->d_partitions[bp];
307 vh->partitions[mp].first = lpp->p_offset;
308 /* XXX ARCS ignores dp_secbytes on calculating offsets */
309 if (lp->d_secsize > SGI_BOOT_BLOCK_BLOCKSIZE)
310 vh->partitions[mp].first *=
311 lp->d_secsize / SGI_BOOT_BLOCK_BLOCKSIZE;
312 vh->partitions[mp].blocks = lpp->p_size;
313 vh->partitions[mp].type = partition_map[i].mips_type;
314 }
315
316 /*
317 * Create a fake partition for bootstrap code (or SASH)
318 */
319 vh->partitions[8].first = 0;
320 vh->partitions[8].blocks = vh->partitions[vh->root].first +
321 BBSIZE / vh->dp.dp_secbytes;
322 vh->partitions[8].type = SGI_PTYPE_VOLHDR;
323
324 vh->checksum = 0;
325 vh->checksum = -mipsvh_cksum(vh);
326 return 0;
327 }
328
329 /*
330 * Compute checksum for MIPS disk volume header
331 *
332 * Mips volume header checksum is the 32bit 2's complement sum
333 * of the entire volume header structure
334 */
335 int
mipsvh_cksum(struct sgi_boot_block * vhp)336 mipsvh_cksum(struct sgi_boot_block *vhp)
337 {
338 int i, *ptr;
339 int cksum = 0;
340
341 ptr = (int *)vhp;
342 i = sizeof(*vhp) / sizeof(*ptr);
343 while (i--)
344 cksum += *ptr++;
345 return cksum;
346 }
347
348