dasd.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:131k
- fdata->start_unit, rc);
- break;
- }
- dasd_free_request (req, device); /* request is no longer used */
- if ( signal_pending(current) ) {
- rc = -ERESTARTSYS;
- break;
- }
- fdata->start_unit++;
- }
- return rc;
- } /* end dasd_format */
- static struct list_head dasd_ioctls = LIST_HEAD_INIT (dasd_ioctls);
- static dasd_ioctl_list_t *
- dasd_find_ioctl (int no)
- {
- struct list_head *curr;
- list_for_each (curr, &dasd_ioctls) {
- if (list_entry (curr, dasd_ioctl_list_t, list)->no == no) {
- return list_entry (curr, dasd_ioctl_list_t, list);
- }
- }
- return NULL;
- }
- int
- dasd_ioctl_no_register (struct module *owner, int no, dasd_ioctl_fn_t handler)
- {
- dasd_ioctl_list_t *new;
- if (dasd_find_ioctl (no))
- return -EBUSY;
- new = kmalloc (sizeof (dasd_ioctl_list_t), GFP_KERNEL);
- if (new == NULL)
- return -ENOMEM;
- new->owner = owner;
- new->no = no;
- new->handler = handler;
- list_add (&new->list, &dasd_ioctls);
- MOD_INC_USE_COUNT;
- return 0;
- }
- int
- dasd_ioctl_no_unregister (struct module *owner, int no, dasd_ioctl_fn_t handler)
- {
- dasd_ioctl_list_t *old = dasd_find_ioctl (no);
- if (old == NULL)
- return -ENOENT;
- if (old->no != no || old->handler != handler || owner != old->owner )
- return -EINVAL;
- list_del (&old->list);
- kfree (old);
- MOD_DEC_USE_COUNT;
- return 0;
- }
- static int
- dasd_revalidate (dasd_device_t * device)
- {
- int rc = 0;
- int i;
- kdev_t kdev = device->kdev;
- int openct = atomic_read (&device->open_count);
- int start = MINOR (kdev);
- if (openct != 1) {
- DASD_MESSAGE (KERN_WARNING, device, "%s",
- "BLKRRPART: device is open! expect errors.");
- }
- for (i = (1 << DASD_PARTN_BITS) - 1; i >= 0; i--) {
- int major = device->major_info->gendisk.major;
- invalidate_device(MKDEV (major, start+i), 1);
- }
- dasd_destroy_partitions(device);
- dasd_setup_partitions(device);
- return rc;
- }
- static int
- do_dasd_ioctl (struct inode *inp, /* unsigned */ int no, unsigned long data)
- {
- int rc = 0;
- dasd_device_t *device = dasd_device_from_kdev (inp->i_rdev);
- major_info_t *major_info;
- if (!device) {
- printk (KERN_WARNING PRINTK_HEADER
- "No device registered as device (%d:%d)n",
- MAJOR (inp->i_rdev),
- MINOR (inp->i_rdev));
- return -EINVAL;
- }
- if ((_IOC_DIR (no) != _IOC_NONE) && (data == 0)) {
- PRINT_DEBUG ("empty data ptr");
- return -EINVAL;
- }
- major_info = device->major_info;
- #if 0
- printk (KERN_DEBUG PRINTK_HEADER
- "ioctl 0x%08x %s'0x%x'%d(%d) on /dev/%s (%d:%d,"
- " devno 0x%04x on irq %d) with data %8lxn",
- no,
- _IOC_DIR (no) == _IOC_NONE ? "0" :
- _IOC_DIR (no) == _IOC_READ ? "r" :
- _IOC_DIR (no) == _IOC_WRITE ? "w" :
- _IOC_DIR (no) == (_IOC_READ | _IOC_WRITE) ? "rw" : "u",
- _IOC_TYPE (no),
- _IOC_NR (no),
- _IOC_SIZE (no),
- device->name,
- MAJOR (inp->i_rdev),
- MINOR (inp->i_rdev),
- device->devinfo.devno,
- device->devinfo.irq,
- data);
- #endif
- switch (no) {
- case DASDAPIVER: {
- int ver = DASD_API_VERSION;
- rc = put_user(ver, (int *) data);
- break;
- }
- case BLKGETSIZE:{ /* Return device size */
- long blocks = major_info->gendisk.sizes
- [MINOR (inp->i_rdev)] << 1;
- rc = put_user(blocks, (long *) data);
- break;
- }
- case BLKGETSIZE64:{
- u64 blocks = major_info->gendisk.sizes
- [MINOR (inp->i_rdev)];
- rc = put_user(blocks << 10, (u64 *) data);
- break;
- }
- case BLKRRPART:{
- if (!capable (CAP_SYS_ADMIN)) {
- rc = -EACCES;
- break;
- }
- rc = dasd_revalidate (device);
- break;
- }
- case HDIO_GETGEO:{
- struct hd_geometry geo = { 0, };
- rc = dasd_fillgeo (inp->i_rdev, &geo);
- if (rc)
- break;
- rc = copy_to_user ((struct hd_geometry *) data, &geo,
- sizeof (struct hd_geometry));
- if (rc)
- rc = -EFAULT;
- break;
- }
- case BIODASDDISABLE:{
- if (!capable (CAP_SYS_ADMIN)) {
- rc = -EACCES;
- break;
- }
- if ( device->level > DASD_STATE_ACCEPT) {
- dasd_deactivate_queue(device);
- if ( device->request_queue)
- dasd_flush_request_queues(device,0);
- dasd_flush_chanq(device,0);
- dasd_disable_blkdev(device);
- dasd_set_device_level (device->devinfo.devno,
- device->discipline,
- DASD_STATE_ACCEPT);
- }
- break;
- }
- case BIODASDENABLE:{
- dasd_range_t range = {
- from: device->devinfo.devno,
- to: device->devinfo.devno
- };
- if (!capable (CAP_SYS_ADMIN)) {
- rc = -EACCES;
- break;
- }
- dasd_enable_ranges (&range, device->discipline, 0);
- break;
- }
- case BIODASDFMT:{
- /* fdata == NULL is no longer a valid arg to dasd_format ! */
- int partn = MINOR (inp->i_rdev) &
- ((1 << major_info->gendisk.minor_shift) - 1);
- format_data_t fdata;
- if (!capable (CAP_SYS_ADMIN)) {
- rc = -EACCES;
- break;
- }
- if (dasd_features_from_devno(device->devinfo.devno)&DASD_FEATURE_READONLY) {
- rc = -EROFS;
- break;
- }
- if (!data) {
- rc = -EINVAL;
- break;
- }
- rc = copy_from_user (&fdata, (void *) data,
- sizeof (format_data_t));
- if (rc) {
- rc = -EFAULT;
- break;
- }
- if (partn != 0) {
- DASD_MESSAGE (KERN_WARNING, device, "%s",
- "Cannot low-level format a partition");
- return -EINVAL;
- }
- rc = dasd_format (device, &fdata);
- break;
- }
- case BIODASDPRRST:{ /* reset device profile information */
- if (!capable (CAP_SYS_ADMIN)) {
- rc = -EACCES;
- break;
- }
- memset (&device->profile, 0,
- sizeof (dasd_profile_info_t));
- break;
- }
- case BIODASDPRRD:{ /* retrun device profile information */
- rc = copy_to_user((long *)data,
- (long *)&device->profile,
- sizeof(dasd_profile_info_t));
- if (rc)
- rc = -EFAULT;
- break;
- }
- case BIODASDRSRV:{ /* reserve */
- ccw_req_t *req;
- if (!capable (CAP_SYS_ADMIN)) {
- rc = -EACCES;
- break;
- }
- req = device->discipline->reserve (device);
- rc = dasd_sleep_on_req (req);
- dasd_free_request (req, device);
- break;
- }
- case BIODASDRLSE:{ /* release */
- ccw_req_t *req;
- if (!capable (CAP_SYS_ADMIN)) {
- rc = -EACCES;
- break;
- }
- req = device->discipline->release (device);
- rc = dasd_sleep_on_req (req);
- dasd_free_request (req, device);
- break;
- }
- case BIODASDSLCK:{ /* steal lock - unconditional reserve */
- ccw_req_t *req;
- if (!capable (CAP_SYS_ADMIN)) {
- rc = -EACCES;
- break;
- }
- req = device->discipline->steal_lock (device);
- rc = dasd_sleep_on_req (req);
- dasd_free_request (req, device);
- break;
- }
- case BIODASDINFO:{
- dasd_information_t dasd_info;
- unsigned long flags;
- rc = device->discipline->fill_info (device, &dasd_info);
- dasd_info.label_block = device->sizes.pt_block;
- dasd_info.devno = device->devinfo.devno;
- dasd_info.schid = device->devinfo.irq;
- dasd_info.cu_type = device->devinfo.sid_data.cu_type;
- dasd_info.cu_model = device->devinfo.sid_data.cu_model;
- dasd_info.dev_type = device->devinfo.sid_data.dev_type;
- dasd_info.dev_model = device->devinfo.sid_data.dev_model;
- dasd_info.open_count =
- atomic_read (&device->open_count);
- dasd_info.status = device->level;
- if (device->discipline) {
- memcpy (dasd_info.type,
- device->discipline->name, 4);
- } else {
- memcpy (dasd_info.type, "none", 4);
- }
- dasd_info.req_queue_len = 0;
- dasd_info.chanq_len = 0;
- if (device->request_queue->request_fn) {
- struct list_head *l;
- ccw_req_t *cqr = device->queue.head;
- spin_lock_irqsave (&io_request_lock, flags);
- list_for_each (l,
- &device->request_queue->
- queue_head) {
- dasd_info.req_queue_len++;
- }
- spin_unlock_irqrestore (&io_request_lock,
- flags);
- s390irq_spin_lock_irqsave (device->devinfo.irq,
- flags);
- while (cqr) {
- cqr = cqr->next;
- dasd_info.chanq_len++;
- }
- s390irq_spin_unlock_irqrestore (device->devinfo.
- irq, flags);
- }
- rc =
- copy_to_user ((long *) data, (long *) &dasd_info,
- sizeof (dasd_information_t));
- if (rc)
- rc = -EFAULT;
- break;
- }
- #if 0 /* needed for XFS */
- case BLKBSZSET:{
- int bsz;
- rc = copy_from_user ((long *)&bsz,(long *)data,sizeof(int));
- if ( rc ) {
- rc = -EFAULT;
- } else {
- if ( bsz >= device->sizes.bp_block )
- rc = blk_ioctl (inp->i_rdev, no, data);
- else
- rc = -EINVAL;
- }
- break;
- }
- #endif /* 0 */
- case BLKSSZGET:
- case BLKROSET:
- case BLKROGET:
- case BLKRASET:
- case BLKRAGET:
- case BLKFLSBUF:
- case BLKPG:
- case BLKELVGET:
- case BLKELVSET:
- return blk_ioctl (inp->i_rdev, no, data);
- break;
- default:{
- dasd_ioctl_list_t *old = dasd_find_ioctl (no);
- if (old) {
- if ( old->owner )
- __MOD_INC_USE_COUNT(old->owner);
- rc = old->handler (inp, no, data);
- if ( old->owner )
- __MOD_DEC_USE_COUNT(old->owner);
- } else {
- DASD_MESSAGE (KERN_INFO, device,
- "ioctl 0x%08x=%s'0x%x'%d(%d) data %8lxn",
- no,
- _IOC_DIR (no) == _IOC_NONE ? "0" :
- _IOC_DIR (no) == _IOC_READ ? "r" :
- _IOC_DIR (no) == _IOC_WRITE ? "w" :
- _IOC_DIR (no) ==
- (_IOC_READ | _IOC_WRITE) ? "rw" : "u",
- _IOC_TYPE (no),
- _IOC_NR (no),
- _IOC_SIZE (no),
- data);
- rc = -ENOTTY;
- }
- break;
- }
- }
- return rc;
- }
- /* SECTION: The members of the struct file_operations */
- static int
- dasd_ioctl (struct inode *inp, struct file *filp,
- unsigned int no, unsigned long data)
- {
- int rc = 0;
- if ((!inp) || !(inp->i_rdev)) {
- return -EINVAL;
- }
- rc = do_dasd_ioctl (inp, no, data);
- return rc;
- }
- static int
- dasd_open (struct inode *inp, struct file *filp)
- {
- int rc = 0;
- unsigned long flags;
- dasd_device_t *device;
- if ((!inp) || !(inp->i_rdev)) {
- rc = -EINVAL;
- goto fail;
- }
- if (dasd_probeonly) {
- printk ("n" KERN_INFO PRINTK_HEADER
- "No access to device (%d:%d) due to probeonly moden",
- MAJOR (inp->i_rdev),
- MINOR (inp->i_rdev));
- rc = -EPERM;
- goto fail;
- }
- spin_lock_irqsave(&discipline_lock,flags);
- device = dasd_device_from_kdev (inp->i_rdev);
- if (!device) {
- printk (KERN_WARNING PRINTK_HEADER
- "No device registered as (%d:%d)n",
- MAJOR (inp->i_rdev),
- MINOR (inp->i_rdev));
- rc = -ENODEV;
- goto unlock;
- }
- if (device->level <= DASD_STATE_ACCEPT ) {
- DASD_MESSAGE (KERN_WARNING, device, " %s",
- " Cannot open unrecognized devicen");
- rc = -ENODEV;
- goto unlock;
- }
- if (atomic_inc_return (&device->open_count) == 1 ) {
- if ( device->discipline->owner )
- __MOD_INC_USE_COUNT(device->discipline->owner);
- }
- unlock:
- spin_unlock_irqrestore(&discipline_lock,flags);
- fail:
- return rc;
- }
- /*
- * DASD_RELEASE
- *
- * DESCRIPTION
- */
- static int
- dasd_release (struct inode *inp, struct file *filp)
- {
- int rc = 0;
- int count;
- dasd_device_t *device;
- if ((!inp) || !(inp->i_rdev)) {
- rc = -EINVAL;
- goto out;
- }
- device = dasd_device_from_kdev (inp->i_rdev);
- if (!device) {
- printk (KERN_WARNING PRINTK_HEADER
- "No device registered as %d:%dn",
- MAJOR (inp->i_rdev),
- MINOR (inp->i_rdev));
- rc = -EINVAL;
- goto out;
- }
- if (device->level < DASD_STATE_ACCEPT ) {
- DASD_MESSAGE (KERN_WARNING, device, " %s",
- " Cannot release unrecognized devicen");
- rc = -ENODEV;
- goto out;
- }
- count = atomic_dec_return (&device->open_count);
- if ( count == 0) {
- invalidate_buffers (inp->i_rdev);
- if ( device->discipline->owner )
- __MOD_DEC_USE_COUNT(device->discipline->owner);
- } else if ( count == -1 ) { /* paranoia only */
- atomic_set (&device->open_count,0);
- printk (KERN_WARNING PRINTK_HEADER
- "release called with open count==0n");
- }
- out:
- return rc;
- }
- static struct
- block_device_operations dasd_device_operations =
- {
- owner:THIS_MODULE,
- open:dasd_open,
- release:dasd_release,
- ioctl:dasd_ioctl,
- };
- /* SECTION: Management of device list */
- int
- dasd_fillgeo(int kdev,struct hd_geometry *geo)
- {
- dasd_device_t *device = dasd_device_from_kdev (kdev);
- if (!device)
- return -EINVAL;
- if (!device->discipline->fill_geometry)
- return -EINVAL;
- device->discipline->fill_geometry (device, geo);
- geo->start = device->major_info->gendisk.part[MINOR(kdev)].start_sect
- >> device->sizes.s2b_shift;;
- return 0;
- }
- /* This one is needed for naming 18000+ possible dasd devices */
- int
- dasd_device_name (char *str, int index, int partition, struct gendisk *hd)
- {
- int len = 0;
- char first, second, third;
- if (hd) {
- major_info_t *major_info = NULL;
- struct list_head *l;
- list_for_each (l, &dasd_major_info[0].list) {
- major_info = list_entry (l, major_info_t, list);
- if (&major_info->gendisk == hd) {
- break;
- }
- index += DASD_PER_MAJOR;
- }
- if (major_info == &dasd_major_info[0]) {
- return -EINVAL;
- }
- }
- third = index % 26;
- second = ((index - 26) / 26) % 26;
- first = (((index - 702) / 26) / 26) % 26;
- len = sprintf (str, "dasd");
- if (index > 701) {
- len += sprintf (str + len, "%c", first + 'a');
- }
- if (index > 25) {
- len += sprintf (str + len, "%c", second + 'a');
- }
- len += sprintf (str + len, "%c", third + 'a');
- if (partition) {
- if (partition > 9) {
- return -EINVAL;
- } else {
- len += sprintf (str + len, "%d", partition);
- }
- }
- str[len] = ' ';
- return 0;
- }
- static void
- dasd_plug_device (dasd_device_t * device)
- {
- atomic_set(&device->plugged,1);
- }
- static void
- dasd_unplug_device (dasd_device_t * device)
- {
- atomic_set(&device->plugged,0);
- dasd_schedule_bh(device);
- }
- static void
- dasd_flush_chanq ( dasd_device_t * device, int destroy )
- {
- ccw_req_t *cqr;
- unsigned long flags;
- if ( destroy ) {
- s390irq_spin_lock_irqsave (device->devinfo.irq, flags);
- cqr = device->queue.head;
- while ( cqr != NULL ) {
- if ( cqr->status == CQR_STATUS_IN_IO )
- device->discipline->term_IO (cqr);
- if ( cqr->status != CQR_STATUS_DONE ||
- cqr->status != CQR_STATUS_FAILED ) {
- cqr->status = CQR_STATUS_FAILED;
- asm volatile ("STCK %0":"=m" (cqr->stopclk));
- }
- dasd_schedule_bh(device);
- cqr = cqr->next;
- }
- s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags);
- }
- wait_event( device->wait_q, device->queue.head == NULL );
- }
- static void
- dasd_flush_request_queues ( dasd_device_t * device, int destroy )
- {
- int i;
- int major = MAJOR(device->kdev);
- int minor = MINOR(device->kdev);
- for ( i = 0; i < (1 << DASD_PARTN_BITS); i ++) {
- if ( destroy )
- destroy_buffers(MKDEV(major,minor+i));
- else
- invalidate_buffers(MKDEV(major,minor+i));
- }
- }
- static int
- dasd_disable_volume ( dasd_device_t * device, int force )
- {
- int rc = 0;
- int target = DASD_STATE_KNOWN;
- int count = atomic_read (&device->open_count);
-
- if ( count ) {
- DASD_MESSAGE (KERN_EMERG, device, "%s",
- "device has vanished although it was open!");
- }
- if ( force ) {
- dasd_deactivate_queue(device);
- dasd_flush_chanq(device,force);
- dasd_flush_request_queues(device,force);
- dasd_disable_blkdev(device);
- target = DASD_STATE_DEL;
- }
- /* unregister partitions ('ungrok_partitions') */
- devfs_register_partitions(&device->major_info->gendisk,
- MINOR(device->kdev),1);
-
- DASD_MESSAGE (KERN_WARNING, device,
- "disabling device, target state: %d",target);
- dasd_set_device_level (device->devinfo.devno,
- device->discipline,
- target);
- return rc;
- }
- static void
- dasd_disable_ranges (dasd_range_t *range,
- dasd_discipline_t *d,
- int all, int force )
- {
- dasd_range_t *rrange;
- int j;
- if (range == &dasd_range_head) {
- rrange = list_entry (range->list.next,
- dasd_range_t, list);
- } else {
- rrange = range;
- }
- do {
- for (j = rrange->from; j <= rrange->to; j++) {
- dasd_device_t **dptr;
- dasd_device_t *device;
- dptr = dasd_device_from_devno(j);
- if ( dptr == NULL ) {
- continue;
- }
- device = *dptr;
- if (device == NULL ||
- (d != NULL &&
- device -> discipline != d))
- continue;
-
- dasd_disable_volume(device, force);
- }
- rrange = list_entry (rrange->list.next, dasd_range_t, list);
- } while ( all && rrange && rrange != range );
- }
- static void
- dasd_enable_single_device ( unsigned long arg ) {
- dasd_device_t * device =(dasd_device_t *) arg;
- int devno = device->devinfo.devno;
- dasd_range_t range = { from: devno, to:devno };
- dasd_enable_ranges (&range,NULL,0);
- }
- static void
- dasd_enable_ranges (dasd_range_t *range, dasd_discipline_t *d, int all )
- {
- int retries = 0;
- int j;
- kdev_t tempdev;
- dasd_range_t *rrange;
- if (range == NULL)
- return;
-
- do {
- if (range == &dasd_range_head) {
- rrange = list_entry (range->list.next,
- dasd_range_t, list);
- } else {
- rrange = range;
- }
- do {
- for (j = rrange->from; j <= rrange->to; j++) {
- if ( dasd_devindex_from_devno(j) < 0 )
- continue;
- dasd_set_device_level (j, d, DASD_STATE_ONLINE);
- }
- rrange = list_entry (rrange->list.next, dasd_range_t, list);
- } while ( all && rrange && rrange != range );
- if (atomic_read (&dasd_init_pending) == 0) /* we are done, exit loop */
- break;
- if ( retries == 0 ) {
- printk (KERN_INFO PRINTK_HEADER
- "waiting for responses...n");
- } else if ( retries < 5 ) {
- printk (KERN_INFO PRINTK_HEADER
- "waiting a little bit longer...n");
- } else {
- printk (KERN_INFO PRINTK_HEADER
- "giving up, enable late devices manually!n");
- break;
- }
- interruptible_sleep_on_timeout (&dasd_init_waitq, (1 * HZ));
- retries ++;
- } while (1);
- /* now setup block devices */
- /* Now do block device and partition setup */
- if (range == &dasd_range_head) {
- rrange = list_entry (range->list.next,
- dasd_range_t, list);
- } else {
- rrange = range;
- }
- do {
- for (j = rrange->from; j <= rrange->to; j++) {
- dasd_device_t **dptr;
- dasd_device_t *device;
- if ( dasd_devindex_from_devno(j) < 0 )
- continue;
- dptr = dasd_device_from_devno(j);
- device = *dptr;
- if (device == NULL )
- continue;
- if ( ((d == NULL && device->discipline != NULL) ||
- (device->discipline == d )) &&
- device->level >= DASD_STATE_READY &&
- device->request_queue == NULL ) {
- if (dasd_features_from_devno(j)&DASD_FEATURE_READONLY) {
- for (tempdev=device->kdev;
- tempdev<(device->kdev +(1 << DASD_PARTN_BITS));
- tempdev++)
- set_device_ro (tempdev, 1);
- printk (KERN_WARNING PRINTK_HEADER
- "setting read-only mode for device /dev/%sn",
- device->name);
- }
- dasd_setup_blkdev(device);
- dasd_setup_partitions(device);
- }
- }
- rrange = list_entry (rrange->list.next, dasd_range_t, list);
- } while ( all && rrange && rrange != range );
- }
- #ifdef CONFIG_DASD_DYNAMIC
- /*
- * DASD_NOT_OPER_HANDLER
- *
- * DESCRIPTION
- * handles leaving devices
- */
- static void
- dasd_not_oper_handler (int irq, int status)
- {
- dasd_device_t *device = NULL;
- major_info_t *major_info = NULL;
- struct list_head *l;
- int i, devno = -ENODEV;
- /* find out devno of leaving device: CIO has already deleted this information ! */
- list_for_each (l, &dasd_major_info[0].list) {
- major_info = list_entry (l, major_info_t, list);
- for (i = 0; i < DASD_PER_MAJOR; i++) {
- device = major_info->dasd_device[i];
- if (device && device->devinfo.irq == irq) {
- devno = device->devinfo.devno;
- break;
- }
- }
- if (devno != -ENODEV)
- break;
- }
- DASD_DRIVER_DEBUG_EVENT (5, dasd_not_oper_handler,
- "called for devno %04x",
- devno);
- if (devno < 0) {
- printk (KERN_WARNING PRINTK_HEADER
- "not_oper_handler called on irq 0x%04x no devno!n",
- irq);
- return;
- }
- dasd_disable_volume(device, 1);
- }
- /*
- * DASD_OPER_HANDLER
- *
- * DESCRIPTION
- * called by the machine check handler to make an device operational
- */
- int
- dasd_oper_handler (int irq, devreg_t * devreg)
- {
- int devno;
- int rc = 0;
- major_info_t *major_info = NULL;
- dasd_range_t *rptr,range;
- dasd_device_t *device = NULL;
- struct list_head *l;
- int i;
- devno = get_devno_by_irq (irq);
- if (devno == -ENODEV) {
- rc = -ENODEV;
- goto out;
- }
- DASD_DRIVER_DEBUG_EVENT (5, dasd_oper_handler,
- "called for devno %04x",
- devno);
- /* find out devno of device */
- list_for_each (l, &dasd_major_info[0].list) {
- major_info = list_entry (l, major_info_t, list);
- for (i = 0; i < DASD_PER_MAJOR; i++) {
- device = major_info->dasd_device[i];
- if (device && device->devinfo.irq == irq) {
- devno = device->devinfo.devno;
- break;
- }
- }
- if (devno != -ENODEV)
- break;
- }
- if (devno < 0) {
- BUG();
- }
- if ( device &&
- device->level == DASD_STATE_READY ) {
- dasd_set_device_level (device->devinfo.devno,
- device->discipline, DASD_STATE_ONLINE);
- } else {
- if (dasd_autodetect) {
- rptr = dasd_add_range (devno, devno, DASD_DEFAULT_FEATURES);
- if ( rptr == NULL ) {
- rc = -ENOMEM;
- goto out;
- }
- } else {
- range.from = devno;
- range.to = devno;
- rptr = ⦥
- }
- dasd_enable_ranges (rptr, NULL, 0);
- }
- out:
- return rc;
- }
- #endif /* CONFIG_DASD_DYNAMIC */
- static inline dasd_device_t **
- dasd_find_device_addr ( int devno )
- {
- dasd_device_t **device_addr;
- DASD_DRIVER_DEBUG_EVENT (1, dasd_find_device_addr,
- "devno %04x",
- devno);
- if ( dasd_devindex_from_devno (devno) < 0 ) {
- DASD_DRIVER_DEBUG_EXCEPTION (1, dasd_find_device_addr,
- "no dasd: devno %04x",
- devno);
- return NULL;
- }
- /* allocate major numbers on demand for new devices */
- while ((device_addr = dasd_device_from_devno (devno)) == NULL) {
- int rc;
- if ((rc = dasd_register_major (NULL)) <= 0) {
- DASD_DRIVER_DEBUG_EXCEPTION (1, dasd_find_device_addr,
- "%s",
- "out of major numbers!");
- break;
- }
- }
- return device_addr;
- }
- static inline int
- dasd_state_del_to_new (dasd_device_t **addr )
- {
- dasd_device_t* device;
- int rc = 0;
- if (*addr == NULL) { /* allocate device descriptor on demand for new device */
- device = kmalloc (sizeof (dasd_device_t), GFP_ATOMIC);
- if (device == NULL ) {
- rc = -ENOMEM;
- goto out;
- }
- memset (device, 0, sizeof (dasd_device_t));
- *addr = device;
- device->lowmem_ccws = (void*)get_free_page (GFP_ATOMIC|GFP_DMA);
- if (device->lowmem_ccws == NULL) {
- rc = -ENOMEM;
- goto noccw;
- }
- #ifdef CONFIG_ARCH_S390X
- device->lowmem_idals =
- device->lowmem_idal_ptr = (void*) get_free_page (GFP_ATOMIC|GFP_DMA);
- if (device->lowmem_idals == NULL) {
- rc = -ENOMEM;
- goto noidal;
- }
- #endif
- }
- goto out;
- #ifdef CONFIG_ARCH_S390X
- noidal:
- free_page ((long) device->lowmem_ccws);
- #endif
- noccw:
- kfree(device);
- out:
- return rc;
- }
- static inline int
- dasd_state_new_to_del (dasd_device_t **addr )
- {
- dasd_device_t *device = *addr;
- if (device && device->private) {
- kfree(device->private);
- device->private = NULL;
- }
- #ifdef CONFIG_ARCH_S390X
- free_page ((long)(device->lowmem_idals));
- #endif
- free_page((long)(device->lowmem_ccws));
- kfree(device);
- *addr = NULL;
- return 0;
- }
- static inline int
- dasd_state_new_to_known (dasd_device_t **dptr, int devno, dasd_discipline_t *disc)
- {
- int rc = 0;
- umode_t devfs_perm = S_IFBLK | S_IRUSR | S_IWUSR;
- struct list_head *l;
- major_info_t *major_info = NULL;
- int i;
- dasd_device_t *device = *dptr;
- devfs_handle_t dir;
- char buffer[5];
-
- list_for_each (l, &dasd_major_info[0].list) {
- major_info = list_entry (l, major_info_t, list);
- for (i = 0; i < DASD_PER_MAJOR; i++) {
- if (major_info->dasd_device[i] == device) {
- device->kdev = MKDEV (major_info->gendisk.major,
- i << DASD_PARTN_BITS);
- break;
- }
- }
- if (i < DASD_PER_MAJOR) /* we found one */
- break;
- }
- if ( major_info == NULL || major_info == &dasd_major_info[0] )
- BUG();
- device->major_info = major_info;
- dasd_device_name (device->name,
- (((long)dptr -
- (long)device->major_info->dasd_device) /
- sizeof (dasd_device_t *)),
- 0, &device->major_info->gendisk);
- init_waitqueue_head (&device->wait_q);
-
- rc = get_dev_info_by_devno (devno, &device->devinfo);
- if ( rc ) {
- goto out;
- }
- DASD_DRIVER_DEBUG_EVENT (5, dasd_state_new_to_known,
- "got devinfo CU-type %04x and dev-type %04x",
- device->devinfo.sid_data.cu_type,
- device->devinfo.sid_data.dev_type);
- if ( devno != device->devinfo.devno )
- BUG();
- device->discipline = dasd_find_disc (device, disc);
- if ( device->discipline == NULL ) {
- rc = -ENODEV;
- goto out;
- }
- sprintf (buffer, "%04x",
- device->devinfo.devno);
- dir = devfs_mk_dir (dasd_devfs_handle, buffer, device);
- device->major_info->gendisk.de_arr[MINOR(device->kdev)
- >> DASD_PARTN_BITS] = dir;
- if (dasd_features_from_devno(device->devinfo.devno)&DASD_FEATURE_READONLY) {
- devfs_perm &= ~(S_IWUSR);
- }
- device->devfs_entry = devfs_register (dir,"device",DEVFS_FL_DEFAULT,
- MAJOR(device->kdev),
- MINOR(device->kdev),
- devfs_perm,
- &dasd_device_operations,NULL);
- device->level = DASD_STATE_KNOWN;
- out:
- return rc;
- }
- static inline int
- dasd_state_known_to_new (dasd_device_t *device )
- {
- int rc = 0;
- /* don't reset to zeros because of persistent data durich detach/attach! */
- devfs_unregister(device->devfs_entry);
- devfs_unregister(device->major_info->gendisk.de_arr[MINOR(device->kdev) >> DASD_PARTN_BITS]);
- return rc;
- }
- static inline int
- dasd_state_known_to_accept (dasd_device_t *device)
- {
- int rc = 0;
- device->debug_area = debug_register (device->name, 0, 2,
- 3 * sizeof (long));
- debug_register_view (device->debug_area, &debug_sprintf_view);
- debug_register_view (device->debug_area, &debug_hex_ascii_view);
- DASD_DEVICE_DEBUG_EVENT (0, device,"%p debug area created",
- device);
-
- if (device->discipline->int_handler) {
- rc = s390_request_irq_special (device->devinfo.irq,
- device->discipline->int_handler,
- dasd_not_oper_handler,
- 0, DASD_NAME,
- &device->dev_status);
- if ( rc ) {
- printk("No request IRQn");
- goto out;
- }
- }
- device->level = DASD_STATE_ACCEPT;
- out:
- return rc;
- }
- static inline int
- dasd_state_accept_to_known (dasd_device_t *device )
- {
- if ( device->discipline == NULL )
- goto out;
- if (device->discipline->int_handler) {
- free_irq (device->devinfo.irq, &device->dev_status);
- }
- DASD_DEVICE_DEBUG_EVENT (0, device,"%p debug area deleted",
- device);
- if ( device->debug_area != NULL )
- debug_unregister (device->debug_area);
- device->discipline = NULL;
- device->level = DASD_STATE_KNOWN;
- out:
- return 0;
- }
- static inline int
- dasd_state_accept_to_init (dasd_device_t *device)
- {
- int rc = 0;
- unsigned long flags;
- if ( device->discipline->init_analysis ) {
- device->init_cqr=device->discipline->init_analysis (device);
- if ( device->init_cqr != NULL ) {
- if ( device->discipline->start_IO == NULL )
- BUG();
- atomic_inc (&dasd_init_pending);
- s390irq_spin_lock_irqsave (device->devinfo.irq,
- flags);
- rc = device->discipline->start_IO (device->init_cqr);
- s390irq_spin_unlock_irqrestore(device->devinfo.irq,
- flags);
- if ( rc )
- goto out;
- device->level = DASD_STATE_INIT;
- } else {
- rc = -ENOMEM;
- }
- } else {
- rc = dasd_state_init_to_ready ( device );
- }
- out:
- return rc;
- }
- static inline int
- dasd_state_init_to_ready (dasd_device_t *device )
- {
- int rc = 0;
- if (device->discipline->do_analysis != NULL)
- if ( device->discipline->do_analysis (device) == 0 )
- switch (device->sizes.bp_block) {
- case 512:
- case 1024:
- case 2048:
- case 4096:
- break;
- default:
- rc = -EMEDIUMTYPE;
- }
- if ( device->init_cqr ) {
- /* This pointer is no longer needed, BUT dont't free the */
- /* memory, because this is done in bh for finished request!!!! */
- atomic_dec(&dasd_init_pending);
- device->init_cqr = NULL;
- }
- device->level = DASD_STATE_READY;
- return rc;
- }
- static inline int
- dasd_state_ready_to_accept (dasd_device_t *device )
- {
- int rc = 0;
- unsigned long flags;
- s390irq_spin_lock_irqsave (device->devinfo.irq, flags);
- if ( device->init_cqr != NULL && atomic_read(&dasd_init_pending) != 0 ) {
- if ( device->discipline->term_IO == NULL )
- BUG();
- device->discipline->term_IO (device->init_cqr);
- atomic_dec (&dasd_init_pending);
- dasd_free_request (device->init_cqr, device);
- device->init_cqr = NULL;
- }
- s390irq_spin_unlock_irqrestore(device->devinfo.irq, flags);
- memset(&device->sizes,0,sizeof(dasd_sizes_t));
- device->level = DASD_STATE_ACCEPT;
- return rc;
- }
- static inline int
- dasd_state_ready_to_online (dasd_device_t *device )
- {
- int rc = 0;
- dasd_unplug_device (device);
- device->level = DASD_STATE_ONLINE;
- return rc;
- }
- static inline int
- dasd_state_online_to_ready (dasd_device_t *device )
- {
- int rc = 0;
- dasd_plug_device (device);
- device->level = DASD_STATE_READY;
- return rc;
- }
- static inline int
- dasd_setup_blkdev (dasd_device_t *device )
- {
- int rc = 0;
- int i;
- int major = MAJOR(device->kdev);
- int minor = MINOR(device->kdev);
- for (i = 0; i < (1 << DASD_PARTN_BITS); i++) {
- if (i == 0)
- device->major_info->gendisk.sizes[minor] =
- (device->sizes.blocks << device->
- sizes.s2b_shift) >> 1;
- else
- device->major_info->gendisk.sizes[minor + i] = 0;
- hardsect_size[major][minor + i] = device->sizes.bp_block;
- blksize_size[major][minor + i] = device->sizes.bp_block;
- max_sectors[major][minor + i] =
- device->discipline->max_blocks <<
- device->sizes.s2b_shift;
- device->major_info->gendisk.part[minor+i].start_sect = 0;
- device->major_info->gendisk.part[minor+i].nr_sects = 0;
- }
- device->request_queue = kmalloc(sizeof(request_queue_t),GFP_KERNEL);
- device->request_queue->queuedata = device;
- blk_init_queue (device->request_queue, do_dasd_request);
- blk_queue_headactive (device->request_queue, 0);
- elevator_init (&(device->request_queue->elevator),ELEVATOR_NOOP);
- return rc;
- }
- static void
- dasd_deactivate_queue (dasd_device_t *device)
- {
- int i;
- int minor = MINOR(device->kdev);
- for (i = 0; i < (1 << DASD_PARTN_BITS); i++) {
- device->major_info->gendisk.sizes[minor + i] = 0;
- }
- }
- static inline int
- dasd_disable_blkdev (dasd_device_t *device )
- {
- int i;
- int major = MAJOR(device->kdev);
- int minor = MINOR(device->kdev);
- for (i = 0; i < (1 << DASD_PARTN_BITS); i++) {
- destroy_buffers(MKDEV(major,minor+i));
- device->major_info->gendisk.sizes[minor + i] = 0;
- hardsect_size[major][minor + i] = 0;
- blksize_size[major][minor + i] = 0;
- max_sectors[major][minor + i] = 0;
- }
- if (device->request_queue) {
- blk_cleanup_queue (device->request_queue);
- kfree(device->request_queue);
- device->request_queue = NULL;
- }
- return 0;
- }
- /*
- * function dasd_setup_partitions
- * calls the function in genhd, which is appropriate to setup a partitioned disk
- */
- static inline void
- dasd_setup_partitions ( dasd_device_t * device )
- {
- register_disk (&device->major_info->gendisk,
- device->kdev,
- 1 << DASD_PARTN_BITS,
- &dasd_device_operations,
- (device->sizes.blocks << device->sizes.s2b_shift));
- }
- static inline void
- dasd_destroy_partitions ( dasd_device_t * device )
- {
- int i;
- int minor = MINOR(device->kdev);
-
- for (i = 0; i < (1 << DASD_PARTN_BITS); i++) {
- device->major_info->gendisk.part[minor+i].start_sect = 0;
- device->major_info->gendisk.part[minor+i].nr_sects = 0;
- }
- devfs_register_partitions(&device->major_info->gendisk,
- MINOR(device->kdev),1);
- }
- static inline void
- dasd_resetup_partitions ( dasd_device_t * device )
- {
- BUG();
- dasd_destroy_partitions ( device ) ;
- dasd_setup_partitions ( device ) ;
- }
- /*
- * function dasd_set_device_level
- */
- static int
- dasd_set_device_level (unsigned int devno,
- dasd_discipline_t * discipline,
- int to_state)
- {
- int rc = 0;
- dasd_device_t **device_addr;
- dasd_device_t *device;
- int from_state;
- device_addr = dasd_find_device_addr ( devno );
- if ( device_addr == NULL ) {
- rc = -ENODEV;
- goto out;
- }
- device = *device_addr;
- if ( device == NULL ) {
- from_state = DASD_STATE_DEL;
- if ( to_state == DASD_STATE_DEL )
- goto out;
- } else {
- from_state = device->level;
- }
- DASD_DRIVER_DEBUG_EVENT (3, dasd_set_device_level,
- "devno %04x; from %i to %i",
- devno,
- from_state,
- to_state);
- if ( from_state == to_state )
- goto out;
- if ( to_state < from_state )
- goto shutdown;
- /* First check for bringup */
- if ( from_state <= DASD_STATE_DEL &&
- to_state >= DASD_STATE_NEW ) {
- rc = dasd_state_del_to_new(device_addr);
- if ( rc ) {
- goto bringup_fail;
- }
- device = *device_addr;
- }
- if ( from_state <= DASD_STATE_NEW &&
- to_state >= DASD_STATE_KNOWN ) {
- rc = dasd_state_new_to_known( device_addr, devno, discipline );
- if ( rc ) {
- goto bringup_fail;
- }
- }
- if ( from_state <= DASD_STATE_KNOWN &&
- to_state >= DASD_STATE_ACCEPT ) {
- rc = dasd_state_known_to_accept(device);
- if ( rc ) {
- goto bringup_fail;
- }
- }
- if ( dasd_probeonly ) {
- goto out;
- }
- if ( from_state <= DASD_STATE_ACCEPT &&
- to_state >= DASD_STATE_INIT ) {
- rc = dasd_state_accept_to_init(device);
- if ( rc ) {
- goto bringup_fail;
- }
- }
- if ( from_state <= DASD_STATE_INIT &&
- to_state >= DASD_STATE_READY ) {
- rc = -EAGAIN;
- goto out;
- }
- if ( from_state <= DASD_STATE_READY &&
- to_state >= DASD_STATE_ONLINE ) {
- rc = dasd_state_ready_to_online(device);
- if ( rc ) {
- goto bringup_fail;
- }
- }
- goto out;
- bringup_fail: /* revert changes */
- #if 0
- printk (KERN_DEBUG PRINTK_HEADER
- "failed to set device from state %d to %d at "
- "level %d rc %d. Reverting...n",
- from_state,
- to_state,
- device->level,
- rc);
- #endif
- to_state = from_state;
- from_state = device->level;
-
- /* now do a shutdown */
- shutdown:
- if ( from_state >= DASD_STATE_ONLINE &&
- to_state <= DASD_STATE_READY )
- if (dasd_state_online_to_ready(device))
- BUG();
- if ( from_state >= DASD_STATE_READY &&
- to_state <= DASD_STATE_ACCEPT )
- if ( dasd_state_ready_to_accept(device))
- BUG();
- if ( from_state >= DASD_STATE_ACCEPT &&
- to_state <= DASD_STATE_KNOWN )
- if ( dasd_state_accept_to_known(device))
- BUG();
- if ( from_state >= DASD_STATE_KNOWN &&
- to_state <= DASD_STATE_NEW )
- if ( dasd_state_known_to_new(device))
- BUG();
- if ( from_state >= DASD_STATE_NEW &&
- to_state <= DASD_STATE_DEL)
- if (dasd_state_new_to_del(device_addr))
- BUG();
- goto out;
- out:
- return rc;
- }
- /* SECTION: Procfs stuff */
- typedef struct {
- char *data;
- int len;
- } tempinfo_t;
- void
- dasd_fill_inode (struct inode *inode, int fill)
- {
- if (fill)
- MOD_INC_USE_COUNT;
- else
- MOD_DEC_USE_COUNT;
- }
- static struct proc_dir_entry *dasd_proc_root_entry = NULL;
- static struct proc_dir_entry *dasd_devices_entry;
- static struct proc_dir_entry *dasd_statistics_entry;
- static int
- dasd_devices_open (struct inode *inode, struct file *file)
- {
- int rc = 0;
- int size = 1;
- int len = 0;
- major_info_t *temp = NULL;
- struct list_head *l;
- tempinfo_t *info;
- int i;
- unsigned long flags;
- int index = 0;
- MOD_INC_USE_COUNT;
- spin_lock_irqsave(&discipline_lock,flags);
- info = (tempinfo_t *) vmalloc (sizeof (tempinfo_t));
- if (info == NULL) {
- printk (KERN_WARNING "No memory available for datan");
- MOD_DEC_USE_COUNT;
- return -ENOMEM;
- } else {
- file->private_data = (void *) info;
- }
- list_for_each (l, &dasd_major_info[0].list) {
- size += 128 * 1 << (MINORBITS - DASD_PARTN_BITS);
- }
- info->data = (char *) vmalloc (size);
- DASD_DRIVER_DEBUG_EVENT (1, dasd_devices_open, "area: %p, size 0x%x",
- info->data,
- size);
- if (size && info->data == NULL) {
- printk (KERN_WARNING "No memory available for datan");
- vfree (info);
- MOD_DEC_USE_COUNT;
- return -ENOMEM;
- }
- list_for_each (l, &dasd_major_info[0].list) {
- temp = list_entry (l, major_info_t, list);
- for (i = 0; i < 1 << (MINORBITS - DASD_PARTN_BITS); i++) {
- dasd_device_t *device;
- int devno = dasd_devno_from_devindex(index+i);
- int features;
- if ( devno == -ENODEV )
- continue;
- features = dasd_features_from_devno(devno);
- if (features < DASD_DEFAULT_FEATURES)
- features = DASD_DEFAULT_FEATURES;
- device = temp->dasd_device[i];
- if (device) {
- len += sprintf (info->data + len,
- "%04x(%s) at (%3d:%3d) is %-7s%4s: ",
- device->devinfo.devno,
- device->discipline ?
- device->
- discipline->name : "none",
- temp->gendisk.major,
- i << DASD_PARTN_BITS,
- device->name,
- (features & DASD_FEATURE_READONLY) ?
- "(ro)" : " ");
-
- switch (device->level) {
- case DASD_STATE_NEW:
- len +=
- sprintf (info->data + len,
- "new");
- break;
- case DASD_STATE_KNOWN:
- len +=
- sprintf (info->data + len,
- "detected");
- break;
- case DASD_STATE_ACCEPT:
- len += sprintf (info->data + len,"accepted");
- break;
- case DASD_STATE_INIT:
- len +=
- sprintf (info->data + len,
- "busy ");
- break;
- case DASD_STATE_READY:
- case DASD_STATE_ONLINE:
- if ( atomic_read(&device->plugged) )
- len +=
- sprintf (info->data + len,
- "fenced ");
- else
- len +=
- sprintf (info->data + len,
- "active ");
- if ( device->sizes.bp_block == 512 ||
- device->sizes.bp_block == 1024 ||
- device->sizes.bp_block == 2048 ||
- device->sizes.bp_block == 4096 )
- len +=
- sprintf (info->data + len,
- "at blocksize: %d, %ld blocks, %ld MB",
- device->sizes.bp_block,
- device->sizes.blocks,
- ((device->
- sizes.bp_block >> 9) *
- device->sizes.
- blocks) >> 11);
- else
- len +=
- sprintf (info->data + len,
- "n/f ");
- break;
- default:
- len +=
- sprintf (info->data + len,
- "no stat");
- break;
- }
- } else {
- char buffer[7];
- dasd_device_name (buffer, i, 0, &temp->gendisk);
- if ( devno < 0 ) {
- len += sprintf (info->data + len,
- "none");
- } else {
- len += sprintf (info->data + len,
- "%04x",devno);
- }
- len += sprintf (info->data + len,
- "(none) at (%3d:%3d) is %-7s%4s: unknown",
- temp->gendisk.major,
- i << DASD_PARTN_BITS,
- buffer,
- (features & DASD_FEATURE_READONLY) ?
- "(ro)" : " ");
- }
- if ( dasd_probeonly )
- len += sprintf(info->data + len,"(probeonly)");
- len += sprintf(info->data + len,"n");
- }
- index += 1 << (MINORBITS - DASD_PARTN_BITS);
- }
- info->len = len;
- spin_unlock_irqrestore(&discipline_lock,flags);
- return rc;
- }
- #define MIN(a,b) ((a)<(b)?(a):(b))
- static ssize_t
- dasd_generic_read (struct file *file, char *user_buf, size_t user_len,
- loff_t * offset)
- {
- loff_t len;
- tempinfo_t *p_info = (tempinfo_t *) file->private_data;
- if (*offset >= p_info->len) {
- return 0; /* EOF */
- } else {
- len = MIN (user_len, (p_info->len - *offset));
- if (copy_to_user (user_buf, &(p_info->data[*offset]), len))
- return -EFAULT;
- (*offset) += len;
- return len; /* number of bytes "read" */
- }
- }
- static ssize_t
- dasd_devices_write (struct file *file, const char *user_buf,
- size_t user_len, loff_t * offset)
- {
- char *buffer;
- int off = 0;
- char *temp;
- dasd_range_t range;
- int features;
- if (user_len > PAGE_SIZE)
- return -EINVAL;
-
- buffer = vmalloc (user_len+1);
- if (buffer == NULL)
- return -ENOMEM;
- if (copy_from_user (buffer, user_buf, user_len)) {
- vfree (buffer);
- return -EFAULT;
- }
- /* replace LF with ' ' */
- if (buffer[user_len -1] == 'n') {
- buffer[user_len -1] = ' ';
- } else {
- buffer[user_len] = ' ';
- }
- printk (KERN_INFO PRINTK_HEADER "/proc/dasd/devices: '%s'n", buffer);
- if (strncmp (buffer, "set ", 4) && strncmp (buffer, "add ", 4)) {
- printk (KERN_WARNING PRINTK_HEADER
- "/proc/dasd/devices: only 'set' and 'add' are supported verbsn");
- return -EINVAL;
- }
- off += 4;
- while (buffer[off] && !isalnum (buffer[off]))
- off++;
- if (!strncmp (buffer + off, "device", strlen ("device"))) {
- off += strlen ("device");
- while (buffer[off] && !isalnum (buffer[off]))
- off++;
- }
- if (!strncmp (buffer + off, "range=", strlen ("range="))) {
- off += strlen ("range=");
- while (buffer[off] && !isalnum (buffer[off]))
- off++;
- }
-
- temp = buffer + off;
- range.from = dasd_strtoul (temp, &temp, &features);
- range.to = range.from;
- if (*temp == '-') {
- temp++;
- range.to = dasd_strtoul (temp, &temp, &features);
- }
- if (range.from == -EINVAL ||
- range.to == -EINVAL ) {
-
- printk (KERN_WARNING PRINTK_HEADER
- "/proc/dasd/devices: range parse error in '%s'n",
- buffer);
- } else {
- off = (long) temp - (long) buffer;
- if (!strncmp (buffer, "add", strlen ("add"))) {
- dasd_add_range (range.from, range.to, features);
- dasd_enable_ranges (&range, NULL, 0);
- } else {
- while (buffer[off] && !isalnum (buffer[off]))
- off++;
- if (!strncmp (buffer + off, "on", strlen ("on"))) {
- dasd_enable_ranges (&range, NULL, 0);
- } else if (!strncmp (buffer + off, "off", strlen ("off"))) {
- dasd_disable_ranges (&range, NULL, 0, 1);
- } else {
- printk (KERN_WARNING PRINTK_HEADER
- "/proc/dasd/devices: parse error in '%s'n",
- buffer);
- }
- }
- }
- vfree (buffer);
- return user_len;
- }
- static int
- dasd_devices_close (struct inode *inode, struct file *file)
- {
- int rc = 0;
- tempinfo_t *p_info = (tempinfo_t *) file->private_data;
- if (p_info) {
- if (p_info->data)
- vfree (p_info->data);
- vfree (p_info);
- }
- MOD_DEC_USE_COUNT;
- return rc;
- }
- static struct file_operations dasd_devices_file_ops = {
- read:dasd_generic_read, /* read */
- write:dasd_devices_write, /* write */
- open:dasd_devices_open, /* open */
- release:dasd_devices_close, /* close */
- };
- static struct inode_operations dasd_devices_inode_ops = {
- };
- static int
- dasd_statistics_open (struct inode *inode, struct file *file)
- {
- int rc = 0;
- int len = 0;
- tempinfo_t *info;
- int shift, i, help = 0;
- MOD_INC_USE_COUNT;
- info = (tempinfo_t *) vmalloc (sizeof (tempinfo_t));
- if (info == NULL) {
- printk (KERN_WARNING "No memory available for datan");
- MOD_DEC_USE_COUNT;
- return -ENOMEM;
- } else {
- file->private_data = (void *) info;
- }
- info->data = (char *) vmalloc (PAGE_SIZE); /* FIXME! determine space needed in a better way */
- if (info->data == NULL) {
- printk (KERN_WARNING "No memory available for datan");
- vfree (info);
- file->private_data = NULL;
- MOD_DEC_USE_COUNT;
- return -ENOMEM;
- }
-
- /* prevent couter 'ouverflow' on output */
- for (shift = 0, help = dasd_global_profile.dasd_io_reqs;
- help > 9999999; help = help >> 1, shift++) ;
- len = sprintf (info->data, "%d dasd I/O requestsn",
- dasd_global_profile.dasd_io_reqs);
- len += sprintf (info->data + len, "with %d sectors(512B each)n",
- dasd_global_profile.dasd_io_sects);
- len += sprintf (info->data + len,
- " __<4 ___8 __16 __32 __64 "
- " _128 _256 _512 __1k __2k "
- " __4k __8k _16k _32k _64k "
- " 128kn");
- len += sprintf (info->data + len,
- " _256 _512 __1M __2M __4M "
- " __8M _16M _32M _64M 128M "
- " 256M 512M __1G __2G __4G "
- " _>4Gn");
- len += sprintf (info->data + len, "Histogram of sizes (512B secs)n");
- for (i = 0; i < 16; i++) {
- len += sprintf (info->data + len, "%7d ",
- dasd_global_profile.dasd_io_secs[i] >> shift);
- }
- len += sprintf (info->data + len, "n");
- len += sprintf (info->data + len, "Histogram of I/O times (microseconds)n");
- for (i = 0; i < 16; i++) {
- len += sprintf (info->data + len, "%7d ",
- dasd_global_profile.dasd_io_times[i] >> shift);
- }
- len += sprintf (info->data + len, "n");
- for (; i < 32; i++) {
- len += sprintf (info->data + len, "%7d ",
- dasd_global_profile.dasd_io_times[i] >> shift);
- }
- len += sprintf (info->data + len, "n");
- len += sprintf (info->data + len, "Histogram of I/O times per sectorn");
- for (i = 0; i < 16; i++) {
- len += sprintf (info->data + len, "%7d ",
- dasd_global_profile.dasd_io_timps[i] >> shift);
- }
- len += sprintf (info->data + len, "n");
- for (; i < 32; i++) {
- len += sprintf (info->data + len, "%7d ",
- dasd_global_profile.dasd_io_timps[i] >> shift);
- }
- len += sprintf (info->data + len, "n");
- len += sprintf (info->data + len, "Histogram of I/O time till sschn");
- for (i = 0; i < 16; i++) {
- len += sprintf (info->data + len, "%7d ",
- dasd_global_profile.dasd_io_time1[i] >> shift);
- }
- len += sprintf (info->data + len, "n");
- for (; i < 32; i++) {
- len += sprintf (info->data + len, "%7d ",
- dasd_global_profile.dasd_io_time1[i] >> shift);
- }
- len += sprintf (info->data + len, "n");
- len += sprintf (info->data + len,
- "Histogram of I/O time between ssch and irqn");
- for (i = 0; i < 16; i++) {
- len += sprintf (info->data + len, "%7d ",
- dasd_global_profile.dasd_io_time2[i] >> shift);
- }
- len += sprintf (info->data + len, "n");
- for (; i < 32; i++) {
- len += sprintf (info->data + len, "%7d ",
- dasd_global_profile.dasd_io_time2[i] >> shift);
- }
- len += sprintf (info->data + len, "n");
- len += sprintf (info->data + len,
- "Histogram of I/O time between ssch and irq per sectorn");
- for (i = 0; i < 16; i++) {
- len += sprintf (info->data + len, "%7d ",
- dasd_global_profile.dasd_io_time2ps[i] >> shift);
- }
- len += sprintf (info->data + len, "n");
- for (; i < 32; i++) {
- len += sprintf (info->data + len, "%7d ",
- dasd_global_profile.dasd_io_time2ps[i] >> shift);
- }
- len += sprintf (info->data + len, "n");
- len += sprintf (info->data + len,
- "Histogram of I/O time between irq and endn");
- for (i = 0; i < 16; i++) {
- len +=
- sprintf (info->data + len, "%7d ",
- dasd_global_profile.dasd_io_time3[i] >> shift);
- }
- len += sprintf (info->data + len, "n");
- for (; i < 32; i++) {
- len += sprintf (info->data + len, "%7d ",
- dasd_global_profile.dasd_io_time3[i] >> shift);
- }
- len += sprintf (info->data + len, "n");
- len += sprintf (info->data + len,
- "# of req in chanq at enqueuing (1..32) n");
- for (i = 0; i < 16; i++) {
- len += sprintf (info->data + len, "%7d ",
- dasd_global_profile.dasd_io_nr_req[i] >> shift);
- }
- len += sprintf (info->data + len, "n");
- for (; i < 32; i++) {
- len += sprintf (info->data + len, "%7d ",
- dasd_global_profile.dasd_io_nr_req[i] >> shift);
- }
- len += sprintf (info->data + len, "n");
- info->len = len;
- return rc;
- }
- static ssize_t
- dasd_statistics_write (struct file *file, const char *user_buf,
- size_t user_len, loff_t * offset)
- {
- char *buffer;
-
- if(user_len > 65536)
- user_len = 65536;
-
- buffer = vmalloc (user_len);
- if (buffer == NULL)
- return -ENOMEM;
- if (copy_from_user (buffer, user_buf, user_len)) {
- vfree (buffer);
- return -EFAULT;
- }
- buffer[user_len] = 0;
- printk (KERN_INFO PRINTK_HEADER "/proc/dasd/statictics: '%s'n",
- buffer);
- if (strncmp (buffer, "reset", 4)) {
- memset (&dasd_global_profile, 0, sizeof (dasd_profile_info_t));
- }
- return user_len;
- }
- static struct file_operations dasd_statistics_file_ops = {
- read:dasd_generic_read, /* read */
- open:dasd_statistics_open, /* open */
- write:dasd_statistics_write, /* write */
- release:dasd_devices_close, /* close */
- };
- static struct inode_operations dasd_statistics_inode_ops = {
- };
- int
- dasd_proc_init (void)
- {
- int rc = 0;
- dasd_proc_root_entry = proc_mkdir ("dasd", &proc_root);
- dasd_devices_entry = create_proc_entry ("devices",
- S_IFREG | S_IRUGO | S_IWUSR,
- dasd_proc_root_entry);
- dasd_devices_entry->proc_fops = &dasd_devices_file_ops;
- dasd_devices_entry->proc_iops = &dasd_devices_inode_ops;
- dasd_statistics_entry = create_proc_entry ("statistics",
- S_IFREG | S_IRUGO | S_IWUSR,
- dasd_proc_root_entry);
- dasd_statistics_entry->proc_fops = &dasd_statistics_file_ops;
- dasd_statistics_entry->proc_iops = &dasd_statistics_inode_ops;
- return rc;
- }
- void
- dasd_proc_cleanup (void)
- {
- remove_proc_entry ("devices", dasd_proc_root_entry);
- remove_proc_entry ("statistics", dasd_proc_root_entry);
- remove_proc_entry ("dasd", &proc_root);
- }
- int
- dasd_request_module ( void *name ) {
- int rc = -ERESTARTSYS;
- strcpy(current->comm, name);
- daemonize();
- while ( current->fs->root == NULL ) { /* wait for root-FS */
- DECLARE_WAIT_QUEUE_HEAD(wait);
- sleep_on_timeout(&wait,HZ); /* wait in steps of one second */
- }
- while ( (rc=request_module(name)) != 0 ) {
- DECLARE_WAIT_QUEUE_HEAD(wait);
- printk ( KERN_INFO "request_module returned %d for %sn",
- rc,
- (char*)name);
- sleep_on_timeout(&wait,5* HZ); /* wait in steps of 5 seconds */
- }
- return rc;
- }
- /* SECTION: Initializing the driver */
- int __init
- dasd_init (void)
- {
- int rc = 0;
- int irq;
- major_info_t *major_info = NULL;
- struct list_head *l;
- printk (KERN_INFO PRINTK_HEADER "initializing...n");
- dasd_debug_area = debug_register (DASD_NAME, 0, 2, 5 * sizeof (long));
- debug_register_view (dasd_debug_area, &debug_sprintf_view);
- debug_register_view (dasd_debug_area, &debug_hex_ascii_view);
- init_waitqueue_head (&dasd_init_waitq);
- if (dasd_debug_area == NULL) {
- goto failed;
- }
- DASD_DRIVER_DEBUG_EVENT (0, dasd_init, "%s",
- "ENTRY");
- dasd_devfs_handle = devfs_mk_dir (NULL, DASD_NAME, NULL);
- if (dasd_devfs_handle < 0) {
- DASD_DRIVER_DEBUG_EVENT (1, dasd_init, "%s",
- "no devfs");
- goto failed;
- }
- list_for_each (l, &dasd_major_info[0].list) {
- major_info = list_entry (l, major_info_t, list);
- if ((rc = dasd_register_major (major_info)) > 0) {
- DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
- "major %d: success",
- major_info->gendisk.major);
- printk (KERN_INFO PRINTK_HEADER
- "Registered successfully to major no %un",
- major_info->gendisk.major);
- } else {
- DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
- "major %d: failed",
- major_info->gendisk.major);
- printk (KERN_WARNING PRINTK_HEADER
- "Couldn't register successfully to major no %dn",
- major_info->gendisk.major);
- /* revert registration of major infos */
- goto failed;
- }
- }
- #ifndef MODULE
- dasd_split_parm_string (dasd_parm_string);
- #endif /* ! MODULE */
- rc = dasd_parse (dasd);
- if (rc) {
- DASD_DRIVER_DEBUG_EVENT (1, dasd_init, "%s",
- "invalid range found");
- goto failed;
- }
- rc = dasd_proc_init ();
- if (rc) {
- DASD_DRIVER_DEBUG_EVENT (1, dasd_init, "%s", "no proc-FS");
- goto failed;
- }
- genhd_dasd_name = dasd_device_name;
- genhd_dasd_ioctl = dasd_ioctl;
- if (dasd_autodetect) { /* update device range to all devices */
- for (irq = get_irq_first (); irq != -ENODEV;
- irq = get_irq_next (irq)) {
- int devno = get_devno_by_irq (irq);
- int index = dasd_devindex_from_devno (devno);
- if (index == -ENODEV) { /* not included in ranges */
- DASD_DRIVER_DEBUG_EVENT (2, dasd_init,
- "add %04x to range",
- devno);
- dasd_add_range (devno, devno, DASD_DEFAULT_FEATURES);
- }
- }
- }
- if (MACHINE_IS_VM) {
- #ifdef CONFIG_DASD_DIAG
- rc = dasd_diag_init ();
- if (rc == 0) {
- DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
- "DIAG discipline %s",
- "success");
- printk (KERN_INFO PRINTK_HEADER
- "Registered DIAG discipline successfullyn");
- } else {
- DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
- "DIAG discipline %s",
- "failed");
- goto failed;
- }
- #endif /* CONFIG_DASD_DIAG */
- #if defined(CONFIG_DASD_DIAG_MODULE) && defined(CONFIG_DASD_AUTO_DIAG)
- kernel_thread(dasd_request_module,"dasd_diag_mod",SIGCHLD);
- #endif /* CONFIG_DASD_AUTO_DIAG */
- }
- #ifdef CONFIG_DASD_ECKD
- rc = dasd_eckd_init ();
- if (rc == 0) {
- DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
- "ECKD discipline %s", "success");
- printk (KERN_INFO PRINTK_HEADER
- "Registered ECKD discipline successfullyn");
- } else {
- DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
- "ECKD discipline %s", "failed");
- goto failed;
- }
- #endif /* CONFIG_DASD_ECKD */
- #if defined(CONFIG_DASD_ECKD_MODULE) && defined(CONFIG_DASD_AUTO_ECKD)
- kernel_thread(dasd_request_module,"dasd_eckd_mod",SIGCHLD);
- #endif /* CONFIG_DASD_AUTO_ECKD */
- #ifdef CONFIG_DASD_FBA
- rc = dasd_fba_init ();
- if (rc == 0) {
- DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
- "FBA discipline %s", "success");
- printk (KERN_INFO PRINTK_HEADER
- "Registered FBA discipline successfullyn");
- } else {
- DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
- "FBA discipline %s", "failed");
- goto failed;
- }
- #endif /* CONFIG_DASD_FBA */
- #if defined(CONFIG_DASD_FBA_MODULE) && defined(CONFIG_DASD_AUTO_FBA)
- kernel_thread(dasd_request_module,"dasd_fba_mod",SIGCHLD);
- #endif /* CONFIG_DASD_AUTO_FBA */
- {
- char **disc=dasd_disciplines;
- while (*disc) {
- kernel_thread(dasd_request_module,*disc,SIGCHLD);
- disc++;
- }
- }
- rc = 0;
- goto out;
- failed:
- printk (KERN_INFO PRINTK_HEADER
- "initialization not performed due to errorsn");
- cleanup_dasd ();
- out:
- DASD_DRIVER_DEBUG_EVENT (0, dasd_init, "%s", "LEAVE");
- printk (KERN_INFO PRINTK_HEADER "initialization finishedn");
- return rc;
- }
- static void
- cleanup_dasd (void)
- {
- int i,rc=0;
- major_info_t *major_info = NULL;
- struct list_head *l,*n;
- dasd_range_t *range;
- printk (KERN_INFO PRINTK_HEADER "shutting downn");
- DASD_DRIVER_DEBUG_EVENT(0,"cleanup_dasd","%s","ENTRY");
- dasd_disable_ranges (&dasd_range_head, NULL, 1, 1);
- if (MACHINE_IS_VM) {
- #ifdef CONFIG_DASD_DIAG
- dasd_diag_cleanup ();
- DASD_DRIVER_DEBUG_EVENT (1, "cleanup_dasd",
- "DIAG discipline %s", "success");
- printk (KERN_INFO PRINTK_HEADER
- "De-Registered DIAG discipline successfullyn");
- #endif /* CONFIG_DASD_ECKD_BUILTIN */
- }
- #ifdef CONFIG_DASD_FBA
- dasd_fba_cleanup ();
- DASD_DRIVER_DEBUG_EVENT (1, "cleanup_dasd",
- "FBA discipline %s", "success");
- printk (KERN_INFO PRINTK_HEADER
- "De-Registered FBA discipline successfullyn");
- #endif /* CONFIG_DASD_ECKD_BUILTIN */
- #ifdef CONFIG_DASD_ECKD
- dasd_eckd_cleanup ();
- DASD_DRIVER_DEBUG_EVENT (1, "cleanup_dasd",
- "ECKD discipline %s", "success");
- printk (KERN_INFO PRINTK_HEADER
- "De-Registered ECKD discipline successfullyn");
- #endif /* CONFIG_DASD_ECKD_BUILTIN */
- genhd_dasd_name = NULL;
- genhd_dasd_ioctl = NULL;
- dasd_proc_cleanup ();
-
- list_for_each_safe (l, n, &dasd_major_info[0].list) {
- major_info = list_entry (l, major_info_t, list);
- for (i = 0; i < DASD_PER_MAJOR; i++) {
- kfree (major_info->dasd_device[i]);
- }
- if ((major_info->flags & DASD_MAJOR_INFO_REGISTERED) &&
- (rc = dasd_unregister_major (major_info)) == 0) {
- DASD_DRIVER_DEBUG_EVENT (1, "cleanup_dasd",
- "major %d: success",
- major_info->gendisk.major);
- printk (KERN_INFO PRINTK_HEADER
- "Unregistered successfully from major no %un",
- major_info->gendisk.major);
- } else {
- DASD_DRIVER_DEBUG_EVENT (1, "cleanup_dasd",
- "major %d: failed",
- major_info->gendisk.major);
- printk (KERN_WARNING PRINTK_HEADER
- "Couldn't unregister successfully from major no %d rc = %dn",
- major_info->gendisk.major, rc);
- }
- }
- list_for_each_safe (l, n, &dasd_range_head.list) {
- range = list_entry (l, dasd_range_t, list);
- dasd_remove_range(range);
- }
- #ifndef MODULE
- for( i = 0; i < 256; i++ )
- if ( dasd[i] ) {
- kfree(dasd[i]);
- dasd[i] = NULL;
- }
- #endif /* MODULE */
- if (dasd_devfs_handle)
- devfs_unregister(dasd_devfs_handle);
- if (dasd_debug_area != NULL )
- debug_unregister(dasd_debug_area);
- printk (KERN_INFO PRINTK_HEADER "shutdown completedn");
- DASD_DRIVER_DEBUG_EVENT(0,"cleanup_dasd","%s","LEAVE");
- }
- #ifdef MODULE
- int
- init_module (void)
- {
- int rc = 0;
- rc = dasd_init ();
- return rc;
- }
- void
- cleanup_module (void)
- {
- cleanup_dasd ();
- return;
- }
- #endif
- /*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
- * tab-width: 8
- * End:
- */