xref: /netbsd-src/sys/arch/atari/stand/tostools/aptck/disklbl.c (revision 5e4c038a45edbc7d63b7c2daa76e29f88b64a4e3)
1 /*	$NetBSD: disklbl.c,v 1.4 2001/07/26 23:07:57 wiz Exp $	*/
2 
3 /*
4  * Copyright (c) 1995 Waldi Ravens.
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. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *        This product includes software developed by Waldi Ravens.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <sys/types.h>
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include "libtos.h"
37 #include "aptck.h"
38 #include "ahdilbl.h"
39 #include "disklbl.h"
40 
41 static int	dkcksum    PROTO((struct disklabel *));
42 static int	bsd_label  PROTO((disk_t *, u_int));
43 static int	ahdi_label PROTO((disk_t *));
44 static int	ahdi_display PROTO((disk_t *));
45 static u_int	ahdi_getparts PROTO((disk_t *, u_int, u_int));
46 
47 int
48 readdisklabel(dd)
49 	disk_t	*dd;
50 {
51 	int	e;
52 
53 	printf("Device     : %s (%s) [%s]\n", dd->sname, dd->fname,
54 							 dd->product);
55 	printf("Medium size: %lu sectors\n", (u_long)dd->msize);
56 	printf("Sector size: %lu bytes\n\n", (u_long)dd->bsize);
57 
58 	e = bsd_label(dd, LABELSECTOR);
59 	if (e < 0) {
60 		printf("Device I/O error (hardware problem?)\n\n");
61 		return(-1);
62 	}
63 	if (!e) {
64 		printf("NetBSD/Atari format, boot block: "
65 		       "sector %u labeloffset %u\n\n",
66 		       dd->bblock, dd->lblofs);
67 		return(0);
68 	}
69 
70 	e = ahdi_label(dd);
71 	if (e < 0) {
72 		printf("Device I/O error (hardware problem?)\n\n");
73 		return(-1);
74 	}
75 	if (!e) {
76 		printf("AHDI format, NetBSD boot block: ");
77 		if (dd->bblock != NO_BOOT_BLOCK)
78 			printf("sector %u labeloffset %u\n\n",
79 			       dd->bblock, dd->lblofs);
80 		else printf("none\n\n");
81 		return(0);
82 	}
83 
84 	printf("Unknown label format.\n\n");
85 	return(-1);
86 }
87 
88 static int
89 bsd_label(dd, offset)
90 	disk_t		*dd;
91 	u_int		offset;
92 {
93 	u_char		*bblk;
94 	u_int		nsec;
95 	int		rv;
96 
97 	nsec = (BBMINSIZE + (dd->bsize - 1)) / dd->bsize;
98 	bblk = disk_read(dd, offset, nsec);
99 	if (bblk) {
100 		u_int	*end, *p;
101 
102 		end = (u_int *)&bblk[BBMINSIZE - sizeof(struct disklabel)];
103 		rv  = 1;
104 		for (p = (u_int *)bblk; p < end; ++p) {
105 			struct disklabel *dl = (struct disklabel *)&p[1];
106 			if (  (  (p[0] == NBDAMAGIC && offset == 0)
107 			      || (p[0] == AHDIMAGIC && offset != 0)
108 			      || (u_char *)dl - bblk == 7168
109 			      )
110 			   && dl->d_npartitions <= MAXPARTITIONS
111 			   && dl->d_magic2 == DISKMAGIC
112 			   && dl->d_magic  == DISKMAGIC
113 			   && dkcksum(dl)  == 0
114 			   )	{
115 		    		dd->lblofs = (u_char *)dl - bblk;
116 		    		dd->bblock = offset;
117 				rv = 0;
118 				break;
119 			}
120 		}
121 		free(bblk);
122 	}
123 	else rv = -1;
124 
125 	return(rv);
126 }
127 
128 static int
129 dkcksum(dl)
130 	struct disklabel *dl;
131 {
132 	u_short	*start, *end, sum = 0;
133 
134 	start = (u_short *)dl;
135 	end   = (u_short *)&dl->d_partitions[dl->d_npartitions];
136 	while (start < end)
137 		sum ^= *start++;
138 	return(sum);
139 }
140 
141 int
142 ahdi_label(dd)
143 	disk_t	*dd;
144 {
145 	u_int	i;
146 	int	e;
147 
148 	/*
149 	 * The AHDI format requires a specific block size.
150 	 */
151 	if (dd->bsize != AHDI_BSIZE)
152 		return(1);
153 
154 	/*
155 	 * Fetch the AHDI partition descriptors.
156 	 */
157 	i = ahdi_getparts(dd, AHDI_BBLOCK, AHDI_BBLOCK);
158 	if (i) {
159 		if (i < dd->msize)
160 			return(-1);	/* disk read error		*/
161 		else return(1);		/* reading past end of medium	*/
162 	}
163 
164 	/*
165 	 * Display and perform sanity checks.
166 	 */
167 	i = ahdi_display(dd);
168 	if (i)
169 		return(i);
170 
171 	/*
172 	 * Search for a NetBSD disk label
173 	 */
174 	dd->bblock = NO_BOOT_BLOCK;
175 	for (i = 0; i < dd->nparts; ++i) {
176 		part_t	*pd = &dd->parts[i];
177 		u_int	id  = *((u_int32_t *)&pd->id) >> 8;
178 		if (id == AHDI_PID_NBD || id == AHDI_PID_RAW) {
179 			u_int	offs = pd->start;
180 			if ((e = bsd_label(dd, offs)) < 0) {
181 				return(e);		/* I/O error */
182 			}
183 			if (!e) {
184 				dd->bblock = offs;	/* got it */
185 				return(0);
186 			}
187 			if (id == AHDI_PID_NBD && dd->bblock == NO_BOOT_BLOCK)
188 				dd->bblock = offs;
189 		}
190 	}
191 	return(0);
192 }
193 
194 static int
195 root_cmp(x1, x2)
196 	const void	*x1, *x2;
197 {
198 	const u_int	*r1 = x1,
199 			*r2 = x2;
200 
201 	if (*r1 < *r2)
202 		return(-1);
203 	if (*r1 > *r2)
204 		return(1);
205 	return(0);
206 }
207 
208 static int
209 part_cmp(x1, x2)
210 	const void	*x1, *x2;
211 {
212 	const part_t	*p1 = x1,
213 			*p2 = x2;
214 
215 	if (p1->start < p2->start)
216 		return(-1);
217 	if (p1->start > p2->start)
218 		return(1);
219 	if (p1->end < p2->end)
220 		return(-1);
221 	if (p1->end > p2->end)
222 		return(1);
223 	if (p1->rsec < p2->rsec)
224 		return(-1);
225 	if (p1->rsec > p2->rsec)
226 		return(1);
227 	if (p1->rent < p2->rent)
228 		return(-1);
229 	if (p1->rent > p2->rent)
230 		return(1);
231 	return(0);
232 }
233 
234 static int
235 ahdi_display(dd)
236 	disk_t	*dd;
237 {
238 	int	i, j, rv = 0;
239 
240 	printf("Start of bad sector list : %u\n", dd->bslst);
241 	if (dd->bslst == 0) {
242 		printf("* Illegal value (zero) *\n"); rv = 1;
243 	}
244 	printf("End of bad sector list   : %u\n", dd->bslend);
245 	if (dd->bslend == 0) {
246 		printf("* Illegal value (zero) *\n"); rv = 1;
247 	}
248 	printf("Medium size (in root sec): %u\n", dd->hdsize);
249 	if (dd->hdsize == 0) {
250 		printf("* Illegal value (zero) *\n"); rv = 1;
251 	}
252 
253 	qsort(dd->roots, dd->nroots, sizeof *dd->roots, root_cmp);
254 	qsort(dd->parts, dd->nparts, sizeof *dd->parts, part_cmp);
255 	printf("\n    root  desc   id     start       end    MBs\n");
256 
257 	for (i = 0; i < dd->nparts; ++i) {
258 		part_t	*p1 = &dd->parts[i];
259 		u_int	megs = p1->end - p1->start + 1,
260 			blpm = (1024 * 1024) / dd->bsize;
261 		megs = (megs + (blpm >> 1)) / blpm;
262 		printf("%8u  %4u  %s  %8u  %8u  (%3u)\n",
263 			p1->rsec, p1->rent, p1->id,
264 			p1->start, p1->end, megs);
265 		for (j = 0; j < dd->nroots; ++j) {
266 			u_int	aux = dd->roots[j];
267 			if (aux >= p1->start && aux <= p1->end) {
268 				printf("FATAL: auxiliary root at %u\n", aux);
269 				rv = 1;
270 			}
271 		}
272 		for (j = i; j--;) {
273 		    part_t	*p2 = &dd->parts[j];
274 		    if (p1->start >= p2->start && p1->start <= p2->end) {
275 			printf("FATAL: clash with %u/%u\n", p2->rsec, p2->rent);
276 			rv = 1;
277 		    }
278 		    if (p2->start >= p1->start && p2->start <= p1->end) {
279 			printf("FATAL: clash with %u/%u\n", p2->rsec, p2->rent);
280 			rv = 1;
281 		    }
282 		}
283 		if (p1->start >= dd->bslst && p1->start <= dd->bslend) {
284 		    printf("FATAL: partition overlaps with bad sector list\n");
285 		    rv = 1;
286 		}
287 		if (dd->bslst >= p1->start && dd->bslst <= p1->end) {
288 		    printf("FATAL: partition overlaps with bad sector list\n");
289 		    rv = 1;
290 		}
291 	}
292 
293 	printf("\nTotal number of auxiliary roots: %u\n", dd->nroots);
294 	printf("Total number of partitions    : %u\n", dd->nparts);
295 	if (dd->nparts == 0) {
296 		printf("* Weird # of partitions (zero) *\n"); rv = 1;
297 	}
298 	if (dd->nparts > AHDI_MAXPARTS) {
299 		printf("* Too many AHDI partitions for the default NetBSD "
300 			"kernel *\n  Increase MAXAUXROOTS in src/sys/arch/"
301 			"atari/include/disklabel.h\n  to at least %u, and "
302 			"recompile the NetBSD kernel.\n", dd->nroots);
303 		rv = -1;
304 	}
305 	return(rv);
306 }
307 
308 static u_int
309 ahdi_getparts(dd, rsec, esec)
310 	disk_t			*dd;
311 	u_int			rsec,
312 				esec;
313 {
314 	struct ahdi_part	*part, *end;
315 	struct ahdi_root	*root;
316 	u_int			rv;
317 
318 	root = disk_read(dd, rsec, 1);
319 	if (!root) {
320 		rv = rsec + (rsec == 0);
321 		goto done;
322 	}
323 
324 	if (rsec == AHDI_BBLOCK)
325 		end = &root->ar_parts[AHDI_MAXRPD];
326 	else end = &root->ar_parts[AHDI_MAXARPD];
327 	for (part = root->ar_parts; part < end; ++part) {
328 		u_int	id = *((u_int32_t *)&part->ap_flg);
329 		if (!(id & 0x01000000))
330 			continue;
331 		if ((id &= 0x00ffffff) == AHDI_PID_XGM) {
332 			u_int	offs = part->ap_offs + esec;
333 			u_int	i = ++dd->nroots;
334 			dd->roots = xrealloc(dd->roots, i * sizeof *dd->roots);
335 			dd->roots[--i] = offs;
336 			rv = ahdi_getparts(dd, offs,
337 					esec == AHDI_BBLOCK ? offs : esec);
338 			if (rv)
339 				goto done;
340 		} else {
341 			part_t	*p;
342 			u_int	i = ++dd->nparts;
343 			dd->parts = xrealloc(dd->parts, i * sizeof *dd->parts);
344 			p = &dd->parts[--i];
345 			*((u_int32_t *)&p->id) = id << 8;
346 			p->start = part->ap_offs + rsec;
347 			p->end   = p->start + part->ap_size - 1;
348 			p->rsec  = rsec;
349 			p->rent  = part - root->ar_parts;
350 		}
351 	}
352 	dd->hdsize = root->ar_hdsize;
353 	dd->bslst  = root->ar_bslst;
354 	dd->bslend = root->ar_bslst + root->ar_bslsize - 1;
355 	rv = 0;
356 done:
357 	free(root);
358 	return(rv);
359 }
360