dasd_diag.c 16.8 KB
Newer Older
1
/*
L
Linus Torvalds 已提交
2 3 4 5 6 7 8 9 10 11 12 13
 * 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
 *
 */

#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/slab.h>
14
#include <linux/hdreg.h>
L
Linus Torvalds 已提交
15 16 17
#include <linux/bio.h>
#include <linux/module.h>
#include <linux/init.h>
18
#include <linux/jiffies.h>
L
Linus Torvalds 已提交
19 20 21 22 23 24 25

#include <asm/dasd.h>
#include <asm/debug.h>
#include <asm/ebcdic.h>
#include <asm/io.h>
#include <asm/s390_ext.h>
#include <asm/todclk.h>
26
#include <asm/vtoc.h>
L
Linus Torvalds 已提交
27 28 29 30 31 32 33 34

#include "dasd_int.h"
#include "dasd_diag.h"

#define PRINTK_HEADER "dasd(diag):"

MODULE_LICENSE("GPL");

35 36 37 38 39 40 41 42 43 44 45
/* 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 * HZ

46
static struct dasd_discipline dasd_diag_discipline;
L
Linus Torvalds 已提交
47 48 49 50 51

struct dasd_diag_private {
	struct dasd_diag_characteristics rdc_data;
	struct dasd_diag_rw_io iob;
	struct dasd_diag_init_io iib;
52
	blocknum_t pt_block;
53
	struct ccw_dev_id dev_id;
L
Linus Torvalds 已提交
54 55 56
};

struct dasd_diag_req {
57
	unsigned int block_count;
L
Linus Torvalds 已提交
58 59 60
	struct dasd_diag_bio bio[0];
};

61 62 63 64 65 66
static const u8 DASD_DIAG_CMS1[] = { 0xc3, 0xd4, 0xe2, 0xf1 };/* EBCDIC CMS1 */

/* 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. */
67
static inline int dia250(void *iob, int cmd)
L
Linus Torvalds 已提交
68
{
69
	register unsigned long reg2 asm ("2") = (unsigned long) iob;
70 71 72
	typedef union {
		struct dasd_diag_init_io init_io;
		struct dasd_diag_rw_io rw_io;
73
	} addr_type;
L
Linus Torvalds 已提交
74 75
	int rc;

76 77
	rc = 3;
	asm volatile(
78
		"	diag	2,%2,0x250\n"
79 80
		"0:	ipm	%0\n"
		"	srl	%0,28\n"
81
		"	or	%0,3\n"
82
		"1:\n"
83 84
		EX_TABLE(0b,1b)
		: "+d" (rc), "=m" (*(addr_type *) iob)
85 86
		: "d" (cmd), "d" (reg2), "m" (*(addr_type *) iob)
		: "3", "cc");
L
Linus Torvalds 已提交
87 88 89
	return rc;
}

90 91 92 93
/* 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. */
94
static inline int
95 96
mdsk_init_io(struct dasd_device *device, unsigned int blocksize,
	     blocknum_t offset, blocknum_t *end_block)
L
Linus Torvalds 已提交
97 98 99 100 101 102 103 104 105
{
	struct dasd_diag_private *private;
	struct dasd_diag_init_io *iib;
	int rc;

	private = (struct dasd_diag_private *) device->private;
	iib = &private->iib;
	memset(iib, 0, sizeof (struct dasd_diag_init_io));

106
	iib->dev_nr = private->dev_id.devno;
L
Linus Torvalds 已提交
107 108
	iib->block_size = blocksize;
	iib->offset = offset;
109
	iib->flaga = DASD_DIAG_FLAGA_DEFAULT;
L
Linus Torvalds 已提交
110 111 112

	rc = dia250(iib, INIT_BIO);

113 114 115 116
	if ((rc & 3) == 0 && end_block)
		*end_block = iib->end_block;

	return rc;
L
Linus Torvalds 已提交
117 118
}

119 120
/* Remove block I/O environment for device. Return zero on success, non-zero
 * otherwise. */
121
static inline int
L
Linus Torvalds 已提交
122 123 124 125 126 127 128 129 130
mdsk_term_io(struct dasd_device * device)
{
	struct dasd_diag_private *private;
	struct dasd_diag_init_io *iib;
	int rc;

	private = (struct dasd_diag_private *) device->private;
	iib = &private->iib;
	memset(iib, 0, sizeof (struct dasd_diag_init_io));
131
	iib->dev_nr = private->dev_id.devno;
L
Linus Torvalds 已提交
132
	rc = dia250(iib, TERM_BIO);
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
	return rc;
}

/* Error recovery for failed DIAG requests - try to reestablish the DIAG
 * environment. */
static void
dasd_diag_erp(struct dasd_device *device)
{
	int rc;

	mdsk_term_io(device);
	rc = mdsk_init_io(device, device->bp_block, 0, NULL);
	if (rc)
		DEV_MESSAGE(KERN_WARNING, device, "DIAG ERP unsuccessful, "
			    "rc=%d", rc);
L
Linus Torvalds 已提交
148 149
}

150 151
/* Start a given request at the device. Return zero on success, non-zero
 * otherwise. */
L
Linus Torvalds 已提交
152 153 154 155 156 157 158 159 160
static int
dasd_start_diag(struct dasd_ccw_req * cqr)
{
	struct dasd_device *device;
	struct dasd_diag_private *private;
	struct dasd_diag_req *dreq;
	int rc;

	device = cqr->device;
161 162 163 164 165 166
	if (cqr->retries < 0) {
		DEV_MESSAGE(KERN_WARNING, device, "DIAG start_IO: request %p "
			    "- no retry left)", cqr);
		cqr->status = DASD_CQR_FAILED;
		return -EIO;
	}
L
Linus Torvalds 已提交
167 168 169
	private = (struct dasd_diag_private *) device->private;
	dreq = (struct dasd_diag_req *) cqr->data;

170
	private->iob.dev_nr = private->dev_id.devno;
L
Linus Torvalds 已提交
171
	private->iob.key = 0;
172
	private->iob.flags = DASD_DIAG_RWFLAG_ASYNC;
L
Linus Torvalds 已提交
173
	private->iob.block_count = dreq->block_count;
174
	private->iob.interrupt_params = (addr_t) cqr;
175
	private->iob.bio_list = dreq->bio;
176
	private->iob.flaga = DASD_DIAG_FLAGA_DEFAULT;
L
Linus Torvalds 已提交
177 178

	cqr->startclk = get_clock();
179 180
	cqr->starttime = jiffies;
	cqr->retries--;
L
Linus Torvalds 已提交
181 182

	rc = dia250(&private->iob, RW_BIO);
183 184 185
	switch (rc) {
	case 0: /* Synchronous I/O finished successfully */
		cqr->stopclk = get_clock();
L
Linus Torvalds 已提交
186
		cqr->status = DASD_CQR_DONE;
187 188 189 190 191
		/* Indicate to calling function that only a dasd_schedule_bh()
		   and no timer is needed */
                rc = -EACCES;
		break;
	case 8: /* Asynchronous I/O was started */
L
Linus Torvalds 已提交
192 193
		cqr->status = DASD_CQR_IN_IO;
		rc = 0;
194 195 196 197 198 199 200
		break;
	default: /* Error condition */
		cqr->status = DASD_CQR_QUEUED;
		DEV_MESSAGE(KERN_WARNING, device, "dia250 returned rc=%d", rc);
		dasd_diag_erp(device);
		rc = -EIO;
		break;
L
Linus Torvalds 已提交
201 202 203 204
	}
	return rc;
}

205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
/* Terminate given request at the device. */
static int
dasd_diag_term_IO(struct dasd_ccw_req * cqr)
{
	struct dasd_device *device;

	device = cqr->device;
	mdsk_term_io(device);
	mdsk_init_io(device, device->bp_block, 0, NULL);
	cqr->status = DASD_CQR_CLEAR;
	cqr->stopclk = get_clock();
	dasd_schedule_bh(device);
	return 0;
}

/* Handle external interruption. */
L
Linus Torvalds 已提交
221
static void
H
Heiko Carstens 已提交
222
dasd_ext_handler(__u16 code)
L
Linus Torvalds 已提交
223 224 225 226 227
{
	struct dasd_ccw_req *cqr, *next;
	struct dasd_device *device;
	unsigned long long expires;
	unsigned long flags;
228 229 230
	u8 int_code, status;
	addr_t ip;
	int rc;
L
Linus Torvalds 已提交
231

232 233 234 235 236 237 238 239 240 241 242 243
	int_code = *((u8 *) DASD_DIAG_LC_INT_CODE);
	status = *((u8 *) DASD_DIAG_LC_INT_STATUS);
	switch (int_code) {
	case DASD_DIAG_CODE_31BIT:
		ip = (addr_t) *((u32 *) DASD_DIAG_LC_INT_PARM_31BIT);
		break;
	case DASD_DIAG_CODE_64BIT:
		ip = (addr_t) *((u64 *) DASD_DIAG_LC_INT_PARM_64BIT);
		break;
	default:
		return;
	}
L
Linus Torvalds 已提交
244 245 246 247
	if (!ip) {		/* no intparm: unsolicited interrupt */
		MESSAGE(KERN_DEBUG, "%s", "caught unsolicited interrupt");
		return;
	}
248
	cqr = (struct dasd_ccw_req *) ip;
L
Linus Torvalds 已提交
249 250 251 252 253 254 255 256 257 258 259 260
	device = (struct dasd_device *) cqr->device;
	if (strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
		DEV_MESSAGE(KERN_WARNING, device,
			    " magic number of dasd_ccw_req 0x%08X doesn't"
			    " match discipline 0x%08X",
			    cqr->magic, *(int *) (&device->discipline->name));
		return;
	}

	/* get irq lock to modify request queue */
	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);

261 262 263 264 265 266 267 268 269
	/* 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);
		spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
		return;
	}

L
Linus Torvalds 已提交
270 271 272 273 274 275 276 277 278 279
	cqr->stopclk = get_clock();

	expires = 0;
	if (status == 0) {
		cqr->status = DASD_CQR_DONE;
		/* 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);
			if (next->status == DASD_CQR_QUEUED) {
280 281
				rc = dasd_start_diag(next);
				if (rc == 0)
L
Linus Torvalds 已提交
282
					expires = next->expires;
283
				else if (rc != -EACCES)
L
Linus Torvalds 已提交
284 285 286 287 288
					DEV_MESSAGE(KERN_WARNING, device, "%s",
						    "Interrupt fastpath "
						    "failed!");
			}
		}
289 290 291 292 293 294 295
	} else {
		cqr->status = DASD_CQR_QUEUED;
		DEV_MESSAGE(KERN_WARNING, device, "interrupt status for "
			    "request %p was %d (%d retries left)", cqr, status,
			    cqr->retries);
		dasd_diag_erp(device);
	}
L
Linus Torvalds 已提交
296 297 298 299 300 301 302 303 304 305

	if (expires != 0)
		dasd_set_timer(device, expires);
	else
		dasd_clear_timer(device);
	dasd_schedule_bh(device);

	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
}

306 307
/* Check whether device can be controlled by DIAG discipline. Return zero on
 * success, non-zero otherwise. */
L
Linus Torvalds 已提交
308 309 310 311 312 313
static int
dasd_diag_check_device(struct dasd_device *device)
{
	struct dasd_diag_private *private;
	struct dasd_diag_characteristics *rdc_data;
	struct dasd_diag_bio bio;
314
	struct vtoc_cms_label *label;
315 316
	blocknum_t end_block;
	unsigned int sb, bsize;
L
Linus Torvalds 已提交
317 318 319 320
	int rc;

	private = (struct dasd_diag_private *) device->private;
	if (private == NULL) {
321
		private = kzalloc(sizeof(struct dasd_diag_private),GFP_KERNEL);
L
Linus Torvalds 已提交
322 323 324 325 326
		if (private == NULL) {
			DEV_MESSAGE(KERN_WARNING, device, "%s",
				"memory allocation failed for private data");
			return -ENOMEM;
		}
327
		ccw_device_get_id(device->cdev, &private->dev_id);
L
Linus Torvalds 已提交
328 329 330 331
		device->private = (void *) private;
	}
	/* Read Device Characteristics */
	rdc_data = (void *) &(private->rdc_data);
332
	rdc_data->dev_nr = private->dev_id.devno;
L
Linus Torvalds 已提交
333 334 335
	rdc_data->rdc_len = sizeof (struct dasd_diag_characteristics);

	rc = diag210((struct diag210 *) rdc_data);
336 337 338
	if (rc) {
		DEV_MESSAGE(KERN_WARNING, device, "failed to retrieve device "
			    "information (rc=%d)", rc);
L
Linus Torvalds 已提交
339
		return -ENOTSUPP;
340
	}
L
Linus Torvalds 已提交
341 342 343 344 345 346 347 348 349 350

	/* 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:
351 352
		DEV_MESSAGE(KERN_WARNING, device, "unsupported device class "
			    "(class=%d)", private->rdc_data.vdev_class);
L
Linus Torvalds 已提交
353 354 355 356 357 358 359 360 361 362 363 364 365
		return -ENOTSUPP;
	}

	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 */
366
	label = (struct vtoc_cms_label *) get_zeroed_page(GFP_KERNEL);
L
Linus Torvalds 已提交
367 368 369 370 371
	if (label == NULL)  {
		DEV_MESSAGE(KERN_WARNING, device, "%s",
			    "No memory to allocate initialization request");
		return -ENOMEM;
	}
372 373
	rc = 0;
	end_block = 0;
L
Linus Torvalds 已提交
374 375
	/* try all sizes - needed for ECKD devices */
	for (bsize = 512; bsize <= PAGE_SIZE; bsize <<= 1) {
376
		mdsk_init_io(device, bsize, 0, &end_block);
L
Linus Torvalds 已提交
377 378 379
		memset(&bio, 0, sizeof (struct dasd_diag_bio));
		bio.type = MDSK_READ_REQ;
		bio.block_number = private->pt_block + 1;
380
		bio.buffer = label;
L
Linus Torvalds 已提交
381 382 383 384 385 386
		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;
387
		private->iob.bio_list = &bio;
388 389
		private->iob.flaga = DASD_DIAG_FLAGA_DEFAULT;
		rc = dia250(&private->iob, RW_BIO);
390 391 392 393 394 395
		if (rc == 3) {
			DEV_MESSAGE(KERN_WARNING, device, "%s",
				"DIAG call failed");
			rc = -EOPNOTSUPP;
			goto out;
		}
L
Linus Torvalds 已提交
396
		mdsk_term_io(device);
397 398
		if (rc == 0)
			break;
L
Linus Torvalds 已提交
399
	}
400
	if (bsize > PAGE_SIZE) {
401 402 403
		DEV_MESSAGE(KERN_WARNING, device, "device access failed "
			    "(rc=%d)", rc);
		rc = -EIO;
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422
		goto out;
	}
	/* check for label block */
	if (memcmp(label->label_id, DASD_DIAG_CMS1,
		  sizeof(DASD_DIAG_CMS1)) == 0) {
		/* get formatted blocksize from label block */
		bsize = (unsigned int) label->block_size;
		device->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 */
	for (sb = 512; sb < bsize; sb = sb << 1)
		device->s2b_shift++;
	rc = mdsk_init_io(device, device->bp_block, 0, NULL);
	if (rc) {
		DEV_MESSAGE(KERN_WARNING, device, "DIAG initialization "
			"failed (rc=%d)", rc);
		rc = -EIO;
423
	} else {
L
Linus Torvalds 已提交
424
		DEV_MESSAGE(KERN_INFO, device,
425 426 427 428
			    "(%ld B/blk): %ldkB",
			    (unsigned long) device->bp_block,
			    (unsigned long) (device->blocks <<
				device->s2b_shift) >> 1);
L
Linus Torvalds 已提交
429
	}
430
out:
L
Linus Torvalds 已提交
431 432 433 434
	free_page((long) label);
	return rc;
}

435 436
/* Fill in virtual disk geometry for device. Return zero on success, non-zero
 * otherwise. */
L
Linus Torvalds 已提交
437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465
static int
dasd_diag_fill_geometry(struct dasd_device *device, struct hd_geometry *geo)
{
	if (dasd_check_blocksize(device->bp_block) != 0)
		return -EINVAL;
	geo->cylinders = (device->blocks << device->s2b_shift) >> 10;
	geo->heads = 16;
	geo->sectors = 128 >> device->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)
{
	return dasd_default_erp_action;
}

static dasd_erp_fn_t
dasd_diag_erp_postaction(struct dasd_ccw_req * cqr)
{
	return dasd_default_erp_postaction;
}

466 467
/* Create DASD request from block device request. Return pointer to new
 * request on success, ERR_PTR otherwise. */
L
Linus Torvalds 已提交
468 469 470 471 472 473 474 475 476
static struct dasd_ccw_req *
dasd_diag_build_cp(struct dasd_device * device, struct request *req)
{
	struct dasd_ccw_req *cqr;
	struct dasd_diag_req *dreq;
	struct dasd_diag_bio *dbio;
	struct bio *bio;
	struct bio_vec *bv;
	char *dst;
477
	unsigned int count, datasize;
L
Linus Torvalds 已提交
478
	sector_t recid, first_rec, last_rec;
479
	unsigned int blksize, off;
L
Linus Torvalds 已提交
480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512
	unsigned char rw_cmd;
	int i;

	if (rq_data_dir(req) == READ)
		rw_cmd = MDSK_READ_REQ;
	else if (rq_data_dir(req) == WRITE)
		rw_cmd = MDSK_WRITE_REQ;
	else
		return ERR_PTR(-EINVAL);
	blksize = device->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;
	/* Check struct bio and count the number of blocks for the request. */
	count = 0;
	rq_for_each_bio(bio, req) {
		bio_for_each_segment(bv, bio, i) {
			if (bv->bv_len & (blksize - 1))
				/* Fba can only do full blocks. */
				return ERR_PTR(-EINVAL);
			count += bv->bv_len >> (device->s2b_shift + 9);
		}
	}
	/* Paranoia. */
	if (count != last_rec - first_rec + 1)
		return ERR_PTR(-EINVAL);
	/* 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, device);
	if (IS_ERR(cqr))
		return cqr;
513

L
Linus Torvalds 已提交
514 515 516 517 518 519 520 521 522 523 524
	dreq = (struct dasd_diag_req *) cqr->data;
	dreq->block_count = count;
	dbio = dreq->bio;
	recid = first_rec;
	rq_for_each_bio(bio, req) {
		bio_for_each_segment(bv, bio, i) {
			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;
525
				dbio->buffer = dst;
L
Linus Torvalds 已提交
526 527 528 529 530 531
				dbio++;
				dst += blksize;
				recid++;
			}
		}
	}
532
	cqr->retries = DIAG_MAX_RETRIES;
L
Linus Torvalds 已提交
533
	cqr->buildclk = get_clock();
534
	if (req->cmd_flags & REQ_FAILFAST)
535
		set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
L
Linus Torvalds 已提交
536
	cqr->device = device;
537
	cqr->expires = DIAG_TIMEOUT;
L
Linus Torvalds 已提交
538 539 540 541
	cqr->status = DASD_CQR_FILLED;
	return cqr;
}

542 543
/* Release DASD request. Return non-zero if request was successful, zero
 * otherwise. */
L
Linus Torvalds 已提交
544 545 546 547 548 549 550 551 552 553
static int
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);
	return status;
}

554
/* Fill in IOCTL data for device. */
L
Linus Torvalds 已提交
555 556 557 558 559 560 561
static int
dasd_diag_fill_info(struct dasd_device * device,
		    struct dasd_information2_t * info)
{
	struct dasd_diag_private *private;

	private = (struct dasd_diag_private *) device->private;
562
	info->label_block = (unsigned int) private->pt_block;
L
Linus Torvalds 已提交
563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580
	info->FBA_layout = 1;
	info->format = DASD_FORMAT_LDL;
	info->characteristics_size = sizeof (struct dasd_diag_characteristics);
	memcpy(info->characteristics,
	       &((struct dasd_diag_private *) device->private)->rdc_data,
	       sizeof (struct dasd_diag_characteristics));
	info->confdata_size = 0;
	return 0;
}

static void
dasd_diag_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
		     struct irb *stat)
{
	DEV_MESSAGE(KERN_ERR, device, "%s",
		    "dump sense not available for DIAG data");
}

581
static struct dasd_discipline dasd_diag_discipline = {
L
Linus Torvalds 已提交
582 583 584
	.owner = THIS_MODULE,
	.name = "DIAG",
	.ebcname = "DIAG",
585
	.max_blocks = DIAG_MAX_BLOCKS,
L
Linus Torvalds 已提交
586 587 588
	.check_device = dasd_diag_check_device,
	.fill_geometry = dasd_diag_fill_geometry,
	.start_IO = dasd_start_diag,
589
	.term_IO = dasd_diag_term_IO,
L
Linus Torvalds 已提交
590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606
	.examine_error = dasd_diag_examine_error,
	.erp_action = dasd_diag_erp_action,
	.erp_postaction = dasd_diag_erp_postaction,
	.build_cp = dasd_diag_build_cp,
	.free_cp = dasd_diag_free_cp,
	.dump_sense = dasd_diag_dump_sense,
	.fill_info = dasd_diag_fill_info,
};

static int __init
dasd_diag_init(void)
{
	if (!MACHINE_IS_VM) {
		MESSAGE_LOG(KERN_INFO,
			    "Machine is not VM: %s "
			    "discipline not initializing",
			    dasd_diag_discipline.name);
607
		return -ENODEV;
L
Linus Torvalds 已提交
608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626
	}
	ASCEBC(dasd_diag_discipline.ebcname, 4);

	ctl_set_bit(0, 9);
	register_external_interrupt(0x2603, dasd_ext_handler);
	dasd_diag_discipline_pointer = &dasd_diag_discipline;
	return 0;
}

static void __exit
dasd_diag_cleanup(void)
{
	unregister_external_interrupt(0x2603, dasd_ext_handler);
	ctl_clear_bit(0, 9);
	dasd_diag_discipline_pointer = NULL;
}

module_init(dasd_diag_init);
module_exit(dasd_diag_cleanup);