162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *    standard tape device functions for ibm tapes.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  S390 and zSeries version
662306a36Sopenharmony_ci *    Copyright IBM Corp. 2001, 2002
762306a36Sopenharmony_ci *    Author(s): Carsten Otte <cotte@de.ibm.com>
862306a36Sopenharmony_ci *		 Michael Holzheu <holzheu@de.ibm.com>
962306a36Sopenharmony_ci *		 Tuan Ngo-Anh <ngoanh@de.ibm.com>
1062306a36Sopenharmony_ci *		 Martin Schwidefsky <schwidefsky@de.ibm.com>
1162306a36Sopenharmony_ci *		 Stefan Bader <shbader@de.ibm.com>
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#define KMSG_COMPONENT "tape"
1562306a36Sopenharmony_ci#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <linux/stddef.h>
1862306a36Sopenharmony_ci#include <linux/kernel.h>
1962306a36Sopenharmony_ci#include <linux/bio.h>
2062306a36Sopenharmony_ci#include <linux/timer.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#include <asm/types.h>
2362306a36Sopenharmony_ci#include <asm/idals.h>
2462306a36Sopenharmony_ci#include <asm/ebcdic.h>
2562306a36Sopenharmony_ci#include <asm/tape390.h>
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define TAPE_DBF_AREA	tape_core_dbf
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#include "tape.h"
3062306a36Sopenharmony_ci#include "tape_std.h"
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/*
3362306a36Sopenharmony_ci * tape_std_assign
3462306a36Sopenharmony_ci */
3562306a36Sopenharmony_cistatic void
3662306a36Sopenharmony_citape_std_assign_timeout(struct timer_list *t)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	struct tape_request *	request = from_timer(request, t, timer);
3962306a36Sopenharmony_ci	struct tape_device *	device = request->device;
4062306a36Sopenharmony_ci	int rc;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	BUG_ON(!device);
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	DBF_EVENT(3, "%08x: Assignment timeout. Device busy.\n",
4562306a36Sopenharmony_ci			device->cdev_id);
4662306a36Sopenharmony_ci	rc = tape_cancel_io(device, request);
4762306a36Sopenharmony_ci	if(rc)
4862306a36Sopenharmony_ci		DBF_EVENT(3, "(%08x): Assign timeout: Cancel failed with rc = "
4962306a36Sopenharmony_ci			  "%i\n", device->cdev_id, rc);
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ciint
5362306a36Sopenharmony_citape_std_assign(struct tape_device *device)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	int                  rc;
5662306a36Sopenharmony_ci	struct tape_request *request;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	request = tape_alloc_request(2, 11);
5962306a36Sopenharmony_ci	if (IS_ERR(request))
6062306a36Sopenharmony_ci		return PTR_ERR(request);
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	request->op = TO_ASSIGN;
6362306a36Sopenharmony_ci	tape_ccw_cc(request->cpaddr, ASSIGN, 11, request->cpdata);
6462306a36Sopenharmony_ci	tape_ccw_end(request->cpaddr + 1, NOP, 0, NULL);
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	/*
6762306a36Sopenharmony_ci	 * The assign command sometimes blocks if the device is assigned
6862306a36Sopenharmony_ci	 * to another host (actually this shouldn't happen but it does).
6962306a36Sopenharmony_ci	 * So we set up a timeout for this call.
7062306a36Sopenharmony_ci	 */
7162306a36Sopenharmony_ci	timer_setup(&request->timer, tape_std_assign_timeout, 0);
7262306a36Sopenharmony_ci	mod_timer(&request->timer, jiffies + msecs_to_jiffies(2000));
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	rc = tape_do_io_interruptible(device, request);
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	del_timer_sync(&request->timer);
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	if (rc != 0) {
7962306a36Sopenharmony_ci		DBF_EVENT(3, "%08x: assign failed - device might be busy\n",
8062306a36Sopenharmony_ci			device->cdev_id);
8162306a36Sopenharmony_ci	} else {
8262306a36Sopenharmony_ci		DBF_EVENT(3, "%08x: Tape assigned\n", device->cdev_id);
8362306a36Sopenharmony_ci	}
8462306a36Sopenharmony_ci	tape_free_request(request);
8562306a36Sopenharmony_ci	return rc;
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci/*
8962306a36Sopenharmony_ci * tape_std_unassign
9062306a36Sopenharmony_ci */
9162306a36Sopenharmony_ciint
9262306a36Sopenharmony_citape_std_unassign (struct tape_device *device)
9362306a36Sopenharmony_ci{
9462306a36Sopenharmony_ci	int                  rc;
9562306a36Sopenharmony_ci	struct tape_request *request;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	if (device->tape_state == TS_NOT_OPER) {
9862306a36Sopenharmony_ci		DBF_EVENT(3, "(%08x): Can't unassign device\n",
9962306a36Sopenharmony_ci			device->cdev_id);
10062306a36Sopenharmony_ci		return -EIO;
10162306a36Sopenharmony_ci	}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	request = tape_alloc_request(2, 11);
10462306a36Sopenharmony_ci	if (IS_ERR(request))
10562306a36Sopenharmony_ci		return PTR_ERR(request);
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	request->op = TO_UNASSIGN;
10862306a36Sopenharmony_ci	tape_ccw_cc(request->cpaddr, UNASSIGN, 11, request->cpdata);
10962306a36Sopenharmony_ci	tape_ccw_end(request->cpaddr + 1, NOP, 0, NULL);
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	if ((rc = tape_do_io(device, request)) != 0) {
11262306a36Sopenharmony_ci		DBF_EVENT(3, "%08x: Unassign failed\n", device->cdev_id);
11362306a36Sopenharmony_ci	} else {
11462306a36Sopenharmony_ci		DBF_EVENT(3, "%08x: Tape unassigned\n", device->cdev_id);
11562306a36Sopenharmony_ci	}
11662306a36Sopenharmony_ci	tape_free_request(request);
11762306a36Sopenharmony_ci	return rc;
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci/*
12162306a36Sopenharmony_ci * TAPE390_DISPLAY: Show a string on the tape display.
12262306a36Sopenharmony_ci */
12362306a36Sopenharmony_ciint
12462306a36Sopenharmony_citape_std_display(struct tape_device *device, struct display_struct *disp)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	struct tape_request *request;
12762306a36Sopenharmony_ci	int rc;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	request = tape_alloc_request(2, 17);
13062306a36Sopenharmony_ci	if (IS_ERR(request)) {
13162306a36Sopenharmony_ci		DBF_EVENT(3, "TAPE: load display failed\n");
13262306a36Sopenharmony_ci		return PTR_ERR(request);
13362306a36Sopenharmony_ci	}
13462306a36Sopenharmony_ci	request->op = TO_DIS;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	*(unsigned char *) request->cpdata = disp->cntrl;
13762306a36Sopenharmony_ci	DBF_EVENT(5, "TAPE: display cntrl=%04x\n", disp->cntrl);
13862306a36Sopenharmony_ci	memcpy(((unsigned char *) request->cpdata) + 1, disp->message1, 8);
13962306a36Sopenharmony_ci	memcpy(((unsigned char *) request->cpdata) + 9, disp->message2, 8);
14062306a36Sopenharmony_ci	ASCEBC(((unsigned char*) request->cpdata) + 1, 16);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	tape_ccw_cc(request->cpaddr, LOAD_DISPLAY, 17, request->cpdata);
14362306a36Sopenharmony_ci	tape_ccw_end(request->cpaddr + 1, NOP, 0, NULL);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	rc = tape_do_io_interruptible(device, request);
14662306a36Sopenharmony_ci	tape_free_request(request);
14762306a36Sopenharmony_ci	return rc;
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci/*
15162306a36Sopenharmony_ci * Read block id.
15262306a36Sopenharmony_ci */
15362306a36Sopenharmony_ciint
15462306a36Sopenharmony_citape_std_read_block_id(struct tape_device *device, __u64 *id)
15562306a36Sopenharmony_ci{
15662306a36Sopenharmony_ci	struct tape_request *request;
15762306a36Sopenharmony_ci	int rc;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	request = tape_alloc_request(3, 8);
16062306a36Sopenharmony_ci	if (IS_ERR(request))
16162306a36Sopenharmony_ci		return PTR_ERR(request);
16262306a36Sopenharmony_ci	request->op = TO_RBI;
16362306a36Sopenharmony_ci	/* setup ccws */
16462306a36Sopenharmony_ci	tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
16562306a36Sopenharmony_ci	tape_ccw_cc(request->cpaddr + 1, READ_BLOCK_ID, 8, request->cpdata);
16662306a36Sopenharmony_ci	tape_ccw_end(request->cpaddr + 2, NOP, 0, NULL);
16762306a36Sopenharmony_ci	/* execute it */
16862306a36Sopenharmony_ci	rc = tape_do_io(device, request);
16962306a36Sopenharmony_ci	if (rc == 0)
17062306a36Sopenharmony_ci		/* Get result from read buffer. */
17162306a36Sopenharmony_ci		*id = *(__u64 *) request->cpdata;
17262306a36Sopenharmony_ci	tape_free_request(request);
17362306a36Sopenharmony_ci	return rc;
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ciint
17762306a36Sopenharmony_citape_std_terminate_write(struct tape_device *device)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	int rc;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	if(device->required_tapemarks == 0)
18262306a36Sopenharmony_ci		return 0;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	DBF_LH(5, "tape%d: terminate write %dxEOF\n", device->first_minor,
18562306a36Sopenharmony_ci		device->required_tapemarks);
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	rc = tape_mtop(device, MTWEOF, device->required_tapemarks);
18862306a36Sopenharmony_ci	if (rc)
18962306a36Sopenharmony_ci		return rc;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	device->required_tapemarks = 0;
19262306a36Sopenharmony_ci	return tape_mtop(device, MTBSR, 1);
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci/*
19662306a36Sopenharmony_ci * MTLOAD: Loads the tape.
19762306a36Sopenharmony_ci * The default implementation just wait until the tape medium state changes
19862306a36Sopenharmony_ci * to MS_LOADED.
19962306a36Sopenharmony_ci */
20062306a36Sopenharmony_ciint
20162306a36Sopenharmony_citape_std_mtload(struct tape_device *device, int count)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	return wait_event_interruptible(device->state_change_wq,
20462306a36Sopenharmony_ci		(device->medium_state == MS_LOADED));
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci/*
20862306a36Sopenharmony_ci * MTSETBLK: Set block size.
20962306a36Sopenharmony_ci */
21062306a36Sopenharmony_ciint
21162306a36Sopenharmony_citape_std_mtsetblk(struct tape_device *device, int count)
21262306a36Sopenharmony_ci{
21362306a36Sopenharmony_ci	struct idal_buffer *new;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	DBF_LH(6, "tape_std_mtsetblk(%d)\n", count);
21662306a36Sopenharmony_ci	if (count <= 0) {
21762306a36Sopenharmony_ci		/*
21862306a36Sopenharmony_ci		 * Just set block_size to 0. tapechar_read/tapechar_write
21962306a36Sopenharmony_ci		 * will realloc the idal buffer if a bigger one than the
22062306a36Sopenharmony_ci		 * current is needed.
22162306a36Sopenharmony_ci		 */
22262306a36Sopenharmony_ci		device->char_data.block_size = 0;
22362306a36Sopenharmony_ci		return 0;
22462306a36Sopenharmony_ci	}
22562306a36Sopenharmony_ci	if (device->char_data.idal_buf != NULL &&
22662306a36Sopenharmony_ci	    device->char_data.idal_buf->size == count)
22762306a36Sopenharmony_ci		/* We already have a idal buffer of that size. */
22862306a36Sopenharmony_ci		return 0;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	if (count > MAX_BLOCKSIZE) {
23162306a36Sopenharmony_ci		DBF_EVENT(3, "Invalid block size (%d > %d) given.\n",
23262306a36Sopenharmony_ci			count, MAX_BLOCKSIZE);
23362306a36Sopenharmony_ci		return -EINVAL;
23462306a36Sopenharmony_ci	}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	/* Allocate a new idal buffer. */
23762306a36Sopenharmony_ci	new = idal_buffer_alloc(count, 0);
23862306a36Sopenharmony_ci	if (IS_ERR(new))
23962306a36Sopenharmony_ci		return -ENOMEM;
24062306a36Sopenharmony_ci	if (device->char_data.idal_buf != NULL)
24162306a36Sopenharmony_ci		idal_buffer_free(device->char_data.idal_buf);
24262306a36Sopenharmony_ci	device->char_data.idal_buf = new;
24362306a36Sopenharmony_ci	device->char_data.block_size = count;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	DBF_LH(6, "new blocksize is %d\n", device->char_data.block_size);
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	return 0;
24862306a36Sopenharmony_ci}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci/*
25162306a36Sopenharmony_ci * MTRESET: Set block size to 0.
25262306a36Sopenharmony_ci */
25362306a36Sopenharmony_ciint
25462306a36Sopenharmony_citape_std_mtreset(struct tape_device *device, int count)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	DBF_EVENT(6, "TCHAR:devreset:\n");
25762306a36Sopenharmony_ci	device->char_data.block_size = 0;
25862306a36Sopenharmony_ci	return 0;
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci/*
26262306a36Sopenharmony_ci * MTFSF: Forward space over 'count' file marks. The tape is positioned
26362306a36Sopenharmony_ci * at the EOT (End of Tape) side of the file mark.
26462306a36Sopenharmony_ci */
26562306a36Sopenharmony_ciint
26662306a36Sopenharmony_citape_std_mtfsf(struct tape_device *device, int mt_count)
26762306a36Sopenharmony_ci{
26862306a36Sopenharmony_ci	struct tape_request *request;
26962306a36Sopenharmony_ci	struct ccw1 *ccw;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	request = tape_alloc_request(mt_count + 2, 0);
27262306a36Sopenharmony_ci	if (IS_ERR(request))
27362306a36Sopenharmony_ci		return PTR_ERR(request);
27462306a36Sopenharmony_ci	request->op = TO_FSF;
27562306a36Sopenharmony_ci	/* setup ccws */
27662306a36Sopenharmony_ci	ccw = tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1,
27762306a36Sopenharmony_ci			  device->modeset_byte);
27862306a36Sopenharmony_ci	ccw = tape_ccw_repeat(ccw, FORSPACEFILE, mt_count);
27962306a36Sopenharmony_ci	ccw = tape_ccw_end(ccw, NOP, 0, NULL);
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	/* execute it */
28262306a36Sopenharmony_ci	return tape_do_io_free(device, request);
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci/*
28662306a36Sopenharmony_ci * MTFSR: Forward space over 'count' tape blocks (blocksize is set
28762306a36Sopenharmony_ci * via MTSETBLK.
28862306a36Sopenharmony_ci */
28962306a36Sopenharmony_ciint
29062306a36Sopenharmony_citape_std_mtfsr(struct tape_device *device, int mt_count)
29162306a36Sopenharmony_ci{
29262306a36Sopenharmony_ci	struct tape_request *request;
29362306a36Sopenharmony_ci	struct ccw1 *ccw;
29462306a36Sopenharmony_ci	int rc;
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	request = tape_alloc_request(mt_count + 2, 0);
29762306a36Sopenharmony_ci	if (IS_ERR(request))
29862306a36Sopenharmony_ci		return PTR_ERR(request);
29962306a36Sopenharmony_ci	request->op = TO_FSB;
30062306a36Sopenharmony_ci	/* setup ccws */
30162306a36Sopenharmony_ci	ccw = tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1,
30262306a36Sopenharmony_ci			  device->modeset_byte);
30362306a36Sopenharmony_ci	ccw = tape_ccw_repeat(ccw, FORSPACEBLOCK, mt_count);
30462306a36Sopenharmony_ci	ccw = tape_ccw_end(ccw, NOP, 0, NULL);
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	/* execute it */
30762306a36Sopenharmony_ci	rc = tape_do_io(device, request);
30862306a36Sopenharmony_ci	if (rc == 0 && request->rescnt > 0) {
30962306a36Sopenharmony_ci		DBF_LH(3, "FSR over tapemark\n");
31062306a36Sopenharmony_ci		rc = 1;
31162306a36Sopenharmony_ci	}
31262306a36Sopenharmony_ci	tape_free_request(request);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	return rc;
31562306a36Sopenharmony_ci}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci/*
31862306a36Sopenharmony_ci * MTBSR: Backward space over 'count' tape blocks.
31962306a36Sopenharmony_ci * (blocksize is set via MTSETBLK.
32062306a36Sopenharmony_ci */
32162306a36Sopenharmony_ciint
32262306a36Sopenharmony_citape_std_mtbsr(struct tape_device *device, int mt_count)
32362306a36Sopenharmony_ci{
32462306a36Sopenharmony_ci	struct tape_request *request;
32562306a36Sopenharmony_ci	struct ccw1 *ccw;
32662306a36Sopenharmony_ci	int rc;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	request = tape_alloc_request(mt_count + 2, 0);
32962306a36Sopenharmony_ci	if (IS_ERR(request))
33062306a36Sopenharmony_ci		return PTR_ERR(request);
33162306a36Sopenharmony_ci	request->op = TO_BSB;
33262306a36Sopenharmony_ci	/* setup ccws */
33362306a36Sopenharmony_ci	ccw = tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1,
33462306a36Sopenharmony_ci			  device->modeset_byte);
33562306a36Sopenharmony_ci	ccw = tape_ccw_repeat(ccw, BACKSPACEBLOCK, mt_count);
33662306a36Sopenharmony_ci	ccw = tape_ccw_end(ccw, NOP, 0, NULL);
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	/* execute it */
33962306a36Sopenharmony_ci	rc = tape_do_io(device, request);
34062306a36Sopenharmony_ci	if (rc == 0 && request->rescnt > 0) {
34162306a36Sopenharmony_ci		DBF_LH(3, "BSR over tapemark\n");
34262306a36Sopenharmony_ci		rc = 1;
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci	tape_free_request(request);
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	return rc;
34762306a36Sopenharmony_ci}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci/*
35062306a36Sopenharmony_ci * MTWEOF: Write 'count' file marks at the current position.
35162306a36Sopenharmony_ci */
35262306a36Sopenharmony_ciint
35362306a36Sopenharmony_citape_std_mtweof(struct tape_device *device, int mt_count)
35462306a36Sopenharmony_ci{
35562306a36Sopenharmony_ci	struct tape_request *request;
35662306a36Sopenharmony_ci	struct ccw1 *ccw;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	request = tape_alloc_request(mt_count + 2, 0);
35962306a36Sopenharmony_ci	if (IS_ERR(request))
36062306a36Sopenharmony_ci		return PTR_ERR(request);
36162306a36Sopenharmony_ci	request->op = TO_WTM;
36262306a36Sopenharmony_ci	/* setup ccws */
36362306a36Sopenharmony_ci	ccw = tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1,
36462306a36Sopenharmony_ci			  device->modeset_byte);
36562306a36Sopenharmony_ci	ccw = tape_ccw_repeat(ccw, WRITETAPEMARK, mt_count);
36662306a36Sopenharmony_ci	ccw = tape_ccw_end(ccw, NOP, 0, NULL);
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	/* execute it */
36962306a36Sopenharmony_ci	return tape_do_io_free(device, request);
37062306a36Sopenharmony_ci}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci/*
37362306a36Sopenharmony_ci * MTBSFM: Backward space over 'count' file marks.
37462306a36Sopenharmony_ci * The tape is positioned at the BOT (Begin Of Tape) side of the
37562306a36Sopenharmony_ci * last skipped file mark.
37662306a36Sopenharmony_ci */
37762306a36Sopenharmony_ciint
37862306a36Sopenharmony_citape_std_mtbsfm(struct tape_device *device, int mt_count)
37962306a36Sopenharmony_ci{
38062306a36Sopenharmony_ci	struct tape_request *request;
38162306a36Sopenharmony_ci	struct ccw1 *ccw;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	request = tape_alloc_request(mt_count + 2, 0);
38462306a36Sopenharmony_ci	if (IS_ERR(request))
38562306a36Sopenharmony_ci		return PTR_ERR(request);
38662306a36Sopenharmony_ci	request->op = TO_BSF;
38762306a36Sopenharmony_ci	/* setup ccws */
38862306a36Sopenharmony_ci	ccw = tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1,
38962306a36Sopenharmony_ci			  device->modeset_byte);
39062306a36Sopenharmony_ci	ccw = tape_ccw_repeat(ccw, BACKSPACEFILE, mt_count);
39162306a36Sopenharmony_ci	ccw = tape_ccw_end(ccw, NOP, 0, NULL);
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	/* execute it */
39462306a36Sopenharmony_ci	return tape_do_io_free(device, request);
39562306a36Sopenharmony_ci}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci/*
39862306a36Sopenharmony_ci * MTBSF: Backward space over 'count' file marks. The tape is positioned at
39962306a36Sopenharmony_ci * the EOT (End of Tape) side of the last skipped file mark.
40062306a36Sopenharmony_ci */
40162306a36Sopenharmony_ciint
40262306a36Sopenharmony_citape_std_mtbsf(struct tape_device *device, int mt_count)
40362306a36Sopenharmony_ci{
40462306a36Sopenharmony_ci	struct tape_request *request;
40562306a36Sopenharmony_ci	struct ccw1 *ccw;
40662306a36Sopenharmony_ci	int rc;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	request = tape_alloc_request(mt_count + 2, 0);
40962306a36Sopenharmony_ci	if (IS_ERR(request))
41062306a36Sopenharmony_ci		return PTR_ERR(request);
41162306a36Sopenharmony_ci	request->op = TO_BSF;
41262306a36Sopenharmony_ci	/* setup ccws */
41362306a36Sopenharmony_ci	ccw = tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1,
41462306a36Sopenharmony_ci			  device->modeset_byte);
41562306a36Sopenharmony_ci	ccw = tape_ccw_repeat(ccw, BACKSPACEFILE, mt_count);
41662306a36Sopenharmony_ci	ccw = tape_ccw_end(ccw, NOP, 0, NULL);
41762306a36Sopenharmony_ci	/* execute it */
41862306a36Sopenharmony_ci	rc = tape_do_io_free(device, request);
41962306a36Sopenharmony_ci	if (rc == 0) {
42062306a36Sopenharmony_ci		rc = tape_mtop(device, MTFSR, 1);
42162306a36Sopenharmony_ci		if (rc > 0)
42262306a36Sopenharmony_ci			rc = 0;
42362306a36Sopenharmony_ci	}
42462306a36Sopenharmony_ci	return rc;
42562306a36Sopenharmony_ci}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci/*
42862306a36Sopenharmony_ci * MTFSFM: Forward space over 'count' file marks.
42962306a36Sopenharmony_ci * The tape is positioned at the BOT (Begin Of Tape) side
43062306a36Sopenharmony_ci * of the last skipped file mark.
43162306a36Sopenharmony_ci */
43262306a36Sopenharmony_ciint
43362306a36Sopenharmony_citape_std_mtfsfm(struct tape_device *device, int mt_count)
43462306a36Sopenharmony_ci{
43562306a36Sopenharmony_ci	struct tape_request *request;
43662306a36Sopenharmony_ci	struct ccw1 *ccw;
43762306a36Sopenharmony_ci	int rc;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	request = tape_alloc_request(mt_count + 2, 0);
44062306a36Sopenharmony_ci	if (IS_ERR(request))
44162306a36Sopenharmony_ci		return PTR_ERR(request);
44262306a36Sopenharmony_ci	request->op = TO_FSF;
44362306a36Sopenharmony_ci	/* setup ccws */
44462306a36Sopenharmony_ci	ccw = tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1,
44562306a36Sopenharmony_ci			  device->modeset_byte);
44662306a36Sopenharmony_ci	ccw = tape_ccw_repeat(ccw, FORSPACEFILE, mt_count);
44762306a36Sopenharmony_ci	ccw = tape_ccw_end(ccw, NOP, 0, NULL);
44862306a36Sopenharmony_ci	/* execute it */
44962306a36Sopenharmony_ci	rc = tape_do_io_free(device, request);
45062306a36Sopenharmony_ci	if (rc == 0) {
45162306a36Sopenharmony_ci		rc = tape_mtop(device, MTBSR, 1);
45262306a36Sopenharmony_ci		if (rc > 0)
45362306a36Sopenharmony_ci			rc = 0;
45462306a36Sopenharmony_ci	}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	return rc;
45762306a36Sopenharmony_ci}
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci/*
46062306a36Sopenharmony_ci * MTREW: Rewind the tape.
46162306a36Sopenharmony_ci */
46262306a36Sopenharmony_ciint
46362306a36Sopenharmony_citape_std_mtrew(struct tape_device *device, int mt_count)
46462306a36Sopenharmony_ci{
46562306a36Sopenharmony_ci	struct tape_request *request;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	request = tape_alloc_request(3, 0);
46862306a36Sopenharmony_ci	if (IS_ERR(request))
46962306a36Sopenharmony_ci		return PTR_ERR(request);
47062306a36Sopenharmony_ci	request->op = TO_REW;
47162306a36Sopenharmony_ci	/* setup ccws */
47262306a36Sopenharmony_ci	tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1,
47362306a36Sopenharmony_ci		    device->modeset_byte);
47462306a36Sopenharmony_ci	tape_ccw_cc(request->cpaddr + 1, REWIND, 0, NULL);
47562306a36Sopenharmony_ci	tape_ccw_end(request->cpaddr + 2, NOP, 0, NULL);
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	/* execute it */
47862306a36Sopenharmony_ci	return tape_do_io_free(device, request);
47962306a36Sopenharmony_ci}
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci/*
48262306a36Sopenharmony_ci * MTOFFL: Rewind the tape and put the drive off-line.
48362306a36Sopenharmony_ci * Implement 'rewind unload'
48462306a36Sopenharmony_ci */
48562306a36Sopenharmony_ciint
48662306a36Sopenharmony_citape_std_mtoffl(struct tape_device *device, int mt_count)
48762306a36Sopenharmony_ci{
48862306a36Sopenharmony_ci	struct tape_request *request;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	request = tape_alloc_request(3, 0);
49162306a36Sopenharmony_ci	if (IS_ERR(request))
49262306a36Sopenharmony_ci		return PTR_ERR(request);
49362306a36Sopenharmony_ci	request->op = TO_RUN;
49462306a36Sopenharmony_ci	/* setup ccws */
49562306a36Sopenharmony_ci	tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
49662306a36Sopenharmony_ci	tape_ccw_cc(request->cpaddr + 1, REWIND_UNLOAD, 0, NULL);
49762306a36Sopenharmony_ci	tape_ccw_end(request->cpaddr + 2, NOP, 0, NULL);
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	/* execute it */
50062306a36Sopenharmony_ci	return tape_do_io_free(device, request);
50162306a36Sopenharmony_ci}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci/*
50462306a36Sopenharmony_ci * MTNOP: 'No operation'.
50562306a36Sopenharmony_ci */
50662306a36Sopenharmony_ciint
50762306a36Sopenharmony_citape_std_mtnop(struct tape_device *device, int mt_count)
50862306a36Sopenharmony_ci{
50962306a36Sopenharmony_ci	struct tape_request *request;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	request = tape_alloc_request(2, 0);
51262306a36Sopenharmony_ci	if (IS_ERR(request))
51362306a36Sopenharmony_ci		return PTR_ERR(request);
51462306a36Sopenharmony_ci	request->op = TO_NOP;
51562306a36Sopenharmony_ci	/* setup ccws */
51662306a36Sopenharmony_ci	tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
51762306a36Sopenharmony_ci	tape_ccw_end(request->cpaddr + 1, NOP, 0, NULL);
51862306a36Sopenharmony_ci	/* execute it */
51962306a36Sopenharmony_ci	return tape_do_io_free(device, request);
52062306a36Sopenharmony_ci}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci/*
52362306a36Sopenharmony_ci * MTEOM: positions at the end of the portion of the tape already used
52462306a36Sopenharmony_ci * for recordind data. MTEOM positions after the last file mark, ready for
52562306a36Sopenharmony_ci * appending another file.
52662306a36Sopenharmony_ci */
52762306a36Sopenharmony_ciint
52862306a36Sopenharmony_citape_std_mteom(struct tape_device *device, int mt_count)
52962306a36Sopenharmony_ci{
53062306a36Sopenharmony_ci	int rc;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	/*
53362306a36Sopenharmony_ci	 * Seek from the beginning of tape (rewind).
53462306a36Sopenharmony_ci	 */
53562306a36Sopenharmony_ci	if ((rc = tape_mtop(device, MTREW, 1)) < 0)
53662306a36Sopenharmony_ci		return rc;
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	/*
53962306a36Sopenharmony_ci	 * The logical end of volume is given by two sewuential tapemarks.
54062306a36Sopenharmony_ci	 * Look for this by skipping to the next file (over one tapemark)
54162306a36Sopenharmony_ci	 * and then test for another one (fsr returns 1 if a tapemark was
54262306a36Sopenharmony_ci	 * encountered).
54362306a36Sopenharmony_ci	 */
54462306a36Sopenharmony_ci	do {
54562306a36Sopenharmony_ci		if ((rc = tape_mtop(device, MTFSF, 1)) < 0)
54662306a36Sopenharmony_ci			return rc;
54762306a36Sopenharmony_ci		if ((rc = tape_mtop(device, MTFSR, 1)) < 0)
54862306a36Sopenharmony_ci			return rc;
54962306a36Sopenharmony_ci	} while (rc == 0);
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	return tape_mtop(device, MTBSR, 1);
55262306a36Sopenharmony_ci}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci/*
55562306a36Sopenharmony_ci * MTRETEN: Retension the tape, i.e. forward space to end of tape and rewind.
55662306a36Sopenharmony_ci */
55762306a36Sopenharmony_ciint
55862306a36Sopenharmony_citape_std_mtreten(struct tape_device *device, int mt_count)
55962306a36Sopenharmony_ci{
56062306a36Sopenharmony_ci	struct tape_request *request;
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	request = tape_alloc_request(4, 0);
56362306a36Sopenharmony_ci	if (IS_ERR(request))
56462306a36Sopenharmony_ci		return PTR_ERR(request);
56562306a36Sopenharmony_ci	request->op = TO_FSF;
56662306a36Sopenharmony_ci	/* setup ccws */
56762306a36Sopenharmony_ci	tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
56862306a36Sopenharmony_ci	tape_ccw_cc(request->cpaddr + 1,FORSPACEFILE, 0, NULL);
56962306a36Sopenharmony_ci	tape_ccw_cc(request->cpaddr + 2, NOP, 0, NULL);
57062306a36Sopenharmony_ci	tape_ccw_end(request->cpaddr + 3, CCW_CMD_TIC, 0, request->cpaddr);
57162306a36Sopenharmony_ci	/* execute it, MTRETEN rc gets ignored */
57262306a36Sopenharmony_ci	tape_do_io_interruptible(device, request);
57362306a36Sopenharmony_ci	tape_free_request(request);
57462306a36Sopenharmony_ci	return tape_mtop(device, MTREW, 1);
57562306a36Sopenharmony_ci}
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci/*
57862306a36Sopenharmony_ci * MTERASE: erases the tape.
57962306a36Sopenharmony_ci */
58062306a36Sopenharmony_ciint
58162306a36Sopenharmony_citape_std_mterase(struct tape_device *device, int mt_count)
58262306a36Sopenharmony_ci{
58362306a36Sopenharmony_ci	struct tape_request *request;
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	request = tape_alloc_request(6, 0);
58662306a36Sopenharmony_ci	if (IS_ERR(request))
58762306a36Sopenharmony_ci		return PTR_ERR(request);
58862306a36Sopenharmony_ci	request->op = TO_DSE;
58962306a36Sopenharmony_ci	/* setup ccws */
59062306a36Sopenharmony_ci	tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
59162306a36Sopenharmony_ci	tape_ccw_cc(request->cpaddr + 1, REWIND, 0, NULL);
59262306a36Sopenharmony_ci	tape_ccw_cc(request->cpaddr + 2, ERASE_GAP, 0, NULL);
59362306a36Sopenharmony_ci	tape_ccw_cc(request->cpaddr + 3, DATA_SEC_ERASE, 0, NULL);
59462306a36Sopenharmony_ci	tape_ccw_cc(request->cpaddr + 4, REWIND, 0, NULL);
59562306a36Sopenharmony_ci	tape_ccw_end(request->cpaddr + 5, NOP, 0, NULL);
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	/* execute it */
59862306a36Sopenharmony_ci	return tape_do_io_free(device, request);
59962306a36Sopenharmony_ci}
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci/*
60262306a36Sopenharmony_ci * MTUNLOAD: Rewind the tape and unload it.
60362306a36Sopenharmony_ci */
60462306a36Sopenharmony_ciint
60562306a36Sopenharmony_citape_std_mtunload(struct tape_device *device, int mt_count)
60662306a36Sopenharmony_ci{
60762306a36Sopenharmony_ci	return tape_mtop(device, MTOFFL, mt_count);
60862306a36Sopenharmony_ci}
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci/*
61162306a36Sopenharmony_ci * MTCOMPRESSION: used to enable compression.
61262306a36Sopenharmony_ci * Sets the IDRC on/off.
61362306a36Sopenharmony_ci */
61462306a36Sopenharmony_ciint
61562306a36Sopenharmony_citape_std_mtcompression(struct tape_device *device, int mt_count)
61662306a36Sopenharmony_ci{
61762306a36Sopenharmony_ci	struct tape_request *request;
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	if (mt_count < 0 || mt_count > 1) {
62062306a36Sopenharmony_ci		DBF_EXCEPTION(6, "xcom parm\n");
62162306a36Sopenharmony_ci		return -EINVAL;
62262306a36Sopenharmony_ci	}
62362306a36Sopenharmony_ci	request = tape_alloc_request(2, 0);
62462306a36Sopenharmony_ci	if (IS_ERR(request))
62562306a36Sopenharmony_ci		return PTR_ERR(request);
62662306a36Sopenharmony_ci	request->op = TO_NOP;
62762306a36Sopenharmony_ci	/* setup ccws */
62862306a36Sopenharmony_ci	if (mt_count == 0)
62962306a36Sopenharmony_ci		*device->modeset_byte &= ~0x08;
63062306a36Sopenharmony_ci	else
63162306a36Sopenharmony_ci		*device->modeset_byte |= 0x08;
63262306a36Sopenharmony_ci	tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
63362306a36Sopenharmony_ci	tape_ccw_end(request->cpaddr + 1, NOP, 0, NULL);
63462306a36Sopenharmony_ci	/* execute it */
63562306a36Sopenharmony_ci	return tape_do_io_free(device, request);
63662306a36Sopenharmony_ci}
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci/*
63962306a36Sopenharmony_ci * Read Block
64062306a36Sopenharmony_ci */
64162306a36Sopenharmony_cistruct tape_request *
64262306a36Sopenharmony_citape_std_read_block(struct tape_device *device, size_t count)
64362306a36Sopenharmony_ci{
64462306a36Sopenharmony_ci	struct tape_request *request;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	/*
64762306a36Sopenharmony_ci	 * We have to alloc 4 ccws in order to be able to transform request
64862306a36Sopenharmony_ci	 * into a read backward request in error case.
64962306a36Sopenharmony_ci	 */
65062306a36Sopenharmony_ci	request = tape_alloc_request(4, 0);
65162306a36Sopenharmony_ci	if (IS_ERR(request)) {
65262306a36Sopenharmony_ci		DBF_EXCEPTION(6, "xrbl fail");
65362306a36Sopenharmony_ci		return request;
65462306a36Sopenharmony_ci	}
65562306a36Sopenharmony_ci	request->op = TO_RFO;
65662306a36Sopenharmony_ci	tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
65762306a36Sopenharmony_ci	tape_ccw_end_idal(request->cpaddr + 1, READ_FORWARD,
65862306a36Sopenharmony_ci			  device->char_data.idal_buf);
65962306a36Sopenharmony_ci	DBF_EVENT(6, "xrbl ccwg\n");
66062306a36Sopenharmony_ci	return request;
66162306a36Sopenharmony_ci}
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci/*
66462306a36Sopenharmony_ci * Read Block backward transformation function.
66562306a36Sopenharmony_ci */
66662306a36Sopenharmony_civoid
66762306a36Sopenharmony_citape_std_read_backward(struct tape_device *device, struct tape_request *request)
66862306a36Sopenharmony_ci{
66962306a36Sopenharmony_ci	/*
67062306a36Sopenharmony_ci	 * We have allocated 4 ccws in tape_std_read, so we can now
67162306a36Sopenharmony_ci	 * transform the request to a read backward, followed by a
67262306a36Sopenharmony_ci	 * forward space block.
67362306a36Sopenharmony_ci	 */
67462306a36Sopenharmony_ci	request->op = TO_RBA;
67562306a36Sopenharmony_ci	tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
67662306a36Sopenharmony_ci	tape_ccw_cc_idal(request->cpaddr + 1, READ_BACKWARD,
67762306a36Sopenharmony_ci			 device->char_data.idal_buf);
67862306a36Sopenharmony_ci	tape_ccw_cc(request->cpaddr + 2, FORSPACEBLOCK, 0, NULL);
67962306a36Sopenharmony_ci	tape_ccw_end(request->cpaddr + 3, NOP, 0, NULL);
68062306a36Sopenharmony_ci	DBF_EVENT(6, "xrop ccwg");}
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci/*
68362306a36Sopenharmony_ci * Write Block
68462306a36Sopenharmony_ci */
68562306a36Sopenharmony_cistruct tape_request *
68662306a36Sopenharmony_citape_std_write_block(struct tape_device *device, size_t count)
68762306a36Sopenharmony_ci{
68862306a36Sopenharmony_ci	struct tape_request *request;
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	request = tape_alloc_request(2, 0);
69162306a36Sopenharmony_ci	if (IS_ERR(request)) {
69262306a36Sopenharmony_ci		DBF_EXCEPTION(6, "xwbl fail\n");
69362306a36Sopenharmony_ci		return request;
69462306a36Sopenharmony_ci	}
69562306a36Sopenharmony_ci	request->op = TO_WRI;
69662306a36Sopenharmony_ci	tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
69762306a36Sopenharmony_ci	tape_ccw_end_idal(request->cpaddr + 1, WRITE_CMD,
69862306a36Sopenharmony_ci			  device->char_data.idal_buf);
69962306a36Sopenharmony_ci	DBF_EVENT(6, "xwbl ccwg\n");
70062306a36Sopenharmony_ci	return request;
70162306a36Sopenharmony_ci}
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci/*
70462306a36Sopenharmony_ci * This routine is called by frontend after an ENOSP on write
70562306a36Sopenharmony_ci */
70662306a36Sopenharmony_civoid
70762306a36Sopenharmony_citape_std_process_eov(struct tape_device *device)
70862306a36Sopenharmony_ci{
70962306a36Sopenharmony_ci	/*
71062306a36Sopenharmony_ci	 * End of volume: We have to backspace the last written record, then
71162306a36Sopenharmony_ci	 * we TRY to write a tapemark and then backspace over the written TM
71262306a36Sopenharmony_ci	 */
71362306a36Sopenharmony_ci	if (tape_mtop(device, MTBSR, 1) == 0 &&
71462306a36Sopenharmony_ci	    tape_mtop(device, MTWEOF, 1) == 0) {
71562306a36Sopenharmony_ci		tape_mtop(device, MTBSR, 1);
71662306a36Sopenharmony_ci	}
71762306a36Sopenharmony_ci}
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ciEXPORT_SYMBOL(tape_std_assign);
72062306a36Sopenharmony_ciEXPORT_SYMBOL(tape_std_unassign);
72162306a36Sopenharmony_ciEXPORT_SYMBOL(tape_std_display);
72262306a36Sopenharmony_ciEXPORT_SYMBOL(tape_std_read_block_id);
72362306a36Sopenharmony_ciEXPORT_SYMBOL(tape_std_mtload);
72462306a36Sopenharmony_ciEXPORT_SYMBOL(tape_std_mtsetblk);
72562306a36Sopenharmony_ciEXPORT_SYMBOL(tape_std_mtreset);
72662306a36Sopenharmony_ciEXPORT_SYMBOL(tape_std_mtfsf);
72762306a36Sopenharmony_ciEXPORT_SYMBOL(tape_std_mtfsr);
72862306a36Sopenharmony_ciEXPORT_SYMBOL(tape_std_mtbsr);
72962306a36Sopenharmony_ciEXPORT_SYMBOL(tape_std_mtweof);
73062306a36Sopenharmony_ciEXPORT_SYMBOL(tape_std_mtbsfm);
73162306a36Sopenharmony_ciEXPORT_SYMBOL(tape_std_mtbsf);
73262306a36Sopenharmony_ciEXPORT_SYMBOL(tape_std_mtfsfm);
73362306a36Sopenharmony_ciEXPORT_SYMBOL(tape_std_mtrew);
73462306a36Sopenharmony_ciEXPORT_SYMBOL(tape_std_mtoffl);
73562306a36Sopenharmony_ciEXPORT_SYMBOL(tape_std_mtnop);
73662306a36Sopenharmony_ciEXPORT_SYMBOL(tape_std_mteom);
73762306a36Sopenharmony_ciEXPORT_SYMBOL(tape_std_mtreten);
73862306a36Sopenharmony_ciEXPORT_SYMBOL(tape_std_mterase);
73962306a36Sopenharmony_ciEXPORT_SYMBOL(tape_std_mtunload);
74062306a36Sopenharmony_ciEXPORT_SYMBOL(tape_std_mtcompression);
74162306a36Sopenharmony_ciEXPORT_SYMBOL(tape_std_read_block);
74262306a36Sopenharmony_ciEXPORT_SYMBOL(tape_std_read_backward);
74362306a36Sopenharmony_ciEXPORT_SYMBOL(tape_std_write_block);
74462306a36Sopenharmony_ciEXPORT_SYMBOL(tape_std_process_eov);
745