Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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