Add missing includes
[yaboot.git] / second / partition.c
index 39f23ca1083e108384b187bc8d87435e7af4b844..0cb8ae85f1768bb7aef755c6ef37f64b64f5f168 100644 (file)
@@ -1,23 +1,31 @@
-/* File related stuff
-   
-   Copyright (C) 1999 Benjamin Herrenschmidt
-
-   Todo: Add disklabel (or let OF do it ?). Eventually think about
-         fixing CDROM handling by directly using the ATAPI layer.
-   
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-   
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+/*
+ *  partition.c - partition table support
+ *
+ *  Copyright (C) 2004 Sven Luther
+ *
+ *  Copyright (C) 2001, 2002 Ethan Benson
+ *
+ *  Copyright (C) 1999 Benjamin Herrenschmidt
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+/*
+ *  Todo: Add disklabel (or let OF do it ?). Eventually think about
+ *        fixing CDROM handling by directly using the ATAPI layer.
+ */
 
 #include "ctype.h"
 #include "types.h"
 #include "stdlib.h"
 #include "mac-part.h"
 #include "fdisk-part.h"
+#include "amiga-part.h"
 #include "partition.h"
 #include "prom.h"
 #include "string.h"
 #include "linux/iso_fs.h"
+#include "debug.h"
+#include "errors.h"
+#include "byteorder.h"
 
 /* We currently don't check the partition type, some users
  * are putting crap there and still expect it to work...
 
 #ifdef CHECK_FOR_VALID_MAC_PARTITION_TYPE
 static const char *valid_mac_partition_types[] = {
-    "apple_unix_svr2",
-    "linux",
-    "apple_hfs",
-    "apple_boot",
-    "apple_bootstrap",
-    NULL
+     "apple_unix_svr2",
+     "linux",
+     "apple_hfs",
+     "apple_boot",
+     "apple_bootstrap",
+     NULL
 };
 #endif
-    
 
-/* Local functions */
-static unsigned long swab32(unsigned long value);
 
 #define MAX_BLOCK_SIZE 2048
 static unsigned char block_buffer[MAX_BLOCK_SIZE];
 
 static void
-add_new_partition( struct partition_t**        list, int part_number,
-                   unsigned long part_start, unsigned long part_size,
-                   unsigned short part_blocksize )
+add_new_partition(struct partition_t** list, int part_number, const char *part_type,
+                 const char *part_name, unsigned long part_start, unsigned long part_size,
+                 unsigned short part_blocksize, int sys_ind)
 {
-       struct partition_t*     part;
-       part = (struct partition_t*)malloc(sizeof(struct partition_t));
-       
-       part->part_number = part_number;
-       part->part_start = part_start;
-       part->part_size = part_size;
-       part->blocksize = part_blocksize;
-
-        /* Tack this entry onto the list */
-       part->next = *list;
-       *list = part;
+     struct partition_t*       part;
+     part = (struct partition_t*)malloc(sizeof(struct partition_t));
+
+     part->part_number = part_number;
+     strncpy(part->part_type, part_type, MAX_PART_NAME);
+     strncpy(part->part_name, part_name, MAX_PART_NAME);
+     part->part_start = part_start;
+     part->part_size = part_size;
+     part->blocksize = part_blocksize;
+     part->sys_ind = sys_ind;
+
+     /* Tack this entry onto the list */
+     part->next = *list;
+     *list = part;
 }
 
 /* Note, we rely on partitions being dev-block-size aligned,
@@ -79,66 +91,69 @@ static void
 partition_mac_lookup( const char *dev_name, prom_handle disk,
                       unsigned int prom_blksize, struct partition_t** list )
 {
-       int block, map_size;
-
-        /* block_buffer contains block 0 from the partitions_lookup() stage */
-       struct mac_partition* part = (struct mac_partition *)block_buffer;
-        unsigned short ptable_block_size =
-                        ((struct mac_driver_desc *)block_buffer)->block_size;
-       
-       map_size = 1;
-       for (block=1; block < map_size + 1; block++)
-        {
+     int block, map_size;
+
+     /* block_buffer contains block 0 from the partitions_lookup() stage */
+     struct mac_partition* part = (struct mac_partition *)block_buffer;
+     unsigned short ptable_block_size =
+         ((struct mac_driver_desc *)block_buffer)->block_size;
+
+     map_size = 1;
+     for (block=1; block < map_size + 1; block++)
+     {
 #ifdef CHECK_FOR_VALID_MAC_PARTITION_TYPE
-                int valid = 0;
-                const char *ptype;
+         int valid = 0;
+         const char *ptype;
 #endif
-               if (prom_readblocks(disk, block, 1, block_buffer) != 1) {
-                       prom_printf("Can't read partition %d\n", block);
-                       break;
-               }
-               if (part->signature != MAC_PARTITION_MAGIC) {
+         if (prom_readblocks(disk, block, 1, block_buffer) != 1) {
+              prom_printf("Can't read partition %d\n", block);
+              break;
+         }
+         if (part->signature != MAC_PARTITION_MAGIC) {
 #if 0
-                       prom_printf("Wrong partition %d signature\n", block);
+              prom_printf("Wrong partition %d signature\n", block);
 #endif
-                       break;
-               }
-               if (block == 1)
-                       map_size = part->map_count;
-               
+              break;
+         }
+         if (block == 1)
+              map_size = part->map_count;
+
 #ifdef CHECK_FOR_VALID_MAC_PARTITION_TYPE
-                /* We don't bother looking at swap partitions of any type, 
-                 * and the rest are the ones we know about */
-                for (ptype = valid_mac_partition_types; ptype; ptype++)
-                    if (!strcmp (part->type, ptype))
-                    {
-                        valid = 1;
-                        break;
-                    }
+         /* We don't bother looking at swap partitions of any type,
+          * and the rest are the ones we know about */
+         for (ptype = valid_mac_partition_types; ptype; ptype++)
+              if (!strcmp (part->type, ptype))
+              {
+                   valid = 1;
+                   break;
+              }
 #if DEBUG
-                if (!valid)
-                    prom_printf( "MAC: Unsupported partition #%d; type=%s\n",
-                        block, part->type );
+         if (!valid)
+              prom_printf( "MAC: Unsupported partition #%d; type=%s\n",
+                           block, part->type );
 #endif
 #endif
 
 
 #ifdef CHECK_FOR_VALID_MAC_PARTITION_TYPE
-                if (valid)
+         if (valid)
 #endif
-                /* We use the partition block size from the partition table.
-                 * The filesystem implmentations are responsible for mapping
-                 * to their own fs blocksize */
-                    add_new_partition(
-                        list, /* partition list */
-                        block, /* partition number */
-                        part->start_block + part->data_start, /* start */
-                        part->data_count, /* size */
-                        ptable_block_size );
-       }
+              /* We use the partition block size from the partition table.
+               * The filesystem implmentations are responsible for mapping
+               * to their own fs blocksize */
+              add_new_partition(
+                   list, /* partition list */
+                   block, /* partition number */
+                   part->type, /* type */
+                   part->name, /* name */
+                   part->start_block + part->data_start, /* start */
+                   part->data_count, /* size */
+                   ptable_block_size,
+                   0);
+     }
 }
 
-/* 
+/*
  * Same function as partition_mac_lookup(), except for fdisk
  * partitioned disks.
  */
@@ -146,23 +161,26 @@ static void
 partition_fdisk_lookup( const char *dev_name, prom_handle disk,
                         unsigned int prom_blksize, struct partition_t** list )
 {
-       int partition;
+     int partition;
 
-       /* fdisk partition tables start at offset 0x1be
-        * from byte 0 of the boot drive.
-        */
-       struct fdisk_partition* part = 
+     /* fdisk partition tables start at offset 0x1be
+      * from byte 0 of the boot drive.
+      */
+     struct fdisk_partition* part =
          (struct fdisk_partition *) (block_buffer + 0x1be);
 
-       for (partition=1; partition <= 4 ;partition++, part++) {
-           if (part->sys_ind == LINUX_NATIVE) {
-               add_new_partition(  list,
-                                   partition,
-                                    swab32(*(unsigned int *)(part->start4)),
-                                    swab32(*(unsigned int *)(part->size4)),
-                                   512 /*blksize*/ );
-           }
-       }
+     for (partition=1; partition <= 4 ;partition++, part++) {
+         if (part->sys_ind == LINUX_NATIVE || part->sys_ind == LINUX_RAID) {
+              add_new_partition(  list,
+                                  partition,
+                                  "Linux", /* type */
+                                  '\0', /* name */
+                                  le32_to_cpu(*(unsigned int *)part->start4),
+                                  le32_to_cpu(*(unsigned int *)part->size4),
+                                  512 /*blksize*/,
+                                  part->sys_ind /* partition type */ );
+         }
+     }
 }
 
 /* I don't know if it's possible to handle multisession and other multitrack
@@ -174,111 +192,251 @@ partition_fdisk_lookup( const char *dev_name, prom_handle disk,
 static int
 identify_iso_fs(ihandle device, unsigned int *iso_root_block)
 {
-       int block;
-
-       for (block = 16; block < 100; block++) {
-           struct iso_volume_descriptor  * vdp;
-
-           if (prom_readblocks(device, block, 1, block_buffer) != 1) {
-               prom_printf("Can't read volume desc block %d\n", block);
-               break;
-           }
-               
-           vdp = (struct iso_volume_descriptor *)block_buffer;
-           
-           /* Due to the overlapping physical location of the descriptors, 
-            * ISO CDs can match hdp->id==HS_STANDARD_ID as well. To ensure 
-            * proper identification in this case, we first check for ISO.
-            */
-           if (strncmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0) {
-               *iso_root_block = block;
-               return 1;
-           }
+     int block;
+
+     for (block = 16; block < 100; block++) {
+         struct iso_volume_descriptor  * vdp;
+
+         if (prom_readblocks(device, block, 1, block_buffer) != 1) {
+              prom_printf("Can't read volume desc block %d\n", block);
+              break;
+         }
+
+         vdp = (struct iso_volume_descriptor *)block_buffer;
+
+         /* Due to the overlapping physical location of the descriptors,
+          * ISO CDs can match hdp->id==HS_STANDARD_ID as well. To ensure
+          * proper identification in this case, we first check for ISO.
+          */
+         if (strncmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0) {
+              *iso_root_block = block;
+              return 1;
+         }
+     }
+
+     return 0;
+}
+
+/*
+ * Detects and read amiga partition tables.
+ */
+
+static int
+_amiga_checksum (unsigned int blk_size)
+{
+       unsigned int sum;
+       int i, end;
+       unsigned int *amiga_block = (unsigned int *) block_buffer;
+
+       sum = amiga_block[0];
+       end = amiga_block[AMIGA_LENGTH];
+
+       if (end > blk_size) end = blk_size;
+
+       for (i = 1; i < end; i++) sum += amiga_block[i];
+
+       return sum;
+}
+
+static int
+_amiga_find_rdb (const char *dev_name, prom_handle disk, unsigned int prom_blksize)
+{
+       int i;
+       unsigned int *amiga_block = (unsigned int *) block_buffer;
+
+       for (i = 0; i<AMIGA_RDB_MAX; i++) {
+               if (i != 0) {
+                       if (prom_readblocks(disk, i, 1, block_buffer) != 1) {
+                               prom_printf("Can't read boot block %d\n", i);
+                               break;
+                       }
+               }
+               if ((amiga_block[AMIGA_ID] == AMIGA_ID_RDB) && (_amiga_checksum (prom_blksize) == 0))
+                       return 1;
+       }
+       /* Amiga partition table not found, let's reread block 0 */
+       if (prom_readblocks(disk, 0, 1, block_buffer) != 1) {
+               prom_printf("Can't read boot blocks\n");
+               return 0; /* TODO: something bad happened, should fail more verbosely */
        }
-       
        return 0;
 }
 
-struct partition_t*
-partitions_lookup(const char *device)
+static void
+partition_amiga_lookup( const char *dev_name, prom_handle disk,
+                        unsigned int prom_blksize, struct partition_t** list )
 {
-       ihandle disk;
-       struct mac_driver_desc *desc = (struct mac_driver_desc *)block_buffer;
-       struct partition_t* list = NULL;
-       unsigned int prom_blksize, iso_root_block;
-       
-       strncpy(block_buffer, device, 2040);
-       strcat(block_buffer, ":0");
-       
-       /* Open device */
-       disk = prom_open(block_buffer);
-       if (disk == NULL) {
-               prom_printf("Can't open device <%s>\n", block_buffer);
-               goto bail;
-       }
-       prom_blksize = prom_getblksize(disk);
-#if DEBUG
-       prom_printf("block size of device is %d\n", prom_blksize);
-#endif 
-       if (prom_blksize <= 1)
-               prom_blksize = 512;
-       if (prom_blksize > MAX_BLOCK_SIZE) {
-               prom_printf("block_size %d not supported !\n", prom_blksize);
-               goto bail;
+       int partition, part;
+       unsigned int blockspercyl;
+       unsigned int *amiga_block = (unsigned int *) block_buffer;
+       unsigned int *used = NULL;
+       unsigned int possible;
+       int checksum;
+       int i;
+
+       blockspercyl = amiga_block[AMIGA_SECT] * amiga_block[AMIGA_HEADS];
+       possible = amiga_block[AMIGA_RDBLIMIT]/32 +1;
+
+       used = (unsigned int *) malloc (sizeof (unsigned int) * (possible + 1));
+       if (!used) {
+               prom_printf("Can't allocate memory\n");
+               return;
        }
-       
-       /* Read boot blocs */
-       if (prom_readblocks(disk, 0, 1, block_buffer) != 1) {
-               prom_printf("Can't read boot blocs\n");
-               goto bail;
-       }       
-       if (desc->signature == MAC_DRIVER_MAGIC) {
-               /* pdisk partition format */
-               partition_mac_lookup(device, disk, prom_blksize, &list);
-       } else if ((block_buffer[510] == 0x55) && (block_buffer[511] == 0xaa)) {
-               /* fdisk partition format */
-               partition_fdisk_lookup(device, disk, prom_blksize, &list);
-       } else if (prom_blksize == 2048 && identify_iso_fs(disk, &iso_root_block)) {
-               add_new_partition(      &list,
-                               0,
-                               iso_root_block,
-                               0,
-                               prom_blksize);
-               prom_printf("ISO9660 disk\n");
-       } else {
-               prom_printf("No supported partition table detected\n");
-               goto bail;
+
+       for (i=0; i < possible; i++) used[i] = 0;
+
+
+       for (part = amiga_block[AMIGA_PARTITIONS], partition = 0;
+               part != AMIGA_END;
+               part = amiga_block[AMIGA_PART_NEXT], partition++)
+       {
+               if (prom_readblocks(disk, part, 1, block_buffer) != 1) {
+                       prom_printf("Can't read partition block %d\n", part);
+                       break;
+               }
+               checksum = _amiga_checksum (prom_blksize);
+               if ((amiga_block[AMIGA_ID] == AMIGA_ID_PART) &&
+                       (checksum == 0) &&
+                       ((used[part/32] & (0x1 << (part % 32))) == 0))
+               {
+                       used[part/32] |= (0x1 << (part % 32));
+               } else {
+                       prom_printf("Amiga partition table corrupted at block %d\n", part);
+                       if (amiga_block[AMIGA_ID] != AMIGA_ID_PART)
+                               prom_printf ("block type is not partition but %08x\n", amiga_block[AMIGA_ID]);
+                       if (checksum != 0)
+                               prom_printf ("block checsum is bad : %d\n", checksum);
+                       if ((used[part/32] & (0x1 << (part % 32))) != 0)
+                               prom_printf ("partition table is looping, block %d already traveled\n", part);
+                       break;
+               }
+
+              /* We use the partition block size from the partition table.
+               * The filesystem implmentations are responsible for mapping
+               * to their own fs blocksize */
+              add_new_partition(
+                   list, /* partition list */
+                   partition, /* partition number */
+                   "Linux", /* type */
+                   '\0', /* name */
+                   blockspercyl * amiga_block[AMIGA_PART_LOWCYL], /* start */
+                   blockspercyl * (amiga_block[AMIGA_PART_HIGHCYL] - amiga_block[AMIGA_PART_LOWCYL] + 1), /* size */
+                   prom_blksize,
+                   0 );
        }
+       if (used)
+               free(used);
+}
+
+struct partition_t*
+partitions_lookup(const char *device)
+{
+     ihandle   disk;
+     struct mac_driver_desc *desc = (struct mac_driver_desc *)block_buffer;
+     struct partition_t* list = NULL;
+     unsigned int prom_blksize, iso_root_block;
+
+     strncpy(block_buffer, device, 2040);
+     strcat(block_buffer, ":0");
+
+     /* Open device */
+     disk = prom_open(block_buffer);
+     if (disk == NULL) {
+         prom_printf("Can't open device <%s>\n", block_buffer);
+         goto bail;
+     }
+     prom_blksize = prom_getblksize(disk);
+     DEBUG_F("block size of device is %d\n", prom_blksize);
+
+     if (prom_blksize <= 1)
+         prom_blksize = 512;
+     if (prom_blksize > MAX_BLOCK_SIZE) {
+         prom_printf("block_size %d not supported !\n", prom_blksize);
+         goto bail;
+     }
+
+     /* Read boot blocs */
+     if (prom_readblocks(disk, 0, 1, block_buffer) != 1) {
+         prom_printf("Can't read boot blocks\n");
+         goto bail;
+     }
+     if (desc->signature == MAC_DRIVER_MAGIC) {
+         /* pdisk partition format */
+         partition_mac_lookup(device, disk, prom_blksize, &list);
+     } else if ((block_buffer[510] == 0x55) && (block_buffer[511] == 0xaa)) {
+         /* fdisk partition format */
+         partition_fdisk_lookup(device, disk, prom_blksize, &list);
+     } else if (prom_blksize == 2048 && identify_iso_fs(disk, &iso_root_block)) {
+         add_new_partition(&list,
+                           0,
+                           '\0',
+                           '\0',
+                           iso_root_block,
+                           0,
+                           prom_blksize,
+                           0);
+         prom_printf("ISO9660 disk\n");
+     } else if (_amiga_find_rdb(device, disk, prom_blksize) != -1) {
+         /* amiga partition format */
+         partition_amiga_lookup(device, disk, prom_blksize, &list);
+     } else {
+         prom_printf("No supported partition table detected\n");
+         goto bail;
+     }
 
 bail:
-       prom_close(disk);
-       
-       return list;
+     prom_close(disk);
+
+     return list;
+}
+
+char *
+get_part_type(char *device, int partition)
+{
+     struct partition_t*       parts;
+     struct partition_t*       p;
+     struct partition_t*       found;
+     char *type = NULL;
+
+     if (prom_get_devtype(device) != FILE_DEVICE_BLOCK)
+         return NULL;
+
+     parts = partitions_lookup(device);
+     found = NULL;
+
+     if (!parts)
+         return '\0';
+
+     for (p = parts; p && !found; p=p->next) {
+         DEBUG_F("number: %02d, start: 0x%08lx, length: 0x%08lx, type: %s, name: %s\n",
+                 p->part_number, p->part_start, p->part_size, p->part_type, p->part_name);
+         if ((partition >= 0) && (partition == p->part_number)) {
+              type = strdup(p->part_type);
+              break;
+         }
+     }
+     if (parts)
+         partitions_free(parts);
+     return type;
 }
 
 /* Freed in reverse order of allocation to help malloc'ator */
 void
 partitions_free(struct partition_t* list)
 {
-       struct partition_t*     next;
-       
-       while(list) {
-               next = list->next;
-               free(list);
-               list = next;
-       }
-}
-unsigned long
-swab32(unsigned long value)
-{
-       __u32 result;
-
-       __asm__("rlwimi %0,%1,24,16,23\n\t"
-           "rlwimi %0,%1,8,8,15\n\t"
-           "rlwimi %0,%1,24,0,7"
-           : "=r" (result)
-           : "r" (value), "0" (value >> 24));
-       return result;
+     struct partition_t*       next;
+
+     while(list) {
+         next = list->next;
+         free(list);
+         list = next;
+     }
 }
 
 
+/*
+ * Local variables:
+ * c-file-style: "k&r"
+ * c-basic-offset: 5
+ * End:
+ */