xref: /openbmc/u-boot/disk/part_amiga.c (revision 8bde7f77)
1 /*
2  * (C) Copyright 2001
3  * Hans-Joerg Frieden, Hyperion Entertainment
4  * Hans-JoergF@hyperion-entertainment.com
5  *
6  * See file CREDITS for list of people who contributed to this
7  * project.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License as
11  * published by the Free Software Foundation; either version 2 of
12  * the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22  * MA 02111-1307 USA
23  */
24 #include <common.h>
25 #include <command.h>
26 #include <ide.h>
27 #include <cmd_disk.h>
28 #include "part_amiga.h"
29 
30 #if ((CONFIG_COMMANDS & CFG_CMD_IDE) || (CONFIG_COMMANDS & CFG_CMD_SCSI)) && defined(CONFIG_AMIGA_PARTITION)
31 
32 #undef AMIGA_DEBUG
33 
34 #ifdef AMIGA_DEBUG
35 #define PRINTF(fmt, args...) printf(fmt ,##args)
36 #else
37 #define PRINTF(fmt, args...)
38 #endif
39 
40 struct block_header
41 {
42     u32 id;
43     u32 summed_longs;
44     s32 chk_sum;
45 };
46 
47 static unsigned char block_buffer[DEFAULT_SECTOR_SIZE];
48 static struct rigid_disk_block rdb = {0};
49 static struct bootcode_block bootcode = {0};
50 
51 /*
52  * Copy a bcpl to a c string
53  */
54 static void bcpl_strcpy(char *to, char *from)
55 {
56     int len = *from++;
57 
58     while (len)
59     {
60 	*to++ = *from++;
61 	len--;
62     }
63     *to = 0;
64 }
65 
66 /*
67  * Print a BCPL String. BCPL strings start with a byte with the length
68  * of the string, and don't contain a terminating nul character
69  */
70 static void bstr_print(char *string)
71 {
72     int len = *string++;
73     char buffer[256];
74     int i;
75 
76     i = 0;
77     while (len)
78     {
79 	buffer[i++] = *string++;
80 	len--;
81     }
82 
83     buffer[i] = 0;
84     printf("%-10s", buffer);
85 }
86 
87 /*
88  * Sum a block. The checksum of a block must end up at zero
89  * to be valid. The chk_sum field is selected so that adding
90  * it yields zero.
91  */
92 int sum_block(struct block_header *header)
93 {
94     s32 *block = (s32 *)header;
95     u32 i;
96     s32 sum = 0;
97 
98     for (i = 0; i < header->summed_longs; i++)
99 	sum += *block++;
100 
101     return (sum != 0);
102 }
103 
104 /*
105  * Print an AmigaOS disk type. Disk types are a four-byte identifier
106  * describing the file system. They are usually written as a three-letter
107  * word followed by a backslash and a version number. For example,
108  * DOS\0 would be the original file system. SFS\0 would be SmartFileSystem.
109  * DOS\1 is FFS.
110  */
111 static void print_disk_type(u32 disk_type)
112 {
113     char buffer[6];
114     buffer[0] = (disk_type & 0xFF000000)>>24;
115     buffer[1] = (disk_type & 0x00FF0000)>>16;
116     buffer[2] = (disk_type & 0x0000FF00)>>8;
117     buffer[3] = '\\';
118     buffer[4] = (disk_type & 0x000000FF) + '0';
119     buffer[5] = 0;
120     printf("%s", buffer);
121 }
122 
123 /*
124  * Print the info contained within the given partition block
125  */
126 static void print_part_info(struct partition_block *p)
127 {
128     struct amiga_part_geometry *g;
129 
130     g = (struct amiga_part_geometry *)&(p->environment);
131 
132     bstr_print(p->drive_name);
133     printf("%6d\t%6d\t",
134 	   g->low_cyl * g->block_per_track * g->surfaces ,
135 	   (g->high_cyl - g->low_cyl + 1) * g->block_per_track * g->surfaces - 1);
136     print_disk_type(g->dos_type);
137     printf("\t%5d\n", g->boot_priority);
138 }
139 
140 /*
141  * Search for the Rigid Disk Block. The rigid disk block is required
142  * to be within the first 16 blocks of a drive, needs to have
143  * the ID AMIGA_ID_RDISK ('RDSK') and needs to have a valid
144  * sum-to-zero checksum
145  */
146 struct rigid_disk_block *get_rdisk(block_dev_desc_t *dev_desc)
147 {
148     int i;
149     int limit;
150     char *s;
151 
152     s = getenv("amiga_scanlimit");
153     if (s)
154 	limit = atoi(s);
155     else
156 	limit = AMIGA_BLOCK_LIMIT;
157 
158     for (i=0; i<limit; i++)
159     {
160 	ulong res = dev_desc->block_read(dev_desc->dev, i, 1,
161 					 (ulong *)block_buffer);
162 	if (res == 1)
163 	{
164 	    struct rigid_disk_block *trdb = (struct rigid_disk_block *)block_buffer;
165 	    if (trdb->id == AMIGA_ID_RDISK)
166 	    {
167 		PRINTF("Rigid disk block suspect at %d, checking checksum\n",i);
168 		if (sum_block((struct block_header *)block_buffer) == 0)
169 		{
170 		    PRINTF("FOUND\n");
171 		    memcpy(&rdb, trdb, sizeof(struct rigid_disk_block));
172 		    return (struct rigid_disk_block *)&rdb;
173 		}
174 	    }
175 	}
176     }
177     PRINTF("Done scanning, no RDB found\n");
178     return NULL;
179 }
180 
181 /*
182  * Search for boot code
183  * Again, the first boot block must be located somewhere in the first 16 blocks, or rooted in the
184  * Ridgid disk block
185  */
186 
187 struct bootcode_block *get_bootcode(block_dev_desc_t *dev_desc)
188 {
189     int i;
190     int limit;
191     char *s;
192 
193     s = getenv("amiga_scanlimit");
194     if (s)
195 	limit = atoi(s);
196     else
197 	limit = AMIGA_BLOCK_LIMIT;
198 
199     PRINTF("Scanning for BOOT from 0 to %d\n", limit);
200 
201     for (i = 0; i < limit; i++)
202     {
203 	ulong res = dev_desc->block_read(dev_desc->dev, i, 1, (ulong *)block_buffer);
204 	if (res == 1)
205 	{
206 	    struct bootcode_block *boot = (struct bootcode_block *)block_buffer;
207 	    if (boot->id == AMIGA_ID_BOOT)
208 	    {
209 		PRINTF("BOOT block at %d, checking checksum\n", i);
210 		if (sum_block((struct block_header *)block_buffer) == 0)
211 		{
212 		    PRINTF("Found valid bootcode block\n");
213 		    memcpy(&bootcode, boot, sizeof(struct bootcode_block));
214 		    return &bootcode;
215 		}
216 	    }
217 	}
218     }
219 
220     PRINTF("No boot code found on disk\n");
221     return 0;
222 }
223 
224 /*
225  * Test if the given partition has an Amiga partition table/Rigid
226  * Disk block
227  */
228 int test_part_amiga(block_dev_desc_t *dev_desc)
229 {
230     struct rigid_disk_block *rdb;
231     struct bootcode_block *bootcode;
232 
233     PRINTF("test_part_amiga: Testing for an Amiga RDB partition\n");
234 
235     rdb = get_rdisk(dev_desc);
236     if (rdb)
237     {
238 	bootcode = get_bootcode(dev_desc);
239 	if (bootcode)
240 	    PRINTF("test_part_amiga: bootable Amiga disk\n");
241 	else
242 	    PRINTF("test_part_amiga: non-bootable Amiga disk\n");
243 
244 	return 0;
245     }
246     else
247     {
248 	PRINTF("test_part_amiga: no RDB found\n");
249 	return -1;
250     }
251 
252 }
253 
254 /*
255  * Find partition number partnum on the given drive.
256  */
257 static struct partition_block *find_partition(block_dev_desc_t *dev_desc, int partnum)
258 {
259     struct rigid_disk_block *rdb;
260     struct partition_block *p;
261     u32 block;
262 
263     PRINTF("Trying to find partition block %d\n", partnum);
264     rdb = get_rdisk(dev_desc);
265     if (!rdb)
266     {
267 	PRINTF("find_partition: no rdb found\n");
268 	return NULL;
269     }
270 
271     PRINTF("find_partition: Scanning partition list\n");
272 
273     block = rdb->partition_list;
274     PRINTF("find_partition: partition list at 0x%x\n", block);
275 
276     while (block != 0xFFFFFFFF)
277     {
278 	ulong res = dev_desc->block_read(dev_desc->dev, block, 1,
279 					 (ulong *)block_buffer);
280 	if (res == 1)
281 	{
282 	    p = (struct partition_block *)block_buffer;
283 	    if (p->id == AMIGA_ID_PART)
284 	    {
285 		PRINTF("PART block suspect at 0x%x, checking checksum\n",block);
286 		if (sum_block((struct block_header *)p) == 0)
287 		{
288 		    if (partnum == 0) break;
289 		    else
290 		    {
291 			partnum--;
292 			block = p->next;
293 		    }
294 		}
295 	    } else block = 0xFFFFFFFF;
296 	} else block = 0xFFFFFFFF;
297     }
298 
299     if (block == 0xFFFFFFFF)
300     {
301 	PRINTF("PART block not found\n");
302 	return NULL;
303     }
304 
305     return (struct partition_block *)block_buffer;
306 }
307 
308 /*
309  * Get info about a partition
310  */
311 int get_partition_info_amiga (block_dev_desc_t *dev_desc, int part, disk_partition_t *info)
312 {
313     struct partition_block *p = find_partition(dev_desc, part-1);
314     struct amiga_part_geometry *g;
315     u32 disk_type;
316 
317     if (!p) return -1;
318 
319     g = (struct amiga_part_geometry *)&(p->environment);
320     info->start = g->low_cyl  * g->block_per_track * g->surfaces;
321     info->size  = (g->high_cyl - g->low_cyl + 1) * g->block_per_track * g->surfaces - 1;
322     info->blksz = rdb.block_bytes;
323     bcpl_strcpy(info->name, p->drive_name);
324 
325 
326     disk_type = g->dos_type;
327 
328     info->type[0] = (disk_type & 0xFF000000)>>24;
329     info->type[1] = (disk_type & 0x00FF0000)>>16;
330     info->type[2] = (disk_type & 0x0000FF00)>>8;
331     info->type[3] = '\\';
332     info->type[4] = (disk_type & 0x000000FF) + '0';
333     info->type[5] = 0;
334 
335     return 0;
336 }
337 
338 void print_part_amiga (block_dev_desc_t *dev_desc)
339 {
340     struct rigid_disk_block *rdb;
341     struct bootcode_block *boot;
342     struct partition_block *p;
343     u32 block;
344     int i = 1;
345 
346     rdb = get_rdisk(dev_desc);
347     if (!rdb)
348     {
349 	PRINTF("print_part_amiga: no rdb found\n");
350 	return;
351     }
352 
353     PRINTF("print_part_amiga: Scanning partition list\n");
354 
355     block = rdb->partition_list;
356     PRINTF("print_part_amiga: partition list at 0x%x\n", block);
357 
358     printf("Summary:  DiskBlockSize: %d\n"
359 	   "          Cylinders    : %d\n"
360 	   "          Sectors/Track: %d\n"
361 	   "          Heads        : %d\n\n",
362 	   rdb->block_bytes, rdb->cylinders, rdb->sectors,
363 	   rdb->heads);
364 
365     printf("                 First   Num. \n"
366 	   "Nr.  Part. Name  Block   Block  Type        Boot Priority\n");
367 
368     while (block != 0xFFFFFFFF)
369     {
370 	ulong res;
371 
372 	PRINTF("Trying to load block #0x%X\n", block);
373 
374 	res = dev_desc->block_read(dev_desc->dev, block, 1,
375 				   (ulong *)block_buffer);
376 	if (res == 1)
377 	{
378 	    p = (struct partition_block *)block_buffer;
379 	    if (p->id == AMIGA_ID_PART)
380 	    {
381 		PRINTF("PART block suspect at 0x%x, checking checksum\n",block);
382 		if (sum_block((struct block_header *)p) == 0)
383 		{
384 		    printf("%-4d ", i); i++;
385 		    print_part_info(p);
386 		    block = p->next;
387 		}
388 	    } else block = 0xFFFFFFFF;
389 	} else block = 0xFFFFFFFF;
390     }
391 
392     boot = get_bootcode(dev_desc);
393     if (boot)
394     {
395 	printf("Disk is bootable\n");
396     }
397 }
398 
399 #endif
400