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

#include <linux/config.h>
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/slab.h>
16
#include <linux/hdreg.h>
L
Linus Torvalds 已提交
17 18 19
#include <linux/bio.h>
#include <linux/module.h>
#include <linux/init.h>
20
#include <linux/jiffies.h>
L
Linus Torvalds 已提交
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35

#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>

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

#define PRINTK_HEADER "dasd(diag):"

MODULE_LICENSE("GPL");

36 37 38 39 40 41 42 43 44 45 46
/* 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 已提交
47 48 49 50 51 52
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;
53
	blocknum_t pt_block;
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. */
L
Linus Torvalds 已提交
67 68 69
static __inline__ int
dia250(void *iob, int cmd)
{
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 78 79 80 81 82 83 84 85 86 87 88
	__asm__ __volatile__(
#ifdef CONFIG_ARCH_S390X
		"	lghi	%0,3\n"
		"	lgr	0,%3\n"
		"	diag	0,%2,0x250\n"
		"0:	ipm	%0\n"
		"	srl	%0,28\n"
		"	or	%0,1\n"
		"1:\n"
		".section __ex_table,\"a\"\n"
		"	.align 8\n"
		"	.quad  0b,1b\n"
		".previous\n"
L
Linus Torvalds 已提交
89
#else
90 91 92 93 94 95 96 97 98 99 100
		"	lhi	%0,3\n"
		"	lr	0,%3\n"
		"	diag	0,%2,0x250\n"
		"0:	ipm	%0\n"
		"	srl	%0,28\n"
		"	or	%0,1\n"
		"1:\n"
		".section __ex_table,\"a\"\n"
		"	.align 4\n"
		"	.long 0b,1b\n"
		".previous\n"
L
Linus Torvalds 已提交
101
#endif
102 103 104
		: "=&d" (rc), "=m" (*(addr_type *) iob)
		: "d" (cmd), "d" (iob), "m" (*(addr_type *) iob)
		: "0", "1", "cc");
L
Linus Torvalds 已提交
105 106 107
	return rc;
}

108 109 110 111
/* 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 已提交
112
static __inline__ int
113 114
mdsk_init_io(struct dasd_device *device, unsigned int blocksize,
	     blocknum_t offset, blocknum_t *end_block)
L
Linus Torvalds 已提交
115 116 117 118 119 120 121 122 123 124 125 126
{
	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;
127
	iib->flaga = DASD_DIAG_FLAGA_DEFAULT;
L
Linus Torvalds 已提交
128 129 130

	rc = dia250(iib, INIT_BIO);

131 132 133 134
	if ((rc & 3) == 0 && end_block)
		*end_block = iib->end_block;

	return rc;
L
Linus Torvalds 已提交
135 136
}

137 138
/* Remove block I/O environment for device. Return zero on success, non-zero
 * otherwise. */
L
Linus Torvalds 已提交
139 140 141 142 143 144 145 146 147 148 149 150
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);
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
	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 已提交
166 167
}

168 169
/* Start a given request at the device. Return zero on success, non-zero
 * otherwise. */
L
Linus Torvalds 已提交
170 171 172 173 174 175 176 177 178
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;
179 180 181 182 183 184
	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 已提交
185 186 187 188 189
	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;
190
	private->iob.flags = DASD_DIAG_RWFLAG_ASYNC;
L
Linus Torvalds 已提交
191
	private->iob.block_count = dreq->block_count;
192
	private->iob.interrupt_params = (addr_t) cqr;
193
	private->iob.bio_list = dreq->bio;
194
	private->iob.flaga = DASD_DIAG_FLAGA_DEFAULT;
L
Linus Torvalds 已提交
195 196

	cqr->startclk = get_clock();
197 198
	cqr->starttime = jiffies;
	cqr->retries--;
L
Linus Torvalds 已提交
199 200

	rc = dia250(&private->iob, RW_BIO);
201 202 203
	switch (rc) {
	case 0: /* Synchronous I/O finished successfully */
		cqr->stopclk = get_clock();
L
Linus Torvalds 已提交
204
		cqr->status = DASD_CQR_DONE;
205 206 207 208 209
		/* 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 已提交
210 211
		cqr->status = DASD_CQR_IN_IO;
		rc = 0;
212 213 214 215 216 217 218
		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 已提交
219 220 221 222
	}
	return rc;
}

223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
/* 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 已提交
239 240 241 242 243 244 245
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;
246 247 248
	u8 int_code, status;
	addr_t ip;
	int rc;
L
Linus Torvalds 已提交
249

250 251 252 253 254 255 256 257 258 259 260 261
	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 已提交
262 263 264 265
	if (!ip) {		/* no intparm: unsolicited interrupt */
		MESSAGE(KERN_DEBUG, "%s", "caught unsolicited interrupt");
		return;
	}
266
	cqr = (struct dasd_ccw_req *) ip;
L
Linus Torvalds 已提交
267 268 269 270 271 272 273 274 275 276 277 278
	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);

279 280 281 282 283 284 285 286 287
	/* 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 已提交
288 289 290 291 292 293 294 295 296 297
	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) {
298 299
				rc = dasd_start_diag(next);
				if (rc == 0)
L
Linus Torvalds 已提交
300
					expires = next->expires;
301
				else if (rc != -EACCES)
L
Linus Torvalds 已提交
302 303 304 305 306
					DEV_MESSAGE(KERN_WARNING, device, "%s",
						    "Interrupt fastpath "
						    "failed!");
			}
		}
307 308 309 310 311 312 313
	} 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 已提交
314 315 316 317 318 319 320 321 322 323

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

324 325
/* Check whether device can be controlled by DIAG discipline. Return zero on
 * success, non-zero otherwise. */
L
Linus Torvalds 已提交
326 327 328 329 330 331
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;
332 333 334
	struct dasd_diag_cms_label *label;
	blocknum_t end_block;
	unsigned int sb, bsize;
L
Linus Torvalds 已提交
335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352
	int rc;

	private = (struct dasd_diag_private *) device->private;
	if (private == NULL) {
		private = kmalloc(sizeof(struct dasd_diag_private),GFP_KERNEL);
		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);
353 354 355
	if (rc) {
		DEV_MESSAGE(KERN_WARNING, device, "failed to retrieve device "
			    "information (rc=%d)", rc);
L
Linus Torvalds 已提交
356
		return -ENOTSUPP;
357
	}
L
Linus Torvalds 已提交
358 359 360 361 362 363 364 365 366 367

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

442 443
/* Fill in virtual disk geometry for device. Return zero on success, non-zero
 * otherwise. */
L
Linus Torvalds 已提交
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472
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;
}

473 474
/* Create DASD request from block device request. Return pointer to new
 * request on success, ERR_PTR otherwise. */
L
Linus Torvalds 已提交
475 476 477 478 479 480 481 482 483
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;
484
	unsigned int count, datasize;
L
Linus Torvalds 已提交
485
	sector_t recid, first_rec, last_rec;
486
	unsigned int blksize, off;
L
Linus Torvalds 已提交
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 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531
	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;
	
	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;
532
				dbio->buffer = dst;
L
Linus Torvalds 已提交
533 534 535 536 537 538
				dbio++;
				dst += blksize;
				recid++;
			}
		}
	}
539
	cqr->retries = DIAG_MAX_RETRIES;
L
Linus Torvalds 已提交
540 541
	cqr->buildclk = get_clock();
	cqr->device = device;
542
	cqr->expires = DIAG_TIMEOUT;
L
Linus Torvalds 已提交
543 544 545 546
	cqr->status = DASD_CQR_FILLED;
	return cqr;
}

547 548
/* Release DASD request. Return non-zero if request was successful, zero
 * otherwise. */
L
Linus Torvalds 已提交
549 550 551 552 553 554 555 556 557 558
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;
}

559
/* Fill in IOCTL data for device. */
L
Linus Torvalds 已提交
560 561 562 563 564 565 566
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;
567
	info->label_block = (unsigned int) private->pt_block;
L
Linus Torvalds 已提交
568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589
	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",
590
	.max_blocks = DIAG_MAX_BLOCKS,
L
Linus Torvalds 已提交
591 592 593
	.check_device = dasd_diag_check_device,
	.fill_geometry = dasd_diag_fill_geometry,
	.start_IO = dasd_start_diag,
594
	.term_IO = dasd_diag_term_IO,
L
Linus Torvalds 已提交
595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611
	.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);
612
		return -ENODEV;
L
Linus Torvalds 已提交
613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631
	}
	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);