brintos

brintos / linux-shallow public Read only

0
0
Text · 18.2 KiB · 8245b74 Raw
677 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>4 * Based on.......: linux/drivers/s390/block/mdisk.c5 * ...............: by Hartmunt Penner <hpenner@de.ibm.com>6 * Bugreports.to..: <Linux390@de.ibm.com>7 * Copyright IBM Corp. 1999, 20008 *9 */10 11#include <linux/kernel_stat.h>12#include <linux/stddef.h>13#include <linux/kernel.h>14#include <linux/slab.h>15#include <linux/hdreg.h>16#include <linux/bio.h>17#include <linux/module.h>18#include <linux/init.h>19#include <linux/jiffies.h>20#include <asm/asm-extable.h>21#include <asm/dasd.h>22#include <asm/debug.h>23#include <asm/diag.h>24#include <asm/ebcdic.h>25#include <linux/io.h>26#include <asm/irq.h>27#include <asm/vtoc.h>28 29#include "dasd_int.h"30#include "dasd_diag.h"31 32MODULE_DESCRIPTION("S/390 Support for DIAG access to DASD Disks");33MODULE_LICENSE("GPL");34 35/* The maximum number of blocks per request (max_blocks) is dependent on the36 * amount of storage that is available in the static I/O buffer for each37 * device. Currently each device gets 2 pages. We want to fit two requests38 * into the available memory so that we can immediately start the next if one39 * finishes. */40#define DIAG_MAX_BLOCKS	(((2 * PAGE_SIZE - sizeof(struct dasd_ccw_req) - \41			   sizeof(struct dasd_diag_req)) / \42		           sizeof(struct dasd_diag_bio)) / 2)43#define DIAG_MAX_RETRIES	3244#define DIAG_TIMEOUT		5045 46static struct dasd_discipline dasd_diag_discipline;47 48struct dasd_diag_private {49	struct dasd_diag_characteristics rdc_data;50	struct dasd_diag_rw_io iob;51	struct dasd_diag_init_io iib;52	blocknum_t pt_block;53	struct ccw_dev_id dev_id;54};55 56struct dasd_diag_req {57	unsigned int block_count;58	struct dasd_diag_bio bio[];59};60 61static const u8 DASD_DIAG_CMS1[] = { 0xc3, 0xd4, 0xe2, 0xf1 };/* EBCDIC CMS1 */62 63/* Perform DIAG250 call with block I/O parameter list iob (input and output)64 * and function code cmd.65 * In case of an exception return 3. Otherwise return result of bitwise OR of66 * resulting condition code and DIAG return code. */67static inline int __dia250(void *iob, int cmd)68{69	union register_pair rx = { .even = (unsigned long)iob, };70	typedef union {71		struct dasd_diag_init_io init_io;72		struct dasd_diag_rw_io rw_io;73	} addr_type;74	int cc;75 76	cc = 3;77	asm volatile(78		"	diag	%[rx],%[cmd],0x250\n"79		"0:	ipm	%[cc]\n"80		"	srl	%[cc],28\n"81		"1:\n"82		EX_TABLE(0b,1b)83		: [cc] "+&d" (cc), [rx] "+&d" (rx.pair), "+m" (*(addr_type *)iob)84		: [cmd] "d" (cmd)85		: "cc");86	return cc | rx.odd;87}88 89static inline int dia250(void *iob, int cmd)90{91	diag_stat_inc(DIAG_STAT_X250);92	return __dia250(iob, cmd);93}94 95/* Initialize block I/O to DIAG device using the specified blocksize and96 * block offset. On success, return zero and set end_block to contain the97 * number of blocks on the device minus the specified offset. Return non-zero98 * otherwise. */99static inline int100mdsk_init_io(struct dasd_device *device, unsigned int blocksize,101	     blocknum_t offset, blocknum_t *end_block)102{103	struct dasd_diag_private *private = device->private;104	struct dasd_diag_init_io *iib = &private->iib;105	int rc;106 107	memset(iib, 0, sizeof (struct dasd_diag_init_io));108 109	iib->dev_nr = private->dev_id.devno;110	iib->block_size = blocksize;111	iib->offset = offset;112	iib->flaga = DASD_DIAG_FLAGA_DEFAULT;113 114	rc = dia250(iib, INIT_BIO);115 116	if ((rc & 3) == 0 && end_block)117		*end_block = iib->end_block;118 119	return rc;120}121 122/* Remove block I/O environment for device. Return zero on success, non-zero123 * otherwise. */124static inline int125mdsk_term_io(struct dasd_device * device)126{127	struct dasd_diag_private *private = device->private;128	struct dasd_diag_init_io *iib = &private->iib;129	int rc;130 131	memset(iib, 0, sizeof (struct dasd_diag_init_io));132	iib->dev_nr = private->dev_id.devno;133	rc = dia250(iib, TERM_BIO);134	return rc;135}136 137/* Error recovery for failed DIAG requests - try to reestablish the DIAG138 * environment. */139static void140dasd_diag_erp(struct dasd_device *device)141{142	int rc;143 144	mdsk_term_io(device);145	rc = mdsk_init_io(device, device->block->bp_block, 0, NULL);146	if (rc == 4) {147		if (!(test_and_set_bit(DASD_FLAG_DEVICE_RO, &device->flags)))148			pr_warn("%s: The access mode of a DIAG device changed to read-only\n",149				dev_name(&device->cdev->dev));150		rc = 0;151	}152	if (rc)153		pr_warn("%s: DIAG ERP failed with rc=%d\n",154			dev_name(&device->cdev->dev), rc);155}156 157/* Start a given request at the device. Return zero on success, non-zero158 * otherwise. */159static int160dasd_start_diag(struct dasd_ccw_req * cqr)161{162	struct dasd_device *device;163	struct dasd_diag_private *private;164	struct dasd_diag_req *dreq;165	int rc;166 167	device = cqr->startdev;168	if (cqr->retries < 0) {169		DBF_DEV_EVENT(DBF_ERR, device, "DIAG start_IO: request %p "170			    "- no retry left)", cqr);171		cqr->status = DASD_CQR_ERROR;172		return -EIO;173	}174	private = device->private;175	dreq = cqr->data;176 177	private->iob.dev_nr = private->dev_id.devno;178	private->iob.key = 0;179	private->iob.flags = DASD_DIAG_RWFLAG_ASYNC;180	private->iob.block_count = dreq->block_count;181	private->iob.interrupt_params = (addr_t) cqr;182	private->iob.bio_list = dreq->bio;183	private->iob.flaga = DASD_DIAG_FLAGA_DEFAULT;184 185	cqr->startclk = get_tod_clock();186	cqr->starttime = jiffies;187	cqr->retries--;188 189	rc = dia250(&private->iob, RW_BIO);190	switch (rc) {191	case 0: /* Synchronous I/O finished successfully */192		cqr->stopclk = get_tod_clock();193		cqr->status = DASD_CQR_SUCCESS;194		/* Indicate to calling function that only a dasd_schedule_bh()195		   and no timer is needed */196                rc = -EACCES;197		break;198	case 8: /* Asynchronous I/O was started */199		cqr->status = DASD_CQR_IN_IO;200		rc = 0;201		break;202	default: /* Error condition */203		cqr->status = DASD_CQR_QUEUED;204		DBF_DEV_EVENT(DBF_WARNING, device, "dia250 returned rc=%d", rc);205		dasd_diag_erp(device);206		rc = -EIO;207		break;208	}209	cqr->intrc = rc;210	return rc;211}212 213/* Terminate given request at the device. */214static int215dasd_diag_term_IO(struct dasd_ccw_req * cqr)216{217	struct dasd_device *device;218 219	device = cqr->startdev;220	mdsk_term_io(device);221	mdsk_init_io(device, device->block->bp_block, 0, NULL);222	cqr->status = DASD_CQR_CLEAR_PENDING;223	cqr->stopclk = get_tod_clock();224	dasd_schedule_device_bh(device);225	return 0;226}227 228/* Handle external interruption. */229static void dasd_ext_handler(struct ext_code ext_code,230			     unsigned int param32, unsigned long param64)231{232	struct dasd_ccw_req *cqr, *next;233	struct dasd_device *device;234	unsigned long expires;235	unsigned long flags;236	addr_t ip;237	int rc;238 239	switch (ext_code.subcode >> 8) {240	case DASD_DIAG_CODE_31BIT:241		ip = (addr_t) param32;242		break;243	case DASD_DIAG_CODE_64BIT:244		ip = (addr_t) param64;245		break;246	default:247		return;248	}249	inc_irq_stat(IRQEXT_DSD);250	if (!ip) {		/* no intparm: unsolicited interrupt */251		DBF_EVENT(DBF_NOTICE, "%s", "caught unsolicited "252			      "interrupt");253		return;254	}255	cqr = (struct dasd_ccw_req *) ip;256	device = (struct dasd_device *) cqr->startdev;257	if (strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {258		DBF_DEV_EVENT(DBF_WARNING, device,259			    " magic number of dasd_ccw_req 0x%08X doesn't"260			    " match discipline 0x%08X",261			    cqr->magic, *(int *) (&device->discipline->name));262		return;263	}264 265	/* get irq lock to modify request queue */266	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);267 268	/* Check for a pending clear operation */269	if (cqr->status == DASD_CQR_CLEAR_PENDING) {270		cqr->status = DASD_CQR_CLEARED;271		dasd_device_clear_timer(device);272		dasd_schedule_device_bh(device);273		spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);274		return;275	}276 277	cqr->stopclk = get_tod_clock();278 279	expires = 0;280	if ((ext_code.subcode & 0xff) == 0) {281		cqr->status = DASD_CQR_SUCCESS;282		/* Start first request on queue if possible -> fast_io. */283		if (!list_empty(&device->ccw_queue)) {284			next = list_entry(device->ccw_queue.next,285					  struct dasd_ccw_req, devlist);286			if (next->status == DASD_CQR_QUEUED) {287				rc = dasd_start_diag(next);288				if (rc == 0)289					expires = next->expires;290			}291		}292	} else {293		cqr->status = DASD_CQR_QUEUED;294		DBF_DEV_EVENT(DBF_DEBUG, device, "interrupt status for "295			      "request %p was %d (%d retries left)", cqr,296			      ext_code.subcode & 0xff, cqr->retries);297		dasd_diag_erp(device);298	}299 300	if (expires != 0)301		dasd_device_set_timer(device, expires);302	else303		dasd_device_clear_timer(device);304	dasd_schedule_device_bh(device);305 306	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);307}308 309/* Check whether device can be controlled by DIAG discipline. Return zero on310 * success, non-zero otherwise. */311static int312dasd_diag_check_device(struct dasd_device *device)313{314	struct dasd_diag_private *private = device->private;315	struct dasd_diag_characteristics *rdc_data;316	struct vtoc_cms_label *label;317	struct dasd_block *block;318	struct dasd_diag_bio *bio;319	unsigned int sb, bsize;320	blocknum_t end_block;321	int rc;322 323	if (private == NULL) {324		private = kzalloc(sizeof(*private), GFP_KERNEL);325		if (private == NULL) {326			DBF_DEV_EVENT(DBF_WARNING, device, "%s",327				"Allocating memory for private DASD data "328				      "failed\n");329			return -ENOMEM;330		}331		ccw_device_get_id(device->cdev, &private->dev_id);332		device->private = private;333	}334	block = dasd_alloc_block();335	if (IS_ERR(block)) {336		DBF_DEV_EVENT(DBF_WARNING, device, "%s",337			    "could not allocate dasd block structure");338		device->private = NULL;339		kfree(private);340		return PTR_ERR(block);341	}342	device->block = block;343	block->base = device;344 345	/* Read Device Characteristics */346	rdc_data = &private->rdc_data;347	rdc_data->dev_nr = private->dev_id.devno;348	rdc_data->rdc_len = sizeof (struct dasd_diag_characteristics);349 350	rc = diag210((struct diag210 *) rdc_data);351	if (rc) {352		DBF_DEV_EVENT(DBF_WARNING, device, "failed to retrieve device "353			    "information (rc=%d)", rc);354		rc = -EOPNOTSUPP;355		goto out;356	}357 358	device->default_expires = DIAG_TIMEOUT;359	device->default_retries = DIAG_MAX_RETRIES;360 361	/* Figure out position of label block */362	switch (private->rdc_data.vdev_class) {363	case DEV_CLASS_FBA:364		private->pt_block = 1;365		break;366	case DEV_CLASS_ECKD:367		private->pt_block = 2;368		break;369	default:370		pr_warn("%s: Device type %d is not supported in DIAG mode\n",371			dev_name(&device->cdev->dev),372			private->rdc_data.vdev_class);373		rc = -EOPNOTSUPP;374		goto out;375	}376 377	DBF_DEV_EVENT(DBF_INFO, device,378		      "%04X: %04X on real %04X/%02X",379		      rdc_data->dev_nr,380		      rdc_data->vdev_type,381		      rdc_data->rdev_type, rdc_data->rdev_model);382 383	/* terminate all outstanding operations */384	mdsk_term_io(device);385 386	/* figure out blocksize of device */387	label = (struct vtoc_cms_label *) get_zeroed_page(GFP_KERNEL);388	if (label == NULL)  {389		DBF_DEV_EVENT(DBF_WARNING, device, "%s",390			    "No memory to allocate initialization request");391		rc = -ENOMEM;392		goto out;393	}394	bio = kzalloc(sizeof(*bio), GFP_KERNEL);395	if (bio == NULL)  {396		DBF_DEV_EVENT(DBF_WARNING, device, "%s",397			      "No memory to allocate initialization bio");398		rc = -ENOMEM;399		goto out_label;400	}401	rc = 0;402	end_block = 0;403	/* try all sizes - needed for ECKD devices */404	for (bsize = 512; bsize <= PAGE_SIZE; bsize <<= 1) {405		mdsk_init_io(device, bsize, 0, &end_block);406		memset(bio, 0, sizeof(*bio));407		bio->type = MDSK_READ_REQ;408		bio->block_number = private->pt_block + 1;409		bio->buffer = label;410		memset(&private->iob, 0, sizeof (struct dasd_diag_rw_io));411		private->iob.dev_nr = rdc_data->dev_nr;412		private->iob.key = 0;413		private->iob.flags = 0;	/* do synchronous io */414		private->iob.block_count = 1;415		private->iob.interrupt_params = 0;416		private->iob.bio_list = bio;417		private->iob.flaga = DASD_DIAG_FLAGA_DEFAULT;418		rc = dia250(&private->iob, RW_BIO);419		if (rc == 3) {420			pr_warn("%s: A 64-bit DIAG call failed\n",421				dev_name(&device->cdev->dev));422			rc = -EOPNOTSUPP;423			goto out_bio;424		}425		mdsk_term_io(device);426		if (rc == 0)427			break;428	}429	if (bsize > PAGE_SIZE) {430		pr_warn("%s: Accessing the DASD failed because of an incorrect format (rc=%d)\n",431			dev_name(&device->cdev->dev), rc);432		rc = -EIO;433		goto out_bio;434	}435	/* check for label block */436	if (memcmp(label->label_id, DASD_DIAG_CMS1,437		  sizeof(DASD_DIAG_CMS1)) == 0) {438		/* get formatted blocksize from label block */439		bsize = (unsigned int) label->block_size;440		block->blocks = (unsigned long) label->block_count;441	} else442		block->blocks = end_block;443	block->bp_block = bsize;444	block->s2b_shift = 0;	/* bits to shift 512 to get a block */445	for (sb = 512; sb < bsize; sb = sb << 1)446		block->s2b_shift++;447	rc = mdsk_init_io(device, block->bp_block, 0, NULL);448	if (rc && (rc != 4)) {449		pr_warn("%s: DIAG initialization failed with rc=%d\n",450			dev_name(&device->cdev->dev), rc);451		rc = -EIO;452	} else {453		if (rc == 4)454			set_bit(DASD_FLAG_DEVICE_RO, &device->flags);455		pr_info("%s: New DASD with %ld byte/block, total size %ld "456			"KB%s\n", dev_name(&device->cdev->dev),457			(unsigned long) block->bp_block,458			(unsigned long) (block->blocks <<459					 block->s2b_shift) >> 1,460			(rc == 4) ? ", read-only device" : "");461		rc = 0;462	}463out_bio:464	kfree(bio);465out_label:466	free_page((long) label);467out:468	if (rc) {469		device->block = NULL;470		dasd_free_block(block);471		device->private = NULL;472		kfree(private);473	}474	return rc;475}476 477/* Fill in virtual disk geometry for device. Return zero on success, non-zero478 * otherwise. */479static int480dasd_diag_fill_geometry(struct dasd_block *block, struct hd_geometry *geo)481{482	if (dasd_check_blocksize(block->bp_block) != 0)483		return -EINVAL;484	geo->cylinders = (block->blocks << block->s2b_shift) >> 10;485	geo->heads = 16;486	geo->sectors = 128 >> block->s2b_shift;487	return 0;488}489 490static dasd_erp_fn_t491dasd_diag_erp_action(struct dasd_ccw_req * cqr)492{493	return dasd_default_erp_action;494}495 496static dasd_erp_fn_t497dasd_diag_erp_postaction(struct dasd_ccw_req * cqr)498{499	return dasd_default_erp_postaction;500}501 502/* Create DASD request from block device request. Return pointer to new503 * request on success, ERR_PTR otherwise. */504static struct dasd_ccw_req *dasd_diag_build_cp(struct dasd_device *memdev,505					       struct dasd_block *block,506					       struct request *req)507{508	struct dasd_ccw_req *cqr;509	struct dasd_diag_req *dreq;510	struct dasd_diag_bio *dbio;511	struct req_iterator iter;512	struct bio_vec bv;513	char *dst;514	unsigned int count;515	sector_t recid, first_rec, last_rec;516	unsigned int blksize, off;517	unsigned char rw_cmd;518 519	if (rq_data_dir(req) == READ)520		rw_cmd = MDSK_READ_REQ;521	else if (rq_data_dir(req) == WRITE)522		rw_cmd = MDSK_WRITE_REQ;523	else524		return ERR_PTR(-EINVAL);525	blksize = block->bp_block;526	/* Calculate record id of first and last block. */527	first_rec = blk_rq_pos(req) >> block->s2b_shift;528	last_rec =529		(blk_rq_pos(req) + blk_rq_sectors(req) - 1) >> block->s2b_shift;530	/* Check struct bio and count the number of blocks for the request. */531	count = 0;532	rq_for_each_segment(bv, req, iter) {533		if (bv.bv_len & (blksize - 1))534			/* Fba can only do full blocks. */535			return ERR_PTR(-EINVAL);536		count += bv.bv_len >> (block->s2b_shift + 9);537	}538	/* Paranoia. */539	if (count != last_rec - first_rec + 1)540		return ERR_PTR(-EINVAL);541	/* Build the request */542	cqr = dasd_smalloc_request(DASD_DIAG_MAGIC, 0, struct_size(dreq, bio, count),543				   memdev, blk_mq_rq_to_pdu(req));544	if (IS_ERR(cqr))545		return cqr;546 547	dreq = (struct dasd_diag_req *) cqr->data;548	dreq->block_count = count;549	dbio = dreq->bio;550	recid = first_rec;551	rq_for_each_segment(bv, req, iter) {552		dst = bvec_virt(&bv);553		for (off = 0; off < bv.bv_len; off += blksize) {554			memset(dbio, 0, sizeof (struct dasd_diag_bio));555			dbio->type = rw_cmd;556			dbio->block_number = recid + 1;557			dbio->buffer = dst;558			dbio++;559			dst += blksize;560			recid++;561		}562	}563	cqr->retries = memdev->default_retries;564	cqr->buildclk = get_tod_clock();565	if (blk_noretry_request(req) ||566	    block->base->features & DASD_FEATURE_FAILFAST)567		set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);568	cqr->startdev = memdev;569	cqr->memdev = memdev;570	cqr->block = block;571	cqr->expires = memdev->default_expires * HZ;572	cqr->status = DASD_CQR_FILLED;573	return cqr;574}575 576/* Release DASD request. Return non-zero if request was successful, zero577 * otherwise. */578static int579dasd_diag_free_cp(struct dasd_ccw_req *cqr, struct request *req)580{581	int status;582 583	status = cqr->status == DASD_CQR_DONE;584	dasd_sfree_request(cqr, cqr->memdev);585	return status;586}587 588static void dasd_diag_handle_terminated_request(struct dasd_ccw_req *cqr)589{590	if (cqr->retries < 0)591		cqr->status = DASD_CQR_FAILED;592	else593		cqr->status = DASD_CQR_FILLED;594};595 596/* Fill in IOCTL data for device. */597static int598dasd_diag_fill_info(struct dasd_device * device,599		    struct dasd_information2_t * info)600{601	struct dasd_diag_private *private = device->private;602 603	info->label_block = (unsigned int) private->pt_block;604	info->FBA_layout = 1;605	info->format = DASD_FORMAT_LDL;606	info->characteristics_size = sizeof(private->rdc_data);607	memcpy(info->characteristics, &private->rdc_data,608	       sizeof(private->rdc_data));609	info->confdata_size = 0;610	return 0;611}612 613static void614dasd_diag_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,615		     struct irb *stat)616{617	DBF_DEV_EVENT(DBF_WARNING, device, "%s",618		    "dump sense not available for DIAG data");619}620 621static unsigned int dasd_diag_max_sectors(struct dasd_block *block)622{623	return DIAG_MAX_BLOCKS << block->s2b_shift;624}625 626static int dasd_diag_pe_handler(struct dasd_device *device,627				__u8 tbvpm, __u8 fcsecpm)628{629	return dasd_generic_verify_path(device, tbvpm);630}631 632static struct dasd_discipline dasd_diag_discipline = {633	.owner = THIS_MODULE,634	.name = "DIAG",635	.ebcname = "DIAG",636	.max_sectors = dasd_diag_max_sectors,637	.check_device = dasd_diag_check_device,638	.pe_handler = dasd_diag_pe_handler,639	.fill_geometry = dasd_diag_fill_geometry,640	.start_IO = dasd_start_diag,641	.term_IO = dasd_diag_term_IO,642	.handle_terminated_request = dasd_diag_handle_terminated_request,643	.erp_action = dasd_diag_erp_action,644	.erp_postaction = dasd_diag_erp_postaction,645	.build_cp = dasd_diag_build_cp,646	.free_cp = dasd_diag_free_cp,647	.dump_sense = dasd_diag_dump_sense,648	.fill_info = dasd_diag_fill_info,649};650 651static int __init652dasd_diag_init(void)653{654	if (!MACHINE_IS_VM) {655		pr_info("Discipline %s cannot be used without z/VM\n",656			dasd_diag_discipline.name);657		return -ENODEV;658	}659	ASCEBC(dasd_diag_discipline.ebcname, 4);660 661	irq_subclass_register(IRQ_SUBCLASS_SERVICE_SIGNAL);662	register_external_irq(EXT_IRQ_CP_SERVICE, dasd_ext_handler);663	dasd_diag_discipline_pointer = &dasd_diag_discipline;664	return 0;665}666 667static void __exit668dasd_diag_cleanup(void)669{670	unregister_external_irq(EXT_IRQ_CP_SERVICE, dasd_ext_handler);671	irq_subclass_unregister(IRQ_SUBCLASS_SERVICE_SIGNAL);672	dasd_diag_discipline_pointer = NULL;673}674 675module_init(dasd_diag_init);676module_exit(dasd_diag_cleanup);677