From: Martin Schwidefsky dasd device driver changes: - After a state change interrupt restart all running i/o on queue and reset device timer. - Improve some debug messages. - Lower timeout of reserve/release/steal_lock to 2 seconds. - Fix BIODASDPSRD ioctl. - Replace ro_flag, use_diag_flag and disconnect_error_flag words by bits. - Use BLKPG_DEL_PARTITION ioctl instead of a call to delete_partition because delete_partition is not an exported function. Since dasd_destroy_partitions can't do blkdev_get because dasd_open would fail, keep the block device open as long as partitions exist. This in turn requires a different approach to the open vs. offline race. --- 25-akpm/drivers/s390/block/dasd.c | 108 +++++++++++++++++------------ 25-akpm/drivers/s390/block/dasd_3990_erp.c | 22 +++-- 25-akpm/drivers/s390/block/dasd_devmap.c | 19 +++-- 25-akpm/drivers/s390/block/dasd_eckd.c | 9 +- 25-akpm/drivers/s390/block/dasd_genhd.c | 62 ++++++++++++---- 25-akpm/drivers/s390/block/dasd_int.h | 15 ++-- 25-akpm/drivers/s390/block/dasd_ioctl.c | 11 +- 25-akpm/drivers/s390/block/dasd_proc.c | 4 - 8 files changed, 158 insertions(+), 92 deletions(-) diff -puN drivers/s390/block/dasd_3990_erp.c~s390-dasd drivers/s390/block/dasd_3990_erp.c --- 25/drivers/s390/block/dasd_3990_erp.c~s390-dasd 2004-03-26 12:15:57.505906512 -0800 +++ 25-akpm/drivers/s390/block/dasd_3990_erp.c 2004-03-26 12:15:57.523903776 -0800 @@ -5,7 +5,7 @@ * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000, 2001 * - * $Revision: 1.27 $ + * $Revision: 1.28 $ */ #include @@ -229,7 +229,7 @@ dasd_3990_erp_block_queue(struct dasd_cc struct dasd_device *device = erp->device; DEV_MESSAGE(KERN_INFO, device, - "blocking request queue for %is", expires); + "blocking request queue for %is", expires/HZ); device->stopped |= DASD_STOPPED_PENDING; erp->status = DASD_CQR_QUEUED; @@ -2623,7 +2623,7 @@ dasd_3990_erp_action(struct dasd_ccw_req #ifdef ERP_DEBUG /* print current erp_chain */ - DEV_MESSAGE(KERN_DEBUG, device, "%s", + DEV_MESSAGE(KERN_ERR, device, "%s", "ERP chain at BEGINNING of ERP-ACTION"); { struct dasd_ccw_req *temp_erp = NULL; @@ -2631,9 +2631,10 @@ dasd_3990_erp_action(struct dasd_ccw_req for (temp_erp = cqr; temp_erp != NULL; temp_erp = temp_erp->refers) { - DEV_MESSAGE(KERN_DEBUG, device, - " erp %p refers to %p", - temp_erp, temp_erp->refers); + DEV_MESSAGE(KERN_ERR, device, + " erp %p (%02x) refers to %p", + temp_erp, temp_erp->status, + temp_erp->refers); } } #endif /* ERP_DEBUG */ @@ -2675,15 +2676,16 @@ dasd_3990_erp_action(struct dasd_ccw_req #ifdef ERP_DEBUG /* print current erp_chain */ - DEV_MESSAGE(KERN_DEBUG, device, "%s", "ERP chain at END of ERP-ACTION"); + DEV_MESSAGE(KERN_ERR, device, "%s", "ERP chain at END of ERP-ACTION"); { struct dasd_ccw_req *temp_erp = NULL; for (temp_erp = erp; temp_erp != NULL; temp_erp = temp_erp->refers) { - DEV_MESSAGE(KERN_DEBUG, device, - " erp %p refers to %p", - temp_erp, temp_erp->refers); + DEV_MESSAGE(KERN_ERR, device, + " erp %p (%02x) refers to %p", + temp_erp, temp_erp->status, + temp_erp->refers); } } #endif /* ERP_DEBUG */ diff -puN drivers/s390/block/dasd.c~s390-dasd drivers/s390/block/dasd.c --- 25/drivers/s390/block/dasd.c~s390-dasd 2004-03-26 12:15:57.506906360 -0800 +++ 25-akpm/drivers/s390/block/dasd.c 2004-03-26 12:15:57.521904080 -0800 @@ -7,7 +7,7 @@ * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001 * - * $Revision: 1.133 $ + * $Revision: 1.136 $ */ #include @@ -224,7 +224,8 @@ dasd_state_basic_to_ready(struct dasd_de return rc; dasd_setup_queue(device); device->state = DASD_STATE_READY; - dasd_scan_partitions(device); + if (dasd_scan_partitions(device) != 0) + device->state = DASD_STATE_BASIC; return 0; } @@ -687,7 +688,10 @@ dasd_term_IO(struct dasd_ccw_req * cqr) rc = ccw_device_clear(device->cdev, (long) cqr); switch (rc) { case 0: /* termination successful */ - cqr->status = DASD_CQR_FAILED; + if (cqr->retries > 0) + cqr->status = DASD_CQR_QUEUED; + else + cqr->status = DASD_CQR_FAILED; cqr->stopclk = get_clock(); break; case -ENODEV: @@ -779,7 +783,7 @@ dasd_timeout_device(unsigned long ptr) device = (struct dasd_device *) ptr; spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); - /* re-activate first request in queue */ + /* re-activate request queue */ device->stopped &= ~DASD_STOPPED_PENDING; spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); dasd_schedule_bh(device); @@ -827,12 +831,25 @@ do_state_change_pending(void *data) struct dasd_device *device; } *p; struct dasd_device *device; + struct dasd_ccw_req *cqr; + struct list_head *l, *n; + unsigned long flags; p = data; device = p->device; DBF_EVENT(DBF_NOTICE, "State change Interrupt for bus_id %s", device->cdev->dev.bus_id); device->stopped &= ~DASD_STOPPED_PENDING; + + /* restart all 'running' IO on queue */ + spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); + list_for_each_safe(l, n, &device->ccw_queue) { + cqr = list_entry(l, struct dasd_ccw_req, list); + if (cqr->status == DASD_CQR_IN_IO) + cqr->status = DASD_CQR_QUEUED; + } + spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); + dasd_set_timer (device, 0); dasd_schedule_bh(device); dasd_put_device(device); kfree(p); @@ -847,7 +864,8 @@ dasd_handle_killed_request(struct ccw_de cqr = (struct dasd_ccw_req *) intparm; if (cqr->status != DASD_CQR_IN_IO) { MESSAGE(KERN_DEBUG, - "invalid status: bus_id %s, status %02x", + "invalid status in handle_killed_request: " + "bus_id %s, status %02x", cdev->dev.bus_id, cqr->status); return; } @@ -1142,7 +1160,8 @@ __dasd_process_blk_queue(struct dasd_dev elv_next_request(queue) && nr_queued < DASD_CHANQ_MAX_SIZE) { req = elv_next_request(queue); - if (device->ro_flag && rq_data_dir(req) == WRITE) { + if (test_bit(DASD_FLAG_RO, &device->flags) && + rq_data_dir(req) == WRITE) { DBF_EVENT(DBF_ERR, "(%s) Rejecting write request %p", device->cdev->dev.bus_id, @@ -1186,13 +1205,11 @@ static inline void __dasd_check_expire(struct dasd_device * device) { struct dasd_ccw_req *cqr; - unsigned long long now; if (list_empty(&device->ccw_queue)) return; cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list); if (cqr->status == DASD_CQR_IN_IO && cqr->expires != 0) { - now = get_clock(); if (time_after_eq(jiffies, cqr->expires + cqr->starttime)) { if (device->discipline->term_IO(cqr) != 0) /* Hmpf, try again in 1/100 sec */ @@ -1517,7 +1534,8 @@ dasd_sleep_on_immediatly(struct dasd_ccw * terminated if it is currently in i/o. * Returns 1 if the request has been terminated. */ -int dasd_cancel_req(struct dasd_ccw_req *cqr) +int +dasd_cancel_req(struct dasd_ccw_req *cqr) { struct dasd_device *device = cqr->device; unsigned long flags; @@ -1655,18 +1673,13 @@ dasd_open(struct inode *inp, struct file { struct gendisk *disk = inp->i_bdev->bd_disk; struct dasd_device *device = disk->private_data; - int old_count, rc; + int rc; - /* - * We use a negative value in open_count to indicate that - * the device must not be used. - */ - do { - old_count = atomic_read(&device->open_count); - if (old_count < 0) - return -ENODEV; - } while (atomic_compare_and_swap(old_count, old_count + 1, - &device->open_count)); + atomic_inc(&device->open_count); + if (test_bit(DASD_FLAG_OFFLINE, &device->flags)) { + rc = -ENODEV; + goto unlock; + } if (!try_module_get(device->discipline->owner)) { rc = -EINVAL; @@ -1681,7 +1694,6 @@ dasd_open(struct inode *inp, struct file goto out; } - rc = -ENODEV; if (device->state < DASD_STATE_BASIC) { DBF_DEV_EVENT(DBF_ERR, device, " %s", " Cannot open unrecognized device"); @@ -1704,12 +1716,6 @@ dasd_release(struct inode *inp, struct f struct gendisk *disk = inp->i_bdev->bd_disk; struct dasd_device *device = disk->private_data; - if (device->state < DASD_STATE_BASIC) { - DBF_DEV_EVENT(DBF_ERR, device, " %s", - " Cannot release unrecognized device"); - return -EINVAL; - } - atomic_dec(&device->open_count); module_put(device->discipline->owner); return 0; @@ -1773,17 +1779,21 @@ dasd_generic_remove (struct ccw_device * dasd_remove_sysfs_files(cdev); device = dasd_device_from_cdev(cdev); - if (!IS_ERR(device)) { - /* - * This device is removed unconditionally. Set open_count - * to -1 to prevent dasd_open from opening it while it is - * no quite down yet. - */ - atomic_set(&device->open_count,-1); - dasd_set_target_state(device, DASD_STATE_NEW); - /* dasd_delete_device destroys the device reference. */ - dasd_delete_device(device); + if (IS_ERR(device)) + return; + if (test_and_set_bit(DASD_FLAG_OFFLINE, &device->flags)) { + /* Already doing offline processing */ + dasd_put_device(device); + return; } + /* + * This device is removed unconditionally. Set offline + * flag to prevent dasd_open from opening it while it is + * no quite down yet. + */ + dasd_set_target_state(device, DASD_STATE_NEW); + /* dasd_delete_device destroys the device reference. */ + dasd_delete_device(device); } /* activate a device. This is called from dasd_{eckd,fba}_probe() when either @@ -1801,7 +1811,7 @@ dasd_generic_set_online (struct ccw_devi if (IS_ERR(device)) return PTR_ERR(device); - if (device->use_diag_flag) { + if (test_bit(DASD_FLAG_USE_DIAG, &device->flags)) { if (!dasd_diag_discipline_pointer) { printk (KERN_WARNING "dasd_generic couldn't online device %s " @@ -1849,18 +1859,28 @@ int dasd_generic_set_offline (struct ccw_device *cdev) { struct dasd_device *device; + int max_count; device = dasd_device_from_cdev(cdev); + if (IS_ERR(device)) + return PTR_ERR(device); + if (test_and_set_bit(DASD_FLAG_OFFLINE, &device->flags)) { + /* Already doing offline processing */ + dasd_put_device(device); + return 0; + } /* - * We must make sure that this device is currently not in use - * (current open_count == 0 ). We set open_count to -1 to indicate - * that from now on set_offline is in progress and the device must - * not be used otherwise. + * We must make sure that this device is currently not in use. + * The open_count is increased for every opener, that includes + * the blkdev_get in dasd_scan_partitions. We are only interested + * in the other openers. */ - if (atomic_compare_and_swap(0, -1, &device->open_count)) { + max_count = device->bdev ? 1 : 0; + if (atomic_read(&device->open_count) > max_count) { printk (KERN_WARNING "Can't offline dasd device with open" " count = %i.\n", atomic_read(&device->open_count)); + clear_bit(DASD_FLAG_OFFLINE, &device->flags); dasd_put_device(device); return -EBUSY; } @@ -1890,7 +1910,7 @@ dasd_generic_notify(struct ccw_device *c if (device->state < DASD_STATE_BASIC) break; /* Device is active. We want to keep it. */ - if (device->disconnect_error_flag) { + if (test_bit(DASD_FLAG_DSC_ERROR, &device->flags)) { list_for_each_entry(cqr, &device->ccw_queue, list) if (cqr->status == DASD_CQR_IN_IO) cqr->status = DASD_CQR_FAILED; diff -puN drivers/s390/block/dasd_devmap.c~s390-dasd drivers/s390/block/dasd_devmap.c --- 25/drivers/s390/block/dasd_devmap.c~s390-dasd 2004-03-26 12:15:57.508906056 -0800 +++ 25-akpm/drivers/s390/block/dasd_devmap.c 2004-03-26 12:15:57.524903624 -0800 @@ -11,7 +11,7 @@ * functions may not be called from interrupt context. In particular * dasd_get_device is a no-no from interrupt context. * - * $Revision: 1.26 $ + * $Revision: 1.27 $ */ #include @@ -466,10 +466,14 @@ dasd_create_device(struct ccw_device *cd if (!devmap->device) { devmap->device = device; device->devindex = devmap->devindex; - device->ro_flag = - (devmap->features & DASD_FEATURE_READONLY) != 0; - device->use_diag_flag = - (devmap->features & DASD_FEATURE_USEDIAG) != 0; + if (devmap->features & DASD_FEATURE_READONLY) + set_bit(DASD_FLAG_RO, &device->flags); + else + clear_bit(DASD_FLAG_RO, &device->flags); + if (devmap->features & DASD_FEATURE_USEDIAG) + set_bit(DASD_FLAG_USE_DIAG, &device->flags); + else + clear_bit(DASD_FLAG_USE_DIAG, &device->flags); get_device(&cdev->dev); device->cdev = cdev; rc = 0; @@ -596,7 +600,10 @@ dasd_ro_store(struct device *dev, const if (devmap->device) { if (devmap->device->gdp) set_disk_ro(devmap->device->gdp, ro_flag); - devmap->device->ro_flag = ro_flag; + if (ro_flag) + set_bit(DASD_FLAG_RO, &devmap->device->flags); + else + clear_bit(DASD_FLAG_RO, &devmap->device->flags); } spin_unlock(&dasd_devmap_lock); return count; diff -puN drivers/s390/block/dasd_eckd.c~s390-dasd drivers/s390/block/dasd_eckd.c --- 25/drivers/s390/block/dasd_eckd.c~s390-dasd 2004-03-26 12:15:57.510905752 -0800 +++ 25-akpm/drivers/s390/block/dasd_eckd.c 2004-03-26 12:15:57.525903472 -0800 @@ -7,7 +7,7 @@ * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * - * $Revision: 1.51 $ + * $Revision: 1.53 $ */ #include @@ -1131,7 +1131,7 @@ dasd_eckd_release(struct block_device *b cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; cqr->device = device; cqr->retries = 0; - cqr->expires = 10 * HZ; + cqr->expires = 2 * HZ; cqr->buildclk = get_clock(); cqr->status = DASD_CQR_FILLED; @@ -1174,7 +1174,7 @@ dasd_eckd_reserve(struct block_device *b cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; cqr->device = device; cqr->retries = 0; - cqr->expires = 10 * HZ; + cqr->expires = 2 * HZ; cqr->buildclk = get_clock(); cqr->status = DASD_CQR_FILLED; @@ -1216,7 +1216,7 @@ dasd_eckd_steal_lock(struct block_device cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; cqr->device = device; cqr->retries = 0; - cqr->expires = 10 * HZ; + cqr->expires = 2 * HZ; cqr->buildclk = get_clock(); cqr->status = DASD_CQR_FILLED; @@ -1274,6 +1274,7 @@ dasd_eckd_performance(struct block_devic stats = (struct dasd_rssd_perf_stats_t *) (prssdp + 1); memset(stats, 0, sizeof (struct dasd_rssd_perf_stats_t)); + ccw++; ccw->cmd_code = DASD_ECKD_CCW_RSSD; ccw->count = sizeof (struct dasd_rssd_perf_stats_t); ccw->cda = (__u32)(addr_t) stats; diff -puN drivers/s390/block/dasd_genhd.c~s390-dasd drivers/s390/block/dasd_genhd.c --- 25/drivers/s390/block/dasd_genhd.c~s390-dasd 2004-03-26 12:15:57.512905448 -0800 +++ 25-akpm/drivers/s390/block/dasd_genhd.c 2004-03-26 12:15:57.526903320 -0800 @@ -9,7 +9,7 @@ * * gendisk related functions for the dasd driver. * - * $Revision: 1.44 $ + * $Revision: 1.46 $ */ #include @@ -71,7 +71,7 @@ dasd_gendisk_alloc(struct dasd_device *d sprintf(gdp->devfs_name, "dasd/%s", device->cdev->dev.bus_id); - if (device->ro_flag) + if (test_bit(DASD_FLAG_RO, &device->flags)) set_disk_ro(gdp, 1); gdp->private_data = device; gdp->queue = device->request_queue; @@ -96,22 +96,33 @@ dasd_gendisk_free(struct dasd_device *de /* * Trigger a partition detection. */ -void +int dasd_scan_partitions(struct dasd_device * device) { struct block_device *bdev; /* Make the disk known. */ set_capacity(device->gdp, device->blocks << device->s2b_shift); - /* See fs/partition/check.c:register_disk,rescan_partitions */ bdev = bdget_disk(device->gdp, 0); - if (bdev) { - if (blkdev_get(bdev, FMODE_READ, 1) >= 0) { - /* Can't call rescan_partitions directly. Use ioctl. */ - ioctl_by_bdev(bdev, BLKRRPART, 0); - blkdev_put(bdev); - } - } + if (!bdev || blkdev_get(bdev, FMODE_READ, 1) < 0) + return -ENODEV; + /* + * See fs/partition/check.c:register_disk,rescan_partitions + * Can't call rescan_partitions directly. Use ioctl. + */ + ioctl_by_bdev(bdev, BLKRRPART, 0); + /* + * Since the matching blkdev_put call to the blkdev_get in + * this function is not called before dasd_destroy_partitions + * the offline open_count limit needs to be increased from + * 0 to 1. This is done by setting device->bdev (see + * dasd_generic_set_offline). As long as the partition + * detection is running no offline should be allowed. That + * is why the assignment to device->bdev is done AFTER + * the BLKRRPART ioctl. + */ + device->bdev = bdev; + return 0; } /* @@ -121,13 +132,32 @@ dasd_scan_partitions(struct dasd_device void dasd_destroy_partitions(struct dasd_device * device) { - int p; + /* The two structs have 168/176 byte on 31/64 bit. */ + struct blkpg_partition bpart; + struct blkpg_ioctl_arg barg; + struct block_device *bdev; + + /* + * Get the bdev pointer from the device structure and clear + * device->bdev to lower the offline open_count limit again. + */ + bdev = device->bdev; + device->bdev = 0; + + /* + * See fs/partition/check.c:delete_partition + * Can't call delete_partitions directly. Use ioctl. + * The ioctl also does locking and invalidation. + */ + memset(&bpart, sizeof(struct blkpg_partition), 0); + memset(&barg, sizeof(struct blkpg_ioctl_arg), 0); + barg.data = &bpart; + for (bpart.pno = device->gdp->minors - 1; bpart.pno > 0; bpart.pno--) + ioctl_by_bdev(bdev, BLKPG_DEL_PARTITION, (unsigned long) &barg); - for (p = device->gdp->minors - 1; p > 0; p--) { - invalidate_partition(device->gdp, p); - delete_partition(device->gdp, p); - } invalidate_partition(device->gdp, 0); + /* Matching blkdev_put to the blkdev_get in dasd_scan_partitions. */ + blkdev_put(bdev); set_capacity(device->gdp, 0); } diff -puN drivers/s390/block/dasd_int.h~s390-dasd drivers/s390/block/dasd_int.h --- 25/drivers/s390/block/dasd_int.h~s390-dasd 2004-03-26 12:15:57.513905296 -0800 +++ 25-akpm/drivers/s390/block/dasd_int.h 2004-03-26 12:15:57.527903168 -0800 @@ -6,7 +6,7 @@ * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * - * $Revision: 1.55 $ + * $Revision: 1.56 $ */ #ifndef DASD_INT_H @@ -268,14 +268,12 @@ struct dasd_device { struct gendisk *gdp; request_queue_t *request_queue; spinlock_t request_queue_lock; + struct block_device *bdev; unsigned int devindex; unsigned long blocks; /* size of volume in blocks */ unsigned int bp_block; /* bytes per block */ unsigned int s2b_shift; /* log2 (bp_block/512) */ - int ro_flag; /* read-only flag */ - int use_diag_flag; /* diag allowed flag */ - int disconnect_error_flag; /* return -EIO when disconnected */ - + unsigned long flags; /* per device flags */ /* Device discipline stuff. */ struct dasd_discipline *discipline; @@ -318,6 +316,11 @@ struct dasd_device { #define DASD_STOPPED_DC_WAIT 8 /* disconnected, wait */ #define DASD_STOPPED_DC_EIO 16 /* disconnected, return -EIO */ +/* per device flags */ +#define DASD_FLAG_RO 0 /* device is read-only */ +#define DASD_FLAG_USE_DIAG 1 /* use diag disciplnie */ +#define DASD_FLAG_DSC_ERROR 2 /* return -EIO when disconnected */ +#define DASD_FLAG_OFFLINE 3 /* device is in offline processing */ void dasd_put_device_wake(struct dasd_device *); @@ -498,7 +501,7 @@ int dasd_gendisk_init(void); void dasd_gendisk_exit(void); int dasd_gendisk_alloc(struct dasd_device *); void dasd_gendisk_free(struct dasd_device *); -void dasd_scan_partitions(struct dasd_device *); +int dasd_scan_partitions(struct dasd_device *); void dasd_destroy_partitions(struct dasd_device *); /* externals in dasd_ioctl.c */ diff -puN drivers/s390/block/dasd_ioctl.c~s390-dasd drivers/s390/block/dasd_ioctl.c --- 25/drivers/s390/block/dasd_ioctl.c~s390-dasd 2004-03-26 12:15:57.515904992 -0800 +++ 25-akpm/drivers/s390/block/dasd_ioctl.c 2004-03-26 12:15:57.528903016 -0800 @@ -303,7 +303,7 @@ dasd_ioctl_format(struct block_device *b if (device == NULL) return -ENODEV; - if (device->ro_flag) + if (test_bit(DASD_FLAG_RO, &device->flags)) return -EROFS; if (copy_from_user(&fdata, (void *) args, sizeof (struct format_data_t))) @@ -415,8 +415,8 @@ dasd_ioctl_information(struct block_devi (dasd_check_blocksize(device->bp_block))) dasd_info->format = DASD_FORMAT_NONE; - dasd_info->features |= device->ro_flag ? DASD_FEATURE_READONLY - : DASD_FEATURE_DEFAULT; + dasd_info->features |= test_bit(DASD_FLAG_RO, &device->flags) ? + DASD_FEATURE_READONLY : DASD_FEATURE_DEFAULT; if (device->discipline) memcpy(dasd_info->type, device->discipline->name, 4); @@ -472,7 +472,10 @@ dasd_ioctl_set_ro(struct block_device *b if (device == NULL) return -ENODEV; set_disk_ro(bdev->bd_disk, intval); - device->ro_flag = intval; + if (intval) + set_bit(DASD_FLAG_RO, &device->flags); + else + clear_bit(DASD_FLAG_RO, &device->flags); return 0; } diff -puN drivers/s390/block/dasd_proc.c~s390-dasd drivers/s390/block/dasd_proc.c --- 25/drivers/s390/block/dasd_proc.c~s390-dasd 2004-03-26 12:15:57.516904840 -0800 +++ 25-akpm/drivers/s390/block/dasd_proc.c 2004-03-26 12:15:57.528903016 -0800 @@ -9,7 +9,7 @@ * * /proc interface for the dasd driver. * - * $Revision: 1.26 $ + * $Revision: 1.27 $ */ #include @@ -77,7 +77,7 @@ dasd_devices_show(struct seq_file *m, vo else seq_printf(m, " is ????????"); /* Print devices features. */ - substr = device->ro_flag ? "(ro)" : " "; + substr = test_bit(DASD_FLAG_RO, &device->flags) ? "(ro)" : " "; seq_printf(m, "%4s: ", substr); /* Print device status information. */ switch ((device != NULL) ? device->state : -1) { _