tape_3590.c

来自「linux 内核源代码」· C语言 代码 · 共 1,767 行 · 第 1/4 页

C
1,767
字号
/* *  drivers/s390/char/tape_3590.c *    tape device discipline for 3590 tapes. * *    Copyright IBM Corp. 2001,2006 *    Author(s): Stefan Bader <shbader@de.ibm.com> *		 Michael Holzheu <holzheu@de.ibm.com> *		 Martin Schwidefsky <schwidefsky@de.ibm.com> */#include <linux/module.h>#include <linux/init.h>#include <linux/bio.h>#include <asm/ebcdic.h>#define TAPE_DBF_AREA	tape_3590_dbf#include "tape.h"#include "tape_std.h"#include "tape_3590.h"/* * Pointer to debug area. */debug_info_t *TAPE_DBF_AREA = NULL;EXPORT_SYMBOL(TAPE_DBF_AREA);/******************************************************************* * Error Recovery fuctions: * - Read Opposite:		 implemented * - Read Device (buffered) log: BRA * - Read Library log:		 BRA * - Swap Devices:		 BRA * - Long Busy:			 implemented * - Special Intercept:		 BRA * - Read Alternate:		 implemented *******************************************************************/#define PRINTK_HEADER "TAPE_3590: "static const char *tape_3590_msg[TAPE_3590_MAX_MSG] = {	[0x00] = "",	[0x10] = "Lost Sense",	[0x11] = "Assigned Elsewhere",	[0x12] = "Allegiance Reset",	[0x13] = "Shared Access Violation",	[0x20] = "Command Reject",	[0x21] = "Configuration Error",	[0x22] = "Protection Exception",	[0x23] = "Write Protect",	[0x24] = "Write Length",	[0x25] = "Read-Only Format",	[0x31] = "Beginning of Partition",	[0x33] = "End of Partition",	[0x34] = "End of Data",	[0x35] = "Block not found",	[0x40] = "Device Intervention",	[0x41] = "Loader Intervention",	[0x42] = "Library Intervention",	[0x50] = "Write Error",	[0x51] = "Erase Error",	[0x52] = "Formatting Error",	[0x53] = "Read Error",	[0x54] = "Unsupported Format",	[0x55] = "No Formatting",	[0x56] = "Positioning lost",	[0x57] = "Read Length",	[0x60] = "Unsupported Medium",	[0x61] = "Medium Length Error",	[0x62] = "Medium removed",	[0x64] = "Load Check",	[0x65] = "Unload Check",	[0x70] = "Equipment Check",	[0x71] = "Bus out Check",	[0x72] = "Protocol Error",	[0x73] = "Interface Error",	[0x74] = "Overrun",	[0x75] = "Halt Signal",	[0x90] = "Device fenced",	[0x91] = "Device Path fenced",	[0xa0] = "Volume misplaced",	[0xa1] = "Volume inaccessible",	[0xa2] = "Volume in input",	[0xa3] = "Volume ejected",	[0xa4] = "All categories reserved",	[0xa5] = "Duplicate Volume",	[0xa6] = "Library Manager Offline",	[0xa7] = "Library Output Station full",	[0xa8] = "Vision System non-operational",	[0xa9] = "Library Manager Equipment Check",	[0xaa] = "Library Equipment Check",	[0xab] = "All Library Cells full",	[0xac] = "No Cleaner Volumes in Library",	[0xad] = "I/O Station door open",	[0xae] = "Subsystem environmental alert",};static int crypt_supported(struct tape_device *device){	return TAPE390_CRYPT_SUPPORTED(TAPE_3590_CRYPT_INFO(device));}static int crypt_enabled(struct tape_device *device){	return TAPE390_CRYPT_ON(TAPE_3590_CRYPT_INFO(device));}static void ext_to_int_kekl(struct tape390_kekl *in,			    struct tape3592_kekl *out){	int i;	memset(out, 0, sizeof(*out));	if (in->type == TAPE390_KEKL_TYPE_HASH)		out->flags |= 0x40;	if (in->type_on_tape == TAPE390_KEKL_TYPE_HASH)		out->flags |= 0x80;	strncpy(out->label, in->label, 64);	for (i = strlen(in->label); i < sizeof(out->label); i++)		out->label[i] = ' ';	ASCEBC(out->label, sizeof(out->label));}static void int_to_ext_kekl(struct tape3592_kekl *in,			    struct tape390_kekl *out){	memset(out, 0, sizeof(*out));	if(in->flags & 0x40)		out->type = TAPE390_KEKL_TYPE_HASH;	else		out->type = TAPE390_KEKL_TYPE_LABEL;	if(in->flags & 0x80)		out->type_on_tape = TAPE390_KEKL_TYPE_HASH;	else		out->type_on_tape = TAPE390_KEKL_TYPE_LABEL;	memcpy(out->label, in->label, sizeof(in->label));	EBCASC(out->label, sizeof(in->label));	strstrip(out->label);}static void int_to_ext_kekl_pair(struct tape3592_kekl_pair *in,				 struct tape390_kekl_pair *out){	if (in->count == 0) {		out->kekl[0].type = TAPE390_KEKL_TYPE_NONE;		out->kekl[0].type_on_tape = TAPE390_KEKL_TYPE_NONE;		out->kekl[1].type = TAPE390_KEKL_TYPE_NONE;		out->kekl[1].type_on_tape = TAPE390_KEKL_TYPE_NONE;	} else if (in->count == 1) {		int_to_ext_kekl(&in->kekl[0], &out->kekl[0]);		out->kekl[1].type = TAPE390_KEKL_TYPE_NONE;		out->kekl[1].type_on_tape = TAPE390_KEKL_TYPE_NONE;	} else if (in->count == 2) {		int_to_ext_kekl(&in->kekl[0], &out->kekl[0]);		int_to_ext_kekl(&in->kekl[1], &out->kekl[1]);	} else {		printk("Invalid KEKL number: %d\n", in->count);		BUG();	}}static int check_ext_kekl(struct tape390_kekl *kekl){	if (kekl->type == TAPE390_KEKL_TYPE_NONE)		goto invalid;	if (kekl->type > TAPE390_KEKL_TYPE_HASH)		goto invalid;	if (kekl->type_on_tape == TAPE390_KEKL_TYPE_NONE)		goto invalid;	if (kekl->type_on_tape > TAPE390_KEKL_TYPE_HASH)		goto invalid;	if ((kekl->type == TAPE390_KEKL_TYPE_HASH) &&	    (kekl->type_on_tape == TAPE390_KEKL_TYPE_LABEL))		goto invalid;	return 0;invalid:	return -EINVAL;}static int check_ext_kekl_pair(struct tape390_kekl_pair *kekls){	if (check_ext_kekl(&kekls->kekl[0]))		goto invalid;	if (check_ext_kekl(&kekls->kekl[1]))		goto invalid;	return 0;invalid:	return -EINVAL;}/* * Query KEKLs */static int tape_3592_kekl_query(struct tape_device *device,				struct tape390_kekl_pair *ext_kekls){	struct tape_request *request;	struct tape3592_kekl_query_order *order;	struct tape3592_kekl_query_data *int_kekls;	int rc;	DBF_EVENT(6, "tape3592_kekl_query\n");	int_kekls = kmalloc(sizeof(*int_kekls), GFP_KERNEL|GFP_DMA);	if (!int_kekls)		return -ENOMEM;	request = tape_alloc_request(2, sizeof(*order));	if (IS_ERR(request)) {		rc = PTR_ERR(request);		goto fail_malloc;	}	order = request->cpdata;	memset(order,0,sizeof(*order));	order->code = 0xe2;	order->max_count = 2;	request->op = TO_KEKL_QUERY;	tape_ccw_cc(request->cpaddr, PERF_SUBSYS_FUNC, sizeof(*order), order);	tape_ccw_end(request->cpaddr + 1, READ_SS_DATA, sizeof(*int_kekls),		     int_kekls);	rc = tape_do_io(device, request);	if (rc)		goto fail_request;	int_to_ext_kekl_pair(&int_kekls->kekls, ext_kekls);	rc = 0;fail_request:	tape_free_request(request);fail_malloc:	kfree(int_kekls);	return rc;}/* * IOCTL: Query KEKLs */static int tape_3592_ioctl_kekl_query(struct tape_device *device,				      unsigned long arg){	int rc;	struct tape390_kekl_pair *ext_kekls;	DBF_EVENT(6, "tape_3592_ioctl_kekl_query\n");	if (!crypt_supported(device))		return -ENOSYS;	if (!crypt_enabled(device))		return -EUNATCH;	ext_kekls = kmalloc(sizeof(*ext_kekls), GFP_KERNEL);	if (!ext_kekls)		return -ENOMEM;	rc = tape_3592_kekl_query(device, ext_kekls);	if (rc != 0)		goto fail;	if (copy_to_user((char __user *) arg, ext_kekls, sizeof(*ext_kekls))) {		rc = -EFAULT;		goto fail;	}	rc = 0;fail:	kfree(ext_kekls);	return rc;}static int tape_3590_mttell(struct tape_device *device, int mt_count);/* * Set KEKLs */static int tape_3592_kekl_set(struct tape_device *device,			      struct tape390_kekl_pair *ext_kekls){	struct tape_request *request;	struct tape3592_kekl_set_order *order;	DBF_EVENT(6, "tape3592_kekl_set\n");	if (check_ext_kekl_pair(ext_kekls)) {		DBF_EVENT(6, "invalid kekls\n");		return -EINVAL;	}	if (tape_3590_mttell(device, 0) != 0)		return -EBADSLT;	request = tape_alloc_request(1, sizeof(*order));	if (IS_ERR(request))		return PTR_ERR(request);	order = request->cpdata;	memset(order, 0, sizeof(*order));	order->code = 0xe3;	order->kekls.count = 2;	ext_to_int_kekl(&ext_kekls->kekl[0], &order->kekls.kekl[0]);	ext_to_int_kekl(&ext_kekls->kekl[1], &order->kekls.kekl[1]);	request->op = TO_KEKL_SET;	tape_ccw_end(request->cpaddr, PERF_SUBSYS_FUNC, sizeof(*order), order);	return tape_do_io_free(device, request);}/* * IOCTL: Set KEKLs */static int tape_3592_ioctl_kekl_set(struct tape_device *device,				    unsigned long arg){	int rc;	struct tape390_kekl_pair *ext_kekls;	DBF_EVENT(6, "tape_3592_ioctl_kekl_set\n");	if (!crypt_supported(device))		return -ENOSYS;	if (!crypt_enabled(device))		return -EUNATCH;	ext_kekls = kmalloc(sizeof(*ext_kekls), GFP_KERNEL);	if (!ext_kekls)		return -ENOMEM;	if (copy_from_user(ext_kekls, (char __user *)arg, sizeof(*ext_kekls))) {		rc = -EFAULT;		goto out;	}	rc = tape_3592_kekl_set(device, ext_kekls);out:	kfree(ext_kekls);	return rc;}/* * Enable encryption */static int tape_3592_enable_crypt(struct tape_device *device){	struct tape_request *request;	char *data;	DBF_EVENT(6, "tape_3592_enable_crypt\n");	if (!crypt_supported(device))		return -ENOSYS;	request = tape_alloc_request(2, 72);	if (IS_ERR(request))		return PTR_ERR(request);	data = request->cpdata;	memset(data,0,72);	data[0]       = 0x05;	data[36 + 0]  = 0x03;	data[36 + 1]  = 0x03;	data[36 + 4]  = 0x40;	data[36 + 6]  = 0x01;	data[36 + 14] = 0x2f;	data[36 + 18] = 0xc3;	data[36 + 35] = 0x72;	request->op = TO_CRYPT_ON;	tape_ccw_cc(request->cpaddr, MODE_SET_CB, 36, data);	tape_ccw_end(request->cpaddr + 1, MODE_SET_CB, 36, data + 36);	return tape_do_io_free(device, request);}/* * Disable encryption */static int tape_3592_disable_crypt(struct tape_device *device){	struct tape_request *request;	char *data;	DBF_EVENT(6, "tape_3592_disable_crypt\n");	if (!crypt_supported(device))		return -ENOSYS;	request = tape_alloc_request(2, 72);	if (IS_ERR(request))		return PTR_ERR(request);	data = request->cpdata;	memset(data,0,72);	data[0]       = 0x05;	data[36 + 0]  = 0x03;	data[36 + 1]  = 0x03;	data[36 + 35] = 0x32;	request->op = TO_CRYPT_OFF;	tape_ccw_cc(request->cpaddr, MODE_SET_CB, 36, data);	tape_ccw_end(request->cpaddr + 1, MODE_SET_CB, 36, data + 36);	return tape_do_io_free(device, request);}/* * IOCTL: Set encryption status */static int tape_3592_ioctl_crypt_set(struct tape_device *device,				     unsigned long arg){	struct tape390_crypt_info info;	DBF_EVENT(6, "tape_3592_ioctl_crypt_set\n");	if (!crypt_supported(device))		return -ENOSYS;	if (copy_from_user(&info, (char __user *)arg, sizeof(info)))		return -EFAULT;	if (info.status & ~TAPE390_CRYPT_ON_MASK)		return -EINVAL;	if (info.status & TAPE390_CRYPT_ON_MASK)		return tape_3592_enable_crypt(device);	else		return tape_3592_disable_crypt(device);}static int tape_3590_sense_medium(struct tape_device *device);/* * IOCTL: Query enryption status */static int tape_3592_ioctl_crypt_query(struct tape_device *device,				       unsigned long arg){	DBF_EVENT(6, "tape_3592_ioctl_crypt_query\n");	if (!crypt_supported(device))		return -ENOSYS;	tape_3590_sense_medium(device);	if (copy_to_user((char __user *) arg, &TAPE_3590_CRYPT_INFO(device),		sizeof(TAPE_3590_CRYPT_INFO(device))))		return -EFAULT;	else		return 0;}/* * 3590 IOCTL Overload */static inttape_3590_ioctl(struct tape_device *device, unsigned int cmd, unsigned long arg){	switch (cmd) {	case TAPE390_DISPLAY: {		struct display_struct disp;		if (copy_from_user(&disp, (char __user *) arg, sizeof(disp)))			return -EFAULT;		return tape_std_display(device, &disp);	}	case TAPE390_KEKL_SET:		return tape_3592_ioctl_kekl_set(device, arg);	case TAPE390_KEKL_QUERY:		return tape_3592_ioctl_kekl_query(device, arg);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?