xref: /openbmc/linux/block/partitions/aix.c (revision 6ceea22bbbc84fcf6bf0913bb3db8a657e9002f6)
1*6ceea22bSPhilippe De Muyter /*
2*6ceea22bSPhilippe De Muyter  *  fs/partitions/aix.c
3*6ceea22bSPhilippe De Muyter  *
4*6ceea22bSPhilippe De Muyter  *  Copyright (C) 2012-2013 Philippe De Muyter <phdm@macqel.be>
5*6ceea22bSPhilippe De Muyter  */
6*6ceea22bSPhilippe De Muyter 
7*6ceea22bSPhilippe De Muyter #include "check.h"
8*6ceea22bSPhilippe De Muyter #include "aix.h"
9*6ceea22bSPhilippe De Muyter 
10*6ceea22bSPhilippe De Muyter struct lvm_rec {
11*6ceea22bSPhilippe De Muyter 	char lvm_id[4]; /* "_LVM" */
12*6ceea22bSPhilippe De Muyter 	char reserved4[16];
13*6ceea22bSPhilippe De Muyter 	__be32 lvmarea_len;
14*6ceea22bSPhilippe De Muyter 	__be32 vgda_len;
15*6ceea22bSPhilippe De Muyter 	__be32 vgda_psn[2];
16*6ceea22bSPhilippe De Muyter 	char reserved36[10];
17*6ceea22bSPhilippe De Muyter 	__be16 pp_size; /* log2(pp_size) */
18*6ceea22bSPhilippe De Muyter 	char reserved46[12];
19*6ceea22bSPhilippe De Muyter 	__be16 version;
20*6ceea22bSPhilippe De Muyter 	};
21*6ceea22bSPhilippe De Muyter 
22*6ceea22bSPhilippe De Muyter struct vgda {
23*6ceea22bSPhilippe De Muyter 	__be32 secs;
24*6ceea22bSPhilippe De Muyter 	__be32 usec;
25*6ceea22bSPhilippe De Muyter 	char reserved8[16];
26*6ceea22bSPhilippe De Muyter 	__be16 numlvs;
27*6ceea22bSPhilippe De Muyter 	__be16 maxlvs;
28*6ceea22bSPhilippe De Muyter 	__be16 pp_size;
29*6ceea22bSPhilippe De Muyter 	__be16 numpvs;
30*6ceea22bSPhilippe De Muyter 	__be16 total_vgdas;
31*6ceea22bSPhilippe De Muyter 	__be16 vgda_size;
32*6ceea22bSPhilippe De Muyter 	};
33*6ceea22bSPhilippe De Muyter 
34*6ceea22bSPhilippe De Muyter struct lvd {
35*6ceea22bSPhilippe De Muyter 	__be16 lv_ix;
36*6ceea22bSPhilippe De Muyter 	__be16 res2;
37*6ceea22bSPhilippe De Muyter 	__be16 res4;
38*6ceea22bSPhilippe De Muyter 	__be16 maxsize;
39*6ceea22bSPhilippe De Muyter 	__be16 lv_state;
40*6ceea22bSPhilippe De Muyter 	__be16 mirror;
41*6ceea22bSPhilippe De Muyter 	__be16 mirror_policy;
42*6ceea22bSPhilippe De Muyter 	__be16 num_lps;
43*6ceea22bSPhilippe De Muyter 	__be16 res10[8];
44*6ceea22bSPhilippe De Muyter 	};
45*6ceea22bSPhilippe De Muyter 
46*6ceea22bSPhilippe De Muyter struct lvname {
47*6ceea22bSPhilippe De Muyter 	char name[64];
48*6ceea22bSPhilippe De Muyter 	};
49*6ceea22bSPhilippe De Muyter 
50*6ceea22bSPhilippe De Muyter struct ppe {
51*6ceea22bSPhilippe De Muyter 	__be16 lv_ix;
52*6ceea22bSPhilippe De Muyter 	unsigned short res2;
53*6ceea22bSPhilippe De Muyter 	unsigned short res4;
54*6ceea22bSPhilippe De Muyter 	__be16 lp_ix;
55*6ceea22bSPhilippe De Muyter 	unsigned short res8[12];
56*6ceea22bSPhilippe De Muyter 	};
57*6ceea22bSPhilippe De Muyter 
58*6ceea22bSPhilippe De Muyter struct pvd {
59*6ceea22bSPhilippe De Muyter 	char reserved0[16];
60*6ceea22bSPhilippe De Muyter 	__be16 pp_count;
61*6ceea22bSPhilippe De Muyter 	char reserved18[2];
62*6ceea22bSPhilippe De Muyter 	__be32 psn_part1;
63*6ceea22bSPhilippe De Muyter 	char reserved24[8];
64*6ceea22bSPhilippe De Muyter 	struct ppe ppe[1016];
65*6ceea22bSPhilippe De Muyter 	};
66*6ceea22bSPhilippe De Muyter 
67*6ceea22bSPhilippe De Muyter #define LVM_MAXLVS 256
68*6ceea22bSPhilippe De Muyter 
69*6ceea22bSPhilippe De Muyter /**
70*6ceea22bSPhilippe De Muyter  * last_lba(): return number of last logical block of device
71*6ceea22bSPhilippe De Muyter  * @bdev: block device
72*6ceea22bSPhilippe De Muyter  *
73*6ceea22bSPhilippe De Muyter  * Description: Returns last LBA value on success, 0 on error.
74*6ceea22bSPhilippe De Muyter  * This is stored (by sd and ide-geometry) in
75*6ceea22bSPhilippe De Muyter  *  the part[0] entry for this disk, and is the number of
76*6ceea22bSPhilippe De Muyter  *  physical sectors available on the disk.
77*6ceea22bSPhilippe De Muyter  */
78*6ceea22bSPhilippe De Muyter static u64 last_lba(struct block_device *bdev)
79*6ceea22bSPhilippe De Muyter {
80*6ceea22bSPhilippe De Muyter 	if (!bdev || !bdev->bd_inode)
81*6ceea22bSPhilippe De Muyter 		return 0;
82*6ceea22bSPhilippe De Muyter 	return (bdev->bd_inode->i_size >> 9) - 1ULL;
83*6ceea22bSPhilippe De Muyter }
84*6ceea22bSPhilippe De Muyter 
85*6ceea22bSPhilippe De Muyter /**
86*6ceea22bSPhilippe De Muyter  * read_lba(): Read bytes from disk, starting at given LBA
87*6ceea22bSPhilippe De Muyter  * @state
88*6ceea22bSPhilippe De Muyter  * @lba
89*6ceea22bSPhilippe De Muyter  * @buffer
90*6ceea22bSPhilippe De Muyter  * @count
91*6ceea22bSPhilippe De Muyter  *
92*6ceea22bSPhilippe De Muyter  * Description:  Reads @count bytes from @state->bdev into @buffer.
93*6ceea22bSPhilippe De Muyter  * Returns number of bytes read on success, 0 on error.
94*6ceea22bSPhilippe De Muyter  */
95*6ceea22bSPhilippe De Muyter static size_t read_lba(struct parsed_partitions *state, u64 lba, u8 *buffer,
96*6ceea22bSPhilippe De Muyter 			size_t count)
97*6ceea22bSPhilippe De Muyter {
98*6ceea22bSPhilippe De Muyter 	size_t totalreadcount = 0;
99*6ceea22bSPhilippe De Muyter 
100*6ceea22bSPhilippe De Muyter 	if (!buffer || lba + count / 512 > last_lba(state->bdev))
101*6ceea22bSPhilippe De Muyter 		return 0;
102*6ceea22bSPhilippe De Muyter 
103*6ceea22bSPhilippe De Muyter 	while (count) {
104*6ceea22bSPhilippe De Muyter 		int copied = 512;
105*6ceea22bSPhilippe De Muyter 		Sector sect;
106*6ceea22bSPhilippe De Muyter 		unsigned char *data = read_part_sector(state, lba++, &sect);
107*6ceea22bSPhilippe De Muyter 		if (!data)
108*6ceea22bSPhilippe De Muyter 			break;
109*6ceea22bSPhilippe De Muyter 		if (copied > count)
110*6ceea22bSPhilippe De Muyter 			copied = count;
111*6ceea22bSPhilippe De Muyter 		memcpy(buffer, data, copied);
112*6ceea22bSPhilippe De Muyter 		put_dev_sector(sect);
113*6ceea22bSPhilippe De Muyter 		buffer += copied;
114*6ceea22bSPhilippe De Muyter 		totalreadcount += copied;
115*6ceea22bSPhilippe De Muyter 		count -= copied;
116*6ceea22bSPhilippe De Muyter 	}
117*6ceea22bSPhilippe De Muyter 	return totalreadcount;
118*6ceea22bSPhilippe De Muyter }
119*6ceea22bSPhilippe De Muyter 
120*6ceea22bSPhilippe De Muyter /**
121*6ceea22bSPhilippe De Muyter  * alloc_pvd(): reads physical volume descriptor
122*6ceea22bSPhilippe De Muyter  * @state
123*6ceea22bSPhilippe De Muyter  * @lba
124*6ceea22bSPhilippe De Muyter  *
125*6ceea22bSPhilippe De Muyter  * Description: Returns pvd on success,  NULL on error.
126*6ceea22bSPhilippe De Muyter  * Allocates space for pvd and fill it with disk blocks at @lba
127*6ceea22bSPhilippe De Muyter  * Notes: remember to free pvd when you're done!
128*6ceea22bSPhilippe De Muyter  */
129*6ceea22bSPhilippe De Muyter static struct pvd *alloc_pvd(struct parsed_partitions *state, u32 lba)
130*6ceea22bSPhilippe De Muyter {
131*6ceea22bSPhilippe De Muyter 	size_t count = sizeof(struct pvd);
132*6ceea22bSPhilippe De Muyter 	struct pvd *p;
133*6ceea22bSPhilippe De Muyter 
134*6ceea22bSPhilippe De Muyter 	p = kmalloc(count, GFP_KERNEL);
135*6ceea22bSPhilippe De Muyter 	if (!p)
136*6ceea22bSPhilippe De Muyter 		return NULL;
137*6ceea22bSPhilippe De Muyter 
138*6ceea22bSPhilippe De Muyter 	if (read_lba(state, lba, (u8 *) p, count) < count) {
139*6ceea22bSPhilippe De Muyter 		kfree(p);
140*6ceea22bSPhilippe De Muyter 		return NULL;
141*6ceea22bSPhilippe De Muyter 	}
142*6ceea22bSPhilippe De Muyter 	return p;
143*6ceea22bSPhilippe De Muyter }
144*6ceea22bSPhilippe De Muyter 
145*6ceea22bSPhilippe De Muyter /**
146*6ceea22bSPhilippe De Muyter  * alloc_lvn(): reads logical volume names
147*6ceea22bSPhilippe De Muyter  * @state
148*6ceea22bSPhilippe De Muyter  * @lba
149*6ceea22bSPhilippe De Muyter  *
150*6ceea22bSPhilippe De Muyter  * Description: Returns lvn on success,  NULL on error.
151*6ceea22bSPhilippe De Muyter  * Allocates space for lvn and fill it with disk blocks at @lba
152*6ceea22bSPhilippe De Muyter  * Notes: remember to free lvn when you're done!
153*6ceea22bSPhilippe De Muyter  */
154*6ceea22bSPhilippe De Muyter static struct lvname *alloc_lvn(struct parsed_partitions *state, u32 lba)
155*6ceea22bSPhilippe De Muyter {
156*6ceea22bSPhilippe De Muyter 	size_t count = sizeof(struct lvname) * LVM_MAXLVS;
157*6ceea22bSPhilippe De Muyter 	struct lvname *p;
158*6ceea22bSPhilippe De Muyter 
159*6ceea22bSPhilippe De Muyter 	p = kmalloc(count, GFP_KERNEL);
160*6ceea22bSPhilippe De Muyter 	if (!p)
161*6ceea22bSPhilippe De Muyter 		return NULL;
162*6ceea22bSPhilippe De Muyter 
163*6ceea22bSPhilippe De Muyter 	if (read_lba(state, lba, (u8 *) p, count) < count) {
164*6ceea22bSPhilippe De Muyter 		kfree(p);
165*6ceea22bSPhilippe De Muyter 		return NULL;
166*6ceea22bSPhilippe De Muyter 	}
167*6ceea22bSPhilippe De Muyter 	return p;
168*6ceea22bSPhilippe De Muyter }
169*6ceea22bSPhilippe De Muyter 
170*6ceea22bSPhilippe De Muyter int aix_partition(struct parsed_partitions *state)
171*6ceea22bSPhilippe De Muyter {
172*6ceea22bSPhilippe De Muyter 	int ret = 0;
173*6ceea22bSPhilippe De Muyter 	Sector sect;
174*6ceea22bSPhilippe De Muyter 	unsigned char *d;
175*6ceea22bSPhilippe De Muyter 	u32 pp_bytes_size;
176*6ceea22bSPhilippe De Muyter 	u32 pp_blocks_size = 0;
177*6ceea22bSPhilippe De Muyter 	u32 vgda_sector = 0;
178*6ceea22bSPhilippe De Muyter 	u32 vgda_len = 0;
179*6ceea22bSPhilippe De Muyter 	int numlvs = 0;
180*6ceea22bSPhilippe De Muyter 	struct pvd *pvd;
181*6ceea22bSPhilippe De Muyter 	struct lv_info {
182*6ceea22bSPhilippe De Muyter 		unsigned short pps_per_lv;
183*6ceea22bSPhilippe De Muyter 		unsigned short pps_found;
184*6ceea22bSPhilippe De Muyter 		unsigned char lv_is_contiguous;
185*6ceea22bSPhilippe De Muyter 	} *lvip;
186*6ceea22bSPhilippe De Muyter 	struct lvname *n = NULL;
187*6ceea22bSPhilippe De Muyter 
188*6ceea22bSPhilippe De Muyter 	d = read_part_sector(state, 7, &sect);
189*6ceea22bSPhilippe De Muyter 	if (d) {
190*6ceea22bSPhilippe De Muyter 		struct lvm_rec *p = (struct lvm_rec *)d;
191*6ceea22bSPhilippe De Muyter 		u16 lvm_version = be16_to_cpu(p->version);
192*6ceea22bSPhilippe De Muyter 		char tmp[64];
193*6ceea22bSPhilippe De Muyter 
194*6ceea22bSPhilippe De Muyter 		if (lvm_version == 1) {
195*6ceea22bSPhilippe De Muyter 			int pp_size_log2 = be16_to_cpu(p->pp_size);
196*6ceea22bSPhilippe De Muyter 
197*6ceea22bSPhilippe De Muyter 			pp_bytes_size = 1 << pp_size_log2;
198*6ceea22bSPhilippe De Muyter 			pp_blocks_size = pp_bytes_size / 512;
199*6ceea22bSPhilippe De Muyter 			snprintf(tmp, sizeof(tmp),
200*6ceea22bSPhilippe De Muyter 				" AIX LVM header version %u found\n",
201*6ceea22bSPhilippe De Muyter 				lvm_version);
202*6ceea22bSPhilippe De Muyter 			vgda_len = be32_to_cpu(p->vgda_len);
203*6ceea22bSPhilippe De Muyter 			vgda_sector = be32_to_cpu(p->vgda_psn[0]);
204*6ceea22bSPhilippe De Muyter 		} else {
205*6ceea22bSPhilippe De Muyter 			snprintf(tmp, sizeof(tmp),
206*6ceea22bSPhilippe De Muyter 				" unsupported AIX LVM version %d found\n",
207*6ceea22bSPhilippe De Muyter 				lvm_version);
208*6ceea22bSPhilippe De Muyter 		}
209*6ceea22bSPhilippe De Muyter 		strlcat(state->pp_buf, tmp, PAGE_SIZE);
210*6ceea22bSPhilippe De Muyter 		put_dev_sector(sect);
211*6ceea22bSPhilippe De Muyter 	}
212*6ceea22bSPhilippe De Muyter 	if (vgda_sector && (d = read_part_sector(state, vgda_sector, &sect))) {
213*6ceea22bSPhilippe De Muyter 		struct vgda *p = (struct vgda *)d;
214*6ceea22bSPhilippe De Muyter 
215*6ceea22bSPhilippe De Muyter 		numlvs = be16_to_cpu(p->numlvs);
216*6ceea22bSPhilippe De Muyter 		put_dev_sector(sect);
217*6ceea22bSPhilippe De Muyter 	}
218*6ceea22bSPhilippe De Muyter 	lvip = kzalloc(sizeof(struct lv_info) * state->limit, GFP_KERNEL);
219*6ceea22bSPhilippe De Muyter 	if (!lvip)
220*6ceea22bSPhilippe De Muyter 		return 0;
221*6ceea22bSPhilippe De Muyter 	if (numlvs && (d = read_part_sector(state, vgda_sector + 1, &sect))) {
222*6ceea22bSPhilippe De Muyter 		struct lvd *p = (struct lvd *)d;
223*6ceea22bSPhilippe De Muyter 		int i;
224*6ceea22bSPhilippe De Muyter 
225*6ceea22bSPhilippe De Muyter 		n = alloc_lvn(state, vgda_sector + vgda_len - 33);
226*6ceea22bSPhilippe De Muyter 		if (n) {
227*6ceea22bSPhilippe De Muyter 			int foundlvs = 0;
228*6ceea22bSPhilippe De Muyter 
229*6ceea22bSPhilippe De Muyter 			for (i = 0; foundlvs < numlvs && i < state->limit; i += 1) {
230*6ceea22bSPhilippe De Muyter 				lvip[i].pps_per_lv = be16_to_cpu(p[i].num_lps);
231*6ceea22bSPhilippe De Muyter 				if (lvip[i].pps_per_lv)
232*6ceea22bSPhilippe De Muyter 					foundlvs += 1;
233*6ceea22bSPhilippe De Muyter 			}
234*6ceea22bSPhilippe De Muyter 		}
235*6ceea22bSPhilippe De Muyter 		put_dev_sector(sect);
236*6ceea22bSPhilippe De Muyter 	}
237*6ceea22bSPhilippe De Muyter 	pvd = alloc_pvd(state, vgda_sector + 17);
238*6ceea22bSPhilippe De Muyter 	if (pvd) {
239*6ceea22bSPhilippe De Muyter 		int numpps = be16_to_cpu(pvd->pp_count);
240*6ceea22bSPhilippe De Muyter 		int psn_part1 = be32_to_cpu(pvd->psn_part1);
241*6ceea22bSPhilippe De Muyter 		int i;
242*6ceea22bSPhilippe De Muyter 		int cur_lv_ix = -1;
243*6ceea22bSPhilippe De Muyter 		int next_lp_ix = 1;
244*6ceea22bSPhilippe De Muyter 		int lp_ix;
245*6ceea22bSPhilippe De Muyter 
246*6ceea22bSPhilippe De Muyter 		for (i = 0; i < numpps; i += 1) {
247*6ceea22bSPhilippe De Muyter 			struct ppe *p = pvd->ppe + i;
248*6ceea22bSPhilippe De Muyter 			unsigned int lv_ix;
249*6ceea22bSPhilippe De Muyter 
250*6ceea22bSPhilippe De Muyter 			lp_ix = be16_to_cpu(p->lp_ix);
251*6ceea22bSPhilippe De Muyter 			if (!lp_ix) {
252*6ceea22bSPhilippe De Muyter 				next_lp_ix = 1;
253*6ceea22bSPhilippe De Muyter 				continue;
254*6ceea22bSPhilippe De Muyter 			}
255*6ceea22bSPhilippe De Muyter 			lv_ix = be16_to_cpu(p->lv_ix) - 1;
256*6ceea22bSPhilippe De Muyter 			if (lv_ix > state->limit) {
257*6ceea22bSPhilippe De Muyter 				cur_lv_ix = -1;
258*6ceea22bSPhilippe De Muyter 				continue;
259*6ceea22bSPhilippe De Muyter 			}
260*6ceea22bSPhilippe De Muyter 			lvip[lv_ix].pps_found += 1;
261*6ceea22bSPhilippe De Muyter 			if (lp_ix == 1) {
262*6ceea22bSPhilippe De Muyter 				cur_lv_ix = lv_ix;
263*6ceea22bSPhilippe De Muyter 				next_lp_ix = 1;
264*6ceea22bSPhilippe De Muyter 			} else if (lv_ix != cur_lv_ix || lp_ix != next_lp_ix) {
265*6ceea22bSPhilippe De Muyter 				next_lp_ix = 1;
266*6ceea22bSPhilippe De Muyter 				continue;
267*6ceea22bSPhilippe De Muyter 			}
268*6ceea22bSPhilippe De Muyter 			if (lp_ix == lvip[lv_ix].pps_per_lv) {
269*6ceea22bSPhilippe De Muyter 				char tmp[70];
270*6ceea22bSPhilippe De Muyter 
271*6ceea22bSPhilippe De Muyter 				put_partition(state, lv_ix + 1,
272*6ceea22bSPhilippe De Muyter 				  (i + 1 - lp_ix) * pp_blocks_size + psn_part1,
273*6ceea22bSPhilippe De Muyter 				  lvip[lv_ix].pps_per_lv * pp_blocks_size);
274*6ceea22bSPhilippe De Muyter 				snprintf(tmp, sizeof(tmp), " <%s>\n",
275*6ceea22bSPhilippe De Muyter 					 n[lv_ix].name);
276*6ceea22bSPhilippe De Muyter 				strlcat(state->pp_buf, tmp, PAGE_SIZE);
277*6ceea22bSPhilippe De Muyter 				lvip[lv_ix].lv_is_contiguous = 1;
278*6ceea22bSPhilippe De Muyter 				ret = 1;
279*6ceea22bSPhilippe De Muyter 				next_lp_ix = 1;
280*6ceea22bSPhilippe De Muyter 			} else
281*6ceea22bSPhilippe De Muyter 				next_lp_ix += 1;
282*6ceea22bSPhilippe De Muyter 		}
283*6ceea22bSPhilippe De Muyter 		for (i = 0; i < state->limit; i += 1)
284*6ceea22bSPhilippe De Muyter 			if (lvip[i].pps_found && !lvip[i].lv_is_contiguous)
285*6ceea22bSPhilippe De Muyter 				pr_warn("partition %s (%u pp's found) is "
286*6ceea22bSPhilippe De Muyter 					"not contiguous\n",
287*6ceea22bSPhilippe De Muyter 					n[i].name, lvip[i].pps_found);
288*6ceea22bSPhilippe De Muyter 		kfree(pvd);
289*6ceea22bSPhilippe De Muyter 	}
290*6ceea22bSPhilippe De Muyter 	kfree(n);
291*6ceea22bSPhilippe De Muyter 	kfree(lvip);
292*6ceea22bSPhilippe De Muyter 	return ret;
293*6ceea22bSPhilippe De Muyter }
294