aboutsummaryrefslogtreecommitdiff
path: root/drivers/s390/scsi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/scsi')
-rw-r--r--drivers/s390/scsi/Makefile5
-rw-r--r--drivers/s390/scsi/zfcp_aux.c261
-rw-r--r--drivers/s390/scsi/zfcp_ccw.c127
-rw-r--r--drivers/s390/scsi/zfcp_cfdc.c268
-rw-r--r--drivers/s390/scsi/zfcp_dbf.c1212
-rw-r--r--drivers/s390/scsi/zfcp_dbf.h503
-rw-r--r--drivers/s390/scsi/zfcp_def.h107
-rw-r--r--drivers/s390/scsi/zfcp_erp.c787
-rw-r--r--drivers/s390/scsi/zfcp_ext.h132
-rw-r--r--drivers/s390/scsi/zfcp_fc.c436
-rw-r--r--drivers/s390/scsi/zfcp_fc.h153
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c1078
-rw-r--r--drivers/s390/scsi/zfcp_fsf.h62
-rw-r--r--drivers/s390/scsi/zfcp_qdio.c322
-rw-r--r--drivers/s390/scsi/zfcp_qdio.h158
-rw-r--r--drivers/s390/scsi/zfcp_reqlist.h2
-rw-r--r--drivers/s390/scsi/zfcp_scsi.c313
-rw-r--r--drivers/s390/scsi/zfcp_sysfs.c273
-rw-r--r--drivers/s390/scsi/zfcp_unit.c255
19 files changed, 3041 insertions, 3413 deletions
diff --git a/drivers/s390/scsi/Makefile b/drivers/s390/scsi/Makefile
index cb301cc6178..9259039e886 100644
--- a/drivers/s390/scsi/Makefile
+++ b/drivers/s390/scsi/Makefile
@@ -2,7 +2,8 @@
# Makefile for the S/390 specific device drivers
#
-zfcp-objs := zfcp_aux.o zfcp_ccw.o zfcp_scsi.o zfcp_erp.o zfcp_qdio.o \
- zfcp_fsf.o zfcp_dbf.o zfcp_sysfs.o zfcp_fc.o zfcp_cfdc.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
obj-$(CONFIG_ZFCP) += zfcp.o
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index e331df2122f..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);
}
@@ -56,7 +58,6 @@ static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun)
struct ccw_device *cdev;
struct zfcp_adapter *adapter;
struct zfcp_port *port;
- struct zfcp_unit *unit;
cdev = get_ccwdev_by_busid(&zfcp_ccw_driver, busid);
if (!cdev)
@@ -72,17 +73,11 @@ static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun)
port = zfcp_get_port_by_wwpn(adapter, wwpn);
if (!port)
goto out_port;
+ flush_work(&port->rport_work);
- unit = zfcp_unit_enqueue(port, lun);
- if (IS_ERR(unit))
- goto out_unit;
-
- zfcp_erp_unit_reopen(unit, 0, "auidc_1", NULL);
- zfcp_erp_wait(adapter);
- flush_work(&unit->scsi_work);
-
-out_unit:
+ zfcp_unit_add(port, lun);
put_device(&port->dev);
+
out_port:
zfcp_ccw_adapter_put(adapter);
out_ccw_device:
@@ -98,24 +93,22 @@ static void __init zfcp_init_device_setup(char *devstr)
u64 wwpn, lun;
/* duplicate devstr and keep the original for sysfs presentation*/
- str_saved = kmalloc(strlen(devstr) + 1, GFP_KERNEL);
+ str_saved = kstrdup(devstr, GFP_KERNEL);
str = str_saved;
if (!str)
return;
- strcpy(str, devstr);
-
token = strsep(&str, ",");
if (!token || strlen(token) >= ZFCP_BUS_ID_SIZE)
goto err_out;
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);
@@ -131,41 +124,22 @@ 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_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.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_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;
-
- retval = misc_register(&zfcp_cfdc_misc);
- if (retval) {
- pr_err("Registering the misc device zfcp_cfdc failed\n");
- goto out_misc;
- }
+ scsi_transport_reserve_device(zfcp_scsi_transport_template,
+ sizeof(struct zfcp_scsi_dev));
retval = ccw_driver_register(&zfcp_ccw_driver);
if (retval) {
@@ -179,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;
}
@@ -201,42 +167,14 @@ 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);
/**
- * zfcp_get_unit_by_lun - find unit in unit list of port by FCP LUN
- * @port: pointer to port to search for unit
- * @fcp_lun: FCP LUN to search for
- *
- * Returns: pointer to zfcp_unit or NULL
- */
-struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *port, u64 fcp_lun)
-{
- unsigned long flags;
- struct zfcp_unit *unit;
-
- read_lock_irqsave(&port->unit_list_lock, flags);
- list_for_each_entry(unit, &port->unit_list, list)
- if (unit->fcp_lun == fcp_lun) {
- if (!get_device(&unit->dev))
- unit = NULL;
- read_unlock_irqrestore(&port->unit_list_lock, flags);
- return unit;
- }
- read_unlock_irqrestore(&port->unit_list_lock, flags);
- return NULL;
-}
-
-/**
* zfcp_get_port_by_wwpn - find port in port list of adapter by wwpn
* @adapter: pointer to adapter to search for port
* @wwpn: wwpn to search for
@@ -261,92 +199,6 @@ struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *adapter,
return NULL;
}
-/**
- * zfcp_unit_release - dequeue unit
- * @dev: pointer to device
- *
- * waits until all work is done on unit and removes it then from the unit->list
- * of the associated port.
- */
-static void zfcp_unit_release(struct device *dev)
-{
- struct zfcp_unit *unit = container_of(dev, struct zfcp_unit, dev);
-
- put_device(&unit->port->dev);
- kfree(unit);
-}
-
-/**
- * zfcp_unit_enqueue - enqueue unit to unit list of a port.
- * @port: pointer to port where unit is added
- * @fcp_lun: FCP LUN of unit to be enqueued
- * Returns: pointer to enqueued unit on success, ERR_PTR on error
- *
- * Sets up some unit internal structures and creates sysfs entry.
- */
-struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun)
-{
- struct zfcp_unit *unit;
- int retval = -ENOMEM;
-
- get_device(&port->dev);
-
- unit = zfcp_get_unit_by_lun(port, fcp_lun);
- if (unit) {
- put_device(&unit->dev);
- retval = -EEXIST;
- goto err_out;
- }
-
- unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL);
- if (!unit)
- goto err_out;
-
- unit->port = port;
- unit->fcp_lun = fcp_lun;
- unit->dev.parent = &port->dev;
- unit->dev.release = zfcp_unit_release;
-
- if (dev_set_name(&unit->dev, "0x%016llx",
- (unsigned long long) fcp_lun)) {
- kfree(unit);
- goto err_out;
- }
- retval = -EINVAL;
-
- INIT_WORK(&unit->scsi_work, zfcp_scsi_scan);
-
- spin_lock_init(&unit->latencies.lock);
- unit->latencies.write.channel.min = 0xFFFFFFFF;
- unit->latencies.write.fabric.min = 0xFFFFFFFF;
- unit->latencies.read.channel.min = 0xFFFFFFFF;
- unit->latencies.read.fabric.min = 0xFFFFFFFF;
- unit->latencies.cmd.channel.min = 0xFFFFFFFF;
- unit->latencies.cmd.fabric.min = 0xFFFFFFFF;
-
- if (device_register(&unit->dev)) {
- put_device(&unit->dev);
- goto err_out;
- }
-
- if (sysfs_create_group(&unit->dev.kobj, &zfcp_sysfs_unit_attrs))
- goto err_out_put;
-
- write_lock_irq(&port->unit_list_lock);
- list_add_tail(&unit->list, &port->unit_list);
- write_unlock_irq(&port->unit_list_lock);
-
- atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status);
-
- return unit;
-
-err_out_put:
- device_unregister(&unit->dev);
-err_out:
- put_device(&port->dev);
- return ERR_PTR(retval);
-}
-
static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter)
{
adapter->pool.erp_req =
@@ -376,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;
@@ -406,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);
}
@@ -427,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;
@@ -503,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;
@@ -526,6 +378,10 @@ struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *ccw_device)
rwlock_init(&adapter->port_list_lock);
INIT_LIST_HEAD(&adapter->port_list);
+ INIT_LIST_HEAD(&adapter->events.list);
+ INIT_WORK(&adapter->events.work, zfcp_fc_post_event);
+ spin_lock_init(&adapter->events.list_lock);
+
init_waitqueue_head(&adapter->erp_ready_wq);
init_waitqueue_head(&adapter->erp_done_wqh);
@@ -550,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:
@@ -564,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 */
@@ -598,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);
@@ -653,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);
@@ -663,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)) {
@@ -676,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);
@@ -688,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 ce1cc7a11fb..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,20 +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_modify_adapter_status(adapter, "ccresu1", NULL,
- ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET);
+ 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);
@@ -66,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
*
@@ -123,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);
}
@@ -164,33 +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_erp_modify_adapter_status(adapter, "ccsonl1", NULL,
- ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET);
- zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
- "ccsonl2", NULL);
- zfcp_erp_wait(adapter);
-
- flush_work(&adapter->scan_work);
-
+ 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);
@@ -198,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
@@ -214,26 +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_modify_adapter_status(adapter, "ccnoti3", NULL,
- ZFCP_STATUS_COMMON_RUNNING,
- ZFCP_SET);
+ 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;
}
@@ -252,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,
@@ -269,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 1a2db0a3573..00000000000
--- a/drivers/s390/scsi/zfcp_cfdc.c
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * zfcp device driver
- *
- * Userspace interface for accessing the
- * Access Control Lists / Control File Data Channel
- *
- * Copyright IBM Corporation 2008, 2009
- */
-
-#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 = kmalloc(sizeof(struct zfcp_cfdc_data), GFP_KERNEL);
- if (!data) {
- retval = -ENOMEM;
- goto no_mem_sense;
- }
-
- retval = copy_from_user(data, data_user, sizeof(*data));
- if (retval) {
- retval = -EFAULT;
- goto free_buffer;
- }
-
- 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
-};
-
-struct miscdevice zfcp_cfdc_misc = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = "zfcp_cfdc",
- .fops = &zfcp_cfdc_fops,
-};
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c
index 075852f6968..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,979 +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.serial = scsi_cmnd->serial_number;
- }
- 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, "scsi_cmnd", "0x%0Lx", r->u.fcp.cmnd);
- zfcp_dbf_out(p, "scsi_serial", "0x%016Lx", r->u.fcp.serial);
- *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, "unit_status", "0x%08x", r->u.trigger.us);
- 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_unit - trace event for unit state change
- * @id: identifier for trigger of state change
- * @ref: additional reference (e.g. request)
- * @unit: unit
- */
-void zfcp_dbf_rec_unit(char *id, void *ref, struct zfcp_unit *unit)
-{
- struct zfcp_port *port = unit->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, &unit->status,
- &unit->erp_counter, port->wwpn, port->d_id,
- unit->fcp_lun);
-}
+ 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
- * @unit: unit
- */
-void zfcp_dbf_rec_trigger(char *id2, void *ref, u8 want, u8 need, void *action,
- struct zfcp_adapter *adapter, struct zfcp_port *port,
- struct zfcp_unit *unit)
-{
- 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 (unit)
- r->u.trigger.us = atomic_read(&unit->status);
- r->u.trigger.fcp_lun = unit ? unit->fcp_lun : 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;
- rec->scsi_serial = scsi_cmnd->serial_number;
- 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_out(&p, "scsi_serial", "0x%016Lx", r->scsi_serial);
- 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
@@ -1002,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 = kmalloc(sizeof(struct zfcp_dbf), GFP_KERNEL);
+ 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 457e046f2d2..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,338 +13,371 @@
#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 us;
- 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;
- u64 serial;
- } 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;
+
+/**
+ * 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_san_record {
- u8 tag[ZFCP_DBF_TAG_SIZE];
- u64 fsf_reqid;
- u32 fsf_seqno;
+/**
+ * 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;
- u64 scsi_serial;
-#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);
}
/**
* zfcp_dbf_scsi_devreset - trace event for Logical Unit or Target Reset
* @tag: tag indicating success or failure of reset operation
+ * @scmnd: SCSI command which caused this error recovery
* @flag: indicates type of reset (Target Reset, Logical Unit Reset)
- * @unit: unit that needs reset
- * @scsi_cmnd: SCSI command which caused this error recovery
*/
static inline
-void zfcp_dbf_scsi_devreset(const char *tag, u8 flag, struct zfcp_unit *unit,
- struct scsi_cmnd *scsi_cmnd)
+void zfcp_dbf_scsi_devreset(char *tag, struct scsi_cmnd *scmnd, u8 flag)
{
- zfcp_dbf_scsi(flag == FCP_TMF_TGT_RESET ? "trst" : "lrst", tag, 1,
- unit->port->adapter->dbf, scsi_cmnd, NULL, 0);
+ char tmp_tag[ZFCP_DBF_TAG_LEN];
+
+ if (flag == FCP_TMF_TGT_RESET)
+ memcpy(tmp_tag, "tr_", 3);
+ else
+ memcpy(tmp_tag, "lr_", 3);
+
+ 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 9fa1b064893..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
@@ -37,6 +37,7 @@
#include <asm/ebcdic.h>
#include <asm/sysinfo.h>
#include "zfcp_fsf.h"
+#include "zfcp_fc.h"
#include "zfcp_qdio.h"
struct zfcp_reqlist;
@@ -71,22 +72,21 @@ 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
/* remote port status */
#define ZFCP_STATUS_PORT_PHYS_OPEN 0x00000001
#define ZFCP_STATUS_PORT_LINK_TEST 0x00000002
-/* logical unit status */
-#define ZFCP_STATUS_UNIT_SHARED 0x00000004
-#define ZFCP_STATUS_UNIT_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
@@ -105,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;
};
@@ -115,7 +115,7 @@ struct zfcp_erp_action {
int action; /* requested action code */
struct zfcp_adapter *adapter; /* device which should be recovered */
struct zfcp_port *port;
- struct zfcp_unit *unit;
+ struct scsi_device *sdev;
u32 status; /* recovery status */
u32 step; /* active step of this erp action */
unsigned long fsf_req_id;
@@ -187,9 +187,11 @@ 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;
+ struct zfcp_fc_events events;
};
struct zfcp_port {
@@ -199,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 */
@@ -212,23 +215,69 @@ struct zfcp_port {
struct work_struct test_link_work;
struct work_struct rport_work;
enum { RPORT_NONE, RPORT_ADD, RPORT_DEL } rport_task;
+ unsigned int starget_id;
};
+/**
+ * struct zfcp_unit - LUN configured via zfcp sysfs
+ * @dev: struct device for sysfs representation and reference counting
+ * @list: entry in LUN/unit list per zfcp_port
+ * @port: reference to zfcp_port where this LUN is configured
+ * @fcp_lun: 64 bit LUN value
+ * @scsi_work: for running scsi_scan_target
+ *
+ * This is the representation of a LUN that has been configured for
+ * usage. The main data here is the 64 bit LUN value, data for
+ * running I/O and recovery is in struct zfcp_scsi_dev.
+ */
struct zfcp_unit {
- struct device dev;
- struct list_head list; /* list of logical units */
- struct zfcp_port *port; /* remote port of unit */
- atomic_t status; /* status of this logical unit */
- u64 fcp_lun; /* own FCP_LUN */
- u32 handle; /* handle assigned by FSF */
- struct scsi_device *device; /* scsi device struct pointer */
- struct zfcp_erp_action erp_action; /* pending error recovery */
- atomic_t erp_counter;
- struct zfcp_latencies latencies;
+ struct device dev;
+ struct list_head list;
+ struct zfcp_port *port;
+ u64 fcp_lun;
struct work_struct scsi_work;
};
/**
+ * struct zfcp_scsi_dev - zfcp data per SCSI device
+ * @status: zfcp internal status flags
+ * @lun_handle: handle from "open lun" for issuing FSF requests
+ * @erp_action: zfcp erp data for opening and recovering this LUN
+ * @erp_counter: zfcp erp counter for this LUN
+ * @latencies: FSF channel and fabric latencies
+ * @port: zfcp_port where this LUN belongs to
+ */
+struct zfcp_scsi_dev {
+ atomic_t status;
+ u32 lun_handle;
+ struct zfcp_erp_action erp_action;
+ atomic_t erp_counter;
+ struct zfcp_latencies latencies;
+ struct zfcp_port *port;
+};
+
+/**
+ * sdev_to_zfcp - Access zfcp LUN data for SCSI device
+ * @sdev: scsi_device where to get the zfcp_scsi_dev pointer
+ */
+static inline struct zfcp_scsi_dev *sdev_to_zfcp(struct scsi_device *sdev)
+{
+ return scsi_transport_device_data(sdev);
+}
+
+/**
+ * zfcp_scsi_dev_lun - Return SCSI device LUN as 64 bit FCP LUN
+ * @sdev: SCSI device where to get the LUN from
+ */
+static inline u64 zfcp_scsi_dev_lun(struct scsi_device *sdev)
+{
+ u64 fcp_lun;
+
+ int_to_scsilun(sdev->lun, (struct scsi_lun *)&fcp_lun);
+ return fcp_lun;
+}
+
+/**
* struct zfcp_fsf_req - basic FSF request structure
* @list: list of FSF requests
* @req_id: unique request ID
@@ -244,7 +293,6 @@ struct zfcp_unit {
* @erp_action: reference to erp action if request issued on behalf of ERP
* @pool: reference to memory pool if used for this request
* @issued: time when request was send (STCK)
- * @unit: reference to unit if this request is a SCSI request
* @handler: handler which should be called to process response
*/
struct zfcp_fsf_req {
@@ -262,24 +310,13 @@ struct zfcp_fsf_req {
struct zfcp_erp_action *erp_action;
mempool_t *pool;
unsigned long long issued;
- struct zfcp_unit *unit;
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;
-};
-
-/********************** ZFCP SPECIFIC DEFINES ********************************/
-
-#define ZFCP_SET 0x00000100
-#define ZFCP_CLEAR 0x00000200
+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 e3dbeda9717..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"
@@ -21,6 +21,7 @@ enum zfcp_erp_act_flags {
ZFCP_STATUS_ERP_DISMISSING = 0x00100000,
ZFCP_STATUS_ERP_DISMISSED = 0x00200000,
ZFCP_STATUS_ERP_LOWMEM = 0x00400000,
+ ZFCP_STATUS_ERP_NO_REF = 0x00800000,
};
enum zfcp_erp_steps {
@@ -29,12 +30,12 @@ enum zfcp_erp_steps {
ZFCP_ERP_STEP_PHYS_PORT_CLOSING = 0x0010,
ZFCP_ERP_STEP_PORT_CLOSING = 0x0100,
ZFCP_ERP_STEP_PORT_OPENING = 0x0800,
- ZFCP_ERP_STEP_UNIT_CLOSING = 0x1000,
- ZFCP_ERP_STEP_UNIT_OPENING = 0x2000,
+ ZFCP_ERP_STEP_LUN_CLOSING = 0x1000,
+ ZFCP_ERP_STEP_LUN_OPENING = 0x2000,
};
enum zfcp_erp_act_type {
- ZFCP_ERP_ACTION_REOPEN_UNIT = 1,
+ ZFCP_ERP_ACTION_REOPEN_LUN = 1,
ZFCP_ERP_ACTION_REOPEN_PORT = 2,
ZFCP_ERP_ACTION_REOPEN_PORT_FORCED = 3,
ZFCP_ERP_ACTION_REOPEN_ADAPTER = 4,
@@ -56,9 +57,8 @@ enum zfcp_erp_act_result {
static void zfcp_erp_adapter_block(struct zfcp_adapter *adapter, int mask)
{
- zfcp_erp_modify_adapter_status(adapter, "erablk1", NULL,
- ZFCP_STATUS_COMMON_UNBLOCKED | mask,
- ZFCP_CLEAR);
+ zfcp_erp_clear_adapter_status(adapter,
+ ZFCP_STATUS_COMMON_UNBLOCKED | mask);
}
static int zfcp_erp_action_exists(struct zfcp_erp_action *act)
@@ -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)
@@ -88,23 +88,26 @@ static void zfcp_erp_action_dismiss(struct zfcp_erp_action *act)
zfcp_erp_action_ready(act);
}
-static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *unit)
+static void zfcp_erp_action_dismiss_lun(struct scsi_device *sdev)
{
- if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
- zfcp_erp_action_dismiss(&unit->erp_action);
+ struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
+
+ if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
+ zfcp_erp_action_dismiss(&zfcp_sdev->erp_action);
}
static void zfcp_erp_action_dismiss_port(struct zfcp_port *port)
{
- struct zfcp_unit *unit;
+ struct scsi_device *sdev;
if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
zfcp_erp_action_dismiss(&port->erp_action);
else {
- read_lock(&port->unit_list_lock);
- list_for_each_entry(unit, &port->unit_list, list)
- zfcp_erp_action_dismiss_unit(unit);
- read_unlock(&port->unit_list_lock);
+ 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);
}
}
@@ -124,15 +127,17 @@ static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter)
static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter,
struct zfcp_port *port,
- struct zfcp_unit *unit)
+ struct scsi_device *sdev)
{
int need = want;
- int u_status, p_status, a_status;
+ int l_status, p_status, a_status;
+ struct zfcp_scsi_dev *zfcp_sdev;
switch (want) {
- case ZFCP_ERP_ACTION_REOPEN_UNIT:
- u_status = atomic_read(&unit->status);
- if (u_status & ZFCP_STATUS_COMMON_ERP_INUSE)
+ case ZFCP_ERP_ACTION_REOPEN_LUN:
+ zfcp_sdev = sdev_to_zfcp(sdev);
+ l_status = atomic_read(&zfcp_sdev->status);
+ if (l_status & ZFCP_STATUS_COMMON_ERP_INUSE)
return 0;
p_status = atomic_read(&port->status);
if (!(p_status & ZFCP_STATUS_COMMON_RUNNING) ||
@@ -141,15 +146,21 @@ static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter,
if (!(p_status & ZFCP_STATUS_COMMON_UNBLOCKED))
need = ZFCP_ERP_ACTION_REOPEN_PORT;
/* fall through */
- case ZFCP_ERP_ACTION_REOPEN_PORT:
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
p_status = atomic_read(&port->status);
+ if (!(p_status & ZFCP_STATUS_COMMON_OPEN))
+ need = ZFCP_ERP_ACTION_REOPEN_PORT;
+ /* fall through */
+ case ZFCP_ERP_ACTION_REOPEN_PORT:
+ p_status = atomic_read(&port->status);
if (p_status & ZFCP_STATUS_COMMON_ERP_INUSE)
return 0;
a_status = atomic_read(&adapter->status);
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 */
@@ -165,22 +176,29 @@ static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter,
return need;
}
-static struct zfcp_erp_action *zfcp_erp_setup_act(int need,
+static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status,
struct zfcp_adapter *adapter,
struct zfcp_port *port,
- struct zfcp_unit *unit)
+ struct scsi_device *sdev)
{
struct zfcp_erp_action *erp_action;
- u32 status = 0;
+ struct zfcp_scsi_dev *zfcp_sdev;
switch (need) {
- case ZFCP_ERP_ACTION_REOPEN_UNIT:
- if (!get_device(&unit->dev))
- return NULL;
- atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status);
- erp_action = &unit->erp_action;
- if (!(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_RUNNING))
- status = ZFCP_STATUS_ERP_CLOSE_ONLY;
+ case ZFCP_ERP_ACTION_REOPEN_LUN:
+ zfcp_sdev = sdev_to_zfcp(sdev);
+ if (!(act_status & ZFCP_STATUS_ERP_NO_REF))
+ if (scsi_device_get(sdev))
+ return NULL;
+ 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;
break;
case ZFCP_ERP_ACTION_REOPEN_PORT:
@@ -190,8 +208,10 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need,
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))
- status = ZFCP_STATUS_ERP_CLOSE_ONLY;
+ act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;
break;
case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
@@ -199,66 +219,65 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need,
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))
- status = ZFCP_STATUS_ERP_CLOSE_ONLY;
+ act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;
break;
default:
return NULL;
}
- memset(erp_action, 0, sizeof(struct zfcp_erp_action));
erp_action->adapter = adapter;
- erp_action->port = port;
- erp_action->unit = unit;
erp_action->action = need;
- erp_action->status = status;
+ erp_action->status = act_status;
return erp_action;
}
static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter,
struct zfcp_port *port,
- struct zfcp_unit *unit, char *id, void *ref)
+ struct scsi_device *sdev,
+ 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;
- need = zfcp_erp_required_act(want, adapter, port, unit);
+ need = zfcp_erp_required_act(want, adapter, port, sdev);
if (!need)
goto out;
- atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status);
- act = zfcp_erp_setup_act(need, adapter, port, unit);
+ act = zfcp_erp_setup_act(need, act_status, adapter, port, sdev);
if (!act)
goto out;
+ atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status);
++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, unit);
+ 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);
/* ensure propagation of failed status to new devices */
if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
- zfcp_erp_adapter_failed(adapter, "erareo1", NULL);
+ zfcp_erp_set_adapter_status(adapter,
+ ZFCP_STATUS_COMMON_ERP_FAILED);
return -EIO;
}
return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER,
- adapter, NULL, NULL, id, ref);
+ adapter, NULL, NULL, id, 0);
}
/**
@@ -266,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;
@@ -278,10 +295,11 @@ void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear,
write_lock_irqsave(&adapter->erp_lock, flags);
if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
- zfcp_erp_adapter_failed(adapter, "erareo1", NULL);
+ zfcp_erp_set_adapter_status(adapter,
+ ZFCP_STATUS_COMMON_ERP_FAILED);
else
zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, adapter,
- NULL, NULL, id, ref);
+ NULL, NULL, id, 0);
write_unlock_irqrestore(&adapter->erp_lock, flags);
}
@@ -290,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);
}
/**
@@ -304,38 +321,21 @@ 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)
-{
- int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
- zfcp_erp_port_reopen(port, clear | flags, id, ref);
-}
-
-/**
- * zfcp_erp_unit_shutdown - Shutdown unit
- * @unit: Unit to shut down.
- * @clear: Status flags to clear.
- * @id: Id for debug trace event.
- * @ref: Reference for debug trace event.
*/
-void zfcp_erp_unit_shutdown(struct zfcp_unit *unit, 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_unit_reopen(unit, clear | flags, id, ref);
+ zfcp_erp_port_reopen(port, clear | flags, id);
}
static void zfcp_erp_port_block(struct zfcp_port *port, int clear)
{
- zfcp_erp_modify_port_status(port, "erpblk1", NULL,
- ZFCP_STATUS_COMMON_UNBLOCKED | clear,
- ZFCP_CLEAR);
+ zfcp_erp_clear_port_status(port,
+ 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);
@@ -344,136 +344,171 @@ 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);
+ 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);
if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
/* ensure propagation of failed status to new devices */
- zfcp_erp_port_failed(port, "erpreo1", NULL);
+ zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_ERP_FAILED);
return -EIO;
}
return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT,
- port->adapter, port, NULL, id, ref);
+ 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;
}
-static void zfcp_erp_unit_block(struct zfcp_unit *unit, int clear_mask)
+static void zfcp_erp_lun_block(struct scsi_device *sdev, int clear_mask)
{
- zfcp_erp_modify_unit_status(unit, "erublk1", NULL,
- ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask,
- ZFCP_CLEAR);
+ zfcp_erp_clear_lun_status(sdev,
+ ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask);
}
-static void _zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, char *id,
- void *ref)
+static void _zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id,
+ u32 act_status)
{
- struct zfcp_adapter *adapter = unit->port->adapter;
+ struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
+ struct zfcp_adapter *adapter = zfcp_sdev->port->adapter;
- zfcp_erp_unit_block(unit, clear);
+ zfcp_erp_lun_block(sdev, clear);
- if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
+ if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
return;
- zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_UNIT,
- adapter, unit->port, unit, id, ref);
+ zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_LUN, adapter,
+ zfcp_sdev->port, sdev, id, act_status);
}
/**
- * zfcp_erp_unit_reopen - initiate reopen of a unit
- * @unit: unit to be reopened
- * @clear_mask: specifies flags in unit status to be cleared
+ * 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_unit_reopen(struct zfcp_unit *unit, int clear, char *id,
- void *ref)
+void zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id)
{
unsigned long flags;
- struct zfcp_port *port = unit->port;
+ struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
+ struct zfcp_port *port = zfcp_sdev->port;
struct zfcp_adapter *adapter = port->adapter;
write_lock_irqsave(&adapter->erp_lock, flags);
- _zfcp_erp_unit_reopen(unit, clear, id, ref);
+ _zfcp_erp_lun_reopen(sdev, clear, id, 0);
write_unlock_irqrestore(&adapter->erp_lock, flags);
}
-static int status_change_set(unsigned long mask, atomic_t *status)
+/**
+ * zfcp_erp_lun_shutdown - Shutdown LUN
+ * @sdev: SCSI device / LUN to shut down.
+ * @clear: Status flags to clear.
+ * @id: Id for debug trace event.
+ */
+void zfcp_erp_lun_shutdown(struct scsi_device *sdev, int clear, char *id)
{
- return (atomic_read(status) ^ mask) & mask;
+ int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
+ zfcp_erp_lun_reopen(sdev, clear | flags, id);
}
-static int status_change_clear(unsigned long mask, atomic_t *status)
+/**
+ * zfcp_erp_lun_shutdown_wait - Shutdown LUN and wait for erp completion
+ * @sdev: SCSI device / LUN to shut down.
+ * @id: Id for debug trace event.
+ *
+ * Do not acquire a reference for the LUN when creating the ERP
+ * action. It is safe, because this function waits for the ERP to
+ * complete first. This allows to shutdown the LUN, even when the SCSI
+ * device is in the state SDEV_DEL when scsi_device_get will fail.
+ */
+void zfcp_erp_lun_shutdown_wait(struct scsi_device *sdev, char *id)
{
- return atomic_read(status) & mask;
+ unsigned long flags;
+ struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
+ struct zfcp_port *port = zfcp_sdev->port;
+ struct zfcp_adapter *adapter = port->adapter;
+ 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, ZFCP_STATUS_ERP_NO_REF);
+ write_unlock_irqrestore(&adapter->erp_lock, flags);
+
+ zfcp_erp_wait(adapter);
+}
+
+static int status_change_set(unsigned long mask, atomic_t *status)
+{
+ return (atomic_read(status) ^ mask) & mask;
}
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);
}
-static void zfcp_erp_unit_unblock(struct zfcp_unit *unit)
+static void zfcp_erp_lun_unblock(struct scsi_device *sdev)
{
- if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status))
- zfcp_dbf_rec_unit("eruubl1", NULL, unit);
- atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status);
+ struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
+
+ if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &zfcp_sdev->status))
+ 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)
@@ -490,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
@@ -545,41 +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_unit_reopen_all(struct zfcp_port *port, int clear,
- char *id, void *ref)
+static void _zfcp_erp_lun_reopen_all(struct zfcp_port *port, int clear,
+ char *id)
{
- struct zfcp_unit *unit;
+ struct scsi_device *sdev;
- read_lock(&port->unit_list_lock);
- list_for_each_entry(unit, &port->unit_list, list)
- _zfcp_erp_unit_reopen(unit, clear, id, ref);
- read_unlock(&port->unit_list_lock);
+ 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, 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_UNIT:
- _zfcp_erp_unit_reopen(act->unit, 0, "ersff_4", NULL);
+ case ZFCP_ERP_ACTION_REOPEN_LUN:
+ _zfcp_erp_lun_reopen(act->sdev, 0, "ersff_4", 0);
break;
}
}
@@ -588,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_unit_reopen_all(act->port, 0, "ersfs_3", NULL);
+ _zfcp_erp_lun_reopen_all(act->port, 0, "ersfs_3");
break;
}
}
@@ -613,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;
@@ -631,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)
@@ -654,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;
@@ -696,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;
@@ -714,6 +737,14 @@ 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.sr_data,
+ act->adapter->stat_read_buf_num, GFP_KERNEL))
+ return ZFCP_ERP_FAILED;
+
+ if (mempool_resize(act->adapter->pool.status_read_req,
+ act->adapter->stat_read_buf_num, GFP_KERNEL))
+ return ZFCP_ERP_FAILED;
+
atomic_set(&act->adapter->stat_miss, act->adapter->stat_read_buf_num);
if (zfcp_status_read_refill(act->adapter))
return ZFCP_ERP_FAILED;
@@ -730,9 +761,8 @@ static void zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *act)
zfcp_fsf_req_dismiss_all(adapter);
adapter->fsf_req_seq_no = 0;
zfcp_fc_wka_ports_force_offline(adapter->gs);
- /* all ports and units are closed */
- zfcp_erp_modify_adapter_status(adapter, "erascl1", NULL,
- ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR);
+ /* all ports and LUNs are closed */
+ zfcp_erp_clear_adapter_status(adapter, ZFCP_STATUS_COMMON_OPEN);
atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK |
ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status);
@@ -742,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);
@@ -849,7 +879,7 @@ static int zfcp_erp_open_ptp_port(struct zfcp_erp_action *act)
struct zfcp_port *port = act->port;
if (port->wwpn != adapter->peer_wwpn) {
- zfcp_erp_port_failed(port, "eroptp1", NULL);
+ zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_ERP_FAILED);
return ZFCP_ERP_FAILED;
}
port->d_id = adapter->peer_d_id;
@@ -885,8 +915,7 @@ static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act)
}
if (port->d_id && !(p_status & ZFCP_STATUS_COMMON_NOESC)) {
port->d_id = 0;
- _zfcp_erp_port_reopen(port, 0, "erpsoc1", NULL);
- return ZFCP_ERP_EXIT;
+ return ZFCP_ERP_FAILED;
}
/* fall through otherwise */
}
@@ -922,82 +951,86 @@ close_init_done:
return zfcp_erp_port_strategy_open_common(erp_action);
}
-static void zfcp_erp_unit_strategy_clearstati(struct zfcp_unit *unit)
+static void zfcp_erp_lun_strategy_clearstati(struct scsi_device *sdev)
{
- atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
- ZFCP_STATUS_UNIT_SHARED |
- ZFCP_STATUS_UNIT_READONLY,
- &unit->status);
+ struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
+
+ atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED,
+ &zfcp_sdev->status);
}
-static int zfcp_erp_unit_strategy_close(struct zfcp_erp_action *erp_action)
+static int zfcp_erp_lun_strategy_close(struct zfcp_erp_action *erp_action)
{
- int retval = zfcp_fsf_close_unit(erp_action);
+ int retval = zfcp_fsf_close_lun(erp_action);
if (retval == -ENOMEM)
return ZFCP_ERP_NOMEM;
- erp_action->step = ZFCP_ERP_STEP_UNIT_CLOSING;
+ erp_action->step = ZFCP_ERP_STEP_LUN_CLOSING;
if (retval)
return ZFCP_ERP_FAILED;
return ZFCP_ERP_CONTINUES;
}
-static int zfcp_erp_unit_strategy_open(struct zfcp_erp_action *erp_action)
+static int zfcp_erp_lun_strategy_open(struct zfcp_erp_action *erp_action)
{
- int retval = zfcp_fsf_open_unit(erp_action);
+ int retval = zfcp_fsf_open_lun(erp_action);
if (retval == -ENOMEM)
return ZFCP_ERP_NOMEM;
- erp_action->step = ZFCP_ERP_STEP_UNIT_OPENING;
+ erp_action->step = ZFCP_ERP_STEP_LUN_OPENING;
if (retval)
return ZFCP_ERP_FAILED;
return ZFCP_ERP_CONTINUES;
}
-static int zfcp_erp_unit_strategy(struct zfcp_erp_action *erp_action)
+static int zfcp_erp_lun_strategy(struct zfcp_erp_action *erp_action)
{
- struct zfcp_unit *unit = erp_action->unit;
+ struct scsi_device *sdev = erp_action->sdev;
+ struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
switch (erp_action->step) {
case ZFCP_ERP_STEP_UNINITIALIZED:
- zfcp_erp_unit_strategy_clearstati(unit);
- if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN)
- return zfcp_erp_unit_strategy_close(erp_action);
+ zfcp_erp_lun_strategy_clearstati(sdev);
+ if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_OPEN)
+ return zfcp_erp_lun_strategy_close(erp_action);
/* already closed, fall through */
- case ZFCP_ERP_STEP_UNIT_CLOSING:
- if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN)
+ case ZFCP_ERP_STEP_LUN_CLOSING:
+ if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_OPEN)
return ZFCP_ERP_FAILED;
if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
return ZFCP_ERP_EXIT;
- return zfcp_erp_unit_strategy_open(erp_action);
+ return zfcp_erp_lun_strategy_open(erp_action);
- case ZFCP_ERP_STEP_UNIT_OPENING:
- if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN)
+ case ZFCP_ERP_STEP_LUN_OPENING:
+ if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_OPEN)
return ZFCP_ERP_SUCCEEDED;
}
return ZFCP_ERP_FAILED;
}
-static int zfcp_erp_strategy_check_unit(struct zfcp_unit *unit, int result)
+static int zfcp_erp_strategy_check_lun(struct scsi_device *sdev, int result)
{
+ struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
+
switch (result) {
case ZFCP_ERP_SUCCEEDED :
- atomic_set(&unit->erp_counter, 0);
- zfcp_erp_unit_unblock(unit);
+ atomic_set(&zfcp_sdev->erp_counter, 0);
+ zfcp_erp_lun_unblock(sdev);
break;
case ZFCP_ERP_FAILED :
- atomic_inc(&unit->erp_counter);
- if (atomic_read(&unit->erp_counter) > ZFCP_MAX_ERPS) {
- dev_err(&unit->port->adapter->ccw_device->dev,
- "ERP failed for unit 0x%016Lx on "
+ atomic_inc(&zfcp_sdev->erp_counter);
+ if (atomic_read(&zfcp_sdev->erp_counter) > ZFCP_MAX_ERPS) {
+ dev_err(&zfcp_sdev->port->adapter->ccw_device->dev,
+ "ERP failed for LUN 0x%016Lx on "
"port 0x%016Lx\n",
- (unsigned long long)unit->fcp_lun,
- (unsigned long long)unit->port->wwpn);
- zfcp_erp_unit_failed(unit, "erusck1", NULL);
+ (unsigned long long)zfcp_scsi_dev_lun(sdev),
+ (unsigned long long)zfcp_sdev->port->wwpn);
+ zfcp_erp_set_lun_status(sdev,
+ ZFCP_STATUS_COMMON_ERP_FAILED);
}
break;
}
- if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
- zfcp_erp_unit_block(unit, 0);
+ if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
+ zfcp_erp_lun_block(sdev, 0);
result = ZFCP_ERP_EXIT;
}
return result;
@@ -1021,7 +1054,8 @@ static int zfcp_erp_strategy_check_port(struct zfcp_port *port, int result)
dev_err(&port->adapter->ccw_device->dev,
"ERP failed for remote port 0x%016Lx\n",
(unsigned long long)port->wwpn);
- zfcp_erp_port_failed(port, "erpsck1", NULL);
+ zfcp_erp_set_port_status(port,
+ ZFCP_STATUS_COMMON_ERP_FAILED);
}
break;
}
@@ -1048,7 +1082,8 @@ static int zfcp_erp_strategy_check_adapter(struct zfcp_adapter *adapter,
dev_err(&adapter->ccw_device->dev,
"ERP cannot recover an error "
"on the FCP device\n");
- zfcp_erp_adapter_failed(adapter, "erasck1", NULL);
+ zfcp_erp_set_adapter_status(adapter,
+ ZFCP_STATUS_COMMON_ERP_FAILED);
}
break;
}
@@ -1065,12 +1100,12 @@ static int zfcp_erp_strategy_check_target(struct zfcp_erp_action *erp_action,
{
struct zfcp_adapter *adapter = erp_action->adapter;
struct zfcp_port *port = erp_action->port;
- struct zfcp_unit *unit = erp_action->unit;
+ struct scsi_device *sdev = erp_action->sdev;
switch (erp_action->action) {
- case ZFCP_ERP_ACTION_REOPEN_UNIT:
- result = zfcp_erp_strategy_check_unit(unit, result);
+ case ZFCP_ERP_ACTION_REOPEN_LUN:
+ result = zfcp_erp_strategy_check_lun(sdev, result);
break;
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
@@ -1105,7 +1140,8 @@ static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret)
int action = act->action;
struct zfcp_adapter *adapter = act->adapter;
struct zfcp_port *port = act->port;
- struct zfcp_unit *unit = act->unit;
+ struct scsi_device *sdev = act->sdev;
+ struct zfcp_scsi_dev *zfcp_sdev;
u32 erp_status = act->status;
switch (action) {
@@ -1113,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;
@@ -1123,16 +1159,17 @@ 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;
- case ZFCP_ERP_ACTION_REOPEN_UNIT:
- if (zfcp_erp_strat_change_det(&unit->status, erp_status)) {
- _zfcp_erp_unit_reopen(unit,
- ZFCP_STATUS_COMMON_ERP_FAILED,
- "ersscg3", NULL);
+ case ZFCP_ERP_ACTION_REOPEN_LUN:
+ zfcp_sdev = sdev_to_zfcp(sdev);
+ if (zfcp_erp_strat_change_det(&zfcp_sdev->status, erp_status)) {
+ _zfcp_erp_lun_reopen(sdev,
+ ZFCP_STATUS_COMMON_ERP_FAILED,
+ "ersscg3", 0);
return ZFCP_ERP_EXIT;
}
break;
@@ -1143,6 +1180,7 @@ static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret)
static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action)
{
struct zfcp_adapter *adapter = erp_action->adapter;
+ struct zfcp_scsi_dev *zfcp_sdev;
adapter->erp_total_count--;
if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) {
@@ -1151,12 +1189,13 @@ 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_UNIT:
+ case ZFCP_ERP_ACTION_REOPEN_LUN:
+ zfcp_sdev = sdev_to_zfcp(erp_action->sdev);
atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
- &erp_action->unit->status);
+ &zfcp_sdev->status);
break;
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
@@ -1176,32 +1215,30 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
{
struct zfcp_adapter *adapter = act->adapter;
struct zfcp_port *port = act->port;
- struct zfcp_unit *unit = act->unit;
+ struct scsi_device *sdev = act->sdev;
switch (act->action) {
- case ZFCP_ERP_ACTION_REOPEN_UNIT:
- if ((result == ZFCP_ERP_SUCCEEDED) && !unit->device) {
- get_device(&unit->dev);
- if (scsi_queue_work(unit->port->adapter->scsi_host,
- &unit->scsi_work) <= 0)
- put_device(&unit->dev);
- }
- put_device(&unit->dev);
+ case ZFCP_ERP_ACTION_REOPEN_LUN:
+ if (!(act->status & ZFCP_STATUS_ERP_NO_REF))
+ scsi_device_put(sdev);
break;
- case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
case ZFCP_ERP_ACTION_REOPEN_PORT:
if (result == ZFCP_ERP_SUCCEEDED)
zfcp_scsi_schedule_rport_register(port);
+ /* fall through */
+ case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
put_device(&port->dev);
break;
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;
}
@@ -1216,8 +1253,8 @@ static int zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action)
return zfcp_erp_port_forced_strategy(erp_action);
case ZFCP_ERP_ACTION_REOPEN_PORT:
return zfcp_erp_port_strategy(erp_action);
- case ZFCP_ERP_ACTION_REOPEN_UNIT:
- return zfcp_erp_unit_strategy(erp_action);
+ case ZFCP_ERP_ACTION_REOPEN_LUN:
+ return zfcp_erp_lun_strategy(erp_action);
}
return ZFCP_ERP_FAILED;
}
@@ -1239,6 +1276,11 @@ static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
goto unlock;
}
+ if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) {
+ retval = ZFCP_ERP_FAILED;
+ goto check_target;
+ }
+
zfcp_erp_action_to_running(erp_action);
/* no lock to allow for blocking operations */
@@ -1256,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;
@@ -1271,6 +1313,7 @@ static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
goto unlock;
}
+check_target:
retval = zfcp_erp_strategy_check_target(erp_action, retval);
zfcp_erp_action_dequeue(erp_action);
retval = zfcp_erp_strategy_statechange(erp_action, retval);
@@ -1299,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;
@@ -1364,42 +1405,6 @@ void zfcp_erp_thread_kill(struct zfcp_adapter *adapter)
}
/**
- * zfcp_erp_adapter_failed - Set adapter status to failed.
- * @adapter: Failed adapter.
- * @id: Event id for debug trace.
- * @ref: Reference for debug trace.
- */
-void zfcp_erp_adapter_failed(struct zfcp_adapter *adapter, char *id, void *ref)
-{
- zfcp_erp_modify_adapter_status(adapter, id, ref,
- ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET);
-}
-
-/**
- * zfcp_erp_port_failed - Set port status to failed.
- * @port: Failed port.
- * @id: Event id for debug trace.
- * @ref: Reference for debug trace.
- */
-void zfcp_erp_port_failed(struct zfcp_port *port, char *id, void *ref)
-{
- zfcp_erp_modify_port_status(port, id, ref,
- ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET);
-}
-
-/**
- * zfcp_erp_unit_failed - Set unit status to failed.
- * @unit: Failed unit.
- * @id: Event id for debug trace.
- * @ref: Reference for debug trace.
- */
-void zfcp_erp_unit_failed(struct zfcp_unit *unit, char *id, void *ref)
-{
- zfcp_erp_modify_unit_status(unit, id, ref,
- ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET);
-}
-
-/**
* zfcp_erp_wait - wait for completion of error recovery on an adapter
* @adapter: adapter for which to wait for completion of its error recovery
*/
@@ -1411,210 +1416,158 @@ void zfcp_erp_wait(struct zfcp_adapter *adapter)
}
/**
- * zfcp_erp_modify_adapter_status - change adapter status bits
+ * zfcp_erp_set_adapter_status - set adapter status bits
* @adapter: adapter to change the status
- * @id: id for the debug trace
- * @ref: reference for the debug trace
* @mask: status bits to change
- * @set_or_clear: ZFCP_SET or ZFCP_CLEAR
*
- * Changes in common status bits are propagated to attached ports and units.
+ * Changes in common status bits are propagated to attached ports and LUNs.
*/
-void zfcp_erp_modify_adapter_status(struct zfcp_adapter *adapter, char *id,
- void *ref, u32 mask, int set_or_clear)
+void zfcp_erp_set_adapter_status(struct zfcp_adapter *adapter, u32 mask)
{
struct zfcp_port *port;
+ struct scsi_device *sdev;
unsigned long flags;
u32 common_mask = mask & ZFCP_COMMON_FLAGS;
- if (set_or_clear == ZFCP_SET) {
- if (status_change_set(mask, &adapter->status))
- zfcp_dbf_rec_adapter(id, ref, adapter->dbf);
- atomic_set_mask(mask, &adapter->status);
- } else {
- if (status_change_clear(mask, &adapter->status))
- zfcp_dbf_rec_adapter(id, ref, adapter->dbf);
- atomic_clear_mask(mask, &adapter->status);
- if (mask & ZFCP_STATUS_COMMON_ERP_FAILED)
- atomic_set(&adapter->erp_counter, 0);
- }
+ atomic_set_mask(mask, &adapter->status);
- if (common_mask) {
- read_lock_irqsave(&adapter->port_list_lock, flags);
- list_for_each_entry(port, &adapter->port_list, list)
- zfcp_erp_modify_port_status(port, id, ref, common_mask,
- set_or_clear);
- read_unlock_irqrestore(&adapter->port_list_lock, flags);
- }
+ if (!common_mask)
+ return;
+
+ read_lock_irqsave(&adapter->port_list_lock, flags);
+ list_for_each_entry(port, &adapter->port_list, list)
+ atomic_set_mask(common_mask, &port->status);
+ read_unlock_irqrestore(&adapter->port_list_lock, flags);
+
+ 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);
}
/**
- * zfcp_erp_modify_port_status - change port status bits
- * @port: port to change the status bits
- * @id: id for the debug trace
- * @ref: reference for the debug trace
+ * zfcp_erp_clear_adapter_status - clear adapter status bits
+ * @adapter: adapter to change the status
* @mask: status bits to change
- * @set_or_clear: ZFCP_SET or ZFCP_CLEAR
*
- * Changes in common status bits are propagated to attached units.
+ * Changes in common status bits are propagated to attached ports and LUNs.
*/
-void zfcp_erp_modify_port_status(struct zfcp_port *port, char *id, void *ref,
- u32 mask, int set_or_clear)
+void zfcp_erp_clear_adapter_status(struct zfcp_adapter *adapter, u32 mask)
{
- struct zfcp_unit *unit;
+ struct zfcp_port *port;
+ struct scsi_device *sdev;
unsigned long flags;
u32 common_mask = mask & ZFCP_COMMON_FLAGS;
+ u32 clear_counter = mask & ZFCP_STATUS_COMMON_ERP_FAILED;
+
+ atomic_clear_mask(mask, &adapter->status);
+
+ if (!common_mask)
+ return;
- if (set_or_clear == ZFCP_SET) {
- if (status_change_set(mask, &port->status))
- zfcp_dbf_rec_port(id, ref, port);
- atomic_set_mask(mask, &port->status);
- } else {
- if (status_change_clear(mask, &port->status))
- zfcp_dbf_rec_port(id, ref, port);
- atomic_clear_mask(mask, &port->status);
- if (mask & ZFCP_STATUS_COMMON_ERP_FAILED)
+ if (clear_counter)
+ atomic_set(&adapter->erp_counter, 0);
+
+ read_lock_irqsave(&adapter->port_list_lock, flags);
+ list_for_each_entry(port, &adapter->port_list, list) {
+ atomic_clear_mask(common_mask, &port->status);
+ if (clear_counter)
atomic_set(&port->erp_counter, 0);
}
+ read_unlock_irqrestore(&adapter->port_list_lock, flags);
- if (common_mask) {
- read_lock_irqsave(&port->unit_list_lock, flags);
- list_for_each_entry(unit, &port->unit_list, list)
- zfcp_erp_modify_unit_status(unit, id, ref, common_mask,
- set_or_clear);
- read_unlock_irqrestore(&port->unit_list_lock, flags);
+ 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);
}
/**
- * zfcp_erp_modify_unit_status - change unit status bits
- * @unit: unit to change the status bits
- * @id: id for the debug trace
- * @ref: reference for the debug trace
+ * zfcp_erp_set_port_status - set port status bits
+ * @port: port to change the status
* @mask: status bits to change
- * @set_or_clear: ZFCP_SET or ZFCP_CLEAR
- */
-void zfcp_erp_modify_unit_status(struct zfcp_unit *unit, char *id, void *ref,
- u32 mask, int set_or_clear)
-{
- if (set_or_clear == ZFCP_SET) {
- if (status_change_set(mask, &unit->status))
- zfcp_dbf_rec_unit(id, ref, unit);
- atomic_set_mask(mask, &unit->status);
- } else {
- if (status_change_clear(mask, &unit->status))
- zfcp_dbf_rec_unit(id, ref, unit);
- atomic_clear_mask(mask, &unit->status);
- if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) {
- atomic_set(&unit->erp_counter, 0);
- }
- }
-}
-
-/**
- * zfcp_erp_port_boxed - Mark port as "boxed" and start ERP
- * @port: The "boxed" port.
- * @id: The debug trace id.
- * @id: Reference for the debug trace.
+ *
+ * Changes in common status bits are propagated to attached LUNs.
*/
-void zfcp_erp_port_boxed(struct zfcp_port *port, char *id, void *ref)
+void zfcp_erp_set_port_status(struct zfcp_port *port, u32 mask)
{
- zfcp_erp_modify_port_status(port, id, ref,
- ZFCP_STATUS_COMMON_ACCESS_BOXED, ZFCP_SET);
- zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref);
-}
+ struct scsi_device *sdev;
+ u32 common_mask = mask & ZFCP_COMMON_FLAGS;
+ unsigned long flags;
-/**
- * zfcp_erp_unit_boxed - Mark unit as "boxed" and start ERP
- * @port: The "boxed" unit.
- * @id: The debug trace id.
- * @id: Reference for the debug trace.
- */
-void zfcp_erp_unit_boxed(struct zfcp_unit *unit, char *id, void *ref)
-{
- zfcp_erp_modify_unit_status(unit, id, ref,
- ZFCP_STATUS_COMMON_ACCESS_BOXED, ZFCP_SET);
- zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref);
-}
+ atomic_set_mask(mask, &port->status);
-/**
- * zfcp_erp_port_access_denied - Adapter denied access to port.
- * @port: port where access has been denied
- * @id: id for debug trace
- * @ref: reference for debug trace
- *
- * Since the adapter has denied access, stop using the port and the
- * attached units.
- */
-void zfcp_erp_port_access_denied(struct zfcp_port *port, char *id, void *ref)
-{
- zfcp_erp_modify_port_status(port, id, ref,
- ZFCP_STATUS_COMMON_ERP_FAILED |
- ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET);
+ if (!common_mask)
+ return;
+
+ 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);
}
/**
- * zfcp_erp_unit_access_denied - Adapter denied access to unit.
- * @unit: unit where access has been denied
- * @id: id for debug trace
- * @ref: reference for debug trace
+ * zfcp_erp_clear_port_status - clear port status bits
+ * @port: adapter to change the status
+ * @mask: status bits to change
*
- * Since the adapter has denied access, stop using the unit.
+ * Changes in common status bits are propagated to attached LUNs.
*/
-void zfcp_erp_unit_access_denied(struct zfcp_unit *unit, char *id, void *ref)
+void zfcp_erp_clear_port_status(struct zfcp_port *port, u32 mask)
{
- zfcp_erp_modify_unit_status(unit, id, ref,
- ZFCP_STATUS_COMMON_ERP_FAILED |
- ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET);
-}
+ struct scsi_device *sdev;
+ u32 common_mask = mask & ZFCP_COMMON_FLAGS;
+ u32 clear_counter = mask & ZFCP_STATUS_COMMON_ERP_FAILED;
+ unsigned long flags;
-static void zfcp_erp_unit_access_changed(struct zfcp_unit *unit, char *id,
- void *ref)
-{
- int status = atomic_read(&unit->status);
- if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED |
- ZFCP_STATUS_COMMON_ACCESS_BOXED)))
+ atomic_clear_mask(mask, &port->status);
+
+ if (!common_mask)
return;
- zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref);
+ if (clear_counter)
+ atomic_set(&port->erp_counter, 0);
+
+ 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);
}
-static void zfcp_erp_port_access_changed(struct zfcp_port *port, char *id,
- void *ref)
+/**
+ * zfcp_erp_set_lun_status - set lun status bits
+ * @sdev: SCSI device / lun to set the status bits
+ * @mask: status bits to change
+ */
+void zfcp_erp_set_lun_status(struct scsi_device *sdev, u32 mask)
{
- struct zfcp_unit *unit;
- unsigned long flags;
- int status = atomic_read(&port->status);
-
- if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED |
- ZFCP_STATUS_COMMON_ACCESS_BOXED))) {
- read_lock_irqsave(&port->unit_list_lock, flags);
- list_for_each_entry(unit, &port->unit_list, list)
- zfcp_erp_unit_access_changed(unit, id, ref);
- read_unlock_irqrestore(&port->unit_list_lock, flags);
- return;
- }
+ struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
- zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref);
+ atomic_set_mask(mask, &zfcp_sdev->status);
}
/**
- * zfcp_erp_adapter_access_changed - Process change in adapter ACT
- * @adapter: Adapter where the Access Control Table (ACT) changed
- * @id: Id for debug trace
- * @ref: Reference for debug trace
+ * zfcp_erp_clear_lun_status - clear lun status bits
+ * @sdev: SCSi device / lun to clear the status bits
+ * @mask: status bits to change
*/
-void zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter, char *id,
- void *ref)
+void zfcp_erp_clear_lun_status(struct scsi_device *sdev, u32 mask)
{
- unsigned long flags;
- struct zfcp_port *port;
+ struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
- if (adapter->connection_features & FSF_FEATURE_NPIV_MODE)
- return;
+ atomic_clear_mask(mask, &zfcp_sdev->status);
- read_lock_irqsave(&adapter->port_list_lock, flags);
- list_for_each_entry(port, &adapter->port_list, list)
- zfcp_erp_port_access_changed(port, id, ref);
- read_unlock_irqrestore(&adapter->port_list_lock, flags);
+ if (mask & ZFCP_STATUS_COMMON_ERP_FAILED)
+ atomic_set(&zfcp_sdev->erp_counter, 0);
}
+
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
index 48a8f93b72f..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
@@ -15,87 +15,63 @@
#include "zfcp_fc.h"
/* zfcp_aux.c */
-extern struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *, u64);
extern struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *, u64);
extern struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *);
extern struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *, u64, u32,
u32);
-extern struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *, u64);
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;
-
/* 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_unit(char *, void *, struct zfcp_unit *);
-extern void zfcp_dbf_rec_trigger(char *, void *, u8, u8, void *,
- struct zfcp_adapter *, struct zfcp_port *,
- struct zfcp_unit *);
-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_modify_adapter_status(struct zfcp_adapter *, char *,
- void *, u32, int);
-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_failed(struct zfcp_adapter *, char *, void *);
-extern void zfcp_erp_modify_port_status(struct zfcp_port *, char *, void *, u32,
- int);
-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 void zfcp_erp_port_failed(struct zfcp_port *, char *, void *);
-extern void zfcp_erp_modify_unit_status(struct zfcp_unit *, char *, void *, u32,
- int);
-extern void zfcp_erp_unit_reopen(struct zfcp_unit *, int, char *, void *);
-extern void zfcp_erp_unit_shutdown(struct zfcp_unit *, int, char *, void *);
-extern void zfcp_erp_unit_failed(struct zfcp_unit *, char *, void *);
+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 *);
+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 *);
+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 *);
+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 *);
extern void zfcp_erp_wait(struct zfcp_adapter *);
extern void zfcp_erp_notify(struct zfcp_erp_action *, unsigned long);
-extern void zfcp_erp_port_boxed(struct zfcp_port *, char *, void *);
-extern void zfcp_erp_unit_boxed(struct zfcp_unit *, char *, void *);
-extern void zfcp_erp_port_access_denied(struct zfcp_port *, char *, void *);
-extern void zfcp_erp_unit_access_denied(struct zfcp_unit *, char *, void *);
-extern void zfcp_erp_adapter_access_changed(struct zfcp_adapter *, char *,
- void *);
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 *);
extern void zfcp_fc_scan_ports(struct work_struct *);
extern void zfcp_fc_incoming_els(struct zfcp_fsf_req *);
extern void zfcp_fc_port_did_lookup(struct work_struct *);
@@ -108,23 +84,25 @@ 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 *);
extern int zfcp_fsf_close_port(struct zfcp_erp_action *);
extern int zfcp_fsf_close_physical_port(struct zfcp_erp_action *);
-extern int zfcp_fsf_open_unit(struct zfcp_erp_action *);
-extern int zfcp_fsf_close_unit(struct zfcp_erp_action *);
+extern int zfcp_fsf_open_lun(struct zfcp_erp_action *);
+extern int zfcp_fsf_close_lun(struct zfcp_erp_action *);
extern int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *);
extern int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *,
struct fsf_qtcb_bottom_config *);
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);
@@ -132,12 +110,10 @@ extern int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *, struct zfcp_fsf_ct_els *,
mempool_t *, unsigned int);
extern int zfcp_fsf_send_els(struct zfcp_adapter *, u32,
struct zfcp_fsf_ct_els *, unsigned int);
-extern int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *,
- struct scsi_cmnd *);
+extern int zfcp_fsf_fcp_cmnd(struct scsi_cmnd *);
extern void zfcp_fsf_req_free(struct zfcp_fsf_req *);
-extern struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *, u8);
-extern struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long,
- struct zfcp_unit *);
+extern struct zfcp_fsf_req *zfcp_fsf_fcp_task_mgmt(struct scsi_cmnd *, u8);
+extern struct zfcp_fsf_req *zfcp_fsf_abort_fcp_cmnd(struct scsi_cmnd *);
extern void zfcp_fsf_reqid_check(struct zfcp_qdio *, int);
/* zfcp_qdio.c */
@@ -146,26 +122,38 @@ extern void zfcp_qdio_destroy(struct zfcp_qdio *);
extern int zfcp_qdio_sbal_get(struct zfcp_qdio *);
extern int zfcp_qdio_send(struct zfcp_qdio *, struct zfcp_qdio_req *);
extern int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *, struct zfcp_qdio_req *,
- struct scatterlist *, int);
+ struct scatterlist *);
extern int zfcp_qdio_open(struct zfcp_qdio *);
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 *);
extern void zfcp_scsi_schedule_rport_block(struct zfcp_port *);
extern void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *);
-extern void zfcp_scsi_scan(struct work_struct *);
+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[];
+/* zfcp_unit.c */
+extern int zfcp_unit_add(struct zfcp_port *, u64);
+extern int zfcp_unit_remove(struct zfcp_port *, u64);
+extern struct zfcp_unit *zfcp_unit_find(struct zfcp_port *, u64);
+extern struct scsi_device *zfcp_unit_sdev(struct zfcp_unit *unit);
+extern void zfcp_unit_scsi_scan(struct zfcp_unit *);
+extern void zfcp_unit_queue_scsi_scan(struct zfcp_port *);
+extern unsigned int zfcp_unit_sdev_status(struct zfcp_unit *);
+
#endif /* ZFCP_EXT_H */
diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c
index 6f8ab43a485..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,79 @@ 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
+ */
+void zfcp_fc_post_event(struct work_struct *work)
+{
+ struct zfcp_fc_event *event = NULL, *tmp = NULL;
+ LIST_HEAD(tmp_lh);
+ struct zfcp_fc_events *events = container_of(work,
+ struct zfcp_fc_events, work);
+ struct zfcp_adapter *adapter = container_of(events, struct zfcp_adapter,
+ events);
+
+ spin_lock_bh(&events->list_lock);
+ list_splice_init(&events->list, &tmp_lh);
+ spin_unlock_bh(&events->list_lock);
+
+ list_for_each_entry_safe(event, tmp, &tmp_lh, list) {
+ fc_host_post_event(adapter->scsi_host, fc_get_event_number(),
+ event->code, event->data);
+ list_del(&event->list);
+ kfree(event);
+ }
+
+}
+
+/**
+ * zfcp_fc_enqueue_event - safely enqueue FC HBA API event from irq context
+ * @adapter: The adapter where to enqueue the event
+ * @event_code: The event code (as defined in fc_host_event_code in
+ * scsi_transport_fc.h)
+ * @event_data: The event data (e.g. n_port page in case of els)
+ */
+void zfcp_fc_enqueue_event(struct zfcp_adapter *adapter,
+ enum fc_host_event_code event_code, u32 event_data)
+{
+ struct zfcp_fc_event *event;
+
+ event = kmalloc(sizeof(struct zfcp_fc_event), GFP_ATOMIC);
+ if (!event)
+ return;
+
+ event->code = event_code;
+ event->data = event_data;
+
+ spin_lock(&adapter->events.list_lock);
+ list_add_tail(&event->list, &adapter->events.list);
+ spin_unlock(&adapter->events.list_lock);
+
+ queue_work(adapter->work_queue, &adapter->events.work);
+}
+
static int zfcp_fc_wka_port_get(struct zfcp_fc_wka_port *wka_port)
{
if (mutex_lock_interruptible(&wka_port->mutex))
@@ -122,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);
}
@@ -148,8 +224,10 @@ static void zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req)
afmt = page->rscn_page_flags & ELS_RSCN_ADDR_FMT_MASK;
_zfcp_fc_incoming_rscn(fsf_req, zfcp_fc_rscn_range_mask[afmt],
page);
+ 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)
@@ -161,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);
@@ -197,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)
@@ -206,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)
@@ -231,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;
}
@@ -306,16 +382,16 @@ 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;
}
if (!port->d_id) {
- zfcp_erp_port_failed(port, "fcgpn_2", NULL);
+ zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_ERP_FAILED);
goto out;
}
- zfcp_erp_port_reopen(port, 0, "fcgpn_3", NULL);
+ zfcp_erp_port_reopen(port, 0, "fcgpn_3");
out:
put_device(&port->dev);
}
@@ -365,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;
}
@@ -382,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;
}
@@ -391,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;
}
@@ -453,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);
@@ -474,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;
-
- kmem_cache_free(zfcp_data.gpn_ft_cache, sg_virt(sg));
- zfcp_sg_free_table(gpn_ft->sg_resp, buf_num);
+ struct zfcp_fc_req *fc_req;
- 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);
@@ -556,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;
@@ -569,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) {
@@ -605,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);
}
@@ -617,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;
@@ -633,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;
@@ -648,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 0747b087390..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
@@ -30,6 +30,30 @@
#define ZFCP_FC_CTELS_TMO (2 * FC_DEF_R_A_TOV / 1000)
/**
+ * struct zfcp_fc_event - FC HBAAPI event for internal queueing from irq context
+ * @code: Event code
+ * @data: Event data
+ * @list: list_head for zfcp_fc_events list
+ */
+struct zfcp_fc_event {
+ enum fc_host_event_code code;
+ u32 data;
+ struct list_head list;
+};
+
+/**
+ * struct zfcp_fc_events - Infrastructure for posting FC events from irq context
+ * @list: List for queueing of events from irq context to workqueue
+ * @list_lock: Lock for event list
+ * @work: work_struct for forwarding events in workqueue
+*/
+struct zfcp_fc_events {
+ struct list_head list;
+ spinlock_t list_lock;
+ struct work_struct work;
+};
+
+/**
* struct zfcp_fc_gid_pn_req - container for ct header plus gid_pn request
* @ct_hdr: FC GS common transport header
* @gid_pn: GID_PN request
@@ -40,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
@@ -77,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_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_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_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;
};
/**
@@ -168,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:
@@ -196,19 +241,9 @@ void zfcp_fc_scsi_to_fcp(struct fcp_cmnd *fcp, struct scsi_cmnd *scsi)
memcpy(fcp->fc_cdb, scsi->cmnd, scsi->cmd_len);
fcp->fc_dl = scsi_bufflen(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;
+ if (scsi_get_prot_type(scsi) == SCSI_PROT_DIF_TYPE1)
+ fcp->fc_dl += fcp->fc_dl / scsi->device->sector_size * 8;
}
/**
@@ -243,7 +278,7 @@ void zfcp_fc_eval_fcp_rsp(struct fcp_resp_with_ext *fcp_rsp,
if (unlikely(rsp_flags & FCP_SNS_LEN_VAL)) {
sense = (char *) &fcp_rsp[1];
if (rsp_flags & FCP_RSP_LEN_VAL)
- sense += fcp_rsp->ext.fr_sns_len;
+ sense += fcp_rsp->ext.fr_rsp_len;
sense_len = min(fcp_rsp->ext.fr_sns_len,
(u32) SCSI_SENSE_BUFFERSIZE);
memcpy(scsi->sense_buffer, sense, sense_len);
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 9ac6a6e4a60..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,11 +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,
@@ -60,50 +63,11 @@ static u32 fsf_qtcb_type[] = {
[FSF_QTCB_UPLOAD_CONTROL_FILE] = FSF_SUPPORT_COMMAND
};
-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);
-}
-
-static void zfcp_fsf_access_denied_port(struct zfcp_fsf_req *req,
- struct zfcp_port *port)
-{
- struct fsf_qtcb_header *header = &req->qtcb->header;
- dev_warn(&req->adapter->ccw_device->dev,
- "Access denied to port 0x%016Lx\n",
- (unsigned long long)port->wwpn);
- zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[0]);
- zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[1]);
- zfcp_erp_port_access_denied(port, "fspad_1", req);
- req->status |= ZFCP_STATUS_FSFREQ_ERROR;
-}
-
-static void zfcp_fsf_access_denied_unit(struct zfcp_fsf_req *req,
- struct zfcp_unit *unit)
-{
- struct fsf_qtcb_header *header = &req->qtcb->header;
- dev_warn(&req->adapter->ccw_device->dev,
- "Access denied to unit 0x%016Lx on port 0x%016Lx\n",
- (unsigned long long)unit->fcp_lun,
- (unsigned long long)unit->port->wwpn);
- zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[0]);
- zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[1]);
- zfcp_erp_unit_access_denied(unit, "fsuad_1", req);
- req->status |= ZFCP_STATUS_FSFREQ_ERROR;
-}
-
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;
}
@@ -121,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);
}
@@ -136,13 +100,13 @@ 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);
}
-static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req, char *id,
+static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req,
struct fsf_link_down_info *link_down)
{
struct zfcp_adapter *adapter = req->adapter;
@@ -222,7 +186,7 @@ static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req, char *id,
"the FC fabric is down\n");
}
out:
- zfcp_erp_adapter_failed(adapter, id, req);
+ zfcp_erp_set_adapter_status(adapter, ZFCP_STATUS_COMMON_ERP_FAILED);
}
static void zfcp_fsf_status_read_link_down(struct zfcp_fsf_req *req)
@@ -233,13 +197,13 @@ static void zfcp_fsf_status_read_link_down(struct zfcp_fsf_req *req)
switch (sr_buf->status_subtype) {
case FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK:
- zfcp_fsf_link_down_info_eval(req, "fssrld1", ldi);
+ zfcp_fsf_link_down_info_eval(req, ldi);
break;
case FSF_STATUS_READ_SUB_FDISC_FAILED:
- zfcp_fsf_link_down_info_eval(req, "fssrld2", ldi);
+ zfcp_fsf_link_down_info_eval(req, ldi);
break;
case FSF_STATUS_READ_SUB_FIRMWARE_UPDATE:
- zfcp_fsf_link_down_info_eval(req, "fssrld3", NULL);
+ zfcp_fsf_link_down_info_eval(req, NULL);
};
}
@@ -249,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:
@@ -270,39 +234,35 @@ 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);
+ zfcp_fc_enqueue_event(adapter, FCH_EVT_LINKDOWN, 0);
break;
case FSF_STATUS_READ_LINK_UP:
dev_info(&adapter->ccw_device->dev,
"The local link has been restored\n");
/* All ports should be marked as ready to run again */
- zfcp_erp_modify_adapter_status(adapter, "fssrh_1", NULL,
- ZFCP_STATUS_COMMON_RUNNING,
- ZFCP_SET);
+ zfcp_erp_set_adapter_status(adapter,
+ ZFCP_STATUS_COMMON_RUNNING);
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_erp_adapter_access_changed(adapter, "fssrh_3",
- req);
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_erp_adapter_access_changed(adapter, "fssrh_4", req);
+ 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);
@@ -323,7 +283,8 @@ static void zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *req)
dev_err(&req->adapter->ccw_device->dev,
"The FCP adapter reported a problem "
"that cannot be recovered\n");
- zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfsqe1", req);
+ zfcp_qdio_siosl(req->adapter);
+ zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfsqe1");
break;
}
/* all non-return stats set FSFREQ_ERROR*/
@@ -340,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:
@@ -371,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,
@@ -391,29 +352,28 @@ 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, "fspse_5",
- &psq->link_down_info);
+ 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 */
- zfcp_erp_modify_adapter_status(adapter, "fspse_7", NULL,
- ZFCP_STATUS_COMMON_RUNNING,
- ZFCP_SET);
+ zfcp_erp_set_adapter_status(adapter,
+ ZFCP_STATUS_COMMON_RUNNING);
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_erp_adapter_shutdown(adapter, 0, "fspse_9", req);
+ zfcp_qdio_siosl(adapter);
+ zfcp_erp_adapter_shutdown(adapter, 0, "fspse_9");
}
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
}
@@ -472,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;
@@ -490,17 +478,28 @@ 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;
- adapter->stat_read_buf_num = max(bottom->status_read_buf_num, (u16)16);
+ 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);
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);
@@ -518,7 +517,7 @@ 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;
}
@@ -552,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,
@@ -566,14 +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, "fsecdh2",
+ 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;
}
@@ -589,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");
}
}
@@ -615,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,
@@ -635,7 +638,7 @@ static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *req)
break;
case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE:
zfcp_fsf_exchange_port_evaluate(req);
- zfcp_fsf_link_down_info_eval(req, "fsepdh1",
+ zfcp_fsf_link_down_info_eval(req,
&qtcb->header.fsf_status_qual.link_down_info);
break;
}
@@ -665,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;
@@ -675,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;
@@ -719,11 +722,6 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_qdio *qdio,
zfcp_qdio_req_init(adapter->qdio, &req->qdio_req, req->req_id, sbtype,
req->qtcb, sizeof(struct fsf_qtcb));
- if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)) {
- zfcp_fsf_req_free(req);
- return ERR_PTR(-EIO);
- }
-
return req;
}
@@ -736,13 +734,13 @@ 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.count);
- req->issued = get_clock();
+ req->qdio_req.qdio_outb_usage = atomic_read(&qdio->req_q_free);
+ 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;
}
@@ -765,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_bh(&qdio->req_q_lock);
+ 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;
@@ -796,34 +797,38 @@ 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_bh(&qdio->req_q_lock);
+ spin_unlock_irq(&qdio->req_q_lock);
return retval;
}
static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req)
{
- struct zfcp_unit *unit = req->data;
+ struct scsi_device *sdev = req->data;
+ 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(unit->port->adapter, 0,
- "fsafch1", req);
+ zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0,
+ "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(unit->port, 0, "fsafch2", req);
+ zfcp_erp_port_reopen(zfcp_sdev->port, 0, "fsafch2");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
}
break;
@@ -831,17 +836,22 @@ static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req)
req->status |= ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED;
break;
case FSF_PORT_BOXED:
- zfcp_erp_port_boxed(unit->port, "fsafch3", 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->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_LUN_BOXED:
- zfcp_erp_unit_boxed(unit, "fsafch4", req);
+ zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ACCESS_BOXED);
+ zfcp_erp_lun_reopen(sdev, ZFCP_STATUS_COMMON_ERP_FAILED,
+ "fsafch4");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_ADAPTER_STATUS_AVAILABLE:
switch (fsq->word[0]) {
case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
- zfcp_fc_test_link(unit->port);
+ zfcp_fc_test_link(zfcp_sdev->port);
/* fall through */
case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
@@ -855,39 +865,40 @@ static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req)
}
/**
- * zfcp_fsf_abort_fcp_command - abort running SCSI command
- * @old_req_id: unsigned long
- * @unit: pointer to struct zfcp_unit
+ * zfcp_fsf_abort_fcp_cmnd - abort running SCSI command
+ * @scmnd: The SCSI command to abort
* Returns: pointer to struct zfcp_fsf_req
*/
-struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long old_req_id,
- struct zfcp_unit *unit)
+struct zfcp_fsf_req *zfcp_fsf_abort_fcp_cmnd(struct scsi_cmnd *scmnd)
{
struct zfcp_fsf_req *req = NULL;
- struct zfcp_qdio *qdio = unit->port->adapter->qdio;
+ struct scsi_device *sdev = scmnd->device;
+ struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
+ struct zfcp_qdio *qdio = zfcp_sdev->port->adapter->qdio;
+ unsigned long old_req_id = (unsigned long) scmnd->host_scribble;
- spin_lock_bh(&qdio->req_q_lock);
+ spin_lock_irq(&qdio->req_q_lock);
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;
goto out;
}
- if (unlikely(!(atomic_read(&unit->status) &
+ if (unlikely(!(atomic_read(&zfcp_sdev->status) &
ZFCP_STATUS_COMMON_UNBLOCKED)))
goto out_error_free;
zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
- req->data = unit;
+ req->data = sdev;
req->handler = zfcp_fsf_abort_fcp_command_handler;
- req->qtcb->header.lun_handle = unit->handle;
- req->qtcb->header.port_handle = unit->port->handle;
+ req->qtcb->header.lun_handle = zfcp_sdev->lun_handle;
+ req->qtcb->header.port_handle = zfcp_sdev->port->handle;
req->qtcb->bottom.support.req_handle = (u64) old_req_id;
zfcp_fsf_start_timer(req, ZFCP_SCSI_ER_TIMEOUT);
@@ -898,7 +909,7 @@ out_error_free:
zfcp_fsf_req_free(req);
req = NULL;
out:
- spin_unlock_bh(&qdio->req_q_lock);
+ spin_unlock_irq(&qdio->req_q_lock);
return req;
}
@@ -915,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:
@@ -929,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:
@@ -963,54 +972,62 @@ static void zfcp_fsf_setup_ct_els_unchained(struct zfcp_qdio *qdio,
static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
struct scatterlist *sg_req,
- struct scatterlist *sg_resp,
- int max_sbals)
+ 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,
+ if (zfcp_qdio_sg_one_sbale(sg_req) && zfcp_qdio_sg_one_sbale(sg_resp)) {
+ 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, max_sbals);
- 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;
- 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, max_sbals);
- 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;
+ qtcb->bottom.support.resp_buf_length = zfcp_qdio_real_bytes(sg_resp);
+
+ zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
+
return 0;
}
static int zfcp_fsf_setup_ct_els(struct zfcp_fsf_req *req,
struct scatterlist *sg_req,
struct scatterlist *sg_resp,
- int max_sbals, unsigned int timeout)
+ unsigned int timeout)
{
int ret;
- ret = zfcp_fsf_setup_ct_els_sbals(req, sg_req, sg_resp, max_sbals);
+ ret = zfcp_fsf_setup_ct_els_sbals(req, sg_req, sg_resp);
if (ret)
return ret;
@@ -1037,12 +1054,12 @@ int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *wka_port,
struct zfcp_fsf_req *req;
int ret = -EIO;
- spin_lock_bh(&qdio->req_q_lock);
+ spin_lock_irq(&qdio->req_q_lock);
if (zfcp_qdio_sbal_get(qdio))
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);
@@ -1050,8 +1067,7 @@ int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *wka_port,
}
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
- ret = zfcp_fsf_setup_ct_els(req, ct->req, ct->resp,
- ZFCP_FSF_MAX_SBALS_PER_REQ, timeout);
+ ret = zfcp_fsf_setup_ct_els(req, ct->req, ct->resp, timeout);
if (ret)
goto failed_send;
@@ -1059,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)
@@ -1070,14 +1086,13 @@ int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *wka_port,
failed_send:
zfcp_fsf_req_free(req);
out:
- spin_unlock_bh(&qdio->req_q_lock);
+ spin_unlock_irq(&qdio->req_q_lock);
return ret;
}
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;
@@ -1087,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:
@@ -1107,12 +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_fsf_access_denied_port(req, port);
- 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;
@@ -1134,12 +1145,12 @@ int zfcp_fsf_send_els(struct zfcp_adapter *adapter, u32 d_id,
struct zfcp_qdio *qdio = adapter->qdio;
int ret = -EIO;
- spin_lock_bh(&qdio->req_q_lock);
+ spin_lock_irq(&qdio->req_q_lock);
if (zfcp_qdio_sbal_get(qdio))
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);
@@ -1147,7 +1158,11 @@ int zfcp_fsf_send_els(struct zfcp_adapter *adapter, u32 d_id,
}
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
- ret = zfcp_fsf_setup_ct_els(req, els->req, els->resp, 2, timeout);
+
+ 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);
if (ret)
goto failed_send;
@@ -1156,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)
@@ -1167,7 +1182,7 @@ int zfcp_fsf_send_els(struct zfcp_adapter *adapter, u32 d_id,
failed_send:
zfcp_fsf_req_free(req);
out:
- spin_unlock_bh(&qdio->req_q_lock);
+ spin_unlock_irq(&qdio->req_q_lock);
return ret;
}
@@ -1177,12 +1192,12 @@ int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
struct zfcp_qdio *qdio = erp_action->adapter->qdio;
int retval = -EIO;
- spin_lock_bh(&qdio->req_q_lock);
+ spin_lock_irq(&qdio->req_q_lock);
if (zfcp_qdio_sbal_get(qdio))
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)) {
@@ -1194,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;
@@ -1209,7 +1222,7 @@ int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
erp_action->fsf_req_id = 0;
}
out:
- spin_unlock_bh(&qdio->req_q_lock);
+ spin_unlock_irq(&qdio->req_q_lock);
return retval;
}
@@ -1219,12 +1232,12 @@ int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *qdio,
struct zfcp_fsf_req *req = NULL;
int retval = -EIO;
- spin_lock_bh(&qdio->req_q_lock);
+ spin_lock_irq(&qdio->req_q_lock);
if (zfcp_qdio_sbal_get(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);
@@ -1235,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;
@@ -1245,7 +1256,7 @@ int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *qdio,
zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
retval = zfcp_fsf_req_send(req);
- spin_unlock_bh(&qdio->req_q_lock);
+ spin_unlock_irq(&qdio->req_q_lock);
if (!retval)
wait_for_completion(&req->completion);
@@ -1253,7 +1264,7 @@ int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *qdio,
return retval;
out_unlock:
- spin_unlock_bh(&qdio->req_q_lock);
+ spin_unlock_irq(&qdio->req_q_lock);
return retval;
}
@@ -1271,12 +1282,12 @@ int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action)
if (!(qdio->adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT))
return -EOPNOTSUPP;
- spin_lock_bh(&qdio->req_q_lock);
+ spin_lock_irq(&qdio->req_q_lock);
if (zfcp_qdio_sbal_get(qdio))
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)) {
@@ -1298,7 +1309,7 @@ int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action)
erp_action->fsf_req_id = 0;
}
out:
- spin_unlock_bh(&qdio->req_q_lock);
+ spin_unlock_irq(&qdio->req_q_lock);
return retval;
}
@@ -1317,12 +1328,12 @@ int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *qdio,
if (!(qdio->adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT))
return -EOPNOTSUPP;
- spin_lock_bh(&qdio->req_q_lock);
+ spin_lock_irq(&qdio->req_q_lock);
if (zfcp_qdio_sbal_get(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);
@@ -1337,7 +1348,7 @@ int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *qdio,
req->handler = zfcp_fsf_exchange_port_data_handler;
zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
retval = zfcp_fsf_req_send(req);
- spin_unlock_bh(&qdio->req_q_lock);
+ spin_unlock_irq(&qdio->req_q_lock);
if (!retval)
wait_for_completion(&req->completion);
@@ -1347,7 +1358,7 @@ int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *qdio,
return retval;
out_unlock:
- spin_unlock_bh(&qdio->req_q_lock);
+ spin_unlock_irq(&qdio->req_q_lock);
return retval;
}
@@ -1363,15 +1374,13 @@ 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_fsf_access_denied_port(req, port);
- break;
case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED:
dev_warn(&req->adapter->ccw_device->dev,
"Not enough FCP adapter resources to open "
"remote port 0x%016Lx\n",
(unsigned long long)port->wwpn);
- zfcp_erp_port_failed(port, "fsoph_1", req);
+ zfcp_erp_set_port_status(port,
+ ZFCP_STATUS_COMMON_ERP_FAILED);
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_ADAPTER_STATUS_AVAILABLE:
@@ -1431,12 +1440,12 @@ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
struct zfcp_fsf_req *req;
int retval = -EIO;
- spin_lock_bh(&qdio->req_q_lock);
+ spin_lock_irq(&qdio->req_q_lock);
if (zfcp_qdio_sbal_get(qdio))
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)) {
@@ -1462,7 +1471,7 @@ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
put_device(&port->dev);
}
out:
- spin_unlock_bh(&qdio->req_q_lock);
+ spin_unlock_irq(&qdio->req_q_lock);
return retval;
}
@@ -1475,15 +1484,13 @@ 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:
break;
case FSF_GOOD:
- zfcp_erp_modify_port_status(port, "fscph_2", req,
- ZFCP_STATUS_COMMON_OPEN,
- ZFCP_CLEAR);
+ zfcp_erp_clear_port_status(port, ZFCP_STATUS_COMMON_OPEN);
break;
}
}
@@ -1499,12 +1506,12 @@ int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action)
struct zfcp_fsf_req *req;
int retval = -EIO;
- spin_lock_bh(&qdio->req_q_lock);
+ spin_lock_irq(&qdio->req_q_lock);
if (zfcp_qdio_sbal_get(qdio))
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)) {
@@ -1528,7 +1535,7 @@ int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action)
erp_action->fsf_req_id = 0;
}
out:
- spin_unlock_bh(&qdio->req_q_lock);
+ spin_unlock_irq(&qdio->req_q_lock);
return retval;
}
@@ -1549,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:
@@ -1574,15 +1579,15 @@ int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *wka_port)
struct zfcp_fsf_req *req;
int retval = -EIO;
- spin_lock_bh(&qdio->req_q_lock);
+ spin_lock_irq(&qdio->req_q_lock);
if (zfcp_qdio_sbal_get(qdio))
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;
}
@@ -1599,7 +1604,7 @@ int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *wka_port)
if (retval)
zfcp_fsf_req_free(req);
out:
- spin_unlock_bh(&qdio->req_q_lock);
+ spin_unlock_irq(&qdio->req_q_lock);
return retval;
}
@@ -1609,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;
@@ -1627,15 +1632,15 @@ int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *wka_port)
struct zfcp_fsf_req *req;
int retval = -EIO;
- spin_lock_bh(&qdio->req_q_lock);
+ spin_lock_irq(&qdio->req_q_lock);
if (zfcp_qdio_sbal_get(qdio))
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;
}
@@ -1652,7 +1657,7 @@ int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *wka_port)
if (retval)
zfcp_fsf_req_free(req);
out:
- spin_unlock_bh(&qdio->req_q_lock);
+ spin_unlock_irq(&qdio->req_q_lock);
return retval;
}
@@ -1660,29 +1665,27 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req)
{
struct zfcp_port *port = req->data;
struct fsf_qtcb_header *header = &req->qtcb->header;
- struct zfcp_unit *unit;
+ struct scsi_device *sdev;
if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
return;
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_fsf_access_denied_port(req, port);
- 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 */
atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
- read_lock(&port->unit_list_lock);
- list_for_each_entry(unit, &port->unit_list, list)
- atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN,
- &unit->status);
- read_unlock(&port->unit_list_lock);
- zfcp_erp_port_boxed(port, "fscpph2", req);
+ shost_for_each_device(sdev, port->adapter->scsi_host)
+ if (sdev_to_zfcp(sdev)->port == port)
+ atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN,
+ &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->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_ADAPTER_STATUS_AVAILABLE:
@@ -1699,11 +1702,10 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req)
* ZFCP_STATUS_COMMON_OPEN must not be reset for the port
*/
atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
- read_lock(&port->unit_list_lock);
- list_for_each_entry(unit, &port->unit_list, list)
- atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN,
- &unit->status);
- read_unlock(&port->unit_list_lock);
+ shost_for_each_device(sdev, port->adapter->scsi_host)
+ if (sdev_to_zfcp(sdev)->port == port)
+ atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN,
+ &sdev_to_zfcp(sdev)->status);
break;
}
}
@@ -1719,12 +1721,12 @@ int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action)
struct zfcp_fsf_req *req;
int retval = -EIO;
- spin_lock_bh(&qdio->req_q_lock);
+ spin_lock_irq(&qdio->req_q_lock);
if (zfcp_qdio_sbal_get(qdio))
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)) {
@@ -1748,69 +1750,62 @@ int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action)
erp_action->fsf_req_id = 0;
}
out:
- spin_unlock_bh(&qdio->req_q_lock);
+ spin_unlock_irq(&qdio->req_q_lock);
return retval;
}
-static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req)
+static void zfcp_fsf_open_lun_handler(struct zfcp_fsf_req *req)
{
struct zfcp_adapter *adapter = req->adapter;
- struct zfcp_unit *unit = req->data;
+ struct scsi_device *sdev = req->data;
+ struct zfcp_scsi_dev *zfcp_sdev;
struct fsf_qtcb_header *header = &req->qtcb->header;
- struct fsf_qtcb_bottom_support *bottom = &req->qtcb->bottom.support;
- struct fsf_queue_designator *queue_designator =
- &header->fsf_status_qual.fsf_queue_designator;
- int exclusive, readwrite;
+ 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_UNIT_SHARED |
- ZFCP_STATUS_UNIT_READONLY,
- &unit->status);
+ ZFCP_STATUS_COMMON_ACCESS_BOXED,
+ &zfcp_sdev->status);
switch (header->fsf_status) {
case FSF_PORT_HANDLE_NOT_VALID:
- zfcp_erp_adapter_reopen(unit->port->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_fsf_access_denied_unit(req, unit);
- atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status);
- atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status);
- break;
case FSF_PORT_BOXED:
- zfcp_erp_port_boxed(unit->port, "fsouh_2", 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, "fsouh_2");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_LUN_SHARING_VIOLATION:
- if (header->fsf_status_qual.word[0])
- dev_warn(&adapter->ccw_device->dev,
+ 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",
- (unsigned long long)unit->fcp_lun,
- (unsigned long long)unit->port->wwpn,
- queue_designator->cssid,
- queue_designator->hla);
- else
- zfcp_act_eval_err(adapter,
- header->fsf_status_qual.word[2]);
- zfcp_erp_unit_access_denied(unit, "fsouh_3", req);
- atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status);
- atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status);
+ 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:
dev_warn(&adapter->ccw_device->dev,
"No handle is available for LUN "
"0x%016Lx on port 0x%016Lx\n",
- (unsigned long long)unit->fcp_lun,
- (unsigned long long)unit->port->wwpn);
- zfcp_erp_unit_failed(unit, "fsouh_4", req);
+ (unsigned long long)zfcp_scsi_dev_lun(sdev),
+ (unsigned long long)zfcp_sdev->port->wwpn);
+ zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ERP_FAILED);
/* fall through */
case FSF_INVALID_COMMAND_OPTION:
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
@@ -1818,7 +1813,7 @@ static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req)
case FSF_ADAPTER_STATUS_AVAILABLE:
switch (header->fsf_status_qual.word[0]) {
case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
- zfcp_fc_test_link(unit->port);
+ zfcp_fc_test_link(zfcp_sdev->port);
/* fall through */
case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
@@ -1827,75 +1822,30 @@ static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req)
break;
case FSF_GOOD:
- unit->handle = header->lun_handle;
- atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status);
-
- if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE) &&
- (adapter->adapter_features & FSF_FEATURE_LUN_SHARING) &&
- !zfcp_ccw_priv_sch(adapter)) {
- exclusive = (bottom->lun_access_info &
- FSF_UNIT_ACCESS_EXCLUSIVE);
- readwrite = (bottom->lun_access_info &
- FSF_UNIT_ACCESS_OUTBOUND_TRANSFER);
-
- if (!exclusive)
- atomic_set_mask(ZFCP_STATUS_UNIT_SHARED,
- &unit->status);
-
- if (!readwrite) {
- atomic_set_mask(ZFCP_STATUS_UNIT_READONLY,
- &unit->status);
- dev_info(&adapter->ccw_device->dev,
- "SCSI device at LUN 0x%016Lx on port "
- "0x%016Lx opened read-only\n",
- (unsigned long long)unit->fcp_lun,
- (unsigned long long)unit->port->wwpn);
- }
-
- if (exclusive && !readwrite) {
- dev_err(&adapter->ccw_device->dev,
- "Exclusive read-only access not "
- "supported (unit 0x%016Lx, "
- "port 0x%016Lx)\n",
- (unsigned long long)unit->fcp_lun,
- (unsigned long long)unit->port->wwpn);
- zfcp_erp_unit_failed(unit, "fsouh_5", req);
- req->status |= ZFCP_STATUS_FSFREQ_ERROR;
- zfcp_erp_unit_shutdown(unit, 0, "fsouh_6", req);
- } else if (!exclusive && readwrite) {
- dev_err(&adapter->ccw_device->dev,
- "Shared read-write access not "
- "supported (unit 0x%016Lx, port "
- "0x%016Lx)\n",
- (unsigned long long)unit->fcp_lun,
- (unsigned long long)unit->port->wwpn);
- zfcp_erp_unit_failed(unit, "fsouh_7", req);
- req->status |= ZFCP_STATUS_FSFREQ_ERROR;
- zfcp_erp_unit_shutdown(unit, 0, "fsouh_8", req);
- }
- }
+ zfcp_sdev->lun_handle = header->lun_handle;
+ atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &zfcp_sdev->status);
break;
}
}
/**
- * zfcp_fsf_open_unit - open unit
+ * zfcp_fsf_open_lun - open LUN
* @erp_action: pointer to struct zfcp_erp_action
* Returns: 0 on success, error otherwise
*/
-int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
+int zfcp_fsf_open_lun(struct zfcp_erp_action *erp_action)
{
struct zfcp_adapter *adapter = erp_action->adapter;
struct zfcp_qdio *qdio = adapter->qdio;
struct zfcp_fsf_req *req;
int retval = -EIO;
- spin_lock_bh(&qdio->req_q_lock);
+ spin_lock_irq(&qdio->req_q_lock);
if (zfcp_qdio_sbal_get(qdio))
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)) {
@@ -1907,9 +1857,9 @@ int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
req->qtcb->header.port_handle = erp_action->port->handle;
- req->qtcb->bottom.support.fcp_lun = erp_action->unit->fcp_lun;
- req->handler = zfcp_fsf_open_unit_handler;
- req->data = erp_action->unit;
+ req->qtcb->bottom.support.fcp_lun = zfcp_scsi_dev_lun(erp_action->sdev);
+ req->handler = zfcp_fsf_open_lun_handler;
+ req->data = erp_action->sdev;
req->erp_action = erp_action;
erp_action->fsf_req_id = req->req_id;
@@ -1923,34 +1873,40 @@ int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
erp_action->fsf_req_id = 0;
}
out:
- spin_unlock_bh(&qdio->req_q_lock);
+ spin_unlock_irq(&qdio->req_q_lock);
return retval;
}
-static void zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *req)
+static void zfcp_fsf_close_lun_handler(struct zfcp_fsf_req *req)
{
- struct zfcp_unit *unit = req->data;
+ struct scsi_device *sdev = req->data;
+ 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(unit->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(unit->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_port_boxed(unit->port, "fscuh_3", 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, "fscuh_3");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_ADAPTER_STATUS_AVAILABLE:
switch (req->qtcb->header.fsf_status_qual.word[0]) {
case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
- zfcp_fc_test_link(unit->port);
+ zfcp_fc_test_link(zfcp_sdev->port);
/* fall through */
case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
@@ -1958,28 +1914,29 @@ static void zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *req)
}
break;
case FSF_GOOD:
- atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status);
+ atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &zfcp_sdev->status);
break;
}
}
/**
- * zfcp_fsf_close_unit - close zfcp unit
- * @erp_action: pointer to struct zfcp_unit
+ * zfcp_fsf_close_LUN - close LUN
+ * @erp_action: pointer to erp_action triggering the "close LUN"
* Returns: 0 on success, error otherwise
*/
-int zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action)
+int zfcp_fsf_close_lun(struct zfcp_erp_action *erp_action)
{
struct zfcp_qdio *qdio = erp_action->adapter->qdio;
+ struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(erp_action->sdev);
struct zfcp_fsf_req *req;
int retval = -EIO;
- spin_lock_bh(&qdio->req_q_lock);
+ spin_lock_irq(&qdio->req_q_lock);
if (zfcp_qdio_sbal_get(qdio))
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)) {
@@ -1991,9 +1948,9 @@ int zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action)
zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
req->qtcb->header.port_handle = erp_action->port->handle;
- req->qtcb->header.lun_handle = erp_action->unit->handle;
- req->handler = zfcp_fsf_close_unit_handler;
- req->data = erp_action->unit;
+ req->qtcb->header.lun_handle = zfcp_sdev->lun_handle;
+ req->handler = zfcp_fsf_close_lun_handler;
+ req->data = erp_action->sdev;
req->erp_action = erp_action;
erp_action->fsf_req_id = req->req_id;
@@ -2004,7 +1961,7 @@ int zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action)
erp_action->fsf_req_id = 0;
}
out:
- spin_unlock_bh(&qdio->req_q_lock);
+ spin_unlock_irq(&qdio->req_q_lock);
return retval;
}
@@ -2019,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_unit *unit = req->unit;
+ struct zfcp_scsi_dev *zfcp_sdev;
struct zfcp_blk_drv_data blktrc;
int ticks = req->adapter->timer_ticks;
@@ -2029,33 +1986,38 @@ static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi)
blktrc.magic = ZFCP_BLK_DRV_DATA_MAGIC;
if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
blktrc.flags |= ZFCP_BLK_REQ_ERROR;
- blktrc.inb_usage = req->qdio_req.qdio_inb_usage;
+ blktrc.inb_usage = 0;
blktrc.outb_usage = req->qdio_req.qdio_outb_usage;
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;
switch (req->qtcb->bottom.io.data_direction) {
+ case FSF_DATADIR_DIF_READ_STRIP:
+ case FSF_DATADIR_DIF_READ_CONVERT:
case FSF_DATADIR_READ:
- lat = &unit->latencies.read;
+ lat = &zfcp_sdev->latencies.read;
break;
+ case FSF_DATADIR_DIF_WRITE_INSERT:
+ case FSF_DATADIR_DIF_WRITE_CONVERT:
case FSF_DATADIR_WRITE:
- lat = &unit->latencies.write;
+ lat = &zfcp_sdev->latencies.write;
break;
case FSF_DATADIR_CMND:
- lat = &unit->latencies.cmd;
+ lat = &zfcp_sdev->latencies.cmd;
break;
}
if (lat) {
- spin_lock(&unit->latencies.lock);
+ spin_lock(&zfcp_sdev->latencies.lock);
zfcp_fsf_update_lat(&lat->channel, lat_in->channel_lat);
zfcp_fsf_update_lat(&lat->fabric, lat_in->fabric_lat);
lat->counter++;
- spin_unlock(&unit->latencies.lock);
+ spin_unlock(&zfcp_sdev->latencies.lock);
}
}
@@ -2063,161 +2025,197 @@ static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi)
sizeof(blktrc));
}
-static void zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *req)
-{
- struct scsi_cmnd *scpnt;
- struct fcp_resp_with_ext *fcp_rsp;
- unsigned long flags;
-
- read_lock_irqsave(&req->adapter->abort_lock, flags);
-
- scpnt = req->data;
- if (unlikely(!scpnt)) {
- read_unlock_irqrestore(&req->adapter->abort_lock, flags);
- return;
- }
-
- if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
- set_host_byte(scpnt, DID_TRANSPORT_DISRUPTED);
- goto skip_fsfstatus;
- }
-
- fcp_rsp = (struct fcp_resp_with_ext *) &req->qtcb->bottom.io.fcp_rsp;
- zfcp_fc_eval_fcp_rsp(fcp_rsp, scpnt);
-
-skip_fsfstatus:
- zfcp_fsf_req_trace(req, scpnt);
- zfcp_dbf_scsi_result(req->adapter->dbf, scpnt, req);
-
- scpnt->host_scribble = NULL;
- (scpnt->scsi_done) (scpnt);
- /*
- * We must hold this lock until scsi_done has been called.
- * Otherwise we may call scsi_done after abort regarding this
- * command has completed.
- * Note: scsi_done must not block!
- */
- read_unlock_irqrestore(&req->adapter->abort_lock, flags);
-}
-
-static void zfcp_fsf_send_fcp_ctm_handler(struct zfcp_fsf_req *req)
+static void zfcp_fsf_fcp_handler_common(struct zfcp_fsf_req *req)
{
- struct fcp_resp_with_ext *fcp_rsp;
- struct fcp_resp_rsp_info *rsp_info;
-
- fcp_rsp = (struct fcp_resp_with_ext *) &req->qtcb->bottom.io.fcp_rsp;
- rsp_info = (struct fcp_resp_rsp_info *) &fcp_rsp[1];
-
- if ((rsp_info->rsp_code != FCP_TMF_CMPL) ||
- (req->status & ZFCP_STATUS_FSFREQ_ERROR))
- req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED;
-}
-
-
-static void zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *req)
-{
- struct zfcp_unit *unit;
+ struct scsi_cmnd *scmnd = req->data;
+ struct scsi_device *sdev = scmnd->device;
+ struct zfcp_scsi_dev *zfcp_sdev;
struct fsf_qtcb_header *header = &req->qtcb->header;
- if (unlikely(req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT))
- unit = req->data;
- else
- unit = req->unit;
-
if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR))
- goto skip_fsfstatus;
+ 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(unit->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(unit->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_fsf_access_denied_unit(req, unit);
- break;
case FSF_DIRECTION_INDICATOR_NOT_VALID:
dev_err(&req->adapter->ccw_device->dev,
- "Incorrect direction %d, unit 0x%016Lx on port "
+ "Incorrect direction %d, LUN 0x%016Lx on port "
"0x%016Lx closed\n",
req->qtcb->bottom.io.data_direction,
- (unsigned long long)unit->fcp_lun,
- (unsigned long long)unit->port->wwpn);
- zfcp_erp_adapter_shutdown(unit->port->adapter, 0, "fssfch3",
- 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->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_CMND_LENGTH_NOT_VALID:
dev_err(&req->adapter->ccw_device->dev,
- "Incorrect CDB length %d, unit 0x%016Lx on "
+ "Incorrect CDB length %d, LUN 0x%016Lx on "
"port 0x%016Lx closed\n",
req->qtcb->bottom.io.fcp_cmnd_length,
- (unsigned long long)unit->fcp_lun,
- (unsigned long long)unit->port->wwpn);
- zfcp_erp_adapter_shutdown(unit->port->adapter, 0, "fssfch4",
- 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->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_PORT_BOXED:
- zfcp_erp_port_boxed(unit->port, "fssfch5", 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, "fssfch5");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_LUN_BOXED:
- zfcp_erp_unit_boxed(unit, "fssfch6", req);
+ zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ACCESS_BOXED);
+ zfcp_erp_lun_reopen(sdev, ZFCP_STATUS_COMMON_ERP_FAILED,
+ "fssfch6");
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_ADAPTER_STATUS_AVAILABLE:
if (header->fsf_status_qual.word[0] ==
FSF_SQ_INVOKE_LINK_TEST_PROCEDURE)
- zfcp_fc_test_link(unit->port);
+ zfcp_fc_test_link(zfcp_sdev->port);
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
}
+}
+
+static void zfcp_fsf_fcp_cmnd_handler(struct zfcp_fsf_req *req)
+{
+ struct scsi_cmnd *scpnt;
+ struct fcp_resp_with_ext *fcp_rsp;
+ unsigned long flags;
+
+ read_lock_irqsave(&req->adapter->abort_lock, flags);
+
+ scpnt = req->data;
+ if (unlikely(!scpnt)) {
+ read_unlock_irqrestore(&req->adapter->abort_lock, flags);
+ 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;
+ }
+
+ switch (req->qtcb->header.fsf_status) {
+ case FSF_INCONSISTENT_PROT_DATA:
+ case FSF_INVALID_PROT_PARM:
+ set_host_byte(scpnt, DID_ERROR);
+ goto skip_fsfstatus;
+ case FSF_BLOCK_GUARD_CHECK_FAILURE:
+ zfcp_scsi_dif_sense_error(scpnt, 0x1);
+ goto skip_fsfstatus;
+ case FSF_APP_TAG_CHECK_FAILURE:
+ zfcp_scsi_dif_sense_error(scpnt, 0x2);
+ goto skip_fsfstatus;
+ case FSF_REF_TAG_CHECK_FAILURE:
+ zfcp_scsi_dif_sense_error(scpnt, 0x3);
+ goto skip_fsfstatus;
+ }
+ fcp_rsp = (struct fcp_resp_with_ext *) &req->qtcb->bottom.io.fcp_rsp;
+ zfcp_fc_eval_fcp_rsp(fcp_rsp, scpnt);
+
skip_fsfstatus:
- if (req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT)
- zfcp_fsf_send_fcp_ctm_handler(req);
- else {
- zfcp_fsf_send_fcp_command_task_handler(req);
- req->unit = NULL;
- put_device(&unit->dev);
+ zfcp_fsf_req_trace(req, scpnt);
+ zfcp_dbf_scsi_result(scpnt, req);
+
+ scpnt->host_scribble = NULL;
+ (scpnt->scsi_done) (scpnt);
+ /*
+ * We must hold this lock until scsi_done has been called.
+ * Otherwise we may call scsi_done after abort regarding this
+ * command has completed.
+ * Note: scsi_done must not block!
+ */
+ read_unlock_irqrestore(&req->adapter->abort_lock, flags);
+}
+
+static int zfcp_fsf_set_data_dir(struct scsi_cmnd *scsi_cmnd, u32 *data_dir)
+{
+ switch (scsi_get_prot_op(scsi_cmnd)) {
+ case SCSI_PROT_NORMAL:
+ switch (scsi_cmnd->sc_data_direction) {
+ case DMA_NONE:
+ *data_dir = FSF_DATADIR_CMND;
+ break;
+ case DMA_FROM_DEVICE:
+ *data_dir = FSF_DATADIR_READ;
+ break;
+ case DMA_TO_DEVICE:
+ *data_dir = FSF_DATADIR_WRITE;
+ break;
+ case DMA_BIDIRECTIONAL:
+ return -EINVAL;
+ }
+ break;
+
+ case SCSI_PROT_READ_STRIP:
+ *data_dir = FSF_DATADIR_DIF_READ_STRIP;
+ break;
+ case SCSI_PROT_WRITE_INSERT:
+ *data_dir = FSF_DATADIR_DIF_WRITE_INSERT;
+ break;
+ case SCSI_PROT_READ_PASS:
+ *data_dir = FSF_DATADIR_DIF_READ_CONVERT;
+ break;
+ case SCSI_PROT_WRITE_PASS:
+ *data_dir = FSF_DATADIR_DIF_WRITE_CONVERT;
+ break;
+ default:
+ return -EINVAL;
}
+
+ return 0;
}
/**
- * zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command)
- * @unit: unit where command is sent to
+ * zfcp_fsf_fcp_cmnd - initiate an FCP command (for a SCSI command)
* @scsi_cmnd: scsi command to be sent
*/
-int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
- struct scsi_cmnd *scsi_cmnd)
+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;
- struct zfcp_adapter *adapter = unit->port->adapter;
+ 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(&unit->status) &
+ if (unlikely(!(atomic_read(&zfcp_sdev->status) &
ZFCP_STATUS_COMMON_UNBLOCKED)))
return -EBUSY;
- spin_lock(&qdio->req_q_lock);
- if (atomic_read(&qdio->req_q.count) <= 0) {
+ 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);
@@ -2227,57 +2225,48 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
goto out;
}
+ scsi_cmnd->host_scribble = (unsigned char *) req->req_id;
+
+ io = &req->qtcb->bottom.io;
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
- req->unit = unit;
req->data = scsi_cmnd;
- req->handler = zfcp_fsf_send_fcp_command_handler;
- req->qtcb->header.lun_handle = unit->handle;
- req->qtcb->header.port_handle = unit->port->handle;
- req->qtcb->bottom.io.service_class = FSF_CLASS_3;
- req->qtcb->bottom.io.fcp_cmnd_length = FCP_CMND_LEN;
-
- scsi_cmnd->host_scribble = (unsigned char *) req->req_id;
+ req->handler = zfcp_fsf_fcp_cmnd_handler;
+ req->qtcb->header.lun_handle = zfcp_sdev->lun_handle;
+ req->qtcb->header.port_handle = zfcp_sdev->port->handle;
+ io->service_class = FSF_CLASS_3;
+ io->fcp_cmnd_length = FCP_CMND_LEN;
- /*
- * set depending on data direction:
- * data direction bits in SBALE (SB Type)
- * data direction bits in QTCB
- */
- switch (scsi_cmnd->sc_data_direction) {
- case DMA_NONE:
- req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND;
- break;
- case DMA_FROM_DEVICE:
- req->qtcb->bottom.io.data_direction = FSF_DATADIR_READ;
- break;
- case DMA_TO_DEVICE:
- req->qtcb->bottom.io.data_direction = FSF_DATADIR_WRITE;
- break;
- case DMA_BIDIRECTIONAL:
- goto failed_scsi_cmnd;
+ if (scsi_get_prot_op(scsi_cmnd) != SCSI_PROT_NORMAL) {
+ io->data_block_length = scsi_cmnd->device->sector_size;
+ io->ref_tag_value = scsi_get_lba(scsi_cmnd) & 0xFFFFFFFF;
}
- get_device(&unit->dev);
+ 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);
- real_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req,
- scsi_sglist(scsi_cmnd),
- ZFCP_FSF_MAX_SBALS_PER_REQ);
- if (unlikely(real_bytes < 0)) {
- if (req->qdio_req.sbal_number >= ZFCP_FSF_MAX_SBALS_PER_REQ) {
- dev_err(&adapter->ccw_device->dev,
- "Oversize data package, unit 0x%016Lx "
- "on port 0x%016Lx closed\n",
- (unsigned long long)unit->fcp_lun,
- (unsigned long long)unit->port->wwpn);
- zfcp_erp_unit_shutdown(unit, 0, "fssfct1", req);
- retval = -EINVAL;
- }
- goto failed_scsi_cmnd;
+ if (scsi_prot_sg_count(scsi_cmnd)) {
+ zfcp_qdio_set_data_div(qdio, &req->qdio_req,
+ scsi_prot_sg_count(scsi_cmnd));
+ 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));
}
+ 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))
goto failed_scsi_cmnd;
@@ -2285,36 +2274,52 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
goto out;
failed_scsi_cmnd:
- put_device(&unit->dev);
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;
}
+static void zfcp_fsf_fcp_task_mgmt_handler(struct zfcp_fsf_req *req)
+{
+ struct fcp_resp_with_ext *fcp_rsp;
+ struct fcp_resp_rsp_info *rsp_info;
+
+ zfcp_fsf_fcp_handler_common(req);
+
+ fcp_rsp = (struct fcp_resp_with_ext *) &req->qtcb->bottom.io.fcp_rsp;
+ rsp_info = (struct fcp_resp_rsp_info *) &fcp_rsp[1];
+
+ if ((rsp_info->rsp_code != FCP_TMF_CMPL) ||
+ (req->status & ZFCP_STATUS_FSFREQ_ERROR))
+ req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED;
+}
+
/**
- * zfcp_fsf_send_fcp_ctm - send SCSI task management command
- * @unit: pointer to struct zfcp_unit
+ * zfcp_fsf_fcp_task_mgmt - send SCSI task management command
+ * @scmnd: SCSI command to send the task management command for
* @tm_flags: unsigned byte for task management flags
* Returns: on success pointer to struct fsf_req, NULL otherwise
*/
-struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags)
+struct zfcp_fsf_req *zfcp_fsf_fcp_task_mgmt(struct scsi_cmnd *scmnd,
+ u8 tm_flags)
{
struct zfcp_fsf_req *req = NULL;
struct fcp_cmnd *fcp_cmnd;
- struct zfcp_qdio *qdio = unit->port->adapter->qdio;
+ struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scmnd->device);
+ struct zfcp_qdio *qdio = zfcp_sdev->port->adapter->qdio;
- if (unlikely(!(atomic_read(&unit->status) &
+ if (unlikely(!(atomic_read(&zfcp_sdev->status) &
ZFCP_STATUS_COMMON_UNBLOCKED)))
return NULL;
- spin_lock_bh(&qdio->req_q_lock);
+ spin_lock_irq(&qdio->req_q_lock);
if (zfcp_qdio_sbal_get(qdio))
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)) {
@@ -2322,11 +2327,10 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags)
goto out;
}
- req->status |= ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT;
- req->data = unit;
- req->handler = zfcp_fsf_send_fcp_command_handler;
- req->qtcb->header.lun_handle = unit->handle;
- req->qtcb->header.port_handle = unit->port->handle;
+ req->data = scmnd;
+ req->handler = zfcp_fsf_fcp_task_mgmt_handler;
+ req->qtcb->header.lun_handle = zfcp_sdev->lun_handle;
+ req->qtcb->header.port_handle = zfcp_sdev->port->handle;
req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND;
req->qtcb->bottom.io.service_class = FSF_CLASS_3;
req->qtcb->bottom.io.fcp_cmnd_length = FCP_CMND_LEN;
@@ -2334,7 +2338,7 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags)
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, unit->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))
@@ -2343,78 +2347,10 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags)
zfcp_fsf_req_free(req);
req = NULL;
out:
- spin_unlock_bh(&qdio->req_q_lock);
+ spin_unlock_irq(&qdio->req_q_lock);
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_bh(&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,
- ZFCP_FSF_MAX_SBALS_PER_REQ);
- if (bytes != ZFCP_CFDC_MAX_SIZE) {
- zfcp_fsf_req_free(req);
- goto out;
- }
-
- zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
- retval = zfcp_fsf_req_send(req);
-out:
- spin_unlock_bh(&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
@@ -2423,7 +2359,7 @@ out:
void zfcp_fsf_reqid_check(struct zfcp_qdio *qdio, int sbal_idx)
{
struct zfcp_adapter *adapter = qdio->adapter;
- struct qdio_buffer *sbal = qdio->resp_q.sbal[sbal_idx];
+ struct qdio_buffer *sbal = qdio->res_q[sbal_idx];
struct qdio_buffer_element *sbale;
struct zfcp_fsf_req *fsf_req;
unsigned long req_id;
@@ -2435,20 +2371,20 @@ void zfcp_fsf_reqid_check(struct zfcp_qdio *qdio, int sbal_idx)
req_id = (unsigned long) sbale->addr;
fsf_req = zfcp_reqlist_find_rm(adapter->req_list, req_id);
- if (!fsf_req)
+ if (!fsf_req) {
/*
* Unknown request means that we have potentially memory
* corruption and must stop the machine immediately.
*/
+ zfcp_qdio_siosl(adapter);
panic("error: unknown req_id (%lx) on adapter %s.\n",
req_id, dev_name(&adapter->ccw_device->dev));
+ }
fsf_req->qdio_req.sbal_response = sbal_idx;
- fsf_req->qdio_req.qdio_inb_usage =
- atomic_read(&qdio->resp_q.count);
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 519083fd6e8..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
@@ -80,11 +72,15 @@
#define FSF_REQUEST_SIZE_TOO_LARGE 0x00000061
#define FSF_RESPONSE_SIZE_TOO_LARGE 0x00000062
#define FSF_SBAL_MISMATCH 0x00000063
+#define FSF_INCONSISTENT_PROT_DATA 0x00000070
+#define FSF_INVALID_PROT_PARM 0x00000071
+#define FSF_BLOCK_GUARD_CHECK_FAILURE 0x00000081
+#define FSF_APP_TAG_CHECK_FAILURE 0x00000082
+#define FSF_REF_TAG_CHECK_FAILURE 0x00000083
#define FSF_ADAPTER_STATUS_AVAILABLE 0x000000AD
#define FSF_UNKNOWN_COMMAND 0x000000E2
#define FSF_UNKNOWN_OP_SUBTYPE 0x000000E3
#define FSF_INVALID_COMMAND_OPTION 0x000000E5
-/* #define FSF_ERROR 0x000000FF */
#define FSF_PROT_STATUS_QUAL_SIZE 16
#define FSF_STATUS_QUALIFIER_SIZE 16
@@ -126,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 */
@@ -136,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
@@ -147,29 +141,28 @@
#define FSF_DATADIR_WRITE 0x00000001
#define FSF_DATADIR_READ 0x00000002
#define FSF_DATADIR_CMND 0x00000004
+#define FSF_DATADIR_DIF_WRITE_INSERT 0x00000009
+#define FSF_DATADIR_DIF_READ_STRIP 0x0000000a
+#define FSF_DATADIR_DIF_WRITE_CONVERT 0x0000000b
+#define FSF_DATADIR_DIF_READ_CONVERT 0X0000000c
+
+/* data protection control flags */
+#define FSF_APP_TAG_CHECK_ENABLE 0x10
/* fc service class */
#define FSF_CLASS_3 0x00000003
-/* SBAL chaining */
-#define ZFCP_FSF_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_FSF_MAX_SBALES_PER_REQ \
- (ZFCP_FSF_MAX_SBALS_PER_REQ * ZFCP_QDIO_MAX_SBALES_PER_SBAL - 2)
-
/* logging space behind QTCB */
#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
#define FSF_FEATURE_UPDATE_ALERT 0x00000100
#define FSF_FEATURE_MEASUREMENT_DATA 0x00000200
+#define FSF_FEATURE_DIF_PROT_TYPE1 0x00010000
+#define FSF_FEATURE_DIX_PROT_TCPIP 0x00020000
/* host connection features */
#define FSF_FEATURE_NPIV_MODE 0x00000001
@@ -177,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;
@@ -324,9 +303,14 @@ struct fsf_qtcb_header {
struct fsf_qtcb_bottom_io {
u32 data_direction;
u32 service_class;
- u8 res1[8];
+ u8 res1;
+ u8 data_prot_flags;
+ u16 app_tag_value;
+ u32 ref_tag_value;
u32 fcp_cmnd_length;
- u8 res2[12];
+ u32 data_block_length;
+ u32 prot_data_length;
+ u8 res2[4];
u8 fcp_cmnd[FSF_FCP_CMND_SIZE];
u8 fcp_rsp[FSF_FCP_RSP_SIZE];
u8 res3[64];
@@ -352,6 +336,8 @@ struct fsf_qtcb_bottom_support {
u8 els[256];
} __attribute__ ((packed));
+#define ZFCP_FSF_TIMER_INT_MASK 0x3FFF
+
struct fsf_qtcb_bottom_config {
u32 lic_version;
u32 feature_selection;
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c
index 28117e130e2..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;
@@ -30,15 +35,21 @@ static int zfcp_qdio_buffers_enqueue(struct qdio_buffer **sbal)
return 0;
}
-static void zfcp_qdio_handler_error(struct zfcp_qdio *qdio, char *id)
+static void zfcp_qdio_handler_error(struct zfcp_qdio *qdio, char *id,
+ unsigned int qdio_err)
{
struct zfcp_adapter *adapter = qdio->adapter;
dev_warn(&adapter->ccw_device->dev, "A QDIO problem occurred\n");
+ 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)
@@ -55,72 +66,67 @@ static void zfcp_qdio_zero_sbals(struct qdio_buffer *sbal[], int first, int cnt)
static inline void zfcp_qdio_account(struct zfcp_qdio *qdio)
{
unsigned long long now, span;
- int free, used;
+ int used;
- spin_lock(&qdio->stat_lock);
- now = get_clock_monotonic();
+ now = get_tod_clock_monotonic();
span = (now - qdio->req_q_time) >> 12;
- free = atomic_read(&qdio->req_q.count);
- used = QDIO_MAX_BUFFERS_PER_Q - free;
+ used = QDIO_MAX_BUFFERS_PER_Q - atomic_read(&qdio->req_q_free);
qdio->req_q_util += used * span;
qdio->req_q_time = now;
- spin_unlock(&qdio->stat_lock);
}
static void zfcp_qdio_int_req(struct ccw_device *cdev, unsigned int qdio_err,
- int queue_no, int first, int count,
+ int queue_no, int idx, int count,
unsigned long parm)
{
struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm;
- struct zfcp_qdio_queue *queue = &qdio->req_q;
if (unlikely(qdio_err)) {
- zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, first,
- count);
- zfcp_qdio_handler_error(qdio, "qdireq1");
+ zfcp_qdio_handler_error(qdio, "qdireq1", qdio_err);
return;
}
/* cleanup all SBALs being program-owned now */
- zfcp_qdio_zero_sbals(queue->sbal, first, count);
+ zfcp_qdio_zero_sbals(qdio->req_q, idx, count);
+ spin_lock_irq(&qdio->stat_lock);
zfcp_qdio_account(qdio);
- atomic_add(count, &queue->count);
+ spin_unlock_irq(&qdio->stat_lock);
+ atomic_add(count, &qdio->req_q_free);
wake_up(&qdio->req_q_wq);
}
-static void zfcp_qdio_resp_put_back(struct zfcp_qdio *qdio, int processed)
-{
- struct zfcp_qdio_queue *queue = &qdio->resp_q;
- struct ccw_device *cdev = qdio->adapter->ccw_device;
- u8 count, start = queue->first;
- unsigned int retval;
-
- count = atomic_read(&queue->count) + processed;
-
- retval = do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, start, count);
-
- if (unlikely(retval)) {
- atomic_set(&queue->count, count);
- zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdrpb_1", NULL);
- } else {
- queue->first += count;
- queue->first %= QDIO_MAX_BUFFERS_PER_Q;
- atomic_set(&queue->count, 0);
- }
-}
-
static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err,
- int queue_no, int first, int count,
+ int queue_no, int idx, int count,
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, first,
- count);
- zfcp_qdio_handler_error(qdio, "qdires1");
+ 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;
}
@@ -129,25 +135,16 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err,
* returned by QDIO layer
*/
for (sbal_no = 0; sbal_no < count; sbal_no++) {
- sbal_idx = (first + sbal_no) % QDIO_MAX_BUFFERS_PER_Q;
+ sbal_idx = (idx + sbal_no) % QDIO_MAX_BUFFERS_PER_Q;
/* go through all SBALEs of SBAL */
zfcp_fsf_reqid_check(qdio, sbal_idx);
}
/*
- * put range of SBALs back to response queue
- * (including SBALs which have already been free before)
+ * put SBALs back to response queue
*/
- zfcp_qdio_resp_put_back(qdio, count);
-}
-
-static void zfcp_qdio_sbal_limit(struct zfcp_qdio *qdio,
- struct zfcp_qdio_req *q_req, int max_sbals)
-{
- int count = atomic_read(&qdio->req_q.count);
- count = min(count, max_sbals);
- q_req->sbal_limit = (q_req->sbal_first + count - 1)
- % QDIO_MAX_BUFFERS_PER_Q;
+ if (do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, idx, count))
+ zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdires2");
}
static struct qdio_buffer_element *
@@ -157,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)
@@ -165,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++;
@@ -173,13 +170,14 @@ zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
/* keep this requests number of SBALs up-to-date */
q_req->sbal_number++;
+ BUG_ON(q_req->sbal_number > ZFCP_QDIO_MAX_SBALS_PER_REQ);
/* start at first SBALE of new SBAL */
q_req->sbale_curr = 0;
/* 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;
}
@@ -187,73 +185,48 @@ 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);
}
-static void zfcp_qdio_undo_sbals(struct zfcp_qdio *qdio,
- struct zfcp_qdio_req *q_req)
-{
- struct qdio_buffer **sbal = qdio->req_q.sbal;
- int first = q_req->sbal_first;
- int last = q_req->sbal_last;
- int count = (last - first + QDIO_MAX_BUFFERS_PER_Q) %
- QDIO_MAX_BUFFERS_PER_Q + 1;
- zfcp_qdio_zero_sbals(sbal, first, count);
-}
-
/**
* zfcp_qdio_sbals_from_sg - fill SBALs from scatter-gather list
* @qdio: pointer to struct zfcp_qdio
* @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, int max_sbals)
+ struct scatterlist *sg)
{
struct qdio_buffer_element *sbale;
- int bytes = 0;
-
- /* figure out last allowed SBAL */
- zfcp_qdio_sbal_limit(qdio, q_req, max_sbals);
/* 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);
if (!sbale) {
atomic_inc(&qdio->req_q_full);
- zfcp_qdio_undo_sbals(qdio, q_req);
+ zfcp_qdio_zero_sbals(qdio->req_q, q_req->sbal_first,
+ q_req->sbal_number);
return -EINVAL;
}
-
sbale->addr = sg_virt(sg);
sbale->length = sg->length;
-
- bytes += sg->length;
}
-
- /* assume that no other SBALEs are to follow in the same SBAL */
- sbale = zfcp_qdio_sbale_curr(qdio, q_req);
- sbale->flags |= SBAL_FLAGS_LAST_ENTRY;
-
- return bytes;
+ return 0;
}
static int zfcp_qdio_sbal_check(struct zfcp_qdio *qdio)
{
- struct zfcp_qdio_queue *req_q = &qdio->req_q;
-
- spin_lock_bh(&qdio->req_q_lock);
- if (atomic_read(&req_q->count))
+ if (atomic_read(&qdio->req_q_free) ||
+ !(atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP))
return 1;
- spin_unlock_bh(&qdio->req_q_lock);
return 0;
}
@@ -271,18 +244,21 @@ int zfcp_qdio_sbal_get(struct zfcp_qdio *qdio)
{
long ret;
- spin_unlock_bh(&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;
+
if (ret > 0)
return 0;
+
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_bh(&qdio->req_q_lock);
return -EIO;
}
@@ -294,25 +270,27 @@ int zfcp_qdio_sbal_get(struct zfcp_qdio *qdio)
*/
int zfcp_qdio_send(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
{
- struct zfcp_qdio_queue *req_q = &qdio->req_q;
- int first = q_req->sbal_first;
- int count = q_req->sbal_number;
int retval;
- unsigned int qdio_flags = QDIO_FLAG_SYNC_OUTPUT;
+ u8 sbal_number = q_req->sbal_number;
+ spin_lock(&qdio->stat_lock);
zfcp_qdio_account(qdio);
+ spin_unlock(&qdio->stat_lock);
+
+ retval = do_QDIO(qdio->adapter->ccw_device, QDIO_FLAG_SYNC_OUTPUT, 0,
+ q_req->sbal_first, sbal_number);
- retval = do_QDIO(qdio->adapter->ccw_device, qdio_flags, 0, first,
- count);
if (unlikely(retval)) {
- zfcp_qdio_zero_sbals(req_q->sbal, first, count);
+ zfcp_qdio_zero_sbals(qdio->req_q, q_req->sbal_first,
+ sbal_number);
return retval;
}
/* account for transferred buffers */
- atomic_sub(count, &req_q->count);
- req_q->first += count;
- req_q->first %= QDIO_MAX_BUFFERS_PER_Q;
+ atomic_sub(sbal_number, &qdio->req_q_free);
+ qdio->req_q_idx += sbal_number;
+ qdio->req_q_idx %= QDIO_MAX_BUFFERS_PER_Q;
+
return 0;
}
@@ -320,24 +298,25 @@ int zfcp_qdio_send(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
static void zfcp_qdio_setup_init_data(struct qdio_initialize *id,
struct zfcp_qdio *qdio)
{
-
+ memset(id, 0, sizeof(*id));
id->cdev = qdio->adapter->ccw_device;
id->q_format = QDIO_ZFCP_QFMT;
memcpy(id->adapter_name, dev_name(&id->cdev->dev), 8);
ASCEBC(id->adapter_name, 8);
- id->qib_param_field_format = 0;
- id->qib_param_field = NULL;
- id->input_slib_elements = NULL;
- id->output_slib_elements = NULL;
+ 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;
id->output_handler = zfcp_qdio_int_req;
id->int_parm = (unsigned long) qdio;
- id->input_sbal_addr_array = (void **) (qdio->resp_q.sbal);
- id->output_sbal_addr_array = (void **) (qdio->req_q.sbal);
-
+ 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;
}
+
/**
* zfcp_qdio_allocate - allocate queue memory and initialize QDIO data
* @adapter: pointer to struct zfcp_adapter
@@ -348,11 +327,12 @@ static int zfcp_qdio_allocate(struct zfcp_qdio *qdio)
{
struct qdio_initialize init_data;
- if (zfcp_qdio_buffers_enqueue(qdio->req_q.sbal) ||
- zfcp_qdio_buffers_enqueue(qdio->resp_q.sbal))
+ if (zfcp_qdio_buffers_enqueue(qdio->req_q) ||
+ zfcp_qdio_buffers_enqueue(qdio->res_q))
return -ENOMEM;
zfcp_qdio_setup_init_data(&init_data, qdio);
+ init_waitqueue_head(&qdio->req_q_wq);
return qdio_allocate(&init_data);
}
@@ -363,32 +343,30 @@ static int zfcp_qdio_allocate(struct zfcp_qdio *qdio)
*/
void zfcp_qdio_close(struct zfcp_qdio *qdio)
{
- struct zfcp_qdio_queue *req_q;
- int first, count;
+ struct zfcp_adapter *adapter = qdio->adapter;
+ int idx, count;
- if (!(atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP))
+ if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP))
return;
/* clear QDIOUP flag, thus do_QDIO is not called during qdio_shutdown */
- req_q = &qdio->req_q;
- spin_lock_bh(&qdio->req_q_lock);
- atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &qdio->adapter->status);
- spin_unlock_bh(&qdio->req_q_lock);
+ spin_lock_irq(&qdio->req_q_lock);
+ atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status);
+ spin_unlock_irq(&qdio->req_q_lock);
+
+ wake_up(&qdio->req_q_wq);
- qdio_shutdown(qdio->adapter->ccw_device,
- QDIO_FLAG_CLEANUP_USING_CLEAR);
+ qdio_shutdown(adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR);
/* cleanup used outbound sbals */
- count = atomic_read(&req_q->count);
+ count = atomic_read(&qdio->req_q_free);
if (count < QDIO_MAX_BUFFERS_PER_Q) {
- first = (req_q->first + count) % QDIO_MAX_BUFFERS_PER_Q;
+ idx = (qdio->req_q_idx + count) % QDIO_MAX_BUFFERS_PER_Q;
count = QDIO_MAX_BUFFERS_PER_Q - count;
- zfcp_qdio_zero_sbals(req_q->sbal, first, count);
+ zfcp_qdio_zero_sbals(qdio->req_q, idx, count);
}
- req_q->first = 0;
- atomic_set(&req_q->count, 0);
- qdio->resp_q.first = 0;
- atomic_set(&qdio->resp_q.count, 0);
+ qdio->req_q_idx = 0;
+ atomic_set(&qdio->req_q_free, 0);
}
/**
@@ -400,34 +378,63 @@ int zfcp_qdio_open(struct zfcp_qdio *qdio)
{
struct qdio_buffer_element *sbale;
struct qdio_initialize init_data;
- struct ccw_device *cdev = qdio->adapter->ccw_device;
+ struct zfcp_adapter *adapter = qdio->adapter;
+ struct ccw_device *cdev = adapter->ccw_device;
+ struct qdio_ssqd_desc ssqd;
int cc;
- if (atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)
+ if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)
return -EIO;
+ atomic_clear_mask(ZFCP_STATUS_ADAPTER_SIOSL_ISSUED,
+ &qdio->adapter->status);
+
zfcp_qdio_setup_init_data(&init_data, qdio);
if (qdio_establish(&init_data))
goto failed_establish;
+ if (qdio_get_ssqd_desc(init_data.cdev, &ssqd))
+ goto failed_qdio;
+
+ if (ssqd.qdioac2 & CHSC_AC2_DATA_DIV_ENABLED)
+ 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->resp_q.sbal[cc]->element[0]);
+ 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))
+ 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 */
- qdio->req_q.first = 0;
- atomic_set(&qdio->req_q.count, QDIO_MAX_BUFFERS_PER_Q);
+ /* 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;
@@ -441,7 +448,6 @@ failed_establish:
void zfcp_qdio_destroy(struct zfcp_qdio *qdio)
{
- struct qdio_buffer **sbal_req, **sbal_resp;
int p;
if (!qdio)
@@ -450,12 +456,9 @@ void zfcp_qdio_destroy(struct zfcp_qdio *qdio)
if (qdio->adapter->ccw_device)
qdio_free(qdio->adapter->ccw_device);
- sbal_req = qdio->req_q.sbal;
- sbal_resp = qdio->resp_q.sbal;
-
for (p = 0; p < QDIO_MAX_BUFFERS_PER_Q; p += QBUFF_PER_PAGE) {
- free_page((unsigned long) sbal_req[p]);
- free_page((unsigned long) sbal_resp[p]);
+ free_page((unsigned long) qdio->req_q[p]);
+ free_page((unsigned long) qdio->res_q[p]);
}
kfree(qdio);
@@ -483,3 +486,26 @@ int zfcp_qdio_setup(struct zfcp_adapter *adapter)
return 0;
}
+/**
+ * zfcp_qdio_siosl - Trigger logging in FCP channel
+ * @adapter: The zfcp_adapter where to trigger logging
+ *
+ * Call the cio siosl function to trigger hardware logging. This
+ * wrapper function sets a flag to ensure hardware logging is only
+ * triggered once before going through qdio shutdown.
+ *
+ * The triggers are always run from qdio tasklet context, so no
+ * additional synchronization is necessary.
+ */
+void zfcp_qdio_siosl(struct zfcp_adapter *adapter)
+{
+ int rc;
+
+ if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_SIOSL_ISSUED)
+ return;
+
+ rc = ccw_device_siosl(adapter->ccw_device);
+ if (!rc)
+ atomic_set_mask(ZFCP_STATUS_ADAPTER_SIOSL_ISSUED,
+ &adapter->status);
+}
diff --git a/drivers/s390/scsi/zfcp_qdio.h b/drivers/s390/scsi/zfcp_qdio.h
index 138fba577b4..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,28 +13,15 @@
#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)
-
-/**
- * struct zfcp_qdio_queue - qdio queue buffer, zfcp index and free count
- * @sbal: qdio buffers
- * @first: index of next free buffer in queue
- * @count: number of free buffers in queue
- */
-struct zfcp_qdio_queue {
- struct qdio_buffer *sbal[QDIO_MAX_BUFFERS_PER_Q];
- u8 first;
- atomic_t count;
-};
+/* Max SBALS for chaining */
+#define ZFCP_QDIO_MAX_SBALS_PER_REQ 36
/**
* struct zfcp_qdio - basic qdio data structure
- * @resp_q: response queue
+ * @res_q: response queue
* @req_q: request queue
+ * @req_q_idx: index of next free buffer
+ * @req_q_free: number of free buffers in queue
* @stat_lock: lock to protect req_q_util and req_q_time
* @req_q_lock: lock to serialize access to request queue
* @req_q_time: time of last fill level change
@@ -44,8 +31,10 @@ struct zfcp_qdio_queue {
* @adapter: adapter used in conjunction with this qdio structure
*/
struct zfcp_qdio {
- struct zfcp_qdio_queue resp_q;
- struct zfcp_qdio_queue req_q;
+ struct qdio_buffer *res_q[QDIO_MAX_BUFFERS_PER_Q];
+ struct qdio_buffer *req_q[QDIO_MAX_BUFFERS_PER_Q];
+ u8 req_q_idx;
+ atomic_t req_q_free;
spinlock_t stat_lock;
spinlock_t req_q_lock;
unsigned long long req_q_time;
@@ -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;
};
/**
@@ -65,10 +56,9 @@ struct zfcp_qdio {
* @sbale_curr: current sbale at creation of this request
* @sbal_response: sbal used in interrupt
* @qdio_outb_usage: usage of outbound queue
- * @qdio_inb_usage: usage of inbound queue
*/
struct zfcp_qdio_req {
- u32 sbtype;
+ u8 sbtype;
u8 sbal_number;
u8 sbal_first;
u8 sbal_last;
@@ -76,22 +66,9 @@ struct zfcp_qdio_req {
u8 sbale_curr;
u8 sbal_response;
u16 qdio_outb_usage;
- u16 qdio_inb_usage;
};
/**
- * zfcp_qdio_sbale - return pointer to sbale in qdio queue
- * @q: queue where to find sbal
- * @sbal_idx: sbal index in queue
- * @sbale_idx: sbale index in sbal
- */
-static inline struct qdio_buffer_element *
-zfcp_qdio_sbale(struct zfcp_qdio_queue *q, int sbal_idx, int sbale_idx)
-{
- return &q->sbal[sbal_idx]->element[sbale_idx];
-}
-
-/**
* zfcp_qdio_sbale_req - return pointer to sbale on req_q for a request
* @qdio: pointer to struct zfcp_qdio
* @q_rec: pointer to struct zfcp_qdio_req
@@ -100,7 +77,7 @@ zfcp_qdio_sbale(struct zfcp_qdio_queue *q, int sbal_idx, int sbale_idx)
static inline struct qdio_buffer_element *
zfcp_qdio_sbale_req(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
{
- return zfcp_qdio_sbale(&qdio->req_q, q_req->sbal_last, 0);
+ return &qdio->req_q[q_req->sbal_last]->element[0];
}
/**
@@ -112,8 +89,7 @@ zfcp_qdio_sbale_req(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
static inline struct qdio_buffer_element *
zfcp_qdio_sbale_curr(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
{
- return zfcp_qdio_sbale(&qdio->req_q, q_req->sbal_last,
- q_req->sbale_curr);
+ return &qdio->req_q[q_req->sbal_last]->element[q_req->sbale_curr];
}
/**
@@ -131,24 +107,29 @@ 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),
+ ZFCP_QDIO_MAX_SBALS_PER_REQ);
- q_req->sbal_first = q_req->sbal_last = qdio->req_q.first;
+ q_req->sbal_first = q_req->sbal_last = qdio->req_q_idx;
q_req->sbal_number = 1;
q_req->sbtype = sbtype;
+ q_req->sbale_curr = 1;
+ q_req->sbal_limit = (q_req->sbal_first + count - 1)
+ % QDIO_MAX_BUFFERS_PER_Q;
sbale = zfcp_qdio_sbale_req(qdio, q_req);
sbale->addr = (void *) req_id;
- sbale->flags |= SBAL_FLAGS0_COMMAND;
- sbale->flags |= sbtype;
+ sbale->eflags = 0;
+ sbale->sflags = SBAL_SFLAGS0_COMMAND | sbtype;
- q_req->sbale_curr = 1;
+ if (unlikely(!data))
+ return;
sbale++;
sbale->addr = data;
- if (likely(data))
- sbale->length = len;
+ sbale->length = len;
}
/**
@@ -165,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;
@@ -184,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;
}
/**
@@ -205,9 +186,86 @@ 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 = qdio->max_sbale_per_sbal - 1;
+}
+
+/**
+ * zfcp_qdio_sbal_limit - set the sbal limit for a request in q_req
+ * @qdio: pointer to struct zfcp_qdio
+ * @q_req: The current zfcp_qdio_req
+ * @max_sbals: maximum number of SBALs allowed
+ */
+static inline
+void zfcp_qdio_sbal_limit(struct zfcp_qdio *qdio,
+ struct zfcp_qdio_req *q_req, int max_sbals)
{
- q_req->sbale_curr = ZFCP_QDIO_LAST_SBALE_PER_SBAL;
+ int count = min(atomic_read(&qdio->req_q_free), max_sbals);
+
+ q_req->sbal_limit = (q_req->sbal_first + count - 1) %
+ QDIO_MAX_BUFFERS_PER_Q;
+}
+
+/**
+ * zfcp_qdio_set_data_div - set data division count
+ * @qdio: pointer to struct zfcp_qdio
+ * @q_req: The current zfcp_qdio_req
+ * @count: The data division count
+ */
+static inline
+void zfcp_qdio_set_data_div(struct zfcp_qdio *qdio,
+ struct zfcp_qdio_req *q_req, u32 count)
+{
+ struct qdio_buffer_element *sbale;
+
+ 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 be5d2c60453..7b353647cb9 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -3,16 +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 <asm/atomic.h>
+#include <scsi/scsi_eh.h>
+#include <linux/atomic.h>
#include "zfcp_ext.h"
#include "zfcp_dbf.h"
#include "zfcp_fc.h"
@@ -22,6 +24,14 @@ static unsigned int default_depth = 32;
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;
+module_param_named(dif, enable_dif, bool, 0400);
+MODULE_PARM_DESC(dif, "Enable DIF/DIX data integrity support");
+
+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)
{
@@ -41,11 +51,16 @@ static int zfcp_scsi_change_queue_depth(struct scsi_device *sdev, int depth,
return sdev->queue_depth;
}
-static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt)
+static void zfcp_scsi_slave_destroy(struct scsi_device *sdev)
{
- struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata;
- unit->device = NULL;
- put_device(&unit->dev);
+ 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);
}
static int zfcp_scsi_slave_configure(struct scsi_device *sdp)
@@ -59,47 +74,35 @@ 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_unit *unit;
- struct zfcp_adapter *adapter;
- int status, scsi_result, ret;
+ struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scpnt->device);
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;
-
- /*
- * figure out adapter and target device
- * (stored there by zfcp_scsi_slave_alloc)
- */
- adapter = (struct zfcp_adapter *) scpnt->device->host->hostdata[0];
- unit = scpnt->device->hostdata;
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;
}
- status = atomic_read(&unit->status);
+ status = atomic_read(&zfcp_sdev->status);
if (unlikely(status & ZFCP_STATUS_COMMON_ERP_FAILED) &&
- !(atomic_read(&unit->port->status) &
+ !(atomic_read(&zfcp_sdev->port->status) &
ZFCP_STATUS_COMMON_ERP_FAILED)) {
- /* only unit access denied, but port is good
+ /* only LUN access denied, but port is good
* not covered by FC transport, have to fail here */
zfcp_scsi_command_fail(scpnt, DID_ERROR);
return 0;
@@ -107,8 +110,8 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
if (unlikely(!(status & ZFCP_STATUS_COMMON_UNBLOCKED))) {
/* This could be either
- * open unit pending: this is temporary, will result in
- * open unit or ERP_FAILED, so retry command
+ * open LUN pending: this is temporary, will result in
+ * open LUN or ERP_FAILED, so retry command
* call to rport_delete pending: mimic retry from
* fc_remote_port_chkready until rport is BLOCKED
*/
@@ -116,7 +119,7 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
return 0;
}
- ret = zfcp_fsf_send_fcp_command_task(unit, scpnt);
+ ret = zfcp_fsf_fcp_cmnd(scpnt);
if (unlikely(ret == -EBUSY))
return SCSI_MLQUEUE_DEVICE_BUSY;
else if (unlikely(ret < 0))
@@ -125,45 +128,43 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
return ret;
}
-static struct zfcp_unit *zfcp_unit_lookup(struct zfcp_adapter *adapter,
- unsigned int id, u64 lun)
+static int zfcp_scsi_slave_alloc(struct scsi_device *sdev)
{
- unsigned long flags;
+ struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
+ struct zfcp_adapter *adapter =
+ (struct zfcp_adapter *) sdev->host->hostdata[0];
+ struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
struct zfcp_port *port;
- struct zfcp_unit *unit = NULL;
+ struct zfcp_unit *unit;
+ int npiv = adapter->connection_features & FSF_FEATURE_NPIV_MODE;
- read_lock_irqsave(&adapter->port_list_lock, flags);
- list_for_each_entry(port, &adapter->port_list, list) {
- if (!port->rport || (id != port->rport->scsi_target_id))
- continue;
- unit = zfcp_get_unit_by_lun(port, lun);
- if (unit)
- break;
- }
- read_unlock_irqrestore(&adapter->port_list_lock, flags);
+ port = zfcp_get_port_by_wwpn(adapter, rport->port_name);
+ if (!port)
+ return -ENXIO;
- return unit;
-}
+ unit = zfcp_unit_find(port, zfcp_scsi_dev_lun(sdev));
+ if (unit)
+ put_device(&unit->dev);
-static int zfcp_scsi_slave_alloc(struct scsi_device *sdp)
-{
- struct zfcp_adapter *adapter;
- struct zfcp_unit *unit;
- u64 lun;
+ if (!unit && !(allow_lun_scan && npiv)) {
+ put_device(&port->dev);
+ return -ENXIO;
+ }
- adapter = (struct zfcp_adapter *) sdp->host->hostdata[0];
- if (!adapter)
- goto out;
+ zfcp_sdev->port = port;
+ zfcp_sdev->latencies.write.channel.min = 0xFFFFFFFF;
+ zfcp_sdev->latencies.write.fabric.min = 0xFFFFFFFF;
+ zfcp_sdev->latencies.read.channel.min = 0xFFFFFFFF;
+ zfcp_sdev->latencies.read.fabric.min = 0xFFFFFFFF;
+ zfcp_sdev->latencies.cmd.channel.min = 0xFFFFFFFF;
+ zfcp_sdev->latencies.cmd.fabric.min = 0xFFFFFFFF;
+ spin_lock_init(&zfcp_sdev->latencies.lock);
- int_to_scsilun(sdp->lun, (struct scsi_lun *)&lun);
- unit = zfcp_unit_lookup(adapter, sdp->id, lun);
- if (unit) {
- sdp->hostdata = unit;
- unit->device = sdp;
- return 0;
- }
-out:
- return -ENXIO;
+ zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_RUNNING);
+ zfcp_erp_lun_reopen(sdev, 0, "scsla_1");
+ zfcp_erp_wait(port->adapter);
+
+ return 0;
}
static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
@@ -171,7 +172,6 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
struct Scsi_Host *scsi_host = scpnt->device->host;
struct zfcp_adapter *adapter =
(struct zfcp_adapter *) scsi_host->hostdata[0];
- struct zfcp_unit *unit = scpnt->device->hostdata;
struct zfcp_fsf_req *old_req, *abrt_req;
unsigned long flags;
unsigned long old_reqid = (unsigned long) scpnt->host_scribble;
@@ -185,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;
@@ -195,49 +194,52 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
write_unlock_irqrestore(&adapter->abort_lock, flags);
while (retry--) {
- abrt_req = zfcp_fsf_abort_fcp_command(old_reqid, unit);
+ abrt_req = zfcp_fsf_abort_fcp_cmnd(scpnt);
if (abrt_req)
break;
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;
}
static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags)
{
- struct zfcp_unit *unit = scpnt->device->hostdata;
- struct zfcp_adapter *adapter = unit->port->adapter;
+ struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scpnt->device);
+ struct zfcp_adapter *adapter = zfcp_sdev->port->adapter;
struct zfcp_fsf_req *fsf_req = NULL;
int retval = SUCCESS, ret;
int retry = 3;
while (retry--) {
- fsf_req = zfcp_fsf_send_fcp_ctm(unit, tm_flags);
+ fsf_req = zfcp_fsf_fcp_task_mgmt(scpnt, tm_flags);
if (fsf_req)
break;
@@ -248,7 +250,7 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags)
if (!(atomic_read(&adapter->status) &
ZFCP_STATUS_COMMON_RUNNING)) {
- zfcp_dbf_scsi_devreset("nres", tm_flags, unit, scpnt);
+ zfcp_dbf_scsi_devreset("nres", scpnt, tm_flags);
return SUCCESS;
}
}
@@ -258,10 +260,10 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags)
wait_for_completion(&fsf_req->completion);
if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) {
- zfcp_dbf_scsi_devreset("fail", tm_flags, unit, scpnt);
+ zfcp_dbf_scsi_devreset("fail", scpnt, tm_flags);
retval = FAILED;
} else
- zfcp_dbf_scsi_devreset("okay", tm_flags, unit, scpnt);
+ zfcp_dbf_scsi_devreset("okay", scpnt, tm_flags);
zfcp_fsf_req_free(fsf_req);
return retval;
@@ -279,11 +281,11 @@ static int zfcp_scsi_eh_target_reset_handler(struct scsi_cmnd *scpnt)
static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
{
- struct zfcp_unit *unit = scpnt->device->hostdata;
- struct zfcp_adapter *adapter = unit->port->adapter;
+ struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scpnt->device);
+ 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)
@@ -292,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;
@@ -301,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,
@@ -311,12 +347,12 @@ int zfcp_adapter_scsi_register(struct zfcp_adapter *adapter)
}
/* tell the SCSI stack some characteristics of this adapter */
- adapter->scsi_host->max_id = 1;
- adapter->scsi_host->max_lun = 1;
+ adapter->scsi_host->max_id = 511;
+ adapter->scsi_host->max_lun = 0xFFFFFFFF;
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;
@@ -328,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;
@@ -346,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*
@@ -506,8 +544,10 @@ static void zfcp_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout)
* @rport: The FC rport where to teminate I/O
*
* Abort all pending SCSI commands for a port by closing the
- * port. Using a reopen avoiding a conflict with a shutdown
- * overwriting a reopen.
+ * port. Using a reopen avoids a conflict with a shutdown
+ * overwriting a reopen. The "forced" ensures that a disappeared port
+ * is not opened again as valid due to the cached plogi data in
+ * non-NPIV mode.
*/
static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport)
{
@@ -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_reopen(port, 0, "sctrpi1", NULL);
+ zfcp_erp_port_forced_reopen(port, 0, "sctrpi1");
put_device(&port->dev);
}
}
@@ -548,6 +588,9 @@ static void zfcp_scsi_rport_register(struct zfcp_port *port)
rport->maxframe_size = port->maxframe_size;
rport->supported_classes = port->supported_classes;
port->rport = rport;
+ port->starget_id = rport->scsi_target_id;
+
+ zfcp_unit_queue_scsi_scan(port);
}
static void zfcp_scsi_rport_block(struct zfcp_port *port)
@@ -610,22 +653,50 @@ void zfcp_scsi_rport_work(struct work_struct *work)
put_device(&port->dev);
}
-
-void zfcp_scsi_scan(struct work_struct *work)
+/**
+ * zfcp_scsi_set_prot - Configure DIF/DIX support in scsi_host
+ * @adapter: The adapter where to configure DIF/DIX for the SCSI host
+ */
+void zfcp_scsi_set_prot(struct zfcp_adapter *adapter)
{
- struct zfcp_unit *unit = container_of(work, struct zfcp_unit,
- scsi_work);
- struct fc_rport *rport;
-
- flush_work(&unit->port->rport_work);
- rport = unit->port->rport;
+ unsigned int mask = 0;
+ unsigned int data_div;
+ struct Scsi_Host *shost = adapter->scsi_host;
+
+ data_div = atomic_read(&adapter->status) &
+ ZFCP_STATUS_ADAPTER_DATA_DIV_ENABLED;
+
+ if (enable_dif &&
+ adapter->adapter_features & FSF_FEATURE_DIF_PROT_TYPE1)
+ mask |= SHOST_DIF_TYPE1_PROTECTION;
+
+ if (enable_dif && data_div &&
+ 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 = adapter->qdio->max_sbale_per_req / 2;
+ shost->sg_tablesize = adapter->qdio->max_sbale_per_req / 2;
+ shost->max_sectors = shost->sg_tablesize * 8;
+ }
- if (rport && rport->port_state == FC_PORTSTATE_ONLINE)
- scsi_scan_target(&rport->dev, 0, rport->scsi_target_id,
- scsilun_to_int((struct scsi_lun *)
- &unit->fcp_lun), 0);
+ scsi_host_set_prot(shost, mask);
+}
- put_device(&unit->dev);
+/**
+ * zfcp_scsi_dif_sense_error - Report DIF/DIX error as driver sense error
+ * @scmd: The SCSI command to report the error for
+ * @ascq: The ASCQ to put in the sense buffer
+ *
+ * See the error handling in sd_done for the sense codes used here.
+ * Set DID_SOFT_ERROR to retry the request, if possible.
+ */
+void zfcp_scsi_dif_sense_error(struct scsi_cmnd *scmd, int ascq)
+{
+ scsi_build_sense_buffer(1, scmd->sense_buffer,
+ ILLEGAL_REQUEST, 0x10, ascq);
+ set_driver_byte(scmd, DRIVER_SENSE);
+ scmd->result |= SAM_STAT_CHECK_CONDITION;
+ set_host_byte(scmd, DID_SOFT_ERROR);
}
struct fc_function_template zfcp_transport_functions = {
@@ -655,34 +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,
- .disable_target_scan = 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_FSF_MAX_SBALES_PER_REQ,
- .cmd_per_lun = 1,
- .use_clustering = 1,
- .sdev_attrs = zfcp_sysfs_sdev_attrs,
- .max_sectors = (ZFCP_FSF_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 f5f60698dc4..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,\
@@ -68,63 +78,91 @@ ZFCP_DEFINE_ATTR(zfcp_port, port, access_denied, "%d\n",
ZFCP_STATUS_COMMON_ACCESS_DENIED) != 0);
ZFCP_DEFINE_ATTR(zfcp_unit, unit, status, "0x%08x\n",
- atomic_read(&unit->status));
+ zfcp_unit_sdev_status(unit));
ZFCP_DEFINE_ATTR(zfcp_unit, unit, in_recovery, "%d\n",
- (atomic_read(&unit->status) &
+ (zfcp_unit_sdev_status(unit) &
ZFCP_STATUS_COMMON_ERP_INUSE) != 0);
ZFCP_DEFINE_ATTR(zfcp_unit, unit, access_denied, "%d\n",
- (atomic_read(&unit->status) &
+ (zfcp_unit_sdev_status(unit) &
ZFCP_STATUS_COMMON_ACCESS_DENIED) != 0);
-ZFCP_DEFINE_ATTR(zfcp_unit, unit, access_shared, "%d\n",
- (atomic_read(&unit->status) &
- ZFCP_STATUS_UNIT_SHARED) != 0);
-ZFCP_DEFINE_ATTR(zfcp_unit, unit, access_readonly, "%d\n",
- (atomic_read(&unit->status) &
- ZFCP_STATUS_UNIT_READONLY) != 0);
-
-#define ZFCP_SYSFS_FAILED(_feat_def, _feat, _adapter, _mod_id, _reopen_id) \
-static ssize_t zfcp_sysfs_##_feat##_failed_show(struct device *dev, \
- struct device_attribute *attr, \
- char *buf) \
-{ \
- struct _feat_def *_feat = container_of(dev, struct _feat_def, dev); \
- \
- if (atomic_read(&_feat->status) & ZFCP_STATUS_COMMON_ERP_FAILED) \
- return sprintf(buf, "1\n"); \
- else \
- return sprintf(buf, "0\n"); \
-} \
-static ssize_t zfcp_sysfs_##_feat##_failed_store(struct device *dev, \
- struct device_attribute *attr,\
- const char *buf, size_t count)\
-{ \
- struct _feat_def *_feat = container_of(dev, struct _feat_def, dev); \
- unsigned long val; \
- int retval = 0; \
- \
- if (!(_feat && get_device(&_feat->dev))) \
- return -EBUSY; \
- \
- if (strict_strtoul(buf, 0, &val) || val != 0) { \
- retval = -EINVAL; \
- goto out; \
- } \
- \
- zfcp_erp_modify_##_feat##_status(_feat, _mod_id, NULL, \
- ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET);\
- zfcp_erp_##_feat##_reopen(_feat, ZFCP_STATUS_COMMON_ERP_FAILED, \
- _reopen_id, NULL); \
- zfcp_erp_wait(_adapter); \
-out: \
- put_device(&_feat->dev); \
- return retval ? retval : (ssize_t) count; \
-} \
-static ZFCP_DEV_ATTR(_feat, failed, S_IWUSR | S_IRUGO, \
- zfcp_sysfs_##_feat##_failed_show, \
- zfcp_sysfs_##_feat##_failed_store);
+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,
+ char *buf)
+{
+ struct zfcp_port *port = container_of(dev, struct zfcp_port, dev);
+
+ if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
+ return sprintf(buf, "1\n");
+
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t zfcp_sysfs_port_failed_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct zfcp_port *port = container_of(dev, struct zfcp_port, dev);
+ unsigned long val;
+
+ 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");
+ zfcp_erp_wait(port->adapter);
+
+ return count;
+}
+static ZFCP_DEV_ATTR(port, failed, S_IWUSR | S_IRUGO,
+ zfcp_sysfs_port_failed_show,
+ zfcp_sysfs_port_failed_store);
+
+static ssize_t zfcp_sysfs_unit_failed_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct zfcp_unit *unit = container_of(dev, struct zfcp_unit, dev);
+ struct scsi_device *sdev;
+ unsigned int status, failed = 1;
+
+ sdev = zfcp_unit_sdev(unit);
+ if (sdev) {
+ status = atomic_read(&sdev_to_zfcp(sdev)->status);
+ failed = status & ZFCP_STATUS_COMMON_ERP_FAILED ? 1 : 0;
+ scsi_device_put(sdev);
+ }
+
+ return sprintf(buf, "%d\n", failed);
+}
+
+static ssize_t zfcp_sysfs_unit_failed_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct zfcp_unit *unit = container_of(dev, struct zfcp_unit, dev);
+ unsigned long val;
+ struct scsi_device *sdev;
-ZFCP_SYSFS_FAILED(zfcp_port, port, port->adapter, "sypfai1", "sypfai2");
-ZFCP_SYSFS_FAILED(zfcp_unit, unit, unit->port->adapter, "syufai1", "syufai2");
+ 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");
+ zfcp_erp_wait(unit->port->adapter);
+ } else
+ zfcp_unit_scsi_scan(unit);
+
+ return count;
+}
+static ZFCP_DEV_ATTR(unit, failed, S_IWUSR | S_IRUGO,
+ zfcp_sysfs_unit_failed_show,
+ zfcp_sysfs_unit_failed_store);
static ssize_t zfcp_sysfs_adapter_failed_show(struct device *dev,
struct device_attribute *attr,
@@ -158,15 +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_modify_adapter_status(adapter, "syafai1", NULL,
- ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET);
+ 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);
@@ -196,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)
@@ -209,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);
@@ -218,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;
@@ -257,28 +306,17 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev,
const char *buf, size_t count)
{
struct zfcp_port *port = container_of(dev, struct zfcp_port, dev);
- struct zfcp_unit *unit;
u64 fcp_lun;
- int retval = -EINVAL;
-
- if (!(port && get_device(&port->dev)))
- return -EBUSY;
+ int retval;
- if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun))
- goto out;
+ if (kstrtoull(buf, 0, (unsigned long long *) &fcp_lun))
+ return -EINVAL;
- unit = zfcp_unit_enqueue(port, fcp_lun);
- if (IS_ERR(unit))
- goto out;
- else
- retval = 0;
+ retval = zfcp_unit_add(port, fcp_lun);
+ if (retval)
+ return retval;
- zfcp_erp_unit_reopen(unit, 0, "syuas_1", NULL);
- zfcp_erp_wait(unit->port->adapter);
- flush_work(&unit->scsi_work);
-out:
- put_device(&port->dev);
- return retval ? retval : (ssize_t) count;
+ return count;
}
static DEVICE_ATTR(unit_add, S_IWUSR, NULL, zfcp_sysfs_unit_add_store);
@@ -287,36 +325,15 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev,
const char *buf, size_t count)
{
struct zfcp_port *port = container_of(dev, struct zfcp_port, dev);
- struct zfcp_unit *unit;
u64 fcp_lun;
- int retval = -EINVAL;
- if (!(port && get_device(&port->dev)))
- return -EBUSY;
+ if (kstrtoull(buf, 0, (unsigned long long *) &fcp_lun))
+ return -EINVAL;
- if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun))
- goto out;
+ if (zfcp_unit_remove(port, fcp_lun))
+ return -EINVAL;
- unit = zfcp_get_unit_by_lun(port, fcp_lun);
- if (!unit)
- goto out;
- else
- retval = 0;
-
- /* wait for possible timeout during SCSI probe */
- flush_work(&unit->scsi_work);
-
- write_lock_irq(&port->unit_list_lock);
- list_del(&unit->list);
- write_unlock_irq(&port->unit_list_lock);
-
- put_device(&unit->dev);
-
- zfcp_erp_unit_shutdown(unit, 0, "syurs_1", NULL);
- zfcp_device_unregister(&unit->dev, &zfcp_sysfs_unit_attrs);
-out:
- put_device(&port->dev);
- return retval ? retval : (ssize_t) count;
+ return count;
}
static DEVICE_ATTR(unit_remove, S_IWUSR, NULL, zfcp_sysfs_unit_remove_store);
@@ -329,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,
@@ -346,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 \
@@ -357,9 +377,9 @@ zfcp_sysfs_unit_##_name##_latency_show(struct device *dev, \
struct device_attribute *attr, \
char *buf) { \
struct scsi_device *sdev = to_scsi_device(dev); \
- struct zfcp_unit *unit = sdev->hostdata; \
- struct zfcp_latencies *lat = &unit->latencies; \
- struct zfcp_adapter *adapter = unit->port->adapter; \
+ struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); \
+ struct zfcp_latencies *lat = &zfcp_sdev->latencies; \
+ struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; \
unsigned long long fsum, fmin, fmax, csum, cmin, cmax, cc; \
\
spin_lock_bh(&lat->lock); \
@@ -388,8 +408,8 @@ zfcp_sysfs_unit_##_name##_latency_store(struct device *dev, \
const char *buf, size_t count) \
{ \
struct scsi_device *sdev = to_scsi_device(dev); \
- struct zfcp_unit *unit = sdev->hostdata; \
- struct zfcp_latencies *lat = &unit->latencies; \
+ struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); \
+ struct zfcp_latencies *lat = &zfcp_sdev->latencies; \
unsigned long flags; \
\
spin_lock_irqsave(&lat->lock, flags); \
@@ -417,19 +437,28 @@ static ssize_t zfcp_sysfs_scsi_##_name##_show(struct device *dev, \
struct device_attribute *attr,\
char *buf) \
{ \
- struct scsi_device *sdev = to_scsi_device(dev); \
- struct zfcp_unit *unit = sdev->hostdata; \
+ struct scsi_device *sdev = to_scsi_device(dev); \
+ struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); \
+ struct zfcp_port *port = zfcp_sdev->port; \
\
return sprintf(buf, _format, _value); \
} \
static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_scsi_##_name##_show, NULL);
ZFCP_DEFINE_SCSI_ATTR(hba_id, "%s\n",
- dev_name(&unit->port->adapter->ccw_device->dev));
+ dev_name(&port->adapter->ccw_device->dev));
ZFCP_DEFINE_SCSI_ATTR(wwpn, "0x%016llx\n",
- (unsigned long long) unit->port->wwpn);
-ZFCP_DEFINE_SCSI_ATTR(fcp_lun, "0x%016llx\n",
- (unsigned long long) unit->fcp_lun);
+ (unsigned long long) port->wwpn);
+
+static ssize_t zfcp_sysfs_scsi_fcp_lun_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+
+ return sprintf(buf, "0x%016llx\n", zfcp_scsi_dev_lun(sdev));
+}
+static DEVICE_ATTR(fcp_lun, S_IRUGO, zfcp_sysfs_scsi_fcp_lun_show, NULL);
struct device_attribute *zfcp_sysfs_sdev_attrs[] = {
&dev_attr_fcp_lun,
diff --git a/drivers/s390/scsi/zfcp_unit.c b/drivers/s390/scsi/zfcp_unit.c
new file mode 100644
index 00000000000..39f5446f721
--- /dev/null
+++ b/drivers/s390/scsi/zfcp_unit.c
@@ -0,0 +1,255 @@
+/*
+ * zfcp device driver
+ *
+ * Tracking of manually configured LUNs and helper functions to
+ * register the LUNs with the SCSI midlayer.
+ *
+ * Copyright IBM Corp. 2010
+ */
+
+#include "zfcp_def.h"
+#include "zfcp_ext.h"
+
+/**
+ * zfcp_unit_scsi_scan - Register LUN with SCSI midlayer
+ * @unit: The zfcp LUN/unit to register
+ *
+ * When the SCSI midlayer is not allowed to automatically scan and
+ * attach SCSI devices, zfcp has to register the single devices with
+ * the SCSI midlayer.
+ */
+void zfcp_unit_scsi_scan(struct zfcp_unit *unit)
+{
+ struct fc_rport *rport = unit->port->rport;
+ unsigned int lun;
+
+ lun = scsilun_to_int((struct scsi_lun *) &unit->fcp_lun);
+
+ if (rport && rport->port_state == FC_PORTSTATE_ONLINE)
+ scsi_scan_target(&rport->dev, 0, rport->scsi_target_id, lun, 1);
+}
+
+static void zfcp_unit_scsi_scan_work(struct work_struct *work)
+{
+ struct zfcp_unit *unit = container_of(work, struct zfcp_unit,
+ scsi_work);
+
+ zfcp_unit_scsi_scan(unit);
+ put_device(&unit->dev);
+}
+
+/**
+ * zfcp_unit_queue_scsi_scan - Register configured units on port
+ * @port: The zfcp_port where to register units
+ *
+ * After opening a port, all units configured on this port have to be
+ * registered with the SCSI midlayer. This function should be called
+ * after calling fc_remote_port_add, so that the fc_rport is already
+ * ONLINE and the call to scsi_scan_target runs the same way as the
+ * call in the FC transport class.
+ */
+void zfcp_unit_queue_scsi_scan(struct zfcp_port *port)
+{
+ struct zfcp_unit *unit;
+
+ read_lock_irq(&port->unit_list_lock);
+ list_for_each_entry(unit, &port->unit_list, list) {
+ get_device(&unit->dev);
+ if (scsi_queue_work(port->adapter->scsi_host,
+ &unit->scsi_work) <= 0)
+ put_device(&unit->dev);
+ }
+ read_unlock_irq(&port->unit_list_lock);
+}
+
+static struct zfcp_unit *_zfcp_unit_find(struct zfcp_port *port, u64 fcp_lun)
+{
+ struct zfcp_unit *unit;
+
+ list_for_each_entry(unit, &port->unit_list, list)
+ if (unit->fcp_lun == fcp_lun) {
+ get_device(&unit->dev);
+ return unit;
+ }
+
+ return NULL;
+}
+
+/**
+ * zfcp_unit_find - Find and return zfcp_unit with specified FCP LUN
+ * @port: zfcp_port where to look for the unit
+ * @fcp_lun: 64 Bit FCP LUN used to identify the zfcp_unit
+ *
+ * If zfcp_unit is found, a reference is acquired that has to be
+ * released later.
+ *
+ * Returns: Pointer to the zfcp_unit, or NULL if there is no zfcp_unit
+ * with the specified FCP LUN.
+ */
+struct zfcp_unit *zfcp_unit_find(struct zfcp_port *port, u64 fcp_lun)
+{
+ struct zfcp_unit *unit;
+
+ read_lock_irq(&port->unit_list_lock);
+ unit = _zfcp_unit_find(port, fcp_lun);
+ read_unlock_irq(&port->unit_list_lock);
+ return unit;
+}
+
+/**
+ * zfcp_unit_release - Drop reference to zfcp_port and free memory of zfcp_unit.
+ * @dev: pointer to device in zfcp_unit
+ */
+static void zfcp_unit_release(struct device *dev)
+{
+ struct zfcp_unit *unit = container_of(dev, struct zfcp_unit, dev);
+
+ atomic_dec(&unit->port->units);
+ kfree(unit);
+}
+
+/**
+ * zfcp_unit_enqueue - enqueue unit to unit list of a port.
+ * @port: pointer to port where unit is added
+ * @fcp_lun: FCP LUN of unit to be enqueued
+ * Returns: 0 success
+ *
+ * Sets up some unit internal structures and creates sysfs entry.
+ */
+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);
+ retval = -EEXIST;
+ goto out;
+ }
+
+ unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL);
+ 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);
+ retval = -ENOMEM;
+ goto out;
+ }
+
+ if (device_register(&unit->dev)) {
+ put_device(&unit->dev);
+ retval = -ENOMEM;
+ goto out;
+ }
+
+ 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);
+ write_unlock_irq(&port->unit_list_lock);
+
+ zfcp_unit_scsi_scan(unit);
+
+out:
+ mutex_unlock(&zfcp_sysfs_port_units_mutex);
+ return retval;
+}
+
+/**
+ * zfcp_unit_sdev - Return SCSI device for zfcp_unit
+ * @unit: The zfcp_unit where to get the SCSI device for
+ *
+ * Returns: scsi_device pointer on success, NULL if there is no SCSI
+ * device for this zfcp_unit
+ *
+ * On success, the caller also holds a reference to the SCSI device
+ * that must be released with scsi_device_put.
+ */
+struct scsi_device *zfcp_unit_sdev(struct zfcp_unit *unit)
+{
+ struct Scsi_Host *shost;
+ struct zfcp_port *port;
+ unsigned int lun;
+
+ lun = scsilun_to_int((struct scsi_lun *) &unit->fcp_lun);
+ port = unit->port;
+ shost = port->adapter->scsi_host;
+ return scsi_device_lookup(shost, 0, port->starget_id, lun);
+}
+
+/**
+ * zfcp_unit_sdev_status - Return zfcp LUN status for SCSI device
+ * @unit: The unit to lookup the SCSI device for
+ *
+ * Returns the zfcp LUN status field of the SCSI device if the SCSI device
+ * for the zfcp_unit exists, 0 otherwise.
+ */
+unsigned int zfcp_unit_sdev_status(struct zfcp_unit *unit)
+{
+ unsigned int status = 0;
+ struct scsi_device *sdev;
+ struct zfcp_scsi_dev *zfcp_sdev;
+
+ sdev = zfcp_unit_sdev(unit);
+ if (sdev) {
+ zfcp_sdev = sdev_to_zfcp(sdev);
+ status = atomic_read(&zfcp_sdev->status);
+ scsi_device_put(sdev);
+ }
+
+ return status;
+}
+
+/**
+ * zfcp_unit_remove - Remove entry from list of configured units
+ * @port: The port where to remove the unit from the configuration
+ * @fcp_lun: The 64 bit LUN of the unit to remove
+ *
+ * Returns: -EINVAL if a unit with the specified LUN does not exist,
+ * 0 on success.
+ */
+int zfcp_unit_remove(struct zfcp_port *port, u64 fcp_lun)
+{
+ struct zfcp_unit *unit;
+ struct scsi_device *sdev;
+
+ write_lock_irq(&port->unit_list_lock);
+ unit = _zfcp_unit_find(port, fcp_lun);
+ if (unit)
+ list_del(&unit->list);
+ write_unlock_irq(&port->unit_list_lock);
+
+ if (!unit)
+ return -EINVAL;
+
+ sdev = zfcp_unit_sdev(unit);
+ if (sdev) {
+ scsi_remove_device(sdev);
+ scsi_device_put(sdev);
+ }
+
+ put_device(&unit->dev);
+
+ device_unregister(&unit->dev);
+
+ return 0;
+}