linux/block/partitions/acorn.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 *  Copyright (c) 1996-2000 Russell King.
   4 *
   5 *  Scan ADFS partitions on hard disk drives.  Unfortunately, there
   6 *  isn't a standard for partitioning drives on Acorn machines, so
   7 *  every single manufacturer of SCSI and IDE cards created their own
   8 *  method.
   9 */
  10#include <linux/buffer_head.h>
  11#include <linux/adfs_fs.h>
  12
  13#include "check.h"
  14#include "acorn.h"
  15
  16/*
  17 * Partition types. (Oh for reusability)
  18 */
  19#define PARTITION_RISCIX_MFM    1
  20#define PARTITION_RISCIX_SCSI   2
  21#define PARTITION_LINUX         9
  22
  23#if defined(CONFIG_ACORN_PARTITION_CUMANA) || \
  24        defined(CONFIG_ACORN_PARTITION_ADFS)
  25static struct adfs_discrecord *
  26adfs_partition(struct parsed_partitions *state, char *name, char *data,
  27               unsigned long first_sector, int slot)
  28{
  29        struct adfs_discrecord *dr;
  30        unsigned int nr_sects;
  31
  32        if (adfs_checkbblk(data))
  33                return NULL;
  34
  35        dr = (struct adfs_discrecord *)(data + 0x1c0);
  36
  37        if (dr->disc_size == 0 && dr->disc_size_high == 0)
  38                return NULL;
  39
  40        nr_sects = (le32_to_cpu(dr->disc_size_high) << 23) |
  41                   (le32_to_cpu(dr->disc_size) >> 9);
  42
  43        if (name) {
  44                strlcat(state->pp_buf, " [", PAGE_SIZE);
  45                strlcat(state->pp_buf, name, PAGE_SIZE);
  46                strlcat(state->pp_buf, "]", PAGE_SIZE);
  47        }
  48        put_partition(state, slot, first_sector, nr_sects);
  49        return dr;
  50}
  51#endif
  52
  53#ifdef CONFIG_ACORN_PARTITION_RISCIX
  54
  55struct riscix_part {
  56        __le32  start;
  57        __le32  length;
  58        __le32  one;
  59        char    name[16];
  60};
  61
  62struct riscix_record {
  63        __le32  magic;
  64#define RISCIX_MAGIC    cpu_to_le32(0x4a657320)
  65        __le32  date;
  66        struct riscix_part part[8];
  67};
  68
  69#if defined(CONFIG_ACORN_PARTITION_CUMANA) || \
  70        defined(CONFIG_ACORN_PARTITION_ADFS)
  71static int riscix_partition(struct parsed_partitions *state,
  72                            unsigned long first_sect, int slot,
  73                            unsigned long nr_sects)
  74{
  75        Sector sect;
  76        struct riscix_record *rr;
  77        
  78        rr = read_part_sector(state, first_sect, &sect);
  79        if (!rr)
  80                return -1;
  81
  82        strlcat(state->pp_buf, " [RISCiX]", PAGE_SIZE);
  83
  84
  85        if (rr->magic == RISCIX_MAGIC) {
  86                unsigned long size = nr_sects > 2 ? 2 : nr_sects;
  87                int part;
  88
  89                strlcat(state->pp_buf, " <", PAGE_SIZE);
  90
  91                put_partition(state, slot++, first_sect, size);
  92                for (part = 0; part < 8; part++) {
  93                        if (rr->part[part].one &&
  94                            memcmp(rr->part[part].name, "All\0", 4)) {
  95                                put_partition(state, slot++,
  96                                        le32_to_cpu(rr->part[part].start),
  97                                        le32_to_cpu(rr->part[part].length));
  98                                strlcat(state->pp_buf, "(", PAGE_SIZE);
  99                                strlcat(state->pp_buf, rr->part[part].name, PAGE_SIZE);
 100                                strlcat(state->pp_buf, ")", PAGE_SIZE);
 101                        }
 102                }
 103
 104                strlcat(state->pp_buf, " >\n", PAGE_SIZE);
 105        } else {
 106                put_partition(state, slot++, first_sect, nr_sects);
 107        }
 108
 109        put_dev_sector(sect);
 110        return slot;
 111}
 112#endif
 113#endif
 114
 115#define LINUX_NATIVE_MAGIC 0xdeafa1de
 116#define LINUX_SWAP_MAGIC   0xdeafab1e
 117
 118struct linux_part {
 119        __le32 magic;
 120        __le32 start_sect;
 121        __le32 nr_sects;
 122};
 123
 124#if defined(CONFIG_ACORN_PARTITION_CUMANA) || \
 125        defined(CONFIG_ACORN_PARTITION_ADFS)
 126static int linux_partition(struct parsed_partitions *state,
 127                           unsigned long first_sect, int slot,
 128                           unsigned long nr_sects)
 129{
 130        Sector sect;
 131        struct linux_part *linuxp;
 132        unsigned long size = nr_sects > 2 ? 2 : nr_sects;
 133
 134        strlcat(state->pp_buf, " [Linux]", PAGE_SIZE);
 135
 136        put_partition(state, slot++, first_sect, size);
 137
 138        linuxp = read_part_sector(state, first_sect, &sect);
 139        if (!linuxp)
 140                return -1;
 141
 142        strlcat(state->pp_buf, " <", PAGE_SIZE);
 143        while (linuxp->magic == cpu_to_le32(LINUX_NATIVE_MAGIC) ||
 144               linuxp->magic == cpu_to_le32(LINUX_SWAP_MAGIC)) {
 145                if (slot == state->limit)
 146                        break;
 147                put_partition(state, slot++, first_sect +
 148                                 le32_to_cpu(linuxp->start_sect),
 149                                 le32_to_cpu(linuxp->nr_sects));
 150                linuxp ++;
 151        }
 152        strlcat(state->pp_buf, " >", PAGE_SIZE);
 153
 154        put_dev_sector(sect);
 155        return slot;
 156}
 157#endif
 158
 159#ifdef CONFIG_ACORN_PARTITION_CUMANA
 160int adfspart_check_CUMANA(struct parsed_partitions *state)
 161{
 162        unsigned long first_sector = 0;
 163        unsigned int start_blk = 0;
 164        Sector sect;
 165        unsigned char *data;
 166        char *name = "CUMANA/ADFS";
 167        int first = 1;
 168        int slot = 1;
 169
 170        /*
 171         * Try Cumana style partitions - sector 6 contains ADFS boot block
 172         * with pointer to next 'drive'.
 173         *
 174         * There are unknowns in this code - is the 'cylinder number' of the
 175         * next partition relative to the start of this one - I'm assuming
 176         * it is.
 177         *
 178         * Also, which ID did Cumana use?
 179         *
 180         * This is totally unfinished, and will require more work to get it
 181         * going. Hence it is totally untested.
 182         */
 183        do {
 184                struct adfs_discrecord *dr;
 185                unsigned int nr_sects;
 186
 187                data = read_part_sector(state, start_blk * 2 + 6, &sect);
 188                if (!data)
 189                        return -1;
 190
 191                if (slot == state->limit)
 192                        break;
 193
 194                dr = adfs_partition(state, name, data, first_sector, slot++);
 195                if (!dr)
 196                        break;
 197
 198                name = NULL;
 199
 200                nr_sects = (data[0x1fd] + (data[0x1fe] << 8)) *
 201                           (dr->heads + (dr->lowsector & 0x40 ? 1 : 0)) *
 202                           dr->secspertrack;
 203
 204                if (!nr_sects)
 205                        break;
 206
 207                first = 0;
 208                first_sector += nr_sects;
 209                start_blk += nr_sects >> (BLOCK_SIZE_BITS - 9);
 210                nr_sects = 0; /* hmm - should be partition size */
 211
 212                switch (data[0x1fc] & 15) {
 213                case 0: /* No partition / ADFS? */
 214                        break;
 215
 216#ifdef CONFIG_ACORN_PARTITION_RISCIX
 217                case PARTITION_RISCIX_SCSI:
 218                        /* RISCiX - we don't know how to find the next one. */
 219                        slot = riscix_partition(state, first_sector, slot,
 220                                                nr_sects);
 221                        break;
 222#endif
 223
 224                case PARTITION_LINUX:
 225                        slot = linux_partition(state, first_sector, slot,
 226                                               nr_sects);
 227                        break;
 228                }
 229                put_dev_sector(sect);
 230                if (slot == -1)
 231                        return -1;
 232        } while (1);
 233        put_dev_sector(sect);
 234        return first ? 0 : 1;
 235}
 236#endif
 237
 238#ifdef CONFIG_ACORN_PARTITION_ADFS
 239/*
 240 * Purpose: allocate ADFS partitions.
 241 *
 242 * Params : hd          - pointer to gendisk structure to store partition info.
 243 *          dev         - device number to access.
 244 *
 245 * Returns: -1 on error, 0 for no ADFS boot sector, 1 for ok.
 246 *
 247 * Alloc  : hda  = whole drive
 248 *          hda1 = ADFS partition on first drive.
 249 *          hda2 = non-ADFS partition.
 250 */
 251int adfspart_check_ADFS(struct parsed_partitions *state)
 252{
 253        unsigned long start_sect, nr_sects, sectscyl, heads;
 254        Sector sect;
 255        unsigned char *data;
 256        struct adfs_discrecord *dr;
 257        unsigned char id;
 258        int slot = 1;
 259
 260        data = read_part_sector(state, 6, &sect);
 261        if (!data)
 262                return -1;
 263
 264        dr = adfs_partition(state, "ADFS", data, 0, slot++);
 265        if (!dr) {
 266                put_dev_sector(sect);
 267                return 0;
 268        }
 269
 270        heads = dr->heads + ((dr->lowsector >> 6) & 1);
 271        sectscyl = dr->secspertrack * heads;
 272        start_sect = ((data[0x1fe] << 8) + data[0x1fd]) * sectscyl;
 273        id = data[0x1fc] & 15;
 274        put_dev_sector(sect);
 275
 276        /*
 277         * Work out start of non-adfs partition.
 278         */
 279        nr_sects = (state->bdev->bd_inode->i_size >> 9) - start_sect;
 280
 281        if (start_sect) {
 282                switch (id) {
 283#ifdef CONFIG_ACORN_PARTITION_RISCIX
 284                case PARTITION_RISCIX_SCSI:
 285                case PARTITION_RISCIX_MFM:
 286                        slot = riscix_partition(state, start_sect, slot,
 287                                                nr_sects);
 288                        break;
 289#endif
 290
 291                case PARTITION_LINUX:
 292                        slot = linux_partition(state, start_sect, slot,
 293                                               nr_sects);
 294                        break;
 295                }
 296        }
 297        strlcat(state->pp_buf, "\n", PAGE_SIZE);
 298        return 1;
 299}
 300#endif
 301
 302#ifdef CONFIG_ACORN_PARTITION_ICS
 303
 304struct ics_part {
 305        __le32 start;
 306        __le32 size;
 307};
 308
 309static int adfspart_check_ICSLinux(struct parsed_partitions *state,
 310                                   unsigned long block)
 311{
 312        Sector sect;
 313        unsigned char *data = read_part_sector(state, block, &sect);
 314        int result = 0;
 315
 316        if (data) {
 317                if (memcmp(data, "LinuxPart", 9) == 0)
 318                        result = 1;
 319                put_dev_sector(sect);
 320        }
 321
 322        return result;
 323}
 324
 325/*
 326 * Check for a valid ICS partition using the checksum.
 327 */
 328static inline int valid_ics_sector(const unsigned char *data)
 329{
 330        unsigned long sum;
 331        int i;
 332
 333        for (i = 0, sum = 0x50617274; i < 508; i++)
 334                sum += data[i];
 335
 336        sum -= le32_to_cpu(*(__le32 *)(&data[508]));
 337
 338        return sum == 0;
 339}
 340
 341/*
 342 * Purpose: allocate ICS partitions.
 343 * Params : hd          - pointer to gendisk structure to store partition info.
 344 *          dev         - device number to access.
 345 * Returns: -1 on error, 0 for no ICS table, 1 for partitions ok.
 346 * Alloc  : hda  = whole drive
 347 *          hda1 = ADFS partition 0 on first drive.
 348 *          hda2 = ADFS partition 1 on first drive.
 349 *              ..etc..
 350 */
 351int adfspart_check_ICS(struct parsed_partitions *state)
 352{
 353        const unsigned char *data;
 354        const struct ics_part *p;
 355        int slot;
 356        Sector sect;
 357
 358        /*
 359         * Try ICS style partitions - sector 0 contains partition info.
 360         */
 361        data = read_part_sector(state, 0, &sect);
 362        if (!data)
 363                return -1;
 364
 365        if (!valid_ics_sector(data)) {
 366                put_dev_sector(sect);
 367                return 0;
 368        }
 369
 370        strlcat(state->pp_buf, " [ICS]", PAGE_SIZE);
 371
 372        for (slot = 1, p = (const struct ics_part *)data; p->size; p++) {
 373                u32 start = le32_to_cpu(p->start);
 374                s32 size = le32_to_cpu(p->size); /* yes, it's signed. */
 375
 376                if (slot == state->limit)
 377                        break;
 378
 379                /*
 380                 * Negative sizes tell the RISC OS ICS driver to ignore
 381                 * this partition - in effect it says that this does not
 382                 * contain an ADFS filesystem.
 383                 */
 384                if (size < 0) {
 385                        size = -size;
 386
 387                        /*
 388                         * Our own extension - We use the first sector
 389                         * of the partition to identify what type this
 390                         * partition is.  We must not make this visible
 391                         * to the filesystem.
 392                         */
 393                        if (size > 1 && adfspart_check_ICSLinux(state, start)) {
 394                                start += 1;
 395                                size -= 1;
 396                        }
 397                }
 398
 399                if (size)
 400                        put_partition(state, slot++, start, size);
 401        }
 402
 403        put_dev_sector(sect);
 404        strlcat(state->pp_buf, "\n", PAGE_SIZE);
 405        return 1;
 406}
 407#endif
 408
 409#ifdef CONFIG_ACORN_PARTITION_POWERTEC
 410struct ptec_part {
 411        __le32 unused1;
 412        __le32 unused2;
 413        __le32 start;
 414        __le32 size;
 415        __le32 unused5;
 416        char type[8];
 417};
 418
 419static inline int valid_ptec_sector(const unsigned char *data)
 420{
 421        unsigned char checksum = 0x2a;
 422        int i;
 423
 424        /*
 425         * If it looks like a PC/BIOS partition, then it
 426         * probably isn't PowerTec.
 427         */
 428        if (data[510] == 0x55 && data[511] == 0xaa)
 429                return 0;
 430
 431        for (i = 0; i < 511; i++)
 432                checksum += data[i];
 433
 434        return checksum == data[511];
 435}
 436
 437/*
 438 * Purpose: allocate ICS partitions.
 439 * Params : hd          - pointer to gendisk structure to store partition info.
 440 *          dev         - device number to access.
 441 * Returns: -1 on error, 0 for no ICS table, 1 for partitions ok.
 442 * Alloc  : hda  = whole drive
 443 *          hda1 = ADFS partition 0 on first drive.
 444 *          hda2 = ADFS partition 1 on first drive.
 445 *              ..etc..
 446 */
 447int adfspart_check_POWERTEC(struct parsed_partitions *state)
 448{
 449        Sector sect;
 450        const unsigned char *data;
 451        const struct ptec_part *p;
 452        int slot = 1;
 453        int i;
 454
 455        data = read_part_sector(state, 0, &sect);
 456        if (!data)
 457                return -1;
 458
 459        if (!valid_ptec_sector(data)) {
 460                put_dev_sector(sect);
 461                return 0;
 462        }
 463
 464        strlcat(state->pp_buf, " [POWERTEC]", PAGE_SIZE);
 465
 466        for (i = 0, p = (const struct ptec_part *)data; i < 12; i++, p++) {
 467                u32 start = le32_to_cpu(p->start);
 468                u32 size = le32_to_cpu(p->size);
 469
 470                if (size)
 471                        put_partition(state, slot++, start, size);
 472        }
 473
 474        put_dev_sector(sect);
 475        strlcat(state->pp_buf, "\n", PAGE_SIZE);
 476        return 1;
 477}
 478#endif
 479
 480#ifdef CONFIG_ACORN_PARTITION_EESOX
 481struct eesox_part {
 482        char    magic[6];
 483        char    name[10];
 484        __le32  start;
 485        __le32  unused6;
 486        __le32  unused7;
 487        __le32  unused8;
 488};
 489
 490/*
 491 * Guess who created this format?
 492 */
 493static const char eesox_name[] = {
 494        'N', 'e', 'i', 'l', ' ',
 495        'C', 'r', 'i', 't', 'c', 'h', 'e', 'l', 'l', ' ', ' '
 496};
 497
 498/*
 499 * EESOX SCSI partition format.
 500 *
 501 * This is a goddamned awful partition format.  We don't seem to store
 502 * the size of the partition in this table, only the start addresses.
 503 *
 504 * There are two possibilities where the size comes from:
 505 *  1. The individual ADFS boot block entries that are placed on the disk.
 506 *  2. The start address of the next entry.
 507 */
 508int adfspart_check_EESOX(struct parsed_partitions *state)
 509{
 510        Sector sect;
 511        const unsigned char *data;
 512        unsigned char buffer[256];
 513        struct eesox_part *p;
 514        sector_t start = 0;
 515        int i, slot = 1;
 516
 517        data = read_part_sector(state, 7, &sect);
 518        if (!data)
 519                return -1;
 520
 521        /*
 522         * "Decrypt" the partition table.  God knows why...
 523         */
 524        for (i = 0; i < 256; i++)
 525                buffer[i] = data[i] ^ eesox_name[i & 15];
 526
 527        put_dev_sector(sect);
 528
 529        for (i = 0, p = (struct eesox_part *)buffer; i < 8; i++, p++) {
 530                sector_t next;
 531
 532                if (memcmp(p->magic, "Eesox", 6))
 533                        break;
 534
 535                next = le32_to_cpu(p->start);
 536                if (i)
 537                        put_partition(state, slot++, start, next - start);
 538                start = next;
 539        }
 540
 541        if (i != 0) {
 542                sector_t size;
 543
 544                size = get_capacity(state->bdev->bd_disk);
 545                put_partition(state, slot++, start, size - start);
 546                strlcat(state->pp_buf, "\n", PAGE_SIZE);
 547        }
 548
 549        return i ? 1 : 0;
 550}
 551#endif
 552