4 * IBM DASD partition table handling.
6 * Mostly taken from drivers/s390/block/dasd.c
8 * Copyright (c) 2005, Hannes Reinecke, SUSE Linux Products GmbH
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
30 #include <sys/types.h>
32 #include <sys/ioctl.h>
33 #include <linux/hdreg.h>
37 #include <libdevmapper.h>
38 #include "devmapper.h"
40 #include "byteorder.h"
46 read_dasd_pt(int fd, struct slice all, struct slice *sp, int ns)
49 int blocksize, offset, size;
51 dasd_information_t info;
52 struct hd_geometry geo;
55 unsigned char *label_raw;
56 volume_label_t vlabel;
57 unsigned char *data = NULL;
69 if (fstat(fd, &sbuf) == -1) {
73 devname = dm_mapname(major(sbuf.st_rdev), minor(sbuf.st_rdev));
75 if (devname != NULL) {
76 /* We were passed a handle to a dm device.
77 * Get the first target and operate on that instead.
79 if (!(dev = dm_get_first_dep(devname))) {
85 if ((unsigned int)major(dev) != 94) {
91 * Hard to believe, but there's no simple way to translate
92 * major/minor into an openable device file, so we have
93 * to create one for ourselves.
96 sprintf(pathname, "/dev/.kpartx-node-%u-%u",
97 (unsigned int)major(dev), (unsigned int)minor(dev));
98 if ((fd_dasd = open(pathname, O_RDONLY)) == -1) {
99 /* Devicenode does not exist. Try to create one */
100 if (mknod(pathname, 0600 | S_IFBLK, dev) == -1) {
101 /* Couldn't create a device node */
104 fd_dasd = open(pathname, O_RDONLY);
106 * The file will vanish when the last process (we)
107 * has ceased to access it.
112 /* Couldn't open the device */
119 if (ioctl(fd_dasd, BIODASDINFO, (unsigned long)&info) != 0) {
123 if (ioctl(fd_dasd, HDIO_GETGEO, (unsigned long)&geo) != 0) {
127 if (ioctl(fd_dasd, BLKGETSIZE, &disksize) != 0)
130 if (ioctl(fd_dasd, BLKSSZGET, &blocksize) != 0)
133 if (blocksize < 512 || blocksize > 4096)
137 * Get volume label, extract name and type.
140 if (!(data = (unsigned char *)malloc(blocksize)))
144 if (lseek(fd_dasd, info.label_block * blocksize, SEEK_SET) == -1)
146 if (read(fd_dasd, data, blocksize) == -1) {
150 vtoc_ebcdic_dec(data, type, 4);
152 if ((!info.FBA_layout) && (!strcmp(info.type, "ECKD")))
153 label_raw = &data[8];
155 label_raw = &data[4];
158 vtoc_ebcdic_dec(label_raw, name, 6);
160 memcpy (&vlabel, data, sizeof(volume_label_t));
163 * Three different types: CMS1, VOL1 and LNX1/unlabeled
165 if (strncmp(type, "CMS1", 4) == 0) {
167 * VM style CMS1 labeled disk
169 int *label = (int *) &vlabel;
171 if (label[13] != 0) {
172 /* disk is reserved minidisk */
173 blocksize = label[3];
175 size = (label[7] - 1)*(blocksize >> 9);
177 offset = (info.label_block + 1) * (blocksize >> 9);
178 size = disksize - offset;
180 sp[0].start = offset * (blocksize >> 9);
181 sp[0].size = size - offset * (blocksize >> 9);
183 } else if ((strncmp(type, "VOL1", 4) == 0) &&
184 (!info.FBA_layout) && (!strcmp(info.type, "ECKD"))) {
186 * New style VOL1 labeled disk
190 /* get block number and read then go through format1 labels */
191 blk = cchhb2blk(&vlabel.vtoc, &geo) + 1;
193 if (lseek(fd_dasd, blk * blocksize, SEEK_SET) == -1)
196 while (read(fd_dasd, data, blocksize) != -1) {
199 memcpy(&f1, data, sizeof(format1_label_t));
201 /* skip FMT4 / FMT5 / FMT7 labels */
202 if (EBCtoASC[f1.DS1FMTID] == '4'
203 || EBCtoASC[f1.DS1FMTID] == '5'
204 || EBCtoASC[f1.DS1FMTID] == '7') {
209 /* only FMT1 valid at this point */
210 if (EBCtoASC[f1.DS1FMTID] != '1')
213 /* OK, we got valid partition data */
214 offset = cchh2blk(&f1.DS1EXT1.llimit, &geo);
215 size = cchh2blk(&f1.DS1EXT1.ulimit, &geo) -
216 offset + geo.sectors;
217 sp[counter].start = offset * (blocksize >> 9);
218 sp[counter].size = size * (blocksize >> 9);
225 * Old style LNX1 or unlabeled disk
227 offset = (info.label_block + 1) * (blocksize >> 9);
228 size = disksize - offset;
229 sp[0].start = offset * (blocksize >> 9);
230 sp[0].size = size - offset * (blocksize >> 9);
237 if (fd_dasd != -1 && fd_dasd != fd)