Merge master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-for-linus-2.6

This commit is contained in:
Linus Torvalds 2005-09-20 08:50:49 -07:00
commit 9600c11ba3
45 changed files with 4234 additions and 1584 deletions

View file

@ -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

View file

@ -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)

View file

@ -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);

View file

@ -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

View file

@ -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;
@ -280,6 +284,171 @@ struct fcp_logo {
wwn_t nport_wwpn;
} __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
*/
@ -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*);

View file

@ -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;
/* do 'exchange configuration data' */
retval = zfcp_erp_adapter_strategy_open_fsf_xconfig(erp_action);
if (retval == ZFCP_ERP_FAILED)
return retval;
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;
}
/* start the desired number of Status Reads */
retval = zfcp_erp_adapter_strategy_open_fsf_statusread(erp_action);
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;
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);

View file

@ -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 */

File diff suppressed because it is too large Load diff

View file

@ -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;

View file

@ -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;
/*

View file

@ -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
/**
* 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
*
* 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.)
*
* 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,
};
/**

View file

@ -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
};