Commit 21df060f authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] s390: dasd driver

From: Martin Schwidefsky <schwidefsky@de.ibm.com>

 - Fix interrupt status examination.
 - Make dasd device attributes dependent on the devmap structure instead of
   the device structure to make them persistent and to be able to modify
   them in the offline state.
 - Allow changing the readonly attribute while dasd is online.
 - Add (diag) option to dasd= paramter.
 - Add missing spin_lock_init call.
 - Increase ref_count in dasd_device_from_cdev and add matching
   dasd_put_device pairs.
 - Adapt to notify api change in cio.
 - Fix bug in 3990 error recovery for cable pulls on ESS.
 - Replace kmap by page_address (no highmem on s/390).
 - Set correct default cache mode on ESS for eckd devices.
 - Change dasd names from "dasdx" to "dasd_<busid>_".
parent b2b9268a
...@@ -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.114 $ * $Revision: 1.123 $
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -43,7 +43,6 @@ MODULE_DESCRIPTION("Linux on S/390 DASD device driver," ...@@ -43,7 +43,6 @@ MODULE_DESCRIPTION("Linux on S/390 DASD device driver,"
" Copyright 2000 IBM Corporation"); " Copyright 2000 IBM Corporation");
MODULE_SUPPORTED_DEVICE("dasd"); MODULE_SUPPORTED_DEVICE("dasd");
MODULE_PARM(dasd, "1-" __MODULE_STRING(256) "s"); MODULE_PARM(dasd, "1-" __MODULE_STRING(256) "s");
MODULE_PARM(dasd_disciplines, "1-" __MODULE_STRING(8) "s");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
/* /*
...@@ -57,7 +56,6 @@ static void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *); ...@@ -57,7 +56,6 @@ static void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *);
static void dasd_flush_ccw_queue(struct dasd_device *, int); static void dasd_flush_ccw_queue(struct dasd_device *, int);
static void dasd_tasklet(struct dasd_device *); static void dasd_tasklet(struct dasd_device *);
static void do_kick_device(void *data); static void do_kick_device(void *data);
static int dasd_add_sysfs_files(struct ccw_device *cdev);
/* /*
* SECTION: Operations on the device structure. * SECTION: Operations on the device structure.
...@@ -93,6 +91,7 @@ dasd_alloc_device(void) ...@@ -93,6 +91,7 @@ dasd_alloc_device(void)
dasd_init_chunklist(&device->ccw_chunks, device->ccw_mem, PAGE_SIZE*2); dasd_init_chunklist(&device->ccw_chunks, device->ccw_mem, PAGE_SIZE*2);
dasd_init_chunklist(&device->erp_chunks, device->erp_mem, PAGE_SIZE); dasd_init_chunklist(&device->erp_chunks, device->erp_mem, PAGE_SIZE);
spin_lock_init(&device->mem_lock);
spin_lock_init(&device->request_queue_lock); spin_lock_init(&device->request_queue_lock);
atomic_set (&device->tasklet_scheduled, 0); atomic_set (&device->tasklet_scheduled, 0);
tasklet_init(&device->tasklet, tasklet_init(&device->tasklet,
...@@ -860,7 +859,7 @@ dasd_handle_killed_request(struct ccw_device *cdev, unsigned long intparm) ...@@ -860,7 +859,7 @@ dasd_handle_killed_request(struct ccw_device *cdev, unsigned long intparm)
device = (struct dasd_device *) cqr->device; device = (struct dasd_device *) cqr->device;
if (device == NULL || if (device == NULL ||
device != cdev->dev.driver_data || device != dasd_device_from_cdev(cdev) ||
strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) { strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
MESSAGE(KERN_DEBUG, "invalid device in request: bus_id %s", MESSAGE(KERN_DEBUG, "invalid device in request: bus_id %s",
cdev->dev.bus_id); cdev->dev.bus_id);
...@@ -872,6 +871,7 @@ dasd_handle_killed_request(struct ccw_device *cdev, unsigned long intparm) ...@@ -872,6 +871,7 @@ dasd_handle_killed_request(struct ccw_device *cdev, unsigned long intparm)
dasd_clear_timer(device); dasd_clear_timer(device);
dasd_schedule_bh(device); dasd_schedule_bh(device);
dasd_put_device(device);
} }
static void static void
...@@ -931,7 +931,11 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, ...@@ -931,7 +931,11 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
/* first of all check for state change pending interrupt */ /* first of all check for state change pending interrupt */
mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP; mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP;
if ((irb->scsw.dstat & mask) == mask) { if ((irb->scsw.dstat & mask) == mask) {
dasd_handle_state_change_pending(cdev->dev.driver_data); device = dasd_device_from_cdev(cdev);
if (!IS_ERR(device)) {
dasd_handle_state_change_pending(device);
dasd_put_device(device);
}
return; return;
} }
...@@ -949,7 +953,6 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, ...@@ -949,7 +953,6 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
device = (struct dasd_device *) cqr->device; device = (struct dasd_device *) cqr->device;
if (device == NULL || if (device == NULL ||
device != cdev->dev.driver_data ||
strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) { strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
MESSAGE(KERN_DEBUG, "invalid device in request: bus_id %s", MESSAGE(KERN_DEBUG, "invalid device in request: bus_id %s",
cdev->dev.bus_id); cdev->dev.bus_id);
...@@ -959,17 +962,19 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, ...@@ -959,17 +962,19 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
DBF_DEV_EVENT(DBF_DEBUG, device, "Int: CS/DS 0x%04x", DBF_DEV_EVENT(DBF_DEBUG, device, "Int: CS/DS 0x%04x",
((irb->scsw.cstat << 8) | irb->scsw.dstat)); ((irb->scsw.cstat << 8) | irb->scsw.dstat));
/* Find out the appropriate era_action. */ /* Find out the appropriate era_action. */
era = dasd_era_none; if (irb->scsw.fctl & SCSW_FCTL_HALT_FUNC)
if (irb->scsw.dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END) || era = dasd_era_fatal;
irb->esw.esw0.erw.cons) { else if (irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) &&
/* The request did end abnormally. */ irb->scsw.cstat == 0 &&
if (irb->scsw.fctl & SCSW_FCTL_HALT_FUNC) !irb->esw.esw0.erw.cons)
era = dasd_era_fatal; era = dasd_era_none;
else else if (irb->esw.esw0.erw.cons)
era = device->discipline->examine_error(cqr, irb); era = device->discipline->examine_error(cqr, irb);
DBF_EVENT(DBF_NOTICE, "era_code %d", era); else
} era = dasd_era_recover;
DBF_DEV_EVENT(DBF_DEBUG, device, "era_code %d", era);
expires = 0; expires = 0;
if (era == dasd_era_none) { if (era == dasd_era_none) {
cqr->status = DASD_CQR_DONE; cqr->status = DASD_CQR_DONE;
...@@ -1149,6 +1154,11 @@ __dasd_process_blk_queue(struct dasd_device * device) ...@@ -1149,6 +1154,11 @@ __dasd_process_blk_queue(struct dasd_device * device)
dasd_end_request(req, 0); dasd_end_request(req, 0);
continue; continue;
} }
if (device->stopped & DASD_STOPPED_DC_EIO) {
blkdev_dequeue_request(req);
dasd_end_request(req, 0);
continue;
}
cqr = device->discipline->build_cp(device, req); cqr = device->discipline->build_cp(device, req);
if (IS_ERR(cqr)) { if (IS_ERR(cqr)) {
if (PTR_ERR(cqr) == -ENOMEM) if (PTR_ERR(cqr) == -ENOMEM)
...@@ -1728,17 +1738,10 @@ int ...@@ -1728,17 +1738,10 @@ int
dasd_generic_probe (struct ccw_device *cdev, dasd_generic_probe (struct ccw_device *cdev,
struct dasd_discipline *discipline) struct dasd_discipline *discipline)
{ {
int ret = 0; int ret;
if (dasd_autodetect &&
(ret = dasd_add_busid(cdev->dev.bus_id, DASD_FEATURE_DEFAULT))) {
printk (KERN_WARNING
"dasd_generic_probe: cannot autodetect %s\n",
cdev->dev.bus_id);
return ret;
}
if (!ret && (ret = dasd_add_sysfs_files(cdev))) { ret = dasd_add_sysfs_files(cdev);
if (ret) {
printk(KERN_WARNING printk(KERN_WARNING
"dasd_generic_probe: could not add driverfs entries" "dasd_generic_probe: could not add driverfs entries"
"for %s\n", cdev->dev.bus_id); "for %s\n", cdev->dev.bus_id);
...@@ -1751,16 +1754,17 @@ dasd_generic_probe (struct ccw_device *cdev, ...@@ -1751,16 +1754,17 @@ dasd_generic_probe (struct ccw_device *cdev,
/* this will one day be called from a global not_oper handler. /* this will one day be called from a global not_oper handler.
* It is also used by driver_unregister during module unload */ * It is also used by driver_unregister during module unload */
int void
dasd_generic_remove (struct ccw_device *cdev) dasd_generic_remove (struct ccw_device *cdev)
{ {
struct dasd_device *device; struct dasd_device *device;
device = cdev->dev.driver_data; device = dasd_device_from_cdev(cdev);
cdev->dev.driver_data = NULL; if (!IS_ERR(device)) {
if (device) dasd_set_target_state(device, DASD_STATE_NEW);
kfree(device); /* dasd_delete_device destroys the device reference. */
return 0; dasd_delete_device(device);
}
} }
/* activate a device. This is called from dasd_{eckd,fba}_probe() when either /* activate a device. This is called from dasd_{eckd,fba}_probe() when either
...@@ -1779,24 +1783,14 @@ dasd_generic_set_online (struct ccw_device *cdev, ...@@ -1779,24 +1783,14 @@ dasd_generic_set_online (struct ccw_device *cdev,
return PTR_ERR(device); return PTR_ERR(device);
if (device->use_diag_flag) if (device->use_diag_flag)
device->discipline = dasd_diag_discipline_pointer; discipline = dasd_diag_discipline_pointer;
device->discipline = discipline;
rc = 0; rc = discipline->check_device(device);
if (!device->discipline ||
(rc = device->discipline->check_device(device))) {
pr_debug("device %s is not diag (%d)\n",
cdev->dev.bus_id, rc);
if (device->private != NULL) {
kfree(device->private);
device->private = NULL;
}
device->discipline = discipline;
rc = discipline->check_device(device);
}
if (rc) { if (rc) {
printk (KERN_WARNING "dasd_generic found a bad device %s\n", printk (KERN_WARNING
cdev->dev.bus_id); "dasd_generic couldn't online device %s "
"with discipline %s\n",
cdev->dev.bus_id, discipline->name);
dasd_delete_device(device); dasd_delete_device(device);
return rc; return rc;
} }
...@@ -1809,16 +1803,16 @@ dasd_generic_set_online (struct ccw_device *cdev, ...@@ -1809,16 +1803,16 @@ dasd_generic_set_online (struct ccw_device *cdev,
rc = -ENODEV; rc = -ENODEV;
dasd_set_target_state(device, DASD_STATE_NEW); dasd_set_target_state(device, DASD_STATE_NEW);
dasd_delete_device(device); 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;
}
/* 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));
dasd_put_device(device);
return rc; return rc;
} }
...@@ -1827,18 +1821,68 @@ dasd_generic_set_offline (struct ccw_device *cdev) ...@@ -1827,18 +1821,68 @@ dasd_generic_set_offline (struct ccw_device *cdev)
{ {
struct dasd_device *device; struct dasd_device *device;
device = cdev->dev.driver_data; device = dasd_device_from_cdev(cdev);
dasd_set_target_state(device, DASD_STATE_NEW); if (atomic_read(&device->open_count) > 0) {
dasd_delete_device(device); printk (KERN_WARNING "Can't offline dasd device with open"
" count = %i.\n",
atomic_read(&device->open_count));
dasd_put_device(device);
return -EBUSY;
}
dasd_put_device(device);
dasd_generic_remove (cdev);
return 0; return 0;
} }
int
dasd_generic_notify(struct ccw_device *cdev, int event)
{
struct dasd_device *device;
struct dasd_ccw_req *cqr;
unsigned long flags;
int ret;
device = dasd_device_from_cdev(cdev);
if (IS_ERR(device))
return 0;
spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
ret = 0;
switch (event) {
case CIO_GONE:
case CIO_NO_PATH:
if (device->state < DASD_STATE_BASIC)
break;
/* Device is active. We want to keep it. */
if (device->disconnect_error_flag) {
list_for_each_entry(cqr, &device->ccw_queue, list)
if (cqr->status == DASD_CQR_IN_IO)
cqr->status = DASD_CQR_FAILED;
device->stopped |= DASD_STOPPED_DC_EIO;
dasd_schedule_bh(device);
} else {
list_for_each_entry(cqr, &device->ccw_queue, list)
if (cqr->status == DASD_CQR_IN_IO)
cqr->status = DASD_CQR_QUEUED;
device->stopped |= DASD_STOPPED_DC_WAIT;
dasd_set_timer(device, 0);
}
ret = 1;
break;
case CIO_OPER:
/* FIXME: add a sanity check. */
device->stopped &= ~(DASD_STOPPED_DC_WAIT|DASD_STOPPED_DC_EIO);
dasd_schedule_bh(device);
ret = 1;
break;
}
spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
dasd_put_device(device);
return ret;
}
/* /*
* Automatically online either all dasd devices (dasd_autodetect) or * Automatically online either all dasd devices (dasd_autodetect) or
* all devices specified with dasd= parameters. For dasd_autodetect * all devices specified with dasd= parameters.
* dasd_generic_probe has added devmaps for all dasd devices. We
* scan all present dasd devmaps and call ccw_device_set_online.
*/ */
void void
dasd_generic_auto_online (struct ccw_driver *dasd_discipline_driver) dasd_generic_auto_online (struct ccw_driver *dasd_discipline_driver)
...@@ -1863,97 +1907,6 @@ dasd_generic_auto_online (struct ccw_driver *dasd_discipline_driver) ...@@ -1863,97 +1907,6 @@ dasd_generic_auto_online (struct ccw_driver *dasd_discipline_driver)
put_driver(drv); put_driver(drv);
} }
/*
* SECTION: files in sysfs
*/
/*
* readonly controls the readonly status of a dasd
*/
static ssize_t
dasd_ro_show(struct device *dev, char *buf)
{
struct dasd_device *device;
device = dev->driver_data;
if (!device)
return snprintf(buf, PAGE_SIZE, "n/a\n");
return snprintf(buf, PAGE_SIZE, device->ro_flag ? "1\n" : "0\n");
}
static ssize_t
dasd_ro_store(struct device *dev, const char *buf, size_t count)
{
struct dasd_device *device = dev->driver_data;
if (device)
device->ro_flag = (buf[0] == '1') ? 1 : 0;
return count;
}
static DEVICE_ATTR(readonly, 0644, dasd_ro_show, dasd_ro_store);
/*
* use_diag controls whether the driver should use diag rather than ssch
* to talk to the device
*/
/* TODO: Implement */
static ssize_t
dasd_use_diag_show(struct device *dev, char *buf)
{
struct dasd_device *device;
device = dev->driver_data;
if (!device)
return sprintf(buf, "n/a\n");
return sprintf(buf, device->use_diag_flag ? "1\n" : "0\n");
}
static ssize_t
dasd_use_diag_store(struct device *dev, const char *buf, size_t count)
{
struct dasd_device *device = dev->driver_data;
if (device)
device->use_diag_flag = (buf[0] == '1') ? 1 : 0;
return count;
}
static
DEVICE_ATTR(use_diag, 0644, dasd_use_diag_show, dasd_use_diag_store);
static ssize_t
dasd_discipline_show(struct device *dev, char *buf)
{
struct dasd_device *device;
device = dev->driver_data;
if (!device || !device->discipline)
return sprintf(buf, "none\n");
return snprintf(buf, PAGE_SIZE, "%s\n", device->discipline->name);
}
static DEVICE_ATTR(discipline, 0444, dasd_discipline_show, NULL);
static struct attribute * dasd_attrs[] = {
&dev_attr_readonly.attr,
&dev_attr_discipline.attr,
&dev_attr_use_diag.attr,
NULL,
};
static struct attribute_group dasd_attr_group = {
.attrs = dasd_attrs,
};
static int
dasd_add_sysfs_files(struct ccw_device *cdev)
{
return sysfs_create_group(&cdev->dev.kobj, &dasd_attr_group);
}
static int __init static int __init
dasd_init(void) dasd_init(void)
{ {
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* Bugreports.to..: <Linux390@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000, 2001 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000, 2001
* *
* $Revision: 1.25 $ * $Revision: 1.26 $
*/ */
#include <linux/timer.h> #include <linux/timer.h>
...@@ -312,7 +312,8 @@ dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp) ...@@ -312,7 +312,8 @@ dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp)
erp->lpm, erp->dstat->esw.esw0.sublog.lpum, opm); erp->lpm, erp->dstat->esw.esw0.sublog.lpum, opm);
/* reset status to queued to handle the request again... */ /* reset status to queued to handle the request again... */
erp->status = DASD_CQR_QUEUED; if (erp->status > DASD_CQR_QUEUED)
erp->status = DASD_CQR_QUEUED;
erp->retries = 1; erp->retries = 1;
} else { } else {
DEV_MESSAGE(KERN_ERR, device, DEV_MESSAGE(KERN_ERR, device,
...@@ -321,7 +322,8 @@ dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp) ...@@ -321,7 +322,8 @@ dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp)
erp->dstat->esw.esw0.sublog.lpum, opm); erp->dstat->esw.esw0.sublog.lpum, opm);
/* post request with permanent error */ /* post request with permanent error */
erp->status = DASD_CQR_FAILED; if (erp->status > DASD_CQR_QUEUED)
erp->status = DASD_CQR_FAILED;
} }
} /* end dasd_3990_erp_alternate_path */ } /* end dasd_3990_erp_alternate_path */
......
...@@ -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.19 $ * $Revision: 1.25 $
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -79,6 +79,8 @@ static spinlock_t dasd_devmap_lock = SPIN_LOCK_UNLOCKED; ...@@ -79,6 +79,8 @@ static spinlock_t dasd_devmap_lock = SPIN_LOCK_UNLOCKED;
static struct list_head dasd_hashlists[256]; static struct list_head dasd_hashlists[256];
int dasd_max_devindex; int dasd_max_devindex;
static struct dasd_devmap *dasd_add_busid(char *, int);
static inline int static inline int
dasd_hash_busid(char *bus_id) dasd_hash_busid(char *bus_id)
{ {
...@@ -168,12 +170,16 @@ dasd_feature_list(char *str, char **endp) ...@@ -168,12 +170,16 @@ dasd_feature_list(char *str, char **endp)
*endp = str; *endp = str;
return DASD_FEATURE_DEFAULT; return DASD_FEATURE_DEFAULT;
} }
str++;
features = 0; features = 0;
while (1) { while (1) {
for (len = 0; for (len = 0;
str[len] && str[len] != ':' && str[len] != ')'; len++); str[len] && str[len] != ':' && str[len] != ')'; len++);
if (len == 2 && !strncmp(str, "ro", 2)) if (len == 2 && !strncmp(str, "ro", 2))
features |= DASD_FEATURE_READONLY; features |= DASD_FEATURE_READONLY;
else if (len == 4 && !strncmp(str, "diag", 4))
features |= DASD_FEATURE_USEDIAG;
else { else {
MESSAGE(KERN_WARNING, MESSAGE(KERN_WARNING,
"unsupported feature: %*s, " "unsupported feature: %*s, "
...@@ -203,6 +209,7 @@ dasd_feature_list(char *str, char **endp) ...@@ -203,6 +209,7 @@ dasd_feature_list(char *str, char **endp)
static inline int static inline int
dasd_ranges_list(char *str) dasd_ranges_list(char *str)
{ {
struct dasd_devmap *devmap;
int from, from_id0, from_id1; int from, from_id0, from_id1;
int to, to_id0, to_id1; int to, to_id0, to_id1;
int features, rc; int features, rc;
...@@ -233,9 +240,9 @@ dasd_ranges_list(char *str) ...@@ -233,9 +240,9 @@ dasd_ranges_list(char *str)
while (from <= to) { while (from <= to) {
sprintf(bus_id, "%01x.%01x.%04x", sprintf(bus_id, "%01x.%01x.%04x",
from_id0, from_id1, from++); from_id0, from_id1, from++);
rc = dasd_add_busid(bus_id, features); devmap = dasd_add_busid(bus_id, features);
if (rc) if (IS_ERR(devmap))
return rc; return PTR_ERR(devmap);
} }
if (*str != ',') if (*str != ',')
break; break;
...@@ -299,7 +306,7 @@ dasd_parse(void) ...@@ -299,7 +306,7 @@ dasd_parse(void)
* added through this function will define the kdevs for the individual * added through this function will define the kdevs for the individual
* devices. * devices.
*/ */
int static struct dasd_devmap *
dasd_add_busid(char *bus_id, int features) dasd_add_busid(char *bus_id, int features)
{ {
struct dasd_devmap *devmap, *new, *tmp; struct dasd_devmap *devmap, *new, *tmp;
...@@ -308,7 +315,7 @@ dasd_add_busid(char *bus_id, int features) ...@@ -308,7 +315,7 @@ dasd_add_busid(char *bus_id, int features)
new = (struct dasd_devmap *) new = (struct dasd_devmap *)
kmalloc(sizeof(struct dasd_devmap), GFP_KERNEL); kmalloc(sizeof(struct dasd_devmap), GFP_KERNEL);
if (!new) if (!new)
return -ENOMEM; return ERR_PTR(-ENOMEM);
spin_lock(&dasd_devmap_lock); spin_lock(&dasd_devmap_lock);
devmap = 0; devmap = 0;
hash = dasd_hash_busid(bus_id); hash = dasd_hash_busid(bus_id);
...@@ -330,7 +337,7 @@ dasd_add_busid(char *bus_id, int features) ...@@ -330,7 +337,7 @@ dasd_add_busid(char *bus_id, int features)
spin_unlock(&dasd_devmap_lock); spin_unlock(&dasd_devmap_lock);
if (new) if (new)
kfree(new); kfree(new);
return 0; return devmap;
} }
/* /*
...@@ -343,7 +350,7 @@ dasd_find_busid(char *bus_id) ...@@ -343,7 +350,7 @@ dasd_find_busid(char *bus_id)
int hash; int hash;
spin_lock(&dasd_devmap_lock); spin_lock(&dasd_devmap_lock);
devmap = 0; devmap = ERR_PTR(-ENODEV);
hash = dasd_hash_busid(bus_id); hash = dasd_hash_busid(bus_id);
list_for_each_entry(tmp, &dasd_hashlists[hash], list) { list_for_each_entry(tmp, &dasd_hashlists[hash], list) {
if (strncmp(tmp->bus_id, bus_id, BUS_ID_SIZE) == 0) { if (strncmp(tmp->bus_id, bus_id, BUS_ID_SIZE) == 0) {
...@@ -361,7 +368,7 @@ dasd_find_busid(char *bus_id) ...@@ -361,7 +368,7 @@ dasd_find_busid(char *bus_id)
int int
dasd_busid_known(char *bus_id) dasd_busid_known(char *bus_id)
{ {
return dasd_find_busid(bus_id) ? 0 : -ENOENT; return IS_ERR(dasd_find_busid(bus_id)) ? -ENOENT : 0;
} }
/* /*
...@@ -414,6 +421,28 @@ dasd_device_from_devindex(int devindex) ...@@ -414,6 +421,28 @@ dasd_device_from_devindex(int devindex)
return device; return device;
} }
/*
* Return devmap for cdev. If no devmap exists yet, create one and
* connect it to the cdev.
*/
static struct dasd_devmap *
dasd_devmap_from_cdev(struct ccw_device *cdev)
{
struct dasd_devmap *devmap;
if (cdev->dev.driver_data)
return (struct dasd_devmap *) cdev->dev.driver_data;
devmap = dasd_find_busid(cdev->dev.bus_id);
if (!IS_ERR(devmap)) {
cdev->dev.driver_data = devmap;
return devmap;
}
devmap = dasd_add_busid(cdev->dev.bus_id, DASD_FEATURE_DEFAULT);
if (!IS_ERR(devmap))
cdev->dev.driver_data = devmap;
return devmap;
}
/* /*
* Create a dasd device structure for cdev. * Create a dasd device structure for cdev.
*/ */
...@@ -424,41 +453,35 @@ dasd_create_device(struct ccw_device *cdev) ...@@ -424,41 +453,35 @@ dasd_create_device(struct ccw_device *cdev)
struct dasd_device *device; struct dasd_device *device;
int rc; int rc;
rc = dasd_add_busid(cdev->dev.bus_id, DASD_FEATURE_DEFAULT); devmap = dasd_devmap_from_cdev(cdev);
if (rc)
return ERR_PTR(rc);
devmap = dasd_find_busid(cdev->dev.bus_id);
if (IS_ERR(devmap)) if (IS_ERR(devmap))
return (void *) devmap; return (void *) devmap;
device = dasd_alloc_device(); device = dasd_alloc_device();
if (IS_ERR(device)) if (IS_ERR(device))
return device; return device;
atomic_set(&device->ref_count, 1); atomic_set(&device->ref_count, 2);
device->devindex = devmap->devindex;
device->ro_flag = (devmap->features & DASD_FEATURE_READONLY) ? 1 : 0;
device->use_diag_flag = 1;
spin_lock_irq(get_ccwdev_lock(cdev)); spin_lock(&dasd_devmap_lock);
if (cdev->dev.driver_data == NULL) { if (!devmap->device) {
devmap->device = device;
device->devindex = devmap->devindex;
device->ro_flag =
(devmap->features & DASD_FEATURE_READONLY) != 0;
device->use_diag_flag =
(devmap->features & DASD_FEATURE_USEDIAG) != 0;
get_device(&cdev->dev); get_device(&cdev->dev);
cdev->dev.driver_data = device;
device->cdev = cdev; device->cdev = cdev;
rc = 0; rc = 0;
} else } else
/* Someone else was faster. */ /* Someone else was faster. */
rc = -EBUSY; rc = -EBUSY;
spin_unlock_irq(get_ccwdev_lock(cdev)); spin_unlock(&dasd_devmap_lock);
if (rc) { if (rc) {
dasd_free_device(device); dasd_free_device(device);
return ERR_PTR(rc); 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; return device;
} }
...@@ -468,7 +491,8 @@ dasd_create_device(struct ccw_device *cdev) ...@@ -468,7 +491,8 @@ dasd_create_device(struct ccw_device *cdev)
static DECLARE_WAIT_QUEUE_HEAD(dasd_delete_wq); static DECLARE_WAIT_QUEUE_HEAD(dasd_delete_wq);
/* /*
* Remove a dasd device structure. * Remove a dasd device structure. The passed referenced
* is destroyed.
*/ */
void void
dasd_delete_device(struct dasd_device *device) dasd_delete_device(struct dasd_device *device)
...@@ -479,17 +503,24 @@ dasd_delete_device(struct dasd_device *device) ...@@ -479,17 +503,24 @@ dasd_delete_device(struct dasd_device *device)
/* First remove device pointer from devmap. */ /* First remove device pointer from devmap. */
devmap = dasd_find_busid(device->cdev->dev.bus_id); devmap = dasd_find_busid(device->cdev->dev.bus_id);
spin_lock(&dasd_devmap_lock); spin_lock(&dasd_devmap_lock);
if (devmap->device != device) {
spin_unlock(&dasd_devmap_lock);
dasd_put_device(device);
return;
}
devmap->device = NULL; devmap->device = NULL;
spin_unlock(&dasd_devmap_lock); spin_unlock(&dasd_devmap_lock);
/* Drop ref_count by 2, one for the devmap reference and
* one for the passed reference. */
atomic_sub(2, &device->ref_count);
/* Wait for reference counter to drop to zero. */ /* Wait for reference counter to drop to zero. */
atomic_dec(&device->ref_count);
wait_event(dasd_delete_wq, atomic_read(&device->ref_count) == 0); wait_event(dasd_delete_wq, atomic_read(&device->ref_count) == 0);
/* Disconnect dasd_device structure from ccw_device structure. */ /* Disconnect dasd_device structure from ccw_device structure. */
cdev = device->cdev; cdev = device->cdev;
device->cdev = NULL; device->cdev = NULL;
cdev->dev.driver_data = NULL;
/* Put ccw_device structure. */ /* Put ccw_device structure. */
put_device(&cdev->dev); put_device(&cdev->dev);
...@@ -508,6 +539,148 @@ dasd_put_device_wake(struct dasd_device *device) ...@@ -508,6 +539,148 @@ dasd_put_device_wake(struct dasd_device *device)
wake_up(&dasd_delete_wq); wake_up(&dasd_delete_wq);
} }
/*
* Return dasd_device structure associated with cdev.
*/
struct dasd_device *
dasd_device_from_cdev(struct ccw_device *cdev)
{
struct dasd_devmap *devmap;
struct dasd_device *device;
device = ERR_PTR(-ENODEV);
spin_lock(&dasd_devmap_lock);
devmap = cdev->dev.driver_data;
if (devmap && devmap->device) {
device = devmap->device;
dasd_get_device(device);
}
spin_unlock(&dasd_devmap_lock);
return device;
}
/*
* SECTION: files in sysfs
*/
/*
* readonly controls the readonly status of a dasd
*/
static ssize_t
dasd_ro_show(struct device *dev, char *buf)
{
struct dasd_devmap *devmap;
int ro_flag;
devmap = dev->driver_data;
if (devmap)
ro_flag = (devmap->features & DASD_FEATURE_READONLY) != 0;
else
ro_flag = (DASD_FEATURE_DEFAULT & DASD_FEATURE_READONLY) != 0;
return snprintf(buf, PAGE_SIZE, ro_flag ? "1\n" : "0\n");
}
static ssize_t
dasd_ro_store(struct device *dev, const char *buf, size_t count)
{
struct dasd_devmap *devmap;
int ro_flag;
devmap = dasd_devmap_from_cdev(to_ccwdev(dev));
ro_flag = buf[0] == '1';
spin_lock(&dasd_devmap_lock);
if (ro_flag)
devmap->features |= DASD_FEATURE_READONLY;
else
devmap->features &= ~DASD_FEATURE_READONLY;
if (devmap->device) {
if (devmap->device->gdp)
set_disk_ro(devmap->device->gdp, ro_flag);
devmap->device->ro_flag = ro_flag;
}
spin_unlock(&dasd_devmap_lock);
return count;
}
static DEVICE_ATTR(readonly, 0644, dasd_ro_show, dasd_ro_store);
/*
* use_diag controls whether the driver should use diag rather than ssch
* to talk to the device
*/
/* TODO: Implement */
static ssize_t
dasd_use_diag_show(struct device *dev, char *buf)
{
struct dasd_devmap *devmap;
int use_diag;
devmap = dev->driver_data;
if (devmap)
use_diag = (devmap->features & DASD_FEATURE_USEDIAG) != 0;
else
use_diag = (DASD_FEATURE_DEFAULT & DASD_FEATURE_USEDIAG) != 0;
return sprintf(buf, use_diag ? "1\n" : "0\n");
}
static ssize_t
dasd_use_diag_store(struct device *dev, const char *buf, size_t count)
{
struct dasd_devmap *devmap;
int use_diag;
devmap = dasd_devmap_from_cdev(to_ccwdev(dev));
use_diag = buf[0] == '1';
spin_lock(&dasd_devmap_lock);
/* Changing diag discipline flag is only allowed in offline state. */
if (!devmap->device) {
if (use_diag)
devmap->features |= DASD_FEATURE_USEDIAG;
else
devmap->features &= ~DASD_FEATURE_USEDIAG;
} else
count = -EPERM;
spin_unlock(&dasd_devmap_lock);
return count;
}
static
DEVICE_ATTR(use_diag, 0644, dasd_use_diag_show, dasd_use_diag_store);
static ssize_t
dasd_discipline_show(struct device *dev, char *buf)
{
struct dasd_devmap *devmap;
char *dname;
spin_lock(&dasd_devmap_lock);
dname = "none";
devmap = dev->driver_data;
if (devmap && devmap->device && devmap->device->discipline)
dname = devmap->device->discipline->name;
spin_unlock(&dasd_devmap_lock);
return snprintf(buf, PAGE_SIZE, "%s\n", dname);
}
static DEVICE_ATTR(discipline, 0444, dasd_discipline_show, NULL);
static struct attribute * dasd_attrs[] = {
&dev_attr_readonly.attr,
&dev_attr_discipline.attr,
&dev_attr_use_diag.attr,
NULL,
};
static struct attribute_group dasd_attr_group = {
.attrs = dasd_attrs,
};
int
dasd_add_sysfs_files(struct ccw_device *cdev)
{
return sysfs_create_group(&cdev->dev.kobj, &dasd_attr_group);
}
int int
dasd_devmap_init(void) dasd_devmap_init(void)
{ {
......
...@@ -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.32 $ * $Revision: 1.33 $
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -393,7 +393,7 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req) ...@@ -393,7 +393,7 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req)
recid = first_rec; recid = first_rec;
rq_for_each_bio(bio, req) { rq_for_each_bio(bio, req) {
bio_for_each_segment(bv, bio, i) { 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) {
memset(dbio, 0, sizeof (struct dasd_diag_bio)); memset(dbio, 0, sizeof (struct dasd_diag_bio));
dbio->type = rw_cmd; dbio->type = rw_cmd;
......
...@@ -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.47 $ * $Revision: 1.49 $
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -103,6 +103,7 @@ static struct ccw_driver dasd_eckd_driver = { ...@@ -103,6 +103,7 @@ static struct ccw_driver dasd_eckd_driver = {
.remove = dasd_generic_remove, .remove = dasd_generic_remove,
.set_offline = dasd_generic_set_offline, .set_offline = dasd_generic_set_offline,
.set_online = dasd_eckd_set_online, .set_online = dasd_eckd_set_online,
.notify = dasd_generic_notify,
}; };
static const int sizes_trk0[] = { 28, 148, 84 }; static const int sizes_trk0[] = { 28, 148, 84 };
...@@ -460,8 +461,8 @@ dasd_eckd_check_characteristics(struct dasd_device *device) ...@@ -460,8 +461,8 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
/* Invalidate status of initial analysis. */ /* Invalidate status of initial analysis. */
private->init_cqr_status = -1; private->init_cqr_status = -1;
/* Set default cache operations. */ /* Set default cache operations. */
private->attrib.operation = DASD_SEQ_ACCESS; private->attrib.operation = DASD_NORMAL_CACHE;
private->attrib.nr_cyl = 0x02; private->attrib.nr_cyl = 0;
/* Read Device Characteristics */ /* Read Device Characteristics */
rdc_data = (void *) &(private->rdc_data); rdc_data = (void *) &(private->rdc_data);
...@@ -1291,6 +1292,36 @@ dasd_eckd_performance(struct block_device *bdev, int no, long args) ...@@ -1291,6 +1292,36 @@ dasd_eckd_performance(struct block_device *bdev, int no, long args)
return rc; return rc;
} }
/*
* Get attributes (cache operations)
* Returnes the cache attributes used in Define Extend (DE).
*/
static int
dasd_eckd_get_attrib (struct block_device *bdev, int no, long args)
{
struct dasd_device *device;
struct dasd_eckd_private *private;
struct attrib_data_t attrib;
int rc;
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (!args)
return -EINVAL;
device = bdev->bd_disk->private_data;
if (device == NULL)
return -ENODEV;
private = (struct dasd_eckd_private *) device->private;
attrib = private->attrib;
rc = copy_to_user((long *) args, (long *) &attrib,
sizeof (struct attrib_data_t));
return rc;
}
/* /*
* Set attributes (cache operations) * Set attributes (cache operations)
* Stores the attributes for cache operation to be used in Define Extend (DE). * Stores the attributes for cache operation to be used in Define Extend (DE).
...@@ -1433,6 +1464,8 @@ dasd_eckd_init(void) ...@@ -1433,6 +1464,8 @@ dasd_eckd_init(void)
{ {
int ret; int ret;
dasd_ioctl_no_register(THIS_MODULE, BIODASDGATTR,
dasd_eckd_get_attrib);
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,
...@@ -1448,6 +1481,8 @@ dasd_eckd_init(void) ...@@ -1448,6 +1481,8 @@ dasd_eckd_init(void)
ret = ccw_driver_register(&dasd_eckd_driver); ret = ccw_driver_register(&dasd_eckd_driver);
if (ret) { if (ret) {
dasd_ioctl_no_unregister(THIS_MODULE, BIODASDGATTR,
dasd_eckd_get_attrib);
dasd_ioctl_no_unregister(THIS_MODULE, BIODASDSATTR, dasd_ioctl_no_unregister(THIS_MODULE, BIODASDSATTR,
dasd_eckd_set_attrib); dasd_eckd_set_attrib);
dasd_ioctl_no_unregister(THIS_MODULE, BIODASDPSRD, dasd_ioctl_no_unregister(THIS_MODULE, BIODASDPSRD,
...@@ -1470,6 +1505,8 @@ dasd_eckd_cleanup(void) ...@@ -1470,6 +1505,8 @@ dasd_eckd_cleanup(void)
{ {
ccw_driver_unregister(&dasd_eckd_driver); ccw_driver_unregister(&dasd_eckd_driver);
dasd_ioctl_no_unregister(THIS_MODULE, BIODASDGATTR,
dasd_eckd_get_attrib);
dasd_ioctl_no_unregister(THIS_MODULE, BIODASDSATTR, dasd_ioctl_no_unregister(THIS_MODULE, BIODASDSATTR,
dasd_eckd_set_attrib); dasd_eckd_set_attrib);
dasd_ioctl_no_unregister(THIS_MODULE, BIODASDPSRD, dasd_ioctl_no_unregister(THIS_MODULE, BIODASDPSRD,
......
...@@ -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.30 $ * $Revision: 1.32 $
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -80,6 +80,7 @@ static struct ccw_driver dasd_fba_driver = { ...@@ -80,6 +80,7 @@ static struct ccw_driver dasd_fba_driver = {
.remove = dasd_generic_remove, .remove = dasd_generic_remove,
.set_offline = dasd_generic_set_offline, .set_offline = dasd_generic_set_offline,
.set_online = dasd_fba_set_online, .set_online = dasd_fba_set_online,
.notify = dasd_generic_notify,
}; };
static inline void static inline void
...@@ -269,7 +270,7 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req) ...@@ -269,7 +270,7 @@ dasd_fba_build_cp(struct dasd_device * 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
} }
...@@ -309,7 +310,7 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req) ...@@ -309,7 +310,7 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req)
} }
recid = first_rec; recid = first_rec;
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) {
/* Locate record for stupid devices. */ /* Locate record for stupid devices. */
if (private->rdc_data.mode.bits.data_chain == 0) { if (private->rdc_data.mode.bits.data_chain == 0) {
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* gendisk related functions for the dasd driver. * gendisk related functions for the dasd driver.
* *
* $Revision: 1.41 $ * $Revision: 1.42 $
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -31,7 +31,6 @@ int ...@@ -31,7 +31,6 @@ int
dasd_gendisk_alloc(struct dasd_device *device) dasd_gendisk_alloc(struct dasd_device *device)
{ {
struct gendisk *gdp; struct gendisk *gdp;
int len;
/* Make sure the minor for this device exists. */ /* Make sure the minor for this device exists. */
if (device->devindex >= DASD_PER_MAJOR) if (device->devindex >= DASD_PER_MAJOR)
...@@ -47,22 +46,8 @@ dasd_gendisk_alloc(struct dasd_device *device) ...@@ -47,22 +46,8 @@ dasd_gendisk_alloc(struct dasd_device *device)
gdp->fops = &dasd_device_operations; gdp->fops = &dasd_device_operations;
gdp->driverfs_dev = &device->cdev->dev; gdp->driverfs_dev = &device->cdev->dev;
/* /* Set device name */
* Set device name. sprintf(gdp->disk_name, "dasd_%s_", device->cdev->dev.bus_id);
* dasda - dasdz : 26 devices
* dasdaa - dasdzz : 676 devices, added up = 702
* dasdaaa - dasdzzz : 17576 devices, added up = 18278
*/
len = sprintf(gdp->disk_name, "dasd");
if (device->devindex > 25) {
if (device->devindex > 701)
len += sprintf(gdp->disk_name + len, "%c",
'a'+(((device->devindex-702)/676)%26));
len += sprintf(gdp->disk_name + len, "%c",
'a'+(((device->devindex-26)/26)%26));
}
len += sprintf(gdp->disk_name + len, "%c", 'a'+(device->devindex%26));
sprintf(gdp->devfs_name, "dasd/%s", device->cdev->dev.bus_id); sprintf(gdp->devfs_name, "dasd/%s", device->cdev->dev.bus_id);
if (device->ro_flag) if (device->ro_flag)
......
...@@ -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.48 $ * $Revision: 1.52 $
*/ */
#ifndef DASD_INT_H #ifndef DASD_INT_H
...@@ -268,6 +268,7 @@ struct dasd_device { ...@@ -268,6 +268,7 @@ struct dasd_device {
unsigned int s2b_shift; /* log2 (bp_block/512) */ unsigned int s2b_shift; /* log2 (bp_block/512) */
int ro_flag; /* read-only flag */ int ro_flag; /* read-only flag */
int use_diag_flag; /* diag allowed flag */ int use_diag_flag; /* diag allowed flag */
int disconnect_error_flag; /* return -EIO when disconnected */
/* Device discipline stuff. */ /* Device discipline stuff. */
...@@ -308,6 +309,8 @@ struct dasd_device { ...@@ -308,6 +309,8 @@ struct dasd_device {
#define DASD_STOPPED_NOT_ACC 1 /* not accessible */ #define DASD_STOPPED_NOT_ACC 1 /* not accessible */
#define DASD_STOPPED_QUIESCE 2 /* Quiesced */ #define DASD_STOPPED_QUIESCE 2 /* Quiesced */
#define DASD_STOPPED_PENDING 4 /* long busy */ #define DASD_STOPPED_PENDING 4 /* long busy */
#define DASD_STOPPED_DC_WAIT 8 /* disconnected, wait */
#define DASD_STOPPED_DC_EIO 16 /* disconnected, return -EIO */
void dasd_put_device_wake(struct dasd_device *); void dasd_put_device_wake(struct dasd_device *);
...@@ -458,9 +461,10 @@ void dasd_set_timer(struct dasd_device *, int); ...@@ -458,9 +461,10 @@ void dasd_set_timer(struct dasd_device *, int);
void dasd_clear_timer(struct dasd_device *); void dasd_clear_timer(struct dasd_device *);
int dasd_cancel_req(struct dasd_ccw_req *); int dasd_cancel_req(struct dasd_ccw_req *);
int dasd_generic_probe (struct ccw_device *, struct dasd_discipline *); int dasd_generic_probe (struct ccw_device *, struct dasd_discipline *);
int dasd_generic_remove (struct ccw_device *cdev); void dasd_generic_remove (struct ccw_device *cdev);
int dasd_generic_set_online(struct ccw_device *, struct dasd_discipline *); int dasd_generic_set_online(struct ccw_device *, struct dasd_discipline *);
int dasd_generic_set_offline (struct ccw_device *cdev); int dasd_generic_set_offline (struct ccw_device *cdev);
int dasd_generic_notify(struct ccw_device *, int);
void dasd_generic_auto_online (struct ccw_driver *); void dasd_generic_auto_online (struct ccw_driver *);
/* externals in dasd_devmap.c */ /* externals in dasd_devmap.c */
...@@ -474,10 +478,11 @@ void dasd_devmap_exit(void); ...@@ -474,10 +478,11 @@ void dasd_devmap_exit(void);
struct dasd_device *dasd_create_device(struct ccw_device *); struct dasd_device *dasd_create_device(struct ccw_device *);
void dasd_delete_device(struct dasd_device *); void dasd_delete_device(struct dasd_device *);
int dasd_add_sysfs_files(struct ccw_device *);
struct dasd_device *dasd_device_from_cdev(struct ccw_device *);
struct dasd_device *dasd_device_from_devindex(int); struct dasd_device *dasd_device_from_devindex(int);
int dasd_parse(void); int dasd_parse(void);
int dasd_add_busid(char *, int);
int dasd_busid_known(char *); int dasd_busid_known(char *);
/* externals in dasd_gendisk.c */ /* externals in dasd_gendisk.c */
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* /proc interface for the dasd driver. * /proc interface for the dasd driver.
* *
* $Revision: 1.23 $ * $Revision: 1.24 $
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -67,15 +67,10 @@ dasd_devices_show(struct seq_file *m, void *v) ...@@ -67,15 +67,10 @@ dasd_devices_show(struct seq_file *m, void *v)
seq_printf(m, "(none)"); seq_printf(m, "(none)");
/* Print kdev. */ /* Print kdev. */
if (device->gdp) if (device->gdp)
seq_printf(m, " at (%3d:%3d)", seq_printf(m, " at (%3d:%7d)",
device->gdp->major, device->gdp->first_minor); device->gdp->major, device->gdp->first_minor);
else else
seq_printf(m, " at (???:???)"); seq_printf(m, " at (???:???????)");
/* Print device name. */
if (device->gdp)
seq_printf(m, " is %-7s", device->gdp->disk_name);
else
seq_printf(m, " is ???????");
/* Print devices features. */ /* Print devices features. */
substr = device->ro_flag ? "(ro)" : " "; substr = device->ro_flag ? "(ro)" : " ";
seq_printf(m, "%4s: ", substr); seq_printf(m, "%4s: ", substr);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* any future changes wrt the API will result in a change of the APIVERSION reported * any future changes wrt the API will result in a change of the APIVERSION reported
* to userspace by the DASDAPIVER-ioctl * to userspace by the DASDAPIVER-ioctl
* *
* $Revision: 1.4 $ * $Revision: 1.6 $
* *
*/ */
...@@ -69,9 +69,11 @@ typedef struct dasd_information2_t { ...@@ -69,9 +69,11 @@ typedef struct dasd_information2_t {
* values to be used for dasd_information_t.features * values to be used for dasd_information_t.features
* 0x00: default features * 0x00: default features
* 0x01: readonly (ro) * 0x01: readonly (ro)
* 0x02: use diag discipline (diag)
*/ */
#define DASD_FEATURE_DEFAULT 0 #define DASD_FEATURE_DEFAULT 0
#define DASD_FEATURE_READONLY 1 #define DASD_FEATURE_READONLY 1
#define DASD_FEATURE_USEDIAG 2
#define DASD_PARTN_BITS 2 #define DASD_PARTN_BITS 2
...@@ -234,6 +236,8 @@ typedef struct attrib_data_t { ...@@ -234,6 +236,8 @@ typedef struct attrib_data_t {
#define BIODASDINFO2 _IOR(DASD_IOCTL_LETTER,3,dasd_information2_t) #define BIODASDINFO2 _IOR(DASD_IOCTL_LETTER,3,dasd_information2_t)
/* Performance Statistics Read */ /* Performance Statistics Read */
#define BIODASDPSRD _IOR(DASD_IOCTL_LETTER,4,dasd_rssd_perf_stats_t) #define BIODASDPSRD _IOR(DASD_IOCTL_LETTER,4,dasd_rssd_perf_stats_t)
/* Get Attributes (cache operations) */
#define BIODASDGATTR _IOR(DASD_IOCTL_LETTER,5,attrib_data_t)
/* #define BIODASDFORMAT _IOW(IOCTL_LETTER,0,format_data_t) , deprecated */ /* #define BIODASDFORMAT _IOW(IOCTL_LETTER,0,format_data_t) , deprecated */
......
...@@ -82,7 +82,7 @@ struct gendisk { ...@@ -82,7 +82,7 @@ struct gendisk {
int major; /* major number of driver */ int major; /* major number of driver */
int first_minor; int first_minor;
int minors; int minors;
char disk_name[16]; /* name of major driver */ char disk_name[32]; /* name of major driver */
struct hd_struct **part; /* [indexed by minor] */ struct hd_struct **part; /* [indexed by minor] */
struct block_device_operations *fops; struct block_device_operations *fops;
struct request_queue *queue; struct request_queue *queue;
......
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