diff options
Diffstat (limited to 'drivers/s390/scsi/zfcp_aux.c')
| -rw-r--r-- | drivers/s390/scsi/zfcp_aux.c | 1689 | 
1 files changed, 326 insertions, 1363 deletions
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 8c7e2b778ef..90abfd06ed5 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -1,22 +1,9 @@  /* - * This file is part of the zfcp device driver for - * FCP adapters for IBM System z9 and zSeries. + * zfcp device driver   * - * (C) Copyright IBM Corp. 2002, 2006 + * Module interface and handling of zfcp data structures.   * - * 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. + * Copyright IBM Corporation 2002, 2008   */  /* @@ -31,93 +18,25 @@   *            Maxim Shchetynin   *            Volker Sameske   *            Ralph Wuerthner + *            Michael Loehr + *            Swen Schillig + *            Christof Schmitt + *            Martin Petermann + *            Sven Schuetz   */ +#include <linux/miscdevice.h>  #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_DESCRIPTION("FCP HBA driver");  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_FSF -  static int zfcp_reqlist_alloc(struct zfcp_adapter *adapter)  {  	int idx; @@ -132,11 +51,12 @@ static int zfcp_reqlist_alloc(struct zfcp_adapter *adapter)  	return 0;  } -static void zfcp_reqlist_free(struct zfcp_adapter *adapter) -{ -	kfree(adapter->req_list); -} - +/** + * zfcp_reqlist_isempty - is the request list empty + * @adapter: pointer to struct zfcp_adapter + * + * Returns: true if list is empty, false otherwise + */  int zfcp_reqlist_isempty(struct zfcp_adapter *adapter)  {  	unsigned int idx; @@ -147,62 +67,58 @@ int zfcp_reqlist_isempty(struct zfcp_adapter *adapter)  	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 __init -zfcp_device_setup(char *devstr) +static int __init zfcp_device_setup(char *devstr)  { -	char *tmp, *str; -	size_t len; +	char *token; +	char *str;  	if (!devstr)  		return 0; -	len = strlen(devstr) + 1; -	str = kmalloc(len, GFP_KERNEL); +	/* duplicate devstr and keep the original for sysfs presentation*/ +	str = kmalloc(strlen(devstr) + 1, GFP_KERNEL);  	if (!str) -		goto err_out; -	memcpy(str, devstr, len); +		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'; +	strcpy(str, devstr); -	zfcp_data.init_wwpn = simple_strtoull(tmp, &tmp, 0); -	if (*tmp++ != ',') +	token = strsep(&str, ","); +	if (!token || strlen(token) >= BUS_ID_SIZE)  		goto err_out; -	if (*tmp == '\0') +	strncpy(zfcp_data.init_busid, token, BUS_ID_SIZE); + +	token = strsep(&str, ","); +	if (!token || strict_strtoull(token, 0, &zfcp_data.init_wwpn))  		goto err_out; -	zfcp_data.init_fcp_lun = simple_strtoull(tmp, &tmp, 0); -	if (*tmp != '\0') +	token = strsep(&str, ","); +	if (!token || strict_strtoull(token, 0, &zfcp_data.init_fcp_lun))  		goto err_out; +  	kfree(str);  	return 1;   err_out: -	ZFCP_LOG_NORMAL("Parse error for device parameter string %s\n", str);  	kfree(str); +	pr_err("zfcp: Parse error for device parameter string %s, " +	       "device not attached.\n", devstr);  	return 0;  } -static void __init -zfcp_init_device_configure(void) +static struct zfcp_adapter *zfcp_get_adapter_by_busid(char *bus_id) +{ +	struct zfcp_adapter *adapter; + +	list_for_each_entry(adapter, &zfcp_data.adapter_list_head, list) +		if ((strncmp(bus_id, adapter->ccw_device->dev.bus_id, +			     BUS_ID_SIZE) == 0) && +		    !(atomic_read(&adapter->status) & +		      ZFCP_STATUS_COMMON_REMOVE)) +		    return adapter; +	return NULL; +} + +static void __init zfcp_init_device_configure(void)  {  	struct zfcp_adapter *adapter;  	struct zfcp_port *port; @@ -215,101 +131,75 @@ zfcp_init_device_configure(void)  		zfcp_adapter_get(adapter);  	read_unlock_irq(&zfcp_data.config_lock); -	if (adapter == NULL) +	if (!adapter)  		goto out_adapter;  	port = zfcp_port_enqueue(adapter, zfcp_data.init_wwpn, 0, 0); -	if (!port) +	if (IS_ERR(port))  		goto out_port;  	unit = zfcp_unit_enqueue(port, zfcp_data.init_fcp_lun); -	if (!unit) +	if (IS_ERR(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: +out_unit:  	zfcp_port_put(port); - out_port: +out_port:  	zfcp_adapter_put(adapter); - out_adapter: +out_adapter:  	up(&zfcp_data.config_sema);  	return;  } -static int calc_alignment(int size) +static struct kmem_cache *zfcp_cache_create(int size, char *name)  {  	int align = 1; - -	if (!size) -		return 0; -  	while ((size - align) > 0)  		align <<= 1; - -	return align; +	return kmem_cache_create(name , size, align, 0, NULL);  } -static int __init -zfcp_module_init(void) +static int __init zfcp_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); +	zfcp_data.fsf_req_qtcb_cache = zfcp_cache_create( +			sizeof(struct zfcp_fsf_req_qtcb), "zfcp_fsf");  	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); +	zfcp_data.sr_buffer_cache = zfcp_cache_create( +			sizeof(struct fsf_status_read_buffer), "zfcp_sr");  	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); +	zfcp_data.gid_pn_cache = zfcp_cache_create( +			sizeof(struct zfcp_gid_pn_data), "zfcp_gid");  	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); +	sema_init(&zfcp_data.config_sema, 1); +	rwlock_init(&zfcp_data.config_lock); +  	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"); +	if (retval) { +		pr_err("zfcp: 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"); +		pr_err("zfcp: Registration with common I/O layer failed.\n");  		goto out_ccw_register;  	} @@ -318,527 +208,88 @@ zfcp_module_init(void)  	goto out; - out_ccw_register: +out_ccw_register:  	misc_deregister(&zfcp_cfdc_misc); - out_misc: +out_misc:  	fc_release_transport(zfcp_data.scsi_transport_template); - out_transport: +out_transport:  	kmem_cache_destroy(zfcp_data.gid_pn_cache); - out_gid_cache: +out_gid_cache:  	kmem_cache_destroy(zfcp_data.sr_buffer_cache); - out_sr_cache: +out_sr_cache:  	kmem_cache_destroy(zfcp_data.fsf_req_qtcb_cache); - out: +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 long -zfcp_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, -					    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; -			goto out; -		} -	} - -	retval = zfcp_fsf_control_file(adapter, &fsf_req, fsf_command, -				       option, sg_list); -	if (retval) -		goto out; - -	if ((fsf_req->qtcb->prefix.prot_status != FSF_PROT_GOOD) && -	    (fsf_req->qtcb->prefix.prot_status != FSF_PROT_FSF_STATUS_PRESENTED)) { -		retval = -ENXIO; -		goto out; -	} - -	sense_data->fsf_status = fsf_req->qtcb->header.fsf_status; -	memcpy(&sense_data->fsf_status_qual, -	       &fsf_req->qtcb->header.fsf_status_qual, -	       sizeof(union fsf_status_qual)); -	memcpy(&sense_data->payloads, &fsf_req->qtcb->bottom.support.els, 256); - -	retval = copy_to_user(sense_data_user, sense_data, -		sizeof(struct zfcp_cfdc_sense_data)); -	if (retval) { -		retval = -EFAULT; -		goto out; -	} - -	if (sense_data->command & ZFCP_CFDC_UPLOAD) { -		retval = zfcp_sg_list_copy_to_user( -			&sense_data_user->control_file, sg_list, -			ZFCP_CFDC_MAX_CONTROL_FILE_SIZE); -		if (retval) { -			retval = -EFAULT; -			goto out; -		} -	} - - out: -	if (fsf_req != NULL) -		zfcp_fsf_req_free(fsf_req); - -	if ((adapter != NULL) && (retval != -ENXIO)) -		zfcp_adapter_put(adapter); - -	if (sg_list != NULL) { -		zfcp_sg_list_free(sg_list); -		kfree(sg_list); -	} - -	kfree(sense_data); - -	return retval; -} - - -/** - * zfcp_sg_list_alloc - create a scatter-gather list of the specified size - * @sg_list: structure describing a scatter gather list - * @size: size of scatter-gather list - * Return: 0 on success, else -ENOMEM - * - * In sg_list->sg a pointer to the created scatter-gather list is returned, - * or NULL if we run out of memory. sg_list->count specifies the number of - * elements of the scatter-gather list. The maximum size of a single element - * in the scatter-gather list is PAGE_SIZE. - */ -static int -zfcp_sg_list_alloc(struct zfcp_sg_list *sg_list, size_t size) -{ -	struct scatterlist *sg; -	unsigned int i; -	int retval = 0; -	void *address; - -	BUG_ON(sg_list == NULL); - -	sg_list->count = size >> PAGE_SHIFT; -	if (size & ~PAGE_MASK) -		sg_list->count++; -	sg_list->sg = kcalloc(sg_list->count, sizeof(struct scatterlist), -			      GFP_KERNEL); -	if (sg_list->sg == NULL) { -		sg_list->count = 0; -		retval = -ENOMEM; -		goto out; -	} -	sg_init_table(sg_list->sg, sg_list->count); - -	for (i = 0, sg = sg_list->sg; i < sg_list->count; i++, sg++) { -		address = (void *) get_zeroed_page(GFP_KERNEL); -		if (address == NULL) { -			sg_list->count = i; -			zfcp_sg_list_free(sg_list); -			retval = -ENOMEM; -			goto out; -		} -		zfcp_address_to_sg(address, sg, min(size, PAGE_SIZE)); -		size -= sg->length; -	} - - out: -	return retval; -} - - -/** - * zfcp_sg_list_free - free memory of a scatter-gather list - * @sg_list: structure describing a scatter-gather list - * - * Memory for each element in the scatter-gather list is freed. - * Finally sg_list->sg is freed itself and sg_list->count is reset. - */ -static void -zfcp_sg_list_free(struct zfcp_sg_list *sg_list) -{ -	struct scatterlist *sg; -	unsigned int i; - -	BUG_ON(sg_list == NULL); - -	for (i = 0, sg = sg_list->sg; i < sg_list->count; i++, sg++) -		free_page((unsigned long) zfcp_sg_to_address(sg)); - -	sg_list->count = 0; -	kfree(sg_list->sg); -} - -/** - * zfcp_sg_size - determine size of a scatter-gather list - * @sg: array of (struct scatterlist) - * @sg_count: elements in array - * Return: size of entire scatter-gather list - */ -static size_t zfcp_sg_size(struct scatterlist *sg, unsigned int sg_count) -{ -	unsigned int i; -	struct scatterlist *p; -	size_t size; - -	size = 0; -	for (i = 0, p = sg; i < sg_count; i++, p++) { -		BUG_ON(p == NULL); -		size += p->length; -	} - -	return size; -} - - -/** - * zfcp_sg_list_copy_from_user -copy data from user space to scatter-gather list - * @sg_list: structure describing a scatter-gather list - * @user_buffer: pointer to buffer in user space - * @size: number of bytes to be copied - * Return: 0 on success, -EFAULT if copy_from_user fails. - */ -static int -zfcp_sg_list_copy_from_user(struct zfcp_sg_list *sg_list, -			    void __user *user_buffer, -                            size_t size) -{ -	struct scatterlist *sg; -	unsigned int length; -	void *zfcp_buffer; -	int retval = 0; - -	BUG_ON(sg_list == NULL); - -	if (zfcp_sg_size(sg_list->sg, sg_list->count) < size) -		return -EFAULT; - -	for (sg = sg_list->sg; size > 0; sg++) { -		length = min((unsigned int)size, sg->length); -		zfcp_buffer = zfcp_sg_to_address(sg); -		if (copy_from_user(zfcp_buffer, user_buffer, length)) { -			retval = -EFAULT; -			goto out; -		} -		user_buffer += length; -		size -= length; -	} - - out: -	return retval; -} - - -/** - * zfcp_sg_list_copy_to_user - copy data from scatter-gather list to user space - * @user_buffer: pointer to buffer in user space - * @sg_list: structure describing a scatter-gather list - * @size: number of bytes to be copied - * Return: 0 on success, -EFAULT if copy_to_user fails - */ -static int -zfcp_sg_list_copy_to_user(void __user  *user_buffer, -			  struct zfcp_sg_list *sg_list, -                          size_t size) -{ -	struct scatterlist *sg; -	unsigned int length; -	void *zfcp_buffer; -	int retval = 0; - -	BUG_ON(sg_list == NULL); - -	if (zfcp_sg_size(sg_list->sg, sg_list->count) < size) -		return -EFAULT; - -	for (sg = sg_list->sg; size > 0; sg++) { -		length = min((unsigned int) size, sg->length); -		zfcp_buffer = zfcp_sg_to_address(sg); -		if (copy_to_user(user_buffer, zfcp_buffer, length)) { -			retval = -EFAULT; -			goto out; -		} -		user_buffer += length; -		size -= length; -	} - - out: -	return retval; -} - - -#undef ZFCP_LOG_AREA - -/****************************************************************/ -/****** Functions for configuration/set-up of structures ********/ -/****************************************************************/ - -#define ZFCP_LOG_AREA			ZFCP_LOG_AREA_CONFIG +module_init(zfcp_module_init);  /**   * zfcp_get_unit_by_lun - find unit in unit list of port by FCP LUN   * @port: pointer to port to search for unit   * @fcp_lun: FCP LUN to search for - * Traverse list of all units of a port and return pointer to a unit - * with the given FCP LUN. + * + * Returns: pointer to zfcp_unit or NULL   */ -struct zfcp_unit * -zfcp_get_unit_by_lun(struct zfcp_port *port, fcp_lun_t fcp_lun) +struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *port, +				       fcp_lun_t fcp_lun)  {  	struct zfcp_unit *unit; -	int found = 0; -	list_for_each_entry(unit, &port->unit_list_head, list) { +	list_for_each_entry(unit, &port->unit_list_head, list)  		if ((unit->fcp_lun == fcp_lun) && -		    !atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status)) -		{ -			found = 1; -			break; -		} -	} -	return found ? unit : NULL; +		    !(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_REMOVE)) +		    return unit; +	return NULL;  }  /**   * zfcp_get_port_by_wwpn - find port in port list of adapter by wwpn   * @adapter: pointer to adapter to search for port   * @wwpn: wwpn to search for - * Traverse list of all ports of an adapter and return pointer to a port - * with the given wwpn. - */ -struct zfcp_port * -zfcp_get_port_by_wwpn(struct zfcp_adapter *adapter, wwn_t wwpn) -{ -	struct zfcp_port *port; -	int found = 0; - -	list_for_each_entry(port, &adapter->port_list_head, list) { -		if ((port->wwpn == wwpn) && -		    !(atomic_read(&port->status) & -		      (ZFCP_STATUS_PORT_NO_WWPN | ZFCP_STATUS_COMMON_REMOVE))) { -			found = 1; -			break; -		} -	} -	return found ? port : NULL; -} - -/** - * zfcp_get_port_by_did - find port in port list of adapter by d_id - * @adapter: pointer to adapter to search for port - * @d_id: d_id to search for - * Traverse list of all ports of an adapter and return pointer to a port - * with the given d_id. + * + * Returns: pointer to zfcp_port or NULL   */ -struct zfcp_port * -zfcp_get_port_by_did(struct zfcp_adapter *adapter, u32 d_id) +struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *adapter, +					wwn_t wwpn)  {  	struct zfcp_port *port; -	int found = 0; -	list_for_each_entry(port, &adapter->port_list_head, list) { -		if ((port->d_id == d_id) && -		    !atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status)) -		{ -			found = 1; -			break; -		} -	} -	return found ? port : NULL; +	list_for_each_entry(port, &adapter->port_list_head, list) +		if ((port->wwpn == wwpn) && !(atomic_read(&port->status) & +		      (ZFCP_STATUS_PORT_NO_WWPN | ZFCP_STATUS_COMMON_REMOVE))) +			return port; +	return NULL;  } -/** - * zfcp_get_adapter_by_busid - find adpater in adapter list by bus_id - * @bus_id: bus_id to search for - * Traverse list of all adapters and return pointer to an adapter - * with the given bus_id. - */ -struct zfcp_adapter * -zfcp_get_adapter_by_busid(char *bus_id) +static void zfcp_sysfs_unit_release(struct device *dev)  { -	struct zfcp_adapter *adapter; -	int found = 0; - -	list_for_each_entry(adapter, &zfcp_data.adapter_list_head, list) { -		if ((strncmp(bus_id, zfcp_get_busid_by_adapter(adapter), -			     BUS_ID_SIZE) == 0) && -		    !atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, -				      &adapter->status)){ -			found = 1; -			break; -		} -	} -	return found ? adapter : NULL; +	kfree(container_of(dev, struct zfcp_unit, sysfs_device));  }  /**   * zfcp_unit_enqueue - enqueue unit to unit list of a port.   * @port: pointer to port where unit is added   * @fcp_lun: FCP LUN of unit to be enqueued - * Return: pointer to enqueued unit on success, NULL on error + * Returns: pointer to enqueued unit on success, ERR_PTR on error   * Locks: config_sema must be held to serialize changes to the unit list   *   * Sets up some unit internal structures and creates sysfs entry.   */ -struct zfcp_unit * -zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun) +struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun)  {  	struct zfcp_unit *unit; -	/* -	 * check that there is no unit with this FCP_LUN already in list -	 * and enqueue it. -	 * Note: Unlike for the adapter and the port, this is an error -	 */ -	read_lock_irq(&zfcp_data.config_lock); -	unit = zfcp_get_unit_by_lun(port, fcp_lun); -	read_unlock_irq(&zfcp_data.config_lock); -	if (unit) -		return NULL; - -	unit = kzalloc(sizeof (struct zfcp_unit), GFP_KERNEL); +	unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL);  	if (!unit) -		return NULL; +		return ERR_PTR(-ENOMEM); -	/* initialise reference count stuff */  	atomic_set(&unit->refcount, 0);  	init_waitqueue_head(&unit->remove_wq);  	unit->port = port;  	unit->fcp_lun = fcp_lun; -	/* setup for sysfs registration */  	snprintf(unit->sysfs_device.bus_id, BUS_ID_SIZE, "0x%016llx", fcp_lun);  	unit->sysfs_device.parent = &port->sysfs_device;  	unit->sysfs_device.release = zfcp_sysfs_unit_release; @@ -847,14 +298,28 @@ zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun)  	/* mark unit unusable as long as sysfs registration is not complete */  	atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); -	if (device_register(&unit->sysfs_device)) { -		kfree(unit); -		return NULL; +	spin_lock_init(&unit->latencies.lock); +	unit->latencies.write.channel.min = 0xFFFFFFFF; +	unit->latencies.write.fabric.min = 0xFFFFFFFF; +	unit->latencies.read.channel.min = 0xFFFFFFFF; +	unit->latencies.read.fabric.min = 0xFFFFFFFF; +	unit->latencies.cmd.channel.min = 0xFFFFFFFF; +	unit->latencies.cmd.fabric.min = 0xFFFFFFFF; + +	read_lock_irq(&zfcp_data.config_lock); +	if (zfcp_get_unit_by_lun(port, fcp_lun)) { +		read_unlock_irq(&zfcp_data.config_lock); +		goto err_out_free;  	} +	read_unlock_irq(&zfcp_data.config_lock); -	if (zfcp_sysfs_unit_create_files(&unit->sysfs_device)) { +	if (device_register(&unit->sysfs_device)) +		goto err_out_free; + +	if (sysfs_create_group(&unit->sysfs_device.kobj, +			       &zfcp_sysfs_unit_attrs)) {  		device_unregister(&unit->sysfs_device); -		return NULL; +		return ERR_PTR(-EIO);  	}  	zfcp_unit_get(unit); @@ -864,16 +329,27 @@ zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun)  	list_add_tail(&unit->list, &port->unit_list_head);  	atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status);  	atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status); +  	write_unlock_irq(&zfcp_data.config_lock);  	port->units++;  	zfcp_port_get(port);  	return unit; + +err_out_free: +	kfree(unit); +	return ERR_PTR(-EINVAL);  } -void -zfcp_unit_dequeue(struct zfcp_unit *unit) +/** + * zfcp_unit_dequeue - dequeue unit + * @unit: pointer to zfcp_unit + * + * waits until all work is done on unit and removes it then from the unit->list + * of the associated port. + */ +void zfcp_unit_dequeue(struct zfcp_unit *unit)  {  	zfcp_unit_wait(unit);  	write_lock_irq(&zfcp_data.config_lock); @@ -881,68 +357,51 @@ zfcp_unit_dequeue(struct zfcp_unit *unit)  	write_unlock_irq(&zfcp_data.config_lock);  	unit->port->units--;  	zfcp_port_put(unit->port); -	zfcp_sysfs_unit_remove_files(&unit->sysfs_device); +	sysfs_remove_group(&unit->sysfs_device.kobj, &zfcp_sysfs_unit_attrs);  	device_unregister(&unit->sysfs_device);  } -/* - * Allocates a combined QTCB/fsf_req buffer for erp actions and fcp/SCSI - * commands. - * It also genrates fcp-nameserver request/response buffer and unsolicited - * status read fsf_req buffers. - * - * locks:       must only be called with zfcp_data.config_sema taken - */ -static int -zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter) +static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter)  { +	/* must only be called with zfcp_data.config_sema taken */  	adapter->pool.fsf_req_erp = -		mempool_create_slab_pool(ZFCP_POOL_FSF_REQ_ERP_NR, -					 zfcp_data.fsf_req_qtcb_cache); +		mempool_create_slab_pool(1, zfcp_data.fsf_req_qtcb_cache);  	if (!adapter->pool.fsf_req_erp)  		return -ENOMEM;  	adapter->pool.fsf_req_scsi = -		mempool_create_slab_pool(ZFCP_POOL_FSF_REQ_SCSI_NR, -					 zfcp_data.fsf_req_qtcb_cache); +		mempool_create_slab_pool(1, zfcp_data.fsf_req_qtcb_cache);  	if (!adapter->pool.fsf_req_scsi)  		return -ENOMEM;  	adapter->pool.fsf_req_abort = -		mempool_create_slab_pool(ZFCP_POOL_FSF_REQ_ABORT_NR, -					 zfcp_data.fsf_req_qtcb_cache); +		mempool_create_slab_pool(1, zfcp_data.fsf_req_qtcb_cache);  	if (!adapter->pool.fsf_req_abort)  		return -ENOMEM;  	adapter->pool.fsf_req_status_read = -		mempool_create_kmalloc_pool(ZFCP_POOL_STATUS_READ_NR, +		mempool_create_kmalloc_pool(FSF_STATUS_READS_RECOM,  					    sizeof(struct zfcp_fsf_req));  	if (!adapter->pool.fsf_req_status_read)  		return -ENOMEM;  	adapter->pool.data_status_read = -		mempool_create_slab_pool(ZFCP_POOL_STATUS_READ_NR, +		mempool_create_slab_pool(FSF_STATUS_READS_RECOM,  					 zfcp_data.sr_buffer_cache);  	if (!adapter->pool.data_status_read)  		return -ENOMEM;  	adapter->pool.data_gid_pn = -		mempool_create_slab_pool(ZFCP_POOL_DATA_GID_PN_NR, -					 zfcp_data.gid_pn_cache); +		mempool_create_slab_pool(1, zfcp_data.gid_pn_cache);  	if (!adapter->pool.data_gid_pn)  		return -ENOMEM;  	return 0;  } -/** - * zfcp_free_low_mem_buffers - free memory pools of an adapter - * @adapter: pointer to zfcp_adapter for which memory pools should be freed - * locking:  zfcp_data.config_sema must be held - */ -static void -zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter) +static void zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter)  { +	/* zfcp_data.config_sema must be held */  	if (adapter->pool.fsf_req_erp)  		mempool_destroy(adapter->pool.fsf_req_erp);  	if (adapter->pool.fsf_req_scsi) @@ -962,20 +421,61 @@ static void zfcp_dummy_release(struct device *dev)  	return;  } -/* +/** + * zfcp_status_read_refill - refill the long running status_read_requests + * @adapter: ptr to struct zfcp_adapter for which the buffers should be refilled + * + * Returns: 0 on success, 1 otherwise + * + * if there are 16 or more status_read requests missing an adapter_reopen + * is triggered + */ +int zfcp_status_read_refill(struct zfcp_adapter *adapter) +{ +	while (atomic_read(&adapter->stat_miss) > 0) +		if (zfcp_fsf_status_read(adapter)) { +			if (atomic_read(&adapter->stat_miss) >= 16) { +				zfcp_erp_adapter_reopen(adapter, 0, 103, NULL); +				return 1; +			} +			break; +		} else +			atomic_dec(&adapter->stat_miss); +	return 0; +} + +static void _zfcp_status_read_scheduler(struct work_struct *work) +{ +	zfcp_status_read_refill(container_of(work, struct zfcp_adapter, +					     stat_work)); +} + +static int zfcp_nameserver_enqueue(struct zfcp_adapter *adapter) +{ +	struct zfcp_port *port; + +	port = zfcp_port_enqueue(adapter, 0, ZFCP_STATUS_PORT_WKA, +				 ZFCP_DID_DIRECTORY_SERVICE); +	if (IS_ERR(port)) +		return PTR_ERR(port); +	zfcp_port_put(port); + +	return 0; +} + +/** + * zfcp_adapter_enqueue - enqueue a new adapter to the list + * @ccw_device: pointer to the struct cc_device + * + * Returns:	0             if a new adapter was successfully enqueued + *		-ENOMEM       if alloc failed   * Enqueues an adapter at the end of the adapter list in the driver data.   * All adapter internal structures are set up.   * Proc-fs entries are also created. - * - * returns:	0             if a new adapter was successfully enqueued - *              ZFCP_KNOWN    if an adapter with this devno was already present - *		-ENOMEM       if alloc failed   * locks:	config_sema must be held to serialise changes to the adapter list   */ -struct zfcp_adapter * -zfcp_adapter_enqueue(struct ccw_device *ccw_device) +int zfcp_adapter_enqueue(struct ccw_device *ccw_device)  { -	int retval = 0;  	struct zfcp_adapter *adapter;  	/* @@ -983,85 +483,58 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)  	 * are protected by the config_sema, which must be held to get here  	 */ -	/* try to allocate new adapter data structure (zeroed) */ -	adapter = kzalloc(sizeof (struct zfcp_adapter), GFP_KERNEL); -	if (!adapter) { -		ZFCP_LOG_INFO("error: allocation of base adapter " -			      "structure failed\n"); -		goto out; -	} +	adapter = kzalloc(sizeof(struct zfcp_adapter), GFP_KERNEL); +	if (!adapter) +		return -ENOMEM;  	ccw_device->handler = NULL; - -	/* save ccw_device pointer */  	adapter->ccw_device = ccw_device; +	atomic_set(&adapter->refcount, 0); -	retval = zfcp_qdio_allocate_queues(adapter); -	if (retval) -		goto queues_alloc_failed; - -	retval = zfcp_qdio_allocate(adapter); -	if (retval) +	if (zfcp_qdio_allocate(adapter))  		goto qdio_allocate_failed; -	retval = zfcp_allocate_low_mem_buffers(adapter); -	if (retval) { -		ZFCP_LOG_INFO("error: pool allocation failed\n"); +	if (zfcp_allocate_low_mem_buffers(adapter))  		goto failed_low_mem_buffers; -	} -	/* initialise reference count stuff */ -	atomic_set(&adapter->refcount, 0); +	if (zfcp_reqlist_alloc(adapter)) +		goto failed_low_mem_buffers; + +	if (zfcp_adapter_debug_register(adapter)) +		goto debug_register_failed; +  	init_waitqueue_head(&adapter->remove_wq); +	init_waitqueue_head(&adapter->erp_thread_wqh); +	init_waitqueue_head(&adapter->erp_done_wqh); -	/* initialise list of ports */  	INIT_LIST_HEAD(&adapter->port_list_head); - -	/* initialise list of ports to be removed */  	INIT_LIST_HEAD(&adapter->port_remove_lh); +	INIT_LIST_HEAD(&adapter->erp_ready_head); +	INIT_LIST_HEAD(&adapter->erp_running_head); -	/* initialize list of fsf requests */  	spin_lock_init(&adapter->req_list_lock); -	retval = zfcp_reqlist_alloc(adapter); -	if (retval) { -		ZFCP_LOG_INFO("request list initialization failed\n"); -		goto failed_low_mem_buffers; -	} - -	/* initialize debug locks */  	spin_lock_init(&adapter->hba_dbf_lock);  	spin_lock_init(&adapter->san_dbf_lock);  	spin_lock_init(&adapter->scsi_dbf_lock);  	spin_lock_init(&adapter->rec_dbf_lock); - -	retval = zfcp_adapter_debug_register(adapter); -	if (retval) -		goto debug_register_failed; - -	/* initialize error recovery stuff */ +	spin_lock_init(&adapter->req_q.lock);  	rwlock_init(&adapter->erp_lock); -	sema_init(&adapter->erp_ready_sem, 0); -	INIT_LIST_HEAD(&adapter->erp_ready_head); -	INIT_LIST_HEAD(&adapter->erp_running_head); - -	/* initialize abort lock */  	rwlock_init(&adapter->abort_lock); -	/* initialise some erp stuff */ -	init_waitqueue_head(&adapter->erp_thread_wqh); -	init_waitqueue_head(&adapter->erp_done_wqh); +	sema_init(&adapter->erp_ready_sem, 0); -	/* initialize lock of associated request queue */ -	rwlock_init(&adapter->request_queue.queue_lock); +	INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler); +	INIT_WORK(&adapter->scan_work, _zfcp_scan_ports_later);  	/* mark adapter unusable as long as sysfs registration is not complete */  	atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status);  	dev_set_drvdata(&ccw_device->dev, adapter); -	if (zfcp_sysfs_adapter_create_files(&ccw_device->dev)) +	if (sysfs_create_group(&ccw_device->dev.kobj, +			       &zfcp_sysfs_adapter_attrs))  		goto sysfs_failed;  	adapter->generic_services.parent = &adapter->ccw_device->dev; @@ -1072,7 +545,6 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)  	if (device_register(&adapter->generic_services))  		goto generic_services_failed; -	/* put allocated adapter at list tail */  	write_lock_irq(&zfcp_data.config_lock);  	atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status);  	list_add_tail(&adapter->list, &zfcp_data.adapter_list_head); @@ -1080,57 +552,49 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)  	zfcp_data.adapters++; -	goto out; +	zfcp_nameserver_enqueue(adapter); - generic_services_failed: -	zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev); - sysfs_failed: +	return 0; + +generic_services_failed: +	sysfs_remove_group(&ccw_device->dev.kobj, +			   &zfcp_sysfs_adapter_attrs); +sysfs_failed:  	zfcp_adapter_debug_unregister(adapter); - debug_register_failed: +debug_register_failed:  	dev_set_drvdata(&ccw_device->dev, NULL); -	zfcp_reqlist_free(adapter); - failed_low_mem_buffers: +	kfree(adapter->req_list); +failed_low_mem_buffers:  	zfcp_free_low_mem_buffers(adapter); -	if (qdio_free(ccw_device) != 0) -		ZFCP_LOG_NORMAL("bug: qdio_free for adapter %s failed\n", -				zfcp_get_busid_by_adapter(adapter)); - qdio_allocate_failed: -	zfcp_qdio_free_queues(adapter); - queues_alloc_failed: +qdio_allocate_failed: +	zfcp_qdio_free(adapter);  	kfree(adapter); -	adapter = NULL; - out: -	return adapter; +	return -ENOMEM;  } -/* - * returns:	0 - struct zfcp_adapter  data structure successfully removed - *		!0 - struct zfcp_adapter  data structure could not be removed - *			(e.g. still used) +/** + * zfcp_adapter_dequeue - remove the adapter from the resource list + * @adapter: pointer to struct zfcp_adapter which should be removed   * locks:	adapter list write lock is assumed to be held by caller   */ -void -zfcp_adapter_dequeue(struct zfcp_adapter *adapter) +void zfcp_adapter_dequeue(struct zfcp_adapter *adapter)  {  	int retval = 0;  	unsigned long flags; +	cancel_work_sync(&adapter->scan_work); +	cancel_work_sync(&adapter->stat_work);  	zfcp_adapter_scsi_unregister(adapter);  	device_unregister(&adapter->generic_services); -	zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev); +	sysfs_remove_group(&adapter->ccw_device->dev.kobj, +			   &zfcp_sysfs_adapter_attrs);  	dev_set_drvdata(&adapter->ccw_device->dev, NULL);  	/* sanity check: no pending FSF requests */  	spin_lock_irqsave(&adapter->req_list_lock, flags);  	retval = zfcp_reqlist_isempty(adapter);  	spin_unlock_irqrestore(&adapter->req_list_lock, flags); -	if (!retval) { -		ZFCP_LOG_NORMAL("bug: adapter %s (%p) still in use, " -				"%i requests outstanding\n", -				zfcp_get_busid_by_adapter(adapter), adapter, -				atomic_read(&adapter->reqs_active)); -		retval = -EBUSY; -		goto out; -	} +	if (!retval) +		return;  	zfcp_adapter_debug_unregister(adapter); @@ -1142,26 +606,18 @@ zfcp_adapter_dequeue(struct zfcp_adapter *adapter)  	/* decrease number of adapters in list */  	zfcp_data.adapters--; -	ZFCP_LOG_TRACE("adapter %s (%p) removed from list, " -		       "%i adapters still in list\n", -		       zfcp_get_busid_by_adapter(adapter), -		       adapter, zfcp_data.adapters); - -	retval = qdio_free(adapter->ccw_device); -	if (retval) -		ZFCP_LOG_NORMAL("bug: qdio_free for adapter %s failed\n", -				zfcp_get_busid_by_adapter(adapter)); +	zfcp_qdio_free(adapter);  	zfcp_free_low_mem_buffers(adapter); -	/* free memory of adapter data structure and queues */ -	zfcp_qdio_free_queues(adapter); -	zfcp_reqlist_free(adapter); +	kfree(adapter->req_list);  	kfree(adapter->fc_stats);  	kfree(adapter->stats_reset_data); -	ZFCP_LOG_TRACE("freeing adapter structure\n");  	kfree(adapter); - out: -	return; +} + +static void zfcp_sysfs_port_release(struct device *dev) +{ +	kfree(container_of(dev, struct zfcp_port, sysfs_device));  }  /** @@ -1170,98 +626,90 @@ zfcp_adapter_dequeue(struct zfcp_adapter *adapter)   * @wwpn: WWPN of the remote port to be enqueued   * @status: initial status for the port   * @d_id: destination id of the remote port to be enqueued - * Return: pointer to enqueued port on success, NULL on error + * Returns: pointer to enqueued port on success, ERR_PTR on error   * Locks: config_sema must be held to serialize changes to the port list   *   * All port internal structures are set up and the sysfs entry is generated.   * d_id is used to enqueue ports with a well known address like the Directory   * Service for nameserver lookup.   */ -struct zfcp_port * -zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn, u32 status, -		  u32 d_id) +struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn, +				     u32 status, u32 d_id)  {  	struct zfcp_port *port; -	int check_wwpn; +	int retval; +	char *bus_id; -	check_wwpn = !(status & ZFCP_STATUS_PORT_NO_WWPN); -	/* -	 * check that there is no port with this WWPN already in list -	 */ -	if (check_wwpn) { -		read_lock_irq(&zfcp_data.config_lock); -		port = zfcp_get_port_by_wwpn(adapter, wwpn); -		read_unlock_irq(&zfcp_data.config_lock); -		if (port) -			return NULL; -	} - -	port = kzalloc(sizeof (struct zfcp_port), GFP_KERNEL); +	port = kzalloc(sizeof(struct zfcp_port), GFP_KERNEL);  	if (!port) -		return NULL; +		return ERR_PTR(-ENOMEM); -	/* initialise reference count stuff */ -	atomic_set(&port->refcount, 0);  	init_waitqueue_head(&port->remove_wq);  	INIT_LIST_HEAD(&port->unit_list_head);  	INIT_LIST_HEAD(&port->unit_remove_lh);  	port->adapter = adapter; +	port->d_id = d_id; +	port->wwpn = wwpn; -	if (check_wwpn) -		port->wwpn = wwpn; - -	atomic_set_mask(status, &port->status); +	/* mark port unusable as long as sysfs registration is not complete */ +	atomic_set_mask(status | ZFCP_STATUS_COMMON_REMOVE, &port->status); +	atomic_set(&port->refcount, 0); -	/* setup for sysfs registration */  	if (status & ZFCP_STATUS_PORT_WKA) {  		switch (d_id) {  		case ZFCP_DID_DIRECTORY_SERVICE: -			snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, -				 "directory"); +			bus_id = "directory";  			break;  		case ZFCP_DID_MANAGEMENT_SERVICE: -			snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, -				 "management"); +			bus_id = "management";  			break;  		case ZFCP_DID_KEY_DISTRIBUTION_SERVICE: -			snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, -				 "key_distribution"); +			bus_id = "key_distribution";  			break;  		case ZFCP_DID_ALIAS_SERVICE: -			snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, -				 "alias"); +			bus_id = "alias";  			break;  		case ZFCP_DID_TIME_SERVICE: -			snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, -				 "time"); +			bus_id = "time";  			break;  		default:  			kfree(port); -			return NULL; +			return ERR_PTR(-EINVAL);  		} -		port->d_id = d_id; +		snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, "%s", bus_id);  		port->sysfs_device.parent = &adapter->generic_services;  	} else {  		snprintf(port->sysfs_device.bus_id,  			 BUS_ID_SIZE, "0x%016llx", wwpn);  		port->sysfs_device.parent = &adapter->ccw_device->dev;  	} +  	port->sysfs_device.release = zfcp_sysfs_port_release;  	dev_set_drvdata(&port->sysfs_device, port); -	/* mark port unusable as long as sysfs registration is not complete */ -	atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); +	read_lock_irq(&zfcp_data.config_lock); +	if (!(status & ZFCP_STATUS_PORT_NO_WWPN)) +		if (zfcp_get_port_by_wwpn(adapter, wwpn)) { +			read_unlock_irq(&zfcp_data.config_lock); +			goto err_out_free; +		} +	read_unlock_irq(&zfcp_data.config_lock); -	if (device_register(&port->sysfs_device)) { -		kfree(port); -		return NULL; -	} +	if (device_register(&port->sysfs_device)) +		goto err_out_free; -	if (zfcp_sysfs_port_create_files(&port->sysfs_device, status)) { +	if (status & ZFCP_STATUS_PORT_WKA) +		retval = sysfs_create_group(&port->sysfs_device.kobj, +					    &zfcp_sysfs_ns_port_attrs); +	else +		retval = sysfs_create_group(&port->sysfs_device.kobj, +					    &zfcp_sysfs_port_attrs); + +	if (retval) {  		device_unregister(&port->sysfs_device); -		return NULL; +		goto err_out;  	}  	zfcp_port_get(port); @@ -1274,15 +722,23 @@ zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn, u32 status,  		if (!adapter->nameserver_port)  			adapter->nameserver_port = port;  	adapter->ports++; +  	write_unlock_irq(&zfcp_data.config_lock);  	zfcp_adapter_get(adapter); -  	return port; + +err_out_free: +	kfree(port); +err_out: +	return ERR_PTR(-EINVAL);  } -void -zfcp_port_dequeue(struct zfcp_port *port) +/** + * zfcp_port_dequeue - dequeues a port from the port list of the adapter + * @port: pointer to struct zfcp_port which should be removed + */ +void zfcp_port_dequeue(struct zfcp_port *port)  {  	zfcp_port_wait(port);  	write_lock_irq(&zfcp_data.config_lock); @@ -1293,546 +749,53 @@ zfcp_port_dequeue(struct zfcp_port *port)  		fc_remote_port_delete(port->rport);  	port->rport = NULL;  	zfcp_adapter_put(port->adapter); -	zfcp_sysfs_port_remove_files(&port->sysfs_device, -				     atomic_read(&port->status)); -	device_unregister(&port->sysfs_device); -} - -/* Enqueues a nameserver port */ -int -zfcp_nameserver_enqueue(struct zfcp_adapter *adapter) -{ -	struct zfcp_port *port; - -	port = zfcp_port_enqueue(adapter, 0, ZFCP_STATUS_PORT_WKA, -				 ZFCP_DID_DIRECTORY_SERVICE); -	if (!port) { -		ZFCP_LOG_INFO("error: enqueue of nameserver port for " -			      "adapter %s failed\n", -			      zfcp_get_busid_by_adapter(adapter)); -		return -ENXIO; -	} -	zfcp_port_put(port); - -	return 0; -} - -#undef ZFCP_LOG_AREA - -/****************************************************************/ -/******* Fibre Channel Standard related Functions  **************/ -/****************************************************************/ - -#define ZFCP_LOG_AREA                   ZFCP_LOG_AREA_FC - -static void zfcp_fsf_incoming_els_rscn(struct zfcp_fsf_req *fsf_req) -{ -	struct fsf_status_read_buffer *status_buffer = (void*)fsf_req->data; -	struct zfcp_adapter *adapter = fsf_req->adapter; -	struct fcp_rscn_head *fcp_rscn_head; -	struct fcp_rscn_element *fcp_rscn_element; -	struct zfcp_port *port; -	u16 i; -	u16 no_entries; -	u32 range_mask; -	unsigned long flags; - -	fcp_rscn_head = (struct fcp_rscn_head *) status_buffer->payload; -	fcp_rscn_element = (struct fcp_rscn_element *) status_buffer->payload; - -	/* see FC-FS */ -	no_entries = (fcp_rscn_head->payload_len / 4); - -	for (i = 1; i < no_entries; i++) { -		/* skip head and start with 1st element */ -		fcp_rscn_element++; -		switch (fcp_rscn_element->addr_format) { -		case ZFCP_PORT_ADDRESS: -			range_mask = ZFCP_PORTS_RANGE_PORT; -			break; -		case ZFCP_AREA_ADDRESS: -			range_mask = ZFCP_PORTS_RANGE_AREA; -			break; -		case ZFCP_DOMAIN_ADDRESS: -			range_mask = ZFCP_PORTS_RANGE_DOMAIN; -			break; -		case ZFCP_FABRIC_ADDRESS: -			range_mask = ZFCP_PORTS_RANGE_FABRIC; -			break; -		default: -			ZFCP_LOG_INFO("incoming RSCN with unknown " -				      "address format\n"); -			continue; -		} -		read_lock_irqsave(&zfcp_data.config_lock, flags); -		list_for_each_entry(port, &adapter->port_list_head, list) { -			if (atomic_test_mask -			    (ZFCP_STATUS_PORT_WKA, &port->status)) -				continue; -			/* Do we know this port? If not skip it. */ -			if (!atomic_test_mask -			    (ZFCP_STATUS_PORT_DID_DID, &port->status)) { -				ZFCP_LOG_INFO("incoming RSCN, trying to open " -					      "port 0x%016Lx\n", port->wwpn); -				zfcp_erp_port_reopen(port, -						     ZFCP_STATUS_COMMON_ERP_FAILED, -						     82, fsf_req); -				continue; -			} - -			/* -			 * FIXME: race: d_id might being invalidated -			 * (...DID_DID reset) -			 */ -			if ((port->d_id & range_mask) -			    == (fcp_rscn_element->nport_did & range_mask)) { -				ZFCP_LOG_TRACE("reopen did 0x%08x\n", -					       fcp_rscn_element->nport_did); -				/* -				 * Unfortunately, an RSCN does not specify the -				 * type of change a target underwent. We assume -				 * that it makes sense to reopen the link. -				 * FIXME: Shall we try to find out more about -				 * the target and link state before closing it? -				 * How to accomplish this? (nameserver?) -				 * Where would such code be put in? -				 * (inside or outside erp) -				 */ -				ZFCP_LOG_INFO("incoming RSCN, trying to open " -					      "port 0x%016Lx\n", port->wwpn); -				zfcp_test_link(port); -			} -		} -		read_unlock_irqrestore(&zfcp_data.config_lock, flags); -	} -} - -static void zfcp_fsf_incoming_els_plogi(struct zfcp_fsf_req *fsf_req) -{ -	struct fsf_status_read_buffer *status_buffer = (void*)fsf_req->data; -	struct zfcp_adapter *adapter = fsf_req->adapter; -	struct fsf_plogi *els_plogi; -	struct zfcp_port *port; -	unsigned long flags; - -	els_plogi = (struct fsf_plogi *) status_buffer->payload; -	read_lock_irqsave(&zfcp_data.config_lock, flags); -	list_for_each_entry(port, &adapter->port_list_head, list) { -		if (port->wwpn == (*(wwn_t *) &els_plogi->serv_param.wwpn)) -			break; -	} -	read_unlock_irqrestore(&zfcp_data.config_lock, flags); - -	if (!port || (port->wwpn != (*(wwn_t *) &els_plogi->serv_param.wwpn))) { -		ZFCP_LOG_DEBUG("ignored incoming PLOGI for nonexisting port " -			       "with d_id 0x%06x on adapter %s\n", -			       status_buffer->d_id, -			       zfcp_get_busid_by_adapter(adapter)); -	} else { -		zfcp_erp_port_forced_reopen(port, 0, 83, fsf_req); -	} -} - -static void zfcp_fsf_incoming_els_logo(struct zfcp_fsf_req *fsf_req) -{ -	struct fsf_status_read_buffer *status_buffer = (void*)fsf_req->data; -	struct zfcp_adapter *adapter = fsf_req->adapter; -	struct fcp_logo *els_logo = (struct fcp_logo *) status_buffer->payload; -	struct zfcp_port *port; -	unsigned long flags; - -	read_lock_irqsave(&zfcp_data.config_lock, flags); -	list_for_each_entry(port, &adapter->port_list_head, list) { -		if (port->wwpn == els_logo->nport_wwpn) -			break; -	} -	read_unlock_irqrestore(&zfcp_data.config_lock, flags); - -	if (!port || (port->wwpn != els_logo->nport_wwpn)) { -		ZFCP_LOG_DEBUG("ignored incoming LOGO for nonexisting port " -			       "with d_id 0x%06x on adapter %s\n", -			       status_buffer->d_id, -			       zfcp_get_busid_by_adapter(adapter)); -	} else { -		zfcp_erp_port_forced_reopen(port, 0, 84, fsf_req); -	} -} - -static void -zfcp_fsf_incoming_els_unknown(struct zfcp_adapter *adapter, -			      struct fsf_status_read_buffer *status_buffer) -{ -	ZFCP_LOG_NORMAL("warning: unknown incoming ELS 0x%08x " -			"for adapter %s\n", *(u32 *) (status_buffer->payload), -			zfcp_get_busid_by_adapter(adapter)); - -} - -void -zfcp_fsf_incoming_els(struct zfcp_fsf_req *fsf_req) -{ -	struct fsf_status_read_buffer *status_buffer; -	u32 els_type; -	struct zfcp_adapter *adapter; - -	status_buffer = (struct fsf_status_read_buffer *) fsf_req->data; -	els_type = *(u32 *) (status_buffer->payload); -	adapter = fsf_req->adapter; - -	zfcp_san_dbf_event_incoming_els(fsf_req); -	if (els_type == LS_PLOGI) -		zfcp_fsf_incoming_els_plogi(fsf_req); -	else if (els_type == LS_LOGO) -		zfcp_fsf_incoming_els_logo(fsf_req); -	else if ((els_type & 0xffff0000) == LS_RSCN) -		/* we are only concerned with the command, not the length */ -		zfcp_fsf_incoming_els_rscn(fsf_req); +	if (atomic_read(&port->status) & ZFCP_STATUS_PORT_WKA) +		sysfs_remove_group(&port->sysfs_device.kobj, +				   &zfcp_sysfs_ns_port_attrs);  	else -		zfcp_fsf_incoming_els_unknown(adapter, status_buffer); -} - - -/** - * zfcp_gid_pn_buffers_alloc - allocate buffers for GID_PN nameserver request - * @gid_pn: pointer to return pointer to struct zfcp_gid_pn_data - * @pool: pointer to mempool_t if non-null memory pool is used for allocation - */ -static int -zfcp_gid_pn_buffers_alloc(struct zfcp_gid_pn_data **gid_pn, mempool_t *pool) -{ -	struct zfcp_gid_pn_data *data; - -	if (pool != NULL) { -		data = mempool_alloc(pool, GFP_ATOMIC); -		if (likely(data != NULL)) { -			data->ct.pool = pool; -		} -	} else { -		data = kmem_cache_alloc(zfcp_data.gid_pn_cache, GFP_ATOMIC); -	} - -        if (NULL == data) -                return -ENOMEM; - -	memset(data, 0, sizeof(*data)); -	sg_init_table(&data->req , 1); -	sg_init_table(&data->resp , 1); -        data->ct.req = &data->req; -        data->ct.resp = &data->resp; -	data->ct.req_count = data->ct.resp_count = 1; -	zfcp_address_to_sg(&data->ct_iu_req, &data->req, sizeof(struct ct_iu_gid_pn_req)); -        zfcp_address_to_sg(&data->ct_iu_resp, &data->resp, sizeof(struct ct_iu_gid_pn_resp)); - -	*gid_pn = data; -	return 0; -} - -/** - * zfcp_gid_pn_buffers_free - free buffers for GID_PN nameserver request - * @gid_pn: pointer to struct zfcp_gid_pn_data which has to be freed - */ -static void zfcp_gid_pn_buffers_free(struct zfcp_gid_pn_data *gid_pn) -{ -	if (gid_pn->ct.pool) -		mempool_free(gid_pn, gid_pn->ct.pool); -	else -		kmem_cache_free(zfcp_data.gid_pn_cache, gid_pn); -} - -/** - * zfcp_ns_gid_pn_request - initiate GID_PN nameserver request - * @erp_action: pointer to zfcp_erp_action where GID_PN request is needed - */ -int -zfcp_ns_gid_pn_request(struct zfcp_erp_action *erp_action) -{ -	int ret; -        struct ct_iu_gid_pn_req *ct_iu_req; -        struct zfcp_gid_pn_data *gid_pn; -        struct zfcp_adapter *adapter = erp_action->adapter; - -	ret = zfcp_gid_pn_buffers_alloc(&gid_pn, adapter->pool.data_gid_pn); -	if (ret < 0) { -		ZFCP_LOG_INFO("error: buffer allocation for gid_pn nameserver " -			      "request failed for adapter %s\n", -			      zfcp_get_busid_by_adapter(adapter)); -		goto out; -	} - -	/* setup nameserver request */ -        ct_iu_req = zfcp_sg_to_address(gid_pn->ct.req); -        ct_iu_req->header.revision = ZFCP_CT_REVISION; -        ct_iu_req->header.gs_type = ZFCP_CT_DIRECTORY_SERVICE; -        ct_iu_req->header.gs_subtype = ZFCP_CT_NAME_SERVER; -        ct_iu_req->header.options = ZFCP_CT_SYNCHRONOUS; -        ct_iu_req->header.cmd_rsp_code = ZFCP_CT_GID_PN; -        ct_iu_req->header.max_res_size = ZFCP_CT_MAX_SIZE; -	ct_iu_req->wwpn = erp_action->port->wwpn; - -        /* setup parameters for send generic command */ -        gid_pn->ct.port = adapter->nameserver_port; -	gid_pn->ct.handler = zfcp_ns_gid_pn_handler; -	gid_pn->ct.handler_data = (unsigned long) gid_pn; -        gid_pn->ct.timeout = ZFCP_NS_GID_PN_TIMEOUT; -	gid_pn->port = erp_action->port; - -	ret = zfcp_fsf_send_ct(&gid_pn->ct, adapter->pool.fsf_req_erp, -			       erp_action); -	if (ret) { -		ZFCP_LOG_INFO("error: initiation of gid_pn nameserver request " -                              "failed for adapter %s\n", -			      zfcp_get_busid_by_adapter(adapter)); - -                zfcp_gid_pn_buffers_free(gid_pn); -	} - - out: -	return ret; -} - -/** - * zfcp_ns_gid_pn_handler - handler for GID_PN nameserver request - * @data: unsigned long, contains pointer to struct zfcp_gid_pn_data - */ -static void zfcp_ns_gid_pn_handler(unsigned long data) -{ -	struct zfcp_port *port; -        struct zfcp_send_ct *ct; -	struct ct_iu_gid_pn_req *ct_iu_req; -	struct ct_iu_gid_pn_resp *ct_iu_resp; -        struct zfcp_gid_pn_data *gid_pn; - - -	gid_pn = (struct zfcp_gid_pn_data *) data; -	port = gid_pn->port; -        ct = &gid_pn->ct; -	ct_iu_req = zfcp_sg_to_address(ct->req); -	ct_iu_resp = zfcp_sg_to_address(ct->resp); - -	if (ct->status != 0) -		goto failed; - -	if (zfcp_check_ct_response(&ct_iu_resp->header)) { -		/* FIXME: do we need some specific erp entry points */ -		atomic_set_mask(ZFCP_STATUS_PORT_INVALID_WWPN, &port->status); -		goto failed; -	} -	/* paranoia */ -	if (ct_iu_req->wwpn != port->wwpn) { -		ZFCP_LOG_NORMAL("bug: wwpn 0x%016Lx returned by nameserver " -				"lookup does not match expected wwpn 0x%016Lx " -				"for adapter %s\n", ct_iu_req->wwpn, port->wwpn, -				zfcp_get_busid_by_port(port)); -		goto mismatch; -	} - -	/* looks like a valid d_id */ -        port->d_id = ct_iu_resp->d_id & ZFCP_DID_MASK; -	atomic_set_mask(ZFCP_STATUS_PORT_DID_DID, &port->status); -	ZFCP_LOG_DEBUG("adapter %s:  wwpn=0x%016Lx ---> d_id=0x%06x\n", -		       zfcp_get_busid_by_port(port), port->wwpn, port->d_id); -	goto out; - - mismatch: -	ZFCP_LOG_DEBUG("CT IUs do not match:\n"); -	ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, (char *) ct_iu_req, -		      sizeof(struct ct_iu_gid_pn_req)); -	ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, (char *) ct_iu_resp, -		      sizeof(struct ct_iu_gid_pn_resp)); - - failed: -	ZFCP_LOG_NORMAL("warning: failed gid_pn nameserver request for wwpn " -			"0x%016Lx for adapter %s\n", -			port->wwpn, zfcp_get_busid_by_port(port)); - out: -        zfcp_gid_pn_buffers_free(gid_pn); -	return; +		sysfs_remove_group(&port->sysfs_device.kobj, +				   &zfcp_sysfs_port_attrs); +	device_unregister(&port->sysfs_device);  } -/* reject CT_IU reason codes acc. to FC-GS-4 */ -static const struct zfcp_rc_entry zfcp_ct_rc[] = { -	{0x01, "invalid command code"}, -	{0x02, "invalid version level"}, -	{0x03, "logical error"}, -	{0x04, "invalid CT_IU size"}, -	{0x05, "logical busy"}, -	{0x07, "protocol error"}, -	{0x09, "unable to perform command request"}, -	{0x0b, "command not supported"}, -	{0x0d, "server not available"}, -	{0x0e, "session could not be established"}, -	{0xff, "vendor specific error"}, -	{0, NULL}, -}; - -/* LS_RJT reason codes acc. to FC-FS */ -static const struct zfcp_rc_entry zfcp_ls_rjt_rc[] = { -	{0x01, "invalid LS_Command code"}, -	{0x03, "logical error"}, -	{0x05, "logical busy"}, -	{0x07, "protocol error"}, -	{0x09, "unable to perform command request"}, -	{0x0b, "command not supported"}, -	{0x0e, "command already in progress"}, -	{0xff, "vendor specific error"}, -	{0, NULL}, -}; - -/* reject reason codes according to FC-PH/FC-FS */ -static const struct zfcp_rc_entry zfcp_p_rjt_rc[] = { -	{0x01, "invalid D_ID"}, -	{0x02, "invalid S_ID"}, -	{0x03, "Nx_Port not available, temporary"}, -	{0x04, "Nx_Port not available, permament"}, -	{0x05, "class not supported"}, -	{0x06, "delimiter usage error"}, -	{0x07, "TYPE not supported"}, -	{0x08, "invalid Link_Control"}, -	{0x09, "invalid R_CTL field"}, -	{0x0a, "invalid F_CTL field"}, -	{0x0b, "invalid OX_ID"}, -	{0x0c, "invalid RX_ID"}, -	{0x0d, "invalid SEQ_ID"}, -	{0x0e, "invalid DF_CTL"}, -	{0x0f, "invalid SEQ_CNT"}, -	{0x10, "invalid parameter field"}, -	{0x11, "exchange error"}, -	{0x12, "protocol error"}, -	{0x13, "incorrect length"}, -	{0x14, "unsupported ACK"}, -	{0x15, "class of service not supported by entity at FFFFFE"}, -	{0x16, "login required"}, -	{0x17, "excessive sequences attempted"}, -	{0x18, "unable to establish exchange"}, -	{0x1a, "fabric path not available"}, -	{0x1b, "invalid VC_ID (class 4)"}, -	{0x1c, "invalid CS_CTL field"}, -	{0x1d, "insufficient resources for VC (class 4)"}, -	{0x1f, "invalid class of service"}, -	{0x20, "preemption request rejected"}, -	{0x21, "preemption not enabled"}, -	{0x22, "multicast error"}, -	{0x23, "multicast error terminate"}, -	{0x24, "process login required"}, -	{0xff, "vendor specific reject"}, -	{0, NULL}, -}; -  /** - * zfcp_rc_description - return description for given reaon code - * @code: reason code - * @rc_table: table of reason codes and descriptions + * zfcp_sg_free_table - free memory used by scatterlists + * @sg: pointer to scatterlist + * @count: number of scatterlist which are to be free'ed + * the scatterlist are expected to reference pages always   */ -static const char * -zfcp_rc_description(u8 code, const struct zfcp_rc_entry *rc_table) +void zfcp_sg_free_table(struct scatterlist *sg, int count)  { -	const char *descr = "unknown reason code"; +	int i; -	do { -		if (code == rc_table->code) { -			descr = rc_table->description; +	for (i = 0; i < count; i++, sg++) +		if (sg) +			free_page((unsigned long) sg_virt(sg)); +		else  			break; -		} -		rc_table++; -	} while (rc_table->code && rc_table->description); - -	return descr;  }  /** - * zfcp_check_ct_response - evaluate reason code for CT_IU - * @rjt: response payload to an CT_IU request - * Return: 0 for accept CT_IU, 1 for reject CT_IU or invlid response code + * zfcp_sg_setup_table - init scatterlist and allocate, assign buffers + * @sg: pointer to struct scatterlist + * @count: number of scatterlists which should be assigned with buffers + * of size page + * + * Returns: 0 on success, -ENOMEM otherwise   */ -int -zfcp_check_ct_response(struct ct_hdr *rjt) +int zfcp_sg_setup_table(struct scatterlist *sg, int count)  { -	if (rjt->cmd_rsp_code == ZFCP_CT_ACCEPT) -		return 0; +	void *addr; +	int i; -	if (rjt->cmd_rsp_code != ZFCP_CT_REJECT) { -		ZFCP_LOG_NORMAL("error: invalid Generic Service command/" -				"response code (0x%04hx)\n", -				rjt->cmd_rsp_code); -		return 1; +	sg_init_table(sg, count); +	for (i = 0; i < count; i++, sg++) { +		addr = (void *) get_zeroed_page(GFP_KERNEL); +		if (!addr) { +			zfcp_sg_free_table(sg, i); +			return -ENOMEM; +		} +		sg_set_buf(sg, addr, PAGE_SIZE);  	} - -	ZFCP_LOG_INFO("Generic Service command rejected\n"); -	ZFCP_LOG_INFO("%s (0x%02x, 0x%02x, 0x%02x)\n", -		      zfcp_rc_description(rjt->reason_code, zfcp_ct_rc), -		      (u32) rjt->reason_code, (u32) rjt->reason_code_expl, -		      (u32) rjt->vendor_unique); - -	return 1; -} - -/** - * zfcp_print_els_rjt - print reject parameter and description for ELS reject - * @rjt_par: reject parameter acc. to FC-PH/FC-FS - * @rc_table: table of reason codes and descriptions - */ -static void -zfcp_print_els_rjt(struct zfcp_ls_rjt_par *rjt_par, -		   const struct zfcp_rc_entry *rc_table) -{ -	ZFCP_LOG_INFO("%s (%02x %02x %02x %02x)\n", -		      zfcp_rc_description(rjt_par->reason_code, rc_table), -		      (u32) rjt_par->action, (u32) rjt_par->reason_code, -		      (u32) rjt_par->reason_expl, (u32) rjt_par->vendor_unique); -} - -/** - * zfcp_fsf_handle_els_rjt - evaluate status qualifier/reason code on ELS reject - * @sq: status qualifier word - * @rjt_par: reject parameter as described in FC-PH and FC-FS - * Return: -EROMTEIO for LS_RJT, -EREMCHG for invalid D_ID, -EIO else - */ -int -zfcp_handle_els_rjt(u32 sq, struct zfcp_ls_rjt_par *rjt_par) -{ -	int ret = -EIO; - -	if (sq == FSF_IOSTAT_NPORT_RJT) { -		ZFCP_LOG_INFO("ELS rejected (P_RJT)\n"); -		zfcp_print_els_rjt(rjt_par, zfcp_p_rjt_rc); -		/* invalid d_id */ -		if (rjt_par->reason_code == 0x01) -			ret = -EREMCHG; -	} else if (sq == FSF_IOSTAT_FABRIC_RJT) { -		ZFCP_LOG_INFO("ELS rejected (F_RJT)\n"); -		zfcp_print_els_rjt(rjt_par, zfcp_p_rjt_rc); -		/* invalid d_id */ -		if (rjt_par->reason_code == 0x01) -			ret = -EREMCHG; -	} else if (sq == FSF_IOSTAT_LS_RJT) { -		ZFCP_LOG_INFO("ELS rejected (LS_RJT)\n"); -		zfcp_print_els_rjt(rjt_par, zfcp_ls_rjt_rc); -		ret = -EREMOTEIO; -	} else -		ZFCP_LOG_INFO("unexpected SQ: 0x%02x\n", sq); - -	return ret; -} - -/** - * zfcp_plogi_evaluate - evaluate PLOGI playload and copy important fields - * into zfcp_port structure - * @port: zfcp_port structure - * @plogi: plogi payload - */ -void -zfcp_plogi_evaluate(struct zfcp_port *port, struct fsf_plogi *plogi) -{ -	port->maxframe_size = plogi->serv_param.common_serv_param[7] | -		((plogi->serv_param.common_serv_param[6] & 0x0F) << 8); -	if (plogi->serv_param.class1_serv_param[0] & 0x80) -		port->supported_classes |= FC_COS_CLASS1; -	if (plogi->serv_param.class2_serv_param[0] & 0x80) -		port->supported_classes |= FC_COS_CLASS2; -	if (plogi->serv_param.class3_serv_param[0] & 0x80) -		port->supported_classes |= FC_COS_CLASS3; -	if (plogi->serv_param.class4_serv_param[0] & 0x80) -		port->supported_classes |= FC_COS_CLASS4; +	return 0;  } - -#undef ZFCP_LOG_AREA  |