/*
- *
- * linux/drivers/s390/scsi/zfcp_erp.c
- *
- * FCP adapter driver for IBM eServer zSeries
- *
- * (C) Copyright IBM Corp. 2002, 2004
- *
- * Author(s): Martin Peschke <mpeschke@de.ibm.com>
- * Raimund Schroeder <raimund.schroeder@de.ibm.com>
- * Aron Zeh
- * Wolfgang Taphorn
- * Stefan Bader <stefan.bader@de.ibm.com>
- * Heiko Carstens <heiko.carstens@de.ibm.com>
- * Andreas Herrmann <aherrman@de.ibm.com>
+ * This file is part of the zfcp device driver for
+ * FCP adapters for IBM System z9 and zSeries.
+ *
+ * (C) Copyright IBM Corp. 2002, 2006
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
static int zfcp_erp_adapter_strategy(struct zfcp_erp_action *);
static int zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *, int);
static int zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *);
-static int zfcp_erp_adapter_strategy_close_qdio(struct zfcp_erp_action *);
-static int zfcp_erp_adapter_strategy_close_fsf(struct zfcp_erp_action *);
static int zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *);
static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *);
static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *);
static int zfcp_erp_unit_strategy_close(struct zfcp_erp_action *);
static int zfcp_erp_unit_strategy_open(struct zfcp_erp_action *);
-static int zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *);
-static int zfcp_erp_action_dismiss_port(struct zfcp_port *);
-static int zfcp_erp_action_dismiss_unit(struct zfcp_unit *);
-static int zfcp_erp_action_dismiss(struct zfcp_erp_action *);
+static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *);
+static void zfcp_erp_action_dismiss_port(struct zfcp_port *);
+static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *);
+static void 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 inline void zfcp_erp_action_to_running(struct zfcp_erp_action *);
static void zfcp_erp_memwait_handler(unsigned long);
-static void zfcp_erp_timeout_handler(unsigned long);
-static inline void zfcp_erp_timeout_init(struct zfcp_erp_action *);
+
+/**
+ * zfcp_close_qdio - close qdio queues for an adapter
+ */
+static void zfcp_close_qdio(struct zfcp_adapter *adapter)
+{
+ struct zfcp_qdio_queue *req_queue;
+ int first, count;
+
+ if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status))
+ return;
+
+ /* clear QDIOUP flag, thus do_QDIO is not called during qdio_shutdown */
+ req_queue = &adapter->request_queue;
+ write_lock_irq(&req_queue->queue_lock);
+ atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status);
+ write_unlock_irq(&req_queue->queue_lock);
+
+ debug_text_event(adapter->erp_dbf, 3, "qdio_down2a");
+ while (qdio_shutdown(adapter->ccw_device,
+ QDIO_FLAG_CLEANUP_USING_CLEAR) == -EINPROGRESS)
+ msleep(1000);
+ debug_text_event(adapter->erp_dbf, 3, "qdio_down2b");
+
+ /* cleanup used outbound sbals */
+ count = atomic_read(&req_queue->free_count);
+ if (count < QDIO_MAX_BUFFERS_PER_Q) {
+ first = (req_queue->free_index+count) % QDIO_MAX_BUFFERS_PER_Q;
+ count = QDIO_MAX_BUFFERS_PER_Q - count;
+ zfcp_qdio_zero_sbals(req_queue->buffer, first, count);
+ }
+ req_queue->free_index = 0;
+ atomic_set(&req_queue->free_count, 0);
+ req_queue->distance_from_int = 0;
+ adapter->response_queue.free_index = 0;
+ atomic_set(&adapter->response_queue.free_count, 0);
+}
+
+/**
+ * zfcp_close_fsf - stop FSF operations for an adapter
+ *
+ * Dismiss and cleanup all pending fsf_reqs (this wakes up all initiators of
+ * requests waiting for completion; especially this returns SCSI commands
+ * with error state).
+ */
+static void zfcp_close_fsf(struct zfcp_adapter *adapter)
+{
+ /* close queues to ensure that buffers are not accessed by adapter */
+ zfcp_close_qdio(adapter);
+ zfcp_fsf_req_dismiss_all(adapter);
+ /* reset FSF request sequence number */
+ adapter->fsf_req_seq_no = 0;
+ /* all ports and units are closed */
+ zfcp_erp_modify_adapter_status(adapter,
+ ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR);
+}
/**
* zfcp_fsf_request_timeout_handler - called if a request timed out
* This function needs to be called if requests (ELS, Generic Service,
* or SCSI commands) exceed a certain time limit. The assumption is
* that after the time limit the adapter get stuck. So we trigger a reopen of
- * the adapter. This should not be used for error recovery, SCSI abort
- * commands and SCSI requests from SCSI mid-layer.
+ * the adapter.
*/
-void
-zfcp_fsf_request_timeout_handler(unsigned long data)
+static void zfcp_fsf_request_timeout_handler(unsigned long data)
{
- struct zfcp_adapter *adapter;
-
- adapter = (struct zfcp_adapter *) data;
-
+ struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
zfcp_erp_adapter_reopen(adapter, 0);
}
-/*
- * function: zfcp_fsf_scsi_er_timeout_handler
- *
- * purpose: This function needs to be called whenever a SCSI error recovery
- * action (abort/reset) does not return.
- * Re-opening the adapter means that the command can be returned
- * by zfcp (it is guarranteed that it does not return via the
- * adapter anymore). The buffer can then be used again.
- *
- * returns: sod all
- */
-void
-zfcp_fsf_scsi_er_timeout_handler(unsigned long data)
+void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req, unsigned long timeout)
{
- struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
-
- ZFCP_LOG_NORMAL("warning: SCSI error recovery timed out. "
- "Restarting all operations on the adapter %s\n",
- zfcp_get_busid_by_adapter(adapter));
- debug_text_event(adapter->erp_dbf, 1, "eh_lmem_tout");
- zfcp_erp_adapter_reopen(adapter, 0);
-
- return;
+ fsf_req->timer.function = zfcp_fsf_request_timeout_handler;
+ fsf_req->timer.data = (unsigned long) fsf_req->adapter;
+ fsf_req->timer.expires = timeout;
+ add_timer(&fsf_req->timer);
}
/*
* initiates adapter recovery which is done
* asynchronously
*
- * returns: 0 - initiated action succesfully
+ * returns: 0 - initiated action successfully
* <0 - failed to initiate action
*/
int
* purpose: Wrappper for zfcp_erp_adapter_reopen_internal
* used to ensure the correct locking
*
- * returns: 0 - initiated action succesfully
+ * returns: 0 - initiated action successfully
* <0 - failed to initiate action
*/
int
return retval;
}
-/*
- * function:
- *
- * purpose:
- *
- * returns:
- */
int
zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear_mask)
{
return retval;
}
-/*
- * function:
- *
- * purpose:
- *
- * returns:
- */
int
zfcp_erp_port_shutdown(struct zfcp_port *port, int clear_mask)
{
return retval;
}
-/*
- * function:
- *
- * purpose:
- *
- * returns:
- */
int
zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear_mask)
{
struct zfcp_ls_adisc *adisc;
void *address = NULL;
int retval = 0;
- struct timer_list *timer;
- send_els = kmalloc(sizeof(struct zfcp_send_els), GFP_ATOMIC);
+ send_els = kzalloc(sizeof(struct zfcp_send_els), GFP_ATOMIC);
if (send_els == NULL)
goto nomem;
- memset(send_els, 0, sizeof(*send_els));
- send_els->req = kmalloc(sizeof(struct scatterlist), GFP_ATOMIC);
+ send_els->req = kzalloc(sizeof(struct scatterlist), GFP_ATOMIC);
if (send_els->req == NULL)
goto nomem;
- memset(send_els->req, 0, sizeof(*send_els->req));
- send_els->resp = kmalloc(sizeof(struct scatterlist), GFP_ATOMIC);
+ send_els->resp = kzalloc(sizeof(struct scatterlist), GFP_ATOMIC);
if (send_els->resp == NULL)
goto nomem;
- memset(send_els->resp, 0, sizeof(*send_els->resp));
address = (void *) get_zeroed_page(GFP_ATOMIC);
if (address == NULL)
(wwn_t) adisc->wwnn, adisc->hard_nport_id,
adisc->nport_id);
- timer = kmalloc(sizeof(struct timer_list), GFP_ATOMIC);
- if (!timer)
- goto nomem;
-
- init_timer(timer);
- timer->function = zfcp_fsf_request_timeout_handler;
- timer->data = (unsigned long) adapter;
- timer->expires = ZFCP_FSF_REQUEST_TIMEOUT;
- send_els->timer = timer;
-
retval = zfcp_fsf_send_els(send_els);
if (retval != 0) {
ZFCP_LOG_NORMAL("error: initiation of Send ELS failed for port "
"0x%08x on adapter %s\n", send_els->d_id,
zfcp_get_busid_by_adapter(adapter));
- del_timer(send_els->timer);
goto freemem;
}
if (address != NULL)
__free_pages(send_els->req->page, 0);
if (send_els != NULL) {
- kfree(send_els->timer);
kfree(send_els->req);
kfree(send_els->resp);
kfree(send_els);
struct zfcp_ls_adisc_acc *adisc;
send_els = (struct zfcp_send_els *) data;
-
- del_timer(send_els->timer);
-
adapter = send_els->adapter;
port = send_els->port;
d_id = send_els->d_id;
out:
zfcp_port_put(port);
__free_pages(send_els->req->page, 0);
- kfree(send_els->timer);
kfree(send_els->req);
kfree(send_els->resp);
kfree(send_els);
* initiates Forced Reopen recovery which is done
* asynchronously
*
- * returns: 0 - initiated action succesfully
+ * returns: 0 - initiated action successfully
* <0 - failed to initiate action
*/
static int
* purpose: Wrappper for zfcp_erp_port_forced_reopen_internal
* used to ensure the correct locking
*
- * returns: 0 - initiated action succesfully
+ * returns: 0 - initiated action successfully
* <0 - failed to initiate action
*/
int
* initiates Reopen recovery which is done
* asynchronously
*
- * returns: 0 - initiated action succesfully
+ * returns: 0 - initiated action successfully
* <0 - failed to initiate action
*/
static int
* initiates Reopen recovery which is done
* asynchronously
*
- * returns: 0 - initiated action succesfully
+ * returns: 0 - initiated action successfully
* <0 - failed to initiate action
*/
static int
return retval;
}
-/*
- * function:
- *
- * purpose: disable I/O,
- * return any open requests and clean them up,
- * aim: no pending and incoming I/O
- *
- * returns:
+/**
+ * zfcp_erp_adapter_block - mark adapter as blocked, block scsi requests
*/
-static void
-zfcp_erp_adapter_block(struct zfcp_adapter *adapter, int clear_mask)
+static void zfcp_erp_adapter_block(struct zfcp_adapter *adapter, int clear_mask)
{
debug_text_event(adapter->erp_dbf, 6, "a_bl");
zfcp_erp_modify_adapter_status(adapter,
clear_mask, ZFCP_CLEAR);
}
-/*
- * function:
- *
- * purpose: enable I/O
- *
- * returns:
+/**
+ * zfcp_erp_adapter_unblock - mark adapter as unblocked, allow scsi requests
*/
-static void
-zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter)
+static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter)
{
debug_text_event(adapter->erp_dbf, 6, "a_ubl");
atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status);
atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status);
}
-/*
- * function:
- *
- * purpose:
- *
- * returns:
- */
static void
zfcp_erp_action_ready(struct zfcp_erp_action *erp_action)
{
struct zfcp_adapter *adapter = erp_action->adapter;
if (erp_action->fsf_req) {
- /* take lock to ensure that request is not being deleted meanwhile */
- spin_lock(&adapter->fsf_req_list_lock);
- /* check whether fsf req does still exist */
- list_for_each_entry(fsf_req, &adapter->fsf_req_list_head, list)
- if (fsf_req == erp_action->fsf_req)
- break;
- if (fsf_req && (fsf_req->erp_action == erp_action)) {
+ /* take lock to ensure that request is not deleted meanwhile */
+ spin_lock(&adapter->req_list_lock);
+ if ((!zfcp_reqlist_ismember(adapter,
+ erp_action->fsf_req->req_id)) &&
+ (fsf_req->erp_action == erp_action)) {
/* fsf_req still exists */
debug_text_event(adapter->erp_dbf, 3, "a_ca_req");
debug_event(adapter->erp_dbf, 3, &fsf_req,
sizeof (unsigned long));
- /* dismiss fsf_req of timed out or dismissed erp_action */
+ /* dismiss fsf_req of timed out/dismissed erp_action */
if (erp_action->status & (ZFCP_STATUS_ERP_DISMISSED |
ZFCP_STATUS_ERP_TIMEDOUT)) {
debug_text_event(adapter->erp_dbf, 3,
*/
erp_action->fsf_req = NULL;
}
- spin_unlock(&adapter->fsf_req_list_lock);
+ spin_unlock(&adapter->req_list_lock);
} else
debug_text_event(adapter->erp_dbf, 3, "a_ca_noreq");
return retval;
}
-/*
- * purpose: generic handler for asynchronous events related to erp_action events
- * (normal completion, time-out, dismissing, retry after
- * low memory condition)
- *
- * note: deletion of timer is not required (e.g. in case of a time-out),
- * but a second try does no harm,
- * we leave it in here to allow for greater simplification
+/**
+ * zfcp_erp_async_handler_nolock - complete erp_action
*
- * returns: 0 - there was an action to handle
- * !0 - otherwise
+ * Used for normal completion, time-out, dismissal and failure after
+ * low memory condition.
*/
-static int
-zfcp_erp_async_handler_nolock(struct zfcp_erp_action *erp_action,
- unsigned long set_mask)
+static void zfcp_erp_async_handler_nolock(struct zfcp_erp_action *erp_action,
+ unsigned long set_mask)
{
- int retval;
struct zfcp_adapter *adapter = erp_action->adapter;
if (zfcp_erp_action_exists(erp_action) == ZFCP_ERP_ACTION_RUNNING) {
debug_text_event(adapter->erp_dbf, 2, "a_asyh_ex");
debug_event(adapter->erp_dbf, 2, &erp_action->action,
sizeof (int));
- if (!(set_mask & ZFCP_STATUS_ERP_TIMEDOUT))
- del_timer(&erp_action->timer);
erp_action->status |= set_mask;
zfcp_erp_action_ready(erp_action);
- retval = 0;
} else {
/* action is ready or gone - nothing to do */
debug_text_event(adapter->erp_dbf, 3, "a_asyh_gone");
debug_event(adapter->erp_dbf, 3, &erp_action->action,
sizeof (int));
- retval = 1;
}
-
- return retval;
}
-/*
- * purpose: generic handler for asynchronous events related to erp_action
- * events (normal completion, time-out, dismissing, retry after
- * low memory condition)
- *
- * note: deletion of timer is not required (e.g. in case of a time-out),
- * but a second try does no harm,
- * we leave it in here to allow for greater simplification
- *
- * returns: 0 - there was an action to handle
- * !0 - otherwise
+/**
+ * zfcp_erp_async_handler - wrapper for erp_async_handler_nolock w/ locking
*/
-int
-zfcp_erp_async_handler(struct zfcp_erp_action *erp_action,
- unsigned long set_mask)
+void zfcp_erp_async_handler(struct zfcp_erp_action *erp_action,
+ unsigned long set_mask)
{
struct zfcp_adapter *adapter = erp_action->adapter;
unsigned long flags;
- int retval;
write_lock_irqsave(&adapter->erp_lock, flags);
- retval = zfcp_erp_async_handler_nolock(erp_action, set_mask);
+ zfcp_erp_async_handler_nolock(erp_action, set_mask);
write_unlock_irqrestore(&adapter->erp_lock, flags);
-
- return retval;
}
/*
* action gets an appropriate flag and will be processed
* accordingly
*/
-static void
-zfcp_erp_timeout_handler(unsigned long data)
+void zfcp_erp_timeout_handler(unsigned long data)
{
struct zfcp_erp_action *erp_action = (struct zfcp_erp_action *) data;
struct zfcp_adapter *adapter = erp_action->adapter;
zfcp_erp_async_handler(erp_action, ZFCP_STATUS_ERP_TIMEDOUT);
}
-/*
- * purpose: is called for an erp_action which needs to be ended
- * though not being done,
- * this is usually required if an higher is generated,
- * action gets an appropriate flag and will be processed
- * accordingly
+/**
+ * zfcp_erp_action_dismiss - dismiss an erp_action
*
- * locks: erp_lock held (thus we need to call another handler variant)
+ * adapter->erp_lock must be held
+ *
+ * Dismissal of an erp_action is usually required if an erp_action of
+ * higher priority is generated.
*/
-static int
-zfcp_erp_action_dismiss(struct zfcp_erp_action *erp_action)
+static void zfcp_erp_action_dismiss(struct zfcp_erp_action *erp_action)
{
struct zfcp_adapter *adapter = erp_action->adapter;
debug_event(adapter->erp_dbf, 2, &erp_action->action, sizeof (int));
zfcp_erp_async_handler_nolock(erp_action, ZFCP_STATUS_ERP_DISMISSED);
-
- return 0;
}
int
return retval;
}
-/*
- * function:
- *
- * purpose:
- *
- * returns:
- */
static int
zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action)
{
return result;
}
-/*
- * function:
- *
- * purpose:
- *
- * returns:
- */
static int
zfcp_erp_strategy_statechange(int action,
u32 status,
return retval;
}
-/*
- * function:
- *
- * purpose:
- *
- * returns:
- */
static inline int
zfcp_erp_strategy_statechange_detected(atomic_t * target_status, u32 erp_status)
{
!(ZFCP_STATUS_ERP_CLOSE_ONLY & erp_status));
}
-/*
- * function:
- *
- * purpose:
- *
- * returns:
- */
static int
zfcp_erp_strategy_check_unit(struct zfcp_unit *unit, int result)
{
return result;
}
-/*
- * function:
- *
- * purpose:
- *
- * returns:
- */
static int
zfcp_erp_strategy_check_port(struct zfcp_port *port, int result)
{
return result;
}
-/*
- * function:
- *
- * purpose:
- *
- * returns:
- */
static int
zfcp_erp_strategy_check_adapter(struct zfcp_adapter *adapter, int result)
{
return 0;
}
-/*
- * function:
- *
- * purpose:
- *
- * returns:
- */
static int
zfcp_erp_strategy_check_queues(struct zfcp_adapter *adapter)
{
return retval;
}
-/*
- * function: zfcp_erp_modify_adapter_status
- *
- * purpose:
- *
- */
void
zfcp_erp_modify_adapter_status(struct zfcp_adapter *adapter,
u32 mask, int set_or_clear)
* purpose: Wrappper for zfcp_erp_port_reopen_all_internal
* used to ensure the correct locking
*
- * returns: 0 - initiated action succesfully
+ * returns: 0 - initiated action successfully
* <0 - failed to initiate action
*/
int
return retval;
}
-/*
- * function:
- *
- * purpose:
- *
- * returns: FIXME
- */
static int
zfcp_erp_port_reopen_all_internal(struct zfcp_adapter *adapter, int clear_mask)
{
&erp_action->adapter->status);
failed_openfcp:
- zfcp_erp_adapter_strategy_close_qdio(erp_action);
- zfcp_erp_adapter_strategy_close_fsf(erp_action);
+ zfcp_close_fsf(erp_action->adapter);
failed_qdio:
out:
return retval;
sbale = &(adapter->response_queue.buffer[i]->element[0]);
sbale->length = 0;
sbale->flags = SBAL_FLAGS_LAST_ENTRY;
- sbale->addr = 0;
+ sbale->addr = NULL;
}
ZFCP_LOG_TRACE("calling do_QDIO on adapter %s (flags=0x%x, "
return retval;
}
-/*
- * function: zfcp_qdio_cleanup
- *
- * purpose: cleans up QDIO operation for the specified adapter
- *
- * returns: 0 - successful cleanup
- * !0 - failed cleanup
- */
-int
-zfcp_erp_adapter_strategy_close_qdio(struct zfcp_erp_action *erp_action)
-{
- int retval = ZFCP_ERP_SUCCEEDED;
- int first_used;
- int used_count;
- struct zfcp_adapter *adapter = erp_action->adapter;
-
- if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)) {
- ZFCP_LOG_DEBUG("error: attempt to shut down inactive QDIO "
- "queues on adapter %s\n",
- zfcp_get_busid_by_adapter(adapter));
- retval = ZFCP_ERP_FAILED;
- goto out;
- }
-
- /*
- * Get queue_lock and clear QDIOUP flag. Thus it's guaranteed that
- * do_QDIO won't be called while qdio_shutdown is in progress.
- */
-
- write_lock_irq(&adapter->request_queue.queue_lock);
- atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status);
- write_unlock_irq(&adapter->request_queue.queue_lock);
-
- debug_text_event(adapter->erp_dbf, 3, "qdio_down2a");
- while (qdio_shutdown(adapter->ccw_device,
- QDIO_FLAG_CLEANUP_USING_CLEAR) == -EINPROGRESS)
- msleep(1000);
- debug_text_event(adapter->erp_dbf, 3, "qdio_down2b");
-
- /*
- * First we had to stop QDIO operation.
- * Now it is safe to take the following actions.
- */
-
- /* Cleanup only necessary when there are unacknowledged buffers */
- if (atomic_read(&adapter->request_queue.free_count)
- < QDIO_MAX_BUFFERS_PER_Q) {
- first_used = (adapter->request_queue.free_index +
- atomic_read(&adapter->request_queue.free_count))
- % QDIO_MAX_BUFFERS_PER_Q;
- used_count = QDIO_MAX_BUFFERS_PER_Q -
- atomic_read(&adapter->request_queue.free_count);
- zfcp_qdio_zero_sbals(adapter->request_queue.buffer,
- first_used, used_count);
- }
- adapter->response_queue.free_index = 0;
- atomic_set(&adapter->response_queue.free_count, 0);
- adapter->request_queue.free_index = 0;
- atomic_set(&adapter->request_queue.free_count, 0);
- adapter->request_queue.distance_from_int = 0;
- out:
- return retval;
-}
static int
zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *erp_action)
atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
&adapter->status);
ZFCP_LOG_DEBUG("Doing exchange config data\n");
- write_lock(&adapter->erp_lock);
+ write_lock_irq(&adapter->erp_lock);
zfcp_erp_action_to_running(erp_action);
- write_unlock(&adapter->erp_lock);
- zfcp_erp_timeout_init(erp_action);
+ write_unlock_irq(&adapter->erp_lock);
if (zfcp_fsf_exchange_config_data(erp_action)) {
retval = ZFCP_ERP_FAILED;
debug_text_event(adapter->erp_dbf, 5, "a_fstx_xf");
adapter = erp_action->adapter;
atomic_clear_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status);
- write_lock(&adapter->erp_lock);
+ write_lock_irq(&adapter->erp_lock);
zfcp_erp_action_to_running(erp_action);
- write_unlock(&adapter->erp_lock);
+ write_unlock_irq(&adapter->erp_lock);
- zfcp_erp_timeout_init(erp_action);
ret = zfcp_fsf_exchange_port_data(erp_action, adapter, NULL);
if (ret == -EOPNOTSUPP) {
debug_text_event(adapter->erp_dbf, 3, "a_xport_notsupp");
"%s)\n", zfcp_get_busid_by_adapter(adapter));
ret = ZFCP_ERP_FAILED;
}
- if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status)) {
- ZFCP_LOG_INFO("error: exchange port data failed (adapter "
+
+ /* don't treat as error for the sake of compatibility */
+ if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status))
+ ZFCP_LOG_INFO("warning: exchange port data failed (adapter "
"%s\n", zfcp_get_busid_by_adapter(adapter));
- ret = ZFCP_ERP_FAILED;
- }
return ret;
}
-/*
- * function:
- *
- * purpose:
- *
- * returns:
- */
static int
zfcp_erp_adapter_strategy_open_fsf_statusread(struct zfcp_erp_action
*erp_action)
return retval;
}
-/*
- * function: zfcp_fsf_cleanup
- *
- * purpose: cleanup FSF operation for specified adapter
- *
- * returns: 0 - FSF operation successfully cleaned up
- * !0 - failed to cleanup FSF operation for this adapter
- */
-static int
-zfcp_erp_adapter_strategy_close_fsf(struct zfcp_erp_action *erp_action)
-{
- int retval = ZFCP_ERP_SUCCEEDED;
- struct zfcp_adapter *adapter = erp_action->adapter;
-
- /*
- * wake waiting initiators of requests,
- * return SCSI commands (with error status),
- * clean up all requests (synchronously)
- */
- zfcp_fsf_req_dismiss_all(adapter);
- /* reset FSF request sequence number */
- adapter->fsf_req_seq_no = 0;
- /* all ports and units are closed */
- zfcp_erp_modify_adapter_status(adapter,
- ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR);
-
- return retval;
-}
-
/*
* function:
*
return retval;
}
-/*
- * function:
- *
- * purpose:
- *
- * returns:
- */
static int
zfcp_erp_port_strategy_open(struct zfcp_erp_action *erp_action)
{
return retval;
}
-/*
- * function:
- *
- * purpose:
- *
- * returns:
- *
- * FIXME(design): currently only prepared for fabric (nameserver!)
- */
static int
zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *erp_action)
{
return retval;
}
-/*
- * function:
- *
- * purpose:
- *
- * returns:
- */
static int
zfcp_erp_port_strategy_open_nameserver(struct zfcp_erp_action *erp_action)
{
struct zfcp_adapter *adapter = erp_action->adapter;
struct zfcp_port *port = erp_action->port;
- zfcp_erp_timeout_init(erp_action);
retval = zfcp_fsf_close_physical_port(erp_action);
if (retval == -ENOMEM) {
debug_text_event(adapter->erp_dbf, 5, "o_pfstc_nomem");
return retval;
}
-/*
- * function:
- *
- * purpose:
- *
- * returns:
- */
static int
zfcp_erp_port_strategy_clearstati(struct zfcp_port *port)
{
struct zfcp_adapter *adapter = erp_action->adapter;
struct zfcp_port *port = erp_action->port;
- zfcp_erp_timeout_init(erp_action);
retval = zfcp_fsf_close_port(erp_action);
if (retval == -ENOMEM) {
debug_text_event(adapter->erp_dbf, 5, "p_pstc_nomem");
struct zfcp_adapter *adapter = erp_action->adapter;
struct zfcp_port *port = erp_action->port;
- zfcp_erp_timeout_init(erp_action);
retval = zfcp_fsf_open_port(erp_action);
if (retval == -ENOMEM) {
debug_text_event(adapter->erp_dbf, 5, "p_psto_nomem");
struct zfcp_adapter *adapter = erp_action->adapter;
struct zfcp_port *port = erp_action->port;
- zfcp_erp_timeout_init(erp_action);
retval = zfcp_ns_gid_pn_request(erp_action);
if (retval == -ENOMEM) {
debug_text_event(adapter->erp_dbf, 5, "p_pstn_nomem");
return retval;
}
-/*
- * function:
- *
- * purpose:
- *
- * returns:
- */
static int
zfcp_erp_unit_strategy_clearstati(struct zfcp_unit *unit)
{
struct zfcp_adapter *adapter = erp_action->adapter;
struct zfcp_unit *unit = erp_action->unit;
- zfcp_erp_timeout_init(erp_action);
retval = zfcp_fsf_close_unit(erp_action);
if (retval == -ENOMEM) {
debug_text_event(adapter->erp_dbf, 5, "u_ustc_nomem");
struct zfcp_adapter *adapter = erp_action->adapter;
struct zfcp_unit *unit = erp_action->unit;
- zfcp_erp_timeout_init(erp_action);
retval = zfcp_fsf_open_unit(erp_action);
if (retval == -ENOMEM) {
debug_text_event(adapter->erp_dbf, 5, "u_usto_nomem");
return retval;
}
-/*
- * function:
- *
- * purpose:
- *
- * returns:
- */
-static inline void
-zfcp_erp_timeout_init(struct zfcp_erp_action *erp_action)
+void zfcp_erp_start_timer(struct zfcp_fsf_req *fsf_req)
{
- init_timer(&erp_action->timer);
- erp_action->timer.function = zfcp_erp_timeout_handler;
- erp_action->timer.data = (unsigned long) erp_action;
- /* jiffies will be added in zfcp_fsf_req_send */
- erp_action->timer.expires = ZFCP_ERP_FSFREQ_TIMEOUT;
+ BUG_ON(!fsf_req->erp_action);
+ fsf_req->timer.function = zfcp_erp_timeout_handler;
+ fsf_req->timer.data = (unsigned long) fsf_req->erp_action;
+ fsf_req->timer.expires = jiffies + ZFCP_ERP_FSFREQ_TIMEOUT;
+ add_timer(&fsf_req->timer);
}
/*
return retval;
}
-/*
- * function:
- *
- * purpose:
- *
- * returns:
- */
static int
zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action)
{
break;
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
case ZFCP_ERP_ACTION_REOPEN_PORT:
+ if (atomic_test_mask(ZFCP_STATUS_PORT_NO_WWPN,
+ &port->status)) {
+ zfcp_port_put(port);
+ break;
+ }
+
if ((result == ZFCP_ERP_SUCCEEDED)
- && !atomic_test_mask(ZFCP_STATUS_PORT_NO_WWPN,
- &port->status)
&& !port->rport) {
struct fc_rport_identifiers ids;
ids.node_name = port->wwnn;
"(adapter %s, wwpn=0x%016Lx)\n",
zfcp_get_busid_by_port(port),
port->wwpn);
- else
+ else {
scsi_flush_work(adapter->scsi_host);
+ port->rport->maxframe_size = port->maxframe_size;
+ port->rport->supported_classes =
+ port->supported_classes;
+ }
+ }
+ if ((result != ZFCP_ERP_SUCCEEDED) && port->rport) {
+ fc_remote_port_delete(port->rport);
+ port->rport = NULL;
}
zfcp_port_put(port);
break;
case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
+ if (result != ZFCP_ERP_SUCCEEDED) {
+ struct zfcp_port *port;
+ list_for_each_entry(port, &adapter->port_list_head, list)
+ if (port->rport &&
+ !atomic_test_mask(ZFCP_STATUS_PORT_WKA,
+ &port->status)) {
+ fc_remote_port_delete(port->rport);
+ port->rport = NULL;
+ }
+ }
zfcp_adapter_put(adapter);
break;
default:
}
-/*
- * function:
- *
- * purpose:
- *
- * returns: FIXME
- */
-static int
-zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter)
+static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter)
{
- int retval = 0;
struct zfcp_port *port;
debug_text_event(adapter->erp_dbf, 5, "a_actab");
else
list_for_each_entry(port, &adapter->port_list_head, list)
zfcp_erp_action_dismiss_port(port);
-
- return retval;
}
-/*
- * function:
- *
- * purpose:
- *
- * returns: FIXME
- */
-static int
-zfcp_erp_action_dismiss_port(struct zfcp_port *port)
+static void zfcp_erp_action_dismiss_port(struct zfcp_port *port)
{
- int retval = 0;
struct zfcp_unit *unit;
struct zfcp_adapter *adapter = port->adapter;
else
list_for_each_entry(unit, &port->unit_list_head, list)
zfcp_erp_action_dismiss_unit(unit);
-
- return retval;
}
-/*
- * function:
- *
- * purpose:
- *
- * returns: FIXME
- */
-static int
-zfcp_erp_action_dismiss_unit(struct zfcp_unit *unit)
+static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *unit)
{
- int retval = 0;
struct zfcp_adapter *adapter = unit->port->adapter;
debug_text_event(adapter->erp_dbf, 5, "u_actab");
debug_event(adapter->erp_dbf, 5, &unit->fcp_lun, sizeof (fcp_lun_t));
if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status))
zfcp_erp_action_dismiss(&unit->erp_action);
-
- return retval;
}
-/*
- * function:
- *
- * purpose: moves erp_action to 'erp running list'
- *
- * returns:
- */
static inline void
zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)
{
list_move(&erp_action->list, &erp_action->adapter->erp_running_head);
}
-/*
- * function:
- *
- * purpose: moves erp_action to 'erp ready list'
- *
- * returns:
- */
static inline void
zfcp_erp_action_to_ready(struct zfcp_erp_action *erp_action)
{
list_move(&erp_action->list, &erp_action->adapter->erp_ready_head);
}
-/*
- * function: zfcp_erp_port_boxed
- *
- * purpose:
- */
void
zfcp_erp_port_boxed(struct zfcp_port *port)
{
zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED);
}
-/*
- * function: zfcp_erp_unit_boxed
- *
- * purpose:
- */
void
zfcp_erp_unit_boxed(struct zfcp_unit *unit)
{
zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED);
}
-/*
- * function: zfcp_erp_port_access_denied
- *
- * purpose:
- */
void
zfcp_erp_port_access_denied(struct zfcp_port *port)
{
read_unlock_irqrestore(&zfcp_data.config_lock, flags);
}
-/*
- * function: zfcp_erp_unit_access_denied
- *
- * purpose:
- */
void
zfcp_erp_unit_access_denied(struct zfcp_unit *unit)
{
ZFCP_SET);
}
-/*
- * function: zfcp_erp_adapter_access_changed
- *
- * purpose:
- */
void
zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter)
{
return;
debug_text_event(adapter->erp_dbf, 3, "a_access_recover");
- debug_event(adapter->erp_dbf, 3, &adapter->name, 8);
+ debug_event(adapter->erp_dbf, 3, zfcp_get_busid_by_adapter(adapter), 8);
read_lock_irqsave(&zfcp_data.config_lock, flags);
if (adapter->nameserver_port)
read_unlock_irqrestore(&zfcp_data.config_lock, flags);
}
-/*
- * function: zfcp_erp_port_access_changed
- *
- * purpose:
- */
void
zfcp_erp_port_access_changed(struct zfcp_port *port)
{
zfcp_get_busid_by_adapter(adapter), port->wwpn);
}
-/*
- * function: zfcp_erp_unit_access_changed
- *
- * purpose:
- */
void
zfcp_erp_unit_access_changed(struct zfcp_unit *unit)
{