Commit 616dea43 authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Linus Torvalds

[PATCH] s390: dasd driver fixes.

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.
parent db165cde
...@@ -164,7 +164,7 @@ config DASD_FBA ...@@ -164,7 +164,7 @@ config DASD_FBA
config DASD_DIAG config DASD_DIAG
tristate "Support for DIAG access to CMS reserved Disks" tristate "Support for DIAG access to CMS reserved Disks"
depends on DASD depends on DASD && ARCH_S390X = 'n'
help help
Select this option if you want to use CMS reserved Disks under VM 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 with the Diagnose250 command. If you are not running under VM or
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Bugreports.to..: <Linux390@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
* *
* $Revision: 1.74 $ * $Revision: 1.82 $
* *
* History of changes (starts July 2000) * History of changes (starts July 2000)
* 11/09/00 complete redesign after code review * 11/09/00 complete redesign after code review
...@@ -101,7 +101,7 @@ static wait_queue_head_t dasd_init_waitq; ...@@ -101,7 +101,7 @@ static wait_queue_head_t dasd_init_waitq;
* Allocate memory for a new device structure. * Allocate memory for a new device structure.
*/ */
dasd_device_t * dasd_device_t *
dasd_alloc_device(dasd_devmap_t *devmap) dasd_alloc_device(unsigned int devindex)
{ {
dasd_device_t *device; dasd_device_t *device;
struct gendisk *gdp; struct gendisk *gdp;
...@@ -111,8 +111,6 @@ dasd_alloc_device(dasd_devmap_t *devmap) ...@@ -111,8 +111,6 @@ dasd_alloc_device(dasd_devmap_t *devmap)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
memset(device, 0, sizeof (dasd_device_t)); memset(device, 0, sizeof (dasd_device_t));
device->devno = devmap->devno;
/* Get two pages for normal block device operations. */ /* Get two pages for normal block device operations. */
device->ccw_mem = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, 1); device->ccw_mem = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, 1);
if (device->ccw_mem == NULL) { if (device->ccw_mem == NULL) {
...@@ -128,7 +126,7 @@ dasd_alloc_device(dasd_devmap_t *devmap) ...@@ -128,7 +126,7 @@ dasd_alloc_device(dasd_devmap_t *devmap)
} }
/* Allocate gendisk structure for device. */ /* Allocate gendisk structure for device. */
gdp = dasd_gendisk_alloc(devmap->devindex); gdp = dasd_gendisk_alloc(devindex);
if (IS_ERR(gdp)) { if (IS_ERR(gdp)) {
free_page((unsigned long) device->erp_mem); free_page((unsigned long) device->erp_mem);
free_pages((unsigned long) device->ccw_mem, 1); free_pages((unsigned long) device->ccw_mem, 1);
...@@ -147,7 +145,7 @@ dasd_alloc_device(dasd_devmap_t *devmap) ...@@ -147,7 +145,7 @@ dasd_alloc_device(dasd_devmap_t *devmap)
(unsigned long) device); (unsigned long) device);
INIT_LIST_HEAD(&device->ccw_queue); INIT_LIST_HEAD(&device->ccw_queue);
init_timer(&device->timer); 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->state = DASD_STATE_NEW;
device->target = DASD_STATE_NEW; device->target = DASD_STATE_NEW;
...@@ -174,35 +172,35 @@ dasd_free_device(dasd_device_t *device) ...@@ -174,35 +172,35 @@ dasd_free_device(dasd_device_t *device)
static inline int static inline int
dasd_state_new_to_known(dasd_device_t *device) dasd_state_new_to_known(dasd_device_t *device)
{ {
dasd_devmap_t *devmap;
umode_t devfs_perm; umode_t devfs_perm;
devfs_handle_t dir; kdev_t kdev;
int major, minor;
char buf[20]; char buf[20];
/* Increase reference count of bdev. */ kdev = dasd_get_kdev(device);
if (bdget(MKDEV(device->gdp->major, device->gdp->first_minor)) == NULL) if (kdev_none(kdev))
return -ENODEV; return -ENODEV;
devmap = dasd_devmap_from_devno(device->devno); /*
if (devmap == NULL) * As long as the device is not in state DASD_STATE_NEW we want to
return -ENODEV; * keep the reference count > 0.
major = dasd_gendisk_index_major(devmap->devindex); */
if (major < 0) dasd_get_device(device);
return -ENODEV;
minor = devmap->devindex % DASD_PER_MAJOR;
#ifdef CONFIG_DEVFS_FS
/* Add a proc directory and the dasd device entry to devfs. */ /* Add a proc directory and the dasd device entry to devfs. */
dir = devfs_mk_dir("dasd/%04x", device->devno); device->gdp->de = devfs_mk_dir("dasd/%04x",
device->gdp->de = dir; _ccw_device_get_device_number(device->cdev));
#endif
if (device->ro_flag) if (device->ro_flag)
devfs_perm = S_IFBLK | S_IRUSR; devfs_perm = S_IFBLK | S_IRUSR;
else else
devfs_perm = S_IFBLK | S_IRUSR | S_IWUSR; 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, device->devfs_entry = devfs_register(NULL, buf, 0,
major, minor << DASD_PARTN_BITS, major(kdev),
minor(kdev) << DASD_PARTN_BITS,
devfs_perm, devfs_perm,
&dasd_device_operations, NULL); &dasd_device_operations, NULL);
device->state = DASD_STATE_KNOWN; device->state = DASD_STATE_KNOWN;
...@@ -215,8 +213,6 @@ dasd_state_new_to_known(dasd_device_t *device) ...@@ -215,8 +213,6 @@ dasd_state_new_to_known(dasd_device_t *device)
static inline void static inline void
dasd_state_known_to_new(dasd_device_t * device) dasd_state_known_to_new(dasd_device_t * device)
{ {
struct block_device *bdev;
/* Remove device entry and devfs directory. */ /* Remove device entry and devfs directory. */
devfs_unregister(device->devfs_entry); devfs_unregister(device->devfs_entry);
devfs_unregister(device->gdp->de); devfs_unregister(device->gdp->de);
...@@ -225,10 +221,8 @@ dasd_state_known_to_new(dasd_device_t * device) ...@@ -225,10 +221,8 @@ dasd_state_known_to_new(dasd_device_t * device)
device->discipline = NULL; device->discipline = NULL;
device->state = DASD_STATE_NEW; device->state = DASD_STATE_NEW;
/* Decrease reference count of bdev. */ /* Give up reference we took in dasd_state_new_to_known. */
bdev = bdget(MKDEV(device->gdp->major, device->gdp->first_minor)); dasd_put_device(device);
bdput(bdev);
bdput(bdev);
} }
/* /*
...@@ -428,7 +422,8 @@ dasd_change_state(dasd_device_t *device) ...@@ -428,7 +422,8 @@ dasd_change_state(dasd_device_t *device)
if (rc && rc != -EAGAIN) { if (rc && rc != -EAGAIN) {
if (rc != -ENODEV) if (rc != -ENODEV)
MESSAGE (KERN_INFO, "giving up on dasd device with " 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; device->target = device->state;
} }
...@@ -445,26 +440,18 @@ dasd_change_state(dasd_device_t *device) ...@@ -445,26 +440,18 @@ dasd_change_state(dasd_device_t *device)
static void static void
do_kick_device(void *data) do_kick_device(void *data)
{ {
int devno;
dasd_devmap_t *devmap;
dasd_device_t *device; dasd_device_t *device;
devno = (long) data; device = (dasd_device_t *) 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);
dasd_change_state(device); dasd_change_state(device);
dasd_schedule_bh(device); dasd_schedule_bh(device);
dasd_put_device(devmap); dasd_put_device(device);
} }
void void
dasd_kick_device(dasd_device_t *device) 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. */ /* queue call to dasd_kick_device to the kernel event daemon. */
schedule_work(&device->kick_work); schedule_work(&device->kick_work);
} }
...@@ -646,7 +633,7 @@ dasd_kmalloc_request(char *magic, int cplength, int datasize, ...@@ -646,7 +633,7 @@ dasd_kmalloc_request(char *magic, int cplength, int datasize,
} }
strncpy((char *) &cqr->magic, magic, 4); strncpy((char *) &cqr->magic, magic, 4);
ASCEBC((char *) &cqr->magic, 4); ASCEBC((char *) &cqr->magic, 4);
atomic_inc(&device->ref_count); dasd_get_device(device);
return cqr; return cqr;
} }
...@@ -693,7 +680,7 @@ dasd_smalloc_request(char *magic, int cplength, int datasize, ...@@ -693,7 +680,7 @@ dasd_smalloc_request(char *magic, int cplength, int datasize,
} }
strncpy((char *) &cqr->magic, magic, 4); strncpy((char *) &cqr->magic, magic, 4);
ASCEBC((char *) &cqr->magic, 4); ASCEBC((char *) &cqr->magic, 4);
atomic_inc(&device->ref_count); dasd_get_device(device);
return cqr; return cqr;
} }
...@@ -723,7 +710,7 @@ dasd_kfree_request(dasd_ccw_req_t * cqr, dasd_device_t * device) ...@@ -723,7 +710,7 @@ dasd_kfree_request(dasd_ccw_req_t * cqr, dasd_device_t * device)
if (cqr->data != NULL) if (cqr->data != NULL)
kfree(cqr->data); kfree(cqr->data);
kfree(cqr); kfree(cqr);
atomic_dec(&device->ref_count); dasd_put_device(device);
} }
void void
...@@ -738,7 +725,7 @@ dasd_sfree_request(dasd_ccw_req_t * cqr, dasd_device_t * device) ...@@ -738,7 +725,7 @@ dasd_sfree_request(dasd_ccw_req_t * cqr, dasd_device_t * device)
spin_lock_irqsave(&device->mem_lock, flags); spin_lock_irqsave(&device->mem_lock, flags);
dasd_free_chunk(&device->ccw_chunks, cqr); dasd_free_chunk(&device->ccw_chunks, cqr);
spin_unlock_irqrestore(&device->mem_lock, flags); spin_unlock_irqrestore(&device->mem_lock, flags);
atomic_dec(&device->ref_count); dasd_put_device(device);
} }
/* /*
...@@ -936,19 +923,14 @@ do_state_change_pending(void *data) ...@@ -936,19 +923,14 @@ do_state_change_pending(void *data)
struct work_struct work; struct work_struct work;
dasd_device_t *device; dasd_device_t *device;
} *p; } *p;
dasd_devmap_t *devmap;
dasd_device_t *device; dasd_device_t *device;
dasd_ccw_req_t *cqr; dasd_ccw_req_t *cqr;
int devno;
p = data; p = data;
device = p->device; device = p->device;
DBF_EVENT(DBF_NOTICE, "State change Interrupt for bus_id %s", DBF_EVENT(DBF_NOTICE, "State change Interrupt for bus_id %s",
device->cdev->dev.bus_id); 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)); spin_lock_irq(get_ccwdev_lock(device->cdev));
/* re-activate first request in queue */ /* re-activate first request in queue */
if (!list_empty(&device->ccw_queue)) { if (!list_empty(&device->ccw_queue)) {
...@@ -965,10 +947,39 @@ do_state_change_pending(void *data) ...@@ -965,10 +947,39 @@ do_state_change_pending(void *data)
} }
spin_unlock_irq(get_ccwdev_lock(device->cdev)); spin_unlock_irq(get_ccwdev_lock(device->cdev));
dasd_schedule_bh(device); dasd_schedule_bh(device);
dasd_put_device(devmap); dasd_put_device(device);
kfree(p); 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 static void
dasd_handle_state_change_pending(dasd_device_t *device) dasd_handle_state_change_pending(dasd_device_t *device)
...@@ -984,8 +995,7 @@ dasd_handle_state_change_pending(dasd_device_t *device) ...@@ -984,8 +995,7 @@ dasd_handle_state_change_pending(dasd_device_t *device)
return; return;
INIT_WORK(&p->work, (void *) do_state_change_pending, p); INIT_WORK(&p->work, (void *) do_state_change_pending, p);
p->device = device; p->device = device;
atomic_inc(&device->ref_count); dasd_get_device(device);
/* queue call to do_state_change_pending to the kernel event daemon. */
schedule_work(&p->work); schedule_work(&p->work);
} }
...@@ -1003,6 +1013,23 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, ...@@ -1003,6 +1013,23 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
dasd_era_t era; dasd_era_t era;
char mask; 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(); now = get_clock();
DBF_EVENT(DBF_DEBUG, "Interrupt: stat %02x, bus_id %s", DBF_EVENT(DBF_DEBUG, "Interrupt: stat %02x, bus_id %s",
...@@ -1108,7 +1135,6 @@ dasd_end_request(struct request *req, int uptodate) ...@@ -1108,7 +1135,6 @@ dasd_end_request(struct request *req, int uptodate)
BUG(); BUG();
add_disk_randomness(req->rq_disk); add_disk_randomness(req->rq_disk);
end_that_request_last(req); end_that_request_last(req);
return;
} }
/* /*
...@@ -1177,7 +1203,9 @@ dasd_end_request_cb(dasd_ccw_req_t * cqr, void *data) ...@@ -1177,7 +1203,9 @@ dasd_end_request_cb(dasd_ccw_req_t * cqr, void *data)
req = (struct request *) data; req = (struct request *) data;
dasd_profile_end(cqr->device, cqr, req); dasd_profile_end(cqr->device, cqr, req);
spin_lock_irq(&cqr->device->request_queue_lock);
dasd_end_request(req, (cqr->status == DASD_CQR_DONE)); dasd_end_request(req, (cqr->status == DASD_CQR_DONE));
spin_unlock_irq(&cqr->device->request_queue_lock);
dasd_sfree_request(cqr, cqr->device); dasd_sfree_request(cqr, cqr->device);
} }
...@@ -1189,7 +1217,6 @@ static inline void ...@@ -1189,7 +1217,6 @@ static inline void
__dasd_process_blk_queue(dasd_device_t * device) __dasd_process_blk_queue(dasd_device_t * device)
{ {
request_queue_t *queue; request_queue_t *queue;
struct list_head *l;
struct request *req; struct request *req;
dasd_ccw_req_t *cqr; dasd_ccw_req_t *cqr;
int nr_queued; int nr_queued;
...@@ -1211,11 +1238,9 @@ __dasd_process_blk_queue(dasd_device_t * device) ...@@ -1211,11 +1238,9 @@ __dasd_process_blk_queue(dasd_device_t * device)
return; return;
nr_queued = 0; nr_queued = 0;
/* Now we try to fetch requests from the request queue */ /* Now we try to fetch requests from the request queue */
list_for_each(l, &device->ccw_queue) { list_for_each_entry(cqr, &device->ccw_queue, list)
cqr = list_entry(l, dasd_ccw_req_t, list);
if (cqr->status == DASD_CQR_QUEUED) if (cqr->status == DASD_CQR_QUEUED)
nr_queued++; nr_queued++;
}
while (!blk_queue_plugged(queue) && while (!blk_queue_plugged(queue) &&
elv_next_request(queue) && elv_next_request(queue) &&
nr_queued < DASD_CHANQ_MAX_SIZE) { nr_queued < DASD_CHANQ_MAX_SIZE) {
...@@ -1223,7 +1248,8 @@ __dasd_process_blk_queue(dasd_device_t * device) ...@@ -1223,7 +1248,8 @@ __dasd_process_blk_queue(dasd_device_t * device)
if (device->ro_flag && rq_data_dir(req) == WRITE) { if (device->ro_flag && rq_data_dir(req) == WRITE) {
DBF_EVENT(DBF_ERR, DBF_EVENT(DBF_ERR,
"(%04x) Rejecting write request %p", "(%04x) Rejecting write request %p",
device->devno, req); _ccw_device_get_device_number(device->cdev),
req);
blkdev_dequeue_request(req); blkdev_dequeue_request(req);
dasd_end_request(req, 0); dasd_end_request(req, 0);
continue; continue;
...@@ -1234,7 +1260,8 @@ __dasd_process_blk_queue(dasd_device_t * device) ...@@ -1234,7 +1260,8 @@ __dasd_process_blk_queue(dasd_device_t * device)
break; /* terminate request queue loop */ break; /* terminate request queue loop */
DBF_EVENT(DBF_ERR, DBF_EVENT(DBF_ERR,
"(%04x) CCW creation failed on request %p", "(%04x) CCW creation failed on request %p",
device->devno, req); _ccw_device_get_device_number(device->cdev),
req);
blkdev_dequeue_request(req); blkdev_dequeue_request(req);
dasd_end_request(req, 0); dasd_end_request(req, 0);
continue; continue;
...@@ -1371,8 +1398,7 @@ dasd_tasklet(dasd_device_t * device) ...@@ -1371,8 +1398,7 @@ dasd_tasklet(dasd_device_t * device)
__dasd_start_head(device); __dasd_start_head(device);
spin_unlock(get_ccwdev_lock(device->cdev)); spin_unlock(get_ccwdev_lock(device->cdev));
spin_unlock_irq(&device->request_queue_lock); spin_unlock_irq(&device->request_queue_lock);
/* FIXME: what if ref_count == 0 && state == DASD_STATE_NEW ?? */ dasd_put_device(device);
atomic_dec(&device->ref_count);
} }
/* /*
...@@ -1384,7 +1410,7 @@ dasd_schedule_bh(dasd_device_t * device) ...@@ -1384,7 +1410,7 @@ dasd_schedule_bh(dasd_device_t * device)
/* Protect against rescheduling. */ /* Protect against rescheduling. */
if (atomic_compare_and_swap (0, 1, &device->tasklet_scheduled)) if (atomic_compare_and_swap (0, 1, &device->tasklet_scheduled))
return; return;
atomic_inc(&device->ref_count); dasd_get_device(device);
tasklet_hi_schedule(&device->tasklet); tasklet_hi_schedule(&device->tasklet);
} }
...@@ -1766,8 +1792,8 @@ dasd_release(struct inode *inp, struct file *filp) ...@@ -1766,8 +1792,8 @@ dasd_release(struct inode *inp, struct file *filp)
return 0; return 0;
} }
struct struct block_device_operations
block_device_operations dasd_device_operations = { dasd_device_operations = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = dasd_open, .open = dasd_open,
.release = dasd_release, .release = dasd_release,
...@@ -1823,12 +1849,6 @@ dasd_generic_probe (struct ccw_device *cdev, dasd_discipline_t *discipline) ...@@ -1823,12 +1849,6 @@ dasd_generic_probe (struct ccw_device *cdev, dasd_discipline_t *discipline)
cdev->handler = &dasd_int_handler; 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; return ret;
} }
...@@ -1854,30 +1874,12 @@ dasd_generic_set_online (struct ccw_device *cdev, ...@@ -1854,30 +1874,12 @@ dasd_generic_set_online (struct ccw_device *cdev,
dasd_discipline_t *discipline) dasd_discipline_t *discipline)
{ {
int devno;
dasd_devmap_t *devmap;
dasd_device_t *device; dasd_device_t *device;
int rc; int rc;
if (cdev->dev.driver_data != NULL) /* already enabled */ device = dasd_create_device(cdev);
return 0; if (IS_ERR(device))
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);
return PTR_ERR(device); return PTR_ERR(device);
}
device->gdp->driverfs_dev = &cdev->dev;
device->cdev = cdev;
if (device->use_diag_flag) if (device->use_diag_flag)
device->discipline = dasd_diag_discipline_pointer; device->discipline = dasd_diag_discipline_pointer;
...@@ -1898,7 +1900,7 @@ dasd_generic_set_online (struct ccw_device *cdev, ...@@ -1898,7 +1900,7 @@ dasd_generic_set_online (struct ccw_device *cdev,
if (rc) { if (rc) {
printk (KERN_WARNING "dasd_generic found a bad device %s\n", printk (KERN_WARNING "dasd_generic found a bad device %s\n",
cdev->dev.bus_id); cdev->dev.bus_id);
dasd_put_device(devmap); dasd_delete_device(device);
return rc; return rc;
} }
...@@ -1909,16 +1911,17 @@ dasd_generic_set_online (struct ccw_device *cdev, ...@@ -1909,16 +1911,17 @@ dasd_generic_set_online (struct ccw_device *cdev,
cdev->dev.bus_id); cdev->dev.bus_id);
rc = -ENODEV; rc = -ENODEV;
dasd_set_target_state(device, DASD_STATE_NEW); dasd_set_target_state(device, DASD_STATE_NEW);
dasd_delete_device(device);
} else { } else {
pr_debug("dasd_generic device %s found\n", pr_debug("dasd_generic device %s found\n",
cdev->dev.bus_id); cdev->dev.bus_id);
cdev->dev.driver_data = device; cdev->dev.driver_data = device;
} }
dasd_put_device(devmap);
/* FIXME: we have to wait for the root device but we don't want /* 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. */ * to wait for each single device but for all at once. */
wait_event(dasd_init_waitq, _wait_for_device(device)); wait_event(dasd_init_waitq, _wait_for_device(device));
return rc; return rc;
} }
...@@ -1926,25 +1929,51 @@ int ...@@ -1926,25 +1929,51 @@ int
dasd_generic_set_offline (struct ccw_device *cdev) dasd_generic_set_offline (struct ccw_device *cdev)
{ {
dasd_device_t *device; dasd_device_t *device;
dasd_devmap_t *devmap;
int devno;
devno = _ccw_device_get_device_number(cdev);
device = cdev->dev.driver_data; device = cdev->dev.driver_data;
devmap = dasd_devmap_from_devno(devno); if (atomic_read(&device->open_count) > 0) {
if (device == NULL || devmap == NULL) printk (KERN_WARNING "Can't offline dasd device with open"
return -ENODEV; " count = %i.\n",
atomic_read(&device->open_count));
device = dasd_get_device(devmap); return -EBUSY;
if (IS_ERR(device)) }
return PTR_ERR(device);
dasd_set_target_state(device, DASD_STATE_NEW); dasd_set_target_state(device, DASD_STATE_NEW);
dasd_put_device(devmap); dasd_delete_device(device);
return 0; 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 * SECTION: files in sysfs
*/ */
...@@ -2078,11 +2107,13 @@ dasd_init(void) ...@@ -2078,11 +2107,13 @@ dasd_init(void)
DBF_EVENT(DBF_EMERG, "%s", "debug area created"); 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"); DBF_EVENT(DBF_ALERT, "%s", "no devfs");
rc = -ENOSYS; rc = -ENOSYS;
goto failed; goto failed;
} }
#endif
rc = dasd_devmap_init(); rc = dasd_devmap_init();
if (rc) if (rc)
goto failed; goto failed;
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* functions may not be called from interrupt context. In particular * functions may not be called from interrupt context. In particular
* dasd_get_device is a no-no from interrupt context. * dasd_get_device is a no-no from interrupt context.
* *
* $Revision: 1.11 $ * $Revision: 1.12 $
* *
* History of changes * History of changes
* 05/04/02 split from dasd.c, code restructuring. * 05/04/02 split from dasd.c, code restructuring.
...@@ -30,6 +30,25 @@ ...@@ -30,6 +30,25 @@
#include "dasd_int.h" #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: * Parameter parsing functions for dasd= parameter. The syntax is:
* <devno> : (0x)?[0-9a-fA-F]+ * <devno> : (0x)?[0-9a-fA-F]+
...@@ -278,6 +297,29 @@ dasd_add_range(int from, int to, int features) ...@@ -278,6 +297,29 @@ dasd_add_range(int from, int to, int features)
return 0; return 0;
} }
/*
* 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. * Forget all about the device numbers added so far.
* This may only be called at module unload or system shutdown. * This may only be called at module unload or system shutdown.
...@@ -307,7 +349,7 @@ dasd_forget_ranges(void) ...@@ -307,7 +349,7 @@ dasd_forget_ranges(void)
* Find the devmap structure from a devno. Can be removed as soon * Find the devmap structure from a devno. Can be removed as soon
* as big minors are available. * as big minors are available.
*/ */
dasd_devmap_t * static dasd_devmap_t *
dasd_devmap_from_devno(int devno) dasd_devmap_from_devno(int devno)
{ {
struct list_head *l; struct list_head *l;
...@@ -332,7 +374,7 @@ dasd_devmap_from_devno(int devno) ...@@ -332,7 +374,7 @@ dasd_devmap_from_devno(int devno)
* Find the devmap for a device by its device index. Can be removed * Find the devmap for a device by its device index. Can be removed
* as soon as big minors are available. * as soon as big minors are available.
*/ */
dasd_devmap_t * static dasd_devmap_t *
dasd_devmap_from_devindex(int devindex) dasd_devmap_from_devindex(int devindex)
{ {
struct list_head *l; struct list_head *l;
...@@ -353,60 +395,140 @@ dasd_devmap_from_devindex(int devindex) ...@@ -353,60 +395,140 @@ dasd_devmap_from_devindex(int devindex)
return devmap; 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_device_t *
dasd_get_device(dasd_devmap_t *devmap) dasd_device_from_devindex(int devindex)
{ {
dasd_devmap_t *devmap;
dasd_device_t *device; dasd_device_t *device;
devmap = dasd_devmap_from_devindex(devindex);
spin_lock(&dasd_devmap_lock); spin_lock(&dasd_devmap_lock);
device = devmap->device; device = devmap->device;
if (device != NULL) if (device)
atomic_inc(&device->ref_count); dasd_get_device(device);
else
device = ERR_PTR(-ENODEV);
spin_unlock(&dasd_devmap_lock); spin_unlock(&dasd_devmap_lock);
if (device != NULL)
return device; return device;
}
/*
* 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); device = dasd_alloc_device(devmap->devindex);
if (IS_ERR(device)) if (IS_ERR(device))
return 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); spin_lock_irq(get_ccwdev_lock(cdev));
if (devmap->device != NULL) { 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. */ /* Someone else was faster. */
rc = -EBUSY;
spin_unlock_irq(get_ccwdev_lock(cdev));
if (rc) {
dasd_free_device(device); dasd_free_device(device);
device = devmap->device; return ERR_PTR(rc);
} else }
/* Device created successfully. Make it known via devmap. */
spin_lock(&dasd_devmap_lock);
devmap->device = device; devmap->device = device;
atomic_inc(&device->ref_count);
device->ro_flag = (devmap->features & DASD_FEATURE_READONLY) ? 1 : 0;
device->use_diag_flag = 1;
spin_unlock(&dasd_devmap_lock); spin_unlock(&dasd_devmap_lock);
return device; return device;
} }
/* /*
* Decrease the reference counter of a devices structure. If the * Wait queue for dasd_delete_device waits.
* reference counter reaches zero and the device status is */
* DASD_STATE_NEW the device structure is freed. static DECLARE_WAIT_QUEUE_HEAD(dasd_delete_wq);
/*
* Remove a dasd device structure.
*/ */
void 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); spin_lock(&dasd_devmap_lock);
device = devmap->device;
if (atomic_dec_return(&device->ref_count) == 0 &&
device->state == DASD_STATE_NEW) {
devmap->device = NULL; devmap->device = NULL;
dasd_free_device(device);
}
spin_unlock(&dasd_devmap_lock); 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 int
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Bugreports.to..: <Linux390@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
* *
* $Revision: 1.27 $ * $Revision: 1.28 $
* *
* History of changes * History of changes
* 07/13/00 Added fixup sections for diagnoses ans saved some registers * 07/13/00 Added fixup sections for diagnoses ans saved some registers
...@@ -96,7 +96,7 @@ mdsk_init_io(dasd_device_t * device, int blocksize, int offset, int size) ...@@ -96,7 +96,7 @@ mdsk_init_io(dasd_device_t * device, int blocksize, int offset, int size)
iib = &private->iib; iib = &private->iib;
memset(iib, 0, sizeof (diag_init_io_t)); 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->block_size = blocksize;
iib->offset = offset; iib->offset = offset;
iib->start_block = 0; iib->start_block = 0;
...@@ -117,7 +117,7 @@ mdsk_term_io(dasd_device_t * device) ...@@ -117,7 +117,7 @@ mdsk_term_io(dasd_device_t * device)
private = (dasd_diag_private_t *) device->private; private = (dasd_diag_private_t *) device->private;
iib = &private->iib; iib = &private->iib;
memset(iib, 0, sizeof (diag_init_io_t)); 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); rc = dia250(iib, TERM_BIO);
return rc & 3; return rc & 3;
} }
...@@ -134,7 +134,7 @@ dasd_start_diag(dasd_ccw_req_t * cqr) ...@@ -134,7 +134,7 @@ dasd_start_diag(dasd_ccw_req_t * cqr)
private = (dasd_diag_private_t *) device->private; private = (dasd_diag_private_t *) device->private;
dreq = (dasd_diag_req_t *) cqr->data; 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.key = 0;
private->iob.flags = 2; /* do asynchronous io */ private->iob.flags = 2; /* do asynchronous io */
private->iob.block_count = dreq->block_count; private->iob.block_count = dreq->block_count;
...@@ -252,7 +252,7 @@ dasd_diag_check_device(dasd_device_t *device) ...@@ -252,7 +252,7 @@ dasd_diag_check_device(dasd_device_t *device)
} }
/* Read Device Characteristics */ /* Read Device Characteristics */
rdc_data = (void *) &(private->rdc_data); 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); rdc_data->rdc_len = sizeof (dasd_diag_characteristics_t);
rc = diag210((struct diag210 *) rdc_data); rc = diag210((struct diag210 *) rdc_data);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Bugreports.to..: <Linux390@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
* *
* $Revision: 1.36 $ * $Revision: 1.38 $
* *
* History of changes (starts July 2000) * History of changes (starts July 2000)
* 07/11/00 Enabled rotational position sensing * 07/11/00 Enabled rotational position sensing
...@@ -1003,7 +1003,7 @@ dasd_eckd_build_cp(dasd_device_t * device, struct request *req) ...@@ -1003,7 +1003,7 @@ dasd_eckd_build_cp(dasd_device_t * device, struct request *req)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
count += bv->bv_len >> (device->s2b_shift + 9); count += bv->bv_len >> (device->s2b_shift + 9);
#if defined(CONFIG_ARCH_S390X) #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); bv->bv_offset, bv->bv_len);
#endif #endif
} }
...@@ -1042,7 +1042,7 @@ dasd_eckd_build_cp(dasd_device_t * device, struct request *req) ...@@ -1042,7 +1042,7 @@ dasd_eckd_build_cp(dasd_device_t * device, struct request *req)
last_rec - recid + 1, cmd, device, blksize); last_rec - recid + 1, cmd, device, blksize);
} }
rq_for_each_bio(bio, req) bio_for_each_segment(bv, bio, i) { 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) { for (off = 0; off < bv->bv_len; off += blksize) {
sector_t trkid = recid; sector_t trkid = recid;
unsigned int recoffs = sector_div(trkid, blk_per_trk); unsigned int recoffs = sector_div(trkid, blk_per_trk);
...@@ -1453,6 +1453,8 @@ static dasd_discipline_t dasd_eckd_discipline = { ...@@ -1453,6 +1453,8 @@ static dasd_discipline_t dasd_eckd_discipline = {
static int __init static int __init
dasd_eckd_init(void) dasd_eckd_init(void)
{ {
int ret;
dasd_ioctl_no_register(THIS_MODULE, BIODASDSATTR, dasd_ioctl_no_register(THIS_MODULE, BIODASDSATTR,
dasd_eckd_set_attrib); dasd_eckd_set_attrib);
dasd_ioctl_no_register(THIS_MODULE, BIODASDPSRD, dasd_ioctl_no_register(THIS_MODULE, BIODASDPSRD,
...@@ -1466,7 +1468,22 @@ dasd_eckd_init(void) ...@@ -1466,7 +1468,22 @@ dasd_eckd_init(void)
ASCEBC(dasd_eckd_discipline.ebcname, 4); 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; return 0;
} }
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* Bugreports.to..: <Linux390@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
* *
* $Revision: 1.25 $ * $Revision: 1.27 $
* *
* History of changes * History of changes
* fixed partition handling and HDIO_GETGEO * fixed partition handling and HDIO_GETGEO
...@@ -414,9 +414,16 @@ static dasd_discipline_t dasd_fba_discipline = { ...@@ -414,9 +414,16 @@ static dasd_discipline_t dasd_fba_discipline = {
static int __init static int __init
dasd_fba_init(void) dasd_fba_init(void)
{ {
int ret;
ASCEBC(dasd_fba_discipline.ebcname, 4); 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 static void __exit
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* Dealing with devices registered to multiple major numbers. * Dealing with devices registered to multiple major numbers.
* *
* $Revision: 1.23 $ * $Revision: 1.24 $
* *
* History of changes * History of changes
* 05/04/02 split from dasd.c, code restructuring. * 05/04/02 split from dasd.c, code restructuring.
...@@ -108,7 +108,6 @@ dasd_unregister_major(struct major_info * mi) ...@@ -108,7 +108,6 @@ dasd_unregister_major(struct major_info * mi)
struct gendisk * struct gendisk *
dasd_gendisk_alloc(int devindex) dasd_gendisk_alloc(int devindex)
{ {
struct list_head *l;
struct major_info *mi; struct major_info *mi;
struct gendisk *gdp; struct gendisk *gdp;
int index, len, rc; int index, len, rc;
...@@ -118,8 +117,7 @@ dasd_gendisk_alloc(int devindex) ...@@ -118,8 +117,7 @@ dasd_gendisk_alloc(int devindex)
while (1) { while (1) {
spin_lock(&dasd_major_lock); spin_lock(&dasd_major_lock);
index = devindex; index = devindex;
list_for_each(l, &dasd_major_info) { list_for_each_entry(mi, &dasd_major_info, list) {
mi = list_entry(l, struct major_info, list);
if (index < DASD_PER_MAJOR) if (index < DASD_PER_MAJOR)
break; break;
index -= DASD_PER_MAJOR; index -= DASD_PER_MAJOR;
...@@ -142,6 +140,7 @@ dasd_gendisk_alloc(int devindex) ...@@ -142,6 +140,7 @@ dasd_gendisk_alloc(int devindex)
gdp->major = mi->major; gdp->major = mi->major;
gdp->first_minor = index << DASD_PARTN_BITS; gdp->first_minor = index << DASD_PARTN_BITS;
gdp->fops = &dasd_device_operations; gdp->fops = &dasd_device_operations;
gdp->flags |= GENHD_FL_DEVFS;
/* /*
* Set device name. * Set device name.
...@@ -191,14 +190,12 @@ static int dasd_gendisk_major_index(int major) ...@@ -191,14 +190,12 @@ static int dasd_gendisk_major_index(int major)
*/ */
int dasd_gendisk_index_major(int devindex) int dasd_gendisk_index_major(int devindex)
{ {
struct list_head *l;
struct major_info *mi; struct major_info *mi;
int rc; int rc;
spin_lock(&dasd_major_lock); spin_lock(&dasd_major_lock);
rc = -ENODEV; rc = -ENODEV;
list_for_each(l, &dasd_major_info) { list_for_each_entry(mi, &dasd_major_info, list) {
mi = list_entry(l, struct major_info, list);
if (devindex < DASD_PER_MAJOR) { if (devindex < DASD_PER_MAJOR) {
rc = mi->major; rc = mi->major;
break; break;
...@@ -231,6 +228,7 @@ void ...@@ -231,6 +228,7 @@ void
dasd_destroy_partitions(dasd_device_t * device) dasd_destroy_partitions(dasd_device_t * device)
{ {
del_gendisk(device->gdp); del_gendisk(device->gdp);
put_disk(device->gdp);
} }
int int
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Bugreports.to..: <Linux390@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
* *
* $Revision: 1.36 $ * $Revision: 1.38 $
* *
* History of changes (starts July 2000) * History of changes (starts July 2000)
* 02/01/01 added dynamic registration of ioctls * 02/01/01 added dynamic registration of ioctls
...@@ -297,10 +297,6 @@ typedef struct dasd_device_t { ...@@ -297,10 +297,6 @@ typedef struct dasd_device_t {
struct list_head ccw_chunks; struct list_head ccw_chunks;
struct list_head erp_chunks; struct list_head erp_chunks;
/* Common i/o stuff. */
/* FIXME: remove the next */
int devno;
atomic_t tasklet_scheduled; atomic_t tasklet_scheduled;
struct tasklet_struct tasklet; struct tasklet_struct tasklet;
struct work_struct kick_work; struct work_struct kick_work;
...@@ -315,24 +311,23 @@ typedef struct dasd_device_t { ...@@ -315,24 +311,23 @@ typedef struct dasd_device_t {
#endif #endif
} dasd_device_t; } dasd_device_t;
void dasd_put_device_wake(dasd_device_t *);
/* /*
* dasd_devmap_t is used to store the features and the relation * Reference count inliners
* 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 { static inline void
struct list_head devindex_list; dasd_get_device(dasd_device_t *device)
struct list_head devno_list; {
unsigned int devindex; atomic_inc(&device->ref_count);
unsigned short devno; }
unsigned short features;
dasd_device_t *device; static inline void
} dasd_devmap_t; 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 * The static memory in ccw_mem and erp_mem is managed by a sorted
...@@ -444,8 +439,9 @@ dasd_kmalloc_set_cda(struct ccw1 *ccw, void *cda, dasd_device_t *device) ...@@ -444,8 +439,9 @@ dasd_kmalloc_set_cda(struct ccw1 *ccw, void *cda, dasd_device_t *device)
return set_normalized_cda(ccw, cda); 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_free_device(dasd_device_t *);
void dasd_enable_device(dasd_device_t *); void dasd_enable_device(dasd_device_t *);
void dasd_set_target_state(dasd_device_t *, int); void dasd_set_target_state(dasd_device_t *, int);
void dasd_kick_device(dasd_device_t *); void dasd_kick_device(dasd_device_t *);
...@@ -467,6 +463,7 @@ int dasd_generic_remove (struct ccw_device *cdev); ...@@ -467,6 +463,7 @@ int dasd_generic_remove (struct ccw_device *cdev);
int dasd_generic_set_online(struct ccw_device *cdev, int dasd_generic_set_online(struct ccw_device *cdev,
dasd_discipline_t *discipline); dasd_discipline_t *discipline);
int dasd_generic_set_offline (struct ccw_device *cdev); int dasd_generic_set_offline (struct ccw_device *cdev);
void dasd_generic_auto_online (struct ccw_driver *);
/* externals in dasd_devmap.c */ /* externals in dasd_devmap.c */
extern int dasd_max_devindex; extern int dasd_max_devindex;
...@@ -475,13 +472,16 @@ extern int dasd_autodetect; ...@@ -475,13 +472,16 @@ extern int dasd_autodetect;
int dasd_devmap_init(void); int dasd_devmap_init(void);
void dasd_devmap_exit(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_create_device(struct ccw_device *);
dasd_device_t *dasd_get_device(dasd_devmap_t *); void dasd_delete_device(dasd_device_t *);
void dasd_put_device(dasd_devmap_t *);
kdev_t dasd_get_kdev(dasd_device_t *);
dasd_device_t *dasd_device_from_devindex(int);
int dasd_parse(void); int dasd_parse(void);
int dasd_add_range(int, int, int); int dasd_add_range(int, int, int);
int dasd_devno_in_range(int);
/* externals in dasd_gendisk.c */ /* externals in dasd_gendisk.c */
int dasd_gendisk_init(void); int dasd_gendisk_init(void);
......
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
* 05/04/02 split from dasd.c, code restructuring. * 05/04/02 split from dasd.c, code restructuring.
*/ */
#include <linux/config.h> #include <linux/config.h>
#include <linux/version.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/major.h> #include <linux/major.h>
#include <linux/fs.h> #include <linux/fs.h>
...@@ -333,7 +332,7 @@ dasd_ioctl_information(struct block_device *bdev, int no, long args) ...@@ -333,7 +332,7 @@ dasd_ioctl_information(struct block_device *bdev, int no, long args)
cdev = device->cdev; 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->schid = _ccw_device_get_subchannel_number(device->cdev);
dasd_info->cu_type = cdev->id.cu_type; dasd_info->cu_type = cdev->id.cu_type;
dasd_info->cu_model = cdev->id.cu_model; dasd_info->cu_model = cdev->id.cu_model;
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* /proc interface for the dasd driver. * /proc interface for the dasd driver.
* *
* $Revision: 1.17 $ * $Revision: 1.18 $
* *
* History of changes * History of changes
* 05/04/02 split from dasd.c, code restructuring. * 05/04/02 split from dasd.c, code restructuring.
...@@ -56,17 +56,14 @@ dasd_get_user_string(const char *user_buf, size_t user_len) ...@@ -56,17 +56,14 @@ dasd_get_user_string(const char *user_buf, size_t user_len)
static int static int
dasd_devices_show(struct seq_file *m, void *v) dasd_devices_show(struct seq_file *m, void *v)
{ {
dasd_devmap_t *devmap;
dasd_device_t *device; dasd_device_t *device;
char *substr; char *substr;
devmap = dasd_devmap_from_devindex((unsigned long) v - 1); device = dasd_device_from_devindex((unsigned long) v - 1);
device = (devmap != NULL) ?
dasd_get_device(devmap) : ERR_PTR(-ENODEV);
if (IS_ERR(device)) if (IS_ERR(device))
return 0; return 0;
/* Print device number. */ /* Print device number. */
seq_printf(m, "%04x", devmap->devno); seq_printf(m, "%04x", _ccw_device_get_device_number(device->cdev));
/* Print discipline string. */ /* Print discipline string. */
if (device != NULL && device->discipline != NULL) if (device != NULL && device->discipline != NULL)
seq_printf(m, "(%s)", device->discipline->name); seq_printf(m, "(%s)", device->discipline->name);
...@@ -113,7 +110,7 @@ dasd_devices_show(struct seq_file *m, void *v) ...@@ -113,7 +110,7 @@ dasd_devices_show(struct seq_file *m, void *v)
seq_printf(m, "no stat"); seq_printf(m, "no stat");
break; break;
} }
dasd_put_device(devmap); dasd_put_device(device);
if (dasd_probeonly) if (dasd_probeonly)
seq_printf(m, "(probeonly)"); seq_printf(m, "(probeonly)");
seq_printf(m, "\n"); seq_printf(m, "\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment