zfcp_aux.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,982 行 · 第 1/4 页

C
1,982
字号
/* * * linux/drivers/s390/scsi/zfcp_aux.c * * FCP adapter driver for IBM eServer zSeries * * (C) Copyright IBM Corp. 2002, 2004 * * Author(s): Martin Peschke <mpeschke@de.ibm.com> *            Raimund Schroeder <raimund.schroeder@de.ibm.com> *            Aron Zeh *            Wolfgang Taphorn *            Stefan Bader <stefan.bader@de.ibm.com> *            Heiko Carstens <heiko.carstens@de.ibm.com> * * 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. *//* this drivers version (do not edit !!! generated and updated by cvs) */#define ZFCP_AUX_REVISION "$Revision: 1.129 $"#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 inline int zfcp_sg_list_alloc(struct zfcp_sg_list *, size_t);static inline void zfcp_sg_list_free(struct zfcp_sg_list *);static inline int zfcp_sg_list_copy_from_user(struct zfcp_sg_list *,					      void __user *, size_t);static inline int zfcp_sg_list_copy_to_user(void __user *,					    struct zfcp_sg_list *, size_t);static int zfcp_cfdc_dev_ioctl(struct inode *, 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)#ifdef CONFIG_S390_SUPPORTstatic struct ioctl_trans zfcp_ioctl_trans = {ZFCP_CFDC_IOC, (void*) sys_ioctl};#endifstatic struct file_operations zfcp_cfdc_fops = {	.ioctl = zfcp_cfdc_dev_ioctl};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("Heiko Carstens <heiko.carstens@de.ibm.com>, "	      "Martin Peschke <mpeschke@de.ibm.com>, "	      "Raimund Schroeder <raimund.schroeder@de.ibm.com>, "	      "Wolfgang Taphorn <taphorn@de.ibm.com>, "	      "Aron Zeh <arzeh@de.ibm.com>, "	      "IBM Deutschland Entwicklung GmbH");MODULE_DESCRIPTION    ("FCP (SCSI over Fibre Channel) HBA driver for IBM eServer zSeries");MODULE_LICENSE("GPL");module_param(device, charp, 0);MODULE_PARM_DESC(device, "specify initial device");module_param(loglevel, uint, 0);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");#ifdef ZFCP_PRINT_FLAGSu32 flags_dump = 0;module_param(flags_dump, uint, 0);#endif/****************************************************************//************** 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");}/****************************************************************//************** Uncategorised Functions *************************//****************************************************************/#define ZFCP_LOG_AREA			ZFCP_LOG_AREA_OTHERstatic inline intzfcp_fsf_req_is_scsi_cmnd(struct zfcp_fsf_req *fsf_req){	return ((fsf_req->fsf_command == FSF_QTCB_FCP_CMND) &&		!(fsf_req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT));}voidzfcp_cmd_dbf_event_fsf(const char *text, struct zfcp_fsf_req *fsf_req,		       void *add_data, int add_length){	struct zfcp_adapter *adapter = fsf_req->adapter;	struct scsi_cmnd *scsi_cmnd;	int level = 3;	int i;	unsigned long flags;	write_lock_irqsave(&adapter->cmd_dbf_lock, flags);	if (zfcp_fsf_req_is_scsi_cmnd(fsf_req)) {		scsi_cmnd = fsf_req->data.send_fcp_command_task.scsi_cmnd;		debug_text_event(adapter->cmd_dbf, level, "fsferror");		debug_text_event(adapter->cmd_dbf, level, text);		debug_event(adapter->cmd_dbf, level, &fsf_req,			    sizeof (unsigned long));		debug_event(adapter->cmd_dbf, level, &fsf_req->seq_no,			    sizeof (u32));		debug_event(adapter->cmd_dbf, level, &scsi_cmnd,			    sizeof (unsigned long));		debug_event(adapter->cmd_dbf, level, &scsi_cmnd->cmnd,			    min(ZFCP_CMD_DBF_LENGTH, (int)scsi_cmnd->cmd_len));		for (i = 0; i < add_length; i += ZFCP_CMD_DBF_LENGTH)			debug_event(adapter->cmd_dbf,				    level,				    (char *) add_data + i,				    min(ZFCP_CMD_DBF_LENGTH, add_length - i));	}	write_unlock_irqrestore(&adapter->cmd_dbf_lock, flags);}/* XXX additionally log unit if available *//* ---> introduce new parameter for unit, see 2.4 code */voidzfcp_cmd_dbf_event_scsi(const char *text, struct scsi_cmnd *scsi_cmnd){	struct zfcp_adapter *adapter;	union zfcp_req_data *req_data;	struct zfcp_fsf_req *fsf_req;	int level = ((host_byte(scsi_cmnd->result) != 0) ? 1 : 5);	unsigned long flags;	adapter = (struct zfcp_adapter *) scsi_cmnd->device->host->hostdata[0];	req_data = (union zfcp_req_data *) scsi_cmnd->host_scribble;	fsf_req = (req_data ? req_data->send_fcp_command_task.fsf_req : NULL);	write_lock_irqsave(&adapter->cmd_dbf_lock, flags);	debug_text_event(adapter->cmd_dbf, level, "hostbyte");	debug_text_event(adapter->cmd_dbf, level, text);	debug_event(adapter->cmd_dbf, level, &scsi_cmnd->result, sizeof (u32));	debug_event(adapter->cmd_dbf, level, &scsi_cmnd,		    sizeof (unsigned long));	debug_event(adapter->cmd_dbf, level, &scsi_cmnd->cmnd,		    min(ZFCP_CMD_DBF_LENGTH, (int)scsi_cmnd->cmd_len));	if (likely(fsf_req)) {		debug_event(adapter->cmd_dbf, level, &fsf_req,			    sizeof (unsigned long));		debug_event(adapter->cmd_dbf, level, &fsf_req->seq_no,			    sizeof (u32));	} else {		debug_text_event(adapter->cmd_dbf, level, "");		debug_text_event(adapter->cmd_dbf, level, "");	}	write_unlock_irqrestore(&adapter->cmd_dbf_lock, flags);}voidzfcp_in_els_dbf_event(struct zfcp_adapter *adapter, const char *text,		      struct fsf_status_read_buffer *status_buffer, int length){	int level = 1;	int i;	debug_text_event(adapter->in_els_dbf, level, text);	debug_event(adapter->in_els_dbf, level, &status_buffer->d_id, 8);	for (i = 0; i < length; i += ZFCP_IN_ELS_DBF_LENGTH)		debug_event(adapter->in_els_dbf,			    level,			    (char *) status_buffer->payload + i,			    min(ZFCP_IN_ELS_DBF_LENGTH, length - i));}/** * zfcp_device_setup - setup function * @str: pointer to parameter string * * Parse "device=..." parameter string. */static int __initzfcp_device_setup(char *str){	char *tmp;	if (!str)		return 0;	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;	return 1; err_out:	ZFCP_LOG_NORMAL("Parse error for device parameter string %s\n", 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);	wait_event(unit->scsi_add_wq, atomic_read(&unit->scsi_add_work) == 0);	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 __initzfcp_module_init(void){	int retval = 0;	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_transport_template = fc_attach_transport(&zfcp_transport_functions);	if (!zfcp_transport_template)		return -ENODEV;#ifdef CONFIG_S390_SUPPORT	retval = register_ioctl32_conversion(zfcp_ioctl_trans.cmd,					     zfcp_ioctl_trans.handler);	if (retval != 0) {		ZFCP_LOG_INFO("registration of ioctl32 conversion failed\n");		goto out_ioctl32;	}#endif	retval = misc_register(&zfcp_cfdc_misc);	if (retval != 0) {		ZFCP_LOG_INFO("registration of misc device "			      "zfcp_cfdc failed\n");		goto out_misc_register;	} else {		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);	/* save address of data structure managing the driver module */	zfcp_data.scsi_host_template.module = THIS_MODULE;	/* 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_register:#ifdef CONFIG_S390_SUPPORT	unregister_ioctl32_conversion(zfcp_ioctl_trans.cmd); out_ioctl32:#endif 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 intzfcp_cfdc_dev_ioctl(struct inode *inode, 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;	sg_list = kmalloc(sizeof(struct zfcp_sg_list), GFP_KERNEL);	if (sg_list == NULL) {		retval = -ENOMEM;		goto out;	}	memset(sg_list, 0, sizeof(*sg_list));	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,					    ZFCP_CFDC_MAX_CONTROL_FILE_SIZE);		if (retval) {			retval = -ENOMEM;			goto out;		}	}	if ((sense_data.command & ZFCP_CFDC_DOWNLOAD) &&	    (sense_data.command & ZFCP_CFDC_WITH_CONTROL_FILE)) {		retval = zfcp_sg_list_copy_from_user(			sg_list, &sense_data_user->control_file,			ZFCP_CFDC_MAX_CONTROL_FILE_SIZE);		if (retval) {			retval = -EFAULT;

⌨️ 快捷键说明

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