162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 1996-2000 Russell King. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Scan ADFS partitions on hard disk drives. Unfortunately, there 662306a36Sopenharmony_ci * isn't a standard for partitioning drives on Acorn machines, so 762306a36Sopenharmony_ci * every single manufacturer of SCSI and IDE cards created their own 862306a36Sopenharmony_ci * method. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci#include <linux/buffer_head.h> 1162306a36Sopenharmony_ci#include <linux/adfs_fs.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include "check.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci/* 1662306a36Sopenharmony_ci * Partition types. (Oh for reusability) 1762306a36Sopenharmony_ci */ 1862306a36Sopenharmony_ci#define PARTITION_RISCIX_MFM 1 1962306a36Sopenharmony_ci#define PARTITION_RISCIX_SCSI 2 2062306a36Sopenharmony_ci#define PARTITION_LINUX 9 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#if defined(CONFIG_ACORN_PARTITION_CUMANA) || \ 2362306a36Sopenharmony_ci defined(CONFIG_ACORN_PARTITION_ADFS) 2462306a36Sopenharmony_cistatic struct adfs_discrecord * 2562306a36Sopenharmony_ciadfs_partition(struct parsed_partitions *state, char *name, char *data, 2662306a36Sopenharmony_ci unsigned long first_sector, int slot) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci struct adfs_discrecord *dr; 2962306a36Sopenharmony_ci unsigned int nr_sects; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci if (adfs_checkbblk(data)) 3262306a36Sopenharmony_ci return NULL; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci dr = (struct adfs_discrecord *)(data + 0x1c0); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci if (dr->disc_size == 0 && dr->disc_size_high == 0) 3762306a36Sopenharmony_ci return NULL; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci nr_sects = (le32_to_cpu(dr->disc_size_high) << 23) | 4062306a36Sopenharmony_ci (le32_to_cpu(dr->disc_size) >> 9); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci if (name) { 4362306a36Sopenharmony_ci strlcat(state->pp_buf, " [", PAGE_SIZE); 4462306a36Sopenharmony_ci strlcat(state->pp_buf, name, PAGE_SIZE); 4562306a36Sopenharmony_ci strlcat(state->pp_buf, "]", PAGE_SIZE); 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci put_partition(state, slot, first_sector, nr_sects); 4862306a36Sopenharmony_ci return dr; 4962306a36Sopenharmony_ci} 5062306a36Sopenharmony_ci#endif 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#ifdef CONFIG_ACORN_PARTITION_RISCIX 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistruct riscix_part { 5562306a36Sopenharmony_ci __le32 start; 5662306a36Sopenharmony_ci __le32 length; 5762306a36Sopenharmony_ci __le32 one; 5862306a36Sopenharmony_ci char name[16]; 5962306a36Sopenharmony_ci}; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistruct riscix_record { 6262306a36Sopenharmony_ci __le32 magic; 6362306a36Sopenharmony_ci#define RISCIX_MAGIC cpu_to_le32(0x4a657320) 6462306a36Sopenharmony_ci __le32 date; 6562306a36Sopenharmony_ci struct riscix_part part[8]; 6662306a36Sopenharmony_ci}; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci#if defined(CONFIG_ACORN_PARTITION_CUMANA) || \ 6962306a36Sopenharmony_ci defined(CONFIG_ACORN_PARTITION_ADFS) 7062306a36Sopenharmony_cistatic int riscix_partition(struct parsed_partitions *state, 7162306a36Sopenharmony_ci unsigned long first_sect, int slot, 7262306a36Sopenharmony_ci unsigned long nr_sects) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci Sector sect; 7562306a36Sopenharmony_ci struct riscix_record *rr; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci rr = read_part_sector(state, first_sect, §); 7862306a36Sopenharmony_ci if (!rr) 7962306a36Sopenharmony_ci return -1; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci strlcat(state->pp_buf, " [RISCiX]", PAGE_SIZE); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci if (rr->magic == RISCIX_MAGIC) { 8562306a36Sopenharmony_ci unsigned long size = nr_sects > 2 ? 2 : nr_sects; 8662306a36Sopenharmony_ci int part; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci strlcat(state->pp_buf, " <", PAGE_SIZE); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci put_partition(state, slot++, first_sect, size); 9162306a36Sopenharmony_ci for (part = 0; part < 8; part++) { 9262306a36Sopenharmony_ci if (rr->part[part].one && 9362306a36Sopenharmony_ci memcmp(rr->part[part].name, "All\0", 4)) { 9462306a36Sopenharmony_ci put_partition(state, slot++, 9562306a36Sopenharmony_ci le32_to_cpu(rr->part[part].start), 9662306a36Sopenharmony_ci le32_to_cpu(rr->part[part].length)); 9762306a36Sopenharmony_ci strlcat(state->pp_buf, "(", PAGE_SIZE); 9862306a36Sopenharmony_ci strlcat(state->pp_buf, rr->part[part].name, PAGE_SIZE); 9962306a36Sopenharmony_ci strlcat(state->pp_buf, ")", PAGE_SIZE); 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci strlcat(state->pp_buf, " >\n", PAGE_SIZE); 10462306a36Sopenharmony_ci } else { 10562306a36Sopenharmony_ci put_partition(state, slot++, first_sect, nr_sects); 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci put_dev_sector(sect); 10962306a36Sopenharmony_ci return slot; 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci#endif 11262306a36Sopenharmony_ci#endif 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci#define LINUX_NATIVE_MAGIC 0xdeafa1de 11562306a36Sopenharmony_ci#define LINUX_SWAP_MAGIC 0xdeafab1e 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistruct linux_part { 11862306a36Sopenharmony_ci __le32 magic; 11962306a36Sopenharmony_ci __le32 start_sect; 12062306a36Sopenharmony_ci __le32 nr_sects; 12162306a36Sopenharmony_ci}; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci#if defined(CONFIG_ACORN_PARTITION_CUMANA) || \ 12462306a36Sopenharmony_ci defined(CONFIG_ACORN_PARTITION_ADFS) 12562306a36Sopenharmony_cistatic int linux_partition(struct parsed_partitions *state, 12662306a36Sopenharmony_ci unsigned long first_sect, int slot, 12762306a36Sopenharmony_ci unsigned long nr_sects) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci Sector sect; 13062306a36Sopenharmony_ci struct linux_part *linuxp; 13162306a36Sopenharmony_ci unsigned long size = nr_sects > 2 ? 2 : nr_sects; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci strlcat(state->pp_buf, " [Linux]", PAGE_SIZE); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci put_partition(state, slot++, first_sect, size); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci linuxp = read_part_sector(state, first_sect, §); 13862306a36Sopenharmony_ci if (!linuxp) 13962306a36Sopenharmony_ci return -1; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci strlcat(state->pp_buf, " <", PAGE_SIZE); 14262306a36Sopenharmony_ci while (linuxp->magic == cpu_to_le32(LINUX_NATIVE_MAGIC) || 14362306a36Sopenharmony_ci linuxp->magic == cpu_to_le32(LINUX_SWAP_MAGIC)) { 14462306a36Sopenharmony_ci if (slot == state->limit) 14562306a36Sopenharmony_ci break; 14662306a36Sopenharmony_ci put_partition(state, slot++, first_sect + 14762306a36Sopenharmony_ci le32_to_cpu(linuxp->start_sect), 14862306a36Sopenharmony_ci le32_to_cpu(linuxp->nr_sects)); 14962306a36Sopenharmony_ci linuxp ++; 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci strlcat(state->pp_buf, " >", PAGE_SIZE); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci put_dev_sector(sect); 15462306a36Sopenharmony_ci return slot; 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci#endif 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci#ifdef CONFIG_ACORN_PARTITION_CUMANA 15962306a36Sopenharmony_ciint adfspart_check_CUMANA(struct parsed_partitions *state) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci unsigned long first_sector = 0; 16262306a36Sopenharmony_ci unsigned int start_blk = 0; 16362306a36Sopenharmony_ci Sector sect; 16462306a36Sopenharmony_ci unsigned char *data; 16562306a36Sopenharmony_ci char *name = "CUMANA/ADFS"; 16662306a36Sopenharmony_ci int first = 1; 16762306a36Sopenharmony_ci int slot = 1; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci /* 17062306a36Sopenharmony_ci * Try Cumana style partitions - sector 6 contains ADFS boot block 17162306a36Sopenharmony_ci * with pointer to next 'drive'. 17262306a36Sopenharmony_ci * 17362306a36Sopenharmony_ci * There are unknowns in this code - is the 'cylinder number' of the 17462306a36Sopenharmony_ci * next partition relative to the start of this one - I'm assuming 17562306a36Sopenharmony_ci * it is. 17662306a36Sopenharmony_ci * 17762306a36Sopenharmony_ci * Also, which ID did Cumana use? 17862306a36Sopenharmony_ci * 17962306a36Sopenharmony_ci * This is totally unfinished, and will require more work to get it 18062306a36Sopenharmony_ci * going. Hence it is totally untested. 18162306a36Sopenharmony_ci */ 18262306a36Sopenharmony_ci do { 18362306a36Sopenharmony_ci struct adfs_discrecord *dr; 18462306a36Sopenharmony_ci unsigned int nr_sects; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci data = read_part_sector(state, start_blk * 2 + 6, §); 18762306a36Sopenharmony_ci if (!data) 18862306a36Sopenharmony_ci return -1; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci if (slot == state->limit) 19162306a36Sopenharmony_ci break; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci dr = adfs_partition(state, name, data, first_sector, slot++); 19462306a36Sopenharmony_ci if (!dr) 19562306a36Sopenharmony_ci break; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci name = NULL; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci nr_sects = (data[0x1fd] + (data[0x1fe] << 8)) * 20062306a36Sopenharmony_ci (dr->heads + (dr->lowsector & 0x40 ? 1 : 0)) * 20162306a36Sopenharmony_ci dr->secspertrack; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci if (!nr_sects) 20462306a36Sopenharmony_ci break; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci first = 0; 20762306a36Sopenharmony_ci first_sector += nr_sects; 20862306a36Sopenharmony_ci start_blk += nr_sects >> (BLOCK_SIZE_BITS - 9); 20962306a36Sopenharmony_ci nr_sects = 0; /* hmm - should be partition size */ 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci switch (data[0x1fc] & 15) { 21262306a36Sopenharmony_ci case 0: /* No partition / ADFS? */ 21362306a36Sopenharmony_ci break; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci#ifdef CONFIG_ACORN_PARTITION_RISCIX 21662306a36Sopenharmony_ci case PARTITION_RISCIX_SCSI: 21762306a36Sopenharmony_ci /* RISCiX - we don't know how to find the next one. */ 21862306a36Sopenharmony_ci slot = riscix_partition(state, first_sector, slot, 21962306a36Sopenharmony_ci nr_sects); 22062306a36Sopenharmony_ci break; 22162306a36Sopenharmony_ci#endif 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci case PARTITION_LINUX: 22462306a36Sopenharmony_ci slot = linux_partition(state, first_sector, slot, 22562306a36Sopenharmony_ci nr_sects); 22662306a36Sopenharmony_ci break; 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci put_dev_sector(sect); 22962306a36Sopenharmony_ci if (slot == -1) 23062306a36Sopenharmony_ci return -1; 23162306a36Sopenharmony_ci } while (1); 23262306a36Sopenharmony_ci put_dev_sector(sect); 23362306a36Sopenharmony_ci return first ? 0 : 1; 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci#endif 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci#ifdef CONFIG_ACORN_PARTITION_ADFS 23862306a36Sopenharmony_ci/* 23962306a36Sopenharmony_ci * Purpose: allocate ADFS partitions. 24062306a36Sopenharmony_ci * 24162306a36Sopenharmony_ci * Params : hd - pointer to gendisk structure to store partition info. 24262306a36Sopenharmony_ci * dev - device number to access. 24362306a36Sopenharmony_ci * 24462306a36Sopenharmony_ci * Returns: -1 on error, 0 for no ADFS boot sector, 1 for ok. 24562306a36Sopenharmony_ci * 24662306a36Sopenharmony_ci * Alloc : hda = whole drive 24762306a36Sopenharmony_ci * hda1 = ADFS partition on first drive. 24862306a36Sopenharmony_ci * hda2 = non-ADFS partition. 24962306a36Sopenharmony_ci */ 25062306a36Sopenharmony_ciint adfspart_check_ADFS(struct parsed_partitions *state) 25162306a36Sopenharmony_ci{ 25262306a36Sopenharmony_ci unsigned long start_sect, nr_sects, sectscyl, heads; 25362306a36Sopenharmony_ci Sector sect; 25462306a36Sopenharmony_ci unsigned char *data; 25562306a36Sopenharmony_ci struct adfs_discrecord *dr; 25662306a36Sopenharmony_ci unsigned char id; 25762306a36Sopenharmony_ci int slot = 1; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci data = read_part_sector(state, 6, §); 26062306a36Sopenharmony_ci if (!data) 26162306a36Sopenharmony_ci return -1; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci dr = adfs_partition(state, "ADFS", data, 0, slot++); 26462306a36Sopenharmony_ci if (!dr) { 26562306a36Sopenharmony_ci put_dev_sector(sect); 26662306a36Sopenharmony_ci return 0; 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci heads = dr->heads + ((dr->lowsector >> 6) & 1); 27062306a36Sopenharmony_ci sectscyl = dr->secspertrack * heads; 27162306a36Sopenharmony_ci start_sect = ((data[0x1fe] << 8) + data[0x1fd]) * sectscyl; 27262306a36Sopenharmony_ci id = data[0x1fc] & 15; 27362306a36Sopenharmony_ci put_dev_sector(sect); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci /* 27662306a36Sopenharmony_ci * Work out start of non-adfs partition. 27762306a36Sopenharmony_ci */ 27862306a36Sopenharmony_ci nr_sects = get_capacity(state->disk) - start_sect; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci if (start_sect) { 28162306a36Sopenharmony_ci switch (id) { 28262306a36Sopenharmony_ci#ifdef CONFIG_ACORN_PARTITION_RISCIX 28362306a36Sopenharmony_ci case PARTITION_RISCIX_SCSI: 28462306a36Sopenharmony_ci case PARTITION_RISCIX_MFM: 28562306a36Sopenharmony_ci riscix_partition(state, start_sect, slot, 28662306a36Sopenharmony_ci nr_sects); 28762306a36Sopenharmony_ci break; 28862306a36Sopenharmony_ci#endif 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci case PARTITION_LINUX: 29162306a36Sopenharmony_ci linux_partition(state, start_sect, slot, 29262306a36Sopenharmony_ci nr_sects); 29362306a36Sopenharmony_ci break; 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci strlcat(state->pp_buf, "\n", PAGE_SIZE); 29762306a36Sopenharmony_ci return 1; 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci#endif 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci#ifdef CONFIG_ACORN_PARTITION_ICS 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_cistruct ics_part { 30462306a36Sopenharmony_ci __le32 start; 30562306a36Sopenharmony_ci __le32 size; 30662306a36Sopenharmony_ci}; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_cistatic int adfspart_check_ICSLinux(struct parsed_partitions *state, 30962306a36Sopenharmony_ci unsigned long block) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci Sector sect; 31262306a36Sopenharmony_ci unsigned char *data = read_part_sector(state, block, §); 31362306a36Sopenharmony_ci int result = 0; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci if (data) { 31662306a36Sopenharmony_ci if (memcmp(data, "LinuxPart", 9) == 0) 31762306a36Sopenharmony_ci result = 1; 31862306a36Sopenharmony_ci put_dev_sector(sect); 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci return result; 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci/* 32562306a36Sopenharmony_ci * Check for a valid ICS partition using the checksum. 32662306a36Sopenharmony_ci */ 32762306a36Sopenharmony_cistatic inline int valid_ics_sector(const unsigned char *data) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci unsigned long sum; 33062306a36Sopenharmony_ci int i; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci for (i = 0, sum = 0x50617274; i < 508; i++) 33362306a36Sopenharmony_ci sum += data[i]; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci sum -= le32_to_cpu(*(__le32 *)(&data[508])); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci return sum == 0; 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci/* 34162306a36Sopenharmony_ci * Purpose: allocate ICS partitions. 34262306a36Sopenharmony_ci * Params : hd - pointer to gendisk structure to store partition info. 34362306a36Sopenharmony_ci * dev - device number to access. 34462306a36Sopenharmony_ci * Returns: -1 on error, 0 for no ICS table, 1 for partitions ok. 34562306a36Sopenharmony_ci * Alloc : hda = whole drive 34662306a36Sopenharmony_ci * hda1 = ADFS partition 0 on first drive. 34762306a36Sopenharmony_ci * hda2 = ADFS partition 1 on first drive. 34862306a36Sopenharmony_ci * ..etc.. 34962306a36Sopenharmony_ci */ 35062306a36Sopenharmony_ciint adfspart_check_ICS(struct parsed_partitions *state) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci const unsigned char *data; 35362306a36Sopenharmony_ci const struct ics_part *p; 35462306a36Sopenharmony_ci int slot; 35562306a36Sopenharmony_ci Sector sect; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci /* 35862306a36Sopenharmony_ci * Try ICS style partitions - sector 0 contains partition info. 35962306a36Sopenharmony_ci */ 36062306a36Sopenharmony_ci data = read_part_sector(state, 0, §); 36162306a36Sopenharmony_ci if (!data) 36262306a36Sopenharmony_ci return -1; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci if (!valid_ics_sector(data)) { 36562306a36Sopenharmony_ci put_dev_sector(sect); 36662306a36Sopenharmony_ci return 0; 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci strlcat(state->pp_buf, " [ICS]", PAGE_SIZE); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci for (slot = 1, p = (const struct ics_part *)data; p->size; p++) { 37262306a36Sopenharmony_ci u32 start = le32_to_cpu(p->start); 37362306a36Sopenharmony_ci s32 size = le32_to_cpu(p->size); /* yes, it's signed. */ 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci if (slot == state->limit) 37662306a36Sopenharmony_ci break; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci /* 37962306a36Sopenharmony_ci * Negative sizes tell the RISC OS ICS driver to ignore 38062306a36Sopenharmony_ci * this partition - in effect it says that this does not 38162306a36Sopenharmony_ci * contain an ADFS filesystem. 38262306a36Sopenharmony_ci */ 38362306a36Sopenharmony_ci if (size < 0) { 38462306a36Sopenharmony_ci size = -size; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci /* 38762306a36Sopenharmony_ci * Our own extension - We use the first sector 38862306a36Sopenharmony_ci * of the partition to identify what type this 38962306a36Sopenharmony_ci * partition is. We must not make this visible 39062306a36Sopenharmony_ci * to the filesystem. 39162306a36Sopenharmony_ci */ 39262306a36Sopenharmony_ci if (size > 1 && adfspart_check_ICSLinux(state, start)) { 39362306a36Sopenharmony_ci start += 1; 39462306a36Sopenharmony_ci size -= 1; 39562306a36Sopenharmony_ci } 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci if (size) 39962306a36Sopenharmony_ci put_partition(state, slot++, start, size); 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci put_dev_sector(sect); 40362306a36Sopenharmony_ci strlcat(state->pp_buf, "\n", PAGE_SIZE); 40462306a36Sopenharmony_ci return 1; 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci#endif 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci#ifdef CONFIG_ACORN_PARTITION_POWERTEC 40962306a36Sopenharmony_cistruct ptec_part { 41062306a36Sopenharmony_ci __le32 unused1; 41162306a36Sopenharmony_ci __le32 unused2; 41262306a36Sopenharmony_ci __le32 start; 41362306a36Sopenharmony_ci __le32 size; 41462306a36Sopenharmony_ci __le32 unused5; 41562306a36Sopenharmony_ci char type[8]; 41662306a36Sopenharmony_ci}; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_cistatic inline int valid_ptec_sector(const unsigned char *data) 41962306a36Sopenharmony_ci{ 42062306a36Sopenharmony_ci unsigned char checksum = 0x2a; 42162306a36Sopenharmony_ci int i; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci /* 42462306a36Sopenharmony_ci * If it looks like a PC/BIOS partition, then it 42562306a36Sopenharmony_ci * probably isn't PowerTec. 42662306a36Sopenharmony_ci */ 42762306a36Sopenharmony_ci if (data[510] == 0x55 && data[511] == 0xaa) 42862306a36Sopenharmony_ci return 0; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci for (i = 0; i < 511; i++) 43162306a36Sopenharmony_ci checksum += data[i]; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci return checksum == data[511]; 43462306a36Sopenharmony_ci} 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci/* 43762306a36Sopenharmony_ci * Purpose: allocate ICS partitions. 43862306a36Sopenharmony_ci * Params : hd - pointer to gendisk structure to store partition info. 43962306a36Sopenharmony_ci * dev - device number to access. 44062306a36Sopenharmony_ci * Returns: -1 on error, 0 for no ICS table, 1 for partitions ok. 44162306a36Sopenharmony_ci * Alloc : hda = whole drive 44262306a36Sopenharmony_ci * hda1 = ADFS partition 0 on first drive. 44362306a36Sopenharmony_ci * hda2 = ADFS partition 1 on first drive. 44462306a36Sopenharmony_ci * ..etc.. 44562306a36Sopenharmony_ci */ 44662306a36Sopenharmony_ciint adfspart_check_POWERTEC(struct parsed_partitions *state) 44762306a36Sopenharmony_ci{ 44862306a36Sopenharmony_ci Sector sect; 44962306a36Sopenharmony_ci const unsigned char *data; 45062306a36Sopenharmony_ci const struct ptec_part *p; 45162306a36Sopenharmony_ci int slot = 1; 45262306a36Sopenharmony_ci int i; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci data = read_part_sector(state, 0, §); 45562306a36Sopenharmony_ci if (!data) 45662306a36Sopenharmony_ci return -1; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci if (!valid_ptec_sector(data)) { 45962306a36Sopenharmony_ci put_dev_sector(sect); 46062306a36Sopenharmony_ci return 0; 46162306a36Sopenharmony_ci } 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci strlcat(state->pp_buf, " [POWERTEC]", PAGE_SIZE); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci for (i = 0, p = (const struct ptec_part *)data; i < 12; i++, p++) { 46662306a36Sopenharmony_ci u32 start = le32_to_cpu(p->start); 46762306a36Sopenharmony_ci u32 size = le32_to_cpu(p->size); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci if (size) 47062306a36Sopenharmony_ci put_partition(state, slot++, start, size); 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci put_dev_sector(sect); 47462306a36Sopenharmony_ci strlcat(state->pp_buf, "\n", PAGE_SIZE); 47562306a36Sopenharmony_ci return 1; 47662306a36Sopenharmony_ci} 47762306a36Sopenharmony_ci#endif 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci#ifdef CONFIG_ACORN_PARTITION_EESOX 48062306a36Sopenharmony_cistruct eesox_part { 48162306a36Sopenharmony_ci char magic[6]; 48262306a36Sopenharmony_ci char name[10]; 48362306a36Sopenharmony_ci __le32 start; 48462306a36Sopenharmony_ci __le32 unused6; 48562306a36Sopenharmony_ci __le32 unused7; 48662306a36Sopenharmony_ci __le32 unused8; 48762306a36Sopenharmony_ci}; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci/* 49062306a36Sopenharmony_ci * Guess who created this format? 49162306a36Sopenharmony_ci */ 49262306a36Sopenharmony_cistatic const char eesox_name[] = { 49362306a36Sopenharmony_ci 'N', 'e', 'i', 'l', ' ', 49462306a36Sopenharmony_ci 'C', 'r', 'i', 't', 'c', 'h', 'e', 'l', 'l', ' ', ' ' 49562306a36Sopenharmony_ci}; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci/* 49862306a36Sopenharmony_ci * EESOX SCSI partition format. 49962306a36Sopenharmony_ci * 50062306a36Sopenharmony_ci * This is a goddamned awful partition format. We don't seem to store 50162306a36Sopenharmony_ci * the size of the partition in this table, only the start addresses. 50262306a36Sopenharmony_ci * 50362306a36Sopenharmony_ci * There are two possibilities where the size comes from: 50462306a36Sopenharmony_ci * 1. The individual ADFS boot block entries that are placed on the disk. 50562306a36Sopenharmony_ci * 2. The start address of the next entry. 50662306a36Sopenharmony_ci */ 50762306a36Sopenharmony_ciint adfspart_check_EESOX(struct parsed_partitions *state) 50862306a36Sopenharmony_ci{ 50962306a36Sopenharmony_ci Sector sect; 51062306a36Sopenharmony_ci const unsigned char *data; 51162306a36Sopenharmony_ci unsigned char buffer[256]; 51262306a36Sopenharmony_ci struct eesox_part *p; 51362306a36Sopenharmony_ci sector_t start = 0; 51462306a36Sopenharmony_ci int i, slot = 1; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci data = read_part_sector(state, 7, §); 51762306a36Sopenharmony_ci if (!data) 51862306a36Sopenharmony_ci return -1; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci /* 52162306a36Sopenharmony_ci * "Decrypt" the partition table. God knows why... 52262306a36Sopenharmony_ci */ 52362306a36Sopenharmony_ci for (i = 0; i < 256; i++) 52462306a36Sopenharmony_ci buffer[i] = data[i] ^ eesox_name[i & 15]; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci put_dev_sector(sect); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci for (i = 0, p = (struct eesox_part *)buffer; i < 8; i++, p++) { 52962306a36Sopenharmony_ci sector_t next; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci if (memcmp(p->magic, "Eesox", 6)) 53262306a36Sopenharmony_ci break; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci next = le32_to_cpu(p->start); 53562306a36Sopenharmony_ci if (i) 53662306a36Sopenharmony_ci put_partition(state, slot++, start, next - start); 53762306a36Sopenharmony_ci start = next; 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci if (i != 0) { 54162306a36Sopenharmony_ci sector_t size; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci size = get_capacity(state->disk); 54462306a36Sopenharmony_ci put_partition(state, slot++, start, size - start); 54562306a36Sopenharmony_ci strlcat(state->pp_buf, "\n", PAGE_SIZE); 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci return i ? 1 : 0; 54962306a36Sopenharmony_ci} 55062306a36Sopenharmony_ci#endif 551