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