18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *    standard tape device functions for ibm tapes.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  S390 and zSeries version
68c2ecf20Sopenharmony_ci *    Copyright IBM Corp. 2001, 2002
78c2ecf20Sopenharmony_ci *    Author(s): Carsten Otte <cotte@de.ibm.com>
88c2ecf20Sopenharmony_ci *		 Michael Holzheu <holzheu@de.ibm.com>
98c2ecf20Sopenharmony_ci *		 Tuan Ngo-Anh <ngoanh@de.ibm.com>
108c2ecf20Sopenharmony_ci *		 Martin Schwidefsky <schwidefsky@de.ibm.com>
118c2ecf20Sopenharmony_ci *		 Stefan Bader <shbader@de.ibm.com>
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#define KMSG_COMPONENT "tape"
158c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <linux/stddef.h>
188c2ecf20Sopenharmony_ci#include <linux/kernel.h>
198c2ecf20Sopenharmony_ci#include <linux/bio.h>
208c2ecf20Sopenharmony_ci#include <linux/timer.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include <asm/types.h>
238c2ecf20Sopenharmony_ci#include <asm/idals.h>
248c2ecf20Sopenharmony_ci#include <asm/ebcdic.h>
258c2ecf20Sopenharmony_ci#include <asm/tape390.h>
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#define TAPE_DBF_AREA	tape_core_dbf
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#include "tape.h"
308c2ecf20Sopenharmony_ci#include "tape_std.h"
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci/*
338c2ecf20Sopenharmony_ci * tape_std_assign
348c2ecf20Sopenharmony_ci */
358c2ecf20Sopenharmony_cistatic void
368c2ecf20Sopenharmony_citape_std_assign_timeout(struct timer_list *t)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	struct tape_request *	request = from_timer(request, t, timer);
398c2ecf20Sopenharmony_ci	struct tape_device *	device = request->device;
408c2ecf20Sopenharmony_ci	int rc;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	BUG_ON(!device);
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	DBF_EVENT(3, "%08x: Assignment timeout. Device busy.\n",
458c2ecf20Sopenharmony_ci			device->cdev_id);
468c2ecf20Sopenharmony_ci	rc = tape_cancel_io(device, request);
478c2ecf20Sopenharmony_ci	if(rc)
488c2ecf20Sopenharmony_ci		DBF_EVENT(3, "(%08x): Assign timeout: Cancel failed with rc = "
498c2ecf20Sopenharmony_ci			  "%i\n", device->cdev_id, rc);
508c2ecf20Sopenharmony_ci}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ciint
538c2ecf20Sopenharmony_citape_std_assign(struct tape_device *device)
548c2ecf20Sopenharmony_ci{
558c2ecf20Sopenharmony_ci	int                  rc;
568c2ecf20Sopenharmony_ci	struct tape_request *request;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	request = tape_alloc_request(2, 11);
598c2ecf20Sopenharmony_ci	if (IS_ERR(request))
608c2ecf20Sopenharmony_ci		return PTR_ERR(request);
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	request->op = TO_ASSIGN;
638c2ecf20Sopenharmony_ci	tape_ccw_cc(request->cpaddr, ASSIGN, 11, request->cpdata);
648c2ecf20Sopenharmony_ci	tape_ccw_end(request->cpaddr + 1, NOP, 0, NULL);
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	/*
678c2ecf20Sopenharmony_ci	 * The assign command sometimes blocks if the device is assigned
688c2ecf20Sopenharmony_ci	 * to another host (actually this shouldn't happen but it does).
698c2ecf20Sopenharmony_ci	 * So we set up a timeout for this call.
708c2ecf20Sopenharmony_ci	 */
718c2ecf20Sopenharmony_ci	timer_setup(&request->timer, tape_std_assign_timeout, 0);
728c2ecf20Sopenharmony_ci	mod_timer(&request->timer, jiffies + msecs_to_jiffies(2000));
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	rc = tape_do_io_interruptible(device, request);
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	del_timer_sync(&request->timer);
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	if (rc != 0) {
798c2ecf20Sopenharmony_ci		DBF_EVENT(3, "%08x: assign failed - device might be busy\n",
808c2ecf20Sopenharmony_ci			device->cdev_id);
818c2ecf20Sopenharmony_ci	} else {
828c2ecf20Sopenharmony_ci		DBF_EVENT(3, "%08x: Tape assigned\n", device->cdev_id);
838c2ecf20Sopenharmony_ci	}
848c2ecf20Sopenharmony_ci	tape_free_request(request);
858c2ecf20Sopenharmony_ci	return rc;
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci/*
898c2ecf20Sopenharmony_ci * tape_std_unassign
908c2ecf20Sopenharmony_ci */
918c2ecf20Sopenharmony_ciint
928c2ecf20Sopenharmony_citape_std_unassign (struct tape_device *device)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	int                  rc;
958c2ecf20Sopenharmony_ci	struct tape_request *request;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	if (device->tape_state == TS_NOT_OPER) {
988c2ecf20Sopenharmony_ci		DBF_EVENT(3, "(%08x): Can't unassign device\n",
998c2ecf20Sopenharmony_ci			device->cdev_id);
1008c2ecf20Sopenharmony_ci		return -EIO;
1018c2ecf20Sopenharmony_ci	}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	request = tape_alloc_request(2, 11);
1048c2ecf20Sopenharmony_ci	if (IS_ERR(request))
1058c2ecf20Sopenharmony_ci		return PTR_ERR(request);
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	request->op = TO_UNASSIGN;
1088c2ecf20Sopenharmony_ci	tape_ccw_cc(request->cpaddr, UNASSIGN, 11, request->cpdata);
1098c2ecf20Sopenharmony_ci	tape_ccw_end(request->cpaddr + 1, NOP, 0, NULL);
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	if ((rc = tape_do_io(device, request)) != 0) {
1128c2ecf20Sopenharmony_ci		DBF_EVENT(3, "%08x: Unassign failed\n", device->cdev_id);
1138c2ecf20Sopenharmony_ci	} else {
1148c2ecf20Sopenharmony_ci		DBF_EVENT(3, "%08x: Tape unassigned\n", device->cdev_id);
1158c2ecf20Sopenharmony_ci	}
1168c2ecf20Sopenharmony_ci	tape_free_request(request);
1178c2ecf20Sopenharmony_ci	return rc;
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci/*
1218c2ecf20Sopenharmony_ci * TAPE390_DISPLAY: Show a string on the tape display.
1228c2ecf20Sopenharmony_ci */
1238c2ecf20Sopenharmony_ciint
1248c2ecf20Sopenharmony_citape_std_display(struct tape_device *device, struct display_struct *disp)
1258c2ecf20Sopenharmony_ci{
1268c2ecf20Sopenharmony_ci	struct tape_request *request;
1278c2ecf20Sopenharmony_ci	int rc;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	request = tape_alloc_request(2, 17);
1308c2ecf20Sopenharmony_ci	if (IS_ERR(request)) {
1318c2ecf20Sopenharmony_ci		DBF_EVENT(3, "TAPE: load display failed\n");
1328c2ecf20Sopenharmony_ci		return PTR_ERR(request);
1338c2ecf20Sopenharmony_ci	}
1348c2ecf20Sopenharmony_ci	request->op = TO_DIS;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	*(unsigned char *) request->cpdata = disp->cntrl;
1378c2ecf20Sopenharmony_ci	DBF_EVENT(5, "TAPE: display cntrl=%04x\n", disp->cntrl);
1388c2ecf20Sopenharmony_ci	memcpy(((unsigned char *) request->cpdata) + 1, disp->message1, 8);
1398c2ecf20Sopenharmony_ci	memcpy(((unsigned char *) request->cpdata) + 9, disp->message2, 8);
1408c2ecf20Sopenharmony_ci	ASCEBC(((unsigned char*) request->cpdata) + 1, 16);
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	tape_ccw_cc(request->cpaddr, LOAD_DISPLAY, 17, request->cpdata);
1438c2ecf20Sopenharmony_ci	tape_ccw_end(request->cpaddr + 1, NOP, 0, NULL);
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	rc = tape_do_io_interruptible(device, request);
1468c2ecf20Sopenharmony_ci	tape_free_request(request);
1478c2ecf20Sopenharmony_ci	return rc;
1488c2ecf20Sopenharmony_ci}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci/*
1518c2ecf20Sopenharmony_ci * Read block id.
1528c2ecf20Sopenharmony_ci */
1538c2ecf20Sopenharmony_ciint
1548c2ecf20Sopenharmony_citape_std_read_block_id(struct tape_device *device, __u64 *id)
1558c2ecf20Sopenharmony_ci{
1568c2ecf20Sopenharmony_ci	struct tape_request *request;
1578c2ecf20Sopenharmony_ci	int rc;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	request = tape_alloc_request(3, 8);
1608c2ecf20Sopenharmony_ci	if (IS_ERR(request))
1618c2ecf20Sopenharmony_ci		return PTR_ERR(request);
1628c2ecf20Sopenharmony_ci	request->op = TO_RBI;
1638c2ecf20Sopenharmony_ci	/* setup ccws */
1648c2ecf20Sopenharmony_ci	tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
1658c2ecf20Sopenharmony_ci	tape_ccw_cc(request->cpaddr + 1, READ_BLOCK_ID, 8, request->cpdata);
1668c2ecf20Sopenharmony_ci	tape_ccw_end(request->cpaddr + 2, NOP, 0, NULL);
1678c2ecf20Sopenharmony_ci	/* execute it */
1688c2ecf20Sopenharmony_ci	rc = tape_do_io(device, request);
1698c2ecf20Sopenharmony_ci	if (rc == 0)
1708c2ecf20Sopenharmony_ci		/* Get result from read buffer. */
1718c2ecf20Sopenharmony_ci		*id = *(__u64 *) request->cpdata;
1728c2ecf20Sopenharmony_ci	tape_free_request(request);
1738c2ecf20Sopenharmony_ci	return rc;
1748c2ecf20Sopenharmony_ci}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ciint
1778c2ecf20Sopenharmony_citape_std_terminate_write(struct tape_device *device)
1788c2ecf20Sopenharmony_ci{
1798c2ecf20Sopenharmony_ci	int rc;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	if(device->required_tapemarks == 0)
1828c2ecf20Sopenharmony_ci		return 0;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	DBF_LH(5, "tape%d: terminate write %dxEOF\n", device->first_minor,
1858c2ecf20Sopenharmony_ci		device->required_tapemarks);
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	rc = tape_mtop(device, MTWEOF, device->required_tapemarks);
1888c2ecf20Sopenharmony_ci	if (rc)
1898c2ecf20Sopenharmony_ci		return rc;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	device->required_tapemarks = 0;
1928c2ecf20Sopenharmony_ci	return tape_mtop(device, MTBSR, 1);
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci/*
1968c2ecf20Sopenharmony_ci * MTLOAD: Loads the tape.
1978c2ecf20Sopenharmony_ci * The default implementation just wait until the tape medium state changes
1988c2ecf20Sopenharmony_ci * to MS_LOADED.
1998c2ecf20Sopenharmony_ci */
2008c2ecf20Sopenharmony_ciint
2018c2ecf20Sopenharmony_citape_std_mtload(struct tape_device *device, int count)
2028c2ecf20Sopenharmony_ci{
2038c2ecf20Sopenharmony_ci	return wait_event_interruptible(device->state_change_wq,
2048c2ecf20Sopenharmony_ci		(device->medium_state == MS_LOADED));
2058c2ecf20Sopenharmony_ci}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci/*
2088c2ecf20Sopenharmony_ci * MTSETBLK: Set block size.
2098c2ecf20Sopenharmony_ci */
2108c2ecf20Sopenharmony_ciint
2118c2ecf20Sopenharmony_citape_std_mtsetblk(struct tape_device *device, int count)
2128c2ecf20Sopenharmony_ci{
2138c2ecf20Sopenharmony_ci	struct idal_buffer *new;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	DBF_LH(6, "tape_std_mtsetblk(%d)\n", count);
2168c2ecf20Sopenharmony_ci	if (count <= 0) {
2178c2ecf20Sopenharmony_ci		/*
2188c2ecf20Sopenharmony_ci		 * Just set block_size to 0. tapechar_read/tapechar_write
2198c2ecf20Sopenharmony_ci		 * will realloc the idal buffer if a bigger one than the
2208c2ecf20Sopenharmony_ci		 * current is needed.
2218c2ecf20Sopenharmony_ci		 */
2228c2ecf20Sopenharmony_ci		device->char_data.block_size = 0;
2238c2ecf20Sopenharmony_ci		return 0;
2248c2ecf20Sopenharmony_ci	}
2258c2ecf20Sopenharmony_ci	if (device->char_data.idal_buf != NULL &&
2268c2ecf20Sopenharmony_ci	    device->char_data.idal_buf->size == count)
2278c2ecf20Sopenharmony_ci		/* We already have a idal buffer of that size. */
2288c2ecf20Sopenharmony_ci		return 0;
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	if (count > MAX_BLOCKSIZE) {
2318c2ecf20Sopenharmony_ci		DBF_EVENT(3, "Invalid block size (%d > %d) given.\n",
2328c2ecf20Sopenharmony_ci			count, MAX_BLOCKSIZE);
2338c2ecf20Sopenharmony_ci		return -EINVAL;
2348c2ecf20Sopenharmony_ci	}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	/* Allocate a new idal buffer. */
2378c2ecf20Sopenharmony_ci	new = idal_buffer_alloc(count, 0);
2388c2ecf20Sopenharmony_ci	if (IS_ERR(new))
2398c2ecf20Sopenharmony_ci		return -ENOMEM;
2408c2ecf20Sopenharmony_ci	if (device->char_data.idal_buf != NULL)
2418c2ecf20Sopenharmony_ci		idal_buffer_free(device->char_data.idal_buf);
2428c2ecf20Sopenharmony_ci	device->char_data.idal_buf = new;
2438c2ecf20Sopenharmony_ci	device->char_data.block_size = count;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	DBF_LH(6, "new blocksize is %d\n", device->char_data.block_size);
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	return 0;
2488c2ecf20Sopenharmony_ci}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci/*
2518c2ecf20Sopenharmony_ci * MTRESET: Set block size to 0.
2528c2ecf20Sopenharmony_ci */
2538c2ecf20Sopenharmony_ciint
2548c2ecf20Sopenharmony_citape_std_mtreset(struct tape_device *device, int count)
2558c2ecf20Sopenharmony_ci{
2568c2ecf20Sopenharmony_ci	DBF_EVENT(6, "TCHAR:devreset:\n");
2578c2ecf20Sopenharmony_ci	device->char_data.block_size = 0;
2588c2ecf20Sopenharmony_ci	return 0;
2598c2ecf20Sopenharmony_ci}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci/*
2628c2ecf20Sopenharmony_ci * MTFSF: Forward space over 'count' file marks. The tape is positioned
2638c2ecf20Sopenharmony_ci * at the EOT (End of Tape) side of the file mark.
2648c2ecf20Sopenharmony_ci */
2658c2ecf20Sopenharmony_ciint
2668c2ecf20Sopenharmony_citape_std_mtfsf(struct tape_device *device, int mt_count)
2678c2ecf20Sopenharmony_ci{
2688c2ecf20Sopenharmony_ci	struct tape_request *request;
2698c2ecf20Sopenharmony_ci	struct ccw1 *ccw;
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	request = tape_alloc_request(mt_count + 2, 0);
2728c2ecf20Sopenharmony_ci	if (IS_ERR(request))
2738c2ecf20Sopenharmony_ci		return PTR_ERR(request);
2748c2ecf20Sopenharmony_ci	request->op = TO_FSF;
2758c2ecf20Sopenharmony_ci	/* setup ccws */
2768c2ecf20Sopenharmony_ci	ccw = tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1,
2778c2ecf20Sopenharmony_ci			  device->modeset_byte);
2788c2ecf20Sopenharmony_ci	ccw = tape_ccw_repeat(ccw, FORSPACEFILE, mt_count);
2798c2ecf20Sopenharmony_ci	ccw = tape_ccw_end(ccw, NOP, 0, NULL);
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	/* execute it */
2828c2ecf20Sopenharmony_ci	return tape_do_io_free(device, request);
2838c2ecf20Sopenharmony_ci}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci/*
2868c2ecf20Sopenharmony_ci * MTFSR: Forward space over 'count' tape blocks (blocksize is set
2878c2ecf20Sopenharmony_ci * via MTSETBLK.
2888c2ecf20Sopenharmony_ci */
2898c2ecf20Sopenharmony_ciint
2908c2ecf20Sopenharmony_citape_std_mtfsr(struct tape_device *device, int mt_count)
2918c2ecf20Sopenharmony_ci{
2928c2ecf20Sopenharmony_ci	struct tape_request *request;
2938c2ecf20Sopenharmony_ci	struct ccw1 *ccw;
2948c2ecf20Sopenharmony_ci	int rc;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	request = tape_alloc_request(mt_count + 2, 0);
2978c2ecf20Sopenharmony_ci	if (IS_ERR(request))
2988c2ecf20Sopenharmony_ci		return PTR_ERR(request);
2998c2ecf20Sopenharmony_ci	request->op = TO_FSB;
3008c2ecf20Sopenharmony_ci	/* setup ccws */
3018c2ecf20Sopenharmony_ci	ccw = tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1,
3028c2ecf20Sopenharmony_ci			  device->modeset_byte);
3038c2ecf20Sopenharmony_ci	ccw = tape_ccw_repeat(ccw, FORSPACEBLOCK, mt_count);
3048c2ecf20Sopenharmony_ci	ccw = tape_ccw_end(ccw, NOP, 0, NULL);
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	/* execute it */
3078c2ecf20Sopenharmony_ci	rc = tape_do_io(device, request);
3088c2ecf20Sopenharmony_ci	if (rc == 0 && request->rescnt > 0) {
3098c2ecf20Sopenharmony_ci		DBF_LH(3, "FSR over tapemark\n");
3108c2ecf20Sopenharmony_ci		rc = 1;
3118c2ecf20Sopenharmony_ci	}
3128c2ecf20Sopenharmony_ci	tape_free_request(request);
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	return rc;
3158c2ecf20Sopenharmony_ci}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci/*
3188c2ecf20Sopenharmony_ci * MTBSR: Backward space over 'count' tape blocks.
3198c2ecf20Sopenharmony_ci * (blocksize is set via MTSETBLK.
3208c2ecf20Sopenharmony_ci */
3218c2ecf20Sopenharmony_ciint
3228c2ecf20Sopenharmony_citape_std_mtbsr(struct tape_device *device, int mt_count)
3238c2ecf20Sopenharmony_ci{
3248c2ecf20Sopenharmony_ci	struct tape_request *request;
3258c2ecf20Sopenharmony_ci	struct ccw1 *ccw;
3268c2ecf20Sopenharmony_ci	int rc;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	request = tape_alloc_request(mt_count + 2, 0);
3298c2ecf20Sopenharmony_ci	if (IS_ERR(request))
3308c2ecf20Sopenharmony_ci		return PTR_ERR(request);
3318c2ecf20Sopenharmony_ci	request->op = TO_BSB;
3328c2ecf20Sopenharmony_ci	/* setup ccws */
3338c2ecf20Sopenharmony_ci	ccw = tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1,
3348c2ecf20Sopenharmony_ci			  device->modeset_byte);
3358c2ecf20Sopenharmony_ci	ccw = tape_ccw_repeat(ccw, BACKSPACEBLOCK, mt_count);
3368c2ecf20Sopenharmony_ci	ccw = tape_ccw_end(ccw, NOP, 0, NULL);
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	/* execute it */
3398c2ecf20Sopenharmony_ci	rc = tape_do_io(device, request);
3408c2ecf20Sopenharmony_ci	if (rc == 0 && request->rescnt > 0) {
3418c2ecf20Sopenharmony_ci		DBF_LH(3, "BSR over tapemark\n");
3428c2ecf20Sopenharmony_ci		rc = 1;
3438c2ecf20Sopenharmony_ci	}
3448c2ecf20Sopenharmony_ci	tape_free_request(request);
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	return rc;
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci/*
3508c2ecf20Sopenharmony_ci * MTWEOF: Write 'count' file marks at the current position.
3518c2ecf20Sopenharmony_ci */
3528c2ecf20Sopenharmony_ciint
3538c2ecf20Sopenharmony_citape_std_mtweof(struct tape_device *device, int mt_count)
3548c2ecf20Sopenharmony_ci{
3558c2ecf20Sopenharmony_ci	struct tape_request *request;
3568c2ecf20Sopenharmony_ci	struct ccw1 *ccw;
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	request = tape_alloc_request(mt_count + 2, 0);
3598c2ecf20Sopenharmony_ci	if (IS_ERR(request))
3608c2ecf20Sopenharmony_ci		return PTR_ERR(request);
3618c2ecf20Sopenharmony_ci	request->op = TO_WTM;
3628c2ecf20Sopenharmony_ci	/* setup ccws */
3638c2ecf20Sopenharmony_ci	ccw = tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1,
3648c2ecf20Sopenharmony_ci			  device->modeset_byte);
3658c2ecf20Sopenharmony_ci	ccw = tape_ccw_repeat(ccw, WRITETAPEMARK, mt_count);
3668c2ecf20Sopenharmony_ci	ccw = tape_ccw_end(ccw, NOP, 0, NULL);
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	/* execute it */
3698c2ecf20Sopenharmony_ci	return tape_do_io_free(device, request);
3708c2ecf20Sopenharmony_ci}
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci/*
3738c2ecf20Sopenharmony_ci * MTBSFM: Backward space over 'count' file marks.
3748c2ecf20Sopenharmony_ci * The tape is positioned at the BOT (Begin Of Tape) side of the
3758c2ecf20Sopenharmony_ci * last skipped file mark.
3768c2ecf20Sopenharmony_ci */
3778c2ecf20Sopenharmony_ciint
3788c2ecf20Sopenharmony_citape_std_mtbsfm(struct tape_device *device, int mt_count)
3798c2ecf20Sopenharmony_ci{
3808c2ecf20Sopenharmony_ci	struct tape_request *request;
3818c2ecf20Sopenharmony_ci	struct ccw1 *ccw;
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	request = tape_alloc_request(mt_count + 2, 0);
3848c2ecf20Sopenharmony_ci	if (IS_ERR(request))
3858c2ecf20Sopenharmony_ci		return PTR_ERR(request);
3868c2ecf20Sopenharmony_ci	request->op = TO_BSF;
3878c2ecf20Sopenharmony_ci	/* setup ccws */
3888c2ecf20Sopenharmony_ci	ccw = tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1,
3898c2ecf20Sopenharmony_ci			  device->modeset_byte);
3908c2ecf20Sopenharmony_ci	ccw = tape_ccw_repeat(ccw, BACKSPACEFILE, mt_count);
3918c2ecf20Sopenharmony_ci	ccw = tape_ccw_end(ccw, NOP, 0, NULL);
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	/* execute it */
3948c2ecf20Sopenharmony_ci	return tape_do_io_free(device, request);
3958c2ecf20Sopenharmony_ci}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci/*
3988c2ecf20Sopenharmony_ci * MTBSF: Backward space over 'count' file marks. The tape is positioned at
3998c2ecf20Sopenharmony_ci * the EOT (End of Tape) side of the last skipped file mark.
4008c2ecf20Sopenharmony_ci */
4018c2ecf20Sopenharmony_ciint
4028c2ecf20Sopenharmony_citape_std_mtbsf(struct tape_device *device, int mt_count)
4038c2ecf20Sopenharmony_ci{
4048c2ecf20Sopenharmony_ci	struct tape_request *request;
4058c2ecf20Sopenharmony_ci	struct ccw1 *ccw;
4068c2ecf20Sopenharmony_ci	int rc;
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	request = tape_alloc_request(mt_count + 2, 0);
4098c2ecf20Sopenharmony_ci	if (IS_ERR(request))
4108c2ecf20Sopenharmony_ci		return PTR_ERR(request);
4118c2ecf20Sopenharmony_ci	request->op = TO_BSF;
4128c2ecf20Sopenharmony_ci	/* setup ccws */
4138c2ecf20Sopenharmony_ci	ccw = tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1,
4148c2ecf20Sopenharmony_ci			  device->modeset_byte);
4158c2ecf20Sopenharmony_ci	ccw = tape_ccw_repeat(ccw, BACKSPACEFILE, mt_count);
4168c2ecf20Sopenharmony_ci	ccw = tape_ccw_end(ccw, NOP, 0, NULL);
4178c2ecf20Sopenharmony_ci	/* execute it */
4188c2ecf20Sopenharmony_ci	rc = tape_do_io_free(device, request);
4198c2ecf20Sopenharmony_ci	if (rc == 0) {
4208c2ecf20Sopenharmony_ci		rc = tape_mtop(device, MTFSR, 1);
4218c2ecf20Sopenharmony_ci		if (rc > 0)
4228c2ecf20Sopenharmony_ci			rc = 0;
4238c2ecf20Sopenharmony_ci	}
4248c2ecf20Sopenharmony_ci	return rc;
4258c2ecf20Sopenharmony_ci}
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci/*
4288c2ecf20Sopenharmony_ci * MTFSFM: Forward space over 'count' file marks.
4298c2ecf20Sopenharmony_ci * The tape is positioned at the BOT (Begin Of Tape) side
4308c2ecf20Sopenharmony_ci * of the last skipped file mark.
4318c2ecf20Sopenharmony_ci */
4328c2ecf20Sopenharmony_ciint
4338c2ecf20Sopenharmony_citape_std_mtfsfm(struct tape_device *device, int mt_count)
4348c2ecf20Sopenharmony_ci{
4358c2ecf20Sopenharmony_ci	struct tape_request *request;
4368c2ecf20Sopenharmony_ci	struct ccw1 *ccw;
4378c2ecf20Sopenharmony_ci	int rc;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	request = tape_alloc_request(mt_count + 2, 0);
4408c2ecf20Sopenharmony_ci	if (IS_ERR(request))
4418c2ecf20Sopenharmony_ci		return PTR_ERR(request);
4428c2ecf20Sopenharmony_ci	request->op = TO_FSF;
4438c2ecf20Sopenharmony_ci	/* setup ccws */
4448c2ecf20Sopenharmony_ci	ccw = tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1,
4458c2ecf20Sopenharmony_ci			  device->modeset_byte);
4468c2ecf20Sopenharmony_ci	ccw = tape_ccw_repeat(ccw, FORSPACEFILE, mt_count);
4478c2ecf20Sopenharmony_ci	ccw = tape_ccw_end(ccw, NOP, 0, NULL);
4488c2ecf20Sopenharmony_ci	/* execute it */
4498c2ecf20Sopenharmony_ci	rc = tape_do_io_free(device, request);
4508c2ecf20Sopenharmony_ci	if (rc == 0) {
4518c2ecf20Sopenharmony_ci		rc = tape_mtop(device, MTBSR, 1);
4528c2ecf20Sopenharmony_ci		if (rc > 0)
4538c2ecf20Sopenharmony_ci			rc = 0;
4548c2ecf20Sopenharmony_ci	}
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	return rc;
4578c2ecf20Sopenharmony_ci}
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci/*
4608c2ecf20Sopenharmony_ci * MTREW: Rewind the tape.
4618c2ecf20Sopenharmony_ci */
4628c2ecf20Sopenharmony_ciint
4638c2ecf20Sopenharmony_citape_std_mtrew(struct tape_device *device, int mt_count)
4648c2ecf20Sopenharmony_ci{
4658c2ecf20Sopenharmony_ci	struct tape_request *request;
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	request = tape_alloc_request(3, 0);
4688c2ecf20Sopenharmony_ci	if (IS_ERR(request))
4698c2ecf20Sopenharmony_ci		return PTR_ERR(request);
4708c2ecf20Sopenharmony_ci	request->op = TO_REW;
4718c2ecf20Sopenharmony_ci	/* setup ccws */
4728c2ecf20Sopenharmony_ci	tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1,
4738c2ecf20Sopenharmony_ci		    device->modeset_byte);
4748c2ecf20Sopenharmony_ci	tape_ccw_cc(request->cpaddr + 1, REWIND, 0, NULL);
4758c2ecf20Sopenharmony_ci	tape_ccw_end(request->cpaddr + 2, NOP, 0, NULL);
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	/* execute it */
4788c2ecf20Sopenharmony_ci	return tape_do_io_free(device, request);
4798c2ecf20Sopenharmony_ci}
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci/*
4828c2ecf20Sopenharmony_ci * MTOFFL: Rewind the tape and put the drive off-line.
4838c2ecf20Sopenharmony_ci * Implement 'rewind unload'
4848c2ecf20Sopenharmony_ci */
4858c2ecf20Sopenharmony_ciint
4868c2ecf20Sopenharmony_citape_std_mtoffl(struct tape_device *device, int mt_count)
4878c2ecf20Sopenharmony_ci{
4888c2ecf20Sopenharmony_ci	struct tape_request *request;
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	request = tape_alloc_request(3, 0);
4918c2ecf20Sopenharmony_ci	if (IS_ERR(request))
4928c2ecf20Sopenharmony_ci		return PTR_ERR(request);
4938c2ecf20Sopenharmony_ci	request->op = TO_RUN;
4948c2ecf20Sopenharmony_ci	/* setup ccws */
4958c2ecf20Sopenharmony_ci	tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
4968c2ecf20Sopenharmony_ci	tape_ccw_cc(request->cpaddr + 1, REWIND_UNLOAD, 0, NULL);
4978c2ecf20Sopenharmony_ci	tape_ccw_end(request->cpaddr + 2, NOP, 0, NULL);
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	/* execute it */
5008c2ecf20Sopenharmony_ci	return tape_do_io_free(device, request);
5018c2ecf20Sopenharmony_ci}
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci/*
5048c2ecf20Sopenharmony_ci * MTNOP: 'No operation'.
5058c2ecf20Sopenharmony_ci */
5068c2ecf20Sopenharmony_ciint
5078c2ecf20Sopenharmony_citape_std_mtnop(struct tape_device *device, int mt_count)
5088c2ecf20Sopenharmony_ci{
5098c2ecf20Sopenharmony_ci	struct tape_request *request;
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	request = tape_alloc_request(2, 0);
5128c2ecf20Sopenharmony_ci	if (IS_ERR(request))
5138c2ecf20Sopenharmony_ci		return PTR_ERR(request);
5148c2ecf20Sopenharmony_ci	request->op = TO_NOP;
5158c2ecf20Sopenharmony_ci	/* setup ccws */
5168c2ecf20Sopenharmony_ci	tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
5178c2ecf20Sopenharmony_ci	tape_ccw_end(request->cpaddr + 1, NOP, 0, NULL);
5188c2ecf20Sopenharmony_ci	/* execute it */
5198c2ecf20Sopenharmony_ci	return tape_do_io_free(device, request);
5208c2ecf20Sopenharmony_ci}
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci/*
5238c2ecf20Sopenharmony_ci * MTEOM: positions at the end of the portion of the tape already used
5248c2ecf20Sopenharmony_ci * for recordind data. MTEOM positions after the last file mark, ready for
5258c2ecf20Sopenharmony_ci * appending another file.
5268c2ecf20Sopenharmony_ci */
5278c2ecf20Sopenharmony_ciint
5288c2ecf20Sopenharmony_citape_std_mteom(struct tape_device *device, int mt_count)
5298c2ecf20Sopenharmony_ci{
5308c2ecf20Sopenharmony_ci	int rc;
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	/*
5338c2ecf20Sopenharmony_ci	 * Seek from the beginning of tape (rewind).
5348c2ecf20Sopenharmony_ci	 */
5358c2ecf20Sopenharmony_ci	if ((rc = tape_mtop(device, MTREW, 1)) < 0)
5368c2ecf20Sopenharmony_ci		return rc;
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	/*
5398c2ecf20Sopenharmony_ci	 * The logical end of volume is given by two sewuential tapemarks.
5408c2ecf20Sopenharmony_ci	 * Look for this by skipping to the next file (over one tapemark)
5418c2ecf20Sopenharmony_ci	 * and then test for another one (fsr returns 1 if a tapemark was
5428c2ecf20Sopenharmony_ci	 * encountered).
5438c2ecf20Sopenharmony_ci	 */
5448c2ecf20Sopenharmony_ci	do {
5458c2ecf20Sopenharmony_ci		if ((rc = tape_mtop(device, MTFSF, 1)) < 0)
5468c2ecf20Sopenharmony_ci			return rc;
5478c2ecf20Sopenharmony_ci		if ((rc = tape_mtop(device, MTFSR, 1)) < 0)
5488c2ecf20Sopenharmony_ci			return rc;
5498c2ecf20Sopenharmony_ci	} while (rc == 0);
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	return tape_mtop(device, MTBSR, 1);
5528c2ecf20Sopenharmony_ci}
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci/*
5558c2ecf20Sopenharmony_ci * MTRETEN: Retension the tape, i.e. forward space to end of tape and rewind.
5568c2ecf20Sopenharmony_ci */
5578c2ecf20Sopenharmony_ciint
5588c2ecf20Sopenharmony_citape_std_mtreten(struct tape_device *device, int mt_count)
5598c2ecf20Sopenharmony_ci{
5608c2ecf20Sopenharmony_ci	struct tape_request *request;
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	request = tape_alloc_request(4, 0);
5638c2ecf20Sopenharmony_ci	if (IS_ERR(request))
5648c2ecf20Sopenharmony_ci		return PTR_ERR(request);
5658c2ecf20Sopenharmony_ci	request->op = TO_FSF;
5668c2ecf20Sopenharmony_ci	/* setup ccws */
5678c2ecf20Sopenharmony_ci	tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
5688c2ecf20Sopenharmony_ci	tape_ccw_cc(request->cpaddr + 1,FORSPACEFILE, 0, NULL);
5698c2ecf20Sopenharmony_ci	tape_ccw_cc(request->cpaddr + 2, NOP, 0, NULL);
5708c2ecf20Sopenharmony_ci	tape_ccw_end(request->cpaddr + 3, CCW_CMD_TIC, 0, request->cpaddr);
5718c2ecf20Sopenharmony_ci	/* execute it, MTRETEN rc gets ignored */
5728c2ecf20Sopenharmony_ci	tape_do_io_interruptible(device, request);
5738c2ecf20Sopenharmony_ci	tape_free_request(request);
5748c2ecf20Sopenharmony_ci	return tape_mtop(device, MTREW, 1);
5758c2ecf20Sopenharmony_ci}
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci/*
5788c2ecf20Sopenharmony_ci * MTERASE: erases the tape.
5798c2ecf20Sopenharmony_ci */
5808c2ecf20Sopenharmony_ciint
5818c2ecf20Sopenharmony_citape_std_mterase(struct tape_device *device, int mt_count)
5828c2ecf20Sopenharmony_ci{
5838c2ecf20Sopenharmony_ci	struct tape_request *request;
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	request = tape_alloc_request(6, 0);
5868c2ecf20Sopenharmony_ci	if (IS_ERR(request))
5878c2ecf20Sopenharmony_ci		return PTR_ERR(request);
5888c2ecf20Sopenharmony_ci	request->op = TO_DSE;
5898c2ecf20Sopenharmony_ci	/* setup ccws */
5908c2ecf20Sopenharmony_ci	tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
5918c2ecf20Sopenharmony_ci	tape_ccw_cc(request->cpaddr + 1, REWIND, 0, NULL);
5928c2ecf20Sopenharmony_ci	tape_ccw_cc(request->cpaddr + 2, ERASE_GAP, 0, NULL);
5938c2ecf20Sopenharmony_ci	tape_ccw_cc(request->cpaddr + 3, DATA_SEC_ERASE, 0, NULL);
5948c2ecf20Sopenharmony_ci	tape_ccw_cc(request->cpaddr + 4, REWIND, 0, NULL);
5958c2ecf20Sopenharmony_ci	tape_ccw_end(request->cpaddr + 5, NOP, 0, NULL);
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	/* execute it */
5988c2ecf20Sopenharmony_ci	return tape_do_io_free(device, request);
5998c2ecf20Sopenharmony_ci}
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci/*
6028c2ecf20Sopenharmony_ci * MTUNLOAD: Rewind the tape and unload it.
6038c2ecf20Sopenharmony_ci */
6048c2ecf20Sopenharmony_ciint
6058c2ecf20Sopenharmony_citape_std_mtunload(struct tape_device *device, int mt_count)
6068c2ecf20Sopenharmony_ci{
6078c2ecf20Sopenharmony_ci	return tape_mtop(device, MTOFFL, mt_count);
6088c2ecf20Sopenharmony_ci}
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci/*
6118c2ecf20Sopenharmony_ci * MTCOMPRESSION: used to enable compression.
6128c2ecf20Sopenharmony_ci * Sets the IDRC on/off.
6138c2ecf20Sopenharmony_ci */
6148c2ecf20Sopenharmony_ciint
6158c2ecf20Sopenharmony_citape_std_mtcompression(struct tape_device *device, int mt_count)
6168c2ecf20Sopenharmony_ci{
6178c2ecf20Sopenharmony_ci	struct tape_request *request;
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	if (mt_count < 0 || mt_count > 1) {
6208c2ecf20Sopenharmony_ci		DBF_EXCEPTION(6, "xcom parm\n");
6218c2ecf20Sopenharmony_ci		return -EINVAL;
6228c2ecf20Sopenharmony_ci	}
6238c2ecf20Sopenharmony_ci	request = tape_alloc_request(2, 0);
6248c2ecf20Sopenharmony_ci	if (IS_ERR(request))
6258c2ecf20Sopenharmony_ci		return PTR_ERR(request);
6268c2ecf20Sopenharmony_ci	request->op = TO_NOP;
6278c2ecf20Sopenharmony_ci	/* setup ccws */
6288c2ecf20Sopenharmony_ci	if (mt_count == 0)
6298c2ecf20Sopenharmony_ci		*device->modeset_byte &= ~0x08;
6308c2ecf20Sopenharmony_ci	else
6318c2ecf20Sopenharmony_ci		*device->modeset_byte |= 0x08;
6328c2ecf20Sopenharmony_ci	tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
6338c2ecf20Sopenharmony_ci	tape_ccw_end(request->cpaddr + 1, NOP, 0, NULL);
6348c2ecf20Sopenharmony_ci	/* execute it */
6358c2ecf20Sopenharmony_ci	return tape_do_io_free(device, request);
6368c2ecf20Sopenharmony_ci}
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci/*
6398c2ecf20Sopenharmony_ci * Read Block
6408c2ecf20Sopenharmony_ci */
6418c2ecf20Sopenharmony_cistruct tape_request *
6428c2ecf20Sopenharmony_citape_std_read_block(struct tape_device *device, size_t count)
6438c2ecf20Sopenharmony_ci{
6448c2ecf20Sopenharmony_ci	struct tape_request *request;
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci	/*
6478c2ecf20Sopenharmony_ci	 * We have to alloc 4 ccws in order to be able to transform request
6488c2ecf20Sopenharmony_ci	 * into a read backward request in error case.
6498c2ecf20Sopenharmony_ci	 */
6508c2ecf20Sopenharmony_ci	request = tape_alloc_request(4, 0);
6518c2ecf20Sopenharmony_ci	if (IS_ERR(request)) {
6528c2ecf20Sopenharmony_ci		DBF_EXCEPTION(6, "xrbl fail");
6538c2ecf20Sopenharmony_ci		return request;
6548c2ecf20Sopenharmony_ci	}
6558c2ecf20Sopenharmony_ci	request->op = TO_RFO;
6568c2ecf20Sopenharmony_ci	tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
6578c2ecf20Sopenharmony_ci	tape_ccw_end_idal(request->cpaddr + 1, READ_FORWARD,
6588c2ecf20Sopenharmony_ci			  device->char_data.idal_buf);
6598c2ecf20Sopenharmony_ci	DBF_EVENT(6, "xrbl ccwg\n");
6608c2ecf20Sopenharmony_ci	return request;
6618c2ecf20Sopenharmony_ci}
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci/*
6648c2ecf20Sopenharmony_ci * Read Block backward transformation function.
6658c2ecf20Sopenharmony_ci */
6668c2ecf20Sopenharmony_civoid
6678c2ecf20Sopenharmony_citape_std_read_backward(struct tape_device *device, struct tape_request *request)
6688c2ecf20Sopenharmony_ci{
6698c2ecf20Sopenharmony_ci	/*
6708c2ecf20Sopenharmony_ci	 * We have allocated 4 ccws in tape_std_read, so we can now
6718c2ecf20Sopenharmony_ci	 * transform the request to a read backward, followed by a
6728c2ecf20Sopenharmony_ci	 * forward space block.
6738c2ecf20Sopenharmony_ci	 */
6748c2ecf20Sopenharmony_ci	request->op = TO_RBA;
6758c2ecf20Sopenharmony_ci	tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
6768c2ecf20Sopenharmony_ci	tape_ccw_cc_idal(request->cpaddr + 1, READ_BACKWARD,
6778c2ecf20Sopenharmony_ci			 device->char_data.idal_buf);
6788c2ecf20Sopenharmony_ci	tape_ccw_cc(request->cpaddr + 2, FORSPACEBLOCK, 0, NULL);
6798c2ecf20Sopenharmony_ci	tape_ccw_end(request->cpaddr + 3, NOP, 0, NULL);
6808c2ecf20Sopenharmony_ci	DBF_EVENT(6, "xrop ccwg");}
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci/*
6838c2ecf20Sopenharmony_ci * Write Block
6848c2ecf20Sopenharmony_ci */
6858c2ecf20Sopenharmony_cistruct tape_request *
6868c2ecf20Sopenharmony_citape_std_write_block(struct tape_device *device, size_t count)
6878c2ecf20Sopenharmony_ci{
6888c2ecf20Sopenharmony_ci	struct tape_request *request;
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci	request = tape_alloc_request(2, 0);
6918c2ecf20Sopenharmony_ci	if (IS_ERR(request)) {
6928c2ecf20Sopenharmony_ci		DBF_EXCEPTION(6, "xwbl fail\n");
6938c2ecf20Sopenharmony_ci		return request;
6948c2ecf20Sopenharmony_ci	}
6958c2ecf20Sopenharmony_ci	request->op = TO_WRI;
6968c2ecf20Sopenharmony_ci	tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
6978c2ecf20Sopenharmony_ci	tape_ccw_end_idal(request->cpaddr + 1, WRITE_CMD,
6988c2ecf20Sopenharmony_ci			  device->char_data.idal_buf);
6998c2ecf20Sopenharmony_ci	DBF_EVENT(6, "xwbl ccwg\n");
7008c2ecf20Sopenharmony_ci	return request;
7018c2ecf20Sopenharmony_ci}
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci/*
7048c2ecf20Sopenharmony_ci * This routine is called by frontend after an ENOSP on write
7058c2ecf20Sopenharmony_ci */
7068c2ecf20Sopenharmony_civoid
7078c2ecf20Sopenharmony_citape_std_process_eov(struct tape_device *device)
7088c2ecf20Sopenharmony_ci{
7098c2ecf20Sopenharmony_ci	/*
7108c2ecf20Sopenharmony_ci	 * End of volume: We have to backspace the last written record, then
7118c2ecf20Sopenharmony_ci	 * we TRY to write a tapemark and then backspace over the written TM
7128c2ecf20Sopenharmony_ci	 */
7138c2ecf20Sopenharmony_ci	if (tape_mtop(device, MTBSR, 1) == 0 &&
7148c2ecf20Sopenharmony_ci	    tape_mtop(device, MTWEOF, 1) == 0) {
7158c2ecf20Sopenharmony_ci		tape_mtop(device, MTBSR, 1);
7168c2ecf20Sopenharmony_ci	}
7178c2ecf20Sopenharmony_ci}
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tape_std_assign);
7208c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tape_std_unassign);
7218c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tape_std_display);
7228c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tape_std_read_block_id);
7238c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tape_std_mtload);
7248c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tape_std_mtsetblk);
7258c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tape_std_mtreset);
7268c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tape_std_mtfsf);
7278c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tape_std_mtfsr);
7288c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tape_std_mtbsr);
7298c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tape_std_mtweof);
7308c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tape_std_mtbsfm);
7318c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tape_std_mtbsf);
7328c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tape_std_mtfsfm);
7338c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tape_std_mtrew);
7348c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tape_std_mtoffl);
7358c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tape_std_mtnop);
7368c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tape_std_mteom);
7378c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tape_std_mtreten);
7388c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tape_std_mterase);
7398c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tape_std_mtunload);
7408c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tape_std_mtcompression);
7418c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tape_std_read_block);
7428c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tape_std_read_backward);
7438c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tape_std_write_block);
7448c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tape_std_process_eov);
745