diff options
Diffstat (limited to 'drivers/s390/block/dasd_diag.c')
| -rw-r--r-- | drivers/s390/block/dasd_diag.c | 124 |
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; } |
