Commit e1bc2047 authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Linus Torvalds

[PATCH] s390: zfcp host adapter

From: Heiko Carstens <heiko.carstens@de.ibm.com>
From: Andreas Herrmann <aherrman@de.ibm.com>
From: Maxim Shchetynin <maxim@de.ibm.com>

zfcp host adapter changes:
 - Exploit FC transport class and autoselect SCSI_FC_ATTRS for zfcp.
 - Fix acl download to zfcp controller.
 - Change message loglevels to make zfcp less noisy.
 - Don't wait for SBAL to finish for command aborts after a timeout
   and for logical unit or target resets.
 - Force reopen of port if link test failed.
 - Fix race between qdio_shutdown and do_QDIO.
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 6e955f71
......@@ -124,7 +124,7 @@ CONFIG_SCSI_LOGGING=y
# SCSI Transport Attributes
#
# CONFIG_SCSI_SPI_ATTRS is not set
# CONFIG_SCSI_FC_ATTRS is not set
CONFIG_SCSI_FC_ATTRS=y
#
# SCSI low-level drivers
......
......@@ -29,7 +29,7 @@
*/
/* this drivers version (do not edit !!! generated and updated by cvs) */
#define ZFCP_AUX_REVISION "$Revision: 1.108 $"
#define ZFCP_AUX_REVISION "$Revision: 1.114 $"
#include "zfcp_ext.h"
......@@ -310,6 +310,10 @@ zfcp_module_init(void)
/* initialize adapters to be removed list head */
INIT_LIST_HEAD(&zfcp_data.adapter_remove_lh);
zfcp_transport_template = fc_attach_transport(&zfcp_transport_functions);
if (!zfcp_transport_template)
return -ENODEV;
#ifdef CONFIG_S390_SUPPORT
retval = register_ioctl32_conversion(zfcp_ioctl_trans.cmd,
zfcp_ioctl_trans.handler);
......@@ -414,7 +418,7 @@ zfcp_cfdc_dev_ioctl(struct inode *inode, struct file *file,
retval = -ENOMEM;
goto out;
}
sg_list->count = 0;
memset(sg_list, 0, sizeof(*sg_list));
if (command != ZFCP_CFDC_IOC) {
ZFCP_LOG_INFO("IOC request code 0x%x invalid\n", command);
......@@ -599,6 +603,7 @@ zfcp_sg_list_alloc(struct zfcp_sg_list *sg_list, size_t size)
sg_list->sg = kmalloc(sg_list->count * sizeof(struct scatterlist),
GFP_KERNEL);
if (sg_list->sg == NULL) {
sg_list->count = 0;
retval = -ENOMEM;
goto out;
}
......@@ -635,11 +640,13 @@ zfcp_sg_list_free(struct zfcp_sg_list *sg_list)
unsigned int i;
int retval = 0;
BUG_ON((sg_list->sg == NULL) || (sg_list == NULL));
BUG_ON(sg_list == NULL);
for (i = 0, sg = sg_list->sg; i < sg_list->count; i++, sg++)
__free_pages(sg->page, 0);
kfree(sg_list->sg);
return retval;
}
......
......@@ -33,7 +33,7 @@
#define ZFCP_DEF_H
/* this drivers version (do not edit !!! generated and updated by cvs) */
#define ZFCP_DEF_REVISION "$Revision: 1.73 $"
#define ZFCP_DEF_REVISION "$Revision: 1.75 $"
/*************************** INCLUDES *****************************************/
......@@ -47,6 +47,8 @@
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_transport.h>
#include <scsi/scsi_transport_fc.h>
#include "../../fc4/fc.h"
#include "zfcp_fsf.h"
#include <asm/ccwdev.h>
......@@ -509,14 +511,14 @@ struct zfcp_ls_rnid_acc {
/* all log-level defaults are combined to generate initial log-level */
#define ZFCP_LOG_LEVEL_DEFAULTS \
(ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_INFO, ZFCP_LOG_AREA_OTHER) | \
ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_INFO, ZFCP_LOG_AREA_SCSI) | \
ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_INFO, ZFCP_LOG_AREA_FSF) | \
ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_INFO, ZFCP_LOG_AREA_CONFIG) | \
ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_INFO, ZFCP_LOG_AREA_CIO) | \
ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_INFO, ZFCP_LOG_AREA_QDIO) | \
ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_INFO, ZFCP_LOG_AREA_ERP) | \
ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_INFO, ZFCP_LOG_AREA_FC))
(ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_NORMAL, ZFCP_LOG_AREA_OTHER) | \
ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_NORMAL, ZFCP_LOG_AREA_SCSI) | \
ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_NORMAL, ZFCP_LOG_AREA_FSF) | \
ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_NORMAL, ZFCP_LOG_AREA_CONFIG) | \
ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_NORMAL, ZFCP_LOG_AREA_CIO) | \
ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_NORMAL, ZFCP_LOG_AREA_QDIO) | \
ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_NORMAL, ZFCP_LOG_AREA_ERP) | \
ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_NORMAL, ZFCP_LOG_AREA_FC))
/* check whether we have the right level for logging */
#define ZFCP_LOG_CHECK(level) \
......
......@@ -31,7 +31,7 @@
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_ERP
/* this drivers version (do not edit !!! generated and updated by cvs) */
#define ZFCP_ERP_REVISION "$Revision: 1.54 $"
#define ZFCP_ERP_REVISION "$Revision: 1.56 $"
#include "zfcp_ext.h"
......@@ -435,8 +435,20 @@ zfcp_els_handler(unsigned long data)
u8 req_code, resp_code;
int retval = 0;
if (send_els->status != 0)
if (send_els->status != 0) {
ZFCP_LOG_NORMAL("ELS request timed out, physical port reopen "
"of port 0x%016Lx on adapter %s failed\n",
port->wwpn, zfcp_get_busid_by_port(port));
debug_text_event(port->adapter->erp_dbf, 3, "forcreop");
retval = zfcp_erp_port_forced_reopen(port, 0);
if (retval != 0) {
ZFCP_LOG_NORMAL("reopen of remote port 0x%016Lx "
"on adapter %s failed\n", port->wwpn,
zfcp_get_busid_by_port(port));
retval = -EPERM;
}
goto skip_fsfstatus;
}
req = (void*)((page_to_pfn(send_els->req->page) << PAGE_SHIFT) + send_els->req->offset);
resp = (void*)((page_to_pfn(send_els->resp->page) << PAGE_SHIFT) + send_els->resp->offset);
......@@ -2286,7 +2298,6 @@ zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action)
int i;
volatile struct qdio_buffer_element *sbale;
struct zfcp_adapter *adapter = erp_action->adapter;
int retval_cleanup = 0;
if (atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)) {
ZFCP_LOG_NORMAL("bug: second attempt to set up QDIO on "
......@@ -2301,7 +2312,7 @@ zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action)
zfcp_get_busid_by_adapter(adapter));
goto failed_qdio_establish;
}
ZFCP_LOG_DEBUG("queues established\n");
debug_text_event(adapter->erp_dbf, 3, "qdio_est");
if (qdio_activate(adapter->ccw_device, 0) != 0) {
ZFCP_LOG_INFO("error: activation of QDIO queues failed "
......@@ -2309,7 +2320,7 @@ zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action)
zfcp_get_busid_by_adapter(adapter));
goto failed_qdio_activate;
}
ZFCP_LOG_DEBUG("queues activated\n");
debug_text_event(adapter->erp_dbf, 3, "qdio_act");
/*
* put buffers into response queue,
......@@ -2357,19 +2368,15 @@ zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action)
/* NOP */
failed_qdio_activate:
/* DEBUG */
//__ZFCP_WAIT_EVENT_TIMEOUT(timeout, 0);
/* cleanup queues previously established */
retval_cleanup = qdio_shutdown(adapter->ccw_device,
QDIO_FLAG_CLEANUP_USING_CLEAR);
if (retval_cleanup) {
ZFCP_LOG_NORMAL("bug: shutdown of QDIO queues failed "
"(retval=%d)\n", retval_cleanup);
debug_text_event(adapter->erp_dbf, 3, "qdio_down1a");
while (qdio_shutdown(adapter->ccw_device,
QDIO_FLAG_CLEANUP_USING_CLEAR) == -EINPROGRESS) {
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ);
}
debug_text_event(adapter->erp_dbf, 3, "qdio_down1b");
failed_qdio_establish:
atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status);
failed_sanity:
retval = ZFCP_ERP_FAILED;
......@@ -2401,42 +2408,22 @@ zfcp_erp_adapter_strategy_close_qdio(struct zfcp_erp_action *erp_action)
goto out;
}
/* cleanup queues previously established */
/*
* MUST NOT LOCK - qdio_cleanup might call schedule
* FIXME: need another way to make cleanup safe
* Get queue_lock and clear QDIOUP flag. Thus it's guaranteed that
* do_QDIO won't be called while qdio_shutdown is in progress.
*/
/* Note:
* We need the request_queue lock here, otherwise there exists the
* following race:
*
* queuecommand calls create_fcp_commmand_task...calls req_create,
* gets sbal x to x+y - meanwhile adapter reopen is called, completes
* - req_send calls do_QDIO for sbal x to x+y, i.e. wrong indices.
*
* with lock:
* queuecommand calls create_fcp_commmand_task...calls req_create,
* gets sbal x to x+y - meanwhile adapter reopen is called, waits
* - req_send calls do_QDIO for sbal x to x+y, i.e. wrong indices
* but do_QDIO fails as adapter_reopen is still waiting for the lock
* OR
* queuecommand calls create_fcp_commmand_task...calls req_create
* - meanwhile adapter reopen is called...completes,
* - gets sbal 0 to 0+y, - req_send calls do_QDIO for sbal 0 to 0+y,
* i.e. correct indices...though an fcp command is called before
* exchange config data...that should be fine, however
*/
if (qdio_shutdown(adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR)) {
/*
* FIXME(design):
* What went wrong? What to do best? Proper retval?
*/
ZFCP_LOG_NORMAL("bug: shutdown of QDIO queues failed on "
"adapter %s\n",
zfcp_get_busid_by_adapter(adapter));
} else
ZFCP_LOG_DEBUG("queues cleaned up\n");
write_lock_irq(&adapter->request_queue.queue_lock);
atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status);
write_unlock_irq(&adapter->request_queue.queue_lock);
debug_text_event(adapter->erp_dbf, 3, "qdio_down2a");
while (qdio_shutdown(adapter->ccw_device,
QDIO_FLAG_CLEANUP_USING_CLEAR) == -EINPROGRESS) {
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ);
}
debug_text_event(adapter->erp_dbf, 3, "qdio_down2b");
/*
* First we had to stop QDIO operation.
......@@ -2459,8 +2446,6 @@ zfcp_erp_adapter_strategy_close_qdio(struct zfcp_erp_action *erp_action)
adapter->request_queue.free_index = 0;
atomic_set(&adapter->request_queue.free_count, 0);
adapter->request_queue.distance_from_int = 0;
atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status);
out:
return retval;
}
......
......@@ -31,7 +31,7 @@
#ifndef ZFCP_EXT_H
#define ZFCP_EXT_H
/* this drivers version (do not edit !!! generated and updated by cvs) */
#define ZFCP_EXT_REVISION "$Revision: 1.50 $"
#define ZFCP_EXT_REVISION "$Revision: 1.51 $"
#include "zfcp_def.h"
......@@ -136,6 +136,8 @@ extern int zfcp_scsi_command_async(struct zfcp_adapter *,struct zfcp_unit *unit,
struct scsi_cmnd *scsi_cmnd);
extern int zfcp_scsi_command_sync(struct zfcp_unit *unit,
struct scsi_cmnd *scsi_cmnd);
extern struct scsi_transport_template *zfcp_transport_template;
extern struct fc_function_template zfcp_transport_functions;
/******************************** ERP ****************************************/
extern void zfcp_erp_modify_adapter_status(struct zfcp_adapter *, u32, int);
......
......@@ -29,7 +29,7 @@
*/
/* this drivers version (do not edit !!! generated and updated by cvs) */
#define ZFCP_FSF_C_REVISION "$Revision: 1.47 $"
#define ZFCP_FSF_C_REVISION "$Revision: 1.49 $"
#include "zfcp_ext.h"
......@@ -3997,15 +3997,14 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
scpnt->result |= fcp_rsp_iu->scsi_status;
if (unlikely(fcp_rsp_iu->scsi_status)) {
/* DEBUG */
ZFCP_LOG_NORMAL("status for SCSI Command:\n");
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL,
ZFCP_LOG_DEBUG("status for SCSI Command:\n");
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
scpnt->cmnd, scpnt->cmd_len);
ZFCP_LOG_NORMAL("SCSI status code 0x%x\n",
ZFCP_LOG_DEBUG("SCSI status code 0x%x\n",
fcp_rsp_iu->scsi_status);
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL,
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
(void *) fcp_rsp_iu, sizeof (struct fcp_rsp_iu));
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL,
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
zfcp_get_fcp_sns_info_ptr(fcp_rsp_iu),
fcp_rsp_iu->fcp_sns_len);
}
......@@ -4782,6 +4781,16 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags,
goto failed_sbals;
}
/*
* We hold queue_lock here. Check if QDIOUP is set and let request fail
* if it is not set (see also *_open_qdio and *_close_qdio).
*/
if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)) {
write_unlock_irqrestore(&req_queue->queue_lock, *lock_flags);
goto failed_sbals;
}
fsf_req->adapter = adapter; /* pointer to "parent" adapter */
fsf_req->fsf_command = fsf_cmd;
fsf_req->sbal_number = 1;
......
......@@ -31,7 +31,7 @@
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_SCSI
/* this drivers version (do not edit !!! generated and updated by cvs) */
#define ZFCP_SCSI_REVISION "$Revision: 1.62 $"
#define ZFCP_SCSI_REVISION "$Revision: 1.65 $"
#include "zfcp_ext.h"
......@@ -51,6 +51,8 @@ static struct zfcp_unit *zfcp_unit_lookup(struct zfcp_adapter *, int, scsi_id_t,
static struct device_attribute *zfcp_sysfs_sdev_attrs[];
struct scsi_transport_template *zfcp_transport_template;
struct zfcp_data zfcp_data = {
.scsi_host_template = {
name: ZFCP_NAME,
......@@ -508,8 +510,7 @@ zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
ZFCP_LOG_DEBUG("unit 0x%016Lx (%p)\n", unit->fcp_lun, unit);
/*
* The 'Abort FCP Command' routine may block (call schedule)
* because it may wait for a free SBAL.
* 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
......@@ -518,8 +519,7 @@ zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
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, ZFCP_WAIT_FOR_SBAL);
adapter, unit, 0);
ZFCP_LOG_DEBUG("new_fsf_req=%p\n", new_fsf_req);
if (!new_fsf_req) {
retval = FAILED;
......@@ -657,7 +657,7 @@ zfcp_task_management_function(struct zfcp_unit *unit, u8 tm_flags)
/* issue task management function */
fsf_req = zfcp_fsf_send_fcp_command_task_management
(adapter, unit, tm_flags, ZFCP_WAIT_FOR_SBAL);
(adapter, unit, tm_flags, 0);
if (!fsf_req) {
ZFCP_LOG_INFO("error: creation of task management request "
"failed for unit 0x%016Lx on port 0x%016Lx on "
......@@ -768,6 +768,7 @@ zfcp_adapter_scsi_register(struct zfcp_adapter *adapter)
adapter->scsi_host->max_channel = 0;
adapter->scsi_host->unique_id = unique_id++; /* FIXME */
adapter->scsi_host->max_cmd_len = ZFCP_MAX_SCSI_CMND_LENGTH;
adapter->scsi_host->transportt = zfcp_transport_template;
/*
* Reverse mapping of the host number to avoid race condition
*/
......@@ -823,6 +824,44 @@ zfcp_fsf_start_scsi_er_timer(struct zfcp_adapter *adapter)
add_timer(&adapter->scsi_er_timer);
}
/*
* Support functions for FC transport class
*/
static void
zfcp_get_port_id(struct scsi_device *sdev)
{
struct zfcp_unit *unit;
unit = (struct zfcp_unit *) sdev->hostdata;
fc_port_id(sdev) = unit->port->d_id;
}
static void
zfcp_get_port_name(struct scsi_device *sdev)
{
struct zfcp_unit *unit;
unit = (struct zfcp_unit *) sdev->hostdata;
fc_port_name(sdev) = unit->port->wwpn;
}
static void
zfcp_get_node_name(struct scsi_device *sdev)
{
struct zfcp_unit *unit;
unit = (struct zfcp_unit *) sdev->hostdata;
fc_node_name(sdev) = unit->port->wwnn;
}
struct fc_function_template zfcp_transport_functions = {
.get_port_id = zfcp_get_port_id,
.get_port_name = zfcp_get_port_name,
.get_node_name = zfcp_get_node_name,
.show_port_id = 1,
.show_port_name = 1,
.show_node_name = 1,
};
/**
* ZFCP_DEFINE_SCSI_ATTR
......
......@@ -1738,6 +1738,7 @@ config SCSI_SUNESP
config ZFCP
tristate "FCP host bus adapter driver for IBM eServer zSeries"
depends on ARCH_S390 && SCSI
select SCSI_FC_ATTRS
help
If you want to access SCSI devices attached to your IBM eServer
zSeries by means of Fibre Channel interfaces say Y.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment