1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2c7de829cSwdenk /*
3c7de829cSwdenk * (C) Copyright 2001
4c7de829cSwdenk * Hans-Joerg Frieden, Hyperion Entertainment
5c7de829cSwdenk * Hans-JoergF@hyperion-entertainment.com
6c7de829cSwdenk */
7c7de829cSwdenk #include <common.h>
8c7de829cSwdenk #include <command.h>
9c7de829cSwdenk #include <ide.h>
10c7de829cSwdenk #include "part_amiga.h"
11c7de829cSwdenk
121811a928SAdam Ford #ifdef CONFIG_HAVE_BLOCK_DEVICE
13c7de829cSwdenk
14c7de829cSwdenk #undef AMIGA_DEBUG
15c7de829cSwdenk
16c7de829cSwdenk #ifdef AMIGA_DEBUG
17c7de829cSwdenk #define PRINTF(fmt, args...) printf(fmt ,##args)
18c7de829cSwdenk #else
19c7de829cSwdenk #define PRINTF(fmt, args...)
20c7de829cSwdenk #endif
21c7de829cSwdenk
22c7de829cSwdenk struct block_header
23c7de829cSwdenk {
24c7de829cSwdenk u32 id;
25c7de829cSwdenk u32 summed_longs;
26c7de829cSwdenk s32 chk_sum;
27c7de829cSwdenk };
28c7de829cSwdenk
29c7de829cSwdenk static unsigned char block_buffer[DEFAULT_SECTOR_SIZE];
30c7de829cSwdenk static struct rigid_disk_block rdb = {0};
31c7de829cSwdenk static struct bootcode_block bootcode = {0};
32c7de829cSwdenk
33c7de829cSwdenk /*
34c7de829cSwdenk * Copy a bcpl to a c string
35c7de829cSwdenk */
bcpl_strcpy(char * to,char * from)36c7de829cSwdenk static void bcpl_strcpy(char *to, char *from)
37c7de829cSwdenk {
38c7de829cSwdenk int len = *from++;
39c7de829cSwdenk
40c7de829cSwdenk while (len)
41c7de829cSwdenk {
42c7de829cSwdenk *to++ = *from++;
43c7de829cSwdenk len--;
44c7de829cSwdenk }
45c7de829cSwdenk *to = 0;
46c7de829cSwdenk }
47c7de829cSwdenk
48c7de829cSwdenk /*
49c7de829cSwdenk * Print a BCPL String. BCPL strings start with a byte with the length
50c7de829cSwdenk * of the string, and don't contain a terminating nul character
51c7de829cSwdenk */
bstr_print(char * string)52c7de829cSwdenk static void bstr_print(char *string)
53c7de829cSwdenk {
54c7de829cSwdenk int len = *string++;
55c7de829cSwdenk char buffer[256];
56c7de829cSwdenk int i;
57c7de829cSwdenk
58c7de829cSwdenk i = 0;
59c7de829cSwdenk while (len)
60c7de829cSwdenk {
61c7de829cSwdenk buffer[i++] = *string++;
62c7de829cSwdenk len--;
63c7de829cSwdenk }
64c7de829cSwdenk
65c7de829cSwdenk buffer[i] = 0;
66c7de829cSwdenk printf("%-10s", buffer);
67c7de829cSwdenk }
68c7de829cSwdenk
69c7de829cSwdenk /*
70c7de829cSwdenk * Sum a block. The checksum of a block must end up at zero
71c7de829cSwdenk * to be valid. The chk_sum field is selected so that adding
72c7de829cSwdenk * it yields zero.
73c7de829cSwdenk */
sum_block(struct block_header * header)74c7de829cSwdenk int sum_block(struct block_header *header)
75c7de829cSwdenk {
76c7de829cSwdenk s32 *block = (s32 *)header;
77c7de829cSwdenk u32 i;
78c7de829cSwdenk s32 sum = 0;
79c7de829cSwdenk
80c7de829cSwdenk for (i = 0; i < header->summed_longs; i++)
81c7de829cSwdenk sum += *block++;
82c7de829cSwdenk
83c7de829cSwdenk return (sum != 0);
84c7de829cSwdenk }
85c7de829cSwdenk
86c7de829cSwdenk /*
87c7de829cSwdenk * Print an AmigaOS disk type. Disk types are a four-byte identifier
88c7de829cSwdenk * describing the file system. They are usually written as a three-letter
89c7de829cSwdenk * word followed by a backslash and a version number. For example,
90c7de829cSwdenk * DOS\0 would be the original file system. SFS\0 would be SmartFileSystem.
91c7de829cSwdenk * DOS\1 is FFS.
92c7de829cSwdenk */
print_disk_type(u32 disk_type)93c7de829cSwdenk static void print_disk_type(u32 disk_type)
94c7de829cSwdenk {
95c7de829cSwdenk char buffer[6];
96c7de829cSwdenk buffer[0] = (disk_type & 0xFF000000)>>24;
97c7de829cSwdenk buffer[1] = (disk_type & 0x00FF0000)>>16;
98c7de829cSwdenk buffer[2] = (disk_type & 0x0000FF00)>>8;
99c7de829cSwdenk buffer[3] = '\\';
100c7de829cSwdenk buffer[4] = (disk_type & 0x000000FF) + '0';
101c7de829cSwdenk buffer[5] = 0;
102c7de829cSwdenk printf("%s", buffer);
103c7de829cSwdenk }
104c7de829cSwdenk
105c7de829cSwdenk /*
106c7de829cSwdenk * Print the info contained within the given partition block
107c7de829cSwdenk */
print_part_info(struct partition_block * p)108c7de829cSwdenk static void print_part_info(struct partition_block *p)
109c7de829cSwdenk {
110c7de829cSwdenk struct amiga_part_geometry *g;
111c7de829cSwdenk
112c7de829cSwdenk g = (struct amiga_part_geometry *)&(p->environment);
113c7de829cSwdenk
114c7de829cSwdenk bstr_print(p->drive_name);
115c7de829cSwdenk printf("%6d\t%6d\t",
116c7de829cSwdenk g->low_cyl * g->block_per_track * g->surfaces ,
117c7de829cSwdenk (g->high_cyl - g->low_cyl + 1) * g->block_per_track * g->surfaces - 1);
118c7de829cSwdenk print_disk_type(g->dos_type);
119c7de829cSwdenk printf("\t%5d\n", g->boot_priority);
120c7de829cSwdenk }
121c7de829cSwdenk
122c7de829cSwdenk /*
123c7de829cSwdenk * Search for the Rigid Disk Block. The rigid disk block is required
124c7de829cSwdenk * to be within the first 16 blocks of a drive, needs to have
125c7de829cSwdenk * the ID AMIGA_ID_RDISK ('RDSK') and needs to have a valid
126c7de829cSwdenk * sum-to-zero checksum
127c7de829cSwdenk */
get_rdisk(struct blk_desc * dev_desc)1284101f687SSimon Glass struct rigid_disk_block *get_rdisk(struct blk_desc *dev_desc)
129c7de829cSwdenk {
130c7de829cSwdenk int i;
131c7de829cSwdenk int limit;
132c7de829cSwdenk char *s;
133c7de829cSwdenk
13400caae6dSSimon Glass s = env_get("amiga_scanlimit");
135c7de829cSwdenk if (s)
13675eb82ecSunsik Kim limit = simple_strtoul(s, NULL, 10);
137c7de829cSwdenk else
138c7de829cSwdenk limit = AMIGA_BLOCK_LIMIT;
139c7de829cSwdenk
140c7de829cSwdenk for (i=0; i<limit; i++)
141c7de829cSwdenk {
1422a981dc2SSimon Glass ulong res = blk_dread(dev_desc, i, 1, (ulong *)block_buffer);
143c7de829cSwdenk if (res == 1)
144c7de829cSwdenk {
145c7de829cSwdenk struct rigid_disk_block *trdb = (struct rigid_disk_block *)block_buffer;
146c7de829cSwdenk if (trdb->id == AMIGA_ID_RDISK)
147c7de829cSwdenk {
148c7de829cSwdenk PRINTF("Rigid disk block suspect at %d, checking checksum\n",i);
149c7de829cSwdenk if (sum_block((struct block_header *)block_buffer) == 0)
150c7de829cSwdenk {
151c7de829cSwdenk PRINTF("FOUND\n");
152c7de829cSwdenk memcpy(&rdb, trdb, sizeof(struct rigid_disk_block));
153c7de829cSwdenk return (struct rigid_disk_block *)&rdb;
154c7de829cSwdenk }
155c7de829cSwdenk }
156c7de829cSwdenk }
157c7de829cSwdenk }
158c7de829cSwdenk PRINTF("Done scanning, no RDB found\n");
159c7de829cSwdenk return NULL;
160c7de829cSwdenk }
161c7de829cSwdenk
162c7de829cSwdenk /*
163c7de829cSwdenk * Search for boot code
164c7de829cSwdenk * Again, the first boot block must be located somewhere in the first 16 blocks, or rooted in the
165c7de829cSwdenk * Ridgid disk block
166c7de829cSwdenk */
167c7de829cSwdenk
get_bootcode(struct blk_desc * dev_desc)1684101f687SSimon Glass struct bootcode_block *get_bootcode(struct blk_desc *dev_desc)
169c7de829cSwdenk {
170c7de829cSwdenk int i;
171c7de829cSwdenk int limit;
172c7de829cSwdenk char *s;
173c7de829cSwdenk
17400caae6dSSimon Glass s = env_get("amiga_scanlimit");
175c7de829cSwdenk if (s)
17675eb82ecSunsik Kim limit = simple_strtoul(s, NULL, 10);
177c7de829cSwdenk else
178c7de829cSwdenk limit = AMIGA_BLOCK_LIMIT;
179c7de829cSwdenk
180c7de829cSwdenk PRINTF("Scanning for BOOT from 0 to %d\n", limit);
181c7de829cSwdenk
182c7de829cSwdenk for (i = 0; i < limit; i++)
183c7de829cSwdenk {
1842a981dc2SSimon Glass ulong res = blk_dread(dev_desc, i, 1, (ulong *)block_buffer);
185c7de829cSwdenk if (res == 1)
186c7de829cSwdenk {
187c7de829cSwdenk struct bootcode_block *boot = (struct bootcode_block *)block_buffer;
188c7de829cSwdenk if (boot->id == AMIGA_ID_BOOT)
189c7de829cSwdenk {
190c7de829cSwdenk PRINTF("BOOT block at %d, checking checksum\n", i);
191c7de829cSwdenk if (sum_block((struct block_header *)block_buffer) == 0)
192c7de829cSwdenk {
193c7de829cSwdenk PRINTF("Found valid bootcode block\n");
194c7de829cSwdenk memcpy(&bootcode, boot, sizeof(struct bootcode_block));
195c7de829cSwdenk return &bootcode;
196c7de829cSwdenk }
197c7de829cSwdenk }
198c7de829cSwdenk }
199c7de829cSwdenk }
200c7de829cSwdenk
201c7de829cSwdenk PRINTF("No boot code found on disk\n");
202c7de829cSwdenk return 0;
203c7de829cSwdenk }
204c7de829cSwdenk
205c7de829cSwdenk /*
206c7de829cSwdenk * Test if the given partition has an Amiga partition table/Rigid
207c7de829cSwdenk * Disk block
208c7de829cSwdenk */
part_test_amiga(struct blk_desc * dev_desc)209084bf4c2SSimon Glass static int part_test_amiga(struct blk_desc *dev_desc)
210c7de829cSwdenk {
211c7de829cSwdenk struct rigid_disk_block *rdb;
212c7de829cSwdenk struct bootcode_block *bootcode;
213c7de829cSwdenk
214084bf4c2SSimon Glass PRINTF("part_test_amiga: Testing for an Amiga RDB partition\n");
215c7de829cSwdenk
216c7de829cSwdenk rdb = get_rdisk(dev_desc);
217c7de829cSwdenk if (rdb)
218c7de829cSwdenk {
219c7de829cSwdenk bootcode = get_bootcode(dev_desc);
220c7de829cSwdenk if (bootcode)
221084bf4c2SSimon Glass PRINTF("part_test_amiga: bootable Amiga disk\n");
222c7de829cSwdenk else
223084bf4c2SSimon Glass PRINTF("part_test_amiga: non-bootable Amiga disk\n");
224c7de829cSwdenk
225c7de829cSwdenk return 0;
226c7de829cSwdenk }
227c7de829cSwdenk else
228c7de829cSwdenk {
229084bf4c2SSimon Glass PRINTF("part_test_amiga: no RDB found\n");
230c7de829cSwdenk return -1;
231c7de829cSwdenk }
232c7de829cSwdenk
233c7de829cSwdenk }
234c7de829cSwdenk
235c7de829cSwdenk /*
236c7de829cSwdenk * Find partition number partnum on the given drive.
237c7de829cSwdenk */
find_partition(struct blk_desc * dev_desc,int partnum)2384101f687SSimon Glass static struct partition_block *find_partition(struct blk_desc *dev_desc,
2394101f687SSimon Glass int partnum)
240c7de829cSwdenk {
241c7de829cSwdenk struct rigid_disk_block *rdb;
242c7de829cSwdenk struct partition_block *p;
243c7de829cSwdenk u32 block;
244c7de829cSwdenk
245c7de829cSwdenk PRINTF("Trying to find partition block %d\n", partnum);
246c7de829cSwdenk rdb = get_rdisk(dev_desc);
247c7de829cSwdenk if (!rdb)
248c7de829cSwdenk {
249c7de829cSwdenk PRINTF("find_partition: no rdb found\n");
250c7de829cSwdenk return NULL;
251c7de829cSwdenk }
252c7de829cSwdenk
253c7de829cSwdenk PRINTF("find_partition: Scanning partition list\n");
254c7de829cSwdenk
255c7de829cSwdenk block = rdb->partition_list;
256c7de829cSwdenk PRINTF("find_partition: partition list at 0x%x\n", block);
257c7de829cSwdenk
258c7de829cSwdenk while (block != 0xFFFFFFFF)
259c7de829cSwdenk {
2602a981dc2SSimon Glass ulong res = blk_dread(dev_desc, block, 1, (ulong *)block_buffer);
261c7de829cSwdenk if (res == 1)
262c7de829cSwdenk {
263c7de829cSwdenk p = (struct partition_block *)block_buffer;
264c7de829cSwdenk if (p->id == AMIGA_ID_PART)
265c7de829cSwdenk {
266c7de829cSwdenk PRINTF("PART block suspect at 0x%x, checking checksum\n",block);
267c7de829cSwdenk if (sum_block((struct block_header *)p) == 0)
268c7de829cSwdenk {
269c7de829cSwdenk if (partnum == 0) break;
270c7de829cSwdenk else
271c7de829cSwdenk {
272c7de829cSwdenk partnum--;
273c7de829cSwdenk block = p->next;
274c7de829cSwdenk }
275c7de829cSwdenk }
276c7de829cSwdenk } else block = 0xFFFFFFFF;
277c7de829cSwdenk } else block = 0xFFFFFFFF;
278c7de829cSwdenk }
279c7de829cSwdenk
280c7de829cSwdenk if (block == 0xFFFFFFFF)
281c7de829cSwdenk {
282c7de829cSwdenk PRINTF("PART block not found\n");
283c7de829cSwdenk return NULL;
284c7de829cSwdenk }
285c7de829cSwdenk
286c7de829cSwdenk return (struct partition_block *)block_buffer;
287c7de829cSwdenk }
288c7de829cSwdenk
289c7de829cSwdenk /*
290c7de829cSwdenk * Get info about a partition
291c7de829cSwdenk */
part_get_info_amiga(struct blk_desc * dev_desc,int part,disk_partition_t * info)2923e8bd469SSimon Glass static int part_get_info_amiga(struct blk_desc *dev_desc, int part,
2934101f687SSimon Glass disk_partition_t *info)
294c7de829cSwdenk {
295c7de829cSwdenk struct partition_block *p = find_partition(dev_desc, part-1);
296c7de829cSwdenk struct amiga_part_geometry *g;
297c7de829cSwdenk u32 disk_type;
298c7de829cSwdenk
299c7de829cSwdenk if (!p) return -1;
300c7de829cSwdenk
301c7de829cSwdenk g = (struct amiga_part_geometry *)&(p->environment);
302c7de829cSwdenk info->start = g->low_cyl * g->block_per_track * g->surfaces;
303c7de829cSwdenk info->size = (g->high_cyl - g->low_cyl + 1) * g->block_per_track * g->surfaces - 1;
304c7de829cSwdenk info->blksz = rdb.block_bytes;
30595a6f9dfSSimon Glass bcpl_strcpy((char *)info->name, p->drive_name);
306c7de829cSwdenk
307c7de829cSwdenk
308c7de829cSwdenk disk_type = g->dos_type;
309c7de829cSwdenk
310c7de829cSwdenk info->type[0] = (disk_type & 0xFF000000)>>24;
311c7de829cSwdenk info->type[1] = (disk_type & 0x00FF0000)>>16;
312c7de829cSwdenk info->type[2] = (disk_type & 0x0000FF00)>>8;
313c7de829cSwdenk info->type[3] = '\\';
314c7de829cSwdenk info->type[4] = (disk_type & 0x000000FF) + '0';
315c7de829cSwdenk info->type[5] = 0;
316c7de829cSwdenk
317c7de829cSwdenk return 0;
318c7de829cSwdenk }
319c7de829cSwdenk
part_print_amiga(struct blk_desc * dev_desc)320084bf4c2SSimon Glass static void part_print_amiga(struct blk_desc *dev_desc)
321c7de829cSwdenk {
322c7de829cSwdenk struct rigid_disk_block *rdb;
323c7de829cSwdenk struct bootcode_block *boot;
324c7de829cSwdenk struct partition_block *p;
325c7de829cSwdenk u32 block;
326c7de829cSwdenk int i = 1;
327c7de829cSwdenk
328c7de829cSwdenk rdb = get_rdisk(dev_desc);
329c7de829cSwdenk if (!rdb)
330c7de829cSwdenk {
331084bf4c2SSimon Glass PRINTF("part_print_amiga: no rdb found\n");
332c7de829cSwdenk return;
333c7de829cSwdenk }
334c7de829cSwdenk
335084bf4c2SSimon Glass PRINTF("part_print_amiga: Scanning partition list\n");
336c7de829cSwdenk
337c7de829cSwdenk block = rdb->partition_list;
338084bf4c2SSimon Glass PRINTF("part_print_amiga: partition list at 0x%x\n", block);
339c7de829cSwdenk
340c7de829cSwdenk printf("Summary: DiskBlockSize: %d\n"
341c7de829cSwdenk " Cylinders : %d\n"
342c7de829cSwdenk " Sectors/Track: %d\n"
343c7de829cSwdenk " Heads : %d\n\n",
344c7de829cSwdenk rdb->block_bytes, rdb->cylinders, rdb->sectors,
345c7de829cSwdenk rdb->heads);
346c7de829cSwdenk
347c7de829cSwdenk printf(" First Num. \n"
348c7de829cSwdenk "Nr. Part. Name Block Block Type Boot Priority\n");
349c7de829cSwdenk
350c7de829cSwdenk while (block != 0xFFFFFFFF)
351c7de829cSwdenk {
352c7de829cSwdenk ulong res;
353c7de829cSwdenk
354c7de829cSwdenk PRINTF("Trying to load block #0x%X\n", block);
355c7de829cSwdenk
3562a981dc2SSimon Glass res = blk_dread(dev_desc, block, 1, (ulong *)block_buffer);
357c7de829cSwdenk if (res == 1)
358c7de829cSwdenk {
359c7de829cSwdenk p = (struct partition_block *)block_buffer;
360c7de829cSwdenk if (p->id == AMIGA_ID_PART)
361c7de829cSwdenk {
362c7de829cSwdenk PRINTF("PART block suspect at 0x%x, checking checksum\n",block);
363c7de829cSwdenk if (sum_block((struct block_header *)p) == 0)
364c7de829cSwdenk {
365c7de829cSwdenk printf("%-4d ", i); i++;
366c7de829cSwdenk print_part_info(p);
367c7de829cSwdenk block = p->next;
368c7de829cSwdenk }
369c7de829cSwdenk } else block = 0xFFFFFFFF;
370c7de829cSwdenk } else block = 0xFFFFFFFF;
371c7de829cSwdenk }
372c7de829cSwdenk
373c7de829cSwdenk boot = get_bootcode(dev_desc);
374c7de829cSwdenk if (boot)
375c7de829cSwdenk {
376c7de829cSwdenk printf("Disk is bootable\n");
377c7de829cSwdenk }
378c7de829cSwdenk }
379c7de829cSwdenk
38096e5b03cSSimon Glass U_BOOT_PART_TYPE(amiga) = {
38196e5b03cSSimon Glass .name = "AMIGA",
38296e5b03cSSimon Glass .part_type = PART_TYPE_AMIGA,
38387b8530fSPetr Kulhavy .max_entries = AMIGA_ENTRY_NUMBERS,
3843e8bd469SSimon Glass .get_info = part_get_info_amiga,
385084bf4c2SSimon Glass .print = part_print_amiga,
386084bf4c2SSimon Glass .test = part_test_amiga,
38796e5b03cSSimon Glass };
38896e5b03cSSimon Glass
389c7de829cSwdenk #endif
390