xref: /OK3568_Linux_fs/kernel/block/partitions/acorn.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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, &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, &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, &sect);
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, &sect);
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, &sect);
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, &sect);
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, &sect);
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, &sect);
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