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