• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/fs/partitions/
1/*
2 * File...........: linux/fs/partitions/ibm.c
3 * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
4 *                  Volker Sameske <sameske@de.ibm.com>
5 * Bugreports.to..: <Linux390@de.ibm.com>
6 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
7 */
8
9#include <linux/buffer_head.h>
10#include <linux/hdreg.h>
11#include <linux/slab.h>
12#include <asm/dasd.h>
13#include <asm/ebcdic.h>
14#include <asm/uaccess.h>
15#include <asm/vtoc.h>
16
17#include "check.h"
18#include "ibm.h"
19
20/*
21 * compute the block number from a
22 * cyl-cyl-head-head structure
23 */
24static sector_t
25cchh2blk (struct vtoc_cchh *ptr, struct hd_geometry *geo) {
26
27	sector_t cyl;
28	__u16 head;
29
30	/*decode cylinder and heads for large volumes */
31	cyl = ptr->hh & 0xFFF0;
32	cyl <<= 12;
33	cyl |= ptr->cc;
34	head = ptr->hh & 0x000F;
35	return cyl * geo->heads * geo->sectors +
36	       head * geo->sectors;
37}
38
39/*
40 * compute the block number from a
41 * cyl-cyl-head-head-block structure
42 */
43static sector_t
44cchhb2blk (struct vtoc_cchhb *ptr, struct hd_geometry *geo) {
45
46	sector_t cyl;
47	__u16 head;
48
49	/*decode cylinder and heads for large volumes */
50	cyl = ptr->hh & 0xFFF0;
51	cyl <<= 12;
52	cyl |= ptr->cc;
53	head = ptr->hh & 0x000F;
54	return	cyl * geo->heads * geo->sectors +
55		head * geo->sectors +
56		ptr->b;
57}
58
59/*
60 */
61int ibm_partition(struct parsed_partitions *state)
62{
63	struct block_device *bdev = state->bdev;
64	int blocksize, res;
65	loff_t i_size, offset, size, fmt_size;
66	dasd_information2_t *info;
67	struct hd_geometry *geo;
68	char type[5] = {0,};
69	char name[7] = {0,};
70	union label_t {
71		struct vtoc_volume_label_cdl vol;
72		struct vtoc_volume_label_ldl lnx;
73		struct vtoc_cms_label cms;
74	} *label;
75	unsigned char *data;
76	Sector sect;
77	sector_t labelsect;
78	char tmp[64];
79
80	res = 0;
81	blocksize = bdev_logical_block_size(bdev);
82	if (blocksize <= 0)
83		goto out_exit;
84	i_size = i_size_read(bdev->bd_inode);
85	if (i_size == 0)
86		goto out_exit;
87
88	info = kmalloc(sizeof(dasd_information2_t), GFP_KERNEL);
89	if (info == NULL)
90		goto out_exit;
91	geo = kmalloc(sizeof(struct hd_geometry), GFP_KERNEL);
92	if (geo == NULL)
93		goto out_nogeo;
94	label = kmalloc(sizeof(union label_t), GFP_KERNEL);
95	if (label == NULL)
96		goto out_nolab;
97
98	if (ioctl_by_bdev(bdev, BIODASDINFO2, (unsigned long)info) != 0 ||
99	    ioctl_by_bdev(bdev, HDIO_GETGEO, (unsigned long)geo) != 0)
100		goto out_freeall;
101
102	/*
103	 * Special case for FBA disks: label sector does not depend on
104	 * blocksize.
105	 */
106	if ((info->cu_type == 0x6310 && info->dev_type == 0x9336) ||
107	    (info->cu_type == 0x3880 && info->dev_type == 0x3370))
108		labelsect = info->label_block;
109	else
110		labelsect = info->label_block * (blocksize >> 9);
111
112	/*
113	 * Get volume label, extract name and type.
114	 */
115	data = read_part_sector(state, labelsect, &sect);
116	if (data == NULL)
117		goto out_readerr;
118
119	memcpy(label, data, sizeof(union label_t));
120	put_dev_sector(sect);
121
122	if ((!info->FBA_layout) && (!strcmp(info->type, "ECKD"))) {
123		strncpy(type, label->vol.vollbl, 4);
124		strncpy(name, label->vol.volid, 6);
125	} else {
126		strncpy(type, label->lnx.vollbl, 4);
127		strncpy(name, label->lnx.volid, 6);
128	}
129	EBCASC(type, 4);
130	EBCASC(name, 6);
131
132	res = 1;
133
134	/*
135	 * Three different formats: LDL, CDL and unformated disk
136	 *
137	 * identified by info->format
138	 *
139	 * unformated disks we do not have to care about
140	 */
141	if (info->format == DASD_FORMAT_LDL) {
142		if (strncmp(type, "CMS1", 4) == 0) {
143			/*
144			 * VM style CMS1 labeled disk
145			 */
146			blocksize = label->cms.block_size;
147			if (label->cms.disk_offset != 0) {
148				snprintf(tmp, sizeof(tmp), "CMS1/%8s(MDSK):", name);
149				strlcat(state->pp_buf, tmp, PAGE_SIZE);
150				/* disk is reserved minidisk */
151				offset = label->cms.disk_offset;
152				size = (label->cms.block_count - 1)
153					* (blocksize >> 9);
154			} else {
155				snprintf(tmp, sizeof(tmp), "CMS1/%8s:", name);
156				strlcat(state->pp_buf, tmp, PAGE_SIZE);
157				offset = (info->label_block + 1);
158				size = label->cms.block_count
159					* (blocksize >> 9);
160			}
161			put_partition(state, 1, offset*(blocksize >> 9),
162				      size-offset*(blocksize >> 9));
163		} else {
164			if (strncmp(type, "LNX1", 4) == 0) {
165				snprintf(tmp, sizeof(tmp), "LNX1/%8s:", name);
166				strlcat(state->pp_buf, tmp, PAGE_SIZE);
167				if (label->lnx.ldl_version == 0xf2) {
168					fmt_size = label->lnx.formatted_blocks
169						* (blocksize >> 9);
170				} else if (!strcmp(info->type, "ECKD")) {
171					/* formated w/o large volume support */
172					fmt_size = geo->cylinders * geo->heads
173					      * geo->sectors * (blocksize >> 9);
174				} else {
175					/* old label and no usable disk geometry
176					 * (e.g. DIAG) */
177					fmt_size = i_size >> 9;
178				}
179				size = i_size >> 9;
180				if (fmt_size < size)
181					size = fmt_size;
182				offset = (info->label_block + 1);
183			} else {
184				/* unlabeled disk */
185				strlcat(state->pp_buf, "(nonl)", PAGE_SIZE);
186				size = i_size >> 9;
187				offset = (info->label_block + 1);
188			}
189			put_partition(state, 1, offset*(blocksize >> 9),
190				      size-offset*(blocksize >> 9));
191		}
192	} else if (info->format == DASD_FORMAT_CDL) {
193		/*
194		 * New style CDL formatted disk
195		 */
196		sector_t blk;
197		int counter;
198
199		/*
200		 * check if VOL1 label is available
201		 * if not, something is wrong, skipping partition detection
202		 */
203		if (strncmp(type, "VOL1",  4) == 0) {
204			snprintf(tmp, sizeof(tmp), "VOL1/%8s:", name);
205			strlcat(state->pp_buf, tmp, PAGE_SIZE);
206			/*
207			 * get block number and read then go through format1
208			 * labels
209			 */
210			blk = cchhb2blk(&label->vol.vtoc, geo) + 1;
211			counter = 0;
212			data = read_part_sector(state, blk * (blocksize/512),
213						&sect);
214			while (data != NULL) {
215				struct vtoc_format1_label f1;
216
217				memcpy(&f1, data,
218				       sizeof(struct vtoc_format1_label));
219				put_dev_sector(sect);
220
221				/* skip FMT4 / FMT5 / FMT7 labels */
222				if (f1.DS1FMTID == _ascebc['4']
223				    || f1.DS1FMTID == _ascebc['5']
224				    || f1.DS1FMTID == _ascebc['7']
225				    || f1.DS1FMTID == _ascebc['9']) {
226					blk++;
227					data = read_part_sector(state,
228						blk * (blocksize/512), &sect);
229					continue;
230				}
231
232				/* only FMT1 and 8 labels valid at this point */
233				if (f1.DS1FMTID != _ascebc['1'] &&
234				    f1.DS1FMTID != _ascebc['8'])
235					break;
236
237				/* OK, we got valid partition data */
238				offset = cchh2blk(&f1.DS1EXT1.llimit, geo);
239				size  = cchh2blk(&f1.DS1EXT1.ulimit, geo) -
240					offset + geo->sectors;
241				if (counter >= state->limit)
242					break;
243				put_partition(state, counter + 1,
244					      offset * (blocksize >> 9),
245					      size * (blocksize >> 9));
246				counter++;
247				blk++;
248				data = read_part_sector(state,
249						blk * (blocksize/512), &sect);
250			}
251
252			if (!data)
253				/* Are we not supposed to report this ? */
254				goto out_readerr;
255		} else
256			printk(KERN_WARNING "Warning, expected Label VOL1 not "
257			       "found, treating as CDL formated Disk");
258
259	}
260
261	strlcat(state->pp_buf, "\n", PAGE_SIZE);
262	goto out_freeall;
263
264
265out_readerr:
266	res = -1;
267out_freeall:
268	kfree(label);
269out_nolab:
270	kfree(geo);
271out_nogeo:
272	kfree(info);
273out_exit:
274	return res;
275}
276