📄 mdisk.c
字号:
/* * drivers/s390/block/mdisk.c * VM minidisk device driver. * * S390 version * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Hartmut Penner (hp@de.ibm.com) */#ifndef __KERNEL__# define __KERNEL__#endif#define __NO_VERSION__#include <linux/config.h>#include <linux/version.h>char kernel_version [] = UTS_RELEASE;#include <linux/module.h>#include <linux/sched.h>#include <linux/kernel.h> /* printk() */#include <linux/malloc.h> /* kmalloc() */#include <linux/vmalloc.h> /* vmalloc() */#include <linux/fs.h> /* everything... */#include <linux/errno.h> /* error codes */#include <linux/timer.h>#include <linux/types.h> /* size_t */#include <linux/fcntl.h> /* O_ACCMODE */#include <linux/hdreg.h> /* HDIO_GETGEO */#include <linux/init.h> /* initfunc */#include <linux/interrupt.h>#include <linux/ctype.h>#include <asm/system.h> /* cli(), *_flags */#include <asm/uaccess.h> /* access_ok */#include <asm/io.h> /* virt_to_phys */ /* Added statement HSM 12/03/99 */#include <asm/irq.h>#define MAJOR_NR MDISK_MAJOR /* force definitions on in blk.h */#include <linux/blk.h>#include "mdisk.h" /* local definitions *//* * structure for all device specific information */typedef struct mdisk_Dev { u32 vdev; /* vdev of mindisk */ u32 size; /* size in blocks */ u32 status; /* status of last io operation */ u32 nr_bhs; /* number of buffer of last io operation */ u32 blksize; /* blksize from minidisk */ u32 blkmult; /* multiplier between blksize and 512 HARDSECT */ u32 blkshift; /* loe2 of multiplier above */ /* * each device has own iob and bio, * it's possible to run io in parallel * not used yet due to only one CURRENT per MAJOR */ mdisk_rw_io_t* iob; /* each device has it own iob and bio */ mdisk_bio_t* bio; /* Added statement HSM 12/03/99 */ devstat_t dev_status; /* Here we hold the I/O status */ int usage; /* usage counter */ struct tq_struct tqueue; /* per device task queue */} mdisk_Dev;/* * appended to global structures in mdisk_init; */static int mdisk_blksizes[MDISK_DEVS];static int mdisk_sizes[MDISK_DEVS] = { 0 };static int mdisk_hardsects[MDISK_DEVS];static int mdisk_maxsectors[MDISK_DEVS];/* * structure hold device specific information */static mdisk_Dev mdisk_devices[MDISK_DEVS];static mdisk_rw_io_t mdisk_iob[MDISK_DEVS] __attribute__ ((aligned(8)));static mdisk_bio_t mdisk_bio[MDISK_DEVS][256]__attribute__ ((aligned(8)));/* * Parameter parsing */struct { long vdev[MDISK_DEVS]; long size[MDISK_DEVS]; long offset[MDISK_DEVS]; long blksize[MDISK_DEVS];} mdisk_setup_data;/* * Parameter parsing function, called from init/main.c * vdev : virtual device number * size : size in kbyte * offset : offset after which minidisk is available * blksize : blocksize minidisk is formated * Format is: mdisk=<vdev>:<size>:<offset>:<blksize>,<vdev>:<size>:<offset>... * <vdev>:<size>:<offset>:<blksize> can be shortened to <vdev>:<size> with offset=0,blksize=512 */int __init mdisk_setup(char *str){ char *cur = str; int vdev, size, offset=0,blksize; static int i = 0; if (!i) memset(&mdisk_setup_data,0,sizeof(mdisk_setup_data)); while (*cur != 0) { blksize=MDISK_HARDSECT; vdev = size = offset = 0; if (!isxdigit(*cur)) goto syntax_error; vdev = simple_strtoul(cur,&cur,16); if (*cur != 0 && *cur != ',') { if (*cur++ != ':') goto syntax_error; if (!isxdigit(*cur)) goto syntax_error; size = simple_strtoul(cur,&cur,16); if (*cur == ':') { /* another colon -> offset specified */ cur++; if (!isxdigit(*cur)) goto syntax_error; offset = simple_strtoul(cur,&cur,16); if (*cur == ':') { /* another colon -> blksize */ cur++; if (!isxdigit(*cur)) goto syntax_error; blksize = simple_strtoul(cur,&cur,16); } } if (*cur != ',' && *cur != 0) goto syntax_error; } if (*cur == ',') cur++; if (i >= MDISK_DEVS) { printk(KERN_WARNING "mnd: too many devices\n"); return 1; } mdisk_setup_data.vdev[i] = vdev; mdisk_setup_data.size[i] = size; mdisk_setup_data.offset[i] = offset; mdisk_setup_data.blksize[i] = blksize; i++; } return 1;syntax_error: printk(KERN_WARNING "mnd: syntax error in parameter string: %s\n", str); return 0;}__setup("mdisk=", mdisk_setup);/* * Open and close */static int mdisk_open (struct inode *inode, struct file *filp){ mdisk_Dev *dev; /* device information */ int num = MINOR(inode->i_rdev); /* * size 0 means device not installed */ if ((num >= MDISK_DEVS) || (mdisk_sizes[num] == 0)) return -ENODEV; MOD_INC_USE_COUNT; dev = &mdisk_devices[num]; dev->usage++; return 0; /* success */}static int mdisk_release (struct inode *inode, struct file *filp){ mdisk_Dev *dev = &mdisk_devices[MINOR(inode->i_rdev)]; /* * flush device */ fsync_dev(inode->i_rdev); dev->usage--; MOD_DEC_USE_COUNT; return 0;}/* * The mdisk() implementation */static int mdisk_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){ int err,rc, size=0; struct hd_geometry *geo = (struct hd_geometry *)arg; mdisk_Dev *dev = mdisk_devices + MINOR(inode->i_rdev); switch(cmd) { case BLKGETSIZE: rc = copy_to_user ((long *) arg, &dev->size, sizeof (long)); printk(KERN_WARNING "mnd: ioctl BLKGETSIZE %d\n",dev->size); return rc; case BLKFLSBUF: /* flush */ if (!suser()) return -EACCES; /* only root */ fsync_dev(inode->i_rdev); invalidate_buffers(inode->i_rdev); return 0; case BLKRAGET: /* return the readahead value */ if (!arg) return -EINVAL; err = access_ok(VERIFY_WRITE, (long *) arg, sizeof(long)); if (err) return err; put_user(read_ahead[MAJOR(inode->i_rdev)],(long *) arg); return 0; case BLKRASET: /* set the readahead value */ if (!suser()) return -EACCES; if (arg > 0xff) return -EINVAL; /* limit it */ read_ahead[MAJOR(inode->i_rdev)] = arg; return 0; case BLKRRPART: /* re-read partition table: can't do it */ return -EINVAL; case HDIO_GETGEO: /* * get geometry of device -> linear */ size = dev->size; if (geo==NULL) return -EINVAL; err = access_ok(VERIFY_WRITE, geo, sizeof(*geo)); if (err) return err; put_user(1, &geo->cylinders); put_user(1, &geo->heads); put_user(size, &geo->sectors); put_user(0, &geo->start); return 0; } return -EINVAL; /* unknown command */}/* * The file operations */static struct block_device_operations mdisk_fops = { ioctl: mdisk_ioctl, open: mdisk_open, release: mdisk_release,};/* * The 'low level' IO function */static __inline__ intdia250(void* iob,int cmd){ int rc; iob = (void*) virt_to_phys(iob); asm volatile (" lr 2,%1\n" " lr 3,%2\n" " .long 0x83230250\n" " lr %0,3" : "=d" (rc) : "d" (iob) , "d" (cmd) : "2", "3" ); return rc;}/* * Init of minidisk device */static __inline__ intmdisk_init_io(mdisk_Dev *dev,int blocksize,int offset,int size){ mdisk_init_io_t *iob = (mdisk_init_io_t*) dev->iob; int rc; memset(iob,0,sizeof(mdisk_init_io_t)); iob->dev_nr = dev->vdev; iob->block_size = blocksize; iob->offset = offset; iob->start_block= 0; iob->end_block = size; rc = dia250(iob,INIT_BIO); /* * clear for following io once */ memset(iob,0,sizeof(mdisk_rw_io_t)); return rc;}/* * release of minidisk device */static __inline__ intmdisk_term_io(mdisk_Dev *dev){ mdisk_init_io_t *iob = (mdisk_init_io_t*) dev->iob; memset(iob,0,sizeof(mdisk_init_io_t)); iob->dev_nr = dev->vdev; return dia250(iob,TERM_BIO);}/* * setup and start of minidisk io request */static __inline__ intmdisk_rw_io_clustered (mdisk_Dev *dev, mdisk_bio_t* bio_array, int length, int req, int sync){ int rc; mdisk_rw_io_t *iob = dev->iob; iob->dev_nr = dev->vdev; iob->key = 0; iob->flags = sync; iob->block_count = length; iob->interrupt_params = req; iob->bio_list = virt_to_phys(bio_array); rc = dia250(iob,RW_BIO); return rc;}/* * The device characteristics function */static __inline__ intdia210(void* devchar){ int rc; devchar = (void*) virt_to_phys(devchar); asm volatile (" lr 2,%1\n" " .long 0x83200210\n" " ipm %0\n" " srl %0,28" : "=d" (rc) : "d" (devchar) : "2" ); return rc;}/* * read the label of a minidisk and extract its characteristics */static __inline__ intmdisk_read_label (mdisk_Dev *dev, int i){ static mdisk_dev_char_t devchar; static long label[1024]; int block, b; int rc; mdisk_bio_t *bio; devchar.dev_nr = dev -> vdev;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -