Add PCI support for MPC8250 Boards (PM825 module)
[karo-tx-uboot.git] / disk / part_amiga.c
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