brintos

brintos / linux-shallow public Read only

0
0
Text · 18.0 KiB · f7e75d9 Raw
745 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 *    standard tape device functions for ibm tapes.4 *5 *  S390 and zSeries version6 *    Copyright IBM Corp. 2001, 20027 *    Author(s): Carsten Otte <cotte@de.ibm.com>8 *		 Michael Holzheu <holzheu@de.ibm.com>9 *		 Tuan Ngo-Anh <ngoanh@de.ibm.com>10 *		 Martin Schwidefsky <schwidefsky@de.ibm.com>11 *		 Stefan Bader <shbader@de.ibm.com>12 */13 14#define KMSG_COMPONENT "tape"15#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt16 17#include <linux/stddef.h>18#include <linux/kernel.h>19#include <linux/bio.h>20#include <linux/timer.h>21 22#include <asm/types.h>23#include <asm/idals.h>24#include <asm/ebcdic.h>25#include <asm/tape390.h>26 27#define TAPE_DBF_AREA	tape_core_dbf28 29#include "tape.h"30#include "tape_std.h"31 32/*33 * tape_std_assign34 */35static void36tape_std_assign_timeout(struct timer_list *t)37{38	struct tape_request *	request = from_timer(request, t, timer);39	struct tape_device *	device = request->device;40	int rc;41 42	BUG_ON(!device);43 44	DBF_EVENT(3, "%08x: Assignment timeout. Device busy.\n",45			device->cdev_id);46	rc = tape_cancel_io(device, request);47	if(rc)48		DBF_EVENT(3, "(%08x): Assign timeout: Cancel failed with rc = "49			  "%i\n", device->cdev_id, rc);50}51 52int53tape_std_assign(struct tape_device *device)54{55	int                  rc;56	struct tape_request *request;57 58	request = tape_alloc_request(2, 11);59	if (IS_ERR(request))60		return PTR_ERR(request);61 62	request->op = TO_ASSIGN;63	tape_ccw_cc(request->cpaddr, ASSIGN, 11, request->cpdata);64	tape_ccw_end(request->cpaddr + 1, NOP, 0, NULL);65 66	/*67	 * The assign command sometimes blocks if the device is assigned68	 * to another host (actually this shouldn't happen but it does).69	 * So we set up a timeout for this call.70	 */71	timer_setup(&request->timer, tape_std_assign_timeout, 0);72	mod_timer(&request->timer, jiffies + msecs_to_jiffies(2000));73 74	rc = tape_do_io_interruptible(device, request);75 76	del_timer_sync(&request->timer);77 78	if (rc != 0) {79		DBF_EVENT(3, "%08x: assign failed - device might be busy\n",80			device->cdev_id);81	} else {82		DBF_EVENT(3, "%08x: Tape assigned\n", device->cdev_id);83	}84	tape_free_request(request);85	return rc;86}87 88/*89 * tape_std_unassign90 */91int92tape_std_unassign (struct tape_device *device)93{94	int                  rc;95	struct tape_request *request;96 97	if (device->tape_state == TS_NOT_OPER) {98		DBF_EVENT(3, "(%08x): Can't unassign device\n",99			device->cdev_id);100		return -EIO;101	}102 103	request = tape_alloc_request(2, 11);104	if (IS_ERR(request))105		return PTR_ERR(request);106 107	request->op = TO_UNASSIGN;108	tape_ccw_cc(request->cpaddr, UNASSIGN, 11, request->cpdata);109	tape_ccw_end(request->cpaddr + 1, NOP, 0, NULL);110 111	if ((rc = tape_do_io(device, request)) != 0) {112		DBF_EVENT(3, "%08x: Unassign failed\n", device->cdev_id);113	} else {114		DBF_EVENT(3, "%08x: Tape unassigned\n", device->cdev_id);115	}116	tape_free_request(request);117	return rc;118}119 120/*121 * TAPE390_DISPLAY: Show a string on the tape display.122 */123int124tape_std_display(struct tape_device *device, struct display_struct *disp)125{126	struct tape_request *request;127	int rc;128 129	request = tape_alloc_request(2, 17);130	if (IS_ERR(request)) {131		DBF_EVENT(3, "TAPE: load display failed\n");132		return PTR_ERR(request);133	}134	request->op = TO_DIS;135 136	*(unsigned char *) request->cpdata = disp->cntrl;137	DBF_EVENT(5, "TAPE: display cntrl=%04x\n", disp->cntrl);138	memcpy(((unsigned char *) request->cpdata) + 1, disp->message1, 8);139	memcpy(((unsigned char *) request->cpdata) + 9, disp->message2, 8);140	ASCEBC(((unsigned char*) request->cpdata) + 1, 16);141 142	tape_ccw_cc(request->cpaddr, LOAD_DISPLAY, 17, request->cpdata);143	tape_ccw_end(request->cpaddr + 1, NOP, 0, NULL);144 145	rc = tape_do_io_interruptible(device, request);146	tape_free_request(request);147	return rc;148}149 150/*151 * Read block id.152 */153int154tape_std_read_block_id(struct tape_device *device, __u64 *id)155{156	struct tape_request *request;157	int rc;158 159	request = tape_alloc_request(3, 8);160	if (IS_ERR(request))161		return PTR_ERR(request);162	request->op = TO_RBI;163	/* setup ccws */164	tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);165	tape_ccw_cc(request->cpaddr + 1, READ_BLOCK_ID, 8, request->cpdata);166	tape_ccw_end(request->cpaddr + 2, NOP, 0, NULL);167	/* execute it */168	rc = tape_do_io(device, request);169	if (rc == 0)170		/* Get result from read buffer. */171		*id = *(__u64 *) request->cpdata;172	tape_free_request(request);173	return rc;174}175 176int177tape_std_terminate_write(struct tape_device *device)178{179	int rc;180 181	if(device->required_tapemarks == 0)182		return 0;183 184	DBF_LH(5, "tape%d: terminate write %dxEOF\n", device->first_minor,185		device->required_tapemarks);186 187	rc = tape_mtop(device, MTWEOF, device->required_tapemarks);188	if (rc)189		return rc;190 191	device->required_tapemarks = 0;192	return tape_mtop(device, MTBSR, 1);193}194 195/*196 * MTLOAD: Loads the tape.197 * The default implementation just wait until the tape medium state changes198 * to MS_LOADED.199 */200int201tape_std_mtload(struct tape_device *device, int count)202{203	return wait_event_interruptible(device->state_change_wq,204		(device->medium_state == MS_LOADED));205}206 207/*208 * MTSETBLK: Set block size.209 */210int211tape_std_mtsetblk(struct tape_device *device, int count)212{213	struct idal_buffer *new;214 215	DBF_LH(6, "tape_std_mtsetblk(%d)\n", count);216	if (count <= 0) {217		/*218		 * Just set block_size to 0. tapechar_read/tapechar_write219		 * will realloc the idal buffer if a bigger one than the220		 * current is needed.221		 */222		device->char_data.block_size = 0;223		return 0;224	}225	if (device->char_data.idal_buf != NULL &&226	    device->char_data.idal_buf->size == count)227		/* We already have a idal buffer of that size. */228		return 0;229 230	if (count > MAX_BLOCKSIZE) {231		DBF_EVENT(3, "Invalid block size (%d > %d) given.\n",232			count, MAX_BLOCKSIZE);233		return -EINVAL;234	}235 236	/* Allocate a new idal buffer. */237	new = idal_buffer_alloc(count, 0);238	if (IS_ERR(new))239		return -ENOMEM;240	if (device->char_data.idal_buf != NULL)241		idal_buffer_free(device->char_data.idal_buf);242	device->char_data.idal_buf = new;243	device->char_data.block_size = count;244 245	DBF_LH(6, "new blocksize is %d\n", device->char_data.block_size);246 247	return 0;248}249 250/*251 * MTRESET: Set block size to 0.252 */253int254tape_std_mtreset(struct tape_device *device, int count)255{256	DBF_EVENT(6, "TCHAR:devreset:\n");257	device->char_data.block_size = 0;258	return 0;259}260 261/*262 * MTFSF: Forward space over 'count' file marks. The tape is positioned263 * at the EOT (End of Tape) side of the file mark.264 */265int266tape_std_mtfsf(struct tape_device *device, int mt_count)267{268	struct tape_request *request;269	struct ccw1 *ccw;270 271	request = tape_alloc_request(mt_count + 2, 0);272	if (IS_ERR(request))273		return PTR_ERR(request);274	request->op = TO_FSF;275	/* setup ccws */276	ccw = tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1,277			  device->modeset_byte);278	ccw = tape_ccw_repeat(ccw, FORSPACEFILE, mt_count);279	ccw = tape_ccw_end(ccw, NOP, 0, NULL);280 281	/* execute it */282	return tape_do_io_free(device, request);283}284 285/*286 * MTFSR: Forward space over 'count' tape blocks (blocksize is set287 * via MTSETBLK.288 */289int290tape_std_mtfsr(struct tape_device *device, int mt_count)291{292	struct tape_request *request;293	struct ccw1 *ccw;294	int rc;295 296	request = tape_alloc_request(mt_count + 2, 0);297	if (IS_ERR(request))298		return PTR_ERR(request);299	request->op = TO_FSB;300	/* setup ccws */301	ccw = tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1,302			  device->modeset_byte);303	ccw = tape_ccw_repeat(ccw, FORSPACEBLOCK, mt_count);304	ccw = tape_ccw_end(ccw, NOP, 0, NULL);305 306	/* execute it */307	rc = tape_do_io(device, request);308	if (rc == 0 && request->rescnt > 0) {309		DBF_LH(3, "FSR over tapemark\n");310		rc = 1;311	}312	tape_free_request(request);313 314	return rc;315}316 317/*318 * MTBSR: Backward space over 'count' tape blocks.319 * (blocksize is set via MTSETBLK.320 */321int322tape_std_mtbsr(struct tape_device *device, int mt_count)323{324	struct tape_request *request;325	struct ccw1 *ccw;326	int rc;327 328	request = tape_alloc_request(mt_count + 2, 0);329	if (IS_ERR(request))330		return PTR_ERR(request);331	request->op = TO_BSB;332	/* setup ccws */333	ccw = tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1,334			  device->modeset_byte);335	ccw = tape_ccw_repeat(ccw, BACKSPACEBLOCK, mt_count);336	ccw = tape_ccw_end(ccw, NOP, 0, NULL);337 338	/* execute it */339	rc = tape_do_io(device, request);340	if (rc == 0 && request->rescnt > 0) {341		DBF_LH(3, "BSR over tapemark\n");342		rc = 1;343	}344	tape_free_request(request);345 346	return rc;347}348 349/*350 * MTWEOF: Write 'count' file marks at the current position.351 */352int353tape_std_mtweof(struct tape_device *device, int mt_count)354{355	struct tape_request *request;356	struct ccw1 *ccw;357 358	request = tape_alloc_request(mt_count + 2, 0);359	if (IS_ERR(request))360		return PTR_ERR(request);361	request->op = TO_WTM;362	/* setup ccws */363	ccw = tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1,364			  device->modeset_byte);365	ccw = tape_ccw_repeat(ccw, WRITETAPEMARK, mt_count);366	ccw = tape_ccw_end(ccw, NOP, 0, NULL);367 368	/* execute it */369	return tape_do_io_free(device, request);370}371 372/*373 * MTBSFM: Backward space over 'count' file marks.374 * The tape is positioned at the BOT (Begin Of Tape) side of the375 * last skipped file mark.376 */377int378tape_std_mtbsfm(struct tape_device *device, int mt_count)379{380	struct tape_request *request;381	struct ccw1 *ccw;382 383	request = tape_alloc_request(mt_count + 2, 0);384	if (IS_ERR(request))385		return PTR_ERR(request);386	request->op = TO_BSF;387	/* setup ccws */388	ccw = tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1,389			  device->modeset_byte);390	ccw = tape_ccw_repeat(ccw, BACKSPACEFILE, mt_count);391	ccw = tape_ccw_end(ccw, NOP, 0, NULL);392 393	/* execute it */394	return tape_do_io_free(device, request);395}396 397/*398 * MTBSF: Backward space over 'count' file marks. The tape is positioned at399 * the EOT (End of Tape) side of the last skipped file mark.400 */401int402tape_std_mtbsf(struct tape_device *device, int mt_count)403{404	struct tape_request *request;405	struct ccw1 *ccw;406	int rc;407 408	request = tape_alloc_request(mt_count + 2, 0);409	if (IS_ERR(request))410		return PTR_ERR(request);411	request->op = TO_BSF;412	/* setup ccws */413	ccw = tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1,414			  device->modeset_byte);415	ccw = tape_ccw_repeat(ccw, BACKSPACEFILE, mt_count);416	ccw = tape_ccw_end(ccw, NOP, 0, NULL);417	/* execute it */418	rc = tape_do_io_free(device, request);419	if (rc == 0) {420		rc = tape_mtop(device, MTFSR, 1);421		if (rc > 0)422			rc = 0;423	}424	return rc;425}426 427/*428 * MTFSFM: Forward space over 'count' file marks.429 * The tape is positioned at the BOT (Begin Of Tape) side430 * of the last skipped file mark.431 */432int433tape_std_mtfsfm(struct tape_device *device, int mt_count)434{435	struct tape_request *request;436	struct ccw1 *ccw;437	int rc;438 439	request = tape_alloc_request(mt_count + 2, 0);440	if (IS_ERR(request))441		return PTR_ERR(request);442	request->op = TO_FSF;443	/* setup ccws */444	ccw = tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1,445			  device->modeset_byte);446	ccw = tape_ccw_repeat(ccw, FORSPACEFILE, mt_count);447	ccw = tape_ccw_end(ccw, NOP, 0, NULL);448	/* execute it */449	rc = tape_do_io_free(device, request);450	if (rc == 0) {451		rc = tape_mtop(device, MTBSR, 1);452		if (rc > 0)453			rc = 0;454	}455 456	return rc;457}458 459/*460 * MTREW: Rewind the tape.461 */462int463tape_std_mtrew(struct tape_device *device, int mt_count)464{465	struct tape_request *request;466 467	request = tape_alloc_request(3, 0);468	if (IS_ERR(request))469		return PTR_ERR(request);470	request->op = TO_REW;471	/* setup ccws */472	tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1,473		    device->modeset_byte);474	tape_ccw_cc(request->cpaddr + 1, REWIND, 0, NULL);475	tape_ccw_end(request->cpaddr + 2, NOP, 0, NULL);476 477	/* execute it */478	return tape_do_io_free(device, request);479}480 481/*482 * MTOFFL: Rewind the tape and put the drive off-line.483 * Implement 'rewind unload'484 */485int486tape_std_mtoffl(struct tape_device *device, int mt_count)487{488	struct tape_request *request;489 490	request = tape_alloc_request(3, 0);491	if (IS_ERR(request))492		return PTR_ERR(request);493	request->op = TO_RUN;494	/* setup ccws */495	tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);496	tape_ccw_cc(request->cpaddr + 1, REWIND_UNLOAD, 0, NULL);497	tape_ccw_end(request->cpaddr + 2, NOP, 0, NULL);498 499	/* execute it */500	return tape_do_io_free(device, request);501}502 503/*504 * MTNOP: 'No operation'.505 */506int507tape_std_mtnop(struct tape_device *device, int mt_count)508{509	struct tape_request *request;510 511	request = tape_alloc_request(2, 0);512	if (IS_ERR(request))513		return PTR_ERR(request);514	request->op = TO_NOP;515	/* setup ccws */516	tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);517	tape_ccw_end(request->cpaddr + 1, NOP, 0, NULL);518	/* execute it */519	return tape_do_io_free(device, request);520}521 522/*523 * MTEOM: positions at the end of the portion of the tape already used524 * for recordind data. MTEOM positions after the last file mark, ready for525 * appending another file.526 */527int528tape_std_mteom(struct tape_device *device, int mt_count)529{530	int rc;531 532	/*533	 * Seek from the beginning of tape (rewind).534	 */535	if ((rc = tape_mtop(device, MTREW, 1)) < 0)536		return rc;537 538	/*539	 * The logical end of volume is given by two sewuential tapemarks.540	 * Look for this by skipping to the next file (over one tapemark)541	 * and then test for another one (fsr returns 1 if a tapemark was542	 * encountered).543	 */544	do {545		if ((rc = tape_mtop(device, MTFSF, 1)) < 0)546			return rc;547		if ((rc = tape_mtop(device, MTFSR, 1)) < 0)548			return rc;549	} while (rc == 0);550 551	return tape_mtop(device, MTBSR, 1);552}553 554/*555 * MTRETEN: Retension the tape, i.e. forward space to end of tape and rewind.556 */557int558tape_std_mtreten(struct tape_device *device, int mt_count)559{560	struct tape_request *request;561 562	request = tape_alloc_request(4, 0);563	if (IS_ERR(request))564		return PTR_ERR(request);565	request->op = TO_FSF;566	/* setup ccws */567	tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);568	tape_ccw_cc(request->cpaddr + 1,FORSPACEFILE, 0, NULL);569	tape_ccw_cc(request->cpaddr + 2, NOP, 0, NULL);570	tape_ccw_end(request->cpaddr + 3, CCW_CMD_TIC, 0, request->cpaddr);571	/* execute it, MTRETEN rc gets ignored */572	tape_do_io_interruptible(device, request);573	tape_free_request(request);574	return tape_mtop(device, MTREW, 1);575}576 577/*578 * MTERASE: erases the tape.579 */580int581tape_std_mterase(struct tape_device *device, int mt_count)582{583	struct tape_request *request;584 585	request = tape_alloc_request(6, 0);586	if (IS_ERR(request))587		return PTR_ERR(request);588	request->op = TO_DSE;589	/* setup ccws */590	tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);591	tape_ccw_cc(request->cpaddr + 1, REWIND, 0, NULL);592	tape_ccw_cc(request->cpaddr + 2, ERASE_GAP, 0, NULL);593	tape_ccw_cc(request->cpaddr + 3, DATA_SEC_ERASE, 0, NULL);594	tape_ccw_cc(request->cpaddr + 4, REWIND, 0, NULL);595	tape_ccw_end(request->cpaddr + 5, NOP, 0, NULL);596 597	/* execute it */598	return tape_do_io_free(device, request);599}600 601/*602 * MTUNLOAD: Rewind the tape and unload it.603 */604int605tape_std_mtunload(struct tape_device *device, int mt_count)606{607	return tape_mtop(device, MTOFFL, mt_count);608}609 610/*611 * MTCOMPRESSION: used to enable compression.612 * Sets the IDRC on/off.613 */614int615tape_std_mtcompression(struct tape_device *device, int mt_count)616{617	struct tape_request *request;618 619	if (mt_count < 0 || mt_count > 1) {620		DBF_EXCEPTION(6, "xcom parm\n");621		return -EINVAL;622	}623	request = tape_alloc_request(2, 0);624	if (IS_ERR(request))625		return PTR_ERR(request);626	request->op = TO_NOP;627	/* setup ccws */628	if (mt_count == 0)629		*device->modeset_byte &= ~0x08;630	else631		*device->modeset_byte |= 0x08;632	tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);633	tape_ccw_end(request->cpaddr + 1, NOP, 0, NULL);634	/* execute it */635	return tape_do_io_free(device, request);636}637 638/*639 * Read Block640 */641struct tape_request *642tape_std_read_block(struct tape_device *device, size_t count)643{644	struct tape_request *request;645 646	/*647	 * We have to alloc 4 ccws in order to be able to transform request648	 * into a read backward request in error case.649	 */650	request = tape_alloc_request(4, 0);651	if (IS_ERR(request)) {652		DBF_EXCEPTION(6, "xrbl fail");653		return request;654	}655	request->op = TO_RFO;656	tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);657	tape_ccw_end_idal(request->cpaddr + 1, READ_FORWARD,658			  device->char_data.idal_buf);659	DBF_EVENT(6, "xrbl ccwg\n");660	return request;661}662 663/*664 * Read Block backward transformation function.665 */666void667tape_std_read_backward(struct tape_device *device, struct tape_request *request)668{669	/*670	 * We have allocated 4 ccws in tape_std_read, so we can now671	 * transform the request to a read backward, followed by a672	 * forward space block.673	 */674	request->op = TO_RBA;675	tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);676	tape_ccw_cc_idal(request->cpaddr + 1, READ_BACKWARD,677			 device->char_data.idal_buf);678	tape_ccw_cc(request->cpaddr + 2, FORSPACEBLOCK, 0, NULL);679	tape_ccw_end(request->cpaddr + 3, NOP, 0, NULL);680	DBF_EVENT(6, "xrop ccwg");}681 682/*683 * Write Block684 */685struct tape_request *686tape_std_write_block(struct tape_device *device, size_t count)687{688	struct tape_request *request;689 690	request = tape_alloc_request(2, 0);691	if (IS_ERR(request)) {692		DBF_EXCEPTION(6, "xwbl fail\n");693		return request;694	}695	request->op = TO_WRI;696	tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);697	tape_ccw_end_idal(request->cpaddr + 1, WRITE_CMD,698			  device->char_data.idal_buf);699	DBF_EVENT(6, "xwbl ccwg\n");700	return request;701}702 703/*704 * This routine is called by frontend after an ENOSP on write705 */706void707tape_std_process_eov(struct tape_device *device)708{709	/*710	 * End of volume: We have to backspace the last written record, then711	 * we TRY to write a tapemark and then backspace over the written TM712	 */713	if (tape_mtop(device, MTBSR, 1) == 0 &&714	    tape_mtop(device, MTWEOF, 1) == 0) {715		tape_mtop(device, MTBSR, 1);716	}717}718 719EXPORT_SYMBOL(tape_std_assign);720EXPORT_SYMBOL(tape_std_unassign);721EXPORT_SYMBOL(tape_std_display);722EXPORT_SYMBOL(tape_std_read_block_id);723EXPORT_SYMBOL(tape_std_mtload);724EXPORT_SYMBOL(tape_std_mtsetblk);725EXPORT_SYMBOL(tape_std_mtreset);726EXPORT_SYMBOL(tape_std_mtfsf);727EXPORT_SYMBOL(tape_std_mtfsr);728EXPORT_SYMBOL(tape_std_mtbsr);729EXPORT_SYMBOL(tape_std_mtweof);730EXPORT_SYMBOL(tape_std_mtbsfm);731EXPORT_SYMBOL(tape_std_mtbsf);732EXPORT_SYMBOL(tape_std_mtfsfm);733EXPORT_SYMBOL(tape_std_mtrew);734EXPORT_SYMBOL(tape_std_mtoffl);735EXPORT_SYMBOL(tape_std_mtnop);736EXPORT_SYMBOL(tape_std_mteom);737EXPORT_SYMBOL(tape_std_mtreten);738EXPORT_SYMBOL(tape_std_mterase);739EXPORT_SYMBOL(tape_std_mtunload);740EXPORT_SYMBOL(tape_std_mtcompression);741EXPORT_SYMBOL(tape_std_read_block);742EXPORT_SYMBOL(tape_std_read_backward);743EXPORT_SYMBOL(tape_std_write_block);744EXPORT_SYMBOL(tape_std_process_eov);745