patch-2.4.2 linux/drivers/s390/block/mdisk.c
Next file: linux/drivers/s390/block/mdisk.h
Previous file: linux/drivers/s390/block/dasd_types.h
Back to the patch index
Back to the overall index
- Lines: 791
- Date:
Wed Dec 31 16:00:00 1969
- Orig file:
v2.4.1/linux/drivers/s390/block/mdisk.c
- Orig date:
Thu Oct 26 23:35:48 2000
diff -u --recursive --new-file v2.4.1/linux/drivers/s390/block/mdisk.c linux/drivers/s390/block/mdisk.c
@@ -1,790 +0,0 @@
-/*
- * 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__ int
-dia250(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__ int
-mdisk_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__ int
-mdisk_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__ int
-mdisk_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__ int
-dia210(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__ int
-mdisk_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;
- devchar.rdc_len = sizeof(mdisk_dev_char_t);
-
- if (dia210(&devchar) == 0) {
- if (devchar.vdev_class == DEV_CLASS_FBA) {
- block = 2;
- }
- else {
- block = 3;
- }
- bio = dev->bio;
- for (b=512;b<4097;b=b*2) {
- rc = mdisk_init_io(dev, b, 0, 64);
- if (rc > 4) {
- continue;
- }
- memset(&bio[0], 0, sizeof(mdisk_bio_t));
- bio[0].type = MDISK_READ_REQ;
- bio[0].block_number = block;
- bio[0].buffer = virt_to_phys(&label);
- dev->nr_bhs = 1;
- if (mdisk_rw_io_clustered(dev,
- &bio[0],
- 1,
- (unsigned long) dev,
- MDISK_SYNC)
- == 0 ) {
- if (label[0] != 0xc3d4e2f1) { /* CMS1 */
- printk ( KERN_WARNING "mnd: %4lX "
- "is not CMS format\n",
- mdisk_setup_data.vdev[i]);
- rc = mdisk_term_io(dev);
- return 1;
- }
- if (label[13] == 0) {
- printk ( KERN_WARNING "mnd: %4lX "
- "is not reserved\n",
- mdisk_setup_data.vdev[i]);
- rc = mdisk_term_io(dev);
- return 2;
- }
- mdisk_setup_data.size[i] =
- (label[7] - 1 - label[13]) *
- (label[3] >> 9) >> 1;
- mdisk_setup_data.blksize[i] = label[3];
- mdisk_setup_data.offset[i] = label[13] + 1;
- rc = mdisk_term_io(dev);
- return rc;
- }
- rc = mdisk_term_io(dev);
- }
- printk ( KERN_WARNING "mnd: Cannot read label of %4lX "
- "- is it formatted?\n",
- mdisk_setup_data.vdev[i]);
- return 3;
- }
- return 4;
-}
-
-
-
-
-
-/*
- * this handles a clustered request in success case
- * all buffers are detach and marked uptodate to the kernel
- * then CURRENT->bh is set to the last processed but not
- * update buffer
- */
-
-static __inline__ void
-mdisk_end_request(int nr_bhs)
-{
- int i;
- struct buffer_head *bh;
- struct request *req;
-
- if (nr_bhs > 1) {
- req = CURRENT;
- bh = req->bh;
-
- for (i=0; i < nr_bhs-1; i++) {
- req->bh = bh->b_reqnext;
- bh->b_reqnext = NULL;
- bh->b_end_io(bh,1);
- bh = req->bh;
- }
-
- /*
- * set CURRENT to last processed, not marked buffer
- */
- req->buffer = bh->b_data;
- req->current_nr_sectors = bh->b_size >> 9;
- CURRENT = req;
- }
- end_request(1);
-}
-
-
-
-/*
- * Block-driver specific functions
- */
-
-void mdisk_request(request_queue_t *queue)
-{
- mdisk_Dev *dev;
- mdisk_bio_t *bio;
- struct buffer_head *bh;
- unsigned int sector, nr, offset;
- int rc,rw,i;
-
- i = 0;
- while(CURRENT) {
- INIT_REQUEST;
-
- /* Check if the minor number is in range */
- if (DEVICE_NR(CURRENT_DEV) > MDISK_DEVS) {
- static int count = 0;
- if (count++ < 5) /* print the message at most five times */
- printk(KERN_WARNING "mnd: request for minor %d out of range\n",
- DEVICE_NR(CURRENT_DEV) ) ;
- end_request(0);
- continue;
- }
-
- /*
- * Pointer to device structure, from the static array
- */
- dev = mdisk_devices + DEVICE_NR(CURRENT_DEV);
-
- /*
- * check, if operation is past end of devices
- */
- if (CURRENT->nr_sectors + CURRENT->sector > dev->size) {
- static int count = 0;
- if (count++ < 5)
- printk(KERN_WARNING "mnd%c: request past end of device\n",
- DEVICE_NR(CURRENT_DEV));
- end_request(0);
- continue;
- }
-
- /*
- * do command (read or write)
- */
- switch(CURRENT->cmd) {
- case READ:
- rw = MDISK_READ_REQ;
- break;
- case WRITE:
- rw = MDISK_WRITE_REQ;
- break;
- default:
- /* can't happen */
- end_request(0);
- continue;
- }
-
- /*
- * put the clustered requests in mdisk_bio array
- * nr_sectors is checked against max_sectors in make_request
- * nr_sectors and sector are always blocks of 512
- * but bh_size depends on the filesystems size
- */
- sector = CURRENT->sector>>dev->blkshift;
- bh = CURRENT->bh;
- bio = dev->bio;
- dev->nr_bhs = 0;
-
- /*
- * sector is translated to block in minidisk context
- *
- */
- offset = 0;
-
-
-
- for (nr = 0,i = 0;
- nr < CURRENT->nr_sectors && bh;
- nr+=dev->blkmult, sector++,i++) {
- memset(&bio[i], 0, sizeof(mdisk_bio_t));
- bio[i].type = rw;
- bio[i].block_number = sector;
- bio[i].buffer = virt_to_phys(bh->b_data+offset);
- offset += dev->blksize;
- if (bh->b_size <= offset) {
- offset = 0;
- bh = bh->b_reqnext;
- dev->nr_bhs++;
- }
- }
-
- if (( rc = mdisk_rw_io_clustered(dev, &bio[0], i,
- (unsigned long) dev,
-#ifdef CONFIG_MDISK_SYNC
- MDISK_SYNC
-#else
- MDISK_ASYNC
-#endif
- )) > 8 ) {
- printk(KERN_WARNING "mnd%c: %s request failed rc %d"
- " sector %ld nr_sectors %ld \n",
- DEVICE_NR(CURRENT_DEV),
- rw == MDISK_READ_REQ ? "read" : "write",
- rc, CURRENT->sector, CURRENT->nr_sectors);
- end_request(0);
- continue;
- }
- i = 0;
- /*
- * Synchron: looping to end of request (INIT_REQUEST has return)
- * Asynchron: end_request done in bottom half
- */
-#ifdef CONFIG_MDISK_SYNC
- mdisk_end_request(dev->nr_bhs);
-#else
- if (rc == 0)
- mdisk_end_request(dev->nr_bhs);
- else
- return;
-#endif
- }
-}
-
-
-/*
- * mdisk interrupt handler called when read/write request finished
- * queues and marks a bottom half.
- *
- */
-void do_mdisk_interrupt(void)
-{
- u16 code;
- mdisk_Dev *dev;
-
- code = S390_lowcore.cpu_addr;
-
- if ((code >> 8) != 0x03) {
- printk("mnd: wrong sub-interruption code %d",code>>8);
- return;
- }
-
- /*
- * pointer to devives structure given as external interruption
- * parameter
- */
- dev = (mdisk_Dev*) S390_lowcore.ext_params;
- dev->status = code & 0x00ff;
-
- queue_task(&dev->tqueue, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
-}
-
-/*
- * the bottom half checks the status of request
- * on success it calls end_request and calls mdisk_request
- * if more transfer to do
- */
-
-static void
-do_mdisk_bh(void *data)
-{
- mdisk_Dev *dev = (mdisk_Dev*) data;
- unsigned long flags;
-
- spin_lock_irqsave(&io_request_lock, flags);
- /*
- * check for status of asynchronous rw
- */
- if (dev->status != 0x00) {
- printk("mnd: status of async rw %d",dev->status);
- end_request(0);
- } else {
- /*
- * end request for clustered requests
- */
- if (CURRENT)
- mdisk_end_request(dev->nr_bhs);
- }
-
- /*
- * if more to do, call mdisk_request
- */
- if (CURRENT)
- mdisk_request(NULL);
- spin_unlock_irqrestore(&io_request_lock, flags);
-}
-
-void /* Added fuction HSM 12/03/99 */
-mdisk_handler (int cpu, void *ds, struct pt_regs *regs)
-{
- printk (KERN_ERR "mnd: received I/O interrupt... shouldn't happen\n");
-}
-
-int __init mdisk_init(void)
-{
- int rc,i;
- mdisk_Dev *dev;
- request_queue_t *q;
-
- /*
- * register block device
- */
- if (register_blkdev(MAJOR_NR,"mnd",&mdisk_fops) < 0) {
- printk("mnd: unable to get major %d for mini disk\n"
- ,MAJOR_NR);
- return MAJOR_NR;
- }
- q = BLK_DEFAULT_QUEUE(MAJOR_NR);
- blk_init_queue(q, mdisk_request);
- blk_queue_headactive(BLK_DEFAULT_QUEUE(major), 0);
-
- /*
- * setup sizes for available devices
- */
- read_ahead[MAJOR_NR] = MDISK_RAHEAD; /* 8 sector (4kB) read-ahead */
- blk_size[MAJOR_NR] = mdisk_sizes; /* size of reserved mdisk */
- blksize_size[MAJOR_NR] = mdisk_blksizes; /* blksize of device */
- hardsect_size[MAJOR_NR] = mdisk_hardsects;
- max_sectors[MAJOR_NR] = mdisk_maxsectors;
- blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
-
- for (i=0;i<MDISK_DEVS;i++) {
- if (mdisk_setup_data.vdev[i] == 0) {
- continue;
- }
- /* Added block HSM 12/03/99 */
- if ( request_irq(get_irq_by_devno(mdisk_setup_data.vdev[i]),
- mdisk_handler, 0, "mnd",
- &(mdisk_devices[i].dev_status)) ){
- printk ( KERN_WARNING "mnd: Cannot acquire I/O irq of"
- " %4lX for paranoia reasons, skipping\n",
- mdisk_setup_data.vdev[i]);
- continue;
- }
- /*
- * open VM minidisk low level device
- */
- dev = &mdisk_devices[i];
- dev->bio=mdisk_bio[i];
- dev->iob=&mdisk_iob[i];
- dev->vdev = mdisk_setup_data.vdev[i];
-
- if ( mdisk_setup_data.size[i] == 0 )
- rc = mdisk_read_label(dev, i);
- dev->size = mdisk_setup_data.size[i] * 2; /* buffer 512 b */
- dev->blksize = mdisk_setup_data.blksize[i];
- dev->tqueue.routine = do_mdisk_bh;
- dev->tqueue.data = dev;
- dev->blkmult = dev->blksize/512;
- dev->blkshift =
- dev->blkmult==1?0:
- dev->blkmult==2?1:
- dev->blkmult==4?2:
- dev->blkmult==8?3:-1;
-
- mdisk_sizes[i] = mdisk_setup_data.size[i];
- mdisk_blksizes[i] = mdisk_setup_data.blksize[i];
- mdisk_hardsects[i] = mdisk_setup_data.blksize[i];
-
- /*
- * max sectors for one clustered req
- */
- mdisk_maxsectors[i] = MDISK_MAXSECTORS*dev->blkmult;
-
- rc = mdisk_init_io(dev,
- mdisk_setup_data.blksize[i],
- mdisk_setup_data.offset[i],/* offset in vdev*/
- dev->size>>dev->blkshift /* size in blocks */
- );
- if (rc > 4) {
- printk("mnd%c: init failed (rc: %d)\n",'a'+i,rc);
- mdisk_sizes[i] = 0;
- continue;
- }
-
- /*
- * set vdev in device structure for further rw access
- * vdev and size given by linload
- */
- printk("mnd%c: register device at major %X with %d blocks %d blksize \n",
- 'a' + i, MAJOR_NR, dev->size>>dev->blkshift,dev->blkmult*512);
- }
-
- /*
- * enable service-signal external interruptions,
- * Control Register 0 bit 22 := 1
- * (besides PSW bit 7 must be set to 1 somewhere for external
- * interruptions)
- */
- ctl_set_bit(0, 9);
-
- return 0;
-}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)