1 /*        $NetBSD: disklbl.c,v 1.6 2009/03/14 21:04:07 dsl 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
readdisklabel(disk_t * dd)48 readdisklabel(disk_t *dd)
49 {
50           int       e;
51 
52           printf("Device     : %s (%s) [%s]\n", dd->sname, dd->fname,
53                                                                        dd->product);
54           printf("Medium size: %lu sectors\n", (u_long)dd->msize);
55           printf("Sector size: %lu bytes\n\n", (u_long)dd->bsize);
56 
57           e = bsd_label(dd, LABELSECTOR);
58           if (e < 0) {
59                     printf("Device I/O error (hardware problem?)\n\n");
60                     return(-1);
61           }
62           if (!e) {
63                     printf("NetBSD/Atari format, boot block: "
64                            "sector %u labeloffset %u\n\n",
65                            dd->bblock, dd->lblofs);
66                     return(0);
67           }
68 
69           e = ahdi_label(dd);
70           if (e < 0) {
71                     printf("Device I/O error (hardware problem?)\n\n");
72                     return(-1);
73           }
74           if (!e) {
75                     printf("AHDI format, NetBSD boot block: ");
76                     if (dd->bblock != NO_BOOT_BLOCK)
77                               printf("sector %u labeloffset %u\n\n",
78                                      dd->bblock, dd->lblofs);
79                     else printf("none\n\n");
80                     return(0);
81           }
82 
83           printf("Unknown label format.\n\n");
84           return(-1);
85 }
86 
87 static int
bsd_label(disk_t * dd,u_int offset)88 bsd_label(disk_t *dd, u_int offset)
89 {
90           u_char              *bblk;
91           u_int               nsec;
92           int                 rv;
93 
94           nsec = (BBMINSIZE + (dd->bsize - 1)) / dd->bsize;
95           bblk = disk_read(dd, offset, nsec);
96           if (bblk) {
97                     u_int     *end, *p;
98 
99                     end = (u_int *)&bblk[BBMINSIZE - sizeof(struct disklabel)];
100                     rv  = 1;
101                     for (p = (u_int *)bblk; p < end; ++p) {
102                               struct disklabel *dl = (struct disklabel *)&p[1];
103                               if (  (  (p[0] == NBDAMAGIC && offset == 0)
104                                     || (p[0] == AHDIMAGIC && offset != 0)
105                                     || (u_char *)dl - bblk == 7168
106                                     )
107                                  && dl->d_npartitions <= MAXPARTITIONS
108                                  && dl->d_magic2 == DISKMAGIC
109                                  && dl->d_magic  == DISKMAGIC
110                                  && dkcksum(dl)  == 0
111                                  )      {
112                                         dd->lblofs = (u_char *)dl - bblk;
113                                         dd->bblock = offset;
114                                         rv = 0;
115                                         break;
116                               }
117                     }
118                     free(bblk);
119           }
120           else rv = -1;
121 
122           return(rv);
123 }
124 
125 static int
dkcksum(struct disklabel * dl)126 dkcksum(struct disklabel *dl)
127 {
128           u_short   *start, *end, sum = 0;
129 
130           start = (u_short *)dl;
131           end   = (u_short *)&dl->d_partitions[dl->d_npartitions];
132           while (start < end)
133                     sum ^= *start++;
134           return(sum);
135 }
136 
137 int
ahdi_label(disk_t * dd)138 ahdi_label(disk_t *dd)
139 {
140           u_int     i;
141           int       e;
142 
143           /*
144            * The AHDI format requires a specific block size.
145            */
146           if (dd->bsize != AHDI_BSIZE)
147                     return(1);
148 
149           /*
150            * Fetch the AHDI partition descriptors.
151            */
152           i = ahdi_getparts(dd, AHDI_BBLOCK, AHDI_BBLOCK);
153           if (i) {
154                     if (i < dd->msize)
155                               return(-1);         /* disk read error            */
156                     else return(1);               /* reading past end of medium */
157           }
158 
159           /*
160            * Display and perform sanity checks.
161            */
162           i = ahdi_display(dd);
163           if (i)
164                     return(i);
165 
166           /*
167            * Search for a NetBSD disk label
168            */
169           dd->bblock = NO_BOOT_BLOCK;
170           for (i = 0; i < dd->nparts; ++i) {
171                     part_t    *pd = &dd->parts[i];
172                     u_int     id  = *((u_int32_t *)&pd->id) >> 8;
173                     if (id == AHDI_PID_NBD || id == AHDI_PID_RAW) {
174                               u_int     offs = pd->start;
175                               if ((e = bsd_label(dd, offs)) < 0) {
176                                         return(e);                    /* I/O error */
177                               }
178                               if (!e) {
179                                         dd->bblock = offs;  /* got it */
180                                         return(0);
181                               }
182                               if (id == AHDI_PID_NBD && dd->bblock == NO_BOOT_BLOCK)
183                                         dd->bblock = offs;
184                     }
185           }
186           return(0);
187 }
188 
189 static int
root_cmp(const void * x1,const void * x2)190 root_cmp(const void *x1, const void *x2)
191 {
192           const u_int         *r1 = x1,
193                               *r2 = x2;
194 
195           if (*r1 < *r2)
196                     return(-1);
197           if (*r1 > *r2)
198                     return(1);
199           return(0);
200 }
201 
202 static int
part_cmp(const void * x1,const void * x2)203 part_cmp(const void *x1, const void *x2)
204 {
205           const part_t        *p1 = x1,
206                               *p2 = x2;
207 
208           if (p1->start < p2->start)
209                     return(-1);
210           if (p1->start > p2->start)
211                     return(1);
212           if (p1->end < p2->end)
213                     return(-1);
214           if (p1->end > p2->end)
215                     return(1);
216           if (p1->rsec < p2->rsec)
217                     return(-1);
218           if (p1->rsec > p2->rsec)
219                     return(1);
220           if (p1->rent < p2->rent)
221                     return(-1);
222           if (p1->rent > p2->rent)
223                     return(1);
224           return(0);
225 }
226 
227 static int
ahdi_display(disk_t * dd)228 ahdi_display(disk_t *dd)
229 {
230           int       i, j, rv = 0;
231 
232           printf("Start of bad sector list : %u\n", dd->bslst);
233           if (dd->bslst == 0) {
234                     printf("* Illegal value (zero) *\n"); rv = 1;
235           }
236           printf("End of bad sector list   : %u\n", dd->bslend);
237           if (dd->bslend == 0) {
238                     printf("* Illegal value (zero) *\n"); rv = 1;
239           }
240           printf("Medium size (in root sec): %u\n", dd->hdsize);
241           if (dd->hdsize == 0) {
242                     printf("* Illegal value (zero) *\n"); rv = 1;
243           }
244 
245           qsort(dd->roots, dd->nroots, sizeof *dd->roots, root_cmp);
246           qsort(dd->parts, dd->nparts, sizeof *dd->parts, part_cmp);
247           printf("\n    root  desc   id     start       end    MBs\n");
248 
249           for (i = 0; i < dd->nparts; ++i) {
250                     part_t    *p1 = &dd->parts[i];
251                     u_int     megs = p1->end - p1->start + 1,
252                               blpm = (1024 * 1024) / dd->bsize;
253                     megs = (megs + (blpm >> 1)) / blpm;
254                     printf("%8u  %4u  %s  %8u  %8u  (%3u)\n",
255                               p1->rsec, p1->rent, p1->id,
256                               p1->start, p1->end, megs);
257                     for (j = 0; j < dd->nroots; ++j) {
258                               u_int     aux = dd->roots[j];
259                               if (aux >= p1->start && aux <= p1->end) {
260                                         printf("FATAL: auxiliary root at %u\n", aux);
261                                         rv = 1;
262                               }
263                     }
264                     for (j = i; j--;) {
265                         part_t          *p2 = &dd->parts[j];
266                         if (p1->start >= p2->start && p1->start <= p2->end) {
267                               printf("FATAL: clash with %u/%u\n", p2->rsec, p2->rent);
268                               rv = 1;
269                         }
270                         if (p2->start >= p1->start && p2->start <= p1->end) {
271                               printf("FATAL: clash with %u/%u\n", p2->rsec, p2->rent);
272                               rv = 1;
273                         }
274                     }
275                     if (p1->start >= dd->bslst && p1->start <= dd->bslend) {
276                         printf("FATAL: partition overlaps with bad sector list\n");
277                         rv = 1;
278                     }
279                     if (dd->bslst >= p1->start && dd->bslst <= p1->end) {
280                         printf("FATAL: partition overlaps with bad sector list\n");
281                         rv = 1;
282                     }
283           }
284 
285           printf("\nTotal number of auxiliary roots: %u\n", dd->nroots);
286           printf("Total number of partitions    : %u\n", dd->nparts);
287           if (dd->nparts == 0) {
288                     printf("* Weird # of partitions (zero) *\n"); rv = 1;
289           }
290           if (dd->nparts > AHDI_MAXPARTS) {
291                     printf("* Too many AHDI partitions for the default NetBSD "
292                               "kernel *\n  Increase MAXAUXROOTS in src/sys/arch/"
293                               "atari/include/disklabel.h\n  to at least %u, and "
294                               "recompile the NetBSD kernel.\n", dd->nroots);
295                     rv = -1;
296           }
297           return(rv);
298 }
299 
300 static u_int
ahdi_getparts(dd,rsec,esec)301 ahdi_getparts(dd, rsec, esec)
302           disk_t                        *dd;
303           u_int                         rsec,
304                                         esec;
305 {
306           struct ahdi_part    *part, *end;
307           struct ahdi_root    *root;
308           u_int                         rv;
309 
310           root = disk_read(dd, rsec, 1);
311           if (!root) {
312                     rv = rsec + (rsec == 0);
313                     goto done;
314           }
315 
316           if (rsec == AHDI_BBLOCK)
317                     end = &root->ar_parts[AHDI_MAXRPD];
318           else end = &root->ar_parts[AHDI_MAXARPD];
319           for (part = root->ar_parts; part < end; ++part) {
320                     u_int     id = *((u_int32_t *)&part->ap_flg);
321                     if (!(id & 0x01000000))
322                               continue;
323                     if ((id &= 0x00ffffff) == AHDI_PID_XGM) {
324                               u_int     offs = part->ap_offs + esec;
325                               u_int     i = ++dd->nroots;
326                               dd->roots = xrealloc(dd->roots, i * sizeof *dd->roots);
327                               dd->roots[--i] = offs;
328                               rv = ahdi_getparts(dd, offs,
329                                                   esec == AHDI_BBLOCK ? offs : esec);
330                               if (rv)
331                                         goto done;
332                     } else {
333                               part_t    *p;
334                               u_int     i = ++dd->nparts;
335                               dd->parts = xrealloc(dd->parts, i * sizeof *dd->parts);
336                               p = &dd->parts[--i];
337                               *((u_int32_t *)&p->id) = id << 8;
338                               p->start = part->ap_offs + rsec;
339                               p->end   = p->start + part->ap_size - 1;
340                               p->rsec  = rsec;
341                               p->rent  = part - root->ar_parts;
342                     }
343           }
344           dd->hdsize = root->ar_hdsize;
345           dd->bslst  = root->ar_bslst;
346           dd->bslend = root->ar_bslst + root->ar_bslsize - 1;
347           rv = 0;
348 done:
349           free(root);
350           return(rv);
351 }
352