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