linux-old/fs/partitions/ibm.c
<<
>>
Prefs
   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 * History of changes (starts July 2000)
   9 * 07/10/00 Fixed detection of CMS formatted disks     
  10 * 02/13/00 VTOC partition support added
  11 * 12/27/01 fixed PL030593 (CMS reserved minidisk not detected on 64 bit)
  12 * 07/24/03 no longer using contents of freed page for CMS label recognition (BZ3611)
  13 */
  14
  15#include <linux/config.h>
  16#include <linux/fs.h>
  17#include <linux/genhd.h>
  18#include <linux/kernel.h>
  19#include <linux/major.h>
  20#include <linux/string.h>
  21#include <linux/blk.h>
  22#include <linux/slab.h>
  23#include <linux/hdreg.h>
  24#include <linux/ioctl.h>
  25#include <linux/version.h>
  26#include <asm/ebcdic.h>
  27#include <asm/uaccess.h>
  28#include <asm/dasd.h>
  29
  30#include "ibm.h"
  31#include "check.h"
  32#include <asm/vtoc.h>
  33
  34/*
  35 * compute the block number from a 
  36 * cyl-cyl-head-head structure
  37 */
  38static inline int
  39cchh2blk (cchh_t *ptr, struct hd_geometry *geo) {
  40        return ptr->cc * geo->heads * geo->sectors +
  41               ptr->hh * geo->sectors;
  42}
  43
  44
  45/*
  46 * compute the block number from a 
  47 * cyl-cyl-head-head-block structure
  48 */
  49static inline int
  50cchhb2blk (cchhb_t *ptr, struct hd_geometry *geo) {
  51        return ptr->cc * geo->heads * geo->sectors +
  52                ptr->hh * geo->sectors +
  53                ptr->b;
  54}
  55
  56/*
  57 * We used to use ioctl_by_bdev in early 2.4, but it broke
  58 * between 2.4.9 and 2.4.18 somewhere.
  59 */
  60extern int (*genhd_dasd_ioctl)(struct inode *inp, struct file *filp,
  61                            unsigned int no, unsigned long data);
  62
  63static int
  64ibm_ioctl_unopened(struct block_device *bdev, unsigned cmd, unsigned long arg)
  65{
  66        int res;
  67        mm_segment_t old_fs = get_fs();
  68
  69        if (genhd_dasd_ioctl == NULL)
  70                return -ENODEV;
  71#if 0
  72        lock_kernel();
  73        if (bd_ops->owner)
  74                __MOD_INC_USE_COUNT(bdev->bd_op->owner);
  75        unlock_kernel();
  76#endif
  77        set_fs(KERNEL_DS);
  78        res = (*genhd_dasd_ioctl)(bdev->bd_inode, NULL, cmd, arg);
  79        set_fs(old_fs);
  80#if 0
  81        lock_kernel();
  82        if (bd_ops->owner)
  83                __MOD_DEV_USE_COUNT(bd_ops->owner);
  84        unlock_kernel();
  85#endif
  86        return res;
  87}
  88
  89/*
  90 */
  91int 
  92ibm_partition(struct gendisk *hd, struct block_device *bdev,
  93              unsigned long first_sector, int first_part_minor)
  94{
  95        int blocksize, offset, size;
  96        dasd_information_t *info;
  97        struct hd_geometry *geo;
  98        char type[5] = {0,};
  99        char name[7] = {0,};
 100        volume_label_t *vlabel;
 101        unsigned char *data;
 102        Sector sect;
 103
 104        if ( first_sector != 0 )
 105                BUG();
 106
 107        if ((info = kmalloc(sizeof(dasd_information_t), GFP_KERNEL)) == NULL)
 108                goto out_noinfo;
 109        if ((geo = kmalloc(sizeof(struct hd_geometry), GFP_KERNEL)) == NULL)
 110                goto out_nogeo;
 111        if ((vlabel = kmalloc(sizeof(volume_label_t), GFP_KERNEL)) == NULL)
 112                goto out_novlab;
 113
 114        if (ibm_ioctl_unopened(bdev, BIODASDINFO, (unsigned long)info) != 0 ||
 115            ibm_ioctl_unopened(bdev, HDIO_GETGEO, (unsigned long)geo) != 0)
 116                goto out_noioctl;
 117
 118        if ((blocksize = get_hardsect_size(to_kdev_t(bdev->bd_dev))) <= 0)
 119                goto out_badsect;
 120
 121        /*
 122         * Get volume label, extract name and type.
 123         */
 124        data = read_dev_sector(bdev, info->label_block*(blocksize/512), &sect);
 125        if (data == NULL)
 126                goto out_readerr;
 127        strncpy (type, data, 4);
 128        if ((!info->FBA_layout) && (!strcmp(info->type, "ECKD")))
 129                strncpy(name, data + 8, 6);
 130        else
 131                strncpy(name, data + 4, 6);
 132        memcpy (vlabel, data, sizeof(volume_label_t));
 133        put_dev_sector(sect);
 134
 135        EBCASC(type, 4);
 136        EBCASC(name, 6);
 137
 138        /*
 139         * Three different types: CMS1, VOL1 and LNX1/unlabeled
 140         */
 141        if (strncmp(type, "CMS1", 4) == 0) {
 142                /*
 143                 * VM style CMS1 labeled disk
 144                 */
 145                int *label = (int *) vlabel;
 146
 147                if (label[13] != 0) {
 148                        printk("CMS1/%8s(MDSK):", name);
 149                        /* disk is reserved minidisk */
 150                        blocksize = label[3];
 151                        offset = label[13];
 152                        size = (label[7] - 1)*(blocksize >> 9);
 153                } else {
 154                        printk("CMS1/%8s:", name);
 155                        offset = (info->label_block + 1);
 156                        size = bdev->bd_inode->i_size >> 9;
 157                }
 158                // add_gd_partition(hd, first_part_minor - 1, 0, size);
 159                add_gd_partition(hd, first_part_minor,
 160                                 offset*(blocksize >> 9),
 161                                 size-offset*(blocksize >> 9));
 162        } else if ((strncmp(type, "VOL1", 4) == 0) &&
 163                (!info->FBA_layout) && (!strcmp(info->type, "ECKD"))) {
 164                /*
 165                 * New style VOL1 labeled disk
 166                 */
 167                unsigned int blk;
 168                int counter;
 169
 170                printk("VOL1/%8s:", name);
 171
 172                /* get block number and read then go through format1 labels */
 173                blk = cchhb2blk(&vlabel->vtoc, geo) + 1;
 174                counter = 0;
 175                while ((data = read_dev_sector(bdev, blk*(blocksize/512),
 176                                               &sect)) != NULL) {
 177                        format1_label_t f1;
 178
 179                        memcpy(&f1, data, sizeof(format1_label_t));
 180                        put_dev_sector(sect);
 181
 182                        /* skip FMT4 / FMT5 / FMT7 labels */
 183                        if (f1.DS1FMTID == _ascebc['4']
 184                            || f1.DS1FMTID == _ascebc['5']
 185                            || f1.DS1FMTID == _ascebc['7']) {
 186                                blk++;
 187                                continue;
 188                        }
 189
 190                        /* only FMT1 valid at this point */
 191                        if (f1.DS1FMTID != _ascebc['1'])
 192                                break;
 193
 194                        /* OK, we got valid partition data */
 195                        offset = cchh2blk(&f1.DS1EXT1.llimit, geo);
 196                        size  = cchh2blk(&f1.DS1EXT1.ulimit, geo) - 
 197                                offset + geo->sectors;
 198                        if (counter >= hd->max_p)
 199                                break;
 200                        add_gd_partition(hd, first_part_minor + counter, 
 201                                         offset * (blocksize >> 9),
 202                                         size * (blocksize >> 9));
 203                        counter++;
 204                        blk++;
 205                }
 206        } else {
 207                /*
 208                 * Old style LNX1 or unlabeled disk
 209                 */
 210                if (strncmp(type, "LNX1", 4) == 0)
 211                        printk ("LNX1/%8s:", name);
 212                else
 213                        printk("(nonl)/%8s:", name);
 214                offset = (info->label_block + 1);
 215                size = (bdev->bd_inode->i_size >> 9);
 216                // add_gd_partition(hd, first_part_minor - 1, 0, size);
 217                add_gd_partition(hd, first_part_minor,
 218                                 offset*(blocksize >> 9),
 219                                  size-offset*(blocksize >> 9));
 220        }
 221
 222        printk("\n");
 223        kfree(vlabel);
 224        kfree(geo);
 225        kfree(info);
 226        return 1;
 227
 228out_readerr:
 229out_badsect:
 230out_noioctl:
 231        kfree(vlabel);
 232out_novlab:
 233        kfree(geo);
 234out_nogeo:
 235        kfree(info);
 236out_noinfo:
 237        return 0;
 238}
 239
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.