Commit b9fbc6c2 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] s390: zfcp host adapter

From: Martin Schwidefsky <schwidefsky@de.ibm.com>

Add new features to the zfcp host adapater driver:
  - Add support for FCP access control.
  - Error recovery enhancements.
parent fb1a1633
......@@ -187,3 +187,5 @@ Code Seq# Include File Comments
0xB1 00-1F PPPoX <mailto:mostrows@styx.uwaterloo.ca>
0xCB 00-1F CBM serial IEC bus in development:
<mailto:michael.klein@puffin.lb.shuttle.de>
0xDD 00-3F ZFCP device driver see drivers/s390/scsi/
<mailto:aherrman@de.ibm.com>
......@@ -4,11 +4,12 @@
*
* FCP adapter driver for IBM eServer zSeries
*
* Copyright 2002 IBM Corporation
* (C) Copyright IBM Corp. 2002, 2004
*
* Author(s): Martin Peschke <mpeschke@de.ibm.com>
* Raimund Schroeder <raimund.schroeder@de.ibm.com>
* Aron Zeh <arzeh@de.ibm.com>
* Wolfgang Taphorn <taphorn@de.ibm.com>
* Aron Zeh
* Wolfgang Taphorn
* Stefan Bader <stefan.bader@de.ibm.com>
* Heiko Carstens <heiko.carstens@de.ibm.com>
*
......@@ -28,7 +29,7 @@
*/
/* this drivers version (do not edit !!! generated and updated by cvs) */
#define ZFCP_AUX_REVISION "$Revision: 1.79 $"
#define ZFCP_AUX_REVISION "$Revision: 1.98 $"
/********************** INCLUDES *********************************************/
......@@ -61,6 +62,9 @@
#include <asm/cpcmd.h> /* Debugging only */
#include <asm/processor.h> /* Debugging only */
#include <linux/miscdevice.h>
#include <linux/major.h>
/* accumulated log level (module parameter) */
static u32 loglevel = ZFCP_LOG_LEVEL_DEFAULTS;
static char *device;
......@@ -73,7 +77,7 @@ static void __exit zfcp_module_exit(void);
int zfcp_reboot_handler(struct notifier_block *, unsigned long, void *);
/* FCP related */
static void zfcp_nameserver_request_handler(struct zfcp_fsf_req *);
static void zfcp_ns_gid_pn_handler(unsigned long);
/* miscellaneous */
#ifdef ZFCP_STAT_REQSIZES
......@@ -83,6 +87,34 @@ static int zfcp_statistics_clear(struct list_head *);
static int zfcp_statistics_new(struct list_head *, u32);
#endif
static inline int zfcp_sg_list_alloc(struct zfcp_sg_list *, size_t);
static inline int zfcp_sg_list_free(struct zfcp_sg_list *);
static inline int zfcp_sg_list_copy_from_user(struct zfcp_sg_list *, void *,
size_t);
static inline int zfcp_sg_list_copy_to_user(void *, struct zfcp_sg_list *,
size_t);
static int zfcp_cfdc_dev_ioctl(struct inode *, struct file *,
unsigned int, unsigned long);
#define ZFCP_CFDC_IOC_MAGIC 0xDD
#define ZFCP_CFDC_IOC \
_IOWR(ZFCP_CFDC_IOC_MAGIC, 0, struct zfcp_cfdc_sense_data)
#ifdef CONFIG_S390_SUPPORT
static struct ioctl_trans zfcp_ioctl_trans = {ZFCP_CFDC_IOC, (void*) sys_ioctl};
#endif
static struct file_operations zfcp_cfdc_fops = {
.ioctl = zfcp_cfdc_dev_ioctl
};
static struct miscdevice zfcp_cfdc_misc = {
.minor = ZFCP_CFDC_DEV_MINOR,
.name = ZFCP_CFDC_DEV_NAME,
.fops = &zfcp_cfdc_fops
};
/*********************** KERNEL/MODULE PARAMETERS ***************************/
/* declare driver module init/cleanup functions */
......@@ -128,7 +160,7 @@ _zfcp_hex_dump(char *addr, int count)
if ((i % 32) == 31)
printk("\n");
}
if ((i % 32) != 31)
if (((i-1) % 32) != 31)
printk("\n");
}
......@@ -137,7 +169,6 @@ _zfcp_hex_dump(char *addr, int count)
/****************************************************************/
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_OTHER
#define ZFCP_LOG_AREA_PREFIX ZFCP_LOG_AREA_PREFIX_OTHER
#ifdef ZFCP_STAT_REQSIZES
......@@ -242,7 +273,7 @@ zfcp_cmd_dbf_event_fsf(const char *text, struct zfcp_fsf_req *fsf_req,
{
#ifdef ZFCP_DEBUG_COMMANDS
struct zfcp_adapter *adapter = fsf_req->adapter;
Scsi_Cmnd *scsi_cmnd;
struct scsi_cmnd *scsi_cmnd;
int level = 3;
int i;
unsigned long flags;
......@@ -258,6 +289,8 @@ zfcp_cmd_dbf_event_fsf(const char *text, struct zfcp_fsf_req *fsf_req,
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,
......@@ -268,8 +301,10 @@ zfcp_cmd_dbf_event_fsf(const char *text, struct zfcp_fsf_req *fsf_req,
#endif
}
/* XXX additionally log unit if available */
/* ---> introduce new parameter for unit, see 2.4 code */
void
zfcp_cmd_dbf_event_scsi(const char *text, Scsi_Cmnd * scsi_cmnd)
zfcp_cmd_dbf_event_scsi(const char *text, struct scsi_cmnd *scsi_cmnd)
{
#ifdef ZFCP_DEBUG_COMMANDS
struct zfcp_adapter *adapter;
......@@ -287,6 +322,8 @@ zfcp_cmd_dbf_event_scsi(const char *text, Scsi_Cmnd * scsi_cmnd)
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));
......@@ -359,13 +396,12 @@ static void __init
zfcp_init_device_configure(void)
{
int found = 0;
unsigned long flags;
struct zfcp_adapter *adapter;
struct zfcp_port *port;
struct zfcp_unit *unit;
down(&zfcp_data.config_sema);
read_lock_irqsave(&zfcp_data.config_lock, flags);
read_lock_irq(&zfcp_data.config_lock);
list_for_each_entry(adapter, &zfcp_data.adapter_list_head, list)
if (strcmp(zfcp_data.init_busid,
zfcp_get_busid_by_adapter(adapter)) == 0) {
......@@ -373,7 +409,7 @@ zfcp_init_device_configure(void)
found = 1;
break;
}
read_unlock_irqrestore(&zfcp_data.config_lock, flags);
read_unlock_irq(&zfcp_data.config_lock);
if (!found)
goto out_adapter;
port = zfcp_port_enqueue(adapter, zfcp_data.init_wwpn, 0);
......@@ -419,6 +455,28 @@ zfcp_module_init(void)
zfcp_statistics_init_all();
#endif
#ifdef CONFIG_S390_SUPPORT
retval = register_ioctl32_conversion(zfcp_ioctl_trans.cmd,
zfcp_ioctl_trans.handler);
if (retval != 0) {
ZFCP_LOG_INFO("Cannot register a 32-bit support of "
"the IOC handler\n");
goto out_ioctl32;
}
#endif
retval = misc_register(&zfcp_cfdc_misc);
if (retval != 0) {
ZFCP_LOG_INFO(
"Device file for the control file data channel "
"cannot be registered\n");
goto out_misc_register;
} else {
ZFCP_LOG_INFO(
"Device file for the control file data channel "
"has become MAJOR/MINOR numbers %d/%d\n",
ZFCP_CFDC_DEV_MAJOR, zfcp_cfdc_misc.minor);
}
/* Initialise proc semaphores */
sema_init(&zfcp_data.config_sema, 1);
......@@ -445,6 +503,12 @@ zfcp_module_init(void)
out_ccw_register:
unregister_reboot_notifier(&zfcp_data.reboot_notifier);
misc_deregister(&zfcp_cfdc_misc);
out_misc_register:
#ifdef CONFIG_S390_SUPPORT
unregister_ioctl32_conversion(zfcp_ioctl_trans.cmd);
out_ioctl32:
#endif
#ifdef ZFCP_STAT_REQSIZES
zfcp_statistics_clear_all();
#endif
......@@ -458,6 +522,10 @@ zfcp_module_exit(void)
{
unregister_reboot_notifier(&zfcp_data.reboot_notifier);
zfcp_ccw_unregister();
misc_deregister(&zfcp_cfdc_misc);
#ifdef CONFIG_S390_SUPPORT
unregister_ioctl32_conversion(zfcp_ioctl_trans.cmd);
#endif
#ifdef ZFCP_STAT_REQSIZES
zfcp_statistics_clear_all();
#endif
......@@ -480,15 +548,372 @@ zfcp_reboot_handler(struct notifier_block *notifier, unsigned long code,
return NOTIFY_DONE;
}
/*
* function: zfcp_cfdc_dev_ioctl
*
* purpose: Handle control file upload/download transaction via IOCTL
* interface
*
* returns: 0 - Operation completed successfuly
* -ENOTTY - Unknown IOCTL command
* -EINVAL - Invalid sense data record
* -ENXIO - The FCP adapter is not available
* -EOPNOTSUPP - The FCP adapter does not have CFDC support
* -ENOMEM - Insufficient memory
* -EFAULT - User space memory I/O operation fault
* -EPERM - Cannot create or queue FSF request or create SBALs
*/
static int
zfcp_cfdc_dev_ioctl(struct inode *inode, struct file *file,
unsigned int command, unsigned long buffer)
{
struct zfcp_cfdc_sense_data sense_data, *sense_data_user;
struct zfcp_adapter *adapter = NULL;
struct zfcp_fsf_req *fsf_req = NULL;
struct zfcp_sg_list *sg_list = NULL;
u32 fsf_command, option;
char *bus_id = NULL;
int retval = 0;
ZFCP_LOG_NORMAL(
"Control file data channel transaction opened\n");
sg_list = kmalloc(sizeof(struct zfcp_sg_list), GFP_KERNEL);
if (sg_list == NULL) {
ZFCP_LOG_NORMAL(
"Not enough memory for the scatter-gather list\n");
retval = -ENOMEM;
goto out;
}
sg_list->count = 0;
if (command != ZFCP_CFDC_IOC) {
ZFCP_LOG_NORMAL(
"IOC request code 0x%x is not valid\n",
command);
retval = -ENOTTY;
goto out;
}
if ((sense_data_user = (struct zfcp_cfdc_sense_data*)buffer) == NULL) {
ZFCP_LOG_NORMAL(
"Sense data record is required\n");
retval = -EINVAL;
goto out;
}
retval = copy_from_user(&sense_data, sense_data_user,
sizeof(struct zfcp_cfdc_sense_data));
if (retval) {
ZFCP_LOG_NORMAL("Cannot copy sense data record from user space "
"memory\n");
retval = -EFAULT;
goto out;
}
if (sense_data.signature != ZFCP_CFDC_SIGNATURE) {
ZFCP_LOG_NORMAL(
"No valid sense data request signature 0x%08x found\n",
ZFCP_CFDC_SIGNATURE);
retval = -EINVAL;
goto out;
}
switch (sense_data.command) {
case ZFCP_CFDC_CMND_DOWNLOAD_NORMAL:
fsf_command = FSF_QTCB_DOWNLOAD_CONTROL_FILE;
option = FSF_CFDC_OPTION_NORMAL_MODE;
break;
case ZFCP_CFDC_CMND_DOWNLOAD_FORCE:
fsf_command = FSF_QTCB_DOWNLOAD_CONTROL_FILE;
option = FSF_CFDC_OPTION_FORCE;
break;
case ZFCP_CFDC_CMND_FULL_ACCESS:
fsf_command = FSF_QTCB_DOWNLOAD_CONTROL_FILE;
option = FSF_CFDC_OPTION_FULL_ACCESS;
break;
case ZFCP_CFDC_CMND_RESTRICTED_ACCESS:
fsf_command = FSF_QTCB_DOWNLOAD_CONTROL_FILE;
option = FSF_CFDC_OPTION_RESTRICTED_ACCESS;
break;
case ZFCP_CFDC_CMND_UPLOAD:
fsf_command = FSF_QTCB_UPLOAD_CONTROL_FILE;
option = 0;
break;
default:
ZFCP_LOG_NORMAL(
"Command code 0x%08x is not valid\n",
sense_data.command);
retval = -EINVAL;
goto out;
}
bus_id = kmalloc(BUS_ID_SIZE, GFP_KERNEL);
if (bus_id == NULL) {
ZFCP_LOG_NORMAL("Out of memory!\n");
retval = -ENOMEM;
goto out;
}
snprintf(bus_id, BUS_ID_SIZE, "%d.%d.%04x",
(sense_data.devno >> 24),
(sense_data.devno >> 16) & 0xFF,
(sense_data.devno & 0xFFFF));
retval = -ENXIO;
read_lock_irq(&zfcp_data.config_lock);
list_for_each_entry(adapter, &zfcp_data.adapter_list_head, list) {
if (strncmp(bus_id, zfcp_get_busid_by_adapter(adapter),
BUS_ID_SIZE) == 0) {
zfcp_adapter_get(adapter);
retval = 0;
break;
}
}
read_unlock_irq(&zfcp_data.config_lock);
kfree(bus_id);
if (retval != 0) {
ZFCP_LOG_NORMAL("Specified adapter does not exist\n");
goto out;
}
if (sense_data.command & ZFCP_CFDC_WITH_CONTROL_FILE) {
retval = zfcp_sg_list_alloc(sg_list,
ZFCP_CFDC_MAX_CONTROL_FILE_SIZE);
if (retval) {
ZFCP_LOG_NORMAL("Not enough memory for the "
"scatter-gather list\n");
retval = -ENOMEM;
goto out;
}
}
if ((sense_data.command & ZFCP_CFDC_DOWNLOAD) &&
(sense_data.command & ZFCP_CFDC_WITH_CONTROL_FILE)) {
retval = zfcp_sg_list_copy_from_user(
sg_list, &sense_data_user->control_file,
ZFCP_CFDC_MAX_CONTROL_FILE_SIZE);
if (retval) {
ZFCP_LOG_NORMAL("Cannot copy control file from user "
"space memory\n");
retval = -EFAULT;
goto out;
}
}
retval = zfcp_fsf_control_file(
adapter, &fsf_req, fsf_command, option, sg_list);
if (retval == -EOPNOTSUPP) {
ZFCP_LOG_NORMAL(
"Specified adapter does not support control file\n");
goto out;
} else if (retval != 0) {
ZFCP_LOG_NORMAL(
"Cannot create or queue FSF request or create SBALs\n");
retval = -EPERM;
goto out;
}
wait_event(fsf_req->completion_wq,
fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
sense_data.fsf_status = fsf_req->qtcb->header.fsf_status;
memcpy(&sense_data.fsf_status_qual,
&fsf_req->qtcb->header.fsf_status_qual,
sizeof(union fsf_status_qual));
memcpy(&sense_data.payloads, &fsf_req->qtcb->bottom.support.els, 256);
retval = copy_to_user(sense_data_user, &sense_data,
sizeof(struct zfcp_cfdc_sense_data));
if (retval) {
ZFCP_LOG_NORMAL(
"Cannot copy sense data record to user space memory\n");
retval = -EFAULT;
goto out;
}
if (sense_data.command & ZFCP_CFDC_UPLOAD) {
retval = zfcp_sg_list_copy_to_user(
&sense_data_user->control_file, sg_list,
ZFCP_CFDC_MAX_CONTROL_FILE_SIZE);
if (retval) {
ZFCP_LOG_NORMAL("Cannot copy control file to user "
"space memory\n");
retval = -EFAULT;
goto out;
}
}
out:
if (fsf_req != NULL)
zfcp_fsf_req_cleanup(fsf_req);
if ((adapter != NULL) && (retval != -ENXIO))
zfcp_adapter_put(adapter);
if (sg_list != NULL) {
zfcp_sg_list_free(sg_list);
kfree(sg_list);
}
ZFCP_LOG_NORMAL(
"Control file data channel transaction closed\n");
return retval;
}
/*
* function: zfcp_sg_list_alloc
*
* purpose: Create a scatter-gather list of the specified size
*
* returns: 0 - Scatter gather list is created
* -ENOMEM - Insufficient memory (*list_ptr is then set to NULL)
*/
static inline int
zfcp_sg_list_alloc(struct zfcp_sg_list *sg_list, size_t size)
{
struct scatterlist *sg;
int i;
int retval = 0;
sg_list->count = size >> PAGE_SHIFT;
if (size & ~PAGE_MASK)
sg_list->count++;
sg_list->sg = kmalloc(sg_list->count * sizeof(struct scatterlist),
GFP_KERNEL);
if (sg_list->sg == NULL) {
retval = -ENOMEM;
goto out;
}
for (i = 0, sg = sg_list->sg; i < sg_list->count; i++, sg++) {
sg->length = min(size, PAGE_SIZE);
sg->offset = 0;
sg->page = alloc_pages(GFP_KERNEL, 0);
if (sg->page == NULL) {
sg_list->count = i;
zfcp_sg_list_free(sg_list);
retval = -ENOMEM;
goto out;
}
size -= sg->length;
}
out:
return retval;
}
/*
* function: zfcp_sg_list_free
*
* purpose: Destroy a scatter-gather list and release memory
*
* returns: Always 0
*/
static inline int
zfcp_sg_list_free(struct zfcp_sg_list *sg_list)
{
struct scatterlist *sg;
int i;
int retval = 0;
BUG_ON((sg_list->sg == NULL) || (sg_list == NULL));
for (i = 0, sg = sg_list->sg; i < sg_list->count; i++, sg++)
__free_pages(sg->page, 0);
return retval;
}
/*
* function: zfcp_sg_list_copy_from_user
*
* purpose: Copy data from user space memory to the scatter-gather list
*
* returns: 0 - The data has been copied from user
* -EFAULT - Memory I/O operation fault
*/
static inline int
zfcp_sg_list_copy_from_user(struct zfcp_sg_list *sg_list, void *user_buffer,
size_t size)
{
struct scatterlist *sg;
unsigned int length;
void *zfcp_buffer;
int retval = 0;
for (sg = sg_list->sg; size > 0; sg++) {
length = min((unsigned int)size, sg->length);
zfcp_buffer = (void*)
((page_to_pfn(sg->page) << PAGE_SHIFT) + sg->offset);
if (copy_from_user(zfcp_buffer, user_buffer, length)) {
ZFCP_LOG_INFO("Memory error (copy_from_user)\n");
retval = -EFAULT;
goto out;
}
user_buffer += length;
size -= length;
}
out:
return retval;
}
/*
* function: zfcp_sg_list_copy_to_user
*
* purpose: Copy data from the scatter-gather list to user space memory
*
* returns: 0 - The data has been copied to user
* -EFAULT - Memory I/O operation fault
*/
static inline int
zfcp_sg_list_copy_to_user(void *user_buffer, struct zfcp_sg_list *sg_list,
size_t size)
{
struct scatterlist *sg;
unsigned int length;
void *zfcp_buffer;
int retval = 0;
for (sg = sg_list->sg; size > 0; sg++) {
length = min((unsigned int)size, sg->length);
zfcp_buffer = (void*)
((page_to_pfn(sg->page) << PAGE_SHIFT) + sg->offset);
if (copy_to_user(user_buffer, zfcp_buffer, length)) {
ZFCP_LOG_INFO("Memory error (copy_to_user)\n");
retval = -EFAULT;
goto out;
}
user_buffer += length;
size -= length;
}
out:
return retval;
}
#undef ZFCP_LOG_AREA
#undef ZFCP_LOG_AREA_PREFIX
/****************************************************************/
/****** Functions for configuration/set-up of structures ********/
/****************************************************************/
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG
#define ZFCP_LOG_AREA_PREFIX ZFCP_LOG_AREA_PREFIX_CONFIG
/**
* zfcp_get_unit_by_lun - find unit in unit list of port by fcp lun
......@@ -684,83 +1109,92 @@ zfcp_mempool_free(void *element, void *size)
static int
zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter)
{
adapter->pool.erp_fsf = mempool_create(
1,
zfcp_mempool_alloc,
zfcp_mempool_free,
(void *) ZFCP_QTCB_AND_REQ_SIZE);
if (!adapter->pool.erp_fsf) {
ZFCP_LOG_INFO
("error: FCP command buffer pool allocation failed\n");
adapter->pool.fsf_req_erp =
mempool_create(ZFCP_POOL_FSF_REQ_ERP_NR,
zfcp_mempool_alloc, zfcp_mempool_free, (void *)
sizeof(struct zfcp_fsf_req_pool_element));
if (NULL == adapter->pool.fsf_req_erp) {
ZFCP_LOG_INFO("error: pool allocation failed (fsf_req_erp)\n");
return -ENOMEM;
}
adapter->pool.nameserver = mempool_create(
1,
zfcp_mempool_alloc,
zfcp_mempool_free,
(void *) (2 * sizeof (struct fc_ct_iu)));
if (!adapter->pool.nameserver) {
ZFCP_LOG_INFO
("error: Nameserver buffer pool allocation failed\n");
adapter->pool.fsf_req_scsi =
mempool_create(ZFCP_POOL_FSF_REQ_SCSI_NR,
zfcp_mempool_alloc, zfcp_mempool_free, (void *)
sizeof(struct zfcp_fsf_req_pool_element));
if (NULL == adapter->pool.fsf_req_scsi) {
ZFCP_LOG_INFO("error: pool allocation failed (fsf_req_scsi)\n");
return -ENOMEM;
}
adapter->pool.status_read_fsf = mempool_create(
ZFCP_STATUS_READS_RECOM,
zfcp_mempool_alloc,
zfcp_mempool_free,
(void *) sizeof (struct zfcp_fsf_req));
if (!adapter->pool.status_read_fsf) {
ZFCP_LOG_INFO
("error: Status read request pool allocation failed\n");
adapter->pool.fsf_req_abort =
mempool_create(ZFCP_POOL_FSF_REQ_ABORT_NR,
zfcp_mempool_alloc, zfcp_mempool_free, (void *)
sizeof(struct zfcp_fsf_req_pool_element));
if (NULL == adapter->pool.fsf_req_abort) {
ZFCP_LOG_INFO("error: pool allocation failed "
"(fsf_req_abort)\n");
return -ENOMEM;
}
adapter->pool.status_read_buf = mempool_create(
ZFCP_STATUS_READS_RECOM,
zfcp_mempool_alloc,
zfcp_mempool_free,
(void *) sizeof (struct fsf_status_read_buffer));
if (!adapter->pool.status_read_buf) {
ZFCP_LOG_INFO
("error: Status read buffer pool allocation failed\n");
adapter->pool.fsf_req_status_read =
mempool_create(ZFCP_POOL_STATUS_READ_NR,
zfcp_mempool_alloc, zfcp_mempool_free,
(void *) sizeof(struct zfcp_fsf_req));
if (NULL == adapter->pool.fsf_req_status_read) {
ZFCP_LOG_INFO("error: pool allocation failed "
"(fsf_req_status_read\n");
return -ENOMEM;
}
adapter->pool.fcp_command_fsf = mempool_create(
1,
zfcp_mempool_alloc,
zfcp_mempool_free,
(void *)
ZFCP_QTCB_AND_REQ_SIZE);
if (!adapter->pool.fcp_command_fsf) {
ZFCP_LOG_INFO
("error: FCP command buffer pool allocation failed\n");
adapter->pool.data_status_read =
mempool_create(ZFCP_POOL_STATUS_READ_NR,
zfcp_mempool_alloc, zfcp_mempool_free,
(void *) sizeof(struct fsf_status_read_buffer));
if (NULL == adapter->pool.data_status_read) {
ZFCP_LOG_INFO("error: pool allocation failed "
"(data_status_read)\n");
return -ENOMEM;
}
adapter->pool.data_gid_pn =
mempool_create(ZFCP_POOL_DATA_GID_PN_NR,
zfcp_mempool_alloc, zfcp_mempool_free, (void *)
sizeof(struct zfcp_gid_pn_data));
if (NULL == adapter->pool.data_gid_pn) {
ZFCP_LOG_INFO("error: pool allocation failed (data_gid_pn)\n");
return -ENOMEM;
}
init_timer(&adapter->pool.fcp_command_fsf_timer);
adapter->pool.fcp_command_fsf_timer.function =
zfcp_erp_scsi_low_mem_buffer_timeout_handler;
adapter->pool.fcp_command_fsf_timer.data = (unsigned long) adapter;
return 0;
}
/* locks: must only be called with zfcp_data.config_sema taken */
/**
* zfcp_free_low_mem_buffers - free memory pools of an adapter
* @adapter: pointer to zfcp_adapter for which memory pools should be freed
* locking: zfcp_data.config_sema must be held
*/
static void
zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter)
{
if (adapter->pool.status_read_fsf)
mempool_destroy(adapter->pool.status_read_fsf);
if (adapter->pool.status_read_buf)
mempool_destroy(adapter->pool.status_read_buf);
if (adapter->pool.nameserver)
mempool_destroy(adapter->pool.nameserver);
if (adapter->pool.erp_fsf)
mempool_destroy(adapter->pool.erp_fsf);
if (adapter->pool.fcp_command_fsf)
mempool_destroy(adapter->pool.fcp_command_fsf);
if (adapter->pool.fsf_req_erp)
mempool_destroy(adapter->pool.fsf_req_erp);
if (adapter->pool.fsf_req_scsi)
mempool_destroy(adapter->pool.fsf_req_scsi);
if (adapter->pool.fsf_req_abort)
mempool_destroy(adapter->pool.fsf_req_abort);
if (adapter->pool.fsf_req_status_read)
mempool_destroy(adapter->pool.fsf_req_status_read);
if (adapter->pool.data_status_read)
mempool_destroy(adapter->pool.data_status_read);
if (adapter->pool.data_gid_pn)
mempool_destroy(adapter->pool.data_gid_pn);
}
/*
......@@ -859,7 +1293,7 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
#ifdef ZFCP_DEBUG_REQUESTS
/* debug feature area which records fsf request sequence numbers */
sprintf(dbf_name, ZFCP_REQ_DBF_NAME "0x%s",
sprintf(dbf_name, ZFCP_REQ_DBF_NAME "%s",
zfcp_get_busid_by_adapter(adapter));
adapter->req_dbf = debug_register(dbf_name,
ZFCP_REQ_DBF_INDEX,
......@@ -954,15 +1388,6 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
debug_register_view(adapter->erp_dbf, &debug_hex_ascii_view);
debug_set_level(adapter->erp_dbf, ZFCP_ERP_DBF_LEVEL);
retval = zfcp_erp_thread_setup(adapter);
if (retval) {
ZFCP_LOG_INFO("error: out of resources. "
"error recovery thread for the adapter %s "
"could not be started\n",
zfcp_get_busid_by_adapter(adapter));
goto thread_failed;
}
/* put allocated adapter at list tail */
write_lock_irq(&zfcp_data.config_lock);
atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status);
......@@ -973,15 +1398,6 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
goto out;
thread_failed:
if (qdio_free(adapter->ccw_device) != 0)
ZFCP_LOG_NORMAL
("bug: could not free memory used by data transfer "
"mechanism for adapter %s\n",
zfcp_get_busid_by_adapter(adapter));
debug_unregister(adapter->erp_dbf);
failed_erp_dbf:
#ifdef ZFCP_DEBUG_INCOMING_ELS
debug_unregister(adapter->in_els_dbf);
......@@ -1007,7 +1423,11 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
dev_set_drvdata(&ccw_device->dev, NULL);
failed_low_mem_buffers:
zfcp_free_low_mem_buffers(adapter);
qdio_free(ccw_device);
if (qdio_free(ccw_device) != 0)
ZFCP_LOG_NORMAL
("bug: could not free memory used by data transfer "
"mechanism for adapter %s\n",
zfcp_get_busid_by_adapter(adapter));
qdio_allocate_failed:
zfcp_qdio_free_queues(adapter);
queues_alloc_failed:
......@@ -1060,9 +1480,7 @@ zfcp_adapter_dequeue(struct zfcp_adapter *adapter)
"%i adapters still in list\n",
(unsigned long) adapter, zfcp_data.adapters);
retval = zfcp_erp_thread_kill(adapter);
retval |= qdio_free(adapter->ccw_device);
retval = qdio_free(adapter->ccw_device);
if (retval)
ZFCP_LOG_NORMAL
("bug: could not free memory used by data transfer "
......@@ -1261,14 +1679,12 @@ zfcp_nameserver_enqueue(struct zfcp_adapter *adapter)
}
#undef ZFCP_LOG_AREA
#undef ZFCP_LOG_AREA_PREFIX
/****************************************************************/
/******* Fibre Channel Standard related Functions **************/
/****************************************************************/
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_FC
#define ZFCP_LOG_AREA_PREFIX ZFCP_LOG_AREA_PREFIX_FC
void
zfcp_fsf_incoming_els_rscn(struct zfcp_adapter *adapter,
......@@ -1361,7 +1777,7 @@ zfcp_fsf_incoming_els_rscn(struct zfcp_adapter *adapter,
"0x%Lx.\n", port->wwpn);
debug_text_event(adapter->erp_dbf, 1,
"unsol_els_rscnk:");
zfcp_erp_port_reopen(port, 0);
zfcp_test_link(port);
}
}
read_unlock_irqrestore(&zfcp_data.config_lock, flags);
......@@ -1462,222 +1878,180 @@ zfcp_fsf_incoming_els(struct zfcp_fsf_req *fsf_req)
zfcp_fsf_incoming_els_rscn(adapter, status_buffer);
else
zfcp_fsf_incoming_els_unknown(adapter, status_buffer);
}
/*
* function: zfcp_release_nameserver_buffers
*
* purpose:
*
* returns:
*/
static void
zfcp_release_nameserver_buffers(struct zfcp_fsf_req *fsf_req)
{
struct zfcp_adapter *adapter = fsf_req->adapter;
void *buffer = fsf_req->data.send_generic.outbuf;
/* FIXME: not sure about appeal of this new flag (martin) */
if (fsf_req->status & ZFCP_STATUS_FSFREQ_POOLBUF)
mempool_free(buffer, adapter->pool.nameserver);
else
kfree(buffer);
}
/*
* function: zfcp_get_nameserver_buffers
*
* purpose:
*
* returns:
*
* locks: fsf_request_list_lock is held when doing buffer pool
* operations
/**
* zfcp_gid_pn_buffers_alloc - allocate buffers for GID_PN nameserver request
* @gid_pn: pointer to return pointer to struct zfcp_gid_pn_data
* @pool: pointer to mempool_t if non-null memory pool is used for allocation
*/
static int
zfcp_get_nameserver_buffers(struct zfcp_fsf_req *fsf_req)
zfcp_gid_pn_buffers_alloc(struct zfcp_gid_pn_data **gid_pn, mempool_t *pool)
{
struct zfcp_send_generic *data = &fsf_req->data.send_generic;
struct zfcp_adapter *adapter = fsf_req->adapter;
int retval = 0;
struct zfcp_gid_pn_data *data;
data->outbuf = kmalloc(2 * sizeof (struct fc_ct_iu), GFP_ATOMIC);
if (data->outbuf) {
memset(data->outbuf, 0, 2 * sizeof (struct fc_ct_iu));
if (pool != NULL) {
data = mempool_alloc(pool, GFP_ATOMIC);
if (likely(data != NULL)) {
data->ct.pool = pool;
}
} else {
ZFCP_LOG_DEBUG("Out of memory. Could not allocate at "
"least one of the buffers "
"required for a name-server request on the"
"adapter %s directly.. trying emergency pool\n",
zfcp_get_busid_by_adapter(adapter));
data->outbuf =
mempool_alloc(adapter->pool.nameserver, GFP_ATOMIC);
if (!data->outbuf) {
ZFCP_LOG_DEBUG
("Out of memory. Could not get emergency "
"buffer required for a name-server request "
"on the adapter %s. All buffers are in "
"use.\n",
zfcp_get_busid_by_adapter(adapter));
retval = -ENOMEM;
goto out;
data = kmalloc(sizeof(struct zfcp_gid_pn_data), GFP_ATOMIC);
}
memset(data->outbuf, 0, 2 * sizeof (struct fc_ct_iu));
fsf_req->status |= ZFCP_STATUS_FSFREQ_POOLBUF;
if (NULL == data){
ZFCP_LOG_DEBUG("Out of memory.\n");
return -ENOMEM;
}
data->outbuf_length = sizeof (struct fc_ct_iu);
data->inbuf_length = sizeof (struct fc_ct_iu);
data->inbuf =
(char *) ((unsigned long) data->outbuf + sizeof (struct fc_ct_iu));
out:
return retval;
memset(data, 0, sizeof(*data));
data->ct.req = &data->req;
data->ct.resp = &data->resp;
data->ct.req_count = data->ct.resp_count = 1;
zfcp_address_to_sg(&data->ct_iu_req, &data->req);
zfcp_address_to_sg(&data->ct_iu_resp, &data->resp);
data->req.length = sizeof(struct ct_iu_gid_pn_req);
data->resp.length = sizeof(struct ct_iu_gid_pn_resp);
*gid_pn = data;
return 0;
}
/*
* function: zfcp_nameserver_request
*
* purpose:
*
* returns:
/**
* zfcp_gid_pn_buffers_free - free buffers for GID_PN nameserver request
* @gid_pn: pointer to struct zfcp_gid_pn_data which has to be freed
*/
int
zfcp_nameserver_request(struct zfcp_erp_action *erp_action)
static void
zfcp_gid_pn_buffers_free(struct zfcp_gid_pn_data *gid_pn)
{
int retval = 0;
struct fc_ct_iu *fc_ct_iu;
unsigned long lock_flags;
/* setup new FSF request */
retval = zfcp_fsf_req_create(erp_action->adapter,
FSF_QTCB_SEND_GENERIC,
&lock_flags,
ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
&(erp_action->fsf_req));
if (retval < 0) {
ZFCP_LOG_INFO("error: Out of resources. Could not create a "
"nameserver registration request for "
"adapter %s.\n",
zfcp_get_busid_by_adapter(erp_action->adapter));
goto failed_req;
}
retval = zfcp_get_nameserver_buffers(erp_action->fsf_req);
if (retval < 0) {
ZFCP_LOG_INFO("error: Out of memory. Could not allocate one of "
"the buffers required for a nameserver request "
"on adapter %s.\n",
zfcp_get_busid_by_adapter(erp_action->adapter));
goto failed_buffers;
if ((gid_pn->ct.pool != 0)) {
mempool_free(gid_pn, gid_pn->ct.pool);
} else {
kfree(gid_pn);
}
/* setup name-server request in first page */
fc_ct_iu =
(struct fc_ct_iu *) erp_action->fsf_req->data.send_generic.outbuf;
fc_ct_iu->revision = ZFCP_CT_REVISION;
fc_ct_iu->gs_type = ZFCP_CT_DIRECTORY_SERVICE;
fc_ct_iu->gs_subtype = ZFCP_CT_NAME_SERVER;
fc_ct_iu->options = ZFCP_CT_SYNCHRONOUS;
fc_ct_iu->cmd_rsp_code = ZFCP_CT_GID_PN;
fc_ct_iu->max_res_size = ZFCP_CT_MAX_SIZE;
fc_ct_iu->data.wwpn = erp_action->port->wwpn;
erp_action->fsf_req->data.send_generic.handler =
zfcp_nameserver_request_handler;
erp_action->fsf_req->data.send_generic.handler_data =
(unsigned long) erp_action->port;
erp_action->fsf_req->data.send_generic.port =
erp_action->adapter->nameserver_port;
erp_action->fsf_req->erp_action = erp_action;
/* send this one */
retval = zfcp_fsf_send_generic(erp_action->fsf_req,
ZFCP_NAMESERVER_TIMEOUT,
&lock_flags,
&erp_action->timer);
if (retval) {
ZFCP_LOG_INFO("error: Could not send a"
"nameserver request command to adapter %s\n",
zfcp_get_busid_by_adapter(erp_action->adapter));
goto failed_send;
}
return;
}
/**
* zfcp_ns_gid_pn_request - initiate GID_PN nameserver request
* @erp_action: pointer to zfcp_erp_action where GID_PN request is needed
*/
int
zfcp_ns_gid_pn_request(struct zfcp_erp_action *erp_action)
{
int ret;
struct ct_iu_gid_pn_req *ct_iu_req;
struct zfcp_gid_pn_data *gid_pn;
struct zfcp_adapter *adapter = erp_action->adapter;
ret = zfcp_gid_pn_buffers_alloc(&gid_pn, adapter->pool.data_gid_pn);
if (ret < 0) {
ZFCP_LOG_INFO("error: Out of memory. Could not allocate "
"buffers for nameserver request GID_PN. "
"(adapter: %s)\n",
zfcp_get_busid_by_adapter(adapter));
goto out;
}
failed_send:
zfcp_release_nameserver_buffers(erp_action->fsf_req);
/* setup nameserver request */
ct_iu_req = zfcp_sg_to_address(gid_pn->ct.req);
ct_iu_req->header.revision = ZFCP_CT_REVISION;
ct_iu_req->header.gs_type = ZFCP_CT_DIRECTORY_SERVICE;
ct_iu_req->header.gs_subtype = ZFCP_CT_NAME_SERVER;
ct_iu_req->header.options = ZFCP_CT_SYNCHRONOUS;
ct_iu_req->header.cmd_rsp_code = ZFCP_CT_GID_PN;
ct_iu_req->header.max_res_size = ZFCP_CT_MAX_SIZE;
ct_iu_req->wwpn = erp_action->port->wwpn;
/* setup parameters for send generic command */
gid_pn->ct.port = adapter->nameserver_port;
gid_pn->ct.handler = zfcp_ns_gid_pn_handler;
gid_pn->ct.handler_data = (unsigned long) gid_pn;
gid_pn->ct.timeout = ZFCP_NS_GID_PN_TIMEOUT;
gid_pn->ct.timer = &erp_action->timer;
gid_pn->port = erp_action->port;
ret = zfcp_fsf_send_ct(&gid_pn->ct, adapter->pool.fsf_req_erp,
erp_action);
if (ret) {
ZFCP_LOG_INFO("error: Could not send nameserver request GID_PN."
"(adapter %s)\n",
zfcp_get_busid_by_adapter(adapter));
failed_buffers:
zfcp_fsf_req_free(erp_action->fsf_req);
erp_action->fsf_req = NULL;
zfcp_gid_pn_buffers_free(gid_pn);
}
failed_req:
out:
write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock,
lock_flags);
return retval;
return ret;
}
/*
* function: zfcp_nameserver_request_handler
*
* purpose:
*
* returns:
/**
* zfcp_ns_gid_pn_handler - handler for GID_PN nameserver request
* @data: unsigned long, contains pointer to struct zfcp_gid_pn_data
*/
static void
zfcp_nameserver_request_handler(struct zfcp_fsf_req *fsf_req)
static void zfcp_ns_gid_pn_handler(unsigned long data)
{
struct fc_ct_iu *fc_ct_iu_resp =
(struct fc_ct_iu *) (fsf_req->data.send_generic.inbuf);
struct fc_ct_iu *fc_ct_iu_req =
(struct fc_ct_iu *) (fsf_req->data.send_generic.outbuf);
struct zfcp_port *port =
(struct zfcp_port *) fsf_req->data.send_generic.handler_data;
if (fc_ct_iu_resp->revision != ZFCP_CT_REVISION)
struct zfcp_port *port;
struct zfcp_send_ct *ct;
struct ct_iu_gid_pn_req *ct_iu_req;
struct ct_iu_gid_pn_resp *ct_iu_resp;
struct zfcp_gid_pn_data *gid_pn;
gid_pn = (struct zfcp_gid_pn_data *) data;
port = gid_pn->port;
ct = &gid_pn->ct;
ct_iu_req = zfcp_sg_to_address(ct->req);
ct_iu_resp = zfcp_sg_to_address(ct->resp);
if (ct_iu_resp->header.revision != ZFCP_CT_REVISION)
goto failed;
if (fc_ct_iu_resp->gs_type != ZFCP_CT_DIRECTORY_SERVICE)
if (ct_iu_resp->header.gs_type != ZFCP_CT_DIRECTORY_SERVICE)
goto failed;
if (fc_ct_iu_resp->gs_subtype != ZFCP_CT_NAME_SERVER)
if (ct_iu_resp->header.gs_subtype != ZFCP_CT_NAME_SERVER)
goto failed;
if (fc_ct_iu_resp->options != ZFCP_CT_SYNCHRONOUS)
if (ct_iu_resp->header.options != ZFCP_CT_SYNCHRONOUS)
goto failed;
if (fc_ct_iu_resp->cmd_rsp_code != ZFCP_CT_ACCEPT) {
if (ct_iu_resp->header.cmd_rsp_code != ZFCP_CT_ACCEPT) {
/* FIXME: do we need some specific erp entry points */
atomic_set_mask(ZFCP_STATUS_PORT_INVALID_WWPN, &port->status);
goto failed;
}
/* paranoia */
if (fc_ct_iu_req->data.wwpn != port->wwpn) {
ZFCP_LOG_NORMAL("bug: Port WWPN returned by nameserver lookup "
"does not correspond to "
"the expected value on the adapter %s. "
"(debug info 0x%Lx, 0x%Lx)\n",
zfcp_get_busid_by_port(port),
port->wwpn, fc_ct_iu_req->data.wwpn);
if (ct_iu_req->wwpn != port->wwpn) {
ZFCP_LOG_NORMAL(
"bug: Port WWPN returned by nameserver lookup "
"does not correspond to the expected value "
"(adapter: %s, debug info: 0x%016Lx, 0x%016Lx)\n",
zfcp_get_busid_by_port(port), port->wwpn,
ct_iu_req->wwpn);
goto failed;
}
/* looks like a valid d_id */
port->d_id = ZFCP_DID_MASK & fc_ct_iu_resp->data.d_id;
port->d_id = ct_iu_resp->d_id & ZFCP_DID_MASK;
atomic_set_mask(ZFCP_STATUS_PORT_DID_DID, &port->status);
ZFCP_LOG_DEBUG("busid %s: WWPN=0x%Lx ---> D_ID=0x%6.6x\n",
zfcp_get_busid_by_port(port),
port->wwpn, (unsigned int) port->d_id);
goto out;
failed:
failed:
ZFCP_LOG_NORMAL("warning: WWPN 0x%Lx not found by nameserver lookup "
"using the adapter %s\n",
"(adapter: %s)\n",
port->wwpn, zfcp_get_busid_by_port(port));
ZFCP_LOG_DEBUG("CT IUs do not match:\n");
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
(char *) fc_ct_iu_req, sizeof (struct fc_ct_iu));
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
(char *) fc_ct_iu_resp, sizeof (struct fc_ct_iu));
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, (char *) ct_iu_req,
sizeof(struct ct_iu_gid_pn_req));
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, (char *) ct_iu_resp,
sizeof(struct ct_iu_gid_pn_resp));
out:
zfcp_release_nameserver_buffers(fsf_req);
zfcp_gid_pn_buffers_free(gid_pn);
return;
}
#undef ZFCP_LOG_AREA
#undef ZFCP_LOG_AREA_PREFIX
......@@ -5,7 +5,8 @@
*
* CCW driver related routines
*
* Copyright (C) 2003 IBM Entwicklung GmbH, IBM Corporation
* (C) Copyright IBM Corp. 2003, 2004
*
* Authors:
* Martin Peschke <mpeschke@de.ibm.com>
* Heiko Carstens <heiko.carstens@de.ibm.com>
......@@ -25,7 +26,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define ZFCP_CCW_C_REVISION "$Revision: 1.36 $"
#define ZFCP_CCW_C_REVISION "$Revision: 1.48 $"
#include <linux/init.h>
#include <linux/module.h>
......@@ -34,18 +35,22 @@
#include "zfcp_def.h"
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG
#define ZFCP_LOG_AREA_PREFIX ZFCP_LOG_AREA_PREFIX_CONFIG
static int zfcp_ccw_probe(struct ccw_device *);
static void zfcp_ccw_remove(struct ccw_device *);
static int zfcp_ccw_set_online(struct ccw_device *);
static int zfcp_ccw_set_offline(struct ccw_device *);
static int zfcp_ccw_notify(struct ccw_device *, int);
static struct ccw_device_id zfcp_ccw_device_id[] = {
{CCW_DEVICE_DEVTYPE(ZFCP_CONTROL_UNIT_TYPE,
ZFCP_CONTROL_UNIT_MODEL,
ZFCP_DEVICE_TYPE,
ZFCP_DEVICE_MODEL)},
{CCW_DEVICE_DEVTYPE(ZFCP_CONTROL_UNIT_TYPE,
ZFCP_CONTROL_UNIT_MODEL,
ZFCP_DEVICE_TYPE,
ZFCP_DEVICE_MODEL_PRIV)},
{},
};
......@@ -56,6 +61,7 @@ static struct ccw_driver zfcp_ccw_driver = {
.remove = zfcp_ccw_remove,
.set_online = zfcp_ccw_set_online,
.set_offline = zfcp_ccw_set_offline,
.notify = zfcp_ccw_notify,
};
MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id);
......@@ -80,6 +86,9 @@ zfcp_ccw_probe(struct ccw_device *ccw_device)
adapter = zfcp_adapter_enqueue(ccw_device);
if (!adapter)
retval = -EINVAL;
else
ZFCP_LOG_DEBUG("Probed adapter %s\n",
zfcp_get_busid_by_adapter(adapter));
up(&zfcp_data.config_sema);
return retval;
}
......@@ -104,6 +113,8 @@ zfcp_ccw_remove(struct ccw_device *ccw_device)
down(&zfcp_data.config_sema);
adapter = dev_get_drvdata(&ccw_device->dev);
ZFCP_LOG_DEBUG("Removing adapter %s\n",
zfcp_get_busid_by_adapter(adapter));
write_lock_irq(&zfcp_data.config_lock);
list_for_each_entry_safe(port, p, &adapter->port_list_head, list) {
list_for_each_entry_safe(unit, u, &port->unit_list_head, list) {
......@@ -152,13 +163,26 @@ zfcp_ccw_set_online(struct ccw_device *ccw_device)
down(&zfcp_data.config_sema);
adapter = dev_get_drvdata(&ccw_device->dev);
retval = zfcp_erp_thread_setup(adapter);
if (retval) {
ZFCP_LOG_INFO("error: out of resources. "
"error recovery thread for adapter %s "
"could not be started\n",
zfcp_get_busid_by_adapter(adapter));
goto out;
}
retval = zfcp_adapter_scsi_register(adapter);
if (retval)
goto out;
goto out_scsi_register;
zfcp_erp_modify_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING,
ZFCP_SET);
zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED);
zfcp_erp_wait(adapter);
goto out;
out_scsi_register:
zfcp_erp_thread_kill(adapter);
out:
up(&zfcp_data.config_sema);
return retval;
......@@ -183,10 +207,49 @@ zfcp_ccw_set_offline(struct ccw_device *ccw_device)
zfcp_erp_adapter_shutdown(adapter, 0);
zfcp_erp_wait(adapter);
zfcp_adapter_scsi_unregister(adapter);
zfcp_erp_thread_kill(adapter);
up(&zfcp_data.config_sema);
return 0;
}
/**
* zfcp_ccw_notify
* @ccw_device: pointer to belonging ccw device
* @event: indicates if adapter was detached or attached
*
* This function gets called by the common i/o layer if an adapter has gone
* or reappeared.
*/
static int
zfcp_ccw_notify(struct ccw_device *ccw_device, int event)
{
struct zfcp_adapter *adapter;
down(&zfcp_data.config_sema);
adapter = dev_get_drvdata(&ccw_device->dev);
switch (event) {
case CIO_GONE:
ZFCP_LOG_NORMAL("Adapter %s: device gone.\n",
zfcp_get_busid_by_adapter(adapter));
break;
case CIO_NO_PATH:
ZFCP_LOG_NORMAL("Adapter %s: no path.\n",
zfcp_get_busid_by_adapter(adapter));
break;
case CIO_OPER:
ZFCP_LOG_NORMAL("Adapter %s: operational again.\n",
zfcp_get_busid_by_adapter(adapter));
zfcp_erp_modify_adapter_status(adapter,
ZFCP_STATUS_COMMON_RUNNING,
ZFCP_SET);
zfcp_erp_adapter_reopen(adapter,
ZFCP_STATUS_COMMON_ERP_FAILED);
break;
}
up(&zfcp_data.config_sema);
return 1;
}
/**
* zfcp_ccw_register - ccw register function
*
......@@ -222,4 +285,3 @@ zfcp_ccw_unregister(void)
}
#undef ZFCP_LOG_AREA
#undef ZFCP_LOG_AREA_PREFIX
......@@ -4,11 +4,12 @@
*
* FCP adapter driver for IBM eServer zSeries
*
* Copyright 2002 IBM Corporation
* (C) Copyright IBM Corp. 2002, 2004
*
* Author(s): Martin Peschke <mpeschke@de.ibm.com>
* Raimund Schroeder <raimund.schroeder@de.ibm.com>
* Aron Zeh <arzeh@de.ibm.com>
* Wolfgang Taphorn <taphorn@de.ibm.com>
* Aron Zeh
* Wolfgang Taphorn
* Stefan Bader <stefan.bader@de.ibm.com>
* Heiko Carstens <heiko.carstens@de.ibm.com>
*
......@@ -32,19 +33,29 @@
#define ZFCP_DEF_H
/* this drivers version (do not edit !!! generated and updated by cvs) */
#define ZFCP_DEF_REVISION "$Revision: 1.48 $"
#define ZFCP_DEF_REVISION "$Revision: 1.62 $"
/*************************** INCLUDES *****************************************/
#include <linux/blkdev.h>
#include <scsi/scsi.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include "../../scsi/scsi.h"
#include "../../scsi/hosts.h"
#include "../../fc4/fc.h"
#include "zfcp_fsf.h" /* FSF SW Interface */
#include <asm/ccwdev.h>
#include <asm/qdio.h>
#include <asm/debug.h>
#include <asm/ebcdic.h>
#include <linux/reboot.h>
#include <linux/mempool.h>
#include <linux/ioctl.h>
#ifdef CONFIG_S390_SUPPORT
#include <linux/ioctl32.h>
#endif
/************************ DEBUG FLAGS *****************************************/
......@@ -56,6 +67,24 @@
#define ZFCP_STAT_REQSIZES
#define ZFCP_STAT_QUEUES
/********************* GENERAL DEFINES *********************************/
/* zfcp version number, it consists of major, minor, and patch-level number */
#define ZFCP_VERSION "4.0.0"
static inline void *
zfcp_sg_to_address(struct scatterlist *list)
{
return (void *) (page_address(list->page) + list->offset);
}
static inline void
zfcp_address_to_sg(void *address, struct scatterlist *list)
{
list->page = virt_to_page(address);
list->offset = ((unsigned long) address) & (PAGE_SIZE - 1);
}
/********************* SCSI SPECIFIC DEFINES *********************************/
/* 32 bit for SCSI ID and LUN as long as the SCSI stack uses this type */
......@@ -64,7 +93,6 @@ typedef u32 scsi_lun_t;
#define ZFCP_ERP_SCSI_LOW_MEM_TIMEOUT (100*HZ)
#define ZFCP_SCSI_ER_TIMEOUT (100*HZ)
#define ZFCP_SCSI_HOST_FLUSH_TIMEOUT (1*HZ)
/********************* CIO/QDIO SPECIFIC DEFINES *****************************/
......@@ -73,9 +101,12 @@ typedef u32 scsi_lun_t;
#define ZFCP_CONTROL_UNIT_MODEL 0x03
#define ZFCP_DEVICE_TYPE 0x1732
#define ZFCP_DEVICE_MODEL 0x03
#define ZFCP_DEVICE_MODEL_PRIV 0x04
/* allow as many chained SBALs as are supported by hardware */
#define ZFCP_MAX_SBALS_PER_REQ FSF_MAX_SBALS_PER_REQ
#define ZFCP_MAX_SBALS_PER_CT_REQ FSF_MAX_SBALS_PER_REQ
#define ZFCP_MAX_SBALS_PER_ELS_REQ FSF_MAX_SBALS_PER_ELS_REQ
/* DMQ bug workaround: don't use last SBALE */
#define ZFCP_MAX_SBALES_PER_SBAL (QDIO_MAX_ELEMENTS_PER_BUFFER - 1)
......@@ -115,9 +146,6 @@ typedef u32 scsi_lun_t;
#define ZFCP_EXCHANGE_CONFIG_DATA_RETRIES 6
#define ZFCP_EXCHANGE_CONFIG_DATA_SLEEP 50
#define ZFCP_QTCB_SIZE (sizeof(struct fsf_qtcb) + FSF_QTCB_LOG_SIZE)
#define ZFCP_QTCB_AND_REQ_SIZE (sizeof(struct zfcp_fsf_req) + ZFCP_QTCB_SIZE)
/*************** FIBRE CHANNEL PROTOCOL SPECIFIC DEFINES ********************/
typedef unsigned long long wwn_t;
......@@ -129,7 +157,8 @@ typedef unsigned int fcp_dl_t;
#define ZFCP_FC_SERVICE_CLASS_DEFAULT FSF_CLASS_3
/* timeout for name-server lookup (in seconds) */
#define ZFCP_NAMESERVER_TIMEOUT 10
#define ZFCP_NS_GID_PN_TIMEOUT 10
#define ZFCP_NS_GA_NXT_TIMEOUT 120
/* largest SCSI command we can process */
/* FCP-2 (FCP_CMND IU) allows up to (255-3+16) */
......@@ -241,33 +270,177 @@ struct fcp_logo {
wwn_t nport_wwpn;
} __attribute__((packed));
struct fc_ct_iu {
u8 revision; /* 0x01 */
u8 in_id[3]; /* 0x00 */
u8 gs_type; /* 0xFC Directory Service */
u8 gs_subtype; /* 0x02 Name Server */
u8 options; /* 0x10 synchronous/single exchange */
u8 reserved0;
u16 cmd_rsp_code; /* 0x0121 GID_PN */
u16 max_res_size; /* <= (4096 - 16) / 4 */
u8 reserved1;
/*
* FC-FS stuff
*/
#define R_A_TOV 10 /* seconds */
#define ZFCP_ELS_TIMEOUT (2 * R_A_TOV)
#define ZFCP_LS_RJT 0x01
#define ZFCP_LS_ACC 0x02
#define ZFCP_LS_RTV 0x0E
#define ZFCP_LS_RLS 0x0F
#define ZFCP_LS_PDISC 0x50
#define ZFCP_LS_ADISC 0x52
#define ZFCP_LS_RSCN 0x61
#define ZFCP_LS_RNID 0x78
#define ZFCP_LS_RLIR 0x7A
#define ZFCP_LS_RTV_E_D_TOV_FLAG 0x04000000
/* LS_ACC Reason Codes */
#define ZFCP_LS_RJT_INVALID_COMMAND_CODE 0x01
#define ZFCP_LS_RJT_LOGICAL_ERROR 0x03
#define ZFCP_LS_RJT_LOGICAL_BUSY 0x05
#define ZFCP_LS_RJT_PROTOCOL_ERROR 0x07
#define ZFCP_LS_RJT_UNABLE_TO_PERFORM 0x09
#define ZFCP_LS_RJT_COMMAND_NOT_SUPPORTED 0x0B
#define ZFCP_LS_RJT_VENDOR_UNIQUE_ERROR 0xFF
struct zfcp_ls_rjt {
u8 code;
u8 field[3];
u8 reserved;
u8 reason_code;
u8 reason_code_expl;
u8 reason_expl;
u8 vendor_unique;
union {
} __attribute__ ((packed));
struct zfcp_ls_rtv {
u8 code;
u8 field[3];
} __attribute__ ((packed));
struct zfcp_ls_rtv_acc {
u8 code;
u8 field[3];
u32 r_a_tov;
u32 e_d_tov;
u32 qualifier;
} __attribute__ ((packed));
struct zfcp_ls_rls {
u8 code;
u8 field[3];
fc_id_t port_id;
} __attribute__ ((packed));
struct zfcp_ls_rls_acc {
u8 code;
u8 field[3];
u32 link_failure_count;
u32 loss_of_sync_count;
u32 loss_of_signal_count;
u32 prim_seq_prot_error;
u32 invalid_transmition_word;
u32 invalid_crc_count;
} __attribute__ ((packed));
struct zfcp_ls_pdisc {
u8 code;
u8 field[3];
u8 common_svc_parm[16];
wwn_t wwpn;
fc_id_t d_id;
} data;
wwn_t wwnn;
struct {
u8 class1[16];
u8 class2[16];
u8 class3[16];
} svc_parm;
u8 reserved[16];
u8 vendor_version[16];
} __attribute__ ((packed));
struct zfcp_ls_pdisc_acc {
u8 code;
u8 field[3];
u8 common_svc_parm[16];
wwn_t wwpn;
wwn_t wwnn;
struct {
u8 class1[16];
u8 class2[16];
u8 class3[16];
} svc_parm;
u8 reserved[16];
u8 vendor_version[16];
} __attribute__ ((packed));
struct zfcp_ls_adisc {
u8 code;
u8 field[3];
fc_id_t hard_nport_id;
wwn_t wwpn;
wwn_t wwnn;
fc_id_t nport_id;
} __attribute__ ((packed));
struct zfcp_ls_adisc_acc {
u8 code;
u8 field[3];
fc_id_t hard_nport_id;
wwn_t wwpn;
wwn_t wwnn;
fc_id_t nport_id;
} __attribute__ ((packed));
struct zfcp_ls_rnid {
u8 code;
u8 field[3];
u8 node_id_format;
u8 reserved[3];
} __attribute__((packed));
/* common identification data */
struct zfcp_ls_rnid_common_id {
u64 n_port_name;
u64 node_name;
} __attribute__((packed));
/* general topology specific identification data */
struct zfcp_ls_rnid_general_topology_id {
u8 vendor_unique[16];
u32 associated_type;
u32 physical_port_number;
u32 nr_attached_nodes;
u8 node_management;
u8 ip_version;
u16 port_number;
u8 ip_address[16];
u8 reserved[2];
u16 vendor_specific;
} __attribute__((packed));
struct zfcp_ls_rnid_acc {
u8 code;
u8 field[3];
u8 node_id_format;
u8 common_id_length;
u8 reserved;
u8 specific_id_length;
struct zfcp_ls_rnid_common_id
common_id;
struct zfcp_ls_rnid_general_topology_id
specific_id;
} __attribute__((packed));
/*
* FC-GS-2 stuff
*/
#define ZFCP_CT_REVISION 0x01
#define ZFCP_CT_DIRECTORY_SERVICE 0xFC
#define ZFCP_CT_NAME_SERVER 0x02
#define ZFCP_CT_SYNCHRONOUS 0x00
#define ZFCP_CT_GID_PN 0x0121
#define ZFCP_CT_GA_NXT 0x0100
#define ZFCP_CT_MAX_SIZE 0x1020
#define ZFCP_CT_ACCEPT 0x8002
/*
* FC-GS-4 stuff
*/
#define ZFCP_CT_TIMEOUT (3 * R_A_TOV)
/***************** S390 DEBUG FEATURE SPECIFIC DEFINES ***********************/
/* debug feature entries per adapter */
......@@ -333,16 +506,6 @@ struct fc_ct_iu {
#define ZFCP_LOG_LEVEL_DEBUG 2
#define ZFCP_LOG_LEVEL_TRACE 3
/* default log levels for different log areas */
#define ZFCP_LOG_LEVEL_DEFAULT_OTHER ZFCP_LOG_LEVEL_INFO
#define ZFCP_LOG_LEVEL_DEFAULT_SCSI ZFCP_LOG_LEVEL_INFO
#define ZFCP_LOG_LEVEL_DEFAULT_FSF ZFCP_LOG_LEVEL_INFO
#define ZFCP_LOG_LEVEL_DEFAULT_CONFIG ZFCP_LOG_LEVEL_INFO
#define ZFCP_LOG_LEVEL_DEFAULT_CIO ZFCP_LOG_LEVEL_INFO
#define ZFCP_LOG_LEVEL_DEFAULT_QDIO ZFCP_LOG_LEVEL_INFO
#define ZFCP_LOG_LEVEL_DEFAULT_ERP ZFCP_LOG_LEVEL_INFO
#define ZFCP_LOG_LEVEL_DEFAULT_FC ZFCP_LOG_LEVEL_INFO
/*
* this allows removal of logging code by the preprocessor
* (the most detailed log level still to be compiled in is specified,
......@@ -350,93 +513,75 @@ struct fc_ct_iu {
*/
#define ZFCP_LOG_LEVEL_LIMIT ZFCP_LOG_LEVEL_TRACE
/* positional "loglevel" nibble assignment */
#define ZFCP_LOG_VALUE(zfcp_lognibble) \
/* get "loglevel" nibble assignment */
#define ZFCP_GET_LOG_VALUE(zfcp_lognibble) \
((atomic_read(&zfcp_data.loglevel) >> (zfcp_lognibble<<2)) & 0xF)
#define ZFCP_LOG_VALUE_OTHER ZFCP_LOG_VALUE(ZFCP_LOG_AREA_OTHER)
#define ZFCP_LOG_VALUE_SCSI ZFCP_LOG_VALUE(ZFCP_LOG_AREA_SCSI)
#define ZFCP_LOG_VALUE_FSF ZFCP_LOG_VALUE(ZFCP_LOG_AREA_FSF)
#define ZFCP_LOG_VALUE_CONFIG ZFCP_LOG_VALUE(ZFCP_LOG_AREA_CONFIG)
#define ZFCP_LOG_VALUE_CIO ZFCP_LOG_VALUE(ZFCP_LOG_AREA_CIO)
#define ZFCP_LOG_VALUE_QDIO ZFCP_LOG_VALUE(ZFCP_LOG_AREA_QDIO)
#define ZFCP_LOG_VALUE_ERP ZFCP_LOG_VALUE(ZFCP_LOG_AREA_ERP)
#define ZFCP_LOG_VALUE_FC ZFCP_LOG_VALUE(ZFCP_LOG_AREA_FC)
/* set "loglevel" nibble */
#define ZFCP_SET_LOG_NIBBLE(value, zfcp_lognibble) \
(value << (zfcp_lognibble << 2))
/* all log-level defaults are combined to generate initial log-level */
#define ZFCP_LOG_LEVEL_DEFAULTS \
((ZFCP_LOG_LEVEL_DEFAULT_OTHER << (ZFCP_LOG_AREA_OTHER<<2)) | \
(ZFCP_LOG_LEVEL_DEFAULT_SCSI << (ZFCP_LOG_AREA_SCSI<<2)) | \
(ZFCP_LOG_LEVEL_DEFAULT_FSF << (ZFCP_LOG_AREA_FSF<<2)) | \
(ZFCP_LOG_LEVEL_DEFAULT_CONFIG << (ZFCP_LOG_AREA_CONFIG<<2)) | \
(ZFCP_LOG_LEVEL_DEFAULT_CIO << (ZFCP_LOG_AREA_CIO<<2)) | \
(ZFCP_LOG_LEVEL_DEFAULT_QDIO << (ZFCP_LOG_AREA_QDIO<<2)) | \
(ZFCP_LOG_LEVEL_DEFAULT_ERP << (ZFCP_LOG_AREA_ERP<<2)) | \
(ZFCP_LOG_LEVEL_DEFAULT_FC << (ZFCP_LOG_AREA_FC<<2)))
/* the prefix placed at the beginning of each driver message */
#define ZFCP_LOG_PREFIX ZFCP_NAME": "
/* log area specific prefixes */
#define ZFCP_LOG_AREA_PREFIX_OTHER ""
#define ZFCP_LOG_AREA_PREFIX_SCSI "SCSI: "
#define ZFCP_LOG_AREA_PREFIX_FSF "FSF: "
#define ZFCP_LOG_AREA_PREFIX_CONFIG "config: "
#define ZFCP_LOG_AREA_PREFIX_CIO "common I/O: "
#define ZFCP_LOG_AREA_PREFIX_QDIO "QDIO: "
#define ZFCP_LOG_AREA_PREFIX_ERP "ERP: "
#define ZFCP_LOG_AREA_PREFIX_FC "FC: "
(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))
/* check whether we have the right level for logging */
#define ZFCP_LOG_CHECK(ll) (ZFCP_LOG_VALUE(ZFCP_LOG_AREA)) >= ll
#define ZFCP_LOG_CHECK(level) \
((ZFCP_GET_LOG_VALUE(ZFCP_LOG_AREA)) >= level)
/* As we have two printks it is possible for them to be seperated by another
* message. This holds true even for printks from within this module.
* In any case there should only be a small readability hit, however.
*/
#define _ZFCP_LOG(m...) \
{ \
printk( "%s%s: ", \
ZFCP_LOG_PREFIX ZFCP_LOG_AREA_PREFIX, \
__FUNCTION__); \
printk(m); \
}
/* logging routine for zfcp */
#define _ZFCP_LOG(fmt, args...) \
printk(KERN_ERR ZFCP_NAME": %s(%d): " fmt, __FUNCTION__, \
__LINE__ , ##args);
#define ZFCP_LOG(ll, m...) \
if (ZFCP_LOG_CHECK(ll)) \
_ZFCP_LOG(m)
#define ZFCP_LOG(level, fmt, args...) \
if (ZFCP_LOG_CHECK(level)) \
_ZFCP_LOG(fmt , ##args)
#if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_NORMAL
#define ZFCP_LOG_NORMAL(m...)
#else /* ZFCP_LOG_LEVEL_LIMIT >= ZFCP_LOG_LEVEL_NORMAL */
#define ZFCP_LOG_NORMAL(m...) ZFCP_LOG(ZFCP_LOG_LEVEL_NORMAL, m)
# define ZFCP_LOG_NORMAL(fmt, args...)
#else
# define ZFCP_LOG_NORMAL(fmt, args...) \
if (ZFCP_LOG_CHECK(ZFCP_LOG_LEVEL_NORMAL)) \
printk(KERN_ERR ZFCP_NAME": " fmt , ##args);
#endif
#if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_INFO
#define ZFCP_LOG_INFO(m...)
#else /* ZFCP_LOG_LEVEL_LIMIT >= ZFCP_LOG_LEVEL_INFO */
#define ZFCP_LOG_INFO(m...) ZFCP_LOG(ZFCP_LOG_LEVEL_INFO, m)
# define ZFCP_LOG_INFO(fmt, args...)
#else
# define ZFCP_LOG_INFO(fmt, args...) \
if (ZFCP_LOG_CHECK(ZFCP_LOG_LEVEL_INFO)) \
printk(KERN_ERR ZFCP_NAME": " fmt , ##args);
#endif
#if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_DEBUG
#define ZFCP_LOG_DEBUG(m...)
#else /* ZFCP_LOG_LEVEL_LIMIT >= ZFCP_LOG_LEVEL_DEBUG */
#define ZFCP_LOG_DEBUG(m...) ZFCP_LOG(ZFCP_LOG_LEVEL_DEBUG, m)
# define ZFCP_LOG_DEBUG(fmt, args...)
#else
# define ZFCP_LOG_DEBUG(fmt, args...) \
ZFCP_LOG(ZFCP_LOG_LEVEL_DEBUG, fmt , ##args)
#endif
#if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_TRACE
#define ZFCP_LOG_TRACE(m...)
#else /* ZFCP_LOG_LEVEL_LIMIT >= ZFCP_LOG_LEVEL_TRACE */
#define ZFCP_LOG_TRACE(m...) ZFCP_LOG(ZFCP_LOG_LEVEL_TRACE, m)
# define ZFCP_LOG_TRACE(fmt, args...)
#else
# define ZFCP_LOG_TRACE(fmt, args...) \
ZFCP_LOG(ZFCP_LOG_LEVEL_TRACE, fmt , ##args)
#endif
#ifdef ZFCP_PRINT_FLAGS
extern u32 flags_dump;
#define ZFCP_LOG_FLAGS(ll, m...) \
if (ll<=flags_dump) \
_ZFCP_LOG(m)
#ifndef ZFCP_PRINT_FLAGS
# define ZFCP_LOG_FLAGS(level, fmt, args...)
#else
#define ZFCP_LOG_FLAGS(ll, m...)
extern u32 flags_dump;
# define ZFCP_LOG_FLAGS(level, fmt, args...) \
if (level <= flags_dump) \
_ZFCP_LOG(fmt , ##args)
#endif
/*************** ADAPTER/PORT/UNIT AND FSF_REQ STATUS FLAGS ******************/
......@@ -506,19 +651,19 @@ extern u32 flags_dump;
#define ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP 0x00000400
#define ZFCP_STATUS_FSFREQ_RETRY 0x00000800
#define ZFCP_STATUS_FSFREQ_DISMISSED 0x00001000
#define ZFCP_STATUS_FSFREQ_POOLBUF 0x00002000
/*********************** ERROR RECOVERY PROCEDURE DEFINES ********************/
#define ZFCP_MAX_ERPS 3
#define ZFCP_ERP_FSFREQ_TIMEOUT (100 * HZ)
#define ZFCP_ERP_FSFREQ_TIMEOUT (30 * HZ)
#define ZFCP_ERP_MEMWAIT_TIMEOUT HZ
#define ZFCP_STATUS_ERP_TIMEDOUT 0x10000000
#define ZFCP_STATUS_ERP_CLOSE_ONLY 0x01000000
#define ZFCP_STATUS_ERP_DISMISSING 0x00100000
#define ZFCP_STATUS_ERP_DISMISSED 0x00200000
#define ZFCP_STATUS_ERP_LOWMEM 0x00400000
#define ZFCP_ERP_STEP_UNINITIALIZED 0x00000000
#define ZFCP_ERP_STEP_FSF_XCONFIG 0x00000001
......@@ -546,19 +691,55 @@ extern u32 flags_dump;
#define ZFCP_ERP_DISMISSED 0x4
#define ZFCP_ERP_NOMEM 0x5
/************************* STRUCTURE DEFINITIONS *****************************/
/******************** CFDC SPECIFIC STUFF *****************************/
/* Firewall data channel sense data record */
struct zfcp_cfdc_sense_data {
u32 signature; /* Request signature */
u32 devno; /* FCP adapter device number */
u32 command; /* Command code */
u32 fsf_status; /* FSF request status and status qualifier */
u8 fsf_status_qual[FSF_STATUS_QUALIFIER_SIZE];
u8 payloads[256]; /* Access conflicts list */
u8 control_file[0]; /* Access control table */
};
#define ZFCP_CFDC_SIGNATURE 0xCFDCACDF
#define ZFCP_CFDC_CMND_DOWNLOAD_NORMAL 0x00010001
#define ZFCP_CFDC_CMND_DOWNLOAD_FORCE 0x00010101
#define ZFCP_CFDC_CMND_FULL_ACCESS 0x00000201
#define ZFCP_CFDC_CMND_RESTRICTED_ACCESS 0x00000401
#define ZFCP_CFDC_CMND_UPLOAD 0x00010002
#define ZFCP_CFDC_DOWNLOAD 0x00000001
#define ZFCP_CFDC_UPLOAD 0x00000002
#define ZFCP_CFDC_WITH_CONTROL_FILE 0x00010000
#define ZFCP_CFDC_DEV_NAME "zfcp_cfdc"
#define ZFCP_CFDC_DEV_MAJOR MISC_MAJOR
#define ZFCP_CFDC_DEV_MINOR MISC_DYNAMIC_MINOR
#define ZFCP_CFDC_MAX_CONTROL_FILE_SIZE 127 * 1024
static const char zfcp_act_subtable_type[5][8] = {
{"unknown"}, {"OS"}, {"WWPN"}, {"DID"}, {"LUN"}
};
/************************* STRUCTURE DEFINITIONS *****************************/
struct zfcp_fsf_req;
typedef void zfcp_send_generic_handler_t(struct zfcp_fsf_req*);
/* holds various memory pools of an adapter */
struct zfcp_adapter_mempool {
mempool_t *status_read_fsf;
mempool_t *status_read_buf;
mempool_t *nameserver;
mempool_t *erp_fsf;
mempool_t *fcp_command_fsf;
struct timer_list fcp_command_fsf_timer;
mempool_t *fsf_req_erp;
mempool_t *fsf_req_scsi;
mempool_t *fsf_req_abort;
mempool_t *fsf_req_status_read;
mempool_t *data_status_read;
mempool_t *data_gid_pn;
};
struct zfcp_exchange_config_data{
......@@ -587,7 +768,7 @@ struct zfcp_close_physical_port {
struct zfcp_send_fcp_command_task {
struct zfcp_fsf_req *fsf_req;
struct zfcp_unit *unit;
Scsi_Cmnd *scsi_cmnd;
struct scsi_cmnd *scsi_cmnd;
unsigned long start_jiffies;
};
......@@ -600,20 +781,119 @@ struct zfcp_abort_fcp_command {
struct zfcp_unit *unit;
};
struct zfcp_send_generic {
/*
* header for CT_IU
*/
struct ct_hdr {
u8 revision; // 0x01
u8 in_id[3]; // 0x00
u8 gs_type; // 0xFC Directory Service
u8 gs_subtype; // 0x02 Name Server
u8 options; // 0x00 single bidirectional exchange
u8 reserved0;
u16 cmd_rsp_code; // 0x0121 GID_PN, or 0x0100 GA_NXT
u16 max_res_size; // <= (4096 - 16) / 4
u8 reserved1;
u8 reason_code;
u8 reason_code_expl;
u8 vendor_unique;
} __attribute__ ((packed));
/* nameserver request CT_IU -- for requests where
* a port name is required */
struct ct_iu_gid_pn_req {
struct ct_hdr header;
wwn_t wwpn;
} __attribute__ ((packed));
/* nameserver request CT_IU -- for requests where
* a port identifier is required */
struct ct_iu_ga_nxt_req {
struct ct_hdr header;
fc_id_t d_id;
} __attribute__ ((packed));
/* 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;
} __attribute__ ((packed));
/* FS_ACC IU and data unit for GA_NXT nameserver request */
struct ct_iu_ga_nxt_resp {
struct ct_hdr header;
u8 port_type;
u8 port_id[3];
u64 port_wwn;
u8 port_symbolic_name_length;
u8 port_symbolic_name[255];
u64 node_wwn;
u8 node_symbolic_name_length;
u8 node_symbolic_name[255];
u64 initial_process_associator;
u8 node_ip[16];
u32 cos;
u8 fc4_types[32];
u8 port_ip[16];
u64 fabric_wwn;
u8 reserved;
u8 hard_address[3];
} __attribute__ ((packed));
typedef void (*zfcp_send_ct_handler_t)(unsigned long);
/* used to pass parameters to zfcp_send_ct() */
struct zfcp_send_ct {
struct zfcp_port *port;
struct scatterlist *req;
struct scatterlist *resp;
unsigned int req_count;
unsigned int resp_count;
zfcp_send_ct_handler_t handler;
unsigned long handler_data;
mempool_t *pool; /* mempool for ct not for fsf_req */
int timeout;
struct timer_list *timer;
struct completion *completion;
int status;
};
/* used for name server requests in error recovery */
struct zfcp_gid_pn_data {
struct zfcp_send_ct ct;
struct scatterlist req;
struct scatterlist resp;
struct ct_iu_gid_pn_req ct_iu_req;
struct ct_iu_gid_pn_resp ct_iu_resp;
struct zfcp_port *port;
char *outbuf;
char *inbuf;
int outbuf_length;
int inbuf_length;
zfcp_send_generic_handler_t *handler;
};
typedef int (*zfcp_send_els_handler_t)(unsigned long);
/* used to pass parameters to zfcp_send_els() */
/* ToDo merge send_ct() and send_els() and corresponding structs */
struct zfcp_send_els {
struct zfcp_port *port;
struct scatterlist *req;
struct scatterlist *resp;
unsigned int req_count;
unsigned int resp_count;
zfcp_send_els_handler_t handler;
unsigned long handler_data;
struct completion *completion;
int ls_code;
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;
......@@ -626,7 +906,8 @@ union zfcp_req_data {
struct zfcp_send_fcp_command_task_management
send_fcp_command_task_management;
struct zfcp_abort_fcp_command abort_fcp_command;
struct zfcp_send_generic send_generic;
struct zfcp_send_ct *send_ct;
struct zfcp_send_els *send_els;
struct zfcp_status_read status_read;
};
......@@ -671,6 +952,9 @@ struct zfcp_adapter {
u32 fc_link_speed; /* FC interface speed */
u32 hydra_version; /* Hydra version */
u32 fsf_lic_version;
u32 supported_features;/* of FCP channel */
u32 hardware_version; /* of FCP channel */
u8 serial_number[32]; /* of hardware */
struct Scsi_Host *scsi_host; /* Pointer to mid-layer */
unsigned char name[9];
......@@ -704,6 +988,10 @@ struct zfcp_adapter {
wait_queue_head_t erp_done_wqh;
struct zfcp_erp_action erp_action; /* pending error recovery */
atomic_t erp_counter;
u32 erp_total_count; /* total nr of enqueued erp
actions */
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;
......@@ -751,7 +1039,7 @@ struct zfcp_unit {
scsi_lun_t scsi_lun; /* own SCSI LUN */
fcp_lun_t fcp_lun; /* own FCP_LUN */
u32 handle; /* handle assigned by FSF */
Scsi_Device *device; /* scsi device struct pointer */
struct scsi_device *device; /* scsi device struct pointer */
struct zfcp_erp_action erp_action; /* pending error recovery */
atomic_t erp_counter;
struct device sysfs_device; /* sysfs device */
......@@ -765,8 +1053,14 @@ struct zfcp_fsf_req {
u32 specific_magic; /* structure specific magic */
struct list_head list; /* list of FSF requests */
struct zfcp_adapter *adapter; /* adapter request belongs to */
u8 sbal_count; /* # of SBALs in FSF request */
u8 sbal_index; /* position of 1st SBAL */
u8 sbal_number; /* nr of SBALs free for use */
u8 sbal_first; /* first SBAL for this request */
u8 sbal_last; /* last possible SBAL for
this reuest */
u8 sbal_curr; /* current SBAL during creation
of request */
u8 sbale_curr; /* current SBALE during creation
of request */
wait_queue_head_t completion_wq; /* can be used by a routine
to wait for completion */
volatile u32 status; /* status of this request */
......@@ -776,13 +1070,15 @@ struct zfcp_fsf_req {
union zfcp_req_data data; /* Info fields 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 */
};
typedef void zfcp_fsf_req_handler_t(struct zfcp_fsf_req*);
/* driver data */
struct zfcp_data {
Scsi_Host_Template scsi_host_template;
struct scsi_host_template scsi_host_template;
atomic_t status; /* Module status flags */
struct list_head adapter_list_head; /* head of adapter list */
struct list_head adapter_remove_lh; /* head of adapters to be
......@@ -792,7 +1088,7 @@ struct zfcp_data {
struct list_head status_read_send_head;
struct semaphore status_read_sema;
wait_queue_head_t status_read_thread_wqh;
u16 adapters; /* # of adapters in list */
u32 adapters; /* # of adapters in list */
rwlock_t config_lock; /* serialises changes
to adapter/port/unit
lists */
......@@ -829,6 +1125,24 @@ struct zfcp_statistics {
};
#endif
struct zfcp_sg_list {
struct scatterlist *sg;
unsigned int count;
};
/* number of elements for various memory pools */
#define ZFCP_POOL_FSF_REQ_ERP_NR 1
#define ZFCP_POOL_FSF_REQ_SCSI_NR 1
#define ZFCP_POOL_FSF_REQ_ABORT_NR 1
#define ZFCP_POOL_STATUS_READ_NR ZFCP_STATUS_READS_RECOM
#define ZFCP_POOL_DATA_GID_PN_NR 1
/* struct used by memory pools for fsf_requests */
struct zfcp_fsf_req_pool_element {
struct zfcp_fsf_req fsf_req;
struct fsf_qtcb qtcb;
};
/********************** ZFCP SPECIFIC DEFINES ********************************/
#define ZFCP_FSFREQ_CLEANUP_TIMEOUT HZ/10
......@@ -836,6 +1150,7 @@ struct zfcp_statistics {
#define ZFCP_KNOWN 0x00000001
#define ZFCP_REQ_AUTO_CLEANUP 0x00000002
#define ZFCP_WAIT_FOR_SBAL 0x00000004
#define ZFCP_REQ_NO_QTCB 0x00000008
#define ZFCP_SET 0x00000100
#define ZFCP_CLEAR 0x00000200
......
......@@ -4,11 +4,12 @@
*
* FCP adapter driver for IBM eServer zSeries
*
* Copyright 2002 IBM Corporation
* (C) Copyright IBM Corp. 2002, 2004
*
* Author(s): Martin Peschke <mpeschke@de.ibm.com>
* Raimund Schroeder <raimund.schroeder@de.ibm.com>
* Aron Zeh <arzeh@de.ibm.com>
* Wolfgang Taphorn <taphorn@de.ibm.com>
* Aron Zeh
* Wolfgang Taphorn
* Stefan Bader <stefan.bader@de.ibm.com>
* Heiko Carstens <heiko.carstens@de.ibm.com>
*
......@@ -28,12 +29,15 @@
*/
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_ERP
#define ZFCP_LOG_AREA_PREFIX ZFCP_LOG_AREA_PREFIX_ERP
/* this drivers version (do not edit !!! generated and updated by cvs) */
#define ZFCP_ERP_REVISION "$Revision: 1.39 $"
#define ZFCP_ERP_REVISION "$Revision: 1.44 $"
#include "zfcp_ext.h"
static int zfcp_els(struct zfcp_port *, u8);
static int zfcp_els_handler(unsigned long);
static int zfcp_erp_adapter_reopen_internal(struct zfcp_adapter *, int);
static int zfcp_erp_port_forced_reopen_internal(struct zfcp_port *, int);
static int zfcp_erp_port_reopen_internal(struct zfcp_port *, int);
......@@ -326,6 +330,375 @@ zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear_mask)
return retval;
}
/*
* function: zfcp_els
*
* purpose: Originator of the ELS commands
*
* returns: 0 - Operation completed successfuly
* -EINVAL - Unknown IOCTL command or invalid sense data record
* -ENOMEM - Insufficient memory
* -EPERM - Cannot create or queue FSF request
*/
int
zfcp_els(struct zfcp_port *port, u8 ls_code)
{
struct zfcp_send_els *send_els;
struct zfcp_ls_rls *rls;
struct zfcp_ls_pdisc *pdisc;
struct zfcp_ls_adisc *adisc;
struct page *page = NULL;
void *req;
int retval = 0;
send_els = kmalloc(sizeof(struct zfcp_send_els), GFP_ATOMIC);
if (send_els == NULL)
goto nomem;
send_els->req = kmalloc(sizeof(struct scatterlist), GFP_ATOMIC);
if (send_els->req == NULL)
goto nomem;
send_els->req_count = 1;
send_els->resp = kmalloc(sizeof(struct scatterlist), GFP_ATOMIC);
if (send_els->resp == NULL)
goto nomem;
send_els->resp_count = 1;
page = alloc_pages(GFP_ATOMIC, 0);
if (page == NULL)
goto nomem;
send_els->req->page = page;
send_els->resp->page = page;
send_els->req->offset = 0;
send_els->resp->offset = PAGE_SIZE >> 1;
send_els->port = port;
send_els->ls_code = ls_code;
send_els->handler = zfcp_els_handler;
send_els->handler_data = (unsigned long)send_els;
send_els->completion = NULL;
req = zfcp_sg_to_address(send_els->req);
*(u32*)req = 0;
*(u8*)req = ls_code;
switch (ls_code) {
case ZFCP_LS_RTV:
send_els->req->length = sizeof(struct zfcp_ls_rtv);
send_els->resp->length = sizeof(struct zfcp_ls_rtv_acc);
ZFCP_LOG_NORMAL(
"RTV request from sid 0x%06x to did 0x%06x\n",
port->adapter->s_id, port->d_id);
break;
case ZFCP_LS_RLS:
send_els->req->length = sizeof(struct zfcp_ls_rls);
send_els->resp->length = sizeof(struct zfcp_ls_rls_acc);
rls = (struct zfcp_ls_rls*)req;
rls->port_id = port->adapter->s_id;
ZFCP_LOG_NORMAL(
"RLS request from sid 0x%06x to did 0x%06x "
"with payload(port_id=0x%06x)\n",
port->adapter->s_id, port->d_id, rls->port_id);
break;
case ZFCP_LS_PDISC:
send_els->req->length = sizeof(struct zfcp_ls_pdisc);
send_els->resp->length = sizeof(struct zfcp_ls_pdisc_acc);
pdisc = (struct zfcp_ls_pdisc*)req;
pdisc->wwpn = port->adapter->wwpn;
pdisc->wwnn = port->adapter->wwnn;
ZFCP_LOG_NORMAL(
"PDISC request from sid 0x%06x to did 0x%06x "
"with payload(wwpn=0x%016Lx wwnn=0x%016Lx)\n",
port->adapter->s_id, port->d_id,
pdisc->wwpn, pdisc->wwnn);
break;
case ZFCP_LS_ADISC:
send_els->req->length = sizeof(struct zfcp_ls_adisc);
send_els->resp->length = sizeof(struct zfcp_ls_adisc_acc);
adisc = (struct zfcp_ls_adisc*)req;
adisc->hard_nport_id = port->adapter->s_id;
adisc->wwpn = port->adapter->wwpn;
adisc->wwnn = port->adapter->wwnn;
adisc->nport_id = port->adapter->s_id;
ZFCP_LOG_NORMAL(
"ADISC request from sid 0x%06x to did 0x%06x "
"with payload(wwpn=0x%016Lx wwnn=0x%016Lx "
"hard_nport_id=0x%06x nport_id=0x%06x)\n",
port->adapter->s_id, port->d_id,
adisc->wwpn, adisc->wwnn,
adisc->hard_nport_id, adisc->nport_id);
break;
default:
ZFCP_LOG_NORMAL(
"ELS command code 0x%02x is not supported\n", ls_code);
retval = -EINVAL;
goto invalid_ls_code;
}
retval = zfcp_fsf_send_els(send_els);
if (retval != 0) {
ZFCP_LOG_NORMAL(
"ELS request could not be processed "
"(sid=0x%06x did=0x%06x)\n",
port->adapter->s_id, port->d_id);
retval = -EPERM;
}
goto out;
nomem:
ZFCP_LOG_INFO("Out of memory!\n");
retval = -ENOMEM;
invalid_ls_code:
if (page != NULL)
__free_pages(page, 0);
if (send_els != NULL) {
if (send_els->req != NULL)
kfree(send_els->req);
if (send_els->resp != NULL)
kfree(send_els->resp);
kfree(send_els);
}
out:
return retval;
}
/*
* function: zfcp_els_handler
*
* purpose: Handler for all kind of ELSs
*
* returns: 0 - Operation completed successfuly
* -ENXIO - ELS has been rejected
* -EPERM - Port forced reopen failed
*/
int
zfcp_els_handler(unsigned long data)
{
struct zfcp_send_els *send_els = (struct zfcp_send_els*)data;
struct zfcp_port *port = send_els->port;
struct zfcp_ls_rjt *rjt;
struct zfcp_ls_rtv_acc *rtv;
struct zfcp_ls_rls_acc *rls;
struct zfcp_ls_pdisc_acc *pdisc;
struct zfcp_ls_adisc_acc *adisc;
void *req, *resp;
u8 req_code, resp_code;
int retval = 0;
if (send_els->status != 0)
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);
req_code = *(u8*)req;
resp_code = *(u8*)resp;
switch (resp_code) {
case ZFCP_LS_RJT:
rjt = (struct zfcp_ls_rjt*)resp;
switch (rjt->reason_code) {
case ZFCP_LS_RJT_INVALID_COMMAND_CODE:
ZFCP_LOG_NORMAL(
"Invalid command code "
"(wwpn=0x%016Lx command=0x%02x)\n",
(unsigned long long)port->wwpn,
req_code);
break;
case ZFCP_LS_RJT_LOGICAL_ERROR:
ZFCP_LOG_NORMAL(
"Logical error "
"(wwpn=0x%016Lx reason_explanation=0x%02x)\n",
(unsigned long long)port->wwpn,
rjt->reason_expl);
break;
case ZFCP_LS_RJT_LOGICAL_BUSY:
ZFCP_LOG_NORMAL(
"Logical busy "
"(wwpn=0x%016Lx reason_explanation=0x%02x)\n",
(unsigned long long)port->wwpn,
rjt->reason_expl);
break;
case ZFCP_LS_RJT_PROTOCOL_ERROR:
ZFCP_LOG_NORMAL(
"Protocol error "
"(wwpn=0x%016Lx reason_explanation=0x%02x)\n",
(unsigned long long)port->wwpn,
rjt->reason_expl);
break;
case ZFCP_LS_RJT_UNABLE_TO_PERFORM:
ZFCP_LOG_NORMAL(
"Unable to perform command requested "
"(wwpn=0x%016Lx reason_explanation=0x%02x)\n",
(unsigned long long)port->wwpn,
rjt->reason_expl);
break;
case ZFCP_LS_RJT_COMMAND_NOT_SUPPORTED:
ZFCP_LOG_NORMAL(
"Command not supported "
"(wwpn=0x%016Lx command=0x%02x)\n",
(unsigned long long)port->wwpn,
req_code);
break;
case ZFCP_LS_RJT_VENDOR_UNIQUE_ERROR:
ZFCP_LOG_NORMAL(
"Vendor unique error "
"(wwpn=0x%016Lx vendor_unique=0x%02x)\n",
(unsigned long long)port->wwpn,
rjt->vendor_unique);
break;
default:
ZFCP_LOG_NORMAL(
"ELS has been rejected by remote port "
"with WWPN 0x%Lx on the adapter %s "
"with the reason code 0x%02x\n",
port->wwpn, zfcp_get_busid_by_port(port),
rjt->reason_code);
}
retval = -ENXIO;
break;
case ZFCP_LS_ACC:
switch (req_code) {
case ZFCP_LS_RTV:
rtv = (struct zfcp_ls_rtv_acc*)resp;
ZFCP_LOG_NORMAL(
"RTV response from did 0x%06x to sid 0x%06x "
"with payload(R_A_TOV=%ds E_D_TOV=%d%cs)\n",
port->d_id, port->adapter->s_id,
rtv->r_a_tov, rtv->e_d_tov,
rtv->qualifier & ZFCP_LS_RTV_E_D_TOV_FLAG ?
'n' : 'm');
break;
case ZFCP_LS_RLS:
rls = (struct zfcp_ls_rls_acc*)resp;
ZFCP_LOG_NORMAL(
"RLS response from did 0x%06x to sid 0x%06x "
"with payload(link_failure_count=%u "
"loss_of_sync_count=%u "
"loss_of_signal_count=%u "
"primitive_sequence_protocol_error=%u "
"invalid_transmition_word=%u "
"invalid_crc_count=%u)\n",
port->d_id, port->adapter->s_id,
rls->link_failure_count,
rls->loss_of_sync_count,
rls->loss_of_signal_count,
rls->prim_seq_prot_error,
rls->invalid_transmition_word,
rls->invalid_crc_count);
break;
case ZFCP_LS_PDISC:
pdisc = (struct zfcp_ls_pdisc_acc*)resp;
ZFCP_LOG_NORMAL(
"PDISC response from did 0x%06x to sid 0x%06x "
"with payload(wwpn=0x%016Lx wwnn=0x%016Lx "
"vendor='%-16s')\n",
port->d_id, port->adapter->s_id,
(unsigned long long)pdisc->wwpn,
(unsigned long long)pdisc->wwnn,
pdisc->vendor_version);
break;
case ZFCP_LS_ADISC:
adisc = (struct zfcp_ls_adisc_acc*)resp;
ZFCP_LOG_NORMAL(
"ADISC response from did 0x%06x to sid 0x%06x "
"with payload(wwpn=0x%016Lx wwnn=0x%016Lx "
"hard_nport_id=0x%06x nport_id=0x%06x)\n",
port->d_id, port->adapter->s_id,
(unsigned long long)adisc->wwpn,
(unsigned long long)adisc->wwnn,
adisc->hard_nport_id, adisc->nport_id);
/* FIXME: missing wwnn value in port struct */
if (port->wwnn == 0)
port->wwnn = adisc->wwnn;
break;
}
break;
default:
ZFCP_LOG_NORMAL(
"Unknown payload code 0x%02x received on a request "
"0x%02x from sid 0x%06x to did 0x%06x, "
"port needs to be reopened\n",
req_code, resp_code, port->adapter->s_id, port->d_id);
retval = zfcp_erp_port_forced_reopen(port, 0);
if (retval != 0) {
ZFCP_LOG_NORMAL(
"Cannot reopen a remote port "
"with WWPN 0x%Lx on the adapter %s\n",
port->wwpn, zfcp_get_busid_by_port(port));
retval = -EPERM;
}
}
skip_fsfstatus:
__free_pages(send_els->req->page, 0);
kfree(send_els->req);
kfree(send_els->resp);
return retval;
}
/*
* function: zfcp_test_link
*
* purpose: Test a status of a link to a remote port using the ELS command ADISC
*
* returns: 0 - Link is OK
* -EPERM - Port forced reopen failed
*/
int
zfcp_test_link(struct zfcp_port *port)
{
int retval;
retval = zfcp_els(port, ZFCP_LS_ADISC);
if (retval != 0) {
ZFCP_LOG_NORMAL(
"Port with WWPN 0x%Lx on the adapter %s "
"needs to be reopened\n",
port->wwpn, zfcp_get_busid_by_port(port));
retval = zfcp_erp_port_forced_reopen(port, 0);
if (retval != 0) {
ZFCP_LOG_NORMAL(
"Cannot reopen a remote port "
"with WWPN 0x%Lx on the adapter %s\n",
port->wwpn, zfcp_get_busid_by_port(port));
retval = -EPERM;
}
}
return retval;
}
/*
* function:
*
......@@ -741,37 +1114,27 @@ zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action)
"a_ca_disreq");
fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED;
}
if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) {
ZFCP_LOG_NORMAL
("error: Error Recovery Procedure "
"step timed out. The action flag "
"is 0x%x. The FSF request "
"is at 0x%lx\n",
erp_action->action,
(unsigned long)
erp_action->fsf_req);
}
/*
* If fsf_req is neither dismissed nor completed
* then keep it running asynchronously and don't mess with
* the association of erp_action and fsf_req.
* then keep it running asynchronously and don't mess
* with the association of erp_action and fsf_req.
*/
if (fsf_req->status & (ZFCP_STATUS_FSFREQ_COMPLETED |
ZFCP_STATUS_FSFREQ_DISMISSED)) {
/* forget about association between fsf_req and erp_action */
/* forget about association between fsf_req
and erp_action */
fsf_req->erp_action = NULL;
erp_action->fsf_req = NULL;
/* some special things for time out conditions */
if (erp_action-> status & ZFCP_STATUS_ERP_TIMEDOUT) {
ZFCP_LOG_NORMAL
("error: Error Recovery Procedure step timed out. "
"The action flag is 0x%x. The FSF request "
"is at 0x%lx\n", erp_action->action,
(unsigned long) erp_action->fsf_req);
/* fight for low memory buffer, if required */
if (fsf_req->
status & ZFCP_STATUS_FSFREQ_POOL) {
debug_text_event(adapter->erp_dbf, 3,
"a_ca_lowmem");
ZFCP_LOG_NORMAL
("error: The error recovery action using the "
"low memory pool timed out. Restarting IO on "
"the adapter %s to free it.\n",
zfcp_get_busid_by_adapter
(adapter));
zfcp_erp_adapter_reopen_internal(adapter, 0);
}
}
}
} else {
debug_text_event(adapter->erp_dbf, 3, "a_ca_gonereq");
......@@ -1122,12 +1485,36 @@ zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
goto unlock;
case ZFCP_ERP_NOMEM:
/* no memory to continue immediately, let it sleep */
if (!(erp_action->status & ZFCP_STATUS_ERP_LOWMEM)) {
++adapter->erp_low_mem_count;
erp_action->status |= ZFCP_STATUS_ERP_LOWMEM;
}
/* This condition is true if there is no memory available
for any erp_action on this adapter. This implies that there
are no elements in the memory pool(s) left for erp_actions.
This might happen if an erp_action that used a memory pool
element was timed out.
*/
if (adapter->erp_total_count == adapter->erp_low_mem_count) {
debug_text_event(adapter->erp_dbf, 3, "a_st_lowmem");
ZFCP_LOG_NORMAL
("error: Out of memory. No mempool elements "
"available. Restarting IO on the adapter %s "
"to free mempool.\n",
zfcp_get_busid_by_adapter(adapter));
zfcp_erp_adapter_reopen_internal(adapter, 0);
} else {
debug_text_event(adapter->erp_dbf, 2, "a_st_memw");
retval = zfcp_erp_strategy_memwait(erp_action);
/* fall through, waiting for memory means action continues */
}
goto unlock;
case ZFCP_ERP_CONTINUES:
/* leave since this action runs asynchronously */
debug_text_event(adapter->erp_dbf, 6, "a_st_cont");
if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) {
--adapter->erp_low_mem_count;
erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM;
}
goto unlock;
}
/* ok, finished action (whatever its result is) */
......@@ -1531,16 +1918,24 @@ zfcp_erp_strategy_check_unit(struct zfcp_unit *unit, int result)
debug_event(unit->port->adapter->erp_dbf, 5, &unit->fcp_lun,
sizeof (fcp_lun_t));
if (result == ZFCP_ERP_SUCCEEDED) {
switch (result) {
case ZFCP_ERP_SUCCEEDED :
atomic_set(&unit->erp_counter, 0);
zfcp_erp_unit_unblock(unit);
} else {
/* ZFCP_ERP_FAILED or ZFCP_ERP_EXIT */
break;
case ZFCP_ERP_FAILED :
atomic_inc(&unit->erp_counter);
if (atomic_read(&unit->erp_counter) > ZFCP_MAX_ERPS) {
if (atomic_read(&unit->erp_counter) > ZFCP_MAX_ERPS)
zfcp_erp_unit_failed(unit);
result = ZFCP_ERP_EXIT;
}
break;
case ZFCP_ERP_EXIT :
/* nothing */
break;
}
if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &unit->status)) {
zfcp_erp_unit_block(unit, 0); /* for ZFCP_ERP_SUCCEEDED */
result = ZFCP_ERP_EXIT;
}
return result;
......@@ -1559,16 +1954,24 @@ zfcp_erp_strategy_check_port(struct zfcp_port *port, int result)
debug_text_event(port->adapter->erp_dbf, 5, "p_stct");
debug_event(port->adapter->erp_dbf, 5, &port->wwpn, sizeof (wwn_t));
if (result == ZFCP_ERP_SUCCEEDED) {
switch (result) {
case ZFCP_ERP_SUCCEEDED :
atomic_set(&port->erp_counter, 0);
zfcp_erp_port_unblock(port);
} else {
/* ZFCP_ERP_FAILED or ZFCP_ERP_EXIT */
break;
case ZFCP_ERP_FAILED :
atomic_inc(&port->erp_counter);
if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS) {
if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS)
break;
case ZFCP_ERP_EXIT :
/* nothing */
break;
}
if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &port->status)) {
zfcp_erp_port_block(port, 0); /* for ZFCP_ERP_SUCCEEDED */
result = ZFCP_ERP_EXIT;
zfcp_erp_port_failed(port);
result = ZFCP_ERP_EXIT;
}
}
return result;
......@@ -1586,16 +1989,24 @@ zfcp_erp_strategy_check_adapter(struct zfcp_adapter *adapter, int result)
{
debug_text_event(adapter->erp_dbf, 5, "a_stct");
if (result == ZFCP_ERP_SUCCEEDED) {
switch (result) {
case ZFCP_ERP_SUCCEEDED :
atomic_set(&adapter->erp_counter, 0);
zfcp_erp_adapter_unblock(adapter);
} else {
/* ZFCP_ERP_FAILED or ZFCP_ERP_EXIT */
break;
case ZFCP_ERP_FAILED :
atomic_inc(&adapter->erp_counter);
if (atomic_read(&adapter->erp_counter) > ZFCP_MAX_ERPS) {
if (atomic_read(&adapter->erp_counter) > ZFCP_MAX_ERPS)
zfcp_erp_adapter_failed(adapter);
result = ZFCP_ERP_EXIT;
}
break;
case ZFCP_ERP_EXIT :
/* nothing */
break;
}
if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &adapter->status)) {
zfcp_erp_adapter_block(adapter, 0); /* for ZFCP_ERP_SUCCEEDED */
result = ZFCP_ERP_EXIT;
}
return result;
......@@ -1999,10 +2410,10 @@ zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *erp_action, int close)
int
zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action)
{
int retval = 0;
struct zfcp_adapter *adapter = erp_action->adapter;
int retval;
int i;
volatile struct qdio_buffer_element *buffere;
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)) {
......@@ -2034,10 +2445,10 @@ zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action)
* put buffers into response queue,
*/
for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) {
buffere = &(adapter->response_queue.buffer[i]->element[0]);
buffere->length = 0;
buffere->flags = SBAL_FLAGS_LAST_ENTRY;
buffere->addr = 0;
sbale = &(adapter->response_queue.buffer[i]->element[0]);
sbale->length = 0;
sbale->flags = SBAL_FLAGS_LAST_ENTRY;
sbale->addr = 0;
}
ZFCP_LOG_TRACE("Calling do QDIO busid=%s, flags=0x%x, queue_no=%i, "
......@@ -2591,7 +3002,7 @@ zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *erp_action)
if (atomic_test_mask((ZFCP_STATUS_COMMON_OPEN |
ZFCP_STATUS_PORT_DID_DID),
&port->status)) {
ZFCP_LOG_DEBUG("port wwpn=0x%Lx is open ", port->wwpn);
ZFCP_LOG_DEBUG("port wwpn=0x%Lx is open\n", port->wwpn);
retval = ZFCP_ERP_SUCCEEDED;
} else {
ZFCP_LOG_DEBUG("failed to open port wwpn=0x%Lx\n",
......@@ -2845,7 +3256,7 @@ zfcp_erp_port_strategy_open_common_lookup(struct zfcp_erp_action *erp_action)
struct zfcp_port *port = erp_action->port;
zfcp_erp_timeout_init(erp_action);
retval = zfcp_nameserver_request(erp_action);
retval = zfcp_ns_gid_pn_request(erp_action);
if (retval == -ENOMEM) {
debug_text_event(adapter->erp_dbf, 5, "p_pstn_nomem");
debug_event(adapter->erp_dbf, 5, &port->wwpn, sizeof (wwn_t));
......@@ -3087,6 +3498,10 @@ zfcp_erp_action_enqueue(int action,
* efficient.
*/
if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP,
&adapter->status))
goto out;
debug_event(adapter->erp_dbf, 4, &action, sizeof (int));
/* check whether we really need this */
switch (action) {
......@@ -3222,6 +3637,8 @@ zfcp_erp_action_enqueue(int action,
erp_action->action = action;
erp_action->status = status;
++adapter->erp_total_count;
/* finally put it into 'ready' queue and kick erp thread */
list_add(&erp_action->list, &adapter->erp_ready_head);
up(&adapter->erp_ready_sem);
......@@ -3243,6 +3660,12 @@ zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action)
int retval = 0;
struct zfcp_adapter *adapter = erp_action->adapter;
--adapter->erp_total_count;
if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) {
--adapter->erp_low_mem_count;
erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM;
}
debug_text_event(adapter->erp_dbf, 4, "a_actdeq");
debug_event(adapter->erp_dbf, 4, &erp_action->action, sizeof (int));
list_del(&erp_action->list);
......@@ -3404,4 +3827,3 @@ zfcp_erp_action_to_ready(struct zfcp_erp_action *erp_action)
}
#undef ZFCP_LOG_AREA
#undef ZFCP_LOG_AREA_PREFIX
......@@ -4,11 +4,12 @@
*
* FCP adapter driver for IBM eServer zSeries
*
* Copyright 2002 IBM Corporation
* (C) Copyright IBM Corp. 2002, 2004
*
* Author(s): Martin Peschke <mpeschke@de.ibm.com>
* Raimund Schroeder <raimund.schroeder@de.ibm.com>
* Aron Zeh <arzeh@de.ibm.com>
* Wolfgang Taphorn <taphorn@de.ibm.com>
* Aron Zeh
* Wolfgang Taphorn
* Stefan Bader <stefan.bader@de.ibm.com>
* Heiko Carstens <heiko.carstens@de.ibm.com>
*
......@@ -30,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.38 $"
#define ZFCP_EXT_REVISION "$Revision: 1.45 $"
#include "zfcp_def.h"
......@@ -46,7 +47,6 @@ extern void zfcp_sysfs_port_remove_files(struct device *, u32);
extern int zfcp_sysfs_unit_create_files(struct device *);
extern void zfcp_sysfs_unit_remove_files(struct device *);
extern void zfcp_sysfs_port_release(struct device *);
extern int zfcp_sysfs_port_shutdown(struct zfcp_port *);
extern void zfcp_sysfs_unit_release(struct device *);
/**************************** CONFIGURATION *********************************/
......@@ -65,7 +65,6 @@ extern void zfcp_unit_dequeue(struct zfcp_unit *);
extern int zfcp_ccw_register(void);
extern void zfcp_ccw_unregister(void);
extern int zfcp_initialize_with_0copy(struct zfcp_adapter *);
extern void zfcp_qdio_zero_sbals(struct qdio_buffer **, int, int);
extern int zfcp_qdio_allocate(struct zfcp_adapter *);
extern int zfcp_qdio_allocate_queues(struct zfcp_adapter *);
......@@ -74,6 +73,16 @@ extern int zfcp_qdio_determine_pci(struct zfcp_qdio_queue *,
struct zfcp_fsf_req *);
extern int zfcp_qdio_reqid_check(struct zfcp_adapter *, void *);
extern volatile struct qdio_buffer_element *zfcp_qdio_sbale_req
(struct zfcp_fsf_req *, int, int);
extern volatile struct qdio_buffer_element *zfcp_qdio_sbale_curr
(struct zfcp_fsf_req *);
extern int zfcp_qdio_sbals_from_sg
(struct zfcp_fsf_req *, unsigned long, struct scatterlist *, int, int);
extern int zfcp_qdio_sbals_from_scsicmnd
(struct zfcp_fsf_req *, unsigned long, struct scsi_cmnd *);
/******************************** FSF ****************************************/
extern int zfcp_fsf_open_port(struct zfcp_erp_action *);
extern int zfcp_fsf_close_port(struct zfcp_erp_action *);
......@@ -83,17 +92,20 @@ 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_control_file(struct zfcp_adapter *, struct zfcp_fsf_req **,
u32, u32, struct zfcp_sg_list *);
extern void zfcp_fsf_scsi_er_timeout_handler(unsigned long);
extern int zfcp_fsf_req_dismiss_all(struct zfcp_adapter *);
extern int zfcp_fsf_status_read(struct zfcp_adapter *, int);
extern int zfcp_fsf_req_create(struct zfcp_adapter *,u32, unsigned long *,
int, struct zfcp_fsf_req **);
extern void zfcp_fsf_req_free(struct zfcp_fsf_req *);
extern int zfcp_fsf_send_generic(struct zfcp_fsf_req *, unsigned char,
unsigned long *, struct timer_list *);
extern int zfcp_fsf_req_create(struct zfcp_adapter *, u32, int, mempool_t *,
unsigned long *, struct zfcp_fsf_req **);
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 *, Scsi_Cmnd *,
struct zfcp_unit *,
struct scsi_cmnd *,
int);
extern int zfcp_fsf_req_complete(struct zfcp_fsf_req *);
extern void zfcp_fsf_incoming_els(struct zfcp_fsf_req *);
......@@ -105,15 +117,11 @@ extern struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(
/******************************** FCP ****************************************/
extern int zfcp_nameserver_enqueue(struct zfcp_adapter *);
extern int zfcp_nameserver_request(struct zfcp_erp_action *);
extern void zfcp_fsf_els_processing(struct zfcp_fsf_req *);
extern int zfcp_ns_gid_pn_request(struct zfcp_erp_action *);
/******************************* SCSI ****************************************/
extern int zfcp_adapter_scsi_register(struct zfcp_adapter *);
extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *);
extern void zfcp_scsi_block_requests(struct Scsi_Host *);
extern int zfcp_create_sbals_from_sg(struct zfcp_fsf_req *,
Scsi_Cmnd *, char, int, int);
extern void zfcp_set_fcp_dl(struct fcp_cmnd_iu *, fcp_dl_t);
extern char *zfcp_get_fcp_rsp_info_ptr(struct fcp_rsp_iu *);
extern void set_host_byte(u32 *, char);
......@@ -122,6 +130,11 @@ extern char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *);
extern void zfcp_fsf_start_scsi_er_timer(struct zfcp_adapter *);
extern fcp_dl_t zfcp_get_fcp_dl(struct fcp_cmnd_iu *);
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);
/******************************** ERP ****************************************/
extern void zfcp_erp_modify_adapter_status(struct zfcp_adapter *, u32, int);
extern int zfcp_erp_adapter_reopen(struct zfcp_adapter *, int);
......@@ -147,10 +160,12 @@ extern int zfcp_erp_thread_kill(struct zfcp_adapter *);
extern int zfcp_erp_wait(struct zfcp_adapter *);
extern void zfcp_erp_fsf_req_handler(struct zfcp_fsf_req *);
extern int zfcp_test_link(struct zfcp_port *);
/******************************** 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 *, Scsi_Cmnd *);
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);
#ifdef ZFCP_STAT_REQSIZES
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -4,11 +4,12 @@
*
* FCP adapter driver for IBM eServer zSeries
*
* Copyright 2002 IBM Corporation
* (C) Copyright IBM Corp. 2002, 2004
*
* Author(s): Martin Peschke <mpeschke@de.ibm.com>
* Raimund Schroeder <raimund.schroeder@de.ibm.com>
* Aron Zeh <arzeh@de.ibm.com>
* Wolfgang Taphorn <taphorn@de.ibm.com>
* Aron Zeh
* Wolfgang Taphorn
* Stefan Bader <stefan.bader@de.ibm.com>
* Heiko Carstens <heiko.carstens@de.ibm.com>
*
......@@ -44,11 +45,22 @@
#define FSF_QTCB_SEND_ELS 0x0000000B
#define FSF_QTCB_SEND_GENERIC 0x0000000C
#define FSF_QTCB_EXCHANGE_CONFIG_DATA 0x0000000D
#define FSF_QTCB_EXCHANGE_PORT_DATA 0x0000000E
#define FSF_QTCB_DOWNLOAD_CONTROL_FILE 0x00000012
#define FSF_QTCB_UPLOAD_CONTROL_FILE 0x00000013
/* FSF QTCB types */
#define FSF_IO_COMMAND 0x00000001
#define FSF_SUPPORT_COMMAND 0x00000002
#define FSF_CONFIG_COMMAND 0x00000003
#define FSF_PORT_COMMAND 0x00000004
/* FSF control file upload/download operations' subtype and options */
#define FSF_CFDC_OPERATION_SUBTYPE 0x00020001
#define FSF_CFDC_OPTION_NORMAL_MODE 0x00000000
#define FSF_CFDC_OPTION_FORCE 0x00000001
#define FSF_CFDC_OPTION_FULL_ACCESS 0x00000002
#define FSF_CFDC_OPTION_RESTRICTED_ACCESS 0x00000004
/* FSF protocol stati */
#define FSF_PROT_GOOD 0x00000001
......@@ -71,9 +83,9 @@
#define FSF_HANDLE_MISMATCH 0x00000005
#define FSF_SERVICE_CLASS_NOT_SUPPORTED 0x00000006
#define FSF_FCPLUN_NOT_VALID 0x00000009
//#define FSF_ACCESS_DENIED 0x00000010
#define FSF_ACCESS_DENIED 0x00000010
#define FSF_ACCESS_TYPE_NOT_VALID 0x00000011
#define FSF_LUN_IN_USE 0x00000012
#define FSF_LUN_SHARING_VIOLATION 0x00000012
#define FSF_COMMAND_ABORTED_ULP 0x00000020
#define FSF_COMMAND_ABORTED_ADAPTER 0x00000021
#define FSF_FCP_COMMAND_DOES_NOT_EXIST 0x00000022
......@@ -87,13 +99,24 @@
#define FSF_RESPONSE_BUF_NOT_VALID 0x00000043
#define FSF_ELS_COMMAND_REJECTED 0x00000050
#define FSF_GENERIC_COMMAND_REJECTED 0x00000051
//#define FSF_AUTHORIZATION_FAILURE 0x00000053
#define FSF_OPERATION_PARTIALLY_SUCCESSFUL 0x00000052
#define FSF_AUTHORIZATION_FAILURE 0x00000053
#define FSF_CFDC_ERROR_DETECTED 0x00000054
#define FSF_CONTROL_FILE_UPDATE_ERROR 0x00000055
#define FSF_CONTROL_FILE_TOO_LARGE 0x00000056
#define FSF_ACCESS_CONFLICT_DETECTED 0x00000057
#define FSF_CONFLICTS_OVERRULED 0x00000058
#define FSF_PORT_BOXED 0x00000059
//#define FSF_LUN_BOXED 0x0000005A
#define FSF_LUN_BOXED 0x0000005A
#define FSF_PAYLOAD_SIZE_MISMATCH 0x00000060
#define FSF_REQUEST_SIZE_TOO_LARGE 0x00000061
#define FSF_RESPONSE_SIZE_TOO_LARGE 0x00000062
#define FSF_ADAPTER_STATUS_AVAILABLE 0x000000AD
#define FSF_FCP_RSP_AVAILABLE 0x000000AF
#define FSF_UNKNOWN_COMMAND 0x000000E2
//#define FSF_ERROR 0x000000FF
#define FSF_UNKNOWN_OP_SUBTYPE 0x000000E3
#define FSF_INVALID_COMMAND_OPTION 0x000000E5
/* #define FSF_ERROR 0x000000FF */
#define FSF_STATUS_QUALIFIER_SIZE 16
......@@ -107,6 +130,15 @@
#define FSF_SQ_COMMAND_ABORTED 0x06
#define FSF_SQ_NO_RETRY_POSSIBLE 0x07
/* FSF status qualifier for CFDC commands */
#define FSF_SQ_CFDC_COULD_NOT_HARDEN_ON_SE 0x00000001
#define FSF_SQ_CFDC_COULD_NOT_HARDEN_ON_SE2 0x00000002
/* CFDC subtable codes */
#define FSF_SQ_CFDC_SUBTABLE_OS 0x0001
#define FSF_SQ_CFDC_SUBTABLE_PORT_WWPN 0x0002
#define FSF_SQ_CFDC_SUBTABLE_PORT_DID 0x0003
#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
......@@ -124,11 +156,20 @@
#define FSF_STATUS_READ_BIT_ERROR_THRESHOLD 0x00000004
#define FSF_STATUS_READ_LINK_DOWN 0x00000005 /* FIXME: really? */
#define FSF_STATUS_READ_LINK_UP 0x00000006
#define FSF_STATUS_READ_NOTIFICATION_LOST 0x00000009
#define FSF_STATUS_READ_CFDC_UPDATED 0x0000000A
#define FSF_STATUS_READ_CFDC_HARDENED 0x0000000B
/* 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 CFDC */
#define FSF_STATUS_READ_SUB_LOST_CFDC_UPDATED 0x00000020
#define FSF_STATUS_READ_SUB_LOST_CFDC_HARDENED 0x00000040
#define FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE 0x00000002
#define FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE2 0x0000000F
/* topologie that is detected by the adapter */
#define FSF_TOPO_ERROR 0x00000000
#define FSF_TOPO_P2P 0x00000001
......@@ -149,10 +190,48 @@
/* SBAL chaining */
#define FSF_MAX_SBALS_PER_REQ 36
#define FSF_MAX_SBALS_PER_ELS_REQ 2
/* logging space behind QTCB */
#define FSF_QTCB_LOG_SIZE 1024
/* channel features */
#define FSF_FEATURE_QTCB_SUPPRESSION 0x00000001
#define FSF_FEATURE_CFDC 0x00000002
#define FSF_FEATURE_SENSEDATA_REPLICATION 0x00000004
#define FSF_FEATURE_LOST_SAN_NOTIFICATION 0x00000008
#define FSF_FEATURE_HBAAPI_MANAGEMENT 0x00000010
#define FSF_FEATURE_ELS_CT_CHAINED_SBALS 0x00000020
/* option */
#define FSF_OPEN_LUN_SUPPRESS_BOXING 0x00000001
/* adapter types */
#define FSF_ADAPTER_TYPE_FICON 0x00000001
#define FSF_ADAPTER_TYPE_FICON_EXPRESS 0x00000002
/* port types */
#define FSF_HBA_PORTTYPE_UNKNOWN 0x00000001
#define FSF_HBA_PORTTYPE_NOTPRESENT 0x00000003
#define FSF_HBA_PORTTYPE_NPORT 0x00000005
#define FSF_HBA_PORTTYPE_PTP 0x00000021
/* following are not defined and used by FSF Spec
but are additionally defined by FC-HBA */
#define FSF_HBA_PORTTYPE_OTHER 0x00000002
#define FSF_HBA_PORTTYPE_NOTPRESENT 0x00000003
#define FSF_HBA_PORTTYPE_NLPORT 0x00000006
#define FSF_HBA_PORTTYPE_FLPORT 0x00000007
#define FSF_HBA_PORTTYPE_FPORT 0x00000008
#define FSF_HBA_PORTTYPE_LPORT 0x00000020
/* port states */
#define FSF_HBA_PORTSTATE_UNKNOWN 0x00000001
#define FSF_HBA_PORTSTATE_ONLINE 0x00000002
#define FSF_HBA_PORTSTATE_OFFLINE 0x00000003
#define FSF_HBA_PORTSTATE_LINKDOWN 0x00000006
#define FSF_HBA_PORTSTATE_ERROR 0x00000007
struct fsf_queue_designator;
struct fsf_status_read_buffer;
struct fsf_port_closed_payload;
......@@ -307,49 +386,92 @@ struct fsf_qtcb_bottom_io {
} __attribute__ ((packed));
struct fsf_qtcb_bottom_support {
u8 res1[16];
u32 operation_subtype;
u8 res1[12];
u32 d_id;
u32 res2;
u32 option;
u64 fcp_lun;
u64 res3;
u64 res2;
u64 req_handle;
u32 service_class;
u8 res4[3];
u8 res3[3];
u8 timeout;
u8 res5[184];
u8 res4[184];
u32 els1_length;
u32 els2_length;
u64 res6;
u32 req_buf_length;
u32 resp_buf_length;
u8 els[256];
} __attribute__ ((packed));
struct fsf_qtcb_bottom_config {
u32 lic_version;
u32 res1;
u32 feature_selection;
u32 high_qtcb_version;
u32 low_qtcb_version;
u32 max_qtcb_size;
u8 res2[12];
u32 max_data_transfer_size;
u32 supported_features;
u8 res1[4];
u32 fc_topology;
u32 fc_link_speed;
u32 adapter_type;
u32 peer_d_id;
u8 res3[12];
u8 res2[12];
u32 s_id;
struct fsf_nport_serv_param nport_serv_param;
u8 res4[320];
u8 res3[8];
u32 adapter_ports;
u32 hardware_version;
u8 serial_number[32];
u8 res4[272];
} __attribute__ ((packed));
struct fsf_qtcb_bottom_port {
u8 res1[8];
u32 fc_port_id;
u32 port_type;
u32 port_state;
u32 class_of_service; /* should be 0x00000006 for class 2 and 3 */
u8 supported_fc4_types[32]; /* should be 0x00000100 for scsi fcp */
u8 active_fc4_types[32];
u32 supported_speed; /* 0x0001 for 1 GBit/s or 0x0002 for 2 GBit/s */
u32 maximum_frame_size; /* fixed value of 2112 */
u64 seconds_since_last_reset;
u64 tx_frames;
u64 tx_words;
u64 rx_frames;
u64 rx_words;
u64 lip; /* 0 */
u64 nos; /* currently 0 */
u64 error_frames; /* currently 0 */
u64 dumped_frames; /* currently 0 */
u64 link_failure;
u64 loss_of_sync;
u64 loss_of_signal;
u64 psp_error_counts;
u64 invalid_tx_words;
u64 invalid_crcs;
u64 input_requests;
u64 output_requests;
u64 control_requests;
u64 input_mb; /* where 1 MByte == 1.000.000 Bytes */
u64 output_mb; /* where 1 MByte == 1.000.000 Bytes */
u8 res2[256];
} __attribute__ ((packed));
union fsf_qtcb_bottom {
struct fsf_qtcb_bottom_io io;
struct fsf_qtcb_bottom_support support;
struct fsf_qtcb_bottom_config config;
struct fsf_qtcb_bottom_port port;
};
struct fsf_qtcb {
struct fsf_qtcb_prefix prefix;
struct fsf_qtcb_header header;
union fsf_qtcb_bottom bottom;
u8 log[FSF_QTCB_LOG_SIZE];
} __attribute__ ((packed));
#endif /* FSF_H */
......@@ -5,11 +5,12 @@
*
* QDIO related routines
*
* Copyright (C) 2003 IBM Entwicklung GmbH, IBM Corporation
* (C) Copyright IBM Corp. 2002, 2004
*
* Authors:
* Martin Peschke <mpeschke@de.ibm.com>
* Raimund Schroeder <raimund.schroeder@de.ibm.com>
* Wolfgang Taphorn <taphorn@de.ibm.com>
* Wolfgang Taphorn
* Heiko Carstens <heiko.carstens@de.ibm.com>
*
* This program is free software; you can redistribute it and/or modify
......@@ -27,10 +28,28 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define ZFCP_QDIO_C_REVISION "$Revision: 1.10 $"
#define ZFCP_QDIO_C_REVISION "$Revision: 1.13 $"
#include "zfcp_ext.h"
static inline void zfcp_qdio_sbal_limit(struct zfcp_fsf_req *, int);
static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_get
(struct zfcp_qdio_queue *, int, int);
static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_resp
(struct zfcp_fsf_req *, int, int);
static inline volatile struct qdio_buffer_element *zfcp_qdio_sbal_chain
(struct zfcp_fsf_req *, unsigned long);
static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_next
(struct zfcp_fsf_req *, unsigned long);
static inline int zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *, int, int);
static inline int zfcp_qdio_sbals_wipe(struct zfcp_fsf_req *);
static inline void zfcp_qdio_sbale_fill
(struct zfcp_fsf_req *, unsigned long, void *, int);
static inline int zfcp_qdio_sbals_from_segment
(struct zfcp_fsf_req *, unsigned long, void *, unsigned long);
static inline int zfcp_qdio_sbals_from_buffer
(struct zfcp_fsf_req *, unsigned long, void *, unsigned long, int);
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 *,
......@@ -38,7 +57,6 @@ static int zfcp_qdio_handler_error_check(struct zfcp_adapter *,
unsigned int, unsigned int);
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_QDIO
#define ZFCP_LOG_AREA_PREFIX ZFCP_LOG_AREA_PREFIX_QDIO
/*
* Allocates BUFFER memory to each of the pointers of the qdio_buffer_t
......@@ -318,7 +336,7 @@ zfcp_qdio_request_handler(struct ccw_device *ccw_device,
atomic_add(elements_processed, &queue->free_count);
ZFCP_LOG_DEBUG("free_count=%d\n", atomic_read(&queue->free_count));
wake_up(&adapter->request_wq);
ZFCP_LOG_DEBUG("Elements_processed = %d, free count=%d \n",
ZFCP_LOG_DEBUG("Elements_processed = %d, free count=%d\n",
elements_processed, atomic_read(&queue->free_count));
out:
return;
......@@ -365,7 +383,7 @@ zfcp_qdio_response_handler(struct ccw_device *ccw_device,
*/
buffere = &(queue->buffer[first_element]->element[0]);
ZFCP_LOG_DEBUG("first BUFFERE flags=0x%x \n ", buffere->flags);
ZFCP_LOG_DEBUG("first BUFFERE flags=0x%x \n", buffere->flags);
/*
* go through all SBALs from input queue currently
* returned by QDIO layer
......@@ -516,8 +534,8 @@ zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, void *sbale_addr)
(unsigned long) fsf_req, (unsigned long) fsf_req->qtcb);
if (likely(fsf_req->qtcb)) {
ZFCP_LOG_TRACE("HEX DUMP OF 1ST BUFFERE PAYLOAD (QTCB):\n");
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE,
(char *) fsf_req->qtcb, ZFCP_QTCB_SIZE);
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, (char *) fsf_req->qtcb,
sizeof(struct fsf_qtcb));
}
/* finish the FSF request */
......@@ -526,24 +544,346 @@ zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, void *sbale_addr)
return retval;
}
/**
* zfcp_qdio_sbale_get - return pointer to SBALE of qdio_queue
* @queue: queue from which SBALE should be returned
* @sbal: specifies number of SBAL in queue
* @sbale: specifes number of SBALE in SBAL
*/
static inline volatile struct qdio_buffer_element *
zfcp_qdio_sbale_get(struct zfcp_qdio_queue *queue, int sbal, int sbale)
{
return &queue->buffer[sbal]->element[sbale];
}
/**
* zfcp_qdio_sbale_req - return pointer to SBALE of request_queue for
* a struct zfcp_fsf_req
*/
inline volatile struct qdio_buffer_element *
zfcp_qdio_sbale_req(struct zfcp_fsf_req *fsf_req, int sbal, int sbale)
{
return zfcp_qdio_sbale_get(&fsf_req->adapter->request_queue,
sbal, sbale);
}
/**
* zfcp_qdio_sbale_resp - return pointer to SBALE of response_queue for
* a struct zfcp_fsf_req
*/
static inline volatile struct qdio_buffer_element *
zfcp_qdio_sbale_resp(struct zfcp_fsf_req *fsf_req, int sbal, int sbale)
{
return zfcp_qdio_sbale_get(&fsf_req->adapter->response_queue,
sbal, sbale);
}
/**
* zfcp_qdio_sbale_curr - return current SBALE on request_queue for
* a struct zfcp_fsf_req
*/
inline volatile struct qdio_buffer_element *
zfcp_qdio_sbale_curr(struct zfcp_fsf_req *fsf_req)
{
return zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr,
fsf_req->sbale_curr);
}
/**
* zfcp_qdio_sbal_limit - determine maximum number of SBALs that can be used
* on the request_queue for a struct zfcp_fsf_req
* @fsf_req: the number of the last SBAL that can be used is stored herein
* @max_sbals: used to pass an upper limit for the number of SBALs
*
* Note: We can assume at least one free SBAL in the request_queue when called.
*/
static inline void
zfcp_qdio_sbal_limit(struct zfcp_fsf_req *fsf_req, int max_sbals)
{
int count = atomic_read(&fsf_req->adapter->request_queue.free_count);
count = min(count, max_sbals);
fsf_req->sbal_last = fsf_req->sbal_first;
fsf_req->sbal_last += (count - 1);
fsf_req->sbal_last %= QDIO_MAX_BUFFERS_PER_Q;
}
/**
* zfcp_qdio_sbal_chain - chain SBALs if more than one SBAL is needed for a
* request
* @fsf_req: zfcp_fsf_req to be processed
* @sbtype: SBAL flags which have to be set in first SBALE of new SBAL
*
* This function changes sbal_curr, sbale_curr, sbal_number of fsf_req.
*/
static inline volatile struct qdio_buffer_element *
zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype)
{
volatile struct qdio_buffer_element *sbale;
/* set last entry flag in current SBALE of current SBAL */
sbale = zfcp_qdio_sbale_curr(fsf_req);
sbale->flags |= SBAL_FLAGS_LAST_ENTRY;
/* don't exceed last allowed SBAL */
if (fsf_req->sbal_curr == fsf_req->sbal_last)
return NULL;
/* set chaining flag in first SBALE of current SBAL */
sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
sbale->flags |= SBAL_FLAGS0_MORE_SBALS;
/* calculate index of next SBAL */
fsf_req->sbal_curr++;
fsf_req->sbal_curr %= QDIO_MAX_BUFFERS_PER_Q;
/* keep this requests number of SBALs up-to-date */
fsf_req->sbal_number++;
/* start at first SBALE of new SBAL */
fsf_req->sbale_curr = 0;
/* set storage-block type for new SBAL */
sbale = zfcp_qdio_sbale_curr(fsf_req);
sbale->flags |= sbtype;
return sbale;
}
/**
* zfcp_qdio_sbale_next - switch to next SBALE, chain SBALs if needed
*/
static inline volatile struct qdio_buffer_element *
zfcp_qdio_sbale_next(struct zfcp_fsf_req *fsf_req, unsigned long sbtype)
{
if (fsf_req->sbale_curr == ZFCP_LAST_SBALE_PER_SBAL)
return zfcp_qdio_sbal_chain(fsf_req, sbtype);
fsf_req->sbale_curr++;
return zfcp_qdio_sbale_curr(fsf_req);
}
/**
* zfcp_qdio_sbals_zero - initialize SBALs between first and last in queue
* with zero from
*/
static inline int
zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *queue, int first, int last)
{
struct qdio_buffer **buf = queue->buffer;
int curr = first;
int count = 0;
for(;;) {
curr %= QDIO_MAX_BUFFERS_PER_Q;
count++;
memset(buf[curr], 0, sizeof(struct qdio_buffer));
if (curr == last)
break;
curr++;
}
return count;
}
/**
* zfcp_qdio_sbals_wipe - reset all changes in SBALs for an fsf_req
*/
static inline int
zfcp_qdio_sbals_wipe(struct zfcp_fsf_req *fsf_req)
{
return zfcp_qdio_sbals_zero(&fsf_req->adapter->request_queue,
fsf_req->sbal_first, fsf_req->sbal_curr);
}
/**
* zfcp_qdio_sbale_fill - set address and lenght in current SBALE
* on request_queue
*/
static inline void
zfcp_qdio_sbale_fill(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
void *addr, int length)
{
volatile struct qdio_buffer_element *sbale;
sbale = zfcp_qdio_sbale_curr(fsf_req);
sbale->addr = addr;
sbale->length = length;
#ifdef ZFCP_STAT_REQSIZES
if (sbtype == SBAL_FLAGS0_TYPE_READ)
zfcp_statistics_inc(&zfcp_data.read_sg_head, length);
else zfcp_statistics_inc(&zfcp_data.write_sg_head, length);
#endif
}
/**
* zfcp_qdio_sbals_from_segment - map memory segment to SBALE(s)
* @fsf_req: request to be processed
* @sbtype: SBALE flags
* @start_addr: address of memory segment
* @total_length: length of memory segment
*
* Alignment and length of the segment determine how many SBALEs are needed
* for the memory segment.
*/
static inline int
zfcp_qdio_sbals_from_segment(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
void *start_addr, unsigned long total_length)
{
unsigned long remaining, length;
void *addr;
/* split segment up heeding page boundaries */
for (addr = start_addr, remaining = total_length; remaining > 0;
addr += length, remaining -= length) {
/* get next free SBALE for new piece */
if (NULL == zfcp_qdio_sbale_next(fsf_req, sbtype)) {
/* no SBALE left, clean up and leave */
zfcp_qdio_sbals_wipe(fsf_req);
return -EINVAL;
}
/* calculate length of new piece */
length = min(remaining,
(PAGE_SIZE - ((unsigned long) addr &
(PAGE_SIZE - 1))));
/* fill current SBALE with calculated piece */
zfcp_qdio_sbale_fill(fsf_req, sbtype, addr, length);
}
return total_length;
}
/**
* zfcp_qdio_sbals_from_sg - fill SBALs from scatter-gather list
* @fsf_req: request to be processed
* @sbtype: SBALE flags
* @sg: scatter-gather list
* @sg_count: number of elements in scatter-gather list
* @max_sbals: upper bound for number of SBALs to be used
*/
inline int
zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
struct scatterlist *sg, int sg_count, int max_sbals)
{
int sg_index;
struct scatterlist *sg_segment;
int retval;
volatile struct qdio_buffer_element *sbale;
int bytes = 0;
/* figure out last allowed SBAL */
zfcp_qdio_sbal_limit(fsf_req, max_sbals);
/* set storage-block type for current SBAL */
sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
sbale->flags |= sbtype;
/* process all segements of scatter-gather list */
for (sg_index = 0, sg_segment = sg, bytes = 0;
sg_index < sg_count;
sg_index++, sg_segment++) {
retval = zfcp_qdio_sbals_from_segment(
fsf_req,
sbtype,
zfcp_sg_to_address(sg_segment),
sg_segment->length);
if (retval < 0) {
bytes = retval;
goto out;
} else
bytes += retval;
}
/* assume that no other SBALEs are to follow in the same SBAL */
sbale = zfcp_qdio_sbale_curr(fsf_req);
sbale->flags |= SBAL_FLAGS_LAST_ENTRY;
out:
#ifdef ZFCP_STAT_REQSIZES
if (sbtype == SBAL_FLAGS0_TYPE_READ) {
zfcp_statistics_inc(&zfcp_data.read_sguse_head, sg_count);
zfcp_statistics_inc(&zfcp_data.read_req_head, bytes);
} else {
zfcp_statistics_inc(&zfcp_data.write_sguse_head, sg_count);
zfcp_statistics_inc(&zfcp_data.write_req_head, bytes);
}
#endif
return bytes;
}
/**
* zfcp_qdio_sbals_from_buffer - fill SBALs from buffer
* @fsf_req: request to be processed
* @sbtype: SBALE flags
* @buffer: data buffer
* @length: length of buffer
* @max_sbals: upper bound for number of SBALs to be used
*/
static inline int
zfcp_qdio_sbals_from_buffer(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
void *buffer, unsigned long length, int max_sbals)
{
struct scatterlist sg_segment;
zfcp_address_to_sg(buffer, &sg_segment);
sg_segment.length = length;
return zfcp_qdio_sbals_from_sg(fsf_req, sbtype, &sg_segment, 1,
max_sbals);
}
/**
* zfcp_qdio_sbals_from_scsicmnd - fill SBALs from scsi command
* @fsf_req: request to be processed
* @sbtype: SBALE flags
* @scsi_cmnd: either scatter-gather list or buffer contained herein is used
* to fill SBALs
*/
inline int
zfcp_qdio_sbals_from_scsicmnd(struct zfcp_fsf_req *fsf_req,
unsigned long sbtype, struct scsi_cmnd *scsi_cmnd)
{
if (scsi_cmnd->use_sg) {
return zfcp_qdio_sbals_from_sg(fsf_req, sbtype,
(struct scatterlist *)
scsi_cmnd->request_buffer,
scsi_cmnd->use_sg,
ZFCP_MAX_SBALS_PER_REQ);
} else {
return zfcp_qdio_sbals_from_buffer(fsf_req, sbtype,
scsi_cmnd->request_buffer,
scsi_cmnd->request_bufflen,
ZFCP_MAX_SBALS_PER_REQ);
}
}
/**
* zfcp_qdio_determine_pci - set PCI flag in first SBALE on qdio queue if needed
*/
int
zfcp_qdio_determine_pci(struct zfcp_qdio_queue *req_queue,
struct zfcp_fsf_req *fsf_req)
{
int new_distance_from_int;
int pci_pos;
volatile struct qdio_buffer_element *sbale;
new_distance_from_int = req_queue->distance_from_int +
fsf_req->sbal_count;
fsf_req->sbal_number;
if (unlikely(new_distance_from_int >= ZFCP_QDIO_PCI_INTERVAL)) {
new_distance_from_int %= ZFCP_QDIO_PCI_INTERVAL;
pci_pos = fsf_req->sbal_index;
pci_pos += fsf_req->sbal_count;
pci_pos = fsf_req->sbal_first;
pci_pos += fsf_req->sbal_number;
pci_pos -= new_distance_from_int;
pci_pos -= 1;
pci_pos %= QDIO_MAX_BUFFERS_PER_Q;
req_queue->buffer[pci_pos]->element[0].flags |= SBAL_FLAGS0_PCI;
ZFCP_LOG_TRACE("Setting PCI flag at pos %d\n", pci_pos);
sbale = zfcp_qdio_sbale_req(fsf_req, pci_pos, 0);
sbale->flags |= SBAL_FLAGS0_PCI;
}
return new_distance_from_int;
}
......@@ -570,4 +910,3 @@ zfcp_qdio_zero_sbals(struct qdio_buffer *buf[], int first, int clean_count)
}
#undef ZFCP_LOG_AREA
#undef ZFCP_LOG_AREA_PREFIX
......@@ -4,11 +4,12 @@
*
* FCP adapter driver for IBM eServer zSeries
*
* Copyright 2002 IBM Corporation
* (C) Copyright IBM Corp. 2002, 2004
*
* Author(s): Martin Peschke <mpeschke@de.ibm.com>
* Raimund Schroeder <raimund.schroeder@de.ibm.com>
* Aron Zeh <arzeh@de.ibm.com>
* Wolfgang Taphorn <taphorn@de.ibm.com>
* Aron Zeh
* Wolfgang Taphorn
* Stefan Bader <stefan.bader@de.ibm.com>
* Heiko Carstens <heiko.carstens@de.ibm.com>
*
......@@ -28,9 +29,9 @@
*/
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_SCSI
#define ZFCP_LOG_AREA_PREFIX ZFCP_LOG_AREA_PREFIX_SCSI
/* this drivers version (do not edit !!! generated and updated by cvs) */
#define ZFCP_SCSI_REVISION "$Revision: 1.42 $"
#define ZFCP_SCSI_REVISION "$Revision: 1.52 $"
#include <linux/blkdev.h>
......@@ -39,24 +40,14 @@
static void zfcp_scsi_slave_destroy(struct scsi_device *sdp);
static int zfcp_scsi_slave_alloc(struct scsi_device *sdp);
static int zfcp_scsi_slave_configure(struct scsi_device *sdp);
static int zfcp_scsi_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
static int zfcp_scsi_eh_abort_handler(Scsi_Cmnd *);
static int zfcp_scsi_eh_device_reset_handler(Scsi_Cmnd *);
static int zfcp_scsi_eh_bus_reset_handler(Scsi_Cmnd *);
static int zfcp_scsi_eh_host_reset_handler(Scsi_Cmnd *);
static int zfcp_scsi_queuecommand(struct scsi_cmnd *,
void (*done) (struct scsi_cmnd *));
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_create_sbales_from_segment(unsigned long, int, int *,
int, int, int *, int *, int,
int, struct qdio_buffer **,
char);
static int zfcp_create_sbale(unsigned long, int, int *, int, int, int *,
int, int, int *, struct qdio_buffer **,
char);
static struct zfcp_unit *zfcp_scsi_determine_unit(struct zfcp_adapter *,
Scsi_Cmnd *);
static struct zfcp_unit *zfcp_unit_lookup(struct zfcp_adapter *, int, int, int);
static struct device_attribute *zfcp_sysfs_sdev_attrs[];
......@@ -225,59 +216,7 @@ zfcp_scsi_slave_destroy(struct scsi_device *sdpnt)
}
}
void
zfcp_scsi_block_requests(struct Scsi_Host *shpnt)
{
scsi_block_requests(shpnt);
/* This is still somewhat racy but the best I could imagine */
do {
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(ZFCP_SCSI_HOST_FLUSH_TIMEOUT);
} while (shpnt->host_busy || shpnt->eh_active);
}
/*
* Tries to associate a zfcp unit with the scsi device.
*
* returns: unit pointer if unit is found
* NULL otherwise
*/
struct zfcp_unit *
zfcp_scsi_determine_unit(struct zfcp_adapter *adapter, Scsi_Cmnd * scpnt)
{
struct zfcp_unit *unit;
/*
* figure out target device
* (stored there by zfcp_scsi_slave_alloc)
* ATTENTION: assumes hostdata initialized to NULL by
* mid layer (see scsi_scan.c)
*/
unit = (struct zfcp_unit *) scpnt->device->hostdata;
if (!unit) {
ZFCP_LOG_DEBUG("logical unit (%i %i %i %i) not configured\n",
scpnt->device->host->host_no,
scpnt->device->channel,
scpnt->device->id, scpnt->device->lun);
/*
* must fake SCSI command execution and scsi_done
* callback for non-configured logical unit
*/
/* return this as long as we are unable to process requests */
set_host_byte(&scpnt->result, DID_NO_CONNECT);
zfcp_cmd_dbf_event_scsi("notconf", scpnt);
scpnt->scsi_done(scpnt);
#ifdef ZFCP_DEBUG_REQUESTS
debug_text_event(adapter->req_dbf, 2, "nc_done:");
debug_event(adapter->req_dbf, 2, &scpnt,
sizeof (unsigned long));
#endif /* ZFCP_DEBUG_REQUESTS */
}
return unit;
}
/*
* called from scsi midlayer to allow finetuning of a device.
*/
static int
......@@ -290,124 +229,143 @@ zfcp_scsi_slave_configure(struct scsi_device *sdp)
return 0;
}
/* Complete a command immediately handing back DID_ERROR */
/**
* zfcp_scsi_command_fail - set result in scsi_cmnd and call scsi_done function
* @scpnt: pointer to struct scsi_cmnd where result is set
* @result: result to be set in scpnt (e.g. DID_ERROR)
*/
static void
zfcp_scsi_queuecommand_stop(Scsi_Cmnd * scpnt,
struct zfcp_adapter *adapter,
struct zfcp_unit *unit)
zfcp_scsi_command_fail(struct scsi_cmnd *scpnt, int result)
{
/* Always pass through to upper layer */
scpnt->retries = scpnt->allowed - 1;
set_host_byte(&scpnt->result, DID_ERROR);
zfcp_cmd_dbf_event_scsi("stopping", scpnt);
set_host_byte(&scpnt->result, result);
zfcp_cmd_dbf_event_scsi("failing", scpnt);
/* return directly */
scpnt->scsi_done(scpnt);
if (adapter && unit) {
ZFCP_LOG_INFO("Stopping SCSI IO on the unit with FCP LUN 0x%Lx "
"connected to the port with WWPN 0x%Lx at the "
"adapter %s.\n",
unit->fcp_lun,
unit->port->wwpn,
zfcp_get_busid_by_adapter(adapter));
#ifdef ZFCP_DEBUG_REQUESTS
debug_text_event(adapter->req_dbf, 2, "de_done:");
debug_event(adapter->req_dbf, 2, &scpnt,
sizeof (unsigned long));
#endif /* ZFCP_DEBUG_REQUESTS */
} else {
ZFCP_LOG_INFO("There is no adapter registered in the zfcp "
"module for the SCSI host with hostnumber %d. "
"Stopping IO.\n", scpnt->device->host->host_no);
}
}
/*
* function: zfcp_scsi_queuecommand
*
* purpose: enqueues a SCSI command to the specified target device
*
* note: The scsi_done midlayer function may be called directly from
* within queuecommand provided queuecommand returns with
* success (0).
* If it fails, it is expected that the command could not be sent
* and is still available for processing.
* As we ensure that queuecommand never fails, we have the choice
* to call done directly wherever we please.
* Thus, any kind of send errors other than those indicating
* 'infinite' retries will be reported directly.
* Retry requests are put into a list to be processed under timer
* control once in a while to allow for other operations to
* complete in the meantime.
/**
* zfcp_scsi_command_async - worker for zfcp_scsi_queuecommand and
* zfcp_scsi_command_sync
* @adapter: adapter for where scsi command is issued
* @unit: unit to which scsi command is sent
* @scpnt: scsi command to be sent
*
* returns: 0 - success, SCSI command enqueued
* !0 - failure, note that we never allow this to happen as the
* SCSI stack would block indefinitely should a non-zero return
* value be reported if there are no outstanding commands
* (as in when the queues are down)
* Note: In scsi_done function must be set in scpnt.
*/
int
zfcp_scsi_queuecommand(Scsi_Cmnd * scpnt, void (*done) (Scsi_Cmnd *))
zfcp_scsi_command_async(struct zfcp_adapter *adapter, struct zfcp_unit *unit,
struct scsi_cmnd *scpnt)
{
int tmp;
int retval;
int temp_ret;
struct zfcp_unit *unit;
struct zfcp_adapter *adapter;
retval = 0;
/* reset the status for this request */
scpnt->result = 0;
/* save address of mid layer call back function */
scpnt->scsi_done = done;
/*
* figure out adapter
* (previously stored there by the driver when
* the adapter was registered)
*/
adapter = (struct zfcp_adapter *) scpnt->device->host->hostdata[0];
/* NULL when the adapter was removed from the zfcp list */
if (unlikely(adapter == NULL)) {
zfcp_scsi_queuecommand_stop(scpnt, NULL, NULL);
goto out;
}
unit = zfcp_scsi_determine_unit(adapter, scpnt);
if (unlikely(unit == NULL))
BUG_ON((adapter == NULL) || (adapter != unit->port->adapter));
BUG_ON(scpnt->scsi_done == NULL);
if (unlikely(NULL == unit)) {
zfcp_scsi_command_fail(scpnt, DID_NO_CONNECT);
goto out;
}
if (unlikely(
atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &unit->status) ||
!atomic_test_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status))) {
zfcp_scsi_queuecommand_stop(scpnt, adapter, unit);
ZFCP_LOG_DEBUG("Stopping SCSI IO on the unit with "
"FCP LUN 0x%Lx connected to the port "
"with WWPN 0x%Lx at the adapter %s.\n",
unit->fcp_lun,
unit->port->wwpn,
zfcp_get_busid_by_adapter(adapter));
zfcp_scsi_command_fail(scpnt, DID_ERROR);
goto out;
}
if (unlikely(
!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status))) {
ZFCP_LOG_DEBUG("adapter %s not ready or unit with LUN 0x%Lx "
"on the port with WWPN 0x%Lx in recovery.\n",
zfcp_get_busid_by_adapter(adapter),
zfcp_get_busid_by_unit(unit),
unit->fcp_lun, unit->port->wwpn);
retval = SCSI_MLQUEUE_DEVICE_BUSY;
goto out;
}
temp_ret = zfcp_fsf_send_fcp_command_task(adapter,
unit,
scpnt, ZFCP_REQ_AUTO_CLEANUP);
tmp = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt,
ZFCP_REQ_AUTO_CLEANUP);
if (unlikely(temp_ret < 0)) {
if (unlikely(tmp < 0)) {
ZFCP_LOG_DEBUG("error: Could not send a Send FCP Command\n");
retval = SCSI_MLQUEUE_HOST_BUSY;
} else {
#ifdef ZFCP_DEBUG_REQUESTS
debug_text_event(adapter->req_dbf, 3, "q_scpnt");
debug_event(adapter->req_dbf, 3, &scpnt,
sizeof (unsigned long));
#endif /* ZFCP_DEBUG_REQUESTS */
}
out:
out:
return retval;
}
void
zfcp_scsi_command_sync_handler(struct scsi_cmnd *scpnt)
{
struct completion *wait = (struct completion *) scpnt->SCp.ptr;
complete(wait);
}
/**
* zfcp_scsi_command_sync - send a SCSI command and wait for completion
* returns 0, errors are indicated by scsi_cmnd->result
*/
int
zfcp_scsi_command_sync(struct zfcp_unit *unit, struct scsi_cmnd *scpnt)
{
DECLARE_COMPLETION(wait);
scpnt->SCp.ptr = (void *) &wait; /* silent re-use */
scpnt->done = zfcp_scsi_command_sync_handler;
zfcp_scsi_command_async(unit->port->adapter, unit, scpnt);
wait_for_completion(&wait);
return 0;
}
/*
* function: zfcp_scsi_queuecommand
*
* purpose: enqueues a SCSI command to the specified target device
*
* returns: 0 - success, SCSI command enqueued
* !0 - failure
*/
int
zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
void (*done) (struct scsi_cmnd *))
{
struct zfcp_unit *unit;
struct zfcp_adapter *adapter;
/* reset the status for this request */
scpnt->result = 0;
/* save address of mid layer call back function */
scpnt->scsi_done = done;
/*
* figure out adapter and target device
* (stored there by zfcp_scsi_slave_alloc)
*/
adapter = (struct zfcp_adapter *) scpnt->device->host->hostdata[0];
unit = (struct zfcp_unit *) scpnt->device->hostdata;
return zfcp_scsi_command_async(adapter, unit, scpnt);
}
/*
* function: zfcp_unit_lookup
*
......@@ -456,22 +414,18 @@ zfcp_unit_lookup(struct zfcp_adapter *adapter, int channel, int id, int lun)
* FAILED - otherwise
*/
int
zfcp_scsi_eh_abort_handler(Scsi_Cmnd * scpnt)
zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
{
int retval = SUCCESS;
struct zfcp_fsf_req *new_fsf_req, *old_fsf_req;
struct zfcp_adapter *adapter;
struct zfcp_unit *unit;
struct zfcp_port *port;
struct Scsi_Host *scsi_host;
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;
unsigned long flags;
u32 status = 0;
adapter = (struct zfcp_adapter *) scpnt->device->host->hostdata[0];
scsi_host = scpnt->device->host;
unit = (struct zfcp_unit *) scpnt->device->hostdata;
port = unit->port;
#ifdef ZFCP_DEBUG_ABORTS
/* the components of a abort_dbf record (fixed size record) */
......@@ -657,7 +611,7 @@ zfcp_scsi_eh_abort_handler(Scsi_Cmnd * scpnt)
* returns:
*/
int
zfcp_scsi_eh_device_reset_handler(Scsi_Cmnd * scpnt)
zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt)
{
int retval;
struct zfcp_unit *unit = (struct zfcp_unit *) scpnt->device->hostdata;
......@@ -764,7 +718,7 @@ zfcp_task_management_function(struct zfcp_unit *unit, u8 tm_flags)
* returns:
*/
int
zfcp_scsi_eh_bus_reset_handler(Scsi_Cmnd * scpnt)
zfcp_scsi_eh_bus_reset_handler(struct scsi_cmnd *scpnt)
{
int retval = 0;
struct zfcp_unit *unit;
......@@ -793,7 +747,7 @@ zfcp_scsi_eh_bus_reset_handler(Scsi_Cmnd * scpnt)
* returns:
*/
int
zfcp_scsi_eh_host_reset_handler(Scsi_Cmnd * scpnt)
zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
{
int retval = 0;
struct zfcp_unit *unit;
......@@ -887,332 +841,6 @@ zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter)
}
/**
* zfcp_create_sbales_from_segment - creates SBALEs
* @addr: begin of this buffer segment
* @length_seg: length of this buffer segment
* @length_total: total length of buffer
* @length_min: roll back if generated buffer smaller than this
* @length_max: sum of all SBALEs (count) not larger than this
* @buffer_index: position of current BUFFER
* @buffere_index: position of current BUFFERE
* @buffer_first: first BUFFER used for this buffer
* @buffer_last: last BUFFER in request queue allowed
* @buffer: begin of SBAL array of request queue
* @sbtype: storage-block type
*/
static int
zfcp_create_sbales_from_segment(unsigned long addr, int length_seg,
int *length_total, int length_min,
int length_max, int *buffer_index,
int *buffere_index, int buffer_first,
int buffer_last, struct qdio_buffer *buffer[],
char sbtype)
{
int retval = 0;
int length = 0;
ZFCP_LOG_TRACE
("SCSI data buffer segment with %i bytes from 0x%lx to 0x%lx\n",
length_seg, addr, (addr + length_seg) - 1);
if (!length_seg)
goto out;
if (addr & (PAGE_SIZE - 1)) {
length =
min((int) (PAGE_SIZE - (addr & (PAGE_SIZE - 1))),
length_seg);
ZFCP_LOG_TRACE
("address 0x%lx not on page boundary, length=0x%x\n",
(unsigned long) addr, length);
retval =
zfcp_create_sbale(addr, length, length_total, length_min,
length_max, buffer_index, buffer_first,
buffer_last, buffere_index, buffer,
sbtype);
if (retval) {
/* no resources */
goto out;
}
addr += length;
length = length_seg - length;
} else
length = length_seg;
while (length > 0) {
retval = zfcp_create_sbale(addr, min((int) PAGE_SIZE, length),
length_total, length_min, length_max,
buffer_index, buffer_first,
buffer_last, buffere_index, buffer,
sbtype);
if (*buffere_index > ZFCP_LAST_SBALE_PER_SBAL)
ZFCP_LOG_NORMAL("bug: Filling output buffers with SCSI "
"data failed. Index ran out of bounds. "
"(debug info %d)\n", *buffere_index);
if (retval) {
/* no resources */
goto out;
}
length -= PAGE_SIZE;
addr += PAGE_SIZE;
}
out:
return retval;
}
/**
* zfcp_create_sbale - creates a single SBALE
* @addr: begin of this buffer segment
* @length: length of this buffer segment
* @length_total: total length of buffer
* @length_min: roll back if generated buffer smaller than this
* @length_max: sum of all SBALEs (count) not larger than this
* @buffer_index: position of current BUFFER
* @buffer_first: first BUFFER used for this buffer
* @buffer_last: last BUFFER allowed for this buffer
* @buffere_index: position of current BUFFERE of current BUFFER
* @buffer: begin of SBAL array of request queue
* @sbtype: storage-block type
*/
static int
zfcp_create_sbale(unsigned long addr, int length, int *length_total,
int length_min, int length_max, int *buffer_index,
int buffer_first, int buffer_last, int *buffere_index,
struct qdio_buffer *buffer[], char sbtype)
{
int retval = 0;
int length_real, residual;
int buffers_used;
volatile struct qdio_buffer_element *buffere =
&(buffer[*buffer_index]->element[*buffere_index]);
/* check whether we hit the limit */
residual = length_max - *length_total;
if (residual == 0) {
ZFCP_LOG_TRACE("skip remaining %i bytes since length_max hit\n",
length);
goto out;
}
length_real = min(length, residual);
/*
* figure out next BUFFERE
* (first BUFFERE of first BUFFER is skipped -
* this is ok since it is reserved for the QTCB)
*/
if (*buffere_index == ZFCP_LAST_SBALE_PER_SBAL) {
/* last BUFFERE in this BUFFER */
buffere->flags |= SBAL_FLAGS_LAST_ENTRY;
/* need further BUFFER */
if (*buffer_index == buffer_last) {
/* queue full or last allowed BUFFER */
buffers_used = (buffer_last - buffer_first) + 1;
/* avoid modulo operation on negative value */
buffers_used += QDIO_MAX_BUFFERS_PER_Q;
buffers_used %= QDIO_MAX_BUFFERS_PER_Q;
ZFCP_LOG_DEBUG("reached limit of number of BUFFERs "
"allowed for this request\n");
/* FIXME (design) - This check is wrong and enforces the
* use of one SBALE less than possible
*/
if ((*length_total < length_min)
|| (buffers_used < ZFCP_MAX_SBALS_PER_REQ)) {
ZFCP_LOG_DEBUG("Rolling back SCSI command as "
"there are insufficient buffers "
"to cover the minimum required "
"amount of data\n");
/*
* roll back complete list of BUFFERs generated
* from the scatter-gather list associated
* with this SCSI command
*/
zfcp_qdio_zero_sbals(buffer,
buffer_first,
buffers_used);
*length_total = 0;
} else {
/* DEBUG */
ZFCP_LOG_NORMAL("Not enough buffers available. "
"Can only transfer %i bytes of "
"data\n",
*length_total);
}
retval = -ENOMEM;
goto out;
} else { /* *buffer_index != buffer_last */
/* chain BUFFERs */
*buffere_index = 0;
buffere =
&(buffer[*buffer_index]->element[*buffere_index]);
buffere->flags |= SBAL_FLAGS0_MORE_SBALS;
(*buffer_index)++;
*buffer_index %= QDIO_MAX_BUFFERS_PER_Q;
buffere =
&(buffer[*buffer_index]->element[*buffere_index]);
buffere->flags |= sbtype;
ZFCP_LOG_DEBUG
("Chaining previous BUFFER %i to BUFFER %i\n",
((*buffer_index !=
0) ? *buffer_index - 1 : QDIO_MAX_BUFFERS_PER_Q -
1), *buffer_index);
}
} else { /* *buffere_index != (QDIO_MAX_ELEMENTS_PER_BUFFER - 1) */
(*buffere_index)++;
buffere = &(buffer[*buffer_index]->element[*buffere_index]);
}
/* ok, found a place for this piece, put it there */
buffere->addr = (void *) addr;
buffere->length = length_real;
#ifdef ZFCP_STAT_REQSIZES
if (sbtype == SBAL_FLAGS0_TYPE_READ)
zfcp_statistics_inc(&zfcp_data.read_sg_head, length_real);
else
zfcp_statistics_inc(&zfcp_data.write_sg_head, length_real);
#endif
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, (char *) addr, length_real);
ZFCP_LOG_TRACE("BUFFER no %i (0x%lx) BUFFERE no %i (0x%lx): BUFFERE "
"data addr 0x%lx, BUFFERE length %i, BUFFER type %i\n",
*buffer_index,
(unsigned long) &buffer[*buffer_index], *buffere_index,
(unsigned long) buffere, addr, length_real, sbtype);
*length_total += length_real;
out:
return retval;
}
/*
* function: zfcp_create_sbals_from_sg
*
* purpose: walks through scatter-gather list of specified SCSI command
* and creates a corresponding list of SBALs
*
* returns: size of generated buffer in bytes
*
* context:
*/
int
zfcp_create_sbals_from_sg(struct zfcp_fsf_req *fsf_req, Scsi_Cmnd * scpnt,
char sbtype, /* storage-block type */
int length_min, /* roll back if generated buffer */
int buffer_max) /* max numbers of BUFFERs */
{
int length_total = 0;
int buffer_index = 0;
int buffer_last = 0;
int buffere_index = 1; /* elements 0 and 1 are req-id and qtcb */
volatile struct qdio_buffer_element *buffere = NULL;
struct zfcp_qdio_queue *req_q = NULL;
int length_max = scpnt->request_bufflen;
req_q = &fsf_req->adapter->request_queue;
buffer_index = req_q->free_index;
buffer_last = req_q->free_index +
min(buffer_max, atomic_read(&req_q->free_count)) - 1;
buffer_last %= QDIO_MAX_BUFFERS_PER_Q;
ZFCP_LOG_TRACE
("total SCSI data buffer size is (scpnt->request_bufflen) %i\n",
scpnt->request_bufflen);
ZFCP_LOG_TRACE
("BUFFERs from (buffer_index)%i to (buffer_last)%i available\n",
buffer_index, buffer_last);
ZFCP_LOG_TRACE("buffer_max=%d, req_q->free_count=%d\n", buffer_max,
atomic_read(&req_q->free_count));
if (scpnt->use_sg) {
int sg_index;
struct scatterlist *list
= (struct scatterlist *) scpnt->request_buffer;
ZFCP_LOG_DEBUG("%i (scpnt->use_sg) scatter-gather segments\n",
scpnt->use_sg);
// length_max+=0x2100;
#ifdef ZFCP_STAT_REQSIZES
if (sbtype == SBAL_FLAGS0_TYPE_READ)
zfcp_statistics_inc(&zfcp_data.read_sguse_head,
scpnt->use_sg);
else
zfcp_statistics_inc(&zfcp_data.write_sguse_head,
scpnt->use_sg);
#endif
for (sg_index = 0; sg_index < scpnt->use_sg; sg_index++, list++)
{
if (zfcp_create_sbales_from_segment(
(page_to_pfn (list->page) << PAGE_SHIFT) +
list->offset,
list->length,
&length_total,
length_min,
length_max,
&buffer_index,
&buffere_index,
req_q->free_index,
buffer_last,
req_q->buffer,
sbtype))
break;
}
} else {
ZFCP_LOG_DEBUG("no scatter-gather list\n");
#ifdef ZFCP_STAT_REQSIZES
if (sbtype == SBAL_FLAGS0_TYPE_READ)
zfcp_statistics_inc(&zfcp_data.read_sguse_head, 1);
else
zfcp_statistics_inc(&zfcp_data.write_sguse_head, 1);
#endif
zfcp_create_sbales_from_segment(
(unsigned long) scpnt->request_buffer,
scpnt->request_bufflen,
&length_total,
length_min,
length_max,
&buffer_index,
&buffere_index,
req_q->free_index,
buffer_last,
req_q->buffer,
sbtype);
}
fsf_req->sbal_index = req_q->free_index;
if (buffer_index >= fsf_req->sbal_index) {
fsf_req->sbal_count = (buffer_index - fsf_req->sbal_index) + 1;
} else {
fsf_req->sbal_count =
(QDIO_MAX_BUFFERS_PER_Q - fsf_req->sbal_index) +
buffer_index + 1;
}
/* HACK */
if ((scpnt->request_bufflen != 0) && (length_total == 0))
goto out;
#ifdef ZFCP_STAT_REQSIZES
if (sbtype == SBAL_FLAGS0_TYPE_READ)
zfcp_statistics_inc(&zfcp_data.read_req_head, length_total);
else
zfcp_statistics_inc(&zfcp_data.write_req_head, length_total);
#endif
buffere = &(req_q->buffer[buffer_index]->element[buffere_index]);
buffere->flags |= SBAL_FLAGS_LAST_ENTRY;
out:
ZFCP_LOG_DEBUG("%i BUFFER(s) from %i to %i needed\n",
fsf_req->sbal_count, fsf_req->sbal_index, buffer_index);
ZFCP_LOG_TRACE("total QDIO data buffer size is %i\n", length_total);
return length_total;
}
void
zfcp_fsf_start_scsi_er_timer(struct zfcp_adapter *adapter)
{
......@@ -1293,4 +921,3 @@ static struct device_attribute *zfcp_sysfs_sdev_attrs[] = {
};
#undef ZFCP_LOG_AREA
#undef ZFCP_LOG_AREA_PREFIX
......@@ -5,7 +5,8 @@
*
* sysfs adapter related routines
*
* Copyright (C) 2003 IBM Entwicklung GmbH, IBM Corporation
* (C) Copyright IBM Corp. 2003, 2004
*
* Authors:
* Martin Peschke <mpeschke@de.ibm.com>
* Heiko Carstens <heiko.carstens@de.ibm.com>
......@@ -25,14 +26,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define ZFCP_SYSFS_ADAPTER_C_REVISION "$Revision: 1.26 $"
#define ZFCP_SYSFS_ADAPTER_C_REVISION "$Revision: 1.30 $"
#include <asm/ccwdev.h>
#include "zfcp_ext.h"
#include "zfcp_def.h"
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG
#define ZFCP_LOG_AREA_PREFIX ZFCP_LOG_AREA_PREFIX_CONFIG
static const char fc_topologies[5][25] = {
{"<error>"},
......@@ -66,12 +66,15 @@ 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(hw_version, "0x%04x\n", adapter->hydra_version);
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_sysfs_adapter_in_recovery_show - recovery state of adapter
......@@ -259,11 +262,6 @@ zfcp_sysfs_adapter_failed_store(struct device *dev,
goto out;
}
/* restart error recovery only if adapter is online */
if (adapter->ccw_device->online != 1) {
retval = -ENXIO;
goto out;
}
zfcp_erp_modify_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING,
ZFCP_SET);
zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED);
......@@ -304,13 +302,15 @@ static struct attribute *zfcp_adapter_attrs[] = {
&dev_attr_wwnn.attr,
&dev_attr_wwpn.attr,
&dev_attr_s_id.attr,
&dev_attr_hw_version.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
};
......@@ -343,4 +343,3 @@ zfcp_sysfs_adapter_remove_files(struct device *dev)
}
#undef ZFCP_LOG_AREA
#undef ZFCP_LOG_AREA_PREFIX
......@@ -5,7 +5,8 @@
*
* sysfs driver related routines
*
* Copyright (C) 2003 IBM Entwicklung GmbH, IBM Corporation
* (C) Copyright IBM Corp. 2003, 2004
*
* Authors:
* Martin Peschke <mpeschke@de.ibm.com>
* Heiko Carstens <heiko.carstens@de.ibm.com>
......@@ -25,14 +26,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define ZFCP_SYSFS_DRIVER_C_REVISION "$Revision: 1.8 $"
#define ZFCP_SYSFS_DRIVER_C_REVISION "$Revision: 1.12 $"
#include <asm/ccwdev.h>
#include "zfcp_ext.h"
#include "zfcp_def.h"
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG
#define ZFCP_LOG_AREA_PREFIX ZFCP_LOG_AREA_PREFIX_CONFIG
/**
* ZFCP_DEFINE_DRIVER_ATTR - define for all loglevels sysfs attributes
......@@ -67,7 +67,8 @@ static ssize_t zfcp_sysfs_loglevel_##_name##_store(struct device_driver *drv, \
static ssize_t zfcp_sysfs_loglevel_##_name##_show(struct device_driver *dev, \
char *buf) \
{ \
return sprintf(buf,"%d\n", ZFCP_LOG_VALUE(ZFCP_LOG_AREA_##_define)); \
return sprintf(buf,"%d\n", \
ZFCP_GET_LOG_VALUE(ZFCP_LOG_AREA_##_define)); \
} \
\
static DRIVER_ATTR(loglevel_##_name, S_IWUSR | S_IRUGO, \
......@@ -83,6 +84,14 @@ ZFCP_DEFINE_DRIVER_ATTR(qdio, QDIO);
ZFCP_DEFINE_DRIVER_ATTR(erp, ERP);
ZFCP_DEFINE_DRIVER_ATTR(fc, FC);
static ssize_t zfcp_sysfs_version_show(struct device_driver *dev,
char *buf)
{
return sprintf(buf, "%s\n", ZFCP_VERSION);
}
static DRIVER_ATTR(version, S_IRUGO, zfcp_sysfs_version_show, NULL);
static struct attribute *zfcp_driver_attrs[] = {
&driver_attr_loglevel_other.attr,
&driver_attr_loglevel_scsi.attr,
......@@ -92,6 +101,7 @@ static struct attribute *zfcp_driver_attrs[] = {
&driver_attr_loglevel_qdio.attr,
&driver_attr_loglevel_erp.attr,
&driver_attr_loglevel_fc.attr,
&driver_attr_version.attr,
NULL
};
......@@ -124,4 +134,3 @@ zfcp_sysfs_driver_remove_files(struct device_driver *drv)
}
#undef ZFCP_LOG_AREA
#undef ZFCP_LOG_AREA_PREFIX
......@@ -5,7 +5,8 @@
*
* sysfs port related routines
*
* Copyright (C) 2003 IBM Entwicklung GmbH, IBM Corporation
* (C) Copyright IBM Corp. 2003, 2004
*
* Authors:
* Martin Peschke <mpeschke@de.ibm.com>
* Heiko Carstens <heiko.carstens@de.ibm.com>
......@@ -25,7 +26,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define ZFCP_SYSFS_PORT_C_REVISION "$Revision: 1.32 $"
#define ZFCP_SYSFS_PORT_C_REVISION "$Revision: 1.37 $"
#include <linux/init.h>
#include <linux/module.h>
......@@ -34,7 +35,6 @@
#include "zfcp_def.h"
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG
#define ZFCP_LOG_AREA_PREFIX ZFCP_LOG_AREA_PREFIX_CONFIG
/**
* zfcp_sysfs_port_release - gets called when a struct device port is released
......@@ -209,11 +209,6 @@ zfcp_sysfs_port_failed_store(struct device *dev, const char *buf, size_t count)
goto out;
}
/* restart error recovery only if adapter is online */
if (port->adapter->ccw_device->online != 1) {
retval = -ENXIO;
goto out;
}
zfcp_erp_modify_port_status(port, ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET);
zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED);
zfcp_erp_wait(port->adapter);
......@@ -268,6 +263,10 @@ zfcp_sysfs_port_in_recovery_show(struct device *dev, char *buf)
static DEVICE_ATTR(in_recovery, S_IRUGO, zfcp_sysfs_port_in_recovery_show,
NULL);
/**
* zfcp_port_common_attrs
* sysfs attributes that are common for all kind of fc ports.
*/
static struct attribute *zfcp_port_common_attrs[] = {
&dev_attr_failed.attr,
&dev_attr_in_recovery.attr,
......@@ -281,6 +280,10 @@ static struct attribute_group zfcp_port_common_attr_group = {
.attrs = zfcp_port_common_attrs,
};
/**
* zfcp_port_no_ns_attrs
* sysfs attributes not to be used for nameserver ports.
*/
static struct attribute *zfcp_port_no_ns_attrs[] = {
&dev_attr_unit_add.attr,
&dev_attr_unit_remove.attr,
......@@ -330,4 +333,3 @@ zfcp_sysfs_port_remove_files(struct device *dev, u32 flags)
}
#undef ZFCP_LOG_AREA
#undef ZFCP_LOG_AREA_PREFIX
......@@ -5,7 +5,8 @@
*
* sysfs unit related routines
*
* Copyright (C) 2003 IBM Entwicklung GmbH, IBM Corporation
* (C) Copyright IBM Corp. 2003, 2004
*
* Authors:
* Martin Peschke <mpeschke@de.ibm.com>
* Heiko Carstens <heiko.carstens@de.ibm.com>
......@@ -25,7 +26,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define ZFCP_SYSFS_UNIT_C_REVISION "$Revision: 1.19 $"
#define ZFCP_SYSFS_UNIT_C_REVISION "$Revision: 1.23 $"
#include <linux/init.h>
#include <linux/module.h>
......@@ -34,7 +35,6 @@
#include "zfcp_def.h"
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG
#define ZFCP_LOG_AREA_PREFIX ZFCP_LOG_AREA_PREFIX_CONFIG
/**
* zfcp_sysfs_unit_release - gets called when a struct device unit is released
......@@ -104,13 +104,9 @@ zfcp_sysfs_unit_failed_store(struct device *dev, const char *buf, size_t count)
goto out;
}
/* restart error recovery only if adapter is online */
if (unit->port->adapter->ccw_device->online != 1) {
retval = -ENXIO;
goto out;
}
zfcp_erp_modify_unit_status(unit, ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET);
zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED);
zfcp_erp_wait(unit->port->adapter);
out:
up(&zfcp_data.config_sema);
return retval ? retval : count;
......@@ -199,4 +195,3 @@ zfcp_sysfs_unit_remove_files(struct device *dev)
}
#undef ZFCP_LOG_AREA
#undef ZFCP_LOG_AREA_PREFIX
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