zfcp_aux.c

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

C
1,840
字号
/* * This file is part of the zfcp device driver for * FCP adapters for IBM System z9 and zSeries. * * (C) Copyright IBM Corp. 2002, 2006 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *//* * Driver authors: *            Martin Peschke (originator of the driver) *            Raimund Schroeder *            Aron Zeh *            Wolfgang Taphorn *            Stefan Bader *            Heiko Carstens (kernel 2.6 port of the driver) *            Andreas Herrmann *            Maxim Shchetynin *            Volker Sameske *            Ralph Wuerthner */#include "zfcp_ext.h"/* accumulated log level (module parameter) */static u32 loglevel = ZFCP_LOG_LEVEL_DEFAULTS;static char *device;/*********************** FUNCTION PROTOTYPES *********************************//* written against the module interface */static int __init  zfcp_module_init(void);/* FCP related */static void zfcp_ns_gid_pn_handler(unsigned long);/* miscellaneous */static int zfcp_sg_list_alloc(struct zfcp_sg_list *, size_t);static void zfcp_sg_list_free(struct zfcp_sg_list *);static int zfcp_sg_list_copy_from_user(struct zfcp_sg_list *,				       void __user *, size_t);static int zfcp_sg_list_copy_to_user(void __user *,				     struct zfcp_sg_list *, size_t);static long zfcp_cfdc_dev_ioctl(struct file *, unsigned int, unsigned long);#define ZFCP_CFDC_IOC_MAGIC                     0xDD#define ZFCP_CFDC_IOC \	_IOWR(ZFCP_CFDC_IOC_MAGIC, 0, struct zfcp_cfdc_sense_data)static const struct file_operations zfcp_cfdc_fops = {	.unlocked_ioctl = zfcp_cfdc_dev_ioctl,#ifdef CONFIG_COMPAT	.compat_ioctl = zfcp_cfdc_dev_ioctl#endif};static struct miscdevice zfcp_cfdc_misc = {	.minor = ZFCP_CFDC_DEV_MINOR,	.name = ZFCP_CFDC_DEV_NAME,	.fops = &zfcp_cfdc_fops};/*********************** KERNEL/MODULE PARAMETERS  ***************************//* declare driver module init/cleanup functions */module_init(zfcp_module_init);MODULE_AUTHOR("IBM Deutschland Entwicklung GmbH - linux390@de.ibm.com");MODULE_DESCRIPTION    ("FCP (SCSI over Fibre Channel) HBA driver for IBM System z9 and zSeries");MODULE_LICENSE("GPL");module_param(device, charp, 0400);MODULE_PARM_DESC(device, "specify initial device");module_param(loglevel, uint, 0400);MODULE_PARM_DESC(loglevel,		 "log levels, 8 nibbles: "		 "FC ERP QDIO CIO Config FSF SCSI Other, "		 "levels: 0=none 1=normal 2=devel 3=trace");/****************************************************************//************** Functions without logging ***********************//****************************************************************/void_zfcp_hex_dump(char *addr, int count){	int i;	for (i = 0; i < count; i++) {		printk("%02x", addr[i]);		if ((i % 4) == 3)			printk(" ");		if ((i % 32) == 31)			printk("\n");	}	if (((i-1) % 32) != 31)		printk("\n");}/****************************************************************//****** Functions to handle the request ID hash table    ********//****************************************************************/#define ZFCP_LOG_AREA			ZFCP_LOG_AREA_FSFstatic int zfcp_reqlist_alloc(struct zfcp_adapter *adapter){	int idx;	adapter->req_list = kcalloc(REQUEST_LIST_SIZE, sizeof(struct list_head),				    GFP_KERNEL);	if (!adapter->req_list)		return -ENOMEM;	for (idx = 0; idx < REQUEST_LIST_SIZE; idx++)		INIT_LIST_HEAD(&adapter->req_list[idx]);	return 0;}static void zfcp_reqlist_free(struct zfcp_adapter *adapter){	kfree(adapter->req_list);}int zfcp_reqlist_isempty(struct zfcp_adapter *adapter){	unsigned int idx;	for (idx = 0; idx < REQUEST_LIST_SIZE; idx++)		if (!list_empty(&adapter->req_list[idx]))			return 0;	return 1;}#undef ZFCP_LOG_AREA/****************************************************************//************** Uncategorised Functions *************************//****************************************************************/#define ZFCP_LOG_AREA			ZFCP_LOG_AREA_OTHER/** * zfcp_device_setup - setup function * @str: pointer to parameter string * * Parse "device=..." parameter string. */static int __initzfcp_device_setup(char *devstr){	char *tmp, *str;	size_t len;	if (!devstr)		return 0;	len = strlen(devstr) + 1;	str = kmalloc(len, GFP_KERNEL);	if (!str)		goto err_out;	memcpy(str, devstr, len);	tmp = strchr(str, ',');	if (!tmp)		goto err_out;	*tmp++ = '\0';	strncpy(zfcp_data.init_busid, str, BUS_ID_SIZE);	zfcp_data.init_busid[BUS_ID_SIZE-1] = '\0';	zfcp_data.init_wwpn = simple_strtoull(tmp, &tmp, 0);	if (*tmp++ != ',')		goto err_out;	if (*tmp == '\0')		goto err_out;	zfcp_data.init_fcp_lun = simple_strtoull(tmp, &tmp, 0);	if (*tmp != '\0')		goto err_out;	kfree(str);	return 1; err_out:	ZFCP_LOG_NORMAL("Parse error for device parameter string %s\n", str);	kfree(str);	return 0;}static void __initzfcp_init_device_configure(void){	struct zfcp_adapter *adapter;	struct zfcp_port *port;	struct zfcp_unit *unit;	down(&zfcp_data.config_sema);	read_lock_irq(&zfcp_data.config_lock);	adapter = zfcp_get_adapter_by_busid(zfcp_data.init_busid);	if (adapter)		zfcp_adapter_get(adapter);	read_unlock_irq(&zfcp_data.config_lock);	if (adapter == NULL)		goto out_adapter;	port = zfcp_port_enqueue(adapter, zfcp_data.init_wwpn, 0, 0);	if (!port)		goto out_port;	unit = zfcp_unit_enqueue(port, zfcp_data.init_fcp_lun);	if (!unit)		goto out_unit;	up(&zfcp_data.config_sema);	ccw_device_set_online(adapter->ccw_device);	zfcp_erp_wait(adapter);	down(&zfcp_data.config_sema);	zfcp_unit_put(unit); out_unit:	zfcp_port_put(port); out_port:	zfcp_adapter_put(adapter); out_adapter:	up(&zfcp_data.config_sema);	return;}static int calc_alignment(int size){	int align = 1;	if (!size)		return 0;	while ((size - align) > 0)		align <<= 1;	return align;}static int __initzfcp_module_init(void){	int retval = -ENOMEM;	int size, align;	size = sizeof(struct zfcp_fsf_req_qtcb);	align = calc_alignment(size);	zfcp_data.fsf_req_qtcb_cache =		kmem_cache_create("zfcp_fsf", size, align, 0, NULL);	if (!zfcp_data.fsf_req_qtcb_cache)		goto out;	size = sizeof(struct fsf_status_read_buffer);	align = calc_alignment(size);	zfcp_data.sr_buffer_cache =		kmem_cache_create("zfcp_sr", size, align, 0, NULL);	if (!zfcp_data.sr_buffer_cache)		goto out_sr_cache;	size = sizeof(struct zfcp_gid_pn_data);	align = calc_alignment(size);	zfcp_data.gid_pn_cache =		kmem_cache_create("zfcp_gid", size, align, 0, NULL);	if (!zfcp_data.gid_pn_cache)		goto out_gid_cache;	atomic_set(&zfcp_data.loglevel, loglevel);	/* initialize adapter list */	INIT_LIST_HEAD(&zfcp_data.adapter_list_head);	/* initialize adapters to be removed list head */	INIT_LIST_HEAD(&zfcp_data.adapter_remove_lh);	zfcp_data.scsi_transport_template =		fc_attach_transport(&zfcp_transport_functions);	if (!zfcp_data.scsi_transport_template)		goto out_transport;	retval = misc_register(&zfcp_cfdc_misc);	if (retval != 0) {		ZFCP_LOG_INFO("registration of misc device "			      "zfcp_cfdc failed\n");		goto out_misc;	}	ZFCP_LOG_TRACE("major/minor for zfcp_cfdc: %d/%d\n",		       ZFCP_CFDC_DEV_MAJOR, zfcp_cfdc_misc.minor);	/* Initialise proc semaphores */	sema_init(&zfcp_data.config_sema, 1);	/* initialise configuration rw lock */	rwlock_init(&zfcp_data.config_lock);	/* setup dynamic I/O */	retval = zfcp_ccw_register();	if (retval) {		ZFCP_LOG_NORMAL("registration with common I/O layer failed\n");		goto out_ccw_register;	}	if (zfcp_device_setup(device))		zfcp_init_device_configure();	goto out; out_ccw_register:	misc_deregister(&zfcp_cfdc_misc); out_misc:	fc_release_transport(zfcp_data.scsi_transport_template); out_transport:	kmem_cache_destroy(zfcp_data.gid_pn_cache); out_gid_cache:	kmem_cache_destroy(zfcp_data.sr_buffer_cache); out_sr_cache:	kmem_cache_destroy(zfcp_data.fsf_req_qtcb_cache); out:	return retval;}/* * function:    zfcp_cfdc_dev_ioctl * * purpose:     Handle control file upload/download transaction via IOCTL *		interface * * returns:     0           - Operation completed successfuly *              -ENOTTY     - Unknown IOCTL command *              -EINVAL     - Invalid sense data record *              -ENXIO      - The FCP adapter is not available *              -EOPNOTSUPP - The FCP adapter does not have CFDC support *              -ENOMEM     - Insufficient memory *              -EFAULT     - User space memory I/O operation fault *              -EPERM      - Cannot create or queue FSF request or create SBALs *              -ERESTARTSYS- Received signal (is mapped to EAGAIN by VFS) */static longzfcp_cfdc_dev_ioctl(struct file *file, unsigned int command,		    unsigned long buffer){	struct zfcp_cfdc_sense_data *sense_data, __user *sense_data_user;	struct zfcp_adapter *adapter = NULL;	struct zfcp_fsf_req *fsf_req = NULL;	struct zfcp_sg_list *sg_list = NULL;	u32 fsf_command, option;	char *bus_id = NULL;	int retval = 0;	sense_data = kmalloc(sizeof(struct zfcp_cfdc_sense_data), GFP_KERNEL);	if (sense_data == NULL) {		retval = -ENOMEM;		goto out;	}	sg_list = kzalloc(sizeof(struct zfcp_sg_list), GFP_KERNEL);	if (sg_list == NULL) {		retval = -ENOMEM;		goto out;	}	if (command != ZFCP_CFDC_IOC) {		ZFCP_LOG_INFO("IOC request code 0x%x invalid\n", command);		retval = -ENOTTY;		goto out;	}	if ((sense_data_user = (void __user *) buffer) == NULL) {		ZFCP_LOG_INFO("sense data record is required\n");		retval = -EINVAL;		goto out;	}	retval = copy_from_user(sense_data, sense_data_user,				sizeof(struct zfcp_cfdc_sense_data));	if (retval) {		retval = -EFAULT;		goto out;	}	if (sense_data->signature != ZFCP_CFDC_SIGNATURE) {		ZFCP_LOG_INFO("invalid sense data request signature 0x%08x\n",			      ZFCP_CFDC_SIGNATURE);		retval = -EINVAL;		goto out;	}	switch (sense_data->command) {	case ZFCP_CFDC_CMND_DOWNLOAD_NORMAL:		fsf_command = FSF_QTCB_DOWNLOAD_CONTROL_FILE;		option = FSF_CFDC_OPTION_NORMAL_MODE;		break;	case ZFCP_CFDC_CMND_DOWNLOAD_FORCE:		fsf_command = FSF_QTCB_DOWNLOAD_CONTROL_FILE;		option = FSF_CFDC_OPTION_FORCE;		break;	case ZFCP_CFDC_CMND_FULL_ACCESS:		fsf_command = FSF_QTCB_DOWNLOAD_CONTROL_FILE;		option = FSF_CFDC_OPTION_FULL_ACCESS;		break;	case ZFCP_CFDC_CMND_RESTRICTED_ACCESS:		fsf_command = FSF_QTCB_DOWNLOAD_CONTROL_FILE;		option = FSF_CFDC_OPTION_RESTRICTED_ACCESS;		break;	case ZFCP_CFDC_CMND_UPLOAD:		fsf_command = FSF_QTCB_UPLOAD_CONTROL_FILE;		option = 0;		break;	default:		ZFCP_LOG_INFO("invalid command code 0x%08x\n",			      sense_data->command);		retval = -EINVAL;		goto out;	}	bus_id = kmalloc(BUS_ID_SIZE, GFP_KERNEL);	if (bus_id == NULL) {		retval = -ENOMEM;		goto out;	}	snprintf(bus_id, BUS_ID_SIZE, "%d.%d.%04x",		(sense_data->devno >> 24),		(sense_data->devno >> 16) & 0xFF,		(sense_data->devno & 0xFFFF));	read_lock_irq(&zfcp_data.config_lock);	adapter = zfcp_get_adapter_by_busid(bus_id);	if (adapter)		zfcp_adapter_get(adapter);	read_unlock_irq(&zfcp_data.config_lock);	kfree(bus_id);	if (adapter == NULL) {		ZFCP_LOG_INFO("invalid adapter\n");		retval = -ENXIO;		goto out;	}	if (sense_data->command & ZFCP_CFDC_WITH_CONTROL_FILE) {		retval = zfcp_sg_list_alloc(sg_list,

⌨️ 快捷键说明

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