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

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

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;
L
Linus Torvalds 已提交
53 54 55
};

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

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

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

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

	iib->dev_nr = _ccw_device_get_device_number(device->cdev);
	iib->block_size = blocksize;
	iib->offset = offset;
108
	iib->flaga = DASD_DIAG_FLAGA_DEFAULT;
L
Linus Torvalds 已提交
109 110 111

	rc = dia250(iib, INIT_BIO);

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

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

118 119
/* Remove block I/O environment for device. Return zero on success, non-zero
 * otherwise. */
L
Linus Torvalds 已提交
120 121 122 123 124 125 126 127 128 129 130 131
static __inline__ int
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));
	iib->dev_nr = _ccw_device_get_device_number(device->cdev);
	rc = dia250(iib, TERM_BIO);
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
	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 已提交
147 148
}

149 150
/* Start a given request at the device. Return zero on success, non-zero
 * otherwise. */
L
Linus Torvalds 已提交
151 152 153 154 155 156 157 158 159
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;
160 161 162 163 164 165
	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 已提交
166 167 168 169 170
	private = (struct dasd_diag_private *) device->private;
	dreq = (struct dasd_diag_req *) cqr->data;

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

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

	rc = dia250(&private->iob, RW_BIO);
182 183 184
	switch (rc) {
	case 0: /* Synchronous I/O finished successfully */
		cqr->stopclk = get_clock();
L
Linus Torvalds 已提交
185
		cqr->status = DASD_CQR_DONE;
186 187 188 189 190
		/* 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 已提交
191 192
		cqr->status = DASD_CQR_IN_IO;
		rc = 0;
193 194 195 196 197 198 199
		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 已提交
200 201 202 203
	}
	return rc;
}

204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
/* 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 已提交
220 221 222 223 224 225 226
static void
dasd_ext_handler(struct pt_regs *regs, __u16 code)
{
	struct dasd_ccw_req *cqr, *next;
	struct dasd_device *device;
	unsigned long long expires;
	unsigned long flags;
227 228 229
	u8 int_code, status;
	addr_t ip;
	int rc;
L
Linus Torvalds 已提交
230

231 232 233 234 235 236 237 238 239 240 241 242
	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 已提交
243 244 245 246
	if (!ip) {		/* no intparm: unsolicited interrupt */
		MESSAGE(KERN_DEBUG, "%s", "caught unsolicited interrupt");
		return;
	}
247
	cqr = (struct dasd_ccw_req *) ip;
L
Linus Torvalds 已提交
248 249 250 251 252 253 254 255 256 257 258 259
	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);

260 261 262 263 264 265 266 267 268
	/* 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 已提交
269 270 271 272 273 274 275 276 277 278
	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) {
279 280
				rc = dasd_start_diag(next);
				if (rc == 0)
L
Linus Torvalds 已提交
281
					expires = next->expires;
282
				else if (rc != -EACCES)
L
Linus Torvalds 已提交
283 284 285 286 287
					DEV_MESSAGE(KERN_WARNING, device, "%s",
						    "Interrupt fastpath "
						    "failed!");
			}
		}
288 289 290 291 292 293 294
	} 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 已提交
295 296 297 298 299 300 301 302 303 304

	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);
}

305 306
/* Check whether device can be controlled by DIAG discipline. Return zero on
 * success, non-zero otherwise. */
L
Linus Torvalds 已提交
307 308 309 310 311 312
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;
313
	struct vtoc_cms_label *label;
314 315
	blocknum_t end_block;
	unsigned int sb, bsize;
L
Linus Torvalds 已提交
316 317 318 319
	int rc;

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

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

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

433 434
/* Fill in virtual disk geometry for device. Return zero on success, non-zero
 * otherwise. */
L
Linus Torvalds 已提交
435 436 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
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;
}

464 465
/* Create DASD request from block device request. Return pointer to new
 * request on success, ERR_PTR otherwise. */
L
Linus Torvalds 已提交
466 467 468 469 470 471 472 473 474
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;
475
	unsigned int count, datasize;
L
Linus Torvalds 已提交
476
	sector_t recid, first_rec, last_rec;
477
	unsigned int blksize, off;
L
Linus Torvalds 已提交
478 479 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
	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;
511

L
Linus Torvalds 已提交
512 513 514 515 516 517 518 519 520 521 522
	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;
523
				dbio->buffer = dst;
L
Linus Torvalds 已提交
524 525 526 527 528 529
				dbio++;
				dst += blksize;
				recid++;
			}
		}
	}
530
	cqr->retries = DIAG_MAX_RETRIES;
L
Linus Torvalds 已提交
531
	cqr->buildclk = get_clock();
532 533
	if (req->flags & REQ_FAILFAST)
		set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
L
Linus Torvalds 已提交
534
	cqr->device = device;
535
	cqr->expires = DIAG_TIMEOUT;
L
Linus Torvalds 已提交
536 537 538 539
	cqr->status = DASD_CQR_FILLED;
	return cqr;
}

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

552
/* Fill in IOCTL data for device. */
L
Linus Torvalds 已提交
553 554 555 556 557 558 559
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;
560
	info->label_block = (unsigned int) private->pt_block;
L
Linus Torvalds 已提交
561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582
	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");
}

struct dasd_discipline dasd_diag_discipline = {
	.owner = THIS_MODULE,
	.name = "DIAG",
	.ebcname = "DIAG",
583
	.max_blocks = DIAG_MAX_BLOCKS,
L
Linus Torvalds 已提交
584 585 586
	.check_device = dasd_diag_check_device,
	.fill_geometry = dasd_diag_fill_geometry,
	.start_IO = dasd_start_diag,
587
	.term_IO = dasd_diag_term_IO,
L
Linus Torvalds 已提交
588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604
	.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);
605
		return -ENODEV;
L
Linus Torvalds 已提交
606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624
	}
	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);