Commit fd791128 authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Linus Torvalds

[PATCH] s390 update (7/27): dasd driver.

parent 7441ad13
......@@ -203,20 +203,24 @@ dasd_device_t *
dasd_alloc_device(dasd_devmap_t *devmap)
{
dasd_device_t *device;
struct gendisk *gdp;
int rc;
/* Make sure the gendisk structure for this device exists. */
while (dasd_gendisk_from_devindex(devmap->devindex) == NULL) {
rc = dasd_gendisk_new_major();
if (rc)
return ERR_PTR(rc);
}
device = kmalloc(sizeof (dasd_device_t), GFP_ATOMIC);
if (device == NULL)
return ERR_PTR(-ENOMEM);
memset(device, 0, sizeof (dasd_device_t));
/* Get devinfo from the common io layer. */
rc = get_dev_info_by_devno(devmap->devno, &device->devinfo);
if (rc) {
kfree(device);
return ERR_PTR(rc);
}
DBF_EVENT(DBF_NOTICE, "got devinfo CU-type %04x and dev-type %04x",
device->devinfo.sid_data.cu_type,
device->devinfo.sid_data.dev_type);
/* 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) {
......@@ -231,17 +235,15 @@ dasd_alloc_device(dasd_devmap_t *devmap)
return ERR_PTR(-ENOMEM);
}
/* Get devinfo from the common io layer. */
rc = get_dev_info_by_devno(devmap->devno, &device->devinfo);
if (rc) {
free_page((unsigned long) device->erp_mem);
/* Allocate gendisk structure for device. */
gdp = dasd_gendisk_alloc(device->name, devmap->devindex);
if (IS_ERR(gdp)) {
free_page((unsigned long) device->erp_mem);
free_pages((unsigned long) device->ccw_mem, 1);
kfree(device);
return ERR_PTR(rc);
return (dasd_device_t *) gdp;
}
DBF_EVENT(DBF_NOTICE, "got devinfo CU-type %04x and dev-type %04x",
device->devinfo.sid_data.cu_type,
device->devinfo.sid_data.dev_type);
device->gdp = gdp;
dasd_init_chunklist(&device->ccw_chunks, device->ccw_mem, PAGE_SIZE*2);
dasd_init_chunklist(&device->erp_chunks, device->erp_mem, PAGE_SIZE);
......@@ -268,6 +270,7 @@ dasd_free_device(dasd_device_t *device)
kfree(device->private);
free_page((unsigned long) device->erp_mem);
free_pages((unsigned long) device->ccw_mem, 1);
dasd_gendisk_free(device->gdp);
kfree(device);
}
......@@ -278,21 +281,22 @@ static inline int
dasd_state_new_to_known(dasd_device_t *device)
{
char buffer[5];
struct gendisk *gdp;
dasd_devmap_t *devmap;
umode_t devfs_perm;
devfs_handle_t dir;
int minor, rc;
int major, minor, rc;
devmap = dasd_devmap_from_devno(device->devinfo.devno);
if (devmap == NULL)
return -ENODEV;
gdp = dasd_gendisk_from_devindex(devmap->devindex);
if (gdp == NULL)
major = dasd_gendisk_index_major(devmap->devindex);
if (major < 0)
return -ENODEV;
/* Set kdev and the device name. */
device->kdev = mk_kdev(gdp->major, gdp->first_minor);
strcpy(device->name, gdp->disk_name);
minor = devmap->devindex % DASD_PER_MAJOR;
/* Set bdev and the device name. */
device->bdev = bdget(MKDEV(major, minor << DASD_PARTN_BITS));
strcpy(device->name, device->gdp->disk_name);
/* Find a discipline for the device. */
rc = dasd_find_disc(device);
......@@ -302,14 +306,13 @@ dasd_state_new_to_known(dasd_device_t *device)
/* Add a proc directory and the dasd device entry to devfs. */
sprintf(buffer, "%04x", device->devinfo.devno);
dir = devfs_mk_dir(dasd_devfs_handle, buffer, device);
gdp->de = dir;
device->gdp->de = dir;
if (devmap->features & DASD_FEATURE_READONLY)
devfs_perm = S_IFBLK | S_IRUSR;
else
devfs_perm = S_IFBLK | S_IRUSR | S_IWUSR;
device->devfs_entry = devfs_register(dir, "device", DEVFS_FL_DEFAULT,
major(device->kdev),
minor(device->kdev),
major, minor << DASD_PARTN_BITS,
devfs_perm,
&dasd_device_operations, NULL);
device->state = DASD_STATE_KNOWN;
......@@ -322,17 +325,25 @@ dasd_state_new_to_known(dasd_device_t *device)
static inline void
dasd_state_known_to_new(dasd_device_t * device)
{
dasd_devmap_t *devmap = dasd_devmap_from_devno(device->devinfo.devno);
struct gendisk *gdp = dasd_gendisk_from_devindex(devmap->devindex);
if (gdp == NULL)
return;
dasd_devmap_t *devmap;
struct block_device *bdev;
int minor;
devmap = dasd_devmap_from_devno(device->devinfo.devno);
minor = devmap->devindex % DASD_PER_MAJOR;
/* Remove device entry and devfs directory. */
devfs_unregister(device->devfs_entry);
devfs_unregister(gdp->de);
devfs_unregister(device->gdp->de);
/* Forget the discipline information. */
device->discipline = NULL;
device->state = DASD_STATE_NEW;
/* Forget the block device */
bdev = device->bdev;
device->bdev = NULL;
bdput(bdev);
}
/*
......@@ -418,6 +429,17 @@ dasd_state_accept_to_basic(dasd_device_t * device)
device->state = DASD_STATE_BASIC;
}
/*
* get the kdev_t of a device
* FIXME: remove this when no longer needed
*/
static inline kdev_t
dasd_partition_to_kdev_t(dasd_device_t *device, unsigned int partition)
{
return to_kdev_t(device->bdev->bd_dev+partition);
}
/*
* Setup block device.
*/
......@@ -425,15 +447,12 @@ static inline int
dasd_state_accept_to_ready(dasd_device_t * device)
{
dasd_devmap_t *devmap;
int major, minor;
int rc, i;
devmap = dasd_devmap_from_devno(device->devinfo.devno);
if (devmap->features & DASD_FEATURE_READONLY) {
major = major(device->kdev);
minor = minor(device->kdev);
for (i = 0; i < (1 << DASD_PARTN_BITS); i++)
set_device_ro(mk_kdev(major, minor+i), 1);
set_device_ro(dasd_partition_to_kdev_t(device, i), 1);
DEV_MESSAGE (KERN_WARNING, device, "%s",
"setting read-only mode ");
}
......@@ -1539,11 +1558,9 @@ __dasd_process_ccw_queue(dasd_device_t * device, struct list_head *final_queue)
goto restart;
}
/* Dechain request from device request queue ... */
/* Rechain request on device device request queue */
cqr->endclk = get_clock();
list_del(&cqr->list);
/* ... and add it to list of final requests. */
list_add_tail(&cqr->list, final_queue);
list_move_tail(&cqr->list, final_queue);
}
}
......@@ -1572,6 +1589,10 @@ __dasd_process_blk_queue(dasd_device_t * device)
dasd_ccw_req_t *cqr;
int nr_queued;
/* No bdev, no queue. */
bdev = device->bdev;
if (!bdev)
return;
queue = device->request_queue;
/* No queue ? Then there is nothing to do. */
if (queue == NULL)
......@@ -1594,9 +1615,6 @@ __dasd_process_blk_queue(dasd_device_t * device)
if (cqr->status == DASD_CQR_QUEUED)
nr_queued++;
}
bdev = bdget(kdev_t_to_nr(device->kdev));
if (!bdev)
return;
while (!blk_queue_plugged(queue) &&
!blk_queue_empty(queue) &&
nr_queued < DASD_CHANQ_MAX_SIZE) {
......@@ -1628,7 +1646,6 @@ __dasd_process_blk_queue(dasd_device_t * device)
dasd_profile_start(device, cqr, req);
nr_queued++;
}
bdput(bdev);
}
/*
......@@ -1707,11 +1724,9 @@ dasd_flush_ccw_queue(dasd_device_t * device, int all)
__dasd_process_erp(device, cqr);
continue;
}
/* Dechain request from device request queue ... */
/* Rechain request on device request queue */
cqr->endclk = get_clock();
list_del(&cqr->list);
/* ... and add it to list of flushed requests. */
list_add_tail(&cqr->list, &flush_queue);
list_move_tail(&cqr->list, &flush_queue);
}
spin_unlock_irq(get_irq_lock(device->devinfo.irq));
/* Now call the callback function of flushed requests */
......
......@@ -448,6 +448,15 @@ dasd_devmap_from_kdev(kdev_t kdev)
return dasd_devmap_from_devindex(devindex);
}
/*
* Find the devmap for a device corresponding to a block_device.
*/
dasd_devmap_t *
dasd_devmap_from_bdev(struct block_device *bdev)
{
return dasd_devmap_from_kdev(to_kdev_t(bdev->bd_dev));
}
/*
* Find the device structure for device number devno. If it does not
* exists yet, allocate it. Increase the reference counter in the device
......
......@@ -21,6 +21,7 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/hdreg.h> /* HDIO_GETGEO */
#include <linux/bio.h>
#include <asm/dasd.h>
#include <asm/debug.h>
......@@ -53,31 +54,6 @@ typedef struct dasd_diag_req_t {
diag_bio_t bio[0];
} dasd_diag_req_t;
static __inline__ int
dia210(void *devchar)
{
int rc;
__asm__ __volatile__(" diag %1,0,0x210\n"
"0: ipm %0\n"
" srl %0,28\n"
"1:\n"
".section .fixup,\"ax\"\n"
"2: lhi %0,3\n"
" bras 1,3f\n"
" .long 1b\n"
"3: l 1,0(1)\n"
" br 1\n"
".previous\n"
".section __ex_table,\"a\"\n"
" .align 4\n"
" .long 0b,2b\n" ".previous\n":"=d"(rc)
:"d"((void *) __pa(devchar))
:"1");
return rc;
}
static __inline__ int
dia250(void *iob, int cmd)
{
......@@ -155,7 +131,7 @@ dasd_start_diag(dasd_ccw_req_t * cqr)
private->iob.key = 0;
private->iob.flags = 2; /* do asynchronous io */
private->iob.block_count = dreq->block_count;
private->iob.interrupt_params = (u32) cqr;
private->iob.interrupt_params = (u32)(addr_t) cqr;
private->iob.bio_list = __pa(dreq->bio);
cqr->startclk = get_clock();
......@@ -196,21 +172,21 @@ dasd_ext_handler(struct pt_regs *regs, __u16 code)
ip = S390_lowcore.ext_params;
cpu = smp_processor_id();
irq_enter(cpu, -1);
irq_enter();
if (!ip) { /* no intparm: unsolicited interrupt */
MESSAGE(KERN_DEBUG, "%s", "caught unsolicited interrupt");
irq_exit(cpu, -1);
irq_exit();
return;
}
cqr = (dasd_ccw_req_t *) ip;
cqr = (dasd_ccw_req_t *)(addr_t) ip;
device = (dasd_device_t *) cqr->device;
if (strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
DEV_MESSAGE(KERN_WARNING, device,
" magic number of dasd_ccw_req_t 0x%08X doesn't"
" match discipline 0x%08X",
cqr->magic, *(int *) (&device->discipline->name));
irq_exit(cpu, -1);
irq_exit();
return;
}
......@@ -244,8 +220,7 @@ dasd_ext_handler(struct pt_regs *regs, __u16 code)
dasd_schedule_bh(device);
spin_unlock_irqrestore(get_irq_lock(device->devinfo.irq), flags);
irq_exit(cpu, -1);
irq_exit();
}
static int
......@@ -273,7 +248,7 @@ dasd_diag_check_device(dasd_device_t *device)
rdc_data->dev_nr = device->devinfo.devno;
rdc_data->rdc_len = sizeof (dasd_diag_characteristics_t);
rc = dia210(rdc_data);
rc = diag210((diag210_t *) rdc_data);
if (rc)
return -ENOTSUPP;
......
......@@ -29,6 +29,7 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/hdreg.h> /* HDIO_GETGEO */
#include <linux/bio.h>
#include <asm/debug.h>
#include <asm/idals.h>
......@@ -69,7 +70,6 @@ typedef struct dasd_eckd_private_t {
attrib_data_t attrib; /* e.g. cache operations */
} dasd_eckd_private_t;
#ifdef CONFIG_DASD_DYNAMIC
static
devreg_t dasd_eckd_known_devices[] = {
{
......@@ -94,7 +94,6 @@ devreg_t dasd_eckd_known_devices[] = {
oper_func:dasd_oper_handler
}
};
#endif
static const int sizes_trk0[] = { 28, 148, 84 };
#define LABEL_SIZE 140
......@@ -1092,7 +1091,8 @@ dasd_eckd_fill_info(dasd_device_t * device, dasd_information2_t * info)
* Buils a channel programm to releases a prior reserved
* (see dasd_eckd_reserve) device.
*/
static int dasd_eckd_release(void *inp, int no, long args)
static int
dasd_eckd_release(struct block_device *bdev, int no, long args)
{
dasd_devmap_t *devmap;
dasd_device_t *device;
......@@ -1101,7 +1101,7 @@ static int dasd_eckd_release(void *inp, int no, long args)
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
devmap = dasd_devmap_from_kdev(((struct inode *) inp)->i_rdev);
devmap = dasd_devmap_from_bdev(bdev);
device = (devmap != NULL) ?
dasd_get_device(devmap) : ERR_PTR(-ENODEV);
if (IS_ERR(device))
......@@ -1134,7 +1134,8 @@ static int dasd_eckd_release(void *inp, int no, long args)
* 'timeout the request'. This leads to an terminate IO if
* the interrupt is outstanding for a certain time.
*/
static int dasd_eckd_reserve(void *inp, int no, long args)
static int
dasd_eckd_reserve(struct block_device *bdev, int no, long args)
{
dasd_devmap_t *devmap;
dasd_device_t *device;
......@@ -1143,7 +1144,7 @@ static int dasd_eckd_reserve(void *inp, int no, long args)
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
devmap = dasd_devmap_from_kdev(((struct inode *) inp)->i_rdev);
devmap = dasd_devmap_from_bdev(bdev);
device = (devmap != NULL) ?
dasd_get_device(devmap) : ERR_PTR(-ENODEV);
if (IS_ERR(device))
......@@ -1168,7 +1169,7 @@ static int dasd_eckd_reserve(void *inp, int no, long args)
if (rc == -EIO) {
/* Request got an eror or has been timed out. */
dasd_eckd_release(inp, no, args);
dasd_eckd_release(bdev, no, args);
}
dasd_kfree_request(cqr, cqr->device);
dasd_put_device(devmap);
......@@ -1180,7 +1181,8 @@ static int dasd_eckd_reserve(void *inp, int no, long args)
* Buils a channel programm to break a device's reservation.
* (unconditional reserve)
*/
static int dasd_eckd_steal_lock(void *inp, int no, long args)
static int
dasd_eckd_steal_lock(struct block_device *bdev, int no, long args)
{
dasd_devmap_t *devmap;
dasd_device_t *device;
......@@ -1189,7 +1191,7 @@ static int dasd_eckd_steal_lock(void *inp, int no, long args)
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
devmap = dasd_devmap_from_kdev(((struct inode *) inp)->i_rdev);
devmap = dasd_devmap_from_bdev(bdev);
device = (devmap != NULL) ?
dasd_get_device(devmap) : ERR_PTR(-ENODEV);
if (IS_ERR(device))
......@@ -1213,7 +1215,7 @@ static int dasd_eckd_steal_lock(void *inp, int no, long args)
if (rc == -EIO) {
/* Request got an eror or has been timed out. */
dasd_eckd_release(inp, no, args);
dasd_eckd_release(bdev, no, args);
}
dasd_kfree_request(cqr, cqr->device);
dasd_put_device(devmap);
......@@ -1223,7 +1225,8 @@ static int dasd_eckd_steal_lock(void *inp, int no, long args)
/*
* Read performance statistics
*/
static int dasd_eckd_performance(void *inp, int no, long args)
static int
dasd_eckd_performance(struct block_device *bdev, int no, long args)
{
dasd_devmap_t *devmap;
dasd_device_t *device;
......@@ -1233,7 +1236,7 @@ static int dasd_eckd_performance(void *inp, int no, long args)
ccw1_t *ccw;
int rc;
devmap = dasd_devmap_from_kdev(((struct inode *) inp)->i_rdev);
devmap = dasd_devmap_from_bdev(bdev);
device = (devmap != NULL) ?
dasd_get_device(devmap) : ERR_PTR(-ENODEV);
if (IS_ERR(device))
......@@ -1292,7 +1295,8 @@ static int dasd_eckd_performance(void *inp, int no, long args)
* Set attributes (cache operations)
* Stores the attributes for cache operation to be used in Define Extend (DE).
*/
static int dasd_eckd_set_attrib(void *inp, int no, long args)
static int
dasd_eckd_set_attrib(struct block_device *bdev, int no, long args)
{
dasd_devmap_t *devmap;
dasd_device_t *device;
......@@ -1304,7 +1308,7 @@ static int dasd_eckd_set_attrib(void *inp, int no, long args)
if (!args)
return -EINVAL;
devmap = dasd_devmap_from_kdev(((struct inode *) inp)->i_rdev);
devmap = dasd_devmap_from_bdev(bdev);
device = (devmap != NULL) ?
dasd_get_device(devmap) : ERR_PTR(-ENODEV);
if (IS_ERR(device))
......@@ -1452,10 +1456,8 @@ dasd_eckd_init(void)
ASCEBC(dasd_eckd_discipline.ebcname, 4);
dasd_discipline_add(&dasd_eckd_discipline);
#ifdef CONFIG_DASD_DYNAMIC
for (i = 0; i < sizeof(dasd_eckd_known_devices)/sizeof(devreg_t); i++)
s390_device_register(&dasd_eckd_known_devices[i]);
#endif
return 0;
}
......@@ -1464,10 +1466,8 @@ dasd_eckd_cleanup(void)
{
int i;
#ifdef CONFIG_DASD_DYNAMIC
for (i = 0; i < sizeof(dasd_eckd_known_devices)/sizeof(devreg_t); i++)
s390_device_unregister(&dasd_eckd_known_devices[i]);
#endif /* CONFIG_DASD_DYNAMIC */
dasd_discipline_del(&dasd_eckd_discipline);
......
......@@ -16,6 +16,7 @@
#include <linux/slab.h>
#include <linux/hdreg.h> /* HDIO_GETGEO */
#include <linux/bio.h>
#include <asm/idals.h>
#include <asm/ebcdic.h>
......@@ -43,7 +44,6 @@ typedef struct dasd_fba_private_t {
dasd_fba_characteristics_t rdc_data;
} dasd_fba_private_t;
#ifdef CONFIG_DASD_DYNAMIC
static
devreg_t dasd_fba_known_devices[] = {
{
......@@ -59,7 +59,6 @@ devreg_t dasd_fba_known_devices[] = {
oper_func:dasd_oper_handler
}
};
#endif
static inline void
define_extent(ccw1_t * ccw, DE_fba_data_t *data, int rw,
......@@ -417,10 +416,8 @@ dasd_fba_init(void)
ASCEBC(dasd_fba_discipline.ebcname, 4);
dasd_discipline_add(&dasd_fba_discipline);
#ifdef CONFIG_DASD_DYNAMIC
for (i = 0; i < sizeof(dasd_fba_known_devices) / sizeof(devreg_t); i++)
s390_device_register(&dasd_fba_known_devices[i]);
#endif
return 0;
}
......@@ -429,10 +426,8 @@ dasd_fba_cleanup(void)
{
int i;
#ifdef CONFIG_DASD_DYNAMIC
for (i = 0; i < sizeof(dasd_fba_known_devices) / sizeof(devreg_t); i++)
s390_device_unregister(&dasd_fba_known_devices[i]);
#endif
dasd_discipline_del(&dasd_fba_discipline);
}
......
......@@ -33,7 +33,6 @@ static struct list_head dasd_major_info = LIST_HEAD_INIT(dasd_major_info);
struct major_info {
struct list_head list;
int major;
struct gendisk disks[DASD_PER_MAJOR];
};
/*
......@@ -65,12 +64,8 @@ static int
dasd_register_major(int major)
{
struct major_info *mi;
int new_major, rc;
struct list_head *l;
int index;
int i;
int new_major;
rc = 0;
/* Allocate major info structure. */
mi = kmalloc(sizeof(struct major_info), GFP_KERNEL);
......@@ -79,66 +74,39 @@ dasd_register_major(int major)
MESSAGE(KERN_WARNING, "%s",
"Cannot get memory to allocate another "
"major number");
rc = -ENOMEM;
goto out_error;
return -ENOMEM;
}
/* Register block device. */
new_major = register_blkdev(major, "dasd", &dasd_device_operations);
if (new_major < 0) {
MESSAGE(KERN_WARNING,
"Cannot register to major no %d, rc = %d", major, rc);
rc = new_major;
goto out_error;
"Cannot register to major no %d, rc = %d",
major, new_major);
kfree(mi);
return new_major;
}
if (major != 0)
new_major = major;
/* Initialize major info structure. */
memset(mi, 0, sizeof(struct major_info));
mi->major = new_major;
for (i = 0; i < DASD_PER_MAJOR; i++) {
struct gendisk *disk = mi->disks + i;
disk->major = new_major;
disk->first_minor = i << DASD_PARTN_BITS;
disk->minor_shift = DASD_PARTN_BITS;
disk->fops = &dasd_device_operations;
disk->flags = GENHD_FL_DEVFS;
}
/* Setup block device pointers for the new major. */
blk_dev[new_major].queue = dasd_get_queue;
/* Insert the new major info structure into dasd_major_info list. */
spin_lock(&dasd_major_lock);
index = 0;
list_for_each(l, &dasd_major_info)
index += DASD_PER_MAJOR;
for (i = 0; i < DASD_PER_MAJOR; i++, index++) {
name = mi->disks[i].disk_name;
sprintf(name, "dasd");
name += 4;
if (index > 701)
*name++ = 'a' + (((index - 702) / 676) % 26);
if (index > 25)
*name++ = 'a' + (((index - 26) / 26) % 26);
sprintf(name, "%c", 'a' + (index % 26));
}
list_add_tail(&mi->list, &dasd_major_info);
spin_unlock(&dasd_major_lock);
return 0;
/* Something failed. Do the cleanup and return rc. */
out_error:
/* We rely on kfree to do the != NULL check. */
kfree(mi);
return rc;
}
static void
dasd_unregister_major(struct major_info * mi)
{
int major, rc;
int rc;
if (mi == NULL)
return;
......@@ -149,99 +117,177 @@ dasd_unregister_major(struct major_info * mi)
spin_unlock(&dasd_major_lock);
/* Clear block device pointers. */
major = mi->major;
blk_dev[major].queue = NULL;
blk_dev[mi->major].queue = NULL;
rc = unregister_blkdev(major, "dasd");
rc = unregister_blkdev(mi->major, "dasd");
if (rc < 0)
MESSAGE(KERN_WARNING,
"Cannot unregister from major no %d, rc = %d",
major, rc);
mi->major, rc);
/* Free memory. */
kfree(mi);
}
/*
* Dynamically allocate a new major for dasd devices.
* This one is needed for naming 18000+ possible dasd devices.
* dasda - dasdz : 26 devices
* dasdaa - dasdzz : 676 devices, added up = 702
* dasdaaa - dasdzzz : 17576 devices, added up = 18278
*/
int
dasd_gendisk_new_major(void)
dasd_device_name(char *str, int index, int partition)
{
int rc;
rc = dasd_register_major(0);
if (rc)
DBF_EXC(DBF_ALERT, "%s", "out of major numbers!");
return rc;
int len;
if (partition > DASD_PARTN_MASK)
return -EINVAL;
len = sprintf(str, "dasd");
if (index > 25) {
if (index > 701)
len += sprintf(str + len, "%c",
'a' + (((index - 702) / 676) % 26));
len += sprintf(str + len, "%c",
'a' + (((index - 26) / 26) % 26));
}
len += sprintf(str + len, "%c", 'a' + (index % 26));
if (partition)
len += sprintf(str + len, "%d", partition);
return 0;
}
/*
* Return pointer to gendisk structure by kdev.
* Allocate gendisk structure for devindex.
*/
static struct gendisk *dasd_gendisk_by_dev(kdev_t dev)
struct gendisk *
dasd_gendisk_alloc(char *device_name, int devindex)
{
struct list_head *l;
struct major_info *mi;
struct gendisk *gdp;
int major = major(dev);
spin_lock(&dasd_major_lock);
gdp = NULL;
list_for_each(l, &dasd_major_info) {
mi = list_entry(l, struct major_info, list);
if (mi->major == major) {
gdp = &mi->disks[minor(dev) >> DASD_PARTN_BITS];
struct hd_struct *gd_part;
int index, len, rc;
/* Make sure the major for this device exists. */
mi = NULL;
while (1) {
spin_lock(&dasd_major_lock);
index = devindex;
list_for_each(l, &dasd_major_info) {
mi = list_entry(l, struct major_info, list);
if (index < DASD_PER_MAJOR)
break;
index -= DASD_PER_MAJOR;
}
spin_unlock(&dasd_major_lock);
if (index < DASD_PER_MAJOR)
break;
rc = dasd_register_major(0);
if (rc) {
DBF_EXC(DBF_ALERT, "%s", "out of major numbers!");
return ERR_PTR(rc);
}
}
spin_unlock(&dasd_major_lock);
/* Allocate genhd structure and gendisk arrays. */
gdp = kmalloc(sizeof(struct gendisk), GFP_KERNEL);
gd_part = kmalloc(sizeof (struct hd_struct) << DASD_PARTN_BITS,
GFP_ATOMIC);
/* Check if one of the allocations failed. */
if (gdp == NULL || gd_part == NULL) {
/* We rely on kfree to do the != NULL check. */
kfree(gd_part);
kfree(gdp);
return ERR_PTR(-ENOMEM);
}
/* Initialize gendisk structure. */
memset(gdp, 0, sizeof(struct gendisk));
memcpy(gdp->disk_name, device_name, 16);
gdp->major = mi->major;
gdp->first_minor = index << DASD_PARTN_BITS;
gdp->minor_shift = DASD_PARTN_BITS;
gdp->part = gd_part;
gdp->fops = &dasd_device_operations;
/*
* Set device name.
* dasda - dasdz : 26 devices
* dasdaa - dasdzz : 676 devices, added up = 702
* dasdaaa - dasdzzz : 17576 devices, added up = 18278
*/
len = sprintf(device_name, "dasd");
if (devindex > 25) {
if (devindex > 701)
len += sprintf(device_name + len, "%c",
'a' + (((devindex - 702) / 676) % 26));
len += sprintf(device_name + len, "%c",
'a' + (((devindex - 26) / 26) % 26));
}
len += sprintf(device_name + len, "%c", 'a' + (devindex % 26));
/* Initialize the gendisk arrays. */
memset(gd_part, 0, sizeof (struct hd_struct) << DASD_PARTN_BITS);
return gdp;
}
/*
* Return pointer to gendisk structure by devindex.
* Free gendisk structure for devindex.
*/
struct gendisk *
dasd_gendisk_from_devindex(int devindex)
void
dasd_gendisk_free(struct gendisk *gdp)
{
/* Free memory. */
kfree(gdp->part);
kfree(gdp);
}
/*
* Return devindex of first device using a specific major number.
*/
int dasd_gendisk_major_index(int major)
{
struct list_head *l;
struct major_info *mi;
struct gendisk *gdp;
int devindex, rc;
spin_lock(&dasd_major_lock);
gdp = NULL;
rc = -EINVAL;
devindex = 0;
list_for_each(l, &dasd_major_info) {
mi = list_entry(l, struct major_info, list);
if (devindex < DASD_PER_MAJOR) {
gdp = &mi->disks[devindex];
if (mi->major == major) {
rc = devindex;
break;
}
devindex -= DASD_PER_MAJOR;
devindex += DASD_PER_MAJOR;
}
spin_unlock(&dasd_major_lock);
return gdp;
return rc;
}
/*
* Return devindex of first device using a specifiy major number.
* Return major number for device with device index devindex.
*/
int dasd_gendisk_major_index(int major)
int dasd_gendisk_index_major(int devindex)
{
struct list_head *l;
struct major_info *mi;
int devindex, rc;
int rc;
spin_lock(&dasd_major_lock);
rc = -EINVAL;
devindex = 0;
rc = -ENODEV;
list_for_each(l, &dasd_major_info) {
mi = list_entry(l, struct major_info, list);
if (mi->major == major) {
rc = devindex;
if (devindex < DASD_PER_MAJOR) {
rc = mi->major;
break;
}
devindex += DASD_PER_MAJOR;
devindex -= DASD_PER_MAJOR;
}
spin_unlock(&dasd_major_lock);
return rc;
......@@ -253,11 +299,9 @@ int dasd_gendisk_major_index(int major)
void
dasd_setup_partitions(dasd_device_t * device)
{
struct gendisk *disk = dasd_gendisk_by_dev(device->kdev);
if (disk == NULL)
return;
set_capacity(disk, device->blocks << device->s2b_shift);
add_disk(disk);
/* Make the disk known. */
set_capacity(device->gdp, device->blocks << device->s2b_shift);
add_disk(device->gdp);
}
/*
......@@ -267,13 +311,7 @@ dasd_setup_partitions(dasd_device_t * device)
void
dasd_destroy_partitions(dasd_device_t * device)
{
struct gendisk *disk = dasd_gendisk_by_dev(device->kdev);
int minor, i;
if (disk == NULL)
return;
del_gendisk(disk);
del_gendisk(device->gdp);
}
int
......@@ -294,6 +332,7 @@ void
dasd_gendisk_exit(void)
{
struct list_head *l, *n;
spin_lock(&dasd_major_lock);
list_for_each_safe(l, n, &dasd_major_info)
dasd_unregister_major(list_entry(l, struct major_info, list));
......
......@@ -64,12 +64,12 @@
#include <asm/irq.h>
#include <asm/s390dyn.h>
#define CONFIG_DASD_DYNAMIC
/*
* SECTION: Type definitions
*/
typedef int (*dasd_ioctl_fn_t) (void *inp, int no, long args);
struct dasd_device_t;
typedef int (*dasd_ioctl_fn_t) (struct block_device *bdev, int no, long args);
typedef struct {
struct list_head list;
......@@ -139,9 +139,8 @@ do { \
/* messages to be written via klogd and dbf */
#define DEV_MESSAGE(d_loglevel,d_device,d_string,d_args...)\
do { \
printk(d_loglevel PRINTK_HEADER " /dev/%-7s(%3d:%3d),%04x@%02x: " \
d_string "\n", d_device->name, \
major(d_device->kdev), minor(d_device->kdev), \
printk(d_loglevel PRINTK_HEADER " %s,%04x@%02x: " \
d_string "\n", bdevname(d_device->bdev), \
d_device->devinfo.devno, d_device->devinfo.irq, \
d_args); \
DBF_DEV_EVENT(DBF_ALERT, d_device, d_string, d_args); \
......@@ -153,8 +152,6 @@ do { \
DBF_EVENT(DBF_ALERT, d_string, d_args); \
} while(0)
struct dasd_device_t;
typedef struct dasd_ccw_req_t {
unsigned int magic; /* Eye catcher */
struct list_head list; /* list_head for request queueing. */
......@@ -262,7 +259,8 @@ typedef struct dasd_discipline_t {
typedef struct dasd_device_t {
/* Block device stuff. */
char name[16]; /* The device name in /dev. */
kdev_t kdev;
struct block_device *bdev;
struct gendisk *gdp;
devfs_handle_t devfs_entry;
request_queue_t *request_queue;
spinlock_t request_queue_lock;
......@@ -467,6 +465,7 @@ dasd_devmap_t *dasd_devmap_from_devno(int);
dasd_devmap_t *dasd_devmap_from_devindex(int);
dasd_devmap_t *dasd_devmap_from_irq(int);
dasd_devmap_t *dasd_devmap_from_kdev(kdev_t);
dasd_devmap_t *dasd_devmap_from_bdev(struct block_device *bdev);
dasd_device_t *dasd_get_device(dasd_devmap_t *);
void dasd_put_device(dasd_devmap_t *);
......@@ -478,9 +477,10 @@ int dasd_add_range(int, int, int);
/* externals in dasd_gendisk.c */
int dasd_gendisk_init(void);
void dasd_gendisk_exit(void);
int dasd_gendisk_new_major(void);
int dasd_gendisk_major_index(int);
struct gendisk *dasd_gendisk_from_devindex(int);
int dasd_gendisk_index_major(int);
struct gendisk *dasd_gendisk_alloc(char *, int);
void dasd_gendisk_free(struct gendisk *);
void dasd_setup_partitions(dasd_device_t *);
void dasd_destroy_partitions(dasd_device_t *);
......
This diff is collapsed.
......@@ -15,6 +15,7 @@
#include <linux/config.h>
#include <linux/version.h>
#include <linux/ctype.h>
#include <linux/vmalloc.h>
#include <asm/debug.h>
#include <asm/irq.h>
......@@ -123,7 +124,7 @@ dasd_devices_write(struct file *file, const char *user_buf,
}
features = dasd_feature_list(str, &str);
/* Negative numbers in from/to/features indicate errors */
if (from < 0 || to < 0 || features < 0)
if (from < 0 || to < 0 || from > 65546 || to > 65536 || features < 0)
goto out_error;
if (add_or_set == 0) {
......@@ -152,10 +153,8 @@ static inline int
dasd_devices_print(dasd_devmap_t *devmap, char *str)
{
dasd_device_t *device;
struct gendisk *gdp;
char buffer[7];
char *substr;
int minor;
int major, minor;
int len;
device = dasd_get_device(devmap);
......@@ -169,11 +168,11 @@ dasd_devices_print(dasd_devmap_t *devmap, char *str)
else
len += sprintf(str + len, "(none)");
/* Print kdev. */
gdp = dasd_gendisk_from_devindex(devmap->devindex);
minor = devmap->devindex % DASD_PER_MAJOR;
len += sprintf(str + len, " at (%3d:%3d)", gdp->major, minor);
major = MAJOR(device->bdev->bd_dev);
minor = MINOR(device->bdev->bd_dev);
len += sprintf(str + len, " at (%3d:%3d)", major, minor);
/* Print device name. */
len += sprintf(str + len, " is %-7s", gdp->disk_name);
len += sprintf(str + len, " is %-7s", device->name);
/* Print devices features. */
substr = (devmap->features & DASD_FEATURE_READONLY) ? "(ro)" : " ";
len += sprintf(str + len, "%4s: ", substr);
......
......@@ -13,6 +13,8 @@
* 12/06/01 DASD_API_VERSION 2 - binary compatible to 0 (new BIODASDINFO2)
* 01/23/02 DASD_API_VERSION 3 - added BIODASDPSRD (and BIODASDENAPAV) IOCTL
* 02/15/02 DASD_API_VERSION 4 - added BIODASDSATTR IOCTL
* ##/##/## DASD_API_VERSION 5 - added boxed dasd support TOBEDONE
* 21/06/02 DASD_API_VERSION 6 - fixed HDIO_GETGEO: geo.start is in sectors!
*
*/
......@@ -22,7 +24,7 @@
#define DASD_IOCTL_LETTER 'D'
#define DASD_API_VERSION 4
#define DASD_API_VERSION 6
/*
* struct dasd_information2_t
......
......@@ -13,6 +13,8 @@
* 12/06/01 DASD_API_VERSION 2 - binary compatible to 0 (new BIODASDINFO2)
* 01/23/02 DASD_API_VERSION 3 - added BIODASDPSRD (and BIODASDENAPAV) IOCTL
* 02/15/02 DASD_API_VERSION 4 - added BIODASDSATTR IOCTL
* ##/##/## DASD_API_VERSION 5 - added boxed dasd support TOBEDONE
* 21/06/02 DASD_API_VERSION 6 - fixed HDIO_GETGEO: geo.start is in sectors!
*
*/
......@@ -22,7 +24,7 @@
#define DASD_IOCTL_LETTER 'D'
#define DASD_API_VERSION 4
#define DASD_API_VERSION 6
/*
* struct dasd_information2_t
......
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