Messages in this thread Patch in this message | ![/](/images/icornerl.gif) | | From | Martin Schwidefsky <> | Subject | [PATCH] s390 (7/16): dasd driver fixes. | Date | Mon, 14 Apr 2003 19:50:13 +0200 |
| |
s390 dasd driver fixes: - Take request queue lock in dasd_end_request. - Make it work with CONFIG_DEVFS_FS=y. - Properly wait for the root device. - Cope with requests killed due to failed channel path. - Improve reference counting. - Remove devno from struct dasd_device. - Remove unnecessary bdget/bdput calls.
diffstat: Kconfig | 2 block/dasd.c | 241 +++++++++++++++++++++++++++++----------------------- block/dasd_devmap.c | 188 +++++++++++++++++++++++++++++++++------- block/dasd_diag.c | 10 +- block/dasd_eckd.c | 25 ++++- block/dasd_fba.c | 11 +- block/dasd_genhd.c | 12 +- block/dasd_int.h | 52 +++++------ block/dasd_ioctl.c | 3 block/dasd_proc.c | 11 -- 10 files changed, 363 insertions(+), 192 deletions(-)
diff -urN linux-2.5.67/drivers/s390/Kconfig linux-2.5.67-s390/drivers/s390/Kconfig --- linux-2.5.67/drivers/s390/Kconfig Mon Apr 7 19:32:28 2003 +++ linux-2.5.67-s390/drivers/s390/Kconfig Mon Apr 14 19:11:52 2003 @@ -164,7 +164,7 @@ config DASD_DIAG tristate "Support for DIAG access to CMS reserved Disks" - depends on DASD + depends on DASD && ARCH_S390X = 'n' help Select this option if you want to use CMS reserved Disks under VM with the Diagnose250 command. If you are not running under VM or diff -urN linux-2.5.67/drivers/s390/block/dasd.c linux-2.5.67-s390/drivers/s390/block/dasd.c --- linux-2.5.67/drivers/s390/block/dasd.c Mon Apr 7 19:31:14 2003 +++ linux-2.5.67-s390/drivers/s390/block/dasd.c Mon Apr 14 19:11:52 2003 @@ -7,7 +7,7 @@ * Bugreports.to..: <Linux390@de.ibm.com> * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001 * - * $Revision: 1.74 $ + * $Revision: 1.82 $ * * History of changes (starts July 2000) * 11/09/00 complete redesign after code review @@ -101,7 +101,7 @@ * Allocate memory for a new device structure. */ dasd_device_t * -dasd_alloc_device(dasd_devmap_t *devmap) +dasd_alloc_device(unsigned int devindex) { dasd_device_t *device; struct gendisk *gdp; @@ -111,8 +111,6 @@ return ERR_PTR(-ENOMEM); memset(device, 0, sizeof (dasd_device_t)); - device->devno = devmap->devno; - /* Get two pages for normal block device operations. */ device->ccw_mem = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, 1); if (device->ccw_mem == NULL) { @@ -128,7 +126,7 @@ } /* Allocate gendisk structure for device. */ - gdp = dasd_gendisk_alloc(devmap->devindex); + gdp = dasd_gendisk_alloc(devindex); if (IS_ERR(gdp)) { free_page((unsigned long) device->erp_mem); free_pages((unsigned long) device->ccw_mem, 1); @@ -147,7 +145,7 @@ (unsigned long) device); INIT_LIST_HEAD(&device->ccw_queue); init_timer(&device->timer); - INIT_WORK(&device->kick_work, do_kick_device, (void *) (addr_t) device->devno); + INIT_WORK(&device->kick_work, do_kick_device, device); device->state = DASD_STATE_NEW; device->target = DASD_STATE_NEW; @@ -174,35 +172,35 @@ static inline int dasd_state_new_to_known(dasd_device_t *device) { - dasd_devmap_t *devmap; umode_t devfs_perm; - devfs_handle_t dir; - int major, minor; + kdev_t kdev; char buf[20]; - /* Increase reference count of bdev. */ - if (bdget(MKDEV(device->gdp->major, device->gdp->first_minor)) == NULL) + kdev = dasd_get_kdev(device); + if (kdev_none(kdev)) return -ENODEV; - devmap = dasd_devmap_from_devno(device->devno); - if (devmap == NULL) - return -ENODEV; - major = dasd_gendisk_index_major(devmap->devindex); - if (major < 0) - return -ENODEV; - minor = devmap->devindex % DASD_PER_MAJOR; + /* + * As long as the device is not in state DASD_STATE_NEW we want to + * keep the reference count > 0. + */ + dasd_get_device(device); +#ifdef CONFIG_DEVFS_FS /* Add a proc directory and the dasd device entry to devfs. */ - dir = devfs_mk_dir("dasd/%04x", device->devno); - device->gdp->de = dir; + device->gdp->de = devfs_mk_dir("dasd/%04x", + _ccw_device_get_device_number(device->cdev)); +#endif if (device->ro_flag) devfs_perm = S_IFBLK | S_IRUSR; else devfs_perm = S_IFBLK | S_IRUSR | S_IWUSR; - snprintf(buf, sizeof(buf), "dasd/%04x/device", device->devno); + snprintf(buf, sizeof(buf), "dasd/%04x/device", + _ccw_device_get_device_number(device->cdev)); device->devfs_entry = devfs_register(NULL, buf, 0, - major, minor << DASD_PARTN_BITS, + major(kdev), + minor(kdev) << DASD_PARTN_BITS, devfs_perm, &dasd_device_operations, NULL); device->state = DASD_STATE_KNOWN; @@ -215,8 +213,6 @@ static inline void dasd_state_known_to_new(dasd_device_t * device) { - struct block_device *bdev; - /* Remove device entry and devfs directory. */ devfs_unregister(device->devfs_entry); devfs_unregister(device->gdp->de); @@ -225,10 +221,8 @@ device->discipline = NULL; device->state = DASD_STATE_NEW; - /* Decrease reference count of bdev. */ - bdev = bdget(MKDEV(device->gdp->major, device->gdp->first_minor)); - bdput(bdev); - bdput(bdev); + /* Give up reference we took in dasd_state_new_to_known. */ + dasd_put_device(device); } /* @@ -428,7 +422,8 @@ if (rc && rc != -EAGAIN) { if (rc != -ENODEV) MESSAGE (KERN_INFO, "giving up on dasd device with " - "devno %04x", device->devno); + "devno %04x", + _ccw_device_get_device_number(device->cdev)); device->target = device->state; } @@ -445,26 +440,18 @@ static void do_kick_device(void *data) { - int devno; - dasd_devmap_t *devmap; dasd_device_t *device; - devno = (long) data; - devmap = dasd_devmap_from_devno(devno); - device = (devmap != NULL) ? - dasd_get_device(devmap) : ERR_PTR(-ENODEV); - if (IS_ERR(device)) - return; - atomic_dec(&device->ref_count); + device = (dasd_device_t *) data; dasd_change_state(device); dasd_schedule_bh(device); - dasd_put_device(devmap); + dasd_put_device(device); } void dasd_kick_device(dasd_device_t *device) { - atomic_inc(&device->ref_count); + dasd_get_device(device); /* queue call to dasd_kick_device to the kernel event daemon. */ schedule_work(&device->kick_work); } @@ -646,7 +633,7 @@ } strncpy((char *) &cqr->magic, magic, 4); ASCEBC((char *) &cqr->magic, 4); - atomic_inc(&device->ref_count); + dasd_get_device(device); return cqr; } @@ -693,7 +680,7 @@ } strncpy((char *) &cqr->magic, magic, 4); ASCEBC((char *) &cqr->magic, 4); - atomic_inc(&device->ref_count); + dasd_get_device(device); return cqr; } @@ -723,7 +710,7 @@ if (cqr->data != NULL) kfree(cqr->data); kfree(cqr); - atomic_dec(&device->ref_count); + dasd_put_device(device); } void @@ -738,7 +725,7 @@ spin_lock_irqsave(&device->mem_lock, flags); dasd_free_chunk(&device->ccw_chunks, cqr); spin_unlock_irqrestore(&device->mem_lock, flags); - atomic_dec(&device->ref_count); + dasd_put_device(device); } /* @@ -936,19 +923,14 @@ struct work_struct work; dasd_device_t *device; } *p; - dasd_devmap_t *devmap; dasd_device_t *device; dasd_ccw_req_t *cqr; - int devno; p = data; device = p->device; DBF_EVENT(DBF_NOTICE, "State change Interrupt for bus_id %s", device->cdev->dev.bus_id); - // FIXME: get rid of devmap. - devno = _ccw_device_get_device_number(device->cdev); - devmap = dasd_devmap_from_devno(devno); spin_lock_irq(get_ccwdev_lock(device->cdev)); /* re-activate first request in queue */ if (!list_empty(&device->ccw_queue)) { @@ -965,10 +947,39 @@ } spin_unlock_irq(get_ccwdev_lock(device->cdev)); dasd_schedule_bh(device); - dasd_put_device(devmap); + dasd_put_device(device); kfree(p); } +static void +dasd_handle_killed_request(struct ccw_device *cdev, unsigned long intparm) +{ + dasd_ccw_req_t *cqr; + dasd_device_t *device; + + cqr = (dasd_ccw_req_t *) intparm; + if (cqr->status != DASD_CQR_IN_IO) { + MESSAGE(KERN_DEBUG, + "invalid status: bus_id %s, status %02x", + cdev->dev.bus_id, cqr->status); + return; + } + + device = (dasd_device_t *) cqr->device; + if (device == NULL || + device != cdev->dev.driver_data || + strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) { + MESSAGE(KERN_DEBUG, "invalid device in request: bus_id %s", + cdev->dev.bus_id); + return; + } + + /* Schedule request to be retried. */ + cqr->status = DASD_CQR_QUEUED; + + dasd_clear_timer(device); + dasd_schedule_bh(device); +} static void dasd_handle_state_change_pending(dasd_device_t *device) @@ -984,8 +995,7 @@ return; INIT_WORK(&p->work, (void *) do_state_change_pending, p); p->device = device; - atomic_inc(&device->ref_count); - /* queue call to do_state_change_pending to the kernel event daemon. */ + dasd_get_device(device); schedule_work(&p->work); } @@ -1003,6 +1013,23 @@ dasd_era_t era; char mask; + if (IS_ERR(irb)) { + switch (PTR_ERR(irb)) { + case -EIO: + dasd_handle_killed_request(cdev, intparm); + break; + case -ETIMEDOUT: + printk(KERN_WARNING"%s(%s): request timed out\n", + __FUNCTION__, cdev->dev.bus_id); + //FIXME - dasd uses own timeout interface... + break; + default: + printk(KERN_WARNING"%s(%s): unknown error %ld\n", + __FUNCTION__, cdev->dev.bus_id, PTR_ERR(irb)); + } + return; + } + now = get_clock(); DBF_EVENT(DBF_DEBUG, "Interrupt: stat %02x, bus_id %s", @@ -1108,7 +1135,6 @@ BUG(); add_disk_randomness(req->rq_disk); end_that_request_last(req); - return; } /* @@ -1177,7 +1203,9 @@ req = (struct request *) data; dasd_profile_end(cqr->device, cqr, req); + spin_lock_irq(&cqr->device->request_queue_lock); dasd_end_request(req, (cqr->status == DASD_CQR_DONE)); + spin_unlock_irq(&cqr->device->request_queue_lock); dasd_sfree_request(cqr, cqr->device); } @@ -1189,7 +1217,6 @@ __dasd_process_blk_queue(dasd_device_t * device) { request_queue_t *queue; - struct list_head *l; struct request *req; dasd_ccw_req_t *cqr; int nr_queued; @@ -1211,11 +1238,9 @@ return; nr_queued = 0; /* Now we try to fetch requests from the request queue */ - list_for_each(l, &device->ccw_queue) { - cqr = list_entry(l, dasd_ccw_req_t, list); + list_for_each_entry(cqr, &device->ccw_queue, list) if (cqr->status == DASD_CQR_QUEUED) nr_queued++; - } while (!blk_queue_plugged(queue) && elv_next_request(queue) && nr_queued < DASD_CHANQ_MAX_SIZE) { @@ -1223,7 +1248,8 @@ if (device->ro_flag && rq_data_dir(req) == WRITE) { DBF_EVENT(DBF_ERR, "(%04x) Rejecting write request %p", - device->devno, req); + _ccw_device_get_device_number(device->cdev), + req); blkdev_dequeue_request(req); dasd_end_request(req, 0); continue; @@ -1234,7 +1260,8 @@ break; /* terminate request queue loop */ DBF_EVENT(DBF_ERR, "(%04x) CCW creation failed on request %p", - device->devno, req); + _ccw_device_get_device_number(device->cdev), + req); blkdev_dequeue_request(req); dasd_end_request(req, 0); continue; @@ -1371,8 +1398,7 @@ __dasd_start_head(device); spin_unlock(get_ccwdev_lock(device->cdev)); spin_unlock_irq(&device->request_queue_lock); - /* FIXME: what if ref_count == 0 && state == DASD_STATE_NEW ?? */ - atomic_dec(&device->ref_count); + dasd_put_device(device); } /* @@ -1384,7 +1410,7 @@ /* Protect against rescheduling. */ if (atomic_compare_and_swap (0, 1, &device->tasklet_scheduled)) return; - atomic_inc(&device->ref_count); + dasd_get_device(device); tasklet_hi_schedule(&device->tasklet); } @@ -1766,8 +1792,8 @@ return 0; } -struct -block_device_operations dasd_device_operations = { +struct block_device_operations +dasd_device_operations = { .owner = THIS_MODULE, .open = dasd_open, .release = dasd_release, @@ -1823,12 +1849,6 @@ cdev->handler = &dasd_int_handler; - if (dasd_autodetect || - dasd_devmap_from_devno(devno) != 0) { - /* => device was in dasd parameter line */ - ccw_device_set_online(cdev); - } - return ret; } @@ -1854,30 +1874,12 @@ dasd_discipline_t *discipline) { - int devno; - dasd_devmap_t *devmap; dasd_device_t *device; int rc; - if (cdev->dev.driver_data != NULL) /* already enabled */ - return 0; - - devno = _ccw_device_get_device_number(cdev); - rc = dasd_add_range(devno, devno, DASD_FEATURE_DEFAULT); - if (rc) - return rc; - - if (!(devmap = dasd_devmap_from_devno (devno))) - return 0; /* device is still disabled -> ignore it */ - - if (IS_ERR(device = dasd_get_device(devmap))) { - printk (KERN_WARNING "dasd_generic could not get %s\n", - cdev->dev.bus_id); + device = dasd_create_device(cdev); + if (IS_ERR(device)) return PTR_ERR(device); - } - - device->gdp->driverfs_dev = &cdev->dev; - device->cdev = cdev; if (device->use_diag_flag) device->discipline = dasd_diag_discipline_pointer; @@ -1898,7 +1900,7 @@ if (rc) { printk (KERN_WARNING "dasd_generic found a bad device %s\n", cdev->dev.bus_id); - dasd_put_device(devmap); + dasd_delete_device(device); return rc; } @@ -1909,16 +1911,17 @@ cdev->dev.bus_id); rc = -ENODEV; dasd_set_target_state(device, DASD_STATE_NEW); + dasd_delete_device(device); } else { pr_debug("dasd_generic device %s found\n", cdev->dev.bus_id); cdev->dev.driver_data = device; } - dasd_put_device(devmap); /* FIXME: we have to wait for the root device but we don't want * to wait for each single device but for all at once. */ wait_event(dasd_init_waitq, _wait_for_device(device)); + return rc; } @@ -1926,26 +1929,52 @@ dasd_generic_set_offline (struct ccw_device *cdev) { dasd_device_t *device; - dasd_devmap_t *devmap; - int devno; - devno = _ccw_device_get_device_number(cdev); device = cdev->dev.driver_data; - devmap = dasd_devmap_from_devno(devno); - if (device == NULL || devmap == NULL) - return -ENODEV; - - device = dasd_get_device(devmap); - if (IS_ERR(device)) - return PTR_ERR(device); - + if (atomic_read(&device->open_count) > 0) { + printk (KERN_WARNING "Can't offline dasd device with open" + " count = %i.\n", + atomic_read(&device->open_count)); + return -EBUSY; + } dasd_set_target_state(device, DASD_STATE_NEW); - dasd_put_device(devmap); + dasd_delete_device(device); return 0; } /* + * Automatically online either all dasd devices (dasd_autodetect) or + * all devices specified with dasd= parameters. For dasd_autodetect + * dasd_generic_probe has added devmaps for all dasd devices. We + * scan all present dasd devmaps and call ccw_device_set_online. + */ +void +dasd_generic_auto_online (struct ccw_driver *dasd_discipline_driver) +{ + struct device_driver *drv; + struct device *d, *dev; + struct ccw_device *cdev; + int devno; + + drv = get_driver(&dasd_discipline_driver->driver); + down_read(&drv->bus->subsys.rwsem); + dev = NULL; + list_for_each_entry(d, &drv->devices, driver_list) { + dev = get_device(d); + if (!dev) + continue; + cdev = to_ccwdev(dev); + devno = _ccw_device_get_device_number(cdev); + if (dasd_autodetect || dasd_devno_in_range(devno) == 0) + ccw_device_set_online(cdev); + put_device(dev); + } + up_read(&drv->bus->subsys.rwsem); + put_driver(drv); +} + +/* * SECTION: files in sysfs */ @@ -2078,11 +2107,13 @@ DBF_EVENT(DBF_EMERG, "%s", "debug area created"); - if (devfs_mk_dir("dasd")) { +#ifdef CONFIG_DEVFS_FS + if (!devfs_mk_dir("dasd")) { DBF_EVENT(DBF_ALERT, "%s", "no devfs"); rc = -ENOSYS; goto failed; } +#endif rc = dasd_devmap_init(); if (rc) goto failed; diff -urN linux-2.5.67/drivers/s390/block/dasd_devmap.c linux-2.5.67-s390/drivers/s390/block/dasd_devmap.c --- linux-2.5.67/drivers/s390/block/dasd_devmap.c Mon Apr 7 19:31:23 2003 +++ linux-2.5.67-s390/drivers/s390/block/dasd_devmap.c Mon Apr 14 19:11:52 2003 @@ -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.11 $ + * $Revision: 1.12 $ * * History of changes * 05/04/02 split from dasd.c, code restructuring. @@ -31,6 +31,25 @@ #include "dasd_int.h" /* + * dasd_devmap_t is used to store the features and the relation + * between device number and device index. To find a dasd_devmap_t + * that corresponds to a device number of a device index each + * dasd_devmap_t is added to two linked lists, one to search by + * the device number and one to search by the device index. As + * soon as big minor numbers are available the device index list + * can be removed since the device number will then be identical + * to the device index. + */ +typedef struct { + struct list_head devindex_list; + struct list_head devno_list; + unsigned int devindex; + unsigned short devno; + unsigned short features; + dasd_device_t *device; +} dasd_devmap_t; + +/* * Parameter parsing functions for dasd= parameter. The syntax is: * <devno> : (0x)?[0-9a-fA-F]+ * <feature> : ro @@ -279,6 +298,29 @@ } /* + * Check if devno has been added to the list of dasd ranges. + */ +int +dasd_devno_in_range(int devno) +{ + struct list_head *l; + int ret; + + ret = -ENOENT; + spin_lock(&dasd_devmap_lock); + /* Find devmap for device with device number devno */ + list_for_each(l, &dasd_devno_hashlists[devno&255]) { + if (list_entry(l, dasd_devmap_t, devno_list)->devno == devno) { + /* Found the device. */ + ret = 0; + break; + } + } + spin_unlock(&dasd_devmap_lock); + return ret; +} + +/* * Forget all about the device numbers added so far. * This may only be called at module unload or system shutdown. */ @@ -307,7 +349,7 @@ * Find the devmap structure from a devno. Can be removed as soon * as big minors are available. */ -dasd_devmap_t * +static dasd_devmap_t * dasd_devmap_from_devno(int devno) { struct list_head *l; @@ -332,7 +374,7 @@ * Find the devmap for a device by its device index. Can be removed * as soon as big minors are available. */ -dasd_devmap_t * +static dasd_devmap_t * dasd_devmap_from_devindex(int devindex) { struct list_head *l; @@ -353,60 +395,140 @@ return devmap; } -/* - * Find the device structure for device number devno. If it does not - * exists yet, allocate it. Increase the reference counter in the device - * structure and return a pointer to it. - */ dasd_device_t * -dasd_get_device(dasd_devmap_t *devmap) +dasd_device_from_devindex(int devindex) { + dasd_devmap_t *devmap; dasd_device_t *device; + devmap = dasd_devmap_from_devindex(devindex); spin_lock(&dasd_devmap_lock); device = devmap->device; - if (device != NULL) - atomic_inc(&device->ref_count); + if (device) + dasd_get_device(device); + else + device = ERR_PTR(-ENODEV); spin_unlock(&dasd_devmap_lock); - if (device != NULL) - return device; + return device; +} - device = dasd_alloc_device(devmap); +/* + * Return kdev for a dasd device. + */ +kdev_t +dasd_get_kdev(dasd_device_t *device) +{ + dasd_devmap_t *devmap; + int major, minor; + int devno; + + devno = _ccw_device_get_device_number(device->cdev); + devmap = dasd_devmap_from_devno(devno); + if (devmap == NULL) + return NODEV; + major = dasd_gendisk_index_major(devmap->devindex); + if (major < 0) + return NODEV; + minor = devmap->devindex % DASD_PER_MAJOR; + return mk_kdev(major, minor); +} + +/* + * Create a dasd device structure for cdev. + */ +dasd_device_t * +dasd_create_device(struct ccw_device *cdev) +{ + dasd_devmap_t *devmap; + dasd_device_t *device; + int devno; + int rc; + + devno = _ccw_device_get_device_number(cdev); + rc = dasd_add_range(devno, devno, DASD_FEATURE_DEFAULT); + if (rc) + return ERR_PTR(rc); + + if (!(devmap = dasd_devmap_from_devno (devno))) + return ERR_PTR(-ENODEV); + + device = dasd_alloc_device(devmap->devindex); if (IS_ERR(device)) return device; + atomic_set(&device->ref_count, 1); + device->ro_flag = (devmap->features & DASD_FEATURE_READONLY) ? 1 : 0; + device->use_diag_flag = 1; - spin_lock(&dasd_devmap_lock); - if (devmap->device != NULL) { + spin_lock_irq(get_ccwdev_lock(cdev)); + if (cdev->dev.driver_data == NULL) { + get_device(&cdev->dev); + cdev->dev.driver_data = device; + device->gdp->driverfs_dev = &cdev->dev; + device->cdev = cdev; + rc = 0; + } else /* Someone else was faster. */ + rc = -EBUSY; + spin_unlock_irq(get_ccwdev_lock(cdev)); + if (rc) { dasd_free_device(device); - device = devmap->device; - } else - devmap->device = device; - atomic_inc(&device->ref_count); - device->ro_flag = (devmap->features & DASD_FEATURE_READONLY) ? 1 : 0; - device->use_diag_flag = 1; + return ERR_PTR(rc); + } + /* Device created successfully. Make it known via devmap. */ + spin_lock(&dasd_devmap_lock); + devmap->device = device; spin_unlock(&dasd_devmap_lock); + return device; } /* - * Decrease the reference counter of a devices structure. If the - * reference counter reaches zero and the device status is - * DASD_STATE_NEW the device structure is freed. + * Wait queue for dasd_delete_device waits. + */ +static DECLARE_WAIT_QUEUE_HEAD(dasd_delete_wq); + +/* + * Remove a dasd device structure. */ void -dasd_put_device(dasd_devmap_t *devmap) +dasd_delete_device(dasd_device_t *device) { - dasd_device_t *device; + struct ccw_device *cdev; + dasd_devmap_t *devmap; + int devno; + /* First remove device pointer from devmap. */ + devno = _ccw_device_get_device_number(device->cdev); + devmap = dasd_devmap_from_devno (devno); spin_lock(&dasd_devmap_lock); - device = devmap->device; - if (atomic_dec_return(&device->ref_count) == 0 && - device->state == DASD_STATE_NEW) { - devmap->device = NULL; - dasd_free_device(device); - } + devmap->device = NULL; spin_unlock(&dasd_devmap_lock); + + /* Wait for reference counter to drop to zero. */ + atomic_dec(&device->ref_count); + wait_event(dasd_delete_wq, atomic_read(&device->ref_count) == 0); + + /* Disconnect dasd_device structure from ccw_device structure. */ + cdev = device->cdev; + device->cdev = NULL; + device->gdp->driverfs_dev = NULL; + cdev->dev.driver_data = NULL; + + /* Put ccw_device structure. */ + put_device(&cdev->dev); + + /* Now the device structure can be freed. */ + dasd_free_device(device); +} + +/* + * Reference counter dropped to zero. Wake up waiter + * in dasd_delete_device. + */ +void +dasd_put_device_wake(dasd_device_t *device) +{ + wake_up(&dasd_delete_wq); } int diff -urN linux-2.5.67/drivers/s390/block/dasd_diag.c linux-2.5.67-s390/drivers/s390/block/dasd_diag.c --- linux-2.5.67/drivers/s390/block/dasd_diag.c Mon Apr 7 19:30:35 2003 +++ linux-2.5.67-s390/drivers/s390/block/dasd_diag.c Mon Apr 14 19:11:52 2003 @@ -6,7 +6,7 @@ * Bugreports.to..: <Linux390@de.ibm.com> * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * - * $Revision: 1.27 $ + * $Revision: 1.28 $ * * History of changes * 07/13/00 Added fixup sections for diagnoses ans saved some registers @@ -96,7 +96,7 @@ iib = &private->iib; memset(iib, 0, sizeof (diag_init_io_t)); - iib->dev_nr = device->devno; + iib->dev_nr = _ccw_device_get_device_number(device->cdev); iib->block_size = blocksize; iib->offset = offset; iib->start_block = 0; @@ -117,7 +117,7 @@ private = (dasd_diag_private_t *) device->private; iib = &private->iib; memset(iib, 0, sizeof (diag_init_io_t)); - iib->dev_nr = device->devno; + iib->dev_nr = _ccw_device_get_device_number(device->cdev); rc = dia250(iib, TERM_BIO); return rc & 3; } @@ -134,7 +134,7 @@ private = (dasd_diag_private_t *) device->private; dreq = (dasd_diag_req_t *) cqr->data; - private->iob.dev_nr = device->devno; + private->iob.dev_nr = _ccw_device_get_device_number(device->cdev); private->iob.key = 0; private->iob.flags = 2; /* do asynchronous io */ private->iob.block_count = dreq->block_count; @@ -252,7 +252,7 @@ } /* Read Device Characteristics */ rdc_data = (void *) &(private->rdc_data); - rdc_data->dev_nr = device->devno; + rdc_data->dev_nr = _ccw_device_get_device_number(device->cdev); rdc_data->rdc_len = sizeof (dasd_diag_characteristics_t); rc = diag210((struct diag210 *) rdc_data); diff -urN linux-2.5.67/drivers/s390/block/dasd_eckd.c linux-2.5.67-s390/drivers/s390/block/dasd_eckd.c --- linux-2.5.67/drivers/s390/block/dasd_eckd.c Mon Apr 7 19:30:34 2003 +++ linux-2.5.67-s390/drivers/s390/block/dasd_eckd.c Mon Apr 14 19:11:52 2003 @@ -7,7 +7,7 @@ * Bugreports.to..: <Linux390@de.ibm.com> * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * - * $Revision: 1.36 $ + * $Revision: 1.38 $ * * History of changes (starts July 2000) * 07/11/00 Enabled rotational position sensing @@ -1003,7 +1003,7 @@ return ERR_PTR(-EINVAL); count += bv->bv_len >> (device->s2b_shift + 9); #if defined(CONFIG_ARCH_S390X) - cidaw += idal_nr_words(kmap(bv->bv_page) + + cidaw += idal_nr_words(page_address(bv->bv_page) + bv->bv_offset, bv->bv_len); #endif } @@ -1042,7 +1042,7 @@ last_rec - recid + 1, cmd, device, blksize); } rq_for_each_bio(bio, req) bio_for_each_segment(bv, bio, i) { - dst = kmap(bv->bv_page) + bv->bv_offset; + dst = page_address(bv->bv_page) + bv->bv_offset; for (off = 0; off < bv->bv_len; off += blksize) { sector_t trkid = recid; unsigned int recoffs = sector_div(trkid, blk_per_trk); @@ -1453,6 +1453,8 @@ static int __init dasd_eckd_init(void) { + int ret; + dasd_ioctl_no_register(THIS_MODULE, BIODASDSATTR, dasd_eckd_set_attrib); dasd_ioctl_no_register(THIS_MODULE, BIODASDPSRD, @@ -1466,7 +1468,22 @@ ASCEBC(dasd_eckd_discipline.ebcname, 4); - ccw_driver_register(&dasd_eckd_driver); + ret = ccw_driver_register(&dasd_eckd_driver); + if (ret) { + dasd_ioctl_no_unregister(THIS_MODULE, BIODASDSATTR, + dasd_eckd_set_attrib); + dasd_ioctl_no_unregister(THIS_MODULE, BIODASDPSRD, + dasd_eckd_performance); + dasd_ioctl_no_unregister(THIS_MODULE, BIODASDRLSE, + dasd_eckd_release); + dasd_ioctl_no_unregister(THIS_MODULE, BIODASDRSRV, + dasd_eckd_reserve); + dasd_ioctl_no_unregister(THIS_MODULE, BIODASDSLCK, + dasd_eckd_steal_lock); + return ret; + } + + dasd_generic_auto_online(&dasd_eckd_driver); return 0; } diff -urN linux-2.5.67/drivers/s390/block/dasd_fba.c linux-2.5.67-s390/drivers/s390/block/dasd_fba.c --- linux-2.5.67/drivers/s390/block/dasd_fba.c Mon Apr 7 19:31:56 2003 +++ linux-2.5.67-s390/drivers/s390/block/dasd_fba.c Mon Apr 14 19:11:52 2003 @@ -4,7 +4,7 @@ * Bugreports.to..: <Linux390@de.ibm.com> * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * - * $Revision: 1.25 $ + * $Revision: 1.27 $ * * History of changes * fixed partition handling and HDIO_GETGEO @@ -414,9 +414,16 @@ static int __init dasd_fba_init(void) { + int ret; + ASCEBC(dasd_fba_discipline.ebcname, 4); - return ccw_driver_register(&dasd_fba_driver); + ret = ccw_driver_register(&dasd_fba_driver); + if (ret) + return ret; + + dasd_generic_auto_online(&dasd_fba_driver); + return 0; } static void __exit diff -urN linux-2.5.67/drivers/s390/block/dasd_genhd.c linux-2.5.67-s390/drivers/s390/block/dasd_genhd.c --- linux-2.5.67/drivers/s390/block/dasd_genhd.c Mon Apr 7 19:32:18 2003 +++ linux-2.5.67-s390/drivers/s390/block/dasd_genhd.c Mon Apr 14 19:11:52 2003 @@ -9,7 +9,7 @@ * * Dealing with devices registered to multiple major numbers. * - * $Revision: 1.23 $ + * $Revision: 1.24 $ * * History of changes * 05/04/02 split from dasd.c, code restructuring. @@ -108,7 +108,6 @@ struct gendisk * dasd_gendisk_alloc(int devindex) { - struct list_head *l; struct major_info *mi; struct gendisk *gdp; int index, len, rc; @@ -118,8 +117,7 @@ while (1) { spin_lock(&dasd_major_lock); index = devindex; - list_for_each(l, &dasd_major_info) { - mi = list_entry(l, struct major_info, list); + list_for_each_entry(mi, &dasd_major_info, list) { if (index < DASD_PER_MAJOR) break; index -= DASD_PER_MAJOR; @@ -142,6 +140,7 @@ gdp->major = mi->major; gdp->first_minor = index << DASD_PARTN_BITS; gdp->fops = &dasd_device_operations; + gdp->flags |= GENHD_FL_DEVFS; /* * Set device name. @@ -191,14 +190,12 @@ */ int dasd_gendisk_index_major(int devindex) { - struct list_head *l; struct major_info *mi; int rc; spin_lock(&dasd_major_lock); rc = -ENODEV; - list_for_each(l, &dasd_major_info) { - mi = list_entry(l, struct major_info, list); + list_for_each_entry(mi, &dasd_major_info, list) { if (devindex < DASD_PER_MAJOR) { rc = mi->major; break; @@ -231,6 +228,7 @@ dasd_destroy_partitions(dasd_device_t * device) { del_gendisk(device->gdp); + put_disk(device->gdp); } int diff -urN linux-2.5.67/drivers/s390/block/dasd_int.h linux-2.5.67-s390/drivers/s390/block/dasd_int.h --- linux-2.5.67/drivers/s390/block/dasd_int.h Mon Apr 7 19:32:16 2003 +++ linux-2.5.67-s390/drivers/s390/block/dasd_int.h Mon Apr 14 19:11:52 2003 @@ -6,7 +6,7 @@ * Bugreports.to..: <Linux390@de.ibm.com> * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * - * $Revision: 1.36 $ + * $Revision: 1.38 $ * * History of changes (starts July 2000) * 02/01/01 added dynamic registration of ioctls @@ -297,10 +297,6 @@ struct list_head ccw_chunks; struct list_head erp_chunks; - /* Common i/o stuff. */ - /* FIXME: remove the next */ - int devno; - atomic_t tasklet_scheduled; struct tasklet_struct tasklet; struct work_struct kick_work; @@ -315,24 +311,23 @@ #endif } dasd_device_t; +void dasd_put_device_wake(dasd_device_t *); + /* - * dasd_devmap_t is used to store the features and the relation - * between device number and device index. To find a dasd_devmap_t - * that corresponds to a device number of a device index each - * dasd_devmap_t is added to two linked lists, one to search by - * the device number and one to search by the device index. As - * soon as big minor numbers are available the device index list - * can be removed since the device number will then be identical - * to the device index. + * Reference count inliners */ -typedef struct { - struct list_head devindex_list; - struct list_head devno_list; - unsigned int devindex; - unsigned short devno; - unsigned short features; - dasd_device_t *device; -} dasd_devmap_t; +static inline void +dasd_get_device(dasd_device_t *device) +{ + atomic_inc(&device->ref_count); +} + +static inline void +dasd_put_device(dasd_device_t *device) +{ + if (atomic_dec_return(&device->ref_count) == 0) + dasd_put_device_wake(device); +} /* * The static memory in ccw_mem and erp_mem is managed by a sorted @@ -444,8 +439,9 @@ return set_normalized_cda(ccw, cda); } -dasd_device_t *dasd_alloc_device(dasd_devmap_t *); +dasd_device_t *dasd_alloc_device(unsigned int devindex); void dasd_free_device(dasd_device_t *); + void dasd_enable_device(dasd_device_t *); void dasd_set_target_state(dasd_device_t *, int); void dasd_kick_device(dasd_device_t *); @@ -467,6 +463,7 @@ int dasd_generic_set_online(struct ccw_device *cdev, dasd_discipline_t *discipline); int dasd_generic_set_offline (struct ccw_device *cdev); +void dasd_generic_auto_online (struct ccw_driver *); /* externals in dasd_devmap.c */ extern int dasd_max_devindex; @@ -475,13 +472,16 @@ int dasd_devmap_init(void); void dasd_devmap_exit(void); -dasd_devmap_t *dasd_devmap_from_devno(int); -dasd_devmap_t *dasd_devmap_from_devindex(int); -dasd_device_t *dasd_get_device(dasd_devmap_t *); -void dasd_put_device(dasd_devmap_t *); + +dasd_device_t *dasd_create_device(struct ccw_device *); +void dasd_delete_device(dasd_device_t *); + +kdev_t dasd_get_kdev(dasd_device_t *); +dasd_device_t *dasd_device_from_devindex(int); int dasd_parse(void); int dasd_add_range(int, int, int); +int dasd_devno_in_range(int); /* externals in dasd_gendisk.c */ int dasd_gendisk_init(void); diff -urN linux-2.5.67/drivers/s390/block/dasd_ioctl.c linux-2.5.67-s390/drivers/s390/block/dasd_ioctl.c --- linux-2.5.67/drivers/s390/block/dasd_ioctl.c Mon Apr 7 19:31:46 2003 +++ linux-2.5.67-s390/drivers/s390/block/dasd_ioctl.c Mon Apr 14 19:11:52 2003 @@ -12,7 +12,6 @@ * 05/04/02 split from dasd.c, code restructuring. */ #include <linux/config.h> -#include <linux/version.h> #include <linux/interrupt.h> #include <linux/major.h> #include <linux/fs.h> @@ -333,7 +332,7 @@ cdev = device->cdev; - dasd_info->devno = device->devno; + dasd_info->devno = _ccw_device_get_device_number(device->cdev); dasd_info->schid = _ccw_device_get_subchannel_number(device->cdev); dasd_info->cu_type = cdev->id.cu_type; dasd_info->cu_model = cdev->id.cu_model; diff -urN linux-2.5.67/drivers/s390/block/dasd_proc.c linux-2.5.67-s390/drivers/s390/block/dasd_proc.c --- linux-2.5.67/drivers/s390/block/dasd_proc.c Mon Apr 7 19:30:45 2003 +++ linux-2.5.67-s390/drivers/s390/block/dasd_proc.c Mon Apr 14 19:11:52 2003 @@ -9,7 +9,7 @@ * * /proc interface for the dasd driver. * - * $Revision: 1.17 $ + * $Revision: 1.18 $ * * History of changes * 05/04/02 split from dasd.c, code restructuring. @@ -56,17 +56,14 @@ static int dasd_devices_show(struct seq_file *m, void *v) { - dasd_devmap_t *devmap; dasd_device_t *device; char *substr; - devmap = dasd_devmap_from_devindex((unsigned long) v - 1); - device = (devmap != NULL) ? - dasd_get_device(devmap) : ERR_PTR(-ENODEV); + device = dasd_device_from_devindex((unsigned long) v - 1); if (IS_ERR(device)) return 0; /* Print device number. */ - seq_printf(m, "%04x", devmap->devno); + seq_printf(m, "%04x", _ccw_device_get_device_number(device->cdev)); /* Print discipline string. */ if (device != NULL && device->discipline != NULL) seq_printf(m, "(%s)", device->discipline->name); @@ -113,7 +110,7 @@ seq_printf(m, "no stat"); break; } - dasd_put_device(devmap); + dasd_put_device(device); if (dasd_probeonly) seq_printf(m, "(probeonly)"); seq_printf(m, "\n"); - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| ![\](/images/icornerr.gif) |