diff options
Diffstat (limited to 'drivers/s390/scsi')
| -rw-r--r-- | drivers/s390/scsi/Makefile | 2 | ||||
| -rw-r--r-- | drivers/s390/scsi/zfcp_aux.c | 131 | ||||
| -rw-r--r-- | drivers/s390/scsi/zfcp_ccw.c | 112 | ||||
| -rw-r--r-- | drivers/s390/scsi/zfcp_cfdc.c | 445 | ||||
| -rw-r--r-- | drivers/s390/scsi/zfcp_dbf.c | 1211 | ||||
| -rw-r--r-- | drivers/s390/scsi/zfcp_dbf.h | 498 | ||||
| -rw-r--r-- | drivers/s390/scsi/zfcp_def.h | 28 | ||||
| -rw-r--r-- | drivers/s390/scsi/zfcp_erp.c | 192 | ||||
| -rw-r--r-- | drivers/s390/scsi/zfcp_ext.h | 86 | ||||
| -rw-r--r-- | drivers/s390/scsi/zfcp_fc.c | 380 | ||||
| -rw-r--r-- | drivers/s390/scsi/zfcp_fc.h | 126 | ||||
| -rw-r--r-- | drivers/s390/scsi/zfcp_fsf.c | 455 | ||||
| -rw-r--r-- | drivers/s390/scsi/zfcp_fsf.h | 28 | ||||
| -rw-r--r-- | drivers/s390/scsi/zfcp_qdio.c | 100 | ||||
| -rw-r--r-- | drivers/s390/scsi/zfcp_qdio.h | 77 | ||||
| -rw-r--r-- | drivers/s390/scsi/zfcp_reqlist.h | 2 | ||||
| -rw-r--r-- | drivers/s390/scsi/zfcp_scsi.c | 143 | ||||
| -rw-r--r-- | drivers/s390/scsi/zfcp_sysfs.c | 78 | ||||
| -rw-r--r-- | drivers/s390/scsi/zfcp_unit.c | 41 | 
19 files changed, 1676 insertions, 2459 deletions
diff --git a/drivers/s390/scsi/Makefile b/drivers/s390/scsi/Makefile index c454ffebb63..9259039e886 100644 --- a/drivers/s390/scsi/Makefile +++ b/drivers/s390/scsi/Makefile @@ -2,7 +2,7 @@  # Makefile for the S/390 specific device drivers  # -zfcp-objs := zfcp_aux.o zfcp_ccw.o zfcp_cfdc.o zfcp_dbf.o zfcp_erp.o \ +zfcp-objs := zfcp_aux.o zfcp_ccw.o zfcp_dbf.o zfcp_erp.o \  	     zfcp_fc.o zfcp_fsf.o zfcp_qdio.o zfcp_scsi.o zfcp_sysfs.o \  	     zfcp_unit.o diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 044fb22718d..8004b071a9f 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -3,7 +3,7 @@   *   * Module interface and handling of zfcp data structures.   * - * Copyright IBM Corporation 2002, 2010 + * Copyright IBM Corp. 2002, 2013   */  /* @@ -23,6 +23,7 @@   *            Christof Schmitt   *            Martin Petermann   *            Sven Schuetz + *            Steffen Maier   */  #define KMSG_COMPONENT "zfcp" @@ -31,6 +32,7 @@  #include <linux/miscdevice.h>  #include <linux/seq_file.h>  #include <linux/slab.h> +#include <linux/module.h>  #include "zfcp_ext.h"  #include "zfcp_fc.h"  #include "zfcp_reqlist.h" @@ -45,8 +47,8 @@ static char *init_device;  module_param_named(device, init_device, charp, 0400);  MODULE_PARM_DESC(device, "specify initial device"); -static struct kmem_cache *zfcp_cache_hw_align(const char *name, -					      unsigned long size) +static struct kmem_cache * __init zfcp_cache_hw_align(const char *name, +						      unsigned long size)  {  	return kmem_cache_create(name, size, roundup_pow_of_two(size), 0, NULL);  } @@ -102,11 +104,11 @@ static void __init zfcp_init_device_setup(char *devstr)  	strncpy(busid, token, ZFCP_BUS_ID_SIZE);  	token = strsep(&str, ","); -	if (!token || strict_strtoull(token, 0, (unsigned long long *) &wwpn)) +	if (!token || kstrtoull(token, 0, (unsigned long long *) &wwpn))  		goto err_out;  	token = strsep(&str, ","); -	if (!token || strict_strtoull(token, 0, (unsigned long long *) &lun)) +	if (!token || kstrtoull(token, 0, (unsigned long long *) &lun))  		goto err_out;  	kfree(str_saved); @@ -122,45 +124,23 @@ static int __init zfcp_module_init(void)  {  	int retval = -ENOMEM; -	zfcp_data.gpn_ft_cache = zfcp_cache_hw_align("zfcp_gpn", -					sizeof(struct zfcp_fc_gpn_ft_req)); -	if (!zfcp_data.gpn_ft_cache) -		goto out; - -	zfcp_data.qtcb_cache = zfcp_cache_hw_align("zfcp_qtcb", -					sizeof(struct fsf_qtcb)); -	if (!zfcp_data.qtcb_cache) +	zfcp_fsf_qtcb_cache = zfcp_cache_hw_align("zfcp_fsf_qtcb", +						  sizeof(struct fsf_qtcb)); +	if (!zfcp_fsf_qtcb_cache)  		goto out_qtcb_cache; -	zfcp_data.sr_buffer_cache = zfcp_cache_hw_align("zfcp_sr", -					sizeof(struct fsf_status_read_buffer)); -	if (!zfcp_data.sr_buffer_cache) -		goto out_sr_cache; - -	zfcp_data.gid_pn_cache = zfcp_cache_hw_align("zfcp_gid", -					sizeof(struct zfcp_fc_gid_pn)); -	if (!zfcp_data.gid_pn_cache) -		goto out_gid_cache; +	zfcp_fc_req_cache = zfcp_cache_hw_align("zfcp_fc_req", +						sizeof(struct zfcp_fc_req)); +	if (!zfcp_fc_req_cache) +		goto out_fc_cache; -	zfcp_data.adisc_cache = zfcp_cache_hw_align("zfcp_adisc", -					sizeof(struct zfcp_fc_els_adisc)); -	if (!zfcp_data.adisc_cache) -		goto out_adisc_cache; - -	zfcp_data.scsi_transport_template = +	zfcp_scsi_transport_template =  		fc_attach_transport(&zfcp_transport_functions); -	if (!zfcp_data.scsi_transport_template) +	if (!zfcp_scsi_transport_template)  		goto out_transport; -	scsi_transport_reserve_device(zfcp_data.scsi_transport_template, +	scsi_transport_reserve_device(zfcp_scsi_transport_template,  				      sizeof(struct zfcp_scsi_dev)); - -	retval = misc_register(&zfcp_cfdc_misc); -	if (retval) { -		pr_err("Registering the misc device zfcp_cfdc failed\n"); -		goto out_misc; -	} -  	retval = ccw_driver_register(&zfcp_ccw_driver);  	if (retval) {  		pr_err("The zfcp device driver could not register with " @@ -173,20 +153,12 @@ static int __init zfcp_module_init(void)  	return 0;  out_ccw_register: -	misc_deregister(&zfcp_cfdc_misc); -out_misc: -	fc_release_transport(zfcp_data.scsi_transport_template); +	fc_release_transport(zfcp_scsi_transport_template);  out_transport: -	kmem_cache_destroy(zfcp_data.adisc_cache); -out_adisc_cache: -	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.qtcb_cache); +	kmem_cache_destroy(zfcp_fc_req_cache); +out_fc_cache: +	kmem_cache_destroy(zfcp_fsf_qtcb_cache);  out_qtcb_cache: -	kmem_cache_destroy(zfcp_data.gpn_ft_cache); -out:  	return retval;  } @@ -195,13 +167,9 @@ module_init(zfcp_module_init);  static void __exit zfcp_module_exit(void)  {  	ccw_driver_unregister(&zfcp_ccw_driver); -	misc_deregister(&zfcp_cfdc_misc); -	fc_release_transport(zfcp_data.scsi_transport_template); -	kmem_cache_destroy(zfcp_data.adisc_cache); -	kmem_cache_destroy(zfcp_data.gid_pn_cache); -	kmem_cache_destroy(zfcp_data.sr_buffer_cache); -	kmem_cache_destroy(zfcp_data.qtcb_cache); -	kmem_cache_destroy(zfcp_data.gpn_ft_cache); +	fc_release_transport(zfcp_scsi_transport_template); +	kmem_cache_destroy(zfcp_fc_req_cache); +	kmem_cache_destroy(zfcp_fsf_qtcb_cache);  }  module_exit(zfcp_module_exit); @@ -260,18 +228,18 @@ static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter)  		return -ENOMEM;  	adapter->pool.qtcb_pool = -		mempool_create_slab_pool(4, zfcp_data.qtcb_cache); +		mempool_create_slab_pool(4, zfcp_fsf_qtcb_cache);  	if (!adapter->pool.qtcb_pool)  		return -ENOMEM; -	adapter->pool.status_read_data = -		mempool_create_slab_pool(FSF_STATUS_READS_RECOM, -					 zfcp_data.sr_buffer_cache); -	if (!adapter->pool.status_read_data) +	BUILD_BUG_ON(sizeof(struct fsf_status_read_buffer) > PAGE_SIZE); +	adapter->pool.sr_data = +		mempool_create_page_pool(FSF_STATUS_READS_RECOM, 0); +	if (!adapter->pool.sr_data)  		return -ENOMEM;  	adapter->pool.gid_pn = -		mempool_create_slab_pool(1, zfcp_data.gid_pn_cache); +		mempool_create_slab_pool(1, zfcp_fc_req_cache);  	if (!adapter->pool.gid_pn)  		return -ENOMEM; @@ -290,8 +258,8 @@ static void zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter)  		mempool_destroy(adapter->pool.qtcb_pool);  	if (adapter->pool.status_read_req)  		mempool_destroy(adapter->pool.status_read_req); -	if (adapter->pool.status_read_data) -		mempool_destroy(adapter->pool.status_read_data); +	if (adapter->pool.sr_data) +		mempool_destroy(adapter->pool.sr_data);  	if (adapter->pool.gid_pn)  		mempool_destroy(adapter->pool.gid_pn);  } @@ -311,8 +279,7 @@ int zfcp_status_read_refill(struct zfcp_adapter *adapter)  		if (zfcp_fsf_status_read(adapter->qdio)) {  			if (atomic_read(&adapter->stat_miss) >=  			    adapter->stat_read_buf_num) { -				zfcp_erp_adapter_reopen(adapter, 0, "axsref1", -							NULL); +				zfcp_erp_adapter_reopen(adapter, 0, "axsref1");  				return 1;  			}  			break; @@ -387,6 +354,7 @@ struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *ccw_device)  	INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler);  	INIT_WORK(&adapter->scan_work, zfcp_fc_scan_ports); +	INIT_WORK(&adapter->ns_up_work, zfcp_fc_sym_name_update);  	if (zfcp_qdio_setup(adapter))  		goto failed; @@ -438,7 +406,9 @@ struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *ccw_device)  	adapter->dma_parms.max_segment_size = ZFCP_QDIO_SBALE_LEN;  	adapter->ccw_device->dev.dma_parms = &adapter->dma_parms; -	if (!zfcp_adapter_scsi_register(adapter)) +	adapter->stat_read_buf_num = FSF_STATUS_READS_RECOM; + +	if (!zfcp_scsi_adapter_register(adapter))  		return adapter;  failed: @@ -452,14 +422,15 @@ void zfcp_adapter_unregister(struct zfcp_adapter *adapter)  	cancel_work_sync(&adapter->scan_work);  	cancel_work_sync(&adapter->stat_work); +	cancel_work_sync(&adapter->ns_up_work);  	zfcp_destroy_adapter_work_queue(adapter);  	zfcp_fc_wka_ports_force_offline(adapter->gs); -	zfcp_adapter_scsi_unregister(adapter); +	zfcp_scsi_adapter_unregister(adapter);  	sysfs_remove_group(&cdev->dev.kobj, &zfcp_sysfs_adapter_attrs);  	zfcp_erp_thread_kill(adapter); -	zfcp_dbf_adapter_unregister(adapter->dbf); +	zfcp_dbf_adapter_unregister(adapter);  	zfcp_qdio_destroy(adapter->qdio);  	zfcp_ccw_adapter_put(adapter); /* final put to release */ @@ -486,20 +457,6 @@ void zfcp_adapter_release(struct kref *ref)  	put_device(&cdev->dev);  } -/** - * zfcp_device_unregister - remove port, unit from system - * @dev: reference to device which is to be removed - * @grp: related reference to attribute group - * - * Helper function to unregister port, unit from system - */ -void zfcp_device_unregister(struct device *dev, -			    const struct attribute_group *grp) -{ -	sysfs_remove_group(&dev->kobj, grp); -	device_unregister(dev); -} -  static void zfcp_port_release(struct device *dev)  {  	struct zfcp_port *port = container_of(dev, struct zfcp_port, dev); @@ -541,6 +498,7 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,  	rwlock_init(&port->unit_list_lock);  	INIT_LIST_HEAD(&port->unit_list); +	atomic_set(&port->units, 0);  	INIT_WORK(&port->gid_pn_work, zfcp_fc_port_did_lookup);  	INIT_WORK(&port->test_link_work, zfcp_fc_link_test_work); @@ -551,6 +509,7 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,  	port->wwpn = wwpn;  	port->rport_task = RPORT_NONE;  	port->dev.parent = &adapter->ccw_device->dev; +	port->dev.groups = zfcp_port_attr_groups;  	port->dev.release = zfcp_port_release;  	if (dev_set_name(&port->dev, "0x%016llx", (unsigned long long)wwpn)) { @@ -564,10 +523,6 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,  		goto err_out;  	} -	if (sysfs_create_group(&port->dev.kobj, -			       &zfcp_sysfs_port_attrs)) -		goto err_out_put; -  	write_lock_irq(&adapter->port_list_lock);  	list_add_tail(&port->list, &adapter->port_list);  	write_unlock_irq(&adapter->port_list_lock); @@ -576,8 +531,6 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,  	return port; -err_out_put: -	device_unregister(&port->dev);  err_out:  	zfcp_ccw_adapter_put(adapter);  	return ERR_PTR(retval); diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index 0833c2b51e3..f9879d400d0 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c @@ -3,12 +3,13 @@   *   * Registration and callback for the s390 common I/O layer.   * - * Copyright IBM Corporation 2002, 2010 + * Copyright IBM Corp. 2002, 2010   */  #define KMSG_COMPONENT "zfcp"  #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +#include <linux/module.h>  #include "zfcp_ext.h"  #include "zfcp_reqlist.h" @@ -38,19 +39,25 @@ void zfcp_ccw_adapter_put(struct zfcp_adapter *adapter)  	spin_unlock_irqrestore(&zfcp_ccw_adapter_ref_lock, flags);  } -static int zfcp_ccw_activate(struct ccw_device *cdev) - +/** + * zfcp_ccw_activate - activate adapter and wait for it to finish + * @cdev: pointer to belonging ccw device + * @clear: Status flags to clear. + * @tag: s390dbf trace record tag + */ +static int zfcp_ccw_activate(struct ccw_device *cdev, int clear, char *tag)  {  	struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);  	if (!adapter)  		return 0; +	zfcp_erp_clear_adapter_status(adapter, clear);  	zfcp_erp_set_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING);  	zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, -				"ccresu2", NULL); +				tag);  	zfcp_erp_wait(adapter); -	flush_work(&adapter->scan_work); +	flush_work(&adapter->scan_work); /* ok to call even if nothing queued */  	zfcp_ccw_adapter_put(adapter); @@ -65,15 +72,6 @@ static struct ccw_device_id zfcp_ccw_device_id[] = {  MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id);  /** - * zfcp_ccw_priv_sch - check if subchannel is privileged - * @adapter: Adapter/Subchannel to check - */ -int zfcp_ccw_priv_sch(struct zfcp_adapter *adapter) -{ -	return adapter->ccw_device->id.dev_model == ZFCP_MODEL_PRIV; -} - -/**   * zfcp_ccw_probe - probe function of zfcp driver   * @cdev: pointer to belonging ccw device   * @@ -122,10 +120,10 @@ static void zfcp_ccw_remove(struct ccw_device *cdev)  	zfcp_ccw_adapter_put(adapter); /* put from zfcp_ccw_adapter_by_cdev */  	list_for_each_entry_safe(unit, u, &unit_remove_lh, list) -		zfcp_device_unregister(&unit->dev, &zfcp_sysfs_unit_attrs); +		device_unregister(&unit->dev);  	list_for_each_entry_safe(port, p, &port_remove_lh, list) -		zfcp_device_unregister(&port->dev, &zfcp_sysfs_port_attrs); +		device_unregister(&port->dev);  	zfcp_adapter_unregister(adapter);  } @@ -163,26 +161,34 @@ static int zfcp_ccw_set_online(struct ccw_device *cdev)  	BUG_ON(!zfcp_reqlist_isempty(adapter->req_list));  	adapter->req_no = 0; -	zfcp_ccw_activate(cdev); +	zfcp_ccw_activate(cdev, 0, "ccsonl1"); +	/* scan for remote ports +	   either at the end of any successful adapter recovery +	   or only after the adapter recovery for setting a device online */ +	zfcp_fc_inverse_conditional_port_scan(adapter); +	flush_work(&adapter->scan_work); /* ok to call even if nothing queued */  	zfcp_ccw_adapter_put(adapter);  	return 0;  }  /** - * zfcp_ccw_set_offline - set_offline function of zfcp driver + * zfcp_ccw_offline_sync - shut down adapter and wait for it to finish   * @cdev: pointer to belonging ccw device + * @set: Status flags to set. + * @tag: s390dbf trace record tag   *   * This function gets called by the common i/o layer and sets an adapter   * into state offline.   */ -static int zfcp_ccw_set_offline(struct ccw_device *cdev) +static int zfcp_ccw_offline_sync(struct ccw_device *cdev, int set, char *tag)  {  	struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);  	if (!adapter)  		return 0; -	zfcp_erp_adapter_shutdown(adapter, 0, "ccsoff1", NULL); +	zfcp_erp_set_adapter_status(adapter, set); +	zfcp_erp_adapter_shutdown(adapter, 0, tag);  	zfcp_erp_wait(adapter);  	zfcp_ccw_adapter_put(adapter); @@ -190,6 +196,18 @@ static int zfcp_ccw_set_offline(struct ccw_device *cdev)  }  /** + * zfcp_ccw_set_offline - set_offline function of zfcp driver + * @cdev: pointer to belonging ccw device + * + * This function gets called by the common i/o layer and sets an adapter + * into state offline. + */ +static int zfcp_ccw_set_offline(struct ccw_device *cdev) +{ +	return zfcp_ccw_offline_sync(cdev, 0, "ccsoff1"); +} + +/**   * zfcp_ccw_notify - ccw notify function   * @cdev: pointer to belonging ccw device   * @event: indicates if adapter was detached or attached @@ -206,25 +224,35 @@ static int zfcp_ccw_notify(struct ccw_device *cdev, int event)  	switch (event) {  	case CIO_GONE: +		if (atomic_read(&adapter->status) & +		    ZFCP_STATUS_ADAPTER_SUSPENDED) { /* notification ignore */ +			zfcp_dbf_hba_basic("ccnigo1", adapter); +			break; +		}  		dev_warn(&cdev->dev, "The FCP device has been detached\n"); -		zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti1", NULL); +		zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti1");  		break;  	case CIO_NO_PATH:  		dev_warn(&cdev->dev,  			 "The CHPID for the FCP device is offline\n"); -		zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti2", NULL); +		zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti2");  		break;  	case CIO_OPER: +		if (atomic_read(&adapter->status) & +		    ZFCP_STATUS_ADAPTER_SUSPENDED) { /* notification ignore */ +			zfcp_dbf_hba_basic("ccniop1", adapter); +			break; +		}  		dev_info(&cdev->dev, "The FCP device is operational again\n");  		zfcp_erp_set_adapter_status(adapter,  					    ZFCP_STATUS_COMMON_RUNNING);  		zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, -					"ccnoti4", NULL); +					"ccnoti4");  		break;  	case CIO_BOXED:  		dev_warn(&cdev->dev, "The FCP device did not respond within "  				     "the specified time\n"); -		zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti5", NULL); +		zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti5");  		break;  	} @@ -243,16 +271,40 @@ static void zfcp_ccw_shutdown(struct ccw_device *cdev)  	if (!adapter)  		return; -	zfcp_erp_adapter_shutdown(adapter, 0, "ccshut1", NULL); +	zfcp_erp_adapter_shutdown(adapter, 0, "ccshut1");  	zfcp_erp_wait(adapter);  	zfcp_erp_thread_kill(adapter);  	zfcp_ccw_adapter_put(adapter);  } +static int zfcp_ccw_suspend(struct ccw_device *cdev) +{ +	zfcp_ccw_offline_sync(cdev, ZFCP_STATUS_ADAPTER_SUSPENDED, "ccsusp1"); +	return 0; +} + +static int zfcp_ccw_thaw(struct ccw_device *cdev) +{ +	/* trace records for thaw and final shutdown during suspend +	   can only be found in system dump until the end of suspend +	   but not after resume because it's based on the memory image +	   right after the very first suspend (freeze) callback */ +	zfcp_ccw_activate(cdev, 0, "ccthaw1"); +	return 0; +} + +static int zfcp_ccw_resume(struct ccw_device *cdev) +{ +	zfcp_ccw_activate(cdev, ZFCP_STATUS_ADAPTER_SUSPENDED, "ccresu1"); +	return 0; +} +  struct ccw_driver zfcp_ccw_driver = { -	.owner       = THIS_MODULE, -	.name        = "zfcp", +	.driver = { +		.owner	= THIS_MODULE, +		.name	= "zfcp", +	},  	.ids         = zfcp_ccw_device_id,  	.probe       = zfcp_ccw_probe,  	.remove      = zfcp_ccw_remove, @@ -260,7 +312,7 @@ struct ccw_driver zfcp_ccw_driver = {  	.set_offline = zfcp_ccw_set_offline,  	.notify      = zfcp_ccw_notify,  	.shutdown    = zfcp_ccw_shutdown, -	.freeze      = zfcp_ccw_set_offline, -	.thaw	     = zfcp_ccw_activate, -	.restore     = zfcp_ccw_activate, +	.freeze      = zfcp_ccw_suspend, +	.thaw	     = zfcp_ccw_thaw, +	.restore     = zfcp_ccw_resume,  }; diff --git a/drivers/s390/scsi/zfcp_cfdc.c b/drivers/s390/scsi/zfcp_cfdc.c deleted file mode 100644 index d692e229ecb..00000000000 --- a/drivers/s390/scsi/zfcp_cfdc.c +++ /dev/null @@ -1,445 +0,0 @@ -/* - * zfcp device driver - * - * Userspace interface for accessing the - * Access Control Lists / Control File Data Channel; - * handling of response code and states for ports and LUNs. - * - * Copyright IBM Corporation 2008, 2010 - */ - -#define KMSG_COMPONENT "zfcp" -#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt - -#include <linux/slab.h> -#include <linux/types.h> -#include <linux/miscdevice.h> -#include <asm/compat.h> -#include <asm/ccwdev.h> -#include "zfcp_def.h" -#include "zfcp_ext.h" -#include "zfcp_fsf.h" - -#define ZFCP_CFDC_CMND_DOWNLOAD_NORMAL		0x00010001 -#define ZFCP_CFDC_CMND_DOWNLOAD_FORCE		0x00010101 -#define ZFCP_CFDC_CMND_FULL_ACCESS		0x00000201 -#define ZFCP_CFDC_CMND_RESTRICTED_ACCESS	0x00000401 -#define ZFCP_CFDC_CMND_UPLOAD			0x00010002 - -#define ZFCP_CFDC_DOWNLOAD			0x00000001 -#define ZFCP_CFDC_UPLOAD			0x00000002 -#define ZFCP_CFDC_WITH_CONTROL_FILE		0x00010000 - -#define ZFCP_CFDC_IOC_MAGIC                     0xDD -#define ZFCP_CFDC_IOC \ -	_IOWR(ZFCP_CFDC_IOC_MAGIC, 0, struct zfcp_cfdc_data) - -/** - * struct zfcp_cfdc_data - data for ioctl cfdc interface - * @signature: request signature - * @devno: FCP adapter device number - * @command: command code - * @fsf_status: returns status of FSF command to userspace - * @fsf_status_qual: returned to userspace - * @payloads: access conflicts list - * @control_file: access control table - */ -struct zfcp_cfdc_data { -	u32 signature; -	u32 devno; -	u32 command; -	u32 fsf_status; -	u8  fsf_status_qual[FSF_STATUS_QUALIFIER_SIZE]; -	u8  payloads[256]; -	u8  control_file[0]; -}; - -static int zfcp_cfdc_copy_from_user(struct scatterlist *sg, -				    void __user *user_buffer) -{ -	unsigned int length; -	unsigned int size = ZFCP_CFDC_MAX_SIZE; - -	while (size) { -		length = min((unsigned int)size, sg->length); -		if (copy_from_user(sg_virt(sg++), user_buffer, length)) -			return -EFAULT; -		user_buffer += length; -		size -= length; -	} -	return 0; -} - -static int zfcp_cfdc_copy_to_user(void __user  *user_buffer, -				  struct scatterlist *sg) -{ -	unsigned int length; -	unsigned int size = ZFCP_CFDC_MAX_SIZE; - -	while (size) { -		length = min((unsigned int) size, sg->length); -		if (copy_to_user(user_buffer, sg_virt(sg++), length)) -			return -EFAULT; -		user_buffer += length; -		size -= length; -	} -	return 0; -} - -static struct zfcp_adapter *zfcp_cfdc_get_adapter(u32 devno) -{ -	char busid[9]; -	struct ccw_device *cdev; -	struct zfcp_adapter *adapter; - -	snprintf(busid, sizeof(busid), "0.0.%04x", devno); -	cdev = get_ccwdev_by_busid(&zfcp_ccw_driver, busid); -	if (!cdev) -		return NULL; - -	adapter = zfcp_ccw_adapter_by_cdev(cdev); - -	put_device(&cdev->dev); -	return adapter; -} - -static int zfcp_cfdc_set_fsf(struct zfcp_fsf_cfdc *fsf_cfdc, int command) -{ -	switch (command) { -	case ZFCP_CFDC_CMND_DOWNLOAD_NORMAL: -		fsf_cfdc->command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; -		fsf_cfdc->option = FSF_CFDC_OPTION_NORMAL_MODE; -		break; -	case ZFCP_CFDC_CMND_DOWNLOAD_FORCE: -		fsf_cfdc->command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; -		fsf_cfdc->option = FSF_CFDC_OPTION_FORCE; -		break; -	case ZFCP_CFDC_CMND_FULL_ACCESS: -		fsf_cfdc->command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; -		fsf_cfdc->option = FSF_CFDC_OPTION_FULL_ACCESS; -		break; -	case ZFCP_CFDC_CMND_RESTRICTED_ACCESS: -		fsf_cfdc->command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; -		fsf_cfdc->option = FSF_CFDC_OPTION_RESTRICTED_ACCESS; -		break; -	case ZFCP_CFDC_CMND_UPLOAD: -		fsf_cfdc->command = FSF_QTCB_UPLOAD_CONTROL_FILE; -		fsf_cfdc->option = 0; -		break; -	default: -		return -EINVAL; -	} - -	return 0; -} - -static int zfcp_cfdc_sg_setup(int command, struct scatterlist *sg, -			      u8 __user *control_file) -{ -	int retval; -	retval = zfcp_sg_setup_table(sg, ZFCP_CFDC_PAGES); -	if (retval) -		return retval; - -	sg[ZFCP_CFDC_PAGES - 1].length = ZFCP_CFDC_MAX_SIZE % PAGE_SIZE; - -	if (command & ZFCP_CFDC_WITH_CONTROL_FILE && -	    command & ZFCP_CFDC_DOWNLOAD) { -		retval = zfcp_cfdc_copy_from_user(sg, control_file); -		if (retval) { -			zfcp_sg_free_table(sg, ZFCP_CFDC_PAGES); -			return -EFAULT; -		} -	} - -	return 0; -} - -static void zfcp_cfdc_req_to_sense(struct zfcp_cfdc_data *data, -				   struct zfcp_fsf_req *req) -{ -	data->fsf_status = req->qtcb->header.fsf_status; -	memcpy(&data->fsf_status_qual, &req->qtcb->header.fsf_status_qual, -	       sizeof(union fsf_status_qual)); -	memcpy(&data->payloads, &req->qtcb->bottom.support.els, -	       sizeof(req->qtcb->bottom.support.els)); -} - -static long zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command, -				unsigned long arg) -{ -	struct zfcp_cfdc_data *data; -	struct zfcp_cfdc_data __user *data_user; -	struct zfcp_adapter *adapter; -	struct zfcp_fsf_req *req; -	struct zfcp_fsf_cfdc *fsf_cfdc; -	int retval; - -	if (command != ZFCP_CFDC_IOC) -		return -ENOTTY; - -	if (is_compat_task()) -		data_user = compat_ptr(arg); -	else -		data_user = (void __user *)arg; - -	if (!data_user) -		return -EINVAL; - -	fsf_cfdc = kmalloc(sizeof(struct zfcp_fsf_cfdc), GFP_KERNEL); -	if (!fsf_cfdc) -		return -ENOMEM; - -	data = memdup_user(data_user, sizeof(*data_user)); -	if (IS_ERR(data)) { -		retval = PTR_ERR(data); -		goto no_mem_sense; -	} - -	if (data->signature != 0xCFDCACDF) { -		retval = -EINVAL; -		goto free_buffer; -	} - -	retval = zfcp_cfdc_set_fsf(fsf_cfdc, data->command); - -	adapter = zfcp_cfdc_get_adapter(data->devno); -	if (!adapter) { -		retval = -ENXIO; -		goto free_buffer; -	} - -	retval = zfcp_cfdc_sg_setup(data->command, fsf_cfdc->sg, -				    data_user->control_file); -	if (retval) -		goto adapter_put; -	req = zfcp_fsf_control_file(adapter, fsf_cfdc); -	if (IS_ERR(req)) { -		retval = PTR_ERR(req); -		goto free_sg; -	} - -	if (req->status & ZFCP_STATUS_FSFREQ_ERROR) { -		retval = -ENXIO; -		goto free_fsf; -	} - -	zfcp_cfdc_req_to_sense(data, req); -	retval = copy_to_user(data_user, data, sizeof(*data_user)); -	if (retval) { -		retval = -EFAULT; -		goto free_fsf; -	} - -	if (data->command & ZFCP_CFDC_UPLOAD) -		retval = zfcp_cfdc_copy_to_user(&data_user->control_file, -						fsf_cfdc->sg); - - free_fsf: -	zfcp_fsf_req_free(req); - free_sg: -	zfcp_sg_free_table(fsf_cfdc->sg, ZFCP_CFDC_PAGES); - adapter_put: -	zfcp_ccw_adapter_put(adapter); - free_buffer: -	kfree(data); - no_mem_sense: -	kfree(fsf_cfdc); -	return retval; -} - -static const struct file_operations zfcp_cfdc_fops = { -	.open = nonseekable_open, -	.unlocked_ioctl = zfcp_cfdc_dev_ioctl, -#ifdef CONFIG_COMPAT -	.compat_ioctl = zfcp_cfdc_dev_ioctl, -#endif -	.llseek = no_llseek, -}; - -struct miscdevice zfcp_cfdc_misc = { -	.minor = MISC_DYNAMIC_MINOR, -	.name = "zfcp_cfdc", -	.fops = &zfcp_cfdc_fops, -}; - -/** - * zfcp_cfdc_adapter_access_changed - Process change in adapter ACT - * @adapter: Adapter where the Access Control Table (ACT) changed - * - * After a change in the adapter ACT, check if access to any - * previously denied resources is now possible. - */ -void zfcp_cfdc_adapter_access_changed(struct zfcp_adapter *adapter) -{ -	unsigned long flags; -	struct zfcp_port *port; -	struct scsi_device *sdev; -	struct zfcp_scsi_dev *zfcp_sdev; -	int status; - -	if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) -		return; - -	read_lock_irqsave(&adapter->port_list_lock, flags); -	list_for_each_entry(port, &adapter->port_list, list) { -		status = atomic_read(&port->status); -		if ((status & ZFCP_STATUS_COMMON_ACCESS_DENIED) || -		    (status & ZFCP_STATUS_COMMON_ACCESS_BOXED)) -			zfcp_erp_port_reopen(port, -					     ZFCP_STATUS_COMMON_ERP_FAILED, -					     "cfaac_1", NULL); -	} -	read_unlock_irqrestore(&adapter->port_list_lock, flags); - -	shost_for_each_device(sdev, port->adapter->scsi_host) { -		zfcp_sdev = sdev_to_zfcp(sdev); -		status = atomic_read(&zfcp_sdev->status); -		if ((status & ZFCP_STATUS_COMMON_ACCESS_DENIED) || -		    (status & ZFCP_STATUS_COMMON_ACCESS_BOXED)) -			zfcp_erp_lun_reopen(sdev, -					    ZFCP_STATUS_COMMON_ERP_FAILED, -					    "cfaac_2", NULL); -	} -} - -static void zfcp_act_eval_err(struct zfcp_adapter *adapter, u32 table) -{ -	u16 subtable = table >> 16; -	u16 rule = table & 0xffff; -	const char *act_type[] = { "unknown", "OS", "WWPN", "DID", "LUN" }; - -	if (subtable && subtable < ARRAY_SIZE(act_type)) -		dev_warn(&adapter->ccw_device->dev, -			 "Access denied according to ACT rule type %s, " -			 "rule %d\n", act_type[subtable], rule); -} - -/** - * zfcp_cfdc_port_denied - Process "access denied" for port - * @port: The port where the acces has been denied - * @qual: The FSF status qualifier for the access denied FSF status - */ -void zfcp_cfdc_port_denied(struct zfcp_port *port, -			   union fsf_status_qual *qual) -{ -	dev_warn(&port->adapter->ccw_device->dev, -		 "Access denied to port 0x%016Lx\n", -		 (unsigned long long)port->wwpn); - -	zfcp_act_eval_err(port->adapter, qual->halfword[0]); -	zfcp_act_eval_err(port->adapter, qual->halfword[1]); -	zfcp_erp_set_port_status(port, -				 ZFCP_STATUS_COMMON_ERP_FAILED | -				 ZFCP_STATUS_COMMON_ACCESS_DENIED); -} - -/** - * zfcp_cfdc_lun_denied - Process "access denied" for LUN - * @sdev: The SCSI device / LUN where the access has been denied - * @qual: The FSF status qualifier for the access denied FSF status - */ -void zfcp_cfdc_lun_denied(struct scsi_device *sdev, -			  union fsf_status_qual *qual) -{ -	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); - -	dev_warn(&zfcp_sdev->port->adapter->ccw_device->dev, -		 "Access denied to LUN 0x%016Lx on port 0x%016Lx\n", -		 zfcp_scsi_dev_lun(sdev), -		 (unsigned long long)zfcp_sdev->port->wwpn); -	zfcp_act_eval_err(zfcp_sdev->port->adapter, qual->halfword[0]); -	zfcp_act_eval_err(zfcp_sdev->port->adapter, qual->halfword[1]); -	zfcp_erp_set_lun_status(sdev, -				ZFCP_STATUS_COMMON_ERP_FAILED | -				ZFCP_STATUS_COMMON_ACCESS_DENIED); - -	atomic_clear_mask(ZFCP_STATUS_LUN_SHARED, &zfcp_sdev->status); -	atomic_clear_mask(ZFCP_STATUS_LUN_READONLY, &zfcp_sdev->status); -} - -/** - * zfcp_cfdc_lun_shrng_vltn - Evaluate LUN sharing violation status - * @sdev: The LUN / SCSI device where sharing violation occurred - * @qual: The FSF status qualifier from the LUN sharing violation - */ -void zfcp_cfdc_lun_shrng_vltn(struct scsi_device *sdev, -			      union fsf_status_qual *qual) -{ -	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); - -	if (qual->word[0]) -		dev_warn(&zfcp_sdev->port->adapter->ccw_device->dev, -			 "LUN 0x%Lx on port 0x%Lx is already in " -			 "use by CSS%d, MIF Image ID %x\n", -			 zfcp_scsi_dev_lun(sdev), -			 (unsigned long long)zfcp_sdev->port->wwpn, -			 qual->fsf_queue_designator.cssid, -			 qual->fsf_queue_designator.hla); -	else -		zfcp_act_eval_err(zfcp_sdev->port->adapter, qual->word[2]); - -	zfcp_erp_set_lun_status(sdev, -				ZFCP_STATUS_COMMON_ERP_FAILED | -				ZFCP_STATUS_COMMON_ACCESS_DENIED); -	atomic_clear_mask(ZFCP_STATUS_LUN_SHARED, &zfcp_sdev->status); -	atomic_clear_mask(ZFCP_STATUS_LUN_READONLY, &zfcp_sdev->status); -} - -/** - * zfcp_cfdc_open_lun_eval - Eval access ctrl. status for successful "open lun" - * @sdev: The SCSI device / LUN where to evaluate the status - * @bottom: The qtcb bottom with the status from the "open lun" - * - * Returns: 0 if LUN is usable, -EACCES if the access control table - *          reports an unsupported configuration. - */ -int zfcp_cfdc_open_lun_eval(struct scsi_device *sdev, -			    struct fsf_qtcb_bottom_support *bottom) -{ -	int shared, rw; -	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); -	struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; - -	if ((adapter->connection_features & FSF_FEATURE_NPIV_MODE) || -	    !(adapter->adapter_features & FSF_FEATURE_LUN_SHARING) || -	    zfcp_ccw_priv_sch(adapter)) -		return 0; - -	shared = !(bottom->lun_access_info & FSF_UNIT_ACCESS_EXCLUSIVE); -	rw = (bottom->lun_access_info & FSF_UNIT_ACCESS_OUTBOUND_TRANSFER); - -	if (shared) -		atomic_set_mask(ZFCP_STATUS_LUN_SHARED, &zfcp_sdev->status); - -	if (!rw) { -		atomic_set_mask(ZFCP_STATUS_LUN_READONLY, &zfcp_sdev->status); -		dev_info(&adapter->ccw_device->dev, "SCSI device at LUN " -			 "0x%016Lx on port 0x%016Lx opened read-only\n", -			 zfcp_scsi_dev_lun(sdev), -			 (unsigned long long)zfcp_sdev->port->wwpn); -	} - -	if (!shared && !rw) { -		dev_err(&adapter->ccw_device->dev, "Exclusive read-only access " -			"not supported (LUN 0x%016Lx, port 0x%016Lx)\n", -			zfcp_scsi_dev_lun(sdev), -			(unsigned long long)zfcp_sdev->port->wwpn); -		zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ERP_FAILED); -		zfcp_erp_lun_shutdown(sdev, 0, "fsouh_6", NULL); -		return -EACCES; -	} - -	if (shared && rw) { -		dev_err(&adapter->ccw_device->dev, -			"Shared read-write access not supported " -			"(LUN 0x%016Lx, port 0x%016Lx)\n", -			zfcp_scsi_dev_lun(sdev), -			(unsigned long long)zfcp_sdev->port->wwpn); -		zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ERP_FAILED); -		zfcp_erp_lun_shutdown(sdev, 0, "fsosh_8", NULL); -		return -EACCES; -	} - -	return 0; -} diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 2cdd6b28ff7..0ca64484cfa 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -3,12 +3,13 @@   *   * Debug traces for zfcp.   * - * Copyright IBM Corporation 2002, 2009 + * Copyright IBM Corp. 2002, 2013   */  #define KMSG_COMPONENT "zfcp"  #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +#include <linux/module.h>  #include <linux/ctype.h>  #include <linux/slab.h>  #include <asm/debug.h> @@ -22,980 +23,455 @@ module_param(dbfsize, uint, 0400);  MODULE_PARM_DESC(dbfsize,  		 "number of pages for each debug feature area (default 4)"); -static void zfcp_dbf_hexdump(debug_info_t *dbf, void *to, int to_len, -			     int level, char *from, int from_len) -{ -	int offset; -	struct zfcp_dbf_dump *dump = to; -	int room = to_len - sizeof(*dump); - -	for (offset = 0; offset < from_len; offset += dump->size) { -		memset(to, 0, to_len); -		strncpy(dump->tag, "dump", ZFCP_DBF_TAG_SIZE); -		dump->total_size = from_len; -		dump->offset = offset; -		dump->size = min(from_len - offset, room); -		memcpy(dump->data, from + offset, dump->size); -		debug_event(dbf, level, dump, dump->size + sizeof(*dump)); -	} -} +static u32 dbflevel = 3; -static void zfcp_dbf_tag(char **p, const char *label, const char *tag) -{ -	int i; - -	*p += sprintf(*p, "%-24s", label); -	for (i = 0; i < ZFCP_DBF_TAG_SIZE; i++) -		*p += sprintf(*p, "%c", tag[i]); -	*p += sprintf(*p, "\n"); -} +module_param(dbflevel, uint, 0400); +MODULE_PARM_DESC(dbflevel, +		 "log level for each debug feature area " +		 "(default 3, range 0..6)"); -static void zfcp_dbf_outs(char **buf, const char *s1, const char *s2) +static inline unsigned int zfcp_dbf_plen(unsigned int offset)  { -	*buf += sprintf(*buf, "%-24s%s\n", s1, s2); +	return sizeof(struct zfcp_dbf_pay) + offset - ZFCP_DBF_PAY_MAX_REC;  } -static void zfcp_dbf_out(char **buf, const char *s, const char *format, ...) +static inline +void zfcp_dbf_pl_write(struct zfcp_dbf *dbf, void *data, u16 length, char *area, +		       u64 req_id)  { -	va_list arg; +	struct zfcp_dbf_pay *pl = &dbf->pay_buf; +	u16 offset = 0, rec_length; -	*buf += sprintf(*buf, "%-24s", s); -	va_start(arg, format); -	*buf += vsprintf(*buf, format, arg); -	va_end(arg); -	*buf += sprintf(*buf, "\n"); -} +	spin_lock(&dbf->pay_lock); +	memset(pl, 0, sizeof(*pl)); +	pl->fsf_req_id = req_id; +	memcpy(pl->area, area, ZFCP_DBF_TAG_LEN); -static void zfcp_dbf_outd(char **p, const char *label, char *buffer, -			  int buflen, int offset, int total_size) -{ -	if (!offset) -		*p += sprintf(*p, "%-24s  ", label); -	while (buflen--) { -		if (offset > 0) { -			if ((offset % 32) == 0) -				*p += sprintf(*p, "\n%-24c  ", ' '); -			else if ((offset % 4) == 0) -				*p += sprintf(*p, " "); -		} -		*p += sprintf(*p, "%02x", *buffer++); -		if (++offset == total_size) { -			*p += sprintf(*p, "\n"); -			break; -		} -	} -	if (!total_size) -		*p += sprintf(*p, "\n"); -} +	while (offset < length) { +		rec_length = min((u16) ZFCP_DBF_PAY_MAX_REC, +				 (u16) (length - offset)); +		memcpy(pl->data, data + offset, rec_length); +		debug_event(dbf->pay, 1, pl, zfcp_dbf_plen(rec_length)); -static int zfcp_dbf_view_header(debug_info_t *id, struct debug_view *view, -				int area, debug_entry_t *entry, char *out_buf) -{ -	struct zfcp_dbf_dump *dump = (struct zfcp_dbf_dump *)DEBUG_DATA(entry); -	struct timespec t; -	char *p = out_buf; - -	if (strncmp(dump->tag, "dump", ZFCP_DBF_TAG_SIZE) != 0) { -		stck_to_timespec(entry->id.stck, &t); -		zfcp_dbf_out(&p, "timestamp", "%011lu:%06lu", -			     t.tv_sec, t.tv_nsec); -		zfcp_dbf_out(&p, "cpu", "%02i", entry->id.fields.cpuid); -	} else	{ -		zfcp_dbf_outd(&p, "", dump->data, dump->size, dump->offset, -			      dump->total_size); -		if ((dump->offset + dump->size) == dump->total_size) -			p += sprintf(p, "\n"); +		offset += rec_length; +		pl->counter++;  	} -	return p - out_buf; + +	spin_unlock(&dbf->pay_lock);  } -void _zfcp_dbf_hba_fsf_response(const char *tag2, int level, -				struct zfcp_fsf_req *fsf_req, -				struct zfcp_dbf *dbf) +/** + * zfcp_dbf_hba_fsf_res - trace event for fsf responses + * @tag: tag indicating which kind of unsolicited status has been received + * @req: request for which a response was received + */ +void zfcp_dbf_hba_fsf_res(char *tag, struct zfcp_fsf_req *req)  { -	struct fsf_qtcb *qtcb = fsf_req->qtcb; -	union fsf_prot_status_qual *prot_status_qual = -					&qtcb->prefix.prot_status_qual; -	union fsf_status_qual *fsf_status_qual = &qtcb->header.fsf_status_qual; -	struct scsi_cmnd *scsi_cmnd; -	struct zfcp_port *port; -	struct zfcp_unit *unit; -	struct zfcp_send_els *send_els; -	struct zfcp_dbf_hba_record *rec = &dbf->hba_buf; -	struct zfcp_dbf_hba_record_response *response = &rec->u.response; +	struct zfcp_dbf *dbf = req->adapter->dbf; +	struct fsf_qtcb_prefix *q_pref = &req->qtcb->prefix; +	struct fsf_qtcb_header *q_head = &req->qtcb->header; +	struct zfcp_dbf_hba *rec = &dbf->hba_buf;  	unsigned long flags;  	spin_lock_irqsave(&dbf->hba_lock, flags);  	memset(rec, 0, sizeof(*rec)); -	strncpy(rec->tag, "resp", ZFCP_DBF_TAG_SIZE); -	strncpy(rec->tag2, tag2, ZFCP_DBF_TAG_SIZE); - -	response->fsf_command = fsf_req->fsf_command; -	response->fsf_reqid = fsf_req->req_id; -	response->fsf_seqno = fsf_req->seq_no; -	response->fsf_issued = fsf_req->issued; -	response->fsf_prot_status = qtcb->prefix.prot_status; -	response->fsf_status = qtcb->header.fsf_status; -	memcpy(response->fsf_prot_status_qual, -	       prot_status_qual, FSF_PROT_STATUS_QUAL_SIZE); -	memcpy(response->fsf_status_qual, -	       fsf_status_qual, FSF_STATUS_QUALIFIER_SIZE); -	response->fsf_req_status = fsf_req->status; -	response->sbal_first = fsf_req->qdio_req.sbal_first; -	response->sbal_last = fsf_req->qdio_req.sbal_last; -	response->sbal_response = fsf_req->qdio_req.sbal_response; -	response->pool = fsf_req->pool != NULL; -	response->erp_action = (unsigned long)fsf_req->erp_action; - -	switch (fsf_req->fsf_command) { -	case FSF_QTCB_FCP_CMND: -		if (fsf_req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT) -			break; -		scsi_cmnd = (struct scsi_cmnd *)fsf_req->data; -		if (scsi_cmnd) { -			response->u.fcp.cmnd = (unsigned long)scsi_cmnd; -			response->u.fcp.data_dir = -				qtcb->bottom.io.data_direction; -		} -		break; - -	case FSF_QTCB_OPEN_PORT_WITH_DID: -	case FSF_QTCB_CLOSE_PORT: -	case FSF_QTCB_CLOSE_PHYSICAL_PORT: -		port = (struct zfcp_port *)fsf_req->data; -		response->u.port.wwpn = port->wwpn; -		response->u.port.d_id = port->d_id; -		response->u.port.port_handle = qtcb->header.port_handle; -		break; - -	case FSF_QTCB_OPEN_LUN: -	case FSF_QTCB_CLOSE_LUN: -		unit = (struct zfcp_unit *)fsf_req->data; -		port = unit->port; -		response->u.unit.wwpn = port->wwpn; -		response->u.unit.fcp_lun = unit->fcp_lun; -		response->u.unit.port_handle = qtcb->header.port_handle; -		response->u.unit.lun_handle = qtcb->header.lun_handle; -		break; - -	case FSF_QTCB_SEND_ELS: -		send_els = (struct zfcp_send_els *)fsf_req->data; -		response->u.els.d_id = ntoh24(qtcb->bottom.support.d_id); -		break; - -	case FSF_QTCB_ABORT_FCP_CMND: -	case FSF_QTCB_SEND_GENERIC: -	case FSF_QTCB_EXCHANGE_CONFIG_DATA: -	case FSF_QTCB_EXCHANGE_PORT_DATA: -	case FSF_QTCB_DOWNLOAD_CONTROL_FILE: -	case FSF_QTCB_UPLOAD_CONTROL_FILE: -		break; -	} - -	debug_event(dbf->hba, level, rec, sizeof(*rec)); -	/* have fcp channel microcode fixed to use as little as possible */ -	if (fsf_req->fsf_command != FSF_QTCB_FCP_CMND) { -		/* adjust length skipping trailing zeros */ -		char *buf = (char *)qtcb + qtcb->header.log_start; -		int len = qtcb->header.log_length; -		for (; len && !buf[len - 1]; len--); -		zfcp_dbf_hexdump(dbf->hba, rec, sizeof(*rec), level, buf, -				 len); +	memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN); +	rec->id = ZFCP_DBF_HBA_RES; +	rec->fsf_req_id = req->req_id; +	rec->fsf_req_status = req->status; +	rec->fsf_cmd = req->fsf_command; +	rec->fsf_seq_no = req->seq_no; +	rec->u.res.req_issued = req->issued; +	rec->u.res.prot_status = q_pref->prot_status; +	rec->u.res.fsf_status = q_head->fsf_status; + +	memcpy(rec->u.res.prot_status_qual, &q_pref->prot_status_qual, +	       FSF_PROT_STATUS_QUAL_SIZE); +	memcpy(rec->u.res.fsf_status_qual, &q_head->fsf_status_qual, +	       FSF_STATUS_QUALIFIER_SIZE); + +	if (req->fsf_command != FSF_QTCB_FCP_CMND) { +		rec->pl_len = q_head->log_length; +		zfcp_dbf_pl_write(dbf, (char *)q_pref + q_head->log_start, +				  rec->pl_len, "fsf_res", req->req_id);  	} +	debug_event(dbf->hba, 1, rec, sizeof(*rec));  	spin_unlock_irqrestore(&dbf->hba_lock, flags);  } -void _zfcp_dbf_hba_fsf_unsol(const char *tag, int level, struct zfcp_dbf *dbf, -			     struct fsf_status_read_buffer *status_buffer) +/** + * zfcp_dbf_hba_fsf_uss - trace event for an unsolicited status buffer + * @tag: tag indicating which kind of unsolicited status has been received + * @req: request providing the unsolicited status + */ +void zfcp_dbf_hba_fsf_uss(char *tag, struct zfcp_fsf_req *req)  { -	struct zfcp_dbf_hba_record *rec = &dbf->hba_buf; +	struct zfcp_dbf *dbf = req->adapter->dbf; +	struct fsf_status_read_buffer *srb = req->data; +	struct zfcp_dbf_hba *rec = &dbf->hba_buf;  	unsigned long flags;  	spin_lock_irqsave(&dbf->hba_lock, flags);  	memset(rec, 0, sizeof(*rec)); -	strncpy(rec->tag, "stat", ZFCP_DBF_TAG_SIZE); -	strncpy(rec->tag2, tag, ZFCP_DBF_TAG_SIZE); - -	rec->u.status.failed = atomic_read(&dbf->adapter->stat_miss); -	if (status_buffer != NULL) { -		rec->u.status.status_type = status_buffer->status_type; -		rec->u.status.status_subtype = status_buffer->status_subtype; -		memcpy(&rec->u.status.queue_designator, -		       &status_buffer->queue_designator, -		       sizeof(struct fsf_queue_designator)); - -		switch (status_buffer->status_type) { -		case FSF_STATUS_READ_SENSE_DATA_AVAIL: -			rec->u.status.payload_size = -			    ZFCP_DBF_UNSOL_PAYLOAD_SENSE_DATA_AVAIL; -			break; - -		case FSF_STATUS_READ_BIT_ERROR_THRESHOLD: -			rec->u.status.payload_size = -			    ZFCP_DBF_UNSOL_PAYLOAD_BIT_ERROR_THRESHOLD; -			break; - -		case FSF_STATUS_READ_LINK_DOWN: -			switch (status_buffer->status_subtype) { -			case FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK: -			case FSF_STATUS_READ_SUB_FDISC_FAILED: -				rec->u.status.payload_size = -					sizeof(struct fsf_link_down_info); -			} -			break; - -		case FSF_STATUS_READ_FEATURE_UPDATE_ALERT: -			rec->u.status.payload_size = -			    ZFCP_DBF_UNSOL_PAYLOAD_FEATURE_UPDATE_ALERT; -			break; -		} -		memcpy(&rec->u.status.payload, -		       &status_buffer->payload, rec->u.status.payload_size); -	} -	debug_event(dbf->hba, level, rec, sizeof(*rec)); +	memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN); +	rec->id = ZFCP_DBF_HBA_USS; +	rec->fsf_req_id = req->req_id; +	rec->fsf_req_status = req->status; +	rec->fsf_cmd = req->fsf_command; + +	if (!srb) +		goto log; + +	rec->u.uss.status_type = srb->status_type; +	rec->u.uss.status_subtype = srb->status_subtype; +	rec->u.uss.d_id = ntoh24(srb->d_id); +	rec->u.uss.lun = srb->fcp_lun; +	memcpy(&rec->u.uss.queue_designator, &srb->queue_designator, +	       sizeof(rec->u.uss.queue_designator)); + +	/* status read buffer payload length */ +	rec->pl_len = (!srb->length) ? 0 : srb->length - +			offsetof(struct fsf_status_read_buffer, payload); + +	if (rec->pl_len) +		zfcp_dbf_pl_write(dbf, srb->payload.data, rec->pl_len, +				  "fsf_uss", req->req_id); +log: +	debug_event(dbf->hba, 2, rec, sizeof(*rec));  	spin_unlock_irqrestore(&dbf->hba_lock, flags);  }  /** - * zfcp_dbf_hba_qdio - trace event for QDIO related failure - * @qdio: qdio structure affected by this QDIO related event - * @qdio_error: as passed by qdio module - * @sbal_index: first buffer with error condition, as passed by qdio module - * @sbal_count: number of buffers affected, as passed by qdio module + * zfcp_dbf_hba_bit_err - trace event for bit error conditions + * @tag: tag indicating which kind of unsolicited status has been received + * @req: request which caused the bit_error condition   */ -void zfcp_dbf_hba_qdio(struct zfcp_dbf *dbf, unsigned int qdio_error, -		       int sbal_index, int sbal_count) +void zfcp_dbf_hba_bit_err(char *tag, struct zfcp_fsf_req *req)  { -	struct zfcp_dbf_hba_record *r = &dbf->hba_buf; +	struct zfcp_dbf *dbf = req->adapter->dbf; +	struct zfcp_dbf_hba *rec = &dbf->hba_buf; +	struct fsf_status_read_buffer *sr_buf = req->data;  	unsigned long flags;  	spin_lock_irqsave(&dbf->hba_lock, flags); -	memset(r, 0, sizeof(*r)); -	strncpy(r->tag, "qdio", ZFCP_DBF_TAG_SIZE); -	r->u.qdio.qdio_error = qdio_error; -	r->u.qdio.sbal_index = sbal_index; -	r->u.qdio.sbal_count = sbal_count; -	debug_event(dbf->hba, 0, r, sizeof(*r)); +	memset(rec, 0, sizeof(*rec)); + +	memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN); +	rec->id = ZFCP_DBF_HBA_BIT; +	rec->fsf_req_id = req->req_id; +	rec->fsf_req_status = req->status; +	rec->fsf_cmd = req->fsf_command; +	memcpy(&rec->u.be, &sr_buf->payload.bit_error, +	       sizeof(struct fsf_bit_error_payload)); + +	debug_event(dbf->hba, 1, rec, sizeof(*rec));  	spin_unlock_irqrestore(&dbf->hba_lock, flags);  }  /** - * zfcp_dbf_hba_berr - trace event for bit error threshold - * @dbf: dbf structure affected by this QDIO related event - * @req: fsf request + * zfcp_dbf_hba_def_err - trace event for deferred error messages + * @adapter: pointer to struct zfcp_adapter + * @req_id: request id which caused the deferred error message + * @scount: number of sbals incl. the signaling sbal + * @pl: array of all involved sbals   */ -void zfcp_dbf_hba_berr(struct zfcp_dbf *dbf, struct zfcp_fsf_req *req) +void zfcp_dbf_hba_def_err(struct zfcp_adapter *adapter, u64 req_id, u16 scount, +			  void **pl)  { -	struct zfcp_dbf_hba_record *r = &dbf->hba_buf; -	struct fsf_status_read_buffer *sr_buf = req->data; -	struct fsf_bit_error_payload *err = &sr_buf->payload.bit_error; +	struct zfcp_dbf *dbf = adapter->dbf; +	struct zfcp_dbf_pay *payload = &dbf->pay_buf;  	unsigned long flags; +	u16 length; -	spin_lock_irqsave(&dbf->hba_lock, flags); -	memset(r, 0, sizeof(*r)); -	strncpy(r->tag, "berr", ZFCP_DBF_TAG_SIZE); -	memcpy(&r->u.berr, err, sizeof(struct fsf_bit_error_payload)); -	debug_event(dbf->hba, 0, r, sizeof(*r)); -	spin_unlock_irqrestore(&dbf->hba_lock, flags); -} -static void zfcp_dbf_hba_view_response(char **p, -				       struct zfcp_dbf_hba_record_response *r) -{ -	struct timespec t; - -	zfcp_dbf_out(p, "fsf_command", "0x%08x", r->fsf_command); -	zfcp_dbf_out(p, "fsf_reqid", "0x%0Lx", r->fsf_reqid); -	zfcp_dbf_out(p, "fsf_seqno", "0x%08x", r->fsf_seqno); -	stck_to_timespec(r->fsf_issued, &t); -	zfcp_dbf_out(p, "fsf_issued", "%011lu:%06lu", t.tv_sec, t.tv_nsec); -	zfcp_dbf_out(p, "fsf_prot_status", "0x%08x", r->fsf_prot_status); -	zfcp_dbf_out(p, "fsf_status", "0x%08x", r->fsf_status); -	zfcp_dbf_outd(p, "fsf_prot_status_qual", r->fsf_prot_status_qual, -		      FSF_PROT_STATUS_QUAL_SIZE, 0, FSF_PROT_STATUS_QUAL_SIZE); -	zfcp_dbf_outd(p, "fsf_status_qual", r->fsf_status_qual, -		      FSF_STATUS_QUALIFIER_SIZE, 0, FSF_STATUS_QUALIFIER_SIZE); -	zfcp_dbf_out(p, "fsf_req_status", "0x%08x", r->fsf_req_status); -	zfcp_dbf_out(p, "sbal_first", "0x%02x", r->sbal_first); -	zfcp_dbf_out(p, "sbal_last", "0x%02x", r->sbal_last); -	zfcp_dbf_out(p, "sbal_response", "0x%02x", r->sbal_response); -	zfcp_dbf_out(p, "pool", "0x%02x", r->pool); - -	switch (r->fsf_command) { -	case FSF_QTCB_FCP_CMND: -		if (r->fsf_req_status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT) -			break; -		zfcp_dbf_out(p, "data_direction", "0x%04x", r->u.fcp.data_dir); -		zfcp_dbf_out(p, "scsi_cmnd", "0x%0Lx", r->u.fcp.cmnd); -		*p += sprintf(*p, "\n"); -		break; - -	case FSF_QTCB_OPEN_PORT_WITH_DID: -	case FSF_QTCB_CLOSE_PORT: -	case FSF_QTCB_CLOSE_PHYSICAL_PORT: -		zfcp_dbf_out(p, "wwpn", "0x%016Lx", r->u.port.wwpn); -		zfcp_dbf_out(p, "d_id", "0x%06x", r->u.port.d_id); -		zfcp_dbf_out(p, "port_handle", "0x%08x", r->u.port.port_handle); -		break; - -	case FSF_QTCB_OPEN_LUN: -	case FSF_QTCB_CLOSE_LUN: -		zfcp_dbf_out(p, "wwpn", "0x%016Lx", r->u.unit.wwpn); -		zfcp_dbf_out(p, "fcp_lun", "0x%016Lx", r->u.unit.fcp_lun); -		zfcp_dbf_out(p, "port_handle", "0x%08x", r->u.unit.port_handle); -		zfcp_dbf_out(p, "lun_handle", "0x%08x", r->u.unit.lun_handle); -		break; - -	case FSF_QTCB_SEND_ELS: -		zfcp_dbf_out(p, "d_id", "0x%06x", r->u.els.d_id); -		break; - -	case FSF_QTCB_ABORT_FCP_CMND: -	case FSF_QTCB_SEND_GENERIC: -	case FSF_QTCB_EXCHANGE_CONFIG_DATA: -	case FSF_QTCB_EXCHANGE_PORT_DATA: -	case FSF_QTCB_DOWNLOAD_CONTROL_FILE: -	case FSF_QTCB_UPLOAD_CONTROL_FILE: -		break; -	} -} - -static void zfcp_dbf_hba_view_status(char **p, -				     struct zfcp_dbf_hba_record_status *r) -{ -	zfcp_dbf_out(p, "failed", "0x%02x", r->failed); -	zfcp_dbf_out(p, "status_type", "0x%08x", r->status_type); -	zfcp_dbf_out(p, "status_subtype", "0x%08x", r->status_subtype); -	zfcp_dbf_outd(p, "queue_designator", (char *)&r->queue_designator, -		      sizeof(struct fsf_queue_designator), 0, -		      sizeof(struct fsf_queue_designator)); -	zfcp_dbf_outd(p, "payload", (char *)&r->payload, r->payload_size, 0, -		      r->payload_size); -} - -static void zfcp_dbf_hba_view_qdio(char **p, struct zfcp_dbf_hba_record_qdio *r) -{ -	zfcp_dbf_out(p, "qdio_error", "0x%08x", r->qdio_error); -	zfcp_dbf_out(p, "sbal_index", "0x%02x", r->sbal_index); -	zfcp_dbf_out(p, "sbal_count", "0x%02x", r->sbal_count); -} +	if (!pl) +		return; -static void zfcp_dbf_hba_view_berr(char **p, struct fsf_bit_error_payload *r) -{ -	zfcp_dbf_out(p, "link_failures", "%d", r->link_failure_error_count); -	zfcp_dbf_out(p, "loss_of_sync_err", "%d", r->loss_of_sync_error_count); -	zfcp_dbf_out(p, "loss_of_sig_err", "%d", r->loss_of_signal_error_count); -	zfcp_dbf_out(p, "prim_seq_err", "%d", -		     r->primitive_sequence_error_count); -	zfcp_dbf_out(p, "inval_trans_word_err", "%d", -		     r->invalid_transmission_word_error_count); -	zfcp_dbf_out(p, "CRC_errors", "%d", r->crc_error_count); -	zfcp_dbf_out(p, "prim_seq_event_to", "%d", -		     r->primitive_sequence_event_timeout_count); -	zfcp_dbf_out(p, "elast_buf_overrun_err", "%d", -		     r->elastic_buffer_overrun_error_count); -	zfcp_dbf_out(p, "adv_rec_buf2buf_cred", "%d", -		     r->advertised_receive_b2b_credit); -	zfcp_dbf_out(p, "curr_rec_buf2buf_cred", "%d", -		     r->current_receive_b2b_credit); -	zfcp_dbf_out(p, "adv_trans_buf2buf_cred", "%d", -		     r->advertised_transmit_b2b_credit); -	zfcp_dbf_out(p, "curr_trans_buf2buf_cred", "%d", -		     r->current_transmit_b2b_credit); -} +	spin_lock_irqsave(&dbf->pay_lock, flags); +	memset(payload, 0, sizeof(*payload)); -static int zfcp_dbf_hba_view_format(debug_info_t *id, struct debug_view *view, -				    char *out_buf, const char *in_buf) -{ -	struct zfcp_dbf_hba_record *r = (struct zfcp_dbf_hba_record *)in_buf; -	char *p = out_buf; - -	if (strncmp(r->tag, "dump", ZFCP_DBF_TAG_SIZE) == 0) -		return 0; - -	zfcp_dbf_tag(&p, "tag", r->tag); -	if (isalpha(r->tag2[0])) -		zfcp_dbf_tag(&p, "tag2", r->tag2); - -	if (strncmp(r->tag, "resp", ZFCP_DBF_TAG_SIZE) == 0) -		zfcp_dbf_hba_view_response(&p, &r->u.response); -	else if (strncmp(r->tag, "stat", ZFCP_DBF_TAG_SIZE) == 0) -		zfcp_dbf_hba_view_status(&p, &r->u.status); -	else if (strncmp(r->tag, "qdio", ZFCP_DBF_TAG_SIZE) == 0) -		zfcp_dbf_hba_view_qdio(&p, &r->u.qdio); -	else if (strncmp(r->tag, "berr", ZFCP_DBF_TAG_SIZE) == 0) -		zfcp_dbf_hba_view_berr(&p, &r->u.berr); - -	if (strncmp(r->tag, "resp", ZFCP_DBF_TAG_SIZE) != 0) -		p += sprintf(p, "\n"); -	return p - out_buf; -} +	memcpy(payload->area, "def_err", 7); +	payload->fsf_req_id = req_id; +	payload->counter = 0; +	length = min((u16)sizeof(struct qdio_buffer), +		     (u16)ZFCP_DBF_PAY_MAX_REC); -static struct debug_view zfcp_dbf_hba_view = { -	.name = "structured", -	.header_proc = zfcp_dbf_view_header, -	.format_proc = zfcp_dbf_hba_view_format, -}; - -static const char *zfcp_dbf_rec_tags[] = { -	[ZFCP_REC_DBF_ID_THREAD] = "thread", -	[ZFCP_REC_DBF_ID_TARGET] = "target", -	[ZFCP_REC_DBF_ID_TRIGGER] = "trigger", -	[ZFCP_REC_DBF_ID_ACTION] = "action", -}; - -static int zfcp_dbf_rec_view_format(debug_info_t *id, struct debug_view *view, -				    char *buf, const char *_rec) -{ -	struct zfcp_dbf_rec_record *r = (struct zfcp_dbf_rec_record *)_rec; -	char *p = buf; -	char hint[ZFCP_DBF_ID_SIZE + 1]; - -	memcpy(hint, r->id2, ZFCP_DBF_ID_SIZE); -	hint[ZFCP_DBF_ID_SIZE] = 0; -	zfcp_dbf_outs(&p, "tag", zfcp_dbf_rec_tags[r->id]); -	zfcp_dbf_outs(&p, "hint", hint); -	switch (r->id) { -	case ZFCP_REC_DBF_ID_THREAD: -		zfcp_dbf_out(&p, "total", "%d", r->u.thread.total); -		zfcp_dbf_out(&p, "ready", "%d", r->u.thread.ready); -		zfcp_dbf_out(&p, "running", "%d", r->u.thread.running); -		break; -	case ZFCP_REC_DBF_ID_TARGET: -		zfcp_dbf_out(&p, "reference", "0x%016Lx", r->u.target.ref); -		zfcp_dbf_out(&p, "status", "0x%08x", r->u.target.status); -		zfcp_dbf_out(&p, "erp_count", "%d", r->u.target.erp_count); -		zfcp_dbf_out(&p, "d_id", "0x%06x", r->u.target.d_id); -		zfcp_dbf_out(&p, "wwpn", "0x%016Lx", r->u.target.wwpn); -		zfcp_dbf_out(&p, "fcp_lun", "0x%016Lx", r->u.target.fcp_lun); -		break; -	case ZFCP_REC_DBF_ID_TRIGGER: -		zfcp_dbf_out(&p, "reference", "0x%016Lx", r->u.trigger.ref); -		zfcp_dbf_out(&p, "erp_action", "0x%016Lx", r->u.trigger.action); -		zfcp_dbf_out(&p, "requested", "%d", r->u.trigger.want); -		zfcp_dbf_out(&p, "executed", "%d", r->u.trigger.need); -		zfcp_dbf_out(&p, "wwpn", "0x%016Lx", r->u.trigger.wwpn); -		zfcp_dbf_out(&p, "fcp_lun", "0x%016Lx", r->u.trigger.fcp_lun); -		zfcp_dbf_out(&p, "adapter_status", "0x%08x", r->u.trigger.as); -		zfcp_dbf_out(&p, "port_status", "0x%08x", r->u.trigger.ps); -		zfcp_dbf_out(&p, "lun_status", "0x%08x", r->u.trigger.ls); -		break; -	case ZFCP_REC_DBF_ID_ACTION: -		zfcp_dbf_out(&p, "erp_action", "0x%016Lx", r->u.action.action); -		zfcp_dbf_out(&p, "fsf_req", "0x%016Lx", r->u.action.fsf_req); -		zfcp_dbf_out(&p, "status", "0x%08Lx", r->u.action.status); -		zfcp_dbf_out(&p, "step", "0x%08Lx", r->u.action.step); -		break; +	while (payload->counter < scount && (char *)pl[payload->counter]) { +		memcpy(payload->data, (char *)pl[payload->counter], length); +		debug_event(dbf->pay, 1, payload, zfcp_dbf_plen(length)); +		payload->counter++;  	} -	p += sprintf(p, "\n"); -	return p - buf; -} -static struct debug_view zfcp_dbf_rec_view = { -	.name = "structured", -	.header_proc = zfcp_dbf_view_header, -	.format_proc = zfcp_dbf_rec_view_format, -}; - -/** - * zfcp_dbf_rec_thread - trace event related to recovery thread operation - * @id2: identifier for event - * @dbf: reference to dbf structure - * This function assumes that the caller is holding erp_lock. - */ -void zfcp_dbf_rec_thread(char *id2, struct zfcp_dbf *dbf) -{ -	struct zfcp_adapter *adapter = dbf->adapter; -	struct zfcp_dbf_rec_record *r = &dbf->rec_buf; -	unsigned long flags = 0; -	struct list_head *entry; -	unsigned ready = 0, running = 0, total; - -	list_for_each(entry, &adapter->erp_ready_head) -		ready++; -	list_for_each(entry, &adapter->erp_running_head) -		running++; -	total = adapter->erp_total_count; - -	spin_lock_irqsave(&dbf->rec_lock, flags); -	memset(r, 0, sizeof(*r)); -	r->id = ZFCP_REC_DBF_ID_THREAD; -	memcpy(r->id2, id2, ZFCP_DBF_ID_SIZE); -	r->u.thread.total = total; -	r->u.thread.ready = ready; -	r->u.thread.running = running; -	debug_event(dbf->rec, 6, r, sizeof(*r)); -	spin_unlock_irqrestore(&dbf->rec_lock, flags); +	spin_unlock_irqrestore(&dbf->pay_lock, flags);  }  /** - * zfcp_dbf_rec_thread - trace event related to recovery thread operation - * @id2: identifier for event - * @adapter: adapter - * This function assumes that the caller does not hold erp_lock. + * zfcp_dbf_hba_basic - trace event for basic adapter events + * @adapter: pointer to struct zfcp_adapter   */ -void zfcp_dbf_rec_thread_lock(char *id2, struct zfcp_dbf *dbf) +void zfcp_dbf_hba_basic(char *tag, struct zfcp_adapter *adapter)  { -	struct zfcp_adapter *adapter = dbf->adapter; +	struct zfcp_dbf *dbf = adapter->dbf; +	struct zfcp_dbf_hba *rec = &dbf->hba_buf;  	unsigned long flags; -	read_lock_irqsave(&adapter->erp_lock, flags); -	zfcp_dbf_rec_thread(id2, dbf); -	read_unlock_irqrestore(&adapter->erp_lock, flags); -} +	spin_lock_irqsave(&dbf->hba_lock, flags); +	memset(rec, 0, sizeof(*rec)); -static void zfcp_dbf_rec_target(char *id2, void *ref, struct zfcp_dbf *dbf, -				atomic_t *status, atomic_t *erp_count, u64 wwpn, -				u32 d_id, u64 fcp_lun) -{ -	struct zfcp_dbf_rec_record *r = &dbf->rec_buf; -	unsigned long flags; +	memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN); +	rec->id = ZFCP_DBF_HBA_BASIC; -	spin_lock_irqsave(&dbf->rec_lock, flags); -	memset(r, 0, sizeof(*r)); -	r->id = ZFCP_REC_DBF_ID_TARGET; -	memcpy(r->id2, id2, ZFCP_DBF_ID_SIZE); -	r->u.target.ref = (unsigned long)ref; -	r->u.target.status = atomic_read(status); -	r->u.target.wwpn = wwpn; -	r->u.target.d_id = d_id; -	r->u.target.fcp_lun = fcp_lun; -	r->u.target.erp_count = atomic_read(erp_count); -	debug_event(dbf->rec, 3, r, sizeof(*r)); -	spin_unlock_irqrestore(&dbf->rec_lock, flags); +	debug_event(dbf->hba, 1, rec, sizeof(*rec)); +	spin_unlock_irqrestore(&dbf->hba_lock, flags);  } -/** - * zfcp_dbf_rec_adapter - trace event for adapter state change - * @id: identifier for trigger of state change - * @ref: additional reference (e.g. request) - * @dbf: reference to dbf structure - */ -void zfcp_dbf_rec_adapter(char *id, void *ref, struct zfcp_dbf *dbf) +static void zfcp_dbf_set_common(struct zfcp_dbf_rec *rec, +				struct zfcp_adapter *adapter, +				struct zfcp_port *port, +				struct scsi_device *sdev)  { -	struct zfcp_adapter *adapter = dbf->adapter; - -	zfcp_dbf_rec_target(id, ref, dbf, &adapter->status, -			    &adapter->erp_counter, 0, 0, -			    ZFCP_DBF_INVALID_LUN); +	rec->adapter_status = atomic_read(&adapter->status); +	if (port) { +		rec->port_status = atomic_read(&port->status); +		rec->wwpn = port->wwpn; +		rec->d_id = port->d_id; +	} +	if (sdev) { +		rec->lun_status = atomic_read(&sdev_to_zfcp(sdev)->status); +		rec->lun = zfcp_scsi_dev_lun(sdev); +	}  }  /** - * zfcp_dbf_rec_port - trace event for port state change - * @id: identifier for trigger of state change - * @ref: additional reference (e.g. request) - * @port: port + * zfcp_dbf_rec_trig - trace event related to triggered recovery + * @tag: identifier for event + * @adapter: adapter on which the erp_action should run + * @port: remote port involved in the erp_action + * @sdev: scsi device involved in the erp_action + * @want: wanted erp_action + * @need: required erp_action + * + * The adapter->erp_lock has to be held.   */ -void zfcp_dbf_rec_port(char *id, void *ref, struct zfcp_port *port) +void zfcp_dbf_rec_trig(char *tag, struct zfcp_adapter *adapter, +		       struct zfcp_port *port, struct scsi_device *sdev, +		       u8 want, u8 need)  { -	struct zfcp_dbf *dbf = port->adapter->dbf; +	struct zfcp_dbf *dbf = adapter->dbf; +	struct zfcp_dbf_rec *rec = &dbf->rec_buf; +	struct list_head *entry; +	unsigned long flags; -	zfcp_dbf_rec_target(id, ref, dbf, &port->status, -			    &port->erp_counter, port->wwpn, port->d_id, -			    ZFCP_DBF_INVALID_LUN); -} +	spin_lock_irqsave(&dbf->rec_lock, flags); +	memset(rec, 0, sizeof(*rec)); -/** - * zfcp_dbf_rec_lun - trace event for LUN state change - * @id: identifier for trigger of state change - * @ref: additional reference (e.g. request) - * @sdev: SCSI device - */ -void zfcp_dbf_rec_lun(char *id, void *ref, struct scsi_device *sdev) -{ -	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); -	struct zfcp_port *port = zfcp_sdev->port; -	struct zfcp_dbf *dbf = port->adapter->dbf; +	rec->id = ZFCP_DBF_REC_TRIG; +	memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN); +	zfcp_dbf_set_common(rec, adapter, port, sdev); -	zfcp_dbf_rec_target(id, ref, dbf, &zfcp_sdev->status, -			    &zfcp_sdev->erp_counter, port->wwpn, port->d_id, -			    zfcp_scsi_dev_lun(sdev)); -} +	list_for_each(entry, &adapter->erp_ready_head) +		rec->u.trig.ready++; -/** - * zfcp_dbf_rec_trigger - trace event for triggered error recovery - * @id2: identifier for error recovery trigger - * @ref: additional reference (e.g. request) - * @want: originally requested error recovery action - * @need: error recovery action actually initiated - * @action: address of error recovery action struct - * @adapter: adapter - * @port: port - * @sdev: SCSI device - */ -void zfcp_dbf_rec_trigger(char *id2, void *ref, u8 want, u8 need, void *action, -			  struct zfcp_adapter *adapter, struct zfcp_port *port, -			  struct scsi_device *sdev) -{ -	struct zfcp_dbf *dbf = adapter->dbf; -	struct zfcp_dbf_rec_record *r = &dbf->rec_buf; -	unsigned long flags; +	list_for_each(entry, &adapter->erp_running_head) +		rec->u.trig.running++; -	spin_lock_irqsave(&dbf->rec_lock, flags); -	memset(r, 0, sizeof(*r)); -	r->id = ZFCP_REC_DBF_ID_TRIGGER; -	memcpy(r->id2, id2, ZFCP_DBF_ID_SIZE); -	r->u.trigger.ref = (unsigned long)ref; -	r->u.trigger.want = want; -	r->u.trigger.need = need; -	r->u.trigger.action = (unsigned long)action; -	r->u.trigger.as = atomic_read(&adapter->status); -	if (port) { -		r->u.trigger.ps = atomic_read(&port->status); -		r->u.trigger.wwpn = port->wwpn; -	} -	if (sdev) -		r->u.trigger.ls = atomic_read(&sdev_to_zfcp(sdev)->status); -	r->u.trigger.fcp_lun = sdev ? zfcp_scsi_dev_lun(sdev) : -				      ZFCP_DBF_INVALID_LUN; -	debug_event(dbf->rec, action ? 1 : 4, r, sizeof(*r)); +	rec->u.trig.want = want; +	rec->u.trig.need = need; + +	debug_event(dbf->rec, 1, rec, sizeof(*rec));  	spin_unlock_irqrestore(&dbf->rec_lock, flags);  } +  /** - * zfcp_dbf_rec_action - trace event showing progress of recovery action - * @id2: identifier - * @erp_action: error recovery action struct pointer + * zfcp_dbf_rec_run - trace event related to running recovery + * @tag: identifier for event + * @erp: erp_action running   */ -void zfcp_dbf_rec_action(char *id2, struct zfcp_erp_action *erp_action) +void zfcp_dbf_rec_run(char *tag, struct zfcp_erp_action *erp)  { -	struct zfcp_dbf *dbf = erp_action->adapter->dbf; -	struct zfcp_dbf_rec_record *r = &dbf->rec_buf; +	struct zfcp_dbf *dbf = erp->adapter->dbf; +	struct zfcp_dbf_rec *rec = &dbf->rec_buf;  	unsigned long flags;  	spin_lock_irqsave(&dbf->rec_lock, flags); -	memset(r, 0, sizeof(*r)); -	r->id = ZFCP_REC_DBF_ID_ACTION; -	memcpy(r->id2, id2, ZFCP_DBF_ID_SIZE); -	r->u.action.action = (unsigned long)erp_action; -	r->u.action.status = erp_action->status; -	r->u.action.step = erp_action->step; -	r->u.action.fsf_req = erp_action->fsf_req_id; -	debug_event(dbf->rec, 5, r, sizeof(*r)); -	spin_unlock_irqrestore(&dbf->rec_lock, flags); -} +	memset(rec, 0, sizeof(*rec)); -/** - * zfcp_dbf_san_ct_request - trace event for issued CT request - * @fsf_req: request containing issued CT data - * @d_id: destination id where ct request is sent to - */ -void zfcp_dbf_san_ct_request(struct zfcp_fsf_req *fsf_req, u32 d_id) -{ -	struct zfcp_fsf_ct_els *ct = (struct zfcp_fsf_ct_els *)fsf_req->data; -	struct zfcp_adapter *adapter = fsf_req->adapter; -	struct zfcp_dbf *dbf = adapter->dbf; -	struct fc_ct_hdr *hdr = sg_virt(ct->req); -	struct zfcp_dbf_san_record *r = &dbf->san_buf; -	struct zfcp_dbf_san_record_ct_request *oct = &r->u.ct_req; -	int level = 3; -	unsigned long flags; +	rec->id = ZFCP_DBF_REC_RUN; +	memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN); +	zfcp_dbf_set_common(rec, erp->adapter, erp->port, erp->sdev); -	spin_lock_irqsave(&dbf->san_lock, flags); -	memset(r, 0, sizeof(*r)); -	strncpy(r->tag, "octc", ZFCP_DBF_TAG_SIZE); -	r->fsf_reqid = fsf_req->req_id; -	r->fsf_seqno = fsf_req->seq_no; -	oct->d_id = d_id; -	oct->cmd_req_code = hdr->ct_cmd; -	oct->revision = hdr->ct_rev; -	oct->gs_type = hdr->ct_fs_type; -	oct->gs_subtype = hdr->ct_fs_subtype; -	oct->options = hdr->ct_options; -	oct->max_res_size = hdr->ct_mr_size; -	oct->len = min((int)ct->req->length - (int)sizeof(struct fc_ct_hdr), -		       ZFCP_DBF_SAN_MAX_PAYLOAD); -	debug_event(dbf->san, level, r, sizeof(*r)); -	zfcp_dbf_hexdump(dbf->san, r, sizeof(*r), level, -			 (void *)hdr + sizeof(struct fc_ct_hdr), oct->len); -	spin_unlock_irqrestore(&dbf->san_lock, flags); -} +	rec->u.run.fsf_req_id = erp->fsf_req_id; +	rec->u.run.rec_status = erp->status; +	rec->u.run.rec_step = erp->step; +	rec->u.run.rec_action = erp->action; -/** - * zfcp_dbf_san_ct_response - trace event for completion of CT request - * @fsf_req: request containing CT response - */ -void zfcp_dbf_san_ct_response(struct zfcp_fsf_req *fsf_req) -{ -	struct zfcp_fsf_ct_els *ct = (struct zfcp_fsf_ct_els *)fsf_req->data; -	struct zfcp_adapter *adapter = fsf_req->adapter; -	struct fc_ct_hdr *hdr = sg_virt(ct->resp); -	struct zfcp_dbf *dbf = adapter->dbf; -	struct zfcp_dbf_san_record *r = &dbf->san_buf; -	struct zfcp_dbf_san_record_ct_response *rct = &r->u.ct_resp; -	int level = 3; -	unsigned long flags; +	if (erp->sdev) +		rec->u.run.rec_count = +			atomic_read(&sdev_to_zfcp(erp->sdev)->erp_counter); +	else if (erp->port) +		rec->u.run.rec_count = atomic_read(&erp->port->erp_counter); +	else +		rec->u.run.rec_count = atomic_read(&erp->adapter->erp_counter); -	spin_lock_irqsave(&dbf->san_lock, flags); -	memset(r, 0, sizeof(*r)); -	strncpy(r->tag, "rctc", ZFCP_DBF_TAG_SIZE); -	r->fsf_reqid = fsf_req->req_id; -	r->fsf_seqno = fsf_req->seq_no; -	rct->cmd_rsp_code = hdr->ct_cmd; -	rct->revision = hdr->ct_rev; -	rct->reason_code = hdr->ct_reason; -	rct->expl = hdr->ct_explan; -	rct->vendor_unique = hdr->ct_vendor; -	rct->max_res_size = hdr->ct_mr_size; -	rct->len = min((int)ct->resp->length - (int)sizeof(struct fc_ct_hdr), -		       ZFCP_DBF_SAN_MAX_PAYLOAD); -	debug_event(dbf->san, level, r, sizeof(*r)); -	zfcp_dbf_hexdump(dbf->san, r, sizeof(*r), level, -			 (void *)hdr + sizeof(struct fc_ct_hdr), rct->len); -	spin_unlock_irqrestore(&dbf->san_lock, flags); +	debug_event(dbf->rec, 1, rec, sizeof(*rec)); +	spin_unlock_irqrestore(&dbf->rec_lock, flags);  } -static void zfcp_dbf_san_els(const char *tag, int level, -			     struct zfcp_fsf_req *fsf_req, u32 d_id, -			     void *buffer, int buflen) +static inline +void zfcp_dbf_san(char *tag, struct zfcp_dbf *dbf, void *data, u8 id, u16 len, +		  u64 req_id, u32 d_id)  { -	struct zfcp_adapter *adapter = fsf_req->adapter; -	struct zfcp_dbf *dbf = adapter->dbf; -	struct zfcp_dbf_san_record *rec = &dbf->san_buf; +	struct zfcp_dbf_san *rec = &dbf->san_buf; +	u16 rec_len;  	unsigned long flags;  	spin_lock_irqsave(&dbf->san_lock, flags);  	memset(rec, 0, sizeof(*rec)); -	strncpy(rec->tag, tag, ZFCP_DBF_TAG_SIZE); -	rec->fsf_reqid = fsf_req->req_id; -	rec->fsf_seqno = fsf_req->seq_no; -	rec->u.els.d_id = d_id; -	debug_event(dbf->san, level, rec, sizeof(*rec)); -	zfcp_dbf_hexdump(dbf->san, rec, sizeof(*rec), level, -			 buffer, min(buflen, ZFCP_DBF_SAN_MAX_PAYLOAD)); + +	rec->id = id; +	rec->fsf_req_id = req_id; +	rec->d_id = d_id; +	rec_len = min(len, (u16)ZFCP_DBF_SAN_MAX_PAYLOAD); +	memcpy(rec->payload, data, rec_len); +	memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN); + +	debug_event(dbf->san, 1, rec, sizeof(*rec));  	spin_unlock_irqrestore(&dbf->san_lock, flags);  }  /** - * zfcp_dbf_san_els_request - trace event for issued ELS - * @fsf_req: request containing issued ELS + * zfcp_dbf_san_req - trace event for issued SAN request + * @tag: identifier for event + * @fsf_req: request containing issued CT data + * d_id: destination ID   */ -void zfcp_dbf_san_els_request(struct zfcp_fsf_req *fsf_req) +void zfcp_dbf_san_req(char *tag, struct zfcp_fsf_req *fsf, u32 d_id)  { -	struct zfcp_fsf_ct_els *els = (struct zfcp_fsf_ct_els *)fsf_req->data; -	u32 d_id = ntoh24(fsf_req->qtcb->bottom.support.d_id); +	struct zfcp_dbf *dbf = fsf->adapter->dbf; +	struct zfcp_fsf_ct_els *ct_els = fsf->data; +	u16 length; -	zfcp_dbf_san_els("oels", 2, fsf_req, d_id, -			 sg_virt(els->req), els->req->length); +	length = (u16)(ct_els->req->length + FC_CT_HDR_LEN); +	zfcp_dbf_san(tag, dbf, sg_virt(ct_els->req), ZFCP_DBF_SAN_REQ, length, +		     fsf->req_id, d_id);  }  /** - * zfcp_dbf_san_els_response - trace event for completed ELS - * @fsf_req: request containing ELS response + * zfcp_dbf_san_res - trace event for received SAN request + * @tag: identifier for event + * @fsf_req: request containing issued CT data   */ -void zfcp_dbf_san_els_response(struct zfcp_fsf_req *fsf_req) +void zfcp_dbf_san_res(char *tag, struct zfcp_fsf_req *fsf)  { -	struct zfcp_fsf_ct_els *els = (struct zfcp_fsf_ct_els *)fsf_req->data; -	u32 d_id = ntoh24(fsf_req->qtcb->bottom.support.d_id); +	struct zfcp_dbf *dbf = fsf->adapter->dbf; +	struct zfcp_fsf_ct_els *ct_els = fsf->data; +	u16 length; -	zfcp_dbf_san_els("rels", 2, fsf_req, d_id, -			       sg_virt(els->resp), els->resp->length); +	length = (u16)(ct_els->resp->length + FC_CT_HDR_LEN); +	zfcp_dbf_san(tag, dbf, sg_virt(ct_els->resp), ZFCP_DBF_SAN_RES, length, +		     fsf->req_id, 0);  }  /** - * zfcp_dbf_san_incoming_els - trace event for incomig ELS - * @fsf_req: request containing unsolicited status buffer with incoming ELS + * zfcp_dbf_san_in_els - trace event for incoming ELS + * @tag: identifier for event + * @fsf_req: request containing issued CT data   */ -void zfcp_dbf_san_incoming_els(struct zfcp_fsf_req *fsf_req) +void zfcp_dbf_san_in_els(char *tag, struct zfcp_fsf_req *fsf)  { -	struct fsf_status_read_buffer *buf = -			(struct fsf_status_read_buffer *)fsf_req->data; -	int length = (int)buf->length - -		     (int)((void *)&buf->payload - (void *)buf); +	struct zfcp_dbf *dbf = fsf->adapter->dbf; +	struct fsf_status_read_buffer *srb = +		(struct fsf_status_read_buffer *) fsf->data; +	u16 length; -	zfcp_dbf_san_els("iels", 1, fsf_req, ntoh24(buf->d_id), -			       (void *)buf->payload.data, length); -} - -static int zfcp_dbf_san_view_format(debug_info_t *id, struct debug_view *view, -				    char *out_buf, const char *in_buf) -{ -	struct zfcp_dbf_san_record *r = (struct zfcp_dbf_san_record *)in_buf; -	char *p = out_buf; - -	if (strncmp(r->tag, "dump", ZFCP_DBF_TAG_SIZE) == 0) -		return 0; - -	zfcp_dbf_tag(&p, "tag", r->tag); -	zfcp_dbf_out(&p, "fsf_reqid", "0x%0Lx", r->fsf_reqid); -	zfcp_dbf_out(&p, "fsf_seqno", "0x%08x", r->fsf_seqno); - -	if (strncmp(r->tag, "octc", ZFCP_DBF_TAG_SIZE) == 0) { -		struct zfcp_dbf_san_record_ct_request *ct = &r->u.ct_req; -		zfcp_dbf_out(&p, "d_id", "0x%06x", ct->d_id); -		zfcp_dbf_out(&p, "cmd_req_code", "0x%04x", ct->cmd_req_code); -		zfcp_dbf_out(&p, "revision", "0x%02x", ct->revision); -		zfcp_dbf_out(&p, "gs_type", "0x%02x", ct->gs_type); -		zfcp_dbf_out(&p, "gs_subtype", "0x%02x", ct->gs_subtype); -		zfcp_dbf_out(&p, "options", "0x%02x", ct->options); -		zfcp_dbf_out(&p, "max_res_size", "0x%04x", ct->max_res_size); -	} else if (strncmp(r->tag, "rctc", ZFCP_DBF_TAG_SIZE) == 0) { -		struct zfcp_dbf_san_record_ct_response *ct = &r->u.ct_resp; -		zfcp_dbf_out(&p, "cmd_rsp_code", "0x%04x", ct->cmd_rsp_code); -		zfcp_dbf_out(&p, "revision", "0x%02x", ct->revision); -		zfcp_dbf_out(&p, "reason_code", "0x%02x", ct->reason_code); -		zfcp_dbf_out(&p, "reason_code_expl", "0x%02x", ct->expl); -		zfcp_dbf_out(&p, "vendor_unique", "0x%02x", ct->vendor_unique); -		zfcp_dbf_out(&p, "max_res_size", "0x%04x", ct->max_res_size); -	} else if (strncmp(r->tag, "oels", ZFCP_DBF_TAG_SIZE) == 0 || -		   strncmp(r->tag, "rels", ZFCP_DBF_TAG_SIZE) == 0 || -		   strncmp(r->tag, "iels", ZFCP_DBF_TAG_SIZE) == 0) { -		struct zfcp_dbf_san_record_els *els = &r->u.els; -		zfcp_dbf_out(&p, "d_id", "0x%06x", els->d_id); -	} -	return p - out_buf; +	length = (u16)(srb->length - +			offsetof(struct fsf_status_read_buffer, payload)); +	zfcp_dbf_san(tag, dbf, srb->payload.data, ZFCP_DBF_SAN_ELS, length, +		     fsf->req_id, ntoh24(srb->d_id));  } -static struct debug_view zfcp_dbf_san_view = { -	.name = "structured", -	.header_proc = zfcp_dbf_view_header, -	.format_proc = zfcp_dbf_san_view_format, -}; - -void _zfcp_dbf_scsi(const char *tag, const char *tag2, int level, -		    struct zfcp_dbf *dbf, struct scsi_cmnd *scsi_cmnd, -		    struct zfcp_fsf_req *fsf_req, unsigned long old_req_id) +/** + * zfcp_dbf_scsi - trace event for scsi commands + * @tag: identifier for event + * @sc: pointer to struct scsi_cmnd + * @fsf: pointer to struct zfcp_fsf_req + */ +void zfcp_dbf_scsi(char *tag, struct scsi_cmnd *sc, struct zfcp_fsf_req *fsf)  { -	struct zfcp_dbf_scsi_record *rec = &dbf->scsi_buf; -	struct zfcp_dbf_dump *dump = (struct zfcp_dbf_dump *)rec; -	unsigned long flags; +	struct zfcp_adapter *adapter = +		(struct zfcp_adapter *) sc->device->host->hostdata[0]; +	struct zfcp_dbf *dbf = adapter->dbf; +	struct zfcp_dbf_scsi *rec = &dbf->scsi_buf;  	struct fcp_resp_with_ext *fcp_rsp; -	struct fcp_resp_rsp_info *fcp_rsp_info = NULL; -	char *fcp_sns_info = NULL; -	int offset = 0, buflen = 0; +	struct fcp_resp_rsp_info *fcp_rsp_info; +	unsigned long flags;  	spin_lock_irqsave(&dbf->scsi_lock, flags); -	do { -		memset(rec, 0, sizeof(*rec)); -		if (offset == 0) { -			strncpy(rec->tag, tag, ZFCP_DBF_TAG_SIZE); -			strncpy(rec->tag2, tag2, ZFCP_DBF_TAG_SIZE); -			if (scsi_cmnd != NULL) { -				if (scsi_cmnd->device) { -					rec->scsi_id = scsi_cmnd->device->id; -					rec->scsi_lun = scsi_cmnd->device->lun; -				} -				rec->scsi_result = scsi_cmnd->result; -				rec->scsi_cmnd = (unsigned long)scsi_cmnd; -				memcpy(rec->scsi_opcode, scsi_cmnd->cmnd, -					min((int)scsi_cmnd->cmd_len, -						ZFCP_DBF_SCSI_OPCODE)); -				rec->scsi_retries = scsi_cmnd->retries; -				rec->scsi_allowed = scsi_cmnd->allowed; -			} -			if (fsf_req != NULL) { -				fcp_rsp = (struct fcp_resp_with_ext *) -					&(fsf_req->qtcb->bottom.io.fcp_rsp); -				fcp_rsp_info = (struct fcp_resp_rsp_info *) -					&fcp_rsp[1]; -				fcp_sns_info = (char *) &fcp_rsp[1]; -				if (fcp_rsp->resp.fr_flags & FCP_RSP_LEN_VAL) -					fcp_sns_info += fcp_rsp->ext.fr_sns_len; - -				rec->rsp_validity = fcp_rsp->resp.fr_flags; -				rec->rsp_scsi_status = fcp_rsp->resp.fr_status; -				rec->rsp_resid = fcp_rsp->ext.fr_resid; -				if (fcp_rsp->resp.fr_flags & FCP_RSP_LEN_VAL) -					rec->rsp_code = fcp_rsp_info->rsp_code; -				if (fcp_rsp->resp.fr_flags & FCP_SNS_LEN_VAL) { -					buflen = min(fcp_rsp->ext.fr_sns_len, -					   (u32)ZFCP_DBF_SCSI_MAX_FCP_SNS_INFO); -					rec->sns_info_len = buflen; -					memcpy(rec->sns_info, fcp_sns_info, -					       min(buflen, -						   ZFCP_DBF_SCSI_FCP_SNS_INFO)); -					offset += min(buflen, -						      ZFCP_DBF_SCSI_FCP_SNS_INFO); -				} - -				rec->fsf_reqid = fsf_req->req_id; -				rec->fsf_seqno = fsf_req->seq_no; -				rec->fsf_issued = fsf_req->issued; -			} -			rec->old_fsf_reqid = old_req_id; -		} else { -			strncpy(dump->tag, "dump", ZFCP_DBF_TAG_SIZE); -			dump->total_size = buflen; -			dump->offset = offset; -			dump->size = min(buflen - offset, -					 (int)sizeof(struct -						     zfcp_dbf_scsi_record) - -					 (int)sizeof(struct zfcp_dbf_dump)); -			memcpy(dump->data, fcp_sns_info + offset, dump->size); -			offset += dump->size; -		} -		debug_event(dbf->scsi, level, rec, sizeof(*rec)); -	} while (offset < buflen); -	spin_unlock_irqrestore(&dbf->scsi_lock, flags); -} +	memset(rec, 0, sizeof(*rec)); -static int zfcp_dbf_scsi_view_format(debug_info_t *id, struct debug_view *view, -				     char *out_buf, const char *in_buf) -{ -	struct zfcp_dbf_scsi_record *r = (struct zfcp_dbf_scsi_record *)in_buf; -	struct timespec t; -	char *p = out_buf; - -	if (strncmp(r->tag, "dump", ZFCP_DBF_TAG_SIZE) == 0) -		return 0; - -	zfcp_dbf_tag(&p, "tag", r->tag); -	zfcp_dbf_tag(&p, "tag2", r->tag2); -	zfcp_dbf_out(&p, "scsi_id", "0x%08x", r->scsi_id); -	zfcp_dbf_out(&p, "scsi_lun", "0x%08x", r->scsi_lun); -	zfcp_dbf_out(&p, "scsi_result", "0x%08x", r->scsi_result); -	zfcp_dbf_out(&p, "scsi_cmnd", "0x%0Lx", r->scsi_cmnd); -	zfcp_dbf_outd(&p, "scsi_opcode", r->scsi_opcode, ZFCP_DBF_SCSI_OPCODE, -		      0, ZFCP_DBF_SCSI_OPCODE); -	zfcp_dbf_out(&p, "scsi_retries", "0x%02x", r->scsi_retries); -	zfcp_dbf_out(&p, "scsi_allowed", "0x%02x", r->scsi_allowed); -	if (strncmp(r->tag, "abrt", ZFCP_DBF_TAG_SIZE) == 0) -		zfcp_dbf_out(&p, "old_fsf_reqid", "0x%0Lx", r->old_fsf_reqid); -	zfcp_dbf_out(&p, "fsf_reqid", "0x%0Lx", r->fsf_reqid); -	zfcp_dbf_out(&p, "fsf_seqno", "0x%08x", r->fsf_seqno); -	stck_to_timespec(r->fsf_issued, &t); -	zfcp_dbf_out(&p, "fsf_issued", "%011lu:%06lu", t.tv_sec, t.tv_nsec); - -	if (strncmp(r->tag, "rslt", ZFCP_DBF_TAG_SIZE) == 0) { -		zfcp_dbf_out(&p, "fcp_rsp_validity", "0x%02x", r->rsp_validity); -		zfcp_dbf_out(&p, "fcp_rsp_scsi_status", "0x%02x", -			     r->rsp_scsi_status); -		zfcp_dbf_out(&p, "fcp_rsp_resid", "0x%08x", r->rsp_resid); -		zfcp_dbf_out(&p, "fcp_rsp_code", "0x%08x", r->rsp_code); -		zfcp_dbf_out(&p, "fcp_sns_info_len", "0x%08x", r->sns_info_len); -		zfcp_dbf_outd(&p, "fcp_sns_info", r->sns_info, -			      min((int)r->sns_info_len, -			      ZFCP_DBF_SCSI_FCP_SNS_INFO), 0, -			      r->sns_info_len); +	memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN); +	rec->id = ZFCP_DBF_SCSI_CMND; +	rec->scsi_result = sc->result; +	rec->scsi_retries = sc->retries; +	rec->scsi_allowed = sc->allowed; +	rec->scsi_id = sc->device->id; +	rec->scsi_lun = sc->device->lun; +	rec->host_scribble = (unsigned long)sc->host_scribble; + +	memcpy(rec->scsi_opcode, sc->cmnd, +	       min((int)sc->cmd_len, ZFCP_DBF_SCSI_OPCODE)); + +	if (fsf) { +		rec->fsf_req_id = fsf->req_id; +		fcp_rsp = (struct fcp_resp_with_ext *) +				&(fsf->qtcb->bottom.io.fcp_rsp); +		memcpy(&rec->fcp_rsp, fcp_rsp, FCP_RESP_WITH_EXT); +		if (fcp_rsp->resp.fr_flags & FCP_RSP_LEN_VAL) { +			fcp_rsp_info = (struct fcp_resp_rsp_info *) &fcp_rsp[1]; +			rec->fcp_rsp_info = fcp_rsp_info->rsp_code; +		} +		if (fcp_rsp->resp.fr_flags & FCP_SNS_LEN_VAL) { +			rec->pl_len = min((u16)SCSI_SENSE_BUFFERSIZE, +					  (u16)ZFCP_DBF_PAY_MAX_REC); +			zfcp_dbf_pl_write(dbf, sc->sense_buffer, rec->pl_len, +					  "fcp_sns", fsf->req_id); +		}  	} -	p += sprintf(p, "\n"); -	return p - out_buf; -} -static struct debug_view zfcp_dbf_scsi_view = { -	.name = "structured", -	.header_proc = zfcp_dbf_view_header, -	.format_proc = zfcp_dbf_scsi_view_format, -}; +	debug_event(dbf->scsi, 1, rec, sizeof(*rec)); +	spin_unlock_irqrestore(&dbf->scsi_lock, flags); +} -static debug_info_t *zfcp_dbf_reg(const char *name, int level, -				  struct debug_view *view, int size) +static debug_info_t *zfcp_dbf_reg(const char *name, int size, int rec_size)  {  	struct debug_info *d; -	d = debug_register(name, dbfsize, level, size); +	d = debug_register(name, size, 1, rec_size);  	if (!d)  		return NULL;  	debug_register_view(d, &debug_hex_ascii_view); -	debug_register_view(d, view); -	debug_set_level(d, level); +	debug_set_level(d, dbflevel);  	return d;  } +static void zfcp_dbf_unregister(struct zfcp_dbf *dbf) +{ +	if (!dbf) +		return; + +	debug_unregister(dbf->scsi); +	debug_unregister(dbf->san); +	debug_unregister(dbf->hba); +	debug_unregister(dbf->pay); +	debug_unregister(dbf->rec); +	kfree(dbf); +} +  /**   * zfcp_adapter_debug_register - registers debug feature for an adapter   * @adapter: pointer to adapter for which debug features should be registered @@ -1003,69 +479,66 @@ static debug_info_t *zfcp_dbf_reg(const char *name, int level,   */  int zfcp_dbf_adapter_register(struct zfcp_adapter *adapter)  { -	char dbf_name[DEBUG_MAX_NAME_LEN]; +	char name[DEBUG_MAX_NAME_LEN];  	struct zfcp_dbf *dbf;  	dbf = kzalloc(sizeof(struct zfcp_dbf), GFP_KERNEL);  	if (!dbf)  		return -ENOMEM; -	dbf->adapter = adapter; - +	spin_lock_init(&dbf->pay_lock);  	spin_lock_init(&dbf->hba_lock);  	spin_lock_init(&dbf->san_lock);  	spin_lock_init(&dbf->scsi_lock);  	spin_lock_init(&dbf->rec_lock);  	/* debug feature area which records recovery activity */ -	sprintf(dbf_name, "zfcp_%s_rec", dev_name(&adapter->ccw_device->dev)); -	dbf->rec = zfcp_dbf_reg(dbf_name, 3, &zfcp_dbf_rec_view, -				sizeof(struct zfcp_dbf_rec_record)); +	sprintf(name, "zfcp_%s_rec", dev_name(&adapter->ccw_device->dev)); +	dbf->rec = zfcp_dbf_reg(name, dbfsize, sizeof(struct zfcp_dbf_rec));  	if (!dbf->rec)  		goto err_out;  	/* debug feature area which records HBA (FSF and QDIO) conditions */ -	sprintf(dbf_name, "zfcp_%s_hba", dev_name(&adapter->ccw_device->dev)); -	dbf->hba = zfcp_dbf_reg(dbf_name, 3, &zfcp_dbf_hba_view, -				sizeof(struct zfcp_dbf_hba_record)); +	sprintf(name, "zfcp_%s_hba", dev_name(&adapter->ccw_device->dev)); +	dbf->hba = zfcp_dbf_reg(name, dbfsize, sizeof(struct zfcp_dbf_hba));  	if (!dbf->hba)  		goto err_out; +	/* debug feature area which records payload info */ +	sprintf(name, "zfcp_%s_pay", dev_name(&adapter->ccw_device->dev)); +	dbf->pay = zfcp_dbf_reg(name, dbfsize * 2, sizeof(struct zfcp_dbf_pay)); +	if (!dbf->pay) +		goto err_out; +  	/* debug feature area which records SAN command failures and recovery */ -	sprintf(dbf_name, "zfcp_%s_san", dev_name(&adapter->ccw_device->dev)); -	dbf->san = zfcp_dbf_reg(dbf_name, 6, &zfcp_dbf_san_view, -				sizeof(struct zfcp_dbf_san_record)); +	sprintf(name, "zfcp_%s_san", dev_name(&adapter->ccw_device->dev)); +	dbf->san = zfcp_dbf_reg(name, dbfsize, sizeof(struct zfcp_dbf_san));  	if (!dbf->san)  		goto err_out;  	/* debug feature area which records SCSI command failures and recovery */ -	sprintf(dbf_name, "zfcp_%s_scsi", dev_name(&adapter->ccw_device->dev)); -	dbf->scsi = zfcp_dbf_reg(dbf_name, 3, &zfcp_dbf_scsi_view, -				 sizeof(struct zfcp_dbf_scsi_record)); +	sprintf(name, "zfcp_%s_scsi", dev_name(&adapter->ccw_device->dev)); +	dbf->scsi = zfcp_dbf_reg(name, dbfsize, sizeof(struct zfcp_dbf_scsi));  	if (!dbf->scsi)  		goto err_out;  	adapter->dbf = dbf; -	return 0; +	return 0;  err_out: -	zfcp_dbf_adapter_unregister(dbf); +	zfcp_dbf_unregister(dbf);  	return -ENOMEM;  }  /**   * zfcp_adapter_debug_unregister - unregisters debug feature for an adapter - * @dbf: pointer to dbf for which debug features should be unregistered + * @adapter: pointer to adapter for which debug features should be unregistered   */ -void zfcp_dbf_adapter_unregister(struct zfcp_dbf *dbf) +void zfcp_dbf_adapter_unregister(struct zfcp_adapter *adapter)  { -	if (!dbf) -		return; -	debug_unregister(dbf->scsi); -	debug_unregister(dbf->san); -	debug_unregister(dbf->hba); -	debug_unregister(dbf->rec); -	dbf->adapter->dbf = NULL; -	kfree(dbf); +	struct zfcp_dbf *dbf = adapter->dbf; + +	adapter->dbf = NULL; +	zfcp_dbf_unregister(dbf);  } diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h index 04081b1b62b..0be3d48681a 100644 --- a/drivers/s390/scsi/zfcp_dbf.h +++ b/drivers/s390/scsi/zfcp_dbf.h @@ -1,22 +1,8 @@  /* - * This file is part of the zfcp device driver for - * FCP adapters for IBM System z9 and zSeries. + * zfcp device driver + * debug feature declarations   * - * Copyright IBM Corp. 2008, 2009 - * - * 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 Corp. 2008, 2010   */  #ifndef ZFCP_DBF_H @@ -27,322 +13,351 @@  #include "zfcp_fsf.h"  #include "zfcp_def.h" -#define ZFCP_DBF_TAG_SIZE      4 -#define ZFCP_DBF_ID_SIZE       7 +#define ZFCP_DBF_TAG_LEN       7  #define ZFCP_DBF_INVALID_LUN	0xFFFFFFFFFFFFFFFFull -struct zfcp_dbf_dump { -	u8 tag[ZFCP_DBF_TAG_SIZE]; -	u32 total_size;		/* size of total dump data */ -	u32 offset;		/* how much data has being already dumped */ -	u32 size;		/* how much data comes with this record */ -	u8 data[];		/* dump data */ -} __attribute__ ((packed)); - -struct zfcp_dbf_rec_record_thread { -	u32 total; +/** + * struct zfcp_dbf_rec_trigger - trace record for triggered recovery action + * @ready: number of ready recovery actions + * @running: number of running recovery actions + * @want: wanted recovery action + * @need: needed recovery action + */ +struct zfcp_dbf_rec_trigger {  	u32 ready;  	u32 running; -}; - -struct zfcp_dbf_rec_record_target { -	u64 ref; -	u32 status; -	u32 d_id; -	u64 wwpn; -	u64 fcp_lun; -	u32 erp_count; -}; - -struct zfcp_dbf_rec_record_trigger {  	u8 want;  	u8 need; -	u32 as; -	u32 ps; -	u32 ls; -	u64 ref; -	u64 action; -	u64 wwpn; -	u64 fcp_lun; -}; +} __packed; -struct zfcp_dbf_rec_record_action { -	u32 status; -	u32 step; -	u64 action; -	u64 fsf_req; +/** + * struct zfcp_dbf_rec_running - trace record for running recovery + * @fsf_req_id: request id for fsf requests + * @rec_status: status of the fsf request + * @rec_step: current step of the recovery action + * rec_count: recovery counter + */ +struct zfcp_dbf_rec_running { +	u64 fsf_req_id; +	u32 rec_status; +	u16 rec_step; +	u8 rec_action; +	u8 rec_count; +} __packed; + +/** + * enum zfcp_dbf_rec_id - recovery trace record id + * @ZFCP_DBF_REC_TRIG: triggered recovery identifier + * @ZFCP_DBF_REC_RUN: running recovery identifier + */ +enum zfcp_dbf_rec_id { +	ZFCP_DBF_REC_TRIG	= 1, +	ZFCP_DBF_REC_RUN	= 2,  }; -struct zfcp_dbf_rec_record { +/** + * struct zfcp_dbf_rec - trace record for error recovery actions + * @id: unique number of recovery record type + * @tag: identifier string specifying the location of initiation + * @lun: logical unit number + * @wwpn: word wide port number + * @d_id: destination ID + * @adapter_status: current status of the adapter + * @port_status: current status of the port + * @lun_status: current status of the lun + * @u.trig: structure zfcp_dbf_rec_trigger + * @u.run: structure zfcp_dbf_rec_running + */ +struct zfcp_dbf_rec {  	u8 id; -	char id2[7]; +	char tag[ZFCP_DBF_TAG_LEN]; +	u64 lun; +	u64 wwpn; +	u32 d_id; +	u32 adapter_status; +	u32 port_status; +	u32 lun_status;  	union { -		struct zfcp_dbf_rec_record_action action; -		struct zfcp_dbf_rec_record_thread thread; -		struct zfcp_dbf_rec_record_target target; -		struct zfcp_dbf_rec_record_trigger trigger; +		struct zfcp_dbf_rec_trigger trig; +		struct zfcp_dbf_rec_running run;  	} u; -}; +} __packed; -enum { -	ZFCP_REC_DBF_ID_ACTION, -	ZFCP_REC_DBF_ID_THREAD, -	ZFCP_REC_DBF_ID_TARGET, -	ZFCP_REC_DBF_ID_TRIGGER, +/** + * enum zfcp_dbf_san_id - SAN trace record identifier + * @ZFCP_DBF_SAN_REQ: request trace record id + * @ZFCP_DBF_SAN_RES: response trace record id + * @ZFCP_DBF_SAN_ELS: extended link service record id + */ +enum zfcp_dbf_san_id { +	ZFCP_DBF_SAN_REQ	= 1, +	ZFCP_DBF_SAN_RES	= 2, +	ZFCP_DBF_SAN_ELS	= 3,  }; -struct zfcp_dbf_hba_record_response { -	u32 fsf_command; -	u64 fsf_reqid; -	u32 fsf_seqno; -	u64 fsf_issued; -	u32 fsf_prot_status; +/** struct zfcp_dbf_san - trace record for SAN requests and responses + * @id: unique number of recovery record type + * @tag: identifier string specifying the location of initiation + * @fsf_req_id: request id for fsf requests + * @payload: unformatted information related to request/response + * @d_id: destination id + */ +struct zfcp_dbf_san { +	u8 id; +	char tag[ZFCP_DBF_TAG_LEN]; +	u64 fsf_req_id; +	u32 d_id; +#define ZFCP_DBF_SAN_MAX_PAYLOAD (FC_CT_HDR_LEN + 32) +	char payload[ZFCP_DBF_SAN_MAX_PAYLOAD]; +} __packed; + +/** + * struct zfcp_dbf_hba_res - trace record for hba responses + * @req_issued: timestamp when request was issued + * @prot_status: protocol status + * @prot_status_qual: protocol status qualifier + * @fsf_status: fsf status + * @fsf_status_qual: fsf status qualifier + */ +struct zfcp_dbf_hba_res { +	u64 req_issued; +	u32 prot_status; +	u8  prot_status_qual[FSF_PROT_STATUS_QUAL_SIZE];  	u32 fsf_status; -	u8 fsf_prot_status_qual[FSF_PROT_STATUS_QUAL_SIZE]; -	u8 fsf_status_qual[FSF_STATUS_QUALIFIER_SIZE]; -	u32 fsf_req_status; -	u8 sbal_first; -	u8 sbal_last; -	u8 sbal_response; -	u8 pool; -	u64 erp_action; -	union { -		struct { -			u64 cmnd; -			u32 data_dir; -		} fcp; -		struct { -			u64 wwpn; -			u32 d_id; -			u32 port_handle; -		} port; -		struct { -			u64 wwpn; -			u64 fcp_lun; -			u32 port_handle; -			u32 lun_handle; -		} unit; -		struct { -			u32 d_id; -		} els; -	} u; -} __attribute__ ((packed)); +	u8  fsf_status_qual[FSF_STATUS_QUALIFIER_SIZE]; +} __packed; -struct zfcp_dbf_hba_record_status { -	u8 failed; +/** + * struct zfcp_dbf_hba_uss - trace record for unsolicited status + * @status_type: type of unsolicited status + * @status_subtype: subtype of unsolicited status + * @d_id: destination ID + * @lun: logical unit number + * @queue_designator: queue designator + */ +struct zfcp_dbf_hba_uss {  	u32 status_type;  	u32 status_subtype; -	struct fsf_queue_designator -	 queue_designator; -	u32 payload_size; -#define ZFCP_DBF_UNSOL_PAYLOAD				80 -#define ZFCP_DBF_UNSOL_PAYLOAD_SENSE_DATA_AVAIL		32 -#define ZFCP_DBF_UNSOL_PAYLOAD_BIT_ERROR_THRESHOLD	56 -#define ZFCP_DBF_UNSOL_PAYLOAD_FEATURE_UPDATE_ALERT	2 * sizeof(u32) -	u8 payload[ZFCP_DBF_UNSOL_PAYLOAD]; -} __attribute__ ((packed)); - -struct zfcp_dbf_hba_record_qdio { -	u32 qdio_error; -	u8 sbal_index; -	u8 sbal_count; -} __attribute__ ((packed)); - -struct zfcp_dbf_hba_record { -	u8 tag[ZFCP_DBF_TAG_SIZE]; -	u8 tag2[ZFCP_DBF_TAG_SIZE]; -	union { -		struct zfcp_dbf_hba_record_response response; -		struct zfcp_dbf_hba_record_status status; -		struct zfcp_dbf_hba_record_qdio qdio; -		struct fsf_bit_error_payload berr; -	} u; -} __attribute__ ((packed)); - -struct zfcp_dbf_san_record_ct_request { -	u16 cmd_req_code; -	u8 revision; -	u8 gs_type; -	u8 gs_subtype; -	u8 options; -	u16 max_res_size; -	u32 len; -	u32 d_id; -} __attribute__ ((packed)); - -struct zfcp_dbf_san_record_ct_response { -	u16 cmd_rsp_code; -	u8 revision; -	u8 reason_code; -	u8 expl; -	u8 vendor_unique; -	u16 max_res_size; -	u32 len; -} __attribute__ ((packed)); - -struct zfcp_dbf_san_record_els {  	u32 d_id; -} __attribute__ ((packed)); +	u64 lun; +	u64 queue_designator; +} __packed; -struct zfcp_dbf_san_record { -	u8 tag[ZFCP_DBF_TAG_SIZE]; -	u64 fsf_reqid; -	u32 fsf_seqno; +/** + * enum zfcp_dbf_hba_id - HBA trace record identifier + * @ZFCP_DBF_HBA_RES: response trace record + * @ZFCP_DBF_HBA_USS: unsolicited status trace record + * @ZFCP_DBF_HBA_BIT: bit error trace record + */ +enum zfcp_dbf_hba_id { +	ZFCP_DBF_HBA_RES	= 1, +	ZFCP_DBF_HBA_USS	= 2, +	ZFCP_DBF_HBA_BIT	= 3, +	ZFCP_DBF_HBA_BASIC	= 4, +}; + +/** + * struct zfcp_dbf_hba - common trace record for HBA records + * @id: unique number of recovery record type + * @tag: identifier string specifying the location of initiation + * @fsf_req_id: request id for fsf requests + * @fsf_req_status: status of fsf request + * @fsf_cmd: fsf command + * @fsf_seq_no: fsf sequence number + * @pl_len: length of payload stored as zfcp_dbf_pay + * @u: record type specific data + */ +struct zfcp_dbf_hba { +	u8 id; +	char tag[ZFCP_DBF_TAG_LEN]; +	u64 fsf_req_id; +	u32 fsf_req_status; +	u32 fsf_cmd; +	u32 fsf_seq_no; +	u16 pl_len;  	union { -		struct zfcp_dbf_san_record_ct_request ct_req; -		struct zfcp_dbf_san_record_ct_response ct_resp; -		struct zfcp_dbf_san_record_els els; +		struct zfcp_dbf_hba_res res; +		struct zfcp_dbf_hba_uss uss; +		struct fsf_bit_error_payload be;  	} u; -} __attribute__ ((packed)); +} __packed; -#define ZFCP_DBF_SAN_MAX_PAYLOAD 1024 +/** + * enum zfcp_dbf_scsi_id - scsi trace record identifier + * @ZFCP_DBF_SCSI_CMND: scsi command trace record + */ +enum zfcp_dbf_scsi_id { +	ZFCP_DBF_SCSI_CMND	= 1, +}; -struct zfcp_dbf_scsi_record { -	u8 tag[ZFCP_DBF_TAG_SIZE]; -	u8 tag2[ZFCP_DBF_TAG_SIZE]; +/** + * struct zfcp_dbf_scsi - common trace record for SCSI records + * @id: unique number of recovery record type + * @tag: identifier string specifying the location of initiation + * @scsi_id: scsi device id + * @scsi_lun: scsi device logical unit number + * @scsi_result: scsi result + * @scsi_retries: current retry number of scsi request + * @scsi_allowed: allowed retries + * @fcp_rsp_info: FCP response info + * @scsi_opcode: scsi opcode + * @fsf_req_id: request id of fsf request + * @host_scribble: LLD specific data attached to SCSI request + * @pl_len: length of paload stored as zfcp_dbf_pay + * @fsf_rsp: response for fsf request + */ +struct zfcp_dbf_scsi { +	u8 id; +	char tag[ZFCP_DBF_TAG_LEN];  	u32 scsi_id;  	u32 scsi_lun;  	u32 scsi_result; -	u64 scsi_cmnd; -#define ZFCP_DBF_SCSI_OPCODE	16 -	u8 scsi_opcode[ZFCP_DBF_SCSI_OPCODE];  	u8 scsi_retries;  	u8 scsi_allowed; -	u64 fsf_reqid; -	u32 fsf_seqno; -	u64 fsf_issued; -	u64 old_fsf_reqid; -	u8 rsp_validity; -	u8 rsp_scsi_status; -	u32 rsp_resid; -	u8 rsp_code; -#define ZFCP_DBF_SCSI_FCP_SNS_INFO	16 -#define ZFCP_DBF_SCSI_MAX_FCP_SNS_INFO	256 -	u32 sns_info_len; -	u8 sns_info[ZFCP_DBF_SCSI_FCP_SNS_INFO]; -} __attribute__ ((packed)); +	u8 fcp_rsp_info; +#define ZFCP_DBF_SCSI_OPCODE	16 +	u8 scsi_opcode[ZFCP_DBF_SCSI_OPCODE]; +	u64 fsf_req_id; +	u64 host_scribble; +	u16 pl_len; +	struct fcp_resp_with_ext fcp_rsp; +} __packed; +/** + * struct zfcp_dbf_pay - trace record for unformatted payload information + * @area: area this record is originated from + * @counter: ascending record number + * @fsf_req_id: request id of fsf request + * @data: unformatted data + */ +struct zfcp_dbf_pay { +	u8 counter; +	char area[ZFCP_DBF_TAG_LEN]; +	u64 fsf_req_id; +#define ZFCP_DBF_PAY_MAX_REC 0x100 +	char data[ZFCP_DBF_PAY_MAX_REC]; +} __packed; + +/** + * struct zfcp_dbf - main dbf trace structure + * @pay: reference to payload trace area + * @rec: reference to recovery trace area + * @hba: reference to hba trace area + * @san: reference to san trace area + * @scsi: reference to scsi trace area + * @pay_lock: lock protecting payload trace buffer + * @rec_lock: lock protecting recovery trace buffer + * @hba_lock: lock protecting hba trace buffer + * @san_lock: lock protecting san trace buffer + * @scsi_lock: lock protecting scsi trace buffer + * @pay_buf: pre-allocated buffer for payload + * @rec_buf: pre-allocated buffer for recovery + * @hba_buf: pre-allocated buffer for hba + * @san_buf: pre-allocated buffer for san + * @scsi_buf: pre-allocated buffer for scsi + */  struct zfcp_dbf { +	debug_info_t			*pay;  	debug_info_t			*rec;  	debug_info_t			*hba;  	debug_info_t			*san;  	debug_info_t			*scsi; +	spinlock_t			pay_lock;  	spinlock_t			rec_lock;  	spinlock_t			hba_lock;  	spinlock_t			san_lock;  	spinlock_t			scsi_lock; -	struct zfcp_dbf_rec_record	rec_buf; -	struct zfcp_dbf_hba_record	hba_buf; -	struct zfcp_dbf_san_record	san_buf; -	struct zfcp_dbf_scsi_record	scsi_buf; -	struct zfcp_adapter		*adapter; +	struct zfcp_dbf_pay		pay_buf; +	struct zfcp_dbf_rec		rec_buf; +	struct zfcp_dbf_hba		hba_buf; +	struct zfcp_dbf_san		san_buf; +	struct zfcp_dbf_scsi		scsi_buf;  };  static inline -void zfcp_dbf_hba_fsf_resp(const char *tag2, int level, -			   struct zfcp_fsf_req *req, struct zfcp_dbf *dbf) +void zfcp_dbf_hba_fsf_resp(char *tag, int level, struct zfcp_fsf_req *req)  { -	if (level <= dbf->hba->level) -		_zfcp_dbf_hba_fsf_response(tag2, level, req, dbf); +	if (debug_level_enabled(req->adapter->dbf->hba, level)) +		zfcp_dbf_hba_fsf_res(tag, req);  }  /**   * zfcp_dbf_hba_fsf_response - trace event for request completion - * @fsf_req: request that has been completed + * @req: request that has been completed   */ -static inline void zfcp_dbf_hba_fsf_response(struct zfcp_fsf_req *req) +static inline +void zfcp_dbf_hba_fsf_response(struct zfcp_fsf_req *req)  { -	struct zfcp_dbf *dbf = req->adapter->dbf;  	struct fsf_qtcb *qtcb = req->qtcb;  	if ((qtcb->prefix.prot_status != FSF_PROT_GOOD) &&  	    (qtcb->prefix.prot_status != FSF_PROT_FSF_STATUS_PRESENTED)) { -		zfcp_dbf_hba_fsf_resp("perr", 1, req, dbf); +		zfcp_dbf_hba_fsf_resp("fs_perr", 1, req);  	} else if (qtcb->header.fsf_status != FSF_GOOD) { -		zfcp_dbf_hba_fsf_resp("ferr", 1, req, dbf); +		zfcp_dbf_hba_fsf_resp("fs_ferr", 1, req);  	} else if ((req->fsf_command == FSF_QTCB_OPEN_PORT_WITH_DID) ||  		   (req->fsf_command == FSF_QTCB_OPEN_LUN)) { -		zfcp_dbf_hba_fsf_resp("open", 4, req, dbf); +		zfcp_dbf_hba_fsf_resp("fs_open", 4, req);  	} else if (qtcb->header.log_length) { -		zfcp_dbf_hba_fsf_resp("qtcb", 5, req, dbf); +		zfcp_dbf_hba_fsf_resp("fs_qtcb", 5, req);  	} else { -		zfcp_dbf_hba_fsf_resp("norm", 6, req, dbf); +		zfcp_dbf_hba_fsf_resp("fs_norm", 6, req);  	} - } - -/** - * zfcp_dbf_hba_fsf_unsol - trace event for an unsolicited status buffer - * @tag: tag indicating which kind of unsolicited status has been received - * @dbf: reference to dbf structure - * @status_buffer: buffer containing payload of unsolicited status - */ -static inline -void zfcp_dbf_hba_fsf_unsol(const char *tag, struct zfcp_dbf *dbf, -			    struct fsf_status_read_buffer *buf) -{ -	int level = 2; - -	if (level <= dbf->hba->level) -		_zfcp_dbf_hba_fsf_unsol(tag, level, dbf, buf);  }  static inline -void zfcp_dbf_scsi(const char *tag, const char *tag2, int level, -		   struct zfcp_dbf *dbf, struct scsi_cmnd *scmd, -		   struct zfcp_fsf_req *req, unsigned long old_id) +void _zfcp_dbf_scsi(char *tag, int level, struct scsi_cmnd *scmd, +		   struct zfcp_fsf_req *req)  { -	if (level <= dbf->scsi->level) -		_zfcp_dbf_scsi(tag, tag2, level, dbf, scmd, req, old_id); +	struct zfcp_adapter *adapter = (struct zfcp_adapter *) +					scmd->device->host->hostdata[0]; + +	if (debug_level_enabled(adapter->dbf->scsi, level)) +		zfcp_dbf_scsi(tag, scmd, req);  }  /**   * zfcp_dbf_scsi_result - trace event for SCSI command completion - * @dbf: adapter dbf trace   * @scmd: SCSI command pointer   * @req: FSF request used to issue SCSI command   */  static inline -void zfcp_dbf_scsi_result(struct zfcp_dbf *dbf, struct scsi_cmnd *scmd, -			  struct zfcp_fsf_req *req) +void zfcp_dbf_scsi_result(struct scsi_cmnd *scmd, struct zfcp_fsf_req *req)  {  	if (scmd->result != 0) -		zfcp_dbf_scsi("rslt", "erro", 3, dbf, scmd, req, 0); +		_zfcp_dbf_scsi("rsl_err", 3, scmd, req);  	else if (scmd->retries > 0) -		zfcp_dbf_scsi("rslt", "retr", 4, dbf, scmd, req, 0); +		_zfcp_dbf_scsi("rsl_ret", 4, scmd, req);  	else -		zfcp_dbf_scsi("rslt", "norm", 6, dbf, scmd, req, 0); +		_zfcp_dbf_scsi("rsl_nor", 6, scmd, req);  }  /**   * zfcp_dbf_scsi_fail_send - trace event for failure to send SCSI command - * @dbf: adapter dbf trace   * @scmd: SCSI command pointer   */  static inline -void zfcp_dbf_scsi_fail_send(struct zfcp_dbf *dbf, struct scsi_cmnd *scmd) +void zfcp_dbf_scsi_fail_send(struct scsi_cmnd *scmd)  { -	zfcp_dbf_scsi("rslt", "fail", 4, dbf, scmd, NULL, 0); +	_zfcp_dbf_scsi("rsl_fai", 4, scmd, NULL);  }  /**   * zfcp_dbf_scsi_abort - trace event for SCSI command abort   * @tag: tag indicating success or failure of abort operation - * @adapter: adapter thas has been used to issue SCSI command to be aborted   * @scmd: SCSI command to be aborted - * @new_req: request containing abort (might be NULL) - * @old_id: identifier of request containg SCSI command to be aborted + * @fsf_req: request containing abort (might be NULL)   */  static inline -void zfcp_dbf_scsi_abort(const char *tag, struct zfcp_dbf *dbf, -			 struct scsi_cmnd *scmd, struct zfcp_fsf_req *new_req, -			 unsigned long old_id) +void zfcp_dbf_scsi_abort(char *tag, struct scsi_cmnd *scmd, +			 struct zfcp_fsf_req *fsf_req)  { -	zfcp_dbf_scsi("abrt", tag, 1, dbf, scmd, new_req, old_id); +	_zfcp_dbf_scsi(tag, 1, scmd, fsf_req);  }  /** @@ -352,12 +367,17 @@ void zfcp_dbf_scsi_abort(const char *tag, struct zfcp_dbf *dbf,   * @flag: indicates type of reset (Target Reset, Logical Unit Reset)   */  static inline -void zfcp_dbf_scsi_devreset(const char *tag, struct scsi_cmnd *scmnd, u8 flag) +void zfcp_dbf_scsi_devreset(char *tag, struct scsi_cmnd *scmnd, u8 flag)  { -	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scmnd->device); +	char tmp_tag[ZFCP_DBF_TAG_LEN]; + +	if (flag == FCP_TMF_TGT_RESET) +		memcpy(tmp_tag, "tr_", 3); +	else +		memcpy(tmp_tag, "lr_", 3); -	zfcp_dbf_scsi(flag == FCP_TMF_TGT_RESET ? "trst" : "lrst", tag, 1, -		      zfcp_sdev->port->adapter->dbf, scmnd, NULL, 0); +	memcpy(&tmp_tag[3], tag, 4); +	_zfcp_dbf_scsi(tmp_tag, 1, scmnd, NULL);  }  #endif /* ZFCP_DBF_H */ diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 9ae1d0a6f62..d91173f326c 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -3,7 +3,7 @@   *   * Global definitions for the zfcp device driver.   * - * Copyright IBM Corporation 2002, 2010 + * Copyright IBM Corp. 2002, 2010   */  #ifndef ZFCP_DEF_H @@ -72,10 +72,12 @@ struct zfcp_reqlist;  #define ZFCP_STATUS_COMMON_NOESC		0x00200000  /* adapter status */ +#define ZFCP_STATUS_ADAPTER_MB_ACT		0x00000001  #define ZFCP_STATUS_ADAPTER_QDIOUP		0x00000002  #define ZFCP_STATUS_ADAPTER_SIOSL_ISSUED	0x00000004  #define ZFCP_STATUS_ADAPTER_XCONFIG_OK		0x00000008  #define ZFCP_STATUS_ADAPTER_HOST_CON_INIT	0x00000010 +#define ZFCP_STATUS_ADAPTER_SUSPENDED		0x00000040  #define ZFCP_STATUS_ADAPTER_ERP_PENDING		0x00000100  #define ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED	0x00000200  #define ZFCP_STATUS_ADAPTER_DATA_DIV_ENABLED	0x00000400 @@ -84,12 +86,7 @@ struct zfcp_reqlist;  #define ZFCP_STATUS_PORT_PHYS_OPEN		0x00000001  #define ZFCP_STATUS_PORT_LINK_TEST		0x00000002 -/* logical unit status */ -#define ZFCP_STATUS_LUN_SHARED			0x00000004 -#define ZFCP_STATUS_LUN_READONLY		0x00000008 -  /* FSF request status (this does not have a common part) */ -#define ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT	0x00000002  #define ZFCP_STATUS_FSFREQ_ERROR		0x00000008  #define ZFCP_STATUS_FSFREQ_CLEANUP		0x00000010  #define ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED	0x00000040 @@ -108,7 +105,7 @@ struct zfcp_adapter_mempool {  	mempool_t *scsi_req;  	mempool_t *scsi_abort;  	mempool_t *status_read_req; -	mempool_t *status_read_data; +	mempool_t *sr_data;  	mempool_t *gid_pn;  	mempool_t *qtcb_pool;  }; @@ -190,6 +187,7 @@ struct zfcp_adapter {  	struct fsf_qtcb_bottom_port *stats_reset_data;  	unsigned long		stats_reset;  	struct work_struct	scan_work; +	struct work_struct	ns_up_work;  	struct service_level	service_level;  	struct workqueue_struct	*work_queue;  	struct device_dma_parameters dma_parms; @@ -203,6 +201,7 @@ struct zfcp_port {  	struct zfcp_adapter    *adapter;       /* adapter used to access port */  	struct list_head	unit_list;	/* head of logical unit list */  	rwlock_t		unit_list_lock; /* unit list lock */ +	atomic_t		units;	       /* zfcp_unit count */  	atomic_t	       status;	       /* status of this remote port */  	u64		       wwnn;	       /* WWNN if known */  	u64		       wwpn;	       /* WWPN */ @@ -314,15 +313,10 @@ struct zfcp_fsf_req {  	void			(*handler)(struct zfcp_fsf_req *);  }; -/* driver data */ -struct zfcp_data { -	struct scsi_host_template scsi_host_template; -	struct scsi_transport_template *scsi_transport_template; -	struct kmem_cache	*gpn_ft_cache; -	struct kmem_cache	*qtcb_cache; -	struct kmem_cache	*sr_buffer_cache; -	struct kmem_cache	*gid_pn_cache; -	struct kmem_cache	*adisc_cache; -}; +static inline +int zfcp_adapter_multi_buffer_active(struct zfcp_adapter *adapter) +{ +	return atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_MB_ACT; +}  #endif /* ZFCP_DEF_H */ diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index d37c7331f24..c82fe65c412 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -3,7 +3,7 @@   *   * Error Recovery Procedures (ERP).   * - * Copyright IBM Corporation 2002, 2010 + * Copyright IBM Corp. 2002, 2010   */  #define KMSG_COMPONENT "zfcp" @@ -76,9 +76,9 @@ static void zfcp_erp_action_ready(struct zfcp_erp_action *act)  	struct zfcp_adapter *adapter = act->adapter;  	list_move(&act->list, &act->adapter->erp_ready_head); -	zfcp_dbf_rec_action("erardy1", act); +	zfcp_dbf_rec_run("erardy1", act);  	wake_up(&adapter->erp_ready_wq); -	zfcp_dbf_rec_thread("erardy2", adapter->dbf); +	zfcp_dbf_rec_run("erardy2", act);  }  static void zfcp_erp_action_dismiss(struct zfcp_erp_action *act) @@ -102,10 +102,13 @@ static void zfcp_erp_action_dismiss_port(struct zfcp_port *port)  	if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_INUSE)  		zfcp_erp_action_dismiss(&port->erp_action); -	else -		shost_for_each_device(sdev, port->adapter->scsi_host) +	else { +		spin_lock(port->adapter->scsi_host->host_lock); +		__shost_for_each_device(sdev, port->adapter->scsi_host)  			if (sdev_to_zfcp(sdev)->port == port)  				zfcp_erp_action_dismiss_lun(sdev); +		spin_unlock(port->adapter->scsi_host->host_lock); +	}  }  static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter) @@ -156,6 +159,8 @@ static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter,  		if (!(a_status & ZFCP_STATUS_COMMON_RUNNING) ||  		      a_status & ZFCP_STATUS_COMMON_ERP_FAILED)  			return 0; +		if (p_status & ZFCP_STATUS_COMMON_NOESC) +			return need;  		if (!(a_status & ZFCP_STATUS_COMMON_UNBLOCKED))  			need = ZFCP_ERP_ACTION_REOPEN_ADAPTER;  		/* fall through */ @@ -188,6 +193,9 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status,  		atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE,  				&zfcp_sdev->status);  		erp_action = &zfcp_sdev->erp_action; +		memset(erp_action, 0, sizeof(struct zfcp_erp_action)); +		erp_action->port = port; +		erp_action->sdev = sdev;  		if (!(atomic_read(&zfcp_sdev->status) &  		      ZFCP_STATUS_COMMON_RUNNING))  			act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY; @@ -200,6 +208,8 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status,  		zfcp_erp_action_dismiss_port(port);  		atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status);  		erp_action = &port->erp_action; +		memset(erp_action, 0, sizeof(struct zfcp_erp_action)); +		erp_action->port = port;  		if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_RUNNING))  			act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;  		break; @@ -209,6 +219,7 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status,  		zfcp_erp_action_dismiss_adapter(adapter);  		atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status);  		erp_action = &adapter->erp_action; +		memset(erp_action, 0, sizeof(struct zfcp_erp_action));  		if (!(atomic_read(&adapter->status) &  		      ZFCP_STATUS_COMMON_RUNNING))  			act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY; @@ -218,10 +229,7 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status,  		return NULL;  	} -	memset(erp_action, 0, sizeof(struct zfcp_erp_action));  	erp_action->adapter = adapter; -	erp_action->port = port; -	erp_action->sdev = sdev;  	erp_action->action = need;  	erp_action->status = act_status; @@ -231,10 +239,10 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status,  static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter,  				   struct zfcp_port *port,  				   struct scsi_device *sdev, -				   char *id, void *ref, u32 act_status) +				   char *id, u32 act_status)  {  	int retval = 1, need; -	struct zfcp_erp_action *act = NULL; +	struct zfcp_erp_action *act;  	if (!adapter->erp_thread)  		return -EIO; @@ -250,15 +258,14 @@ static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter,  	++adapter->erp_total_count;  	list_add_tail(&act->list, &adapter->erp_ready_head);  	wake_up(&adapter->erp_ready_wq); -	zfcp_dbf_rec_thread("eracte1", adapter->dbf);  	retval = 0;   out: -	zfcp_dbf_rec_trigger(id, ref, want, need, act, adapter, port, sdev); +	zfcp_dbf_rec_trig(id, adapter, port, sdev, want, need);  	return retval;  }  static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, -				    int clear_mask, char *id, void *ref) +				    int clear_mask, char *id)  {  	zfcp_erp_adapter_block(adapter, clear_mask);  	zfcp_scsi_schedule_rports_block(adapter); @@ -270,7 +277,7 @@ static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter,  		return -EIO;  	}  	return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, -				       adapter, NULL, NULL, id, ref, 0); +				       adapter, NULL, NULL, id, 0);  }  /** @@ -278,10 +285,8 @@ static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter,   * @adapter: Adapter to reopen.   * @clear: Status flags to clear.   * @id: Id for debug trace event. - * @ref: Reference for debug trace event.   */ -void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear, -			     char *id, void *ref) +void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear, char *id)  {  	unsigned long flags; @@ -294,7 +299,7 @@ void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear,  					    ZFCP_STATUS_COMMON_ERP_FAILED);  	else  		zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, adapter, -					NULL, NULL, id, ref, 0); +					NULL, NULL, id, 0);  	write_unlock_irqrestore(&adapter->erp_lock, flags);  } @@ -303,13 +308,12 @@ void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear,   * @adapter: Adapter to shut down.   * @clear: Status flags to clear.   * @id: Id for debug trace event. - * @ref: Reference for debug trace event.   */  void zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear, -			       char *id, void *ref) +			       char *id)  {  	int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; -	zfcp_erp_adapter_reopen(adapter, clear | flags, id, ref); +	zfcp_erp_adapter_reopen(adapter, clear | flags, id);  }  /** @@ -317,13 +321,11 @@ void zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear,   * @port: Port to shut down.   * @clear: Status flags to clear.   * @id: Id for debug trace event. - * @ref: Reference for debug trace event.   */ -void zfcp_erp_port_shutdown(struct zfcp_port *port, int clear, char *id, -			    void *ref) +void zfcp_erp_port_shutdown(struct zfcp_port *port, int clear, char *id)  {  	int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; -	zfcp_erp_port_reopen(port, clear | flags, id, ref); +	zfcp_erp_port_reopen(port, clear | flags, id);  }  static void zfcp_erp_port_block(struct zfcp_port *port, int clear) @@ -332,8 +334,8 @@ static void zfcp_erp_port_block(struct zfcp_port *port, int clear)  				    ZFCP_STATUS_COMMON_UNBLOCKED | clear);  } -static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port, -					 int clear, char *id, void *ref) +static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, +					 char *id)  {  	zfcp_erp_port_block(port, clear);  	zfcp_scsi_schedule_rport_block(port); @@ -342,28 +344,26 @@ static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port,  		return;  	zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED, -				port->adapter, port, NULL, id, ref, 0); +				port->adapter, port, NULL, id, 0);  }  /**   * zfcp_erp_port_forced_reopen - Forced close of port and open again   * @port: Port to force close and to reopen. + * @clear: Status flags to clear.   * @id: Id for debug trace event. - * @ref: Reference for debug trace event.   */ -void zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, char *id, -				 void *ref) +void zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, char *id)  {  	unsigned long flags;  	struct zfcp_adapter *adapter = port->adapter;  	write_lock_irqsave(&adapter->erp_lock, flags); -	_zfcp_erp_port_forced_reopen(port, clear, id, ref); +	_zfcp_erp_port_forced_reopen(port, clear, id);  	write_unlock_irqrestore(&adapter->erp_lock, flags);  } -static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id, -				 void *ref) +static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id)  {  	zfcp_erp_port_block(port, clear);  	zfcp_scsi_schedule_rport_block(port); @@ -375,24 +375,25 @@ static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id,  	}  	return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT, -				       port->adapter, port, NULL, id, ref, 0); +				       port->adapter, port, NULL, id, 0);  }  /**   * zfcp_erp_port_reopen - trigger remote port recovery   * @port: port to recover   * @clear_mask: flags in port status to be cleared + * @id: Id for debug trace event.   *   * Returns 0 if recovery has been triggered, < 0 if not.   */ -int zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id, void *ref) +int zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id)  {  	int retval;  	unsigned long flags;  	struct zfcp_adapter *adapter = port->adapter;  	write_lock_irqsave(&adapter->erp_lock, flags); -	retval = _zfcp_erp_port_reopen(port, clear, id, ref); +	retval = _zfcp_erp_port_reopen(port, clear, id);  	write_unlock_irqrestore(&adapter->erp_lock, flags);  	return retval; @@ -405,7 +406,7 @@ static void zfcp_erp_lun_block(struct scsi_device *sdev, int clear_mask)  }  static void _zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id, -				 void *ref, u32 act_status) +				 u32 act_status)  {  	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);  	struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; @@ -416,17 +417,18 @@ static void _zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id,  		return;  	zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_LUN, adapter, -				zfcp_sdev->port, sdev, id, ref, act_status); +				zfcp_sdev->port, sdev, id, act_status);  }  /**   * zfcp_erp_lun_reopen - initiate reopen of a LUN   * @sdev: SCSI device / LUN to be reopened   * @clear_mask: specifies flags in LUN status to be cleared + * @id: Id for debug trace event. + *   * Return: 0 on success, < 0 on error   */ -void zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id, -			 void *ref) +void zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id)  {  	unsigned long flags;  	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); @@ -434,7 +436,7 @@ void zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id,  	struct zfcp_adapter *adapter = port->adapter;  	write_lock_irqsave(&adapter->erp_lock, flags); -	_zfcp_erp_lun_reopen(sdev, clear, id, ref, 0); +	_zfcp_erp_lun_reopen(sdev, clear, id, 0);  	write_unlock_irqrestore(&adapter->erp_lock, flags);  } @@ -443,13 +445,11 @@ void zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id,   * @sdev: SCSI device / LUN to shut down.   * @clear: Status flags to clear.   * @id: Id for debug trace event. - * @ref: Reference for debug trace event.   */ -void zfcp_erp_lun_shutdown(struct scsi_device *sdev, int clear, char *id, -			   void *ref) +void zfcp_erp_lun_shutdown(struct scsi_device *sdev, int clear, char *id)  {  	int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; -	zfcp_erp_lun_reopen(sdev, clear | flags, id, ref); +	zfcp_erp_lun_reopen(sdev, clear | flags, id);  }  /** @@ -471,7 +471,7 @@ void zfcp_erp_lun_shutdown_wait(struct scsi_device *sdev, char *id)  	int clear = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;  	write_lock_irqsave(&adapter->erp_lock, flags); -	_zfcp_erp_lun_reopen(sdev, clear, id, NULL, ZFCP_STATUS_ERP_NO_REF); +	_zfcp_erp_lun_reopen(sdev, clear, id, ZFCP_STATUS_ERP_NO_REF);  	write_unlock_irqrestore(&adapter->erp_lock, flags);  	zfcp_erp_wait(adapter); @@ -485,14 +485,14 @@ static int status_change_set(unsigned long mask, atomic_t *status)  static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter)  {  	if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status)) -		zfcp_dbf_rec_adapter("eraubl1", NULL, adapter->dbf); +		zfcp_dbf_rec_run("eraubl1", &adapter->erp_action);  	atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status);  }  static void zfcp_erp_port_unblock(struct zfcp_port *port)  {  	if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status)) -		zfcp_dbf_rec_port("erpubl1", NULL, port); +		zfcp_dbf_rec_run("erpubl1", &port->erp_action);  	atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status);  } @@ -501,14 +501,14 @@ static void zfcp_erp_lun_unblock(struct scsi_device *sdev)  	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);  	if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &zfcp_sdev->status)) -		zfcp_dbf_rec_lun("erlubl1", NULL, sdev); +		zfcp_dbf_rec_run("erlubl1", &sdev_to_zfcp(sdev)->erp_action);  	atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &zfcp_sdev->status);  }  static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)  {  	list_move(&erp_action->list, &erp_action->adapter->erp_running_head); -	zfcp_dbf_rec_action("erator1", erp_action); +	zfcp_dbf_rec_run("erator1", erp_action);  }  static void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act) @@ -525,11 +525,11 @@ static void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act)  		if (act->status & (ZFCP_STATUS_ERP_DISMISSED |  				   ZFCP_STATUS_ERP_TIMEDOUT)) {  			req->status |= ZFCP_STATUS_FSFREQ_DISMISSED; -			zfcp_dbf_rec_action("erscf_1", act); +			zfcp_dbf_rec_run("erscf_1", act);  			req->erp_action = NULL;  		}  		if (act->status & ZFCP_STATUS_ERP_TIMEDOUT) -			zfcp_dbf_rec_action("erscf_2", act); +			zfcp_dbf_rec_run("erscf_2", act);  		if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED)  			act->fsf_req_id = 0;  	} else @@ -580,40 +580,42 @@ static void zfcp_erp_strategy_memwait(struct zfcp_erp_action *erp_action)  }  static void _zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter, -				      int clear, char *id, void *ref) +				      int clear, char *id)  {  	struct zfcp_port *port;  	read_lock(&adapter->port_list_lock);  	list_for_each_entry(port, &adapter->port_list, list) -		_zfcp_erp_port_reopen(port, clear, id, ref); +		_zfcp_erp_port_reopen(port, clear, id);  	read_unlock(&adapter->port_list_lock);  }  static void _zfcp_erp_lun_reopen_all(struct zfcp_port *port, int clear, -				     char *id, void *ref) +				     char *id)  {  	struct scsi_device *sdev; -	shost_for_each_device(sdev, port->adapter->scsi_host) +	spin_lock(port->adapter->scsi_host->host_lock); +	__shost_for_each_device(sdev, port->adapter->scsi_host)  		if (sdev_to_zfcp(sdev)->port == port) -			_zfcp_erp_lun_reopen(sdev, clear, id, ref, 0); +			_zfcp_erp_lun_reopen(sdev, clear, id, 0); +	spin_unlock(port->adapter->scsi_host->host_lock);  }  static void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act)  {  	switch (act->action) {  	case ZFCP_ERP_ACTION_REOPEN_ADAPTER: -		_zfcp_erp_adapter_reopen(act->adapter, 0, "ersff_1", NULL); +		_zfcp_erp_adapter_reopen(act->adapter, 0, "ersff_1");  		break;  	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: -		_zfcp_erp_port_forced_reopen(act->port, 0, "ersff_2", NULL); +		_zfcp_erp_port_forced_reopen(act->port, 0, "ersff_2");  		break;  	case ZFCP_ERP_ACTION_REOPEN_PORT: -		_zfcp_erp_port_reopen(act->port, 0, "ersff_3", NULL); +		_zfcp_erp_port_reopen(act->port, 0, "ersff_3");  		break;  	case ZFCP_ERP_ACTION_REOPEN_LUN: -		_zfcp_erp_lun_reopen(act->sdev, 0, "ersff_4", NULL, 0); +		_zfcp_erp_lun_reopen(act->sdev, 0, "ersff_4", 0);  		break;  	}  } @@ -622,13 +624,13 @@ static void zfcp_erp_strategy_followup_success(struct zfcp_erp_action *act)  {  	switch (act->action) {  	case ZFCP_ERP_ACTION_REOPEN_ADAPTER: -		_zfcp_erp_port_reopen_all(act->adapter, 0, "ersfs_1", NULL); +		_zfcp_erp_port_reopen_all(act->adapter, 0, "ersfs_1");  		break;  	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: -		_zfcp_erp_port_reopen(act->port, 0, "ersfs_2", NULL); +		_zfcp_erp_port_reopen(act->port, 0, "ersfs_2");  		break;  	case ZFCP_ERP_ACTION_REOPEN_PORT: -		_zfcp_erp_lun_reopen_all(act->port, 0, "ersfs_3", NULL); +		_zfcp_erp_lun_reopen_all(act->port, 0, "ersfs_3");  		break;  	}  } @@ -647,17 +649,6 @@ static void zfcp_erp_wakeup(struct zfcp_adapter *adapter)  	read_unlock_irqrestore(&adapter->erp_lock, flags);  } -static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *act) -{ -	struct zfcp_qdio *qdio = act->adapter->qdio; - -	if (zfcp_qdio_open(qdio)) -		return ZFCP_ERP_FAILED; -	init_waitqueue_head(&qdio->req_q_wq); -	atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &act->adapter->status); -	return ZFCP_ERP_SUCCEEDED; -} -  static void zfcp_erp_enqueue_ptp_port(struct zfcp_adapter *adapter)  {  	struct zfcp_port *port; @@ -665,7 +656,7 @@ static void zfcp_erp_enqueue_ptp_port(struct zfcp_adapter *adapter)  				 adapter->peer_d_id);  	if (IS_ERR(port)) /* error or port already attached */  		return; -	_zfcp_erp_port_reopen(port, 0, "ereptp1", NULL); +	_zfcp_erp_port_reopen(port, 0, "ereptp1");  }  static int zfcp_erp_adapter_strat_fsf_xconf(struct zfcp_erp_action *erp_action) @@ -688,10 +679,8 @@ static int zfcp_erp_adapter_strat_fsf_xconf(struct zfcp_erp_action *erp_action)  			return ZFCP_ERP_FAILED;  		} -		zfcp_dbf_rec_thread_lock("erasfx1", adapter->dbf);  		wait_event(adapter->erp_ready_wq,  			   !list_empty(&adapter->erp_ready_head)); -		zfcp_dbf_rec_thread_lock("erasfx2", adapter->dbf);  		if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT)  			break; @@ -730,10 +719,10 @@ static int zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *act)  	if (ret)  		return ZFCP_ERP_FAILED; -	zfcp_dbf_rec_thread_lock("erasox1", adapter->dbf); +	zfcp_dbf_rec_run("erasox1", act);  	wait_event(adapter->erp_ready_wq,  		   !list_empty(&adapter->erp_ready_head)); -	zfcp_dbf_rec_thread_lock("erasox2", adapter->dbf); +	zfcp_dbf_rec_run("erasox2", act);  	if (act->status & ZFCP_STATUS_ERP_TIMEDOUT)  		return ZFCP_ERP_FAILED; @@ -748,7 +737,7 @@ static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *act)  	if (zfcp_erp_adapter_strategy_open_fsf_xport(act) == ZFCP_ERP_FAILED)  		return ZFCP_ERP_FAILED; -	if (mempool_resize(act->adapter->pool.status_read_data, +	if (mempool_resize(act->adapter->pool.sr_data,  			   act->adapter->stat_read_buf_num, GFP_KERNEL))  		return ZFCP_ERP_FAILED; @@ -783,7 +772,7 @@ static int zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *act)  {  	struct zfcp_adapter *adapter = act->adapter; -	if (zfcp_erp_adapter_strategy_open_qdio(act)) { +	if (zfcp_qdio_open(adapter->qdio)) {  		atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK |  				  ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,  				  &adapter->status); @@ -966,8 +955,7 @@ static void zfcp_erp_lun_strategy_clearstati(struct scsi_device *sdev)  {  	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); -	atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | -			  ZFCP_STATUS_LUN_SHARED | ZFCP_STATUS_LUN_READONLY, +	atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED,  			  &zfcp_sdev->status);  } @@ -1161,7 +1149,7 @@ static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret)  		if (zfcp_erp_strat_change_det(&adapter->status, erp_status)) {  			_zfcp_erp_adapter_reopen(adapter,  						 ZFCP_STATUS_COMMON_ERP_FAILED, -						 "ersscg1", NULL); +						 "ersscg1");  			return ZFCP_ERP_EXIT;  		}  		break; @@ -1171,7 +1159,7 @@ static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret)  		if (zfcp_erp_strat_change_det(&port->status, erp_status)) {  			_zfcp_erp_port_reopen(port,  					      ZFCP_STATUS_COMMON_ERP_FAILED, -					      "ersscg2", NULL); +					      "ersscg2");  			return ZFCP_ERP_EXIT;  		}  		break; @@ -1181,7 +1169,7 @@ static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret)  		if (zfcp_erp_strat_change_det(&zfcp_sdev->status, erp_status)) {  			_zfcp_erp_lun_reopen(sdev,  					     ZFCP_STATUS_COMMON_ERP_FAILED, -					     "ersscg3", NULL, 0); +					     "ersscg3", 0);  			return ZFCP_ERP_EXIT;  		}  		break; @@ -1201,7 +1189,7 @@ static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action)  	}  	list_del(&erp_action->list); -	zfcp_dbf_rec_action("eractd1", erp_action); +	zfcp_dbf_rec_run("eractd1", erp_action);  	switch (erp_action->action) {  	case ZFCP_ERP_ACTION_REOPEN_LUN: @@ -1246,9 +1234,11 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)  	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:  		if (result == ZFCP_ERP_SUCCEEDED) {  			register_service_level(&adapter->service_level); -			queue_work(adapter->work_queue, &adapter->scan_work); +			zfcp_fc_conditional_port_scan(adapter); +			queue_work(adapter->work_queue, &adapter->ns_up_work);  		} else  			unregister_service_level(&adapter->service_level); +  		kref_put(&adapter->ref, zfcp_adapter_release);  		break;  	} @@ -1308,7 +1298,7 @@ static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action)  			erp_action->status |= ZFCP_STATUS_ERP_LOWMEM;  		}  		if (adapter->erp_total_count == adapter->erp_low_mem_count) -			_zfcp_erp_adapter_reopen(adapter, 0, "erstgy1", NULL); +			_zfcp_erp_adapter_reopen(adapter, 0, "erstgy1");  		else {  			zfcp_erp_strategy_memwait(erp_action);  			retval = ZFCP_ERP_CONTINUES; @@ -1352,11 +1342,9 @@ static int zfcp_erp_thread(void *data)  	unsigned long flags;  	for (;;) { -		zfcp_dbf_rec_thread_lock("erthrd1", adapter->dbf);  		wait_event_interruptible(adapter->erp_ready_wq,  			   !list_empty(&adapter->erp_ready_head) ||  			   kthread_should_stop()); -		zfcp_dbf_rec_thread_lock("erthrd2", adapter->dbf);  		if (kthread_should_stop())  			break; @@ -1451,8 +1439,10 @@ void zfcp_erp_set_adapter_status(struct zfcp_adapter *adapter, u32 mask)  		atomic_set_mask(common_mask, &port->status);  	read_unlock_irqrestore(&adapter->port_list_lock, flags); -	shost_for_each_device(sdev, adapter->scsi_host) +	spin_lock_irqsave(adapter->scsi_host->host_lock, flags); +	__shost_for_each_device(sdev, adapter->scsi_host)  		atomic_set_mask(common_mask, &sdev_to_zfcp(sdev)->status); +	spin_unlock_irqrestore(adapter->scsi_host->host_lock, flags);  }  /** @@ -1486,11 +1476,13 @@ void zfcp_erp_clear_adapter_status(struct zfcp_adapter *adapter, u32 mask)  	}  	read_unlock_irqrestore(&adapter->port_list_lock, flags); -	shost_for_each_device(sdev, adapter->scsi_host) { +	spin_lock_irqsave(adapter->scsi_host->host_lock, flags); +	__shost_for_each_device(sdev, adapter->scsi_host) {  		atomic_clear_mask(common_mask, &sdev_to_zfcp(sdev)->status);  		if (clear_counter)  			atomic_set(&sdev_to_zfcp(sdev)->erp_counter, 0);  	} +	spin_unlock_irqrestore(adapter->scsi_host->host_lock, flags);  }  /** @@ -1504,16 +1496,19 @@ void zfcp_erp_set_port_status(struct zfcp_port *port, u32 mask)  {  	struct scsi_device *sdev;  	u32 common_mask = mask & ZFCP_COMMON_FLAGS; +	unsigned long flags;  	atomic_set_mask(mask, &port->status);  	if (!common_mask)  		return; -	shost_for_each_device(sdev, port->adapter->scsi_host) +	spin_lock_irqsave(port->adapter->scsi_host->host_lock, flags); +	__shost_for_each_device(sdev, port->adapter->scsi_host)  		if (sdev_to_zfcp(sdev)->port == port)  			atomic_set_mask(common_mask,  					&sdev_to_zfcp(sdev)->status); +	spin_unlock_irqrestore(port->adapter->scsi_host->host_lock, flags);  }  /** @@ -1528,6 +1523,7 @@ void zfcp_erp_clear_port_status(struct zfcp_port *port, u32 mask)  	struct scsi_device *sdev;  	u32 common_mask = mask & ZFCP_COMMON_FLAGS;  	u32 clear_counter = mask & ZFCP_STATUS_COMMON_ERP_FAILED; +	unsigned long flags;  	atomic_clear_mask(mask, &port->status); @@ -1537,13 +1533,15 @@ void zfcp_erp_clear_port_status(struct zfcp_port *port, u32 mask)  	if (clear_counter)  		atomic_set(&port->erp_counter, 0); -	shost_for_each_device(sdev, port->adapter->scsi_host) +	spin_lock_irqsave(port->adapter->scsi_host->host_lock, flags); +	__shost_for_each_device(sdev, port->adapter->scsi_host)  		if (sdev_to_zfcp(sdev)->port == port) {  			atomic_clear_mask(common_mask,  					  &sdev_to_zfcp(sdev)->status);  			if (clear_counter)  				atomic_set(&sdev_to_zfcp(sdev)->erp_counter, 0);  		} +	spin_unlock_irqrestore(port->adapter->scsi_host->host_lock, flags);  }  /** diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index bf8f3e51483..a9c570a09b8 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -3,7 +3,7 @@   *   * External function declarations.   * - * Copyright IBM Corporation 2002, 2010 + * Copyright IBM Corp. 2002, 2010   */  #ifndef ZFCP_EXT_H @@ -21,71 +21,45 @@ extern struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *, u64, u32,  					   u32);  extern void zfcp_sg_free_table(struct scatterlist *, int);  extern int zfcp_sg_setup_table(struct scatterlist *, int); -extern void zfcp_device_unregister(struct device *, -				   const struct attribute_group *);  extern void zfcp_adapter_release(struct kref *);  extern void zfcp_adapter_unregister(struct zfcp_adapter *);  /* zfcp_ccw.c */ -extern int zfcp_ccw_priv_sch(struct zfcp_adapter *);  extern struct ccw_driver zfcp_ccw_driver;  extern struct zfcp_adapter *zfcp_ccw_adapter_by_cdev(struct ccw_device *);  extern void zfcp_ccw_adapter_put(struct zfcp_adapter *); -/* zfcp_cfdc.c */ -extern struct miscdevice zfcp_cfdc_misc; -extern void zfcp_cfdc_port_denied(struct zfcp_port *, union fsf_status_qual *); -extern void zfcp_cfdc_lun_denied(struct scsi_device *, union fsf_status_qual *); -extern void zfcp_cfdc_lun_shrng_vltn(struct scsi_device *, -				     union fsf_status_qual *); -extern int zfcp_cfdc_open_lun_eval(struct scsi_device *, -				   struct fsf_qtcb_bottom_support *); -extern void zfcp_cfdc_adapter_access_changed(struct zfcp_adapter *); - -  /* zfcp_dbf.c */  extern int zfcp_dbf_adapter_register(struct zfcp_adapter *); -extern void zfcp_dbf_adapter_unregister(struct zfcp_dbf *); -extern void zfcp_dbf_rec_thread(char *, struct zfcp_dbf *); -extern void zfcp_dbf_rec_thread_lock(char *, struct zfcp_dbf *); -extern void zfcp_dbf_rec_adapter(char *, void *, struct zfcp_dbf *); -extern void zfcp_dbf_rec_port(char *, void *, struct zfcp_port *); -extern void zfcp_dbf_rec_lun(char *, void *, struct scsi_device *); -extern void zfcp_dbf_rec_trigger(char *, void *, u8, u8, void *, -				 struct zfcp_adapter *, struct zfcp_port *, -				 struct scsi_device *); -extern void zfcp_dbf_rec_action(char *, struct zfcp_erp_action *); -extern void _zfcp_dbf_hba_fsf_response(const char *, int, struct zfcp_fsf_req *, -				       struct zfcp_dbf *); -extern void _zfcp_dbf_hba_fsf_unsol(const char *, int level, struct zfcp_dbf *, -					  struct fsf_status_read_buffer *); -extern void zfcp_dbf_hba_qdio(struct zfcp_dbf *, unsigned int, int, int); +extern void zfcp_dbf_adapter_unregister(struct zfcp_adapter *); +extern void zfcp_dbf_rec_trig(char *, struct zfcp_adapter *, +			      struct zfcp_port *, struct scsi_device *, u8, u8); +extern void zfcp_dbf_rec_run(char *, struct zfcp_erp_action *); +extern void zfcp_dbf_hba_fsf_uss(char *, struct zfcp_fsf_req *); +extern void zfcp_dbf_hba_fsf_res(char *, struct zfcp_fsf_req *); +extern void zfcp_dbf_hba_bit_err(char *, struct zfcp_fsf_req *);  extern void zfcp_dbf_hba_berr(struct zfcp_dbf *, struct zfcp_fsf_req *); -extern void zfcp_dbf_san_ct_request(struct zfcp_fsf_req *, u32); -extern void zfcp_dbf_san_ct_response(struct zfcp_fsf_req *); -extern void zfcp_dbf_san_els_request(struct zfcp_fsf_req *); -extern void zfcp_dbf_san_els_response(struct zfcp_fsf_req *); -extern void zfcp_dbf_san_incoming_els(struct zfcp_fsf_req *); -extern void _zfcp_dbf_scsi(const char *, const char *, int, struct zfcp_dbf *, -			   struct scsi_cmnd *, struct zfcp_fsf_req *, -			   unsigned long); +extern void zfcp_dbf_hba_def_err(struct zfcp_adapter *, u64, u16, void **); +extern void zfcp_dbf_hba_basic(char *, struct zfcp_adapter *); +extern void zfcp_dbf_san_req(char *, struct zfcp_fsf_req *, u32); +extern void zfcp_dbf_san_res(char *, struct zfcp_fsf_req *); +extern void zfcp_dbf_san_in_els(char *, struct zfcp_fsf_req *); +extern void zfcp_dbf_scsi(char *, struct scsi_cmnd *, struct zfcp_fsf_req *);  /* zfcp_erp.c */  extern void zfcp_erp_set_adapter_status(struct zfcp_adapter *, u32);  extern void zfcp_erp_clear_adapter_status(struct zfcp_adapter *, u32); -extern void zfcp_erp_adapter_reopen(struct zfcp_adapter *, int, char *, void *); -extern void zfcp_erp_adapter_shutdown(struct zfcp_adapter *, int, char *, -				      void *); +extern void zfcp_erp_adapter_reopen(struct zfcp_adapter *, int, char *); +extern void zfcp_erp_adapter_shutdown(struct zfcp_adapter *, int, char *);  extern void zfcp_erp_set_port_status(struct zfcp_port *, u32);  extern void zfcp_erp_clear_port_status(struct zfcp_port *, u32); -extern int  zfcp_erp_port_reopen(struct zfcp_port *, int, char *, void *); -extern void zfcp_erp_port_shutdown(struct zfcp_port *, int, char *, void *); -extern void zfcp_erp_port_forced_reopen(struct zfcp_port *, int, char *, -					void *); +extern int  zfcp_erp_port_reopen(struct zfcp_port *, int, char *); +extern void zfcp_erp_port_shutdown(struct zfcp_port *, int, char *); +extern void zfcp_erp_port_forced_reopen(struct zfcp_port *, int, char *);  extern void zfcp_erp_set_lun_status(struct scsi_device *, u32);  extern void zfcp_erp_clear_lun_status(struct scsi_device *, u32); -extern void zfcp_erp_lun_reopen(struct scsi_device *, int, char *, void *); -extern void zfcp_erp_lun_shutdown(struct scsi_device *, int, char *, void *); +extern void zfcp_erp_lun_reopen(struct scsi_device *, int, char *); +extern void zfcp_erp_lun_shutdown(struct scsi_device *, int, char *);  extern void zfcp_erp_lun_shutdown_wait(struct scsi_device *, char *);  extern int  zfcp_erp_thread_setup(struct zfcp_adapter *);  extern void zfcp_erp_thread_kill(struct zfcp_adapter *); @@ -94,6 +68,7 @@ extern void zfcp_erp_notify(struct zfcp_erp_action *, unsigned long);  extern void zfcp_erp_timeout_handler(unsigned long);  /* zfcp_fc.c */ +extern struct kmem_cache *zfcp_fc_req_cache;  extern void zfcp_fc_enqueue_event(struct zfcp_adapter *,  				enum fc_host_event_code event_code, u32);  extern void zfcp_fc_post_event(struct work_struct *); @@ -109,8 +84,12 @@ extern int zfcp_fc_gs_setup(struct zfcp_adapter *);  extern void zfcp_fc_gs_destroy(struct zfcp_adapter *);  extern int zfcp_fc_exec_bsg_job(struct fc_bsg_job *);  extern int zfcp_fc_timeout_bsg_job(struct fc_bsg_job *); +extern void zfcp_fc_sym_name_update(struct work_struct *); +extern void zfcp_fc_conditional_port_scan(struct zfcp_adapter *); +extern void zfcp_fc_inverse_conditional_port_scan(struct zfcp_adapter *);  /* zfcp_fsf.c */ +extern struct kmem_cache *zfcp_fsf_qtcb_cache;  extern int zfcp_fsf_open_port(struct zfcp_erp_action *);  extern int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *);  extern int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *); @@ -124,8 +103,6 @@ extern int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *,  extern int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *);  extern int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *,  					    struct fsf_qtcb_bottom_port *); -extern struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *, -						  struct zfcp_fsf_cfdc *);  extern void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *);  extern int zfcp_fsf_status_read(struct zfcp_qdio *);  extern int zfcp_status_read_refill(struct zfcp_adapter *adapter); @@ -151,9 +128,9 @@ extern void zfcp_qdio_close(struct zfcp_qdio *);  extern void zfcp_qdio_siosl(struct zfcp_adapter *);  /* zfcp_scsi.c */ -extern struct zfcp_data zfcp_data; -extern int zfcp_adapter_scsi_register(struct zfcp_adapter *); -extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *); +extern struct scsi_transport_template *zfcp_scsi_transport_template; +extern int zfcp_scsi_adapter_register(struct zfcp_adapter *); +extern void zfcp_scsi_adapter_unregister(struct zfcp_adapter *);  extern struct fc_function_template zfcp_transport_functions;  extern void zfcp_scsi_rport_work(struct work_struct *);  extern void zfcp_scsi_schedule_rport_register(struct zfcp_port *); @@ -163,9 +140,10 @@ extern void zfcp_scsi_set_prot(struct zfcp_adapter *);  extern void zfcp_scsi_dif_sense_error(struct scsi_cmnd *, int);  /* zfcp_sysfs.c */ -extern struct attribute_group zfcp_sysfs_unit_attrs; +extern const struct attribute_group *zfcp_unit_attr_groups[];  extern struct attribute_group zfcp_sysfs_adapter_attrs; -extern struct attribute_group zfcp_sysfs_port_attrs; +extern const struct attribute_group *zfcp_port_attr_groups[]; +extern struct mutex zfcp_sysfs_port_units_mutex;  extern struct device_attribute *zfcp_sysfs_sdev_attrs[];  extern struct device_attribute *zfcp_sysfs_shost_attrs[]; diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 86fd905df48..ca28e1c6611 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -3,7 +3,7 @@   *   * Fibre Channel related functions for the zfcp device driver.   * - * Copyright IBM Corporation 2008, 2010 + * Copyright IBM Corp. 2008, 2010   */  #define KMSG_COMPONENT "zfcp" @@ -11,11 +11,14 @@  #include <linux/types.h>  #include <linux/slab.h> +#include <linux/utsname.h>  #include <scsi/fc/fc_els.h>  #include <scsi/libfc.h>  #include "zfcp_ext.h"  #include "zfcp_fc.h" +struct kmem_cache *zfcp_fc_req_cache; +  static u32 zfcp_fc_rscn_range_mask[] = {  	[ELS_ADDR_FMT_PORT]		= 0xFFFFFF,  	[ELS_ADDR_FMT_AREA]		= 0xFFFF00, @@ -23,6 +26,27 @@ static u32 zfcp_fc_rscn_range_mask[] = {  	[ELS_ADDR_FMT_FAB]		= 0x000000,  }; +static bool no_auto_port_rescan; +module_param_named(no_auto_port_rescan, no_auto_port_rescan, bool, 0600); +MODULE_PARM_DESC(no_auto_port_rescan, +		 "no automatic port_rescan (default off)"); + +void zfcp_fc_conditional_port_scan(struct zfcp_adapter *adapter) +{ +	if (no_auto_port_rescan) +		return; + +	queue_work(adapter->work_queue, &adapter->scan_work); +} + +void zfcp_fc_inverse_conditional_port_scan(struct zfcp_adapter *adapter) +{ +	if (!no_auto_port_rescan) +		return; + +	queue_work(adapter->work_queue, &adapter->scan_work); +} +  /**   * zfcp_fc_post_event - post event to userspace via fc_transport   * @work: work struct with enqueued events @@ -174,7 +198,7 @@ static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range,  		if (!port->d_id)  			zfcp_erp_port_reopen(port,  					     ZFCP_STATUS_COMMON_ERP_FAILED, -					     "fcrscn1", NULL); +					     "fcrscn1");  	}  	read_unlock_irqrestore(&adapter->port_list_lock, flags);  } @@ -203,7 +227,7 @@ static void zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req)  		zfcp_fc_enqueue_event(fsf_req->adapter, FCH_EVT_RSCN,  				      *(u32 *)page);  	} -	queue_work(fsf_req->adapter->work_queue, &fsf_req->adapter->scan_work); +	zfcp_fc_conditional_port_scan(fsf_req->adapter);  }  static void zfcp_fc_incoming_wwpn(struct zfcp_fsf_req *req, u64 wwpn) @@ -215,7 +239,7 @@ static void zfcp_fc_incoming_wwpn(struct zfcp_fsf_req *req, u64 wwpn)  	read_lock_irqsave(&adapter->port_list_lock, flags);  	list_for_each_entry(port, &adapter->port_list, list)  		if (port->wwpn == wwpn) { -			zfcp_erp_port_forced_reopen(port, 0, "fciwwp1", req); +			zfcp_erp_port_forced_reopen(port, 0, "fciwwp1");  			break;  		}  	read_unlock_irqrestore(&adapter->port_list_lock, flags); @@ -251,7 +275,7 @@ void zfcp_fc_incoming_els(struct zfcp_fsf_req *fsf_req)  		(struct fsf_status_read_buffer *) fsf_req->data;  	unsigned int els_type = status_buffer->payload.data[0]; -	zfcp_dbf_san_incoming_els(fsf_req); +	zfcp_dbf_san_in_els("fciels1", fsf_req);  	if (els_type == ELS_PLOGI)  		zfcp_fc_incoming_plogi(fsf_req);  	else if (els_type == ELS_LOGO) @@ -260,24 +284,18 @@ void zfcp_fc_incoming_els(struct zfcp_fsf_req *fsf_req)  		zfcp_fc_incoming_rscn(fsf_req);  } -static void zfcp_fc_ns_gid_pn_eval(void *data) +static void zfcp_fc_ns_gid_pn_eval(struct zfcp_fc_req *fc_req)  { -	struct zfcp_fc_gid_pn *gid_pn = data; -	struct zfcp_fsf_ct_els *ct = &gid_pn->ct; -	struct zfcp_fc_gid_pn_req *gid_pn_req = sg_virt(ct->req); -	struct zfcp_fc_gid_pn_resp *gid_pn_resp = sg_virt(ct->resp); -	struct zfcp_port *port = gid_pn->port; +	struct zfcp_fsf_ct_els *ct_els = &fc_req->ct_els; +	struct zfcp_fc_gid_pn_rsp *gid_pn_rsp = &fc_req->u.gid_pn.rsp; -	if (ct->status) +	if (ct_els->status)  		return; -	if (gid_pn_resp->ct_hdr.ct_cmd != FC_FS_ACC) +	if (gid_pn_rsp->ct_hdr.ct_cmd != FC_FS_ACC)  		return; -	/* paranoia */ -	if (gid_pn_req->gid_pn.fn_wwpn != port->wwpn) -		return;  	/* looks like a valid d_id */ -	port->d_id = ntoh24(gid_pn_resp->gid_pn.fp_fid); +	ct_els->port->d_id = ntoh24(gid_pn_rsp->gid_pn.fp_fid);  }  static void zfcp_fc_complete(void *data) @@ -285,69 +303,73 @@ static void zfcp_fc_complete(void *data)  	complete(data);  } +static void zfcp_fc_ct_ns_init(struct fc_ct_hdr *ct_hdr, u16 cmd, u16 mr_size) +{ +	ct_hdr->ct_rev = FC_CT_REV; +	ct_hdr->ct_fs_type = FC_FST_DIR; +	ct_hdr->ct_fs_subtype = FC_NS_SUBTYPE; +	ct_hdr->ct_cmd = cmd; +	ct_hdr->ct_mr_size = mr_size / 4; +} +  static int zfcp_fc_ns_gid_pn_request(struct zfcp_port *port, -				     struct zfcp_fc_gid_pn *gid_pn) +				     struct zfcp_fc_req *fc_req)  {  	struct zfcp_adapter *adapter = port->adapter;  	DECLARE_COMPLETION_ONSTACK(completion); +	struct zfcp_fc_gid_pn_req *gid_pn_req = &fc_req->u.gid_pn.req; +	struct zfcp_fc_gid_pn_rsp *gid_pn_rsp = &fc_req->u.gid_pn.rsp;  	int ret;  	/* setup parameters for send generic command */ -	gid_pn->port = port; -	gid_pn->ct.handler = zfcp_fc_complete; -	gid_pn->ct.handler_data = &completion; -	gid_pn->ct.req = &gid_pn->sg_req; -	gid_pn->ct.resp = &gid_pn->sg_resp; -	sg_init_one(&gid_pn->sg_req, &gid_pn->gid_pn_req, -		    sizeof(struct zfcp_fc_gid_pn_req)); -	sg_init_one(&gid_pn->sg_resp, &gid_pn->gid_pn_resp, -		    sizeof(struct zfcp_fc_gid_pn_resp)); - -	/* setup nameserver request */ -	gid_pn->gid_pn_req.ct_hdr.ct_rev = FC_CT_REV; -	gid_pn->gid_pn_req.ct_hdr.ct_fs_type = FC_FST_DIR; -	gid_pn->gid_pn_req.ct_hdr.ct_fs_subtype = FC_NS_SUBTYPE; -	gid_pn->gid_pn_req.ct_hdr.ct_options = 0; -	gid_pn->gid_pn_req.ct_hdr.ct_cmd = FC_NS_GID_PN; -	gid_pn->gid_pn_req.ct_hdr.ct_mr_size = ZFCP_FC_CT_SIZE_PAGE / 4; -	gid_pn->gid_pn_req.gid_pn.fn_wwpn = port->wwpn; - -	ret = zfcp_fsf_send_ct(&adapter->gs->ds, &gid_pn->ct, +	fc_req->ct_els.port = port; +	fc_req->ct_els.handler = zfcp_fc_complete; +	fc_req->ct_els.handler_data = &completion; +	fc_req->ct_els.req = &fc_req->sg_req; +	fc_req->ct_els.resp = &fc_req->sg_rsp; +	sg_init_one(&fc_req->sg_req, gid_pn_req, sizeof(*gid_pn_req)); +	sg_init_one(&fc_req->sg_rsp, gid_pn_rsp, sizeof(*gid_pn_rsp)); + +	zfcp_fc_ct_ns_init(&gid_pn_req->ct_hdr, +			   FC_NS_GID_PN, ZFCP_FC_CT_SIZE_PAGE); +	gid_pn_req->gid_pn.fn_wwpn = port->wwpn; + +	ret = zfcp_fsf_send_ct(&adapter->gs->ds, &fc_req->ct_els,  			       adapter->pool.gid_pn_req,  			       ZFCP_FC_CTELS_TMO);  	if (!ret) {  		wait_for_completion(&completion); -		zfcp_fc_ns_gid_pn_eval(gid_pn); +		zfcp_fc_ns_gid_pn_eval(fc_req);  	}  	return ret;  }  /** - * zfcp_fc_ns_gid_pn_request - initiate GID_PN nameserver request + * zfcp_fc_ns_gid_pn - initiate GID_PN nameserver request   * @port: port where GID_PN request is needed   * return: -ENOMEM on error, 0 otherwise   */  static int zfcp_fc_ns_gid_pn(struct zfcp_port *port)  {  	int ret; -	struct zfcp_fc_gid_pn *gid_pn; +	struct zfcp_fc_req *fc_req;  	struct zfcp_adapter *adapter = port->adapter; -	gid_pn = mempool_alloc(adapter->pool.gid_pn, GFP_ATOMIC); -	if (!gid_pn) +	fc_req = mempool_alloc(adapter->pool.gid_pn, GFP_ATOMIC); +	if (!fc_req)  		return -ENOMEM; -	memset(gid_pn, 0, sizeof(*gid_pn)); +	memset(fc_req, 0, sizeof(*fc_req));  	ret = zfcp_fc_wka_port_get(&adapter->gs->ds);  	if (ret)  		goto out; -	ret = zfcp_fc_ns_gid_pn_request(port, gid_pn); +	ret = zfcp_fc_ns_gid_pn_request(port, fc_req);  	zfcp_fc_wka_port_put(&adapter->gs->ds);  out: -	mempool_free(gid_pn, adapter->pool.gid_pn); +	mempool_free(fc_req, adapter->pool.gid_pn);  	return ret;  } @@ -360,7 +382,7 @@ void zfcp_fc_port_did_lookup(struct work_struct *work)  	ret = zfcp_fc_ns_gid_pn(port);  	if (ret) {  		/* could not issue gid_pn for some reason */ -		zfcp_erp_adapter_reopen(port->adapter, 0, "fcgpn_1", NULL); +		zfcp_erp_adapter_reopen(port->adapter, 0, "fcgpn_1");  		goto out;  	} @@ -369,7 +391,7 @@ void zfcp_fc_port_did_lookup(struct work_struct *work)  		goto out;  	} -	zfcp_erp_port_reopen(port, 0, "fcgpn_3", NULL); +	zfcp_erp_port_reopen(port, 0, "fcgpn_3");  out:  	put_device(&port->dev);  } @@ -419,14 +441,14 @@ void zfcp_fc_plogi_evaluate(struct zfcp_port *port, struct fc_els_flogi *plogi)  static void zfcp_fc_adisc_handler(void *data)  { -	struct zfcp_fc_els_adisc *adisc = data; -	struct zfcp_port *port = adisc->els.port; -	struct fc_els_adisc *adisc_resp = &adisc->adisc_resp; +	struct zfcp_fc_req *fc_req = data; +	struct zfcp_port *port = fc_req->ct_els.port; +	struct fc_els_adisc *adisc_resp = &fc_req->u.adisc.rsp; -	if (adisc->els.status) { +	if (fc_req->ct_els.status) {  		/* request rejected or timed out */  		zfcp_erp_port_forced_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, -					    "fcadh_1", NULL); +					    "fcadh_1");  		goto out;  	} @@ -436,7 +458,7 @@ static void zfcp_fc_adisc_handler(void *data)  	if ((port->wwpn != adisc_resp->adisc_wwpn) ||  	    !(atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN)) {  		zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, -				     "fcadh_2", NULL); +				     "fcadh_2");  		goto out;  	} @@ -445,42 +467,42 @@ static void zfcp_fc_adisc_handler(void *data)   out:  	atomic_clear_mask(ZFCP_STATUS_PORT_LINK_TEST, &port->status);  	put_device(&port->dev); -	kmem_cache_free(zfcp_data.adisc_cache, adisc); +	kmem_cache_free(zfcp_fc_req_cache, fc_req);  }  static int zfcp_fc_adisc(struct zfcp_port *port)  { -	struct zfcp_fc_els_adisc *adisc; +	struct zfcp_fc_req *fc_req;  	struct zfcp_adapter *adapter = port->adapter; +	struct Scsi_Host *shost = adapter->scsi_host;  	int ret; -	adisc = kmem_cache_zalloc(zfcp_data.adisc_cache, GFP_ATOMIC); -	if (!adisc) +	fc_req = kmem_cache_zalloc(zfcp_fc_req_cache, GFP_ATOMIC); +	if (!fc_req)  		return -ENOMEM; -	adisc->els.port = port; -	adisc->els.req = &adisc->req; -	adisc->els.resp = &adisc->resp; -	sg_init_one(adisc->els.req, &adisc->adisc_req, +	fc_req->ct_els.port = port; +	fc_req->ct_els.req = &fc_req->sg_req; +	fc_req->ct_els.resp = &fc_req->sg_rsp; +	sg_init_one(&fc_req->sg_req, &fc_req->u.adisc.req,  		    sizeof(struct fc_els_adisc)); -	sg_init_one(adisc->els.resp, &adisc->adisc_resp, +	sg_init_one(&fc_req->sg_rsp, &fc_req->u.adisc.rsp,  		    sizeof(struct fc_els_adisc)); -	adisc->els.handler = zfcp_fc_adisc_handler; -	adisc->els.handler_data = adisc; +	fc_req->ct_els.handler = zfcp_fc_adisc_handler; +	fc_req->ct_els.handler_data = fc_req;  	/* acc. to FC-FS, hard_nport_id in ADISC should not be set for ports  	   without FC-AL-2 capability, so we don't set it */ -	adisc->adisc_req.adisc_wwpn = fc_host_port_name(adapter->scsi_host); -	adisc->adisc_req.adisc_wwnn = fc_host_node_name(adapter->scsi_host); -	adisc->adisc_req.adisc_cmd = ELS_ADISC; -	hton24(adisc->adisc_req.adisc_port_id, -	       fc_host_port_id(adapter->scsi_host)); +	fc_req->u.adisc.req.adisc_wwpn = fc_host_port_name(shost); +	fc_req->u.adisc.req.adisc_wwnn = fc_host_node_name(shost); +	fc_req->u.adisc.req.adisc_cmd = ELS_ADISC; +	hton24(fc_req->u.adisc.req.adisc_port_id, fc_host_port_id(shost)); -	ret = zfcp_fsf_send_els(adapter, port->d_id, &adisc->els, +	ret = zfcp_fsf_send_els(adapter, port->d_id, &fc_req->ct_els,  				ZFCP_FC_CTELS_TMO);  	if (ret) -		kmem_cache_free(zfcp_data.adisc_cache, adisc); +		kmem_cache_free(zfcp_fc_req_cache, fc_req);  	return ret;  } @@ -507,7 +529,7 @@ void zfcp_fc_link_test_work(struct work_struct *work)  	/* send of ADISC was not possible */  	atomic_clear_mask(ZFCP_STATUS_PORT_LINK_TEST, &port->status); -	zfcp_erp_port_forced_reopen(port, 0, "fcltwk1", NULL); +	zfcp_erp_port_forced_reopen(port, 0, "fcltwk1");  out:  	put_device(&port->dev); @@ -528,68 +550,42 @@ void zfcp_fc_test_link(struct zfcp_port *port)  		put_device(&port->dev);  } -static void zfcp_free_sg_env(struct zfcp_fc_gpn_ft *gpn_ft, int buf_num) +static struct zfcp_fc_req *zfcp_alloc_sg_env(int buf_num)  { -	struct scatterlist *sg = &gpn_ft->sg_req; +	struct zfcp_fc_req *fc_req; -	kmem_cache_free(zfcp_data.gpn_ft_cache, sg_virt(sg)); -	zfcp_sg_free_table(gpn_ft->sg_resp, buf_num); - -	kfree(gpn_ft); -} - -static struct zfcp_fc_gpn_ft *zfcp_alloc_sg_env(int buf_num) -{ -	struct zfcp_fc_gpn_ft *gpn_ft; -	struct zfcp_fc_gpn_ft_req *req; - -	gpn_ft = kzalloc(sizeof(*gpn_ft), GFP_KERNEL); -	if (!gpn_ft) +	fc_req = kmem_cache_zalloc(zfcp_fc_req_cache, GFP_KERNEL); +	if (!fc_req)  		return NULL; -	req = kmem_cache_zalloc(zfcp_data.gpn_ft_cache, GFP_KERNEL); -	if (!req) { -		kfree(gpn_ft); -		gpn_ft = NULL; -		goto out; +	if (zfcp_sg_setup_table(&fc_req->sg_rsp, buf_num)) { +		kmem_cache_free(zfcp_fc_req_cache, fc_req); +		return NULL;  	} -	sg_init_one(&gpn_ft->sg_req, req, sizeof(*req)); -	if (zfcp_sg_setup_table(gpn_ft->sg_resp, buf_num)) { -		zfcp_free_sg_env(gpn_ft, buf_num); -		gpn_ft = NULL; -	} -out: -	return gpn_ft; -} +	sg_init_one(&fc_req->sg_req, &fc_req->u.gpn_ft.req, +		    sizeof(struct zfcp_fc_gpn_ft_req)); +	return fc_req; +} -static int zfcp_fc_send_gpn_ft(struct zfcp_fc_gpn_ft *gpn_ft, +static int zfcp_fc_send_gpn_ft(struct zfcp_fc_req *fc_req,  			       struct zfcp_adapter *adapter, int max_bytes)  { -	struct zfcp_fsf_ct_els *ct = &gpn_ft->ct; -	struct zfcp_fc_gpn_ft_req *req = sg_virt(&gpn_ft->sg_req); +	struct zfcp_fsf_ct_els *ct_els = &fc_req->ct_els; +	struct zfcp_fc_gpn_ft_req *req = &fc_req->u.gpn_ft.req;  	DECLARE_COMPLETION_ONSTACK(completion);  	int ret; -	/* prepare CT IU for GPN_FT */ -	req->ct_hdr.ct_rev = FC_CT_REV; -	req->ct_hdr.ct_fs_type = FC_FST_DIR; -	req->ct_hdr.ct_fs_subtype = FC_NS_SUBTYPE; -	req->ct_hdr.ct_options = 0; -	req->ct_hdr.ct_cmd = FC_NS_GPN_FT; -	req->ct_hdr.ct_mr_size = max_bytes / 4; -	req->gpn_ft.fn_domain_id_scope = 0; -	req->gpn_ft.fn_area_id_scope = 0; +	zfcp_fc_ct_ns_init(&req->ct_hdr, FC_NS_GPN_FT, max_bytes);  	req->gpn_ft.fn_fc4_type = FC_TYPE_FCP; -	/* prepare zfcp_send_ct */ -	ct->handler = zfcp_fc_complete; -	ct->handler_data = &completion; -	ct->req = &gpn_ft->sg_req; -	ct->resp = gpn_ft->sg_resp; +	ct_els->handler = zfcp_fc_complete; +	ct_els->handler_data = &completion; +	ct_els->req = &fc_req->sg_req; +	ct_els->resp = &fc_req->sg_rsp; -	ret = zfcp_fsf_send_ct(&adapter->gs->ds, ct, NULL, +	ret = zfcp_fsf_send_ct(&adapter->gs->ds, ct_els, NULL,  			       ZFCP_FC_CTELS_TMO);  	if (!ret)  		wait_for_completion(&completion); @@ -610,11 +606,11 @@ static void zfcp_fc_validate_port(struct zfcp_port *port, struct list_head *lh)  	list_move_tail(&port->list, lh);  } -static int zfcp_fc_eval_gpn_ft(struct zfcp_fc_gpn_ft *gpn_ft, +static int zfcp_fc_eval_gpn_ft(struct zfcp_fc_req *fc_req,  			       struct zfcp_adapter *adapter, int max_entries)  { -	struct zfcp_fsf_ct_els *ct = &gpn_ft->ct; -	struct scatterlist *sg = gpn_ft->sg_resp; +	struct zfcp_fsf_ct_els *ct_els = &fc_req->ct_els; +	struct scatterlist *sg = &fc_req->sg_rsp;  	struct fc_ct_hdr *hdr = sg_virt(sg);  	struct fc_gpn_ft_resp *acc = sg_virt(sg);  	struct zfcp_port *port, *tmp; @@ -623,7 +619,7 @@ static int zfcp_fc_eval_gpn_ft(struct zfcp_fc_gpn_ft *gpn_ft,  	u32 d_id;  	int ret = 0, x, last = 0; -	if (ct->status) +	if (ct_els->status)  		return -EIO;  	if (hdr->ct_cmd != FC_FS_ACC) { @@ -659,7 +655,7 @@ static int zfcp_fc_eval_gpn_ft(struct zfcp_fc_gpn_ft *gpn_ft,  		port = zfcp_port_enqueue(adapter, acc->fp_wwpn,  					 ZFCP_STATUS_COMMON_NOESC, d_id);  		if (!IS_ERR(port)) -			zfcp_erp_port_reopen(port, 0, "fcegpf1", NULL); +			zfcp_erp_port_reopen(port, 0, "fcegpf1");  		else if (PTR_ERR(port) != -EEXIST)  			ret = PTR_ERR(port);  	} @@ -671,8 +667,8 @@ static int zfcp_fc_eval_gpn_ft(struct zfcp_fc_gpn_ft *gpn_ft,  	write_unlock_irqrestore(&adapter->port_list_lock, flags);  	list_for_each_entry_safe(port, tmp, &remove_lh, list) { -		zfcp_erp_port_shutdown(port, 0, "fcegpf2", NULL); -		zfcp_device_unregister(&port->dev, &zfcp_sysfs_port_attrs); +		zfcp_erp_port_shutdown(port, 0, "fcegpf2"); +		device_unregister(&port->dev);  	}  	return ret; @@ -687,7 +683,7 @@ void zfcp_fc_scan_ports(struct work_struct *work)  	struct zfcp_adapter *adapter = container_of(work, struct zfcp_adapter,  						    scan_work);  	int ret, i; -	struct zfcp_fc_gpn_ft *gpn_ft; +	struct zfcp_fc_req *fc_req;  	int chain, max_entries, buf_num, max_bytes;  	chain = adapter->adapter_features & FSF_FEATURE_ELS_CT_CHAINED_SBALS; @@ -702,25 +698,145 @@ void zfcp_fc_scan_ports(struct work_struct *work)  	if (zfcp_fc_wka_port_get(&adapter->gs->ds))  		return; -	gpn_ft = zfcp_alloc_sg_env(buf_num); -	if (!gpn_ft) +	fc_req = zfcp_alloc_sg_env(buf_num); +	if (!fc_req)  		goto out;  	for (i = 0; i < 3; i++) { -		ret = zfcp_fc_send_gpn_ft(gpn_ft, adapter, max_bytes); +		ret = zfcp_fc_send_gpn_ft(fc_req, adapter, max_bytes);  		if (!ret) { -			ret = zfcp_fc_eval_gpn_ft(gpn_ft, adapter, max_entries); +			ret = zfcp_fc_eval_gpn_ft(fc_req, adapter, max_entries);  			if (ret == -EAGAIN)  				ssleep(1);  			else  				break;  		}  	} -	zfcp_free_sg_env(gpn_ft, buf_num); +	zfcp_sg_free_table(&fc_req->sg_rsp, buf_num); +	kmem_cache_free(zfcp_fc_req_cache, fc_req);  out:  	zfcp_fc_wka_port_put(&adapter->gs->ds);  } +static int zfcp_fc_gspn(struct zfcp_adapter *adapter, +			struct zfcp_fc_req *fc_req) +{ +	DECLARE_COMPLETION_ONSTACK(completion); +	char devno[] = "DEVNO:"; +	struct zfcp_fsf_ct_els *ct_els = &fc_req->ct_els; +	struct zfcp_fc_gspn_req *gspn_req = &fc_req->u.gspn.req; +	struct zfcp_fc_gspn_rsp *gspn_rsp = &fc_req->u.gspn.rsp; +	int ret; + +	zfcp_fc_ct_ns_init(&gspn_req->ct_hdr, FC_NS_GSPN_ID, +			   FC_SYMBOLIC_NAME_SIZE); +	hton24(gspn_req->gspn.fp_fid, fc_host_port_id(adapter->scsi_host)); + +	sg_init_one(&fc_req->sg_req, gspn_req, sizeof(*gspn_req)); +	sg_init_one(&fc_req->sg_rsp, gspn_rsp, sizeof(*gspn_rsp)); + +	ct_els->handler = zfcp_fc_complete; +	ct_els->handler_data = &completion; +	ct_els->req = &fc_req->sg_req; +	ct_els->resp = &fc_req->sg_rsp; + +	ret = zfcp_fsf_send_ct(&adapter->gs->ds, ct_els, NULL, +			       ZFCP_FC_CTELS_TMO); +	if (ret) +		return ret; + +	wait_for_completion(&completion); +	if (ct_els->status) +		return ct_els->status; + +	if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_NPIV && +	    !(strstr(gspn_rsp->gspn.fp_name, devno))) +		snprintf(fc_host_symbolic_name(adapter->scsi_host), +			 FC_SYMBOLIC_NAME_SIZE, "%s%s %s NAME: %s", +			 gspn_rsp->gspn.fp_name, devno, +			 dev_name(&adapter->ccw_device->dev), +			 init_utsname()->nodename); +	else +		strlcpy(fc_host_symbolic_name(adapter->scsi_host), +			gspn_rsp->gspn.fp_name, FC_SYMBOLIC_NAME_SIZE); + +	return 0; +} + +static void zfcp_fc_rspn(struct zfcp_adapter *adapter, +			 struct zfcp_fc_req *fc_req) +{ +	DECLARE_COMPLETION_ONSTACK(completion); +	struct Scsi_Host *shost = adapter->scsi_host; +	struct zfcp_fsf_ct_els *ct_els = &fc_req->ct_els; +	struct zfcp_fc_rspn_req *rspn_req = &fc_req->u.rspn.req; +	struct fc_ct_hdr *rspn_rsp = &fc_req->u.rspn.rsp; +	int ret, len; + +	zfcp_fc_ct_ns_init(&rspn_req->ct_hdr, FC_NS_RSPN_ID, +			   FC_SYMBOLIC_NAME_SIZE); +	hton24(rspn_req->rspn.fr_fid.fp_fid, fc_host_port_id(shost)); +	len = strlcpy(rspn_req->rspn.fr_name, fc_host_symbolic_name(shost), +		      FC_SYMBOLIC_NAME_SIZE); +	rspn_req->rspn.fr_name_len = len; + +	sg_init_one(&fc_req->sg_req, rspn_req, sizeof(*rspn_req)); +	sg_init_one(&fc_req->sg_rsp, rspn_rsp, sizeof(*rspn_rsp)); + +	ct_els->handler = zfcp_fc_complete; +	ct_els->handler_data = &completion; +	ct_els->req = &fc_req->sg_req; +	ct_els->resp = &fc_req->sg_rsp; + +	ret = zfcp_fsf_send_ct(&adapter->gs->ds, ct_els, NULL, +			       ZFCP_FC_CTELS_TMO); +	if (!ret) +		wait_for_completion(&completion); +} + +/** + * zfcp_fc_sym_name_update - Retrieve and update the symbolic port name + * @work: ns_up_work of the adapter where to update the symbolic port name + * + * Retrieve the current symbolic port name that may have been set by + * the hardware using the GSPN request and update the fc_host + * symbolic_name sysfs attribute. When running in NPIV mode (and hence + * the port name is unique for this system), update the symbolic port + * name to add Linux specific information and update the FC nameserver + * using the RSPN request. + */ +void zfcp_fc_sym_name_update(struct work_struct *work) +{ +	struct zfcp_adapter *adapter = container_of(work, struct zfcp_adapter, +						    ns_up_work); +	int ret; +	struct zfcp_fc_req *fc_req; + +	if (fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPORT && +	    fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPIV) +		return; + +	fc_req = kmem_cache_zalloc(zfcp_fc_req_cache, GFP_KERNEL); +	if (!fc_req) +		return; + +	ret = zfcp_fc_wka_port_get(&adapter->gs->ds); +	if (ret) +		goto out_free; + +	ret = zfcp_fc_gspn(adapter, fc_req); +	if (ret || fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPIV) +		goto out_ds_put; + +	memset(fc_req, 0, sizeof(*fc_req)); +	zfcp_fc_rspn(adapter, fc_req); + +out_ds_put: +	zfcp_fc_wka_port_put(&adapter->gs->ds); +out_free: +	kmem_cache_free(zfcp_fc_req_cache, fc_req); +} +  static void zfcp_fc_ct_els_job_handler(void *data)  {  	struct fc_bsg_job *job = data; diff --git a/drivers/s390/scsi/zfcp_fc.h b/drivers/s390/scsi/zfcp_fc.h index b464ae01086..b1d2024ed51 100644 --- a/drivers/s390/scsi/zfcp_fc.h +++ b/drivers/s390/scsi/zfcp_fc.h @@ -4,7 +4,7 @@   * Fibre Channel related definitions and inline functions for the zfcp   * device driver   * - * Copyright IBM Corporation 2009 + * Copyright IBM Corp. 2009   */  #ifndef ZFCP_FC_H @@ -64,33 +64,16 @@ struct zfcp_fc_gid_pn_req {  } __packed;  /** - * struct zfcp_fc_gid_pn_resp - container for ct header plus gid_pn response + * struct zfcp_fc_gid_pn_rsp - container for ct header plus gid_pn response   * @ct_hdr: FC GS common transport header   * @gid_pn: GID_PN response   */ -struct zfcp_fc_gid_pn_resp { +struct zfcp_fc_gid_pn_rsp {  	struct fc_ct_hdr	ct_hdr;  	struct fc_gid_pn_resp	gid_pn;  } __packed;  /** - * struct zfcp_fc_gid_pn - everything required in zfcp for gid_pn request - * @ct: data passed to zfcp_fsf for issuing fsf request - * @sg_req: scatterlist entry for request data - * @sg_resp: scatterlist entry for response data - * @gid_pn_req: GID_PN request data - * @gid_pn_resp: GID_PN response data - */ -struct zfcp_fc_gid_pn { -	struct zfcp_fsf_ct_els ct; -	struct scatterlist sg_req; -	struct scatterlist sg_resp; -	struct zfcp_fc_gid_pn_req gid_pn_req; -	struct zfcp_fc_gid_pn_resp gid_pn_resp; -	struct zfcp_port *port; -}; - -/**   * struct zfcp_fc_gpn_ft - container for ct header plus gpn_ft request   * @ct_hdr: FC GS common transport header   * @gpn_ft: GPN_FT request @@ -101,41 +84,72 @@ struct zfcp_fc_gpn_ft_req {  } __packed;  /** - * struct zfcp_fc_gpn_ft_resp - container for ct header plus gpn_ft response + * struct zfcp_fc_gspn_req - container for ct header plus GSPN_ID request   * @ct_hdr: FC GS common transport header - * @gpn_ft: Array of gpn_ft response data to fill one memory page + * @gspn: GSPN_ID request   */ -struct zfcp_fc_gpn_ft_resp { +struct zfcp_fc_gspn_req {  	struct fc_ct_hdr	ct_hdr; -	struct fc_gpn_ft_resp	gpn_ft[ZFCP_FC_GPN_FT_ENT_PAGE]; +	struct fc_gid_pn_resp	gspn;  } __packed;  /** - * struct zfcp_fc_gpn_ft - zfcp data for gpn_ft request - * @ct: data passed to zfcp_fsf for issuing fsf request - * @sg_req: scatter list entry for gpn_ft request - * @sg_resp: scatter list entries for gpn_ft responses (per memory page) + * struct zfcp_fc_gspn_rsp - container for ct header plus GSPN_ID response + * @ct_hdr: FC GS common transport header + * @gspn: GSPN_ID response + * @name: The name string of the GSPN_ID response   */ -struct zfcp_fc_gpn_ft { -	struct zfcp_fsf_ct_els ct; -	struct scatterlist sg_req; -	struct scatterlist sg_resp[ZFCP_FC_GPN_FT_NUM_BUFS]; -}; +struct zfcp_fc_gspn_rsp { +	struct fc_ct_hdr	ct_hdr; +	struct fc_gspn_resp	gspn; +	char			name[FC_SYMBOLIC_NAME_SIZE]; +} __packed;  /** - * struct zfcp_fc_els_adisc - everything required in zfcp for issuing ELS ADISC - * @els: data required for issuing els fsf command - * @req: scatterlist entry for ELS ADISC request - * @resp: scatterlist entry for ELS ADISC response - * @adisc_req: ELS ADISC request data - * @adisc_resp: ELS ADISC response data + * struct zfcp_fc_rspn_req - container for ct header plus RSPN_ID request + * @ct_hdr: FC GS common transport header + * @rspn: RSPN_ID request + * @name: The name string of the RSPN_ID request   */ -struct zfcp_fc_els_adisc { -	struct zfcp_fsf_ct_els els; -	struct scatterlist req; -	struct scatterlist resp; -	struct fc_els_adisc adisc_req; -	struct fc_els_adisc adisc_resp; +struct zfcp_fc_rspn_req { +	struct fc_ct_hdr	ct_hdr; +	struct fc_ns_rspn	rspn; +	char			name[FC_SYMBOLIC_NAME_SIZE]; +} __packed; + +/** + * struct zfcp_fc_req - Container for FC ELS and CT requests sent from zfcp + * @ct_els: data required for issuing fsf command + * @sg_req: scatterlist entry for request data + * @sg_rsp: scatterlist entry for response data + * @u: request specific data + */ +struct zfcp_fc_req { +	struct zfcp_fsf_ct_els				ct_els; +	struct scatterlist				sg_req; +	struct scatterlist				sg_rsp; +	union { +		struct { +			struct fc_els_adisc		req; +			struct fc_els_adisc		rsp; +		} adisc; +		struct { +			struct zfcp_fc_gid_pn_req	req; +			struct zfcp_fc_gid_pn_rsp	rsp; +		} gid_pn; +		struct { +			struct scatterlist sg_rsp2[ZFCP_FC_GPN_FT_NUM_BUFS - 1]; +			struct zfcp_fc_gpn_ft_req	req; +		} gpn_ft; +		struct { +			struct zfcp_fc_gspn_req		req; +			struct zfcp_fc_gspn_rsp		rsp; +		} gspn; +		struct { +			struct zfcp_fc_rspn_req		req; +			struct fc_ct_hdr		rsp; +		} rspn; +	} u;  };  /** @@ -192,14 +206,21 @@ struct zfcp_fc_wka_ports {   * zfcp_fc_scsi_to_fcp - setup FCP command with data from scsi_cmnd   * @fcp: fcp_cmnd to setup   * @scsi: scsi_cmnd where to get LUN, task attributes/flags and CDB + * @tm: task management flags to setup task management command   */  static inline -void zfcp_fc_scsi_to_fcp(struct fcp_cmnd *fcp, struct scsi_cmnd *scsi) +void zfcp_fc_scsi_to_fcp(struct fcp_cmnd *fcp, struct scsi_cmnd *scsi, +			 u8 tm_flags)  {  	char tag[2];  	int_to_scsilun(scsi->device->lun, (struct scsi_lun *) &fcp->fc_lun); +	if (unlikely(tm_flags)) { +		fcp->fc_tm_flags = tm_flags; +		return; +	} +  	if (scsi_populate_tag_msg(scsi, tag)) {  		switch (tag[0]) {  		case MSG_ORDERED_TAG: @@ -226,19 +247,6 @@ void zfcp_fc_scsi_to_fcp(struct fcp_cmnd *fcp, struct scsi_cmnd *scsi)  }  /** - * zfcp_fc_fcp_tm - setup FCP command as task management command - * @fcp: fcp_cmnd to setup - * @dev: scsi_device where to send the task management command - * @tm: task management flags to setup tm command - */ -static inline -void zfcp_fc_fcp_tm(struct fcp_cmnd *fcp, struct scsi_device *dev, u8 tm_flags) -{ -	int_to_scsilun(dev->lun, (struct scsi_lun *) &fcp->fc_lun); -	fcp->fc_tm_flags |= tm_flags; -} - -/**   * zfcp_fc_evap_fcp_rsp - evaluate FCP RSP IU and update scsi_cmnd accordingly   * @fcp_rsp: FCP RSP IU to evaluate   * @scsi: SCSI command where to update status and sense buffer diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index be031745714..0fe8d5d9511 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -3,7 +3,7 @@   *   * Implementation of FSF commands.   * - * Copyright IBM Corporation 2002, 2010 + * Copyright IBM Corp. 2002, 2013   */  #define KMSG_COMPONENT "zfcp" @@ -18,12 +18,14 @@  #include "zfcp_qdio.h"  #include "zfcp_reqlist.h" +struct kmem_cache *zfcp_fsf_qtcb_cache; +  static void zfcp_fsf_request_timeout_handler(unsigned long data)  {  	struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;  	zfcp_qdio_siosl(adapter);  	zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, -				"fsrth_1", NULL); +				"fsrth_1");  }  static void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req, @@ -65,7 +67,7 @@ static void zfcp_fsf_class_not_supp(struct zfcp_fsf_req *req)  {  	dev_err(&req->adapter->ccw_device->dev, "FCP device not "  		"operational because of an unsupported FC class\n"); -	zfcp_erp_adapter_shutdown(req->adapter, 0, "fscns_1", req); +	zfcp_erp_adapter_shutdown(req->adapter, 0, "fscns_1");  	req->status |= ZFCP_STATUS_FSFREQ_ERROR;  } @@ -83,7 +85,7 @@ void zfcp_fsf_req_free(struct zfcp_fsf_req *req)  	}  	if (likely(req->qtcb)) -		kmem_cache_free(zfcp_data.qtcb_cache, req->qtcb); +		kmem_cache_free(zfcp_fsf_qtcb_cache, req->qtcb);  	kfree(req);  } @@ -98,7 +100,7 @@ static void zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *req)  	read_lock_irqsave(&adapter->port_list_lock, flags);  	list_for_each_entry(port, &adapter->port_list, list)  		if (port->d_id == d_id) { -			zfcp_erp_port_reopen(port, 0, "fssrpc1", req); +			zfcp_erp_port_reopen(port, 0, "fssrpc1");  			break;  		}  	read_unlock_irqrestore(&adapter->port_list_lock, flags); @@ -211,13 +213,13 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req)  	struct fsf_status_read_buffer *sr_buf = req->data;  	if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED) { -		zfcp_dbf_hba_fsf_unsol("dism", adapter->dbf, sr_buf); -		mempool_free(sr_buf, adapter->pool.status_read_data); +		zfcp_dbf_hba_fsf_uss("fssrh_1", req); +		mempool_free(virt_to_page(sr_buf), adapter->pool.sr_data);  		zfcp_fsf_req_free(req);  		return;  	} -	zfcp_dbf_hba_fsf_unsol("read", adapter->dbf, sr_buf); +	zfcp_dbf_hba_fsf_uss("fssrh_4", req);  	switch (sr_buf->status_type) {  	case FSF_STATUS_READ_PORT_CLOSED: @@ -232,7 +234,7 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req)  		dev_warn(&adapter->ccw_device->dev,  			 "The error threshold for checksum statistics "  			 "has been exceeded\n"); -		zfcp_dbf_hba_berr(adapter->dbf, req); +		zfcp_dbf_hba_bit_err("fssrh_3", req);  		break;  	case FSF_STATUS_READ_LINK_DOWN:  		zfcp_fsf_status_read_link_down(req); @@ -247,25 +249,20 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req)  		zfcp_erp_adapter_reopen(adapter,  					ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |  					ZFCP_STATUS_COMMON_ERP_FAILED, -					"fssrh_2", req); +					"fssrh_2");  		zfcp_fc_enqueue_event(adapter, FCH_EVT_LINKUP, 0);  		break;  	case FSF_STATUS_READ_NOTIFICATION_LOST: -		if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_ACT_UPDATED) -			zfcp_cfdc_adapter_access_changed(adapter);  		if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_INCOMING_ELS) -			queue_work(adapter->work_queue, &adapter->scan_work); -		break; -	case FSF_STATUS_READ_CFDC_UPDATED: -		zfcp_cfdc_adapter_access_changed(adapter); +			zfcp_fc_conditional_port_scan(adapter);  		break;  	case FSF_STATUS_READ_FEATURE_UPDATE_ALERT:  		adapter->adapter_features = sr_buf->payload.word[0];  		break;  	} -	mempool_free(sr_buf, adapter->pool.status_read_data); +	mempool_free(virt_to_page(sr_buf), adapter->pool.sr_data);  	zfcp_fsf_req_free(req);  	atomic_inc(&adapter->stat_miss); @@ -287,7 +284,7 @@ static void zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *req)  			"The FCP adapter reported a problem "  			"that cannot be recovered\n");  		zfcp_qdio_siosl(req->adapter); -		zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfsqe1", req); +		zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfsqe1");  		break;  	}  	/* all non-return stats set FSFREQ_ERROR*/ @@ -304,7 +301,7 @@ static void zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *req)  		dev_err(&req->adapter->ccw_device->dev,  			"The FCP adapter does not recognize the command 0x%x\n",  			req->qtcb->header.fsf_command); -		zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfse_1", req); +		zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfse_1");  		req->status |= ZFCP_STATUS_FSFREQ_ERROR;  		break;  	case FSF_ADAPTER_STATUS_AVAILABLE: @@ -335,17 +332,17 @@ static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req)  			"QTCB version 0x%x not supported by FCP adapter "  			"(0x%x to 0x%x)\n", FSF_QTCB_CURRENT_VERSION,  			psq->word[0], psq->word[1]); -		zfcp_erp_adapter_shutdown(adapter, 0, "fspse_1", req); +		zfcp_erp_adapter_shutdown(adapter, 0, "fspse_1");  		break;  	case FSF_PROT_ERROR_STATE:  	case FSF_PROT_SEQ_NUMB_ERROR: -		zfcp_erp_adapter_reopen(adapter, 0, "fspse_2", req); +		zfcp_erp_adapter_reopen(adapter, 0, "fspse_2");  		req->status |= ZFCP_STATUS_FSFREQ_ERROR;  		break;  	case FSF_PROT_UNSUPP_QTCB_TYPE:  		dev_err(&adapter->ccw_device->dev,  			"The QTCB type is not supported by the FCP adapter\n"); -		zfcp_erp_adapter_shutdown(adapter, 0, "fspse_3", req); +		zfcp_erp_adapter_shutdown(adapter, 0, "fspse_3");  		break;  	case FSF_PROT_HOST_CONNECTION_INITIALIZING:  		atomic_set_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, @@ -355,12 +352,12 @@ static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req)  		dev_err(&adapter->ccw_device->dev,  			"0x%Lx is an ambiguous request identifier\n",  			(unsigned long long)qtcb->bottom.support.req_handle); -		zfcp_erp_adapter_shutdown(adapter, 0, "fspse_4", req); +		zfcp_erp_adapter_shutdown(adapter, 0, "fspse_4");  		break;  	case FSF_PROT_LINK_DOWN:  		zfcp_fsf_link_down_info_eval(req, &psq->link_down_info);  		/* go through reopen to flush pending requests */ -		zfcp_erp_adapter_reopen(adapter, 0, "fspse_6", req); +		zfcp_erp_adapter_reopen(adapter, 0, "fspse_6");  		break;  	case FSF_PROT_REEST_QUEUE:  		/* All ports should be marked as ready to run again */ @@ -369,14 +366,14 @@ static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req)  		zfcp_erp_adapter_reopen(adapter,  					ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |  					ZFCP_STATUS_COMMON_ERP_FAILED, -					"fspse_8", req); +					"fspse_8");  		break;  	default:  		dev_err(&adapter->ccw_device->dev,  			"0x%x is not a valid transfer protocol status\n",  			qtcb->prefix.prot_status);  		zfcp_qdio_siosl(adapter); -		zfcp_erp_adapter_shutdown(adapter, 0, "fspse_9", req); +		zfcp_erp_adapter_shutdown(adapter, 0, "fspse_9");  	}  	req->status |= ZFCP_STATUS_FSFREQ_ERROR;  } @@ -435,6 +432,34 @@ void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter)  	}  } +#define ZFCP_FSF_PORTSPEED_1GBIT	(1 <<  0) +#define ZFCP_FSF_PORTSPEED_2GBIT	(1 <<  1) +#define ZFCP_FSF_PORTSPEED_4GBIT	(1 <<  2) +#define ZFCP_FSF_PORTSPEED_10GBIT	(1 <<  3) +#define ZFCP_FSF_PORTSPEED_8GBIT	(1 <<  4) +#define ZFCP_FSF_PORTSPEED_16GBIT	(1 <<  5) +#define ZFCP_FSF_PORTSPEED_NOT_NEGOTIATED (1 << 15) + +static u32 zfcp_fsf_convert_portspeed(u32 fsf_speed) +{ +	u32 fdmi_speed = 0; +	if (fsf_speed & ZFCP_FSF_PORTSPEED_1GBIT) +		fdmi_speed |= FC_PORTSPEED_1GBIT; +	if (fsf_speed & ZFCP_FSF_PORTSPEED_2GBIT) +		fdmi_speed |= FC_PORTSPEED_2GBIT; +	if (fsf_speed & ZFCP_FSF_PORTSPEED_4GBIT) +		fdmi_speed |= FC_PORTSPEED_4GBIT; +	if (fsf_speed & ZFCP_FSF_PORTSPEED_10GBIT) +		fdmi_speed |= FC_PORTSPEED_10GBIT; +	if (fsf_speed & ZFCP_FSF_PORTSPEED_8GBIT) +		fdmi_speed |= FC_PORTSPEED_8GBIT; +	if (fsf_speed & ZFCP_FSF_PORTSPEED_16GBIT) +		fdmi_speed |= FC_PORTSPEED_16GBIT; +	if (fsf_speed & ZFCP_FSF_PORTSPEED_NOT_NEGOTIATED) +		fdmi_speed |= FC_PORTSPEED_NOT_NEGOTIATED; +	return fdmi_speed; +} +  static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req)  {  	struct fsf_qtcb_bottom_config *bottom = &req->qtcb->bottom.config; @@ -453,11 +478,8 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req)  	fc_host_port_name(shost) = nsp->fl_wwpn;  	fc_host_node_name(shost) = nsp->fl_wwnn; -	fc_host_port_id(shost) = ntoh24(bottom->s_id); -	fc_host_speed(shost) = bottom->fc_link_speed;  	fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3; -	adapter->hydra_version = bottom->adapter_type;  	adapter->timer_ticks = bottom->timer_interval & ZFCP_FSF_TIMER_INT_MASK;  	adapter->stat_read_buf_num = max(bottom->status_read_buf_num,  					 (u16)FSF_STATUS_READS_RECOM); @@ -465,6 +487,19 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req)  	if (fc_host_permanent_port_name(shost) == -1)  		fc_host_permanent_port_name(shost) = fc_host_port_name(shost); +	zfcp_scsi_set_prot(adapter); + +	/* no error return above here, otherwise must fix call chains */ +	/* do not evaluate invalid fields */ +	if (req->qtcb->header.fsf_status == FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE) +		return 0; + +	fc_host_port_id(shost) = ntoh24(bottom->s_id); +	fc_host_speed(shost) = +		zfcp_fsf_convert_portspeed(bottom->fc_link_speed); + +	adapter->hydra_version = bottom->adapter_type; +  	switch (bottom->fc_topology) {  	case FSF_TOPO_P2P:  		adapter->peer_d_id = ntoh24(bottom->peer_d_id); @@ -482,12 +517,10 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req)  		dev_err(&adapter->ccw_device->dev,  			"Unknown or unsupported arbitrated loop "  			"fibre channel topology detected\n"); -		zfcp_erp_adapter_shutdown(adapter, 0, "fsece_1", req); +		zfcp_erp_adapter_shutdown(adapter, 0, "fsece_1");  		return -EIO;  	} -	zfcp_scsi_set_prot(adapter); -  	return 0;  } @@ -518,7 +551,7 @@ static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req)  				"FCP adapter maximum QTCB size (%d bytes) "  				"is too small\n",  				bottom->max_qtcb_size); -			zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh1", req); +			zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh1");  			return;  		}  		atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, @@ -532,11 +565,17 @@ static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req)  		fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN;  		adapter->hydra_version = 0; +		/* avoids adapter shutdown to be able to recognize +		 * events such as LINK UP */ +		atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, +				&adapter->status);  		zfcp_fsf_link_down_info_eval(req,  			&qtcb->header.fsf_status_qual.link_down_info); +		if (zfcp_fsf_exchange_config_evaluate(req)) +			return;  		break;  	default: -		zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh3", req); +		zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh3");  		return;  	} @@ -552,14 +591,14 @@ static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req)  		dev_err(&adapter->ccw_device->dev,  			"The FCP adapter only supports newer "  			"control block versions\n"); -		zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh4", req); +		zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh4");  		return;  	}  	if (FSF_QTCB_CURRENT_VERSION > bottom->high_qtcb_version) {  		dev_err(&adapter->ccw_device->dev,  			"The FCP adapter only supports older "  			"control block versions\n"); -		zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh5", req); +		zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh5");  	}  } @@ -578,7 +617,8 @@ static void zfcp_fsf_exchange_port_evaluate(struct zfcp_fsf_req *req)  	} else  		fc_host_permanent_port_name(shost) = fc_host_port_name(shost);  	fc_host_maxframe_size(shost) = bottom->maximum_frame_size; -	fc_host_supported_speeds(shost) = bottom->supported_speed; +	fc_host_supported_speeds(shost) = +		zfcp_fsf_convert_portspeed(bottom->supported_speed);  	memcpy(fc_host_supported_fc4s(shost), bottom->supported_fc4_types,  	       FC_FC4_LIST_SIZE);  	memcpy(fc_host_active_fc4s(shost), bottom->active_fc4_types, @@ -628,7 +668,7 @@ static struct fsf_qtcb *zfcp_qtcb_alloc(mempool_t *pool)  	if (likely(pool))  		qtcb = mempool_alloc(pool, GFP_ATOMIC);  	else -		qtcb = kmem_cache_alloc(zfcp_data.qtcb_cache, GFP_ATOMIC); +		qtcb = kmem_cache_alloc(zfcp_fsf_qtcb_cache, GFP_ATOMIC);  	if (unlikely(!qtcb))  		return NULL; @@ -638,7 +678,7 @@ static struct fsf_qtcb *zfcp_qtcb_alloc(mempool_t *pool)  }  static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_qdio *qdio, -						u32 fsf_cmd, u32 sbtype, +						u32 fsf_cmd, u8 sbtype,  						mempool_t *pool)  {  	struct zfcp_adapter *adapter = qdio->adapter; @@ -695,12 +735,12 @@ static int zfcp_fsf_req_send(struct zfcp_fsf_req *req)  	zfcp_reqlist_add(adapter->req_list, req);  	req->qdio_req.qdio_outb_usage = atomic_read(&qdio->req_q_free); -	req->issued = get_clock(); +	req->issued = get_tod_clock();  	if (zfcp_qdio_send(qdio, &req->qdio_req)) {  		del_timer(&req->timer);  		/* lookup request again, list might have changed */  		zfcp_reqlist_find_rm(adapter->req_list, req_id); -		zfcp_erp_adapter_reopen(adapter, 0, "fsrs__1", req); +		zfcp_erp_adapter_reopen(adapter, 0, "fsrs__1");  		return -EIO;  	} @@ -723,24 +763,27 @@ int zfcp_fsf_status_read(struct zfcp_qdio *qdio)  	struct zfcp_adapter *adapter = qdio->adapter;  	struct zfcp_fsf_req *req;  	struct fsf_status_read_buffer *sr_buf; +	struct page *page;  	int retval = -EIO;  	spin_lock_irq(&qdio->req_q_lock);  	if (zfcp_qdio_sbal_get(qdio))  		goto out; -	req = zfcp_fsf_req_create(qdio, FSF_QTCB_UNSOLICITED_STATUS, 0, +	req = zfcp_fsf_req_create(qdio, FSF_QTCB_UNSOLICITED_STATUS, +				  SBAL_SFLAGS0_TYPE_STATUS,  				  adapter->pool.status_read_req);  	if (IS_ERR(req)) {  		retval = PTR_ERR(req);  		goto out;  	} -	sr_buf = mempool_alloc(adapter->pool.status_read_data, GFP_ATOMIC); -	if (!sr_buf) { +	page = mempool_alloc(adapter->pool.sr_data, GFP_ATOMIC); +	if (!page) {  		retval = -ENOMEM;  		goto failed_buf;  	} +	sr_buf = page_address(page);  	memset(sr_buf, 0, sizeof(*sr_buf));  	req->data = sr_buf; @@ -754,10 +797,11 @@ int zfcp_fsf_status_read(struct zfcp_qdio *qdio)  	goto out;  failed_req_send: -	mempool_free(sr_buf, adapter->pool.status_read_data); +	req->data = NULL; +	mempool_free(virt_to_page(sr_buf), adapter->pool.sr_data);  failed_buf: +	zfcp_dbf_hba_fsf_uss("fssr__1", req);  	zfcp_fsf_req_free(req); -	zfcp_dbf_hba_fsf_unsol("fail", adapter->dbf, NULL);  out:  	spin_unlock_irq(&qdio->req_q_lock);  	return retval; @@ -766,24 +810,25 @@ out:  static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req)  {  	struct scsi_device *sdev = req->data; -	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); +	struct zfcp_scsi_dev *zfcp_sdev;  	union fsf_status_qual *fsq = &req->qtcb->header.fsf_status_qual;  	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)  		return; +	zfcp_sdev = sdev_to_zfcp(sdev); +  	switch (req->qtcb->header.fsf_status) {  	case FSF_PORT_HANDLE_NOT_VALID:  		if (fsq->word[0] == fsq->word[1]) {  			zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0, -						"fsafch1", req); +						"fsafch1");  			req->status |= ZFCP_STATUS_FSFREQ_ERROR;  		}  		break;  	case FSF_LUN_HANDLE_NOT_VALID:  		if (fsq->word[0] == fsq->word[1]) { -			zfcp_erp_port_reopen(zfcp_sdev->port, 0, "fsafch2", -					     req); +			zfcp_erp_port_reopen(zfcp_sdev->port, 0, "fsafch2");  			req->status |= ZFCP_STATUS_FSFREQ_ERROR;  		}  		break; @@ -794,14 +839,13 @@ static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req)  		zfcp_erp_set_port_status(zfcp_sdev->port,  					 ZFCP_STATUS_COMMON_ACCESS_BOXED);  		zfcp_erp_port_reopen(zfcp_sdev->port, -				     ZFCP_STATUS_COMMON_ERP_FAILED, "fsafch3", -				     req); +				     ZFCP_STATUS_COMMON_ERP_FAILED, "fsafch3");  		req->status |= ZFCP_STATUS_FSFREQ_ERROR;  		break;  	case FSF_LUN_BOXED:  		zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ACCESS_BOXED);  		zfcp_erp_lun_reopen(sdev, ZFCP_STATUS_COMMON_ERP_FAILED, -				    "fsafch4", req); +				    "fsafch4");  		req->status |= ZFCP_STATUS_FSFREQ_ERROR;                  break;  	case FSF_ADAPTER_STATUS_AVAILABLE: @@ -838,7 +882,7 @@ struct zfcp_fsf_req *zfcp_fsf_abort_fcp_cmnd(struct scsi_cmnd *scmnd)  	if (zfcp_qdio_sbal_get(qdio))  		goto out;  	req = zfcp_fsf_req_create(qdio, FSF_QTCB_ABORT_FCP_CMND, -				  SBAL_FLAGS0_TYPE_READ, +				  SBAL_SFLAGS0_TYPE_READ,  				  qdio->adapter->pool.scsi_abort);  	if (IS_ERR(req)) {  		req = NULL; @@ -851,7 +895,7 @@ struct zfcp_fsf_req *zfcp_fsf_abort_fcp_cmnd(struct scsi_cmnd *scmnd)  	zfcp_qdio_set_sbale_last(qdio, &req->qdio_req); -	req->data = zfcp_sdev; +	req->data = sdev;  	req->handler = zfcp_fsf_abort_fcp_command_handler;  	req->qtcb->header.lun_handle = zfcp_sdev->lun_handle;  	req->qtcb->header.port_handle = zfcp_sdev->port->handle; @@ -882,7 +926,7 @@ static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req)  	switch (header->fsf_status) {          case FSF_GOOD: -		zfcp_dbf_san_ct_response(req); +		zfcp_dbf_san_res("fsscth2", req);  		ct->status = 0;  		break;          case FSF_SERVICE_CLASS_NOT_SUPPORTED: @@ -896,13 +940,11 @@ static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req)  			break;                  }                  break; -	case FSF_ACCESS_DENIED: -		break;          case FSF_PORT_BOXED:  		req->status |= ZFCP_STATUS_FSFREQ_ERROR;  		break;  	case FSF_PORT_HANDLE_NOT_VALID: -		zfcp_erp_adapter_reopen(adapter, 0, "fsscth1", req); +		zfcp_erp_adapter_reopen(adapter, 0, "fsscth1");  		/* fall through */  	case FSF_GENERIC_COMMAND_REJECTED:  	case FSF_PAYLOAD_SIZE_MISMATCH: @@ -933,39 +975,47 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,  				       struct scatterlist *sg_resp)  {  	struct zfcp_adapter *adapter = req->adapter; +	struct zfcp_qdio *qdio = adapter->qdio; +	struct fsf_qtcb *qtcb = req->qtcb;  	u32 feat = adapter->adapter_features; -	int bytes; -	if (!(feat & FSF_FEATURE_ELS_CT_CHAINED_SBALS)) { -		if (!zfcp_qdio_sg_one_sbale(sg_req) || -		    !zfcp_qdio_sg_one_sbale(sg_resp)) -			return -EOPNOTSUPP; +	if (zfcp_adapter_multi_buffer_active(adapter)) { +		if (zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, sg_req)) +			return -EIO; +		if (zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, sg_resp)) +			return -EIO; -		zfcp_fsf_setup_ct_els_unchained(adapter->qdio, &req->qdio_req, -						sg_req, sg_resp); +		zfcp_qdio_set_data_div(qdio, &req->qdio_req, +					zfcp_qdio_sbale_count(sg_req)); +		zfcp_qdio_set_sbale_last(qdio, &req->qdio_req); +		zfcp_qdio_set_scount(qdio, &req->qdio_req);  		return 0;  	}  	/* use single, unchained SBAL if it can hold the request */  	if (zfcp_qdio_sg_one_sbale(sg_req) && zfcp_qdio_sg_one_sbale(sg_resp)) { -		zfcp_fsf_setup_ct_els_unchained(adapter->qdio, &req->qdio_req, +		zfcp_fsf_setup_ct_els_unchained(qdio, &req->qdio_req,  						sg_req, sg_resp);  		return 0;  	} -	bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->qdio_req, sg_req); -	if (bytes <= 0) +	if (!(feat & FSF_FEATURE_ELS_CT_CHAINED_SBALS)) +		return -EOPNOTSUPP; + +	if (zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, sg_req))  		return -EIO; -	zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req); -	req->qtcb->bottom.support.req_buf_length = bytes; -	zfcp_qdio_skip_to_last_sbale(&req->qdio_req); -	bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->qdio_req, -					sg_resp); -	req->qtcb->bottom.support.resp_buf_length = bytes; -	if (bytes <= 0) +	qtcb->bottom.support.req_buf_length = zfcp_qdio_real_bytes(sg_req); + +	zfcp_qdio_set_sbale_last(qdio, &req->qdio_req); +	zfcp_qdio_skip_to_last_sbale(qdio, &req->qdio_req); + +	if (zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, sg_resp))  		return -EIO; -	zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req); + +	qtcb->bottom.support.resp_buf_length = zfcp_qdio_real_bytes(sg_resp); + +	zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);  	return 0;  } @@ -1009,7 +1059,7 @@ int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *wka_port,  		goto out;  	req = zfcp_fsf_req_create(qdio, FSF_QTCB_SEND_GENERIC, -				  SBAL_FLAGS0_TYPE_WRITE_READ, pool); +				  SBAL_SFLAGS0_TYPE_WRITE_READ, pool);  	if (IS_ERR(req)) {  		ret = PTR_ERR(req); @@ -1025,7 +1075,7 @@ int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *wka_port,  	req->qtcb->header.port_handle = wka_port->handle;  	req->data = ct; -	zfcp_dbf_san_ct_request(req, wka_port->d_id); +	zfcp_dbf_san_req("fssct_1", req, wka_port->d_id);  	ret = zfcp_fsf_req_send(req);  	if (ret) @@ -1043,7 +1093,6 @@ out:  static void zfcp_fsf_send_els_handler(struct zfcp_fsf_req *req)  {  	struct zfcp_fsf_ct_els *send_els = req->data; -	struct zfcp_port *port = send_els->port;  	struct fsf_qtcb_header *header = &req->qtcb->header;  	send_els->status = -EINVAL; @@ -1053,7 +1102,7 @@ static void zfcp_fsf_send_els_handler(struct zfcp_fsf_req *req)  	switch (header->fsf_status) {  	case FSF_GOOD: -		zfcp_dbf_san_els_response(req); +		zfcp_dbf_san_res("fsselh1", req);  		send_els->status = 0;  		break;  	case FSF_SERVICE_CLASS_NOT_SUPPORTED: @@ -1073,14 +1122,8 @@ static void zfcp_fsf_send_els_handler(struct zfcp_fsf_req *req)  	case FSF_REQUEST_SIZE_TOO_LARGE:  	case FSF_RESPONSE_SIZE_TOO_LARGE:  		break; -	case FSF_ACCESS_DENIED: -		if (port) { -			zfcp_cfdc_port_denied(port, &header->fsf_status_qual); -			req->status |= ZFCP_STATUS_FSFREQ_ERROR; -		} -		break;  	case FSF_SBAL_MISMATCH: -		/* should never occure, avoided in zfcp_fsf_send_els */ +		/* should never occur, avoided in zfcp_fsf_send_els */  		/* fall through */  	default:  		req->status |= ZFCP_STATUS_FSFREQ_ERROR; @@ -1107,7 +1150,7 @@ int zfcp_fsf_send_els(struct zfcp_adapter *adapter, u32 d_id,  		goto out;  	req = zfcp_fsf_req_create(qdio, FSF_QTCB_SEND_ELS, -				  SBAL_FLAGS0_TYPE_WRITE_READ, NULL); +				  SBAL_SFLAGS0_TYPE_WRITE_READ, NULL);  	if (IS_ERR(req)) {  		ret = PTR_ERR(req); @@ -1116,7 +1159,8 @@ int zfcp_fsf_send_els(struct zfcp_adapter *adapter, u32 d_id,  	req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; -	zfcp_qdio_sbal_limit(qdio, &req->qdio_req, 2); +	if (!zfcp_adapter_multi_buffer_active(adapter)) +		zfcp_qdio_sbal_limit(qdio, &req->qdio_req, 2);  	ret = zfcp_fsf_setup_ct_els(req, els->req, els->resp, timeout); @@ -1127,7 +1171,7 @@ int zfcp_fsf_send_els(struct zfcp_adapter *adapter, u32 d_id,  	req->handler = zfcp_fsf_send_els_handler;  	req->data = els; -	zfcp_dbf_san_els_request(req); +	zfcp_dbf_san_req("fssels1", req, d_id);  	ret = zfcp_fsf_req_send(req);  	if (ret) @@ -1153,7 +1197,7 @@ int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)  		goto out;  	req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_CONFIG_DATA, -				  SBAL_FLAGS0_TYPE_READ, +				  SBAL_SFLAGS0_TYPE_READ,  				  qdio->adapter->pool.erp_req);  	if (IS_ERR(req)) { @@ -1165,8 +1209,6 @@ int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)  	zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);  	req->qtcb->bottom.config.feature_selection = -			FSF_FEATURE_CFDC | -			FSF_FEATURE_LUN_SHARING |  			FSF_FEATURE_NOTIFICATION_LOST |  			FSF_FEATURE_UPDATE_ALERT;  	req->erp_action = erp_action; @@ -1195,7 +1237,7 @@ int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *qdio,  		goto out_unlock;  	req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_CONFIG_DATA, -				  SBAL_FLAGS0_TYPE_READ, NULL); +				  SBAL_SFLAGS0_TYPE_READ, NULL);  	if (IS_ERR(req)) {  		retval = PTR_ERR(req); @@ -1206,8 +1248,6 @@ int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *qdio,  	req->handler = zfcp_fsf_exchange_config_data_handler;  	req->qtcb->bottom.config.feature_selection = -			FSF_FEATURE_CFDC | -			FSF_FEATURE_LUN_SHARING |  			FSF_FEATURE_NOTIFICATION_LOST |  			FSF_FEATURE_UPDATE_ALERT; @@ -1247,7 +1287,7 @@ int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action)  		goto out;  	req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_PORT_DATA, -				  SBAL_FLAGS0_TYPE_READ, +				  SBAL_SFLAGS0_TYPE_READ,  				  qdio->adapter->pool.erp_req);  	if (IS_ERR(req)) { @@ -1293,7 +1333,7 @@ int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *qdio,  		goto out_unlock;  	req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_PORT_DATA, -				  SBAL_FLAGS0_TYPE_READ, NULL); +				  SBAL_SFLAGS0_TYPE_READ, NULL);  	if (IS_ERR(req)) {  		retval = PTR_ERR(req); @@ -1334,10 +1374,6 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req)  	switch (header->fsf_status) {  	case FSF_PORT_ALREADY_OPEN:  		break; -	case FSF_ACCESS_DENIED: -		zfcp_cfdc_port_denied(port, &header->fsf_status_qual); -		req->status |= ZFCP_STATUS_FSFREQ_ERROR; -		break;  	case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED:  		dev_warn(&req->adapter->ccw_device->dev,  			 "Not enough FCP adapter resources to open " @@ -1409,7 +1445,7 @@ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)  		goto out;  	req = zfcp_fsf_req_create(qdio, FSF_QTCB_OPEN_PORT_WITH_DID, -				  SBAL_FLAGS0_TYPE_READ, +				  SBAL_SFLAGS0_TYPE_READ,  				  qdio->adapter->pool.erp_req);  	if (IS_ERR(req)) { @@ -1448,7 +1484,7 @@ static void zfcp_fsf_close_port_handler(struct zfcp_fsf_req *req)  	switch (req->qtcb->header.fsf_status) {  	case FSF_PORT_HANDLE_NOT_VALID: -		zfcp_erp_adapter_reopen(port->adapter, 0, "fscph_1", req); +		zfcp_erp_adapter_reopen(port->adapter, 0, "fscph_1");  		req->status |= ZFCP_STATUS_FSFREQ_ERROR;  		break;  	case FSF_ADAPTER_STATUS_AVAILABLE: @@ -1475,7 +1511,7 @@ int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action)  		goto out;  	req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_PORT, -				  SBAL_FLAGS0_TYPE_READ, +				  SBAL_SFLAGS0_TYPE_READ,  				  qdio->adapter->pool.erp_req);  	if (IS_ERR(req)) { @@ -1520,8 +1556,6 @@ static void zfcp_fsf_open_wka_port_handler(struct zfcp_fsf_req *req)  		/* fall through */  	case FSF_ADAPTER_STATUS_AVAILABLE:  		req->status |= ZFCP_STATUS_FSFREQ_ERROR; -		/* fall through */ -	case FSF_ACCESS_DENIED:  		wka_port->status = ZFCP_FC_WKA_PORT_OFFLINE;  		break;  	case FSF_GOOD: @@ -1550,10 +1584,10 @@ int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *wka_port)  		goto out;  	req = zfcp_fsf_req_create(qdio, FSF_QTCB_OPEN_PORT_WITH_DID, -				  SBAL_FLAGS0_TYPE_READ, +				  SBAL_SFLAGS0_TYPE_READ,  				  qdio->adapter->pool.erp_req); -	if (unlikely(IS_ERR(req))) { +	if (IS_ERR(req)) {  		retval = PTR_ERR(req);  		goto out;  	} @@ -1580,7 +1614,7 @@ static void zfcp_fsf_close_wka_port_handler(struct zfcp_fsf_req *req)  	if (req->qtcb->header.fsf_status == FSF_PORT_HANDLE_NOT_VALID) {  		req->status |= ZFCP_STATUS_FSFREQ_ERROR; -		zfcp_erp_adapter_reopen(wka_port->adapter, 0, "fscwph1", req); +		zfcp_erp_adapter_reopen(wka_port->adapter, 0, "fscwph1");  	}  	wka_port->status = ZFCP_FC_WKA_PORT_OFFLINE; @@ -1603,10 +1637,10 @@ int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *wka_port)  		goto out;  	req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_PORT, -				  SBAL_FLAGS0_TYPE_READ, +				  SBAL_SFLAGS0_TYPE_READ,  				  qdio->adapter->pool.erp_req); -	if (unlikely(IS_ERR(req))) { +	if (IS_ERR(req)) {  		retval = PTR_ERR(req);  		goto out;  	} @@ -1638,12 +1672,9 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req)  	switch (header->fsf_status) {  	case FSF_PORT_HANDLE_NOT_VALID: -		zfcp_erp_adapter_reopen(port->adapter, 0, "fscpph1", req); +		zfcp_erp_adapter_reopen(port->adapter, 0, "fscpph1");  		req->status |= ZFCP_STATUS_FSFREQ_ERROR;  		break; -	case FSF_ACCESS_DENIED: -		zfcp_cfdc_port_denied(port, &header->fsf_status_qual); -		break;  	case FSF_PORT_BOXED:  		/* can't use generic zfcp_erp_modify_port_status because  		 * ZFCP_STATUS_COMMON_OPEN must not be reset for the port */ @@ -1654,7 +1685,7 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req)  						  &sdev_to_zfcp(sdev)->status);  		zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_ACCESS_BOXED);  		zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, -				     "fscpph2", req); +				     "fscpph2");  		req->status |= ZFCP_STATUS_FSFREQ_ERROR;  		break;  	case FSF_ADAPTER_STATUS_AVAILABLE: @@ -1695,7 +1726,7 @@ int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action)  		goto out;  	req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_PHYSICAL_PORT, -				  SBAL_FLAGS0_TYPE_READ, +				  SBAL_SFLAGS0_TYPE_READ,  				  qdio->adapter->pool.erp_req);  	if (IS_ERR(req)) { @@ -1727,40 +1758,45 @@ static void zfcp_fsf_open_lun_handler(struct zfcp_fsf_req *req)  {  	struct zfcp_adapter *adapter = req->adapter;  	struct scsi_device *sdev = req->data; -	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); +	struct zfcp_scsi_dev *zfcp_sdev;  	struct fsf_qtcb_header *header = &req->qtcb->header; -	struct fsf_qtcb_bottom_support *bottom = &req->qtcb->bottom.support; +	union fsf_status_qual *qual = &header->fsf_status_qual;  	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)  		return; +	zfcp_sdev = sdev_to_zfcp(sdev); +  	atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | -			  ZFCP_STATUS_COMMON_ACCESS_BOXED | -			  ZFCP_STATUS_LUN_SHARED | -			  ZFCP_STATUS_LUN_READONLY, +			  ZFCP_STATUS_COMMON_ACCESS_BOXED,  			  &zfcp_sdev->status);  	switch (header->fsf_status) {  	case FSF_PORT_HANDLE_NOT_VALID: -		zfcp_erp_adapter_reopen(adapter, 0, "fsouh_1", req); +		zfcp_erp_adapter_reopen(adapter, 0, "fsouh_1");  		/* fall through */  	case FSF_LUN_ALREADY_OPEN:  		break; -	case FSF_ACCESS_DENIED: -		zfcp_cfdc_lun_denied(sdev, &header->fsf_status_qual); -		req->status |= ZFCP_STATUS_FSFREQ_ERROR; -		break;  	case FSF_PORT_BOXED:  		zfcp_erp_set_port_status(zfcp_sdev->port,  					 ZFCP_STATUS_COMMON_ACCESS_BOXED);  		zfcp_erp_port_reopen(zfcp_sdev->port, -				     ZFCP_STATUS_COMMON_ERP_FAILED, "fsouh_2", -				     req); +				     ZFCP_STATUS_COMMON_ERP_FAILED, "fsouh_2");  		req->status |= ZFCP_STATUS_FSFREQ_ERROR;  		break;  	case FSF_LUN_SHARING_VIOLATION: -		zfcp_cfdc_lun_shrng_vltn(sdev, &header->fsf_status_qual); +		if (qual->word[0]) +			dev_warn(&zfcp_sdev->port->adapter->ccw_device->dev, +				 "LUN 0x%Lx on port 0x%Lx is already in " +				 "use by CSS%d, MIF Image ID %x\n", +				 zfcp_scsi_dev_lun(sdev), +				 (unsigned long long)zfcp_sdev->port->wwpn, +				 qual->fsf_queue_designator.cssid, +				 qual->fsf_queue_designator.hla); +		zfcp_erp_set_lun_status(sdev, +					ZFCP_STATUS_COMMON_ERP_FAILED | +					ZFCP_STATUS_COMMON_ACCESS_DENIED);  		req->status |= ZFCP_STATUS_FSFREQ_ERROR;  		break;  	case FSF_MAXIMUM_NUMBER_OF_LUNS_EXCEEDED: @@ -1788,7 +1824,6 @@ static void zfcp_fsf_open_lun_handler(struct zfcp_fsf_req *req)  	case FSF_GOOD:  		zfcp_sdev->lun_handle = header->lun_handle;  		atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &zfcp_sdev->status); -		zfcp_cfdc_open_lun_eval(sdev, bottom);  		break;  	}  } @@ -1810,7 +1845,7 @@ int zfcp_fsf_open_lun(struct zfcp_erp_action *erp_action)  		goto out;  	req = zfcp_fsf_req_create(qdio, FSF_QTCB_OPEN_LUN, -				  SBAL_FLAGS0_TYPE_READ, +				  SBAL_SFLAGS0_TYPE_READ,  				  adapter->pool.erp_req);  	if (IS_ERR(req)) { @@ -1845,27 +1880,27 @@ out:  static void zfcp_fsf_close_lun_handler(struct zfcp_fsf_req *req)  {  	struct scsi_device *sdev = req->data; -	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); +	struct zfcp_scsi_dev *zfcp_sdev;  	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)  		return; +	zfcp_sdev = sdev_to_zfcp(sdev); +  	switch (req->qtcb->header.fsf_status) {  	case FSF_PORT_HANDLE_NOT_VALID: -		zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0, "fscuh_1", -					req); +		zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0, "fscuh_1");  		req->status |= ZFCP_STATUS_FSFREQ_ERROR;  		break;  	case FSF_LUN_HANDLE_NOT_VALID: -		zfcp_erp_port_reopen(zfcp_sdev->port, 0, "fscuh_2", req); +		zfcp_erp_port_reopen(zfcp_sdev->port, 0, "fscuh_2");  		req->status |= ZFCP_STATUS_FSFREQ_ERROR;  		break;  	case FSF_PORT_BOXED:  		zfcp_erp_set_port_status(zfcp_sdev->port,  					 ZFCP_STATUS_COMMON_ACCESS_BOXED);  		zfcp_erp_port_reopen(zfcp_sdev->port, -				     ZFCP_STATUS_COMMON_ERP_FAILED, "fscuh_3", -				     req); +				     ZFCP_STATUS_COMMON_ERP_FAILED, "fscuh_3");  		req->status |= ZFCP_STATUS_FSFREQ_ERROR;  		break;  	case FSF_ADAPTER_STATUS_AVAILABLE: @@ -1901,7 +1936,7 @@ int zfcp_fsf_close_lun(struct zfcp_erp_action *erp_action)  		goto out;  	req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_LUN, -				  SBAL_FLAGS0_TYPE_READ, +				  SBAL_SFLAGS0_TYPE_READ,  				  qdio->adapter->pool.erp_req);  	if (IS_ERR(req)) { @@ -1941,7 +1976,7 @@ static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi)  {  	struct fsf_qual_latency_info *lat_in;  	struct latency_cont *lat = NULL; -	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scsi->device); +	struct zfcp_scsi_dev *zfcp_sdev;  	struct zfcp_blk_drv_data blktrc;  	int ticks = req->adapter->timer_ticks; @@ -1956,6 +1991,7 @@ static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi)  	if (req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA &&  	    !(req->status & ZFCP_STATUS_FSFREQ_ERROR)) { +		zfcp_sdev = sdev_to_zfcp(scsi->device);  		blktrc.flags |= ZFCP_BLK_LAT_VALID;  		blktrc.channel_lat = lat_in->channel_lat * ticks;  		blktrc.fabric_lat = lat_in->fabric_lat * ticks; @@ -1993,31 +2029,28 @@ static void zfcp_fsf_fcp_handler_common(struct zfcp_fsf_req *req)  {  	struct scsi_cmnd *scmnd = req->data;  	struct scsi_device *sdev = scmnd->device; -	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); +	struct zfcp_scsi_dev *zfcp_sdev;  	struct fsf_qtcb_header *header = &req->qtcb->header;  	if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR))  		return; +	zfcp_sdev = sdev_to_zfcp(sdev); +  	switch (header->fsf_status) {  	case FSF_HANDLE_MISMATCH:  	case FSF_PORT_HANDLE_NOT_VALID: -		zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0, "fssfch1", -					req); +		zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0, "fssfch1");  		req->status |= ZFCP_STATUS_FSFREQ_ERROR;  		break;  	case FSF_FCPLUN_NOT_VALID:  	case FSF_LUN_HANDLE_NOT_VALID: -		zfcp_erp_port_reopen(zfcp_sdev->port, 0, "fssfch2", req); +		zfcp_erp_port_reopen(zfcp_sdev->port, 0, "fssfch2");  		req->status |= ZFCP_STATUS_FSFREQ_ERROR;  		break;  	case FSF_SERVICE_CLASS_NOT_SUPPORTED:  		zfcp_fsf_class_not_supp(req);  		break; -	case FSF_ACCESS_DENIED: -		zfcp_cfdc_lun_denied(sdev, &header->fsf_status_qual); -		req->status |= ZFCP_STATUS_FSFREQ_ERROR; -		break;  	case FSF_DIRECTION_INDICATOR_NOT_VALID:  		dev_err(&req->adapter->ccw_device->dev,  			"Incorrect direction %d, LUN 0x%016Lx on port " @@ -2026,7 +2059,7 @@ static void zfcp_fsf_fcp_handler_common(struct zfcp_fsf_req *req)  			(unsigned long long)zfcp_scsi_dev_lun(sdev),  			(unsigned long long)zfcp_sdev->port->wwpn);  		zfcp_erp_adapter_shutdown(zfcp_sdev->port->adapter, 0, -					  "fssfch3", req); +					  "fssfch3");  		req->status |= ZFCP_STATUS_FSFREQ_ERROR;  		break;  	case FSF_CMND_LENGTH_NOT_VALID: @@ -2037,21 +2070,20 @@ static void zfcp_fsf_fcp_handler_common(struct zfcp_fsf_req *req)  			(unsigned long long)zfcp_scsi_dev_lun(sdev),  			(unsigned long long)zfcp_sdev->port->wwpn);  		zfcp_erp_adapter_shutdown(zfcp_sdev->port->adapter, 0, -					  "fssfch4", req); +					  "fssfch4");  		req->status |= ZFCP_STATUS_FSFREQ_ERROR;  		break;  	case FSF_PORT_BOXED:  		zfcp_erp_set_port_status(zfcp_sdev->port,  					 ZFCP_STATUS_COMMON_ACCESS_BOXED);  		zfcp_erp_port_reopen(zfcp_sdev->port, -				     ZFCP_STATUS_COMMON_ERP_FAILED, "fssfch5", -				     req); +				     ZFCP_STATUS_COMMON_ERP_FAILED, "fssfch5");  		req->status |= ZFCP_STATUS_FSFREQ_ERROR;  		break;  	case FSF_LUN_BOXED:  		zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ACCESS_BOXED);  		zfcp_erp_lun_reopen(sdev, ZFCP_STATUS_COMMON_ERP_FAILED, -				    "fssfch6", req); +				    "fssfch6");  		req->status |= ZFCP_STATUS_FSFREQ_ERROR;  		break;  	case FSF_ADAPTER_STATUS_AVAILABLE: @@ -2069,8 +2101,6 @@ static void zfcp_fsf_fcp_cmnd_handler(struct zfcp_fsf_req *req)  	struct fcp_resp_with_ext *fcp_rsp;  	unsigned long flags; -	zfcp_fsf_fcp_handler_common(req); -  	read_lock_irqsave(&req->adapter->abort_lock, flags);  	scpnt = req->data; @@ -2079,6 +2109,8 @@ static void zfcp_fsf_fcp_cmnd_handler(struct zfcp_fsf_req *req)  		return;  	} +	zfcp_fsf_fcp_handler_common(req); +  	if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR)) {  		set_host_byte(scpnt, DID_TRANSPORT_DISRUPTED);  		goto skip_fsfstatus; @@ -2104,7 +2136,7 @@ static void zfcp_fsf_fcp_cmnd_handler(struct zfcp_fsf_req *req)  skip_fsfstatus:  	zfcp_fsf_req_trace(req, scpnt); -	zfcp_dbf_scsi_result(req->adapter->dbf, scpnt, req); +	zfcp_dbf_scsi_result(scpnt, req);  	scpnt->host_scribble = NULL;  	(scpnt->scsi_done) (scpnt); @@ -2163,26 +2195,27 @@ int zfcp_fsf_fcp_cmnd(struct scsi_cmnd *scsi_cmnd)  {  	struct zfcp_fsf_req *req;  	struct fcp_cmnd *fcp_cmnd; -	unsigned int sbtype = SBAL_FLAGS0_TYPE_READ; -	int real_bytes, retval = -EIO, dix_bytes = 0; +	u8 sbtype = SBAL_SFLAGS0_TYPE_READ; +	int retval = -EIO;  	struct scsi_device *sdev = scsi_cmnd->device;  	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);  	struct zfcp_adapter *adapter = zfcp_sdev->port->adapter;  	struct zfcp_qdio *qdio = adapter->qdio;  	struct fsf_qtcb_bottom_io *io; +	unsigned long flags;  	if (unlikely(!(atomic_read(&zfcp_sdev->status) &  		       ZFCP_STATUS_COMMON_UNBLOCKED)))  		return -EBUSY; -	spin_lock(&qdio->req_q_lock); +	spin_lock_irqsave(&qdio->req_q_lock, flags);  	if (atomic_read(&qdio->req_q_free) <= 0) {  		atomic_inc(&qdio->req_q_full);  		goto out;  	}  	if (scsi_cmnd->sc_data_direction == DMA_TO_DEVICE) -		sbtype = SBAL_FLAGS0_TYPE_WRITE; +		sbtype = SBAL_SFLAGS0_TYPE_WRITE;  	req = zfcp_fsf_req_create(qdio, FSF_QTCB_FCP_CMND,  				  sbtype, adapter->pool.scsi_req); @@ -2208,26 +2241,31 @@ int zfcp_fsf_fcp_cmnd(struct scsi_cmnd *scsi_cmnd)  		io->ref_tag_value = scsi_get_lba(scsi_cmnd) & 0xFFFFFFFF;  	} -	zfcp_fsf_set_data_dir(scsi_cmnd, &io->data_direction); +	if (zfcp_fsf_set_data_dir(scsi_cmnd, &io->data_direction)) +		goto failed_scsi_cmnd;  	fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd; -	zfcp_fc_scsi_to_fcp(fcp_cmnd, scsi_cmnd); +	zfcp_fc_scsi_to_fcp(fcp_cmnd, scsi_cmnd, 0);  	if (scsi_prot_sg_count(scsi_cmnd)) {  		zfcp_qdio_set_data_div(qdio, &req->qdio_req,  				       scsi_prot_sg_count(scsi_cmnd)); -		dix_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, +		retval = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, +						 scsi_prot_sglist(scsi_cmnd)); +		if (retval) +			goto failed_scsi_cmnd; +		io->prot_data_length = zfcp_qdio_real_bytes(  						scsi_prot_sglist(scsi_cmnd)); -		io->prot_data_length = dix_bytes;  	} -	real_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, -					     scsi_sglist(scsi_cmnd)); - -	if (unlikely(real_bytes < 0) || unlikely(dix_bytes < 0)) +	retval = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, +					 scsi_sglist(scsi_cmnd)); +	if (unlikely(retval))  		goto failed_scsi_cmnd;  	zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req); +	if (zfcp_adapter_multi_buffer_active(adapter)) +		zfcp_qdio_set_scount(qdio, &req->qdio_req);  	retval = zfcp_fsf_req_send(req);  	if (unlikely(retval)) @@ -2239,7 +2277,7 @@ failed_scsi_cmnd:  	zfcp_fsf_req_free(req);  	scsi_cmnd->host_scribble = NULL;  out: -	spin_unlock(&qdio->req_q_lock); +	spin_unlock_irqrestore(&qdio->req_q_lock, flags);  	return retval;  } @@ -2281,7 +2319,7 @@ struct zfcp_fsf_req *zfcp_fsf_fcp_task_mgmt(struct scsi_cmnd *scmnd,  		goto out;  	req = zfcp_fsf_req_create(qdio, FSF_QTCB_FCP_CMND, -				  SBAL_FLAGS0_TYPE_WRITE, +				  SBAL_SFLAGS0_TYPE_WRITE,  				  qdio->adapter->pool.scsi_req);  	if (IS_ERR(req)) { @@ -2289,7 +2327,6 @@ struct zfcp_fsf_req *zfcp_fsf_fcp_task_mgmt(struct scsi_cmnd *scmnd,  		goto out;  	} -	req->status |= ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT;  	req->data = scmnd;  	req->handler = zfcp_fsf_fcp_task_mgmt_handler;  	req->qtcb->header.lun_handle = zfcp_sdev->lun_handle; @@ -2301,7 +2338,7 @@ struct zfcp_fsf_req *zfcp_fsf_fcp_task_mgmt(struct scsi_cmnd *scmnd,  	zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);  	fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd; -	zfcp_fc_fcp_tm(fcp_cmnd, scmnd->device, tm_flags); +	zfcp_fc_scsi_to_fcp(fcp_cmnd, scmnd, tm_flags);  	zfcp_fsf_start_timer(req, ZFCP_SCSI_ER_TIMEOUT);  	if (!zfcp_fsf_req_send(req)) @@ -2314,74 +2351,6 @@ out:  	return req;  } -static void zfcp_fsf_control_file_handler(struct zfcp_fsf_req *req) -{ -} - -/** - * zfcp_fsf_control_file - control file upload/download - * @adapter: pointer to struct zfcp_adapter - * @fsf_cfdc: pointer to struct zfcp_fsf_cfdc - * Returns: on success pointer to struct zfcp_fsf_req, NULL otherwise - */ -struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter, -					   struct zfcp_fsf_cfdc *fsf_cfdc) -{ -	struct zfcp_qdio *qdio = adapter->qdio; -	struct zfcp_fsf_req *req = NULL; -	struct fsf_qtcb_bottom_support *bottom; -	int direction, retval = -EIO, bytes; - -	if (!(adapter->adapter_features & FSF_FEATURE_CFDC)) -		return ERR_PTR(-EOPNOTSUPP); - -	switch (fsf_cfdc->command) { -	case FSF_QTCB_DOWNLOAD_CONTROL_FILE: -		direction = SBAL_FLAGS0_TYPE_WRITE; -		break; -	case FSF_QTCB_UPLOAD_CONTROL_FILE: -		direction = SBAL_FLAGS0_TYPE_READ; -		break; -	default: -		return ERR_PTR(-EINVAL); -	} - -	spin_lock_irq(&qdio->req_q_lock); -	if (zfcp_qdio_sbal_get(qdio)) -		goto out; - -	req = zfcp_fsf_req_create(qdio, fsf_cfdc->command, direction, NULL); -	if (IS_ERR(req)) { -		retval = -EPERM; -		goto out; -	} - -	req->handler = zfcp_fsf_control_file_handler; - -	bottom = &req->qtcb->bottom.support; -	bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE; -	bottom->option = fsf_cfdc->option; - -	bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, fsf_cfdc->sg); - -	if (bytes != ZFCP_CFDC_MAX_SIZE) { -		zfcp_fsf_req_free(req); -		goto out; -	} -	zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req); - -	zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); -	retval = zfcp_fsf_req_send(req); -out: -	spin_unlock_irq(&qdio->req_q_lock); - -	if (!retval) { -		wait_for_completion(&req->completion); -		return req; -	} -	return ERR_PTR(retval); -} -  /**   * zfcp_fsf_reqid_check - validate req_id contained in SBAL returned by QDIO   * @adapter: pointer to struct zfcp_adapter @@ -2415,7 +2384,7 @@ void zfcp_fsf_reqid_check(struct zfcp_qdio *qdio, int sbal_idx)  		fsf_req->qdio_req.sbal_response = sbal_idx;  		zfcp_fsf_req_complete(fsf_req); -		if (likely(sbale->flags & SBAL_FLAGS_LAST_ENTRY)) +		if (likely(sbale->eflags & SBAL_EFLAGS_LAST_ENTRY))  			break;  	}  } diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h index db8c85382dc..57ae3ae1046 100644 --- a/drivers/s390/scsi/zfcp_fsf.h +++ b/drivers/s390/scsi/zfcp_fsf.h @@ -3,7 +3,7 @@   *   * Interface to the FSF support functions.   * - * Copyright IBM Corporation 2002, 2010 + * Copyright IBM Corp. 2002, 2010   */  #ifndef FSF_H @@ -36,13 +36,6 @@  #define FSF_CONFIG_COMMAND			0x00000003  #define FSF_PORT_COMMAND			0x00000004 -/* FSF control file upload/download operations' subtype and options */ -#define FSF_CFDC_OPERATION_SUBTYPE		0x00020001 -#define FSF_CFDC_OPTION_NORMAL_MODE		0x00000000 -#define FSF_CFDC_OPTION_FORCE			0x00000001 -#define FSF_CFDC_OPTION_FULL_ACCESS		0x00000002 -#define FSF_CFDC_OPTION_RESTRICTED_ACCESS	0x00000004 -  /* FSF protocol states */  #define FSF_PROT_GOOD				0x00000001  #define FSF_PROT_QTCB_VERSION_ERROR		0x00000010 @@ -64,7 +57,6 @@  #define FSF_HANDLE_MISMATCH			0x00000005  #define FSF_SERVICE_CLASS_NOT_SUPPORTED		0x00000006  #define FSF_FCPLUN_NOT_VALID			0x00000009 -#define FSF_ACCESS_DENIED			0x00000010  #define FSF_LUN_SHARING_VIOLATION               0x00000012  #define FSF_FCP_COMMAND_DOES_NOT_EXIST		0x00000022  #define FSF_DIRECTION_INDICATOR_NOT_VALID	0x00000030 @@ -130,7 +122,6 @@  #define FSF_STATUS_READ_LINK_DOWN		0x00000005  #define FSF_STATUS_READ_LINK_UP          	0x00000006  #define FSF_STATUS_READ_NOTIFICATION_LOST	0x00000009 -#define FSF_STATUS_READ_CFDC_UPDATED		0x0000000A  #define FSF_STATUS_READ_FEATURE_UPDATE_ALERT	0x0000000C  /* status subtypes for link down */ @@ -140,7 +131,6 @@  /* status subtypes for unsolicited status notification lost */  #define FSF_STATUS_READ_SUB_INCOMING_ELS	0x00000001 -#define FSF_STATUS_READ_SUB_ACT_UPDATED		0x00000020  /* topologie that is detected by the adapter */  #define FSF_TOPO_P2P				0x00000001 @@ -166,8 +156,6 @@  #define FSF_QTCB_LOG_SIZE			1024  /* channel features */ -#define FSF_FEATURE_CFDC			0x00000002 -#define FSF_FEATURE_LUN_SHARING			0x00000004  #define FSF_FEATURE_NOTIFICATION_LOST		0x00000008  #define FSF_FEATURE_HBAAPI_MANAGEMENT           0x00000010  #define FSF_FEATURE_ELS_CT_CHAINED_SBALS	0x00000020 @@ -182,20 +170,6 @@  /* option */  #define FSF_OPEN_LUN_SUPPRESS_BOXING		0x00000001 -/* open LUN access flags*/ -#define FSF_UNIT_ACCESS_EXCLUSIVE		0x02000000 -#define FSF_UNIT_ACCESS_OUTBOUND_TRANSFER	0x10000000 - -/* FSF interface for CFDC */ -#define ZFCP_CFDC_MAX_SIZE		127 * 1024 -#define ZFCP_CFDC_PAGES 		PFN_UP(ZFCP_CFDC_MAX_SIZE) - -struct zfcp_fsf_cfdc { -	struct scatterlist sg[ZFCP_CFDC_PAGES]; -	u32 command; -	u32 option; -}; -  struct fsf_queue_designator {  	u8  cssid;  	u8  chpid; diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index a0554beb417..06025cdaa4a 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -3,18 +3,23 @@   *   * Setup and helper functions to access QDIO.   * - * Copyright IBM Corporation 2002, 2010 + * Copyright IBM Corp. 2002, 2010   */  #define KMSG_COMPONENT "zfcp"  #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt  #include <linux/slab.h> +#include <linux/module.h>  #include "zfcp_ext.h"  #include "zfcp_qdio.h"  #define QBUFF_PER_PAGE		(PAGE_SIZE / sizeof(struct qdio_buffer)) +static bool enable_multibuffer = 1; +module_param_named(datarouter, enable_multibuffer, bool, 0400); +MODULE_PARM_DESC(datarouter, "Enable hardware data router support (default on)"); +  static int zfcp_qdio_buffers_enqueue(struct qdio_buffer **sbal)  {  	int pos; @@ -37,11 +42,14 @@ static void zfcp_qdio_handler_error(struct zfcp_qdio *qdio, char *id,  	dev_warn(&adapter->ccw_device->dev, "A QDIO problem occurred\n"); -	if (qdio_err & QDIO_ERROR_SLSB_STATE) +	if (qdio_err & QDIO_ERROR_SLSB_STATE) {  		zfcp_qdio_siosl(adapter); +		zfcp_erp_adapter_shutdown(adapter, 0, id); +		return; +	}  	zfcp_erp_adapter_reopen(adapter,  				ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | -				ZFCP_STATUS_COMMON_ERP_FAILED, id, NULL); +				ZFCP_STATUS_COMMON_ERP_FAILED, id);  }  static void zfcp_qdio_zero_sbals(struct qdio_buffer *sbal[], int first, int cnt) @@ -60,7 +68,7 @@ static inline void zfcp_qdio_account(struct zfcp_qdio *qdio)  	unsigned long long now, span;  	int used; -	now = get_clock_monotonic(); +	now = get_tod_clock_monotonic();  	span = (now - qdio->req_q_time) >> 12;  	used = QDIO_MAX_BUFFERS_PER_Q - atomic_read(&qdio->req_q_free);  	qdio->req_q_util += used * span; @@ -74,7 +82,6 @@ static void zfcp_qdio_int_req(struct ccw_device *cdev, unsigned int qdio_err,  	struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm;  	if (unlikely(qdio_err)) { -		zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, idx, count);  		zfcp_qdio_handler_error(qdio, "qdireq1", qdio_err);  		return;  	} @@ -94,10 +101,31 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err,  			       unsigned long parm)  {  	struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm; -	int sbal_idx, sbal_no; +	struct zfcp_adapter *adapter = qdio->adapter; +	int sbal_no, sbal_idx;  	if (unlikely(qdio_err)) { -		zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, idx, count); +		if (zfcp_adapter_multi_buffer_active(adapter)) { +			void *pl[ZFCP_QDIO_MAX_SBALS_PER_REQ + 1]; +			struct qdio_buffer_element *sbale; +			u64 req_id; +			u8 scount; + +			memset(pl, 0, +			       ZFCP_QDIO_MAX_SBALS_PER_REQ * sizeof(void *)); +			sbale = qdio->res_q[idx]->element; +			req_id = (u64) sbale->addr; +			scount = min(sbale->scount + 1, +				     ZFCP_QDIO_MAX_SBALS_PER_REQ + 1); +				     /* incl. signaling SBAL */ + +			for (sbal_no = 0; sbal_no < scount; sbal_no++) { +				sbal_idx = (idx + sbal_no) % +					QDIO_MAX_BUFFERS_PER_Q; +				pl[sbal_no] = qdio->res_q[sbal_idx]; +			} +			zfcp_dbf_hba_def_err(adapter, req_id, scount, pl); +		}  		zfcp_qdio_handler_error(qdio, "qdires1", qdio_err);  		return;  	} @@ -116,7 +144,7 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err,  	 * put SBALs back to response queue  	 */  	if (do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, idx, count)) -		zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdires2", NULL); +		zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdires2");  }  static struct qdio_buffer_element * @@ -126,7 +154,7 @@ zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)  	/* set last entry flag in current SBALE of current SBAL */  	sbale = zfcp_qdio_sbale_curr(qdio, q_req); -	sbale->flags |= SBAL_FLAGS_LAST_ENTRY; +	sbale->eflags |= SBAL_EFLAGS_LAST_ENTRY;  	/* don't exceed last allowed SBAL */  	if (q_req->sbal_last == q_req->sbal_limit) @@ -134,7 +162,7 @@ zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)  	/* set chaining flag in first SBALE of current SBAL */  	sbale = zfcp_qdio_sbale_req(qdio, q_req); -	sbale->flags |= SBAL_FLAGS0_MORE_SBALS; +	sbale->sflags |= SBAL_SFLAGS0_MORE_SBALS;  	/* calculate index of next SBAL */  	q_req->sbal_last++; @@ -149,7 +177,7 @@ zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)  	/* set storage-block type for new SBAL */  	sbale = zfcp_qdio_sbale_curr(qdio, q_req); -	sbale->flags |= q_req->sbtype; +	sbale->sflags |= q_req->sbtype;  	return sbale;  } @@ -157,7 +185,7 @@ zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)  static struct qdio_buffer_element *  zfcp_qdio_sbale_next(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)  { -	if (q_req->sbale_curr == ZFCP_QDIO_LAST_SBALE_PER_SBAL) +	if (q_req->sbale_curr == qdio->max_sbale_per_sbal - 1)  		return zfcp_qdio_sbal_chain(qdio, q_req);  	q_req->sbale_curr++;  	return zfcp_qdio_sbale_curr(qdio, q_req); @@ -169,17 +197,16 @@ zfcp_qdio_sbale_next(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)   * @q_req: pointer to struct zfcp_qdio_req   * @sg: scatter-gather list   * @max_sbals: upper bound for number of SBALs to be used - * Returns: number of bytes, or error (negativ) + * Returns: zero or -EINVAL on error   */  int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,  			    struct scatterlist *sg)  {  	struct qdio_buffer_element *sbale; -	int bytes = 0;  	/* set storage-block type for this request */  	sbale = zfcp_qdio_sbale_req(qdio, q_req); -	sbale->flags |= q_req->sbtype; +	sbale->sflags |= q_req->sbtype;  	for (; sg; sg = sg_next(sg)) {  		sbale = zfcp_qdio_sbale_next(qdio, q_req); @@ -189,23 +216,17 @@ int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,  					     q_req->sbal_number);  			return -EINVAL;  		} -  		sbale->addr = sg_virt(sg);  		sbale->length = sg->length; - -		bytes += sg->length;  	} - -	return bytes; +	return 0;  }  static int zfcp_qdio_sbal_check(struct zfcp_qdio *qdio)  { -	spin_lock_irq(&qdio->req_q_lock);  	if (atomic_read(&qdio->req_q_free) ||  	    !(atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP))  		return 1; -	spin_unlock_irq(&qdio->req_q_lock);  	return 0;  } @@ -223,9 +244,8 @@ int zfcp_qdio_sbal_get(struct zfcp_qdio *qdio)  {  	long ret; -	spin_unlock_irq(&qdio->req_q_lock); -	ret = wait_event_interruptible_timeout(qdio->req_q_wq, -			       zfcp_qdio_sbal_check(qdio), 5 * HZ); +	ret = wait_event_interruptible_lock_irq_timeout(qdio->req_q_wq, +		       zfcp_qdio_sbal_check(qdio), qdio->req_q_lock, 5 * HZ);  	if (!(atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP))  		return -EIO; @@ -236,10 +256,9 @@ int zfcp_qdio_sbal_get(struct zfcp_qdio *qdio)  	if (!ret) {  		atomic_inc(&qdio->req_q_full);  		/* assume hanging outbound queue, try queue recovery */ -		zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdsbg_1", NULL); +		zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdsbg_1");  	} -	spin_lock_irq(&qdio->req_q_lock);  	return -EIO;  } @@ -285,6 +304,8 @@ static void zfcp_qdio_setup_init_data(struct qdio_initialize *id,  	memcpy(id->adapter_name, dev_name(&id->cdev->dev), 8);  	ASCEBC(id->adapter_name, 8);  	id->qib_rflags = QIB_RFLAGS_ENABLE_DATA_DIV; +	if (enable_multibuffer) +		id->qdr_ac |= QDR_AC_MULTI_BUFFER_ENABLE;  	id->no_input_qs = 1;  	id->no_output_qs = 1;  	id->input_handler = zfcp_qdio_int_resp; @@ -292,6 +313,8 @@ static void zfcp_qdio_setup_init_data(struct qdio_initialize *id,  	id->int_parm = (unsigned long) qdio;  	id->input_sbal_addr_array = (void **) (qdio->res_q);  	id->output_sbal_addr_array = (void **) (qdio->req_q); +	id->scan_threshold = +		QDIO_MAX_BUFFERS_PER_Q - ZFCP_QDIO_MAX_SBALS_PER_REQ * 2;  }  /** @@ -309,6 +332,7 @@ static int zfcp_qdio_allocate(struct zfcp_qdio *qdio)  		return -ENOMEM;  	zfcp_qdio_setup_init_data(&init_data, qdio); +	init_waitqueue_head(&qdio->req_q_wq);  	return qdio_allocate(&init_data);  } @@ -377,22 +401,40 @@ int zfcp_qdio_open(struct zfcp_qdio *qdio)  		atomic_set_mask(ZFCP_STATUS_ADAPTER_DATA_DIV_ENABLED,  				&qdio->adapter->status); +	if (ssqd.qdioac2 & CHSC_AC2_MULTI_BUFFER_ENABLED) { +		atomic_set_mask(ZFCP_STATUS_ADAPTER_MB_ACT, &adapter->status); +		qdio->max_sbale_per_sbal = QDIO_MAX_ELEMENTS_PER_BUFFER; +	} else { +		atomic_clear_mask(ZFCP_STATUS_ADAPTER_MB_ACT, &adapter->status); +		qdio->max_sbale_per_sbal = QDIO_MAX_ELEMENTS_PER_BUFFER - 1; +	} + +	qdio->max_sbale_per_req = +		ZFCP_QDIO_MAX_SBALS_PER_REQ * qdio->max_sbale_per_sbal +		- 2;  	if (qdio_activate(cdev))  		goto failed_qdio;  	for (cc = 0; cc < QDIO_MAX_BUFFERS_PER_Q; cc++) {  		sbale = &(qdio->res_q[cc]->element[0]);  		sbale->length = 0; -		sbale->flags = SBAL_FLAGS_LAST_ENTRY; +		sbale->eflags = SBAL_EFLAGS_LAST_ENTRY; +		sbale->sflags = 0;  		sbale->addr = NULL;  	}  	if (do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, 0, QDIO_MAX_BUFFERS_PER_Q))  		goto failed_qdio; -	/* set index of first avalable SBALS / number of available SBALS */ +	/* set index of first available SBALS / number of available SBALS */  	qdio->req_q_idx = 0;  	atomic_set(&qdio->req_q_free, QDIO_MAX_BUFFERS_PER_Q); +	atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &qdio->adapter->status); + +	if (adapter->scsi_host) { +		adapter->scsi_host->sg_tablesize = qdio->max_sbale_per_req; +		adapter->scsi_host->max_sectors = qdio->max_sbale_per_req * 8; +	}  	return 0; diff --git a/drivers/s390/scsi/zfcp_qdio.h b/drivers/s390/scsi/zfcp_qdio.h index 2297d8d3e94..497cd379b0d 100644 --- a/drivers/s390/scsi/zfcp_qdio.h +++ b/drivers/s390/scsi/zfcp_qdio.h @@ -3,7 +3,7 @@   *   * Header file for zfcp qdio interface   * - * Copyright IBM Corporation 2010 + * Copyright IBM Corp. 2010   */  #ifndef ZFCP_QDIO_H @@ -13,20 +13,9 @@  #define ZFCP_QDIO_SBALE_LEN	PAGE_SIZE -/* DMQ bug workaround: don't use last SBALE */ -#define ZFCP_QDIO_MAX_SBALES_PER_SBAL	(QDIO_MAX_ELEMENTS_PER_BUFFER - 1) - -/* index of last SBALE (with respect to DMQ bug workaround) */ -#define ZFCP_QDIO_LAST_SBALE_PER_SBAL	(ZFCP_QDIO_MAX_SBALES_PER_SBAL - 1) -  /* Max SBALS for chaining */  #define ZFCP_QDIO_MAX_SBALS_PER_REQ	36 -/* max. number of (data buffer) SBALEs in largest SBAL chain - * request ID + QTCB in SBALE 0 + 1 of first SBAL in chain   */ -#define ZFCP_QDIO_MAX_SBALES_PER_REQ     \ -	(ZFCP_QDIO_MAX_SBALS_PER_REQ * ZFCP_QDIO_MAX_SBALES_PER_SBAL - 2) -  /**   * struct zfcp_qdio - basic qdio data structure   * @res_q: response queue @@ -53,6 +42,8 @@ struct zfcp_qdio {  	atomic_t		req_q_full;  	wait_queue_head_t	req_q_wq;  	struct zfcp_adapter	*adapter; +	u16			max_sbale_per_sbal; +	u16			max_sbale_per_req;  };  /** @@ -67,7 +58,7 @@ struct zfcp_qdio {   * @qdio_outb_usage: usage of outbound queue   */  struct zfcp_qdio_req { -	u32	sbtype; +	u8	sbtype;  	u8	sbal_number;  	u8	sbal_first;  	u8	sbal_last; @@ -116,7 +107,7 @@ zfcp_qdio_sbale_curr(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)   */  static inline  void zfcp_qdio_req_init(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req, -			unsigned long req_id, u32 sbtype, void *data, u32 len) +			unsigned long req_id, u8 sbtype, void *data, u32 len)  {  	struct qdio_buffer_element *sbale;  	int count = min(atomic_read(&qdio->req_q_free), @@ -131,7 +122,8 @@ void zfcp_qdio_req_init(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,  	sbale = zfcp_qdio_sbale_req(qdio, q_req);  	sbale->addr = (void *) req_id; -	sbale->flags = SBAL_FLAGS0_COMMAND | sbtype; +	sbale->eflags = 0; +	sbale->sflags = SBAL_SFLAGS0_COMMAND | sbtype;  	if (unlikely(!data))  		return; @@ -154,7 +146,7 @@ void zfcp_qdio_fill_next(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,  {  	struct qdio_buffer_element *sbale; -	BUG_ON(q_req->sbale_curr == ZFCP_QDIO_LAST_SBALE_PER_SBAL); +	BUG_ON(q_req->sbale_curr == qdio->max_sbale_per_sbal - 1);  	q_req->sbale_curr++;  	sbale = zfcp_qdio_sbale_curr(qdio, q_req);  	sbale->addr = data; @@ -173,7 +165,7 @@ void zfcp_qdio_set_sbale_last(struct zfcp_qdio *qdio,  	struct qdio_buffer_element *sbale;  	sbale = zfcp_qdio_sbale_curr(qdio, q_req); -	sbale->flags |= SBAL_FLAGS_LAST_ENTRY; +	sbale->eflags |= SBAL_EFLAGS_LAST_ENTRY;  }  /** @@ -194,9 +186,10 @@ int zfcp_qdio_sg_one_sbale(struct scatterlist *sg)   * @q_req: The current zfcp_qdio_req   */  static inline -void zfcp_qdio_skip_to_last_sbale(struct zfcp_qdio_req *q_req) +void zfcp_qdio_skip_to_last_sbale(struct zfcp_qdio *qdio, +				  struct zfcp_qdio_req *q_req)  { -	q_req->sbale_curr = ZFCP_QDIO_LAST_SBALE_PER_SBAL; +	q_req->sbale_curr = qdio->max_sbale_per_sbal - 1;  }  /** @@ -227,8 +220,52 @@ void zfcp_qdio_set_data_div(struct zfcp_qdio *qdio,  {  	struct qdio_buffer_element *sbale; -	sbale = &qdio->req_q[q_req->sbal_first]->element[0]; +	sbale = qdio->req_q[q_req->sbal_first]->element;  	sbale->length = count;  } +/** + * zfcp_qdio_sbale_count - count sbale used + * @sg: pointer to struct scatterlist + */ +static inline +unsigned int zfcp_qdio_sbale_count(struct scatterlist *sg) +{ +	unsigned int count = 0; + +	for (; sg; sg = sg_next(sg)) +		count++; + +	return count; +} + +/** + * zfcp_qdio_real_bytes - count bytes used + * @sg: pointer to struct scatterlist + */ +static inline +unsigned int zfcp_qdio_real_bytes(struct scatterlist *sg) +{ +	unsigned int real_bytes = 0; + +	for (; sg; sg = sg_next(sg)) +		real_bytes += sg->length; + +	return real_bytes; +} + +/** + * zfcp_qdio_set_scount - set SBAL count value + * @qdio: pointer to struct zfcp_qdio + * @q_req: The current zfcp_qdio_req + */ +static inline +void zfcp_qdio_set_scount(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req) +{ +	struct qdio_buffer_element *sbale; + +	sbale = qdio->req_q[q_req->sbal_first]->element; +	sbale->scount = q_req->sbal_number - 1; +} +  #endif /* ZFCP_QDIO_H */ diff --git a/drivers/s390/scsi/zfcp_reqlist.h b/drivers/s390/scsi/zfcp_reqlist.h index a72d1b730ab..7c2c6194dfc 100644 --- a/drivers/s390/scsi/zfcp_reqlist.h +++ b/drivers/s390/scsi/zfcp_reqlist.h @@ -4,7 +4,7 @@   * Data structure and helper functions for tracking pending FSF   * requests.   * - * Copyright IBM Corporation 2009 + * Copyright IBM Corp. 2009   */  #ifndef ZFCP_REQLIST_H diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 50286d8707f..7b353647cb9 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -3,17 +3,18 @@   *   * Interface to Linux SCSI midlayer.   * - * Copyright IBM Corporation 2002, 2010 + * Copyright IBM Corp. 2002, 2013   */  #define KMSG_COMPONENT "zfcp"  #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +#include <linux/module.h>  #include <linux/types.h>  #include <linux/slab.h>  #include <scsi/fc/fc_fcp.h>  #include <scsi/scsi_eh.h> -#include <asm/atomic.h> +#include <linux/atomic.h>  #include "zfcp_ext.h"  #include "zfcp_dbf.h"  #include "zfcp_fc.h" @@ -24,11 +25,12 @@ module_param_named(queue_depth, default_depth, uint, 0600);  MODULE_PARM_DESC(queue_depth, "Default queue depth for new SCSI devices");  static bool enable_dif; - -#ifdef CONFIG_ZFCP_DIF -module_param_named(dif, enable_dif, bool, 0600); +module_param_named(dif, enable_dif, bool, 0400);  MODULE_PARM_DESC(dif, "Enable DIF/DIX data integrity support"); -#endif + +static bool allow_lun_scan = 1; +module_param(allow_lun_scan, bool, 0600); +MODULE_PARM_DESC(allow_lun_scan, "For NPIV, scan and attach all storage LUNs");  static int zfcp_scsi_change_queue_depth(struct scsi_device *sdev, int depth,  					int reason) @@ -53,6 +55,10 @@ static void zfcp_scsi_slave_destroy(struct scsi_device *sdev)  {  	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); +	/* if previous slave_alloc returned early, there is nothing to do */ +	if (!zfcp_sdev->port) +		return; +  	zfcp_erp_lun_shutdown_wait(sdev, "scssd_1");  	put_device(&zfcp_sdev->port->dev);  } @@ -68,31 +74,26 @@ static int zfcp_scsi_slave_configure(struct scsi_device *sdp)  static void zfcp_scsi_command_fail(struct scsi_cmnd *scpnt, int result)  { -	struct zfcp_adapter *adapter = -		(struct zfcp_adapter *) scpnt->device->host->hostdata[0]; -  	set_host_byte(scpnt, result); -	zfcp_dbf_scsi_fail_send(adapter->dbf, scpnt); +	zfcp_dbf_scsi_fail_send(scpnt);  	scpnt->scsi_done(scpnt);  } -static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, -				  void (*done) (struct scsi_cmnd *)) +static +int zfcp_scsi_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scpnt)  {  	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scpnt->device); -	struct zfcp_adapter *adapter = zfcp_sdev->port->adapter;  	struct fc_rport *rport = starget_to_rport(scsi_target(scpnt->device));  	int    status, scsi_result, ret;  	/* reset the status for this request */  	scpnt->result = 0;  	scpnt->host_scribble = NULL; -	scpnt->scsi_done = done;  	scsi_result = fc_remote_port_chkready(rport);  	if (unlikely(scsi_result)) {  		scpnt->result = scsi_result; -		zfcp_dbf_scsi_fail_send(adapter->dbf, scpnt); +		zfcp_dbf_scsi_fail_send(scpnt);  		scpnt->scsi_done(scpnt);  		return 0;  	} @@ -135,6 +136,7 @@ static int zfcp_scsi_slave_alloc(struct scsi_device *sdev)  	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);  	struct zfcp_port *port;  	struct zfcp_unit *unit; +	int npiv = adapter->connection_features & FSF_FEATURE_NPIV_MODE;  	port = zfcp_get_port_by_wwpn(adapter, rport->port_name);  	if (!port) @@ -144,7 +146,7 @@ static int zfcp_scsi_slave_alloc(struct scsi_device *sdev)  	if (unit)  		put_device(&unit->dev); -	if (!unit && !(adapter->connection_features & FSF_FEATURE_NPIV_MODE)) { +	if (!unit && !(allow_lun_scan && npiv)) {  		put_device(&port->dev);  		return -ENXIO;  	} @@ -159,7 +161,7 @@ static int zfcp_scsi_slave_alloc(struct scsi_device *sdev)  	spin_lock_init(&zfcp_sdev->latencies.lock);  	zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_RUNNING); -	zfcp_erp_lun_reopen(sdev, 0, "scsla_1", NULL); +	zfcp_erp_lun_reopen(sdev, 0, "scsla_1");  	zfcp_erp_wait(port->adapter);  	return 0; @@ -183,8 +185,7 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)  	old_req = zfcp_reqlist_find(adapter->req_list, old_reqid);  	if (!old_req) {  		write_unlock_irqrestore(&adapter->abort_lock, flags); -		zfcp_dbf_scsi_abort("lte1", adapter->dbf, scpnt, NULL, -				    old_reqid); +		zfcp_dbf_scsi_abort("abrt_or", scpnt, NULL);  		return FAILED; /* completion could be in progress */  	}  	old_req->data = NULL; @@ -199,29 +200,32 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)  		zfcp_erp_wait(adapter);  		ret = fc_block_scsi_eh(scpnt); -		if (ret) +		if (ret) { +			zfcp_dbf_scsi_abort("abrt_bl", scpnt, NULL);  			return ret; +		}  		if (!(atomic_read(&adapter->status) &  		      ZFCP_STATUS_COMMON_RUNNING)) { -			zfcp_dbf_scsi_abort("nres", adapter->dbf, scpnt, NULL, -					    old_reqid); +			zfcp_dbf_scsi_abort("abrt_ru", scpnt, NULL);  			return SUCCESS;  		}  	} -	if (!abrt_req) +	if (!abrt_req) { +		zfcp_dbf_scsi_abort("abrt_ar", scpnt, NULL);  		return FAILED; +	}  	wait_for_completion(&abrt_req->completion);  	if (abrt_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED) -		dbf_tag = "okay"; +		dbf_tag = "abrt_ok";  	else if (abrt_req->status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED) -		dbf_tag = "lte2"; +		dbf_tag = "abrt_nn";  	else { -		dbf_tag = "fail"; +		dbf_tag = "abrt_fa";  		retval = FAILED;  	} -	zfcp_dbf_scsi_abort(dbf_tag, adapter->dbf, scpnt, abrt_req, old_reqid); +	zfcp_dbf_scsi_abort(dbf_tag, scpnt, abrt_req);  	zfcp_fsf_req_free(abrt_req);  	return retval;  } @@ -281,7 +285,7 @@ static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)  	struct zfcp_adapter *adapter = zfcp_sdev->port->adapter;  	int ret; -	zfcp_erp_adapter_reopen(adapter, 0, "schrh_1", scpnt); +	zfcp_erp_adapter_reopen(adapter, 0, "schrh_1");  	zfcp_erp_wait(adapter);  	ret = fc_block_scsi_eh(scpnt);  	if (ret) @@ -290,7 +294,41 @@ static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)  	return SUCCESS;  } -int zfcp_adapter_scsi_register(struct zfcp_adapter *adapter) +struct scsi_transport_template *zfcp_scsi_transport_template; + +static struct scsi_host_template zfcp_scsi_host_template = { +	.module			 = THIS_MODULE, +	.name			 = "zfcp", +	.queuecommand		 = zfcp_scsi_queuecommand, +	.eh_abort_handler	 = zfcp_scsi_eh_abort_handler, +	.eh_device_reset_handler = zfcp_scsi_eh_device_reset_handler, +	.eh_target_reset_handler = zfcp_scsi_eh_target_reset_handler, +	.eh_host_reset_handler	 = zfcp_scsi_eh_host_reset_handler, +	.slave_alloc		 = zfcp_scsi_slave_alloc, +	.slave_configure	 = zfcp_scsi_slave_configure, +	.slave_destroy		 = zfcp_scsi_slave_destroy, +	.change_queue_depth	 = zfcp_scsi_change_queue_depth, +	.proc_name		 = "zfcp", +	.can_queue		 = 4096, +	.this_id		 = -1, +	.sg_tablesize		 = (((QDIO_MAX_ELEMENTS_PER_BUFFER - 1) +				     * ZFCP_QDIO_MAX_SBALS_PER_REQ) - 2), +				   /* GCD, adjusted later */ +	.max_sectors		 = (((QDIO_MAX_ELEMENTS_PER_BUFFER - 1) +				     * ZFCP_QDIO_MAX_SBALS_PER_REQ) - 2) * 8, +				   /* GCD, adjusted later */ +	.dma_boundary		 = ZFCP_QDIO_SBALE_LEN - 1, +	.cmd_per_lun		 = 1, +	.use_clustering		 = 1, +	.shost_attrs		 = zfcp_sysfs_shost_attrs, +	.sdev_attrs		 = zfcp_sysfs_sdev_attrs, +}; + +/** + * zfcp_scsi_adapter_register - Register SCSI and FC host with SCSI midlayer + * @adapter: The zfcp adapter to register with the SCSI midlayer + */ +int zfcp_scsi_adapter_register(struct zfcp_adapter *adapter)  {  	struct ccw_dev_id dev_id; @@ -299,7 +337,7 @@ int zfcp_adapter_scsi_register(struct zfcp_adapter *adapter)  	ccw_device_get_id(adapter->ccw_device, &dev_id);  	/* register adapter as SCSI host with mid layer of SCSI stack */ -	adapter->scsi_host = scsi_host_alloc(&zfcp_data.scsi_host_template, +	adapter->scsi_host = scsi_host_alloc(&zfcp_scsi_host_template,  					     sizeof (struct zfcp_adapter *));  	if (!adapter->scsi_host) {  		dev_err(&adapter->ccw_device->dev, @@ -314,7 +352,7 @@ int zfcp_adapter_scsi_register(struct zfcp_adapter *adapter)  	adapter->scsi_host->max_channel = 0;  	adapter->scsi_host->unique_id = dev_id.devno;  	adapter->scsi_host->max_cmd_len = 16; /* in struct fcp_cmnd */ -	adapter->scsi_host->transportt = zfcp_data.scsi_transport_template; +	adapter->scsi_host->transportt = zfcp_scsi_transport_template;  	adapter->scsi_host->hostdata[0] = (unsigned long) adapter; @@ -326,7 +364,11 @@ int zfcp_adapter_scsi_register(struct zfcp_adapter *adapter)  	return 0;  } -void zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter) +/** + * zfcp_scsi_adapter_unregister - Unregister SCSI and FC host from SCSI midlayer + * @adapter: The zfcp adapter to unregister. + */ +void zfcp_scsi_adapter_unregister(struct zfcp_adapter *adapter)  {  	struct Scsi_Host *shost;  	struct zfcp_port *port; @@ -344,8 +386,6 @@ void zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter)  	scsi_remove_host(shost);  	scsi_host_put(shost);  	adapter->scsi_host = NULL; - -	return;  }  static struct fc_host_statistics* @@ -519,7 +559,7 @@ static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport)  	port = zfcp_get_port_by_wwpn(adapter, rport->port_name);  	if (port) { -		zfcp_erp_port_forced_reopen(port, 0, "sctrpi1", NULL); +		zfcp_erp_port_forced_reopen(port, 0, "sctrpi1");  		put_device(&port->dev);  	}  } @@ -634,9 +674,9 @@ void zfcp_scsi_set_prot(struct zfcp_adapter *adapter)  	    adapter->adapter_features & FSF_FEATURE_DIX_PROT_TCPIP) {  		mask |= SHOST_DIX_TYPE1_PROTECTION;  		scsi_host_set_guard(shost, SHOST_DIX_GUARD_IP); -		shost->sg_prot_tablesize = ZFCP_QDIO_MAX_SBALES_PER_REQ / 2; -		shost->sg_tablesize = ZFCP_QDIO_MAX_SBALES_PER_REQ / 2; -		shost->max_sectors = ZFCP_QDIO_MAX_SBALES_PER_REQ * 8 / 2; +		shost->sg_prot_tablesize = adapter->qdio->max_sbale_per_req / 2; +		shost->sg_tablesize = adapter->qdio->max_sbale_per_req / 2; +		shost->max_sectors = shost->sg_tablesize * 8;  	}  	scsi_host_set_prot(shost, mask); @@ -686,33 +726,8 @@ struct fc_function_template zfcp_transport_functions = {  	/* no functions registered for following dynamic attributes but  	   directly set by LLDD */  	.show_host_port_type = 1, +	.show_host_symbolic_name = 1,  	.show_host_speed = 1,  	.show_host_port_id = 1,  	.dd_bsg_size = sizeof(struct zfcp_fsf_ct_els),  }; - -struct zfcp_data zfcp_data = { -	.scsi_host_template = { -		.name			 = "zfcp", -		.module			 = THIS_MODULE, -		.proc_name		 = "zfcp", -		.change_queue_depth	 = zfcp_scsi_change_queue_depth, -		.slave_alloc		 = zfcp_scsi_slave_alloc, -		.slave_configure	 = zfcp_scsi_slave_configure, -		.slave_destroy		 = zfcp_scsi_slave_destroy, -		.queuecommand		 = zfcp_scsi_queuecommand, -		.eh_abort_handler	 = zfcp_scsi_eh_abort_handler, -		.eh_device_reset_handler = zfcp_scsi_eh_device_reset_handler, -		.eh_target_reset_handler = zfcp_scsi_eh_target_reset_handler, -		.eh_host_reset_handler	 = zfcp_scsi_eh_host_reset_handler, -		.can_queue		 = 4096, -		.this_id		 = -1, -		.sg_tablesize		 = ZFCP_QDIO_MAX_SBALES_PER_REQ, -		.cmd_per_lun		 = 1, -		.use_clustering		 = 1, -		.sdev_attrs		 = zfcp_sysfs_sdev_attrs, -		.max_sectors		 = (ZFCP_QDIO_MAX_SBALES_PER_REQ * 8), -		.dma_boundary		 = ZFCP_QDIO_SBALE_LEN - 1, -		.shost_attrs		 = zfcp_sysfs_shost_attrs, -	}, -}; diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c index 2f2c54f4718..672b57219e1 100644 --- a/drivers/s390/scsi/zfcp_sysfs.c +++ b/drivers/s390/scsi/zfcp_sysfs.c @@ -3,7 +3,7 @@   *   * sysfs attributes.   * - * Copyright IBM Corporation 2008, 2010 + * Copyright IBM Corp. 2008, 2010   */  #define KMSG_COMPONENT "zfcp" @@ -27,6 +27,16 @@ static ssize_t zfcp_sysfs_##_feat##_##_name##_show(struct device *dev,	       \  static ZFCP_DEV_ATTR(_feat, _name, S_IRUGO,				       \  		     zfcp_sysfs_##_feat##_##_name##_show, NULL); +#define ZFCP_DEFINE_ATTR_CONST(_feat, _name, _format, _value)		       \ +static ssize_t zfcp_sysfs_##_feat##_##_name##_show(struct device *dev,	       \ +						   struct device_attribute *at,\ +						   char *buf)		       \ +{									       \ +	return sprintf(buf, _format, _value);				       \ +}									       \ +static ZFCP_DEV_ATTR(_feat, _name, S_IRUGO,				       \ +		     zfcp_sysfs_##_feat##_##_name##_show, NULL); +  #define ZFCP_DEFINE_A_ATTR(_name, _format, _value)			     \  static ssize_t zfcp_sysfs_adapter_##_name##_show(struct device *dev,	     \  						 struct device_attribute *at,\ @@ -75,12 +85,8 @@ ZFCP_DEFINE_ATTR(zfcp_unit, unit, in_recovery, "%d\n",  ZFCP_DEFINE_ATTR(zfcp_unit, unit, access_denied, "%d\n",  		 (zfcp_unit_sdev_status(unit) &  		  ZFCP_STATUS_COMMON_ACCESS_DENIED) != 0); -ZFCP_DEFINE_ATTR(zfcp_unit, unit, access_shared, "%d\n", -		 (zfcp_unit_sdev_status(unit) & -		  ZFCP_STATUS_LUN_SHARED) != 0); -ZFCP_DEFINE_ATTR(zfcp_unit, unit, access_readonly, "%d\n", -		 (zfcp_unit_sdev_status(unit) & -		  ZFCP_STATUS_LUN_READONLY) != 0); +ZFCP_DEFINE_ATTR_CONST(unit, access_shared, "%d\n", 0); +ZFCP_DEFINE_ATTR_CONST(unit, access_readonly, "%d\n", 0);  static ssize_t zfcp_sysfs_port_failed_show(struct device *dev,  					   struct device_attribute *attr, @@ -101,12 +107,11 @@ static ssize_t zfcp_sysfs_port_failed_store(struct device *dev,  	struct zfcp_port *port = container_of(dev, struct zfcp_port, dev);  	unsigned long val; -	if (strict_strtoul(buf, 0, &val) || val != 0) +	if (kstrtoul(buf, 0, &val) || val != 0)  		return -EINVAL;  	zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_RUNNING); -	zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, "sypfai2", -			     NULL); +	zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, "sypfai2");  	zfcp_erp_wait(port->adapter);  	return count; @@ -141,14 +146,14 @@ static ssize_t zfcp_sysfs_unit_failed_store(struct device *dev,  	unsigned long val;  	struct scsi_device *sdev; -	if (strict_strtoul(buf, 0, &val) || val != 0) +	if (kstrtoul(buf, 0, &val) || val != 0)  		return -EINVAL;  	sdev = zfcp_unit_sdev(unit);  	if (sdev) {  		zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_RUNNING);  		zfcp_erp_lun_reopen(sdev, ZFCP_STATUS_COMMON_ERP_FAILED, -				    "syufai2", NULL); +				    "syufai2");  		zfcp_erp_wait(unit->port->adapter);  	} else  		zfcp_unit_scsi_scan(unit); @@ -191,14 +196,14 @@ static ssize_t zfcp_sysfs_adapter_failed_store(struct device *dev,  	if (!adapter)  		return -ENODEV; -	if (strict_strtoul(buf, 0, &val) || val != 0) { +	if (kstrtoul(buf, 0, &val) || val != 0) {  		retval = -EINVAL;  		goto out;  	}  	zfcp_erp_set_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING);  	zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, -				"syafai2", NULL); +				"syafai2");  	zfcp_erp_wait(adapter);  out:  	zfcp_ccw_adapter_put(adapter); @@ -228,6 +233,8 @@ static ssize_t zfcp_sysfs_port_rescan_store(struct device *dev,  static ZFCP_DEV_ATTR(adapter, port_rescan, S_IWUSR, NULL,  		     zfcp_sysfs_port_rescan_store); +DEFINE_MUTEX(zfcp_sysfs_port_units_mutex); +  static ssize_t zfcp_sysfs_port_remove_store(struct device *dev,  					    struct device_attribute *attr,  					    const char *buf, size_t count) @@ -241,7 +248,7 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev,  	if (!adapter)  		return -ENODEV; -	if (strict_strtoull(buf, 0, (unsigned long long *) &wwpn)) +	if (kstrtoull(buf, 0, (unsigned long long *) &wwpn))  		goto out;  	port = zfcp_get_port_by_wwpn(adapter, wwpn); @@ -250,14 +257,24 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev,  	else  		retval = 0; +	mutex_lock(&zfcp_sysfs_port_units_mutex); +	if (atomic_read(&port->units) > 0) { +		retval = -EBUSY; +		mutex_unlock(&zfcp_sysfs_port_units_mutex); +		goto out; +	} +	/* port is about to be removed, so no more unit_add */ +	atomic_set(&port->units, -1); +	mutex_unlock(&zfcp_sysfs_port_units_mutex); +  	write_lock_irq(&adapter->port_list_lock);  	list_del(&port->list);  	write_unlock_irq(&adapter->port_list_lock);  	put_device(&port->dev); -	zfcp_erp_port_shutdown(port, 0, "syprs_1", NULL); -	zfcp_device_unregister(&port->dev, &zfcp_sysfs_port_attrs); +	zfcp_erp_port_shutdown(port, 0, "syprs_1"); +	device_unregister(&port->dev);   out:  	zfcp_ccw_adapter_put(adapter);  	return retval ? retval : (ssize_t) count; @@ -290,12 +307,14 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev,  {  	struct zfcp_port *port = container_of(dev, struct zfcp_port, dev);  	u64 fcp_lun; +	int retval; -	if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun)) +	if (kstrtoull(buf, 0, (unsigned long long *) &fcp_lun))  		return -EINVAL; -	if (zfcp_unit_add(port, fcp_lun)) -		return -EINVAL; +	retval = zfcp_unit_add(port, fcp_lun); +	if (retval) +		return retval;  	return count;  } @@ -308,7 +327,7 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev,  	struct zfcp_port *port = container_of(dev, struct zfcp_port, dev);  	u64 fcp_lun; -	if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun)) +	if (kstrtoull(buf, 0, (unsigned long long *) &fcp_lun))  		return -EINVAL;  	if (zfcp_unit_remove(port, fcp_lun)) @@ -327,13 +346,13 @@ static struct attribute *zfcp_port_attrs[] = {  	&dev_attr_port_access_denied.attr,  	NULL  }; - -/** - * zfcp_sysfs_port_attrs - sysfs attributes for all other ports - */ -struct attribute_group zfcp_sysfs_port_attrs = { +static struct attribute_group zfcp_port_attr_group = {  	.attrs = zfcp_port_attrs,  }; +const struct attribute_group *zfcp_port_attr_groups[] = { +	&zfcp_port_attr_group, +	NULL, +};  static struct attribute *zfcp_unit_attrs[] = {  	&dev_attr_unit_failed.attr, @@ -344,10 +363,13 @@ static struct attribute *zfcp_unit_attrs[] = {  	&dev_attr_unit_access_readonly.attr,  	NULL  }; - -struct attribute_group zfcp_sysfs_unit_attrs = { +static struct attribute_group zfcp_unit_attr_group = {  	.attrs = zfcp_unit_attrs,  }; +const struct attribute_group *zfcp_unit_attr_groups[] = { +	&zfcp_unit_attr_group, +	NULL, +};  #define ZFCP_DEFINE_LATENCY_ATTR(_name) 				\  static ssize_t								\ diff --git a/drivers/s390/scsi/zfcp_unit.c b/drivers/s390/scsi/zfcp_unit.c index 20796ebc33c..39f5446f721 100644 --- a/drivers/s390/scsi/zfcp_unit.c +++ b/drivers/s390/scsi/zfcp_unit.c @@ -4,7 +4,7 @@   * Tracking of manually configured LUNs and helper functions to   * register the LUNs with the SCSI midlayer.   * - * Copyright IBM Corporation 2010 + * Copyright IBM Corp. 2010   */  #include "zfcp_def.h" @@ -104,7 +104,7 @@ static void zfcp_unit_release(struct device *dev)  {  	struct zfcp_unit *unit = container_of(dev, struct zfcp_unit, dev); -	put_device(&unit->port->dev); +	atomic_dec(&unit->port->units);  	kfree(unit);  } @@ -119,40 +119,49 @@ static void zfcp_unit_release(struct device *dev)  int zfcp_unit_add(struct zfcp_port *port, u64 fcp_lun)  {  	struct zfcp_unit *unit; +	int retval = 0; + +	mutex_lock(&zfcp_sysfs_port_units_mutex); +	if (atomic_read(&port->units) == -1) { +		/* port is already gone */ +		retval = -ENODEV; +		goto out; +	}  	unit = zfcp_unit_find(port, fcp_lun);  	if (unit) {  		put_device(&unit->dev); -		return -EEXIST; +		retval = -EEXIST; +		goto out;  	}  	unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL); -	if (!unit) -		return -ENOMEM; +	if (!unit) { +		retval = -ENOMEM; +		goto out; +	}  	unit->port = port;  	unit->fcp_lun = fcp_lun;  	unit->dev.parent = &port->dev;  	unit->dev.release = zfcp_unit_release; +	unit->dev.groups = zfcp_unit_attr_groups;  	INIT_WORK(&unit->scsi_work, zfcp_unit_scsi_scan_work);  	if (dev_set_name(&unit->dev, "0x%016llx",  			 (unsigned long long) fcp_lun)) {  		kfree(unit); -		return -ENOMEM; +		retval = -ENOMEM; +		goto out;  	} -	get_device(&port->dev); -  	if (device_register(&unit->dev)) {  		put_device(&unit->dev); -		return -ENOMEM; +		retval = -ENOMEM; +		goto out;  	} -	if (sysfs_create_group(&unit->dev.kobj, &zfcp_sysfs_unit_attrs)) { -		device_unregister(&unit->dev); -		return -EINVAL; -	} +	atomic_inc(&port->units); /* under zfcp_sysfs_port_units_mutex ! */  	write_lock_irq(&port->unit_list_lock);  	list_add_tail(&unit->list, &port->unit_list); @@ -160,7 +169,9 @@ int zfcp_unit_add(struct zfcp_port *port, u64 fcp_lun)  	zfcp_unit_scsi_scan(unit); -	return 0; +out: +	mutex_unlock(&zfcp_sysfs_port_units_mutex); +	return retval;  }  /** @@ -238,7 +249,7 @@ int zfcp_unit_remove(struct zfcp_port *port, u64 fcp_lun)  	put_device(&unit->dev); -	zfcp_device_unregister(&unit->dev, &zfcp_sysfs_unit_attrs); +	device_unregister(&unit->dev);  	return 0;  }  | 
