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 ...@@ -187,3 +187,5 @@ Code Seq# Include File Comments
0xB1 00-1F PPPoX <mailto:mostrows@styx.uwaterloo.ca> 0xB1 00-1F PPPoX <mailto:mostrows@styx.uwaterloo.ca>
0xCB 00-1F CBM serial IEC bus in development: 0xCB 00-1F CBM serial IEC bus in development:
<mailto:michael.klein@puffin.lb.shuttle.de> <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 @@ ...@@ -4,11 +4,12 @@
* *
* FCP adapter driver for IBM eServer zSeries * 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> * Author(s): Martin Peschke <mpeschke@de.ibm.com>
* Raimund Schroeder <raimund.schroeder@de.ibm.com> * Raimund Schroeder <raimund.schroeder@de.ibm.com>
* Aron Zeh <arzeh@de.ibm.com> * Aron Zeh
* Wolfgang Taphorn <taphorn@de.ibm.com> * Wolfgang Taphorn
* Stefan Bader <stefan.bader@de.ibm.com> * Stefan Bader <stefan.bader@de.ibm.com>
* Heiko Carstens <heiko.carstens@de.ibm.com> * Heiko Carstens <heiko.carstens@de.ibm.com>
* *
...@@ -28,7 +29,7 @@ ...@@ -28,7 +29,7 @@
*/ */
/* this drivers version (do not edit !!! generated and updated by cvs) */ /* 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 *********************************************/ /********************** INCLUDES *********************************************/
...@@ -61,6 +62,9 @@ ...@@ -61,6 +62,9 @@
#include <asm/cpcmd.h> /* Debugging only */ #include <asm/cpcmd.h> /* Debugging only */
#include <asm/processor.h> /* Debugging only */ #include <asm/processor.h> /* Debugging only */
#include <linux/miscdevice.h>
#include <linux/major.h>
/* accumulated log level (module parameter) */ /* accumulated log level (module parameter) */
static u32 loglevel = ZFCP_LOG_LEVEL_DEFAULTS; static u32 loglevel = ZFCP_LOG_LEVEL_DEFAULTS;
static char *device; static char *device;
...@@ -73,7 +77,7 @@ static void __exit zfcp_module_exit(void); ...@@ -73,7 +77,7 @@ static void __exit zfcp_module_exit(void);
int zfcp_reboot_handler(struct notifier_block *, unsigned long, void *); int zfcp_reboot_handler(struct notifier_block *, unsigned long, void *);
/* FCP related */ /* FCP related */
static void zfcp_nameserver_request_handler(struct zfcp_fsf_req *); static void zfcp_ns_gid_pn_handler(unsigned long);
/* miscellaneous */ /* miscellaneous */
#ifdef ZFCP_STAT_REQSIZES #ifdef ZFCP_STAT_REQSIZES
...@@ -83,6 +87,34 @@ static int zfcp_statistics_clear(struct list_head *); ...@@ -83,6 +87,34 @@ static int zfcp_statistics_clear(struct list_head *);
static int zfcp_statistics_new(struct list_head *, u32); static int zfcp_statistics_new(struct list_head *, u32);
#endif #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 ***************************/ /*********************** KERNEL/MODULE PARAMETERS ***************************/
/* declare driver module init/cleanup functions */ /* declare driver module init/cleanup functions */
...@@ -128,7 +160,7 @@ _zfcp_hex_dump(char *addr, int count) ...@@ -128,7 +160,7 @@ _zfcp_hex_dump(char *addr, int count)
if ((i % 32) == 31) if ((i % 32) == 31)
printk("\n"); printk("\n");
} }
if ((i % 32) != 31) if (((i-1) % 32) != 31)
printk("\n"); printk("\n");
} }
...@@ -137,7 +169,6 @@ _zfcp_hex_dump(char *addr, int count) ...@@ -137,7 +169,6 @@ _zfcp_hex_dump(char *addr, int count)
/****************************************************************/ /****************************************************************/
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_OTHER #define ZFCP_LOG_AREA ZFCP_LOG_AREA_OTHER
#define ZFCP_LOG_AREA_PREFIX ZFCP_LOG_AREA_PREFIX_OTHER
#ifdef ZFCP_STAT_REQSIZES #ifdef ZFCP_STAT_REQSIZES
...@@ -242,7 +273,7 @@ zfcp_cmd_dbf_event_fsf(const char *text, struct zfcp_fsf_req *fsf_req, ...@@ -242,7 +273,7 @@ zfcp_cmd_dbf_event_fsf(const char *text, struct zfcp_fsf_req *fsf_req,
{ {
#ifdef ZFCP_DEBUG_COMMANDS #ifdef ZFCP_DEBUG_COMMANDS
struct zfcp_adapter *adapter = fsf_req->adapter; struct zfcp_adapter *adapter = fsf_req->adapter;
Scsi_Cmnd *scsi_cmnd; struct scsi_cmnd *scsi_cmnd;
int level = 3; int level = 3;
int i; int i;
unsigned long flags; unsigned long flags;
...@@ -258,6 +289,8 @@ zfcp_cmd_dbf_event_fsf(const char *text, struct zfcp_fsf_req *fsf_req, ...@@ -258,6 +289,8 @@ zfcp_cmd_dbf_event_fsf(const char *text, struct zfcp_fsf_req *fsf_req,
sizeof (u32)); sizeof (u32));
debug_event(adapter->cmd_dbf, level, &scsi_cmnd, debug_event(adapter->cmd_dbf, level, &scsi_cmnd,
sizeof (unsigned long)); 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) for (i = 0; i < add_length; i += ZFCP_CMD_DBF_LENGTH)
debug_event(adapter->cmd_dbf, debug_event(adapter->cmd_dbf,
level, level,
...@@ -268,8 +301,10 @@ zfcp_cmd_dbf_event_fsf(const char *text, struct zfcp_fsf_req *fsf_req, ...@@ -268,8 +301,10 @@ zfcp_cmd_dbf_event_fsf(const char *text, struct zfcp_fsf_req *fsf_req,
#endif #endif
} }
/* XXX additionally log unit if available */
/* ---> introduce new parameter for unit, see 2.4 code */
void 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 #ifdef ZFCP_DEBUG_COMMANDS
struct zfcp_adapter *adapter; struct zfcp_adapter *adapter;
...@@ -287,6 +322,8 @@ zfcp_cmd_dbf_event_scsi(const char *text, Scsi_Cmnd * scsi_cmnd) ...@@ -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->result, sizeof (u32));
debug_event(adapter->cmd_dbf, level, &scsi_cmnd, debug_event(adapter->cmd_dbf, level, &scsi_cmnd,
sizeof (unsigned long)); 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)) { if (likely(fsf_req)) {
debug_event(adapter->cmd_dbf, level, &fsf_req, debug_event(adapter->cmd_dbf, level, &fsf_req,
sizeof (unsigned long)); sizeof (unsigned long));
...@@ -359,13 +396,12 @@ static void __init ...@@ -359,13 +396,12 @@ static void __init
zfcp_init_device_configure(void) zfcp_init_device_configure(void)
{ {
int found = 0; int found = 0;
unsigned long flags;
struct zfcp_adapter *adapter; struct zfcp_adapter *adapter;
struct zfcp_port *port; struct zfcp_port *port;
struct zfcp_unit *unit; struct zfcp_unit *unit;
down(&zfcp_data.config_sema); 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) list_for_each_entry(adapter, &zfcp_data.adapter_list_head, list)
if (strcmp(zfcp_data.init_busid, if (strcmp(zfcp_data.init_busid,
zfcp_get_busid_by_adapter(adapter)) == 0) { zfcp_get_busid_by_adapter(adapter)) == 0) {
...@@ -373,7 +409,7 @@ zfcp_init_device_configure(void) ...@@ -373,7 +409,7 @@ zfcp_init_device_configure(void)
found = 1; found = 1;
break; break;
} }
read_unlock_irqrestore(&zfcp_data.config_lock, flags); read_unlock_irq(&zfcp_data.config_lock);
if (!found) if (!found)
goto out_adapter; goto out_adapter;
port = zfcp_port_enqueue(adapter, zfcp_data.init_wwpn, 0); port = zfcp_port_enqueue(adapter, zfcp_data.init_wwpn, 0);
...@@ -419,6 +455,28 @@ zfcp_module_init(void) ...@@ -419,6 +455,28 @@ zfcp_module_init(void)
zfcp_statistics_init_all(); zfcp_statistics_init_all();
#endif #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 */ /* Initialise proc semaphores */
sema_init(&zfcp_data.config_sema, 1); sema_init(&zfcp_data.config_sema, 1);
...@@ -445,6 +503,12 @@ zfcp_module_init(void) ...@@ -445,6 +503,12 @@ zfcp_module_init(void)
out_ccw_register: out_ccw_register:
unregister_reboot_notifier(&zfcp_data.reboot_notifier); 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 #ifdef ZFCP_STAT_REQSIZES
zfcp_statistics_clear_all(); zfcp_statistics_clear_all();
#endif #endif
...@@ -458,6 +522,10 @@ zfcp_module_exit(void) ...@@ -458,6 +522,10 @@ zfcp_module_exit(void)
{ {
unregister_reboot_notifier(&zfcp_data.reboot_notifier); unregister_reboot_notifier(&zfcp_data.reboot_notifier);
zfcp_ccw_unregister(); zfcp_ccw_unregister();
misc_deregister(&zfcp_cfdc_misc);
#ifdef CONFIG_S390_SUPPORT
unregister_ioctl32_conversion(zfcp_ioctl_trans.cmd);
#endif
#ifdef ZFCP_STAT_REQSIZES #ifdef ZFCP_STAT_REQSIZES
zfcp_statistics_clear_all(); zfcp_statistics_clear_all();
#endif #endif
...@@ -480,15 +548,372 @@ zfcp_reboot_handler(struct notifier_block *notifier, unsigned long code, ...@@ -480,15 +548,372 @@ zfcp_reboot_handler(struct notifier_block *notifier, unsigned long code,
return NOTIFY_DONE; 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
#undef ZFCP_LOG_AREA_PREFIX
/****************************************************************/ /****************************************************************/
/****** Functions for configuration/set-up of structures ********/ /****** Functions for configuration/set-up of structures ********/
/****************************************************************/ /****************************************************************/
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG #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 * 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) ...@@ -684,83 +1109,92 @@ zfcp_mempool_free(void *element, void *size)
static int static int
zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter) zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter)
{ {
adapter->pool.erp_fsf = mempool_create( adapter->pool.fsf_req_erp =
1, mempool_create(ZFCP_POOL_FSF_REQ_ERP_NR,
zfcp_mempool_alloc, zfcp_mempool_alloc, zfcp_mempool_free, (void *)
zfcp_mempool_free, sizeof(struct zfcp_fsf_req_pool_element));
(void *) ZFCP_QTCB_AND_REQ_SIZE);
if (!adapter->pool.erp_fsf) { if (NULL == adapter->pool.fsf_req_erp) {
ZFCP_LOG_INFO ZFCP_LOG_INFO("error: pool allocation failed (fsf_req_erp)\n");
("error: FCP command buffer pool allocation failed\n");
return -ENOMEM; return -ENOMEM;
} }
adapter->pool.nameserver = mempool_create( adapter->pool.fsf_req_scsi =
1, mempool_create(ZFCP_POOL_FSF_REQ_SCSI_NR,
zfcp_mempool_alloc, zfcp_mempool_alloc, zfcp_mempool_free, (void *)
zfcp_mempool_free, sizeof(struct zfcp_fsf_req_pool_element));
(void *) (2 * sizeof (struct fc_ct_iu)));
if (!adapter->pool.nameserver) { if (NULL == adapter->pool.fsf_req_scsi) {
ZFCP_LOG_INFO ZFCP_LOG_INFO("error: pool allocation failed (fsf_req_scsi)\n");
("error: Nameserver buffer pool allocation failed\n");
return -ENOMEM; return -ENOMEM;
} }
adapter->pool.status_read_fsf = mempool_create( adapter->pool.fsf_req_abort =
ZFCP_STATUS_READS_RECOM, mempool_create(ZFCP_POOL_FSF_REQ_ABORT_NR,
zfcp_mempool_alloc, zfcp_mempool_alloc, zfcp_mempool_free, (void *)
zfcp_mempool_free, sizeof(struct zfcp_fsf_req_pool_element));
(void *) sizeof (struct zfcp_fsf_req));
if (!adapter->pool.status_read_fsf) { if (NULL == adapter->pool.fsf_req_abort) {
ZFCP_LOG_INFO ZFCP_LOG_INFO("error: pool allocation failed "
("error: Status read request pool allocation failed\n"); "(fsf_req_abort)\n");
return -ENOMEM; return -ENOMEM;
} }
adapter->pool.status_read_buf = mempool_create( adapter->pool.fsf_req_status_read =
ZFCP_STATUS_READS_RECOM, mempool_create(ZFCP_POOL_STATUS_READ_NR,
zfcp_mempool_alloc, zfcp_mempool_alloc, zfcp_mempool_free,
zfcp_mempool_free, (void *) sizeof(struct zfcp_fsf_req));
(void *) sizeof (struct fsf_status_read_buffer));
if (!adapter->pool.status_read_buf) { if (NULL == adapter->pool.fsf_req_status_read) {
ZFCP_LOG_INFO ZFCP_LOG_INFO("error: pool allocation failed "
("error: Status read buffer pool allocation failed\n"); "(fsf_req_status_read\n");
return -ENOMEM; return -ENOMEM;
} }
adapter->pool.fcp_command_fsf = mempool_create( adapter->pool.data_status_read =
1, mempool_create(ZFCP_POOL_STATUS_READ_NR,
zfcp_mempool_alloc, zfcp_mempool_alloc, zfcp_mempool_free,
zfcp_mempool_free, (void *) sizeof(struct fsf_status_read_buffer));
(void *)
ZFCP_QTCB_AND_REQ_SIZE); if (NULL == adapter->pool.data_status_read) {
if (!adapter->pool.fcp_command_fsf) { ZFCP_LOG_INFO("error: pool allocation failed "
ZFCP_LOG_INFO "(data_status_read)\n");
("error: FCP command buffer pool allocation failed\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; 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; 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 static void
zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter) zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter)
{ {
if (adapter->pool.status_read_fsf) if (adapter->pool.fsf_req_erp)
mempool_destroy(adapter->pool.status_read_fsf); mempool_destroy(adapter->pool.fsf_req_erp);
if (adapter->pool.status_read_buf) if (adapter->pool.fsf_req_scsi)
mempool_destroy(adapter->pool.status_read_buf); mempool_destroy(adapter->pool.fsf_req_scsi);
if (adapter->pool.nameserver) if (adapter->pool.fsf_req_abort)
mempool_destroy(adapter->pool.nameserver); mempool_destroy(adapter->pool.fsf_req_abort);
if (adapter->pool.erp_fsf) if (adapter->pool.fsf_req_status_read)
mempool_destroy(adapter->pool.erp_fsf); mempool_destroy(adapter->pool.fsf_req_status_read);
if (adapter->pool.fcp_command_fsf) if (adapter->pool.data_status_read)
mempool_destroy(adapter->pool.fcp_command_fsf); 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) ...@@ -859,7 +1293,7 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
#ifdef ZFCP_DEBUG_REQUESTS #ifdef ZFCP_DEBUG_REQUESTS
/* debug feature area which records fsf request sequence numbers */ /* 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)); zfcp_get_busid_by_adapter(adapter));
adapter->req_dbf = debug_register(dbf_name, adapter->req_dbf = debug_register(dbf_name,
ZFCP_REQ_DBF_INDEX, ZFCP_REQ_DBF_INDEX,
...@@ -954,15 +1388,6 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) ...@@ -954,15 +1388,6 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
debug_register_view(adapter->erp_dbf, &debug_hex_ascii_view); debug_register_view(adapter->erp_dbf, &debug_hex_ascii_view);
debug_set_level(adapter->erp_dbf, ZFCP_ERP_DBF_LEVEL); 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 */ /* put allocated adapter at list tail */
write_lock_irq(&zfcp_data.config_lock); write_lock_irq(&zfcp_data.config_lock);
atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status);
...@@ -973,15 +1398,6 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) ...@@ -973,15 +1398,6 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
goto out; 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: failed_erp_dbf:
#ifdef ZFCP_DEBUG_INCOMING_ELS #ifdef ZFCP_DEBUG_INCOMING_ELS
debug_unregister(adapter->in_els_dbf); debug_unregister(adapter->in_els_dbf);
...@@ -1007,7 +1423,11 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) ...@@ -1007,7 +1423,11 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
dev_set_drvdata(&ccw_device->dev, NULL); dev_set_drvdata(&ccw_device->dev, NULL);
failed_low_mem_buffers: failed_low_mem_buffers:
zfcp_free_low_mem_buffers(adapter); 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: qdio_allocate_failed:
zfcp_qdio_free_queues(adapter); zfcp_qdio_free_queues(adapter);
queues_alloc_failed: queues_alloc_failed:
...@@ -1060,9 +1480,7 @@ zfcp_adapter_dequeue(struct zfcp_adapter *adapter) ...@@ -1060,9 +1480,7 @@ zfcp_adapter_dequeue(struct zfcp_adapter *adapter)
"%i adapters still in list\n", "%i adapters still in list\n",
(unsigned long) adapter, zfcp_data.adapters); (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) if (retval)
ZFCP_LOG_NORMAL ZFCP_LOG_NORMAL
("bug: could not free memory used by data transfer " ("bug: could not free memory used by data transfer "
...@@ -1261,14 +1679,12 @@ zfcp_nameserver_enqueue(struct zfcp_adapter *adapter) ...@@ -1261,14 +1679,12 @@ zfcp_nameserver_enqueue(struct zfcp_adapter *adapter)
} }
#undef ZFCP_LOG_AREA #undef ZFCP_LOG_AREA
#undef ZFCP_LOG_AREA_PREFIX
/****************************************************************/ /****************************************************************/
/******* Fibre Channel Standard related Functions **************/ /******* Fibre Channel Standard related Functions **************/
/****************************************************************/ /****************************************************************/
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_FC #define ZFCP_LOG_AREA ZFCP_LOG_AREA_FC
#define ZFCP_LOG_AREA_PREFIX ZFCP_LOG_AREA_PREFIX_FC
void void
zfcp_fsf_incoming_els_rscn(struct zfcp_adapter *adapter, zfcp_fsf_incoming_els_rscn(struct zfcp_adapter *adapter,
...@@ -1361,7 +1777,7 @@ 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); "0x%Lx.\n", port->wwpn);
debug_text_event(adapter->erp_dbf, 1, debug_text_event(adapter->erp_dbf, 1,
"unsol_els_rscnk:"); "unsol_els_rscnk:");
zfcp_erp_port_reopen(port, 0); zfcp_test_link(port);
} }
} }
read_unlock_irqrestore(&zfcp_data.config_lock, flags); read_unlock_irqrestore(&zfcp_data.config_lock, flags);
...@@ -1462,222 +1878,180 @@ zfcp_fsf_incoming_els(struct zfcp_fsf_req *fsf_req) ...@@ -1462,222 +1878,180 @@ zfcp_fsf_incoming_els(struct zfcp_fsf_req *fsf_req)
zfcp_fsf_incoming_els_rscn(adapter, status_buffer); zfcp_fsf_incoming_els_rscn(adapter, status_buffer);
else else
zfcp_fsf_incoming_els_unknown(adapter, status_buffer); 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 /**
* * zfcp_gid_pn_buffers_alloc - allocate buffers for GID_PN nameserver request
* purpose: * @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
* returns:
*
* locks: fsf_request_list_lock is held when doing buffer pool
* operations
*/ */
static int 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_gid_pn_data *data;
struct zfcp_adapter *adapter = fsf_req->adapter;
int retval = 0;
data->outbuf = kmalloc(2 * sizeof (struct fc_ct_iu), GFP_ATOMIC); if (pool != NULL) {
if (data->outbuf) { data = mempool_alloc(pool, GFP_ATOMIC);
memset(data->outbuf, 0, 2 * sizeof (struct fc_ct_iu)); if (likely(data != NULL)) {
data->ct.pool = pool;
}
} else { } else {
ZFCP_LOG_DEBUG("Out of memory. Could not allocate at " data = kmalloc(sizeof(struct zfcp_gid_pn_data), GFP_ATOMIC);
"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;
} }
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); memset(data, 0, sizeof(*data));
data->inbuf = data->ct.req = &data->req;
(char *) ((unsigned long) data->outbuf + sizeof (struct fc_ct_iu)); data->ct.resp = &data->resp;
out: data->ct.req_count = data->ct.resp_count = 1;
return retval; 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 * 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
* purpose:
*
* returns:
*/ */
int static void
zfcp_nameserver_request(struct zfcp_erp_action *erp_action) zfcp_gid_pn_buffers_free(struct zfcp_gid_pn_data *gid_pn)
{ {
int retval = 0; if ((gid_pn->ct.pool != 0)) {
struct fc_ct_iu *fc_ct_iu; mempool_free(gid_pn, gid_pn->ct.pool);
unsigned long lock_flags; } else {
kfree(gid_pn);
/* 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;
}
/* 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; goto out;
}
failed_send: /* setup nameserver request */
zfcp_release_nameserver_buffers(erp_action->fsf_req); 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_gid_pn_buffers_free(gid_pn);
zfcp_fsf_req_free(erp_action->fsf_req); }
erp_action->fsf_req = NULL;
failed_req:
out: out:
write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock, return ret;
lock_flags);
return retval;
} }
/* /**
* function: zfcp_nameserver_request_handler * zfcp_ns_gid_pn_handler - handler for GID_PN nameserver request
* * @data: unsigned long, contains pointer to struct zfcp_gid_pn_data
* purpose:
*
* returns:
*/ */
static void static void zfcp_ns_gid_pn_handler(unsigned long data)
zfcp_nameserver_request_handler(struct zfcp_fsf_req *fsf_req)
{ {
struct fc_ct_iu *fc_ct_iu_resp = struct zfcp_port *port;
(struct fc_ct_iu *) (fsf_req->data.send_generic.inbuf); struct zfcp_send_ct *ct;
struct fc_ct_iu *fc_ct_iu_req = struct ct_iu_gid_pn_req *ct_iu_req;
(struct fc_ct_iu *) (fsf_req->data.send_generic.outbuf); struct ct_iu_gid_pn_resp *ct_iu_resp;
struct zfcp_port *port = struct zfcp_gid_pn_data *gid_pn;
(struct zfcp_port *) fsf_req->data.send_generic.handler_data;
if (fc_ct_iu_resp->revision != ZFCP_CT_REVISION) 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; 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; 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; goto failed;
if (fc_ct_iu_resp->options != ZFCP_CT_SYNCHRONOUS) if (ct_iu_resp->header.options != ZFCP_CT_SYNCHRONOUS)
goto failed; 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 */ /* FIXME: do we need some specific erp entry points */
atomic_set_mask(ZFCP_STATUS_PORT_INVALID_WWPN, &port->status); atomic_set_mask(ZFCP_STATUS_PORT_INVALID_WWPN, &port->status);
goto failed; goto failed;
} }
/* paranoia */ /* paranoia */
if (fc_ct_iu_req->data.wwpn != port->wwpn) { if (ct_iu_req->wwpn != port->wwpn) {
ZFCP_LOG_NORMAL("bug: Port WWPN returned by nameserver lookup " ZFCP_LOG_NORMAL(
"does not correspond to " "bug: Port WWPN returned by nameserver lookup "
"the expected value on the adapter %s. " "does not correspond to the expected value "
"(debug info 0x%Lx, 0x%Lx)\n", "(adapter: %s, debug info: 0x%016Lx, 0x%016Lx)\n",
zfcp_get_busid_by_port(port), zfcp_get_busid_by_port(port), port->wwpn,
port->wwpn, fc_ct_iu_req->data.wwpn); ct_iu_req->wwpn);
goto failed; goto failed;
} }
/* looks like a valid d_id */ /* 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); 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_LOG_DEBUG("busid %s: WWPN=0x%Lx ---> D_ID=0x%6.6x\n",
zfcp_get_busid_by_port(port), zfcp_get_busid_by_port(port),
port->wwpn, (unsigned int) port->d_id); port->wwpn, (unsigned int) port->d_id);
goto out; goto out;
failed: failed:
ZFCP_LOG_NORMAL("warning: WWPN 0x%Lx not found by nameserver lookup " 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)); port->wwpn, zfcp_get_busid_by_port(port));
ZFCP_LOG_DEBUG("CT IUs do not match:\n"); ZFCP_LOG_DEBUG("CT IUs do not match:\n");
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, (char *) ct_iu_req,
(char *) fc_ct_iu_req, sizeof (struct fc_ct_iu)); sizeof(struct ct_iu_gid_pn_req));
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, (char *) ct_iu_resp,
(char *) fc_ct_iu_resp, sizeof (struct fc_ct_iu)); sizeof(struct ct_iu_gid_pn_resp));
out: out:
zfcp_release_nameserver_buffers(fsf_req); zfcp_gid_pn_buffers_free(gid_pn);
return;
} }
#undef ZFCP_LOG_AREA #undef ZFCP_LOG_AREA
#undef ZFCP_LOG_AREA_PREFIX
...@@ -5,7 +5,8 @@ ...@@ -5,7 +5,8 @@
* *
* CCW driver related routines * CCW driver related routines
* *
* Copyright (C) 2003 IBM Entwicklung GmbH, IBM Corporation * (C) Copyright IBM Corp. 2003, 2004
*
* Authors: * Authors:
* Martin Peschke <mpeschke@de.ibm.com> * Martin Peschke <mpeschke@de.ibm.com>
* Heiko Carstens <heiko.carstens@de.ibm.com> * Heiko Carstens <heiko.carstens@de.ibm.com>
...@@ -25,7 +26,7 @@ ...@@ -25,7 +26,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * 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/init.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -34,18 +35,22 @@ ...@@ -34,18 +35,22 @@
#include "zfcp_def.h" #include "zfcp_def.h"
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG #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 int zfcp_ccw_probe(struct ccw_device *);
static void zfcp_ccw_remove(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_online(struct ccw_device *);
static int zfcp_ccw_set_offline(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[] = { static struct ccw_device_id zfcp_ccw_device_id[] = {
{CCW_DEVICE_DEVTYPE(ZFCP_CONTROL_UNIT_TYPE, {CCW_DEVICE_DEVTYPE(ZFCP_CONTROL_UNIT_TYPE,
ZFCP_CONTROL_UNIT_MODEL, ZFCP_CONTROL_UNIT_MODEL,
ZFCP_DEVICE_TYPE, ZFCP_DEVICE_TYPE,
ZFCP_DEVICE_MODEL)}, 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 = { ...@@ -56,6 +61,7 @@ static struct ccw_driver zfcp_ccw_driver = {
.remove = zfcp_ccw_remove, .remove = zfcp_ccw_remove,
.set_online = zfcp_ccw_set_online, .set_online = zfcp_ccw_set_online,
.set_offline = zfcp_ccw_set_offline, .set_offline = zfcp_ccw_set_offline,
.notify = zfcp_ccw_notify,
}; };
MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id); MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id);
...@@ -80,6 +86,9 @@ zfcp_ccw_probe(struct ccw_device *ccw_device) ...@@ -80,6 +86,9 @@ zfcp_ccw_probe(struct ccw_device *ccw_device)
adapter = zfcp_adapter_enqueue(ccw_device); adapter = zfcp_adapter_enqueue(ccw_device);
if (!adapter) if (!adapter)
retval = -EINVAL; retval = -EINVAL;
else
ZFCP_LOG_DEBUG("Probed adapter %s\n",
zfcp_get_busid_by_adapter(adapter));
up(&zfcp_data.config_sema); up(&zfcp_data.config_sema);
return retval; return retval;
} }
...@@ -104,6 +113,8 @@ zfcp_ccw_remove(struct ccw_device *ccw_device) ...@@ -104,6 +113,8 @@ zfcp_ccw_remove(struct ccw_device *ccw_device)
down(&zfcp_data.config_sema); down(&zfcp_data.config_sema);
adapter = dev_get_drvdata(&ccw_device->dev); 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); write_lock_irq(&zfcp_data.config_lock);
list_for_each_entry_safe(port, p, &adapter->port_list_head, list) { list_for_each_entry_safe(port, p, &adapter->port_list_head, list) {
list_for_each_entry_safe(unit, u, &port->unit_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) ...@@ -152,13 +163,26 @@ zfcp_ccw_set_online(struct ccw_device *ccw_device)
down(&zfcp_data.config_sema); down(&zfcp_data.config_sema);
adapter = dev_get_drvdata(&ccw_device->dev); 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); retval = zfcp_adapter_scsi_register(adapter);
if (retval) if (retval)
goto out; goto out_scsi_register;
zfcp_erp_modify_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING, zfcp_erp_modify_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING,
ZFCP_SET); ZFCP_SET);
zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED); zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED);
zfcp_erp_wait(adapter); zfcp_erp_wait(adapter);
goto out;
out_scsi_register:
zfcp_erp_thread_kill(adapter);
out: out:
up(&zfcp_data.config_sema); up(&zfcp_data.config_sema);
return retval; return retval;
...@@ -183,10 +207,49 @@ zfcp_ccw_set_offline(struct ccw_device *ccw_device) ...@@ -183,10 +207,49 @@ zfcp_ccw_set_offline(struct ccw_device *ccw_device)
zfcp_erp_adapter_shutdown(adapter, 0); zfcp_erp_adapter_shutdown(adapter, 0);
zfcp_erp_wait(adapter); zfcp_erp_wait(adapter);
zfcp_adapter_scsi_unregister(adapter); zfcp_adapter_scsi_unregister(adapter);
zfcp_erp_thread_kill(adapter);
up(&zfcp_data.config_sema); up(&zfcp_data.config_sema);
return 0; 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 * zfcp_ccw_register - ccw register function
* *
...@@ -222,4 +285,3 @@ zfcp_ccw_unregister(void) ...@@ -222,4 +285,3 @@ zfcp_ccw_unregister(void)
} }
#undef ZFCP_LOG_AREA #undef ZFCP_LOG_AREA
#undef ZFCP_LOG_AREA_PREFIX
...@@ -4,11 +4,12 @@ ...@@ -4,11 +4,12 @@
* *
* FCP adapter driver for IBM eServer zSeries * 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> * Author(s): Martin Peschke <mpeschke@de.ibm.com>
* Raimund Schroeder <raimund.schroeder@de.ibm.com> * Raimund Schroeder <raimund.schroeder@de.ibm.com>
* Aron Zeh <arzeh@de.ibm.com> * Aron Zeh
* Wolfgang Taphorn <taphorn@de.ibm.com> * Wolfgang Taphorn
* Stefan Bader <stefan.bader@de.ibm.com> * Stefan Bader <stefan.bader@de.ibm.com>
* Heiko Carstens <heiko.carstens@de.ibm.com> * Heiko Carstens <heiko.carstens@de.ibm.com>
* *
...@@ -32,19 +33,29 @@ ...@@ -32,19 +33,29 @@
#define ZFCP_DEF_H #define ZFCP_DEF_H
/* this drivers version (do not edit !!! generated and updated by cvs) */ /* 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 *****************************************/ /*************************** INCLUDES *****************************************/
#include <linux/blkdev.h> #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/scsi.h"
#include "../../scsi/hosts.h"
#include "../../fc4/fc.h" #include "../../fc4/fc.h"
#include "zfcp_fsf.h" /* FSF SW Interface */ #include "zfcp_fsf.h" /* FSF SW Interface */
#include <asm/ccwdev.h> #include <asm/ccwdev.h>
#include <asm/qdio.h> #include <asm/qdio.h>
#include <asm/debug.h> #include <asm/debug.h>
#include <asm/ebcdic.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/mempool.h>
#include <linux/ioctl.h>
#ifdef CONFIG_S390_SUPPORT
#include <linux/ioctl32.h>
#endif
/************************ DEBUG FLAGS *****************************************/ /************************ DEBUG FLAGS *****************************************/
...@@ -56,6 +67,24 @@ ...@@ -56,6 +67,24 @@
#define ZFCP_STAT_REQSIZES #define ZFCP_STAT_REQSIZES
#define ZFCP_STAT_QUEUES #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 *********************************/ /********************* SCSI SPECIFIC DEFINES *********************************/
/* 32 bit for SCSI ID and LUN as long as the SCSI stack uses this type */ /* 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; ...@@ -64,7 +93,6 @@ typedef u32 scsi_lun_t;
#define ZFCP_ERP_SCSI_LOW_MEM_TIMEOUT (100*HZ) #define ZFCP_ERP_SCSI_LOW_MEM_TIMEOUT (100*HZ)
#define ZFCP_SCSI_ER_TIMEOUT (100*HZ) #define ZFCP_SCSI_ER_TIMEOUT (100*HZ)
#define ZFCP_SCSI_HOST_FLUSH_TIMEOUT (1*HZ)
/********************* CIO/QDIO SPECIFIC DEFINES *****************************/ /********************* CIO/QDIO SPECIFIC DEFINES *****************************/
...@@ -73,9 +101,12 @@ typedef u32 scsi_lun_t; ...@@ -73,9 +101,12 @@ typedef u32 scsi_lun_t;
#define ZFCP_CONTROL_UNIT_MODEL 0x03 #define ZFCP_CONTROL_UNIT_MODEL 0x03
#define ZFCP_DEVICE_TYPE 0x1732 #define ZFCP_DEVICE_TYPE 0x1732
#define ZFCP_DEVICE_MODEL 0x03 #define ZFCP_DEVICE_MODEL 0x03
#define ZFCP_DEVICE_MODEL_PRIV 0x04
/* allow as many chained SBALs as are supported by hardware */ /* 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_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 */ /* DMQ bug workaround: don't use last SBALE */
#define ZFCP_MAX_SBALES_PER_SBAL (QDIO_MAX_ELEMENTS_PER_BUFFER - 1) #define ZFCP_MAX_SBALES_PER_SBAL (QDIO_MAX_ELEMENTS_PER_BUFFER - 1)
...@@ -115,9 +146,6 @@ typedef u32 scsi_lun_t; ...@@ -115,9 +146,6 @@ typedef u32 scsi_lun_t;
#define ZFCP_EXCHANGE_CONFIG_DATA_RETRIES 6 #define ZFCP_EXCHANGE_CONFIG_DATA_RETRIES 6
#define ZFCP_EXCHANGE_CONFIG_DATA_SLEEP 50 #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 ********************/ /*************** FIBRE CHANNEL PROTOCOL SPECIFIC DEFINES ********************/
typedef unsigned long long wwn_t; typedef unsigned long long wwn_t;
...@@ -129,7 +157,8 @@ typedef unsigned int fcp_dl_t; ...@@ -129,7 +157,8 @@ typedef unsigned int fcp_dl_t;
#define ZFCP_FC_SERVICE_CLASS_DEFAULT FSF_CLASS_3 #define ZFCP_FC_SERVICE_CLASS_DEFAULT FSF_CLASS_3
/* timeout for name-server lookup (in seconds) */ /* 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 */ /* largest SCSI command we can process */
/* FCP-2 (FCP_CMND IU) allows up to (255-3+16) */ /* FCP-2 (FCP_CMND IU) allows up to (255-3+16) */
...@@ -241,33 +270,177 @@ struct fcp_logo { ...@@ -241,33 +270,177 @@ struct fcp_logo {
wwn_t nport_wwpn; wwn_t nport_wwpn;
} __attribute__((packed)); } __attribute__((packed));
struct fc_ct_iu { /*
u8 revision; /* 0x01 */ * FC-FS stuff
u8 in_id[3]; /* 0x00 */ */
u8 gs_type; /* 0xFC Directory Service */ #define R_A_TOV 10 /* seconds */
u8 gs_subtype; /* 0x02 Name Server */ #define ZFCP_ELS_TIMEOUT (2 * R_A_TOV)
u8 options; /* 0x10 synchronous/single exchange */
u8 reserved0; #define ZFCP_LS_RJT 0x01
u16 cmd_rsp_code; /* 0x0121 GID_PN */ #define ZFCP_LS_ACC 0x02
u16 max_res_size; /* <= (4096 - 16) / 4 */ #define ZFCP_LS_RTV 0x0E
u8 reserved1; #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;
u8 reason_code_expl; u8 reason_expl;
u8 vendor_unique; 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; wwn_t wwpn;
fc_id_t d_id; wwn_t wwnn;
} data; 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)); } __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_REVISION 0x01
#define ZFCP_CT_DIRECTORY_SERVICE 0xFC #define ZFCP_CT_DIRECTORY_SERVICE 0xFC
#define ZFCP_CT_NAME_SERVER 0x02 #define ZFCP_CT_NAME_SERVER 0x02
#define ZFCP_CT_SYNCHRONOUS 0x00 #define ZFCP_CT_SYNCHRONOUS 0x00
#define ZFCP_CT_GID_PN 0x0121 #define ZFCP_CT_GID_PN 0x0121
#define ZFCP_CT_GA_NXT 0x0100
#define ZFCP_CT_MAX_SIZE 0x1020 #define ZFCP_CT_MAX_SIZE 0x1020
#define ZFCP_CT_ACCEPT 0x8002 #define ZFCP_CT_ACCEPT 0x8002
/*
* FC-GS-4 stuff
*/
#define ZFCP_CT_TIMEOUT (3 * R_A_TOV)
/***************** S390 DEBUG FEATURE SPECIFIC DEFINES ***********************/ /***************** S390 DEBUG FEATURE SPECIFIC DEFINES ***********************/
/* debug feature entries per adapter */ /* debug feature entries per adapter */
...@@ -333,16 +506,6 @@ struct fc_ct_iu { ...@@ -333,16 +506,6 @@ struct fc_ct_iu {
#define ZFCP_LOG_LEVEL_DEBUG 2 #define ZFCP_LOG_LEVEL_DEBUG 2
#define ZFCP_LOG_LEVEL_TRACE 3 #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 * this allows removal of logging code by the preprocessor
* (the most detailed log level still to be compiled in is specified, * (the most detailed log level still to be compiled in is specified,
...@@ -350,93 +513,75 @@ struct fc_ct_iu { ...@@ -350,93 +513,75 @@ struct fc_ct_iu {
*/ */
#define ZFCP_LOG_LEVEL_LIMIT ZFCP_LOG_LEVEL_TRACE #define ZFCP_LOG_LEVEL_LIMIT ZFCP_LOG_LEVEL_TRACE
/* positional "loglevel" nibble assignment */ /* get "loglevel" nibble assignment */
#define ZFCP_LOG_VALUE(zfcp_lognibble) \ #define ZFCP_GET_LOG_VALUE(zfcp_lognibble) \
((atomic_read(&zfcp_data.loglevel) >> (zfcp_lognibble<<2)) & 0xF) ((atomic_read(&zfcp_data.loglevel) >> (zfcp_lognibble<<2)) & 0xF)
#define ZFCP_LOG_VALUE_OTHER ZFCP_LOG_VALUE(ZFCP_LOG_AREA_OTHER) /* set "loglevel" nibble */
#define ZFCP_LOG_VALUE_SCSI ZFCP_LOG_VALUE(ZFCP_LOG_AREA_SCSI) #define ZFCP_SET_LOG_NIBBLE(value, zfcp_lognibble) \
#define ZFCP_LOG_VALUE_FSF ZFCP_LOG_VALUE(ZFCP_LOG_AREA_FSF) (value << (zfcp_lognibble << 2))
#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)
/* all log-level defaults are combined to generate initial log-level */ /* all log-level defaults are combined to generate initial log-level */
#define ZFCP_LOG_LEVEL_DEFAULTS \ #define ZFCP_LOG_LEVEL_DEFAULTS \
((ZFCP_LOG_LEVEL_DEFAULT_OTHER << (ZFCP_LOG_AREA_OTHER<<2)) | \ (ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_INFO, ZFCP_LOG_AREA_OTHER) | \
(ZFCP_LOG_LEVEL_DEFAULT_SCSI << (ZFCP_LOG_AREA_SCSI<<2)) | \ ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_INFO, ZFCP_LOG_AREA_SCSI) | \
(ZFCP_LOG_LEVEL_DEFAULT_FSF << (ZFCP_LOG_AREA_FSF<<2)) | \ ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_INFO, ZFCP_LOG_AREA_FSF) | \
(ZFCP_LOG_LEVEL_DEFAULT_CONFIG << (ZFCP_LOG_AREA_CONFIG<<2)) | \ ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_INFO, ZFCP_LOG_AREA_CONFIG) | \
(ZFCP_LOG_LEVEL_DEFAULT_CIO << (ZFCP_LOG_AREA_CIO<<2)) | \ ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_INFO, ZFCP_LOG_AREA_CIO) | \
(ZFCP_LOG_LEVEL_DEFAULT_QDIO << (ZFCP_LOG_AREA_QDIO<<2)) | \ ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_INFO, ZFCP_LOG_AREA_QDIO) | \
(ZFCP_LOG_LEVEL_DEFAULT_ERP << (ZFCP_LOG_AREA_ERP<<2)) | \ ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_INFO, ZFCP_LOG_AREA_ERP) | \
(ZFCP_LOG_LEVEL_DEFAULT_FC << (ZFCP_LOG_AREA_FC<<2))) ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_INFO, ZFCP_LOG_AREA_FC))
/* 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: "
/* check whether we have the right level for logging */ /* 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 /* logging routine for zfcp */
* message. This holds true even for printks from within this module. #define _ZFCP_LOG(fmt, args...) \
* In any case there should only be a small readability hit, however. printk(KERN_ERR ZFCP_NAME": %s(%d): " fmt, __FUNCTION__, \
*/ __LINE__ , ##args);
#define _ZFCP_LOG(m...) \
{ \
printk( "%s%s: ", \
ZFCP_LOG_PREFIX ZFCP_LOG_AREA_PREFIX, \
__FUNCTION__); \
printk(m); \
}
#define ZFCP_LOG(ll, m...) \ #define ZFCP_LOG(level, fmt, args...) \
if (ZFCP_LOG_CHECK(ll)) \ if (ZFCP_LOG_CHECK(level)) \
_ZFCP_LOG(m) _ZFCP_LOG(fmt , ##args)
#if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_NORMAL #if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_NORMAL
#define ZFCP_LOG_NORMAL(m...) # define ZFCP_LOG_NORMAL(fmt, args...)
#else /* ZFCP_LOG_LEVEL_LIMIT >= ZFCP_LOG_LEVEL_NORMAL */ #else
#define ZFCP_LOG_NORMAL(m...) ZFCP_LOG(ZFCP_LOG_LEVEL_NORMAL, m) # define ZFCP_LOG_NORMAL(fmt, args...) \
if (ZFCP_LOG_CHECK(ZFCP_LOG_LEVEL_NORMAL)) \
printk(KERN_ERR ZFCP_NAME": " fmt , ##args);
#endif #endif
#if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_INFO #if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_INFO
#define ZFCP_LOG_INFO(m...) # define ZFCP_LOG_INFO(fmt, args...)
#else /* ZFCP_LOG_LEVEL_LIMIT >= ZFCP_LOG_LEVEL_INFO */ #else
#define ZFCP_LOG_INFO(m...) ZFCP_LOG(ZFCP_LOG_LEVEL_INFO, m) # define ZFCP_LOG_INFO(fmt, args...) \
if (ZFCP_LOG_CHECK(ZFCP_LOG_LEVEL_INFO)) \
printk(KERN_ERR ZFCP_NAME": " fmt , ##args);
#endif #endif
#if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_DEBUG #if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_DEBUG
#define ZFCP_LOG_DEBUG(m...) # define ZFCP_LOG_DEBUG(fmt, args...)
#else /* ZFCP_LOG_LEVEL_LIMIT >= ZFCP_LOG_LEVEL_DEBUG */ #else
#define ZFCP_LOG_DEBUG(m...) ZFCP_LOG(ZFCP_LOG_LEVEL_DEBUG, m) # define ZFCP_LOG_DEBUG(fmt, args...) \
ZFCP_LOG(ZFCP_LOG_LEVEL_DEBUG, fmt , ##args)
#endif #endif
#if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_TRACE #if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_TRACE
#define ZFCP_LOG_TRACE(m...) # define ZFCP_LOG_TRACE(fmt, args...)
#else /* ZFCP_LOG_LEVEL_LIMIT >= ZFCP_LOG_LEVEL_TRACE */ #else
#define ZFCP_LOG_TRACE(m...) ZFCP_LOG(ZFCP_LOG_LEVEL_TRACE, m) # define ZFCP_LOG_TRACE(fmt, args...) \
ZFCP_LOG(ZFCP_LOG_LEVEL_TRACE, fmt , ##args)
#endif #endif
#ifdef ZFCP_PRINT_FLAGS #ifndef ZFCP_PRINT_FLAGS
extern u32 flags_dump; # define ZFCP_LOG_FLAGS(level, fmt, args...)
#define ZFCP_LOG_FLAGS(ll, m...) \
if (ll<=flags_dump) \
_ZFCP_LOG(m)
#else #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 #endif
/*************** ADAPTER/PORT/UNIT AND FSF_REQ STATUS FLAGS ******************/ /*************** ADAPTER/PORT/UNIT AND FSF_REQ STATUS FLAGS ******************/
...@@ -506,19 +651,19 @@ extern u32 flags_dump; ...@@ -506,19 +651,19 @@ extern u32 flags_dump;
#define ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP 0x00000400 #define ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP 0x00000400
#define ZFCP_STATUS_FSFREQ_RETRY 0x00000800 #define ZFCP_STATUS_FSFREQ_RETRY 0x00000800
#define ZFCP_STATUS_FSFREQ_DISMISSED 0x00001000 #define ZFCP_STATUS_FSFREQ_DISMISSED 0x00001000
#define ZFCP_STATUS_FSFREQ_POOLBUF 0x00002000
/*********************** ERROR RECOVERY PROCEDURE DEFINES ********************/ /*********************** ERROR RECOVERY PROCEDURE DEFINES ********************/
#define ZFCP_MAX_ERPS 3 #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_ERP_MEMWAIT_TIMEOUT HZ
#define ZFCP_STATUS_ERP_TIMEDOUT 0x10000000 #define ZFCP_STATUS_ERP_TIMEDOUT 0x10000000
#define ZFCP_STATUS_ERP_CLOSE_ONLY 0x01000000 #define ZFCP_STATUS_ERP_CLOSE_ONLY 0x01000000
#define ZFCP_STATUS_ERP_DISMISSING 0x00100000 #define ZFCP_STATUS_ERP_DISMISSING 0x00100000
#define ZFCP_STATUS_ERP_DISMISSED 0x00200000 #define ZFCP_STATUS_ERP_DISMISSED 0x00200000
#define ZFCP_STATUS_ERP_LOWMEM 0x00400000
#define ZFCP_ERP_STEP_UNINITIALIZED 0x00000000 #define ZFCP_ERP_STEP_UNINITIALIZED 0x00000000
#define ZFCP_ERP_STEP_FSF_XCONFIG 0x00000001 #define ZFCP_ERP_STEP_FSF_XCONFIG 0x00000001
...@@ -546,19 +691,55 @@ extern u32 flags_dump; ...@@ -546,19 +691,55 @@ extern u32 flags_dump;
#define ZFCP_ERP_DISMISSED 0x4 #define ZFCP_ERP_DISMISSED 0x4
#define ZFCP_ERP_NOMEM 0x5 #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; 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 { struct zfcp_adapter_mempool {
mempool_t *status_read_fsf; mempool_t *fsf_req_erp;
mempool_t *status_read_buf; mempool_t *fsf_req_scsi;
mempool_t *nameserver; mempool_t *fsf_req_abort;
mempool_t *erp_fsf; mempool_t *fsf_req_status_read;
mempool_t *fcp_command_fsf; mempool_t *data_status_read;
struct timer_list fcp_command_fsf_timer; mempool_t *data_gid_pn;
}; };
struct zfcp_exchange_config_data{ struct zfcp_exchange_config_data{
...@@ -587,7 +768,7 @@ struct zfcp_close_physical_port { ...@@ -587,7 +768,7 @@ struct zfcp_close_physical_port {
struct zfcp_send_fcp_command_task { struct zfcp_send_fcp_command_task {
struct zfcp_fsf_req *fsf_req; struct zfcp_fsf_req *fsf_req;
struct zfcp_unit *unit; struct zfcp_unit *unit;
Scsi_Cmnd *scsi_cmnd; struct scsi_cmnd *scsi_cmnd;
unsigned long start_jiffies; unsigned long start_jiffies;
}; };
...@@ -600,20 +781,119 @@ struct zfcp_abort_fcp_command { ...@@ -600,20 +781,119 @@ struct zfcp_abort_fcp_command {
struct zfcp_unit *unit; 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 zfcp_port *port;
char *outbuf; struct scatterlist *req;
char *inbuf; struct scatterlist *resp;
int outbuf_length; unsigned int req_count;
int inbuf_length; unsigned int resp_count;
zfcp_send_generic_handler_t *handler; zfcp_send_ct_handler_t handler;
unsigned long handler_data; 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;
};
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 zfcp_status_read {
struct fsf_status_read_buffer *buffer; struct fsf_status_read_buffer *buffer;
}; };
struct zfcp_fsf_done {
struct completion *complete;
int status;
};
/* request specific data */ /* request specific data */
union zfcp_req_data { union zfcp_req_data {
struct zfcp_exchange_config_data exchange_config_data; struct zfcp_exchange_config_data exchange_config_data;
...@@ -626,7 +906,8 @@ union zfcp_req_data { ...@@ -626,7 +906,8 @@ union zfcp_req_data {
struct zfcp_send_fcp_command_task_management struct zfcp_send_fcp_command_task_management
send_fcp_command_task_management; send_fcp_command_task_management;
struct zfcp_abort_fcp_command abort_fcp_command; 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; struct zfcp_status_read status_read;
}; };
...@@ -671,6 +952,9 @@ struct zfcp_adapter { ...@@ -671,6 +952,9 @@ struct zfcp_adapter {
u32 fc_link_speed; /* FC interface speed */ u32 fc_link_speed; /* FC interface speed */
u32 hydra_version; /* Hydra version */ u32 hydra_version; /* Hydra version */
u32 fsf_lic_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 */ struct Scsi_Host *scsi_host; /* Pointer to mid-layer */
unsigned char name[9]; unsigned char name[9];
...@@ -704,6 +988,10 @@ struct zfcp_adapter { ...@@ -704,6 +988,10 @@ struct zfcp_adapter {
wait_queue_head_t erp_done_wqh; wait_queue_head_t erp_done_wqh;
struct zfcp_erp_action erp_action; /* pending error recovery */ struct zfcp_erp_action erp_action; /* pending error recovery */
atomic_t erp_counter; 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 */ struct zfcp_port *nameserver_port; /* adapter's nameserver */
debug_info_t *erp_dbf; /* S/390 debug features */ debug_info_t *erp_dbf; /* S/390 debug features */
debug_info_t *abort_dbf; debug_info_t *abort_dbf;
...@@ -751,7 +1039,7 @@ struct zfcp_unit { ...@@ -751,7 +1039,7 @@ struct zfcp_unit {
scsi_lun_t scsi_lun; /* own SCSI LUN */ scsi_lun_t scsi_lun; /* own SCSI LUN */
fcp_lun_t fcp_lun; /* own FCP_LUN */ fcp_lun_t fcp_lun; /* own FCP_LUN */
u32 handle; /* handle assigned by FSF */ 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 */ struct zfcp_erp_action erp_action; /* pending error recovery */
atomic_t erp_counter; atomic_t erp_counter;
struct device sysfs_device; /* sysfs device */ struct device sysfs_device; /* sysfs device */
...@@ -765,8 +1053,14 @@ struct zfcp_fsf_req { ...@@ -765,8 +1053,14 @@ struct zfcp_fsf_req {
u32 specific_magic; /* structure specific magic */ u32 specific_magic; /* structure specific magic */
struct list_head list; /* list of FSF requests */ struct list_head list; /* list of FSF requests */
struct zfcp_adapter *adapter; /* adapter request belongs to */ struct zfcp_adapter *adapter; /* adapter request belongs to */
u8 sbal_count; /* # of SBALs in FSF request */ u8 sbal_number; /* nr of SBALs free for use */
u8 sbal_index; /* position of 1st SBAL */ 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 wait_queue_head_t completion_wq; /* can be used by a routine
to wait for completion */ to wait for completion */
volatile u32 status; /* status of this request */ volatile u32 status; /* status of this request */
...@@ -776,13 +1070,15 @@ struct zfcp_fsf_req { ...@@ -776,13 +1070,15 @@ struct zfcp_fsf_req {
union zfcp_req_data data; /* Info fields of request */ union zfcp_req_data data; /* Info fields of request */
struct zfcp_erp_action *erp_action; /* used if this request is struct zfcp_erp_action *erp_action; /* used if this request is
issued on behalf of erp */ 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*); typedef void zfcp_fsf_req_handler_t(struct zfcp_fsf_req*);
/* driver data */ /* driver data */
struct zfcp_data { struct zfcp_data {
Scsi_Host_Template scsi_host_template; struct scsi_host_template scsi_host_template;
atomic_t status; /* Module status flags */ atomic_t status; /* Module status flags */
struct list_head adapter_list_head; /* head of adapter list */ struct list_head adapter_list_head; /* head of adapter list */
struct list_head adapter_remove_lh; /* head of adapters to be struct list_head adapter_remove_lh; /* head of adapters to be
...@@ -792,7 +1088,7 @@ struct zfcp_data { ...@@ -792,7 +1088,7 @@ struct zfcp_data {
struct list_head status_read_send_head; struct list_head status_read_send_head;
struct semaphore status_read_sema; struct semaphore status_read_sema;
wait_queue_head_t status_read_thread_wqh; 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 rwlock_t config_lock; /* serialises changes
to adapter/port/unit to adapter/port/unit
lists */ lists */
...@@ -829,6 +1125,24 @@ struct zfcp_statistics { ...@@ -829,6 +1125,24 @@ struct zfcp_statistics {
}; };
#endif #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 ********************************/ /********************** ZFCP SPECIFIC DEFINES ********************************/
#define ZFCP_FSFREQ_CLEANUP_TIMEOUT HZ/10 #define ZFCP_FSFREQ_CLEANUP_TIMEOUT HZ/10
...@@ -836,6 +1150,7 @@ struct zfcp_statistics { ...@@ -836,6 +1150,7 @@ struct zfcp_statistics {
#define ZFCP_KNOWN 0x00000001 #define ZFCP_KNOWN 0x00000001
#define ZFCP_REQ_AUTO_CLEANUP 0x00000002 #define ZFCP_REQ_AUTO_CLEANUP 0x00000002
#define ZFCP_WAIT_FOR_SBAL 0x00000004 #define ZFCP_WAIT_FOR_SBAL 0x00000004
#define ZFCP_REQ_NO_QTCB 0x00000008
#define ZFCP_SET 0x00000100 #define ZFCP_SET 0x00000100
#define ZFCP_CLEAR 0x00000200 #define ZFCP_CLEAR 0x00000200
......
...@@ -4,11 +4,12 @@ ...@@ -4,11 +4,12 @@
* *
* FCP adapter driver for IBM eServer zSeries * 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> * Author(s): Martin Peschke <mpeschke@de.ibm.com>
* Raimund Schroeder <raimund.schroeder@de.ibm.com> * Raimund Schroeder <raimund.schroeder@de.ibm.com>
* Aron Zeh <arzeh@de.ibm.com> * Aron Zeh
* Wolfgang Taphorn <taphorn@de.ibm.com> * Wolfgang Taphorn
* Stefan Bader <stefan.bader@de.ibm.com> * Stefan Bader <stefan.bader@de.ibm.com>
* Heiko Carstens <heiko.carstens@de.ibm.com> * Heiko Carstens <heiko.carstens@de.ibm.com>
* *
...@@ -28,12 +29,15 @@ ...@@ -28,12 +29,15 @@
*/ */
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_ERP #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) */ /* 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" #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_adapter_reopen_internal(struct zfcp_adapter *, int);
static int zfcp_erp_port_forced_reopen_internal(struct zfcp_port *, int); static int zfcp_erp_port_forced_reopen_internal(struct zfcp_port *, int);
static int zfcp_erp_port_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) ...@@ -326,6 +330,375 @@ zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear_mask)
return retval; 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: * function:
* *
...@@ -741,37 +1114,27 @@ zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action) ...@@ -741,37 +1114,27 @@ zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action)
"a_ca_disreq"); "a_ca_disreq");
fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED; 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 * If fsf_req is neither dismissed nor completed
* then keep it running asynchronously and don't mess with * then keep it running asynchronously and don't mess
* the association of erp_action and fsf_req. * with the association of erp_action and fsf_req.
*/ */
if (fsf_req->status & (ZFCP_STATUS_FSFREQ_COMPLETED | if (fsf_req->status & (ZFCP_STATUS_FSFREQ_COMPLETED |
ZFCP_STATUS_FSFREQ_DISMISSED)) { 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; fsf_req->erp_action = NULL;
erp_action->fsf_req = 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 { } else {
debug_text_event(adapter->erp_dbf, 3, "a_ca_gonereq"); debug_text_event(adapter->erp_dbf, 3, "a_ca_gonereq");
...@@ -1122,12 +1485,36 @@ zfcp_erp_strategy(struct zfcp_erp_action *erp_action) ...@@ -1122,12 +1485,36 @@ zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
goto unlock; goto unlock;
case ZFCP_ERP_NOMEM: case ZFCP_ERP_NOMEM:
/* no memory to continue immediately, let it sleep */ /* 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"); debug_text_event(adapter->erp_dbf, 2, "a_st_memw");
retval = zfcp_erp_strategy_memwait(erp_action); retval = zfcp_erp_strategy_memwait(erp_action);
/* fall through, waiting for memory means action continues */ }
goto unlock;
case ZFCP_ERP_CONTINUES: case ZFCP_ERP_CONTINUES:
/* leave since this action runs asynchronously */ /* leave since this action runs asynchronously */
debug_text_event(adapter->erp_dbf, 6, "a_st_cont"); 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; goto unlock;
} }
/* ok, finished action (whatever its result is) */ /* ok, finished action (whatever its result is) */
...@@ -1531,16 +1918,24 @@ zfcp_erp_strategy_check_unit(struct zfcp_unit *unit, int result) ...@@ -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, debug_event(unit->port->adapter->erp_dbf, 5, &unit->fcp_lun,
sizeof (fcp_lun_t)); sizeof (fcp_lun_t));
if (result == ZFCP_ERP_SUCCEEDED) { switch (result) {
case ZFCP_ERP_SUCCEEDED :
atomic_set(&unit->erp_counter, 0); atomic_set(&unit->erp_counter, 0);
zfcp_erp_unit_unblock(unit); zfcp_erp_unit_unblock(unit);
} else { break;
/* ZFCP_ERP_FAILED or ZFCP_ERP_EXIT */ case ZFCP_ERP_FAILED :
atomic_inc(&unit->erp_counter); 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); 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; return result;
...@@ -1559,16 +1954,24 @@ zfcp_erp_strategy_check_port(struct zfcp_port *port, int 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_text_event(port->adapter->erp_dbf, 5, "p_stct");
debug_event(port->adapter->erp_dbf, 5, &port->wwpn, sizeof (wwn_t)); 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); atomic_set(&port->erp_counter, 0);
zfcp_erp_port_unblock(port); zfcp_erp_port_unblock(port);
} else { break;
/* ZFCP_ERP_FAILED or ZFCP_ERP_EXIT */ case ZFCP_ERP_FAILED :
atomic_inc(&port->erp_counter); atomic_inc(&port->erp_counter);
if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS) { if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS)
zfcp_erp_port_failed(port); break;
result = ZFCP_ERP_EXIT; 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);
} }
return result; return result;
...@@ -1586,16 +1989,24 @@ zfcp_erp_strategy_check_adapter(struct zfcp_adapter *adapter, int 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"); 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); atomic_set(&adapter->erp_counter, 0);
zfcp_erp_adapter_unblock(adapter); zfcp_erp_adapter_unblock(adapter);
} else { break;
/* ZFCP_ERP_FAILED or ZFCP_ERP_EXIT */ case ZFCP_ERP_FAILED :
atomic_inc(&adapter->erp_counter); 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); 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; return result;
...@@ -1999,10 +2410,10 @@ zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *erp_action, int close) ...@@ -1999,10 +2410,10 @@ zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *erp_action, int close)
int int
zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action) zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action)
{ {
int retval = 0; int retval;
struct zfcp_adapter *adapter = erp_action->adapter;
int i; 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; int retval_cleanup = 0;
if (atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)) { 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) ...@@ -2034,10 +2445,10 @@ zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action)
* put buffers into response queue, * put buffers into response queue,
*/ */
for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) { for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) {
buffere = &(adapter->response_queue.buffer[i]->element[0]); sbale = &(adapter->response_queue.buffer[i]->element[0]);
buffere->length = 0; sbale->length = 0;
buffere->flags = SBAL_FLAGS_LAST_ENTRY; sbale->flags = SBAL_FLAGS_LAST_ENTRY;
buffere->addr = 0; sbale->addr = 0;
} }
ZFCP_LOG_TRACE("Calling do QDIO busid=%s, flags=0x%x, queue_no=%i, " 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) ...@@ -2591,7 +3002,7 @@ zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *erp_action)
if (atomic_test_mask((ZFCP_STATUS_COMMON_OPEN | if (atomic_test_mask((ZFCP_STATUS_COMMON_OPEN |
ZFCP_STATUS_PORT_DID_DID), ZFCP_STATUS_PORT_DID_DID),
&port->status)) { &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; retval = ZFCP_ERP_SUCCEEDED;
} else { } else {
ZFCP_LOG_DEBUG("failed to open port wwpn=0x%Lx\n", 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) ...@@ -2845,7 +3256,7 @@ zfcp_erp_port_strategy_open_common_lookup(struct zfcp_erp_action *erp_action)
struct zfcp_port *port = erp_action->port; struct zfcp_port *port = erp_action->port;
zfcp_erp_timeout_init(erp_action); zfcp_erp_timeout_init(erp_action);
retval = zfcp_nameserver_request(erp_action); retval = zfcp_ns_gid_pn_request(erp_action);
if (retval == -ENOMEM) { if (retval == -ENOMEM) {
debug_text_event(adapter->erp_dbf, 5, "p_pstn_nomem"); debug_text_event(adapter->erp_dbf, 5, "p_pstn_nomem");
debug_event(adapter->erp_dbf, 5, &port->wwpn, sizeof (wwn_t)); debug_event(adapter->erp_dbf, 5, &port->wwpn, sizeof (wwn_t));
...@@ -3087,6 +3498,10 @@ zfcp_erp_action_enqueue(int action, ...@@ -3087,6 +3498,10 @@ zfcp_erp_action_enqueue(int action,
* efficient. * efficient.
*/ */
if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP,
&adapter->status))
goto out;
debug_event(adapter->erp_dbf, 4, &action, sizeof (int)); debug_event(adapter->erp_dbf, 4, &action, sizeof (int));
/* check whether we really need this */ /* check whether we really need this */
switch (action) { switch (action) {
...@@ -3222,6 +3637,8 @@ zfcp_erp_action_enqueue(int action, ...@@ -3222,6 +3637,8 @@ zfcp_erp_action_enqueue(int action,
erp_action->action = action; erp_action->action = action;
erp_action->status = status; erp_action->status = status;
++adapter->erp_total_count;
/* finally put it into 'ready' queue and kick erp thread */ /* finally put it into 'ready' queue and kick erp thread */
list_add(&erp_action->list, &adapter->erp_ready_head); list_add(&erp_action->list, &adapter->erp_ready_head);
up(&adapter->erp_ready_sem); up(&adapter->erp_ready_sem);
...@@ -3243,6 +3660,12 @@ zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action) ...@@ -3243,6 +3660,12 @@ zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action)
int retval = 0; int retval = 0;
struct zfcp_adapter *adapter = erp_action->adapter; 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_text_event(adapter->erp_dbf, 4, "a_actdeq");
debug_event(adapter->erp_dbf, 4, &erp_action->action, sizeof (int)); debug_event(adapter->erp_dbf, 4, &erp_action->action, sizeof (int));
list_del(&erp_action->list); list_del(&erp_action->list);
...@@ -3404,4 +3827,3 @@ zfcp_erp_action_to_ready(struct zfcp_erp_action *erp_action) ...@@ -3404,4 +3827,3 @@ zfcp_erp_action_to_ready(struct zfcp_erp_action *erp_action)
} }
#undef ZFCP_LOG_AREA #undef ZFCP_LOG_AREA
#undef ZFCP_LOG_AREA_PREFIX
...@@ -4,11 +4,12 @@ ...@@ -4,11 +4,12 @@
* *
* FCP adapter driver for IBM eServer zSeries * 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> * Author(s): Martin Peschke <mpeschke@de.ibm.com>
* Raimund Schroeder <raimund.schroeder@de.ibm.com> * Raimund Schroeder <raimund.schroeder@de.ibm.com>
* Aron Zeh <arzeh@de.ibm.com> * Aron Zeh
* Wolfgang Taphorn <taphorn@de.ibm.com> * Wolfgang Taphorn
* Stefan Bader <stefan.bader@de.ibm.com> * Stefan Bader <stefan.bader@de.ibm.com>
* Heiko Carstens <heiko.carstens@de.ibm.com> * Heiko Carstens <heiko.carstens@de.ibm.com>
* *
...@@ -30,7 +31,7 @@ ...@@ -30,7 +31,7 @@
#ifndef ZFCP_EXT_H #ifndef ZFCP_EXT_H
#define ZFCP_EXT_H #define ZFCP_EXT_H
/* this drivers version (do not edit !!! generated and updated by cvs) */ /* 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" #include "zfcp_def.h"
...@@ -46,7 +47,6 @@ extern void zfcp_sysfs_port_remove_files(struct device *, u32); ...@@ -46,7 +47,6 @@ extern void zfcp_sysfs_port_remove_files(struct device *, u32);
extern int zfcp_sysfs_unit_create_files(struct device *); extern int zfcp_sysfs_unit_create_files(struct device *);
extern void zfcp_sysfs_unit_remove_files(struct device *); extern void zfcp_sysfs_unit_remove_files(struct device *);
extern void zfcp_sysfs_port_release(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 *); extern void zfcp_sysfs_unit_release(struct device *);
/**************************** CONFIGURATION *********************************/ /**************************** CONFIGURATION *********************************/
...@@ -65,7 +65,6 @@ extern void zfcp_unit_dequeue(struct zfcp_unit *); ...@@ -65,7 +65,6 @@ extern void zfcp_unit_dequeue(struct zfcp_unit *);
extern int zfcp_ccw_register(void); extern int zfcp_ccw_register(void);
extern void zfcp_ccw_unregister(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 void zfcp_qdio_zero_sbals(struct qdio_buffer **, int, int);
extern int zfcp_qdio_allocate(struct zfcp_adapter *); extern int zfcp_qdio_allocate(struct zfcp_adapter *);
extern int zfcp_qdio_allocate_queues(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 *, ...@@ -74,6 +73,16 @@ extern int zfcp_qdio_determine_pci(struct zfcp_qdio_queue *,
struct zfcp_fsf_req *); struct zfcp_fsf_req *);
extern int zfcp_qdio_reqid_check(struct zfcp_adapter *, void *); 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 ****************************************/ /******************************** FSF ****************************************/
extern int zfcp_fsf_open_port(struct zfcp_erp_action *); extern int zfcp_fsf_open_port(struct zfcp_erp_action *);
extern int zfcp_fsf_close_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 *); ...@@ -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_close_unit(struct zfcp_erp_action *);
extern int zfcp_fsf_exchange_config_data(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 void zfcp_fsf_scsi_er_timeout_handler(unsigned long);
extern int zfcp_fsf_req_dismiss_all(struct zfcp_adapter *); extern int zfcp_fsf_req_dismiss_all(struct zfcp_adapter *);
extern int zfcp_fsf_status_read(struct zfcp_adapter *, int); extern int zfcp_fsf_status_read(struct zfcp_adapter *, int);
extern int zfcp_fsf_req_create(struct zfcp_adapter *,u32, unsigned long *, extern int zfcp_fsf_req_create(struct zfcp_adapter *, u32, int, mempool_t *,
int, struct zfcp_fsf_req **); unsigned long *, struct zfcp_fsf_req **);
extern void zfcp_fsf_req_free(struct zfcp_fsf_req *); extern int zfcp_fsf_send_ct(struct zfcp_send_ct *, mempool_t *,
extern int zfcp_fsf_send_generic(struct zfcp_fsf_req *, unsigned char, struct zfcp_erp_action *);
unsigned long *, struct timer_list *); 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_req_wait_and_cleanup(struct zfcp_fsf_req *, int, u32 *);
extern int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *, extern int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *,
struct zfcp_unit *, Scsi_Cmnd *, struct zfcp_unit *,
struct scsi_cmnd *,
int); int);
extern int zfcp_fsf_req_complete(struct zfcp_fsf_req *); extern int zfcp_fsf_req_complete(struct zfcp_fsf_req *);
extern void zfcp_fsf_incoming_els(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( ...@@ -105,15 +117,11 @@ extern struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(
/******************************** FCP ****************************************/ /******************************** FCP ****************************************/
extern int zfcp_nameserver_enqueue(struct zfcp_adapter *); extern int zfcp_nameserver_enqueue(struct zfcp_adapter *);
extern int zfcp_nameserver_request(struct zfcp_erp_action *); extern int zfcp_ns_gid_pn_request(struct zfcp_erp_action *);
extern void zfcp_fsf_els_processing(struct zfcp_fsf_req *);
/******************************* SCSI ****************************************/ /******************************* SCSI ****************************************/
extern int zfcp_adapter_scsi_register(struct zfcp_adapter *); extern int zfcp_adapter_scsi_register(struct zfcp_adapter *);
extern void zfcp_adapter_scsi_unregister(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 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 char *zfcp_get_fcp_rsp_info_ptr(struct fcp_rsp_iu *);
extern void set_host_byte(u32 *, char); extern void set_host_byte(u32 *, char);
...@@ -122,6 +130,11 @@ extern char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *); ...@@ -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 void zfcp_fsf_start_scsi_er_timer(struct zfcp_adapter *);
extern fcp_dl_t zfcp_get_fcp_dl(struct fcp_cmnd_iu *); 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 ****************************************/ /******************************** ERP ****************************************/
extern void zfcp_erp_modify_adapter_status(struct zfcp_adapter *, u32, int); extern void zfcp_erp_modify_adapter_status(struct zfcp_adapter *, u32, int);
extern int zfcp_erp_adapter_reopen(struct zfcp_adapter *, int); extern int zfcp_erp_adapter_reopen(struct zfcp_adapter *, int);
...@@ -147,10 +160,12 @@ extern int zfcp_erp_thread_kill(struct zfcp_adapter *); ...@@ -147,10 +160,12 @@ extern int zfcp_erp_thread_kill(struct zfcp_adapter *);
extern int zfcp_erp_wait(struct zfcp_adapter *); extern int zfcp_erp_wait(struct zfcp_adapter *);
extern void zfcp_erp_fsf_req_handler(struct zfcp_fsf_req *); extern void zfcp_erp_fsf_req_handler(struct zfcp_fsf_req *);
extern int zfcp_test_link(struct zfcp_port *);
/******************************** AUX ****************************************/ /******************************** AUX ****************************************/
extern void zfcp_cmd_dbf_event_fsf(const char *, struct zfcp_fsf_req *, extern void zfcp_cmd_dbf_event_fsf(const char *, struct zfcp_fsf_req *,
void *, int); 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 *, extern void zfcp_in_els_dbf_event(struct zfcp_adapter *, const char *,
struct fsf_status_read_buffer *, int); struct fsf_status_read_buffer *, int);
#ifdef ZFCP_STAT_REQSIZES #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 @@ ...@@ -4,11 +4,12 @@
* *
* FCP adapter driver for IBM eServer zSeries * 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> * Author(s): Martin Peschke <mpeschke@de.ibm.com>
* Raimund Schroeder <raimund.schroeder@de.ibm.com> * Raimund Schroeder <raimund.schroeder@de.ibm.com>
* Aron Zeh <arzeh@de.ibm.com> * Aron Zeh
* Wolfgang Taphorn <taphorn@de.ibm.com> * Wolfgang Taphorn
* Stefan Bader <stefan.bader@de.ibm.com> * Stefan Bader <stefan.bader@de.ibm.com>
* Heiko Carstens <heiko.carstens@de.ibm.com> * Heiko Carstens <heiko.carstens@de.ibm.com>
* *
...@@ -44,11 +45,22 @@ ...@@ -44,11 +45,22 @@
#define FSF_QTCB_SEND_ELS 0x0000000B #define FSF_QTCB_SEND_ELS 0x0000000B
#define FSF_QTCB_SEND_GENERIC 0x0000000C #define FSF_QTCB_SEND_GENERIC 0x0000000C
#define FSF_QTCB_EXCHANGE_CONFIG_DATA 0x0000000D #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 */ /* FSF QTCB types */
#define FSF_IO_COMMAND 0x00000001 #define FSF_IO_COMMAND 0x00000001
#define FSF_SUPPORT_COMMAND 0x00000002 #define FSF_SUPPORT_COMMAND 0x00000002
#define FSF_CONFIG_COMMAND 0x00000003 #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 */ /* FSF protocol stati */
#define FSF_PROT_GOOD 0x00000001 #define FSF_PROT_GOOD 0x00000001
...@@ -71,9 +83,9 @@ ...@@ -71,9 +83,9 @@
#define FSF_HANDLE_MISMATCH 0x00000005 #define FSF_HANDLE_MISMATCH 0x00000005
#define FSF_SERVICE_CLASS_NOT_SUPPORTED 0x00000006 #define FSF_SERVICE_CLASS_NOT_SUPPORTED 0x00000006
#define FSF_FCPLUN_NOT_VALID 0x00000009 #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_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_ULP 0x00000020
#define FSF_COMMAND_ABORTED_ADAPTER 0x00000021 #define FSF_COMMAND_ABORTED_ADAPTER 0x00000021
#define FSF_FCP_COMMAND_DOES_NOT_EXIST 0x00000022 #define FSF_FCP_COMMAND_DOES_NOT_EXIST 0x00000022
...@@ -87,13 +99,24 @@ ...@@ -87,13 +99,24 @@
#define FSF_RESPONSE_BUF_NOT_VALID 0x00000043 #define FSF_RESPONSE_BUF_NOT_VALID 0x00000043
#define FSF_ELS_COMMAND_REJECTED 0x00000050 #define FSF_ELS_COMMAND_REJECTED 0x00000050
#define FSF_GENERIC_COMMAND_REJECTED 0x00000051 #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_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_ADAPTER_STATUS_AVAILABLE 0x000000AD
#define FSF_FCP_RSP_AVAILABLE 0x000000AF #define FSF_FCP_RSP_AVAILABLE 0x000000AF
#define FSF_UNKNOWN_COMMAND 0x000000E2 #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 #define FSF_STATUS_QUALIFIER_SIZE 16
...@@ -107,6 +130,15 @@ ...@@ -107,6 +130,15 @@
#define FSF_SQ_COMMAND_ABORTED 0x06 #define FSF_SQ_COMMAND_ABORTED 0x06
#define FSF_SQ_NO_RETRY_POSSIBLE 0x07 #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 */ /* FSF status qualifier (most significant 4 bytes), local link down */
#define FSF_PSQ_LINK_NOLIGHT 0x00000004 #define FSF_PSQ_LINK_NOLIGHT 0x00000004
#define FSF_PSQ_LINK_WRAPPLUG 0x00000008 #define FSF_PSQ_LINK_WRAPPLUG 0x00000008
...@@ -124,11 +156,20 @@ ...@@ -124,11 +156,20 @@
#define FSF_STATUS_READ_BIT_ERROR_THRESHOLD 0x00000004 #define FSF_STATUS_READ_BIT_ERROR_THRESHOLD 0x00000004
#define FSF_STATUS_READ_LINK_DOWN 0x00000005 /* FIXME: really? */ #define FSF_STATUS_READ_LINK_DOWN 0x00000005 /* FIXME: really? */
#define FSF_STATUS_READ_LINK_UP 0x00000006 #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 */ /* status subtypes in status read buffer */
#define FSF_STATUS_READ_SUB_CLOSE_PHYS_PORT 0x00000001 #define FSF_STATUS_READ_SUB_CLOSE_PHYS_PORT 0x00000001
#define FSF_STATUS_READ_SUB_ERROR_PORT 0x00000002 #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 */ /* topologie that is detected by the adapter */
#define FSF_TOPO_ERROR 0x00000000 #define FSF_TOPO_ERROR 0x00000000
#define FSF_TOPO_P2P 0x00000001 #define FSF_TOPO_P2P 0x00000001
...@@ -149,10 +190,48 @@ ...@@ -149,10 +190,48 @@
/* SBAL chaining */ /* SBAL chaining */
#define FSF_MAX_SBALS_PER_REQ 36 #define FSF_MAX_SBALS_PER_REQ 36
#define FSF_MAX_SBALS_PER_ELS_REQ 2
/* logging space behind QTCB */ /* logging space behind QTCB */
#define FSF_QTCB_LOG_SIZE 1024 #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_queue_designator;
struct fsf_status_read_buffer; struct fsf_status_read_buffer;
struct fsf_port_closed_payload; struct fsf_port_closed_payload;
...@@ -307,49 +386,92 @@ struct fsf_qtcb_bottom_io { ...@@ -307,49 +386,92 @@ struct fsf_qtcb_bottom_io {
} __attribute__ ((packed)); } __attribute__ ((packed));
struct fsf_qtcb_bottom_support { struct fsf_qtcb_bottom_support {
u8 res1[16]; u32 operation_subtype;
u8 res1[12];
u32 d_id; u32 d_id;
u32 res2; u32 option;
u64 fcp_lun; u64 fcp_lun;
u64 res3; u64 res2;
u64 req_handle; u64 req_handle;
u32 service_class; u32 service_class;
u8 res4[3]; u8 res3[3];
u8 timeout; u8 timeout;
u8 res5[184]; u8 res4[184];
u32 els1_length; u32 els1_length;
u32 els2_length; u32 els2_length;
u64 res6; u32 req_buf_length;
u32 resp_buf_length;
u8 els[256]; u8 els[256];
} __attribute__ ((packed)); } __attribute__ ((packed));
struct fsf_qtcb_bottom_config { struct fsf_qtcb_bottom_config {
u32 lic_version; u32 lic_version;
u32 res1; u32 feature_selection;
u32 high_qtcb_version; u32 high_qtcb_version;
u32 low_qtcb_version; u32 low_qtcb_version;
u32 max_qtcb_size; u32 max_qtcb_size;
u8 res2[12]; u32 max_data_transfer_size;
u32 supported_features;
u8 res1[4];
u32 fc_topology; u32 fc_topology;
u32 fc_link_speed; u32 fc_link_speed;
u32 adapter_type; u32 adapter_type;
u32 peer_d_id; u32 peer_d_id;
u8 res3[12]; u8 res2[12];
u32 s_id; u32 s_id;
struct fsf_nport_serv_param nport_serv_param; 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)); } __attribute__ ((packed));
union fsf_qtcb_bottom { union fsf_qtcb_bottom {
struct fsf_qtcb_bottom_io io; struct fsf_qtcb_bottom_io io;
struct fsf_qtcb_bottom_support support; struct fsf_qtcb_bottom_support support;
struct fsf_qtcb_bottom_config config; struct fsf_qtcb_bottom_config config;
struct fsf_qtcb_bottom_port port;
}; };
struct fsf_qtcb { struct fsf_qtcb {
struct fsf_qtcb_prefix prefix; struct fsf_qtcb_prefix prefix;
struct fsf_qtcb_header header; struct fsf_qtcb_header header;
union fsf_qtcb_bottom bottom; union fsf_qtcb_bottom bottom;
u8 log[FSF_QTCB_LOG_SIZE];
} __attribute__ ((packed)); } __attribute__ ((packed));
#endif /* FSF_H */ #endif /* FSF_H */
...@@ -5,11 +5,12 @@ ...@@ -5,11 +5,12 @@
* *
* QDIO related routines * QDIO related routines
* *
* Copyright (C) 2003 IBM Entwicklung GmbH, IBM Corporation * (C) Copyright IBM Corp. 2002, 2004
*
* Authors: * Authors:
* Martin Peschke <mpeschke@de.ibm.com> * Martin Peschke <mpeschke@de.ibm.com>
* Raimund Schroeder <raimund.schroeder@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> * Heiko Carstens <heiko.carstens@de.ibm.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -27,10 +28,28 @@ ...@@ -27,10 +28,28 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * 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" #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_request_handler;
static qdio_handler_t zfcp_qdio_response_handler; static qdio_handler_t zfcp_qdio_response_handler;
static int zfcp_qdio_handler_error_check(struct zfcp_adapter *, static int zfcp_qdio_handler_error_check(struct zfcp_adapter *,
...@@ -38,7 +57,6 @@ 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); unsigned int, unsigned int);
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_QDIO #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 * 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, ...@@ -318,7 +336,7 @@ zfcp_qdio_request_handler(struct ccw_device *ccw_device,
atomic_add(elements_processed, &queue->free_count); atomic_add(elements_processed, &queue->free_count);
ZFCP_LOG_DEBUG("free_count=%d\n", atomic_read(&queue->free_count)); ZFCP_LOG_DEBUG("free_count=%d\n", atomic_read(&queue->free_count));
wake_up(&adapter->request_wq); 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)); elements_processed, atomic_read(&queue->free_count));
out: out:
return; return;
...@@ -365,7 +383,7 @@ zfcp_qdio_response_handler(struct ccw_device *ccw_device, ...@@ -365,7 +383,7 @@ zfcp_qdio_response_handler(struct ccw_device *ccw_device,
*/ */
buffere = &(queue->buffer[first_element]->element[0]); 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 * go through all SBALs from input queue currently
* returned by QDIO layer * returned by QDIO layer
...@@ -516,8 +534,8 @@ zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, void *sbale_addr) ...@@ -516,8 +534,8 @@ zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, void *sbale_addr)
(unsigned long) fsf_req, (unsigned long) fsf_req->qtcb); (unsigned long) fsf_req, (unsigned long) fsf_req->qtcb);
if (likely(fsf_req->qtcb)) { if (likely(fsf_req->qtcb)) {
ZFCP_LOG_TRACE("HEX DUMP OF 1ST BUFFERE PAYLOAD (QTCB):\n"); ZFCP_LOG_TRACE("HEX DUMP OF 1ST BUFFERE PAYLOAD (QTCB):\n");
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, (char *) fsf_req->qtcb,
(char *) fsf_req->qtcb, ZFCP_QTCB_SIZE); sizeof(struct fsf_qtcb));
} }
/* finish the FSF request */ /* finish the FSF request */
...@@ -526,24 +544,346 @@ zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, void *sbale_addr) ...@@ -526,24 +544,346 @@ zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, void *sbale_addr)
return retval; 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 int
zfcp_qdio_determine_pci(struct zfcp_qdio_queue *req_queue, zfcp_qdio_determine_pci(struct zfcp_qdio_queue *req_queue,
struct zfcp_fsf_req *fsf_req) struct zfcp_fsf_req *fsf_req)
{ {
int new_distance_from_int; int new_distance_from_int;
int pci_pos; int pci_pos;
volatile struct qdio_buffer_element *sbale;
new_distance_from_int = req_queue->distance_from_int + 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)) { if (unlikely(new_distance_from_int >= ZFCP_QDIO_PCI_INTERVAL)) {
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_first;
pci_pos += fsf_req->sbal_count; pci_pos += fsf_req->sbal_number;
pci_pos -= new_distance_from_int; pci_pos -= new_distance_from_int;
pci_pos -= 1; pci_pos -= 1;
pci_pos %= QDIO_MAX_BUFFERS_PER_Q; pci_pos %= QDIO_MAX_BUFFERS_PER_Q;
req_queue->buffer[pci_pos]->element[0].flags |= SBAL_FLAGS0_PCI; sbale = zfcp_qdio_sbale_req(fsf_req, pci_pos, 0);
ZFCP_LOG_TRACE("Setting PCI flag at pos %d\n", pci_pos); sbale->flags |= SBAL_FLAGS0_PCI;
} }
return new_distance_from_int; return new_distance_from_int;
} }
...@@ -570,4 +910,3 @@ zfcp_qdio_zero_sbals(struct qdio_buffer *buf[], int first, int clean_count) ...@@ -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
#undef ZFCP_LOG_AREA_PREFIX
...@@ -4,11 +4,12 @@ ...@@ -4,11 +4,12 @@
* *
* FCP adapter driver for IBM eServer zSeries * 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> * Author(s): Martin Peschke <mpeschke@de.ibm.com>
* Raimund Schroeder <raimund.schroeder@de.ibm.com> * Raimund Schroeder <raimund.schroeder@de.ibm.com>
* Aron Zeh <arzeh@de.ibm.com> * Aron Zeh
* Wolfgang Taphorn <taphorn@de.ibm.com> * Wolfgang Taphorn
* Stefan Bader <stefan.bader@de.ibm.com> * Stefan Bader <stefan.bader@de.ibm.com>
* Heiko Carstens <heiko.carstens@de.ibm.com> * Heiko Carstens <heiko.carstens@de.ibm.com>
* *
...@@ -28,9 +29,9 @@ ...@@ -28,9 +29,9 @@
*/ */
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_SCSI #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) */ /* 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> #include <linux/blkdev.h>
...@@ -39,24 +40,14 @@ ...@@ -39,24 +40,14 @@
static void zfcp_scsi_slave_destroy(struct scsi_device *sdp); 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_alloc(struct scsi_device *sdp);
static int zfcp_scsi_slave_configure(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_queuecommand(struct scsi_cmnd *,
static int zfcp_scsi_eh_abort_handler(Scsi_Cmnd *); void (*done) (struct scsi_cmnd *));
static int zfcp_scsi_eh_device_reset_handler(Scsi_Cmnd *); static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *);
static int zfcp_scsi_eh_bus_reset_handler(Scsi_Cmnd *); static int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *);
static int zfcp_scsi_eh_host_reset_handler(Scsi_Cmnd *); static int zfcp_scsi_eh_bus_reset_handler(struct scsi_cmnd *);
static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *);
static int zfcp_task_management_function(struct zfcp_unit *, u8); static int zfcp_task_management_function(struct zfcp_unit *, u8);
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 zfcp_unit *zfcp_unit_lookup(struct zfcp_adapter *, int, int, int);
static struct device_attribute *zfcp_sysfs_sdev_attrs[]; static struct device_attribute *zfcp_sysfs_sdev_attrs[];
...@@ -225,58 +216,6 @@ zfcp_scsi_slave_destroy(struct scsi_device *sdpnt) ...@@ -225,58 +216,6 @@ 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. * called from scsi midlayer to allow finetuning of a device.
*/ */
...@@ -290,124 +229,143 @@ zfcp_scsi_slave_configure(struct scsi_device *sdp) ...@@ -290,124 +229,143 @@ zfcp_scsi_slave_configure(struct scsi_device *sdp)
return 0; 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 static void
zfcp_scsi_queuecommand_stop(Scsi_Cmnd * scpnt, zfcp_scsi_command_fail(struct scsi_cmnd *scpnt, int result)
struct zfcp_adapter *adapter,
struct zfcp_unit *unit)
{ {
/* Always pass through to upper layer */ set_host_byte(&scpnt->result, result);
scpnt->retries = scpnt->allowed - 1; zfcp_cmd_dbf_event_scsi("failing", scpnt);
set_host_byte(&scpnt->result, DID_ERROR);
zfcp_cmd_dbf_event_scsi("stopping", scpnt);
/* return directly */ /* return directly */
scpnt->scsi_done(scpnt); 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 * zfcp_scsi_command_async - worker for zfcp_scsi_queuecommand and
* * zfcp_scsi_command_sync
* purpose: enqueues a SCSI command to the specified target device * @adapter: adapter for where scsi command is issued
* * @unit: unit to which scsi command is sent
* note: The scsi_done midlayer function may be called directly from * @scpnt: scsi command to be sent
* 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.
* *
* returns: 0 - success, SCSI command enqueued * Note: In scsi_done function must be set in scpnt.
* !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)
*/ */
int 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 retval;
int temp_ret;
struct zfcp_unit *unit;
struct zfcp_adapter *adapter;
retval = 0; 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); BUG_ON((adapter == NULL) || (adapter != unit->port->adapter));
if (unlikely(unit == NULL)) BUG_ON(scpnt->scsi_done == NULL);
if (unlikely(NULL == unit)) {
zfcp_scsi_command_fail(scpnt, DID_NO_CONNECT);
goto out; goto out;
}
if (unlikely( if (unlikely(
atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &unit->status) || atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &unit->status) ||
!atomic_test_mask(ZFCP_STATUS_COMMON_RUNNING, &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; goto out;
} }
if (unlikely( if (unlikely(
!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status))) { !atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status))) {
ZFCP_LOG_DEBUG("adapter %s not ready or unit with LUN 0x%Lx " ZFCP_LOG_DEBUG("adapter %s not ready or unit with LUN 0x%Lx "
"on the port with WWPN 0x%Lx in recovery.\n", "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); unit->fcp_lun, unit->port->wwpn);
retval = SCSI_MLQUEUE_DEVICE_BUSY; retval = SCSI_MLQUEUE_DEVICE_BUSY;
goto out; goto out;
} }
temp_ret = zfcp_fsf_send_fcp_command_task(adapter, tmp = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt,
unit, ZFCP_REQ_AUTO_CLEANUP);
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"); ZFCP_LOG_DEBUG("error: Could not send a Send FCP Command\n");
retval = SCSI_MLQUEUE_HOST_BUSY; retval = SCSI_MLQUEUE_HOST_BUSY;
} else { } else {
#ifdef ZFCP_DEBUG_REQUESTS #ifdef ZFCP_DEBUG_REQUESTS
debug_text_event(adapter->req_dbf, 3, "q_scpnt"); debug_text_event(adapter->req_dbf, 3, "q_scpnt");
debug_event(adapter->req_dbf, 3, &scpnt, debug_event(adapter->req_dbf, 3, &scpnt,
sizeof (unsigned long)); sizeof (unsigned long));
#endif /* ZFCP_DEBUG_REQUESTS */ #endif /* ZFCP_DEBUG_REQUESTS */
} }
out:
out:
return retval; 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 * function: zfcp_unit_lookup
* *
...@@ -456,22 +414,18 @@ zfcp_unit_lookup(struct zfcp_adapter *adapter, int channel, int id, int lun) ...@@ -456,22 +414,18 @@ zfcp_unit_lookup(struct zfcp_adapter *adapter, int channel, int id, int lun)
* FAILED - otherwise * FAILED - otherwise
*/ */
int int
zfcp_scsi_eh_abort_handler(Scsi_Cmnd * scpnt) zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
{ {
int retval = SUCCESS; int retval = SUCCESS;
struct zfcp_fsf_req *new_fsf_req, *old_fsf_req; struct zfcp_fsf_req *new_fsf_req, *old_fsf_req;
struct zfcp_adapter *adapter; struct zfcp_adapter *adapter = (struct zfcp_adapter *) scpnt->device->host->hostdata[0];
struct zfcp_unit *unit; struct zfcp_unit *unit = (struct zfcp_unit *) scpnt->device->hostdata;
struct zfcp_port *port; struct zfcp_port *port = unit->port;
struct Scsi_Host *scsi_host; struct Scsi_Host *scsi_host = scpnt->device->host;
union zfcp_req_data *req_data = NULL; union zfcp_req_data *req_data = NULL;
unsigned long flags; unsigned long flags;
u32 status = 0; 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 #ifdef ZFCP_DEBUG_ABORTS
/* the components of a abort_dbf record (fixed size record) */ /* the components of a abort_dbf record (fixed size record) */
...@@ -657,7 +611,7 @@ zfcp_scsi_eh_abort_handler(Scsi_Cmnd * scpnt) ...@@ -657,7 +611,7 @@ zfcp_scsi_eh_abort_handler(Scsi_Cmnd * scpnt)
* returns: * returns:
*/ */
int int
zfcp_scsi_eh_device_reset_handler(Scsi_Cmnd * scpnt) zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt)
{ {
int retval; int retval;
struct zfcp_unit *unit = (struct zfcp_unit *) scpnt->device->hostdata; 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) ...@@ -764,7 +718,7 @@ zfcp_task_management_function(struct zfcp_unit *unit, u8 tm_flags)
* returns: * returns:
*/ */
int int
zfcp_scsi_eh_bus_reset_handler(Scsi_Cmnd * scpnt) zfcp_scsi_eh_bus_reset_handler(struct scsi_cmnd *scpnt)
{ {
int retval = 0; int retval = 0;
struct zfcp_unit *unit; struct zfcp_unit *unit;
...@@ -793,7 +747,7 @@ zfcp_scsi_eh_bus_reset_handler(Scsi_Cmnd * scpnt) ...@@ -793,7 +747,7 @@ zfcp_scsi_eh_bus_reset_handler(Scsi_Cmnd * scpnt)
* returns: * returns:
*/ */
int int
zfcp_scsi_eh_host_reset_handler(Scsi_Cmnd * scpnt) zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
{ {
int retval = 0; int retval = 0;
struct zfcp_unit *unit; struct zfcp_unit *unit;
...@@ -887,332 +841,6 @@ zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter) ...@@ -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 void
zfcp_fsf_start_scsi_er_timer(struct zfcp_adapter *adapter) zfcp_fsf_start_scsi_er_timer(struct zfcp_adapter *adapter)
{ {
...@@ -1293,4 +921,3 @@ static struct device_attribute *zfcp_sysfs_sdev_attrs[] = { ...@@ -1293,4 +921,3 @@ static struct device_attribute *zfcp_sysfs_sdev_attrs[] = {
}; };
#undef ZFCP_LOG_AREA #undef ZFCP_LOG_AREA
#undef ZFCP_LOG_AREA_PREFIX
...@@ -5,7 +5,8 @@ ...@@ -5,7 +5,8 @@
* *
* sysfs adapter related routines * sysfs adapter related routines
* *
* Copyright (C) 2003 IBM Entwicklung GmbH, IBM Corporation * (C) Copyright IBM Corp. 2003, 2004
*
* Authors: * Authors:
* Martin Peschke <mpeschke@de.ibm.com> * Martin Peschke <mpeschke@de.ibm.com>
* Heiko Carstens <heiko.carstens@de.ibm.com> * Heiko Carstens <heiko.carstens@de.ibm.com>
...@@ -25,14 +26,13 @@ ...@@ -25,14 +26,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * 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 <asm/ccwdev.h>
#include "zfcp_ext.h" #include "zfcp_ext.h"
#include "zfcp_def.h" #include "zfcp_def.h"
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG #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] = { static const char fc_topologies[5][25] = {
{"<error>"}, {"<error>"},
...@@ -66,12 +66,15 @@ ZFCP_DEFINE_ADAPTER_ATTR(status, "0x%08x\n", atomic_read(&adapter->status)); ...@@ -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(wwnn, "0x%016llx\n", adapter->wwnn);
ZFCP_DEFINE_ADAPTER_ATTR(wwpn, "0x%016llx\n", adapter->wwpn); 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(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(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_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_service_class, "%d\n", adapter->fc_service_class);
ZFCP_DEFINE_ADAPTER_ATTR(fc_topology, "%s\n", ZFCP_DEFINE_ADAPTER_ATTR(fc_topology, "%s\n",
fc_topologies[adapter->fc_topology]); 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 * zfcp_sysfs_adapter_in_recovery_show - recovery state of adapter
...@@ -259,11 +262,6 @@ zfcp_sysfs_adapter_failed_store(struct device *dev, ...@@ -259,11 +262,6 @@ zfcp_sysfs_adapter_failed_store(struct device *dev,
goto out; 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_erp_modify_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING,
ZFCP_SET); ZFCP_SET);
zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED); zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED);
...@@ -304,13 +302,15 @@ static struct attribute *zfcp_adapter_attrs[] = { ...@@ -304,13 +302,15 @@ static struct attribute *zfcp_adapter_attrs[] = {
&dev_attr_wwnn.attr, &dev_attr_wwnn.attr,
&dev_attr_wwpn.attr, &dev_attr_wwpn.attr,
&dev_attr_s_id.attr, &dev_attr_s_id.attr,
&dev_attr_hw_version.attr, &dev_attr_card_version.attr,
&dev_attr_lic_version.attr, &dev_attr_lic_version.attr,
&dev_attr_fc_link_speed.attr, &dev_attr_fc_link_speed.attr,
&dev_attr_fc_service_class.attr, &dev_attr_fc_service_class.attr,
&dev_attr_fc_topology.attr, &dev_attr_fc_topology.attr,
&dev_attr_scsi_host_no.attr, &dev_attr_scsi_host_no.attr,
&dev_attr_status.attr, &dev_attr_status.attr,
&dev_attr_hardware_version.attr,
&dev_attr_serial_number.attr,
NULL NULL
}; };
...@@ -343,4 +343,3 @@ zfcp_sysfs_adapter_remove_files(struct device *dev) ...@@ -343,4 +343,3 @@ zfcp_sysfs_adapter_remove_files(struct device *dev)
} }
#undef ZFCP_LOG_AREA #undef ZFCP_LOG_AREA
#undef ZFCP_LOG_AREA_PREFIX
...@@ -5,7 +5,8 @@ ...@@ -5,7 +5,8 @@
* *
* sysfs driver related routines * sysfs driver related routines
* *
* Copyright (C) 2003 IBM Entwicklung GmbH, IBM Corporation * (C) Copyright IBM Corp. 2003, 2004
*
* Authors: * Authors:
* Martin Peschke <mpeschke@de.ibm.com> * Martin Peschke <mpeschke@de.ibm.com>
* Heiko Carstens <heiko.carstens@de.ibm.com> * Heiko Carstens <heiko.carstens@de.ibm.com>
...@@ -25,14 +26,13 @@ ...@@ -25,14 +26,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * 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 <asm/ccwdev.h>
#include "zfcp_ext.h" #include "zfcp_ext.h"
#include "zfcp_def.h" #include "zfcp_def.h"
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG #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 * 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, \ ...@@ -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, \ static ssize_t zfcp_sysfs_loglevel_##_name##_show(struct device_driver *dev, \
char *buf) \ 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, \ static DRIVER_ATTR(loglevel_##_name, S_IWUSR | S_IRUGO, \
...@@ -83,6 +84,14 @@ ZFCP_DEFINE_DRIVER_ATTR(qdio, QDIO); ...@@ -83,6 +84,14 @@ ZFCP_DEFINE_DRIVER_ATTR(qdio, QDIO);
ZFCP_DEFINE_DRIVER_ATTR(erp, ERP); ZFCP_DEFINE_DRIVER_ATTR(erp, ERP);
ZFCP_DEFINE_DRIVER_ATTR(fc, FC); 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[] = { static struct attribute *zfcp_driver_attrs[] = {
&driver_attr_loglevel_other.attr, &driver_attr_loglevel_other.attr,
&driver_attr_loglevel_scsi.attr, &driver_attr_loglevel_scsi.attr,
...@@ -92,6 +101,7 @@ static struct attribute *zfcp_driver_attrs[] = { ...@@ -92,6 +101,7 @@ static struct attribute *zfcp_driver_attrs[] = {
&driver_attr_loglevel_qdio.attr, &driver_attr_loglevel_qdio.attr,
&driver_attr_loglevel_erp.attr, &driver_attr_loglevel_erp.attr,
&driver_attr_loglevel_fc.attr, &driver_attr_loglevel_fc.attr,
&driver_attr_version.attr,
NULL NULL
}; };
...@@ -124,4 +134,3 @@ zfcp_sysfs_driver_remove_files(struct device_driver *drv) ...@@ -124,4 +134,3 @@ zfcp_sysfs_driver_remove_files(struct device_driver *drv)
} }
#undef ZFCP_LOG_AREA #undef ZFCP_LOG_AREA
#undef ZFCP_LOG_AREA_PREFIX
...@@ -5,7 +5,8 @@ ...@@ -5,7 +5,8 @@
* *
* sysfs port related routines * sysfs port related routines
* *
* Copyright (C) 2003 IBM Entwicklung GmbH, IBM Corporation * (C) Copyright IBM Corp. 2003, 2004
*
* Authors: * Authors:
* Martin Peschke <mpeschke@de.ibm.com> * Martin Peschke <mpeschke@de.ibm.com>
* Heiko Carstens <heiko.carstens@de.ibm.com> * Heiko Carstens <heiko.carstens@de.ibm.com>
...@@ -25,7 +26,7 @@ ...@@ -25,7 +26,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * 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/init.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -34,7 +35,6 @@ ...@@ -34,7 +35,6 @@
#include "zfcp_def.h" #include "zfcp_def.h"
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG #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 * 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) ...@@ -209,11 +209,6 @@ zfcp_sysfs_port_failed_store(struct device *dev, const char *buf, size_t count)
goto out; 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_modify_port_status(port, ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET);
zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED); zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED);
zfcp_erp_wait(port->adapter); zfcp_erp_wait(port->adapter);
...@@ -268,6 +263,10 @@ zfcp_sysfs_port_in_recovery_show(struct device *dev, char *buf) ...@@ -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, static DEVICE_ATTR(in_recovery, S_IRUGO, zfcp_sysfs_port_in_recovery_show,
NULL); NULL);
/**
* zfcp_port_common_attrs
* sysfs attributes that are common for all kind of fc ports.
*/
static struct attribute *zfcp_port_common_attrs[] = { static struct attribute *zfcp_port_common_attrs[] = {
&dev_attr_failed.attr, &dev_attr_failed.attr,
&dev_attr_in_recovery.attr, &dev_attr_in_recovery.attr,
...@@ -281,6 +280,10 @@ static struct attribute_group zfcp_port_common_attr_group = { ...@@ -281,6 +280,10 @@ static struct attribute_group zfcp_port_common_attr_group = {
.attrs = zfcp_port_common_attrs, .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[] = { static struct attribute *zfcp_port_no_ns_attrs[] = {
&dev_attr_unit_add.attr, &dev_attr_unit_add.attr,
&dev_attr_unit_remove.attr, &dev_attr_unit_remove.attr,
...@@ -330,4 +333,3 @@ zfcp_sysfs_port_remove_files(struct device *dev, u32 flags) ...@@ -330,4 +333,3 @@ zfcp_sysfs_port_remove_files(struct device *dev, u32 flags)
} }
#undef ZFCP_LOG_AREA #undef ZFCP_LOG_AREA
#undef ZFCP_LOG_AREA_PREFIX
...@@ -5,7 +5,8 @@ ...@@ -5,7 +5,8 @@
* *
* sysfs unit related routines * sysfs unit related routines
* *
* Copyright (C) 2003 IBM Entwicklung GmbH, IBM Corporation * (C) Copyright IBM Corp. 2003, 2004
*
* Authors: * Authors:
* Martin Peschke <mpeschke@de.ibm.com> * Martin Peschke <mpeschke@de.ibm.com>
* Heiko Carstens <heiko.carstens@de.ibm.com> * Heiko Carstens <heiko.carstens@de.ibm.com>
...@@ -25,7 +26,7 @@ ...@@ -25,7 +26,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * 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/init.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -34,7 +35,6 @@ ...@@ -34,7 +35,6 @@
#include "zfcp_def.h" #include "zfcp_def.h"
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG #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 * 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) ...@@ -104,13 +104,9 @@ zfcp_sysfs_unit_failed_store(struct device *dev, const char *buf, size_t count)
goto out; 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_modify_unit_status(unit, ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET);
zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED); zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED);
zfcp_erp_wait(unit->port->adapter);
out: out:
up(&zfcp_data.config_sema); up(&zfcp_data.config_sema);
return retval ? retval : count; return retval ? retval : count;
...@@ -199,4 +195,3 @@ zfcp_sysfs_unit_remove_files(struct device *dev) ...@@ -199,4 +195,3 @@ zfcp_sysfs_unit_remove_files(struct device *dev)
} }
#undef ZFCP_LOG_AREA #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