aboutsummaryrefslogtreecommitdiff
path: root/drivers/s390/scsi/zfcp_fsf.c
diff options
context:
space:
mode:
authorSwen Schillig <swen@vnet.ibm.com>2008-07-02 10:56:39 +0200
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-07-12 08:22:35 -0500
commitc41f8cbddd4e0e72951e0575165dea8ea26f1c4b (patch)
tree67eaa89161e594ff2b45dbc9c1bdaee7176b2a32 /drivers/s390/scsi/zfcp_fsf.c
parent60221920706a01bef89af2577f9a90a8eeb4e662 (diff)
[SCSI] zfcp: zfcp_fsf cleanup.
Code cleanup for the zfcp_fsf.c file. Signed-off-by: Swen Schillig <swen@vnet.ibm.com> Signed-off-by: Christof Schmitt <christof.schmitt@de.ibm.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/s390/scsi/zfcp_fsf.c')
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c4119
1 files changed, 1536 insertions, 2583 deletions
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 22e3aa61278..e6d815593b4 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -8,35 +8,6 @@
#include "zfcp_ext.h"
-static int zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *);
-static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *);
-static int zfcp_fsf_open_port_handler(struct zfcp_fsf_req *);
-static int zfcp_fsf_close_port_handler(struct zfcp_fsf_req *);
-static int zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *);
-static int zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *);
-static int zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *);
-static int zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *);
-static int zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *);
-static int zfcp_fsf_send_fcp_command_task_management_handler(
- struct zfcp_fsf_req *);
-static int zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *);
-static int zfcp_fsf_status_read_handler(struct zfcp_fsf_req *);
-static int zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *);
-static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *);
-static void zfcp_fsf_control_file_handler(struct zfcp_fsf_req *);
-static inline int zfcp_fsf_req_sbal_check(
- unsigned long *, struct zfcp_qdio_queue *, int);
-static inline int zfcp_use_one_sbal(
- struct scatterlist *, int, struct scatterlist *, int);
-static struct zfcp_fsf_req *zfcp_fsf_req_alloc(mempool_t *, int);
-static int zfcp_fsf_req_send(struct zfcp_fsf_req *);
-static int zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *);
-static int zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *);
-static int zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *);
-static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *, u8,
- struct fsf_link_down_info *);
-static int zfcp_fsf_req_dispatch(struct zfcp_fsf_req *);
-
/* association between FSF command and FSF QTCB type */
static u32 fsf_qtcb_type[] = {
[FSF_QTCB_FCP_CMND] = FSF_IO_COMMAND,
@@ -54,21 +25,19 @@ static u32 fsf_qtcb_type[] = {
[FSF_QTCB_UPLOAD_CONTROL_FILE] = FSF_SUPPORT_COMMAND
};
-static const char zfcp_act_subtable_type[5][8] = {
+static const char *zfcp_act_subtable_type[] = {
"unknown", "OS", "WWPN", "DID", "LUN"
};
static void zfcp_act_eval_err(struct zfcp_adapter *adapter, u32 table)
{
- u16 subtable = (table & 0xffff0000) >> 16;
+ u16 subtable = table >> 16;
u16 rule = table & 0xffff;
- if (subtable > 0 &&
- subtable < ARRAY_SIZE(zfcp_act_subtable_type)) {
+ if (subtable && subtable < ARRAY_SIZE(zfcp_act_subtable_type))
dev_warn(&adapter->ccw_device->dev,
"Access denied in subtable %s, rule %d.\n",
zfcp_act_subtable_type[subtable], rule);
- }
}
static void zfcp_fsf_access_denied_port(struct zfcp_fsf_req *req,
@@ -106,90 +75,27 @@ static void zfcp_fsf_class_not_supp(struct zfcp_fsf_req *req)
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
}
-/****************************************************************/
-/*************** FSF related Functions *************************/
-/****************************************************************/
-
-/*
- * function: zfcp_fsf_req_alloc
- *
- * purpose: Obtains an fsf_req and potentially a qtcb (for all but
- * unsolicited requests) via helper functions
- * Does some initial fsf request set-up.
- *
- * returns: pointer to allocated fsf_req if successfull
- * NULL otherwise
- *
- * locks: none
- *
- */
-static struct zfcp_fsf_req *
-zfcp_fsf_req_alloc(mempool_t *pool, int req_flags)
-{
- size_t size;
- void *ptr;
- struct zfcp_fsf_req *fsf_req = NULL;
-
- if (req_flags & ZFCP_REQ_NO_QTCB)
- size = sizeof(struct zfcp_fsf_req);
- else
- size = sizeof(struct zfcp_fsf_req_qtcb);
-
- if (likely(pool))
- ptr = mempool_alloc(pool, GFP_ATOMIC);
- else {
- if (req_flags & ZFCP_REQ_NO_QTCB)
- ptr = kmalloc(size, GFP_ATOMIC);
- else
- ptr = kmem_cache_alloc(zfcp_data.fsf_req_qtcb_cache,
- GFP_ATOMIC);
- }
-
- if (unlikely(!ptr))
- goto out;
-
- memset(ptr, 0, size);
-
- if (req_flags & ZFCP_REQ_NO_QTCB) {
- fsf_req = (struct zfcp_fsf_req *) ptr;
- } else {
- fsf_req = &((struct zfcp_fsf_req_qtcb *) ptr)->fsf_req;
- fsf_req->qtcb = &((struct zfcp_fsf_req_qtcb *) ptr)->qtcb;
- }
-
- fsf_req->pool = pool;
-
- out:
- return fsf_req;
-}
-
-/*
- * function: zfcp_fsf_req_free
- *
- * purpose: Frees the memory of an fsf_req (and potentially a qtcb) or
- * returns it into the pool via helper functions.
- *
- * returns: sod all
- *
- * locks: none
+/**
+ * zfcp_fsf_req_free - free memory used by fsf request
+ * @fsf_req: pointer to struct zfcp_fsf_req
*/
-void
-zfcp_fsf_req_free(struct zfcp_fsf_req *fsf_req)
+void zfcp_fsf_req_free(struct zfcp_fsf_req *req)
{
- if (likely(fsf_req->pool)) {
- mempool_free(fsf_req, fsf_req->pool);
+ if (likely(req->pool)) {
+ mempool_free(req, req->pool);
return;
}
- if (fsf_req->qtcb) {
- kmem_cache_free(zfcp_data.fsf_req_qtcb_cache, fsf_req);
+ if (req->qtcb) {
+ kmem_cache_free(zfcp_data.fsf_req_qtcb_cache, req);
return;
}
-
- kfree(fsf_req);
}
-/*
+/**
+ * zfcp_fsf_req_dismiss_all - dismiss all fsf requests
+ * @adapter: pointer to struct zfcp_adapter
+ *
* Never ever call this without shutting down the adapter first.
* Otherwise the adapter would continue using and corrupting s390 storage.
* Included BUG_ON() call to ensure this is done.
@@ -197,1815 +103,1359 @@ zfcp_fsf_req_free(struct zfcp_fsf_req *fsf_req)
*/
void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter)
{
- struct zfcp_fsf_req *fsf_req, *tmp;
+ struct zfcp_fsf_req *req, *tmp;
unsigned long flags;
LIST_HEAD(remove_queue);
unsigned int i;
- BUG_ON(atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status));
+ BUG_ON(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP);
spin_lock_irqsave(&adapter->req_list_lock, flags);
for (i = 0; i < REQUEST_LIST_SIZE; i++)
list_splice_init(&adapter->req_list[i], &remove_queue);
spin_unlock_irqrestore(&adapter->req_list_lock, flags);
- list_for_each_entry_safe(fsf_req, tmp, &remove_queue, list) {
- list_del(&fsf_req->list);
- fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED;
- zfcp_fsf_req_complete(fsf_req);
+ list_for_each_entry_safe(req, tmp, &remove_queue, list) {
+ list_del(&req->list);
+ req->status |= ZFCP_STATUS_FSFREQ_DISMISSED;
+ zfcp_fsf_req_complete(req);
}
}
-/*
- * function: zfcp_fsf_req_complete
- *
- * purpose: Updates active counts and timers for openfcp-reqs
- * May cleanup request after req_eval returns
- *
- * returns: 0 - success
- * !0 - failure
- *
- * context:
- */
-int
-zfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req)
+static void zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *req)
{
- int retval = 0;
- int cleanup;
-
- if (unlikely(fsf_req->fsf_command == FSF_QTCB_UNSOLICITED_STATUS)) {
- /*
- * Note: all cleanup handling is done in the callchain of
- * the function call-chain below.
- */
- zfcp_fsf_status_read_handler(fsf_req);
- goto out;
- } else {
- del_timer(&fsf_req->timer);
- zfcp_fsf_protstatus_eval(fsf_req);
- }
-
- /*
- * fsf_req may be deleted due to waking up functions, so
- * cleanup is saved here and used later
- */
- if (likely(fsf_req->status & ZFCP_STATUS_FSFREQ_CLEANUP))
- cleanup = 1;
- else
- cleanup = 0;
-
- fsf_req->status |= ZFCP_STATUS_FSFREQ_COMPLETED;
-
- /* cleanup request if requested by initiator */
- if (likely(cleanup)) {
- /*
- * lock must not be held here since it will be
- * grabed by the called routine, too
- */
- zfcp_fsf_req_free(fsf_req);
- } else {
- /* notify initiator waiting for the requests completion */
- /*
- * 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);
- }
-
- out:
- return retval;
-}
-
-/*
- * function: zfcp_fsf_protstatus_eval
- *
- * purpose: evaluates the QTCB of the finished FSF request
- * and initiates appropriate actions
- * (usually calling FSF command specific handlers)
- *
- * returns:
- *
- * context:
- *
- * locks:
- */
-static int
-zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *fsf_req)
-{
- int retval = 0;
- struct zfcp_adapter *adapter = fsf_req->adapter;
- struct fsf_qtcb *qtcb = fsf_req->qtcb;
- union fsf_prot_status_qual *prot_status_qual =
- &qtcb->prefix.prot_status_qual;
-
- zfcp_hba_dbf_event_fsf_response(fsf_req);
-
- if (fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED) {
- fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR |
- ZFCP_STATUS_FSFREQ_RETRY; /* only for SCSI cmnds. */
- goto skip_protstatus;
- }
-
- /* evaluate FSF Protocol Status */
- switch (qtcb->prefix.prot_status) {
-
- case FSF_PROT_GOOD:
- case FSF_PROT_FSF_STATUS_PRESENTED:
- break;
-
- case FSF_PROT_QTCB_VERSION_ERROR:
- dev_err(&adapter->ccw_device->dev,
- "The QTCB version requested by zfcp (0x%x) is not "
- "supported by the FCP adapter (lowest supported 0x%x, "
- "highest supported 0x%x).\n",
- ZFCP_QTCB_VERSION, prot_status_qual->word[0],
- prot_status_qual->word[1]);
- zfcp_erp_adapter_shutdown(adapter, 0, 117, fsf_req);
- fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
- break;
-
- case FSF_PROT_SEQ_NUMB_ERROR:
- zfcp_erp_adapter_reopen(adapter, 0, 98, fsf_req);
- fsf_req->status |= ZFCP_STATUS_FSFREQ_RETRY;
- fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
- break;
-
- case FSF_PROT_UNSUPP_QTCB_TYPE:
- dev_err(&adapter->ccw_device->dev,
- "Packet header type used by the device driver is "
- "incompatible with that used on the adapter.\n");
- zfcp_erp_adapter_shutdown(adapter, 0, 118, fsf_req);
- fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
- break;
-
- case FSF_PROT_HOST_CONNECTION_INITIALIZING:
- fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
- atomic_set_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
- &(adapter->status));
- break;
-
- case FSF_PROT_DUPLICATE_REQUEST_ID:
- dev_err(&adapter->ccw_device->dev,
- "The request identifier 0x%Lx is ambiguous.\n",
- (unsigned long long)qtcb->bottom.support.req_handle);
- zfcp_erp_adapter_shutdown(adapter, 0, 78, fsf_req);
- fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
- break;
-
- case FSF_PROT_LINK_DOWN:
- zfcp_fsf_link_down_info_eval(fsf_req, 37,
- &prot_status_qual->link_down_info);
- /* FIXME: reopening adapter now? better wait for link up */
- zfcp_erp_adapter_reopen(adapter, 0, 79, fsf_req);
- fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
- break;
-
- case FSF_PROT_REEST_QUEUE:
- /* All ports should be marked as ready to run again */
- zfcp_erp_modify_adapter_status(adapter, 28, NULL,
- ZFCP_STATUS_COMMON_RUNNING,
- ZFCP_SET);
- zfcp_erp_adapter_reopen(adapter,
- ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED
- | ZFCP_STATUS_COMMON_ERP_FAILED,
- 99, fsf_req);
- fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
- break;
-
- case FSF_PROT_ERROR_STATE:
- zfcp_erp_adapter_reopen(adapter, 0, 100, fsf_req);
- fsf_req->status |= ZFCP_STATUS_FSFREQ_RETRY;
- fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
- break;
-
- default:
- dev_err(&adapter->ccw_device->dev,
- "Transfer protocol status information"
- "provided by the adapter (0x%x) "
- "is not compatible with the device driver.\n",
- qtcb->prefix.prot_status);
- zfcp_erp_adapter_shutdown(adapter, 0, 119, fsf_req);
- fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
- }
-
- skip_protstatus:
- /*
- * always call specific handlers to give them a chance to do
- * something meaningful even in error cases
- */
- zfcp_fsf_fsfstatus_eval(fsf_req);
- return retval;
-}
-
-/*
- * function: zfcp_fsf_fsfstatus_eval
- *
- * purpose: evaluates FSF status of completed FSF request
- * and acts accordingly
- *
- * returns:
- */
-static int
-zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *fsf_req)
-{
- int retval = 0;
-
- if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
- goto skip_fsfstatus;
- }
-
- /* evaluate FSF Status */
- switch (fsf_req->qtcb->header.fsf_status) {
- case FSF_UNKNOWN_COMMAND:
- dev_err(&fsf_req->adapter->ccw_device->dev,
- "Command issued by the device driver (0x%x) is "
- "not known by the adapter.\n",
- fsf_req->qtcb->header.fsf_command);
- zfcp_erp_adapter_shutdown(fsf_req->adapter, 0, 120, fsf_req);
- fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
- break;
-
- case FSF_ADAPTER_STATUS_AVAILABLE:
- zfcp_fsf_fsfstatus_qual_eval(fsf_req);
- break;
- }
-
- skip_fsfstatus:
- /*
- * always call specific handlers to give them a chance to do
- * something meaningful even in error cases
- */
- zfcp_fsf_req_dispatch(fsf_req);
+ struct fsf_status_read_buffer *sr_buf = req->data;
+ struct zfcp_adapter *adapter = req->adapter;
+ struct zfcp_port *port;
+ int d_id = sr_buf->d_id & ZFCP_DID_MASK;
+ unsigned long flags;
- return retval;
+ read_lock_irqsave(&zfcp_data.config_lock, flags);
+ list_for_each_entry(port, &adapter->port_list_head, list)
+ if (port->d_id == d_id) {
+ read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+ switch (sr_buf->status_subtype) {
+ case FSF_STATUS_READ_SUB_CLOSE_PHYS_PORT:
+ zfcp_erp_port_reopen(port, 0, 101, req);
+ break;
+ case FSF_STATUS_READ_SUB_ERROR_PORT:
+ zfcp_erp_port_shutdown(port, 0, 122, req);
+ break;
+ }
+ return;
+ }
+ read_unlock_irqrestore(&zfcp_data.config_lock, flags);
}
-/*
- * function: zfcp_fsf_fsfstatus_qual_eval
- *
- * purpose: evaluates FSF status-qualifier of completed FSF request
- * and acts accordingly
- *
- * returns:
- */
-static int
-zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *fsf_req)
+static void zfcp_fsf_bit_error_threshold(struct zfcp_fsf_req *req)
{
- int retval = 0;
-
- switch (fsf_req->qtcb->header.fsf_status_qual.word[0]) {
- case FSF_SQ_FCP_RSP_AVAILABLE:
- break;
- case FSF_SQ_RETRY_IF_POSSIBLE:
- /* The SCSI-stack may now issue retries or escalate */
- fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
- break;
- case FSF_SQ_COMMAND_ABORTED:
- /* Carry the aborted state on to upper layer */
- fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTED;
- fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
- break;
- case FSF_SQ_NO_RECOM:
- dev_err(&fsf_req->adapter->ccw_device->dev,
- "No recommendation could be given for a "
- "problem on the adapter.\n");
- zfcp_erp_adapter_shutdown(fsf_req->adapter, 0, 121, fsf_req);
- fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
- break;
- case FSF_SQ_ULP_PROGRAMMING_ERROR:
- fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
- break;
- case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
- case FSF_SQ_NO_RETRY_POSSIBLE:
- case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
- /* dealt with in the respective functions */
- break;
- default:
- fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
- break;
- }
+ struct zfcp_adapter *adapter = req->adapter;
+ struct fsf_status_read_buffer *sr_buf = req->data;
+ struct fsf_bit_error_payload *err = &sr_buf->payload.bit_error;
- return retval;
+ dev_warn(&adapter->ccw_device->dev,
+ "Warning: bit error threshold data "
+ "received for the adapter: "
+ "link failures = %i, loss of sync errors = %i, "
+ "loss of signal errors = %i, "
+ "primitive sequence errors = %i, "
+ "invalid transmission word errors = %i, "
+ "CRC errors = %i).\n",
+ err->link_failure_error_count,
+ err->loss_of_sync_error_count,
+ err->loss_of_signal_error_count,
+ err->primitive_sequence_error_count,
+ err->invalid_transmission_word_error_count,
+ err->crc_error_count);
+ dev_warn(&adapter->ccw_device->dev,
+ "Additional bit error threshold data of the adapter: "
+ "primitive sequence event time-outs = %i, "
+ "elastic buffer overrun errors = %i, "
+ "advertised receive buffer-to-buffer credit = %i, "
+ "current receice buffer-to-buffer credit = %i, "
+ "advertised transmit buffer-to-buffer credit = %i, "
+ "current transmit buffer-to-buffer credit = %i).\n",
+ err->primitive_sequence_event_timeout_count,
+ err->elastic_buffer_overrun_error_count,
+ err->advertised_receive_b2b_credit,
+ err->current_receive_b2b_credit,
+ err->advertised_transmit_b2b_credit,
+ err->current_transmit_b2b_credit);
}
-/**
- * zfcp_fsf_link_down_info_eval - evaluate link down information block
- */
-static void
-zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *fsf_req, u8 id,
- struct fsf_link_down_info *link_down)
+static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req, u8 id,
+ struct fsf_link_down_info *link_down)
{
- struct zfcp_adapter *adapter = fsf_req->adapter;
+ struct zfcp_adapter *adapter = req->adapter;
- if (atomic_test_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
- &adapter->status))
+ if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED)
return;
atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status);
- if (link_down == NULL)
+ if (!link_down)
goto out;
switch (link_down->error_code) {
case FSF_PSQ_LINK_NO_LIGHT:
- dev_warn(&fsf_req->adapter->ccw_device->dev,
- "The local link is down: "
- "no light detected.\n");
+ dev_warn(&req->adapter->ccw_device->dev,
+ "The local link is down: no light detected.\n");
break;
case FSF_PSQ_LINK_WRAP_PLUG:
- dev_warn(&fsf_req->adapter->ccw_device->dev,
- "The local link is down: "
- "wrap plug detected.\n");
+ dev_warn(&req->adapter->ccw_device->dev,
+ "The local link is down: wrap plug detected.\n");
break;
case FSF_PSQ_LINK_NO_FCP:
- dev_warn(&fsf_req->adapter->ccw_device->dev,
+ dev_warn(&req->adapter->ccw_device->dev,
"The local link is down: "
"adjacent node on link does not support FCP.\n");
break;
case FSF_PSQ_LINK_FIRMWARE_UPDATE:
- dev_warn(&fsf_req->adapter->ccw_device->dev,
+ dev_warn(&req->adapter->ccw_device->dev,
"The local link is down: "
"firmware update in progress.\n");
break;
case FSF_PSQ_LINK_INVALID_WWPN:
- dev_warn(&fsf_req->adapter->ccw_device->dev,
+ dev_warn(&req->adapter->ccw_device->dev,
"The local link is down: "
"duplicate or invalid WWPN detected.\n");
break;
case FSF_PSQ_LINK_NO_NPIV_SUPPORT:
- dev_warn(&fsf_req->adapter->ccw_device->dev,
+ dev_warn(&req->adapter->ccw_device->dev,
"The local link is down: "
"no support for NPIV by Fabric.\n");
break;
case FSF_PSQ_LINK_NO_FCP_RESOURCES:
- dev_warn(&fsf_req->adapter->ccw_device->dev,
+ dev_warn(&req->adapter->ccw_device->dev,
"The local link is down: "
"out of resource in FCP daughtercard.\n");
break;
case FSF_PSQ_LINK_NO_FABRIC_RESOURCES:
- dev_warn(&fsf_req->adapter->ccw_device->dev,
+ dev_warn(&req->adapter->ccw_device->dev,
"The local link is down: "
"out of resource in Fabric.\n");
break;
case FSF_PSQ_LINK_FABRIC_LOGIN_UNABLE:
- dev_warn(&fsf_req->adapter->ccw_device->dev,
+ dev_warn(&req->adapter->ccw_device->dev,
"The local link is down: "
"unable to login to Fabric.\n");
break;
case FSF_PSQ_LINK_WWPN_ASSIGNMENT_CORRUPTED:
- dev_warn(&fsf_req->adapter->ccw_device->dev,
+ dev_warn(&req->adapter->ccw_device->dev,
"WWPN assignment file corrupted on adapter.\n");
break;
case FSF_PSQ_LINK_MODE_TABLE_CURRUPTED:
- dev_warn(&fsf_req->adapter->ccw_device->dev,
+ dev_warn(&req->adapter->ccw_device->dev,
"Mode table corrupted on adapter.\n");
break;
case FSF_PSQ_LINK_NO_WWPN_ASSIGNMENT:
- dev_warn(&fsf_req->adapter->ccw_device->dev,
+ dev_warn(&req->adapter->ccw_device->dev,
"No WWPN for assignment table on adapter.\n");
break;
default:
- dev_warn(&fsf_req->adapter->ccw_device->dev,
+ dev_warn(&req->adapter->ccw_device->dev,
"The local link to adapter is down.\n");
}
+out:
+ zfcp_erp_adapter_failed(adapter, id, req);
+}
+
+static void zfcp_fsf_status_read_link_down(struct zfcp_fsf_req *req)
+{
+ struct zfcp_adapter *adapter = req->adapter;
+ struct fsf_status_read_buffer *sr_buf = req->data;
+ struct fsf_link_down_info *ldi =
+ (struct fsf_link_down_info *) &sr_buf->payload;
- out:
- zfcp_erp_adapter_failed(adapter, id, fsf_req);
+ switch (sr_buf->status_subtype) {
+ case FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK:
+ dev_warn(&adapter->ccw_device->dev,
+ "Physical link is down.\n");
+ zfcp_fsf_link_down_info_eval(req, 38, ldi);
+ break;
+ case FSF_STATUS_READ_SUB_FDISC_FAILED:
+ dev_warn(&adapter->ccw_device->dev,
+ "Local link is down "
+ "due to failed FDISC login.\n");
+ zfcp_fsf_link_down_info_eval(req, 39, ldi);
+ break;
+ case FSF_STATUS_READ_SUB_FIRMWARE_UPDATE:
+ dev_warn(&adapter->ccw_device->dev,
+ "Local link is down "
+ "due to firmware update on adapter.\n");
+ zfcp_fsf_link_down_info_eval(req, 40, NULL);
+ };
}
-/*
- * function: zfcp_fsf_req_dispatch
- *
- * purpose: calls the appropriate command specific handler
- *
- * returns:
- */
-static int
-zfcp_fsf_req_dispatch(struct zfcp_fsf_req *fsf_req)
+static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req)
{
- struct zfcp_erp_action *erp_action = fsf_req->erp_action;
- int retval = 0;
+ struct zfcp_adapter *adapter = req->adapter;
+ struct fsf_status_read_buffer *sr_buf = req->data;
+ if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED) {
+ zfcp_hba_dbf_event_fsf_unsol("dism", adapter, sr_buf);
+ mempool_free(sr_buf, adapter->pool.data_status_read);
+ zfcp_fsf_req_free(req);
+ return;
+ }
- switch (fsf_req->fsf_command) {
+ zfcp_hba_dbf_event_fsf_unsol("read", adapter, sr_buf);
- case FSF_QTCB_FCP_CMND:
- zfcp_fsf_send_fcp_command_handler(fsf_req);
+ switch (sr_buf->status_type) {
+ case FSF_STATUS_READ_PORT_CLOSED:
+ zfcp_fsf_status_read_port_closed(req);
break;
-
- case FSF_QTCB_ABORT_FCP_CMND:
- zfcp_fsf_abort_fcp_command_handler(fsf_req);
+ case FSF_STATUS_READ_INCOMING_ELS:
+ zfcp_fc_incoming_els(req);
break;
-
- case FSF_QTCB_SEND_GENERIC:
- zfcp_fsf_send_ct_handler(fsf_req);
+ case FSF_STATUS_READ_SENSE_DATA_AVAIL:
break;
-
- case FSF_QTCB_OPEN_PORT_WITH_DID:
- zfcp_fsf_open_port_handler(fsf_req);
+ case FSF_STATUS_READ_BIT_ERROR_THRESHOLD:
+ zfcp_fsf_bit_error_threshold(req);
break;
-
- case FSF_QTCB_OPEN_LUN:
- zfcp_fsf_open_unit_handler(fsf_req);
+ case FSF_STATUS_READ_LINK_DOWN:
+ zfcp_fsf_status_read_link_down(req);
break;
-
- case FSF_QTCB_CLOSE_LUN:
- zfcp_fsf_close_unit_handler(fsf_req);
+ case FSF_STATUS_READ_LINK_UP:
+ dev_info(&adapter->ccw_device->dev,
+ "Local link was replugged.\n");
+ /* All ports should be marked as ready to run again */
+ zfcp_erp_modify_adapter_status(adapter, 30, NULL,
+ ZFCP_STATUS_COMMON_RUNNING,
+ ZFCP_SET);
+ zfcp_erp_adapter_reopen(adapter,
+ ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
+ ZFCP_STATUS_COMMON_ERP_FAILED,
+ 102, req);
break;
-
- case FSF_QTCB_CLOSE_PORT:
- zfcp_fsf_close_port_handler(fsf_req);
+ case FSF_STATUS_READ_NOTIFICATION_LOST:
+ if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_ACT_UPDATED)
+ zfcp_erp_adapter_access_changed(adapter, 135, req);
+ if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_INCOMING_ELS)
+ schedule_work(&adapter->scan_work);
break;
-
- case FSF_QTCB_CLOSE_PHYSICAL_PORT:
- zfcp_fsf_close_physical_port_handler(fsf_req);
+ case FSF_STATUS_READ_CFDC_UPDATED:
+ zfcp_erp_adapter_access_changed(adapter, 136, req);
break;
-
- case FSF_QTCB_EXCHANGE_CONFIG_DATA:
- zfcp_fsf_exchange_config_data_handler(fsf_req);
+ case FSF_STATUS_READ_FEATURE_UPDATE_ALERT:
+ adapter->adapter_features = sr_buf->payload.word[0];
break;
+ }
- case FSF_QTCB_EXCHANGE_PORT_DATA:
- zfcp_fsf_exchange_port_data_handler(fsf_req);
- break;
+ mempool_free(sr_buf, adapter->pool.data_status_read);
+ zfcp_fsf_req_free(req);
- case FSF_QTCB_SEND_ELS:
- zfcp_fsf_send_els_handler(fsf_req);
- break;
+ atomic_inc(&adapter->stat_miss);
+ schedule_work(&adapter->stat_work);
+}
- case FSF_QTCB_DOWNLOAD_CONTROL_FILE:
- zfcp_fsf_control_file_handler(fsf_req);
+static void zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *req)
+{
+ switch (req->qtcb->header.fsf_status_qual.word[0]) {
+ case FSF_SQ_FCP_RSP_AVAILABLE:
+ case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
+ case FSF_SQ_NO_RETRY_POSSIBLE:
+ case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
+ return;
+ case FSF_SQ_COMMAND_ABORTED:
+ req->status |= ZFCP_STATUS_FSFREQ_ABORTED;
+ break;
+ case FSF_SQ_NO_RECOM:
+ dev_err(&req->adapter->ccw_device->dev,
+ "No recommendation could be given for a "
+ "problem on the adapter.\n");
+ zfcp_erp_adapter_shutdown(req->adapter, 0, 121, req);
break;
+ }
+ /* all non-return stats set FSFREQ_ERROR*/
+ req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+}
- case FSF_QTCB_UPLOAD_CONTROL_FILE:
- zfcp_fsf_control_file_handler(fsf_req);
+static void zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *req)
+{
+ if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR))
+ return;
+
+ switch (req->qtcb->header.fsf_status) {
+ case FSF_UNKNOWN_COMMAND:
+ dev_err(&req->adapter->ccw_device->dev,
+ "Command issued by the device driver (0x%x) is "
+ "not known by the adapter.\n",
+ req->qtcb->header.fsf_command);
+ zfcp_erp_adapter_shutdown(req->adapter, 0, 120, req);
+ req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+ break;
+ case FSF_ADAPTER_STATUS_AVAILABLE:
+ zfcp_fsf_fsfstatus_qual_eval(req);
break;
}
+}
- if (!erp_action)
- return retval;
+static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req)
+{
+ struct zfcp_adapter *adapter = req->adapter;
+ struct fsf_qtcb *qtcb = req->qtcb;
+ union fsf_prot_status_qual *psq = &qtcb->prefix.prot_status_qual;
- zfcp_erp_async_handler(erp_action, 0);
+ zfcp_hba_dbf_event_fsf_response(req);
- return retval;
+ if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED) {
+ req->status |= ZFCP_STATUS_FSFREQ_ERROR |
+ ZFCP_STATUS_FSFREQ_RETRY; /* only for SCSI cmnds. */
+ return;
+ }
+
+ switch (qtcb->prefix.prot_status) {
+ case FSF_PROT_GOOD:
+ case FSF_PROT_FSF_STATUS_PRESENTED:
+ return;
+ case FSF_PROT_QTCB_VERSION_ERROR:
+ dev_err(&adapter->ccw_device->dev,
+ "The QTCB version requested by zfcp (0x%x) is not "
+ "supported by the FCP adapter (lowest supported "
+ "0x%x, highest supported 0x%x).\n",
+ FSF_QTCB_CURRENT_VERSION, psq->word[0],
+ psq->word[1]);
+ zfcp_erp_adapter_shutdown(adapter, 0, 117, req);
+ break;
+ case FSF_PROT_ERROR_STATE:
+ case FSF_PROT_SEQ_NUMB_ERROR:
+ zfcp_erp_adapter_reopen(adapter, 0, 98, req);
+ req->status |= ZFCP_STATUS_FSFREQ_RETRY;
+ break;
+ case FSF_PROT_UNSUPP_QTCB_TYPE:
+ dev_err(&adapter->ccw_device->dev,
+ "Packet header type used by the device driver is "
+ "incompatible with that used on the adapter.\n");
+ zfcp_erp_adapter_shutdown(adapter, 0, 118, req);
+ break;
+ case FSF_PROT_HOST_CONNECTION_INITIALIZING:
+ atomic_set_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
+ &adapter->status);
+ break;
+ case FSF_PROT_DUPLICATE_REQUEST_ID:
+ dev_err(&adapter->ccw_device->dev,
+ "The request identifier 0x%Lx is ambiguous.\n",
+ (unsigned long long)qtcb->bottom.support.req_handle);
+ zfcp_erp_adapter_shutdown(adapter, 0, 78, req);
+ break;
+ case FSF_PROT_LINK_DOWN:
+ zfcp_fsf_link_down_info_eval(req, 37, &psq->link_down_info);
+ /* FIXME: reopening adapter now? better wait for link up */
+ zfcp_erp_adapter_reopen(adapter, 0, 79, req);
+ break;
+ case FSF_PROT_REEST_QUEUE:
+ /* All ports should be marked as ready to run again */
+ zfcp_erp_modify_adapter_status(adapter, 28, NULL,
+ ZFCP_STATUS_COMMON_RUNNING,
+ ZFCP_SET);
+ zfcp_erp_adapter_reopen(adapter,
+ ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
+ ZFCP_STATUS_COMMON_ERP_FAILED, 99, req);
+ break;
+ default:
+ dev_err(&adapter->ccw_device->dev,
+ "Transfer protocol status information"
+ "provided by the adapter (0x%x) "
+ "is not compatible with the device driver.\n",
+ qtcb->prefix.prot_status);
+ zfcp_erp_adapter_shutdown(adapter, 0, 119, req);
+ }
+ req->status |= ZFCP_STATUS_FSFREQ_ERROR;
}
-/*
- * function: zfcp_fsf_status_read
- *
- * purpose: initiates a Status Read command at the specified adapter
+/**
+ * zfcp_fsf_req_complete - process completion of a FSF request
+ * @fsf_req: The FSF request that has been completed.
*
- * returns:
+ * When a request has been completed either from the FCP adapter,
+ * or it has been dismissed due to a queue shutdown, this function
+ * is called to process the completion status and trigger further
+ * events related to the FSF request.
*/
-int
-zfcp_fsf_status_read(struct zfcp_adapter *adapter, int req_flags)
+void zfcp_fsf_req_complete(struct zfcp_fsf_req *req)
{
- struct zfcp_fsf_req *fsf_req;
- struct fsf_status_read_buffer *status_buffer;
- unsigned long lock_flags;
- volatile struct qdio_buffer_element *sbale;
- int retval;
-
- /* setup new FSF request */
- retval = zfcp_fsf_req_create(adapter, FSF_QTCB_UNSOLICITED_STATUS,
- req_flags | ZFCP_REQ_NO_QTCB,
- adapter->pool.fsf_req_status_read,
- &lock_flags, &fsf_req);
- if (retval < 0)
- goto failed_req_create;
-
- sbale = zfcp_qdio_sbale_req(fsf_req);
- sbale[0].flags |= SBAL_FLAGS0_TYPE_STATUS;
- sbale[2].flags |= SBAL_FLAGS_LAST_ENTRY;
- fsf_req->sbale_curr = 2;
-
- retval = -ENOMEM;
- status_buffer =
- mempool_alloc(adapter->pool.data_status_read, GFP_ATOMIC);
- if (!status_buffer)
- goto failed_buf;
- memset(status_buffer, 0, sizeof (struct fsf_status_read_buffer));
- fsf_req->data = (unsigned long) status_buffer;
-
- /* insert pointer to respective buffer */
- sbale = zfcp_qdio_sbale_curr(fsf_req);
- sbale->addr = (void *) status_buffer;
- sbale->length = sizeof(struct fsf_status_read_buffer);
-
- retval = zfcp_fsf_req_send(fsf_req);
- if (retval)
- goto failed_req_send;
+ if (unlikely(req->fsf_command == FSF_QTCB_UNSOLICITED_STATUS)) {
+ zfcp_fsf_status_read_handler(req);
+ return;
+ }
- goto out;
+ del_timer(&req->timer);
+ zfcp_fsf_protstatus_eval(req);
+ zfcp_fsf_fsfstatus_eval(req);
+ req->handler(req);
- failed_req_send:
- mempool_free(status_buffer, adapter->pool.data_status_read);
+ if (req->erp_action)
+ zfcp_erp_async_handler(req->erp_action, 0);
+ req->status |= ZFCP_STATUS_FSFREQ_COMPLETED;
- failed_buf:
- zfcp_fsf_req_free(fsf_req);
- failed_req_create:
- zfcp_hba_dbf_event_fsf_unsol("fail", adapter, NULL);
- out:
- write_unlock_irqrestore(&adapter->req_q.lock, lock_flags);
- return retval;
+ if (likely(req->status & ZFCP_STATUS_FSFREQ_CLEANUP))
+ zfcp_fsf_req_free(req);
+ else
+ /* notify initiator waiting for the requests completion */
+ /*
+ * 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(&req->completion_wq);
}
-static int
-zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *fsf_req)
+static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req)
{
- struct fsf_status_read_buffer *status_buffer;
- struct zfcp_adapter *adapter;
- struct zfcp_port *port;
- unsigned long flags;
+ struct fsf_qtcb_bottom_config *bottom;
+ struct zfcp_adapter *adapter = req->adapter;
+ struct Scsi_Host *shost = adapter->scsi_host;
- status_buffer = (struct fsf_status_read_buffer *) fsf_req->data;
- adapter = fsf_req->adapter;
+ bottom = &req->qtcb->bottom.config;
- read_lock_irqsave(&zfcp_data.config_lock, flags);
- list_for_each_entry(port, &adapter->port_list_head, list)
- if (port->d_id == (status_buffer->d_id & ZFCP_DID_MASK))
- break;
- read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+ if (req->data)
+ memcpy(req->data, bottom, sizeof(*bottom));
- if (!port || (port->d_id != (status_buffer->d_id & ZFCP_DID_MASK)))
- goto out;
+ fc_host_node_name(shost) = bottom->nport_serv_param.wwnn;
+ fc_host_port_name(shost) = bottom->nport_serv_param.wwpn;
+ fc_host_port_id(shost) = bottom->s_id & ZFCP_DID_MASK;
+ fc_host_speed(shost) = bottom->fc_link_speed;
+ fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3;
- switch (status_buffer->status_subtype) {
+ adapter->hydra_version = bottom->adapter_type;
+ adapter->timer_ticks = bottom->timer_interval;
- case FSF_STATUS_READ_SUB_CLOSE_PHYS_PORT:
- zfcp_erp_port_reopen(port, 0, 101, fsf_req);
- break;
+ if (fc_host_permanent_port_name(shost) == -1)
+ fc_host_permanent_port_name(shost) = fc_host_port_name(shost);
- case FSF_STATUS_READ_SUB_ERROR_PORT:
- zfcp_erp_port_shutdown(port, 0, 122, fsf_req);
- break;
+ switch (bottom->fc_topology) {
+ case FSF_TOPO_P2P:
+ adapter->peer_d_id = bottom->peer_d_id & ZFCP_DID_MASK;
+ adapter->peer_wwpn = bottom->plogi_payload.wwpn;
+ adapter->peer_wwnn = bottom->plogi_payload.wwnn;
+ fc_host_port_type(shost) = FC_PORTTYPE_PTP;
+ if (req->erp_action)
+ dev_info(&adapter->ccw_device->dev,
+ "Point-to-Point fibrechannel "
+ "configuration detected.\n");
+ break;
+ case FSF_TOPO_FABRIC:
+ fc_host_port_type(shost) = FC_PORTTYPE_NPORT;
+ if (req->erp_action)
+ dev_info(&adapter->ccw_device->dev,
+ "Switched fabric fibrechannel "
+ "network detected.\n");
+ break;
+ case FSF_TOPO_AL:
+ fc_host_port_type(shost) = FC_PORTTYPE_NLPORT;
+ dev_err(&adapter->ccw_device->dev,
+ "Unsupported arbitrated loop fibre