mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 11:11:45 -04:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (222 commits) [SCSI] zfcp: Remove flag ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP [SCSI] zfcp: Activate fc4s attributes for zfcp in FC transport class [SCSI] zfcp: Block scsi_eh thread for rport state BLOCKED [SCSI] zfcp: Update FSF error reporting [SCSI] zfcp: Improve ELS ADISC handling [SCSI] zfcp: Simplify handling of ct and els requests [SCSI] zfcp: Remove ZFCP_DID_MASK [SCSI] zfcp: Move WKA port to zfcp FC code [SCSI] zfcp: Use common code definitions for FC CT structs [SCSI] zfcp: Use common code definitions for FC ELS structs [SCSI] zfcp: Update FCP protocol related code [SCSI] zfcp: Dont fail SCSI commands when transitioning to blocked fc_rport [SCSI] zfcp: Assign scheduled work to driver queue [SCSI] zfcp: Remove STATUS_COMMON_REMOVE flag as it is not required anymore [SCSI] zfcp: Implement module unloading [SCSI] zfcp: Merge trace code for fsf requests in one function [SCSI] zfcp: Access ports and units with container_of in sysfs code [SCSI] zfcp: Remove suspend callback [SCSI] zfcp: Remove global config_mutex [SCSI] zfcp: Replace local reference counting with common kref ...
This commit is contained in:
commit
382f51fe2f
235 changed files with 27284 additions and 7716 deletions
|
|
@ -31,6 +31,7 @@
|
|||
#include <linux/miscdevice.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include "zfcp_ext.h"
|
||||
#include "zfcp_fc.h"
|
||||
|
||||
#define ZFCP_BUS_ID_SIZE 20
|
||||
|
||||
|
|
@ -80,48 +81,40 @@ int zfcp_reqlist_isempty(struct zfcp_adapter *adapter)
|
|||
|
||||
static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun)
|
||||
{
|
||||
struct ccw_device *ccwdev;
|
||||
struct ccw_device *cdev;
|
||||
struct zfcp_adapter *adapter;
|
||||
struct zfcp_port *port;
|
||||
struct zfcp_unit *unit;
|
||||
|
||||
ccwdev = get_ccwdev_by_busid(&zfcp_ccw_driver, busid);
|
||||
if (!ccwdev)
|
||||
cdev = get_ccwdev_by_busid(&zfcp_ccw_driver, busid);
|
||||
if (!cdev)
|
||||
return;
|
||||
|
||||
if (ccw_device_set_online(ccwdev))
|
||||
goto out_ccwdev;
|
||||
if (ccw_device_set_online(cdev))
|
||||
goto out_ccw_device;
|
||||
|
||||
mutex_lock(&zfcp_data.config_mutex);
|
||||
adapter = dev_get_drvdata(&ccwdev->dev);
|
||||
adapter = zfcp_ccw_adapter_by_cdev(cdev);
|
||||
if (!adapter)
|
||||
goto out_unlock;
|
||||
zfcp_adapter_get(adapter);
|
||||
goto out_ccw_device;
|
||||
|
||||
port = zfcp_get_port_by_wwpn(adapter, wwpn);
|
||||
if (!port)
|
||||
goto out_port;
|
||||
|
||||
zfcp_port_get(port);
|
||||
unit = zfcp_unit_enqueue(port, lun);
|
||||
if (IS_ERR(unit))
|
||||
goto out_unit;
|
||||
mutex_unlock(&zfcp_data.config_mutex);
|
||||
|
||||
zfcp_erp_unit_reopen(unit, 0, "auidc_1", NULL);
|
||||
zfcp_erp_wait(adapter);
|
||||
flush_work(&unit->scsi_work);
|
||||
|
||||
mutex_lock(&zfcp_data.config_mutex);
|
||||
zfcp_unit_put(unit);
|
||||
out_unit:
|
||||
zfcp_port_put(port);
|
||||
put_device(&port->sysfs_device);
|
||||
out_port:
|
||||
zfcp_adapter_put(adapter);
|
||||
out_unlock:
|
||||
mutex_unlock(&zfcp_data.config_mutex);
|
||||
out_ccwdev:
|
||||
put_device(&ccwdev->dev);
|
||||
zfcp_ccw_adapter_put(adapter);
|
||||
out_ccw_device:
|
||||
put_device(&cdev->dev);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -167,7 +160,7 @@ static int __init zfcp_module_init(void)
|
|||
int retval = -ENOMEM;
|
||||
|
||||
zfcp_data.gpn_ft_cache = zfcp_cache_hw_align("zfcp_gpn",
|
||||
sizeof(struct ct_iu_gpn_ft_req));
|
||||
sizeof(struct zfcp_fc_gpn_ft_req));
|
||||
if (!zfcp_data.gpn_ft_cache)
|
||||
goto out;
|
||||
|
||||
|
|
@ -182,12 +175,14 @@ static int __init zfcp_module_init(void)
|
|||
goto out_sr_cache;
|
||||
|
||||
zfcp_data.gid_pn_cache = zfcp_cache_hw_align("zfcp_gid",
|
||||
sizeof(struct zfcp_gid_pn_data));
|
||||
sizeof(struct zfcp_fc_gid_pn));
|
||||
if (!zfcp_data.gid_pn_cache)
|
||||
goto out_gid_cache;
|
||||
|
||||
mutex_init(&zfcp_data.config_mutex);
|
||||
rwlock_init(&zfcp_data.config_lock);
|
||||
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 =
|
||||
fc_attach_transport(&zfcp_transport_functions);
|
||||
|
|
@ -200,7 +195,7 @@ static int __init zfcp_module_init(void)
|
|||
goto out_misc;
|
||||
}
|
||||
|
||||
retval = zfcp_ccw_register();
|
||||
retval = ccw_driver_register(&zfcp_ccw_driver);
|
||||
if (retval) {
|
||||
pr_err("The zfcp device driver could not register with "
|
||||
"the common I/O layer\n");
|
||||
|
|
@ -216,6 +211,8 @@ out_ccw_register:
|
|||
out_misc:
|
||||
fc_release_transport(zfcp_data.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);
|
||||
|
|
@ -229,6 +226,20 @@ out:
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
|
|
@ -238,12 +249,18 @@ module_init(zfcp_module_init);
|
|||
*/
|
||||
struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *port, u64 fcp_lun)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct zfcp_unit *unit;
|
||||
|
||||
list_for_each_entry(unit, &port->unit_list_head, list)
|
||||
if ((unit->fcp_lun == fcp_lun) &&
|
||||
!(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_REMOVE))
|
||||
return 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->sysfs_device))
|
||||
unit = NULL;
|
||||
read_unlock_irqrestore(&port->unit_list_lock, flags);
|
||||
return unit;
|
||||
}
|
||||
read_unlock_irqrestore(&port->unit_list_lock, flags);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -257,18 +274,35 @@ struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *port, u64 fcp_lun)
|
|||
struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *adapter,
|
||||
u64 wwpn)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct zfcp_port *port;
|
||||
|
||||
list_for_each_entry(port, &adapter->port_list_head, list)
|
||||
if ((port->wwpn == wwpn) &&
|
||||
!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE))
|
||||
read_lock_irqsave(&adapter->port_list_lock, flags);
|
||||
list_for_each_entry(port, &adapter->port_list, list)
|
||||
if (port->wwpn == wwpn) {
|
||||
if (!get_device(&port->sysfs_device))
|
||||
port = NULL;
|
||||
read_unlock_irqrestore(&adapter->port_list_lock, flags);
|
||||
return port;
|
||||
}
|
||||
read_unlock_irqrestore(&adapter->port_list_lock, flags);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void zfcp_sysfs_unit_release(struct device *dev)
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
kfree(container_of(dev, struct zfcp_unit, sysfs_device));
|
||||
struct zfcp_unit *unit = container_of(dev, struct zfcp_unit,
|
||||
sysfs_device);
|
||||
|
||||
put_device(&unit->port->sysfs_device);
|
||||
kfree(unit);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -276,43 +310,40 @@ static void zfcp_sysfs_unit_release(struct device *dev)
|
|||
* @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
|
||||
* Locks: config_mutex must be held to serialize changes to the unit list
|
||||
*
|
||||
* Sets up some unit internal structures and creates sysfs entry.
|
||||
*/
|
||||
struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun)
|
||||
{
|
||||
struct zfcp_unit *unit;
|
||||
int retval = -ENOMEM;
|
||||
|
||||
read_lock_irq(&zfcp_data.config_lock);
|
||||
if (zfcp_get_unit_by_lun(port, fcp_lun)) {
|
||||
read_unlock_irq(&zfcp_data.config_lock);
|
||||
return ERR_PTR(-EINVAL);
|
||||
get_device(&port->sysfs_device);
|
||||
|
||||
unit = zfcp_get_unit_by_lun(port, fcp_lun);
|
||||
if (unit) {
|
||||
put_device(&unit->sysfs_device);
|
||||
retval = -EEXIST;
|
||||
goto err_out;
|
||||
}
|
||||
read_unlock_irq(&zfcp_data.config_lock);
|
||||
|
||||
unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL);
|
||||
if (!unit)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
atomic_set(&unit->refcount, 0);
|
||||
init_waitqueue_head(&unit->remove_wq);
|
||||
INIT_WORK(&unit->scsi_work, zfcp_scsi_scan);
|
||||
goto err_out;
|
||||
|
||||
unit->port = port;
|
||||
unit->fcp_lun = fcp_lun;
|
||||
unit->sysfs_device.parent = &port->sysfs_device;
|
||||
unit->sysfs_device.release = zfcp_unit_release;
|
||||
|
||||
if (dev_set_name(&unit->sysfs_device, "0x%016llx",
|
||||
(unsigned long long) fcp_lun)) {
|
||||
kfree(unit);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
goto err_out;
|
||||
}
|
||||
unit->sysfs_device.parent = &port->sysfs_device;
|
||||
unit->sysfs_device.release = zfcp_sysfs_unit_release;
|
||||
dev_set_drvdata(&unit->sysfs_device, unit);
|
||||
retval = -EINVAL;
|
||||
|
||||
/* mark unit unusable as long as sysfs registration is not complete */
|
||||
atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status);
|
||||
INIT_WORK(&unit->scsi_work, zfcp_scsi_scan);
|
||||
|
||||
spin_lock_init(&unit->latencies.lock);
|
||||
unit->latencies.write.channel.min = 0xFFFFFFFF;
|
||||
|
|
@ -324,50 +355,30 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun)
|
|||
|
||||
if (device_register(&unit->sysfs_device)) {
|
||||
put_device(&unit->sysfs_device);
|
||||
return ERR_PTR(-EINVAL);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if (sysfs_create_group(&unit->sysfs_device.kobj,
|
||||
&zfcp_sysfs_unit_attrs)) {
|
||||
device_unregister(&unit->sysfs_device);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
&zfcp_sysfs_unit_attrs))
|
||||
goto err_out_put;
|
||||
|
||||
zfcp_unit_get(unit);
|
||||
write_lock_irq(&port->unit_list_lock);
|
||||
list_add_tail(&unit->list, &port->unit_list);
|
||||
write_unlock_irq(&port->unit_list_lock);
|
||||
|
||||
write_lock_irq(&zfcp_data.config_lock);
|
||||
list_add_tail(&unit->list, &port->unit_list_head);
|
||||
atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status);
|
||||
atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status);
|
||||
|
||||
write_unlock_irq(&zfcp_data.config_lock);
|
||||
|
||||
zfcp_port_get(port);
|
||||
|
||||
return unit;
|
||||
}
|
||||
|
||||
/**
|
||||
* zfcp_unit_dequeue - dequeue unit
|
||||
* @unit: pointer to zfcp_unit
|
||||
*
|
||||
* waits until all work is done on unit and removes it then from the unit->list
|
||||
* of the associated port.
|
||||
*/
|
||||
void zfcp_unit_dequeue(struct zfcp_unit *unit)
|
||||
{
|
||||
wait_event(unit->remove_wq, atomic_read(&unit->refcount) == 0);
|
||||
write_lock_irq(&zfcp_data.config_lock);
|
||||
list_del(&unit->list);
|
||||
write_unlock_irq(&zfcp_data.config_lock);
|
||||
zfcp_port_put(unit->port);
|
||||
sysfs_remove_group(&unit->sysfs_device.kobj, &zfcp_sysfs_unit_attrs);
|
||||
err_out_put:
|
||||
device_unregister(&unit->sysfs_device);
|
||||
err_out:
|
||||
put_device(&port->sysfs_device);
|
||||
return ERR_PTR(retval);
|
||||
}
|
||||
|
||||
static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter)
|
||||
{
|
||||
/* must only be called with zfcp_data.config_mutex taken */
|
||||
adapter->pool.erp_req =
|
||||
mempool_create_kmalloc_pool(1, sizeof(struct zfcp_fsf_req));
|
||||
if (!adapter->pool.erp_req)
|
||||
|
|
@ -405,9 +416,9 @@ static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter)
|
|||
if (!adapter->pool.status_read_data)
|
||||
return -ENOMEM;
|
||||
|
||||
adapter->pool.gid_pn_data =
|
||||
adapter->pool.gid_pn =
|
||||
mempool_create_slab_pool(1, zfcp_data.gid_pn_cache);
|
||||
if (!adapter->pool.gid_pn_data)
|
||||
if (!adapter->pool.gid_pn)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
|
|
@ -415,7 +426,6 @@ static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter)
|
|||
|
||||
static void zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter)
|
||||
{
|
||||
/* zfcp_data.config_mutex must be held */
|
||||
if (adapter->pool.erp_req)
|
||||
mempool_destroy(adapter->pool.erp_req);
|
||||
if (adapter->pool.scsi_req)
|
||||
|
|
@ -428,8 +438,8 @@ static void zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter)
|
|||
mempool_destroy(adapter->pool.status_read_req);
|
||||
if (adapter->pool.status_read_data)
|
||||
mempool_destroy(adapter->pool.status_read_data);
|
||||
if (adapter->pool.gid_pn_data)
|
||||
mempool_destroy(adapter->pool.gid_pn_data);
|
||||
if (adapter->pool.gid_pn)
|
||||
mempool_destroy(adapter->pool.gid_pn);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -497,53 +507,56 @@ static void zfcp_destroy_adapter_work_queue(struct zfcp_adapter *adapter)
|
|||
* zfcp_adapter_enqueue - enqueue a new adapter to the list
|
||||
* @ccw_device: pointer to the struct cc_device
|
||||
*
|
||||
* Returns: 0 if a new adapter was successfully enqueued
|
||||
* -ENOMEM if alloc failed
|
||||
* Returns: struct zfcp_adapter*
|
||||
* Enqueues an adapter at the end of the adapter list in the driver data.
|
||||
* All adapter internal structures are set up.
|
||||
* Proc-fs entries are also created.
|
||||
* locks: config_mutex must be held to serialize changes to the adapter list
|
||||
*/
|
||||
int zfcp_adapter_enqueue(struct ccw_device *ccw_device)
|
||||
struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *ccw_device)
|
||||
{
|
||||
struct zfcp_adapter *adapter;
|
||||
|
||||
/*
|
||||
* Note: It is safe to release the list_lock, as any list changes
|
||||
* are protected by the config_mutex, which must be held to get here
|
||||
*/
|
||||
if (!get_device(&ccw_device->dev))
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
adapter = kzalloc(sizeof(struct zfcp_adapter), GFP_KERNEL);
|
||||
if (!adapter)
|
||||
return -ENOMEM;
|
||||
if (!adapter) {
|
||||
put_device(&ccw_device->dev);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
kref_init(&adapter->ref);
|
||||
|
||||
ccw_device->handler = NULL;
|
||||
adapter->ccw_device = ccw_device;
|
||||
atomic_set(&adapter->refcount, 0);
|
||||
|
||||
INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler);
|
||||
INIT_WORK(&adapter->scan_work, zfcp_fc_scan_ports);
|
||||
|
||||
if (zfcp_qdio_setup(adapter))
|
||||
goto qdio_failed;
|
||||
goto failed;
|
||||
|
||||
if (zfcp_allocate_low_mem_buffers(adapter))
|
||||
goto low_mem_buffers_failed;
|
||||
goto failed;
|
||||
|
||||
if (zfcp_reqlist_alloc(adapter))
|
||||
goto low_mem_buffers_failed;
|
||||
goto failed;
|
||||
|
||||
if (zfcp_dbf_adapter_register(adapter))
|
||||
goto debug_register_failed;
|
||||
goto failed;
|
||||
|
||||
if (zfcp_setup_adapter_work_queue(adapter))
|
||||
goto work_queue_failed;
|
||||
goto failed;
|
||||
|
||||
if (zfcp_fc_gs_setup(adapter))
|
||||
goto generic_services_failed;
|
||||
goto failed;
|
||||
|
||||
rwlock_init(&adapter->port_list_lock);
|
||||
INIT_LIST_HEAD(&adapter->port_list);
|
||||
|
||||
init_waitqueue_head(&adapter->remove_wq);
|
||||
init_waitqueue_head(&adapter->erp_ready_wq);
|
||||
init_waitqueue_head(&adapter->erp_done_wqh);
|
||||
|
||||
INIT_LIST_HEAD(&adapter->port_list_head);
|
||||
INIT_LIST_HEAD(&adapter->erp_ready_head);
|
||||
INIT_LIST_HEAD(&adapter->erp_running_head);
|
||||
|
||||
|
|
@ -553,83 +566,85 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device)
|
|||
rwlock_init(&adapter->abort_lock);
|
||||
|
||||
if (zfcp_erp_thread_setup(adapter))
|
||||
goto erp_thread_failed;
|
||||
|
||||
INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler);
|
||||
INIT_WORK(&adapter->scan_work, _zfcp_fc_scan_ports_later);
|
||||
goto failed;
|
||||
|
||||
adapter->service_level.seq_print = zfcp_print_sl;
|
||||
|
||||
/* mark adapter unusable as long as sysfs registration is not complete */
|
||||
atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status);
|
||||
|
||||
dev_set_drvdata(&ccw_device->dev, adapter);
|
||||
|
||||
if (sysfs_create_group(&ccw_device->dev.kobj,
|
||||
&zfcp_sysfs_adapter_attrs))
|
||||
goto sysfs_failed;
|
||||
|
||||
atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status);
|
||||
goto failed;
|
||||
|
||||
if (!zfcp_adapter_scsi_register(adapter))
|
||||
return 0;
|
||||
return adapter;
|
||||
|
||||
sysfs_failed:
|
||||
zfcp_erp_thread_kill(adapter);
|
||||
erp_thread_failed:
|
||||
zfcp_fc_gs_destroy(adapter);
|
||||
generic_services_failed:
|
||||
failed:
|
||||
zfcp_adapter_unregister(adapter);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
void zfcp_adapter_unregister(struct zfcp_adapter *adapter)
|
||||
{
|
||||
struct ccw_device *cdev = adapter->ccw_device;
|
||||
|
||||
cancel_work_sync(&adapter->scan_work);
|
||||
cancel_work_sync(&adapter->stat_work);
|
||||
zfcp_destroy_adapter_work_queue(adapter);
|
||||
work_queue_failed:
|
||||
|
||||
zfcp_fc_wka_ports_force_offline(adapter->gs);
|
||||
zfcp_adapter_scsi_unregister(adapter);
|
||||
sysfs_remove_group(&cdev->dev.kobj, &zfcp_sysfs_adapter_attrs);
|
||||
|
||||
zfcp_erp_thread_kill(adapter);
|
||||
zfcp_dbf_adapter_unregister(adapter->dbf);
|
||||
debug_register_failed:
|
||||
dev_set_drvdata(&ccw_device->dev, NULL);
|
||||
kfree(adapter->req_list);
|
||||
low_mem_buffers_failed:
|
||||
zfcp_free_low_mem_buffers(adapter);
|
||||
qdio_failed:
|
||||
zfcp_qdio_destroy(adapter->qdio);
|
||||
kfree(adapter);
|
||||
return -ENOMEM;
|
||||
|
||||
zfcp_ccw_adapter_put(adapter); /* final put to release */
|
||||
}
|
||||
|
||||
/**
|
||||
* zfcp_adapter_dequeue - remove the adapter from the resource list
|
||||
* @adapter: pointer to struct zfcp_adapter which should be removed
|
||||
* zfcp_adapter_release - remove the adapter from the resource list
|
||||
* @ref: pointer to struct kref
|
||||
* locks: adapter list write lock is assumed to be held by caller
|
||||
*/
|
||||
void zfcp_adapter_dequeue(struct zfcp_adapter *adapter)
|
||||
void zfcp_adapter_release(struct kref *ref)
|
||||
{
|
||||
int retval = 0;
|
||||
unsigned long flags;
|
||||
struct zfcp_adapter *adapter = container_of(ref, struct zfcp_adapter,
|
||||
ref);
|
||||
struct ccw_device *cdev = adapter->ccw_device;
|
||||
|
||||
cancel_work_sync(&adapter->stat_work);
|
||||
zfcp_fc_wka_ports_force_offline(adapter->gs);
|
||||
sysfs_remove_group(&adapter->ccw_device->dev.kobj,
|
||||
&zfcp_sysfs_adapter_attrs);
|
||||
dev_set_drvdata(&adapter->ccw_device->dev, NULL);
|
||||
/* sanity check: no pending FSF requests */
|
||||
spin_lock_irqsave(&adapter->req_list_lock, flags);
|
||||
retval = zfcp_reqlist_isempty(adapter);
|
||||
spin_unlock_irqrestore(&adapter->req_list_lock, flags);
|
||||
if (!retval)
|
||||
return;
|
||||
|
||||
zfcp_fc_gs_destroy(adapter);
|
||||
zfcp_erp_thread_kill(adapter);
|
||||
zfcp_destroy_adapter_work_queue(adapter);
|
||||
zfcp_dbf_adapter_unregister(adapter->dbf);
|
||||
zfcp_free_low_mem_buffers(adapter);
|
||||
zfcp_qdio_destroy(adapter->qdio);
|
||||
kfree(adapter->req_list);
|
||||
kfree(adapter->fc_stats);
|
||||
kfree(adapter->stats_reset_data);
|
||||
kfree(adapter);
|
||||
put_device(&cdev->dev);
|
||||
}
|
||||
|
||||
static void zfcp_sysfs_port_release(struct device *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)
|
||||
{
|
||||
kfree(container_of(dev, struct zfcp_port, sysfs_device));
|
||||
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,
|
||||
sysfs_device);
|
||||
|
||||
zfcp_ccw_adapter_put(port->adapter);
|
||||
kfree(port);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -639,7 +654,6 @@ static void zfcp_sysfs_port_release(struct device *dev)
|
|||
* @status: initial status for the port
|
||||
* @d_id: destination id of the remote port to be enqueued
|
||||
* Returns: pointer to enqueued port on success, ERR_PTR on error
|
||||
* Locks: config_mutex must be held to serialize changes to the port list
|
||||
*
|
||||
* All port internal structures are set up and the sysfs entry is generated.
|
||||
* d_id is used to enqueue ports with a well known address like the Directory
|
||||
|
|
@ -649,20 +663,24 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,
|
|||
u32 status, u32 d_id)
|
||||
{
|
||||
struct zfcp_port *port;
|
||||
int retval = -ENOMEM;
|
||||
|
||||
read_lock_irq(&zfcp_data.config_lock);
|
||||
if (zfcp_get_port_by_wwpn(adapter, wwpn)) {
|
||||
read_unlock_irq(&zfcp_data.config_lock);
|
||||
return ERR_PTR(-EINVAL);
|
||||
kref_get(&adapter->ref);
|
||||
|
||||
port = zfcp_get_port_by_wwpn(adapter, wwpn);
|
||||
if (port) {
|
||||
put_device(&port->sysfs_device);
|
||||
retval = -EEXIST;
|
||||
goto err_out;
|
||||
}
|
||||
read_unlock_irq(&zfcp_data.config_lock);
|
||||
|
||||
port = kzalloc(sizeof(struct zfcp_port), GFP_KERNEL);
|
||||
if (!port)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
goto err_out;
|
||||
|
||||
rwlock_init(&port->unit_list_lock);
|
||||
INIT_LIST_HEAD(&port->unit_list);
|
||||
|
||||
init_waitqueue_head(&port->remove_wq);
|
||||
INIT_LIST_HEAD(&port->unit_list_head);
|
||||
INIT_WORK(&port->gid_pn_work, zfcp_fc_port_did_lookup);
|
||||
INIT_WORK(&port->test_link_work, zfcp_fc_link_test_work);
|
||||
INIT_WORK(&port->rport_work, zfcp_scsi_rport_work);
|
||||
|
|
@ -671,58 +689,38 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,
|
|||
port->d_id = d_id;
|
||||
port->wwpn = wwpn;
|
||||
port->rport_task = RPORT_NONE;
|
||||
|
||||
/* mark port unusable as long as sysfs registration is not complete */
|
||||
atomic_set_mask(status | ZFCP_STATUS_COMMON_REMOVE, &port->status);
|
||||
atomic_set(&port->refcount, 0);
|
||||
port->sysfs_device.parent = &adapter->ccw_device->dev;
|
||||
port->sysfs_device.release = zfcp_port_release;
|
||||
|
||||
if (dev_set_name(&port->sysfs_device, "0x%016llx",
|
||||
(unsigned long long)wwpn)) {
|
||||
kfree(port);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
goto err_out;
|
||||
}
|
||||
port->sysfs_device.parent = &adapter->ccw_device->dev;
|
||||
port->sysfs_device.release = zfcp_sysfs_port_release;
|
||||
dev_set_drvdata(&port->sysfs_device, port);
|
||||
retval = -EINVAL;
|
||||
|
||||
if (device_register(&port->sysfs_device)) {
|
||||
put_device(&port->sysfs_device);
|
||||
return ERR_PTR(-EINVAL);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if (sysfs_create_group(&port->sysfs_device.kobj,
|
||||
&zfcp_sysfs_port_attrs)) {
|
||||
device_unregister(&port->sysfs_device);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
&zfcp_sysfs_port_attrs))
|
||||
goto err_out_put;
|
||||
|
||||
zfcp_port_get(port);
|
||||
write_lock_irq(&adapter->port_list_lock);
|
||||
list_add_tail(&port->list, &adapter->port_list);
|
||||
write_unlock_irq(&adapter->port_list_lock);
|
||||
|
||||
write_lock_irq(&zfcp_data.config_lock);
|
||||
list_add_tail(&port->list, &adapter->port_list_head);
|
||||
atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status);
|
||||
atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &port->status);
|
||||
atomic_set_mask(status | ZFCP_STATUS_COMMON_RUNNING, &port->status);
|
||||
|
||||
write_unlock_irq(&zfcp_data.config_lock);
|
||||
|
||||
zfcp_adapter_get(adapter);
|
||||
return port;
|
||||
}
|
||||
|
||||
/**
|
||||
* zfcp_port_dequeue - dequeues a port from the port list of the adapter
|
||||
* @port: pointer to struct zfcp_port which should be removed
|
||||
*/
|
||||
void zfcp_port_dequeue(struct zfcp_port *port)
|
||||
{
|
||||
write_lock_irq(&zfcp_data.config_lock);
|
||||
list_del(&port->list);
|
||||
write_unlock_irq(&zfcp_data.config_lock);
|
||||
wait_event(port->remove_wq, atomic_read(&port->refcount) == 0);
|
||||
cancel_work_sync(&port->rport_work); /* usually not necessary */
|
||||
zfcp_adapter_put(port->adapter);
|
||||
sysfs_remove_group(&port->sysfs_device.kobj, &zfcp_sysfs_port_attrs);
|
||||
err_out_put:
|
||||
device_unregister(&port->sysfs_device);
|
||||
err_out:
|
||||
zfcp_ccw_adapter_put(adapter);
|
||||
return ERR_PTR(retval);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -13,28 +13,34 @@
|
|||
|
||||
#define ZFCP_MODEL_PRIV 0x4
|
||||
|
||||
static int zfcp_ccw_suspend(struct ccw_device *cdev)
|
||||
static DEFINE_SPINLOCK(zfcp_ccw_adapter_ref_lock);
|
||||
|
||||
struct zfcp_adapter *zfcp_ccw_adapter_by_cdev(struct ccw_device *cdev)
|
||||
{
|
||||
struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev);
|
||||
struct zfcp_adapter *adapter;
|
||||
unsigned long flags;
|
||||
|
||||
if (!adapter)
|
||||
return 0;
|
||||
spin_lock_irqsave(&zfcp_ccw_adapter_ref_lock, flags);
|
||||
adapter = dev_get_drvdata(&cdev->dev);
|
||||
if (adapter)
|
||||
kref_get(&adapter->ref);
|
||||
spin_unlock_irqrestore(&zfcp_ccw_adapter_ref_lock, flags);
|
||||
return adapter;
|
||||
}
|
||||
|
||||
mutex_lock(&zfcp_data.config_mutex);
|
||||
void zfcp_ccw_adapter_put(struct zfcp_adapter *adapter)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
zfcp_erp_adapter_shutdown(adapter, 0, "ccsusp1", NULL);
|
||||
zfcp_erp_wait(adapter);
|
||||
|
||||
mutex_unlock(&zfcp_data.config_mutex);
|
||||
|
||||
return 0;
|
||||
spin_lock_irqsave(&zfcp_ccw_adapter_ref_lock, flags);
|
||||
kref_put(&adapter->ref, zfcp_adapter_release);
|
||||
spin_unlock_irqrestore(&zfcp_ccw_adapter_ref_lock, flags);
|
||||
}
|
||||
|
||||
static int zfcp_ccw_activate(struct ccw_device *cdev)
|
||||
|
||||
{
|
||||
struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev);
|
||||
struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);
|
||||
|
||||
if (!adapter)
|
||||
return 0;
|
||||
|
|
@ -46,6 +52,8 @@ static int zfcp_ccw_activate(struct ccw_device *cdev)
|
|||
zfcp_erp_wait(adapter);
|
||||
flush_work(&adapter->scan_work);
|
||||
|
||||
zfcp_ccw_adapter_put(adapter);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -67,28 +75,28 @@ int zfcp_ccw_priv_sch(struct zfcp_adapter *adapter)
|
|||
|
||||
/**
|
||||
* zfcp_ccw_probe - probe function of zfcp driver
|
||||
* @ccw_device: pointer to belonging ccw device
|
||||
* @cdev: pointer to belonging ccw device
|
||||
*
|
||||
* This function gets called by the common i/o layer for each FCP
|
||||
* device found on the current system. This is only a stub to make cio
|
||||
* work: To only allocate adapter resources for devices actually used,
|
||||
* the allocation is deferred to the first call to ccw_set_online.
|
||||
*/
|
||||
static int zfcp_ccw_probe(struct ccw_device *ccw_device)
|
||||
static int zfcp_ccw_probe(struct ccw_device *cdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* zfcp_ccw_remove - remove function of zfcp driver
|
||||
* @ccw_device: pointer to belonging ccw device
|
||||
* @cdev: pointer to belonging ccw device
|
||||
*
|
||||
* This function gets called by the common i/o layer and removes an adapter
|
||||
* from the system. Task of this function is to get rid of all units and
|
||||
* ports that belong to this adapter. And in addition all resources of this
|
||||
* adapter will be freed too.
|
||||
*/
|
||||
static void zfcp_ccw_remove(struct ccw_device *ccw_device)
|
||||
static void zfcp_ccw_remove(struct ccw_device *cdev)
|
||||
{
|
||||
struct zfcp_adapter *adapter;
|
||||
struct zfcp_port *port, *p;
|
||||
|
|
@ -96,49 +104,37 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device)
|
|||
LIST_HEAD(unit_remove_lh);
|
||||
LIST_HEAD(port_remove_lh);
|
||||
|
||||
ccw_device_set_offline(ccw_device);
|
||||
ccw_device_set_offline(cdev);
|
||||
|
||||
mutex_lock(&zfcp_data.config_mutex);
|
||||
adapter = dev_get_drvdata(&ccw_device->dev);
|
||||
adapter = zfcp_ccw_adapter_by_cdev(cdev);
|
||||
if (!adapter)
|
||||
goto out;
|
||||
mutex_unlock(&zfcp_data.config_mutex);
|
||||
return;
|
||||
|
||||
cancel_work_sync(&adapter->scan_work);
|
||||
|
||||
mutex_lock(&zfcp_data.config_mutex);
|
||||
|
||||
/* this also removes the scsi devices, so call it first */
|
||||
zfcp_adapter_scsi_unregister(adapter);
|
||||
|
||||
write_lock_irq(&zfcp_data.config_lock);
|
||||
list_for_each_entry_safe(port, p, &adapter->port_list_head, list) {
|
||||
list_for_each_entry_safe(unit, u, &port->unit_list_head, list) {
|
||||
write_lock_irq(&adapter->port_list_lock);
|
||||
list_for_each_entry_safe(port, p, &adapter->port_list, list) {
|
||||
write_lock(&port->unit_list_lock);
|
||||
list_for_each_entry_safe(unit, u, &port->unit_list, list)
|
||||
list_move(&unit->list, &unit_remove_lh);
|
||||
atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE,
|
||||
&unit->status);
|
||||
}
|
||||
write_unlock(&port->unit_list_lock);
|
||||
list_move(&port->list, &port_remove_lh);
|
||||
atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status);
|
||||
}
|
||||
atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status);
|
||||
write_unlock_irq(&zfcp_data.config_lock);
|
||||
write_unlock_irq(&adapter->port_list_lock);
|
||||
zfcp_ccw_adapter_put(adapter); /* put from zfcp_ccw_adapter_by_cdev */
|
||||
|
||||
list_for_each_entry_safe(port, p, &port_remove_lh, list) {
|
||||
list_for_each_entry_safe(unit, u, &unit_remove_lh, list)
|
||||
zfcp_unit_dequeue(unit);
|
||||
zfcp_port_dequeue(port);
|
||||
}
|
||||
wait_event(adapter->remove_wq, atomic_read(&adapter->refcount) == 0);
|
||||
zfcp_adapter_dequeue(adapter);
|
||||
list_for_each_entry_safe(unit, u, &unit_remove_lh, list)
|
||||
zfcp_device_unregister(&unit->sysfs_device,
|
||||
&zfcp_sysfs_unit_attrs);
|
||||
|
||||
out:
|
||||
mutex_unlock(&zfcp_data.config_mutex);
|
||||
list_for_each_entry_safe(port, p, &port_remove_lh, list)
|
||||
zfcp_device_unregister(&port->sysfs_device,
|
||||
&zfcp_sysfs_port_attrs);
|
||||
|
||||
zfcp_adapter_unregister(adapter);
|
||||
}
|
||||
|
||||
/**
|
||||
* zfcp_ccw_set_online - set_online function of zfcp driver
|
||||
* @ccw_device: pointer to belonging ccw device
|
||||
* @cdev: pointer to belonging ccw device
|
||||
*
|
||||
* This function gets called by the common i/o layer and sets an
|
||||
* adapter into state online. The first call will allocate all
|
||||
|
|
@ -149,23 +145,20 @@ out:
|
|||
* the SCSI stack, that the QDIO queues will be set up and that the
|
||||
* adapter will be opened.
|
||||
*/
|
||||
static int zfcp_ccw_set_online(struct ccw_device *ccw_device)
|
||||
static int zfcp_ccw_set_online(struct ccw_device *cdev)
|
||||
{
|
||||
struct zfcp_adapter *adapter;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&zfcp_data.config_mutex);
|
||||
adapter = dev_get_drvdata(&ccw_device->dev);
|
||||
struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);
|
||||
|
||||
if (!adapter) {
|
||||
ret = zfcp_adapter_enqueue(ccw_device);
|
||||
if (ret) {
|
||||
dev_err(&ccw_device->dev,
|
||||
adapter = zfcp_adapter_enqueue(cdev);
|
||||
|
||||
if (IS_ERR(adapter)) {
|
||||
dev_err(&cdev->dev,
|
||||
"Setting up data structures for the "
|
||||
"FCP adapter failed\n");
|
||||
goto out;
|
||||
return PTR_ERR(adapter);
|
||||
}
|
||||
adapter = dev_get_drvdata(&ccw_device->dev);
|
||||
kref_get(&adapter->ref);
|
||||
}
|
||||
|
||||
/* initialize request counter */
|
||||
|
|
@ -177,58 +170,61 @@ static int zfcp_ccw_set_online(struct ccw_device *ccw_device)
|
|||
zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
|
||||
"ccsonl2", NULL);
|
||||
zfcp_erp_wait(adapter);
|
||||
out:
|
||||
mutex_unlock(&zfcp_data.config_mutex);
|
||||
if (!ret)
|
||||
flush_work(&adapter->scan_work);
|
||||
return ret;
|
||||
|
||||
flush_work(&adapter->scan_work);
|
||||
|
||||
zfcp_ccw_adapter_put(adapter);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* zfcp_ccw_set_offline - set_offline function of zfcp driver
|
||||
* @ccw_device: pointer to belonging ccw device
|
||||
* @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 *ccw_device)
|
||||
static int zfcp_ccw_set_offline(struct ccw_device *cdev)
|
||||
{
|
||||
struct zfcp_adapter *adapter;
|
||||
struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);
|
||||
|
||||
if (!adapter)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&zfcp_data.config_mutex);
|
||||
adapter = dev_get_drvdata(&ccw_device->dev);
|
||||
zfcp_erp_adapter_shutdown(adapter, 0, "ccsoff1", NULL);
|
||||
zfcp_erp_wait(adapter);
|
||||
mutex_unlock(&zfcp_data.config_mutex);
|
||||
|
||||
zfcp_ccw_adapter_put(adapter);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* zfcp_ccw_notify - ccw notify function
|
||||
* @ccw_device: pointer to belonging ccw device
|
||||
* @cdev: pointer to belonging ccw device
|
||||
* @event: indicates if adapter was detached or attached
|
||||
*
|
||||
* This function gets called by the common i/o layer if an adapter has gone
|
||||
* or reappeared.
|
||||
*/
|
||||
static int zfcp_ccw_notify(struct ccw_device *ccw_device, int event)
|
||||
static int zfcp_ccw_notify(struct ccw_device *cdev, int event)
|
||||
{
|
||||
struct zfcp_adapter *adapter = dev_get_drvdata(&ccw_device->dev);
|
||||
struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);
|
||||
|
||||
if (!adapter)
|
||||
return 1;
|
||||
|
||||
switch (event) {
|
||||
case CIO_GONE:
|
||||
dev_warn(&adapter->ccw_device->dev,
|
||||
"The FCP device has been detached\n");
|
||||
dev_warn(&cdev->dev, "The FCP device has been detached\n");
|
||||
zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti1", NULL);
|
||||
break;
|
||||
case CIO_NO_PATH:
|
||||
dev_warn(&adapter->ccw_device->dev,
|
||||
dev_warn(&cdev->dev,
|
||||
"The CHPID for the FCP device is offline\n");
|
||||
zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti2", NULL);
|
||||
break;
|
||||
case CIO_OPER:
|
||||
dev_info(&adapter->ccw_device->dev,
|
||||
"The FCP device is operational again\n");
|
||||
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);
|
||||
|
|
@ -236,11 +232,13 @@ static int zfcp_ccw_notify(struct ccw_device *ccw_device, int event)
|
|||
"ccnoti4", NULL);
|
||||
break;
|
||||
case CIO_BOXED:
|
||||
dev_warn(&adapter->ccw_device->dev, "The FCP device "
|
||||
"did not respond within the specified time\n");
|
||||
dev_warn(&cdev->dev, "The FCP device did not respond within "
|
||||
"the specified time\n");
|
||||
zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti5", NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
zfcp_ccw_adapter_put(adapter);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -250,18 +248,16 @@ static int zfcp_ccw_notify(struct ccw_device *ccw_device, int event)
|
|||
*/
|
||||
static void zfcp_ccw_shutdown(struct ccw_device *cdev)
|
||||
{
|
||||
struct zfcp_adapter *adapter;
|
||||
struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);
|
||||
|
||||
mutex_lock(&zfcp_data.config_mutex);
|
||||
adapter = dev_get_drvdata(&cdev->dev);
|
||||
if (!adapter)
|
||||
goto out;
|
||||
return;
|
||||
|
||||
zfcp_erp_adapter_shutdown(adapter, 0, "ccshut1", NULL);
|
||||
zfcp_erp_wait(adapter);
|
||||
zfcp_erp_thread_kill(adapter);
|
||||
out:
|
||||
mutex_unlock(&zfcp_data.config_mutex);
|
||||
|
||||
zfcp_ccw_adapter_put(adapter);
|
||||
}
|
||||
|
||||
struct ccw_driver zfcp_ccw_driver = {
|
||||
|
|
@ -274,18 +270,7 @@ struct ccw_driver zfcp_ccw_driver = {
|
|||
.set_offline = zfcp_ccw_set_offline,
|
||||
.notify = zfcp_ccw_notify,
|
||||
.shutdown = zfcp_ccw_shutdown,
|
||||
.freeze = zfcp_ccw_suspend,
|
||||
.freeze = zfcp_ccw_set_offline,
|
||||
.thaw = zfcp_ccw_activate,
|
||||
.restore = zfcp_ccw_activate,
|
||||
};
|
||||
|
||||
/**
|
||||
* zfcp_ccw_register - ccw register function
|
||||
*
|
||||
* Registers the driver at the common i/o layer. This function will be called
|
||||
* at module load time/system start.
|
||||
*/
|
||||
int __init zfcp_ccw_register(void)
|
||||
{
|
||||
return ccw_driver_register(&zfcp_ccw_driver);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,22 +86,17 @@ static int zfcp_cfdc_copy_to_user(void __user *user_buffer,
|
|||
static struct zfcp_adapter *zfcp_cfdc_get_adapter(u32 devno)
|
||||
{
|
||||
char busid[9];
|
||||
struct ccw_device *ccwdev;
|
||||
struct zfcp_adapter *adapter = NULL;
|
||||
struct ccw_device *cdev;
|
||||
struct zfcp_adapter *adapter;
|
||||
|
||||
snprintf(busid, sizeof(busid), "0.0.%04x", devno);
|
||||
ccwdev = get_ccwdev_by_busid(&zfcp_ccw_driver, busid);
|
||||
if (!ccwdev)
|
||||
goto out;
|
||||
cdev = get_ccwdev_by_busid(&zfcp_ccw_driver, busid);
|
||||
if (!cdev)
|
||||
return NULL;
|
||||
|
||||
adapter = dev_get_drvdata(&ccwdev->dev);
|
||||
if (!adapter)
|
||||
goto out_put;
|
||||
adapter = zfcp_ccw_adapter_by_cdev(cdev);
|
||||
|
||||
zfcp_adapter_get(adapter);
|
||||
out_put:
|
||||
put_device(&ccwdev->dev);
|
||||
out:
|
||||
put_device(&cdev->dev);
|
||||
return adapter;
|
||||
}
|
||||
|
||||
|
|
@ -212,7 +207,6 @@ static long zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command,
|
|||
retval = -ENXIO;
|
||||
goto free_buffer;
|
||||
}
|
||||
zfcp_adapter_get(adapter);
|
||||
|
||||
retval = zfcp_cfdc_sg_setup(data->command, fsf_cfdc->sg,
|
||||
data_user->control_file);
|
||||
|
|
@ -245,7 +239,7 @@ static long zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command,
|
|||
free_sg:
|
||||
zfcp_sg_free_table(fsf_cfdc->sg, ZFCP_CFDC_PAGES);
|
||||
adapter_put:
|
||||
zfcp_adapter_put(adapter);
|
||||
zfcp_ccw_adapter_put(adapter);
|
||||
free_buffer:
|
||||
kfree(data);
|
||||
no_mem_sense:
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include <asm/debug.h>
|
||||
#include "zfcp_dbf.h"
|
||||
#include "zfcp_ext.h"
|
||||
#include "zfcp_fc.h"
|
||||
|
||||
static u32 dbfsize = 4;
|
||||
|
||||
|
|
@ -177,8 +178,7 @@ void _zfcp_dbf_hba_fsf_response(const char *tag2, int level,
|
|||
|
||||
case FSF_QTCB_SEND_ELS:
|
||||
send_els = (struct zfcp_send_els *)fsf_req->data;
|
||||
response->u.els.d_id = qtcb->bottom.support.d_id;
|
||||
response->u.els.ls_code = send_els->ls_code >> 24;
|
||||
response->u.els.d_id = ntoh24(qtcb->bottom.support.d_id);
|
||||
break;
|
||||
|
||||
case FSF_QTCB_ABORT_FCP_CMND:
|
||||
|
|
@ -348,7 +348,6 @@ static void zfcp_dbf_hba_view_response(char **p,
|
|||
|
||||
case FSF_QTCB_SEND_ELS:
|
||||
zfcp_dbf_out(p, "d_id", "0x%06x", r->u.els.d_id);
|
||||
zfcp_dbf_out(p, "ls_code", "0x%02x", r->u.els.ls_code);
|
||||
break;
|
||||
|
||||
case FSF_QTCB_ABORT_FCP_CMND:
|
||||
|
|
@ -677,14 +676,14 @@ void zfcp_dbf_rec_action(char *id2, struct zfcp_erp_action *erp_action)
|
|||
/**
|
||||
* 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)
|
||||
void zfcp_dbf_san_ct_request(struct zfcp_fsf_req *fsf_req, u32 d_id)
|
||||
{
|
||||
struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data;
|
||||
struct zfcp_wka_port *wka_port = ct->wka_port;
|
||||
struct zfcp_adapter *adapter = wka_port->adapter;
|
||||
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 ct_hdr *hdr = sg_virt(ct->req);
|
||||
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;
|
||||
|
|
@ -695,19 +694,18 @@ void zfcp_dbf_san_ct_request(struct zfcp_fsf_req *fsf_req)
|
|||
strncpy(r->tag, "octc", ZFCP_DBF_TAG_SIZE);
|
||||
r->fsf_reqid = fsf_req->req_id;
|
||||
r->fsf_seqno = fsf_req->seq_no;
|
||||
r->s_id = fc_host_port_id(adapter->scsi_host);
|
||||
r->d_id = wka_port->d_id;
|
||||
oct->cmd_req_code = hdr->cmd_rsp_code;
|
||||
oct->revision = hdr->revision;
|
||||
oct->gs_type = hdr->gs_type;
|
||||
oct->gs_subtype = hdr->gs_subtype;
|
||||
oct->options = hdr->options;
|
||||
oct->max_res_size = hdr->max_res_size;
|
||||
oct->len = min((int)ct->req->length - (int)sizeof(struct ct_hdr),
|
||||
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 ct_hdr), oct->len);
|
||||
(void *)hdr + sizeof(struct fc_ct_hdr), oct->len);
|
||||
spin_unlock_irqrestore(&dbf->san_lock, flags);
|
||||
}
|
||||
|
||||
|
|
@ -717,10 +715,9 @@ void zfcp_dbf_san_ct_request(struct zfcp_fsf_req *fsf_req)
|
|||
*/
|
||||
void zfcp_dbf_san_ct_response(struct zfcp_fsf_req *fsf_req)
|
||||
{
|
||||
struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data;
|
||||
struct zfcp_wka_port *wka_port = ct->wka_port;
|
||||
struct zfcp_adapter *adapter = wka_port->adapter;
|
||||
struct ct_hdr *hdr = sg_virt(ct->resp);
|
||||
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;
|
||||
|
|
@ -732,25 +729,23 @@ void zfcp_dbf_san_ct_response(struct zfcp_fsf_req *fsf_req)
|
|||
strncpy(r->tag, "rctc", ZFCP_DBF_TAG_SIZE);
|
||||
r->fsf_reqid = fsf_req->req_id;
|
||||
r->fsf_seqno = fsf_req->seq_no;
|
||||
r->s_id = wka_port->d_id;
|
||||
r->d_id = fc_host_port_id(adapter->scsi_host);
|
||||
rct->cmd_rsp_code = hdr->cmd_rsp_code;
|
||||
rct->revision = hdr->revision;
|
||||
rct->reason_code = hdr->reason_code;
|
||||
rct->expl = hdr->reason_code_expl;
|
||||
rct->vendor_unique = hdr->vendor_unique;
|
||||
rct->max_res_size = hdr->max_res_size;
|
||||
rct->len = min((int)ct->resp->length - (int)sizeof(struct ct_hdr),
|
||||
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 ct_hdr), rct->len);
|
||||
(void *)hdr + sizeof(struct fc_ct_hdr), rct->len);
|
||||
spin_unlock_irqrestore(&dbf->san_lock, flags);
|
||||
}
|
||||
|
||||
static void zfcp_dbf_san_els(const char *tag, int level,
|
||||
struct zfcp_fsf_req *fsf_req, u32 s_id, u32 d_id,
|
||||
u8 ls_code, void *buffer, int buflen)
|
||||
struct zfcp_fsf_req *fsf_req, u32 d_id,
|
||||
void *buffer, int buflen)
|
||||
{
|
||||
struct zfcp_adapter *adapter = fsf_req->adapter;
|
||||
struct zfcp_dbf *dbf = adapter->dbf;
|
||||
|
|
@ -762,9 +757,7 @@ static void zfcp_dbf_san_els(const char *tag, int level,
|
|||
strncpy(rec->tag, tag, ZFCP_DBF_TAG_SIZE);
|
||||
rec->fsf_reqid = fsf_req->req_id;
|
||||
rec->fsf_seqno = fsf_req->seq_no;
|
||||
rec->s_id = s_id;
|
||||
rec->d_id = d_id;
|
||||
rec->u.els.ls_code = ls_code;
|
||||
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));
|
||||
|
|
@ -777,12 +770,11 @@ static void zfcp_dbf_san_els(const char *tag, int level,
|
|||
*/
|
||||
void zfcp_dbf_san_els_request(struct zfcp_fsf_req *fsf_req)
|
||||
{
|
||||
struct zfcp_send_els *els = (struct zfcp_send_els *)fsf_req->data;
|
||||
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);
|
||||
|
||||
zfcp_dbf_san_els("oels", 2, fsf_req,
|
||||
fc_host_port_id(els->adapter->scsi_host),
|
||||
els->d_id, *(u8 *) sg_virt(els->req),
|
||||
sg_virt(els->req), els->req->length);
|
||||
zfcp_dbf_san_els("oels", 2, fsf_req, d_id,
|
||||
sg_virt(els->req), els->req->length);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -791,12 +783,11 @@ void zfcp_dbf_san_els_request(struct zfcp_fsf_req *fsf_req)
|
|||
*/
|
||||
void zfcp_dbf_san_els_response(struct zfcp_fsf_req *fsf_req)
|
||||
{
|
||||
struct zfcp_send_els *els = (struct zfcp_send_els *)fsf_req->data;
|
||||
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);
|
||||
|
||||
zfcp_dbf_san_els("rels", 2, fsf_req, els->d_id,
|
||||
fc_host_port_id(els->adapter->scsi_host),
|
||||
*(u8 *)sg_virt(els->req), sg_virt(els->resp),
|
||||
els->resp->length);
|
||||
zfcp_dbf_san_els("rels", 2, fsf_req, d_id,
|
||||
sg_virt(els->resp), els->resp->length);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -805,16 +796,13 @@ void zfcp_dbf_san_els_response(struct zfcp_fsf_req *fsf_req)
|
|||
*/
|
||||
void zfcp_dbf_san_incoming_els(struct zfcp_fsf_req *fsf_req)
|
||||
{
|
||||
struct zfcp_adapter *adapter = fsf_req->adapter;
|
||||
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);
|
||||
|
||||
zfcp_dbf_san_els("iels", 1, fsf_req, buf->d_id,
|
||||
fc_host_port_id(adapter->scsi_host),
|
||||
buf->payload.data[0], (void *)buf->payload.data,
|
||||
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,
|
||||
|
|
@ -829,11 +817,10 @@ static int zfcp_dbf_san_view_format(debug_info_t *id, struct debug_view *view,
|
|||
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);
|
||||
zfcp_dbf_out(&p, "s_id", "0x%06x", r->s_id);
|
||||
zfcp_dbf_out(&p, "d_id", "0x%06x", r->d_id);
|
||||
|
||||
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);
|
||||
|
|
@ -852,7 +839,7 @@ static int zfcp_dbf_san_view_format(debug_info_t *id, struct debug_view *view,
|
|||
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, "ls_code", "0x%02x", els->ls_code);
|
||||
zfcp_dbf_out(&p, "d_id", "0x%06x", els->d_id);
|
||||
}
|
||||
return p - out_buf;
|
||||
}
|
||||
|
|
@ -870,8 +857,9 @@ void _zfcp_dbf_scsi(const char *tag, const char *tag2, int level,
|
|||
struct zfcp_dbf_scsi_record *rec = &dbf->scsi_buf;
|
||||
struct zfcp_dbf_dump *dump = (struct zfcp_dbf_dump *)rec;
|
||||
unsigned long flags;
|
||||
struct fcp_rsp_iu *fcp_rsp;
|
||||
char *fcp_rsp_info = NULL, *fcp_sns_info = NULL;
|
||||
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;
|
||||
|
||||
spin_lock_irqsave(&dbf->scsi_lock, flags);
|
||||
|
|
@ -895,20 +883,22 @@ void _zfcp_dbf_scsi(const char *tag, const char *tag2, int level,
|
|||
rec->scsi_allowed = scsi_cmnd->allowed;
|
||||
}
|
||||
if (fsf_req != NULL) {
|
||||
fcp_rsp = (struct fcp_rsp_iu *)
|
||||
&(fsf_req->qtcb->bottom.io.fcp_rsp);
|
||||
fcp_rsp_info = (unsigned char *) &fcp_rsp[1];
|
||||
fcp_sns_info =
|
||||
zfcp_get_fcp_sns_info_ptr(fcp_rsp);
|
||||
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->validity.value;
|
||||
rec->rsp_scsi_status = fcp_rsp->scsi_status;
|
||||
rec->rsp_resid = fcp_rsp->fcp_resid;
|
||||
if (fcp_rsp->validity.bits.fcp_rsp_len_valid)
|
||||
rec->rsp_code = *(fcp_rsp_info + 3);
|
||||
if (fcp_rsp->validity.bits.fcp_sns_len_valid) {
|
||||
buflen = min((int)fcp_rsp->fcp_sns_len,
|
||||
ZFCP_DBF_SCSI_MAX_FCP_SNS_INFO);
|
||||
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,
|
||||
|
|
@ -1067,6 +1057,8 @@ err_out:
|
|||
*/
|
||||
void zfcp_dbf_adapter_unregister(struct zfcp_dbf *dbf)
|
||||
{
|
||||
if (!dbf)
|
||||
return;
|
||||
debug_unregister(dbf->scsi);
|
||||
debug_unregister(dbf->san);
|
||||
debug_unregister(dbf->hba);
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#ifndef ZFCP_DBF_H
|
||||
#define ZFCP_DBF_H
|
||||
|
||||
#include <scsi/fc/fc_fcp.h>
|
||||
#include "zfcp_ext.h"
|
||||
#include "zfcp_fsf.h"
|
||||
#include "zfcp_def.h"
|
||||
|
|
@ -122,7 +123,6 @@ struct zfcp_dbf_hba_record_response {
|
|||
} unit;
|
||||
struct {
|
||||
u32 d_id;
|
||||
u8 ls_code;
|
||||
} els;
|
||||
} u;
|
||||
} __attribute__ ((packed));
|
||||
|
|
@ -166,6 +166,7 @@ struct zfcp_dbf_san_record_ct_request {
|
|||
u8 options;
|
||||
u16 max_res_size;
|
||||
u32 len;
|
||||
u32 d_id;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct zfcp_dbf_san_record_ct_response {
|
||||
|
|
@ -179,16 +180,13 @@ struct zfcp_dbf_san_record_ct_response {
|
|||
} __attribute__ ((packed));
|
||||
|
||||
struct zfcp_dbf_san_record_els {
|
||||
u8 ls_code;
|
||||
u32 len;
|
||||
u32 d_id;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct zfcp_dbf_san_record {
|
||||
u8 tag[ZFCP_DBF_TAG_SIZE];
|
||||
u64 fsf_reqid;
|
||||
u32 fsf_seqno;
|
||||
u32 s_id;
|
||||
u32 d_id;
|
||||
union {
|
||||
struct zfcp_dbf_san_record_ct_request ct_req;
|
||||
struct zfcp_dbf_san_record_ct_response ct_resp;
|
||||
|
|
@ -343,7 +341,7 @@ static inline
|
|||
void zfcp_dbf_scsi_devreset(const char *tag, u8 flag, struct zfcp_unit *unit,
|
||||
struct scsi_cmnd *scsi_cmnd)
|
||||
{
|
||||
zfcp_dbf_scsi(flag == FCP_TARGET_RESET ? "trst" : "lrst", tag, 1,
|
||||
zfcp_dbf_scsi(flag == FCP_TMF_TGT_RESET ? "trst" : "lrst", tag, 1,
|
||||
unit->port->adapter->dbf, scsi_cmnd, NULL, 0);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -71,131 +71,6 @@
|
|||
/* timeout value for "default timer" for fsf requests */
|
||||
#define ZFCP_FSF_REQUEST_TIMEOUT (60*HZ)
|
||||
|
||||
/*************** FIBRE CHANNEL PROTOCOL SPECIFIC DEFINES ********************/
|
||||
|
||||
/* task attribute values in FCP-2 FCP_CMND IU */
|
||||
#define SIMPLE_Q 0
|
||||
#define HEAD_OF_Q 1
|
||||
#define ORDERED_Q 2
|
||||
#define ACA_Q 4
|
||||
#define UNTAGGED 5
|
||||
|
||||
/* task management flags in FCP-2 FCP_CMND IU */
|
||||
#define FCP_CLEAR_ACA 0x40
|
||||
#define FCP_TARGET_RESET 0x20
|
||||
#define FCP_LOGICAL_UNIT_RESET 0x10
|
||||
#define FCP_CLEAR_TASK_SET 0x04
|
||||
#define FCP_ABORT_TASK_SET 0x02
|
||||
|
||||
#define FCP_CDB_LENGTH 16
|
||||
|
||||
#define ZFCP_DID_MASK 0x00FFFFFF
|
||||
|
||||
/* FCP(-2) FCP_CMND IU */
|
||||
struct fcp_cmnd_iu {
|
||||
u64 fcp_lun; /* FCP logical unit number */
|
||||
u8 crn; /* command reference number */
|
||||
u8 reserved0:5; /* reserved */
|
||||
u8 task_attribute:3; /* task attribute */
|
||||
u8 task_management_flags; /* task management flags */
|
||||
u8 add_fcp_cdb_length:6; /* additional FCP_CDB length */
|
||||
u8 rddata:1; /* read data */
|
||||
u8 wddata:1; /* write data */
|
||||
u8 fcp_cdb[FCP_CDB_LENGTH];
|
||||
} __attribute__((packed));
|
||||
|
||||
/* FCP(-2) FCP_RSP IU */
|
||||
struct fcp_rsp_iu {
|
||||
u8 reserved0[10];
|
||||
union {
|
||||
struct {
|
||||
u8 reserved1:3;
|
||||
u8 fcp_conf_req:1;
|
||||
u8 fcp_resid_under:1;
|
||||
u8 fcp_resid_over:1;
|
||||
u8 fcp_sns_len_valid:1;
|
||||
u8 fcp_rsp_len_valid:1;
|
||||
} bits;
|
||||
u8 value;
|
||||
} validity;
|
||||
u8 scsi_status;
|
||||
u32 fcp_resid;
|
||||
u32 fcp_sns_len;
|
||||
u32 fcp_rsp_len;
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
#define RSP_CODE_GOOD 0
|
||||
#define RSP_CODE_LENGTH_MISMATCH 1
|
||||
#define RSP_CODE_FIELD_INVALID 2
|
||||
#define RSP_CODE_RO_MISMATCH 3
|
||||
#define RSP_CODE_TASKMAN_UNSUPP 4
|
||||
#define RSP_CODE_TASKMAN_FAILED 5
|
||||
|
||||
/* see fc-fs */
|
||||
#define LS_RSCN 0x61
|
||||
#define LS_LOGO 0x05
|
||||
#define LS_PLOGI 0x03
|
||||
|
||||
struct fcp_rscn_head {
|
||||
u8 command;
|
||||
u8 page_length; /* always 0x04 */
|
||||
u16 payload_len;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct fcp_rscn_element {
|
||||
u8 reserved:2;
|
||||
u8 event_qual:4;
|
||||
u8 addr_format:2;
|
||||
u32 nport_did:24;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* see fc-ph */
|
||||
struct fcp_logo {
|
||||
u32 command;
|
||||
u32 nport_did;
|
||||
u64 nport_wwpn;
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
* FC-FS stuff
|
||||
*/
|
||||
#define R_A_TOV 10 /* seconds */
|
||||
|
||||
#define ZFCP_LS_RLS 0x0f
|
||||
#define ZFCP_LS_ADISC 0x52
|
||||
#define ZFCP_LS_RPS 0x56
|
||||
#define ZFCP_LS_RSCN 0x61
|
||||
#define ZFCP_LS_RNID 0x78
|
||||
|
||||
struct zfcp_ls_adisc {
|
||||
u8 code;
|
||||
u8 field[3];
|
||||
u32 hard_nport_id;
|
||||
u64 wwpn;
|
||||
u64 wwnn;
|
||||
u32 nport_id;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/*
|
||||
* FC-GS-2 stuff
|
||||
*/
|
||||
#define ZFCP_CT_REVISION 0x01
|
||||
#define ZFCP_CT_DIRECTORY_SERVICE 0xFC
|
||||
#define ZFCP_CT_NAME_SERVER 0x02
|
||||
#define ZFCP_CT_SYNCHRONOUS 0x00
|
||||
#define ZFCP_CT_SCSI_FCP 0x08
|
||||
#define ZFCP_CT_UNABLE_TO_PERFORM_CMD 0x09
|
||||
#define ZFCP_CT_GID_PN 0x0121
|
||||
#define ZFCP_CT_GPN_FT 0x0172
|
||||
#define ZFCP_CT_ACCEPT 0x8002
|
||||
#define ZFCP_CT_REJECT 0x8001
|
||||
|
||||
/*
|
||||
* FC-GS-4 stuff
|
||||
*/
|
||||
#define ZFCP_CT_TIMEOUT (3 * R_A_TOV)
|
||||
|
||||
/*************** ADAPTER/PORT/UNIT AND FSF_REQ STATUS FLAGS ******************/
|
||||
|
||||
/*
|
||||
|
|
@ -205,7 +80,6 @@ struct zfcp_ls_adisc {
|
|||
#define ZFCP_COMMON_FLAGS 0xfff00000
|
||||
|
||||
/* common status bits */
|
||||
#define ZFCP_STATUS_COMMON_REMOVE 0x80000000
|
||||
#define ZFCP_STATUS_COMMON_RUNNING 0x40000000
|
||||
#define ZFCP_STATUS_COMMON_ERP_FAILED 0x20000000
|
||||
#define ZFCP_STATUS_COMMON_UNBLOCKED 0x10000000
|
||||
|
|
@ -222,21 +96,10 @@ struct zfcp_ls_adisc {
|
|||
#define ZFCP_STATUS_ADAPTER_ERP_PENDING 0x00000100
|
||||
#define ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED 0x00000200
|
||||
|
||||
/* FC-PH/FC-GS well-known address identifiers for generic services */
|
||||
#define ZFCP_DID_WKA 0xFFFFF0
|
||||
|
||||
/* remote port status */
|
||||
#define ZFCP_STATUS_PORT_PHYS_OPEN 0x00000001
|
||||
#define ZFCP_STATUS_PORT_LINK_TEST 0x00000002
|
||||
|
||||
/* well known address (WKA) port status*/
|
||||
enum zfcp_wka_status {
|
||||
ZFCP_WKA_PORT_OFFLINE,
|
||||
ZFCP_WKA_PORT_CLOSING,
|
||||
ZFCP_WKA_PORT_OPENING,
|
||||
ZFCP_WKA_PORT_ONLINE,
|
||||
};
|
||||
|
||||
/* logical unit status */
|
||||
#define ZFCP_STATUS_UNIT_SHARED 0x00000004
|
||||
#define ZFCP_STATUS_UNIT_READONLY 0x00000008
|
||||
|
|
@ -247,10 +110,7 @@ enum zfcp_wka_status {
|
|||
#define ZFCP_STATUS_FSFREQ_CLEANUP 0x00000010
|
||||
#define ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED 0x00000040
|
||||
#define ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED 0x00000080
|
||||
#define ZFCP_STATUS_FSFREQ_ABORTED 0x00000100
|
||||
#define ZFCP_STATUS_FSFREQ_TMFUNCFAILED 0x00000200
|
||||
#define ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP 0x00000400
|
||||
#define ZFCP_STATUS_FSFREQ_RETRY 0x00000800
|
||||
#define ZFCP_STATUS_FSFREQ_DISMISSED 0x00001000
|
||||
|
||||
/************************* STRUCTURE DEFINITIONS *****************************/
|
||||
|
|
@ -265,125 +125,10 @@ struct zfcp_adapter_mempool {
|
|||
mempool_t *scsi_abort;
|
||||
mempool_t *status_read_req;
|
||||
mempool_t *status_read_data;
|
||||
mempool_t *gid_pn_data;
|
||||
mempool_t *gid_pn;
|
||||
mempool_t *qtcb_pool;
|
||||
};
|
||||
|
||||
/*
|
||||
* header for CT_IU
|
||||
*/
|
||||
struct ct_hdr {
|
||||
u8 revision; // 0x01
|
||||
u8 in_id[3]; // 0x00
|
||||
u8 gs_type; // 0xFC Directory Service
|
||||
u8 gs_subtype; // 0x02 Name Server
|
||||
u8 options; // 0x00 single bidirectional exchange
|
||||
u8 reserved0;
|
||||
u16 cmd_rsp_code; // 0x0121 GID_PN, or 0x0100 GA_NXT
|
||||
u16 max_res_size; // <= (4096 - 16) / 4
|
||||
u8 reserved1;
|
||||
u8 reason_code;
|
||||
u8 reason_code_expl;
|
||||
u8 vendor_unique;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* nameserver request CT_IU -- for requests where
|
||||
* a port name is required */
|
||||
struct ct_iu_gid_pn_req {
|
||||
struct ct_hdr header;
|
||||
u64 wwpn;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* FS_ACC IU and data unit for GID_PN nameserver request */
|
||||
struct ct_iu_gid_pn_resp {
|
||||
struct ct_hdr header;
|
||||
u32 d_id;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ct_iu_gpn_ft_req {
|
||||
struct ct_hdr header;
|
||||
u8 flags;
|
||||
u8 domain_id_scope;
|
||||
u8 area_id_scope;
|
||||
u8 fc4_type;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
/**
|
||||
* struct zfcp_send_ct - used to pass parameters to function zfcp_fsf_send_ct
|
||||
* @wka_port: port where the request is sent to
|
||||
* @req: scatter-gather list for request
|
||||
* @resp: scatter-gather list for response
|
||||
* @handler: handler function (called for response to the request)
|
||||
* @handler_data: data passed to handler function
|
||||
* @completion: completion for synchronization purposes
|
||||
* @status: used to pass error status to calling function
|
||||
*/
|
||||
struct zfcp_send_ct {
|
||||
struct zfcp_wka_port *wka_port;
|
||||
struct scatterlist *req;
|
||||
struct scatterlist *resp;
|
||||
void (*handler)(unsigned long);
|
||||
unsigned long handler_data;
|
||||
struct completion *completion;
|
||||
int status;
|
||||
};
|
||||
|
||||
/* used for name server requests in error recovery */
|
||||
struct zfcp_gid_pn_data {
|
||||
struct zfcp_send_ct ct;
|
||||
struct scatterlist req;
|
||||
struct scatterlist resp;
|
||||
struct ct_iu_gid_pn_req ct_iu_req;
|
||||
struct ct_iu_gid_pn_resp ct_iu_resp;
|
||||
struct zfcp_port *port;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct zfcp_send_els - used to pass parameters to function zfcp_fsf_send_els
|
||||
* @adapter: adapter where request is sent from
|
||||
* @port: port where ELS is destinated (port reference count has to be increased)
|
||||
* @d_id: destiniation id of port where request is sent to
|
||||
* @req: scatter-gather list for request
|
||||
* @resp: scatter-gather list for response
|
||||
* @handler: handler function (called for response to the request)
|
||||
* @handler_data: data passed to handler function
|
||||
* @completion: completion for synchronization purposes
|
||||
* @ls_code: hex code of ELS command
|
||||
* @status: used to pass error status to calling function
|
||||
*/
|
||||
struct zfcp_send_els {
|
||||
struct zfcp_adapter *adapter;
|
||||
struct zfcp_port *port;
|
||||
u32 d_id;
|
||||
struct scatterlist *req;
|
||||
struct scatterlist *resp;
|
||||
void (*handler)(unsigned long);
|
||||
unsigned long handler_data;
|
||||
struct completion *completion;
|
||||
int ls_code;
|
||||
int status;
|
||||
};
|
||||
|
||||
struct zfcp_wka_port {
|
||||
struct zfcp_adapter *adapter;
|
||||
wait_queue_head_t completion_wq;
|
||||
enum zfcp_wka_status status;
|
||||
atomic_t refcount;
|
||||
u32 d_id;
|
||||
u32 handle;
|
||||
struct mutex mutex;
|
||||
struct delayed_work work;
|
||||
};
|
||||
|
||||
struct zfcp_wka_ports {
|
||||
struct zfcp_wka_port ms; /* management service */
|
||||
struct zfcp_wka_port ts; /* time service */
|
||||
struct zfcp_wka_port ds; /* directory service */
|
||||
struct zfcp_wka_port as; /* alias service */
|
||||
struct zfcp_wka_port ks; /* key distribution service */
|
||||
};
|
||||
|
||||
struct zfcp_qdio_queue {
|
||||
struct qdio_buffer *sbal[QDIO_MAX_BUFFERS_PER_Q];
|
||||
u8 first; /* index of next free bfr in queue */
|
||||
|
|
@ -446,9 +191,7 @@ struct zfcp_qdio {
|
|||
};
|
||||
|
||||
struct zfcp_adapter {
|
||||
atomic_t refcount; /* reference count */
|
||||
wait_queue_head_t remove_wq; /* can be used to wait for
|
||||
refcount drop to zero */
|
||||
struct kref ref;
|
||||
u64 peer_wwnn; /* P2P peer WWNN */
|
||||
u64 peer_wwpn; /* P2P peer WWPN */
|
||||
u32 peer_d_id; /* P2P peer D_ID */
|
||||
|
|
@ -461,7 +204,8 @@ struct zfcp_adapter {
|
|||
u32 hardware_version; /* of FCP channel */
|
||||
u16 timer_ticks; /* time int for a tick */
|
||||
struct Scsi_Host *scsi_host; /* Pointer to mid-layer */
|
||||
struct list_head port_list_head; /* remote port list */
|
||||
struct list_head port_list; /* remote port list */
|
||||
rwlock_t port_list_lock; /* port list lock */
|
||||
unsigned long req_no; /* unique FSF req number */
|
||||
struct list_head *req_list; /* list of pending reqs */
|
||||
spinlock_t req_list_lock; /* request list lock */
|
||||
|
|
@ -485,7 +229,7 @@ struct zfcp_adapter {
|
|||
u32 erp_low_mem_count; /* nr of erp actions waiting
|
||||
for memory */
|
||||
struct task_struct *erp_thread;
|
||||
struct zfcp_wka_ports *gs; /* generic services */
|
||||
struct zfcp_fc_wka_ports *gs; /* generic services */
|
||||
struct zfcp_dbf *dbf; /* debug traces */
|
||||
struct zfcp_adapter_mempool pool; /* Adapter memory pools */
|
||||
struct fc_host_statistics *fc_stats;
|
||||
|
|
@ -500,11 +244,9 @@ struct zfcp_port {
|
|||
struct device sysfs_device; /* sysfs device */
|
||||
struct fc_rport *rport; /* rport of fc transport class */
|
||||
struct list_head list; /* list of remote ports */
|
||||
atomic_t refcount; /* reference count */
|
||||
wait_queue_head_t remove_wq; /* can be used to wait for
|
||||
refcount drop to zero */
|
||||
struct zfcp_adapter *adapter; /* adapter used to access port */
|
||||
struct list_head unit_list_head; /* head of logical unit list */
|
||||
struct list_head unit_list; /* head of logical unit list */
|
||||
rwlock_t unit_list_lock; /* unit list lock */
|
||||
atomic_t status; /* status of this remote port */
|
||||
u64 wwnn; /* WWNN if known */
|
||||
u64 wwpn; /* WWPN */
|
||||
|
|
@ -523,9 +265,6 @@ struct zfcp_port {
|
|||
struct zfcp_unit {
|
||||
struct device sysfs_device; /* sysfs device */
|
||||
struct list_head list; /* list of logical units */
|
||||
atomic_t refcount; /* reference count */
|
||||
wait_queue_head_t remove_wq; /* can be used to wait for
|
||||
refcount drop to zero */
|
||||
struct zfcp_port *port; /* remote port of unit */
|
||||
atomic_t status; /* status of this logical unit */
|
||||
u64 fcp_lun; /* own FCP_LUN */
|
||||
|
|
@ -601,14 +340,11 @@ struct zfcp_fsf_req {
|
|||
struct zfcp_data {
|
||||
struct scsi_host_template scsi_host_template;
|
||||
struct scsi_transport_template *scsi_transport_template;
|
||||
rwlock_t config_lock; /* serialises changes
|
||||
to adapter/port/unit
|
||||
lists */
|
||||
struct mutex config_mutex;
|
||||
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 ********************************/
|
||||
|
|
@ -657,47 +393,4 @@ zfcp_reqlist_find_safe(struct zfcp_adapter *adapter, struct zfcp_fsf_req *req)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* functions needed for reference/usage counting
|
||||
*/
|
||||
|
||||
static inline void
|
||||
zfcp_unit_get(struct zfcp_unit *unit)
|
||||
{
|
||||
atomic_inc(&unit->refcount);
|
||||
}
|
||||
|
||||
static inline void
|
||||
zfcp_unit_put(struct zfcp_unit *unit)
|
||||
{
|
||||
if (atomic_dec_return(&unit->refcount) == 0)
|
||||
wake_up(&unit->remove_wq);
|
||||
}
|
||||
|
||||
static inline void
|
||||
zfcp_port_get(struct zfcp_port *port)
|
||||
{
|
||||
atomic_inc(&port->refcount);
|
||||
}
|
||||
|
||||
static inline void
|
||||
zfcp_port_put(struct zfcp_port *port)
|
||||
{
|
||||
if (atomic_dec_return(&port->refcount) == 0)
|
||||
wake_up(&port->remove_wq);
|
||||
}
|
||||
|
||||
static inline void
|
||||
zfcp_adapter_get(struct zfcp_adapter *adapter)
|
||||
{
|
||||
atomic_inc(&adapter->refcount);
|
||||
}
|
||||
|
||||
static inline void
|
||||
zfcp_adapter_put(struct zfcp_adapter *adapter)
|
||||
{
|
||||
if (atomic_dec_return(&adapter->refcount) == 0)
|
||||
wake_up(&adapter->remove_wq);
|
||||
}
|
||||
|
||||
#endif /* ZFCP_DEF_H */
|
||||
|
|
|
|||
|
|
@ -99,9 +99,12 @@ static void zfcp_erp_action_dismiss_port(struct zfcp_port *port)
|
|||
|
||||
if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
|
||||
zfcp_erp_action_dismiss(&port->erp_action);
|
||||
else
|
||||
list_for_each_entry(unit, &port->unit_list_head, list)
|
||||
zfcp_erp_action_dismiss_unit(unit);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter)
|
||||
|
|
@ -110,9 +113,12 @@ static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter)
|
|||
|
||||
if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
|
||||
zfcp_erp_action_dismiss(&adapter->erp_action);
|
||||
else
|
||||
list_for_each_entry(port, &adapter->port_list_head, list)
|
||||
else {
|
||||
read_lock(&adapter->port_list_lock);
|
||||
list_for_each_entry(port, &adapter->port_list, list)
|
||||
zfcp_erp_action_dismiss_port(port);
|
||||
read_unlock(&adapter->port_list_lock);
|
||||
}
|
||||
}
|
||||
|
||||
static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter,
|
||||
|
|
@ -168,7 +174,8 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need,
|
|||
|
||||
switch (need) {
|
||||
case ZFCP_ERP_ACTION_REOPEN_UNIT:
|
||||
zfcp_unit_get(unit);
|
||||
if (!get_device(&unit->sysfs_device))
|
||||
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))
|
||||
|
|
@ -177,7 +184,8 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need,
|
|||
|
||||
case ZFCP_ERP_ACTION_REOPEN_PORT:
|
||||
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
|
||||
zfcp_port_get(port);
|
||||
if (!get_device(&port->sysfs_device))
|
||||
return NULL;
|
||||
zfcp_erp_action_dismiss_port(port);
|
||||
atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status);
|
||||
erp_action = &port->erp_action;
|
||||
|
|
@ -186,7 +194,7 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need,
|
|||
break;
|
||||
|
||||
case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
|
||||
zfcp_adapter_get(adapter);
|
||||
kref_get(&adapter->ref);
|
||||
zfcp_erp_action_dismiss_adapter(adapter);
|
||||
atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status);
|
||||
erp_action = &adapter->erp_action;
|
||||
|
|
@ -264,11 +272,16 @@ void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear,
|
|||
{
|
||||
unsigned long flags;
|
||||
|
||||
read_lock_irqsave(&zfcp_data.config_lock, flags);
|
||||
write_lock(&adapter->erp_lock);
|
||||
_zfcp_erp_adapter_reopen(adapter, clear, id, ref);
|
||||
write_unlock(&adapter->erp_lock);
|
||||
read_unlock_irqrestore(&zfcp_data.config_lock, flags);
|
||||
zfcp_erp_adapter_block(adapter, clear);
|
||||
zfcp_scsi_schedule_rports_block(adapter);
|
||||
|
||||
write_lock_irqsave(&adapter->erp_lock, flags);
|
||||
if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
|
||||
zfcp_erp_adapter_failed(adapter, "erareo1", NULL);
|
||||
else
|
||||
zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, adapter,
|
||||
NULL, NULL, id, ref);
|
||||
write_unlock_irqrestore(&adapter->erp_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -345,11 +358,9 @@ void zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, char *id,
|
|||
unsigned long flags;
|
||||
struct zfcp_adapter *adapter = port->adapter;
|
||||
|
||||
read_lock_irqsave(&zfcp_data.config_lock, flags);
|
||||
write_lock(&adapter->erp_lock);
|
||||
write_lock_irqsave(&adapter->erp_lock, flags);
|
||||
_zfcp_erp_port_forced_reopen(port, clear, id, ref);
|
||||
write_unlock(&adapter->erp_lock);
|
||||
read_unlock_irqrestore(&zfcp_data.config_lock, flags);
|
||||
write_unlock_irqrestore(&adapter->erp_lock, flags);
|
||||
}
|
||||
|
||||
static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id,
|
||||
|
|
@ -377,15 +388,13 @@ static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id,
|
|||
*/
|
||||
int zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id, void *ref)
|
||||
{
|
||||
unsigned long flags;
|
||||
int retval;
|
||||
unsigned long flags;
|
||||
struct zfcp_adapter *adapter = port->adapter;
|
||||
|
||||
read_lock_irqsave(&zfcp_data.config_lock, flags);
|
||||
write_lock(&adapter->erp_lock);
|
||||
write_lock_irqsave(&adapter->erp_lock, flags);
|
||||
retval = _zfcp_erp_port_reopen(port, clear, id, ref);
|
||||
write_unlock(&adapter->erp_lock);
|
||||
read_unlock_irqrestore(&zfcp_data.config_lock, flags);
|
||||
write_unlock_irqrestore(&adapter->erp_lock, flags);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
|
@ -424,11 +433,9 @@ void zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, char *id,
|
|||
struct zfcp_port *port = unit->port;
|
||||
struct zfcp_adapter *adapter = port->adapter;
|
||||
|
||||
read_lock_irqsave(&zfcp_data.config_lock, flags);
|
||||
write_lock(&adapter->erp_lock);
|
||||
write_lock_irqsave(&adapter->erp_lock, flags);
|
||||
_zfcp_erp_unit_reopen(unit, clear, id, ref);
|
||||
write_unlock(&adapter->erp_lock);
|
||||
read_unlock_irqrestore(&zfcp_data.config_lock, flags);
|
||||
write_unlock_irqrestore(&adapter->erp_lock, flags);
|
||||
}
|
||||
|
||||
static int status_change_set(unsigned long mask, atomic_t *status)
|
||||
|
|
@ -540,8 +547,10 @@ static void _zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter,
|
|||
{
|
||||
struct zfcp_port *port;
|
||||
|
||||
list_for_each_entry(port, &adapter->port_list_head, list)
|
||||
read_lock(&adapter->port_list_lock);
|
||||
list_for_each_entry(port, &adapter->port_list, list)
|
||||
_zfcp_erp_port_reopen(port, clear, id, ref);
|
||||
read_unlock(&adapter->port_list_lock);
|
||||
}
|
||||
|
||||
static void _zfcp_erp_unit_reopen_all(struct zfcp_port *port, int clear,
|
||||
|
|
@ -549,8 +558,10 @@ static void _zfcp_erp_unit_reopen_all(struct zfcp_port *port, int clear,
|
|||
{
|
||||
struct zfcp_unit *unit;
|
||||
|
||||
list_for_each_entry(unit, &port->unit_list_head, list)
|
||||
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);
|
||||
}
|
||||
|
||||
static void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act)
|
||||
|
|
@ -590,16 +601,14 @@ static void zfcp_erp_wakeup(struct zfcp_adapter *adapter)
|
|||
{
|
||||
unsigned long flags;
|
||||
|
||||
read_lock_irqsave(&zfcp_data.config_lock, flags);
|
||||
read_lock(&adapter->erp_lock);
|
||||
read_lock_irqsave(&adapter->erp_lock, flags);
|
||||
if (list_empty(&adapter->erp_ready_head) &&
|
||||
list_empty(&adapter->erp_running_head)) {
|
||||
atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING,
|
||||
&adapter->status);
|
||||
wake_up(&adapter->erp_done_wqh);
|
||||
}
|
||||
read_unlock(&adapter->erp_lock);
|
||||
read_unlock_irqrestore(&zfcp_data.config_lock, flags);
|
||||
read_unlock_irqrestore(&adapter->erp_lock, flags);
|
||||
}
|
||||
|
||||
static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *act)
|
||||
|
|
@ -1170,28 +1179,28 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
|
|||
switch (act->action) {
|
||||
case ZFCP_ERP_ACTION_REOPEN_UNIT:
|
||||
if ((result == ZFCP_ERP_SUCCEEDED) && !unit->device) {
|
||||
zfcp_unit_get(unit);
|
||||
get_device(&unit->sysfs_device);
|
||||
if (scsi_queue_work(unit->port->adapter->scsi_host,
|
||||
&unit->scsi_work) <= 0)
|
||||
zfcp_unit_put(unit);
|
||||
put_device(&unit->sysfs_device);
|
||||
}
|
||||
zfcp_unit_put(unit);
|
||||
put_device(&unit->sysfs_device);
|
||||
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);
|
||||
zfcp_port_put(port);
|
||||
put_device(&port->sysfs_device);
|
||||
break;
|
||||
|
||||
case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
|
||||
if (result == ZFCP_ERP_SUCCEEDED) {
|
||||
register_service_level(&adapter->service_level);
|
||||
schedule_work(&adapter->scan_work);
|
||||
queue_work(adapter->work_queue, &adapter->scan_work);
|
||||
} else
|
||||
unregister_service_level(&adapter->service_level);
|
||||
zfcp_adapter_put(adapter);
|
||||
kref_put(&adapter->ref, zfcp_adapter_release);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -1214,12 +1223,12 @@ static int zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action)
|
|||
static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
|
||||
{
|
||||
int retval;
|
||||
struct zfcp_adapter *adapter = erp_action->adapter;
|
||||
unsigned long flags;
|
||||
struct zfcp_adapter *adapter = erp_action->adapter;
|
||||
|
||||
read_lock_irqsave(&zfcp_data.config_lock, flags);
|
||||
write_lock(&adapter->erp_lock);
|
||||
kref_get(&adapter->ref);
|
||||
|
||||
write_lock_irqsave(&adapter->erp_lock, flags);
|
||||
zfcp_erp_strategy_check_fsfreq(erp_action);
|
||||
|
||||
if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) {
|
||||
|
|
@ -1231,11 +1240,9 @@ static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
|
|||
zfcp_erp_action_to_running(erp_action);
|
||||
|
||||
/* no lock to allow for blocking operations */
|
||||
write_unlock(&adapter->erp_lock);
|
||||
read_unlock_irqrestore(&zfcp_data.config_lock, flags);
|
||||
write_unlock_irqrestore(&adapter->erp_lock, flags);
|
||||
retval = zfcp_erp_strategy_do_action(erp_action);
|
||||
read_lock_irqsave(&zfcp_data.config_lock, flags);
|
||||
write_lock(&adapter->erp_lock);
|
||||
write_lock_irqsave(&adapter->erp_lock, flags);
|
||||
|
||||
if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED)
|
||||
retval = ZFCP_ERP_CONTINUES;
|
||||
|
|
@ -1273,12 +1280,12 @@ static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
|
|||
zfcp_erp_strategy_followup_failed(erp_action);
|
||||
|
||||
unlock:
|
||||
write_unlock(&adapter->erp_lock);
|
||||
read_unlock_irqrestore(&zfcp_data.config_lock, flags);
|
||||
write_unlock_irqrestore(&adapter->erp_lock, flags);
|
||||
|
||||
if (retval != ZFCP_ERP_CONTINUES)
|
||||
zfcp_erp_action_cleanup(erp_action, retval);
|
||||
|
||||
kref_put(&adapter->ref, zfcp_adapter_release);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -1415,6 +1422,7 @@ void zfcp_erp_modify_adapter_status(struct zfcp_adapter *adapter, char *id,
|
|||
void *ref, u32 mask, int set_or_clear)
|
||||
{
|
||||
struct zfcp_port *port;
|
||||
unsigned long flags;
|
||||
u32 common_mask = mask & ZFCP_COMMON_FLAGS;
|
||||
|
||||
if (set_or_clear == ZFCP_SET) {
|
||||
|
|
@ -1429,10 +1437,13 @@ void zfcp_erp_modify_adapter_status(struct zfcp_adapter *adapter, char *id,
|
|||
atomic_set(&adapter->erp_counter, 0);
|
||||
}
|
||||
|
||||
if (common_mask)
|
||||
list_for_each_entry(port, &adapter->port_list_head, list)
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1449,6 +1460,7 @@ void zfcp_erp_modify_port_status(struct zfcp_port *port, char *id, void *ref,
|
|||
u32 mask, int set_or_clear)
|
||||
{
|
||||
struct zfcp_unit *unit;
|
||||
unsigned long flags;
|
||||
u32 common_mask = mask & ZFCP_COMMON_FLAGS;
|
||||
|
||||
if (set_or_clear == ZFCP_SET) {
|
||||
|
|
@ -1463,10 +1475,13 @@ void zfcp_erp_modify_port_status(struct zfcp_port *port, char *id, void *ref,
|
|||
atomic_set(&port->erp_counter, 0);
|
||||
}
|
||||
|
||||
if (common_mask)
|
||||
list_for_each_entry(unit, &port->unit_list_head, list)
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1502,12 +1517,8 @@ void zfcp_erp_modify_unit_status(struct zfcp_unit *unit, char *id, void *ref,
|
|||
*/
|
||||
void zfcp_erp_port_boxed(struct zfcp_port *port, char *id, void *ref)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
read_lock_irqsave(&zfcp_data.config_lock, flags);
|
||||
zfcp_erp_modify_port_status(port, id, ref,
|
||||
ZFCP_STATUS_COMMON_ACCESS_BOXED, ZFCP_SET);
|
||||
read_unlock_irqrestore(&zfcp_data.config_lock, flags);
|
||||
zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref);
|
||||
}
|
||||
|
||||
|
|
@ -1535,13 +1546,9 @@ void zfcp_erp_unit_boxed(struct zfcp_unit *unit, char *id, void *ref)
|
|||
*/
|
||||
void zfcp_erp_port_access_denied(struct zfcp_port *port, char *id, void *ref)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
read_lock_irqsave(&zfcp_data.config_lock, flags);
|
||||
zfcp_erp_modify_port_status(port, id, ref,
|
||||
ZFCP_STATUS_COMMON_ERP_FAILED |
|
||||
ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET);
|
||||
read_unlock_irqrestore(&zfcp_data.config_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1574,12 +1581,15 @@ static void zfcp_erp_port_access_changed(struct zfcp_port *port, char *id,
|
|||
void *ref)
|
||||
{
|
||||
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))) {
|
||||
list_for_each_entry(unit, &port->unit_list_head, list)
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -1595,14 +1605,14 @@ static void zfcp_erp_port_access_changed(struct zfcp_port *port, char *id,
|
|||
void zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter, char *id,
|
||||
void *ref)
|
||||
{
|
||||
struct zfcp_port *port;
|
||||
unsigned long flags;
|
||||
struct zfcp_port *port;
|
||||
|
||||
if (adapter->connection_features & FSF_FEATURE_NPIV_MODE)
|
||||
return;
|
||||
|
||||
read_lock_irqsave(&zfcp_data.config_lock, flags);
|
||||
list_for_each_entry(port, &adapter->port_list_head, list)
|
||||
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(&zfcp_data.config_lock, flags);
|
||||
read_unlock_irqrestore(&adapter->port_list_lock, flags);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,26 +9,31 @@
|
|||
#ifndef ZFCP_EXT_H
|
||||
#define ZFCP_EXT_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <scsi/fc/fc_els.h>
|
||||
#include "zfcp_def.h"
|
||||
#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 int zfcp_adapter_enqueue(struct ccw_device *);
|
||||
extern void zfcp_adapter_dequeue(struct zfcp_adapter *);
|
||||
extern struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *);
|
||||
extern struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *, u64, u32,
|
||||
u32);
|
||||
extern void zfcp_port_dequeue(struct zfcp_port *);
|
||||
extern struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *, u64);
|
||||
extern void zfcp_unit_dequeue(struct zfcp_unit *);
|
||||
extern int zfcp_reqlist_isempty(struct zfcp_adapter *);
|
||||
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_register(void);
|
||||
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;
|
||||
|
|
@ -51,7 +56,7 @@ 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_hba_berr(struct zfcp_dbf *, struct zfcp_fsf_req *);
|
||||
extern void zfcp_dbf_san_ct_request(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 *);
|
||||
|
|
@ -92,24 +97,22 @@ extern void zfcp_erp_adapter_access_changed(struct zfcp_adapter *, char *,
|
|||
extern void zfcp_erp_timeout_handler(unsigned long);
|
||||
|
||||
/* zfcp_fc.c */
|
||||
extern int zfcp_fc_scan_ports(struct zfcp_adapter *);
|
||||
extern void _zfcp_fc_scan_ports_later(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 *);
|
||||
extern void zfcp_fc_trigger_did_lookup(struct zfcp_port *);
|
||||
extern void zfcp_fc_plogi_evaluate(struct zfcp_port *, struct fsf_plogi *);
|
||||
extern void zfcp_fc_plogi_evaluate(struct zfcp_port *, struct fc_els_flogi *);
|
||||
extern void zfcp_fc_test_link(struct zfcp_port *);
|
||||
extern void zfcp_fc_link_test_work(struct work_struct *);
|
||||
extern void zfcp_fc_wka_ports_force_offline(struct zfcp_wka_ports *);
|
||||
extern void zfcp_fc_wka_ports_force_offline(struct zfcp_fc_wka_ports *);
|
||||
extern int zfcp_fc_gs_setup(struct zfcp_adapter *);
|
||||
extern void zfcp_fc_gs_destroy(struct zfcp_adapter *);
|
||||
extern int zfcp_fc_execute_els_fc_job(struct fc_bsg_job *);
|
||||
extern int zfcp_fc_execute_ct_fc_job(struct fc_bsg_job *);
|
||||
extern int zfcp_fc_exec_bsg_job(struct fc_bsg_job *);
|
||||
|
||||
/* zfcp_fsf.c */
|
||||
extern int zfcp_fsf_open_port(struct zfcp_erp_action *);
|
||||
extern int zfcp_fsf_open_wka_port(struct zfcp_wka_port *);
|
||||
extern int zfcp_fsf_close_wka_port(struct zfcp_wka_port *);
|
||||
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 *);
|
||||
|
|
@ -125,8 +128,10 @@ extern struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *,
|
|||
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);
|
||||
extern int zfcp_fsf_send_ct(struct zfcp_send_ct *, mempool_t *);
|
||||
extern int zfcp_fsf_send_els(struct zfcp_send_els *);
|
||||
extern int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *, struct zfcp_fsf_ct_els *,
|
||||
mempool_t *);
|
||||
extern int zfcp_fsf_send_els(struct zfcp_adapter *, u32,
|
||||
struct zfcp_fsf_ct_els *);
|
||||
extern int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *,
|
||||
struct scsi_cmnd *);
|
||||
extern void zfcp_fsf_req_free(struct zfcp_fsf_req *);
|
||||
|
|
@ -153,7 +158,6 @@ extern void zfcp_qdio_close(struct zfcp_qdio *);
|
|||
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 char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *);
|
||||
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 *);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
260
drivers/s390/scsi/zfcp_fc.h
Normal file
260
drivers/s390/scsi/zfcp_fc.h
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
/*
|
||||
* zfcp device driver
|
||||
*
|
||||
* Fibre Channel related definitions and inline functions for the zfcp
|
||||
* device driver
|
||||
*
|
||||
* Copyright IBM Corporation 2009
|
||||
*/
|
||||
|
||||
#ifndef ZFCP_FC_H
|
||||
#define ZFCP_FC_H
|
||||
|
||||
#include <scsi/fc/fc_els.h>
|
||||
#include <scsi/fc/fc_fcp.h>
|
||||
#include <scsi/fc/fc_ns.h>
|
||||
#include <scsi/scsi_cmnd.h>
|
||||
#include <scsi/scsi_tcq.h>
|
||||
#include "zfcp_fsf.h"
|
||||
|
||||
#define ZFCP_FC_CT_SIZE_PAGE (PAGE_SIZE - sizeof(struct fc_ct_hdr))
|
||||
#define ZFCP_FC_GPN_FT_ENT_PAGE (ZFCP_FC_CT_SIZE_PAGE \
|
||||
/ sizeof(struct fc_gpn_ft_resp))
|
||||
#define ZFCP_FC_GPN_FT_NUM_BUFS 4 /* memory pages */
|
||||
|
||||
#define ZFCP_FC_GPN_FT_MAX_SIZE (ZFCP_FC_GPN_FT_NUM_BUFS * PAGE_SIZE \
|
||||
- sizeof(struct fc_ct_hdr))
|
||||
#define ZFCP_FC_GPN_FT_MAX_ENT (ZFCP_FC_GPN_FT_NUM_BUFS * \
|
||||
(ZFCP_FC_GPN_FT_ENT_PAGE + 1))
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
struct zfcp_fc_gid_pn_req {
|
||||
struct fc_ct_hdr ct_hdr;
|
||||
struct fc_ns_gid_pn gid_pn;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct zfcp_fc_gid_pn_resp - 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 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
|
||||
*/
|
||||
struct zfcp_fc_gpn_ft_req {
|
||||
struct fc_ct_hdr ct_hdr;
|
||||
struct fc_ns_gid_ft gpn_ft;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct zfcp_fc_gpn_ft_resp - container for ct header plus gpn_ft response
|
||||
* @ct_hdr: FC GS common transport header
|
||||
* @gpn_ft: Array of gpn_ft response data to fill one memory page
|
||||
*/
|
||||
struct zfcp_fc_gpn_ft_resp {
|
||||
struct fc_ct_hdr ct_hdr;
|
||||
struct fc_gpn_ft_resp gpn_ft[ZFCP_FC_GPN_FT_ENT_PAGE];
|
||||
} __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_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_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_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;
|
||||
};
|
||||
|
||||
/**
|
||||
* enum zfcp_fc_wka_status - FC WKA port status in zfcp
|
||||
* @ZFCP_FC_WKA_PORT_OFFLINE: Port is closed and not in use
|
||||
* @ZFCP_FC_WKA_PORT_CLOSING: The FSF "close port" request is pending
|
||||
* @ZFCP_FC_WKA_PORT_OPENING: The FSF "open port" request is pending
|
||||
* @ZFCP_FC_WKA_PORT_ONLINE: The port is open and the port handle is valid
|
||||
*/
|
||||
enum zfcp_fc_wka_status {
|
||||
ZFCP_FC_WKA_PORT_OFFLINE,
|
||||
ZFCP_FC_WKA_PORT_CLOSING,
|
||||
ZFCP_FC_WKA_PORT_OPENING,
|
||||
ZFCP_FC_WKA_PORT_ONLINE,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct zfcp_fc_wka_port - representation of well-known-address (WKA) FC port
|
||||
* @adapter: Pointer to adapter structure this WKA port belongs to
|
||||
* @completion_wq: Wait for completion of open/close command
|
||||
* @status: Current status of WKA port
|
||||
* @refcount: Reference count to keep port open as long as it is in use
|
||||
* @d_id: FC destination id or well-known-address
|
||||
* @handle: FSF handle for the open WKA port
|
||||
* @mutex: Mutex used during opening/closing state changes
|
||||
* @work: For delaying the closing of the WKA port
|
||||
*/
|
||||
struct zfcp_fc_wka_port {
|
||||
struct zfcp_adapter *adapter;
|
||||
wait_queue_head_t completion_wq;
|
||||
enum zfcp_fc_wka_status status;
|
||||
atomic_t refcount;
|
||||
u32 d_id;
|
||||
u32 handle;
|
||||
struct mutex mutex;
|
||||
struct delayed_work work;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct zfcp_fc_wka_ports - Data structures for FC generic services
|
||||
* @ms: FC Management service
|
||||
* @ts: FC time service
|
||||
* @ds: FC directory service
|
||||
* @as: FC alias service
|
||||
*/
|
||||
struct zfcp_fc_wka_ports {
|
||||
struct zfcp_fc_wka_port ms;
|
||||
struct zfcp_fc_wka_port ts;
|
||||
struct zfcp_fc_wka_port ds;
|
||||
struct zfcp_fc_wka_port as;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
static inline
|
||||
void zfcp_fc_scsi_to_fcp(struct fcp_cmnd *fcp, struct scsi_cmnd *scsi)
|
||||
{
|
||||
char tag[2];
|
||||
|
||||
int_to_scsilun(scsi->device->lun, (struct scsi_lun *) &fcp->fc_lun);
|
||||
|
||||
if (scsi_populate_tag_msg(scsi, tag)) {
|
||||
switch (tag[0]) {
|
||||
case MSG_ORDERED_TAG:
|
||||
fcp->fc_pri_ta |= FCP_PTA_ORDERED;
|
||||
break;
|
||||
case MSG_SIMPLE_TAG:
|
||||
fcp->fc_pri_ta |= FCP_PTA_SIMPLE;
|
||||
break;
|
||||
};
|
||||
} else
|
||||
fcp->fc_pri_ta = FCP_PTA_SIMPLE;
|
||||
|
||||
if (scsi->sc_data_direction == DMA_FROM_DEVICE)
|
||||
fcp->fc_flags |= FCP_CFL_RDDATA;
|
||||
if (scsi->sc_data_direction == DMA_TO_DEVICE)
|
||||
fcp->fc_flags |= FCP_CFL_WRDATA;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* zfcp_fc_evap_fcp_rsp - evaluate FCP RSP IU and update scsi_cmnd accordingly
|
||||
* @fcp_rsp: FCP RSP IU to evaluate
|
||||
* @scsi: SCSI command where to update status and sense buffer
|
||||
*/
|
||||
static inline
|
||||
void zfcp_fc_eval_fcp_rsp(struct fcp_resp_with_ext *fcp_rsp,
|
||||
struct scsi_cmnd *scsi)
|
||||
{
|
||||
struct fcp_resp_rsp_info *rsp_info;
|
||||
char *sense;
|
||||
u32 sense_len, resid;
|
||||
u8 rsp_flags;
|
||||
|
||||
set_msg_byte(scsi, COMMAND_COMPLETE);
|
||||
scsi->result |= fcp_rsp->resp.fr_status;
|
||||
|
||||
rsp_flags = fcp_rsp->resp.fr_flags;
|
||||
|
||||
if (unlikely(rsp_flags & FCP_RSP_LEN_VAL)) {
|
||||
rsp_info = (struct fcp_resp_rsp_info *) &fcp_rsp[1];
|
||||
if (rsp_info->rsp_code == FCP_TMF_CMPL)
|
||||
set_host_byte(scsi, DID_OK);
|
||||
else {
|
||||
set_host_byte(scsi, DID_ERROR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
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_len = min(fcp_rsp->ext.fr_sns_len,
|
||||
(u32) SCSI_SENSE_BUFFERSIZE);
|
||||
memcpy(scsi->sense_buffer, sense, sense_len);
|
||||
}
|
||||
|
||||
if (unlikely(rsp_flags & FCP_RESID_UNDER)) {
|
||||
resid = fcp_rsp->ext.fr_resid;
|
||||
scsi_set_resid(scsi, resid);
|
||||
if (scsi_bufflen(scsi) - resid < scsi->underflow &&
|
||||
!(rsp_flags & FCP_SNS_LEN_VAL) &&
|
||||
fcp_rsp->resp.fr_status == SAM_STAT_GOOD)
|
||||
set_host_byte(scsi, DID_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -10,7 +10,9 @@
|
|||
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
|
||||
|
||||
#include <linux/blktrace_api.h>
|
||||
#include <scsi/fc/fc_els.h>
|
||||
#include "zfcp_ext.h"
|
||||
#include "zfcp_fc.h"
|
||||
#include "zfcp_dbf.h"
|
||||
|
||||
static void zfcp_fsf_request_timeout_handler(unsigned long data)
|
||||
|
|
@ -122,36 +124,32 @@ void zfcp_fsf_req_free(struct zfcp_fsf_req *req)
|
|||
|
||||
static void zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *req)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct fsf_status_read_buffer *sr_buf = req->data;
|
||||
struct zfcp_adapter *adapter = req->adapter;
|
||||
struct zfcp_port *port;
|
||||
int d_id = sr_buf->d_id & ZFCP_DID_MASK;
|
||||
unsigned long flags;
|
||||
int d_id = ntoh24(sr_buf->d_id);
|
||||
|
||||
read_lock_irqsave(&zfcp_data.config_lock, flags);
|
||||
list_for_each_entry(port, &adapter->port_list_head, list)
|
||||
read_lock_irqsave(&adapter->port_list_lock, flags);
|
||||
list_for_each_entry(port, &adapter->port_list, list)
|
||||
if (port->d_id == d_id) {
|
||||
read_unlock_irqrestore(&zfcp_data.config_lock, flags);
|
||||
zfcp_erp_port_reopen(port, 0, "fssrpc1", req);
|
||||
return;
|
||||
break;
|
||||
}
|
||||
read_unlock_irqrestore(&zfcp_data.config_lock, flags);
|
||||
read_unlock_irqrestore(&adapter->port_list_lock, flags);
|
||||
}
|
||||
|
||||
static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req, char *id,
|
||||
struct fsf_link_down_info *link_down)
|
||||
{
|
||||
struct zfcp_adapter *adapter = req->adapter;
|
||||
unsigned long flags;
|
||||
|
||||
if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED)
|
||||
return;
|
||||
|
||||
atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status);
|
||||
|
||||
read_lock_irqsave(&zfcp_data.config_lock, flags);
|
||||
zfcp_scsi_schedule_rports_block(adapter);
|
||||
read_unlock_irqrestore(&zfcp_data.config_lock, flags);
|
||||
|
||||
if (!link_down)
|
||||
goto out;
|
||||
|
|
@ -291,7 +289,7 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req)
|
|||
zfcp_erp_adapter_access_changed(adapter, "fssrh_3",
|
||||
req);
|
||||
if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_INCOMING_ELS)
|
||||
schedule_work(&adapter->scan_work);
|
||||
queue_work(adapter->work_queue, &adapter->scan_work);
|
||||
break;
|
||||
case FSF_STATUS_READ_CFDC_UPDATED:
|
||||
zfcp_erp_adapter_access_changed(adapter, "fssrh_4", req);
|
||||
|
|
@ -317,7 +315,6 @@ static void zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *req)
|
|||
case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
|
||||
return;
|
||||
case FSF_SQ_COMMAND_ABORTED:
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ABORTED;
|
||||
break;
|
||||
case FSF_SQ_NO_RECOM:
|
||||
dev_err(&req->adapter->ccw_device->dev,
|
||||
|
|
@ -358,8 +355,7 @@ static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req)
|
|||
zfcp_dbf_hba_fsf_response(req);
|
||||
|
||||
if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED) {
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR |
|
||||
ZFCP_STATUS_FSFREQ_RETRY; /* only for SCSI cmnds. */
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -377,7 +373,7 @@ static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req)
|
|||
case FSF_PROT_ERROR_STATE:
|
||||
case FSF_PROT_SEQ_NUMB_ERROR:
|
||||
zfcp_erp_adapter_reopen(adapter, 0, "fspse_2", req);
|
||||
req->status |= ZFCP_STATUS_FSFREQ_RETRY;
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
|
||||
break;
|
||||
case FSF_PROT_UNSUPP_QTCB_TYPE:
|
||||
dev_err(&adapter->ccw_device->dev,
|
||||
|
|
@ -480,20 +476,27 @@ void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter)
|
|||
|
||||
static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req)
|
||||
{
|
||||
struct fsf_qtcb_bottom_config *bottom;
|
||||
struct fsf_qtcb_bottom_config *bottom = &req->qtcb->bottom.config;
|
||||
struct zfcp_adapter *adapter = req->adapter;
|
||||
struct Scsi_Host *shost = adapter->scsi_host;
|
||||
struct fc_els_flogi *nsp, *plogi;
|
||||
|
||||
bottom = &req->qtcb->bottom.config;
|
||||
/* adjust pointers for missing command code */
|
||||
nsp = (struct fc_els_flogi *) ((u8 *)&bottom->nport_serv_param
|
||||
- sizeof(u32));
|
||||
plogi = (struct fc_els_flogi *) ((u8 *)&bottom->plogi_payload
|
||||
- sizeof(u32));
|
||||
|
||||
if (req->data)
|
||||
memcpy(req->data, bottom, sizeof(*bottom));
|
||||
|
||||
fc_host_node_name(shost) = bottom->nport_serv_param.wwnn;
|
||||
fc_host_port_name(shost) = bottom->nport_serv_param.wwpn;
|
||||
fc_host_port_id(shost) = bottom->s_id & ZFCP_DID_MASK;
|
||||
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;
|
||||
fc_host_supported_fc4s(shost)[2] = 1; /* FCP */
|
||||
fc_host_active_fc4s(shost)[2] = 1; /* FCP */
|
||||
|
||||
adapter->hydra_version = bottom->adapter_type;
|
||||
adapter->timer_ticks = bottom->timer_interval;
|
||||
|
|
@ -503,9 +506,9 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req)
|
|||
|
||||
switch (bottom->fc_topology) {
|
||||
case FSF_TOPO_P2P:
|
||||
adapter->peer_d_id = bottom->peer_d_id & ZFCP_DID_MASK;
|
||||
adapter->peer_wwpn = bottom->plogi_payload.wwpn;
|
||||
adapter->peer_wwnn = bottom->plogi_payload.wwnn;
|
||||
adapter->peer_d_id = ntoh24(bottom->peer_d_id);
|
||||
adapter->peer_wwpn = plogi->fl_wwpn;
|
||||
adapter->peer_wwnn = plogi->fl_wwnn;
|
||||
fc_host_port_type(shost) = FC_PORTTYPE_PTP;
|
||||
break;
|
||||
case FSF_TOPO_FABRIC:
|
||||
|
|
@ -881,13 +884,11 @@ static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req)
|
|||
break;
|
||||
case FSF_PORT_BOXED:
|
||||
zfcp_erp_port_boxed(unit->port, "fsafch3", req);
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR |
|
||||
ZFCP_STATUS_FSFREQ_RETRY;
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
|
||||
break;
|
||||
case FSF_LUN_BOXED:
|
||||
zfcp_erp_unit_boxed(unit, "fsafch4", req);
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR |
|
||||
ZFCP_STATUS_FSFREQ_RETRY;
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
|
||||
break;
|
||||
case FSF_ADAPTER_STATUS_AVAILABLE:
|
||||
switch (fsq->word[0]) {
|
||||
|
|
@ -958,10 +959,10 @@ out:
|
|||
static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req)
|
||||
{
|
||||
struct zfcp_adapter *adapter = req->adapter;
|
||||
struct zfcp_send_ct *send_ct = req->data;
|
||||
struct zfcp_fsf_ct_els *ct = req->data;
|
||||
struct fsf_qtcb_header *header = &req->qtcb->header;
|
||||
|
||||
send_ct->status = -EINVAL;
|
||||
ct->status = -EINVAL;
|
||||
|
||||
if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
|
||||
goto skip_fsfstatus;
|
||||
|
|
@ -969,7 +970,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);
|
||||
send_ct->status = 0;
|
||||
ct->status = 0;
|
||||
break;
|
||||
case FSF_SERVICE_CLASS_NOT_SUPPORTED:
|
||||
zfcp_fsf_class_not_supp(req);
|
||||
|
|
@ -985,8 +986,7 @@ static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req)
|
|||
case FSF_ACCESS_DENIED:
|
||||
break;
|
||||
case FSF_PORT_BOXED:
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR |
|
||||
ZFCP_STATUS_FSFREQ_RETRY;
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
|
||||
break;
|
||||
case FSF_PORT_HANDLE_NOT_VALID:
|
||||
zfcp_erp_adapter_reopen(adapter, 0, "fsscth1", req);
|
||||
|
|
@ -1001,8 +1001,8 @@ static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req)
|
|||
}
|
||||
|
||||
skip_fsfstatus:
|
||||
if (send_ct->handler)
|
||||
send_ct->handler(send_ct->handler_data);
|
||||
if (ct->handler)
|
||||
ct->handler(ct->handler_data);
|
||||
}
|
||||
|
||||
static void zfcp_fsf_setup_ct_els_unchained(struct qdio_buffer_element *sbale,
|
||||
|
|
@ -1071,15 +1071,17 @@ static int zfcp_fsf_setup_ct_els(struct zfcp_fsf_req *req,
|
|||
int max_sbals)
|
||||
{
|
||||
int ret;
|
||||
unsigned int fcp_chan_timeout;
|
||||
|
||||
ret = zfcp_fsf_setup_ct_els_sbals(req, sg_req, sg_resp, max_sbals);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* common settings for ct/gs and els requests */
|
||||
fcp_chan_timeout = 2 * FC_DEF_R_A_TOV / 1000;
|
||||
req->qtcb->bottom.support.service_class = FSF_CLASS_3;
|
||||
req->qtcb->bottom.support.timeout = 2 * R_A_TOV;
|
||||
zfcp_fsf_start_timer(req, (2 * R_A_TOV + 10) * HZ);
|
||||
req->qtcb->bottom.support.timeout = fcp_chan_timeout;
|
||||
zfcp_fsf_start_timer(req, (fcp_chan_timeout + 10) * HZ);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1089,9 +1091,9 @@ static int zfcp_fsf_setup_ct_els(struct zfcp_fsf_req *req,
|
|||
* @ct: pointer to struct zfcp_send_ct with data for request
|
||||
* @pool: if non-null this mempool is used to allocate struct zfcp_fsf_req
|
||||
*/
|
||||
int zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool)
|
||||
int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *wka_port,
|
||||
struct zfcp_fsf_ct_els *ct, mempool_t *pool)
|
||||
{
|
||||
struct zfcp_wka_port *wka_port = ct->wka_port;
|
||||
struct zfcp_qdio *qdio = wka_port->adapter->qdio;
|
||||
struct zfcp_fsf_req *req;
|
||||
int ret = -EIO;
|
||||
|
|
@ -1117,7 +1119,7 @@ int zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool)
|
|||
req->qtcb->header.port_handle = wka_port->handle;
|
||||
req->data = ct;
|
||||
|
||||
zfcp_dbf_san_ct_request(req);
|
||||
zfcp_dbf_san_ct_request(req, wka_port->d_id);
|
||||
|
||||
ret = zfcp_fsf_req_send(req);
|
||||
if (ret)
|
||||
|
|
@ -1134,7 +1136,7 @@ out:
|
|||
|
||||
static void zfcp_fsf_send_els_handler(struct zfcp_fsf_req *req)
|
||||
{
|
||||
struct zfcp_send_els *send_els = req->data;
|
||||
struct zfcp_fsf_ct_els *send_els = req->data;
|
||||
struct zfcp_port *port = send_els->port;
|
||||
struct fsf_qtcb_header *header = &req->qtcb->header;
|
||||
|
||||
|
|
@ -1154,9 +1156,6 @@ static void zfcp_fsf_send_els_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:
|
||||
if (port && (send_els->ls_code != ZFCP_LS_ADISC))
|
||||
zfcp_fc_test_link(port);
|
||||
/*fall through */
|
||||
case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
|
||||
case FSF_SQ_RETRY_IF_POSSIBLE:
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
|
||||
|
|
@ -1188,10 +1187,11 @@ skip_fsfstatus:
|
|||
* zfcp_fsf_send_els - initiate an ELS command (FC-FS)
|
||||
* @els: pointer to struct zfcp_send_els with data for the command
|
||||
*/
|
||||
int zfcp_fsf_send_els(struct zfcp_send_els *els)
|
||||
int zfcp_fsf_send_els(struct zfcp_adapter *adapter, u32 d_id,
|
||||
struct zfcp_fsf_ct_els *els)
|
||||
{
|
||||
struct zfcp_fsf_req *req;
|
||||
struct zfcp_qdio *qdio = els->adapter->qdio;
|
||||
struct zfcp_qdio *qdio = adapter->qdio;
|
||||
int ret = -EIO;
|
||||
|
||||
spin_lock_bh(&qdio->req_q_lock);
|
||||
|
|
@ -1211,7 +1211,7 @@ int zfcp_fsf_send_els(struct zfcp_send_els *els)
|
|||
if (ret)
|
||||
goto failed_send;
|
||||
|
||||
req->qtcb->bottom.support.d_id = els->d_id;
|
||||
hton24(req->qtcb->bottom.support.d_id, d_id);
|
||||
req->handler = zfcp_fsf_send_els_handler;
|
||||
req->data = els;
|
||||
|
||||
|
|
@ -1422,7 +1422,7 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req)
|
|||
{
|
||||
struct zfcp_port *port = req->data;
|
||||
struct fsf_qtcb_header *header = &req->qtcb->header;
|
||||
struct fsf_plogi *plogi;
|
||||
struct fc_els_flogi *plogi;
|
||||
|
||||
if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
|
||||
goto out;
|
||||
|
|
@ -1472,23 +1472,10 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req)
|
|||
* another GID_PN straight after a port has been opened.
|
||||
* Alternately, an ADISC/PDISC ELS should suffice, as well.
|
||||
*/
|
||||
plogi = (struct fsf_plogi *) req->qtcb->bottom.support.els;
|
||||
plogi = (struct fc_els_flogi *) req->qtcb->bottom.support.els;
|
||||
if (req->qtcb->bottom.support.els1_length >=
|
||||
FSF_PLOGI_MIN_LEN) {
|
||||
if (plogi->serv_param.wwpn != port->wwpn) {
|
||||
port->d_id = 0;
|
||||
dev_warn(&port->adapter->ccw_device->dev,
|
||||
"A port opened with WWPN 0x%016Lx "
|
||||
"returned data that identifies it as "
|
||||
"WWPN 0x%016Lx\n",
|
||||
(unsigned long long) port->wwpn,
|
||||
(unsigned long long)
|
||||
plogi->serv_param.wwpn);
|
||||
} else {
|
||||
port->wwnn = plogi->serv_param.wwnn;
|
||||
FSF_PLOGI_MIN_LEN)
|
||||
zfcp_fc_plogi_evaluate(port, plogi);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FSF_UNKNOWN_OP_SUBTYPE:
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
|
||||
|
|
@ -1496,7 +1483,7 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req)
|
|||
}
|
||||
|
||||
out:
|
||||
zfcp_port_put(port);
|
||||
put_device(&port->sysfs_device);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1530,18 +1517,18 @@ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
|
|||
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
|
||||
|
||||
req->handler = zfcp_fsf_open_port_handler;
|
||||
req->qtcb->bottom.support.d_id = port->d_id;
|
||||
hton24(req->qtcb->bottom.support.d_id, port->d_id);
|
||||
req->data = port;
|
||||
req->erp_action = erp_action;
|
||||
erp_action->fsf_req = req;
|
||||
zfcp_port_get(port);
|
||||
get_device(&port->sysfs_device);
|
||||
|
||||
zfcp_fsf_start_erp_timer(req);
|
||||
retval = zfcp_fsf_req_send(req);
|
||||
if (retval) {
|
||||
zfcp_fsf_req_free(req);
|
||||
erp_action->fsf_req = NULL;
|
||||
zfcp_port_put(port);
|
||||
put_device(&port->sysfs_device);
|
||||
}
|
||||
out:
|
||||
spin_unlock_bh(&qdio->req_q_lock);
|
||||
|
|
@ -1618,11 +1605,11 @@ out:
|
|||
|
||||
static void zfcp_fsf_open_wka_port_handler(struct zfcp_fsf_req *req)
|
||||
{
|
||||
struct zfcp_wka_port *wka_port = req->data;
|
||||
struct zfcp_fc_wka_port *wka_port = req->data;
|
||||
struct fsf_qtcb_header *header = &req->qtcb->header;
|
||||
|
||||
if (req->status & ZFCP_STATUS_FSFREQ_ERROR) {
|
||||
wka_port->status = ZFCP_WKA_PORT_OFFLINE;
|
||||
wka_port->status = ZFCP_FC_WKA_PORT_OFFLINE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
@ -1635,13 +1622,13 @@ static void zfcp_fsf_open_wka_port_handler(struct zfcp_fsf_req *req)
|
|||
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
|
||||
/* fall through */
|
||||
case FSF_ACCESS_DENIED:
|
||||
wka_port->status = ZFCP_WKA_PORT_OFFLINE;
|
||||
wka_port->status = ZFCP_FC_WKA_PORT_OFFLINE;
|
||||
break;
|
||||
case FSF_GOOD:
|
||||
wka_port->handle = header->port_handle;
|
||||
/* fall through */
|
||||
case FSF_PORT_ALREADY_OPEN:
|
||||
wka_port->status = ZFCP_WKA_PORT_ONLINE;
|
||||
wka_port->status = ZFCP_FC_WKA_PORT_ONLINE;
|
||||
}
|
||||
out:
|
||||
wake_up(&wka_port->completion_wq);
|
||||
|
|
@ -1649,10 +1636,10 @@ out:
|
|||
|
||||
/**
|
||||
* zfcp_fsf_open_wka_port - create and send open wka-port request
|
||||
* @wka_port: pointer to struct zfcp_wka_port
|
||||
* @wka_port: pointer to struct zfcp_fc_wka_port
|
||||
* Returns: 0 on success, error otherwise
|
||||
*/
|
||||
int zfcp_fsf_open_wka_port(struct zfcp_wka_port *wka_port)
|
||||
int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *wka_port)
|
||||
{
|
||||
struct qdio_buffer_element *sbale;
|
||||
struct zfcp_qdio *qdio = wka_port->adapter->qdio;
|
||||
|
|
@ -1677,7 +1664,7 @@ int zfcp_fsf_open_wka_port(struct zfcp_wka_port *wka_port)
|
|||
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
|
||||
|
||||
req->handler = zfcp_fsf_open_wka_port_handler;
|
||||
req->qtcb->bottom.support.d_id = wka_port->d_id;
|
||||
hton24(req->qtcb->bottom.support.d_id, wka_port->d_id);
|
||||
req->data = wka_port;
|
||||
|
||||
zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
|
||||
|
|
@ -1691,23 +1678,23 @@ out:
|
|||
|
||||
static void zfcp_fsf_close_wka_port_handler(struct zfcp_fsf_req *req)
|
||||
{
|
||||
struct zfcp_wka_port *wka_port = req->data;
|
||||
struct zfcp_fc_wka_port *wka_port = req->data;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
wka_port->status = ZFCP_WKA_PORT_OFFLINE;
|
||||
wka_port->status = ZFCP_FC_WKA_PORT_OFFLINE;
|
||||
wake_up(&wka_port->completion_wq);
|
||||
}
|
||||
|
||||
/**
|
||||
* zfcp_fsf_close_wka_port - create and send close wka port request
|
||||
* @erp_action: pointer to struct zfcp_erp_action
|
||||
* @wka_port: WKA port to open
|
||||
* Returns: 0 on success, error otherwise
|
||||
*/
|
||||
int zfcp_fsf_close_wka_port(struct zfcp_wka_port *wka_port)
|
||||
int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *wka_port)
|
||||
{
|
||||
struct qdio_buffer_element *sbale;
|
||||
struct zfcp_qdio *qdio = wka_port->adapter->qdio;
|
||||
|
|
@ -1765,13 +1752,13 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req)
|
|||
/* 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);
|
||||
list_for_each_entry(unit, &port->unit_list_head, list)
|
||||
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);
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR |
|
||||
ZFCP_STATUS_FSFREQ_RETRY;
|
||||
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
|
||||
break;
|
||||
case FSF_ADAPTER_STATUS_AVAILABLE:
|
||||
switch (header->fsf_status_qual.word[0]) {
|
||||
|
|
@ -1787,9 +1774,11 @@ 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);
|
||||
list_for_each_entry(unit, &port->unit_list_head, list)
|
||||
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);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -1873,8 +1862,7 @@ static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req)
|
|||
break;
|
||||
case FSF_PORT_BOXED:
|
||||
zfcp_erp_port_boxed(unit->port, "fsouh_2", req);
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR |
|
||||
ZFCP_STATUS_FSFREQ_RETRY;
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
|
||||
break;
|
||||
case FSF_LUN_SHARING_VIOLATION:
|
||||
if (header->fsf_status_qual.word[0])
|
||||
|
|
@ -2036,8 +2024,7 @@ static void zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *req)
|
|||
break;
|
||||
case FSF_PORT_BOXED:
|
||||
zfcp_erp_port_boxed(unit->port, "fscuh_3", req);
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR |
|
||||
ZFCP_STATUS_FSFREQ_RETRY;
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
|
||||
break;
|
||||
case FSF_ADAPTER_STATUS_AVAILABLE:
|
||||
switch (req->qtcb->header.fsf_status_qual.word[0]) {
|
||||
|
|
@ -2109,72 +2096,57 @@ static void zfcp_fsf_update_lat(struct fsf_latency_record *lat_rec, u32 lat)
|
|||
lat_rec->max = max(lat_rec->max, lat);
|
||||
}
|
||||
|
||||
static void zfcp_fsf_req_latency(struct zfcp_fsf_req *req)
|
||||
static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi)
|
||||
{
|
||||
struct fsf_qual_latency_info *lat_inf;
|
||||
struct latency_cont *lat;
|
||||
struct fsf_qual_latency_info *lat_in;
|
||||
struct latency_cont *lat = NULL;
|
||||
struct zfcp_unit *unit = req->unit;
|
||||
struct zfcp_blk_drv_data blktrc;
|
||||
int ticks = req->adapter->timer_ticks;
|
||||
|
||||
lat_inf = &req->qtcb->prefix.prot_status_qual.latency_info;
|
||||
lat_in = &req->qtcb->prefix.prot_status_qual.latency_info;
|
||||
|
||||
switch (req->qtcb->bottom.io.data_direction) {
|
||||
case FSF_DATADIR_READ:
|
||||
lat = &unit->latencies.read;
|
||||
break;
|
||||
case FSF_DATADIR_WRITE:
|
||||
lat = &unit->latencies.write;
|
||||
break;
|
||||
case FSF_DATADIR_CMND:
|
||||
lat = &unit->latencies.cmd;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
blktrc.flags = 0;
|
||||
blktrc.magic = ZFCP_BLK_DRV_DATA_MAGIC;
|
||||
if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
|
||||
blktrc.flags |= ZFCP_BLK_REQ_ERROR;
|
||||
blktrc.inb_usage = req->queue_req.qdio_inb_usage;
|
||||
blktrc.outb_usage = req->queue_req.qdio_outb_usage;
|
||||
|
||||
if (req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA) {
|
||||
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_READ:
|
||||
lat = &unit->latencies.read;
|
||||
break;
|
||||
case FSF_DATADIR_WRITE:
|
||||
lat = &unit->latencies.write;
|
||||
break;
|
||||
case FSF_DATADIR_CMND:
|
||||
lat = &unit->latencies.cmd;
|
||||
break;
|
||||
}
|
||||
|
||||
if (lat) {
|
||||
spin_lock(&unit->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_lock(&unit->latencies.lock);
|
||||
zfcp_fsf_update_lat(&lat->channel, lat_inf->channel_lat);
|
||||
zfcp_fsf_update_lat(&lat->fabric, lat_inf->fabric_lat);
|
||||
lat->counter++;
|
||||
spin_unlock(&unit->latencies.lock);
|
||||
blk_add_driver_data(scsi->request->q, scsi->request, &blktrc,
|
||||
sizeof(blktrc));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BLK_DEV_IO_TRACE
|
||||
static void zfcp_fsf_trace_latency(struct zfcp_fsf_req *fsf_req)
|
||||
{
|
||||
struct fsf_qual_latency_info *lat_inf;
|
||||
struct scsi_cmnd *scsi_cmnd = (struct scsi_cmnd *)fsf_req->data;
|
||||
struct request *req = scsi_cmnd->request;
|
||||
struct zfcp_blk_drv_data trace;
|
||||
int ticks = fsf_req->adapter->timer_ticks;
|
||||
|
||||
trace.flags = 0;
|
||||
trace.magic = ZFCP_BLK_DRV_DATA_MAGIC;
|
||||
if (fsf_req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA) {
|
||||
trace.flags |= ZFCP_BLK_LAT_VALID;
|
||||
lat_inf = &fsf_req->qtcb->prefix.prot_status_qual.latency_info;
|
||||
trace.channel_lat = lat_inf->channel_lat * ticks;
|
||||
trace.fabric_lat = lat_inf->fabric_lat * ticks;
|
||||
}
|
||||
if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)
|
||||
trace.flags |= ZFCP_BLK_REQ_ERROR;
|
||||
trace.inb_usage = fsf_req->queue_req.qdio_inb_usage;
|
||||
trace.outb_usage = fsf_req->queue_req.qdio_outb_usage;
|
||||
|
||||
blk_add_driver_data(req->q, req, &trace, sizeof(trace));
|
||||
}
|
||||
#else
|
||||
static inline void zfcp_fsf_trace_latency(struct zfcp_fsf_req *fsf_req)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
static void zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *req)
|
||||
{
|
||||
struct scsi_cmnd *scpnt;
|
||||
struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *)
|
||||
&(req->qtcb->bottom.io.fcp_rsp);
|
||||
u32 sns_len;
|
||||
char *fcp_rsp_info = (unsigned char *) &fcp_rsp_iu[1];
|
||||
struct fcp_resp_with_ext *fcp_rsp;
|
||||
unsigned long flags;
|
||||
|
||||
read_lock_irqsave(&req->adapter->abort_lock, flags);
|
||||
|
|
@ -2185,50 +2157,16 @@ static void zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *req)
|
|||
return;
|
||||
}
|
||||
|
||||
if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ABORTED)) {
|
||||
set_host_byte(scpnt, DID_SOFT_ERROR);
|
||||
goto skip_fsfstatus;
|
||||
}
|
||||
|
||||
if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
|
||||
set_host_byte(scpnt, DID_ERROR);
|
||||
set_host_byte(scpnt, DID_TRANSPORT_DISRUPTED);
|
||||
goto skip_fsfstatus;
|
||||
}
|
||||
|
||||
set_msg_byte(scpnt, COMMAND_COMPLETE);
|
||||
fcp_rsp = (struct fcp_resp_with_ext *) &req->qtcb->bottom.io.fcp_rsp;
|
||||
zfcp_fc_eval_fcp_rsp(fcp_rsp, scpnt);
|
||||
|
||||
scpnt->result |= fcp_rsp_iu->scsi_status;
|
||||
zfcp_fsf_req_trace(req, scpnt);
|
||||
|
||||
if (req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA)
|
||||
zfcp_fsf_req_latency(req);
|
||||
|
||||
zfcp_fsf_trace_latency(req);
|
||||
|
||||
if (unlikely(fcp_rsp_iu->validity.bits.fcp_rsp_len_valid)) {
|
||||
if (fcp_rsp_info[3] == RSP_CODE_GOOD)
|
||||
set_host_byte(scpnt, DID_OK);
|
||||
else {
|
||||
set_host_byte(scpnt, DID_ERROR);
|
||||
goto skip_fsfstatus;
|
||||
}
|
||||
}
|
||||
|
||||
if (unlikely(fcp_rsp_iu->validity.bits.fcp_sns_len_valid)) {
|
||||
sns_len = FSF_FCP_RSP_SIZE - sizeof(struct fcp_rsp_iu) +
|
||||
fcp_rsp_iu->fcp_rsp_len;
|
||||
sns_len = min(sns_len, (u32) SCSI_SENSE_BUFFERSIZE);
|
||||
sns_len = min(sns_len, fcp_rsp_iu->fcp_sns_len);
|
||||
|
||||
memcpy(scpnt->sense_buffer,
|
||||
zfcp_get_fcp_sns_info_ptr(fcp_rsp_iu), sns_len);
|
||||
}
|
||||
|
||||
if (unlikely(fcp_rsp_iu->validity.bits.fcp_resid_under)) {
|
||||
scsi_set_resid(scpnt, fcp_rsp_iu->fcp_resid);
|
||||
if (scsi_bufflen(scpnt) - scsi_get_resid(scpnt) <
|
||||
scpnt->underflow)
|
||||
set_host_byte(scpnt, DID_ERROR);
|
||||
}
|
||||
skip_fsfstatus:
|
||||
if (scpnt->result != 0)
|
||||
zfcp_dbf_scsi_result("erro", 3, req->adapter->dbf, scpnt, req);
|
||||
|
|
@ -2250,11 +2188,13 @@ skip_fsfstatus:
|
|||
|
||||
static void zfcp_fsf_send_fcp_ctm_handler(struct zfcp_fsf_req *req)
|
||||
{
|
||||
struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *)
|
||||
&(req->qtcb->bottom.io.fcp_rsp);
|
||||
char *fcp_rsp_info = (unsigned char *) &fcp_rsp_iu[1];
|
||||
struct fcp_resp_with_ext *fcp_rsp;
|
||||
struct fcp_resp_rsp_info *rsp_info;
|
||||
|
||||
if ((fcp_rsp_info[3] != RSP_CODE_GOOD) ||
|
||||
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;
|
||||
}
|
||||
|
|
@ -2314,13 +2254,11 @@ static void zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *req)
|
|||
break;
|
||||
case FSF_PORT_BOXED:
|
||||
zfcp_erp_port_boxed(unit->port, "fssfch5", req);
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR |
|
||||
ZFCP_STATUS_FSFREQ_RETRY;
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
|
||||
break;
|
||||
case FSF_LUN_BOXED:
|
||||
zfcp_erp_unit_boxed(unit, "fssfch6", req);
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR |
|
||||
ZFCP_STATUS_FSFREQ_RETRY;
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
|
||||
break;
|
||||
case FSF_ADAPTER_STATUS_AVAILABLE:
|
||||
if (header->fsf_status_qual.word[0] ==
|
||||
|
|
@ -2335,24 +2273,10 @@ skip_fsfstatus:
|
|||
else {
|
||||
zfcp_fsf_send_fcp_command_task_handler(req);
|
||||
req->unit = NULL;
|
||||
zfcp_unit_put(unit);
|
||||
put_device(&unit->sysfs_device);
|
||||
}
|
||||
}
|
||||
|
||||
static void zfcp_set_fcp_dl(struct fcp_cmnd_iu *fcp_cmd, u32 fcp_dl)
|
||||
{
|
||||
u32 *fcp_dl_ptr;
|
||||
|
||||
/*
|
||||
* fcp_dl_addr = start address of fcp_cmnd structure +
|
||||
* size of fixed part + size of dynamically sized add_dcp_cdb field
|
||||
* SEE FCP-2 documentation
|
||||
*/
|
||||
fcp_dl_ptr = (u32 *) ((unsigned char *) &fcp_cmd[1] +
|
||||
(fcp_cmd->add_fcp_cdb_length << 2));
|
||||
*fcp_dl_ptr = fcp_dl;
|
||||
}
|
||||
|
||||
/**
|
||||
* zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command)
|
||||
* @unit: unit where command is sent to
|
||||
|
|
@ -2362,7 +2286,7 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
|
|||
struct scsi_cmnd *scsi_cmnd)
|
||||
{
|
||||
struct zfcp_fsf_req *req;
|
||||
struct fcp_cmnd_iu *fcp_cmnd_iu;
|
||||
struct fcp_cmnd *fcp_cmnd;
|
||||
unsigned int sbtype = SBAL_FLAGS0_TYPE_READ;
|
||||
int real_bytes, retval = -EIO;
|
||||
struct zfcp_adapter *adapter = unit->port->adapter;
|
||||
|
|
@ -2387,23 +2311,21 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
|
|||
}
|
||||
|
||||
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
|
||||
zfcp_unit_get(unit);
|
||||
get_device(&unit->sysfs_device);
|
||||
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;
|
||||
|
||||
fcp_cmnd_iu = (struct fcp_cmnd_iu *) &(req->qtcb->bottom.io.fcp_cmnd);
|
||||
fcp_cmnd_iu->fcp_lun = unit->fcp_lun;
|
||||
/*
|
||||
* set depending on data direction:
|
||||
* data direction bits in SBALE (SB Type)
|
||||
* data direction bits in QTCB
|
||||
* data direction bits in FCP_CMND IU
|
||||
*/
|
||||
switch (scsi_cmnd->sc_data_direction) {
|
||||
case DMA_NONE:
|
||||
|
|
@ -2411,32 +2333,17 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
|
|||
break;
|
||||
case DMA_FROM_DEVICE:
|
||||
req->qtcb->bottom.io.data_direction = FSF_DATADIR_READ;
|
||||
fcp_cmnd_iu->rddata = 1;
|
||||
break;
|
||||
case DMA_TO_DEVICE:
|
||||
req->qtcb->bottom.io.data_direction = FSF_DATADIR_WRITE;
|
||||
sbtype = SBAL_FLAGS0_TYPE_WRITE;
|
||||
fcp_cmnd_iu->wddata = 1;
|
||||
break;
|
||||
case DMA_BIDIRECTIONAL:
|
||||
goto failed_scsi_cmnd;
|
||||
}
|
||||
|
||||
if (likely((scsi_cmnd->device->simple_tags) ||
|
||||
((atomic_read(&unit->status) & ZFCP_STATUS_UNIT_READONLY) &&
|
||||
(atomic_read(&unit->status) & ZFCP_STATUS_UNIT_SHARED))))
|
||||
fcp_cmnd_iu->task_attribute = SIMPLE_Q;
|
||||
else
|
||||
fcp_cmnd_iu->task_attribute = UNTAGGED;
|
||||
|
||||
if (unlikely(scsi_cmnd->cmd_len > FCP_CDB_LENGTH))
|
||||
fcp_cmnd_iu->add_fcp_cdb_length =
|
||||
(scsi_cmnd->cmd_len - FCP_CDB_LENGTH) >> 2;
|
||||
|
||||
memcpy(fcp_cmnd_iu->fcp_cdb, scsi_cmnd->cmnd, scsi_cmnd->cmd_len);
|
||||
|
||||
req->qtcb->bottom.io.fcp_cmnd_length = sizeof(struct fcp_cmnd_iu) +
|
||||
fcp_cmnd_iu->add_fcp_cdb_length + sizeof(u32);
|
||||
fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd;
|
||||
zfcp_fc_scsi_to_fcp(fcp_cmnd, scsi_cmnd);
|
||||
|
||||
real_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->queue_req, sbtype,
|
||||
scsi_sglist(scsi_cmnd),
|
||||
|
|
@ -2454,8 +2361,6 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
|
|||
goto failed_scsi_cmnd;
|
||||
}
|
||||
|
||||
zfcp_set_fcp_dl(fcp_cmnd_iu, real_bytes);
|
||||
|
||||
retval = zfcp_fsf_req_send(req);
|
||||
if (unlikely(retval))
|
||||
goto failed_scsi_cmnd;
|
||||
|
|
@ -2463,7 +2368,7 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
|
|||
goto out;
|
||||
|
||||
failed_scsi_cmnd:
|
||||
zfcp_unit_put(unit);
|
||||
put_device(&unit->sysfs_device);
|
||||
zfcp_fsf_req_free(req);
|
||||
scsi_cmnd->host_scribble = NULL;
|
||||
out:
|
||||
|
|
@ -2481,7 +2386,7 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags)
|
|||
{
|
||||
struct qdio_buffer_element *sbale;
|
||||
struct zfcp_fsf_req *req = NULL;
|
||||
struct fcp_cmnd_iu *fcp_cmnd_iu;
|
||||
struct fcp_cmnd *fcp_cmnd;
|
||||
struct zfcp_qdio *qdio = unit->port->adapter->qdio;
|
||||
|
||||
if (unlikely(!(atomic_read(&unit->status) &
|
||||
|
|
@ -2507,16 +2412,14 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags)
|
|||
req->qtcb->header.port_handle = unit->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 = sizeof(struct fcp_cmnd_iu) +
|
||||
sizeof(u32);
|
||||
req->qtcb->bottom.io.fcp_cmnd_length = FCP_CMND_LEN;
|
||||
|
||||
sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req);
|
||||
sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE;
|
||||
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
|
||||
|
||||
fcp_cmnd_iu = (struct fcp_cmnd_iu *) &req->qtcb->bottom.io.fcp_cmnd;
|
||||
fcp_cmnd_iu->fcp_lun = unit->fcp_lun;
|
||||
fcp_cmnd_iu->task_management_flags = tm_flags;
|
||||
fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd;
|
||||
zfcp_fc_fcp_tm(fcp_cmnd, unit->device, tm_flags);
|
||||
|
||||
zfcp_fsf_start_timer(req, ZFCP_SCSI_ER_TIMEOUT);
|
||||
if (!zfcp_fsf_req_send(req))
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include <linux/pfn.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <scsi/libfc.h>
|
||||
|
||||
#define FSF_QTCB_CURRENT_VERSION 0x00000001
|
||||
|
||||
|
|
@ -228,7 +229,8 @@ struct fsf_status_read_buffer {
|
|||
u32 length;
|
||||
u32 res1;
|
||||
struct fsf_queue_designator queue_designator;
|
||||
u32 d_id;
|
||||
u8 res2;
|
||||
u8 d_id[3];
|
||||
u32 class;
|
||||
u64 fcp_lun;
|
||||
u8 res3[24];
|
||||
|
|
@ -309,22 +311,7 @@ struct fsf_qtcb_header {
|
|||
u8 res4[16];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct fsf_nport_serv_param {
|
||||
u8 common_serv_param[16];
|
||||
u64 wwpn;
|
||||
u64 wwnn;
|
||||
u8 class1_serv_param[16];
|
||||
u8 class2_serv_param[16];
|
||||
u8 class3_serv_param[16];
|
||||
u8 class4_serv_param[16];
|
||||
u8 vendor_version_level[16];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define FSF_PLOGI_MIN_LEN 112
|
||||
struct fsf_plogi {
|
||||
u32 code;
|
||||
struct fsf_nport_serv_param serv_param;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define FSF_FCP_CMND_SIZE 288
|
||||
#define FSF_FCP_RSP_SIZE 128
|
||||
|
|
@ -342,8 +329,8 @@ struct fsf_qtcb_bottom_io {
|
|||
|
||||
struct fsf_qtcb_bottom_support {
|
||||
u32 operation_subtype;
|
||||
u8 res1[12];
|
||||
u32 d_id;
|
||||
u8 res1[13];
|
||||
u8 d_id[3];
|
||||
u32 option;
|
||||
u64 fcp_lun;
|
||||
u64 res2;
|
||||
|
|
@ -372,18 +359,18 @@ struct fsf_qtcb_bottom_config {
|
|||
u32 fc_topology;
|
||||
u32 fc_link_speed;
|
||||
u32 adapter_type;
|
||||
u32 peer_d_id;
|
||||
u8 res0;
|
||||
u8 peer_d_id[3];
|
||||
u8 res1[2];
|
||||
u16 timer_interval;
|
||||
u8 res2[8];
|
||||
u32 s_id;
|
||||
struct fsf_nport_serv_param nport_serv_param;
|
||||
u8 reserved_nport_serv_param[16];
|
||||
u8 res2[9];
|
||||
u8 s_id[3];
|
||||
u8 nport_serv_param[128];
|
||||
u8 res3[8];
|
||||
u32 adapter_ports;
|
||||
u32 hardware_version;
|
||||
u8 serial_number[32];
|
||||
struct fsf_nport_serv_param plogi_payload;
|
||||
u8 plogi_payload[112];
|
||||
struct fsf_statistics_info stat_info;
|
||||
u8 res4[112];
|
||||
} __attribute__ ((packed));
|
||||
|
|
@ -450,4 +437,22 @@ struct zfcp_blk_drv_data {
|
|||
u64 fabric_lat;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/**
|
||||
* struct zfcp_fsf_ct_els - zfcp data for ct or els request
|
||||
* @req: scatter-gather list for request
|
||||
* @resp: scatter-gather list for response
|
||||
* @handler: handler function (called for response to the request)
|
||||
* @handler_data: data passed to handler function
|
||||
* @port: Optional pointer to port for zfcp internal ELS (only test link ADISC)
|
||||
* @status: used to pass error status to calling function
|
||||
*/
|
||||
struct zfcp_fsf_ct_els {
|
||||
struct scatterlist *req;
|
||||
struct scatterlist *resp;
|
||||
void (*handler)(void *);
|
||||
void *handler_data;
|
||||
struct zfcp_port *port;
|
||||
int status;
|
||||
};
|
||||
|
||||
#endif /* FSF_H */
|
||||
|
|
|
|||
|
|
@ -9,29 +9,33 @@
|
|||
#define KMSG_COMPONENT "zfcp"
|
||||
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <scsi/fc/fc_fcp.h>
|
||||
#include <asm/atomic.h>
|
||||
#include "zfcp_ext.h"
|
||||
#include "zfcp_dbf.h"
|
||||
#include "zfcp_fc.h"
|
||||
|
||||
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");
|
||||
|
||||
/* Find start of Sense Information in FCP response unit*/
|
||||
char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *fcp_rsp_iu)
|
||||
static int zfcp_scsi_change_queue_depth(struct scsi_device *sdev, int depth,
|
||||
int reason)
|
||||
{
|
||||
char *fcp_sns_info_ptr;
|
||||
|
||||
fcp_sns_info_ptr = (unsigned char *) &fcp_rsp_iu[1];
|
||||
if (fcp_rsp_iu->validity.bits.fcp_rsp_len_valid)
|
||||
fcp_sns_info_ptr += fcp_rsp_iu->fcp_rsp_len;
|
||||
|
||||
return fcp_sns_info_ptr;
|
||||
}
|
||||
|
||||
static int zfcp_scsi_change_queue_depth(struct scsi_device *sdev, int depth)
|
||||
{
|
||||
scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
|
||||
switch (reason) {
|
||||
case SCSI_QDEPTH_DEFAULT:
|
||||
scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
|
||||
break;
|
||||
case SCSI_QDEPTH_QFULL:
|
||||
scsi_track_queue_full(sdev, depth);
|
||||
break;
|
||||
case SCSI_QDEPTH_RAMP_UP:
|
||||
scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
return sdev->queue_depth;
|
||||
}
|
||||
|
||||
|
|
@ -39,7 +43,7 @@ static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt)
|
|||
{
|
||||
struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata;
|
||||
unit->device = NULL;
|
||||
zfcp_unit_put(unit);
|
||||
put_device(&unit->sysfs_device);
|
||||
}
|
||||
|
||||
static int zfcp_scsi_slave_configure(struct scsi_device *sdp)
|
||||
|
|
@ -99,12 +103,26 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
|
|||
}
|
||||
|
||||
status = atomic_read(&unit->status);
|
||||
if (unlikely((status & ZFCP_STATUS_COMMON_ERP_FAILED) ||
|
||||
!(status & ZFCP_STATUS_COMMON_RUNNING))) {
|
||||
if (unlikely(status & ZFCP_STATUS_COMMON_ERP_FAILED) &&
|
||||
!(atomic_read(&unit->port->status) &
|
||||
ZFCP_STATUS_COMMON_ERP_FAILED)) {
|
||||
/* only unit access denied, but port is good
|
||||
* not covered by FC transport, have to fail here */
|
||||
zfcp_scsi_command_fail(scpnt, DID_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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
|
||||
* call to rport_delete pending: mimic retry from
|
||||
* fc_remote_port_chkready until rport is BLOCKED
|
||||
*/
|
||||
zfcp_scsi_command_fail(scpnt, DID_IMM_RETRY);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = zfcp_fsf_send_fcp_command_task(unit, scpnt);
|
||||
if (unlikely(ret == -EBUSY))
|
||||
return SCSI_MLQUEUE_DEVICE_BUSY;
|
||||
|
|
@ -115,49 +133,44 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
|
|||
}
|
||||
|
||||
static struct zfcp_unit *zfcp_unit_lookup(struct zfcp_adapter *adapter,
|
||||
int channel, unsigned int id,
|
||||
unsigned int lun)
|
||||
unsigned int id, u64 lun)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct zfcp_port *port;
|
||||
struct zfcp_unit *unit;
|
||||
int scsi_lun;
|
||||
struct zfcp_unit *unit = NULL;
|
||||
|
||||
list_for_each_entry(port, &adapter->port_list_head, list) {
|
||||
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;
|
||||
list_for_each_entry(unit, &port->unit_list_head, list) {
|
||||
scsi_lun = scsilun_to_int(
|
||||
(struct scsi_lun *)&unit->fcp_lun);
|
||||
if (lun == scsi_lun)
|
||||
return unit;
|
||||
}
|
||||
unit = zfcp_get_unit_by_lun(port, lun);
|
||||
if (unit)
|
||||
break;
|
||||
}
|
||||
read_unlock_irqrestore(&adapter->port_list_lock, flags);
|
||||
|
||||
return NULL;
|
||||
return unit;
|
||||
}
|
||||
|
||||
static int zfcp_scsi_slave_alloc(struct scsi_device *sdp)
|
||||
{
|
||||
struct zfcp_adapter *adapter;
|
||||
struct zfcp_unit *unit;
|
||||
unsigned long flags;
|
||||
int retval = -ENXIO;
|
||||
u64 lun;
|
||||
|
||||
adapter = (struct zfcp_adapter *) sdp->host->hostdata[0];
|
||||
if (!adapter)
|
||||
goto out;
|
||||
|
||||
read_lock_irqsave(&zfcp_data.config_lock, flags);
|
||||
unit = zfcp_unit_lookup(adapter, sdp->channel, sdp->id, sdp->lun);
|
||||
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;
|
||||
zfcp_unit_get(unit);
|
||||
retval = 0;
|
||||
return 0;
|
||||
}
|
||||
read_unlock_irqrestore(&zfcp_data.config_lock, flags);
|
||||
out:
|
||||
return retval;
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
|
||||
|
|
@ -196,6 +209,7 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
|
|||
break;
|
||||
|
||||
zfcp_erp_wait(adapter);
|
||||
fc_block_scsi_eh(scpnt);
|
||||
if (!(atomic_read(&adapter->status) &
|
||||
ZFCP_STATUS_COMMON_RUNNING)) {
|
||||
zfcp_dbf_scsi_abort("nres", adapter->dbf, scpnt, NULL,
|
||||
|
|
@ -235,6 +249,7 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags)
|
|||
break;
|
||||
|
||||
zfcp_erp_wait(adapter);
|
||||
fc_block_scsi_eh(scpnt);
|
||||
if (!(atomic_read(&adapter->status) &
|
||||
ZFCP_STATUS_COMMON_RUNNING)) {
|
||||
zfcp_dbf_scsi_devreset("nres", tm_flags, unit, scpnt);
|
||||
|
|
@ -249,9 +264,6 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags)
|
|||
if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) {
|
||||
zfcp_dbf_scsi_devreset("fail", tm_flags, unit, scpnt);
|
||||
retval = FAILED;
|
||||
} else if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP) {
|
||||
zfcp_dbf_scsi_devreset("nsup", tm_flags, unit, scpnt);
|
||||
retval = FAILED;
|
||||
} else
|
||||
zfcp_dbf_scsi_devreset("okay", tm_flags, unit, scpnt);
|
||||
|
||||
|
|
@ -261,12 +273,12 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags)
|
|||
|
||||
static int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt)
|
||||
{
|
||||
return zfcp_task_mgmt_function(scpnt, FCP_LOGICAL_UNIT_RESET);
|
||||
return zfcp_task_mgmt_function(scpnt, FCP_TMF_LUN_RESET);
|
||||
}
|
||||
|
||||
static int zfcp_scsi_eh_target_reset_handler(struct scsi_cmnd *scpnt)
|
||||
{
|
||||
return zfcp_task_mgmt_function(scpnt, FCP_TARGET_RESET);
|
||||
return zfcp_task_mgmt_function(scpnt, FCP_TMF_TGT_RESET);
|
||||
}
|
||||
|
||||
static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
|
||||
|
|
@ -276,6 +288,7 @@ static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
|
|||
|
||||
zfcp_erp_adapter_reopen(adapter, 0, "schrh_1", scpnt);
|
||||
zfcp_erp_wait(adapter);
|
||||
fc_block_scsi_eh(scpnt);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
|
@ -303,7 +316,7 @@ int zfcp_adapter_scsi_register(struct zfcp_adapter *adapter)
|
|||
adapter->scsi_host->max_lun = 1;
|
||||
adapter->scsi_host->max_channel = 0;
|
||||
adapter->scsi_host->unique_id = dev_id.devno;
|
||||
adapter->scsi_host->max_cmd_len = 255;
|
||||
adapter->scsi_host->max_cmd_len = 16; /* in struct fcp_cmnd */
|
||||
adapter->scsi_host->transportt = zfcp_data.scsi_transport_template;
|
||||
|
||||
adapter->scsi_host->hostdata[0] = (unsigned long) adapter;
|
||||
|
|
@ -325,12 +338,11 @@ void zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter)
|
|||
if (!shost)
|
||||
return;
|
||||
|
||||
read_lock_irq(&zfcp_data.config_lock);
|
||||
list_for_each_entry(port, &adapter->port_list_head, list)
|
||||
if (port->rport)
|
||||
port->rport = NULL;
|
||||
read_lock_irq(&adapter->port_list_lock);
|
||||
list_for_each_entry(port, &adapter->port_list, list)
|
||||
port->rport = NULL;
|
||||
read_unlock_irq(&adapter->port_list_lock);
|
||||
|
||||
read_unlock_irq(&zfcp_data.config_lock);
|
||||
fc_remove_host(shost);
|
||||
scsi_remove_host(shost);
|
||||
scsi_host_put(shost);
|
||||
|
|
@ -348,7 +360,7 @@ zfcp_init_fc_host_stats(struct zfcp_adapter *adapter)
|
|||
fc_stats = kmalloc(sizeof(*fc_stats), GFP_KERNEL);
|
||||
if (!fc_stats)
|
||||
return NULL;
|
||||
adapter->fc_stats = fc_stats; /* freed in adater_dequeue */
|
||||
adapter->fc_stats = fc_stats; /* freed in adapter_release */
|
||||
}
|
||||
memset(adapter->fc_stats, 0, sizeof(*adapter->fc_stats));
|
||||
return adapter->fc_stats;
|
||||
|
|
@ -464,7 +476,7 @@ static void zfcp_reset_fc_host_stats(struct Scsi_Host *shost)
|
|||
adapter->stats_reset = jiffies/HZ;
|
||||
kfree(adapter->stats_reset_data);
|
||||
adapter->stats_reset_data = data; /* finally freed in
|
||||
adapter_dequeue */
|
||||
adapter_release */
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -495,7 +507,7 @@ 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 for avoids a conflict with a shutdown
|
||||
* port. Using a reopen avoiding a conflict with a shutdown
|
||||
* overwriting a reopen.
|
||||
*/
|
||||
static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport)
|
||||
|
|
@ -505,15 +517,11 @@ static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport)
|
|||
struct zfcp_adapter *adapter =
|
||||
(struct zfcp_adapter *)shost->hostdata[0];
|
||||
|
||||
write_lock_irq(&zfcp_data.config_lock);
|
||||
port = zfcp_get_port_by_wwpn(adapter, rport->port_name);
|
||||
if (port)
|
||||
zfcp_port_get(port);
|
||||
write_unlock_irq(&zfcp_data.config_lock);
|
||||
|
||||
if (port) {
|
||||
zfcp_erp_port_reopen(port, 0, "sctrpi1", NULL);
|
||||
zfcp_port_put(port);
|
||||
put_device(&port->sysfs_device);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -555,31 +563,34 @@ static void zfcp_scsi_rport_block(struct zfcp_port *port)
|
|||
|
||||
void zfcp_scsi_schedule_rport_register(struct zfcp_port *port)
|
||||
{
|
||||
zfcp_port_get(port);
|
||||
get_device(&port->sysfs_device);
|
||||
port->rport_task = RPORT_ADD;
|
||||
|
||||
if (!queue_work(port->adapter->work_queue, &port->rport_work))
|
||||
zfcp_port_put(port);
|
||||
put_device(&port->sysfs_device);
|
||||
}
|
||||
|
||||
void zfcp_scsi_schedule_rport_block(struct zfcp_port *port)
|
||||
{
|
||||
zfcp_port_get(port);
|
||||
get_device(&port->sysfs_device);
|
||||
port->rport_task = RPORT_DEL;
|
||||
|
||||
if (port->rport && queue_work(port->adapter->work_queue,
|
||||
&port->rport_work))
|
||||
return;
|
||||
|
||||
zfcp_port_put(port);
|
||||
put_device(&port->sysfs_device);
|
||||
}
|
||||
|
||||
void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *adapter)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct zfcp_port *port;
|
||||
|
||||
list_for_each_entry(port, &adapter->port_list_head, list)
|
||||
read_lock_irqsave(&adapter->port_list_lock, flags);
|
||||
list_for_each_entry(port, &adapter->port_list, list)
|
||||
zfcp_scsi_schedule_rport_block(port);
|
||||
read_unlock_irqrestore(&adapter->port_list_lock, flags);
|
||||
}
|
||||
|
||||
void zfcp_scsi_rport_work(struct work_struct *work)
|
||||
|
|
@ -597,7 +608,7 @@ void zfcp_scsi_rport_work(struct work_struct *work)
|
|||
}
|
||||
}
|
||||
|
||||
zfcp_port_put(port);
|
||||
put_device(&port->sysfs_device);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -615,21 +626,7 @@ void zfcp_scsi_scan(struct work_struct *work)
|
|||
scsilun_to_int((struct scsi_lun *)
|
||||
&unit->fcp_lun), 0);
|
||||
|
||||
zfcp_unit_put(unit);
|
||||
}
|
||||
|
||||
static int zfcp_execute_fc_job(struct fc_bsg_job *job)
|
||||
{
|
||||
switch (job->request->msgcode) {
|
||||
case FC_BSG_RPT_ELS:
|
||||
case FC_BSG_HST_ELS_NOLOGIN:
|
||||
return zfcp_fc_execute_els_fc_job(job);
|
||||
case FC_BSG_RPT_CT:
|
||||
case FC_BSG_HST_CT:
|
||||
return zfcp_fc_execute_ct_fc_job(job);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
put_device(&unit->sysfs_device);
|
||||
}
|
||||
|
||||
struct fc_function_template zfcp_transport_functions = {
|
||||
|
|
@ -643,6 +640,7 @@ struct fc_function_template zfcp_transport_functions = {
|
|||
.show_host_port_name = 1,
|
||||
.show_host_permanent_port_name = 1,
|
||||
.show_host_supported_classes = 1,
|
||||
.show_host_supported_fc4s = 1,
|
||||
.show_host_supported_speeds = 1,
|
||||
.show_host_maxframe_size = 1,
|
||||
.show_host_serial_number = 1,
|
||||
|
|
@ -652,13 +650,15 @@ struct fc_function_template zfcp_transport_functions = {
|
|||
.get_host_port_state = zfcp_get_host_port_state,
|
||||
.terminate_rport_io = zfcp_scsi_terminate_rport_io,
|
||||
.show_host_port_state = 1,
|
||||
.bsg_request = zfcp_execute_fc_job,
|
||||
.show_host_active_fc4s = 1,
|
||||
.bsg_request = zfcp_fc_exec_bsg_job,
|
||||
/* no functions registered for following dynamic attributes but
|
||||
directly set by LLDD */
|
||||
.show_host_port_type = 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 = {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* sysfs attributes.
|
||||
*
|
||||
* Copyright IBM Corporation 2008
|
||||
* Copyright IBM Corporation 2008, 2009
|
||||
*/
|
||||
|
||||
#define KMSG_COMPONENT "zfcp"
|
||||
|
|
@ -19,30 +19,44 @@ static ssize_t zfcp_sysfs_##_feat##_##_name##_show(struct device *dev, \
|
|||
struct device_attribute *at,\
|
||||
char *buf) \
|
||||
{ \
|
||||
struct _feat_def *_feat = dev_get_drvdata(dev); \
|
||||
struct _feat_def *_feat = container_of(dev, struct _feat_def, \
|
||||
sysfs_device); \
|
||||
\
|
||||
return sprintf(buf, _format, _value); \
|
||||
} \
|
||||
static ZFCP_DEV_ATTR(_feat, _name, S_IRUGO, \
|
||||
zfcp_sysfs_##_feat##_##_name##_show, NULL);
|
||||
|
||||
ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, status, "0x%08x\n",
|
||||
atomic_read(&adapter->status));
|
||||
ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, peer_wwnn, "0x%016llx\n",
|
||||
(unsigned long long) adapter->peer_wwnn);
|
||||
ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, peer_wwpn, "0x%016llx\n",
|
||||
(unsigned long long) adapter->peer_wwpn);
|
||||
ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, peer_d_id, "0x%06x\n",
|
||||
adapter->peer_d_id);
|
||||
ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, card_version, "0x%04x\n",
|
||||
adapter->hydra_version);
|
||||
ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, lic_version, "0x%08x\n",
|
||||
adapter->fsf_lic_version);
|
||||
ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, hardware_version, "0x%08x\n",
|
||||
adapter->hardware_version);
|
||||
ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, in_recovery, "%d\n",
|
||||
(atomic_read(&adapter->status) &
|
||||
ZFCP_STATUS_COMMON_ERP_INUSE) != 0);
|
||||
#define ZFCP_DEFINE_A_ATTR(_name, _format, _value) \
|
||||
static ssize_t zfcp_sysfs_adapter_##_name##_show(struct device *dev, \
|
||||
struct device_attribute *at,\
|
||||
char *buf) \
|
||||
{ \
|
||||
struct ccw_device *cdev = to_ccwdev(dev); \
|
||||
struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); \
|
||||
int i; \
|
||||
\
|
||||
if (!adapter) \
|
||||
return -ENODEV; \
|
||||
\
|
||||
i = sprintf(buf, _format, _value); \
|
||||
zfcp_ccw_adapter_put(adapter); \
|
||||
return i; \
|
||||
} \
|
||||
static ZFCP_DEV_ATTR(adapter, _name, S_IRUGO, \
|
||||
zfcp_sysfs_adapter_##_name##_show, NULL);
|
||||
|
||||
ZFCP_DEFINE_A_ATTR(status, "0x%08x\n", atomic_read(&adapter->status));
|
||||
ZFCP_DEFINE_A_ATTR(peer_wwnn, "0x%016llx\n",
|
||||
(unsigned long long) adapter->peer_wwnn);
|
||||
ZFCP_DEFINE_A_ATTR(peer_wwpn, "0x%016llx\n",
|
||||
(unsigned long long) adapter->peer_wwpn);
|
||||
ZFCP_DEFINE_A_ATTR(peer_d_id, "0x%06x\n", adapter->peer_d_id);
|
||||
ZFCP_DEFINE_A_ATTR(card_version, "0x%04x\n", adapter->hydra_version);
|
||||
ZFCP_DEFINE_A_ATTR(lic_version, "0x%08x\n", adapter->fsf_lic_version);
|
||||
ZFCP_DEFINE_A_ATTR(hardware_version, "0x%08x\n", adapter->hardware_version);
|
||||
ZFCP_DEFINE_A_ATTR(in_recovery, "%d\n", (atomic_read(&adapter->status) &
|
||||
ZFCP_STATUS_COMMON_ERP_INUSE) != 0);
|
||||
|
||||
ZFCP_DEFINE_ATTR(zfcp_port, port, status, "0x%08x\n",
|
||||
atomic_read(&port->status));
|
||||
|
|
@ -73,7 +87,8 @@ static ssize_t zfcp_sysfs_##_feat##_failed_show(struct device *dev, \
|
|||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
struct _feat_def *_feat = dev_get_drvdata(dev); \
|
||||
struct _feat_def *_feat = container_of(dev, struct _feat_def, \
|
||||
sysfs_device); \
|
||||
\
|
||||
if (atomic_read(&_feat->status) & ZFCP_STATUS_COMMON_ERP_FAILED) \
|
||||
return sprintf(buf, "1\n"); \
|
||||
|
|
@ -84,15 +99,13 @@ 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 = dev_get_drvdata(dev); \
|
||||
struct _feat_def *_feat = container_of(dev, struct _feat_def, \
|
||||
sysfs_device); \
|
||||
unsigned long val; \
|
||||
int retval = 0; \
|
||||
\
|
||||
mutex_lock(&zfcp_data.config_mutex); \
|
||||
if (atomic_read(&_feat->status) & ZFCP_STATUS_COMMON_REMOVE) { \
|
||||
retval = -EBUSY; \
|
||||
goto out; \
|
||||
} \
|
||||
if (!(_feat && get_device(&_feat->sysfs_device))) \
|
||||
return -EBUSY; \
|
||||
\
|
||||
if (strict_strtoul(buf, 0, &val) || val != 0) { \
|
||||
retval = -EINVAL; \
|
||||
|
|
@ -105,29 +118,82 @@ static ssize_t zfcp_sysfs_##_feat##_failed_store(struct device *dev, \
|
|||
_reopen_id, NULL); \
|
||||
zfcp_erp_wait(_adapter); \
|
||||
out: \
|
||||
mutex_unlock(&zfcp_data.config_mutex); \
|
||||
put_device(&_feat->sysfs_device); \
|
||||
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_SYSFS_FAILED(zfcp_adapter, adapter, adapter, "syafai1", "syafai2");
|
||||
ZFCP_SYSFS_FAILED(zfcp_port, port, port->adapter, "sypfai1", "sypfai2");
|
||||
ZFCP_SYSFS_FAILED(zfcp_unit, unit, unit->port->adapter, "syufai1", "syufai2");
|
||||
|
||||
static ssize_t zfcp_sysfs_adapter_failed_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct ccw_device *cdev = to_ccwdev(dev);
|
||||
struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);
|
||||
int i;
|
||||
|
||||
if (!adapter)
|
||||
return -ENODEV;
|
||||
|
||||
if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
|
||||
i = sprintf(buf, "1\n");
|
||||
else
|
||||
i = sprintf(buf, "0\n");
|
||||
|
||||
zfcp_ccw_adapter_put(adapter);
|
||||
return i;
|
||||
}
|
||||
|
||||
static ssize_t zfcp_sysfs_adapter_failed_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct ccw_device *cdev = to_ccwdev(dev);
|
||||
struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);
|
||||
unsigned long val;
|
||||
int retval = 0;
|
||||
|
||||
if (!adapter)
|
||||
return -ENODEV;
|
||||
|
||||
if (strict_strtoul(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_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
|
||||
"syafai2", NULL);
|
||||
zfcp_erp_wait(adapter);
|
||||
out:
|
||||
zfcp_ccw_adapter_put(adapter);
|
||||
return retval ? retval : (ssize_t) count;
|
||||
}
|
||||
static ZFCP_DEV_ATTR(adapter, failed, S_IWUSR | S_IRUGO,
|
||||
zfcp_sysfs_adapter_failed_show,
|
||||
zfcp_sysfs_adapter_failed_store);
|
||||
|
||||
static ssize_t zfcp_sysfs_port_rescan_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct zfcp_adapter *adapter = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
struct ccw_device *cdev = to_ccwdev(dev);
|
||||
struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);
|
||||
|
||||
if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_REMOVE)
|
||||
return -EBUSY;
|
||||
if (!adapter)
|
||||
return -ENODEV;
|
||||
|
||||
ret = zfcp_fc_scan_ports(adapter);
|
||||
return ret ? ret : (ssize_t) count;
|
||||
/* sync the user-space- with the kernel-invocation of scan_work */
|
||||
queue_work(adapter->work_queue, &adapter->scan_work);
|
||||
flush_work(&adapter->scan_work);
|
||||
zfcp_ccw_adapter_put(adapter);
|
||||
|
||||
return (ssize_t) count;
|
||||
}
|
||||
static ZFCP_DEV_ATTR(adapter, port_rescan, S_IWUSR, NULL,
|
||||
zfcp_sysfs_port_rescan_store);
|
||||
|
|
@ -136,44 +202,34 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev,
|
|||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct zfcp_adapter *adapter = dev_get_drvdata(dev);
|
||||
struct ccw_device *cdev = to_ccwdev(dev);
|
||||
struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);
|
||||
struct zfcp_port *port;
|
||||
u64 wwpn;
|
||||
int retval = 0;
|
||||
LIST_HEAD(port_remove_lh);
|
||||
int retval = -EINVAL;
|
||||
|
||||
mutex_lock(&zfcp_data.config_mutex);
|
||||
if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_REMOVE) {
|
||||
retval = -EBUSY;
|
||||
if (!adapter)
|
||||
return -ENODEV;
|
||||
|
||||
if (strict_strtoull(buf, 0, (unsigned long long *) &wwpn))
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (strict_strtoull(buf, 0, (unsigned long long *) &wwpn)) {
|
||||
retval = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
write_lock_irq(&zfcp_data.config_lock);
|
||||
port = zfcp_get_port_by_wwpn(adapter, wwpn);
|
||||
if (port && (atomic_read(&port->refcount) == 0)) {
|
||||
zfcp_port_get(port);
|
||||
atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status);
|
||||
list_move(&port->list, &port_remove_lh);
|
||||
} else
|
||||
port = NULL;
|
||||
write_unlock_irq(&zfcp_data.config_lock);
|
||||
|
||||
if (!port) {
|
||||
retval = -ENXIO;
|
||||
if (!port)
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
retval = 0;
|
||||
|
||||
write_lock_irq(&adapter->port_list_lock);
|
||||
list_del(&port->list);
|
||||
write_unlock_irq(&adapter->port_list_lock);
|
||||
|
||||
put_device(&port->sysfs_device);
|
||||
|
||||
zfcp_erp_port_shutdown(port, 0, "syprs_1", NULL);
|
||||
zfcp_erp_wait(adapter);
|
||||
zfcp_port_put(port);
|
||||
zfcp_port_dequeue(port);
|
||||
zfcp_device_unregister(&port->sysfs_device, &zfcp_sysfs_port_attrs);
|
||||
out:
|
||||
mutex_unlock(&zfcp_data.config_mutex);
|
||||
zfcp_ccw_adapter_put(adapter);
|
||||
return retval ? retval : (ssize_t) count;
|
||||
}
|
||||
static ZFCP_DEV_ATTR(adapter, port_remove, S_IWUSR, NULL,
|
||||
|
|
@ -202,16 +258,14 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev,
|
|||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct zfcp_port *port = dev_get_drvdata(dev);
|
||||
struct zfcp_port *port = container_of(dev, struct zfcp_port,
|
||||
sysfs_device);
|
||||
struct zfcp_unit *unit;
|
||||
u64 fcp_lun;
|
||||
int retval = -EINVAL;
|
||||
|
||||
mutex_lock(&zfcp_data.config_mutex);
|
||||
if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE) {
|
||||
retval = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
if (!(port && get_device(&port->sysfs_device)))
|
||||
return -EBUSY;
|
||||
|
||||
if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun))
|
||||
goto out;
|
||||
|
|
@ -219,15 +273,14 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev,
|
|||
unit = zfcp_unit_enqueue(port, fcp_lun);
|
||||
if (IS_ERR(unit))
|
||||
goto out;
|
||||
|
||||
retval = 0;
|
||||
else
|
||||
retval = 0;
|
||||
|
||||
zfcp_erp_unit_reopen(unit, 0, "syuas_1", NULL);
|
||||
zfcp_erp_wait(unit->port->adapter);
|
||||
flush_work(&unit->scsi_work);
|
||||
zfcp_unit_put(unit);
|
||||
out:
|
||||
mutex_unlock(&zfcp_data.config_mutex);
|
||||
put_device(&port->sysfs_device);
|
||||
return retval ? retval : (ssize_t) count;
|
||||
}
|
||||
static DEVICE_ATTR(unit_add, S_IWUSR, NULL, zfcp_sysfs_unit_add_store);
|
||||
|
|
@ -236,54 +289,37 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev,
|
|||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct zfcp_port *port = dev_get_drvdata(dev);
|
||||
struct zfcp_port *port = container_of(dev, struct zfcp_port,
|
||||
sysfs_device);
|
||||
struct zfcp_unit *unit;
|
||||
u64 fcp_lun;
|
||||
int retval = 0;
|
||||
LIST_HEAD(unit_remove_lh);
|
||||
int retval = -EINVAL;
|
||||
|
||||
mutex_lock(&zfcp_data.config_mutex);
|
||||
if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE) {
|
||||
retval = -EBUSY;
|
||||
if (!(port && get_device(&port->sysfs_device)))
|
||||
return -EBUSY;
|
||||
|
||||
if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun))
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun)) {
|
||||
retval = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
write_lock_irq(&zfcp_data.config_lock);
|
||||
unit = zfcp_get_unit_by_lun(port, fcp_lun);
|
||||
if (unit) {
|
||||
write_unlock_irq(&zfcp_data.config_lock);
|
||||
/* wait for possible timeout during SCSI probe */
|
||||
flush_work(&unit->scsi_work);
|
||||
write_lock_irq(&zfcp_data.config_lock);
|
||||
|
||||
if (atomic_read(&unit->refcount) == 0) {
|
||||
zfcp_unit_get(unit);
|
||||
atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE,
|
||||
&unit->status);
|
||||
list_move(&unit->list, &unit_remove_lh);
|
||||
} else {
|
||||
unit = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
write_unlock_irq(&zfcp_data.config_lock);
|
||||
|
||||
if (!unit) {
|
||||
retval = -ENXIO;
|
||||
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->sysfs_device);
|
||||
|
||||
zfcp_erp_unit_shutdown(unit, 0, "syurs_1", NULL);
|
||||
zfcp_erp_wait(unit->port->adapter);
|
||||
zfcp_unit_put(unit);
|
||||
zfcp_unit_dequeue(unit);
|
||||
zfcp_device_unregister(&unit->sysfs_device, &zfcp_sysfs_unit_attrs);
|
||||
out:
|
||||
mutex_unlock(&zfcp_data.config_mutex);
|
||||
put_device(&port->sysfs_device);
|
||||
return retval ? retval : (ssize_t) count;
|
||||
}
|
||||
static DEVICE_ATTR(unit_remove, S_IWUSR, NULL, zfcp_sysfs_unit_remove_store);
|
||||
|
|
|
|||
Loading…
Reference in a new issue