📄 tape_std.c
字号:
/* * drivers/s390/char/tape_std.c * standard tape device functions for ibm tapes. * * S390 and zSeries version * Copyright (C) 2001,2002 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Carsten Otte <cotte@de.ibm.com> * Michael Holzheu <holzheu@de.ibm.com> * Tuan Ngo-Anh <ngoanh@de.ibm.com> * Martin Schwidefsky <schwidefsky@de.ibm.com> * Stefan Bader <shbader@de.ibm.com> */#include <linux/config.h>#include <linux/stddef.h>#include <linux/kernel.h>#include <linux/bio.h>#include <linux/timer.h>#include <asm/types.h>#include <asm/idals.h>#include <asm/ebcdic.h>#include <asm/tape390.h>#define TAPE_DBF_AREA tape_core_dbf#include "tape.h"#include "tape_std.h"#define PRINTK_HEADER "TAPE_STD: "/* * tape_std_assign */static voidtape_std_assign_timeout(unsigned long data){ struct tape_request * request; struct tape_device * device; request = (struct tape_request *) data; if ((device = request->device) == NULL) BUG(); spin_lock_irq(get_ccwdev_lock(device->cdev)); if (request->callback != NULL) { DBF_EVENT(3, "%08x: Assignment timeout. Device busy.\n", device->cdev_id); PRINT_ERR("%s: Assignment timeout. Device busy.\n", device->cdev->dev.bus_id); ccw_device_clear(device->cdev, (long) request); } spin_unlock_irq(get_ccwdev_lock(device->cdev));}inttape_std_assign(struct tape_device *device){ int rc; struct timer_list timeout; struct tape_request *request; request = tape_alloc_request(2, 11); if (IS_ERR(request)) return PTR_ERR(request); request->op = TO_ASSIGN; tape_ccw_cc(request->cpaddr, ASSIGN, 11, request->cpdata); tape_ccw_end(request->cpaddr + 1, NOP, 0, NULL); /* * The assign command sometimes blocks if the device is assigned * to another host (actually this shouldn't happen but it does). * So we set up a timeout for this call. */ init_timer(&timeout); timeout.function = tape_std_assign_timeout; timeout.data = (unsigned long) request; timeout.expires = jiffies + 2 * HZ; add_timer(&timeout); rc = tape_do_io_interruptible(device, request); del_timer(&timeout); if (rc != 0) { PRINT_WARN("%s: assign failed - device might be busy\n", device->cdev->dev.bus_id); DBF_EVENT(3, "%08x: assign failed - device might be busy\n", device->cdev_id); } else { DBF_EVENT(3, "%08x: Tape assigned\n", device->cdev_id); } tape_free_request(request); return rc;}/* * tape_std_unassign */inttape_std_unassign (struct tape_device *device){ int rc; struct tape_request *request; if (device->tape_state == TS_NOT_OPER) { DBF_EVENT(3, "(%08x): Can't unassign device\n", device->cdev_id); PRINT_WARN("(%s): Can't unassign device - device gone\n", device->cdev->dev.bus_id); return -EIO; } request = tape_alloc_request(2, 11); if (IS_ERR(request)) return PTR_ERR(request); request->op = TO_UNASSIGN; tape_ccw_cc(request->cpaddr, UNASSIGN, 11, request->cpdata); tape_ccw_end(request->cpaddr + 1, NOP, 0, NULL); if ((rc = tape_do_io(device, request)) != 0) { DBF_EVENT(3, "%08x: Unassign failed\n", device->cdev_id); PRINT_WARN("%s: Unassign failed\n", device->cdev->dev.bus_id); } else { DBF_EVENT(3, "%08x: Tape unassigned\n", device->cdev_id); } tape_free_request(request); return rc;}/* * TAPE390_DISPLAY: Show a string on the tape display. */inttape_std_display(struct tape_device *device, struct display_struct *disp){ struct tape_request *request; int rc; request = tape_alloc_request(2, 17); if (IS_ERR(request)) { DBF_EVENT(3, "TAPE: load display failed\n"); return PTR_ERR(request); } request->op = TO_DIS; *(unsigned char *) request->cpdata = disp->cntrl; DBF_EVENT(5, "TAPE: display cntrl=%04x\n", disp->cntrl); memcpy(((unsigned char *) request->cpdata) + 1, disp->message1, 8); memcpy(((unsigned char *) request->cpdata) + 9, disp->message2, 8); ASCEBC(((unsigned char*) request->cpdata) + 1, 16); tape_ccw_cc(request->cpaddr, LOAD_DISPLAY, 17, request->cpdata); tape_ccw_end(request->cpaddr + 1, NOP, 0, NULL); rc = tape_do_io_interruptible(device, request); tape_free_request(request); return rc;}/* * Read block id. */inttape_std_read_block_id(struct tape_device *device, __u64 *id){ struct tape_request *request; int rc; request = tape_alloc_request(3, 8); if (IS_ERR(request)) return PTR_ERR(request); request->op = TO_RBI; /* setup ccws */ tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte); tape_ccw_cc(request->cpaddr + 1, READ_BLOCK_ID, 8, request->cpdata); tape_ccw_end(request->cpaddr + 2, NOP, 0, NULL); /* execute it */ rc = tape_do_io(device, request); if (rc == 0) /* Get result from read buffer. */ *id = *(__u64 *) request->cpdata; tape_free_request(request); return rc;}inttape_std_terminate_write(struct tape_device *device){ int rc; if(device->required_tapemarks == 0) return 0; DBF_LH(5, "tape%d: terminate write %dxEOF\n", device->first_minor, device->required_tapemarks); rc = tape_mtop(device, MTWEOF, device->required_tapemarks); if (rc) return rc; device->required_tapemarks = 0; return tape_mtop(device, MTBSR, 1);}/* * MTLOAD: Loads the tape. * The default implementation just wait until the tape medium state changes * to MS_LOADED. */inttape_std_mtload(struct tape_device *device, int count){ return wait_event_interruptible(device->state_change_wq, (device->medium_state == MS_LOADED));}/* * MTSETBLK: Set block size. */inttape_std_mtsetblk(struct tape_device *device, int count){ struct idal_buffer *new; DBF_LH(6, "tape_std_mtsetblk(%d)\n", count); if (count <= 0) { /* * Just set block_size to 0. tapechar_read/tapechar_write * will realloc the idal buffer if a bigger one than the * current is needed. */ device->char_data.block_size = 0; return 0; } if (device->char_data.idal_buf != NULL && device->char_data.idal_buf->size == count) /* We already have a idal buffer of that size. */ return 0; if (count > MAX_BLOCKSIZE) { DBF_EVENT(3, "Invalid block size (%d > %d) given.\n", count, MAX_BLOCKSIZE); PRINT_ERR("Invalid block size (%d > %d) given.\n", count, MAX_BLOCKSIZE); return -EINVAL; } /* Allocate a new idal buffer. */ new = idal_buffer_alloc(count, 0); if (new == NULL) return -ENOMEM; if (device->char_data.idal_buf != NULL) idal_buffer_free(device->char_data.idal_buf); device->char_data.idal_buf = new; device->char_data.block_size = count; DBF_LH(6, "new blocksize is %d\n", device->char_data.block_size); return 0;}/* * MTRESET: Set block size to 0. */inttape_std_mtreset(struct tape_device *device, int count){ DBF_EVENT(6, "TCHAR:devreset:\n"); device->char_data.block_size = 0; return 0;}/* * MTFSF: Forward space over 'count' file marks. The tape is positioned * at the EOT (End of Tape) side of the file mark. */inttape_std_mtfsf(struct tape_device *device, int mt_count){ struct tape_request *request; struct ccw1 *ccw; request = tape_alloc_request(mt_count + 2, 0); if (IS_ERR(request)) return PTR_ERR(request); request->op = TO_FSF; /* setup ccws */ ccw = tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte); ccw = tape_ccw_repeat(ccw, FORSPACEFILE, mt_count); ccw = tape_ccw_end(ccw, NOP, 0, NULL); /* execute it */ return tape_do_io_free(device, request);}/* * MTFSR: Forward space over 'count' tape blocks (blocksize is set * via MTSETBLK. */inttape_std_mtfsr(struct tape_device *device, int mt_count){ struct tape_request *request; struct ccw1 *ccw; int rc; request = tape_alloc_request(mt_count + 2, 0); if (IS_ERR(request)) return PTR_ERR(request); request->op = TO_FSB; /* setup ccws */ ccw = tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte); ccw = tape_ccw_repeat(ccw, FORSPACEBLOCK, mt_count); ccw = tape_ccw_end(ccw, NOP, 0, NULL); /* execute it */ rc = tape_do_io(device, request); if (rc == 0 && request->rescnt > 0) { DBF_LH(3, "FSR over tapemark\n"); rc = 1; } tape_free_request(request); return rc;}/* * MTBSR: Backward space over 'count' tape blocks. * (blocksize is set via MTSETBLK. */inttape_std_mtbsr(struct tape_device *device, int mt_count){ struct tape_request *request; struct ccw1 *ccw; int rc; request = tape_alloc_request(mt_count + 2, 0); if (IS_ERR(request)) return PTR_ERR(request); request->op = TO_BSB; /* setup ccws */ ccw = tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte); ccw = tape_ccw_repeat(ccw, BACKSPACEBLOCK, mt_count); ccw = tape_ccw_end(ccw, NOP, 0, NULL); /* execute it */ rc = tape_do_io(device, request); if (rc == 0 && request->rescnt > 0) { DBF_LH(3, "BSR over tapemark\n"); rc = 1; } tape_free_request(request); return rc;}/* * MTWEOF: Write 'count' file marks at the current position. */inttape_std_mtweof(struct tape_device *device, int mt_count){ struct tape_request *request; struct ccw1 *ccw; request = tape_alloc_request(mt_count + 2, 0); if (IS_ERR(request)) return PTR_ERR(request); request->op = TO_WTM; /* setup ccws */ ccw = tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte); ccw = tape_ccw_repeat(ccw, WRITETAPEMARK, mt_count); ccw = tape_ccw_end(ccw, NOP, 0, NULL); /* execute it */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -