mirror of
https://github.com/ukui/kernel.git
synced 2026-03-09 10:07:04 -07:00
[S390] dasd: add hyper PAV support to DASD device driver, part 1
Parallel access volumes (PAV) is a storage server feature, that allows to start multiple channel programs on the same DASD in parallel. It defines alias devices which can be used as alternative paths to the same disk. With the old base PAV support we only needed rudimentary functionality in the DASD device driver. As the mapping between base and alias devices was static, we just had to export an identifier (uid) and could leave the combining of devices to external layers like a device mapper multipath. Now hyper PAV removes the requirement to dedicate alias devices to specific base devices. Instead each alias devices can be combined with multiple base device on a per request basis. This requires full support by the DASD device driver as now each channel program itself has to identify the target base device. The changes to the dasd device driver and the ECKD discipline are: - Separate subchannel device representation (dasd_device) from block device representation (dasd_block). Only base devices are block devices. - Gather information about base and alias devices and possible combinations. - For each request decide which dasd_device should be used (base or alias) and build specific channel program. - Support summary unit checks, which allow the storage server to upgrade / downgrade between base and hyper PAV at runtime (support is mandatory). Signed-off-by: Stefan Weinhuber <wein@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
committed by
Martin Schwidefsky
parent
0ac30be461
commit
8e09f21574
@@ -2,8 +2,8 @@
|
||||
# S/390 block devices
|
||||
#
|
||||
|
||||
dasd_eckd_mod-objs := dasd_eckd.o dasd_3990_erp.o dasd_9343_erp.o
|
||||
dasd_fba_mod-objs := dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o
|
||||
dasd_eckd_mod-objs := dasd_eckd.o dasd_3990_erp.o dasd_alias.o
|
||||
dasd_fba_mod-objs := dasd_fba.o
|
||||
dasd_diag_mod-objs := dasd_diag.o
|
||||
dasd_mod-objs := dasd.o dasd_ioctl.o dasd_proc.o dasd_devmap.o \
|
||||
dasd_genhd.o dasd_erp.o
|
||||
|
||||
+961
-753
File diff suppressed because it is too large
Load Diff
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* File...........: linux/drivers/s390/block/dasd_3370_erp.c
|
||||
* Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
|
||||
* Bugreports.to..: <Linux390@de.ibm.com>
|
||||
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
|
||||
*
|
||||
*/
|
||||
|
||||
#define PRINTK_HEADER "dasd_erp(3370)"
|
||||
|
||||
#include "dasd_int.h"
|
||||
|
||||
|
||||
/*
|
||||
* DASD_3370_ERP_EXAMINE
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Checks only for fatal/no/recover error.
|
||||
* A detailed examination of the sense data is done later outside
|
||||
* the interrupt handler.
|
||||
*
|
||||
* The logic is based on the 'IBM 3880 Storage Control Reference' manual
|
||||
* 'Chapter 7. 3370 Sense Data'.
|
||||
*
|
||||
* RETURN VALUES
|
||||
* dasd_era_none no error
|
||||
* dasd_era_fatal for all fatal (unrecoverable errors)
|
||||
* dasd_era_recover for all others.
|
||||
*/
|
||||
dasd_era_t
|
||||
dasd_3370_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
|
||||
{
|
||||
char *sense = irb->ecw;
|
||||
|
||||
/* check for successful execution first */
|
||||
if (irb->scsw.cstat == 0x00 &&
|
||||
irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
|
||||
return dasd_era_none;
|
||||
if (sense[0] & 0x80) { /* CMD reject */
|
||||
return dasd_era_fatal;
|
||||
}
|
||||
if (sense[0] & 0x40) { /* Drive offline */
|
||||
return dasd_era_recover;
|
||||
}
|
||||
if (sense[0] & 0x20) { /* Bus out parity */
|
||||
return dasd_era_recover;
|
||||
}
|
||||
if (sense[0] & 0x10) { /* equipment check */
|
||||
if (sense[1] & 0x80) {
|
||||
return dasd_era_fatal;
|
||||
}
|
||||
return dasd_era_recover;
|
||||
}
|
||||
if (sense[0] & 0x08) { /* data check */
|
||||
if (sense[1] & 0x80) {
|
||||
return dasd_era_fatal;
|
||||
}
|
||||
return dasd_era_recover;
|
||||
}
|
||||
if (sense[0] & 0x04) { /* overrun */
|
||||
if (sense[1] & 0x80) {
|
||||
return dasd_era_fatal;
|
||||
}
|
||||
return dasd_era_recover;
|
||||
}
|
||||
if (sense[1] & 0x40) { /* invalid blocksize */
|
||||
return dasd_era_fatal;
|
||||
}
|
||||
if (sense[1] & 0x04) { /* file protected */
|
||||
return dasd_era_recover;
|
||||
}
|
||||
if (sense[1] & 0x01) { /* operation incomplete */
|
||||
return dasd_era_recover;
|
||||
}
|
||||
if (sense[2] & 0x80) { /* check data erroor */
|
||||
return dasd_era_recover;
|
||||
}
|
||||
if (sense[2] & 0x10) { /* Env. data present */
|
||||
return dasd_era_recover;
|
||||
}
|
||||
/* examine the 24 byte sense data */
|
||||
return dasd_era_recover;
|
||||
|
||||
} /* END dasd_3370_erp_examine */
|
||||
+126
-232
File diff suppressed because it is too large
Load Diff
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* File...........: linux/drivers/s390/block/dasd_9336_erp.c
|
||||
* Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
|
||||
* Bugreports.to..: <Linux390@de.ibm.com>
|
||||
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
|
||||
*
|
||||
*/
|
||||
|
||||
#define PRINTK_HEADER "dasd_erp(9336)"
|
||||
|
||||
#include "dasd_int.h"
|
||||
|
||||
|
||||
/*
|
||||
* DASD_9336_ERP_EXAMINE
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Checks only for fatal/no/recover error.
|
||||
* A detailed examination of the sense data is done later outside
|
||||
* the interrupt handler.
|
||||
*
|
||||
* The logic is based on the 'IBM 3880 Storage Control Reference' manual
|
||||
* 'Chapter 7. 9336 Sense Data'.
|
||||
*
|
||||
* RETURN VALUES
|
||||
* dasd_era_none no error
|
||||
* dasd_era_fatal for all fatal (unrecoverable errors)
|
||||
* dasd_era_recover for all others.
|
||||
*/
|
||||
dasd_era_t
|
||||
dasd_9336_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
|
||||
{
|
||||
/* check for successful execution first */
|
||||
if (irb->scsw.cstat == 0x00 &&
|
||||
irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
|
||||
return dasd_era_none;
|
||||
|
||||
/* examine the 24 byte sense data */
|
||||
return dasd_era_recover;
|
||||
|
||||
} /* END dasd_9336_erp_examine */
|
||||
@@ -1,21 +0,0 @@
|
||||
/*
|
||||
* File...........: linux/drivers/s390/block/dasd_9345_erp.c
|
||||
* Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
|
||||
* Bugreports.to..: <Linux390@de.ibm.com>
|
||||
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
|
||||
*
|
||||
*/
|
||||
|
||||
#define PRINTK_HEADER "dasd_erp(9343)"
|
||||
|
||||
#include "dasd_int.h"
|
||||
|
||||
dasd_era_t
|
||||
dasd_9343_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
|
||||
{
|
||||
if (irb->scsw.cstat == 0x00 &&
|
||||
irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
|
||||
return dasd_era_none;
|
||||
|
||||
return dasd_era_recover;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -48,22 +48,6 @@ struct dasd_devmap {
|
||||
struct dasd_uid uid;
|
||||
};
|
||||
|
||||
/*
|
||||
* dasd_server_ssid_map contains a globally unique storage server subsystem ID.
|
||||
* dasd_server_ssid_list contains the list of all subsystem IDs accessed by
|
||||
* the DASD device driver.
|
||||
*/
|
||||
struct dasd_server_ssid_map {
|
||||
struct list_head list;
|
||||
struct system_id {
|
||||
char vendor[4];
|
||||
char serial[15];
|
||||
__u16 ssid;
|
||||
} sid;
|
||||
};
|
||||
|
||||
static struct list_head dasd_server_ssid_list;
|
||||
|
||||
/*
|
||||
* Parameter parsing functions for dasd= parameter. The syntax is:
|
||||
* <devno> : (0x)?[0-9a-fA-F]+
|
||||
@@ -721,8 +705,9 @@ dasd_ro_store(struct device *dev, struct device_attribute *attr,
|
||||
devmap->features &= ~DASD_FEATURE_READONLY;
|
||||
if (devmap->device)
|
||||
devmap->device->features = devmap->features;
|
||||
if (devmap->device && devmap->device->gdp)
|
||||
set_disk_ro(devmap->device->gdp, val);
|
||||
if (devmap->device && devmap->device->block
|
||||
&& devmap->device->block->gdp)
|
||||
set_disk_ro(devmap->device->block->gdp, val);
|
||||
spin_unlock(&dasd_devmap_lock);
|
||||
return count;
|
||||
}
|
||||
@@ -893,12 +878,16 @@ dasd_alias_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
|
||||
devmap = dasd_find_busid(dev->bus_id);
|
||||
spin_lock(&dasd_devmap_lock);
|
||||
if (!IS_ERR(devmap))
|
||||
alias = devmap->uid.alias;
|
||||
if (IS_ERR(devmap) || strlen(devmap->uid.vendor) == 0) {
|
||||
spin_unlock(&dasd_devmap_lock);
|
||||
return sprintf(buf, "0\n");
|
||||
}
|
||||
if (devmap->uid.type == UA_BASE_PAV_ALIAS ||
|
||||
devmap->uid.type == UA_HYPER_PAV_ALIAS)
|
||||
alias = 1;
|
||||
else
|
||||
alias = 0;
|
||||
spin_unlock(&dasd_devmap_lock);
|
||||
|
||||
return sprintf(buf, alias ? "1\n" : "0\n");
|
||||
}
|
||||
|
||||
@@ -930,19 +919,36 @@ static ssize_t
|
||||
dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct dasd_devmap *devmap;
|
||||
char uid[UID_STRLEN];
|
||||
char uid_string[UID_STRLEN];
|
||||
char ua_string[3];
|
||||
struct dasd_uid *uid;
|
||||
|
||||
devmap = dasd_find_busid(dev->bus_id);
|
||||
spin_lock(&dasd_devmap_lock);
|
||||
if (!IS_ERR(devmap) && strlen(devmap->uid.vendor) > 0)
|
||||
snprintf(uid, sizeof(uid), "%s.%s.%04x.%02x",
|
||||
devmap->uid.vendor, devmap->uid.serial,
|
||||
devmap->uid.ssid, devmap->uid.unit_addr);
|
||||
else
|
||||
uid[0] = 0;
|
||||
if (IS_ERR(devmap) || strlen(devmap->uid.vendor) == 0) {
|
||||
spin_unlock(&dasd_devmap_lock);
|
||||
return sprintf(buf, "\n");
|
||||
}
|
||||
uid = &devmap->uid;
|
||||
switch (uid->type) {
|
||||
case UA_BASE_DEVICE:
|
||||
sprintf(ua_string, "%02x", uid->real_unit_addr);
|
||||
break;
|
||||
case UA_BASE_PAV_ALIAS:
|
||||
sprintf(ua_string, "%02x", uid->base_unit_addr);
|
||||
break;
|
||||
case UA_HYPER_PAV_ALIAS:
|
||||
sprintf(ua_string, "xx");
|
||||
break;
|
||||
default:
|
||||
/* should not happen, treat like base device */
|
||||
sprintf(ua_string, "%02x", uid->real_unit_addr);
|
||||
break;
|
||||
}
|
||||
snprintf(uid_string, sizeof(uid_string), "%s.%s.%04x.%s",
|
||||
uid->vendor, uid->serial, uid->ssid, ua_string);
|
||||
spin_unlock(&dasd_devmap_lock);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", uid);
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", uid_string);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(uid, 0444, dasd_uid_show, NULL);
|
||||
@@ -1040,39 +1046,16 @@ int
|
||||
dasd_set_uid(struct ccw_device *cdev, struct dasd_uid *uid)
|
||||
{
|
||||
struct dasd_devmap *devmap;
|
||||
struct dasd_server_ssid_map *srv, *tmp;
|
||||
|
||||
devmap = dasd_find_busid(cdev->dev.bus_id);
|
||||
if (IS_ERR(devmap))
|
||||
return PTR_ERR(devmap);
|
||||
|
||||
/* generate entry for server_ssid_map */
|
||||
srv = (struct dasd_server_ssid_map *)
|
||||
kzalloc(sizeof(struct dasd_server_ssid_map), GFP_KERNEL);
|
||||
if (!srv)
|
||||
return -ENOMEM;
|
||||
strncpy(srv->sid.vendor, uid->vendor, sizeof(srv->sid.vendor) - 1);
|
||||
strncpy(srv->sid.serial, uid->serial, sizeof(srv->sid.serial) - 1);
|
||||
srv->sid.ssid = uid->ssid;
|
||||
|
||||
/* server is already contained ? */
|
||||
spin_lock(&dasd_devmap_lock);
|
||||
devmap->uid = *uid;
|
||||
list_for_each_entry(tmp, &dasd_server_ssid_list, list) {
|
||||
if (!memcmp(&srv->sid, &tmp->sid,
|
||||
sizeof(struct system_id))) {
|
||||
kfree(srv);
|
||||
srv = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* add servermap to serverlist */
|
||||
if (srv)
|
||||
list_add(&srv->list, &dasd_server_ssid_list);
|
||||
spin_unlock(&dasd_devmap_lock);
|
||||
|
||||
return (srv ? 1 : 0);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dasd_set_uid);
|
||||
|
||||
@@ -1138,9 +1121,6 @@ dasd_devmap_init(void)
|
||||
dasd_max_devindex = 0;
|
||||
for (i = 0; i < 256; i++)
|
||||
INIT_LIST_HEAD(&dasd_hashlists[i]);
|
||||
|
||||
/* Initialize servermap structure. */
|
||||
INIT_LIST_HEAD(&dasd_server_ssid_list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -142,7 +142,7 @@ dasd_diag_erp(struct dasd_device *device)
|
||||
int rc;
|
||||
|
||||
mdsk_term_io(device);
|
||||
rc = mdsk_init_io(device, device->bp_block, 0, NULL);
|
||||
rc = mdsk_init_io(device, device->block->bp_block, 0, NULL);
|
||||
if (rc)
|
||||
DEV_MESSAGE(KERN_WARNING, device, "DIAG ERP unsuccessful, "
|
||||
"rc=%d", rc);
|
||||
@@ -158,11 +158,11 @@ dasd_start_diag(struct dasd_ccw_req * cqr)
|
||||
struct dasd_diag_req *dreq;
|
||||
int rc;
|
||||
|
||||
device = cqr->device;
|
||||
device = cqr->startdev;
|
||||
if (cqr->retries < 0) {
|
||||
DEV_MESSAGE(KERN_WARNING, device, "DIAG start_IO: request %p "
|
||||
"- no retry left)", cqr);
|
||||
cqr->status = DASD_CQR_FAILED;
|
||||
cqr->status = DASD_CQR_ERROR;
|
||||
return -EIO;
|
||||
}
|
||||
private = (struct dasd_diag_private *) device->private;
|
||||
@@ -184,7 +184,7 @@ dasd_start_diag(struct dasd_ccw_req * cqr)
|
||||
switch (rc) {
|
||||
case 0: /* Synchronous I/O finished successfully */
|
||||
cqr->stopclk = get_clock();
|
||||
cqr->status = DASD_CQR_DONE;
|
||||
cqr->status = DASD_CQR_SUCCESS;
|
||||
/* Indicate to calling function that only a dasd_schedule_bh()
|
||||
and no timer is needed */
|
||||
rc = -EACCES;
|
||||
@@ -209,12 +209,12 @@ dasd_diag_term_IO(struct dasd_ccw_req * cqr)
|
||||
{
|
||||
struct dasd_device *device;
|
||||
|
||||
device = cqr->device;
|
||||
device = cqr->startdev;
|
||||
mdsk_term_io(device);
|
||||
mdsk_init_io(device, device->bp_block, 0, NULL);
|
||||
cqr->status = DASD_CQR_CLEAR;
|
||||
mdsk_init_io(device, device->block->bp_block, 0, NULL);
|
||||
cqr->status = DASD_CQR_CLEAR_PENDING;
|
||||
cqr->stopclk = get_clock();
|
||||
dasd_schedule_bh(device);
|
||||
dasd_schedule_device_bh(device);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -247,7 +247,7 @@ dasd_ext_handler(__u16 code)
|
||||
return;
|
||||
}
|
||||
cqr = (struct dasd_ccw_req *) ip;
|
||||
device = (struct dasd_device *) cqr->device;
|
||||
device = (struct dasd_device *) cqr->startdev;
|
||||
if (strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
|
||||
DEV_MESSAGE(KERN_WARNING, device,
|
||||
" magic number of dasd_ccw_req 0x%08X doesn't"
|
||||
@@ -260,10 +260,10 @@ dasd_ext_handler(__u16 code)
|
||||
spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
|
||||
|
||||
/* Check for a pending clear operation */
|
||||
if (cqr->status == DASD_CQR_CLEAR) {
|
||||
cqr->status = DASD_CQR_QUEUED;
|
||||
dasd_clear_timer(device);
|
||||
dasd_schedule_bh(device);
|
||||
if (cqr->status == DASD_CQR_CLEAR_PENDING) {
|
||||
cqr->status = DASD_CQR_CLEARED;
|
||||
dasd_device_clear_timer(device);
|
||||
dasd_schedule_device_bh(device);
|
||||
spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
|
||||
return;
|
||||
}
|
||||
@@ -272,11 +272,11 @@ dasd_ext_handler(__u16 code)
|
||||
|
||||
expires = 0;
|
||||
if (status == 0) {
|
||||
cqr->status = DASD_CQR_DONE;
|
||||
cqr->status = DASD_CQR_SUCCESS;
|
||||
/* Start first request on queue if possible -> fast_io. */
|
||||
if (!list_empty(&device->ccw_queue)) {
|
||||
next = list_entry(device->ccw_queue.next,
|
||||
struct dasd_ccw_req, list);
|
||||
struct dasd_ccw_req, devlist);
|
||||
if (next->status == DASD_CQR_QUEUED) {
|
||||
rc = dasd_start_diag(next);
|
||||
if (rc == 0)
|
||||
@@ -296,10 +296,10 @@ dasd_ext_handler(__u16 code)
|
||||
}
|
||||
|
||||
if (expires != 0)
|
||||
dasd_set_timer(device, expires);
|
||||
dasd_device_set_timer(device, expires);
|
||||
else
|
||||
dasd_clear_timer(device);
|
||||
dasd_schedule_bh(device);
|
||||
dasd_device_clear_timer(device);
|
||||
dasd_schedule_device_bh(device);
|
||||
|
||||
spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
|
||||
}
|
||||
@@ -309,6 +309,7 @@ dasd_ext_handler(__u16 code)
|
||||
static int
|
||||
dasd_diag_check_device(struct dasd_device *device)
|
||||
{
|
||||
struct dasd_block *block;
|
||||
struct dasd_diag_private *private;
|
||||
struct dasd_diag_characteristics *rdc_data;
|
||||
struct dasd_diag_bio bio;
|
||||
@@ -328,6 +329,16 @@ dasd_diag_check_device(struct dasd_device *device)
|
||||
ccw_device_get_id(device->cdev, &private->dev_id);
|
||||
device->private = (void *) private;
|
||||
}
|
||||
block = dasd_alloc_block();
|
||||
if (IS_ERR(block)) {
|
||||
DEV_MESSAGE(KERN_WARNING, device, "%s",
|
||||
"could not allocate dasd block structure");
|
||||
kfree(device->private);
|
||||
return PTR_ERR(block);
|
||||
}
|
||||
device->block = block;
|
||||
block->base = device;
|
||||
|
||||
/* Read Device Characteristics */
|
||||
rdc_data = (void *) &(private->rdc_data);
|
||||
rdc_data->dev_nr = private->dev_id.devno;
|
||||
@@ -409,14 +420,14 @@ dasd_diag_check_device(struct dasd_device *device)
|
||||
sizeof(DASD_DIAG_CMS1)) == 0) {
|
||||
/* get formatted blocksize from label block */
|
||||
bsize = (unsigned int) label->block_size;
|
||||
device->blocks = (unsigned long) label->block_count;
|
||||
block->blocks = (unsigned long) label->block_count;
|
||||
} else
|
||||
device->blocks = end_block;
|
||||
device->bp_block = bsize;
|
||||
device->s2b_shift = 0; /* bits to shift 512 to get a block */
|
||||
block->blocks = end_block;
|
||||
block->bp_block = bsize;
|
||||
block->s2b_shift = 0; /* bits to shift 512 to get a block */
|
||||
for (sb = 512; sb < bsize; sb = sb << 1)
|
||||
device->s2b_shift++;
|
||||
rc = mdsk_init_io(device, device->bp_block, 0, NULL);
|
||||
block->s2b_shift++;
|
||||
rc = mdsk_init_io(device, block->bp_block, 0, NULL);
|
||||
if (rc) {
|
||||
DEV_MESSAGE(KERN_WARNING, device, "DIAG initialization "
|
||||
"failed (rc=%d)", rc);
|
||||
@@ -424,9 +435,9 @@ dasd_diag_check_device(struct dasd_device *device)
|
||||
} else {
|
||||
DEV_MESSAGE(KERN_INFO, device,
|
||||
"(%ld B/blk): %ldkB",
|
||||
(unsigned long) device->bp_block,
|
||||
(unsigned long) (device->blocks <<
|
||||
device->s2b_shift) >> 1);
|
||||
(unsigned long) block->bp_block,
|
||||
(unsigned long) (block->blocks <<
|
||||
block->s2b_shift) >> 1);
|
||||
}
|
||||
out:
|
||||
free_page((long) label);
|
||||
@@ -436,22 +447,16 @@ out:
|
||||
/* Fill in virtual disk geometry for device. Return zero on success, non-zero
|
||||
* otherwise. */
|
||||
static int
|
||||
dasd_diag_fill_geometry(struct dasd_device *device, struct hd_geometry *geo)
|
||||
dasd_diag_fill_geometry(struct dasd_block *block, struct hd_geometry *geo)
|
||||
{
|
||||
if (dasd_check_blocksize(device->bp_block) != 0)
|
||||
if (dasd_check_blocksize(block->bp_block) != 0)
|
||||
return -EINVAL;
|
||||
geo->cylinders = (device->blocks << device->s2b_shift) >> 10;
|
||||
geo->cylinders = (block->blocks << block->s2b_shift) >> 10;
|
||||
geo->heads = 16;
|
||||
geo->sectors = 128 >> device->s2b_shift;
|
||||
geo->sectors = 128 >> block->s2b_shift;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static dasd_era_t
|
||||
dasd_diag_examine_error(struct dasd_ccw_req * cqr, struct irb * stat)
|
||||
{
|
||||
return dasd_era_fatal;
|
||||
}
|
||||
|
||||
static dasd_erp_fn_t
|
||||
dasd_diag_erp_action(struct dasd_ccw_req * cqr)
|
||||
{
|
||||
@@ -466,8 +471,9 @@ dasd_diag_erp_postaction(struct dasd_ccw_req * cqr)
|
||||
|
||||
/* Create DASD request from block device request. Return pointer to new
|
||||
* request on success, ERR_PTR otherwise. */
|
||||
static struct dasd_ccw_req *
|
||||
dasd_diag_build_cp(struct dasd_device * device, struct request *req)
|
||||
static struct dasd_ccw_req *dasd_diag_build_cp(struct dasd_device *memdev,
|
||||
struct dasd_block *block,
|
||||
struct request *req)
|
||||
{
|
||||
struct dasd_ccw_req *cqr;
|
||||
struct dasd_diag_req *dreq;
|
||||
@@ -486,17 +492,17 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req)
|
||||
rw_cmd = MDSK_WRITE_REQ;
|
||||
else
|
||||
return ERR_PTR(-EINVAL);
|
||||
blksize = device->bp_block;
|
||||
blksize = block->bp_block;
|
||||
/* Calculate record id of first and last block. */
|
||||
first_rec = req->sector >> device->s2b_shift;
|
||||
last_rec = (req->sector + req->nr_sectors - 1) >> device->s2b_shift;
|
||||
first_rec = req->sector >> block->s2b_shift;
|
||||
last_rec = (req->sector + req->nr_sectors - 1) >> block->s2b_shift;
|
||||
/* Check struct bio and count the number of blocks for the request. */
|
||||
count = 0;
|
||||
rq_for_each_segment(bv, req, iter) {
|
||||
if (bv->bv_len & (blksize - 1))
|
||||
/* Fba can only do full blocks. */
|
||||
return ERR_PTR(-EINVAL);
|
||||
count += bv->bv_len >> (device->s2b_shift + 9);
|
||||
count += bv->bv_len >> (block->s2b_shift + 9);
|
||||
}
|
||||
/* Paranoia. */
|
||||
if (count != last_rec - first_rec + 1)
|
||||
@@ -505,7 +511,7 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req)
|
||||
datasize = sizeof(struct dasd_diag_req) +
|
||||
count*sizeof(struct dasd_diag_bio);
|
||||
cqr = dasd_smalloc_request(dasd_diag_discipline.name, 0,
|
||||
datasize, device);
|
||||
datasize, memdev);
|
||||
if (IS_ERR(cqr))
|
||||
return cqr;
|
||||
|
||||
@@ -529,7 +535,9 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req)
|
||||
cqr->buildclk = get_clock();
|
||||
if (req->cmd_flags & REQ_FAILFAST)
|
||||
set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
|
||||
cqr->device = device;
|
||||
cqr->startdev = memdev;
|
||||
cqr->memdev = memdev;
|
||||
cqr->block = block;
|
||||
cqr->expires = DIAG_TIMEOUT;
|
||||
cqr->status = DASD_CQR_FILLED;
|
||||
return cqr;
|
||||
@@ -543,10 +551,15 @@ dasd_diag_free_cp(struct dasd_ccw_req *cqr, struct request *req)
|
||||
int status;
|
||||
|
||||
status = cqr->status == DASD_CQR_DONE;
|
||||
dasd_sfree_request(cqr, cqr->device);
|
||||
dasd_sfree_request(cqr, cqr->memdev);
|
||||
return status;
|
||||
}
|
||||
|
||||
static void dasd_diag_handle_terminated_request(struct dasd_ccw_req *cqr)
|
||||
{
|
||||
cqr->status = DASD_CQR_FILLED;
|
||||
};
|
||||
|
||||
/* Fill in IOCTL data for device. */
|
||||
static int
|
||||
dasd_diag_fill_info(struct dasd_device * device,
|
||||
@@ -583,7 +596,7 @@ static struct dasd_discipline dasd_diag_discipline = {
|
||||
.fill_geometry = dasd_diag_fill_geometry,
|
||||
.start_IO = dasd_start_diag,
|
||||
.term_IO = dasd_diag_term_IO,
|
||||
.examine_error = dasd_diag_examine_error,
|
||||
.handle_terminated_request = dasd_diag_handle_terminated_request,
|
||||
.erp_action = dasd_diag_erp_action,
|
||||
.erp_postaction = dasd_diag_erp_postaction,
|
||||
.build_cp = dasd_diag_build_cp,
|
||||
|
||||
+572
-209
File diff suppressed because it is too large
Load Diff
@@ -39,6 +39,8 @@
|
||||
#define DASD_ECKD_CCW_READ_CKD_MT 0x9e
|
||||
#define DASD_ECKD_CCW_WRITE_CKD_MT 0x9d
|
||||
#define DASD_ECKD_CCW_RESERVE 0xB4
|
||||
#define DASD_ECKD_CCW_PFX 0xE7
|
||||
#define DASD_ECKD_CCW_RSCK 0xF9
|
||||
|
||||
/*
|
||||
* Perform Subsystem Function / Sub-Orders
|
||||
@@ -137,6 +139,25 @@ struct LO_eckd_data {
|
||||
__u16 length;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Prefix data for format 0x00 and 0x01 */
|
||||
struct PFX_eckd_data {
|
||||
unsigned char format;
|
||||
struct {
|
||||
unsigned char define_extend:1;
|
||||
unsigned char time_stamp:1;
|
||||
unsigned char verify_base:1;
|
||||
unsigned char hyper_pav:1;
|
||||
unsigned char reserved:4;
|
||||
} __attribute__ ((packed)) validity;
|
||||
__u8 base_address;
|
||||
__u8 aux;
|
||||
__u8 base_lss;
|
||||
__u8 reserved[7];
|
||||
struct DE_eckd_data define_extend;
|
||||
struct LO_eckd_data locate_record;
|
||||
__u8 LO_extended_data[4];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct dasd_eckd_characteristics {
|
||||
__u16 cu_type;
|
||||
struct {
|
||||
@@ -254,7 +275,9 @@ struct dasd_eckd_confdata {
|
||||
} __attribute__ ((packed)) ned;
|
||||
struct {
|
||||
unsigned char flags; /* byte 0 */
|
||||
unsigned char res2[7]; /* byte 1- 7 */
|
||||
unsigned char res1; /* byte 1 */
|
||||
__u16 format; /* byte 2-3 */
|
||||
unsigned char res2[4]; /* byte 4-7 */
|
||||
unsigned char sua_flags; /* byte 8 */
|
||||
__u8 base_unit_addr; /* byte 9 */
|
||||
unsigned char res3[22]; /* byte 10-31 */
|
||||
@@ -343,6 +366,11 @@ struct dasd_eckd_path {
|
||||
__u8 npm;
|
||||
};
|
||||
|
||||
struct dasd_rssd_features {
|
||||
char feature[256];
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
/*
|
||||
* Perform Subsystem Function - Prepare for Read Subsystem Data
|
||||
*/
|
||||
@@ -365,4 +393,99 @@ struct dasd_psf_ssc_data {
|
||||
unsigned char reserved[59];
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
/*
|
||||
* some structures and definitions for alias handling
|
||||
*/
|
||||
struct dasd_unit_address_configuration {
|
||||
struct {
|
||||
char ua_type;
|
||||
char base_ua;
|
||||
} unit[256];
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
#define MAX_DEVICES_PER_LCU 256
|
||||
|
||||
/* flags on the LCU */
|
||||
#define NEED_UAC_UPDATE 0x01
|
||||
#define UPDATE_PENDING 0x02
|
||||
|
||||
enum pavtype {NO_PAV, BASE_PAV, HYPER_PAV};
|
||||
|
||||
|
||||
struct alias_root {
|
||||
struct list_head serverlist;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
struct alias_server {
|
||||
struct list_head server;
|
||||
struct dasd_uid uid;
|
||||
struct list_head lculist;
|
||||
};
|
||||
|
||||
struct summary_unit_check_work_data {
|
||||
char reason;
|
||||
struct dasd_device *device;
|
||||
struct work_struct worker;
|
||||
};
|
||||
|
||||
struct read_uac_work_data {
|
||||
struct dasd_device *device;
|
||||
struct delayed_work dwork;
|
||||
};
|
||||
|
||||
struct alias_lcu {
|
||||
struct list_head lcu;
|
||||
struct dasd_uid uid;
|
||||
enum pavtype pav;
|
||||
char flags;
|
||||
spinlock_t lock;
|
||||
struct list_head grouplist;
|
||||
struct list_head active_devices;
|
||||
struct list_head inactive_devices;
|
||||
struct dasd_unit_address_configuration *uac;
|
||||
struct summary_unit_check_work_data suc_data;
|
||||
struct read_uac_work_data ruac_data;
|
||||
struct dasd_ccw_req *rsu_cqr;
|
||||
};
|
||||
|
||||
struct alias_pav_group {
|
||||
struct list_head group;
|
||||
struct dasd_uid uid;
|
||||
struct alias_lcu *lcu;
|
||||
struct list_head baselist;
|
||||
struct list_head aliaslist;
|
||||
struct dasd_device *next;
|
||||
};
|
||||
|
||||
|
||||
struct dasd_eckd_private {
|
||||
struct dasd_eckd_characteristics rdc_data;
|
||||
struct dasd_eckd_confdata conf_data;
|
||||
struct dasd_eckd_path path_data;
|
||||
struct eckd_count count_area[5];
|
||||
int init_cqr_status;
|
||||
int uses_cdl;
|
||||
struct attrib_data_t attrib; /* e.g. cache operations */
|
||||
struct dasd_rssd_features features;
|
||||
|
||||
/* alias managemnet */
|
||||
struct dasd_uid uid;
|
||||
struct alias_pav_group *pavgroup;
|
||||
struct alias_lcu *lcu;
|
||||
int count;
|
||||
};
|
||||
|
||||
|
||||
|
||||
int dasd_alias_make_device_known_to_lcu(struct dasd_device *);
|
||||
void dasd_alias_disconnect_device_from_lcu(struct dasd_device *);
|
||||
int dasd_alias_add_device(struct dasd_device *);
|
||||
int dasd_alias_remove_device(struct dasd_device *);
|
||||
struct dasd_device *dasd_alias_get_start_dev(struct dasd_device *);
|
||||
void dasd_alias_handle_summary_unit_check(struct dasd_device *, struct irb *);
|
||||
void dasd_eckd_reset_ccw_to_base_io(struct dasd_ccw_req *);
|
||||
|
||||
#endif /* DASD_ECKD_H */
|
||||
|
||||
@@ -336,7 +336,7 @@ static void dasd_eer_write_snss_trigger(struct dasd_device *device,
|
||||
unsigned long flags;
|
||||
struct eerbuffer *eerb;
|
||||
|
||||
snss_rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0;
|
||||
snss_rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
|
||||
if (snss_rc)
|
||||
data_size = 0;
|
||||
else
|
||||
@@ -404,10 +404,11 @@ void dasd_eer_snss(struct dasd_device *device)
|
||||
set_bit(DASD_FLAG_EER_SNSS, &device->flags);
|
||||
return;
|
||||
}
|
||||
/* cdev is already locked, can't use dasd_add_request_head */
|
||||
clear_bit(DASD_FLAG_EER_SNSS, &device->flags);
|
||||
cqr->status = DASD_CQR_QUEUED;
|
||||
list_add(&cqr->list, &device->ccw_queue);
|
||||
dasd_schedule_bh(device);
|
||||
list_add(&cqr->devlist, &device->ccw_queue);
|
||||
dasd_schedule_device_bh(device);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -415,7 +416,7 @@ void dasd_eer_snss(struct dasd_device *device)
|
||||
*/
|
||||
static void dasd_eer_snss_cb(struct dasd_ccw_req *cqr, void *data)
|
||||
{
|
||||
struct dasd_device *device = cqr->device;
|
||||
struct dasd_device *device = cqr->startdev;
|
||||
unsigned long flags;
|
||||
|
||||
dasd_eer_write(device, cqr, DASD_EER_STATECHANGE);
|
||||
@@ -458,7 +459,7 @@ int dasd_eer_enable(struct dasd_device *device)
|
||||
if (!cqr)
|
||||
return -ENOMEM;
|
||||
|
||||
cqr->device = device;
|
||||
cqr->startdev = device;
|
||||
cqr->retries = 255;
|
||||
cqr->expires = 10 * HZ;
|
||||
clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
|
||||
|
||||
@@ -46,6 +46,8 @@ dasd_alloc_erp_request(char *magic, int cplength, int datasize,
|
||||
if (cqr == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
memset(cqr, 0, sizeof(struct dasd_ccw_req));
|
||||
INIT_LIST_HEAD(&cqr->devlist);
|
||||
INIT_LIST_HEAD(&cqr->blocklist);
|
||||
data = (char *) cqr + ((sizeof(struct dasd_ccw_req) + 7L) & -8L);
|
||||
cqr->cpaddr = NULL;
|
||||
if (cplength > 0) {
|
||||
@@ -66,7 +68,7 @@ dasd_alloc_erp_request(char *magic, int cplength, int datasize,
|
||||
}
|
||||
|
||||
void
|
||||
dasd_free_erp_request(struct dasd_ccw_req * cqr, struct dasd_device * device)
|
||||
dasd_free_erp_request(struct dasd_ccw_req *cqr, struct dasd_device * device)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
@@ -81,11 +83,11 @@ dasd_free_erp_request(struct dasd_ccw_req * cqr, struct dasd_device * device)
|
||||
* dasd_default_erp_action just retries the current cqr
|
||||
*/
|
||||
struct dasd_ccw_req *
|
||||
dasd_default_erp_action(struct dasd_ccw_req * cqr)
|
||||
dasd_default_erp_action(struct dasd_ccw_req *cqr)
|
||||
{
|
||||
struct dasd_device *device;
|
||||
|
||||
device = cqr->device;
|
||||
device = cqr->startdev;
|
||||
|
||||
/* just retry - there is nothing to save ... I got no sense data.... */
|
||||
if (cqr->retries > 0) {
|
||||
@@ -93,12 +95,12 @@ dasd_default_erp_action(struct dasd_ccw_req * cqr)
|
||||
"default ERP called (%i retries left)",
|
||||
cqr->retries);
|
||||
cqr->lpm = LPM_ANYPATH;
|
||||
cqr->status = DASD_CQR_QUEUED;
|
||||
cqr->status = DASD_CQR_FILLED;
|
||||
} else {
|
||||
DEV_MESSAGE (KERN_WARNING, device, "%s",
|
||||
"default ERP called (NO retry left)");
|
||||
cqr->status = DASD_CQR_FAILED;
|
||||
cqr->stopclk = get_clock ();
|
||||
cqr->stopclk = get_clock();
|
||||
}
|
||||
return cqr;
|
||||
} /* end dasd_default_erp_action */
|
||||
@@ -117,15 +119,12 @@ dasd_default_erp_action(struct dasd_ccw_req * cqr)
|
||||
* RETURN VALUES
|
||||
* cqr pointer to the original CQR
|
||||
*/
|
||||
struct dasd_ccw_req *
|
||||
dasd_default_erp_postaction(struct dasd_ccw_req * cqr)
|
||||
struct dasd_ccw_req *dasd_default_erp_postaction(struct dasd_ccw_req *cqr)
|
||||
{
|
||||
struct dasd_device *device;
|
||||
int success;
|
||||
|
||||
BUG_ON(cqr->refers == NULL || cqr->function == NULL);
|
||||
|
||||
device = cqr->device;
|
||||
success = cqr->status == DASD_CQR_DONE;
|
||||
|
||||
/* free all ERPs - but NOT the original cqr */
|
||||
@@ -133,10 +132,10 @@ dasd_default_erp_postaction(struct dasd_ccw_req * cqr)
|
||||
struct dasd_ccw_req *refers;
|
||||
|
||||
refers = cqr->refers;
|
||||
/* remove the request from the device queue */
|
||||
list_del(&cqr->list);
|
||||
/* remove the request from the block queue */
|
||||
list_del(&cqr->blocklist);
|
||||
/* free the finished erp request */
|
||||
dasd_free_erp_request(cqr, device);
|
||||
dasd_free_erp_request(cqr, cqr->memdev);
|
||||
cqr = refers;
|
||||
}
|
||||
|
||||
@@ -157,7 +156,7 @@ dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb)
|
||||
{
|
||||
struct dasd_device *device;
|
||||
|
||||
device = cqr->device;
|
||||
device = cqr->startdev;
|
||||
/* dump sense data */
|
||||
if (device->discipline && device->discipline->dump_sense)
|
||||
device->discipline->dump_sense(device, cqr, irb);
|
||||
|
||||
@@ -117,6 +117,7 @@ locate_record(struct ccw1 * ccw, struct LO_fba_data *data, int rw,
|
||||
static int
|
||||
dasd_fba_check_characteristics(struct dasd_device *device)
|
||||
{
|
||||
struct dasd_block *block;
|
||||
struct dasd_fba_private *private;
|
||||
struct ccw_device *cdev = device->cdev;
|
||||
void *rdc_data;
|
||||
@@ -133,6 +134,16 @@ dasd_fba_check_characteristics(struct dasd_device *device)
|
||||
}
|
||||
device->private = (void *) private;
|
||||
}
|
||||
block = dasd_alloc_block();
|
||||
if (IS_ERR(block)) {
|
||||
DEV_MESSAGE(KERN_WARNING, device, "%s",
|
||||
"could not allocate dasd block structure");
|
||||
kfree(device->private);
|
||||
return PTR_ERR(block);
|
||||
}
|
||||
device->block = block;
|
||||
block->base = device;
|
||||
|
||||
/* Read Device Characteristics */
|
||||
rdc_data = (void *) &(private->rdc_data);
|
||||
rc = dasd_generic_read_dev_chars(device, "FBA ", &rdc_data, 32);
|
||||
@@ -155,60 +166,37 @@ dasd_fba_check_characteristics(struct dasd_device *device)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
dasd_fba_do_analysis(struct dasd_device *device)
|
||||
static int dasd_fba_do_analysis(struct dasd_block *block)
|
||||
{
|
||||
struct dasd_fba_private *private;
|
||||
int sb, rc;
|
||||
|
||||
private = (struct dasd_fba_private *) device->private;
|
||||
private = (struct dasd_fba_private *) block->base->private;
|
||||
rc = dasd_check_blocksize(private->rdc_data.blk_size);
|
||||
if (rc) {
|
||||
DEV_MESSAGE(KERN_INFO, device, "unknown blocksize %d",
|
||||
DEV_MESSAGE(KERN_INFO, block->base, "unknown blocksize %d",
|
||||
private->rdc_data.blk_size);
|
||||
return rc;
|
||||
}
|
||||
device->blocks = private->rdc_data.blk_bdsa;
|
||||
device->bp_block = private->rdc_data.blk_size;
|
||||
device->s2b_shift = 0; /* bits to shift 512 to get a block */
|
||||
block->blocks = private->rdc_data.blk_bdsa;
|
||||
block->bp_block = private->rdc_data.blk_size;
|
||||
block->s2b_shift = 0; /* bits to shift 512 to get a block */
|
||||
for (sb = 512; sb < private->rdc_data.blk_size; sb = sb << 1)
|
||||
device->s2b_shift++;
|
||||
block->s2b_shift++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
dasd_fba_fill_geometry(struct dasd_device *device, struct hd_geometry *geo)
|
||||
static int dasd_fba_fill_geometry(struct dasd_block *block,
|
||||
struct hd_geometry *geo)
|
||||
{
|
||||
if (dasd_check_blocksize(device->bp_block) != 0)
|
||||
if (dasd_check_blocksize(block->bp_block) != 0)
|
||||
return -EINVAL;
|
||||
geo->cylinders = (device->blocks << device->s2b_shift) >> 10;
|
||||
geo->cylinders = (block->blocks << block->s2b_shift) >> 10;
|
||||
geo->heads = 16;
|
||||
geo->sectors = 128 >> device->s2b_shift;
|
||||
geo->sectors = 128 >> block->s2b_shift;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static dasd_era_t
|
||||
dasd_fba_examine_error(struct dasd_ccw_req * cqr, struct irb * irb)
|
||||
{
|
||||
struct dasd_device *device;
|
||||
struct ccw_device *cdev;
|
||||
|
||||
device = (struct dasd_device *) cqr->device;
|
||||
if (irb->scsw.cstat == 0x00 &&
|
||||
irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
|
||||
return dasd_era_none;
|
||||
|
||||
cdev = device->cdev;
|
||||
switch (cdev->id.dev_type) {
|
||||
case 0x3370:
|
||||
return dasd_3370_erp_examine(cqr, irb);
|
||||
case 0x9336:
|
||||
return dasd_9336_erp_examine(cqr, irb);
|
||||
default:
|
||||
return dasd_era_recover;
|
||||
}
|
||||
}
|
||||
|
||||
static dasd_erp_fn_t
|
||||
dasd_fba_erp_action(struct dasd_ccw_req * cqr)
|
||||
{
|
||||
@@ -221,13 +209,34 @@ dasd_fba_erp_postaction(struct dasd_ccw_req * cqr)
|
||||
if (cqr->function == dasd_default_erp_action)
|
||||
return dasd_default_erp_postaction;
|
||||
|
||||
DEV_MESSAGE(KERN_WARNING, cqr->device, "unknown ERP action %p",
|
||||
DEV_MESSAGE(KERN_WARNING, cqr->startdev, "unknown ERP action %p",
|
||||
cqr->function);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct dasd_ccw_req *
|
||||
dasd_fba_build_cp(struct dasd_device * device, struct request *req)
|
||||
static void dasd_fba_handle_unsolicited_interrupt(struct dasd_device *device,
|
||||
struct irb *irb)
|
||||
{
|
||||
char mask;
|
||||
|
||||
/* first of all check for state change pending interrupt */
|
||||
mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP;
|
||||
if ((irb->scsw.dstat & mask) == mask) {
|
||||
dasd_generic_handle_state_change(device);
|
||||
return;
|
||||
}
|
||||
|
||||
/* check for unsolicited interrupts */
|
||||
DEV_MESSAGE(KERN_DEBUG, device, "%s",
|
||||
"unsolicited interrupt received");
|
||||
device->discipline->dump_sense(device, NULL, irb);
|
||||
dasd_schedule_device_bh(device);
|
||||
return;
|
||||
};
|
||||
|
||||
static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev,
|
||||
struct dasd_block *block,
|
||||
struct request *req)
|
||||
{
|
||||
struct dasd_fba_private *private;
|
||||
unsigned long *idaws;
|
||||
@@ -242,17 +251,17 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req)
|
||||
unsigned int blksize, off;
|
||||
unsigned char cmd;
|
||||
|
||||
private = (struct dasd_fba_private *) device->private;
|
||||
private = (struct dasd_fba_private *) block->base->private;
|
||||
if (rq_data_dir(req) == READ) {
|
||||
cmd = DASD_FBA_CCW_READ;
|
||||
} else if (rq_data_dir(req) == WRITE) {
|
||||
cmd = DASD_FBA_CCW_WRITE;
|
||||
} else
|
||||
return ERR_PTR(-EINVAL);
|
||||
blksize = device->bp_block;
|
||||
blksize = block->bp_block;
|
||||
/* Calculate record id of first and last block. */
|
||||
first_rec = req->sector >> device->s2b_shift;
|
||||
last_rec = (req->sector + req->nr_sectors - 1) >> device->s2b_shift;
|
||||
first_rec = req->sector >> block->s2b_shift;
|
||||
last_rec = (req->sector + req->nr_sectors - 1) >> block->s2b_shift;
|
||||
/* Check struct bio and count the number of blocks for the request. */
|
||||
count = 0;
|
||||
cidaw = 0;
|
||||
@@ -260,7 +269,7 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req)
|
||||
if (bv->bv_len & (blksize - 1))
|
||||
/* Fba can only do full blocks. */
|
||||
return ERR_PTR(-EINVAL);
|
||||
count += bv->bv_len >> (device->s2b_shift + 9);
|
||||
count += bv->bv_len >> (block->s2b_shift + 9);
|
||||
#if defined(CONFIG_64BIT)
|
||||
if (idal_is_needed (page_address(bv->bv_page), bv->bv_len))
|
||||
cidaw += bv->bv_len / blksize;
|
||||
@@ -284,13 +293,13 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req)
|
||||
}
|
||||
/* Allocate the ccw request. */
|
||||
cqr = dasd_smalloc_request(dasd_fba_discipline.name,
|
||||
cplength, datasize, device);
|
||||
cplength, datasize, memdev);
|
||||
if (IS_ERR(cqr))
|
||||
return cqr;
|
||||
ccw = cqr->cpaddr;
|
||||
/* First ccw is define extent. */
|
||||
define_extent(ccw++, cqr->data, rq_data_dir(req),
|
||||
device->bp_block, req->sector, req->nr_sectors);
|
||||
block->bp_block, req->sector, req->nr_sectors);
|
||||
/* Build locate_record + read/write ccws. */
|
||||
idaws = (unsigned long *) (cqr->data + sizeof(struct DE_fba_data));
|
||||
LO_data = (struct LO_fba_data *) (idaws + cidaw);
|
||||
@@ -326,7 +335,7 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req)
|
||||
ccw[-1].flags |= CCW_FLAG_CC;
|
||||
}
|
||||
ccw->cmd_code = cmd;
|
||||
ccw->count = device->bp_block;
|
||||
ccw->count = block->bp_block;
|
||||
if (idal_is_needed(dst, blksize)) {
|
||||
ccw->cda = (__u32)(addr_t) idaws;
|
||||
ccw->flags = CCW_FLAG_IDA;
|
||||
@@ -342,7 +351,9 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req)
|
||||
}
|
||||
if (req->cmd_flags & REQ_FAILFAST)
|
||||
set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
|
||||
cqr->device = device;
|
||||
cqr->startdev = memdev;
|
||||
cqr->memdev = memdev;
|
||||
cqr->block = block;
|
||||
cqr->expires = 5 * 60 * HZ; /* 5 minutes */
|
||||
cqr->retries = 32;
|
||||
cqr->buildclk = get_clock();
|
||||
@@ -363,8 +374,8 @@ dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req)
|
||||
|
||||
if (!dasd_page_cache)
|
||||
goto out;
|
||||
private = (struct dasd_fba_private *) cqr->device->private;
|
||||
blksize = cqr->device->bp_block;
|
||||
private = (struct dasd_fba_private *) cqr->block->base->private;
|
||||
blksize = cqr->block->bp_block;
|
||||
ccw = cqr->cpaddr;
|
||||
/* Skip over define extent & locate record. */
|
||||
ccw++;
|
||||
@@ -394,10 +405,15 @@ dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req)
|
||||
}
|
||||
out:
|
||||
status = cqr->status == DASD_CQR_DONE;
|
||||
dasd_sfree_request(cqr, cqr->device);
|
||||
dasd_sfree_request(cqr, cqr->memdev);
|
||||
return status;
|
||||
}
|
||||
|
||||
static void dasd_fba_handle_terminated_request(struct dasd_ccw_req *cqr)
|
||||
{
|
||||
cqr->status = DASD_CQR_FILLED;
|
||||
};
|
||||
|
||||
static int
|
||||
dasd_fba_fill_info(struct dasd_device * device,
|
||||
struct dasd_information2_t * info)
|
||||
@@ -546,9 +562,10 @@ static struct dasd_discipline dasd_fba_discipline = {
|
||||
.fill_geometry = dasd_fba_fill_geometry,
|
||||
.start_IO = dasd_start_IO,
|
||||
.term_IO = dasd_term_IO,
|
||||
.examine_error = dasd_fba_examine_error,
|
||||
.handle_terminated_request = dasd_fba_handle_terminated_request,
|
||||
.erp_action = dasd_fba_erp_action,
|
||||
.erp_postaction = dasd_fba_erp_postaction,
|
||||
.handle_unsolicited_interrupt = dasd_fba_handle_unsolicited_interrupt,
|
||||
.build_cp = dasd_fba_build_cp,
|
||||
.free_cp = dasd_fba_free_cp,
|
||||
.dump_sense = dasd_fba_dump_sense,
|
||||
|
||||
@@ -25,14 +25,15 @@
|
||||
/*
|
||||
* Allocate and register gendisk structure for device.
|
||||
*/
|
||||
int
|
||||
dasd_gendisk_alloc(struct dasd_device *device)
|
||||
int dasd_gendisk_alloc(struct dasd_block *block)
|
||||
{
|
||||
struct gendisk *gdp;
|
||||
struct dasd_device *base;
|
||||
int len;
|
||||
|
||||
/* Make sure the minor for this device exists. */
|
||||
if (device->devindex >= DASD_PER_MAJOR)
|
||||
base = block->base;
|
||||
if (base->devindex >= DASD_PER_MAJOR)
|
||||
return -EBUSY;
|
||||
|
||||
gdp = alloc_disk(1 << DASD_PARTN_BITS);
|
||||
@@ -41,9 +42,9 @@ dasd_gendisk_alloc(struct dasd_device *device)
|
||||
|
||||
/* Initialize gendisk structure. */
|
||||
gdp->major = DASD_MAJOR;
|
||||
gdp->first_minor = device->devindex << DASD_PARTN_BITS;
|
||||
gdp->first_minor = base->devindex << DASD_PARTN_BITS;
|
||||
gdp->fops = &dasd_device_operations;
|
||||
gdp->driverfs_dev = &device->cdev->dev;
|
||||
gdp->driverfs_dev = &base->cdev->dev;
|
||||
|
||||
/*
|
||||
* Set device name.
|
||||
@@ -53,53 +54,51 @@ dasd_gendisk_alloc(struct dasd_device *device)
|
||||
* dasdaaaa - dasdzzzz : 456976 devices, added up = 475252
|
||||
*/
|
||||
len = sprintf(gdp->disk_name, "dasd");
|
||||
if (device->devindex > 25) {
|
||||
if (device->devindex > 701) {
|
||||
if (device->devindex > 18277)
|
||||
if (base->devindex > 25) {
|
||||
if (base->devindex > 701) {
|
||||
if (base->devindex > 18277)
|
||||
len += sprintf(gdp->disk_name + len, "%c",
|
||||
'a'+(((device->devindex-18278)
|
||||
'a'+(((base->devindex-18278)
|
||||
/17576)%26));
|
||||
len += sprintf(gdp->disk_name + len, "%c",
|
||||
'a'+(((device->devindex-702)/676)%26));
|
||||
'a'+(((base->devindex-702)/676)%26));
|
||||
}
|
||||
len += sprintf(gdp->disk_name + len, "%c",
|
||||
'a'+(((device->devindex-26)/26)%26));
|
||||
'a'+(((base->devindex-26)/26)%26));
|
||||
}
|
||||
len += sprintf(gdp->disk_name + len, "%c", 'a'+(device->devindex%26));
|
||||
len += sprintf(gdp->disk_name + len, "%c", 'a'+(base->devindex%26));
|
||||
|
||||
if (device->features & DASD_FEATURE_READONLY)
|
||||
if (block->base->features & DASD_FEATURE_READONLY)
|
||||
set_disk_ro(gdp, 1);
|
||||
gdp->private_data = device;
|
||||
gdp->queue = device->request_queue;
|
||||
device->gdp = gdp;
|
||||
set_capacity(device->gdp, 0);
|
||||
add_disk(device->gdp);
|
||||
gdp->private_data = block;
|
||||
gdp->queue = block->request_queue;
|
||||
block->gdp = gdp;
|
||||
set_capacity(block->gdp, 0);
|
||||
add_disk(block->gdp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unregister and free gendisk structure for device.
|
||||
*/
|
||||
void
|
||||
dasd_gendisk_free(struct dasd_device *device)
|
||||
void dasd_gendisk_free(struct dasd_block *block)
|
||||
{
|
||||
if (device->gdp) {
|
||||
del_gendisk(device->gdp);
|
||||
device->gdp->queue = NULL;
|
||||
put_disk(device->gdp);
|
||||
device->gdp = NULL;
|
||||
if (block->gdp) {
|
||||
del_gendisk(block->gdp);
|
||||
block->gdp->queue = NULL;
|
||||
put_disk(block->gdp);
|
||||
block->gdp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Trigger a partition detection.
|
||||
*/
|
||||
int
|
||||
dasd_scan_partitions(struct dasd_device * device)
|
||||
int dasd_scan_partitions(struct dasd_block *block)
|
||||
{
|
||||
struct block_device *bdev;
|
||||
|
||||
bdev = bdget_disk(device->gdp, 0);
|
||||
bdev = bdget_disk(block->gdp, 0);
|
||||
if (!bdev || blkdev_get(bdev, FMODE_READ, 1) < 0)
|
||||
return -ENODEV;
|
||||
/*
|
||||
@@ -117,7 +116,7 @@ dasd_scan_partitions(struct dasd_device * device)
|
||||
* is why the assignment to device->bdev is done AFTER
|
||||
* the BLKRRPART ioctl.
|
||||
*/
|
||||
device->bdev = bdev;
|
||||
block->bdev = bdev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -125,8 +124,7 @@ dasd_scan_partitions(struct dasd_device * device)
|
||||
* Remove all inodes in the system for a device, delete the
|
||||
* partitions and make device unusable by setting its size to zero.
|
||||
*/
|
||||
void
|
||||
dasd_destroy_partitions(struct dasd_device * device)
|
||||
void dasd_destroy_partitions(struct dasd_block *block)
|
||||
{
|
||||
/* The two structs have 168/176 byte on 31/64 bit. */
|
||||
struct blkpg_partition bpart;
|
||||
@@ -137,8 +135,8 @@ dasd_destroy_partitions(struct dasd_device * device)
|
||||
* Get the bdev pointer from the device structure and clear
|
||||
* device->bdev to lower the offline open_count limit again.
|
||||
*/
|
||||
bdev = device->bdev;
|
||||
device->bdev = NULL;
|
||||
bdev = block->bdev;
|
||||
block->bdev = NULL;
|
||||
|
||||
/*
|
||||
* See fs/partition/check.c:delete_partition
|
||||
@@ -149,17 +147,16 @@ dasd_destroy_partitions(struct dasd_device * device)
|
||||
memset(&barg, 0, sizeof(struct blkpg_ioctl_arg));
|
||||
barg.data = (void __force __user *) &bpart;
|
||||
barg.op = BLKPG_DEL_PARTITION;
|
||||
for (bpart.pno = device->gdp->minors - 1; bpart.pno > 0; bpart.pno--)
|
||||
for (bpart.pno = block->gdp->minors - 1; bpart.pno > 0; bpart.pno--)
|
||||
ioctl_by_bdev(bdev, BLKPG, (unsigned long) &barg);
|
||||
|
||||
invalidate_partition(device->gdp, 0);
|
||||
invalidate_partition(block->gdp, 0);
|
||||
/* Matching blkdev_put to the blkdev_get in dasd_scan_partitions. */
|
||||
blkdev_put(bdev);
|
||||
set_capacity(device->gdp, 0);
|
||||
set_capacity(block->gdp, 0);
|
||||
}
|
||||
|
||||
int
|
||||
dasd_gendisk_init(void)
|
||||
int dasd_gendisk_init(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
@@ -174,8 +171,7 @@ dasd_gendisk_init(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
dasd_gendisk_exit(void)
|
||||
void dasd_gendisk_exit(void)
|
||||
{
|
||||
unregister_blkdev(DASD_MAJOR, "dasd");
|
||||
}
|
||||
|
||||
+126
-81
@@ -64,13 +64,7 @@
|
||||
* SECTION: Type definitions
|
||||
*/
|
||||
struct dasd_device;
|
||||
|
||||
typedef enum {
|
||||
dasd_era_fatal = -1, /* no chance to recover */
|
||||
dasd_era_none = 0, /* don't recover, everything alright */
|
||||
dasd_era_msg = 1, /* don't recover, just report... */
|
||||
dasd_era_recover = 2 /* recovery action recommended */
|
||||
} dasd_era_t;
|
||||
struct dasd_block;
|
||||
|
||||
/* BIT DEFINITIONS FOR SENSE DATA */
|
||||
#define DASD_SENSE_BIT_0 0x80
|
||||
@@ -151,19 +145,22 @@ do { \
|
||||
|
||||
struct dasd_ccw_req {
|
||||
unsigned int magic; /* Eye catcher */
|
||||
struct list_head list; /* list_head for request queueing. */
|
||||
struct list_head devlist; /* for dasd_device request queue */
|
||||
struct list_head blocklist; /* for dasd_block request queue */
|
||||
|
||||
/* Where to execute what... */
|
||||
struct dasd_device *device; /* device the request is for */
|
||||
struct dasd_block *block; /* the originating block device */
|
||||
struct dasd_device *memdev; /* the device used to allocate this */
|
||||
struct dasd_device *startdev; /* device the request is started on */
|
||||
struct ccw1 *cpaddr; /* address of channel program */
|
||||
char status; /* status of this request */
|
||||
char status; /* status of this request */
|
||||
short retries; /* A retry counter */
|
||||
unsigned long flags; /* flags of this request */
|
||||
|
||||
/* ... and how */
|
||||
unsigned long starttime; /* jiffies time of request start */
|
||||
int expires; /* expiration period in jiffies */
|
||||
char lpm; /* logical path mask */
|
||||
char lpm; /* logical path mask */
|
||||
void *data; /* pointer to data area */
|
||||
|
||||
/* these are important for recovering erroneous requests */
|
||||
@@ -178,20 +175,27 @@ struct dasd_ccw_req {
|
||||
unsigned long long endclk; /* TOD-clock of request termination */
|
||||
|
||||
/* Callback that is called after reaching final status. */
|
||||
void (*callback)(struct dasd_ccw_req *, void *data);
|
||||
void *callback_data;
|
||||
void (*callback)(struct dasd_ccw_req *, void *data);
|
||||
void *callback_data;
|
||||
};
|
||||
|
||||
/*
|
||||
* dasd_ccw_req -> status can be:
|
||||
*/
|
||||
#define DASD_CQR_FILLED 0x00 /* request is ready to be processed */
|
||||
#define DASD_CQR_QUEUED 0x01 /* request is queued to be processed */
|
||||
#define DASD_CQR_IN_IO 0x02 /* request is currently in IO */
|
||||
#define DASD_CQR_DONE 0x03 /* request is completed successfully */
|
||||
#define DASD_CQR_ERROR 0x04 /* request is completed with error */
|
||||
#define DASD_CQR_FAILED 0x05 /* request is finally failed */
|
||||
#define DASD_CQR_CLEAR 0x06 /* request is clear pending */
|
||||
#define DASD_CQR_FILLED 0x00 /* request is ready to be processed */
|
||||
#define DASD_CQR_DONE 0x01 /* request is completed successfully */
|
||||
#define DASD_CQR_NEED_ERP 0x02 /* request needs recovery action */
|
||||
#define DASD_CQR_IN_ERP 0x03 /* request is in recovery */
|
||||
#define DASD_CQR_FAILED 0x04 /* request is finally failed */
|
||||
#define DASD_CQR_TERMINATED 0x05 /* request was stopped by driver */
|
||||
|
||||
#define DASD_CQR_QUEUED 0x80 /* request is queued to be processed */
|
||||
#define DASD_CQR_IN_IO 0x81 /* request is currently in IO */
|
||||
#define DASD_CQR_ERROR 0x82 /* request is completed with error */
|
||||
#define DASD_CQR_CLEAR_PENDING 0x83 /* request is clear pending */
|
||||
#define DASD_CQR_CLEARED 0x84 /* request was cleared */
|
||||
#define DASD_CQR_SUCCESS 0x85 /* request was successfull */
|
||||
|
||||
|
||||
/* per dasd_ccw_req flags */
|
||||
#define DASD_CQR_FLAGS_USE_ERP 0 /* use ERP for this request */
|
||||
@@ -214,52 +218,71 @@ struct dasd_discipline {
|
||||
|
||||
struct list_head list; /* used for list of disciplines */
|
||||
|
||||
/*
|
||||
* Device recognition functions. check_device is used to verify
|
||||
* the sense data and the information returned by read device
|
||||
* characteristics. It returns 0 if the discipline can be used
|
||||
* for the device in question.
|
||||
* do_analysis is used in the step from device state "basic" to
|
||||
* state "accept". It returns 0 if the device can be made ready,
|
||||
* it returns -EMEDIUMTYPE if the device can't be made ready or
|
||||
* -EAGAIN if do_analysis started a ccw that needs to complete
|
||||
* before the analysis may be repeated.
|
||||
*/
|
||||
int (*check_device)(struct dasd_device *);
|
||||
int (*do_analysis) (struct dasd_device *);
|
||||
/*
|
||||
* Device recognition functions. check_device is used to verify
|
||||
* the sense data and the information returned by read device
|
||||
* characteristics. It returns 0 if the discipline can be used
|
||||
* for the device in question. uncheck_device is called during
|
||||
* device shutdown to deregister a device from its discipline.
|
||||
*/
|
||||
int (*check_device) (struct dasd_device *);
|
||||
void (*uncheck_device) (struct dasd_device *);
|
||||
|
||||
/*
|
||||
* Device operation functions. build_cp creates a ccw chain for
|
||||
* a block device request, start_io starts the request and
|
||||
* term_IO cancels it (e.g. in case of a timeout). format_device
|
||||
* returns a ccw chain to be used to format the device.
|
||||
*/
|
||||
/*
|
||||
* do_analysis is used in the step from device state "basic" to
|
||||
* state "accept". It returns 0 if the device can be made ready,
|
||||
* it returns -EMEDIUMTYPE if the device can't be made ready or
|
||||
* -EAGAIN if do_analysis started a ccw that needs to complete
|
||||
* before the analysis may be repeated.
|
||||
*/
|
||||
int (*do_analysis) (struct dasd_block *);
|
||||
|
||||
/*
|
||||
* Last things to do when a device is set online, and first things
|
||||
* when it is set offline.
|
||||
*/
|
||||
int (*ready_to_online) (struct dasd_device *);
|
||||
int (*online_to_ready) (struct dasd_device *);
|
||||
|
||||
/*
|
||||
* Device operation functions. build_cp creates a ccw chain for
|
||||
* a block device request, start_io starts the request and
|
||||
* term_IO cancels it (e.g. in case of a timeout). format_device
|
||||
* returns a ccw chain to be used to format the device.
|
||||
* handle_terminated_request allows to examine a cqr and prepare
|
||||
* it for retry.
|
||||
*/
|
||||
struct dasd_ccw_req *(*build_cp) (struct dasd_device *,
|
||||
struct dasd_block *,
|
||||
struct request *);
|
||||
int (*start_IO) (struct dasd_ccw_req *);
|
||||
int (*term_IO) (struct dasd_ccw_req *);
|
||||
void (*handle_terminated_request) (struct dasd_ccw_req *);
|
||||
struct dasd_ccw_req *(*format_device) (struct dasd_device *,
|
||||
struct format_data_t *);
|
||||
int (*free_cp) (struct dasd_ccw_req *, struct request *);
|
||||
/*
|
||||
* Error recovery functions. examine_error() returns a value that
|
||||
* indicates what to do for an error condition. If examine_error()
|
||||
|
||||
/*
|
||||
* Error recovery functions. examine_error() returns a value that
|
||||
* indicates what to do for an error condition. If examine_error()
|
||||
* returns 'dasd_era_recover' erp_action() is called to create a
|
||||
* special error recovery ccw. erp_postaction() is called after
|
||||
* an error recovery ccw has finished its execution. dump_sense
|
||||
* is called for every error condition to print the sense data
|
||||
* to the console.
|
||||
*/
|
||||
dasd_era_t(*examine_error) (struct dasd_ccw_req *, struct irb *);
|
||||
* special error recovery ccw. erp_postaction() is called after
|
||||
* an error recovery ccw has finished its execution. dump_sense
|
||||
* is called for every error condition to print the sense data
|
||||
* to the console.
|
||||
*/
|
||||
dasd_erp_fn_t(*erp_action) (struct dasd_ccw_req *);
|
||||
dasd_erp_fn_t(*erp_postaction) (struct dasd_ccw_req *);
|
||||
void (*dump_sense) (struct dasd_device *, struct dasd_ccw_req *,
|
||||
struct irb *);
|
||||
|
||||
void (*handle_unsolicited_interrupt) (struct dasd_device *,
|
||||
struct irb *);
|
||||
|
||||
/* i/o control functions. */
|
||||
int (*fill_geometry) (struct dasd_device *, struct hd_geometry *);
|
||||
int (*fill_geometry) (struct dasd_block *, struct hd_geometry *);
|
||||
int (*fill_info) (struct dasd_device *, struct dasd_information2_t *);
|
||||
int (*ioctl) (struct dasd_device *, unsigned int, void __user *);
|
||||
int (*ioctl) (struct dasd_block *, unsigned int, void __user *);
|
||||
};
|
||||
|
||||
extern struct dasd_discipline *dasd_diag_discipline_pointer;
|
||||
@@ -267,12 +290,18 @@ extern struct dasd_discipline *dasd_diag_discipline_pointer;
|
||||
/*
|
||||
* Unique identifier for dasd device.
|
||||
*/
|
||||
#define UA_NOT_CONFIGURED 0x00
|
||||
#define UA_BASE_DEVICE 0x01
|
||||
#define UA_BASE_PAV_ALIAS 0x02
|
||||
#define UA_HYPER_PAV_ALIAS 0x03
|
||||
|
||||
struct dasd_uid {
|
||||
__u8 alias;
|
||||
__u8 type;
|
||||
char vendor[4];
|
||||
char serial[15];
|
||||
__u16 ssid;
|
||||
__u8 unit_addr;
|
||||
__u8 real_unit_addr;
|
||||
__u8 base_unit_addr;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -293,14 +322,9 @@ struct dasd_uid {
|
||||
|
||||
struct dasd_device {
|
||||
/* Block device stuff. */
|
||||
struct gendisk *gdp;
|
||||
struct request_queue *request_queue;
|
||||
spinlock_t request_queue_lock;
|
||||
struct block_device *bdev;
|
||||
struct dasd_block *block;
|
||||
|
||||
unsigned int devindex;
|
||||
unsigned long blocks; /* size of volume in blocks */
|
||||
unsigned int bp_block; /* bytes per block */
|
||||
unsigned int s2b_shift; /* log2 (bp_block/512) */
|
||||
unsigned long flags; /* per device flags */
|
||||
unsigned short features; /* copy of devmap-features (read-only!) */
|
||||
|
||||
@@ -316,9 +340,8 @@ struct dasd_device {
|
||||
int state, target;
|
||||
int stopped; /* device (ccw_device_start) was stopped */
|
||||
|
||||
/* Open and reference count. */
|
||||
/* reference count. */
|
||||
atomic_t ref_count;
|
||||
atomic_t open_count;
|
||||
|
||||
/* ccw queue and memory for static ccw/erp buffers. */
|
||||
struct list_head ccw_queue;
|
||||
@@ -337,20 +360,45 @@ struct dasd_device {
|
||||
|
||||
struct ccw_device *cdev;
|
||||
|
||||
/* hook for alias management */
|
||||
struct list_head alias_list;
|
||||
};
|
||||
|
||||
struct dasd_block {
|
||||
/* Block device stuff. */
|
||||
struct gendisk *gdp;
|
||||
struct request_queue *request_queue;
|
||||
spinlock_t request_queue_lock;
|
||||
struct block_device *bdev;
|
||||
atomic_t open_count;
|
||||
|
||||
unsigned long blocks; /* size of volume in blocks */
|
||||
unsigned int bp_block; /* bytes per block */
|
||||
unsigned int s2b_shift; /* log2 (bp_block/512) */
|
||||
|
||||
struct dasd_device *base;
|
||||
struct list_head ccw_queue;
|
||||
spinlock_t queue_lock;
|
||||
|
||||
atomic_t tasklet_scheduled;
|
||||
struct tasklet_struct tasklet;
|
||||
struct timer_list timer;
|
||||
|
||||
#ifdef CONFIG_DASD_PROFILE
|
||||
struct dasd_profile_info_t profile;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* reasons why device (ccw_device_start) was stopped */
|
||||
#define DASD_STOPPED_NOT_ACC 1 /* not accessible */
|
||||
#define DASD_STOPPED_QUIESCE 2 /* Quiesced */
|
||||
#define DASD_STOPPED_PENDING 4 /* long busy */
|
||||
#define DASD_STOPPED_DC_WAIT 8 /* disconnected, wait */
|
||||
#define DASD_STOPPED_DC_EIO 16 /* disconnected, return -EIO */
|
||||
#define DASD_STOPPED_SU 16 /* summary unit check handling */
|
||||
|
||||
/* per device flags */
|
||||
#define DASD_FLAG_DSC_ERROR 2 /* return -EIO when disconnected */
|
||||
#define DASD_FLAG_OFFLINE 3 /* device is in offline processing */
|
||||
#define DASD_FLAG_EER_SNSS 4 /* A SNSS is required */
|
||||
#define DASD_FLAG_EER_IN_USE 5 /* A SNSS request is running */
|
||||
@@ -489,6 +537,9 @@ dasd_kmalloc_set_cda(struct ccw1 *ccw, void *cda, struct dasd_device *device)
|
||||
struct dasd_device *dasd_alloc_device(void);
|
||||
void dasd_free_device(struct dasd_device *);
|
||||
|
||||
struct dasd_block *dasd_alloc_block(void);
|
||||
void dasd_free_block(struct dasd_block *);
|
||||
|
||||
void dasd_enable_device(struct dasd_device *);
|
||||
void dasd_set_target_state(struct dasd_device *, int);
|
||||
void dasd_kick_device(struct dasd_device *);
|
||||
@@ -497,18 +548,23 @@ void dasd_add_request_head(struct dasd_ccw_req *);
|
||||
void dasd_add_request_tail(struct dasd_ccw_req *);
|
||||
int dasd_start_IO(struct dasd_ccw_req *);
|
||||
int dasd_term_IO(struct dasd_ccw_req *);
|
||||
void dasd_schedule_bh(struct dasd_device *);
|
||||
void dasd_schedule_device_bh(struct dasd_device *);
|
||||
void dasd_schedule_block_bh(struct dasd_block *);
|
||||
int dasd_sleep_on(struct dasd_ccw_req *);
|
||||
int dasd_sleep_on_immediatly(struct dasd_ccw_req *);
|
||||
int dasd_sleep_on_interruptible(struct dasd_ccw_req *);
|
||||
void dasd_set_timer(struct dasd_device *, int);
|
||||
void dasd_clear_timer(struct dasd_device *);
|
||||
void dasd_device_set_timer(struct dasd_device *, int);
|
||||
void dasd_device_clear_timer(struct dasd_device *);
|
||||
void dasd_block_set_timer(struct dasd_block *, int);
|
||||
void dasd_block_clear_timer(struct dasd_block *);
|
||||
int dasd_cancel_req(struct dasd_ccw_req *);
|
||||
int dasd_flush_device_queue(struct dasd_device *);
|
||||
int dasd_generic_probe (struct ccw_device *, struct dasd_discipline *);
|
||||
void dasd_generic_remove (struct ccw_device *cdev);
|
||||
int dasd_generic_set_online(struct ccw_device *, struct dasd_discipline *);
|
||||
int dasd_generic_set_offline (struct ccw_device *cdev);
|
||||
int dasd_generic_notify(struct ccw_device *, int);
|
||||
void dasd_generic_handle_state_change(struct dasd_device *);
|
||||
|
||||
int dasd_generic_read_dev_chars(struct dasd_device *, char *, void **, int);
|
||||
|
||||
@@ -542,10 +598,10 @@ int dasd_busid_known(char *);
|
||||
/* externals in dasd_gendisk.c */
|
||||
int dasd_gendisk_init(void);
|
||||
void dasd_gendisk_exit(void);
|
||||
int dasd_gendisk_alloc(struct dasd_device *);
|
||||
void dasd_gendisk_free(struct dasd_device *);
|
||||
int dasd_scan_partitions(struct dasd_device *);
|
||||
void dasd_destroy_partitions(struct dasd_device *);
|
||||
int dasd_gendisk_alloc(struct dasd_block *);
|
||||
void dasd_gendisk_free(struct dasd_block *);
|
||||
int dasd_scan_partitions(struct dasd_block *);
|
||||
void dasd_destroy_partitions(struct dasd_block *);
|
||||
|
||||
/* externals in dasd_ioctl.c */
|
||||
int dasd_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
|
||||
@@ -563,20 +619,9 @@ struct dasd_ccw_req *dasd_alloc_erp_request(char *, int, int,
|
||||
void dasd_free_erp_request(struct dasd_ccw_req *, struct dasd_device *);
|
||||
void dasd_log_sense(struct dasd_ccw_req *, struct irb *);
|
||||
|
||||
/* externals in dasd_3370_erp.c */
|
||||
dasd_era_t dasd_3370_erp_examine(struct dasd_ccw_req *, struct irb *);
|
||||
|
||||
/* externals in dasd_3990_erp.c */
|
||||
dasd_era_t dasd_3990_erp_examine(struct dasd_ccw_req *, struct irb *);
|
||||
struct dasd_ccw_req *dasd_3990_erp_action(struct dasd_ccw_req *);
|
||||
|
||||
/* externals in dasd_9336_erp.c */
|
||||
dasd_era_t dasd_9336_erp_examine(struct dasd_ccw_req *, struct irb *);
|
||||
|
||||
/* externals in dasd_9336_erp.c */
|
||||
dasd_era_t dasd_9343_erp_examine(struct dasd_ccw_req *, struct irb *);
|
||||
struct dasd_ccw_req *dasd_9343_erp_action(struct dasd_ccw_req *);
|
||||
|
||||
/* externals in dasd_eer.c */
|
||||
#ifdef CONFIG_DASD_EER
|
||||
int dasd_eer_init(void);
|
||||
|
||||
@@ -38,15 +38,15 @@ dasd_ioctl_api_version(void __user *argp)
|
||||
static int
|
||||
dasd_ioctl_enable(struct block_device *bdev)
|
||||
{
|
||||
struct dasd_device *device = bdev->bd_disk->private_data;
|
||||
struct dasd_block *block = bdev->bd_disk->private_data;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EACCES;
|
||||
|
||||
dasd_enable_device(device);
|
||||
dasd_enable_device(block->base);
|
||||
/* Formatting the dasd device can change the capacity. */
|
||||
mutex_lock(&bdev->bd_mutex);
|
||||
i_size_write(bdev->bd_inode, (loff_t)get_capacity(device->gdp) << 9);
|
||||
i_size_write(bdev->bd_inode, (loff_t)get_capacity(block->gdp) << 9);
|
||||
mutex_unlock(&bdev->bd_mutex);
|
||||
return 0;
|
||||
}
|
||||
@@ -58,7 +58,7 @@ dasd_ioctl_enable(struct block_device *bdev)
|
||||
static int
|
||||
dasd_ioctl_disable(struct block_device *bdev)
|
||||
{
|
||||
struct dasd_device *device = bdev->bd_disk->private_data;
|
||||
struct dasd_block *block = bdev->bd_disk->private_data;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EACCES;
|
||||
@@ -71,7 +71,7 @@ dasd_ioctl_disable(struct block_device *bdev)
|
||||
* using the BIODASDFMT ioctl. Therefore the correct state for the
|
||||
* device is DASD_STATE_BASIC that allows to do basic i/o.
|
||||
*/
|
||||
dasd_set_target_state(device, DASD_STATE_BASIC);
|
||||
dasd_set_target_state(block->base, DASD_STATE_BASIC);
|
||||
/*
|
||||
* Set i_size to zero, since read, write, etc. check against this
|
||||
* value.
|
||||
@@ -85,19 +85,19 @@ dasd_ioctl_disable(struct block_device *bdev)
|
||||
/*
|
||||
* Quiesce device.
|
||||
*/
|
||||
static int
|
||||
dasd_ioctl_quiesce(struct dasd_device *device)
|
||||
static int dasd_ioctl_quiesce(struct dasd_block *block)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct dasd_device *base;
|
||||
|
||||
base = block->base;
|
||||
if (!capable (CAP_SYS_ADMIN))
|
||||
return -EACCES;
|
||||
|
||||
DEV_MESSAGE (KERN_DEBUG, device, "%s",
|
||||
"Quiesce IO on device");
|
||||
spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
|
||||
device->stopped |= DASD_STOPPED_QUIESCE;
|
||||
spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
|
||||
DEV_MESSAGE(KERN_DEBUG, base, "%s", "Quiesce IO on device");
|
||||
spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
|
||||
base->stopped |= DASD_STOPPED_QUIESCE;
|
||||
spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -105,22 +105,21 @@ dasd_ioctl_quiesce(struct dasd_device *device)
|
||||
/*
|
||||
* Quiesce device.
|
||||
*/
|
||||
static int
|
||||
dasd_ioctl_resume(struct dasd_device *device)
|
||||
static int dasd_ioctl_resume(struct dasd_block *block)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct dasd_device *base;
|
||||
|
||||
base = block->base;
|
||||
if (!capable (CAP_SYS_ADMIN))
|
||||
return -EACCES;
|
||||
|
||||
DEV_MESSAGE (KERN_DEBUG, device, "%s",
|
||||
"resume IO on device");
|
||||
DEV_MESSAGE(KERN_DEBUG, base, "%s", "resume IO on device");
|
||||
spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
|
||||
base->stopped &= ~DASD_STOPPED_QUIESCE;
|
||||
spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags);
|
||||
|
||||
spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
|
||||
device->stopped &= ~DASD_STOPPED_QUIESCE;
|
||||
spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
|
||||
|
||||
dasd_schedule_bh (device);
|
||||
dasd_schedule_block_bh(block);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -130,22 +129,23 @@ dasd_ioctl_resume(struct dasd_device *device)
|
||||
* commands to format a single unit of the device. In terms of the ECKD
|
||||
* devices this means CCWs are generated to format a single track.
|
||||
*/
|
||||
static int
|
||||
dasd_format(struct dasd_device * device, struct format_data_t * fdata)
|
||||
static int dasd_format(struct dasd_block *block, struct format_data_t *fdata)
|
||||
{
|
||||
struct dasd_ccw_req *cqr;
|
||||
struct dasd_device *base;
|
||||
int rc;
|
||||
|
||||
if (device->discipline->format_device == NULL)
|
||||
base = block->base;
|
||||
if (base->discipline->format_device == NULL)
|
||||
return -EPERM;
|
||||
|
||||
if (device->state != DASD_STATE_BASIC) {
|
||||
DEV_MESSAGE(KERN_WARNING, device, "%s",
|
||||
if (base->state != DASD_STATE_BASIC) {
|
||||
DEV_MESSAGE(KERN_WARNING, base, "%s",
|
||||
"dasd_format: device is not disabled! ");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
DBF_DEV_EVENT(DBF_NOTICE, device,
|
||||
DBF_DEV_EVENT(DBF_NOTICE, base,
|
||||
"formatting units %d to %d (%d B blocks) flags %d",
|
||||
fdata->start_unit,
|
||||
fdata->stop_unit, fdata->blksize, fdata->intensity);
|
||||
@@ -156,20 +156,20 @@ dasd_format(struct dasd_device * device, struct format_data_t * fdata)
|
||||
* enabling the device later.
|
||||
*/
|
||||
if (fdata->start_unit == 0) {
|
||||
struct block_device *bdev = bdget_disk(device->gdp, 0);
|
||||
struct block_device *bdev = bdget_disk(block->gdp, 0);
|
||||
bdev->bd_inode->i_blkbits = blksize_bits(fdata->blksize);
|
||||
bdput(bdev);
|
||||
}
|
||||
|
||||
while (fdata->start_unit <= fdata->stop_unit) {
|
||||
cqr = device->discipline->format_device(device, fdata);
|
||||
cqr = base->discipline->format_device(base, fdata);
|
||||
if (IS_ERR(cqr))
|
||||
return PTR_ERR(cqr);
|
||||
rc = dasd_sleep_on_interruptible(cqr);
|
||||
dasd_sfree_request(cqr, cqr->device);
|
||||
dasd_sfree_request(cqr, cqr->memdev);
|
||||
if (rc) {
|
||||
if (rc != -ERESTARTSYS)
|
||||
DEV_MESSAGE(KERN_ERR, device,
|
||||
DEV_MESSAGE(KERN_ERR, base,
|
||||
" Formatting of unit %d failed "
|
||||
"with rc = %d",
|
||||
fdata->start_unit, rc);
|
||||
@@ -186,7 +186,7 @@ dasd_format(struct dasd_device * device, struct format_data_t * fdata)
|
||||
static int
|
||||
dasd_ioctl_format(struct block_device *bdev, void __user *argp)
|
||||
{
|
||||
struct dasd_device *device = bdev->bd_disk->private_data;
|
||||
struct dasd_block *block = bdev->bd_disk->private_data;
|
||||
struct format_data_t fdata;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
@@ -194,51 +194,47 @@ dasd_ioctl_format(struct block_device *bdev, void __user *argp)
|
||||
if (!argp)
|
||||
return -EINVAL;
|
||||
|
||||
if (device->features & DASD_FEATURE_READONLY)
|
||||
if (block->base->features & DASD_FEATURE_READONLY)
|
||||
return -EROFS;
|
||||
if (copy_from_user(&fdata, argp, sizeof(struct format_data_t)))
|
||||
return -EFAULT;
|
||||
if (bdev != bdev->bd_contains) {
|
||||
DEV_MESSAGE(KERN_WARNING, device, "%s",
|
||||
DEV_MESSAGE(KERN_WARNING, block->base, "%s",
|
||||
"Cannot low-level format a partition");
|
||||
return -EINVAL;
|
||||
}
|
||||
return dasd_format(device, &fdata);
|
||||
return dasd_format(block, &fdata);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DASD_PROFILE
|
||||
/*
|
||||
* Reset device profile information
|
||||
*/
|
||||
static int
|
||||
dasd_ioctl_reset_profile(struct dasd_device *device)
|
||||
static int dasd_ioctl_reset_profile(struct dasd_block *block)
|
||||
{
|
||||
memset(&device->profile, 0, sizeof (struct dasd_profile_info_t));
|
||||
memset(&block->profile, 0, sizeof(struct dasd_profile_info_t));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return device profile information
|
||||
*/
|
||||
static int
|
||||
dasd_ioctl_read_profile(struct dasd_device *device, void __user *argp)
|
||||
static int dasd_ioctl_read_profile(struct dasd_block *block, void __user *argp)
|
||||
{
|
||||
if (dasd_profile_level == DASD_PROFILE_OFF)
|
||||
return -EIO;
|
||||
if (copy_to_user(argp, &device->profile,
|
||||
sizeof (struct dasd_profile_info_t)))
|
||||
if (copy_to_user(argp, &block->profile,
|
||||
sizeof(struct dasd_profile_info_t)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int
|
||||
dasd_ioctl_reset_profile(struct dasd_device *device)
|
||||
static int dasd_ioctl_reset_profile(struct dasd_block *block)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static int
|
||||
dasd_ioctl_read_profile(struct dasd_device *device, void __user *argp)
|
||||
static int dasd_ioctl_read_profile(struct dasd_block *block, void __user *argp)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
@@ -247,87 +243,88 @@ dasd_ioctl_read_profile(struct dasd_device *device, void __user *argp)
|
||||
/*
|
||||
* Return dasd information. Used for BIODASDINFO and BIODASDINFO2.
|
||||
*/
|
||||
static int
|
||||
dasd_ioctl_information(struct dasd_device *device,
|
||||
unsigned int cmd, void __user *argp)
|
||||
static int dasd_ioctl_information(struct dasd_block *block,
|
||||
unsigned int cmd, void __user *argp)
|
||||
{
|
||||
struct dasd_information2_t *dasd_info;
|
||||
unsigned long flags;
|
||||
int rc;
|
||||
struct dasd_device *base;
|
||||
struct ccw_device *cdev;
|
||||
struct ccw_dev_id dev_id;
|
||||
|
||||
if (!device->discipline->fill_info)
|
||||
base = block->base;
|
||||
if (!base->discipline->fill_info)
|
||||
return -EINVAL;
|
||||
|
||||
dasd_info = kzalloc(sizeof(struct dasd_information2_t), GFP_KERNEL);
|
||||
if (dasd_info == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
rc = device->discipline->fill_info(device, dasd_info);
|
||||
rc = base->discipline->fill_info(base, dasd_info);
|
||||
if (rc) {
|
||||
kfree(dasd_info);
|
||||
return rc;
|
||||
}
|
||||
|
||||
cdev = device->cdev;
|
||||
cdev = base->cdev;
|
||||
ccw_device_get_id(cdev, &dev_id);
|
||||
|
||||
dasd_info->devno = dev_id.devno;
|
||||
dasd_info->schid = _ccw_device_get_subchannel_number(device->cdev);
|
||||
dasd_info->schid = _ccw_device_get_subchannel_number(base->cdev);
|
||||
dasd_info->cu_type = cdev->id.cu_type;
|
||||
dasd_info->cu_model = cdev->id.cu_model;
|
||||
dasd_info->dev_type = cdev->id.dev_type;
|
||||
dasd_info->dev_model = cdev->id.dev_model;
|
||||
dasd_info->status = device->state;
|
||||
dasd_info->status = base->state;
|
||||
/*
|
||||
* The open_count is increased for every opener, that includes
|
||||
* the blkdev_get in dasd_scan_partitions.
|
||||
* This must be hidden from user-space.
|
||||
*/
|
||||
dasd_info->open_count = atomic_read(&device->open_count);
|
||||
if (!device->bdev)
|
||||
dasd_info->open_count = atomic_read(&block->open_count);
|
||||
if (!block->bdev)
|
||||
dasd_info->open_count++;
|
||||
|
||||
/*
|
||||
* check if device is really formatted
|
||||
* LDL / CDL was returned by 'fill_info'
|
||||
*/
|
||||
if ((device->state < DASD_STATE_READY) ||
|
||||
(dasd_check_blocksize(device->bp_block)))
|
||||
if ((base->state < DASD_STATE_READY) ||
|
||||
(dasd_check_blocksize(block->bp_block)))
|
||||
dasd_info->format = DASD_FORMAT_NONE;
|
||||
|
||||
dasd_info->features |=
|
||||
((device->features & DASD_FEATURE_READONLY) != 0);
|
||||
((base->features & DASD_FEATURE_READONLY) != 0);
|
||||
|
||||
if (device->discipline)
|
||||
memcpy(dasd_info->type, device->discipline->name, 4);
|
||||
if (base->discipline)
|
||||
memcpy(dasd_info->type, base->discipline->name, 4);
|
||||
else
|
||||
memcpy(dasd_info->type, "none", 4);
|
||||
|
||||
if (device->request_queue->request_fn) {
|
||||
if (block->request_queue->request_fn) {
|
||||
struct list_head *l;
|
||||
#ifdef DASD_EXTENDED_PROFILING
|
||||
{
|
||||
struct list_head *l;
|
||||
spin_lock_irqsave(&device->lock, flags);
|
||||
list_for_each(l, &device->request_queue->queue_head)
|
||||
spin_lock_irqsave(&block->lock, flags);
|
||||
list_for_each(l, &block->request_queue->queue_head)
|
||||
dasd_info->req_queue_len++;
|
||||
spin_unlock_irqrestore(&device->lock, flags);
|
||||
spin_unlock_irqrestore(&block->lock, flags);
|
||||
}
|
||||
#endif /* DASD_EXTENDED_PROFILING */
|
||||
spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
|
||||
list_for_each(l, &device->ccw_queue)
|
||||
spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
|
||||
list_for_each(l, &base->ccw_queue)
|
||||
dasd_info->chanq_len++;
|
||||
spin_unlock_irqrestore(get_ccwdev_lock(device->cdev),
|
||||
spin_unlock_irqrestore(get_ccwdev_lock(base->cdev),
|
||||
flags);
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
if (copy_to_user(argp, dasd_info,
|
||||
((cmd == (unsigned int) BIODASDINFO2) ?
|
||||
sizeof (struct dasd_information2_t) :
|
||||
sizeof (struct dasd_information_t))))
|
||||
sizeof(struct dasd_information2_t) :
|
||||
sizeof(struct dasd_information_t))))
|
||||
rc = -EFAULT;
|
||||
kfree(dasd_info);
|
||||
return rc;
|
||||
@@ -339,7 +336,7 @@ dasd_ioctl_information(struct dasd_device *device,
|
||||
static int
|
||||
dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp)
|
||||
{
|
||||
struct dasd_device *device = bdev->bd_disk->private_data;
|
||||
struct dasd_block *block = bdev->bd_disk->private_data;
|
||||
int intval;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
@@ -351,11 +348,10 @@ dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp)
|
||||
return -EFAULT;
|
||||
|
||||
set_disk_ro(bdev->bd_disk, intval);
|
||||
return dasd_set_feature(device->cdev, DASD_FEATURE_READONLY, intval);
|
||||
return dasd_set_feature(block->base->cdev, DASD_FEATURE_READONLY, intval);
|
||||
}
|
||||
|
||||
static int
|
||||
dasd_ioctl_readall_cmb(struct dasd_device *device, unsigned int cmd,
|
||||
static int dasd_ioctl_readall_cmb(struct dasd_block *block, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct cmbdata __user *argp = (void __user *) arg;
|
||||
@@ -363,7 +359,7 @@ dasd_ioctl_readall_cmb(struct dasd_device *device, unsigned int cmd,
|
||||
struct cmbdata data;
|
||||
int ret;
|
||||
|
||||
ret = cmf_readall(device->cdev, &data);
|
||||
ret = cmf_readall(block->base->cdev, &data);
|
||||
if (!ret && copy_to_user(argp, &data, min(size, sizeof(*argp))))
|
||||
return -EFAULT;
|
||||
return ret;
|
||||
@@ -374,10 +370,10 @@ dasd_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct block_device *bdev = inode->i_bdev;
|
||||
struct dasd_device *device = bdev->bd_disk->private_data;
|
||||
struct dasd_block *block = bdev->bd_disk->private_data;
|
||||
void __user *argp = (void __user *)arg;
|
||||
|
||||
if (!device)
|
||||
if (!block)
|
||||
return -ENODEV;
|
||||
|
||||
if ((_IOC_DIR(cmd) != _IOC_NONE) && !arg) {
|
||||
@@ -391,33 +387,33 @@ dasd_ioctl(struct inode *inode, struct file *file,
|
||||
case BIODASDENABLE:
|
||||
return dasd_ioctl_enable(bdev);
|
||||
case BIODASDQUIESCE:
|
||||
return dasd_ioctl_quiesce(device);
|
||||
return dasd_ioctl_quiesce(block);
|
||||
case BIODASDRESUME:
|
||||
return dasd_ioctl_resume(device);
|
||||
return dasd_ioctl_resume(block);
|
||||
case BIODASDFMT:
|
||||
return dasd_ioctl_format(bdev, argp);
|
||||
case BIODASDINFO:
|
||||
return dasd_ioctl_information(device, cmd, argp);
|
||||
return dasd_ioctl_information(block, cmd, argp);
|
||||
case BIODASDINFO2:
|
||||
return dasd_ioctl_information(device, cmd, argp);
|
||||
return dasd_ioctl_information(block, cmd, argp);
|
||||
case BIODASDPRRD:
|
||||
return dasd_ioctl_read_profile(device, argp);
|
||||
return dasd_ioctl_read_profile(block, argp);
|
||||
case BIODASDPRRST:
|
||||
return dasd_ioctl_reset_profile(device);
|
||||
return dasd_ioctl_reset_profile(block);
|
||||
case BLKROSET:
|
||||
return dasd_ioctl_set_ro(bdev, argp);
|
||||
case DASDAPIVER:
|
||||
return dasd_ioctl_api_version(argp);
|
||||
case BIODASDCMFENABLE:
|
||||
return enable_cmf(device->cdev);
|
||||
return enable_cmf(block->base->cdev);
|
||||
case BIODASDCMFDISABLE:
|
||||
return disable_cmf(device->cdev);
|
||||
return disable_cmf(block->base->cdev);
|
||||
case BIODASDREADALLCMB:
|
||||
return dasd_ioctl_readall_cmb(device, cmd, arg);
|
||||
return dasd_ioctl_readall_cmb(block, cmd, arg);
|
||||
default:
|
||||
/* if the discipline has an ioctl method try it. */
|
||||
if (device->discipline->ioctl) {
|
||||
int rval = device->discipline->ioctl(device, cmd, argp);
|
||||
if (block->base->discipline->ioctl) {
|
||||
int rval = block->base->discipline->ioctl(block, cmd, argp);
|
||||
if (rval != -ENOIOCTLCMD)
|
||||
return rval;
|
||||
}
|
||||
|
||||
@@ -54,11 +54,16 @@ static int
|
||||
dasd_devices_show(struct seq_file *m, void *v)
|
||||
{
|
||||
struct dasd_device *device;
|
||||
struct dasd_block *block;
|
||||
char *substr;
|
||||
|
||||
device = dasd_device_from_devindex((unsigned long) v - 1);
|
||||
if (IS_ERR(device))
|
||||
return 0;
|
||||
if (device->block)
|
||||
block = device->block;
|
||||
else
|
||||
return 0;
|
||||
/* Print device number. */
|
||||
seq_printf(m, "%s", device->cdev->dev.bus_id);
|
||||
/* Print discipline string. */
|
||||
@@ -67,14 +72,14 @@ dasd_devices_show(struct seq_file *m, void *v)
|
||||
else
|
||||
seq_printf(m, "(none)");
|
||||
/* Print kdev. */
|
||||
if (device->gdp)
|
||||
if (block->gdp)
|
||||
seq_printf(m, " at (%3d:%6d)",
|
||||
device->gdp->major, device->gdp->first_minor);
|
||||
block->gdp->major, block->gdp->first_minor);
|
||||
else
|
||||
seq_printf(m, " at (???:??????)");
|
||||
/* Print device name. */
|
||||
if (device->gdp)
|
||||
seq_printf(m, " is %-8s", device->gdp->disk_name);
|
||||
if (block->gdp)
|
||||
seq_printf(m, " is %-8s", block->gdp->disk_name);
|
||||
else
|
||||
seq_printf(m, " is ????????");
|
||||
/* Print devices features. */
|
||||
@@ -100,14 +105,14 @@ dasd_devices_show(struct seq_file *m, void *v)
|
||||
case DASD_STATE_READY:
|
||||
case DASD_STATE_ONLINE:
|
||||
seq_printf(m, "active ");
|
||||
if (dasd_check_blocksize(device->bp_block))
|
||||
if (dasd_check_blocksize(block->bp_block))
|
||||
seq_printf(m, "n/f ");
|
||||
else
|
||||
seq_printf(m,
|
||||
"at blocksize: %d, %ld blocks, %ld MB",
|
||||
device->bp_block, device->blocks,
|
||||
((device->bp_block >> 9) *
|
||||
device->blocks) >> 11);
|
||||
block->bp_block, block->blocks,
|
||||
((block->bp_block >> 9) *
|
||||
block->blocks) >> 11);
|
||||
break;
|
||||
default:
|
||||
seq_printf(m, "no stat");
|
||||
|
||||
Reference in New Issue
Block a user