aboutsummaryrefslogtreecommitdiff
path: root/drivers/s390/block/dasd_diag.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/block/dasd_diag.c')
-rw-r--r--drivers/s390/block/dasd_diag.c124
1 files changed, 71 insertions, 53 deletions
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
index b9a7f773344..c062f1620c5 100644
--- a/drivers/s390/block/dasd_diag.c
+++ b/drivers/s390/block/dasd_diag.c
@@ -1,15 +1,15 @@
/*
- * File...........: linux/drivers/s390/block/dasd_diag.c
* Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
* Based on.......: linux/drivers/s390/block/mdisk.c
* ...............: by Hartmunt Penner <hpenner@de.ibm.com>
* Bugreports.to..: <Linux390@de.ibm.com>
- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
+ * Copyright IBM Corp. 1999, 2000
*
*/
#define KMSG_COMPONENT "dasd"
+#include <linux/kernel_stat.h>
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -23,8 +23,7 @@
#include <asm/debug.h>
#include <asm/ebcdic.h>
#include <asm/io.h>
-#include <asm/s390_ext.h>
-#include <asm/todclk.h>
+#include <asm/irq.h>
#include <asm/vtoc.h>
#include <asm/diag.h>
@@ -44,7 +43,7 @@ MODULE_LICENSE("GPL");
sizeof(struct dasd_diag_req)) / \
sizeof(struct dasd_diag_bio)) / 2)
#define DIAG_MAX_RETRIES 32
-#define DIAG_TIMEOUT 50 * HZ
+#define DIAG_TIMEOUT 50
static struct dasd_discipline dasd_diag_discipline;
@@ -145,9 +144,16 @@ dasd_diag_erp(struct dasd_device *device)
mdsk_term_io(device);
rc = mdsk_init_io(device, device->block->bp_block, 0, NULL);
+ if (rc == 4) {
+ if (!(test_and_set_bit(DASD_FLAG_DEVICE_RO, &device->flags)))
+ pr_warning("%s: The access mode of a DIAG device "
+ "changed to read-only\n",
+ dev_name(&device->cdev->dev));
+ rc = 0;
+ }
if (rc)
- dev_warn(&device->cdev->dev, "DIAG ERP failed with "
- "rc=%d\n", rc);
+ pr_warning("%s: DIAG ERP failed with "
+ "rc=%d\n", dev_name(&device->cdev->dev), rc);
}
/* Start a given request at the device. Return zero on success, non-zero
@@ -178,14 +184,14 @@ dasd_start_diag(struct dasd_ccw_req * cqr)
private->iob.bio_list = dreq->bio;
private->iob.flaga = DASD_DIAG_FLAGA_DEFAULT;
- cqr->startclk = get_clock();
+ cqr->startclk = get_tod_clock();
cqr->starttime = jiffies;
cqr->retries--;
rc = dia250(&private->iob, RW_BIO);
switch (rc) {
case 0: /* Synchronous I/O finished successfully */
- cqr->stopclk = get_clock();
+ cqr->stopclk = get_tod_clock();
cqr->status = DASD_CQR_SUCCESS;
/* Indicate to calling function that only a dasd_schedule_bh()
and no timer is needed */
@@ -202,6 +208,7 @@ dasd_start_diag(struct dasd_ccw_req * cqr)
rc = -EIO;
break;
}
+ cqr->intrc = rc;
return rc;
}
@@ -215,35 +222,33 @@ dasd_diag_term_IO(struct dasd_ccw_req * cqr)
mdsk_term_io(device);
mdsk_init_io(device, device->block->bp_block, 0, NULL);
cqr->status = DASD_CQR_CLEAR_PENDING;
- cqr->stopclk = get_clock();
+ cqr->stopclk = get_tod_clock();
dasd_schedule_device_bh(device);
return 0;
}
/* Handle external interruption. */
-static void
-dasd_ext_handler(__u16 code)
+static void dasd_ext_handler(struct ext_code ext_code,
+ unsigned int param32, unsigned long param64)
{
struct dasd_ccw_req *cqr, *next;
struct dasd_device *device;
unsigned long long expires;
unsigned long flags;
- u8 int_code, status;
addr_t ip;
int rc;
- int_code = *((u8 *) DASD_DIAG_LC_INT_CODE);
- status = *((u8 *) DASD_DIAG_LC_INT_STATUS);
- switch (int_code) {
+ switch (ext_code.subcode >> 8) {
case DASD_DIAG_CODE_31BIT:
- ip = (addr_t) *((u32 *) DASD_DIAG_LC_INT_PARM_31BIT);
+ ip = (addr_t) param32;
break;
case DASD_DIAG_CODE_64BIT:
- ip = (addr_t) *((u64 *) DASD_DIAG_LC_INT_PARM_64BIT);
+ ip = (addr_t) param64;
break;
default:
return;
}
+ inc_irq_stat(IRQEXT_DSD);
if (!ip) { /* no intparm: unsolicited interrupt */
DBF_EVENT(DBF_NOTICE, "%s", "caught unsolicited "
"interrupt");
@@ -271,10 +276,10 @@ dasd_ext_handler(__u16 code)
return;
}
- cqr->stopclk = get_clock();
+ cqr->stopclk = get_tod_clock();
expires = 0;
- if (status == 0) {
+ if ((ext_code.subcode & 0xff) == 0) {
cqr->status = DASD_CQR_SUCCESS;
/* Start first request on queue if possible -> fast_io. */
if (!list_empty(&device->ccw_queue)) {
@@ -289,8 +294,8 @@ dasd_ext_handler(__u16 code)
} else {
cqr->status = DASD_CQR_QUEUED;
DBF_DEV_EVENT(DBF_DEBUG, device, "interrupt status for "
- "request %p was %d (%d retries left)", cqr, status,
- cqr->retries);
+ "request %p was %d (%d retries left)", cqr,
+ ext_code.subcode & 0xff, cqr->retries);
dasd_diag_erp(device);
}
@@ -353,6 +358,9 @@ dasd_diag_check_device(struct dasd_device *device)
goto out;
}
+ device->default_expires = DIAG_TIMEOUT;
+ device->default_retries = DIAG_MAX_RETRIES;
+
/* Figure out position of label block */
switch (private->rdc_data.vdev_class) {
case DEV_CLASS_FBA:
@@ -362,8 +370,9 @@ dasd_diag_check_device(struct dasd_device *device)
private->pt_block = 2;
break;
default:
- dev_warn(&device->cdev->dev, "Device type %d is not supported "
- "in DIAG mode\n", private->rdc_data.vdev_class);
+ pr_warning("%s: Device type %d is not supported "
+ "in DIAG mode\n", dev_name(&device->cdev->dev),
+ private->rdc_data.vdev_class);
rc = -EOPNOTSUPP;
goto out;
}
@@ -404,8 +413,8 @@ dasd_diag_check_device(struct dasd_device *device)
private->iob.flaga = DASD_DIAG_FLAGA_DEFAULT;
rc = dia250(&private->iob, RW_BIO);
if (rc == 3) {
- dev_warn(&device->cdev->dev,
- "A 64-bit DIAG call failed\n");
+ pr_warning("%s: A 64-bit DIAG call failed\n",
+ dev_name(&device->cdev->dev));
rc = -EOPNOTSUPP;
goto out_label;
}
@@ -414,8 +423,9 @@ dasd_diag_check_device(struct dasd_device *device)
break;
}
if (bsize > PAGE_SIZE) {
- dev_warn(&device->cdev->dev, "Accessing the DASD failed because"
- " of an incorrect format (rc=%d)\n", rc);
+ pr_warning("%s: Accessing the DASD failed because of an "
+ "incorrect format (rc=%d)\n",
+ dev_name(&device->cdev->dev), rc);
rc = -EIO;
goto out_label;
}
@@ -432,16 +442,20 @@ dasd_diag_check_device(struct dasd_device *device)
for (sb = 512; sb < bsize; sb = sb << 1)
block->s2b_shift++;
rc = mdsk_init_io(device, block->bp_block, 0, NULL);
- if (rc) {
- dev_warn(&device->cdev->dev, "DIAG initialization "
- "failed with rc=%d\n", rc);
+ if (rc && (rc != 4)) {
+ pr_warning("%s: DIAG initialization failed with rc=%d\n",
+ dev_name(&device->cdev->dev), rc);
rc = -EIO;
} else {
- dev_info(&device->cdev->dev,
- "New DASD with %ld byte/block, total size %ld KB\n",
- (unsigned long) block->bp_block,
- (unsigned long) (block->blocks <<
- block->s2b_shift) >> 1);
+ if (rc == 4)
+ set_bit(DASD_FLAG_DEVICE_RO, &device->flags);
+ pr_info("%s: New DASD with %ld byte/block, total size %ld "
+ "KB%s\n", dev_name(&device->cdev->dev),
+ (unsigned long) block->bp_block,
+ (unsigned long) (block->blocks <<
+ block->s2b_shift) >> 1,
+ (rc == 4) ? ", read-only device" : "");
+ rc = 0;
}
out_label:
free_page((long) label);
@@ -490,7 +504,7 @@ static struct dasd_ccw_req *dasd_diag_build_cp(struct dasd_device *memdev,
struct dasd_diag_req *dreq;
struct dasd_diag_bio *dbio;
struct req_iterator iter;
- struct bio_vec *bv;
+ struct bio_vec bv;
char *dst;
unsigned int count, datasize;
sector_t recid, first_rec, last_rec;
@@ -505,15 +519,16 @@ static struct dasd_ccw_req *dasd_diag_build_cp(struct dasd_device *memdev,
return ERR_PTR(-EINVAL);
blksize = block->bp_block;
/* Calculate record id of first and last block. */
- first_rec = req->sector >> block->s2b_shift;
- last_rec = (req->sector + req->nr_sectors - 1) >> block->s2b_shift;
+ first_rec = blk_rq_pos(req) >> block->s2b_shift;
+ last_rec =
+ (blk_rq_pos(req) + blk_rq_sectors(req) - 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))
+ if (bv.bv_len & (blksize - 1))
/* Fba can only do full blocks. */
return ERR_PTR(-EINVAL);
- count += bv->bv_len >> (block->s2b_shift + 9);
+ count += bv.bv_len >> (block->s2b_shift + 9);
}
/* Paranoia. */
if (count != last_rec - first_rec + 1)
@@ -521,8 +536,7 @@ static struct dasd_ccw_req *dasd_diag_build_cp(struct dasd_device *memdev,
/* Build the request */
datasize = sizeof(struct dasd_diag_req) +
count*sizeof(struct dasd_diag_bio);
- cqr = dasd_smalloc_request(dasd_diag_discipline.name, 0,
- datasize, memdev);
+ cqr = dasd_smalloc_request(DASD_DIAG_MAGIC, 0, datasize, memdev);
if (IS_ERR(cqr))
return cqr;
@@ -531,8 +545,8 @@ static struct dasd_ccw_req *dasd_diag_build_cp(struct dasd_device *memdev,
dbio = dreq->bio;
recid = first_rec;
rq_for_each_segment(bv, req, iter) {
- dst = page_address(bv->bv_page) + bv->bv_offset;
- for (off = 0; off < bv->bv_len; off += blksize) {
+ dst = page_address(bv.bv_page) + bv.bv_offset;
+ for (off = 0; off < bv.bv_len; off += blksize) {
memset(dbio, 0, sizeof (struct dasd_diag_bio));
dbio->type = rw_cmd;
dbio->block_number = recid + 1;
@@ -542,15 +556,15 @@ static struct dasd_ccw_req *dasd_diag_build_cp(struct dasd_device *memdev,
recid++;
}
}
- cqr->retries = DIAG_MAX_RETRIES;
- cqr->buildclk = get_clock();
+ cqr->retries = memdev->default_retries;
+ cqr->buildclk = get_tod_clock();
if (blk_noretry_request(req) ||
block->base->features & DASD_FEATURE_FAILFAST)
set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
cqr->startdev = memdev;
cqr->memdev = memdev;
cqr->block = block;
- cqr->expires = DIAG_TIMEOUT;
+ cqr->expires = memdev->default_expires * HZ;
cqr->status = DASD_CQR_FILLED;
return cqr;
}
@@ -569,7 +583,10 @@ dasd_diag_free_cp(struct dasd_ccw_req *cqr, struct request *req)
static void dasd_diag_handle_terminated_request(struct dasd_ccw_req *cqr)
{
- cqr->status = DASD_CQR_FILLED;
+ if (cqr->retries < 0)
+ cqr->status = DASD_CQR_FAILED;
+ else
+ cqr->status = DASD_CQR_FILLED;
};
/* Fill in IOCTL data for device. */
@@ -605,6 +622,7 @@ static struct dasd_discipline dasd_diag_discipline = {
.ebcname = "DIAG",
.max_blocks = DIAG_MAX_BLOCKS,
.check_device = dasd_diag_check_device,
+ .verify_path = dasd_generic_verify_path,
.fill_geometry = dasd_diag_fill_geometry,
.start_IO = dasd_start_diag,
.term_IO = dasd_diag_term_IO,
@@ -627,8 +645,8 @@ dasd_diag_init(void)
}
ASCEBC(dasd_diag_discipline.ebcname, 4);
- ctl_set_bit(0, 9);
- register_external_interrupt(0x2603, dasd_ext_handler);
+ irq_subclass_register(IRQ_SUBCLASS_SERVICE_SIGNAL);
+ register_external_irq(EXT_IRQ_CP_SERVICE, dasd_ext_handler);
dasd_diag_discipline_pointer = &dasd_diag_discipline;
return 0;
}
@@ -636,8 +654,8 @@ dasd_diag_init(void)
static void __exit
dasd_diag_cleanup(void)
{
- unregister_external_interrupt(0x2603, dasd_ext_handler);
- ctl_clear_bit(0, 9);
+ unregister_external_irq(EXT_IRQ_CP_SERVICE, dasd_ext_handler);
+ irq_subclass_unregister(IRQ_SUBCLASS_SERVICE_SIGNAL);
dasd_diag_discipline_pointer = NULL;
}