xref: /openbmc/u-boot/disk/part_amiga.c (revision 83d290c56fab2d38cd1ab4c4cc7099559c1d5046)
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