arm64: dts: qcom: sm8550: add TRNG node
[linux-modified.git] / block / partitions / ibm.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
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  * Copyright IBM Corp. 1999, 2012
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 <linux/uaccess.h>
15 #include <asm/vtoc.h>
16 #include <linux/module.h>
17 #include <linux/dasd_mod.h>
18
19 #include "check.h"
20
21 union label_t {
22         struct vtoc_volume_label_cdl vol;
23         struct vtoc_volume_label_ldl lnx;
24         struct vtoc_cms_label cms;
25 };
26
27 /*
28  * compute the block number from a
29  * cyl-cyl-head-head structure
30  */
31 static sector_t cchh2blk(struct vtoc_cchh *ptr, struct hd_geometry *geo)
32 {
33         sector_t cyl;
34         __u16 head;
35
36         /* decode cylinder and heads for large volumes */
37         cyl = ptr->hh & 0xFFF0;
38         cyl <<= 12;
39         cyl |= ptr->cc;
40         head = ptr->hh & 0x000F;
41         return cyl * geo->heads * geo->sectors +
42                head * geo->sectors;
43 }
44
45 /*
46  * compute the block number from a
47  * cyl-cyl-head-head-block structure
48  */
49 static sector_t cchhb2blk(struct vtoc_cchhb *ptr, struct hd_geometry *geo)
50 {
51         sector_t cyl;
52         __u16 head;
53
54         /* decode cylinder and heads for large volumes */
55         cyl = ptr->hh & 0xFFF0;
56         cyl <<= 12;
57         cyl |= ptr->cc;
58         head = ptr->hh & 0x000F;
59         return  cyl * geo->heads * geo->sectors +
60                 head * geo->sectors +
61                 ptr->b;
62 }
63
64 /* Volume Label Type/ID Length */
65 #define DASD_VOL_TYPE_LEN       4
66 #define DASD_VOL_ID_LEN         6
67
68 /* Volume Label Types */
69 #define DASD_VOLLBL_TYPE_VOL1 0
70 #define DASD_VOLLBL_TYPE_LNX1 1
71 #define DASD_VOLLBL_TYPE_CMS1 2
72
73 struct dasd_vollabel {
74         char *type;
75         int idx;
76 };
77
78 static struct dasd_vollabel dasd_vollabels[] = {
79         [DASD_VOLLBL_TYPE_VOL1] = {
80                 .type = "VOL1",
81                 .idx = DASD_VOLLBL_TYPE_VOL1,
82         },
83         [DASD_VOLLBL_TYPE_LNX1] = {
84                 .type = "LNX1",
85                 .idx = DASD_VOLLBL_TYPE_LNX1,
86         },
87         [DASD_VOLLBL_TYPE_CMS1] = {
88                 .type = "CMS1",
89                 .idx = DASD_VOLLBL_TYPE_CMS1,
90         },
91 };
92
93 static int get_label_by_type(const char *type)
94 {
95         int i;
96
97         for (i = 0; i < ARRAY_SIZE(dasd_vollabels); i++) {
98                 if (!memcmp(type, dasd_vollabels[i].type, DASD_VOL_TYPE_LEN))
99                         return dasd_vollabels[i].idx;
100         }
101
102         return -1;
103 }
104
105 static int find_label(struct parsed_partitions *state,
106                       dasd_information2_t *info,
107                       struct hd_geometry *geo,
108                       int blocksize,
109                       sector_t *labelsect,
110                       char name[],
111                       char type[],
112                       union label_t *label)
113 {
114         sector_t testsect[3];
115         int i, testcount;
116         Sector sect;
117         void *data;
118
119         /* There a three places where we may find a valid label:
120          * - on an ECKD disk it's block 2
121          * - on an FBA disk it's block 1
122          * - on an CMS formatted FBA disk it is sector 1, even if the block size
123          *   is larger than 512 bytes (possible if the DIAG discipline is used)
124          * If we have a valid info structure, then we know exactly which case we
125          * have, otherwise we just search through all possebilities.
126          */
127         if (info) {
128                 if ((info->cu_type == 0x6310 && info->dev_type == 0x9336) ||
129                     (info->cu_type == 0x3880 && info->dev_type == 0x3370))
130                         testsect[0] = info->label_block;
131                 else
132                         testsect[0] = info->label_block * (blocksize >> 9);
133                 testcount = 1;
134         } else {
135                 testsect[0] = 1;
136                 testsect[1] = (blocksize >> 9);
137                 testsect[2] = 2 * (blocksize >> 9);
138                 testcount = 3;
139         }
140         for (i = 0; i < testcount; ++i) {
141                 data = read_part_sector(state, testsect[i], &sect);
142                 if (data == NULL)
143                         continue;
144                 memcpy(label, data, sizeof(*label));
145                 memcpy(type, data, DASD_VOL_TYPE_LEN);
146                 EBCASC(type, DASD_VOL_TYPE_LEN);
147                 put_dev_sector(sect);
148                 switch (get_label_by_type(type)) {
149                 case DASD_VOLLBL_TYPE_VOL1:
150                         memcpy(name, label->vol.volid, DASD_VOL_ID_LEN);
151                         EBCASC(name, DASD_VOL_ID_LEN);
152                         *labelsect = testsect[i];
153                         return 1;
154                 case DASD_VOLLBL_TYPE_LNX1:
155                 case DASD_VOLLBL_TYPE_CMS1:
156                         memcpy(name, label->lnx.volid, DASD_VOL_ID_LEN);
157                         EBCASC(name, DASD_VOL_ID_LEN);
158                         *labelsect = testsect[i];
159                         return 1;
160                 default:
161                         break;
162                 }
163         }
164
165         return 0;
166 }
167
168 static int find_vol1_partitions(struct parsed_partitions *state,
169                                 struct hd_geometry *geo,
170                                 int blocksize,
171                                 char name[],
172                                 union label_t *label)
173 {
174         sector_t blk;
175         int counter;
176         char tmp[64];
177         Sector sect;
178         unsigned char *data;
179         loff_t offset, size;
180         struct vtoc_format1_label f1;
181         int secperblk;
182
183         snprintf(tmp, sizeof(tmp), "VOL1/%8s:", name);
184         strlcat(state->pp_buf, tmp, PAGE_SIZE);
185         /*
186          * get start of VTOC from the disk label and then search for format1
187          * and format8 labels
188          */
189         secperblk = blocksize >> 9;
190         blk = cchhb2blk(&label->vol.vtoc, geo) + 1;
191         counter = 0;
192         data = read_part_sector(state, blk * secperblk, &sect);
193         while (data != NULL) {
194                 memcpy(&f1, data, sizeof(struct vtoc_format1_label));
195                 put_dev_sector(sect);
196                 /* skip FMT4 / FMT5 / FMT7 labels */
197                 if (f1.DS1FMTID == _ascebc['4']
198                     || f1.DS1FMTID == _ascebc['5']
199                     || f1.DS1FMTID == _ascebc['7']
200                     || f1.DS1FMTID == _ascebc['9']) {
201                         blk++;
202                         data = read_part_sector(state, blk * secperblk, &sect);
203                         continue;
204                 }
205                 /* only FMT1 and 8 labels valid at this point */
206                 if (f1.DS1FMTID != _ascebc['1'] &&
207                     f1.DS1FMTID != _ascebc['8'])
208                         break;
209                 /* OK, we got valid partition data */
210                 offset = cchh2blk(&f1.DS1EXT1.llimit, geo);
211                 size  = cchh2blk(&f1.DS1EXT1.ulimit, geo) -
212                         offset + geo->sectors;
213                 offset *= secperblk;
214                 size *= secperblk;
215                 if (counter >= state->limit)
216                         break;
217                 put_partition(state, counter + 1, offset, size);
218                 counter++;
219                 blk++;
220                 data = read_part_sector(state, blk * secperblk, &sect);
221         }
222         strlcat(state->pp_buf, "\n", PAGE_SIZE);
223
224         if (!data)
225                 return -1;
226
227         return 1;
228 }
229
230 static int find_lnx1_partitions(struct parsed_partitions *state,
231                                 struct hd_geometry *geo,
232                                 int blocksize,
233                                 char name[],
234                                 union label_t *label,
235                                 sector_t labelsect,
236                                 sector_t nr_sectors,
237                                 dasd_information2_t *info)
238 {
239         loff_t offset, geo_size, size;
240         char tmp[64];
241         int secperblk;
242
243         snprintf(tmp, sizeof(tmp), "LNX1/%8s:", name);
244         strlcat(state->pp_buf, tmp, PAGE_SIZE);
245         secperblk = blocksize >> 9;
246         if (label->lnx.ldl_version == 0xf2) {
247                 size = label->lnx.formatted_blocks * secperblk;
248         } else {
249                 /*
250                  * Formated w/o large volume support. If the sanity check
251                  * 'size based on geo == size based on nr_sectors' is true, then
252                  * we can safely assume that we know the formatted size of
253                  * the disk, otherwise we need additional information
254                  * that we can only get from a real DASD device.
255                  */
256                 geo_size = geo->cylinders * geo->heads
257                         * geo->sectors * secperblk;
258                 size = nr_sectors;
259                 if (size != geo_size) {
260                         if (!info) {
261                                 strlcat(state->pp_buf, "\n", PAGE_SIZE);
262                                 return 1;
263                         }
264                         if (!strcmp(info->type, "ECKD"))
265                                 if (geo_size < size)
266                                         size = geo_size;
267                         /* else keep size based on nr_sectors */
268                 }
269         }
270         /* first and only partition starts in the first block after the label */
271         offset = labelsect + secperblk;
272         put_partition(state, 1, offset, size - offset);
273         strlcat(state->pp_buf, "\n", PAGE_SIZE);
274         return 1;
275 }
276
277 static int find_cms1_partitions(struct parsed_partitions *state,
278                                 struct hd_geometry *geo,
279                                 int blocksize,
280                                 char name[],
281                                 union label_t *label,
282                                 sector_t labelsect)
283 {
284         loff_t offset, size;
285         char tmp[64];
286         int secperblk;
287
288         /*
289          * VM style CMS1 labeled disk
290          */
291         blocksize = label->cms.block_size;
292         secperblk = blocksize >> 9;
293         if (label->cms.disk_offset != 0) {
294                 snprintf(tmp, sizeof(tmp), "CMS1/%8s(MDSK):", name);
295                 strlcat(state->pp_buf, tmp, PAGE_SIZE);
296                 /* disk is reserved minidisk */
297                 offset = label->cms.disk_offset * secperblk;
298                 size = (label->cms.block_count - 1) * secperblk;
299         } else {
300                 snprintf(tmp, sizeof(tmp), "CMS1/%8s:", name);
301                 strlcat(state->pp_buf, tmp, PAGE_SIZE);
302                 /*
303                  * Special case for FBA devices:
304                  * If an FBA device is CMS formatted with blocksize > 512 byte
305                  * and the DIAG discipline is used, then the CMS label is found
306                  * in sector 1 instead of block 1. However, the partition is
307                  * still supposed to start in block 2.
308                  */
309                 if (labelsect == 1)
310                         offset = 2 * secperblk;
311                 else
312                         offset = labelsect + secperblk;
313                 size = label->cms.block_count * secperblk;
314         }
315
316         put_partition(state, 1, offset, size-offset);
317         strlcat(state->pp_buf, "\n", PAGE_SIZE);
318         return 1;
319 }
320
321
322 /*
323  * This is the main function, called by check.c
324  */
325 int ibm_partition(struct parsed_partitions *state)
326 {
327         int (*fn)(struct gendisk *disk, dasd_information2_t *info);
328         struct gendisk *disk = state->disk;
329         struct block_device *bdev = disk->part0;
330         int blocksize, res;
331         loff_t offset, size;
332         sector_t nr_sectors;
333         dasd_information2_t *info;
334         struct hd_geometry *geo;
335         char type[DASD_VOL_TYPE_LEN + 1] = "";
336         char name[DASD_VOL_ID_LEN + 1] = "";
337         sector_t labelsect;
338         union label_t *label;
339
340         res = 0;
341         if (!disk->fops->getgeo)
342                 goto out_exit;
343         fn = symbol_get(dasd_biodasdinfo);
344         blocksize = bdev_logical_block_size(bdev);
345         if (blocksize <= 0)
346                 goto out_symbol;
347         nr_sectors = bdev_nr_sectors(bdev);
348         if (nr_sectors == 0)
349                 goto out_symbol;
350         info = kmalloc(sizeof(dasd_information2_t), GFP_KERNEL);
351         if (info == NULL)
352                 goto out_symbol;
353         geo = kmalloc(sizeof(struct hd_geometry), GFP_KERNEL);
354         if (geo == NULL)
355                 goto out_nogeo;
356         label = kmalloc(sizeof(union label_t), GFP_KERNEL);
357         if (label == NULL)
358                 goto out_nolab;
359         /* set start if not filled by getgeo function e.g. virtblk */
360         geo->start = get_start_sect(bdev);
361         if (disk->fops->getgeo(bdev, geo))
362                 goto out_freeall;
363         if (!fn || fn(disk, info)) {
364                 kfree(info);
365                 info = NULL;
366         }
367
368         if (find_label(state, info, geo, blocksize, &labelsect, name, type, label)) {
369                 switch (get_label_by_type(type)) {
370                 case DASD_VOLLBL_TYPE_VOL1:
371                         res = find_vol1_partitions(state, geo, blocksize, name,
372                                                    label);
373                         break;
374                 case DASD_VOLLBL_TYPE_LNX1:
375                         res = find_lnx1_partitions(state, geo, blocksize, name,
376                                                    label, labelsect, nr_sectors,
377                                                    info);
378                         break;
379                 case DASD_VOLLBL_TYPE_CMS1:
380                         res = find_cms1_partitions(state, geo, blocksize, name,
381                                                    label, labelsect);
382                         break;
383                 }
384         } else if (info) {
385                 /*
386                  * ugly but needed for backward compatibility:
387                  * If the block device is a DASD (i.e. BIODASDINFO2 works),
388                  * then we claim it in any case, even though it has no valid
389                  * label. If it has the LDL format, then we simply define a
390                  * partition as if it had an LNX1 label.
391                  */
392                 res = 1;
393                 if (info->format == DASD_FORMAT_LDL) {
394                         strlcat(state->pp_buf, "(nonl)", PAGE_SIZE);
395                         size = nr_sectors;
396                         offset = (info->label_block + 1) * (blocksize >> 9);
397                         put_partition(state, 1, offset, size-offset);
398                         strlcat(state->pp_buf, "\n", PAGE_SIZE);
399                 }
400         } else
401                 res = 0;
402
403 out_freeall:
404         kfree(label);
405 out_nolab:
406         kfree(geo);
407 out_nogeo:
408         kfree(info);
409 out_symbol:
410         if (fn)
411                 symbol_put(dasd_biodasdinfo);
412 out_exit:
413         return res;
414 }