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 @@
*/
/* 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 *********************************************/
......@@ -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,
sizeof (unsigned long));
if (fsf_req) {
if (likely(fsf_req)) {
debug_event(adapter->cmd_dbf, level, &fsf_req,
sizeof (unsigned long));
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,
#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
zfcp_module_init(void)
{
......@@ -357,9 +440,15 @@ zfcp_module_init(void)
ZFCP_LOG_NORMAL("Registering with common I/O layer failed.\n");
goto out_ccw_register;
}
#ifndef MODULE
if (zfcp_data.init_is_valid)
zfcp_init_device_configure();
#endif
goto out;
out_ccw_register:
unregister_reboot_notifier(&zfcp_data.reboot_notifier);
#ifdef ZFCP_STAT_REQSIZES
zfcp_statistics_clear_all();
#endif
......@@ -391,13 +480,8 @@ int
zfcp_reboot_handler(struct notifier_block *notifier, unsigned long code,
void *ptr)
{
int retval = 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;
zfcp_ccw_unregister();
return NOTIFY_DONE;
}
#undef ZFCP_LOG_AREA
......@@ -503,6 +587,7 @@ zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun)
return NULL;
memset(unit, 0, sizeof (struct zfcp_unit));
init_waitqueue_head(&unit->scsi_add_wq);
/* initialise reference count stuff */
atomic_set(&unit->refcount, 0);
init_waitqueue_head(&unit->remove_wq);
......@@ -571,6 +656,7 @@ zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun)
write_unlock_irq(&zfcp_data.config_lock);
port->units++;
zfcp_port_get(port);
return unit;
}
......@@ -763,17 +849,10 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
/* initialize 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 */
init_waitqueue_head(&adapter->erp_thread_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 */
rwlock_init(&adapter->request_queue.queue_lock);
......@@ -904,7 +983,6 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
/* put allocated adapter at list tail */
write_lock_irq(&zfcp_data.config_lock);
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);
write_unlock_irq(&zfcp_data.config_lock);
......@@ -1149,6 +1227,7 @@ zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn, u32 status)
write_unlock_irq(&zfcp_data.config_lock);
adapter->ports++;
zfcp_adapter_get(adapter);
return port;
}
......@@ -1193,7 +1272,6 @@ zfcp_nameserver_enqueue(struct zfcp_adapter *adapter)
/* set special D_ID */
port->d_id = ZFCP_DID_NAMESERVER;
adapter->nameserver_port = port;
zfcp_adapter_get(adapter);
zfcp_port_put(port);
return 0;
......@@ -1216,9 +1294,9 @@ zfcp_fsf_incoming_els_rscn(struct zfcp_adapter *adapter,
struct fcp_rscn_head *fcp_rscn_head;
struct fcp_rscn_element *fcp_rscn_element;
struct zfcp_port *port;
int i;
int reopen_unknown = 0;
int no_entries;
u16 i;
u16 no_entries;
u32 range_mask;
unsigned long flags;
fcp_rscn_head = (struct fcp_rscn_head *) status_buffer->payload;
......@@ -1232,56 +1310,57 @@ zfcp_fsf_incoming_els_rscn(struct zfcp_adapter *adapter,
debug_text_event(adapter->erp_dbf, 1, "unsol_els_rscn:");
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 */
fcp_rscn_element++;
switch (fcp_rscn_element->addr_format) {
case ZFCP_PORT_ADDRESS:
ZFCP_LOG_FLAGS(1, "ZFCP_PORT_ADDRESS\n");
range_mask = ZFCP_PORTS_RANGE_PORT;
no_notifications = 1;
break;
case ZFCP_AREA_ADDRESS:
ZFCP_LOG_FLAGS(1, "ZFCP_AREA_ADDRESS\n");
/* skip head and start with 1st element */
range_mask = ZFCP_PORTS_RANGE_AREA;
no_notifications = ZFCP_NO_PORTS_PER_AREA;
break;
case ZFCP_DOMAIN_ADDRESS:
ZFCP_LOG_FLAGS(1, "ZFCP_DOMAIN_ADDRESS\n");
range_mask = ZFCP_PORTS_RANGE_DOMAIN;
no_notifications = ZFCP_NO_PORTS_PER_DOMAIN;
break;
case ZFCP_FABRIC_ADDRESS:
ZFCP_LOG_FLAGS(1, "ZFCP_FABRIC_ADDRESS\n");
range_mask = ZFCP_PORTS_RANGE_FABRIC;
no_notifications = ZFCP_NO_PORTS_PER_FABRIC;
break;
default:
/* cannot happen */
break;
ZFCP_LOG_INFO("Received RSCN with unknown "
"address format.\n");
continue;
}
read_lock_irqsave(&zfcp_data.config_lock, flags);
list_for_each_entry(port, &adapter->port_list_head, list) {
if (atomic_test_mask
(ZFCP_STATUS_PORT_NAMESERVER, &port->status))
continue;
/* Do we know this port? If not skip it. */
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;
}
/*
* FIXME: race: d_id might being invalidated
* (...DID_DID reset)
*/
if ((port->d_id & range_mask)
== (fcp_rscn_element->nport_did & range_mask)) {
known++;
ZFCP_LOG_TRACE("known=%d, reopen did 0x%x\n",
known,
ZFCP_LOG_TRACE("reopen did 0x%x\n",
fcp_rscn_element->nport_did);
/*
* Unfortunately, an RSCN does not specify the
......@@ -1303,36 +1382,6 @@ zfcp_fsf_incoming_els_rscn(struct zfcp_adapter *adapter,
}
}
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)
struct zfcp_adapter *adapter = fsf_req->adapter;
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) {
memset(data->outbuf, 0, 2 * sizeof (struct fc_ct_iu));
} else {
......@@ -1479,7 +1528,7 @@ zfcp_get_nameserver_buffers(struct zfcp_fsf_req *fsf_req)
"adapter %s directly.. trying emergency pool\n",
zfcp_get_busid_by_adapter(adapter));
data->outbuf =
mempool_alloc(adapter->pool.nameserver, GFP_KERNEL);
mempool_alloc(adapter->pool.nameserver, GFP_ATOMIC);
if (!data->outbuf) {
ZFCP_LOG_DEBUG
("Out of memory. Could not get emergency "
......
......@@ -25,7 +25,7 @@
* 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/module.h>
......@@ -37,7 +37,7 @@
#define ZFCP_LOG_AREA_PREFIX ZFCP_LOG_AREA_PREFIX_CONFIG
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_offline(struct 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
* 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.
*/
static int
static void
zfcp_ccw_remove(struct ccw_device *ccw_device)
{
struct zfcp_adapter *adapter;
struct zfcp_port *port, *p;
struct zfcp_unit *unit, *u;
ccw_device_set_offline(ccw_device);
down(&zfcp_data.config_sema);
adapter = dev_get_drvdata(&ccw_device->dev);
......@@ -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(unit, u, &port->unit_remove_lh, list) {
zfcp_unit_wait(unit);
zfcp_sysfs_unit_remove_files(&unit->sysfs_device);
device_unregister(&unit->sysfs_device);
}
zfcp_port_wait(port);
zfcp_sysfs_port_remove_files(&port->sysfs_device,
atomic_read(&port->status));
device_unregister(&port->sysfs_device);
}
zfcp_adapter_wait(adapter);
zfcp_adapter_dequeue(adapter);
up(&zfcp_data.config_sema);
return 0;
}
/**
......@@ -155,6 +158,7 @@ zfcp_ccw_set_online(struct ccw_device *ccw_device)
zfcp_erp_modify_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING,
ZFCP_SET);
zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED);
zfcp_erp_wait(adapter);
out:
up(&zfcp_data.config_sema);
return retval;
......
......@@ -31,10 +31,8 @@
#ifndef ZFCP_DEF_H
#define ZFCP_DEF_H
#ifdef __KERNEL__
/* 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 *****************************************/
......@@ -64,7 +62,6 @@
typedef u32 scsi_id_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_SCSI_ER_TIMEOUT (100*HZ)
#define ZFCP_SCSI_HOST_FLUSH_TIMEOUT (1*HZ)
......@@ -470,7 +467,6 @@ extern u32 flags_dump;
#define ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL 0x00000080
#define ZFCP_STATUS_ADAPTER_ERP_PENDING 0x00000100
#define ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED 0x00000200
#define ZFCP_STATUS_ADAPTER_QUEUECOMMAND_BLOCK 0x00000400
#define ZFCP_STATUS_ADAPTER_SCSI_UP \
(ZFCP_STATUS_COMMON_UNBLOCKED | \
......@@ -676,10 +672,7 @@ struct zfcp_adapter {
u32 hydra_version; /* Hydra version */
u32 fsf_lic_version;
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];
struct list_head port_list_head; /* remote port list */
struct list_head port_remove_lh; /* head of ports to be
......@@ -692,9 +685,6 @@ struct zfcp_adapter {
rwlock_t fsf_req_list_lock; /* lock for ops on list of
FSF requests */
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 */
u32 fsf_req_seq_no; /* FSF cmnd seq number */
wait_queue_head_t request_wq; /* can be used to wait for
......@@ -765,6 +755,8 @@ struct zfcp_unit {
struct zfcp_erp_action erp_action; /* pending error recovery */
atomic_t erp_counter;
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 */
......@@ -809,6 +801,14 @@ struct zfcp_data {
struct notifier_block reboot_notifier; /* used to register cleanup
functions */
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
of processed data */
struct list_head read_req_head;
......@@ -857,7 +857,7 @@ struct zfcp_statistics {
#ifndef atomic_test_mask
#define atomic_test_mask(mask, target) \
(atomic_read(target) & mask)
((atomic_read(target) & mask) == mask)
#endif
extern void _zfcp_hex_dump(char *, int);
......@@ -957,5 +957,4 @@ zfcp_adapter_wait(struct zfcp_adapter *adapter)
wait_event(adapter->remove_wq, atomic_read(&adapter->refcount) == 0);
}
#endif /* __KERNEL_- */
#endif /* ZFCP_DEF_H */
......@@ -30,7 +30,7 @@
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_ERP
#define ZFCP_LOG_AREA_PREFIX ZFCP_LOG_AREA_PREFIX_ERP
/* 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"
......@@ -108,6 +108,9 @@ static int zfcp_erp_action_dismiss(struct zfcp_erp_action *);
static int zfcp_erp_action_enqueue(int, struct zfcp_adapter *,
struct zfcp_port *, struct zfcp_unit *);
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 int zfcp_erp_action_exists(struct zfcp_erp_action *);
......@@ -1160,6 +1163,9 @@ zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
write_unlock(&adapter->erp_lock);
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
* (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)
!(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:
*
......@@ -1468,10 +1534,6 @@ zfcp_erp_strategy_check_unit(struct zfcp_unit *unit, int result)
if (result == ZFCP_ERP_SUCCEEDED) {
atomic_set(&unit->erp_counter, 0);
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 {
/* ZFCP_ERP_FAILED or ZFCP_ERP_EXIT */
atomic_inc(&unit->erp_counter);
......@@ -1773,9 +1835,8 @@ zfcp_erp_port_reopen_all_internal(struct zfcp_adapter *adapter, int clear_mask)
struct zfcp_port *port;
list_for_each_entry(port, &adapter->port_list_head, list)
if (atomic_test_mask(ZFCP_STATUS_PORT_NAMESERVER, &port->status)
!= ZFCP_STATUS_PORT_NAMESERVER)
zfcp_erp_port_reopen_internal(port, clear_mask);
if (!atomic_test_mask(ZFCP_STATUS_PORT_NAMESERVER, &port->status))
zfcp_erp_port_reopen_internal(port, clear_mask);
return retval;
}
......@@ -2333,8 +2394,8 @@ zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action)
* open flag is unset - however, this is for readabilty ...
*/
if (atomic_test_mask((ZFCP_STATUS_PORT_PHYS_OPEN |
ZFCP_STATUS_COMMON_OPEN), &port->status)
== (ZFCP_STATUS_PORT_PHYS_OPEN | ZFCP_STATUS_COMMON_OPEN)) {
ZFCP_STATUS_COMMON_OPEN),
&port->status)) {
ZFCP_LOG_DEBUG("Port wwpn=0x%Lx is open -> trying "
" close physical\n",
port->wwpn);
......@@ -2433,8 +2494,7 @@ zfcp_erp_port_strategy_open(struct zfcp_erp_action *erp_action)
int retval;
if (atomic_test_mask(ZFCP_STATUS_PORT_NAMESERVER,
&erp_action->port->status)
== ZFCP_STATUS_PORT_NAMESERVER)
&erp_action->port->status))
retval = zfcp_erp_port_strategy_open_nameserver(erp_action);
else
retval = zfcp_erp_port_strategy_open_common(erp_action);
......@@ -3040,6 +3100,12 @@ zfcp_erp_action_enqueue(int action,
sizeof (fcp_lun_t));
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
(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status)) {
stronger_action = ZFCP_ERP_ACTION_REOPEN_PORT;
......@@ -3067,6 +3133,12 @@ zfcp_erp_action_enqueue(int action,
sizeof (wwn_t));
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
(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status)) {
stronger_action = ZFCP_ERP_ACTION_REOPEN_ADAPTER;
......@@ -3178,18 +3250,15 @@ zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action)
case ZFCP_ERP_ACTION_REOPEN_UNIT:
atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
&erp_action->unit->status);
zfcp_unit_put(erp_action->unit);
break;
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
case ZFCP_ERP_ACTION_REOPEN_PORT:
atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
&erp_action->port->status);
zfcp_port_put(erp_action->port);
break;
case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
&erp_action->adapter->status);
zfcp_adapter_put(adapter);
break;
default:
/* bug */
......@@ -3198,6 +3267,39 @@ zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action)
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:
*
......
......@@ -30,9 +30,7 @@
#ifndef ZFCP_EXT_H
#define ZFCP_EXT_H
/* this drivers version (do not edit !!! generated and updated by cvs) */
#define ZFCP_EXT_REVISION "$Revision: 1.33 $"
#ifdef __KERNEL__
#define ZFCP_EXT_REVISION "$Revision: 1.38 $"
#include "zfcp_def.h"
......@@ -44,7 +42,9 @@ extern void zfcp_sysfs_driver_remove_files(struct device_driver *);
extern int zfcp_sysfs_adapter_create_files(struct device *);
extern void zfcp_sysfs_adapter_remove_files(struct device *);
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 void zfcp_sysfs_unit_remove_files(struct device *);
extern void zfcp_sysfs_port_release(struct device *);
extern int zfcp_sysfs_port_shutdown(struct zfcp_port *);
extern void zfcp_sysfs_unit_release(struct device *);
......@@ -112,9 +112,6 @@ extern void zfcp_fsf_els_processing(struct zfcp_fsf_req *);
extern int zfcp_adapter_scsi_register(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_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 *,
Scsi_Cmnd *, char, int, int);
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 *,
#ifdef ZFCP_STAT_REQSIZES
extern int zfcp_statistics_inc(struct list_head *, u32);
#endif
#endif /* __KERNEL__ */
#endif /* ZFCP_EXT_H */
......@@ -28,7 +28,7 @@
*/
/* 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"
......@@ -101,7 +101,8 @@ zfcp_fsf_req_alloc(struct zfcp_adapter *adapter, u32 fsf_cmd, int kmalloc_flags)
case FSF_QTCB_ABORT_FCP_CMND:
fsf_req = zfcp_fsf_req_get(kmalloc_flags,
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
* 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)
}
#ifdef ZFCP_DEBUG_REQUESTS
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");
#endif /* ZFCP_DEBUG_REQUESTS */
break;
......@@ -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);
} //switch(fsf_cmd)
if (!fsf_req) {
if (unlikely(!fsf_req)) {
ZFCP_LOG_DEBUG("error: Out of memory. Allocation of FSF "
"request structure failed\n");
} else {
......@@ -171,7 +173,7 @@ zfcp_fsf_req_alloc(struct zfcp_adapter *adapter, u32 fsf_cmd, int kmalloc_flags)
#ifdef ZFCP_DEBUG_REQUESTS
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,
sizeof (unsigned long));
#endif /* ZFCP_DEBUG_REQUESTS */
......@@ -198,7 +200,7 @@ zfcp_fsf_req_free(struct zfcp_fsf_req *fsf_req)
case FSF_QTCB_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);
mempool_free(fsf_req, adapter->pool.fcp_command_fsf);
} else
......@@ -299,7 +301,7 @@ zfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req)
/* do some statistics */
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");
/*
* Note: all cleanup handling is done in the callchain of
......@@ -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
* 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;
else
cleanup = 0;
......@@ -322,7 +324,7 @@ zfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req)
fsf_req->status |= ZFCP_STATUS_FSFREQ_COMPLETED;
/* cleanup request if requested by initiator */
if (cleanup) {
if (likely(cleanup)) {
ZFCP_LOG_TRACE("removing FSF request 0x%lx\n",
(unsigned long) fsf_req);
/*
......@@ -334,6 +336,16 @@ zfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req)
/* notify initiator waiting for the requests completion */
ZFCP_LOG_TRACE("waking initiator of FSF request 0x%lx\n",
(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);
}
......@@ -372,7 +384,7 @@ zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *fsf_req)
}
/* 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 ;-) */
if (fsf_req->qtcb->header.log_start > ZFCP_QTCB_SIZE) {
ZFCP_LOG_NORMAL
......@@ -686,7 +698,7 @@ zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *fsf_req)
{
int retval = 0;
if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
goto skip_fsfstatus;
}
......@@ -835,7 +847,7 @@ zfcp_fsf_req_dispatch(struct zfcp_fsf_req *fsf_req)
{
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",
(unsigned long) fsf_req,
(unsigned long) (fsf_req->qtcb));
......@@ -1996,6 +2008,20 @@ zfcp_fsf_open_port_handler(struct zfcp_fsf_req *fsf_req)
ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
retval = 0;
/* 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;
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)
}
erp_action->fsf_req->qtcb->header.port_handle =
erp_action->port->handle;
*(fcp_lun_t *) & (erp_action->fsf_req->qtcb->bottom.support.fcp_lun)
= erp_action->unit->fcp_lun;
erp_action->port->handle;
erp_action->fsf_req->qtcb->bottom.support.fcp_lun =
erp_action->unit->fcp_lun;
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->erp_action = erp_action;
......@@ -2835,7 +2861,7 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
retval = zfcp_fsf_req_create(adapter,
FSF_QTCB_FCP_CMND,
&lock_flags, req_flags, &(fsf_req));
if (retval < 0) {
if (unlikely(retval < 0)) {
ZFCP_LOG_DEBUG("error: Out of resources. Could not create an "
"FCP command request for FCP-LUN 0x%Lx "
"connected to the port with WWPN 0x%Lx "
......@@ -2928,7 +2954,7 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
fcp_cmnd_iu->fcp_lun = unit->fcp_lun;
/* 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;
ZFCP_LOG_TRACE("setting SIMPLE_Q task attribute\n");
} else {
......@@ -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 */
if (scsi_cmnd->cmd_len > FCP_CDB_LENGTH) {
if (unlikely(scsi_cmnd->cmd_len > FCP_CDB_LENGTH)) {
fcp_cmnd_iu->add_fcp_cdb_length
= (scsi_cmnd->cmd_len - FCP_CDB_LENGTH) >> 2;
ZFCP_LOG_TRACE("SCSI CDB length is 0x%x, "
......@@ -2965,9 +2991,9 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
/* Note: >= and not = because the combined scatter-gather entries
* 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");
} else if (real_bytes == 0) {
} else if (likely(real_bytes == 0)) {
ZFCP_LOG_DEBUG("Data did not fit into available buffer(s), "
"waiting for more...\n");
retval = -EIO;
......@@ -2996,7 +3022,7 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
* covered by an SBALE)
*/
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 "
"for a command on the adapter %s, "
"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)
int retval = -EINVAL;
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;
else
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 */
goto skip_fsfstatus;
}
......@@ -3445,7 +3471,6 @@ static int
zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
{
int retval = 0;
struct zfcp_adapter *adapter = fsf_req->adapter;
Scsi_Cmnd *scpnt;
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)
read_lock_irqsave(&fsf_req->adapter->abort_lock, flags);
scpnt = fsf_req->data.send_fcp_command_task.scsi_cmnd;
if (!scpnt) {
if (unlikely(!scpnt)) {
ZFCP_LOG_DEBUG
("Command with fsf_req 0x%lx is not associated to "
"a scsi command anymore. Aborted?\n",
(unsigned long) fsf_req);
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
* DID_SOFT_ERROR by retrying the request for devices
* that allow retries.
......@@ -3477,7 +3502,7 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
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");
set_host_byte(&scpnt->result, DID_ERROR);
goto skip_fsfstatus;
......@@ -3491,7 +3516,7 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
* of result in SCSI command
*/
scpnt->result |= fcp_rsp_iu->scsi_status;
if (fcp_rsp_iu->scsi_status) {
if (unlikely(fcp_rsp_iu->scsi_status)) {
/* DEBUG */
ZFCP_LOG_NORMAL("status for SCSI Command:\n");
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL,
......@@ -3507,7 +3532,7 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
}
/* 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");
switch (fcp_rsp_info[3]) {
case RSP_CODE_GOOD:
......@@ -3600,7 +3625,7 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
}
/* 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 -
sizeof (struct fcp_rsp_iu) + fcp_rsp_iu->fcp_rsp_len;
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)
}
/* 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. "
"This happened for a command to the unit "
"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)
}
/* 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. "
"This happened for a command to the unit "
"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)
* the new eh
*/
/* always call back */
(scpnt->scsi_done) (scpnt);
atomic_dec(&adapter->scsi_reqs_active);
wake_up(&adapter->scsi_reqs_active_wq);
#ifdef ZFCP_DEBUG_REQUESTS
debug_text_event(fsf_req->adapter->req_dbf, 2, "ok_done:");
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)
sizeof (unsigned long));
#endif /* ZFCP_DEBUG_REQUESTS */
(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.
* Otherwise we may call scsi_done after abort regarding this
......@@ -3904,7 +3924,7 @@ zfcp_fsf_req_create_sbal_check(unsigned long *flags,
struct zfcp_qdio_queue *queue, int needed)
{
write_lock_irqsave(&queue->queue_lock, *flags);
if (atomic_read(&queue->free_count) >= needed)
if (likely(atomic_read(&queue->free_count) >= needed))
return 1;
write_unlock_irqrestore(&queue->queue_lock, *flags);
return 0;
......@@ -3942,7 +3962,7 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter,
/* allocate new FSF request */
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"
"the outbound (send) queue.\n");
retval = -ENOMEM;
......@@ -3960,11 +3980,11 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter,
fsf_req->specific_magic = ZFCP_MAGIC_FSFREQ;
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;
/* 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",
(unsigned long) fsf_req->qtcb);
fsf_req->qtcb->prefix.req_id = (unsigned long) fsf_req;
......@@ -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)
*/
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;
ZFCP_WAIT_EVENT_TIMEOUT(adapter->request_wq,
timeout,
......@@ -4009,7 +4029,7 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter,
/* setup common SBALE fields */
buffere[0].addr = fsf_req;
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].length = ZFCP_QTCB_SIZE;
}
......@@ -4116,7 +4136,7 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer)
buffere->length);
/* 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->seq_no = adapter->fsf_req_seq_no;
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)
write_unlock_irqrestore(&adapter->fsf_req_list_lock, flags);
/* figure out expiration time of timeout and start timeout */
if (timer) {
if (unlikely(timer)) {
timer->expires += jiffies;
add_timer(timer);
}
......@@ -4167,7 +4187,7 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer)
QDIO_FLAG_SYNC_OUTPUT,
0, fsf_req->sbal_index, fsf_req->sbal_count, NULL);
if (retval) {
if (unlikely(retval)) {
/* Queues are down..... */
retval = -EIO;
/*
......@@ -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_event(adapter->req_dbf, 1, &fsf_req,
sizeof (unsigned long));
if (inc_seq_no) {
if (likely(inc_seq_no)) {
debug_event(adapter->req_dbf, 1,
&adapter->fsf_req_seq_no, sizeof (u32));
} else {
......@@ -4213,7 +4233,7 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer)
* otherwise,
*/
/* Don't increase for unsolicited status */
if (inc_seq_no) {
if (likely(inc_seq_no)) {
adapter->fsf_req_seq_no++;
ZFCP_LOG_TRACE
("FSF sequence counter value of adapter 0x%lx "
......@@ -4263,16 +4283,16 @@ zfcp_fsf_req_get(int kmalloc_flags, mempool_t * pool)
struct zfcp_fsf_req *fsf_req;
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);
} else {
fsf_req = mempool_alloc(pool, kmalloc_flags);
if (fsf_req) {
if (likely(fsf_req)) {
memset(fsf_req, 0, ZFCP_QTCB_AND_REQ_SIZE);
fsf_req->status |= ZFCP_STATUS_FSFREQ_POOL;
}
}
if (fsf_req)
if (likely(fsf_req))
fsf_req->qtcb =
(struct fsf_qtcb *) ((unsigned long) fsf_req +
sizeof (struct zfcp_fsf_req));
......
......@@ -30,8 +30,6 @@
#ifndef FSF_H
#define FSF_H
#ifdef __KERNEL__
#define FSF_QTCB_VERSION1 0x00000001
#define FSF_QTCB_CURRENT_VERSION FSF_QTCB_VERSION1
......@@ -354,5 +352,4 @@ struct fsf_qtcb {
union fsf_qtcb_bottom bottom;
} __attribute__ ((packed));
#endif /* __KERNEL__ */
#endif /* FSF_H */
......@@ -27,7 +27,7 @@
* 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"
......@@ -214,7 +214,7 @@ zfcp_qdio_handler_error_check(struct zfcp_adapter *adapter,
" QDIO_STATUS_OUTBOUND_INT \n");
}
} // 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;
ZFCP_LOG_FLAGS(1, "QDIO_STATUS_LOOK_FOR_ERROR \n");
......@@ -261,7 +261,17 @@ zfcp_qdio_handler_error_check(struct zfcp_adapter *adapter,
}
/* Restarting IO on the failed adapter from scratch */
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;
}
......@@ -293,8 +303,8 @@ zfcp_qdio_request_handler(struct ccw_device *ccw_device,
zfcp_get_busid_by_adapter(adapter),
first_element, elements_processed);
if (zfcp_qdio_handler_error_check(adapter, status, qdio_error,
siga_error))
if (unlikely(zfcp_qdio_handler_error_check(adapter, status, qdio_error,
siga_error)))
goto out;
/*
* we stored address of struct zfcp_adapter data structure
......@@ -345,8 +355,8 @@ zfcp_qdio_response_handler(struct ccw_device *ccw_device,
adapter = (struct zfcp_adapter *) int_parm;
queue = &adapter->response_queue;
if (zfcp_qdio_handler_error_check(adapter, status, qdio_error,
siga_error))
if (unlikely(zfcp_qdio_handler_error_check(adapter, status, qdio_error,
siga_error)))
goto out;
/*
......@@ -394,11 +404,17 @@ zfcp_qdio_response_handler(struct ccw_device *ccw_device,
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL,
(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;
};
if (!buffere->flags & SBAL_FLAGS_LAST_ENTRY) {
if (unlikely(!(buffere->flags & SBAL_FLAGS_LAST_ENTRY))) {
ZFCP_LOG_NORMAL("bug: End of inbound data "
"not marked!\n");
}
......@@ -421,7 +437,7 @@ zfcp_qdio_response_handler(struct ccw_device *ccw_device,
QDIO_FLAG_SYNC_INPUT | QDIO_FLAG_UNDER_INTERRUPT,
0, start, count, NULL);
if (retval) {
if (unlikely(retval)) {
atomic_set(&queue->free_count, count);
ZFCP_LOG_DEBUG("Inbound data regions could not be cleared "
"Transfer queues may be down. "
......@@ -458,7 +474,7 @@ zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, void *sbale_addr)
#endif /* ZFCP_DEBUG_REQUESTS */
/* invalid (per convention used in this driver) */
if (!sbale_addr) {
if (unlikely(!sbale_addr)) {
ZFCP_LOG_NORMAL
("bug: Inbound data faulty, contains null-pointer!\n");
retval = -EINVAL;
......@@ -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 */
fsf_req = (struct zfcp_fsf_req *) sbale_addr;
if ((fsf_req->common_magic != ZFCP_MAGIC) ||
(fsf_req->specific_magic != ZFCP_MAGIC_FSFREQ)) {
if (unlikely((fsf_req->common_magic != ZFCP_MAGIC) ||
(fsf_req->specific_magic != ZFCP_MAGIC_FSFREQ))) {
ZFCP_LOG_NORMAL("bug: An inbound FSF acknowledgement was "
"faulty (debug info 0x%x, 0x%x, 0x%lx)\n",
fsf_req->common_magic,
......@@ -479,7 +495,7 @@ zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, void *sbale_addr)
goto out;
}
if (adapter != fsf_req->adapter) {
if (unlikely(adapter != fsf_req->adapter)) {
ZFCP_LOG_NORMAL("bug: An inbound FSF acknowledgement was not "
"correct (debug info 0x%lx, 0x%lx, 0%lx) \n",
(unsigned long) fsf_req,
......@@ -490,7 +506,7 @@ zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, void *sbale_addr)
}
#ifdef ZFCP_DEBUG_REQUESTS
/* 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,
&fsf_req->qtcb->prefix.req_seq_no, sizeof (u32));
}
......@@ -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",
(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_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE,
(char *) fsf_req->qtcb, ZFCP_QTCB_SIZE);
......@@ -518,8 +534,8 @@ zfcp_qdio_determine_pci(struct zfcp_qdio_queue *req_queue,
int pci_pos;
new_distance_from_int = req_queue->distance_from_int +
fsf_req->sbal_count;
if (new_distance_from_int >= ZFCP_QDIO_PCI_INTERVAL) {
fsf_req->sbal_count;
if (unlikely(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_count;
......
......@@ -30,7 +30,7 @@
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_SCSI
#define ZFCP_LOG_AREA_PREFIX ZFCP_LOG_AREA_PREFIX_SCSI
/* 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>
......@@ -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
zfcp_scsi_block_requests(struct Scsi_Host *shpnt)
{
......@@ -383,25 +290,6 @@ zfcp_scsi_slave_configure(struct scsi_device *sdp)
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 */
static void
zfcp_scsi_queuecommand_stop(Scsi_Cmnd * scpnt,
......@@ -460,10 +348,12 @@ zfcp_scsi_queuecommand_stop(Scsi_Cmnd * scpnt,
int
zfcp_scsi_queuecommand(Scsi_Cmnd * scpnt, void (*done) (Scsi_Cmnd *))
{
int retval;
int temp_ret;
struct zfcp_unit *unit;
struct zfcp_adapter *adapter;
retval = 0;
/* reset the status for this request */
scpnt->result = 0;
/* save address of mid layer call back function */
......@@ -475,47 +365,38 @@ zfcp_scsi_queuecommand(Scsi_Cmnd * scpnt, void (*done) (Scsi_Cmnd *))
*/
adapter = (struct zfcp_adapter *) scpnt->device->host->hostdata[0];
/* NULL when the adapter was removed from the zfcp list */
if (adapter == NULL) {
if (unlikely(adapter == NULL)) {
zfcp_scsi_queuecommand_stop(scpnt, NULL, NULL);
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);
if (unit == NULL)
if (unlikely(unit == NULL))
goto out;
if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &unit->status)
|| !atomic_test_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status)) {
if (unlikely(
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);
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 "
"on the port with WWPN 0x%Lx in recovery.\n",
zfcp_get_busid_by_adapter(adapter),
unit->fcp_lun, unit->port->wwpn);
zfcp_scsi_queuecommand_fake(scpnt, adapter);
retval = SCSI_MLQUEUE_DEVICE_BUSY;
goto out;
}
atomic_inc(&adapter->scsi_reqs_active);
temp_ret = zfcp_fsf_send_fcp_command_task(adapter,
unit,
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");
atomic_dec(&adapter->scsi_reqs_active);
wake_up(&adapter->scsi_reqs_active_wq);
zfcp_scsi_queuecommand_fake(scpnt, adapter);
retval = SCSI_MLQUEUE_HOST_BUSY;
} else {
#ifdef ZFCP_DEBUG_REQUESTS
debug_text_event(adapter->req_dbf, 3, "q_scpnt");
......@@ -524,7 +405,7 @@ zfcp_scsi_queuecommand(Scsi_Cmnd * scpnt, void (*done) (Scsi_Cmnd *))
#endif /* ZFCP_DEBUG_REQUESTS */
}
out:
return 0;
return retval;
}
/*
......@@ -556,45 +437,6 @@ zfcp_unit_lookup(struct zfcp_adapter *adapter, int channel, int id, int lun)
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
*
......@@ -663,33 +505,11 @@ zfcp_scsi_eh_abort_handler(Scsi_Cmnd * scpnt)
* Race condition between normal (late) completion and abort has
* to be avoided.
* The entirity of all accesses to scsi_req have to be atomic.
* scsi_req is usually part of the fsf_req (for requests which
* are not faked) and thus we block the release of fsf_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.
* scsi_req is usually part of the fsf_req and thus we block the
* release of fsf_req as long as we need to access scsi_req.
*/
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.
* 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)
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) {
ZFCP_LOG_NORMAL("bug: Tried to reset a non existant unit.\n");
retval = SUCCESS;
......@@ -1023,7 +838,6 @@ zfcp_adapter_scsi_register(struct zfcp_adapter *adapter)
retval = -EIO;
goto out;
}
atomic_set_mask(ZFCP_STATUS_ADAPTER_REGISTERED, &adapter->status);
ZFCP_LOG_DEBUG("host registered, scsi_host at 0x%lx\n",
(unsigned long) adapter->scsi_host);
......@@ -1039,7 +853,12 @@ zfcp_adapter_scsi_register(struct zfcp_adapter *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:
return retval;
}
......@@ -1061,8 +880,9 @@ zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter)
return;
scsi_remove_host(shost);
scsi_host_put(shost);
adapter->scsi_host = NULL;
atomic_clear_mask(ZFCP_STATUS_ADAPTER_REGISTERED, &adapter->status);
return;
}
......
......@@ -25,7 +25,7 @@
* 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 "zfcp_ext.h"
......@@ -155,11 +155,8 @@ zfcp_sysfs_port_add_store(struct device *dev, const char *buf, size_t count)
retval = 0;
zfcp_adapter_get(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_erp_port_reopen(port, 0);
zfcp_erp_wait(port->adapter);
zfcp_port_put(port);
out:
up(&zfcp_data.config_sema);
......@@ -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_wait(adapter);
zfcp_port_put(port);
zfcp_sysfs_port_remove_files(&port->sysfs_device,
atomic_read(&port->status));
device_unregister(&port->sysfs_device);
out:
up(&zfcp_data.config_sema);
......@@ -268,6 +267,7 @@ zfcp_sysfs_adapter_failed_store(struct device *dev,
zfcp_erp_modify_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING,
ZFCP_SET);
zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED);
zfcp_erp_wait(adapter);
out:
up(&zfcp_data.config_sema);
return retval ? retval : count;
......
......@@ -25,7 +25,7 @@
* 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/module.h>
......@@ -110,11 +110,9 @@ zfcp_sysfs_unit_add_store(struct device *dev, const char *buf, size_t count)
retval = 0;
zfcp_port_get(port);
/* try to open unit only if adapter is online */
if (port->adapter->ccw_device->online == 1)
zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED);
zfcp_erp_unit_reopen(unit, 0);
zfcp_erp_wait(unit->port->adapter);
wait_event(unit->scsi_add_wq, atomic_read(&unit->scsi_add_work) == 0);
zfcp_unit_put(unit);
out:
up(&zfcp_data.config_sema);
......@@ -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_wait(unit->port->adapter);
zfcp_unit_put(unit);
zfcp_sysfs_unit_remove_files(&unit->sysfs_device);
device_unregister(&unit->sysfs_device);
out:
up(&zfcp_data.config_sema);
......@@ -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_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED);
zfcp_erp_wait(port->adapter);
out:
up(&zfcp_data.config_sema);
return retval ? retval : count;
......@@ -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
*
* Create all attributes of the sysfs representation of a port.
......@@ -315,5 +315,19 @@ zfcp_sysfs_port_create_files(struct device *dev, u32 flags)
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_PREFIX
......@@ -25,7 +25,7 @@
* 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/module.h>
......@@ -186,5 +186,17 @@ zfcp_sysfs_unit_create_files(struct device *dev)
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_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