summaryrefslogtreecommitdiff
path: root/drivers/s390
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@g5.osdl.org>2005-09-20 19:50:49 +0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-09-20 19:50:49 +0400
commit9600c11ba3602be161cd376f1460f3de561fc299 (patch)
treed071c2427a8f7ad601aec6d8ae76b0f61410becf /drivers/s390
parent676d55ae30ea3b688f0386f70553489f25f24d55 (diff)
parent13e1e1f08c1c098c7574c1fa72bd8c67792dc89b (diff)
downloadlinux-9600c11ba3602be161cd376f1460f3de561fc299.tar.xz
Merge master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-for-linus-2.6
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/scsi/Makefile2
-rw-r--r--drivers/s390/scsi/zfcp_aux.c184
-rw-r--r--drivers/s390/scsi/zfcp_ccw.c10
-rw-r--r--drivers/s390/scsi/zfcp_dbf.c995
-rw-r--r--drivers/s390/scsi/zfcp_def.h307
-rw-r--r--drivers/s390/scsi/zfcp_erp.c135
-rw-r--r--drivers/s390/scsi/zfcp_ext.h30
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c769
-rw-r--r--drivers/s390/scsi/zfcp_fsf.h54
-rw-r--r--drivers/s390/scsi/zfcp_qdio.c30
-rw-r--r--drivers/s390/scsi/zfcp_scsi.c297
-rw-r--r--drivers/s390/scsi/zfcp_sysfs_adapter.c14
12 files changed, 1822 insertions, 1005 deletions
diff --git a/drivers/s390/scsi/Makefile b/drivers/s390/scsi/Makefile
index fc145307a7d4..d6a78f1a2f16 100644
--- a/drivers/s390/scsi/Makefile
+++ b/drivers/s390/scsi/Makefile
@@ -3,7 +3,7 @@
#
zfcp-objs := zfcp_aux.o zfcp_ccw.o zfcp_scsi.o zfcp_erp.o zfcp_qdio.o \
- zfcp_fsf.o zfcp_sysfs_adapter.o zfcp_sysfs_port.o \
+ zfcp_fsf.o zfcp_dbf.o zfcp_sysfs_adapter.o zfcp_sysfs_port.o \
zfcp_sysfs_unit.o zfcp_sysfs_driver.o
obj-$(CONFIG_ZFCP) += zfcp.o
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index bfe3ba73bc0f..0b5087f7cabc 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -122,95 +122,6 @@ _zfcp_hex_dump(char *addr, int count)
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_OTHER
-static inline int
-zfcp_fsf_req_is_scsi_cmnd(struct zfcp_fsf_req *fsf_req)
-{
- return ((fsf_req->fsf_command == FSF_QTCB_FCP_CMND) &&
- !(fsf_req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT));
-}
-
-void
-zfcp_cmd_dbf_event_fsf(const char *text, struct zfcp_fsf_req *fsf_req,
- void *add_data, int add_length)
-{
- struct zfcp_adapter *adapter = fsf_req->adapter;
- struct scsi_cmnd *scsi_cmnd;
- int level = 3;
- int i;
- unsigned long flags;
-
- spin_lock_irqsave(&adapter->dbf_lock, flags);
- if (zfcp_fsf_req_is_scsi_cmnd(fsf_req)) {
- scsi_cmnd = fsf_req->data.send_fcp_command_task.scsi_cmnd;
- debug_text_event(adapter->cmd_dbf, level, "fsferror");
- debug_text_event(adapter->cmd_dbf, level, text);
- debug_event(adapter->cmd_dbf, level, &fsf_req,
- sizeof (unsigned long));
- debug_event(adapter->cmd_dbf, level, &fsf_req->seq_no,
- sizeof (u32));
- debug_event(adapter->cmd_dbf, level, &scsi_cmnd,
- sizeof (unsigned long));
- debug_event(adapter->cmd_dbf, level, &scsi_cmnd->cmnd,
- min(ZFCP_CMD_DBF_LENGTH, (int)scsi_cmnd->cmd_len));
- for (i = 0; i < add_length; i += ZFCP_CMD_DBF_LENGTH)
- debug_event(adapter->cmd_dbf,
- level,
- (char *) add_data + i,
- min(ZFCP_CMD_DBF_LENGTH, add_length - i));
- }
- spin_unlock_irqrestore(&adapter->dbf_lock, flags);
-}
-
-/* XXX additionally log unit if available */
-/* ---> introduce new parameter for unit, see 2.4 code */
-void
-zfcp_cmd_dbf_event_scsi(const char *text, struct scsi_cmnd *scsi_cmnd)
-{
- struct zfcp_adapter *adapter;
- union zfcp_req_data *req_data;
- struct zfcp_fsf_req *fsf_req;
- int level = ((host_byte(scsi_cmnd->result) != 0) ? 1 : 5);
- unsigned long flags;
-
- adapter = (struct zfcp_adapter *) scsi_cmnd->device->host->hostdata[0];
- req_data = (union zfcp_req_data *) scsi_cmnd->host_scribble;
- fsf_req = (req_data ? req_data->send_fcp_command_task.fsf_req : NULL);
- spin_lock_irqsave(&adapter->dbf_lock, flags);
- debug_text_event(adapter->cmd_dbf, level, "hostbyte");
- debug_text_event(adapter->cmd_dbf, level, text);
- debug_event(adapter->cmd_dbf, level, &scsi_cmnd->result, sizeof (u32));
- debug_event(adapter->cmd_dbf, level, &scsi_cmnd,
- sizeof (unsigned long));
- debug_event(adapter->cmd_dbf, level, &scsi_cmnd->cmnd,
- min(ZFCP_CMD_DBF_LENGTH, (int)scsi_cmnd->cmd_len));
- 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,
- sizeof (u32));
- } else {
- debug_text_event(adapter->cmd_dbf, level, "");
- debug_text_event(adapter->cmd_dbf, level, "");
- }
- spin_unlock_irqrestore(&adapter->dbf_lock, flags);
-}
-
-void
-zfcp_in_els_dbf_event(struct zfcp_adapter *adapter, const char *text,
- struct fsf_status_read_buffer *status_buffer, int length)
-{
- int level = 1;
- int i;
-
- debug_text_event(adapter->in_els_dbf, level, text);
- debug_event(adapter->in_els_dbf, level, &status_buffer->d_id, 8);
- for (i = 0; i < length; i += ZFCP_IN_ELS_DBF_LENGTH)
- debug_event(adapter->in_els_dbf,
- level,
- (char *) status_buffer->payload + i,
- min(ZFCP_IN_ELS_DBF_LENGTH, length - i));
-}
-
/**
* zfcp_device_setup - setup function
* @str: pointer to parameter string
@@ -1017,81 +928,6 @@ zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter)
mempool_destroy(adapter->pool.data_gid_pn);
}
-/**
- * zfcp_adapter_debug_register - registers debug feature for an adapter
- * @adapter: pointer to adapter for which debug features should be registered
- * return: -ENOMEM on error, 0 otherwise
- */
-int
-zfcp_adapter_debug_register(struct zfcp_adapter *adapter)
-{
- char dbf_name[20];
-
- /* debug feature area which records SCSI command failures (hostbyte) */
- spin_lock_init(&adapter->dbf_lock);
-
- sprintf(dbf_name, ZFCP_CMD_DBF_NAME "%s",
- zfcp_get_busid_by_adapter(adapter));
- adapter->cmd_dbf = debug_register(dbf_name, ZFCP_CMD_DBF_INDEX,
- ZFCP_CMD_DBF_AREAS,
- ZFCP_CMD_DBF_LENGTH);
- debug_register_view(adapter->cmd_dbf, &debug_hex_ascii_view);
- debug_set_level(adapter->cmd_dbf, ZFCP_CMD_DBF_LEVEL);
-
- /* debug feature area which records SCSI command aborts */
- sprintf(dbf_name, ZFCP_ABORT_DBF_NAME "%s",
- zfcp_get_busid_by_adapter(adapter));
- adapter->abort_dbf = debug_register(dbf_name, ZFCP_ABORT_DBF_INDEX,
- ZFCP_ABORT_DBF_AREAS,
- ZFCP_ABORT_DBF_LENGTH);
- debug_register_view(adapter->abort_dbf, &debug_hex_ascii_view);
- debug_set_level(adapter->abort_dbf, ZFCP_ABORT_DBF_LEVEL);
-
- /* debug feature area which records incoming ELS commands */
- sprintf(dbf_name, ZFCP_IN_ELS_DBF_NAME "%s",
- zfcp_get_busid_by_adapter(adapter));
- adapter->in_els_dbf = debug_register(dbf_name, ZFCP_IN_ELS_DBF_INDEX,
- ZFCP_IN_ELS_DBF_AREAS,
- ZFCP_IN_ELS_DBF_LENGTH);
- debug_register_view(adapter->in_els_dbf, &debug_hex_ascii_view);
- debug_set_level(adapter->in_els_dbf, ZFCP_IN_ELS_DBF_LEVEL);
-
- /* debug feature area which records erp events */
- sprintf(dbf_name, ZFCP_ERP_DBF_NAME "%s",
- zfcp_get_busid_by_adapter(adapter));
- adapter->erp_dbf = debug_register(dbf_name, ZFCP_ERP_DBF_INDEX,
- ZFCP_ERP_DBF_AREAS,
- ZFCP_ERP_DBF_LENGTH);
- debug_register_view(adapter->erp_dbf, &debug_hex_ascii_view);
- debug_set_level(adapter->erp_dbf, ZFCP_ERP_DBF_LEVEL);
-
- if (!(adapter->cmd_dbf && adapter->abort_dbf &&
- adapter->in_els_dbf && adapter->erp_dbf)) {
- zfcp_adapter_debug_unregister(adapter);
- return -ENOMEM;
- }
-
- return 0;
-
-}
-
-/**
- * zfcp_adapter_debug_unregister - unregisters debug feature for an adapter
- * @adapter: pointer to adapter for which debug features should be unregistered
- */
-void
-zfcp_adapter_debug_unregister(struct zfcp_adapter *adapter)
-{
- debug_unregister(adapter->abort_dbf);
- debug_unregister(adapter->cmd_dbf);
- debug_unregister(adapter->erp_dbf);
- debug_unregister(adapter->in_els_dbf);
- adapter->abort_dbf = NULL;
- adapter->cmd_dbf = NULL;
- adapter->erp_dbf = NULL;
- adapter->in_els_dbf = NULL;
-}
-
void
zfcp_dummy_release(struct device *dev)
{
@@ -1462,10 +1298,6 @@ zfcp_fsf_incoming_els_rscn(struct zfcp_adapter *adapter,
/* see FC-FS */
no_entries = (fcp_rscn_head->payload_len / 4);
- zfcp_in_els_dbf_event(adapter, "##rscn", status_buffer,
- fcp_rscn_head->payload_len);
-
- debug_text_event(adapter->erp_dbf, 1, "unsol_els_rscn:");
for (i = 1; i < no_entries; i++) {
/* skip head and start with 1st element */
fcp_rscn_element++;
@@ -1497,8 +1329,6 @@ zfcp_fsf_incoming_els_rscn(struct zfcp_adapter *adapter,
(ZFCP_STATUS_PORT_DID_DID, &port->status)) {
ZFCP_LOG_INFO("incoming RSCN, trying to open "
"port 0x%016Lx\n", port->wwpn);
- debug_text_event(adapter->erp_dbf, 1,
- "unsol_els_rscnu:");
zfcp_erp_port_reopen(port,
ZFCP_STATUS_COMMON_ERP_FAILED);
continue;
@@ -1524,8 +1354,6 @@ zfcp_fsf_incoming_els_rscn(struct zfcp_adapter *adapter,
*/
ZFCP_LOG_INFO("incoming RSCN, trying to open "
"port 0x%016Lx\n", port->wwpn);
- debug_text_event(adapter->erp_dbf, 1,
- "unsol_els_rscnk:");
zfcp_test_link(port);
}
}
@@ -1541,8 +1369,6 @@ zfcp_fsf_incoming_els_plogi(struct zfcp_adapter *adapter,
struct zfcp_port *port;
unsigned long flags;
- zfcp_in_els_dbf_event(adapter, "##plogi", status_buffer, 28);
-
read_lock_irqsave(&zfcp_data.config_lock, flags);
list_for_each_entry(port, &adapter->port_list_head, list) {
if (port->wwpn == (*(wwn_t *) & els_logi->nport_wwn))
@@ -1556,8 +1382,6 @@ zfcp_fsf_incoming_els_plogi(struct zfcp_adapter *adapter,
status_buffer->d_id,
zfcp_get_busid_by_adapter(adapter));
} else {
- debug_text_event(adapter->erp_dbf, 1, "unsol_els_plogi:");
- debug_event(adapter->erp_dbf, 1, &els_logi->nport_wwn, 8);
zfcp_erp_port_forced_reopen(port, 0);
}
}
@@ -1570,8 +1394,6 @@ zfcp_fsf_incoming_els_logo(struct zfcp_adapter *adapter,
struct zfcp_port *port;
unsigned long flags;
- zfcp_in_els_dbf_event(adapter, "##logo", status_buffer, 16);
-
read_lock_irqsave(&zfcp_data.config_lock, flags);
list_for_each_entry(port, &adapter->port_list_head, list) {
if (port->wwpn == els_logo->nport_wwpn)
@@ -1585,8 +1407,6 @@ zfcp_fsf_incoming_els_logo(struct zfcp_adapter *adapter,
status_buffer->d_id,
zfcp_get_busid_by_adapter(adapter));
} else {
- debug_text_event(adapter->erp_dbf, 1, "unsol_els_logo:");
- debug_event(adapter->erp_dbf, 1, &els_logo->nport_wwpn, 8);
zfcp_erp_port_forced_reopen(port, 0);
}
}
@@ -1595,7 +1415,6 @@ static void
zfcp_fsf_incoming_els_unknown(struct zfcp_adapter *adapter,
struct fsf_status_read_buffer *status_buffer)
{
- zfcp_in_els_dbf_event(adapter, "##undef", status_buffer, 24);
ZFCP_LOG_NORMAL("warning: unknown incoming ELS 0x%08x "
"for adapter %s\n", *(u32 *) (status_buffer->payload),
zfcp_get_busid_by_adapter(adapter));
@@ -1609,10 +1428,11 @@ zfcp_fsf_incoming_els(struct zfcp_fsf_req *fsf_req)
u32 els_type;
struct zfcp_adapter *adapter;
- status_buffer = fsf_req->data.status_read.buffer;
+ status_buffer = (struct fsf_status_read_buffer *) fsf_req->data;
els_type = *(u32 *) (status_buffer->payload);
adapter = fsf_req->adapter;
+ zfcp_san_dbf_event_incoming_els(fsf_req);
if (els_type == LS_PLOGI)
zfcp_fsf_incoming_els_plogi(adapter, status_buffer);
else if (els_type == LS_LOGO)
diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c
index b30abab77da3..0fc46381fc22 100644
--- a/drivers/s390/scsi/zfcp_ccw.c
+++ b/drivers/s390/scsi/zfcp_ccw.c
@@ -202,19 +202,9 @@ static int
zfcp_ccw_set_offline(struct ccw_device *ccw_device)
{
struct zfcp_adapter *adapter;
- struct zfcp_port *port;
- struct fc_rport *rport;
down(&zfcp_data.config_sema);
adapter = dev_get_drvdata(&ccw_device->dev);
- /* might be racy, but we cannot take config_lock due to the fact that
- fc_remote_port_delete might sleep */
- list_for_each_entry(port, &adapter->port_list_head, list)
- if (port->rport) {
- rport = port->rport;
- port->rport = NULL;
- fc_remote_port_delete(rport);
- }
zfcp_erp_adapter_shutdown(adapter, 0);
zfcp_erp_wait(adapter);
zfcp_adapter_scsi_unregister(adapter);
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c
new file mode 100644
index 000000000000..826fb3b00605
--- /dev/null
+++ b/drivers/s390/scsi/zfcp_dbf.c
@@ -0,0 +1,995 @@
+/*
+ *
+ * linux/drivers/s390/scsi/zfcp_dbf.c
+ *
+ * FCP adapter driver for IBM eServer zSeries
+ *
+ * Debugging facilities
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * 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
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define ZFCP_DBF_REVISION "$Revision$"
+
+#include <asm/debug.h>
+#include <linux/ctype.h>
+#include "zfcp_ext.h"
+
+static u32 dbfsize = 4;
+
+module_param(dbfsize, uint, 0400);
+MODULE_PARM_DESC(dbfsize,
+ "number of pages for each debug feature area (default 4)");
+
+#define ZFCP_LOG_AREA ZFCP_LOG_AREA_OTHER
+
+static inline int
+zfcp_dbf_stck(char *out_buf, const char *label, unsigned long long stck)
+{
+ unsigned long long sec;
+ struct timespec xtime;
+ int len = 0;
+
+ stck -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096);
+ sec = stck >> 12;
+ do_div(sec, 1000000);
+ xtime.tv_sec = sec;
+ stck -= (sec * 1000000) << 12;
+ xtime.tv_nsec = ((stck * 1000) >> 12);
+ len += sprintf(out_buf + len, "%-24s%011lu:%06lu\n",
+ label, xtime.tv_sec, xtime.tv_nsec);
+
+ return len;
+}
+
+static int zfcp_dbf_tag(char *out_buf, const char *label, const char *tag)
+{
+ int len = 0, i;
+
+ len += sprintf(out_buf + len, "%-24s", label);
+ for (i = 0; i < ZFCP_DBF_TAG_SIZE; i++)
+ len += sprintf(out_buf + len, "%c", tag[i]);
+ len += sprintf(out_buf + len, "\n");
+
+ return len;
+}
+
+static int
+zfcp_dbf_view(char *out_buf, const char *label, const char *format, ...)
+{
+ va_list arg;
+ int len = 0;
+
+ len += sprintf(out_buf + len, "%-24s", label);
+ va_start(arg, format);
+ len += vsprintf(out_buf + len, format, arg);
+ va_end(arg);
+ len += sprintf(out_buf + len, "\n");
+
+ return len;
+}
+
+static int
+zfcp_dbf_view_dump(char *out_buf, const char *label,
+ char *buffer, int buflen, int offset, int total_size)
+{
+ int len = 0;
+
+ if (offset == 0)
+ len += sprintf(out_buf + len, "%-24s ", label);
+
+ while (buflen--) {
+ if (offset > 0) {
+ if ((offset % 32) == 0)
+ len += sprintf(out_buf + len, "\n%-24c ", ' ');
+ else if ((offset % 4) == 0)
+ len += sprintf(out_buf + len, " ");
+ }
+ len += sprintf(out_buf + len, "%02x", *buffer++);
+ if (++offset == total_size) {
+ len += sprintf(out_buf + len, "\n");
+ break;
+ }
+ }
+
+ if (total_size == 0)
+ len += sprintf(out_buf + len, "\n");
+
+ return len;
+}
+
+static inline int
+zfcp_dbf_view_header(debug_info_t * id, struct debug_view *view, int area,
+ debug_entry_t * entry, char *out_buf)
+{
+ struct zfcp_dbf_dump *dump = (struct zfcp_dbf_dump *)DEBUG_DATA(entry);
+ int len = 0;
+
+ if (strncmp(dump->tag, "dump", ZFCP_DBF_TAG_SIZE) != 0) {
+ len += zfcp_dbf_stck(out_buf + len, "timestamp",
+ entry->id.stck);
+ len += zfcp_dbf_view(out_buf + len, "cpu", "%02i",
+ entry->id.fields.cpuid);
+ } else {
+ len += zfcp_dbf_view_dump(out_buf + len, NULL,
+ dump->data,
+ dump->size,
+ dump->offset, dump->total_size);
+ if ((dump->offset + dump->size) == dump->total_size)
+ len += sprintf(out_buf + len, "\n");
+ }
+
+ return len;
+}
+
+inline void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req)
+{
+ 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;
+ union fsf_status_qual *fsf_status_qual = &qtcb->header.fsf_status_qual;
+ struct scsi_cmnd *scsi_cmnd;
+ struct zfcp_port *port;
+ struct zfcp_unit *unit;
+ struct zfcp_send_els *send_els;
+ struct zfcp_hba_dbf_record *rec = &adapter->hba_dbf_buf;
+ struct zfcp_hba_dbf_record_response *response = &rec->type.response;
+ int level;
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->hba_dbf_lock, flags);
+ memset(rec, 0, sizeof(struct zfcp_hba_dbf_record));
+ strncpy(rec->tag, "resp", ZFCP_DBF_TAG_SIZE);
+
+ if ((qtcb->prefix.prot_status != FSF_PROT_GOOD) &&
+ (qtcb->prefix.prot_status != FSF_PROT_FSF_STATUS_PRESENTED)) {
+ strncpy(rec->tag2, "perr", ZFCP_DBF_TAG_SIZE);
+ level = 1;
+ } else if (qtcb->header.fsf_status != FSF_GOOD) {
+ strncpy(rec->tag2, "ferr", ZFCP_DBF_TAG_SIZE);
+ level = 1;
+ } else if ((fsf_req->fsf_command == FSF_QTCB_OPEN_PORT_WITH_DID) ||
+ (fsf_req->fsf_command == FSF_QTCB_OPEN_LUN)) {
+ strncpy(rec->tag2, "open", ZFCP_DBF_TAG_SIZE);
+ level = 4;
+ } else if ((prot_status_qual->doubleword[0] != 0) ||
+ (prot_status_qual->doubleword[1] != 0) ||
+ (fsf_status_qual->doubleword[0] != 0) ||
+ (fsf_status_qual->doubleword[1] != 0)) {
+ strncpy(rec->tag2, "qual", ZFCP_DBF_TAG_SIZE);
+ level = 3;
+ } else {
+ strncpy(rec->tag2, "norm", ZFCP_DBF_TAG_SIZE);
+ level = 6;
+ }
+
+ response->fsf_command = fsf_req->fsf_command;
+ response->fsf_reqid = (unsigned long)fsf_req;
+ response->fsf_seqno = fsf_req->seq_no;
+ response->fsf_issued = fsf_req->issued;
+ response->fsf_prot_status = qtcb->prefix.prot_status;
+ response->fsf_status = qtcb->header.fsf_status;
+ memcpy(response->fsf_prot_status_qual,
+ prot_status_qual, FSF_PROT_STATUS_QUAL_SIZE);
+ memcpy(response->fsf_status_qual,
+ fsf_status_qual, FSF_STATUS_QUALIFIER_SIZE);
+ response->fsf_req_status = fsf_req->status;
+ response->sbal_first = fsf_req->sbal_first;
+ response->sbal_curr = fsf_req->sbal_curr;
+ response->sbal_last = fsf_req->sbal_last;
+ response->pool = fsf_req->pool != NULL;
+ response->erp_action = (unsigned long)fsf_req->erp_action;
+
+ switch (fsf_req->fsf_command) {
+ case FSF_QTCB_FCP_CMND:
+ if (fsf_req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT)
+ break;
+ scsi_cmnd = (struct scsi_cmnd *)fsf_req->data;
+ if (scsi_cmnd != NULL) {
+ response->data.send_fcp.scsi_cmnd
+ = (unsigned long)scsi_cmnd;
+ response->data.send_fcp.scsi_serial
+ = scsi_cmnd->serial_number;
+ }
+ break;
+
+ case FSF_QTCB_OPEN_PORT_WITH_DID:
+ case FSF_QTCB_CLOSE_PORT:
+ case FSF_QTCB_CLOSE_PHYSICAL_PORT:
+ port = (struct zfcp_port *)fsf_req->data;
+ response->data.port.wwpn = port->wwpn;
+ response->data.port.d_id = port->d_id;
+ response->data.port.port_handle = qtcb->header.port_handle;
+ break;
+
+ case FSF_QTCB_OPEN_LUN:
+ case FSF_QTCB_CLOSE_LUN:
+ unit = (struct zfcp_unit *)fsf_req->data;
+ port = unit->port;
+ response->data.unit.wwpn = port->wwpn;
+ response->data.unit.fcp_lun = unit->fcp_lun;
+ response->data.unit.port_handle = qtcb->header.port_handle;
+ response->data.unit.lun_handle = qtcb->header.lun_handle;
+ break;
+
+ case FSF_QTCB_SEND_ELS:
+ send_els = (struct zfcp_send_els *)fsf_req->data;
+ response->data.send_els.d_id = qtcb->bottom.support.d_id;
+ response->data.send_els.ls_code = send_els->ls_code >> 24;
+ break;
+
+ case FSF_QTCB_ABORT_FCP_CMND:
+ case FSF_QTCB_SEND_GENERIC:
+ case FSF_QTCB_EXCHANGE_CONFIG_DATA:
+ case FSF_QTCB_EXCHANGE_PORT_DATA:
+ case FSF_QTCB_DOWNLOAD_CONTROL_FILE:
+ case FSF_QTCB_UPLOAD_CONTROL_FILE:
+ break;
+ }
+
+ debug_event(adapter->hba_dbf, level,
+ rec, sizeof(struct zfcp_hba_dbf_record));
+ spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags);
+}
+
+inline void
+zfcp_hba_dbf_event_fsf_unsol(const char *tag, struct zfcp_adapter *adapter,
+ struct fsf_status_read_buffer *status_buffer)
+{
+ struct zfcp_hba_dbf_record *rec = &adapter->hba_dbf_buf;
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->hba_dbf_lock, flags);
+ memset(rec, 0, sizeof(struct zfcp_hba_dbf_record));
+ strncpy(rec->tag, "stat", ZFCP_DBF_TAG_SIZE);
+ strncpy(rec->tag2, tag, ZFCP_DBF_TAG_SIZE);
+
+ rec->type.status.failed = adapter->status_read_failed;
+ if (status_buffer != NULL) {
+ rec->type.status.status_type = status_buffer->status_type;
+ rec->type.status.status_subtype = status_buffer->status_subtype;
+ memcpy(&rec->type.status.queue_designator,
+ &status_buffer->queue_designator,
+ sizeof(struct fsf_queue_designator));
+
+ switch (status_buffer->status_type) {
+ case FSF_STATUS_READ_SENSE_DATA_AVAIL:
+ rec->type.status.payload_size =
+ ZFCP_DBF_UNSOL_PAYLOAD_SENSE_DATA_AVAIL;
+ break;
+
+ case FSF_STATUS_READ_BIT_ERROR_THRESHOLD:
+ rec->type.status.payload_size =
+ ZFCP_DBF_UNSOL_PAYLOAD_BIT_ERROR_THRESHOLD;
+ break;
+
+ case FSF_STATUS_READ_LINK_DOWN:
+ switch (status_buffer->status_subtype) {
+ case FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK:
+ case FSF_STATUS_READ_SUB_FDISC_FAILED:
+ rec->type.status.payload_size =
+ sizeof(struct fsf_link_down_info);
+ }
+ break;
+
+ case FSF_STATUS_READ_FEATURE_UPDATE_ALERT:
+ rec->type.status.payload_size =
+ ZFCP_DBF_UNSOL_PAYLOAD_FEATURE_UPDATE_ALERT;
+ break;
+ }
+ memcpy(&rec->type.status.payload,
+ &status_buffer->payload, rec->type.status.payload_size);
+ }
+
+ debug_event(adapter->hba_dbf, 2,
+ rec, sizeof(struct zfcp_hba_dbf_record));
+ spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags);
+}
+
+inline void
+zfcp_hba_dbf_event_qdio(struct zfcp_adapter *adapter, unsigned int status,
+ unsigned int qdio_error, unsigned int siga_error,
+ int sbal_index, int sbal_count)
+{
+ struct zfcp_hba_dbf_record *rec = &adapter->hba_dbf_buf;
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->hba_dbf_lock, flags);
+ memset(rec, 0, sizeof(struct zfcp_hba_dbf_record));
+ strncpy(rec->tag, "qdio", ZFCP_DBF_TAG_SIZE);
+ rec->type.qdio.status = status;
+ rec->type.qdio.qdio_error = qdio_error;
+ rec->type.qdio.siga_error = siga_error;
+ rec->type.qdio.sbal_index = sbal_index;
+ rec->type.qdio.sbal_count = sbal_count;
+ debug_event(adapter->hba_dbf, 0,
+ rec, sizeof(struct zfcp_hba_dbf_record));
+ spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags);
+}
+
+static inline int
+zfcp_hba_dbf_view_response(char *out_buf,
+ struct zfcp_hba_dbf_record_response *rec)
+{
+ int len = 0;
+
+ len += zfcp_dbf_view(out_buf + len, "fsf_command", "0x%08x",
+ rec->fsf_command);
+ len += zfcp_dbf_view(out_buf + len, "fsf_reqid", "0x%0Lx",
+ rec->fsf_reqid);
+ len += zfcp_dbf_view(out_buf + len, "fsf_seqno", "0x%08x",
+ rec->fsf_seqno);
+ len += zfcp_dbf_stck(out_buf + len, "fsf_issued", rec->fsf_issued);
+ len += zfcp_dbf_view(out_buf + len, "fsf_prot_status", "0x%08x",
+ rec->fsf_prot_status);
+ len += zfcp_dbf_view(out_buf + len, "fsf_status", "0x%08x",
+ rec->fsf_status);
+ len += zfcp_dbf_view_dump(out_buf + len, "fsf_prot_status_qual",
+ rec->fsf_prot_status_qual,
+ FSF_PROT_STATUS_QUAL_SIZE,
+ 0, FSF_PROT_STATUS_QUAL_SIZE);
+ len += zfcp_dbf_view_dump(out_buf + len, "fsf_status_qual",
+ rec->fsf_status_qual,
+ FSF_STATUS_QUALIFIER_SIZE,
+ 0, FSF_STATUS_QUALIFIER_SIZE);
+ len += zfcp_dbf_view(out_buf + len, "fsf_req_status", "0x%08x",
+ rec->fsf_req_status);
+ len += zfcp_dbf_view(out_buf + len, "sbal_first", "0x%02x",
+ rec->sbal_first);
+ len += zfcp_dbf_view(out_buf + len, "sbal_curr", "0x%02x",
+ rec->sbal_curr);
+ len += zfcp_dbf_view(out_buf + len, "sbal_last", "0x%02x",
+ rec->sbal_last);
+ len += zfcp_dbf_view(out_buf + len, "pool", "0x%02x", rec->pool);
+
+ switch (rec->fsf_command) {
+ case FSF_QTCB_FCP_CMND:
+ if (rec->fsf_req_status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT)
+ break;
+ len += zfcp_dbf_view(out_buf + len, "scsi_cmnd", "0x%0Lx",
+ rec->data.send_fcp.scsi_cmnd);
+ len += zfcp_dbf_view(out_buf + len, "scsi_serial", "0x%016Lx",
+ rec->data.send_fcp.scsi_serial);
+ break;
+
+ case FSF_QTCB_OPEN_PORT_WITH_DID:
+ case FSF_QTCB_CLOSE_PORT:
+ case FSF_QTCB_CLOSE_PHYSICAL_PORT:
+ len += zfcp_dbf_view(out_buf + len, "wwpn", "0x%016Lx",
+ rec->data.port.wwpn);
+ len += zfcp_dbf_view(out_buf + len, "d_id", "0x%06x",
+ rec->data.port.d_id);
+ len += zfcp_dbf_view(out_buf + len, "port_handle", "0x%08x",
+ rec->data.port.port_handle);
+ break;
+
+ case FSF_QTCB_OPEN_LUN:
+ case FSF_QTCB_CLOSE_LUN:
+ len += zfcp_dbf_view(out_buf + len, "wwpn", "0x%016Lx",
+ rec->data.unit.wwpn);
+ len += zfcp_dbf_view(out_buf + len, "fcp_lun", "0x%016Lx",
+ rec->data.unit.fcp_lun);
+ len += zfcp_dbf_view(out_buf + len, "port_handle", "0x%08x",
+ rec->data.unit.port_handle);
+ len += zfcp_dbf_view(out_buf + len, "lun_handle", "0x%08x",
+ rec->data.unit.lun_handle);
+ break;
+
+ case FSF_QTCB_SEND_ELS:
+ len += zfcp_dbf_view(out_buf + len, "d_id", "0x%06x",
+ rec->data.send_els.d_id);
+ len += zfcp_dbf_view(out_buf + len, "ls_code", "0x%02x",
+ rec->data.send_els.ls_code);
+ break;
+
+ case FSF_QTCB_ABORT_FCP_CMND:
+ case FSF_QTCB_SEND_GENERIC:
+ case FSF_QTCB_EXCHANGE_CONFIG_DATA:
+ case FSF_QTCB_EXCHANGE_PORT_DATA:
+ case FSF_QTCB_DOWNLOAD_CONTROL_FILE:
+ case FSF_QTCB_UPLOAD_CONTROL_FILE:
+ break;
+ }
+
+ return len;
+}
+
+static inline int
+zfcp_hba_dbf_view_status(char *out_buf, struct zfcp_hba_dbf_record_status *rec)
+{
+ int len = 0;
+
+ len += zfcp_dbf_view(out_buf + len, "failed", "0x%02x", rec->failed);
+ len += zfcp_dbf_view(out_buf + len, "status_type", "0x%08x",
+ rec->status_type);
+ len += zfcp_dbf_view(out_buf + len, "status_subtype", "0x%08x",
+ rec->status_subtype);
+ len += zfcp_dbf_view_dump(out_buf + len, "queue_designator",
+ (char *)&rec->queue_designator,
+ sizeof(struct fsf_queue_designator),
+ 0, sizeof(struct fsf_queue_designator));
+ len += zfcp_dbf_view_dump(out_buf + len, "payload",
+ (char *)&rec->payload,
+ rec->payload_size, 0, rec->payload_size);
+
+ return len;
+}
+
+static inline int
+zfcp_hba_dbf_view_qdio(char *out_buf, struct zfcp_hba_dbf_record_qdio *rec)
+{
+ int len = 0;
+
+ len += zfcp_dbf_view(out_buf + len, "status", "0x%08x", rec->status);
+ len += zfcp_dbf_view(out_buf + len, "qdio_error", "0x%08x",
+ rec->qdio_error);
+ len += zfcp_dbf_view(out_buf + len, "siga_error", "0x%08x",
+ rec->siga_error);
+ len += zfcp_dbf_view(out_buf + len, "sbal_index", "0x%02x",
+ rec->sbal_index);
+ len += zfcp_dbf_view(out_buf + len, "sbal_count", "0x%02x",
+ rec->sbal_count);
+
+ return len;
+}
+
+static int
+zfcp_hba_dbf_view_format(debug_info_t * id, struct debug_view *view,
+ char *out_buf, const char *in_buf)
+{
+ struct zfcp_hba_dbf_record *rec = (struct zfcp_hba_dbf_record *)in_buf;
+ int len = 0;
+
+ if (strncmp(rec->tag, "dump", ZFCP_DBF_TAG_SIZE) == 0)
+ return 0;
+
+ len += zfcp_dbf_tag(out_buf + len, "tag", rec->tag);
+ if (isalpha(rec->tag2[0]))
+ len += zfcp_dbf_tag(out_buf + len, "tag2", rec->tag2);
+ if (strncmp(rec->tag, "resp", ZFCP_DBF_TAG_SIZE) == 0)
+ len += zfcp_hba_dbf_view_response(out_buf + len,
+ &rec->type.response);
+ else if (strncmp(rec->tag, "stat", ZFCP_DBF_TAG_SIZE) == 0)
+ len += zfcp_hba_dbf_view_status(out_buf + len,
+ &rec->type.status);
+ else if (strncmp(rec->tag, "qdio", ZFCP_DBF_TAG_SIZE) == 0)
+ len += zfcp_hba_dbf_view_qdio(out_buf + len, &rec->type.qdio);
+
+ len += sprintf(out_buf + len, "\n");
+
+ return len;
+}
+
+struct debug_view zfcp_hba_dbf_view = {
+ "structured",
+ NULL,
+ &zfcp_dbf_view_header,
+ &zfcp_hba_dbf_view_format,
+ NULL,
+ NULL
+};
+
+inline void
+_zfcp_san_dbf_event_common_ct(const char *tag, struct zfcp_fsf_req *fsf_req,
+ u32 s_id, u32 d_id, void *buffer, int buflen)
+{
+ struct zfcp_send_ct *send_ct = (struct zfcp_send_ct *)fsf_req->data;
+ struct zfcp_port *port = send_ct->port;
+ struct zfcp_adapter *adapter = port->adapter;
+ struct ct_hdr *header = (struct ct_hdr *)buffer;
+ struct zfcp_san_dbf_record *rec = &adapter->san_dbf_buf;
+ struct zfcp_san_dbf_record_ct *ct = &rec->type.ct;
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->san_dbf_lock, flags);
+ memset(rec, 0, sizeof(struct zfcp_san_dbf_record));
+ strncpy(rec->tag, tag, ZFCP_DBF_TAG_SIZE);
+ rec->fsf_reqid = (unsigned long)fsf_req;
+ rec->fsf_seqno = fsf_req->seq_no;
+ rec->s_id = s_id;
+ rec->d_id = d_id;
+ if (strncmp(tag, "octc", ZFCP_DBF_TAG_SIZE) == 0) {
+ ct->type.request.cmd_req_code = header->cmd_rsp_code;
+ ct->type.request.revision = header->revision;
+ ct->type.request.gs_type = header->gs_type;
+ ct->type.request.gs_subtype = header->gs_subtype;
+ ct->type.request.options = header->options;
+ ct->type.request.max_res_size = header->max_res_size;
+ } else if (strncmp(tag, "rctc", ZFCP_DBF_TAG_SIZE) == 0) {
+ ct->type.response.cmd_rsp_code = header->cmd_rsp_code;
+ ct->type.response.revision = header->revision;
+ ct->type.response.reason_code = header->reason_code;
+ ct->type.response.reason_code_expl = header->reason_code_expl;
+ ct->type.response.vendor_unique = header->vendor_unique;
+ }
+ ct->payload_size =
+ min(buflen - (int)sizeof(struct ct_hdr), ZFCP_DBF_CT_PAYLOAD);
+ memcpy(ct->payload, buffer + sizeof(struct ct_hdr), ct->payload_size);
+ debug_event(adapter->san_dbf, 3,
+ rec, sizeof(struct zfcp_san_dbf_record));
+ spin_unlock_irqrestore(&adapter->san_dbf_lock, flags);
+}
+
+inline void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req)
+{
+ struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data;
+ struct zfcp_port *port = ct->port;
+ struct zfcp_adapter *adapter = port->adapter;
+
+ _zfcp_san_dbf_event_common_ct("octc", fsf_req,
+ fc_host_port_id(adapter->scsi_host),
+ port->d_id, zfcp_sg_to_address(ct->req),
+ ct->req->length);
+}
+
+inline void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req)
+{
+ struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data;
+ struct zfcp_port *port = ct->port;
+ struct zfcp_adapter *adapter = port->adapter;
+
+ _zfcp_san_dbf_event_common_ct("rctc", fsf_req, port->d_id,
+ fc_host_port_id(adapter->scsi_host),
+ zfcp_sg_to_address(ct->resp),
+ ct->resp->length);
+}
+
+static inline void
+_zfcp_san_dbf_event_common_els(const char *tag, int level,
+ struct zfcp_fsf_req *fsf_req, u32 s_id,
+ u32 d_id, u8 ls_code, void *buffer, int buflen)
+{
+ struct zfcp_adapter *adapter = fsf_req->adapter;
+ struct zfcp_san_dbf_record *rec = &adapter->san_dbf_buf;
+ struct zfcp_dbf_dump *dump = (struct zfcp_dbf_dump *)rec;
+ unsigned long flags;
+ int offset = 0;
+
+ spin_lock_irqsave(&adapter->san_dbf_lock, flags);
+ do {
+ memset(rec, 0, sizeof(struct zfcp_san_dbf_record));
+ if (offset == 0) {
+ strncpy(rec->tag, tag, ZFCP_DBF_TAG_SIZE);
+ rec->fsf_reqid = (unsigned long)fsf_req;
+ rec->fsf_seqno = fsf_req->seq_no;
+ rec->s_id = s_id;
+ rec->d_id = d_id;
+ rec->type.els.ls_code = ls_code;
+ buflen = min(buflen, ZFCP_DBF_ELS_MAX_PAYLOAD);
+ rec->type.els.payload_size = buflen;
+ memcpy(rec->type.els.payload,
+ buffer, min(buflen, ZFCP_DBF_ELS_PAYLOAD));
+ offset += min(buflen, ZFCP_DBF_ELS_PAYLOAD);
+ } else {
+ strncpy(dump->tag, "dump", ZFCP_DBF_TAG_SIZE);
+ dump->total_size = buflen;
+ dump->offset = offset;
+ dump->size = min(buflen - offset,
+ (int)sizeof(struct zfcp_san_dbf_record)
+ - (int)sizeof(struct zfcp_dbf_dump));
+ memcpy(dump->data, buffer + offset, dump->size);
+ offset += dump->size;
+ }
+ debug_event(adapter->san_dbf, level,
+ rec, sizeof(struct zfcp_san_dbf_record));
+ } while (offset < buflen);
+ spin_unlock_irqrestore(&adapter->san_dbf_lock, flags);
+}
+
+inline void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *fsf_req)
+{
+ struct zfcp_send_els *els = (struct zfcp_send_els *)fsf_req->data;
+
+ _zfcp_san_dbf_event_common_els("oels", 2, fsf_req,
+ fc_host_port_id(els->adapter->scsi_host),
+ els->d_id,
+ *(u8 *) zfcp_sg_to_address(els->req),
+ zfcp_sg_to_address(els->req),
+ els->req->length);
+}
+
+inline void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *fsf_req)
+{
+ struct zfcp_send_els *els = (struct zfcp_send_els *)fsf_req->data;
+
+ _zfcp_san_dbf_event_common_els("rels", 2, fsf_req, els->d_id,
+ fc_host_port_id(els->adapter->scsi_host),
+ *(u8 *) zfcp_sg_to_address(els->req),
+ zfcp_sg_to_address(els->resp),
+ els->resp->length);
+}
+
+inline void zfcp_san_dbf_event_incoming_els(struct zfcp_fsf_req *fsf_req)
+{
+ struct zfcp_adapter *adapter = fsf_req->adapter;
+ struct fsf_status_read_buffer *status_buffer =
+ (struct fsf_status_read_buffer *)fsf_req->data;
+ int length = (int)status_buffer->length -
+ (int)((void *)&status_buffer->payload - (void *)status_buffer);
+
+ _zfcp_san_dbf_event_common_els("iels", 1, fsf_req, status_buffer->d_id,
+ fc_host_port_id(adapter->scsi_host),
+ *(u8 *) status_buffer->payload,
+ (void *)status_buffer->payload, length);
+}
+
+static int
+zfcp_san_dbf_view_format(debug_info_t * id, struct debug_view *view,
+ char *out_buf, const char *in_buf)
+{
+ struct zfcp_san_dbf_record *rec = (struct zfcp_san_dbf_record *)in_buf;
+ char *buffer = NULL;
+ int buflen = 0, total = 0;
+ int len = 0;
+
+ if (strncmp(rec->tag, "dump", ZFCP_DBF_TAG_SIZE) == 0)
+ return 0;
+
+ len += zfcp_dbf_tag(out_buf + len, "tag", rec->tag);
+ len += zfcp_dbf_view(out_buf + len, "fsf_reqid", "0x%0Lx",
+ rec->fsf_reqid);
+ len += zfcp_dbf_view(out_buf + len, "fsf_seqno", "0x%08x",
+ rec->fsf_seqno);
+ len += zfcp_dbf_view(out_buf + len, "s_id", "0x%06x", rec->s_id);
+ len += zfcp_dbf_view(out_buf + len, "d_id", "0x%06x", rec->d_id);
+
+ if (strncmp(rec->tag, "octc", ZFCP_DBF_TAG_SIZE) == 0) {
+ len += zfcp_dbf_view(out_buf + len, "cmd_req_code", "0x%04x",
+ rec->type.ct.type.request.cmd_req_code);
+ len += zfcp_dbf_view(out_buf + len, "revision", "0x%02x",
+ rec->type.ct.type.request.revision);
+ len += zfcp_dbf_view(out_buf + len, "gs_type", "0x%02x",
+ rec->type.ct.type.request.gs_type);
+ len += zfcp_dbf_view(out_buf + len, "gs_subtype", "0x%02x",
+ rec->type.ct.type.request.gs_subtype);
+ len += zfcp_dbf_view(out_buf + len, "options", "0x%02x",
+ rec->type.ct.type.request.options);
+ len += zfcp_dbf_view(out_buf + len, "max_res_size", "0x%04x",
+ rec->type.ct.type.request.max_res_size);
+ total = rec->type.ct.payload_size;
+ buffer = rec->type.ct.payload;
+ buflen = min(total, ZFCP_DBF_CT_PAYLOAD);
+ } else if (strncmp(rec->tag, "rctc", ZFCP_DBF_TAG_SIZE) == 0) {
+ len += zfcp_dbf_view(out_buf + len, "cmd_rsp_code", "0x%04x",
+ rec->type.ct.type.response.cmd_rsp_code);
+ len += zfcp_dbf_view(out_buf + len, "revision", "0x%02x",
+ rec->type.ct.type.response.revision);
+ len += zfcp_dbf_view(out_buf + len, "reason_code", "0x%02x",
+ rec->type.ct.type.response.reason_code);
+ len +=
+ zfcp_dbf_view(out_buf + len, "reason_code_expl", "0x%02x",
+ rec->type.ct.type.response.reason_code_expl);
+ len +=
+ zfcp_dbf_view(out_buf + len, "vendor_unique", "0x%02x",
+ rec->type.ct.type.response.vendor_unique);
+ total = rec->type.ct.payload_size;
+ buffer = rec->type.ct.payload;
+ buflen = min(total, ZFCP_DBF_CT_PAYLOAD);
+ } else if (strncmp(rec->tag, "oels", ZFCP_DBF_TAG_SIZE) == 0 ||
+ strncmp(rec->tag, "rels", ZFCP_DBF_TAG_SIZE) == 0 ||
+ strncmp(rec->tag, "iels", ZFCP_DBF_TAG_SIZE) == 0) {
+ len += zfcp_dbf_view(out_buf + len, "ls_code", "0x%02x",
+ rec->type.els.ls_code);
+ total = rec->type.els.payload_size;
+ buffer = rec->type.els.payload;
+ buflen = min(total, ZFCP_DBF_ELS_PAYLOAD);
+ }
+
+ len += zfcp_dbf_view_dump(out_buf + len, "payload",
+ buffer, buflen, 0, total);
+
+ if (buflen == total)
+ len += sprintf(out_buf + len, "\n");
+
+ return len;
+}
+
+struct debug_view zfcp_san_dbf_view = {
+ "structured",
+ NULL,
+ &zfcp_dbf_view_header,
+ &zfcp_san_dbf_view_format,
+ NULL,
+ NULL
+};
+
+static inline void
+_zfcp_scsi_dbf_event_common(const char *tag, const char *tag2, int level,
+ struct zfcp_adapter *adapter,
+ struct scsi_cmnd *scsi_cmnd,
+ struct zfcp_fsf_req *new_fsf_req)
+{
+ struct zfcp_fsf_req *fsf_req =
+ (struct zfcp_fsf_req *)scsi_cmnd->host_scribble;
+ struct zfcp_scsi_dbf_record *rec = &adapter->scsi_dbf_buf;
+ struct zfcp_dbf_dump *dump = (struct zfcp_dbf_dump *)rec;
+ unsigned long flags;
+ struct fcp_rsp_iu *fcp_rsp;
+ char *fcp_rsp_info = NULL, *fcp_sns_info = NULL;
+ int offset = 0, buflen = 0;
+
+ spin_lock_irqsave(&adapter->scsi_dbf_lock, flags);
+ do {
+ memset(rec, 0, sizeof(struct zfcp_scsi_dbf_record));
+ if (offset == 0) {
+ strncpy(rec->tag, tag, ZFCP_DBF_TAG_SIZE);
+ strncpy(rec->tag2, tag2, ZFCP_DBF_TAG_SIZE);
+ if (scsi_cmnd->device) {
+ rec->scsi_id = scsi_cmnd->device->id;
+ rec->scsi_lun = scsi_cmnd->device->lun;
+ }
+ rec->scsi_result = scsi_cmnd->result;
+ rec->scsi_cmnd = (unsigned long)scsi_cmnd;
+ rec->scsi_serial = scsi_cmnd->serial_number;
+ memcpy(rec->scsi_opcode,
+ &scsi_cmnd->cmnd,
+ min((int)scsi_cmnd->cmd_len,
+ ZFCP_DBF_SCSI_OPCODE));
+ rec->scsi_retries = scsi_cmnd->retries;
+ rec->scsi_allowed = scsi_cmnd->allowed;
+ if (fsf_req != NULL) {
+ fcp_rsp = (struct fcp_rsp_iu *)
+ &(fsf_req->qtcb->bottom.io.fcp_rsp);
+ fcp_rsp_info =
+ zfcp_get_fcp_rsp_info_ptr(fcp_rsp);
+ fcp_sns_info =
+ zfcp_get_fcp_sns_info_ptr(fcp_rsp);
+
+ rec->type.fcp.rsp_validity =
+ fcp_rsp->validity.value;
+ rec->type.fcp.rsp_scsi_status =
+ fcp_rsp->scsi_status;
+ rec->type.fcp.rsp_resid = fcp_rsp->fcp_resid;
+ if (fcp_rsp->validity.bits.fcp_rsp_len_valid)
+ rec->type.fcp.rsp_code =
+ *(fcp_rsp_info + 3);
+ if (fcp_rsp->validity.bits.fcp_sns_len_valid) {
+ buflen = min((int)fcp_rsp->fcp_sns_len,
+ ZFCP_DBF_SCSI_MAX_FCP_SNS_INFO);
+ rec->type.fcp.sns_info_len = buflen;
+ memcpy(rec->type.fcp.sns_info,
+ fcp_sns_info,
+ min(buflen,
+ ZFCP_DBF_SCSI_FCP_SNS_INFO));
+ offset += min(buflen,
+ ZFCP_DBF_SCSI_FCP_SNS_INFO);
+ }
+
+ rec->fsf_reqid = (unsigned long)fsf_req;
+ rec->fsf_seqno = fsf_req->seq_no;
+ rec->fsf_issued = fsf_req->issued;
+ }
+ if (new_fsf_req != NULL) {
+ rec->type.new_fsf_req.fsf_reqid =
+ (unsigned long)
+ new_fsf_req;
+ rec->type.new_fsf_req.fsf_seqno =
+ new_fsf_req->seq_no;
+ rec->type.new_fsf_req.fsf_issued =
+ new_fsf_req->issued;
+ }
+ } else {
+ strncpy(dump->tag, "dump", ZFCP_DBF_TAG_SIZE);
+ dump->total_size = buflen;
+ dump->offset = offset;
+ dump->size = min(buflen - offset,
+ (int)sizeof(struct
+ zfcp_scsi_dbf_record) -
+ (int)sizeof(struct zfcp_dbf_dump));
+ memcpy(dump->data, fcp_sns_info + offset, dump->size);
+ offset += dump->size;
+ }
+ debug_event(adapter->scsi_dbf, level,
+ rec, sizeof(struct zfcp_scsi_dbf_record));
+ } while (offset < buflen);
+ spin_unlock_irqrestore(&adapter->scsi_dbf_lock, flags);
+}
+
+inline void
+zfcp_scsi_dbf_event_result(const char *tag, int level,
+ struct zfcp_adapter *adapter,
+ struct scsi_cmnd *scsi_cmnd)
+{
+ _zfcp_scsi_dbf_event_common("rslt",
+ tag, level, adapter, scsi_cmnd, NULL);
+}
+
+inline void
+zfcp_scsi_dbf_event_abort(const char *tag, struct zfcp_adapter *adapter,
+ struct scsi_cmnd *scsi_cmnd,
+ struct zfcp_fsf_req *new_fsf_req)
+{
+ _zfcp_scsi_dbf_event_common("abrt",
+ tag, 1, adapter, scsi_cmnd, new_fsf_req);
+}
+
+inline void
+zfcp_scsi_dbf_event_devreset(const char *tag, u8 flag, struct zfcp_unit *unit,
+ struct scsi_cmnd *scsi_cmnd)
+{
+ struct zfcp_adapter *adapter = unit->port->adapter;
+
+ _zfcp_scsi_dbf_event_common(flag == FCP_TARGET_RESET ? "trst" : "lrst",
+ tag, 1, adapter, scsi_cmnd, NULL);
+}
+
+static int
+zfcp_scsi_dbf_view_format(debug_info_t * id, struct debug_view *view,
+ char *out_buf, const char *in_buf)
+{
+ struct zfcp_scsi_dbf_record *rec =
+ (struct zfcp_scsi_dbf_record *)in_buf;
+ int len = 0;
+
+ if (strncmp(rec->tag, "dump", ZFCP_DBF_TAG_SIZE) == 0)
+ return 0;
+
+ len += zfcp_dbf_tag(out_buf + len, "tag", rec->tag);
+ len += zfcp_dbf_tag(out_buf + len, "tag2", rec->tag2);
+ len += zfcp_dbf_view(out_buf + len, "scsi_id", "0x%08x", rec->scsi_id);
+ len += zfcp_dbf_view(out_buf + len, "scsi_lun", "0x%08x",
+ rec->scsi_lun);
+ len += zfcp_dbf_view(out_buf + len, "scsi_result", "0x%08x",
+ rec->scsi_result);
+ len += zfcp_dbf_view(out_buf + len, "scsi_cmnd", "0x%0Lx",
+ rec->scsi_cmnd);
+ len += zfcp_dbf_view(out_buf + len, "scsi_serial", "0x%016Lx",
+ rec->scsi_serial);
+ len += zfcp_dbf_view_dump(out_buf + len, "scsi_opcode",
+ rec->scsi_opcode,
+ ZFCP_DBF_SCSI_OPCODE,
+ 0, ZFCP_DBF_SCSI_OPCODE);
+ len += zfcp_dbf_view(out_buf + len, "scsi_retries", "0x%02x",
+ rec->scsi_retries);
+ len += zfcp_dbf_view(out_buf + len, "scsi_allowed", "0x%02x",
+ rec->scsi_allowed);
+ len += zfcp_dbf_view(out_buf + len, "fsf_reqid", "0x%0Lx",
+ rec->fsf_reqid);
+ len += zfcp_dbf_view(out_buf + len, "fsf_seqno", "0x%08x",
+ rec->fsf_seqno);
+ len += zfcp_dbf_stck(out_buf + len, "fsf_issued", rec->fsf_issued);
+ if (strncmp(rec->tag, "rslt", ZFCP_DBF_TAG_SIZE) == 0) {
+ len +=
+ zfcp_dbf_view(out_buf + len, "fcp_rsp_validity", "0x%02x",
+ rec->type.fcp.rsp_validity);
+ len +=
+ zfcp_dbf_view(out_buf + len, "fcp_rsp_scsi_status",
+ "0x%02x", rec->type.fcp.rsp_scsi_status);
+ len +=
+ zfcp_dbf_view(out_buf + len, "fcp_rsp_resid", "0x%08x",
+ rec->type.fcp.rsp_resid);
+ len +=
+ zfcp_dbf_view(out_buf + len, "fcp_rsp_code", "0x%08x",
+ rec->type.fcp.rsp_code);
+ len +=
+ zfcp_dbf_view(out_buf + len, "fcp_sns_info_len", "0x%08x",
+ rec->type.fcp.sns_info_len);
+ len +=
+ zfcp_dbf_view_dump(out_buf + len, "fcp_sns_info",
+ rec->type.fcp.sns_info,
+ min((int)rec->type.fcp.sns_info_len,
+ ZFCP_DBF_SCSI_FCP_SNS_INFO), 0,
+ rec->type.fcp.sns_info_len);
+ } else if (strncmp(rec->tag, "abrt", ZFCP_DBF_TAG_SIZE) == 0) {
+ len += zfcp_dbf_view(out_buf + len, "fsf_reqid_abort", "0x%0Lx",
+ rec->type.new_fsf_req.fsf_reqid);
+ len += zfcp_dbf_view(out_buf + len, "fsf_seqno_abort", "0x%08x",
+ rec->type.new_fsf_req.fsf_seqno);
+ len += zfcp_dbf_stck(out_buf + len, "fsf_issued",
+ rec->type.new_fsf_req.fsf_issued);
+ } else if ((strncmp(rec->tag, "trst", ZFCP_DBF_TAG_SIZE) == 0) ||
+ (strncmp(rec->tag, "lrst", ZFCP_DBF_TAG_SIZE) == 0)) {
+ len += zfcp_dbf_view(out_buf + len, "fsf_reqid_reset", "0x%0Lx",
+ rec->type.new_fsf_req.fsf_reqid);
+ len += zfcp_dbf_view(out_buf + len, "fsf_seqno_reset", "0x%08x",
+ rec->type.new_fsf_req.fsf_seqno);
+ len += zfcp_dbf_stck(out_buf + len, "fsf_issued",
+ rec->type.new_fsf_req.fsf_issued);
+ }
+
+ len += sprintf(out_buf + len, "\n");
+
+ return len;
+}
+
+struct debug_view zfcp_scsi_dbf_view = {
+ "structured",
+ NULL,
+ &zfcp_dbf_view_header,
+ &zfcp_scsi_dbf_view_format,
+ NULL,
+ NULL
+};
+
+/**
+ * zfcp_adapter_debug_register - registers debug feature for an adapter
+ * @adapter: pointer to adapter for which debug features should be registered
+ * return: -ENOMEM on error, 0 otherwise
+ */
+int zfcp_adapter_debug_register(struct zfcp_adapter *adapter)
+{
+ char dbf_name[DEBUG_MAX_NAME_LEN];
+
+ /* debug feature area which records recovery activity */
+ spin_lock_init(&adapter->erp_dbf_lock);
+ sprintf(dbf_name, "zfcp_%s_erp", zfcp_get_busid_by_adapter(adapter));
+ adapter->erp_dbf = debug_register(dbf_name, dbfsize, 2,
+ sizeof(struct zfcp_erp_dbf_record));
+ if (!adapter->erp_dbf)
+ goto failed;
+ debug_register_view(adapter->erp_dbf, &debug_hex_ascii_view);
+ debug_set_level(adapter->erp_dbf, 3);
+
+ /* debug feature area which records HBA (FSF and QDIO) conditions */
+ spin_lock_init(&adapter->hba_dbf_lock);
+ sprintf(dbf_name, "zfcp_%s_hba", zfcp_get_busid_by_adapter(adapter));
+ adapter->hba_dbf = debug_register(dbf_name, dbfsize, 1,
+ sizeof(struct zfcp_hba_dbf_record));
+ if (!adapter->hba_dbf)
+ goto failed;
+ debug_register_view(adapter->hba_dbf, &debug_hex_ascii_view);
+ debug_register_view(adapter->hba_dbf, &zfcp_hba_dbf_view);
+ debug_set_level(adapter->hba_dbf, 3);
+
+ /* debug feature area which records SAN command failures and recovery */
+ spin_lock_init(&adapter->san_dbf_lock);
+ sprintf(dbf_name, "zfcp_%s_san", zfcp_get_busid_by_adapter(adapter));
+ adapter->san_dbf = debug_register(dbf_name, dbfsize, 1,
+ sizeof(struct zfcp_san_dbf_record));
+ if (!adapter->san_dbf)
+ goto failed;
+ debug_register_view(adapter->san_dbf, &debug_hex_ascii_view);
+ debug_register_view(adapter->san_dbf, &zfcp_san_dbf_view);
+ debug_set_level(adapter->san_dbf, 6);
+
+ /* debug feature area which records SCSI command failures and recovery */
+ spin_lock_init(&adapter->scsi_dbf_lock);
+ sprintf(dbf_name, "zfcp_%s_scsi", zfcp_get_busid_by_adapter(adapter));
+ adapter->scsi_dbf = debug_register(dbf_name, dbfsize, 1,
+ sizeof(struct zfcp_scsi_dbf_record));
+ if (!adapter->scsi_dbf)
+ goto failed;
+ debug_register_view(adapter->scsi_dbf, &debug_hex_ascii_view);
+ debug_register_view(adapter->scsi_dbf, &zfcp_scsi_dbf_view);
+ debug_set_level(adapter->scsi_dbf, 3);
+
+ return 0;
+
+ failed:
+ zfcp_adapter_debug_unregister(adapter);
+
+ return -ENOMEM;
+}
+
+/**
+ * zfcp_adapter_debug_unregister - unregisters debug feature for an adapter
+ * @adapter: pointer to adapter for which debug features should be unregistered
+ */
+void zfcp_adapter_debug_unregister(struct zfcp_adapter *adapter)
+{
+ debug_unregister(adapter->scsi_dbf);
+ debug_unregister(adapter->san_dbf);
+ debug_unregister(adapter->hba_dbf);
+ debug_unregister(adapter->erp_dbf);
+ adapter->scsi_dbf = NULL;
+ adapter->san_dbf = NULL;
+ adapter->hba_dbf = NULL;
+ adapter->erp_dbf = NULL;
+}
+
+#undef ZFCP_LOG_AREA
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h
index 455e902533a9..d81b737d68cc 100644
--- a/drivers/s390/scsi/zfcp_def.h
+++ b/drivers/s390/scsi/zfcp_def.h
@@ -66,7 +66,7 @@
/********************* GENERAL DEFINES *********************************/
/* zfcp version number, it consists of major, minor, and patch-level number */
-#define ZFCP_VERSION "4.3.0"
+#define ZFCP_VERSION "4.5.0"
/**
* zfcp_sg_to_address - determine kernel address from struct scatterlist
@@ -154,13 +154,17 @@ typedef u32 scsi_lun_t;
#define ZFCP_EXCHANGE_CONFIG_DATA_FIRST_SLEEP 100
#define ZFCP_EXCHANGE_CONFIG_DATA_RETRIES 7
+/* Retry 5 times every 2 second, then every minute */
+#define ZFCP_EXCHANGE_PORT_DATA_SHORT_RETRIES 5
+#define ZFCP_EXCHANGE_PORT_DATA_SHORT_SLEEP 200
+#define ZFCP_EXCHANGE_PORT_DATA_LONG_SLEEP 6000
+
/* timeout value for "default timer" for fsf requests */
#define ZFCP_FSF_REQUEST_TIMEOUT (60*HZ);
/*************** FIBRE CHANNEL PROTOCOL SPECIFIC DEFINES ********************/
typedef unsigned long long wwn_t;
-typedef unsigned int fc_id_t;
typedef unsigned long long fcp_lun_t;
/* data length field may be at variable position in FCP-2 FCP_CMND IU */
typedef unsigned int fcp_dl_t;
@@ -281,6 +285,171 @@ struct fcp_logo {
} __attribute__((packed));
/*
+ * DBF stuff
+ */
+#define ZFCP_DBF_TAG_SIZE 4
+
+struct zfcp_dbf_dump {
+ u8 tag[ZFCP_DBF_TAG_SIZE];
+ u32 total_size; /* size of total dump data */
+ u32 offset; /* how much data has being already dumped */
+ u32 size; /* how much data comes with this record */
+ u8 data[]; /* dump data */
+} __attribute__ ((packed));
+
+/* FIXME: to be inflated when reworking the erp dbf */
+struct zfcp_erp_dbf_record {
+ u8 dummy[16];
+} __attribute__ ((packed));
+
+struct zfcp_hba_dbf_record_response {
+ u32 fsf_command;
+ u64 fsf_reqid;
+ u32 fsf_seqno;
+ u64 fsf_issued;
+ u32 fsf_prot_status;
+ u32 fsf_status;
+ u8 fsf_prot_status_qual[FSF_PROT_STATUS_QUAL_SIZE];
+ u8 fsf_status_qual[FSF_STATUS_QUALIFIER_SIZE];
+ u32 fsf_req_status;
+ u8 sbal_first;
+ u8 sbal_curr;
+ u8 sbal_last;
+ u8 pool;
+ u64 erp_action;
+ union {
+ struct {
+ u64 scsi_cmnd;
+ u64 scsi_serial;
+ } send_fcp;
+ struct {
+ u64 wwpn;
+ u32 d_id;
+ u32 port_handle;
+ } port;
+ struct {
+ u64 wwpn;
+ u64 fcp_lun;
+ u32 port_handle;
+ u32 lun_handle;
+ } unit;
+ struct {
+ u32 d_id;
+ u8 ls_code;
+ } send_els;
+ } data;
+} __attribute__ ((packed));
+
+struct zfcp_hba_dbf_record_status {
+ u8 failed;
+ u32 status_type;
+ u32 status_subtype;
+ struct fsf_queue_designator
+ queue_designator;
+ u32 payload_size;
+#define ZFCP_DBF_UNSOL_PAYLOAD 80
+#define ZFCP_DBF_UNSOL_PAYLOAD_SENSE_DATA_AVAIL 32
+#define ZFCP_DBF_UNSOL_PAYLOAD_BIT_ERROR_THRESHOLD 56
+#define ZFCP_DBF_UNSOL_PAYLOAD_FEATURE_UPDATE_ALERT 2 * sizeof(u32)
+ u8 payload[ZFCP_DBF_UNSOL_PAYLOAD];
+} __attribute__ ((packed));
+
+struct zfcp_hba_dbf_record_qdio {
+ u32 status;
+ u32 qdio_error;
+ u32 siga_error;
+ u8 sbal_index;
+ u8 sbal_count;
+} __attribute__ ((packed));
+
+struct zfcp_hba_dbf_record {
+ u8 tag[ZFCP_DBF_TAG_SIZE];
+ u8 tag2[ZFCP_DBF_TAG_SIZE];
+ union {
+ struct zfcp_hba_dbf_record_response response;
+ struct zfcp_hba_dbf_record_status status;
+ struct zfcp_hba_dbf_record_qdio qdio;
+ } type;
+} __attribute__ ((packed));
+
+struct zfcp_san_dbf_record_ct {
+ union {
+ struct {
+ u16 cmd_req_code;
+ u8 revision;
+ u8 gs_type;
+ u8 gs_subtype;
+ u8 options;
+ u16 max_res_size;
+ } request;
+ struct {
+ u16 cmd_rsp_code;
+ u8 revision;
+ u8 reason_code;
+ u8 reason_code_expl;
+ u8 vendor_unique;
+ } response;
+ } type;
+ u32 payload_size;
+#define ZFCP_DBF_CT_PAYLOAD 24
+ u8 payload[ZFCP_DBF_CT_PAYLOAD];
+} __attribute__ ((packed));
+
+struct zfcp_san_dbf_record_els {
+ u8 ls_code;
+ u32 payload_size;
+#define ZFCP_DBF_ELS_PAYLOAD 32
+#define ZFCP_DBF_ELS_MAX_PAYLOAD 1024
+ u8 payload[ZFCP_DBF_ELS_PAYLOAD];
+} __attribute__ ((packed));
+
+struct zfcp_san_dbf_record {
+ u8 tag[ZFCP_DBF_TAG_SIZE];
+ u64 fsf_reqid;
+ u32 fsf_seqno;
+ u32 s_id;
+ u32 d_id;
+ union {
+ struct zfcp_san_dbf_record_ct ct;
+ struct zfcp_san_dbf_record_els els;
+ } type;
+} __attribute__ ((packed));
+
+struct zfcp_scsi_dbf_record {
+ u8 tag[ZFCP_DBF_TAG_SIZE];
+ u8 tag2[ZFCP_DBF_TAG_SIZE];
+ u32 scsi_id;
+ u32 scsi_lun;
+ u32 scsi_result;
+ u64 scsi_cmnd;
+ u64 scsi_serial;
+#define ZFCP_DBF_SCSI_OPCODE 16
+ u8 scsi_opcode[ZFCP_DBF_SCSI_OPCODE];
+ u8 scsi_retries;
+ u8 scsi_allowed;
+ u64 fsf_reqid;
+ u32 fsf_seqno;
+ u64 fsf_issued;
+ union {
+ struct {
+ u64 fsf_reqid;
+ u32 fsf_seqno;
+ u64 fsf_issued;
+ } new_fsf_req;
+ struct {
+ u8 rsp_validity;
+ u8 rsp_scsi_status;
+ u32 rsp_resid;
+ u8 rsp_code;
+#define ZFCP_DBF_SCSI_FCP_SNS_INFO 16
+#define ZFCP_DBF_SCSI_MAX_FCP_SNS_INFO 256
+ u32 sns_info_len;
+ u8 sns_info[ZFCP_DBF_SCSI_FCP_SNS_INFO];
+ } fcp;
+ } type;
+} __attribute__ ((packed));
+
+/*
* FC-FS stuff
*/
#define R_A_TOV 10 /* seconds */
@@ -339,34 +508,6 @@ struct zfcp_rc_entry {
*/
#define ZFCP_CT_TIMEOUT (3 * R_A_TOV)
-
-/***************** S390 DEBUG FEATURE SPECIFIC DEFINES ***********************/
-
-/* debug feature entries per adapter */
-#define ZFCP_ERP_DBF_INDEX 1
-#define ZFCP_ERP_DBF_AREAS 2
-#define ZFCP_ERP_DBF_LENGTH 16
-#define ZFCP_ERP_DBF_LEVEL 3
-#define ZFCP_ERP_DBF_NAME "zfcperp"
-
-#define ZFCP_CMD_DBF_INDEX 2
-#define ZFCP_CMD_DBF_AREAS 1
-#define ZFCP_CMD_DBF_LENGTH 8
-#define ZFCP_CMD_DBF_LEVEL 3
-#define ZFCP_CMD_DBF_NAME "zfcpcmd"
-
-#define ZFCP_ABORT_DBF_INDEX 2
-#define ZFCP_ABORT_DBF_AREAS 1
-#define ZFCP_ABORT_DBF_LENGTH 8
-#define ZFCP_ABORT_DBF_LEVEL 6
-#define ZFCP_ABORT_DBF_NAME "zfcpabt"
-
-#define ZFCP_IN_ELS_DBF_INDEX 2
-#define ZFCP_IN_ELS_DBF_AREAS 1
-#define ZFCP_IN_ELS_DBF_LENGTH 8
-#define ZFCP_IN_ELS_DBF_LEVEL 6
-#define ZFCP_IN_ELS_DBF_NAME "zfcpels"
-
/******************** LOGGING MACROS AND DEFINES *****************************/
/*
@@ -501,6 +642,7 @@ do { \
#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_XPORT_OK 0x00000800
#define ZFCP_STATUS_ADAPTER_SCSI_UP \
(ZFCP_STATUS_COMMON_UNBLOCKED | \
@@ -635,45 +777,6 @@ struct zfcp_adapter_mempool {
mempool_t *data_gid_pn;
};
-struct zfcp_exchange_config_data{
-};
-
-struct zfcp_open_port {
- struct zfcp_port *port;
-};
-
-struct zfcp_close_port {
- struct zfcp_port *port;
-};
-
-struct zfcp_open_unit {
- struct zfcp_unit *unit;
-};
-
-struct zfcp_close_unit {
- struct zfcp_unit *unit;
-};
-
-struct zfcp_close_physical_port {
- struct zfcp_port *port;
-};
-
-struct zfcp_send_fcp_command_task {
- struct zfcp_fsf_req *fsf_req;
- struct zfcp_unit *unit;
- struct scsi_cmnd *scsi_cmnd;
- unsigned long start_jiffies;
-};
-
-struct zfcp_send_fcp_command_task_management {
- struct zfcp_unit *unit;
-};
-
-struct zfcp_abort_fcp_command {
- struct zfcp_fsf_req *fsf_req;
- struct zfcp_unit *unit;
-};
-
/*
* header for CT_IU
*/
@@ -702,7 +805,7 @@ struct ct_iu_gid_pn_req {
/* FS_ACC IU and data unit for GID_PN nameserver request */
struct ct_iu_gid_pn_resp {
struct ct_hdr header;
- fc_id_t d_id;
+ u32 d_id;
} __attribute__ ((packed));
typedef void (*zfcp_send_ct_handler_t)(unsigned long);
@@ -768,7 +871,7 @@ typedef void (*zfcp_send_els_handler_t)(unsigned long);
struct zfcp_send_els {
struct zfcp_adapter *adapter;
struct zfcp_port *port;
- fc_id_t d_id;
+ u32 d_id;
struct scatterlist *req;
struct scatterlist *resp;
unsigned int req_count;
@@ -781,33 +884,6 @@ struct zfcp_send_els {
int status;
};
-struct zfcp_status_read {
- struct fsf_status_read_buffer *buffer;
-};
-
-struct zfcp_fsf_done {
- struct completion *complete;
- int status;
-};
-
-/* request specific data */
-union zfcp_req_data {
- struct zfcp_exchange_config_data exchange_config_data;
- struct zfcp_open_port open_port;
- struct zfcp_close_port close_port;
- struct zfcp_open_unit open_unit;
- struct zfcp_close_unit close_unit;
- struct zfcp_close_physical_port close_physical_port;
- struct zfcp_send_fcp_command_task send_fcp_command_task;
- struct zfcp_send_fcp_command_task_management
- send_fcp_command_task_management;
- struct zfcp_abort_fcp_command abort_fcp_command;
- struct zfcp_send_ct *send_ct;
- struct zfcp_send_els *send_els;
- struct zfcp_status_read status_read;
- struct fsf_qtcb_bottom_port *port_data;
-};
-
struct zfcp_qdio_queue {
struct qdio_buffer *buffer[QDIO_MAX_BUFFERS_PER_Q]; /* SBALs */
u8 free_index; /* index of next free bfr
@@ -838,21 +914,19 @@ struct zfcp_adapter {
atomic_t refcount; /* reference count */
wait_queue_head_t remove_wq; /* can be used to wait for
refcount drop to zero */
- wwn_t wwnn; /* WWNN */
- wwn_t wwpn; /* WWPN */
- fc_id_t s_id; /* N_Port ID */
wwn_t peer_wwnn; /* P2P peer WWNN */
wwn_t peer_wwpn; /* P2P peer WWPN */
- fc_id_t peer_d_id; /* P2P peer D_ID */
+ u32 peer_d_id; /* P2P peer D_ID */
+ wwn_t physical_wwpn; /* WWPN of physical port */
+ u32 physical_s_id; /* local FC port ID */
struct ccw_device *ccw_device; /* S/390 ccw device */
u8 fc_service_class;
u32 fc_topology; /* FC topology */
- u32 fc_link_speed; /* FC interface speed */
u32 hydra_version; /* Hydra version */
u32 fsf_lic_version;
- u32 supported_features;/* of FCP channel */
+ u32 adapter_features; /* FCP channel features */
+ u32 connection_features; /* host connection features */
u32 hardware_version; /* of FCP channel */
- u8 serial_number[32]; /* of hardware */
struct Scsi_Host *scsi_host; /* Pointer to mid-layer */
unsigned short scsi_host_no; /* Assigned host number */
unsigned char name[9];
@@ -889,11 +963,18 @@ struct zfcp_adapter {
u32 erp_low_mem_count; /* nr of erp actions waiting
for memory */
struct zfcp_port *nameserver_port; /* adapter's nameserver */
- debug_info_t *erp_dbf; /* S/390 debug features */
- debug_info_t *abort_dbf;
- debug_info_t *in_els_dbf;
- debug_info_t *cmd_dbf;
- spinlock_t dbf_lock;
+ debug_info_t *erp_dbf;
+ debug_info_t *hba_dbf;
+ debug_info_t *san_dbf; /* debug feature areas */
+ debug_info_t *scsi_dbf;
+ spinlock_t erp_dbf_lock;
+ spinlock_t hba_dbf_lock;
+ spinlock_t san_dbf_lock;
+ spinlock_t scsi_dbf_lock;
+ struct zfcp_erp_dbf_record erp_dbf_buf;
+ struct zfcp_hba_dbf_record hba_dbf_buf;
+ struct zfcp_san_dbf_record san_dbf_buf;
+ struct zfcp_scsi_dbf_record scsi_dbf_buf;
struct zfcp_adapter_mempool pool; /* Adapter memory pools */
struct qdio_initialize qdio_init_data; /* for qdio_establish */
struct device generic_services; /* directory for WKA ports */
@@ -919,7 +1000,7 @@ struct zfcp_port {
atomic_t status; /* status of this remote port */
wwn_t wwnn; /* WWNN if known */
wwn_t wwpn; /* WWPN */
- fc_id_t d_id; /* D_ID */
+ u32 d_id; /* D_ID */
u32 handle; /* handle assigned by FSF */
struct zfcp_erp_action erp_action; /* pending error recovery */
atomic_t erp_counter;
@@ -963,11 +1044,13 @@ struct zfcp_fsf_req {
u32 fsf_command; /* FSF Command copy */
struct fsf_qtcb *qtcb; /* address of associated QTCB */
u32 seq_no; /* Sequence number of request */
- union zfcp_req_data data; /* Info fields of request */
+ unsigned long data; /* private data of request */
struct zfcp_erp_action *erp_action; /* used if this request is
issued on behalf of erp */
mempool_t *pool; /* used if request was alloacted
from emergency pool */
+ unsigned long long issued; /* request sent time (STCK) */
+ struct zfcp_unit *unit;
};
typedef void zfcp_fsf_req_handler_t(struct zfcp_fsf_req*);
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index cb4f612550ba..023f4e558ae4 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -82,6 +82,7 @@ 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_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *);
+static int zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *);
static int zfcp_erp_adapter_strategy_open_fsf_statusread(
struct zfcp_erp_action *);
@@ -345,13 +346,13 @@ zfcp_erp_adisc(struct zfcp_port *port)
/* acc. to FC-FS, hard_nport_id in ADISC should not be set for ports
without FC-AL-2 capability, so we don't set it */
- adisc->wwpn = adapter->wwpn;
- adisc->wwnn = adapter->wwnn;
- adisc->nport_id = adapter->s_id;
+ adisc->wwpn = fc_host_port_name(adapter->scsi_host);
+ adisc->wwnn = fc_host_node_name(adapter->scsi_host);
+ adisc->nport_id = fc_host_port_id(adapter->scsi_host);
ZFCP_LOG_INFO("ADISC request from s_id 0x%08x to d_id 0x%08x "
"(wwpn=0x%016Lx, wwnn=0x%016Lx, "
"hard_nport_id=0x%08x, nport_id=0x%08x)\n",
- adapter->s_id, send_els->d_id, (wwn_t) adisc->wwpn,
+ adisc->nport_id, send_els->d_id, (wwn_t) adisc->wwpn,
(wwn_t) adisc->wwnn, adisc->hard_nport_id,
adisc->nport_id);
@@ -404,7 +405,7 @@ zfcp_erp_adisc_handler(unsigned long data)
struct zfcp_send_els *send_els;
struct zfcp_port *port;
struct zfcp_adapter *adapter;
- fc_id_t d_id;
+ u32 d_id;
struct zfcp_ls_adisc_acc *adisc;
send_els = (struct zfcp_send_els *) data;
@@ -435,9 +436,9 @@ zfcp_erp_adisc_handler(unsigned long data)
ZFCP_LOG_INFO("ADISC response from d_id 0x%08x to s_id "
"0x%08x (wwpn=0x%016Lx, wwnn=0x%016Lx, "
"hard_nport_id=0x%08x, nport_id=0x%08x)\n",
- d_id, adapter->s_id, (wwn_t) adisc->wwpn,
- (wwn_t) adisc->wwnn, adisc->hard_nport_id,
- adisc->nport_id);
+ d_id, fc_host_port_id(adapter->scsi_host),
+ (wwn_t) adisc->wwpn, (wwn_t) adisc->wwnn,
+ adisc->hard_nport_id, adisc->nport_id);
/* set wwnn for port */
if (port->wwnn == 0)
@@ -886,7 +887,7 @@ static int
zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action)
{
int retval = 0;
- struct zfcp_fsf_req *fsf_req;
+ struct zfcp_fsf_req *fsf_req = NULL;
struct zfcp_adapter *adapter = erp_action->adapter;
if (erp_action->fsf_req) {
@@ -896,7 +897,7 @@ zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action)
list_for_each_entry(fsf_req, &adapter->fsf_req_list_head, list)
if (fsf_req == erp_action->fsf_req)
break;
- if (fsf_req == erp_action->fsf_req) {
+ if (fsf_req && (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,
@@ -2258,16 +2259,21 @@ zfcp_erp_adapter_strategy_close_qdio(struct zfcp_erp_action *erp_action)
static int
zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *erp_action)
{
- int retval;
+ int xconfig, xport;
+
+ if (atomic_test_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
+ &erp_action->adapter->status)) {
+ zfcp_erp_adapter_strategy_open_fsf_xport(erp_action);
+ atomic_set(&erp_action->adapter->erp_counter, 0);
+ return ZFCP_ERP_FAILED;
+ }
- /* do 'exchange configuration data' */
- retval = zfcp_erp_adapter_strategy_open_fsf_xconfig(erp_action);
- if (retval == ZFCP_ERP_FAILED)
- return retval;
+ xconfig = zfcp_erp_adapter_strategy_open_fsf_xconfig(erp_action);
+ xport = zfcp_erp_adapter_strategy_open_fsf_xport(erp_action);
+ if ((xconfig == ZFCP_ERP_FAILED) || (xport == ZFCP_ERP_FAILED))
+ return ZFCP_ERP_FAILED;
- /* start the desired number of Status Reads */
- retval = zfcp_erp_adapter_strategy_open_fsf_statusread(erp_action);
- return retval;
+ return zfcp_erp_adapter_strategy_open_fsf_statusread(erp_action);
}
/*
@@ -2291,7 +2297,9 @@ zfcp_erp_adapter_strategy_open_fsf_xconfig(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);
zfcp_erp_action_to_running(erp_action);
+ write_unlock(&adapter->erp_lock);
zfcp_erp_timeout_init(erp_action);
if (zfcp_fsf_exchange_config_data(erp_action)) {
retval = ZFCP_ERP_FAILED;
@@ -2348,6 +2356,76 @@ zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *erp_action)
return retval;
}
+static int
+zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *erp_action)
+{
+ int retval = ZFCP_ERP_SUCCEEDED;
+ int retries;
+ int sleep;
+ struct zfcp_adapter *adapter = erp_action->adapter;
+
+ atomic_clear_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status);
+
+ for (retries = 0; ; retries++) {
+ ZFCP_LOG_DEBUG("Doing exchange port data\n");
+ zfcp_erp_action_to_running(erp_action);
+ zfcp_erp_timeout_init(erp_action);
+ if (zfcp_fsf_exchange_port_data(erp_action, adapter, NULL)) {
+ retval = ZFCP_ERP_FAILED;
+ debug_text_event(adapter->erp_dbf, 5, "a_fstx_xf");
+ ZFCP_LOG_INFO("error: initiation of exchange of "
+ "port data failed for adapter %s\n",
+ zfcp_get_busid_by_adapter(adapter));
+ break;
+ }
+ debug_text_event(adapter->erp_dbf, 6, "a_fstx_xok");
+ ZFCP_LOG_DEBUG("Xchange underway\n");
+
+ /*
+ * Why this works:
+ * Both the normal completion handler as well as the timeout
+ * handler will do an 'up' when the 'exchange port data'
+ * request completes or times out. Thus, the signal to go on
+ * won't be lost utilizing this semaphore.
+ * Furthermore, this 'adapter_reopen' action is
+ * guaranteed to be the only action being there (highest action
+ * which prevents other actions from being created).
+ * Resulting from that, the wake signal recognized here
+ * _must_ be the one belonging to the 'exchange port
+ * data' request.
+ */
+ down(&adapter->erp_ready_sem);
+ if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) {
+ ZFCP_LOG_INFO("error: exchange of port data "
+ "for adapter %s timed out\n",
+ zfcp_get_busid_by_adapter(adapter));
+ break;
+ }
+
+ if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
+ &adapter->status))
+ break;
+
+ ZFCP_LOG_DEBUG("host connection still initialising... "
+ "waiting and retrying...\n");
+ /* sleep a little bit before retry */
+ sleep = retries < ZFCP_EXCHANGE_PORT_DATA_SHORT_RETRIES ?
+ ZFCP_EXCHANGE_PORT_DATA_SHORT_SLEEP :
+ ZFCP_EXCHANGE_PORT_DATA_LONG_SLEEP;
+ msleep(jiffies_to_msecs(sleep));
+ }
+
+ if (atomic_test_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
+ &adapter->status)) {
+ ZFCP_LOG_INFO("error: exchange of port data for "
+ "adapter %s failed\n",
+ zfcp_get_busid_by_adapter(adapter));
+ retval = ZFCP_ERP_FAILED;
+ }
+
+ return retval;
+}
+
/*
* function:
*
@@ -3194,11 +3272,19 @@ zfcp_erp_action_enqueue(int action,
/* fall through !!! */
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
- if (atomic_test_mask
- (ZFCP_STATUS_COMMON_ERP_INUSE, &port->status)
- && port->erp_action.action ==
- ZFCP_ERP_ACTION_REOPEN_PORT_FORCED) {
- debug_text_event(adapter->erp_dbf, 4, "pf_actenq_drp");
+ if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
+ &port->status)) {
+ if (port->erp_action.action !=
+ ZFCP_ERP_ACTION_REOPEN_PORT_FORCED) {
+ ZFCP_LOG_INFO("dropped erp action %i (port "
+ "0x%016Lx, action in use: %i)\n",
+ action, port->wwpn,
+ port->erp_action.action);
+ debug_text_event(adapter->erp_dbf, 4,
+ "pf_actenq_drp");
+ } else
+ debug_text_event(adapter->erp_dbf, 4,
+ "pf_actenq_drpcp");
debug_event(adapter->erp_dbf, 4, &port->wwpn,
sizeof (wwn_t));
goto out;
@@ -3589,6 +3675,9 @@ zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter)
struct zfcp_port *port;
unsigned long flags;
+ if (adapter->connection_features & FSF_FEATURE_NPIV_MODE)
+ return;
+
debug_text_event(adapter->erp_dbf, 3, "a_access_recover");
debug_event(adapter->erp_dbf, 3, &adapter->name, 8);
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
index cd98a2de9f8f..c3782261cb5c 100644
--- a/drivers/s390/scsi/zfcp_ext.h
+++ b/drivers/s390/scsi/zfcp_ext.h
@@ -96,7 +96,8 @@ extern int zfcp_fsf_open_unit(struct zfcp_erp_action *);
extern int zfcp_fsf_close_unit(struct zfcp_erp_action *);
extern int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *);
-extern int zfcp_fsf_exchange_port_data(struct zfcp_adapter *,
+extern int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *,
+ struct zfcp_adapter *,
struct fsf_qtcb_bottom_port *);
extern int zfcp_fsf_control_file(struct zfcp_adapter *, struct zfcp_fsf_req **,
u32, u32, struct zfcp_sg_list *);
@@ -109,7 +110,6 @@ extern int zfcp_fsf_req_create(struct zfcp_adapter *, u32, int, mempool_t *,
extern int zfcp_fsf_send_ct(struct zfcp_send_ct *, mempool_t *,
struct zfcp_erp_action *);
extern int zfcp_fsf_send_els(struct zfcp_send_els *);
-extern int zfcp_fsf_req_wait_and_cleanup(struct zfcp_fsf_req *, int, u32 *);
extern int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *,
struct zfcp_unit *,
struct scsi_cmnd *,
@@ -182,9 +182,25 @@ extern void zfcp_erp_port_access_changed(struct zfcp_port *);
extern void zfcp_erp_unit_access_changed(struct zfcp_unit *);
/******************************** AUX ****************************************/
-extern void zfcp_cmd_dbf_event_fsf(const char *, struct zfcp_fsf_req *,
- void *, int);
-extern void zfcp_cmd_dbf_event_scsi(const char *, struct scsi_cmnd *);
-extern void zfcp_in_els_dbf_event(struct zfcp_adapter *, const char *,
- struct fsf_status_read_buffer *, int);
+extern void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *);
+extern void zfcp_hba_dbf_event_fsf_unsol(const char *, struct zfcp_adapter *,
+ struct fsf_status_read_buffer *);
+extern void zfcp_hba_dbf_event_qdio(struct zfcp_adapter *,
+ unsigned int, unsigned int, unsigned int,
+ int, int);
+
+extern void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *);
+extern void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *);
+extern void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *);
+extern void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *);
+extern void zfcp_san_dbf_event_incoming_els(struct zfcp_fsf_req *);
+
+extern void zfcp_scsi_dbf_event_result(const char *, int, struct zfcp_adapter *,
+ struct scsi_cmnd *);
+extern void zfcp_scsi_dbf_event_abort(const char *, struct zfcp_adapter *,
+ struct scsi_cmnd *,
+ struct zfcp_fsf_req *);
+extern void zfcp_scsi_dbf_event_devreset(const char *, u8, struct zfcp_unit *,
+ struct scsi_cmnd *);
+
#endif /* ZFCP_EXT_H */
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index c007b6424e74..3b0fc1163f5f 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -59,6 +59,8 @@ static int zfcp_fsf_req_send(struct zfcp_fsf_req *, struct timer_list *);
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_adapter *,
+ struct fsf_link_down_info *);
static int zfcp_fsf_req_dispatch(struct zfcp_fsf_req *);
static void zfcp_fsf_req_dismiss(struct zfcp_fsf_req *);
@@ -285,51 +287,51 @@ 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_LOG_DEBUG("QTCB is at %p\n", fsf_req->qtcb);
+ zfcp_hba_dbf_event_fsf_response(fsf_req);
if (fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED) {
ZFCP_LOG_DEBUG("fsf_req 0x%lx has been dismissed\n",
(unsigned long) fsf_req);
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR |
ZFCP_STATUS_FSFREQ_RETRY; /* only for SCSI cmnds. */
- zfcp_cmd_dbf_event_fsf("dismiss", fsf_req, NULL, 0);
goto skip_protstatus;
}
/* log additional information provided by FSF (if any) */
- if (unlikely(fsf_req->qtcb->header.log_length)) {
+ if (unlikely(qtcb->header.log_length)) {
/* do not trust them ;-) */
- if (fsf_req->qtcb->header.log_start > sizeof(struct fsf_qtcb)) {
+ if (qtcb->header.log_start > sizeof(struct fsf_qtcb)) {
ZFCP_LOG_NORMAL
("bug: ULP (FSF logging) log data starts "
"beyond end of packet header. Ignored. "
"(start=%i, size=%li)\n",
- fsf_req->qtcb->header.log_start,
+ qtcb->header.log_start,
sizeof(struct fsf_qtcb));
goto forget_log;
}
- if ((size_t) (fsf_req->qtcb->header.log_start +
- fsf_req->qtcb->header.log_length)
+ if ((size_t) (qtcb->header.log_start + qtcb->header.log_length)
> sizeof(struct fsf_qtcb)) {
ZFCP_LOG_NORMAL("bug: ULP (FSF logging) log data ends "
"beyond end of packet header. Ignored. "
"(start=%i, length=%i, size=%li)\n",
- fsf_req->qtcb->header.log_start,
- fsf_req->qtcb->header.log_length,
+ qtcb->header.log_start,
+ qtcb->header.log_length,
sizeof(struct fsf_qtcb));
goto forget_log;
}
ZFCP_LOG_TRACE("ULP log data: \n");
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE,
- (char *) fsf_req->qtcb +
- fsf_req->qtcb->header.log_start,
- fsf_req->qtcb->header.log_length);
+ (char *) qtcb + qtcb->header.log_start,
+ qtcb->header.log_length);
}
forget_log:
/* evaluate FSF Protocol Status */
- switch (fsf_req->qtcb->prefix.prot_status) {
+ switch (qtcb->prefix.prot_status) {
case FSF_PROT_GOOD:
case FSF_PROT_FSF_STATUS_PRESENTED:
@@ -340,14 +342,9 @@ zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *fsf_req)
"microcode of version 0x%x, the device driver "
"only supports 0x%x. Aborting.\n",
zfcp_get_busid_by_adapter(adapter),
- fsf_req->qtcb->prefix.prot_status_qual.
- version_error.fsf_version, ZFCP_QTCB_VERSION);
- /* stop operation for this adapter */
- debug_text_exception(adapter->erp_dbf, 0, "prot_ver_err");
+ prot_status_qual->version_error.fsf_version,
+ ZFCP_QTCB_VERSION);
zfcp_erp_adapter_shutdown(adapter, 0);
- zfcp_cmd_dbf_event_fsf("qverserr", fsf_req,
- &fsf_req->qtcb->prefix.prot_status_qual,
- sizeof (union fsf_prot_status_qual));
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
@@ -355,16 +352,10 @@ zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *fsf_req)
ZFCP_LOG_NORMAL("bug: Sequence number mismatch between "
"driver (0x%x) and adapter %s (0x%x). "
"Restarting all operations on this adapter.\n",
- fsf_req->qtcb->prefix.req_seq_no,
+ qtcb->prefix.req_seq_no,
zfcp_get_busid_by_adapter(adapter),
- fsf_req->qtcb->prefix.prot_status_qual.
- sequence_error.exp_req_seq_no);
- debug_text_exception(adapter->erp_dbf, 0, "prot_seq_err");
- /* restart operation on this adapter */
+ prot_status_qual->sequence_error.exp_req_seq_no);
zfcp_erp_adapter_reopen(adapter, 0);
- zfcp_cmd_dbf_event_fsf("seqnoerr", fsf_req,
- &fsf_req->qtcb->prefix.prot_status_qual,
- sizeof (union fsf_prot_status_qual));
fsf_req->status |= ZFCP_STATUS_FSFREQ_RETRY;
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
@@ -375,116 +366,35 @@ zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *fsf_req)
"that used on adapter %s. "
"Stopping all operations on this adapter.\n",
zfcp_get_busid_by_adapter(adapter));
- debug_text_exception(adapter->erp_dbf, 0, "prot_unsup_qtcb");
zfcp_erp_adapter_shutdown(adapter, 0);
- zfcp_cmd_dbf_event_fsf("unsqtcbt", fsf_req,
- &fsf_req->qtcb->prefix.prot_status_qual,
- sizeof (union fsf_prot_status_qual));
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_PROT_HOST_CONNECTION_INITIALIZING:
- zfcp_cmd_dbf_event_fsf("hconinit", fsf_req,
- &fsf_req->qtcb->prefix.prot_status_qual,
- sizeof (union fsf_prot_status_qual));
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
atomic_set_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
&(adapter->status));
- debug_text_event(adapter->erp_dbf, 3, "prot_con_init");
break;
case FSF_PROT_DUPLICATE_REQUEST_ID:
- if (fsf_req->qtcb) {
ZFCP_LOG_NORMAL("bug: The request identifier 0x%Lx "
"to the adapter %s is ambiguous. "
- "Stopping all operations on this "
- "adapter.\n",
- *(unsigned long long *)
- (&fsf_req->qtcb->bottom.support.
- req_handle),
- zfcp_get_busid_by_adapter(adapter));
- } else {
- ZFCP_LOG_NORMAL("bug: The request identifier %p "
- "to the adapter %s is ambiguous. "
- "Stopping all operations on this "
- "adapter. "
- "(bug: got this for an unsolicited "
- "status read request)\n",
- fsf_req,
+ "Stopping all operations on this adapter.\n",
+ *(unsigned long long*)
+ (&qtcb->bottom.support.req_handle),
zfcp_get_busid_by_adapter(adapter));
- }
- debug_text_exception(adapter->erp_dbf, 0, "prot_dup_id");
zfcp_erp_adapter_shutdown(adapter, 0);
- zfcp_cmd_dbf_event_fsf("dupreqid", fsf_req,
- &fsf_req->qtcb->prefix.prot_status_qual,
- sizeof (union fsf_prot_status_qual));
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_PROT_LINK_DOWN:
- /*
- * 'test and set' is not atomic here -
- * it's ok as long as calls to our response queue handler
- * (and thus execution of this code here) are serialized
- * by the qdio module
- */
- if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
- &adapter->status)) {
- switch (fsf_req->qtcb->prefix.prot_status_qual.
- locallink_error.code) {
- case FSF_PSQ_LINK_NOLIGHT:
- ZFCP_LOG_INFO("The local link to adapter %s "
- "is down (no light detected).\n",
- zfcp_get_busid_by_adapter(
- adapter));
- break;
- case FSF_PSQ_LINK_WRAPPLUG:
- ZFCP_LOG_INFO("The local link to adapter %s "
- "is down (wrap plug detected).\n",
- zfcp_get_busid_by_adapter(
- adapter));
- break;
- case FSF_PSQ_LINK_NOFCP:
- ZFCP_LOG_INFO("The local link to adapter %s "
- "is down (adjacent node on "
- "link does not support FCP).\n",
- zfcp_get_busid_by_adapter(
- adapter));
- break;
- default:
- ZFCP_LOG_INFO("The local link to adapter %s "
- "is down "
- "(warning: unknown reason "
- "code).\n",
- zfcp_get_busid_by_adapter(
- adapter));
- break;
-
- }
- /*
- * Due to the 'erp failed' flag the adapter won't
- * be recovered but will be just set to 'blocked'
- * state. All subordinary devices will have state
- * 'blocked' and 'erp failed', too.
- * Thus the adapter is still able to provide
- * 'link up' status without being flooded with
- * requests.
- * (note: even 'close port' is not permitted)
- */
- ZFCP_LOG_INFO("Stopping all operations for adapter "
- "%s.\n",
- zfcp_get_busid_by_adapter(adapter));
- atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
- ZFCP_STATUS_COMMON_ERP_FAILED,
- &adapter->status);
- zfcp_erp_adapter_reopen(adapter, 0);
- }
+ zfcp_fsf_link_down_info_eval(adapter,
+ &prot_status_qual->link_down_info);
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_PROT_REEST_QUEUE:
- debug_text_event(adapter->erp_dbf, 1, "prot_reest_queue");
- ZFCP_LOG_INFO("The local link to adapter with "
+ ZFCP_LOG_NORMAL("The local link to adapter with "
"%s was re-plugged. "
"Re-starting operations on this adapter.\n",
zfcp_get_busid_by_adapter(adapter));
@@ -495,9 +405,6 @@ zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *fsf_req)
zfcp_erp_adapter_reopen(adapter,
ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED
| ZFCP_STATUS_COMMON_ERP_FAILED);
- zfcp_cmd_dbf_event_fsf("reestque", fsf_req,
- &fsf_req->qtcb->prefix.prot_status_qual,
- sizeof (union fsf_prot_status_qual));
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
@@ -507,12 +414,7 @@ zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *fsf_req)
"Restarting all operations on this "
"adapter.\n",
zfcp_get_busid_by_adapter(adapter));
- debug_text_event(adapter->erp_dbf, 0, "prot_err_sta");
- /* restart operation on this adapter */
zfcp_erp_adapter_reopen(adapter, 0);
- zfcp_cmd_dbf_event_fsf("proterrs", fsf_req,
- &fsf_req->qtcb->prefix.prot_status_qual,
- sizeof (union fsf_prot_status_qual));
fsf_req->status |= ZFCP_STATUS_FSFREQ_RETRY;
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
@@ -524,11 +426,7 @@ zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *fsf_req)
"Stopping all operations on this adapter. "
"(debug info 0x%x).\n",
zfcp_get_busid_by_adapter(adapter),
- fsf_req->qtcb->prefix.prot_status);
- debug_text_event(adapter->erp_dbf, 0, "prot_inval:");
- debug_exception(adapter->erp_dbf, 0,
- &fsf_req->qtcb->prefix.prot_status,
- sizeof (u32));
+ qtcb->prefix.prot_status);
zfcp_erp_adapter_shutdown(adapter, 0);
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
}
@@ -568,28 +466,18 @@ zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *fsf_req)
"(debug info 0x%x).\n",
zfcp_get_busid_by_adapter(fsf_req->adapter),
fsf_req->qtcb->header.fsf_command);
- debug_text_exception(fsf_req->adapter->erp_dbf, 0,
- "fsf_s_unknown");
zfcp_erp_adapter_shutdown(fsf_req->adapter, 0);
- zfcp_cmd_dbf_event_fsf("unknownc", fsf_req,
- &fsf_req->qtcb->header.fsf_status_qual,
- sizeof (union fsf_status_qual));
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_FCP_RSP_AVAILABLE:
ZFCP_LOG_DEBUG("FCP Sense data will be presented to the "
"SCSI stack.\n");
- debug_text_event(fsf_req->adapter->erp_dbf, 3, "fsf_s_rsp");
break;
case FSF_ADAPTER_STATUS_AVAILABLE:
- debug_text_event(fsf_req->adapter->erp_dbf, 2, "fsf_s_astatus");
zfcp_fsf_fsfstatus_qual_eval(fsf_req);
break;
-
- default:
- break;
}
skip_fsfstatus:
@@ -617,44 +505,28 @@ zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *fsf_req)
switch (fsf_req->qtcb->header.fsf_status_qual.word[0]) {
case FSF_SQ_FCP_RSP_AVAILABLE:
- debug_text_event(fsf_req->adapter->erp_dbf, 4, "fsf_sq_rsp");
break;
case FSF_SQ_RETRY_IF_POSSIBLE:
/* The SCSI-stack may now issue retries or escalate */
- debug_text_event(fsf_req->adapter->erp_dbf, 2, "fsf_sq_retry");
- zfcp_cmd_dbf_event_fsf("sqretry", fsf_req,
- &fsf_req->qtcb->header.fsf_status_qual,
- sizeof (union fsf_status_qual));
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_SQ_COMMAND_ABORTED:
/* Carry the aborted state on to upper layer */
- debug_text_event(fsf_req->adapter->erp_dbf, 2, "fsf_sq_abort");
- zfcp_cmd_dbf_event_fsf("sqabort", fsf_req,
- &fsf_req->qtcb->header.fsf_status_qual,
- sizeof (union fsf_status_qual));
fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTED;
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_SQ_NO_RECOM:
- debug_text_exception(fsf_req->adapter->erp_dbf, 0,
- "fsf_sq_no_rec");
ZFCP_LOG_NORMAL("bug: No recommendation could be given for a"
"problem on the adapter %s "
"Stopping all operations on this adapter. ",
zfcp_get_busid_by_adapter(fsf_req->adapter));
zfcp_erp_adapter_shutdown(fsf_req->adapter, 0);
- zfcp_cmd_dbf_event_fsf("sqnrecom", fsf_req,
- &fsf_req->qtcb->header.fsf_status_qual,
- sizeof (union fsf_status_qual));
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_SQ_ULP_PROGRAMMING_ERROR:
ZFCP_LOG_NORMAL("error: not enough SBALs for data transfer "
"(adapter %s)\n",
zfcp_get_busid_by_adapter(fsf_req->adapter));
- debug_text_exception(fsf_req->adapter->erp_dbf, 0,
- "fsf_sq_ulp_err");
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
@@ -668,13 +540,6 @@ zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *fsf_req)
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL,
(char *) &fsf_req->qtcb->header.fsf_status_qual,
sizeof (union fsf_status_qual));
- debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_sq_inval:");
- debug_exception(fsf_req->adapter->erp_dbf, 0,
- &fsf_req->qtcb->header.fsf_status_qual.word[0],
- sizeof (u32));
- zfcp_cmd_dbf_event_fsf("squndef", fsf_req,
- &fsf_req->qtcb->header.fsf_status_qual,
- sizeof (union fsf_status_qual));
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
}
@@ -682,6 +547,110 @@ zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *fsf_req)
return retval;
}
+/**
+ * zfcp_fsf_link_down_info_eval - evaluate link down information block
+ */
+static void
+zfcp_fsf_link_down_info_eval(struct zfcp_adapter *adapter,
+ struct fsf_link_down_info *link_down)
+{
+ switch (link_down->error_code) {
+ case FSF_PSQ_LINK_NO_LIGHT:
+ ZFCP_LOG_NORMAL("The local link to adapter %s is down "
+ "(no light detected)\n",
+ zfcp_get_busid_by_adapter(adapter));
+ break;
+ case FSF_PSQ_LINK_WRAP_PLUG:
+ ZFCP_LOG_NORMAL("The local link to adapter %s is down "
+ "(wrap plug detected)\n",
+ zfcp_get_busid_by_adapter(adapter));
+ break;
+ case FSF_PSQ_LINK_NO_FCP:
+ ZFCP_LOG_NORMAL("The local link to adapter %s is down "
+ "(adjacent node on link does not support FCP)\n",
+ zfcp_get_busid_by_adapter(adapter));
+ break;
+ case FSF_PSQ_LINK_FIRMWARE_UPDATE:
+ ZFCP_LOG_NORMAL("The local link to adapter %s is down "
+ "(firmware update in progress)\n",
+ zfcp_get_busid_by_adapter(adapter));
+ break;
+ case FSF_PSQ_LINK_INVALID_WWPN:
+ ZFCP_LOG_NORMAL("The local link to adapter %s is down "
+ "(duplicate or invalid WWPN detected)\n",
+ zfcp_get_busid_by_adapter(adapter));
+ break;
+ case FSF_PSQ_LINK_NO_NPIV_SUPPORT:
+ ZFCP_LOG_NORMAL("The local link to adapter %s is down "
+ "(no support for NPIV by Fabric)\n",
+ zfcp_get_busid_by_adapter(adapter));
+ break;
+ case FSF_PSQ_LINK_NO_FCP_RESOURCES:
+ ZFCP_LOG_NORMAL("The local link to adapter %s is down "
+ "(out of resource in FCP daughtercard)\n",
+ zfcp_get_busid_by_adapter(adapter));
+ break;
+ case FSF_PSQ_LINK_NO_FABRIC_RESOURCES:
+ ZFCP_LOG_NORMAL("The local link to adapter %s is down "
+ "(out of resource in Fabric)\n",
+ zfcp_get_busid_by_adapter(adapter));
+ break;
+ case FSF_PSQ_LINK_FABRIC_LOGIN_UNABLE:
+ ZFCP_LOG_NORMAL("The local link to adapter %s is down "
+ "(unable to Fabric login)\n",
+ zfcp_get_busid_by_adapter(adapter));
+ break;
+ case FSF_PSQ_LINK_WWPN_ASSIGNMENT_CORRUPTED:
+ ZFCP_LOG_NORMAL("WWPN assignment file corrupted on adapter %s\n",
+ zfcp_get_busid_by_adapter(adapter));
+ break;
+ case FSF_PSQ_LINK_MODE_TABLE_CURRUPTED:
+ ZFCP_LOG_NORMAL("Mode table corrupted on adapter %s\n",
+ zfcp_get_busid_by_adapter(adapter));
+ break;
+ case FSF_PSQ_LINK_NO_WWPN_ASSIGNMENT:
+ ZFCP_LOG_NORMAL("No WWPN for assignment table on adapter %s\n",
+ zfcp_get_busid_by_adapter(adapter));
+ break;
+ default:
+ ZFCP_LOG_NORMAL("The local link to adapter %s is down "
+ "(warning: unknown reason code %d)\n",
+ zfcp_get_busid_by_adapter(adapter),
+ link_down->error_code);
+ }
+
+ if (adapter->connection_features & FSF_FEATURE_NPIV_MODE)
+ ZFCP_LOG_DEBUG("Debug information to link down: "
+ "primary_status=0x%02x "
+ "ioerr_code=0x%02x "
+ "action_code=0x%02x "
+ "reason_code=0x%02x "
+ "explanation_code=0x%02x "
+ "vendor_specific_code=0x%02x\n",
+ link_down->primary_status,
+ link_down->ioerr_code,
+ link_down->action_code,
+ link_down->reason_code,
+ link_down->explanation_code,
+ link_down->vendor_specific_code);
+
+ if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
+ &adapter->status)) {
+ atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
+ &adapter->status);
+ switch (link_down->error_code) {
+ case FSF_PSQ_LINK_NO_LIGHT:
+ case FSF_PSQ_LINK_WRAP_PLUG:
+ case FSF_PSQ_LINK_NO_FCP:
+ case FSF_PSQ_LINK_FIRMWARE_UPDATE:
+ zfcp_erp_adapter_reopen(adapter, 0);
+ break;
+ default:
+ zfcp_erp_adapter_failed(adapter);
+ }
+ }
+}
+
/*
* function: zfcp_fsf_req_dispatch
*
@@ -696,11 +665,6 @@ zfcp_fsf_req_dispatch(struct zfcp_fsf_req *fsf_req)
struct zfcp_adapter *adapter = fsf_req->adapter;
int retval = 0;
- if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
- ZFCP_LOG_TRACE("fsf_req=%p, QTCB=%p\n", fsf_req, fsf_req->qtcb);
- ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE,
- (char *) fsf_req->qtcb, sizeof(struct fsf_qtcb));
- }
switch (fsf_req->fsf_command) {
@@ -760,13 +724,13 @@ zfcp_fsf_req_dispatch(struct zfcp_fsf_req *fsf_req)
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
ZFCP_LOG_NORMAL("bug: Command issued by the device driver is "
"not supported by the adapter %s\n",
- zfcp_get_busid_by_adapter(fsf_req->adapter));
+ zfcp_get_busid_by_adapter(adapter));
if (fsf_req->fsf_command != fsf_req->qtcb->header.fsf_command)
ZFCP_LOG_NORMAL
("bug: Command issued by the device driver differs "
"from the command returned by the adapter %s "
"(debug info 0x%x, 0x%x).\n",
- zfcp_get_busid_by_adapter(fsf_req->adapter),
+ zfcp_get_busid_by_adapter(adapter),
fsf_req->fsf_command,
fsf_req->qtcb->header.fsf_command);
}
@@ -774,8 +738,6 @@ zfcp_fsf_req_dispatch(struct zfcp_fsf_req *fsf_req)
if (!erp_action)
return retval;
- debug_text_event(adapter->erp_dbf, 3, "a_frh");
- debug_event(adapter->erp_dbf, 3, &erp_action->action, sizeof (int));
zfcp_erp_async_handler(erp_action, 0);
return retval;
@@ -821,7 +783,7 @@ zfcp_fsf_status_read(struct zfcp_adapter *adapter, int req_flags)
goto failed_buf;
}
memset(status_buffer, 0, sizeof (struct fsf_status_read_buffer));
- fsf_req->data.status_read.buffer = status_buffer;
+ fsf_req->data = (unsigned long) status_buffer;
/* insert pointer to respective buffer */
sbale = zfcp_qdio_sbale_curr(fsf_req);
@@ -846,6 +808,7 @@ zfcp_fsf_status_read(struct zfcp_adapter *adapter, int req_flags)
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->request_queue.queue_lock, lock_flags);
return retval;
@@ -859,7 +822,7 @@ zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *fsf_req)
struct zfcp_port *port;
unsigned long flags;
- status_buffer = fsf_req->data.status_read.buffer;
+ status_buffer = (struct fsf_status_read_buffer *) fsf_req->data;
adapter = fsf_req->adapter;
read_lock_irqsave(&zfcp_data.config_lock, flags);
@@ -918,38 +881,33 @@ zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req)
int retval = 0;
struct zfcp_adapter *adapter = fsf_req->adapter;
struct fsf_status_read_buffer *status_buffer =
- fsf_req->data.status_read.buffer;
+ (struct fsf_status_read_buffer *) fsf_req->data;
if (fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED) {
+ zfcp_hba_dbf_event_fsf_unsol("dism", adapter, status_buffer);
mempool_free(status_buffer, adapter->pool.data_status_read);
zfcp_fsf_req_free(fsf_req);
goto out;
}
+ zfcp_hba_dbf_event_fsf_unsol("read", adapter, status_buffer);
+
switch (status_buffer->status_type) {
case FSF_STATUS_READ_PORT_CLOSED:
- debug_text_event(adapter->erp_dbf, 3, "unsol_pclosed:");
- debug_event(adapter->erp_dbf, 3,
- &status_buffer->d_id, sizeof (u32));
zfcp_fsf_status_read_port_closed(fsf_req);
break;
case FSF_STATUS_READ_INCOMING_ELS:
- debug_text_event(adapter->erp_dbf, 3, "unsol_els:");
zfcp_fsf_incoming_els(fsf_req);
break;
case FSF_STATUS_READ_SENSE_DATA_AVAIL:
- debug_text_event(adapter->erp_dbf, 3, "unsol_sense:");
ZFCP_LOG_INFO("unsolicited sense data received (adapter %s)\n",
zfcp_get_busid_by_adapter(adapter));
- ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL, (char *) status_buffer,
- sizeof(struct fsf_status_read_buffer));
break;
case FSF_STATUS_READ_BIT_ERROR_THRESHOLD:
- debug_text_event(adapter->erp_dbf, 3, "unsol_bit_err:");
ZFCP_LOG_NORMAL("Bit error threshold data received:\n");
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL,
(char *) status_buffer,
@@ -957,17 +915,32 @@ zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req)
break;
case FSF_STATUS_READ_LINK_DOWN:
- debug_text_event(adapter->erp_dbf, 0, "unsol_link_down:");
- ZFCP_LOG_INFO("Local link to adapter %s is down\n",
+ switch (status_buffer->status_subtype) {
+ case FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK:
+ ZFCP_LOG_INFO("Physical link to adapter %s is down\n",
+ zfcp_get_busid_by_adapter(adapter));
+ break;
+ case FSF_STATUS_READ_SUB_FDISC_FAILED:
+ ZFCP_LOG_INFO("Local link to adapter %s is down "
+ "due to failed FDISC login\n",
zfcp_get_busid_by_adapter(adapter));
- atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
- &adapter->status);
- zfcp_erp_adapter_failed(adapter);
+ break;
+ case FSF_STATUS_READ_SUB_FIRMWARE_UPDATE:
+ ZFCP_LOG_INFO("Local link to adapter %s is down "
+ "due to firmware update on adapter\n",
+ zfcp_get_busid_by_adapter(adapter));
+ break;
+ default:
+ ZFCP_LOG_INFO("Local link to adapter %s is down "
+ "due to unknown reason\n",
+ zfcp_get_busid_by_adapter(adapter));
+ };
+ zfcp_fsf_link_down_info_eval(adapter,
+ (struct fsf_link_down_info *) &status_buffer->payload);
break;
case FSF_STATUS_READ_LINK_UP:
- debug_text_event(adapter->erp_dbf, 2, "unsol_link_up:");
- ZFCP_LOG_INFO("Local link to adapter %s was replugged. "
+ ZFCP_LOG_NORMAL("Local link to adapter %s was replugged. "
"Restarting operations on this adapter\n",
zfcp_get_busid_by_adapter(adapter));
/* All ports should be marked as ready to run again */
@@ -980,35 +953,40 @@ zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req)
break;
case FSF_STATUS_READ_CFDC_UPDATED:
- debug_text_event(adapter->erp_dbf, 2, "unsol_cfdc_update:");
- ZFCP_LOG_INFO("CFDC has been updated on the adapter %s\n",
+ ZFCP_LOG_NORMAL("CFDC has been updated on the adapter %s\n",
zfcp_get_busid_by_adapter(adapter));
zfcp_erp_adapter_access_changed(adapter);
break;
case FSF_STATUS_READ_CFDC_HARDENED:
- debug_text_event(adapter->erp_dbf, 2, "unsol_cfdc_harden:");
switch (status_buffer->status_subtype) {
case FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE:
- ZFCP_LOG_INFO("CFDC of adapter %s saved on SE\n",
+ ZFCP_LOG_NORMAL("CFDC of adapter %s saved on SE\n",
zfcp_get_busid_by_adapter(adapter));
break;
case FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE2:
- ZFCP_LOG_INFO("CFDC of adapter %s has been copied "
+ ZFCP_LOG_NORMAL("CFDC of adapter %s has been copied "
"to the secondary SE\n",
zfcp_get_busid_by_adapter(adapter));
break;
default:
- ZFCP_LOG_INFO("CFDC of adapter %s has been hardened\n",
+ ZFCP_LOG_NORMAL("CFDC of adapter %s has been hardened\n",
zfcp_get_busid_by_adapter(adapter));
}
break;
+ case FSF_STATUS_READ_FEATURE_UPDATE_ALERT:
+ debug_text_event(adapter->erp_dbf, 2, "unsol_features:");
+ ZFCP_LOG_INFO("List of supported features on adapter %s has "
+ "been changed from 0x%08X to 0x%08X\n",
+ zfcp_get_busid_by_adapter(adapter),
+ *(u32*) (status_buffer->payload + 4),
+ *(u32*) (status_buffer->payload));
+ adapter->adapter_features = *(u32*) status_buffer->payload;
+ break;
+
default:
- debug_text_event(adapter->erp_dbf, 0, "unsol_unknown:");
- debug_exception(adapter->erp_dbf, 0,
- &status_buffer->status_type, sizeof (u32));
- ZFCP_LOG_NORMAL("bug: An unsolicited status packet of unknown "
+ ZFCP_LOG_NORMAL("warning: An unsolicited status packet of unknown "
"type was received (debug info 0x%x)\n",
status_buffer->status_type);
ZFCP_LOG_DEBUG("Dump of status_read_buffer %p:\n",
@@ -1093,7 +1071,7 @@ zfcp_fsf_abort_fcp_command(unsigned long old_req_id,
sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
- fsf_req->data.abort_fcp_command.unit = unit;
+ fsf_req->data = (unsigned long) unit;
/* set handles of unit and its parent port in QTCB */
fsf_req->qtcb->header.lun_handle = unit->handle;
@@ -1139,7 +1117,7 @@ static int
zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req)
{
int retval = -EINVAL;
- struct zfcp_unit *unit = new_fsf_req->data.abort_fcp_command.unit;
+ struct zfcp_unit *unit;
unsigned char status_qual =
new_fsf_req->qtcb->header.fsf_status_qual.word[0];
@@ -1150,6 +1128,8 @@ zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req)
goto skip_fsfstatus;
}
+ unit = (struct zfcp_unit *) new_fsf_req->data;
+
/* evaluate FSF status in QTCB */
switch (new_fsf_req->qtcb->header.fsf_status) {
@@ -1364,7 +1344,7 @@ zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool,
sbale[3].addr = zfcp_sg_to_address(&ct->resp[0]);
sbale[3].length = ct->resp[0].length;
sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY;
- } else if (adapter->supported_features &
+ } else if (adapter->adapter_features &
FSF_FEATURE_ELS_CT_CHAINED_SBALS) {
/* try to use chained SBALs */
bytes = zfcp_qdio_sbals_from_sg(fsf_req,
@@ -1414,7 +1394,9 @@ zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool,
fsf_req->qtcb->header.port_handle = port->handle;
fsf_req->qtcb->bottom.support.service_class = adapter->fc_service_class;
fsf_req->qtcb->bottom.support.timeout = ct->timeout;
- fsf_req->data.send_ct = ct;
+ fsf_req->data = (unsigned long) ct;
+
+ zfcp_san_dbf_event_ct_request(fsf_req);
/* start QDIO request for this FSF request */
ret = zfcp_fsf_req_send(fsf_req, ct->timer);
@@ -1445,10 +1427,10 @@ zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool,
* zfcp_fsf_send_ct_handler - handler for Generic Service requests
* @fsf_req: pointer to struct zfcp_fsf_req
*
- * Data specific for the Generic Service request is passed by
- * fsf_req->data.send_ct
- * Usually a specific handler for the request is called via
- * fsf_req->data.send_ct->handler at end of this function.
+ * Data specific for the Generic Service request is passed using
+ * fsf_req->data. There we find the pointer to struct zfcp_send_ct.
+ * Usually a specific handler for the CT request is called which is
+ * found in this structure.
*/
static int
zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req)
@@ -1462,7 +1444,7 @@ zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req)
u16 subtable, rule, counter;
adapter = fsf_req->adapter;
- send_ct = fsf_req->data.send_ct;
+ send_ct = (struct zfcp_send_ct *) fsf_req->data;
port = send_ct->port;
header = &fsf_req->qtcb->header;
bottom = &fsf_req->qtcb->bottom.support;
@@ -1474,6 +1456,7 @@ zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req)
switch (header->fsf_status) {
case FSF_GOOD:
+ zfcp_san_dbf_event_ct_response(fsf_req);
retval = 0;
break;
@@ -1634,7 +1617,7 @@ zfcp_fsf_send_els(struct zfcp_send_els *els)
{
volatile struct qdio_buffer_element *sbale;
struct zfcp_fsf_req *fsf_req;
- fc_id_t d_id;
+ u32 d_id;
struct zfcp_adapter *adapter;
unsigned long lock_flags;
int bytes;
@@ -1664,7 +1647,7 @@ zfcp_fsf_send_els(struct zfcp_send_els *els)
sbale[3].addr = zfcp_sg_to_address(&els->resp[0]);
sbale[3].length = els->resp[0].length;
sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY;
- } else if (adapter->supported_features &
+ } else if (adapter->adapter_features &
FSF_FEATURE_ELS_CT_CHAINED_SBALS) {
/* try to use chained SBALs */
bytes = zfcp_qdio_sbals_from_sg(fsf_req,
@@ -1714,10 +1697,12 @@ zfcp_fsf_send_els(struct zfcp_send_els *els)
fsf_req->qtcb->bottom.support.d_id = d_id;
fsf_req->qtcb->bottom.support.service_class = adapter->fc_service_class;
fsf_req->qtcb->bottom.support.timeout = ZFCP_ELS_TIMEOUT;
- fsf_req->data.send_els = els;
+ fsf_req->data = (unsigned long) els;
sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
+ zfcp_san_dbf_event_els_request(fsf_req);
+
/* start QDIO request for this FSF request */
ret = zfcp_fsf_req_send(fsf_req, els->timer);
if (ret) {
@@ -1746,23 +1731,23 @@ zfcp_fsf_send_els(struct zfcp_send_els *els)
* zfcp_fsf_send_els_handler - handler for ELS commands
* @fsf_req: pointer to struct zfcp_fsf_req
*
- * Data specific for the ELS command is passed by
- * fsf_req->data.send_els
- * Usually a specific handler for the command is called via
- * fsf_req->data.send_els->handler at end of this function.
+ * Data specific for the ELS command is passed using
+ * fsf_req->data. There we find the pointer to struct zfcp_send_els.
+ * Usually a specific handler for the ELS command is called which is
+ * found in this structure.
*/
static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req)
{
struct zfcp_adapter *adapter;
struct zfcp_port *port;
- fc_id_t d_id;
+ u32 d_id;
struct fsf_qtcb_header *header;
struct fsf_qtcb_bottom_support *bottom;
struct zfcp_send_els *send_els;
int retval = -EINVAL;
u16 subtable, rule, counter;
- send_els = fsf_req->data.send_els;
+ send_els = (struct zfcp_send_els *) fsf_req->data;
adapter = send_els->adapter;
port = send_els->port;
d_id = send_els->d_id;
@@ -1775,6 +1760,7 @@ static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req)
switch (header->fsf_status) {
case FSF_GOOD:
+ zfcp_san_dbf_event_els_response(fsf_req);
retval = 0;
break;
@@ -1954,7 +1940,9 @@ zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
erp_action->fsf_req->erp_action = erp_action;
erp_action->fsf_req->qtcb->bottom.config.feature_selection =
- (FSF_FEATURE_CFDC | FSF_FEATURE_LUN_SHARING);
+ FSF_FEATURE_CFDC |
+ FSF_FEATURE_LUN_SHARING |
+ FSF_FEATURE_UPDATE_ALERT;
/* start QDIO request for this FSF request */
retval = zfcp_fsf_req_send(erp_action->fsf_req, &erp_action->timer);
@@ -1990,29 +1978,36 @@ zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok)
{
struct fsf_qtcb_bottom_config *bottom;
struct zfcp_adapter *adapter = fsf_req->adapter;
+ struct Scsi_Host *shost = adapter->scsi_host;
bottom = &fsf_req->qtcb->bottom.config;
ZFCP_LOG_DEBUG("low/high QTCB version 0x%x/0x%x of FSF\n",
bottom->low_qtcb_version, bottom->high_qtcb_version);
adapter->fsf_lic_version = bottom->lic_version;
- adapter->supported_features = bottom->supported_features;
+ adapter->adapter_features = bottom->adapter_features;
+ adapter->connection_features = bottom->connection_features;
adapter->peer_wwpn = 0;
adapter->peer_wwnn = 0;
adapter->peer_d_id = 0;
if (xchg_ok) {
- adapter->wwnn = bottom->nport_serv_param.wwnn;
- adapter->wwpn = bottom->nport_serv_param.wwpn;
- adapter->s_id = bottom->s_id & ZFCP_DID_MASK;
+ 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;
adapter->fc_topology = bottom->fc_topology;
- adapter->fc_link_speed = bottom->fc_link_speed;
adapter->hydra_version = bottom->adapter_type;
+ if (adapter->physical_wwpn == 0)
+ adapter->physical_wwpn = fc_host_port_name(shost);
+ if (adapter->physical_s_id == 0)
+ adapter->physical_s_id = fc_host_port_id(shost);
} else {
- adapter->wwnn = 0;
- adapter->wwpn = 0;
- adapter->s_id = 0;
+ fc_host_node_name(shost) = 0;
+ fc_host_port_name(shost) = 0;
+ fc_host_port_id(shost) = 0;
+ fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
adapter->fc_topology = 0;
- adapter->fc_link_speed = 0;
adapter->hydra_version = 0;
}
@@ -2022,26 +2017,28 @@ zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok)
adapter->peer_wwnn = bottom->plogi_payload.wwnn;
}
- if(adapter->supported_features & FSF_FEATURE_HBAAPI_MANAGEMENT){
+ if (adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT) {
adapter->hardware_version = bottom->hardware_version;
- memcpy(adapter->serial_number, bottom->serial_number, 17);
- EBCASC(adapter->serial_number, sizeof(adapter->serial_number));
+ memcpy(fc_host_serial_number(shost), bottom->serial_number,
+ min(FC_SERIAL_NUMBER_SIZE, 17));
+ EBCASC(fc_host_serial_number(shost),
+ min(FC_SERIAL_NUMBER_SIZE, 17));
}
ZFCP_LOG_NORMAL("The adapter %s reported the following characteristics:\n"
- "WWNN 0x%016Lx, "
- "WWPN 0x%016Lx, "
- "S_ID 0x%08x,\n"
- "adapter version 0x%x, "
- "LIC version 0x%x, "
- "FC link speed %d Gb/s\n",
- zfcp_get_busid_by_adapter(adapter),
- adapter->wwnn,
- adapter->wwpn,
- (unsigned int) adapter->s_id,
- adapter->hydra_version,
- adapter->fsf_lic_version,
- adapter->fc_link_speed);
+ "WWNN 0x%016Lx, "
+ "WWPN 0x%016Lx, "
+ "S_ID 0x%08x,\n"
+ "adapter version 0x%x, "
+ "LIC version 0x%x, "
+ "FC link speed %d Gb/s\n",
+ zfcp_get_busid_by_adapter(adapter),
+ (wwn_t) fc_host_node_name(shost),
+ (wwn_t) fc_host_port_name(shost),
+ fc_host_port_id(shost),
+ adapter->hydra_version,
+ adapter->fsf_lic_version,
+ fc_host_speed(shost));
if (ZFCP_QTCB_VERSION < bottom->low_qtcb_version) {
ZFCP_LOG_NORMAL("error: the adapter %s "
"only supports newer control block "
@@ -2062,7 +2059,6 @@ zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok)
zfcp_erp_adapter_shutdown(adapter, 0);
return -EIO;
}
- zfcp_set_fc_host_attrs(adapter);
return 0;
}
@@ -2078,11 +2074,12 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req)
{
struct fsf_qtcb_bottom_config *bottom;
struct zfcp_adapter *adapter = fsf_req->adapter;
+ struct fsf_qtcb *qtcb = fsf_req->qtcb;
if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)
return -EIO;
- switch (fsf_req->qtcb->header.fsf_status) {
+ switch (qtcb->header.fsf_status) {
case FSF_GOOD:
if (zfcp_fsf_exchange_config_evaluate(fsf_req, 1))
@@ -2112,7 +2109,7 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req)
zfcp_erp_adapter_shutdown(adapter, 0);
return -EIO;
case FSF_TOPO_FABRIC:
- ZFCP_LOG_INFO("Switched fabric fibrechannel "
+ ZFCP_LOG_NORMAL("Switched fabric fibrechannel "
"network detected at adapter %s.\n",
zfcp_get_busid_by_adapter(adapter));
break;
@@ -2130,7 +2127,7 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req)
zfcp_erp_adapter_shutdown(adapter, 0);
return -EIO;
}
- bottom = &fsf_req->qtcb->bottom.config;
+ bottom = &qtcb->bottom.config;
if (bottom->max_qtcb_size < sizeof(struct fsf_qtcb)) {
ZFCP_LOG_NORMAL("bug: Maximum QTCB size (%d bytes) "
"allowed by the adapter %s "
@@ -2155,12 +2152,10 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req)
if (zfcp_fsf_exchange_config_evaluate(fsf_req, 0))
return -EIO;
- ZFCP_LOG_INFO("Local link to adapter %s is down\n",
- zfcp_get_busid_by_adapter(adapter));
- atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK |
- ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
- &adapter->status);
- zfcp_erp_adapter_failed(adapter);
+ atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status);
+
+ zfcp_fsf_link_down_info_eval(adapter,
+ &qtcb->header.fsf_status_qual.link_down_info);
break;
default:
debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf-stat-ng");
@@ -2174,11 +2169,13 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req)
/**
* zfcp_fsf_exchange_port_data - request information about local port
+ * @erp_action: ERP action for the adapter for which port data is requested
* @adapter: for which port data is requested
* @data: response to exchange port data request
*/
int
-zfcp_fsf_exchange_port_data(struct zfcp_adapter *adapter,
+zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action,
+ struct zfcp_adapter *adapter,
struct fsf_qtcb_bottom_port *data)
{
volatile struct qdio_buffer_element *sbale;
@@ -2187,7 +2184,7 @@ zfcp_fsf_exchange_port_data(struct zfcp_adapter *adapter,
struct zfcp_fsf_req *fsf_req;
struct timer_list *timer;
- if(!(adapter->supported_features & FSF_FEATURE_HBAAPI_MANAGEMENT)){
+ if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) {
ZFCP_LOG_INFO("error: exchange port data "
"command not supported by adapter %s\n",
zfcp_get_busid_by_adapter(adapter));
@@ -2211,12 +2208,18 @@ zfcp_fsf_exchange_port_data(struct zfcp_adapter *adapter,
goto out;
}
+ if (erp_action) {
+ erp_action->fsf_req = fsf_req;
+ fsf_req->erp_action = erp_action;
+ }
+
+ if (data)
+ fsf_req->data = (unsigned long) data;
+
sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
- fsf_req->data.port_data = data;
-
init_timer(timer);
timer->function = zfcp_fsf_request_timeout_handler;
timer->data = (unsigned long) adapter;
@@ -2228,6 +2231,8 @@ zfcp_fsf_exchange_port_data(struct zfcp_adapter *adapter,
"command on the adapter %s\n",
zfcp_get_busid_by_adapter(adapter));
zfcp_fsf_req_free(fsf_req);
+ if (erp_action)
+ erp_action->fsf_req = NULL;
write_unlock_irqrestore(&adapter->request_queue.queue_lock,
lock_flags);
goto out;
@@ -2256,21 +2261,42 @@ zfcp_fsf_exchange_port_data(struct zfcp_adapter *adapter,
static void
zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *fsf_req)
{
- struct fsf_qtcb_bottom_port *bottom;
- struct fsf_qtcb_bottom_port *data = fsf_req->data.port_data;
+ struct zfcp_adapter *adapter = fsf_req->adapter;
+ struct Scsi_Host *shost = adapter->scsi_host;
+ struct fsf_qtcb *qtcb = fsf_req->qtcb;
+ struct fsf_qtcb_bottom_port *bottom, *data;
if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)
return;
- switch (fsf_req->qtcb->header.fsf_status) {
+ switch (qtcb->header.fsf_status) {
case FSF_GOOD:
- bottom = &fsf_req->qtcb->bottom.port;
- memcpy(data, bottom, sizeof(*data));
+ atomic_set_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status);
+
+ bottom = &qtcb->bottom.port;
+ data = (struct fsf_qtcb_bottom_port*) fsf_req->data;
+ if (data)
+ memcpy(data, bottom, sizeof(struct fsf_qtcb_bottom_port));
+ if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) {
+ adapter->physical_wwpn = bottom->wwpn;
+ adapter->physical_s_id = bottom->fc_port_id;
+ } else {
+ adapter->physical_wwpn = fc_host_port_name(shost);
+ adapter->physical_s_id = fc_host_port_id(shost);
+ }
+ fc_host_maxframe_size(shost) = bottom->maximum_frame_size;
+ break;
+
+ case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE:
+ atomic_set_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status);
+
+ zfcp_fsf_link_down_info_eval(adapter,
+ &qtcb->header.fsf_status_qual.link_down_info);
break;
default:
- debug_text_event(fsf_req->adapter->erp_dbf, 0, "xchg-port-ng");
- debug_event(fsf_req->adapter->erp_dbf, 0,
+ debug_text_event(adapter->erp_dbf, 0, "xchg-port-ng");
+ debug_event(adapter->erp_dbf, 0,
&fsf_req->qtcb->header.fsf_status, sizeof(u32));
}
}
@@ -2312,7 +2338,7 @@ zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
erp_action->fsf_req->qtcb->bottom.support.d_id = erp_action->port->d_id;
atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->port->status);
- erp_action->fsf_req->data.open_port.port = erp_action->port;
+ erp_action->fsf_req->data = (unsigned long) erp_action->port;
erp_action->fsf_req->erp_action = erp_action;
/* start QDIO request for this FSF request */
@@ -2353,7 +2379,7 @@ zfcp_fsf_open_port_handler(struct zfcp_fsf_req *fsf_req)
struct fsf_qtcb_header *header;
u16 subtable, rule, counter;
- port = fsf_req->data.open_port.port;
+ port = (struct zfcp_port *) fsf_req->data;
header = &fsf_req->qtcb->header;
if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
@@ -2566,7 +2592,7 @@ zfcp_fsf_close_port(struct zfcp_erp_action *erp_action)
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->port->status);
- erp_action->fsf_req->data.close_port.port = erp_action->port;
+ erp_action->fsf_req->data = (unsigned long) erp_action->port;
erp_action->fsf_req->erp_action = erp_action;
erp_action->fsf_req->qtcb->header.port_handle =
erp_action->port->handle;
@@ -2606,7 +2632,7 @@ zfcp_fsf_close_port_handler(struct zfcp_fsf_req *fsf_req)
int retval = -EINVAL;
struct zfcp_port *port;
- port = fsf_req->data.close_port.port;
+ port = (struct zfcp_port *) fsf_req->data;
if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
/* don't change port status in our bookkeeping */
@@ -2703,8 +2729,8 @@ zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action)
atomic_set_mask(ZFCP_STATUS_PORT_PHYS_CLOSING,
&erp_action->port->status);
/* save a pointer to this port */
- erp_action->fsf_req->data.close_physical_port.port = erp_action->port;
- /* port to be closeed */
+ erp_action->fsf_req->data = (unsigned long) erp_action->port;
+ /* port to be closed */
erp_action->fsf_req->qtcb->header.port_handle =
erp_action->port->handle;
erp_action->fsf_req->erp_action = erp_action;
@@ -2747,7 +2773,7 @@ zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *fsf_req)
struct fsf_qtcb_header *header;
u16 subtable, rule, counter;
- port = fsf_req->data.close_physical_port.port;
+ port = (struct zfcp_port *) fsf_req->data;
header = &fsf_req->qtcb->header;
if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
@@ -2908,10 +2934,11 @@ zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
erp_action->port->handle;
erp_action->fsf_req->qtcb->bottom.support.fcp_lun =
erp_action->unit->fcp_lun;
+ if (!(erp_action->adapter->connection_features & FSF_FEATURE_NPIV_MODE))
erp_action->fsf_req->qtcb->bottom.support.option =
FSF_OPEN_LUN_SUPPRESS_BOXING;
atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->unit->status);
- erp_action->fsf_req->data.open_unit.unit = erp_action->unit;
+ erp_action->fsf_req->data = (unsigned long) erp_action->unit;
erp_action->fsf_req->erp_action = erp_action;
/* start QDIO request for this FSF request */
@@ -2955,9 +2982,9 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req)
struct fsf_qtcb_bottom_support *bottom;
struct fsf_queue_designator *queue_designator;
u16 subtable, rule, counter;
- u32 allowed, exclusive, readwrite;
+ int exclusive, readwrite;
- unit = fsf_req->data.open_unit.unit;
+ unit = (struct zfcp_unit *) fsf_req->data;
if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
/* don't change unit status in our bookkeeping */
@@ -2969,10 +2996,6 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req)
bottom = &fsf_req->qtcb->bottom.support;
queue_designator = &header->fsf_status_qual.fsf_queue_designator;
- allowed = bottom->lun_access_info & FSF_UNIT_ACCESS_OPEN_LUN_ALLOWED;
- exclusive = bottom->lun_access_info & FSF_UNIT_ACCESS_EXCLUSIVE;
- readwrite = bottom->lun_access_info & FSF_UNIT_ACCESS_OUTBOUND_TRANSFER;
-
atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
ZFCP_STATUS_UNIT_SHARED |
ZFCP_STATUS_UNIT_READONLY,
@@ -3146,10 +3169,15 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req)
unit->handle);
/* mark unit as open */
atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status);
- atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
- ZFCP_STATUS_COMMON_ACCESS_BOXED,
- &unit->status);
- if (adapter->supported_features & FSF_FEATURE_LUN_SHARING){
+
+ if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE) &&
+ (adapter->adapter_features & FSF_FEATURE_LUN_SHARING) &&
+ (adapter->ccw_device->id.dev_model != ZFCP_DEVICE_MODEL_PRIV)) {
+ exclusive = (bottom->lun_access_info &
+ FSF_UNIT_ACCESS_EXCLUSIVE);
+ readwrite = (bottom->lun_access_info &
+ FSF_UNIT_ACCESS_OUTBOUND_TRANSFER);
+
if (!exclusive)
atomic_set_mask(ZFCP_STATUS_UNIT_SHARED,
&unit->status);
@@ -3242,7 +3270,7 @@ zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action)
erp_action->port->handle;
erp_action->fsf_req->qtcb->header.lun_handle = erp_action->unit->handle;
atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->unit->status);
- erp_action->fsf_req->data.close_unit.unit = erp_action->unit;
+ erp_action->fsf_req->data = (unsigned long) erp_action->unit;
erp_action->fsf_req->erp_action = erp_action;
/* start QDIO request for this FSF request */
@@ -3281,7 +3309,7 @@ zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *fsf_req)
int retval = -EINVAL;
struct zfcp_unit *unit;
- unit = fsf_req->data.close_unit.unit; /* restore unit */
+ unit = (struct zfcp_unit *) fsf_req->data;
if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
/* don't change unit status in our bookkeeping */
@@ -3305,9 +3333,6 @@ zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *fsf_req)
debug_text_event(fsf_req->adapter->erp_dbf, 1,
"fsf_s_phand_nv");
zfcp_erp_adapter_reopen(unit->port->adapter, 0);
- zfcp_cmd_dbf_event_fsf("porthinv", fsf_req,
- &fsf_req->qtcb->header.fsf_status_qual,
- sizeof (union fsf_status_qual));
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
@@ -3326,9 +3351,6 @@ zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *fsf_req)
debug_text_event(fsf_req->adapter->erp_dbf, 1,
"fsf_s_lhand_nv");
zfcp_erp_port_reopen(unit->port, 0);
- zfcp_cmd_dbf_event_fsf("lunhinv", fsf_req,
- &fsf_req->qtcb->header.fsf_status_qual,
- sizeof (union fsf_status_qual));
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
@@ -3436,21 +3458,14 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
goto failed_req_create;
}
- /*
- * associate FSF request with SCSI request
- * (need this for look up on abort)
- */
- fsf_req->data.send_fcp_command_task.fsf_req = fsf_req;
- scsi_cmnd->host_scribble = (char *) &(fsf_req->data);
+ zfcp_unit_get(unit);
+ fsf_req->unit = unit;
- /*
- * associate SCSI command with FSF request
- * (need this for look up on normal command completion)
- */
- fsf_req->data.send_fcp_command_task.scsi_cmnd = scsi_cmnd;
- fsf_req->data.send_fcp_command_task.start_jiffies = jiffies;
- fsf_req->data.send_fcp_command_task.unit = unit;
- ZFCP_LOG_DEBUG("unit=%p, fcp_lun=0x%016Lx\n", unit, unit->fcp_lun);
+ /* associate FSF request with SCSI request (for look up on abort) */
+ scsi_cmnd->host_scribble = (char *) fsf_req;
+
+ /* associate SCSI command with FSF request */
+ fsf_req->data = (unsigned long) scsi_cmnd;
/* set handles of unit and its parent port in QTCB */
fsf_req->qtcb->header.lun_handle = unit->handle;
@@ -3584,6 +3599,7 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
send_failed:
no_fit:
failed_scsi_cmnd:
+ zfcp_unit_put(unit);
zfcp_fsf_req_free(fsf_req);
fsf_req = NULL;
scsi_cmnd->host_scribble = NULL;
@@ -3640,7 +3656,7 @@ zfcp_fsf_send_fcp_command_task_management(struct zfcp_adapter *adapter,
* hold a pointer to the unit being target of this
* task management request
*/
- fsf_req->data.send_fcp_command_task_management.unit = unit;
+ fsf_req->data = (unsigned long) unit;
/* set FSF related fields in QTCB */
fsf_req->qtcb->header.lun_handle = unit->handle;
@@ -3706,9 +3722,9 @@ zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req)
header = &fsf_req->qtcb->header;
if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT))
- unit = fsf_req->data.send_fcp_command_task_management.unit;
+ unit = (struct zfcp_unit *) fsf_req->data;
else
- unit = fsf_req->data.send_fcp_command_task.unit;
+ unit = fsf_req->unit;
if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
/* go directly to calls of special handlers */
@@ -3765,10 +3781,6 @@ zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req)
debug_text_event(fsf_req->adapter->erp_dbf, 1,
"fsf_s_hand_mis");
zfcp_erp_adapter_reopen(unit->port->adapter, 0);
- zfcp_cmd_dbf_event_fsf("handmism",
- fsf_req,
- &header->fsf_status_qual,
- sizeof (union fsf_status_qual));
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
@@ -3789,10 +3801,6 @@ zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req)
debug_text_exception(fsf_req->adapter->erp_dbf, 0,
"fsf_s_class_nsup");
zfcp_erp_adapter_shutdown(unit->port->adapter, 0);
- zfcp_cmd_dbf_event_fsf("unsclass",
- fsf_req,
- &header->fsf_status_qual,
- sizeof (union fsf_status_qual));
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
@@ -3811,10 +3819,6 @@ zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req)
debug_text_event(fsf_req->adapter->erp_dbf, 1,
"fsf_s_fcp_lun_nv");
zfcp_erp_port_reopen(unit->port, 0);
- zfcp_cmd_dbf_event_fsf("fluninv",
- fsf_req,
- &header->fsf_status_qual,
- sizeof (union fsf_status_qual));
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
@@ -3853,10 +3857,6 @@ zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req)
debug_text_event(fsf_req->adapter->erp_dbf, 0,
"fsf_s_dir_ind_nv");
zfcp_erp_adapter_shutdown(unit->port->adapter, 0);
- zfcp_cmd_dbf_event_fsf("dirinv",
- fsf_req,
- &header->fsf_status_qual,
- sizeof (union fsf_status_qual));
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
@@ -3872,10 +3872,6 @@ zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req)
debug_text_event(fsf_req->adapter->erp_dbf, 0,
"fsf_s_cmd_len_nv");
zfcp_erp_adapter_shutdown(unit->port->adapter, 0);
- zfcp_cmd_dbf_event_fsf("cleninv",
- fsf_req,
- &header->fsf_status_qual,
- sizeof (union fsf_status_qual));
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
@@ -3947,6 +3943,8 @@ zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req)
zfcp_fsf_send_fcp_command_task_management_handler(fsf_req);
} else {
retval = zfcp_fsf_send_fcp_command_task_handler(fsf_req);
+ fsf_req->unit = NULL;
+ zfcp_unit_put(unit);
}
return retval;
}
@@ -3970,10 +3968,10 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
u32 sns_len;
char *fcp_rsp_info = zfcp_get_fcp_rsp_info_ptr(fcp_rsp_iu);
unsigned long flags;
- struct zfcp_unit *unit = fsf_req->data.send_fcp_command_task.unit;
+ struct zfcp_unit *unit = fsf_req->unit;
read_lock_irqsave(&fsf_req->adapter->abort_lock, flags);
- scpnt = fsf_req->data.send_fcp_command_task.scsi_cmnd;
+ scpnt = (struct scsi_cmnd *) fsf_req->data;
if (unlikely(!scpnt)) {
ZFCP_LOG_DEBUG
("Command with fsf_req %p is not associated to "
@@ -4043,7 +4041,6 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
(char *) &fsf_req->qtcb->
bottom.io.fcp_cmnd, FSF_FCP_CMND_SIZE);
- zfcp_cmd_dbf_event_fsf("clenmis", fsf_req, NULL, 0);
set_host_byte(&scpnt->result, DID_ERROR);
goto skip_fsfstatus;
case RSP_CODE_FIELD_INVALID:
@@ -4062,7 +4059,6 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
(char *) &fsf_req->qtcb->
bottom.io.fcp_cmnd, FSF_FCP_CMND_SIZE);
set_host_byte(&scpnt->result, DID_ERROR);
- zfcp_cmd_dbf_event_fsf("codeinv", fsf_req, NULL, 0);
goto skip_fsfstatus;
case RSP_CODE_RO_MISMATCH:
/* hardware bug */
@@ -4079,7 +4075,6 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
(char *) &fsf_req->qtcb->
bottom.io.fcp_cmnd, FSF_FCP_CMND_SIZE);
- zfcp_cmd_dbf_event_fsf("codemism", fsf_req, NULL, 0);
set_host_byte(&scpnt->result, DID_ERROR);
goto skip_fsfstatus;
default:
@@ -4096,7 +4091,6 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
(char *) &fsf_req->qtcb->
bottom.io.fcp_cmnd, FSF_FCP_CMND_SIZE);
- zfcp_cmd_dbf_event_fsf("undeffcp", fsf_req, NULL, 0);
set_host_byte(&scpnt->result, DID_ERROR);
goto skip_fsfstatus;
}
@@ -4158,19 +4152,17 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
skip_fsfstatus:
ZFCP_LOG_DEBUG("scpnt->result =0x%x\n", scpnt->result);
- zfcp_cmd_dbf_event_scsi("response", scpnt);
+ if (scpnt->result != 0)
+ zfcp_scsi_dbf_event_result("erro", 3, fsf_req->adapter, scpnt);
+ else if (scpnt->retries > 0)
+ zfcp_scsi_dbf_event_result("retr", 4, fsf_req->adapter, scpnt);
+ else
+ zfcp_scsi_dbf_event_result("norm", 6, fsf_req->adapter, scpnt);
/* cleanup pointer (need this especially for abort) */
scpnt->host_scribble = NULL;
- /*
- * NOTE:
- * according to the outcome of a discussion on linux-scsi we
- * don't need to grab the io_request_lock here since we use
- * the new eh
- */
/* always call back */
-
(scpnt->scsi_done) (scpnt);
/*
@@ -4198,8 +4190,7 @@ zfcp_fsf_send_fcp_command_task_management_handler(struct zfcp_fsf_req *fsf_req)
struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *)
&(fsf_req->qtcb->bottom.io.fcp_rsp);
char *fcp_rsp_info = zfcp_get_fcp_rsp_info_ptr(fcp_rsp_iu);
- struct zfcp_unit *unit =
- fsf_req->data.send_fcp_command_task_management.unit;
+ struct zfcp_unit *unit = (struct zfcp_unit *) fsf_req->data;
del_timer(&fsf_req->adapter->scsi_er_timer);
if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
@@ -4276,7 +4267,7 @@ zfcp_fsf_control_file(struct zfcp_adapter *adapter,
int direction;
int retval = 0;
- if (!(adapter->supported_features & FSF_FEATURE_CFDC)) {
+ if (!(adapter->adapter_features & FSF_FEATURE_CFDC)) {
ZFCP_LOG_INFO("cfdc not supported (adapter %s)\n",
zfcp_get_busid_by_adapter(adapter));
retval = -EOPNOTSUPP;
@@ -4549,52 +4540,6 @@ skip_fsfstatus:
return retval;
}
-
-/*
- * function: zfcp_fsf_req_wait_and_cleanup
- *
- * purpose:
- *
- * FIXME(design): signal seems to be <0 !!!
- * returns: 0 - request completed (*status is valid), cleanup succ.
- * <0 - request completed (*status is valid), cleanup failed
- * >0 - signal which interrupted waiting (*status invalid),
- * request not completed, no cleanup
- *
- * *status is a copy of status of completed fsf_req
- */
-int
-zfcp_fsf_req_wait_and_cleanup(struct zfcp_fsf_req *fsf_req,
- int interruptible, u32 * status)
-{
- int retval = 0;
- int signal = 0;
-
- if (interruptible) {
- __wait_event_interruptible(fsf_req->completion_wq,
- fsf_req->status &
- ZFCP_STATUS_FSFREQ_COMPLETED,
- signal);
- if (signal) {
- ZFCP_LOG_DEBUG("Caught signal %i while waiting for the "
- "completion of the request at %p\n",
- signal, fsf_req);
- retval = signal;
- goto out;
- }
- } else {
- __wait_event(fsf_req->completion_wq,
- fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
- }
-
- *status = fsf_req->status;
-
- /* cleanup request */
- zfcp_fsf_req_free(fsf_req);
- out:
- return retval;
-}
-
static inline int
zfcp_fsf_req_sbal_check(unsigned long *flags,
struct zfcp_qdio_queue *queue, int needed)
@@ -4610,15 +4555,16 @@ zfcp_fsf_req_sbal_check(unsigned long *flags,
* set qtcb pointer in fsf_req and initialize QTCB
*/
static inline void
-zfcp_fsf_req_qtcb_init(struct zfcp_fsf_req *fsf_req, u32 fsf_cmd)
+zfcp_fsf_req_qtcb_init(struct zfcp_fsf_req *fsf_req)
{
if (likely(fsf_req->qtcb != NULL)) {
+ fsf_req->qtcb->prefix.req_seq_no = fsf_req->adapter->fsf_req_seq_no;
fsf_req->qtcb->prefix.req_id = (unsigned long)fsf_req;
fsf_req->qtcb->prefix.ulp_info = ZFCP_ULP_INFO_VERSION;
- fsf_req->qtcb->prefix.qtcb_type = fsf_qtcb_type[fsf_cmd];
+ fsf_req->qtcb->prefix.qtcb_type = fsf_qtcb_type[fsf_req->fsf_command];
fsf_req->qtcb->prefix.qtcb_version = ZFCP_QTCB_VERSION;
fsf_req->qtcb->header.req_handle = (unsigned long)fsf_req;
- fsf_req->qtcb->header.fsf_command = fsf_cmd;
+ fsf_req->qtcb->header.fsf_command = fsf_req->fsf_command;
}
}
@@ -4686,7 +4632,10 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags,
goto failed_fsf_req;
}
- zfcp_fsf_req_qtcb_init(fsf_req, fsf_cmd);
+ fsf_req->adapter = adapter;
+ fsf_req->fsf_command = fsf_cmd;
+
+ zfcp_fsf_req_qtcb_init(fsf_req);
/* initialize waitqueue which may be used to wait on
this request completion */
@@ -4708,8 +4657,10 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags,
goto failed_sbals;
}
- fsf_req->adapter = adapter; /* pointer to "parent" adapter */
- fsf_req->fsf_command = fsf_cmd;
+ if (fsf_req->qtcb) {
+ fsf_req->seq_no = adapter->fsf_req_seq_no;
+ fsf_req->qtcb->prefix.req_seq_no = adapter->fsf_req_seq_no;
+ }
fsf_req->sbal_number = 1;
fsf_req->sbal_first = req_queue->free_index;
fsf_req->sbal_curr = req_queue->free_index;
@@ -4760,9 +4711,9 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer)
struct zfcp_adapter *adapter;
struct zfcp_qdio_queue *req_queue;
volatile struct qdio_buffer_element *sbale;
+ int inc_seq_no;
int new_distance_from_int;
unsigned long flags;
- int inc_seq_no = 1;
int retval = 0;
adapter = fsf_req->adapter;
@@ -4776,23 +4727,13 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer)
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, (char *) sbale[1].addr,
sbale[1].length);
- /* set sequence counter in 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 %p of adapter %s gets "
- "FSF sequence counter value of %i\n",
- fsf_req,
- zfcp_get_busid_by_adapter(adapter),
- fsf_req->qtcb->prefix.req_seq_no);
- } else
- inc_seq_no = 0;
-
/* put allocated FSF request at list tail */
spin_lock_irqsave(&adapter->fsf_req_list_lock, flags);
list_add_tail(&fsf_req->list, &adapter->fsf_req_list_head);
spin_unlock_irqrestore(&adapter->fsf_req_list_lock, flags);
+ inc_seq_no = (fsf_req->qtcb != NULL);
+
/* figure out expiration time of timeout and start timeout */
if (unlikely(timer)) {
timer->expires += jiffies;
@@ -4822,6 +4763,8 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer)
req_queue->free_index %= QDIO_MAX_BUFFERS_PER_Q; /* wrap if needed */
new_distance_from_int = zfcp_qdio_determine_pci(req_queue, fsf_req);
+ fsf_req->issued = get_clock();
+
retval = do_QDIO(adapter->ccw_device,
QDIO_FLAG_SYNC_OUTPUT,
0, fsf_req->sbal_first, fsf_req->sbal_number, NULL);
@@ -4860,15 +4803,11 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer)
* routines resulting in missing sequence counter values
* otherwise,
*/
+
/* Don't increase for unsolicited status */
- if (likely(inc_seq_no)) {
+ if (inc_seq_no)
adapter->fsf_req_seq_no++;
- ZFCP_LOG_TRACE
- ("FSF sequence counter value of adapter %s "
- "increased to %i\n",
- zfcp_get_busid_by_adapter(adapter),
- adapter->fsf_req_seq_no);
- }
+
/* count FSF requests pending */
atomic_inc(&adapter->fsf_reqs_active);
}
diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h
index 07140dfda2a7..48719f055952 100644
--- a/drivers/s390/scsi/zfcp_fsf.h
+++ b/drivers/s390/scsi/zfcp_fsf.h
@@ -116,6 +116,7 @@
#define FSF_INVALID_COMMAND_OPTION 0x000000E5
/* #define FSF_ERROR 0x000000FF */
+#define FSF_PROT_STATUS_QUAL_SIZE 16
#define FSF_STATUS_QUALIFIER_SIZE 16
/* FSF status qualifier, recommendations */
@@ -139,9 +140,18 @@
#define FSF_SQ_CFDC_SUBTABLE_LUN 0x0004
/* FSF status qualifier (most significant 4 bytes), local link down */
-#define FSF_PSQ_LINK_NOLIGHT 0x00000004
-#define FSF_PSQ_LINK_WRAPPLUG 0x00000008
-#define FSF_PSQ_LINK_NOFCP 0x00000010
+#define FSF_PSQ_LINK_NO_LIGHT 0x00000004
+#define FSF_PSQ_LINK_WRAP_PLUG 0x00000008
+#define FSF_PSQ_LINK_NO_FCP 0x00000010
+#define FSF_PSQ_LINK_FIRMWARE_UPDATE 0x00000020
+#define FSF_PSQ_LINK_INVALID_WWPN 0x00000100
+#define FSF_PSQ_LINK_NO_NPIV_SUPPORT 0x00000200
+#define FSF_PSQ_LINK_NO_FCP_RESOURCES 0x00000400
+#define FSF_PSQ_LINK_NO_FABRIC_RESOURCES 0x00000800
+#define FSF_PSQ_LINK_FABRIC_LOGIN_UNABLE 0x00001000
+#define FSF_PSQ_LINK_WWPN_ASSIGNMENT_CORRUPTED 0x00002000
+#define FSF_PSQ_LINK_MODE_TABLE_CURRUPTED 0x00004000
+#define FSF_PSQ_LINK_NO_WWPN_ASSIGNMENT 0x00008000
/* payload size in status read buffer */
#define FSF_STATUS_READ_PAYLOAD_SIZE 4032
@@ -154,15 +164,21 @@
#define FSF_STATUS_READ_INCOMING_ELS 0x00000002
#define FSF_STATUS_READ_SENSE_DATA_AVAIL 0x00000003
#define FSF_STATUS_READ_BIT_ERROR_THRESHOLD 0x00000004
-#define FSF_STATUS_READ_LINK_DOWN 0x00000005 /* FIXME: really? */
+#define FSF_STATUS_READ_LINK_DOWN 0x00000005
#define FSF_STATUS_READ_LINK_UP 0x00000006
#define FSF_STATUS_READ_CFDC_UPDATED 0x0000000A
#define FSF_STATUS_READ_CFDC_HARDENED 0x0000000B
+#define FSF_STATUS_READ_FEATURE_UPDATE_ALERT 0x0000000C
/* status subtypes in status read buffer */
#define FSF_STATUS_READ_SUB_CLOSE_PHYS_PORT 0x00000001
#define FSF_STATUS_READ_SUB_ERROR_PORT 0x00000002
+/* status subtypes for link down */
+#define FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK 0x00000000
+#define FSF_STATUS_READ_SUB_FDISC_FAILED 0x00000001
+#define FSF_STATUS_READ_SUB_FIRMWARE_UPDATE 0x00000002
+
/* status subtypes for CFDC */
#define FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE 0x00000002
#define FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE2 0x0000000F
@@ -193,11 +209,15 @@
#define FSF_QTCB_LOG_SIZE 1024
/* channel features */
-#define FSF_FEATURE_QTCB_SUPPRESSION 0x00000001
#define FSF_FEATURE_CFDC 0x00000002
#define FSF_FEATURE_LUN_SHARING 0x00000004
#define FSF_FEATURE_HBAAPI_MANAGEMENT 0x00000010
#define FSF_FEATURE_ELS_CT_CHAINED_SBALS 0x00000020
+#define FSF_FEATURE_UPDATE_ALERT 0x00000100
+
+/* host connection features */
+#define FSF_FEATURE_NPIV_MODE 0x00000001
+#define FSF_FEATURE_VM_ASSIGNED_WWPN 0x00000002
/* option */
#define FSF_OPEN_LUN_SUPPRESS_BOXING 0x00000001
@@ -305,15 +325,23 @@ struct fsf_qual_sequence_error {
u32 res1[3];
} __attribute__ ((packed));
-struct fsf_qual_locallink_error {
- u32 code;
- u32 res1[3];
+struct fsf_link_down_info {
+ u32 error_code;
+ u32 res1;
+ u8 res2[2];
+ u8 primary_status;
+ u8 ioerr_code;
+ u8 action_code;
+ u8 reason_code;
+ u8 explanation_code;
+ u8 vendor_specific_code;
} __attribute__ ((packed));
union fsf_prot_status_qual {
+ u64 doubleword[FSF_PROT_STATUS_QUAL_SIZE / sizeof(u64)];
struct fsf_qual_version_error version_error;
struct fsf_qual_sequence_error sequence_error;
- struct fsf_qual_locallink_error locallink_error;
+ struct fsf_link_down_info link_down_info;
} __attribute__ ((packed));
struct fsf_qtcb_prefix {
@@ -331,7 +359,9 @@ union fsf_status_qual {
u8 byte[FSF_STATUS_QUALIFIER_SIZE];
u16 halfword[FSF_STATUS_QUALIFIER_SIZE / sizeof (u16)];
u32 word[FSF_STATUS_QUALIFIER_SIZE / sizeof (u32)];
+ u64 doubleword[FSF_STATUS_QUALIFIER_SIZE / sizeof(u64)];
struct fsf_queue_designator fsf_queue_designator;
+ struct fsf_link_down_info link_down_info;
} __attribute__ ((packed));
struct fsf_qtcb_header {
@@ -406,8 +436,8 @@ struct fsf_qtcb_bottom_config {
u32 low_qtcb_version;
u32 max_qtcb_size;
u32 max_data_transfer_size;
- u32 supported_features;
- u8 res1[4];
+ u32 adapter_features;
+ u32 connection_features;
u32 fc_topology;
u32 fc_link_speed;
u32 adapter_type;
@@ -425,7 +455,7 @@ struct fsf_qtcb_bottom_config {
} __attribute__ ((packed));
struct fsf_qtcb_bottom_port {
- u8 res1[8];
+ u64 wwpn;
u32 fc_port_id;
u32 port_type;
u32 port_state;
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c
index 24e16ec331d9..d719f66a29a4 100644
--- a/drivers/s390/scsi/zfcp_qdio.c
+++ b/drivers/s390/scsi/zfcp_qdio.c
@@ -54,8 +54,7 @@ static inline int zfcp_qdio_sbals_from_buffer
static qdio_handler_t zfcp_qdio_request_handler;
static qdio_handler_t zfcp_qdio_response_handler;
static int zfcp_qdio_handler_error_check(struct zfcp_adapter *,
- unsigned int,
- unsigned int, unsigned int);
+ unsigned int, unsigned int, unsigned int, int, int);
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_QDIO
@@ -214,22 +213,12 @@ zfcp_qdio_allocate(struct zfcp_adapter *adapter)
*
*/
static inline int
-zfcp_qdio_handler_error_check(struct zfcp_adapter *adapter,
- unsigned int status,
- unsigned int qdio_error, unsigned int siga_error)
+zfcp_qdio_handler_error_check(struct zfcp_adapter *adapter, unsigned int status,
+ unsigned int qdio_error, unsigned int siga_error,
+ int first_element, int elements_processed)
{
int retval = 0;
- if (ZFCP_LOG_CHECK(ZFCP_LOG_LEVEL_TRACE)) {
- if (status & QDIO_STATUS_INBOUND_INT) {
- ZFCP_LOG_TRACE("status is"
- " QDIO_STATUS_INBOUND_INT \n");
- }
- if (status & QDIO_STATUS_OUTBOUND_INT) {
- ZFCP_LOG_TRACE("status is"
- " QDIO_STATUS_OUTBOUND_INT \n");
- }
- }
if (unlikely(status & QDIO_STATUS_LOOK_FOR_ERROR)) {
retval = -EIO;
@@ -237,9 +226,10 @@ zfcp_qdio_handler_error_check(struct zfcp_adapter *adapter,
"qdio_error=0x%x, siga_error=0x%x)\n",
status, qdio_error, siga_error);
- /* Restarting IO on the failed adapter from scratch */
- debug_text_event(adapter->erp_dbf, 1, "qdio_err");
+ zfcp_hba_dbf_event_qdio(adapter, status, qdio_error, siga_error,
+ first_element, elements_processed);
/*
+ * Restarting IO on the failed adapter from scratch.
* 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.
@@ -282,7 +272,8 @@ zfcp_qdio_request_handler(struct ccw_device *ccw_device,
first_element, elements_processed);
if (unlikely(zfcp_qdio_handler_error_check(adapter, status, qdio_error,
- siga_error)))
+ siga_error, first_element,
+ elements_processed)))
goto out;
/*
* we stored address of struct zfcp_adapter data structure
@@ -334,7 +325,8 @@ zfcp_qdio_response_handler(struct ccw_device *ccw_device,
queue = &adapter->response_queue;
if (unlikely(zfcp_qdio_handler_error_check(adapter, status, qdio_error,
- siga_error)))
+ siga_error, first_element,
+ elements_processed)))
goto out;
/*
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index 31a76065cf28..3dcd1bfba3b4 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -44,7 +44,8 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *);
static int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *);
static int zfcp_scsi_eh_bus_reset_handler(struct scsi_cmnd *);
static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *);
-static int zfcp_task_management_function(struct zfcp_unit *, u8);
+static int zfcp_task_management_function(struct zfcp_unit *, u8,
+ struct scsi_cmnd *);
static struct zfcp_unit *zfcp_unit_lookup(struct zfcp_adapter *, int, scsi_id_t,
scsi_lun_t);
@@ -242,7 +243,10 @@ static void
zfcp_scsi_command_fail(struct scsi_cmnd *scpnt, int result)
{
set_host_byte(&scpnt->result, result);
- zfcp_cmd_dbf_event_scsi("failing", scpnt);
+ if ((scpnt->device != NULL) && (scpnt->device->host != NULL))
+ zfcp_scsi_dbf_event_result("fail", 4,
+ (struct zfcp_adapter*) scpnt->device->host->hostdata[0],
+ scpnt);
/* return directly */
scpnt->scsi_done(scpnt);
}
@@ -414,67 +418,38 @@ zfcp_port_lookup(struct zfcp_adapter *adapter, int channel, scsi_id_t id)
return (struct zfcp_port *) NULL;
}
-/*
- * function: zfcp_scsi_eh_abort_handler
- *
- * purpose: tries to abort the specified (timed out) SCSI command
- *
- * note: We do not need to care for a SCSI command which completes
- * normally but late during this abort routine runs.
- * We are allowed to return late commands to the SCSI stack.
- * It tracks the state of commands and will handle late commands.
- * (Usually, the normal completion of late commands is ignored with
- * respect to the running abort operation. Grep for 'done_late'
- * in the SCSI stacks sources.)
+/**
+ * zfcp_scsi_eh_abort_handler - abort the specified SCSI command
+ * @scpnt: pointer to scsi_cmnd to be aborted
+ * Return: SUCCESS - command has been aborted and cleaned up in internal
+ * bookkeeping, SCSI stack won't be called for aborted command
+ * FAILED - otherwise
*
- * returns: SUCCESS - command has been aborted and cleaned up in internal
- * bookkeeping,
- * SCSI stack won't be called for aborted command
- * FAILED - otherwise
+ * We do not need to care for a SCSI command which completes normally
+ * but late during this abort routine runs. We are allowed to return
+ * late commands to the SCSI stack. It tracks the state of commands and
+ * will handle late commands. (Usually, the normal completion of late
+ * commands is ignored with respect to the running abort operation.)
*/
int
-__zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
+zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
{
+ struct Scsi_Host *scsi_host;
+ struct zfcp_adapter *adapter;
+ struct zfcp_unit *unit;
int retval = SUCCESS;
- struct zfcp_fsf_req *new_fsf_req, *old_fsf_req;
- struct zfcp_adapter *adapter = (struct zfcp_adapter *) scpnt->device->host->hostdata[0];
- struct zfcp_unit *unit = (struct zfcp_unit *) scpnt->device->hostdata;
- struct zfcp_port *port = unit->port;
- struct Scsi_Host *scsi_host = scpnt->device->host;
- union zfcp_req_data *req_data = NULL;
+ struct zfcp_fsf_req *new_fsf_req = NULL;
+ struct zfcp_fsf_req *old_fsf_req;
unsigned long flags;
- u32 status = 0;
-
- /* the components of a abort_dbf record (fixed size record) */
- u64 dbf_scsi_cmnd = (unsigned long) scpnt;
- char dbf_opcode[ZFCP_ABORT_DBF_LENGTH];
- wwn_t dbf_wwn = port->wwpn;
- fcp_lun_t dbf_fcp_lun = unit->fcp_lun;
- u64 dbf_retries = scpnt->retries;
- u64 dbf_allowed = scpnt->allowed;
- u64 dbf_timeout = 0;
- u64 dbf_fsf_req = 0;
- u64 dbf_fsf_status = 0;
- u64 dbf_fsf_qual[2] = { 0, 0 };
- char dbf_result[ZFCP_ABORT_DBF_LENGTH] = "##undef";
-
- memset(dbf_opcode, 0, ZFCP_ABORT_DBF_LENGTH);
- memcpy(dbf_opcode,
- scpnt->cmnd,
- min(scpnt->cmd_len, (unsigned char) ZFCP_ABORT_DBF_LENGTH));
+
+ scsi_host = scpnt->device->host;
+ adapter = (struct zfcp_adapter *) scsi_host->hostdata[0];
+ unit = (struct zfcp_unit *) scpnt->device->hostdata;
ZFCP_LOG_INFO("aborting scsi_cmnd=%p on adapter %s\n",
scpnt, zfcp_get_busid_by_adapter(adapter));
- spin_unlock_irq(scsi_host->host_lock);
-
- /*
- * 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 and thus we block the
- * release of fsf_req as long as we need to access scsi_req.
- */
+ /* avoid race condition between late normal completion and abort */
write_lock_irqsave(&adapter->abort_lock, flags);
/*
@@ -484,144 +459,47 @@ __zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
* this routine returns. (scpnt is parameter passed to this routine
* and must not disappear during abort even on late completion.)
*/
- req_data = (union zfcp_req_data *) scpnt->host_scribble;
- /* DEBUG */
- ZFCP_LOG_DEBUG("req_data=%p\n", req_data);
- if (!req_data) {
- ZFCP_LOG_DEBUG("late command completion overtook abort\n");
- /*
- * That's it.
- * Do not initiate abort but return SUCCESS.
- */
- write_unlock_irqrestore(&adapter->abort_lock, flags);
- retval = SUCCESS;
- strncpy(dbf_result, "##late1", ZFCP_ABORT_DBF_LENGTH);
- goto out;
- }
-
- /* Figure out which fsf_req needs to be aborted. */
- old_fsf_req = req_data->send_fcp_command_task.fsf_req;
-
- dbf_fsf_req = (unsigned long) old_fsf_req;
- dbf_timeout =
- (jiffies - req_data->send_fcp_command_task.start_jiffies) / HZ;
-
- ZFCP_LOG_DEBUG("old_fsf_req=%p\n", old_fsf_req);
+ old_fsf_req = (struct zfcp_fsf_req *) scpnt->host_scribble;
if (!old_fsf_req) {
write_unlock_irqrestore(&adapter->abort_lock, flags);
- ZFCP_LOG_NORMAL("bug: no old fsf request found\n");
- ZFCP_LOG_NORMAL("req_data:\n");
- ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL,
- (char *) req_data, sizeof (union zfcp_req_data));
- ZFCP_LOG_NORMAL("scsi_cmnd:\n");
- ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL,
- (char *) scpnt, sizeof (struct scsi_cmnd));
- retval = FAILED;
- strncpy(dbf_result, "##bug:r", ZFCP_ABORT_DBF_LENGTH);
+ zfcp_scsi_dbf_event_abort("lte1", adapter, scpnt, new_fsf_req);
+ retval = SUCCESS;
goto out;
}
- old_fsf_req->data.send_fcp_command_task.scsi_cmnd = NULL;
- /* mark old request as being aborted */
+ old_fsf_req->data = 0;
old_fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTING;
- /*
- * We have to collect all information (e.g. unit) needed by
- * zfcp_fsf_abort_fcp_command before calling that routine
- * since that routine is not allowed to access
- * fsf_req which it is going to abort.
- * This is because of we need to release fsf_req_list_lock
- * before calling zfcp_fsf_abort_fcp_command.
- * Since this lock will not be held, fsf_req may complete
- * late and may be released meanwhile.
- */
- ZFCP_LOG_DEBUG("unit 0x%016Lx (%p)\n", unit->fcp_lun, unit);
- /*
- * We block (call schedule)
- * That's why we must release the lock and enable the
- * interrupts before.
- * On the other hand we do not need the lock anymore since
- * all critical accesses to scsi_req are done.
- */
+ /* don't access old_fsf_req after releasing the abort_lock */
write_unlock_irqrestore(&adapter->abort_lock, flags);
/* call FSF routine which does the abort */
new_fsf_req = zfcp_fsf_abort_fcp_command((unsigned long) old_fsf_req,
adapter, unit, 0);
- ZFCP_LOG_DEBUG("new_fsf_req=%p\n", new_fsf_req);
if (!new_fsf_req) {
+ ZFCP_LOG_INFO("error: initiation of Abort FCP Cmnd failed\n");
retval = FAILED;
- ZFCP_LOG_NORMAL("error: initiation of Abort FCP Cmnd "
- "failed\n");
- strncpy(dbf_result, "##nores", ZFCP_ABORT_DBF_LENGTH);
goto out;
}
/* wait for completion of abort */
- ZFCP_LOG_DEBUG("waiting for cleanup...\n");
-#if 1
- /*
- * FIXME:
- * copying zfcp_fsf_req_wait_and_cleanup code is not really nice
- */
__wait_event(new_fsf_req->completion_wq,
new_fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
- status = new_fsf_req->status;
- dbf_fsf_status = new_fsf_req->qtcb->header.fsf_status;
- /*
- * Ralphs special debug load provides timestamps in the FSF
- * status qualifier. This might be specified later if being
- * useful for debugging aborts.
- */
- dbf_fsf_qual[0] =
- *(u64 *) & new_fsf_req->qtcb->header.fsf_status_qual.word[0];
- dbf_fsf_qual[1] =
- *(u64 *) & new_fsf_req->qtcb->header.fsf_status_qual.word[2];
- zfcp_fsf_req_free(new_fsf_req);
-#else
- retval = zfcp_fsf_req_wait_and_cleanup(new_fsf_req,
- ZFCP_UNINTERRUPTIBLE, &status);
-#endif
- ZFCP_LOG_DEBUG("Waiting for cleanup complete, status=0x%x\n", status);
+
/* status should be valid since signals were not permitted */
- if (status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED) {
+ if (new_fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED) {
+ zfcp_scsi_dbf_event_abort("okay", adapter, scpnt, new_fsf_req);
retval = SUCCESS;
- strncpy(dbf_result, "##succ", ZFCP_ABORT_DBF_LENGTH);
- } else if (status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED) {
+ } else if (new_fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED) {
+ zfcp_scsi_dbf_event_abort("lte2", adapter, scpnt, new_fsf_req);
retval = SUCCESS;
- strncpy(dbf_result, "##late2", ZFCP_ABORT_DBF_LENGTH);
} else {
+ zfcp_scsi_dbf_event_abort("fail", adapter, scpnt, new_fsf_req);
retval = FAILED;
- strncpy(dbf_result, "##fail", ZFCP_ABORT_DBF_LENGTH);
}
-
+ zfcp_fsf_req_free(new_fsf_req);
out:
- debug_event(adapter->abort_dbf, 1, &dbf_scsi_cmnd, sizeof (u64));
- debug_event(adapter->abort_dbf, 1, &dbf_opcode, ZFCP_ABORT_DBF_LENGTH);
- debug_event(adapter->abort_dbf, 1, &dbf_wwn, sizeof (wwn_t));
- debug_event(adapter->abort_dbf, 1, &dbf_fcp_lun, sizeof (fcp_lun_t));
- debug_event(adapter->abort_dbf, 1, &dbf_retries, sizeof (u64));
- debug_event(adapter->abort_dbf, 1, &dbf_allowed, sizeof (u64));
- debug_event(adapter->abort_dbf, 1, &dbf_timeout, sizeof (u64));
- debug_event(adapter->abort_dbf, 1, &dbf_fsf_req, sizeof (u64));
- debug_event(adapter->abort_dbf, 1, &dbf_fsf_status, sizeof (u64));
- debug_event(adapter->abort_dbf, 1, &dbf_fsf_qual[0], sizeof (u64));
- debug_event(adapter->abort_dbf, 1, &dbf_fsf_qual[1], sizeof (u64));
- debug_text_event(adapter->abort_dbf, 1, dbf_result);
-
- spin_lock_irq(scsi_host->host_lock);
return retval;
}
-int
-zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
-{
- int rc;
- struct Scsi_Host *scsi_host = scpnt->device->host;
- spin_lock_irq(scsi_host->host_lock);
- rc = __zfcp_scsi_eh_abort_handler(scpnt);
- spin_unlock_irq(scsi_host->host_lock);
- return rc;
-}
-
/*
* function: zfcp_scsi_eh_device_reset_handler
*
@@ -651,8 +529,9 @@ zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt)
*/
if (!atomic_test_mask(ZFCP_STATUS_UNIT_NOTSUPPUNITRESET,
&unit->status)) {
- retval =
- zfcp_task_management_function(unit, FCP_LOGICAL_UNIT_RESET);
+ retval = zfcp_task_management_function(unit,
+ FCP_LOGICAL_UNIT_RESET,
+ scpnt);
if (retval) {
ZFCP_LOG_DEBUG("unit reset failed (unit=%p)\n", unit);
if (retval == -ENOTSUPP)
@@ -668,7 +547,7 @@ zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt)
goto out;
}
}
- retval = zfcp_task_management_function(unit, FCP_TARGET_RESET);
+ retval = zfcp_task_management_function(unit, FCP_TARGET_RESET, scpnt);
if (retval) {
ZFCP_LOG_DEBUG("target reset failed (unit=%p)\n", unit);
retval = FAILED;
@@ -681,12 +560,12 @@ zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt)
}
static int
-zfcp_task_management_function(struct zfcp_unit *unit, u8 tm_flags)
+zfcp_task_management_function(struct zfcp_unit *unit, u8 tm_flags,
+ struct scsi_cmnd *scpnt)
{
struct zfcp_adapter *adapter = unit->port->adapter;
- int retval;
- int status;
struct zfcp_fsf_req *fsf_req;
+ int retval = 0;
/* issue task management function */
fsf_req = zfcp_fsf_send_fcp_command_task_management
@@ -696,70 +575,63 @@ zfcp_task_management_function(struct zfcp_unit *unit, u8 tm_flags)
"failed for unit 0x%016Lx on port 0x%016Lx on "
"adapter %s\n", unit->fcp_lun, unit->port->wwpn,
zfcp_get_busid_by_adapter(adapter));
+ zfcp_scsi_dbf_event_devreset("nres", tm_flags, unit, scpnt);
retval = -ENOMEM;
goto out;
}
- retval = zfcp_fsf_req_wait_and_cleanup(fsf_req,
- ZFCP_UNINTERRUPTIBLE, &status);
+ __wait_event(fsf_req->completion_wq,
+ fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
+
/*
* check completion status of task management function
- * (status should always be valid since no signals permitted)
*/
- if (status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED)
+ if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) {
+ zfcp_scsi_dbf_event_devreset("fail", tm_flags, unit, scpnt);
retval = -EIO;
- else if (status & ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP)
+ } else if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP) {
+ zfcp_scsi_dbf_event_devreset("nsup", tm_flags, unit, scpnt);
retval = -ENOTSUPP;
- else
- retval = 0;
+ } else
+ zfcp_scsi_dbf_event_devreset("okay", tm_flags, unit, scpnt);
+
+ zfcp_fsf_req_free(fsf_req);
out:
return retval;
}
-/*
- * function: zfcp_scsi_eh_bus_reset_handler
- *
- * purpose:
- *
- * returns:
+/**
+ * zfcp_scsi_eh_bus_reset_handler - reset bus (reopen adapter)
*/
int
zfcp_scsi_eh_bus_reset_handler(struct scsi_cmnd *scpnt)
{
- int retval = 0;
- struct zfcp_unit *unit;
+ struct zfcp_unit *unit = (struct zfcp_unit*) scpnt->device->hostdata;
+ struct zfcp_adapter *adapter = unit->port->adapter;
- unit = (struct zfcp_unit *) scpnt->device->hostdata;
ZFCP_LOG_NORMAL("bus reset because of problems with "
"unit 0x%016Lx\n", unit->fcp_lun);
- zfcp_erp_adapter_reopen(unit->port->adapter, 0);
- zfcp_erp_wait(unit->port->adapter);
- retval = SUCCESS;
+ zfcp_erp_adapter_reopen(adapter, 0);
+ zfcp_erp_wait(adapter);
- return retval;
+ return SUCCESS;
}
-/*
- * function: zfcp_scsi_eh_host_reset_handler
- *
- * purpose:
- *
- * returns:
+/**
+ * zfcp_scsi_eh_host_reset_handler - reset host (reopen adapter)
*/
int
zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
{
- int retval = 0;
- struct zfcp_unit *unit;
+ struct zfcp_unit *unit = (struct zfcp_unit*) scpnt->device->hostdata;
+ struct zfcp_adapter *adapter = unit->port->adapter;
- unit = (struct zfcp_unit *) scpnt->device->hostdata;
ZFCP_LOG_NORMAL("host reset because of problems with "
"unit 0x%016Lx\n", unit->fcp_lun);
- zfcp_erp_adapter_reopen(unit->port->adapter, 0);
- zfcp_erp_wait(unit->port->adapter);
- retval = SUCCESS;
+ zfcp_erp_adapter_reopen(adapter, 0);
+ zfcp_erp_wait(adapter);
- return retval;
+ return SUCCESS;
}
/*
@@ -826,10 +698,16 @@ void
zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter)
{
struct Scsi_Host *shost;
+ struct zfcp_port *port;
shost = adapter->scsi_host;
if (!shost)
return;
+ read_lock_irq(&zfcp_data.config_lock);
+ list_for_each_entry(port, &adapter->port_list_head, list)
+ if (port->rport)
+ port->rport = NULL;
+ read_unlock_irq(&zfcp_data.config_lock);
fc_remove_host(shost);
scsi_remove_host(shost);
scsi_host_put(shost);
@@ -904,18 +782,6 @@ zfcp_get_node_name(struct scsi_target *starget)
read_unlock_irqrestore(&zfcp_data.config_lock, flags);
}
-void
-zfcp_set_fc_host_attrs(struct zfcp_adapter *adapter)
-{
- struct Scsi_Host *shost = adapter->scsi_host;
-
- fc_host_node_name(shost) = adapter->wwnn;
- fc_host_port_name(shost) = adapter->wwpn;
- strncpy(fc_host_serial_number(shost), adapter->serial_number,
- min(FC_SERIAL_NUMBER_SIZE, 32));
- fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3;
-}
-
struct fc_function_template zfcp_transport_functions = {
.get_starget_port_id = zfcp_get_port_id,
.get_starget_port_name = zfcp_get_port_name,
@@ -927,7 +793,10 @@ struct fc_function_template zfcp_transport_functions = {
.show_host_node_name = 1,
.show_host_port_name = 1,
.show_host_supported_classes = 1,
+ .show_host_maxframe_size = 1,
.show_host_serial_number = 1,
+ .show_host_speed = 1,
+ .show_host_port_id = 1,
};
/**
diff --git a/drivers/s390/scsi/zfcp_sysfs_adapter.c b/drivers/s390/scsi/zfcp_sysfs_adapter.c
index e7345a74800a..0cd435280e7d 100644
--- a/drivers/s390/scsi/zfcp_sysfs_adapter.c
+++ b/drivers/s390/scsi/zfcp_sysfs_adapter.c
@@ -62,21 +62,18 @@ static ssize_t zfcp_sysfs_adapter_##_name##_show(struct device *dev, struct devi
static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_adapter_##_name##_show, NULL);
ZFCP_DEFINE_ADAPTER_ATTR(status, "0x%08x\n", atomic_read(&adapter->status));
-ZFCP_DEFINE_ADAPTER_ATTR(wwnn, "0x%016llx\n", adapter->wwnn);
-ZFCP_DEFINE_ADAPTER_ATTR(wwpn, "0x%016llx\n", adapter->wwpn);
-ZFCP_DEFINE_ADAPTER_ATTR(s_id, "0x%06x\n", adapter->s_id);
ZFCP_DEFINE_ADAPTER_ATTR(peer_wwnn, "0x%016llx\n", adapter->peer_wwnn);
ZFCP_DEFINE_ADAPTER_ATTR(peer_wwpn, "0x%016llx\n", adapter->peer_wwpn);
ZFCP_DEFINE_ADAPTER_ATTR(peer_d_id, "0x%06x\n", adapter->peer_d_id);
+ZFCP_DEFINE_ADAPTER_ATTR(physical_wwpn, "0x%016llx\n", adapter->physical_wwpn);
+ZFCP_DEFINE_ADAPTER_ATTR(physical_s_id, "0x%06x\n", adapter->physical_s_id);
ZFCP_DEFINE_ADAPTER_ATTR(card_version, "0x%04x\n", adapter->hydra_version);
ZFCP_DEFINE_ADAPTER_ATTR(lic_version, "0x%08x\n", adapter->fsf_lic_version);
-ZFCP_DEFINE_ADAPTER_ATTR(fc_link_speed, "%d Gb/s\n", adapter->fc_link_speed);
ZFCP_DEFINE_ADAPTER_ATTR(fc_service_class, "%d\n", adapter->fc_service_class);
ZFCP_DEFINE_ADAPTER_ATTR(fc_topology, "%s\n",
fc_topologies[adapter->fc_topology]);
ZFCP_DEFINE_ADAPTER_ATTR(hardware_version, "0x%08x\n",
adapter->hardware_version);
-ZFCP_DEFINE_ADAPTER_ATTR(serial_number, "%17s\n", adapter->serial_number);
ZFCP_DEFINE_ADAPTER_ATTR(scsi_host_no, "0x%x\n", adapter->scsi_host_no);
ZFCP_DEFINE_ADAPTER_ATTR(in_recovery, "%d\n", atomic_test_mask
(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status));
@@ -255,21 +252,18 @@ static struct attribute *zfcp_adapter_attrs[] = {
&dev_attr_in_recovery.attr,
&dev_attr_port_remove.attr,
&dev_attr_port_add.attr,
- &dev_attr_wwnn.attr,
- &dev_attr_wwpn.attr,
- &dev_attr_s_id.attr,
&dev_attr_peer_wwnn.attr,
&dev_attr_peer_wwpn.attr,
&dev_attr_peer_d_id.attr,
+ &dev_attr_physical_wwpn.attr,
+ &dev_attr_physical_s_id.attr,
&dev_attr_card_version.attr,
&dev_attr_lic_version.attr,
- &dev_attr_fc_link_speed.attr,
&dev_attr_fc_service_class.attr,
&dev_attr_fc_topology.attr,
&dev_attr_scsi_host_no.attr,
&dev_attr_status.attr,
&dev_attr_hardware_version.attr,
- &dev_attr_serial_number.attr,
NULL
};