MODULE_DESCRIPTION("S/390 Support for DIAG access to DASD Disks");
MODULE_LICENSE("GPL");
/* The maximum number of blocks per request (max_blocks) is dependent on the * amount of storage that is available in the static I/O buffer for each * device. Currently each device gets 2 pages. We want to fit two requests * into the available memory so that we can immediately start the next if one
* finishes. */ #define DIAG_MAX_BLOCKS (((2 * PAGE_SIZE - sizeof(struct dasd_ccw_req) - \ sizeof(struct dasd_diag_req)) / \ sizeof(struct dasd_diag_bio)) / 2) #define DIAG_MAX_RETRIES 32 #define DIAG_TIMEOUT 50
/* Perform DIAG250 call with block I/O parameter list iob (input and output) * and function code cmd. * In case of an exception return 3. Otherwise return result of bitwise OR of
* resulting condition code and DIAG return code. */ staticinlineint __dia250(void *iob, int cmd)
{ union register_pair rx = { .even = (unsignedlong)iob, }; int cc, exception; typedefunion { struct dasd_diag_init_io init_io; struct dasd_diag_rw_io rw_io;
} addr_type;
/* Initialize block I/O to DIAG device using the specified blocksize and * block offset. On success, return zero and set end_block to contain the * number of blocks on the device minus the specified offset. Return non-zero
* otherwise. */ staticinlineint
mdsk_init_io(struct dasd_device *device, unsignedint blocksize,
blocknum_t offset, blocknum_t *end_block)
{ struct dasd_diag_private *private = device->private; struct dasd_diag_init_io *iib = &private->iib; int rc;
/* Error recovery for failed DIAG requests - try to reestablish the DIAG
* environment. */ staticvoid
dasd_diag_erp(struct dasd_device *device)
{ int rc;
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_warn("%s: The access mode of a DIAG device changed to read-only\n",
dev_name(&device->cdev->dev));
rc = 0;
} if (rc)
pr_warn("%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
* otherwise. */ staticint
dasd_start_diag(struct dasd_ccw_req * cqr)
{ struct dasd_device *device; struct dasd_diag_private *private; struct dasd_diag_req *dreq; int rc;
/* Figure out position of label block */ switch (private->rdc_data.vdev_class) { case DEV_CLASS_FBA:
private->pt_block = 1; break; case DEV_CLASS_ECKD:
private->pt_block = 2; break; default:
pr_warn("%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;
}
DBF_DEV_EVENT(DBF_INFO, device, "%04X: %04X on real %04X/%02X",
rdc_data->dev_nr,
rdc_data->vdev_type,
rdc_data->rdev_type, rdc_data->rdev_model);
/* terminate all outstanding operations */
mdsk_term_io(device);
/* figure out blocksize of device */
label = (struct vtoc_cms_label *) get_zeroed_page(GFP_KERNEL); if (label == NULL) {
DBF_DEV_EVENT(DBF_WARNING, device, "%s", "No memory to allocate initialization request");
rc = -ENOMEM; goto out;
}
bio = kzalloc(sizeof(*bio), GFP_KERNEL); if (bio == NULL) {
DBF_DEV_EVENT(DBF_WARNING, device, "%s", "No memory to allocate initialization bio");
rc = -ENOMEM; goto out_label;
}
rc = 0;
end_block = 0; /* try all sizes - needed for ECKD devices */ for (bsize = 512; bsize <= PAGE_SIZE; bsize <<= 1) {
mdsk_init_io(device, bsize, 0, &end_block);
memset(bio, 0, sizeof(*bio));
bio->type = MDSK_READ_REQ;
bio->block_number = private->pt_block + 1;
bio->buffer = label;
memset(&private->iob, 0, sizeof (struct dasd_diag_rw_io));
private->iob.dev_nr = rdc_data->dev_nr;
private->iob.key = 0;
private->iob.flags = 0; /* do synchronous io */
private->iob.block_count = 1;
private->iob.interrupt_params = 0;
private->iob.bio_list = bio;
private->iob.flaga = DASD_DIAG_FLAGA_DEFAULT;
rc = dia250(&private->iob, RW_BIO); if (rc == 3) {
pr_warn("%s: A 64-bit DIAG call failed\n",
dev_name(&device->cdev->dev));
rc = -EOPNOTSUPP; goto out_bio;
}
mdsk_term_io(device); if (rc == 0) break;
} if (bsize > PAGE_SIZE) {
pr_warn("%s: Accessing the DASD failed because of an incorrect format (rc=%d)\n",
dev_name(&device->cdev->dev), rc);
rc = -EIO; goto out_bio;
} /* check for label block */ if (memcmp(label->label_id, DASD_DIAG_CMS1, sizeof(DASD_DIAG_CMS1)) == 0) { /* get formatted blocksize from label block */
bsize = (unsignedint) label->block_size;
block->blocks = (unsignedlong) label->block_count;
} else
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)
block->s2b_shift++;
rc = mdsk_init_io(device, block->bp_block, 0, NULL); if (rc && (rc != 4)) {
pr_warn("%s: DIAG initialization failed with rc=%d\n",
dev_name(&device->cdev->dev), rc);
rc = -EIO;
} else { 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),
(unsignedlong) block->bp_block,
(unsignedlong) (block->blocks <<
block->s2b_shift) >> 1,
(rc == 4) ? ", read-only device" : "");
rc = 0;
}
out_bio:
kfree(bio);
out_label:
free_page((long) label);
out: if (rc) {
device->block = NULL;
dasd_free_block(block);
device->private = NULL;
kfree(private);
} return rc;
}
/* Fill in virtual disk geometry for device. Return zero on success, non-zero
* otherwise. */ staticint
dasd_diag_fill_geometry(struct dasd_block *block, struct hd_geometry *geo)
{ if (dasd_check_blocksize(block->bp_block) != 0) return -EINVAL;
geo->cylinders = (block->blocks << block->s2b_shift) >> 10;
geo->heads = 16;
geo->sectors = 128 >> block->s2b_shift; return 0;
}
staticint __init
dasd_diag_init(void)
{ if (!machine_is_vm()) {
pr_info("Discipline %s cannot be used without z/VM\n",
dasd_diag_discipline.name); return -ENODEV;
}
ASCEBC(dasd_diag_discipline.ebcname, 4);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.