Commit 2eb6e1f3 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] s390: zfcp host adapter

From: Martin Schwidefsky <schwidefsky@de.ibm.com>

 - Adapt to notify api change in cio.
 - Add missing unregister_reboot_notifier() for error path.
 - Fix infinite error recovery escalation for certain port failures.
 - Fix reference counting.
 - Use GFP_ATOMIC for kmalloc while holding a spinlock.
 - Don't open adapter/port if unit/port is removed from configuration
   after it has already been closed.
 - Don't establish qdio queues if a port/unit is going to be removed.
 - Shutdown ports and units before removing them.
 - Use schedule_work for scsi_add_device.
 - Don't reopen nameserver port when an rscn was received.
 - Don't call scsi_done twice in zfcp_fsf_send_fcp_command_task_handler.
 - Get rid of scsi fake queue, scsi_reqs_active and scsi_reqs_active_wq.
 - Get rid of unused adapter status.
 - Allow enabling of scsi devices at boot time with zfcp_dev parameter.
 - Change name prefix from sg to sg_list for functions which work with
   the struct sg_list.
 - Don't call scsi_add_device from zfcp error recovery thread to avoid a
   deadlock if a scsi command sent during scsi_add_device fails.
 - Fix scsi i/o stall due to missing local-link-up event.
parent 99e0846e
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
*/ */
/* this drivers version (do not edit !!! generated and updated by cvs) */ /* this drivers version (do not edit !!! generated and updated by cvs) */
#define ZFCP_AUX_REVISION "$Revision: 1.65 $" #define ZFCP_AUX_REVISION "$Revision: 1.79 $"
/********************** INCLUDES *********************************************/ /********************** INCLUDES *********************************************/
...@@ -285,7 +285,7 @@ zfcp_cmd_dbf_event_scsi(const char *text, Scsi_Cmnd * scsi_cmnd) ...@@ -285,7 +285,7 @@ zfcp_cmd_dbf_event_scsi(const char *text, Scsi_Cmnd * scsi_cmnd)
debug_event(adapter->cmd_dbf, level, &scsi_cmnd->result, sizeof (u32)); debug_event(adapter->cmd_dbf, level, &scsi_cmnd->result, sizeof (u32));
debug_event(adapter->cmd_dbf, level, &scsi_cmnd, debug_event(adapter->cmd_dbf, level, &scsi_cmnd,
sizeof (unsigned long)); sizeof (unsigned long));
if (fsf_req) { if (likely(fsf_req)) {
debug_event(adapter->cmd_dbf, level, &fsf_req, debug_event(adapter->cmd_dbf, level, &fsf_req,
sizeof (unsigned long)); sizeof (unsigned long));
debug_event(adapter->cmd_dbf, level, &fsf_req->seq_no, debug_event(adapter->cmd_dbf, level, &fsf_req->seq_no,
...@@ -316,6 +316,89 @@ zfcp_in_els_dbf_event(struct zfcp_adapter *adapter, const char *text, ...@@ -316,6 +316,89 @@ zfcp_in_els_dbf_event(struct zfcp_adapter *adapter, const char *text,
#endif #endif
} }
#ifndef MODULE
/**
* zfcp_device_setup - setup function
* @str: pointer to parameter string
*
* Parse the kernel parameter string "zfcp_device=..."
*/
static int __init
zfcp_device_setup(char *str)
{
char *tmp;
tmp = strchr(str, ',');
if (!tmp)
goto err_out;
*tmp++ = '\0';
strncpy(zfcp_data.init_busid, str, BUS_ID_SIZE);
zfcp_data.init_busid[BUS_ID_SIZE-1] = '\0';
zfcp_data.init_wwpn = simple_strtoull(tmp, &tmp, 0);
if (*tmp++ != ',')
goto err_out;
if (*tmp == '\0')
goto err_out;
zfcp_data.init_fcp_lun = simple_strtoull(tmp, &tmp, 0);
if (*tmp != '\0')
goto err_out;
zfcp_data.init_is_valid = 1;
goto out;
err_out:
ZFCP_LOG_NORMAL("Parse error for parameter string %s\n", str);
out:
return 1;
}
__setup("zfcp_device=", zfcp_device_setup);
static void __init
zfcp_init_device_configure(void)
{
int found = 0;
unsigned long flags;
struct zfcp_adapter *adapter;
struct zfcp_port *port;
struct zfcp_unit *unit;
down(&zfcp_data.config_sema);
read_lock_irqsave(&zfcp_data.config_lock, flags);
list_for_each_entry(adapter, &zfcp_data.adapter_list_head, list)
if (strcmp(zfcp_data.init_busid,
zfcp_get_busid_by_adapter(adapter)) == 0) {
zfcp_adapter_get(adapter);
found = 1;
break;
}
read_unlock_irqrestore(&zfcp_data.config_lock, flags);
if (!found)
goto out_adapter;
port = zfcp_port_enqueue(adapter, zfcp_data.init_wwpn, 0);
if (!port)
goto out_port;
unit = zfcp_unit_enqueue(port, zfcp_data.init_fcp_lun);
if (!unit)
goto out_unit;
up(&zfcp_data.config_sema);
ccw_device_set_online(adapter->ccw_device);
down(&zfcp_data.config_sema);
wait_event(unit->scsi_add_wq, atomic_read(&unit->scsi_add_work) == 0);
zfcp_unit_put(unit);
out_unit:
zfcp_port_put(port);
out_port:
zfcp_adapter_put(adapter);
out_adapter:
up(&zfcp_data.config_sema);
return;
}
#endif /* #ifndef MODULE */
static int __init static int __init
zfcp_module_init(void) zfcp_module_init(void)
{ {
...@@ -357,9 +440,15 @@ zfcp_module_init(void) ...@@ -357,9 +440,15 @@ zfcp_module_init(void)
ZFCP_LOG_NORMAL("Registering with common I/O layer failed.\n"); ZFCP_LOG_NORMAL("Registering with common I/O layer failed.\n");
goto out_ccw_register; goto out_ccw_register;
} }
#ifndef MODULE
if (zfcp_data.init_is_valid)
zfcp_init_device_configure();
#endif
goto out; goto out;
out_ccw_register: out_ccw_register:
unregister_reboot_notifier(&zfcp_data.reboot_notifier);
#ifdef ZFCP_STAT_REQSIZES #ifdef ZFCP_STAT_REQSIZES
zfcp_statistics_clear_all(); zfcp_statistics_clear_all();
#endif #endif
...@@ -391,13 +480,8 @@ int ...@@ -391,13 +480,8 @@ int
zfcp_reboot_handler(struct notifier_block *notifier, unsigned long code, zfcp_reboot_handler(struct notifier_block *notifier, unsigned long code,
void *ptr) void *ptr)
{ {
int retval = NOTIFY_DONE; zfcp_ccw_unregister();
return NOTIFY_DONE;
/* block access to config (for rest of lifetime of this Linux) */
down(&zfcp_data.config_sema);
zfcp_erp_adapter_shutdown_all();
return retval;
} }
#undef ZFCP_LOG_AREA #undef ZFCP_LOG_AREA
...@@ -503,6 +587,7 @@ zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun) ...@@ -503,6 +587,7 @@ zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun)
return NULL; return NULL;
memset(unit, 0, sizeof (struct zfcp_unit)); memset(unit, 0, sizeof (struct zfcp_unit));
init_waitqueue_head(&unit->scsi_add_wq);
/* initialise reference count stuff */ /* initialise reference count stuff */
atomic_set(&unit->refcount, 0); atomic_set(&unit->refcount, 0);
init_waitqueue_head(&unit->remove_wq); init_waitqueue_head(&unit->remove_wq);
...@@ -571,6 +656,7 @@ zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun) ...@@ -571,6 +656,7 @@ zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun)
write_unlock_irq(&zfcp_data.config_lock); write_unlock_irq(&zfcp_data.config_lock);
port->units++; port->units++;
zfcp_port_get(port);
return unit; return unit;
} }
...@@ -763,17 +849,10 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) ...@@ -763,17 +849,10 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
/* initialize abort lock */ /* initialize abort lock */
rwlock_init(&adapter->abort_lock); rwlock_init(&adapter->abort_lock);
/* initialise scsi faking structures */
rwlock_init(&adapter->fake_list_lock);
init_timer(&adapter->fake_scsi_timer);
/* initialise some erp stuff */ /* initialise some erp stuff */
init_waitqueue_head(&adapter->erp_thread_wqh); init_waitqueue_head(&adapter->erp_thread_wqh);
init_waitqueue_head(&adapter->erp_done_wqh); init_waitqueue_head(&adapter->erp_done_wqh);
/* notification when there are no outstanding SCSI commands */
init_waitqueue_head(&adapter->scsi_reqs_active_wq);
/* initialize lock of associated request queue */ /* initialize lock of associated request queue */
rwlock_init(&adapter->request_queue.queue_lock); rwlock_init(&adapter->request_queue.queue_lock);
...@@ -904,7 +983,6 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) ...@@ -904,7 +983,6 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
/* put allocated adapter at list tail */ /* put allocated adapter at list tail */
write_lock_irq(&zfcp_data.config_lock); write_lock_irq(&zfcp_data.config_lock);
atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status);
atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &adapter->status);
list_add_tail(&adapter->list, &zfcp_data.adapter_list_head); list_add_tail(&adapter->list, &zfcp_data.adapter_list_head);
write_unlock_irq(&zfcp_data.config_lock); write_unlock_irq(&zfcp_data.config_lock);
...@@ -1149,6 +1227,7 @@ zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn, u32 status) ...@@ -1149,6 +1227,7 @@ zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn, u32 status)
write_unlock_irq(&zfcp_data.config_lock); write_unlock_irq(&zfcp_data.config_lock);
adapter->ports++; adapter->ports++;
zfcp_adapter_get(adapter);
return port; return port;
} }
...@@ -1193,7 +1272,6 @@ zfcp_nameserver_enqueue(struct zfcp_adapter *adapter) ...@@ -1193,7 +1272,6 @@ zfcp_nameserver_enqueue(struct zfcp_adapter *adapter)
/* set special D_ID */ /* set special D_ID */
port->d_id = ZFCP_DID_NAMESERVER; port->d_id = ZFCP_DID_NAMESERVER;
adapter->nameserver_port = port; adapter->nameserver_port = port;
zfcp_adapter_get(adapter);
zfcp_port_put(port); zfcp_port_put(port);
return 0; return 0;
...@@ -1216,9 +1294,9 @@ zfcp_fsf_incoming_els_rscn(struct zfcp_adapter *adapter, ...@@ -1216,9 +1294,9 @@ zfcp_fsf_incoming_els_rscn(struct zfcp_adapter *adapter,
struct fcp_rscn_head *fcp_rscn_head; struct fcp_rscn_head *fcp_rscn_head;
struct fcp_rscn_element *fcp_rscn_element; struct fcp_rscn_element *fcp_rscn_element;
struct zfcp_port *port; struct zfcp_port *port;
int i; u16 i;
int reopen_unknown = 0; u16 no_entries;
int no_entries; u32 range_mask;
unsigned long flags; unsigned long flags;
fcp_rscn_head = (struct fcp_rscn_head *) status_buffer->payload; fcp_rscn_head = (struct fcp_rscn_head *) status_buffer->payload;
...@@ -1232,56 +1310,57 @@ zfcp_fsf_incoming_els_rscn(struct zfcp_adapter *adapter, ...@@ -1232,56 +1310,57 @@ zfcp_fsf_incoming_els_rscn(struct zfcp_adapter *adapter,
debug_text_event(adapter->erp_dbf, 1, "unsol_els_rscn:"); debug_text_event(adapter->erp_dbf, 1, "unsol_els_rscn:");
for (i = 1; i < no_entries; i++) { for (i = 1; i < no_entries; i++) {
int known;
int range_mask;
int no_notifications;
range_mask = 0;
no_notifications = 0;
known = 0;
/* skip head and start with 1st element */ /* skip head and start with 1st element */
fcp_rscn_element++; fcp_rscn_element++;
switch (fcp_rscn_element->addr_format) { switch (fcp_rscn_element->addr_format) {
case ZFCP_PORT_ADDRESS: case ZFCP_PORT_ADDRESS:
ZFCP_LOG_FLAGS(1, "ZFCP_PORT_ADDRESS\n"); ZFCP_LOG_FLAGS(1, "ZFCP_PORT_ADDRESS\n");
range_mask = ZFCP_PORTS_RANGE_PORT; range_mask = ZFCP_PORTS_RANGE_PORT;
no_notifications = 1;
break; break;
case ZFCP_AREA_ADDRESS: case ZFCP_AREA_ADDRESS:
ZFCP_LOG_FLAGS(1, "ZFCP_AREA_ADDRESS\n"); ZFCP_LOG_FLAGS(1, "ZFCP_AREA_ADDRESS\n");
/* skip head and start with 1st element */
range_mask = ZFCP_PORTS_RANGE_AREA; range_mask = ZFCP_PORTS_RANGE_AREA;
no_notifications = ZFCP_NO_PORTS_PER_AREA;
break; break;
case ZFCP_DOMAIN_ADDRESS: case ZFCP_DOMAIN_ADDRESS:
ZFCP_LOG_FLAGS(1, "ZFCP_DOMAIN_ADDRESS\n"); ZFCP_LOG_FLAGS(1, "ZFCP_DOMAIN_ADDRESS\n");
range_mask = ZFCP_PORTS_RANGE_DOMAIN; range_mask = ZFCP_PORTS_RANGE_DOMAIN;
no_notifications = ZFCP_NO_PORTS_PER_DOMAIN;
break; break;
case ZFCP_FABRIC_ADDRESS: case ZFCP_FABRIC_ADDRESS:
ZFCP_LOG_FLAGS(1, "ZFCP_FABRIC_ADDRESS\n"); ZFCP_LOG_FLAGS(1, "ZFCP_FABRIC_ADDRESS\n");
range_mask = ZFCP_PORTS_RANGE_FABRIC; range_mask = ZFCP_PORTS_RANGE_FABRIC;
no_notifications = ZFCP_NO_PORTS_PER_FABRIC;
break; break;
default: default:
/* cannot happen */ ZFCP_LOG_INFO("Received RSCN with unknown "
break; "address format.\n");
continue;
} }
read_lock_irqsave(&zfcp_data.config_lock, flags); read_lock_irqsave(&zfcp_data.config_lock, flags);
list_for_each_entry(port, &adapter->port_list_head, list) { list_for_each_entry(port, &adapter->port_list_head, list) {
if (atomic_test_mask
(ZFCP_STATUS_PORT_NAMESERVER, &port->status))
continue;
/* Do we know this port? If not skip it. */ /* Do we know this port? If not skip it. */
if (!atomic_test_mask if (!atomic_test_mask
(ZFCP_STATUS_PORT_DID_DID, &port->status)) (ZFCP_STATUS_PORT_DID_DID, &port->status)) {
ZFCP_LOG_INFO
("Received state change notification."
"Trying to open the port with wwpn "
"0x%Lx. Hope it's there now.\n",
port->wwpn);
debug_text_event(adapter->erp_dbf, 1,
"unsol_els_rscnu:");
zfcp_erp_port_reopen(port,
ZFCP_STATUS_COMMON_ERP_FAILED);
continue; continue;
}
/* /*
* FIXME: race: d_id might being invalidated * FIXME: race: d_id might being invalidated
* (...DID_DID reset) * (...DID_DID reset)
*/ */
if ((port->d_id & range_mask) if ((port->d_id & range_mask)
== (fcp_rscn_element->nport_did & range_mask)) { == (fcp_rscn_element->nport_did & range_mask)) {
known++; ZFCP_LOG_TRACE("reopen did 0x%x\n",
ZFCP_LOG_TRACE("known=%d, reopen did 0x%x\n",
known,
fcp_rscn_element->nport_did); fcp_rscn_element->nport_did);
/* /*
* Unfortunately, an RSCN does not specify the * Unfortunately, an RSCN does not specify the
...@@ -1303,36 +1382,6 @@ zfcp_fsf_incoming_els_rscn(struct zfcp_adapter *adapter, ...@@ -1303,36 +1382,6 @@ zfcp_fsf_incoming_els_rscn(struct zfcp_adapter *adapter,
} }
} }
read_unlock_irqrestore(&zfcp_data.config_lock, flags); read_unlock_irqrestore(&zfcp_data.config_lock, flags);
ZFCP_LOG_TRACE("known %d, no_notifications %d\n",
known, no_notifications);
if (known < no_notifications) {
ZFCP_LOG_DEBUG
("At least one unknown port changed state. "
"Unknown ports need to be reopened.\n");
reopen_unknown = 1;
}
} // for (i=1; i < no_entries; i++)
if (reopen_unknown) {
ZFCP_LOG_DEBUG("At least one unknown did "
"underwent a state change.\n");
read_lock_irqsave(&zfcp_data.config_lock, flags);
list_for_each_entry(port, &adapter->port_list_head, list) {
if (!atomic_test_mask((ZFCP_STATUS_PORT_DID_DID
| ZFCP_STATUS_PORT_NAMESERVER),
&port->status)) {
ZFCP_LOG_INFO
("Received state change notification."
"Trying to open the port with wwpn "
"0x%Lx. Hope it's there now.\n",
port->wwpn);
debug_text_event(adapter->erp_dbf, 1,
"unsol_els_rscnu:");
zfcp_erp_port_reopen(port,
ZFCP_STATUS_COMMON_ERP_FAILED);
}
}
read_unlock_irqrestore(&zfcp_data.config_lock, flags);
} }
} }
...@@ -1469,7 +1518,7 @@ zfcp_get_nameserver_buffers(struct zfcp_fsf_req *fsf_req) ...@@ -1469,7 +1518,7 @@ zfcp_get_nameserver_buffers(struct zfcp_fsf_req *fsf_req)
struct zfcp_adapter *adapter = fsf_req->adapter; struct zfcp_adapter *adapter = fsf_req->adapter;
int retval = 0; int retval = 0;
data->outbuf = kmalloc(2 * sizeof (struct fc_ct_iu), GFP_KERNEL); data->outbuf = kmalloc(2 * sizeof (struct fc_ct_iu), GFP_ATOMIC);
if (data->outbuf) { if (data->outbuf) {
memset(data->outbuf, 0, 2 * sizeof (struct fc_ct_iu)); memset(data->outbuf, 0, 2 * sizeof (struct fc_ct_iu));
} else { } else {
...@@ -1479,7 +1528,7 @@ zfcp_get_nameserver_buffers(struct zfcp_fsf_req *fsf_req) ...@@ -1479,7 +1528,7 @@ zfcp_get_nameserver_buffers(struct zfcp_fsf_req *fsf_req)
"adapter %s directly.. trying emergency pool\n", "adapter %s directly.. trying emergency pool\n",
zfcp_get_busid_by_adapter(adapter)); zfcp_get_busid_by_adapter(adapter));
data->outbuf = data->outbuf =
mempool_alloc(adapter->pool.nameserver, GFP_KERNEL); mempool_alloc(adapter->pool.nameserver, GFP_ATOMIC);
if (!data->outbuf) { if (!data->outbuf) {
ZFCP_LOG_DEBUG ZFCP_LOG_DEBUG
("Out of memory. Could not get emergency " ("Out of memory. Could not get emergency "
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#define ZFCP_CCW_C_REVISION "$Revision: 1.33 $" #define ZFCP_CCW_C_REVISION "$Revision: 1.36 $"
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
#define ZFCP_LOG_AREA_PREFIX ZFCP_LOG_AREA_PREFIX_CONFIG #define ZFCP_LOG_AREA_PREFIX ZFCP_LOG_AREA_PREFIX_CONFIG
static int zfcp_ccw_probe(struct ccw_device *); static int zfcp_ccw_probe(struct ccw_device *);
static int zfcp_ccw_remove(struct ccw_device *); static void zfcp_ccw_remove(struct ccw_device *);
static int zfcp_ccw_set_online(struct ccw_device *); static int zfcp_ccw_set_online(struct ccw_device *);
static int zfcp_ccw_set_offline(struct ccw_device *); static int zfcp_ccw_set_offline(struct ccw_device *);
...@@ -90,16 +90,17 @@ zfcp_ccw_probe(struct ccw_device *ccw_device) ...@@ -90,16 +90,17 @@ zfcp_ccw_probe(struct ccw_device *ccw_device)
* *
* This function gets called by the common i/o layer and removes an adapter * 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 * from the system. Task of this function is to get rid of all units and
* ports that belong to this adapter. And addition all resources of this * ports that belong to this adapter. And in addition all resources of this
* adapter will be freed too. * adapter will be freed too.
*/ */
static int static void
zfcp_ccw_remove(struct ccw_device *ccw_device) zfcp_ccw_remove(struct ccw_device *ccw_device)
{ {
struct zfcp_adapter *adapter; struct zfcp_adapter *adapter;
struct zfcp_port *port, *p; struct zfcp_port *port, *p;
struct zfcp_unit *unit, *u; struct zfcp_unit *unit, *u;
ccw_device_set_offline(ccw_device);
down(&zfcp_data.config_sema); down(&zfcp_data.config_sema);
adapter = dev_get_drvdata(&ccw_device->dev); adapter = dev_get_drvdata(&ccw_device->dev);
...@@ -119,16 +120,18 @@ zfcp_ccw_remove(struct ccw_device *ccw_device) ...@@ -119,16 +120,18 @@ zfcp_ccw_remove(struct ccw_device *ccw_device)
list_for_each_entry_safe(port, p, &adapter->port_remove_lh, list) { list_for_each_entry_safe(port, p, &adapter->port_remove_lh, list) {
list_for_each_entry_safe(unit, u, &port->unit_remove_lh, list) { list_for_each_entry_safe(unit, u, &port->unit_remove_lh, list) {
zfcp_unit_wait(unit); zfcp_unit_wait(unit);
zfcp_sysfs_unit_remove_files(&unit->sysfs_device);
device_unregister(&unit->sysfs_device); device_unregister(&unit->sysfs_device);
} }
zfcp_port_wait(port); zfcp_port_wait(port);
zfcp_sysfs_port_remove_files(&port->sysfs_device,
atomic_read(&port->status));
device_unregister(&port->sysfs_device); device_unregister(&port->sysfs_device);
} }
zfcp_adapter_wait(adapter); zfcp_adapter_wait(adapter);
zfcp_adapter_dequeue(adapter); zfcp_adapter_dequeue(adapter);
up(&zfcp_data.config_sema); up(&zfcp_data.config_sema);
return 0;
} }
/** /**
...@@ -155,6 +158,7 @@ zfcp_ccw_set_online(struct ccw_device *ccw_device) ...@@ -155,6 +158,7 @@ zfcp_ccw_set_online(struct ccw_device *ccw_device)
zfcp_erp_modify_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING, zfcp_erp_modify_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING,
ZFCP_SET); ZFCP_SET);
zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED); zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED);
zfcp_erp_wait(adapter);
out: out:
up(&zfcp_data.config_sema); up(&zfcp_data.config_sema);
return retval; return retval;
......
...@@ -31,10 +31,8 @@ ...@@ -31,10 +31,8 @@
#ifndef ZFCP_DEF_H #ifndef ZFCP_DEF_H
#define ZFCP_DEF_H #define ZFCP_DEF_H
#ifdef __KERNEL__
/* this drivers version (do not edit !!! generated and updated by cvs) */ /* this drivers version (do not edit !!! generated and updated by cvs) */
#define ZFCP_DEF_REVISION "$Revision: 1.41 $" #define ZFCP_DEF_REVISION "$Revision: 1.48 $"
/*************************** INCLUDES *****************************************/ /*************************** INCLUDES *****************************************/
...@@ -64,7 +62,6 @@ ...@@ -64,7 +62,6 @@
typedef u32 scsi_id_t; typedef u32 scsi_id_t;
typedef u32 scsi_lun_t; typedef u32 scsi_lun_t;
#define ZFCP_FAKE_SCSI_COMPLETION_TIME (HZ / 3)
#define ZFCP_ERP_SCSI_LOW_MEM_TIMEOUT (100*HZ) #define ZFCP_ERP_SCSI_LOW_MEM_TIMEOUT (100*HZ)
#define ZFCP_SCSI_ER_TIMEOUT (100*HZ) #define ZFCP_SCSI_ER_TIMEOUT (100*HZ)
#define ZFCP_SCSI_HOST_FLUSH_TIMEOUT (1*HZ) #define ZFCP_SCSI_HOST_FLUSH_TIMEOUT (1*HZ)
...@@ -470,7 +467,6 @@ extern u32 flags_dump; ...@@ -470,7 +467,6 @@ extern u32 flags_dump;
#define ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL 0x00000080 #define ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL 0x00000080
#define ZFCP_STATUS_ADAPTER_ERP_PENDING 0x00000100 #define ZFCP_STATUS_ADAPTER_ERP_PENDING 0x00000100
#define ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED 0x00000200 #define ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED 0x00000200
#define ZFCP_STATUS_ADAPTER_QUEUECOMMAND_BLOCK 0x00000400
#define ZFCP_STATUS_ADAPTER_SCSI_UP \ #define ZFCP_STATUS_ADAPTER_SCSI_UP \
(ZFCP_STATUS_COMMON_UNBLOCKED | \ (ZFCP_STATUS_COMMON_UNBLOCKED | \
...@@ -676,10 +672,7 @@ struct zfcp_adapter { ...@@ -676,10 +672,7 @@ struct zfcp_adapter {
u32 hydra_version; /* Hydra version */ u32 hydra_version; /* Hydra version */
u32 fsf_lic_version; u32 fsf_lic_version;
struct Scsi_Host *scsi_host; /* Pointer to mid-layer */ struct Scsi_Host *scsi_host; /* Pointer to mid-layer */
Scsi_Cmnd *first_fake_cmnd; /* Packets in flight list */
rwlock_t fake_list_lock; /* Lock for the above */
struct timer_list fake_scsi_timer; /* Starts processing of
faked commands */
unsigned char name[9]; unsigned char name[9];
struct list_head port_list_head; /* remote port list */ struct list_head port_list_head; /* remote port list */
struct list_head port_remove_lh; /* head of ports to be struct list_head port_remove_lh; /* head of ports to be
...@@ -692,9 +685,6 @@ struct zfcp_adapter { ...@@ -692,9 +685,6 @@ struct zfcp_adapter {
rwlock_t fsf_req_list_lock; /* lock for ops on list of rwlock_t fsf_req_list_lock; /* lock for ops on list of
FSF requests */ FSF requests */
atomic_t fsf_reqs_active; /* # active FSF reqs */ atomic_t fsf_reqs_active; /* # active FSF reqs */
atomic_t scsi_reqs_active; /* # active SCSI reqs */
wait_queue_head_t scsi_reqs_active_wq; /* can be used to wait for
fsf_reqs_active chngs */
struct zfcp_qdio_queue request_queue; /* request queue */ struct zfcp_qdio_queue request_queue; /* request queue */
u32 fsf_req_seq_no; /* FSF cmnd seq number */ u32 fsf_req_seq_no; /* FSF cmnd seq number */
wait_queue_head_t request_wq; /* can be used to wait for wait_queue_head_t request_wq; /* can be used to wait for
...@@ -765,6 +755,8 @@ struct zfcp_unit { ...@@ -765,6 +755,8 @@ struct zfcp_unit {
struct zfcp_erp_action erp_action; /* pending error recovery */ struct zfcp_erp_action erp_action; /* pending error recovery */
atomic_t erp_counter; atomic_t erp_counter;
struct device sysfs_device; /* sysfs device */ struct device sysfs_device; /* sysfs device */
atomic_t scsi_add_work; /* used to synchronize */
wait_queue_head_t scsi_add_wq; /* wait for scsi_add_device */
}; };
/* FSF request */ /* FSF request */
...@@ -809,6 +801,14 @@ struct zfcp_data { ...@@ -809,6 +801,14 @@ struct zfcp_data {
struct notifier_block reboot_notifier; /* used to register cleanup struct notifier_block reboot_notifier; /* used to register cleanup
functions */ functions */
atomic_t loglevel; /* current loglevel */ atomic_t loglevel; /* current loglevel */
#ifndef MODULE /* initial parameters
needed if ipl from a
scsi device is wanted */
char init_busid[BUS_ID_SIZE];
wwn_t init_wwpn;
fcp_lun_t init_fcp_lun;
int init_is_valid;
#endif
#ifdef ZFCP_STAT_REQSIZES /* Statistical accounting #ifdef ZFCP_STAT_REQSIZES /* Statistical accounting
of processed data */ of processed data */
struct list_head read_req_head; struct list_head read_req_head;
...@@ -857,7 +857,7 @@ struct zfcp_statistics { ...@@ -857,7 +857,7 @@ struct zfcp_statistics {
#ifndef atomic_test_mask #ifndef atomic_test_mask
#define atomic_test_mask(mask, target) \ #define atomic_test_mask(mask, target) \
(atomic_read(target) & mask) ((atomic_read(target) & mask) == mask)
#endif #endif
extern void _zfcp_hex_dump(char *, int); extern void _zfcp_hex_dump(char *, int);
...@@ -957,5 +957,4 @@ zfcp_adapter_wait(struct zfcp_adapter *adapter) ...@@ -957,5 +957,4 @@ zfcp_adapter_wait(struct zfcp_adapter *adapter)
wait_event(adapter->remove_wq, atomic_read(&adapter->refcount) == 0); wait_event(adapter->remove_wq, atomic_read(&adapter->refcount) == 0);
} }
#endif /* __KERNEL_- */
#endif /* ZFCP_DEF_H */ #endif /* ZFCP_DEF_H */
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_ERP #define ZFCP_LOG_AREA ZFCP_LOG_AREA_ERP
#define ZFCP_LOG_AREA_PREFIX ZFCP_LOG_AREA_PREFIX_ERP #define ZFCP_LOG_AREA_PREFIX ZFCP_LOG_AREA_PREFIX_ERP
/* this drivers version (do not edit !!! generated and updated by cvs) */ /* this drivers version (do not edit !!! generated and updated by cvs) */
#define ZFCP_ERP_REVISION "$Revision: 1.33 $" #define ZFCP_ERP_REVISION "$Revision: 1.39 $"
#include "zfcp_ext.h" #include "zfcp_ext.h"
...@@ -108,6 +108,9 @@ static int zfcp_erp_action_dismiss(struct zfcp_erp_action *); ...@@ -108,6 +108,9 @@ static int zfcp_erp_action_dismiss(struct zfcp_erp_action *);
static int zfcp_erp_action_enqueue(int, struct zfcp_adapter *, static int zfcp_erp_action_enqueue(int, struct zfcp_adapter *,
struct zfcp_port *, struct zfcp_unit *); struct zfcp_port *, struct zfcp_unit *);
static int zfcp_erp_action_dequeue(struct zfcp_erp_action *); static int zfcp_erp_action_dequeue(struct zfcp_erp_action *);
static void zfcp_erp_action_cleanup(int, struct zfcp_adapter *,
struct zfcp_port *, struct zfcp_unit *,
int);
static void zfcp_erp_action_ready(struct zfcp_erp_action *); static void zfcp_erp_action_ready(struct zfcp_erp_action *);
static int zfcp_erp_action_exists(struct zfcp_erp_action *); static int zfcp_erp_action_exists(struct zfcp_erp_action *);
...@@ -1160,6 +1163,9 @@ zfcp_erp_strategy(struct zfcp_erp_action *erp_action) ...@@ -1160,6 +1163,9 @@ zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
write_unlock(&adapter->erp_lock); write_unlock(&adapter->erp_lock);
read_unlock_irqrestore(&zfcp_data.config_lock, flags); read_unlock_irqrestore(&zfcp_data.config_lock, flags);
if (retval != ZFCP_ERP_CONTINUES)
zfcp_erp_action_cleanup(action, adapter, port, unit, retval);
/* /*
* a few tasks remain when the erp queues are empty * a few tasks remain when the erp queues are empty
* (don't do that if the last action evaluated was dismissed * (don't do that if the last action evaluated was dismissed
...@@ -1451,6 +1457,66 @@ zfcp_erp_strategy_statechange_detected(atomic_t * target_status, u32 erp_status) ...@@ -1451,6 +1457,66 @@ zfcp_erp_strategy_statechange_detected(atomic_t * target_status, u32 erp_status)
!(ZFCP_STATUS_ERP_CLOSE_ONLY & erp_status)); !(ZFCP_STATUS_ERP_CLOSE_ONLY & erp_status));
} }
/**
* zfcp_erp_scsi_add_device
* @data: pointer to a struct zfcp_unit
*
* Registers a logical unit with the SCSI stack.
*/
static void
zfcp_erp_scsi_add_device(void *data)
{
struct {
struct zfcp_unit *unit;
struct work_struct work;
} *p;
p = data;
scsi_add_device(p->unit->port->adapter->scsi_host,
0, p->unit->port->scsi_id, p->unit->scsi_lun);
atomic_set(&p->unit->scsi_add_work, 0);
wake_up(&p->unit->scsi_add_wq);
zfcp_unit_put(p->unit);
kfree(p);
}
/**
* zfcp_erp_schedule_work
* @unit: pointer to unit which should be registered with SCSI stack
*
* Schedules work which registers a unit with the SCSI stack
*/
static int
zfcp_erp_schedule_work(struct zfcp_unit *unit)
{
struct {
struct zfcp_unit * unit;
struct work_struct work;
} *p;
if (atomic_compare_and_swap(0, 1, &unit->scsi_add_work))
return 0;
if ((p = kmalloc(sizeof(*p), GFP_KERNEL)) == NULL) {
ZFCP_LOG_NORMAL("error: Out of resources. Could not register "
"the FCP-LUN 0x%Lx connected to "
"the port with WWPN 0x%Lx connected to "
"the adapter %s with the SCSI stack.\n",
unit->fcp_lun,
unit->port->wwpn,
zfcp_get_busid_by_unit(unit));
atomic_set(&p->unit->scsi_add_work, 0);
return -ENOMEM;
}
zfcp_unit_get(unit);
memset(p, 0, sizeof(*p));
INIT_WORK(&p->work, zfcp_erp_scsi_add_device, p);
p->unit = unit;
schedule_work(&p->work);
return 0;
}
/* /*
* function: * function:
* *
...@@ -1468,10 +1534,6 @@ zfcp_erp_strategy_check_unit(struct zfcp_unit *unit, int result) ...@@ -1468,10 +1534,6 @@ zfcp_erp_strategy_check_unit(struct zfcp_unit *unit, int result)
if (result == ZFCP_ERP_SUCCEEDED) { if (result == ZFCP_ERP_SUCCEEDED) {
atomic_set(&unit->erp_counter, 0); atomic_set(&unit->erp_counter, 0);
zfcp_erp_unit_unblock(unit); zfcp_erp_unit_unblock(unit);
/* register unit with scsi stack */
if (!unit->device)
scsi_add_device(unit->port->adapter->scsi_host,
0, unit->port->scsi_id, unit->scsi_lun);
} else { } else {
/* ZFCP_ERP_FAILED or ZFCP_ERP_EXIT */ /* ZFCP_ERP_FAILED or ZFCP_ERP_EXIT */
atomic_inc(&unit->erp_counter); atomic_inc(&unit->erp_counter);
...@@ -1773,9 +1835,8 @@ zfcp_erp_port_reopen_all_internal(struct zfcp_adapter *adapter, int clear_mask) ...@@ -1773,9 +1835,8 @@ zfcp_erp_port_reopen_all_internal(struct zfcp_adapter *adapter, int clear_mask)
struct zfcp_port *port; struct zfcp_port *port;
list_for_each_entry(port, &adapter->port_list_head, list) list_for_each_entry(port, &adapter->port_list_head, list)
if (atomic_test_mask(ZFCP_STATUS_PORT_NAMESERVER, &port->status) if (!atomic_test_mask(ZFCP_STATUS_PORT_NAMESERVER, &port->status))
!= ZFCP_STATUS_PORT_NAMESERVER) zfcp_erp_port_reopen_internal(port, clear_mask);
zfcp_erp_port_reopen_internal(port, clear_mask);
return retval; return retval;
} }
...@@ -2333,8 +2394,8 @@ zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action) ...@@ -2333,8 +2394,8 @@ zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action)
* open flag is unset - however, this is for readabilty ... * open flag is unset - however, this is for readabilty ...
*/ */
if (atomic_test_mask((ZFCP_STATUS_PORT_PHYS_OPEN | if (atomic_test_mask((ZFCP_STATUS_PORT_PHYS_OPEN |
ZFCP_STATUS_COMMON_OPEN), &port->status) ZFCP_STATUS_COMMON_OPEN),
== (ZFCP_STATUS_PORT_PHYS_OPEN | ZFCP_STATUS_COMMON_OPEN)) { &port->status)) {
ZFCP_LOG_DEBUG("Port wwpn=0x%Lx is open -> trying " ZFCP_LOG_DEBUG("Port wwpn=0x%Lx is open -> trying "
" close physical\n", " close physical\n",
port->wwpn); port->wwpn);
...@@ -2433,8 +2494,7 @@ zfcp_erp_port_strategy_open(struct zfcp_erp_action *erp_action) ...@@ -2433,8 +2494,7 @@ zfcp_erp_port_strategy_open(struct zfcp_erp_action *erp_action)
int retval; int retval;
if (atomic_test_mask(ZFCP_STATUS_PORT_NAMESERVER, if (atomic_test_mask(ZFCP_STATUS_PORT_NAMESERVER,
&erp_action->port->status) &erp_action->port->status))
== ZFCP_STATUS_PORT_NAMESERVER)
retval = zfcp_erp_port_strategy_open_nameserver(erp_action); retval = zfcp_erp_port_strategy_open_nameserver(erp_action);
else else
retval = zfcp_erp_port_strategy_open_common(erp_action); retval = zfcp_erp_port_strategy_open_common(erp_action);
...@@ -3040,6 +3100,12 @@ zfcp_erp_action_enqueue(int action, ...@@ -3040,6 +3100,12 @@ zfcp_erp_action_enqueue(int action,
sizeof (fcp_lun_t)); sizeof (fcp_lun_t));
goto out; goto out;
} }
if (!atomic_test_mask
(ZFCP_STATUS_COMMON_RUNNING, &port->status) ||
atomic_test_mask
(ZFCP_STATUS_COMMON_ERP_FAILED, &port->status)) {
goto out;
}
if (!atomic_test_mask if (!atomic_test_mask
(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status)) { (ZFCP_STATUS_COMMON_UNBLOCKED, &port->status)) {
stronger_action = ZFCP_ERP_ACTION_REOPEN_PORT; stronger_action = ZFCP_ERP_ACTION_REOPEN_PORT;
...@@ -3067,6 +3133,12 @@ zfcp_erp_action_enqueue(int action, ...@@ -3067,6 +3133,12 @@ zfcp_erp_action_enqueue(int action,
sizeof (wwn_t)); sizeof (wwn_t));
goto out; goto out;
} }
if (!atomic_test_mask
(ZFCP_STATUS_COMMON_RUNNING, &adapter->status) ||
atomic_test_mask
(ZFCP_STATUS_COMMON_ERP_FAILED, &adapter->status)) {
goto out;
}
if (!atomic_test_mask if (!atomic_test_mask
(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status)) { (ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status)) {
stronger_action = ZFCP_ERP_ACTION_REOPEN_ADAPTER; stronger_action = ZFCP_ERP_ACTION_REOPEN_ADAPTER;
...@@ -3178,18 +3250,15 @@ zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action) ...@@ -3178,18 +3250,15 @@ zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action)
case ZFCP_ERP_ACTION_REOPEN_UNIT: case ZFCP_ERP_ACTION_REOPEN_UNIT:
atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
&erp_action->unit->status); &erp_action->unit->status);
zfcp_unit_put(erp_action->unit);
break; break;
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
case ZFCP_ERP_ACTION_REOPEN_PORT: case ZFCP_ERP_ACTION_REOPEN_PORT:
atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
&erp_action->port->status); &erp_action->port->status);
zfcp_port_put(erp_action->port);
break; break;
case ZFCP_ERP_ACTION_REOPEN_ADAPTER: case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
&erp_action->adapter->status); &erp_action->adapter->status);
zfcp_adapter_put(adapter);
break; break;
default: default:
/* bug */ /* bug */
...@@ -3198,6 +3267,39 @@ zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action) ...@@ -3198,6 +3267,39 @@ zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action)
return retval; return retval;
} }
/**
* zfcp_erp_action_cleanup
*
* registers unit with scsi stack if appropiate and fixes reference counts
*/
static void
zfcp_erp_action_cleanup(int action, struct zfcp_adapter *adapter,
struct zfcp_port *port, struct zfcp_unit *unit,
int result)
{
if ((action == ZFCP_ERP_ACTION_REOPEN_UNIT)
&& (result == ZFCP_ERP_SUCCEEDED)
&& (!unit->device)) {
zfcp_erp_schedule_work(unit);
}
switch (action) {
case ZFCP_ERP_ACTION_REOPEN_UNIT:
zfcp_unit_put(unit);
break;
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
case ZFCP_ERP_ACTION_REOPEN_PORT:
zfcp_port_put(port);
break;
case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
zfcp_adapter_put(adapter);
break;
default:
break;
}
}
/* /*
* function: * function:
* *
......
...@@ -30,9 +30,7 @@ ...@@ -30,9 +30,7 @@
#ifndef ZFCP_EXT_H #ifndef ZFCP_EXT_H
#define ZFCP_EXT_H #define ZFCP_EXT_H
/* this drivers version (do not edit !!! generated and updated by cvs) */ /* this drivers version (do not edit !!! generated and updated by cvs) */
#define ZFCP_EXT_REVISION "$Revision: 1.33 $" #define ZFCP_EXT_REVISION "$Revision: 1.38 $"
#ifdef __KERNEL__
#include "zfcp_def.h" #include "zfcp_def.h"
...@@ -44,7 +42,9 @@ extern void zfcp_sysfs_driver_remove_files(struct device_driver *); ...@@ -44,7 +42,9 @@ extern void zfcp_sysfs_driver_remove_files(struct device_driver *);
extern int zfcp_sysfs_adapter_create_files(struct device *); extern int zfcp_sysfs_adapter_create_files(struct device *);
extern void zfcp_sysfs_adapter_remove_files(struct device *); extern void zfcp_sysfs_adapter_remove_files(struct device *);
extern int zfcp_sysfs_port_create_files(struct device *, u32); extern int zfcp_sysfs_port_create_files(struct device *, u32);
extern void zfcp_sysfs_port_remove_files(struct device *, u32);
extern int zfcp_sysfs_unit_create_files(struct device *); extern int zfcp_sysfs_unit_create_files(struct device *);
extern void zfcp_sysfs_unit_remove_files(struct device *);
extern void zfcp_sysfs_port_release(struct device *); extern void zfcp_sysfs_port_release(struct device *);
extern int zfcp_sysfs_port_shutdown(struct zfcp_port *); extern int zfcp_sysfs_port_shutdown(struct zfcp_port *);
extern void zfcp_sysfs_unit_release(struct device *); extern void zfcp_sysfs_unit_release(struct device *);
...@@ -112,9 +112,6 @@ extern void zfcp_fsf_els_processing(struct zfcp_fsf_req *); ...@@ -112,9 +112,6 @@ extern void zfcp_fsf_els_processing(struct zfcp_fsf_req *);
extern int zfcp_adapter_scsi_register(struct zfcp_adapter *); extern int zfcp_adapter_scsi_register(struct zfcp_adapter *);
extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *); extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *);
extern void zfcp_scsi_block_requests(struct Scsi_Host *); extern void zfcp_scsi_block_requests(struct Scsi_Host *);
extern void zfcp_scsi_insert_into_fake_queue(struct zfcp_adapter *,
Scsi_Cmnd *);
extern void zfcp_scsi_process_and_clear_fake_queue(unsigned long);
extern int zfcp_create_sbals_from_sg(struct zfcp_fsf_req *, extern int zfcp_create_sbals_from_sg(struct zfcp_fsf_req *,
Scsi_Cmnd *, char, int, int); Scsi_Cmnd *, char, int, int);
extern void zfcp_set_fcp_dl(struct fcp_cmnd_iu *, fcp_dl_t); extern void zfcp_set_fcp_dl(struct fcp_cmnd_iu *, fcp_dl_t);
...@@ -159,5 +156,4 @@ extern void zfcp_in_els_dbf_event(struct zfcp_adapter *, const char *, ...@@ -159,5 +156,4 @@ extern void zfcp_in_els_dbf_event(struct zfcp_adapter *, const char *,
#ifdef ZFCP_STAT_REQSIZES #ifdef ZFCP_STAT_REQSIZES
extern int zfcp_statistics_inc(struct list_head *, u32); extern int zfcp_statistics_inc(struct list_head *, u32);
#endif #endif
#endif /* __KERNEL__ */
#endif /* ZFCP_EXT_H */ #endif /* ZFCP_EXT_H */
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
*/ */
/* this drivers version (do not edit !!! generated and updated by cvs) */ /* this drivers version (do not edit !!! generated and updated by cvs) */
#define ZFCP_FSF_C_REVISION "$Revision: 1.12 $" #define ZFCP_FSF_C_REVISION "$Revision: 1.16 $"
#include "zfcp_ext.h" #include "zfcp_ext.h"
...@@ -101,7 +101,8 @@ zfcp_fsf_req_alloc(struct zfcp_adapter *adapter, u32 fsf_cmd, int kmalloc_flags) ...@@ -101,7 +101,8 @@ zfcp_fsf_req_alloc(struct zfcp_adapter *adapter, u32 fsf_cmd, int kmalloc_flags)
case FSF_QTCB_ABORT_FCP_CMND: case FSF_QTCB_ABORT_FCP_CMND:
fsf_req = zfcp_fsf_req_get(kmalloc_flags, fsf_req = zfcp_fsf_req_get(kmalloc_flags,
adapter->pool.fcp_command_fsf); adapter->pool.fcp_command_fsf);
if (fsf_req && (fsf_req->status & ZFCP_STATUS_FSFREQ_POOL)) { if (unlikely(fsf_req &&
(fsf_req->status & ZFCP_STATUS_FSFREQ_POOL))) {
/* /*
* watch low mem buffer * watch low mem buffer
* Note: If the command is reset or aborted, two * Note: If the command is reset or aborted, two
...@@ -116,7 +117,8 @@ zfcp_fsf_req_alloc(struct zfcp_adapter *adapter, u32 fsf_cmd, int kmalloc_flags) ...@@ -116,7 +117,8 @@ zfcp_fsf_req_alloc(struct zfcp_adapter *adapter, u32 fsf_cmd, int kmalloc_flags)
} }
#ifdef ZFCP_DEBUG_REQUESTS #ifdef ZFCP_DEBUG_REQUESTS
debug_text_event(adapter->req_dbf, 5, "fsfa_fcp"); debug_text_event(adapter->req_dbf, 5, "fsfa_fcp");
if (fsf_req && (fsf_req->status & ZFCP_STATUS_FSFREQ_POOL)) if (unlikely(fsf_req &&
(fsf_req->status & ZFCP_STATUS_FSFREQ_POOL)))
debug_text_event(adapter->req_dbf, 5, "fsfa_pl"); debug_text_event(adapter->req_dbf, 5, "fsfa_pl");
#endif /* ZFCP_DEBUG_REQUESTS */ #endif /* ZFCP_DEBUG_REQUESTS */
break; break;
...@@ -158,7 +160,7 @@ zfcp_fsf_req_alloc(struct zfcp_adapter *adapter, u32 fsf_cmd, int kmalloc_flags) ...@@ -158,7 +160,7 @@ zfcp_fsf_req_alloc(struct zfcp_adapter *adapter, u32 fsf_cmd, int kmalloc_flags)
"(debug info 0x%x)\n", fsf_cmd); "(debug info 0x%x)\n", fsf_cmd);
} //switch(fsf_cmd) } //switch(fsf_cmd)
if (!fsf_req) { if (unlikely(!fsf_req)) {
ZFCP_LOG_DEBUG("error: Out of memory. Allocation of FSF " ZFCP_LOG_DEBUG("error: Out of memory. Allocation of FSF "
"request structure failed\n"); "request structure failed\n");
} else { } else {
...@@ -171,7 +173,7 @@ zfcp_fsf_req_alloc(struct zfcp_adapter *adapter, u32 fsf_cmd, int kmalloc_flags) ...@@ -171,7 +173,7 @@ zfcp_fsf_req_alloc(struct zfcp_adapter *adapter, u32 fsf_cmd, int kmalloc_flags)
#ifdef ZFCP_DEBUG_REQUESTS #ifdef ZFCP_DEBUG_REQUESTS
debug_event(adapter->req_dbf, 5, &fsf_req, sizeof (unsigned long)); debug_event(adapter->req_dbf, 5, &fsf_req, sizeof (unsigned long));
if (fsf_req->qtcb) if (likely(fsf_req->qtcb))
debug_event(adapter->req_dbf, 5, &fsf_req->qtcb, debug_event(adapter->req_dbf, 5, &fsf_req->qtcb,
sizeof (unsigned long)); sizeof (unsigned long));
#endif /* ZFCP_DEBUG_REQUESTS */ #endif /* ZFCP_DEBUG_REQUESTS */
...@@ -198,7 +200,7 @@ zfcp_fsf_req_free(struct zfcp_fsf_req *fsf_req) ...@@ -198,7 +200,7 @@ zfcp_fsf_req_free(struct zfcp_fsf_req *fsf_req)
case FSF_QTCB_FCP_CMND: case FSF_QTCB_FCP_CMND:
case FSF_QTCB_ABORT_FCP_CMND: case FSF_QTCB_ABORT_FCP_CMND:
if (fsf_req->status & ZFCP_STATUS_FSFREQ_POOL) { if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_POOL)) {
del_timer(&adapter->pool.fcp_command_fsf_timer); del_timer(&adapter->pool.fcp_command_fsf_timer);
mempool_free(fsf_req, adapter->pool.fcp_command_fsf); mempool_free(fsf_req, adapter->pool.fcp_command_fsf);
} else } else
...@@ -299,7 +301,7 @@ zfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req) ...@@ -299,7 +301,7 @@ zfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req)
/* do some statistics */ /* do some statistics */
atomic_dec(&adapter->fsf_reqs_active); atomic_dec(&adapter->fsf_reqs_active);
if (fsf_req->fsf_command == FSF_QTCB_UNSOLICITED_STATUS) { if (unlikely(fsf_req->fsf_command == FSF_QTCB_UNSOLICITED_STATUS)) {
ZFCP_LOG_DEBUG("Status read response received\n"); ZFCP_LOG_DEBUG("Status read response received\n");
/* /*
* Note: all cleanup handling is done in the callchain of * Note: all cleanup handling is done in the callchain of
...@@ -314,7 +316,7 @@ zfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req) ...@@ -314,7 +316,7 @@ zfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req)
* fsf_req may be deleted due to waking up functions, so * fsf_req may be deleted due to waking up functions, so
* cleanup is saved here and used later * cleanup is saved here and used later
*/ */
if (fsf_req->status & ZFCP_STATUS_FSFREQ_CLEANUP) if (likely(fsf_req->status & ZFCP_STATUS_FSFREQ_CLEANUP))
cleanup = 1; cleanup = 1;
else else
cleanup = 0; cleanup = 0;
...@@ -322,7 +324,7 @@ zfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req) ...@@ -322,7 +324,7 @@ zfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req)
fsf_req->status |= ZFCP_STATUS_FSFREQ_COMPLETED; fsf_req->status |= ZFCP_STATUS_FSFREQ_COMPLETED;
/* cleanup request if requested by initiator */ /* cleanup request if requested by initiator */
if (cleanup) { if (likely(cleanup)) {
ZFCP_LOG_TRACE("removing FSF request 0x%lx\n", ZFCP_LOG_TRACE("removing FSF request 0x%lx\n",
(unsigned long) fsf_req); (unsigned long) fsf_req);
/* /*
...@@ -334,6 +336,16 @@ zfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req) ...@@ -334,6 +336,16 @@ zfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req)
/* notify initiator waiting for the requests completion */ /* notify initiator waiting for the requests completion */
ZFCP_LOG_TRACE("waking initiator of FSF request 0x%lx\n", ZFCP_LOG_TRACE("waking initiator of FSF request 0x%lx\n",
(unsigned long) fsf_req); (unsigned long) fsf_req);
/*
* FIXME: Race! We must not access fsf_req here as it might have been
* cleaned up already due to the set ZFCP_STATUS_FSFREQ_COMPLETED
* flag. It's an improbable case. But, we have the same paranoia for
* the cleanup flag already.
* Might better be handled using complete()?
* (setting the flag and doing wakeup ought to be atomic
* with regard to checking the flag as long as waitqueue is
* part of the to be released structure)
*/
wake_up(&fsf_req->completion_wq); wake_up(&fsf_req->completion_wq);
} }
...@@ -372,7 +384,7 @@ zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *fsf_req) ...@@ -372,7 +384,7 @@ zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *fsf_req)
} }
/* log additional information provided by FSF (if any) */ /* log additional information provided by FSF (if any) */
if (fsf_req->qtcb->header.log_length) { if (unlikely(fsf_req->qtcb->header.log_length)) {
/* do not trust them ;-) */ /* do not trust them ;-) */
if (fsf_req->qtcb->header.log_start > ZFCP_QTCB_SIZE) { if (fsf_req->qtcb->header.log_start > ZFCP_QTCB_SIZE) {
ZFCP_LOG_NORMAL ZFCP_LOG_NORMAL
...@@ -686,7 +698,7 @@ zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *fsf_req) ...@@ -686,7 +698,7 @@ zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *fsf_req)
{ {
int retval = 0; int retval = 0;
if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
goto skip_fsfstatus; goto skip_fsfstatus;
} }
...@@ -835,7 +847,7 @@ zfcp_fsf_req_dispatch(struct zfcp_fsf_req *fsf_req) ...@@ -835,7 +847,7 @@ zfcp_fsf_req_dispatch(struct zfcp_fsf_req *fsf_req)
{ {
int retval = 0; int retval = 0;
if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
ZFCP_LOG_TRACE("fsf_req=0x%lx, QTCB=0x%lx\n", ZFCP_LOG_TRACE("fsf_req=0x%lx, QTCB=0x%lx\n",
(unsigned long) fsf_req, (unsigned long) fsf_req,
(unsigned long) (fsf_req->qtcb)); (unsigned long) (fsf_req->qtcb));
...@@ -1996,6 +2008,20 @@ zfcp_fsf_open_port_handler(struct zfcp_fsf_req *fsf_req) ...@@ -1996,6 +2008,20 @@ zfcp_fsf_open_port_handler(struct zfcp_fsf_req *fsf_req)
ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
retval = 0; retval = 0;
/* check whether D_ID has changed during open */ /* check whether D_ID has changed during open */
/*
* FIXME: This check is not airtight, as the FCP channel does
* not monitor closures of target port connections caused on
* the remote side. Thus, they might miss out on invalidating
* locally cached WWPNs (and other N_Port parameters) of gone
* target ports. So, our heroic attempt to make things safe
* could be undermined by 'open port' response data tagged with
* obsolete WWPNs. Another reason to monitor potential
* connection closures ourself at least (by interpreting
* incoming ELS' and unsolicited status). It just crosses my
* mind that one should be able to cross-check by means of
* another GID_PN straight after a port has been opened.
* Alternately, an ADISC/PDISC ELS should suffice, as well.
*/
plogi = (struct fsf_plogi *) fsf_req->qtcb->bottom.support.els; plogi = (struct fsf_plogi *) fsf_req->qtcb->bottom.support.els;
if (!atomic_test_mask(ZFCP_STATUS_PORT_NO_WWPN, &port->status)) if (!atomic_test_mask(ZFCP_STATUS_PORT_NO_WWPN, &port->status))
{ {
...@@ -2398,9 +2424,9 @@ zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action) ...@@ -2398,9 +2424,9 @@ zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
} }
erp_action->fsf_req->qtcb->header.port_handle = erp_action->fsf_req->qtcb->header.port_handle =
erp_action->port->handle; erp_action->port->handle;
*(fcp_lun_t *) & (erp_action->fsf_req->qtcb->bottom.support.fcp_lun) erp_action->fsf_req->qtcb->bottom.support.fcp_lun =
= erp_action->unit->fcp_lun; erp_action->unit->fcp_lun;
atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->unit->status); atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->unit->status);
erp_action->fsf_req->data.open_unit.unit = erp_action->unit; erp_action->fsf_req->data.open_unit.unit = erp_action->unit;
erp_action->fsf_req->erp_action = erp_action; erp_action->fsf_req->erp_action = erp_action;
...@@ -2835,7 +2861,7 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter, ...@@ -2835,7 +2861,7 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
retval = zfcp_fsf_req_create(adapter, retval = zfcp_fsf_req_create(adapter,
FSF_QTCB_FCP_CMND, FSF_QTCB_FCP_CMND,
&lock_flags, req_flags, &(fsf_req)); &lock_flags, req_flags, &(fsf_req));
if (retval < 0) { if (unlikely(retval < 0)) {
ZFCP_LOG_DEBUG("error: Out of resources. Could not create an " ZFCP_LOG_DEBUG("error: Out of resources. Could not create an "
"FCP command request for FCP-LUN 0x%Lx " "FCP command request for FCP-LUN 0x%Lx "
"connected to the port with WWPN 0x%Lx " "connected to the port with WWPN 0x%Lx "
...@@ -2928,7 +2954,7 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter, ...@@ -2928,7 +2954,7 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
fcp_cmnd_iu->fcp_lun = unit->fcp_lun; fcp_cmnd_iu->fcp_lun = unit->fcp_lun;
/* set task attributes in FCP_CMND IU in QTCB */ /* set task attributes in FCP_CMND IU in QTCB */
if (scsi_cmnd->device->simple_tags) { if (likely(scsi_cmnd->device->simple_tags)) {
fcp_cmnd_iu->task_attribute = SIMPLE_Q; fcp_cmnd_iu->task_attribute = SIMPLE_Q;
ZFCP_LOG_TRACE("setting SIMPLE_Q task attribute\n"); ZFCP_LOG_TRACE("setting SIMPLE_Q task attribute\n");
} else { } else {
...@@ -2937,7 +2963,7 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter, ...@@ -2937,7 +2963,7 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
} }
/* set additional length of FCP_CDB in FCP_CMND IU in QTCB, if needed */ /* set additional length of FCP_CDB in FCP_CMND IU in QTCB, if needed */
if (scsi_cmnd->cmd_len > FCP_CDB_LENGTH) { if (unlikely(scsi_cmnd->cmd_len > FCP_CDB_LENGTH)) {
fcp_cmnd_iu->add_fcp_cdb_length fcp_cmnd_iu->add_fcp_cdb_length
= (scsi_cmnd->cmd_len - FCP_CDB_LENGTH) >> 2; = (scsi_cmnd->cmd_len - FCP_CDB_LENGTH) >> 2;
ZFCP_LOG_TRACE("SCSI CDB length is 0x%x, " ZFCP_LOG_TRACE("SCSI CDB length is 0x%x, "
...@@ -2965,9 +2991,9 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter, ...@@ -2965,9 +2991,9 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
/* Note: >= and not = because the combined scatter-gather entries /* Note: >= and not = because the combined scatter-gather entries
* may be larger than request_bufflen according to the mailing list * may be larger than request_bufflen according to the mailing list
*/ */
if (real_bytes >= scsi_cmnd->request_bufflen) { if (likely(real_bytes >= scsi_cmnd->request_bufflen)) {
ZFCP_LOG_TRACE("Data fits\n"); ZFCP_LOG_TRACE("Data fits\n");
} else if (real_bytes == 0) { } else if (likely(real_bytes == 0)) {
ZFCP_LOG_DEBUG("Data did not fit into available buffer(s), " ZFCP_LOG_DEBUG("Data did not fit into available buffer(s), "
"waiting for more...\n"); "waiting for more...\n");
retval = -EIO; retval = -EIO;
...@@ -2996,7 +3022,7 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter, ...@@ -2996,7 +3022,7 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
* covered by an SBALE) * covered by an SBALE)
*/ */
retval = zfcp_fsf_req_send(fsf_req, NULL); retval = zfcp_fsf_req_send(fsf_req, NULL);
if (retval < 0) { if (unlikely(retval < 0)) {
ZFCP_LOG_INFO("error: Could not send an FCP command request " ZFCP_LOG_INFO("error: Could not send an FCP command request "
"for a command on the adapter %s, " "for a command on the adapter %s, "
"port WWPN 0x%Lx and unit LUN 0x%Lx\n", "port WWPN 0x%Lx and unit LUN 0x%Lx\n",
...@@ -3139,12 +3165,12 @@ zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req) ...@@ -3139,12 +3165,12 @@ zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req)
int retval = -EINVAL; int retval = -EINVAL;
struct zfcp_unit *unit; struct zfcp_unit *unit;
if (fsf_req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT) if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT))
unit = fsf_req->data.send_fcp_command_task_management.unit; unit = fsf_req->data.send_fcp_command_task_management.unit;
else else
unit = fsf_req->data.send_fcp_command_task.unit; unit = fsf_req->data.send_fcp_command_task.unit;
if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
/* go directly to calls of special handlers */ /* go directly to calls of special handlers */
goto skip_fsfstatus; goto skip_fsfstatus;
} }
...@@ -3445,7 +3471,6 @@ static int ...@@ -3445,7 +3471,6 @@ static int
zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
{ {
int retval = 0; int retval = 0;
struct zfcp_adapter *adapter = fsf_req->adapter;
Scsi_Cmnd *scpnt; Scsi_Cmnd *scpnt;
struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *) struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *)
...@@ -3459,14 +3484,14 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) ...@@ -3459,14 +3484,14 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
read_lock_irqsave(&fsf_req->adapter->abort_lock, flags); read_lock_irqsave(&fsf_req->adapter->abort_lock, flags);
scpnt = fsf_req->data.send_fcp_command_task.scsi_cmnd; scpnt = fsf_req->data.send_fcp_command_task.scsi_cmnd;
if (!scpnt) { if (unlikely(!scpnt)) {
ZFCP_LOG_DEBUG ZFCP_LOG_DEBUG
("Command with fsf_req 0x%lx is not associated to " ("Command with fsf_req 0x%lx is not associated to "
"a scsi command anymore. Aborted?\n", "a scsi command anymore. Aborted?\n",
(unsigned long) fsf_req); (unsigned long) fsf_req);
goto out; goto out;
} }
if (fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTED) { if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTED)) {
/* FIXME: (design) mid-layer should handle DID_ABORT like /* FIXME: (design) mid-layer should handle DID_ABORT like
* DID_SOFT_ERROR by retrying the request for devices * DID_SOFT_ERROR by retrying the request for devices
* that allow retries. * that allow retries.
...@@ -3477,7 +3502,7 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) ...@@ -3477,7 +3502,7 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
goto skip_fsfstatus; goto skip_fsfstatus;
} }
if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
ZFCP_LOG_DEBUG("Setting DID_ERROR\n"); ZFCP_LOG_DEBUG("Setting DID_ERROR\n");
set_host_byte(&scpnt->result, DID_ERROR); set_host_byte(&scpnt->result, DID_ERROR);
goto skip_fsfstatus; goto skip_fsfstatus;
...@@ -3491,7 +3516,7 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) ...@@ -3491,7 +3516,7 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
* of result in SCSI command * of result in SCSI command
*/ */
scpnt->result |= fcp_rsp_iu->scsi_status; scpnt->result |= fcp_rsp_iu->scsi_status;
if (fcp_rsp_iu->scsi_status) { if (unlikely(fcp_rsp_iu->scsi_status)) {
/* DEBUG */ /* DEBUG */
ZFCP_LOG_NORMAL("status for SCSI Command:\n"); ZFCP_LOG_NORMAL("status for SCSI Command:\n");
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL, ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL,
...@@ -3507,7 +3532,7 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) ...@@ -3507,7 +3532,7 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
} }
/* check FCP_RSP_INFO */ /* check FCP_RSP_INFO */
if (fcp_rsp_iu->validity.bits.fcp_rsp_len_valid) { if (unlikely(fcp_rsp_iu->validity.bits.fcp_rsp_len_valid)) {
ZFCP_LOG_DEBUG("rsp_len is valid\n"); ZFCP_LOG_DEBUG("rsp_len is valid\n");
switch (fcp_rsp_info[3]) { switch (fcp_rsp_info[3]) {
case RSP_CODE_GOOD: case RSP_CODE_GOOD:
...@@ -3600,7 +3625,7 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) ...@@ -3600,7 +3625,7 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
} }
/* check for sense data */ /* check for sense data */
if (fcp_rsp_iu->validity.bits.fcp_sns_len_valid) { if (unlikely(fcp_rsp_iu->validity.bits.fcp_sns_len_valid)) {
sns_len = FSF_FCP_RSP_SIZE - sns_len = FSF_FCP_RSP_SIZE -
sizeof (struct fcp_rsp_iu) + fcp_rsp_iu->fcp_rsp_len; sizeof (struct fcp_rsp_iu) + fcp_rsp_iu->fcp_rsp_len;
ZFCP_LOG_TRACE("room for %i bytes sense data in QTCB\n", ZFCP_LOG_TRACE("room for %i bytes sense data in QTCB\n",
...@@ -3623,7 +3648,7 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) ...@@ -3623,7 +3648,7 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
} }
/* check for overrun */ /* check for overrun */
if (fcp_rsp_iu->validity.bits.fcp_resid_over) { if (unlikely(fcp_rsp_iu->validity.bits.fcp_resid_over)) {
ZFCP_LOG_INFO("A data overrun was detected for a command. " ZFCP_LOG_INFO("A data overrun was detected for a command. "
"This happened for a command to the unit " "This happened for a command to the unit "
"with FCP LUN 0x%Lx connected to the " "with FCP LUN 0x%Lx connected to the "
...@@ -3638,7 +3663,7 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) ...@@ -3638,7 +3663,7 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
} }
/* check for underrun */ /* check for underrun */
if (fcp_rsp_iu->validity.bits.fcp_resid_under) { if (unlikely(fcp_rsp_iu->validity.bits.fcp_resid_under)) {
ZFCP_LOG_DEBUG("A data underrun was detected for a command. " ZFCP_LOG_DEBUG("A data underrun was detected for a command. "
"This happened for a command to the unit " "This happened for a command to the unit "
"with FCP LUN 0x%Lx connected to the " "with FCP LUN 0x%Lx connected to the "
...@@ -3755,9 +3780,6 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) ...@@ -3755,9 +3780,6 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
* the new eh * the new eh
*/ */
/* always call back */ /* always call back */
(scpnt->scsi_done) (scpnt);
atomic_dec(&adapter->scsi_reqs_active);
wake_up(&adapter->scsi_reqs_active_wq);
#ifdef ZFCP_DEBUG_REQUESTS #ifdef ZFCP_DEBUG_REQUESTS
debug_text_event(fsf_req->adapter->req_dbf, 2, "ok_done:"); debug_text_event(fsf_req->adapter->req_dbf, 2, "ok_done:");
debug_event(fsf_req->adapter->req_dbf, 2, &scpnt, debug_event(fsf_req->adapter->req_dbf, 2, &scpnt,
...@@ -3768,8 +3790,6 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) ...@@ -3768,8 +3790,6 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
sizeof (unsigned long)); sizeof (unsigned long));
#endif /* ZFCP_DEBUG_REQUESTS */ #endif /* ZFCP_DEBUG_REQUESTS */
(scpnt->scsi_done) (scpnt); (scpnt->scsi_done) (scpnt);
atomic_dec(&adapter->scsi_reqs_active);
wake_up(&adapter->scsi_reqs_active_wq);
/* /*
* We must hold this lock until scsi_done has been called. * We must hold this lock until scsi_done has been called.
* Otherwise we may call scsi_done after abort regarding this * Otherwise we may call scsi_done after abort regarding this
...@@ -3904,7 +3924,7 @@ zfcp_fsf_req_create_sbal_check(unsigned long *flags, ...@@ -3904,7 +3924,7 @@ zfcp_fsf_req_create_sbal_check(unsigned long *flags,
struct zfcp_qdio_queue *queue, int needed) struct zfcp_qdio_queue *queue, int needed)
{ {
write_lock_irqsave(&queue->queue_lock, *flags); write_lock_irqsave(&queue->queue_lock, *flags);
if (atomic_read(&queue->free_count) >= needed) if (likely(atomic_read(&queue->free_count) >= needed))
return 1; return 1;
write_unlock_irqrestore(&queue->queue_lock, *flags); write_unlock_irqrestore(&queue->queue_lock, *flags);
return 0; return 0;
...@@ -3942,7 +3962,7 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter, ...@@ -3942,7 +3962,7 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter,
/* allocate new FSF request */ /* allocate new FSF request */
fsf_req = zfcp_fsf_req_alloc(adapter, fsf_cmd, GFP_ATOMIC); fsf_req = zfcp_fsf_req_alloc(adapter, fsf_cmd, GFP_ATOMIC);
if (!fsf_req) { if (unlikely(!fsf_req)) {
ZFCP_LOG_DEBUG("error: Could not put an FSF request into" ZFCP_LOG_DEBUG("error: Could not put an FSF request into"
"the outbound (send) queue.\n"); "the outbound (send) queue.\n");
retval = -ENOMEM; retval = -ENOMEM;
...@@ -3960,11 +3980,11 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter, ...@@ -3960,11 +3980,11 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter,
fsf_req->specific_magic = ZFCP_MAGIC_FSFREQ; fsf_req->specific_magic = ZFCP_MAGIC_FSFREQ;
fsf_req->fsf_command = fsf_cmd; fsf_req->fsf_command = fsf_cmd;
if (req_flags & ZFCP_REQ_AUTO_CLEANUP) if (likely(req_flags & ZFCP_REQ_AUTO_CLEANUP))
fsf_req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; fsf_req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
/* initialize QTCB */ /* initialize QTCB */
if (fsf_cmd != FSF_QTCB_UNSOLICITED_STATUS) { if (likely(fsf_cmd != FSF_QTCB_UNSOLICITED_STATUS)) {
ZFCP_LOG_TRACE("fsf_req->qtcb=0x%lx\n", ZFCP_LOG_TRACE("fsf_req->qtcb=0x%lx\n",
(unsigned long) fsf_req->qtcb); (unsigned long) fsf_req->qtcb);
fsf_req->qtcb->prefix.req_id = (unsigned long) fsf_req; fsf_req->qtcb->prefix.req_id = (unsigned long) fsf_req;
...@@ -3983,7 +4003,7 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter, ...@@ -3983,7 +4003,7 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter,
* try to get needed SBALs in request queue (get queue lock on success) * try to get needed SBALs in request queue (get queue lock on success)
*/ */
ZFCP_LOG_TRACE("try to get free BUFFER in request queue\n"); ZFCP_LOG_TRACE("try to get free BUFFER in request queue\n");
if (req_flags & ZFCP_WAIT_FOR_SBAL) { if (unlikely(req_flags & ZFCP_WAIT_FOR_SBAL)) {
timeout = ZFCP_SBAL_TIMEOUT; timeout = ZFCP_SBAL_TIMEOUT;
ZFCP_WAIT_EVENT_TIMEOUT(adapter->request_wq, ZFCP_WAIT_EVENT_TIMEOUT(adapter->request_wq,
timeout, timeout,
...@@ -4009,7 +4029,7 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter, ...@@ -4009,7 +4029,7 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter,
/* setup common SBALE fields */ /* setup common SBALE fields */
buffere[0].addr = fsf_req; buffere[0].addr = fsf_req;
buffere[0].flags |= SBAL_FLAGS0_COMMAND; buffere[0].flags |= SBAL_FLAGS0_COMMAND;
if (fsf_cmd != FSF_QTCB_UNSOLICITED_STATUS) { if (likely(fsf_cmd != FSF_QTCB_UNSOLICITED_STATUS)) {
buffere[1].addr = (void *) fsf_req->qtcb; buffere[1].addr = (void *) fsf_req->qtcb;
buffere[1].length = ZFCP_QTCB_SIZE; buffere[1].length = ZFCP_QTCB_SIZE;
} }
...@@ -4116,7 +4136,7 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer) ...@@ -4116,7 +4136,7 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer)
buffere->length); buffere->length);
/* set sequence counter in QTCB */ /* set sequence counter in QTCB */
if (fsf_req->qtcb) { if (likely(fsf_req->qtcb)) {
fsf_req->qtcb->prefix.req_seq_no = adapter->fsf_req_seq_no; fsf_req->qtcb->prefix.req_seq_no = adapter->fsf_req_seq_no;
fsf_req->seq_no = adapter->fsf_req_seq_no; fsf_req->seq_no = adapter->fsf_req_seq_no;
ZFCP_LOG_TRACE("FSF request 0x%lx of adapter 0x%lx gets " ZFCP_LOG_TRACE("FSF request 0x%lx of adapter 0x%lx gets "
...@@ -4133,7 +4153,7 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer) ...@@ -4133,7 +4153,7 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer)
write_unlock_irqrestore(&adapter->fsf_req_list_lock, flags); write_unlock_irqrestore(&adapter->fsf_req_list_lock, flags);
/* figure out expiration time of timeout and start timeout */ /* figure out expiration time of timeout and start timeout */
if (timer) { if (unlikely(timer)) {
timer->expires += jiffies; timer->expires += jiffies;
add_timer(timer); add_timer(timer);
} }
...@@ -4167,7 +4187,7 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer) ...@@ -4167,7 +4187,7 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer)
QDIO_FLAG_SYNC_OUTPUT, QDIO_FLAG_SYNC_OUTPUT,
0, fsf_req->sbal_index, fsf_req->sbal_count, NULL); 0, fsf_req->sbal_index, fsf_req->sbal_count, NULL);
if (retval) { if (unlikely(retval)) {
/* Queues are down..... */ /* Queues are down..... */
retval = -EIO; retval = -EIO;
/* /*
...@@ -4198,7 +4218,7 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer) ...@@ -4198,7 +4218,7 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer)
debug_text_event(adapter->req_dbf, 1, "o:a/seq"); debug_text_event(adapter->req_dbf, 1, "o:a/seq");
debug_event(adapter->req_dbf, 1, &fsf_req, debug_event(adapter->req_dbf, 1, &fsf_req,
sizeof (unsigned long)); sizeof (unsigned long));
if (inc_seq_no) { if (likely(inc_seq_no)) {
debug_event(adapter->req_dbf, 1, debug_event(adapter->req_dbf, 1,
&adapter->fsf_req_seq_no, sizeof (u32)); &adapter->fsf_req_seq_no, sizeof (u32));
} else { } else {
...@@ -4213,7 +4233,7 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer) ...@@ -4213,7 +4233,7 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer)
* otherwise, * otherwise,
*/ */
/* Don't increase for unsolicited status */ /* Don't increase for unsolicited status */
if (inc_seq_no) { if (likely(inc_seq_no)) {
adapter->fsf_req_seq_no++; adapter->fsf_req_seq_no++;
ZFCP_LOG_TRACE ZFCP_LOG_TRACE
("FSF sequence counter value of adapter 0x%lx " ("FSF sequence counter value of adapter 0x%lx "
...@@ -4263,16 +4283,16 @@ zfcp_fsf_req_get(int kmalloc_flags, mempool_t * pool) ...@@ -4263,16 +4283,16 @@ zfcp_fsf_req_get(int kmalloc_flags, mempool_t * pool)
struct zfcp_fsf_req *fsf_req; struct zfcp_fsf_req *fsf_req;
fsf_req = kmalloc(ZFCP_QTCB_AND_REQ_SIZE, kmalloc_flags); fsf_req = kmalloc(ZFCP_QTCB_AND_REQ_SIZE, kmalloc_flags);
if (fsf_req) { if (likely(fsf_req)) {
memset(fsf_req, 0, ZFCP_QTCB_AND_REQ_SIZE); memset(fsf_req, 0, ZFCP_QTCB_AND_REQ_SIZE);
} else { } else {
fsf_req = mempool_alloc(pool, kmalloc_flags); fsf_req = mempool_alloc(pool, kmalloc_flags);
if (fsf_req) { if (likely(fsf_req)) {
memset(fsf_req, 0, ZFCP_QTCB_AND_REQ_SIZE); memset(fsf_req, 0, ZFCP_QTCB_AND_REQ_SIZE);
fsf_req->status |= ZFCP_STATUS_FSFREQ_POOL; fsf_req->status |= ZFCP_STATUS_FSFREQ_POOL;
} }
} }
if (fsf_req) if (likely(fsf_req))
fsf_req->qtcb = fsf_req->qtcb =
(struct fsf_qtcb *) ((unsigned long) fsf_req + (struct fsf_qtcb *) ((unsigned long) fsf_req +
sizeof (struct zfcp_fsf_req)); sizeof (struct zfcp_fsf_req));
......
...@@ -30,8 +30,6 @@ ...@@ -30,8 +30,6 @@
#ifndef FSF_H #ifndef FSF_H
#define FSF_H #define FSF_H
#ifdef __KERNEL__
#define FSF_QTCB_VERSION1 0x00000001 #define FSF_QTCB_VERSION1 0x00000001
#define FSF_QTCB_CURRENT_VERSION FSF_QTCB_VERSION1 #define FSF_QTCB_CURRENT_VERSION FSF_QTCB_VERSION1
...@@ -354,5 +352,4 @@ struct fsf_qtcb { ...@@ -354,5 +352,4 @@ struct fsf_qtcb {
union fsf_qtcb_bottom bottom; union fsf_qtcb_bottom bottom;
} __attribute__ ((packed)); } __attribute__ ((packed));
#endif /* __KERNEL__ */
#endif /* FSF_H */ #endif /* FSF_H */
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#define ZFCP_QDIO_C_REVISION "$Revision: 1.7 $" #define ZFCP_QDIO_C_REVISION "$Revision: 1.10 $"
#include "zfcp_ext.h" #include "zfcp_ext.h"
...@@ -214,7 +214,7 @@ zfcp_qdio_handler_error_check(struct zfcp_adapter *adapter, ...@@ -214,7 +214,7 @@ zfcp_qdio_handler_error_check(struct zfcp_adapter *adapter,
" QDIO_STATUS_OUTBOUND_INT \n"); " QDIO_STATUS_OUTBOUND_INT \n");
} }
} // if (ZFCP_LOG_CHECK(ZFCP_LOG_LEVEL_TRACE)) } // if (ZFCP_LOG_CHECK(ZFCP_LOG_LEVEL_TRACE))
if (status & QDIO_STATUS_LOOK_FOR_ERROR) { if (unlikely(status & QDIO_STATUS_LOOK_FOR_ERROR)) {
retval = -EIO; retval = -EIO;
ZFCP_LOG_FLAGS(1, "QDIO_STATUS_LOOK_FOR_ERROR \n"); ZFCP_LOG_FLAGS(1, "QDIO_STATUS_LOOK_FOR_ERROR \n");
...@@ -261,7 +261,17 @@ zfcp_qdio_handler_error_check(struct zfcp_adapter *adapter, ...@@ -261,7 +261,17 @@ zfcp_qdio_handler_error_check(struct zfcp_adapter *adapter,
} }
/* Restarting IO on the failed adapter from scratch */ /* Restarting IO on the failed adapter from scratch */
debug_text_event(adapter->erp_dbf, 1, "qdio_err"); debug_text_event(adapter->erp_dbf, 1, "qdio_err");
zfcp_erp_adapter_reopen(adapter, 0); /*
* Since we have been using this adapter, it is save to assume
* that it is not failed but recoverable. The card seems to
* report link-up events by self-initiated queue shutdown.
* That is why we need to clear the the link-down flag
* which is set again in case we have missed by a mile.
*/
zfcp_erp_adapter_reopen(
adapter,
ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
ZFCP_STATUS_COMMON_ERP_FAILED);
} }
return retval; return retval;
} }
...@@ -293,8 +303,8 @@ zfcp_qdio_request_handler(struct ccw_device *ccw_device, ...@@ -293,8 +303,8 @@ zfcp_qdio_request_handler(struct ccw_device *ccw_device,
zfcp_get_busid_by_adapter(adapter), zfcp_get_busid_by_adapter(adapter),
first_element, elements_processed); first_element, elements_processed);
if (zfcp_qdio_handler_error_check(adapter, status, qdio_error, if (unlikely(zfcp_qdio_handler_error_check(adapter, status, qdio_error,
siga_error)) siga_error)))
goto out; goto out;
/* /*
* we stored address of struct zfcp_adapter data structure * we stored address of struct zfcp_adapter data structure
...@@ -345,8 +355,8 @@ zfcp_qdio_response_handler(struct ccw_device *ccw_device, ...@@ -345,8 +355,8 @@ zfcp_qdio_response_handler(struct ccw_device *ccw_device,
adapter = (struct zfcp_adapter *) int_parm; adapter = (struct zfcp_adapter *) int_parm;
queue = &adapter->response_queue; queue = &adapter->response_queue;
if (zfcp_qdio_handler_error_check(adapter, status, qdio_error, if (unlikely(zfcp_qdio_handler_error_check(adapter, status, qdio_error,
siga_error)) siga_error)))
goto out; goto out;
/* /*
...@@ -394,11 +404,17 @@ zfcp_qdio_response_handler(struct ccw_device *ccw_device, ...@@ -394,11 +404,17 @@ zfcp_qdio_response_handler(struct ccw_device *ccw_device,
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL, ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL,
(char *) buffer, SBAL_SIZE); (char *) buffer, SBAL_SIZE);
} }
if (buffere->flags & SBAL_FLAGS_LAST_ENTRY) /*
* A single used SBALE per inbound SBALE has been
* implemented by QDIO so far. Hope they will
* do some optimisation. Will need to change to
* unlikely() then.
*/
if (likely(buffere->flags & SBAL_FLAGS_LAST_ENTRY))
break; break;
}; };
if (!buffere->flags & SBAL_FLAGS_LAST_ENTRY) { if (unlikely(!(buffere->flags & SBAL_FLAGS_LAST_ENTRY))) {
ZFCP_LOG_NORMAL("bug: End of inbound data " ZFCP_LOG_NORMAL("bug: End of inbound data "
"not marked!\n"); "not marked!\n");
} }
...@@ -421,7 +437,7 @@ zfcp_qdio_response_handler(struct ccw_device *ccw_device, ...@@ -421,7 +437,7 @@ zfcp_qdio_response_handler(struct ccw_device *ccw_device,
QDIO_FLAG_SYNC_INPUT | QDIO_FLAG_UNDER_INTERRUPT, QDIO_FLAG_SYNC_INPUT | QDIO_FLAG_UNDER_INTERRUPT,
0, start, count, NULL); 0, start, count, NULL);
if (retval) { if (unlikely(retval)) {
atomic_set(&queue->free_count, count); atomic_set(&queue->free_count, count);
ZFCP_LOG_DEBUG("Inbound data regions could not be cleared " ZFCP_LOG_DEBUG("Inbound data regions could not be cleared "
"Transfer queues may be down. " "Transfer queues may be down. "
...@@ -458,7 +474,7 @@ zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, void *sbale_addr) ...@@ -458,7 +474,7 @@ zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, void *sbale_addr)
#endif /* ZFCP_DEBUG_REQUESTS */ #endif /* ZFCP_DEBUG_REQUESTS */
/* invalid (per convention used in this driver) */ /* invalid (per convention used in this driver) */
if (!sbale_addr) { if (unlikely(!sbale_addr)) {
ZFCP_LOG_NORMAL ZFCP_LOG_NORMAL
("bug: Inbound data faulty, contains null-pointer!\n"); ("bug: Inbound data faulty, contains null-pointer!\n");
retval = -EINVAL; retval = -EINVAL;
...@@ -468,8 +484,8 @@ zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, void *sbale_addr) ...@@ -468,8 +484,8 @@ zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, void *sbale_addr)
/* valid request id and thus (hopefully :) valid fsf_req address */ /* valid request id and thus (hopefully :) valid fsf_req address */
fsf_req = (struct zfcp_fsf_req *) sbale_addr; fsf_req = (struct zfcp_fsf_req *) sbale_addr;
if ((fsf_req->common_magic != ZFCP_MAGIC) || if (unlikely((fsf_req->common_magic != ZFCP_MAGIC) ||
(fsf_req->specific_magic != ZFCP_MAGIC_FSFREQ)) { (fsf_req->specific_magic != ZFCP_MAGIC_FSFREQ))) {
ZFCP_LOG_NORMAL("bug: An inbound FSF acknowledgement was " ZFCP_LOG_NORMAL("bug: An inbound FSF acknowledgement was "
"faulty (debug info 0x%x, 0x%x, 0x%lx)\n", "faulty (debug info 0x%x, 0x%x, 0x%lx)\n",
fsf_req->common_magic, fsf_req->common_magic,
...@@ -479,7 +495,7 @@ zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, void *sbale_addr) ...@@ -479,7 +495,7 @@ zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, void *sbale_addr)
goto out; goto out;
} }
if (adapter != fsf_req->adapter) { if (unlikely(adapter != fsf_req->adapter)) {
ZFCP_LOG_NORMAL("bug: An inbound FSF acknowledgement was not " ZFCP_LOG_NORMAL("bug: An inbound FSF acknowledgement was not "
"correct (debug info 0x%lx, 0x%lx, 0%lx) \n", "correct (debug info 0x%lx, 0x%lx, 0%lx) \n",
(unsigned long) fsf_req, (unsigned long) fsf_req,
...@@ -490,7 +506,7 @@ zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, void *sbale_addr) ...@@ -490,7 +506,7 @@ zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, void *sbale_addr)
} }
#ifdef ZFCP_DEBUG_REQUESTS #ifdef ZFCP_DEBUG_REQUESTS
/* debug feature stuff (test for QTCB: remember new unsol. status!) */ /* debug feature stuff (test for QTCB: remember new unsol. status!) */
if (fsf_req->qtcb) { if (likely(fsf_req->qtcb)) {
debug_event(adapter->req_dbf, 1, debug_event(adapter->req_dbf, 1,
&fsf_req->qtcb->prefix.req_seq_no, sizeof (u32)); &fsf_req->qtcb->prefix.req_seq_no, sizeof (u32));
} }
...@@ -498,7 +514,7 @@ zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, void *sbale_addr) ...@@ -498,7 +514,7 @@ zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, void *sbale_addr)
ZFCP_LOG_TRACE("fsf_req at 0x%lx, QTCB at 0x%lx\n", ZFCP_LOG_TRACE("fsf_req at 0x%lx, QTCB at 0x%lx\n",
(unsigned long) fsf_req, (unsigned long) fsf_req->qtcb); (unsigned long) fsf_req, (unsigned long) fsf_req->qtcb);
if (fsf_req->qtcb) { if (likely(fsf_req->qtcb)) {
ZFCP_LOG_TRACE("HEX DUMP OF 1ST BUFFERE PAYLOAD (QTCB):\n"); ZFCP_LOG_TRACE("HEX DUMP OF 1ST BUFFERE PAYLOAD (QTCB):\n");
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE,
(char *) fsf_req->qtcb, ZFCP_QTCB_SIZE); (char *) fsf_req->qtcb, ZFCP_QTCB_SIZE);
...@@ -518,8 +534,8 @@ zfcp_qdio_determine_pci(struct zfcp_qdio_queue *req_queue, ...@@ -518,8 +534,8 @@ zfcp_qdio_determine_pci(struct zfcp_qdio_queue *req_queue,
int pci_pos; int pci_pos;
new_distance_from_int = req_queue->distance_from_int + new_distance_from_int = req_queue->distance_from_int +
fsf_req->sbal_count; fsf_req->sbal_count;
if (new_distance_from_int >= ZFCP_QDIO_PCI_INTERVAL) { if (unlikely(new_distance_from_int >= ZFCP_QDIO_PCI_INTERVAL)) {
new_distance_from_int %= ZFCP_QDIO_PCI_INTERVAL; new_distance_from_int %= ZFCP_QDIO_PCI_INTERVAL;
pci_pos = fsf_req->sbal_index; pci_pos = fsf_req->sbal_index;
pci_pos += fsf_req->sbal_count; pci_pos += fsf_req->sbal_count;
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_SCSI #define ZFCP_LOG_AREA ZFCP_LOG_AREA_SCSI
#define ZFCP_LOG_AREA_PREFIX ZFCP_LOG_AREA_PREFIX_SCSI #define ZFCP_LOG_AREA_PREFIX ZFCP_LOG_AREA_PREFIX_SCSI
/* this drivers version (do not edit !!! generated and updated by cvs) */ /* this drivers version (do not edit !!! generated and updated by cvs) */
#define ZFCP_SCSI_REVISION "$Revision: 1.38 $" #define ZFCP_SCSI_REVISION "$Revision: 1.42 $"
#include <linux/blkdev.h> #include <linux/blkdev.h>
...@@ -225,99 +225,6 @@ zfcp_scsi_slave_destroy(struct scsi_device *sdpnt) ...@@ -225,99 +225,6 @@ zfcp_scsi_slave_destroy(struct scsi_device *sdpnt)
} }
} }
/*
* function: zfcp_scsi_insert_into_fake_queue
*
* purpose:
*
*
* returns:
*
* FIXME: Is the following scenario possible and - even more interesting -
* a problem? It reminds me of the famous 'no retry for tape' fix
* (no problem for disks, but what is about tapes...)
*
* device is unaccessable,
* command A is put into the fake queue,
* device becomes accessable again,
* command B is queued to the device,
* fake queue timer expires
* command A is returned to the mid-layer
* command A is queued to the device
*/
void
zfcp_scsi_insert_into_fake_queue(struct zfcp_adapter *adapter,
Scsi_Cmnd * new_cmnd)
{
unsigned long flags;
Scsi_Cmnd *current_cmnd;
ZFCP_LOG_DEBUG("Faking SCSI command:\n");
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
(char *) new_cmnd->cmnd, new_cmnd->cmd_len);
new_cmnd->host_scribble = NULL;
write_lock_irqsave(&adapter->fake_list_lock, flags);
if (adapter->first_fake_cmnd == NULL) {
adapter->first_fake_cmnd = new_cmnd;
adapter->fake_scsi_timer.function =
zfcp_scsi_process_and_clear_fake_queue;
adapter->fake_scsi_timer.data = (unsigned long) adapter;
adapter->fake_scsi_timer.expires =
jiffies + ZFCP_FAKE_SCSI_COMPLETION_TIME;
add_timer(&adapter->fake_scsi_timer);
} else {
for (current_cmnd = adapter->first_fake_cmnd;
current_cmnd->host_scribble != NULL;
current_cmnd =
(Scsi_Cmnd *) (current_cmnd->host_scribble)) ;
current_cmnd->host_scribble = (char *) new_cmnd;
}
write_unlock_irqrestore(&adapter->fake_list_lock, flags);
}
/*
* function: zfcp_scsi_process_and_clear_fake_queue
*
* purpose:
*
*
* returns:
*/
void
zfcp_scsi_process_and_clear_fake_queue(unsigned long data)
{
unsigned long flags;
struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
Scsi_Cmnd *cur = adapter->first_fake_cmnd;
Scsi_Cmnd *next;
/*
* We need a common lock for scsi_req on command completion
* as well as on command abort to avoid race conditions
* during completions and aborts taking place at the same time.
* It needs to be the outer lock as in the eh_abort_handler.
*/
read_lock_irqsave(&adapter->abort_lock, flags);
write_lock(&adapter->fake_list_lock);
while (cur) {
next = (Scsi_Cmnd *) cur->host_scribble;
cur->host_scribble = NULL;
zfcp_cmd_dbf_event_scsi("clrfake", cur);
cur->scsi_done(cur);
cur = next;
#ifdef ZFCP_DEBUG_REQUESTS
debug_text_event(adapter->req_dbf, 2, "fk_done:");
debug_event(adapter->req_dbf, 2, &cur, sizeof (unsigned long));
#endif
}
adapter->first_fake_cmnd = NULL;
write_unlock(&adapter->fake_list_lock);
read_unlock_irqrestore(&adapter->abort_lock, flags);
return;
}
void void
zfcp_scsi_block_requests(struct Scsi_Host *shpnt) zfcp_scsi_block_requests(struct Scsi_Host *shpnt)
{ {
...@@ -383,25 +290,6 @@ zfcp_scsi_slave_configure(struct scsi_device *sdp) ...@@ -383,25 +290,6 @@ zfcp_scsi_slave_configure(struct scsi_device *sdp)
return 0; return 0;
} }
/* Sends command on a round-trip using SCSI stack */
static void
zfcp_scsi_queuecommand_fake(Scsi_Cmnd * scpnt, struct zfcp_adapter *adapter)
{
ZFCP_LOG_DEBUG("Looping SCSI IO on the adapter %s.\n",
zfcp_get_busid_by_adapter(adapter));
/*
* Reset everything for devices with retries, allow at least one retry
* for others, e.g. tape.
*/
scpnt->retries = 0;
if (scpnt->allowed == 1) {
scpnt->allowed = 2;
}
set_host_byte(&scpnt->result, DID_SOFT_ERROR);
set_driver_byte(&scpnt->result, SUGGEST_RETRY);
zfcp_scsi_insert_into_fake_queue(adapter, scpnt);
}
/* Complete a command immediately handing back DID_ERROR */ /* Complete a command immediately handing back DID_ERROR */
static void static void
zfcp_scsi_queuecommand_stop(Scsi_Cmnd * scpnt, zfcp_scsi_queuecommand_stop(Scsi_Cmnd * scpnt,
...@@ -460,10 +348,12 @@ zfcp_scsi_queuecommand_stop(Scsi_Cmnd * scpnt, ...@@ -460,10 +348,12 @@ zfcp_scsi_queuecommand_stop(Scsi_Cmnd * scpnt,
int int
zfcp_scsi_queuecommand(Scsi_Cmnd * scpnt, void (*done) (Scsi_Cmnd *)) zfcp_scsi_queuecommand(Scsi_Cmnd * scpnt, void (*done) (Scsi_Cmnd *))
{ {
int retval;
int temp_ret; int temp_ret;
struct zfcp_unit *unit; struct zfcp_unit *unit;
struct zfcp_adapter *adapter; struct zfcp_adapter *adapter;
retval = 0;
/* reset the status for this request */ /* reset the status for this request */
scpnt->result = 0; scpnt->result = 0;
/* save address of mid layer call back function */ /* save address of mid layer call back function */
...@@ -475,47 +365,38 @@ zfcp_scsi_queuecommand(Scsi_Cmnd * scpnt, void (*done) (Scsi_Cmnd *)) ...@@ -475,47 +365,38 @@ zfcp_scsi_queuecommand(Scsi_Cmnd * scpnt, void (*done) (Scsi_Cmnd *))
*/ */
adapter = (struct zfcp_adapter *) scpnt->device->host->hostdata[0]; adapter = (struct zfcp_adapter *) scpnt->device->host->hostdata[0];
/* NULL when the adapter was removed from the zfcp list */ /* NULL when the adapter was removed from the zfcp list */
if (adapter == NULL) { if (unlikely(adapter == NULL)) {
zfcp_scsi_queuecommand_stop(scpnt, NULL, NULL); zfcp_scsi_queuecommand_stop(scpnt, NULL, NULL);
goto out; goto out;
} }
/* set when we have a unit/port list modification */
if (atomic_test_mask(ZFCP_STATUS_ADAPTER_QUEUECOMMAND_BLOCK,
&adapter->status)) {
zfcp_scsi_queuecommand_fake(scpnt, adapter);
goto out;
}
unit = zfcp_scsi_determine_unit(adapter, scpnt); unit = zfcp_scsi_determine_unit(adapter, scpnt);
if (unit == NULL) if (unlikely(unit == NULL))
goto out; goto out;
if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &unit->status) if (unlikely(
|| !atomic_test_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status)) { atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &unit->status) ||
!atomic_test_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status))) {
zfcp_scsi_queuecommand_stop(scpnt, adapter, unit); zfcp_scsi_queuecommand_stop(scpnt, adapter, unit);
goto out; goto out;
} }
if (!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status)) { if (unlikely(
!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status))) {
ZFCP_LOG_DEBUG("adapter %s not ready or unit with LUN 0x%Lx " ZFCP_LOG_DEBUG("adapter %s not ready or unit with LUN 0x%Lx "
"on the port with WWPN 0x%Lx in recovery.\n", "on the port with WWPN 0x%Lx in recovery.\n",
zfcp_get_busid_by_adapter(adapter), zfcp_get_busid_by_adapter(adapter),
unit->fcp_lun, unit->port->wwpn); unit->fcp_lun, unit->port->wwpn);
zfcp_scsi_queuecommand_fake(scpnt, adapter); retval = SCSI_MLQUEUE_DEVICE_BUSY;
goto out; goto out;
} }
atomic_inc(&adapter->scsi_reqs_active);
temp_ret = zfcp_fsf_send_fcp_command_task(adapter, temp_ret = zfcp_fsf_send_fcp_command_task(adapter,
unit, unit,
scpnt, ZFCP_REQ_AUTO_CLEANUP); scpnt, ZFCP_REQ_AUTO_CLEANUP);
if (temp_ret < 0) { if (unlikely(temp_ret < 0)) {
ZFCP_LOG_DEBUG("error: Could not send a Send FCP Command\n"); ZFCP_LOG_DEBUG("error: Could not send a Send FCP Command\n");
atomic_dec(&adapter->scsi_reqs_active); retval = SCSI_MLQUEUE_HOST_BUSY;
wake_up(&adapter->scsi_reqs_active_wq);
zfcp_scsi_queuecommand_fake(scpnt, adapter);
} else { } else {
#ifdef ZFCP_DEBUG_REQUESTS #ifdef ZFCP_DEBUG_REQUESTS
debug_text_event(adapter->req_dbf, 3, "q_scpnt"); debug_text_event(adapter->req_dbf, 3, "q_scpnt");
...@@ -524,7 +405,7 @@ zfcp_scsi_queuecommand(Scsi_Cmnd * scpnt, void (*done) (Scsi_Cmnd *)) ...@@ -524,7 +405,7 @@ zfcp_scsi_queuecommand(Scsi_Cmnd * scpnt, void (*done) (Scsi_Cmnd *))
#endif /* ZFCP_DEBUG_REQUESTS */ #endif /* ZFCP_DEBUG_REQUESTS */
} }
out: out:
return 0; return retval;
} }
/* /*
...@@ -556,45 +437,6 @@ zfcp_unit_lookup(struct zfcp_adapter *adapter, int channel, int id, int lun) ...@@ -556,45 +437,6 @@ zfcp_unit_lookup(struct zfcp_adapter *adapter, int channel, int id, int lun)
return retval; return retval;
} }
/*
* function: zfcp_scsi_potential_abort_on_fake
*
* purpose:
*
* returns: 0 - no fake request aborted
* 1 - fake request was aborted
*
* context: both the adapter->abort_lock and the
* adapter->fake_list_lock are assumed to be held write lock
* irqsave
*/
int
zfcp_scsi_potential_abort_on_fake(struct zfcp_adapter *adapter,
Scsi_Cmnd * cmnd)
{
Scsi_Cmnd *cur = adapter->first_fake_cmnd;
Scsi_Cmnd *pre = NULL;
int retval = 0;
while (cur) {
if (cur == cmnd) {
if (pre)
pre->host_scribble = cur->host_scribble;
else
adapter->first_fake_cmnd =
(Scsi_Cmnd *) cur->host_scribble;
cur->host_scribble = NULL;
if (!adapter->first_fake_cmnd)
del_timer(&adapter->fake_scsi_timer);
retval = 1;
break;
}
pre = cur;
cur = (Scsi_Cmnd *) cur->host_scribble;
}
return retval;
}
/* /*
* function: zfcp_scsi_eh_abort_handler * function: zfcp_scsi_eh_abort_handler
* *
...@@ -663,33 +505,11 @@ zfcp_scsi_eh_abort_handler(Scsi_Cmnd * scpnt) ...@@ -663,33 +505,11 @@ zfcp_scsi_eh_abort_handler(Scsi_Cmnd * scpnt)
* Race condition between normal (late) completion and abort has * Race condition between normal (late) completion and abort has
* to be avoided. * to be avoided.
* The entirity of all accesses to scsi_req have to be atomic. * The entirity of all accesses to scsi_req have to be atomic.
* scsi_req is usually part of the fsf_req (for requests which * scsi_req is usually part of the fsf_req and thus we block the
* are not faked) and thus we block the release of fsf_req * release of fsf_req as long as we need to access scsi_req.
* as long as we need to access scsi_req.
* For faked commands we use the same lock even if they are not
* put into the fsf_req queue. This makes implementation
* easier.
*/ */
write_lock_irqsave(&adapter->abort_lock, flags); write_lock_irqsave(&adapter->abort_lock, flags);
/*
* Check if we deal with a faked command, which we may just forget
* about from now on
*/
write_lock(&adapter->fake_list_lock);
/* only need to go through list if there are faked requests */
if (adapter->first_fake_cmnd != NULL) {
if (zfcp_scsi_potential_abort_on_fake(adapter, scpnt)) {
write_unlock(&adapter->fake_list_lock);
write_unlock_irqrestore(&adapter->abort_lock, flags);
ZFCP_LOG_INFO("A faked command was aborted\n");
retval = SUCCESS;
strncpy(dbf_result, "##faked", ZFCP_ABORT_DBF_LENGTH);
goto out;
}
}
write_unlock(&adapter->fake_list_lock);
/* /*
* Check whether command has just completed and can not be aborted. * Check whether command has just completed and can not be aborted.
* Even if the command has just been completed late, we can access * Even if the command has just been completed late, we can access
...@@ -845,11 +665,6 @@ zfcp_scsi_eh_device_reset_handler(Scsi_Cmnd * scpnt) ...@@ -845,11 +665,6 @@ zfcp_scsi_eh_device_reset_handler(Scsi_Cmnd * scpnt)
spin_unlock_irq(scsi_host->host_lock); spin_unlock_irq(scsi_host->host_lock);
/*
* We should not be called to reset a target which we 'sent' faked SCSI
* commands since the abort of faked SCSI commands should always
* succeed (simply delete timer).
*/
if (!unit) { if (!unit) {
ZFCP_LOG_NORMAL("bug: Tried to reset a non existant unit.\n"); ZFCP_LOG_NORMAL("bug: Tried to reset a non existant unit.\n");
retval = SUCCESS; retval = SUCCESS;
...@@ -1023,7 +838,6 @@ zfcp_adapter_scsi_register(struct zfcp_adapter *adapter) ...@@ -1023,7 +838,6 @@ zfcp_adapter_scsi_register(struct zfcp_adapter *adapter)
retval = -EIO; retval = -EIO;
goto out; goto out;
} }
atomic_set_mask(ZFCP_STATUS_ADAPTER_REGISTERED, &adapter->status);
ZFCP_LOG_DEBUG("host registered, scsi_host at 0x%lx\n", ZFCP_LOG_DEBUG("host registered, scsi_host at 0x%lx\n",
(unsigned long) adapter->scsi_host); (unsigned long) adapter->scsi_host);
...@@ -1039,7 +853,12 @@ zfcp_adapter_scsi_register(struct zfcp_adapter *adapter) ...@@ -1039,7 +853,12 @@ zfcp_adapter_scsi_register(struct zfcp_adapter *adapter)
*/ */
adapter->scsi_host->hostdata[0] = (unsigned long) adapter; adapter->scsi_host->hostdata[0] = (unsigned long) adapter;
scsi_add_host(adapter->scsi_host, &adapter->ccw_device->dev); if (scsi_add_host(adapter->scsi_host, &adapter->ccw_device->dev)) {
scsi_host_put(adapter->scsi_host);
retval = -EIO;
goto out;
}
atomic_set_mask(ZFCP_STATUS_ADAPTER_REGISTERED, &adapter->status);
out: out:
return retval; return retval;
} }
...@@ -1061,8 +880,9 @@ zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter) ...@@ -1061,8 +880,9 @@ zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter)
return; return;
scsi_remove_host(shost); scsi_remove_host(shost);
scsi_host_put(shost); scsi_host_put(shost);
adapter->scsi_host = NULL; adapter->scsi_host = NULL;
atomic_clear_mask(ZFCP_STATUS_ADAPTER_REGISTERED, &adapter->status);
return; return;
} }
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#define ZFCP_SYSFS_ADAPTER_C_REVISION "$Revision: 1.21 $" #define ZFCP_SYSFS_ADAPTER_C_REVISION "$Revision: 1.26 $"
#include <asm/ccwdev.h> #include <asm/ccwdev.h>
#include "zfcp_ext.h" #include "zfcp_ext.h"
...@@ -155,11 +155,8 @@ zfcp_sysfs_port_add_store(struct device *dev, const char *buf, size_t count) ...@@ -155,11 +155,8 @@ zfcp_sysfs_port_add_store(struct device *dev, const char *buf, size_t count)
retval = 0; retval = 0;
zfcp_adapter_get(adapter); zfcp_erp_port_reopen(port, 0);
zfcp_erp_wait(port->adapter);
/* try to open port only if adapter is online */
if (adapter->ccw_device->online == 1)
zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED);
zfcp_port_put(port); zfcp_port_put(port);
out: out:
up(&zfcp_data.config_sema); up(&zfcp_data.config_sema);
...@@ -219,6 +216,8 @@ zfcp_sysfs_port_remove_store(struct device *dev, const char *buf, size_t count) ...@@ -219,6 +216,8 @@ zfcp_sysfs_port_remove_store(struct device *dev, const char *buf, size_t count)
zfcp_erp_port_shutdown(port, 0); zfcp_erp_port_shutdown(port, 0);
zfcp_erp_wait(adapter); zfcp_erp_wait(adapter);
zfcp_port_put(port); zfcp_port_put(port);
zfcp_sysfs_port_remove_files(&port->sysfs_device,
atomic_read(&port->status));
device_unregister(&port->sysfs_device); device_unregister(&port->sysfs_device);
out: out:
up(&zfcp_data.config_sema); up(&zfcp_data.config_sema);
...@@ -268,6 +267,7 @@ zfcp_sysfs_adapter_failed_store(struct device *dev, ...@@ -268,6 +267,7 @@ zfcp_sysfs_adapter_failed_store(struct device *dev,
zfcp_erp_modify_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING, zfcp_erp_modify_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING,
ZFCP_SET); ZFCP_SET);
zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED); zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED);
zfcp_erp_wait(adapter);
out: out:
up(&zfcp_data.config_sema); up(&zfcp_data.config_sema);
return retval ? retval : count; return retval ? retval : count;
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#define ZFCP_SYSFS_PORT_C_REVISION "$Revision: 1.26 $" #define ZFCP_SYSFS_PORT_C_REVISION "$Revision: 1.32 $"
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -110,11 +110,9 @@ zfcp_sysfs_unit_add_store(struct device *dev, const char *buf, size_t count) ...@@ -110,11 +110,9 @@ zfcp_sysfs_unit_add_store(struct device *dev, const char *buf, size_t count)
retval = 0; retval = 0;
zfcp_port_get(port); zfcp_erp_unit_reopen(unit, 0);
zfcp_erp_wait(unit->port->adapter);
/* try to open unit only if adapter is online */ wait_event(unit->scsi_add_wq, atomic_read(&unit->scsi_add_work) == 0);
if (port->adapter->ccw_device->online == 1)
zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED);
zfcp_unit_put(unit); zfcp_unit_put(unit);
out: out:
up(&zfcp_data.config_sema); up(&zfcp_data.config_sema);
...@@ -170,6 +168,7 @@ zfcp_sysfs_unit_remove_store(struct device *dev, const char *buf, size_t count) ...@@ -170,6 +168,7 @@ zfcp_sysfs_unit_remove_store(struct device *dev, const char *buf, size_t count)
zfcp_erp_unit_shutdown(unit, 0); zfcp_erp_unit_shutdown(unit, 0);
zfcp_erp_wait(unit->port->adapter); zfcp_erp_wait(unit->port->adapter);
zfcp_unit_put(unit); zfcp_unit_put(unit);
zfcp_sysfs_unit_remove_files(&unit->sysfs_device);
device_unregister(&unit->sysfs_device); device_unregister(&unit->sysfs_device);
out: out:
up(&zfcp_data.config_sema); up(&zfcp_data.config_sema);
...@@ -217,6 +216,7 @@ zfcp_sysfs_port_failed_store(struct device *dev, const char *buf, size_t count) ...@@ -217,6 +216,7 @@ zfcp_sysfs_port_failed_store(struct device *dev, const char *buf, size_t count)
} }
zfcp_erp_modify_port_status(port, ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET); zfcp_erp_modify_port_status(port, ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET);
zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED); zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED);
zfcp_erp_wait(port->adapter);
out: out:
up(&zfcp_data.config_sema); up(&zfcp_data.config_sema);
return retval ? retval : count; return retval ? retval : count;
...@@ -293,7 +293,7 @@ static struct attribute_group zfcp_port_no_ns_attr_group = { ...@@ -293,7 +293,7 @@ static struct attribute_group zfcp_port_no_ns_attr_group = {
}; };
/** /**
* zfcp_sysfs_create_port_files - create sysfs port files * zfcp_sysfs_port_create_files - create sysfs port files
* @dev: pointer to belonging device * @dev: pointer to belonging device
* *
* Create all attributes of the sysfs representation of a port. * Create all attributes of the sysfs representation of a port.
...@@ -315,5 +315,19 @@ zfcp_sysfs_port_create_files(struct device *dev, u32 flags) ...@@ -315,5 +315,19 @@ zfcp_sysfs_port_create_files(struct device *dev, u32 flags)
return retval; return retval;
} }
/**
* zfcp_sysfs_port_remove_files - remove sysfs port files
* @dev: pointer to belonging device
*
* Remove all attributes of the sysfs representation of a port.
*/
void
zfcp_sysfs_port_remove_files(struct device *dev, u32 flags)
{
sysfs_remove_group(&dev->kobj, &zfcp_port_common_attr_group);
if (!(flags & ZFCP_STATUS_PORT_NAMESERVER))
sysfs_remove_group(&dev->kobj, &zfcp_port_no_ns_attr_group);
}
#undef ZFCP_LOG_AREA #undef ZFCP_LOG_AREA
#undef ZFCP_LOG_AREA_PREFIX #undef ZFCP_LOG_AREA_PREFIX
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#define ZFCP_SYSFS_UNIT_C_REVISION "$Revision: 1.17 $" #define ZFCP_SYSFS_UNIT_C_REVISION "$Revision: 1.19 $"
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -186,5 +186,17 @@ zfcp_sysfs_unit_create_files(struct device *dev) ...@@ -186,5 +186,17 @@ zfcp_sysfs_unit_create_files(struct device *dev)
return sysfs_create_group(&dev->kobj, &zfcp_unit_attr_group); return sysfs_create_group(&dev->kobj, &zfcp_unit_attr_group);
} }
/**
* zfcp_sysfs_remove_unit_files - remove sysfs unit files
* @dev: pointer to belonging device
*
* Remove all attributes of the sysfs representation of a unit.
*/
void
zfcp_sysfs_unit_remove_files(struct device *dev)
{
sysfs_remove_group(&dev->kobj, &zfcp_unit_attr_group);
}
#undef ZFCP_LOG_AREA #undef ZFCP_LOG_AREA
#undef ZFCP_LOG_AREA_PREFIX #undef ZFCP_LOG_AREA_PREFIX
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment