| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 | /* *  linux/fs/partitions/acorn.c * *  Copyright (c) 1996-2000 Russell King. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * *  Scan ADFS partitions on hard disk drives.  Unfortunately, there *  isn't a standard for partitioning drives on Acorn machines, so *  every single manufacturer of SCSI and IDE cards created their own *  method. */#include <linux/buffer_head.h>#include <linux/adfs_fs.h>#include "check.h"#include "acorn.h"/* * Partition types. (Oh for reusability) */#define PARTITION_RISCIX_MFM	1#define PARTITION_RISCIX_SCSI	2#define PARTITION_LINUX		9#if defined(CONFIG_ACORN_PARTITION_CUMANA) || \	defined(CONFIG_ACORN_PARTITION_ADFS)static struct adfs_discrecord *adfs_partition(struct parsed_partitions *state, char *name, char *data,	       unsigned long first_sector, int slot){	struct adfs_discrecord *dr;	unsigned int nr_sects;	if (adfs_checkbblk(data))		return NULL;	dr = (struct adfs_discrecord *)(data + 0x1c0);	if (dr->disc_size == 0 && dr->disc_size_high == 0)		return NULL;	nr_sects = (le32_to_cpu(dr->disc_size_high) << 23) |		   (le32_to_cpu(dr->disc_size) >> 9);	if (name) {		strlcat(state->pp_buf, " [", PAGE_SIZE);		strlcat(state->pp_buf, name, PAGE_SIZE);		strlcat(state->pp_buf, "]", PAGE_SIZE);	}	put_partition(state, slot, first_sector, nr_sects);	return dr;}#endif#ifdef CONFIG_ACORN_PARTITION_RISCIXstruct riscix_part {	__le32	start;	__le32	length;	__le32	one;	char	name[16];};struct riscix_record {	__le32	magic;#define RISCIX_MAGIC	cpu_to_le32(0x4a657320)	__le32	date;	struct riscix_part part[8];};#if defined(CONFIG_ACORN_PARTITION_CUMANA) || \	defined(CONFIG_ACORN_PARTITION_ADFS)static int riscix_partition(struct parsed_partitions *state,			    unsigned long first_sect, int slot,			    unsigned long nr_sects){	Sector sect;	struct riscix_record *rr;		rr = read_part_sector(state, first_sect, §);	if (!rr)		return -1;	strlcat(state->pp_buf, " [RISCiX]", PAGE_SIZE);	if (rr->magic == RISCIX_MAGIC) {		unsigned long size = nr_sects > 2 ? 2 : nr_sects;		int part;		strlcat(state->pp_buf, " <", PAGE_SIZE);		put_partition(state, slot++, first_sect, size);		for (part = 0; part < 8; part++) {			if (rr->part[part].one &&			    memcmp(rr->part[part].name, "All\0", 4)) {				put_partition(state, slot++,					le32_to_cpu(rr->part[part].start),					le32_to_cpu(rr->part[part].length));				strlcat(state->pp_buf, "(", PAGE_SIZE);				strlcat(state->pp_buf, rr->part[part].name, PAGE_SIZE);				strlcat(state->pp_buf, ")", PAGE_SIZE);			}		}		strlcat(state->pp_buf, " >\n", PAGE_SIZE);	} else {		put_partition(state, slot++, first_sect, nr_sects);	}	put_dev_sector(sect);	return slot;}#endif#endif#define LINUX_NATIVE_MAGIC 0xdeafa1de#define LINUX_SWAP_MAGIC   0xdeafab1estruct linux_part {	__le32 magic;	__le32 start_sect;	__le32 nr_sects;};#if defined(CONFIG_ACORN_PARTITION_CUMANA) || \	defined(CONFIG_ACORN_PARTITION_ADFS)static int linux_partition(struct parsed_partitions *state,			   unsigned long first_sect, int slot,			   unsigned long nr_sects){	Sector sect;	struct linux_part *linuxp;	unsigned long size = nr_sects > 2 ? 2 : nr_sects;	strlcat(state->pp_buf, " [Linux]", PAGE_SIZE);	put_partition(state, slot++, first_sect, size);	linuxp = read_part_sector(state, first_sect, §);	if (!linuxp)		return -1;	strlcat(state->pp_buf, " <", PAGE_SIZE);	while (linuxp->magic == cpu_to_le32(LINUX_NATIVE_MAGIC) ||	       linuxp->magic == cpu_to_le32(LINUX_SWAP_MAGIC)) {		if (slot == state->limit)			break;		put_partition(state, slot++, first_sect +				 le32_to_cpu(linuxp->start_sect),				 le32_to_cpu(linuxp->nr_sects));		linuxp ++;	}	strlcat(state->pp_buf, " >", PAGE_SIZE);	put_dev_sector(sect);	return slot;}#endif#ifdef CONFIG_ACORN_PARTITION_CUMANAint adfspart_check_CUMANA(struct parsed_partitions *state){	unsigned long first_sector = 0;	unsigned int start_blk = 0;	Sector sect;	unsigned char *data;	char *name = "CUMANA/ADFS";	int first = 1;	int slot = 1;	/*	 * Try Cumana style partitions - sector 6 contains ADFS boot block	 * with pointer to next 'drive'.	 *	 * There are unknowns in this code - is the 'cylinder number' of the	 * next partition relative to the start of this one - I'm assuming	 * it is.	 *	 * Also, which ID did Cumana use?	 *	 * This is totally unfinished, and will require more work to get it	 * going. Hence it is totally untested.	 */	do {		struct adfs_discrecord *dr;		unsigned int nr_sects;		data = read_part_sector(state, start_blk * 2 + 6, §);		if (!data)			return -1;		if (slot == state->limit)			break;		dr = adfs_partition(state, name, data, first_sector, slot++);		if (!dr)
 |