18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 1996-2000 Russell King. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Scan ADFS partitions on hard disk drives. Unfortunately, there 68c2ecf20Sopenharmony_ci * isn't a standard for partitioning drives on Acorn machines, so 78c2ecf20Sopenharmony_ci * every single manufacturer of SCSI and IDE cards created their own 88c2ecf20Sopenharmony_ci * method. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci#include <linux/buffer_head.h> 118c2ecf20Sopenharmony_ci#include <linux/adfs_fs.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "check.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci/* 168c2ecf20Sopenharmony_ci * Partition types. (Oh for reusability) 178c2ecf20Sopenharmony_ci */ 188c2ecf20Sopenharmony_ci#define PARTITION_RISCIX_MFM 1 198c2ecf20Sopenharmony_ci#define PARTITION_RISCIX_SCSI 2 208c2ecf20Sopenharmony_ci#define PARTITION_LINUX 9 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#if defined(CONFIG_ACORN_PARTITION_CUMANA) || \ 238c2ecf20Sopenharmony_ci defined(CONFIG_ACORN_PARTITION_ADFS) 248c2ecf20Sopenharmony_cistatic struct adfs_discrecord * 258c2ecf20Sopenharmony_ciadfs_partition(struct parsed_partitions *state, char *name, char *data, 268c2ecf20Sopenharmony_ci unsigned long first_sector, int slot) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci struct adfs_discrecord *dr; 298c2ecf20Sopenharmony_ci unsigned int nr_sects; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci if (adfs_checkbblk(data)) 328c2ecf20Sopenharmony_ci return NULL; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci dr = (struct adfs_discrecord *)(data + 0x1c0); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci if (dr->disc_size == 0 && dr->disc_size_high == 0) 378c2ecf20Sopenharmony_ci return NULL; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci nr_sects = (le32_to_cpu(dr->disc_size_high) << 23) | 408c2ecf20Sopenharmony_ci (le32_to_cpu(dr->disc_size) >> 9); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci if (name) { 438c2ecf20Sopenharmony_ci strlcat(state->pp_buf, " [", PAGE_SIZE); 448c2ecf20Sopenharmony_ci strlcat(state->pp_buf, name, PAGE_SIZE); 458c2ecf20Sopenharmony_ci strlcat(state->pp_buf, "]", PAGE_SIZE); 468c2ecf20Sopenharmony_ci } 478c2ecf20Sopenharmony_ci put_partition(state, slot, first_sector, nr_sects); 488c2ecf20Sopenharmony_ci return dr; 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ci#endif 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#ifdef CONFIG_ACORN_PARTITION_RISCIX 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistruct riscix_part { 558c2ecf20Sopenharmony_ci __le32 start; 568c2ecf20Sopenharmony_ci __le32 length; 578c2ecf20Sopenharmony_ci __le32 one; 588c2ecf20Sopenharmony_ci char name[16]; 598c2ecf20Sopenharmony_ci}; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistruct riscix_record { 628c2ecf20Sopenharmony_ci __le32 magic; 638c2ecf20Sopenharmony_ci#define RISCIX_MAGIC cpu_to_le32(0x4a657320) 648c2ecf20Sopenharmony_ci __le32 date; 658c2ecf20Sopenharmony_ci struct riscix_part part[8]; 668c2ecf20Sopenharmony_ci}; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci#if defined(CONFIG_ACORN_PARTITION_CUMANA) || \ 698c2ecf20Sopenharmony_ci defined(CONFIG_ACORN_PARTITION_ADFS) 708c2ecf20Sopenharmony_cistatic int riscix_partition(struct parsed_partitions *state, 718c2ecf20Sopenharmony_ci unsigned long first_sect, int slot, 728c2ecf20Sopenharmony_ci unsigned long nr_sects) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci Sector sect; 758c2ecf20Sopenharmony_ci struct riscix_record *rr; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci rr = read_part_sector(state, first_sect, §); 788c2ecf20Sopenharmony_ci if (!rr) 798c2ecf20Sopenharmony_ci return -1; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci strlcat(state->pp_buf, " [RISCiX]", PAGE_SIZE); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci if (rr->magic == RISCIX_MAGIC) { 858c2ecf20Sopenharmony_ci unsigned long size = nr_sects > 2 ? 2 : nr_sects; 868c2ecf20Sopenharmony_ci int part; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci strlcat(state->pp_buf, " <", PAGE_SIZE); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci put_partition(state, slot++, first_sect, size); 918c2ecf20Sopenharmony_ci for (part = 0; part < 8; part++) { 928c2ecf20Sopenharmony_ci if (rr->part[part].one && 938c2ecf20Sopenharmony_ci memcmp(rr->part[part].name, "All\0", 4)) { 948c2ecf20Sopenharmony_ci put_partition(state, slot++, 958c2ecf20Sopenharmony_ci le32_to_cpu(rr->part[part].start), 968c2ecf20Sopenharmony_ci le32_to_cpu(rr->part[part].length)); 978c2ecf20Sopenharmony_ci strlcat(state->pp_buf, "(", PAGE_SIZE); 988c2ecf20Sopenharmony_ci strlcat(state->pp_buf, rr->part[part].name, PAGE_SIZE); 998c2ecf20Sopenharmony_ci strlcat(state->pp_buf, ")", PAGE_SIZE); 1008c2ecf20Sopenharmony_ci } 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci strlcat(state->pp_buf, " >\n", PAGE_SIZE); 1048c2ecf20Sopenharmony_ci } else { 1058c2ecf20Sopenharmony_ci put_partition(state, slot++, first_sect, nr_sects); 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci put_dev_sector(sect); 1098c2ecf20Sopenharmony_ci return slot; 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci#endif 1128c2ecf20Sopenharmony_ci#endif 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci#define LINUX_NATIVE_MAGIC 0xdeafa1de 1158c2ecf20Sopenharmony_ci#define LINUX_SWAP_MAGIC 0xdeafab1e 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistruct linux_part { 1188c2ecf20Sopenharmony_ci __le32 magic; 1198c2ecf20Sopenharmony_ci __le32 start_sect; 1208c2ecf20Sopenharmony_ci __le32 nr_sects; 1218c2ecf20Sopenharmony_ci}; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci#if defined(CONFIG_ACORN_PARTITION_CUMANA) || \ 1248c2ecf20Sopenharmony_ci defined(CONFIG_ACORN_PARTITION_ADFS) 1258c2ecf20Sopenharmony_cistatic int linux_partition(struct parsed_partitions *state, 1268c2ecf20Sopenharmony_ci unsigned long first_sect, int slot, 1278c2ecf20Sopenharmony_ci unsigned long nr_sects) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci Sector sect; 1308c2ecf20Sopenharmony_ci struct linux_part *linuxp; 1318c2ecf20Sopenharmony_ci unsigned long size = nr_sects > 2 ? 2 : nr_sects; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci strlcat(state->pp_buf, " [Linux]", PAGE_SIZE); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci put_partition(state, slot++, first_sect, size); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci linuxp = read_part_sector(state, first_sect, §); 1388c2ecf20Sopenharmony_ci if (!linuxp) 1398c2ecf20Sopenharmony_ci return -1; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci strlcat(state->pp_buf, " <", PAGE_SIZE); 1428c2ecf20Sopenharmony_ci while (linuxp->magic == cpu_to_le32(LINUX_NATIVE_MAGIC) || 1438c2ecf20Sopenharmony_ci linuxp->magic == cpu_to_le32(LINUX_SWAP_MAGIC)) { 1448c2ecf20Sopenharmony_ci if (slot == state->limit) 1458c2ecf20Sopenharmony_ci break; 1468c2ecf20Sopenharmony_ci put_partition(state, slot++, first_sect + 1478c2ecf20Sopenharmony_ci le32_to_cpu(linuxp->start_sect), 1488c2ecf20Sopenharmony_ci le32_to_cpu(linuxp->nr_sects)); 1498c2ecf20Sopenharmony_ci linuxp ++; 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci strlcat(state->pp_buf, " >", PAGE_SIZE); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci put_dev_sector(sect); 1548c2ecf20Sopenharmony_ci return slot; 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci#endif 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci#ifdef CONFIG_ACORN_PARTITION_CUMANA 1598c2ecf20Sopenharmony_ciint adfspart_check_CUMANA(struct parsed_partitions *state) 1608c2ecf20Sopenharmony_ci{ 1618c2ecf20Sopenharmony_ci unsigned long first_sector = 0; 1628c2ecf20Sopenharmony_ci unsigned int start_blk = 0; 1638c2ecf20Sopenharmony_ci Sector sect; 1648c2ecf20Sopenharmony_ci unsigned char *data; 1658c2ecf20Sopenharmony_ci char *name = "CUMANA/ADFS"; 1668c2ecf20Sopenharmony_ci int first = 1; 1678c2ecf20Sopenharmony_ci int slot = 1; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci /* 1708c2ecf20Sopenharmony_ci * Try Cumana style partitions - sector 6 contains ADFS boot block 1718c2ecf20Sopenharmony_ci * with pointer to next 'drive'. 1728c2ecf20Sopenharmony_ci * 1738c2ecf20Sopenharmony_ci * There are unknowns in this code - is the 'cylinder number' of the 1748c2ecf20Sopenharmony_ci * next partition relative to the start of this one - I'm assuming 1758c2ecf20Sopenharmony_ci * it is. 1768c2ecf20Sopenharmony_ci * 1778c2ecf20Sopenharmony_ci * Also, which ID did Cumana use? 1788c2ecf20Sopenharmony_ci * 1798c2ecf20Sopenharmony_ci * This is totally unfinished, and will require more work to get it 1808c2ecf20Sopenharmony_ci * going. Hence it is totally untested. 1818c2ecf20Sopenharmony_ci */ 1828c2ecf20Sopenharmony_ci do { 1838c2ecf20Sopenharmony_ci struct adfs_discrecord *dr; 1848c2ecf20Sopenharmony_ci unsigned int nr_sects; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci data = read_part_sector(state, start_blk * 2 + 6, §); 1878c2ecf20Sopenharmony_ci if (!data) 1888c2ecf20Sopenharmony_ci return -1; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci if (slot == state->limit) 1918c2ecf20Sopenharmony_ci break; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci dr = adfs_partition(state, name, data, first_sector, slot++); 1948c2ecf20Sopenharmony_ci if (!dr) 1958c2ecf20Sopenharmony_ci break; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci name = NULL; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci nr_sects = (data[0x1fd] + (data[0x1fe] << 8)) * 2008c2ecf20Sopenharmony_ci (dr->heads + (dr->lowsector & 0x40 ? 1 : 0)) * 2018c2ecf20Sopenharmony_ci dr->secspertrack; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci if (!nr_sects) 2048c2ecf20Sopenharmony_ci break; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci first = 0; 2078c2ecf20Sopenharmony_ci first_sector += nr_sects; 2088c2ecf20Sopenharmony_ci start_blk += nr_sects >> (BLOCK_SIZE_BITS - 9); 2098c2ecf20Sopenharmony_ci nr_sects = 0; /* hmm - should be partition size */ 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci switch (data[0x1fc] & 15) { 2128c2ecf20Sopenharmony_ci case 0: /* No partition / ADFS? */ 2138c2ecf20Sopenharmony_ci break; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci#ifdef CONFIG_ACORN_PARTITION_RISCIX 2168c2ecf20Sopenharmony_ci case PARTITION_RISCIX_SCSI: 2178c2ecf20Sopenharmony_ci /* RISCiX - we don't know how to find the next one. */ 2188c2ecf20Sopenharmony_ci slot = riscix_partition(state, first_sector, slot, 2198c2ecf20Sopenharmony_ci nr_sects); 2208c2ecf20Sopenharmony_ci break; 2218c2ecf20Sopenharmony_ci#endif 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci case PARTITION_LINUX: 2248c2ecf20Sopenharmony_ci slot = linux_partition(state, first_sector, slot, 2258c2ecf20Sopenharmony_ci nr_sects); 2268c2ecf20Sopenharmony_ci break; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci put_dev_sector(sect); 2298c2ecf20Sopenharmony_ci if (slot == -1) 2308c2ecf20Sopenharmony_ci return -1; 2318c2ecf20Sopenharmony_ci } while (1); 2328c2ecf20Sopenharmony_ci put_dev_sector(sect); 2338c2ecf20Sopenharmony_ci return first ? 0 : 1; 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci#endif 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci#ifdef CONFIG_ACORN_PARTITION_ADFS 2388c2ecf20Sopenharmony_ci/* 2398c2ecf20Sopenharmony_ci * Purpose: allocate ADFS partitions. 2408c2ecf20Sopenharmony_ci * 2418c2ecf20Sopenharmony_ci * Params : hd - pointer to gendisk structure to store partition info. 2428c2ecf20Sopenharmony_ci * dev - device number to access. 2438c2ecf20Sopenharmony_ci * 2448c2ecf20Sopenharmony_ci * Returns: -1 on error, 0 for no ADFS boot sector, 1 for ok. 2458c2ecf20Sopenharmony_ci * 2468c2ecf20Sopenharmony_ci * Alloc : hda = whole drive 2478c2ecf20Sopenharmony_ci * hda1 = ADFS partition on first drive. 2488c2ecf20Sopenharmony_ci * hda2 = non-ADFS partition. 2498c2ecf20Sopenharmony_ci */ 2508c2ecf20Sopenharmony_ciint adfspart_check_ADFS(struct parsed_partitions *state) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci unsigned long start_sect, nr_sects, sectscyl, heads; 2538c2ecf20Sopenharmony_ci Sector sect; 2548c2ecf20Sopenharmony_ci unsigned char *data; 2558c2ecf20Sopenharmony_ci struct adfs_discrecord *dr; 2568c2ecf20Sopenharmony_ci unsigned char id; 2578c2ecf20Sopenharmony_ci int slot = 1; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci data = read_part_sector(state, 6, §); 2608c2ecf20Sopenharmony_ci if (!data) 2618c2ecf20Sopenharmony_ci return -1; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci dr = adfs_partition(state, "ADFS", data, 0, slot++); 2648c2ecf20Sopenharmony_ci if (!dr) { 2658c2ecf20Sopenharmony_ci put_dev_sector(sect); 2668c2ecf20Sopenharmony_ci return 0; 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci heads = dr->heads + ((dr->lowsector >> 6) & 1); 2708c2ecf20Sopenharmony_ci sectscyl = dr->secspertrack * heads; 2718c2ecf20Sopenharmony_ci start_sect = ((data[0x1fe] << 8) + data[0x1fd]) * sectscyl; 2728c2ecf20Sopenharmony_ci id = data[0x1fc] & 15; 2738c2ecf20Sopenharmony_ci put_dev_sector(sect); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci /* 2768c2ecf20Sopenharmony_ci * Work out start of non-adfs partition. 2778c2ecf20Sopenharmony_ci */ 2788c2ecf20Sopenharmony_ci nr_sects = (state->bdev->bd_inode->i_size >> 9) - start_sect; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci if (start_sect) { 2818c2ecf20Sopenharmony_ci switch (id) { 2828c2ecf20Sopenharmony_ci#ifdef CONFIG_ACORN_PARTITION_RISCIX 2838c2ecf20Sopenharmony_ci case PARTITION_RISCIX_SCSI: 2848c2ecf20Sopenharmony_ci case PARTITION_RISCIX_MFM: 2858c2ecf20Sopenharmony_ci slot = riscix_partition(state, start_sect, slot, 2868c2ecf20Sopenharmony_ci nr_sects); 2878c2ecf20Sopenharmony_ci break; 2888c2ecf20Sopenharmony_ci#endif 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci case PARTITION_LINUX: 2918c2ecf20Sopenharmony_ci slot = linux_partition(state, start_sect, slot, 2928c2ecf20Sopenharmony_ci nr_sects); 2938c2ecf20Sopenharmony_ci break; 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci strlcat(state->pp_buf, "\n", PAGE_SIZE); 2978c2ecf20Sopenharmony_ci return 1; 2988c2ecf20Sopenharmony_ci} 2998c2ecf20Sopenharmony_ci#endif 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci#ifdef CONFIG_ACORN_PARTITION_ICS 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistruct ics_part { 3048c2ecf20Sopenharmony_ci __le32 start; 3058c2ecf20Sopenharmony_ci __le32 size; 3068c2ecf20Sopenharmony_ci}; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_cistatic int adfspart_check_ICSLinux(struct parsed_partitions *state, 3098c2ecf20Sopenharmony_ci unsigned long block) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci Sector sect; 3128c2ecf20Sopenharmony_ci unsigned char *data = read_part_sector(state, block, §); 3138c2ecf20Sopenharmony_ci int result = 0; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci if (data) { 3168c2ecf20Sopenharmony_ci if (memcmp(data, "LinuxPart", 9) == 0) 3178c2ecf20Sopenharmony_ci result = 1; 3188c2ecf20Sopenharmony_ci put_dev_sector(sect); 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci return result; 3228c2ecf20Sopenharmony_ci} 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci/* 3258c2ecf20Sopenharmony_ci * Check for a valid ICS partition using the checksum. 3268c2ecf20Sopenharmony_ci */ 3278c2ecf20Sopenharmony_cistatic inline int valid_ics_sector(const unsigned char *data) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci unsigned long sum; 3308c2ecf20Sopenharmony_ci int i; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci for (i = 0, sum = 0x50617274; i < 508; i++) 3338c2ecf20Sopenharmony_ci sum += data[i]; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci sum -= le32_to_cpu(*(__le32 *)(&data[508])); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci return sum == 0; 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci/* 3418c2ecf20Sopenharmony_ci * Purpose: allocate ICS partitions. 3428c2ecf20Sopenharmony_ci * Params : hd - pointer to gendisk structure to store partition info. 3438c2ecf20Sopenharmony_ci * dev - device number to access. 3448c2ecf20Sopenharmony_ci * Returns: -1 on error, 0 for no ICS table, 1 for partitions ok. 3458c2ecf20Sopenharmony_ci * Alloc : hda = whole drive 3468c2ecf20Sopenharmony_ci * hda1 = ADFS partition 0 on first drive. 3478c2ecf20Sopenharmony_ci * hda2 = ADFS partition 1 on first drive. 3488c2ecf20Sopenharmony_ci * ..etc.. 3498c2ecf20Sopenharmony_ci */ 3508c2ecf20Sopenharmony_ciint adfspart_check_ICS(struct parsed_partitions *state) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci const unsigned char *data; 3538c2ecf20Sopenharmony_ci const struct ics_part *p; 3548c2ecf20Sopenharmony_ci int slot; 3558c2ecf20Sopenharmony_ci Sector sect; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci /* 3588c2ecf20Sopenharmony_ci * Try ICS style partitions - sector 0 contains partition info. 3598c2ecf20Sopenharmony_ci */ 3608c2ecf20Sopenharmony_ci data = read_part_sector(state, 0, §); 3618c2ecf20Sopenharmony_ci if (!data) 3628c2ecf20Sopenharmony_ci return -1; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci if (!valid_ics_sector(data)) { 3658c2ecf20Sopenharmony_ci put_dev_sector(sect); 3668c2ecf20Sopenharmony_ci return 0; 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci strlcat(state->pp_buf, " [ICS]", PAGE_SIZE); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci for (slot = 1, p = (const struct ics_part *)data; p->size; p++) { 3728c2ecf20Sopenharmony_ci u32 start = le32_to_cpu(p->start); 3738c2ecf20Sopenharmony_ci s32 size = le32_to_cpu(p->size); /* yes, it's signed. */ 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci if (slot == state->limit) 3768c2ecf20Sopenharmony_ci break; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci /* 3798c2ecf20Sopenharmony_ci * Negative sizes tell the RISC OS ICS driver to ignore 3808c2ecf20Sopenharmony_ci * this partition - in effect it says that this does not 3818c2ecf20Sopenharmony_ci * contain an ADFS filesystem. 3828c2ecf20Sopenharmony_ci */ 3838c2ecf20Sopenharmony_ci if (size < 0) { 3848c2ecf20Sopenharmony_ci size = -size; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci /* 3878c2ecf20Sopenharmony_ci * Our own extension - We use the first sector 3888c2ecf20Sopenharmony_ci * of the partition to identify what type this 3898c2ecf20Sopenharmony_ci * partition is. We must not make this visible 3908c2ecf20Sopenharmony_ci * to the filesystem. 3918c2ecf20Sopenharmony_ci */ 3928c2ecf20Sopenharmony_ci if (size > 1 && adfspart_check_ICSLinux(state, start)) { 3938c2ecf20Sopenharmony_ci start += 1; 3948c2ecf20Sopenharmony_ci size -= 1; 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci if (size) 3998c2ecf20Sopenharmony_ci put_partition(state, slot++, start, size); 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci put_dev_sector(sect); 4038c2ecf20Sopenharmony_ci strlcat(state->pp_buf, "\n", PAGE_SIZE); 4048c2ecf20Sopenharmony_ci return 1; 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci#endif 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci#ifdef CONFIG_ACORN_PARTITION_POWERTEC 4098c2ecf20Sopenharmony_cistruct ptec_part { 4108c2ecf20Sopenharmony_ci __le32 unused1; 4118c2ecf20Sopenharmony_ci __le32 unused2; 4128c2ecf20Sopenharmony_ci __le32 start; 4138c2ecf20Sopenharmony_ci __le32 size; 4148c2ecf20Sopenharmony_ci __le32 unused5; 4158c2ecf20Sopenharmony_ci char type[8]; 4168c2ecf20Sopenharmony_ci}; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_cistatic inline int valid_ptec_sector(const unsigned char *data) 4198c2ecf20Sopenharmony_ci{ 4208c2ecf20Sopenharmony_ci unsigned char checksum = 0x2a; 4218c2ecf20Sopenharmony_ci int i; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci /* 4248c2ecf20Sopenharmony_ci * If it looks like a PC/BIOS partition, then it 4258c2ecf20Sopenharmony_ci * probably isn't PowerTec. 4268c2ecf20Sopenharmony_ci */ 4278c2ecf20Sopenharmony_ci if (data[510] == 0x55 && data[511] == 0xaa) 4288c2ecf20Sopenharmony_ci return 0; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci for (i = 0; i < 511; i++) 4318c2ecf20Sopenharmony_ci checksum += data[i]; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci return checksum == data[511]; 4348c2ecf20Sopenharmony_ci} 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci/* 4378c2ecf20Sopenharmony_ci * Purpose: allocate ICS partitions. 4388c2ecf20Sopenharmony_ci * Params : hd - pointer to gendisk structure to store partition info. 4398c2ecf20Sopenharmony_ci * dev - device number to access. 4408c2ecf20Sopenharmony_ci * Returns: -1 on error, 0 for no ICS table, 1 for partitions ok. 4418c2ecf20Sopenharmony_ci * Alloc : hda = whole drive 4428c2ecf20Sopenharmony_ci * hda1 = ADFS partition 0 on first drive. 4438c2ecf20Sopenharmony_ci * hda2 = ADFS partition 1 on first drive. 4448c2ecf20Sopenharmony_ci * ..etc.. 4458c2ecf20Sopenharmony_ci */ 4468c2ecf20Sopenharmony_ciint adfspart_check_POWERTEC(struct parsed_partitions *state) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci Sector sect; 4498c2ecf20Sopenharmony_ci const unsigned char *data; 4508c2ecf20Sopenharmony_ci const struct ptec_part *p; 4518c2ecf20Sopenharmony_ci int slot = 1; 4528c2ecf20Sopenharmony_ci int i; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci data = read_part_sector(state, 0, §); 4558c2ecf20Sopenharmony_ci if (!data) 4568c2ecf20Sopenharmony_ci return -1; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci if (!valid_ptec_sector(data)) { 4598c2ecf20Sopenharmony_ci put_dev_sector(sect); 4608c2ecf20Sopenharmony_ci return 0; 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci strlcat(state->pp_buf, " [POWERTEC]", PAGE_SIZE); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci for (i = 0, p = (const struct ptec_part *)data; i < 12; i++, p++) { 4668c2ecf20Sopenharmony_ci u32 start = le32_to_cpu(p->start); 4678c2ecf20Sopenharmony_ci u32 size = le32_to_cpu(p->size); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci if (size) 4708c2ecf20Sopenharmony_ci put_partition(state, slot++, start, size); 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci put_dev_sector(sect); 4748c2ecf20Sopenharmony_ci strlcat(state->pp_buf, "\n", PAGE_SIZE); 4758c2ecf20Sopenharmony_ci return 1; 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ci#endif 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci#ifdef CONFIG_ACORN_PARTITION_EESOX 4808c2ecf20Sopenharmony_cistruct eesox_part { 4818c2ecf20Sopenharmony_ci char magic[6]; 4828c2ecf20Sopenharmony_ci char name[10]; 4838c2ecf20Sopenharmony_ci __le32 start; 4848c2ecf20Sopenharmony_ci __le32 unused6; 4858c2ecf20Sopenharmony_ci __le32 unused7; 4868c2ecf20Sopenharmony_ci __le32 unused8; 4878c2ecf20Sopenharmony_ci}; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci/* 4908c2ecf20Sopenharmony_ci * Guess who created this format? 4918c2ecf20Sopenharmony_ci */ 4928c2ecf20Sopenharmony_cistatic const char eesox_name[] = { 4938c2ecf20Sopenharmony_ci 'N', 'e', 'i', 'l', ' ', 4948c2ecf20Sopenharmony_ci 'C', 'r', 'i', 't', 'c', 'h', 'e', 'l', 'l', ' ', ' ' 4958c2ecf20Sopenharmony_ci}; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci/* 4988c2ecf20Sopenharmony_ci * EESOX SCSI partition format. 4998c2ecf20Sopenharmony_ci * 5008c2ecf20Sopenharmony_ci * This is a goddamned awful partition format. We don't seem to store 5018c2ecf20Sopenharmony_ci * the size of the partition in this table, only the start addresses. 5028c2ecf20Sopenharmony_ci * 5038c2ecf20Sopenharmony_ci * There are two possibilities where the size comes from: 5048c2ecf20Sopenharmony_ci * 1. The individual ADFS boot block entries that are placed on the disk. 5058c2ecf20Sopenharmony_ci * 2. The start address of the next entry. 5068c2ecf20Sopenharmony_ci */ 5078c2ecf20Sopenharmony_ciint adfspart_check_EESOX(struct parsed_partitions *state) 5088c2ecf20Sopenharmony_ci{ 5098c2ecf20Sopenharmony_ci Sector sect; 5108c2ecf20Sopenharmony_ci const unsigned char *data; 5118c2ecf20Sopenharmony_ci unsigned char buffer[256]; 5128c2ecf20Sopenharmony_ci struct eesox_part *p; 5138c2ecf20Sopenharmony_ci sector_t start = 0; 5148c2ecf20Sopenharmony_ci int i, slot = 1; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci data = read_part_sector(state, 7, §); 5178c2ecf20Sopenharmony_ci if (!data) 5188c2ecf20Sopenharmony_ci return -1; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci /* 5218c2ecf20Sopenharmony_ci * "Decrypt" the partition table. God knows why... 5228c2ecf20Sopenharmony_ci */ 5238c2ecf20Sopenharmony_ci for (i = 0; i < 256; i++) 5248c2ecf20Sopenharmony_ci buffer[i] = data[i] ^ eesox_name[i & 15]; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci put_dev_sector(sect); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci for (i = 0, p = (struct eesox_part *)buffer; i < 8; i++, p++) { 5298c2ecf20Sopenharmony_ci sector_t next; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci if (memcmp(p->magic, "Eesox", 6)) 5328c2ecf20Sopenharmony_ci break; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci next = le32_to_cpu(p->start); 5358c2ecf20Sopenharmony_ci if (i) 5368c2ecf20Sopenharmony_ci put_partition(state, slot++, start, next - start); 5378c2ecf20Sopenharmony_ci start = next; 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci if (i != 0) { 5418c2ecf20Sopenharmony_ci sector_t size; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci size = get_capacity(state->bdev->bd_disk); 5448c2ecf20Sopenharmony_ci put_partition(state, slot++, start, size - start); 5458c2ecf20Sopenharmony_ci strlcat(state->pp_buf, "\n", PAGE_SIZE); 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci return i ? 1 : 0; 5498c2ecf20Sopenharmony_ci} 5508c2ecf20Sopenharmony_ci#endif 551