git-archimport-id: pnasrat@redhat.com/yaboot--devel--1.3--patch-1
[yaboot.git] / second / partition.c
index ea84ee23f8817f26cc713596b94f64cdbb208eee..05823092614e1b9011fe4e2d88d26f69ebe32e40 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"
@@ -25,6 +33,7 @@
 #include "stdlib.h"
 #include "mac-part.h"
 #include "fdisk-part.h"
+#include "amiga-part.h"
 #include "partition.h"
 #include "prom.h"
 #include "string.h"
@@ -58,7 +67,7 @@ static unsigned char block_buffer[MAX_BLOCK_SIZE];
 static void
 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)
+                 unsigned short part_blocksize, int sys_ind)
 {
      struct partition_t*       part;
      part = (struct partition_t*)malloc(sizeof(struct partition_t));
@@ -69,6 +78,7 @@ add_new_partition(struct partition_t**        list, int part_number, const char *part_t
      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;
@@ -140,7 +150,8 @@ partition_mac_lookup( const char *dev_name, prom_handle disk,
                    part->name, /* name */
                    part->start_block + part->data_start, /* start */
                    part->data_count, /* size */
-                   ptable_block_size );
+                   ptable_block_size,
+                   0);
      }
 }
 
@@ -161,14 +172,15 @@ partition_fdisk_lookup( const char *dev_name, prom_handle disk,
          (struct fdisk_partition *) (block_buffer + 0x1be);
 
      for (partition=1; partition <= 4 ;partition++, part++) {
-         if (part->sys_ind == LINUX_NATIVE) {
+         if (part->sys_ind == LINUX_NATIVE || part->sys_ind == LINUX_RAID) {
               add_new_partition(  list,
                                   partition,
                                   "Linux", /* type */
                                   '\0', /* name */
                                   swab32(*(unsigned int *)(part->start4)),
                                   swab32(*(unsigned int *)(part->size4)),
-                                  512 /*blksize*/ );
+                                  512 /*blksize*/,
+                                  part->sys_ind /* partition type */ );
          }
      }
 }
@@ -207,6 +219,117 @@ identify_iso_fs(ihandle device, unsigned int *iso_root_block)
      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;
+}
+
+static void
+partition_amiga_lookup( const char *dev_name, prom_handle disk,
+                        unsigned int prom_blksize, struct partition_t** list )
+{
+       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;
+       }
+
+       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)
 {
@@ -252,8 +375,12 @@ partitions_lookup(const char *device)
                            '\0',
                            iso_root_block,
                            0,
-                           prom_blksize);
+                           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;
@@ -323,7 +450,7 @@ swab32(unsigned long value)
 
 /* 
  * Local variables:
- * c-file-style: "K&R"
+ * c-file-style: "k&r"
  * c-basic-offset: 5
  * End:
  */